diff --git a/conf/distro/ktn-eglfs.conf b/conf/distro/exceet-eglfs.conf
similarity index 86%
rename from conf/distro/ktn-eglfs.conf
rename to conf/distro/exceet-eglfs.conf
index b658ffea6539a3b25f6ec5e09036f34d524d79b8..20b2f34bf54ec27bf003019f2eaaccc178d24a5b 100644
--- a/conf/distro/ktn-eglfs.conf
+++ b/conf/distro/exceet-eglfs.conf
@@ -11,17 +11,17 @@ require conf/distro/include/openstlinux.inc
 MAINTAINER = "kontron Electronics GmbH <support@kontron.de>"
 SOURCECODE_VERSION ?= "0.0.0"
 
-DISTRO = "ktn-eglfs"
+DISTRO = "exceet-eglfs"
 DISTRO_NAME = "Kontron reference distro for eglfs backend"
 DISTRO_VERSION = "${SOURCECODE_VERSION}"
-DISTRO_CODENAME ?= "thud"
+DISTRO_CODENAME ?= "rocko"
 
 # Warning: TARGET_VENDOR does not contains a valid OS/ARCH name like : linux, arm
 # Warning: '-' are forbidden between each word of TARGET_VENDOR
-TARGET_VENDOR = "-ktn_eglfs"
+TARGET_VENDOR = "-exceet_eglfs"
 
 # Warning: '-' are forbidden between each word of SDK_VENDOR
-SDK_VENDOR = "-ktn_eglfs"
+SDK_VENDOR = "-exceet_eglfs"
 SDK_VERSION = "${DISTRO_CODENAME}_v${DISTRO_VERSION}"
 
 # Add image name for generated SDK and set default SDK install folder
@@ -38,15 +38,10 @@ PACKAGE_FEED_URIS ??= "http://192.168.1.1:8000/"
 # DISTRO settings
 # =========================================================================
 
-GCNANO_USERLAND_USE_VENDOR_DIR = "0"
-
 # Settings to be removed from OpenST
 #IMAGE_INSTALL_remove = " systemd-mount-bootfs-userfs "
 
 DISTRO_FEATURES_append = " opengl "
-DISTRO_FEATURES_append = " gplv3 "
 DISTRO_FEATURES_remove = " wayland x11 "
-DISTRO_FEATURES_append = " swupdate "
 
-# suppress gnome warnings when x11 is disabled
-SKIP_META_GNOME_SANITY_CHECK = "1"
+DISTRO_FEATURES_append = " gplv3 "
diff --git a/conf/distro/ktn-eglfs-sysvint.conf b/conf/distro/ktn-eglfs-sysvint.conf
deleted file mode 100644
index 3439f2a317e1d92c89b13babe4ae03e1ae9627c2..0000000000000000000000000000000000000000
--- a/conf/distro/ktn-eglfs-sysvint.conf
+++ /dev/null
@@ -1,61 +0,0 @@
-#@NAME: exceet-eglfs
-#@DESCRIPTION: Kontron distro based on OpenSTLinux with eglfs - no X11, no Wayland (with GPLv3 software)
-
-require conf/distro/include/st-default-distro-rules.inc
-require conf/distro/include/st-default-distro-providers.inc
-require conf/distro/include/openstlinux.inc
-
-# =========================================================================
-# DISTRO namings and integration
-# =========================================================================
-MAINTAINER = "kontron Electronics GmbH <support@kontron.de>"
-SOURCECODE_VERSION ?= "0.0.0"
-
-DISTRO = "ktn-eglfs-sysvint"
-DISTRO_NAME = "Kontron reference distro for eglfs backend"
-DISTRO_VERSION = "${SOURCECODE_VERSION}"
-DISTRO_CODENAME ?= "thud"
-
-# Warning: TARGET_VENDOR does not contains a valid OS/ARCH name like : linux, arm
-# Warning: '-' are forbidden between each word of TARGET_VENDOR
-TARGET_VENDOR = "-ktn_eglfs"
-
-# Warning: '-' are forbidden between each word of SDK_VENDOR
-SDK_VENDOR = "-ktn_eglfs"
-SDK_VERSION = "${DISTRO_CODENAME}_v${DISTRO_VERSION}"
-
-# Add image name for generated SDK and set default SDK install folder
-SDK_NAME = "${IMAGE_LINK_NAME}-${SDK_ARCH}"
-SDKPATH = "/opt/kontron/${MACHINE}/${SDK_VERSION}"
-SDKPATH[vardepsexclude] = "DATETIME DATE"
-
-IMAGE_NAME = "${IMAGE_BASENAME}-${MACHINE}-${DISTRO_CODENAME}-v${DISTRO_VERSION}-${DATETIME}"
-IMAGE_NAME[vardepsexclude] = "DATETIME DATE"
-
-PACKAGE_FEED_URIS ??= "http://192.168.1.1:8000/"
-
-# =========================================================================
-# DISTRO settings
-# =========================================================================
-# Disabling sysvinit
-DISTRO_FEATURES_BACKFILL_CONSIDERED_remove = "sysvinit"
-DISTRO_FEATURES_BACKFILL_CONSIDERED += "systemd"
-
-VIRTUAL-RUNTIME_init_manager = "sysvinit"
-VIRTUAL-RUNTIME_initscripts = "initscripts"
-
-GCNANO_USERLAND_USE_VENDOR_DIR = "0"
-
-DISTRO_FEATURES_remove = "systemd"
-
-# Settings to be removed from OpenST
-IMAGE_INSTALL_remove = " systemd-mount-bootfs-userfs "
-
-
-DISTRO_FEATURES_append = " opengl "
-DISTRO_FEATURES_append = " gplv3 "
-DISTRO_FEATURES_remove = " wayland x11 "
-DISTRO_FEATURES_append = " swupdate "
-
-# suppress gnome warnings when x11 is disabled
-SKIP_META_GNOME_SANITY_CHECK = "1"
diff --git a/conf/eula/stmxceet b/conf/eula/stmxceet
new file mode 100644
index 0000000000000000000000000000000000000000..ec27baaa1abb933ca34c8d5555982965097a9c48
--- /dev/null
+++ b/conf/eula/stmxceet
@@ -0,0 +1,339 @@
+
+LIMITED LICENSE AGREEMENT FOR ST MATERIALS EVALUATION
+
+
+IMPORTANT-READ CAREFULLY: This Limited License Agreement ("LLA") for ST
+materials is made between you on behalf of yourself, and on behalf of any entity to
+which you are employed or engaged (collectively referred to in this LLA as "You" or
+"Licensee") and STMicroelectronics International NV, a company incorporated under
+the laws of the Netherlands acting for the purpose of this LLA through its Swiss branch
+39, Chemin du Champ des Filles, 1228 Plan-les-Ouates, Geneva, Switzerland
+(hereinafter "ST"). Affiliates shall mean any corporation, partnership, or other entity
+that, directly or indirectly, owns, is owned by, or is under common ownership with ST,
+for so long as such ownership exists. For the purposes of the foregoing, "own", 
+"owned," or "ownership" shall mean ownership of more than fifty percent (50%) of the
+stock or other equity interests entitled to vote for the election of directors or an
+equivalent governing body.
+
+
+The ST materials licensed under this Agreement shall mean the software and/or any
+hardware material which accompany or are otherwise made available by ST and/or its
+Affiliates upon agreeing to this LLA, including any associated media, Documentation
+(as defined below), printed materials and electronic documentation (the "Licensed
+Materials"). The Licensed Materials include any software updates, hardware products
+and supplements that ST and/or its Affiliates may provide You or make available to
+You after the date You obtain the Licensed Materials to the extent that such items are
+not accompanied by a separate license agreement or other terms of use.
+
+
+1. LIMITED LICENSE
+
+
+Subject to the terms and conditions of this LLA and applicable Open Source Terms
+(as defined hereafter) and during the term of this LLA, ST hereby grants You under
+intellectual property rights owned by ST and its Affiliates or under which ST and its
+Affiliates has the right to grant a license, a non-exclusive, non-transferable, royalty-
+free, license, without the right to sub-license, to use internally the Licensed Materials
+solely and exclusively on or in combination with ST chipsets or ST integrated circuits
+(collectively "ST Chipsets") for the sole purpose of performing evaluation, simulation,
+testing, development of software/hardware applications and non-commercial
+demonstration of such Licensee's software/hardware applications with ST Chipsets
+"Limited License Purpose").
+
+
+Subject to the terms and conditions of this LLA, ST hereby grants You under
+intellectual property rights owned by ST and its Affiliates or under which ST and its
+Affiliates has the right to grant a license, a non-exclusive, non-transferable, royalty-
+free, license without the right to sub-license, to use internally any documentation of the
+Licensed Materials which is made available by ST under this LLA, including but not
+limited to documents in the form of comments, annotations, instructions, manuals, and
+other materials, whether in printed or electronic form, including without limitation
+installation manuals, user's guides, and programmer guides ("Documentation") solely
+to support the Limited License Purpose.
+
+
+You acknowledge that the Licensed Materials have not been specifically designed to
+meet your individual requirements and that You have all information necessary to
+evaluate whether the Licensed Materials meet your requirements or not, and will be
+suitable for your intended use or application. Therefore the Licensed Materials shall be
+deemed accepted upon delivery to Licensee. You shall use, at your own risk, the 
+Licensed Materials and any development that is obtained from such use.
+
+
+The Licensed Materials may also include third party software as expressly specified in
+the Licensed Materials subject to specific license terms from such third parties. Such
+third party software is supplied under such specific license terms and is not subject to
+the terms and conditions of the license hereunder. By installing copying, downloading,
+accessing or otherwise using this software package, the recipient agrees to be bound
+by such license terms with regard to such third party software.
+
+
+2. RESTRICTIONS
+
+
+Unless otherwise expressly stipulated under Article 1, You shall not, and shall not
+permit any third party to: (i) copy, reproduce or duplicate the Licensed Materials; (ii)
+translate, modify, adapt, decompile, disassemble or reverse engineer and make
+derivative works of (any portion of) the Licensed Materials; (iii) rent, disclose, publish,
+sell, assign, lease, lend, sublicense, market, transfer, distribute or otherwise provide
+third parties access to (any portion of) the Licensed Materials for any purpose; (iv)
+attempt to derive the source code, algorithmic nature or structure of any object code
+portions of the Licensed Materials; (v) use the Licensed Materials to create any product
+that competes with the Licensed Materials or ST Chipsets; (vi) disclose the results of
+the Licensed Materials' performance to any third party; or (vii) otherwise use any
+portion of the Licensed Materials in any manner not expressly authorized by this LLA.
+
+
+Other than the limited expressed license granted to You under Article 1 herein, no
+other rights or licenses are granted, or implied by estoppel or otherwise, under any
+intellectual property rights of ST and/or its Affiliates or any intellectual property of a
+third-party residing in the Licensed Materials or in any other confidential information
+furnished by ST, including (i) for the combination of such Licensed Materials or other
+confidential information with one or more other items (including items acquired from ST
+and/or its Affiliates) even if such items have no substantial use other than as part of
+such combination (ii) with respect to any trademark, trade or brand name, domain
+name, corporate name of ST and/or Affiliates, or any other name or mark, or
+contraction abbreviation or simulation thereof, (iii) under any intellectual property rights
+covering any standard set by a standard setting body and any de facto standards.
+
+
+You shall limit access and use of the Licensed Materials to You and those individuals
+who may be employed by You who have a need to access the Licensed Materials for 
+the Limited License Purpose and provided that You shall ensure that such individuals
+shall comply with the provisions of this LLA, and You shall not allow any third-party to
+use the Licensed Materials, unless otherwise expressly agreed in writing by ST and
+provided that You agree to be liable towards ST for any damages due to a failure by
+such authorized third-party(ies) to comply with the provisions of this LLA.
+
+
+ST and its Affiliates have no obligation to provide You with maintenance, technical
+support or updates for the Licensed Materials.
+
+
+3. OWNERSHIP, COPYRIGHTS AND TRADEMARKS
+
+
+The Licensed Materials are and will remain the exclusive property of ST and/or its
+Affiliates or its licensors, whether or not specifically recognized or perfected under the
+laws of the country where the Licensed Materials are used. You will not take any action
+that jeopardizes ST and its Affiliates or its licensors' proprietary rights or acquire any
+rights in the Licensed Materials, except the limited rights specified in Article 1.
+
+
+All right, title and interest in and to the Licensed Materials, are owned or licensed by
+ST or its Affiliates or licensors. You shall ensure that all notices, including but not
+limited to all copyright and trademark notices of ST or its Affiliates or licensors are
+reproduced in any copy of the whole or any part of the Licensed Materials. You shall
+not remove, modify or alter any ST or its Affiliates' or licensors' copyright or trademark
+notice from any part of the Licensed Materials.
+
+
+4. CONFIDENTIALITY
+
+
+Confidential information shall include all information provided with the Licensed
+Materials which (a) is designated as "confidential", "proprietary" or with a similar
+legend, (b) is by its own nature of a type which would reasonably be considered 
+confidential and/or (c) is source code. You may only use the Licensed Materials for the
+Limited License Purpose and shall protect the confidentiality of the Licensed Materials
+provided by ST under this LLA by using the same degree of care, but not less than a
+reasonable degree of care, to prevent the unauthorized use, dissemination, or
+publication of the confidential information as You use to protect your own confidential
+information of like nature.
+
+
+You shall immediately notify ST of any unauthorised use or disclosure of, or of any
+unauthorised access to, or of any theft or loss of the Licensed Materials or part thereof,
+which comes to your notice.
+
+
+The confidentiality obligations shall not apply to Licensed Materials, which can be
+shown by documentary evidence: (i) entered the public domain through no fault of the
+Licensee; or, (ii) known to the Licensee prior to receipt from ST; or, (iii) disclosed to the
+Licensee by a third party having the right to disclose; or, (iv) independently developed
+by the Licensee without use of the Licensed Materials, the onus of proof of
+independence being on the Licensee.
+
+
+These confidentiality obligations shall survive any termination or expiration of the LLA
+for whatever cause.
+
+
+5. OPEN SOURCE
+
+
+Some portion of the Licensed Materials might contain Open Source Software subject to
+Open Source Terms applicable for each such portion, as further specified in the 
+Licensed Materials. Such Open Source Software is supplied to You under the
+applicable Open Source Terms and is not subject to the terms of this LLA to the extent
+the terms of this LLA are in conflict with such applicable Open Source Terms.
+
+
+Except for Open Source Software, You have no rights under this LLA to, and may not
+under any circumstances use the Licensed Materials or any parts thereof such that
+they become subject to any Open Source Terms. These actions include but are not 
+limited to combining the Licensed Materials by means of incorporation or linking or
+otherwise.
+
+
+For the purpose of this LLA, "Open Source Terms" shall mean any open source license
+which requires as part of distribution of software that the source code of such software
+is distributed therewith, or any other open source license that complies with the Open
+
+Source Definition specified at www.opensource.org and any other comparable open 
+source license such as for example GNU General Public License (GPL), Eclipse Public
+License (EPL), Apache Software License, BSD license and MIT license. "Open Source
+Software" shall mean any software that is licensed or distributed under Open Source
+Terms as specified in the Licensed Materials.
+
+
+6. COMPLIANCE
+
+
+You agree not to use the Licensed Materials in violation of any law, statute, ordinance
+or other regulation or any obligation to which You are bound. You agree to comply with
+all applicable laws and regulations regarding the use of the Licensed Materials. You
+acknowledge that the Licensed Materials may be subject to export controls restrictions.
+You agree that You will not export, re-export Licensed Materials, directly or indirectly,
+to any country to the extent export to such country at the time of export requires an
+export license or other governmental approval under any export control laws and 
+regulations, without first obtaining such license or approval.
+
+
+7. DISCLAIMER OF WARRANTY AND DAMAGES
+
+
+THE LICENSED MATERIALS ARE PROVIDED BY STMICROELECTRONICS AND
+CONTRIBUTORS "AS IS" AND ANY EXPRESS, IMPLIED OR STATUTORY
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-
+INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY RIGHTS ARE
+DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT
+SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE PACKAGE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGE. ST AND ITS AFFILIATES AGGREGATE AND CUMULATIVE LIABILITY
+TOWARDS LICENSEE UNDER THIS LLA SHALL NOT EXCEED 100 USD. THE
+LIMITATIONS SET FORTH ABOVE IN THIS ARTICLE 7 SHALL ONLY APPLY TO
+THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW.
+
+
+8. TERM AND TERMINATION
+
+
+This LLA shall be valid for one year from acceptance by You of this LLA, unless 
+terminated before by You at any time by destroying all Licensed Materials or by 
+returning those to ST. ST may terminate this LLA at any time if (i) You fail to comply
+with the terms and conditions of this LLA, or (ii) You file litigation against ST or its
+Affiliates, (iii) ST or its Affiliates receives notice of any claim, suit or proceeding that
+alleges that the Licensed Materials or your use of the Licensed Materials infringes any
+third-party intellectual property rights or (iv) to the extent permitted by laws, a voluntary
+or involuntary petition in bankruptcy or winding up is filed against Licensee, any
+proceedings in insolvency or bankruptcy are instituted against Licensee, a trustee or
+receiver is appointed over Licensee, or any assignment is made for the benefit of
+creditors of Licensee. Upon termination, You shall delete, destroy, or return to ST all
+Licensed Materials in your possession and You shall stop using the Licensed Materials
+for any purpose whatsoever. The rights and obligations under Articles from 2 to 11 will
+survive the termination or expiration of this LLA.
+
+
+9. MISCELLANEOUS
+
+
+If a court or agency of competent jurisdiction holds any term of this LLA invalid, illegal,
+or unenforceable for any reason, the remainder of this LLA shall be valid and
+enforceable and You and ST shall discuss in good faith a substitute, valid, enforceable
+provision which most nearly effects the parties intent in entering into this LLA.
+
+
+The failure by ST to enforce any provisions of this LLA or to exercise any right in
+respect thereto shall not be construed as constituting a waiver of its rights thereof.
+
+
+No agency, joint venture, partnership or other business organization shall be created or
+be construed as being created by reason of this LLA. You will not have the right or
+authority to, and shall not, assume or create any obligation of any nature whatsoever
+on behalf of ST or bind ST in any respect whatsoever. You and ST are independent
+parties. Nothing in this LLA shall be construed as making You an employee, agent or
+legal representative of ST.
+
+
+This LLA contains the entire and sole agreement between You and ST on the subject
+matter of this LLA, and supersedes all representations, undertakings and agreements
+previously made between You and ST and/or its Affiliates and shall prevail over the
+terms and conditions set forth in any document from You with respect to the subject
+matter of this LLA. Any amendment to this LLA shall be agreed in writing and be duly
+signed by You and ST or signed or agreed solely by You on the format proposed by ST
+and shall make reference to this LLA.
+
+
+THE LICENSED MATERIALS ARE LICENSED TO YOU ON THE CONDITION THAT
+YOU ACCEPT ALL THE TERMS AND CONDITIONS OF THIS LLA. BY CLICKING ON
+THE "I ACCEPT" BUTTON OR BY INSTALLING, COPYING, DOWNLOADING,
+ACCESSING OR OTHERWISE USING THE LICENSED MATERIALS, YOU AGREE
+TO BE BOUND BY THE TERMS OF THIS LLA. IF YOU DO NOT AGREE WITH ANY
+CONDITION OF THIS LLA, DO NOT INSTALL, ACCESS OR USE THE LICENSED
+MATERIALS.
+
+
+###############################################################################
+
+Vivante End User Software License Terms
+
+The following are the terms to be agreed to by end users of Vivante Software licensed herein:
+
+Copyright 2003-2017 Vivante Corporation, all rights reserved.
+
+Use, reproduction and redistribution of this software in binary form, without modification and solely for use in conjunction with STMicroelectronics semiconductor chips with the Linux operating system environment that contain Vivante Corporation’s technology, are permitted provided that the following conditions are met:
+
+* Redistributions must reproduce the above copyright notice, this list of conditions and the following disclaimers in the documentation and/or other materials provided with the distribution.
+
+* Neither the name nor trademarks of STMicroelectronics International N.V. nor any other STMicroelectronics company (nor Vivante Corporation unless permission is granted separately by Vivante Corporation) may be used to endorse or promote products derived from this software without specific prior written permission.
+
+* No reverse engineering, decompilation or disassembly of this software is permitted.
+
+* No use, reproduction or redistribution of this software may be done in any manner that may cause this software to be redistributed as part of the Linux kernel or in any other manner that would subject this software to the terms of the GNU General Public License, the GNU Lesser General Public License, or any other copyleft license.
+
+DISCLAIMERS:
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL STMICROELECTRONICS INTERNATIONAL N.V. NOR ANY OTHER STMICROELECTRONICS COMPANY (NOR VIVANTE CORPORATION) BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+THE DELIVERY OF THIS SOFTWARE DOES NOT CONVEY ANY LICENSE, WHETHER EXPRESS OR IMPLIED, TO ANY THIRD-PARTY INTELLECTUAL PROPERTY RIGHTS.
+
+EXCEPT THE LIMITED RIGHT TO USE, REPRODUCE AND REDISTRIBUTE THIS SOFTWARE IN BINARY FORM, NO LICENSE OR OTHER RIGHTS, WHETHER EXPRESS OR IMPLIED, ARE GRANTED UNDER ANY PATENT OR OTHER INTELLECTUAL PROPERTY RIGHTS OF STMICROELECTRONICS INTERNATIONAL N.V. OR ANY OTHER STMICROELECTRONICS COMPANY (OR VIVANTE CORPORATION).
+
+
+###############################################################################
+
+### CYPRESS WIRELESS CONNECTIVITY DEVICES
+### DRIVER END USER LICENSE AGREEMENT (SOURCE AND BINARY DISTRIBUTION)
+
+PLEASE READ THIS END USER LICENSE AGREEMENT ("Agreement") CAREFULLY BEFORE DOWNLOADING, INSTALLING, OR USING THIS SOFTWARE, ANY ACCOMPANYING DOCUMENTATION, OR ANY UPDATES PROVIDED BY CYPRESS ("Software").  BY DOWNLOADING, INSTALLING, OR USING THE SOFTWARE, YOU ARE AGREEING TO BE BOUND BY THIS AGREEMENT.  IF YOU DO NOT AGREE TO ALL OF THE TERMS OF THIS AGREEMENT, PROMPTLY RETURN AND DO NOT USE THE SOFTWARE.  IF YOU HAVE PURCHASED THE SOFTWARE, YOUR RIGHT TO RETURN THE SOFTWARE EXPIRES 30 DAYS AFTER YOUR PURCHASE AND APPLIES ONLY TO THE ORIGINAL PURCHASER.
+
+Software Provided in Binary Code Form.  This paragraph applies to any Software provided in binary code form.  Subject to the terms and conditions of this Agreement, Cypress Semiconductor Corporation ("Cypress") grants you a non-exclusive, non-transferable license under its copyright rights in the Software to reproduce and distribute the Software in object code form only, solely for use in connection with Cypress integrated circuit products ("Purpose").
+
+Software Provided in Source Code Form.  This paragraph applies to any Software provided in source code form ("Cypress Source Code").  Subject to the terms and conditions of this Agreement, Cypress grants you a non-exclusive, non-transferable license under its copyright rights in the Cypress Source Code to reproduce, modify, compile, and distribute the Cypress Source Code (whether in source code form or as compiled into binary code form) solely for the Purpose.  Cypress retains ownership of the Cypress Source Code and any compiled version thereof.  Subject to Cypress' ownership of the underlying Cypress Source Code, you retain ownership of any modifications you make to the Cypress Source Code.  You agree not to remove any Cypress copyright or other notices from the Cypress Source Code and any modifications thereof.  Any reproduction, modification, translation, compilation, or representation of the Cypress Source Code except as permitted in this paragraph is prohibited without the express written permission of Cypress.
+
+Free and Open Source Software.  Portions of the Software may be licensed under free and/or open source licenses such as the GNU General Public License ("FOSS").  FOSS is subject to the applicable license agreement and not this Agreement.  If you are entitled to receive the source code from Cypress for any FOSS included with the Software, either the source code will  be included with the Software or you may obtain the source code at no charge from <http://www.cypress.com/go/opensource>.  The applicable license terms will accompany each source code package.  To review the license terms applicable to any FOSS for which Cypress is not required to provide you with source code, please see the Software's installation directory on your computer.
+
+Proprietary Rights.  The Software, including all intellectual property rights therein, is and will remain the sole and exclusive property of Cypress or its suppliers.  Except as otherwise expressly provided in this Agreement, you may not: (i) modify, adapt, or create derivative works based upon the Software; (ii) copy the Software; (iii) except and only to the extent explicitly permitted by applicable law despite this limitation, decompile, translate, reverse engineer, disassemble or otherwise reduce the Software to human-readable form; or (iv) use the Software other than for the Purpose.
+
+No Support.  Cypress may, but is not required to, provide technical support for the Software.
+
+Term and Termination.  This Agreement is effective until terminated, and either party may terminate this Agreement at any time with or without cause.  Your license rights under this Agreement will terminate immediately without notice from Cypress if you fail to comply with any provision of this Agreement.  Upon termination, you must destroy all copies of Software in your possession or control.  Termination of this Agreement will not affect any licenses validly granted as of the termination date to any end users of the Software.  The following paragraphs shall survive any termination of this Agreement: "Free and Open Source Software," "Proprietary Rights," "Compliance With Law," "Disclaimer," "Limitation of Liability," and "General."
+
+Compliance With Law.  Each party agrees to comply with all applicable laws, rules and regulations in connection with its activities under this Agreement. Without limiting the foregoing, the Software may be subject to export control laws and regulations of the United States and other countries.  You agree to comply strictly with all such laws and regulations and acknowledge that you have the responsibility to obtain licenses to export, re-export, or import the Software.
+
+Disclaimer.  TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, CYPRESS MAKES NO WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, WITH REGARD TO THE SOFTWARE, INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Cypress reserves the right to make changes to the Software without notice. Cypress does not assume any liability arising out of the application or use of Software or any product or circuit described in the Software. Cypress does not authorize its products for use as critical components in life-support systems where a malfunction or failure may reasonably be expected to result in significant injury to the user. The inclusion of Cypress' product in a life-support system or application implies that the manufacturer of such system or application assumes all risk of such use and in doing so indemnifies Cypress against all charges.
+
+Limitation of Liability.  IN NO EVENT WILL CYPRESS OR ITS SUPPLIERS, RESELLERS, OR DISTRIBUTORS BE LIABLE FOR ANY LOST REVENUE, PROFIT, OR DATA, OR FOR SPECIAL, INDIRECT, CONSEQUENTIAL, INCIDENTAL, OR PUNITIVE DAMAGES HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF CYPRESS OR ITS SUPPLIERS, RESELLERS, OR DISTRIBUTORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.  IN NO EVENT SHALL CYPRESS' OR ITS SUPPLIERS' RESELLERS', OR DISTRIBUTORS' TOTAL LIABILITY TO YOU, WHETHER IN CONTRACT, TORT (INCLUDING NEGLIGENCE), OR OTHERWISE, EXCEED THE PRICE PAID BY YOU FOR THE SOFTWARE. THE FOREGOING LIMITATIONS SHALL APPLY EVEN IF THE ABOVE-STATED WARRANTY FAILS OF ITS ESSENTIAL PURPOSE.  BECAUSE SOME STATES OR JURISDICTIONS DO NOT ALLOW LIMITATION OR EXCLUSION OF CONSEQUENTIAL OR INCIDENTAL DAMAGES, THE ABOVE LIMITATION MAY NOT APPLY TO YOU.
+
+Restricted Rights.  The Software under this Agreement is commercial computer software as that term is described in 48 C.F.R. 252.227-7014(a)(1).  If acquired by or on behalf of a civilian agency, the U.S. Government acquires this commercial computer software and/or commercial computer software documentation subject to the terms of this Agreement as specified in 48 C.F.R. 12.212 (Computer Software) and 12.211 (Technical Data) of the Federal Acquisition Regulations ("FAR") and its successors.  If acquired by or on behalf of any agency within the Department of Defense ("DOD"), the U.S. Government acquires this commercial computer software and/or commercial computer software documentation subject to the terms of this Agreement as specified in 48 C.F.R. 227.7202-3 of the DOD FAR Supplement ("DFAR") and its successors.
+
+General.  This Agreement will bind and inure to the benefit of each party's successors and assigns, provided that you may not assign or transfer this Agreement, in whole or in part, without Cypress' written consent.  This Agreement shall be governed by and construed in accordance with the laws of the State of California, United States of America, as if performed wholly within the state and without giving effect to the principles of conflict of law.  The parties consent to personal and exclusive jurisdiction of and venue in, the state and federal courts within Santa Clara County, California; provided however, that nothing in this Agreement will limit Cypress' right to bring legal action in any venue in order to protect or enforce its intellectual property rights.  No failure of either party to exercise or enforce any of its rights under this Agreement will act as a waiver of such rights.  If any portion hereof is found to be void or unenforceable, the remaining provisions of this Agreement shall remain in full force and effect.  This Agreement is the complete and exclusive agreement between the parties with respect to the subject matter hereof, superseding and replacing any and all prior agreements, communications, and understandings (both written and oral) regarding such subject matter.  Any notice to Cypress will be deemed effective when actually received and must be sent to Cypress Semiconductor Corporation, ATTN: Chief Legal Officer, 198 Champion Court, San
+Jose, CA 95134 USA.
diff --git a/conf/layer.conf b/conf/layer.conf
index 2e3885aca69e2ce079a1cc813f3cdd69c87e8ee3..b2579ce51d75d2b31b3e87ad5e11c6c73ca0adc3 100644
--- a/conf/layer.conf
+++ b/conf/layer.conf
@@ -14,20 +14,20 @@ BBPATH .= ":${LAYERDIR}"
 # We have a recipes directory, add to BBFILES
 BBFILES += "${LAYERDIR}/recipes-*/*/*.bb ${LAYERDIR}/recipes-*/*/*.bbappend"
 
-BBFILE_COLLECTIONS += "ktn-stm32mp"
-BBFILE_PATTERN_ktn-stm32mp := "^${LAYERDIR}/"
+BBFILE_COLLECTIONS += "exceet-stm32mp"
+BBFILE_PATTERN_exceet-stm32mp := "^${LAYERDIR}/"
 
 # Define the priority for recipes (.bb files) from this layer,
 # choosing carefully how this layer interacts with all of the
 # other layers.
 
-BBFILE_PRIORITY_ktn-stm32mp = "9"
+BBFILE_PRIORITY_exceet-stm32mp = "9"
 
 # This should only be incremented on significant changes that will
 # cause compatibility issues with other layers
-LAYERVERSION_ktn-stm32mp = "1"
+LAYERVERSION_exceet-stm32mp = "1"
 
-LAYERDEPENDS_ktn-stm32mp = "stm-st-stm32mp"
+LAYERDEPENDS_exceet-stm32mp = "stm-st-stm32mp"
 
 LICENSE_PATH += "${LAYERDIR}/licenses"
 
@@ -41,6 +41,7 @@ BBFILES += "${@' '.join('${LAYERDIR}/%s/recipes*/*/*.bbappend' % layer \
 BBFILES += "${@' '.join('${LAYERDIR}/%s/recipes*/*/*.bb' % layer \
                for layer in BBFILE_COLLECTIONS.split())}"
 
-LAYERVERSION_ktn-stm32mp = "1"
-LAYERSERIES_COMPAT_ktn-stm32mp = "thud"
+# EULA files for our machines are located in this layer
+EULA_FILE_ST_stm32mpcommon_lxctrl = "${LAYERDIR}/conf/eula/${MACHINE}"
+EULA_FILE_ST_MD5SUM_stm32mpcommon_lxctrl = "d8005832005aa0a04f3ba6d04c4e9364"
 
diff --git a/conf/local.conf.sample b/conf/local.conf.sample
index 1680b64cbbb2465bf882b716148e1c7b488a057e..0b9a9f8da61b9d03f431a713614bcf8a7b1081dc 100644
--- a/conf/local.conf.sample
+++ b/conf/local.conf.sample
@@ -1,36 +1,16 @@
-#
-# This file is your local configuration file and is where all local user settings
-# are placed. The comments in this file give some guide to the options a new user
-# to the system might want to change but pretty much any configuration option can
-# be set in this file. More adventurous users can look at local.conf.extended
-# which contains other examples of configuration which can be placed in this file
-# but new users likely won't need any of them initially.
-#
-# Lines starting with the '#' character are commented out and in some cases the
-# default values are provided as comments to show people example syntax. Enabling
-# the option is a question of removing the # character and making any change to the
-# variable as required.
 
-# include version variables for source code
-include sourcecode-version.conf
-
-# Machine Selection
-MACHINE ?= "stm32mp-t1000-multi"
-#MACHINE ?= "stm32mp-t1000"
-#MACHINE ?= "stm32mp-t1001"
+# This sets the default machine to be qemux86 if no other machine is selected:
+MACHINE = "stm32mp-t1000-s-multi"
 
 # Default policy config
-DISTRO = "ktn"
-
-# Package Management configuration
-PACKAGE_CLASSES ?= "package_deb"
+DISTRO = "exceet-eglfs"
 
-# Where to find the debian package server
-#DISTRO_FEED_URI = "http://192.168.1.1:8000/"
+# Version tag for all sourcecode (corresponds to repo.conf)
+#SOURCECODE_VERSION = "0.1.0.a"
+# 0.1 - OpenST a2 release
 
 # SDK target architecture
-# Supported values are i686 and x86_64
-#SDKMACHINE ?= "i686"
+SDKMACHINE ?= "x86_64"
 
 #
 # Extra image configuration defaults
@@ -69,9 +49,16 @@ EXTRA_IMAGE_FEATURES ?= "debug-tweaks tools-debug"
 # NOTE: mklibs also needs to be explicitly enabled for a given image, see local.conf.extended
 USER_CLASSES ?= "buildstats image-mklibs image-prelink"
 
+# Interactive shell configuration
+OE_TERMINAL = "auto"
 # By default disable interactive patch resolution (tasks will just fail instead):
 PATCHRESOLVE = "noop"
 
+# Where to place intermediate files
+#DL_DIR ?= "${TOPDIR}/downloads"
+#SSTATE_DIR ?= "${TOPDIR}/sstate-cache"
+#TMPDIR = "${TOPDIR}/tmp"
+
 #
 # Disk Space Monitoring during the build
 #
@@ -110,17 +97,6 @@ BB_DISKMON_DIRS = "\
 #file://.* http://someserver.tld/share/sstate/PATH;downloadfilename=PATH \n \
 #file://.* file:///some/local/dir/sstate/PATH"
 
-# Where to place downloads
-# The default is a downloads directory under TOPDIR which is the build directory.
-#DL_DIR ?= "${TOPDIR}/downloads"
-
-# Where to place shared-state files
-# The default is a sstate-cache directory under TOPDIR.
-#SSTATE_DIR ?= "${TOPDIR}/sstate-cache"
-
-# Where to place the build output
-# The default is a tmp directory under TOPDIR.
-#TMPDIR = "${TOPDIR}/tmp"
 
 #
 # Qemu configuration
@@ -134,7 +110,7 @@ PACKAGECONFIG_append_pn-nativesdk-qemu = " sdl"
 #ASSUME_PROVIDED += "libsdl-native"
 
 # =========================================================================
-#   ST Specific
+#   ST SPecific
 # =========================================================================
 #
 # CONF_VERSION is increased each time build/conf/ changes incompatibly and is used to
@@ -159,9 +135,6 @@ IMAGE_LINGUAS ?= "en-gb"
 # Support of devshell
 INHERIT += "devshell"
 
-# Clean up working directory after build
-INHERIT += "rm_work"
-
 # Remove the old image before the new one generated to save disk space
 RM_OLD_IMAGE = "1"
 
@@ -169,30 +142,30 @@ RM_OLD_IMAGE = "1"
 INHERIT += "buildhistory"
 BUILDHISTORY_COMMIT = "1"
 
+# Clean up working directory after build
+INHERIT += "rm_work"
+# ... except those packages
+RM_WORK_EXCLUDE += ""
+
 # To generate debug image with all symbol
 #IMAGE_GEN_DEBUGFS = "1"
 
-# To enable archiver for recipes that are configured (e.g. atf, u-boot, kernel...)
-#ST_ARCHIVER_ENABLE = "1"
+# force the usage of debian package
+PACKAGE_CLASSES = "package_deb"
 
-# Accept license agreement
-# Read the license files in conf/eula directory in meta-st-stm32mp layer before
-# accepting the license
-#ACCEPT_EULA_stm32mp-t1000-multi = "1"
-#ACCEPT_EULA_stm32mp-t1000 = "1"
-#ACCEPT_EULA_stm32mp-t1001 = "1"
+# Package server
+PACKAGE_FEED_URIS = "http://192.168.1.1:8000/"
 
-# Allowed license types
-LICENSE_FLAGS_WHITELIST += " non-commercial "
-LICENSE_FLAGS_WHITELIST += " commercial_gstreamer1.0-plugins-ugly commercial_gstreamer1.0-libav commercial_faac commercial_mpeg2dec "
+# To enable archiver for recipes that are configured (e.g. atf, u-boot, kernel...)
+#ST_ARCHIVER_ENABLE = "1"
 
-# Don't remove source of these recipes
-#RM_WORK_EXCLUDE += " linux-stm32mp "
-#RM_WORK_EXCLUDE += " u-boot-stm32mp "
-#RM_WORK_EXCLUDE += " tf-a-stm32mp "
+# =========================================================================
+# Set EULA acceptance
+# =========================================================================
+# Read the EULA and uncomment this for your machine
+# You can find the EULA file in layer meta-st-stm32mp/conf/eula/ST_EULA
+#ACCEPT_EULA_stm32mp-t1000-s-multi = "1"
 
-# Additional packages to install in image
-CORE_IMAGE_EXTRA_INSTALL = ""
+# Additional packages to install
+CORE_IMAGE_EXTRA_INSTALL += ""
 
-# include local user configuration
-include user.conf
diff --git a/conf/machine/FlashLayout_t1000-s-multi_nor-emmc.tsv b/conf/machine/FlashLayout_t1000-s-multi_nor-emmc.tsv
deleted file mode 100644
index 696c9f8894111b7cb1b5d21a9fbbc25de301f2be..0000000000000000000000000000000000000000
--- a/conf/machine/FlashLayout_t1000-s-multi_nor-emmc.tsv
+++ /dev/null
@@ -1,11 +0,0 @@
-#Opt	Id	Name	Type	IP	Offset	Binary
--	0x01	fsbl1-boot	Binary	none	0x0	tf-a-stm32mp-t1000-s-trusted.stm32
--	0x03	ssbl-boot	Binary	none	0x0	u-boot-stm32mp-t1000-s-trusted.stm32
-PD	0x02	fsbl1	Binary	nor0	0x00000000	tf-a-stm32mp-t1000-s-trusted.stm32
-PD	0x04	fsbl2	Binary	nor0	0x00040000	tf-a-stm32mp-t1000-s-trusted.stm32
-PD	0x05	ssbl	Binary	nor0	0x00080000	u-boot-stm32mp-t1000-s-trusted.stm32
-PDE	0x06	env	Binary	nor0	0x00180000	none
-PDE	0x07	nor_user	Binary	nor0	0x00190000	none
-PD	0x10	bootfs	System	mmc1	0x00080000		st-image-bootfs-ktn-eglfs-stm32mp-t1000-s-multi.ext4
-PD	0x11	rootfs	FileSystem	mmc1	0x05080000	image-stm32mp-console-ktn-eglfs-stm32mp-t1000-s-multi.ext4
-PD	0x12	userfs	FileSystem	mmc1	0x35080000	st-image-userfs-ktn-eglfs-stm32mp-t1000-s-multi.ext4
diff --git a/conf/machine/FlashLayout_t1000-s-multi_nor.tsv b/conf/machine/FlashLayout_t1000-s-multi_nor.tsv
deleted file mode 100644
index 065f5993b23905bf62164726a5bbc7e295354c80..0000000000000000000000000000000000000000
--- a/conf/machine/FlashLayout_t1000-s-multi_nor.tsv
+++ /dev/null
@@ -1,8 +0,0 @@
-#Opt	Id	Name	Type	IP	Offset	Binary
--	0x01	fsbl1-boot	Binary	none	0x0	tf-a-stm32mp-t1000-s-trusted.stm32
--	0x03	ssbl-boot	Binary	none	0x0	u-boot-stm32mp-t1000-s-trusted.stm32
-PD	0x02	fsbl1	Binary	nor0	0x00000000	tf-a-stm32mp-t1000-s-trusted.stm32
-PD	0x04	fsbl2	Binary	nor0	0x00040000	tf-a-stm32mp-t1000-s-trusted.stm32
-PD	0x05	ssbl	Binary	nor0	0x00080000	u-boot-stm32mp-t1000-s-trusted.stm32
-PDE	0x06	env	Binary	nor0	0x00180000	none
-PDE	0x07	nor_user	Binary	nor0	0x00190000	none
diff --git a/conf/machine/FlashLayout_t1000-s-multi_qt_nor-emmc.tsv b/conf/machine/FlashLayout_t1000-s-multi_qt_nor-emmc.tsv
deleted file mode 100644
index 9d1f91289123e15ebcc5ec6945ff94920ae05550..0000000000000000000000000000000000000000
--- a/conf/machine/FlashLayout_t1000-s-multi_qt_nor-emmc.tsv
+++ /dev/null
@@ -1,11 +0,0 @@
-#Opt	Id	Name	Type	IP	Offset	Binary
--	0x01	fsbl1-boot	Binary	none	0x0	tf-a-stm32mp-t1000-s-trusted.stm32
--	0x03	ssbl-boot	Binary	none	0x0	u-boot-stm32mp-t1000-s-trusted.stm32
-PD	0x02	fsbl1	Binary	nor0	0x00000000	tf-a-stm32mp-t1000-s-trusted.stm32
-PD	0x04	fsbl2	Binary	nor0	0x00040000	tf-a-stm32mp-t1000-s-trusted.stm32
-PD	0x05	ssbl	Binary	nor0	0x00080000	u-boot-stm32mp-t1000-s-trusted.stm32
-PDE	0x06	env	Binary	nor0	0x00180000	none
-PDE	0x07	nor_user	Binary	nor0	0x00190000	none
-PD	0x10	bootfs	System	mmc1	0x00080000		st-image-bootfs-ktn-eglfs-stm32mp-t1000-s-multi.ext4
-PD	0x11	rootfs	FileSystem	mmc1	0x05080000	image-stm32mp-qt-ktn-eglfs-stm32mp-t1000-s-multi.ext4
-PD	0x12	userfs	FileSystem	mmc1	0x35080000	st-image-userfs-ktn-eglfs-stm32mp-t1000-s-multi.ext4
diff --git a/conf/machine/FlashLayout_t1000-s-multi_qt_sdcard.tsv b/conf/machine/FlashLayout_t1000-s-multi_qt_sdcard.tsv
deleted file mode 100644
index 9cee0a792a8c3fc2b953eb73a3e3123653056a68..0000000000000000000000000000000000000000
--- a/conf/machine/FlashLayout_t1000-s-multi_qt_sdcard.tsv
+++ /dev/null
@@ -1,9 +0,0 @@
-#Opt	Id	Name	Type	IP	Offset	Binary
--	0x01	fsbl1-boot	Binary	none	0x0	tf-a-stm32mp-t1000-s-trusted.stm32
--	0x03	ssbl-boot	Binary	none	0x0	u-boot-stm32mp-t1000-s-trusted.stm32
-PD	0x02	fsbl1	Binary	mmc0	0x00004400	tf-a-stm32mp-t1000-s-trusted.stm32
-PD	0x04	fsbl2	Binary	mmc0	0x00044400	tf-a-stm32mp-t1000-s-trusted.stm32
-PD	0x05	ssbl	Binary	mmc0	0x00084400	u-boot-stm32mp-t1000-s-trusted.stm32
-PD	0x10	bootfs	System	mmc0	0x00284400	st-image-bootfs-ktn-eglfs-stm32mp-t1000-s-multi.ext4
-PD	0x11	rootfs	FileSystem	mmc0	0x05284400	image-stm32mp-qt-ktn-eglfs-stm32mp-t1000-s-multi.ext4
-PD	0x12	userfs	FileSystem	mmc0	0x35284400	st-image-userfs-ktn-eglfs-stm32mp-t1000-s-multi.ext4
diff --git a/conf/machine/FlashLayout_t1000-s-multi_sdcard.tsv b/conf/machine/FlashLayout_t1000-s-multi_sdcard.tsv
deleted file mode 100644
index 22028391d16ed0eb69cc96d14faa70a875f68cda..0000000000000000000000000000000000000000
--- a/conf/machine/FlashLayout_t1000-s-multi_sdcard.tsv
+++ /dev/null
@@ -1,9 +0,0 @@
-#Opt	Id	Name	Type	IP	Offset	Binary
--	0x01	fsbl1-boot	Binary	none	0x0	tf-a-stm32mp-t1000-s-trusted.stm32
--	0x03	ssbl-boot	Binary	none	0x0	u-boot-stm32mp-t1000-s-trusted.stm32
-PD	0x02	fsbl1	Binary	mmc0	0x00004400	tf-a-stm32mp-t1000-s-trusted.stm32
-PD	0x04	fsbl2	Binary	mmc0	0x00044400	tf-a-stm32mp-t1000-s-trusted.stm32
-PD	0x05	ssbl	Binary	mmc0	0x00084400	u-boot-stm32mp-t1000-s-trusted.stm32
-PD	0x10	bootfs	System	mmc0	0x00284400	st-image-bootfs-ktn-eglfs-stm32mp-t1000-s-multi.ext4
-PD	0x11	rootfs	FileSystem	mmc0	0x05284400	image-stm32mp-console-ktn-eglfs-stm32mp-t1000-s-multi.ext4
-PD	0x12	userfs	FileSystem	mmc0	0x35284400	st-image-userfs-ktn-eglfs-stm32mp-t1000-s-multi.ext4
diff --git a/conf/machine/FlashLayout_t1001_nor.tsv b/conf/machine/FlashLayout_t1001_nor.tsv
deleted file mode 100644
index 7ba131302d2d09556e47feea845b96f11aed018d..0000000000000000000000000000000000000000
--- a/conf/machine/FlashLayout_t1001_nor.tsv
+++ /dev/null
@@ -1,8 +0,0 @@
-#Opt	Id	Name	Type	IP	Offset	Binary
--	0x01	fsbl1-boot	Binary	none	0x0	tf-a-stm32mp-t1001-trusted.stm32
--	0x03	ssbl-boot	Binary	none	0x0	u-boot-stm32mp-t1001-trusted.stm32
-PD	0x02	fsbl1	Binary	nor0	0x00000000	tf-a-stm32mp-t1001-trusted.stm32
-PD	0x04	fsbl2	Binary	nor0	0x00040000	tf-a-stm32mp-t1001-trusted.stm32
-PD	0x05	ssbl	Binary	nor0	0x00080000	u-boot-stm32mp-t1001-trusted.stm32
-PDE	0x06	env	Binary	nor0	0x00180000	none
-PDE	0x07	nor_user	Binary	nor0	0x00190000	none
diff --git a/conf/machine/cubemx/stm32mp1-t1000-s-24/stm32mp1-t1000-s-24.ioc b/conf/machine/cubemx/stm32mp1-t1000-s-24/stm32mp1-t1000-s-24.ioc
deleted file mode 100644
index b163040576c227ecb0b9fcdc41f03b9998a2a2b4..0000000000000000000000000000000000000000
--- a/conf/machine/cubemx/stm32mp1-t1000-s-24/stm32mp1-t1000-s-24.ioc
+++ /dev/null
@@ -1,1097 +0,0 @@
-#MicroXplorer Configuration settings - do not modify
-ADC1.Channel-0\#ChannelRegularConversion=ADC_CHANNEL_5
-ADC1.IPParameters=Rank-0\#ChannelRegularConversion,Channel-0\#ChannelRegularConversion,SamplingTime-0\#ChannelRegularConversion,OffsetNumber-0\#ChannelRegularConversion,NbrOfConversionFlag,master
-ADC1.NbrOfConversionFlag=1
-ADC1.OffsetNumber-0\#ChannelRegularConversion=ADC_OFFSET_NONE
-ADC1.Rank-0\#ChannelRegularConversion=1
-ADC1.SamplingTime-0\#ChannelRegularConversion=ADC_SAMPLETIME_1CYCLE_5
-ADC1.master=1
-BootLoader.IPs=RCC,QUADSPI,SDMMC1,SDMMC2,UART4,USB_OTG_HS
-BootROM.IPs=RCC,SDMMC1\:I,UART4\:I
-CortexA7NS.IPs=BSEC,DDR\:I,ETZPC,HSEM\:I,IPCC\:I,PWR,RCC\:I,RTC,TAMP\:I,DMA\:I,GIC,ADC1\:I,ADC2\:I,TIM4\:I,ETH1\:I,FDCAN1\:I,I2C2\:I,I2C4\:I,QUADSPI\:I,SDMMC1,SDMMC2\:I,UART4,USART2\:I,USART6\:I,USBH_HS1\:I,USB_OTG_HS\:I,GPU\:I,TIM1\:I,CRYP1\:I,HASH1\:I,RNG1,I2S2\:I,SPI2\:I,CRC1\:I,DEBUG\:I,DTS\:I,VREFBUF\:I,SPI1\:I,I2S1\:I,DMA1\:I,MDMA_A7NS\:I
-CortexA7S.IPs=BSEC\:I,ETZPC\:I,PWR\:I,RCC,RNG1\:I,RTC\:I,GIC\:I,MDMA_A7S\:I
-CortexM4.IPs=HSEM,IPCC,ETZPC,FREERTOS\:I,PWR,RCC,SYS\:I,DMA,NVIC\:I,DMA2\:I
-DDR.0dqdly0=1
-DDR.0dqdly1=0
-DDR.0dqdly2=0
-DDR.0dqdly3=0
-DDR.0dqdly4=1
-DDR.0dqdly5=0
-DDR.0dqdly6=1
-DDR.0dqdly7=1
-DDR.0dqsdly=2
-DDR.0dqsndly=2
-DDR.1dqdly0=0
-DDR.1dqdly1=0
-DDR.1dqdly2=1
-DDR.1dqdly3=0
-DDR.1dqdly4=1
-DDR.1dqdly5=0
-DDR.1dqdly6=0
-DDR.1dqdly7=0
-DDR.ADDRMAP1=0x00070707
-DDR.ADDRMAP3=0x1F000000
-DDR.ADDRMAP5=0x06060606
-DDR.ADDRMAP6=0x0F060606
-DDR.CL=7
-DDR.DDR_Frequency=528.0
-DDR.DFITMG0=0x02050105
-DDR.DRAMTMG0=0x121B1214
-DDR.DRAMTMG1=0x000A041B
-DDR.DRAMTMG2=0x0607080F
-DDR.DRAMTMG4=0x07040607
-DDR.DTPR0=0x36D477D0
-DDR.DTPR1=0x098A00D8
-DDR.DX0DQSTR=0x3D202000
-DDR.DX0DQTR=0x55050005
-DDR.DX1DQTR=0x00050500
-DDR.IPParameters=DDR_Frequency,CL,addrmap_col_b9,addrmap_col_b10,addrmap_col_b11,addrmap_bank_b0,addrmap_bank_b1,addrmap_bank_b2,addrmap_row_b0,addrmap_row_b1,addrmap_row_b2_10,addrmap_row_b11,addrmap_row_b12,addrmap_row_b13,addrmap_row_b14,addrmap_row_b15,MSTR,RFSHTMG,DRAMTMG1,DRAMTMG2,DRAMTMG4,SCHED,ADDRMAP1,ADDRMAP3,ADDRMAP5,ADDRMAP6,PTR0,PTR1,PTR2,DTPR0,DTPR1,MR0,SPEED_BIN_GRADE,tRCD,tRP,tRC,wr2pre,t_faw,t_ras_max,t_ras_min,t_xp,t_rd2pre,t_rp,t_rc,write_latency,read_latency,wr2rd,t_rcd,t_rrd,t_cksrx,t_cksre,t_ckesr,t_cke,t_xs_dll_x32,t_xs_x32,t_rfc_nom_x1_x32,t_rfc_min,dfi_t_rddata_en,dfi_tphy_wrlat,tdlllock,tdllsrst,tdinit1,tdinit0,tdinit2,tccd,trc,trrd,tras,trcd,trp,twtr,trtp,tmrd,trfc,tmod,tfaw,tdllk,tcke,txp,txs,MR0.WR,MR0.CL,MR2.RTT,MR2.CWL,data_bus_width,DFITMG0,TEMPERATURE_OVER_85C,tREFI,DRAMTMG0,MR2,0dqsndly,0dqsdly,0dqdly0,0dqdly1,0dqdly2,0dqdly3,0dqdly4,0dqdly5,0dqdly6,0dqdly7,1dqdly0,1dqdly1,1dqdly2,1dqdly3,1dqdly4,1dqdly5,1dqdly6,1dqdly7,DX0DQTR,DX0DQSTR,DX1DQTR
-DDR.MR0=0x00000830
-DDR.MR0.CL=3
-DDR.MR0.WR=4
-DDR.MR2=0x00000248
-DDR.MR2.CWL=1
-DDR.MR2.RTT=1
-DDR.MSTR=0x00041401
-DDR.PTR0=0x0022A41B
-DDR.PTR1=0x047C0740
-DDR.PTR2=0x042D9C80
-DDR.RFSHTMG=0x0040008A
-DDR.SCHED=0x00000C01
-DDR.SPEED_BIN_GRADE=SPEED BIN GRADE CONFIG1
-DDR.TEMPERATURE_OVER_85C=true
-DDR.addrmap_bank_b0=7
-DDR.addrmap_bank_b1=7
-DDR.addrmap_bank_b2=7
-DDR.addrmap_col_b10=31
-DDR.addrmap_col_b11=31
-DDR.addrmap_col_b9=31
-DDR.addrmap_row_b0=6
-DDR.addrmap_row_b1=6
-DDR.addrmap_row_b11=6
-DDR.addrmap_row_b12=6
-DDR.addrmap_row_b13=6
-DDR.addrmap_row_b14=6
-DDR.addrmap_row_b15=15
-DDR.addrmap_row_b2_10=6
-DDR.data_bus_width=1
-DDR.dfi_t_rddata_en=5
-DDR.dfi_tphy_wrlat=5
-DDR.read_latency=7
-DDR.tRC=50.625
-DDR.tRCD=13.125
-DDR.tREFI=3.9
-DDR.tRP=13.125
-DDR.t_cke=3
-DDR.t_ckesr=4
-DDR.t_cksre=6
-DDR.t_cksrx=6
-DDR.t_faw=27
-DDR.t_ras_max=18
-DDR.t_ras_min=20
-DDR.t_rc=27
-DDR.t_rcd=7
-DDR.t_rd2pre=4
-DDR.t_rfc_min=138
-DDR.t_rfc_nom_x1_x32=64
-DDR.t_rp=7
-DDR.t_rrd=6
-DDR.t_xp=10
-DDR.t_xs_dll_x32=16
-DDR.t_xs_x32=5
-DDR.tccd=0
-DDR.tcke=4
-DDR.tdinit0=264000
-DDR.tdinit1=143
-DDR.tdinit2=105600
-DDR.tdllk=512
-DDR.tdlllock=2704
-DDR.tdllsrst=27
-DDR.tfaw=27
-DDR.tmod=0
-DDR.tmrd=0
-DDR.tras=20
-DDR.trc=27
-DDR.trcd=7
-DDR.trfc=138
-DDR.trp=7
-DDR.trrd=6
-DDR.trtp=4
-DDR.twtr=6
-DDR.txp=13
-DDR.txs=512
-DDR.wr2pre=18
-DDR.wr2rd=15
-DDR.write_latency=6
-DDR_A0.Mode=DDR3
-DDR_A0.Signal=DDR_A0
-DDR_A1.Mode=DDR3
-DDR_A1.Signal=DDR_A1
-DDR_A10.Mode=DDR3
-DDR_A10.Signal=DDR_A10
-DDR_A11.Mode=DDR3
-DDR_A11.Signal=DDR_A11
-DDR_A12.Mode=4Gb_16bits
-DDR_A12.Signal=DDR_A12
-DDR_A13.Mode=4Gb_16bits
-DDR_A13.Signal=DDR_A13
-DDR_A14.Mode=4Gb_16bits
-DDR_A14.Signal=DDR_A14
-DDR_A2.Mode=DDR3
-DDR_A2.Signal=DDR_A2
-DDR_A3.Mode=DDR3
-DDR_A3.Signal=DDR_A3
-DDR_A4.Mode=DDR3
-DDR_A4.Signal=DDR_A4
-DDR_A5.Mode=DDR3
-DDR_A5.Signal=DDR_A5
-DDR_A6.Mode=DDR3
-DDR_A6.Signal=DDR_A6
-DDR_A7.Mode=DDR3
-DDR_A7.Signal=DDR_A7
-DDR_A8.Mode=DDR3
-DDR_A8.Signal=DDR_A8
-DDR_A9.Mode=DDR3
-DDR_A9.Signal=DDR_A9
-DDR_ATO.Mode=DDR3
-DDR_ATO.Signal=DDR_ATO
-DDR_BA0.Mode=DDR3
-DDR_BA0.Signal=DDR_BA0
-DDR_BA1.Mode=DDR3
-DDR_BA1.Signal=DDR_BA1
-DDR_BA2.Mode=DDR3
-DDR_BA2.Signal=DDR_BA2
-DDR_CASN.Mode=DDR3
-DDR_CASN.Signal=DDR_CASN
-DDR_CKE.Mode=DDR3
-DDR_CKE.Signal=DDR_CKE
-DDR_CLKN.Mode=DDR3
-DDR_CLKN.Signal=DDR_CLKN
-DDR_CLKP.Mode=DDR3
-DDR_CLKP.Signal=DDR_CLKP
-DDR_CSN.Mode=DDR3
-DDR_CSN.Signal=DDR_CSN
-DDR_DQ0.Mode=DDR3
-DDR_DQ0.Signal=DDR_DQ0
-DDR_DQ1.Mode=DDR3
-DDR_DQ1.Signal=DDR_DQ1
-DDR_DQ10.Mode=DDR3
-DDR_DQ10.Signal=DDR_DQ10
-DDR_DQ11.Mode=DDR3
-DDR_DQ11.Signal=DDR_DQ11
-DDR_DQ12.Mode=DDR3
-DDR_DQ12.Signal=DDR_DQ12
-DDR_DQ13.Mode=DDR3
-DDR_DQ13.Signal=DDR_DQ13
-DDR_DQ14.Mode=DDR3
-DDR_DQ14.Signal=DDR_DQ14
-DDR_DQ15.Mode=DDR3
-DDR_DQ15.Signal=DDR_DQ15
-DDR_DQ2.Mode=DDR3
-DDR_DQ2.Signal=DDR_DQ2
-DDR_DQ3.Mode=DDR3
-DDR_DQ3.Signal=DDR_DQ3
-DDR_DQ4.Mode=DDR3
-DDR_DQ4.Signal=DDR_DQ4
-DDR_DQ5.Mode=DDR3
-DDR_DQ5.Signal=DDR_DQ5
-DDR_DQ6.Mode=DDR3
-DDR_DQ6.Signal=DDR_DQ6
-DDR_DQ7.Mode=DDR3
-DDR_DQ7.Signal=DDR_DQ7
-DDR_DQ8.Mode=DDR3
-DDR_DQ8.Signal=DDR_DQ8
-DDR_DQ9.Mode=DDR3
-DDR_DQ9.Signal=DDR_DQ9
-DDR_DQM0.Mode=DDR3
-DDR_DQM0.Signal=DDR_DQM0
-DDR_DQM1.Mode=DDR3
-DDR_DQM1.Signal=DDR_DQM1
-DDR_DQS0N.Mode=DDR3
-DDR_DQS0N.Signal=DDR_DQS0N
-DDR_DQS0P.Mode=DDR3
-DDR_DQS0P.Signal=DDR_DQS0P
-DDR_DQS1N.Mode=DDR3
-DDR_DQS1N.Signal=DDR_DQS1N
-DDR_DQS1P.Mode=DDR3
-DDR_DQS1P.Signal=DDR_DQS1P
-DDR_DTO0.Mode=DDR3
-DDR_DTO0.Signal=DDR_DTO0
-DDR_DTO1.Mode=DDR3
-DDR_DTO1.Signal=DDR_DTO1
-DDR_ODT.Mode=DDR3
-DDR_ODT.Signal=DDR_ODT
-DDR_RASN.Mode=DDR3
-DDR_RASN.Signal=DDR_RASN
-DDR_RESETN.Mode=DDR3
-DDR_RESETN.Signal=DDR_RESETN
-DDR_VREF.Mode=DDR3
-DDR_VREF.Signal=DDR_VREF
-DDR_WEN.Mode=DDR3
-DDR_WEN.Signal=DDR_WEN
-DDR_ZQ.Mode=DDR3
-DDR_ZQ.Signal=DDR_ZQ
-File.Version=6
-GIC.ADC1_IRQn=true\:false\:High level
-GIC.CRYP1_IRQn=true\:false\:High level
-GIC.DTS_IRQn=true\:false\:High level
-GIC.ETH1_IRQn=true\:false\:High level
-GIC.ETH1_WKUP_IRQn=true\:false\:High level
-GIC.FDCAN1_IT0_IRQn=true\:false\:High level
-GIC.FDCAN1_IT1_IRQn=true\:false\:High level
-GIC.GPU_IRQn=true\:false\:High level
-GIC.HASH1_IRQn=true\:false\:High level
-GIC.I2C2_ER_IRQn=true\:false\:High level
-GIC.I2C2_EV_IRQn=true\:false\:High level
-GIC.I2C4_ER_IRQn=true\:false\:High level
-GIC.I2C4_EV_IRQn=true\:false\:High level
-GIC.IPCC_RX0_IRQn=true\:false\:High level
-GIC.IPCC_TX0_IRQn=true\:false\:High level
-GIC.OTG_IRQn=true\:false\:High level
-GIC.PMUIRQ0_IRQn=true\:false\:High level
-GIC.PMUIRQ1_IRQn=true\:false\:High level
-GIC.QUADSPI_IRQn=true\:false\:High level
-GIC.RCC_IRQn=true\:false\:High level
-GIC.RTC_WKUP_ALARM_IRQn=true\:false\:High level
-GIC.SDMMC1_IRQn=true\:false\:High level
-GIC.SDMMC2_IRQn=true\:false\:High level
-GIC.SPI1_IRQn=true\:false\:High level
-GIC.SPI2_IRQn=true\:false\:High level
-GIC.UART4_IRQn=true\:false\:High level
-GIC.USART2_IRQn=true\:false\:High level
-GIC.USART6_IRQn=true\:false\:High level
-GIC.USBH_OHCI_IRQn=true\:false\:High level
-I2S2.ErrorAudioFreq=1.72 %
-I2S2.FullDuplexMode=I2S_MODE_MASTER_FD
-I2S2.IPParameters=Instance,VirtualMode,FullDuplexMode,RealAudioFreq,ErrorAudioFreq
-I2S2.Instance=SPI$Index
-I2S2.RealAudioFreq=8.138 KHz
-I2S2.VirtualMode=I2S_MODE_MASTER
-JTCK-SWCLK.Mode=JTAG_4_pins
-JTCK-SWCLK.Signal=DEBUG_JTCK-SWCLK
-JTDI.Mode=JTAG_4_pins
-JTDI.Signal=DEBUG_JTDI
-JTDO-TRACESWO.Mode=JTAG_4_pins
-JTDO-TRACESWO.Signal=DEBUG_JTDO-SWO
-JTMS-SWDIO.Mode=JTAG_4_pins
-JTMS-SWDIO.Signal=DEBUG_JTMS-SWDIO
-KeepUserPlacement=true
-Mcu.Context0=BootROM
-Mcu.Context1=BootLoader
-Mcu.Context2=CortexA7S
-Mcu.Context3=CortexA7NS
-Mcu.Context4=CortexM4
-Mcu.ContextNb=5
-Mcu.Family=STM32MP1
-Mcu.IP0=ADC1
-Mcu.IP1=BSEC
-Mcu.IP10=GIC
-Mcu.IP11=GPU
-Mcu.IP12=HASH1
-Mcu.IP13=HSEM
-Mcu.IP14=I2C2
-Mcu.IP15=I2C4
-Mcu.IP16=I2S2
-Mcu.IP17=IPCC
-Mcu.IP18=NVIC
-Mcu.IP19=QUADSPI
-Mcu.IP2=CRC1
-Mcu.IP20=RCC
-Mcu.IP21=RNG1
-Mcu.IP22=RTC
-Mcu.IP23=SDMMC1
-Mcu.IP24=SDMMC2
-Mcu.IP25=SPI1
-Mcu.IP26=SYS
-Mcu.IP27=TIM1
-Mcu.IP28=TIM4
-Mcu.IP29=UART4
-Mcu.IP3=CRYP1
-Mcu.IP30=USART2
-Mcu.IP31=USART6
-Mcu.IP32=USBH_HS1
-Mcu.IP33=USB_OTG_HS
-Mcu.IP34=VREFBUF
-Mcu.IP4=DDR
-Mcu.IP5=DEBUG
-Mcu.IP6=DTS
-Mcu.IP7=ETH1
-Mcu.IP8=ETZPC
-Mcu.IP9=FDCAN1
-Mcu.IPNb=35
-Mcu.Name=STM32MP157CADx
-Mcu.Package=TFBGA257
-Mcu.Pin0=PD1
-Mcu.Pin1=PB7
-Mcu.Pin10=PG15
-Mcu.Pin100=PB12
-Mcu.Pin101=PB8
-Mcu.Pin102=PB5
-Mcu.Pin103=PG8
-Mcu.Pin104=PE7
-Mcu.Pin105=PF8
-Mcu.Pin106=PF9
-Mcu.Pin107=USB_DP2
-Mcu.Pin108=PE10
-Mcu.Pin109=PB2
-Mcu.Pin11=PD7
-Mcu.Pin110=USB_DP1
-Mcu.Pin111=PA12
-Mcu.Pin112=DDR_DQ15
-Mcu.Pin113=DDR_DQM1
-Mcu.Pin114=DDR_DQS1P
-Mcu.Pin115=PA7
-Mcu.Pin116=PA6
-Mcu.Pin117=PF7
-Mcu.Pin118=PG9
-Mcu.Pin119=USB_DM2
-Mcu.Pin12=PA15
-Mcu.Pin120=PB6
-Mcu.Pin121=USB_DM1
-Mcu.Pin122=DDR_VREF
-Mcu.Pin123=DDR_DQ12
-Mcu.Pin124=DDR_DQ11
-Mcu.Pin125=PE1
-Mcu.Pin126=PD10
-Mcu.Pin127=PE3
-Mcu.Pin128=PB14
-Mcu.Pin129=PD2
-Mcu.Pin13=PG6
-Mcu.Pin130=DDR_ZQ
-Mcu.Pin131=DDR_A7
-Mcu.Pin132=PD6
-Mcu.Pin133=PE14
-Mcu.Pin134=PC12
-Mcu.Pin135=PD9
-Mcu.Pin136=PD15
-Mcu.Pin137=DDR_DTO1
-Mcu.Pin138=DDR_A5
-Mcu.Pin139=DDR_DTO0
-Mcu.Pin14=PB4
-Mcu.Pin140=PD14
-Mcu.Pin141=DDR_RASN
-Mcu.Pin142=DDR_ATO
-Mcu.Pin143=DDR_A6
-Mcu.Pin144=PA5
-Mcu.Pin145=PA4
-Mcu.Pin146=PB13
-Mcu.Pin147=PE9
-Mcu.Pin148=PF10
-Mcu.Pin149=VP_BSEC_VS_BSEC
-Mcu.Pin15=PC9
-Mcu.Pin150=VP_CRC1_VS_CRC
-Mcu.Pin151=VP_CRYP1_VS_CRYP
-Mcu.Pin152=VP_DDR_DDR3
-Mcu.Pin153=VP_DDR_DDR_16_bits
-Mcu.Pin154=VP_DDR_DDR3_16_4Gb
-Mcu.Pin155=VP_DTS_VS_DTS
-Mcu.Pin156=VP_ETZPC_VS_ETZPC
-Mcu.Pin157=VP_GPU_VS_GPU
-Mcu.Pin158=VP_HASH1_VS_HASH
-Mcu.Pin159=VP_HSEM_VS_HSEM
-Mcu.Pin16=PC10
-Mcu.Pin160=VP_IPCC_VS_IPCC
-Mcu.Pin161=VP_RNG1_VS_RNG
-Mcu.Pin162=VP_RTC_VS_RTC_Activate
-Mcu.Pin163=VP_SYS_VS_Systick
-Mcu.Pin164=VP_VREFBUF_VS_VREFBUF
-Mcu.Pin165=VP_DMA_VS_DMA1_A7NS
-Mcu.Pin166=VP_DMA_VS_DMA2_M4
-Mcu.Pin167=VP_MDMA_VS_MDMA_A7NS_8
-Mcu.Pin17=JTDI
-Mcu.Pin18=DDR_DQ3
-Mcu.Pin19=DDR_DQ7
-Mcu.Pin2=PC6
-Mcu.Pin20=DDR_DQS0N
-Mcu.Pin21=DDR_DQS0P
-Mcu.Pin22=PE12
-Mcu.Pin23=PD4
-Mcu.Pin24=PD5
-Mcu.Pin25=PD0
-Mcu.Pin26=PA9
-Mcu.Pin27=PB3
-Mcu.Pin28=PB15
-Mcu.Pin29=PB9
-Mcu.Pin3=PD3
-Mcu.Pin30=PC11
-Mcu.Pin31=JTMS-SWDIO
-Mcu.Pin32=DDR_RESETN
-Mcu.Pin33=DDR_DQM0
-Mcu.Pin34=DDR_DQ2
-Mcu.Pin35=DDR_DQ6
-Mcu.Pin36=PG12
-Mcu.Pin37=DDR_DQ4
-Mcu.Pin38=DDR_DQ5
-Mcu.Pin39=PD8
-Mcu.Pin4=PC8
-Mcu.Pin40=PE13
-Mcu.Pin41=DDR_A13
-Mcu.Pin42=DDR_A9
-Mcu.Pin43=PC15-OSC32_OUT
-Mcu.Pin44=DDR_A2
-Mcu.Pin45=DDR_A3
-Mcu.Pin46=PC14-OSC32_IN
-Mcu.Pin47=DDR_A0
-Mcu.Pin48=DDR_BA0
-Mcu.Pin49=PH0-OSC_IN
-Mcu.Pin5=PE4
-Mcu.Pin50=DDR_BA2
-Mcu.Pin51=DDR_ODT
-Mcu.Pin52=PH1-OSC_OUT
-Mcu.Pin53=DDR_CSN
-Mcu.Pin54=DDR_WEN
-Mcu.Pin55=DDR_CASN
-Mcu.Pin56=DDR_CLKN
-Mcu.Pin57=PA14
-Mcu.Pin58=PA13
-Mcu.Pin59=DDR_CLKP
-Mcu.Pin6=JTDO-TRACESWO
-Mcu.Pin60=DDR_A10
-Mcu.Pin61=DDR_A12
-Mcu.Pin62=DDR_A1
-Mcu.Pin63=PA3
-Mcu.Pin64=PA0
-Mcu.Pin65=DDR_A14
-Mcu.Pin66=DDR_A11
-Mcu.Pin67=PE2
-Mcu.Pin68=PC2
-Mcu.Pin69=PC3
-Mcu.Pin7=JTCK-SWCLK
-Mcu.Pin70=DDR_CKE
-Mcu.Pin71=DDR_BA1
-Mcu.Pin72=PG14
-Mcu.Pin73=PG13
-Mcu.Pin74=DDR_A4
-Mcu.Pin75=DDR_DQ8
-Mcu.Pin76=PA1
-Mcu.Pin77=PC1
-Mcu.Pin78=PA2
-Mcu.Pin79=DDR_A8
-Mcu.Pin8=DDR_DQ0
-Mcu.Pin80=DDR_DQ13
-Mcu.Pin81=DDR_DQ10
-Mcu.Pin82=PB1
-Mcu.Pin83=PB0
-Mcu.Pin84=PB11
-Mcu.Pin85=PC0
-Mcu.Pin86=PG11
-Mcu.Pin87=PG10
-Mcu.Pin88=PD11
-Mcu.Pin89=PF6
-Mcu.Pin9=DDR_DQ1
-Mcu.Pin90=PE8
-Mcu.Pin91=PD13
-Mcu.Pin92=PD12
-Mcu.Pin93=PA11
-Mcu.Pin94=PA10
-Mcu.Pin95=DDR_DQ14
-Mcu.Pin96=DDR_DQS1N
-Mcu.Pin97=DDR_DQ9
-Mcu.Pin98=PC5
-Mcu.Pin99=PC4
-Mcu.PinsNb=168
-Mcu.ThirdPartyNb=0
-Mcu.UserConstants=
-Mcu.UserName=STM32MP157CADx
-MxCube.Version=5.1.0
-MxDb.Version=DB.5.0.10
-NVIC.BusFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false
-NVIC.DebugMonitor_IRQn=true\:0\:0\:false\:false\:true\:false\:false
-NVIC.HardFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false
-NVIC.MemoryManagement_IRQn=true\:0\:0\:false\:false\:true\:false\:false
-NVIC.NonMaskableInt_IRQn=true\:0\:0\:false\:false\:true\:false\:false
-NVIC.PendSV_IRQn=true\:0\:0\:false\:false\:true\:false\:false
-NVIC.PriorityGroup=NVIC_PRIORITYGROUP_4
-NVIC.SVCall_IRQn=true\:0\:0\:false\:false\:true\:false\:false
-NVIC.SysTick_IRQn=true\:0\:0\:false\:false\:true\:false\:true
-NVIC.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false
-PA0.Mode=IN16-Single-Ended
-PA0.Signal=ADC1_INP16
-PA1.GPIOParameters=GPIO_Label
-PA1.GPIO_Label=DISP_MESH
-PA1.Locked=true
-PA1.Signal=GPIO_Input
-PA10.Mode=Ext_Phy_OTG/Dual-Role-Device
-PA10.Signal=USB_OTG_HS_ID
-PA11.Locked=true
-PA11.Mode=Full_Duplex_Master
-PA11.Signal=I2S2_WS
-PA12.GPIOParameters=GPIO_Label
-PA12.GPIO_Label=DISP_LPTE
-PA12.Locked=true
-PA12.Signal=GPIO_Input
-PA13.GPIOParameters=GPIO_Label
-PA13.GPIO_Label=LED1
-PA13.Locked=true
-PA13.Signal=GPIO_Output
-PA14.GPIOParameters=GPIO_Label
-PA14.GPIO_Label=LED2
-PA14.Locked=true
-PA14.Signal=GPIO_Output
-PA15.GPIOParameters=GPIO_Label
-PA15.GPIO_Label=DISP_RST
-PA15.Locked=true
-PA15.Signal=GPIO_Output
-PA2.Locked=true
-PA2.Mode=RMII (Reduced MII)
-PA2.Signal=ETH1_MDIO
-PA3.GPIOParameters=GPIO_Label
-PA3.GPIO_Label=PAD_PA3
-PA3.Locked=true
-PA3.Signal=GPIO_Input
-PA4.GPIOParameters=GPIO_Label
-PA4.GPIO_Label=PAD_PA4
-PA4.Locked=true
-PA4.Signal=GPIO_Input
-PA5.Locked=true
-PA5.Mode=Full_Duplex_Master
-PA5.Signal=SPI1_SCK
-PA6.Locked=true
-PA6.Mode=Full_Duplex_Master
-PA6.Signal=SPI1_MISO
-PA7.Locked=true
-PA7.Mode=RMII (Reduced MII)
-PA7.Signal=ETH1_CRS_DV
-PA9.Locked=true
-PA9.Signal=S_TIM1_CH2
-PB0.GPIOParameters=GPIO_Label
-PB0.GPIO_Label=SPI1_CS
-PB0.Locked=true
-PB0.Signal=GPIO_Output
-PB1.Signal=ADCx_INP5
-PB11.Mode=RMII (Reduced MII)
-PB11.Signal=ETH1_TX_EN
-PB12.Locked=true
-PB12.Mode=RMII (Reduced MII)
-PB12.Signal=ETH1_TXD0
-PB13.Mode=RMII (Reduced MII)
-PB13.Signal=ETH1_TXD1
-PB14.GPIOParameters=GPIO_PuPd,GPIO_Speed_Medium_Default,GPIO_Mode
-PB14.GPIO_Mode=GPIO_MODE_AF_PP
-PB14.GPIO_PuPd=GPIO_PULLUP
-PB14.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_MEDIUM
-PB14.Locked=true
-PB14.Mode=SD_4_bits_Wide_bus
-PB14.Signal=SDMMC2_D0
-PB15.GPIOParameters=GPIO_PuPd,GPIO_Speed_Medium_Default,GPIO_Mode
-PB15.GPIO_Mode=GPIO_MODE_AF_PP
-PB15.GPIO_PuPd=GPIO_PULLUP
-PB15.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_MEDIUM
-PB15.Mode=SD_4_bits_Wide_bus
-PB15.Signal=SDMMC2_D1
-PB2.GPIOParameters=GPIO_ModePuPdOnly,GPIO_PuPd,GPIO_Label
-PB2.GPIO_Label=Console
-PB2.GPIO_ModePuPdOnly=GPIO_MODE_AF
-PB2.GPIO_PuPd=GPIO_PULLUP
-PB2.Locked=true
-PB2.Mode=Asynchronous
-PB2.Signal=UART4_RX
-PB3.GPIOParameters=GPIO_PuPd,GPIO_Speed_Medium_Default,GPIO_Mode
-PB3.GPIO_Mode=GPIO_MODE_AF_PP
-PB3.GPIO_PuPd=GPIO_PULLUP
-PB3.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_MEDIUM
-PB3.Mode=SD_4_bits_Wide_bus
-PB3.Signal=SDMMC2_D2
-PB4.GPIOParameters=GPIO_PuPd,GPIO_Speed_Medium_Default,GPIO_Mode
-PB4.GPIO_Mode=GPIO_MODE_AF_PP
-PB4.GPIO_PuPd=GPIO_PULLUP
-PB4.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_MEDIUM
-PB4.Mode=SD_4_bits_Wide_bus
-PB4.Signal=SDMMC2_D3
-PB5.Locked=true
-PB5.Mode=Full_Duplex_Master
-PB5.Signal=SPI1_MOSI
-PB6.GPIOParameters=GPIO_PuPd,GPIO_Speed_Medium_Default,GPIO_Mode
-PB6.GPIO_Mode=GPIO_MODE_AF_PP
-PB6.GPIO_PuPd=GPIO_PULLUP
-PB6.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_VERY_HIGH
-PB6.Locked=true
-PB6.Mode=Enable Chip Select for each bank
-PB6.Signal=QUADSPI_BK1_NCS
-PB7.Mode=I2C
-PB7.Signal=I2C4_SDA
-PB8.GPIOParameters=GPIO_Label
-PB8.GPIO_Label=PAD_PB8
-PB8.Locked=true
-PB8.Signal=GPIO_Input
-PB9.GPIOParameters=GPIO_Label
-PB9.GPIO_Label=PAD_PB9
-PB9.Locked=true
-PB9.Signal=GPIO_Input
-PC0.GPIOParameters=GPIO_PuPd,GPIO_Speed_Medium_Default
-PC0.GPIO_PuPd=GPIO_PULLUP
-PC0.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_VERY_HIGH
-PC0.Locked=true
-PC0.Mode=Enable Chip Select for each bank
-PC0.Signal=QUADSPI_BK2_NCS
-PC1.Mode=RMII (Reduced MII)
-PC1.Signal=ETH1_MDC
-PC10.GPIOParameters=GPIO_PuPd,GPIO_Speed_Medium_Default,GPIO_Mode
-PC10.GPIO_Mode=GPIO_MODE_AF_PP
-PC10.GPIO_PuPd=GPIO_PULLUP
-PC10.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_MEDIUM
-PC10.Locked=true
-PC10.Mode=SD_4_bits_Wide_bus
-PC10.Signal=SDMMC1_D2
-PC11.GPIOParameters=GPIO_PuPd,GPIO_Speed_Medium_Default,GPIO_Mode
-PC11.GPIO_Mode=GPIO_MODE_AF_PP
-PC11.GPIO_PuPd=GPIO_PULLUP
-PC11.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_MEDIUM
-PC11.Mode=SD_4_bits_Wide_bus
-PC11.Signal=SDMMC1_D3
-PC12.GPIOParameters=GPIO_PuPd,GPIO_Speed_High_Default,GPIO_Mode
-PC12.GPIO_Mode=GPIO_MODE_AF_PP
-PC12.GPIO_PuPd=GPIO_PULLUP
-PC12.GPIO_Speed_High_Default=GPIO_SPEED_FREQ_VERY_HIGH
-PC12.Mode=SD_4_bits_Wide_bus
-PC12.Signal=SDMMC1_CK
-PC14-OSC32_IN.Mode=LSE-External-Oscillator
-PC14-OSC32_IN.Signal=RCC_OSC32_IN
-PC15-OSC32_OUT.Mode=LSE-External-Oscillator
-PC15-OSC32_OUT.Signal=RCC_OSC32_OUT
-PC2.Locked=true
-PC2.Mode=Full_Duplex_Master
-PC2.Signal=I2S2_SDI
-PC3.Locked=true
-PC3.Mode=Full_Duplex_Master
-PC3.Signal=I2S2_SDO
-PC4.Mode=RMII (Reduced MII)
-PC4.Signal=ETH1_RXD0
-PC5.Mode=RMII (Reduced MII)
-PC5.Signal=ETH1_RXD1
-PC6.GPIOParameters=GPIO_Label
-PC6.GPIO_Label=PAD_PC6
-PC6.Locked=true
-PC6.Signal=GPIO_Input
-PC8.GPIOParameters=GPIO_PuPd,GPIO_Speed_Medium_Default,GPIO_Mode
-PC8.GPIO_Mode=GPIO_MODE_AF_PP
-PC8.GPIO_PuPd=GPIO_PULLUP
-PC8.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_MEDIUM
-PC8.Mode=SD_4_bits_Wide_bus
-PC8.Signal=SDMMC1_D0
-PC9.GPIOParameters=GPIO_PuPd,GPIO_Speed_Medium_Default,GPIO_Mode
-PC9.GPIO_Mode=GPIO_MODE_AF_PP
-PC9.GPIO_PuPd=GPIO_PULLUP
-PC9.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_MEDIUM
-PC9.Mode=SD_4_bits_Wide_bus
-PC9.Signal=SDMMC1_D1
-PCC.Checker=false
-PCC.Line=STM32MP157
-PCC.MCU=STM32MP157CADx
-PCC.PartNumber=STM32MP157CADx
-PCC.Seq0=0
-PCC.Series=STM32MP1
-PCC.Temperature=0
-PCC.Vdd=null
-PD0.Mode=FDCANMaster
-PD0.Signal=FDCAN1_RX
-PD1.GPIOParameters=GPIO_Speed,GPIO_PuPd,GPIO_Mode
-PD1.GPIO_Mode=GPIO_MODE_AF_PP
-PD1.GPIO_PuPd=GPIO_NOPULL
-PD1.GPIO_Speed=GPIO_SPEED_FREQ_LOW
-PD1.Mode=FDCANMaster
-PD1.Signal=FDCAN1_TX
-PD10.GPIOParameters=GPIO_Label
-PD10.GPIO_Label=PAD_PD10
-PD10.Locked=true
-PD10.Signal=GPIO_Input
-PD11.GPIOParameters=GPIO_Label
-PD11.GPIO_Label=TOUCH_WAKE
-PD11.Locked=true
-PD11.Signal=GPIO_Input
-PD12.GPIOParameters=GPIO_Label
-PD12.GPIO_Label=USB_OVR
-PD12.Locked=true
-PD12.Signal=GPIO_Input
-PD13.Locked=true
-PD13.Signal=DSIHOST_TE
-PD14.GPIOParameters=GPIO_ModeDefaultPP,GPIO_Speed,GPIO_PuPd
-PD14.GPIO_ModeDefaultPP=GPIO_MODE_AF_PP
-PD14.GPIO_PuPd=GPIO_NOPULL
-PD14.GPIO_Speed=GPIO_SPEED_FREQ_LOW
-PD14.Locked=true
-PD14.Signal=S_TIM4_CH3
-PD15.GPIOParameters=GPIO_Label
-PD15.GPIO_Label=RESET_OUT
-PD15.Locked=true
-PD15.Signal=GPIO_Output
-PD2.GPIOParameters=GPIO_PuPd,GPIO_Speed_Medium_Default,GPIO_Mode
-PD2.GPIO_Mode=GPIO_MODE_AF_PP
-PD2.GPIO_PuPd=GPIO_PULLUP
-PD2.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_MEDIUM
-PD2.Mode=SD_4_bits_Wide_bus
-PD2.Signal=SDMMC1_CMD
-PD3.Locked=true
-PD3.Mode=Full_Duplex_Master
-PD3.Signal=I2S2_CK
-PD4.GPIOParameters=GPIO_Speed,GPIO_PuPd,GPIO_Mode
-PD4.GPIO_Mode=GPIO_MODE_AF_PP
-PD4.GPIO_PuPd=GPIO_PULLDOWN
-PD4.GPIO_Speed=GPIO_SPEED_FREQ_LOW
-PD4.Mode=RTS_Only
-PD4.Signal=USART2_RTS
-PD5.GPIOParameters=GPIO_ModeDefaultPP,GPIO_Speed,GPIO_PuPd
-PD5.GPIO_ModeDefaultPP=GPIO_MODE_AF_PP
-PD5.GPIO_PuPd=GPIO_PULLUP
-PD5.GPIO_Speed=GPIO_SPEED_FREQ_LOW
-PD5.Mode=Asynchronous
-PD5.Signal=USART2_TX
-PD6.GPIOParameters=GPIO_ModePuPdOnly,GPIO_PuPd
-PD6.GPIO_ModePuPdOnly=GPIO_MODE_AF
-PD6.GPIO_PuPd=GPIO_PULLUP
-PD6.Locked=true
-PD6.Mode=Asynchronous
-PD6.Signal=USART2_RX
-PD7.Locked=true
-PD7.Mode=I2C
-PD7.Signal=I2C2_SCL
-PD8.GPIOParameters=GPIO_Label
-PD8.GPIO_Label=LDC_PCTRL
-PD8.Locked=true
-PD8.Signal=GPIO_Output
-PD9.GPIOParameters=GPIO_Label
-PD9.GPIO_Label=TOUCH_INT
-PD9.Locked=true
-PD9.Signal=GPIO_Input
-PE1.Locked=true
-PE1.Mode=Master_Clock_Activated
-PE1.Signal=I2S2_MCK
-PE10.GPIOParameters=GPIO_Speed_Medium_Default
-PE10.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_VERY_HIGH
-PE10.Locked=true
-PE10.Mode=Dual Bank
-PE10.Signal=QUADSPI_BK2_IO3
-PE12.GPIOParameters=GPIO_Label
-PE12.GPIO_Label=PAD_PE12
-PE12.Locked=true
-PE12.Signal=GPIO_Input
-PE13.GPIOParameters=GPIO_Label
-PE13.GPIO_Label=PAD_PE13
-PE13.Locked=true
-PE13.Signal=GPIO_Input
-PE14.GPIOParameters=GPIO_Label
-PE14.GPIO_Label=PAD_PE14
-PE14.Locked=true
-PE14.Signal=GPIO_Input
-PE2.Mode=I2C
-PE2.Signal=I2C4_SCL
-PE3.GPIOParameters=GPIO_PuPd,GPIO_Speed_High_Default,GPIO_Mode
-PE3.GPIO_Mode=GPIO_MODE_AF_PP
-PE3.GPIO_PuPd=GPIO_PULLUP
-PE3.GPIO_Speed_High_Default=GPIO_SPEED_FREQ_VERY_HIGH
-PE3.Mode=SD_4_bits_Wide_bus
-PE3.Signal=SDMMC2_CK
-PE4.GPIOParameters=GPIO_Label
-PE4.GPIO_Label=PAD_PE4
-PE4.Locked=true
-PE4.Signal=GPIO_Input
-PE7.GPIOParameters=GPIO_Speed_Medium_Default
-PE7.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_VERY_HIGH
-PE7.Mode=Dual Bank
-PE7.Signal=QUADSPI_BK2_IO0
-PE8.GPIOParameters=GPIO_Speed_Medium_Default
-PE8.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_VERY_HIGH
-PE8.Mode=Dual Bank
-PE8.Signal=QUADSPI_BK2_IO1
-PE9.GPIOParameters=GPIO_Speed_Medium_Default
-PE9.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_VERY_HIGH
-PE9.Locked=true
-PE9.Mode=Dual Bank
-PE9.Signal=QUADSPI_BK2_IO2
-PF10.GPIOParameters=GPIO_Speed_Medium_Default
-PF10.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_VERY_HIGH
-PF10.Locked=true
-PF10.Mode=Dual Bank
-PF10.Signal=QUADSPI_CLK
-PF6.GPIOParameters=GPIO_Speed_Medium_Default
-PF6.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_VERY_HIGH
-PF6.Mode=Dual Bank
-PF6.Signal=QUADSPI_BK1_IO3
-PF7.GPIOParameters=GPIO_Speed_Medium_Default
-PF7.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_VERY_HIGH
-PF7.Mode=Dual Bank
-PF7.Signal=QUADSPI_BK1_IO2
-PF8.GPIOParameters=GPIO_Speed_Medium_Default
-PF8.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_VERY_HIGH
-PF8.Locked=true
-PF8.Mode=Dual Bank
-PF8.Signal=QUADSPI_BK1_IO0
-PF9.GPIOParameters=GPIO_Speed_Medium_Default
-PF9.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_VERY_HIGH
-PF9.Locked=true
-PF9.Mode=Dual Bank
-PF9.Signal=QUADSPI_BK1_IO1
-PG10.GPIOParameters=GPIO_Label
-PG10.GPIO_Label=PAD_PG10
-PG10.Locked=true
-PG10.Signal=GPIO_Input
-PG11.GPIOParameters=GPIO_ModeDefaultPP,GPIO_Speed,GPIO_PuPd,GPIO_Label
-PG11.GPIO_Label=Console
-PG11.GPIO_ModeDefaultPP=GPIO_MODE_AF_PP
-PG11.GPIO_PuPd=GPIO_PULLUP
-PG11.GPIO_Speed=GPIO_SPEED_FREQ_LOW
-PG11.Locked=true
-PG11.Mode=Asynchronous
-PG11.Signal=UART4_TX
-PG12.GPIOParameters=GPIO_Label
-PG12.GPIO_Label=PAD_PG12
-PG12.Locked=true
-PG12.Signal=GPIO_Input
-PG13.GPIOParameters=GPIO_Label
-PG13.GPIO_Label=DISP_A0
-PG13.Locked=true
-PG13.Signal=GPIO_Output
-PG14.GPIOParameters=GPIO_PuPd
-PG14.GPIO_PuPd=GPIO_PULLUP
-PG14.Locked=true
-PG14.Mode=Asynchronous
-PG14.Signal=USART6_TX
-PG15.Locked=true
-PG15.Mode=I2C
-PG15.Signal=I2C2_SDA
-PG6.GPIOParameters=GPIO_PuPd,GPIO_Speed_Medium_Default,GPIO_Mode
-PG6.GPIO_Mode=GPIO_MODE_AF_PP
-PG6.GPIO_PuPd=GPIO_PULLUP
-PG6.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_MEDIUM
-PG6.Mode=SD_4_bits_Wide_bus
-PG6.Signal=SDMMC2_CMD
-PG8.Locked=true
-PG8.Mode=ETH Clock Output (PHY without Quartz)
-PG8.Signal=ETH1_CLK
-PG9.GPIOParameters=GPIO_PuPd
-PG9.GPIO_PuPd=GPIO_PULLUP
-PG9.Locked=true
-PG9.Mode=Asynchronous
-PG9.Signal=USART6_RX
-PH0-OSC_IN.Mode=HSE-External-Oscillator
-PH0-OSC_IN.Signal=RCC_OSC_IN
-PH1-OSC_OUT.Mode=HSE-External-Oscillator
-PH1-OSC_OUT.Signal=RCC_OSC_OUT
-PinOutPanel.CurrentBGAView=Top
-PinOutPanel.RotationAngle=0
-ProjectManager.AskForMigrate=true
-ProjectManager.BackupPrevious=false
-ProjectManager.CompilerOptimize=6
-ProjectManager.ComputerToolchain=false
-ProjectManager.CoupleFile=false
-ProjectManager.CustomerFirmwarePackage=
-ProjectManager.DefaultFWLocation=true
-ProjectManager.DeletePrevious=true
-ProjectManager.DeviceId=STM32MP157CADx
-ProjectManager.DeviceTreeLocation=/home/user/mp1-v1-workspace/DeviceTree/
-ProjectManager.FirmwarePackage=STM32Cube FW_MP1 V1.0.0
-ProjectManager.FreePins=false
-ProjectManager.HalAssertFull=false
-ProjectManager.HeapSize=0x200
-ProjectManager.KeepUserCode=true
-ProjectManager.LastFirmware=false
-ProjectManager.LibraryCopy=1
-ProjectManager.MainLocation=Src
-ProjectManager.NoMain=false
-ProjectManager.PreviousToolchain=SW4STM32
-ProjectManager.ProjectBuild=false
-ProjectManager.ProjectFileName=stm32mp1-t1000-s-24.ioc
-ProjectManager.ProjectName=stm32mp1-t1000-s-24
-ProjectManager.StackSize=0x400
-ProjectManager.TargetToolchain=SW4STM32
-ProjectManager.ToolChainLocation=
-ProjectManager.UnderRoot=true
-ProjectManager.functionlistsort=1-MX_GPIO_Init-GPIO-false-HAL-true,2-SystemClock_Config-RCC-false-HAL-false,3-MX_ETZPC_Init-ETZPC-false-HAL-true,4-MX_IPCC_Init-IPCC-false-HAL-true
-RCC.ADCCLockSelection=RCC_ADCCLKSOURCE_PER
-RCC.ADCFreq_Value=24000000
-RCC.AHB1234Freq_Value=196000000
-RCC.APB1DIV=RCC_APB1_DIV2
-RCC.APB1Freq_Value=98000000
-RCC.APB2DIV=RCC_APB2_DIV2
-RCC.APB2Freq_Value=98000000
-RCC.APB3DIV=RCC_APB3_DIV2
-RCC.APB3Freq_Value=98000000
-RCC.APB4DIV=RCC_APB4_DIV2
-RCC.APB4Freq_Value=132000000
-RCC.APB5DIV=RCC_APB5_DIV4
-RCC.APB5DIVClockFreq_Value=66000000
-RCC.AXICLKFreq_VALUE=264000000
-RCC.AXICLKSource=RCC_AXISSOURCE_PLL2
-RCC.AXIDIVFreq_Value=264000000
-RCC.CECFreq_Value=32768
-RCC.CKPERCLKFreq_VALUE=24000000
-RCC.CKPERCLKSource=RCC_CKPERCLKSOURCE_HSE
-RCC.CSI_VALUE=4000000
-RCC.DACCLKFreq_VALUE=32000
-RCC.DDRCFreq_Value=528000000
-RCC.DDRPERFMFreq_Value=528000000
-RCC.DDRPHYFreq_Value=528000000
-RCC.DFSDFAFreq_Value=50000000
-RCC.DFSDMFreq_Value=196000000
-RCC.DIVM1=3
-RCC.DIVM2=3
-RCC.DIVM3=3
-RCC.DIVM4=6
-RCC.DIVN1=81
-RCC.DIVN2=66
-RCC.DIVN3=98
-RCC.DIVN4=125
-RCC.DIVP1Freq_Value=648000000
-RCC.DIVP2Freq_Value=264000000
-RCC.DIVP3=4
-RCC.DIVP3Freq_Value=196000000
-RCC.DIVP4=10
-RCC.DIVP4Freq_Value=50000000
-RCC.DIVQ1Freq_Value=324000000
-RCC.DIVQ2Freq_Value=264000000
-RCC.DIVQ3Freq_Value=392000000
-RCC.DIVQ4=10
-RCC.DIVQ4Freq_Value=50000000
-RCC.DIVR1Freq_Value=324000000
-RCC.DIVR2=1
-RCC.DIVR2Freq_Value=528000000
-RCC.DIVR3Freq_Value=392000000
-RCC.DIVR4=10
-RCC.DIVR4Freq_Value=50000000
-RCC.DSIFreq_Value=60000000
-RCC.DSIPixelFreq_Value=50000000
-RCC.DSITXEscFreq_Value=15000000
-RCC.DSI_VALUE=60000000
-RCC.ETHFreq_Value=50000000
-RCC.FDCANFreq_Value=24000000
-RCC.FMCFreq_Value=264000000
-RCC.FamilyName=M
-RCC.HSE_Timout=100
-RCC.HSE_VALUE=24000000
-RCC.HSIDivClkFreq_Value=64000000
-RCC.HSI_VALUE=64000000
-RCC.Hclk5DIVFreq_Value=264000000
-RCC.Hclk6DIVFreq_Value=264000000
-RCC.I2C12CLockSelection=RCC_I2C12CLKSOURCE_HSI
-RCC.I2C12Freq_Value=64000000
-RCC.I2C35Freq_Value=98000000
-RCC.I2C46CLockSelection=RCC_I2C46CLKSOURCE_HSI
-RCC.I2C46Freq_Value=64000000
-RCC.IPParameters=ADCCLockSelection,ADCFreq_Value,AHB1234Freq_Value,APB1DIV,APB1Freq_Value,APB2DIV,APB2Freq_Value,APB3DIV,APB3Freq_Value,APB4DIV,APB4Freq_Value,APB5DIV,APB5DIVClockFreq_Value,AXICLKFreq_VALUE,AXICLKSource,AXIDIVFreq_Value,CECFreq_Value,CKPERCLKFreq_VALUE,CKPERCLKSource,CSI_VALUE,DACCLKFreq_VALUE,DDRCFreq_Value,DDRPERFMFreq_Value,DDRPHYFreq_Value,DFSDFAFreq_Value,DFSDMFreq_Value,DIVM1,DIVM2,DIVM3,DIVM4,DIVN1,DIVN2,DIVN3,DIVN4,DIVP1Freq_Value,DIVP2Freq_Value,DIVP3,DIVP3Freq_Value,DIVP4,DIVP4Freq_Value,DIVQ1Freq_Value,DIVQ2Freq_Value,DIVQ3Freq_Value,DIVQ4,DIVQ4Freq_Value,DIVR1Freq_Value,DIVR2,DIVR2Freq_Value,DIVR3Freq_Value,DIVR4,DIVR4Freq_Value,DSIFreq_Value,DSIPixelFreq_Value,DSITXEscFreq_Value,DSI_VALUE,ETHFreq_Value,FDCANFreq_Value,FMCFreq_Value,FamilyName,HSE_Timout,HSE_VALUE,HSIDivClkFreq_Value,HSI_VALUE,Hclk5DIVFreq_Value,Hclk6DIVFreq_Value,I2C12CLockSelection,I2C12Freq_Value,I2C35Freq_Value,I2C46CLockSelection,I2C46Freq_Value,LPTIM1Freq_Value,LPTIM23Freq_Value,LPTIM45Freq_Value,LSE_Timout,LSI_VALUE,LTDCFreq_Value,MCO1PinFreq_Value,MCO2PinFreq_Value,MCUCLKFreq_VALUE,MCUCLKSource,MCUClockFreq_Value,MCUDIVCLKFreq_Value,MPUCLKFreq_VALUE,MPUCLKSource,PLL12Source,PLL2FRACV,PLL3Source,PLL4PDSIFreq_Value,PLL4Source,PLLDSIFreq_Value,PLLDSIVCOFreq_Value,PUBLFreq_Value,QSPIFreq_Value,RNG1Freq_Value,RNG2Freq_Value,RTCClockSelection,RTCFreq_Value,SAI1Freq_Value,SAI2Freq_Value,SAI3Freq_Value,SAI4Freq_Value,SDMMC12CLockSelection,SDMMC12Freq_Value,SDMMC3Freq_Value,SPDIFRXFreq_Value,SPI1Freq_Value,SPI23Freq_Value,SPI45Freq_Value,SPI6Freq_Value,STGENCLockSelection,STGENFreq_Value,Tim1OutputFreq_Value,Tim2OutputFreq_Value,UART78Freq_Value,USART1Freq_Value,USART24Freq_Value,USART35Freq_Value,USART6Freq_Value,USBOCLKSource,USBOHSFreq_Value,USBPHYCLKSource,USBPHYFreq_Value,VCO1OutputFreq_Value,VCO2OutputFreq_Value,VCO3OutputFreq_Value,VCO4OutputFreq_Value,VCOInput1Freq_Value,VCOInput2Freq_Value,VCOInput3Freq_Value,VCOInput4Freq_Value
-RCC.LPTIM1Freq_Value=98000000
-RCC.LPTIM23Freq_Value=98000000
-RCC.LPTIM45Freq_Value=98000000
-RCC.LSE_Timout=5000
-RCC.LSI_VALUE=32000
-RCC.LTDCFreq_Value=50000000
-RCC.MCO1PinFreq_Value=64000000
-RCC.MCO2PinFreq_Value=648000000
-RCC.MCUCLKFreq_VALUE=196000000
-RCC.MCUCLKSource=RCC_MCUSSOURCE_PLL3
-RCC.MCUClockFreq_Value=196000000
-RCC.MCUDIVCLKFreq_Value=196000000
-RCC.MPUCLKFreq_VALUE=648000000
-RCC.MPUCLKSource=RCC_MPUSOURCE_PLL1
-RCC.PLL12Source=RCC_PLL12SOURCE_HSE
-RCC.PLL2FRACV=0
-RCC.PLL3Source=RCC_PLL3SOURCE_HSE
-RCC.PLL4PDSIFreq_Value=50000000
-RCC.PLL4Source=RCC_PLL4SOURCE_HSE
-RCC.PLLDSIFreq_Value=480000000
-RCC.PLLDSIVCOFreq_Value=960000000
-RCC.PUBLFreq_Value=528000000
-RCC.QSPIFreq_Value=264000000
-RCC.RNG1Freq_Value=4000000
-RCC.RNG2Freq_Value=4000000
-RCC.RTCClockSelection=RCC_RTCCLKSOURCE_LSE
-RCC.RTCFreq_Value=32768
-RCC.SAI1Freq_Value=50000000
-RCC.SAI2Freq_Value=50000000
-RCC.SAI3Freq_Value=50000000
-RCC.SAI4Freq_Value=50000000
-RCC.SDMMC12CLockSelection=RCC_SDMMC12CLKSOURCE_PLL4
-RCC.SDMMC12Freq_Value=50000000
-RCC.SDMMC3Freq_Value=196000000
-RCC.SPDIFRXFreq_Value=50000000
-RCC.SPI1Freq_Value=50000000
-RCC.SPI23Freq_Value=50000000
-RCC.SPI45Freq_Value=98000000
-RCC.SPI6Freq_Value=66000000
-RCC.STGENCLockSelection=RCC_STGENCLKSOURCE_HSE
-RCC.STGENFreq_Value=24000000
-RCC.Tim1OutputFreq_Value=196000000
-RCC.Tim2OutputFreq_Value=196000000
-RCC.UART78Freq_Value=98000000
-RCC.USART1Freq_Value=66000000
-RCC.USART24Freq_Value=98000000
-RCC.USART35Freq_Value=98000000
-RCC.USART6Freq_Value=98000000
-RCC.USBOCLKSource=RCC_USBOCLKSOURCE_PHY
-RCC.USBOHSFreq_Value=48000000
-RCC.USBPHYCLKSource=RCC_USBPHYCLKSOURCE_HSE
-RCC.USBPHYFreq_Value=24000000
-RCC.VCO1OutputFreq_Value=1296000000
-RCC.VCO2OutputFreq_Value=1056000000
-RCC.VCO3OutputFreq_Value=784000000
-RCC.VCO4OutputFreq_Value=500000000
-RCC.VCOInput1Freq_Value=8000000
-RCC.VCOInput2Freq_Value=8000000
-RCC.VCOInput3Freq_Value=8000000
-RCC.VCOInput4Freq_Value=4000000
-SH.ADCx_INP5.0=ADC1_INP5,IN5-Single-Ended
-SH.ADCx_INP5.ConfNb=1
-SH.S_TIM1_CH2.0=TIM1_CH2,PWM Generation2 CH2
-SH.S_TIM1_CH2.ConfNb=1
-SH.S_TIM4_CH3.0=TIM4_CH3,PWM Generation3 CH3
-SH.S_TIM4_CH3.ConfNb=1
-SPI1.BaudRatePrescaler=SPI_BAUDRATEPRESCALER_2
-SPI1.CalculateBaudRate=25.0 MBits/s
-SPI1.Direction=SPI_DIRECTION_2LINES
-SPI1.IPParameters=VirtualType,Mode,Direction,CalculateBaudRate,BaudRatePrescaler
-SPI1.Mode=SPI_MODE_MASTER
-SPI1.VirtualType=VM_MASTER
-TIM1.Channel-PWM\ Generation2\ CH2=TIM_CHANNEL_2
-TIM1.IPParameters=Channel-PWM Generation2 CH2
-TIM4.Channel-PWM\ Generation3\ CH3=TIM_CHANNEL_3
-TIM4.IPParameters=Channel-PWM Generation3 CH3
-USART2.IPParameters=VirtualMode-Asynchronous
-USART2.VirtualMode-Asynchronous=VM_ASYNC
-USART6.IPParameters=VirtualMode-Asynchronous
-USART6.VirtualMode-Asynchronous=VM_ASYNC
-USB_DM1.Mode=Enable
-USB_DM1.Signal=USBH_HS1_DM
-USB_DM2.Mode=Ext_Phy_OTG/Dual-Role-Device
-USB_DM2.Signal=USB_OTG_HS_DM
-USB_DP1.Mode=Enable
-USB_DP1.Signal=USBH_HS1_DP
-USB_DP2.Mode=Ext_Phy_OTG/Dual-Role-Device
-USB_DP2.Signal=USB_OTG_HS_DP
-VP_BSEC_VS_BSEC.Mode=BSEC_Activate
-VP_BSEC_VS_BSEC.Signal=BSEC_VS_BSEC
-VP_CRC1_VS_CRC.Mode=CRC_Activate
-VP_CRC1_VS_CRC.Signal=CRC1_VS_CRC
-VP_CRYP1_VS_CRYP.Mode=CRYP_Activate
-VP_CRYP1_VS_CRYP.Signal=CRYP1_VS_CRYP
-VP_DDR_DDR3.Mode=DDR3
-VP_DDR_DDR3.Signal=DDR_DDR3
-VP_DDR_DDR3_16_4Gb.Mode=4Gb_16bits
-VP_DDR_DDR3_16_4Gb.Signal=DDR_DDR3_16_4Gb
-VP_DDR_DDR_16_bits.Mode=16bits
-VP_DDR_DDR_16_bits.Signal=DDR_DDR_16_bits
-VP_DMA_VS_DMA1_A7NS.Mode=CortexA7NS
-VP_DMA_VS_DMA1_A7NS.Signal=DMA_VS_DMA1_A7NS
-VP_DMA_VS_DMA2_M4.Mode=CortexM4
-VP_DMA_VS_DMA2_M4.Signal=DMA_VS_DMA2_M4
-VP_DTS_VS_DTS.Mode=DTS_Activate
-VP_DTS_VS_DTS.Signal=DTS_VS_DTS
-VP_ETZPC_VS_ETZPC.Mode=ETZPC_Activate
-VP_ETZPC_VS_ETZPC.Signal=ETZPC_VS_ETZPC
-VP_GPU_VS_GPU.Mode=GPU_Activate
-VP_GPU_VS_GPU.Signal=GPU_VS_GPU
-VP_HASH1_VS_HASH.Mode=HASH_Activate
-VP_HASH1_VS_HASH.Signal=HASH1_VS_HASH
-VP_HSEM_VS_HSEM.Mode=HSEM_Activate
-VP_HSEM_VS_HSEM.Signal=HSEM_VS_HSEM
-VP_IPCC_VS_IPCC.Mode=IPCC_Activate
-VP_IPCC_VS_IPCC.Signal=IPCC_VS_IPCC
-VP_MDMA_VS_MDMA_A7NS_8.Mode=8\:8
-VP_MDMA_VS_MDMA_A7NS_8.Signal=MDMA_VS_MDMA_A7NS_8
-VP_RNG1_VS_RNG.Mode=RNG_Activate
-VP_RNG1_VS_RNG.Signal=RNG1_VS_RNG
-VP_RTC_VS_RTC_Activate.Mode=RTC_Enabled
-VP_RTC_VS_RTC_Activate.Signal=RTC_VS_RTC_Activate
-VP_SYS_VS_Systick.Mode=SysTick
-VP_SYS_VS_Systick.Signal=SYS_VS_Systick
-VP_VREFBUF_VS_VREFBUF.Mode=VREFBUF_Activate
-VP_VREFBUF_VS_VREFBUF.Signal=VREFBUF_VS_VREFBUF
-board=custom
diff --git a/conf/machine/cubemx/t1000-calib.ioc b/conf/machine/cubemx/t1000-calib.ioc
new file mode 100644
index 0000000000000000000000000000000000000000..0bbb0e0978755ad1a637f3dadcec5954bf91b66d
--- /dev/null
+++ b/conf/machine/cubemx/t1000-calib.ioc
@@ -0,0 +1,1033 @@
+#MicroXplorer Configuration settings - do not modify
+Boot\ ROM.IPs=SDMMC1,SDMMC2,UART4
+Boot\ loader.IPs=RCC,I2C4,SDMMC1,SDMMC2,UART4,USART2
+Cortex-A7\ non\ secure.IPs=DDR\:I,RCC\:I,RTC\:I,SYS\:I,I2C4\:I,I2C1\:I,LTDC\:I,DSIHOST\:I,USBH_HS1\:I,HDMI_CEC\:I,ETH1\:I,SDMMC1\:I,USART2\:I,I2S1\:I,SDMMC2\:I,UART4\:I,DMA1\:I
+Cortex-M4.IPs=RCC,WWDG1\:I,NVIC\:I,DMA2\:I
+DDR.ADDRMAP1=0x00070707
+DDR.ADDRMAP3=0x1F000000
+DDR.ADDRMAP5=0x06060606
+DDR.ADDRMAP6=0x0F060606
+DDR.DFITMG0=0x02050105
+DDR.DRAMTMG2=0x0607080F
+DDR.DRAMTMG4=0x07040607
+DDR.DRAMTMG5=0x06060403
+DDR.DTPR0=0x36D477D0
+DDR.DTPR1=0x098A00D8
+DDR.IPParameters=addrmap_col_b9,addrmap_col_b10,addrmap_col_b11,addrmap_bank_b0,addrmap_bank_b1,addrmap_bank_b2,addrmap_row_b0,addrmap_row_b1,addrmap_row_b2_10,addrmap_row_b11,addrmap_row_b12,addrmap_row_b13,addrmap_row_b14,addrmap_row_b15,MSTR,RFSHTMG,DRAMTMG2,DRAMTMG4,DRAMTMG5,DFITMG0,ADDRMAP1,ADDRMAP3,ADDRMAP5,ADDRMAP6,PTR0,PTR1,PTR2,DTPR0,DTPR1
+DDR.MSTR=0x00041401
+DDR.PTR0=0x0022A41B
+DDR.PTR1=0x047C0740
+DDR.PTR2=0x042D9C80
+DDR.RFSHTMG=0x0080008A
+DDR.addrmap_bank_b0=7
+DDR.addrmap_bank_b1=7
+DDR.addrmap_bank_b2=7
+DDR.addrmap_col_b10=31
+DDR.addrmap_col_b11=31
+DDR.addrmap_col_b9=31
+DDR.addrmap_row_b0=6
+DDR.addrmap_row_b1=6
+DDR.addrmap_row_b11=6
+DDR.addrmap_row_b12=6
+DDR.addrmap_row_b13=6
+DDR.addrmap_row_b14=6
+DDR.addrmap_row_b15=15
+DDR.addrmap_row_b2_10=6
+DDR_A0.GPIOParameters=GPIO_Label
+DDR_A0.GPIO_Label=DDR_A0 [MT41K256M16TW_A0]
+DDR_A0.Locked=true
+DDR_A0.Mode=DDR3
+DDR_A0.Signal=DDR_A0
+DDR_A1.GPIOParameters=GPIO_Label
+DDR_A1.GPIO_Label=DDR_A1 [MT41K256M16TW_A1]
+DDR_A1.Locked=true
+DDR_A1.Mode=DDR3
+DDR_A1.Signal=DDR_A1
+DDR_A10.GPIOParameters=GPIO_Label
+DDR_A10.GPIO_Label=DDR_A10 [MT41K256M16TW_A10]
+DDR_A10.Locked=true
+DDR_A10.Mode=DDR3
+DDR_A10.Signal=DDR_A10
+DDR_A11.GPIOParameters=GPIO_Label
+DDR_A11.GPIO_Label=DDR_A11 [MT41K256M16TW_A11]
+DDR_A11.Locked=true
+DDR_A11.Mode=DDR3
+DDR_A11.Signal=DDR_A11
+DDR_A12.GPIOParameters=GPIO_Label
+DDR_A12.GPIO_Label=DDR_A12 [MT41K256M16TW_A12]
+DDR_A12.Locked=true
+DDR_A12.Mode=4Gb_16bits
+DDR_A12.Signal=DDR_A12
+DDR_A13.GPIOParameters=GPIO_Label
+DDR_A13.GPIO_Label=DDR_A13 [MT41K256M16TW_A13]
+DDR_A13.Locked=true
+DDR_A13.Mode=4Gb_16bits
+DDR_A13.Signal=DDR_A13
+DDR_A14.GPIOParameters=GPIO_Label
+DDR_A14.GPIO_Label=DDR_A14 [MT41K256M16TW_A14]
+DDR_A14.Locked=true
+DDR_A14.Mode=4Gb_16bits
+DDR_A14.Signal=DDR_A14
+DDR_A2.GPIOParameters=GPIO_Label
+DDR_A2.GPIO_Label=DDR_A2 [MT41K256M16TW_A2]
+DDR_A2.Locked=true
+DDR_A2.Mode=DDR3
+DDR_A2.Signal=DDR_A2
+DDR_A3.GPIOParameters=GPIO_Label
+DDR_A3.GPIO_Label=DDR_A3 [MT41K256M16TW_A3]
+DDR_A3.Locked=true
+DDR_A3.Mode=DDR3
+DDR_A3.Signal=DDR_A3
+DDR_A4.GPIOParameters=GPIO_Label
+DDR_A4.GPIO_Label=DDR_A4 [MT41K256M16TW_A4]
+DDR_A4.Locked=true
+DDR_A4.Mode=DDR3
+DDR_A4.Signal=DDR_A4
+DDR_A5.GPIOParameters=GPIO_Label
+DDR_A5.GPIO_Label=DDR_A5 [MT41K256M16TW_A5]
+DDR_A5.Locked=true
+DDR_A5.Mode=DDR3
+DDR_A5.Signal=DDR_A5
+DDR_A6.GPIOParameters=GPIO_Label
+DDR_A6.GPIO_Label=DDR_A6 [MT41K256M16TW_A6]
+DDR_A6.Locked=true
+DDR_A6.Mode=DDR3
+DDR_A6.Signal=DDR_A6
+DDR_A7.GPIOParameters=GPIO_Label
+DDR_A7.GPIO_Label=DDR_A7 [MT41K256M16TW_A7]
+DDR_A7.Locked=true
+DDR_A7.Mode=DDR3
+DDR_A7.Signal=DDR_A7
+DDR_A8.GPIOParameters=GPIO_Label
+DDR_A8.GPIO_Label=DDR_A8 [MT41K256M16TW_A8]
+DDR_A8.Locked=true
+DDR_A8.Mode=DDR3
+DDR_A8.Signal=DDR_A8
+DDR_A9.GPIOParameters=GPIO_Label
+DDR_A9.GPIO_Label=DDR_A9 [MT41K256M16TW_A9]
+DDR_A9.Locked=true
+DDR_A9.Mode=DDR3
+DDR_A9.Signal=DDR_A9
+DDR_ATO.GPIOParameters=GPIO_Label
+DDR_ATO.GPIO_Label=DDR_ATO
+DDR_ATO.Locked=true
+DDR_ATO.Mode=DDR3
+DDR_ATO.Signal=DDR_ATO
+DDR_BA0.GPIOParameters=GPIO_Label
+DDR_BA0.GPIO_Label=DDR_BA0 [MT41K256M16TW_BA0]
+DDR_BA0.Locked=true
+DDR_BA0.Mode=DDR3
+DDR_BA0.Signal=DDR_BA0
+DDR_BA1.GPIOParameters=GPIO_Label
+DDR_BA1.GPIO_Label=DDR_BA1 [MT41K256M16TW_BA1]
+DDR_BA1.Locked=true
+DDR_BA1.Mode=DDR3
+DDR_BA1.Signal=DDR_BA1
+DDR_BA2.GPIOParameters=GPIO_Label
+DDR_BA2.GPIO_Label=DDR_BA2 [MT41K256M16TW_BA2]
+DDR_BA2.Locked=true
+DDR_BA2.Mode=DDR3
+DDR_BA2.Signal=DDR_BA2
+DDR_CASN.GPIOParameters=GPIO_Label
+DDR_CASN.GPIO_Label=DDR_CASN [MT41K256M16TW_CAS\#]
+DDR_CASN.Locked=true
+DDR_CASN.Mode=DDR3
+DDR_CASN.Signal=DDR_CASN
+DDR_CKE.GPIOParameters=GPIO_Label
+DDR_CKE.GPIO_Label=DDR_CKE [MT41K256M16TW_CKE]
+DDR_CKE.Locked=true
+DDR_CKE.Mode=DDR3
+DDR_CKE.Signal=DDR_CKE
+DDR_CLKN.GPIOParameters=GPIO_Label
+DDR_CLKN.GPIO_Label=DDR_CLK_N [MT41K256M16TW_CK\#]
+DDR_CLKN.Locked=true
+DDR_CLKN.Mode=DDR3
+DDR_CLKN.Signal=DDR_CLKN
+DDR_CLKP.GPIOParameters=GPIO_Label
+DDR_CLKP.GPIO_Label=DDR_CLK_P [MT41K256M16TW_CK]
+DDR_CLKP.Locked=true
+DDR_CLKP.Mode=DDR3
+DDR_CLKP.Signal=DDR_CLKP
+DDR_CSN.GPIOParameters=GPIO_Label
+DDR_CSN.GPIO_Label=DDR_CSN [MT41K256M16TW_CS\#]
+DDR_CSN.Locked=true
+DDR_CSN.Mode=DDR3
+DDR_CSN.Signal=DDR_CSN
+DDR_DQ0.GPIOParameters=GPIO_Label
+DDR_DQ0.GPIO_Label=DDR_DQ0 [MT41K256M16TW_DQU5]
+DDR_DQ0.Locked=true
+DDR_DQ0.Mode=DDR3
+DDR_DQ0.Signal=DDR_DQ0
+DDR_DQ1.GPIOParameters=GPIO_Label
+DDR_DQ1.GPIO_Label=DDR_DQ1 [MT41K256M16TW_DQU1]
+DDR_DQ1.Locked=true
+DDR_DQ1.Mode=DDR3
+DDR_DQ1.Signal=DDR_DQ1
+DDR_DQ10.GPIOParameters=GPIO_Label
+DDR_DQ10.GPIO_Label=DDR_DQ10 [MT41K256M16TW_DQL6]
+DDR_DQ10.Locked=true
+DDR_DQ10.Mode=DDR3
+DDR_DQ10.Signal=DDR_DQ10
+DDR_DQ11.GPIOParameters=GPIO_Label
+DDR_DQ11.GPIO_Label=DDR_DQ11 [MT41K256M16TW_DQL1]
+DDR_DQ11.Locked=true
+DDR_DQ11.Mode=DDR3
+DDR_DQ11.Signal=DDR_DQ11
+DDR_DQ12.GPIOParameters=GPIO_Label
+DDR_DQ12.GPIO_Label=DDR_DQ12 [MT41K256M16TW_DQL5]
+DDR_DQ12.Locked=true
+DDR_DQ12.Mode=DDR3
+DDR_DQ12.Signal=DDR_DQ12
+DDR_DQ13.GPIOParameters=GPIO_Label
+DDR_DQ13.GPIO_Label=DDR_DQ13 [MT41K256M16TW_DQL4]
+DDR_DQ13.Locked=true
+DDR_DQ13.Mode=DDR3
+DDR_DQ13.Signal=DDR_DQ13
+DDR_DQ14.GPIOParameters=GPIO_Label
+DDR_DQ14.GPIO_Label=DDR_DQ14 [MT41K256M16TW_DQL7]
+DDR_DQ14.Locked=true
+DDR_DQ14.Mode=DDR3
+DDR_DQ14.Signal=DDR_DQ14
+DDR_DQ15.GPIOParameters=GPIO_Label
+DDR_DQ15.GPIO_Label=DDR_DQ15 [MT41K256M16TW_DQL3]
+DDR_DQ15.Locked=true
+DDR_DQ15.Mode=DDR3
+DDR_DQ15.Signal=DDR_DQ15
+DDR_DQ2.GPIOParameters=GPIO_Label
+DDR_DQ2.GPIO_Label=DDR_DQ2 [MT41K256M16TW_DQU4]
+DDR_DQ2.Locked=true
+DDR_DQ2.Mode=DDR3
+DDR_DQ2.Signal=DDR_DQ2
+DDR_DQ3.GPIOParameters=GPIO_Label
+DDR_DQ3.GPIO_Label=DDR_DQ3 [MT41K256M16TW_DQU3]
+DDR_DQ3.Locked=true
+DDR_DQ3.Mode=DDR3
+DDR_DQ3.Signal=DDR_DQ3
+DDR_DQ4.GPIOParameters=GPIO_Label
+DDR_DQ4.GPIO_Label=DDR_DQ4 [MT41K256M16TW_DQU6]
+DDR_DQ4.Locked=true
+DDR_DQ4.Mode=DDR3
+DDR_DQ4.Signal=DDR_DQ4
+DDR_DQ5.GPIOParameters=GPIO_Label
+DDR_DQ5.GPIO_Label=DDR_DQ5 [MT41K256M16TW_DQU2]
+DDR_DQ5.Locked=true
+DDR_DQ5.Mode=DDR3
+DDR_DQ5.Signal=DDR_DQ5
+DDR_DQ6.GPIOParameters=GPIO_Label
+DDR_DQ6.GPIO_Label=DDR_DQ6 [MT41K256M16TW_DQU0]
+DDR_DQ6.Locked=true
+DDR_DQ6.Mode=DDR3
+DDR_DQ6.Signal=DDR_DQ6
+DDR_DQ7.GPIOParameters=GPIO_Label
+DDR_DQ7.GPIO_Label=DDR_DQ7 [MT41K256M16TW_DQU7]
+DDR_DQ7.Locked=true
+DDR_DQ7.Mode=DDR3
+DDR_DQ7.Signal=DDR_DQ7
+DDR_DQ8.GPIOParameters=GPIO_Label
+DDR_DQ8.GPIO_Label=DDR_DQ8 [MT41K256M16TW_DQL2]
+DDR_DQ8.Locked=true
+DDR_DQ8.Mode=DDR3
+DDR_DQ8.Signal=DDR_DQ8
+DDR_DQ9.GPIOParameters=GPIO_Label
+DDR_DQ9.GPIO_Label=DDR_DQ9 [MT41K256M16TW_DQL0]
+DDR_DQ9.Locked=true
+DDR_DQ9.Mode=DDR3
+DDR_DQ9.Signal=DDR_DQ9
+DDR_DQM0.GPIOParameters=GPIO_Label
+DDR_DQM0.GPIO_Label=DDR_DQM0 [MT41K256M16TW_DMU]
+DDR_DQM0.Locked=true
+DDR_DQM0.Mode=DDR3
+DDR_DQM0.Signal=DDR_DQM0
+DDR_DQM1.GPIOParameters=GPIO_Label
+DDR_DQM1.GPIO_Label=DDR_DQM1 [MT41K256M16TW_DML]
+DDR_DQM1.Locked=true
+DDR_DQM1.Mode=DDR3
+DDR_DQM1.Signal=DDR_DQM1
+DDR_DQS0N.GPIOParameters=GPIO_Label
+DDR_DQS0N.GPIO_Label=DDR_DQS0_N [MT41K256M16TW_DQSU\#]
+DDR_DQS0N.Locked=true
+DDR_DQS0N.Mode=DDR3
+DDR_DQS0N.Signal=DDR_DQS0N
+DDR_DQS0P.GPIOParameters=GPIO_Label
+DDR_DQS0P.GPIO_Label=DDR_DQS0_P [MT41K256M16TW_DQSU]
+DDR_DQS0P.Locked=true
+DDR_DQS0P.Mode=DDR3
+DDR_DQS0P.Signal=DDR_DQS0P
+DDR_DQS1N.GPIOParameters=GPIO_Label
+DDR_DQS1N.GPIO_Label=DDR_DQS1_N [MT41K256M16TW_DQSL\#]
+DDR_DQS1N.Locked=true
+DDR_DQS1N.Mode=DDR3
+DDR_DQS1N.Signal=DDR_DQS1N
+DDR_DQS1P.GPIOParameters=GPIO_Label
+DDR_DQS1P.GPIO_Label=DDR_DQS1_P [MT41K256M16TW_DQSL]
+DDR_DQS1P.Locked=true
+DDR_DQS1P.Mode=DDR3
+DDR_DQS1P.Signal=DDR_DQS1P
+DDR_DTO0.GPIOParameters=GPIO_Label
+DDR_DTO0.GPIO_Label=DDR_DTO0
+DDR_DTO0.Locked=true
+DDR_DTO0.Mode=DDR3
+DDR_DTO0.Signal=DDR_DTO0
+DDR_DTO1.GPIOParameters=GPIO_Label
+DDR_DTO1.GPIO_Label=DDR_DTO1
+DDR_DTO1.Locked=true
+DDR_DTO1.Mode=DDR3
+DDR_DTO1.Signal=DDR_DTO1
+DDR_ODT.GPIOParameters=GPIO_Label
+DDR_ODT.GPIO_Label=DDR_ODT [MT41K256M16TW_ODT]
+DDR_ODT.Locked=true
+DDR_ODT.Mode=DDR3
+DDR_ODT.Signal=DDR_ODT
+DDR_RASN.GPIOParameters=GPIO_Label
+DDR_RASN.GPIO_Label=DDR_RASN [MT41K256M16TW_RAS\#]
+DDR_RASN.Locked=true
+DDR_RASN.Mode=DDR3
+DDR_RASN.Signal=DDR_RASN
+DDR_RESETN.GPIOParameters=GPIO_Label
+DDR_RESETN.GPIO_Label=DDR_RESETN [MT41K256M16TW_RESET\#]
+DDR_RESETN.Locked=true
+DDR_RESETN.Mode=DDR3
+DDR_RESETN.Signal=DDR_RESETN
+DDR_VREF.GPIOParameters=GPIO_Label
+DDR_VREF.GPIO_Label=VREF_DDR
+DDR_VREF.Locked=true
+DDR_VREF.Mode=DDR3
+DDR_VREF.Signal=DDR_VREF
+DDR_WEN.GPIOParameters=GPIO_Label
+DDR_WEN.GPIO_Label=DDR_WEN_P [MT41K256M16TW_WE\#]
+DDR_WEN.Locked=true
+DDR_WEN.Mode=DDR3
+DDR_WEN.Signal=DDR_WEN
+DDR_ZQ.GPIOParameters=GPIO_Label
+DDR_ZQ.GPIO_Label=DDR_ZQ
+DDR_ZQ.Locked=true
+DDR_ZQ.Mode=DDR3
+DDR_ZQ.Signal=DDR_ZQ
+DSIHOST_CKN.GPIOParameters=GPIO_Label
+DSIHOST_CKN.GPIO_Label=HSSI_CLK_N [FH26W-25S_HSSI_CLK_N]
+DSIHOST_CKN.Locked=true
+DSIHOST_CKN.Mode=DSIHost_Video
+DSIHOST_CKN.Signal=DSIHOST_CKN
+DSIHOST_CKP.GPIOParameters=GPIO_Label
+DSIHOST_CKP.GPIO_Label=HSSI_CLK_P [FH26W-25S_HSSI_CLK_P]
+DSIHOST_CKP.Locked=true
+DSIHOST_CKP.Mode=DSIHost_Video
+DSIHOST_CKP.Signal=DSIHOST_CKP
+DSIHOST_D0N.GPIOParameters=GPIO_Label
+DSIHOST_D0N.GPIO_Label=HSSI_D0_N [FH26W-25S_HSSI_D0_N]
+DSIHOST_D0N.Locked=true
+DSIHOST_D0N.Mode=DSIHost_Video
+DSIHOST_D0N.Signal=DSIHOST_D0N
+DSIHOST_D0P.GPIOParameters=GPIO_Label
+DSIHOST_D0P.GPIO_Label=HSSI_D0_P [FH26W-25S_HSSI_D0_P]
+DSIHOST_D0P.Locked=true
+DSIHOST_D0P.Mode=DSIHost_Video
+DSIHOST_D0P.Signal=DSIHOST_D0P
+DSIHOST_D1N.GPIOParameters=GPIO_Label
+DSIHOST_D1N.GPIO_Label=HSSI_D1_N [FH26W-25S_HSSI_D1_N]
+DSIHOST_D1N.Locked=true
+DSIHOST_D1N.Mode=DSIHost_Video
+DSIHOST_D1N.Signal=DSIHOST_D1N
+DSIHOST_D1P.GPIOParameters=GPIO_Label
+DSIHOST_D1P.GPIO_Label=HSSI_D1_P [FH26W-25S_HSSI_D1_P]
+DSIHOST_D1P.Locked=true
+DSIHOST_D1P.Mode=DSIHost_Video
+DSIHOST_D1P.Signal=DSIHOST_D1P
+ETH1.IPParameters=MediaInterface
+ETH1.MediaInterface=HAL_ETH_RGMII_MODE
+File.Version=6
+I2S1.ErrorAudioFreq=0.21 %
+I2S1.FullDuplexMode=I2S_MODE_MASTER_FD
+I2S1.IPParameters=Instance,VirtualMode,FullDuplexMode,RealAudioFreq,ErrorAudioFreq
+I2S1.Instance=SPI$Index
+I2S1.RealAudioFreq=8.017 KHz
+I2S1.VirtualMode=I2S_MODE_MASTER
+JTCK-SWCLK.GPIOParameters=GPIO_Label
+JTCK-SWCLK.GPIO_Label=T_JTCK [STM32F103CBT6_PB13]
+JTCK-SWCLK.Locked=true
+JTCK-SWCLK.Mode=JTAG_5_pins
+JTCK-SWCLK.Signal=SYS_JTCK-SWCLK
+JTDI.GPIOParameters=GPIO_Label
+JTDI.GPIO_Label=JTDI
+JTDI.Locked=true
+JTDI.Mode=JTAG_5_pins
+JTDI.Signal=SYS_JTDI
+JTDO-TRACESWO.GPIOParameters=GPIO_Label
+JTDO-TRACESWO.GPIO_Label=T_SWO [STM32F103CBT6_PA10]
+JTDO-TRACESWO.Locked=true
+JTDO-TRACESWO.Mode=JTAG_5_pins
+JTDO-TRACESWO.Signal=SYS_JTDO-SWO
+JTMS-SWDIO.GPIOParameters=GPIO_Label
+JTMS-SWDIO.GPIO_Label=T_JTMS [STM32F103CBT6_PB14]
+JTMS-SWDIO.Locked=true
+JTMS-SWDIO.Mode=JTAG_5_pins
+JTMS-SWDIO.Signal=SYS_JTMS-SWDIO
+KeepUserPlacement=true
+Mcu.Context0=Boot ROM
+Mcu.Context1=Boot loader
+Mcu.Context2=Cortex-A7 non secure
+Mcu.Context3=Cortex-M4
+Mcu.ContextNb=4
+Mcu.Family=STM32MP1
+Mcu.IP0=DDR
+Mcu.IP1=DSIHOST
+Mcu.IP10=RTC
+Mcu.IP11=SDMMC1
+Mcu.IP12=SDMMC2
+Mcu.IP13=SYS
+Mcu.IP14=UART4
+Mcu.IP15=USART2
+Mcu.IP16=USBH_HS1
+Mcu.IP2=ETH1
+Mcu.IP3=HDMI_CEC
+Mcu.IP4=I2C1
+Mcu.IP5=I2C4
+Mcu.IP6=I2S1
+Mcu.IP7=LTDC
+Mcu.IP8=NVIC
+Mcu.IP9=RCC
+Mcu.IPNb=17
+Mcu.Name=STM32MP157CACx
+Mcu.Package=TFBGA361
+Mcu.Pin0=PH5
+Mcu.Pin1=PD5
+Mcu.Pin10=PD4
+Mcu.Pin100=DDR_A6
+Mcu.Pin101=DDR_DQ11
+Mcu.Pin102=DDR_DQ14
+Mcu.Pin103=DDR_DQ12
+Mcu.Pin104=PE2
+Mcu.Pin105=PC2
+Mcu.Pin106=PF15
+Mcu.Pin107=PG5
+Mcu.Pin108=PG11
+Mcu.Pin109=PB5
+Mcu.Pin11=PD0
+Mcu.Pin110=PG9
+Mcu.Pin111=PB6
+Mcu.Pin112=PB2
+Mcu.Pin113=PA10
+Mcu.Pin114=PD12
+Mcu.Pin115=DDR_ATO
+Mcu.Pin116=DDR_A8
+Mcu.Pin117=DDR_DQ15
+Mcu.Pin118=PG14
+Mcu.Pin119=PG13
+Mcu.Pin12=PB15
+Mcu.Pin120=PA1
+Mcu.Pin121=PC1
+Mcu.Pin122=PB1
+Mcu.Pin123=PB11
+Mcu.Pin124=PG4
+Mcu.Pin125=PA0
+Mcu.Pin126=PB0
+Mcu.Pin127=PC5
+Mcu.Pin128=PA7
+Mcu.Pin129=USB_DM1
+Mcu.Pin13=PB4
+Mcu.Pin130=PA2
+Mcu.Pin131=PC4
+Mcu.Pin132=PA6
+Mcu.Pin133=PD11
+Mcu.Pin134=USB_DP1
+Mcu.Pin135=DDR_VREF
+Mcu.Pin136=VP_DDR_DDR3
+Mcu.Pin137=VP_DDR_DDR_16_bits
+Mcu.Pin138=VP_DDR_DDR3_16_4Gb
+Mcu.Pin139=VP_LTDC_DSIMode
+Mcu.Pin14=PC6
+Mcu.Pin140=VP_RTC_VS_RTC_Activate
+Mcu.Pin141=VP_DMA_VS_DMA1_A7NS
+Mcu.Pin142=VP_DMA_VS_DMA2_M4
+Mcu.Pin15=DSIHOST_D0N
+Mcu.Pin16=DSIHOST_CKP
+Mcu.Pin17=DSIHOST_D1P
+Mcu.Pin18=NJTRST
+Mcu.Pin19=JTCK-SWCLK
+Mcu.Pin2=PG6
+Mcu.Pin20=PE3
+Mcu.Pin21=PB14
+Mcu.Pin22=DSIHOST_D0P
+Mcu.Pin23=PA15
+Mcu.Pin24=JTMS-SWDIO
+Mcu.Pin25=PD6
+Mcu.Pin26=PB7
+Mcu.Pin27=PD2
+Mcu.Pin28=PC12
+Mcu.Pin29=PD3
+Mcu.Pin3=PB3
+Mcu.Pin30=PC10
+Mcu.Pin31=PC11
+Mcu.Pin32=PC9
+Mcu.Pin33=PC8
+Mcu.Pin34=PE4
+Mcu.Pin35=DDR_RESETN
+Mcu.Pin36=DDR_A7
+Mcu.Pin37=DDR_DQ3
+Mcu.Pin38=DDR_DQ0
+Mcu.Pin39=DDR_A13
+Mcu.Pin4=PF2
+Mcu.Pin40=DDR_DQ1
+Mcu.Pin41=PZ1
+Mcu.Pin42=PZ4
+Mcu.Pin43=PZ0
+Mcu.Pin44=PZ3
+Mcu.Pin45=DDR_A9
+Mcu.Pin46=DDR_DQ7
+Mcu.Pin47=DDR_DQS0P
+Mcu.Pin48=DDR_DQS0N
+Mcu.Pin49=PZ6
+Mcu.Pin5=DSIHOST_CKN
+Mcu.Pin50=PZ5
+Mcu.Pin51=DDR_A5
+Mcu.Pin52=DDR_DQ2
+Mcu.Pin53=DDR_DQ6
+Mcu.Pin54=DDR_DQM0
+Mcu.Pin55=PZ7
+Mcu.Pin56=PZ2
+Mcu.Pin57=DDR_A2
+Mcu.Pin58=DDR_DQ4
+Mcu.Pin59=DDR_DQ5
+Mcu.Pin6=DSIHOST_D1N
+Mcu.Pin60=PC13
+Mcu.Pin61=DDR_DTO0
+Mcu.Pin62=DDR_A3
+Mcu.Pin63=DDR_ZQ
+Mcu.Pin64=PC15-OSC32_OUT
+Mcu.Pin65=PC14-OSC32_IN
+Mcu.Pin66=PI8
+Mcu.Pin67=DDR_A0
+Mcu.Pin68=DDR_DTO1
+Mcu.Pin69=DDR_ODT
+Mcu.Pin7=JTDO-TRACESWO
+Mcu.Pin70=DDR_BA0
+Mcu.Pin71=DDR_WEN
+Mcu.Pin72=DDR_BA2
+Mcu.Pin73=DDR_CSN
+Mcu.Pin74=PA13
+Mcu.Pin75=DDR_CASN
+Mcu.Pin76=DDR_RASN
+Mcu.Pin77=DDR_CLKP
+Mcu.Pin78=DDR_CLKN
+Mcu.Pin79=PH0-OSC_IN
+Mcu.Pin8=JTDI
+Mcu.Pin80=PH1-OSC_OUT
+Mcu.Pin81=PI11
+Mcu.Pin82=DDR_A1
+Mcu.Pin83=DDR_A12
+Mcu.Pin84=DDR_A11
+Mcu.Pin85=DDR_A14
+Mcu.Pin86=DDR_A10
+Mcu.Pin87=PA14
+Mcu.Pin88=DDR_CKE
+Mcu.Pin89=DDR_DQ8
+Mcu.Pin9=PH4
+Mcu.Pin90=DDR_DQ10
+Mcu.Pin91=DDR_DQ13
+Mcu.Pin92=DDR_BA1
+Mcu.Pin93=DDR_DQ9
+Mcu.Pin94=DDR_DQS1P
+Mcu.Pin95=DDR_DQS1N
+Mcu.Pin96=DDR_A4
+Mcu.Pin97=DDR_DQM1
+Mcu.Pin98=PG1
+Mcu.Pin99=PH7
+Mcu.PinsNb=143
+Mcu.ThirdPartyNb=0
+Mcu.UserConstants=
+Mcu.UserName=STM32MP157CACx
+MxCube.Version=4.99.1
+MxDb.Version=DB.4.0.270
+NJTRST.GPIOParameters=GPIO_Label
+NJTRST.GPIO_Label=T_NRST [STM32F103CBT6_PB0]
+NJTRST.Locked=true
+NJTRST.Mode=JTAG_5_pins
+NJTRST.Signal=SYS_JTRST
+NVIC.BusFault_IRQn=true\:0\:0\:false\:false\:true\:false
+NVIC.DebugMonitor_IRQn=true\:0\:0\:false\:false\:true\:false
+NVIC.HardFault_IRQn=true\:0\:0\:false\:false\:true\:false
+NVIC.MemoryManagement_IRQn=true\:0\:0\:false\:false\:true\:false
+NVIC.NonMaskableInt_IRQn=true\:0\:0\:false\:false\:true\:false
+NVIC.PendSV_IRQn=true\:0\:0\:false\:false\:true\:false
+NVIC.PriorityGroup=NVIC_PRIORITYGROUP_4
+NVIC.SVCall_IRQn=true\:0\:0\:false\:false\:true\:false
+NVIC.SysTick_IRQn=true\:0\:0\:false\:false\:true\:false
+NVIC.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:false
+PA0.GPIOParameters=GPIO_Label
+PA0.GPIO_Label=PA0_WKUP [STPMU1A_INT_N]
+PA0.Locked=true
+PA0.Mode=SYS_WakeUp1
+PA0.Signal=SYS_WKUP1
+PA1.GPIOParameters=GPIO_Label
+PA1.GPIO_Label=ETH_RX_CLK [RTL8211F_RXCLK_PHYAD1]
+PA1.Locked=true
+PA1.Mode=RGMII (Reduced GMII)
+PA1.Signal=ETH1_RX_CLK
+PA10.GPIOParameters=GPIO_Label
+PA10.GPIO_Label=HDMI_NRST [SiI9022ACNU_RESET\#]
+PA10.Locked=true
+PA10.Signal=GPIO_Output
+PA13.GPIOParameters=GPIO_Label
+PA13.GPIO_Label=PA13 [LD6_RED]
+PA13.Locked=true
+PA13.Signal=GPIO_Output
+PA14.GPIOParameters=GPIO_Label
+PA14.GPIO_Label=PA14 [SW-PUSH-TS-02H-Blue]
+PA14.Locked=true
+PA14.Signal=GPIO_Input
+PA15.GPIOParameters=GPIO_Label
+PA15.GPIO_Label=BL_CTRL [STLD40DPUR_EN]
+PA15.Locked=true
+PA15.Signal=GPIO_Output
+PA2.GPIOParameters=GPIO_Label
+PA2.GPIO_Label=ETH_MIO [RTL8211F_MIO]
+PA2.Locked=true
+PA2.Mode=RGMII (Reduced GMII)
+PA2.Signal=ETH1_MDIO
+PA6.GPIOParameters=GPIO_Label
+PA6.GPIO_Label=ETH_MDINT [RTL8211F_INT]
+PA6.Locked=true
+PA6.Signal=GPIO_Input
+PA7.GPIOParameters=GPIO_Label
+PA7.GPIO_Label=ETH_RX_DV [RTL8211F_RXCTL_PHYAD2]
+PA7.Locked=true
+PA7.Mode=RGMII (Reduced GMII)
+PA7.Signal=ETH1_RX_CTL
+PB0.GPIOParameters=GPIO_Label
+PB0.GPIO_Label=ETH_RXD2 [RTL8211F_RXD2_PLLOFF]
+PB0.Locked=true
+PB0.Mode=RGMII (Reduced GMII)
+PB0.Signal=ETH1_RXD2
+PB1.GPIOParameters=GPIO_Label
+PB1.GPIO_Label=ETH_RXD3 [RTL8211F_RXD3_PHYAD0]
+PB1.Locked=true
+PB1.Mode=RGMII (Reduced GMII)
+PB1.Signal=ETH1_RXD3
+PB11.GPIOParameters=GPIO_Label
+PB11.GPIO_Label=ETH_TX_EN [RTL8211F_TXCTL]
+PB11.Locked=true
+PB11.Mode=RGMII (Reduced GMII)
+PB11.Signal=ETH1_TX_CTL
+PB14.GPIOParameters=GPIO_Label
+PB14.GPIO_Label=SDMMC2_D0 [LBEE5KL1DX_SDIO_D0]
+PB14.Locked=true
+PB14.Mode=SD_4_bits_Wide_bus
+PB14.Signal=SDMMC2_D0
+PB15.GPIOParameters=GPIO_Label
+PB15.GPIO_Label=SDMMC2_D1 [LBEE5KL1DX_SDIO_D1]
+PB15.Locked=true
+PB15.Mode=SD_4_bits_Wide_bus
+PB15.Signal=SDMMC2_D1
+PB2.GPIOParameters=GPIO_Label
+PB2.GPIO_Label=STLINK_TX [STM32F103CBT6_PA2]
+PB2.Locked=true
+PB2.Mode=Asynchronous
+PB2.Signal=UART4_RX
+PB3.GPIOParameters=GPIO_Label
+PB3.GPIO_Label=SDMMC2_D2 [LBEE5KL1DX_SDIO_D2]
+PB3.Locked=true
+PB3.Mode=SD_4_bits_Wide_bus
+PB3.Signal=SDMMC2_D2
+PB4.GPIOParameters=GPIO_Label
+PB4.GPIO_Label=SDMMC2_D3 [LBEE5KL1DX_SDIO_D3]
+PB4.Locked=true
+PB4.Mode=SD_4_bits_Wide_bus
+PB4.Signal=SDMMC2_D3
+PB5.GPIOParameters=GPIO_Label
+PB5.GPIO_Label=ETH_CLK [RTL8211F_XTAL_IN]
+PB5.Locked=true
+PB5.Mode=ETH Clock Output (PHY without Quartz)
+PB5.Signal=ETH1_CLK
+PB6.GPIOParameters=GPIO_Label
+PB6.GPIO_Label=HDMI_CEC [SiI9022ACNU_CEC_D]
+PB6.Locked=true
+PB6.Mode=CEC_Activate
+PB6.Signal=CEC
+PB7.GPIOParameters=GPIO_Label
+PB7.GPIO_Label=uSD_DETECT [PJS008-2003-1]
+PB7.Locked=true
+PB7.Signal=GPIO_Input
+PC1.GPIOParameters=GPIO_Label
+PC1.GPIO_Label=ETH_MDC [RTL8211F_MDC]
+PC1.Locked=true
+PC1.Mode=RGMII (Reduced GMII)
+PC1.Signal=ETH1_MDC
+PC10.GPIOParameters=GPIO_Label
+PC10.GPIO_Label=SDMMC1_D2 [PJS008-2003-1]
+PC10.Locked=true
+PC10.Mode=SD_4_bits_Wide_bus
+PC10.Signal=SDMMC1_D2
+PC11.GPIOParameters=GPIO_Label
+PC11.GPIO_Label=SDMMC1_D3 [PJS008-2003-1]
+PC11.Locked=true
+PC11.Mode=SD_4_bits_Wide_bus
+PC11.Signal=SDMMC1_D3
+PC12.GPIOParameters=GPIO_Label
+PC12.GPIO_Label=SDMMC1_CK [PJS008-2003-1]
+PC12.Locked=true
+PC12.Mode=SD_4_bits_Wide_bus
+PC12.Signal=SDMMC1_CK
+PC13.GPIOParameters=GPIO_Label
+PC13.GPIO_Label=PMIC_WAKEUP [STPMU1A_WAKEUP]
+PC13.Locked=true
+PC13.Signal=GPIO_Output
+PC14-OSC32_IN.Locked=true
+PC14-OSC32_IN.Mode=LSE-External-Oscillator
+PC14-OSC32_IN.Signal=RCC_OSC32_IN
+PC15-OSC32_OUT.Locked=true
+PC15-OSC32_OUT.Mode=LSE-External-Oscillator
+PC15-OSC32_OUT.Signal=RCC_OSC32_OUT
+PC2.GPIOParameters=GPIO_Label
+PC2.GPIO_Label=ETH_TXD2 [RTL8211F_TXD2]
+PC2.Locked=true
+PC2.Mode=RGMII (Reduced GMII)
+PC2.Signal=ETH1_TXD2
+PC4.GPIOParameters=GPIO_Label
+PC4.GPIO_Label=ETH_RXD0 [RTL8211F_RXD0_RXDLY]
+PC4.Locked=true
+PC4.Mode=RGMII (Reduced GMII)
+PC4.Signal=ETH1_RXD0
+PC5.GPIOParameters=GPIO_Label
+PC5.GPIO_Label=ETH_RXD1 [RTL8211F_RXD1_TXDLY]
+PC5.Locked=true
+PC5.Mode=RGMII (Reduced GMII)
+PC5.Signal=ETH1_RXD1
+PC6.GPIOParameters=GPIO_Label
+PC6.GPIO_Label=TE  [FH26W-25S_TE]
+PC6.Locked=true
+PC6.Signal=GPIO_Output
+PC8.GPIOParameters=GPIO_Label
+PC8.GPIO_Label=SDMMC1_D0 [PJS008-2003-1]
+PC8.Locked=true
+PC8.Mode=SD_4_bits_Wide_bus
+PC8.Signal=SDMMC1_D0
+PC9.GPIOParameters=GPIO_Label
+PC9.GPIO_Label=SDMMC1_D1 [PJS008-2003-1]
+PC9.Locked=true
+PC9.Mode=SD_4_bits_Wide_bus
+PC9.Signal=SDMMC1_D1
+PD0.GPIOParameters=GPIO_Label
+PD0.GPIO_Label=WL_HOST_WAKE [LBEE5KL1DX_WL_HOST_WAKE]
+PD0.Locked=true
+PD0.Signal=GPIO_Input
+PD11.GPIOParameters=GPIO_Label
+PD11.GPIO_Label=LED_B [LD8_BLUE]
+PD11.Locked=true
+PD11.Signal=GPIO_Output
+PD12.GPIOParameters=GPIO_Label
+PD12.GPIO_Label=I2C1_SCL [CS42L51-CNZ_SCL]
+PD12.Locked=true
+PD12.Mode=I2C
+PD12.Signal=I2C1_SCL
+PD2.GPIOParameters=GPIO_Label
+PD2.GPIO_Label=SDMMC1_CMD [PJS008-2003-1]
+PD2.Locked=true
+PD2.Mode=SD_4_bits_Wide_bus
+PD2.Signal=SDMMC1_CMD
+PD3.GPIOParameters=GPIO_Label
+PD3.GPIO_Label=USART2_CTS [LBEE5KL1DX_BT_UART_CTS_N]
+PD3.Locked=true
+PD3.Mode=CTS_RTS
+PD3.Signal=USART2_CTS
+PD4.GPIOParameters=GPIO_Label
+PD4.GPIO_Label=USART2_RTS [LBEE5KL1DX_BT_UART_RTS_N]
+PD4.Locked=true
+PD4.Mode=CTS_RTS
+PD4.Signal=USART2_RTS
+PD5.GPIOParameters=GPIO_Label
+PD5.GPIO_Label=USART2_TX [LBEE5KL1DX_BT_UART_TX]
+PD5.Locked=true
+PD5.Mode=Asynchronous
+PD5.Signal=USART2_TX
+PD6.GPIOParameters=GPIO_Label
+PD6.GPIO_Label=USART2_RX [LBEE5KL1DX_BT_UART_RX]
+PD6.Locked=true
+PD6.Mode=Asynchronous
+PD6.Signal=USART2_RX
+PE2.GPIOParameters=GPIO_Label
+PE2.GPIO_Label=ETH_TXD3 [RTL8211F_TXD3]
+PE2.Locked=true
+PE2.Mode=RGMII (Reduced GMII)
+PE2.Signal=ETH1_TXD3
+PE3.GPIOParameters=GPIO_Label
+PE3.GPIO_Label=SDMMC2_CK [LBEE5KL1DX_SDIO_CK]
+PE3.Locked=true
+PE3.Mode=SD_4_bits_Wide_bus
+PE3.Signal=SDMMC2_CK
+PE4.GPIOParameters=GPIO_Label
+PE4.GPIO_Label=RSTN  [FH26W-25S_RSTN]
+PE4.Locked=true
+PE4.Signal=GPIO_Output
+PF15.GPIOParameters=GPIO_Label
+PF15.GPIO_Label=I2C1_SDA [CS42L51-CNZ_SDA]
+PF15.Locked=true
+PF15.Mode=I2C
+PF15.Signal=I2C1_SDA
+PF2.GPIOParameters=GPIO_Label
+PF2.GPIO_Label=INT [FH26W-25S_INT]
+PF2.Locked=true
+PF2.Signal=GPIO_Input
+PG1.GPIOParameters=GPIO_Label
+PG1.GPIO_Label=HDMI_INT [SiI9022ACNU_INT]
+PG1.Locked=true
+PG1.Signal=GPIO_Input
+PG11.GPIOParameters=GPIO_Label
+PG11.GPIO_Label=STLINK_RX [STM32F103CBT6_PA3]
+PG11.Locked=true
+PG11.Mode=Asynchronous
+PG11.Signal=UART4_TX
+PG13.GPIOParameters=GPIO_Label
+PG13.GPIO_Label=ETH_TXD0 [RTL8211F_TXD0]
+PG13.Locked=true
+PG13.Mode=RGMII (Reduced GMII)
+PG13.Signal=ETH1_TXD0
+PG14.GPIOParameters=GPIO_Label
+PG14.GPIO_Label=ETH_TXD1 [RTL8211F_TXD1]
+PG14.Locked=true
+PG14.Mode=RGMII (Reduced GMII)
+PG14.Signal=ETH1_TXD1
+PG4.GPIOParameters=GPIO_Label
+PG4.GPIO_Label=ETH_GTX_CLK [RTL8211F_TXCLK]
+PG4.Locked=true
+PG4.Mode=RGMII (Reduced GMII)
+PG4.Signal=ETH1_GTX_CLK
+PG5.GPIOParameters=GPIO_Label
+PG5.GPIO_Label=ETH_CLK125 [RTL8211F_CLKOUT]
+PG5.Locked=true
+PG5.Mode=ETH 125MHz Clock Input
+PG5.Signal=ETH1_CLK125
+PG6.GPIOParameters=GPIO_Label
+PG6.GPIO_Label=SDMMC2_CMD [LBEE5KL1DX_SDIO_CMD]
+PG6.Locked=true
+PG6.Mode=SD_4_bits_Wide_bus
+PG6.Signal=SDMMC2_CMD
+PG9.GPIOParameters=GPIO_Label
+PG9.GPIO_Label=AUDIO_RST [CS42L51-CNZ_RESET]
+PG9.Locked=true
+PG9.Signal=GPIO_Output
+PH0-OSC_IN.Locked=true
+PH0-OSC_IN.Mode=HSE-External-Oscillator
+PH0-OSC_IN.Signal=RCC_OSC_IN
+PH1-OSC_OUT.Locked=true
+PH1-OSC_OUT.Mode=HSE-External-Oscillator
+PH1-OSC_OUT.Signal=RCC_OSC_OUT
+PH4.GPIOParameters=GPIO_Label
+PH4.GPIO_Label=WL_REG_ON [LBEE5KL1DX_WL_REG_ON]
+PH4.Locked=true
+PH4.Signal=GPIO_Output
+PH5.GPIOParameters=GPIO_Label
+PH5.GPIO_Label=BT_HOST_WAKE [LBEE5KL1DX_BT_HOST_WAKE]
+PH5.Locked=true
+PH5.Signal=GPIO_Input
+PH7.GPIOParameters=GPIO_Label
+PH7.GPIO_Label=LED_Y [LD7_ORANGE]
+PH7.Locked=true
+PH7.Signal=GPIO_Output
+PI11.GPIOParameters=GPIO_Label
+PI11.GPIO_Label=STUSB1600_IRQOUTn [STUSB1600_ALERT\#]
+PI11.Locked=true
+PI11.Signal=GPIO_Input
+PI8.GPIOParameters=GPIO_Label
+PI8.GPIO_Label=LPO_32 [LBEE5KL1DX_LPO_IN]
+PI8.Locked=true
+PI8.Signal=GPIO_Output
+PZ0.GPIOParameters=GPIO_Label
+PZ0.GPIO_Label=BT_PCM_CLK [LBEE5KL1DX_BT_PCM_CLK]
+PZ0.Locked=true
+PZ0.Mode=Full_Duplex_Master
+PZ0.Signal=I2S1_CK
+PZ1.GPIOParameters=GPIO_Label
+PZ1.GPIO_Label=BT_PCM_SDI [LBEE5KL1DX_BT_PCM_OUT]
+PZ1.Locked=true
+PZ1.Mode=Full_Duplex_Master
+PZ1.Signal=I2S1_SDI
+PZ2.GPIOParameters=GPIO_Label
+PZ2.GPIO_Label=BT_PCM_SDO [LBEE5KL1DX_BT_PCM_IN]
+PZ2.Locked=true
+PZ2.Mode=Full_Duplex_Master
+PZ2.Signal=I2S1_SDO
+PZ3.GPIOParameters=GPIO_Label
+PZ3.GPIO_Label=BT_PCM_WS [LBEE5KL1DX_BT_PCM_SYNC]
+PZ3.Locked=true
+PZ3.Mode=Full_Duplex_Master
+PZ3.Signal=I2S1_WS
+PZ4.GPIOParameters=GPIO_Label
+PZ4.GPIO_Label=I2C4_SCL [STPMU1A_SCL]
+PZ4.Locked=true
+PZ4.Mode=I2C
+PZ4.Signal=I2C4_SCL
+PZ5.GPIOParameters=GPIO_Label
+PZ5.GPIO_Label=I2C4_SDA [STPMU1A_SDA]
+PZ5.Locked=true
+PZ5.Mode=I2C
+PZ5.Signal=I2C4_SDA
+PZ6.GPIOParameters=GPIO_Label
+PZ6.GPIO_Label=BT_REG_ON [LBEE5KL1DX_BT_REG_ON]
+PZ6.Locked=true
+PZ6.Signal=GPIO_Output
+PZ7.GPIOParameters=GPIO_Label
+PZ7.GPIO_Label=BT_DEV_WAKE [LBEE5KL1DX_BT_DEV_WAKE]
+PZ7.Locked=true
+PZ7.Signal=GPIO_Output
+PinOutPanel.CurrentBGAView=Top
+PinOutPanel.RotationAngle=0
+RCC.ADCFreq_Value=74250000
+RCC.AHB1234Freq_Value=196000000
+RCC.APB1DIV=RCC_APB1_DIV2
+RCC.APB1Freq_Value=98000000
+RCC.APB2DIV=RCC_APB2_DIV2
+RCC.APB2Freq_Value=98000000
+RCC.APB3DIV=RCC_APB3_DIV2
+RCC.APB3Freq_Value=98000000
+RCC.APB4DIV=RCC_APB4_DIV2
+RCC.APB4Freq_Value=132000000
+RCC.APB5DIV=RCC_APB5_DIV4
+RCC.APB5DIVClockFreq_Value=66000000
+RCC.AXICLKFreq_VALUE=264000000
+RCC.AXICLKSource=RCC_AXISSOURCE_PLL2
+RCC.AXIDIVFreq_Value=264000000
+RCC.CECFreq_Value=32768
+RCC.CKPERCLKFreq_VALUE=64000000
+RCC.CSI_VALUE=4000000
+RCC.CortexFreq_Value=196000000
+RCC.DACCLKFreq_VALUE=32000
+RCC.DDRCFreq_Value=528000000
+RCC.DDRPERFMFreq_Value=528000000
+RCC.DDRPHYFreq_Value=528000000
+RCC.DFSDFAFreq_Value=74250000
+RCC.DFSDMFreq_Value=196000000
+RCC.DIVM1=3
+RCC.DIVM2=3
+RCC.DIVM3=3
+RCC.DIVM4=4
+RCC.DIVN1=81
+RCC.DIVN2=66
+RCC.DIVN3=98
+RCC.DIVN4=99
+RCC.DIVP1Freq_Value=648000000
+RCC.DIVP2Freq_Value=264000000
+RCC.DIVP3=4
+RCC.DIVP3Freq_Value=196000000
+RCC.DIVP4=8
+RCC.DIVP4Freq_Value=74250000
+RCC.DIVQ1Freq_Value=324000000
+RCC.DIVQ2Freq_Value=264000000
+RCC.DIVQ3=16
+RCC.DIVQ3Freq_Value=49000000
+RCC.DIVQ4=8
+RCC.DIVQ4Freq_Value=74250000
+RCC.DIVR1Freq_Value=324000000
+RCC.DIVR2=1
+RCC.DIVR2Freq_Value=528000000
+RCC.DIVR3=8
+RCC.DIVR3Freq_Value=98000000
+RCC.DIVR4=8
+RCC.DIVR4Freq_Value=74250000
+RCC.DSIFreq_Value=60000000
+RCC.DSITXEscFreq_Value=15000000
+RCC.DSI_VALUE=60000000
+RCC.ETHFreq_Value=74250000
+RCC.FCLKFreq_Value=196000000
+RCC.FDCANFreq_Value=24000000
+RCC.FMCFreq_Value=264000000
+RCC.FamilyName=M
+RCC.HSE_VALUE=24000000
+RCC.HSIDivClkFreq_Value=64000000
+RCC.HSI_VALUE=64000000
+RCC.Hclk5DIVFreq_Value=264000000
+RCC.Hclk6DIVFreq_Value=264000000
+RCC.I2C12CLockSelection=RCC_I2C12CLKSOURCE_HSI
+RCC.I2C12Freq_Value=64000000
+RCC.I2C35Freq_Value=98000000
+RCC.I2C46CLockSelection=RCC_I2C46CLKSOURCE_HSI
+RCC.I2C46Freq_Value=64000000
+RCC.IPParameters=ADCFreq_Value,AHB1234Freq_Value,APB1DIV,APB1Freq_Value,APB2DIV,APB2Freq_Value,APB3DIV,APB3Freq_Value,APB4DIV,APB4Freq_Value,APB5DIV,APB5DIVClockFreq_Value,AXICLKFreq_VALUE,AXICLKSource,AXIDIVFreq_Value,CECFreq_Value,CKPERCLKFreq_VALUE,CSI_VALUE,CortexFreq_Value,DACCLKFreq_VALUE,DDRCFreq_Value,DDRPERFMFreq_Value,DDRPHYFreq_Value,DFSDFAFreq_Value,DFSDMFreq_Value,DIVM1,DIVM2,DIVM3,DIVM4,DIVN1,DIVN2,DIVN3,DIVN4,DIVP1Freq_Value,DIVP2Freq_Value,DIVP3,DIVP3Freq_Value,DIVP4,DIVP4Freq_Value,DIVQ1Freq_Value,DIVQ2Freq_Value,DIVQ3,DIVQ3Freq_Value,DIVQ4,DIVQ4Freq_Value,DIVR1Freq_Value,DIVR2,DIVR2Freq_Value,DIVR3,DIVR3Freq_Value,DIVR4,DIVR4Freq_Value,DSIFreq_Value,DSITXEscFreq_Value,DSI_VALUE,ETHFreq_Value,FCLKFreq_Value,FDCANFreq_Value,FMCFreq_Value,FamilyName,HSE_VALUE,HSIDivClkFreq_Value,HSI_VALUE,Hclk5DIVFreq_Value,Hclk6DIVFreq_Value,I2C12CLockSelection,I2C12Freq_Value,I2C35Freq_Value,I2C46CLockSelection,I2C46Freq_Value,LPTIM1Freq_Value,LPTIM23Freq_Value,LPTIM45Freq_Value,LSI_VALUE,LTDCFreq_Value,MCO1PinFreq_Value,MCO2PinFreq_Value,MCUCLKFreq_VALUE,MCUCLKSource,MCUClockFreq_Value,MPUCLKFreq_VALUE,MPUCLKSource,PLL12Source,PLL1FRACV,PLL1MODE,PLL2FRACV,PLL2MODE,PLL3FRACV,PLL3MODE,PLL3Source,PLL4PDSIFreq_Value,PLL4Source,PLLDSIFreq_Value,PLLDSIVCOFreq_Value,PUBLFreq_Value,QSPIFreq_Value,RCC_RTC_Clock_Source_FROM_HSE,RTCClockSelection,RTCFreq_Value,SAI1Freq_Value,SAI2Freq_Value,SAI3Freq_Value,SAI4Freq_Value,SDMMC12CLockSelection,SDMMC12Freq_Value,SDMMC3Freq_Value,SPDIFRXFreq_Value,SPI1CLockSelection,SPI1Freq_Value,SPI23Freq_Value,SPI45Freq_Value,SPI6Freq_Value,STGENCLockSelection,STGENFreq_Value,Tim1OutputFreq_Value,Tim2OutputFreq_Value,UART78Freq_Value,USART1Freq_Value,USART24CLockSelection,USART24Freq_Value,USART35Freq_Value,USART6Freq_Value,USBOHSFreq_Value,USBPHYFreq_Value,VCO1OutputFreq_Value,VCO2OutputFreq_Value,VCO3OutputFreq_Value,VCO4OutputFreq_Value,VCOInput1Freq_Value,VCOInput2Freq_Value,VCOInput3Freq_Value,VCOInput4Freq_Value
+RCC.LPTIM1Freq_Value=98000000
+RCC.LPTIM23Freq_Value=98000000
+RCC.LPTIM45Freq_Value=98000000
+RCC.LSI_VALUE=32000
+RCC.LTDCFreq_Value=74250000
+RCC.MCO1PinFreq_Value=64000000
+RCC.MCO2PinFreq_Value=648000000
+RCC.MCUCLKFreq_VALUE=196000000
+RCC.MCUCLKSource=RCC_MCUSSOURCE_PLL3
+RCC.MCUClockFreq_Value=196000000
+RCC.MPUCLKFreq_VALUE=648000000
+RCC.MPUCLKSource=RCC_MPUSOURCE_PLL1
+RCC.PLL12Source=RCC_PLL12SOURCE_HSE
+RCC.PLL1FRACV=0x800
+RCC.PLL1MODE=RCC_PLL_FRACTIONAL
+RCC.PLL2FRACV=0x1400
+RCC.PLL2MODE=RCC_PLL_FRACTIONAL
+RCC.PLL3FRACV=0x9ba
+RCC.PLL3MODE=RCC_PLL_FRACTIONAL
+RCC.PLL3Source=RCC_PLL3SOURCE_HSE
+RCC.PLL4PDSIFreq_Value=74250000
+RCC.PLL4Source=RCC_PLL4SOURCE_HSE
+RCC.PLLDSIFreq_Value=480000000
+RCC.PLLDSIVCOFreq_Value=960000000
+RCC.PUBLFreq_Value=528000000
+RCC.QSPIFreq_Value=264000000
+RCC.RCC_RTC_Clock_Source_FROM_HSE=24
+RCC.RTCClockSelection=RCC_RTCCLKSOURCE_LSE
+RCC.RTCFreq_Value=32768
+RCC.SAI1Freq_Value=74250000
+RCC.SAI2Freq_Value=74250000
+RCC.SAI3Freq_Value=74250000
+RCC.SAI4Freq_Value=74250000
+RCC.SDMMC12CLockSelection=RCC_SDMMC12CLKSOURCE_PLL3
+RCC.SDMMC12Freq_Value=98000000
+RCC.SDMMC3Freq_Value=196000000
+RCC.SPDIFRXFreq_Value=74250000
+RCC.SPI1CLockSelection=RCC_SPI1CLKSOURCE_PLL3_Q
+RCC.SPI1Freq_Value=49000000
+RCC.SPI23Freq_Value=74250000
+RCC.SPI45Freq_Value=98000000
+RCC.SPI6Freq_Value=66000000
+RCC.STGENCLockSelection=RCC_STGENCLKSOURCE_HSE
+RCC.STGENFreq_Value=24000000
+RCC.Tim1OutputFreq_Value=196000000
+RCC.Tim2OutputFreq_Value=196000000
+RCC.UART78Freq_Value=98000000
+RCC.USART1Freq_Value=66000000
+RCC.USART24CLockSelection=RCC_UART24CLKSOURCE_HSI
+RCC.USART24Freq_Value=64000000
+RCC.USART35Freq_Value=98000000
+RCC.USART6Freq_Value=98000000
+RCC.USBOHSFreq_Value=74250000
+RCC.USBPHYFreq_Value=74250000
+RCC.VCO1OutputFreq_Value=1296000000
+RCC.VCO2OutputFreq_Value=1056000000
+RCC.VCO3OutputFreq_Value=784000000
+RCC.VCO4OutputFreq_Value=594000000
+RCC.VCOInput1Freq_Value=8000000
+RCC.VCOInput2Freq_Value=8000000
+RCC.VCOInput3Freq_Value=8000000
+RCC.VCOInput4Freq_Value=6000000
+USART2.IPParameters=VirtualMode-Asynchronous
+USART2.VirtualMode-Asynchronous=VM_ASYNC
+USB_DM1.GPIOParameters=GPIO_Label
+USB_DM1.GPIO_Label=USB_HUB_N [USB2514B_USB_UP_DM]
+USB_DM1.Locked=true
+USB_DM1.Mode=Enable
+USB_DM1.Signal=USBH_HS1_DM
+USB_DP1.GPIOParameters=GPIO_Label
+USB_DP1.GPIO_Label=USB_HUB_P [USB2514B_USB_UP_DP]
+USB_DP1.Locked=true
+USB_DP1.Mode=Enable
+USB_DP1.Signal=USBH_HS1_DP
+VP_DDR_DDR3.Mode=DDR3
+VP_DDR_DDR3.Signal=DDR_DDR3
+VP_DDR_DDR3_16_4Gb.Mode=4Gb_16bits
+VP_DDR_DDR3_16_4Gb.Signal=DDR_DDR3_16_4Gb
+VP_DDR_DDR_16_bits.Mode=16bits
+VP_DDR_DDR_16_bits.Signal=DDR_DDR_16_bits
+VP_DMA_VS_DMA1_A7NS.Mode=Cortex-A7 non secure
+VP_DMA_VS_DMA1_A7NS.Signal=DMA_VS_DMA1_A7NS
+VP_DMA_VS_DMA2_M4.Mode=Cortex-M4
+VP_DMA_VS_DMA2_M4.Signal=DMA_VS_DMA2_M4
+VP_LTDC_DSIMode.Mode=RGB888
+VP_LTDC_DSIMode.Signal=LTDC_DSIMode
+VP_RTC_VS_RTC_Activate.Mode=RTC_Enabled
+VP_RTC_VS_RTC_Activate.Signal=RTC_VS_RTC_Activate
+board=STM32MP157C-DK2
diff --git a/conf/machine/cubemx/t1000-calib/t1000-calib.ioc b/conf/machine/cubemx/t1000-calib/t1000-calib.ioc
new file mode 100644
index 0000000000000000000000000000000000000000..83193d8b6c6e38e06a9bfdec89ab179573a83382
--- /dev/null
+++ b/conf/machine/cubemx/t1000-calib/t1000-calib.ioc
@@ -0,0 +1,1106 @@
+#MicroXplorer Configuration settings - do not modify
+Boot\ ROM.IPs=SDMMC1,SDMMC2,UART4
+Boot\ loader.IPs=RCC,I2C4,SDMMC1,SDMMC2,UART4,USART2
+Cortex-A7\ non\ secure.IPs=DDR\:I,RCC\:I,RTC\:I,SYS\:I,I2C4\:I,I2C1\:I,LTDC\:I,DSIHOST\:I,USBH_HS1\:I,HDMI_CEC\:I,ETH1\:I,SDMMC1\:I,USART2\:I,I2S1\:I,SDMMC2\:I,UART4\:I,DMA1\:I
+Cortex-M4.IPs=RCC,WWDG1\:I,NVIC\:I,DMA2\:I
+DDR.0dqdly0=0
+DDR.0dqdly1=1
+DDR.0dqdly2=1
+DDR.0dqdly3=0
+DDR.0dqdly4=0
+DDR.0dqdly5=1
+DDR.0dqdly6=0
+DDR.0dqdly7=0
+DDR.0sdphase=3
+DDR.1dqdly0=0
+DDR.1dqdly1=1
+DDR.1dqdly2=1
+DDR.1dqdly3=0
+DDR.1dqdly4=0
+DDR.1dqdly5=1
+DDR.1dqdly6=0
+DDR.1dqdly7=0
+DDR.1dqsdly=2
+DDR.1dqsndly=2
+DDR.1sdphase=3
+DDR.ADDRMAP1=0x00070707
+DDR.ADDRMAP3=0x1F000000
+DDR.ADDRMAP5=0x06060606
+DDR.ADDRMAP6=0x0F060606
+DDR.DFITMG0=0x02050105
+DDR.DRAMTMG0=0x121B1214
+DDR.DRAMTMG2=0x0607080F
+DDR.DRAMTMG4=0x07040607
+DDR.DRAMTMG5=0x06060403
+DDR.DTPR0=0x36D477D0
+DDR.DTPR1=0x098A00D8
+DDR.DX0DLLCR=0x4000C000
+DDR.DX0DQTR=0x00100110
+DDR.DX1DLLCR=0x4000C000
+DDR.DX1DQSTR=0x3D202000
+DDR.DX1DQTR=0x00100110
+DDR.IPParameters=tREFI,MSTR,RFSHTMG,DRAMTMG0,DRAMTMG2,DRAMTMG4,DRAMTMG5,DFITMG0,PCFGQOS1_1,PTR0,PTR1,PTR2,DTPR0,DTPR1,ZQ0CR1,addrmap_col_b9,addrmap_col_b10,addrmap_col_b11,addrmap_bank_b0,addrmap_bank_b1,addrmap_bank_b2,addrmap_row_b0,addrmap_row_b1,addrmap_row_b2_10,addrmap_row_b11,addrmap_row_b12,addrmap_row_b13,addrmap_row_b14,addrmap_row_b15,wr2pre,t_faw,t_ras_max,t_ras_min,t_xp,t_rd2pre,t_rp,t_rc,t_cksrx,t_cksre,t_ckesr,t_cke,t_xs_dll_x32,t_xs_x32,t_rfc_nom_x1_x32,t_rfc_min,dfi_t_rddata_en,tdlllock,tdllsrst,tdinit1,tdinit0,tdinit2,tccd,trc,trrd,tras,trcd,trp,twtr,trtp,tmrd,trfc,tmod,tfaw,tdllk,tcke,txp,txs,MR0.WR,MR0.CL,MR2.RTT,MR2.CWL,data_bus_width,ADDRMAP1,ADDRMAP3,ADDRMAP5,ADDRMAP6,0sdphase,0dqdly0,0dqdly1,0dqdly2,0dqdly3,0dqdly4,0dqdly5,0dqdly6,0dqdly7,1sdphase,1dqsndly,1dqsdly,1dqdly0,1dqdly1,1dqdly2,1dqdly3,1dqdly4,1dqdly5,1dqdly6,1dqdly7,DX0DLLCR,DX0DQTR,DX1DLLCR,DX1DQTR,DX1DQSTR
+DDR.MR0.CL=3
+DDR.MR0.WR=4
+DDR.MR2.CWL=1
+DDR.MR2.RTT=1
+DDR.MSTR=0x00041401
+DDR.PCFGQOS1_1=0x00800000
+DDR.PTR0=0x0022A41B
+DDR.PTR1=0x047C0740
+DDR.PTR2=0x042D9C80
+DDR.RFSHTMG=0x0040008A
+DDR.ZQ0CR1=0x00000038
+DDR.addrmap_bank_b0=7
+DDR.addrmap_bank_b1=7
+DDR.addrmap_bank_b2=7
+DDR.addrmap_col_b10=31
+DDR.addrmap_col_b11=31
+DDR.addrmap_col_b9=31
+DDR.addrmap_row_b0=6
+DDR.addrmap_row_b1=6
+DDR.addrmap_row_b11=6
+DDR.addrmap_row_b12=6
+DDR.addrmap_row_b13=6
+DDR.addrmap_row_b14=6
+DDR.addrmap_row_b15=15
+DDR.addrmap_row_b2_10=6
+DDR.data_bus_width=1
+DDR.dfi_t_rddata_en=5
+DDR.tREFI=3.9
+DDR.t_cke=3
+DDR.t_ckesr=4
+DDR.t_cksre=6
+DDR.t_cksrx=6
+DDR.t_faw=27
+DDR.t_ras_max=18
+DDR.t_ras_min=20
+DDR.t_rc=27
+DDR.t_rd2pre=4
+DDR.t_rfc_min=138
+DDR.t_rfc_nom_x1_x32=64
+DDR.t_rp=7
+DDR.t_xp=10
+DDR.t_xs_dll_x32=16
+DDR.t_xs_x32=5
+DDR.tccd=0
+DDR.tcke=4
+DDR.tdinit0=264000
+DDR.tdinit1=143
+DDR.tdinit2=105600
+DDR.tdllk=512
+DDR.tdlllock=2704
+DDR.tdllsrst=27
+DDR.tfaw=27
+DDR.tmod=0
+DDR.tmrd=0
+DDR.tras=20
+DDR.trc=27
+DDR.trcd=7
+DDR.trfc=138
+DDR.trp=7
+DDR.trrd=6
+DDR.trtp=4
+DDR.twtr=6
+DDR.txp=13
+DDR.txs=512
+DDR.wr2pre=18
+DDR_A0.Locked=true
+DDR_A0.Mode=DDR3
+DDR_A0.Signal=DDR_A0
+DDR_A1.Locked=true
+DDR_A1.Mode=DDR3
+DDR_A1.Signal=DDR_A1
+DDR_A10.Locked=true
+DDR_A10.Mode=DDR3
+DDR_A10.Signal=DDR_A10
+DDR_A11.Locked=true
+DDR_A11.Mode=DDR3
+DDR_A11.Signal=DDR_A11
+DDR_A12.Locked=true
+DDR_A12.Mode=4Gb_16bits
+DDR_A12.Signal=DDR_A12
+DDR_A13.Locked=true
+DDR_A13.Mode=4Gb_16bits
+DDR_A13.Signal=DDR_A13
+DDR_A14.Locked=true
+DDR_A14.Mode=4Gb_16bits
+DDR_A14.Signal=DDR_A14
+DDR_A2.Locked=true
+DDR_A2.Mode=DDR3
+DDR_A2.Signal=DDR_A2
+DDR_A3.Locked=true
+DDR_A3.Mode=DDR3
+DDR_A3.Signal=DDR_A3
+DDR_A4.Locked=true
+DDR_A4.Mode=DDR3
+DDR_A4.Signal=DDR_A4
+DDR_A5.Locked=true
+DDR_A5.Mode=DDR3
+DDR_A5.Signal=DDR_A5
+DDR_A6.Locked=true
+DDR_A6.Mode=DDR3
+DDR_A6.Signal=DDR_A6
+DDR_A7.Locked=true
+DDR_A7.Mode=DDR3
+DDR_A7.Signal=DDR_A7
+DDR_A8.Locked=true
+DDR_A8.Mode=DDR3
+DDR_A8.Signal=DDR_A8
+DDR_A9.Locked=true
+DDR_A9.Mode=DDR3
+DDR_A9.Signal=DDR_A9
+DDR_ATO.Locked=true
+DDR_ATO.Mode=DDR3
+DDR_ATO.Signal=DDR_ATO
+DDR_BA0.Locked=true
+DDR_BA0.Mode=DDR3
+DDR_BA0.Signal=DDR_BA0
+DDR_BA1.Locked=true
+DDR_BA1.Mode=DDR3
+DDR_BA1.Signal=DDR_BA1
+DDR_BA2.Locked=true
+DDR_BA2.Mode=DDR3
+DDR_BA2.Signal=DDR_BA2
+DDR_CASN.Locked=true
+DDR_CASN.Mode=DDR3
+DDR_CASN.Signal=DDR_CASN
+DDR_CKE.Locked=true
+DDR_CKE.Mode=DDR3
+DDR_CKE.Signal=DDR_CKE
+DDR_CLKN.Locked=true
+DDR_CLKN.Mode=DDR3
+DDR_CLKN.Signal=DDR_CLKN
+DDR_CLKP.Locked=true
+DDR_CLKP.Mode=DDR3
+DDR_CLKP.Signal=DDR_CLKP
+DDR_CSN.Locked=true
+DDR_CSN.Mode=DDR3
+DDR_CSN.Signal=DDR_CSN
+DDR_DQ0.Locked=true
+DDR_DQ0.Mode=DDR3
+DDR_DQ0.Signal=DDR_DQ0
+DDR_DQ1.Locked=true
+DDR_DQ1.Mode=DDR3
+DDR_DQ1.Signal=DDR_DQ1
+DDR_DQ10.Locked=true
+DDR_DQ10.Mode=DDR3
+DDR_DQ10.Signal=DDR_DQ10
+DDR_DQ11.Locked=true
+DDR_DQ11.Mode=DDR3
+DDR_DQ11.Signal=DDR_DQ11
+DDR_DQ12.Locked=true
+DDR_DQ12.Mode=DDR3
+DDR_DQ12.Signal=DDR_DQ12
+DDR_DQ13.Locked=true
+DDR_DQ13.Mode=DDR3
+DDR_DQ13.Signal=DDR_DQ13
+DDR_DQ14.Locked=true
+DDR_DQ14.Mode=DDR3
+DDR_DQ14.Signal=DDR_DQ14
+DDR_DQ15.Locked=true
+DDR_DQ15.Mode=DDR3
+DDR_DQ15.Signal=DDR_DQ15
+DDR_DQ2.Locked=true
+DDR_DQ2.Mode=DDR3
+DDR_DQ2.Signal=DDR_DQ2
+DDR_DQ3.Locked=true
+DDR_DQ3.Mode=DDR3
+DDR_DQ3.Signal=DDR_DQ3
+DDR_DQ4.Locked=true
+DDR_DQ4.Mode=DDR3
+DDR_DQ4.Signal=DDR_DQ4
+DDR_DQ5.Locked=true
+DDR_DQ5.Mode=DDR3
+DDR_DQ5.Signal=DDR_DQ5
+DDR_DQ6.Locked=true
+DDR_DQ6.Mode=DDR3
+DDR_DQ6.Signal=DDR_DQ6
+DDR_DQ7.Locked=true
+DDR_DQ7.Mode=DDR3
+DDR_DQ7.Signal=DDR_DQ7
+DDR_DQ8.Locked=true
+DDR_DQ8.Mode=DDR3
+DDR_DQ8.Signal=DDR_DQ8
+DDR_DQ9.Locked=true
+DDR_DQ9.Mode=DDR3
+DDR_DQ9.Signal=DDR_DQ9
+DDR_DQM0.Locked=true
+DDR_DQM0.Mode=DDR3
+DDR_DQM0.Signal=DDR_DQM0
+DDR_DQM1.Locked=true
+DDR_DQM1.Mode=DDR3
+DDR_DQM1.Signal=DDR_DQM1
+DDR_DQS0N.Locked=true
+DDR_DQS0N.Mode=DDR3
+DDR_DQS0N.Signal=DDR_DQS0N
+DDR_DQS0P.Locked=true
+DDR_DQS0P.Mode=DDR3
+DDR_DQS0P.Signal=DDR_DQS0P
+DDR_DQS1N.Locked=true
+DDR_DQS1N.Mode=DDR3
+DDR_DQS1N.Signal=DDR_DQS1N
+DDR_DQS1P.Locked=true
+DDR_DQS1P.Mode=DDR3
+DDR_DQS1P.Signal=DDR_DQS1P
+DDR_DTO0.Locked=true
+DDR_DTO0.Mode=DDR3
+DDR_DTO0.Signal=DDR_DTO0
+DDR_DTO1.Locked=true
+DDR_DTO1.Mode=DDR3
+DDR_DTO1.Signal=DDR_DTO1
+DDR_ODT.Locked=true
+DDR_ODT.Mode=DDR3
+DDR_ODT.Signal=DDR_ODT
+DDR_RASN.Locked=true
+DDR_RASN.Mode=DDR3
+DDR_RASN.Signal=DDR_RASN
+DDR_RESETN.Locked=true
+DDR_RESETN.Mode=DDR3
+DDR_RESETN.Signal=DDR_RESETN
+DDR_VREF.Locked=true
+DDR_VREF.Mode=DDR3
+DDR_VREF.Signal=DDR_VREF
+DDR_WEN.Locked=true
+DDR_WEN.Mode=DDR3
+DDR_WEN.Signal=DDR_WEN
+DDR_ZQ.Locked=true
+DDR_ZQ.Mode=DDR3
+DDR_ZQ.Signal=DDR_ZQ
+DSIHOST_CKN.Locked=true
+DSIHOST_CKN.Mode=DSIHost_Video
+DSIHOST_CKN.Signal=DSIHOST_CKN
+DSIHOST_CKP.Locked=true
+DSIHOST_CKP.Mode=DSIHost_Video
+DSIHOST_CKP.Signal=DSIHOST_CKP
+DSIHOST_D0N.Locked=true
+DSIHOST_D0N.Mode=DSIHost_Video
+DSIHOST_D0N.Signal=DSIHOST_D0N
+DSIHOST_D0P.Locked=true
+DSIHOST_D0P.Mode=DSIHost_Video
+DSIHOST_D0P.Signal=DSIHOST_D0P
+DSIHOST_D1N.Locked=true
+DSIHOST_D1N.Mode=DSIHost_Video
+DSIHOST_D1N.Signal=DSIHOST_D1N
+DSIHOST_D1P.Locked=true
+DSIHOST_D1P.Mode=DSIHost_Video
+DSIHOST_D1P.Signal=DSIHOST_D1P
+ETH1.IPParameters=MediaInterface
+ETH1.MediaInterface=HAL_ETH_RGMII_MODE
+File.Version=6
+I2S1.ErrorAudioFreq=0.21 %
+I2S1.FullDuplexMode=I2S_MODE_MASTER_FD
+I2S1.IPParameters=Instance,VirtualMode,FullDuplexMode,RealAudioFreq,ErrorAudioFreq
+I2S1.Instance=SPI$Index
+I2S1.RealAudioFreq=8.017 KHz
+I2S1.VirtualMode=I2S_MODE_MASTER
+JTCK-SWCLK.Locked=true
+JTCK-SWCLK.Mode=JTAG_5_pins
+JTCK-SWCLK.Signal=SYS_JTCK-SWCLK
+JTDI.Locked=true
+JTDI.Mode=JTAG_5_pins
+JTDI.Signal=SYS_JTDI
+JTDO-TRACESWO.Locked=true
+JTDO-TRACESWO.Mode=JTAG_5_pins
+JTDO-TRACESWO.Signal=SYS_JTDO-SWO
+JTMS-SWDIO.Locked=true
+JTMS-SWDIO.Mode=JTAG_5_pins
+JTMS-SWDIO.Signal=SYS_JTMS-SWDIO
+KeepUserPlacement=true
+Mcu.Context0=Boot ROM
+Mcu.Context1=Boot loader
+Mcu.Context2=Cortex-A7 non secure
+Mcu.Context3=Cortex-M4
+Mcu.ContextNb=4
+Mcu.Family=STM32MP1
+Mcu.IP0=DDR
+Mcu.IP1=DSIHOST
+Mcu.IP10=RTC
+Mcu.IP11=SDMMC1
+Mcu.IP12=SDMMC2
+Mcu.IP13=SYS
+Mcu.IP14=UART4
+Mcu.IP15=USART2
+Mcu.IP16=USBH_HS1
+Mcu.IP2=ETH1
+Mcu.IP3=HDMI_CEC
+Mcu.IP4=I2C1
+Mcu.IP5=I2C4
+Mcu.IP6=I2S1
+Mcu.IP7=LTDC
+Mcu.IP8=NVIC
+Mcu.IP9=RCC
+Mcu.IPNb=17
+Mcu.Name=STM32MP157CACx
+Mcu.Package=TFBGA361
+Mcu.Pin0=PH5
+Mcu.Pin1=PD5
+Mcu.Pin10=PD4
+Mcu.Pin100=DDR_A6
+Mcu.Pin101=DDR_DQ11
+Mcu.Pin102=DDR_DQ14
+Mcu.Pin103=DDR_DQ12
+Mcu.Pin104=PE2
+Mcu.Pin105=PC2
+Mcu.Pin106=PF15
+Mcu.Pin107=PG5
+Mcu.Pin108=PG11
+Mcu.Pin109=PB5
+Mcu.Pin11=PD0
+Mcu.Pin110=PG9
+Mcu.Pin111=PB6
+Mcu.Pin112=PB2
+Mcu.Pin113=PA10
+Mcu.Pin114=PD12
+Mcu.Pin115=DDR_ATO
+Mcu.Pin116=DDR_A8
+Mcu.Pin117=DDR_DQ15
+Mcu.Pin118=PG14
+Mcu.Pin119=PG13
+Mcu.Pin12=PB15
+Mcu.Pin120=PA1
+Mcu.Pin121=PC1
+Mcu.Pin122=PB1
+Mcu.Pin123=PB11
+Mcu.Pin124=PG4
+Mcu.Pin125=PA0
+Mcu.Pin126=PB0
+Mcu.Pin127=PC5
+Mcu.Pin128=PA7
+Mcu.Pin129=USB_DM1
+Mcu.Pin13=PB4
+Mcu.Pin130=PA2
+Mcu.Pin131=PC4
+Mcu.Pin132=PA6
+Mcu.Pin133=PD11
+Mcu.Pin134=USB_DP1
+Mcu.Pin135=DDR_VREF
+Mcu.Pin136=VP_DDR_DDR3
+Mcu.Pin137=VP_DDR_DDR_16_bits
+Mcu.Pin138=VP_DDR_DDR3_16_4Gb
+Mcu.Pin139=VP_LTDC_DSIMode
+Mcu.Pin14=PC6
+Mcu.Pin140=VP_RTC_VS_RTC_Activate
+Mcu.Pin141=VP_DMA_VS_DMA1_A7NS
+Mcu.Pin142=VP_DMA_VS_DMA2_M4
+Mcu.Pin15=DSIHOST_D0N
+Mcu.Pin16=DSIHOST_CKP
+Mcu.Pin17=DSIHOST_D1P
+Mcu.Pin18=NJTRST
+Mcu.Pin19=JTCK-SWCLK
+Mcu.Pin2=PG6
+Mcu.Pin20=PE3
+Mcu.Pin21=PB14
+Mcu.Pin22=DSIHOST_D0P
+Mcu.Pin23=PA15
+Mcu.Pin24=JTMS-SWDIO
+Mcu.Pin25=PD6
+Mcu.Pin26=PB7
+Mcu.Pin27=PD2
+Mcu.Pin28=PC12
+Mcu.Pin29=PD3
+Mcu.Pin3=PB3
+Mcu.Pin30=PC10
+Mcu.Pin31=PC11
+Mcu.Pin32=PC9
+Mcu.Pin33=PC8
+Mcu.Pin34=PE4
+Mcu.Pin35=DDR_RESETN
+Mcu.Pin36=DDR_A7
+Mcu.Pin37=DDR_DQ3
+Mcu.Pin38=DDR_DQ0
+Mcu.Pin39=DDR_A13
+Mcu.Pin4=PF2
+Mcu.Pin40=DDR_DQ1
+Mcu.Pin41=PZ1
+Mcu.Pin42=PZ4
+Mcu.Pin43=PZ0
+Mcu.Pin44=PZ3
+Mcu.Pin45=DDR_A9
+Mcu.Pin46=DDR_DQ7
+Mcu.Pin47=DDR_DQS0P
+Mcu.Pin48=DDR_DQS0N
+Mcu.Pin49=PZ6
+Mcu.Pin5=DSIHOST_CKN
+Mcu.Pin50=PZ5
+Mcu.Pin51=DDR_A5
+Mcu.Pin52=DDR_DQ2
+Mcu.Pin53=DDR_DQ6
+Mcu.Pin54=DDR_DQM0
+Mcu.Pin55=PZ7
+Mcu.Pin56=PZ2
+Mcu.Pin57=DDR_A2
+Mcu.Pin58=DDR_DQ4
+Mcu.Pin59=DDR_DQ5
+Mcu.Pin6=DSIHOST_D1N
+Mcu.Pin60=PC13
+Mcu.Pin61=DDR_DTO0
+Mcu.Pin62=DDR_A3
+Mcu.Pin63=DDR_ZQ
+Mcu.Pin64=PC15-OSC32_OUT
+Mcu.Pin65=PC14-OSC32_IN
+Mcu.Pin66=PI8
+Mcu.Pin67=DDR_A0
+Mcu.Pin68=DDR_DTO1
+Mcu.Pin69=DDR_ODT
+Mcu.Pin7=JTDO-TRACESWO
+Mcu.Pin70=DDR_BA0
+Mcu.Pin71=DDR_WEN
+Mcu.Pin72=DDR_BA2
+Mcu.Pin73=DDR_CSN
+Mcu.Pin74=PA13
+Mcu.Pin75=DDR_CASN
+Mcu.Pin76=DDR_RASN
+Mcu.Pin77=DDR_CLKP
+Mcu.Pin78=DDR_CLKN
+Mcu.Pin79=PH0-OSC_IN
+Mcu.Pin8=JTDI
+Mcu.Pin80=PH1-OSC_OUT
+Mcu.Pin81=PI11
+Mcu.Pin82=DDR_A1
+Mcu.Pin83=DDR_A12
+Mcu.Pin84=DDR_A11
+Mcu.Pin85=DDR_A14
+Mcu.Pin86=DDR_A10
+Mcu.Pin87=PA14
+Mcu.Pin88=DDR_CKE
+Mcu.Pin89=DDR_DQ8
+Mcu.Pin9=PH4
+Mcu.Pin90=DDR_DQ10
+Mcu.Pin91=DDR_DQ13
+Mcu.Pin92=DDR_BA1
+Mcu.Pin93=DDR_DQ9
+Mcu.Pin94=DDR_DQS1P
+Mcu.Pin95=DDR_DQS1N
+Mcu.Pin96=DDR_A4
+Mcu.Pin97=DDR_DQM1
+Mcu.Pin98=PG1
+Mcu.Pin99=PH7
+Mcu.PinsNb=143
+Mcu.ThirdPartyNb=0
+Mcu.UserConstants=
+Mcu.UserName=STM32MP157CACx
+MxCube.Version=4.99.1
+MxDb.Version=DB.4.0.270
+NJTRST.Locked=true
+NJTRST.Mode=JTAG_5_pins
+NJTRST.Signal=SYS_JTRST
+NVIC.BusFault_IRQn=true\:0\:0\:false\:false\:true\:false
+NVIC.DebugMonitor_IRQn=true\:0\:0\:false\:false\:true\:false
+NVIC.HardFault_IRQn=true\:0\:0\:false\:false\:true\:false
+NVIC.MemoryManagement_IRQn=true\:0\:0\:false\:false\:true\:false
+NVIC.NonMaskableInt_IRQn=true\:0\:0\:false\:false\:true\:false
+NVIC.PendSV_IRQn=true\:0\:0\:false\:false\:true\:false
+NVIC.PriorityGroup=NVIC_PRIORITYGROUP_4
+NVIC.SVCall_IRQn=true\:0\:0\:false\:false\:true\:false
+NVIC.SysTick_IRQn=true\:0\:0\:false\:false\:true\:false
+NVIC.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:false
+PA0.Locked=true
+PA0.Mode=SYS_WakeUp1
+PA0.Signal=SYS_WKUP1
+PA1.GPIOParameters=GPIO_PuPd
+PA1.GPIO_PuPd=GPIO_NOPULL
+PA1.Locked=true
+PA1.Mode=RGMII (Reduced GMII)
+PA1.Signal=ETH1_RX_CLK
+PA10.GPIOParameters=GPIO_Speed,GPIO_PuPd,GPIO_ModeDefaultOutputPP
+PA10.GPIO_ModeDefaultOutputPP=GPIO_MODE_OUTPUT_PP
+PA10.GPIO_PuPd=GPIO_NOPULL
+PA10.GPIO_Speed=GPIO_SPEED_FREQ_LOW
+PA10.Locked=true
+PA10.Signal=GPIO_Output
+PA13.GPIOParameters=GPIO_Speed,GPIO_PuPd,GPIO_ModeDefaultOutputPP
+PA13.GPIO_ModeDefaultOutputPP=GPIO_MODE_OUTPUT_PP
+PA13.GPIO_PuPd=GPIO_NOPULL
+PA13.GPIO_Speed=GPIO_SPEED_FREQ_LOW
+PA13.Locked=true
+PA13.Signal=GPIO_Output
+PA14.GPIOParameters=GPIO_PuPd,GPIO_Mode
+PA14.GPIO_Mode=GPIO_MODE_INPUT
+PA14.GPIO_PuPd=GPIO_NOPULL
+PA14.Locked=true
+PA14.Signal=GPIO_Input
+PA15.GPIOParameters=GPIO_Speed,GPIO_PuPd,GPIO_ModeDefaultOutputPP
+PA15.GPIO_ModeDefaultOutputPP=GPIO_MODE_OUTPUT_PP
+PA15.GPIO_PuPd=GPIO_NOPULL
+PA15.GPIO_Speed=GPIO_SPEED_FREQ_LOW
+PA15.Locked=true
+PA15.Signal=GPIO_Output
+PA2.GPIOParameters=GPIO_Speed,GPIO_PuPd,GPIO_Mode
+PA2.GPIO_Mode=GPIO_MODE_AF_PP
+PA2.GPIO_PuPd=GPIO_NOPULL
+PA2.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH
+PA2.Locked=true
+PA2.Mode=RGMII (Reduced GMII)
+PA2.Signal=ETH1_MDIO
+PA6.GPIOParameters=GPIO_PuPd,GPIO_Mode
+PA6.GPIO_Mode=GPIO_MODE_INPUT
+PA6.GPIO_PuPd=GPIO_NOPULL
+PA6.Locked=true
+PA6.Signal=GPIO_Input
+PA7.GPIOParameters=GPIO_PuPd
+PA7.GPIO_PuPd=GPIO_NOPULL
+PA7.Locked=true
+PA7.Mode=RGMII (Reduced GMII)
+PA7.Signal=ETH1_RX_CTL
+PB0.GPIOParameters=GPIO_PuPd
+PB0.GPIO_PuPd=GPIO_NOPULL
+PB0.Locked=true
+PB0.Mode=RGMII (Reduced GMII)
+PB0.Signal=ETH1_RXD2
+PB1.GPIOParameters=GPIO_PuPd
+PB1.GPIO_PuPd=GPIO_NOPULL
+PB1.Locked=true
+PB1.Mode=RGMII (Reduced GMII)
+PB1.Signal=ETH1_RXD3
+PB11.GPIOParameters=GPIO_Speed,GPIO_PuPd,GPIO_Mode
+PB11.GPIO_Mode=GPIO_MODE_AF_PP
+PB11.GPIO_PuPd=GPIO_NOPULL
+PB11.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH
+PB11.Locked=true
+PB11.Mode=RGMII (Reduced GMII)
+PB11.Signal=ETH1_TX_CTL
+PB14.GPIOParameters=GPIO_PuPd,GPIO_Speed_High_Default,GPIO_Mode
+PB14.GPIO_Mode=GPIO_MODE_AF_PP
+PB14.GPIO_PuPd=GPIO_NOPULL
+PB14.GPIO_Speed_High_Default=GPIO_SPEED_FREQ_VERY_HIGH
+PB14.Locked=true
+PB14.Mode=SD_4_bits_Wide_bus
+PB14.Signal=SDMMC2_D0
+PB15.GPIOParameters=GPIO_PuPd,GPIO_Speed_High_Default,GPIO_Mode
+PB15.GPIO_Mode=GPIO_MODE_AF_PP
+PB15.GPIO_PuPd=GPIO_NOPULL
+PB15.GPIO_Speed_High_Default=GPIO_SPEED_FREQ_VERY_HIGH
+PB15.Locked=true
+PB15.Mode=SD_4_bits_Wide_bus
+PB15.Signal=SDMMC2_D1
+PB2.GPIOParameters=GPIO_PuPd
+PB2.GPIO_PuPd=GPIO_NOPULL
+PB2.Locked=true
+PB2.Mode=Asynchronous
+PB2.Signal=UART4_RX
+PB3.GPIOParameters=GPIO_PuPd,GPIO_Speed_High_Default,GPIO_Mode
+PB3.GPIO_Mode=GPIO_MODE_AF_PP
+PB3.GPIO_PuPd=GPIO_NOPULL
+PB3.GPIO_Speed_High_Default=GPIO_SPEED_FREQ_VERY_HIGH
+PB3.Locked=true
+PB3.Mode=SD_4_bits_Wide_bus
+PB3.Signal=SDMMC2_D2
+PB4.GPIOParameters=GPIO_PuPd,GPIO_Speed_High_Default,GPIO_Mode
+PB4.GPIO_Mode=GPIO_MODE_AF_PP
+PB4.GPIO_PuPd=GPIO_NOPULL
+PB4.GPIO_Speed_High_Default=GPIO_SPEED_FREQ_VERY_HIGH
+PB4.Locked=true
+PB4.Mode=SD_4_bits_Wide_bus
+PB4.Signal=SDMMC2_D3
+PB5.GPIOParameters=GPIO_Speed,GPIO_PuPd,GPIO_Mode
+PB5.GPIO_Mode=GPIO_MODE_AF_PP
+PB5.GPIO_PuPd=GPIO_NOPULL
+PB5.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH
+PB5.Locked=true
+PB5.Mode=ETH Clock Output (PHY without Quartz)
+PB5.Signal=ETH1_CLK
+PB6.GPIOParameters=GPIO_Speed,GPIO_Pu,GPIO_Mode
+PB6.GPIO_Mode=GPIO_MODE_AF_OD
+PB6.GPIO_Pu=GPIO_NOPULL
+PB6.GPIO_Speed=GPIO_SPEED_FREQ_LOW
+PB6.Locked=true
+PB6.Mode=CEC_Activate
+PB6.Signal=CEC
+PB7.GPIOParameters=GPIO_PuPd,GPIO_Mode
+PB7.GPIO_Mode=GPIO_MODE_INPUT
+PB7.GPIO_PuPd=GPIO_NOPULL
+PB7.Locked=true
+PB7.Signal=GPIO_Input
+PC1.GPIOParameters=GPIO_Speed,GPIO_PuPd,GPIO_Mode
+PC1.GPIO_Mode=GPIO_MODE_AF_PP
+PC1.GPIO_PuPd=GPIO_NOPULL
+PC1.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH
+PC1.Locked=true
+PC1.Mode=RGMII (Reduced GMII)
+PC1.Signal=ETH1_MDC
+PC10.GPIOParameters=GPIO_PuPd,GPIO_Speed_High_Default,GPIO_Mode
+PC10.GPIO_Mode=GPIO_MODE_AF_PP
+PC10.GPIO_PuPd=GPIO_NOPULL
+PC10.GPIO_Speed_High_Default=GPIO_SPEED_FREQ_VERY_HIGH
+PC10.Locked=true
+PC10.Mode=SD_4_bits_Wide_bus
+PC10.Signal=SDMMC1_D2
+PC11.GPIOParameters=GPIO_PuPd,GPIO_Speed_High_Default,GPIO_Mode
+PC11.GPIO_Mode=GPIO_MODE_AF_PP
+PC11.GPIO_PuPd=GPIO_NOPULL
+PC11.GPIO_Speed_High_Default=GPIO_SPEED_FREQ_VERY_HIGH
+PC11.Locked=true
+PC11.Mode=SD_4_bits_Wide_bus
+PC11.Signal=SDMMC1_D3
+PC12.GPIOParameters=GPIO_PuPd,GPIO_Speed_High_Default,GPIO_Mode
+PC12.GPIO_Mode=GPIO_MODE_AF_PP
+PC12.GPIO_PuPd=GPIO_NOPULL
+PC12.GPIO_Speed_High_Default=GPIO_SPEED_FREQ_VERY_HIGH
+PC12.Locked=true
+PC12.Mode=SD_4_bits_Wide_bus
+PC12.Signal=SDMMC1_CK
+PC13.GPIOParameters=GPIO_Speed,GPIO_PuPd,GPIO_ModeDefaultOutputPP
+PC13.GPIO_ModeDefaultOutputPP=GPIO_MODE_OUTPUT_PP
+PC13.GPIO_PuPd=GPIO_NOPULL
+PC13.GPIO_Speed=GPIO_SPEED_FREQ_LOW
+PC13.Locked=true
+PC13.Signal=GPIO_Output
+PC14-OSC32_IN.Locked=true
+PC14-OSC32_IN.Mode=LSE-External-Oscillator
+PC14-OSC32_IN.Signal=RCC_OSC32_IN
+PC15-OSC32_OUT.Locked=true
+PC15-OSC32_OUT.Mode=LSE-External-Oscillator
+PC15-OSC32_OUT.Signal=RCC_OSC32_OUT
+PC2.GPIOParameters=GPIO_Speed,GPIO_PuPd,GPIO_Mode
+PC2.GPIO_Mode=GPIO_MODE_AF_PP
+PC2.GPIO_PuPd=GPIO_NOPULL
+PC2.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH
+PC2.Locked=true
+PC2.Mode=RGMII (Reduced GMII)
+PC2.Signal=ETH1_TXD2
+PC4.GPIOParameters=GPIO_PuPd
+PC4.GPIO_PuPd=GPIO_NOPULL
+PC4.Locked=true
+PC4.Mode=RGMII (Reduced GMII)
+PC4.Signal=ETH1_RXD0
+PC5.GPIOParameters=GPIO_PuPd
+PC5.GPIO_PuPd=GPIO_NOPULL
+PC5.Locked=true
+PC5.Mode=RGMII (Reduced GMII)
+PC5.Signal=ETH1_RXD1
+PC6.GPIOParameters=GPIO_Speed,GPIO_PuPd,GPIO_ModeDefaultOutputPP
+PC6.GPIO_ModeDefaultOutputPP=GPIO_MODE_OUTPUT_PP
+PC6.GPIO_PuPd=GPIO_NOPULL
+PC6.GPIO_Speed=GPIO_SPEED_FREQ_LOW
+PC6.Locked=true
+PC6.Signal=GPIO_Output
+PC8.GPIOParameters=GPIO_PuPd,GPIO_Speed_High_Default,GPIO_Mode
+PC8.GPIO_Mode=GPIO_MODE_AF_PP
+PC8.GPIO_PuPd=GPIO_NOPULL
+PC8.GPIO_Speed_High_Default=GPIO_SPEED_FREQ_VERY_HIGH
+PC8.Locked=true
+PC8.Mode=SD_4_bits_Wide_bus
+PC8.Signal=SDMMC1_D0
+PC9.GPIOParameters=GPIO_PuPd,GPIO_Speed_High_Default,GPIO_Mode
+PC9.GPIO_Mode=GPIO_MODE_AF_PP
+PC9.GPIO_PuPd=GPIO_NOPULL
+PC9.GPIO_Speed_High_Default=GPIO_SPEED_FREQ_VERY_HIGH
+PC9.Locked=true
+PC9.Mode=SD_4_bits_Wide_bus
+PC9.Signal=SDMMC1_D1
+PD0.GPIOParameters=GPIO_PuPd,GPIO_Mode
+PD0.GPIO_Mode=GPIO_MODE_INPUT
+PD0.GPIO_PuPd=GPIO_NOPULL
+PD0.Locked=true
+PD0.Signal=GPIO_Input
+PD11.GPIOParameters=GPIO_Speed,GPIO_PuPd,GPIO_ModeDefaultOutputPP
+PD11.GPIO_ModeDefaultOutputPP=GPIO_MODE_OUTPUT_PP
+PD11.GPIO_PuPd=GPIO_NOPULL
+PD11.GPIO_Speed=GPIO_SPEED_FREQ_LOW
+PD11.Locked=true
+PD11.Signal=GPIO_Output
+PD12.GPIOParameters=GPIO_Speed,GPIO_PuPd,GPIO_Mode
+PD12.GPIO_Mode=GPIO_MODE_AF_OD
+PD12.GPIO_PuPd=GPIO_NOPULL
+PD12.GPIO_Speed=GPIO_SPEED_FREQ_LOW
+PD12.Locked=true
+PD12.Mode=I2C
+PD12.Signal=I2C1_SCL
+PD2.GPIOParameters=GPIO_PuPd,GPIO_Speed_High_Default,GPIO_Mode
+PD2.GPIO_Mode=GPIO_MODE_AF_PP
+PD2.GPIO_PuPd=GPIO_NOPULL
+PD2.GPIO_Speed_High_Default=GPIO_SPEED_FREQ_VERY_HIGH
+PD2.Locked=true
+PD2.Mode=SD_4_bits_Wide_bus
+PD2.Signal=SDMMC1_CMD
+PD3.GPIOParameters=GPIO_PuPd
+PD3.GPIO_PuPd=GPIO_NOPULL
+PD3.Locked=true
+PD3.Mode=CTS_RTS
+PD3.Signal=USART2_CTS
+PD4.GPIOParameters=GPIO_Speed,GPIO_PuPd,GPIO_Mode
+PD4.GPIO_Mode=GPIO_MODE_AF_PP
+PD4.GPIO_PuPd=GPIO_NOPULL
+PD4.GPIO_Speed=GPIO_SPEED_FREQ_LOW
+PD4.Locked=true
+PD4.Mode=CTS_RTS
+PD4.Signal=USART2_RTS
+PD5.GPIOParameters=GPIO_Speed,GPIO_PuPd,GPIO_Mode
+PD5.GPIO_Mode=GPIO_MODE_AF_PP
+PD5.GPIO_PuPd=GPIO_PULLUP
+PD5.GPIO_Speed=GPIO_SPEED_FREQ_LOW
+PD5.Locked=true
+PD5.Mode=Asynchronous
+PD5.Signal=USART2_TX
+PD6.GPIOParameters=GPIO_PuPd
+PD6.GPIO_PuPd=GPIO_NOPULL
+PD6.Locked=true
+PD6.Mode=Asynchronous
+PD6.Signal=USART2_RX
+PE2.GPIOParameters=GPIO_Speed,GPIO_PuPd,GPIO_Mode
+PE2.GPIO_Mode=GPIO_MODE_AF_PP
+PE2.GPIO_PuPd=GPIO_NOPULL
+PE2.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH
+PE2.Locked=true
+PE2.Mode=RGMII (Reduced GMII)
+PE2.Signal=ETH1_TXD3
+PE3.GPIOParameters=GPIO_PuPd,GPIO_Speed_High_Default,GPIO_Mode
+PE3.GPIO_Mode=GPIO_MODE_AF_PP
+PE3.GPIO_PuPd=GPIO_NOPULL
+PE3.GPIO_Speed_High_Default=GPIO_SPEED_FREQ_VERY_HIGH
+PE3.Locked=true
+PE3.Mode=SD_4_bits_Wide_bus
+PE3.Signal=SDMMC2_CK
+PE4.GPIOParameters=GPIO_Speed,GPIO_PuPd,GPIO_ModeDefaultOutputPP
+PE4.GPIO_ModeDefaultOutputPP=GPIO_MODE_OUTPUT_PP
+PE4.GPIO_PuPd=GPIO_NOPULL
+PE4.GPIO_Speed=GPIO_SPEED_FREQ_LOW
+PE4.Locked=true
+PE4.Signal=GPIO_Output
+PF15.GPIOParameters=GPIO_Speed,GPIO_PuPd,GPIO_Mode
+PF15.GPIO_Mode=GPIO_MODE_AF_OD
+PF15.GPIO_PuPd=GPIO_NOPULL
+PF15.GPIO_Speed=GPIO_SPEED_FREQ_LOW
+PF15.Locked=true
+PF15.Mode=I2C
+PF15.Signal=I2C1_SDA
+PF2.GPIOParameters=GPIO_PuPd,GPIO_Mode
+PF2.GPIO_Mode=GPIO_MODE_INPUT
+PF2.GPIO_PuPd=GPIO_NOPULL
+PF2.Locked=true
+PF2.Signal=GPIO_Input
+PG1.GPIOParameters=GPIO_PuPd,GPIO_Mode
+PG1.GPIO_Mode=GPIO_MODE_INPUT
+PG1.GPIO_PuPd=GPIO_NOPULL
+PG1.Locked=true
+PG1.Signal=GPIO_Input
+PG11.GPIOParameters=GPIO_ModeDefaultPP,GPIO_Speed,GPIO_PuPd
+PG11.GPIO_ModeDefaultPP=GPIO_MODE_AF_PP
+PG11.GPIO_PuPd=GPIO_NOPULL
+PG11.GPIO_Speed=GPIO_SPEED_FREQ_LOW
+PG11.Locked=true
+PG11.Mode=Asynchronous
+PG11.Signal=UART4_TX
+PG13.GPIOParameters=GPIO_Speed,GPIO_PuPd,GPIO_Mode
+PG13.GPIO_Mode=GPIO_MODE_AF_PP
+PG13.GPIO_PuPd=GPIO_NOPULL
+PG13.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH
+PG13.Locked=true
+PG13.Mode=RGMII (Reduced GMII)
+PG13.Signal=ETH1_TXD0
+PG14.GPIOParameters=GPIO_Speed,GPIO_PuPd,GPIO_Mode
+PG14.GPIO_Mode=GPIO_MODE_AF_PP
+PG14.GPIO_PuPd=GPIO_NOPULL
+PG14.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH
+PG14.Locked=true
+PG14.Mode=RGMII (Reduced GMII)
+PG14.Signal=ETH1_TXD1
+PG4.GPIOParameters=GPIO_Speed,GPIO_PuPd,GPIO_Mode
+PG4.GPIO_Mode=GPIO_MODE_AF_PP
+PG4.GPIO_PuPd=GPIO_NOPULL
+PG4.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH
+PG4.Locked=true
+PG4.Mode=RGMII (Reduced GMII)
+PG4.Signal=ETH1_GTX_CLK
+PG5.GPIOParameters=GPIO_Speed,GPIO_PuPd,GPIO_Mode
+PG5.GPIO_Mode=GPIO_MODE_AF_PP
+PG5.GPIO_PuPd=GPIO_NOPULL
+PG5.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH
+PG5.Locked=true
+PG5.Mode=ETH 125MHz Clock Input
+PG5.Signal=ETH1_CLK125
+PG6.GPIOParameters=GPIO_PuPd,GPIO_Speed_High_Default,GPIO_Mode
+PG6.GPIO_Mode=GPIO_MODE_AF_PP
+PG6.GPIO_PuPd=GPIO_NOPULL
+PG6.GPIO_Speed_High_Default=GPIO_SPEED_FREQ_VERY_HIGH
+PG6.Locked=true
+PG6.Mode=SD_4_bits_Wide_bus
+PG6.Signal=SDMMC2_CMD
+PG9.GPIOParameters=GPIO_Speed,GPIO_PuPd,GPIO_ModeDefaultOutputPP
+PG9.GPIO_ModeDefaultOutputPP=GPIO_MODE_OUTPUT_PP
+PG9.GPIO_PuPd=GPIO_NOPULL
+PG9.GPIO_Speed=GPIO_SPEED_FREQ_LOW
+PG9.Locked=true
+PG9.Signal=GPIO_Output
+PH0-OSC_IN.Locked=true
+PH0-OSC_IN.Mode=HSE-External-Oscillator
+PH0-OSC_IN.Signal=RCC_OSC_IN
+PH1-OSC_OUT.Locked=true
+PH1-OSC_OUT.Mode=HSE-External-Oscillator
+PH1-OSC_OUT.Signal=RCC_OSC_OUT
+PH4.GPIOParameters=GPIO_Speed,GPIO_PuPd,GPIO_ModeDefaultOutputPP
+PH4.GPIO_ModeDefaultOutputPP=GPIO_MODE_OUTPUT_PP
+PH4.GPIO_PuPd=GPIO_NOPULL
+PH4.GPIO_Speed=GPIO_SPEED_FREQ_LOW
+PH4.Locked=true
+PH4.Signal=GPIO_Output
+PH5.GPIOParameters=GPIO_PuPd,GPIO_Mode
+PH5.GPIO_Mode=GPIO_MODE_INPUT
+PH5.GPIO_PuPd=GPIO_NOPULL
+PH5.Locked=true
+PH5.Signal=GPIO_Input
+PH7.GPIOParameters=GPIO_Speed,GPIO_PuPd,GPIO_ModeDefaultOutputPP
+PH7.GPIO_ModeDefaultOutputPP=GPIO_MODE_OUTPUT_PP
+PH7.GPIO_PuPd=GPIO_NOPULL
+PH7.GPIO_Speed=GPIO_SPEED_FREQ_LOW
+PH7.Locked=true
+PH7.Signal=GPIO_Output
+PI11.GPIOParameters=GPIO_PuPd,GPIO_Mode
+PI11.GPIO_Mode=GPIO_MODE_INPUT
+PI11.GPIO_PuPd=GPIO_NOPULL
+PI11.Locked=true
+PI11.Signal=GPIO_Input
+PI8.GPIOParameters=GPIO_Speed,GPIO_PuPd,GPIO_ModeDefaultOutputPP
+PI8.GPIO_ModeDefaultOutputPP=GPIO_MODE_OUTPUT_PP
+PI8.GPIO_PuPd=GPIO_NOPULL
+PI8.GPIO_Speed=GPIO_SPEED_FREQ_LOW
+PI8.Locked=true
+PI8.Signal=GPIO_Output
+PZ0.GPIOParameters=GPIO_Speed,GPIO_PuPd,GPIO_Mode
+PZ0.GPIO_Mode=GPIO_MODE_AF_PP
+PZ0.GPIO_PuPd=GPIO_NOPULL
+PZ0.GPIO_Speed=GPIO_SPEED_FREQ_MEDIUM
+PZ0.Locked=true
+PZ0.Mode=Full_Duplex_Master
+PZ0.Signal=I2S1_CK
+PZ1.GPIOParameters=GPIO_Speed,GPIO_PuPd,GPIO_Mode
+PZ1.GPIO_Mode=GPIO_MODE_AF_PP
+PZ1.GPIO_PuPd=GPIO_NOPULL
+PZ1.GPIO_Speed=GPIO_SPEED_FREQ_MEDIUM
+PZ1.Locked=true
+PZ1.Mode=Full_Duplex_Master
+PZ1.Signal=I2S1_SDI
+PZ2.GPIOParameters=GPIO_Speed,GPIO_PuPd,GPIO_Mode
+PZ2.GPIO_Mode=GPIO_MODE_AF_PP
+PZ2.GPIO_PuPd=GPIO_NOPULL
+PZ2.GPIO_Speed=GPIO_SPEED_FREQ_MEDIUM
+PZ2.Locked=true
+PZ2.Mode=Full_Duplex_Master
+PZ2.Signal=I2S1_SDO
+PZ3.GPIOParameters=GPIO_Speed,GPIO_PuPd,GPIO_Mode
+PZ3.GPIO_Mode=GPIO_MODE_AF_PP
+PZ3.GPIO_PuPd=GPIO_NOPULL
+PZ3.GPIO_Speed=GPIO_SPEED_FREQ_MEDIUM
+PZ3.Locked=true
+PZ3.Mode=Full_Duplex_Master
+PZ3.Signal=I2S1_WS
+PZ4.GPIOParameters=GPIO_Speed,GPIO_PuPd,GPIO_Mode
+PZ4.GPIO_Mode=GPIO_MODE_AF_OD
+PZ4.GPIO_PuPd=GPIO_NOPULL
+PZ4.GPIO_Speed=GPIO_SPEED_FREQ_LOW
+PZ4.Locked=true
+PZ4.Mode=I2C
+PZ4.Signal=I2C4_SCL
+PZ5.GPIOParameters=GPIO_Speed,GPIO_PuPd,GPIO_Mode
+PZ5.GPIO_Mode=GPIO_MODE_AF_OD
+PZ5.GPIO_PuPd=GPIO_NOPULL
+PZ5.GPIO_Speed=GPIO_SPEED_FREQ_LOW
+PZ5.Locked=true
+PZ5.Mode=I2C
+PZ5.Signal=I2C4_SDA
+PZ6.GPIOParameters=GPIO_Speed,GPIO_PuPd,GPIO_ModeDefaultOutputPP
+PZ6.GPIO_ModeDefaultOutputPP=GPIO_MODE_OUTPUT_PP
+PZ6.GPIO_PuPd=GPIO_NOPULL
+PZ6.GPIO_Speed=GPIO_SPEED_FREQ_LOW
+PZ6.Locked=true
+PZ6.Signal=GPIO_Output
+PZ7.GPIOParameters=GPIO_Speed,GPIO_PuPd,GPIO_ModeDefaultOutputPP
+PZ7.GPIO_ModeDefaultOutputPP=GPIO_MODE_OUTPUT_PP
+PZ7.GPIO_PuPd=GPIO_NOPULL
+PZ7.GPIO_Speed=GPIO_SPEED_FREQ_LOW
+PZ7.Locked=true
+PZ7.Signal=GPIO_Output
+PinOutPanel.CurrentBGAView=Top
+PinOutPanel.RotationAngle=0
+ProjectManager.AskForMigrate=true
+ProjectManager.BackupPrevious=false
+ProjectManager.CompilerOptimize=3
+ProjectManager.ComputerToolchain=false
+ProjectManager.CoupleFile=false
+ProjectManager.CustomerFirmwarePackage=
+ProjectManager.DefaultFWLocation=true
+ProjectManager.DeletePrevious=true
+ProjectManager.DeviceId=STM32MP157CACx
+ProjectManager.DeviceTreeLocation=/home/user/gen/src/yocto-genisys/layers/meta-exceet-stm32mp/conf/machine/dts/
+ProjectManager.FirmwarePackage=STM32Cube FW_MP1 V0.4.0
+ProjectManager.FreePins=false
+ProjectManager.HalAssertFull=false
+ProjectManager.HeapSize=0x200
+ProjectManager.KeepUserCode=true
+ProjectManager.LastFirmware=true
+ProjectManager.LibraryCopy=0
+ProjectManager.MainLocation=Src
+ProjectManager.PreviousToolchain=
+ProjectManager.ProjectBuild=false
+ProjectManager.ProjectFileName=t1000-calib.ioc
+ProjectManager.ProjectName=t1000-calib
+ProjectManager.StackSize=0x400
+ProjectManager.TargetToolchain=SW4STM32
+ProjectManager.ToolChainLocation=
+ProjectManager.UnderRoot=false
+ProjectManager.functionlistsort=1-MX_GPIO_Init-GPIO-false-HAL-true,2-SystemClock_Config-RCC-false-HAL-false
+RCC.ADCFreq_Value=74250000
+RCC.AHB1234Freq_Value=196000000
+RCC.APB1DIV=RCC_APB1_DIV2
+RCC.APB1Freq_Value=98000000
+RCC.APB2DIV=RCC_APB2_DIV2
+RCC.APB2Freq_Value=98000000
+RCC.APB3DIV=RCC_APB3_DIV2
+RCC.APB3Freq_Value=98000000
+RCC.APB4DIV=RCC_APB4_DIV2
+RCC.APB4Freq_Value=132000000
+RCC.APB5DIV=RCC_APB5_DIV4
+RCC.APB5DIVClockFreq_Value=66000000
+RCC.AXICLKFreq_VALUE=264000000
+RCC.AXICLKSource=RCC_AXISSOURCE_PLL2
+RCC.AXIDIVFreq_Value=264000000
+RCC.CECFreq_Value=32768
+RCC.CKPERCLKFreq_VALUE=64000000
+RCC.CSI_VALUE=4000000
+RCC.CortexFreq_Value=196000000
+RCC.DACCLKFreq_VALUE=32000
+RCC.DDRCFreq_Value=528000000
+RCC.DDRPERFMFreq_Value=528000000
+RCC.DDRPHYFreq_Value=528000000
+RCC.DFSDFAFreq_Value=74250000
+RCC.DFSDMFreq_Value=196000000
+RCC.DIVM1=3
+RCC.DIVM2=3
+RCC.DIVM3=3
+RCC.DIVM4=4
+RCC.DIVN1=81
+RCC.DIVN2=66
+RCC.DIVN3=98
+RCC.DIVN4=99
+RCC.DIVP1Freq_Value=648000000
+RCC.DIVP2Freq_Value=264000000
+RCC.DIVP3=4
+RCC.DIVP3Freq_Value=196000000
+RCC.DIVP4=8
+RCC.DIVP4Freq_Value=74250000
+RCC.DIVQ1Freq_Value=324000000
+RCC.DIVQ2Freq_Value=264000000
+RCC.DIVQ3=16
+RCC.DIVQ3Freq_Value=49000000
+RCC.DIVQ4=8
+RCC.DIVQ4Freq_Value=74250000
+RCC.DIVR1Freq_Value=324000000
+RCC.DIVR2=1
+RCC.DIVR2Freq_Value=528000000
+RCC.DIVR3=8
+RCC.DIVR3Freq_Value=98000000
+RCC.DIVR4=8
+RCC.DIVR4Freq_Value=74250000
+RCC.DSIFreq_Value=60000000
+RCC.DSITXEscFreq_Value=15000000
+RCC.DSI_VALUE=60000000
+RCC.ETHFreq_Value=74250000
+RCC.FCLKFreq_Value=196000000
+RCC.FDCANFreq_Value=24000000
+RCC.FMCFreq_Value=264000000
+RCC.FamilyName=M
+RCC.HSE_VALUE=24000000
+RCC.HSIDivClkFreq_Value=64000000
+RCC.HSI_VALUE=64000000
+RCC.Hclk5DIVFreq_Value=264000000
+RCC.Hclk6DIVFreq_Value=264000000
+RCC.I2C12CLockSelection=RCC_I2C12CLKSOURCE_HSI
+RCC.I2C12Freq_Value=64000000
+RCC.I2C35Freq_Value=98000000
+RCC.I2C46CLockSelection=RCC_I2C46CLKSOURCE_HSI
+RCC.I2C46Freq_Value=64000000
+RCC.IPParameters=ADCFreq_Value,AHB1234Freq_Value,APB1DIV,APB1Freq_Value,APB2DIV,APB2Freq_Value,APB3DIV,APB3Freq_Value,APB4DIV,APB4Freq_Value,APB5DIV,APB5DIVClockFreq_Value,AXICLKFreq_VALUE,AXICLKSource,AXIDIVFreq_Value,CECFreq_Value,CKPERCLKFreq_VALUE,CSI_VALUE,CortexFreq_Value,DACCLKFreq_VALUE,DDRCFreq_Value,DDRPERFMFreq_Value,DDRPHYFreq_Value,DFSDFAFreq_Value,DFSDMFreq_Value,DIVM1,DIVM2,DIVM3,DIVM4,DIVN1,DIVN2,DIVN3,DIVN4,DIVP1Freq_Value,DIVP2Freq_Value,DIVP3,DIVP3Freq_Value,DIVP4,DIVP4Freq_Value,DIVQ1Freq_Value,DIVQ2Freq_Value,DIVQ3,DIVQ3Freq_Value,DIVQ4,DIVQ4Freq_Value,DIVR1Freq_Value,DIVR2,DIVR2Freq_Value,DIVR3,DIVR3Freq_Value,DIVR4,DIVR4Freq_Value,DSIFreq_Value,DSITXEscFreq_Value,DSI_VALUE,ETHFreq_Value,FCLKFreq_Value,FDCANFreq_Value,FMCFreq_Value,FamilyName,HSE_VALUE,HSIDivClkFreq_Value,HSI_VALUE,Hclk5DIVFreq_Value,Hclk6DIVFreq_Value,I2C12CLockSelection,I2C12Freq_Value,I2C35Freq_Value,I2C46CLockSelection,I2C46Freq_Value,LPTIM1Freq_Value,LPTIM23Freq_Value,LPTIM45Freq_Value,LSI_VALUE,LTDCFreq_Value,MCO1PinFreq_Value,MCO2PinFreq_Value,MCUCLKFreq_VALUE,MCUCLKSource,MCUClockFreq_Value,MPUCLKFreq_VALUE,MPUCLKSource,PLL12Source,PLL1FRACV,PLL1MODE,PLL2FRACV,PLL2MODE,PLL3FRACV,PLL3MODE,PLL3Source,PLL4PDSIFreq_Value,PLL4Source,PLLDSIFreq_Value,PLLDSIVCOFreq_Value,PUBLFreq_Value,QSPIFreq_Value,RCC_RTC_Clock_Source_FROM_HSE,RTCClockSelection,RTCFreq_Value,SAI1Freq_Value,SAI2Freq_Value,SAI3Freq_Value,SAI4Freq_Value,SDMMC12CLockSelection,SDMMC12Freq_Value,SDMMC3Freq_Value,SPDIFRXFreq_Value,SPI1CLockSelection,SPI1Freq_Value,SPI23Freq_Value,SPI45Freq_Value,SPI6Freq_Value,STGENCLockSelection,STGENFreq_Value,Tim1OutputFreq_Value,Tim2OutputFreq_Value,UART78Freq_Value,USART1Freq_Value,USART24CLockSelection,USART24Freq_Value,USART35Freq_Value,USART6Freq_Value,USBOHSFreq_Value,USBPHYFreq_Value,VCO1OutputFreq_Value,VCO2OutputFreq_Value,VCO3OutputFreq_Value,VCO4OutputFreq_Value,VCOInput1Freq_Value,VCOInput2Freq_Value,VCOInput3Freq_Value,VCOInput4Freq_Value
+RCC.LPTIM1Freq_Value=98000000
+RCC.LPTIM23Freq_Value=98000000
+RCC.LPTIM45Freq_Value=98000000
+RCC.LSI_VALUE=32000
+RCC.LTDCFreq_Value=74250000
+RCC.MCO1PinFreq_Value=64000000
+RCC.MCO2PinFreq_Value=648000000
+RCC.MCUCLKFreq_VALUE=196000000
+RCC.MCUCLKSource=RCC_MCUSSOURCE_PLL3
+RCC.MCUClockFreq_Value=196000000
+RCC.MPUCLKFreq_VALUE=648000000
+RCC.MPUCLKSource=RCC_MPUSOURCE_PLL1
+RCC.PLL12Source=RCC_PLL12SOURCE_HSE
+RCC.PLL1FRACV=0x800
+RCC.PLL1MODE=RCC_PLL_FRACTIONAL
+RCC.PLL2FRACV=0x1400
+RCC.PLL2MODE=RCC_PLL_FRACTIONAL
+RCC.PLL3FRACV=0x9ba
+RCC.PLL3MODE=RCC_PLL_FRACTIONAL
+RCC.PLL3Source=RCC_PLL3SOURCE_HSE
+RCC.PLL4PDSIFreq_Value=74250000
+RCC.PLL4Source=RCC_PLL4SOURCE_HSE
+RCC.PLLDSIFreq_Value=480000000
+RCC.PLLDSIVCOFreq_Value=960000000
+RCC.PUBLFreq_Value=528000000
+RCC.QSPIFreq_Value=264000000
+RCC.RCC_RTC_Clock_Source_FROM_HSE=24
+RCC.RTCClockSelection=RCC_RTCCLKSOURCE_LSE
+RCC.RTCFreq_Value=32768
+RCC.SAI1Freq_Value=74250000
+RCC.SAI2Freq_Value=74250000
+RCC.SAI3Freq_Value=74250000
+RCC.SAI4Freq_Value=74250000
+RCC.SDMMC12CLockSelection=RCC_SDMMC12CLKSOURCE_PLL3
+RCC.SDMMC12Freq_Value=98000000
+RCC.SDMMC3Freq_Value=196000000
+RCC.SPDIFRXFreq_Value=74250000
+RCC.SPI1CLockSelection=RCC_SPI1CLKSOURCE_PLL3_Q
+RCC.SPI1Freq_Value=49000000
+RCC.SPI23Freq_Value=74250000
+RCC.SPI45Freq_Value=98000000
+RCC.SPI6Freq_Value=66000000
+RCC.STGENCLockSelection=RCC_STGENCLKSOURCE_HSE
+RCC.STGENFreq_Value=24000000
+RCC.Tim1OutputFreq_Value=196000000
+RCC.Tim2OutputFreq_Value=196000000
+RCC.UART78Freq_Value=98000000
+RCC.USART1Freq_Value=66000000
+RCC.USART24CLockSelection=RCC_UART24CLKSOURCE_HSI
+RCC.USART24Freq_Value=64000000
+RCC.USART35Freq_Value=98000000
+RCC.USART6Freq_Value=98000000
+RCC.USBOHSFreq_Value=74250000
+RCC.USBPHYFreq_Value=74250000
+RCC.VCO1OutputFreq_Value=1296000000
+RCC.VCO2OutputFreq_Value=1056000000
+RCC.VCO3OutputFreq_Value=784000000
+RCC.VCO4OutputFreq_Value=594000000
+RCC.VCOInput1Freq_Value=8000000
+RCC.VCOInput2Freq_Value=8000000
+RCC.VCOInput3Freq_Value=8000000
+RCC.VCOInput4Freq_Value=6000000
+USART2.IPParameters=VirtualMode-Asynchronous
+USART2.VirtualMode-Asynchronous=VM_ASYNC
+USB_DM1.GPIOParameters=GPIO_Speed,GPIO_PuPd,GPIO_Mode
+USB_DM1.GPIO_Mode=GPIO_MODE_AF_PP
+USB_DM1.GPIO_PuPd=GPIO_NOPULL
+USB_DM1.GPIO_Speed=GPIO_SPEED_FREQ_LOW
+USB_DM1.Locked=true
+USB_DM1.Mode=Enable
+USB_DM1.Signal=USBH_HS1_DM
+USB_DP1.GPIOParameters=GPIO_Speed,GPIO_PuPd,GPIO_Mode
+USB_DP1.GPIO_Mode=GPIO_MODE_AF_PP
+USB_DP1.GPIO_PuPd=GPIO_NOPULL
+USB_DP1.GPIO_Speed=GPIO_SPEED_FREQ_LOW
+USB_DP1.Locked=true
+USB_DP1.Mode=Enable
+USB_DP1.Signal=USBH_HS1_DP
+VP_DDR_DDR3.Mode=DDR3
+VP_DDR_DDR3.Signal=DDR_DDR3
+VP_DDR_DDR3_16_4Gb.Mode=4Gb_16bits
+VP_DDR_DDR3_16_4Gb.Signal=DDR_DDR3_16_4Gb
+VP_DDR_DDR_16_bits.Mode=16bits
+VP_DDR_DDR_16_bits.Signal=DDR_DDR_16_bits
+VP_DMA_VS_DMA1_A7NS.Mode=Cortex-A7 non secure
+VP_DMA_VS_DMA1_A7NS.Signal=DMA_VS_DMA1_A7NS
+VP_DMA_VS_DMA2_M4.Mode=Cortex-M4
+VP_DMA_VS_DMA2_M4.Signal=DMA_VS_DMA2_M4
+VP_LTDC_DSIMode.Mode=RGB888
+VP_LTDC_DSIMode.Signal=LTDC_DSIMode
+VP_RTC_VS_RTC_Activate.Mode=RTC_Enabled
+VP_RTC_VS_RTC_Activate.Signal=RTC_VS_RTC_Activate
+board=STM32MP157C-DK2
diff --git a/conf/machine/cubemx/t1000-default.ioc b/conf/machine/cubemx/t1000-default.ioc
new file mode 100644
index 0000000000000000000000000000000000000000..350a035ebdc48742afdf7a4490a75a7a06e3252c
--- /dev/null
+++ b/conf/machine/cubemx/t1000-default.ioc
@@ -0,0 +1,1067 @@
+#MicroXplorer Configuration settings - do not modify
+ADC1.BoostMode=ENABLE
+ADC1.Channel-2\#ChannelRegularConversion=ADC_CHANNEL_16
+ADC1.ClockPrescaler=ADC_CLOCK_ASYNC_DIV1
+ADC1.ContinuousConvMode=DISABLE
+ADC1.ConversionDataManagement=ADC_CONVERSIONDATA_DR
+ADC1.DiscontinuousConvMode=DISABLE
+ADC1.EOCSelection=ADC_EOC_SINGLE_CONV
+ADC1.EnableAnalogWatchDog1=false
+ADC1.EnableAnalogWatchDog2=false
+ADC1.EnableAnalogWatchDog3=false
+ADC1.EnableInjectedConversion=DISABLE
+ADC1.EnableRegularConversion=ENABLE
+ADC1.ExternalTrigConv=ADC_SOFTWARE_START
+ADC1.ExternalTrigConvEdge=ADC_EXTERNALTRIGCONVEDGE_NONE
+ADC1.IPParameters=Rank-2\#ChannelRegularConversion,Channel-2\#ChannelRegularConversion,SamplingTime-2\#ChannelRegularConversion,OffsetNumber-2\#ChannelRegularConversion,NbrOfConversionFlag,ClockPrescaler,Resolution,ScanConvMode,ContinuousConvMode,DiscontinuousConvMode,EOCSelection,Overrun,BoostMode,ConversionDataManagement,LowPowerAutoWait,EnableRegularConversion,LeftBitShift,OversamplingMode,NbrOfConversion,ExternalTrigConv,ExternalTrigConvEdge,EnableInjectedConversion,EnableAnalogWatchDog1,EnableAnalogWatchDog2,EnableAnalogWatchDog3,master
+ADC1.LeftBitShift=ADC_LEFTBITSHIFT_NONE
+ADC1.LowPowerAutoWait=DISABLE
+ADC1.NbrOfConversion=1
+ADC1.NbrOfConversionFlag=1
+ADC1.OffsetNumber-2\#ChannelRegularConversion=ADC_OFFSET_NONE
+ADC1.Overrun=ADC_OVR_DATA_PRESERVED
+ADC1.OversamplingMode=DISABLE
+ADC1.Rank-2\#ChannelRegularConversion=1
+ADC1.Resolution=ADC_RESOLUTION_16B
+ADC1.SamplingTime-2\#ChannelRegularConversion=ADC_SAMPLETIME_1CYCLE_5
+ADC1.ScanConvMode=ADC_SCAN_DISABLE
+ADC1.master=1
+Boot\ ROM.IPs=SDMMC1,SDMMC2,UART4
+Boot\ loader.IPs=RCC,UART4,QUADSPI,SDMMC1,SDMMC2,USB_OTG_HS
+Cortex-A7\ non\ secure.IPs=DDR\:I,RCC\:I,RTC\:I,SYS\:I,QUADSPI\:I,ETH1\:I,LTDC\:I,SPI2\:I,UART4\:I,SDMMC2\:I,SDMMC1\:I,FDCAN1\:I,USART2\:I,USART3\:I,USART6\:I,I2C2\:I,I2C4\:I,ADC1\:I,ADC2\:I,UART8\:I,USBH_HS1\:I,USB_OTG_HS\:I,DMA1\:I
+Cortex-M4.IPs=RCC,WWDG1\:I,NVIC\:I,DMA2\:I
+DDR.0dqdly0=0
+DDR.0dqdly1=1
+DDR.0dqdly2=2
+DDR.0dqdly3=0
+DDR.0dqdly4=0
+DDR.0dqdly5=1
+DDR.0dqdly6=0
+DDR.0dqdly7=1
+DDR.0sdphase=3
+DDR.1dqdly0=0
+DDR.1dqdly1=1
+DDR.1dqdly2=2
+DDR.1dqdly3=0
+DDR.1dqdly4=0
+DDR.1dqdly5=1
+DDR.1dqdly6=0
+DDR.1dqdly7=1
+DDR.1dqsdly=2
+DDR.1dqsndly=2
+DDR.1sdphase=3
+DDR.ADDRMAP1=0x00070707
+DDR.ADDRMAP3=0x1F000000
+DDR.ADDRMAP5=0x06060606
+DDR.ADDRMAP6=0x0F060606
+DDR.CL=8
+DDR.DRAMTMG0=0x121B1214
+DDR.DRAMTMG1=0x000A041C
+DDR.DRAMTMG2=0x0608090F
+DDR.DRAMTMG4=0x08040608
+DDR.DRAMTMG5=0x06060403
+DDR.DTPR0=0x38D488D0
+DDR.DTPR1=0x098A00D8
+DDR.DX0DLLCR=0x4000C000
+DDR.DX0DQTR=0x10100210
+DDR.DX1DLLCR=0x4000C000
+DDR.DX1DQSTR=0x3D202000
+DDR.DX1DQTR=0x10100210
+DDR.IPParameters=addrmap_col_b9,addrmap_col_b10,addrmap_col_b11,addrmap_bank_b0,addrmap_bank_b1,addrmap_bank_b2,addrmap_row_b0,addrmap_row_b1,addrmap_row_b2_10,addrmap_row_b11,addrmap_row_b12,addrmap_row_b13,addrmap_row_b14,addrmap_row_b15,MSTR,RFSHTMG,DRAMTMG2,DRAMTMG4,DRAMTMG5,PCFGQOS1_1,ADDRMAP1,ADDRMAP3,ADDRMAP5,ADDRMAP6,PTR0,PTR1,PTR2,DTPR0,DTPR1,ZQ0CR1,SPEED_BIN_GRADE,tRCD,tRP,tRC,wr2pre,t_faw,t_ras_max,t_ras_min,t_xp,t_rd2pre,t_rp,t_rc,write_latency,read_latency,wr2rd,t_rcd,t_cksrx,t_cksre,t_ckesr,t_cke,t_xs_dll_x32,t_xs_x32,t_rfc_nom_x1_x32,t_rfc_min,dfi_t_rddata_en,dfi_tphy_wrlat,tdlllock,tdllsrst,tdinit1,tdinit0,tdinit2,tccd,trc,trrd,tras,trcd,trp,twtr,trtp,tmrd,trfc,tmod,tfaw,tdllk,tcke,txp,txs,MR0.WR,MR0.CL,MR2.RTT,MR2.CWL,data_bus_width,tREFI,DRAMTMG0,RELAXED_TIMING_MODE,DRAMTMG1,0sdphase,0dqdly0,0dqdly1,0dqdly2,0dqdly3,0dqdly4,0dqdly5,0dqdly6,0dqdly7,1sdphase,1dqsndly,1dqsdly,1dqdly0,1dqdly1,1dqdly2,1dqdly3,1dqdly4,1dqdly5,1dqdly6,1dqdly7,DX0DLLCR,DX0DQTR,DX1DLLCR,DX1DQTR,DX1DQSTR,CL,RL,MR0,rd2wr
+DDR.MR0=0x00000840
+DDR.MR0.CL=4
+DDR.MR0.WR=4
+DDR.MR2.CWL=1
+DDR.MR2.RTT=1
+DDR.MSTR=0x00041401
+DDR.PCFGQOS1_1=0x00800000
+DDR.PTR0=0x0022A41B
+DDR.PTR1=0x047C0740
+DDR.PTR2=0x042D9C80
+DDR.RELAXED_TIMING_MODE=false
+DDR.RFSHTMG=0x0040008A
+DDR.RL=8
+DDR.SPEED_BIN_GRADE=SPEED BIN GRADE CONFIG2
+DDR.ZQ0CR1=0x00000038
+DDR.addrmap_bank_b0=7
+DDR.addrmap_bank_b1=7
+DDR.addrmap_bank_b2=7
+DDR.addrmap_col_b10=31
+DDR.addrmap_col_b11=31
+DDR.addrmap_col_b9=31
+DDR.addrmap_row_b0=6
+DDR.addrmap_row_b1=6
+DDR.addrmap_row_b11=6
+DDR.addrmap_row_b12=6
+DDR.addrmap_row_b13=6
+DDR.addrmap_row_b14=6
+DDR.addrmap_row_b15=15
+DDR.addrmap_row_b2_10=6
+DDR.data_bus_width=1
+DDR.dfi_t_rddata_en=6
+DDR.dfi_tphy_wrlat=5
+DDR.rd2wr=9
+DDR.read_latency=8
+DDR.tRC=52.5
+DDR.tRCD=15
+DDR.tREFI=3.9
+DDR.tRP=15
+DDR.t_cke=3
+DDR.t_ckesr=4
+DDR.t_cksre=6
+DDR.t_cksrx=6
+DDR.t_faw=27
+DDR.t_ras_max=18
+DDR.t_ras_min=20
+DDR.t_rc=28
+DDR.t_rcd=8
+DDR.t_rd2pre=4
+DDR.t_rfc_min=138
+DDR.t_rfc_nom_x1_x32=64
+DDR.t_rp=8
+DDR.t_xp=10
+DDR.t_xs_dll_x32=16
+DDR.t_xs_x32=5
+DDR.tccd=0
+DDR.tcke=4
+DDR.tdinit0=264000
+DDR.tdinit1=143
+DDR.tdinit2=105600
+DDR.tdllk=512
+DDR.tdlllock=2704
+DDR.tdllsrst=27
+DDR.tfaw=27
+DDR.tmod=0
+DDR.tmrd=0
+DDR.tras=20
+DDR.trc=28
+DDR.trcd=8
+DDR.trfc=138
+DDR.trp=8
+DDR.trrd=6
+DDR.trtp=4
+DDR.twtr=6
+DDR.txp=13
+DDR.txs=512
+DDR.wr2pre=18
+DDR.wr2rd=15
+DDR.write_latency=6
+DDR_A0.Mode=DDR3
+DDR_A0.Signal=DDR_A0
+DDR_A1.Mode=DDR3
+DDR_A1.Signal=DDR_A1
+DDR_A10.Mode=DDR3
+DDR_A10.Signal=DDR_A10
+DDR_A11.Mode=DDR3
+DDR_A11.Signal=DDR_A11
+DDR_A12.Mode=4Gb_16bits
+DDR_A12.Signal=DDR_A12
+DDR_A13.Mode=4Gb_16bits
+DDR_A13.Signal=DDR_A13
+DDR_A14.Mode=4Gb_16bits
+DDR_A14.Signal=DDR_A14
+DDR_A2.Mode=DDR3
+DDR_A2.Signal=DDR_A2
+DDR_A3.Mode=DDR3
+DDR_A3.Signal=DDR_A3
+DDR_A4.Mode=DDR3
+DDR_A4.Signal=DDR_A4
+DDR_A5.Mode=DDR3
+DDR_A5.Signal=DDR_A5
+DDR_A6.Mode=DDR3
+DDR_A6.Signal=DDR_A6
+DDR_A7.Mode=DDR3
+DDR_A7.Signal=DDR_A7
+DDR_A8.Mode=DDR3
+DDR_A8.Signal=DDR_A8
+DDR_A9.Mode=DDR3
+DDR_A9.Signal=DDR_A9
+DDR_ATO.Mode=DDR3
+DDR_ATO.Signal=DDR_ATO
+DDR_BA0.Mode=DDR3
+DDR_BA0.Signal=DDR_BA0
+DDR_BA1.Mode=DDR3
+DDR_BA1.Signal=DDR_BA1
+DDR_BA2.Mode=DDR3
+DDR_BA2.Signal=DDR_BA2
+DDR_CASN.Mode=DDR3
+DDR_CASN.Signal=DDR_CASN
+DDR_CKE.Mode=DDR3
+DDR_CKE.Signal=DDR_CKE
+DDR_CLKN.Mode=DDR3
+DDR_CLKN.Signal=DDR_CLKN
+DDR_CLKP.Mode=DDR3
+DDR_CLKP.Signal=DDR_CLKP
+DDR_CSN.Mode=DDR3
+DDR_CSN.Signal=DDR_CSN
+DDR_DQ0.Mode=DDR3
+DDR_DQ0.Signal=DDR_DQ0
+DDR_DQ1.Mode=DDR3
+DDR_DQ1.Signal=DDR_DQ1
+DDR_DQ10.Mode=DDR3
+DDR_DQ10.Signal=DDR_DQ10
+DDR_DQ11.Mode=DDR3
+DDR_DQ11.Signal=DDR_DQ11
+DDR_DQ12.Mode=DDR3
+DDR_DQ12.Signal=DDR_DQ12
+DDR_DQ13.Mode=DDR3
+DDR_DQ13.Signal=DDR_DQ13
+DDR_DQ14.Mode=DDR3
+DDR_DQ14.Signal=DDR_DQ14
+DDR_DQ15.Mode=DDR3
+DDR_DQ15.Signal=DDR_DQ15
+DDR_DQ2.Mode=DDR3
+DDR_DQ2.Signal=DDR_DQ2
+DDR_DQ3.Mode=DDR3
+DDR_DQ3.Signal=DDR_DQ3
+DDR_DQ4.Mode=DDR3
+DDR_DQ4.Signal=DDR_DQ4
+DDR_DQ5.Mode=DDR3
+DDR_DQ5.Signal=DDR_DQ5
+DDR_DQ6.Mode=DDR3
+DDR_DQ6.Signal=DDR_DQ6
+DDR_DQ7.Mode=DDR3
+DDR_DQ7.Signal=DDR_DQ7
+DDR_DQ8.Mode=DDR3
+DDR_DQ8.Signal=DDR_DQ8
+DDR_DQ9.Mode=DDR3
+DDR_DQ9.Signal=DDR_DQ9
+DDR_DQM0.Mode=DDR3
+DDR_DQM0.Signal=DDR_DQM0
+DDR_DQM1.Mode=DDR3
+DDR_DQM1.Signal=DDR_DQM1
+DDR_DQS0N.Mode=DDR3
+DDR_DQS0N.Signal=DDR_DQS0N
+DDR_DQS0P.Mode=DDR3
+DDR_DQS0P.Signal=DDR_DQS0P
+DDR_DQS1N.Mode=DDR3
+DDR_DQS1N.Signal=DDR_DQS1N
+DDR_DQS1P.Mode=DDR3
+DDR_DQS1P.Signal=DDR_DQS1P
+DDR_DTO0.Mode=DDR3
+DDR_DTO0.Signal=DDR_DTO0
+DDR_DTO1.Mode=DDR3
+DDR_DTO1.Signal=DDR_DTO1
+DDR_ODT.Mode=DDR3
+DDR_ODT.Signal=DDR_ODT
+DDR_RASN.Mode=DDR3
+DDR_RASN.Signal=DDR_RASN
+DDR_RESETN.Mode=DDR3
+DDR_RESETN.Signal=DDR_RESETN
+DDR_VREF.Mode=DDR3
+DDR_VREF.Signal=DDR_VREF
+DDR_WEN.Mode=DDR3
+DDR_WEN.Signal=DDR_WEN
+DDR_ZQ.Mode=DDR3
+DDR_ZQ.Signal=DDR_ZQ
+File.Version=6
+JTCK-SWCLK.Mode=JTAG_5_pins
+JTCK-SWCLK.Signal=SYS_JTCK-SWCLK
+JTDI.Mode=JTAG_5_pins
+JTDI.Signal=SYS_JTDI
+JTDO-TRACESWO.Mode=JTAG_5_pins
+JTDO-TRACESWO.Signal=SYS_JTDO-SWO
+JTMS-SWDIO.Mode=JTAG_5_pins
+JTMS-SWDIO.Signal=SYS_JTMS-SWDIO
+KeepUserPlacement=false
+Mcu.Context0=Boot ROM
+Mcu.Context1=Boot loader
+Mcu.Context2=Cortex-A7 non secure
+Mcu.Context3=Cortex-M4
+Mcu.ContextNb=4
+Mcu.Family=STM32MP1
+Mcu.IP0=ADC1
+Mcu.IP1=DDR
+Mcu.IP10=RTC
+Mcu.IP11=SDMMC1
+Mcu.IP12=SDMMC2
+Mcu.IP13=SPI2
+Mcu.IP14=SYS
+Mcu.IP15=UART4
+Mcu.IP16=UART8
+Mcu.IP17=USART2
+Mcu.IP18=USART3
+Mcu.IP19=USART6
+Mcu.IP2=ETH1
+Mcu.IP20=USBH_HS1
+Mcu.IP21=USB_OTG_HS
+Mcu.IP3=FDCAN1
+Mcu.IP4=I2C2
+Mcu.IP5=I2C4
+Mcu.IP6=LTDC
+Mcu.IP7=NVIC
+Mcu.IP8=QUADSPI
+Mcu.IP9=RCC
+Mcu.IPNb=22
+Mcu.Name=STM32MP157CADx
+Mcu.Package=TFBGA257
+Mcu.Pin0=PD1
+Mcu.Pin1=PB7
+Mcu.Pin10=PG15
+Mcu.Pin100=PE8
+Mcu.Pin101=PD13
+Mcu.Pin102=PD12
+Mcu.Pin103=PA11
+Mcu.Pin104=PA10
+Mcu.Pin105=DDR_DQ14
+Mcu.Pin106=DDR_DQS1N
+Mcu.Pin107=DDR_DQ9
+Mcu.Pin108=PC5
+Mcu.Pin109=PC4
+Mcu.Pin11=PE6
+Mcu.Pin110=PB12
+Mcu.Pin111=PB8
+Mcu.Pin112=PB5
+Mcu.Pin113=PG8
+Mcu.Pin114=PE7
+Mcu.Pin115=PF8
+Mcu.Pin116=PF9
+Mcu.Pin117=USB_DP2
+Mcu.Pin118=PG7
+Mcu.Pin119=PE10
+Mcu.Pin12=PD7
+Mcu.Pin120=PB2
+Mcu.Pin121=USB_DP1
+Mcu.Pin122=PA12
+Mcu.Pin123=DDR_DQ15
+Mcu.Pin124=DDR_DQM1
+Mcu.Pin125=DDR_DQS1P
+Mcu.Pin126=PA7
+Mcu.Pin127=PA6
+Mcu.Pin128=PF11
+Mcu.Pin129=PF7
+Mcu.Pin13=PA15
+Mcu.Pin130=PG9
+Mcu.Pin131=USB_DM2
+Mcu.Pin132=PB6
+Mcu.Pin133=USB_DM1
+Mcu.Pin134=DDR_VREF
+Mcu.Pin135=DDR_DQ12
+Mcu.Pin136=DDR_DQ11
+Mcu.Pin137=PE1
+Mcu.Pin138=PD10
+Mcu.Pin139=PE3
+Mcu.Pin14=PG6
+Mcu.Pin140=PB14
+Mcu.Pin141=PD2
+Mcu.Pin142=DDR_ZQ
+Mcu.Pin143=DDR_A7
+Mcu.Pin144=PD6
+Mcu.Pin145=PE14
+Mcu.Pin146=PC12
+Mcu.Pin147=PD9
+Mcu.Pin148=PD15
+Mcu.Pin149=DDR_DTO1
+Mcu.Pin15=PB4
+Mcu.Pin150=DDR_A5
+Mcu.Pin151=DDR_DTO0
+Mcu.Pin152=PD14
+Mcu.Pin153=DDR_RASN
+Mcu.Pin154=DDR_ATO
+Mcu.Pin155=DDR_A6
+Mcu.Pin156=PA5
+Mcu.Pin157=PA4
+Mcu.Pin158=PB13
+Mcu.Pin159=PE9
+Mcu.Pin16=PE5
+Mcu.Pin160=PF10
+Mcu.Pin161=VP_DDR_DDR3
+Mcu.Pin162=VP_DDR_DDR_16_bits
+Mcu.Pin163=VP_DDR_DDR3_16_4Gb
+Mcu.Pin164=VP_RTC_VS_RTC_Activate
+Mcu.Pin165=VP_DMA_VS_DMA1_A7NS
+Mcu.Pin166=VP_DMA_VS_DMA2_M4
+Mcu.Pin17=PA8
+Mcu.Pin18=PC9
+Mcu.Pin19=PC10
+Mcu.Pin2=PC6
+Mcu.Pin20=NJTRST
+Mcu.Pin21=JTDI
+Mcu.Pin22=DDR_DQ3
+Mcu.Pin23=DDR_DQ7
+Mcu.Pin24=DDR_DQS0N
+Mcu.Pin25=DDR_DQS0P
+Mcu.Pin26=PE12
+Mcu.Pin27=PE0
+Mcu.Pin28=PD4
+Mcu.Pin29=PD5
+Mcu.Pin3=PD3
+Mcu.Pin30=PD0
+Mcu.Pin31=PA9
+Mcu.Pin32=PB3
+Mcu.Pin33=PB15
+Mcu.Pin34=PB9
+Mcu.Pin35=PC7
+Mcu.Pin36=PC11
+Mcu.Pin37=JTMS-SWDIO
+Mcu.Pin38=DDR_RESETN
+Mcu.Pin39=DDR_DQM0
+Mcu.Pin4=PC8
+Mcu.Pin40=DDR_DQ2
+Mcu.Pin41=DDR_DQ6
+Mcu.Pin42=PG12
+Mcu.Pin43=PE11
+Mcu.Pin44=PE15
+Mcu.Pin45=DDR_DQ4
+Mcu.Pin46=DDR_DQ5
+Mcu.Pin47=PD8
+Mcu.Pin48=PE13
+Mcu.Pin49=DDR_A13
+Mcu.Pin5=PE4
+Mcu.Pin50=DDR_A9
+Mcu.Pin51=PC15-OSC32_OUT
+Mcu.Pin52=DDR_A2
+Mcu.Pin53=DDR_A3
+Mcu.Pin54=PC14-OSC32_IN
+Mcu.Pin55=PC13
+Mcu.Pin56=DDR_A0
+Mcu.Pin57=DDR_BA0
+Mcu.Pin58=PH0-OSC_IN
+Mcu.Pin59=DDR_BA2
+Mcu.Pin6=JTDO-TRACESWO
+Mcu.Pin60=DDR_ODT
+Mcu.Pin61=PH1-OSC_OUT
+Mcu.Pin62=DDR_CSN
+Mcu.Pin63=DDR_WEN
+Mcu.Pin64=DDR_CASN
+Mcu.Pin65=DDR_CLKN
+Mcu.Pin66=PA14
+Mcu.Pin67=PA13
+Mcu.Pin68=DDR_CLKP
+Mcu.Pin69=DDR_A10
+Mcu.Pin7=JTCK-SWCLK
+Mcu.Pin70=DDR_A12
+Mcu.Pin71=DDR_A1
+Mcu.Pin72=PA3
+Mcu.Pin73=PA0
+Mcu.Pin74=DDR_A14
+Mcu.Pin75=DDR_A11
+Mcu.Pin76=PE2
+Mcu.Pin77=PC2
+Mcu.Pin78=PC3
+Mcu.Pin79=DDR_CKE
+Mcu.Pin8=DDR_DQ0
+Mcu.Pin80=DDR_BA1
+Mcu.Pin81=PG14
+Mcu.Pin82=PG13
+Mcu.Pin83=DDR_A4
+Mcu.Pin84=DDR_DQ8
+Mcu.Pin85=PA1
+Mcu.Pin86=PC1
+Mcu.Pin87=PA2
+Mcu.Pin88=DDR_A8
+Mcu.Pin89=DDR_DQ13
+Mcu.Pin9=DDR_DQ1
+Mcu.Pin90=DDR_DQ10
+Mcu.Pin91=PB1
+Mcu.Pin92=PB0
+Mcu.Pin93=PB11
+Mcu.Pin94=PC0
+Mcu.Pin95=PB10
+Mcu.Pin96=PG11
+Mcu.Pin97=PG10
+Mcu.Pin98=PD11
+Mcu.Pin99=PF6
+Mcu.PinsNb=167
+Mcu.ThirdPartyNb=0
+Mcu.UserConstants=
+Mcu.UserName=STM32MP157CADx
+MxCube.Version=4.99.1
+MxDb.Version=DB.4.0.270
+NJTRST.Mode=JTAG_5_pins
+NJTRST.Signal=SYS_JTRST
+NVIC.BusFault_IRQn=true\:0\:0\:false\:false\:true\:false
+NVIC.DebugMonitor_IRQn=true\:0\:0\:false\:false\:true\:false
+NVIC.HardFault_IRQn=true\:0\:0\:false\:false\:true\:false
+NVIC.MemoryManagement_IRQn=true\:0\:0\:false\:false\:true\:false
+NVIC.NonMaskableInt_IRQn=true\:0\:0\:false\:false\:true\:false
+NVIC.PendSV_IRQn=true\:0\:0\:false\:false\:true\:false
+NVIC.PriorityGroup=NVIC_PRIORITYGROUP_4
+NVIC.SVCall_IRQn=true\:0\:0\:false\:false\:true\:false
+NVIC.SysTick_IRQn=true\:0\:0\:false\:false\:true\:false
+NVIC.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:false
+PA0.Mode=IN16-Single-Ended
+PA0.Signal=ADC1_INP16
+PA1.Locked=true
+PA1.Mode=RGB666
+PA1.Signal=LTDC_R2
+PA10.Locked=true
+PA10.Mode=Ext_Phy_OTG/Dual-Role-Device
+PA10.Signal=USB_OTG_HS_ID
+PA11.GPIOParameters=GPIO_Label
+PA11.GPIO_Label=SPI2_NSS
+PA11.Locked=true
+PA11.Signal=GPIO_Output
+PA12.Locked=true
+PA12.Mode=RGB666
+PA12.Signal=LTDC_R5
+PA13.GPIOParameters=GPIO_Label
+PA13.GPIO_Label=GPIO_PA13
+PA13.Locked=true
+PA13.Signal=GPIO_Output
+PA14.GPIOParameters=GPIO_Label
+PA14.GPIO_Label=GPIO_PA14
+PA14.Locked=true
+PA14.Signal=GPIO_Output
+PA15.GPIOParameters=GPIO_Label
+PA15.GPIO_Label=LDTC_R1
+PA15.Locked=true
+PA15.Signal=GPIO_Output
+PA2.Locked=true
+PA2.Mode=RMII (Reduced MII)
+PA2.Signal=ETH1_MDIO
+PA3.Locked=true
+PA3.Mode=RGB666
+PA3.Signal=LTDC_B5
+PA4.Locked=true
+PA4.Mode=RGB666
+PA4.Signal=LTDC_VSYNC
+PA5.Locked=true
+PA5.Mode=RGB666
+PA5.Signal=LTDC_R4
+PA6.Locked=true
+PA6.Mode=RGB666
+PA6.Signal=LTDC_G2
+PA7.Locked=true
+PA7.Mode=RMII (Reduced MII)
+PA7.Signal=ETH1_CRS_DV
+PA8.Locked=true
+PA8.Mode=RGB666
+PA8.Signal=LTDC_R6
+PA9.Locked=true
+PA9.Mode=Full_Duplex_Master
+PA9.Signal=SPI2_SCK
+PB0.Locked=true
+PB0.Mode=RGB666
+PB0.Signal=LTDC_R3
+PB1.Locked=true
+PB1.Signal=ADCx_INP5
+PB10.Locked=true
+PB10.Mode=RGB666
+PB10.Signal=LTDC_G4
+PB11.Locked=true
+PB11.Mode=RMII (Reduced MII)
+PB11.Signal=ETH1_TX_EN
+PB12.Locked=true
+PB12.Mode=RMII (Reduced MII)
+PB12.Signal=ETH1_TXD0
+PB13.Locked=true
+PB13.Mode=RMII (Reduced MII)
+PB13.Signal=ETH1_TXD1
+PB14.GPIOParameters=GPIO_PuPd
+PB14.GPIO_PuPd=GPIO_PULLUP
+PB14.Locked=true
+PB14.Mode=SD_4_bits_Wide_bus
+PB14.Signal=SDMMC2_D0
+PB15.GPIOParameters=GPIO_PuPd
+PB15.GPIO_PuPd=GPIO_PULLUP
+PB15.Locked=true
+PB15.Mode=SD_4_bits_Wide_bus
+PB15.Signal=SDMMC2_D1
+PB2.GPIOParameters=GPIO_PuPd
+PB2.GPIO_PuPd=GPIO_PULLUP
+PB2.Locked=true
+PB2.Mode=Asynchronous
+PB2.Signal=UART4_RX
+PB3.GPIOParameters=GPIO_PuPd
+PB3.GPIO_PuPd=GPIO_PULLUP
+PB3.Locked=true
+PB3.Mode=SD_4_bits_Wide_bus
+PB3.Signal=SDMMC2_D2
+PB4.GPIOParameters=GPIO_PuPd
+PB4.GPIO_PuPd=GPIO_PULLUP
+PB4.Locked=true
+PB4.Mode=SD_4_bits_Wide_bus
+PB4.Signal=SDMMC2_D3
+PB5.Locked=true
+PB5.Mode=RGB666
+PB5.Signal=LTDC_G7
+PB6.Locked=true
+PB6.Mode=Enable Chip Select for each bank
+PB6.Signal=QUADSPI_BK1_NCS
+PB7.Locked=true
+PB7.Mode=I2C
+PB7.Signal=I2C4_SDA
+PB8.Locked=true
+PB8.Mode=RGB666
+PB8.Signal=LTDC_B6
+PB9.Locked=true
+PB9.Mode=RGB666
+PB9.Signal=LTDC_B7
+PC0.Locked=true
+PC0.Mode=Enable Chip Select for each bank
+PC0.Signal=QUADSPI_BK2_NCS
+PC1.Locked=true
+PC1.Mode=RMII (Reduced MII)
+PC1.Signal=ETH1_MDC
+PC10.GPIOParameters=GPIO_PuPd
+PC10.GPIO_PuPd=GPIO_PULLUP
+PC10.Locked=true
+PC10.Mode=SD_4_bits_Wide_bus
+PC10.Signal=SDMMC1_D2
+PC11.GPIOParameters=GPIO_PuPd
+PC11.GPIO_PuPd=GPIO_PULLUP
+PC11.Locked=true
+PC11.Mode=SD_4_bits_Wide_bus
+PC11.Signal=SDMMC1_D3
+PC12.GPIOParameters=GPIO_PuPd
+PC12.GPIO_PuPd=GPIO_PULLUP
+PC12.Locked=true
+PC12.Mode=SD_4_bits_Wide_bus
+PC12.Signal=SDMMC1_CK
+PC13.GPIOParameters=GPIO_Label
+PC13.GPIO_Label=TP16
+PC13.Locked=true
+PC13.Signal=GPIO_Output
+PC14-OSC32_IN.Locked=true
+PC14-OSC32_IN.Mode=LSE-External-Oscillator
+PC14-OSC32_IN.Signal=RCC_OSC32_IN
+PC15-OSC32_OUT.Locked=true
+PC15-OSC32_OUT.Mode=LSE-External-Oscillator
+PC15-OSC32_OUT.Signal=RCC_OSC32_OUT
+PC2.Locked=true
+PC2.Mode=Full_Duplex_Master
+PC2.Signal=SPI2_MISO
+PC3.Locked=true
+PC3.Mode=Full_Duplex_Master
+PC3.Signal=SPI2_MOSI
+PC4.Locked=true
+PC4.Mode=RMII (Reduced MII)
+PC4.Signal=ETH1_RXD0
+PC5.Locked=true
+PC5.Mode=RMII (Reduced MII)
+PC5.Signal=ETH1_RXD1
+PC6.Locked=true
+PC6.Mode=RGB666
+PC6.Signal=LTDC_HSYNC
+PC7.Locked=true
+PC7.Mode=RGB666
+PC7.Signal=LTDC_G6
+PC8.GPIOParameters=GPIO_PuPd
+PC8.GPIO_PuPd=GPIO_PULLUP
+PC8.Locked=true
+PC8.Mode=SD_4_bits_Wide_bus
+PC8.Signal=SDMMC1_D0
+PC9.GPIOParameters=GPIO_PuPd
+PC9.GPIO_PuPd=GPIO_PULLUP
+PC9.Locked=true
+PC9.Mode=SD_4_bits_Wide_bus
+PC9.Signal=SDMMC1_D1
+PD0.Locked=true
+PD0.Mode=FDCANMaster
+PD0.Signal=FDCAN1_RX
+PD1.Locked=true
+PD1.Mode=FDCANMaster
+PD1.Signal=FDCAN1_TX
+PD10.Locked=true
+PD10.Mode=RGB666
+PD10.Signal=LTDC_B3
+PD11.GPIOParameters=GPIO_PuPd
+PD11.GPIO_PuPd=GPIO_PULLDOWN
+PD11.Locked=true
+PD11.Mode=CTS_RTS
+PD11.Signal=USART3_CTS
+PD12.GPIOParameters=GPIO_PuPd
+PD12.GPIO_PuPd=GPIO_PULLDOWN
+PD12.Locked=true
+PD12.Mode=CTS_RTS
+PD12.Signal=USART3_RTS
+PD13.GPIOParameters=GPIO_Label
+PD13.GPIO_Label=DSIHOST_TE
+PD13.Locked=true
+PD13.Signal=GPIO_Output
+PD14.GPIOParameters=GPIO_PuPd
+PD14.GPIO_PuPd=GPIO_PULLDOWN
+PD14.Locked=true
+PD14.Mode=CTS_RTS
+PD14.Signal=UART8_CTS
+PD15.GPIOParameters=GPIO_Label
+PD15.GPIO_Label=RESET_OUT
+PD15.Locked=true
+PD15.Signal=GPIO_Output
+PD2.GPIOParameters=GPIO_PuPd
+PD2.GPIO_PuPd=GPIO_PULLUP
+PD2.Locked=true
+PD2.Mode=SD_4_bits_Wide_bus
+PD2.Signal=SDMMC1_CMD
+PD3.GPIOParameters=GPIO_PuPd
+PD3.GPIO_PuPd=GPIO_PULLDOWN
+PD3.Locked=true
+PD3.Mode=CTS_RTS
+PD3.Signal=USART2_CTS
+PD4.GPIOParameters=GPIO_PuPd
+PD4.GPIO_PuPd=GPIO_PULLDOWN
+PD4.Locked=true
+PD4.Mode=CTS_RTS
+PD4.Signal=USART2_RTS
+PD5.Locked=true
+PD5.Mode=Asynchronous
+PD5.Signal=USART2_TX
+PD6.GPIOParameters=GPIO_PuPd
+PD6.GPIO_PuPd=GPIO_PULLUP
+PD6.Locked=true
+PD6.Mode=Asynchronous
+PD6.Signal=USART2_RX
+PD7.Locked=true
+PD7.Mode=I2C
+PD7.Signal=I2C2_SCL
+PD8.Locked=true
+PD8.Mode=Asynchronous
+PD8.Signal=USART3_TX
+PD9.GPIOParameters=GPIO_PuPd
+PD9.GPIO_PuPd=GPIO_PULLUP
+PD9.Locked=true
+PD9.Mode=Asynchronous
+PD9.Signal=USART3_RX
+PE0.GPIOParameters=GPIO_PuPd
+PE0.GPIO_PuPd=GPIO_PULLUP
+PE0.Locked=true
+PE0.Mode=Asynchronous
+PE0.Signal=UART8_RX
+PE1.GPIOParameters=GPIO_PuPd
+PE1.GPIO_PuPd=GPIO_PULLUP
+PE1.Locked=true
+PE1.Mode=Asynchronous
+PE1.Signal=UART8_TX
+PE10.Mode=Dual Bank
+PE10.Signal=QUADSPI_BK2_IO3
+PE11.Locked=true
+PE11.Mode=RGB666
+PE11.Signal=LTDC_G3
+PE12.Locked=true
+PE12.Mode=RGB666
+PE12.Signal=LTDC_B4
+PE13.Locked=true
+PE13.Mode=RGB666
+PE13.Signal=LTDC_DE
+PE14.Locked=true
+PE14.Mode=RGB666
+PE14.Signal=LTDC_CLK
+PE15.Locked=true
+PE15.Mode=RGB666
+PE15.Signal=LTDC_R7
+PE2.Locked=true
+PE2.Mode=I2C
+PE2.Signal=I2C4_SCL
+PE3.GPIOParameters=GPIO_PuPd
+PE3.GPIO_PuPd=GPIO_PULLUP
+PE3.Locked=true
+PE3.Mode=SD_4_bits_Wide_bus
+PE3.Signal=SDMMC2_CK
+PE4.GPIOParameters=GPIO_Label
+PE4.GPIO_Label=LTDC_B0
+PE4.Locked=true
+PE4.Signal=GPIO_Output
+PE5.GPIOParameters=GPIO_Label
+PE5.GPIO_Label=LTDC_G0
+PE5.Locked=true
+PE5.Signal=GPIO_Output
+PE6.GPIOParameters=GPIO_Label
+PE6.GPIO_Label=LTDC_G1
+PE6.Locked=true
+PE6.Signal=GPIO_Output
+PE7.Mode=Dual Bank
+PE7.Signal=QUADSPI_BK2_IO0
+PE8.Mode=Dual Bank
+PE8.Signal=QUADSPI_BK2_IO1
+PE9.Mode=Dual Bank
+PE9.Signal=QUADSPI_BK2_IO2
+PF10.Mode=Dual Bank
+PF10.Signal=QUADSPI_CLK
+PF11.Locked=true
+PF11.Mode=RGB666
+PF11.Signal=LTDC_G5
+PF6.Mode=Dual Bank
+PF6.Signal=QUADSPI_BK1_IO3
+PF7.Mode=Dual Bank
+PF7.Signal=QUADSPI_BK1_IO2
+PF8.Mode=Dual Bank
+PF8.Signal=QUADSPI_BK1_IO0
+PF9.Mode=Dual Bank
+PF9.Signal=QUADSPI_BK1_IO1
+PG10.Locked=true
+PG10.Mode=RGB666
+PG10.Signal=LTDC_B2
+PG11.GPIOParameters=GPIO_PuPd
+PG11.GPIO_PuPd=GPIO_PULLUP
+PG11.Locked=true
+PG11.Mode=Asynchronous
+PG11.Signal=UART4_TX
+PG12.GPIOParameters=GPIO_Label
+PG12.GPIO_Label=LTDC_B1
+PG12.Locked=true
+PG12.Signal=GPIO_Output
+PG13.GPIOParameters=GPIO_Label
+PG13.GPIO_Label=LTDC_R0
+PG13.Locked=true
+PG13.Signal=GPIO_Output
+PG14.Locked=true
+PG14.Mode=Asynchronous
+PG14.Signal=USART6_TX
+PG15.Locked=true
+PG15.Mode=I2C
+PG15.Signal=I2C2_SDA
+PG6.GPIOParameters=GPIO_PuPd
+PG6.GPIO_PuPd=GPIO_PULLUP
+PG6.Locked=true
+PG6.Mode=SD_4_bits_Wide_bus
+PG6.Signal=SDMMC2_CMD
+PG7.GPIOParameters=GPIO_PuPd
+PG7.GPIO_PuPd=GPIO_PULLDOWN
+PG7.Locked=true
+PG7.Mode=CTS_RTS
+PG7.Signal=UART8_RTS
+PG8.Locked=true
+PG8.Mode=ETH Clock Output (PHY without Quartz)
+PG8.Signal=ETH1_CLK
+PG9.GPIOParameters=GPIO_PuPd
+PG9.GPIO_PuPd=GPIO_PULLUP
+PG9.Locked=true
+PG9.Mode=Asynchronous
+PG9.Signal=USART6_RX
+PH0-OSC_IN.Locked=true
+PH0-OSC_IN.Mode=HSE-External-Oscillator
+PH0-OSC_IN.Signal=RCC_OSC_IN
+PH1-OSC_OUT.Locked=true
+PH1-OSC_OUT.Mode=HSE-External-Oscillator
+PH1-OSC_OUT.Signal=RCC_OSC_OUT
+PinOutPanel.CurrentBGAView=Top
+PinOutPanel.RotationAngle=0
+ProjectManager.AskForMigrate=true
+ProjectManager.BackupPrevious=false
+ProjectManager.CompilerOptimize=3
+ProjectManager.ComputerToolchain=false
+ProjectManager.CoupleFile=false
+ProjectManager.CustomerFirmwarePackage=
+ProjectManager.DefaultFWLocation=true
+ProjectManager.DeletePrevious=true
+ProjectManager.DeviceId=STM32MP157CADx
+ProjectManager.DeviceTreeLocation=/home/user/gen/src/yocto-genisys/layers/meta-exceet-stm32mp/conf/machine/dts/
+ProjectManager.FirmwarePackage=STM32Cube FW_MP1 V0.4.0
+ProjectManager.FreePins=false
+ProjectManager.HalAssertFull=false
+ProjectManager.HeapSize=0x200
+ProjectManager.KeepUserCode=true
+ProjectManager.LastFirmware=true
+ProjectManager.LibraryCopy=0
+ProjectManager.MainLocation=Src
+ProjectManager.PreviousToolchain=
+ProjectManager.ProjectBuild=false
+ProjectManager.ProjectFileName=t1000-default.ioc
+ProjectManager.ProjectName=t1000-default
+ProjectManager.StackSize=0x400
+ProjectManager.TargetToolchain=SW4STM32
+ProjectManager.ToolChainLocation=
+ProjectManager.UnderRoot=false
+ProjectManager.functionlistsort=1-MX_GPIO_Init-GPIO-false-HAL-true,2-SystemClock_Config-RCC-false-HAL-false
+RCC.ADCCLockSelection=RCC_ADCCLKSOURCE_PER
+RCC.ADCFreq_Value=24000000
+RCC.AHB1234Freq_Value=196000000
+RCC.AHB123Freq_Value=193500000
+RCC.AHB12Freq_Value=64000000
+RCC.AHB4Freq_Value=64000000
+RCC.APB1DIV=RCC_APB1_DIV2
+RCC.APB1Freq_Value=98000000
+RCC.APB2DIV=RCC_APB2_DIV2
+RCC.APB2Freq_Value=98000000
+RCC.APB3DIV=RCC_APB3_DIV2
+RCC.APB3Freq_Value=98000000
+RCC.APB4DIV=RCC_APB4_DIV2
+RCC.APB4Freq_Value=132000000
+RCC.APB5DIV=RCC_APB5_DIV4
+RCC.APB5DIVClockFreq_Value=66000000
+RCC.AXICLKFreq_VALUE=264000000
+RCC.AXICLKSource=RCC_AXISSOURCE_PLL2
+RCC.AXIClockFreq_Value=64000000
+RCC.AXIDIVFreq_Value=264000000
+RCC.CECFreq_Value=32768
+RCC.CKPERCLKFreq_VALUE=24000000
+RCC.CKPERCLKSource=RCC_CKPERCLKSOURCE_HSE
+RCC.CKPERFreq_Value=64000000
+RCC.CSI_VALUE=4000000
+RCC.CortexFreq_Value=196000000
+RCC.CpuClockFreq_Value=64000000
+RCC.D1CPREFreq_Value=64000000
+RCC.DACCLKFreq_VALUE=32000
+RCC.DDRCFreq_Value=528000000
+RCC.DDRPERFMFreq_Value=528000000
+RCC.DDRPHYFreq_Value=528000000
+RCC.DFSDFAFreq_Value=50000000
+RCC.DFSDMACLkFreq_Value=50390625
+RCC.DFSDMFreq_Value=196000000
+RCC.DIVM1=3
+RCC.DIVM2=3
+RCC.DIVM3=3
+RCC.DIVM4=6
+RCC.DIVN1=81
+RCC.DIVN2=66
+RCC.DIVN3=98
+RCC.DIVN4=125
+RCC.DIVP1Freq_Value=648000000
+RCC.DIVP2Freq_Value=264000000
+RCC.DIVP3=4
+RCC.DIVP3Freq_Value=196000000
+RCC.DIVP4=10
+RCC.DIVP4Freq_Value=50000000
+RCC.DIVQ1=1
+RCC.DIVQ1Freq_Value=648000000
+RCC.DIVQ2=1
+RCC.DIVQ2Freq_Value=528000000
+RCC.DIVQ3=16
+RCC.DIVQ3Freq_Value=49000000
+RCC.DIVQ4=10
+RCC.DIVQ4Freq_Value=50000000
+RCC.DIVR1=1
+RCC.DIVR1Freq_Value=648000000
+RCC.DIVR2=1
+RCC.DIVR2Freq_Value=528000000
+RCC.DIVR3=8
+RCC.DIVR3Freq_Value=98000000
+RCC.DIVR4=10
+RCC.DIVR4Freq_Value=50000000
+RCC.DSIFreq_Value=60000000
+RCC.DSIRXEscFreq_Value=60000000
+RCC.DSITXEscFreq_Value=15000000
+RCC.DSI_VALUE=60000000
+RCC.ETHFreq_Value=50000000
+RCC.FCLKFreq_Value=196000000
+RCC.FDCANFreq_Value=24000000
+RCC.FMCFreq_Value=264000000
+RCC.FamilyName=M
+RCC.HCLK3ClockFreq_Value=64000000
+RCC.HCLK4ClockFreq_Value=193500000
+RCC.HCLKFreq_Value=64000000
+RCC.HSE_VALUE=24000000
+RCC.HSIDivClkFreq_Value=64000000
+RCC.HSI_VALUE=64000000
+RCC.Hclk5DIVFreq_Value=264000000
+RCC.Hclk6DIVFreq_Value=264000000
+RCC.I2C123Freq_Value=64000000
+RCC.I2C12CLockSelection=RCC_I2C12CLKSOURCE_HSI
+RCC.I2C12Freq_Value=64000000
+RCC.I2C35Freq_Value=98000000
+RCC.I2C46CLockSelection=RCC_I2C46CLKSOURCE_HSI
+RCC.I2C46Freq_Value=64000000
+RCC.I2C4Freq_Value=64000000
+RCC.IPParameters=ADCCLockSelection,ADCFreq_Value,AHB1234Freq_Value,AHB123Freq_Value,AHB12Freq_Value,AHB4Freq_Value,APB1DIV,APB1Freq_Value,APB2DIV,APB2Freq_Value,APB3DIV,APB3Freq_Value,APB4DIV,APB4Freq_Value,APB5DIV,APB5DIVClockFreq_Value,AXICLKFreq_VALUE,AXICLKSource,AXIClockFreq_Value,AXIDIVFreq_Value,CECFreq_Value,CKPERCLKFreq_VALUE,CKPERCLKSource,CKPERFreq_Value,CSI_VALUE,CortexFreq_Value,CpuClockFreq_Value,D1CPREFreq_Value,DACCLKFreq_VALUE,DDRCFreq_Value,DDRPERFMFreq_Value,DDRPHYFreq_Value,DFSDFAFreq_Value,DFSDMACLkFreq_Value,DFSDMFreq_Value,DIVM1,DIVM2,DIVM3,DIVM4,DIVN1,DIVN2,DIVN3,DIVN4,DIVP1Freq_Value,DIVP2Freq_Value,DIVP3,DIVP3Freq_Value,DIVP4,DIVP4Freq_Value,DIVQ1,DIVQ1Freq_Value,DIVQ2,DIVQ2Freq_Value,DIVQ3,DIVQ3Freq_Value,DIVQ4,DIVQ4Freq_Value,DIVR1,DIVR1Freq_Value,DIVR2,DIVR2Freq_Value,DIVR3,DIVR3Freq_Value,DIVR4,DIVR4Freq_Value,DSIFreq_Value,DSIRXEscFreq_Value,DSITXEscFreq_Value,DSI_VALUE,ETHFreq_Value,FCLKFreq_Value,FDCANFreq_Value,FMCFreq_Value,FamilyName,HCLK3ClockFreq_Value,HCLK4ClockFreq_Value,HCLKFreq_Value,HSE_VALUE,HSIDivClkFreq_Value,HSI_VALUE,Hclk5DIVFreq_Value,Hclk6DIVFreq_Value,I2C123Freq_Value,I2C12CLockSelection,I2C12Freq_Value,I2C35Freq_Value,I2C46CLockSelection,I2C46Freq_Value,I2C4Freq_Value,LPTIM1Freq_Value,LPTIM23Freq_Value,LPTIM2Freq_Value,LPTIM345Freq_Value,LPTIM45Freq_Value,LPUART1Freq_Value,LSI_VALUE,LTDCFreq_Value,MCO1PinFreq_Value,MCO2PinFreq_Value,MCUCLKFreq_VALUE,MCUCLKSource,MCUClockFreq_Value,MPUCLKFreq_VALUE,MPUCLKSource,PLL12Source,PLL1FRACV,PLL1MODE,PLL2FRACV,PLL2MODE,PLL3FRACV,PLL3MODE,PLL3Source,PLL4PDSIFreq_Value,PLL4Source,PLLDSIFreq_Value,PLLDSIVCOFreq_Value,PLLSource,PLLSourceVirtual,PLLSourceVirtualString,PUBLFreq_Value,QSPIFreq_Value,RCC_RTC_Clock_Source_FROM_HSE,RTCClockSelection,RTCFreq_Value,SAI1Freq_Value,SAI23Freq_Value,SAI2CLockSelection,SAI2Freq_Value,SAI3Freq_Value,SAI4AFreq_Value,SAI4BFreq_Value,SAI4CLockSelection,SAI4Freq_Value,SDMMC12CLockSelection,SDMMC12Freq_Value,SDMMC3Freq_Value,SDMMCFreq_Value,SPDIFCLockSelection,SPDIFRXFreq_Value,SPI123Freq_Value,SPI1Freq_Value,SPI23CLockSelection,SPI23Freq_Value,SPI45Freq_Value,SPI6Freq_Value,STGENCLockSelection,STGENFreq_Value,SWPMI1Freq_Value,SYSCLKFreq_VALUE,Tim1OutputFreq_Value,Tim2OutputFreq_Value,UART78CLockSelection,UART78Freq_Value,USART16Freq_Value,USART1Freq_Value,USART234578Freq_Value,USART24CLockSelection,USART24Freq_Value,USART35CLockSelection,USART35Freq_Value,USART6CLockSelection,USART6Freq_Value,USBFreq_Value,USBOCLKSource,USBOFSFreq_Value,USBOHSFreq_Value,USBPHYCLKSource,USBPHYFreq_Value,VCO1OutputFreq_Value,VCO2OutputFreq_Value,VCO3OutputFreq_Value,VCO4OutputFreq_Value,VCOInput1Freq_Value,VCOInput2Freq_Value,VCOInput3Freq_Value,VCOInput4Freq_Value
+RCC.LPTIM1Freq_Value=98000000
+RCC.LPTIM23Freq_Value=98000000
+RCC.LPTIM2Freq_Value=64000000
+RCC.LPTIM345Freq_Value=64000000
+RCC.LPTIM45Freq_Value=98000000
+RCC.LPUART1Freq_Value=64000000
+RCC.LSI_VALUE=32000
+RCC.LTDCFreq_Value=50000000
+RCC.MCO1PinFreq_Value=64000000
+RCC.MCO2PinFreq_Value=648000000
+RCC.MCUCLKFreq_VALUE=196000000
+RCC.MCUCLKSource=RCC_MCUSSOURCE_PLL3
+RCC.MCUClockFreq_Value=196000000
+RCC.MPUCLKFreq_VALUE=648000000
+RCC.MPUCLKSource=RCC_MPUSOURCE_PLL1
+RCC.PLL12Source=RCC_PLL12SOURCE_HSE
+RCC.PLL1FRACV=0x800
+RCC.PLL1MODE=RCC_PLL_FRACTIONAL
+RCC.PLL2FRACV=0x1400
+RCC.PLL2MODE=RCC_PLL_FRACTIONAL
+RCC.PLL3FRACV=0x9ba
+RCC.PLL3MODE=RCC_PLL_FRACTIONAL
+RCC.PLL3Source=RCC_PLL3SOURCE_HSE
+RCC.PLL4PDSIFreq_Value=50000000
+RCC.PLL4Source=RCC_PLL4SOURCE_HSE
+RCC.PLLDSIFreq_Value=480000000
+RCC.PLLDSIVCOFreq_Value=960000000
+RCC.PLLSource=RCC_PLL3SOURCE_HSI
+RCC.PLLSourceVirtual=RCC_PLL3SOURCE_HSI
+RCC.PLLSourceVirtualString=RCC_PLL3SOURCE_HSI
+RCC.PUBLFreq_Value=528000000
+RCC.QSPIFreq_Value=264000000
+RCC.RCC_RTC_Clock_Source_FROM_HSE=24
+RCC.RTCClockSelection=RCC_RTCCLKSOURCE_LSE
+RCC.RTCFreq_Value=32768
+RCC.SAI1Freq_Value=50000000
+RCC.SAI23Freq_Value=50390625
+RCC.SAI2CLockSelection=RCC_SAI2CLKSOURCE_PLL3_Q
+RCC.SAI2Freq_Value=49000000
+RCC.SAI3Freq_Value=50000000
+RCC.SAI4AFreq_Value=50390625
+RCC.SAI4BFreq_Value=50390625
+RCC.SAI4CLockSelection=RCC_SAI4CLKSOURCE_PLL3_Q
+RCC.SAI4Freq_Value=49000000
+RCC.SDMMC12CLockSelection=RCC_SDMMC12CLKSOURCE_PLL3
+RCC.SDMMC12Freq_Value=98000000
+RCC.SDMMC3Freq_Value=196000000
+RCC.SDMMCFreq_Value=50390625
+RCC.SPDIFCLockSelection=RCC_SPDIFRXCLKSOURCE_PLL3
+RCC.SPDIFRXFreq_Value=49000000
+RCC.SPI123Freq_Value=50390625
+RCC.SPI1Freq_Value=50000000
+RCC.SPI23CLockSelection=RCC_SPI23CLKSOURCE_PLL3_Q
+RCC.SPI23Freq_Value=49000000
+RCC.SPI45Freq_Value=98000000
+RCC.SPI6Freq_Value=66000000
+RCC.STGENCLockSelection=RCC_STGENCLKSOURCE_HSE
+RCC.STGENFreq_Value=24000000
+RCC.SWPMI1Freq_Value=64000000
+RCC.SYSCLKFreq_VALUE=64000000
+RCC.Tim1OutputFreq_Value=196000000
+RCC.Tim2OutputFreq_Value=196000000
+RCC.UART78CLockSelection=RCC_UART78CLKSOURCE_HSI
+RCC.UART78Freq_Value=64000000
+RCC.USART16Freq_Value=64000000
+RCC.USART1Freq_Value=66000000
+RCC.USART234578Freq_Value=64000000
+RCC.USART24CLockSelection=RCC_UART24CLKSOURCE_HSI
+RCC.USART24Freq_Value=64000000
+RCC.USART35CLockSelection=RCC_UART35CLKSOURCE_HSI
+RCC.USART35Freq_Value=64000000
+RCC.USART6CLockSelection=RCC_USART6CLKSOURCE_HSI
+RCC.USART6Freq_Value=64000000
+RCC.USBFreq_Value=50390625
+RCC.USBOCLKSource=RCC_USBOCLKSOURCE_PHY
+RCC.USBOFSFreq_Value=48000000
+RCC.USBOHSFreq_Value=48000000
+RCC.USBPHYCLKSource=RCC_USBPHYCLKSOURCE_HSE
+RCC.USBPHYFreq_Value=24000000
+RCC.VCO1OutputFreq_Value=1296000000
+RCC.VCO2OutputFreq_Value=1056000000
+RCC.VCO3OutputFreq_Value=784000000
+RCC.VCO4OutputFreq_Value=500000000
+RCC.VCOInput1Freq_Value=8000000
+RCC.VCOInput2Freq_Value=8000000
+RCC.VCOInput3Freq_Value=8000000
+RCC.VCOInput4Freq_Value=4000000
+SH.ADCx_INP5.0=ADC1_INP5,IN5-Single-Ended
+SH.ADCx_INP5.ConfNb=1
+SPI2.CalculateBaudRate=24.5 MBits/s
+SPI2.Direction=SPI_DIRECTION_2LINES
+SPI2.IPParameters=VirtualType,Mode,Direction,CalculateBaudRate
+SPI2.Mode=SPI_MODE_MASTER
+SPI2.VirtualType=VM_MASTER
+USART2.IPParameters=VirtualMode-Asynchronous
+USART2.VirtualMode-Asynchronous=VM_ASYNC
+USART3.IPParameters=VirtualMode-Asynchronous
+USART3.VirtualMode-Asynchronous=VM_ASYNC
+USART6.IPParameters=VirtualMode-Asynchronous
+USART6.VirtualMode-Asynchronous=VM_ASYNC
+USB_DM1.Mode=Enable
+USB_DM1.Signal=USBH_HS1_DM
+USB_DM2.Mode=Ext_Phy_OTG/Dual-Role-Device
+USB_DM2.Signal=USB_OTG_HS_DM
+USB_DP1.Mode=Enable
+USB_DP1.Signal=USBH_HS1_DP
+USB_DP2.Mode=Ext_Phy_OTG/Dual-Role-Device
+USB_DP2.Signal=USB_OTG_HS_DP
+VP_DDR_DDR3.Mode=DDR3
+VP_DDR_DDR3.Signal=DDR_DDR3
+VP_DDR_DDR3_16_4Gb.Mode=4Gb_16bits
+VP_DDR_DDR3_16_4Gb.Signal=DDR_DDR3_16_4Gb
+VP_DDR_DDR_16_bits.Mode=16bits
+VP_DDR_DDR_16_bits.Signal=DDR_DDR_16_bits
+VP_DMA_VS_DMA1_A7NS.Mode=Cortex-A7 non secure
+VP_DMA_VS_DMA1_A7NS.Signal=DMA_VS_DMA1_A7NS
+VP_DMA_VS_DMA2_M4.Mode=Cortex-M4
+VP_DMA_VS_DMA2_M4.Signal=DMA_VS_DMA2_M4
+VP_RTC_VS_RTC_Activate.Mode=RTC_Enabled
+VP_RTC_VS_RTC_Activate.Signal=RTC_VS_RTC_Activate
+board=custom
diff --git a/conf/machine/cubemx/t1000-k/DeviceTree/t1000-k/kernel/stm32mp157c-t1000-k-mx.dts b/conf/machine/cubemx/t1000-k/DeviceTree/t1000-k/kernel/stm32mp157c-t1000-k-mx.dts
deleted file mode 100644
index 52b8368243f58fffb0585cd1c22cc679d364d37e..0000000000000000000000000000000000000000
--- a/conf/machine/cubemx/t1000-k/DeviceTree/t1000-k/kernel/stm32mp157c-t1000-k-mx.dts
+++ /dev/null
@@ -1,879 +0,0 @@
-/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
-/*
- * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
- * Author: STM32CubeMX code generation for STMicroelectronics.
- */
-
-/dts-v1/;
-#include "stm32mp157c.dtsi"
-#include "stm32mp157c-m4-srm.dtsi"
-#include "stm32mp157cad-pinctrl.dtsi"
-
-/* USER CODE BEGIN includes */
-/* USER CODE END includes */
-
-/ {
-	model = "STMicroelectronics custom STM32CubeMX board";
-	compatible = "st,stm32mp157c-t1000-k-mx", "st,stm32mp157";
-
-	memory@c0000000 {
-		reg = <0xc0000000 0x20000000>;
-
-		/* USER CODE BEGIN memory */
-		/* USER CODE END memory */
-	};
-
-	reserved-memory {
-		#address-cells = <1>;
-		#size-cells = <1>;
-		ranges;
-
-		/* USER CODE BEGIN reserved-memory */
-		/* USER CODE END reserved-memory */
-
-		gpu_reserved: gpu@dc000000 {
-			reg = <0xdc000000 0x4000000>;
-			no-map;
-		};
-	};
-
-	/* USER CODE BEGIN root */
-	/* USER CODE END root */
-
-	clocks {
-		/* USER CODE BEGIN clocks */
-		/* USER CODE END clocks */
-
-		clk_hsi: clk-hsi {
-			clock-frequency = <64000000>;
-		};
-
-		clk_csi: clk-csi {
-			clock-frequency = <4000000>;
-		};
-
-		clk_lse: clk-lse {
-			clock-frequency = <32768>;
-		};
-
-		clk_hse: clk-hse {
-			clock-frequency = <24000000>;
-		};
-	};
-
-}; /*root*/
-
-&pinctrl {
-	u-boot,dm-pre-reloc;
-
-	adc_pins_mx: adc_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 0, ANALOG)>, /* ADC1_INP16 */
-					 <STM32_PINMUX('B', 1, ANALOG)>; /* ADC1_INP5 */
-		};
-	};
-
-	adc_sleep_pins_mx: adc_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 0, ANALOG)>, /* ADC1_INP16 */
-					 <STM32_PINMUX('B', 1, ANALOG)>; /* ADC1_INP5 */
-		};
-	};
-
-	eth1_pins_mx: eth1_mx-0 {
-		pins1 {
-			pinmux = <STM32_PINMUX('A', 2, AF11)>; /* ETH1_MDIO */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-		pins2 {
-			pinmux = <STM32_PINMUX('A', 7, AF11)>, /* ETH1_CRS_DV */
-					 <STM32_PINMUX('C', 4, AF11)>, /* ETH1_RXD0 */
-					 <STM32_PINMUX('C', 5, AF11)>; /* ETH1_RXD1 */
-			bias-disable;
-		};
-		pins3 {
-			pinmux = <STM32_PINMUX('B', 11, AF11)>; /* ETH1_TX_EN */
-		};
-		pins4 {
-			pinmux = <STM32_PINMUX('B', 12, AF11)>, /* ETH1_TXD0 */
-					 <STM32_PINMUX('B', 13, AF11)>, /* ETH1_TXD1 */
-					 <STM32_PINMUX('C', 1, AF11)>, /* ETH1_MDC */
-					 <STM32_PINMUX('G', 8, AF2)>; /* ETH1_CLK */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-	};
-
-	eth1_sleep_pins_mx: eth1_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 2, ANALOG)>, /* ETH1_MDIO */
-					 <STM32_PINMUX('A', 7, ANALOG)>, /* ETH1_CRS_DV */
-					 <STM32_PINMUX('B', 11, ANALOG)>, /* ETH1_TX_EN */
-					 <STM32_PINMUX('B', 12, ANALOG)>, /* ETH1_TXD0 */
-					 <STM32_PINMUX('B', 13, ANALOG)>, /* ETH1_TXD1 */
-					 <STM32_PINMUX('C', 1, ANALOG)>, /* ETH1_MDC */
-					 <STM32_PINMUX('C', 4, ANALOG)>, /* ETH1_RXD0 */
-					 <STM32_PINMUX('C', 5, ANALOG)>, /* ETH1_RXD1 */
-					 <STM32_PINMUX('G', 8, ANALOG)>; /* ETH1_CLK */
-		};
-	};
-
-	fdcan1_pins_mx: fdcan1_mx-0 {
-		pins1 {
-			pinmux = <STM32_PINMUX('D', 0, AF9)>; /* FDCAN1_RX */
-			bias-disable;
-		};
-		pins2 {
-			pinmux = <STM32_PINMUX('D', 1, AF9)>; /* FDCAN1_TX */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-	};
-
-	fdcan1_sleep_pins_mx: fdcan1_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('D', 0, ANALOG)>, /* FDCAN1_RX */
-					 <STM32_PINMUX('D', 1, ANALOG)>; /* FDCAN1_TX */
-		};
-	};
-
-	i2c2_pins_mx: i2c2_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('D', 7, AF4)>, /* I2C2_SCL */
-					 <STM32_PINMUX('G', 15, AF4)>; /* I2C2_SDA */
-			bias-disable;
-			drive-open-drain;
-			slew-rate = <0>;
-		};
-	};
-
-	i2c2_sleep_pins_mx: i2c2_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('D', 7, ANALOG)>, /* I2C2_SCL */
-					 <STM32_PINMUX('G', 15, ANALOG)>; /* I2C2_SDA */
-		};
-	};
-
-	i2c4_pins_mx: i2c4_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('B', 7, AF6)>, /* I2C4_SDA */
-					 <STM32_PINMUX('E', 2, AF4)>; /* I2C4_SCL */
-			bias-disable;
-			drive-open-drain;
-			slew-rate = <0>;
-		};
-	};
-
-	i2c4_sleep_pins_mx: i2c4_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('B', 7, ANALOG)>, /* I2C4_SDA */
-					 <STM32_PINMUX('E', 2, ANALOG)>; /* I2C4_SCL */
-		};
-	};
-
-	ltdc_pins_mx: ltdc_mx-0 {
-		pins1 {
-			pinmux = <STM32_PINMUX('A', 1, AF14)>, /* LTDC_R2 */
-					 <STM32_PINMUX('A', 3, AF14)>, /* LTDC_B5 */
-					 <STM32_PINMUX('A', 4, AF14)>, /* LTDC_VSYNC */
-					 <STM32_PINMUX('A', 5, AF14)>, /* LTDC_R4 */
-					 <STM32_PINMUX('A', 6, AF14)>, /* LTDC_G2 */
-					 <STM32_PINMUX('A', 8, AF14)>, /* LTDC_R6 */
-					 <STM32_PINMUX('A', 12, AF14)>, /* LTDC_R5 */
-					 <STM32_PINMUX('A', 15, AF14)>, /* LTDC_R1 */
-					 <STM32_PINMUX('B', 0, AF9)>, /* LTDC_R3 */
-					 <STM32_PINMUX('B', 5, AF14)>, /* LTDC_G7 */
-					 <STM32_PINMUX('B', 8, AF14)>, /* LTDC_B6 */
-					 <STM32_PINMUX('B', 9, AF14)>, /* LTDC_B7 */
-					 <STM32_PINMUX('B', 10, AF14)>, /* LTDC_G4 */
-					 <STM32_PINMUX('C', 6, AF14)>, /* LTDC_HSYNC */
-					 <STM32_PINMUX('C', 7, AF14)>, /* LTDC_G6 */
-					 <STM32_PINMUX('D', 10, AF14)>, /* LTDC_B3 */
-					 <STM32_PINMUX('E', 4, AF14)>, /* LTDC_B0 */
-					 <STM32_PINMUX('E', 5, AF14)>, /* LTDC_G0 */
-					 <STM32_PINMUX('E', 6, AF14)>, /* LTDC_G1 */
-					 <STM32_PINMUX('E', 11, AF14)>, /* LTDC_G3 */
-					 <STM32_PINMUX('E', 12, AF14)>, /* LTDC_B4 */
-					 <STM32_PINMUX('E', 13, AF14)>, /* LTDC_DE */
-					 <STM32_PINMUX('E', 15, AF14)>, /* LTDC_R7 */
-					 <STM32_PINMUX('F', 11, AF14)>, /* LTDC_G5 */
-					 <STM32_PINMUX('G', 10, AF14)>, /* LTDC_B2 */
-					 <STM32_PINMUX('G', 12, AF14)>, /* LTDC_B1 */
-					 <STM32_PINMUX('G', 13, AF14)>; /* LTDC_R0 */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-		pins2 {
-			pinmux = <STM32_PINMUX('E', 14, AF14)>; /* LTDC_CLK */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-	};
-
-	ltdc_sleep_pins_mx: ltdc_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 1, ANALOG)>, /* LTDC_R2 */
-					 <STM32_PINMUX('A', 3, ANALOG)>, /* LTDC_B5 */
-					 <STM32_PINMUX('A', 4, ANALOG)>, /* LTDC_VSYNC */
-					 <STM32_PINMUX('A', 5, ANALOG)>, /* LTDC_R4 */
-					 <STM32_PINMUX('A', 6, ANALOG)>, /* LTDC_G2 */
-					 <STM32_PINMUX('A', 8, ANALOG)>, /* LTDC_R6 */
-					 <STM32_PINMUX('A', 12, ANALOG)>, /* LTDC_R5 */
-					 <STM32_PINMUX('A', 15, ANALOG)>, /* LTDC_R1 */
-					 <STM32_PINMUX('B', 0, ANALOG)>, /* LTDC_R3 */
-					 <STM32_PINMUX('B', 5, ANALOG)>, /* LTDC_G7 */
-					 <STM32_PINMUX('B', 8, ANALOG)>, /* LTDC_B6 */
-					 <STM32_PINMUX('B', 9, ANALOG)>, /* LTDC_B7 */
-					 <STM32_PINMUX('B', 10, ANALOG)>, /* LTDC_G4 */
-					 <STM32_PINMUX('C', 6, ANALOG)>, /* LTDC_HSYNC */
-					 <STM32_PINMUX('C', 7, ANALOG)>, /* LTDC_G6 */
-					 <STM32_PINMUX('D', 10, ANALOG)>, /* LTDC_B3 */
-					 <STM32_PINMUX('E', 4, ANALOG)>, /* LTDC_B0 */
-					 <STM32_PINMUX('E', 5, ANALOG)>, /* LTDC_G0 */
-					 <STM32_PINMUX('E', 6, ANALOG)>, /* LTDC_G1 */
-					 <STM32_PINMUX('E', 11, ANALOG)>, /* LTDC_G3 */
-					 <STM32_PINMUX('E', 12, ANALOG)>, /* LTDC_B4 */
-					 <STM32_PINMUX('E', 13, ANALOG)>, /* LTDC_DE */
-					 <STM32_PINMUX('E', 14, ANALOG)>, /* LTDC_CLK */
-					 <STM32_PINMUX('E', 15, ANALOG)>, /* LTDC_R7 */
-					 <STM32_PINMUX('F', 11, ANALOG)>, /* LTDC_G5 */
-					 <STM32_PINMUX('G', 10, ANALOG)>, /* LTDC_B2 */
-					 <STM32_PINMUX('G', 12, ANALOG)>, /* LTDC_B1 */
-					 <STM32_PINMUX('G', 13, ANALOG)>; /* LTDC_R0 */
-		};
-	};
-
-	quadspi_pins_mx: quadspi_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 6, AF10)>, /* QUADSPI_BK1_NCS */
-					 <STM32_PINMUX('C', 0, AF10)>; /* QUADSPI_BK2_NCS */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('E', 7, AF10)>, /* QUADSPI_BK2_IO0 */
-					 <STM32_PINMUX('E', 8, AF10)>, /* QUADSPI_BK2_IO1 */
-					 <STM32_PINMUX('E', 9, AF10)>, /* QUADSPI_BK2_IO2 */
-					 <STM32_PINMUX('E', 10, AF10)>, /* QUADSPI_BK2_IO3 */
-					 <STM32_PINMUX('F', 6, AF9)>, /* QUADSPI_BK1_IO3 */
-					 <STM32_PINMUX('F', 7, AF9)>, /* QUADSPI_BK1_IO2 */
-					 <STM32_PINMUX('F', 8, AF10)>, /* QUADSPI_BK1_IO0 */
-					 <STM32_PINMUX('F', 9, AF10)>; /* QUADSPI_BK1_IO1 */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins3 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('F', 10, AF9)>; /* QUADSPI_CLK */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <2>;
-		};
-	};
-
-	quadspi_sleep_pins_mx: quadspi_sleep_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 6, ANALOG)>, /* QUADSPI_BK1_NCS */
-					 <STM32_PINMUX('C', 0, ANALOG)>, /* QUADSPI_BK2_NCS */
-					 <STM32_PINMUX('E', 7, ANALOG)>, /* QUADSPI_BK2_IO0 */
-					 <STM32_PINMUX('E', 8, ANALOG)>, /* QUADSPI_BK2_IO1 */
-					 <STM32_PINMUX('E', 9, ANALOG)>, /* QUADSPI_BK2_IO2 */
-					 <STM32_PINMUX('E', 10, ANALOG)>, /* QUADSPI_BK2_IO3 */
-					 <STM32_PINMUX('F', 6, ANALOG)>, /* QUADSPI_BK1_IO3 */
-					 <STM32_PINMUX('F', 7, ANALOG)>, /* QUADSPI_BK1_IO2 */
-					 <STM32_PINMUX('F', 8, ANALOG)>, /* QUADSPI_BK1_IO0 */
-					 <STM32_PINMUX('F', 9, ANALOG)>, /* QUADSPI_BK1_IO1 */
-					 <STM32_PINMUX('F', 10, ANALOG)>; /* QUADSPI_CLK */
-		};
-	};
-
-	rtc_pins_mx: rtc_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('C', 13, ANALOG)>; /* RTC_LSCO */
-		};
-	};
-
-	rtc_sleep_pins_mx: rtc_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('C', 13, ANALOG)>; /* RTC_LSCO */
-		};
-	};
-
-	sdmmc1_pins_mx: sdmmc1_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
-					 <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
-					 <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
-					 <STM32_PINMUX('C', 11, AF12)>, /* SDMMC1_D3 */
-					 <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 12, AF12)>; /* SDMMC1_CK */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-	};
-
-	sdmmc1_opendrain_pins_mx: sdmmc1_opendrain_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
-					 <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
-					 <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
-					 <STM32_PINMUX('C', 11, AF12)>; /* SDMMC1_D3 */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 12, AF12)>; /* SDMMC1_CK */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins3 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
-			bias-pull-up;
-			drive-open-drain;
-			slew-rate = <1>;
-		};
-	};
-
-	sdmmc1_sleep_pins_mx: sdmmc1_sleep_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 8, ANALOG)>, /* SDMMC1_D0 */
-					 <STM32_PINMUX('C', 9, ANALOG)>, /* SDMMC1_D1 */
-					 <STM32_PINMUX('C', 10, ANALOG)>, /* SDMMC1_D2 */
-					 <STM32_PINMUX('C', 11, ANALOG)>, /* SDMMC1_D3 */
-					 <STM32_PINMUX('C', 12, ANALOG)>, /* SDMMC1_CK */
-					 <STM32_PINMUX('D', 2, ANALOG)>; /* SDMMC1_CMD */
-		};
-	};
-
-	sdmmc2_pins_mx: sdmmc2_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 3, AF9)>, /* SDMMC2_D2 */
-					 <STM32_PINMUX('B', 4, AF9)>, /* SDMMC2_D3 */
-					 <STM32_PINMUX('B', 14, AF9)>, /* SDMMC2_D0 */
-					 <STM32_PINMUX('B', 15, AF9)>, /* SDMMC2_D1 */
-					 <STM32_PINMUX('G', 6, AF10)>; /* SDMMC2_CMD */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('E', 3, AF9)>; /* SDMMC2_CK */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-	};
-
-	sdmmc2_opendrain_pins_mx: sdmmc2_opendrain_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 3, AF9)>, /* SDMMC2_D2 */
-					 <STM32_PINMUX('B', 4, AF9)>, /* SDMMC2_D3 */
-					 <STM32_PINMUX('B', 14, AF9)>, /* SDMMC2_D0 */
-					 <STM32_PINMUX('B', 15, AF9)>; /* SDMMC2_D1 */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('E', 3, AF9)>; /* SDMMC2_CK */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins3 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('G', 6, AF10)>; /* SDMMC2_CMD */
-			bias-pull-up;
-			drive-open-drain;
-			slew-rate = <1>;
-		};
-	};
-
-	sdmmc2_sleep_pins_mx: sdmmc2_sleep_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 3, ANALOG)>, /* SDMMC2_D2 */
-					 <STM32_PINMUX('B', 4, ANALOG)>, /* SDMMC2_D3 */
-					 <STM32_PINMUX('B', 14, ANALOG)>, /* SDMMC2_D0 */
-					 <STM32_PINMUX('B', 15, ANALOG)>, /* SDMMC2_D1 */
-					 <STM32_PINMUX('E', 3, ANALOG)>, /* SDMMC2_CK */
-					 <STM32_PINMUX('G', 6, ANALOG)>; /* SDMMC2_CMD */
-		};
-	};
-
-	tim1_pwm_pins_mx: tim1_pwm_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 9, AF1)>; /* TIM1_CH2 */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-	};
-
-	tim1_pwm_sleep_pins_mx: tim1_pwm_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 9, ANALOG)>; /* TIM1_CH2 */
-		};
-	};
-
-	tim4_pwm_pins_mx: tim4_pwm_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('D', 14, AF2)>; /* TIM4_CH3 */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-	};
-
-	tim4_pwm_sleep_pins_mx: tim4_pwm_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('D', 14, ANALOG)>; /* TIM4_CH3 */
-		};
-	};
-
-	uart4_pins_mx: uart4_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 2, AF8)>; /* UART4_RX */
-			bias-pull-up;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('G', 11, AF6)>; /* UART4_TX */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-	};
-
-	uart4_sleep_pins_mx: uart4_sleep_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 2, ANALOG)>, /* UART4_RX */
-					 <STM32_PINMUX('G', 11, ANALOG)>; /* UART4_TX */
-		};
-	};
-
-	usart2_pins_mx: usart2_mx-0 {
-		pins1 {
-			pinmux = <STM32_PINMUX('D', 4, AF7)>; /* USART2_RTS */
-			bias-pull-down;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-		pins2 {
-			pinmux = <STM32_PINMUX('D', 5, AF7)>; /* USART2_TX */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-		pins3 {
-			pinmux = <STM32_PINMUX('D', 6, AF7)>; /* USART2_RX */
-			bias-pull-up;
-		};
-	};
-
-	usart2_sleep_pins_mx: usart2_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('D', 4, ANALOG)>, /* USART2_RTS */
-					 <STM32_PINMUX('D', 5, ANALOG)>, /* USART2_TX */
-					 <STM32_PINMUX('D', 6, ANALOG)>; /* USART2_RX */
-		};
-	};
-
-	usart3_pins_mx: usart3_mx-0 {
-		pins1 {
-			pinmux = <STM32_PINMUX('D', 9, AF7)>, /* USART3_RX */
-					 <STM32_PINMUX('D', 11, AF7)>; /* USART3_CTS */
-			bias-disable;
-		};
-		pins2 {
-			pinmux = <STM32_PINMUX('D', 8, AF7)>, /* USART3_TX */
-					 <STM32_PINMUX('D', 12, AF7)>; /* USART3_RTS */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-	};
-
-	usart3_sleep_pins_mx: usart3_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('D', 8, ANALOG)>, /* USART3_TX */
-					 <STM32_PINMUX('D', 9, ANALOG)>, /* USART3_RX */
-					 <STM32_PINMUX('D', 11, ANALOG)>, /* USART3_CTS */
-					 <STM32_PINMUX('D', 12, ANALOG)>; /* USART3_RTS */
-		};
-	};
-
-	usb_otg_hs_pins_mx: usb_otg_hs_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
-		};
-	};
-
-	usb_otg_hs_sleep_pins_mx: usb_otg_hs_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
-		};
-	};
-
-	/* USER CODE BEGIN pinctrl */
-	/* USER CODE END pinctrl */
-};
-
-&pinctrl_z {
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN pinctrl_z */
-	/* USER CODE END pinctrl_z */
-};
-
-&m4_rproc{
-	mboxes = <&ipcc 0>, <&ipcc 1>, <&ipcc 2>;
-	mbox-names = "vq0", "vq1", "shutdown";
-	recovery;
-	status = "okay";
-
-	/* USER CODE BEGIN m4_rproc */
-	/* USER CODE END m4_rproc */
-};
-
-&adc{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&adc_pins_mx>;
-	pinctrl-1 = <&adc_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN adc */
-	/* USER CODE END adc */
-};
-
-&bsec{
-	status = "okay";
-
-	/* USER CODE BEGIN bsec */
-	/* USER CODE END bsec */
-};
-
-&crc1{
-	status = "okay";
-
-	/* USER CODE BEGIN crc1 */
-	/* USER CODE END crc1 */
-};
-
-&cryp1{
-	status = "okay";
-
-	/* USER CODE BEGIN cryp1 */
-	/* USER CODE END cryp1 */
-};
-
-&dts{
-	status = "okay";
-
-	/* USER CODE BEGIN dts */
-	/* USER CODE END dts */
-};
-
-&ethernet0{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&eth1_pins_mx>;
-	pinctrl-1 = <&eth1_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN ethernet0 */
-	/* USER CODE END ethernet0 */
-};
-
-&gpu{
-	status = "okay";
-
-	/* USER CODE BEGIN gpu */
-	/* USER CODE END gpu */
-};
-
-&hash1{
-	status = "okay";
-
-	/* USER CODE BEGIN hash1 */
-	/* USER CODE END hash1 */
-};
-
-&hsem{
-	status = "okay";
-
-	/* USER CODE BEGIN hsem */
-	/* USER CODE END hsem */
-};
-
-&i2c2{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&i2c2_pins_mx>;
-	pinctrl-1 = <&i2c2_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN i2c2 */
-	/* USER CODE END i2c2 */
-};
-
-&i2c4{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&i2c4_pins_mx>;
-	pinctrl-1 = <&i2c4_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN i2c4 */
-	/* USER CODE END i2c4 */
-};
-
-&ipcc{
-	status = "okay";
-
-	/* USER CODE BEGIN ipcc */
-	/* USER CODE END ipcc */
-};
-
-&ltdc{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&ltdc_pins_mx>;
-	pinctrl-1 = <&ltdc_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN ltdc */
-	/* USER CODE END ltdc */
-};
-
-&m_can1{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&fdcan1_pins_mx>;
-	pinctrl-1 = <&fdcan1_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN m_can1 */
-	/* USER CODE END m_can1 */
-};
-
-&qspi{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&quadspi_pins_mx>;
-	pinctrl-1 = <&quadspi_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN qspi */
-	/* USER CODE END qspi */
-};
-
-&rcc{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN rcc */
-	/* USER CODE END rcc */
-};
-
-&rng1{
-	status = "okay";
-
-	/* USER CODE BEGIN rng1 */
-	/* USER CODE END rng1 */
-};
-
-&rtc{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&rtc_pins_mx>;
-	pinctrl-1 = <&rtc_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN rtc */
-	/* USER CODE END rtc */
-};
-
-&sdmmc1{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "opendrain", "sleep";
-	pinctrl-0 = <&sdmmc1_pins_mx>;
-	pinctrl-1 = <&sdmmc1_opendrain_pins_mx>;
-	pinctrl-2 = <&sdmmc1_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN sdmmc1 */
-	/* USER CODE END sdmmc1 */
-};
-
-&sdmmc2{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "opendrain", "sleep";
-	pinctrl-0 = <&sdmmc2_pins_mx>;
-	pinctrl-1 = <&sdmmc2_opendrain_pins_mx>;
-	pinctrl-2 = <&sdmmc2_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN sdmmc2 */
-	/* USER CODE END sdmmc2 */
-};
-
-&timers1{
-	status = "okay";
-
-	/* USER CODE BEGIN timers1 */
-	/* USER CODE END timers1 */
-
-	pwm{
-		pinctrl-names = "default", "sleep";
-		pinctrl-0 = <&tim1_pwm_pins_mx>;
-		pinctrl-1 = <&tim1_pwm_sleep_pins_mx>;
-		status = "okay";
-
-		/* USER CODE BEGIN timers1_pwm */
-		/* USER CODE END timers1_pwm */
-	};
-};
-
-&timers4{
-	status = "okay";
-
-	/* USER CODE BEGIN timers4 */
-	/* USER CODE END timers4 */
-
-	pwm{
-		pinctrl-names = "default", "sleep";
-		pinctrl-0 = <&tim4_pwm_pins_mx>;
-		pinctrl-1 = <&tim4_pwm_sleep_pins_mx>;
-		status = "okay";
-
-		/* USER CODE BEGIN timers4_pwm */
-		/* USER CODE END timers4_pwm */
-	};
-};
-
-&uart4{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&uart4_pins_mx>;
-	pinctrl-1 = <&uart4_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN uart4 */
-	/* USER CODE END uart4 */
-};
-
-&usart2{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&usart2_pins_mx>;
-	pinctrl-1 = <&usart2_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN usart2 */
-	/* USER CODE END usart2 */
-};
-
-&usart3{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&usart3_pins_mx>;
-	pinctrl-1 = <&usart3_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN usart3 */
-	/* USER CODE END usart3 */
-};
-
-&usbh_ehci{
-	status = "okay";
-
-	/* USER CODE BEGIN usbh_ehci */
-	/* USER CODE END usbh_ehci */
-};
-
-&usbh_ohci{
-	status = "okay";
-
-	/* USER CODE BEGIN usbh_ohci */
-	/* USER CODE END usbh_ohci */
-};
-
-&usbotg_hs{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&usb_otg_hs_pins_mx>;
-	pinctrl-1 = <&usb_otg_hs_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN usbotg_hs */
-	/* USER CODE END usbotg_hs */
-};
-
-&usbphyc{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc */
-	/* USER CODE END usbphyc */
-};
-
-&usbphyc_port0{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc_port0 */
-	/* USER CODE END usbphyc_port0 */
-};
-
-&usbphyc_port1{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc_port1 */
-	/* USER CODE END usbphyc_port1 */
-};
-
-&vrefbuf{
-	status = "okay";
-
-	/* USER CODE BEGIN vrefbuf */
-	/* USER CODE END vrefbuf */
-};
-
-/* USER CODE BEGIN addons */
-/* USER CODE END addons */
-
diff --git a/conf/machine/cubemx/t1000-k/DeviceTree/t1000-k/tf-a/stm32mp15-mx.h b/conf/machine/cubemx/t1000-k/DeviceTree/t1000-k/tf-a/stm32mp15-mx.h
deleted file mode 100644
index 260cb1764cbcc3cad3375f8f7e0e0566c4ad965a..0000000000000000000000000000000000000000
--- a/conf/machine/cubemx/t1000-k/DeviceTree/t1000-k/tf-a/stm32mp15-mx.h
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright (C) 2015-2018, STMicroelectronics - All Rights Reserved
- *
- * SPDX-License-Identifier:	GPL-2.0+	BSD-3-Clause
- *
- */
-
-/*
- * File generated by STMicroelectronics STM32CubeMX DDR Tool for MPUs
- * DDR type: DDR3 / DDR3L
- * DDR width: 16bits
- * DDR density: 4Gb
- * System frequency: 528000Khz
- * Relaxed Timing Mode: false
- * Address mapping type: RBC
- *
- * Save Date: 2019.11.25, save Time: 18:28:16
- */
-
-#define DDR_MEM_NAME	"DDR3-DDR3L 16bits 528000Khz"
-#define DDR_MEM_SPEED	528000
-#define DDR_MEM_SIZE	0x20000000
-
-#define DDR_MSTR 0x00041401
-#define DDR_MRCTRL0 0x00000010
-#define DDR_MRCTRL1 0x00000000
-#define DDR_DERATEEN 0x00000000
-#define DDR_DERATEINT 0x00800000
-#define DDR_PWRCTL 0x00000000
-#define DDR_PWRTMG 0x00400010
-#define DDR_HWLPCTL 0x00000000
-#define DDR_RFSHCTL0 0x00210000
-#define DDR_RFSHCTL3 0x00000000
-#define DDR_RFSHTMG 0x0040008A
-#define DDR_CRCPARCTL0 0x00000000
-#define DDR_DRAMTMG0 0x121B1214
-#define DDR_DRAMTMG1 0x000A041B
-#define DDR_DRAMTMG2 0x0607080F
-#define DDR_DRAMTMG3 0x0050400C
-#define DDR_DRAMTMG4 0x07040607
-#define DDR_DRAMTMG5 0x06060403
-#define DDR_DRAMTMG6 0x02020002
-#define DDR_DRAMTMG7 0x00000202
-#define DDR_DRAMTMG8 0x00001005
-#define DDR_DRAMTMG14 0x000000A0
-#define DDR_ZQCTL0 0xC2000040
-#define DDR_DFITMG0 0x02050105
-#define DDR_DFITMG1 0x00000202
-#define DDR_DFILPCFG0 0x07000000
-#define DDR_DFIUPD0 0xC0400003
-#define DDR_DFIUPD1 0x00000000
-#define DDR_DFIUPD2 0x00000000
-#define DDR_DFIPHYMSTR 0x00000000
-#define DDR_ODTCFG 0x06000600
-#define DDR_ODTMAP 0x00000001
-#define DDR_SCHED 0x00000C01
-#define DDR_SCHED1 0x00000000
-#define DDR_PERFHPR1 0x01000001
-#define DDR_PERFLPR1 0x08000200
-#define DDR_PERFWR1 0x08000400
-#define DDR_DBG0 0x00000000
-#define DDR_DBG1 0x00000000
-#define DDR_DBGCMD 0x00000000
-#define DDR_POISONCFG 0x00000000
-#define DDR_PCCFG 0x00000010
-#define DDR_PCFGR_0 0x00010000
-#define DDR_PCFGW_0 0x00000000
-#define DDR_PCFGQOS0_0 0x02100C03
-#define DDR_PCFGQOS1_0 0x00800100
-#define DDR_PCFGWQOS0_0 0x01100C03
-#define DDR_PCFGWQOS1_0 0x01000200
-#define DDR_PCFGR_1 0x00010000
-#define DDR_PCFGW_1 0x00000000
-#define DDR_PCFGQOS0_1 0x02100C03
-#define DDR_PCFGQOS1_1 0x00800040
-#define DDR_PCFGWQOS0_1 0x01100C03
-#define DDR_PCFGWQOS1_1 0x01000200
-#define DDR_ADDRMAP1 0x00070707
-#define DDR_ADDRMAP2 0x00000000
-#define DDR_ADDRMAP3 0x1F000000
-#define DDR_ADDRMAP4 0x00001F1F
-#define DDR_ADDRMAP5 0x06060606
-#define DDR_ADDRMAP6 0x0F060606
-#define DDR_ADDRMAP9 0x00000000
-#define DDR_ADDRMAP10 0x00000000
-#define DDR_ADDRMAP11 0x00000000
-#define DDR_PGCR 0x01442E02
-#define DDR_PTR0 0x0022A41B
-#define DDR_PTR1 0x047C0740
-#define DDR_PTR2 0x042D9C80
-#define DDR_ACIOCR 0x10400812
-#define DDR_DXCCR 0x00000C40
-#define DDR_DSGCR 0xF200001F
-#define DDR_DCR 0x0000000B
-#define DDR_DTPR0 0x36D477D0
-#define DDR_DTPR1 0x098A00D8
-#define DDR_DTPR2 0x10023600
-#define DDR_MR0 0x00000830
-#define DDR_MR1 0x00000000
-#define DDR_MR2 0x00000248
-#define DDR_MR3 0x00000000
-#define DDR_ODTCR 0x00010000
-#define DDR_ZQ0CR1 0x00000038
-#define DDR_DX0GCR 0x0000CE81
-#define DDR_DX0DLLCR 0x40000000
-#define DDR_DX0DQTR 0x55050005
-#define DDR_DX0DQSTR 0x3D202000
-#define DDR_DX1GCR 0x0000CE81
-#define DDR_DX1DLLCR 0x40000000
-#define DDR_DX1DQTR 0x00050500
-#define DDR_DX1DQSTR 0x3DB02000
-#define DDR_DX2GCR 0x0000C881
-#define DDR_DX2DLLCR 0x40000000
-#define DDR_DX2DQTR 0xFFFFFFFF
-#define DDR_DX2DQSTR 0x3DB02000
-#define DDR_DX3GCR 0x0000C881
-#define DDR_DX3DLLCR 0x40000000
-#define DDR_DX3DQTR 0xFFFFFFFF
-#define DDR_DX3DQSTR 0x3DB02000
diff --git a/conf/machine/cubemx/t1000-k/DeviceTree/t1000-k/tf-a/stm32mp157c-t1000-k-mx.dts b/conf/machine/cubemx/t1000-k/DeviceTree/t1000-k/tf-a/stm32mp157c-t1000-k-mx.dts
deleted file mode 100644
index 9d80dc633d584e04a6d24d9cc1b28389368b38cc..0000000000000000000000000000000000000000
--- a/conf/machine/cubemx/t1000-k/DeviceTree/t1000-k/tf-a/stm32mp157c-t1000-k-mx.dts
+++ /dev/null
@@ -1,362 +0,0 @@
-/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
-/*
- * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
- * Author: STM32CubeMX code generation for STMicroelectronics.
- */
-
-/dts-v1/;
-#include <dt-bindings/clock/stm32mp1-clksrc.h>
-#include "stm32mp15-mx.h"
-
-#include "stm32mp157c.dtsi"
-#include "stm32mp157cad-pinctrl.dtsi"
-#include "stm32mp15-ddr.dtsi"
-#include "stm32mp157c-security.dtsi"
-
-/* USER CODE BEGIN includes */
-/* USER CODE END includes */
-
-/ {
-	model = "STMicroelectronics custom STM32CubeMX board";
-	compatible = "st,stm32mp157c-t1000-k-mx", "st,stm32mp157";
-
-	/* USER CODE BEGIN root */
-	/* USER CODE END root */
-
-	clocks {
-		/* USER CODE BEGIN clocks */
-		/* USER CODE END clocks */
-
-		clk_lse: clk-lse {
-			/* USER CODE BEGIN clocks */
-			/* USER CODE END clocks */
-			st,drive=<LSEDRV_MEDIUM_HIGH>;
-		};
-
-		clk_hse: clk-hse {
-			/* USER CODE BEGIN clocks */
-			/* USER CODE END clocks */
-		};
-	};
-
-}; /*root*/
-
-&pinctrl {
-	quadspi_pins_mx: quadspi_mx-0 {
-		pins1 {
-			pinmux = <STM32_PINMUX('B', 6, AF10)>, /* QUADSPI_BK1_NCS */
-					 <STM32_PINMUX('C', 0, AF10)>; /* QUADSPI_BK2_NCS */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins2 {
-			pinmux = <STM32_PINMUX('E', 7, AF10)>, /* QUADSPI_BK2_IO0 */
-					 <STM32_PINMUX('E', 8, AF10)>, /* QUADSPI_BK2_IO1 */
-					 <STM32_PINMUX('E', 9, AF10)>, /* QUADSPI_BK2_IO2 */
-					 <STM32_PINMUX('E', 10, AF10)>, /* QUADSPI_BK2_IO3 */
-					 <STM32_PINMUX('F', 6, AF9)>, /* QUADSPI_BK1_IO3 */
-					 <STM32_PINMUX('F', 7, AF9)>, /* QUADSPI_BK1_IO2 */
-					 <STM32_PINMUX('F', 8, AF10)>, /* QUADSPI_BK1_IO0 */
-					 <STM32_PINMUX('F', 9, AF10)>; /* QUADSPI_BK1_IO1 */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins3 {
-			pinmux = <STM32_PINMUX('F', 10, AF9)>; /* QUADSPI_CLK */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <2>;
-		};
-	};
-
-	rtc_pins_mx: rtc_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('C', 13, ANALOG)>; /* RTC_LSCO */
-		};
-	};
-
-	sdmmc1_pins_mx: sdmmc1_mx-0 {
-		pins1 {
-			pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
-					 <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
-					 <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
-					 <STM32_PINMUX('C', 11, AF12)>, /* SDMMC1_D3 */
-					 <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-		pins2 {
-			pinmux = <STM32_PINMUX('C', 12, AF12)>; /* SDMMC1_CK */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-	};
-
-	sdmmc2_pins_mx: sdmmc2_mx-0 {
-		pins1 {
-			pinmux = <STM32_PINMUX('B', 3, AF9)>, /* SDMMC2_D2 */
-					 <STM32_PINMUX('B', 4, AF9)>, /* SDMMC2_D3 */
-					 <STM32_PINMUX('B', 14, AF9)>, /* SDMMC2_D0 */
-					 <STM32_PINMUX('B', 15, AF9)>, /* SDMMC2_D1 */
-					 <STM32_PINMUX('G', 6, AF10)>; /* SDMMC2_CMD */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-		pins2 {
-			pinmux = <STM32_PINMUX('E', 3, AF9)>; /* SDMMC2_CK */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-	};
-
-	uart4_pins_mx: uart4_mx-0 {
-		pins1 {
-			pinmux = <STM32_PINMUX('B', 2, AF8)>; /* UART4_RX */
-			bias-pull-up;
-		};
-		pins2 {
-			pinmux = <STM32_PINMUX('G', 11, AF6)>; /* UART4_TX */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-	};
-
-	usb_otg_hs_pins_mx: usb_otg_hs_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
-		};
-	};
-
-	/* USER CODE BEGIN pinctrl */
-	/* USER CODE END pinctrl */
-};
-
-&pinctrl_z {
-	/* USER CODE BEGIN pinctrl_z */
-	/* USER CODE END pinctrl_z */
-};
-
-&rcc {
-	st,csi-cal;
-	st,hsi-cal;
-	st,cal-sec = <60>;
-	st,clksrc = <
-		CLK_MPU_PLL1P
-		CLK_AXI_PLL2P
-		CLK_MCU_PLL3P
-		CLK_PLL12_HSE
-		CLK_PLL3_HSE
-		CLK_PLL4_HSE
-		CLK_RTC_LSE
-		CLK_MCO1_DISABLED
-		CLK_MCO2_DISABLED
-	>;
-	st,clkdiv = <
-		1 		/*MPU*/
-		0 		/*AXI*/
-		0 		/*MCU*/
-		1 		/*APB1*/
-		1 		/*APB2*/
-		1 		/*APB3*/
-		1 		/*APB4*/
-		2 		/*APB5*/
-		0 		/*RTC*/
-		0 		/*MCO1*/
-		0 		/*MCO2*/
-	>;
-	st,pkcs = <
-		CLK_CKPER_HSE
-		CLK_QSPI_ACLK
-		CLK_ETH_PLL4P
-		CLK_SDMMC12_PLL4P
-		CLK_STGEN_HSE
-		CLK_USBPHY_HSE
-		CLK_SPI2S1_DISABLED
-		CLK_SPI2S23_DISABLED
-		CLK_SPI45_DISABLED
-		CLK_SPI6_DISABLED
-		CLK_I2C46_HSI
-		CLK_SDMMC3_DISABLED
-		CLK_USBO_USBPHY
-		CLK_ADC_CKPER
-		CLK_CEC_DISABLED
-		CLK_I2C12_HSI
-		CLK_I2C35_DISABLED
-		CLK_UART1_DISABLED
-		CLK_UART24_PCLK1
-		CLK_UART35_PCLK1
-		CLK_UART6_DISABLED
-		CLK_UART78_DISABLED
-		CLK_SPDIF_DISABLED
-		CLK_FDCAN_HSE
-		CLK_SAI1_DISABLED
-		CLK_SAI2_DISABLED
-		CLK_SAI3_DISABLED
-		CLK_SAI4_DISABLED
-		CLK_RNG1_CSI
-		CLK_LPTIM1_DISABLED
-		CLK_LPTIM23_DISABLED
-		CLK_LPTIM45_DISABLED
-	>;
-	pll1:st,pll@0 {
-		cfg = < 2 80 0 1 1 1>;
-	};
-	pll2:st,pll@1 {
-		cfg = < 2 65 1 1 0 7>;
-	};
-	pll3:st,pll@2 {
-		cfg = < 2 97 3 1 1 1>;
-	};
-	pll4:st,pll@3 {
-		cfg = < 5 124 9 9 9 3>;
-	};
-};
-
-&bsec{
-	status = "okay";
-	secure-status = "okay";
-
-	/* USER CODE BEGIN bsec */
-	/* USER CODE END bsec */
-};
-
-&etzpc{
-	st,decprot = <
-	/*"Non Secured" peripherals*/
-	DECPROT(STM32MP1_ETZPC_ADC_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-	DECPROT(STM32MP1_ETZPC_CRYP1_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-	DECPROT(STM32MP1_ETZPC_ETH_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-	DECPROT(STM32MP1_ETZPC_TT_FDCAN_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-	DECPROT(STM32MP1_ETZPC_HASH1_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-	DECPROT(STM32MP1_ETZPC_I2C2_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-	DECPROT(STM32MP1_ETZPC_I2C4_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-	DECPROT(STM32MP1_ETZPC_QSPI_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-	DECPROT(STM32MP1_ETZPC_DLYBQ_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-	DECPROT(STM32MP1_ETZPC_RNG1_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-	DECPROT(STM32MP1_ETZPC_TIM1_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-	DECPROT(STM32MP1_ETZPC_TIM4_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-	DECPROT(STM32MP1_ETZPC_UART4_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-	DECPROT(STM32MP1_ETZPC_USART2_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-	DECPROT(STM32MP1_ETZPC_USART3_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-	DECPROT(STM32MP1_ETZPC_OTG_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-	DECPROT(STM32MP1_ETZPC_VREFBUF_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-
-	/*Restriction: following IDs are not managed  - please to use User-Section if needed:
-		STM32MP1_ETZPC_DMA1_ID, STM32MP1_ETZPC_DMA2_ID, STM32MP1_ETZPC_DMAMUX_ID,
-		STM32MP1_ETZPC_SRAMx_ID, STM32MP1_ETZPC_RETRAM_ID, STM32MP1_ETZPC_BKPSRAM_ID*/
-
-	/* USER CODE BEGIN etzpc_decprot */
-		/*STM32CubeMX generates a basic and standard configuration for ETZPC.
-		Additional device configurations can be added here if needed.
-		"etzpc" node could be also overloaded in "addons" User-Section.*/
-	/* USER CODE END etzpc_decprot */
-	>;
-
-	secure-status = "okay";
-
-	/* USER CODE BEGIN etzpc */
-	/* USER CODE END etzpc */
-};
-
-&qspi{
-	pinctrl-names = "default";
-	pinctrl-0 = <&quadspi_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN qspi */
-	/* USER CODE END qspi */
-};
-
-&rcc{
-	status = "okay";
-	secure-status = "okay";
-
-	/* USER CODE BEGIN rcc */
-	/* USER CODE END rcc */
-};
-
-&rng1{
-	status = "okay";
-	secure-status = "okay";
-
-	/* USER CODE BEGIN rng1 */
-	/* USER CODE END rng1 */
-};
-
-&rtc{
-	pinctrl-names = "default";
-	pinctrl-0 = <&rtc_pins_mx>;
-	status = "okay";
-	secure-status = "okay";
-
-	/* USER CODE BEGIN rtc */
-	/* USER CODE END rtc */
-};
-
-&sdmmc1{
-	pinctrl-names = "default";
-	pinctrl-0 = <&sdmmc1_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN sdmmc1 */
-	/* USER CODE END sdmmc1 */
-};
-
-&sdmmc2{
-	pinctrl-names = "default";
-	pinctrl-0 = <&sdmmc2_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN sdmmc2 */
-	/* USER CODE END sdmmc2 */
-};
-
-&uart4{
-	pinctrl-names = "default";
-	pinctrl-0 = <&uart4_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN uart4 */
-	/* USER CODE END uart4 */
-};
-
-&usbotg_hs{
-	pinctrl-names = "default";
-	pinctrl-0 = <&usb_otg_hs_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN usbotg_hs */
-	/* USER CODE END usbotg_hs */
-};
-
-&usbphyc{
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc */
-	/* USER CODE END usbphyc */
-};
-
-&usbphyc_port0{
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc_port0 */
-	/* USER CODE END usbphyc_port0 */
-};
-
-&usbphyc_port1{
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc_port1 */
-	/* USER CODE END usbphyc_port1 */
-};
-
-/* USER CODE BEGIN addons */
-/* USER CODE END addons */
-
diff --git a/conf/machine/cubemx/t1000-k/DeviceTree/t1000-k/u-boot/stm32mp15-mx.h b/conf/machine/cubemx/t1000-k/DeviceTree/t1000-k/u-boot/stm32mp15-mx.h
deleted file mode 100644
index 260cb1764cbcc3cad3375f8f7e0e0566c4ad965a..0000000000000000000000000000000000000000
--- a/conf/machine/cubemx/t1000-k/DeviceTree/t1000-k/u-boot/stm32mp15-mx.h
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright (C) 2015-2018, STMicroelectronics - All Rights Reserved
- *
- * SPDX-License-Identifier:	GPL-2.0+	BSD-3-Clause
- *
- */
-
-/*
- * File generated by STMicroelectronics STM32CubeMX DDR Tool for MPUs
- * DDR type: DDR3 / DDR3L
- * DDR width: 16bits
- * DDR density: 4Gb
- * System frequency: 528000Khz
- * Relaxed Timing Mode: false
- * Address mapping type: RBC
- *
- * Save Date: 2019.11.25, save Time: 18:28:16
- */
-
-#define DDR_MEM_NAME	"DDR3-DDR3L 16bits 528000Khz"
-#define DDR_MEM_SPEED	528000
-#define DDR_MEM_SIZE	0x20000000
-
-#define DDR_MSTR 0x00041401
-#define DDR_MRCTRL0 0x00000010
-#define DDR_MRCTRL1 0x00000000
-#define DDR_DERATEEN 0x00000000
-#define DDR_DERATEINT 0x00800000
-#define DDR_PWRCTL 0x00000000
-#define DDR_PWRTMG 0x00400010
-#define DDR_HWLPCTL 0x00000000
-#define DDR_RFSHCTL0 0x00210000
-#define DDR_RFSHCTL3 0x00000000
-#define DDR_RFSHTMG 0x0040008A
-#define DDR_CRCPARCTL0 0x00000000
-#define DDR_DRAMTMG0 0x121B1214
-#define DDR_DRAMTMG1 0x000A041B
-#define DDR_DRAMTMG2 0x0607080F
-#define DDR_DRAMTMG3 0x0050400C
-#define DDR_DRAMTMG4 0x07040607
-#define DDR_DRAMTMG5 0x06060403
-#define DDR_DRAMTMG6 0x02020002
-#define DDR_DRAMTMG7 0x00000202
-#define DDR_DRAMTMG8 0x00001005
-#define DDR_DRAMTMG14 0x000000A0
-#define DDR_ZQCTL0 0xC2000040
-#define DDR_DFITMG0 0x02050105
-#define DDR_DFITMG1 0x00000202
-#define DDR_DFILPCFG0 0x07000000
-#define DDR_DFIUPD0 0xC0400003
-#define DDR_DFIUPD1 0x00000000
-#define DDR_DFIUPD2 0x00000000
-#define DDR_DFIPHYMSTR 0x00000000
-#define DDR_ODTCFG 0x06000600
-#define DDR_ODTMAP 0x00000001
-#define DDR_SCHED 0x00000C01
-#define DDR_SCHED1 0x00000000
-#define DDR_PERFHPR1 0x01000001
-#define DDR_PERFLPR1 0x08000200
-#define DDR_PERFWR1 0x08000400
-#define DDR_DBG0 0x00000000
-#define DDR_DBG1 0x00000000
-#define DDR_DBGCMD 0x00000000
-#define DDR_POISONCFG 0x00000000
-#define DDR_PCCFG 0x00000010
-#define DDR_PCFGR_0 0x00010000
-#define DDR_PCFGW_0 0x00000000
-#define DDR_PCFGQOS0_0 0x02100C03
-#define DDR_PCFGQOS1_0 0x00800100
-#define DDR_PCFGWQOS0_0 0x01100C03
-#define DDR_PCFGWQOS1_0 0x01000200
-#define DDR_PCFGR_1 0x00010000
-#define DDR_PCFGW_1 0x00000000
-#define DDR_PCFGQOS0_1 0x02100C03
-#define DDR_PCFGQOS1_1 0x00800040
-#define DDR_PCFGWQOS0_1 0x01100C03
-#define DDR_PCFGWQOS1_1 0x01000200
-#define DDR_ADDRMAP1 0x00070707
-#define DDR_ADDRMAP2 0x00000000
-#define DDR_ADDRMAP3 0x1F000000
-#define DDR_ADDRMAP4 0x00001F1F
-#define DDR_ADDRMAP5 0x06060606
-#define DDR_ADDRMAP6 0x0F060606
-#define DDR_ADDRMAP9 0x00000000
-#define DDR_ADDRMAP10 0x00000000
-#define DDR_ADDRMAP11 0x00000000
-#define DDR_PGCR 0x01442E02
-#define DDR_PTR0 0x0022A41B
-#define DDR_PTR1 0x047C0740
-#define DDR_PTR2 0x042D9C80
-#define DDR_ACIOCR 0x10400812
-#define DDR_DXCCR 0x00000C40
-#define DDR_DSGCR 0xF200001F
-#define DDR_DCR 0x0000000B
-#define DDR_DTPR0 0x36D477D0
-#define DDR_DTPR1 0x098A00D8
-#define DDR_DTPR2 0x10023600
-#define DDR_MR0 0x00000830
-#define DDR_MR1 0x00000000
-#define DDR_MR2 0x00000248
-#define DDR_MR3 0x00000000
-#define DDR_ODTCR 0x00010000
-#define DDR_ZQ0CR1 0x00000038
-#define DDR_DX0GCR 0x0000CE81
-#define DDR_DX0DLLCR 0x40000000
-#define DDR_DX0DQTR 0x55050005
-#define DDR_DX0DQSTR 0x3D202000
-#define DDR_DX1GCR 0x0000CE81
-#define DDR_DX1DLLCR 0x40000000
-#define DDR_DX1DQTR 0x00050500
-#define DDR_DX1DQSTR 0x3DB02000
-#define DDR_DX2GCR 0x0000C881
-#define DDR_DX2DLLCR 0x40000000
-#define DDR_DX2DQTR 0xFFFFFFFF
-#define DDR_DX2DQSTR 0x3DB02000
-#define DDR_DX3GCR 0x0000C881
-#define DDR_DX3DLLCR 0x40000000
-#define DDR_DX3DQTR 0xFFFFFFFF
-#define DDR_DX3DQSTR 0x3DB02000
diff --git a/conf/machine/cubemx/t1000-k/DeviceTree/t1000-k/u-boot/stm32mp157c-t1000-k-mx-u-boot.dtsi b/conf/machine/cubemx/t1000-k/DeviceTree/t1000-k/u-boot/stm32mp157c-t1000-k-mx-u-boot.dtsi
deleted file mode 100644
index e17d86f066b05ea28dc62c8477189ebb6738c111..0000000000000000000000000000000000000000
--- a/conf/machine/cubemx/t1000-k/DeviceTree/t1000-k/u-boot/stm32mp157c-t1000-k-mx-u-boot.dtsi
+++ /dev/null
@@ -1,196 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause*/
-/*
- * Copyright (C) 2019, STMicroelectronics - All Rights Reserved
- * Author: STM32CubeMX code generation for STMicroelectronics.
- */
-
-#include <dt-bindings/clock/stm32mp1-clksrc.h>
-#include "stm32mp15-mx.h"
-
-#include "stm32mp157-u-boot.dtsi"
-#include "stm32mp15-ddr.dtsi"
-
-/* USER CODE BEGIN includes */
-/* USER CODE END includes */
-
-/ {
-
-	/* USER CODE BEGIN root */
-	/* USER CODE END root */
-
-	clocks {
-		/* USER CODE BEGIN clocks */
-		/* USER CODE END clocks */
-
-		clk_hsi: clk-hsi {
-			/* USER CODE BEGIN clocks */
-			/* USER CODE END clocks */
-			u-boot,dm-pre-reloc;
-		};
-
-		clk_csi: clk-csi {
-			/* USER CODE BEGIN clocks */
-			/* USER CODE END clocks */
-			u-boot,dm-pre-reloc;
-		};
-
-		clk_lse: clk-lse {
-			/* USER CODE BEGIN clocks */
-			/* USER CODE END clocks */
-			st,drive=<LSEDRV_MEDIUM_HIGH>;
-			u-boot,dm-pre-reloc;
-		};
-
-		clk_hse: clk-hse {
-			/* USER CODE BEGIN clocks */
-			/* USER CODE END clocks */
-			u-boot,dm-pre-reloc;
-		};
-	};
-
-}; /*root*/
-
-&rcc {
-	u-boot,dm-pre-reloc;
-	st,clksrc = <
-		CLK_MPU_PLL1P
-		CLK_AXI_PLL2P
-		CLK_MCU_PLL3P
-		CLK_PLL12_HSE
-		CLK_PLL3_HSE
-		CLK_PLL4_HSE
-		CLK_RTC_LSE
-		CLK_MCO1_DISABLED
-		CLK_MCO2_DISABLED
-	>;
-	st,clkdiv = <
-		1 		/*MPU*/
-		0 		/*AXI*/
-		0 		/*MCU*/
-		1 		/*APB1*/
-		1 		/*APB2*/
-		1 		/*APB3*/
-		1 		/*APB4*/
-		2 		/*APB5*/
-		0 		/*RTC*/
-		0 		/*MCO1*/
-		0 		/*MCO2*/
-	>;
-	st,pkcs = <
-		CLK_CKPER_HSE
-		CLK_QSPI_ACLK
-		CLK_ETH_PLL4P
-		CLK_SDMMC12_PLL4P
-		CLK_STGEN_HSE
-		CLK_USBPHY_HSE
-		CLK_SPI2S1_DISABLED
-		CLK_SPI2S23_DISABLED
-		CLK_SPI45_DISABLED
-		CLK_SPI6_DISABLED
-		CLK_I2C46_HSI
-		CLK_SDMMC3_DISABLED
-		CLK_USBO_USBPHY
-		CLK_ADC_CKPER
-		CLK_CEC_DISABLED
-		CLK_I2C12_HSI
-		CLK_I2C35_DISABLED
-		CLK_UART1_DISABLED
-		CLK_UART24_PCLK1
-		CLK_UART35_PCLK1
-		CLK_UART6_DISABLED
-		CLK_UART78_DISABLED
-		CLK_SPDIF_DISABLED
-		CLK_FDCAN_HSE
-		CLK_SAI1_DISABLED
-		CLK_SAI2_DISABLED
-		CLK_SAI3_DISABLED
-		CLK_SAI4_DISABLED
-		CLK_RNG1_CSI
-		CLK_LPTIM1_DISABLED
-		CLK_LPTIM23_DISABLED
-		CLK_LPTIM45_DISABLED
-	>;
-	pll1:st,pll@0 {
-		cfg = < 2 80 0 1 1 1>;
-		u-boot,dm-pre-reloc;
-	};
-	pll2:st,pll@1 {
-		cfg = < 2 65 1 1 0 7>;
-		u-boot,dm-pre-reloc;
-	};
-	pll3:st,pll@2 {
-		cfg = < 2 97 3 1 1 1>;
-		u-boot,dm-pre-reloc;
-	};
-	pll4:st,pll@3 {
-		cfg = < 5 124 9 9 9 3>;
-		u-boot,dm-pre-reloc;
-	};
-};
-
-&qspi{
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN qspi */
-	/* USER CODE END qspi */
-};
-
-&rcc{
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN rcc */
-	/* USER CODE END rcc */
-};
-
-&sdmmc1{
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN sdmmc1 */
-	/* USER CODE END sdmmc1 */
-};
-
-&sdmmc2{
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN sdmmc2 */
-	/* USER CODE END sdmmc2 */
-};
-
-&uart4{
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN uart4 */
-	/* USER CODE END uart4 */
-};
-
-&usbotg_hs{
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN usbotg_hs */
-	/* USER CODE END usbotg_hs */
-};
-
-&usbphyc{
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN usbphyc */
-	/* USER CODE END usbphyc */
-};
-
-&usbphyc_port0{
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN usbphyc_port0 */
-	/* USER CODE END usbphyc_port0 */
-};
-
-&usbphyc_port1{
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN usbphyc_port1 */
-	/* USER CODE END usbphyc_port1 */
-};
-
-/* USER CODE BEGIN addons */
-/* USER CODE END addons */
-
diff --git a/conf/machine/cubemx/t1000-k/DeviceTree/t1000-k/u-boot/stm32mp157c-t1000-k-mx.dts b/conf/machine/cubemx/t1000-k/DeviceTree/t1000-k/u-boot/stm32mp157c-t1000-k-mx.dts
deleted file mode 100644
index 00edeacca2124d6063093a31e4e672d84c745c2c..0000000000000000000000000000000000000000
--- a/conf/machine/cubemx/t1000-k/DeviceTree/t1000-k/u-boot/stm32mp157c-t1000-k-mx.dts
+++ /dev/null
@@ -1,879 +0,0 @@
-/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
-/*
- * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
- * Author: STM32CubeMX code generation for STMicroelectronics.
- */
-
-/dts-v1/;
-#include "stm32mp157c.dtsi"
-#include "stm32mp157c-m4-srm.dtsi"
-#include "stm32mp157cad-pinctrl.dtsi"
-
-/* USER CODE BEGIN includes */
-/* USER CODE END includes */
-
-/ {
-	model = "STMicroelectronics custom STM32CubeMX board";
-	compatible = "st,stm32mp157c-t1000-k-mx", "st,stm32mp157";
-
-	memory@c0000000 {
-		reg = <0xc0000000 0x20000000>;
-
-		/* USER CODE BEGIN memory */
-		/* USER CODE END memory */
-	};
-
-	reserved-memory {
-		#address-cells = <1>;
-		#size-cells = <1>;
-		ranges;
-
-		/* USER CODE BEGIN reserved-memory */
-		/* USER CODE END reserved-memory */
-
-		gpu_reserved: gpu@dc000000 {
-			reg = <0xdc000000 0x4000000>;
-			no-map;
-		};
-	};
-
-	/* USER CODE BEGIN root */
-	/* USER CODE END root */
-
-	clocks {
-		/* USER CODE BEGIN clocks */
-		/* USER CODE END clocks */
-
-		clk_hsi: clk-hsi {
-			clock-frequency = <64000000>;
-		};
-
-		clk_csi: clk-csi {
-			clock-frequency = <4000000>;
-		};
-
-		clk_lse: clk-lse {
-			clock-frequency = <32768>;
-		};
-
-		clk_hse: clk-hse {
-			clock-frequency = <24000000>;
-		};
-	};
-
-}; /*root*/
-
-&pinctrl {
-	u-boot,dm-pre-reloc;
-
-	adc_pins_mx: adc_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 0, ANALOG)>, /* ADC1_INP16 */
-					 <STM32_PINMUX('B', 1, ANALOG)>; /* ADC1_INP5 */
-		};
-	};
-
-	adc_sleep_pins_mx: adc_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 0, ANALOG)>, /* ADC1_INP16 */
-					 <STM32_PINMUX('B', 1, ANALOG)>; /* ADC1_INP5 */
-		};
-	};
-
-	eth1_pins_mx: eth1_mx-0 {
-		pins1 {
-			pinmux = <STM32_PINMUX('A', 2, AF11)>; /* ETH1_MDIO */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-		pins2 {
-			pinmux = <STM32_PINMUX('A', 7, AF11)>, /* ETH1_CRS_DV */
-					 <STM32_PINMUX('C', 4, AF11)>, /* ETH1_RXD0 */
-					 <STM32_PINMUX('C', 5, AF11)>; /* ETH1_RXD1 */
-			bias-disable;
-		};
-		pins3 {
-			pinmux = <STM32_PINMUX('B', 11, AF11)>; /* ETH1_TX_EN */
-		};
-		pins4 {
-			pinmux = <STM32_PINMUX('B', 12, AF11)>, /* ETH1_TXD0 */
-					 <STM32_PINMUX('B', 13, AF11)>, /* ETH1_TXD1 */
-					 <STM32_PINMUX('C', 1, AF11)>, /* ETH1_MDC */
-					 <STM32_PINMUX('G', 8, AF2)>; /* ETH1_CLK */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-	};
-
-	eth1_sleep_pins_mx: eth1_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 2, ANALOG)>, /* ETH1_MDIO */
-					 <STM32_PINMUX('A', 7, ANALOG)>, /* ETH1_CRS_DV */
-					 <STM32_PINMUX('B', 11, ANALOG)>, /* ETH1_TX_EN */
-					 <STM32_PINMUX('B', 12, ANALOG)>, /* ETH1_TXD0 */
-					 <STM32_PINMUX('B', 13, ANALOG)>, /* ETH1_TXD1 */
-					 <STM32_PINMUX('C', 1, ANALOG)>, /* ETH1_MDC */
-					 <STM32_PINMUX('C', 4, ANALOG)>, /* ETH1_RXD0 */
-					 <STM32_PINMUX('C', 5, ANALOG)>, /* ETH1_RXD1 */
-					 <STM32_PINMUX('G', 8, ANALOG)>; /* ETH1_CLK */
-		};
-	};
-
-	fdcan1_pins_mx: fdcan1_mx-0 {
-		pins1 {
-			pinmux = <STM32_PINMUX('D', 0, AF9)>; /* FDCAN1_RX */
-			bias-disable;
-		};
-		pins2 {
-			pinmux = <STM32_PINMUX('D', 1, AF9)>; /* FDCAN1_TX */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-	};
-
-	fdcan1_sleep_pins_mx: fdcan1_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('D', 0, ANALOG)>, /* FDCAN1_RX */
-					 <STM32_PINMUX('D', 1, ANALOG)>; /* FDCAN1_TX */
-		};
-	};
-
-	i2c2_pins_mx: i2c2_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('D', 7, AF4)>, /* I2C2_SCL */
-					 <STM32_PINMUX('G', 15, AF4)>; /* I2C2_SDA */
-			bias-disable;
-			drive-open-drain;
-			slew-rate = <0>;
-		};
-	};
-
-	i2c2_sleep_pins_mx: i2c2_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('D', 7, ANALOG)>, /* I2C2_SCL */
-					 <STM32_PINMUX('G', 15, ANALOG)>; /* I2C2_SDA */
-		};
-	};
-
-	i2c4_pins_mx: i2c4_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('B', 7, AF6)>, /* I2C4_SDA */
-					 <STM32_PINMUX('E', 2, AF4)>; /* I2C4_SCL */
-			bias-disable;
-			drive-open-drain;
-			slew-rate = <0>;
-		};
-	};
-
-	i2c4_sleep_pins_mx: i2c4_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('B', 7, ANALOG)>, /* I2C4_SDA */
-					 <STM32_PINMUX('E', 2, ANALOG)>; /* I2C4_SCL */
-		};
-	};
-
-	ltdc_pins_mx: ltdc_mx-0 {
-		pins1 {
-			pinmux = <STM32_PINMUX('A', 1, AF14)>, /* LTDC_R2 */
-					 <STM32_PINMUX('A', 3, AF14)>, /* LTDC_B5 */
-					 <STM32_PINMUX('A', 4, AF14)>, /* LTDC_VSYNC */
-					 <STM32_PINMUX('A', 5, AF14)>, /* LTDC_R4 */
-					 <STM32_PINMUX('A', 6, AF14)>, /* LTDC_G2 */
-					 <STM32_PINMUX('A', 8, AF14)>, /* LTDC_R6 */
-					 <STM32_PINMUX('A', 12, AF14)>, /* LTDC_R5 */
-					 <STM32_PINMUX('A', 15, AF14)>, /* LTDC_R1 */
-					 <STM32_PINMUX('B', 0, AF9)>, /* LTDC_R3 */
-					 <STM32_PINMUX('B', 5, AF14)>, /* LTDC_G7 */
-					 <STM32_PINMUX('B', 8, AF14)>, /* LTDC_B6 */
-					 <STM32_PINMUX('B', 9, AF14)>, /* LTDC_B7 */
-					 <STM32_PINMUX('B', 10, AF14)>, /* LTDC_G4 */
-					 <STM32_PINMUX('C', 6, AF14)>, /* LTDC_HSYNC */
-					 <STM32_PINMUX('C', 7, AF14)>, /* LTDC_G6 */
-					 <STM32_PINMUX('D', 10, AF14)>, /* LTDC_B3 */
-					 <STM32_PINMUX('E', 4, AF14)>, /* LTDC_B0 */
-					 <STM32_PINMUX('E', 5, AF14)>, /* LTDC_G0 */
-					 <STM32_PINMUX('E', 6, AF14)>, /* LTDC_G1 */
-					 <STM32_PINMUX('E', 11, AF14)>, /* LTDC_G3 */
-					 <STM32_PINMUX('E', 12, AF14)>, /* LTDC_B4 */
-					 <STM32_PINMUX('E', 13, AF14)>, /* LTDC_DE */
-					 <STM32_PINMUX('E', 15, AF14)>, /* LTDC_R7 */
-					 <STM32_PINMUX('F', 11, AF14)>, /* LTDC_G5 */
-					 <STM32_PINMUX('G', 10, AF14)>, /* LTDC_B2 */
-					 <STM32_PINMUX('G', 12, AF14)>, /* LTDC_B1 */
-					 <STM32_PINMUX('G', 13, AF14)>; /* LTDC_R0 */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-		pins2 {
-			pinmux = <STM32_PINMUX('E', 14, AF14)>; /* LTDC_CLK */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-	};
-
-	ltdc_sleep_pins_mx: ltdc_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 1, ANALOG)>, /* LTDC_R2 */
-					 <STM32_PINMUX('A', 3, ANALOG)>, /* LTDC_B5 */
-					 <STM32_PINMUX('A', 4, ANALOG)>, /* LTDC_VSYNC */
-					 <STM32_PINMUX('A', 5, ANALOG)>, /* LTDC_R4 */
-					 <STM32_PINMUX('A', 6, ANALOG)>, /* LTDC_G2 */
-					 <STM32_PINMUX('A', 8, ANALOG)>, /* LTDC_R6 */
-					 <STM32_PINMUX('A', 12, ANALOG)>, /* LTDC_R5 */
-					 <STM32_PINMUX('A', 15, ANALOG)>, /* LTDC_R1 */
-					 <STM32_PINMUX('B', 0, ANALOG)>, /* LTDC_R3 */
-					 <STM32_PINMUX('B', 5, ANALOG)>, /* LTDC_G7 */
-					 <STM32_PINMUX('B', 8, ANALOG)>, /* LTDC_B6 */
-					 <STM32_PINMUX('B', 9, ANALOG)>, /* LTDC_B7 */
-					 <STM32_PINMUX('B', 10, ANALOG)>, /* LTDC_G4 */
-					 <STM32_PINMUX('C', 6, ANALOG)>, /* LTDC_HSYNC */
-					 <STM32_PINMUX('C', 7, ANALOG)>, /* LTDC_G6 */
-					 <STM32_PINMUX('D', 10, ANALOG)>, /* LTDC_B3 */
-					 <STM32_PINMUX('E', 4, ANALOG)>, /* LTDC_B0 */
-					 <STM32_PINMUX('E', 5, ANALOG)>, /* LTDC_G0 */
-					 <STM32_PINMUX('E', 6, ANALOG)>, /* LTDC_G1 */
-					 <STM32_PINMUX('E', 11, ANALOG)>, /* LTDC_G3 */
-					 <STM32_PINMUX('E', 12, ANALOG)>, /* LTDC_B4 */
-					 <STM32_PINMUX('E', 13, ANALOG)>, /* LTDC_DE */
-					 <STM32_PINMUX('E', 14, ANALOG)>, /* LTDC_CLK */
-					 <STM32_PINMUX('E', 15, ANALOG)>, /* LTDC_R7 */
-					 <STM32_PINMUX('F', 11, ANALOG)>, /* LTDC_G5 */
-					 <STM32_PINMUX('G', 10, ANALOG)>, /* LTDC_B2 */
-					 <STM32_PINMUX('G', 12, ANALOG)>, /* LTDC_B1 */
-					 <STM32_PINMUX('G', 13, ANALOG)>; /* LTDC_R0 */
-		};
-	};
-
-	quadspi_pins_mx: quadspi_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 6, AF10)>, /* QUADSPI_BK1_NCS */
-					 <STM32_PINMUX('C', 0, AF10)>; /* QUADSPI_BK2_NCS */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('E', 7, AF10)>, /* QUADSPI_BK2_IO0 */
-					 <STM32_PINMUX('E', 8, AF10)>, /* QUADSPI_BK2_IO1 */
-					 <STM32_PINMUX('E', 9, AF10)>, /* QUADSPI_BK2_IO2 */
-					 <STM32_PINMUX('E', 10, AF10)>, /* QUADSPI_BK2_IO3 */
-					 <STM32_PINMUX('F', 6, AF9)>, /* QUADSPI_BK1_IO3 */
-					 <STM32_PINMUX('F', 7, AF9)>, /* QUADSPI_BK1_IO2 */
-					 <STM32_PINMUX('F', 8, AF10)>, /* QUADSPI_BK1_IO0 */
-					 <STM32_PINMUX('F', 9, AF10)>; /* QUADSPI_BK1_IO1 */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins3 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('F', 10, AF9)>; /* QUADSPI_CLK */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <2>;
-		};
-	};
-
-	quadspi_sleep_pins_mx: quadspi_sleep_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 6, ANALOG)>, /* QUADSPI_BK1_NCS */
-					 <STM32_PINMUX('C', 0, ANALOG)>, /* QUADSPI_BK2_NCS */
-					 <STM32_PINMUX('E', 7, ANALOG)>, /* QUADSPI_BK2_IO0 */
-					 <STM32_PINMUX('E', 8, ANALOG)>, /* QUADSPI_BK2_IO1 */
-					 <STM32_PINMUX('E', 9, ANALOG)>, /* QUADSPI_BK2_IO2 */
-					 <STM32_PINMUX('E', 10, ANALOG)>, /* QUADSPI_BK2_IO3 */
-					 <STM32_PINMUX('F', 6, ANALOG)>, /* QUADSPI_BK1_IO3 */
-					 <STM32_PINMUX('F', 7, ANALOG)>, /* QUADSPI_BK1_IO2 */
-					 <STM32_PINMUX('F', 8, ANALOG)>, /* QUADSPI_BK1_IO0 */
-					 <STM32_PINMUX('F', 9, ANALOG)>, /* QUADSPI_BK1_IO1 */
-					 <STM32_PINMUX('F', 10, ANALOG)>; /* QUADSPI_CLK */
-		};
-	};
-
-	rtc_pins_mx: rtc_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('C', 13, ANALOG)>; /* RTC_LSCO */
-		};
-	};
-
-	rtc_sleep_pins_mx: rtc_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('C', 13, ANALOG)>; /* RTC_LSCO */
-		};
-	};
-
-	sdmmc1_pins_mx: sdmmc1_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
-					 <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
-					 <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
-					 <STM32_PINMUX('C', 11, AF12)>, /* SDMMC1_D3 */
-					 <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 12, AF12)>; /* SDMMC1_CK */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-	};
-
-	sdmmc1_opendrain_pins_mx: sdmmc1_opendrain_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
-					 <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
-					 <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
-					 <STM32_PINMUX('C', 11, AF12)>; /* SDMMC1_D3 */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 12, AF12)>; /* SDMMC1_CK */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins3 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
-			bias-pull-up;
-			drive-open-drain;
-			slew-rate = <1>;
-		};
-	};
-
-	sdmmc1_sleep_pins_mx: sdmmc1_sleep_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 8, ANALOG)>, /* SDMMC1_D0 */
-					 <STM32_PINMUX('C', 9, ANALOG)>, /* SDMMC1_D1 */
-					 <STM32_PINMUX('C', 10, ANALOG)>, /* SDMMC1_D2 */
-					 <STM32_PINMUX('C', 11, ANALOG)>, /* SDMMC1_D3 */
-					 <STM32_PINMUX('C', 12, ANALOG)>, /* SDMMC1_CK */
-					 <STM32_PINMUX('D', 2, ANALOG)>; /* SDMMC1_CMD */
-		};
-	};
-
-	sdmmc2_pins_mx: sdmmc2_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 3, AF9)>, /* SDMMC2_D2 */
-					 <STM32_PINMUX('B', 4, AF9)>, /* SDMMC2_D3 */
-					 <STM32_PINMUX('B', 14, AF9)>, /* SDMMC2_D0 */
-					 <STM32_PINMUX('B', 15, AF9)>, /* SDMMC2_D1 */
-					 <STM32_PINMUX('G', 6, AF10)>; /* SDMMC2_CMD */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('E', 3, AF9)>; /* SDMMC2_CK */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-	};
-
-	sdmmc2_opendrain_pins_mx: sdmmc2_opendrain_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 3, AF9)>, /* SDMMC2_D2 */
-					 <STM32_PINMUX('B', 4, AF9)>, /* SDMMC2_D3 */
-					 <STM32_PINMUX('B', 14, AF9)>, /* SDMMC2_D0 */
-					 <STM32_PINMUX('B', 15, AF9)>; /* SDMMC2_D1 */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('E', 3, AF9)>; /* SDMMC2_CK */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins3 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('G', 6, AF10)>; /* SDMMC2_CMD */
-			bias-pull-up;
-			drive-open-drain;
-			slew-rate = <1>;
-		};
-	};
-
-	sdmmc2_sleep_pins_mx: sdmmc2_sleep_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 3, ANALOG)>, /* SDMMC2_D2 */
-					 <STM32_PINMUX('B', 4, ANALOG)>, /* SDMMC2_D3 */
-					 <STM32_PINMUX('B', 14, ANALOG)>, /* SDMMC2_D0 */
-					 <STM32_PINMUX('B', 15, ANALOG)>, /* SDMMC2_D1 */
-					 <STM32_PINMUX('E', 3, ANALOG)>, /* SDMMC2_CK */
-					 <STM32_PINMUX('G', 6, ANALOG)>; /* SDMMC2_CMD */
-		};
-	};
-
-	tim1_pwm_pins_mx: tim1_pwm_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 9, AF1)>; /* TIM1_CH2 */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-	};
-
-	tim1_pwm_sleep_pins_mx: tim1_pwm_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 9, ANALOG)>; /* TIM1_CH2 */
-		};
-	};
-
-	tim4_pwm_pins_mx: tim4_pwm_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('D', 14, AF2)>; /* TIM4_CH3 */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-	};
-
-	tim4_pwm_sleep_pins_mx: tim4_pwm_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('D', 14, ANALOG)>; /* TIM4_CH3 */
-		};
-	};
-
-	uart4_pins_mx: uart4_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 2, AF8)>; /* UART4_RX */
-			bias-pull-up;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('G', 11, AF6)>; /* UART4_TX */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-	};
-
-	uart4_sleep_pins_mx: uart4_sleep_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 2, ANALOG)>, /* UART4_RX */
-					 <STM32_PINMUX('G', 11, ANALOG)>; /* UART4_TX */
-		};
-	};
-
-	usart2_pins_mx: usart2_mx-0 {
-		pins1 {
-			pinmux = <STM32_PINMUX('D', 4, AF7)>; /* USART2_RTS */
-			bias-pull-down;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-		pins2 {
-			pinmux = <STM32_PINMUX('D', 5, AF7)>; /* USART2_TX */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-		pins3 {
-			pinmux = <STM32_PINMUX('D', 6, AF7)>; /* USART2_RX */
-			bias-pull-up;
-		};
-	};
-
-	usart2_sleep_pins_mx: usart2_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('D', 4, ANALOG)>, /* USART2_RTS */
-					 <STM32_PINMUX('D', 5, ANALOG)>, /* USART2_TX */
-					 <STM32_PINMUX('D', 6, ANALOG)>; /* USART2_RX */
-		};
-	};
-
-	usart3_pins_mx: usart3_mx-0 {
-		pins1 {
-			pinmux = <STM32_PINMUX('D', 9, AF7)>, /* USART3_RX */
-					 <STM32_PINMUX('D', 11, AF7)>; /* USART3_CTS */
-			bias-disable;
-		};
-		pins2 {
-			pinmux = <STM32_PINMUX('D', 8, AF7)>, /* USART3_TX */
-					 <STM32_PINMUX('D', 12, AF7)>; /* USART3_RTS */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-	};
-
-	usart3_sleep_pins_mx: usart3_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('D', 8, ANALOG)>, /* USART3_TX */
-					 <STM32_PINMUX('D', 9, ANALOG)>, /* USART3_RX */
-					 <STM32_PINMUX('D', 11, ANALOG)>, /* USART3_CTS */
-					 <STM32_PINMUX('D', 12, ANALOG)>; /* USART3_RTS */
-		};
-	};
-
-	usb_otg_hs_pins_mx: usb_otg_hs_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
-		};
-	};
-
-	usb_otg_hs_sleep_pins_mx: usb_otg_hs_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
-		};
-	};
-
-	/* USER CODE BEGIN pinctrl */
-	/* USER CODE END pinctrl */
-};
-
-&pinctrl_z {
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN pinctrl_z */
-	/* USER CODE END pinctrl_z */
-};
-
-&m4_rproc{
-	mboxes = <&ipcc 0>, <&ipcc 1>, <&ipcc 2>;
-	mbox-names = "vq0", "vq1", "shutdown";
-	recovery;
-	status = "okay";
-
-	/* USER CODE BEGIN m4_rproc */
-	/* USER CODE END m4_rproc */
-};
-
-&adc{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&adc_pins_mx>;
-	pinctrl-1 = <&adc_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN adc */
-	/* USER CODE END adc */
-};
-
-&bsec{
-	status = "okay";
-
-	/* USER CODE BEGIN bsec */
-	/* USER CODE END bsec */
-};
-
-&crc1{
-	status = "okay";
-
-	/* USER CODE BEGIN crc1 */
-	/* USER CODE END crc1 */
-};
-
-&cryp1{
-	status = "okay";
-
-	/* USER CODE BEGIN cryp1 */
-	/* USER CODE END cryp1 */
-};
-
-&dts{
-	status = "okay";
-
-	/* USER CODE BEGIN dts */
-	/* USER CODE END dts */
-};
-
-&ethernet0{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&eth1_pins_mx>;
-	pinctrl-1 = <&eth1_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN ethernet0 */
-	/* USER CODE END ethernet0 */
-};
-
-&gpu{
-	status = "okay";
-
-	/* USER CODE BEGIN gpu */
-	/* USER CODE END gpu */
-};
-
-&hash1{
-	status = "okay";
-
-	/* USER CODE BEGIN hash1 */
-	/* USER CODE END hash1 */
-};
-
-&hsem{
-	status = "okay";
-
-	/* USER CODE BEGIN hsem */
-	/* USER CODE END hsem */
-};
-
-&i2c2{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&i2c2_pins_mx>;
-	pinctrl-1 = <&i2c2_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN i2c2 */
-	/* USER CODE END i2c2 */
-};
-
-&i2c4{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&i2c4_pins_mx>;
-	pinctrl-1 = <&i2c4_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN i2c4 */
-	/* USER CODE END i2c4 */
-};
-
-&ipcc{
-	status = "okay";
-
-	/* USER CODE BEGIN ipcc */
-	/* USER CODE END ipcc */
-};
-
-&ltdc{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&ltdc_pins_mx>;
-	pinctrl-1 = <&ltdc_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN ltdc */
-	/* USER CODE END ltdc */
-};
-
-&m_can1{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&fdcan1_pins_mx>;
-	pinctrl-1 = <&fdcan1_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN m_can1 */
-	/* USER CODE END m_can1 */
-};
-
-&qspi{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&quadspi_pins_mx>;
-	pinctrl-1 = <&quadspi_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN qspi */
-	/* USER CODE END qspi */
-};
-
-&rcc{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN rcc */
-	/* USER CODE END rcc */
-};
-
-&rng1{
-	status = "okay";
-
-	/* USER CODE BEGIN rng1 */
-	/* USER CODE END rng1 */
-};
-
-&rtc{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&rtc_pins_mx>;
-	pinctrl-1 = <&rtc_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN rtc */
-	/* USER CODE END rtc */
-};
-
-&sdmmc1{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "opendrain", "sleep";
-	pinctrl-0 = <&sdmmc1_pins_mx>;
-	pinctrl-1 = <&sdmmc1_opendrain_pins_mx>;
-	pinctrl-2 = <&sdmmc1_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN sdmmc1 */
-	/* USER CODE END sdmmc1 */
-};
-
-&sdmmc2{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "opendrain", "sleep";
-	pinctrl-0 = <&sdmmc2_pins_mx>;
-	pinctrl-1 = <&sdmmc2_opendrain_pins_mx>;
-	pinctrl-2 = <&sdmmc2_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN sdmmc2 */
-	/* USER CODE END sdmmc2 */
-};
-
-&timers1{
-	status = "okay";
-
-	/* USER CODE BEGIN timers1 */
-	/* USER CODE END timers1 */
-
-	pwm{
-		pinctrl-names = "default", "sleep";
-		pinctrl-0 = <&tim1_pwm_pins_mx>;
-		pinctrl-1 = <&tim1_pwm_sleep_pins_mx>;
-		status = "okay";
-
-		/* USER CODE BEGIN timers1_pwm */
-		/* USER CODE END timers1_pwm */
-	};
-};
-
-&timers4{
-	status = "okay";
-
-	/* USER CODE BEGIN timers4 */
-	/* USER CODE END timers4 */
-
-	pwm{
-		pinctrl-names = "default", "sleep";
-		pinctrl-0 = <&tim4_pwm_pins_mx>;
-		pinctrl-1 = <&tim4_pwm_sleep_pins_mx>;
-		status = "okay";
-
-		/* USER CODE BEGIN timers4_pwm */
-		/* USER CODE END timers4_pwm */
-	};
-};
-
-&uart4{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&uart4_pins_mx>;
-	pinctrl-1 = <&uart4_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN uart4 */
-	/* USER CODE END uart4 */
-};
-
-&usart2{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&usart2_pins_mx>;
-	pinctrl-1 = <&usart2_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN usart2 */
-	/* USER CODE END usart2 */
-};
-
-&usart3{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&usart3_pins_mx>;
-	pinctrl-1 = <&usart3_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN usart3 */
-	/* USER CODE END usart3 */
-};
-
-&usbh_ehci{
-	status = "okay";
-
-	/* USER CODE BEGIN usbh_ehci */
-	/* USER CODE END usbh_ehci */
-};
-
-&usbh_ohci{
-	status = "okay";
-
-	/* USER CODE BEGIN usbh_ohci */
-	/* USER CODE END usbh_ohci */
-};
-
-&usbotg_hs{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&usb_otg_hs_pins_mx>;
-	pinctrl-1 = <&usb_otg_hs_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN usbotg_hs */
-	/* USER CODE END usbotg_hs */
-};
-
-&usbphyc{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc */
-	/* USER CODE END usbphyc */
-};
-
-&usbphyc_port0{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc_port0 */
-	/* USER CODE END usbphyc_port0 */
-};
-
-&usbphyc_port1{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc_port1 */
-	/* USER CODE END usbphyc_port1 */
-};
-
-&vrefbuf{
-	status = "okay";
-
-	/* USER CODE BEGIN vrefbuf */
-	/* USER CODE END vrefbuf */
-};
-
-/* USER CODE BEGIN addons */
-/* USER CODE END addons */
-
diff --git a/conf/machine/cubemx/t1000-k/t1000-k.ioc b/conf/machine/cubemx/t1000-k/t1000-k.ioc
deleted file mode 100644
index 97b0d88e9c36106db22ea4507c242d66abd109c6..0000000000000000000000000000000000000000
--- a/conf/machine/cubemx/t1000-k/t1000-k.ioc
+++ /dev/null
@@ -1,1470 +0,0 @@
-#MicroXplorer Configuration settings - do not modify
-ADC1.Channel-0\#ChannelRegularConversion=ADC_CHANNEL_5
-ADC1.IPParameters=Rank-0\#ChannelRegularConversion,Channel-0\#ChannelRegularConversion,SamplingTime-0\#ChannelRegularConversion,OffsetNumber-0\#ChannelRegularConversion,NbrOfConversionFlag,master
-ADC1.NbrOfConversionFlag=1
-ADC1.OffsetNumber-0\#ChannelRegularConversion=ADC_OFFSET_NONE
-ADC1.Rank-0\#ChannelRegularConversion=1
-ADC1.SamplingTime-0\#ChannelRegularConversion=ADC_SAMPLETIME_1CYCLE_5
-ADC1.master=1
-BootLoader.IPs=RCC,QUADSPI,SDMMC1,SDMMC2,UART4,USB_OTG_HS
-BootROM.IPs=RCC,SDMMC1\:I,UART4\:I
-CortexA7NS.IPs=BSEC,DDR\:I,ETZPC,HSEM\:I,IPCC\:I,PWR,RCC\:I,RTC,TAMP\:I,DMA\:I,GIC,ADC1\:I,ADC2\:I,TIM4\:I,ETH1\:I,FDCAN1\:I,I2C2\:I,I2C4\:I,QUADSPI\:I,SDMMC1,SDMMC2\:I,UART4,USART2\:I,USBH_HS1\:I,USB_OTG_HS\:I,LTDC\:I,GPU\:I,TIM1\:I,CRYP1\:I,HASH1\:I,RNG1,SPI2\:I,CRC1\:I,DEBUG\:I,DTS\:I,VREFBUF\:I,DMA1\:I,MDMA_A7NS\:I,USART3\:I
-CortexA7S.IPs=BSEC\:I,ETZPC\:I,PWR\:I,RCC,RNG1\:I,RTC\:I,GIC\:I,MDMA_A7S\:I
-CortexM4.IPs=HSEM,IPCC,ETZPC,FREERTOS\:I,PWR,RCC,SYS\:I,DMA,NVIC\:I,DMA2\:I
-DDR.0dqdly0=1
-DDR.0dqdly1=0
-DDR.0dqdly2=0
-DDR.0dqdly3=0
-DDR.0dqdly4=1
-DDR.0dqdly5=0
-DDR.0dqdly6=1
-DDR.0dqdly7=1
-DDR.0dqsdly=2
-DDR.0dqsndly=2
-DDR.1dqdly0=0
-DDR.1dqdly1=0
-DDR.1dqdly2=1
-DDR.1dqdly3=0
-DDR.1dqdly4=1
-DDR.1dqdly5=0
-DDR.1dqdly6=0
-DDR.1dqdly7=0
-DDR.ADDRMAP1=0x00070707
-DDR.ADDRMAP3=0x1F000000
-DDR.ADDRMAP5=0x06060606
-DDR.ADDRMAP6=0x0F060606
-DDR.CL=7
-DDR.DDR_Frequency=528.0
-DDR.DFITMG0=0x02050105
-DDR.DRAMTMG0=0x121B1214
-DDR.DRAMTMG1=0x000A041B
-DDR.DRAMTMG2=0x0607080F
-DDR.DRAMTMG4=0x07040607
-DDR.DTPR0=0x36D477D0
-DDR.DTPR1=0x098A00D8
-DDR.DX0DQSTR=0x3D202000
-DDR.DX0DQTR=0x55050005
-DDR.DX1DQTR=0x00050500
-DDR.IPParameters=DDR_Frequency,CL,addrmap_col_b9,addrmap_col_b10,addrmap_col_b11,addrmap_bank_b0,addrmap_bank_b1,addrmap_bank_b2,addrmap_row_b0,addrmap_row_b1,addrmap_row_b2_10,addrmap_row_b11,addrmap_row_b12,addrmap_row_b13,addrmap_row_b14,addrmap_row_b15,MSTR,RFSHTMG,DRAMTMG1,DRAMTMG2,DRAMTMG4,SCHED,ADDRMAP1,ADDRMAP3,ADDRMAP5,ADDRMAP6,PTR0,PTR1,PTR2,DTPR0,DTPR1,MR0,SPEED_BIN_GRADE,tRCD,tRP,tRC,wr2pre,t_faw,t_ras_max,t_ras_min,t_xp,t_rd2pre,t_rp,t_rc,write_latency,read_latency,wr2rd,t_rcd,t_rrd,t_cksrx,t_cksre,t_ckesr,t_cke,t_xs_dll_x32,t_xs_x32,t_rfc_nom_x1_x32,t_rfc_min,dfi_t_rddata_en,dfi_tphy_wrlat,tdlllock,tdllsrst,tdinit1,tdinit0,tdinit2,tccd,trc,trrd,tras,trcd,trp,twtr,trtp,tmrd,trfc,tmod,tfaw,tdllk,tcke,txp,txs,MR0.WR,MR0.CL,MR2.RTT,MR2.CWL,data_bus_width,DFITMG0,TEMPERATURE_OVER_85C,tREFI,DRAMTMG0,MR2,0dqsndly,0dqsdly,0dqdly0,0dqdly1,0dqdly2,0dqdly3,0dqdly4,0dqdly5,0dqdly6,0dqdly7,1dqdly0,1dqdly1,1dqdly2,1dqdly3,1dqdly4,1dqdly5,1dqdly6,1dqdly7,DX0DQTR,DX0DQSTR,DX1DQTR
-DDR.MR0=0x00000830
-DDR.MR0.CL=3
-DDR.MR0.WR=4
-DDR.MR2=0x00000248
-DDR.MR2.CWL=1
-DDR.MR2.RTT=1
-DDR.MSTR=0x00041401
-DDR.PTR0=0x0022A41B
-DDR.PTR1=0x047C0740
-DDR.PTR2=0x042D9C80
-DDR.RFSHTMG=0x0040008A
-DDR.SCHED=0x00000C01
-DDR.SPEED_BIN_GRADE=SPEED BIN GRADE CONFIG1
-DDR.TEMPERATURE_OVER_85C=true
-DDR.addrmap_bank_b0=7
-DDR.addrmap_bank_b1=7
-DDR.addrmap_bank_b2=7
-DDR.addrmap_col_b10=31
-DDR.addrmap_col_b11=31
-DDR.addrmap_col_b9=31
-DDR.addrmap_row_b0=6
-DDR.addrmap_row_b1=6
-DDR.addrmap_row_b11=6
-DDR.addrmap_row_b12=6
-DDR.addrmap_row_b13=6
-DDR.addrmap_row_b14=6
-DDR.addrmap_row_b15=15
-DDR.addrmap_row_b2_10=6
-DDR.data_bus_width=1
-DDR.dfi_t_rddata_en=5
-DDR.dfi_tphy_wrlat=5
-DDR.read_latency=7
-DDR.tRC=50.625
-DDR.tRCD=13.125
-DDR.tREFI=3.9
-DDR.tRP=13.125
-DDR.t_cke=3
-DDR.t_ckesr=4
-DDR.t_cksre=6
-DDR.t_cksrx=6
-DDR.t_faw=27
-DDR.t_ras_max=18
-DDR.t_ras_min=20
-DDR.t_rc=27
-DDR.t_rcd=7
-DDR.t_rd2pre=4
-DDR.t_rfc_min=138
-DDR.t_rfc_nom_x1_x32=64
-DDR.t_rp=7
-DDR.t_rrd=6
-DDR.t_xp=10
-DDR.t_xs_dll_x32=16
-DDR.t_xs_x32=5
-DDR.tccd=0
-DDR.tcke=4
-DDR.tdinit0=264000
-DDR.tdinit1=143
-DDR.tdinit2=105600
-DDR.tdllk=512
-DDR.tdlllock=2704
-DDR.tdllsrst=27
-DDR.tfaw=27
-DDR.tmod=0
-DDR.tmrd=0
-DDR.tras=20
-DDR.trc=27
-DDR.trcd=7
-DDR.trfc=138
-DDR.trp=7
-DDR.trrd=6
-DDR.trtp=4
-DDR.twtr=6
-DDR.txp=13
-DDR.txs=512
-DDR.wr2pre=18
-DDR.wr2rd=15
-DDR.write_latency=6
-DDR_A0.GPIOParameters=GPIO_Label
-DDR_A0.GPIO_Label=DDR Memory
-DDR_A0.Locked=true
-DDR_A0.Mode=DDR3
-DDR_A0.Signal=DDR_A0
-DDR_A1.GPIOParameters=GPIO_Label
-DDR_A1.GPIO_Label=DDR Memory
-DDR_A1.Locked=true
-DDR_A1.Mode=DDR3
-DDR_A1.Signal=DDR_A1
-DDR_A10.GPIOParameters=GPIO_Label
-DDR_A10.GPIO_Label=DDR Memory
-DDR_A10.Locked=true
-DDR_A10.Mode=DDR3
-DDR_A10.Signal=DDR_A10
-DDR_A11.GPIOParameters=GPIO_Label
-DDR_A11.GPIO_Label=DDR Memory
-DDR_A11.Locked=true
-DDR_A11.Mode=DDR3
-DDR_A11.Signal=DDR_A11
-DDR_A12.GPIOParameters=GPIO_Label
-DDR_A12.GPIO_Label=DDR Memory
-DDR_A12.Locked=true
-DDR_A12.Mode=4Gb_16bits
-DDR_A12.Signal=DDR_A12
-DDR_A13.GPIOParameters=GPIO_Label
-DDR_A13.GPIO_Label=DDR Memory
-DDR_A13.Locked=true
-DDR_A13.Mode=4Gb_16bits
-DDR_A13.Signal=DDR_A13
-DDR_A14.GPIOParameters=GPIO_Label
-DDR_A14.GPIO_Label=DDR Memory
-DDR_A14.Locked=true
-DDR_A14.Mode=4Gb_16bits
-DDR_A14.Signal=DDR_A14
-DDR_A2.GPIOParameters=GPIO_Label
-DDR_A2.GPIO_Label=DDR Memory
-DDR_A2.Locked=true
-DDR_A2.Mode=DDR3
-DDR_A2.Signal=DDR_A2
-DDR_A3.GPIOParameters=GPIO_Label
-DDR_A3.GPIO_Label=DDR Memory
-DDR_A3.Locked=true
-DDR_A3.Mode=DDR3
-DDR_A3.Signal=DDR_A3
-DDR_A4.GPIOParameters=GPIO_Label
-DDR_A4.GPIO_Label=DDR Memory
-DDR_A4.Locked=true
-DDR_A4.Mode=DDR3
-DDR_A4.Signal=DDR_A4
-DDR_A5.GPIOParameters=GPIO_Label
-DDR_A5.GPIO_Label=DDR Memory
-DDR_A5.Locked=true
-DDR_A5.Mode=DDR3
-DDR_A5.Signal=DDR_A5
-DDR_A6.GPIOParameters=GPIO_Label
-DDR_A6.GPIO_Label=DDR Memory
-DDR_A6.Locked=true
-DDR_A6.Mode=DDR3
-DDR_A6.Signal=DDR_A6
-DDR_A7.GPIOParameters=GPIO_Label
-DDR_A7.GPIO_Label=DDR Memory
-DDR_A7.Locked=true
-DDR_A7.Mode=DDR3
-DDR_A7.Signal=DDR_A7
-DDR_A8.GPIOParameters=GPIO_Label
-DDR_A8.GPIO_Label=DDR Memory
-DDR_A8.Locked=true
-DDR_A8.Mode=DDR3
-DDR_A8.Signal=DDR_A8
-DDR_A9.GPIOParameters=GPIO_Label
-DDR_A9.GPIO_Label=DDR Memory
-DDR_A9.Locked=true
-DDR_A9.Mode=DDR3
-DDR_A9.Signal=DDR_A9
-DDR_ATO.GPIOParameters=GPIO_Label
-DDR_ATO.GPIO_Label=DDR Memory
-DDR_ATO.Locked=true
-DDR_ATO.Mode=DDR3
-DDR_ATO.Signal=DDR_ATO
-DDR_BA0.GPIOParameters=GPIO_Label
-DDR_BA0.GPIO_Label=DDR Memory
-DDR_BA0.Locked=true
-DDR_BA0.Mode=DDR3
-DDR_BA0.Signal=DDR_BA0
-DDR_BA1.GPIOParameters=GPIO_Label
-DDR_BA1.GPIO_Label=DDR Memory
-DDR_BA1.Locked=true
-DDR_BA1.Mode=DDR3
-DDR_BA1.Signal=DDR_BA1
-DDR_BA2.GPIOParameters=GPIO_Label
-DDR_BA2.GPIO_Label=DDR Memory
-DDR_BA2.Locked=true
-DDR_BA2.Mode=DDR3
-DDR_BA2.Signal=DDR_BA2
-DDR_CASN.GPIOParameters=GPIO_Label
-DDR_CASN.GPIO_Label=DDR Memory
-DDR_CASN.Locked=true
-DDR_CASN.Mode=DDR3
-DDR_CASN.Signal=DDR_CASN
-DDR_CKE.GPIOParameters=GPIO_Label
-DDR_CKE.GPIO_Label=DDR Memory
-DDR_CKE.Locked=true
-DDR_CKE.Mode=DDR3
-DDR_CKE.Signal=DDR_CKE
-DDR_CLKN.GPIOParameters=GPIO_Label
-DDR_CLKN.GPIO_Label=DDR Memory
-DDR_CLKN.Locked=true
-DDR_CLKN.Mode=DDR3
-DDR_CLKN.Signal=DDR_CLKN
-DDR_CLKP.GPIOParameters=GPIO_Label
-DDR_CLKP.GPIO_Label=DDR Memory
-DDR_CLKP.Locked=true
-DDR_CLKP.Mode=DDR3
-DDR_CLKP.Signal=DDR_CLKP
-DDR_CSN.GPIOParameters=GPIO_Label
-DDR_CSN.GPIO_Label=DDR Memory
-DDR_CSN.Locked=true
-DDR_CSN.Mode=DDR3
-DDR_CSN.Signal=DDR_CSN
-DDR_DQ0.GPIOParameters=GPIO_Label
-DDR_DQ0.GPIO_Label=DDR Memory
-DDR_DQ0.Locked=true
-DDR_DQ0.Mode=DDR3
-DDR_DQ0.Signal=DDR_DQ0
-DDR_DQ1.GPIOParameters=GPIO_Label
-DDR_DQ1.GPIO_Label=DDR Memory
-DDR_DQ1.Locked=true
-DDR_DQ1.Mode=DDR3
-DDR_DQ1.Signal=DDR_DQ1
-DDR_DQ10.GPIOParameters=GPIO_Label
-DDR_DQ10.GPIO_Label=DDR Memory
-DDR_DQ10.Locked=true
-DDR_DQ10.Mode=DDR3
-DDR_DQ10.Signal=DDR_DQ10
-DDR_DQ11.GPIOParameters=GPIO_Label
-DDR_DQ11.GPIO_Label=DDR Memory
-DDR_DQ11.Locked=true
-DDR_DQ11.Mode=DDR3
-DDR_DQ11.Signal=DDR_DQ11
-DDR_DQ12.GPIOParameters=GPIO_Label
-DDR_DQ12.GPIO_Label=DDR Memory
-DDR_DQ12.Locked=true
-DDR_DQ12.Mode=DDR3
-DDR_DQ12.Signal=DDR_DQ12
-DDR_DQ13.GPIOParameters=GPIO_Label
-DDR_DQ13.GPIO_Label=DDR Memory
-DDR_DQ13.Locked=true
-DDR_DQ13.Mode=DDR3
-DDR_DQ13.Signal=DDR_DQ13
-DDR_DQ14.GPIOParameters=GPIO_Label
-DDR_DQ14.GPIO_Label=DDR Memory
-DDR_DQ14.Locked=true
-DDR_DQ14.Mode=DDR3
-DDR_DQ14.Signal=DDR_DQ14
-DDR_DQ15.GPIOParameters=GPIO_Label
-DDR_DQ15.GPIO_Label=DDR Memory
-DDR_DQ15.Locked=true
-DDR_DQ15.Mode=DDR3
-DDR_DQ15.Signal=DDR_DQ15
-DDR_DQ2.GPIOParameters=GPIO_Label
-DDR_DQ2.GPIO_Label=DDR Memory
-DDR_DQ2.Locked=true
-DDR_DQ2.Mode=DDR3
-DDR_DQ2.Signal=DDR_DQ2
-DDR_DQ3.GPIOParameters=GPIO_Label
-DDR_DQ3.GPIO_Label=DDR Memory
-DDR_DQ3.Locked=true
-DDR_DQ3.Mode=DDR3
-DDR_DQ3.Signal=DDR_DQ3
-DDR_DQ4.GPIOParameters=GPIO_Label
-DDR_DQ4.GPIO_Label=DDR Memory
-DDR_DQ4.Locked=true
-DDR_DQ4.Mode=DDR3
-DDR_DQ4.Signal=DDR_DQ4
-DDR_DQ5.GPIOParameters=GPIO_Label
-DDR_DQ5.GPIO_Label=DDR Memory
-DDR_DQ5.Locked=true
-DDR_DQ5.Mode=DDR3
-DDR_DQ5.Signal=DDR_DQ5
-DDR_DQ6.GPIOParameters=GPIO_Label
-DDR_DQ6.GPIO_Label=DDR Memory
-DDR_DQ6.Locked=true
-DDR_DQ6.Mode=DDR3
-DDR_DQ6.Signal=DDR_DQ6
-DDR_DQ7.GPIOParameters=GPIO_Label
-DDR_DQ7.GPIO_Label=DDR Memory
-DDR_DQ7.Locked=true
-DDR_DQ7.Mode=DDR3
-DDR_DQ7.Signal=DDR_DQ7
-DDR_DQ8.GPIOParameters=GPIO_Label
-DDR_DQ8.GPIO_Label=DDR Memory
-DDR_DQ8.Locked=true
-DDR_DQ8.Mode=DDR3
-DDR_DQ8.Signal=DDR_DQ8
-DDR_DQ9.GPIOParameters=GPIO_Label
-DDR_DQ9.GPIO_Label=DDR Memory
-DDR_DQ9.Locked=true
-DDR_DQ9.Mode=DDR3
-DDR_DQ9.Signal=DDR_DQ9
-DDR_DQM0.GPIOParameters=GPIO_Label
-DDR_DQM0.GPIO_Label=DDR Memory
-DDR_DQM0.Locked=true
-DDR_DQM0.Mode=DDR3
-DDR_DQM0.Signal=DDR_DQM0
-DDR_DQM1.GPIOParameters=GPIO_Label
-DDR_DQM1.GPIO_Label=DDR Memory
-DDR_DQM1.Locked=true
-DDR_DQM1.Mode=DDR3
-DDR_DQM1.Signal=DDR_DQM1
-DDR_DQS0N.GPIOParameters=GPIO_Label
-DDR_DQS0N.GPIO_Label=DDR Memory
-DDR_DQS0N.Locked=true
-DDR_DQS0N.Mode=DDR3
-DDR_DQS0N.Signal=DDR_DQS0N
-DDR_DQS0P.GPIOParameters=GPIO_Label
-DDR_DQS0P.GPIO_Label=DDR Memory
-DDR_DQS0P.Locked=true
-DDR_DQS0P.Mode=DDR3
-DDR_DQS0P.Signal=DDR_DQS0P
-DDR_DQS1N.GPIOParameters=GPIO_Label
-DDR_DQS1N.GPIO_Label=DDR Memory
-DDR_DQS1N.Locked=true
-DDR_DQS1N.Mode=DDR3
-DDR_DQS1N.Signal=DDR_DQS1N
-DDR_DQS1P.GPIOParameters=GPIO_Label
-DDR_DQS1P.GPIO_Label=DDR Memory
-DDR_DQS1P.Locked=true
-DDR_DQS1P.Mode=DDR3
-DDR_DQS1P.Signal=DDR_DQS1P
-DDR_DTO0.GPIOParameters=GPIO_Label
-DDR_DTO0.GPIO_Label=DDR Memory
-DDR_DTO0.Locked=true
-DDR_DTO0.Mode=DDR3
-DDR_DTO0.Signal=DDR_DTO0
-DDR_DTO1.GPIOParameters=GPIO_Label
-DDR_DTO1.GPIO_Label=DDR Memory
-DDR_DTO1.Locked=true
-DDR_DTO1.Mode=DDR3
-DDR_DTO1.Signal=DDR_DTO1
-DDR_ODT.GPIOParameters=GPIO_Label
-DDR_ODT.GPIO_Label=DDR Memory
-DDR_ODT.Locked=true
-DDR_ODT.Mode=DDR3
-DDR_ODT.Signal=DDR_ODT
-DDR_RASN.GPIOParameters=GPIO_Label
-DDR_RASN.GPIO_Label=DDR Memory
-DDR_RASN.Locked=true
-DDR_RASN.Mode=DDR3
-DDR_RASN.Signal=DDR_RASN
-DDR_RESETN.GPIOParameters=GPIO_Label
-DDR_RESETN.GPIO_Label=DDR Memory
-DDR_RESETN.Locked=true
-DDR_RESETN.Mode=DDR3
-DDR_RESETN.Signal=DDR_RESETN
-DDR_VREF.GPIOParameters=GPIO_Label
-DDR_VREF.GPIO_Label=DDR Memory
-DDR_VREF.Locked=true
-DDR_VREF.Mode=DDR3
-DDR_VREF.Signal=DDR_VREF
-DDR_WEN.GPIOParameters=GPIO_Label
-DDR_WEN.GPIO_Label=DDR Memory
-DDR_WEN.Locked=true
-DDR_WEN.Mode=DDR3
-DDR_WEN.Signal=DDR_WEN
-DDR_ZQ.GPIOParameters=GPIO_Label
-DDR_ZQ.GPIO_Label=DDR Memory
-DDR_ZQ.Locked=true
-DDR_ZQ.Mode=DDR3
-DDR_ZQ.Signal=DDR_ZQ
-File.Version=6
-GIC.ADC1_IRQn=true\:false\:High level
-GIC.CRYP1_IRQn=true\:false\:High level
-GIC.DTS_IRQn=true\:false\:High level
-GIC.ETH1_IRQn=true\:false\:High level
-GIC.ETH1_WKUP_IRQn=true\:false\:High level
-GIC.FDCAN1_IT0_IRQn=true\:false\:High level
-GIC.FDCAN1_IT1_IRQn=true\:false\:High level
-GIC.GPU_IRQn=true\:false\:High level
-GIC.HASH1_IRQn=true\:false\:High level
-GIC.I2C2_ER_IRQn=true\:false\:High level
-GIC.I2C2_EV_IRQn=true\:false\:High level
-GIC.I2C4_ER_IRQn=true\:false\:High level
-GIC.I2C4_EV_IRQn=true\:false\:High level
-GIC.IPCC_RX0_IRQn=true\:false\:High level
-GIC.IPCC_TX0_IRQn=true\:false\:High level
-GIC.LTDC_ER_IRQn=true\:false\:High level
-GIC.LTDC_IRQn=true\:false\:High level
-GIC.OTG_IRQn=true\:false\:High level
-GIC.PMUIRQ0_IRQn=true\:false\:High level
-GIC.PMUIRQ1_IRQn=true\:false\:High level
-GIC.QUADSPI_IRQn=true\:false\:High level
-GIC.RCC_IRQn=true\:false\:High level
-GIC.RTC_WKUP_ALARM_IRQn=true\:false\:High level
-GIC.SDMMC1_IRQn=true\:false\:High level
-GIC.SDMMC2_IRQn=true\:false\:High level
-GIC.UART4_IRQn=true\:false\:High level
-GIC.USART2_IRQn=true\:false\:High level
-GIC.USART3_IRQn=true\:false\:High level
-GIC.USBH_OHCI_IRQn=true\:false\:High level
-JTCK-SWCLK.GPIOParameters=GPIO_Label
-JTCK-SWCLK.GPIO_Label=JTAG Debug
-JTCK-SWCLK.Locked=true
-JTCK-SWCLK.Mode=JTAG_4_pins
-JTCK-SWCLK.Signal=DEBUG_JTCK-SWCLK
-JTDI.GPIOParameters=GPIO_Label
-JTDI.GPIO_Label=JTAG Debug
-JTDI.Locked=true
-JTDI.Mode=JTAG_4_pins
-JTDI.Signal=DEBUG_JTDI
-JTDO-TRACESWO.GPIOParameters=GPIO_Label
-JTDO-TRACESWO.GPIO_Label=JTAG Debug
-JTDO-TRACESWO.Locked=true
-JTDO-TRACESWO.Mode=JTAG_4_pins
-JTDO-TRACESWO.Signal=DEBUG_JTDO-SWO
-JTMS-SWDIO.GPIOParameters=GPIO_Label
-JTMS-SWDIO.GPIO_Label=JTAG Debug
-JTMS-SWDIO.Locked=true
-JTMS-SWDIO.Mode=JTAG_4_pins
-JTMS-SWDIO.Signal=DEBUG_JTMS-SWDIO
-KeepUserPlacement=false
-Mcu.Context0=BootROM
-Mcu.Context1=BootLoader
-Mcu.Context2=CortexA7S
-Mcu.Context3=CortexA7NS
-Mcu.Context4=CortexM4
-Mcu.ContextNb=5
-Mcu.Family=STM32MP1
-Mcu.IP0=ADC1
-Mcu.IP1=BSEC
-Mcu.IP10=GIC
-Mcu.IP11=GPU
-Mcu.IP12=HASH1
-Mcu.IP13=HSEM
-Mcu.IP14=I2C2
-Mcu.IP15=I2C4
-Mcu.IP16=IPCC
-Mcu.IP17=LTDC
-Mcu.IP18=NVIC
-Mcu.IP19=QUADSPI
-Mcu.IP2=CRC1
-Mcu.IP20=RCC
-Mcu.IP21=RNG1
-Mcu.IP22=RTC
-Mcu.IP23=SDMMC1
-Mcu.IP24=SDMMC2
-Mcu.IP25=SYS
-Mcu.IP26=TIM1
-Mcu.IP27=TIM4
-Mcu.IP28=UART4
-Mcu.IP29=USART2
-Mcu.IP3=CRYP1
-Mcu.IP30=USART3
-Mcu.IP31=USBH_HS1
-Mcu.IP32=USB_OTG_HS
-Mcu.IP33=VREFBUF
-Mcu.IP4=DDR
-Mcu.IP5=DEBUG
-Mcu.IP6=DTS
-Mcu.IP7=ETH1
-Mcu.IP8=ETZPC
-Mcu.IP9=FDCAN1
-Mcu.IPNb=34
-Mcu.Name=STM32MP157CADx
-Mcu.Package=TFBGA257
-Mcu.Pin0=PD1
-Mcu.Pin1=PB7
-Mcu.Pin10=PG15
-Mcu.Pin100=PD13
-Mcu.Pin101=PD12
-Mcu.Pin102=PA11
-Mcu.Pin103=PA10
-Mcu.Pin104=DDR_DQ14
-Mcu.Pin105=DDR_DQS1N
-Mcu.Pin106=DDR_DQ9
-Mcu.Pin107=PC5
-Mcu.Pin108=PC4
-Mcu.Pin109=PB12
-Mcu.Pin11=PE6
-Mcu.Pin110=PB8
-Mcu.Pin111=PB5
-Mcu.Pin112=PG8
-Mcu.Pin113=PE7
-Mcu.Pin114=PF8
-Mcu.Pin115=PF9
-Mcu.Pin116=USB_DP2
-Mcu.Pin117=PG7
-Mcu.Pin118=PE10
-Mcu.Pin119=PB2
-Mcu.Pin12=PD7
-Mcu.Pin120=USB_DP1
-Mcu.Pin121=PA12
-Mcu.Pin122=DDR_DQ15
-Mcu.Pin123=DDR_DQM1
-Mcu.Pin124=DDR_DQS1P
-Mcu.Pin125=PA7
-Mcu.Pin126=PA6
-Mcu.Pin127=PF11
-Mcu.Pin128=PF7
-Mcu.Pin129=PG9
-Mcu.Pin13=PA15
-Mcu.Pin130=USB_DM2
-Mcu.Pin131=PB6
-Mcu.Pin132=USB_DM1
-Mcu.Pin133=DDR_VREF
-Mcu.Pin134=DDR_DQ12
-Mcu.Pin135=DDR_DQ11
-Mcu.Pin136=PE1
-Mcu.Pin137=PD10
-Mcu.Pin138=PE3
-Mcu.Pin139=PB14
-Mcu.Pin14=PG6
-Mcu.Pin140=PD2
-Mcu.Pin141=DDR_ZQ
-Mcu.Pin142=DDR_A7
-Mcu.Pin143=PD6
-Mcu.Pin144=PE14
-Mcu.Pin145=PC12
-Mcu.Pin146=PD9
-Mcu.Pin147=PD15
-Mcu.Pin148=DDR_DTO1
-Mcu.Pin149=DDR_A5
-Mcu.Pin15=PB4
-Mcu.Pin150=DDR_DTO0
-Mcu.Pin151=PD14
-Mcu.Pin152=DDR_RASN
-Mcu.Pin153=DDR_ATO
-Mcu.Pin154=DDR_A6
-Mcu.Pin155=PA5
-Mcu.Pin156=PA4
-Mcu.Pin157=PB13
-Mcu.Pin158=PE9
-Mcu.Pin159=PF10
-Mcu.Pin16=PE5
-Mcu.Pin160=VP_BSEC_VS_BSEC
-Mcu.Pin161=VP_CRC1_VS_CRC
-Mcu.Pin162=VP_CRYP1_VS_CRYP
-Mcu.Pin163=VP_DDR_DDR3
-Mcu.Pin164=VP_DDR_DDR_16_bits
-Mcu.Pin165=VP_DDR_DDR3_16_4Gb
-Mcu.Pin166=VP_DTS_VS_DTS
-Mcu.Pin167=VP_ETZPC_VS_ETZPC
-Mcu.Pin168=VP_GPU_VS_GPU
-Mcu.Pin169=VP_HASH1_VS_HASH
-Mcu.Pin17=PA8
-Mcu.Pin170=VP_HSEM_VS_HSEM
-Mcu.Pin171=VP_IPCC_VS_IPCC
-Mcu.Pin172=VP_RNG1_VS_RNG
-Mcu.Pin173=VP_RTC_VS_RTC_Activate
-Mcu.Pin174=VP_SYS_VS_Systick
-Mcu.Pin175=VP_VREFBUF_VS_VREFBUF
-Mcu.Pin176=VP_DMA_VS_DMA1_A7NS
-Mcu.Pin177=VP_DMA_VS_DMA2_M4
-Mcu.Pin178=VP_MDMA_VS_MDMA_A7NS_8
-Mcu.Pin18=PC9
-Mcu.Pin19=PC10
-Mcu.Pin2=PC6
-Mcu.Pin20=JTDI
-Mcu.Pin21=DDR_DQ3
-Mcu.Pin22=DDR_DQ7
-Mcu.Pin23=DDR_DQS0N
-Mcu.Pin24=DDR_DQS0P
-Mcu.Pin25=PE12
-Mcu.Pin26=PE0
-Mcu.Pin27=PD4
-Mcu.Pin28=PD5
-Mcu.Pin29=PD0
-Mcu.Pin3=PD3
-Mcu.Pin30=PA9
-Mcu.Pin31=PB3
-Mcu.Pin32=PB15
-Mcu.Pin33=PB9
-Mcu.Pin34=PC7
-Mcu.Pin35=PC11
-Mcu.Pin36=JTMS-SWDIO
-Mcu.Pin37=DDR_RESETN
-Mcu.Pin38=DDR_DQM0
-Mcu.Pin39=DDR_DQ2
-Mcu.Pin4=PC8
-Mcu.Pin40=DDR_DQ6
-Mcu.Pin41=PG12
-Mcu.Pin42=PE11
-Mcu.Pin43=PE15
-Mcu.Pin44=DDR_DQ4
-Mcu.Pin45=DDR_DQ5
-Mcu.Pin46=PD8
-Mcu.Pin47=PE13
-Mcu.Pin48=DDR_A13
-Mcu.Pin49=DDR_A9
-Mcu.Pin5=PE4
-Mcu.Pin50=PC15-OSC32_OUT
-Mcu.Pin51=DDR_A2
-Mcu.Pin52=DDR_A3
-Mcu.Pin53=PC14-OSC32_IN
-Mcu.Pin54=PC13
-Mcu.Pin55=DDR_A0
-Mcu.Pin56=DDR_BA0
-Mcu.Pin57=PH0-OSC_IN
-Mcu.Pin58=DDR_BA2
-Mcu.Pin59=DDR_ODT
-Mcu.Pin6=JTDO-TRACESWO
-Mcu.Pin60=PH1-OSC_OUT
-Mcu.Pin61=DDR_CSN
-Mcu.Pin62=DDR_WEN
-Mcu.Pin63=DDR_CASN
-Mcu.Pin64=DDR_CLKN
-Mcu.Pin65=PA14
-Mcu.Pin66=PA13
-Mcu.Pin67=DDR_CLKP
-Mcu.Pin68=DDR_A10
-Mcu.Pin69=DDR_A12
-Mcu.Pin7=JTCK-SWCLK
-Mcu.Pin70=DDR_A1
-Mcu.Pin71=PA3
-Mcu.Pin72=PA0
-Mcu.Pin73=DDR_A14
-Mcu.Pin74=DDR_A11
-Mcu.Pin75=PE2
-Mcu.Pin76=PC2
-Mcu.Pin77=PC3
-Mcu.Pin78=DDR_CKE
-Mcu.Pin79=DDR_BA1
-Mcu.Pin8=DDR_DQ0
-Mcu.Pin80=PG14
-Mcu.Pin81=PG13
-Mcu.Pin82=DDR_A4
-Mcu.Pin83=DDR_DQ8
-Mcu.Pin84=PA1
-Mcu.Pin85=PC1
-Mcu.Pin86=PA2
-Mcu.Pin87=DDR_A8
-Mcu.Pin88=DDR_DQ13
-Mcu.Pin89=DDR_DQ10
-Mcu.Pin9=DDR_DQ1
-Mcu.Pin90=PB1
-Mcu.Pin91=PB0
-Mcu.Pin92=PB11
-Mcu.Pin93=PC0
-Mcu.Pin94=PB10
-Mcu.Pin95=PG11
-Mcu.Pin96=PG10
-Mcu.Pin97=PD11
-Mcu.Pin98=PF6
-Mcu.Pin99=PE8
-Mcu.PinsNb=179
-Mcu.ThirdPartyNb=0
-Mcu.UserConstants=
-Mcu.UserName=STM32MP157CADx
-MxCube.Version=5.3.0
-MxDb.Version=DB.5.0.30
-NVIC.BusFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false
-NVIC.DebugMonitor_IRQn=true\:0\:0\:false\:false\:true\:false\:false
-NVIC.HardFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false
-NVIC.MemoryManagement_IRQn=true\:0\:0\:false\:false\:true\:false\:false
-NVIC.NonMaskableInt_IRQn=true\:0\:0\:false\:false\:true\:false\:false
-NVIC.PendSV_IRQn=true\:0\:0\:false\:false\:true\:false\:false
-NVIC.PriorityGroup=NVIC_PRIORITYGROUP_4
-NVIC.SVCall_IRQn=true\:0\:0\:false\:false\:true\:false\:false
-NVIC.SysTick_IRQn=true\:0\:0\:false\:false\:true\:false\:true
-NVIC.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false
-PA0.GPIOParameters=GPIO_Label
-PA0.GPIO_Label=AIN_IN1
-PA0.Locked=true
-PA0.Mode=IN16-Single-Ended
-PA0.Signal=ADC1_INP16
-PA1.GPIOParameters=GPIO_Label
-PA1.GPIO_Label=Display RGB
-PA1.Locked=true
-PA1.Mode=RGB888
-PA1.Signal=LTDC_R2
-PA10.GPIOParameters=GPIO_Label
-PA10.GPIO_Label=USB OTG
-PA10.Locked=true
-PA10.Mode=Ext_Phy_OTG/Dual-Role-Device
-PA10.Signal=USB_OTG_HS_ID
-PA11.GPIOParameters=GPIO_Label
-PA11.GPIO_Label=DIO_IN2
-PA11.Locked=true
-PA11.Signal=GPIO_Input
-PA12.GPIOParameters=GPIO_Label
-PA12.GPIO_Label=Display RGB
-PA12.Locked=true
-PA12.Mode=RGB888
-PA12.Signal=LTDC_R5
-PA13.GPIOParameters=GPIO_Label
-PA13.GPIO_Label=LED1
-PA13.Locked=true
-PA13.Signal=GPIO_Output
-PA14.GPIOParameters=GPIO_Label
-PA14.GPIO_Label=LED2
-PA14.Locked=true
-PA14.Signal=GPIO_Output
-PA15.GPIOParameters=GPIO_Label
-PA15.GPIO_Label=Display RGB
-PA15.Locked=true
-PA15.Mode=RGB888
-PA15.Signal=LTDC_R1
-PA2.GPIOParameters=GPIO_Label
-PA2.GPIO_Label=Ethernet
-PA2.Locked=true
-PA2.Mode=RMII (Reduced MII)
-PA2.Signal=ETH1_MDIO
-PA3.GPIOParameters=GPIO_Label
-PA3.GPIO_Label=Display RGB
-PA3.Locked=true
-PA3.Mode=RGB888
-PA3.Signal=LTDC_B5
-PA4.GPIOParameters=GPIO_Label
-PA4.GPIO_Label=Display RGB
-PA4.Locked=true
-PA4.Mode=RGB888
-PA4.Signal=LTDC_VSYNC
-PA5.GPIOParameters=GPIO_Label
-PA5.GPIO_Label=Display RGB
-PA5.Locked=true
-PA5.Mode=RGB888
-PA5.Signal=LTDC_R4
-PA6.GPIOParameters=GPIO_Label
-PA6.GPIO_Label=Display RGB
-PA6.Locked=true
-PA6.Mode=RGB888
-PA6.Signal=LTDC_G2
-PA7.GPIOParameters=GPIO_Label
-PA7.GPIO_Label=Ethernet
-PA7.Locked=true
-PA7.Mode=RMII (Reduced MII)
-PA7.Signal=ETH1_CRS_DV
-PA8.GPIOParameters=GPIO_Label
-PA8.GPIO_Label=Display RGB
-PA8.Locked=true
-PA8.Mode=RGB888
-PA8.Signal=LTDC_R6
-PA9.GPIOParameters=GPIO_Label
-PA9.GPIO_Label=PIEZO
-PA9.Locked=true
-PA9.Signal=S_TIM1_CH2
-PB0.GPIOParameters=GPIO_Label
-PB0.GPIO_Label=Display RGB
-PB0.Locked=true
-PB0.Mode=RGB888
-PB0.Signal=LTDC_R3
-PB1.GPIOParameters=GPIO_Label
-PB1.GPIO_Label=AIN_IN2
-PB1.Locked=true
-PB1.Signal=ADCx_INP5
-PB10.GPIOParameters=GPIO_Label
-PB10.GPIO_Label=Display RGB
-PB10.Locked=true
-PB10.Mode=RGB888
-PB10.Signal=LTDC_G4
-PB11.GPIOParameters=GPIO_Label
-PB11.GPIO_Label=Ethernet
-PB11.Locked=true
-PB11.Mode=RMII (Reduced MII)
-PB11.Signal=ETH1_TX_EN
-PB12.GPIOParameters=GPIO_Label
-PB12.GPIO_Label=Ethernet
-PB12.Locked=true
-PB12.Mode=RMII (Reduced MII)
-PB12.Signal=ETH1_TXD0
-PB13.GPIOParameters=GPIO_Label
-PB13.GPIO_Label=Ethernet
-PB13.Locked=true
-PB13.Mode=RMII (Reduced MII)
-PB13.Signal=ETH1_TXD1
-PB14.GPIOParameters=GPIO_PuPd,GPIO_Label,GPIO_Speed_Medium_Default,GPIO_Mode
-PB14.GPIO_Label=SDCARD
-PB14.GPIO_Mode=GPIO_MODE_AF_PP
-PB14.GPIO_PuPd=GPIO_PULLUP
-PB14.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_MEDIUM
-PB14.Locked=true
-PB14.Mode=SD_4_bits_Wide_bus
-PB14.Signal=SDMMC2_D0
-PB15.GPIOParameters=GPIO_PuPd,GPIO_Label,GPIO_Speed_Medium_Default,GPIO_Mode
-PB15.GPIO_Label=SDCARD
-PB15.GPIO_Mode=GPIO_MODE_AF_PP
-PB15.GPIO_PuPd=GPIO_PULLUP
-PB15.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_MEDIUM
-PB15.Locked=true
-PB15.Mode=SD_4_bits_Wide_bus
-PB15.Signal=SDMMC2_D1
-PB2.GPIOParameters=GPIO_ModePuPdOnly,GPIO_PuPd,GPIO_Label
-PB2.GPIO_Label=Console UART
-PB2.GPIO_ModePuPdOnly=GPIO_MODE_AF
-PB2.GPIO_PuPd=GPIO_PULLUP
-PB2.Locked=true
-PB2.Mode=Asynchronous
-PB2.Signal=UART4_RX
-PB3.GPIOParameters=GPIO_PuPd,GPIO_Label,GPIO_Speed_Medium_Default,GPIO_Mode
-PB3.GPIO_Label=SDCARD
-PB3.GPIO_Mode=GPIO_MODE_AF_PP
-PB3.GPIO_PuPd=GPIO_PULLUP
-PB3.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_MEDIUM
-PB3.Locked=true
-PB3.Mode=SD_4_bits_Wide_bus
-PB3.Signal=SDMMC2_D2
-PB4.GPIOParameters=GPIO_PuPd,GPIO_Label,GPIO_Speed_Medium_Default,GPIO_Mode
-PB4.GPIO_Label=SDCARD
-PB4.GPIO_Mode=GPIO_MODE_AF_PP
-PB4.GPIO_PuPd=GPIO_PULLUP
-PB4.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_MEDIUM
-PB4.Locked=true
-PB4.Mode=SD_4_bits_Wide_bus
-PB4.Signal=SDMMC2_D3
-PB5.GPIOParameters=GPIO_Label
-PB5.GPIO_Label=Display RGB
-PB5.Locked=true
-PB5.Mode=RGB888
-PB5.Signal=LTDC_G7
-PB6.GPIOParameters=GPIO_PuPd,GPIO_Label,GPIO_Speed_Medium_Default,GPIO_Mode
-PB6.GPIO_Label=NOR Flash
-PB6.GPIO_Mode=GPIO_MODE_AF_PP
-PB6.GPIO_PuPd=GPIO_PULLUP
-PB6.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_VERY_HIGH
-PB6.Locked=true
-PB6.Mode=Enable Chip Select for each bank
-PB6.Signal=QUADSPI_BK1_NCS
-PB7.GPIOParameters=GPIO_Label
-PB7.GPIO_Label=I2C4 Bus Ext
-PB7.Locked=true
-PB7.Mode=I2C
-PB7.Signal=I2C4_SDA
-PB8.GPIOParameters=GPIO_Label
-PB8.GPIO_Label=Display RGB
-PB8.Locked=true
-PB8.Mode=RGB888
-PB8.Signal=LTDC_B6
-PB9.GPIOParameters=GPIO_Label
-PB9.GPIO_Label=Display RGB
-PB9.Locked=true
-PB9.Mode=RGB888
-PB9.Signal=LTDC_B7
-PC0.GPIOParameters=GPIO_PuPd,GPIO_Label,GPIO_Speed_Medium_Default
-PC0.GPIO_Label=NAND Flash
-PC0.GPIO_PuPd=GPIO_PULLUP
-PC0.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_VERY_HIGH
-PC0.Locked=true
-PC0.Mode=Enable Chip Select for each bank
-PC0.Signal=QUADSPI_BK2_NCS
-PC1.GPIOParameters=GPIO_Label
-PC1.GPIO_Label=Ethernet
-PC1.Locked=true
-PC1.Mode=RMII (Reduced MII)
-PC1.Signal=ETH1_MDC
-PC10.GPIOParameters=GPIO_PuPd,GPIO_Label,GPIO_Speed_Medium_Default,GPIO_Mode
-PC10.GPIO_Label=EMMC
-PC10.GPIO_Mode=GPIO_MODE_AF_PP
-PC10.GPIO_PuPd=GPIO_PULLUP
-PC10.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_MEDIUM
-PC10.Locked=true
-PC10.Mode=SD_4_bits_Wide_bus
-PC10.Signal=SDMMC1_D2
-PC11.GPIOParameters=GPIO_PuPd,GPIO_Label,GPIO_Speed_Medium_Default,GPIO_Mode
-PC11.GPIO_Label=EMMC
-PC11.GPIO_Mode=GPIO_MODE_AF_PP
-PC11.GPIO_PuPd=GPIO_PULLUP
-PC11.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_MEDIUM
-PC11.Locked=true
-PC11.Mode=SD_4_bits_Wide_bus
-PC11.Signal=SDMMC1_D3
-PC12.GPIOParameters=GPIO_PuPd,GPIO_Speed_High_Default,GPIO_Label,GPIO_Mode
-PC12.GPIO_Label=EMMC
-PC12.GPIO_Mode=GPIO_MODE_AF_PP
-PC12.GPIO_PuPd=GPIO_PULLUP
-PC12.GPIO_Speed_High_Default=GPIO_SPEED_FREQ_VERY_HIGH
-PC12.Locked=true
-PC12.Mode=SD_4_bits_Wide_bus
-PC12.Signal=SDMMC1_CK
-PC13.GPIOParameters=GPIO_Label
-PC13.GPIO_Label=TP16
-PC13.Locked=true
-PC13.Signal=RTC_LSCO
-PC14-OSC32_IN.GPIOParameters=GPIO_Label
-PC14-OSC32_IN.GPIO_Label=OSC RTC
-PC14-OSC32_IN.Locked=true
-PC14-OSC32_IN.Mode=LSE-External-Oscillator
-PC14-OSC32_IN.Signal=RCC_OSC32_IN
-PC15-OSC32_OUT.GPIOParameters=GPIO_Label
-PC15-OSC32_OUT.GPIO_Label=OSC RTC
-PC15-OSC32_OUT.Locked=true
-PC15-OSC32_OUT.Mode=LSE-External-Oscillator
-PC15-OSC32_OUT.Signal=RCC_OSC32_OUT
-PC2.GPIOParameters=GPIO_Label
-PC2.GPIO_Label=DIO_OUT2
-PC2.Locked=true
-PC2.Signal=GPIO_Output
-PC3.GPIOParameters=GPIO_Label
-PC3.GPIO_Label=DIO_IN1
-PC3.Locked=true
-PC3.Signal=GPIO_Input
-PC4.GPIOParameters=GPIO_Label
-PC4.GPIO_Label=Ethernet
-PC4.Locked=true
-PC4.Mode=RMII (Reduced MII)
-PC4.Signal=ETH1_RXD0
-PC5.GPIOParameters=GPIO_Label
-PC5.GPIO_Label=Ethernet
-PC5.Locked=true
-PC5.Mode=RMII (Reduced MII)
-PC5.Signal=ETH1_RXD1
-PC6.GPIOParameters=GPIO_Label
-PC6.GPIO_Label=Display RGB
-PC6.Locked=true
-PC6.Mode=RGB888
-PC6.Signal=LTDC_HSYNC
-PC7.GPIOParameters=GPIO_Label
-PC7.GPIO_Label=Display RGB
-PC7.Locked=true
-PC7.Mode=RGB888
-PC7.Signal=LTDC_G6
-PC8.GPIOParameters=GPIO_PuPd,GPIO_Label,GPIO_Speed_Medium_Default,GPIO_Mode
-PC8.GPIO_Label=EMMC
-PC8.GPIO_Mode=GPIO_MODE_AF_PP
-PC8.GPIO_PuPd=GPIO_PULLUP
-PC8.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_MEDIUM
-PC8.Locked=true
-PC8.Mode=SD_4_bits_Wide_bus
-PC8.Signal=SDMMC1_D0
-PC9.GPIOParameters=GPIO_PuPd,GPIO_Label,GPIO_Speed_Medium_Default,GPIO_Mode
-PC9.GPIO_Label=EMMC
-PC9.GPIO_Mode=GPIO_MODE_AF_PP
-PC9.GPIO_PuPd=GPIO_PULLUP
-PC9.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_MEDIUM
-PC9.Locked=true
-PC9.Mode=SD_4_bits_Wide_bus
-PC9.Signal=SDMMC1_D1
-PCC.Checker=false
-PCC.Line=STM32MP157
-PCC.MCU=STM32MP157CADx
-PCC.PartNumber=STM32MP157CADx
-PCC.Seq0=0
-PCC.Series=STM32MP1
-PCC.Temperature=25
-PCC.Vdd=3.0
-PD0.GPIOParameters=GPIO_Label
-PD0.GPIO_Label=CAN
-PD0.Locked=true
-PD0.Mode=FDCANMaster
-PD0.Signal=FDCAN1_RX
-PD1.GPIOParameters=GPIO_Speed,GPIO_PuPd,GPIO_Label,GPIO_Mode
-PD1.GPIO_Label=CAN
-PD1.GPIO_Mode=GPIO_MODE_AF_PP
-PD1.GPIO_PuPd=GPIO_NOPULL
-PD1.GPIO_Speed=GPIO_SPEED_FREQ_LOW
-PD1.Locked=true
-PD1.Mode=FDCANMaster
-PD1.Signal=FDCAN1_TX
-PD10.GPIOParameters=GPIO_Label
-PD10.GPIO_Label=Display RGB
-PD10.Locked=true
-PD10.Mode=RGB888
-PD10.Signal=LTDC_B3
-PD11.GPIOParameters=GPIO_Label
-PD11.GPIO_Label=UART3_RS232
-PD11.Locked=true
-PD11.Mode=CTS_RTS
-PD11.Signal=USART3_CTS
-PD12.GPIOParameters=GPIO_Label
-PD12.GPIO_Label=UART3_RS232
-PD12.Locked=true
-PD12.Mode=CTS_RTS
-PD12.Signal=USART3_RTS
-PD13.GPIOParameters=GPIO_Label
-PD13.GPIO_Label=DSI_SEL
-PD13.Locked=true
-PD13.Signal=GPIO_Output
-PD14.GPIOParameters=GPIO_ModeDefaultPP,GPIO_Speed,GPIO_PuPd,GPIO_Label
-PD14.GPIO_Label=BACKLIGHT
-PD14.GPIO_ModeDefaultPP=GPIO_MODE_AF_PP
-PD14.GPIO_PuPd=GPIO_NOPULL
-PD14.GPIO_Speed=GPIO_SPEED_FREQ_LOW
-PD14.Locked=true
-PD14.Signal=S_TIM4_CH3
-PD15.GPIOParameters=GPIO_Label
-PD15.GPIO_Label=RESET_OUT
-PD15.Locked=true
-PD15.Signal=GPIO_Output
-PD2.GPIOParameters=GPIO_PuPd,GPIO_Label,GPIO_Speed_Medium_Default,GPIO_Mode
-PD2.GPIO_Label=EMMC
-PD2.GPIO_Mode=GPIO_MODE_AF_PP
-PD2.GPIO_PuPd=GPIO_PULLUP
-PD2.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_MEDIUM
-PD2.Locked=true
-PD2.Mode=SD_4_bits_Wide_bus
-PD2.Signal=SDMMC1_CMD
-PD3.GPIOParameters=GPIO_Label
-PD3.GPIO_Label=LVDS_TF_PWR_EN
-PD3.Locked=true
-PD3.Signal=GPIO_Output
-PD4.GPIOParameters=GPIO_Speed,GPIO_PuPd,GPIO_Label,GPIO_Mode
-PD4.GPIO_Label=UART2_RS485
-PD4.GPIO_Mode=GPIO_MODE_AF_PP
-PD4.GPIO_PuPd=GPIO_PULLDOWN
-PD4.GPIO_Speed=GPIO_SPEED_FREQ_LOW
-PD4.Locked=true
-PD4.Mode=RTS_Only
-PD4.Signal=USART2_RTS
-PD5.GPIOParameters=GPIO_ModeDefaultPP,GPIO_Speed,GPIO_PuPd,GPIO_Label
-PD5.GPIO_Label=UART2_RS485
-PD5.GPIO_ModeDefaultPP=GPIO_MODE_AF_PP
-PD5.GPIO_PuPd=GPIO_PULLUP
-PD5.GPIO_Speed=GPIO_SPEED_FREQ_LOW
-PD5.Locked=true
-PD5.Mode=Asynchronous
-PD5.Signal=USART2_TX
-PD6.GPIOParameters=GPIO_ModePuPdOnly,GPIO_PuPd,GPIO_Label
-PD6.GPIO_Label=UART2_RS485
-PD6.GPIO_ModePuPdOnly=GPIO_MODE_AF
-PD6.GPIO_PuPd=GPIO_PULLUP
-PD6.Locked=true
-PD6.Mode=Asynchronous
-PD6.Signal=USART2_RX
-PD7.GPIOParameters=GPIO_Label
-PD7.GPIO_Label=I2C2 Bus Int+Ext
-PD7.Locked=true
-PD7.Mode=I2C
-PD7.Signal=I2C2_SCL
-PD8.GPIOParameters=GPIO_Label
-PD8.GPIO_Label=UART3_RS232
-PD8.Locked=true
-PD8.Mode=Asynchronous
-PD8.Signal=USART3_TX
-PD9.GPIOParameters=GPIO_Label
-PD9.GPIO_Label=UART3_RS232
-PD9.Locked=true
-PD9.Mode=Asynchronous
-PD9.Signal=USART3_RX
-PE0.GPIOParameters=GPIO_Label
-PE0.GPIO_Label=TOUCH_WAKE
-PE0.Locked=true
-PE0.Signal=GPIO_Input
-PE1.GPIOParameters=GPIO_Label
-PE1.GPIO_Label=DIO_OUT1
-PE1.Locked=true
-PE1.Signal=GPIO_Output
-PE10.GPIOParameters=GPIO_Label,GPIO_Speed_Medium_Default
-PE10.GPIO_Label=NAND Flash
-PE10.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_VERY_HIGH
-PE10.Locked=true
-PE10.Mode=Dual Bank
-PE10.Signal=QUADSPI_BK2_IO3
-PE11.GPIOParameters=GPIO_Label
-PE11.GPIO_Label=Display RGB
-PE11.Locked=true
-PE11.Mode=RGB888
-PE11.Signal=LTDC_G3
-PE12.GPIOParameters=GPIO_Label
-PE12.GPIO_Label=Display RGB
-PE12.Locked=true
-PE12.Mode=RGB888
-PE12.Signal=LTDC_B4
-PE13.GPIOParameters=GPIO_Label
-PE13.GPIO_Label=Display RGB
-PE13.Locked=true
-PE13.Mode=RGB888
-PE13.Signal=LTDC_DE
-PE14.GPIOParameters=GPIO_Label
-PE14.GPIO_Label=Display RGB
-PE14.Locked=true
-PE14.Mode=RGB888
-PE14.Signal=LTDC_CLK
-PE15.GPIOParameters=GPIO_Label
-PE15.GPIO_Label=Display RGB
-PE15.Locked=true
-PE15.Mode=RGB888
-PE15.Signal=LTDC_R7
-PE2.GPIOParameters=GPIO_Label
-PE2.GPIO_Label=I2C4 Bus Ext
-PE2.Locked=true
-PE2.Mode=I2C
-PE2.Signal=I2C4_SCL
-PE3.GPIOParameters=GPIO_PuPd,GPIO_Speed_High_Default,GPIO_Label,GPIO_Mode
-PE3.GPIO_Label=SDCARD
-PE3.GPIO_Mode=GPIO_MODE_AF_PP
-PE3.GPIO_PuPd=GPIO_PULLUP
-PE3.GPIO_Speed_High_Default=GPIO_SPEED_FREQ_VERY_HIGH
-PE3.Locked=true
-PE3.Mode=SD_4_bits_Wide_bus
-PE3.Signal=SDMMC2_CK
-PE4.GPIOParameters=GPIO_Label
-PE4.GPIO_Label=Display RGB
-PE4.Locked=true
-PE4.Mode=RGB888
-PE4.Signal=LTDC_B0
-PE5.GPIOParameters=GPIO_Label
-PE5.GPIO_Label=Display RGB
-PE5.Locked=true
-PE5.Mode=RGB888
-PE5.Signal=LTDC_G0
-PE6.GPIOParameters=GPIO_Label
-PE6.GPIO_Label=Display RGB
-PE6.Locked=true
-PE6.Mode=RGB888
-PE6.Signal=LTDC_G1
-PE7.GPIOParameters=GPIO_Label,GPIO_Speed_Medium_Default
-PE7.GPIO_Label=NAND Flash
-PE7.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_VERY_HIGH
-PE7.Locked=true
-PE7.Mode=Dual Bank
-PE7.Signal=QUADSPI_BK2_IO0
-PE8.GPIOParameters=GPIO_Label,GPIO_Speed_Medium_Default
-PE8.GPIO_Label=NAND Flash
-PE8.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_VERY_HIGH
-PE8.Locked=true
-PE8.Mode=Dual Bank
-PE8.Signal=QUADSPI_BK2_IO1
-PE9.GPIOParameters=GPIO_Label,GPIO_Speed_Medium_Default
-PE9.GPIO_Label=NAND Flash
-PE9.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_VERY_HIGH
-PE9.Locked=true
-PE9.Mode=Dual Bank
-PE9.Signal=QUADSPI_BK2_IO2
-PF10.GPIOParameters=GPIO_Label,GPIO_Speed_Medium_Default
-PF10.GPIO_Label=NOR/NAND Flash
-PF10.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_VERY_HIGH
-PF10.Locked=true
-PF10.Mode=Dual Bank
-PF10.Signal=QUADSPI_CLK
-PF11.GPIOParameters=GPIO_Label
-PF11.GPIO_Label=Display RGB
-PF11.Locked=true
-PF11.Mode=RGB888
-PF11.Signal=LTDC_G5
-PF6.GPIOParameters=GPIO_Label,GPIO_Speed_Medium_Default
-PF6.GPIO_Label=NOR Flash
-PF6.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_VERY_HIGH
-PF6.Locked=true
-PF6.Mode=Dual Bank
-PF6.Signal=QUADSPI_BK1_IO3
-PF7.GPIOParameters=GPIO_Label,GPIO_Speed_Medium_Default
-PF7.GPIO_Label=NOR Flash
-PF7.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_VERY_HIGH
-PF7.Locked=true
-PF7.Mode=Dual Bank
-PF7.Signal=QUADSPI_BK1_IO2
-PF8.GPIOParameters=GPIO_Label,GPIO_Speed_Medium_Default
-PF8.GPIO_Label=NOR Flash
-PF8.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_VERY_HIGH
-PF8.Locked=true
-PF8.Mode=Dual Bank
-PF8.Signal=QUADSPI_BK1_IO0
-PF9.GPIOParameters=GPIO_Label,GPIO_Speed_Medium_Default
-PF9.GPIO_Label=NOR Flash
-PF9.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_VERY_HIGH
-PF9.Locked=true
-PF9.Mode=Dual Bank
-PF9.Signal=QUADSPI_BK1_IO1
-PG10.GPIOParameters=GPIO_Label
-PG10.GPIO_Label=Display RGB
-PG10.Locked=true
-PG10.Mode=RGB888
-PG10.Signal=LTDC_B2
-PG11.GPIOParameters=GPIO_ModeDefaultPP,GPIO_Speed,GPIO_PuPd,GPIO_Label
-PG11.GPIO_Label=Console UART
-PG11.GPIO_ModeDefaultPP=GPIO_MODE_AF_PP
-PG11.GPIO_PuPd=GPIO_PULLUP
-PG11.GPIO_Speed=GPIO_SPEED_FREQ_LOW
-PG11.Locked=true
-PG11.Mode=Asynchronous
-PG11.Signal=UART4_TX
-PG12.GPIOParameters=GPIO_Label
-PG12.GPIO_Label=Display RGB
-PG12.Locked=true
-PG12.Mode=RGB888
-PG12.Signal=LTDC_B1
-PG13.GPIOParameters=GPIO_Label
-PG13.GPIO_Label=Display RGB
-PG13.Locked=true
-PG13.Mode=RGB888
-PG13.Signal=LTDC_R0
-PG14.GPIOParameters=GPIO_Label
-PG14.GPIO_Label=LVDS_DSI2LVDS_IRQ
-PG14.Locked=true
-PG14.Signal=GPIO_Input
-PG15.GPIOParameters=GPIO_Label
-PG15.GPIO_Label=I2C2 Bus Int+Ext
-PG15.Locked=true
-PG15.Mode=I2C
-PG15.Signal=I2C2_SDA
-PG6.GPIOParameters=GPIO_PuPd,GPIO_Label,GPIO_Speed_Medium_Default,GPIO_Mode
-PG6.GPIO_Label=SDCARD
-PG6.GPIO_Mode=GPIO_MODE_AF_PP
-PG6.GPIO_PuPd=GPIO_PULLUP
-PG6.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_MEDIUM
-PG6.Locked=true
-PG6.Mode=SD_4_bits_Wide_bus
-PG6.Signal=SDMMC2_CMD
-PG7.GPIOParameters=GPIO_PuPd,GPIO_Label
-PG7.GPIO_Label=TOUCH_INT
-PG7.GPIO_PuPd=GPIO_PULLUP
-PG7.Locked=true
-PG7.Signal=GPIO_Input
-PG8.GPIOParameters=GPIO_Label
-PG8.GPIO_Label=Ethernet
-PG8.Locked=true
-PG8.Mode=ETH Clock Output (PHY without Quartz)
-PG8.Signal=ETH1_CLK
-PG9.GPIOParameters=GPIO_Label
-PG9.GPIO_Label=HDMI_DSI2HDMI_IRQ
-PG9.Locked=true
-PG9.Signal=GPIO_Input
-PH0-OSC_IN.GPIOParameters=GPIO_Label
-PH0-OSC_IN.GPIO_Label=OSC System
-PH0-OSC_IN.Locked=true
-PH0-OSC_IN.Mode=HSE-External-Oscillator
-PH0-OSC_IN.Signal=RCC_OSC_IN
-PH1-OSC_OUT.GPIOParameters=GPIO_Label
-PH1-OSC_OUT.GPIO_Label=OSC System
-PH1-OSC_OUT.Locked=true
-PH1-OSC_OUT.Mode=HSE-External-Oscillator
-PH1-OSC_OUT.Signal=RCC_OSC_OUT
-PinOutPanel.CurrentBGAView=Top
-PinOutPanel.RotationAngle=0
-ProjectManager.AskForMigrate=true
-ProjectManager.BackupPrevious=false
-ProjectManager.CompilerOptimize=6
-ProjectManager.ComputerToolchain=false
-ProjectManager.CoupleFile=false
-ProjectManager.CustomerFirmwarePackage=
-ProjectManager.DefaultFWLocation=true
-ProjectManager.DeletePrevious=true
-ProjectManager.DeviceId=STM32MP157CADx
-ProjectManager.DeviceTreeLocation=/home/user/gen/thud/ktn/ye/layers/meta-ktn-stm32mp/conf/machine/cubemx/t1000-k/DeviceTree/
-ProjectManager.FirmwarePackage=STM32Cube FW_MP1 V1.0.1
-ProjectManager.FreePins=false
-ProjectManager.HalAssertFull=false
-ProjectManager.HeapSize=0x200
-ProjectManager.KeepUserCode=true
-ProjectManager.LastFirmware=true
-ProjectManager.LibraryCopy=1
-ProjectManager.MainLocation=Src
-ProjectManager.NoMain=false
-ProjectManager.PreviousToolchain=SW4STM32
-ProjectManager.ProjectBuild=false
-ProjectManager.ProjectFileName=t1000-k.ioc
-ProjectManager.ProjectName=t1000-k
-ProjectManager.StackSize=0x400
-ProjectManager.TargetToolchain=SW4STM32
-ProjectManager.ToolChainLocation=
-ProjectManager.UnderRoot=true
-ProjectManager.functionlistsort=1-MX_GPIO_Init-GPIO-false-HAL-true,2-SystemClock_Config-RCC-false-HAL-true,3-MX_ETZPC_Init-ETZPC-false-HAL-true,4-MX_IPCC_Init-IPCC-false-HAL-true
-RCC.ADCCLockSelection=RCC_ADCCLKSOURCE_PER
-RCC.ADCFreq_Value=24000000
-RCC.AHB1234Freq_Value=196000000
-RCC.APB1DIV=RCC_APB1_DIV2
-RCC.APB1Freq_Value=98000000
-RCC.APB2DIV=RCC_APB2_DIV2
-RCC.APB2Freq_Value=98000000
-RCC.APB3DIV=RCC_APB3_DIV2
-RCC.APB3Freq_Value=98000000
-RCC.APB4DIV=RCC_APB4_DIV2
-RCC.APB4Freq_Value=132000000
-RCC.APB5DIV=RCC_APB5_DIV4
-RCC.APB5DIVClockFreq_Value=66000000
-RCC.AXICLKFreq_VALUE=264000000
-RCC.AXICLKSource=RCC_AXISSOURCE_PLL2
-RCC.AXIDIVFreq_Value=264000000
-RCC.CECFreq_Value=32768
-RCC.CKPERCLKFreq_VALUE=24000000
-RCC.CKPERCLKSource=RCC_CKPERCLKSOURCE_HSE
-RCC.CSI_VALUE=4000000
-RCC.DACCLKFreq_VALUE=32000
-RCC.DDRCFreq_Value=528000000
-RCC.DDRPERFMFreq_Value=528000000
-RCC.DDRPHYFreq_Value=528000000
-RCC.DFSDFAFreq_Value=50000000
-RCC.DFSDMFreq_Value=196000000
-RCC.DIVM1=3
-RCC.DIVM2=3
-RCC.DIVM3=3
-RCC.DIVM4=6
-RCC.DIVN1=81
-RCC.DIVN2=66
-RCC.DIVN3=98
-RCC.DIVN4=125
-RCC.DIVP1Freq_Value=648000000
-RCC.DIVP2Freq_Value=264000000
-RCC.DIVP3=4
-RCC.DIVP3Freq_Value=196000000
-RCC.DIVP4=10
-RCC.DIVP4Freq_Value=50000000
-RCC.DIVQ1Freq_Value=324000000
-RCC.DIVQ2Freq_Value=264000000
-RCC.DIVQ3Freq_Value=392000000
-RCC.DIVQ4=10
-RCC.DIVQ4Freq_Value=50000000
-RCC.DIVR1Freq_Value=324000000
-RCC.DIVR2=1
-RCC.DIVR2Freq_Value=528000000
-RCC.DIVR3Freq_Value=392000000
-RCC.DIVR4=10
-RCC.DIVR4Freq_Value=50000000
-RCC.DSIFreq_Value=60000000
-RCC.DSIPixelFreq_Value=50000000
-RCC.DSITXEscFreq_Value=15000000
-RCC.DSI_VALUE=60000000
-RCC.ETHFreq_Value=50000000
-RCC.FDCANFreq_Value=24000000
-RCC.FMCFreq_Value=264000000
-RCC.FamilyName=M
-RCC.HSE_Timout=100
-RCC.HSE_VALUE=24000000
-RCC.HSIDivClkFreq_Value=64000000
-RCC.HSI_VALUE=64000000
-RCC.Hclk5DIVFreq_Value=264000000
-RCC.Hclk6DIVFreq_Value=264000000
-RCC.I2C12CLockSelection=RCC_I2C12CLKSOURCE_HSI
-RCC.I2C12Freq_Value=64000000
-RCC.I2C35Freq_Value=98000000
-RCC.I2C46CLockSelection=RCC_I2C46CLKSOURCE_HSI
-RCC.I2C46Freq_Value=64000000
-RCC.IPParameters=ADCCLockSelection,ADCFreq_Value,AHB1234Freq_Value,APB1DIV,APB1Freq_Value,APB2DIV,APB2Freq_Value,APB3DIV,APB3Freq_Value,APB4DIV,APB4Freq_Value,APB5DIV,APB5DIVClockFreq_Value,AXICLKFreq_VALUE,AXICLKSource,AXIDIVFreq_Value,CECFreq_Value,CKPERCLKFreq_VALUE,CKPERCLKSource,CSI_VALUE,DACCLKFreq_VALUE,DDRCFreq_Value,DDRPERFMFreq_Value,DDRPHYFreq_Value,DFSDFAFreq_Value,DFSDMFreq_Value,DIVM1,DIVM2,DIVM3,DIVM4,DIVN1,DIVN2,DIVN3,DIVN4,DIVP1Freq_Value,DIVP2Freq_Value,DIVP3,DIVP3Freq_Value,DIVP4,DIVP4Freq_Value,DIVQ1Freq_Value,DIVQ2Freq_Value,DIVQ3Freq_Value,DIVQ4,DIVQ4Freq_Value,DIVR1Freq_Value,DIVR2,DIVR2Freq_Value,DIVR3Freq_Value,DIVR4,DIVR4Freq_Value,DSIFreq_Value,DSIPixelFreq_Value,DSITXEscFreq_Value,DSI_VALUE,ETHFreq_Value,FDCANFreq_Value,FMCFreq_Value,FamilyName,HSE_Timout,HSE_VALUE,HSIDivClkFreq_Value,HSI_VALUE,Hclk5DIVFreq_Value,Hclk6DIVFreq_Value,I2C12CLockSelection,I2C12Freq_Value,I2C35Freq_Value,I2C46CLockSelection,I2C46Freq_Value,LPTIM1Freq_Value,LPTIM23Freq_Value,LPTIM45Freq_Value,LSE_Timout,LSI_VALUE,LTDCFreq_Value,MCO1PinFreq_Value,MCO2PinFreq_Value,MCUCLKFreq_VALUE,MCUCLKSource,MCUClockFreq_Value,MCUDIVCLKFreq_Value,MPUCLKFreq_VALUE,MPUCLKSource,PLL12Source,PLL2FRACV,PLL3Source,PLL4PDSIFreq_Value,PLL4Source,PLLDSIFreq_Value,PLLDSIVCOFreq_Value,PUBLFreq_Value,QSPIFreq_Value,RNG1Freq_Value,RNG2Freq_Value,RTCClockSelection,RTCFreq_Value,SAI1Freq_Value,SAI2Freq_Value,SAI3Freq_Value,SAI4Freq_Value,SDMMC12CLockSelection,SDMMC12Freq_Value,SDMMC3Freq_Value,SPDIFRXFreq_Value,SPI1Freq_Value,SPI23Freq_Value,SPI45Freq_Value,SPI6Freq_Value,STGENCLockSelection,STGENFreq_Value,Tim1OutputFreq_Value,Tim2OutputFreq_Value,UART78Freq_Value,USART1Freq_Value,USART24Freq_Value,USART35Freq_Value,USART6Freq_Value,USBOCLKSource,USBOHSFreq_Value,USBPHYCLKSource,USBPHYFreq_Value,VCO1OutputFreq_Value,VCO2OutputFreq_Value,VCO3OutputFreq_Value,VCO4OutputFreq_Value,VCOInput1Freq_Value,VCOInput2Freq_Value,VCOInput3Freq_Value,VCOInput4Freq_Value
-RCC.LPTIM1Freq_Value=98000000
-RCC.LPTIM23Freq_Value=98000000
-RCC.LPTIM45Freq_Value=98000000
-RCC.LSE_Timout=5000
-RCC.LSI_VALUE=32000
-RCC.LTDCFreq_Value=50000000
-RCC.MCO1PinFreq_Value=64000000
-RCC.MCO2PinFreq_Value=648000000
-RCC.MCUCLKFreq_VALUE=196000000
-RCC.MCUCLKSource=RCC_MCUSSOURCE_PLL3
-RCC.MCUClockFreq_Value=196000000
-RCC.MCUDIVCLKFreq_Value=196000000
-RCC.MPUCLKFreq_VALUE=648000000
-RCC.MPUCLKSource=RCC_MPUSOURCE_PLL1
-RCC.PLL12Source=RCC_PLL12SOURCE_HSE
-RCC.PLL2FRACV=0
-RCC.PLL3Source=RCC_PLL3SOURCE_HSE
-RCC.PLL4PDSIFreq_Value=50000000
-RCC.PLL4Source=RCC_PLL4SOURCE_HSE
-RCC.PLLDSIFreq_Value=480000000
-RCC.PLLDSIVCOFreq_Value=960000000
-RCC.PUBLFreq_Value=528000000
-RCC.QSPIFreq_Value=264000000
-RCC.RNG1Freq_Value=4000000
-RCC.RNG2Freq_Value=4000000
-RCC.RTCClockSelection=RCC_RTCCLKSOURCE_LSE
-RCC.RTCFreq_Value=32768
-RCC.SAI1Freq_Value=50000000
-RCC.SAI2Freq_Value=50000000
-RCC.SAI3Freq_Value=50000000
-RCC.SAI4Freq_Value=50000000
-RCC.SDMMC12CLockSelection=RCC_SDMMC12CLKSOURCE_PLL4
-RCC.SDMMC12Freq_Value=50000000
-RCC.SDMMC3Freq_Value=196000000
-RCC.SPDIFRXFreq_Value=50000000
-RCC.SPI1Freq_Value=50000000
-RCC.SPI23Freq_Value=50000000
-RCC.SPI45Freq_Value=98000000
-RCC.SPI6Freq_Value=66000000
-RCC.STGENCLockSelection=RCC_STGENCLKSOURCE_HSE
-RCC.STGENFreq_Value=24000000
-RCC.Tim1OutputFreq_Value=196000000
-RCC.Tim2OutputFreq_Value=196000000
-RCC.UART78Freq_Value=98000000
-RCC.USART1Freq_Value=66000000
-RCC.USART24Freq_Value=98000000
-RCC.USART35Freq_Value=98000000
-RCC.USART6Freq_Value=98000000
-RCC.USBOCLKSource=RCC_USBOCLKSOURCE_PHY
-RCC.USBOHSFreq_Value=48000000
-RCC.USBPHYCLKSource=RCC_USBPHYCLKSOURCE_HSE
-RCC.USBPHYFreq_Value=24000000
-RCC.VCO1OutputFreq_Value=1296000000
-RCC.VCO2OutputFreq_Value=1056000000
-RCC.VCO3OutputFreq_Value=784000000
-RCC.VCO4OutputFreq_Value=500000000
-RCC.VCOInput1Freq_Value=8000000
-RCC.VCOInput2Freq_Value=8000000
-RCC.VCOInput3Freq_Value=8000000
-RCC.VCOInput4Freq_Value=4000000
-SH.ADCx_INP5.0=ADC1_INP5,IN5-Single-Ended
-SH.ADCx_INP5.ConfNb=1
-SH.S_TIM1_CH2.0=TIM1_CH2,PWM Generation2 CH2
-SH.S_TIM1_CH2.ConfNb=1
-SH.S_TIM4_CH3.0=TIM4_CH3,PWM Generation3 CH3
-SH.S_TIM4_CH3.ConfNb=1
-TIM1.Channel-PWM\ Generation2\ CH2=TIM_CHANNEL_2
-TIM1.IPParameters=Channel-PWM Generation2 CH2
-TIM4.Channel-PWM\ Generation3\ CH3=TIM_CHANNEL_3
-TIM4.IPParameters=Channel-PWM Generation3 CH3
-USART2.IPParameters=VirtualMode-Asynchronous
-USART2.VirtualMode-Asynchronous=VM_ASYNC
-USART3.IPParameters=VirtualMode-Asynchronous
-USART3.VirtualMode-Asynchronous=VM_ASYNC
-USB_DM1.GPIOParameters=GPIO_Label
-USB_DM1.GPIO_Label=USB Host
-USB_DM1.Locked=true
-USB_DM1.Mode=Enable
-USB_DM1.Signal=USBH_HS1_DM
-USB_DM2.GPIOParameters=GPIO_Label
-USB_DM2.GPIO_Label=USB OTG
-USB_DM2.Locked=true
-USB_DM2.Mode=Ext_Phy_OTG/Dual-Role-Device
-USB_DM2.Signal=USB_OTG_HS_DM
-USB_DP1.GPIOParameters=GPIO_Label
-USB_DP1.GPIO_Label=USB Host
-USB_DP1.Locked=true
-USB_DP1.Mode=Enable
-USB_DP1.Signal=USBH_HS1_DP
-USB_DP2.GPIOParameters=GPIO_Label
-USB_DP2.GPIO_Label=USB OTG
-USB_DP2.Locked=true
-USB_DP2.Mode=Ext_Phy_OTG/Dual-Role-Device
-USB_DP2.Signal=USB_OTG_HS_DP
-VP_BSEC_VS_BSEC.Mode=BSEC_Activate
-VP_BSEC_VS_BSEC.Signal=BSEC_VS_BSEC
-VP_CRC1_VS_CRC.Mode=CRC_Activate
-VP_CRC1_VS_CRC.Signal=CRC1_VS_CRC
-VP_CRYP1_VS_CRYP.Mode=CRYP_Activate
-VP_CRYP1_VS_CRYP.Signal=CRYP1_VS_CRYP
-VP_DDR_DDR3.Mode=DDR3
-VP_DDR_DDR3.Signal=DDR_DDR3
-VP_DDR_DDR3_16_4Gb.Mode=4Gb_16bits
-VP_DDR_DDR3_16_4Gb.Signal=DDR_DDR3_16_4Gb
-VP_DDR_DDR_16_bits.Mode=16bits
-VP_DDR_DDR_16_bits.Signal=DDR_DDR_16_bits
-VP_DMA_VS_DMA1_A7NS.Mode=CortexA7NS
-VP_DMA_VS_DMA1_A7NS.Signal=DMA_VS_DMA1_A7NS
-VP_DMA_VS_DMA2_M4.Mode=CortexM4
-VP_DMA_VS_DMA2_M4.Signal=DMA_VS_DMA2_M4
-VP_DTS_VS_DTS.Mode=DTS_Activate
-VP_DTS_VS_DTS.Signal=DTS_VS_DTS
-VP_ETZPC_VS_ETZPC.Mode=ETZPC_Activate
-VP_ETZPC_VS_ETZPC.Signal=ETZPC_VS_ETZPC
-VP_GPU_VS_GPU.Mode=GPU_Activate
-VP_GPU_VS_GPU.Signal=GPU_VS_GPU
-VP_HASH1_VS_HASH.Mode=HASH_Activate
-VP_HASH1_VS_HASH.Signal=HASH1_VS_HASH
-VP_HSEM_VS_HSEM.Mode=HSEM_Activate
-VP_HSEM_VS_HSEM.Signal=HSEM_VS_HSEM
-VP_IPCC_VS_IPCC.Mode=IPCC_Activate
-VP_IPCC_VS_IPCC.Signal=IPCC_VS_IPCC
-VP_MDMA_VS_MDMA_A7NS_8.Mode=8\:8
-VP_MDMA_VS_MDMA_A7NS_8.Signal=MDMA_VS_MDMA_A7NS_8
-VP_RNG1_VS_RNG.Mode=RNG_Activate
-VP_RNG1_VS_RNG.Signal=RNG1_VS_RNG
-VP_RTC_VS_RTC_Activate.Mode=RTC_Enabled
-VP_RTC_VS_RTC_Activate.Signal=RTC_VS_RTC_Activate
-VP_SYS_VS_Systick.Mode=SysTick
-VP_SYS_VS_Systick.Signal=SYS_VS_Systick
-VP_VREFBUF_VS_VREFBUF.Mode=VREFBUF_Activate
-VP_VREFBUF_VS_VREFBUF.Signal=VREFBUF_VS_VREFBUF
-board=custom
diff --git a/conf/machine/cubemx/t1000-mini.ioc b/conf/machine/cubemx/t1000-mini.ioc
new file mode 100644
index 0000000000000000000000000000000000000000..d7b58cea1b3db49587d90dd3495309687842b34d
--- /dev/null
+++ b/conf/machine/cubemx/t1000-mini.ioc
@@ -0,0 +1,947 @@
+#MicroXplorer Configuration settings - do not modify
+ADC1.BoostMode=ENABLE
+ADC1.Channel-2\#ChannelRegularConversion=ADC_CHANNEL_16
+ADC1.Channel-4\#ChannelRegularConversion=ADC_CHANNEL_2
+ADC1.ClockPrescaler=ADC_CLOCK_ASYNC_DIV1
+ADC1.ContinuousConvMode=DISABLE
+ADC1.ConversionDataManagement=ADC_CONVERSIONDATA_DR
+ADC1.DiscontinuousConvMode=DISABLE
+ADC1.EOCSelection=ADC_EOC_SINGLE_CONV
+ADC1.EnableAnalogWatchDog1=false
+ADC1.EnableAnalogWatchDog2=false
+ADC1.EnableAnalogWatchDog3=false
+ADC1.EnableInjectedConversion=DISABLE
+ADC1.EnableRegularConversion=ENABLE
+ADC1.ExternalTrigConv=ADC_SOFTWARE_START
+ADC1.ExternalTrigConvEdge=ADC_EXTERNALTRIGCONVEDGE_NONE
+ADC1.IPParameters=Rank-4\#ChannelRegularConversion,Channel-4\#ChannelRegularConversion,SamplingTime-4\#ChannelRegularConversion,OffsetNumber-4\#ChannelRegularConversion,NbrOfConversionFlag,master,ClockPrescaler,Resolution,ScanConvMode,ContinuousConvMode,DiscontinuousConvMode,EOCSelection,Overrun,BoostMode,ConversionDataManagement,LowPowerAutoWait,EnableRegularConversion,LeftBitShift,OversamplingMode,NbrOfConversion,ExternalTrigConv,ExternalTrigConvEdge,EnableInjectedConversion,EnableAnalogWatchDog1,EnableAnalogWatchDog2,EnableAnalogWatchDog3,Rank-2\#ChannelRegularConversion,Channel-2\#ChannelRegularConversion,SamplingTime-2\#ChannelRegularConversion,OffsetNumber-2\#ChannelRegularConversion
+ADC1.LeftBitShift=ADC_LEFTBITSHIFT_NONE
+ADC1.LowPowerAutoWait=DISABLE
+ADC1.NbrOfConversion=1
+ADC1.NbrOfConversionFlag=1
+ADC1.OffsetNumber-2\#ChannelRegularConversion=ADC_OFFSET_NONE
+ADC1.OffsetNumber-4\#ChannelRegularConversion=ADC_OFFSET_NONE
+ADC1.Overrun=ADC_OVR_DATA_PRESERVED
+ADC1.OversamplingMode=DISABLE
+ADC1.Rank-2\#ChannelRegularConversion=1
+ADC1.Rank-4\#ChannelRegularConversion=1
+ADC1.Resolution=ADC_RESOLUTION_16B
+ADC1.SamplingTime-2\#ChannelRegularConversion=ADC_SAMPLETIME_1CYCLE_5
+ADC1.SamplingTime-4\#ChannelRegularConversion=ADC_SAMPLETIME_1CYCLE_5
+ADC1.ScanConvMode=ADC_SCAN_DISABLE
+ADC1.master=1
+Boot\ ROM.IPs=SDMMC1,UART4
+Boot\ loader.IPs=RCC,UART4,QUADSPI,SDMMC1,USB_OTG_HS
+Cortex-A7\ non\ secure.IPs=DDR\:I,RCC\:I,RTC\:I,SYS\:I,QUADSPI\:I,ETH1\:I,SPI2\:I,UART4\:I,SDMMC1\:I,USART2\:I,I2C2\:I,I2C4\:I,USBH_HS1\:I,USB_OTG_HS\:I,ADC2\:I,ADC1\:I,TIM1\:I,DMA1\:I
+Cortex-M4.IPs=RCC,WWDG1\:I,NVIC\:I,DMA2\:I
+DDR.0dqdly0=0
+DDR.0dqdly1=0
+DDR.0dqdly2=2
+DDR.0dqdly3=1
+DDR.0dqdly4=0
+DDR.0dqdly5=2
+DDR.0dqdly6=0
+DDR.0dqdly7=2
+DDR.0sdphase=3
+DDR.1dqdly0=0
+DDR.1dqdly1=0
+DDR.1dqdly2=2
+DDR.1dqdly3=1
+DDR.1dqdly4=0
+DDR.1dqdly5=2
+DDR.1dqdly6=0
+DDR.1dqdly7=2
+DDR.1dqsdly=2
+DDR.1dqsndly=2
+DDR.1sdphase=3
+DDR.ADDRMAP1=0x00070707
+DDR.ADDRMAP3=0x1F000000
+DDR.ADDRMAP5=0x06060606
+DDR.ADDRMAP6=0x0F060606
+DDR.CL=8
+DDR.DRAMTMG0=0x121B1214
+DDR.DRAMTMG1=0x000A041C
+DDR.DRAMTMG2=0x0608090F
+DDR.DRAMTMG4=0x08040608
+DDR.DRAMTMG5=0x06060403
+DDR.DTPR0=0x38D488D0
+DDR.DTPR1=0x098A00D8
+DDR.DX0DLLCR=0x4000C000
+DDR.DX0DQTR=0x20201200
+DDR.DX1DLLCR=0x4000C000
+DDR.DX1DQSTR=0x3D202000
+DDR.DX1DQTR=0x20201200
+DDR.IPParameters=addrmap_col_b9,addrmap_col_b10,addrmap_col_b11,addrmap_bank_b0,addrmap_bank_b1,addrmap_bank_b2,addrmap_row_b0,addrmap_row_b1,addrmap_row_b2_10,addrmap_row_b11,addrmap_row_b12,addrmap_row_b13,addrmap_row_b14,addrmap_row_b15,MSTR,RFSHTMG,DRAMTMG2,DRAMTMG4,DRAMTMG5,PCFGQOS1_1,ADDRMAP1,ADDRMAP3,ADDRMAP5,ADDRMAP6,PTR0,PTR1,PTR2,DTPR0,DTPR1,ZQ0CR1,SPEED_BIN_GRADE,tRCD,tRP,tRC,wr2pre,t_faw,t_ras_max,t_ras_min,t_xp,t_rd2pre,t_rp,t_rc,write_latency,read_latency,wr2rd,t_rcd,t_cksrx,t_cksre,t_ckesr,t_cke,t_xs_dll_x32,t_xs_x32,t_rfc_nom_x1_x32,t_rfc_min,dfi_t_rddata_en,dfi_tphy_wrlat,tdlllock,tdllsrst,tdinit1,tdinit0,tdinit2,tccd,trc,trrd,tras,trcd,trp,twtr,trtp,tmrd,trfc,tmod,tfaw,tdllk,tcke,txp,txs,MR0.WR,MR0.CL,MR2.RTT,MR2.CWL,data_bus_width,tREFI,DRAMTMG0,RELAXED_TIMING_MODE,DRAMTMG1,0sdphase,0dqdly0,0dqdly1,0dqdly2,0dqdly3,0dqdly4,0dqdly5,0dqdly6,0dqdly7,1sdphase,1dqsndly,1dqsdly,1dqdly0,1dqdly1,1dqdly2,1dqdly3,1dqdly4,1dqdly5,1dqdly6,1dqdly7,DX0DLLCR,DX0DQTR,DX1DLLCR,DX1DQTR,DX1DQSTR,CL,RL,MR0,rd2wr
+DDR.MR0=0x00000840
+DDR.MR0.CL=4
+DDR.MR0.WR=4
+DDR.MR2.CWL=1
+DDR.MR2.RTT=1
+DDR.MSTR=0x00041401
+DDR.PCFGQOS1_1=0x00800000
+DDR.PTR0=0x0022A41B
+DDR.PTR1=0x047C0740
+DDR.PTR2=0x042D9C80
+DDR.RELAXED_TIMING_MODE=false
+DDR.RFSHTMG=0x0040008A
+DDR.RL=8
+DDR.SPEED_BIN_GRADE=SPEED BIN GRADE CONFIG2
+DDR.ZQ0CR1=0x00000038
+DDR.addrmap_bank_b0=7
+DDR.addrmap_bank_b1=7
+DDR.addrmap_bank_b2=7
+DDR.addrmap_col_b10=31
+DDR.addrmap_col_b11=31
+DDR.addrmap_col_b9=31
+DDR.addrmap_row_b0=6
+DDR.addrmap_row_b1=6
+DDR.addrmap_row_b11=6
+DDR.addrmap_row_b12=6
+DDR.addrmap_row_b13=6
+DDR.addrmap_row_b14=6
+DDR.addrmap_row_b15=15
+DDR.addrmap_row_b2_10=6
+DDR.data_bus_width=1
+DDR.dfi_t_rddata_en=6
+DDR.dfi_tphy_wrlat=5
+DDR.rd2wr=9
+DDR.read_latency=8
+DDR.tRC=52.5
+DDR.tRCD=15
+DDR.tREFI=3.9
+DDR.tRP=15
+DDR.t_cke=3
+DDR.t_ckesr=4
+DDR.t_cksre=6
+DDR.t_cksrx=6
+DDR.t_faw=27
+DDR.t_ras_max=18
+DDR.t_ras_min=20
+DDR.t_rc=28
+DDR.t_rcd=8
+DDR.t_rd2pre=4
+DDR.t_rfc_min=138
+DDR.t_rfc_nom_x1_x32=64
+DDR.t_rp=8
+DDR.t_xp=10
+DDR.t_xs_dll_x32=16
+DDR.t_xs_x32=5
+DDR.tccd=0
+DDR.tcke=4
+DDR.tdinit0=264000
+DDR.tdinit1=143
+DDR.tdinit2=105600
+DDR.tdllk=512
+DDR.tdlllock=2704
+DDR.tdllsrst=27
+DDR.tfaw=27
+DDR.tmod=0
+DDR.tmrd=0
+DDR.tras=20
+DDR.trc=28
+DDR.trcd=8
+DDR.trfc=138
+DDR.trp=8
+DDR.trrd=6
+DDR.trtp=4
+DDR.twtr=6
+DDR.txp=13
+DDR.txs=512
+DDR.wr2pre=18
+DDR.wr2rd=15
+DDR.write_latency=6
+DDR_A0.Mode=DDR3
+DDR_A0.Signal=DDR_A0
+DDR_A1.Mode=DDR3
+DDR_A1.Signal=DDR_A1
+DDR_A10.Mode=DDR3
+DDR_A10.Signal=DDR_A10
+DDR_A11.Mode=DDR3
+DDR_A11.Signal=DDR_A11
+DDR_A12.Mode=4Gb_16bits
+DDR_A12.Signal=DDR_A12
+DDR_A13.Mode=4Gb_16bits
+DDR_A13.Signal=DDR_A13
+DDR_A14.Mode=4Gb_16bits
+DDR_A14.Signal=DDR_A14
+DDR_A2.Mode=DDR3
+DDR_A2.Signal=DDR_A2
+DDR_A3.Mode=DDR3
+DDR_A3.Signal=DDR_A3
+DDR_A4.Mode=DDR3
+DDR_A4.Signal=DDR_A4
+DDR_A5.Mode=DDR3
+DDR_A5.Signal=DDR_A5
+DDR_A6.Mode=DDR3
+DDR_A6.Signal=DDR_A6
+DDR_A7.Mode=DDR3
+DDR_A7.Signal=DDR_A7
+DDR_A8.Mode=DDR3
+DDR_A8.Signal=DDR_A8
+DDR_A9.Mode=DDR3
+DDR_A9.Signal=DDR_A9
+DDR_ATO.Mode=DDR3
+DDR_ATO.Signal=DDR_ATO
+DDR_BA0.Mode=DDR3
+DDR_BA0.Signal=DDR_BA0
+DDR_BA1.Mode=DDR3
+DDR_BA1.Signal=DDR_BA1
+DDR_BA2.Mode=DDR3
+DDR_BA2.Signal=DDR_BA2
+DDR_CASN.Mode=DDR3
+DDR_CASN.Signal=DDR_CASN
+DDR_CKE.Mode=DDR3
+DDR_CKE.Signal=DDR_CKE
+DDR_CLKN.Mode=DDR3
+DDR_CLKN.Signal=DDR_CLKN
+DDR_CLKP.Mode=DDR3
+DDR_CLKP.Signal=DDR_CLKP
+DDR_CSN.Mode=DDR3
+DDR_CSN.Signal=DDR_CSN
+DDR_DQ0.Mode=DDR3
+DDR_DQ0.Signal=DDR_DQ0
+DDR_DQ1.Mode=DDR3
+DDR_DQ1.Signal=DDR_DQ1
+DDR_DQ10.Mode=DDR3
+DDR_DQ10.Signal=DDR_DQ10
+DDR_DQ11.Mode=DDR3
+DDR_DQ11.Signal=DDR_DQ11
+DDR_DQ12.Mode=DDR3
+DDR_DQ12.Signal=DDR_DQ12
+DDR_DQ13.Mode=DDR3
+DDR_DQ13.Signal=DDR_DQ13
+DDR_DQ14.Mode=DDR3
+DDR_DQ14.Signal=DDR_DQ14
+DDR_DQ15.Mode=DDR3
+DDR_DQ15.Signal=DDR_DQ15
+DDR_DQ2.Mode=DDR3
+DDR_DQ2.Signal=DDR_DQ2
+DDR_DQ3.Mode=DDR3
+DDR_DQ3.Signal=DDR_DQ3
+DDR_DQ4.Mode=DDR3
+DDR_DQ4.Signal=DDR_DQ4
+DDR_DQ5.Mode=DDR3
+DDR_DQ5.Signal=DDR_DQ5
+DDR_DQ6.Mode=DDR3
+DDR_DQ6.Signal=DDR_DQ6
+DDR_DQ7.Mode=DDR3
+DDR_DQ7.Signal=DDR_DQ7
+DDR_DQ8.Mode=DDR3
+DDR_DQ8.Signal=DDR_DQ8
+DDR_DQ9.Mode=DDR3
+DDR_DQ9.Signal=DDR_DQ9
+DDR_DQM0.Mode=DDR3
+DDR_DQM0.Signal=DDR_DQM0
+DDR_DQM1.Mode=DDR3
+DDR_DQM1.Signal=DDR_DQM1
+DDR_DQS0N.Mode=DDR3
+DDR_DQS0N.Signal=DDR_DQS0N
+DDR_DQS0P.Mode=DDR3
+DDR_DQS0P.Signal=DDR_DQS0P
+DDR_DQS1N.Mode=DDR3
+DDR_DQS1N.Signal=DDR_DQS1N
+DDR_DQS1P.Mode=DDR3
+DDR_DQS1P.Signal=DDR_DQS1P
+DDR_DTO0.Mode=DDR3
+DDR_DTO0.Signal=DDR_DTO0
+DDR_DTO1.Mode=DDR3
+DDR_DTO1.Signal=DDR_DTO1
+DDR_ODT.Mode=DDR3
+DDR_ODT.Signal=DDR_ODT
+DDR_RASN.Mode=DDR3
+DDR_RASN.Signal=DDR_RASN
+DDR_RESETN.Mode=DDR3
+DDR_RESETN.Signal=DDR_RESETN
+DDR_VREF.Mode=DDR3
+DDR_VREF.Signal=DDR_VREF
+DDR_WEN.Mode=DDR3
+DDR_WEN.Signal=DDR_WEN
+DDR_ZQ.Mode=DDR3
+DDR_ZQ.Signal=DDR_ZQ
+File.Version=6
+JTCK-SWCLK.Mode=JTAG_5_pins
+JTCK-SWCLK.Signal=SYS_JTCK-SWCLK
+JTDI.Mode=JTAG_5_pins
+JTDI.Signal=SYS_JTDI
+JTDO-TRACESWO.Mode=JTAG_5_pins
+JTDO-TRACESWO.Signal=SYS_JTDO-SWO
+JTMS-SWDIO.Mode=JTAG_5_pins
+JTMS-SWDIO.Signal=SYS_JTMS-SWDIO
+KeepUserPlacement=false
+Mcu.Context0=Boot ROM
+Mcu.Context1=Boot loader
+Mcu.Context2=Cortex-A7 non secure
+Mcu.Context3=Cortex-M4
+Mcu.ContextNb=4
+Mcu.Family=STM32MP1
+Mcu.IP0=ADC1
+Mcu.IP1=DDR
+Mcu.IP10=SPI2
+Mcu.IP11=SYS
+Mcu.IP12=TIM1
+Mcu.IP13=UART4
+Mcu.IP14=USART2
+Mcu.IP15=USBH_HS1
+Mcu.IP16=USB_OTG_HS
+Mcu.IP2=ETH1
+Mcu.IP3=I2C2
+Mcu.IP4=I2C4
+Mcu.IP5=NVIC
+Mcu.IP6=QUADSPI
+Mcu.IP7=RCC
+Mcu.IP8=RTC
+Mcu.IP9=SDMMC1
+Mcu.IPNb=17
+Mcu.Name=STM32MP157CADx
+Mcu.Package=TFBGA257
+Mcu.Pin0=PD1
+Mcu.Pin1=PB7
+Mcu.Pin10=PG15
+Mcu.Pin100=PF8
+Mcu.Pin101=PF9
+Mcu.Pin102=USB_DP2
+Mcu.Pin103=PG7
+Mcu.Pin104=PE10
+Mcu.Pin105=PB2
+Mcu.Pin106=USB_DP1
+Mcu.Pin107=DDR_DQ15
+Mcu.Pin108=DDR_DQM1
+Mcu.Pin109=DDR_DQS1P
+Mcu.Pin11=PE6
+Mcu.Pin110=PA7
+Mcu.Pin111=PA6
+Mcu.Pin112=PF11
+Mcu.Pin113=PF7
+Mcu.Pin114=PG9
+Mcu.Pin115=USB_DM2
+Mcu.Pin116=PB6
+Mcu.Pin117=USB_DM1
+Mcu.Pin118=DDR_VREF
+Mcu.Pin119=DDR_DQ12
+Mcu.Pin12=PD7
+Mcu.Pin120=DDR_DQ11
+Mcu.Pin121=PE1
+Mcu.Pin122=PD2
+Mcu.Pin123=DDR_ZQ
+Mcu.Pin124=DDR_A7
+Mcu.Pin125=PD6
+Mcu.Pin126=PE14
+Mcu.Pin127=PC12
+Mcu.Pin128=PD15
+Mcu.Pin129=DDR_DTO1
+Mcu.Pin13=PA15
+Mcu.Pin130=DDR_A5
+Mcu.Pin131=DDR_DTO0
+Mcu.Pin132=PD14
+Mcu.Pin133=DDR_RASN
+Mcu.Pin134=DDR_ATO
+Mcu.Pin135=DDR_A6
+Mcu.Pin136=PB13
+Mcu.Pin137=PE9
+Mcu.Pin138=PF10
+Mcu.Pin139=VP_DDR_DDR3
+Mcu.Pin14=PB4
+Mcu.Pin140=VP_DDR_DDR_16_bits
+Mcu.Pin141=VP_DDR_DDR3_16_4Gb
+Mcu.Pin142=VP_RTC_VS_RTC_Activate
+Mcu.Pin143=VP_RTC_VS_RTC_Calendar
+Mcu.Pin144=VP_RTC_VS_RTC_WakeUp_intern
+Mcu.Pin145=VP_RTC_VS_RTC_Alarm_A_Intern
+Mcu.Pin146=VP_DMA_VS_DMA1_A7NS
+Mcu.Pin147=VP_DMA_VS_DMA2_M4
+Mcu.Pin15=PE5
+Mcu.Pin16=PA8
+Mcu.Pin17=PC9
+Mcu.Pin18=PC10
+Mcu.Pin19=NJTRST
+Mcu.Pin2=PC6
+Mcu.Pin20=JTDI
+Mcu.Pin21=DDR_DQ3
+Mcu.Pin22=DDR_DQ7
+Mcu.Pin23=DDR_DQS0N
+Mcu.Pin24=DDR_DQS0P
+Mcu.Pin25=PE0
+Mcu.Pin26=PD4
+Mcu.Pin27=PD5
+Mcu.Pin28=PD0
+Mcu.Pin29=PA9
+Mcu.Pin3=PD3
+Mcu.Pin30=PB3
+Mcu.Pin31=PC7
+Mcu.Pin32=PC11
+Mcu.Pin33=JTMS-SWDIO
+Mcu.Pin34=DDR_RESETN
+Mcu.Pin35=DDR_DQM0
+Mcu.Pin36=DDR_DQ2
+Mcu.Pin37=DDR_DQ6
+Mcu.Pin38=PG12
+Mcu.Pin39=PE11
+Mcu.Pin4=PC8
+Mcu.Pin40=DDR_DQ4
+Mcu.Pin41=DDR_DQ5
+Mcu.Pin42=PE13
+Mcu.Pin43=DDR_A13
+Mcu.Pin44=DDR_A9
+Mcu.Pin45=PC15-OSC32_OUT
+Mcu.Pin46=DDR_A2
+Mcu.Pin47=DDR_A3
+Mcu.Pin48=PC14-OSC32_IN
+Mcu.Pin49=PC13
+Mcu.Pin5=PE4
+Mcu.Pin50=DDR_A0
+Mcu.Pin51=DDR_BA0
+Mcu.Pin52=PH0-OSC_IN
+Mcu.Pin53=DDR_BA2
+Mcu.Pin54=DDR_ODT
+Mcu.Pin55=PH1-OSC_OUT
+Mcu.Pin56=DDR_CSN
+Mcu.Pin57=DDR_WEN
+Mcu.Pin58=DDR_CASN
+Mcu.Pin59=DDR_CLKN
+Mcu.Pin6=JTDO-TRACESWO
+Mcu.Pin60=PA14
+Mcu.Pin61=PA13
+Mcu.Pin62=DDR_CLKP
+Mcu.Pin63=DDR_A10
+Mcu.Pin64=DDR_A12
+Mcu.Pin65=DDR_A1
+Mcu.Pin66=PA0
+Mcu.Pin67=DDR_A14
+Mcu.Pin68=DDR_A11
+Mcu.Pin69=PE2
+Mcu.Pin7=JTCK-SWCLK
+Mcu.Pin70=PC2
+Mcu.Pin71=PC3
+Mcu.Pin72=DDR_CKE
+Mcu.Pin73=DDR_BA1
+Mcu.Pin74=PG14
+Mcu.Pin75=PG13
+Mcu.Pin76=DDR_A4
+Mcu.Pin77=DDR_DQ8
+Mcu.Pin78=PC1
+Mcu.Pin79=PA2
+Mcu.Pin8=DDR_DQ0
+Mcu.Pin80=DDR_A8
+Mcu.Pin81=DDR_DQ13
+Mcu.Pin82=DDR_DQ10
+Mcu.Pin83=PB1
+Mcu.Pin84=PB11
+Mcu.Pin85=PC0
+Mcu.Pin86=PG11
+Mcu.Pin87=PF6
+Mcu.Pin88=PE8
+Mcu.Pin89=PD13
+Mcu.Pin9=DDR_DQ1
+Mcu.Pin90=PA11
+Mcu.Pin91=PA10
+Mcu.Pin92=DDR_DQ14
+Mcu.Pin93=DDR_DQS1N
+Mcu.Pin94=DDR_DQ9
+Mcu.Pin95=PC5
+Mcu.Pin96=PC4
+Mcu.Pin97=PB12
+Mcu.Pin98=PG8
+Mcu.Pin99=PE7
+Mcu.PinsNb=148
+Mcu.ThirdPartyNb=0
+Mcu.UserConstants=
+Mcu.UserName=STM32MP157CADx
+MxCube.Version=4.99.1
+MxDb.Version=DB.4.0.270
+NJTRST.Mode=JTAG_5_pins
+NJTRST.Signal=SYS_JTRST
+NVIC.BusFault_IRQn=true\:0\:0\:false\:false\:true\:false
+NVIC.DebugMonitor_IRQn=true\:0\:0\:false\:false\:true\:false
+NVIC.HardFault_IRQn=true\:0\:0\:false\:false\:true\:false
+NVIC.MemoryManagement_IRQn=true\:0\:0\:false\:false\:true\:false
+NVIC.NonMaskableInt_IRQn=true\:0\:0\:false\:false\:true\:false
+NVIC.PendSV_IRQn=true\:0\:0\:false\:false\:true\:false
+NVIC.PriorityGroup=NVIC_PRIORITYGROUP_4
+NVIC.SVCall_IRQn=true\:0\:0\:false\:false\:true\:false
+NVIC.SysTick_IRQn=true\:0\:0\:false\:false\:true\:false
+NVIC.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:false
+PA0.Locked=true
+PA0.Mode=IN16-Single-Ended
+PA0.Signal=ADC1_INP16
+PA10.Locked=true
+PA10.Mode=Ext_Phy_OTG/Dual-Role-Device
+PA10.Signal=USB_OTG_HS_ID
+PA11.GPIOParameters=GPIO_Label
+PA11.GPIO_Label=SPI2_NSS
+PA11.Locked=true
+PA11.Signal=GPIO_Output
+PA13.GPIOParameters=GPIO_Label
+PA13.GPIO_Label=GPIO_PA13
+PA13.Locked=true
+PA13.Signal=GPIO_Output
+PA14.GPIOParameters=GPIO_Label
+PA14.GPIO_Label=GPIO_PA14
+PA14.Locked=true
+PA14.Signal=GPIO_Output
+PA15.Signal=GPIO_Output
+PA2.Locked=true
+PA2.Mode=RMII (Reduced MII)
+PA2.Signal=ETH1_MDIO
+PA6.Locked=true
+PA6.Signal=ADCx_INP3
+PA7.Locked=true
+PA7.Mode=RMII (Reduced MII)
+PA7.Signal=ETH1_CRS_DV
+PA8.GPIOParameters=GPIO_Speed
+PA8.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH
+PA8.Locked=true
+PA8.Signal=S_TIM1_CH1
+PA9.Locked=true
+PA9.Mode=Full_Duplex_Master
+PA9.Signal=SPI2_SCK
+PB1.Locked=true
+PB1.Signal=ADCx_INP5
+PB11.Locked=true
+PB11.Mode=RMII (Reduced MII)
+PB11.Signal=ETH1_TX_EN
+PB12.Locked=true
+PB12.Mode=RMII (Reduced MII)
+PB12.Signal=ETH1_TXD0
+PB13.Locked=true
+PB13.Mode=RMII (Reduced MII)
+PB13.Signal=ETH1_TXD1
+PB2.GPIOParameters=GPIO_PuPd
+PB2.GPIO_PuPd=GPIO_PULLUP
+PB2.Locked=true
+PB2.Mode=Asynchronous
+PB2.Signal=UART4_RX
+PB3.Locked=true
+PB3.Signal=GPIO_Input
+PB4.GPIOParameters=GPIO_Label
+PB4.GPIO_Label=X9_PC6
+PB4.Locked=true
+PB4.Signal=GPIO_Input
+PB6.Locked=true
+PB6.Mode=Enable Chip Select for each bank
+PB6.Signal=QUADSPI_BK1_NCS
+PB7.Locked=true
+PB7.Mode=I2C
+PB7.Signal=I2C4_SDA
+PC0.Locked=true
+PC0.Mode=Enable Chip Select for each bank
+PC0.Signal=QUADSPI_BK2_NCS
+PC1.Locked=true
+PC1.Mode=RMII (Reduced MII)
+PC1.Signal=ETH1_MDC
+PC10.GPIOParameters=GPIO_PuPd
+PC10.GPIO_PuPd=GPIO_PULLUP
+PC10.Locked=true
+PC10.Mode=SD_4_bits_Wide_bus
+PC10.Signal=SDMMC1_D2
+PC11.GPIOParameters=GPIO_PuPd
+PC11.GPIO_PuPd=GPIO_PULLUP
+PC11.Locked=true
+PC11.Mode=SD_4_bits_Wide_bus
+PC11.Signal=SDMMC1_D3
+PC12.GPIOParameters=GPIO_PuPd
+PC12.GPIO_PuPd=GPIO_PULLUP
+PC12.Locked=true
+PC12.Mode=SD_4_bits_Wide_bus
+PC12.Signal=SDMMC1_CK
+PC13.GPIOParameters=GPIO_Label
+PC13.GPIO_Label=TP16
+PC13.Signal=GPIO_Output
+PC14-OSC32_IN.Locked=true
+PC14-OSC32_IN.Mode=LSE-External-Oscillator
+PC14-OSC32_IN.Signal=RCC_OSC32_IN
+PC15-OSC32_OUT.Locked=true
+PC15-OSC32_OUT.Mode=LSE-External-Oscillator
+PC15-OSC32_OUT.Signal=RCC_OSC32_OUT
+PC2.Locked=true
+PC2.Mode=Full_Duplex_Master
+PC2.Signal=SPI2_MISO
+PC3.Locked=true
+PC3.Mode=Full_Duplex_Master
+PC3.Signal=SPI2_MOSI
+PC4.Locked=true
+PC4.Mode=RMII (Reduced MII)
+PC4.Signal=ETH1_RXD0
+PC5.Locked=true
+PC5.Mode=RMII (Reduced MII)
+PC5.Signal=ETH1_RXD1
+PC6.Locked=true
+PC6.Signal=GPIO_Input
+PC7.GPIOParameters=GPIO_Label
+PC7.GPIO_Label=I2C2_INT
+PC7.Locked=true
+PC7.Signal=GPIO_Input
+PC8.GPIOParameters=GPIO_PuPd
+PC8.GPIO_PuPd=GPIO_PULLUP
+PC8.Locked=true
+PC8.Mode=SD_4_bits_Wide_bus
+PC8.Signal=SDMMC1_D0
+PC9.GPIOParameters=GPIO_PuPd
+PC9.GPIO_PuPd=GPIO_PULLUP
+PC9.Locked=true
+PC9.Mode=SD_4_bits_Wide_bus
+PC9.Signal=SDMMC1_D1
+PD0.Signal=FDCAN1_RX
+PD1.Signal=FDCAN1_TX
+PD13.Signal=GPIO_Output
+PD14.Signal=UART8_CTS
+PD15.GPIOParameters=GPIO_Label
+PD15.GPIO_Label=RESET_OUT
+PD15.Locked=true
+PD15.Signal=GPIO_Output
+PD2.GPIOParameters=GPIO_PuPd
+PD2.GPIO_PuPd=GPIO_PULLUP
+PD2.Locked=true
+PD2.Mode=SD_4_bits_Wide_bus
+PD2.Signal=SDMMC1_CMD
+PD3.GPIOParameters=GPIO_PuPd
+PD3.GPIO_PuPd=GPIO_PULLDOWN
+PD3.Locked=true
+PD3.Mode=CTS_RTS
+PD3.Signal=USART2_CTS
+PD4.GPIOParameters=GPIO_PuPd
+PD4.GPIO_PuPd=GPIO_PULLDOWN
+PD4.Locked=true
+PD4.Mode=CTS_RTS
+PD4.Signal=USART2_RTS
+PD5.Locked=true
+PD5.Mode=Asynchronous
+PD5.Signal=USART2_TX
+PD6.GPIOParameters=GPIO_PuPd
+PD6.GPIO_PuPd=GPIO_PULLUP
+PD6.Locked=true
+PD6.Mode=Asynchronous
+PD6.Signal=USART2_RX
+PD7.Locked=true
+PD7.Mode=I2C
+PD7.Signal=I2C2_SCL
+PE0.Signal=UART8_RX
+PE1.Signal=UART8_TX
+PE10.Locked=true
+PE10.Mode=Dual Bank
+PE10.Signal=QUADSPI_BK2_IO3
+PE11.GPIOParameters=GPIO_Speed
+PE11.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH
+PE11.Locked=true
+PE11.Signal=S_TIM1_CH2
+PE13.GPIOParameters=GPIO_Speed
+PE13.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH
+PE13.Locked=true
+PE13.Signal=S_TIM1_CH3
+PE14.GPIOParameters=GPIO_Speed
+PE14.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH
+PE14.Locked=true
+PE14.Signal=S_TIM1_CH4
+PE2.Locked=true
+PE2.Mode=I2C
+PE2.Signal=I2C4_SCL
+PE4.Signal=GPIO_Output
+PE5.Signal=GPIO_Output
+PE6.Signal=GPIO_Output
+PE7.Locked=true
+PE7.Mode=Dual Bank
+PE7.Signal=QUADSPI_BK2_IO0
+PE8.Locked=true
+PE8.Mode=Dual Bank
+PE8.Signal=QUADSPI_BK2_IO1
+PE9.Locked=true
+PE9.Mode=Dual Bank
+PE9.Signal=QUADSPI_BK2_IO2
+PF10.Locked=true
+PF10.Mode=Dual Bank
+PF10.Signal=QUADSPI_CLK
+PF11.Locked=true
+PF11.Mode=IN2-Single-Ended
+PF11.Signal=ADC1_INP2
+PF6.Locked=true
+PF6.Mode=Dual Bank
+PF6.Signal=QUADSPI_BK1_IO3
+PF7.Locked=true
+PF7.Mode=Dual Bank
+PF7.Signal=QUADSPI_BK1_IO2
+PF8.Locked=true
+PF8.Mode=Dual Bank
+PF8.Signal=QUADSPI_BK1_IO0
+PF9.Locked=true
+PF9.Mode=Dual Bank
+PF9.Signal=QUADSPI_BK1_IO1
+PG11.GPIOParameters=GPIO_PuPd
+PG11.GPIO_PuPd=GPIO_PULLUP
+PG11.Locked=true
+PG11.Mode=Asynchronous
+PG11.Signal=UART4_TX
+PG12.Signal=GPIO_Output
+PG13.Signal=GPIO_Output
+PG14.Signal=USART6_TX
+PG15.Locked=true
+PG15.Mode=I2C
+PG15.Signal=I2C2_SDA
+PG7.Signal=UART8_RTS
+PG8.Locked=true
+PG8.Mode=ETH Clock Output (PHY without Quartz)
+PG8.Signal=ETH1_CLK
+PG9.Signal=USART6_RX
+PH0-OSC_IN.Locked=true
+PH0-OSC_IN.Mode=HSE-External-Oscillator
+PH0-OSC_IN.Signal=RCC_OSC_IN
+PH1-OSC_OUT.Locked=true
+PH1-OSC_OUT.Mode=HSE-External-Oscillator
+PH1-OSC_OUT.Signal=RCC_OSC_OUT
+PinOutPanel.CurrentBGAView=Top
+PinOutPanel.RotationAngle=0
+ProjectManager.AskForMigrate=true
+ProjectManager.BackupPrevious=false
+ProjectManager.CompilerOptimize=3
+ProjectManager.ComputerToolchain=false
+ProjectManager.CoupleFile=false
+ProjectManager.CustomerFirmwarePackage=
+ProjectManager.DefaultFWLocation=true
+ProjectManager.DeletePrevious=true
+ProjectManager.DeviceId=STM32MP157CADx
+ProjectManager.DeviceTreeLocation=/home/user/gen/src/yocto-genisys/layers/meta-exceet-stm32mp/conf/machine/dts/
+ProjectManager.FirmwarePackage=STM32Cube FW_MP1 V0.4.0
+ProjectManager.FreePins=false
+ProjectManager.HalAssertFull=false
+ProjectManager.HeapSize=0x200
+ProjectManager.KeepUserCode=true
+ProjectManager.LastFirmware=true
+ProjectManager.LibraryCopy=1
+ProjectManager.MainLocation=Src
+ProjectManager.PreviousToolchain=SW4STM32
+ProjectManager.ProjectBuild=false
+ProjectManager.ProjectFileName=t1000-mini.ioc
+ProjectManager.ProjectName=t1000-mini
+ProjectManager.StackSize=0x400
+ProjectManager.TargetToolchain=SW4STM32
+ProjectManager.ToolChainLocation=
+ProjectManager.UnderRoot=true
+ProjectManager.functionlistsort=1-MX_GPIO_Init-GPIO-false-HAL-true,2-SystemClock_Config-RCC-false-HAL-false
+RCC.ADCCLockSelection=RCC_ADCCLKSOURCE_PER
+RCC.ADCFreq_Value=24000000
+RCC.AHB1234Freq_Value=196000000
+RCC.AHB123Freq_Value=193500000
+RCC.AHB12Freq_Value=64000000
+RCC.AHB4Freq_Value=64000000
+RCC.APB1DIV=RCC_APB1_DIV2
+RCC.APB1Freq_Value=98000000
+RCC.APB2DIV=RCC_APB2_DIV2
+RCC.APB2Freq_Value=98000000
+RCC.APB3DIV=RCC_APB3_DIV2
+RCC.APB3Freq_Value=98000000
+RCC.APB4DIV=RCC_APB4_DIV2
+RCC.APB4Freq_Value=132000000
+RCC.APB5DIV=RCC_APB5_DIV4
+RCC.APB5DIVClockFreq_Value=66000000
+RCC.AXICLKFreq_VALUE=264000000
+RCC.AXICLKSource=RCC_AXISSOURCE_PLL2
+RCC.AXIClockFreq_Value=64000000
+RCC.AXIDIVFreq_Value=264000000
+RCC.CECFreq_Value=32768
+RCC.CKPERCLKFreq_VALUE=24000000
+RCC.CKPERCLKSource=RCC_CKPERCLKSOURCE_HSE
+RCC.CKPERFreq_Value=64000000
+RCC.CSI_VALUE=4000000
+RCC.CortexFreq_Value=196000000
+RCC.CpuClockFreq_Value=64000000
+RCC.D1CPREFreq_Value=64000000
+RCC.DACCLKFreq_VALUE=32000
+RCC.DDRCFreq_Value=528000000
+RCC.DDRPERFMFreq_Value=528000000
+RCC.DDRPHYFreq_Value=528000000
+RCC.DFSDFAFreq_Value=50000000
+RCC.DFSDMACLkFreq_Value=50390625
+RCC.DFSDMFreq_Value=196000000
+RCC.DIVM1=3
+RCC.DIVM2=3
+RCC.DIVM3=3
+RCC.DIVM4=6
+RCC.DIVN1=81
+RCC.DIVN2=66
+RCC.DIVN3=98
+RCC.DIVN4=125
+RCC.DIVP1Freq_Value=648000000
+RCC.DIVP2Freq_Value=264000000
+RCC.DIVP3=4
+RCC.DIVP3Freq_Value=196000000
+RCC.DIVP4=10
+RCC.DIVP4Freq_Value=50000000
+RCC.DIVQ1=1
+RCC.DIVQ1Freq_Value=648000000
+RCC.DIVQ2=1
+RCC.DIVQ2Freq_Value=528000000
+RCC.DIVQ3=16
+RCC.DIVQ3Freq_Value=49000000
+RCC.DIVQ4=10
+RCC.DIVQ4Freq_Value=50000000
+RCC.DIVR1=1
+RCC.DIVR1Freq_Value=648000000
+RCC.DIVR2=1
+RCC.DIVR2Freq_Value=528000000
+RCC.DIVR3=8
+RCC.DIVR3Freq_Value=98000000
+RCC.DIVR4=10
+RCC.DIVR4Freq_Value=50000000
+RCC.DSIFreq_Value=60000000
+RCC.DSIRXEscFreq_Value=60000000
+RCC.DSITXEscFreq_Value=15000000
+RCC.DSI_VALUE=60000000
+RCC.ETHFreq_Value=50000000
+RCC.FCLKFreq_Value=196000000
+RCC.FDCANFreq_Value=24000000
+RCC.FMCFreq_Value=264000000
+RCC.FamilyName=M
+RCC.HCLK3ClockFreq_Value=64000000
+RCC.HCLK4ClockFreq_Value=193500000
+RCC.HCLKFreq_Value=64000000
+RCC.HSE_VALUE=24000000
+RCC.HSIDivClkFreq_Value=64000000
+RCC.HSI_VALUE=64000000
+RCC.Hclk5DIVFreq_Value=264000000
+RCC.Hclk6DIVFreq_Value=264000000
+RCC.I2C123Freq_Value=64000000
+RCC.I2C12CLockSelection=RCC_I2C12CLKSOURCE_HSI
+RCC.I2C12Freq_Value=64000000
+RCC.I2C35Freq_Value=98000000
+RCC.I2C46CLockSelection=RCC_I2C46CLKSOURCE_HSI
+RCC.I2C46Freq_Value=64000000
+RCC.I2C4Freq_Value=64000000
+RCC.IPParameters=ADCCLockSelection,ADCFreq_Value,AHB1234Freq_Value,AHB123Freq_Value,AHB12Freq_Value,AHB4Freq_Value,APB1DIV,APB1Freq_Value,APB2DIV,APB2Freq_Value,APB3DIV,APB3Freq_Value,APB4DIV,APB4Freq_Value,APB5DIV,APB5DIVClockFreq_Value,AXICLKFreq_VALUE,AXICLKSource,AXIClockFreq_Value,AXIDIVFreq_Value,CECFreq_Value,CKPERCLKFreq_VALUE,CKPERCLKSource,CKPERFreq_Value,CSI_VALUE,CortexFreq_Value,CpuClockFreq_Value,D1CPREFreq_Value,DACCLKFreq_VALUE,DDRCFreq_Value,DDRPERFMFreq_Value,DDRPHYFreq_Value,DFSDFAFreq_Value,DFSDMACLkFreq_Value,DFSDMFreq_Value,DIVM1,DIVM2,DIVM3,DIVM4,DIVN1,DIVN2,DIVN3,DIVN4,DIVP1Freq_Value,DIVP2Freq_Value,DIVP3,DIVP3Freq_Value,DIVP4,DIVP4Freq_Value,DIVQ1,DIVQ1Freq_Value,DIVQ2,DIVQ2Freq_Value,DIVQ3,DIVQ3Freq_Value,DIVQ4,DIVQ4Freq_Value,DIVR1,DIVR1Freq_Value,DIVR2,DIVR2Freq_Value,DIVR3,DIVR3Freq_Value,DIVR4,DIVR4Freq_Value,DSIFreq_Value,DSIRXEscFreq_Value,DSITXEscFreq_Value,DSI_VALUE,ETHFreq_Value,FCLKFreq_Value,FDCANFreq_Value,FMCFreq_Value,FamilyName,HCLK3ClockFreq_Value,HCLK4ClockFreq_Value,HCLKFreq_Value,HSE_VALUE,HSIDivClkFreq_Value,HSI_VALUE,Hclk5DIVFreq_Value,Hclk6DIVFreq_Value,I2C123Freq_Value,I2C12CLockSelection,I2C12Freq_Value,I2C35Freq_Value,I2C46CLockSelection,I2C46Freq_Value,I2C4Freq_Value,LPTIM1Freq_Value,LPTIM23Freq_Value,LPTIM2Freq_Value,LPTIM345Freq_Value,LPTIM45Freq_Value,LPUART1Freq_Value,LSI_VALUE,LTDCFreq_Value,MCO1PinFreq_Value,MCO2PinFreq_Value,MCUCLKFreq_VALUE,MCUCLKSource,MCUClockFreq_Value,MPUCLKFreq_VALUE,MPUCLKSource,PLL12Source,PLL1FRACV,PLL1MODE,PLL2FRACV,PLL2MODE,PLL3FRACV,PLL3MODE,PLL3Source,PLL4PDSIFreq_Value,PLL4Source,PLLDSIFreq_Value,PLLDSIVCOFreq_Value,PLLSource,PLLSourceVirtual,PLLSourceVirtualString,PUBLFreq_Value,QSPIFreq_Value,RCC_RTC_Clock_Source_FROM_HSE,RTCClockSelection,RTCFreq_Value,SAI1Freq_Value,SAI23Freq_Value,SAI2CLockSelection,SAI2Freq_Value,SAI3Freq_Value,SAI4AFreq_Value,SAI4BFreq_Value,SAI4CLockSelection,SAI4Freq_Value,SDMMC12CLockSelection,SDMMC12Freq_Value,SDMMC3Freq_Value,SDMMCFreq_Value,SPDIFCLockSelection,SPDIFRXFreq_Value,SPI123Freq_Value,SPI1Freq_Value,SPI23CLockSelection,SPI23Freq_Value,SPI45Freq_Value,SPI6Freq_Value,STGENCLockSelection,STGENFreq_Value,SWPMI1Freq_Value,SYSCLKFreq_VALUE,Tim1OutputFreq_Value,Tim2OutputFreq_Value,UART78CLockSelection,UART78Freq_Value,USART16Freq_Value,USART1Freq_Value,USART234578Freq_Value,USART24CLockSelection,USART24Freq_Value,USART35CLockSelection,USART35Freq_Value,USART6CLockSelection,USART6Freq_Value,USBFreq_Value,USBOCLKSource,USBOFSFreq_Value,USBOHSFreq_Value,USBPHYCLKSource,USBPHYFreq_Value,VCO1OutputFreq_Value,VCO2OutputFreq_Value,VCO3OutputFreq_Value,VCO4OutputFreq_Value,VCOInput1Freq_Value,VCOInput2Freq_Value,VCOInput3Freq_Value,VCOInput4Freq_Value
+RCC.LPTIM1Freq_Value=98000000
+RCC.LPTIM23Freq_Value=98000000
+RCC.LPTIM2Freq_Value=64000000
+RCC.LPTIM345Freq_Value=64000000
+RCC.LPTIM45Freq_Value=98000000
+RCC.LPUART1Freq_Value=64000000
+RCC.LSI_VALUE=32000
+RCC.LTDCFreq_Value=50000000
+RCC.MCO1PinFreq_Value=64000000
+RCC.MCO2PinFreq_Value=648000000
+RCC.MCUCLKFreq_VALUE=196000000
+RCC.MCUCLKSource=RCC_MCUSSOURCE_PLL3
+RCC.MCUClockFreq_Value=196000000
+RCC.MPUCLKFreq_VALUE=648000000
+RCC.MPUCLKSource=RCC_MPUSOURCE_PLL1
+RCC.PLL12Source=RCC_PLL12SOURCE_HSE
+RCC.PLL1FRACV=0x800
+RCC.PLL1MODE=RCC_PLL_FRACTIONAL
+RCC.PLL2FRACV=0x1400
+RCC.PLL2MODE=RCC_PLL_FRACTIONAL
+RCC.PLL3FRACV=0x9ba
+RCC.PLL3MODE=RCC_PLL_FRACTIONAL
+RCC.PLL3Source=RCC_PLL3SOURCE_HSE
+RCC.PLL4PDSIFreq_Value=50000000
+RCC.PLL4Source=RCC_PLL4SOURCE_HSE
+RCC.PLLDSIFreq_Value=480000000
+RCC.PLLDSIVCOFreq_Value=960000000
+RCC.PLLSource=RCC_PLL3SOURCE_HSI
+RCC.PLLSourceVirtual=RCC_PLL3SOURCE_HSI
+RCC.PLLSourceVirtualString=RCC_PLL3SOURCE_HSI
+RCC.PUBLFreq_Value=528000000
+RCC.QSPIFreq_Value=264000000
+RCC.RCC_RTC_Clock_Source_FROM_HSE=24
+RCC.RTCClockSelection=RCC_RTCCLKSOURCE_LSE
+RCC.RTCFreq_Value=32768
+RCC.SAI1Freq_Value=50000000
+RCC.SAI23Freq_Value=50390625
+RCC.SAI2CLockSelection=RCC_SAI2CLKSOURCE_PLL3_Q
+RCC.SAI2Freq_Value=49000000
+RCC.SAI3Freq_Value=50000000
+RCC.SAI4AFreq_Value=50390625
+RCC.SAI4BFreq_Value=50390625
+RCC.SAI4CLockSelection=RCC_SAI4CLKSOURCE_PLL3_Q
+RCC.SAI4Freq_Value=49000000
+RCC.SDMMC12CLockSelection=RCC_SDMMC12CLKSOURCE_PLL3
+RCC.SDMMC12Freq_Value=98000000
+RCC.SDMMC3Freq_Value=196000000
+RCC.SDMMCFreq_Value=50390625
+RCC.SPDIFCLockSelection=RCC_SPDIFRXCLKSOURCE_PLL3
+RCC.SPDIFRXFreq_Value=49000000
+RCC.SPI123Freq_Value=50390625
+RCC.SPI1Freq_Value=50000000
+RCC.SPI23CLockSelection=RCC_SPI23CLKSOURCE_PLL3_Q
+RCC.SPI23Freq_Value=49000000
+RCC.SPI45Freq_Value=98000000
+RCC.SPI6Freq_Value=66000000
+RCC.STGENCLockSelection=RCC_STGENCLKSOURCE_HSE
+RCC.STGENFreq_Value=24000000
+RCC.SWPMI1Freq_Value=64000000
+RCC.SYSCLKFreq_VALUE=64000000
+RCC.Tim1OutputFreq_Value=196000000
+RCC.Tim2OutputFreq_Value=196000000
+RCC.UART78CLockSelection=RCC_UART78CLKSOURCE_HSI
+RCC.UART78Freq_Value=64000000
+RCC.USART16Freq_Value=64000000
+RCC.USART1Freq_Value=66000000
+RCC.USART234578Freq_Value=64000000
+RCC.USART24CLockSelection=RCC_UART24CLKSOURCE_HSI
+RCC.USART24Freq_Value=64000000
+RCC.USART35CLockSelection=RCC_UART35CLKSOURCE_HSI
+RCC.USART35Freq_Value=64000000
+RCC.USART6CLockSelection=RCC_USART6CLKSOURCE_HSI
+RCC.USART6Freq_Value=64000000
+RCC.USBFreq_Value=50390625
+RCC.USBOCLKSource=RCC_USBOCLKSOURCE_PHY
+RCC.USBOFSFreq_Value=48000000
+RCC.USBOHSFreq_Value=48000000
+RCC.USBPHYCLKSource=RCC_USBPHYCLKSOURCE_HSE
+RCC.USBPHYFreq_Value=24000000
+RCC.VCO1OutputFreq_Value=1296000000
+RCC.VCO2OutputFreq_Value=1056000000
+RCC.VCO3OutputFreq_Value=784000000
+RCC.VCO4OutputFreq_Value=500000000
+RCC.VCOInput1Freq_Value=8000000
+RCC.VCOInput2Freq_Value=8000000
+RCC.VCOInput3Freq_Value=8000000
+RCC.VCOInput4Freq_Value=4000000
+RTC.Alarm=RTC_ALARM_A
+RTC.IPParameters=Alarm
+SH.ADCx_INP3.0=ADC1_INP3,IN3-Single-Ended
+SH.ADCx_INP3.ConfNb=1
+SH.ADCx_INP5.0=ADC1_INP5,IN5-Single-Ended
+SH.ADCx_INP5.ConfNb=1
+SH.S_TIM1_CH1.0=TIM1_CH1,PWM Generation1 CH1
+SH.S_TIM1_CH1.ConfNb=1
+SH.S_TIM1_CH2.0=TIM1_CH2,PWM Generation2 CH2
+SH.S_TIM1_CH2.ConfNb=1
+SH.S_TIM1_CH3.0=TIM1_CH3,PWM Generation3 CH3
+SH.S_TIM1_CH3.ConfNb=1
+SH.S_TIM1_CH4.0=TIM1_CH4,PWM Generation4 CH4
+SH.S_TIM1_CH4.ConfNb=1
+SPI2.CalculateBaudRate=24.5 MBits/s
+SPI2.Direction=SPI_DIRECTION_2LINES
+SPI2.IPParameters=VirtualType,Mode,Direction,CalculateBaudRate
+SPI2.Mode=SPI_MODE_MASTER
+SPI2.VirtualType=VM_MASTER
+TIM1.Channel-PWM\ Generation1\ CH1=TIM_CHANNEL_1
+TIM1.Channel-PWM\ Generation2\ CH2=TIM_CHANNEL_2
+TIM1.Channel-PWM\ Generation3\ CH3=TIM_CHANNEL_3
+TIM1.Channel-PWM\ Generation4\ CH4=TIM_CHANNEL_4
+TIM1.IPParameters=Channel-PWM Generation1 CH1,Channel-PWM Generation2 CH2,Channel-PWM Generation3 CH3,Channel-PWM Generation4 CH4
+USART2.IPParameters=VirtualMode-Asynchronous
+USART2.VirtualMode-Asynchronous=VM_ASYNC
+USB_DM1.Mode=Enable
+USB_DM1.Signal=USBH_HS1_DM
+USB_DM2.Mode=Ext_Phy_OTG/Dual-Role-Device
+USB_DM2.Signal=USB_OTG_HS_DM
+USB_DP1.Mode=Enable
+USB_DP1.Signal=USBH_HS1_DP
+USB_DP2.Mode=Ext_Phy_OTG/Dual-Role-Device
+USB_DP2.Signal=USB_OTG_HS_DP
+VP_DDR_DDR3.Mode=DDR3
+VP_DDR_DDR3.Signal=DDR_DDR3
+VP_DDR_DDR3_16_4Gb.Mode=4Gb_16bits
+VP_DDR_DDR3_16_4Gb.Signal=DDR_DDR3_16_4Gb
+VP_DDR_DDR_16_bits.Mode=16bits
+VP_DDR_DDR_16_bits.Signal=DDR_DDR_16_bits
+VP_DMA_VS_DMA1_A7NS.Mode=Cortex-A7 non secure
+VP_DMA_VS_DMA1_A7NS.Signal=DMA_VS_DMA1_A7NS
+VP_DMA_VS_DMA2_M4.Mode=Cortex-M4
+VP_DMA_VS_DMA2_M4.Signal=DMA_VS_DMA2_M4
+VP_RTC_VS_RTC_Activate.Mode=RTC_Enabled
+VP_RTC_VS_RTC_Activate.Signal=RTC_VS_RTC_Activate
+VP_RTC_VS_RTC_Alarm_A_Intern.Mode=Alarm A
+VP_RTC_VS_RTC_Alarm_A_Intern.Signal=RTC_VS_RTC_Alarm_A_Intern
+VP_RTC_VS_RTC_Calendar.Mode=RTC_Calendar
+VP_RTC_VS_RTC_Calendar.Signal=RTC_VS_RTC_Calendar
+VP_RTC_VS_RTC_WakeUp_intern.Mode=WakeUp
+VP_RTC_VS_RTC_WakeUp_intern.Signal=RTC_VS_RTC_WakeUp_intern
+board=custom
diff --git a/conf/machine/cubemx/t1000-s.ioc b/conf/machine/cubemx/t1000-s.ioc
new file mode 100644
index 0000000000000000000000000000000000000000..55c62b148778171f20e2df433906450171c2c378
--- /dev/null
+++ b/conf/machine/cubemx/t1000-s.ioc
@@ -0,0 +1,968 @@
+#MicroXplorer Configuration settings - do not modify
+ADC1.BoostMode=ENABLE
+ADC1.Channel-2\#ChannelRegularConversion=ADC_CHANNEL_16
+ADC1.ClockPrescaler=ADC_CLOCK_ASYNC_DIV1
+ADC1.ContinuousConvMode=DISABLE
+ADC1.ConversionDataManagement=ADC_CONVERSIONDATA_DR
+ADC1.DiscontinuousConvMode=DISABLE
+ADC1.EOCSelection=ADC_EOC_SINGLE_CONV
+ADC1.EnableAnalogWatchDog1=false
+ADC1.EnableAnalogWatchDog2=false
+ADC1.EnableAnalogWatchDog3=false
+ADC1.EnableInjectedConversion=DISABLE
+ADC1.EnableRegularConversion=ENABLE
+ADC1.ExternalTrigConv=ADC_SOFTWARE_START
+ADC1.ExternalTrigConvEdge=ADC_EXTERNALTRIGCONVEDGE_NONE
+ADC1.IPParameters=Rank-2\#ChannelRegularConversion,Channel-2\#ChannelRegularConversion,SamplingTime-2\#ChannelRegularConversion,OffsetNumber-2\#ChannelRegularConversion,NbrOfConversionFlag,ClockPrescaler,Resolution,ScanConvMode,ContinuousConvMode,DiscontinuousConvMode,EOCSelection,Overrun,BoostMode,ConversionDataManagement,LowPowerAutoWait,EnableRegularConversion,LeftBitShift,OversamplingMode,NbrOfConversion,ExternalTrigConv,ExternalTrigConvEdge,EnableInjectedConversion,EnableAnalogWatchDog1,EnableAnalogWatchDog2,EnableAnalogWatchDog3,master
+ADC1.LeftBitShift=ADC_LEFTBITSHIFT_NONE
+ADC1.LowPowerAutoWait=DISABLE
+ADC1.NbrOfConversion=1
+ADC1.NbrOfConversionFlag=1
+ADC1.OffsetNumber-2\#ChannelRegularConversion=ADC_OFFSET_NONE
+ADC1.Overrun=ADC_OVR_DATA_PRESERVED
+ADC1.OversamplingMode=DISABLE
+ADC1.Rank-2\#ChannelRegularConversion=1
+ADC1.Resolution=ADC_RESOLUTION_16B
+ADC1.SamplingTime-2\#ChannelRegularConversion=ADC_SAMPLETIME_1CYCLE_5
+ADC1.ScanConvMode=ADC_SCAN_DISABLE
+ADC1.master=1
+Boot\ ROM.IPs=SDMMC1,UART4
+Boot\ loader.IPs=RCC,UART4,QUADSPI,SDMMC1,SDMMC2,USB_OTG_HS
+Cortex-A7\ non\ secure.IPs=DDR\:I,RCC\:I,RTC\:I,SYS\:I,QUADSPI\:I,ETH1\:I,UART4\:I,SDMMC2\:I,SDMMC1\:I,FDCAN1\:I,USART2\:I,USART6\:I,I2C2\:I,I2C4\:I,ADC1\:I,ADC2\:I,USBH_HS1\:I,USB_OTG_HS\:I,DSIHOST\:I,LTDC\:I,I2S2\:I,TIM4\:I,DMA1\:I
+Cortex-M4.IPs=RCC,WWDG1\:I,NVIC\:I,DMA2\:I
+DDR.ADDRMAP1=0x00070707
+DDR.ADDRMAP3=0x1F000000
+DDR.ADDRMAP5=0x06060606
+DDR.ADDRMAP6=0x0F060606
+DDR.DFITMG0=0x02050105
+DDR.DRAMTMG2=0x0607080F
+DDR.DRAMTMG4=0x07040607
+DDR.DRAMTMG5=0x06060403
+DDR.DTPR0=0x36D477D0
+DDR.DTPR1=0x098A00D8
+DDR.IPParameters=addrmap_col_b9,addrmap_col_b10,addrmap_col_b11,addrmap_bank_b0,addrmap_bank_b1,addrmap_bank_b2,addrmap_row_b0,addrmap_row_b1,addrmap_row_b2_10,addrmap_row_b11,addrmap_row_b12,addrmap_row_b13,addrmap_row_b14,addrmap_row_b15,MSTR,RFSHTMG,DRAMTMG2,DRAMTMG4,DRAMTMG5,DFITMG0,PCFGQOS1_1,ADDRMAP1,ADDRMAP3,ADDRMAP5,ADDRMAP6,PTR0,PTR1,PTR2,DTPR0,DTPR1,ZQ0CR1
+DDR.MSTR=0x00041401
+DDR.PCFGQOS1_1=0x00800000
+DDR.PTR0=0x0022A41B
+DDR.PTR1=0x047C0740
+DDR.PTR2=0x042D9C80
+DDR.RFSHTMG=0x0080008A
+DDR.ZQ0CR1=0x00000038
+DDR.addrmap_bank_b0=7
+DDR.addrmap_bank_b1=7
+DDR.addrmap_bank_b2=7
+DDR.addrmap_col_b10=31
+DDR.addrmap_col_b11=31
+DDR.addrmap_col_b9=31
+DDR.addrmap_row_b0=6
+DDR.addrmap_row_b1=6
+DDR.addrmap_row_b11=6
+DDR.addrmap_row_b12=6
+DDR.addrmap_row_b13=6
+DDR.addrmap_row_b14=6
+DDR.addrmap_row_b15=15
+DDR.addrmap_row_b2_10=6
+DDR_A0.Mode=DDR3
+DDR_A0.Signal=DDR_A0
+DDR_A1.Mode=DDR3
+DDR_A1.Signal=DDR_A1
+DDR_A10.Mode=DDR3
+DDR_A10.Signal=DDR_A10
+DDR_A11.Mode=DDR3
+DDR_A11.Signal=DDR_A11
+DDR_A12.Mode=4Gb_16bits
+DDR_A12.Signal=DDR_A12
+DDR_A13.Mode=4Gb_16bits
+DDR_A13.Signal=DDR_A13
+DDR_A14.Mode=4Gb_16bits
+DDR_A14.Signal=DDR_A14
+DDR_A2.Mode=DDR3
+DDR_A2.Signal=DDR_A2
+DDR_A3.Mode=DDR3
+DDR_A3.Signal=DDR_A3
+DDR_A4.Mode=DDR3
+DDR_A4.Signal=DDR_A4
+DDR_A5.Mode=DDR3
+DDR_A5.Signal=DDR_A5
+DDR_A6.Mode=DDR3
+DDR_A6.Signal=DDR_A6
+DDR_A7.Mode=DDR3
+DDR_A7.Signal=DDR_A7
+DDR_A8.Mode=DDR3
+DDR_A8.Signal=DDR_A8
+DDR_A9.Mode=DDR3
+DDR_A9.Signal=DDR_A9
+DDR_ATO.Mode=DDR3
+DDR_ATO.Signal=DDR_ATO
+DDR_BA0.Mode=DDR3
+DDR_BA0.Signal=DDR_BA0
+DDR_BA1.Mode=DDR3
+DDR_BA1.Signal=DDR_BA1
+DDR_BA2.Mode=DDR3
+DDR_BA2.Signal=DDR_BA2
+DDR_CASN.Mode=DDR3
+DDR_CASN.Signal=DDR_CASN
+DDR_CKE.Mode=DDR3
+DDR_CKE.Signal=DDR_CKE
+DDR_CLKN.Mode=DDR3
+DDR_CLKN.Signal=DDR_CLKN
+DDR_CLKP.Mode=DDR3
+DDR_CLKP.Signal=DDR_CLKP
+DDR_CSN.Mode=DDR3
+DDR_CSN.Signal=DDR_CSN
+DDR_DQ0.Mode=DDR3
+DDR_DQ0.Signal=DDR_DQ0
+DDR_DQ1.Mode=DDR3
+DDR_DQ1.Signal=DDR_DQ1
+DDR_DQ10.Mode=DDR3
+DDR_DQ10.Signal=DDR_DQ10
+DDR_DQ11.Mode=DDR3
+DDR_DQ11.Signal=DDR_DQ11
+DDR_DQ12.Mode=DDR3
+DDR_DQ12.Signal=DDR_DQ12
+DDR_DQ13.Mode=DDR3
+DDR_DQ13.Signal=DDR_DQ13
+DDR_DQ14.Mode=DDR3
+DDR_DQ14.Signal=DDR_DQ14
+DDR_DQ15.Mode=DDR3
+DDR_DQ15.Signal=DDR_DQ15
+DDR_DQ2.Mode=DDR3
+DDR_DQ2.Signal=DDR_DQ2
+DDR_DQ3.Mode=DDR3
+DDR_DQ3.Signal=DDR_DQ3
+DDR_DQ4.Mode=DDR3
+DDR_DQ4.Signal=DDR_DQ4
+DDR_DQ5.Mode=DDR3
+DDR_DQ5.Signal=DDR_DQ5
+DDR_DQ6.Mode=DDR3
+DDR_DQ6.Signal=DDR_DQ6
+DDR_DQ7.Mode=DDR3
+DDR_DQ7.Signal=DDR_DQ7
+DDR_DQ8.Mode=DDR3
+DDR_DQ8.Signal=DDR_DQ8
+DDR_DQ9.Mode=DDR3
+DDR_DQ9.Signal=DDR_DQ9
+DDR_DQM0.Mode=DDR3
+DDR_DQM0.Signal=DDR_DQM0
+DDR_DQM1.Mode=DDR3
+DDR_DQM1.Signal=DDR_DQM1
+DDR_DQS0N.Mode=DDR3
+DDR_DQS0N.Signal=DDR_DQS0N
+DDR_DQS0P.Mode=DDR3
+DDR_DQS0P.Signal=DDR_DQS0P
+DDR_DQS1N.Mode=DDR3
+DDR_DQS1N.Signal=DDR_DQS1N
+DDR_DQS1P.Mode=DDR3
+DDR_DQS1P.Signal=DDR_DQS1P
+DDR_DTO0.Mode=DDR3
+DDR_DTO0.Signal=DDR_DTO0
+DDR_DTO1.Mode=DDR3
+DDR_DTO1.Signal=DDR_DTO1
+DDR_ODT.Mode=DDR3
+DDR_ODT.Signal=DDR_ODT
+DDR_RASN.Mode=DDR3
+DDR_RASN.Signal=DDR_RASN
+DDR_RESETN.Mode=DDR3
+DDR_RESETN.Signal=DDR_RESETN
+DDR_VREF.Mode=DDR3
+DDR_VREF.Signal=DDR_VREF
+DDR_WEN.Mode=DDR3
+DDR_WEN.Signal=DDR_WEN
+DDR_ZQ.Mode=DDR3
+DDR_ZQ.Signal=DDR_ZQ
+File.Version=6
+I2S2.ErrorAudioFreq=-0.31 %
+I2S2.FullDuplexMode=I2S_MODE_MASTER_FD
+I2S2.IPParameters=Instance,VirtualMode,FullDuplexMode,RealAudioFreq,ErrorAudioFreq
+I2S2.Instance=SPI$Index
+I2S2.RealAudioFreq=7.975 KHz
+I2S2.VirtualMode=I2S_MODE_MASTER
+JTCK-SWCLK.Mode=JTAG_5_pins
+JTCK-SWCLK.Signal=SYS_JTCK-SWCLK
+JTDI.Mode=JTAG_5_pins
+JTDI.Signal=SYS_JTDI
+JTDO-TRACESWO.Mode=JTAG_5_pins
+JTDO-TRACESWO.Signal=SYS_JTDO-SWO
+JTMS-SWDIO.Mode=JTAG_5_pins
+JTMS-SWDIO.Signal=SYS_JTMS-SWDIO
+KeepUserPlacement=false
+Mcu.Context0=Boot ROM
+Mcu.Context1=Boot loader
+Mcu.Context2=Cortex-A7 non secure
+Mcu.Context3=Cortex-M4
+Mcu.ContextNb=4
+Mcu.Family=STM32MP1
+Mcu.IP0=ADC1
+Mcu.IP1=DDR
+Mcu.IP10=RCC
+Mcu.IP11=RTC
+Mcu.IP12=SDMMC1
+Mcu.IP13=SDMMC2
+Mcu.IP14=SYS
+Mcu.IP15=TIM4
+Mcu.IP16=UART4
+Mcu.IP17=USART2
+Mcu.IP18=USART6
+Mcu.IP19=USBH_HS1
+Mcu.IP2=ETH1
+Mcu.IP20=USB_OTG_HS
+Mcu.IP3=FDCAN1
+Mcu.IP4=I2C2
+Mcu.IP5=I2C4
+Mcu.IP6=I2S2
+Mcu.IP7=LTDC
+Mcu.IP8=NVIC
+Mcu.IP9=QUADSPI
+Mcu.IPNb=21
+Mcu.Name=STM32MP157CADx
+Mcu.Package=TFBGA257
+Mcu.Pin0=PD1
+Mcu.Pin1=PB7
+Mcu.Pin10=PG15
+Mcu.Pin100=PD13
+Mcu.Pin101=PD12
+Mcu.Pin102=PA11
+Mcu.Pin103=PA10
+Mcu.Pin104=DDR_DQ14
+Mcu.Pin105=DDR_DQS1N
+Mcu.Pin106=DDR_DQ9
+Mcu.Pin107=PC5
+Mcu.Pin108=PC4
+Mcu.Pin109=PB12
+Mcu.Pin11=PE6
+Mcu.Pin110=PB8
+Mcu.Pin111=PB5
+Mcu.Pin112=PG8
+Mcu.Pin113=PE7
+Mcu.Pin114=PF8
+Mcu.Pin115=PF9
+Mcu.Pin116=USB_DP2
+Mcu.Pin117=PG7
+Mcu.Pin118=PE10
+Mcu.Pin119=PB2
+Mcu.Pin12=PD7
+Mcu.Pin120=USB_DP1
+Mcu.Pin121=PA12
+Mcu.Pin122=DDR_DQ15
+Mcu.Pin123=DDR_DQM1
+Mcu.Pin124=DDR_DQS1P
+Mcu.Pin125=PA7
+Mcu.Pin126=PA6
+Mcu.Pin127=PF11
+Mcu.Pin128=PF7
+Mcu.Pin129=PG9
+Mcu.Pin13=PA15
+Mcu.Pin130=USB_DM2
+Mcu.Pin131=PB6
+Mcu.Pin132=USB_DM1
+Mcu.Pin133=DDR_VREF
+Mcu.Pin134=DDR_DQ12
+Mcu.Pin135=DDR_DQ11
+Mcu.Pin136=PE1
+Mcu.Pin137=PD10
+Mcu.Pin138=PE3
+Mcu.Pin139=PB14
+Mcu.Pin14=PG6
+Mcu.Pin140=PD2
+Mcu.Pin141=DDR_ZQ
+Mcu.Pin142=DDR_A7
+Mcu.Pin143=PD6
+Mcu.Pin144=PE14
+Mcu.Pin145=PC12
+Mcu.Pin146=PD9
+Mcu.Pin147=PD15
+Mcu.Pin148=DDR_DTO1
+Mcu.Pin149=DDR_A5
+Mcu.Pin15=PB4
+Mcu.Pin150=DDR_DTO0
+Mcu.Pin151=PD14
+Mcu.Pin152=DDR_RASN
+Mcu.Pin153=DDR_ATO
+Mcu.Pin154=DDR_A6
+Mcu.Pin155=PA5
+Mcu.Pin156=PA4
+Mcu.Pin157=PB13
+Mcu.Pin158=PE9
+Mcu.Pin159=PF10
+Mcu.Pin16=PE5
+Mcu.Pin160=VP_DDR_DDR3
+Mcu.Pin161=VP_DDR_DDR_16_bits
+Mcu.Pin162=VP_DDR_DDR3_16_4Gb
+Mcu.Pin163=VP_RTC_VS_RTC_Activate
+Mcu.Pin164=VP_DMA_VS_DMA1_A7NS
+Mcu.Pin165=VP_DMA_VS_DMA2_M4
+Mcu.Pin17=PA8
+Mcu.Pin18=PC9
+Mcu.Pin19=PC10
+Mcu.Pin2=PC6
+Mcu.Pin20=NJTRST
+Mcu.Pin21=JTDI
+Mcu.Pin22=DDR_DQ3
+Mcu.Pin23=DDR_DQ7
+Mcu.Pin24=DDR_DQS0N
+Mcu.Pin25=DDR_DQS0P
+Mcu.Pin26=PE12
+Mcu.Pin27=PE0
+Mcu.Pin28=PD4
+Mcu.Pin29=PD5
+Mcu.Pin3=PD3
+Mcu.Pin30=PD0
+Mcu.Pin31=PA9
+Mcu.Pin32=PB3
+Mcu.Pin33=PB15
+Mcu.Pin34=PB9
+Mcu.Pin35=PC7
+Mcu.Pin36=PC11
+Mcu.Pin37=JTMS-SWDIO
+Mcu.Pin38=DDR_RESETN
+Mcu.Pin39=DDR_DQM0
+Mcu.Pin4=PC8
+Mcu.Pin40=DDR_DQ2
+Mcu.Pin41=DDR_DQ6
+Mcu.Pin42=PG12
+Mcu.Pin43=PE11
+Mcu.Pin44=PE15
+Mcu.Pin45=DDR_DQ4
+Mcu.Pin46=DDR_DQ5
+Mcu.Pin47=PD8
+Mcu.Pin48=PE13
+Mcu.Pin49=DDR_A13
+Mcu.Pin5=PE4
+Mcu.Pin50=DDR_A9
+Mcu.Pin51=PC15-OSC32_OUT
+Mcu.Pin52=DDR_A2
+Mcu.Pin53=DDR_A3
+Mcu.Pin54=PC14-OSC32_IN
+Mcu.Pin55=PC13
+Mcu.Pin56=DDR_A0
+Mcu.Pin57=DDR_BA0
+Mcu.Pin58=PH0-OSC_IN
+Mcu.Pin59=DDR_BA2
+Mcu.Pin6=JTDO-TRACESWO
+Mcu.Pin60=DDR_ODT
+Mcu.Pin61=PH1-OSC_OUT
+Mcu.Pin62=DDR_CSN
+Mcu.Pin63=DDR_WEN
+Mcu.Pin64=DDR_CASN
+Mcu.Pin65=DDR_CLKN
+Mcu.Pin66=PA14
+Mcu.Pin67=PA13
+Mcu.Pin68=DDR_CLKP
+Mcu.Pin69=DDR_A10
+Mcu.Pin7=JTCK-SWCLK
+Mcu.Pin70=DDR_A12
+Mcu.Pin71=DDR_A1
+Mcu.Pin72=PA3
+Mcu.Pin73=PA0
+Mcu.Pin74=DDR_A14
+Mcu.Pin75=DDR_A11
+Mcu.Pin76=PE2
+Mcu.Pin77=PC2
+Mcu.Pin78=PC3
+Mcu.Pin79=DDR_CKE
+Mcu.Pin8=DDR_DQ0
+Mcu.Pin80=DDR_BA1
+Mcu.Pin81=PG14
+Mcu.Pin82=DDR_A4
+Mcu.Pin83=DDR_DQ8
+Mcu.Pin84=PA1
+Mcu.Pin85=PC1
+Mcu.Pin86=PA2
+Mcu.Pin87=DDR_A8
+Mcu.Pin88=DDR_DQ13
+Mcu.Pin89=DDR_DQ10
+Mcu.Pin9=DDR_DQ1
+Mcu.Pin90=PB1
+Mcu.Pin91=PB0
+Mcu.Pin92=PB11
+Mcu.Pin93=PC0
+Mcu.Pin94=PB10
+Mcu.Pin95=PG11
+Mcu.Pin96=PG10
+Mcu.Pin97=PD11
+Mcu.Pin98=PF6
+Mcu.Pin99=PE8
+Mcu.PinsNb=166
+Mcu.ThirdPartyNb=0
+Mcu.UserConstants=
+Mcu.UserName=STM32MP157CADx
+MxCube.Version=4.99.1
+MxDb.Version=DB.4.0.270
+NJTRST.Mode=JTAG_5_pins
+NJTRST.Signal=SYS_JTRST
+NVIC.BusFault_IRQn=true\:0\:0\:false\:false\:true\:false
+NVIC.DebugMonitor_IRQn=true\:0\:0\:false\:false\:true\:false
+NVIC.HardFault_IRQn=true\:0\:0\:false\:false\:true\:false
+NVIC.MemoryManagement_IRQn=true\:0\:0\:false\:false\:true\:false
+NVIC.NonMaskableInt_IRQn=true\:0\:0\:false\:false\:true\:false
+NVIC.PendSV_IRQn=true\:0\:0\:false\:false\:true\:false
+NVIC.PriorityGroup=NVIC_PRIORITYGROUP_4
+NVIC.SVCall_IRQn=true\:0\:0\:false\:false\:true\:false
+NVIC.SysTick_IRQn=true\:0\:0\:false\:false\:true\:false
+NVIC.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:false
+PA0.Mode=IN16-Single-Ended
+PA0.Signal=ADC1_INP16
+PA1.Locked=true
+PA1.Mode=RGB666
+PA1.Signal=LTDC_R2
+PA10.Locked=true
+PA10.Mode=Ext_Phy_OTG/Dual-Role-Device
+PA10.Signal=USB_OTG_HS_ID
+PA11.Locked=true
+PA11.Mode=Full_Duplex_Master
+PA11.Signal=I2S2_WS
+PA12.Locked=true
+PA12.Mode=RGB666
+PA12.Signal=LTDC_R5
+PA13.GPIOParameters=GPIO_Label
+PA13.GPIO_Label=LED1
+PA13.Locked=true
+PA13.Signal=GPIO_Output
+PA14.GPIOParameters=GPIO_Label
+PA14.GPIO_Label=LED2
+PA14.Locked=true
+PA14.Signal=GPIO_Output
+PA15.GPIOParameters=GPIO_Label
+PA15.GPIO_Label=LDTC_R1
+PA15.Locked=true
+PA15.Signal=GPIO_Output
+PA2.Locked=true
+PA2.Mode=RMII (Reduced MII)
+PA2.Signal=ETH1_MDIO
+PA3.Locked=true
+PA3.Mode=RGB666
+PA3.Signal=LTDC_B5
+PA4.Locked=true
+PA4.Mode=RGB666
+PA4.Signal=LTDC_VSYNC
+PA5.Mode=RGB666
+PA5.Signal=LTDC_R4
+PA6.Locked=true
+PA6.Mode=RGB666
+PA6.Signal=LTDC_G2
+PA7.Locked=true
+PA7.Mode=RMII (Reduced MII)
+PA7.Signal=ETH1_CRS_DV
+PA8.Locked=true
+PA8.Mode=RGB666
+PA8.Signal=LTDC_R6
+PA9.GPIOParameters=GPIO_Label
+PA9.GPIO_Label=SDMMC2_RST_N
+PA9.Locked=true
+PA9.Signal=GPIO_Output
+PB0.Locked=true
+PB0.Mode=RGB666
+PB0.Signal=LTDC_R3
+PB1.Locked=true
+PB1.Signal=ADCx_INP5
+PB10.Locked=true
+PB10.Mode=RGB666
+PB10.Signal=LTDC_G4
+PB11.Locked=true
+PB11.Mode=RMII (Reduced MII)
+PB11.Signal=ETH1_TX_EN
+PB12.Locked=true
+PB12.Mode=RMII (Reduced MII)
+PB12.Signal=ETH1_TXD0
+PB13.Locked=true
+PB13.Mode=RMII (Reduced MII)
+PB13.Signal=ETH1_TXD1
+PB14.GPIOParameters=GPIO_PuPd
+PB14.GPIO_PuPd=GPIO_PULLUP
+PB14.Locked=true
+PB14.Mode=mmc_4_bits_Wide_bus
+PB14.Signal=SDMMC2_D0
+PB15.GPIOParameters=GPIO_PuPd
+PB15.GPIO_PuPd=GPIO_PULLUP
+PB15.Locked=true
+PB15.Mode=mmc_4_bits_Wide_bus
+PB15.Signal=SDMMC2_D1
+PB2.GPIOParameters=GPIO_PuPd
+PB2.GPIO_PuPd=GPIO_PULLUP
+PB2.Locked=true
+PB2.Mode=Asynchronous
+PB2.Signal=UART4_RX
+PB3.GPIOParameters=GPIO_PuPd
+PB3.GPIO_PuPd=GPIO_PULLUP
+PB3.Locked=true
+PB3.Mode=mmc_4_bits_Wide_bus
+PB3.Signal=SDMMC2_D2
+PB4.GPIOParameters=GPIO_PuPd
+PB4.GPIO_PuPd=GPIO_PULLUP
+PB4.Locked=true
+PB4.Mode=mmc_4_bits_Wide_bus
+PB4.Signal=SDMMC2_D3
+PB5.Locked=true
+PB5.Mode=RGB666
+PB5.Signal=LTDC_G7
+PB6.Locked=true
+PB6.Mode=Enable Chip Select for each bank
+PB6.Signal=QUADSPI_BK1_NCS
+PB7.Locked=true
+PB7.Mode=I2C
+PB7.Signal=I2C4_SDA
+PB8.Locked=true
+PB8.Mode=RGB666
+PB8.Signal=LTDC_B6
+PB9.Locked=true
+PB9.Mode=RGB666
+PB9.Signal=LTDC_B7
+PC0.Locked=true
+PC0.Mode=Enable Chip Select for each bank
+PC0.Signal=QUADSPI_BK2_NCS
+PC1.Locked=true
+PC1.Mode=RMII (Reduced MII)
+PC1.Signal=ETH1_MDC
+PC10.GPIOParameters=GPIO_PuPd
+PC10.GPIO_PuPd=GPIO_PULLUP
+PC10.Locked=true
+PC10.Mode=SD_4_bits_Wide_bus
+PC10.Signal=SDMMC1_D2
+PC11.GPIOParameters=GPIO_PuPd
+PC11.GPIO_PuPd=GPIO_PULLUP
+PC11.Locked=true
+PC11.Mode=SD_4_bits_Wide_bus
+PC11.Signal=SDMMC1_D3
+PC12.GPIOParameters=GPIO_PuPd
+PC12.GPIO_PuPd=GPIO_PULLUP
+PC12.Locked=true
+PC12.Mode=SD_4_bits_Wide_bus
+PC12.Signal=SDMMC1_CK
+PC13.GPIOParameters=GPIO_Label
+PC13.GPIO_Label=TP16
+PC13.Locked=true
+PC13.Signal=GPIO_Output
+PC14-OSC32_IN.Locked=true
+PC14-OSC32_IN.Mode=LSE-External-Oscillator
+PC14-OSC32_IN.Signal=RCC_OSC32_IN
+PC15-OSC32_OUT.Locked=true
+PC15-OSC32_OUT.Mode=LSE-External-Oscillator
+PC15-OSC32_OUT.Signal=RCC_OSC32_OUT
+PC2.Locked=true
+PC2.Mode=Full_Duplex_Master
+PC2.Signal=I2S2_SDI
+PC3.Locked=true
+PC3.Mode=Full_Duplex_Master
+PC3.Signal=I2S2_SDO
+PC4.Locked=true
+PC4.Mode=RMII (Reduced MII)
+PC4.Signal=ETH1_RXD0
+PC5.Locked=true
+PC5.Mode=RMII (Reduced MII)
+PC5.Signal=ETH1_RXD1
+PC6.Locked=true
+PC6.Mode=RGB666
+PC6.Signal=LTDC_HSYNC
+PC7.Locked=true
+PC7.Mode=RGB666
+PC7.Signal=LTDC_G6
+PC8.GPIOParameters=GPIO_PuPd
+PC8.GPIO_PuPd=GPIO_PULLUP
+PC8.Locked=true
+PC8.Mode=SD_4_bits_Wide_bus
+PC8.Signal=SDMMC1_D0
+PC9.GPIOParameters=GPIO_PuPd
+PC9.GPIO_PuPd=GPIO_PULLUP
+PC9.Locked=true
+PC9.Mode=SD_4_bits_Wide_bus
+PC9.Signal=SDMMC1_D1
+PD0.Locked=true
+PD0.Mode=FDCANMaster
+PD0.Signal=FDCAN1_RX
+PD1.Locked=true
+PD1.Mode=FDCANMaster
+PD1.Signal=FDCAN1_TX
+PD10.Locked=true
+PD10.Mode=RGB666
+PD10.Signal=LTDC_B3
+PD11.GPIOParameters=GPIO_PuPd,GPIO_Label
+PD11.GPIO_Label=TOUCH_WAKE
+PD11.GPIO_PuPd=GPIO_PULLDOWN
+PD11.Locked=true
+PD11.Signal=GPIO_Input
+PD12.GPIOParameters=GPIO_Speed
+PD12.GPIO_Speed=GPIO_SPEED_FREQ_HIGH
+PD12.Locked=true
+PD12.Signal=S_TIM4_CH1
+PD13.GPIOParameters=GPIO_Label
+PD13.GPIO_Label=DSIHOST_TE
+PD13.Locked=true
+PD13.Signal=GPIO_Output
+PD14.GPIOParameters=GPIO_Speed
+PD14.GPIO_Speed=GPIO_SPEED_FREQ_HIGH
+PD14.Locked=true
+PD14.Signal=S_TIM4_CH3
+PD15.GPIOParameters=GPIO_Label
+PD15.GPIO_Label=RESET_OUT
+PD15.Locked=true
+PD15.Signal=GPIO_Output
+PD2.GPIOParameters=GPIO_PuPd
+PD2.GPIO_PuPd=GPIO_PULLUP
+PD2.Locked=true
+PD2.Mode=SD_4_bits_Wide_bus
+PD2.Signal=SDMMC1_CMD
+PD3.Locked=true
+PD3.Mode=Full_Duplex_Master
+PD3.Signal=I2S2_CK
+PD4.GPIOParameters=GPIO_PuPd
+PD4.GPIO_PuPd=GPIO_PULLDOWN
+PD4.Locked=true
+PD4.Mode=RTS_Only
+PD4.Signal=USART2_RTS
+PD5.Locked=true
+PD5.Mode=Asynchronous
+PD5.Signal=USART2_TX
+PD6.GPIOParameters=GPIO_PuPd
+PD6.GPIO_PuPd=GPIO_PULLUP
+PD6.Locked=true
+PD6.Mode=Asynchronous
+PD6.Signal=USART2_RX
+PD7.Locked=true
+PD7.Mode=I2C
+PD7.Signal=I2C2_SCL
+PD8.GPIOParameters=GPIO_Label
+PD8.GPIO_Label=LCD_PCTRL
+PD8.Locked=true
+PD8.Signal=GPIO_Output
+PD9.GPIOParameters=GPIO_PuPd,GPIO_Label
+PD9.GPIO_Label=TOUCH_INT
+PD9.GPIO_PuPd=GPIO_PULLDOWN
+PD9.Locked=true
+PD9.Signal=GPIO_Input
+PE0.Signal=UART8_RX
+PE1.Locked=true
+PE1.Mode=Master_Clock_Activated
+PE1.Signal=I2S2_MCK
+PE10.Mode=Dual Bank
+PE10.Signal=QUADSPI_BK2_IO3
+PE11.Locked=true
+PE11.Mode=RGB666
+PE11.Signal=LTDC_G3
+PE12.Locked=true
+PE12.Mode=RGB666
+PE12.Signal=LTDC_B4
+PE13.Locked=true
+PE13.Mode=RGB666
+PE13.Signal=LTDC_DE
+PE14.Locked=true
+PE14.Mode=RGB666
+PE14.Signal=LTDC_CLK
+PE15.Locked=true
+PE15.Mode=RGB666
+PE15.Signal=LTDC_R7
+PE2.Locked=true
+PE2.Mode=I2C
+PE2.Signal=I2C4_SCL
+PE3.GPIOParameters=GPIO_PuPd
+PE3.GPIO_PuPd=GPIO_PULLUP
+PE3.Locked=true
+PE3.Mode=mmc_4_bits_Wide_bus
+PE3.Signal=SDMMC2_CK
+PE4.GPIOParameters=GPIO_Label
+PE4.GPIO_Label=LTDC_B0
+PE4.Locked=true
+PE4.Signal=GPIO_Output
+PE5.GPIOParameters=GPIO_Label
+PE5.GPIO_Label=LTDC_G0
+PE5.Locked=true
+PE5.Signal=GPIO_Output
+PE6.GPIOParameters=GPIO_Label
+PE6.GPIO_Label=LTDC_G1
+PE6.Locked=true
+PE6.Signal=GPIO_Output
+PE7.Mode=Dual Bank
+PE7.Signal=QUADSPI_BK2_IO0
+PE8.Mode=Dual Bank
+PE8.Signal=QUADSPI_BK2_IO1
+PE9.Mode=Dual Bank
+PE9.Signal=QUADSPI_BK2_IO2
+PF10.Mode=Dual Bank
+PF10.Signal=QUADSPI_CLK
+PF11.Mode=RGB666
+PF11.Signal=LTDC_G5
+PF6.Mode=Dual Bank
+PF6.Signal=QUADSPI_BK1_IO3
+PF7.Mode=Dual Bank
+PF7.Signal=QUADSPI_BK1_IO2
+PF8.Mode=Dual Bank
+PF8.Signal=QUADSPI_BK1_IO0
+PF9.Mode=Dual Bank
+PF9.Signal=QUADSPI_BK1_IO1
+PG10.Locked=true
+PG10.Mode=RGB666
+PG10.Signal=LTDC_B2
+PG11.GPIOParameters=GPIO_PuPd
+PG11.GPIO_PuPd=GPIO_PULLUP
+PG11.Locked=true
+PG11.Mode=Asynchronous
+PG11.Signal=UART4_TX
+PG12.GPIOParameters=GPIO_Label
+PG12.GPIO_Label=LTDC_B1
+PG12.Locked=true
+PG12.Signal=GPIO_Output
+PG14.Locked=true
+PG14.Mode=Asynchronous
+PG14.Signal=USART6_TX
+PG15.Locked=true
+PG15.Mode=I2C
+PG15.Signal=I2C2_SDA
+PG6.GPIOParameters=GPIO_PuPd
+PG6.GPIO_PuPd=GPIO_PULLUP
+PG6.Locked=true
+PG6.Mode=mmc_4_bits_Wide_bus
+PG6.Signal=SDMMC2_CMD
+PG7.Signal=UART8_RTS
+PG8.Locked=true
+PG8.Mode=ETH Clock Output (PHY without Quartz)
+PG8.Signal=ETH1_CLK
+PG9.GPIOParameters=GPIO_PuPd
+PG9.GPIO_PuPd=GPIO_PULLUP
+PG9.Locked=true
+PG9.Mode=Asynchronous
+PG9.Signal=USART6_RX
+PH0-OSC_IN.Locked=true
+PH0-OSC_IN.Mode=HSE-External-Oscillator
+PH0-OSC_IN.Signal=RCC_OSC_IN
+PH1-OSC_OUT.Locked=true
+PH1-OSC_OUT.Mode=HSE-External-Oscillator
+PH1-OSC_OUT.Signal=RCC_OSC_OUT
+PinOutPanel.CurrentBGAView=Top
+PinOutPanel.RotationAngle=0
+ProjectManager.AskForMigrate=true
+ProjectManager.BackupPrevious=false
+ProjectManager.CompilerOptimize=3
+ProjectManager.ComputerToolchain=false
+ProjectManager.CoupleFile=false
+ProjectManager.CustomerFirmwarePackage=
+ProjectManager.DefaultFWLocation=true
+ProjectManager.DeletePrevious=true
+ProjectManager.DeviceId=STM32MP157CADx
+ProjectManager.DeviceTreeLocation=/home/user/gen/src/yocto-genisys/layers/meta-exceet-stm32mp/conf/machine/dts/
+ProjectManager.FirmwarePackage=STM32Cube FW_MP1 V0.4.0
+ProjectManager.FreePins=false
+ProjectManager.HalAssertFull=false
+ProjectManager.HeapSize=0x200
+ProjectManager.KeepUserCode=true
+ProjectManager.LastFirmware=true
+ProjectManager.LibraryCopy=0
+ProjectManager.MainLocation=Src
+ProjectManager.PreviousToolchain=
+ProjectManager.ProjectBuild=false
+ProjectManager.ProjectFileName=t1000-s.ioc
+ProjectManager.ProjectName=t1000-s
+ProjectManager.StackSize=0x400
+ProjectManager.TargetToolchain=SW4STM32
+ProjectManager.ToolChainLocation=
+ProjectManager.UnderRoot=false
+ProjectManager.functionlistsort=1-MX_GPIO_Init-GPIO-false-HAL-true,2-SystemClock_Config-RCC-false-HAL-false
+RCC.ADCCLockSelection=RCC_ADCCLKSOURCE_PER
+RCC.ADCFreq_Value=24000000
+RCC.AHB1234Freq_Value=196000000
+RCC.AHB123Freq_Value=193500000
+RCC.AHB12Freq_Value=64000000
+RCC.AHB4Freq_Value=64000000
+RCC.APB1DIV=RCC_APB1_DIV2
+RCC.APB1Freq_Value=98000000
+RCC.APB2DIV=RCC_APB2_DIV2
+RCC.APB2Freq_Value=98000000
+RCC.APB3DIV=RCC_APB3_DIV2
+RCC.APB3Freq_Value=98000000
+RCC.APB4DIV=RCC_APB4_DIV2
+RCC.APB4Freq_Value=132000000
+RCC.APB5DIV=RCC_APB5_DIV4
+RCC.APB5DIVClockFreq_Value=66000000
+RCC.AXICLKFreq_VALUE=264000000
+RCC.AXICLKSource=RCC_AXISSOURCE_PLL2
+RCC.AXIClockFreq_Value=64000000
+RCC.AXIDIVFreq_Value=264000000
+RCC.CECFreq_Value=32768
+RCC.CKPERCLKFreq_VALUE=24000000
+RCC.CKPERCLKSource=RCC_CKPERCLKSOURCE_HSE
+RCC.CKPERFreq_Value=64000000
+RCC.CSI_VALUE=4000000
+RCC.CortexFreq_Value=196000000
+RCC.CpuClockFreq_Value=64000000
+RCC.D1CPREFreq_Value=64000000
+RCC.DACCLKFreq_VALUE=32000
+RCC.DDRCFreq_Value=528000000
+RCC.DDRPERFMFreq_Value=528000000
+RCC.DDRPHYFreq_Value=528000000
+RCC.DFSDFAFreq_Value=50000000
+RCC.DFSDMACLkFreq_Value=50390625
+RCC.DFSDMFreq_Value=196000000
+RCC.DIVM1=3
+RCC.DIVM2=3
+RCC.DIVM3=3
+RCC.DIVM4=6
+RCC.DIVN1=81
+RCC.DIVN2=66
+RCC.DIVN3=98
+RCC.DIVN4=125
+RCC.DIVP1Freq_Value=648000000
+RCC.DIVP2Freq_Value=264000000
+RCC.DIVP3=4
+RCC.DIVP3Freq_Value=196000000
+RCC.DIVP4=10
+RCC.DIVP4Freq_Value=50000000
+RCC.DIVQ1=1
+RCC.DIVQ1Freq_Value=648000000
+RCC.DIVQ2=1
+RCC.DIVQ2Freq_Value=528000000
+RCC.DIVQ3=16
+RCC.DIVQ3Freq_Value=49000000
+RCC.DIVQ4=10
+RCC.DIVQ4Freq_Value=50000000
+RCC.DIVR1=1
+RCC.DIVR1Freq_Value=648000000
+RCC.DIVR2=1
+RCC.DIVR2Freq_Value=528000000
+RCC.DIVR3=8
+RCC.DIVR3Freq_Value=98000000
+RCC.DIVR4=10
+RCC.DIVR4Freq_Value=50000000
+RCC.DSIFreq_Value=60000000
+RCC.DSIRXEscFreq_Value=60000000
+RCC.DSITXEscFreq_Value=15000000
+RCC.DSI_VALUE=60000000
+RCC.ETHFreq_Value=50000000
+RCC.FCLKFreq_Value=196000000
+RCC.FDCANFreq_Value=24000000
+RCC.FMCFreq_Value=264000000
+RCC.FamilyName=M
+RCC.HCLK3ClockFreq_Value=64000000
+RCC.HCLK4ClockFreq_Value=193500000
+RCC.HCLKFreq_Value=64000000
+RCC.HSE_VALUE=24000000
+RCC.HSIDivClkFreq_Value=64000000
+RCC.HSI_VALUE=64000000
+RCC.Hclk5DIVFreq_Value=264000000
+RCC.Hclk6DIVFreq_Value=264000000
+RCC.I2C123Freq_Value=64000000
+RCC.I2C12CLockSelection=RCC_I2C12CLKSOURCE_HSI
+RCC.I2C12Freq_Value=64000000
+RCC.I2C35Freq_Value=98000000
+RCC.I2C46CLockSelection=RCC_I2C46CLKSOURCE_HSI
+RCC.I2C46Freq_Value=64000000
+RCC.I2C4Freq_Value=64000000
+RCC.IPParameters=ADCCLockSelection,ADCFreq_Value,AHB1234Freq_Value,AHB123Freq_Value,AHB12Freq_Value,AHB4Freq_Value,APB1DIV,APB1Freq_Value,APB2DIV,APB2Freq_Value,APB3DIV,APB3Freq_Value,APB4DIV,APB4Freq_Value,APB5DIV,APB5DIVClockFreq_Value,AXICLKFreq_VALUE,AXICLKSource,AXIClockFreq_Value,AXIDIVFreq_Value,CECFreq_Value,CKPERCLKFreq_VALUE,CKPERCLKSource,CKPERFreq_Value,CSI_VALUE,CortexFreq_Value,CpuClockFreq_Value,D1CPREFreq_Value,DACCLKFreq_VALUE,DDRCFreq_Value,DDRPERFMFreq_Value,DDRPHYFreq_Value,DFSDFAFreq_Value,DFSDMACLkFreq_Value,DFSDMFreq_Value,DIVM1,DIVM2,DIVM3,DIVM4,DIVN1,DIVN2,DIVN3,DIVN4,DIVP1Freq_Value,DIVP2Freq_Value,DIVP3,DIVP3Freq_Value,DIVP4,DIVP4Freq_Value,DIVQ1,DIVQ1Freq_Value,DIVQ2,DIVQ2Freq_Value,DIVQ3,DIVQ3Freq_Value,DIVQ4,DIVQ4Freq_Value,DIVR1,DIVR1Freq_Value,DIVR2,DIVR2Freq_Value,DIVR3,DIVR3Freq_Value,DIVR4,DIVR4Freq_Value,DSIFreq_Value,DSIRXEscFreq_Value,DSITXEscFreq_Value,DSI_VALUE,ETHFreq_Value,FCLKFreq_Value,FDCANFreq_Value,FMCFreq_Value,FamilyName,HCLK3ClockFreq_Value,HCLK4ClockFreq_Value,HCLKFreq_Value,HSE_VALUE,HSIDivClkFreq_Value,HSI_VALUE,Hclk5DIVFreq_Value,Hclk6DIVFreq_Value,I2C123Freq_Value,I2C12CLockSelection,I2C12Freq_Value,I2C35Freq_Value,I2C46CLockSelection,I2C46Freq_Value,I2C4Freq_Value,LPTIM1Freq_Value,LPTIM23Freq_Value,LPTIM2Freq_Value,LPTIM345Freq_Value,LPTIM45Freq_Value,LPUART1Freq_Value,LSI_VALUE,LTDCFreq_Value,MCO1PinFreq_Value,MCO2PinFreq_Value,MCUCLKFreq_VALUE,MCUCLKSource,MCUClockFreq_Value,MPUCLKFreq_VALUE,MPUCLKSource,PLL12Source,PLL1FRACV,PLL1MODE,PLL2FRACV,PLL2MODE,PLL3FRACV,PLL3MODE,PLL3Source,PLL4PDSIFreq_Value,PLL4Source,PLLDSIFreq_Value,PLLDSIVCOFreq_Value,PLLSource,PLLSourceVirtual,PLLSourceVirtualString,PUBLFreq_Value,QSPIFreq_Value,RCC_RTC_Clock_Source_FROM_HSE,RTCClockSelection,RTCFreq_Value,SAI1Freq_Value,SAI23Freq_Value,SAI2CLockSelection,SAI2Freq_Value,SAI3Freq_Value,SAI4AFreq_Value,SAI4BFreq_Value,SAI4CLockSelection,SAI4Freq_Value,SDMMC12CLockSelection,SDMMC12Freq_Value,SDMMC3Freq_Value,SDMMCFreq_Value,SPDIFCLockSelection,SPDIFRXFreq_Value,SPI123Freq_Value,SPI1Freq_Value,SPI23CLockSelection,SPI23Freq_Value,SPI45Freq_Value,SPI6Freq_Value,STGENCLockSelection,STGENFreq_Value,SWPMI1Freq_Value,SYSCLKFreq_VALUE,Tim1OutputFreq_Value,Tim2OutputFreq_Value,UART78CLockSelection,UART78Freq_Value,USART16Freq_Value,USART1Freq_Value,USART234578Freq_Value,USART24CLockSelection,USART24Freq_Value,USART35CLockSelection,USART35Freq_Value,USART6CLockSelection,USART6Freq_Value,USBFreq_Value,USBOCLKSource,USBOFSFreq_Value,USBOHSFreq_Value,USBPHYCLKSource,USBPHYFreq_Value,VCO1OutputFreq_Value,VCO2OutputFreq_Value,VCO3OutputFreq_Value,VCO4OutputFreq_Value,VCOInput1Freq_Value,VCOInput2Freq_Value,VCOInput3Freq_Value,VCOInput4Freq_Value
+RCC.LPTIM1Freq_Value=98000000
+RCC.LPTIM23Freq_Value=98000000
+RCC.LPTIM2Freq_Value=64000000
+RCC.LPTIM345Freq_Value=64000000
+RCC.LPTIM45Freq_Value=98000000
+RCC.LPUART1Freq_Value=64000000
+RCC.LSI_VALUE=32000
+RCC.LTDCFreq_Value=50000000
+RCC.MCO1PinFreq_Value=64000000
+RCC.MCO2PinFreq_Value=648000000
+RCC.MCUCLKFreq_VALUE=196000000
+RCC.MCUCLKSource=RCC_MCUSSOURCE_PLL3
+RCC.MCUClockFreq_Value=196000000
+RCC.MPUCLKFreq_VALUE=648000000
+RCC.MPUCLKSource=RCC_MPUSOURCE_PLL1
+RCC.PLL12Source=RCC_PLL12SOURCE_HSE
+RCC.PLL1FRACV=0x800
+RCC.PLL1MODE=RCC_PLL_FRACTIONAL
+RCC.PLL2FRACV=0x1400
+RCC.PLL2MODE=RCC_PLL_FRACTIONAL
+RCC.PLL3FRACV=0x9ba
+RCC.PLL3MODE=RCC_PLL_FRACTIONAL
+RCC.PLL3Source=RCC_PLL3SOURCE_HSE
+RCC.PLL4PDSIFreq_Value=50000000
+RCC.PLL4Source=RCC_PLL4SOURCE_HSE
+RCC.PLLDSIFreq_Value=480000000
+RCC.PLLDSIVCOFreq_Value=960000000
+RCC.PLLSource=RCC_PLL3SOURCE_HSI
+RCC.PLLSourceVirtual=RCC_PLL3SOURCE_HSI
+RCC.PLLSourceVirtualString=RCC_PLL3SOURCE_HSI
+RCC.PUBLFreq_Value=528000000
+RCC.QSPIFreq_Value=264000000
+RCC.RCC_RTC_Clock_Source_FROM_HSE=24
+RCC.RTCClockSelection=RCC_RTCCLKSOURCE_LSE
+RCC.RTCFreq_Value=32768
+RCC.SAI1Freq_Value=50000000
+RCC.SAI23Freq_Value=50390625
+RCC.SAI2CLockSelection=RCC_SAI2CLKSOURCE_PLL3_Q
+RCC.SAI2Freq_Value=49000000
+RCC.SAI3Freq_Value=50000000
+RCC.SAI4AFreq_Value=50390625
+RCC.SAI4BFreq_Value=50390625
+RCC.SAI4CLockSelection=RCC_SAI4CLKSOURCE_PLL3_Q
+RCC.SAI4Freq_Value=49000000
+RCC.SDMMC12CLockSelection=RCC_SDMMC12CLKSOURCE_PLL3
+RCC.SDMMC12Freq_Value=98000000
+RCC.SDMMC3Freq_Value=196000000
+RCC.SDMMCFreq_Value=50390625
+RCC.SPDIFCLockSelection=RCC_SPDIFRXCLKSOURCE_PLL3
+RCC.SPDIFRXFreq_Value=49000000
+RCC.SPI123Freq_Value=50390625
+RCC.SPI1Freq_Value=50000000
+RCC.SPI23CLockSelection=RCC_SPI23CLKSOURCE_PLL3_Q
+RCC.SPI23Freq_Value=49000000
+RCC.SPI45Freq_Value=98000000
+RCC.SPI6Freq_Value=66000000
+RCC.STGENCLockSelection=RCC_STGENCLKSOURCE_HSE
+RCC.STGENFreq_Value=24000000
+RCC.SWPMI1Freq_Value=64000000
+RCC.SYSCLKFreq_VALUE=64000000
+RCC.Tim1OutputFreq_Value=196000000
+RCC.Tim2OutputFreq_Value=196000000
+RCC.UART78CLockSelection=RCC_UART78CLKSOURCE_HSI
+RCC.UART78Freq_Value=64000000
+RCC.USART16Freq_Value=64000000
+RCC.USART1Freq_Value=66000000
+RCC.USART234578Freq_Value=64000000
+RCC.USART24CLockSelection=RCC_UART24CLKSOURCE_HSI
+RCC.USART24Freq_Value=64000000
+RCC.USART35CLockSelection=RCC_UART35CLKSOURCE_HSI
+RCC.USART35Freq_Value=64000000
+RCC.USART6CLockSelection=RCC_USART6CLKSOURCE_HSI
+RCC.USART6Freq_Value=64000000
+RCC.USBFreq_Value=50390625
+RCC.USBOCLKSource=RCC_USBOCLKSOURCE_PHY
+RCC.USBOFSFreq_Value=48000000
+RCC.USBOHSFreq_Value=48000000
+RCC.USBPHYCLKSource=RCC_USBPHYCLKSOURCE_HSE
+RCC.USBPHYFreq_Value=24000000
+RCC.VCO1OutputFreq_Value=1296000000
+RCC.VCO2OutputFreq_Value=1056000000
+RCC.VCO3OutputFreq_Value=784000000
+RCC.VCO4OutputFreq_Value=500000000
+RCC.VCOInput1Freq_Value=8000000
+RCC.VCOInput2Freq_Value=8000000
+RCC.VCOInput3Freq_Value=8000000
+RCC.VCOInput4Freq_Value=4000000
+SH.ADCx_INP5.0=ADC1_INP5,IN5-Single-Ended
+SH.ADCx_INP5.ConfNb=1
+SH.S_TIM4_CH1.0=TIM4_CH1,PWM Generation1 CH1
+SH.S_TIM4_CH1.ConfNb=1
+SH.S_TIM4_CH3.0=TIM4_CH3,PWM Generation3 CH3
+SH.S_TIM4_CH3.ConfNb=1
+TIM4.Channel-PWM\ Generation1\ CH1=TIM_CHANNEL_1
+TIM4.Channel-PWM\ Generation3\ CH3=TIM_CHANNEL_3
+TIM4.IPParameters=Channel-PWM Generation1 CH1,Channel-PWM Generation3 CH3
+USART2.IPParameters=VirtualMode-Asynchronous
+USART2.VirtualMode-Asynchronous=VM_ASYNC
+USART6.IPParameters=VirtualMode-Asynchronous
+USART6.VirtualMode-Asynchronous=VM_ASYNC
+USB_DM1.Mode=Enable
+USB_DM1.Signal=USBH_HS1_DM
+USB_DM2.Mode=Ext_Phy_OTG/Dual-Role-Device
+USB_DM2.Signal=USB_OTG_HS_DM
+USB_DP1.Mode=Enable
+USB_DP1.Signal=USBH_HS1_DP
+USB_DP2.Mode=Ext_Phy_OTG/Dual-Role-Device
+USB_DP2.Signal=USB_OTG_HS_DP
+VP_DDR_DDR3.Mode=DDR3
+VP_DDR_DDR3.Signal=DDR_DDR3
+VP_DDR_DDR3_16_4Gb.Mode=4Gb_16bits
+VP_DDR_DDR3_16_4Gb.Signal=DDR_DDR3_16_4Gb
+VP_DDR_DDR_16_bits.Mode=16bits
+VP_DDR_DDR_16_bits.Signal=DDR_DDR_16_bits
+VP_DMA_VS_DMA1_A7NS.Mode=Cortex-A7 non secure
+VP_DMA_VS_DMA1_A7NS.Signal=DMA_VS_DMA1_A7NS
+VP_DMA_VS_DMA2_M4.Mode=Cortex-M4
+VP_DMA_VS_DMA2_M4.Signal=DMA_VS_DMA2_M4
+VP_RTC_VS_RTC_Activate.Mode=RTC_Enabled
+VP_RTC_VS_RTC_Activate.Signal=RTC_VS_RTC_Activate
+board=custom
diff --git a/conf/machine/cubemx/t1000-s/DeviceTree/t1000-s/kernel/stm32mp157c-t1000-s-mx.dts b/conf/machine/cubemx/t1000-s/DeviceTree/t1000-s/kernel/stm32mp157c-t1000-s-mx.dts
deleted file mode 100644
index dcee7a06816b329b74329eeda9bf30f58b7314c1..0000000000000000000000000000000000000000
--- a/conf/machine/cubemx/t1000-s/DeviceTree/t1000-s/kernel/stm32mp157c-t1000-s-mx.dts
+++ /dev/null
@@ -1,899 +0,0 @@
-/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
-/*
- * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
- * Author: STM32CubeMX code generation for STMicroelectronics.
- */
-
-/dts-v1/;
-#include "stm32mp157c.dtsi"
-#include "stm32mp157c-m4-srm.dtsi"
-#include "stm32mp157cad-pinctrl.dtsi"
-
-/* USER CODE BEGIN includes */
-/* USER CODE END includes */
-
-/ {
-	model = "STMicroelectronics custom STM32CubeMX board";
-	compatible = "st,stm32mp157c-t1000-s-mx", "st,stm32mp157";
-
-	memory@c0000000 {
-		reg = <0xc0000000 0x20000000>;
-
-		/* USER CODE BEGIN memory */
-		/* USER CODE END memory */
-	};
-
-	reserved-memory {
-		#address-cells = <1>;
-		#size-cells = <1>;
-		ranges;
-
-		/* USER CODE BEGIN reserved-memory */
-		/* USER CODE END reserved-memory */
-
-		gpu_reserved: gpu@dc000000 {
-			reg = <0xdc000000 0x4000000>;
-			no-map;
-		};
-	};
-
-	/* USER CODE BEGIN root */
-	/* USER CODE END root */
-
-	clocks {
-		/* USER CODE BEGIN clocks */
-		/* USER CODE END clocks */
-
-		clk_hsi: clk-hsi {
-			clock-frequency = <64000000>;
-		};
-
-		clk_csi: clk-csi {
-			clock-frequency = <4000000>;
-		};
-
-		clk_lse: clk-lse {
-			clock-frequency = <32768>;
-		};
-
-		clk_hse: clk-hse {
-			clock-frequency = <24000000>;
-		};
-	};
-
-}; /*root*/
-
-&pinctrl {
-	u-boot,dm-pre-reloc;
-
-	adc_pins_mx: adc_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 0, ANALOG)>, /* ADC1_INP16 */
-					 <STM32_PINMUX('B', 1, ANALOG)>; /* ADC1_INP5 */
-		};
-	};
-
-	adc_sleep_pins_mx: adc_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 0, ANALOG)>, /* ADC1_INP16 */
-					 <STM32_PINMUX('B', 1, ANALOG)>; /* ADC1_INP5 */
-		};
-	};
-
-	eth1_pins_mx: eth1_mx-0 {
-		pins1 {
-			pinmux = <STM32_PINMUX('A', 2, AF11)>; /* ETH1_MDIO */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-		pins2 {
-			pinmux = <STM32_PINMUX('A', 7, AF11)>, /* ETH1_CRS_DV */
-					 <STM32_PINMUX('C', 4, AF11)>, /* ETH1_RXD0 */
-					 <STM32_PINMUX('C', 5, AF11)>; /* ETH1_RXD1 */
-			bias-disable;
-		};
-		pins3 {
-			pinmux = <STM32_PINMUX('B', 11, AF11)>; /* ETH1_TX_EN */
-		};
-		pins4 {
-			pinmux = <STM32_PINMUX('B', 12, AF11)>, /* ETH1_TXD0 */
-					 <STM32_PINMUX('B', 13, AF11)>, /* ETH1_TXD1 */
-					 <STM32_PINMUX('C', 1, AF11)>, /* ETH1_MDC */
-					 <STM32_PINMUX('G', 8, AF2)>; /* ETH1_CLK */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-	};
-
-	eth1_sleep_pins_mx: eth1_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 2, ANALOG)>, /* ETH1_MDIO */
-					 <STM32_PINMUX('A', 7, ANALOG)>, /* ETH1_CRS_DV */
-					 <STM32_PINMUX('B', 11, ANALOG)>, /* ETH1_TX_EN */
-					 <STM32_PINMUX('B', 12, ANALOG)>, /* ETH1_TXD0 */
-					 <STM32_PINMUX('B', 13, ANALOG)>, /* ETH1_TXD1 */
-					 <STM32_PINMUX('C', 1, ANALOG)>, /* ETH1_MDC */
-					 <STM32_PINMUX('C', 4, ANALOG)>, /* ETH1_RXD0 */
-					 <STM32_PINMUX('C', 5, ANALOG)>, /* ETH1_RXD1 */
-					 <STM32_PINMUX('G', 8, ANALOG)>; /* ETH1_CLK */
-		};
-	};
-
-	fdcan1_pins_mx: fdcan1_mx-0 {
-		pins1 {
-			pinmux = <STM32_PINMUX('D', 0, AF9)>; /* FDCAN1_RX */
-			bias-disable;
-		};
-		pins2 {
-			pinmux = <STM32_PINMUX('D', 1, AF9)>; /* FDCAN1_TX */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-	};
-
-	fdcan1_sleep_pins_mx: fdcan1_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('D', 0, ANALOG)>, /* FDCAN1_RX */
-					 <STM32_PINMUX('D', 1, ANALOG)>; /* FDCAN1_TX */
-		};
-	};
-
-	i2c2_pins_mx: i2c2_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('D', 7, AF4)>, /* I2C2_SCL */
-					 <STM32_PINMUX('G', 15, AF4)>; /* I2C2_SDA */
-			bias-disable;
-			drive-open-drain;
-			slew-rate = <0>;
-		};
-	};
-
-	i2c2_sleep_pins_mx: i2c2_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('D', 7, ANALOG)>, /* I2C2_SCL */
-					 <STM32_PINMUX('G', 15, ANALOG)>; /* I2C2_SDA */
-		};
-	};
-
-	i2c4_pins_mx: i2c4_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('B', 7, AF6)>, /* I2C4_SDA */
-					 <STM32_PINMUX('E', 2, AF4)>; /* I2C4_SCL */
-			bias-disable;
-			drive-open-drain;
-			slew-rate = <0>;
-		};
-	};
-
-	i2c4_sleep_pins_mx: i2c4_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('B', 7, ANALOG)>, /* I2C4_SDA */
-					 <STM32_PINMUX('E', 2, ANALOG)>; /* I2C4_SCL */
-		};
-	};
-
-	i2s2_pins_mx: i2s2_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 11, AF5)>, /* I2S2_WS */
-					 <STM32_PINMUX('C', 2, AF5)>, /* I2S2_SDI */
-					 <STM32_PINMUX('C', 3, AF5)>, /* I2S2_SDO */
-					 <STM32_PINMUX('D', 3, AF5)>, /* I2S2_CK */
-					 <STM32_PINMUX('E', 1, AF5)>; /* I2S2_MCK */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-	};
-
-	i2s2_sleep_pins_mx: i2s2_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 11, ANALOG)>, /* I2S2_WS */
-					 <STM32_PINMUX('C', 2, ANALOG)>, /* I2S2_SDI */
-					 <STM32_PINMUX('C', 3, ANALOG)>, /* I2S2_SDO */
-					 <STM32_PINMUX('D', 3, ANALOG)>, /* I2S2_CK */
-					 <STM32_PINMUX('E', 1, ANALOG)>; /* I2S2_MCK */
-		};
-	};
-
-	ltdc_pins_mx: ltdc_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('A', 1, AF14)>, /* LTDC_R2 */
-					 <STM32_PINMUX('A', 3, AF14)>, /* LTDC_B5 */
-					 <STM32_PINMUX('A', 4, AF14)>, /* LTDC_VSYNC */
-					 <STM32_PINMUX('A', 5, AF14)>, /* LTDC_R4 */
-					 <STM32_PINMUX('A', 6, AF14)>, /* LTDC_G2 */
-					 <STM32_PINMUX('A', 8, AF14)>, /* LTDC_R6 */
-					 <STM32_PINMUX('A', 12, AF14)>, /* LTDC_R5 */
-					 <STM32_PINMUX('A', 15, AF14)>, /* LTDC_R1 */
-					 <STM32_PINMUX('B', 0, AF9)>, /* LTDC_R3 */
-					 <STM32_PINMUX('B', 5, AF14)>, /* LTDC_G7 */
-					 <STM32_PINMUX('B', 8, AF14)>, /* LTDC_B6 */
-					 <STM32_PINMUX('B', 9, AF14)>, /* LTDC_B7 */
-					 <STM32_PINMUX('B', 10, AF14)>, /* LTDC_G4 */
-					 <STM32_PINMUX('C', 6, AF14)>, /* LTDC_HSYNC */
-					 <STM32_PINMUX('C', 7, AF14)>, /* LTDC_G6 */
-					 <STM32_PINMUX('D', 10, AF14)>, /* LTDC_B3 */
-					 <STM32_PINMUX('E', 4, AF14)>, /* LTDC_B0 */
-					 <STM32_PINMUX('E', 5, AF14)>, /* LTDC_G0 */
-					 <STM32_PINMUX('E', 6, AF14)>, /* LTDC_G1 */
-					 <STM32_PINMUX('E', 11, AF14)>, /* LTDC_G3 */
-					 <STM32_PINMUX('E', 12, AF14)>, /* LTDC_B4 */
-					 <STM32_PINMUX('E', 13, AF14)>, /* LTDC_DE */
-					 <STM32_PINMUX('E', 15, AF14)>, /* LTDC_R7 */
-					 <STM32_PINMUX('F', 11, AF14)>, /* LTDC_G5 */
-					 <STM32_PINMUX('G', 10, AF14)>, /* LTDC_B2 */
-					 <STM32_PINMUX('G', 12, AF14)>, /* LTDC_B1 */
-					 <STM32_PINMUX('G', 13, AF14)>; /* LTDC_R0 */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('E', 14, AF14)>; /* LTDC_CLK */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-	};
-
-	ltdc_sleep_pins_mx: ltdc_sleep_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('A', 1, ANALOG)>, /* LTDC_R2 */
-					 <STM32_PINMUX('A', 3, ANALOG)>, /* LTDC_B5 */
-					 <STM32_PINMUX('A', 4, ANALOG)>, /* LTDC_VSYNC */
-					 <STM32_PINMUX('A', 5, ANALOG)>, /* LTDC_R4 */
-					 <STM32_PINMUX('A', 6, ANALOG)>, /* LTDC_G2 */
-					 <STM32_PINMUX('A', 8, ANALOG)>, /* LTDC_R6 */
-					 <STM32_PINMUX('A', 12, ANALOG)>, /* LTDC_R5 */
-					 <STM32_PINMUX('A', 15, ANALOG)>, /* LTDC_R1 */
-					 <STM32_PINMUX('B', 0, ANALOG)>, /* LTDC_R3 */
-					 <STM32_PINMUX('B', 5, ANALOG)>, /* LTDC_G7 */
-					 <STM32_PINMUX('B', 8, ANALOG)>, /* LTDC_B6 */
-					 <STM32_PINMUX('B', 9, ANALOG)>, /* LTDC_B7 */
-					 <STM32_PINMUX('B', 10, ANALOG)>, /* LTDC_G4 */
-					 <STM32_PINMUX('C', 6, ANALOG)>, /* LTDC_HSYNC */
-					 <STM32_PINMUX('C', 7, ANALOG)>, /* LTDC_G6 */
-					 <STM32_PINMUX('D', 10, ANALOG)>, /* LTDC_B3 */
-					 <STM32_PINMUX('E', 4, ANALOG)>, /* LTDC_B0 */
-					 <STM32_PINMUX('E', 5, ANALOG)>, /* LTDC_G0 */
-					 <STM32_PINMUX('E', 6, ANALOG)>, /* LTDC_G1 */
-					 <STM32_PINMUX('E', 11, ANALOG)>, /* LTDC_G3 */
-					 <STM32_PINMUX('E', 12, ANALOG)>, /* LTDC_B4 */
-					 <STM32_PINMUX('E', 13, ANALOG)>, /* LTDC_DE */
-					 <STM32_PINMUX('E', 14, ANALOG)>, /* LTDC_CLK */
-					 <STM32_PINMUX('E', 15, ANALOG)>, /* LTDC_R7 */
-					 <STM32_PINMUX('F', 11, ANALOG)>, /* LTDC_G5 */
-					 <STM32_PINMUX('G', 10, ANALOG)>, /* LTDC_B2 */
-					 <STM32_PINMUX('G', 12, ANALOG)>, /* LTDC_B1 */
-					 <STM32_PINMUX('G', 13, ANALOG)>; /* LTDC_R0 */
-		};
-	};
-
-	quadspi_pins_mx: quadspi_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 6, AF10)>, /* QUADSPI_BK1_NCS */
-					 <STM32_PINMUX('C', 0, AF10)>; /* QUADSPI_BK2_NCS */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('E', 7, AF10)>, /* QUADSPI_BK2_IO0 */
-					 <STM32_PINMUX('E', 8, AF10)>, /* QUADSPI_BK2_IO1 */
-					 <STM32_PINMUX('E', 9, AF10)>, /* QUADSPI_BK2_IO2 */
-					 <STM32_PINMUX('E', 10, AF10)>, /* QUADSPI_BK2_IO3 */
-					 <STM32_PINMUX('F', 6, AF9)>, /* QUADSPI_BK1_IO3 */
-					 <STM32_PINMUX('F', 7, AF9)>, /* QUADSPI_BK1_IO2 */
-					 <STM32_PINMUX('F', 8, AF10)>, /* QUADSPI_BK1_IO0 */
-					 <STM32_PINMUX('F', 9, AF10)>; /* QUADSPI_BK1_IO1 */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins3 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('F', 10, AF9)>; /* QUADSPI_CLK */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <2>;
-		};
-	};
-
-	quadspi_sleep_pins_mx: quadspi_sleep_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 6, ANALOG)>, /* QUADSPI_BK1_NCS */
-					 <STM32_PINMUX('C', 0, ANALOG)>, /* QUADSPI_BK2_NCS */
-					 <STM32_PINMUX('E', 7, ANALOG)>, /* QUADSPI_BK2_IO0 */
-					 <STM32_PINMUX('E', 8, ANALOG)>, /* QUADSPI_BK2_IO1 */
-					 <STM32_PINMUX('E', 9, ANALOG)>, /* QUADSPI_BK2_IO2 */
-					 <STM32_PINMUX('E', 10, ANALOG)>, /* QUADSPI_BK2_IO3 */
-					 <STM32_PINMUX('F', 6, ANALOG)>, /* QUADSPI_BK1_IO3 */
-					 <STM32_PINMUX('F', 7, ANALOG)>, /* QUADSPI_BK1_IO2 */
-					 <STM32_PINMUX('F', 8, ANALOG)>, /* QUADSPI_BK1_IO0 */
-					 <STM32_PINMUX('F', 9, ANALOG)>, /* QUADSPI_BK1_IO1 */
-					 <STM32_PINMUX('F', 10, ANALOG)>; /* QUADSPI_CLK */
-		};
-	};
-
-	sdmmc1_pins_mx: sdmmc1_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
-					 <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
-					 <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
-					 <STM32_PINMUX('C', 11, AF12)>, /* SDMMC1_D3 */
-					 <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 12, AF12)>; /* SDMMC1_CK */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-	};
-
-	sdmmc1_opendrain_pins_mx: sdmmc1_opendrain_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
-					 <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
-					 <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
-					 <STM32_PINMUX('C', 11, AF12)>; /* SDMMC1_D3 */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 12, AF12)>; /* SDMMC1_CK */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins3 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
-			bias-pull-up;
-			drive-open-drain;
-			slew-rate = <1>;
-		};
-	};
-
-	sdmmc1_sleep_pins_mx: sdmmc1_sleep_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 8, ANALOG)>, /* SDMMC1_D0 */
-					 <STM32_PINMUX('C', 9, ANALOG)>, /* SDMMC1_D1 */
-					 <STM32_PINMUX('C', 10, ANALOG)>, /* SDMMC1_D2 */
-					 <STM32_PINMUX('C', 11, ANALOG)>, /* SDMMC1_D3 */
-					 <STM32_PINMUX('C', 12, ANALOG)>, /* SDMMC1_CK */
-					 <STM32_PINMUX('D', 2, ANALOG)>; /* SDMMC1_CMD */
-		};
-	};
-
-	sdmmc2_pins_mx: sdmmc2_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 3, AF9)>, /* SDMMC2_D2 */
-					 <STM32_PINMUX('B', 4, AF9)>, /* SDMMC2_D3 */
-					 <STM32_PINMUX('B', 14, AF9)>, /* SDMMC2_D0 */
-					 <STM32_PINMUX('B', 15, AF9)>, /* SDMMC2_D1 */
-					 <STM32_PINMUX('G', 6, AF10)>; /* SDMMC2_CMD */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('E', 3, AF9)>; /* SDMMC2_CK */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-	};
-
-	sdmmc2_opendrain_pins_mx: sdmmc2_opendrain_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 3, AF9)>, /* SDMMC2_D2 */
-					 <STM32_PINMUX('B', 4, AF9)>, /* SDMMC2_D3 */
-					 <STM32_PINMUX('B', 14, AF9)>, /* SDMMC2_D0 */
-					 <STM32_PINMUX('B', 15, AF9)>; /* SDMMC2_D1 */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('E', 3, AF9)>; /* SDMMC2_CK */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins3 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('G', 6, AF10)>; /* SDMMC2_CMD */
-			bias-pull-up;
-			drive-open-drain;
-			slew-rate = <1>;
-		};
-	};
-
-	sdmmc2_sleep_pins_mx: sdmmc2_sleep_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 3, ANALOG)>, /* SDMMC2_D2 */
-					 <STM32_PINMUX('B', 4, ANALOG)>, /* SDMMC2_D3 */
-					 <STM32_PINMUX('B', 14, ANALOG)>, /* SDMMC2_D0 */
-					 <STM32_PINMUX('B', 15, ANALOG)>, /* SDMMC2_D1 */
-					 <STM32_PINMUX('E', 3, ANALOG)>, /* SDMMC2_CK */
-					 <STM32_PINMUX('G', 6, ANALOG)>; /* SDMMC2_CMD */
-		};
-	};
-
-	tim1_pwm_pins_mx: tim1_pwm_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 9, AF1)>; /* TIM1_CH2 */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-	};
-
-	tim1_pwm_sleep_pins_mx: tim1_pwm_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 9, ANALOG)>; /* TIM1_CH2 */
-		};
-	};
-
-	tim4_pwm_pins_mx: tim4_pwm_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('D', 14, AF2)>; /* TIM4_CH3 */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-	};
-
-	tim4_pwm_sleep_pins_mx: tim4_pwm_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('D', 14, ANALOG)>; /* TIM4_CH3 */
-		};
-	};
-
-	uart4_pins_mx: uart4_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 2, AF8)>; /* UART4_RX */
-			bias-pull-up;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('G', 11, AF6)>; /* UART4_TX */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-	};
-
-	uart4_sleep_pins_mx: uart4_sleep_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 2, ANALOG)>, /* UART4_RX */
-					 <STM32_PINMUX('G', 11, ANALOG)>; /* UART4_TX */
-		};
-	};
-
-	usart2_pins_mx: usart2_mx-0 {
-		pins1 {
-			pinmux = <STM32_PINMUX('D', 4, AF7)>; /* USART2_RTS */
-			bias-pull-down;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-		pins2 {
-			pinmux = <STM32_PINMUX('D', 5, AF7)>; /* USART2_TX */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-		pins3 {
-			pinmux = <STM32_PINMUX('D', 6, AF7)>; /* USART2_RX */
-			bias-pull-up;
-		};
-	};
-
-	usart2_sleep_pins_mx: usart2_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('D', 4, ANALOG)>, /* USART2_RTS */
-					 <STM32_PINMUX('D', 5, ANALOG)>, /* USART2_TX */
-					 <STM32_PINMUX('D', 6, ANALOG)>; /* USART2_RX */
-		};
-	};
-
-	usart6_pins_mx: usart6_mx-0 {
-		pins1 {
-			pinmux = <STM32_PINMUX('G', 14, AF7)>; /* USART6_TX */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-		pins2 {
-			pinmux = <STM32_PINMUX('G', 9, AF7)>; /* USART6_RX */
-			bias-pull-up;
-		};
-	};
-
-	usart6_sleep_pins_mx: usart6_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('G', 9, ANALOG)>, /* USART6_RX */
-					 <STM32_PINMUX('G', 14, ANALOG)>; /* USART6_TX */
-		};
-	};
-
-	usb_otg_hs_pins_mx: usb_otg_hs_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
-		};
-	};
-
-	usb_otg_hs_sleep_pins_mx: usb_otg_hs_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
-		};
-	};
-
-	/* USER CODE BEGIN pinctrl */
-	/* USER CODE END pinctrl */
-};
-
-&pinctrl_z {
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN pinctrl_z */
-	/* USER CODE END pinctrl_z */
-};
-
-&m4_rproc{
-	mboxes = <&ipcc 0>, <&ipcc 1>, <&ipcc 2>;
-	mbox-names = "vq0", "vq1", "shutdown";
-	recovery;
-	status = "okay";
-
-	/* USER CODE BEGIN m4_rproc */
-	/* USER CODE END m4_rproc */
-};
-
-&adc{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&adc_pins_mx>;
-	pinctrl-1 = <&adc_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN adc */
-	/* USER CODE END adc */
-};
-
-&bsec{
-	status = "okay";
-
-	/* USER CODE BEGIN bsec */
-	/* USER CODE END bsec */
-};
-
-&crc1{
-	status = "okay";
-
-	/* USER CODE BEGIN crc1 */
-	/* USER CODE END crc1 */
-};
-
-&cryp1{
-	status = "okay";
-
-	/* USER CODE BEGIN cryp1 */
-	/* USER CODE END cryp1 */
-};
-
-&dts{
-	status = "okay";
-
-	/* USER CODE BEGIN dts */
-	/* USER CODE END dts */
-};
-
-&ethernet0{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&eth1_pins_mx>;
-	pinctrl-1 = <&eth1_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN ethernet0 */
-	/* USER CODE END ethernet0 */
-};
-
-&gpu{
-	status = "okay";
-
-	/* USER CODE BEGIN gpu */
-	/* USER CODE END gpu */
-};
-
-&hash1{
-	status = "okay";
-
-	/* USER CODE BEGIN hash1 */
-	/* USER CODE END hash1 */
-};
-
-&hsem{
-	status = "okay";
-
-	/* USER CODE BEGIN hsem */
-	/* USER CODE END hsem */
-};
-
-&i2c2{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&i2c2_pins_mx>;
-	pinctrl-1 = <&i2c2_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN i2c2 */
-	/* USER CODE END i2c2 */
-};
-
-&i2c4{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&i2c4_pins_mx>;
-	pinctrl-1 = <&i2c4_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN i2c4 */
-	/* USER CODE END i2c4 */
-};
-
-&i2s2{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&i2s2_pins_mx>;
-	pinctrl-1 = <&i2s2_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN i2s2 */
-	/* USER CODE END i2s2 */
-};
-
-&ipcc{
-	status = "okay";
-
-	/* USER CODE BEGIN ipcc */
-	/* USER CODE END ipcc */
-};
-
-&ltdc{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&ltdc_pins_mx>;
-	pinctrl-1 = <&ltdc_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN ltdc */
-	/* USER CODE END ltdc */
-};
-
-&m_can1{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&fdcan1_pins_mx>;
-	pinctrl-1 = <&fdcan1_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN m_can1 */
-	/* USER CODE END m_can1 */
-};
-
-&qspi{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&quadspi_pins_mx>;
-	pinctrl-1 = <&quadspi_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN qspi */
-	/* USER CODE END qspi */
-};
-
-&rcc{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN rcc */
-	/* USER CODE END rcc */
-};
-
-&rng1{
-	status = "okay";
-
-	/* USER CODE BEGIN rng1 */
-	/* USER CODE END rng1 */
-};
-
-&rtc{
-	status = "okay";
-
-	/* USER CODE BEGIN rtc */
-	/* USER CODE END rtc */
-};
-
-&sdmmc1{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "opendrain", "sleep";
-	pinctrl-0 = <&sdmmc1_pins_mx>;
-	pinctrl-1 = <&sdmmc1_opendrain_pins_mx>;
-	pinctrl-2 = <&sdmmc1_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN sdmmc1 */
-	/* USER CODE END sdmmc1 */
-};
-
-&sdmmc2{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "opendrain", "sleep";
-	pinctrl-0 = <&sdmmc2_pins_mx>;
-	pinctrl-1 = <&sdmmc2_opendrain_pins_mx>;
-	pinctrl-2 = <&sdmmc2_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN sdmmc2 */
-	/* USER CODE END sdmmc2 */
-};
-
-&timers1{
-	status = "okay";
-
-	/* USER CODE BEGIN timers1 */
-	/* USER CODE END timers1 */
-
-	pwm{
-		pinctrl-names = "default", "sleep";
-		pinctrl-0 = <&tim1_pwm_pins_mx>;
-		pinctrl-1 = <&tim1_pwm_sleep_pins_mx>;
-		status = "okay";
-
-		/* USER CODE BEGIN timers1_pwm */
-		/* USER CODE END timers1_pwm */
-	};
-};
-
-&timers4{
-	status = "okay";
-
-	/* USER CODE BEGIN timers4 */
-	/* USER CODE END timers4 */
-
-	pwm{
-		pinctrl-names = "default", "sleep";
-		pinctrl-0 = <&tim4_pwm_pins_mx>;
-		pinctrl-1 = <&tim4_pwm_sleep_pins_mx>;
-		status = "okay";
-
-		/* USER CODE BEGIN timers4_pwm */
-		/* USER CODE END timers4_pwm */
-	};
-};
-
-&uart4{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&uart4_pins_mx>;
-	pinctrl-1 = <&uart4_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN uart4 */
-	/* USER CODE END uart4 */
-};
-
-&usart2{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&usart2_pins_mx>;
-	pinctrl-1 = <&usart2_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN usart2 */
-	/* USER CODE END usart2 */
-};
-
-&usart6{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&usart6_pins_mx>;
-	pinctrl-1 = <&usart6_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN usart6 */
-	/* USER CODE END usart6 */
-};
-
-&usbh_ehci{
-	status = "okay";
-
-	/* USER CODE BEGIN usbh_ehci */
-	/* USER CODE END usbh_ehci */
-};
-
-&usbh_ohci{
-	status = "okay";
-
-	/* USER CODE BEGIN usbh_ohci */
-	/* USER CODE END usbh_ohci */
-};
-
-&usbotg_hs{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&usb_otg_hs_pins_mx>;
-	pinctrl-1 = <&usb_otg_hs_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN usbotg_hs */
-	/* USER CODE END usbotg_hs */
-};
-
-&usbphyc{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc */
-	/* USER CODE END usbphyc */
-};
-
-&usbphyc_port0{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc_port0 */
-	/* USER CODE END usbphyc_port0 */
-};
-
-&usbphyc_port1{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc_port1 */
-	/* USER CODE END usbphyc_port1 */
-};
-
-&vrefbuf{
-	status = "okay";
-
-	/* USER CODE BEGIN vrefbuf */
-	/* USER CODE END vrefbuf */
-};
-
-/* USER CODE BEGIN addons */
-/* USER CODE END addons */
-
diff --git a/conf/machine/cubemx/t1000-s/DeviceTree/t1000-s/tf-a/stm32mp157c-t1000-s-mx.dts b/conf/machine/cubemx/t1000-s/DeviceTree/t1000-s/tf-a/stm32mp157c-t1000-s-mx.dts
deleted file mode 100644
index 1a4158e02444d1097ec6e51d71f479ae8dd5e51d..0000000000000000000000000000000000000000
--- a/conf/machine/cubemx/t1000-s/DeviceTree/t1000-s/tf-a/stm32mp157c-t1000-s-mx.dts
+++ /dev/null
@@ -1,355 +0,0 @@
-/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
-/*
- * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
- * Author: STM32CubeMX code generation for STMicroelectronics.
- */
-
-/dts-v1/;
-#include <dt-bindings/clock/stm32mp1-clksrc.h>
-#include "stm32mp15-mx.h"
-
-#include "stm32mp157c.dtsi"
-#include "stm32mp157cad-pinctrl.dtsi"
-#include "stm32mp15-ddr.dtsi"
-#include "stm32mp157c-security.dtsi"
-
-/* USER CODE BEGIN includes */
-/* USER CODE END includes */
-
-/ {
-	model = "STMicroelectronics custom STM32CubeMX board";
-	compatible = "st,stm32mp157c-t1000-s-mx", "st,stm32mp157";
-
-	/* USER CODE BEGIN root */
-	/* USER CODE END root */
-
-	clocks {
-		/* USER CODE BEGIN clocks */
-		/* USER CODE END clocks */
-
-		clk_lse: clk-lse {
-			/* USER CODE BEGIN clocks */
-			/* USER CODE END clocks */
-			st,drive=<LSEDRV_MEDIUM_HIGH>;
-		};
-
-		clk_hse: clk-hse {
-			/* USER CODE BEGIN clocks */
-			/* USER CODE END clocks */
-		};
-	};
-
-}; /*root*/
-
-&pinctrl {
-	quadspi_pins_mx: quadspi_mx-0 {
-		pins1 {
-			pinmux = <STM32_PINMUX('B', 6, AF10)>, /* QUADSPI_BK1_NCS */
-					 <STM32_PINMUX('C', 0, AF10)>; /* QUADSPI_BK2_NCS */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins2 {
-			pinmux = <STM32_PINMUX('E', 7, AF10)>, /* QUADSPI_BK2_IO0 */
-					 <STM32_PINMUX('E', 8, AF10)>, /* QUADSPI_BK2_IO1 */
-					 <STM32_PINMUX('E', 9, AF10)>, /* QUADSPI_BK2_IO2 */
-					 <STM32_PINMUX('E', 10, AF10)>, /* QUADSPI_BK2_IO3 */
-					 <STM32_PINMUX('F', 6, AF9)>, /* QUADSPI_BK1_IO3 */
-					 <STM32_PINMUX('F', 7, AF9)>, /* QUADSPI_BK1_IO2 */
-					 <STM32_PINMUX('F', 8, AF10)>, /* QUADSPI_BK1_IO0 */
-					 <STM32_PINMUX('F', 9, AF10)>; /* QUADSPI_BK1_IO1 */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins3 {
-			pinmux = <STM32_PINMUX('F', 10, AF9)>; /* QUADSPI_CLK */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <2>;
-		};
-	};
-
-	sdmmc1_pins_mx: sdmmc1_mx-0 {
-		pins1 {
-			pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
-					 <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
-					 <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
-					 <STM32_PINMUX('C', 11, AF12)>, /* SDMMC1_D3 */
-					 <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-		pins2 {
-			pinmux = <STM32_PINMUX('C', 12, AF12)>; /* SDMMC1_CK */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-	};
-
-	sdmmc2_pins_mx: sdmmc2_mx-0 {
-		pins1 {
-			pinmux = <STM32_PINMUX('B', 3, AF9)>, /* SDMMC2_D2 */
-					 <STM32_PINMUX('B', 4, AF9)>, /* SDMMC2_D3 */
-					 <STM32_PINMUX('B', 14, AF9)>, /* SDMMC2_D0 */
-					 <STM32_PINMUX('B', 15, AF9)>, /* SDMMC2_D1 */
-					 <STM32_PINMUX('G', 6, AF10)>; /* SDMMC2_CMD */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-		pins2 {
-			pinmux = <STM32_PINMUX('E', 3, AF9)>; /* SDMMC2_CK */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-	};
-
-	uart4_pins_mx: uart4_mx-0 {
-		pins1 {
-			pinmux = <STM32_PINMUX('B', 2, AF8)>; /* UART4_RX */
-			bias-pull-up;
-		};
-		pins2 {
-			pinmux = <STM32_PINMUX('G', 11, AF6)>; /* UART4_TX */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-	};
-
-	usb_otg_hs_pins_mx: usb_otg_hs_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
-		};
-	};
-
-	/* USER CODE BEGIN pinctrl */
-	/* USER CODE END pinctrl */
-};
-
-&pinctrl_z {
-	/* USER CODE BEGIN pinctrl_z */
-	/* USER CODE END pinctrl_z */
-};
-
-&rcc {
-	st,csi-cal;
-	st,hsi-cal;
-	st,cal-sec = <60>;
-	st,clksrc = <
-		CLK_MPU_PLL1P
-		CLK_AXI_PLL2P
-		CLK_MCU_PLL3P
-		CLK_PLL12_HSE
-		CLK_PLL3_HSE
-		CLK_PLL4_HSE
-		CLK_RTC_LSE
-		CLK_MCO1_DISABLED
-		CLK_MCO2_DISABLED
-	>;
-	st,clkdiv = <
-		1 		/*MPU*/
-		0 		/*AXI*/
-		0 		/*MCU*/
-		1 		/*APB1*/
-		1 		/*APB2*/
-		1 		/*APB3*/
-		1 		/*APB4*/
-		2 		/*APB5*/
-		0 		/*RTC*/
-		0 		/*MCO1*/
-		0 		/*MCO2*/
-	>;
-	st,pkcs = <
-		CLK_CKPER_HSE
-		CLK_QSPI_ACLK
-		CLK_ETH_PLL4P
-		CLK_SDMMC12_PLL4P
-		CLK_STGEN_HSE
-		CLK_USBPHY_HSE
-		CLK_SPI2S1_DISABLED
-		CLK_SPI2S23_PLL4P
-		CLK_SPI45_DISABLED
-		CLK_SPI6_DISABLED
-		CLK_I2C46_HSI
-		CLK_SDMMC3_DISABLED
-		CLK_USBO_USBPHY
-		CLK_ADC_CKPER
-		CLK_CEC_DISABLED
-		CLK_I2C12_HSI
-		CLK_I2C35_DISABLED
-		CLK_UART1_DISABLED
-		CLK_UART24_PCLK1
-		CLK_UART35_DISABLED
-		CLK_UART6_PCLK2
-		CLK_UART78_DISABLED
-		CLK_SPDIF_DISABLED
-		CLK_FDCAN_HSE
-		CLK_SAI1_DISABLED
-		CLK_SAI2_DISABLED
-		CLK_SAI3_DISABLED
-		CLK_SAI4_DISABLED
-		CLK_RNG1_CSI
-		CLK_LPTIM1_DISABLED
-		CLK_LPTIM23_DISABLED
-		CLK_LPTIM45_DISABLED
-	>;
-	pll1:st,pll@0 {
-		cfg = < 2 80 0 1 1 1>;
-	};
-	pll2:st,pll@1 {
-		cfg = < 2 65 1 1 0 7>;
-	};
-	pll3:st,pll@2 {
-		cfg = < 2 97 3 1 1 1>;
-	};
-	pll4:st,pll@3 {
-		cfg = < 5 124 9 9 9 3>;
-	};
-};
-
-&bsec{
-	status = "okay";
-	secure-status = "okay";
-
-	/* USER CODE BEGIN bsec */
-	/* USER CODE END bsec */
-};
-
-&etzpc{
-	st,decprot = <
-	/*"Non Secured" peripherals*/
-	DECPROT(STM32MP1_ETZPC_ADC_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-	DECPROT(STM32MP1_ETZPC_CRYP1_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-	DECPROT(STM32MP1_ETZPC_ETH_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-	DECPROT(STM32MP1_ETZPC_TT_FDCAN_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-	DECPROT(STM32MP1_ETZPC_HASH1_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-	DECPROT(STM32MP1_ETZPC_I2C2_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-	DECPROT(STM32MP1_ETZPC_I2C4_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-	DECPROT(STM32MP1_ETZPC_SPI2_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-	DECPROT(STM32MP1_ETZPC_QSPI_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-	DECPROT(STM32MP1_ETZPC_DLYBQ_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-	DECPROT(STM32MP1_ETZPC_RNG1_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-	DECPROT(STM32MP1_ETZPC_TIM1_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-	DECPROT(STM32MP1_ETZPC_TIM4_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-	DECPROT(STM32MP1_ETZPC_UART4_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-	DECPROT(STM32MP1_ETZPC_USART2_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-	DECPROT(STM32MP1_ETZPC_USART6_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-	DECPROT(STM32MP1_ETZPC_OTG_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-	DECPROT(STM32MP1_ETZPC_VREFBUF_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-
-	/*Restriction: following IDs are not managed  - please to use User-Section if needed:
-		STM32MP1_ETZPC_DMA1_ID, STM32MP1_ETZPC_DMA2_ID, STM32MP1_ETZPC_DMAMUX_ID,
-		STM32MP1_ETZPC_SRAMx_ID, STM32MP1_ETZPC_RETRAM_ID, STM32MP1_ETZPC_BKPSRAM_ID*/
-
-	/* USER CODE BEGIN etzpc_decprot */
-     /*STM32CubeMX generates a basic and standard configuration for ETZPC.
-     Additional device configurations can be added here if needed.
-     "etzpc" node could be also overloaded in "addons" User-Section.*/
-	/* USER CODE END etzpc_decprot */
-	>;
-
-	secure-status = "okay";
-
-	/* USER CODE BEGIN etzpc */
-	/* USER CODE END etzpc */
-};
-
-&qspi{
-	pinctrl-names = "default";
-	pinctrl-0 = <&quadspi_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN qspi */
-	/* USER CODE END qspi */
-};
-
-&rcc{
-	status = "okay";
-	secure-status = "okay";
-
-	/* USER CODE BEGIN rcc */
-	/* USER CODE END rcc */
-};
-
-&rng1{
-	status = "okay";
-	secure-status = "okay";
-
-	/* USER CODE BEGIN rng1 */
-	/* USER CODE END rng1 */
-};
-
-&rtc{
-	status = "okay";
-	secure-status = "okay";
-
-	/* USER CODE BEGIN rtc */
-	/* USER CODE END rtc */
-};
-
-&sdmmc1{
-	pinctrl-names = "default";
-	pinctrl-0 = <&sdmmc1_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN sdmmc1 */
-	/* USER CODE END sdmmc1 */
-};
-
-&sdmmc2{
-	pinctrl-names = "default";
-	pinctrl-0 = <&sdmmc2_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN sdmmc2 */
-	/* USER CODE END sdmmc2 */
-};
-
-&uart4{
-	pinctrl-names = "default";
-	pinctrl-0 = <&uart4_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN uart4 */
-	/* USER CODE END uart4 */
-};
-
-&usbotg_hs{
-	pinctrl-names = "default";
-	pinctrl-0 = <&usb_otg_hs_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN usbotg_hs */
-	/* USER CODE END usbotg_hs */
-};
-
-&usbphyc{
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc */
-	/* USER CODE END usbphyc */
-};
-
-&usbphyc_port0{
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc_port0 */
-	/* USER CODE END usbphyc_port0 */
-};
-
-&usbphyc_port1{
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc_port1 */
-	/* USER CODE END usbphyc_port1 */
-};
-
-/* USER CODE BEGIN addons */
-/* USER CODE END addons */
-
diff --git a/conf/machine/cubemx/t1000-s/DeviceTree/t1000-s/u-boot/stm32mp15-mx.h b/conf/machine/cubemx/t1000-s/DeviceTree/t1000-s/u-boot/stm32mp15-mx.h
deleted file mode 100644
index 9abe0891ec7d433fb15136da080dc87904a49055..0000000000000000000000000000000000000000
--- a/conf/machine/cubemx/t1000-s/DeviceTree/t1000-s/u-boot/stm32mp15-mx.h
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright (C) 2015-2018, STMicroelectronics - All Rights Reserved
- *
- * SPDX-License-Identifier:	GPL-2.0+	BSD-3-Clause
- *
- */
-
-/*
- * File generated by STMicroelectronics STM32CubeMX DDR Tool for MPUs
- * DDR type: DDR3 / DDR3L
- * DDR width: 16bits
- * DDR density: 4Gb
- * System frequency: 528000Khz
- * Relaxed Timing Mode: false
- * Address mapping type: RBC
- *
- * Save Date: 2019.11.25, save Time: 15:00:39
- */
-
-#define DDR_MEM_NAME	"DDR3-DDR3L 16bits 528000Khz"
-#define DDR_MEM_SPEED	528000
-#define DDR_MEM_SIZE	0x20000000
-
-#define DDR_MSTR 0x00041401
-#define DDR_MRCTRL0 0x00000010
-#define DDR_MRCTRL1 0x00000000
-#define DDR_DERATEEN 0x00000000
-#define DDR_DERATEINT 0x00800000
-#define DDR_PWRCTL 0x00000000
-#define DDR_PWRTMG 0x00400010
-#define DDR_HWLPCTL 0x00000000
-#define DDR_RFSHCTL0 0x00210000
-#define DDR_RFSHCTL3 0x00000000
-#define DDR_RFSHTMG 0x0040008A
-#define DDR_CRCPARCTL0 0x00000000
-#define DDR_DRAMTMG0 0x121B1214
-#define DDR_DRAMTMG1 0x000A041B
-#define DDR_DRAMTMG2 0x0607080F
-#define DDR_DRAMTMG3 0x0050400C
-#define DDR_DRAMTMG4 0x07040607
-#define DDR_DRAMTMG5 0x06060403
-#define DDR_DRAMTMG6 0x02020002
-#define DDR_DRAMTMG7 0x00000202
-#define DDR_DRAMTMG8 0x00001005
-#define DDR_DRAMTMG14 0x000000A0
-#define DDR_ZQCTL0 0xC2000040
-#define DDR_DFITMG0 0x02050105
-#define DDR_DFITMG1 0x00000202
-#define DDR_DFILPCFG0 0x07000000
-#define DDR_DFIUPD0 0xC0400003
-#define DDR_DFIUPD1 0x00000000
-#define DDR_DFIUPD2 0x00000000
-#define DDR_DFIPHYMSTR 0x00000000
-#define DDR_ODTCFG 0x06000600
-#define DDR_ODTMAP 0x00000001
-#define DDR_SCHED 0x00000C01
-#define DDR_SCHED1 0x00000000
-#define DDR_PERFHPR1 0x01000001
-#define DDR_PERFLPR1 0x08000200
-#define DDR_PERFWR1 0x08000400
-#define DDR_DBG0 0x00000000
-#define DDR_DBG1 0x00000000
-#define DDR_DBGCMD 0x00000000
-#define DDR_POISONCFG 0x00000000
-#define DDR_PCCFG 0x00000010
-#define DDR_PCFGR_0 0x00010000
-#define DDR_PCFGW_0 0x00000000
-#define DDR_PCFGQOS0_0 0x02100C03
-#define DDR_PCFGQOS1_0 0x00800100
-#define DDR_PCFGWQOS0_0 0x01100C03
-#define DDR_PCFGWQOS1_0 0x01000200
-#define DDR_PCFGR_1 0x00010000
-#define DDR_PCFGW_1 0x00000000
-#define DDR_PCFGQOS0_1 0x02100C03
-#define DDR_PCFGQOS1_1 0x00800040
-#define DDR_PCFGWQOS0_1 0x01100C03
-#define DDR_PCFGWQOS1_1 0x01000200
-#define DDR_ADDRMAP1 0x00070707
-#define DDR_ADDRMAP2 0x00000000
-#define DDR_ADDRMAP3 0x1F000000
-#define DDR_ADDRMAP4 0x00001F1F
-#define DDR_ADDRMAP5 0x06060606
-#define DDR_ADDRMAP6 0x0F060606
-#define DDR_ADDRMAP9 0x00000000
-#define DDR_ADDRMAP10 0x00000000
-#define DDR_ADDRMAP11 0x00000000
-#define DDR_PGCR 0x01442E02
-#define DDR_PTR0 0x0022A41B
-#define DDR_PTR1 0x047C0740
-#define DDR_PTR2 0x042D9C80
-#define DDR_ACIOCR 0x10400812
-#define DDR_DXCCR 0x00000C40
-#define DDR_DSGCR 0xF200001F
-#define DDR_DCR 0x0000000B
-#define DDR_DTPR0 0x36D477D0
-#define DDR_DTPR1 0x098A00D8
-#define DDR_DTPR2 0x10023600
-#define DDR_MR0 0x00000830
-#define DDR_MR1 0x00000000
-#define DDR_MR2 0x00000248
-#define DDR_MR3 0x00000000
-#define DDR_ODTCR 0x00010000
-#define DDR_ZQ0CR1 0x00000038
-#define DDR_DX0GCR 0x0000CE81
-#define DDR_DX0DLLCR 0x40000000
-#define DDR_DX0DQTR 0x55050005
-#define DDR_DX0DQSTR 0x3D202000
-#define DDR_DX1GCR 0x0000CE81
-#define DDR_DX1DLLCR 0x40000000
-#define DDR_DX1DQTR 0x00050500
-#define DDR_DX1DQSTR 0x3DB02000
-#define DDR_DX2GCR 0x0000C881
-#define DDR_DX2DLLCR 0x40000000
-#define DDR_DX2DQTR 0xFFFFFFFF
-#define DDR_DX2DQSTR 0x3DB02000
-#define DDR_DX3GCR 0x0000C881
-#define DDR_DX3DLLCR 0x40000000
-#define DDR_DX3DQTR 0xFFFFFFFF
-#define DDR_DX3DQSTR 0x3DB02000
diff --git a/conf/machine/cubemx/t1000-s/DeviceTree/t1000-s/u-boot/stm32mp157c-t1000-s-mx-u-boot.dtsi b/conf/machine/cubemx/t1000-s/DeviceTree/t1000-s/u-boot/stm32mp157c-t1000-s-mx-u-boot.dtsi
deleted file mode 100644
index 76dc78c13d1a739841c217271e8706f331dde49f..0000000000000000000000000000000000000000
--- a/conf/machine/cubemx/t1000-s/DeviceTree/t1000-s/u-boot/stm32mp157c-t1000-s-mx-u-boot.dtsi
+++ /dev/null
@@ -1,203 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause*/
-/*
- * Copyright (C) 2019, STMicroelectronics - All Rights Reserved
- * Author: STM32CubeMX code generation for STMicroelectronics.
- */
-
-#include <dt-bindings/clock/stm32mp1-clksrc.h>
-#include "stm32mp15-mx.h"
-
-#include "stm32mp157-u-boot.dtsi"
-#include "stm32mp15-ddr.dtsi"
-
-/* USER CODE BEGIN includes */
-/* USER CODE END includes */
-
-/ {
-
-	/* USER CODE BEGIN root */
-	/* USER CODE END root */
-
-	clocks {
-		/* USER CODE BEGIN clocks */
-		/* USER CODE END clocks */
-
-		clk_hsi: clk-hsi {
-			/* USER CODE BEGIN clocks */
-			/* USER CODE END clocks */
-			u-boot,dm-pre-reloc;
-		};
-
-		clk_csi: clk-csi {
-			/* USER CODE BEGIN clocks */
-			/* USER CODE END clocks */
-			u-boot,dm-pre-reloc;
-		};
-
-		clk_lse: clk-lse {
-			/* USER CODE BEGIN clocks */
-			/* USER CODE END clocks */
-			st,drive=<LSEDRV_MEDIUM_HIGH>;
-			u-boot,dm-pre-reloc;
-		};
-
-		clk_hse: clk-hse {
-			/* USER CODE BEGIN clocks */
-			/* USER CODE END clocks */
-			u-boot,dm-pre-reloc;
-		};
-	};
-
-}; /*root*/
-
-&rcc {
-	u-boot,dm-pre-reloc;
-	st,clksrc = <
-		CLK_MPU_PLL1P
-		CLK_AXI_PLL2P
-		CLK_MCU_PLL3P
-		CLK_PLL12_HSE
-		CLK_PLL3_HSE
-		CLK_PLL4_HSE
-		CLK_RTC_LSE
-		CLK_MCO1_DISABLED
-		CLK_MCO2_DISABLED
-	>;
-	st,clkdiv = <
-		1 		/*MPU*/
-		0 		/*AXI*/
-		0 		/*MCU*/
-		1 		/*APB1*/
-		1 		/*APB2*/
-		1 		/*APB3*/
-		1 		/*APB4*/
-		2 		/*APB5*/
-		0 		/*RTC*/
-		0 		/*MCO1*/
-		0 		/*MCO2*/
-	>;
-	st,pkcs = <
-		CLK_CKPER_HSE
-		CLK_QSPI_ACLK
-		CLK_ETH_PLL4P
-		CLK_SDMMC12_PLL4P
-		CLK_STGEN_HSE
-		CLK_USBPHY_HSE
-		CLK_SPI2S1_DISABLED
-		CLK_SPI2S23_PLL4P
-		CLK_SPI45_DISABLED
-		CLK_SPI6_DISABLED
-		CLK_I2C46_HSI
-		CLK_SDMMC3_DISABLED
-		CLK_USBO_USBPHY
-		CLK_ADC_CKPER
-		CLK_CEC_DISABLED
-		CLK_I2C12_HSI
-		CLK_I2C35_DISABLED
-		CLK_UART1_DISABLED
-		CLK_UART24_PCLK1
-		CLK_UART35_DISABLED
-		CLK_UART6_PCLK2
-		CLK_UART78_DISABLED
-		CLK_SPDIF_DISABLED
-		CLK_FDCAN_HSE
-		CLK_SAI1_DISABLED
-		CLK_SAI2_DISABLED
-		CLK_SAI3_DISABLED
-		CLK_SAI4_DISABLED
-		CLK_RNG1_CSI
-		CLK_LPTIM1_DISABLED
-		CLK_LPTIM23_DISABLED
-		CLK_LPTIM45_DISABLED
-	>;
-	pll1:st,pll@0 {
-		cfg = < 2 80 0 1 1 1>;
-		u-boot,dm-pre-reloc;
-	};
-	pll2:st,pll@1 {
-		cfg = < 2 65 1 1 0 7>;
-		u-boot,dm-pre-reloc;
-	};
-	pll3:st,pll@2 {
-		cfg = < 2 97 3 1 1 1>;
-		u-boot,dm-pre-reloc;
-	};
-	pll4:st,pll@3 {
-		cfg = < 5 124 9 9 9 3>;
-		u-boot,dm-pre-reloc;
-	};
-};
-
-&ltdc{
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN ltdc */
-	/* USER CODE END ltdc */
-};
-
-&qspi{
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN qspi */
-	/* USER CODE END qspi */
-};
-
-&rcc{
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN rcc */
-	/* USER CODE END rcc */
-};
-
-&sdmmc1{
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN sdmmc1 */
-	/* USER CODE END sdmmc1 */
-};
-
-&sdmmc2{
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN sdmmc2 */
-	/* USER CODE END sdmmc2 */
-};
-
-&uart4{
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN uart4 */
-	/* USER CODE END uart4 */
-};
-
-&usbotg_hs{
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN usbotg_hs */
-	/* USER CODE END usbotg_hs */
-};
-
-&usbphyc{
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN usbphyc */
-	/* USER CODE END usbphyc */
-};
-
-&usbphyc_port0{
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN usbphyc_port0 */
-	/* USER CODE END usbphyc_port0 */
-};
-
-&usbphyc_port1{
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN usbphyc_port1 */
-	/* USER CODE END usbphyc_port1 */
-};
-
-/* USER CODE BEGIN addons */
-/* USER CODE END addons */
-
diff --git a/conf/machine/cubemx/t1000-s/DeviceTree/t1000-s/u-boot/stm32mp157c-t1000-s-mx.dts b/conf/machine/cubemx/t1000-s/DeviceTree/t1000-s/u-boot/stm32mp157c-t1000-s-mx.dts
deleted file mode 100644
index ee68baf421a1529cb19db7e712dc2ba6e73f0ba2..0000000000000000000000000000000000000000
--- a/conf/machine/cubemx/t1000-s/DeviceTree/t1000-s/u-boot/stm32mp157c-t1000-s-mx.dts
+++ /dev/null
@@ -1,899 +0,0 @@
-/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
-/*
- * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
- * Author: STM32CubeMX code generation for STMicroelectronics.
- */
-
-/dts-v1/;
-#include "stm32mp157c.dtsi"
-#include "stm32mp157c-m4-srm.dtsi"
-#include "stm32mp157cad-pinctrl.dtsi"
-
-/* USER CODE BEGIN includes */
-/* USER CODE END includes */
-
-/ {
-	model = "STMicroelectronics custom STM32CubeMX board";
-	compatible = "st,stm32mp157c-t1000-s-mx", "st,stm32mp157";
-
-	memory@c0000000 {
-		reg = <0xc0000000 0x20000000>;
-
-		/* USER CODE BEGIN memory */
-		/* USER CODE END memory */
-	};
-
-	reserved-memory {
-		#address-cells = <1>;
-		#size-cells = <1>;
-		ranges;
-
-		/* USER CODE BEGIN reserved-memory */
-		/* USER CODE END reserved-memory */
-
-		gpu_reserved: gpu@dc000000 {
-			reg = <0xdc000000 0x4000000>;
-			no-map;
-		};
-	};
-
-	/* USER CODE BEGIN root */
-	/* USER CODE END root */
-
-	clocks {
-		/* USER CODE BEGIN clocks */
-		/* USER CODE END clocks */
-
-		clk_hsi: clk-hsi {
-			clock-frequency = <64000000>;
-		};
-
-		clk_csi: clk-csi {
-			clock-frequency = <4000000>;
-		};
-
-		clk_lse: clk-lse {
-			clock-frequency = <32768>;
-		};
-
-		clk_hse: clk-hse {
-			clock-frequency = <24000000>;
-		};
-	};
-
-}; /*root*/
-
-&pinctrl {
-	u-boot,dm-pre-reloc;
-
-	adc_pins_mx: adc_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 0, ANALOG)>, /* ADC1_INP16 */
-					 <STM32_PINMUX('B', 1, ANALOG)>; /* ADC1_INP5 */
-		};
-	};
-
-	adc_sleep_pins_mx: adc_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 0, ANALOG)>, /* ADC1_INP16 */
-					 <STM32_PINMUX('B', 1, ANALOG)>; /* ADC1_INP5 */
-		};
-	};
-
-	eth1_pins_mx: eth1_mx-0 {
-		pins1 {
-			pinmux = <STM32_PINMUX('A', 2, AF11)>; /* ETH1_MDIO */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-		pins2 {
-			pinmux = <STM32_PINMUX('A', 7, AF11)>, /* ETH1_CRS_DV */
-					 <STM32_PINMUX('C', 4, AF11)>, /* ETH1_RXD0 */
-					 <STM32_PINMUX('C', 5, AF11)>; /* ETH1_RXD1 */
-			bias-disable;
-		};
-		pins3 {
-			pinmux = <STM32_PINMUX('B', 11, AF11)>; /* ETH1_TX_EN */
-		};
-		pins4 {
-			pinmux = <STM32_PINMUX('B', 12, AF11)>, /* ETH1_TXD0 */
-					 <STM32_PINMUX('B', 13, AF11)>, /* ETH1_TXD1 */
-					 <STM32_PINMUX('C', 1, AF11)>, /* ETH1_MDC */
-					 <STM32_PINMUX('G', 8, AF2)>; /* ETH1_CLK */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-	};
-
-	eth1_sleep_pins_mx: eth1_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 2, ANALOG)>, /* ETH1_MDIO */
-					 <STM32_PINMUX('A', 7, ANALOG)>, /* ETH1_CRS_DV */
-					 <STM32_PINMUX('B', 11, ANALOG)>, /* ETH1_TX_EN */
-					 <STM32_PINMUX('B', 12, ANALOG)>, /* ETH1_TXD0 */
-					 <STM32_PINMUX('B', 13, ANALOG)>, /* ETH1_TXD1 */
-					 <STM32_PINMUX('C', 1, ANALOG)>, /* ETH1_MDC */
-					 <STM32_PINMUX('C', 4, ANALOG)>, /* ETH1_RXD0 */
-					 <STM32_PINMUX('C', 5, ANALOG)>, /* ETH1_RXD1 */
-					 <STM32_PINMUX('G', 8, ANALOG)>; /* ETH1_CLK */
-		};
-	};
-
-	fdcan1_pins_mx: fdcan1_mx-0 {
-		pins1 {
-			pinmux = <STM32_PINMUX('D', 0, AF9)>; /* FDCAN1_RX */
-			bias-disable;
-		};
-		pins2 {
-			pinmux = <STM32_PINMUX('D', 1, AF9)>; /* FDCAN1_TX */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-	};
-
-	fdcan1_sleep_pins_mx: fdcan1_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('D', 0, ANALOG)>, /* FDCAN1_RX */
-					 <STM32_PINMUX('D', 1, ANALOG)>; /* FDCAN1_TX */
-		};
-	};
-
-	i2c2_pins_mx: i2c2_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('D', 7, AF4)>, /* I2C2_SCL */
-					 <STM32_PINMUX('G', 15, AF4)>; /* I2C2_SDA */
-			bias-disable;
-			drive-open-drain;
-			slew-rate = <0>;
-		};
-	};
-
-	i2c2_sleep_pins_mx: i2c2_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('D', 7, ANALOG)>, /* I2C2_SCL */
-					 <STM32_PINMUX('G', 15, ANALOG)>; /* I2C2_SDA */
-		};
-	};
-
-	i2c4_pins_mx: i2c4_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('B', 7, AF6)>, /* I2C4_SDA */
-					 <STM32_PINMUX('E', 2, AF4)>; /* I2C4_SCL */
-			bias-disable;
-			drive-open-drain;
-			slew-rate = <0>;
-		};
-	};
-
-	i2c4_sleep_pins_mx: i2c4_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('B', 7, ANALOG)>, /* I2C4_SDA */
-					 <STM32_PINMUX('E', 2, ANALOG)>; /* I2C4_SCL */
-		};
-	};
-
-	i2s2_pins_mx: i2s2_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 11, AF5)>, /* I2S2_WS */
-					 <STM32_PINMUX('C', 2, AF5)>, /* I2S2_SDI */
-					 <STM32_PINMUX('C', 3, AF5)>, /* I2S2_SDO */
-					 <STM32_PINMUX('D', 3, AF5)>, /* I2S2_CK */
-					 <STM32_PINMUX('E', 1, AF5)>; /* I2S2_MCK */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-	};
-
-	i2s2_sleep_pins_mx: i2s2_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 11, ANALOG)>, /* I2S2_WS */
-					 <STM32_PINMUX('C', 2, ANALOG)>, /* I2S2_SDI */
-					 <STM32_PINMUX('C', 3, ANALOG)>, /* I2S2_SDO */
-					 <STM32_PINMUX('D', 3, ANALOG)>, /* I2S2_CK */
-					 <STM32_PINMUX('E', 1, ANALOG)>; /* I2S2_MCK */
-		};
-	};
-
-	ltdc_pins_mx: ltdc_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('A', 1, AF14)>, /* LTDC_R2 */
-					 <STM32_PINMUX('A', 3, AF14)>, /* LTDC_B5 */
-					 <STM32_PINMUX('A', 4, AF14)>, /* LTDC_VSYNC */
-					 <STM32_PINMUX('A', 5, AF14)>, /* LTDC_R4 */
-					 <STM32_PINMUX('A', 6, AF14)>, /* LTDC_G2 */
-					 <STM32_PINMUX('A', 8, AF14)>, /* LTDC_R6 */
-					 <STM32_PINMUX('A', 12, AF14)>, /* LTDC_R5 */
-					 <STM32_PINMUX('A', 15, AF14)>, /* LTDC_R1 */
-					 <STM32_PINMUX('B', 0, AF9)>, /* LTDC_R3 */
-					 <STM32_PINMUX('B', 5, AF14)>, /* LTDC_G7 */
-					 <STM32_PINMUX('B', 8, AF14)>, /* LTDC_B6 */
-					 <STM32_PINMUX('B', 9, AF14)>, /* LTDC_B7 */
-					 <STM32_PINMUX('B', 10, AF14)>, /* LTDC_G4 */
-					 <STM32_PINMUX('C', 6, AF14)>, /* LTDC_HSYNC */
-					 <STM32_PINMUX('C', 7, AF14)>, /* LTDC_G6 */
-					 <STM32_PINMUX('D', 10, AF14)>, /* LTDC_B3 */
-					 <STM32_PINMUX('E', 4, AF14)>, /* LTDC_B0 */
-					 <STM32_PINMUX('E', 5, AF14)>, /* LTDC_G0 */
-					 <STM32_PINMUX('E', 6, AF14)>, /* LTDC_G1 */
-					 <STM32_PINMUX('E', 11, AF14)>, /* LTDC_G3 */
-					 <STM32_PINMUX('E', 12, AF14)>, /* LTDC_B4 */
-					 <STM32_PINMUX('E', 13, AF14)>, /* LTDC_DE */
-					 <STM32_PINMUX('E', 15, AF14)>, /* LTDC_R7 */
-					 <STM32_PINMUX('F', 11, AF14)>, /* LTDC_G5 */
-					 <STM32_PINMUX('G', 10, AF14)>, /* LTDC_B2 */
-					 <STM32_PINMUX('G', 12, AF14)>, /* LTDC_B1 */
-					 <STM32_PINMUX('G', 13, AF14)>; /* LTDC_R0 */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('E', 14, AF14)>; /* LTDC_CLK */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-	};
-
-	ltdc_sleep_pins_mx: ltdc_sleep_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('A', 1, ANALOG)>, /* LTDC_R2 */
-					 <STM32_PINMUX('A', 3, ANALOG)>, /* LTDC_B5 */
-					 <STM32_PINMUX('A', 4, ANALOG)>, /* LTDC_VSYNC */
-					 <STM32_PINMUX('A', 5, ANALOG)>, /* LTDC_R4 */
-					 <STM32_PINMUX('A', 6, ANALOG)>, /* LTDC_G2 */
-					 <STM32_PINMUX('A', 8, ANALOG)>, /* LTDC_R6 */
-					 <STM32_PINMUX('A', 12, ANALOG)>, /* LTDC_R5 */
-					 <STM32_PINMUX('A', 15, ANALOG)>, /* LTDC_R1 */
-					 <STM32_PINMUX('B', 0, ANALOG)>, /* LTDC_R3 */
-					 <STM32_PINMUX('B', 5, ANALOG)>, /* LTDC_G7 */
-					 <STM32_PINMUX('B', 8, ANALOG)>, /* LTDC_B6 */
-					 <STM32_PINMUX('B', 9, ANALOG)>, /* LTDC_B7 */
-					 <STM32_PINMUX('B', 10, ANALOG)>, /* LTDC_G4 */
-					 <STM32_PINMUX('C', 6, ANALOG)>, /* LTDC_HSYNC */
-					 <STM32_PINMUX('C', 7, ANALOG)>, /* LTDC_G6 */
-					 <STM32_PINMUX('D', 10, ANALOG)>, /* LTDC_B3 */
-					 <STM32_PINMUX('E', 4, ANALOG)>, /* LTDC_B0 */
-					 <STM32_PINMUX('E', 5, ANALOG)>, /* LTDC_G0 */
-					 <STM32_PINMUX('E', 6, ANALOG)>, /* LTDC_G1 */
-					 <STM32_PINMUX('E', 11, ANALOG)>, /* LTDC_G3 */
-					 <STM32_PINMUX('E', 12, ANALOG)>, /* LTDC_B4 */
-					 <STM32_PINMUX('E', 13, ANALOG)>, /* LTDC_DE */
-					 <STM32_PINMUX('E', 14, ANALOG)>, /* LTDC_CLK */
-					 <STM32_PINMUX('E', 15, ANALOG)>, /* LTDC_R7 */
-					 <STM32_PINMUX('F', 11, ANALOG)>, /* LTDC_G5 */
-					 <STM32_PINMUX('G', 10, ANALOG)>, /* LTDC_B2 */
-					 <STM32_PINMUX('G', 12, ANALOG)>, /* LTDC_B1 */
-					 <STM32_PINMUX('G', 13, ANALOG)>; /* LTDC_R0 */
-		};
-	};
-
-	quadspi_pins_mx: quadspi_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 6, AF10)>, /* QUADSPI_BK1_NCS */
-					 <STM32_PINMUX('C', 0, AF10)>; /* QUADSPI_BK2_NCS */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('E', 7, AF10)>, /* QUADSPI_BK2_IO0 */
-					 <STM32_PINMUX('E', 8, AF10)>, /* QUADSPI_BK2_IO1 */
-					 <STM32_PINMUX('E', 9, AF10)>, /* QUADSPI_BK2_IO2 */
-					 <STM32_PINMUX('E', 10, AF10)>, /* QUADSPI_BK2_IO3 */
-					 <STM32_PINMUX('F', 6, AF9)>, /* QUADSPI_BK1_IO3 */
-					 <STM32_PINMUX('F', 7, AF9)>, /* QUADSPI_BK1_IO2 */
-					 <STM32_PINMUX('F', 8, AF10)>, /* QUADSPI_BK1_IO0 */
-					 <STM32_PINMUX('F', 9, AF10)>; /* QUADSPI_BK1_IO1 */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins3 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('F', 10, AF9)>; /* QUADSPI_CLK */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <2>;
-		};
-	};
-
-	quadspi_sleep_pins_mx: quadspi_sleep_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 6, ANALOG)>, /* QUADSPI_BK1_NCS */
-					 <STM32_PINMUX('C', 0, ANALOG)>, /* QUADSPI_BK2_NCS */
-					 <STM32_PINMUX('E', 7, ANALOG)>, /* QUADSPI_BK2_IO0 */
-					 <STM32_PINMUX('E', 8, ANALOG)>, /* QUADSPI_BK2_IO1 */
-					 <STM32_PINMUX('E', 9, ANALOG)>, /* QUADSPI_BK2_IO2 */
-					 <STM32_PINMUX('E', 10, ANALOG)>, /* QUADSPI_BK2_IO3 */
-					 <STM32_PINMUX('F', 6, ANALOG)>, /* QUADSPI_BK1_IO3 */
-					 <STM32_PINMUX('F', 7, ANALOG)>, /* QUADSPI_BK1_IO2 */
-					 <STM32_PINMUX('F', 8, ANALOG)>, /* QUADSPI_BK1_IO0 */
-					 <STM32_PINMUX('F', 9, ANALOG)>, /* QUADSPI_BK1_IO1 */
-					 <STM32_PINMUX('F', 10, ANALOG)>; /* QUADSPI_CLK */
-		};
-	};
-
-	sdmmc1_pins_mx: sdmmc1_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
-					 <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
-					 <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
-					 <STM32_PINMUX('C', 11, AF12)>, /* SDMMC1_D3 */
-					 <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 12, AF12)>; /* SDMMC1_CK */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-	};
-
-	sdmmc1_opendrain_pins_mx: sdmmc1_opendrain_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
-					 <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
-					 <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
-					 <STM32_PINMUX('C', 11, AF12)>; /* SDMMC1_D3 */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 12, AF12)>; /* SDMMC1_CK */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins3 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
-			bias-pull-up;
-			drive-open-drain;
-			slew-rate = <1>;
-		};
-	};
-
-	sdmmc1_sleep_pins_mx: sdmmc1_sleep_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 8, ANALOG)>, /* SDMMC1_D0 */
-					 <STM32_PINMUX('C', 9, ANALOG)>, /* SDMMC1_D1 */
-					 <STM32_PINMUX('C', 10, ANALOG)>, /* SDMMC1_D2 */
-					 <STM32_PINMUX('C', 11, ANALOG)>, /* SDMMC1_D3 */
-					 <STM32_PINMUX('C', 12, ANALOG)>, /* SDMMC1_CK */
-					 <STM32_PINMUX('D', 2, ANALOG)>; /* SDMMC1_CMD */
-		};
-	};
-
-	sdmmc2_pins_mx: sdmmc2_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 3, AF9)>, /* SDMMC2_D2 */
-					 <STM32_PINMUX('B', 4, AF9)>, /* SDMMC2_D3 */
-					 <STM32_PINMUX('B', 14, AF9)>, /* SDMMC2_D0 */
-					 <STM32_PINMUX('B', 15, AF9)>, /* SDMMC2_D1 */
-					 <STM32_PINMUX('G', 6, AF10)>; /* SDMMC2_CMD */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('E', 3, AF9)>; /* SDMMC2_CK */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-	};
-
-	sdmmc2_opendrain_pins_mx: sdmmc2_opendrain_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 3, AF9)>, /* SDMMC2_D2 */
-					 <STM32_PINMUX('B', 4, AF9)>, /* SDMMC2_D3 */
-					 <STM32_PINMUX('B', 14, AF9)>, /* SDMMC2_D0 */
-					 <STM32_PINMUX('B', 15, AF9)>; /* SDMMC2_D1 */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('E', 3, AF9)>; /* SDMMC2_CK */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins3 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('G', 6, AF10)>; /* SDMMC2_CMD */
-			bias-pull-up;
-			drive-open-drain;
-			slew-rate = <1>;
-		};
-	};
-
-	sdmmc2_sleep_pins_mx: sdmmc2_sleep_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 3, ANALOG)>, /* SDMMC2_D2 */
-					 <STM32_PINMUX('B', 4, ANALOG)>, /* SDMMC2_D3 */
-					 <STM32_PINMUX('B', 14, ANALOG)>, /* SDMMC2_D0 */
-					 <STM32_PINMUX('B', 15, ANALOG)>, /* SDMMC2_D1 */
-					 <STM32_PINMUX('E', 3, ANALOG)>, /* SDMMC2_CK */
-					 <STM32_PINMUX('G', 6, ANALOG)>; /* SDMMC2_CMD */
-		};
-	};
-
-	tim1_pwm_pins_mx: tim1_pwm_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 9, AF1)>; /* TIM1_CH2 */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-	};
-
-	tim1_pwm_sleep_pins_mx: tim1_pwm_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 9, ANALOG)>; /* TIM1_CH2 */
-		};
-	};
-
-	tim4_pwm_pins_mx: tim4_pwm_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('D', 14, AF2)>; /* TIM4_CH3 */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-	};
-
-	tim4_pwm_sleep_pins_mx: tim4_pwm_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('D', 14, ANALOG)>; /* TIM4_CH3 */
-		};
-	};
-
-	uart4_pins_mx: uart4_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 2, AF8)>; /* UART4_RX */
-			bias-pull-up;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('G', 11, AF6)>; /* UART4_TX */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-	};
-
-	uart4_sleep_pins_mx: uart4_sleep_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 2, ANALOG)>, /* UART4_RX */
-					 <STM32_PINMUX('G', 11, ANALOG)>; /* UART4_TX */
-		};
-	};
-
-	usart2_pins_mx: usart2_mx-0 {
-		pins1 {
-			pinmux = <STM32_PINMUX('D', 4, AF7)>; /* USART2_RTS */
-			bias-pull-down;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-		pins2 {
-			pinmux = <STM32_PINMUX('D', 5, AF7)>; /* USART2_TX */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-		pins3 {
-			pinmux = <STM32_PINMUX('D', 6, AF7)>; /* USART2_RX */
-			bias-pull-up;
-		};
-	};
-
-	usart2_sleep_pins_mx: usart2_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('D', 4, ANALOG)>, /* USART2_RTS */
-					 <STM32_PINMUX('D', 5, ANALOG)>, /* USART2_TX */
-					 <STM32_PINMUX('D', 6, ANALOG)>; /* USART2_RX */
-		};
-	};
-
-	usart6_pins_mx: usart6_mx-0 {
-		pins1 {
-			pinmux = <STM32_PINMUX('G', 14, AF7)>; /* USART6_TX */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-		pins2 {
-			pinmux = <STM32_PINMUX('G', 9, AF7)>; /* USART6_RX */
-			bias-pull-up;
-		};
-	};
-
-	usart6_sleep_pins_mx: usart6_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('G', 9, ANALOG)>, /* USART6_RX */
-					 <STM32_PINMUX('G', 14, ANALOG)>; /* USART6_TX */
-		};
-	};
-
-	usb_otg_hs_pins_mx: usb_otg_hs_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
-		};
-	};
-
-	usb_otg_hs_sleep_pins_mx: usb_otg_hs_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
-		};
-	};
-
-	/* USER CODE BEGIN pinctrl */
-	/* USER CODE END pinctrl */
-};
-
-&pinctrl_z {
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN pinctrl_z */
-	/* USER CODE END pinctrl_z */
-};
-
-&m4_rproc{
-	mboxes = <&ipcc 0>, <&ipcc 1>, <&ipcc 2>;
-	mbox-names = "vq0", "vq1", "shutdown";
-	recovery;
-	status = "okay";
-
-	/* USER CODE BEGIN m4_rproc */
-	/* USER CODE END m4_rproc */
-};
-
-&adc{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&adc_pins_mx>;
-	pinctrl-1 = <&adc_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN adc */
-	/* USER CODE END adc */
-};
-
-&bsec{
-	status = "okay";
-
-	/* USER CODE BEGIN bsec */
-	/* USER CODE END bsec */
-};
-
-&crc1{
-	status = "okay";
-
-	/* USER CODE BEGIN crc1 */
-	/* USER CODE END crc1 */
-};
-
-&cryp1{
-	status = "okay";
-
-	/* USER CODE BEGIN cryp1 */
-	/* USER CODE END cryp1 */
-};
-
-&dts{
-	status = "okay";
-
-	/* USER CODE BEGIN dts */
-	/* USER CODE END dts */
-};
-
-&ethernet0{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&eth1_pins_mx>;
-	pinctrl-1 = <&eth1_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN ethernet0 */
-	/* USER CODE END ethernet0 */
-};
-
-&gpu{
-	status = "okay";
-
-	/* USER CODE BEGIN gpu */
-	/* USER CODE END gpu */
-};
-
-&hash1{
-	status = "okay";
-
-	/* USER CODE BEGIN hash1 */
-	/* USER CODE END hash1 */
-};
-
-&hsem{
-	status = "okay";
-
-	/* USER CODE BEGIN hsem */
-	/* USER CODE END hsem */
-};
-
-&i2c2{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&i2c2_pins_mx>;
-	pinctrl-1 = <&i2c2_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN i2c2 */
-	/* USER CODE END i2c2 */
-};
-
-&i2c4{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&i2c4_pins_mx>;
-	pinctrl-1 = <&i2c4_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN i2c4 */
-	/* USER CODE END i2c4 */
-};
-
-&i2s2{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&i2s2_pins_mx>;
-	pinctrl-1 = <&i2s2_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN i2s2 */
-	/* USER CODE END i2s2 */
-};
-
-&ipcc{
-	status = "okay";
-
-	/* USER CODE BEGIN ipcc */
-	/* USER CODE END ipcc */
-};
-
-&ltdc{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&ltdc_pins_mx>;
-	pinctrl-1 = <&ltdc_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN ltdc */
-	/* USER CODE END ltdc */
-};
-
-&m_can1{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&fdcan1_pins_mx>;
-	pinctrl-1 = <&fdcan1_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN m_can1 */
-	/* USER CODE END m_can1 */
-};
-
-&qspi{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&quadspi_pins_mx>;
-	pinctrl-1 = <&quadspi_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN qspi */
-	/* USER CODE END qspi */
-};
-
-&rcc{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN rcc */
-	/* USER CODE END rcc */
-};
-
-&rng1{
-	status = "okay";
-
-	/* USER CODE BEGIN rng1 */
-	/* USER CODE END rng1 */
-};
-
-&rtc{
-	status = "okay";
-
-	/* USER CODE BEGIN rtc */
-	/* USER CODE END rtc */
-};
-
-&sdmmc1{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "opendrain", "sleep";
-	pinctrl-0 = <&sdmmc1_pins_mx>;
-	pinctrl-1 = <&sdmmc1_opendrain_pins_mx>;
-	pinctrl-2 = <&sdmmc1_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN sdmmc1 */
-	/* USER CODE END sdmmc1 */
-};
-
-&sdmmc2{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "opendrain", "sleep";
-	pinctrl-0 = <&sdmmc2_pins_mx>;
-	pinctrl-1 = <&sdmmc2_opendrain_pins_mx>;
-	pinctrl-2 = <&sdmmc2_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN sdmmc2 */
-	/* USER CODE END sdmmc2 */
-};
-
-&timers1{
-	status = "okay";
-
-	/* USER CODE BEGIN timers1 */
-	/* USER CODE END timers1 */
-
-	pwm{
-		pinctrl-names = "default", "sleep";
-		pinctrl-0 = <&tim1_pwm_pins_mx>;
-		pinctrl-1 = <&tim1_pwm_sleep_pins_mx>;
-		status = "okay";
-
-		/* USER CODE BEGIN timers1_pwm */
-		/* USER CODE END timers1_pwm */
-	};
-};
-
-&timers4{
-	status = "okay";
-
-	/* USER CODE BEGIN timers4 */
-	/* USER CODE END timers4 */
-
-	pwm{
-		pinctrl-names = "default", "sleep";
-		pinctrl-0 = <&tim4_pwm_pins_mx>;
-		pinctrl-1 = <&tim4_pwm_sleep_pins_mx>;
-		status = "okay";
-
-		/* USER CODE BEGIN timers4_pwm */
-		/* USER CODE END timers4_pwm */
-	};
-};
-
-&uart4{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&uart4_pins_mx>;
-	pinctrl-1 = <&uart4_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN uart4 */
-	/* USER CODE END uart4 */
-};
-
-&usart2{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&usart2_pins_mx>;
-	pinctrl-1 = <&usart2_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN usart2 */
-	/* USER CODE END usart2 */
-};
-
-&usart6{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&usart6_pins_mx>;
-	pinctrl-1 = <&usart6_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN usart6 */
-	/* USER CODE END usart6 */
-};
-
-&usbh_ehci{
-	status = "okay";
-
-	/* USER CODE BEGIN usbh_ehci */
-	/* USER CODE END usbh_ehci */
-};
-
-&usbh_ohci{
-	status = "okay";
-
-	/* USER CODE BEGIN usbh_ohci */
-	/* USER CODE END usbh_ohci */
-};
-
-&usbotg_hs{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&usb_otg_hs_pins_mx>;
-	pinctrl-1 = <&usb_otg_hs_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN usbotg_hs */
-	/* USER CODE END usbotg_hs */
-};
-
-&usbphyc{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc */
-	/* USER CODE END usbphyc */
-};
-
-&usbphyc_port0{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc_port0 */
-	/* USER CODE END usbphyc_port0 */
-};
-
-&usbphyc_port1{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc_port1 */
-	/* USER CODE END usbphyc_port1 */
-};
-
-&vrefbuf{
-	status = "okay";
-
-	/* USER CODE BEGIN vrefbuf */
-	/* USER CODE END vrefbuf */
-};
-
-/* USER CODE BEGIN addons */
-/* USER CODE END addons */
-
diff --git a/conf/machine/cubemx/t1000-s/t1000-s.ioc b/conf/machine/cubemx/t1000-s/t1000-s.ioc
deleted file mode 100644
index 21f7d4803aabfe25270806ad86b08ebc318ae749..0000000000000000000000000000000000000000
--- a/conf/machine/cubemx/t1000-s/t1000-s.ioc
+++ /dev/null
@@ -1,1078 +0,0 @@
-#MicroXplorer Configuration settings - do not modify
-ADC1.Channel-0\#ChannelRegularConversion=ADC_CHANNEL_5
-ADC1.IPParameters=Rank-0\#ChannelRegularConversion,Channel-0\#ChannelRegularConversion,SamplingTime-0\#ChannelRegularConversion,OffsetNumber-0\#ChannelRegularConversion,NbrOfConversionFlag,master
-ADC1.NbrOfConversionFlag=1
-ADC1.OffsetNumber-0\#ChannelRegularConversion=ADC_OFFSET_NONE
-ADC1.Rank-0\#ChannelRegularConversion=1
-ADC1.SamplingTime-0\#ChannelRegularConversion=ADC_SAMPLETIME_1CYCLE_5
-ADC1.master=1
-BootLoader.IPs=RCC,QUADSPI,SDMMC1,SDMMC2,UART4,USB_OTG_HS,LTDC
-BootROM.IPs=RCC,SDMMC1\:I,UART4\:I
-CortexA7NS.IPs=BSEC,DDR\:I,ETZPC,HSEM\:I,IPCC\:I,PWR,RCC\:I,RTC,TAMP\:I,DMA\:I,GIC,ADC1\:I,ADC2\:I,TIM4\:I,ETH1\:I,FDCAN1\:I,I2C2\:I,I2C4\:I,QUADSPI\:I,SDMMC1,SDMMC2\:I,UART4,USART2\:I,USART6\:I,USBH_HS1\:I,USB_OTG_HS\:I,LTDC\:I,GPU\:I,TIM1\:I,CRYP1\:I,HASH1\:I,RNG1,I2S2\:I,SPI2\:I,CRC1\:I,DEBUG\:I,DTS\:I,VREFBUF\:I,DMA1\:I,MDMA_A7NS\:I
-CortexA7S.IPs=BSEC\:I,ETZPC\:I,PWR\:I,RCC,RNG1\:I,RTC\:I,GIC\:I,MDMA_A7S\:I
-CortexM4.IPs=HSEM,IPCC,ETZPC,FREERTOS\:I,PWR,RCC,SYS\:I,DMA,NVIC\:I,DMA2\:I
-DDR.0dqdly0=1
-DDR.0dqdly1=0
-DDR.0dqdly2=0
-DDR.0dqdly3=0
-DDR.0dqdly4=1
-DDR.0dqdly5=0
-DDR.0dqdly6=1
-DDR.0dqdly7=1
-DDR.0dqsdly=2
-DDR.0dqsndly=2
-DDR.1dqdly0=0
-DDR.1dqdly1=0
-DDR.1dqdly2=1
-DDR.1dqdly3=0
-DDR.1dqdly4=1
-DDR.1dqdly5=0
-DDR.1dqdly6=0
-DDR.1dqdly7=0
-DDR.ADDRMAP1=0x00070707
-DDR.ADDRMAP3=0x1F000000
-DDR.ADDRMAP5=0x06060606
-DDR.ADDRMAP6=0x0F060606
-DDR.CL=7
-DDR.DDR_Frequency=528.0
-DDR.DFITMG0=0x02050105
-DDR.DRAMTMG0=0x121B1214
-DDR.DRAMTMG1=0x000A041B
-DDR.DRAMTMG2=0x0607080F
-DDR.DRAMTMG4=0x07040607
-DDR.DTPR0=0x36D477D0
-DDR.DTPR1=0x098A00D8
-DDR.DX0DQSTR=0x3D202000
-DDR.DX0DQTR=0x55050005
-DDR.DX1DQTR=0x00050500
-DDR.IPParameters=DDR_Frequency,CL,addrmap_col_b9,addrmap_col_b10,addrmap_col_b11,addrmap_bank_b0,addrmap_bank_b1,addrmap_bank_b2,addrmap_row_b0,addrmap_row_b1,addrmap_row_b2_10,addrmap_row_b11,addrmap_row_b12,addrmap_row_b13,addrmap_row_b14,addrmap_row_b15,MSTR,RFSHTMG,DRAMTMG1,DRAMTMG2,DRAMTMG4,SCHED,ADDRMAP1,ADDRMAP3,ADDRMAP5,ADDRMAP6,PTR0,PTR1,PTR2,DTPR0,DTPR1,MR0,SPEED_BIN_GRADE,tRCD,tRP,tRC,wr2pre,t_faw,t_ras_max,t_ras_min,t_xp,t_rd2pre,t_rp,t_rc,write_latency,read_latency,wr2rd,t_rcd,t_rrd,t_cksrx,t_cksre,t_ckesr,t_cke,t_xs_dll_x32,t_xs_x32,t_rfc_nom_x1_x32,t_rfc_min,dfi_t_rddata_en,dfi_tphy_wrlat,tdlllock,tdllsrst,tdinit1,tdinit0,tdinit2,tccd,trc,trrd,tras,trcd,trp,twtr,trtp,tmrd,trfc,tmod,tfaw,tdllk,tcke,txp,txs,MR0.WR,MR0.CL,MR2.RTT,MR2.CWL,data_bus_width,DFITMG0,TEMPERATURE_OVER_85C,tREFI,DRAMTMG0,MR2,0dqsndly,0dqsdly,0dqdly0,0dqdly1,0dqdly2,0dqdly3,0dqdly4,0dqdly5,0dqdly6,0dqdly7,1dqdly0,1dqdly1,1dqdly2,1dqdly3,1dqdly4,1dqdly5,1dqdly6,1dqdly7,DX0DQTR,DX0DQSTR,DX1DQTR
-DDR.MR0=0x00000830
-DDR.MR0.CL=3
-DDR.MR0.WR=4
-DDR.MR2=0x00000248
-DDR.MR2.CWL=1
-DDR.MR2.RTT=1
-DDR.MSTR=0x00041401
-DDR.PTR0=0x0022A41B
-DDR.PTR1=0x047C0740
-DDR.PTR2=0x042D9C80
-DDR.RFSHTMG=0x0040008A
-DDR.SCHED=0x00000C01
-DDR.SPEED_BIN_GRADE=SPEED BIN GRADE CONFIG1
-DDR.TEMPERATURE_OVER_85C=true
-DDR.addrmap_bank_b0=7
-DDR.addrmap_bank_b1=7
-DDR.addrmap_bank_b2=7
-DDR.addrmap_col_b10=31
-DDR.addrmap_col_b11=31
-DDR.addrmap_col_b9=31
-DDR.addrmap_row_b0=6
-DDR.addrmap_row_b1=6
-DDR.addrmap_row_b11=6
-DDR.addrmap_row_b12=6
-DDR.addrmap_row_b13=6
-DDR.addrmap_row_b14=6
-DDR.addrmap_row_b15=15
-DDR.addrmap_row_b2_10=6
-DDR.data_bus_width=1
-DDR.dfi_t_rddata_en=5
-DDR.dfi_tphy_wrlat=5
-DDR.read_latency=7
-DDR.tRC=50.625
-DDR.tRCD=13.125
-DDR.tREFI=3.9
-DDR.tRP=13.125
-DDR.t_cke=3
-DDR.t_ckesr=4
-DDR.t_cksre=6
-DDR.t_cksrx=6
-DDR.t_faw=27
-DDR.t_ras_max=18
-DDR.t_ras_min=20
-DDR.t_rc=27
-DDR.t_rcd=7
-DDR.t_rd2pre=4
-DDR.t_rfc_min=138
-DDR.t_rfc_nom_x1_x32=64
-DDR.t_rp=7
-DDR.t_rrd=6
-DDR.t_xp=10
-DDR.t_xs_dll_x32=16
-DDR.t_xs_x32=5
-DDR.tccd=0
-DDR.tcke=4
-DDR.tdinit0=264000
-DDR.tdinit1=143
-DDR.tdinit2=105600
-DDR.tdllk=512
-DDR.tdlllock=2704
-DDR.tdllsrst=27
-DDR.tfaw=27
-DDR.tmod=0
-DDR.tmrd=0
-DDR.tras=20
-DDR.trc=27
-DDR.trcd=7
-DDR.trfc=138
-DDR.trp=7
-DDR.trrd=6
-DDR.trtp=4
-DDR.twtr=6
-DDR.txp=13
-DDR.txs=512
-DDR.wr2pre=18
-DDR.wr2rd=15
-DDR.write_latency=6
-DDR_A0.Mode=DDR3
-DDR_A0.Signal=DDR_A0
-DDR_A1.Mode=DDR3
-DDR_A1.Signal=DDR_A1
-DDR_A10.Mode=DDR3
-DDR_A10.Signal=DDR_A10
-DDR_A11.Mode=DDR3
-DDR_A11.Signal=DDR_A11
-DDR_A12.Mode=4Gb_16bits
-DDR_A12.Signal=DDR_A12
-DDR_A13.Mode=4Gb_16bits
-DDR_A13.Signal=DDR_A13
-DDR_A14.Mode=4Gb_16bits
-DDR_A14.Signal=DDR_A14
-DDR_A2.Mode=DDR3
-DDR_A2.Signal=DDR_A2
-DDR_A3.Mode=DDR3
-DDR_A3.Signal=DDR_A3
-DDR_A4.Mode=DDR3
-DDR_A4.Signal=DDR_A4
-DDR_A5.Mode=DDR3
-DDR_A5.Signal=DDR_A5
-DDR_A6.Mode=DDR3
-DDR_A6.Signal=DDR_A6
-DDR_A7.Mode=DDR3
-DDR_A7.Signal=DDR_A7
-DDR_A8.Mode=DDR3
-DDR_A8.Signal=DDR_A8
-DDR_A9.Mode=DDR3
-DDR_A9.Signal=DDR_A9
-DDR_ATO.Mode=DDR3
-DDR_ATO.Signal=DDR_ATO
-DDR_BA0.Mode=DDR3
-DDR_BA0.Signal=DDR_BA0
-DDR_BA1.Mode=DDR3
-DDR_BA1.Signal=DDR_BA1
-DDR_BA2.Mode=DDR3
-DDR_BA2.Signal=DDR_BA2
-DDR_CASN.Mode=DDR3
-DDR_CASN.Signal=DDR_CASN
-DDR_CKE.Mode=DDR3
-DDR_CKE.Signal=DDR_CKE
-DDR_CLKN.Mode=DDR3
-DDR_CLKN.Signal=DDR_CLKN
-DDR_CLKP.Mode=DDR3
-DDR_CLKP.Signal=DDR_CLKP
-DDR_CSN.Mode=DDR3
-DDR_CSN.Signal=DDR_CSN
-DDR_DQ0.Mode=DDR3
-DDR_DQ0.Signal=DDR_DQ0
-DDR_DQ1.Mode=DDR3
-DDR_DQ1.Signal=DDR_DQ1
-DDR_DQ10.Mode=DDR3
-DDR_DQ10.Signal=DDR_DQ10
-DDR_DQ11.Mode=DDR3
-DDR_DQ11.Signal=DDR_DQ11
-DDR_DQ12.Mode=DDR3
-DDR_DQ12.Signal=DDR_DQ12
-DDR_DQ13.Mode=DDR3
-DDR_DQ13.Signal=DDR_DQ13
-DDR_DQ14.Mode=DDR3
-DDR_DQ14.Signal=DDR_DQ14
-DDR_DQ15.Mode=DDR3
-DDR_DQ15.Signal=DDR_DQ15
-DDR_DQ2.Mode=DDR3
-DDR_DQ2.Signal=DDR_DQ2
-DDR_DQ3.Mode=DDR3
-DDR_DQ3.Signal=DDR_DQ3
-DDR_DQ4.Mode=DDR3
-DDR_DQ4.Signal=DDR_DQ4
-DDR_DQ5.Mode=DDR3
-DDR_DQ5.Signal=DDR_DQ5
-DDR_DQ6.Mode=DDR3
-DDR_DQ6.Signal=DDR_DQ6
-DDR_DQ7.Mode=DDR3
-DDR_DQ7.Signal=DDR_DQ7
-DDR_DQ8.Mode=DDR3
-DDR_DQ8.Signal=DDR_DQ8
-DDR_DQ9.Mode=DDR3
-DDR_DQ9.Signal=DDR_DQ9
-DDR_DQM0.Mode=DDR3
-DDR_DQM0.Signal=DDR_DQM0
-DDR_DQM1.Mode=DDR3
-DDR_DQM1.Signal=DDR_DQM1
-DDR_DQS0N.Mode=DDR3
-DDR_DQS0N.Signal=DDR_DQS0N
-DDR_DQS0P.Mode=DDR3
-DDR_DQS0P.Signal=DDR_DQS0P
-DDR_DQS1N.Mode=DDR3
-DDR_DQS1N.Signal=DDR_DQS1N
-DDR_DQS1P.Mode=DDR3
-DDR_DQS1P.Signal=DDR_DQS1P
-DDR_DTO0.Mode=DDR3
-DDR_DTO0.Signal=DDR_DTO0
-DDR_DTO1.Mode=DDR3
-DDR_DTO1.Signal=DDR_DTO1
-DDR_ODT.Mode=DDR3
-DDR_ODT.Signal=DDR_ODT
-DDR_RASN.Mode=DDR3
-DDR_RASN.Signal=DDR_RASN
-DDR_RESETN.Mode=DDR3
-DDR_RESETN.Signal=DDR_RESETN
-DDR_VREF.Mode=DDR3
-DDR_VREF.Signal=DDR_VREF
-DDR_WEN.Mode=DDR3
-DDR_WEN.Signal=DDR_WEN
-DDR_ZQ.Mode=DDR3
-DDR_ZQ.Signal=DDR_ZQ
-File.Version=6
-GIC.ADC1_IRQn=true\:false\:High level
-GIC.CRYP1_IRQn=true\:false\:High level
-GIC.DTS_IRQn=true\:false\:High level
-GIC.ETH1_IRQn=true\:false\:High level
-GIC.ETH1_WKUP_IRQn=true\:false\:High level
-GIC.FDCAN1_IT0_IRQn=true\:false\:High level
-GIC.FDCAN1_IT1_IRQn=true\:false\:High level
-GIC.GPU_IRQn=true\:false\:High level
-GIC.HASH1_IRQn=true\:false\:High level
-GIC.I2C2_ER_IRQn=true\:false\:High level
-GIC.I2C2_EV_IRQn=true\:false\:High level
-GIC.I2C4_ER_IRQn=true\:false\:High level
-GIC.I2C4_EV_IRQn=true\:false\:High level
-GIC.IPCC_RX0_IRQn=true\:false\:High level
-GIC.IPCC_TX0_IRQn=true\:false\:High level
-GIC.LTDC_ER_IRQn=true\:false\:High level
-GIC.LTDC_IRQn=true\:false\:High level
-GIC.OTG_IRQn=true\:false\:High level
-GIC.PMUIRQ0_IRQn=true\:false\:High level
-GIC.PMUIRQ1_IRQn=true\:false\:High level
-GIC.QUADSPI_IRQn=true\:false\:High level
-GIC.RCC_IRQn=true\:false\:High level
-GIC.RTC_WKUP_ALARM_IRQn=true\:false\:High level
-GIC.SDMMC1_IRQn=true\:false\:High level
-GIC.SDMMC2_IRQn=true\:false\:High level
-GIC.SPI2_IRQn=true\:false\:High level
-GIC.UART4_IRQn=true\:false\:High level
-GIC.USART2_IRQn=true\:false\:High level
-GIC.USART6_IRQn=true\:false\:High level
-GIC.USBH_OHCI_IRQn=true\:false\:High level
-I2S2.ErrorAudioFreq=1.72 %
-I2S2.FullDuplexMode=I2S_MODE_MASTER_FD
-I2S2.IPParameters=Instance,VirtualMode,FullDuplexMode,RealAudioFreq,ErrorAudioFreq
-I2S2.Instance=SPI$Index
-I2S2.RealAudioFreq=8.138 KHz
-I2S2.VirtualMode=I2S_MODE_MASTER
-JTCK-SWCLK.Mode=JTAG_4_pins
-JTCK-SWCLK.Signal=DEBUG_JTCK-SWCLK
-JTDI.Mode=JTAG_4_pins
-JTDI.Signal=DEBUG_JTDI
-JTDO-TRACESWO.Mode=JTAG_4_pins
-JTDO-TRACESWO.Signal=DEBUG_JTDO-SWO
-JTMS-SWDIO.Mode=JTAG_4_pins
-JTMS-SWDIO.Signal=DEBUG_JTMS-SWDIO
-KeepUserPlacement=false
-Mcu.Context0=BootROM
-Mcu.Context1=BootLoader
-Mcu.Context2=CortexA7S
-Mcu.Context3=CortexA7NS
-Mcu.Context4=CortexM4
-Mcu.ContextNb=5
-Mcu.Family=STM32MP1
-Mcu.IP0=ADC1
-Mcu.IP1=BSEC
-Mcu.IP10=GIC
-Mcu.IP11=GPU
-Mcu.IP12=HASH1
-Mcu.IP13=HSEM
-Mcu.IP14=I2C2
-Mcu.IP15=I2C4
-Mcu.IP16=I2S2
-Mcu.IP17=IPCC
-Mcu.IP18=LTDC
-Mcu.IP19=NVIC
-Mcu.IP2=CRC1
-Mcu.IP20=QUADSPI
-Mcu.IP21=RCC
-Mcu.IP22=RNG1
-Mcu.IP23=RTC
-Mcu.IP24=SDMMC1
-Mcu.IP25=SDMMC2
-Mcu.IP26=SYS
-Mcu.IP27=TIM1
-Mcu.IP28=TIM4
-Mcu.IP29=UART4
-Mcu.IP3=CRYP1
-Mcu.IP30=USART2
-Mcu.IP31=USART6
-Mcu.IP32=USBH_HS1
-Mcu.IP33=USB_OTG_HS
-Mcu.IP34=VREFBUF
-Mcu.IP4=DDR
-Mcu.IP5=DEBUG
-Mcu.IP6=DTS
-Mcu.IP7=ETH1
-Mcu.IP8=ETZPC
-Mcu.IP9=FDCAN1
-Mcu.IPNb=35
-Mcu.Name=STM32MP157CADx
-Mcu.Package=TFBGA257
-Mcu.Pin0=PD1
-Mcu.Pin1=PB7
-Mcu.Pin10=PG15
-Mcu.Pin100=PA11
-Mcu.Pin101=PA10
-Mcu.Pin102=DDR_DQ14
-Mcu.Pin103=DDR_DQS1N
-Mcu.Pin104=DDR_DQ9
-Mcu.Pin105=PC5
-Mcu.Pin106=PC4
-Mcu.Pin107=PB12
-Mcu.Pin108=PB8
-Mcu.Pin109=PB5
-Mcu.Pin11=PE6
-Mcu.Pin110=PG8
-Mcu.Pin111=PE7
-Mcu.Pin112=PF8
-Mcu.Pin113=PF9
-Mcu.Pin114=USB_DP2
-Mcu.Pin115=PE10
-Mcu.Pin116=PB2
-Mcu.Pin117=USB_DP1
-Mcu.Pin118=PA12
-Mcu.Pin119=DDR_DQ15
-Mcu.Pin12=PD7
-Mcu.Pin120=DDR_DQM1
-Mcu.Pin121=DDR_DQS1P
-Mcu.Pin122=PA7
-Mcu.Pin123=PA6
-Mcu.Pin124=PF11
-Mcu.Pin125=PF7
-Mcu.Pin126=PG9
-Mcu.Pin127=USB_DM2
-Mcu.Pin128=PB6
-Mcu.Pin129=USB_DM1
-Mcu.Pin13=PA15
-Mcu.Pin130=DDR_VREF
-Mcu.Pin131=DDR_DQ12
-Mcu.Pin132=DDR_DQ11
-Mcu.Pin133=PE1
-Mcu.Pin134=PD10
-Mcu.Pin135=PE3
-Mcu.Pin136=PB14
-Mcu.Pin137=PD2
-Mcu.Pin138=DDR_ZQ
-Mcu.Pin139=DDR_A7
-Mcu.Pin14=PG6
-Mcu.Pin140=PD6
-Mcu.Pin141=PE14
-Mcu.Pin142=PC12
-Mcu.Pin143=PD9
-Mcu.Pin144=PD15
-Mcu.Pin145=DDR_DTO1
-Mcu.Pin146=DDR_A5
-Mcu.Pin147=DDR_DTO0
-Mcu.Pin148=PD14
-Mcu.Pin149=DDR_RASN
-Mcu.Pin15=PB4
-Mcu.Pin150=DDR_ATO
-Mcu.Pin151=DDR_A6
-Mcu.Pin152=PA5
-Mcu.Pin153=PA4
-Mcu.Pin154=PB13
-Mcu.Pin155=PE9
-Mcu.Pin156=PF10
-Mcu.Pin157=VP_BSEC_VS_BSEC
-Mcu.Pin158=VP_CRC1_VS_CRC
-Mcu.Pin159=VP_CRYP1_VS_CRYP
-Mcu.Pin16=PE5
-Mcu.Pin160=VP_DDR_DDR3
-Mcu.Pin161=VP_DDR_DDR_16_bits
-Mcu.Pin162=VP_DDR_DDR3_16_4Gb
-Mcu.Pin163=VP_DTS_VS_DTS
-Mcu.Pin164=VP_ETZPC_VS_ETZPC
-Mcu.Pin165=VP_GPU_VS_GPU
-Mcu.Pin166=VP_HASH1_VS_HASH
-Mcu.Pin167=VP_HSEM_VS_HSEM
-Mcu.Pin168=VP_IPCC_VS_IPCC
-Mcu.Pin169=VP_RNG1_VS_RNG
-Mcu.Pin17=PA8
-Mcu.Pin170=VP_RTC_VS_RTC_Activate
-Mcu.Pin171=VP_SYS_VS_Systick
-Mcu.Pin172=VP_VREFBUF_VS_VREFBUF
-Mcu.Pin173=VP_DMA_VS_DMA1_A7NS
-Mcu.Pin174=VP_DMA_VS_DMA2_M4
-Mcu.Pin175=VP_MDMA_VS_MDMA_A7NS_8
-Mcu.Pin18=PC9
-Mcu.Pin19=PC10
-Mcu.Pin2=PC6
-Mcu.Pin20=JTDI
-Mcu.Pin21=DDR_DQ3
-Mcu.Pin22=DDR_DQ7
-Mcu.Pin23=DDR_DQS0N
-Mcu.Pin24=DDR_DQS0P
-Mcu.Pin25=PE12
-Mcu.Pin26=PD4
-Mcu.Pin27=PD5
-Mcu.Pin28=PD0
-Mcu.Pin29=PA9
-Mcu.Pin3=PD3
-Mcu.Pin30=PB3
-Mcu.Pin31=PB15
-Mcu.Pin32=PB9
-Mcu.Pin33=PC7
-Mcu.Pin34=PC11
-Mcu.Pin35=JTMS-SWDIO
-Mcu.Pin36=DDR_RESETN
-Mcu.Pin37=DDR_DQM0
-Mcu.Pin38=DDR_DQ2
-Mcu.Pin39=DDR_DQ6
-Mcu.Pin4=PC8
-Mcu.Pin40=PG12
-Mcu.Pin41=PE11
-Mcu.Pin42=PE15
-Mcu.Pin43=DDR_DQ4
-Mcu.Pin44=DDR_DQ5
-Mcu.Pin45=PD8
-Mcu.Pin46=PE13
-Mcu.Pin47=DDR_A13
-Mcu.Pin48=DDR_A9
-Mcu.Pin49=PC15-OSC32_OUT
-Mcu.Pin5=PE4
-Mcu.Pin50=DDR_A2
-Mcu.Pin51=DDR_A3
-Mcu.Pin52=PC14-OSC32_IN
-Mcu.Pin53=DDR_A0
-Mcu.Pin54=DDR_BA0
-Mcu.Pin55=PH0-OSC_IN
-Mcu.Pin56=DDR_BA2
-Mcu.Pin57=DDR_ODT
-Mcu.Pin58=PH1-OSC_OUT
-Mcu.Pin59=DDR_CSN
-Mcu.Pin6=JTDO-TRACESWO
-Mcu.Pin60=DDR_WEN
-Mcu.Pin61=DDR_CASN
-Mcu.Pin62=DDR_CLKN
-Mcu.Pin63=PA14
-Mcu.Pin64=PA13
-Mcu.Pin65=DDR_CLKP
-Mcu.Pin66=DDR_A10
-Mcu.Pin67=DDR_A12
-Mcu.Pin68=DDR_A1
-Mcu.Pin69=PA3
-Mcu.Pin7=JTCK-SWCLK
-Mcu.Pin70=PA0
-Mcu.Pin71=DDR_A14
-Mcu.Pin72=DDR_A11
-Mcu.Pin73=PE2
-Mcu.Pin74=PC2
-Mcu.Pin75=PC3
-Mcu.Pin76=DDR_CKE
-Mcu.Pin77=DDR_BA1
-Mcu.Pin78=PG14
-Mcu.Pin79=PG13
-Mcu.Pin8=DDR_DQ0
-Mcu.Pin80=DDR_A4
-Mcu.Pin81=DDR_DQ8
-Mcu.Pin82=PA1
-Mcu.Pin83=PC1
-Mcu.Pin84=PA2
-Mcu.Pin85=DDR_A8
-Mcu.Pin86=DDR_DQ13
-Mcu.Pin87=DDR_DQ10
-Mcu.Pin88=PB1
-Mcu.Pin89=PB0
-Mcu.Pin9=DDR_DQ1
-Mcu.Pin90=PB11
-Mcu.Pin91=PC0
-Mcu.Pin92=PB10
-Mcu.Pin93=PG11
-Mcu.Pin94=PG10
-Mcu.Pin95=PD11
-Mcu.Pin96=PF6
-Mcu.Pin97=PE8
-Mcu.Pin98=PD13
-Mcu.Pin99=PD12
-Mcu.PinsNb=176
-Mcu.ThirdPartyNb=0
-Mcu.UserConstants=
-Mcu.UserName=STM32MP157CADx
-MxCube.Version=5.3.0
-MxDb.Version=DB.5.0.30
-NVIC.BusFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false
-NVIC.DebugMonitor_IRQn=true\:0\:0\:false\:false\:true\:false\:false
-NVIC.HardFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false
-NVIC.MemoryManagement_IRQn=true\:0\:0\:false\:false\:true\:false\:false
-NVIC.NonMaskableInt_IRQn=true\:0\:0\:false\:false\:true\:false\:false
-NVIC.PendSV_IRQn=true\:0\:0\:false\:false\:true\:false\:false
-NVIC.PriorityGroup=NVIC_PRIORITYGROUP_4
-NVIC.SVCall_IRQn=true\:0\:0\:false\:false\:true\:false\:false
-NVIC.SysTick_IRQn=true\:0\:0\:false\:false\:true\:false\:true
-NVIC.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false
-PA0.Mode=IN16-Single-Ended
-PA0.Signal=ADC1_INP16
-PA1.Mode=RGB888
-PA1.Signal=LTDC_R2
-PA10.Mode=Ext_Phy_OTG/Dual-Role-Device
-PA10.Signal=USB_OTG_HS_ID
-PA11.Locked=true
-PA11.Mode=Full_Duplex_Master
-PA11.Signal=I2S2_WS
-PA12.Locked=true
-PA12.Mode=RGB888
-PA12.Signal=LTDC_R5
-PA13.GPIOParameters=GPIO_Label
-PA13.GPIO_Label=LED1
-PA13.Locked=true
-PA13.Signal=GPIO_Output
-PA14.GPIOParameters=GPIO_Label
-PA14.GPIO_Label=LED2
-PA14.Locked=true
-PA14.Signal=GPIO_Output
-PA15.Locked=true
-PA15.Mode=RGB888
-PA15.Signal=LTDC_R1
-PA2.Locked=true
-PA2.Mode=RMII (Reduced MII)
-PA2.Signal=ETH1_MDIO
-PA3.Mode=RGB888
-PA3.Signal=LTDC_B5
-PA4.Mode=RGB888
-PA4.Signal=LTDC_VSYNC
-PA5.Locked=true
-PA5.Mode=RGB888
-PA5.Signal=LTDC_R4
-PA6.Mode=RGB888
-PA6.Signal=LTDC_G2
-PA7.Locked=true
-PA7.Mode=RMII (Reduced MII)
-PA7.Signal=ETH1_CRS_DV
-PA8.Mode=RGB888
-PA8.Signal=LTDC_R6
-PA9.Locked=true
-PA9.Signal=S_TIM1_CH2
-PB0.Mode=RGB888
-PB0.Signal=LTDC_R3
-PB1.Signal=ADCx_INP5
-PB10.Mode=RGB888
-PB10.Signal=LTDC_G4
-PB11.Mode=RMII (Reduced MII)
-PB11.Signal=ETH1_TX_EN
-PB12.Locked=true
-PB12.Mode=RMII (Reduced MII)
-PB12.Signal=ETH1_TXD0
-PB13.Mode=RMII (Reduced MII)
-PB13.Signal=ETH1_TXD1
-PB14.GPIOParameters=GPIO_PuPd,GPIO_Speed_Medium_Default,GPIO_Mode
-PB14.GPIO_Mode=GPIO_MODE_AF_PP
-PB14.GPIO_PuPd=GPIO_PULLUP
-PB14.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_MEDIUM
-PB14.Locked=true
-PB14.Mode=SD_4_bits_Wide_bus
-PB14.Signal=SDMMC2_D0
-PB15.GPIOParameters=GPIO_PuPd,GPIO_Speed_Medium_Default,GPIO_Mode
-PB15.GPIO_Mode=GPIO_MODE_AF_PP
-PB15.GPIO_PuPd=GPIO_PULLUP
-PB15.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_MEDIUM
-PB15.Mode=SD_4_bits_Wide_bus
-PB15.Signal=SDMMC2_D1
-PB2.GPIOParameters=GPIO_ModePuPdOnly,GPIO_PuPd
-PB2.GPIO_ModePuPdOnly=GPIO_MODE_AF
-PB2.GPIO_PuPd=GPIO_PULLUP
-PB2.Mode=Asynchronous
-PB2.Signal=UART4_RX
-PB3.GPIOParameters=GPIO_PuPd,GPIO_Speed_Medium_Default,GPIO_Mode
-PB3.GPIO_Mode=GPIO_MODE_AF_PP
-PB3.GPIO_PuPd=GPIO_PULLUP
-PB3.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_MEDIUM
-PB3.Mode=SD_4_bits_Wide_bus
-PB3.Signal=SDMMC2_D2
-PB4.GPIOParameters=GPIO_PuPd,GPIO_Speed_Medium_Default,GPIO_Mode
-PB4.GPIO_Mode=GPIO_MODE_AF_PP
-PB4.GPIO_PuPd=GPIO_PULLUP
-PB4.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_MEDIUM
-PB4.Mode=SD_4_bits_Wide_bus
-PB4.Signal=SDMMC2_D3
-PB5.Locked=true
-PB5.Mode=RGB888
-PB5.Signal=LTDC_G7
-PB6.GPIOParameters=GPIO_PuPd,GPIO_Speed_Medium_Default,GPIO_Mode
-PB6.GPIO_Mode=GPIO_MODE_AF_PP
-PB6.GPIO_PuPd=GPIO_PULLUP
-PB6.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_VERY_HIGH
-PB6.Locked=true
-PB6.Mode=Enable Chip Select for each bank
-PB6.Signal=QUADSPI_BK1_NCS
-PB7.Mode=I2C
-PB7.Signal=I2C4_SDA
-PB8.Mode=RGB888
-PB8.Signal=LTDC_B6
-PB9.Mode=RGB888
-PB9.Signal=LTDC_B7
-PC0.GPIOParameters=GPIO_PuPd,GPIO_Speed_Medium_Default
-PC0.GPIO_PuPd=GPIO_PULLUP
-PC0.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_VERY_HIGH
-PC0.Locked=true
-PC0.Mode=Enable Chip Select for each bank
-PC0.Signal=QUADSPI_BK2_NCS
-PC1.Mode=RMII (Reduced MII)
-PC1.Signal=ETH1_MDC
-PC10.GPIOParameters=GPIO_PuPd,GPIO_Speed_Medium_Default,GPIO_Mode
-PC10.GPIO_Mode=GPIO_MODE_AF_PP
-PC10.GPIO_PuPd=GPIO_PULLUP
-PC10.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_MEDIUM
-PC10.Locked=true
-PC10.Mode=SD_4_bits_Wide_bus
-PC10.Signal=SDMMC1_D2
-PC11.GPIOParameters=GPIO_PuPd,GPIO_Speed_Medium_Default,GPIO_Mode
-PC11.GPIO_Mode=GPIO_MODE_AF_PP
-PC11.GPIO_PuPd=GPIO_PULLUP
-PC11.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_MEDIUM
-PC11.Mode=SD_4_bits_Wide_bus
-PC11.Signal=SDMMC1_D3
-PC12.GPIOParameters=GPIO_PuPd,GPIO_Speed_High_Default,GPIO_Mode
-PC12.GPIO_Mode=GPIO_MODE_AF_PP
-PC12.GPIO_PuPd=GPIO_PULLUP
-PC12.GPIO_Speed_High_Default=GPIO_SPEED_FREQ_VERY_HIGH
-PC12.Mode=SD_4_bits_Wide_bus
-PC12.Signal=SDMMC1_CK
-PC14-OSC32_IN.Mode=LSE-External-Oscillator
-PC14-OSC32_IN.Signal=RCC_OSC32_IN
-PC15-OSC32_OUT.Mode=LSE-External-Oscillator
-PC15-OSC32_OUT.Signal=RCC_OSC32_OUT
-PC2.Locked=true
-PC2.Mode=Full_Duplex_Master
-PC2.Signal=I2S2_SDI
-PC3.Locked=true
-PC3.Mode=Full_Duplex_Master
-PC3.Signal=I2S2_SDO
-PC4.Mode=RMII (Reduced MII)
-PC4.Signal=ETH1_RXD0
-PC5.Mode=RMII (Reduced MII)
-PC5.Signal=ETH1_RXD1
-PC6.Mode=RGB888
-PC6.Signal=LTDC_HSYNC
-PC7.Mode=RGB888
-PC7.Signal=LTDC_G6
-PC8.GPIOParameters=GPIO_PuPd,GPIO_Speed_Medium_Default,GPIO_Mode
-PC8.GPIO_Mode=GPIO_MODE_AF_PP
-PC8.GPIO_PuPd=GPIO_PULLUP
-PC8.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_MEDIUM
-PC8.Mode=SD_4_bits_Wide_bus
-PC8.Signal=SDMMC1_D0
-PC9.GPIOParameters=GPIO_PuPd,GPIO_Speed_Medium_Default,GPIO_Mode
-PC9.GPIO_Mode=GPIO_MODE_AF_PP
-PC9.GPIO_PuPd=GPIO_PULLUP
-PC9.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_MEDIUM
-PC9.Mode=SD_4_bits_Wide_bus
-PC9.Signal=SDMMC1_D1
-PCC.Checker=false
-PCC.Line=STM32MP157
-PCC.MCU=STM32MP157CADx
-PCC.PartNumber=STM32MP157CADx
-PCC.Seq0=0
-PCC.Series=STM32MP1
-PCC.Temperature=25
-PCC.Vdd=3.0
-PD0.Mode=FDCANMaster
-PD0.Signal=FDCAN1_RX
-PD1.GPIOParameters=GPIO_Speed,GPIO_PuPd,GPIO_Mode
-PD1.GPIO_Mode=GPIO_MODE_AF_PP
-PD1.GPIO_PuPd=GPIO_NOPULL
-PD1.GPIO_Speed=GPIO_SPEED_FREQ_LOW
-PD1.Mode=FDCANMaster
-PD1.Signal=FDCAN1_TX
-PD10.Mode=RGB888
-PD10.Signal=LTDC_B3
-PD11.GPIOParameters=GPIO_Label
-PD11.GPIO_Label=TOUCH_WAKE
-PD11.Locked=true
-PD11.Signal=GPIO_Input
-PD12.GPIOParameters=GPIO_Label
-PD12.GPIO_Label=USB_OVR
-PD12.Locked=true
-PD12.Signal=GPIO_Input
-PD13.Locked=true
-PD13.Signal=DSIHOST_TE
-PD14.GPIOParameters=GPIO_ModeDefaultPP,GPIO_Speed,GPIO_PuPd
-PD14.GPIO_ModeDefaultPP=GPIO_MODE_AF_PP
-PD14.GPIO_PuPd=GPIO_NOPULL
-PD14.GPIO_Speed=GPIO_SPEED_FREQ_LOW
-PD14.Locked=true
-PD14.Signal=S_TIM4_CH3
-PD15.GPIOParameters=GPIO_Label
-PD15.GPIO_Label=RESET_OUT
-PD15.Locked=true
-PD15.Signal=GPIO_Output
-PD2.GPIOParameters=GPIO_PuPd,GPIO_Speed_Medium_Default,GPIO_Mode
-PD2.GPIO_Mode=GPIO_MODE_AF_PP
-PD2.GPIO_PuPd=GPIO_PULLUP
-PD2.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_MEDIUM
-PD2.Mode=SD_4_bits_Wide_bus
-PD2.Signal=SDMMC1_CMD
-PD3.Locked=true
-PD3.Mode=Full_Duplex_Master
-PD3.Signal=I2S2_CK
-PD4.GPIOParameters=GPIO_Speed,GPIO_PuPd,GPIO_Mode
-PD4.GPIO_Mode=GPIO_MODE_AF_PP
-PD4.GPIO_PuPd=GPIO_PULLDOWN
-PD4.GPIO_Speed=GPIO_SPEED_FREQ_LOW
-PD4.Mode=RTS_Only
-PD4.Signal=USART2_RTS
-PD5.GPIOParameters=GPIO_ModeDefaultPP,GPIO_Speed,GPIO_PuPd
-PD5.GPIO_ModeDefaultPP=GPIO_MODE_AF_PP
-PD5.GPIO_PuPd=GPIO_PULLUP
-PD5.GPIO_Speed=GPIO_SPEED_FREQ_LOW
-PD5.Mode=Asynchronous
-PD5.Signal=USART2_TX
-PD6.GPIOParameters=GPIO_ModePuPdOnly,GPIO_PuPd
-PD6.GPIO_ModePuPdOnly=GPIO_MODE_AF
-PD6.GPIO_PuPd=GPIO_PULLUP
-PD6.Locked=true
-PD6.Mode=Asynchronous
-PD6.Signal=USART2_RX
-PD7.Mode=I2C
-PD7.Signal=I2C2_SCL
-PD8.GPIOParameters=GPIO_Label
-PD8.GPIO_Label=LDC_PCTRL
-PD8.Locked=true
-PD8.Signal=GPIO_Output
-PD9.Locked=true
-PD9.Signal=USART3_RX
-PE1.Locked=true
-PE1.Mode=Master_Clock_Activated
-PE1.Signal=I2S2_MCK
-PE10.GPIOParameters=GPIO_Speed_Medium_Default
-PE10.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_VERY_HIGH
-PE10.Locked=true
-PE10.Mode=Dual Bank
-PE10.Signal=QUADSPI_BK2_IO3
-PE11.Mode=RGB888
-PE11.Signal=LTDC_G3
-PE12.Mode=RGB888
-PE12.Signal=LTDC_B4
-PE13.Mode=RGB888
-PE13.Signal=LTDC_DE
-PE14.Locked=true
-PE14.Mode=RGB888
-PE14.Signal=LTDC_CLK
-PE15.Mode=RGB888
-PE15.Signal=LTDC_R7
-PE2.Mode=I2C
-PE2.Signal=I2C4_SCL
-PE3.GPIOParameters=GPIO_PuPd,GPIO_Speed_High_Default,GPIO_Mode
-PE3.GPIO_Mode=GPIO_MODE_AF_PP
-PE3.GPIO_PuPd=GPIO_PULLUP
-PE3.GPIO_Speed_High_Default=GPIO_SPEED_FREQ_VERY_HIGH
-PE3.Mode=SD_4_bits_Wide_bus
-PE3.Signal=SDMMC2_CK
-PE4.Locked=true
-PE4.Mode=RGB888
-PE4.Signal=LTDC_B0
-PE5.Locked=true
-PE5.Mode=RGB888
-PE5.Signal=LTDC_G0
-PE6.Mode=RGB888
-PE6.Signal=LTDC_G1
-PE7.GPIOParameters=GPIO_Speed_Medium_Default
-PE7.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_VERY_HIGH
-PE7.Mode=Dual Bank
-PE7.Signal=QUADSPI_BK2_IO0
-PE8.GPIOParameters=GPIO_Speed_Medium_Default
-PE8.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_VERY_HIGH
-PE8.Mode=Dual Bank
-PE8.Signal=QUADSPI_BK2_IO1
-PE9.GPIOParameters=GPIO_Speed_Medium_Default
-PE9.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_VERY_HIGH
-PE9.Locked=true
-PE9.Mode=Dual Bank
-PE9.Signal=QUADSPI_BK2_IO2
-PF10.GPIOParameters=GPIO_Speed_Medium_Default
-PF10.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_VERY_HIGH
-PF10.Locked=true
-PF10.Mode=Dual Bank
-PF10.Signal=QUADSPI_CLK
-PF11.Mode=RGB888
-PF11.Signal=LTDC_G5
-PF6.GPIOParameters=GPIO_Speed_Medium_Default
-PF6.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_VERY_HIGH
-PF6.Mode=Dual Bank
-PF6.Signal=QUADSPI_BK1_IO3
-PF7.GPIOParameters=GPIO_Speed_Medium_Default
-PF7.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_VERY_HIGH
-PF7.Mode=Dual Bank
-PF7.Signal=QUADSPI_BK1_IO2
-PF8.GPIOParameters=GPIO_Speed_Medium_Default
-PF8.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_VERY_HIGH
-PF8.Locked=true
-PF8.Mode=Dual Bank
-PF8.Signal=QUADSPI_BK1_IO0
-PF9.GPIOParameters=GPIO_Speed_Medium_Default
-PF9.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_VERY_HIGH
-PF9.Locked=true
-PF9.Mode=Dual Bank
-PF9.Signal=QUADSPI_BK1_IO1
-PG10.Mode=RGB888
-PG10.Signal=LTDC_B2
-PG11.GPIOParameters=GPIO_ModeDefaultPP,GPIO_Speed,GPIO_PuPd
-PG11.GPIO_ModeDefaultPP=GPIO_MODE_AF_PP
-PG11.GPIO_PuPd=GPIO_PULLUP
-PG11.GPIO_Speed=GPIO_SPEED_FREQ_LOW
-PG11.Mode=Asynchronous
-PG11.Signal=UART4_TX
-PG12.Mode=RGB888
-PG12.Signal=LTDC_B1
-PG13.Mode=RGB888
-PG13.Signal=LTDC_R0
-PG14.GPIOParameters=GPIO_PuPd
-PG14.GPIO_PuPd=GPIO_PULLUP
-PG14.Locked=true
-PG14.Mode=Asynchronous
-PG14.Signal=USART6_TX
-PG15.Mode=I2C
-PG15.Signal=I2C2_SDA
-PG6.GPIOParameters=GPIO_PuPd,GPIO_Speed_Medium_Default,GPIO_Mode
-PG6.GPIO_Mode=GPIO_MODE_AF_PP
-PG6.GPIO_PuPd=GPIO_PULLUP
-PG6.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_MEDIUM
-PG6.Mode=SD_4_bits_Wide_bus
-PG6.Signal=SDMMC2_CMD
-PG8.Locked=true
-PG8.Mode=ETH Clock Output (PHY without Quartz)
-PG8.Signal=ETH1_CLK
-PG9.GPIOParameters=GPIO_PuPd
-PG9.GPIO_PuPd=GPIO_PULLUP
-PG9.Locked=true
-PG9.Mode=Asynchronous
-PG9.Signal=USART6_RX
-PH0-OSC_IN.Mode=HSE-External-Oscillator
-PH0-OSC_IN.Signal=RCC_OSC_IN
-PH1-OSC_OUT.Mode=HSE-External-Oscillator
-PH1-OSC_OUT.Signal=RCC_OSC_OUT
-PinOutPanel.CurrentBGAView=Top
-PinOutPanel.RotationAngle=0
-ProjectManager.AskForMigrate=true
-ProjectManager.BackupPrevious=false
-ProjectManager.CompilerOptimize=6
-ProjectManager.ComputerToolchain=false
-ProjectManager.CoupleFile=false
-ProjectManager.CustomerFirmwarePackage=
-ProjectManager.DefaultFWLocation=true
-ProjectManager.DeletePrevious=true
-ProjectManager.DeviceId=STM32MP157CADx
-ProjectManager.DeviceTreeLocation=/home/user/gen/thud/ktn/ye/layers/meta-ktn-stm32mp/conf/machine/cubemx/t1000-s/DeviceTree/
-ProjectManager.FirmwarePackage=STM32Cube FW_MP1 V1.0.1
-ProjectManager.FreePins=false
-ProjectManager.HalAssertFull=false
-ProjectManager.HeapSize=0x200
-ProjectManager.KeepUserCode=true
-ProjectManager.LastFirmware=true
-ProjectManager.LibraryCopy=1
-ProjectManager.MainLocation=Src
-ProjectManager.NoMain=false
-ProjectManager.PreviousToolchain=SW4STM32
-ProjectManager.ProjectBuild=false
-ProjectManager.ProjectFileName=t1000-s.ioc
-ProjectManager.ProjectName=t1000-s
-ProjectManager.StackSize=0x400
-ProjectManager.TargetToolchain=SW4STM32
-ProjectManager.ToolChainLocation=
-ProjectManager.UnderRoot=true
-ProjectManager.functionlistsort=1-MX_GPIO_Init-GPIO-false-HAL-true,2-SystemClock_Config-RCC-false-HAL-false,3-MX_ETZPC_Init-ETZPC-false-HAL-true,4-MX_IPCC_Init-IPCC-false-HAL-true
-RCC.ADCCLockSelection=RCC_ADCCLKSOURCE_PER
-RCC.ADCFreq_Value=24000000
-RCC.AHB1234Freq_Value=196000000
-RCC.APB1DIV=RCC_APB1_DIV2
-RCC.APB1Freq_Value=98000000
-RCC.APB2DIV=RCC_APB2_DIV2
-RCC.APB2Freq_Value=98000000
-RCC.APB3DIV=RCC_APB3_DIV2
-RCC.APB3Freq_Value=98000000
-RCC.APB4DIV=RCC_APB4_DIV2
-RCC.APB4Freq_Value=132000000
-RCC.APB5DIV=RCC_APB5_DIV4
-RCC.APB5DIVClockFreq_Value=66000000
-RCC.AXICLKFreq_VALUE=264000000
-RCC.AXICLKSource=RCC_AXISSOURCE_PLL2
-RCC.AXIDIVFreq_Value=264000000
-RCC.CECFreq_Value=32768
-RCC.CKPERCLKFreq_VALUE=24000000
-RCC.CKPERCLKSource=RCC_CKPERCLKSOURCE_HSE
-RCC.CSI_VALUE=4000000
-RCC.DACCLKFreq_VALUE=32000
-RCC.DDRCFreq_Value=528000000
-RCC.DDRPERFMFreq_Value=528000000
-RCC.DDRPHYFreq_Value=528000000
-RCC.DFSDFAFreq_Value=50000000
-RCC.DFSDMFreq_Value=196000000
-RCC.DIVM1=3
-RCC.DIVM2=3
-RCC.DIVM3=3
-RCC.DIVM4=6
-RCC.DIVN1=81
-RCC.DIVN2=66
-RCC.DIVN3=98
-RCC.DIVN4=125
-RCC.DIVP1Freq_Value=648000000
-RCC.DIVP2Freq_Value=264000000
-RCC.DIVP3=4
-RCC.DIVP3Freq_Value=196000000
-RCC.DIVP4=10
-RCC.DIVP4Freq_Value=50000000
-RCC.DIVQ1Freq_Value=324000000
-RCC.DIVQ2Freq_Value=264000000
-RCC.DIVQ3Freq_Value=392000000
-RCC.DIVQ4=10
-RCC.DIVQ4Freq_Value=50000000
-RCC.DIVR1Freq_Value=324000000
-RCC.DIVR2=1
-RCC.DIVR2Freq_Value=528000000
-RCC.DIVR3Freq_Value=392000000
-RCC.DIVR4=10
-RCC.DIVR4Freq_Value=50000000
-RCC.DSIFreq_Value=60000000
-RCC.DSIPixelFreq_Value=50000000
-RCC.DSITXEscFreq_Value=15000000
-RCC.DSI_VALUE=60000000
-RCC.ETHFreq_Value=50000000
-RCC.FDCANFreq_Value=24000000
-RCC.FMCFreq_Value=264000000
-RCC.FamilyName=M
-RCC.HSE_Timout=100
-RCC.HSE_VALUE=24000000
-RCC.HSIDivClkFreq_Value=64000000
-RCC.HSI_VALUE=64000000
-RCC.Hclk5DIVFreq_Value=264000000
-RCC.Hclk6DIVFreq_Value=264000000
-RCC.I2C12CLockSelection=RCC_I2C12CLKSOURCE_HSI
-RCC.I2C12Freq_Value=64000000
-RCC.I2C35Freq_Value=98000000
-RCC.I2C46CLockSelection=RCC_I2C46CLKSOURCE_HSI
-RCC.I2C46Freq_Value=64000000
-RCC.IPParameters=ADCCLockSelection,ADCFreq_Value,AHB1234Freq_Value,APB1DIV,APB1Freq_Value,APB2DIV,APB2Freq_Value,APB3DIV,APB3Freq_Value,APB4DIV,APB4Freq_Value,APB5DIV,APB5DIVClockFreq_Value,AXICLKFreq_VALUE,AXICLKSource,AXIDIVFreq_Value,CECFreq_Value,CKPERCLKFreq_VALUE,CKPERCLKSource,CSI_VALUE,DACCLKFreq_VALUE,DDRCFreq_Value,DDRPERFMFreq_Value,DDRPHYFreq_Value,DFSDFAFreq_Value,DFSDMFreq_Value,DIVM1,DIVM2,DIVM3,DIVM4,DIVN1,DIVN2,DIVN3,DIVN4,DIVP1Freq_Value,DIVP2Freq_Value,DIVP3,DIVP3Freq_Value,DIVP4,DIVP4Freq_Value,DIVQ1Freq_Value,DIVQ2Freq_Value,DIVQ3Freq_Value,DIVQ4,DIVQ4Freq_Value,DIVR1Freq_Value,DIVR2,DIVR2Freq_Value,DIVR3Freq_Value,DIVR4,DIVR4Freq_Value,DSIFreq_Value,DSIPixelFreq_Value,DSITXEscFreq_Value,DSI_VALUE,ETHFreq_Value,FDCANFreq_Value,FMCFreq_Value,FamilyName,HSE_Timout,HSE_VALUE,HSIDivClkFreq_Value,HSI_VALUE,Hclk5DIVFreq_Value,Hclk6DIVFreq_Value,I2C12CLockSelection,I2C12Freq_Value,I2C35Freq_Value,I2C46CLockSelection,I2C46Freq_Value,LPTIM1Freq_Value,LPTIM23Freq_Value,LPTIM45Freq_Value,LSE_Timout,LSI_VALUE,LTDCFreq_Value,MCO1PinFreq_Value,MCO2PinFreq_Value,MCUCLKFreq_VALUE,MCUCLKSource,MCUClockFreq_Value,MCUDIVCLKFreq_Value,MPUCLKFreq_VALUE,MPUCLKSource,PLL12Source,PLL2FRACV,PLL3Source,PLL4PDSIFreq_Value,PLL4Source,PLLDSIFreq_Value,PLLDSIVCOFreq_Value,PUBLFreq_Value,QSPIFreq_Value,RNG1Freq_Value,RNG2Freq_Value,RTCClockSelection,RTCFreq_Value,SAI1Freq_Value,SAI2Freq_Value,SAI3Freq_Value,SAI4Freq_Value,SDMMC12CLockSelection,SDMMC12Freq_Value,SDMMC3Freq_Value,SPDIFRXFreq_Value,SPI1Freq_Value,SPI23Freq_Value,SPI45Freq_Value,SPI6Freq_Value,STGENCLockSelection,STGENFreq_Value,Tim1OutputFreq_Value,Tim2OutputFreq_Value,UART78Freq_Value,USART1Freq_Value,USART24Freq_Value,USART35Freq_Value,USART6Freq_Value,USBOCLKSource,USBOHSFreq_Value,USBPHYCLKSource,USBPHYFreq_Value,VCO1OutputFreq_Value,VCO2OutputFreq_Value,VCO3OutputFreq_Value,VCO4OutputFreq_Value,VCOInput1Freq_Value,VCOInput2Freq_Value,VCOInput3Freq_Value,VCOInput4Freq_Value
-RCC.LPTIM1Freq_Value=98000000
-RCC.LPTIM23Freq_Value=98000000
-RCC.LPTIM45Freq_Value=98000000
-RCC.LSE_Timout=5000
-RCC.LSI_VALUE=32000
-RCC.LTDCFreq_Value=50000000
-RCC.MCO1PinFreq_Value=64000000
-RCC.MCO2PinFreq_Value=648000000
-RCC.MCUCLKFreq_VALUE=196000000
-RCC.MCUCLKSource=RCC_MCUSSOURCE_PLL3
-RCC.MCUClockFreq_Value=196000000
-RCC.MCUDIVCLKFreq_Value=196000000
-RCC.MPUCLKFreq_VALUE=648000000
-RCC.MPUCLKSource=RCC_MPUSOURCE_PLL1
-RCC.PLL12Source=RCC_PLL12SOURCE_HSE
-RCC.PLL2FRACV=0
-RCC.PLL3Source=RCC_PLL3SOURCE_HSE
-RCC.PLL4PDSIFreq_Value=50000000
-RCC.PLL4Source=RCC_PLL4SOURCE_HSE
-RCC.PLLDSIFreq_Value=480000000
-RCC.PLLDSIVCOFreq_Value=960000000
-RCC.PUBLFreq_Value=528000000
-RCC.QSPIFreq_Value=264000000
-RCC.RNG1Freq_Value=4000000
-RCC.RNG2Freq_Value=4000000
-RCC.RTCClockSelection=RCC_RTCCLKSOURCE_LSE
-RCC.RTCFreq_Value=32768
-RCC.SAI1Freq_Value=50000000
-RCC.SAI2Freq_Value=50000000
-RCC.SAI3Freq_Value=50000000
-RCC.SAI4Freq_Value=50000000
-RCC.SDMMC12CLockSelection=RCC_SDMMC12CLKSOURCE_PLL4
-RCC.SDMMC12Freq_Value=50000000
-RCC.SDMMC3Freq_Value=196000000
-RCC.SPDIFRXFreq_Value=50000000
-RCC.SPI1Freq_Value=50000000
-RCC.SPI23Freq_Value=50000000
-RCC.SPI45Freq_Value=98000000
-RCC.SPI6Freq_Value=66000000
-RCC.STGENCLockSelection=RCC_STGENCLKSOURCE_HSE
-RCC.STGENFreq_Value=24000000
-RCC.Tim1OutputFreq_Value=196000000
-RCC.Tim2OutputFreq_Value=196000000
-RCC.UART78Freq_Value=98000000
-RCC.USART1Freq_Value=66000000
-RCC.USART24Freq_Value=98000000
-RCC.USART35Freq_Value=98000000
-RCC.USART6Freq_Value=98000000
-RCC.USBOCLKSource=RCC_USBOCLKSOURCE_PHY
-RCC.USBOHSFreq_Value=48000000
-RCC.USBPHYCLKSource=RCC_USBPHYCLKSOURCE_HSE
-RCC.USBPHYFreq_Value=24000000
-RCC.VCO1OutputFreq_Value=1296000000
-RCC.VCO2OutputFreq_Value=1056000000
-RCC.VCO3OutputFreq_Value=784000000
-RCC.VCO4OutputFreq_Value=500000000
-RCC.VCOInput1Freq_Value=8000000
-RCC.VCOInput2Freq_Value=8000000
-RCC.VCOInput3Freq_Value=8000000
-RCC.VCOInput4Freq_Value=4000000
-SH.ADCx_INP5.0=ADC1_INP5,IN5-Single-Ended
-SH.ADCx_INP5.ConfNb=1
-SH.S_TIM1_CH2.0=TIM1_CH2,PWM Generation2 CH2
-SH.S_TIM1_CH2.ConfNb=1
-SH.S_TIM4_CH3.0=TIM4_CH3,PWM Generation3 CH3
-SH.S_TIM4_CH3.ConfNb=1
-TIM1.Channel-PWM\ Generation2\ CH2=TIM_CHANNEL_2
-TIM1.IPParameters=Channel-PWM Generation2 CH2
-TIM4.Channel-PWM\ Generation3\ CH3=TIM_CHANNEL_3
-TIM4.IPParameters=Channel-PWM Generation3 CH3
-USART2.IPParameters=VirtualMode-Asynchronous
-USART2.VirtualMode-Asynchronous=VM_ASYNC
-USART6.IPParameters=VirtualMode-Asynchronous
-USART6.VirtualMode-Asynchronous=VM_ASYNC
-USB_DM1.Mode=Enable
-USB_DM1.Signal=USBH_HS1_DM
-USB_DM2.Mode=Ext_Phy_OTG/Dual-Role-Device
-USB_DM2.Signal=USB_OTG_HS_DM
-USB_DP1.Mode=Enable
-USB_DP1.Signal=USBH_HS1_DP
-USB_DP2.Mode=Ext_Phy_OTG/Dual-Role-Device
-USB_DP2.Signal=USB_OTG_HS_DP
-VP_BSEC_VS_BSEC.Mode=BSEC_Activate
-VP_BSEC_VS_BSEC.Signal=BSEC_VS_BSEC
-VP_CRC1_VS_CRC.Mode=CRC_Activate
-VP_CRC1_VS_CRC.Signal=CRC1_VS_CRC
-VP_CRYP1_VS_CRYP.Mode=CRYP_Activate
-VP_CRYP1_VS_CRYP.Signal=CRYP1_VS_CRYP
-VP_DDR_DDR3.Mode=DDR3
-VP_DDR_DDR3.Signal=DDR_DDR3
-VP_DDR_DDR3_16_4Gb.Mode=4Gb_16bits
-VP_DDR_DDR3_16_4Gb.Signal=DDR_DDR3_16_4Gb
-VP_DDR_DDR_16_bits.Mode=16bits
-VP_DDR_DDR_16_bits.Signal=DDR_DDR_16_bits
-VP_DMA_VS_DMA1_A7NS.Mode=CortexA7NS
-VP_DMA_VS_DMA1_A7NS.Signal=DMA_VS_DMA1_A7NS
-VP_DMA_VS_DMA2_M4.Mode=CortexM4
-VP_DMA_VS_DMA2_M4.Signal=DMA_VS_DMA2_M4
-VP_DTS_VS_DTS.Mode=DTS_Activate
-VP_DTS_VS_DTS.Signal=DTS_VS_DTS
-VP_ETZPC_VS_ETZPC.Mode=ETZPC_Activate
-VP_ETZPC_VS_ETZPC.Signal=ETZPC_VS_ETZPC
-VP_GPU_VS_GPU.Mode=GPU_Activate
-VP_GPU_VS_GPU.Signal=GPU_VS_GPU
-VP_HASH1_VS_HASH.Mode=HASH_Activate
-VP_HASH1_VS_HASH.Signal=HASH1_VS_HASH
-VP_HSEM_VS_HSEM.Mode=HSEM_Activate
-VP_HSEM_VS_HSEM.Signal=HSEM_VS_HSEM
-VP_IPCC_VS_IPCC.Mode=IPCC_Activate
-VP_IPCC_VS_IPCC.Signal=IPCC_VS_IPCC
-VP_MDMA_VS_MDMA_A7NS_8.Mode=8\:8
-VP_MDMA_VS_MDMA_A7NS_8.Signal=MDMA_VS_MDMA_A7NS_8
-VP_RNG1_VS_RNG.Mode=RNG_Activate
-VP_RNG1_VS_RNG.Signal=RNG1_VS_RNG
-VP_RTC_VS_RTC_Activate.Mode=RTC_Enabled
-VP_RTC_VS_RTC_Activate.Signal=RTC_VS_RTC_Activate
-VP_SYS_VS_Systick.Mode=SysTick
-VP_SYS_VS_Systick.Signal=SYS_VS_Systick
-VP_VREFBUF_VS_VREFBUF.Mode=VREFBUF_Activate
-VP_VREFBUF_VS_VREFBUF.Signal=VREFBUF_VS_VREFBUF
-board=custom
diff --git a/conf/machine/cubemx/t1000-som-minimal/DeviceTree/t1000-som-minimal/kernel/stm32mp157c-t1000-som-minimal-mx.dts b/conf/machine/cubemx/t1000-som-minimal/DeviceTree/t1000-som-minimal/kernel/stm32mp157c-t1000-som-minimal-mx.dts
deleted file mode 100644
index c9753dfd647a80120c3e55a48116af453e66cbc0..0000000000000000000000000000000000000000
--- a/conf/machine/cubemx/t1000-som-minimal/DeviceTree/t1000-som-minimal/kernel/stm32mp157c-t1000-som-minimal-mx.dts
+++ /dev/null
@@ -1,518 +0,0 @@
-/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
-/*
- * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
- * Author: STM32CubeMX code generation for STMicroelectronics.
- */
-
-/dts-v1/;
-#include "stm32mp157c.dtsi"
-#include "stm32mp157c-m4-srm.dtsi"
-#include "stm32mp157cad-pinctrl.dtsi"
-
-/* USER CODE BEGIN includes */
-/* USER CODE END includes */
-
-/ {
-	model = "STMicroelectronics custom STM32CubeMX board";
-	compatible = "st,stm32mp157c-t1000-som-minimal-mx", "st,stm32mp157";
-
-	memory@c0000000 {
-		reg = <0xc0000000 0x20000000>;
-
-		/* USER CODE BEGIN memory */
-		/* USER CODE END memory */
-	};
-
-	reserved-memory {
-		#address-cells = <1>;
-		#size-cells = <1>;
-		ranges;
-
-		/* USER CODE BEGIN reserved-memory */
-		/* USER CODE END reserved-memory */
-
-		gpu_reserved: gpu@dc000000 {
-			reg = <0xdc000000 0x4000000>;
-			no-map;
-		};
-	};
-
-	/* USER CODE BEGIN root */
-	/* USER CODE END root */
-
-	clocks {
-		/* USER CODE BEGIN clocks */
-		/* USER CODE END clocks */
-
-		clk_hsi: clk-hsi {
-			clock-frequency = <64000000>;
-		};
-
-		clk_csi: clk-csi {
-			clock-frequency = <4000000>;
-		};
-
-		clk_lse: clk-lse {
-			clock-frequency = <32768>;
-		};
-
-		clk_hse: clk-hse {
-			clock-frequency = <24000000>;
-		};
-	};
-
-}; /*root*/
-
-&pinctrl {
-	u-boot,dm-pre-reloc;
-
-	eth1_pins_mx: eth1_mx-0 {
-		pins1 {
-			pinmux = <STM32_PINMUX('A', 2, AF11)>; /* ETH1_MDIO */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-		pins2 {
-			pinmux = <STM32_PINMUX('A', 7, AF11)>, /* ETH1_CRS_DV */
-					 <STM32_PINMUX('C', 4, AF11)>, /* ETH1_RXD0 */
-					 <STM32_PINMUX('C', 5, AF11)>; /* ETH1_RXD1 */
-			bias-disable;
-		};
-		pins3 {
-			pinmux = <STM32_PINMUX('B', 11, AF11)>; /* ETH1_TX_EN */
-		};
-		pins4 {
-			pinmux = <STM32_PINMUX('B', 12, AF11)>, /* ETH1_TXD0 */
-					 <STM32_PINMUX('B', 13, AF11)>, /* ETH1_TXD1 */
-					 <STM32_PINMUX('C', 1, AF11)>, /* ETH1_MDC */
-					 <STM32_PINMUX('G', 8, AF2)>; /* ETH1_CLK */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-	};
-
-	eth1_sleep_pins_mx: eth1_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 2, ANALOG)>, /* ETH1_MDIO */
-					 <STM32_PINMUX('A', 7, ANALOG)>, /* ETH1_CRS_DV */
-					 <STM32_PINMUX('B', 11, ANALOG)>, /* ETH1_TX_EN */
-					 <STM32_PINMUX('B', 12, ANALOG)>, /* ETH1_TXD0 */
-					 <STM32_PINMUX('B', 13, ANALOG)>, /* ETH1_TXD1 */
-					 <STM32_PINMUX('C', 1, ANALOG)>, /* ETH1_MDC */
-					 <STM32_PINMUX('C', 4, ANALOG)>, /* ETH1_RXD0 */
-					 <STM32_PINMUX('C', 5, ANALOG)>, /* ETH1_RXD1 */
-					 <STM32_PINMUX('G', 8, ANALOG)>; /* ETH1_CLK */
-		};
-	};
-
-	i2c2_pins_mx: i2c2_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('D', 7, AF4)>, /* I2C2_SCL */
-					 <STM32_PINMUX('G', 15, AF4)>; /* I2C2_SDA */
-			bias-disable;
-			drive-open-drain;
-			slew-rate = <0>;
-		};
-	};
-
-	i2c2_sleep_pins_mx: i2c2_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('D', 7, ANALOG)>, /* I2C2_SCL */
-					 <STM32_PINMUX('G', 15, ANALOG)>; /* I2C2_SDA */
-		};
-	};
-
-	quadspi_pins_mx: quadspi_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 6, AF10)>, /* QUADSPI_BK1_NCS */
-					 <STM32_PINMUX('C', 0, AF10)>; /* QUADSPI_BK2_NCS */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('E', 7, AF10)>, /* QUADSPI_BK2_IO0 */
-					 <STM32_PINMUX('E', 8, AF10)>, /* QUADSPI_BK2_IO1 */
-					 <STM32_PINMUX('E', 9, AF10)>, /* QUADSPI_BK2_IO2 */
-					 <STM32_PINMUX('E', 10, AF10)>, /* QUADSPI_BK2_IO3 */
-					 <STM32_PINMUX('F', 6, AF9)>, /* QUADSPI_BK1_IO3 */
-					 <STM32_PINMUX('F', 7, AF9)>, /* QUADSPI_BK1_IO2 */
-					 <STM32_PINMUX('F', 8, AF10)>, /* QUADSPI_BK1_IO0 */
-					 <STM32_PINMUX('F', 9, AF10)>; /* QUADSPI_BK1_IO1 */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins3 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('F', 10, AF9)>; /* QUADSPI_CLK */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <2>;
-		};
-	};
-
-	quadspi_sleep_pins_mx: quadspi_sleep_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 6, ANALOG)>, /* QUADSPI_BK1_NCS */
-					 <STM32_PINMUX('C', 0, ANALOG)>, /* QUADSPI_BK2_NCS */
-					 <STM32_PINMUX('E', 7, ANALOG)>, /* QUADSPI_BK2_IO0 */
-					 <STM32_PINMUX('E', 8, ANALOG)>, /* QUADSPI_BK2_IO1 */
-					 <STM32_PINMUX('E', 9, ANALOG)>, /* QUADSPI_BK2_IO2 */
-					 <STM32_PINMUX('E', 10, ANALOG)>, /* QUADSPI_BK2_IO3 */
-					 <STM32_PINMUX('F', 6, ANALOG)>, /* QUADSPI_BK1_IO3 */
-					 <STM32_PINMUX('F', 7, ANALOG)>, /* QUADSPI_BK1_IO2 */
-					 <STM32_PINMUX('F', 8, ANALOG)>, /* QUADSPI_BK1_IO0 */
-					 <STM32_PINMUX('F', 9, ANALOG)>, /* QUADSPI_BK1_IO1 */
-					 <STM32_PINMUX('F', 10, ANALOG)>; /* QUADSPI_CLK */
-		};
-	};
-
-	rtc_pins_mx: rtc_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('C', 13, ANALOG)>; /* RTC_LSCO */
-		};
-	};
-
-	rtc_sleep_pins_mx: rtc_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('C', 13, ANALOG)>; /* RTC_LSCO */
-		};
-	};
-
-	sdmmc1_pins_mx: sdmmc1_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
-					 <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
-					 <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
-					 <STM32_PINMUX('C', 11, AF12)>, /* SDMMC1_D3 */
-					 <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 12, AF12)>; /* SDMMC1_CK */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-	};
-
-	sdmmc1_opendrain_pins_mx: sdmmc1_opendrain_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
-					 <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
-					 <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
-					 <STM32_PINMUX('C', 11, AF12)>; /* SDMMC1_D3 */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 12, AF12)>; /* SDMMC1_CK */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins3 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
-			bias-pull-up;
-			drive-open-drain;
-			slew-rate = <1>;
-		};
-	};
-
-	sdmmc1_sleep_pins_mx: sdmmc1_sleep_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 8, ANALOG)>, /* SDMMC1_D0 */
-					 <STM32_PINMUX('C', 9, ANALOG)>, /* SDMMC1_D1 */
-					 <STM32_PINMUX('C', 10, ANALOG)>, /* SDMMC1_D2 */
-					 <STM32_PINMUX('C', 11, ANALOG)>, /* SDMMC1_D3 */
-					 <STM32_PINMUX('C', 12, ANALOG)>, /* SDMMC1_CK */
-					 <STM32_PINMUX('D', 2, ANALOG)>; /* SDMMC1_CMD */
-		};
-	};
-
-	uart4_pins_mx: uart4_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 2, AF8)>; /* UART4_RX */
-			bias-pull-up;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('G', 11, AF6)>; /* UART4_TX */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-	};
-
-	uart4_sleep_pins_mx: uart4_sleep_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 2, ANALOG)>, /* UART4_RX */
-					 <STM32_PINMUX('G', 11, ANALOG)>; /* UART4_TX */
-		};
-	};
-
-	usb_otg_hs_pins_mx: usb_otg_hs_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
-		};
-	};
-
-	usb_otg_hs_sleep_pins_mx: usb_otg_hs_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
-		};
-	};
-
-	/* USER CODE BEGIN pinctrl */
-	/* USER CODE END pinctrl */
-};
-
-&pinctrl_z {
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN pinctrl_z */
-	/* USER CODE END pinctrl_z */
-};
-
-&m4_rproc{
-	mboxes = <&ipcc 0>, <&ipcc 1>, <&ipcc 2>;
-	mbox-names = "vq0", "vq1", "shutdown";
-	recovery;
-	status = "okay";
-
-	/* USER CODE BEGIN m4_rproc */
-	/* USER CODE END m4_rproc */
-};
-
-&adc{
-	status = "okay";
-
-	/* USER CODE BEGIN adc */
-	/* USER CODE END adc */
-};
-
-&bsec{
-	status = "okay";
-
-	/* USER CODE BEGIN bsec */
-	/* USER CODE END bsec */
-};
-
-&crc1{
-	status = "okay";
-
-	/* USER CODE BEGIN crc1 */
-	/* USER CODE END crc1 */
-};
-
-&cryp1{
-	status = "okay";
-
-	/* USER CODE BEGIN cryp1 */
-	/* USER CODE END cryp1 */
-};
-
-&dts{
-	status = "okay";
-
-	/* USER CODE BEGIN dts */
-	/* USER CODE END dts */
-};
-
-&ethernet0{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&eth1_pins_mx>;
-	pinctrl-1 = <&eth1_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN ethernet0 */
-	/* USER CODE END ethernet0 */
-};
-
-&gpu{
-	status = "okay";
-
-	/* USER CODE BEGIN gpu */
-	/* USER CODE END gpu */
-};
-
-&hash1{
-	status = "okay";
-
-	/* USER CODE BEGIN hash1 */
-	/* USER CODE END hash1 */
-};
-
-&hsem{
-	status = "okay";
-
-	/* USER CODE BEGIN hsem */
-	/* USER CODE END hsem */
-};
-
-&i2c2{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&i2c2_pins_mx>;
-	pinctrl-1 = <&i2c2_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN i2c2 */
-	/* USER CODE END i2c2 */
-};
-
-&ipcc{
-	status = "okay";
-
-	/* USER CODE BEGIN ipcc */
-	/* USER CODE END ipcc */
-};
-
-&iwdg2{
-	status = "okay";
-
-	/* USER CODE BEGIN iwdg2 */
-	/* USER CODE END iwdg2 */
-};
-
-&qspi{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&quadspi_pins_mx>;
-	pinctrl-1 = <&quadspi_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN qspi */
-	/* USER CODE END qspi */
-};
-
-&rcc{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN rcc */
-	/* USER CODE END rcc */
-};
-
-&rng1{
-	status = "okay";
-
-	/* USER CODE BEGIN rng1 */
-	/* USER CODE END rng1 */
-};
-
-&rtc{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&rtc_pins_mx>;
-	pinctrl-1 = <&rtc_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN rtc */
-	/* USER CODE END rtc */
-};
-
-&sdmmc1{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "opendrain", "sleep";
-	pinctrl-0 = <&sdmmc1_pins_mx>;
-	pinctrl-1 = <&sdmmc1_opendrain_pins_mx>;
-	pinctrl-2 = <&sdmmc1_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN sdmmc1 */
-	/* USER CODE END sdmmc1 */
-};
-
-&uart4{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&uart4_pins_mx>;
-	pinctrl-1 = <&uart4_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN uart4 */
-	/* USER CODE END uart4 */
-};
-
-&usbh_ehci{
-	status = "okay";
-
-	/* USER CODE BEGIN usbh_ehci */
-	/* USER CODE END usbh_ehci */
-};
-
-&usbh_ohci{
-	status = "okay";
-
-	/* USER CODE BEGIN usbh_ohci */
-	/* USER CODE END usbh_ohci */
-};
-
-&usbotg_hs{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&usb_otg_hs_pins_mx>;
-	pinctrl-1 = <&usb_otg_hs_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN usbotg_hs */
-	/* USER CODE END usbotg_hs */
-};
-
-&usbphyc{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc */
-	/* USER CODE END usbphyc */
-};
-
-&usbphyc_port0{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc_port0 */
-	/* USER CODE END usbphyc_port0 */
-};
-
-&usbphyc_port1{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc_port1 */
-	/* USER CODE END usbphyc_port1 */
-};
-
-&vrefbuf{
-	status = "okay";
-
-	/* USER CODE BEGIN vrefbuf */
-	/* USER CODE END vrefbuf */
-};
-
-/* USER CODE BEGIN addons */
-/* USER CODE END addons */
-
diff --git a/conf/machine/cubemx/t1000-som-minimal/DeviceTree/t1000-som-minimal/tf-a/stm32mp15-mx.h b/conf/machine/cubemx/t1000-som-minimal/DeviceTree/t1000-som-minimal/tf-a/stm32mp15-mx.h
deleted file mode 100644
index ef7055bca186a6230f8d5242275f0b18f610a369..0000000000000000000000000000000000000000
--- a/conf/machine/cubemx/t1000-som-minimal/DeviceTree/t1000-som-minimal/tf-a/stm32mp15-mx.h
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright (C) 2015-2018, STMicroelectronics - All Rights Reserved
- *
- * SPDX-License-Identifier:	GPL-2.0+	BSD-3-Clause
- *
- */
-
-/*
- * File generated by STMicroelectronics STM32CubeMX DDR Tool for MPUs
- * DDR type: DDR3 / DDR3L
- * DDR width: 16bits
- * DDR density: 4Gb
- * System frequency: 528000Khz
- * Relaxed Timing Mode: false
- * Address mapping type: RBC
- *
- * Save Date: 2019.09.17, save Time: 18:43:33
- */
-
-#define DDR_MEM_NAME	"DDR3-DDR3L 16bits 528000Khz"
-#define DDR_MEM_SPEED	528000
-#define DDR_MEM_SIZE	0x20000000
-
-#define DDR_MSTR 0x00041401
-#define DDR_MRCTRL0 0x00000010
-#define DDR_MRCTRL1 0x00000000
-#define DDR_DERATEEN 0x00000000
-#define DDR_DERATEINT 0x00800000
-#define DDR_PWRCTL 0x00000000
-#define DDR_PWRTMG 0x00400010
-#define DDR_HWLPCTL 0x00000000
-#define DDR_RFSHCTL0 0x00210000
-#define DDR_RFSHCTL3 0x00000000
-#define DDR_RFSHTMG 0x0040008A
-#define DDR_CRCPARCTL0 0x00000000
-#define DDR_DRAMTMG0 0x121B1214
-#define DDR_DRAMTMG1 0x000A041B
-#define DDR_DRAMTMG2 0x0607080F
-#define DDR_DRAMTMG3 0x0050400C
-#define DDR_DRAMTMG4 0x07040607
-#define DDR_DRAMTMG5 0x06060403
-#define DDR_DRAMTMG6 0x02020002
-#define DDR_DRAMTMG7 0x00000202
-#define DDR_DRAMTMG8 0x00001005
-#define DDR_DRAMTMG14 0x000000A0
-#define DDR_ZQCTL0 0xC2000040
-#define DDR_DFITMG0 0x02050105
-#define DDR_DFITMG1 0x00000202
-#define DDR_DFILPCFG0 0x07000000
-#define DDR_DFIUPD0 0xC0400003
-#define DDR_DFIUPD1 0x00000000
-#define DDR_DFIUPD2 0x00000000
-#define DDR_DFIPHYMSTR 0x00000000
-#define DDR_ODTCFG 0x06000600
-#define DDR_ODTMAP 0x00000001
-#define DDR_SCHED 0x00000C01
-#define DDR_SCHED1 0x00000000
-#define DDR_PERFHPR1 0x01000001
-#define DDR_PERFLPR1 0x08000200
-#define DDR_PERFWR1 0x08000400
-#define DDR_DBG0 0x00000000
-#define DDR_DBG1 0x00000000
-#define DDR_DBGCMD 0x00000000
-#define DDR_POISONCFG 0x00000000
-#define DDR_PCCFG 0x00000010
-#define DDR_PCFGR_0 0x00010000
-#define DDR_PCFGW_0 0x00000000
-#define DDR_PCFGQOS0_0 0x02100C03
-#define DDR_PCFGQOS1_0 0x00800100
-#define DDR_PCFGWQOS0_0 0x01100C03
-#define DDR_PCFGWQOS1_0 0x01000200
-#define DDR_PCFGR_1 0x00010000
-#define DDR_PCFGW_1 0x00000000
-#define DDR_PCFGQOS0_1 0x02100C03
-#define DDR_PCFGQOS1_1 0x00800040
-#define DDR_PCFGWQOS0_1 0x01100C03
-#define DDR_PCFGWQOS1_1 0x01000200
-#define DDR_ADDRMAP1 0x00070707
-#define DDR_ADDRMAP2 0x00000000
-#define DDR_ADDRMAP3 0x1F000000
-#define DDR_ADDRMAP4 0x00001F1F
-#define DDR_ADDRMAP5 0x06060606
-#define DDR_ADDRMAP6 0x0F060606
-#define DDR_ADDRMAP9 0x00000000
-#define DDR_ADDRMAP10 0x00000000
-#define DDR_ADDRMAP11 0x00000000
-#define DDR_PGCR 0x01442E02
-#define DDR_PTR0 0x0022A41B
-#define DDR_PTR1 0x047C0740
-#define DDR_PTR2 0x042D9C80
-#define DDR_ACIOCR 0x10400812
-#define DDR_DXCCR 0x00000C40
-#define DDR_DSGCR 0xF200001F
-#define DDR_DCR 0x0000000B
-#define DDR_DTPR0 0x36D477D0
-#define DDR_DTPR1 0x098A00D8
-#define DDR_DTPR2 0x10023600
-#define DDR_MR0 0x00000830
-#define DDR_MR1 0x00000000
-#define DDR_MR2 0x00000248
-#define DDR_MR3 0x00000000
-#define DDR_ODTCR 0x00010000
-#define DDR_ZQ0CR1 0x00000038
-#define DDR_DX0GCR 0x0000CE81
-#define DDR_DX0DLLCR 0x40000000
-#define DDR_DX0DQTR 0x55050005
-#define DDR_DX0DQSTR 0x3D202000
-#define DDR_DX1GCR 0x0000CE81
-#define DDR_DX1DLLCR 0x40000000
-#define DDR_DX1DQTR 0x00050500
-#define DDR_DX1DQSTR 0x3DB02000
-#define DDR_DX2GCR 0x0000C881
-#define DDR_DX2DLLCR 0x40000000
-#define DDR_DX2DQTR 0xFFFFFFFF
-#define DDR_DX2DQSTR 0x3DB02000
-#define DDR_DX3GCR 0x0000C881
-#define DDR_DX3DLLCR 0x40000000
-#define DDR_DX3DQTR 0xFFFFFFFF
-#define DDR_DX3DQSTR 0x3DB02000
diff --git a/conf/machine/cubemx/t1000-som-minimal/DeviceTree/t1000-som-minimal/tf-a/stm32mp157c-t1000-som-minimal-mx.dts b/conf/machine/cubemx/t1000-som-minimal/DeviceTree/t1000-som-minimal/tf-a/stm32mp157c-t1000-som-minimal-mx.dts
deleted file mode 100644
index a78c61cac5bd5c863b37625b99470ca3e630b3dc..0000000000000000000000000000000000000000
--- a/conf/machine/cubemx/t1000-som-minimal/DeviceTree/t1000-som-minimal/tf-a/stm32mp157c-t1000-som-minimal-mx.dts
+++ /dev/null
@@ -1,335 +0,0 @@
-/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
-/*
- * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
- * Author: STM32CubeMX code generation for STMicroelectronics.
- */
-
-/dts-v1/;
-#include <dt-bindings/clock/stm32mp1-clksrc.h>
-#include "stm32mp15-mx.h"
-
-#include "stm32mp157c.dtsi"
-#include "stm32mp157cad-pinctrl.dtsi"
-#include "stm32mp15-ddr.dtsi"
-#include "stm32mp157c-security.dtsi"
-
-/* USER CODE BEGIN includes */
-/* USER CODE END includes */
-
-/ {
-	model = "STMicroelectronics custom STM32CubeMX board";
-	compatible = "st,stm32mp157c-t1000-som-minimal-mx", "st,stm32mp157";
-
-	/* USER CODE BEGIN root */
-	/* USER CODE END root */
-
-	clocks {
-		/* USER CODE BEGIN clocks */
-		/* USER CODE END clocks */
-
-		clk_lse: clk-lse {
-			/* USER CODE BEGIN clocks */
-			/* USER CODE END clocks */
-			st,drive=<LSEDRV_MEDIUM_HIGH>;
-		};
-
-		clk_hse: clk-hse {
-			/* USER CODE BEGIN clocks */
-			/* USER CODE END clocks */
-		};
-	};
-
-}; /*root*/
-
-&pinctrl {
-	quadspi_pins_mx: quadspi_mx-0 {
-		pins1 {
-			pinmux = <STM32_PINMUX('B', 6, AF10)>, /* QUADSPI_BK1_NCS */
-					 <STM32_PINMUX('C', 0, AF10)>; /* QUADSPI_BK2_NCS */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins2 {
-			pinmux = <STM32_PINMUX('E', 7, AF10)>, /* QUADSPI_BK2_IO0 */
-					 <STM32_PINMUX('E', 8, AF10)>, /* QUADSPI_BK2_IO1 */
-					 <STM32_PINMUX('E', 9, AF10)>, /* QUADSPI_BK2_IO2 */
-					 <STM32_PINMUX('E', 10, AF10)>, /* QUADSPI_BK2_IO3 */
-					 <STM32_PINMUX('F', 6, AF9)>, /* QUADSPI_BK1_IO3 */
-					 <STM32_PINMUX('F', 7, AF9)>, /* QUADSPI_BK1_IO2 */
-					 <STM32_PINMUX('F', 8, AF10)>, /* QUADSPI_BK1_IO0 */
-					 <STM32_PINMUX('F', 9, AF10)>; /* QUADSPI_BK1_IO1 */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins3 {
-			pinmux = <STM32_PINMUX('F', 10, AF9)>; /* QUADSPI_CLK */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <2>;
-		};
-	};
-
-	rtc_pins_mx: rtc_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('C', 13, ANALOG)>; /* RTC_LSCO */
-		};
-	};
-
-	sdmmc1_pins_mx: sdmmc1_mx-0 {
-		pins1 {
-			pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
-					 <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
-					 <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
-					 <STM32_PINMUX('C', 11, AF12)>, /* SDMMC1_D3 */
-					 <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-		pins2 {
-			pinmux = <STM32_PINMUX('C', 12, AF12)>; /* SDMMC1_CK */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-	};
-
-	uart4_pins_mx: uart4_mx-0 {
-		pins1 {
-			pinmux = <STM32_PINMUX('B', 2, AF8)>; /* UART4_RX */
-			bias-pull-up;
-		};
-		pins2 {
-			pinmux = <STM32_PINMUX('G', 11, AF6)>; /* UART4_TX */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-	};
-
-	usb_otg_hs_pins_mx: usb_otg_hs_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
-		};
-	};
-
-	/* USER CODE BEGIN pinctrl */
-	/* USER CODE END pinctrl */
-};
-
-&pinctrl_z {
-	/* USER CODE BEGIN pinctrl_z */
-	/* USER CODE END pinctrl_z */
-};
-
-&rcc {
-	st,csi-cal;
-	st,hsi-cal;
-	st,cal-sec = <60>;
-	st,clksrc = <
-		CLK_MPU_PLL1P
-		CLK_AXI_PLL2P
-		CLK_MCU_PLL3P
-		CLK_PLL12_HSE
-		CLK_PLL3_HSE
-		CLK_PLL4_HSE
-		CLK_RTC_LSE
-		CLK_MCO1_DISABLED
-		CLK_MCO2_DISABLED
-	>;
-	st,clkdiv = <
-		1 		/*MPU*/
-		0 		/*AXI*/
-		0 		/*MCU*/
-		1 		/*APB1*/
-		1 		/*APB2*/
-		1 		/*APB3*/
-		1 		/*APB4*/
-		2 		/*APB5*/
-		0 		/*RTC*/
-		0 		/*MCO1*/
-		0 		/*MCO2*/
-	>;
-	st,pkcs = <
-		CLK_CKPER_HSE
-		CLK_QSPI_ACLK
-		CLK_ETH_PLL4P
-		CLK_SDMMC12_PLL4P
-		CLK_STGEN_HSE
-		CLK_USBPHY_HSE
-		CLK_SPI2S1_DISABLED
-		CLK_SPI2S23_DISABLED
-		CLK_SPI45_DISABLED
-		CLK_SPI6_DISABLED
-		CLK_I2C46_DISABLED
-		CLK_SDMMC3_DISABLED
-		CLK_USBO_USBPHY
-		CLK_ADC_CKPER
-		CLK_CEC_DISABLED
-		CLK_I2C12_HSI
-		CLK_I2C35_DISABLED
-		CLK_UART1_DISABLED
-		CLK_UART24_PCLK1
-		CLK_UART35_DISABLED
-		CLK_UART6_DISABLED
-		CLK_UART78_DISABLED
-		CLK_SPDIF_DISABLED
-		CLK_SAI1_DISABLED
-		CLK_SAI2_DISABLED
-		CLK_SAI3_DISABLED
-		CLK_SAI4_DISABLED
-		CLK_RNG1_CSI
-		CLK_LPTIM1_DISABLED
-		CLK_LPTIM23_DISABLED
-		CLK_LPTIM45_DISABLED
-	>;
-	pll1:st,pll@0 {
-		cfg = < 2 80 0 1 1 1>;
-	};
-	pll2:st,pll@1 {
-		cfg = < 2 65 1 1 0 7>;
-	};
-	pll3:st,pll@2 {
-		cfg = < 1 49 2 2 1 1>;
-	};
-	pll4:st,pll@3 {
-		cfg = < 5 124 9 9 9 1>;
-	};
-};
-
-&bsec{
-	status = "okay";
-	secure-status = "okay";
-
-	/* USER CODE BEGIN bsec */
-	/* USER CODE END bsec */
-};
-
-&etzpc{
-	st,decprot = <
-	/*"Non Secured" peripherals*/
-	DECPROT(STM32MP1_ETZPC_ADC_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-	DECPROT(STM32MP1_ETZPC_CRYP1_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-	DECPROT(STM32MP1_ETZPC_ETH_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-	DECPROT(STM32MP1_ETZPC_HASH1_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-	DECPROT(STM32MP1_ETZPC_I2C2_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-	DECPROT(STM32MP1_ETZPC_QSPI_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-	DECPROT(STM32MP1_ETZPC_DLYBQ_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-	DECPROT(STM32MP1_ETZPC_RNG1_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-	DECPROT(STM32MP1_ETZPC_UART4_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-	DECPROT(STM32MP1_ETZPC_OTG_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-	DECPROT(STM32MP1_ETZPC_VREFBUF_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-
-	/*Restriction: following IDs are not managed  - please to use User-Section if needed:
-		STM32MP1_ETZPC_DMA1_ID, STM32MP1_ETZPC_DMA2_ID, STM32MP1_ETZPC_DMAMUX_ID,
-		STM32MP1_ETZPC_SRAMx_ID, STM32MP1_ETZPC_RETRAM_ID, STM32MP1_ETZPC_BKPSRAM_ID*/
-
-	/* USER CODE BEGIN etzpc_decprot */
-		/*STM32CubeMX generates a basic and standard configuration for ETZPC.
-		Additional device configurations can be added here if needed.
-		"etzpc" node could be also overloaded in "addons" User-Section.*/
-	/* USER CODE END etzpc_decprot */
-	>;
-
-	secure-status = "okay";
-
-	/* USER CODE BEGIN etzpc */
-	/* USER CODE END etzpc */
-};
-
-&iwdg2{
-	status = "okay";
-	secure-status = "okay";
-
-	/* USER CODE BEGIN iwdg2 */
-	/* USER CODE END iwdg2 */
-};
-
-&qspi{
-	pinctrl-names = "default";
-	pinctrl-0 = <&quadspi_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN qspi */
-	/* USER CODE END qspi */
-};
-
-&rcc{
-	status = "okay";
-	secure-status = "okay";
-
-	/* USER CODE BEGIN rcc */
-	/* USER CODE END rcc */
-};
-
-&rng1{
-	status = "okay";
-	secure-status = "okay";
-
-	/* USER CODE BEGIN rng1 */
-	/* USER CODE END rng1 */
-};
-
-&rtc{
-	pinctrl-names = "default";
-	pinctrl-0 = <&rtc_pins_mx>;
-	status = "okay";
-	secure-status = "okay";
-
-	/* USER CODE BEGIN rtc */
-	/* USER CODE END rtc */
-};
-
-&sdmmc1{
-	pinctrl-names = "default";
-	pinctrl-0 = <&sdmmc1_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN sdmmc1 */
-	/* USER CODE END sdmmc1 */
-};
-
-&uart4{
-	pinctrl-names = "default";
-	pinctrl-0 = <&uart4_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN uart4 */
-	/* USER CODE END uart4 */
-};
-
-&usbotg_hs{
-	pinctrl-names = "default";
-	pinctrl-0 = <&usb_otg_hs_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN usbotg_hs */
-	/* USER CODE END usbotg_hs */
-};
-
-&usbphyc{
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc */
-	/* USER CODE END usbphyc */
-};
-
-&usbphyc_port0{
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc_port0 */
-	/* USER CODE END usbphyc_port0 */
-};
-
-&usbphyc_port1{
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc_port1 */
-	/* USER CODE END usbphyc_port1 */
-};
-
-/* USER CODE BEGIN addons */
-/* USER CODE END addons */
-
diff --git a/conf/machine/cubemx/t1000-som-minimal/DeviceTree/t1000-som-minimal/u-boot/stm32mp15-mx.h b/conf/machine/cubemx/t1000-som-minimal/DeviceTree/t1000-som-minimal/u-boot/stm32mp15-mx.h
deleted file mode 100644
index ef7055bca186a6230f8d5242275f0b18f610a369..0000000000000000000000000000000000000000
--- a/conf/machine/cubemx/t1000-som-minimal/DeviceTree/t1000-som-minimal/u-boot/stm32mp15-mx.h
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright (C) 2015-2018, STMicroelectronics - All Rights Reserved
- *
- * SPDX-License-Identifier:	GPL-2.0+	BSD-3-Clause
- *
- */
-
-/*
- * File generated by STMicroelectronics STM32CubeMX DDR Tool for MPUs
- * DDR type: DDR3 / DDR3L
- * DDR width: 16bits
- * DDR density: 4Gb
- * System frequency: 528000Khz
- * Relaxed Timing Mode: false
- * Address mapping type: RBC
- *
- * Save Date: 2019.09.17, save Time: 18:43:33
- */
-
-#define DDR_MEM_NAME	"DDR3-DDR3L 16bits 528000Khz"
-#define DDR_MEM_SPEED	528000
-#define DDR_MEM_SIZE	0x20000000
-
-#define DDR_MSTR 0x00041401
-#define DDR_MRCTRL0 0x00000010
-#define DDR_MRCTRL1 0x00000000
-#define DDR_DERATEEN 0x00000000
-#define DDR_DERATEINT 0x00800000
-#define DDR_PWRCTL 0x00000000
-#define DDR_PWRTMG 0x00400010
-#define DDR_HWLPCTL 0x00000000
-#define DDR_RFSHCTL0 0x00210000
-#define DDR_RFSHCTL3 0x00000000
-#define DDR_RFSHTMG 0x0040008A
-#define DDR_CRCPARCTL0 0x00000000
-#define DDR_DRAMTMG0 0x121B1214
-#define DDR_DRAMTMG1 0x000A041B
-#define DDR_DRAMTMG2 0x0607080F
-#define DDR_DRAMTMG3 0x0050400C
-#define DDR_DRAMTMG4 0x07040607
-#define DDR_DRAMTMG5 0x06060403
-#define DDR_DRAMTMG6 0x02020002
-#define DDR_DRAMTMG7 0x00000202
-#define DDR_DRAMTMG8 0x00001005
-#define DDR_DRAMTMG14 0x000000A0
-#define DDR_ZQCTL0 0xC2000040
-#define DDR_DFITMG0 0x02050105
-#define DDR_DFITMG1 0x00000202
-#define DDR_DFILPCFG0 0x07000000
-#define DDR_DFIUPD0 0xC0400003
-#define DDR_DFIUPD1 0x00000000
-#define DDR_DFIUPD2 0x00000000
-#define DDR_DFIPHYMSTR 0x00000000
-#define DDR_ODTCFG 0x06000600
-#define DDR_ODTMAP 0x00000001
-#define DDR_SCHED 0x00000C01
-#define DDR_SCHED1 0x00000000
-#define DDR_PERFHPR1 0x01000001
-#define DDR_PERFLPR1 0x08000200
-#define DDR_PERFWR1 0x08000400
-#define DDR_DBG0 0x00000000
-#define DDR_DBG1 0x00000000
-#define DDR_DBGCMD 0x00000000
-#define DDR_POISONCFG 0x00000000
-#define DDR_PCCFG 0x00000010
-#define DDR_PCFGR_0 0x00010000
-#define DDR_PCFGW_0 0x00000000
-#define DDR_PCFGQOS0_0 0x02100C03
-#define DDR_PCFGQOS1_0 0x00800100
-#define DDR_PCFGWQOS0_0 0x01100C03
-#define DDR_PCFGWQOS1_0 0x01000200
-#define DDR_PCFGR_1 0x00010000
-#define DDR_PCFGW_1 0x00000000
-#define DDR_PCFGQOS0_1 0x02100C03
-#define DDR_PCFGQOS1_1 0x00800040
-#define DDR_PCFGWQOS0_1 0x01100C03
-#define DDR_PCFGWQOS1_1 0x01000200
-#define DDR_ADDRMAP1 0x00070707
-#define DDR_ADDRMAP2 0x00000000
-#define DDR_ADDRMAP3 0x1F000000
-#define DDR_ADDRMAP4 0x00001F1F
-#define DDR_ADDRMAP5 0x06060606
-#define DDR_ADDRMAP6 0x0F060606
-#define DDR_ADDRMAP9 0x00000000
-#define DDR_ADDRMAP10 0x00000000
-#define DDR_ADDRMAP11 0x00000000
-#define DDR_PGCR 0x01442E02
-#define DDR_PTR0 0x0022A41B
-#define DDR_PTR1 0x047C0740
-#define DDR_PTR2 0x042D9C80
-#define DDR_ACIOCR 0x10400812
-#define DDR_DXCCR 0x00000C40
-#define DDR_DSGCR 0xF200001F
-#define DDR_DCR 0x0000000B
-#define DDR_DTPR0 0x36D477D0
-#define DDR_DTPR1 0x098A00D8
-#define DDR_DTPR2 0x10023600
-#define DDR_MR0 0x00000830
-#define DDR_MR1 0x00000000
-#define DDR_MR2 0x00000248
-#define DDR_MR3 0x00000000
-#define DDR_ODTCR 0x00010000
-#define DDR_ZQ0CR1 0x00000038
-#define DDR_DX0GCR 0x0000CE81
-#define DDR_DX0DLLCR 0x40000000
-#define DDR_DX0DQTR 0x55050005
-#define DDR_DX0DQSTR 0x3D202000
-#define DDR_DX1GCR 0x0000CE81
-#define DDR_DX1DLLCR 0x40000000
-#define DDR_DX1DQTR 0x00050500
-#define DDR_DX1DQSTR 0x3DB02000
-#define DDR_DX2GCR 0x0000C881
-#define DDR_DX2DLLCR 0x40000000
-#define DDR_DX2DQTR 0xFFFFFFFF
-#define DDR_DX2DQSTR 0x3DB02000
-#define DDR_DX3GCR 0x0000C881
-#define DDR_DX3DLLCR 0x40000000
-#define DDR_DX3DQTR 0xFFFFFFFF
-#define DDR_DX3DQSTR 0x3DB02000
diff --git a/conf/machine/cubemx/t1000-som-minimal/DeviceTree/t1000-som-minimal/u-boot/stm32mp157c-t1000-som-minimal-mx-u-boot.dtsi b/conf/machine/cubemx/t1000-som-minimal/DeviceTree/t1000-som-minimal/u-boot/stm32mp157c-t1000-som-minimal-mx-u-boot.dtsi
deleted file mode 100644
index 8ebc1c967a6109012d3239173317972792453151..0000000000000000000000000000000000000000
--- a/conf/machine/cubemx/t1000-som-minimal/DeviceTree/t1000-som-minimal/u-boot/stm32mp157c-t1000-som-minimal-mx-u-boot.dtsi
+++ /dev/null
@@ -1,188 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause*/
-/*
- * Copyright (C) 2019, STMicroelectronics - All Rights Reserved
- * Author: STM32CubeMX code generation for STMicroelectronics.
- */
-
-#include <dt-bindings/clock/stm32mp1-clksrc.h>
-#include "stm32mp15-mx.h"
-
-#include "stm32mp157-u-boot.dtsi"
-#include "stm32mp15-ddr.dtsi"
-
-/* USER CODE BEGIN includes */
-/* USER CODE END includes */
-
-/ {
-
-	/* USER CODE BEGIN root */
-	/* USER CODE END root */
-
-	clocks {
-		/* USER CODE BEGIN clocks */
-		/* USER CODE END clocks */
-
-		clk_hsi: clk-hsi {
-			/* USER CODE BEGIN clocks */
-			/* USER CODE END clocks */
-			u-boot,dm-pre-reloc;
-		};
-
-		clk_csi: clk-csi {
-			/* USER CODE BEGIN clocks */
-			/* USER CODE END clocks */
-			u-boot,dm-pre-reloc;
-		};
-
-		clk_lse: clk-lse {
-			/* USER CODE BEGIN clocks */
-			/* USER CODE END clocks */
-			st,drive=<LSEDRV_MEDIUM_HIGH>;
-			u-boot,dm-pre-reloc;
-		};
-
-		clk_hse: clk-hse {
-			/* USER CODE BEGIN clocks */
-			/* USER CODE END clocks */
-			u-boot,dm-pre-reloc;
-		};
-	};
-
-}; /*root*/
-
-&rcc {
-	u-boot,dm-pre-reloc;
-	st,clksrc = <
-		CLK_MPU_PLL1P
-		CLK_AXI_PLL2P
-		CLK_MCU_PLL3P
-		CLK_PLL12_HSE
-		CLK_PLL3_HSE
-		CLK_PLL4_HSE
-		CLK_RTC_LSE
-		CLK_MCO1_DISABLED
-		CLK_MCO2_DISABLED
-	>;
-	st,clkdiv = <
-		1 		/*MPU*/
-		0 		/*AXI*/
-		0 		/*MCU*/
-		1 		/*APB1*/
-		1 		/*APB2*/
-		1 		/*APB3*/
-		1 		/*APB4*/
-		2 		/*APB5*/
-		0 		/*RTC*/
-		0 		/*MCO1*/
-		0 		/*MCO2*/
-	>;
-	st,pkcs = <
-		CLK_CKPER_HSE
-		CLK_QSPI_ACLK
-		CLK_ETH_PLL4P
-		CLK_SDMMC12_PLL4P
-		CLK_STGEN_HSE
-		CLK_USBPHY_HSE
-		CLK_SPI2S1_DISABLED
-		CLK_SPI2S23_DISABLED
-		CLK_SPI45_DISABLED
-		CLK_SPI6_DISABLED
-		CLK_I2C46_DISABLED
-		CLK_SDMMC3_DISABLED
-		CLK_USBO_USBPHY
-		CLK_ADC_CKPER
-		CLK_CEC_DISABLED
-		CLK_I2C12_HSI
-		CLK_I2C35_DISABLED
-		CLK_UART1_DISABLED
-		CLK_UART24_PCLK1
-		CLK_UART35_DISABLED
-		CLK_UART6_DISABLED
-		CLK_UART78_DISABLED
-		CLK_SPDIF_DISABLED
-		CLK_SAI1_DISABLED
-		CLK_SAI2_DISABLED
-		CLK_SAI3_DISABLED
-		CLK_SAI4_DISABLED
-		CLK_RNG1_CSI
-		CLK_LPTIM1_DISABLED
-		CLK_LPTIM23_DISABLED
-		CLK_LPTIM45_DISABLED
-	>;
-	pll1:st,pll@0 {
-		cfg = < 2 80 0 1 1 1>;
-		u-boot,dm-pre-reloc;
-	};
-	pll2:st,pll@1 {
-		cfg = < 2 65 1 1 0 7>;
-		u-boot,dm-pre-reloc;
-	};
-	pll3:st,pll@2 {
-		cfg = < 1 49 2 2 1 1>;
-		u-boot,dm-pre-reloc;
-	};
-	pll4:st,pll@3 {
-		cfg = < 5 124 9 9 9 1>;
-		u-boot,dm-pre-reloc;
-	};
-};
-
-&qspi{
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN qspi */
-	/* USER CODE END qspi */
-};
-
-&rcc{
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN rcc */
-	/* USER CODE END rcc */
-};
-
-&sdmmc1{
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN sdmmc1 */
-	/* USER CODE END sdmmc1 */
-};
-
-&uart4{
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN uart4 */
-	/* USER CODE END uart4 */
-};
-
-&usbotg_hs{
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN usbotg_hs */
-	/* USER CODE END usbotg_hs */
-};
-
-&usbphyc{
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN usbphyc */
-	/* USER CODE END usbphyc */
-};
-
-&usbphyc_port0{
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN usbphyc_port0 */
-	/* USER CODE END usbphyc_port0 */
-};
-
-&usbphyc_port1{
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN usbphyc_port1 */
-	/* USER CODE END usbphyc_port1 */
-};
-
-/* USER CODE BEGIN addons */
-/* USER CODE END addons */
-
diff --git a/conf/machine/cubemx/t1000-som-minimal/DeviceTree/t1000-som-minimal/u-boot/stm32mp157c-t1000-som-minimal-mx.dts b/conf/machine/cubemx/t1000-som-minimal/DeviceTree/t1000-som-minimal/u-boot/stm32mp157c-t1000-som-minimal-mx.dts
deleted file mode 100644
index 016425c712e15ca3a2f98af2a2e28aff7f8fa46a..0000000000000000000000000000000000000000
--- a/conf/machine/cubemx/t1000-som-minimal/DeviceTree/t1000-som-minimal/u-boot/stm32mp157c-t1000-som-minimal-mx.dts
+++ /dev/null
@@ -1,518 +0,0 @@
-/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
-/*
- * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
- * Author: STM32CubeMX code generation for STMicroelectronics.
- */
-
-/dts-v1/;
-#include "stm32mp157c.dtsi"
-#include "stm32mp157c-m4-srm.dtsi"
-#include "stm32mp157cad-pinctrl.dtsi"
-
-/* USER CODE BEGIN includes */
-/* USER CODE END includes */
-
-/ {
-	model = "STMicroelectronics custom STM32CubeMX board";
-	compatible = "st,stm32mp157c-t1000-som-minimal-mx", "st,stm32mp157";
-
-	memory@c0000000 {
-		reg = <0xc0000000 0x20000000>;
-
-		/* USER CODE BEGIN memory */
-		/* USER CODE END memory */
-	};
-
-	reserved-memory {
-		#address-cells = <1>;
-		#size-cells = <1>;
-		ranges;
-
-		/* USER CODE BEGIN reserved-memory */
-		/* USER CODE END reserved-memory */
-
-		gpu_reserved: gpu@dc000000 {
-			reg = <0xdc000000 0x4000000>;
-			no-map;
-		};
-	};
-
-	/* USER CODE BEGIN root */
-	/* USER CODE END root */
-
-	clocks {
-		/* USER CODE BEGIN clocks */
-		/* USER CODE END clocks */
-
-		clk_hsi: clk-hsi {
-			clock-frequency = <64000000>;
-		};
-
-		clk_csi: clk-csi {
-			clock-frequency = <4000000>;
-		};
-
-		clk_lse: clk-lse {
-			clock-frequency = <32768>;
-		};
-
-		clk_hse: clk-hse {
-			clock-frequency = <24000000>;
-		};
-	};
-
-}; /*root*/
-
-&pinctrl {
-	u-boot,dm-pre-reloc;
-
-	eth1_pins_mx: eth1_mx-0 {
-		pins1 {
-			pinmux = <STM32_PINMUX('A', 2, AF11)>; /* ETH1_MDIO */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-		pins2 {
-			pinmux = <STM32_PINMUX('A', 7, AF11)>, /* ETH1_CRS_DV */
-					 <STM32_PINMUX('C', 4, AF11)>, /* ETH1_RXD0 */
-					 <STM32_PINMUX('C', 5, AF11)>; /* ETH1_RXD1 */
-			bias-disable;
-		};
-		pins3 {
-			pinmux = <STM32_PINMUX('B', 11, AF11)>; /* ETH1_TX_EN */
-		};
-		pins4 {
-			pinmux = <STM32_PINMUX('B', 12, AF11)>, /* ETH1_TXD0 */
-					 <STM32_PINMUX('B', 13, AF11)>, /* ETH1_TXD1 */
-					 <STM32_PINMUX('C', 1, AF11)>, /* ETH1_MDC */
-					 <STM32_PINMUX('G', 8, AF2)>; /* ETH1_CLK */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-	};
-
-	eth1_sleep_pins_mx: eth1_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 2, ANALOG)>, /* ETH1_MDIO */
-					 <STM32_PINMUX('A', 7, ANALOG)>, /* ETH1_CRS_DV */
-					 <STM32_PINMUX('B', 11, ANALOG)>, /* ETH1_TX_EN */
-					 <STM32_PINMUX('B', 12, ANALOG)>, /* ETH1_TXD0 */
-					 <STM32_PINMUX('B', 13, ANALOG)>, /* ETH1_TXD1 */
-					 <STM32_PINMUX('C', 1, ANALOG)>, /* ETH1_MDC */
-					 <STM32_PINMUX('C', 4, ANALOG)>, /* ETH1_RXD0 */
-					 <STM32_PINMUX('C', 5, ANALOG)>, /* ETH1_RXD1 */
-					 <STM32_PINMUX('G', 8, ANALOG)>; /* ETH1_CLK */
-		};
-	};
-
-	i2c2_pins_mx: i2c2_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('D', 7, AF4)>, /* I2C2_SCL */
-					 <STM32_PINMUX('G', 15, AF4)>; /* I2C2_SDA */
-			bias-disable;
-			drive-open-drain;
-			slew-rate = <0>;
-		};
-	};
-
-	i2c2_sleep_pins_mx: i2c2_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('D', 7, ANALOG)>, /* I2C2_SCL */
-					 <STM32_PINMUX('G', 15, ANALOG)>; /* I2C2_SDA */
-		};
-	};
-
-	quadspi_pins_mx: quadspi_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 6, AF10)>, /* QUADSPI_BK1_NCS */
-					 <STM32_PINMUX('C', 0, AF10)>; /* QUADSPI_BK2_NCS */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('E', 7, AF10)>, /* QUADSPI_BK2_IO0 */
-					 <STM32_PINMUX('E', 8, AF10)>, /* QUADSPI_BK2_IO1 */
-					 <STM32_PINMUX('E', 9, AF10)>, /* QUADSPI_BK2_IO2 */
-					 <STM32_PINMUX('E', 10, AF10)>, /* QUADSPI_BK2_IO3 */
-					 <STM32_PINMUX('F', 6, AF9)>, /* QUADSPI_BK1_IO3 */
-					 <STM32_PINMUX('F', 7, AF9)>, /* QUADSPI_BK1_IO2 */
-					 <STM32_PINMUX('F', 8, AF10)>, /* QUADSPI_BK1_IO0 */
-					 <STM32_PINMUX('F', 9, AF10)>; /* QUADSPI_BK1_IO1 */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins3 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('F', 10, AF9)>; /* QUADSPI_CLK */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <2>;
-		};
-	};
-
-	quadspi_sleep_pins_mx: quadspi_sleep_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 6, ANALOG)>, /* QUADSPI_BK1_NCS */
-					 <STM32_PINMUX('C', 0, ANALOG)>, /* QUADSPI_BK2_NCS */
-					 <STM32_PINMUX('E', 7, ANALOG)>, /* QUADSPI_BK2_IO0 */
-					 <STM32_PINMUX('E', 8, ANALOG)>, /* QUADSPI_BK2_IO1 */
-					 <STM32_PINMUX('E', 9, ANALOG)>, /* QUADSPI_BK2_IO2 */
-					 <STM32_PINMUX('E', 10, ANALOG)>, /* QUADSPI_BK2_IO3 */
-					 <STM32_PINMUX('F', 6, ANALOG)>, /* QUADSPI_BK1_IO3 */
-					 <STM32_PINMUX('F', 7, ANALOG)>, /* QUADSPI_BK1_IO2 */
-					 <STM32_PINMUX('F', 8, ANALOG)>, /* QUADSPI_BK1_IO0 */
-					 <STM32_PINMUX('F', 9, ANALOG)>, /* QUADSPI_BK1_IO1 */
-					 <STM32_PINMUX('F', 10, ANALOG)>; /* QUADSPI_CLK */
-		};
-	};
-
-	rtc_pins_mx: rtc_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('C', 13, ANALOG)>; /* RTC_LSCO */
-		};
-	};
-
-	rtc_sleep_pins_mx: rtc_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('C', 13, ANALOG)>; /* RTC_LSCO */
-		};
-	};
-
-	sdmmc1_pins_mx: sdmmc1_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
-					 <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
-					 <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
-					 <STM32_PINMUX('C', 11, AF12)>, /* SDMMC1_D3 */
-					 <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 12, AF12)>; /* SDMMC1_CK */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-	};
-
-	sdmmc1_opendrain_pins_mx: sdmmc1_opendrain_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
-					 <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
-					 <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
-					 <STM32_PINMUX('C', 11, AF12)>; /* SDMMC1_D3 */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 12, AF12)>; /* SDMMC1_CK */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins3 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
-			bias-pull-up;
-			drive-open-drain;
-			slew-rate = <1>;
-		};
-	};
-
-	sdmmc1_sleep_pins_mx: sdmmc1_sleep_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 8, ANALOG)>, /* SDMMC1_D0 */
-					 <STM32_PINMUX('C', 9, ANALOG)>, /* SDMMC1_D1 */
-					 <STM32_PINMUX('C', 10, ANALOG)>, /* SDMMC1_D2 */
-					 <STM32_PINMUX('C', 11, ANALOG)>, /* SDMMC1_D3 */
-					 <STM32_PINMUX('C', 12, ANALOG)>, /* SDMMC1_CK */
-					 <STM32_PINMUX('D', 2, ANALOG)>; /* SDMMC1_CMD */
-		};
-	};
-
-	uart4_pins_mx: uart4_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 2, AF8)>; /* UART4_RX */
-			bias-pull-up;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('G', 11, AF6)>; /* UART4_TX */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-	};
-
-	uart4_sleep_pins_mx: uart4_sleep_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 2, ANALOG)>, /* UART4_RX */
-					 <STM32_PINMUX('G', 11, ANALOG)>; /* UART4_TX */
-		};
-	};
-
-	usb_otg_hs_pins_mx: usb_otg_hs_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
-		};
-	};
-
-	usb_otg_hs_sleep_pins_mx: usb_otg_hs_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
-		};
-	};
-
-	/* USER CODE BEGIN pinctrl */
-	/* USER CODE END pinctrl */
-};
-
-&pinctrl_z {
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN pinctrl_z */
-	/* USER CODE END pinctrl_z */
-};
-
-&m4_rproc{
-	mboxes = <&ipcc 0>, <&ipcc 1>, <&ipcc 2>;
-	mbox-names = "vq0", "vq1", "shutdown";
-	recovery;
-	status = "okay";
-
-	/* USER CODE BEGIN m4_rproc */
-	/* USER CODE END m4_rproc */
-};
-
-&adc{
-	status = "okay";
-
-	/* USER CODE BEGIN adc */
-	/* USER CODE END adc */
-};
-
-&bsec{
-	status = "okay";
-
-	/* USER CODE BEGIN bsec */
-	/* USER CODE END bsec */
-};
-
-&crc1{
-	status = "okay";
-
-	/* USER CODE BEGIN crc1 */
-	/* USER CODE END crc1 */
-};
-
-&cryp1{
-	status = "okay";
-
-	/* USER CODE BEGIN cryp1 */
-	/* USER CODE END cryp1 */
-};
-
-&dts{
-	status = "okay";
-
-	/* USER CODE BEGIN dts */
-	/* USER CODE END dts */
-};
-
-&ethernet0{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&eth1_pins_mx>;
-	pinctrl-1 = <&eth1_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN ethernet0 */
-	/* USER CODE END ethernet0 */
-};
-
-&gpu{
-	status = "okay";
-
-	/* USER CODE BEGIN gpu */
-	/* USER CODE END gpu */
-};
-
-&hash1{
-	status = "okay";
-
-	/* USER CODE BEGIN hash1 */
-	/* USER CODE END hash1 */
-};
-
-&hsem{
-	status = "okay";
-
-	/* USER CODE BEGIN hsem */
-	/* USER CODE END hsem */
-};
-
-&i2c2{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&i2c2_pins_mx>;
-	pinctrl-1 = <&i2c2_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN i2c2 */
-	/* USER CODE END i2c2 */
-};
-
-&ipcc{
-	status = "okay";
-
-	/* USER CODE BEGIN ipcc */
-	/* USER CODE END ipcc */
-};
-
-&iwdg2{
-	status = "okay";
-
-	/* USER CODE BEGIN iwdg2 */
-	/* USER CODE END iwdg2 */
-};
-
-&qspi{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&quadspi_pins_mx>;
-	pinctrl-1 = <&quadspi_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN qspi */
-	/* USER CODE END qspi */
-};
-
-&rcc{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN rcc */
-	/* USER CODE END rcc */
-};
-
-&rng1{
-	status = "okay";
-
-	/* USER CODE BEGIN rng1 */
-	/* USER CODE END rng1 */
-};
-
-&rtc{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&rtc_pins_mx>;
-	pinctrl-1 = <&rtc_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN rtc */
-	/* USER CODE END rtc */
-};
-
-&sdmmc1{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "opendrain", "sleep";
-	pinctrl-0 = <&sdmmc1_pins_mx>;
-	pinctrl-1 = <&sdmmc1_opendrain_pins_mx>;
-	pinctrl-2 = <&sdmmc1_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN sdmmc1 */
-	/* USER CODE END sdmmc1 */
-};
-
-&uart4{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&uart4_pins_mx>;
-	pinctrl-1 = <&uart4_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN uart4 */
-	/* USER CODE END uart4 */
-};
-
-&usbh_ehci{
-	status = "okay";
-
-	/* USER CODE BEGIN usbh_ehci */
-	/* USER CODE END usbh_ehci */
-};
-
-&usbh_ohci{
-	status = "okay";
-
-	/* USER CODE BEGIN usbh_ohci */
-	/* USER CODE END usbh_ohci */
-};
-
-&usbotg_hs{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&usb_otg_hs_pins_mx>;
-	pinctrl-1 = <&usb_otg_hs_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN usbotg_hs */
-	/* USER CODE END usbotg_hs */
-};
-
-&usbphyc{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc */
-	/* USER CODE END usbphyc */
-};
-
-&usbphyc_port0{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc_port0 */
-	/* USER CODE END usbphyc_port0 */
-};
-
-&usbphyc_port1{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc_port1 */
-	/* USER CODE END usbphyc_port1 */
-};
-
-&vrefbuf{
-	status = "okay";
-
-	/* USER CODE BEGIN vrefbuf */
-	/* USER CODE END vrefbuf */
-};
-
-/* USER CODE BEGIN addons */
-/* USER CODE END addons */
-
diff --git a/conf/machine/cubemx/t1000-som-minimal/t1000-som-minimal.ioc b/conf/machine/cubemx/t1000-som-minimal/t1000-som-minimal.ioc
deleted file mode 100644
index e64718a1ec0a72068409ea41c1d420100550482e..0000000000000000000000000000000000000000
--- a/conf/machine/cubemx/t1000-som-minimal/t1000-som-minimal.ioc
+++ /dev/null
@@ -1,1085 +0,0 @@
-#MicroXplorer Configuration settings - do not modify
-ADC2.Channel-0\#ChannelRegularConversion=ADC_CHANNEL_VBAT
-ADC2.IPParameters=Rank-0\#ChannelRegularConversion,Channel-0\#ChannelRegularConversion,SamplingTime-0\#ChannelRegularConversion,OffsetNumber-0\#ChannelRegularConversion,NbrOfConversionFlag
-ADC2.NbrOfConversionFlag=1
-ADC2.OffsetNumber-0\#ChannelRegularConversion=ADC_OFFSET_NONE
-ADC2.Rank-0\#ChannelRegularConversion=1
-ADC2.SamplingTime-0\#ChannelRegularConversion=ADC_SAMPLETIME_1CYCLE_5
-BootLoader.IPs=RCC,QUADSPI,SDMMC1,UART4,USB_OTG_HS
-BootROM.IPs=RCC,SDMMC1\:I,UART4\:I
-CortexA7NS.IPs=IWDG2\:I,BSEC,DDR\:I,ETZPC,HSEM\:I,IPCC\:I,PWR,RCC\:I,RTC,TAMP\:I,DMA\:I,GIC,ADC1\:I,ADC2\:I,ETH1\:I,I2C2\:I,QUADSPI\:I,SDMMC1,UART4,USBH_HS1\:I,USB_OTG_HS\:I,GPU\:I,CRYP1\:I,HASH1\:I,RNG1,CRC1\:I,DEBUG\:I,DTS\:I,VREFBUF\:I,I2S1\:I,SPI1\:I,DMA1\:I,MDMA_A7NS\:I
-CortexA7S.IPs=BSEC\:I,ETZPC\:I,PWR\:I,RCC,RNG1\:I,RTC\:I,GIC\:I,IWDG2,MDMA_A7S\:I
-CortexM4.IPs=HSEM,IPCC,ETZPC,FREERTOS\:I,PWR,RCC,SYS\:I,DMA,NVIC\:I,DMA2\:I
-DDR.0dqdly0=1
-DDR.0dqdly1=0
-DDR.0dqdly2=0
-DDR.0dqdly3=0
-DDR.0dqdly4=1
-DDR.0dqdly5=0
-DDR.0dqdly6=1
-DDR.0dqdly7=1
-DDR.0dqsdly=2
-DDR.0dqsndly=2
-DDR.1dqdly0=0
-DDR.1dqdly1=0
-DDR.1dqdly2=1
-DDR.1dqdly3=0
-DDR.1dqdly4=1
-DDR.1dqdly5=0
-DDR.1dqdly6=0
-DDR.1dqdly7=0
-DDR.ADDRMAP1=0x00070707
-DDR.ADDRMAP3=0x1F000000
-DDR.ADDRMAP5=0x06060606
-DDR.ADDRMAP6=0x0F060606
-DDR.CL=7
-DDR.DDR_Frequency=528.0
-DDR.DFITMG0=0x02050105
-DDR.DRAMTMG0=0x121B1214
-DDR.DRAMTMG1=0x000A041B
-DDR.DRAMTMG2=0x0607080F
-DDR.DRAMTMG4=0x07040607
-DDR.DTPR0=0x36D477D0
-DDR.DTPR1=0x098A00D8
-DDR.DX0DQSTR=0x3D202000
-DDR.DX0DQTR=0x55050005
-DDR.DX1DQTR=0x00050500
-DDR.IPParameters=DDR_Frequency,CL,addrmap_col_b9,addrmap_col_b10,addrmap_col_b11,addrmap_bank_b0,addrmap_bank_b1,addrmap_bank_b2,addrmap_row_b0,addrmap_row_b1,addrmap_row_b2_10,addrmap_row_b11,addrmap_row_b12,addrmap_row_b13,addrmap_row_b14,addrmap_row_b15,MSTR,RFSHTMG,DRAMTMG1,DRAMTMG2,DRAMTMG4,SCHED,ADDRMAP1,ADDRMAP3,ADDRMAP5,ADDRMAP6,PTR0,PTR1,PTR2,DTPR0,DTPR1,MR0,SPEED_BIN_GRADE,tRCD,tRP,tRC,wr2pre,t_faw,t_ras_max,t_ras_min,t_xp,t_rd2pre,t_rp,t_rc,write_latency,read_latency,wr2rd,t_rcd,t_rrd,t_cksrx,t_cksre,t_ckesr,t_cke,t_xs_dll_x32,t_xs_x32,t_rfc_nom_x1_x32,t_rfc_min,dfi_t_rddata_en,dfi_tphy_wrlat,tdlllock,tdllsrst,tdinit1,tdinit0,tdinit2,tccd,trc,trrd,tras,trcd,trp,twtr,trtp,tmrd,trfc,tmod,tfaw,tdllk,tcke,txp,txs,MR0.WR,MR0.CL,MR2.RTT,MR2.CWL,data_bus_width,DFITMG0,TEMPERATURE_OVER_85C,tREFI,DRAMTMG0,MR2,0dqsndly,0dqsdly,0dqdly0,0dqdly1,0dqdly2,0dqdly3,0dqdly4,0dqdly5,0dqdly6,0dqdly7,1dqdly0,1dqdly1,1dqdly2,1dqdly3,1dqdly4,1dqdly5,1dqdly6,1dqdly7,DX0DQTR,DX0DQSTR,DX1DQTR
-DDR.MR0=0x00000830
-DDR.MR0.CL=3
-DDR.MR0.WR=4
-DDR.MR2=0x00000248
-DDR.MR2.CWL=1
-DDR.MR2.RTT=1
-DDR.MSTR=0x00041401
-DDR.PTR0=0x0022A41B
-DDR.PTR1=0x047C0740
-DDR.PTR2=0x042D9C80
-DDR.RFSHTMG=0x0040008A
-DDR.SCHED=0x00000C01
-DDR.SPEED_BIN_GRADE=SPEED BIN GRADE CONFIG1
-DDR.TEMPERATURE_OVER_85C=true
-DDR.addrmap_bank_b0=7
-DDR.addrmap_bank_b1=7
-DDR.addrmap_bank_b2=7
-DDR.addrmap_col_b10=31
-DDR.addrmap_col_b11=31
-DDR.addrmap_col_b9=31
-DDR.addrmap_row_b0=6
-DDR.addrmap_row_b1=6
-DDR.addrmap_row_b11=6
-DDR.addrmap_row_b12=6
-DDR.addrmap_row_b13=6
-DDR.addrmap_row_b14=6
-DDR.addrmap_row_b15=15
-DDR.addrmap_row_b2_10=6
-DDR.data_bus_width=1
-DDR.dfi_t_rddata_en=5
-DDR.dfi_tphy_wrlat=5
-DDR.read_latency=7
-DDR.tRC=50.625
-DDR.tRCD=13.125
-DDR.tREFI=3.9
-DDR.tRP=13.125
-DDR.t_cke=3
-DDR.t_ckesr=4
-DDR.t_cksre=6
-DDR.t_cksrx=6
-DDR.t_faw=27
-DDR.t_ras_max=18
-DDR.t_ras_min=20
-DDR.t_rc=27
-DDR.t_rcd=7
-DDR.t_rd2pre=4
-DDR.t_rfc_min=138
-DDR.t_rfc_nom_x1_x32=64
-DDR.t_rp=7
-DDR.t_rrd=6
-DDR.t_xp=10
-DDR.t_xs_dll_x32=16
-DDR.t_xs_x32=5
-DDR.tccd=0
-DDR.tcke=4
-DDR.tdinit0=264000
-DDR.tdinit1=143
-DDR.tdinit2=105600
-DDR.tdllk=512
-DDR.tdlllock=2704
-DDR.tdllsrst=27
-DDR.tfaw=27
-DDR.tmod=0
-DDR.tmrd=0
-DDR.tras=20
-DDR.trc=27
-DDR.trcd=7
-DDR.trfc=138
-DDR.trp=7
-DDR.trrd=6
-DDR.trtp=4
-DDR.twtr=6
-DDR.txp=13
-DDR.txs=512
-DDR.wr2pre=18
-DDR.wr2rd=15
-DDR.write_latency=6
-DDR_A0.GPIOParameters=GPIO_Label
-DDR_A0.GPIO_Label=DDR Memory
-DDR_A0.Locked=true
-DDR_A0.Mode=DDR3
-DDR_A0.Signal=DDR_A0
-DDR_A1.GPIOParameters=GPIO_Label
-DDR_A1.GPIO_Label=DDR Memory
-DDR_A1.Locked=true
-DDR_A1.Mode=DDR3
-DDR_A1.Signal=DDR_A1
-DDR_A10.GPIOParameters=GPIO_Label
-DDR_A10.GPIO_Label=DDR Memory
-DDR_A10.Locked=true
-DDR_A10.Mode=DDR3
-DDR_A10.Signal=DDR_A10
-DDR_A11.GPIOParameters=GPIO_Label
-DDR_A11.GPIO_Label=DDR Memory
-DDR_A11.Locked=true
-DDR_A11.Mode=DDR3
-DDR_A11.Signal=DDR_A11
-DDR_A12.GPIOParameters=GPIO_Label
-DDR_A12.GPIO_Label=DDR Memory
-DDR_A12.Locked=true
-DDR_A12.Mode=4Gb_16bits
-DDR_A12.Signal=DDR_A12
-DDR_A13.GPIOParameters=GPIO_Label
-DDR_A13.GPIO_Label=DDR Memory
-DDR_A13.Locked=true
-DDR_A13.Mode=4Gb_16bits
-DDR_A13.Signal=DDR_A13
-DDR_A14.GPIOParameters=GPIO_Label
-DDR_A14.GPIO_Label=DDR Memory
-DDR_A14.Locked=true
-DDR_A14.Mode=4Gb_16bits
-DDR_A14.Signal=DDR_A14
-DDR_A2.GPIOParameters=GPIO_Label
-DDR_A2.GPIO_Label=DDR Memory
-DDR_A2.Locked=true
-DDR_A2.Mode=DDR3
-DDR_A2.Signal=DDR_A2
-DDR_A3.GPIOParameters=GPIO_Label
-DDR_A3.GPIO_Label=DDR Memory
-DDR_A3.Locked=true
-DDR_A3.Mode=DDR3
-DDR_A3.Signal=DDR_A3
-DDR_A4.GPIOParameters=GPIO_Label
-DDR_A4.GPIO_Label=DDR Memory
-DDR_A4.Locked=true
-DDR_A4.Mode=DDR3
-DDR_A4.Signal=DDR_A4
-DDR_A5.GPIOParameters=GPIO_Label
-DDR_A5.GPIO_Label=DDR Memory
-DDR_A5.Locked=true
-DDR_A5.Mode=DDR3
-DDR_A5.Signal=DDR_A5
-DDR_A6.GPIOParameters=GPIO_Label
-DDR_A6.GPIO_Label=DDR Memory
-DDR_A6.Locked=true
-DDR_A6.Mode=DDR3
-DDR_A6.Signal=DDR_A6
-DDR_A7.GPIOParameters=GPIO_Label
-DDR_A7.GPIO_Label=DDR Memory
-DDR_A7.Locked=true
-DDR_A7.Mode=DDR3
-DDR_A7.Signal=DDR_A7
-DDR_A8.GPIOParameters=GPIO_Label
-DDR_A8.GPIO_Label=DDR Memory
-DDR_A8.Locked=true
-DDR_A8.Mode=DDR3
-DDR_A8.Signal=DDR_A8
-DDR_A9.GPIOParameters=GPIO_Label
-DDR_A9.GPIO_Label=DDR Memory
-DDR_A9.Locked=true
-DDR_A9.Mode=DDR3
-DDR_A9.Signal=DDR_A9
-DDR_ATO.GPIOParameters=GPIO_Label
-DDR_ATO.GPIO_Label=DDR Memory
-DDR_ATO.Locked=true
-DDR_ATO.Mode=DDR3
-DDR_ATO.Signal=DDR_ATO
-DDR_BA0.GPIOParameters=GPIO_Label
-DDR_BA0.GPIO_Label=DDR Memory
-DDR_BA0.Locked=true
-DDR_BA0.Mode=DDR3
-DDR_BA0.Signal=DDR_BA0
-DDR_BA1.GPIOParameters=GPIO_Label
-DDR_BA1.GPIO_Label=DDR Memory
-DDR_BA1.Locked=true
-DDR_BA1.Mode=DDR3
-DDR_BA1.Signal=DDR_BA1
-DDR_BA2.GPIOParameters=GPIO_Label
-DDR_BA2.GPIO_Label=DDR Memory
-DDR_BA2.Locked=true
-DDR_BA2.Mode=DDR3
-DDR_BA2.Signal=DDR_BA2
-DDR_CASN.GPIOParameters=GPIO_Label
-DDR_CASN.GPIO_Label=DDR Memory
-DDR_CASN.Locked=true
-DDR_CASN.Mode=DDR3
-DDR_CASN.Signal=DDR_CASN
-DDR_CKE.GPIOParameters=GPIO_Label
-DDR_CKE.GPIO_Label=DDR Memory
-DDR_CKE.Locked=true
-DDR_CKE.Mode=DDR3
-DDR_CKE.Signal=DDR_CKE
-DDR_CLKN.GPIOParameters=GPIO_Label
-DDR_CLKN.GPIO_Label=DDR Memory
-DDR_CLKN.Locked=true
-DDR_CLKN.Mode=DDR3
-DDR_CLKN.Signal=DDR_CLKN
-DDR_CLKP.GPIOParameters=GPIO_Label
-DDR_CLKP.GPIO_Label=DDR Memory
-DDR_CLKP.Locked=true
-DDR_CLKP.Mode=DDR3
-DDR_CLKP.Signal=DDR_CLKP
-DDR_CSN.GPIOParameters=GPIO_Label
-DDR_CSN.GPIO_Label=DDR Memory
-DDR_CSN.Locked=true
-DDR_CSN.Mode=DDR3
-DDR_CSN.Signal=DDR_CSN
-DDR_DQ0.GPIOParameters=GPIO_Label
-DDR_DQ0.GPIO_Label=DDR Memory
-DDR_DQ0.Locked=true
-DDR_DQ0.Mode=DDR3
-DDR_DQ0.Signal=DDR_DQ0
-DDR_DQ1.GPIOParameters=GPIO_Label
-DDR_DQ1.GPIO_Label=DDR Memory
-DDR_DQ1.Locked=true
-DDR_DQ1.Mode=DDR3
-DDR_DQ1.Signal=DDR_DQ1
-DDR_DQ10.GPIOParameters=GPIO_Label
-DDR_DQ10.GPIO_Label=DDR Memory
-DDR_DQ10.Locked=true
-DDR_DQ10.Mode=DDR3
-DDR_DQ10.Signal=DDR_DQ10
-DDR_DQ11.GPIOParameters=GPIO_Label
-DDR_DQ11.GPIO_Label=DDR Memory
-DDR_DQ11.Locked=true
-DDR_DQ11.Mode=DDR3
-DDR_DQ11.Signal=DDR_DQ11
-DDR_DQ12.GPIOParameters=GPIO_Label
-DDR_DQ12.GPIO_Label=DDR Memory
-DDR_DQ12.Locked=true
-DDR_DQ12.Mode=DDR3
-DDR_DQ12.Signal=DDR_DQ12
-DDR_DQ13.GPIOParameters=GPIO_Label
-DDR_DQ13.GPIO_Label=DDR Memory
-DDR_DQ13.Locked=true
-DDR_DQ13.Mode=DDR3
-DDR_DQ13.Signal=DDR_DQ13
-DDR_DQ14.GPIOParameters=GPIO_Label
-DDR_DQ14.GPIO_Label=DDR Memory
-DDR_DQ14.Locked=true
-DDR_DQ14.Mode=DDR3
-DDR_DQ14.Signal=DDR_DQ14
-DDR_DQ15.GPIOParameters=GPIO_Label
-DDR_DQ15.GPIO_Label=DDR Memory
-DDR_DQ15.Locked=true
-DDR_DQ15.Mode=DDR3
-DDR_DQ15.Signal=DDR_DQ15
-DDR_DQ2.GPIOParameters=GPIO_Label
-DDR_DQ2.GPIO_Label=DDR Memory
-DDR_DQ2.Locked=true
-DDR_DQ2.Mode=DDR3
-DDR_DQ2.Signal=DDR_DQ2
-DDR_DQ3.GPIOParameters=GPIO_Label
-DDR_DQ3.GPIO_Label=DDR Memory
-DDR_DQ3.Locked=true
-DDR_DQ3.Mode=DDR3
-DDR_DQ3.Signal=DDR_DQ3
-DDR_DQ4.GPIOParameters=GPIO_Label
-DDR_DQ4.GPIO_Label=DDR Memory
-DDR_DQ4.Locked=true
-DDR_DQ4.Mode=DDR3
-DDR_DQ4.Signal=DDR_DQ4
-DDR_DQ5.GPIOParameters=GPIO_Label
-DDR_DQ5.GPIO_Label=DDR Memory
-DDR_DQ5.Locked=true
-DDR_DQ5.Mode=DDR3
-DDR_DQ5.Signal=DDR_DQ5
-DDR_DQ6.GPIOParameters=GPIO_Label
-DDR_DQ6.GPIO_Label=DDR Memory
-DDR_DQ6.Locked=true
-DDR_DQ6.Mode=DDR3
-DDR_DQ6.Signal=DDR_DQ6
-DDR_DQ7.GPIOParameters=GPIO_Label
-DDR_DQ7.GPIO_Label=DDR Memory
-DDR_DQ7.Locked=true
-DDR_DQ7.Mode=DDR3
-DDR_DQ7.Signal=DDR_DQ7
-DDR_DQ8.GPIOParameters=GPIO_Label
-DDR_DQ8.GPIO_Label=DDR Memory
-DDR_DQ8.Locked=true
-DDR_DQ8.Mode=DDR3
-DDR_DQ8.Signal=DDR_DQ8
-DDR_DQ9.GPIOParameters=GPIO_Label
-DDR_DQ9.GPIO_Label=DDR Memory
-DDR_DQ9.Locked=true
-DDR_DQ9.Mode=DDR3
-DDR_DQ9.Signal=DDR_DQ9
-DDR_DQM0.GPIOParameters=GPIO_Label
-DDR_DQM0.GPIO_Label=DDR Memory
-DDR_DQM0.Locked=true
-DDR_DQM0.Mode=DDR3
-DDR_DQM0.Signal=DDR_DQM0
-DDR_DQM1.GPIOParameters=GPIO_Label
-DDR_DQM1.GPIO_Label=DDR Memory
-DDR_DQM1.Locked=true
-DDR_DQM1.Mode=DDR3
-DDR_DQM1.Signal=DDR_DQM1
-DDR_DQS0N.GPIOParameters=GPIO_Label
-DDR_DQS0N.GPIO_Label=DDR Memory
-DDR_DQS0N.Locked=true
-DDR_DQS0N.Mode=DDR3
-DDR_DQS0N.Signal=DDR_DQS0N
-DDR_DQS0P.GPIOParameters=GPIO_Label
-DDR_DQS0P.GPIO_Label=DDR Memory
-DDR_DQS0P.Locked=true
-DDR_DQS0P.Mode=DDR3
-DDR_DQS0P.Signal=DDR_DQS0P
-DDR_DQS1N.GPIOParameters=GPIO_Label
-DDR_DQS1N.GPIO_Label=DDR Memory
-DDR_DQS1N.Locked=true
-DDR_DQS1N.Mode=DDR3
-DDR_DQS1N.Signal=DDR_DQS1N
-DDR_DQS1P.GPIOParameters=GPIO_Label
-DDR_DQS1P.GPIO_Label=DDR Memory
-DDR_DQS1P.Locked=true
-DDR_DQS1P.Mode=DDR3
-DDR_DQS1P.Signal=DDR_DQS1P
-DDR_DTO0.GPIOParameters=GPIO_Label
-DDR_DTO0.GPIO_Label=DDR Memory
-DDR_DTO0.Locked=true
-DDR_DTO0.Mode=DDR3
-DDR_DTO0.Signal=DDR_DTO0
-DDR_DTO1.GPIOParameters=GPIO_Label
-DDR_DTO1.GPIO_Label=DDR Memory
-DDR_DTO1.Locked=true
-DDR_DTO1.Mode=DDR3
-DDR_DTO1.Signal=DDR_DTO1
-DDR_ODT.GPIOParameters=GPIO_Label
-DDR_ODT.GPIO_Label=DDR Memory
-DDR_ODT.Locked=true
-DDR_ODT.Mode=DDR3
-DDR_ODT.Signal=DDR_ODT
-DDR_RASN.GPIOParameters=GPIO_Label
-DDR_RASN.GPIO_Label=DDR Memory
-DDR_RASN.Locked=true
-DDR_RASN.Mode=DDR3
-DDR_RASN.Signal=DDR_RASN
-DDR_RESETN.GPIOParameters=GPIO_Label
-DDR_RESETN.GPIO_Label=DDR Memory
-DDR_RESETN.Locked=true
-DDR_RESETN.Mode=DDR3
-DDR_RESETN.Signal=DDR_RESETN
-DDR_VREF.GPIOParameters=GPIO_Label
-DDR_VREF.GPIO_Label=DDR Memory
-DDR_VREF.Locked=true
-DDR_VREF.Mode=DDR3
-DDR_VREF.Signal=DDR_VREF
-DDR_WEN.GPIOParameters=GPIO_Label
-DDR_WEN.GPIO_Label=DDR Memory
-DDR_WEN.Locked=true
-DDR_WEN.Mode=DDR3
-DDR_WEN.Signal=DDR_WEN
-DDR_ZQ.GPIOParameters=GPIO_Label
-DDR_ZQ.GPIO_Label=DDR Memory
-DDR_ZQ.Locked=true
-DDR_ZQ.Mode=DDR3
-DDR_ZQ.Signal=DDR_ZQ
-File.Version=6
-GIC.ADC2_IRQn=true\:false\:High level
-GIC.CRYP1_IRQn=true\:false\:High level
-GIC.DTS_IRQn=true\:false\:High level
-GIC.ETH1_IRQn=true\:false\:High level
-GIC.ETH1_WKUP_IRQn=true\:false\:High level
-GIC.GPU_IRQn=true\:false\:High level
-GIC.HASH1_IRQn=true\:false\:High level
-GIC.I2C2_ER_IRQn=true\:false\:High level
-GIC.I2C2_EV_IRQn=true\:false\:High level
-GIC.IPCC_RX0_IRQn=true\:false\:High level
-GIC.IPCC_TX0_IRQn=true\:false\:High level
-GIC.OTG_IRQn=true\:false\:High level
-GIC.PMUIRQ0_IRQn=true\:false\:High level
-GIC.PMUIRQ1_IRQn=true\:false\:High level
-GIC.QUADSPI_IRQn=true\:false\:High level
-GIC.RCC_IRQn=true\:false\:High level
-GIC.RTC_WKUP_ALARM_IRQn=true\:false\:High level
-GIC.SDMMC1_IRQn=true\:false\:High level
-GIC.UART4_IRQn=true\:false\:High level
-GIC.USBH_OHCI_IRQn=true\:false\:High level
-JTCK-SWCLK.GPIOParameters=GPIO_Label
-JTCK-SWCLK.GPIO_Label=JTAG Debug
-JTCK-SWCLK.Locked=true
-JTCK-SWCLK.Mode=JTAG_4_pins
-JTCK-SWCLK.Signal=DEBUG_JTCK-SWCLK
-JTDI.GPIOParameters=GPIO_Label
-JTDI.GPIO_Label=JTAG Debug
-JTDI.Locked=true
-JTDI.Mode=JTAG_4_pins
-JTDI.Signal=DEBUG_JTDI
-JTDO-TRACESWO.GPIOParameters=GPIO_Label
-JTDO-TRACESWO.GPIO_Label=JTAG Debug
-JTDO-TRACESWO.Locked=true
-JTDO-TRACESWO.Mode=JTAG_4_pins
-JTDO-TRACESWO.Signal=DEBUG_JTDO-SWO
-JTMS-SWDIO.GPIOParameters=GPIO_Label
-JTMS-SWDIO.GPIO_Label=JTAG Debug
-JTMS-SWDIO.Locked=true
-JTMS-SWDIO.Mode=JTAG_4_pins
-JTMS-SWDIO.Signal=DEBUG_JTMS-SWDIO
-KeepUserPlacement=false
-Mcu.Context0=BootROM
-Mcu.Context1=BootLoader
-Mcu.Context2=CortexA7S
-Mcu.Context3=CortexA7NS
-Mcu.Context4=CortexM4
-Mcu.ContextNb=5
-Mcu.Family=STM32MP1
-Mcu.IP0=ADC2
-Mcu.IP1=BSEC
-Mcu.IP10=GPU
-Mcu.IP11=HASH1
-Mcu.IP12=HSEM
-Mcu.IP13=I2C2
-Mcu.IP14=IPCC
-Mcu.IP15=IWDG2
-Mcu.IP16=NVIC
-Mcu.IP17=QUADSPI
-Mcu.IP18=RCC
-Mcu.IP19=RNG1
-Mcu.IP2=CRC1
-Mcu.IP20=RTC
-Mcu.IP21=SDMMC1
-Mcu.IP22=SYS
-Mcu.IP23=UART4
-Mcu.IP24=USBH_HS1
-Mcu.IP25=USB_OTG_HS
-Mcu.IP26=VREFBUF
-Mcu.IP3=CRYP1
-Mcu.IP4=DDR
-Mcu.IP5=DEBUG
-Mcu.IP6=DTS
-Mcu.IP7=ETH1
-Mcu.IP8=ETZPC
-Mcu.IP9=GIC
-Mcu.IPNb=27
-Mcu.Name=STM32MP157CADx
-Mcu.Package=TFBGA257
-Mcu.Pin0=PC8
-Mcu.Pin1=JTDO-TRACESWO
-Mcu.Pin10=DDR_DQ3
-Mcu.Pin100=PF10
-Mcu.Pin101=VP_ADC2_TempSens_Input
-Mcu.Pin102=VP_ADC2_Vref_Input
-Mcu.Pin103=VP_ADC2_VddCore_Input
-Mcu.Pin104=VP_ADC2_Vbat_Input
-Mcu.Pin105=VP_BSEC_VS_BSEC
-Mcu.Pin106=VP_CRC1_VS_CRC
-Mcu.Pin107=VP_CRYP1_VS_CRYP
-Mcu.Pin108=VP_DDR_DDR3
-Mcu.Pin109=VP_DDR_DDR_16_bits
-Mcu.Pin11=DDR_DQ7
-Mcu.Pin110=VP_DDR_DDR3_16_4Gb
-Mcu.Pin111=VP_DTS_VS_DTS
-Mcu.Pin112=VP_ETZPC_VS_ETZPC
-Mcu.Pin113=VP_GPU_VS_GPU
-Mcu.Pin114=VP_HASH1_VS_HASH
-Mcu.Pin115=VP_HSEM_VS_HSEM
-Mcu.Pin116=VP_IPCC_VS_IPCC
-Mcu.Pin117=VP_IWDG2_VS_IWDG
-Mcu.Pin118=VP_RNG1_VS_RNG
-Mcu.Pin119=VP_RTC_VS_RTC_Activate
-Mcu.Pin12=DDR_DQS0N
-Mcu.Pin120=VP_SYS_VS_Systick
-Mcu.Pin121=VP_VREFBUF_VS_VREFBUF
-Mcu.Pin122=VP_DMA_VS_DMA1_A7NS
-Mcu.Pin123=VP_DMA_VS_DMA2_M4
-Mcu.Pin124=VP_MDMA_VS_MDMA_A7NS_8
-Mcu.Pin13=DDR_DQS0P
-Mcu.Pin14=PC11
-Mcu.Pin15=JTMS-SWDIO
-Mcu.Pin16=DDR_RESETN
-Mcu.Pin17=DDR_DQM0
-Mcu.Pin18=DDR_DQ2
-Mcu.Pin19=DDR_DQ6
-Mcu.Pin2=JTCK-SWCLK
-Mcu.Pin20=DDR_DQ4
-Mcu.Pin21=DDR_DQ5
-Mcu.Pin22=DDR_A13
-Mcu.Pin23=DDR_A9
-Mcu.Pin24=PC15-OSC32_OUT
-Mcu.Pin25=DDR_A2
-Mcu.Pin26=DDR_A3
-Mcu.Pin27=PC14-OSC32_IN
-Mcu.Pin28=PC13
-Mcu.Pin29=DDR_A0
-Mcu.Pin3=DDR_DQ0
-Mcu.Pin30=DDR_BA0
-Mcu.Pin31=PH0-OSC_IN
-Mcu.Pin32=DDR_BA2
-Mcu.Pin33=DDR_ODT
-Mcu.Pin34=PH1-OSC_OUT
-Mcu.Pin35=DDR_CSN
-Mcu.Pin36=DDR_WEN
-Mcu.Pin37=DDR_CASN
-Mcu.Pin38=DDR_CLKN
-Mcu.Pin39=PA13
-Mcu.Pin4=DDR_DQ1
-Mcu.Pin40=DDR_CLKP
-Mcu.Pin41=DDR_A10
-Mcu.Pin42=DDR_A12
-Mcu.Pin43=DDR_A1
-Mcu.Pin44=DDR_A14
-Mcu.Pin45=DDR_A11
-Mcu.Pin46=DDR_CKE
-Mcu.Pin47=DDR_BA1
-Mcu.Pin48=DDR_A4
-Mcu.Pin49=DDR_DQ8
-Mcu.Pin5=PG15
-Mcu.Pin50=PC1
-Mcu.Pin51=PA2
-Mcu.Pin52=DDR_A8
-Mcu.Pin53=DDR_DQ13
-Mcu.Pin54=DDR_DQ10
-Mcu.Pin55=PB11
-Mcu.Pin56=PC0
-Mcu.Pin57=PG11
-Mcu.Pin58=PF6
-Mcu.Pin59=PE8
-Mcu.Pin6=PD7
-Mcu.Pin60=PA10
-Mcu.Pin61=DDR_DQ14
-Mcu.Pin62=DDR_DQS1N
-Mcu.Pin63=DDR_DQ9
-Mcu.Pin64=PC5
-Mcu.Pin65=PC4
-Mcu.Pin66=PB12
-Mcu.Pin67=PG8
-Mcu.Pin68=PE7
-Mcu.Pin69=PF8
-Mcu.Pin7=PC9
-Mcu.Pin70=PF9
-Mcu.Pin71=USB_DP2
-Mcu.Pin72=PE10
-Mcu.Pin73=PB2
-Mcu.Pin74=USB_DP1
-Mcu.Pin75=OTG_VBUS
-Mcu.Pin76=DDR_DQ15
-Mcu.Pin77=DDR_DQM1
-Mcu.Pin78=DDR_DQS1P
-Mcu.Pin79=PA7
-Mcu.Pin8=PC10
-Mcu.Pin80=PF7
-Mcu.Pin81=USB_DM2
-Mcu.Pin82=PB6
-Mcu.Pin83=USB_DM1
-Mcu.Pin84=DDR_VREF
-Mcu.Pin85=DDR_DQ12
-Mcu.Pin86=DDR_DQ11
-Mcu.Pin87=PD2
-Mcu.Pin88=DDR_ZQ
-Mcu.Pin89=DDR_A7
-Mcu.Pin9=JTDI
-Mcu.Pin90=PC12
-Mcu.Pin91=PD15
-Mcu.Pin92=DDR_DTO1
-Mcu.Pin93=DDR_A5
-Mcu.Pin94=DDR_DTO0
-Mcu.Pin95=DDR_RASN
-Mcu.Pin96=DDR_ATO
-Mcu.Pin97=DDR_A6
-Mcu.Pin98=PB13
-Mcu.Pin99=PE9
-Mcu.PinsNb=125
-Mcu.ThirdPartyNb=0
-Mcu.UserConstants=
-Mcu.UserName=STM32MP157CADx
-MxCube.Version=5.3.0
-MxDb.Version=DB.5.0.30
-NVIC.BusFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false
-NVIC.DebugMonitor_IRQn=true\:0\:0\:false\:false\:true\:false\:false
-NVIC.HardFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false
-NVIC.MemoryManagement_IRQn=true\:0\:0\:false\:false\:true\:false\:false
-NVIC.NonMaskableInt_IRQn=true\:0\:0\:false\:false\:true\:false\:false
-NVIC.PendSV_IRQn=true\:0\:0\:false\:false\:true\:false\:false
-NVIC.PriorityGroup=NVIC_PRIORITYGROUP_4
-NVIC.SVCall_IRQn=true\:0\:0\:false\:false\:true\:false\:false
-NVIC.SysTick_IRQn=true\:0\:0\:false\:false\:true\:false\:true
-NVIC.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false
-OTG_VBUS.GPIOParameters=GPIO_Label
-OTG_VBUS.GPIO_Label=USB OTG
-OTG_VBUS.Locked=true
-OTG_VBUS.Mode=Activate_VBUS_FS
-OTG_VBUS.Signal=USB_OTG_HS_VBUS
-PA10.GPIOParameters=GPIO_Label
-PA10.GPIO_Label=USB OTG
-PA10.Locked=true
-PA10.Mode=Ext_Phy_OTG/Dual-Role-Device
-PA10.Signal=USB_OTG_HS_ID
-PA13.GPIOParameters=GPIO_Label
-PA13.GPIO_Label=LED1
-PA13.Locked=true
-PA13.Signal=GPIO_Output
-PA2.GPIOParameters=GPIO_Label
-PA2.GPIO_Label=Ethernet
-PA2.Locked=true
-PA2.Mode=RMII (Reduced MII)
-PA2.Signal=ETH1_MDIO
-PA7.GPIOParameters=GPIO_Label
-PA7.GPIO_Label=Ethernet
-PA7.Locked=true
-PA7.Mode=RMII (Reduced MII)
-PA7.Signal=ETH1_CRS_DV
-PB11.GPIOParameters=GPIO_Label
-PB11.GPIO_Label=Ethernet
-PB11.Locked=true
-PB11.Mode=RMII (Reduced MII)
-PB11.Signal=ETH1_TX_EN
-PB12.GPIOParameters=GPIO_Label
-PB12.GPIO_Label=Ethernet
-PB12.Locked=true
-PB12.Mode=RMII (Reduced MII)
-PB12.Signal=ETH1_TXD0
-PB13.GPIOParameters=GPIO_Label
-PB13.GPIO_Label=Ethernet
-PB13.Locked=true
-PB13.Mode=RMII (Reduced MII)
-PB13.Signal=ETH1_TXD1
-PB2.GPIOParameters=GPIO_ModePuPdOnly,GPIO_PuPd,GPIO_Label
-PB2.GPIO_Label=Console UART
-PB2.GPIO_ModePuPdOnly=GPIO_MODE_AF
-PB2.GPIO_PuPd=GPIO_PULLUP
-PB2.Locked=true
-PB2.Mode=Asynchronous
-PB2.Signal=UART4_RX
-PB6.GPIOParameters=GPIO_PuPd,GPIO_Label,GPIO_Speed_Medium_Default,GPIO_Mode
-PB6.GPIO_Label=NOR Flash
-PB6.GPIO_Mode=GPIO_MODE_AF_PP
-PB6.GPIO_PuPd=GPIO_PULLUP
-PB6.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_VERY_HIGH
-PB6.Locked=true
-PB6.Mode=Enable Chip Select for each bank
-PB6.Signal=QUADSPI_BK1_NCS
-PC0.GPIOParameters=GPIO_PuPd,GPIO_Label,GPIO_Speed_Medium_Default
-PC0.GPIO_Label=NAND Flash
-PC0.GPIO_PuPd=GPIO_PULLUP
-PC0.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_VERY_HIGH
-PC0.Locked=true
-PC0.Mode=Enable Chip Select for each bank
-PC0.Signal=QUADSPI_BK2_NCS
-PC1.GPIOParameters=GPIO_Label
-PC1.GPIO_Label=Ethernet
-PC1.Locked=true
-PC1.Mode=RMII (Reduced MII)
-PC1.Signal=ETH1_MDC
-PC10.GPIOParameters=GPIO_PuPd,GPIO_Label,GPIO_Speed_Medium_Default,GPIO_Mode
-PC10.GPIO_Label=SDCARD
-PC10.GPIO_Mode=GPIO_MODE_AF_PP
-PC10.GPIO_PuPd=GPIO_PULLUP
-PC10.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_MEDIUM
-PC10.Locked=true
-PC10.Mode=SD_4_bits_Wide_bus
-PC10.Signal=SDMMC1_D2
-PC11.GPIOParameters=GPIO_PuPd,GPIO_Label,GPIO_Speed_Medium_Default,GPIO_Mode
-PC11.GPIO_Label=SDCARD
-PC11.GPIO_Mode=GPIO_MODE_AF_PP
-PC11.GPIO_PuPd=GPIO_PULLUP
-PC11.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_MEDIUM
-PC11.Locked=true
-PC11.Mode=SD_4_bits_Wide_bus
-PC11.Signal=SDMMC1_D3
-PC12.GPIOParameters=GPIO_PuPd,GPIO_Speed_High_Default,GPIO_Label,GPIO_Mode
-PC12.GPIO_Label=SDCARD
-PC12.GPIO_Mode=GPIO_MODE_AF_PP
-PC12.GPIO_PuPd=GPIO_PULLUP
-PC12.GPIO_Speed_High_Default=GPIO_SPEED_FREQ_VERY_HIGH
-PC12.Locked=true
-PC12.Mode=SD_4_bits_Wide_bus
-PC12.Signal=SDMMC1_CK
-PC13.GPIOParameters=GPIO_Label
-PC13.GPIO_Label=TP16
-PC13.Locked=true
-PC13.Mode=RTC_OUT1
-PC13.Signal=RTC_LSCO
-PC14-OSC32_IN.GPIOParameters=GPIO_Label
-PC14-OSC32_IN.GPIO_Label=OSC RTC
-PC14-OSC32_IN.Locked=true
-PC14-OSC32_IN.Mode=LSE-External-Oscillator
-PC14-OSC32_IN.Signal=RCC_OSC32_IN
-PC15-OSC32_OUT.GPIOParameters=GPIO_Label
-PC15-OSC32_OUT.GPIO_Label=OSC RTC
-PC15-OSC32_OUT.Locked=true
-PC15-OSC32_OUT.Mode=LSE-External-Oscillator
-PC15-OSC32_OUT.Signal=RCC_OSC32_OUT
-PC4.GPIOParameters=GPIO_Label
-PC4.GPIO_Label=Ethernet
-PC4.Locked=true
-PC4.Mode=RMII (Reduced MII)
-PC4.Signal=ETH1_RXD0
-PC5.GPIOParameters=GPIO_Label
-PC5.GPIO_Label=Ethernet
-PC5.Locked=true
-PC5.Mode=RMII (Reduced MII)
-PC5.Signal=ETH1_RXD1
-PC8.GPIOParameters=GPIO_PuPd,GPIO_Label,GPIO_Speed_Medium_Default,GPIO_Mode
-PC8.GPIO_Label=SDCARD
-PC8.GPIO_Mode=GPIO_MODE_AF_PP
-PC8.GPIO_PuPd=GPIO_PULLUP
-PC8.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_MEDIUM
-PC8.Locked=true
-PC8.Mode=SD_4_bits_Wide_bus
-PC8.Signal=SDMMC1_D0
-PC9.GPIOParameters=GPIO_PuPd,GPIO_Label,GPIO_Speed_Medium_Default,GPIO_Mode
-PC9.GPIO_Label=SDCARD
-PC9.GPIO_Mode=GPIO_MODE_AF_PP
-PC9.GPIO_PuPd=GPIO_PULLUP
-PC9.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_MEDIUM
-PC9.Locked=true
-PC9.Mode=SD_4_bits_Wide_bus
-PC9.Signal=SDMMC1_D1
-PCC.Checker=false
-PCC.Line=STM32MP157
-PCC.MCU=STM32MP157CADx
-PCC.PartNumber=STM32MP157CADx
-PCC.Seq0=0
-PCC.Series=STM32MP1
-PCC.Temperature=25
-PCC.Vdd=3.0
-PD15.GPIOParameters=GPIO_Label
-PD15.GPIO_Label=RESET_OUT
-PD15.Locked=true
-PD15.Signal=GPIO_Output
-PD2.GPIOParameters=GPIO_PuPd,GPIO_Label,GPIO_Speed_Medium_Default,GPIO_Mode
-PD2.GPIO_Label=SDCARD
-PD2.GPIO_Mode=GPIO_MODE_AF_PP
-PD2.GPIO_PuPd=GPIO_PULLUP
-PD2.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_MEDIUM
-PD2.Locked=true
-PD2.Mode=SD_4_bits_Wide_bus
-PD2.Signal=SDMMC1_CMD
-PD7.GPIOParameters=GPIO_Label
-PD7.GPIO_Label=GPIO Expander
-PD7.Locked=true
-PD7.Mode=I2C
-PD7.Signal=I2C2_SCL
-PE10.GPIOParameters=GPIO_Label,GPIO_Speed_Medium_Default
-PE10.GPIO_Label=NAND Flash
-PE10.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_VERY_HIGH
-PE10.Locked=true
-PE10.Mode=Dual Bank
-PE10.Signal=QUADSPI_BK2_IO3
-PE7.GPIOParameters=GPIO_Label,GPIO_Speed_Medium_Default
-PE7.GPIO_Label=NAND Flash
-PE7.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_VERY_HIGH
-PE7.Locked=true
-PE7.Mode=Dual Bank
-PE7.Signal=QUADSPI_BK2_IO0
-PE8.GPIOParameters=GPIO_Label,GPIO_Speed_Medium_Default
-PE8.GPIO_Label=NAND Flash
-PE8.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_VERY_HIGH
-PE8.Locked=true
-PE8.Mode=Dual Bank
-PE8.Signal=QUADSPI_BK2_IO1
-PE9.GPIOParameters=GPIO_Label,GPIO_Speed_Medium_Default
-PE9.GPIO_Label=NAND Flash
-PE9.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_VERY_HIGH
-PE9.Locked=true
-PE9.Mode=Dual Bank
-PE9.Signal=QUADSPI_BK2_IO2
-PF10.GPIOParameters=GPIO_Label,GPIO_Speed_Medium_Default
-PF10.GPIO_Label=NOR/NAND Flash
-PF10.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_VERY_HIGH
-PF10.Locked=true
-PF10.Mode=Dual Bank
-PF10.Signal=QUADSPI_CLK
-PF6.GPIOParameters=GPIO_Label,GPIO_Speed_Medium_Default
-PF6.GPIO_Label=NOR Flash
-PF6.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_VERY_HIGH
-PF6.Locked=true
-PF6.Mode=Dual Bank
-PF6.Signal=QUADSPI_BK1_IO3
-PF7.GPIOParameters=GPIO_Label,GPIO_Speed_Medium_Default
-PF7.GPIO_Label=NOR Flash
-PF7.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_VERY_HIGH
-PF7.Locked=true
-PF7.Mode=Dual Bank
-PF7.Signal=QUADSPI_BK1_IO2
-PF8.GPIOParameters=GPIO_Label,GPIO_Speed_Medium_Default
-PF8.GPIO_Label=NOR Flash
-PF8.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_VERY_HIGH
-PF8.Locked=true
-PF8.Mode=Dual Bank
-PF8.Signal=QUADSPI_BK1_IO0
-PF9.GPIOParameters=GPIO_Label,GPIO_Speed_Medium_Default
-PF9.GPIO_Label=NOR Flash
-PF9.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_VERY_HIGH
-PF9.Locked=true
-PF9.Mode=Dual Bank
-PF9.Signal=QUADSPI_BK1_IO1
-PG11.GPIOParameters=GPIO_ModeDefaultPP,GPIO_Speed,GPIO_PuPd,GPIO_Label
-PG11.GPIO_Label=Console UART
-PG11.GPIO_ModeDefaultPP=GPIO_MODE_AF_PP
-PG11.GPIO_PuPd=GPIO_PULLUP
-PG11.GPIO_Speed=GPIO_SPEED_FREQ_LOW
-PG11.Locked=true
-PG11.Mode=Asynchronous
-PG11.Signal=UART4_TX
-PG15.GPIOParameters=GPIO_Label
-PG15.GPIO_Label=GPIO Expander
-PG15.Locked=true
-PG15.Mode=I2C
-PG15.Signal=I2C2_SDA
-PG8.GPIOParameters=GPIO_Label
-PG8.GPIO_Label=Ethernet
-PG8.Locked=true
-PG8.Mode=ETH Clock Output (PHY without Quartz)
-PG8.Signal=ETH1_CLK
-PH0-OSC_IN.GPIOParameters=GPIO_Label
-PH0-OSC_IN.GPIO_Label=OSC System
-PH0-OSC_IN.Locked=true
-PH0-OSC_IN.Mode=HSE-External-Oscillator
-PH0-OSC_IN.Signal=RCC_OSC_IN
-PH1-OSC_OUT.GPIOParameters=GPIO_Label
-PH1-OSC_OUT.GPIO_Label=OSC System
-PH1-OSC_OUT.Locked=true
-PH1-OSC_OUT.Mode=HSE-External-Oscillator
-PH1-OSC_OUT.Signal=RCC_OSC_OUT
-PinOutPanel.CurrentBGAView=Top
-PinOutPanel.RotationAngle=0
-ProjectManager.AskForMigrate=true
-ProjectManager.BackupPrevious=false
-ProjectManager.CompilerOptimize=6
-ProjectManager.ComputerToolchain=false
-ProjectManager.CoupleFile=false
-ProjectManager.CustomerFirmwarePackage=
-ProjectManager.DefaultFWLocation=true
-ProjectManager.DeletePrevious=true
-ProjectManager.DeviceId=STM32MP157CADx
-ProjectManager.DeviceTreeLocation=/home/user/gen/thud/ktn/ye/layers/meta-ktn-stm32mp/conf/machine/cubemx/t1000-som-minimal/DeviceTree/
-ProjectManager.FirmwarePackage=STM32Cube FW_MP1 V1.0.1
-ProjectManager.FreePins=false
-ProjectManager.HalAssertFull=false
-ProjectManager.HeapSize=0x200
-ProjectManager.KeepUserCode=true
-ProjectManager.LastFirmware=true
-ProjectManager.LibraryCopy=1
-ProjectManager.MainLocation=Src
-ProjectManager.NoMain=false
-ProjectManager.PreviousToolchain=SW4STM32
-ProjectManager.ProjectBuild=false
-ProjectManager.ProjectFileName=t1000-som-minimal.ioc
-ProjectManager.ProjectName=t1000-som-minimal
-ProjectManager.StackSize=0x400
-ProjectManager.TargetToolchain=SW4STM32
-ProjectManager.ToolChainLocation=
-ProjectManager.UnderRoot=true
-ProjectManager.functionlistsort=1-MX_GPIO_Init-GPIO-false-HAL-true,2-SystemClock_Config-RCC-false-HAL-false,3-MX_ETZPC_Init-ETZPC-false-HAL-true,4-MX_IPCC_Init-IPCC-false-HAL-true
-RCC.ADCCLockSelection=RCC_ADCCLKSOURCE_PER
-RCC.ADCFreq_Value=24000000
-RCC.AHB1234Freq_Value=200000000
-RCC.APB1DIV=RCC_APB1_DIV2
-RCC.APB1Freq_Value=100000000
-RCC.APB2DIV=RCC_APB2_DIV2
-RCC.APB2Freq_Value=100000000
-RCC.APB3DIV=RCC_APB3_DIV2
-RCC.APB3Freq_Value=100000000
-RCC.APB4DIV=RCC_APB4_DIV2
-RCC.APB4Freq_Value=132000000
-RCC.APB5DIV=RCC_APB5_DIV4
-RCC.APB5DIVClockFreq_Value=66000000
-RCC.AXICLKFreq_VALUE=264000000
-RCC.AXICLKSource=RCC_AXISSOURCE_PLL2
-RCC.AXIDIVFreq_Value=264000000
-RCC.CECFreq_Value=32768
-RCC.CKPERCLKFreq_VALUE=24000000
-RCC.CKPERCLKSource=RCC_CKPERCLKSOURCE_HSE
-RCC.CSI_VALUE=4000000
-RCC.DACCLKFreq_VALUE=32000
-RCC.DDRCFreq_Value=528000000
-RCC.DDRPERFMFreq_Value=528000000
-RCC.DDRPHYFreq_Value=528000000
-RCC.DFSDFAFreq_Value=50000000
-RCC.DFSDMFreq_Value=200000000
-RCC.DIVM1=3
-RCC.DIVM2=3
-RCC.DIVM3=2
-RCC.DIVM4=6
-RCC.DIVN1=81
-RCC.DIVN2=66
-RCC.DIVN3=50
-RCC.DIVN4=125
-RCC.DIVP1Freq_Value=648000000
-RCC.DIVP2Freq_Value=264000000
-RCC.DIVP3=3
-RCC.DIVP3Freq_Value=200000000
-RCC.DIVP4=10
-RCC.DIVP4Freq_Value=50000000
-RCC.DIVQ1Freq_Value=324000000
-RCC.DIVQ2Freq_Value=264000000
-RCC.DIVQ3=3
-RCC.DIVQ3Freq_Value=200000000
-RCC.DIVQ4=10
-RCC.DIVQ4Freq_Value=50000000
-RCC.DIVR1Freq_Value=324000000
-RCC.DIVR2=1
-RCC.DIVR2Freq_Value=528000000
-RCC.DIVR3Freq_Value=300000000
-RCC.DIVR4=10
-RCC.DIVR4Freq_Value=50000000
-RCC.DSIFreq_Value=60000000
-RCC.DSIPixelFreq_Value=50000000
-RCC.DSITXEscFreq_Value=15000000
-RCC.DSI_VALUE=60000000
-RCC.ETHFreq_Value=50000000
-RCC.FDCANFreq_Value=24000000
-RCC.FMCFreq_Value=264000000
-RCC.FamilyName=M
-RCC.HSE_Timout=100
-RCC.HSE_VALUE=24000000
-RCC.HSIDivClkFreq_Value=64000000
-RCC.HSI_VALUE=64000000
-RCC.Hclk5DIVFreq_Value=264000000
-RCC.Hclk6DIVFreq_Value=264000000
-RCC.I2C12CLockSelection=RCC_I2C12CLKSOURCE_HSI
-RCC.I2C12Freq_Value=64000000
-RCC.I2C35Freq_Value=100000000
-RCC.I2C46CLockSelection=RCC_I2C46CLKSOURCE_HSI
-RCC.I2C46Freq_Value=64000000
-RCC.IPParameters=ADCCLockSelection,ADCFreq_Value,AHB1234Freq_Value,APB1DIV,APB1Freq_Value,APB2DIV,APB2Freq_Value,APB3DIV,APB3Freq_Value,APB4DIV,APB4Freq_Value,APB5DIV,APB5DIVClockFreq_Value,AXICLKFreq_VALUE,AXICLKSource,AXIDIVFreq_Value,CECFreq_Value,CKPERCLKFreq_VALUE,CKPERCLKSource,CSI_VALUE,DACCLKFreq_VALUE,DDRCFreq_Value,DDRPERFMFreq_Value,DDRPHYFreq_Value,DFSDFAFreq_Value,DFSDMFreq_Value,DIVM1,DIVM2,DIVM3,DIVM4,DIVN1,DIVN2,DIVN3,DIVN4,DIVP1Freq_Value,DIVP2Freq_Value,DIVP3,DIVP3Freq_Value,DIVP4,DIVP4Freq_Value,DIVQ1Freq_Value,DIVQ2Freq_Value,DIVQ3,DIVQ3Freq_Value,DIVQ4,DIVQ4Freq_Value,DIVR1Freq_Value,DIVR2,DIVR2Freq_Value,DIVR3Freq_Value,DIVR4,DIVR4Freq_Value,DSIFreq_Value,DSIPixelFreq_Value,DSITXEscFreq_Value,DSI_VALUE,ETHFreq_Value,FDCANFreq_Value,FMCFreq_Value,FamilyName,HSE_Timout,HSE_VALUE,HSIDivClkFreq_Value,HSI_VALUE,Hclk5DIVFreq_Value,Hclk6DIVFreq_Value,I2C12CLockSelection,I2C12Freq_Value,I2C35Freq_Value,I2C46CLockSelection,I2C46Freq_Value,LPTIM1Freq_Value,LPTIM23Freq_Value,LPTIM45Freq_Value,LSE_Timout,LSI_VALUE,LTDCFreq_Value,MCO1PinFreq_Value,MCO2PinFreq_Value,MCUCLKFreq_VALUE,MCUCLKSource,MCUClockFreq_Value,MCUDIVCLKFreq_Value,MPUCLKFreq_VALUE,MPUCLKSource,PLL12Source,PLL2FRACV,PLL3FRACV,PLL3Source,PLL4PDSIFreq_Value,PLL4Source,PLLDSIFreq_Value,PLLDSIVCOFreq_Value,PUBLFreq_Value,QSPIFreq_Value,RNG1Freq_Value,RNG2Freq_Value,RTCClockSelection,RTCFreq_Value,SAI1Freq_Value,SAI2Freq_Value,SAI3Freq_Value,SAI4Freq_Value,SDMMC12CLockSelection,SDMMC12Freq_Value,SDMMC3Freq_Value,SPDIFRXFreq_Value,SPI1CLockSelection,SPI1Freq_Value,SPI23Freq_Value,SPI45Freq_Value,SPI6Freq_Value,STGENCLockSelection,STGENFreq_Value,Tim1OutputFreq_Value,Tim2OutputFreq_Value,UART78Freq_Value,USART1Freq_Value,USART24Freq_Value,USART35Freq_Value,USART6Freq_Value,USBOCLKSource,USBOHSFreq_Value,USBPHYCLKSource,USBPHYFreq_Value,VCO1OutputFreq_Value,VCO2OutputFreq_Value,VCO3OutputFreq_Value,VCO4OutputFreq_Value,VCOInput1Freq_Value,VCOInput2Freq_Value,VCOInput3Freq_Value,VCOInput4Freq_Value
-RCC.LPTIM1Freq_Value=100000000
-RCC.LPTIM23Freq_Value=100000000
-RCC.LPTIM45Freq_Value=100000000
-RCC.LSE_Timout=5000
-RCC.LSI_VALUE=32000
-RCC.LTDCFreq_Value=50000000
-RCC.MCO1PinFreq_Value=64000000
-RCC.MCO2PinFreq_Value=648000000
-RCC.MCUCLKFreq_VALUE=200000000
-RCC.MCUCLKSource=RCC_MCUSSOURCE_PLL3
-RCC.MCUClockFreq_Value=200000000
-RCC.MCUDIVCLKFreq_Value=200000000
-RCC.MPUCLKFreq_VALUE=648000000
-RCC.MPUCLKSource=RCC_MPUSOURCE_PLL1
-RCC.PLL12Source=RCC_PLL12SOURCE_HSE
-RCC.PLL2FRACV=0
-RCC.PLL3FRACV=0
-RCC.PLL3Source=RCC_PLL3SOURCE_HSE
-RCC.PLL4PDSIFreq_Value=50000000
-RCC.PLL4Source=RCC_PLL4SOURCE_HSE
-RCC.PLLDSIFreq_Value=480000000
-RCC.PLLDSIVCOFreq_Value=960000000
-RCC.PUBLFreq_Value=528000000
-RCC.QSPIFreq_Value=264000000
-RCC.RNG1Freq_Value=4000000
-RCC.RNG2Freq_Value=4000000
-RCC.RTCClockSelection=RCC_RTCCLKSOURCE_LSE
-RCC.RTCFreq_Value=32768
-RCC.SAI1Freq_Value=50000000
-RCC.SAI2Freq_Value=50000000
-RCC.SAI3Freq_Value=50000000
-RCC.SAI4Freq_Value=50000000
-RCC.SDMMC12CLockSelection=RCC_SDMMC12CLKSOURCE_PLL4
-RCC.SDMMC12Freq_Value=50000000
-RCC.SDMMC3Freq_Value=200000000
-RCC.SPDIFRXFreq_Value=50000000
-RCC.SPI1CLockSelection=RCC_SPI1CLKSOURCE_PLL3_Q
-RCC.SPI1Freq_Value=200000000
-RCC.SPI23Freq_Value=50000000
-RCC.SPI45Freq_Value=100000000
-RCC.SPI6Freq_Value=66000000
-RCC.STGENCLockSelection=RCC_STGENCLKSOURCE_HSE
-RCC.STGENFreq_Value=24000000
-RCC.Tim1OutputFreq_Value=200000000
-RCC.Tim2OutputFreq_Value=200000000
-RCC.UART78Freq_Value=100000000
-RCC.USART1Freq_Value=66000000
-RCC.USART24Freq_Value=100000000
-RCC.USART35Freq_Value=100000000
-RCC.USART6Freq_Value=100000000
-RCC.USBOCLKSource=RCC_USBOCLKSOURCE_PHY
-RCC.USBOHSFreq_Value=48000000
-RCC.USBPHYCLKSource=RCC_USBPHYCLKSOURCE_HSE
-RCC.USBPHYFreq_Value=24000000
-RCC.VCO1OutputFreq_Value=1296000000
-RCC.VCO2OutputFreq_Value=1056000000
-RCC.VCO3OutputFreq_Value=600000000
-RCC.VCO4OutputFreq_Value=500000000
-RCC.VCOInput1Freq_Value=8000000
-RCC.VCOInput2Freq_Value=8000000
-RCC.VCOInput3Freq_Value=12000000
-RCC.VCOInput4Freq_Value=4000000
-USB_DM1.GPIOParameters=GPIO_Label
-USB_DM1.GPIO_Label=USB Host
-USB_DM1.Locked=true
-USB_DM1.Mode=Enable
-USB_DM1.Signal=USBH_HS1_DM
-USB_DM2.GPIOParameters=GPIO_Label
-USB_DM2.GPIO_Label=USB OTG
-USB_DM2.Locked=true
-USB_DM2.Mode=Ext_Phy_OTG/Dual-Role-Device
-USB_DM2.Signal=USB_OTG_HS_DM
-USB_DP1.GPIOParameters=GPIO_Label
-USB_DP1.GPIO_Label=USB Host
-USB_DP1.Locked=true
-USB_DP1.Mode=Enable
-USB_DP1.Signal=USBH_HS1_DP
-USB_DP2.GPIOParameters=GPIO_Label
-USB_DP2.GPIO_Label=USB OTG
-USB_DP2.Locked=true
-USB_DP2.Mode=Ext_Phy_OTG/Dual-Role-Device
-USB_DP2.Signal=USB_OTG_HS_DP
-VP_ADC2_TempSens_Input.Mode=IN-TempSens
-VP_ADC2_TempSens_Input.Signal=ADC2_TempSens_Input
-VP_ADC2_Vbat_Input.Mode=IN-Vbat
-VP_ADC2_Vbat_Input.Signal=ADC2_Vbat_Input
-VP_ADC2_VddCore_Input.Mode=IN-VddCore
-VP_ADC2_VddCore_Input.Signal=ADC2_VddCore_Input
-VP_ADC2_Vref_Input.Mode=IN-Vrefint
-VP_ADC2_Vref_Input.Signal=ADC2_Vref_Input
-VP_BSEC_VS_BSEC.Mode=BSEC_Activate
-VP_BSEC_VS_BSEC.Signal=BSEC_VS_BSEC
-VP_CRC1_VS_CRC.Mode=CRC_Activate
-VP_CRC1_VS_CRC.Signal=CRC1_VS_CRC
-VP_CRYP1_VS_CRYP.Mode=CRYP_Activate
-VP_CRYP1_VS_CRYP.Signal=CRYP1_VS_CRYP
-VP_DDR_DDR3.Mode=DDR3
-VP_DDR_DDR3.Signal=DDR_DDR3
-VP_DDR_DDR3_16_4Gb.Mode=4Gb_16bits
-VP_DDR_DDR3_16_4Gb.Signal=DDR_DDR3_16_4Gb
-VP_DDR_DDR_16_bits.Mode=16bits
-VP_DDR_DDR_16_bits.Signal=DDR_DDR_16_bits
-VP_DMA_VS_DMA1_A7NS.Mode=CortexA7NS
-VP_DMA_VS_DMA1_A7NS.Signal=DMA_VS_DMA1_A7NS
-VP_DMA_VS_DMA2_M4.Mode=CortexM4
-VP_DMA_VS_DMA2_M4.Signal=DMA_VS_DMA2_M4
-VP_DTS_VS_DTS.Mode=DTS_Activate
-VP_DTS_VS_DTS.Signal=DTS_VS_DTS
-VP_ETZPC_VS_ETZPC.Mode=ETZPC_Activate
-VP_ETZPC_VS_ETZPC.Signal=ETZPC_VS_ETZPC
-VP_GPU_VS_GPU.Mode=GPU_Activate
-VP_GPU_VS_GPU.Signal=GPU_VS_GPU
-VP_HASH1_VS_HASH.Mode=HASH_Activate
-VP_HASH1_VS_HASH.Signal=HASH1_VS_HASH
-VP_HSEM_VS_HSEM.Mode=HSEM_Activate
-VP_HSEM_VS_HSEM.Signal=HSEM_VS_HSEM
-VP_IPCC_VS_IPCC.Mode=IPCC_Activate
-VP_IPCC_VS_IPCC.Signal=IPCC_VS_IPCC
-VP_IWDG2_VS_IWDG.Mode=IWDG_Activate
-VP_IWDG2_VS_IWDG.Signal=IWDG2_VS_IWDG
-VP_MDMA_VS_MDMA_A7NS_8.Mode=8\:8
-VP_MDMA_VS_MDMA_A7NS_8.Signal=MDMA_VS_MDMA_A7NS_8
-VP_RNG1_VS_RNG.Mode=RNG_Activate
-VP_RNG1_VS_RNG.Signal=RNG1_VS_RNG
-VP_RTC_VS_RTC_Activate.Mode=RTC_Enabled
-VP_RTC_VS_RTC_Activate.Signal=RTC_VS_RTC_Activate
-VP_SYS_VS_Systick.Mode=SysTick
-VP_SYS_VS_Systick.Signal=SYS_VS_Systick
-VP_VREFBUF_VS_VREFBUF.Mode=VREFBUF_Activate
-VP_VREFBUF_VS_VREFBUF.Signal=VREFBUF_VS_VREFBUF
-board=custom
diff --git a/conf/machine/cubemx/t1001-som-minimal/DeviceTree/t1001-som-minimal/kernel/stm32mp157c-t1001-som-minimal-mx.dts b/conf/machine/cubemx/t1001-som-minimal/DeviceTree/t1001-som-minimal/kernel/stm32mp157c-t1001-som-minimal-mx.dts
deleted file mode 100644
index 860db514df9845f933572d562ad27081c2ce609f..0000000000000000000000000000000000000000
--- a/conf/machine/cubemx/t1001-som-minimal/DeviceTree/t1001-som-minimal/kernel/stm32mp157c-t1001-som-minimal-mx.dts
+++ /dev/null
@@ -1,405 +0,0 @@
-/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
-/*
- * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
- * Author: STM32CubeMX code generation for STMicroelectronics.
- */
-
-/dts-v1/;
-#include "stm32mp157c.dtsi"
-#include "stm32mp157c-m4-srm.dtsi"
-#include "stm32mp157cad-pinctrl.dtsi"
-
-/* USER CODE BEGIN includes */
-/* USER CODE END includes */
-
-/ {
-	model = "STMicroelectronics custom STM32CubeMX board";
-	compatible = "st,stm32mp157c-t1001-som-minimal-mx", "st,stm32mp157";
-
-	memory@c0000000 {
-		reg = <0xc0000000 0x20000000>;
-
-		/* USER CODE BEGIN memory */
-		/* USER CODE END memory */
-	};
-
-	reserved-memory {
-		#address-cells = <1>;
-		#size-cells = <1>;
-		ranges;
-
-		/* USER CODE BEGIN reserved-memory */
-		/* USER CODE END reserved-memory */
-
-		gpu_reserved: gpu@dc000000 {
-			reg = <0xdc000000 0x4000000>;
-			no-map;
-		};
-	};
-
-	/* USER CODE BEGIN root */
-	/* USER CODE END root */
-
-	clocks {
-		/* USER CODE BEGIN clocks */
-		/* USER CODE END clocks */
-
-		clk_csi: clk-csi {
-			clock-frequency = <4000000>;
-		};
-
-		clk_lse: clk-lse {
-			clock-frequency = <32768>;
-		};
-
-		clk_hse: clk-hse {
-			clock-frequency = <24000000>;
-		};
-	};
-
-}; /*root*/
-
-&pinctrl {
-	u-boot,dm-pre-reloc;
-
-	quadspi_pins_mx: quadspi_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 6, AF10)>; /* QUADSPI_BK1_NCS */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('F', 6, AF9)>, /* QUADSPI_BK1_IO3 */
-					 <STM32_PINMUX('F', 7, AF9)>, /* QUADSPI_BK1_IO2 */
-					 <STM32_PINMUX('F', 8, AF10)>, /* QUADSPI_BK1_IO0 */
-					 <STM32_PINMUX('F', 9, AF10)>, /* QUADSPI_BK1_IO1 */
-					 <STM32_PINMUX('F', 10, AF9)>; /* QUADSPI_CLK */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-	};
-
-	quadspi_sleep_pins_mx: quadspi_sleep_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 6, ANALOG)>, /* QUADSPI_BK1_NCS */
-					 <STM32_PINMUX('F', 6, ANALOG)>, /* QUADSPI_BK1_IO3 */
-					 <STM32_PINMUX('F', 7, ANALOG)>, /* QUADSPI_BK1_IO2 */
-					 <STM32_PINMUX('F', 8, ANALOG)>, /* QUADSPI_BK1_IO0 */
-					 <STM32_PINMUX('F', 9, ANALOG)>, /* QUADSPI_BK1_IO1 */
-					 <STM32_PINMUX('F', 10, ANALOG)>; /* QUADSPI_CLK */
-		};
-	};
-
-	sdmmc1_pins_mx: sdmmc1_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
-					 <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
-					 <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
-					 <STM32_PINMUX('C', 11, AF12)>, /* SDMMC1_D3 */
-					 <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 12, AF12)>; /* SDMMC1_CK */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-	};
-
-	sdmmc1_opendrain_pins_mx: sdmmc1_opendrain_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
-					 <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
-					 <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
-					 <STM32_PINMUX('C', 11, AF12)>; /* SDMMC1_D3 */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 12, AF12)>; /* SDMMC1_CK */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins3 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
-			bias-pull-up;
-			drive-open-drain;
-			slew-rate = <1>;
-		};
-	};
-
-	sdmmc1_sleep_pins_mx: sdmmc1_sleep_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 8, ANALOG)>, /* SDMMC1_D0 */
-					 <STM32_PINMUX('C', 9, ANALOG)>, /* SDMMC1_D1 */
-					 <STM32_PINMUX('C', 10, ANALOG)>, /* SDMMC1_D2 */
-					 <STM32_PINMUX('C', 11, ANALOG)>, /* SDMMC1_D3 */
-					 <STM32_PINMUX('C', 12, ANALOG)>, /* SDMMC1_CK */
-					 <STM32_PINMUX('D', 2, ANALOG)>; /* SDMMC1_CMD */
-		};
-	};
-
-	uart4_pins_mx: uart4_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 2, AF8)>; /* UART4_RX */
-			bias-pull-up;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('G', 11, AF6)>; /* UART4_TX */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-	};
-
-	uart4_sleep_pins_mx: uart4_sleep_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 2, ANALOG)>, /* UART4_RX */
-					 <STM32_PINMUX('G', 11, ANALOG)>; /* UART4_TX */
-		};
-	};
-
-	usb_otg_hs_pins_mx: usb_otg_hs_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
-		};
-	};
-
-	usb_otg_hs_sleep_pins_mx: usb_otg_hs_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
-		};
-	};
-
-	/* USER CODE BEGIN pinctrl */
-	/* USER CODE END pinctrl */
-};
-
-&pinctrl_z {
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN pinctrl_z */
-	/* USER CODE END pinctrl_z */
-};
-
-&m4_rproc{
-	mboxes = <&ipcc 0>, <&ipcc 1>, <&ipcc 2>;
-	mbox-names = "vq0", "vq1", "shutdown";
-	recovery;
-	status = "okay";
-
-	/* USER CODE BEGIN m4_rproc */
-	/* USER CODE END m4_rproc */
-};
-
-&adc{
-	status = "okay";
-
-	/* USER CODE BEGIN adc */
-	/* USER CODE END adc */
-};
-
-&bsec{
-	status = "okay";
-
-	/* USER CODE BEGIN bsec */
-	/* USER CODE END bsec */
-};
-
-&crc1{
-	status = "okay";
-
-	/* USER CODE BEGIN crc1 */
-	/* USER CODE END crc1 */
-};
-
-&cryp1{
-	status = "okay";
-
-	/* USER CODE BEGIN cryp1 */
-	/* USER CODE END cryp1 */
-};
-
-&dts{
-	status = "okay";
-
-	/* USER CODE BEGIN dts */
-	/* USER CODE END dts */
-};
-
-&gpu{
-	status = "okay";
-
-	/* USER CODE BEGIN gpu */
-	/* USER CODE END gpu */
-};
-
-&hash1{
-	status = "okay";
-
-	/* USER CODE BEGIN hash1 */
-	/* USER CODE END hash1 */
-};
-
-&hsem{
-	status = "okay";
-
-	/* USER CODE BEGIN hsem */
-	/* USER CODE END hsem */
-};
-
-&ipcc{
-	status = "okay";
-
-	/* USER CODE BEGIN ipcc */
-	/* USER CODE END ipcc */
-};
-
-&iwdg2{
-	status = "okay";
-
-	/* USER CODE BEGIN iwdg2 */
-	/* USER CODE END iwdg2 */
-};
-
-&qspi{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&quadspi_pins_mx>;
-	pinctrl-1 = <&quadspi_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN qspi */
-	/* USER CODE END qspi */
-};
-
-&rcc{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN rcc */
-	/* USER CODE END rcc */
-};
-
-&rng1{
-	status = "okay";
-
-	/* USER CODE BEGIN rng1 */
-	/* USER CODE END rng1 */
-};
-
-&rtc{
-	status = "okay";
-
-	/* USER CODE BEGIN rtc */
-	/* USER CODE END rtc */
-};
-
-&sdmmc1{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "opendrain", "sleep";
-	pinctrl-0 = <&sdmmc1_pins_mx>;
-	pinctrl-1 = <&sdmmc1_opendrain_pins_mx>;
-	pinctrl-2 = <&sdmmc1_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN sdmmc1 */
-	/* USER CODE END sdmmc1 */
-};
-
-&uart4{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&uart4_pins_mx>;
-	pinctrl-1 = <&uart4_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN uart4 */
-	/* USER CODE END uart4 */
-};
-
-&usbh_ehci{
-	status = "okay";
-
-	/* USER CODE BEGIN usbh_ehci */
-	/* USER CODE END usbh_ehci */
-};
-
-&usbh_ohci{
-	status = "okay";
-
-	/* USER CODE BEGIN usbh_ohci */
-	/* USER CODE END usbh_ohci */
-};
-
-&usbotg_hs{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&usb_otg_hs_pins_mx>;
-	pinctrl-1 = <&usb_otg_hs_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN usbotg_hs */
-	/* USER CODE END usbotg_hs */
-};
-
-&usbphyc{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc */
-	/* USER CODE END usbphyc */
-};
-
-&usbphyc_port0{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc_port0 */
-	/* USER CODE END usbphyc_port0 */
-};
-
-&usbphyc_port1{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc_port1 */
-	/* USER CODE END usbphyc_port1 */
-};
-
-&vrefbuf{
-	status = "okay";
-
-	/* USER CODE BEGIN vrefbuf */
-	/* USER CODE END vrefbuf */
-};
-
-/* USER CODE BEGIN addons */
-/* USER CODE END addons */
-
diff --git a/conf/machine/cubemx/t1001-som-minimal/DeviceTree/t1001-som-minimal/tf-a/stm32mp15-mx.h b/conf/machine/cubemx/t1001-som-minimal/DeviceTree/t1001-som-minimal/tf-a/stm32mp15-mx.h
deleted file mode 100644
index e6897cf871f24d9492c58ab0ee152f3b2b6bc429..0000000000000000000000000000000000000000
--- a/conf/machine/cubemx/t1001-som-minimal/DeviceTree/t1001-som-minimal/tf-a/stm32mp15-mx.h
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright (C) 2015-2018, STMicroelectronics - All Rights Reserved
- *
- * SPDX-License-Identifier:	GPL-2.0+	BSD-3-Clause
- *
- */
-
-/*
- * File generated by STMicroelectronics STM32CubeMX DDR Tool for MPUs
- * DDR type: DDR3 / DDR3L
- * DDR width: 16bits
- * DDR density: 4Gb
- * System frequency: 528000Khz
- * Relaxed Timing Mode: false
- * Address mapping type: RBC
- *
- * Save Date: 2019.09.27, save Time: 17:49:09
- */
-
-#define DDR_MEM_NAME	"DDR3-DDR3L 16bits 528000Khz"
-#define DDR_MEM_SPEED	528000
-#define DDR_MEM_SIZE	0x20000000
-
-#define DDR_MSTR 0x00041401
-#define DDR_MRCTRL0 0x00000010
-#define DDR_MRCTRL1 0x00000000
-#define DDR_DERATEEN 0x00000000
-#define DDR_DERATEINT 0x00800000
-#define DDR_PWRCTL 0x00000000
-#define DDR_PWRTMG 0x00400010
-#define DDR_HWLPCTL 0x00000000
-#define DDR_RFSHCTL0 0x00210000
-#define DDR_RFSHCTL3 0x00000000
-#define DDR_RFSHTMG 0x0040008A
-#define DDR_CRCPARCTL0 0x00000000
-#define DDR_DRAMTMG0 0x121B1214
-#define DDR_DRAMTMG1 0x000A041B
-#define DDR_DRAMTMG2 0x0607080F
-#define DDR_DRAMTMG3 0x0050400C
-#define DDR_DRAMTMG4 0x07040607
-#define DDR_DRAMTMG5 0x06060403
-#define DDR_DRAMTMG6 0x02020002
-#define DDR_DRAMTMG7 0x00000202
-#define DDR_DRAMTMG8 0x00001005
-#define DDR_DRAMTMG14 0x000000A0
-#define DDR_ZQCTL0 0xC2000040
-#define DDR_DFITMG0 0x02050105
-#define DDR_DFITMG1 0x00000202
-#define DDR_DFILPCFG0 0x07000000
-#define DDR_DFIUPD0 0xC0400003
-#define DDR_DFIUPD1 0x00000000
-#define DDR_DFIUPD2 0x00000000
-#define DDR_DFIPHYMSTR 0x00000000
-#define DDR_ODTCFG 0x06000600
-#define DDR_ODTMAP 0x00000001
-#define DDR_SCHED 0x00000C01
-#define DDR_SCHED1 0x00000000
-#define DDR_PERFHPR1 0x01000001
-#define DDR_PERFLPR1 0x08000200
-#define DDR_PERFWR1 0x08000400
-#define DDR_DBG0 0x00000000
-#define DDR_DBG1 0x00000000
-#define DDR_DBGCMD 0x00000000
-#define DDR_POISONCFG 0x00000000
-#define DDR_PCCFG 0x00000010
-#define DDR_PCFGR_0 0x00010000
-#define DDR_PCFGW_0 0x00000000
-#define DDR_PCFGQOS0_0 0x02100C03
-#define DDR_PCFGQOS1_0 0x00800100
-#define DDR_PCFGWQOS0_0 0x01100C03
-#define DDR_PCFGWQOS1_0 0x01000200
-#define DDR_PCFGR_1 0x00010000
-#define DDR_PCFGW_1 0x00000000
-#define DDR_PCFGQOS0_1 0x02100C03
-#define DDR_PCFGQOS1_1 0x00800040
-#define DDR_PCFGWQOS0_1 0x01100C03
-#define DDR_PCFGWQOS1_1 0x01000200
-#define DDR_ADDRMAP1 0x00070707
-#define DDR_ADDRMAP2 0x00000000
-#define DDR_ADDRMAP3 0x1F000000
-#define DDR_ADDRMAP4 0x00001F1F
-#define DDR_ADDRMAP5 0x06060606
-#define DDR_ADDRMAP6 0x0F060606
-#define DDR_ADDRMAP9 0x00000000
-#define DDR_ADDRMAP10 0x00000000
-#define DDR_ADDRMAP11 0x00000000
-#define DDR_PGCR 0x01442E02
-#define DDR_PTR0 0x0022A41B
-#define DDR_PTR1 0x047C0740
-#define DDR_PTR2 0x042D9C80
-#define DDR_ACIOCR 0x10400812
-#define DDR_DXCCR 0x00000C40
-#define DDR_DSGCR 0xF200001F
-#define DDR_DCR 0x0000000B
-#define DDR_DTPR0 0x36D477D0
-#define DDR_DTPR1 0x098A00D8
-#define DDR_DTPR2 0x10023600
-#define DDR_MR0 0x00000830
-#define DDR_MR1 0x00000000
-#define DDR_MR2 0x00000248
-#define DDR_MR3 0x00000000
-#define DDR_ODTCR 0x00010000
-#define DDR_ZQ0CR1 0x00000038
-#define DDR_DX0GCR 0x0000CE81
-#define DDR_DX0DLLCR 0x40000000
-#define DDR_DX0DQTR 0x55050005
-#define DDR_DX0DQSTR 0x3D202000
-#define DDR_DX1GCR 0x0000CE81
-#define DDR_DX1DLLCR 0x40000000
-#define DDR_DX1DQTR 0x00050500
-#define DDR_DX1DQSTR 0x3DB02000
-#define DDR_DX2GCR 0x0000C881
-#define DDR_DX2DLLCR 0x40000000
-#define DDR_DX2DQTR 0xFFFFFFFF
-#define DDR_DX2DQSTR 0x3DB02000
-#define DDR_DX3GCR 0x0000C881
-#define DDR_DX3DLLCR 0x40000000
-#define DDR_DX3DQTR 0xFFFFFFFF
-#define DDR_DX3DQSTR 0x3DB02000
diff --git a/conf/machine/cubemx/t1001-som-minimal/DeviceTree/t1001-som-minimal/tf-a/stm32mp157c-t1001-som-minimal-mx.dts b/conf/machine/cubemx/t1001-som-minimal/DeviceTree/t1001-som-minimal/tf-a/stm32mp157c-t1001-som-minimal-mx.dts
deleted file mode 100644
index 1a16f0123301380c170cb37e39fb40f02ffbe32c..0000000000000000000000000000000000000000
--- a/conf/machine/cubemx/t1001-som-minimal/DeviceTree/t1001-som-minimal/tf-a/stm32mp157c-t1001-som-minimal-mx.dts
+++ /dev/null
@@ -1,315 +0,0 @@
-/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
-/*
- * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
- * Author: STM32CubeMX code generation for STMicroelectronics.
- */
-
-/dts-v1/;
-#include <dt-bindings/clock/stm32mp1-clksrc.h>
-#include "stm32mp15-mx.h"
-
-#include "stm32mp157c.dtsi"
-#include "stm32mp157cad-pinctrl.dtsi"
-#include "stm32mp15-ddr.dtsi"
-#include "stm32mp157c-security.dtsi"
-
-/* USER CODE BEGIN includes */
-/* USER CODE END includes */
-
-/ {
-	model = "STMicroelectronics custom STM32CubeMX board";
-	compatible = "st,stm32mp157c-t1001-som-minimal-mx", "st,stm32mp157";
-
-	/* USER CODE BEGIN root */
-	/* USER CODE END root */
-
-	clocks {
-		/* USER CODE BEGIN clocks */
-		/* USER CODE END clocks */
-
-		clk_lse: clk-lse {
-			/* USER CODE BEGIN clocks */
-			/* USER CODE END clocks */
-			st,drive=<LSEDRV_MEDIUM_HIGH>;
-		};
-
-		clk_hse: clk-hse {
-			/* USER CODE BEGIN clocks */
-			/* USER CODE END clocks */
-		};
-	};
-
-}; /*root*/
-
-&pinctrl {
-	quadspi_pins_mx: quadspi_mx-0 {
-		pins1 {
-			pinmux = <STM32_PINMUX('B', 6, AF10)>; /* QUADSPI_BK1_NCS */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins2 {
-			pinmux = <STM32_PINMUX('F', 6, AF9)>, /* QUADSPI_BK1_IO3 */
-					 <STM32_PINMUX('F', 7, AF9)>, /* QUADSPI_BK1_IO2 */
-					 <STM32_PINMUX('F', 8, AF10)>, /* QUADSPI_BK1_IO0 */
-					 <STM32_PINMUX('F', 9, AF10)>, /* QUADSPI_BK1_IO1 */
-					 <STM32_PINMUX('F', 10, AF9)>; /* QUADSPI_CLK */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-	};
-
-	sdmmc1_pins_mx: sdmmc1_mx-0 {
-		pins1 {
-			pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
-					 <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
-					 <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
-					 <STM32_PINMUX('C', 11, AF12)>, /* SDMMC1_D3 */
-					 <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-		pins2 {
-			pinmux = <STM32_PINMUX('C', 12, AF12)>; /* SDMMC1_CK */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-	};
-
-	uart4_pins_mx: uart4_mx-0 {
-		pins1 {
-			pinmux = <STM32_PINMUX('B', 2, AF8)>; /* UART4_RX */
-			bias-pull-up;
-		};
-		pins2 {
-			pinmux = <STM32_PINMUX('G', 11, AF6)>; /* UART4_TX */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-	};
-
-	usb_otg_hs_pins_mx: usb_otg_hs_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
-		};
-	};
-
-	/* USER CODE BEGIN pinctrl */
-	/* USER CODE END pinctrl */
-};
-
-&pinctrl_z {
-	/* USER CODE BEGIN pinctrl_z */
-	/* USER CODE END pinctrl_z */
-};
-
-&rcc {
-	st,csi-cal;
-	st,hsi-cal;
-	st,cal-sec = <60>;
-	st,clksrc = <
-		CLK_MPU_PLL1P
-		CLK_AXI_PLL2P
-		CLK_MCU_PLL3P
-		CLK_PLL12_HSE
-		CLK_PLL3_HSE
-		CLK_PLL4_HSE
-		CLK_RTC_LSE
-		CLK_MCO1_DISABLED
-		CLK_MCO2_DISABLED
-	>;
-	st,clkdiv = <
-		1 		/*MPU*/
-		0 		/*AXI*/
-		0 		/*MCU*/
-		1 		/*APB1*/
-		1 		/*APB2*/
-		1 		/*APB3*/
-		1 		/*APB4*/
-		2 		/*APB5*/
-		0 		/*RTC*/
-		0 		/*MCO1*/
-		0 		/*MCO2*/
-	>;
-	st,pkcs = <
-		CLK_CKPER_HSE
-		CLK_QSPI_ACLK
-		CLK_ETH_DISABLED
-		CLK_SDMMC12_PLL4P
-		CLK_STGEN_HSE
-		CLK_USBPHY_HSE
-		CLK_SPI2S1_DISABLED
-		CLK_SPI2S23_DISABLED
-		CLK_SPI45_DISABLED
-		CLK_SPI6_DISABLED
-		CLK_I2C46_DISABLED
-		CLK_SDMMC3_DISABLED
-		CLK_USBO_USBPHY
-		CLK_ADC_CKPER
-		CLK_CEC_DISABLED
-		CLK_I2C12_DISABLED
-		CLK_I2C35_DISABLED
-		CLK_UART1_DISABLED
-		CLK_UART24_PCLK1
-		CLK_UART35_DISABLED
-		CLK_UART6_DISABLED
-		CLK_UART78_DISABLED
-		CLK_SPDIF_DISABLED
-		CLK_SAI1_DISABLED
-		CLK_SAI2_DISABLED
-		CLK_SAI3_DISABLED
-		CLK_SAI4_DISABLED
-		CLK_RNG1_CSI
-		CLK_LPTIM1_DISABLED
-		CLK_LPTIM23_DISABLED
-		CLK_LPTIM45_DISABLED
-	>;
-	pll1:st,pll@0 {
-		cfg = < 2 80 0 1 1 1>;
-	};
-	pll2:st,pll@1 {
-		cfg = < 2 65 1 1 0 7>;
-	};
-	pll3:st,pll@2 {
-		cfg = < 1 49 2 2 1 1>;
-	};
-	pll4:st,pll@3 {
-		cfg = < 5 124 9 9 9 1>;
-	};
-};
-
-&bsec{
-	status = "okay";
-	secure-status = "okay";
-
-	/* USER CODE BEGIN bsec */
-	/* USER CODE END bsec */
-};
-
-&etzpc{
-	st,decprot = <
-	/*"Non Secured" peripherals*/
-	DECPROT(STM32MP1_ETZPC_ADC_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-	DECPROT(STM32MP1_ETZPC_CRYP1_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-	DECPROT(STM32MP1_ETZPC_HASH1_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-	DECPROT(STM32MP1_ETZPC_QSPI_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-	DECPROT(STM32MP1_ETZPC_DLYBQ_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-	DECPROT(STM32MP1_ETZPC_RNG1_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-	DECPROT(STM32MP1_ETZPC_UART4_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-	DECPROT(STM32MP1_ETZPC_OTG_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-	DECPROT(STM32MP1_ETZPC_VREFBUF_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-
-	/*Restriction: following IDs are not managed  - please to use User-Section if needed:
-		STM32MP1_ETZPC_DMA1_ID, STM32MP1_ETZPC_DMA2_ID, STM32MP1_ETZPC_DMAMUX_ID,
-		STM32MP1_ETZPC_SRAMx_ID, STM32MP1_ETZPC_RETRAM_ID, STM32MP1_ETZPC_BKPSRAM_ID*/
-
-	/* USER CODE BEGIN etzpc_decprot */
-		/*STM32CubeMX generates a basic and standard configuration for ETZPC.
-		Additional device configurations can be added here if needed.
-		"etzpc" node could be also overloaded in "addons" User-Section.*/
-	/* USER CODE END etzpc_decprot */
-	>;
-
-	secure-status = "okay";
-
-	/* USER CODE BEGIN etzpc */
-	/* USER CODE END etzpc */
-};
-
-&iwdg2{
-	status = "okay";
-	secure-status = "okay";
-
-	/* USER CODE BEGIN iwdg2 */
-	/* USER CODE END iwdg2 */
-};
-
-&qspi{
-	pinctrl-names = "default";
-	pinctrl-0 = <&quadspi_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN qspi */
-	/* USER CODE END qspi */
-};
-
-&rcc{
-	status = "okay";
-	secure-status = "okay";
-
-	/* USER CODE BEGIN rcc */
-	/* USER CODE END rcc */
-};
-
-&rng1{
-	status = "okay";
-	secure-status = "okay";
-
-	/* USER CODE BEGIN rng1 */
-	/* USER CODE END rng1 */
-};
-
-&rtc{
-	status = "okay";
-	secure-status = "okay";
-
-	/* USER CODE BEGIN rtc */
-	/* USER CODE END rtc */
-};
-
-&sdmmc1{
-	pinctrl-names = "default";
-	pinctrl-0 = <&sdmmc1_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN sdmmc1 */
-	/* USER CODE END sdmmc1 */
-};
-
-&uart4{
-	pinctrl-names = "default";
-	pinctrl-0 = <&uart4_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN uart4 */
-	/* USER CODE END uart4 */
-};
-
-&usbotg_hs{
-	pinctrl-names = "default";
-	pinctrl-0 = <&usb_otg_hs_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN usbotg_hs */
-	/* USER CODE END usbotg_hs */
-};
-
-&usbphyc{
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc */
-	/* USER CODE END usbphyc */
-};
-
-&usbphyc_port0{
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc_port0 */
-	/* USER CODE END usbphyc_port0 */
-};
-
-&usbphyc_port1{
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc_port1 */
-	/* USER CODE END usbphyc_port1 */
-};
-
-/* USER CODE BEGIN addons */
-/* USER CODE END addons */
-
diff --git a/conf/machine/cubemx/t1001-som-minimal/DeviceTree/t1001-som-minimal/u-boot/stm32mp15-mx.h b/conf/machine/cubemx/t1001-som-minimal/DeviceTree/t1001-som-minimal/u-boot/stm32mp15-mx.h
deleted file mode 100644
index e6897cf871f24d9492c58ab0ee152f3b2b6bc429..0000000000000000000000000000000000000000
--- a/conf/machine/cubemx/t1001-som-minimal/DeviceTree/t1001-som-minimal/u-boot/stm32mp15-mx.h
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright (C) 2015-2018, STMicroelectronics - All Rights Reserved
- *
- * SPDX-License-Identifier:	GPL-2.0+	BSD-3-Clause
- *
- */
-
-/*
- * File generated by STMicroelectronics STM32CubeMX DDR Tool for MPUs
- * DDR type: DDR3 / DDR3L
- * DDR width: 16bits
- * DDR density: 4Gb
- * System frequency: 528000Khz
- * Relaxed Timing Mode: false
- * Address mapping type: RBC
- *
- * Save Date: 2019.09.27, save Time: 17:49:09
- */
-
-#define DDR_MEM_NAME	"DDR3-DDR3L 16bits 528000Khz"
-#define DDR_MEM_SPEED	528000
-#define DDR_MEM_SIZE	0x20000000
-
-#define DDR_MSTR 0x00041401
-#define DDR_MRCTRL0 0x00000010
-#define DDR_MRCTRL1 0x00000000
-#define DDR_DERATEEN 0x00000000
-#define DDR_DERATEINT 0x00800000
-#define DDR_PWRCTL 0x00000000
-#define DDR_PWRTMG 0x00400010
-#define DDR_HWLPCTL 0x00000000
-#define DDR_RFSHCTL0 0x00210000
-#define DDR_RFSHCTL3 0x00000000
-#define DDR_RFSHTMG 0x0040008A
-#define DDR_CRCPARCTL0 0x00000000
-#define DDR_DRAMTMG0 0x121B1214
-#define DDR_DRAMTMG1 0x000A041B
-#define DDR_DRAMTMG2 0x0607080F
-#define DDR_DRAMTMG3 0x0050400C
-#define DDR_DRAMTMG4 0x07040607
-#define DDR_DRAMTMG5 0x06060403
-#define DDR_DRAMTMG6 0x02020002
-#define DDR_DRAMTMG7 0x00000202
-#define DDR_DRAMTMG8 0x00001005
-#define DDR_DRAMTMG14 0x000000A0
-#define DDR_ZQCTL0 0xC2000040
-#define DDR_DFITMG0 0x02050105
-#define DDR_DFITMG1 0x00000202
-#define DDR_DFILPCFG0 0x07000000
-#define DDR_DFIUPD0 0xC0400003
-#define DDR_DFIUPD1 0x00000000
-#define DDR_DFIUPD2 0x00000000
-#define DDR_DFIPHYMSTR 0x00000000
-#define DDR_ODTCFG 0x06000600
-#define DDR_ODTMAP 0x00000001
-#define DDR_SCHED 0x00000C01
-#define DDR_SCHED1 0x00000000
-#define DDR_PERFHPR1 0x01000001
-#define DDR_PERFLPR1 0x08000200
-#define DDR_PERFWR1 0x08000400
-#define DDR_DBG0 0x00000000
-#define DDR_DBG1 0x00000000
-#define DDR_DBGCMD 0x00000000
-#define DDR_POISONCFG 0x00000000
-#define DDR_PCCFG 0x00000010
-#define DDR_PCFGR_0 0x00010000
-#define DDR_PCFGW_0 0x00000000
-#define DDR_PCFGQOS0_0 0x02100C03
-#define DDR_PCFGQOS1_0 0x00800100
-#define DDR_PCFGWQOS0_0 0x01100C03
-#define DDR_PCFGWQOS1_0 0x01000200
-#define DDR_PCFGR_1 0x00010000
-#define DDR_PCFGW_1 0x00000000
-#define DDR_PCFGQOS0_1 0x02100C03
-#define DDR_PCFGQOS1_1 0x00800040
-#define DDR_PCFGWQOS0_1 0x01100C03
-#define DDR_PCFGWQOS1_1 0x01000200
-#define DDR_ADDRMAP1 0x00070707
-#define DDR_ADDRMAP2 0x00000000
-#define DDR_ADDRMAP3 0x1F000000
-#define DDR_ADDRMAP4 0x00001F1F
-#define DDR_ADDRMAP5 0x06060606
-#define DDR_ADDRMAP6 0x0F060606
-#define DDR_ADDRMAP9 0x00000000
-#define DDR_ADDRMAP10 0x00000000
-#define DDR_ADDRMAP11 0x00000000
-#define DDR_PGCR 0x01442E02
-#define DDR_PTR0 0x0022A41B
-#define DDR_PTR1 0x047C0740
-#define DDR_PTR2 0x042D9C80
-#define DDR_ACIOCR 0x10400812
-#define DDR_DXCCR 0x00000C40
-#define DDR_DSGCR 0xF200001F
-#define DDR_DCR 0x0000000B
-#define DDR_DTPR0 0x36D477D0
-#define DDR_DTPR1 0x098A00D8
-#define DDR_DTPR2 0x10023600
-#define DDR_MR0 0x00000830
-#define DDR_MR1 0x00000000
-#define DDR_MR2 0x00000248
-#define DDR_MR3 0x00000000
-#define DDR_ODTCR 0x00010000
-#define DDR_ZQ0CR1 0x00000038
-#define DDR_DX0GCR 0x0000CE81
-#define DDR_DX0DLLCR 0x40000000
-#define DDR_DX0DQTR 0x55050005
-#define DDR_DX0DQSTR 0x3D202000
-#define DDR_DX1GCR 0x0000CE81
-#define DDR_DX1DLLCR 0x40000000
-#define DDR_DX1DQTR 0x00050500
-#define DDR_DX1DQSTR 0x3DB02000
-#define DDR_DX2GCR 0x0000C881
-#define DDR_DX2DLLCR 0x40000000
-#define DDR_DX2DQTR 0xFFFFFFFF
-#define DDR_DX2DQSTR 0x3DB02000
-#define DDR_DX3GCR 0x0000C881
-#define DDR_DX3DLLCR 0x40000000
-#define DDR_DX3DQTR 0xFFFFFFFF
-#define DDR_DX3DQSTR 0x3DB02000
diff --git a/conf/machine/cubemx/t1001-som-minimal/DeviceTree/t1001-som-minimal/u-boot/stm32mp157c-t1001-som-minimal-mx-u-boot.dtsi b/conf/machine/cubemx/t1001-som-minimal/DeviceTree/t1001-som-minimal/u-boot/stm32mp157c-t1001-som-minimal-mx-u-boot.dtsi
deleted file mode 100644
index 96c8430a24326975c6fe461bda86533452b7973a..0000000000000000000000000000000000000000
--- a/conf/machine/cubemx/t1001-som-minimal/DeviceTree/t1001-som-minimal/u-boot/stm32mp157c-t1001-som-minimal-mx-u-boot.dtsi
+++ /dev/null
@@ -1,182 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause*/
-/*
- * Copyright (C) 2019, STMicroelectronics - All Rights Reserved
- * Author: STM32CubeMX code generation for STMicroelectronics.
- */
-
-#include <dt-bindings/clock/stm32mp1-clksrc.h>
-#include "stm32mp15-mx.h"
-
-#include "stm32mp157-u-boot.dtsi"
-#include "stm32mp15-ddr.dtsi"
-
-/* USER CODE BEGIN includes */
-/* USER CODE END includes */
-
-/ {
-
-	/* USER CODE BEGIN root */
-	/* USER CODE END root */
-
-	clocks {
-		/* USER CODE BEGIN clocks */
-		/* USER CODE END clocks */
-
-		clk_csi: clk-csi {
-			/* USER CODE BEGIN clocks */
-			/* USER CODE END clocks */
-			u-boot,dm-pre-reloc;
-		};
-
-		clk_lse: clk-lse {
-			/* USER CODE BEGIN clocks */
-			/* USER CODE END clocks */
-			st,drive=<LSEDRV_MEDIUM_HIGH>;
-			u-boot,dm-pre-reloc;
-		};
-
-		clk_hse: clk-hse {
-			/* USER CODE BEGIN clocks */
-			/* USER CODE END clocks */
-			u-boot,dm-pre-reloc;
-		};
-	};
-
-}; /*root*/
-
-&rcc {
-	u-boot,dm-pre-reloc;
-	st,clksrc = <
-		CLK_MPU_PLL1P
-		CLK_AXI_PLL2P
-		CLK_MCU_PLL3P
-		CLK_PLL12_HSE
-		CLK_PLL3_HSE
-		CLK_PLL4_HSE
-		CLK_RTC_LSE
-		CLK_MCO1_DISABLED
-		CLK_MCO2_DISABLED
-	>;
-	st,clkdiv = <
-		1 		/*MPU*/
-		0 		/*AXI*/
-		0 		/*MCU*/
-		1 		/*APB1*/
-		1 		/*APB2*/
-		1 		/*APB3*/
-		1 		/*APB4*/
-		2 		/*APB5*/
-		0 		/*RTC*/
-		0 		/*MCO1*/
-		0 		/*MCO2*/
-	>;
-	st,pkcs = <
-		CLK_CKPER_HSE
-		CLK_QSPI_ACLK
-		CLK_ETH_DISABLED
-		CLK_SDMMC12_PLL4P
-		CLK_STGEN_HSE
-		CLK_USBPHY_HSE
-		CLK_SPI2S1_DISABLED
-		CLK_SPI2S23_DISABLED
-		CLK_SPI45_DISABLED
-		CLK_SPI6_DISABLED
-		CLK_I2C46_DISABLED
-		CLK_SDMMC3_DISABLED
-		CLK_USBO_USBPHY
-		CLK_ADC_CKPER
-		CLK_CEC_DISABLED
-		CLK_I2C12_DISABLED
-		CLK_I2C35_DISABLED
-		CLK_UART1_DISABLED
-		CLK_UART24_PCLK1
-		CLK_UART35_DISABLED
-		CLK_UART6_DISABLED
-		CLK_UART78_DISABLED
-		CLK_SPDIF_DISABLED
-		CLK_SAI1_DISABLED
-		CLK_SAI2_DISABLED
-		CLK_SAI3_DISABLED
-		CLK_SAI4_DISABLED
-		CLK_RNG1_CSI
-		CLK_LPTIM1_DISABLED
-		CLK_LPTIM23_DISABLED
-		CLK_LPTIM45_DISABLED
-	>;
-	pll1:st,pll@0 {
-		cfg = < 2 80 0 1 1 1>;
-		u-boot,dm-pre-reloc;
-	};
-	pll2:st,pll@1 {
-		cfg = < 2 65 1 1 0 7>;
-		u-boot,dm-pre-reloc;
-	};
-	pll3:st,pll@2 {
-		cfg = < 1 49 2 2 1 1>;
-		u-boot,dm-pre-reloc;
-	};
-	pll4:st,pll@3 {
-		cfg = < 5 124 9 9 9 1>;
-		u-boot,dm-pre-reloc;
-	};
-};
-
-&qspi{
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN qspi */
-	/* USER CODE END qspi */
-};
-
-&rcc{
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN rcc */
-	/* USER CODE END rcc */
-};
-
-&sdmmc1{
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN sdmmc1 */
-	/* USER CODE END sdmmc1 */
-};
-
-&uart4{
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN uart4 */
-	/* USER CODE END uart4 */
-};
-
-&usbotg_hs{
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN usbotg_hs */
-	/* USER CODE END usbotg_hs */
-};
-
-&usbphyc{
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN usbphyc */
-	/* USER CODE END usbphyc */
-};
-
-&usbphyc_port0{
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN usbphyc_port0 */
-	/* USER CODE END usbphyc_port0 */
-};
-
-&usbphyc_port1{
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN usbphyc_port1 */
-	/* USER CODE END usbphyc_port1 */
-};
-
-/* USER CODE BEGIN addons */
-/* USER CODE END addons */
-
diff --git a/conf/machine/cubemx/t1001-som-minimal/DeviceTree/t1001-som-minimal/u-boot/stm32mp157c-t1001-som-minimal-mx.dts b/conf/machine/cubemx/t1001-som-minimal/DeviceTree/t1001-som-minimal/u-boot/stm32mp157c-t1001-som-minimal-mx.dts
deleted file mode 100644
index a7a6c3f479076a30ac6ae7bdc70ceba6f78005f1..0000000000000000000000000000000000000000
--- a/conf/machine/cubemx/t1001-som-minimal/DeviceTree/t1001-som-minimal/u-boot/stm32mp157c-t1001-som-minimal-mx.dts
+++ /dev/null
@@ -1,405 +0,0 @@
-/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
-/*
- * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
- * Author: STM32CubeMX code generation for STMicroelectronics.
- */
-
-/dts-v1/;
-#include "stm32mp157c.dtsi"
-#include "stm32mp157c-m4-srm.dtsi"
-#include "stm32mp157cad-pinctrl.dtsi"
-
-/* USER CODE BEGIN includes */
-/* USER CODE END includes */
-
-/ {
-	model = "STMicroelectronics custom STM32CubeMX board";
-	compatible = "st,stm32mp157c-t1001-som-minimal-mx", "st,stm32mp157";
-
-	memory@c0000000 {
-		reg = <0xc0000000 0x20000000>;
-
-		/* USER CODE BEGIN memory */
-		/* USER CODE END memory */
-	};
-
-	reserved-memory {
-		#address-cells = <1>;
-		#size-cells = <1>;
-		ranges;
-
-		/* USER CODE BEGIN reserved-memory */
-		/* USER CODE END reserved-memory */
-
-		gpu_reserved: gpu@dc000000 {
-			reg = <0xdc000000 0x4000000>;
-			no-map;
-		};
-	};
-
-	/* USER CODE BEGIN root */
-	/* USER CODE END root */
-
-	clocks {
-		/* USER CODE BEGIN clocks */
-		/* USER CODE END clocks */
-
-		clk_csi: clk-csi {
-			clock-frequency = <4000000>;
-		};
-
-		clk_lse: clk-lse {
-			clock-frequency = <32768>;
-		};
-
-		clk_hse: clk-hse {
-			clock-frequency = <24000000>;
-		};
-	};
-
-}; /*root*/
-
-&pinctrl {
-	u-boot,dm-pre-reloc;
-
-	quadspi_pins_mx: quadspi_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 6, AF10)>; /* QUADSPI_BK1_NCS */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('F', 6, AF9)>, /* QUADSPI_BK1_IO3 */
-					 <STM32_PINMUX('F', 7, AF9)>, /* QUADSPI_BK1_IO2 */
-					 <STM32_PINMUX('F', 8, AF10)>, /* QUADSPI_BK1_IO0 */
-					 <STM32_PINMUX('F', 9, AF10)>, /* QUADSPI_BK1_IO1 */
-					 <STM32_PINMUX('F', 10, AF9)>; /* QUADSPI_CLK */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-	};
-
-	quadspi_sleep_pins_mx: quadspi_sleep_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 6, ANALOG)>, /* QUADSPI_BK1_NCS */
-					 <STM32_PINMUX('F', 6, ANALOG)>, /* QUADSPI_BK1_IO3 */
-					 <STM32_PINMUX('F', 7, ANALOG)>, /* QUADSPI_BK1_IO2 */
-					 <STM32_PINMUX('F', 8, ANALOG)>, /* QUADSPI_BK1_IO0 */
-					 <STM32_PINMUX('F', 9, ANALOG)>, /* QUADSPI_BK1_IO1 */
-					 <STM32_PINMUX('F', 10, ANALOG)>; /* QUADSPI_CLK */
-		};
-	};
-
-	sdmmc1_pins_mx: sdmmc1_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
-					 <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
-					 <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
-					 <STM32_PINMUX('C', 11, AF12)>, /* SDMMC1_D3 */
-					 <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 12, AF12)>; /* SDMMC1_CK */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-	};
-
-	sdmmc1_opendrain_pins_mx: sdmmc1_opendrain_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
-					 <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
-					 <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
-					 <STM32_PINMUX('C', 11, AF12)>; /* SDMMC1_D3 */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 12, AF12)>; /* SDMMC1_CK */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins3 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
-			bias-pull-up;
-			drive-open-drain;
-			slew-rate = <1>;
-		};
-	};
-
-	sdmmc1_sleep_pins_mx: sdmmc1_sleep_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 8, ANALOG)>, /* SDMMC1_D0 */
-					 <STM32_PINMUX('C', 9, ANALOG)>, /* SDMMC1_D1 */
-					 <STM32_PINMUX('C', 10, ANALOG)>, /* SDMMC1_D2 */
-					 <STM32_PINMUX('C', 11, ANALOG)>, /* SDMMC1_D3 */
-					 <STM32_PINMUX('C', 12, ANALOG)>, /* SDMMC1_CK */
-					 <STM32_PINMUX('D', 2, ANALOG)>; /* SDMMC1_CMD */
-		};
-	};
-
-	uart4_pins_mx: uart4_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 2, AF8)>; /* UART4_RX */
-			bias-pull-up;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('G', 11, AF6)>; /* UART4_TX */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-	};
-
-	uart4_sleep_pins_mx: uart4_sleep_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 2, ANALOG)>, /* UART4_RX */
-					 <STM32_PINMUX('G', 11, ANALOG)>; /* UART4_TX */
-		};
-	};
-
-	usb_otg_hs_pins_mx: usb_otg_hs_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
-		};
-	};
-
-	usb_otg_hs_sleep_pins_mx: usb_otg_hs_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
-		};
-	};
-
-	/* USER CODE BEGIN pinctrl */
-	/* USER CODE END pinctrl */
-};
-
-&pinctrl_z {
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN pinctrl_z */
-	/* USER CODE END pinctrl_z */
-};
-
-&m4_rproc{
-	mboxes = <&ipcc 0>, <&ipcc 1>, <&ipcc 2>;
-	mbox-names = "vq0", "vq1", "shutdown";
-	recovery;
-	status = "okay";
-
-	/* USER CODE BEGIN m4_rproc */
-	/* USER CODE END m4_rproc */
-};
-
-&adc{
-	status = "okay";
-
-	/* USER CODE BEGIN adc */
-	/* USER CODE END adc */
-};
-
-&bsec{
-	status = "okay";
-
-	/* USER CODE BEGIN bsec */
-	/* USER CODE END bsec */
-};
-
-&crc1{
-	status = "okay";
-
-	/* USER CODE BEGIN crc1 */
-	/* USER CODE END crc1 */
-};
-
-&cryp1{
-	status = "okay";
-
-	/* USER CODE BEGIN cryp1 */
-	/* USER CODE END cryp1 */
-};
-
-&dts{
-	status = "okay";
-
-	/* USER CODE BEGIN dts */
-	/* USER CODE END dts */
-};
-
-&gpu{
-	status = "okay";
-
-	/* USER CODE BEGIN gpu */
-	/* USER CODE END gpu */
-};
-
-&hash1{
-	status = "okay";
-
-	/* USER CODE BEGIN hash1 */
-	/* USER CODE END hash1 */
-};
-
-&hsem{
-	status = "okay";
-
-	/* USER CODE BEGIN hsem */
-	/* USER CODE END hsem */
-};
-
-&ipcc{
-	status = "okay";
-
-	/* USER CODE BEGIN ipcc */
-	/* USER CODE END ipcc */
-};
-
-&iwdg2{
-	status = "okay";
-
-	/* USER CODE BEGIN iwdg2 */
-	/* USER CODE END iwdg2 */
-};
-
-&qspi{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&quadspi_pins_mx>;
-	pinctrl-1 = <&quadspi_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN qspi */
-	/* USER CODE END qspi */
-};
-
-&rcc{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN rcc */
-	/* USER CODE END rcc */
-};
-
-&rng1{
-	status = "okay";
-
-	/* USER CODE BEGIN rng1 */
-	/* USER CODE END rng1 */
-};
-
-&rtc{
-	status = "okay";
-
-	/* USER CODE BEGIN rtc */
-	/* USER CODE END rtc */
-};
-
-&sdmmc1{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "opendrain", "sleep";
-	pinctrl-0 = <&sdmmc1_pins_mx>;
-	pinctrl-1 = <&sdmmc1_opendrain_pins_mx>;
-	pinctrl-2 = <&sdmmc1_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN sdmmc1 */
-	/* USER CODE END sdmmc1 */
-};
-
-&uart4{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&uart4_pins_mx>;
-	pinctrl-1 = <&uart4_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN uart4 */
-	/* USER CODE END uart4 */
-};
-
-&usbh_ehci{
-	status = "okay";
-
-	/* USER CODE BEGIN usbh_ehci */
-	/* USER CODE END usbh_ehci */
-};
-
-&usbh_ohci{
-	status = "okay";
-
-	/* USER CODE BEGIN usbh_ohci */
-	/* USER CODE END usbh_ohci */
-};
-
-&usbotg_hs{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&usb_otg_hs_pins_mx>;
-	pinctrl-1 = <&usb_otg_hs_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN usbotg_hs */
-	/* USER CODE END usbotg_hs */
-};
-
-&usbphyc{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc */
-	/* USER CODE END usbphyc */
-};
-
-&usbphyc_port0{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc_port0 */
-	/* USER CODE END usbphyc_port0 */
-};
-
-&usbphyc_port1{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc_port1 */
-	/* USER CODE END usbphyc_port1 */
-};
-
-&vrefbuf{
-	status = "okay";
-
-	/* USER CODE BEGIN vrefbuf */
-	/* USER CODE END vrefbuf */
-};
-
-/* USER CODE BEGIN addons */
-/* USER CODE END addons */
-
diff --git a/conf/machine/cubemx/t1001-som-minimal/t1001-som-minimal.ioc b/conf/machine/cubemx/t1001-som-minimal/t1001-som-minimal.ioc
deleted file mode 100644
index b6e64547a5e29b3b4f96dc376edf376d06b70980..0000000000000000000000000000000000000000
--- a/conf/machine/cubemx/t1001-som-minimal/t1001-som-minimal.ioc
+++ /dev/null
@@ -1,1008 +0,0 @@
-#MicroXplorer Configuration settings - do not modify
-ADC2.Channel-0\#ChannelRegularConversion=ADC_CHANNEL_VBAT
-ADC2.IPParameters=Rank-0\#ChannelRegularConversion,Channel-0\#ChannelRegularConversion,SamplingTime-0\#ChannelRegularConversion,OffsetNumber-0\#ChannelRegularConversion,NbrOfConversionFlag
-ADC2.NbrOfConversionFlag=1
-ADC2.OffsetNumber-0\#ChannelRegularConversion=ADC_OFFSET_NONE
-ADC2.Rank-0\#ChannelRegularConversion=1
-ADC2.SamplingTime-0\#ChannelRegularConversion=ADC_SAMPLETIME_1CYCLE_5
-BootLoader.IPs=RCC,QUADSPI,SDMMC1,UART4,USB_OTG_HS
-BootROM.IPs=RCC,SDMMC1\:I,UART4\:I
-CortexA7NS.IPs=IWDG2\:I,BSEC,DDR\:I,ETZPC,HSEM\:I,IPCC\:I,PWR,RCC\:I,RTC,TAMP\:I,DMA\:I,GIC,ADC1\:I,ADC2\:I,QUADSPI\:I,SDMMC1,UART4,USBH_HS1\:I,USB_OTG_HS\:I,GPU\:I,CRYP1\:I,HASH1\:I,RNG1,CRC1\:I,DEBUG\:I,DTS\:I,VREFBUF\:I,DMA1\:I,MDMA_A7NS\:I
-CortexA7S.IPs=BSEC\:I,ETZPC\:I,PWR\:I,RCC,RNG1\:I,RTC\:I,GIC\:I,IWDG2,MDMA_A7S\:I
-CortexM4.IPs=HSEM,IPCC,ETZPC,FREERTOS\:I,PWR,RCC,SYS\:I,DMA,NVIC\:I,DMA2\:I
-DDR.0dqdly0=1
-DDR.0dqdly1=0
-DDR.0dqdly2=0
-DDR.0dqdly3=0
-DDR.0dqdly4=1
-DDR.0dqdly5=0
-DDR.0dqdly6=1
-DDR.0dqdly7=1
-DDR.0dqsdly=2
-DDR.0dqsndly=2
-DDR.1dqdly0=0
-DDR.1dqdly1=0
-DDR.1dqdly2=1
-DDR.1dqdly3=0
-DDR.1dqdly4=1
-DDR.1dqdly5=0
-DDR.1dqdly6=0
-DDR.1dqdly7=0
-DDR.ADDRMAP1=0x00070707
-DDR.ADDRMAP3=0x1F000000
-DDR.ADDRMAP5=0x06060606
-DDR.ADDRMAP6=0x0F060606
-DDR.CL=7
-DDR.DDR_Frequency=528.0
-DDR.DFITMG0=0x02050105
-DDR.DRAMTMG0=0x121B1214
-DDR.DRAMTMG1=0x000A041B
-DDR.DRAMTMG2=0x0607080F
-DDR.DRAMTMG4=0x07040607
-DDR.DTPR0=0x36D477D0
-DDR.DTPR1=0x098A00D8
-DDR.DX0DQSTR=0x3D202000
-DDR.DX0DQTR=0x55050005
-DDR.DX1DQTR=0x00050500
-DDR.IPParameters=DDR_Frequency,CL,addrmap_col_b9,addrmap_col_b10,addrmap_col_b11,addrmap_bank_b0,addrmap_bank_b1,addrmap_bank_b2,addrmap_row_b0,addrmap_row_b1,addrmap_row_b2_10,addrmap_row_b11,addrmap_row_b12,addrmap_row_b13,addrmap_row_b14,addrmap_row_b15,MSTR,RFSHTMG,DRAMTMG1,DRAMTMG2,DRAMTMG4,SCHED,ADDRMAP1,ADDRMAP3,ADDRMAP5,ADDRMAP6,PTR0,PTR1,PTR2,DTPR0,DTPR1,MR0,SPEED_BIN_GRADE,tRCD,tRP,tRC,wr2pre,t_faw,t_ras_max,t_ras_min,t_xp,t_rd2pre,t_rp,t_rc,write_latency,read_latency,wr2rd,t_rcd,t_rrd,t_cksrx,t_cksre,t_ckesr,t_cke,t_xs_dll_x32,t_xs_x32,t_rfc_nom_x1_x32,t_rfc_min,dfi_t_rddata_en,dfi_tphy_wrlat,tdlllock,tdllsrst,tdinit1,tdinit0,tdinit2,tccd,trc,trrd,tras,trcd,trp,twtr,trtp,tmrd,trfc,tmod,tfaw,tdllk,tcke,txp,txs,MR0.WR,MR0.CL,MR2.RTT,MR2.CWL,data_bus_width,DFITMG0,TEMPERATURE_OVER_85C,tREFI,DRAMTMG0,MR2,0dqsndly,0dqsdly,0dqdly0,0dqdly1,0dqdly2,0dqdly3,0dqdly4,0dqdly5,0dqdly6,0dqdly7,1dqdly0,1dqdly1,1dqdly2,1dqdly3,1dqdly4,1dqdly5,1dqdly6,1dqdly7,DX0DQTR,DX0DQSTR,DX1DQTR
-DDR.MR0=0x00000830
-DDR.MR0.CL=3
-DDR.MR0.WR=4
-DDR.MR2=0x00000248
-DDR.MR2.CWL=1
-DDR.MR2.RTT=1
-DDR.MSTR=0x00041401
-DDR.PTR0=0x0022A41B
-DDR.PTR1=0x047C0740
-DDR.PTR2=0x042D9C80
-DDR.RFSHTMG=0x0040008A
-DDR.SCHED=0x00000C01
-DDR.SPEED_BIN_GRADE=SPEED BIN GRADE CONFIG1
-DDR.TEMPERATURE_OVER_85C=true
-DDR.addrmap_bank_b0=7
-DDR.addrmap_bank_b1=7
-DDR.addrmap_bank_b2=7
-DDR.addrmap_col_b10=31
-DDR.addrmap_col_b11=31
-DDR.addrmap_col_b9=31
-DDR.addrmap_row_b0=6
-DDR.addrmap_row_b1=6
-DDR.addrmap_row_b11=6
-DDR.addrmap_row_b12=6
-DDR.addrmap_row_b13=6
-DDR.addrmap_row_b14=6
-DDR.addrmap_row_b15=15
-DDR.addrmap_row_b2_10=6
-DDR.data_bus_width=1
-DDR.dfi_t_rddata_en=5
-DDR.dfi_tphy_wrlat=5
-DDR.read_latency=7
-DDR.tRC=50.625
-DDR.tRCD=13.125
-DDR.tREFI=3.9
-DDR.tRP=13.125
-DDR.t_cke=3
-DDR.t_ckesr=4
-DDR.t_cksre=6
-DDR.t_cksrx=6
-DDR.t_faw=27
-DDR.t_ras_max=18
-DDR.t_ras_min=20
-DDR.t_rc=27
-DDR.t_rcd=7
-DDR.t_rd2pre=4
-DDR.t_rfc_min=138
-DDR.t_rfc_nom_x1_x32=64
-DDR.t_rp=7
-DDR.t_rrd=6
-DDR.t_xp=10
-DDR.t_xs_dll_x32=16
-DDR.t_xs_x32=5
-DDR.tccd=0
-DDR.tcke=4
-DDR.tdinit0=264000
-DDR.tdinit1=143
-DDR.tdinit2=105600
-DDR.tdllk=512
-DDR.tdlllock=2704
-DDR.tdllsrst=27
-DDR.tfaw=27
-DDR.tmod=0
-DDR.tmrd=0
-DDR.tras=20
-DDR.trc=27
-DDR.trcd=7
-DDR.trfc=138
-DDR.trp=7
-DDR.trrd=6
-DDR.trtp=4
-DDR.twtr=6
-DDR.txp=13
-DDR.txs=512
-DDR.wr2pre=18
-DDR.wr2rd=15
-DDR.write_latency=6
-DDR_A0.GPIOParameters=GPIO_Label
-DDR_A0.GPIO_Label=DDR Memory
-DDR_A0.Locked=true
-DDR_A0.Mode=DDR3
-DDR_A0.Signal=DDR_A0
-DDR_A1.GPIOParameters=GPIO_Label
-DDR_A1.GPIO_Label=DDR Memory
-DDR_A1.Locked=true
-DDR_A1.Mode=DDR3
-DDR_A1.Signal=DDR_A1
-DDR_A10.GPIOParameters=GPIO_Label
-DDR_A10.GPIO_Label=DDR Memory
-DDR_A10.Locked=true
-DDR_A10.Mode=DDR3
-DDR_A10.Signal=DDR_A10
-DDR_A11.GPIOParameters=GPIO_Label
-DDR_A11.GPIO_Label=DDR Memory
-DDR_A11.Locked=true
-DDR_A11.Mode=DDR3
-DDR_A11.Signal=DDR_A11
-DDR_A12.GPIOParameters=GPIO_Label
-DDR_A12.GPIO_Label=DDR Memory
-DDR_A12.Locked=true
-DDR_A12.Mode=4Gb_16bits
-DDR_A12.Signal=DDR_A12
-DDR_A13.GPIOParameters=GPIO_Label
-DDR_A13.GPIO_Label=DDR Memory
-DDR_A13.Locked=true
-DDR_A13.Mode=4Gb_16bits
-DDR_A13.Signal=DDR_A13
-DDR_A14.GPIOParameters=GPIO_Label
-DDR_A14.GPIO_Label=DDR Memory
-DDR_A14.Locked=true
-DDR_A14.Mode=4Gb_16bits
-DDR_A14.Signal=DDR_A14
-DDR_A2.GPIOParameters=GPIO_Label
-DDR_A2.GPIO_Label=DDR Memory
-DDR_A2.Locked=true
-DDR_A2.Mode=DDR3
-DDR_A2.Signal=DDR_A2
-DDR_A3.GPIOParameters=GPIO_Label
-DDR_A3.GPIO_Label=DDR Memory
-DDR_A3.Locked=true
-DDR_A3.Mode=DDR3
-DDR_A3.Signal=DDR_A3
-DDR_A4.GPIOParameters=GPIO_Label
-DDR_A4.GPIO_Label=DDR Memory
-DDR_A4.Locked=true
-DDR_A4.Mode=DDR3
-DDR_A4.Signal=DDR_A4
-DDR_A5.GPIOParameters=GPIO_Label
-DDR_A5.GPIO_Label=DDR Memory
-DDR_A5.Locked=true
-DDR_A5.Mode=DDR3
-DDR_A5.Signal=DDR_A5
-DDR_A6.GPIOParameters=GPIO_Label
-DDR_A6.GPIO_Label=DDR Memory
-DDR_A6.Locked=true
-DDR_A6.Mode=DDR3
-DDR_A6.Signal=DDR_A6
-DDR_A7.GPIOParameters=GPIO_Label
-DDR_A7.GPIO_Label=DDR Memory
-DDR_A7.Locked=true
-DDR_A7.Mode=DDR3
-DDR_A7.Signal=DDR_A7
-DDR_A8.GPIOParameters=GPIO_Label
-DDR_A8.GPIO_Label=DDR Memory
-DDR_A8.Locked=true
-DDR_A8.Mode=DDR3
-DDR_A8.Signal=DDR_A8
-DDR_A9.GPIOParameters=GPIO_Label
-DDR_A9.GPIO_Label=DDR Memory
-DDR_A9.Locked=true
-DDR_A9.Mode=DDR3
-DDR_A9.Signal=DDR_A9
-DDR_ATO.GPIOParameters=GPIO_Label
-DDR_ATO.GPIO_Label=DDR Memory
-DDR_ATO.Locked=true
-DDR_ATO.Mode=DDR3
-DDR_ATO.Signal=DDR_ATO
-DDR_BA0.GPIOParameters=GPIO_Label
-DDR_BA0.GPIO_Label=DDR Memory
-DDR_BA0.Locked=true
-DDR_BA0.Mode=DDR3
-DDR_BA0.Signal=DDR_BA0
-DDR_BA1.GPIOParameters=GPIO_Label
-DDR_BA1.GPIO_Label=DDR Memory
-DDR_BA1.Locked=true
-DDR_BA1.Mode=DDR3
-DDR_BA1.Signal=DDR_BA1
-DDR_BA2.GPIOParameters=GPIO_Label
-DDR_BA2.GPIO_Label=DDR Memory
-DDR_BA2.Locked=true
-DDR_BA2.Mode=DDR3
-DDR_BA2.Signal=DDR_BA2
-DDR_CASN.GPIOParameters=GPIO_Label
-DDR_CASN.GPIO_Label=DDR Memory
-DDR_CASN.Locked=true
-DDR_CASN.Mode=DDR3
-DDR_CASN.Signal=DDR_CASN
-DDR_CKE.GPIOParameters=GPIO_Label
-DDR_CKE.GPIO_Label=DDR Memory
-DDR_CKE.Locked=true
-DDR_CKE.Mode=DDR3
-DDR_CKE.Signal=DDR_CKE
-DDR_CLKN.GPIOParameters=GPIO_Label
-DDR_CLKN.GPIO_Label=DDR Memory
-DDR_CLKN.Locked=true
-DDR_CLKN.Mode=DDR3
-DDR_CLKN.Signal=DDR_CLKN
-DDR_CLKP.GPIOParameters=GPIO_Label
-DDR_CLKP.GPIO_Label=DDR Memory
-DDR_CLKP.Locked=true
-DDR_CLKP.Mode=DDR3
-DDR_CLKP.Signal=DDR_CLKP
-DDR_CSN.GPIOParameters=GPIO_Label
-DDR_CSN.GPIO_Label=DDR Memory
-DDR_CSN.Locked=true
-DDR_CSN.Mode=DDR3
-DDR_CSN.Signal=DDR_CSN
-DDR_DQ0.GPIOParameters=GPIO_Label
-DDR_DQ0.GPIO_Label=DDR Memory
-DDR_DQ0.Locked=true
-DDR_DQ0.Mode=DDR3
-DDR_DQ0.Signal=DDR_DQ0
-DDR_DQ1.GPIOParameters=GPIO_Label
-DDR_DQ1.GPIO_Label=DDR Memory
-DDR_DQ1.Locked=true
-DDR_DQ1.Mode=DDR3
-DDR_DQ1.Signal=DDR_DQ1
-DDR_DQ10.GPIOParameters=GPIO_Label
-DDR_DQ10.GPIO_Label=DDR Memory
-DDR_DQ10.Locked=true
-DDR_DQ10.Mode=DDR3
-DDR_DQ10.Signal=DDR_DQ10
-DDR_DQ11.GPIOParameters=GPIO_Label
-DDR_DQ11.GPIO_Label=DDR Memory
-DDR_DQ11.Locked=true
-DDR_DQ11.Mode=DDR3
-DDR_DQ11.Signal=DDR_DQ11
-DDR_DQ12.GPIOParameters=GPIO_Label
-DDR_DQ12.GPIO_Label=DDR Memory
-DDR_DQ12.Locked=true
-DDR_DQ12.Mode=DDR3
-DDR_DQ12.Signal=DDR_DQ12
-DDR_DQ13.GPIOParameters=GPIO_Label
-DDR_DQ13.GPIO_Label=DDR Memory
-DDR_DQ13.Locked=true
-DDR_DQ13.Mode=DDR3
-DDR_DQ13.Signal=DDR_DQ13
-DDR_DQ14.GPIOParameters=GPIO_Label
-DDR_DQ14.GPIO_Label=DDR Memory
-DDR_DQ14.Locked=true
-DDR_DQ14.Mode=DDR3
-DDR_DQ14.Signal=DDR_DQ14
-DDR_DQ15.GPIOParameters=GPIO_Label
-DDR_DQ15.GPIO_Label=DDR Memory
-DDR_DQ15.Locked=true
-DDR_DQ15.Mode=DDR3
-DDR_DQ15.Signal=DDR_DQ15
-DDR_DQ2.GPIOParameters=GPIO_Label
-DDR_DQ2.GPIO_Label=DDR Memory
-DDR_DQ2.Locked=true
-DDR_DQ2.Mode=DDR3
-DDR_DQ2.Signal=DDR_DQ2
-DDR_DQ3.GPIOParameters=GPIO_Label
-DDR_DQ3.GPIO_Label=DDR Memory
-DDR_DQ3.Locked=true
-DDR_DQ3.Mode=DDR3
-DDR_DQ3.Signal=DDR_DQ3
-DDR_DQ4.GPIOParameters=GPIO_Label
-DDR_DQ4.GPIO_Label=DDR Memory
-DDR_DQ4.Locked=true
-DDR_DQ4.Mode=DDR3
-DDR_DQ4.Signal=DDR_DQ4
-DDR_DQ5.GPIOParameters=GPIO_Label
-DDR_DQ5.GPIO_Label=DDR Memory
-DDR_DQ5.Locked=true
-DDR_DQ5.Mode=DDR3
-DDR_DQ5.Signal=DDR_DQ5
-DDR_DQ6.GPIOParameters=GPIO_Label
-DDR_DQ6.GPIO_Label=DDR Memory
-DDR_DQ6.Locked=true
-DDR_DQ6.Mode=DDR3
-DDR_DQ6.Signal=DDR_DQ6
-DDR_DQ7.GPIOParameters=GPIO_Label
-DDR_DQ7.GPIO_Label=DDR Memory
-DDR_DQ7.Locked=true
-DDR_DQ7.Mode=DDR3
-DDR_DQ7.Signal=DDR_DQ7
-DDR_DQ8.GPIOParameters=GPIO_Label
-DDR_DQ8.GPIO_Label=DDR Memory
-DDR_DQ8.Locked=true
-DDR_DQ8.Mode=DDR3
-DDR_DQ8.Signal=DDR_DQ8
-DDR_DQ9.GPIOParameters=GPIO_Label
-DDR_DQ9.GPIO_Label=DDR Memory
-DDR_DQ9.Locked=true
-DDR_DQ9.Mode=DDR3
-DDR_DQ9.Signal=DDR_DQ9
-DDR_DQM0.GPIOParameters=GPIO_Label
-DDR_DQM0.GPIO_Label=DDR Memory
-DDR_DQM0.Locked=true
-DDR_DQM0.Mode=DDR3
-DDR_DQM0.Signal=DDR_DQM0
-DDR_DQM1.GPIOParameters=GPIO_Label
-DDR_DQM1.GPIO_Label=DDR Memory
-DDR_DQM1.Locked=true
-DDR_DQM1.Mode=DDR3
-DDR_DQM1.Signal=DDR_DQM1
-DDR_DQS0N.GPIOParameters=GPIO_Label
-DDR_DQS0N.GPIO_Label=DDR Memory
-DDR_DQS0N.Locked=true
-DDR_DQS0N.Mode=DDR3
-DDR_DQS0N.Signal=DDR_DQS0N
-DDR_DQS0P.GPIOParameters=GPIO_Label
-DDR_DQS0P.GPIO_Label=DDR Memory
-DDR_DQS0P.Locked=true
-DDR_DQS0P.Mode=DDR3
-DDR_DQS0P.Signal=DDR_DQS0P
-DDR_DQS1N.GPIOParameters=GPIO_Label
-DDR_DQS1N.GPIO_Label=DDR Memory
-DDR_DQS1N.Locked=true
-DDR_DQS1N.Mode=DDR3
-DDR_DQS1N.Signal=DDR_DQS1N
-DDR_DQS1P.GPIOParameters=GPIO_Label
-DDR_DQS1P.GPIO_Label=DDR Memory
-DDR_DQS1P.Locked=true
-DDR_DQS1P.Mode=DDR3
-DDR_DQS1P.Signal=DDR_DQS1P
-DDR_DTO0.GPIOParameters=GPIO_Label
-DDR_DTO0.GPIO_Label=DDR Memory
-DDR_DTO0.Locked=true
-DDR_DTO0.Mode=DDR3
-DDR_DTO0.Signal=DDR_DTO0
-DDR_DTO1.GPIOParameters=GPIO_Label
-DDR_DTO1.GPIO_Label=DDR Memory
-DDR_DTO1.Locked=true
-DDR_DTO1.Mode=DDR3
-DDR_DTO1.Signal=DDR_DTO1
-DDR_ODT.GPIOParameters=GPIO_Label
-DDR_ODT.GPIO_Label=DDR Memory
-DDR_ODT.Locked=true
-DDR_ODT.Mode=DDR3
-DDR_ODT.Signal=DDR_ODT
-DDR_RASN.GPIOParameters=GPIO_Label
-DDR_RASN.GPIO_Label=DDR Memory
-DDR_RASN.Locked=true
-DDR_RASN.Mode=DDR3
-DDR_RASN.Signal=DDR_RASN
-DDR_RESETN.GPIOParameters=GPIO_Label
-DDR_RESETN.GPIO_Label=DDR Memory
-DDR_RESETN.Locked=true
-DDR_RESETN.Mode=DDR3
-DDR_RESETN.Signal=DDR_RESETN
-DDR_VREF.GPIOParameters=GPIO_Label
-DDR_VREF.GPIO_Label=DDR Memory
-DDR_VREF.Locked=true
-DDR_VREF.Mode=DDR3
-DDR_VREF.Signal=DDR_VREF
-DDR_WEN.GPIOParameters=GPIO_Label
-DDR_WEN.GPIO_Label=DDR Memory
-DDR_WEN.Locked=true
-DDR_WEN.Mode=DDR3
-DDR_WEN.Signal=DDR_WEN
-DDR_ZQ.GPIOParameters=GPIO_Label
-DDR_ZQ.GPIO_Label=DDR Memory
-DDR_ZQ.Locked=true
-DDR_ZQ.Mode=DDR3
-DDR_ZQ.Signal=DDR_ZQ
-DSIHOST_CKN.GPIOParameters=GPIO_Label
-DSIHOST_CKN.GPIO_Label=DSI
-DSIHOST_CKN.Locked=true
-DSIHOST_CKN.Signal=DSIHOST_CKN
-DSIHOST_CKP.GPIOParameters=GPIO_Label
-DSIHOST_CKP.GPIO_Label=DSI
-DSIHOST_CKP.Locked=true
-DSIHOST_CKP.Signal=DSIHOST_CKP
-DSIHOST_D0N.GPIOParameters=GPIO_Label
-DSIHOST_D0N.GPIO_Label=DSI
-DSIHOST_D0N.Locked=true
-DSIHOST_D0N.Signal=DSIHOST_D0N
-DSIHOST_D0P.GPIOParameters=GPIO_Label
-DSIHOST_D0P.GPIO_Label=DSI
-DSIHOST_D0P.Locked=true
-DSIHOST_D0P.Signal=DSIHOST_D0P
-DSIHOST_D1N.GPIOParameters=GPIO_Label
-DSIHOST_D1N.GPIO_Label=DSI
-DSIHOST_D1N.Locked=true
-DSIHOST_D1N.Signal=DSIHOST_D1N
-DSIHOST_D1P.GPIOParameters=GPIO_Label
-DSIHOST_D1P.GPIO_Label=DSI
-DSIHOST_D1P.Locked=true
-DSIHOST_D1P.Signal=DSIHOST_D1P
-File.Version=6
-GIC.ADC2_IRQn=true\:false\:High level
-GIC.CRYP1_IRQn=true\:false\:High level
-GIC.DTS_IRQn=true\:false\:High level
-GIC.GPU_IRQn=true\:false\:High level
-GIC.HASH1_IRQn=true\:false\:High level
-GIC.IPCC_RX0_IRQn=true\:false\:High level
-GIC.IPCC_TX0_IRQn=true\:false\:High level
-GIC.OTG_IRQn=true\:false\:High level
-GIC.PMUIRQ0_IRQn=true\:false\:High level
-GIC.PMUIRQ1_IRQn=true\:false\:High level
-GIC.QUADSPI_IRQn=true\:false\:High level
-GIC.RCC_IRQn=true\:false\:High level
-GIC.RTC_WKUP_ALARM_IRQn=true\:false\:High level
-GIC.SDMMC1_IRQn=true\:false\:High level
-GIC.UART4_IRQn=true\:false\:High level
-GIC.USBH_OHCI_IRQn=true\:false\:High level
-JTCK-SWCLK.GPIOParameters=GPIO_Label
-JTCK-SWCLK.GPIO_Label=JTAG Debug
-JTCK-SWCLK.Locked=true
-JTCK-SWCLK.Mode=JTAG_5_pins
-JTCK-SWCLK.Signal=DEBUG_JTCK-SWCLK
-JTDI.GPIOParameters=GPIO_Label
-JTDI.GPIO_Label=JTAG Debug
-JTDI.Locked=true
-JTDI.Mode=JTAG_5_pins
-JTDI.Signal=DEBUG_JTDI
-JTDO-TRACESWO.GPIOParameters=GPIO_Label
-JTDO-TRACESWO.GPIO_Label=JTAG Debug
-JTDO-TRACESWO.Locked=true
-JTDO-TRACESWO.Mode=JTAG_5_pins
-JTDO-TRACESWO.Signal=DEBUG_JTDO-SWO
-JTMS-SWDIO.GPIOParameters=GPIO_Label
-JTMS-SWDIO.GPIO_Label=JTAG Debug
-JTMS-SWDIO.Locked=true
-JTMS-SWDIO.Mode=JTAG_5_pins
-JTMS-SWDIO.Signal=DEBUG_JTMS-SWDIO
-KeepUserPlacement=false
-Mcu.Context0=BootROM
-Mcu.Context1=BootLoader
-Mcu.Context2=CortexA7S
-Mcu.Context3=CortexA7NS
-Mcu.Context4=CortexM4
-Mcu.ContextNb=5
-Mcu.Family=STM32MP1
-Mcu.IP0=ADC2
-Mcu.IP1=BSEC
-Mcu.IP10=HASH1
-Mcu.IP11=HSEM
-Mcu.IP12=IPCC
-Mcu.IP13=IWDG2
-Mcu.IP14=NVIC
-Mcu.IP15=QUADSPI
-Mcu.IP16=RCC
-Mcu.IP17=RNG1
-Mcu.IP18=RTC
-Mcu.IP19=SDMMC1
-Mcu.IP2=CRC1
-Mcu.IP20=SYS
-Mcu.IP21=UART4
-Mcu.IP22=USBH_HS1
-Mcu.IP23=USB_OTG_HS
-Mcu.IP24=VREFBUF
-Mcu.IP3=CRYP1
-Mcu.IP4=DDR
-Mcu.IP5=DEBUG
-Mcu.IP6=DTS
-Mcu.IP7=ETZPC
-Mcu.IP8=GIC
-Mcu.IP9=GPU
-Mcu.IPNb=25
-Mcu.Name=STM32MP157CADx
-Mcu.Package=TFBGA257
-Mcu.Pin0=PC8
-Mcu.Pin1=DSIHOST_CKP
-Mcu.Pin10=DSIHOST_CKN
-Mcu.Pin100=VP_DDR_DDR3_16_4Gb
-Mcu.Pin101=VP_DTS_VS_DTS
-Mcu.Pin102=VP_ETZPC_VS_ETZPC
-Mcu.Pin103=VP_GPU_VS_GPU
-Mcu.Pin104=VP_HASH1_VS_HASH
-Mcu.Pin105=VP_HSEM_VS_HSEM
-Mcu.Pin106=VP_IPCC_VS_IPCC
-Mcu.Pin107=VP_IWDG2_VS_IWDG
-Mcu.Pin108=VP_RNG1_VS_RNG
-Mcu.Pin109=VP_RTC_VS_RTC_Activate
-Mcu.Pin11=DSIHOST_D1N
-Mcu.Pin110=VP_SYS_VS_Systick
-Mcu.Pin111=VP_VREFBUF_VS_VREFBUF
-Mcu.Pin112=VP_DMA_VS_DMA1_A7NS
-Mcu.Pin113=VP_DMA_VS_DMA2_M4
-Mcu.Pin114=VP_MDMA_VS_MDMA_A7NS_8
-Mcu.Pin12=NJTRST
-Mcu.Pin13=JTDI
-Mcu.Pin14=DDR_DQ3
-Mcu.Pin15=DDR_DQ7
-Mcu.Pin16=DDR_DQS0N
-Mcu.Pin17=DDR_DQS0P
-Mcu.Pin18=PC11
-Mcu.Pin19=DSIHOST_D0N
-Mcu.Pin2=DSIHOST_D1P
-Mcu.Pin20=JTMS-SWDIO
-Mcu.Pin21=DDR_RESETN
-Mcu.Pin22=DDR_DQM0
-Mcu.Pin23=DDR_DQ2
-Mcu.Pin24=DDR_DQ6
-Mcu.Pin25=DDR_DQ4
-Mcu.Pin26=DDR_DQ5
-Mcu.Pin27=DDR_A13
-Mcu.Pin28=DDR_A9
-Mcu.Pin29=PC15-OSC32_OUT
-Mcu.Pin3=JTDO-TRACESWO
-Mcu.Pin30=DDR_A2
-Mcu.Pin31=DDR_A3
-Mcu.Pin32=PC14-OSC32_IN
-Mcu.Pin33=DDR_A0
-Mcu.Pin34=DDR_BA0
-Mcu.Pin35=PH0-OSC_IN
-Mcu.Pin36=DDR_BA2
-Mcu.Pin37=DDR_ODT
-Mcu.Pin38=PH1-OSC_OUT
-Mcu.Pin39=DDR_CSN
-Mcu.Pin4=JTCK-SWCLK
-Mcu.Pin40=DDR_WEN
-Mcu.Pin41=DDR_CASN
-Mcu.Pin42=DDR_CLKN
-Mcu.Pin43=PA13
-Mcu.Pin44=DDR_CLKP
-Mcu.Pin45=DDR_A10
-Mcu.Pin46=DDR_A12
-Mcu.Pin47=DDR_A1
-Mcu.Pin48=DDR_A14
-Mcu.Pin49=DDR_A11
-Mcu.Pin5=DDR_DQ0
-Mcu.Pin50=DDR_CKE
-Mcu.Pin51=DDR_BA1
-Mcu.Pin52=DDR_A4
-Mcu.Pin53=DDR_DQ8
-Mcu.Pin54=DDR_A8
-Mcu.Pin55=DDR_DQ13
-Mcu.Pin56=DDR_DQ10
-Mcu.Pin57=PG11
-Mcu.Pin58=PF6
-Mcu.Pin59=PA10
-Mcu.Pin6=DDR_DQ1
-Mcu.Pin60=DDR_DQ14
-Mcu.Pin61=DDR_DQS1N
-Mcu.Pin62=DDR_DQ9
-Mcu.Pin63=PF8
-Mcu.Pin64=PF9
-Mcu.Pin65=USB_DP2
-Mcu.Pin66=PB2
-Mcu.Pin67=USB_DP1
-Mcu.Pin68=OTG_VBUS
-Mcu.Pin69=DDR_DQ15
-Mcu.Pin7=PC9
-Mcu.Pin70=DDR_DQM1
-Mcu.Pin71=DDR_DQS1P
-Mcu.Pin72=PF7
-Mcu.Pin73=USB_DM2
-Mcu.Pin74=PB6
-Mcu.Pin75=USB_DM1
-Mcu.Pin76=DDR_VREF
-Mcu.Pin77=DDR_DQ12
-Mcu.Pin78=DDR_DQ11
-Mcu.Pin79=PD2
-Mcu.Pin8=PC10
-Mcu.Pin80=DDR_ZQ
-Mcu.Pin81=DDR_A7
-Mcu.Pin82=PC12
-Mcu.Pin83=PD15
-Mcu.Pin84=DDR_DTO1
-Mcu.Pin85=DDR_A5
-Mcu.Pin86=DDR_DTO0
-Mcu.Pin87=DDR_RASN
-Mcu.Pin88=DDR_ATO
-Mcu.Pin89=DDR_A6
-Mcu.Pin9=DSIHOST_D0P
-Mcu.Pin90=PF10
-Mcu.Pin91=VP_ADC2_TempSens_Input
-Mcu.Pin92=VP_ADC2_Vref_Input
-Mcu.Pin93=VP_ADC2_VddCore_Input
-Mcu.Pin94=VP_ADC2_Vbat_Input
-Mcu.Pin95=VP_BSEC_VS_BSEC
-Mcu.Pin96=VP_CRC1_VS_CRC
-Mcu.Pin97=VP_CRYP1_VS_CRYP
-Mcu.Pin98=VP_DDR_DDR3
-Mcu.Pin99=VP_DDR_DDR_16_bits
-Mcu.PinsNb=115
-Mcu.ThirdPartyNb=0
-Mcu.UserConstants=
-Mcu.UserName=STM32MP157CADx
-MxCube.Version=5.3.0
-MxDb.Version=DB.5.0.30
-NJTRST.GPIOParameters=GPIO_Label
-NJTRST.GPIO_Label=JTAG Debug
-NJTRST.Locked=true
-NJTRST.Mode=JTAG_5_pins
-NJTRST.Signal=DEBUG_JTRST
-NVIC.BusFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false
-NVIC.DebugMonitor_IRQn=true\:0\:0\:false\:false\:true\:false\:false
-NVIC.HardFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false
-NVIC.MemoryManagement_IRQn=true\:0\:0\:false\:false\:true\:false\:false
-NVIC.NonMaskableInt_IRQn=true\:0\:0\:false\:false\:true\:false\:false
-NVIC.PendSV_IRQn=true\:0\:0\:false\:false\:true\:false\:false
-NVIC.PriorityGroup=NVIC_PRIORITYGROUP_4
-NVIC.SVCall_IRQn=true\:0\:0\:false\:false\:true\:false\:false
-NVIC.SysTick_IRQn=true\:0\:0\:false\:false\:true\:false\:true
-NVIC.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false
-OTG_VBUS.GPIOParameters=GPIO_Label
-OTG_VBUS.GPIO_Label=USB OTG
-OTG_VBUS.Locked=true
-OTG_VBUS.Mode=Activate_VBUS_FS
-OTG_VBUS.Signal=USB_OTG_HS_VBUS
-PA10.GPIOParameters=GPIO_Label
-PA10.GPIO_Label=USB OTG
-PA10.Locked=true
-PA10.Mode=Ext_Phy_OTG/Dual-Role-Device
-PA10.Signal=USB_OTG_HS_ID
-PA13.GPIOParameters=GPIO_Label
-PA13.GPIO_Label=LED1
-PA13.Locked=true
-PA13.Signal=GPIO_Output
-PB2.GPIOParameters=GPIO_ModePuPdOnly,GPIO_PuPd,GPIO_Label
-PB2.GPIO_Label=Console UART
-PB2.GPIO_ModePuPdOnly=GPIO_MODE_AF
-PB2.GPIO_PuPd=GPIO_PULLUP
-PB2.Locked=true
-PB2.Mode=Asynchronous
-PB2.Signal=UART4_RX
-PB6.GPIOParameters=GPIO_PuPd,GPIO_Label,GPIO_Speed_Medium_Default,GPIO_Mode
-PB6.GPIO_Label=NOR Flash
-PB6.GPIO_Mode=GPIO_MODE_AF_PP
-PB6.GPIO_PuPd=GPIO_PULLUP
-PB6.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_VERY_HIGH
-PB6.Locked=true
-PB6.Mode=Single Bank 1
-PB6.Signal=QUADSPI_BK1_NCS
-PC10.GPIOParameters=GPIO_PuPd,GPIO_Label,GPIO_Speed_Medium_Default,GPIO_Mode
-PC10.GPIO_Label=SDCARD
-PC10.GPIO_Mode=GPIO_MODE_AF_PP
-PC10.GPIO_PuPd=GPIO_PULLUP
-PC10.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_MEDIUM
-PC10.Locked=true
-PC10.Mode=SD_4_bits_Wide_bus
-PC10.Signal=SDMMC1_D2
-PC11.GPIOParameters=GPIO_PuPd,GPIO_Label,GPIO_Speed_Medium_Default,GPIO_Mode
-PC11.GPIO_Label=SDCARD
-PC11.GPIO_Mode=GPIO_MODE_AF_PP
-PC11.GPIO_PuPd=GPIO_PULLUP
-PC11.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_MEDIUM
-PC11.Locked=true
-PC11.Mode=SD_4_bits_Wide_bus
-PC11.Signal=SDMMC1_D3
-PC12.GPIOParameters=GPIO_PuPd,GPIO_Speed_High_Default,GPIO_Label,GPIO_Mode
-PC12.GPIO_Label=SDCARD
-PC12.GPIO_Mode=GPIO_MODE_AF_PP
-PC12.GPIO_PuPd=GPIO_PULLUP
-PC12.GPIO_Speed_High_Default=GPIO_SPEED_FREQ_VERY_HIGH
-PC12.Locked=true
-PC12.Mode=SD_4_bits_Wide_bus
-PC12.Signal=SDMMC1_CK
-PC14-OSC32_IN.GPIOParameters=GPIO_Label
-PC14-OSC32_IN.GPIO_Label=OSC RTC
-PC14-OSC32_IN.Locked=true
-PC14-OSC32_IN.Mode=LSE-External-Oscillator
-PC14-OSC32_IN.Signal=RCC_OSC32_IN
-PC15-OSC32_OUT.GPIOParameters=GPIO_Label
-PC15-OSC32_OUT.GPIO_Label=OSC RTC
-PC15-OSC32_OUT.Locked=true
-PC15-OSC32_OUT.Mode=LSE-External-Oscillator
-PC15-OSC32_OUT.Signal=RCC_OSC32_OUT
-PC8.GPIOParameters=GPIO_PuPd,GPIO_Label,GPIO_Speed_Medium_Default,GPIO_Mode
-PC8.GPIO_Label=SDCARD
-PC8.GPIO_Mode=GPIO_MODE_AF_PP
-PC8.GPIO_PuPd=GPIO_PULLUP
-PC8.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_MEDIUM
-PC8.Locked=true
-PC8.Mode=SD_4_bits_Wide_bus
-PC8.Signal=SDMMC1_D0
-PC9.GPIOParameters=GPIO_PuPd,GPIO_Label,GPIO_Speed_Medium_Default,GPIO_Mode
-PC9.GPIO_Label=SDCARD
-PC9.GPIO_Mode=GPIO_MODE_AF_PP
-PC9.GPIO_PuPd=GPIO_PULLUP
-PC9.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_MEDIUM
-PC9.Locked=true
-PC9.Mode=SD_4_bits_Wide_bus
-PC9.Signal=SDMMC1_D1
-PCC.Checker=false
-PCC.Line=STM32MP157
-PCC.MCU=STM32MP157CADx
-PCC.PartNumber=STM32MP157CADx
-PCC.Seq0=0
-PCC.Series=STM32MP1
-PCC.Temperature=25
-PCC.Vdd=3.0
-PD15.GPIOParameters=GPIO_Label
-PD15.GPIO_Label=RESET_OUT
-PD15.Locked=true
-PD15.Signal=GPIO_Output
-PD2.GPIOParameters=GPIO_PuPd,GPIO_Label,GPIO_Speed_Medium_Default,GPIO_Mode
-PD2.GPIO_Label=SDCARD
-PD2.GPIO_Mode=GPIO_MODE_AF_PP
-PD2.GPIO_PuPd=GPIO_PULLUP
-PD2.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_MEDIUM
-PD2.Locked=true
-PD2.Mode=SD_4_bits_Wide_bus
-PD2.Signal=SDMMC1_CMD
-PF10.GPIOParameters=GPIO_Label,GPIO_Speed_High_ByDefault,GPIO_Speed_Medium_Default
-PF10.GPIO_Label=NOR/NAND Flash
-PF10.GPIO_Speed_High_ByDefault=GPIO_SPEED_FREQ_VERY_HIGH
-PF10.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_VERY_HIGH
-PF10.Locked=true
-PF10.Mode=Single Bank 1
-PF10.Signal=QUADSPI_CLK
-PF6.GPIOParameters=GPIO_Label,GPIO_Speed_Medium_Default
-PF6.GPIO_Label=NOR Flash
-PF6.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_VERY_HIGH
-PF6.Locked=true
-PF6.Mode=Single Bank 1
-PF6.Signal=QUADSPI_BK1_IO3
-PF7.GPIOParameters=GPIO_Label,GPIO_Speed_Medium_Default
-PF7.GPIO_Label=NOR Flash
-PF7.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_VERY_HIGH
-PF7.Locked=true
-PF7.Mode=Single Bank 1
-PF7.Signal=QUADSPI_BK1_IO2
-PF8.GPIOParameters=GPIO_Label,GPIO_Speed_Medium_Default
-PF8.GPIO_Label=NOR Flash
-PF8.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_VERY_HIGH
-PF8.Locked=true
-PF8.Mode=Single Bank 1
-PF8.Signal=QUADSPI_BK1_IO0
-PF9.GPIOParameters=GPIO_Label,GPIO_Speed_Medium_Default
-PF9.GPIO_Label=NOR Flash
-PF9.GPIO_Speed_Medium_Default=GPIO_SPEED_FREQ_VERY_HIGH
-PF9.Locked=true
-PF9.Mode=Single Bank 1
-PF9.Signal=QUADSPI_BK1_IO1
-PG11.GPIOParameters=GPIO_ModeDefaultPP,GPIO_Speed,GPIO_PuPd,GPIO_Label
-PG11.GPIO_Label=Console UART
-PG11.GPIO_ModeDefaultPP=GPIO_MODE_AF_PP
-PG11.GPIO_PuPd=GPIO_PULLUP
-PG11.GPIO_Speed=GPIO_SPEED_FREQ_LOW
-PG11.Locked=true
-PG11.Mode=Asynchronous
-PG11.Signal=UART4_TX
-PH0-OSC_IN.GPIOParameters=GPIO_Label
-PH0-OSC_IN.GPIO_Label=OSC System
-PH0-OSC_IN.Locked=true
-PH0-OSC_IN.Mode=HSE-External-Oscillator
-PH0-OSC_IN.Signal=RCC_OSC_IN
-PH1-OSC_OUT.GPIOParameters=GPIO_Label
-PH1-OSC_OUT.GPIO_Label=OSC System
-PH1-OSC_OUT.Locked=true
-PH1-OSC_OUT.Mode=HSE-External-Oscillator
-PH1-OSC_OUT.Signal=RCC_OSC_OUT
-PinOutPanel.CurrentBGAView=Top
-PinOutPanel.RotationAngle=0
-ProjectManager.AskForMigrate=true
-ProjectManager.BackupPrevious=false
-ProjectManager.CompilerOptimize=6
-ProjectManager.ComputerToolchain=false
-ProjectManager.CoupleFile=false
-ProjectManager.CustomerFirmwarePackage=
-ProjectManager.DefaultFWLocation=true
-ProjectManager.DeletePrevious=true
-ProjectManager.DeviceId=STM32MP157CADx
-ProjectManager.DeviceTreeLocation=/home/user/gen/thud/ktn/ye/layers/meta-ktn-stm32mp/conf/machine/cubemx/t1001-som-minimal/DeviceTree/
-ProjectManager.FirmwarePackage=STM32Cube FW_MP1 V1.0.1
-ProjectManager.FreePins=false
-ProjectManager.HalAssertFull=false
-ProjectManager.HeapSize=0x200
-ProjectManager.KeepUserCode=true
-ProjectManager.LastFirmware=true
-ProjectManager.LibraryCopy=1
-ProjectManager.MainLocation=Src
-ProjectManager.NoMain=false
-ProjectManager.PreviousToolchain=SW4STM32
-ProjectManager.ProjectBuild=false
-ProjectManager.ProjectFileName=t1001-som-minimal.ioc
-ProjectManager.ProjectName=t1001-som-minimal
-ProjectManager.StackSize=0x400
-ProjectManager.TargetToolchain=SW4STM32
-ProjectManager.ToolChainLocation=
-ProjectManager.UnderRoot=true
-ProjectManager.functionlistsort=1-MX_GPIO_Init-GPIO-false-HAL-true,2-SystemClock_Config-RCC-false-HAL-false,3-MX_ETZPC_Init-ETZPC-false-HAL-true,4-MX_IPCC_Init-IPCC-false-HAL-true
-RCC.ADCCLockSelection=RCC_ADCCLKSOURCE_PER
-RCC.ADCFreq_Value=24000000
-RCC.AHB1234Freq_Value=200000000
-RCC.APB1DIV=RCC_APB1_DIV2
-RCC.APB1Freq_Value=100000000
-RCC.APB2DIV=RCC_APB2_DIV2
-RCC.APB2Freq_Value=100000000
-RCC.APB3DIV=RCC_APB3_DIV2
-RCC.APB3Freq_Value=100000000
-RCC.APB4DIV=RCC_APB4_DIV2
-RCC.APB4Freq_Value=132000000
-RCC.APB5DIV=RCC_APB5_DIV4
-RCC.APB5DIVClockFreq_Value=66000000
-RCC.AXICLKFreq_VALUE=264000000
-RCC.AXICLKSource=RCC_AXISSOURCE_PLL2
-RCC.AXIDIVFreq_Value=264000000
-RCC.CECFreq_Value=32768
-RCC.CKPERCLKFreq_VALUE=24000000
-RCC.CKPERCLKSource=RCC_CKPERCLKSOURCE_HSE
-RCC.CSI_VALUE=4000000
-RCC.DACCLKFreq_VALUE=32000
-RCC.DDRCFreq_Value=528000000
-RCC.DDRPERFMFreq_Value=528000000
-RCC.DDRPHYFreq_Value=528000000
-RCC.DFSDFAFreq_Value=50000000
-RCC.DFSDMFreq_Value=200000000
-RCC.DIVM1=3
-RCC.DIVM2=3
-RCC.DIVM3=2
-RCC.DIVM4=6
-RCC.DIVN1=81
-RCC.DIVN2=66
-RCC.DIVN3=50
-RCC.DIVN4=125
-RCC.DIVP1Freq_Value=648000000
-RCC.DIVP2Freq_Value=264000000
-RCC.DIVP3=3
-RCC.DIVP3Freq_Value=200000000
-RCC.DIVP4=10
-RCC.DIVP4Freq_Value=50000000
-RCC.DIVQ1Freq_Value=324000000
-RCC.DIVQ2Freq_Value=264000000
-RCC.DIVQ3=3
-RCC.DIVQ3Freq_Value=200000000
-RCC.DIVQ4=10
-RCC.DIVQ4Freq_Value=50000000
-RCC.DIVR1Freq_Value=324000000
-RCC.DIVR2=1
-RCC.DIVR2Freq_Value=528000000
-RCC.DIVR3Freq_Value=300000000
-RCC.DIVR4=10
-RCC.DIVR4Freq_Value=50000000
-RCC.DSIFreq_Value=60000000
-RCC.DSIPixelFreq_Value=50000000
-RCC.DSITXEscFreq_Value=15000000
-RCC.DSI_VALUE=60000000
-RCC.ETHFreq_Value=50000000
-RCC.FDCANFreq_Value=24000000
-RCC.FMCFreq_Value=264000000
-RCC.FamilyName=M
-RCC.HSE_Timout=100
-RCC.HSE_VALUE=24000000
-RCC.HSIDivClkFreq_Value=64000000
-RCC.HSI_VALUE=64000000
-RCC.Hclk5DIVFreq_Value=264000000
-RCC.Hclk6DIVFreq_Value=264000000
-RCC.I2C12CLockSelection=RCC_I2C12CLKSOURCE_HSI
-RCC.I2C12Freq_Value=64000000
-RCC.I2C35Freq_Value=100000000
-RCC.I2C46CLockSelection=RCC_I2C46CLKSOURCE_HSI
-RCC.I2C46Freq_Value=64000000
-RCC.IPParameters=ADCCLockSelection,ADCFreq_Value,AHB1234Freq_Value,APB1DIV,APB1Freq_Value,APB2DIV,APB2Freq_Value,APB3DIV,APB3Freq_Value,APB4DIV,APB4Freq_Value,APB5DIV,APB5DIVClockFreq_Value,AXICLKFreq_VALUE,AXICLKSource,AXIDIVFreq_Value,CECFreq_Value,CKPERCLKFreq_VALUE,CKPERCLKSource,CSI_VALUE,DACCLKFreq_VALUE,DDRCFreq_Value,DDRPERFMFreq_Value,DDRPHYFreq_Value,DFSDFAFreq_Value,DFSDMFreq_Value,DIVM1,DIVM2,DIVM3,DIVM4,DIVN1,DIVN2,DIVN3,DIVN4,DIVP1Freq_Value,DIVP2Freq_Value,DIVP3,DIVP3Freq_Value,DIVP4,DIVP4Freq_Value,DIVQ1Freq_Value,DIVQ2Freq_Value,DIVQ3,DIVQ3Freq_Value,DIVQ4,DIVQ4Freq_Value,DIVR1Freq_Value,DIVR2,DIVR2Freq_Value,DIVR3Freq_Value,DIVR4,DIVR4Freq_Value,DSIFreq_Value,DSIPixelFreq_Value,DSITXEscFreq_Value,DSI_VALUE,ETHFreq_Value,FDCANFreq_Value,FMCFreq_Value,FamilyName,HSE_Timout,HSE_VALUE,HSIDivClkFreq_Value,HSI_VALUE,Hclk5DIVFreq_Value,Hclk6DIVFreq_Value,I2C12CLockSelection,I2C12Freq_Value,I2C35Freq_Value,I2C46CLockSelection,I2C46Freq_Value,LPTIM1Freq_Value,LPTIM23Freq_Value,LPTIM45Freq_Value,LSE_Timout,LSI_VALUE,LTDCFreq_Value,MCO1PinFreq_Value,MCO2PinFreq_Value,MCUCLKFreq_VALUE,MCUCLKSource,MCUClockFreq_Value,MCUDIVCLKFreq_Value,MPUCLKFreq_VALUE,MPUCLKSource,PLL12Source,PLL2FRACV,PLL3FRACV,PLL3Source,PLL4PDSIFreq_Value,PLL4Source,PLLDSIFreq_Value,PLLDSIVCOFreq_Value,PUBLFreq_Value,QSPIFreq_Value,RNG1Freq_Value,RNG2Freq_Value,RTCClockSelection,RTCFreq_Value,SAI1Freq_Value,SAI2Freq_Value,SAI3Freq_Value,SAI4Freq_Value,SDMMC12CLockSelection,SDMMC12Freq_Value,SDMMC3Freq_Value,SPDIFRXFreq_Value,SPI1CLockSelection,SPI1Freq_Value,SPI23Freq_Value,SPI45Freq_Value,SPI6Freq_Value,STGENCLockSelection,STGENFreq_Value,Tim1OutputFreq_Value,Tim2OutputFreq_Value,UART78Freq_Value,USART1Freq_Value,USART24Freq_Value,USART35Freq_Value,USART6Freq_Value,USBOCLKSource,USBOHSFreq_Value,USBPHYCLKSource,USBPHYFreq_Value,VCO1OutputFreq_Value,VCO2OutputFreq_Value,VCO3OutputFreq_Value,VCO4OutputFreq_Value,VCOInput1Freq_Value,VCOInput2Freq_Value,VCOInput3Freq_Value,VCOInput4Freq_Value
-RCC.LPTIM1Freq_Value=100000000
-RCC.LPTIM23Freq_Value=100000000
-RCC.LPTIM45Freq_Value=100000000
-RCC.LSE_Timout=5000
-RCC.LSI_VALUE=32000
-RCC.LTDCFreq_Value=50000000
-RCC.MCO1PinFreq_Value=64000000
-RCC.MCO2PinFreq_Value=648000000
-RCC.MCUCLKFreq_VALUE=200000000
-RCC.MCUCLKSource=RCC_MCUSSOURCE_PLL3
-RCC.MCUClockFreq_Value=200000000
-RCC.MCUDIVCLKFreq_Value=200000000
-RCC.MPUCLKFreq_VALUE=648000000
-RCC.MPUCLKSource=RCC_MPUSOURCE_PLL1
-RCC.PLL12Source=RCC_PLL12SOURCE_HSE
-RCC.PLL2FRACV=0
-RCC.PLL3FRACV=0
-RCC.PLL3Source=RCC_PLL3SOURCE_HSE
-RCC.PLL4PDSIFreq_Value=50000000
-RCC.PLL4Source=RCC_PLL4SOURCE_HSE
-RCC.PLLDSIFreq_Value=480000000
-RCC.PLLDSIVCOFreq_Value=960000000
-RCC.PUBLFreq_Value=528000000
-RCC.QSPIFreq_Value=264000000
-RCC.RNG1Freq_Value=4000000
-RCC.RNG2Freq_Value=4000000
-RCC.RTCClockSelection=RCC_RTCCLKSOURCE_LSE
-RCC.RTCFreq_Value=32768
-RCC.SAI1Freq_Value=50000000
-RCC.SAI2Freq_Value=50000000
-RCC.SAI3Freq_Value=50000000
-RCC.SAI4Freq_Value=50000000
-RCC.SDMMC12CLockSelection=RCC_SDMMC12CLKSOURCE_PLL4
-RCC.SDMMC12Freq_Value=50000000
-RCC.SDMMC3Freq_Value=200000000
-RCC.SPDIFRXFreq_Value=50000000
-RCC.SPI1CLockSelection=RCC_SPI1CLKSOURCE_PLL3_Q
-RCC.SPI1Freq_Value=200000000
-RCC.SPI23Freq_Value=50000000
-RCC.SPI45Freq_Value=100000000
-RCC.SPI6Freq_Value=66000000
-RCC.STGENCLockSelection=RCC_STGENCLKSOURCE_HSE
-RCC.STGENFreq_Value=24000000
-RCC.Tim1OutputFreq_Value=200000000
-RCC.Tim2OutputFreq_Value=200000000
-RCC.UART78Freq_Value=100000000
-RCC.USART1Freq_Value=66000000
-RCC.USART24Freq_Value=100000000
-RCC.USART35Freq_Value=100000000
-RCC.USART6Freq_Value=100000000
-RCC.USBOCLKSource=RCC_USBOCLKSOURCE_PHY
-RCC.USBOHSFreq_Value=48000000
-RCC.USBPHYCLKSource=RCC_USBPHYCLKSOURCE_HSE
-RCC.USBPHYFreq_Value=24000000
-RCC.VCO1OutputFreq_Value=1296000000
-RCC.VCO2OutputFreq_Value=1056000000
-RCC.VCO3OutputFreq_Value=600000000
-RCC.VCO4OutputFreq_Value=500000000
-RCC.VCOInput1Freq_Value=8000000
-RCC.VCOInput2Freq_Value=8000000
-RCC.VCOInput3Freq_Value=12000000
-RCC.VCOInput4Freq_Value=4000000
-USB_DM1.GPIOParameters=GPIO_Label
-USB_DM1.GPIO_Label=USB Host
-USB_DM1.Locked=true
-USB_DM1.Mode=Enable
-USB_DM1.Signal=USBH_HS1_DM
-USB_DM2.GPIOParameters=GPIO_Label
-USB_DM2.GPIO_Label=USB OTG
-USB_DM2.Locked=true
-USB_DM2.Mode=Ext_Phy_OTG/Dual-Role-Device
-USB_DM2.Signal=USB_OTG_HS_DM
-USB_DP1.GPIOParameters=GPIO_Label
-USB_DP1.GPIO_Label=USB Host
-USB_DP1.Locked=true
-USB_DP1.Mode=Enable
-USB_DP1.Signal=USBH_HS1_DP
-USB_DP2.GPIOParameters=GPIO_Label
-USB_DP2.GPIO_Label=USB OTG
-USB_DP2.Locked=true
-USB_DP2.Mode=Ext_Phy_OTG/Dual-Role-Device
-USB_DP2.Signal=USB_OTG_HS_DP
-VP_ADC2_TempSens_Input.Mode=IN-TempSens
-VP_ADC2_TempSens_Input.Signal=ADC2_TempSens_Input
-VP_ADC2_Vbat_Input.Mode=IN-Vbat
-VP_ADC2_Vbat_Input.Signal=ADC2_Vbat_Input
-VP_ADC2_VddCore_Input.Mode=IN-VddCore
-VP_ADC2_VddCore_Input.Signal=ADC2_VddCore_Input
-VP_ADC2_Vref_Input.Mode=IN-Vrefint
-VP_ADC2_Vref_Input.Signal=ADC2_Vref_Input
-VP_BSEC_VS_BSEC.Mode=BSEC_Activate
-VP_BSEC_VS_BSEC.Signal=BSEC_VS_BSEC
-VP_CRC1_VS_CRC.Mode=CRC_Activate
-VP_CRC1_VS_CRC.Signal=CRC1_VS_CRC
-VP_CRYP1_VS_CRYP.Mode=CRYP_Activate
-VP_CRYP1_VS_CRYP.Signal=CRYP1_VS_CRYP
-VP_DDR_DDR3.Mode=DDR3
-VP_DDR_DDR3.Signal=DDR_DDR3
-VP_DDR_DDR3_16_4Gb.Mode=4Gb_16bits
-VP_DDR_DDR3_16_4Gb.Signal=DDR_DDR3_16_4Gb
-VP_DDR_DDR_16_bits.Mode=16bits
-VP_DDR_DDR_16_bits.Signal=DDR_DDR_16_bits
-VP_DMA_VS_DMA1_A7NS.Mode=CortexA7NS
-VP_DMA_VS_DMA1_A7NS.Signal=DMA_VS_DMA1_A7NS
-VP_DMA_VS_DMA2_M4.Mode=CortexM4
-VP_DMA_VS_DMA2_M4.Signal=DMA_VS_DMA2_M4
-VP_DTS_VS_DTS.Mode=DTS_Activate
-VP_DTS_VS_DTS.Signal=DTS_VS_DTS
-VP_ETZPC_VS_ETZPC.Mode=ETZPC_Activate
-VP_ETZPC_VS_ETZPC.Signal=ETZPC_VS_ETZPC
-VP_GPU_VS_GPU.Mode=GPU_Activate
-VP_GPU_VS_GPU.Signal=GPU_VS_GPU
-VP_HASH1_VS_HASH.Mode=HASH_Activate
-VP_HASH1_VS_HASH.Signal=HASH1_VS_HASH
-VP_HSEM_VS_HSEM.Mode=HSEM_Activate
-VP_HSEM_VS_HSEM.Signal=HSEM_VS_HSEM
-VP_IPCC_VS_IPCC.Mode=IPCC_Activate
-VP_IPCC_VS_IPCC.Signal=IPCC_VS_IPCC
-VP_IWDG2_VS_IWDG.Mode=IWDG_Activate
-VP_IWDG2_VS_IWDG.Signal=IWDG2_VS_IWDG
-VP_MDMA_VS_MDMA_A7NS_8.Mode=8\:8
-VP_MDMA_VS_MDMA_A7NS_8.Signal=MDMA_VS_MDMA_A7NS_8
-VP_RNG1_VS_RNG.Mode=RNG_Activate
-VP_RNG1_VS_RNG.Signal=RNG1_VS_RNG
-VP_RTC_VS_RTC_Activate.Mode=RTC_Enabled
-VP_RTC_VS_RTC_Activate.Signal=RTC_VS_RTC_Activate
-VP_SYS_VS_Systick.Mode=SysTick
-VP_SYS_VS_Systick.Signal=SYS_VS_Systick
-VP_VREFBUF_VS_VREFBUF.Mode=VREFBUF_Activate
-VP_VREFBUF_VS_VREFBUF.Signal=VREFBUF_VS_VREFBUF
-board=custom
diff --git a/conf/machine/include/extlinux-stmxceet-mp157-som.inc b/conf/machine/include/extlinux-stmxceet-mp157-som.inc
new file mode 100644
index 0000000000000000000000000000000000000000..199256bb34a12f7a313ecc4fc3d04fb676e4a100
--- /dev/null
+++ b/conf/machine/include/extlinux-stmxceet-mp157-som.inc
@@ -0,0 +1,40 @@
+# =========================================================================
+# Extlinux boot commands for
+# Board: stmxceet-mp157-som
+# =========================================================================
+# Define boot command lines
+#
+# The following bootschemes are supported
+# - boot from sdcard (BOOTPIN_0,2=1, BOOTPIN_1=0)
+# - boot from nor (BOOTPIN_0=1, BOOTPIN_3,2=0)
+#   When booting from nor u-boot variable 'boot_targets' select where to find
+#   the bootfs with EXTLINUX configuration
+#
+
+# add targets to generate
+UBOOT_EXTLINUX_TARGETS += "\
+	stmxceet-mp157-som-mini_sdcard \
+	stmxceet-mp157-som-mini_nor-emmc \
+	stmxceet-mp157-som-mini_nor-nand \
+"
+
+# definitions for this target *_sdcard boot
+UBOOT_EXTLINUX_BOOTPREFIXES_stmxceet-mp157-som-mini_sdcard    = "mmc0_stmxceet-mp157-som-mini_"
+UBOOT_EXTLINUX_LABELS_stmxceet-mp157-som-mini_sdcard          = "stmxceet-mp157-som-mini-sdcard"
+UBOOT_EXTLINUX_DEFAULT_LABEL_stmxceet-mp157-som-mini_sdcard   = "stmxceet-mp157-som-mini-sdcard"
+UBOOT_EXTLINUX_FDT_stmxceet-mp157-som-mini-sdcard             = "/stmxceet-mp157-som-mini.dtb"
+UBOOT_EXTLINUX_ROOT_stmxceet-mp157-som-mini-sdcard            = "root=/dev/mmcblk0p5"
+
+# definitions for this target *_nor-emmc boot
+UBOOT_EXTLINUX_BOOTPREFIXES_stmxceet-mp157-som-mini_nor-emmc  = "mmc1_stmxceet-mp157-som-mini_"
+UBOOT_EXTLINUX_LABELS_stmxceet-mp157-som-mini_nor-emmc        = "stmxceet-mp157-som-mini-nor-emmc"
+UBOOT_EXTLINUX_DEFAULT_LABEL_stmxceet-mp157-som-mini_nor-emmc = "stmxceet-mp157-som-mini-nor-emmc"
+UBOOT_EXTLINUX_FDT_stmxceet-mp157-som-mini-nor-emmc           = "/stmxceet-mp157-som-mini.dtb"
+UBOOT_EXTLINUX_ROOT_stmxceet-mp157-som-mini-nor-emmc          = "root=/dev/mmcblk1p2"
+
+# definitions for this target *_nor-nand boot
+UBOOT_EXTLINUX_BOOTPREFIXES_stmxceet-mp157-som-mini_nor-nand  = "ubifs0_stmxceet-mp157-som-mini_"
+UBOOT_EXTLINUX_LABELS_stmxceet-mp157-som-mini_nor-nand        = "stmxceet-mp157-som-mini-nor-nand"
+UBOOT_EXTLINUX_DEFAULT_LABEL_stmxceet-mp157-som-mini_nor-nand = "stmxceet-mp157-som-mini-nor-nand"
+UBOOT_EXTLINUX_FDT_stmxceet-mp157-som-mini-nor-nand           = "/stmxceet-mp157-som-mini.dtb"
+UBOOT_EXTLINUX_ROOT_stmxceet-mp157-som-mini-nor-nand          = "ubi.mtd=UBI rootfstype=ubifs root=ubi0:bootfs"
diff --git a/conf/machine/include/extlinux-t1000-default.inc b/conf/machine/include/extlinux-t1000-default.inc
new file mode 100644
index 0000000000000000000000000000000000000000..c655ab5f40873f9b6518f9c9f9316763b6ab400d
--- /dev/null
+++ b/conf/machine/include/extlinux-t1000-default.inc
@@ -0,0 +1,40 @@
+# =========================================================================
+# Extlinux boot commands for
+# Board: stm32mp-t1000-mini
+# =========================================================================
+# Define boot command lines
+#
+# The following bootschemes are supported
+# - boot from sdcard (BOOTPIN_0,2=1, BOOTPIN_1=0)
+# - boot from nor (BOOTPIN_0=1, BOOTPIN_3,2=0)
+#   When booting from nor u-boot variable 'boot_targets' select where to find
+#   the bootfs with EXTLINUX configuration
+#
+
+# add targets to generate
+UBOOT_EXTLINUX_TARGETS += "\
+	stm32mp-t1000-default_sdcard \
+	stm32mp-t1000-default_nor-emmc \
+	stm32mp-t1000-default_nor-nand \
+"
+
+# definitions for this target *_sdcard boot
+UBOOT_EXTLINUX_BOOTPREFIXES_stm32mp-t1000-default_sdcard    = "mmc0_stm32mp-t1000-default_"
+UBOOT_EXTLINUX_LABELS_stm32mp-t1000-default_sdcard          = "stm32mp-t1000-default-sdcard"
+UBOOT_EXTLINUX_DEFAULT_LABEL_stm32mp-t1000-default_sdcard   = "stm32mp-t1000-default-sdcard"
+UBOOT_EXTLINUX_FDT_stm32mp-t1000-default-sdcard             = "/stm32mp-t1000-default.dtb"
+UBOOT_EXTLINUX_ROOT_stm32mp-t1000-default-sdcard            = "root=/dev/mmcblk0p5"
+
+# definitions for this target *_nor-emmc boot
+UBOOT_EXTLINUX_BOOTPREFIXES_stm32mp-t1000-default_nor-emmc  = "mmc1_stm32mp-t1000-default_"
+UBOOT_EXTLINUX_LABELS_stm32mp-t1000-default_nor-emmc        = "stm32mp-t1000-default-nor-emmc"
+UBOOT_EXTLINUX_DEFAULT_LABEL_stm32mp-t1000-default_nor-emmc = "stm32mp-t1000-default-nor-emmc"
+UBOOT_EXTLINUX_FDT_stm32mp-t1000-default-nor-emmc           = "/stm32mp-t1000-default.dtb"
+UBOOT_EXTLINUX_ROOT_stm32mp-t1000-default-nor-emmc          = "root=/dev/mmcblk1p2"
+
+# definitions for this target *_nor-nand boot
+UBOOT_EXTLINUX_BOOTPREFIXES_stm32mp-t1000-default_nor-nand  = "ubifs0_stm32mp-t1000-default_"
+UBOOT_EXTLINUX_LABELS_stm32mp-t1000-default_nor-nand        = "stm32mp-t1000-default-nor-nand"
+UBOOT_EXTLINUX_DEFAULT_LABEL_stm32mp-t1000-default_nor-nand = "stm32mp-t1000-default-nor-nand"
+UBOOT_EXTLINUX_FDT_stm32mp-t1000-default-nor-nand           = "/stm32mp-t1000-default.dtb"
+UBOOT_EXTLINUX_ROOT_stm32mp-t1000-default-nor-nand          = "ubi.mtd=UBI rootfstype=ubifs root=ubi0:bootfs"
diff --git a/conf/machine/include/extlinux-t1000-k-101.inc b/conf/machine/include/extlinux-t1000-k-101.inc
deleted file mode 100644
index 7a3d5524bd0e84f9bd99121a94c37d0b0d509d28..0000000000000000000000000000000000000000
--- a/conf/machine/include/extlinux-t1000-k-101.inc
+++ /dev/null
@@ -1,43 +0,0 @@
-# =========================================================================
-# Extlinux boot commands for
-# Board: stm32mp-t1000-k-101
-# =========================================================================
-# Define boot command lines
-#
-# The following bootschemes are supported
-# - boot from sdcard (BOOTPIN_0,2=1, BOOTPIN_1=0)
-# - boot from nor (BOOTPIN_0=1, BOOTPIN_3,2=0)
-#   When booting from nor u-boot variable 'boot_targets' select where to find
-#   the bootfs with EXTLINUX configuration
-#
-
-# add targets to generate
-UBOOT_EXTLINUX_TARGETS += "\
-	stm32mp-t1000-k-101_sdcard \
-	stm32mp-t1000-k-101_nor-emmc \
-	stm32mp-t1000-k-101_nor-nand \
-"
-
-# definitions for this target *_sdcard boot
-UBOOT_EXTLINUX_BOOTPREFIXES_stm32mp-t1000-k-101_sdcard    = "mmc0_stm32mp-t1000-k-101_"
-UBOOT_EXTLINUX_LABELS_stm32mp-t1000-k-101_sdcard          = "stm32mp-t1000-k-101-sdcard"
-UBOOT_EXTLINUX_DEFAULT_LABEL_stm32mp-t1000-k-101_sdcard   = "stm32mp-t1000-k-101-sdcard"
-# label t1000-k-101
-UBOOT_EXTLINUX_FDT_stm32mp-t1000-k-101-sdcard             = "/boot/stm32mp-t1000-k-101.dtb"
-UBOOT_EXTLINUX_ROOT_stm32mp-t1000-k-101-sdcard            = "root=/dev/mmcblk0p4"
-
-# definitions for this target *_nor-emmc boot
-UBOOT_EXTLINUX_BOOTPREFIXES_stm32mp-t1000-k-101_nor-emmc  = "mmc1_stm32mp-t1000-k-101_"
-UBOOT_EXTLINUX_LABELS_stm32mp-t1000-k-101_nor-emmc        = "stm32mp-t1000-k-101-nor-emmc"
-UBOOT_EXTLINUX_DEFAULT_LABEL_stm32mp-t1000-k-101_nor-emmc = "stm32mp-t1000-k-101-nor-emmc"
-# label t1000-k-101
-UBOOT_EXTLINUX_FDT_stm32mp-t1000-k-101-nor-emmc           = "/boot/stm32mp-t1000-k-101.dtb"
-UBOOT_EXTLINUX_ROOT_stm32mp-t1000-k-101-nor-emmc          = "root=/dev/mmcblk1p1"
-
-# definitions for this target *_nor-nand boot
-UBOOT_EXTLINUX_BOOTPREFIXES_stm32mp-t1000-k-101_nor-nand  = "ubi0_stm32mp-t1000-k-101_"
-UBOOT_EXTLINUX_LABELS_stm32mp-t1000-k-101_nor-nand        = "stm32mp-t1000-k-101-nor-nand"
-UBOOT_EXTLINUX_DEFAULT_LABEL_stm32mp-t1000-k-101_nor-nand = "stm32mp-t1000-k-101-nor-nand"
-# label t1000-k-101
-UBOOT_EXTLINUX_FDT_stm32mp-t1000-k-101-nor-nand           = "/boot/stm32mp-t1000-k-101.dtb"
-UBOOT_EXTLINUX_ROOT_stm32mp-t1000-k-101-nor-nand          = "ubi.mtd=5 rootfstype=ubifs root=ubi0_0"
diff --git a/conf/machine/include/extlinux-t1000-k-50.inc b/conf/machine/include/extlinux-t1000-k-50.inc
deleted file mode 100644
index 49ef012381cc0c6dce60e44ec5df20539dada222..0000000000000000000000000000000000000000
--- a/conf/machine/include/extlinux-t1000-k-50.inc
+++ /dev/null
@@ -1,43 +0,0 @@
-# =========================================================================
-# Extlinux boot commands for
-# Board: stm32mp-t1000-k-50
-# =========================================================================
-# Define boot command lines
-#
-# The following bootschemes are supported
-# - boot from sdcard (BOOTPIN_0,2=1, BOOTPIN_1=0)
-# - boot from nor (BOOTPIN_0=1, BOOTPIN_3,2=0)
-#   When booting from nor u-boot variable 'boot_targets' select where to find
-#   the bootfs with EXTLINUX configuration
-#
-
-# add targets to generate
-UBOOT_EXTLINUX_TARGETS += "\
-	stm32mp-t1000-k-50_sdcard \
-	stm32mp-t1000-k-50_nor-emmc \
-	stm32mp-t1000-k-50_nor-nand \
-"
-
-# definitions for this target *_sdcard boot
-UBOOT_EXTLINUX_BOOTPREFIXES_stm32mp-t1000-k-50_sdcard    = "mmc0_stm32mp-t1000-k-50_"
-UBOOT_EXTLINUX_LABELS_stm32mp-t1000-k-50_sdcard          = "stm32mp-t1000-k-50-sdcard"
-UBOOT_EXTLINUX_DEFAULT_LABEL_stm32mp-t1000-k-50_sdcard   = "stm32mp-t1000-k-50-sdcard"
-# label t1000-k-50
-UBOOT_EXTLINUX_FDT_stm32mp-t1000-k-50-sdcard             = "/boot/stm32mp-t1000-k-50.dtb"
-UBOOT_EXTLINUX_ROOT_stm32mp-t1000-k-50-sdcard            = "root=/dev/mmcblk0p4"
-
-# definitions for this target *_nor-emmc boot
-UBOOT_EXTLINUX_BOOTPREFIXES_stm32mp-t1000-k-50_nor-emmc  = "mmc1_stm32mp-t1000-k-50_"
-UBOOT_EXTLINUX_LABELS_stm32mp-t1000-k-50_nor-emmc        = "stm32mp-t1000-k-50-nor-emmc"
-UBOOT_EXTLINUX_DEFAULT_LABEL_stm32mp-t1000-k-50_nor-emmc = "stm32mp-t1000-k-50-nor-emmc"
-# label t1000-k-50
-UBOOT_EXTLINUX_FDT_stm32mp-t1000-k-50-nor-emmc           = "/boot/stm32mp-t1000-k-50.dtb"
-UBOOT_EXTLINUX_ROOT_stm32mp-t1000-k-50-nor-emmc          = "root=/dev/mmcblk1p1"
-
-# definitions for this target *_nor-nand boot
-UBOOT_EXTLINUX_BOOTPREFIXES_stm32mp-t1000-k-50_nor-nand  = "ubi0_stm32mp-t1000-k-50_"
-UBOOT_EXTLINUX_LABELS_stm32mp-t1000-k-50_nor-nand        = "stm32mp-t1000-k-50-nor-nand"
-UBOOT_EXTLINUX_DEFAULT_LABEL_stm32mp-t1000-k-50_nor-nand = "stm32mp-t1000-k-50-nor-nand"
-# label t1000-k-50
-UBOOT_EXTLINUX_FDT_stm32mp-t1000-k-50-nor-nand           = "/boot/stm32mp-t1000-k-50.dtb"
-UBOOT_EXTLINUX_ROOT_stm32mp-t1000-k-50-nor-nand          = "ubi.mtd=5 rootfstype=ubifs root=ubi0_0"
diff --git a/conf/machine/include/extlinux-t1000-k-70.inc b/conf/machine/include/extlinux-t1000-k-70.inc
deleted file mode 100644
index fe6867e652afcdc327dd05b530db3af6d9fe6330..0000000000000000000000000000000000000000
--- a/conf/machine/include/extlinux-t1000-k-70.inc
+++ /dev/null
@@ -1,43 +0,0 @@
-# =========================================================================
-# Extlinux boot commands for
-# Board: stm32mp-t1000-k-70
-# =========================================================================
-# Define boot command lines
-#
-# The following bootschemes are supported
-# - boot from sdcard (BOOTPIN_0,2=1, BOOTPIN_1=0)
-# - boot from nor (BOOTPIN_0=1, BOOTPIN_3,2=0)
-#   When booting from nor u-boot variable 'boot_targets' select where to find
-#   the bootfs with EXTLINUX configuration
-#
-
-# add targets to generate
-UBOOT_EXTLINUX_TARGETS += "\
-	stm32mp-t1000-k-70_sdcard \
-	stm32mp-t1000-k-70_nor-emmc \
-	stm32mp-t1000-k-70_nor-nand \
-"
-
-# definitions for this target *_sdcard boot
-UBOOT_EXTLINUX_BOOTPREFIXES_stm32mp-t1000-k-70_sdcard    = "mmc0_stm32mp-t1000-k-70_"
-UBOOT_EXTLINUX_LABELS_stm32mp-t1000-k-70_sdcard          = "stm32mp-t1000-k-70-sdcard"
-UBOOT_EXTLINUX_DEFAULT_LABEL_stm32mp-t1000-k-70_sdcard   = "stm32mp-t1000-k-70-sdcard"
-# label t1000-k-70
-UBOOT_EXTLINUX_FDT_stm32mp-t1000-k-70-sdcard             = "/boot/stm32mp-t1000-k-70.dtb"
-UBOOT_EXTLINUX_ROOT_stm32mp-t1000-k-70-sdcard            = "root=/dev/mmcblk0p4"
-
-# definitions for this target *_nor-emmc boot
-UBOOT_EXTLINUX_BOOTPREFIXES_stm32mp-t1000-k-70_nor-emmc  = "mmc1_stm32mp-t1000-k-70_"
-UBOOT_EXTLINUX_LABELS_stm32mp-t1000-k-70_nor-emmc        = "stm32mp-t1000-k-70-nor-emmc"
-UBOOT_EXTLINUX_DEFAULT_LABEL_stm32mp-t1000-k-70_nor-emmc = "stm32mp-t1000-k-70-nor-emmc"
-# label t1000-k-70
-UBOOT_EXTLINUX_FDT_stm32mp-t1000-k-70-nor-emmc           = "/boot/stm32mp-t1000-k-70.dtb"
-UBOOT_EXTLINUX_ROOT_stm32mp-t1000-k-70-nor-emmc          = "root=/dev/mmcblk1p1"
-
-# definitions for this target *_nor-nand boot
-UBOOT_EXTLINUX_BOOTPREFIXES_stm32mp-t1000-k-70_nor-nand  = "ubi0_stm32mp-t1000-k-70_"
-UBOOT_EXTLINUX_LABELS_stm32mp-t1000-k-70_nor-nand        = "stm32mp-t1000-k-70-nor-nand"
-UBOOT_EXTLINUX_DEFAULT_LABEL_stm32mp-t1000-k-70_nor-nand = "stm32mp-t1000-k-70-nor-nand"
-# label t1000-k-70
-UBOOT_EXTLINUX_FDT_stm32mp-t1000-k-70-nor-nand           = "/boot/stm32mp-t1000-k-70.dtb"
-UBOOT_EXTLINUX_ROOT_stm32mp-t1000-k-70-nor-nand          = "ubi.mtd=5 rootfstype=ubifs root=ubi0_0"
diff --git a/conf/machine/include/extlinux-t1000-k.inc b/conf/machine/include/extlinux-t1000-k.inc
deleted file mode 100644
index 3a5f83e851f5956d49f762e56748982085812c31..0000000000000000000000000000000000000000
--- a/conf/machine/include/extlinux-t1000-k.inc
+++ /dev/null
@@ -1,42 +0,0 @@
-# =========================================================================
-# Extlinux boot commands for
-# Board: stm32mp-t1000-k
-# =========================================================================
-# Define boot command lines
-#
-# The following bootschemes are supported
-# - boot from sdcard (BOOTPIN_0,2=1, BOOTPIN_1=0)
-# - boot from nor (BOOTPIN_0=1, BOOTPIN_3,2=0)
-#   When booting from nor u-boot variable 'boot_targets' select where to find
-#   the bootfs with EXTLINUX configuration
-
-# add targets to generate
-UBOOT_EXTLINUX_TARGETS += "\
-	stm32mp-t1000-k_sdcard \
-	stm32mp-t1000-k_nor-emmc \
-	stm32mp-t1000-k_nor-nand \
-	"
-
-# definitions for this target *_sdcard boot
-UBOOT_EXTLINUX_BOOTPREFIXES_stm32mp-t1000-k_sdcard    = "mmc0_stm32mp-t1000-k_"
-UBOOT_EXTLINUX_LABELS_stm32mp-t1000-k_sdcard          = "stm32mp-t1000-k-sdcard"
-UBOOT_EXTLINUX_DEFAULT_LABEL_stm32mp-t1000-k_sdcard   ?= "stm32mp-t1000-k-sdcard"
-# label t1000-k
-UBOOT_EXTLINUX_FDT_stm32mp-t1000-k-sdcard             = "/boot/stm32mp-t1000-k.dtb"
-UBOOT_EXTLINUX_ROOT_stm32mp-t1000-k-sdcard            = "root=/dev/mmcblk0p4"
-
-# definitions for this target *_nor-emmc boot
-UBOOT_EXTLINUX_BOOTPREFIXES_stm32mp-t1000-k_nor-emmc  = "mmc1_stm32mp-t1000-k_"
-UBOOT_EXTLINUX_LABELS_stm32mp-t1000-k_nor-emmc        = "stm32mp-t1000-k-nor-emmc"
-UBOOT_EXTLINUX_DEFAULT_LABEL_stm32mp-t1000-k_nor-emmc ?= "stm32mp-t1000-k-nor-emmc"
-# label t1000-k
-UBOOT_EXTLINUX_FDT_stm32mp-t1000-k-nor-emmc           = "/boot/stm32mp-t1000-k.dtb"
-UBOOT_EXTLINUX_ROOT_stm32mp-t1000-k-nor-emmc          = "root=/dev/mmcblk1p1"
-
-# definitions for this target *_nor-nand boot
-UBOOT_EXTLINUX_BOOTPREFIXES_stm32mp-t1000-k_nor-nand  = "ubi0_stm32mp-t1000-k_"
-UBOOT_EXTLINUX_LABELS_stm32mp-t1000-k_nor-nand        = "stm32mp-t1000-k-nor-nand"
-UBOOT_EXTLINUX_DEFAULT_LABEL_stm32mp-t1000-k_nor-nand ?= "stm32mp-t1000-k-nor-nand"
-# label t1000-k
-UBOOT_EXTLINUX_FDT_stm32mp-t1000-k-nor-nand           = "/stm32mp-t1000-k.dtb"
-UBOOT_EXTLINUX_ROOT_stm32mp-t1000-k-nor-nand          = "ubi.mtd=5 rootfstype=ubifs root=ubi0_0"
diff --git a/conf/machine/include/extlinux-t1000-mini.inc b/conf/machine/include/extlinux-t1000-mini.inc
new file mode 100644
index 0000000000000000000000000000000000000000..e97d46b994ffeff2ff3d3456b135a1b8ca2368a7
--- /dev/null
+++ b/conf/machine/include/extlinux-t1000-mini.inc
@@ -0,0 +1,40 @@
+# =========================================================================
+# Extlinux boot commands for
+# Board: stm32mp-t1000-mini
+# =========================================================================
+# Define boot command lines
+#
+# The following bootschemes are supported
+# - boot from sdcard (BOOTPIN_0,2=1, BOOTPIN_1=0)
+# - boot from nor (BOOTPIN_0=1, BOOTPIN_3,2=0)
+#   When booting from nor u-boot variable 'boot_targets' select where to find
+#   the bootfs with EXTLINUX configuration
+#
+
+# add targets to generate
+UBOOT_EXTLINUX_TARGETS += "\
+	stm32mp-t1000-mini_sdcard \
+	stm32mp-t1000-mini_nor-emmc \
+	stm32mp-t1000-mini_nor-nand \
+"
+
+# definitions for this target *_sdcard boot
+UBOOT_EXTLINUX_BOOTPREFIXES_stm32mp-t1000-mini_sdcard    = "mmc0_stm32mp-t1000-mini_"
+UBOOT_EXTLINUX_LABELS_stm32mp-t1000-mini_sdcard          = "stm32mp-t1000-mini-sdcard"
+UBOOT_EXTLINUX_DEFAULT_LABEL_stm32mp-t1000-mini_sdcard   = "stm32mp-t1000-mini-sdcard"
+UBOOT_EXTLINUX_FDT_stm32mp-t1000-mini-sdcard             = "/stm32mp-t1000-mini.dtb"
+UBOOT_EXTLINUX_ROOT_stm32mp-t1000-mini-sdcard            = "root=/dev/mmcblk0p5"
+
+# definitions for this target *_nor-emmc boot
+UBOOT_EXTLINUX_BOOTPREFIXES_stm32mp-t1000-mini_nor-emmc  = "mmc1_stm32mp-t1000-mini_"
+UBOOT_EXTLINUX_LABELS_stm32mp-t1000-mini_nor-emmc        = "stm32mp-t1000-mini-nor-emmc"
+UBOOT_EXTLINUX_DEFAULT_LABEL_stm32mp-t1000-mini_nor-emmc = "stm32mp-t1000-mini-nor-emmc"
+UBOOT_EXTLINUX_FDT_stm32mp-t1000-mini-nor-emmc           = "/stm32mp-t1000-mini.dtb"
+UBOOT_EXTLINUX_ROOT_stm32mp-t1000-mini-nor-emmc          = "root=/dev/mmcblk1p2"
+
+# definitions for this target *_nor-nand boot
+UBOOT_EXTLINUX_BOOTPREFIXES_stm32mp-t1000-mini_nor-nand  = "ubifs0_stm32mp-t1000-mini_"
+UBOOT_EXTLINUX_LABELS_stm32mp-t1000-mini_nor-nand        = "stm32mp-t1000-mini-nor-nand"
+UBOOT_EXTLINUX_DEFAULT_LABEL_stm32mp-t1000-mini_nor-nand = "stm32mp-t1000-mini-nor-nand"
+UBOOT_EXTLINUX_FDT_stm32mp-t1000-mini-nor-nand           = "/stm32mp-t1000-mini.dtb"
+UBOOT_EXTLINUX_ROOT_stm32mp-t1000-mini-nor-nand          = "ubi.mtd=UBI rootfstype=ubifs root=ubi0:bootfs"
diff --git a/conf/machine/include/extlinux-t1000-s-24.inc b/conf/machine/include/extlinux-t1000-s-24.inc
deleted file mode 100644
index 84f92803deacbd8365e5afa2d8d3ef93f2a741e7..0000000000000000000000000000000000000000
--- a/conf/machine/include/extlinux-t1000-s-24.inc
+++ /dev/null
@@ -1,40 +0,0 @@
-# =========================================================================
-# Extlinux boot commands for
-# Board: stm32mp-t1000-s-24
-# =========================================================================
-# Define boot command lines
-#
-# The following bootschemes are supported
-# - boot from sdcard (BOOTPIN_0,2=1, BOOTPIN_1=0)
-# - boot from nor (BOOTPIN_0=1, BOOTPIN_3,2=0)
-#   When booting from nor u-boot variable 'boot_targets' select where to find
-#   the bootfs with EXTLINUX configuration
-#
-
-# add targets to generate
-UBOOT_EXTLINUX_TARGETS += "\
-	stm32mp-t1000-s-24_sdcard \
-	stm32mp-t1000-s-24_nor-emmc \
-	stm32mp-t1000-s-24_nor-nand \
-"
-
-# definitions for this target *_sdcard boot
-UBOOT_EXTLINUX_BOOTPREFIXES_stm32mp-t1000-s-24_sdcard    = "mmc0_stm32mp-t1000-s-24_"
-UBOOT_EXTLINUX_LABELS_stm32mp-t1000-s-24_sdcard          = "stm32mp-t1000-s-24-sdcard"
-UBOOT_EXTLINUX_DEFAULT_LABEL_stm32mp-t1000-s-24_sdcard   = "stm32mp-t1000-s-24-sdcard"
-UBOOT_EXTLINUX_FDT_stm32mp-t1000-s-24-sdcard             = "/boot/stm32mp-t1000-s-24.dtb"
-UBOOT_EXTLINUX_ROOT_stm32mp-t1000-s-24-sdcard            = "root=/dev/mmcblk0p4"
-
-# definitions for this target *_nor-emmc boot
-UBOOT_EXTLINUX_BOOTPREFIXES_stm32mp-t1000-s-24_nor-emmc  = "mmc1_stm32mp-t1000-s-24_"
-UBOOT_EXTLINUX_LABELS_stm32mp-t1000-s-24_nor-emmc        = "stm32mp-t1000-s-24-nor-emmc"
-UBOOT_EXTLINUX_DEFAULT_LABEL_stm32mp-t1000-s-24_nor-emmc = "stm32mp-t1000-s-24-nor-emmc"
-UBOOT_EXTLINUX_FDT_stm32mp-t1000-s-24-nor-emmc           = "/boot/stm32mp-t1000-s-24.dtb"
-UBOOT_EXTLINUX_ROOT_stm32mp-t1000-s-24-nor-emmc          = "root=/dev/mmcblk1p1"
-
-# definitions for this target *_nor-nand boot
-UBOOT_EXTLINUX_BOOTPREFIXES_stm32mp-t1000-s-24_nor-nand  = "ubi0_stm32mp-t1000-s-24_"
-UBOOT_EXTLINUX_LABELS_stm32mp-t1000-s-24_nor-nand        = "stm32mp-t1000-s-24-nor-nand"
-UBOOT_EXTLINUX_DEFAULT_LABEL_stm32mp-t1000-s-24_nor-nand = "stm32mp-t1000-s-24-nor-nand"
-UBOOT_EXTLINUX_FDT_stm32mp-t1000-s-24-nor-nand           = "/boot/stm32mp-t1000-s-24.dtb"
-UBOOT_EXTLINUX_ROOT_stm32mp-t1000-s-24-nor-nand          = "ubi.mtd=5 rootfstype=ubifs root=ubi0_0"
diff --git a/conf/machine/include/extlinux-t1000-s-43.inc b/conf/machine/include/extlinux-t1000-s-43.inc
index 161b01537f808383afd961ca65252dd73c4f4cb4..2acef2dbd72a0add309d2452fb100ea9ea96984a 100644
--- a/conf/machine/include/extlinux-t1000-s-43.inc
+++ b/conf/machine/include/extlinux-t1000-s-43.inc
@@ -1,6 +1,6 @@
 # =========================================================================
 # Extlinux boot commands for
-# Board: stm32mp-t1000-s-43
+# Board: stm32mp-t1000-mini
 # =========================================================================
 # Define boot command lines
 #
@@ -22,19 +22,19 @@ UBOOT_EXTLINUX_TARGETS += "\
 UBOOT_EXTLINUX_BOOTPREFIXES_stm32mp-t1000-s-43_sdcard    = "mmc0_stm32mp-t1000-s-43_"
 UBOOT_EXTLINUX_LABELS_stm32mp-t1000-s-43_sdcard          = "stm32mp-t1000-s-43-sdcard"
 UBOOT_EXTLINUX_DEFAULT_LABEL_stm32mp-t1000-s-43_sdcard   = "stm32mp-t1000-s-43-sdcard"
-UBOOT_EXTLINUX_FDT_stm32mp-t1000-s-43-sdcard             = "/boot/stm32mp-t1000-s-43.dtb"
-UBOOT_EXTLINUX_ROOT_stm32mp-t1000-s-43-sdcard            = "root=/dev/mmcblk0p4"
+UBOOT_EXTLINUX_FDT_stm32mp-t1000-s-43-sdcard             = "/stm32mp-t1000-s-43.dtb"
+UBOOT_EXTLINUX_ROOT_stm32mp-t1000-s-43-sdcard            = "root=/dev/mmcblk0p5"
 
 # definitions for this target *_nor-emmc boot
 UBOOT_EXTLINUX_BOOTPREFIXES_stm32mp-t1000-s-43_nor-emmc  = "mmc1_stm32mp-t1000-s-43_"
 UBOOT_EXTLINUX_LABELS_stm32mp-t1000-s-43_nor-emmc        = "stm32mp-t1000-s-43-nor-emmc"
 UBOOT_EXTLINUX_DEFAULT_LABEL_stm32mp-t1000-s-43_nor-emmc = "stm32mp-t1000-s-43-nor-emmc"
-UBOOT_EXTLINUX_FDT_stm32mp-t1000-s-43-nor-emmc           = "/boot/stm32mp-t1000-s-43.dtb"
-UBOOT_EXTLINUX_ROOT_stm32mp-t1000-s-43-nor-emmc          = "root=/dev/mmcblk1p1"
+UBOOT_EXTLINUX_FDT_stm32mp-t1000-s-43-nor-emmc           = "/stm32mp-t1000-s-43.dtb"
+UBOOT_EXTLINUX_ROOT_stm32mp-t1000-s-43-nor-emmc          = "root=/dev/mmcblk1p2"
 
 # definitions for this target *_nor-nand boot
-UBOOT_EXTLINUX_BOOTPREFIXES_stm32mp-t1000-s-43_nor-nand  = "ubi0_stm32mp-t1000-s-43_"
+UBOOT_EXTLINUX_BOOTPREFIXES_stm32mp-t1000-s-43_nor-nand  = "ubifs0_stm32mp-t1000-s-43_"
 UBOOT_EXTLINUX_LABELS_stm32mp-t1000-s-43_nor-nand        = "stm32mp-t1000-s-43-nor-nand"
 UBOOT_EXTLINUX_DEFAULT_LABEL_stm32mp-t1000-s-43_nor-nand = "stm32mp-t1000-s-43-nor-nand"
-UBOOT_EXTLINUX_FDT_stm32mp-t1000-s-43-nor-nand           = "/boot/stm32mp-t1000-s-43.dtb"
-UBOOT_EXTLINUX_ROOT_stm32mp-t1000-s-43-nor-nand          = "ubi.mtd=5 rootfstype=ubifs root=ubi0_0"
+UBOOT_EXTLINUX_FDT_stm32mp-t1000-s-43-nor-nand           = "/stm32mp-t1000-s-43.dtb"
+UBOOT_EXTLINUX_ROOT_stm32mp-t1000-s-43-nor-nand          = "ubi.mtd=UBI rootfstype=ubifs root=ubi0:bootfs"
diff --git a/conf/machine/include/extlinux-t1000-s-50.inc b/conf/machine/include/extlinux-t1000-s-50.inc
index b245c5e0a81cafe54d824f7b6648499eb4810ca5..f8f41a079b9e1b86b2a096d5300087237e0284e4 100644
--- a/conf/machine/include/extlinux-t1000-s-50.inc
+++ b/conf/machine/include/extlinux-t1000-s-50.inc
@@ -1,6 +1,6 @@
 # =========================================================================
 # Extlinux boot commands for
-# Board: stm32mp-t1000-s-50
+# Board: stm32mp-t1000-s
 # =========================================================================
 # Define boot command lines
 #
@@ -22,19 +22,19 @@ UBOOT_EXTLINUX_TARGETS += "\
 UBOOT_EXTLINUX_BOOTPREFIXES_stm32mp-t1000-s-50_sdcard    = "mmc0_stm32mp-t1000-s-50_"
 UBOOT_EXTLINUX_LABELS_stm32mp-t1000-s-50_sdcard          = "stm32mp-t1000-s-50-sdcard"
 UBOOT_EXTLINUX_DEFAULT_LABEL_stm32mp-t1000-s-50_sdcard   = "stm32mp-t1000-s-50-sdcard"
-UBOOT_EXTLINUX_FDT_stm32mp-t1000-s-50-sdcard             = "/boot/stm32mp-t1000-s-50.dtb"
-UBOOT_EXTLINUX_ROOT_stm32mp-t1000-s-50-sdcard            = "root=/dev/mmcblk0p4"
+UBOOT_EXTLINUX_FDT_stm32mp-t1000-s-50-sdcard             = "/stm32mp-t1000-s-50.dtb"
+UBOOT_EXTLINUX_ROOT_stm32mp-t1000-s-50-sdcard            = "root=/dev/mmcblk0p5"
 
 # definitions for this target *_nor-emmc boot
 UBOOT_EXTLINUX_BOOTPREFIXES_stm32mp-t1000-s-50_nor-emmc  = "mmc1_stm32mp-t1000-s-50_"
 UBOOT_EXTLINUX_LABELS_stm32mp-t1000-s-50_nor-emmc        = "stm32mp-t1000-s-50-nor-emmc"
 UBOOT_EXTLINUX_DEFAULT_LABEL_stm32mp-t1000-s-50_nor-emmc = "stm32mp-t1000-s-50-nor-emmc"
-UBOOT_EXTLINUX_FDT_stm32mp-t1000-s-50-nor-emmc           = "/boot/stm32mp-t1000-s-50.dtb"
-UBOOT_EXTLINUX_ROOT_stm32mp-t1000-s-50-nor-emmc          = "root=/dev/mmcblk1p1"
+UBOOT_EXTLINUX_FDT_stm32mp-t1000-s-50-nor-emmc           = "/stm32mp-t1000-s-50.dtb"
+UBOOT_EXTLINUX_ROOT_stm32mp-t1000-s-50-nor-emmc          = "root=/dev/mmcblk1p2"
 
 # definitions for this target *_nor-nand boot
-UBOOT_EXTLINUX_BOOTPREFIXES_stm32mp-t1000-s-50_nor-nand  = "ubi0_stm32mp-t1000-s-50_"
+UBOOT_EXTLINUX_BOOTPREFIXES_stm32mp-t1000-s-50_nor-nand  = "ubifs0_stm32mp-t1000-s-50_"
 UBOOT_EXTLINUX_LABELS_stm32mp-t1000-s-50_nor-nand        = "stm32mp-t1000-s-50-nor-nand"
 UBOOT_EXTLINUX_DEFAULT_LABEL_stm32mp-t1000-s-50_nor-nand = "stm32mp-t1000-s-50-nor-nand"
-UBOOT_EXTLINUX_FDT_stm32mp-t1000-s-50-nor-nand           = "/boot/stm32mp-t1000-s-50.dtb"
-UBOOT_EXTLINUX_ROOT_stm32mp-t1000-s-50-nor-nand          = "ubi.mtd=5 rootfstype=ubifs root=ubi0_0"
+UBOOT_EXTLINUX_FDT_stm32mp-t1000-s-50-nor-nand           = "/stm32mp-t1000-s-50.dtb"
+UBOOT_EXTLINUX_ROOT_stm32mp-t1000-s-50-nor-nand          = "ubi.mtd=UBI rootfstype=ubifs root=ubi0:bootfs"
diff --git a/conf/machine/include/extlinux-t1000-s-clkout32k.inc b/conf/machine/include/extlinux-t1000-s-clkout32k.inc
deleted file mode 100644
index 56a0f052b6f145307f9b30c900ac838c622286ec..0000000000000000000000000000000000000000
--- a/conf/machine/include/extlinux-t1000-s-clkout32k.inc
+++ /dev/null
@@ -1,40 +0,0 @@
-# =========================================================================
-# Extlinux boot commands for
-# Board: stm32mp-t1000-s-clkout32k
-# =========================================================================
-# Define boot command lines
-#
-# The following bootschemes are supported
-# - boot from sdcard (BOOTPIN_0,2=1, BOOTPIN_1=0)
-# - boot from nor (BOOTPIN_0=1, BOOTPIN_3,2=0)
-#   When booting from nor u-boot variable 'boot_targets' select where to find
-#   the bootfs with EXTLINUX configuration
-#
-
-# add targets to generate
-UBOOT_EXTLINUX_TARGETS += "\
-	stm32mp-t1000-s-clkout32k_sdcard \
-	stm32mp-t1000-s-clkout32k_nor-emmc \
-	stm32mp-t1000-s-clkout32k_nor-nand \
-"
-
-# definitions for this target *_sdcard boot
-UBOOT_EXTLINUX_BOOTPREFIXES_stm32mp-t1000-s-clkout32k_sdcard    = "mmc0_stm32mp-t1000-s-clkout32k_"
-UBOOT_EXTLINUX_LABELS_stm32mp-t1000-s-clkout32k_sdcard          = "stm32mp-t1000-s-clkout32k-sdcard"
-UBOOT_EXTLINUX_DEFAULT_LABEL_stm32mp-t1000-s-clkout32k_sdcard   = "stm32mp-t1000-s-clkout32k-sdcard"
-UBOOT_EXTLINUX_FDT_stm32mp-t1000-s-clkout32k-sdcard             = "/boot/stm32mp-t1000-s-clkout32k.dtb"
-UBOOT_EXTLINUX_ROOT_stm32mp-t1000-s-clkout32k-sdcard            = "root=/dev/mmcblk0p4"
-
-# definitions for this target *_nor-emmc boot
-UBOOT_EXTLINUX_BOOTPREFIXES_stm32mp-t1000-s-clkout32k_nor-emmc  = "mmc1_stm32mp-t1000-s-clkout32k_"
-UBOOT_EXTLINUX_LABELS_stm32mp-t1000-s-clkout32k_nor-emmc        = "stm32mp-t1000-s-clkout32k-nor-emmc"
-UBOOT_EXTLINUX_DEFAULT_LABEL_stm32mp-t1000-s-clkout32k_nor-emmc = "stm32mp-t1000-s-clkout32k-nor-emmc"
-UBOOT_EXTLINUX_FDT_stm32mp-t1000-s-clkout32k-nor-emmc           = "/boot/stm32mp-t1000-s-clkout32k.dtb"
-UBOOT_EXTLINUX_ROOT_stm32mp-t1000-s-clkout32k-nor-emmc          = "root=/dev/mmcblk1p1"
-
-# definitions for this target *_nor-nand boot
-UBOOT_EXTLINUX_BOOTPREFIXES_stm32mp-t1000-s-clkout32k_nor-nand  = "ubi0_stm32mp-t1000-s-clkout32k_"
-UBOOT_EXTLINUX_LABELS_stm32mp-t1000-s-clkout32k_nor-nand        = "stm32mp-t1000-s-clkout32k-nor-nand"
-UBOOT_EXTLINUX_DEFAULT_LABEL_stm32mp-t1000-s-clkout32k_nor-nand = "stm32mp-t1000-s-clkout32k-nor-nand"
-UBOOT_EXTLINUX_FDT_stm32mp-t1000-s-clkout32k-nor-nand           = "/boot/stm32mp-t1000-s-clkout32k.dtb"
-UBOOT_EXTLINUX_ROOT_stm32mp-t1000-s-clkout32k-nor-nand          = "ubi.mtd=5 rootfstype=ubifs root=ubi0_0"
diff --git a/conf/machine/include/extlinux-t1000-s.inc b/conf/machine/include/extlinux-t1000-s.inc
index bc26722f89a886bf3e0e1616aadc16f73303d57c..78e2a93ed4356118eda6f0b0e681ae5307a80032 100644
--- a/conf/machine/include/extlinux-t1000-s.inc
+++ b/conf/machine/include/extlinux-t1000-s.inc
@@ -1,6 +1,6 @@
 # =========================================================================
 # Extlinux boot commands for
-# Board: stm32mp-t1000-s
+# Board: stm32mp-t1000-mini
 # =========================================================================
 # Define boot command lines
 #
@@ -9,34 +9,32 @@
 # - boot from nor (BOOTPIN_0=1, BOOTPIN_3,2=0)
 #   When booting from nor u-boot variable 'boot_targets' select where to find
 #   the bootfs with EXTLINUX configuration
+#
 
 # add targets to generate
 UBOOT_EXTLINUX_TARGETS += "\
 	stm32mp-t1000-s_sdcard \
 	stm32mp-t1000-s_nor-emmc \
 	stm32mp-t1000-s_nor-nand \
-	"
+"
 
 # definitions for this target *_sdcard boot
 UBOOT_EXTLINUX_BOOTPREFIXES_stm32mp-t1000-s_sdcard    = "mmc0_stm32mp-t1000-s_"
 UBOOT_EXTLINUX_LABELS_stm32mp-t1000-s_sdcard          = "stm32mp-t1000-s-sdcard"
-UBOOT_EXTLINUX_DEFAULT_LABEL_stm32mp-t1000-s_sdcard   ?= "stm32mp-t1000-s-sdcard"
-# label t1000-s
-UBOOT_EXTLINUX_FDT_stm32mp-t1000-s-sdcard             = "/boot/stm32mp-t1000-s.dtb"
-UBOOT_EXTLINUX_ROOT_stm32mp-t1000-s-sdcard            = "root=/dev/mmcblk0p4"
+UBOOT_EXTLINUX_DEFAULT_LABEL_stm32mp-t1000-s_sdcard   = "stm32mp-t1000-s-sdcard"
+UBOOT_EXTLINUX_FDT_stm32mp-t1000-s-sdcard             = "/stm32mp-t1000-s.dtb"
+UBOOT_EXTLINUX_ROOT_stm32mp-t1000-s-sdcard            = "root=/dev/mmcblk0p5"
 
 # definitions for this target *_nor-emmc boot
 UBOOT_EXTLINUX_BOOTPREFIXES_stm32mp-t1000-s_nor-emmc  = "mmc1_stm32mp-t1000-s_"
 UBOOT_EXTLINUX_LABELS_stm32mp-t1000-s_nor-emmc        = "stm32mp-t1000-s-nor-emmc"
-UBOOT_EXTLINUX_DEFAULT_LABEL_stm32mp-t1000-s_nor-emmc ?= "stm32mp-t1000-s-nor-emmc"
-# label t1000-s
-UBOOT_EXTLINUX_FDT_stm32mp-t1000-s-nor-emmc           = "/boot/stm32mp-t1000-s.dtb"
-UBOOT_EXTLINUX_ROOT_stm32mp-t1000-s-nor-emmc          = "root=/dev/mmcblk1p1"
+UBOOT_EXTLINUX_DEFAULT_LABEL_stm32mp-t1000-s_nor-emmc = "stm32mp-t1000-s-nor-emmc"
+UBOOT_EXTLINUX_FDT_stm32mp-t1000-s-nor-emmc           = "/stm32mp-t1000-s.dtb"
+UBOOT_EXTLINUX_ROOT_stm32mp-t1000-s-nor-emmc          = "root=/dev/mmcblk1p2"
 
 # definitions for this target *_nor-nand boot
-UBOOT_EXTLINUX_BOOTPREFIXES_stm32mp-t1000-s_nor-nand  = "ubi0_stm32mp-t1000-s_"
+UBOOT_EXTLINUX_BOOTPREFIXES_stm32mp-t1000-s_nor-nand  = "ubifs0_stm32mp-t1000-s_"
 UBOOT_EXTLINUX_LABELS_stm32mp-t1000-s_nor-nand        = "stm32mp-t1000-s-nor-nand"
-UBOOT_EXTLINUX_DEFAULT_LABEL_stm32mp-t1000-s_nor-nand ?= "stm32mp-t1000-s-nor-nand"
-# label t1000-s
+UBOOT_EXTLINUX_DEFAULT_LABEL_stm32mp-t1000-s_nor-nand = "stm32mp-t1000-s-nor-nand"
 UBOOT_EXTLINUX_FDT_stm32mp-t1000-s-nor-nand           = "/stm32mp-t1000-s.dtb"
-UBOOT_EXTLINUX_ROOT_stm32mp-t1000-s-nor-nand          = "ubi.mtd=5 rootfstype=ubifs root=ubi0_0"
+UBOOT_EXTLINUX_ROOT_stm32mp-t1000-s-nor-nand          = "ubi.mtd=UBI rootfstype=ubifs root=ubi0:bootfs"
diff --git a/conf/machine/include/extlinux-t1000.inc b/conf/machine/include/extlinux-t1000.inc
deleted file mode 100644
index b804e2a39e2fd6b780ebe5213bb7981a1ff39dd0..0000000000000000000000000000000000000000
--- a/conf/machine/include/extlinux-t1000.inc
+++ /dev/null
@@ -1,32 +0,0 @@
-# =========================================================================
-# Extlinux boot commands for
-# Board: stm32mp-t1000
-# =========================================================================
-# Define boot command lines
-#
-# The following bootschemes are supported
-# - boot from sdcard (BOOTPIN_0,2=1, BOOTPIN_1=0)
-# - boot from nor (BOOTPIN_0=1, BOOTPIN_3,2=0)
-#   When booting from nor u-boot variable 'boot_targets' select where to find
-#   the bootfs with EXTLINUX configuration
-#
-
-# add targets to generate
-UBOOT_EXTLINUX_TARGETS += "\
-	stm32mp-t1000_sdcard \
-	stm32mp-t1000_nor-nand \
-"
-
-# definitions for this target *_sdcard boot
-UBOOT_EXTLINUX_BOOTPREFIXES_stm32mp-t1000_sdcard    = "mmc0_stm32mp-t1000_"
-UBOOT_EXTLINUX_LABELS_stm32mp-t1000_sdcard          = "stm32mp-t1000-sdcard"
-UBOOT_EXTLINUX_DEFAULT_LABEL_stm32mp-t1000_sdcard   = "stm32mp-t1000-sdcard"
-UBOOT_EXTLINUX_FDT_stm32mp-t1000-sdcard             = "/boot/stm32mp-t1000.dtb"
-UBOOT_EXTLINUX_ROOT_stm32mp-t1000-sdcard            = "root=/dev/mmcblk0p4"
-
-# definitions for this target *_nor-nand boot
-UBOOT_EXTLINUX_BOOTPREFIXES_stm32mp-t1000_nor-nand  = "ubi0_stm32mp-t1000_"
-UBOOT_EXTLINUX_LABELS_stm32mp-t1000_nor-nand        = "stm32mp-t1000-nor-nand"
-UBOOT_EXTLINUX_DEFAULT_LABEL_stm32mp-t1000_nor-nand = "stm32mp-t1000-nor-nand"
-UBOOT_EXTLINUX_FDT_stm32mp-t1000-nor-nand           = "/boot/stm32mp-t1000.dtb"
-UBOOT_EXTLINUX_ROOT_stm32mp-t1000-nor-nand          = "ubi.mtd=5 rootfstype=ubifs root=ubi0_0"
diff --git a/conf/machine/include/extlinux-t1001.inc b/conf/machine/include/extlinux-t1001.inc
deleted file mode 100644
index f7181b65a006ce3853b195b714622d5e1f25b295..0000000000000000000000000000000000000000
--- a/conf/machine/include/extlinux-t1001.inc
+++ /dev/null
@@ -1,24 +0,0 @@
-# =========================================================================
-# Extlinux boot commands for
-# Board: stm32mp-t1001
-# =========================================================================
-# Define boot command lines
-#
-# The following bootschemes are supported
-# - boot from sdcard (BOOTPIN_0,2=1, BOOTPIN_1=0)
-# - boot from nor (BOOTPIN_0=1, BOOTPIN_3,2=0)
-#   When booting from nor u-boot variable 'boot_targets' select where to find
-#   the bootfs with EXTLINUX configuration
-#
-
-# add targets to generate
-UBOOT_EXTLINUX_TARGETS += "\
-	stm32mp-t1001_sdcard \
-"
-
-# definitions for this target *_sdcard boot
-UBOOT_EXTLINUX_BOOTPREFIXES_stm32mp-t1001_sdcard    = "mmc0_stm32mp-t1001_"
-UBOOT_EXTLINUX_LABELS_stm32mp-t1001_sdcard          = "stm32mp-t1001-sdcard"
-UBOOT_EXTLINUX_DEFAULT_LABEL_stm32mp-t1001_sdcard   = "stm32mp-t1001-sdcard"
-UBOOT_EXTLINUX_FDT_stm32mp-t1001-sdcard             = "/boot/stm32mp-t1001.dtb"
-UBOOT_EXTLINUX_ROOT_stm32mp-t1001-sdcard            = "root=/dev/mmcblk0p4"
diff --git a/conf/machine/include/extlinux-t1004-k-50.inc b/conf/machine/include/extlinux-t1004-k-50.inc
deleted file mode 100644
index 233be4397fc70a6aee8fb479ddddabe2576b7efb..0000000000000000000000000000000000000000
--- a/conf/machine/include/extlinux-t1004-k-50.inc
+++ /dev/null
@@ -1,43 +0,0 @@
-# =========================================================================
-# Extlinux boot commands for
-# Board: stm32mp-t1004-k-50
-# =========================================================================
-# Define boot command lines
-#
-# The following bootschemes are supported
-# - boot from sdcard (BOOTPIN_0,2=1, BOOTPIN_1=0)
-# - boot from nor (BOOTPIN_0=1, BOOTPIN_3,2=0)
-#   When booting from nor u-boot variable 'boot_targets' select where to find
-#   the bootfs with EXTLINUX configuration
-#
-
-# add targets to generate
-UBOOT_EXTLINUX_TARGETS += "\
-	stm32mp-t1004-k-50_sdcard \
-	stm32mp-t1004-k-50_nor-emmc \
-	stm32mp-t1004-k-50_nor-nand \
-"
-
-# definitions for this target *_sdcard boot
-UBOOT_EXTLINUX_BOOTPREFIXES_stm32mp-t1004-k-50_sdcard    = "mmc0_stm32mp-t1004-k-50_"
-UBOOT_EXTLINUX_LABELS_stm32mp-t1004-k-50_sdcard          = "stm32mp-t1004-k-50-sdcard"
-UBOOT_EXTLINUX_DEFAULT_LABEL_stm32mp-t1004-k-50_sdcard   = "stm32mp-t1004-k-50-sdcard"
-# label t1004-k-50
-UBOOT_EXTLINUX_FDT_stm32mp-t1004-k-50-sdcard             = "/boot/stm32mp-t1004-k-50.dtb"
-UBOOT_EXTLINUX_ROOT_stm32mp-t1004-k-50-sdcard            = "root=/dev/mmcblk0p4"
-
-# definitions for this target *_nor-emmc boot
-UBOOT_EXTLINUX_BOOTPREFIXES_stm32mp-t1004-k-50_nor-emmc  = "mmc1_stm32mp-t1004-k-50_"
-UBOOT_EXTLINUX_LABELS_stm32mp-t1004-k-50_nor-emmc        = "stm32mp-t1004-k-50-nor-emmc"
-UBOOT_EXTLINUX_DEFAULT_LABEL_stm32mp-t1004-k-50_nor-emmc = "stm32mp-t1004-k-50-nor-emmc"
-# label t1004-k-50
-UBOOT_EXTLINUX_FDT_stm32mp-t1004-k-50-nor-emmc           = "/boot/stm32mp-t1004-k-50.dtb"
-UBOOT_EXTLINUX_ROOT_stm32mp-t1004-k-50-nor-emmc          = "root=/dev/mmcblk1p1"
-
-# definitions for this target *_nor-nand boot
-UBOOT_EXTLINUX_BOOTPREFIXES_stm32mp-t1004-k-50_nor-nand  = "ubi0_stm32mp-t1004-k-50_"
-UBOOT_EXTLINUX_LABELS_stm32mp-t1004-k-50_nor-nand        = "stm32mp-t1004-k-50-nor-nand"
-UBOOT_EXTLINUX_DEFAULT_LABEL_stm32mp-t1004-k-50_nor-nand = "stm32mp-t1004-k-50-nor-nand"
-# label t1004-k-50
-UBOOT_EXTLINUX_FDT_stm32mp-t1004-k-50-nor-nand           = "/boot/stm32mp-t1004-k-50.dtb"
-UBOOT_EXTLINUX_ROOT_stm32mp-t1004-k-50-nor-nand          = "ubi.mtd=5 rootfstype=ubifs root=ubi0_0"
diff --git a/conf/machine/include/extlinux-t1004-k.inc b/conf/machine/include/extlinux-t1004-k.inc
deleted file mode 100644
index 05d07e25c0ede33ac00e136d21d08b79a8525237..0000000000000000000000000000000000000000
--- a/conf/machine/include/extlinux-t1004-k.inc
+++ /dev/null
@@ -1,46 +0,0 @@
-# =========================================================================
-# Extlinux boot commands for
-# Board: stm32mp-t1004-k
-# =========================================================================
-# Define boot command lines
-#
-# The following bootschemes are supported
-# - boot from sdcard (BOOTPIN_0,2=1, BOOTPIN_1=0)
-# - boot from nor (BOOTPIN_0=1, BOOTPIN_3,2=0)
-#   When booting from nor u-boot variable 'boot_targets' select where to find
-#   the bootfs with EXTLINUX configuration
-#
-# This is a multi configuration file for all t1004-k configurations. With
-# extlinux it is possible to choose your different machine even when you have the
-# default t1004-k u-boot configuration
-
-# add targets to generate
-UBOOT_EXTLINUX_TARGETS += "\
-	stm32mp-t1004-k_sdcard \
-	stm32mp-t1004-k_nor-emmc \
-	stm32mp-t1004-k_nor-nand \
-	"
-
-# definitions for this target *_sdcard boot
-UBOOT_EXTLINUX_BOOTPREFIXES_stm32mp-t1004-k_sdcard    = "mmc0_stm32mp-t1004-k_"
-UBOOT_EXTLINUX_LABELS_stm32mp-t1004-k_sdcard          = "stm32mp-t1004-k-sdcard"
-UBOOT_EXTLINUX_DEFAULT_LABEL_stm32mp-t1004-k_sdcard   ?= "stm32mp-t1004-k-sdcard"
-# label t1004-k
-UBOOT_EXTLINUX_FDT_stm32mp-t1004-k-sdcard             = "/boot/stm32mp-t1004-k.dtb"
-UBOOT_EXTLINUX_ROOT_stm32mp-t1004-k-sdcard            = "root=/dev/mmcblk0p4"
-
-# definitions for this target *_nor-emmc boot
-UBOOT_EXTLINUX_BOOTPREFIXES_stm32mp-t1004-k_nor-emmc  = "mmc1_stm32mp-t1004-k_"
-UBOOT_EXTLINUX_LABELS_stm32mp-t1004-k_nor-emmc        = "stm32mp-t1004-k-nor-emmc"
-UBOOT_EXTLINUX_DEFAULT_LABEL_stm32mp-t1004-k_nor-emmc ?= "stm32mp-t1004-k-nor-emmc"
-# label t1004-k
-UBOOT_EXTLINUX_FDT_stm32mp-t1004-k-nor-emmc           = "/boot/stm32mp-t1004-k.dtb"
-UBOOT_EXTLINUX_ROOT_stm32mp-t1004-k-nor-emmc          = "root=/dev/mmcblk1p1"
-
-# definitions for this target *_nor-nand boot
-UBOOT_EXTLINUX_BOOTPREFIXES_stm32mp-t1004-k_nor-nand  = "ubi0_stm32mp-t1004-k_"
-UBOOT_EXTLINUX_LABELS_stm32mp-t1004-k_nor-nand        = "stm32mp-t1004-k-nor-nand"
-UBOOT_EXTLINUX_DEFAULT_LABEL_stm32mp-t1004-k_nor-nand ?= "stm32mp-t1004-k-nor-nand"
-# label t1004-k
-UBOOT_EXTLINUX_FDT_stm32mp-t1004-k-nor-nand           = "/stm32mp-t1004-k.dtb"
-UBOOT_EXTLINUX_ROOT_stm32mp-t1004-k-nor-nand          = "ubi.mtd=5 rootfstype=ubifs root=ubi0_0"
diff --git a/conf/machine/include/extlinux-t1004.inc b/conf/machine/include/extlinux-t1004.inc
deleted file mode 100644
index 0bbd3bcf63fc6372f8140616b2f0609e1a7033ad..0000000000000000000000000000000000000000
--- a/conf/machine/include/extlinux-t1004.inc
+++ /dev/null
@@ -1,32 +0,0 @@
-# =========================================================================
-# Extlinux boot commands for
-# Board: stm32mp-t1004
-# =========================================================================
-# Define boot command lines
-#
-# The following bootschemes are supported
-# - boot from sdcard (BOOTPIN_0,2=1, BOOTPIN_1=0)
-# - boot from nor (BOOTPIN_0=1, BOOTPIN_3,2=0)
-#   When booting from nor u-boot variable 'boot_targets' select where to find
-#   the bootfs with EXTLINUX configuration
-#
-
-# add targets to generate
-UBOOT_EXTLINUX_TARGETS += "\
-	stm32mp-t1004_sdcard \
-	stm32mp-t1004_nor-nand \
-"
-
-# definitions for this target *_sdcard boot
-UBOOT_EXTLINUX_BOOTPREFIXES_stm32mp-t1004_sdcard    = "mmc0_stm32mp-t1004_"
-UBOOT_EXTLINUX_LABELS_stm32mp-t1004_sdcard          = "stm32mp-t1004-sdcard"
-UBOOT_EXTLINUX_DEFAULT_LABEL_stm32mp-t1004_sdcard   = "stm32mp-t1004-sdcard"
-UBOOT_EXTLINUX_FDT_stm32mp-t1004-sdcard             = "/boot/stm32mp-t1004.dtb"
-UBOOT_EXTLINUX_ROOT_stm32mp-t1004-sdcard            = "root=/dev/mmcblk0p4"
-
-# definitions for this target *_nor-nand boot
-UBOOT_EXTLINUX_BOOTPREFIXES_stm32mp-t1004_nor-nand  = "ubi0_stm32mp-t1004_"
-UBOOT_EXTLINUX_LABELS_stm32mp-t1004_nor-nand        = "stm32mp-t1004-nor-nand"
-UBOOT_EXTLINUX_DEFAULT_LABEL_stm32mp-t1004_nor-nand = "stm32mp-t1004-nor-nand"
-UBOOT_EXTLINUX_FDT_stm32mp-t1004-nor-nand           = "/boot/stm32mp-t1004.dtb"
-UBOOT_EXTLINUX_ROOT_stm32mp-t1004-nor-nand          = "ubi.mtd=5 rootfstype=ubifs root=ubi0_0"
diff --git a/conf/machine/include/extlinux-t1005-k-50.inc b/conf/machine/include/extlinux-t1005-k-50.inc
deleted file mode 100644
index 585dd1d9bc5feb81f52c3d10e6329289e1ad2ef8..0000000000000000000000000000000000000000
--- a/conf/machine/include/extlinux-t1005-k-50.inc
+++ /dev/null
@@ -1,43 +0,0 @@
-# =========================================================================
-# Extlinux boot commands for
-# Board: stm32mp-t1005-k-50
-# =========================================================================
-# Define boot command lines
-#
-# The following bootschemes are supported
-# - boot from sdcard (BOOTPIN_0,2=1, BOOTPIN_1=0)
-# - boot from nor (BOOTPIN_0=1, BOOTPIN_3,2=0)
-#   When booting from nor u-boot variable 'boot_targets' select where to find
-#   the bootfs with EXTLINUX configuration
-#
-
-# add targets to generate
-UBOOT_EXTLINUX_TARGETS += "\
-	stm32mp-t1005-k-50_sdcard \
-	stm32mp-t1005-k-50_nor-emmc \
-	stm32mp-t1005-k-50_nor-nand \
-"
-
-# definitions for this target *_sdcard boot
-UBOOT_EXTLINUX_BOOTPREFIXES_stm32mp-t1005-k-50_sdcard    = "mmc0_stm32mp-t1005-k-50_"
-UBOOT_EXTLINUX_LABELS_stm32mp-t1005-k-50_sdcard          = "stm32mp-t1005-k-50-sdcard"
-UBOOT_EXTLINUX_DEFAULT_LABEL_stm32mp-t1005-k-50_sdcard   = "stm32mp-t1005-k-50-sdcard"
-# label t1005-k-50
-UBOOT_EXTLINUX_FDT_stm32mp-t1005-k-50-sdcard             = "/boot/stm32mp-t1005-k-50.dtb"
-UBOOT_EXTLINUX_ROOT_stm32mp-t1005-k-50-sdcard            = "root=/dev/mmcblk0p4"
-
-# definitions for this target *_nor-emmc boot
-UBOOT_EXTLINUX_BOOTPREFIXES_stm32mp-t1005-k-50_nor-emmc  = "mmc1_stm32mp-t1005-k-50_"
-UBOOT_EXTLINUX_LABELS_stm32mp-t1005-k-50_nor-emmc        = "stm32mp-t1005-k-50-nor-emmc"
-UBOOT_EXTLINUX_DEFAULT_LABEL_stm32mp-t1005-k-50_nor-emmc = "stm32mp-t1005-k-50-nor-emmc"
-# label t1005-k-50
-UBOOT_EXTLINUX_FDT_stm32mp-t1005-k-50-nor-emmc           = "/boot/stm32mp-t1005-k-50.dtb"
-UBOOT_EXTLINUX_ROOT_stm32mp-t1005-k-50-nor-emmc          = "root=/dev/mmcblk1p1"
-
-# definitions for this target *_nor-nand boot
-UBOOT_EXTLINUX_BOOTPREFIXES_stm32mp-t1005-k-50_nor-nand  = "ubi0_stm32mp-t1005-k-50_"
-UBOOT_EXTLINUX_LABELS_stm32mp-t1005-k-50_nor-nand        = "stm32mp-t1005-k-50-nor-nand"
-UBOOT_EXTLINUX_DEFAULT_LABEL_stm32mp-t1005-k-50_nor-nand = "stm32mp-t1005-k-50-nor-nand"
-# label t1005-k-50
-UBOOT_EXTLINUX_FDT_stm32mp-t1005-k-50-nor-nand           = "/boot/stm32mp-t1005-k-50.dtb"
-UBOOT_EXTLINUX_ROOT_stm32mp-t1005-k-50-nor-nand          = "ubi.mtd=5 rootfstype=ubifs root=ubi0_0"
diff --git a/conf/machine/include/extlinux-t1005-k.inc b/conf/machine/include/extlinux-t1005-k.inc
deleted file mode 100644
index cafab0fdd5602f44ea13e3c0f4ea3f66c9726faf..0000000000000000000000000000000000000000
--- a/conf/machine/include/extlinux-t1005-k.inc
+++ /dev/null
@@ -1,46 +0,0 @@
-# =========================================================================
-# Extlinux boot commands for
-# Board: stm32mp-t1005-k
-# =========================================================================
-# Define boot command lines
-#
-# The following bootschemes are supported
-# - boot from sdcard (BOOTPIN_0,2=1, BOOTPIN_1=0)
-# - boot from nor (BOOTPIN_0=1, BOOTPIN_3,2=0)
-#   When booting from nor u-boot variable 'boot_targets' select where to find
-#   the bootfs with EXTLINUX configuration
-#
-# This is a multi configuration file for all t1005-k configurations. With
-# extlinux it is possible to choose your different machine even when you have the
-# default t1005-k u-boot configuration
-
-# add targets to generate
-UBOOT_EXTLINUX_TARGETS += "\
-	stm32mp-t1005-k_sdcard \
-	stm32mp-t1005-k_nor-emmc \
-	stm32mp-t1005-k_nor-nand \
-	"
-
-# definitions for this target *_sdcard boot
-UBOOT_EXTLINUX_BOOTPREFIXES_stm32mp-t1005-k_sdcard    = "mmc0_stm32mp-t1005-k_"
-UBOOT_EXTLINUX_LABELS_stm32mp-t1005-k_sdcard          = "stm32mp-t1005-k-sdcard"
-UBOOT_EXTLINUX_DEFAULT_LABEL_stm32mp-t1005-k_sdcard   ?= "stm32mp-t1005-k-sdcard"
-# label t1005-k
-UBOOT_EXTLINUX_FDT_stm32mp-t1005-k-sdcard             = "/boot/stm32mp-t1005-k.dtb"
-UBOOT_EXTLINUX_ROOT_stm32mp-t1005-k-sdcard            = "root=/dev/mmcblk0p4"
-
-# definitions for this target *_nor-emmc boot
-UBOOT_EXTLINUX_BOOTPREFIXES_stm32mp-t1005-k_nor-emmc  = "mmc1_stm32mp-t1005-k_"
-UBOOT_EXTLINUX_LABELS_stm32mp-t1005-k_nor-emmc        = "stm32mp-t1005-k-nor-emmc"
-UBOOT_EXTLINUX_DEFAULT_LABEL_stm32mp-t1005-k_nor-emmc ?= "stm32mp-t1005-k-nor-emmc"
-# label t1005-k
-UBOOT_EXTLINUX_FDT_stm32mp-t1005-k-nor-emmc           = "/boot/stm32mp-t1005-k.dtb"
-UBOOT_EXTLINUX_ROOT_stm32mp-t1005-k-nor-emmc          = "root=/dev/mmcblk1p1"
-
-# definitions for this target *_nor-nand boot
-UBOOT_EXTLINUX_BOOTPREFIXES_stm32mp-t1005-k_nor-nand  = "ubi0_stm32mp-t1005-k_"
-UBOOT_EXTLINUX_LABELS_stm32mp-t1005-k_nor-nand        = "stm32mp-t1005-k-nor-nand"
-UBOOT_EXTLINUX_DEFAULT_LABEL_stm32mp-t1005-k_nor-nand ?= "stm32mp-t1005-k-nor-nand"
-# label t1005-k
-UBOOT_EXTLINUX_FDT_stm32mp-t1005-k-nor-nand           = "/stm32mp-t1005-k.dtb"
-UBOOT_EXTLINUX_ROOT_stm32mp-t1005-k-nor-nand          = "ubi.mtd=5 rootfstype=ubifs root=ubi0_0"
diff --git a/conf/machine/include/extlinux-t1005.inc b/conf/machine/include/extlinux-t1005.inc
deleted file mode 100644
index e2ae32313aa09ccd3d9e6dd2dfcae043b1c8fb8c..0000000000000000000000000000000000000000
--- a/conf/machine/include/extlinux-t1005.inc
+++ /dev/null
@@ -1,32 +0,0 @@
-# =========================================================================
-# Extlinux boot commands for
-# Board: stm32mp-t1005
-# =========================================================================
-# Define boot command lines
-#
-# The following bootschemes are supported
-# - boot from sdcard (BOOTPIN_0,2=1, BOOTPIN_1=0)
-# - boot from nor (BOOTPIN_0=1, BOOTPIN_3,2=0)
-#   When booting from nor u-boot variable 'boot_targets' select where to find
-#   the bootfs with EXTLINUX configuration
-#
-
-# add targets to generate
-UBOOT_EXTLINUX_TARGETS += "\
-	stm32mp-t1005_sdcard \
-	stm32mp-t1005_nor-nand \
-"
-
-# definitions for this target *_sdcard boot
-UBOOT_EXTLINUX_BOOTPREFIXES_stm32mp-t1005_sdcard    = "mmc0_stm32mp-t1005_"
-UBOOT_EXTLINUX_LABELS_stm32mp-t1005_sdcard          = "stm32mp-t1005-sdcard"
-UBOOT_EXTLINUX_DEFAULT_LABEL_stm32mp-t1005_sdcard   = "stm32mp-t1005-sdcard"
-UBOOT_EXTLINUX_FDT_stm32mp-t1005-sdcard             = "/boot/stm32mp-t1005.dtb"
-UBOOT_EXTLINUX_ROOT_stm32mp-t1005-sdcard            = "root=/dev/mmcblk0p4"
-
-# definitions for this target *_nor-nand boot
-UBOOT_EXTLINUX_BOOTPREFIXES_stm32mp-t1005_nor-nand  = "ubi0_stm32mp-t1005_"
-UBOOT_EXTLINUX_LABELS_stm32mp-t1005_nor-nand        = "stm32mp-t1005-nor-nand"
-UBOOT_EXTLINUX_DEFAULT_LABEL_stm32mp-t1005_nor-nand = "stm32mp-t1005-nor-nand"
-UBOOT_EXTLINUX_FDT_stm32mp-t1005-nor-nand           = "/boot/stm32mp-t1005.dtb"
-UBOOT_EXTLINUX_ROOT_stm32mp-t1005-nor-nand          = "ubi.mtd=5 rootfstype=ubifs root=ubi0_0"
diff --git a/conf/machine/include/stm32mp-t1000-common.inc b/conf/machine/include/stm32mp-t1000-common.inc
index e45e2085d5c06b3e9c744b9e179933787f8d47bd..5f69bb45147d01a6e8936aab221e38afb814a262 100644
--- a/conf/machine/include/stm32mp-t1000-common.inc
+++ b/conf/machine/include/stm32mp-t1000-common.inc
@@ -4,43 +4,31 @@
 #@NEEDED_BSPLAYERS: meta-st-stm32mp
 
 PREFERRED_PROVIDER_virtual/kernel = "linux-stm32mp"
-PREFERRED_VERSION_linux-stm32mp ?= "4.19"
-PREFERRED_PROVIDER_virtual/bootloader = "u-boot-stm32mp"
-PREFERRED_VERSION_u-boot-stm32mp ?= "2018.11"
+PREFERRED_VERSION_linux-stm32mp ?= "4.14"
+# PREFERRED_PROVIDER_virtual/bootloader doesn't exist because multiple
+# u-boot loaders can be built (see meta-st-stm32mp/recipes-bsp/u-boot/u-boot-stm32mp.inc
 
 include conf/machine/include/st-machine-common-stm32mp.inc
-# =========================================================================
-# Remove obsolete settings from ST
-# =========================================================================
-MACHINE_EXTRA_RRECOMMENDS_remove = " linux-examples-stm32mp1 "
-MACHINE_EXTRA_RRECOMMENDS_remove = " m4projects-stm32mp1 "
-INHERIT_remove = " flashlayout-stm32mp "
-EXTRA_IMAGEDEPENDS_remove = "sdcard-raw-tools-native"
-IMAGE_CLASSES_remove = "image_types-stubi"
 
-# Do not yet remove st-partitions-image because it is needed for image-stm32mp-* images
-#IMAGE_CLASSES_remove = "st-partitions-image"
-UBOOT_SPLASH_IMAGE = ""
+# Define specific common layer name
+MACHINEOVERRIDES =. "stm32mp-t1000:"
 
-# If required extra partitions are defined in main rootfs image, not in machine
-PARTITIONS_IMAGE = ""
-PARTITIONS_MOUNTPOINT_IMAGE = ""
+# =========================================================================
+# Machine features
+# =========================================================================
+MACHINE_FEATURES += "${@'gpu' if d.getVar('ACCEPT_EULA_'+d.getVar('MACHINE', True), True) == '1' else ''}"
 
-# We don't use STs UBI image generation options
-ENABLE_MULTIVOLUME_UBI="0"
 
 # =========================================================================
 # Machine settings
 # =========================================================================
-# Define specific common layer name
-MACHINEOVERRIDES =. "stm32mp-t10xx:"
-
-# Extend machine feature
-MACHINE_FEATURES += "${@'gpu' if d.getVar('ACCEPT_EULA_'+d.getVar('MACHINE', True), True) == '1' else ''}"
+# Default machine feature
+# See ST definition
+#MACHINE_FEATURES = "usbhost usbgadget alsa screen ext2"
 
 # Default serial consoles (TTYs) to enable using getty
-SERIAL_CONSOLES = "115200;ttySTM0"
-SERIAL_CONSOLE = "115200 ttySTM0"
+SERIAL_CONSOLES = "115200;ttyS3"
+SERIAL_CONSOLE = "115200 ttyS3"
 
 # We have no soundcard (yet). So remove configuration and current settings file
 # from OpenST for alsa
@@ -48,26 +36,294 @@ MACHINE_EXTRA_RRECOMMENDS_remove = "alsa-state-stm32mp1"
 
 # What should be built alongside this image
 EXTRA_IMAGEDEPENDS += "tf-a-stm32mp"
-EXTRA_IMAGEDEPENDS += "u-boot-stm32mp"
+EXTRA_IMAGEDEPENDS += "u-boot-basic-stm32mp"
+EXTRA_IMAGEDEPENDS += "u-boot-trusted-stm32mp"
 
+# =========================================================================
 # Chip architecture
+# =========================================================================
 DEFAULTTUNE = "cortexa7thf-neon-vfpv4"
 include conf/machine/include/tune-cortexa7.inc
 
-# Kernel settings
-ST_KERNEL_LOADADDR   = "0xC2000040"
+
+# =========================================================================
+# Kernel
+# =========================================================================
+# Kernel config
+ST_KERNEL_ENTRYPOINT = "0xC0008000"
+ST_KERNEL_LOADADDR   = "0xC0008000"
 
 
 # =========================================================================
-# License settings
+# U-Boot
 # =========================================================================
 
-# Enable licence summary and configure License content generation
-ENABLE_IMAGE_LICENSE_SUMMARY = "1"
-IMAGE_SUMMARY_LIST = "#IMAGE#:${STM32MP_USERFS_IMAGE}"
+UBOOT_CONFIG_FILEPATTERN = "_devicetree_"
+
+# Set u-boot configuration (combination of devicetree and defconfig)
+UBOOT_DEVICETREE = ""
+
 
 # =========================================================================
-# Common Extlinux boot settings
+# Image
+# =========================================================================
+# Append ubi FSTYPES to default ones
+IMAGE_FSTYPES = "tar.xz ext4 stmultiubi"
+
+# Define image to use for extra partitions
+STM32MP_BOOTFS_IMAGE = "st-image-bootfs"
+STM32MP_USERFS_IMAGE = "st-image-userfs"
+
+# Define extra partition to build
+PARTITIONS_IMAGE = "${STM32MP_BOOTFS_IMAGE} ${STM32MP_USERFS_IMAGE}"
+
+# Define image partition size (supposed to be set as max size in image recipe)
+# Bootfs partition size 20MB (kernel ~7MB)
+BOOTFS_PARTITION_SIZE = "20480"
+#Rootfs partition size 512MB
+#ROOTFS_PARTITION_SIZE = "524288"
+# Rootfs partition size (with Qt)
+ROOTFS_PARTITION_SIZE = "786432"
+# Userfs partition size 128MB
+USERFS_PARTITION_SIZE = "131072"
+# Pay attention: QSPI NAND is 512MB on
+# Overall size: fsbl1+2 2x256k, ssbl 2M, bootfs 20M, rootfs 512M, userfs 128M
+
+# Define volume list for multivolume UBIFS
+STM32MP_UBI_VOLUME += "${STM32MP_BOOTFS_IMAGE}-${DISTRO}-${MACHINE}:${BOOTFS_PARTITION_SIZE}"
+STM32MP_UBI_VOLUME += "${IMAGE_LINK_NAME}:${ROOTFS_PARTITION_SIZE}"
+STM32MP_UBI_VOLUME += "${STM32MP_USERFS_IMAGE}-${DISTRO}-${MACHINE}:${USERFS_PARTITION_SIZE}"
+
+# Set on machine side the max size for ROOTFS image to apply for default rootfs being built
+# On other image partition such settings is directly done in image recipe
+IMAGE_ROOTFS_MAXSIZE ?= "${ROOTFS_PARTITION_SIZE}"
+
+# ST Naming rules partitions for UBI format are :
+#   nand_<PageSize>_<BlockSize>
+#   nor_<BlockSize>
+# Like that a same UBI partition can be used for severals NAND/NOR providers
+
+# UBI Args for NAND soldered by default on MB1262
+# Micron MT29F8G16ABACAH4
+# LEB = BLOCK_SIZE - (2 * page size): 256*1024 - (2*4096)
+MKUBIFS_ARGS_nand_4_256 = "--min-io-size 4096 --leb-size 253952 --max-leb-cnt 4096 --space-fixup"
+UBINIZE_ARGS_nand_4_256 = "--min-io-size 4096 --peb-size 256KiB"
+
+# Define UBI labels to build
+MULTIUBI_BUILD = " nand_4_256 "
+
+# TODO: set correct values for this flash type
+# currently mtdinfo reports some weird values (i/o size of 4069)
+#
+#   root@stmxceet:~# ubiformat /dev/mtd3
+#   ubiformat: error!: min. I/O size is 4069, but should be power of 2
+#
+# -> wait for new kernel
+#   root@stmxceet:~# mtdinfo -u /dev/mtd3
+#   mtd3
+#   Name:                           spi0.1
+#   Type:                           nand
+#   Eraseblock size:                260416 bytes, 254.3 KiB
+#    of eraseblocks:          2048 (533331968 bytes, 508.6 MiB)
+#   Minimum input/output unit size: 4069 bytes
+#   Sub-page size:                  4069 bytes
+#   OOB size:                       256 bytes
+#   Character device major/minor:   90:6
+#   Bad blocks are allowed:         true
+#   Device is writable:             true
+#   Default UBI VID header offset:  4069
+#   Default UBI data offset:        8138
+#   Default UBI LEB size:           252278 bytes, 246.4 KiB
+#   Maximum UBI volumes count:      128
+
+
+# =========================================================================
+# flashlayout files for STM32_Programmer (has to fit with image definitions!)
+# =========================================================================
+#
+# Generate flashlayout files
+FLASHLAYOUT_PARTITION_ENABLE = "1"
+
+# Define which flashlayout file should be generated
+# sdcard   - booting from sdcard
+# nor-emmc - bootloader (tf-a, u-boot) is in NOR flash, rootfs etc. is in eMMC
+# nor-nand - bootloader (tf-a, u-boot) is in NOR flash, rootfs etc. is in QSPI NAND
+FLASHLAYOUT_CONFIG_LABELS = "sdcard nor-emmc nor-nand-4-256"
+FLASHLAYOUT_RESTRICTION_TYPES_sdcard = ""
+FLASHLAYOUT_RESTRICTION_TYPES_nor-emmc = ""
+FLASHLAYOUT_RESTRICTION_TYPES_nor-nand-4-256 = ""
+
+# Define which bootschemes should be generated
+# basic   - only for board bringup (DDR calibration)
+# trusted - standard configuration
+FLASHLAYOUT_BOOTSCHEME_LABELS = "basic trusted"
+
+# -----------------------------------------------------------------------------
+# Partition configuration for each partition label
+# NOTE: each item can be defined with following priority assignment:
+#           1) item_<BOOTSCHEME>_<CONFIG>_<PARTITION>
+#           2) item_<BOOTSCHEME>_<CONFIG>
+#           3) item_<BOOTSCHEME>_<PARTITION>
+#           4) item_<BOOTSCHEME>
+#           5) item_<CONFIG>_<PARTITION>
+#           6) item_<CONFIG>
+#           7) item_<PARTITION>
+#           8) Default 'item' to 'none' when not defined
+# -----------------------------------------------------------------------------
+
+# -----------------------------------------------------------------------------
+# Define common partitions IDs
+# -----------------------------------------------------------------------------
+# common partition ids
+FLASHLAYOUT_PARTITION_ID_fsbl1  = "0x01"
+FLASHLAYOUT_PARTITION_ID_fsbl2  = "0x02"
+FLASHLAYOUT_PARTITION_ID_ssbl   = "0x03"
+FLASHLAYOUT_PARTITION_ID_env    = "0x04"
+FLASHLAYOUT_PARTITION_ID_empty  = "0x10"
+FLASHLAYOUT_PARTITION_ID_bootfs = "0x11"
+FLASHLAYOUT_PARTITION_ID_rootfs = "0x12"
+FLASHLAYOUT_PARTITION_ID_userfs = "0x13"
+
+
+# -----------------------------------------------------------------------------
+# Define common partitions types
+# -----------------------------------------------------------------------------
+# common partition types
+FLASHLAYOUT_PARTITION_TYPE                  = "Binary"
+FLASHLAYOUT_PARTITION_TYPE_env              = "Empty"
+FLASHLAYOUT_PARTITION_TYPE_empty            = "Empty"
+FLASHLAYOUT_PARTITION_TYPE_bootfs           = "System"
+FLASHLAYOUT_PARTITION_TYPE_rootfs           = "FileSystem"
+FLASHLAYOUT_PARTITION_TYPE_userfs           = "FileSystem"
+
+
+# -----------------------------------------------------------------------------
+# Define common partitions contents
+# -----------------------------------------------------------------------------
+# Set default binaries to flash for each partition
+
+# trusted configuration
+FLASHLAYOUT_PARTITION_BIN2LOAD_trusted_fsbl1   = "tf-a.stm32"
+FLASHLAYOUT_PARTITION_BIN2LOAD_trusted_fsbl2   = "tf-a.stm32"
+FLASHLAYOUT_PARTITION_BIN2LOAD_trusted_ssbl    = "u-boot.stm32"
+FLASHLAYOUT_PARTITION_BIN2LOAD_trusted_bootfs  = "${STM32MP_BOOTFS_IMAGE}-${DISTRO}-${MACHINE}.ext4"
+FLASHLAYOUT_PARTITION_BIN2LOAD_trusted_rootfs  = "${IMAGE_LINK_NAME}.ext4"
+FLASHLAYOUT_PARTITION_BIN2LOAD_trusted_userfs  = "${STM32MP_USERFS_IMAGE}-${DISTRO}-${MACHINE}.ext4"
+
+# basic configuration
+FLASHLAYOUT_PARTITION_BIN2LOAD_basic_fsbl1   = "u-boot-spl.stm32"
+FLASHLAYOUT_PARTITION_BIN2LOAD_basic_fsbl2   = "u-boot-spl.stm32"
+FLASHLAYOUT_PARTITION_BIN2LOAD_basic_ssbl    = "u-boot.img"
+FLASHLAYOUT_PARTITION_BIN2LOAD_basic_bootfs  = "none"
+FLASHLAYOUT_PARTITION_BIN2LOAD_basic_rootfs = "none"
+FLASHLAYOUT_PARTITION_BIN2LOAD_basic_userfs = "none"
+
+# Binaries to boot from RAM (only board bring up)
+FLASHLAYOUT_PARTITION_BIN2BOOT_fsbl1 = "tf-a.stm32"
+FLASHLAYOUT_PARTITION_BIN2BOOT_fsbl2 = "tf-a.stm32"
+FLASHLAYOUT_PARTITION_BIN2BOOT_ssbl = "u-boot.stm32"
+
+
+# -----------------------------------------------------------------------------
+# Define flash layouts
+# -----------------------------------------------------------------------------
+
+# sdcard flashlayout
+# -----------------------------------------------------------------------------
+# fsbl1  on SDMMC1 size 0x00040000 (256k)
+# fsbl2  on SDMMC1 size 0x00040000 (256k)
+# ssbl   on SDMMC1 size 0x00200000 (2M)
+# bootfs on SDMMC1 size 0x01400000 (20M)
+# rootfs on SDMMC1 size 0x20000000 (512M)
+# userfs on SDMMC1 size rest of device
+
+FLASHLAYOUT_PARTITION_LABELS = "fsbl1 fsbl2 ssbl bootfs rootfs userfs"
+
+# Device SDMMC1
+# Fixed offsets in ROM code (cut1 version) for fsbl1 and fsbl2: 0x4400, 0x44400
+FLASHLAYOUT_PARTITION_DEVICE_sdcard = "SDMMC1"
+FLASHLAYOUT_PARTITION_OFFSET_sdcard_fsbl1  = "0x00004400"
+FLASHLAYOUT_PARTITION_OFFSET_sdcard_fsbl2  = "0x00044400"
+FLASHLAYOUT_PARTITION_OFFSET_sdcard_ssbl   = "0x00084400"
+FLASHLAYOUT_PARTITION_OFFSET_sdcard_bootfs = "0x00284400"
+FLASHLAYOUT_PARTITION_OFFSET_sdcard_rootfs = "0x01684400"
+FLASHLAYOUT_PARTITION_OFFSET_sdcard_userfs = "0x21684400"
+
+
+# nor-emmc flashlayout
+# -----------------------------------------------------------------------------
+# fsbl1  on SPI1   size 0x40000 (256k)
+# fsbl2  on SPI1   size 0x40000 (256k)
+# ssbl   on SPI1   size 0x100000 (1M)
+# empty  on SPI1   size rest of device
+# bootfs on SDMMC2 size 0x01400000 (20M)
+# rootfs on SDMMC2 size 0x20000000 (512M)
+# userfs on SDMMC2 size rest of device
+# 'empty' partition is a fake partition just to limit ssbl size to 2MBytes
+
+FLASHLAYOUT_PARTITION_LABELS_nor-emmc = "fsbl1 fsbl2 ssbl env empty bootfs rootfs userfs"
+
+# Device SPI1
+# Fixed offsets in ROM code for fsbl1 and fsbl2: 0x0, 0x40000
+FLASHLAYOUT_PARTITION_DEVICE_nor-emmc_fsbl1  = "SPI1"
+FLASHLAYOUT_PARTITION_DEVICE_nor-emmc_fsbl2  = "SPI1"
+FLASHLAYOUT_PARTITION_DEVICE_nor-emmc_ssbl   = "SPI1"
+FLASHLAYOUT_PARTITION_OFFSET_nor-emmc_fsbl1  = "0x00000000"
+FLASHLAYOUT_PARTITION_OFFSET_nor-emmc_fsbl2  = "0x00040000"
+FLASHLAYOUT_PARTITION_OFFSET_nor-emmc_ssbl   = "0x00080000"
+FLASHLAYOUT_PARTITION_OFFSET_nor-emmc_env    = "0x00180000"
+FLASHLAYOUT_PARTITION_OFFSET_nor-emmc_empty  = "0x00190000"
+
+# Device SDMMC2
+FLASHLAYOUT_PARTITION_DEVICE_nor-emmc_bootfs = "SDMMC2"
+FLASHLAYOUT_PARTITION_DEVICE_nor-emmc_rootfs = "SDMMC2"
+FLASHLAYOUT_PARTITION_DEVICE_nor-emmc_userfs = "SDMMC2"
+FLASHLAYOUT_PARTITION_OFFSET_nor-emmc_bootfs = "0x00004400"
+FLASHLAYOUT_PARTITION_OFFSET_nor-emmc_rootfs = "0x01404400"
+FLASHLAYOUT_PARTITION_OFFSET_nor-emmc_userfs = "0x21404400"
+
+
+# nor-nand-4-256 flashlayout
+# -----------------------------------------------------------------------------
+# fsbl1  on SPI1   size 0x40000 (256k)
+# fsbl2  on SPI1   size 0x40000 (256k)
+# ssbl   on SPI1   size 0x100000 (1M)
+# empty  on SPI1   size rest of device
+# bootfs on FMC    size 0x01400000 (20M)
+# rootfs on FMC    size 0x20000000 (392M)
+# userfs on FMC    size rest of device (100M)
+# 'empty' partition is a fake partition just to limit ssbl size to 2MBytes
+
+FLASHLAYOUT_PARTITION_LABELS_nor-nand-4-256 = "fsbl1 fsbl2 ssbl empty bootfs rootfs userfs"
+
+# Device SPI1
+# Fixed offsets in ROM code for fsbl1 and fsbl2: 0x0, 0x40000
+FLASHLAYOUT_PARTITION_DEVICE_nor-nand-4-256_fsbl1  = "SPI1"
+FLASHLAYOUT_PARTITION_DEVICE_nor-nand-4-256_fsbl2  = "SPI1"
+FLASHLAYOUT_PARTITION_DEVICE_nor-nand-4-256_ssbl   = "SPI1"
+FLASHLAYOUT_PARTITION_OFFSET_nor-nand-4-256_fsbl1  = "0x00000000"
+FLASHLAYOUT_PARTITION_OFFSET_nor-nand-4-256_fsbl2  = "0x00040000"
+FLASHLAYOUT_PARTITION_OFFSET_nor-nand-4-256_ssbl   = "0x00080000"
+FLASHLAYOUT_PARTITION_OFFSET_nor-nand-4-256_env    = "0x00180000"
+FLASHLAYOUT_PARTITION_OFFSET_nor-nand-4-256_empty  = "0x00190000"
+
+# Device FMC1
+FLASHLAYOUT_PARTITION_DEVICE_nor-nand-4-256_bootfs = "FMC1"
+FLASHLAYOUT_PARTITION_DEVICE_nor-nand-4-256_rootfs = "FMC1"
+FLASHLAYOUT_PARTITION_DEVICE_nor-nand-4-256_userfs = "FMC1"
+FLASHLAYOUT_PARTITION_OFFSET_nor-nand-4-256_bootfs = "0x00000000"
+FLASHLAYOUT_PARTITION_OFFSET_nor-nand-4-256_rootfs = "0x01400000"
+FLASHLAYOUT_PARTITION_OFFSET_nor-nand-4-256_userfs = "0x19C00000"
+
+# NAND special settings
+FLASHLAYOUT_PARTITION_TYPE_nand-4-256_fsbl1 = "Binary(4)"
+FLASHLAYOUT_PARTITION_BIN2LOAD_nand-4-256_bootfs = "${IMAGE_LINK_NAME}_nand_4_256.ubi"
+FLASHLAYOUT_PARTITION_BIN2LOAD_nand-4-256_rootfs = "${IMAGE_LINK_NAME}_nand_4_256.ubi"
+FLASHLAYOUT_PARTITION_BIN2LOAD_nand-4-256_userfs = "${STM32MP_USERFS_IMAGE}-${DISTRO}-${MACHINE}_nand_4_256.ubi"
+
+
+# =========================================================================
+# Extlinux boot commands
 # =========================================================================
 # Define boot command lines
 #
@@ -79,9 +335,8 @@ IMAGE_SUMMARY_LIST = "#IMAGE#:${STM32MP_USERFS_IMAGE}"
 #
 
 # Add extlinux definintions for boards
-UBOOT_EXTLINUX_TIMEOUT = "-1"
-UBOOT_EXTLINUX_KERNEL_IMAGE = "/boot/${KERNEL_IMAGETYPE}"
-UBOOT_EXTLINUX_CONFIG_FLAGS = "sdcard nor-emmc nor-nand"
+UBOOT_EXTLINUX_TIMEOUT = "20"
+UBOOT_EXTLINUX_KERNEL_IMAGE = "/${KERNEL_IMAGETYPE}"
 
 
 # =========================================================================
@@ -90,19 +345,3 @@ UBOOT_EXTLINUX_CONFIG_FLAGS = "sdcard nor-emmc nor-nand"
 # OPTEE
 OPTEE_OS_WITH_PAGER = "n"
 
-
-# =========================================================================
-# Settings to forward to distro
-# =========================================================================
-# If swupdate layer is used we want to use libubootenv as provider. Else
-# we should use it from openembedded-core or poky. This isn't yet implemented
-# by this code. It should be integrated in the distro and activated e.g. by
-# swupdate DISTRO_FEATURE. This requires the layers to contain meta-swupdate
-# which isn't true for all supported platfoms currently.
-# The best would be to include PREFERRED_PROVIDER_u-boot-fw-utils ??= "libubootenv"
-# in the layer.conf file of meta-swupdate.
-#
-# So the workaround is to include it here
-PREFERRED_PROVIDER_u-boot-fw-utils = "libubootenv"
-
-
diff --git a/conf/machine/stm32mp-t1000-mini.conf b/conf/machine/stm32mp-t1000-mini.conf
new file mode 100644
index 0000000000000000000000000000000000000000..24c2db9aff7d45fd081c7af09fe600fd8d1d0c41
--- /dev/null
+++ b/conf/machine/stm32mp-t1000-mini.conf
@@ -0,0 +1,112 @@
+#@TYPE: Machine
+#@NAME: stm32mp-t1000-mini
+#@DESCRIPTION: Machine configuration for specific hardware
+#@NEEDED_BSPLAYERS: meta-st-stm32mp
+
+require conf/machine/include/stm32mp-t1000-common.inc
+
+# =========================================================================
+# Machine features
+# =========================================================================
+MACHINE_FEATURES += "wifi"
+
+
+# =========================================================================
+# tf-a, u-boot and kernel configuration
+# =========================================================================
+
+# Kernel device tree
+KERNEL_DEVICETREE = "stm32mp-t1000-mini.dtb"
+
+# U-boot and tf-a configuration
+UBOOT_CONFIG_pn-u-boot-trusted-stm32mp = "stm32mp-t1000-mini-trusted"
+UBOOT_CONFIG_pn-u-boot-basic-stm32mp = "stmxceet-mp157-som-basic"
+
+# OpenSTM configuration of u-boot with dts: <DEVICETREE>${UBOOT_CONFIG_FILEPATTERN}<DEFCONFIG>
+# With this it is possible to build multiple uboot configurations with different devicetree and
+# configuration. But be aware !FROM THE SAME SOURCE!
+# Configuration this way:
+UBOOT_CONFIG[stm32mp-t1000-mini-trusted] = "stm32mp-t1000-mini${UBOOT_CONFIG_FILEPATTERN}stmxceet-mp157-som_defconfig"
+UBOOT_CONFIG[stm32mp-t1000-mini-basic] = "stm32mp-t1000-mini${UBOOT_CONFIG_FILEPATTERN}stmxceet-mp157-som-basic_defconfig"
+
+
+# =========================================================================
+# Extlinux boot commands
+# =========================================================================
+
+require conf/machine/include/extlinux-t1000-mini.inc
+
+
+# =========================================================================
+# Machine specific software packages
+# =========================================================================
+CORE_IMAGE_EXTRA_INSTALL += "\
+	${@bb.utils.contains('MACHINE_FEATURES', 'wifi', 'linux-firmware-usb8801', '', d)} \
+    "
+
+
+# =========================================================================
+# Image
+# =========================================================================
+
+# currently don't build ubifs image
+IMAGE_FSTYPES = "tar.xz ext4"
+
+
+# =========================================================================
+# flashlayout files for STM32_Programmer (has to fit with image definitions!)
+# =========================================================================
+
+# restrict output to currently needed
+FLASHLAYOUT_CONFIG_LABELS = "sdcard"
+
+# -----------------------------------------------------------------------------
+# Define flash layouts
+# -----------------------------------------------------------------------------
+
+# sdcard flashlayout
+# -----------------------------------------------------------------------------
+# fsbl1  on SDMMC1 size 0x00040000 (256k)
+# fsbl2  on SDMMC1 size 0x00040000 (256k)
+# ssbl   on SDMMC1 size 0x00200000 (2M)
+# bootfs on SDMMC1 size 0x01400000 (20M)
+# rootfs on SDMMC1 size 0x20000000 (512M)
+# userfs on SDMMC1 size rest of device
+
+#FLASHLAYOUT_PARTITION_OFFSET_sdcard_bootfs = "0x00284400"
+#FLASHLAYOUT_PARTITION_OFFSET_sdcard_rootfs = "0x01684400"
+#FLASHLAYOUT_PARTITION_OFFSET_sdcard_userfs = "0x21684400"
+
+
+# nor-emmc flashlayout
+# -----------------------------------------------------------------------------
+# fsbl1  on SPI1   size 0x40000 (256k)
+# fsbl2  on SPI1   size 0x40000 (256k)
+# ssbl   on SPI1   size 0x200000 (2M)
+# empty  on SPI1   size rest of device
+# bootfs on SDMMC2 size 0x01400000 (20M)
+# rootfs on SDMMC2 size 0x20000000 (512M)
+# userfs on SDMMC2 size rest of device
+# 'empty' partition is a fake partition just to limit ssbl size to 2MBytes
+
+# Device SDMMC2
+#FLASHLAYOUT_PARTITION_OFFSET_nor-emmc_bootfs = "0x00004400"
+#FLASHLAYOUT_PARTITION_OFFSET_nor-emmc_rootfs = "0x01404400"
+#FLASHLAYOUT_PARTITION_OFFSET_nor-emmc_userfs = "0x21404400"
+
+
+# nor-nand-4-256 flashlayout
+# -----------------------------------------------------------------------------
+# fsbl1  on SPI1   size 0x40000 (256k)
+# fsbl2  on SPI1   size 0x40000 (256k)
+# ssbl   on SPI1   size 0x200000 (2M)
+# empty  on SPI1   size rest of device
+# bootfs on FMC    size 0x01400000 (20M)
+# rootfs on FMC    size 0x20000000 (392M)
+# userfs on FMC    size rest of device (100M)
+# 'empty' partition is a fake partition just to limit ssbl size to 2MBytes
+
+# Device FMC1
+#FLASHLAYOUT_PARTITION_OFFSET_nor-nand-4-256_bootfs = "0x00000000"
+#FLASHLAYOUT_PARTITION_OFFSET_nor-nand-4-256_rootfs = "0x01400000"
+#FLASHLAYOUT_PARTITION_OFFSET_nor-nand-4-256_userfs = "0x19C00000"
diff --git a/conf/machine/stm32mp-t1000-multi.conf b/conf/machine/stm32mp-t1000-multi.conf
index 1fa2c66e78842fed775010a7426cb80c006c0bf3..331fbad5cadab5d89c920ff72622b2418d46e271 100644
--- a/conf/machine/stm32mp-t1000-multi.conf
+++ b/conf/machine/stm32mp-t1000-multi.conf
@@ -1,6 +1,6 @@
-#@TYPE: Machine
-#@NAME: stm32mp-t1000-multi (t1000 boards with all other housings)
-#@DESCRIPTION: Machine configuration for specific hardware
+#@TYPE: Multi-Machine
+#@NAME: stm32mp-t1000-multi
+#@DESCRIPTION: Machine configuration for multiple hardware
 #@NEEDED_BSPLAYERS: meta-st-stm32mp
 
 require conf/machine/include/stm32mp-t1000-common.inc
@@ -8,152 +8,59 @@ require conf/machine/include/stm32mp-t1000-common.inc
 # =========================================================================
 # Machine features
 # =========================================================================
-MACHINE_FEATURES += "wifi-sd8977"
+MACHINE_FEATURES += "wifi"
 
 
 # =========================================================================
 # tf-a, u-boot and kernel configuration
 # =========================================================================
 
-# Device trees
-#STM32MP_DEVICETREE = "stm32mp-t1000-s"
-
-TF_A_DEVICETREE = "\
-    stm32mp-t1000 \
-    stm32mp-t1000-clkout32k \
-    "
-
-UBOOT_DEVICETREE = "\
-    stm32mp-t1000-s \
-    stm32mp-t1000-s-clkout32k \
-    stm32mp-t1000-k \
-    "
-
+# Kernel device tree
 KERNEL_DEVICETREE = "\
+    stmxceet-mp157-som.dtb \
+    stm32mp-t1000-mini.dtb \
     stm32mp-t1000-s.dtb \
     stm32mp-t1000-s-43.dtb \
     stm32mp-t1000-s-50.dtb \
-    stm32mp-t1000-s-24.dtb \
-    stm32mp-t1000-s-clkout32k.dtb \
-    stm32mp-t1000-k.dtb \
-    stm32mp-t1000-k-50.dtb \
-    stm32mp-t1000-k-70.dtb \
-    stm32mp-t1000-k-101.dtb \
-    stm32mp-t1004-k.dtb \
-    stm32mp-t1004-k-50.dtb \
-    stm32mp-t1005-k.dtb \
-    stm32mp-t1005-k-50.dtb \
     "
 
-UBOOT_CONFIG[trusted] = "stm32mp1-t1000-evk50_defconfig,,u-boot.stm32"
-UBOOT_CONFIG[sdcard] = "stm32mp1-t1000-evk50sdcard_defconfig,,u-boot.stm32"
+# U-boot and tf-a configuration
+UBOOT_CONFIG_pn-u-boot-trusted-stm32mp = "\
+    stmxceet-mp157-som-trusted \
+    stm32mp-t1000-default-trusted \
+    stm32mp-t1000-mini-trusted \
+    stm32mp-t1000-s-trusted \
+    "
+UBOOT_CONFIG_pn-u-boot-basic-stm32mp = "\
+    stmxceet-mp157-som-basic \
+    stm32mp-t1000-s-basic \
+    "
 
-UBOOT_CONFIG_append = " sdcard "
 
-# =========================================================================
-# boot scheme
-# =========================================================================
-BOOTSCHEME_LABELS += "basic"
-BOOTSCHEME_LABELS += "trusted"
-#BOOTSCHEME_LABELS += "optee"
+# OpenSTM configuration of u-boot with dts: <DEVICETREE>${UBOOT_CONFIG_FILEPATTERN}<DEFCONFIG>
+# With this it is possible to build multiple uboot configurations with different devicetree and
+# configuration. But be aware !FROM THE SAME SOURCE!
+# Configuration this way:
+UBOOT_CONFIG[stmxceet-mp157-som-trusted] = "stmxceet-mp157-som${UBOOT_CONFIG_FILEPATTERN}stmxceet-mp157-som_defconfig"
+UBOOT_CONFIG[stmxceet-mp157-som-basic] = "stmxceet-mp157-som${UBOOT_CONFIG_FILEPATTERN}stmxceet-mp157-som-basic_defconfig"
+UBOOT_CONFIG[stm32mp-t1000-default-trusted] = "stm32mp-t1000-default${UBOOT_CONFIG_FILEPATTERN}stmxceet-mp157-som_defconfig"
+UBOOT_CONFIG[stm32mp-t1000-default-basic] = "stm32mp-t1000-default${UBOOT_CONFIG_FILEPATTERN}stmxceet-mp157-som-basic_defconfig"
+UBOOT_CONFIG[stm32mp-t1000-mini-trusted] = "stm32mp-t1000-mini${UBOOT_CONFIG_FILEPATTERN}stmxceet-mp157-som_defconfig"
+UBOOT_CONFIG[stm32mp-t1000-mini-basic] = "stm32mp-t1000-mini${UBOOT_CONFIG_FILEPATTERN}stmxceet-mp157-som-basic_defconfig"
+UBOOT_CONFIG[stm32mp-t1000-s-trusted] = "stm32mp-t1000-s${UBOOT_CONFIG_FILEPATTERN}stmxceet-mp157-som_defconfig"
+UBOOT_CONFIG[stm32mp-t1000-s-basic] = "stm32mp-t1000-s${UBOOT_CONFIG_FILEPATTERN}stmxceet-mp157-som-basic_defconfig"
+
 
 # =========================================================================
 # Extlinux boot commands
 # =========================================================================
 
-UBOOT_EXTLINUX_TIMEOUT = "10"
-UBOOT_EXTLINUX_KERNEL_ARGS="rootwait ro earlyprintk"
-
-# == t1000-s configurations ==
+require conf/machine/include/extlinux-stmxceet-mp157-som.inc
+require conf/machine/include/extlinux-t1000-mini.inc
 require conf/machine/include/extlinux-t1000-s.inc
 require conf/machine/include/extlinux-t1000-s-43.inc
 require conf/machine/include/extlinux-t1000-s-50.inc
-require conf/machine/include/extlinux-t1000-s-24.inc
-require conf/machine/include/extlinux-t1000-s-clkout32k.inc
-
-# t1000-s is the multi configuration machine with extlinux
-UBOOT_EXTLINUX_TIMEOUT_stm32mp-t1000-s_sdcard = "0"
-UBOOT_EXTLINUX_TIMEOUT_stm32mp-t1000-s_nor-emmc = "0"
-UBOOT_EXTLINUX_TIMEOUT_stm32mp-t1000-s_nor-nand = "0"
-# label t1000-s-50 
-UBOOT_EXTLINUX_LABELS_stm32mp-t1000-s_sdcard_append   = " stm32mp-t1000-s-50-sdcard "
-UBOOT_EXTLINUX_LABELS_stm32mp-t1000-s_nor-emmc_append = " stm32mp-t1000-s-50-nor-emmc "
-UBOOT_EXTLINUX_LABELS_stm32mp-t1000-s_nor-nand_append = " stm32mp-t1000-s-50-nor-nand "
-# label t1000-s-43 
-UBOOT_EXTLINUX_LABELS_stm32mp-t1000-s_sdcard_append   = " stm32mp-t1000-s-43-sdcard "
-UBOOT_EXTLINUX_LABELS_stm32mp-t1000-s_nor-emmc_append = " stm32mp-t1000-s-43-nor-emmc "
-UBOOT_EXTLINUX_LABELS_stm32mp-t1000-s_nor-nand_append = " stm32mp-t1000-s-43-nor-nand "
-# label t1000-s-24 
-UBOOT_EXTLINUX_LABELS_stm32mp-t1000-s_sdcard_append   = " stm32mp-t1000-s-24-sdcard "
-UBOOT_EXTLINUX_LABELS_stm32mp-t1000-s_nor-emmc_append = " stm32mp-t1000-s-24-nor-emmc "
-UBOOT_EXTLINUX_LABELS_stm32mp-t1000-s_nor-nand_append = " stm32mp-t1000-s-24-nor-nand "
-# label t1000-s-clkout32k
-UBOOT_EXTLINUX_LABELS_stm32mp-t1000-s_sdcard_append   = " stm32mp-t1000-s-clkout32k-sdcard "
-UBOOT_EXTLINUX_LABELS_stm32mp-t1000-s_nor-emmc_append = " stm32mp-t1000-s-clkout32k-nor-emmc "
-UBOOT_EXTLINUX_LABELS_stm32mp-t1000-s_nor-nand_append = " stm32mp-t1000-s-clkout32k-nor-nand "
-
-# default label for t1000-s
-UBOOT_EXTLINUX_DEFAULT_LABEL_stm32mp-t1000-s_sdcard   = "stm32mp-t1000-s-50-sdcard"
-UBOOT_EXTLINUX_DEFAULT_LABEL_stm32mp-t1000-s_nor-emmc = "stm32mp-t1000-s-50-nor-emmc"
-UBOOT_EXTLINUX_DEFAULT_LABEL_stm32mp-t1000-s_nor-nand = "stm32mp-t1000-s-50-nor-nand"
-
-# == t1000-k configurations ==
-require conf/machine/include/extlinux-t1000-k.inc
-require conf/machine/include/extlinux-t1000-k-50.inc
-require conf/machine/include/extlinux-t1000-k-70.inc
-require conf/machine/include/extlinux-t1000-k-101.inc
-require conf/machine/include/extlinux-t1004-k.inc
-require conf/machine/include/extlinux-t1004-k-50.inc
-require conf/machine/include/extlinux-t1005-k.inc
-require conf/machine/include/extlinux-t1005-k-50.inc
-
-# t1000-k is the multi configuration machine with extlinux
-UBOOT_EXTLINUX_TIMEOUT_stm32mp-t1000-k_sdcard = "0"
-UBOOT_EXTLINUX_TIMEOUT_stm32mp-t1000-k_nor-emmc = "0"
-UBOOT_EXTLINUX_TIMEOUT_stm32mp-t1000-k_nor-nand = "0"
-
-# label t1000-k-50 
-UBOOT_EXTLINUX_LABELS_stm32mp-t1000-k_sdcard_append   = " stm32mp-t1000-k-50-sdcard "
-UBOOT_EXTLINUX_LABELS_stm32mp-t1000-k_nor-emmc_append = " stm32mp-t1000-k-50-nor-emmc "
-UBOOT_EXTLINUX_LABELS_stm32mp-t1000-k_nor-nand_append = " stm32mp-t1000-k-50-nor-nand "
-
-# label t1000-k-70 
-UBOOT_EXTLINUX_LABELS_stm32mp-t1000-k_sdcard_append   = " stm32mp-t1000-k-70-sdcard "
-UBOOT_EXTLINUX_LABELS_stm32mp-t1000-k_nor-emmc_append = " stm32mp-t1000-k-70-nor-emmc "
-UBOOT_EXTLINUX_LABELS_stm32mp-t1000-k_nor-nand_append = " stm32mp-t1000-k-70-nor-nand "
-
-# label t1000-k-101
-UBOOT_EXTLINUX_LABELS_stm32mp-t1000-k_sdcard_append   = " stm32mp-t1000-k-101-sdcard "
-UBOOT_EXTLINUX_LABELS_stm32mp-t1000-k_nor-emmc_append = " stm32mp-t1000-k-101-nor-emmc "
-UBOOT_EXTLINUX_LABELS_stm32mp-t1000-k_nor-nand_append = " stm32mp-t1000-k-101-nor-nand "
-
-# label t1004-k-50 
-UBOOT_EXTLINUX_LABELS_stm32mp-t1000-k_sdcard_append   = " stm32mp-t1004-k-50-sdcard "
-UBOOT_EXTLINUX_LABELS_stm32mp-t1000-k_nor-emmc_append = " stm32mp-t1004-k-50-nor-emmc "
-UBOOT_EXTLINUX_LABELS_stm32mp-t1000-k_nor-nand_append = " stm32mp-t1004-k-50-nor-nand "
-
-# label t1005-k-50 
-UBOOT_EXTLINUX_LABELS_stm32mp-t1000-k_sdcard_append   = " stm32mp-t1005-k-50-sdcard "
-UBOOT_EXTLINUX_LABELS_stm32mp-t1000-k_nor-emmc_append = " stm32mp-t1005-k-50-nor-emmc "
-UBOOT_EXTLINUX_LABELS_stm32mp-t1000-k_nor-nand_append = " stm32mp-t1005-k-50-nor-nand "
-
-# compatibility with t1000-s-50: label t1000-s-50 
-UBOOT_EXTLINUX_LABELS_stm32mp-t1000-k_sdcard_append   = " stm32mp-t1000-s-50-sdcard "
-UBOOT_EXTLINUX_LABELS_stm32mp-t1000-k_nor-emmc_append = " stm32mp-t1000-s-50-nor-emmc "
-UBOOT_EXTLINUX_LABELS_stm32mp-t1000-k_nor-nand_append = " stm32mp-t1000-s-50-nor-nand "
-# compatibility with t1000-s: label t1000-s-50 
-UBOOT_EXTLINUX_LABELS_stm32mp-t1000-k_sdcard_append   = " stm32mp-t1000-s-sdcard "
-UBOOT_EXTLINUX_LABELS_stm32mp-t1000-k_nor-emmc_append = " stm32mp-t1000-s-nor-emmc "
-UBOOT_EXTLINUX_LABELS_stm32mp-t1000-k_nor-nand_append = " stm32mp-t1000-s-nor-nand "
-# compatibility with t1000-s: label t1000-s-clkout32k
-UBOOT_EXTLINUX_LABELS_stm32mp-t1000-k_sdcard_append   = " stm32mp-t1000-s-clkout32k-sdcard "
-UBOOT_EXTLINUX_LABELS_stm32mp-t1000-k_nor-emmc_append = " stm32mp-t1000-s-clkout32k-nor-emmc "
-UBOOT_EXTLINUX_LABELS_stm32mp-t1000-k_nor-nand_append = " stm32mp-t1000-s-clkout32k-nor-nand "
-
-# default label for t1000-k
-UBOOT_EXTLINUX_DEFAULT_LABEL_stm32mp-t1000-k_sdcard   = "stm32mp-t1000-k-50-sdcard"
-UBOOT_EXTLINUX_DEFAULT_LABEL_stm32mp-t1000-k_nor-emmc = "stm32mp-t1000-k-50-nor-emmc"
-UBOOT_EXTLINUX_DEFAULT_LABEL_stm32mp-t1000-k_nor-nand = "stm32mp-t1000-k-50-nor-nand"
+
 
 # =========================================================================
 # Housing configuration
@@ -169,19 +76,75 @@ CORE_IMAGE_EXTRA_INSTALL += "\
 	${@bb.utils.contains('MACHINE_FEATURES', 'wifi', 'linux-firmware-usb8801', '', d)} \
     "
 # recommend machine-specific packages to install (Touchscreen drivers)
-MACHINE_ESSENTIAL_EXTRA_RRECOMMENDS += "\
-	kernel-module-goodix \
-	goodix-touchconfig \
-	"
+MACHINE_ESSENTIAL_EXTRA_RRECOMMENDS += "kernel-module-goodix"
 
 # autoload the modules
 KERNEL_MODULE_AUTOLOAD += "goodix"
 
+
 # =========================================================================
 # Image
 # =========================================================================
 
-# Only build tar.gz
-IMAGE_FSTYPES = "tar.gz"
+# currently don't build ubifs image
+IMAGE_FSTYPES = "tar.xz ext4"
+
 
+# =========================================================================
+# flashlayout files for STM32_Programmer (has to fit with image definitions!)
+# =========================================================================
 
+# restrict output to currently needed
+FLASHLAYOUT_CONFIG_LABELS = "sdcard nor-emmc"
+
+
+# -----------------------------------------------------------------------------
+# Define flash layouts
+# -----------------------------------------------------------------------------
+
+# sdcard flashlayout
+# -----------------------------------------------------------------------------
+# fsbl1  on SDMMC1 size 0x00040000 (256k)
+# fsbl2  on SDMMC1 size 0x00040000 (256k)
+# ssbl   on SDMMC1 size 0x00200000 (2M)
+# bootfs on SDMMC1 size 0x01400000 (20M)
+# rootfs on SDMMC1 size 0x20000000 (512M)
+# userfs on SDMMC1 size rest of device
+
+#FLASHLAYOUT_PARTITION_OFFSET_sdcard_bootfs = "0x00284400"
+#FLASHLAYOUT_PARTITION_OFFSET_sdcard_rootfs = "0x01684400"
+#FLASHLAYOUT_PARTITION_OFFSET_sdcard_userfs = "0x21684400"
+
+
+# nor-emmc flashlayout
+# -----------------------------------------------------------------------------
+# fsbl1  on SPI1   size 0x40000 (256k)
+# fsbl2  on SPI1   size 0x40000 (256k)
+# ssbl   on SPI1   size 0x200000 (2M)
+# empty  on SPI1   size rest of device
+# bootfs on SDMMC2 size 0x01400000 (20M)
+# rootfs on SDMMC2 size 0x20000000 (512M)
+# userfs on SDMMC2 size rest of device
+# 'empty' partition is a fake partition just to limit ssbl size to 2MBytes
+
+# Device SDMMC2
+#FLASHLAYOUT_PARTITION_OFFSET_nor-emmc_bootfs = "0x00004400"
+#FLASHLAYOUT_PARTITION_OFFSET_nor-emmc_rootfs = "0x01404400"
+#FLASHLAYOUT_PARTITION_OFFSET_nor-emmc_userfs = "0x21404400"
+
+
+# nor-nand-4-256 flashlayout
+# -----------------------------------------------------------------------------
+# fsbl1  on SPI1   size 0x40000 (256k)
+# fsbl2  on SPI1   size 0x40000 (256k)
+# ssbl   on SPI1   size 0x200000 (2M)
+# empty  on SPI1   size rest of device
+# bootfs on FMC    size 0x01400000 (20M)
+# rootfs on FMC    size 0x20000000 (392M)
+# userfs on FMC    size rest of device (100M)
+# 'empty' partition is a fake partition just to limit ssbl size to 2MBytes
+
+# Device FMC1
+#FLASHLAYOUT_PARTITION_OFFSET_nor-nand-4-256_bootfs = "0x00000000"
+#FLASHLAYOUT_PARTITION_OFFSET_nor-nand-4-256_rootfs = "0x01400000"
+#FLASHLAYOUT_PARTITION_OFFSET_nor-nand-4-256_userfs = "0x19C00000"
diff --git a/conf/machine/stm32mp-t1000-s-multi.conf b/conf/machine/stm32mp-t1000-s-multi.conf
index 05108ef343490c2ea58942d56de9d191cae10a79..4dcfddaddb4d7f70e8c465f1ab3b7848bea1e83f 100644
--- a/conf/machine/stm32mp-t1000-s-multi.conf
+++ b/conf/machine/stm32mp-t1000-s-multi.conf
@@ -8,52 +8,42 @@ require conf/machine/include/stm32mp-t1000-common.inc
 # =========================================================================
 # Machine features
 # =========================================================================
-MACHINE_FEATURES += "wifi-sd8977"
+#MACHINE_FEATURES += "wifi"
 
 
 # =========================================================================
 # tf-a, u-boot and kernel configuration
 # =========================================================================
 
-# Device trees
-#STM32MP_DEVICETREE = "stm32mp-t1000-s"
-
-TF_A_DEVICETREE = "\
-    stm32mp-t1000-s \
-    "
-
-UBOOT_DEVICETREE = "\
-    stm32mp-t1000-s \
-    "
-
+# Kernel device tree
 KERNEL_DEVICETREE = "\
-    stm32mp-t1000-s.dtb \
-    stm32mp-t1000-s-43.dtb \
-    stm32mp-t1000-s-50.dtb \
-    stm32mp-t1000-s-24.dtb \
-    "
+	stm32mp-t1000-s.dtb \
+	stm32mp-t1000-s-43.dtb \
+	stm32mp-t1000-s-50.dtb \
+	"
 
-UBOOT_CONFIG[trusted] = "stm32mp1-t1000-evk50_defconfig,,u-boot.stm32"
-UBOOT_CONFIG[sdcard] = "stm32mp1-t1000-evk50sdcard_defconfig,,u-boot.stm32"
+# U-boot and tf-a configuration
+UBOOT_CONFIG_pn-u-boot-trusted-stm32mp = "stm32mp-t1000-s-trusted"
+#UBOOT_CONFIG_pn-u-boot-basic-stm32mp = "stmxceet-mp157-som-basic"
+UBOOT_CONFIG_pn-u-boot-basic-stm32mp = "stm32mp-t1000-s-basic"
 
-UBOOT_CONFIG_append = " sdcard "
+# OpenSTM configuration of u-boot with dts: <DEVICETREE>${UBOOT_CONFIG_FILEPATTERN}<DEFCONFIG>
+# With this it is possible to build multiple uboot configurations with different devicetree and
+# configuration. But be aware !FROM THE SAME SOURCE!
+# Configuration this way:
+UBOOT_CONFIG[stm32mp-t1000-s-trusted] = "stm32mp-t1000-s${UBOOT_CONFIG_FILEPATTERN}stmxceet-mp157-som_defconfig"
+UBOOT_CONFIG[stm32mp-t1000-s-basic] = "stm32mp-t1000-s${UBOOT_CONFIG_FILEPATTERN}stmxceet-mp157-som-basic_defconfig"
 
-# =========================================================================
-# boot scheme
-# =========================================================================
-BOOTSCHEME_LABELS += "basic"
-BOOTSCHEME_LABELS += "trusted"
-#BOOTSCHEME_LABELS += "optee"
 
 # =========================================================================
 # Extlinux boot commands
 # =========================================================================
 
-UBOOT_EXTLINUX_KERNEL_ARGS="rootwait ro earlyprintk"
+UBOOT_EXTLINUX_KERNEL_ARGS="rootwait ro earlyprintk" 
 require conf/machine/include/extlinux-t1000-s.inc
 require conf/machine/include/extlinux-t1000-s-43.inc
 require conf/machine/include/extlinux-t1000-s-50.inc
-require conf/machine/include/extlinux-t1000-s-24.inc
+
 
 # =========================================================================
 # Housing configuration
@@ -69,19 +59,77 @@ CORE_IMAGE_EXTRA_INSTALL += "\
 	${@bb.utils.contains('MACHINE_FEATURES', 'wifi', 'linux-firmware-usb8801', '', d)} \
     "
 # recommend machine-specific packages to install (Touchscreen drivers)
-MACHINE_ESSENTIAL_EXTRA_RRECOMMENDS += "\
-	kernel-module-goodix \
-	goodix-touchconfig \
-	"
+MACHINE_ESSENTIAL_EXTRA_RRECOMMENDS += "kernel-module-goodix"
+
 
 # autoload the modules
 KERNEL_MODULE_AUTOLOAD += "goodix"
 
+
+
 # =========================================================================
 # Image
 # =========================================================================
 
-# Only build tar.gz
-IMAGE_FSTYPES = "tar.gz"
+# currently don't build ubifs image
+IMAGE_FSTYPES = "tar.xz ext4"
+
 
+# =========================================================================
+# flashlayout files for STM32_Programmer (has to fit with image definitions!)
+# =========================================================================
 
+# restrict output to currently needed
+#FLASHLAYOUT_CONFIG_LABELS = "sdcard nor-emmc nor-nand-4-256"
+FLASHLAYOUT_CONFIG_LABELS = "sdcard nor-emmc"
+
+# -----------------------------------------------------------------------------
+# Define flash layouts
+# -----------------------------------------------------------------------------
+
+# sdcard flashlayout
+# -----------------------------------------------------------------------------
+# fsbl1  on SDMMC1 size 0x00040000 (256k)
+# fsbl2  on SDMMC1 size 0x00040000 (256k)
+# ssbl   on SDMMC1 size 0x00200000 (2M)
+# bootfs on SDMMC1 size 0x01400000 (20M)
+# rootfs on SDMMC1 size 0x20000000 (512M)
+# userfs on SDMMC1 size rest of device
+
+#FLASHLAYOUT_PARTITION_OFFSET_sdcard_bootfs = "0x00284400"
+#FLASHLAYOUT_PARTITION_OFFSET_sdcard_rootfs = "0x01684400"
+#FLASHLAYOUT_PARTITION_OFFSET_sdcard_userfs = "0x21684400"
+
+
+# nor-emmc flashlayout
+# -----------------------------------------------------------------------------
+# fsbl1  on SPI1   size 0x40000 (256k)
+# fsbl2  on SPI1   size 0x40000 (256k)
+# ssbl   on SPI1   size 0x200000 (2M)
+# empty  on SPI1   size rest of device
+# bootfs on SDMMC2 size 0x01400000 (20M)
+# rootfs on SDMMC2 size 0x20000000 (512M)
+# userfs on SDMMC2 size rest of device
+# 'empty' partition is a fake partition just to limit ssbl size to 2MBytes
+
+# Device SDMMC2
+#FLASHLAYOUT_PARTITION_OFFSET_nor-emmc_bootfs = "0x00004400"
+#FLASHLAYOUT_PARTITION_OFFSET_nor-emmc_rootfs = "0x01404400"
+#FLASHLAYOUT_PARTITION_OFFSET_nor-emmc_userfs = "0x21404400"
+
+
+# nor-nand-4-256 flashlayout
+# -----------------------------------------------------------------------------
+# fsbl1  on SPI1   size 0x40000 (256k)
+# fsbl2  on SPI1   size 0x40000 (256k)
+# ssbl   on SPI1   size 0x200000 (2M)
+# empty  on SPI1   size rest of device
+# bootfs on FMC    size 0x01400000 (20M)
+# rootfs on FMC    size 0x20000000 (392M)
+# userfs on FMC    size rest of device (100M)
+# 'empty' partition is a fake partition just to limit ssbl size to 2MBytes
+
+# Device FMC1
+#FLASHLAYOUT_PARTITION_OFFSET_nor-nand-4-256_bootfs = "0x00000000"
+#FLASHLAYOUT_PARTITION_OFFSET_nor-nand-4-256_rootfs = "0x01400000"
+#FLASHLAYOUT_PARTITION_OFFSET_nor-nand-4-256_userfs = "0x19C00000"
diff --git a/conf/machine/stm32mp-t1000-testadapter.conf b/conf/machine/stm32mp-t1000-testadapter.conf
deleted file mode 100644
index ac7dccba00443f60e5c618c0031aea1b7494102f..0000000000000000000000000000000000000000
--- a/conf/machine/stm32mp-t1000-testadapter.conf
+++ /dev/null
@@ -1,67 +0,0 @@
-#@TYPE: Machine
-#@NAME: stm32mp-t1000-testadapter (testadapter board for production)
-#@DESCRIPTION: Machine configuration for specific hardware
-#@NEEDED_BSPLAYERS: meta-st-stm32mp
-
-require conf/machine/include/stm32mp-t1000-common.inc
-
-# Remove ST settings
-ENABLE_PARTITIONS_IMAGE = "0"
-# IMAGE_CLASSES = <DEFAULTVALUE> (license-image)
-IMAGE_CLASSES_remove = "image_types-stubi st-partitions-image"
-IMAGE_FSTYPES = "tar.gz"
-# MACHINE_FEATURES = "usbhost usbgadget ext2 rtc qemu-usermode"
-MACHINE_FEATURES_remove = "alsa tpm2 screen"
-# MACHINE_EXTRA_RRECOMMENDS = <DEFAULTVALUE>
-MACHINE_EXTRA_RRECOMMENDS_remove = "m4fwcoredump wifi-suspend"
-
-EXTRA_IMAGEDEPENDS = "\
-	tf-a-stm32mp \
-	u-boot-stm32mp \
-	"
-
-# =========================================================================
-# Machine features
-# =========================================================================
-#MACHINE_FEATURES += "wifi"
-
-
-# =========================================================================
-# tf-a, u-boot and kernel configuration
-# =========================================================================
-
-# Device trees
-TF_A_DEVICETREE = "\
-    stm32mp-t1000-s \
-    "
-
-UBOOT_DEVICETREE = "\
-    stm32mp-t1000-s \
-    stm32mp-t1000-testadapter \
-    "
-
-KERNEL_DEVICETREE = "\
-    stm32mp-t1000-s.dtb \
-    stm32mp-t1000-testadapter.dtb \
-    "
-
-# =========================================================================
-# boot scheme
-# =========================================================================
-BOOTSCHEME_LABELS += "trusted"
-BOOTSCHEME_LABELS += "production"
-UBOOT_CONFIG[trusted] = "stm32mp1-t1000_defconfig,,u-boot.stm32"
-UBOOT_CONFIG[production] = "stm32mp1-t1000-production_defconfig,,u-boot.stm32"
-
-# =========================================================================
-# Extlinux boot commands
-# =========================================================================
-# No extlinux required for production boot
-
-# =========================================================================
-# Housing configuration
-# =========================================================================
-
-# =========================================================================
-# Machine specific software packages
-# =========================================================================
diff --git a/conf/machine/stm32mp-t1000.conf b/conf/machine/stm32mp-t1000.conf
deleted file mode 100644
index 996296f082907c93f6d5432df6c6b9b4dc8c386b..0000000000000000000000000000000000000000
--- a/conf/machine/stm32mp-t1000.conf
+++ /dev/null
@@ -1,73 +0,0 @@
-#@TYPE: Machine
-#@NAME: stm32mp-t1000
-#@DESCRIPTION: Machine configuration for t1000 SoM minimal configuration
-
-require conf/machine/include/stm32mp-t1000-common.inc
-
-# =========================================================================
-# Machine features
-# =========================================================================
-MACHINE_FEATURES += ""
-
-
-# =========================================================================
-# tf-a, u-boot and kernel configuration
-# =========================================================================
-
-# Device trees
-TF_A_DEVICETREE = "\
-    stm32mp-t1000 \
-    "
-
-UBOOT_DEVICETREE = "\
-    stm32mp-t1000 \
-    "
-
-KERNEL_DEVICETREE = "\
-    stm32mp-t1000.dtb \
-    "
-
-UBOOT_CONFIG[trusted] = "stm32mp1-t1000_defconfig,,u-boot.stm32"
-UBOOT_CONFIG[sdcard] = "stm32mp1-t1000-sdcard_defconfig,,u-boot.stm32"
-
-UBOOT_CONFIG = " trusted sdcard "
-
-# =========================================================================
-# boot scheme
-# =========================================================================
-#BOOTSCHEME_LABELS += "basic"
-BOOTSCHEME_LABELS += "trusted"
-#BOOTSCHEME_LABELS += "optee"
-
-# =========================================================================
-# Extlinux boot commands
-# =========================================================================
-
-UBOOT_EXTLINUX_CONFIG_FLAGS="sdcard nor-nand"
-UBOOT_EXTLINUX_KERNEL_ARGS="rootwait ro earlyprintk"
-require conf/machine/include/extlinux-t1000.inc
-
-# =========================================================================
-# Housing configuration
-# =========================================================================
-
-# =========================================================================
-# Machine specific software packages
-# =========================================================================
-CORE_IMAGE_EXTRA_INSTALL += "\
-    "
-# recommend machine-specific packages to install (Touchscreen drivers)
-MACHINE_ESSENTIAL_EXTRA_RRECOMMENDS += "\
-	"
-
-# autoload the modules
-KERNEL_MODULE_AUTOLOAD += ""
-
-# =========================================================================
-# Image
-# =========================================================================
-
-# Only build tar.gz
-IMAGE_FSTYPES = "tar.gz"
-
-
diff --git a/conf/machine/stm32mp-t1001.conf b/conf/machine/stm32mp-t1001.conf
deleted file mode 100644
index e6616bf66ceba405035d3f27480f12b472a3c7e1..0000000000000000000000000000000000000000
--- a/conf/machine/stm32mp-t1001.conf
+++ /dev/null
@@ -1,73 +0,0 @@
-#@TYPE: Machine
-#@NAME: stm32mp-t1001
-#@DESCRIPTION: Machine configuration for t1001 SoM minimal configuration
-
-require conf/machine/include/stm32mp-t1000-common.inc
-
-# =========================================================================
-# Machine features
-# =========================================================================
-MACHINE_FEATURES += ""
-
-
-# =========================================================================
-# tf-a, u-boot and kernel configuration
-# =========================================================================
-
-# Device trees
-TF_A_DEVICETREE = "\
-    stm32mp-t1001 \
-    "
-
-UBOOT_DEVICETREE = "\
-    stm32mp-t1001 \
-    "
-
-KERNEL_DEVICETREE = "\
-    stm32mp-t1001.dtb \
-    "
-
-UBOOT_CONFIG[trusted] = "stm32mp1-t1000_defconfig,,u-boot.stm32"
-UBOOT_CONFIG[sdcard] = "stm32mp1-t1000-sdcard_defconfig,,u-boot.stm32"
-
-UBOOT_CONFIG = " trusted sdcard "
-
-# =========================================================================
-# boot scheme
-# =========================================================================
-#BOOTSCHEME_LABELS += "basic"
-BOOTSCHEME_LABELS += "trusted"
-#BOOTSCHEME_LABELS += "optee"
-
-# =========================================================================
-# Extlinux boot commands
-# =========================================================================
-
-UBOOT_EXTLINUX_CONFIG_FLAGS="sdcard"
-UBOOT_EXTLINUX_KERNEL_ARGS="rootwait ro earlyprintk"
-require conf/machine/include/extlinux-t1001.inc
-
-# =========================================================================
-# Housing configuration
-# =========================================================================
-
-# =========================================================================
-# Machine specific software packages
-# =========================================================================
-CORE_IMAGE_EXTRA_INSTALL += "\
-    "
-# recommend machine-specific packages to install (Touchscreen drivers)
-MACHINE_ESSENTIAL_EXTRA_RRECOMMENDS += "\
-	"
-
-# autoload the modules
-KERNEL_MODULE_AUTOLOAD += ""
-
-# =========================================================================
-# Image
-# =========================================================================
-
-# Only build tar.gz
-IMAGE_FSTYPES = "tar.gz"
-
-
diff --git a/conf/machine/stm32mp-t1004.conf b/conf/machine/stm32mp-t1004.conf
deleted file mode 100644
index 048d76e307acda1a3b739a528666fd02447425b3..0000000000000000000000000000000000000000
--- a/conf/machine/stm32mp-t1004.conf
+++ /dev/null
@@ -1,74 +0,0 @@
-#@TYPE: Machine
-#@NAME: stm32mp-t1004
-#@DESCRIPTION: Machine configuration for t1000 SoM minimal configuration
-
-require conf/machine/include/stm32mp-t1000-common.inc
-
-# =========================================================================
-# Machine features
-# =========================================================================
-MACHINE_FEATURES_remove = "gpu"
-MACHINE_FEATURES += ""
-
-
-# =========================================================================
-# tf-a, u-boot and kernel configuration
-# =========================================================================
-
-# Device trees
-TF_A_DEVICETREE = "\
-    stm32mp-t1000 \
-    "
-
-UBOOT_DEVICETREE = "\
-    stm32mp-t1004 \
-    "
-
-KERNEL_DEVICETREE = "\
-    stm32mp-t1004.dtb \
-    "
-
-UBOOT_CONFIG[trusted] = "stm32mp1-t1000_defconfig,,u-boot.stm32"
-UBOOT_CONFIG[sdcard] = "stm32mp1-t1000-sdcard_defconfig,,u-boot.stm32"
-
-UBOOT_CONFIG = " trusted sdcard "
-
-# =========================================================================
-# boot scheme
-# =========================================================================
-#BOOTSCHEME_LABELS += "basic"
-BOOTSCHEME_LABELS += "trusted"
-#BOOTSCHEME_LABELS += "optee"
-
-# =========================================================================
-# Extlinux boot commands
-# =========================================================================
-
-UBOOT_EXTLINUX_CONFIG_FLAGS="sdcard nor-nand"
-UBOOT_EXTLINUX_KERNEL_ARGS="rootwait ro earlyprintk"
-require conf/machine/include/extlinux-t1004.inc
-
-# =========================================================================
-# Housing configuration
-# =========================================================================
-
-# =========================================================================
-# Machine specific software packages
-# =========================================================================
-CORE_IMAGE_EXTRA_INSTALL += "\
-    "
-# recommend machine-specific packages to install (Touchscreen drivers)
-MACHINE_ESSENTIAL_EXTRA_RRECOMMENDS += "\
-	"
-
-# autoload the modules
-KERNEL_MODULE_AUTOLOAD += ""
-
-# =========================================================================
-# Image
-# =========================================================================
-
-# Only build tar.gz
-IMAGE_FSTYPES = "tar.gz"
-
-
diff --git a/conf/machine/stm32mp-t1005.conf b/conf/machine/stm32mp-t1005.conf
deleted file mode 100644
index fd18f750b91a2f65bd235829e0ceef0c21e33ede..0000000000000000000000000000000000000000
--- a/conf/machine/stm32mp-t1005.conf
+++ /dev/null
@@ -1,74 +0,0 @@
-#@TYPE: Machine
-#@NAME: stm32mp-t1005
-#@DESCRIPTION: Machine configuration for t1000 SoM minimal configuration
-
-require conf/machine/include/stm32mp-t1000-common.inc
-
-# =========================================================================
-# Machine features
-# =========================================================================
-MACHINE_FEATURES_remove = "gpu"
-MACHINE_FEATURES += ""
-
-
-# =========================================================================
-# tf-a, u-boot and kernel configuration
-# =========================================================================
-
-# Device trees
-TF_A_DEVICETREE = "\
-    stm32mp-t1000 \
-    "
-
-UBOOT_DEVICETREE = "\
-    stm32mp-t1005 \
-    "
-
-KERNEL_DEVICETREE = "\
-    stm32mp-t1005.dtb \
-    "
-
-UBOOT_CONFIG[trusted] = "stm32mp1-t1000_defconfig,,u-boot.stm32"
-UBOOT_CONFIG[sdcard] = "stm32mp1-t1000-sdcard_defconfig,,u-boot.stm32"
-
-UBOOT_CONFIG = " trusted sdcard "
-
-# =========================================================================
-# boot scheme
-# =========================================================================
-#BOOTSCHEME_LABELS += "basic"
-BOOTSCHEME_LABELS += "trusted"
-#BOOTSCHEME_LABELS += "optee"
-
-# =========================================================================
-# Extlinux boot commands
-# =========================================================================
-
-UBOOT_EXTLINUX_CONFIG_FLAGS="sdcard nor-nand"
-UBOOT_EXTLINUX_KERNEL_ARGS="rootwait ro earlyprintk"
-require conf/machine/include/extlinux-t1005.inc
-
-# =========================================================================
-# Housing configuration
-# =========================================================================
-
-# =========================================================================
-# Machine specific software packages
-# =========================================================================
-CORE_IMAGE_EXTRA_INSTALL += "\
-    "
-# recommend machine-specific packages to install (Touchscreen drivers)
-MACHINE_ESSENTIAL_EXTRA_RRECOMMENDS += "\
-	"
-
-# autoload the modules
-KERNEL_MODULE_AUTOLOAD += ""
-
-# =========================================================================
-# Image
-# =========================================================================
-
-# Only build tar.gz
-IMAGE_FSTYPES = "tar.gz"
-
-
diff --git a/conf/machine/stmxceet.conf b/conf/machine/stmxceet.conf
new file mode 100644
index 0000000000000000000000000000000000000000..174511ccba0f8e27015d0f03e5cc85da5571a63d
--- /dev/null
+++ b/conf/machine/stmxceet.conf
@@ -0,0 +1,377 @@
+#@TYPE: Machine
+#@NAME: stmxceet
+#@DESCRIPTION: Machine configuration for all stmxceet hw configurations
+#@NEEDED_BSPLAYERS: meta-st-stm32mp
+
+PREFERRED_PROVIDER_virtual/kernel = "linux-stm32mp"
+PREFERRED_VERSION_linux-stm32mp ?= "4.14"
+# PREFERRED_PROVIDER_virtual/bootloader doesn't exist because multiple
+# u-boot loaders can be built (see meta-st-stm32mp/recipes-bsp/u-boot/u-boot-stm32mp.inc
+
+include conf/machine/include/st-machine-common-stm32mp.inc
+
+# Define specific common layer name
+MACHINEOVERRIDES =. "lxctrl:"
+
+
+# =========================================================================
+# Machine settings
+# =========================================================================
+# Default machine feature
+# See ST definition
+#MACHINE_FEATURES = "usbhost usbgadget alsa screen ext2"
+
+# Default serial consoles (TTYs) to enable using getty
+SERIAL_CONSOLES = "115200;ttyS3"
+SERIAL_CONSOLE = "115200 ttyS3"
+
+# We have no soundcard (yet). So remove configuration and current settings file
+# from OpenST for alsa
+MACHINE_EXTRA_RRECOMMENDS_remove = "alsa-state-stm32mp1"
+
+# What should be built alongside this image
+EXTRA_IMAGEDEPENDS += "tf-a-stm32mp"
+EXTRA_IMAGEDEPENDS += "u-boot-basic-stm32mp"
+EXTRA_IMAGEDEPENDS += "u-boot-trusted-stm32mp"
+
+# =========================================================================
+# Chip architecture
+# =========================================================================
+DEFAULTTUNE = "cortexa7thf-neon-vfpv4"
+include conf/machine/include/tune-cortexa7.inc
+
+
+# =========================================================================
+# Kernel
+# =========================================================================
+# Kernel config
+ST_KERNEL_ENTRYPOINT = "0xC0008000"
+ST_KERNEL_LOADADDR   = "0xC0008000"
+
+# Kernel device tree
+KERNEL_DEVICETREE += "stmxceet-mp157-som.dtb"
+KERNEL_DEVICETREE += "stm32mp-t1000-mini.dtb"
+#KERNEL_DEVICETREE += "stm32mp157c-ev1.dtb"
+
+
+# =========================================================================
+# U-Boot
+# =========================================================================
+
+UBOOT_CONFIG_FILEPATTERN = "_devicetree_"
+
+# Set u-boot configuration (combination of devicetree and defconfig)
+UBOOT_DEVICETREE = ""
+UBOOT_CONFIG_pn-u-boot-trusted-stm32mp += "stmxceet-mp157-som-trusted"
+UBOOT_CONFIG_pn-u-boot-trusted-stm32mp += "stm32mp-t1000-mini-trusted"
+#UBOOT_CONFIG_pn-u-boot-trusted-stm32mp += "stm32mp157c-ev1-trusted"
+#UBOOT_CONFIG_pn-u-boot-trusted-stm32mp += "stm32mp157c-ev2-trusted"
+
+UBOOT_CONFIG_pn-u-boot-basic-stm32mp = "stmxceet-mp157-som-basic"
+
+# OpenSTM configuration of u-boot with dts: <DEVICETREE>${UBOOT_CONFIG_FILEPATTERN}<DEFCONFIG>
+# With this it is possible to build multiple uboot configurations with different devicetree and
+# configuration. But be aware !FROM THE SAME SOURCE!
+# Configuration this way:
+UBOOT_CONFIG[stmxceet-mp157-som-trusted] = "stmxceet-mp157-som${UBOOT_CONFIG_FILEPATTERN}stmxceet-mp157-som_defconfig"
+UBOOT_CONFIG[stmxceet-mp157-som-basic] = "stmxceet-mp157-som${UBOOT_CONFIG_FILEPATTERN}stmxceet-mp157-som-basic_defconfig"
+UBOOT_CONFIG[stm32mp-t1000-mini-trusted] = "stm32mp-t1000-mini${UBOOT_CONFIG_FILEPATTERN}stmxceet-mp157-som_defconfig"
+UBOOT_CONFIG[stm32mp-t1000-mini-basic] = "stm32mp-t1000-mini${UBOOT_CONFIG_FILEPATTERN}stmxceet-mp157-som-basic_defconfig"
+
+# =========================================================================
+# Machine features
+# =========================================================================
+#MACHINE_FEATURES += "bluetooth"
+MACHINE_FEATURES += "wifi"
+
+MACHINE_FEATURES += "${@'gpu' if d.getVar('ACCEPT_EULA_'+d.getVar('MACHINE', True), True) == '1' else ''}"
+#MACHINE_FEATURES += "optee"
+
+
+# =========================================================================
+# Image
+# =========================================================================
+# Append ubi FSTYPES to default ones
+IMAGE_FSTYPES = "tar.xz ext4 stmultiubi"
+
+# Define image to use for extra partitions
+STM32MP_BOOTFS_IMAGE = "st-image-bootfs"
+STM32MP_USERFS_IMAGE = "st-image-userfs"
+
+# Define extra partition to build
+PARTITIONS_IMAGE = "${STM32MP_BOOTFS_IMAGE} ${STM32MP_USERFS_IMAGE}"
+
+# Define image partition size (supposed to be set as max size in image recipe)
+# Bootfs partition size 20MB (kernel ~7MB)
+BOOTFS_PARTITION_SIZE = "20480"
+# Rootfs partition size 512MB (without Qt)
+#ROOTFS_PARTITION_SIZE = "524288"
+# Rootfs partition size (with Qt)
+ROOTFS_PARTITION_SIZE = "786432"
+# Userfs partition size 128MB
+USERFS_PARTITION_SIZE = "131072"
+# Pay attention: QSPI NAND is 512MB on
+# Overall size: fsbl1+2 2x256k, ssbl 2M, bootfs 20M, rootfs 512M, userfs 128M
+
+# Define volume list for multivolume UBIFS
+STM32MP_UBI_VOLUME += "${STM32MP_BOOTFS_IMAGE}-${DISTRO}-${MACHINE}:${BOOTFS_PARTITION_SIZE}"
+STM32MP_UBI_VOLUME += "${IMAGE_LINK_NAME}:${ROOTFS_PARTITION_SIZE}"
+STM32MP_UBI_VOLUME += "${STM32MP_USERFS_IMAGE}-${DISTRO}-${MACHINE}:${USERFS_PARTITION_SIZE}"
+
+# Set on machine side the max size for ROOTFS image to apply for default rootfs being built
+# On other image partition such settings is directly done in image recipe
+IMAGE_ROOTFS_MAXSIZE ?= "${ROOTFS_PARTITION_SIZE}"
+
+# ST Naming rules partitions for UBI format are :
+#   nand_<PageSize>_<BlockSize>
+#   nor_<BlockSize>
+# Like that a same UBI partition can be used for severals NAND/NOR providers
+
+# UBI Args for NAND soldered by default on MB1262
+# Micron MT29F8G16ABACAH4
+# LEB = BLOCK_SIZE - (2 * page size): 256*1024 - (2*4096)
+MKUBIFS_ARGS_nand_4_256 = "--min-io-size 4096 --leb-size 253952 --max-leb-cnt 4096 --space-fixup"
+UBINIZE_ARGS_nand_4_256 = "--min-io-size 4096 --peb-size 256KiB"
+
+# Define UBI labels to build
+MULTIUBI_BUILD = " nand_4_256 "
+
+# TODO: set correct values for this flash type
+# currently mtdinfo reports some weird values (i/o size of 4069)
+#
+#   root@stmxceet:~# ubiformat /dev/mtd3
+#   ubiformat: error!: min. I/O size is 4069, but should be power of 2
+#
+# -> wait for new kernel
+#   root@stmxceet:~# mtdinfo -u /dev/mtd3
+#   mtd3
+#   Name:                           spi0.1
+#   Type:                           nand
+#   Eraseblock size:                260416 bytes, 254.3 KiB
+#    of eraseblocks:          2048 (533331968 bytes, 508.6 MiB)
+#   Minimum input/output unit size: 4069 bytes
+#   Sub-page size:                  4069 bytes
+#   OOB size:                       256 bytes
+#   Character device major/minor:   90:6
+#   Bad blocks are allowed:         true
+#   Device is writable:             true
+#   Default UBI VID header offset:  4069
+#   Default UBI data offset:        8138
+#   Default UBI LEB size:           252278 bytes, 246.4 KiB
+#   Maximum UBI volumes count:      128
+
+
+# =========================================================================
+# flashlayout
+# =========================================================================
+#
+# Generate flashlayout files
+FLASHLAYOUT_PARTITION_ENABLE = "1"
+
+# Define which flashlayout file should be generated
+# sdcard   - booting from sdcard
+# nor-emmc - bootloader (tf-a, u-boot) is in NOR flash, rootfs etc. is in eMMC
+# nor-nand - bootloader (tf-a, u-boot) is in NOR flash, rootfs etc. is in QSPI NAND
+FLASHLAYOUT_CONFIG_LABELS = "sdcard nor-emmc nor-nand-4-256"
+FLASHLAYOUT_RESTRICTION_TYPES_sdcard = ""
+FLASHLAYOUT_RESTRICTION_TYPES_nor-emmc = ""
+FLASHLAYOUT_RESTRICTION_TYPES_nor-nand-4-256 = ""
+
+# Define which bootschemes should be generated
+# basic   - only for board bringup (DDR calibration)
+# trusted - standard configuration
+FLASHLAYOUT_BOOTSCHEME_LABELS = "basic trusted"
+
+# -----------------------------------------------------------------------------
+# Partition configuration for each partition label
+# NOTE: each item can be defined with following priority assignment:
+#           1) item_<BOOTSCHEME>_<CONFIG>_<PARTITION>
+#           2) item_<BOOTSCHEME>_<CONFIG>
+#           3) item_<BOOTSCHEME>_<PARTITION>
+#           4) item_<BOOTSCHEME>
+#           5) item_<CONFIG>_<PARTITION>
+#           6) item_<CONFIG>
+#           7) item_<PARTITION>
+#           8) Default 'item' to 'none' when not defined
+# -----------------------------------------------------------------------------
+
+# -----------------------------------------------------------------------------
+# Define common partitions IDs
+# -----------------------------------------------------------------------------
+# common partition ids
+FLASHLAYOUT_PARTITION_ID_fsbl1  = "0x01"
+FLASHLAYOUT_PARTITION_ID_fsbl2  = "0x02"
+FLASHLAYOUT_PARTITION_ID_ssbl   = "0x03"
+FLASHLAYOUT_PARTITION_ID_empty  = "0x10"
+FLASHLAYOUT_PARTITION_ID_bootfs = "0x11"
+FLASHLAYOUT_PARTITION_ID_rootfs = "0x12"
+FLASHLAYOUT_PARTITION_ID_userfs = "0x13"
+
+
+# -----------------------------------------------------------------------------
+# Define common partitions types
+# -----------------------------------------------------------------------------
+# common partition types
+FLASHLAYOUT_PARTITION_TYPE                  = "Binary"
+FLASHLAYOUT_PARTITION_TYPE_empty            = "Empty"
+FLASHLAYOUT_PARTITION_TYPE_bootfs           = "System"
+FLASHLAYOUT_PARTITION_TYPE_rootfs           = "FileSystem"
+FLASHLAYOUT_PARTITION_TYPE_userfs           = "FileSystem"
+
+
+# -----------------------------------------------------------------------------
+# Define common partitions contents
+# -----------------------------------------------------------------------------
+# Set default binaries to flash for each partition
+
+# trusted configuration
+FLASHLAYOUT_PARTITION_BIN2LOAD_trusted_fsbl1   = "tf-a.stm32"
+FLASHLAYOUT_PARTITION_BIN2LOAD_trusted_fsbl2   = "tf-a.stm32"
+FLASHLAYOUT_PARTITION_BIN2LOAD_trusted_ssbl    = "u-boot.stm32"
+FLASHLAYOUT_PARTITION_BIN2LOAD_trusted_bootfs  = "${STM32MP_BOOTFS_IMAGE}-${DISTRO}-${MACHINE}.ext4"
+FLASHLAYOUT_PARTITION_BIN2LOAD_trusted_rootfs  = "${IMAGE_LINK_NAME}.ext4"
+FLASHLAYOUT_PARTITION_BIN2LOAD_trusted_userfs  = "${STM32MP_USERFS_IMAGE}-${DISTRO}-${MACHINE}.ext4"
+
+# basic configuration
+FLASHLAYOUT_PARTITION_BIN2LOAD_basic_fsbl1   = "u-boot-spl.stm32"
+FLASHLAYOUT_PARTITION_BIN2LOAD_basic_fsbl2   = "u-boot-spl.stm32"
+FLASHLAYOUT_PARTITION_BIN2LOAD_basic_ssbl    = "u-boot.img"
+FLASHLAYOUT_PARTITION_BIN2LOAD_basic_bootfs  = "none"
+FLASHLAYOUT_PARTITION_BIN2LOAD_basic_rootfs = "none"
+FLASHLAYOUT_PARTITION_BIN2LOAD_basic_userfs = "none"
+
+# Binaries to boot from RAM (only board bring up)
+FLASHLAYOUT_PARTITION_BIN2BOOT_fsbl1 = "tf-a.stm32"
+FLASHLAYOUT_PARTITION_BIN2BOOT_fsbl2 = "tf-a.stm32"
+FLASHLAYOUT_PARTITION_BIN2BOOT_ssbl = "u-boot.stm32"
+
+
+# -----------------------------------------------------------------------------
+# Define flash layouts
+# -----------------------------------------------------------------------------
+
+# sdcard flashlayout
+# -----------------------------------------------------------------------------
+# fsbl1  on SDMMC1 size 0x00040000 (256k)
+# fsbl2  on SDMMC1 size 0x00040000 (256k)
+# ssbl   on SDMMC1 size 0x00200000 (2M)
+# bootfs on SDMMC1 size 0x01400000 (20M)
+# rootfs on SDMMC1 size 0x20000000 (512M)
+# userfs on SDMMC1 size rest of device
+
+#FLASHLAYOUT_PARTITION_LABELS = "fsbl1 fsbl2 ssbl bootfs"
+FLASHLAYOUT_PARTITION_LABELS = "fsbl1 fsbl2 ssbl bootfs rootfs userfs"
+
+# Device SDMMC1
+# Fixed offsets in ROM code (cut1 version) for fsbl1 and fsbl2: 0x4400, 0x44400
+FLASHLAYOUT_PARTITION_DEVICE_sdcard = "SDMMC1"
+FLASHLAYOUT_PARTITION_OFFSET_sdcard_fsbl1  = "0x00004400"
+FLASHLAYOUT_PARTITION_OFFSET_sdcard_fsbl2  = "0x00044400"
+FLASHLAYOUT_PARTITION_OFFSET_sdcard_ssbl   = "0x00084400"
+FLASHLAYOUT_PARTITION_OFFSET_sdcard_bootfs = "0x00284400"
+FLASHLAYOUT_PARTITION_OFFSET_sdcard_rootfs = "0x01684400"
+FLASHLAYOUT_PARTITION_OFFSET_sdcard_userfs = "0x21684400"
+
+
+# nor-emmc flashlayout
+# -----------------------------------------------------------------------------
+# fsbl1  on SPI1   size 0x40000 (256k)
+# fsbl2  on SPI1   size 0x40000 (256k)
+# ssbl   on SPI1   size 0x200000 (2M)
+# empty  on SPI1   size rest of device
+# bootfs on SDMMC2 size rest of device
+# 'empty' partition is a fake partition just to limit ssbl size to 2MBytes
+
+
+FLASHLAYOUT_PARTITION_LABELS_nor-emmc = "fsbl1 fsbl2 ssbl empty bootfs"
+#FLASHLAYOUT_PARTITION_LABELS_nor-emmc = "fsbl1 fsbl2 ssbl empty bootfs rootfs userfs"
+
+# Device SPI1
+# Fixed offsets in ROM code for fsbl1 and fsbl2: 0x0, 0x40000
+FLASHLAYOUT_PARTITION_DEVICE_nor-emmc_fsbl1  = "SPI1"
+FLASHLAYOUT_PARTITION_DEVICE_nor-emmc_fsbl2  = "SPI1"
+FLASHLAYOUT_PARTITION_DEVICE_nor-emmc_ssbl   = "SPI1"
+FLASHLAYOUT_PARTITION_OFFSET_nor-emmc_fsbl1  = "0x00000000"
+FLASHLAYOUT_PARTITION_OFFSET_nor-emmc_fsbl2  = "0x00040000"
+FLASHLAYOUT_PARTITION_OFFSET_nor-emmc_ssbl   = "0x00080000"
+FLASHLAYOUT_PARTITION_OFFSET_nor-emmc_empty  = "0x00280000"
+
+# Device SDMMC2
+FLASHLAYOUT_PARTITION_DEVICE_nor-emmc_bootfs = "SDMMC2"
+FLASHLAYOUT_PARTITION_OFFSET_nor-emmc_bootfs = "0x00004400"
+FLASHLAYOUT_PARTITION_DEVICE_nor-emmc_rootfs = "SDMMC2"
+FLASHLAYOUT_PARTITION_DEVICE_nor-emmc_userfs = "SDMMC2"
+FLASHLAYOUT_PARTITION_OFFSET_nor-emmc_rootfs = "0x04204400"
+FLASHLAYOUT_PARTITION_OFFSET_nor-emmc_userfs = "0x24204400"
+
+
+# nor-nand-4-256 flashlayout
+# -----------------------------------------------------------------------------
+# fsbl1  on SPI1   size 0x40000 (256k)
+# fsbl2  on SPI1   size 0x40000 (256k)
+# ssbl   on SPI1   size 0x200000 (2M)
+# empty  on SPI1   size rest of device
+# bootfs on SDMMC2 size rest of device
+# 'empty' partition is a fake partition just to limit ssbl size to 2MBytes
+
+FLASHLAYOUT_PARTITION_LABELS_nor-nand-4-256 = "fsbl1 fsbl2 ssbl empty bootfs"
+#FLASHLAYOUT_PARTITION_LABELS_nor-nand-4-256 = "fsbl1 fsbl2 ssbl empty bootfs rootfs userfs"
+
+# Device SPI1
+# Fixed offsets in ROM code for fsbl1 and fsbl2: 0x0, 0x40000
+FLASHLAYOUT_PARTITION_DEVICE_nor-nand-4-256_fsbl1  = "SPI1"
+FLASHLAYOUT_PARTITION_DEVICE_nor-nand-4-256_fsbl2  = "SPI1"
+FLASHLAYOUT_PARTITION_DEVICE_nor-nand-4-256_ssbl   = "SPI1"
+FLASHLAYOUT_PARTITION_OFFSET_nor-nand-4-256_fsbl1  = "0x00000000"
+FLASHLAYOUT_PARTITION_OFFSET_nor-nand-4-256_fsbl2  = "0x00040000"
+FLASHLAYOUT_PARTITION_OFFSET_nor-nand-4-256_ssbl   = "0x00080000"
+FLASHLAYOUT_PARTITION_OFFSET_nor-nand-4-256_empty  = "0x00280000"
+
+# Device FMC1
+FLASHLAYOUT_PARTITION_DEVICE_nor-nand-4-256_bootfs = "FMC1"
+FLASHLAYOUT_PARTITION_OFFSET_nor-nand-4-256_bootfs = "0x00000000"
+FLASHLAYOUT_PARTITION_DEVICE_nor-nand-4-256_rootfs = "FMC1"
+FLASHLAYOUT_PARTITION_DEVICE_nor-nand-4-256_userfs = "FMC1"
+FLASHLAYOUT_PARTITION_OFFSET_nor-nand-4-256_rootfs = "0x04000000"
+FLASHLAYOUT_PARTITION_OFFSET_nor-nand-4-256_userfs = "0x24000000"
+
+# NAND special settings
+FLASHLAYOUT_PARTITION_TYPE_nand-4-256_fsbl1 = "Binary(4)"
+FLASHLAYOUT_PARTITION_BIN2LOAD_nand-4-256_bootfs = "${IMAGE_LINK_NAME}_nand_4_256.ubi"
+FLASHLAYOUT_PARTITION_BIN2LOAD_nand-4-256_rootfs = "${IMAGE_LINK_NAME}_nand_4_256.ubi"
+FLASHLAYOUT_PARTITION_BIN2LOAD_nand-4-256_userfs = "${STM32MP_USERFS_IMAGE}-${DISTRO}-${MACHINE}_nand_4_256.ubi"
+
+
+
+# =========================================================================
+# Extlinux boot commands
+# =========================================================================
+# Define boot command lines
+#
+# The following bootschemes are supported
+# - boot from sdcard (BOOTPIN_0,2=1, BOOTPIN_1=0)
+# - boot from nor (BOOTPIN_0=1, BOOTPIN_3,2=0)
+#   When booting from nor u-boot variable 'boot_targets' select where to find
+#   the bootfs with EXTLINUX configuration
+#
+
+# Add extlinux definintions for boards
+UBOOT_EXTLINUX_TIMEOUT = "20"
+UBOOT_EXTLINUX_KERNEL_IMAGE = "/${KERNEL_IMAGETYPE}"
+require conf/machine/include/extlinux-stmxceet-mp157-som.inc
+require conf/machine/include/extlinux-t1000-mini.inc
+
+
+# =========================================================================
+# Specific features settings
+# =========================================================================
+# OPTEE
+OPTEE_OS_WITH_PAGER = "n"
+
+
+# =========================================================================
+# Machine specific software packages
+# =========================================================================
+CORE_IMAGE_EXTRA_INSTALL += "\
+	${@bb.utils.contains('MACHINE_FEATURES', 'wifi', 'linux-firmware-usb8801', '', d)} \
+    "
diff --git a/recipes-bsp/trusted-firmware-a/fetch_files_workdir.sh b/recipes-bsp/trusted-firmware-a/fetch_files_workdir.sh
new file mode 100755
index 0000000000000000000000000000000000000000..92f654cb19ed42ea439797d5c1f76b947ecf6030
--- /dev/null
+++ b/recipes-bsp/trusted-firmware-a/fetch_files_workdir.sh
@@ -0,0 +1,95 @@
+#!/bin/bash
+
+# fetch_files_workdir <DEVTOOL_WORKDIR>
+
+FILELIST="\
+	fdts/stmxceet-mp157-som.dts \
+	fdts/stmxceet-mp157-som_atf.dts \
+	fdts/stmxceet-mp157-som_rcc.dtsi \
+	fdts/include/stmxceet-mp157-som_ddr.h \
+	"
+
+PATCHDIR="atf-stm32mp"
+
+red=`tput setaf 1`
+green=`tput setaf 2`
+yellow=`tput setaf 3`
+reset=`tput sgr0`
+
+DEVTOOL_WORKDIR=${1}
+COMMAND=${2}
+
+print_usage ()
+{
+	echo "fetch_files_workdir <DEVTOOL_WORKDIR> [diff]"
+}
+
+echo "$1"
+if test -z "${DEVTOOL_WORKDIR}"; then
+	print_usage
+	echo -n $red
+	echo "ERROR: No workdir on commandline"
+	echo -n $reset
+	exit 1
+fi
+if test ! -d "${DEVTOOL_WORKDIR}"; then
+	echo -n $red
+	echo "ERROR: Workdir <${DEVTOOL_WORKDIR}> doesn't exist"
+	echo -n $reset
+	exit 1
+fi
+
+# COMMAND configuration
+if test ! -z "${COMMAND}"; then
+	echo "Command: ${COMMAND}"
+fi
+do_onlydiff="no"
+if test "${COMMAND}" == "diff"; then
+	do_onlydiff="yes"
+fi
+
+for wdfile in ${FILELIST}; do
+	file_differ="no"
+	filename=$(basename $wdfile)
+	if test ! -e ${PATCHDIR}/${filename}; then
+		echo -n $yellow
+		echo "new      : $filename (${PATCHDIR}/${filename})"
+		echo -n $reset
+		file_differ="yes"
+	else
+		cmp -s ${DEVTOOL_WORKDIR}/${wdfile} ${PATCHDIR}/${filename}
+		if test $? != 0; then
+			echo -n $red
+			echo "differ   : $filename)"
+			echo -n $reset
+			file_differ="yes"
+		else
+			echo -n $green
+			echo "unchanged: $filename"
+			echo -n $reset
+		fi
+	fi
+	
+	if test ${file_differ} = "yes" -a ${do_onlydiff} != "yes" ; then
+	
+		echo "Show differences [Y/n]?"
+		read show_diff
+		if test -z "${show_diff}"; then
+			show_diff="Y"
+		fi
+		if test "${show_diff}" == "Y" -o ${show_diff} == "y"; then
+			meld ${DEVTOOL_WORKDIR}/${wdfile} ${PATCHDIR}/${filename}
+		fi
+				
+		echo "Copy files [y/N]?"
+		read copy_files
+		if test -z "${copy_files}"; then
+			copy_files="N"
+		fi
+		if test "${copy_files}" == "y" -o "${copy_files}" == "y"; then
+			cp ${DEVTOOL_WORKDIR}/${wdfile} ${PATCHDIR}/${filename}
+		fi
+	fi
+
+done
+
diff --git a/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/0001-bsec-added-write-lock-and-shadow-register-update-aft.patch b/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/0001-bsec-added-write-lock-and-shadow-register-update-aft.patch
deleted file mode 100644
index fdc79fc165efeed7505be2599338d5cda24b36e5..0000000000000000000000000000000000000000
--- a/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/0001-bsec-added-write-lock-and-shadow-register-update-aft.patch
+++ /dev/null
@@ -1,169 +0,0 @@
-From d46b0397a10a8de5d8b6a88aee77eb5dcd21f7db Mon Sep 17 00:00:00 2001
-From: Philipp Beck <Philipp.Beck@exceet.de>
-Date: Tue, 5 Nov 2019 10:45:26 +0100
-Subject: [PATCH] bsec: added write lock and shadow register update after
- program otp word larger than 56 Also add additional output which registers
- are permanent locked (on boot) or if a register read failed (disturbed or
- inconsistent). Adapted patch to fix some issues for permanent lock
-
----
- bl32/sp_min/sp_min_main.c              | 32 ++++++++++++++++++++++++++
- drivers/st/bsec/bsec.c                 |  3 +++
- plat/st/stm32mp1/services/bsec_svc.c   | 27 ++++++++++++++++++++++
- plat/st/stm32mp1/sp_min/sp_min_setup.c |  8 +++----
- 4 files changed, 66 insertions(+), 4 deletions(-)
-
-diff --git a/bl32/sp_min/sp_min_main.c b/bl32/sp_min/sp_min_main.c
-index 59e88eb9..fe098201 100644
---- a/bl32/sp_min/sp_min_main.c
-+++ b/bl32/sp_min/sp_min_main.c
-@@ -24,6 +24,7 @@
- #include <stdint.h>
- #include <string.h>
- #include <utils.h>
-+#include <stdio.h>
- #include "sp_min_private.h"
- 
- /* Pointers to per-core cpu contexts */
-@@ -173,6 +174,37 @@ void sp_min_main(void)
- 	INFO("SP_MIN: Initializing runtime services\n");
- 	runtime_svc_init();
- 
-+	{
-+#define OTP_LAST_REGISTER (95)
-+		uint32_t otp;
-+		bool value;
-+		uint32_t result;
-+		char msg[96*3];
-+
-+		/* Show permanent locked registers */
-+		msg[0] = '\0';
-+		for(otp = 0; otp <= OTP_LAST_REGISTER; otp++){
-+			/* Skip factory locked registers:
-+			 *  1
-+			 *  12 13 14 15 16 17
-+			 *  19 20 21 22 23
-+			 *  32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 */
-+			if ((1 == otp) |
-+				((otp >= 12) && (otp <= 17))|
-+				((otp >= 19) && (otp <= 23))|
-+				((otp >= 32) && (otp <= 55)))
-+				continue;
-+			result = bsec_read_permanent_lock(otp, &value);
-+			if (result != BSEC_OK) {
-+				ERROR("BSEC: %u permanent write lock bit read Error %i\n", otp, result);
-+				continue;
-+			}
-+			if (value)
-+				snprintf(msg, sizeof(msg), "%s %d", msg, otp);
-+		}
-+		INFO("BSEC permanent locked user registers:%s\n", msg);
-+	}
-+
- 	/*
- 	 * We are ready to enter the next EL. Prepare entry into the image
- 	 * corresponding to the desired security state after the next ERET.
-diff --git a/drivers/st/bsec/bsec.c b/drivers/st/bsec/bsec.c
-index 3dad2c26..3573ad6d 100644
---- a/drivers/st/bsec/bsec.c
-+++ b/drivers/st/bsec/bsec.c
-@@ -138,7 +138,9 @@ static uint32_t bsec_check_error(uint32_t otp, bool check_disturbed)
- 	uint32_t bank = otp_bank_offset(otp);
- 
- 	if ((mmio_read_32(bsec_base + BSEC_ERROR_OFF + bank) & bit) != 0U) {
-+		ERROR("BSEC_ERROR in register %d\n", otp);
- 		return BSEC_ERROR;
-+		//return BSEC_OK; /* for corrupted devices only */
- 	}
- 
- 	if (!check_disturbed) {
-@@ -146,6 +148,7 @@ static uint32_t bsec_check_error(uint32_t otp, bool check_disturbed)
- 	}
- 
- 	if ((mmio_read_32(bsec_base + BSEC_DISTURBED_OFF + bank) & bit) != 0U) {
-+		ERROR("BSEC_DISTURBED in register %d\n", otp);
- 		return BSEC_DISTURBED;
- 	}
- 
-diff --git a/plat/st/stm32mp1/services/bsec_svc.c b/plat/st/stm32mp1/services/bsec_svc.c
-index b13580d7..39a33924 100644
---- a/plat/st/stm32mp1/services/bsec_svc.c
-+++ b/plat/st/stm32mp1/services/bsec_svc.c
-@@ -24,6 +24,7 @@
- #define SSP_OTP_REQ		BIT(BOOT_API_OTP_SSP_REQ_BIT_POS)
- #define SSP_OTP_SUCCESS		BIT(BOOT_API_OTP_SSP_SUCCESS_BIT_POS)
- #define SSP_OTP_MASK		(SSP_OTP_REQ | SSP_OTP_SUCCESS)
-+#define OTP_USERSPACE_OFFSET 57
- 
- enum bsec_ssp_status {
- 	BSEC_NO_SSP = 0,
-@@ -388,6 +389,7 @@ uint32_t bsec_main(uint32_t x1, uint32_t x2, uint32_t x3,
- {
- 	uint32_t result;
- 	uint32_t tmp_data = 0U;
-+	bool value;
- 
- 	if ((x1 != STM32_SMC_READ_ALL) && (x1 != STM32_SMC_WRITE_ALL) &&
- 	    (bsec_check_nsec_access_rights(x2) != BSEC_OK)) {
-@@ -418,7 +420,32 @@ uint32_t bsec_main(uint32_t x1, uint32_t x2, uint32_t x3,
- 				break;
- 			}
- 		}
-+
-+		/* check if otp location is permanently locked and generate an error if so */
-+		result = bsec_read_permanent_lock(x2, &value);
-+		if (result != BSEC_OK){
-+			break;
-+		}
-+		if (value){
-+			WARN("BSEC: OTP %d is already permanent locked!\n", x2);
-+			result = BSEC_PROG_FAIL;
-+			break;
-+		}
-+
- 		result = bsec_program_otp(x3, x2);
-+		if (result != BSEC_OK) {
-+			break;
-+		}
-+
-+		result = bsec_shadow_register(x2);
-+		if (result != BSEC_OK) {
-+			break;
-+		}
-+
-+		if (x2 >= OTP_USERSPACE_OFFSET) {
-+			result = bsec_permanent_lock_otp(x2);
-+			bsec_set_sp_lock(x2);
-+		}
- 		break;
- 	case STM32_SMC_WRITE_SHADOW:
- 		*ret_otp_value = 0;
-diff --git a/plat/st/stm32mp1/sp_min/sp_min_setup.c b/plat/st/stm32mp1/sp_min/sp_min_setup.c
-index 8748b68f..817caae7 100644
---- a/plat/st/stm32mp1/sp_min/sp_min_setup.c
-+++ b/plat/st/stm32mp1/sp_min/sp_min_setup.c
-@@ -269,10 +269,6 @@ void sp_min_early_platform_setup2(u_register_t arg0, u_register_t arg1,
- 		panic();
- 	}
- 
--	if (bsec_probe() != 0) {
--		panic();
--	}
--
- 	if (stm32mp1_clk_probe() < 0) {
- 		panic();
- 	}
-@@ -295,6 +291,10 @@ void sp_min_early_platform_setup2(u_register_t arg0, u_register_t arg1,
- 		}
- 	}
- 
-+	if (bsec_probe() != 0) {
-+		panic();
-+	}
-+
- 	if (dt_pmic_status() > 0) {
- 		initialize_pmic();
- 	}
--- 
-2.17.1
-
diff --git a/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/0001-fix-add-missing-definition-for-stm32mp157cad-pinctrl.patch b/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/0001-fix-add-missing-definition-for-stm32mp157cad-pinctrl.patch
new file mode 100644
index 0000000000000000000000000000000000000000..9688427867307e7b50a9a30f477f2fcf0da2090e
--- /dev/null
+++ b/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/0001-fix-add-missing-definition-for-stm32mp157cad-pinctrl.patch
@@ -0,0 +1,20 @@
+From 2aa9f07eb95669cb731b31a46e6ad29c49255a8a Mon Sep 17 00:00:00 2001
+From: Eberhard Stoll <eberhard.stoll@exceet.de>
+Date: Thu, 19 Jul 2018 14:45:02 +0200
+Subject: [PATCH 1/4] fix: add missing definition for stm32mp157cad-pinctrl
+
+---
+ fdts/stm32mp157cad-pinctrl.dtsi | 1 +
+ 1 file changed, 1 insertion(+)
+ create mode 100644 fdts/stm32mp157cad-pinctrl.dtsi
+
+diff --git a/fdts/stm32mp157cad-pinctrl.dtsi b/fdts/stm32mp157cad-pinctrl.dtsi
+new file mode 100644
+index 0000000..6c98c38
+--- /dev/null
++++ b/fdts/stm32mp157cad-pinctrl.dtsi
+@@ -0,0 +1 @@
++#include "stm32mp157caa-pinctrl.dtsi"
+-- 
+2.7.4
+
diff --git a/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/0003-fix-add-missing-tag-usbotg_hs.patch b/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/0003-fix-add-missing-tag-usbotg_hs.patch
new file mode 100644
index 0000000000000000000000000000000000000000..ed690a4ce48a100358b7ea08e03701de333afa5d
--- /dev/null
+++ b/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/0003-fix-add-missing-tag-usbotg_hs.patch
@@ -0,0 +1,27 @@
+From eb66ddd0683270af446e0b377375e48a84f2a963 Mon Sep 17 00:00:00 2001
+From: Eberhard Stoll <eberhard.stoll@exceet.de>
+Date: Thu, 19 Jul 2018 14:49:14 +0200
+Subject: [PATCH 3/4] fix: add missing tag usbotg_hs
+
+---
+ fdts/stm32mp157c.dtsi | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/fdts/stm32mp157c.dtsi b/fdts/stm32mp157c.dtsi
+index 675b4a4..8d9bd27 100644
+--- a/fdts/stm32mp157c.dtsi
++++ b/fdts/stm32mp157c.dtsi
+@@ -140,6 +140,10 @@
+ 			status = "disabled";
+ 		};
+ 
++		usbotg_hs: usb-otg@49000000 {
++			/* dummy anchor for stm32mp157c-*-mx.dts file */
++		};
++
+ 		rcc: rcc@50000000 {
+ 			compatible = "syscon", "st,stm32mp1-rcc";
+ 			#clock-cells = <1>;
+-- 
+2.7.4
+
diff --git a/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/bleeding/stm32mp-som-t1000.dtsi b/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/bleeding/stm32mp-som-t1000.dtsi
deleted file mode 100644
index 6fe5361a90fd0ae6097de7fb737b3888c2e53541..0000000000000000000000000000000000000000
--- a/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/bleeding/stm32mp-som-t1000.dtsi
+++ /dev/null
@@ -1,358 +0,0 @@
-/* Devicetree file for fixed components for SOM t1000
- *
- * device    : stm32mp-som-t1000
- * board code: 40099 130
- * revision  : 03
- *
- * Defines fixed SOM components
- * - RAM configuration,
- * - Default clock configuration (rcc node)
- * - Default security configuration (etzpc node)
- * - Pin configurations for fixed SOM peripherals
- *
- * If rcc node or etzpc node shouldn't be include define this variables
- * to leave the configuration as is:
- * - RCC_FROM_MX
- * - ETZPC_FROM_MX
- *
- * Kontron Electronics GmbH
- * Copyright 2018 Kontron Electronics GmbH. All rights reserved.
- */
-
-
-#include <dt-bindings/power/stm32mp1-power.h>
-
-/* force DDR settings */
-#include "stm32mp157c-t1000-ddr-undef.h"
-#include "stm32mp157c-t1000-ddr3-1x4Gb-1066-binG.h"
-#include "stm32mp15-ddr.dtsi"
-
-/ {
-	aliases {
-		serial0 = &uart4;
-	};
-
-	chosen {
-		stdout-path = "serial0:115200n8";
-	};
-
-	aliases {
-		gpio0 = &gpioa;
-		gpio1 = &gpiob;
-		gpio2 = &gpioc;
-		gpio3 = &gpiod;
-		gpio4 = &gpioe;
-		gpio5 = &gpiof;
-		gpio6 = &gpiog;
-		gpio7 = &gpioh;
-		gpio8 = &gpioi;
-		gpio9 = &gpioj;
-		gpio10 = &gpiok;
-		gpio25 = &gpioz;
-	};
-
-	/* Regulators */
-	vdd: regulator-vdd {
-		compatible = "regulator-fixed";
-		regulator-name = "vdd";
-		regulator-min-microvolt = <3300000>;
-		regulator-max-microvolt = <3300000>;
-		regulator-always-on;
-	};
-
-    clocks {
-        clk_lse: clk-lse {
-            /*st,drive=<LSEDRV_MEDIUM_HIGH>;*/
-            st,drive=<LSEDRV_HIGHEST>;
-        };
-    };
-};
-
-#ifndef RCC_FROM_MX
-/* force clock settings */
-/* Set all clocks to sensible defaults
- * If you need special settings you have to define your own devicetree and tf-a
- * variant.
- */
-&rcc {
-    st,hsi-cal;
-    st,csi-cal;
-    st,cal-sec = <60>;
-    st,clksrc = <
-        CLK_MPU_PLL1P
-        CLK_AXI_PLL2P
-        CLK_MCU_PLL3P
-        CLK_PLL12_HSE
-        CLK_PLL3_HSE
-        CLK_PLL4_HSE
-        CLK_RTC_LSE
-        CLK_MCO1_DISABLED
-        CLK_MCO2_DISABLED
-    >;
-    st,clkdiv = <
-        1         /*MPU*/
-        0         /*AXI*/
-        0         /*MCU*/
-        1         /*APB1*/
-        1         /*APB2*/
-        1         /*APB3*/
-        1         /*APB4*/
-        2         /*APB5*/
-        0         /*RTC*/
-        0         /*MCO1*/
-        0         /*MCO2*/
-    >;
-    st,pkcs = <
-        CLK_CKPER_HSE
-        CLK_QSPI_ACLK
-        CLK_ETH_PLL4P
-        CLK_SDMMC12_PLL4P
-		CLK_DSI_DSIPLL /* s disabled */
-        CLK_STGEN_HSE
-        CLK_USBPHY_HSE
-        CLK_SPI2S1_PLL3Q /* s disabled */
-        CLK_SPI2S23_PLL4P
-        CLK_SPI45_HSI /* s disabled */
-        CLK_SPI6_HSI /* s disabled */
-        CLK_I2C46_HSI
-        CLK_SDMMC3_PLL3R  /* s disabled */
-        CLK_USBO_USBPHY
-        CLK_ADC_CKPER
-        CLK_CEC_LSE  /* s disabled */
-        CLK_I2C12_HSI
-        CLK_I2C35_HSI  /* s disabled */
-        CLK_UART1_HSI  /* s disabled */
-        CLK_UART24_PCLK1
-        CLK_UART35_HSI /* s disabled */
-        CLK_UART6_PCLK2
-        CLK_UART78_HSI /* s disabled */
-        CLK_SPDIF_PLL3Q /* s disabled */
-        CLK_FDCAN_HSE
-        CLK_SAI1_PLL3Q /* s disabled */
-        CLK_SAI2_PLL3Q /* s disabled */
-        CLK_SAI3_PLL3Q /* s disabled */
-        CLK_SAI4_PLL3Q /* s disabled */
-        CLK_RNG1_CSI
-        CLK_RNG2_CSI
-        CLK_LPTIM1_PCLK1 /* s disabled */
-        CLK_LPTIM23_PCLK3 /* s disabled */
-        CLK_LPTIM45_PCLK3 /* s disabled */
-    >;
-    pll1:st,pll@0 {
-        cfg = < 2 80 0 1 1 1>; /* P=648MHz, Q=324Hz, R=324MHz */
-        /* frac = < 0x800 >; */
-    };
-    pll2:st,pll@1 {
-        cfg = < 2 65 1 1 0 7>; /* P=264MHz, Q=264Hz, R=528MHz */
-        /* frac = < 0x1400 >; */
-    };
-    pll3:st,pll@2 {
-        cfg = < 1 49 2 2 1 3>; /* P=200MHz, Q=200MHz, R=300MHz */
-    };
-    pll4:st,pll@3 {
-        cfg = < 5 124 9 9 9 3>; /* P=50MHz, Q=50Hz, R=50MHz */
-    };
-};
-#endif /* RCC_FROM_MX */
-
-&pwr {
-	pwr-supply = <&vdd>;
-	system_suspend_supported_soc_modes = <
-		STM32_PM_CSLEEP_RUN
-		STM32_PM_CSTOP_ALLOW_LP_STOP
-		STM32_PM_CSTOP_ALLOW_STANDBY_DDR_SR
-	>;
-
-	system_off_soc_mode = <STM32_PM_CSTOP_ALLOW_STANDBY_DDR_OFF>;
-};
-
-#ifndef ETZPC_FROM_MX
-/* Security specific */
-/* Set all peripherals to sensible defaults (DECPROT_NS_RW)
- * If you need special settings you have to define your own devicetree and tf-a
- * variant
- */
-&etzpc{
-    st,decprot = <
-    /*"Cortex-A7 secure" context*/
-    /*"Cortex-A7 non secure" context*/
-    DECPROT(STM32MP1_ETZPC_ADC_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_OTG_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_CRYP1_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_HASH1_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_VREFBUF_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_ETH_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_TT_FDCAN_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_TIM4_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_TIM1_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_SPI1_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_UART4_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_QSPI_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    /*Restriction: STM32MP1_ETZPC_DLYBQ_ID is not managed - please to use User-Section if needed*/
-    DECPROT(STM32MP1_ETZPC_RNG1_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_USART2_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_I2C2_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_I2C4_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_SPI2_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_USART6_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-
-    /*Restriction: following IDs are not managed - please to use User-Section if needed:
-     STM32MP1_ETZPC_DMA1_ID, STM32MP1_ETZPC_DMA2_ID, STM32MP1_ETZPC_DMAMUX_ID,
-     STM32MP1_ETZPC_SRAMx_ID, STM32MP1_ETZPC_RETRAM_ID, STM32MP1_ETZPC_BKPSRAM_ID*/
-
-    /* USER CODE BEGIN etzpc_decprot */
-     /*STM32CubeMX generates a basic and standard configuration for ETZPC.
-     Additional device configurations can be added here if needed.
-     "etzpc" node could be also overloaded in "addons" User-Section.*/
-    /* USER CODE END etzpc_decprot */
-    >;
-    secure-status = "okay";
-
-    /* USER CODE BEGIN etzpc */
-    /* USER CODE END etzpc */
-};
-#endif /* ETZPC_FROM_MX */
-
-&pinctrl {
-	/* som pin mux */
-    quadspi_pins_som: quadspi_som@0 {
-        pins1 {
-            pinmux = <STM32_PINMUX('B', 6, AF10)>, /* QUADSPI_BK1_NCS */
-                     <STM32_PINMUX('C', 0, AF10)>; /* QUADSPI_BK2_NCS */
-            bias-pull-up;
-            drive-push-pull;
-            slew-rate = <3>;
-        };
-        pins2 {
-            pinmux = <STM32_PINMUX('E', 7, AF10)>, /* QUADSPI_BK2_IO0 */
-                     <STM32_PINMUX('E', 8, AF10)>, /* QUADSPI_BK2_IO1 */
-                     <STM32_PINMUX('E', 9, AF10)>, /* QUADSPI_BK2_IO2 */
-                     <STM32_PINMUX('E', 10, AF10)>, /* QUADSPI_BK2_IO3 */
-                     <STM32_PINMUX('F', 6, AF9)>, /* QUADSPI_BK1_IO3 */
-                     <STM32_PINMUX('F', 7, AF9)>, /* QUADSPI_BK1_IO2 */
-                     <STM32_PINMUX('F', 8, AF10)>, /* QUADSPI_BK1_IO0 */
-                     <STM32_PINMUX('F', 9, AF10)>, /* QUADSPI_BK1_IO1 */
-                     <STM32_PINMUX('F', 10, AF9)>; /* QUADSPI_CLK */
-            bias-disable;
-            drive-push-pull;
-            slew-rate = <3>;
-        };
-    };
-    uart4_pins_som: uart4_som@0 {
-        pins1 {
-            pinmux = <STM32_PINMUX('G', 11, AF6)>; /* UART4_TX */
-            bias-pull-up;
-            drive-push-pull;
-            slew-rate = <0>;
-        };
-        pins2 {
-            pinmux = <STM32_PINMUX('B', 2, AF8)>; /* UART4_RX */
-            bias-pull-up;
-        };
-    };
-    usb_otg_hs_pins_som: usb_otg_hs_som@0 {
-        pins {
-            pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
-        };
-    };
-
-    /* default pin mux */
-    sdmmc1_pins_default: sdmmc1_default@0 {
-        pins {
-            pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
-                     <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
-                     <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
-                     <STM32_PINMUX('C', 11, AF12)>, /* SDMMC1_D3 */
-                     <STM32_PINMUX('C', 12, AF12)>, /* SDMMC1_CK */
-                     <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
-            bias-pull-up;
-            drive-push-pull;
-            slew-rate = <3>;
-        };
-    };
-};
-
-&bsec{
-    status = "okay";
-    secure-status = "okay";
-    
-    /*opt word 59*/
-    som_id: som_id@ec{
-		reg=<0xec 0x4>;
-		status="okay";
-		secure-status="okay";			
-	};
-	
-	/*otp word 60*/
-	board_id: board_id@f0{
-		reg=<0xf0 0x4>;
-		status="okay";
-		secure-status="okay";			
-	};
-};
-
-/* Console */
-&uart4 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&uart4_pins_som>;
-	resets = <&rcc UART4_R>;
-	status = "okay";
-};
-
-/* qspi flash */
-&qspi {
-	#address-cells = <1>;
-	#size-cells = <0>;
-    pinctrl-names = "default";
-    pinctrl-0 = <&quadspi_pins_som>;
-    status = "okay";
-
-    flash0: mx25r1635f@0 {
-		u-boot,dm-pre-reloc;
-		compatible = "spi-flash", "jedec,spi-nor";
-		reg = <0>;
-		spi-rx-bus-width = <4>;
-		spi-tx-bus-width = <4>;
-		spi-max-frequency = <8000000>; /* MX25R1635F is slow */
-
-		/* required for partitions when mtdparts in u-boot are used */
-		#address-cells = <1>;
-		#size-cells = <1>;
-	};
-
-	flash1: spinand@1 {
-		u-boot,dm-pre-reloc;
-		compatible = "spi-nand";
-		reg = <1>;
-		spi-rx-bus-width = <4>;
-		spi-tx-bus-width = <4>;
-		spi-max-frequency = <104000000>;
-
-		/* required for partitions when mtdparts in u-boot are used */
-		#address-cells = <1>;
-		#size-cells = <1>;
-	};
-};
-
-&usbotg_hs {
-    pinctrl-names = "default";
-    pinctrl-0 = <&usb_otg_hs_pins_som>;
-    status = "okay";
-};
-
-&rng1 {
-	status = "okay";
-	secure-status = "okay";
-};
-
-&iwdg2 {
-	instance = <0x2>;
-	timeout-sec = <0x20>;
-	status = "okay";
-};
-
-&rcc {
-    status = "okay";
-    secure-status = "okay";
-};
-
diff --git a/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/bleeding/stm32mp-som-t1001.dtsi b/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/bleeding/stm32mp-som-t1001.dtsi
deleted file mode 100644
index 3bd26545e28220d93af73241c5310ed0f73c289a..0000000000000000000000000000000000000000
--- a/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/bleeding/stm32mp-som-t1001.dtsi
+++ /dev/null
@@ -1,347 +0,0 @@
-/* Devicetree file for fixed components for SOM t1001
- *
- * device    : stm32mp-som-t1001
- * board code: 40099 164
- * revision  : 00
- *
- * Defines fixed SOM components
- * - RAM configuration,
- * - Default clock configuration (rcc node)
- * - Default security configuration (etzpc node)
- * - Pin configurations for fixed SOM peripherals
- *
- * If rcc node or etzpc node shouldn't be include define this variables
- * to leave the configuration as is:
- * - RCC_FROM_MX
- * - ETZPC_FROM_MX
- *
- * Kontron Electronics GmbH
- * Copyright 2019 Kontron Electronics GmbH. All rights reserved.
- */
-
-
-#include <dt-bindings/power/stm32mp1-power.h>
-
-/* force DDR settings */
-#include "stm32mp157c-t1000-ddr-undef.h"
-#include "stm32mp157c-t1000-ddr3-1x4Gb-1066-binG.h"
-#include "stm32mp15-ddr.dtsi"
-
-/ {
-	aliases {
-		serial0 = &uart4;
-	};
-
-	chosen {
-		stdout-path = "serial0:115200n8";
-	};
-
-	aliases {
-		gpio0 = &gpioa;
-		gpio1 = &gpiob;
-		gpio2 = &gpioc;
-		gpio3 = &gpiod;
-		gpio4 = &gpioe;
-		gpio5 = &gpiof;
-		gpio6 = &gpiog;
-		gpio7 = &gpioh;
-		gpio8 = &gpioi;
-		gpio9 = &gpioj;
-		gpio10 = &gpiok;
-		gpio25 = &gpioz;
-	};
-
-	/* Regulators */
-	vdd: regulator-vdd {
-		compatible = "regulator-fixed";
-		regulator-name = "vdd";
-		regulator-min-microvolt = <3300000>;
-		regulator-max-microvolt = <3300000>;
-		regulator-always-on;
-	};
-
-    clocks {
-        clk_lse: clk-lse {
-            st,drive=<LSEDRV_MEDIUM_HIGH>;
-        };
-    };
-};
-
-#ifndef RCC_FROM_MX
-/* force clock settings */
-/* Set all clocks to sensible defaults
- * If you need special settings you have to define your own devicetree and tf-a
- * variant.
- */
-&rcc {
-    st,hsi-cal;
-    st,csi-cal;
-    st,cal-sec = <60>;
-    st,clksrc = <
-        CLK_MPU_PLL1P
-        CLK_AXI_PLL2P
-        CLK_MCU_PLL3P
-        CLK_PLL12_HSE
-        CLK_PLL3_HSE
-        CLK_PLL4_HSE
-        CLK_RTC_LSE
-        CLK_MCO1_DISABLED
-        CLK_MCO2_DISABLED
-    >;
-    st,clkdiv = <
-        1         /*MPU*/
-        0         /*AXI*/
-        0         /*MCU*/
-        1         /*APB1*/
-        1         /*APB2*/
-        1         /*APB3*/
-        1         /*APB4*/
-        2         /*APB5*/
-        0         /*RTC*/
-        0         /*MCO1*/
-        0         /*MCO2*/
-    >;
-    st,pkcs = <
-        CLK_CKPER_HSE
-        CLK_QSPI_ACLK
-        CLK_ETH_PLL4P
-        CLK_SDMMC12_PLL4P
-		CLK_DSI_DSIPLL
-        CLK_STGEN_HSE
-        CLK_USBPHY_HSE
-        CLK_SPI2S1_PLL3Q
-        CLK_SPI2S23_PLL4P
-        CLK_SPI45_HSI
-        CLK_SPI6_HSI
-        CLK_I2C46_HSI
-        CLK_SDMMC3_PLL3R
-        CLK_USBO_USBPHY
-        CLK_ADC_CKPER
-        CLK_CEC_LSE
-        CLK_I2C12_HSI
-        CLK_I2C35_HSI
-        CLK_UART1_HSI
-        CLK_UART24_PCLK1
-        CLK_UART35_HSI
-        CLK_UART6_PCLK2
-        CLK_UART78_HSI
-        CLK_SPDIF_PLL3Q
-        CLK_FDCAN_HSE
-        CLK_SAI1_PLL3Q
-        CLK_SAI2_PLL3Q
-        CLK_SAI3_PLL3Q
-        CLK_SAI4_PLL3Q
-        CLK_RNG1_CSI
-        CLK_RNG2_CSI
-        CLK_LPTIM1_PCLK1
-        CLK_LPTIM23_PCLK3
-        CLK_LPTIM45_PCLK3
-    >;
-    pll1:st,pll@0 {
-        cfg = < 2 80 0 1 1 1>; /* P=648MHz, Q=324Hz, R=324MHz */
-        /* frac = < 0x800 >; */
-    };
-    pll2:st,pll@1 {
-        cfg = < 2 65 1 1 0 7>; /* P=264MHz, Q=264Hz, R=528MHz */
-        /* frac = < 0x1400 >; */
-    };
-    pll3:st,pll@2 {
-        cfg = < 1 49 2 2 1 3>; /* P=200MHz, Q=200MHz, R=300MHz */
-    };
-    pll4:st,pll@3 {
-        cfg = < 5 124 9 9 9 3>; /* P=50MHz, Q=50Hz, R=50MHz */
-    };
-};
-#endif /* RCC_FROM_MX */
-
-&pwr {
-	pwr-supply = <&vdd>;
-	system_suspend_supported_soc_modes = <
-		STM32_PM_CSLEEP_RUN
-		STM32_PM_CSTOP_ALLOW_LP_STOP
-		STM32_PM_CSTOP_ALLOW_STANDBY_DDR_SR
-	>;
-
-	system_off_soc_mode = <STM32_PM_CSTOP_ALLOW_STANDBY_DDR_OFF>;
-};
-
-#ifndef ETZPC_FROM_MX
-/* Security specific */
-/* Set all peripherals to sensible defaults (DECPROT_NS_RW)
- * If you need special settings you have to define your own devicetree and tf-a
- * variant
- */
-&etzpc{
-    st,decprot = <
-    /*"Cortex-A7 secure" context*/
-    /*"Cortex-A7 non secure" context*/
-    DECPROT(STM32MP1_ETZPC_ADC_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_OTG_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_CRYP1_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_HASH1_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_VREFBUF_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_ETH_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_TT_FDCAN_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_TIM4_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_TIM1_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_SPI1_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_UART4_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_QSPI_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_DLYBQ_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_RNG1_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_USART2_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_I2C2_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_I2C4_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_SPI2_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_USART6_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-
-    /*Restriction: following IDs are not managed - please to use User-Section if needed:
-     STM32MP1_ETZPC_DMA1_ID, STM32MP1_ETZPC_DMA2_ID, STM32MP1_ETZPC_DMAMUX_ID,
-     STM32MP1_ETZPC_SRAMx_ID, STM32MP1_ETZPC_RETRAM_ID, STM32MP1_ETZPC_BKPSRAM_ID*/
-
-    /* USER CODE BEGIN etzpc_decprot */
-     /*STM32CubeMX generates a basic and standard configuration for ETZPC.
-     Additional device configurations can be added here if needed.
-     "etzpc" node could be also overloaded in "addons" User-Section.*/
-    /* USER CODE END etzpc_decprot */
-    >;
-    secure-status = "okay";
-
-    /* USER CODE BEGIN etzpc */
-    /* USER CODE END etzpc */
-};
-#endif /* ETZPC_FROM_MX */
-
-&pinctrl {
-	/* som pin mux */
-    quadspi_pins_som: quadspi_som@0 {
-        pins1 {
-            pinmux = <STM32_PINMUX('B', 6, AF10)>, /* QUADSPI_BK1_NCS */
-                     <STM32_PINMUX('C', 0, AF10)>; /* QUADSPI_BK2_NCS */
-            bias-pull-up;
-            drive-push-pull;
-            slew-rate = <3>;
-        };
-        pins2 {
-            pinmux = <STM32_PINMUX('E', 7, AF10)>, /* QUADSPI_BK2_IO0 */
-                     <STM32_PINMUX('E', 8, AF10)>, /* QUADSPI_BK2_IO1 */
-                     <STM32_PINMUX('E', 9, AF10)>, /* QUADSPI_BK2_IO2 */
-                     <STM32_PINMUX('E', 10, AF10)>, /* QUADSPI_BK2_IO3 */
-                     <STM32_PINMUX('F', 6, AF9)>, /* QUADSPI_BK1_IO3 */
-                     <STM32_PINMUX('F', 7, AF9)>, /* QUADSPI_BK1_IO2 */
-                     <STM32_PINMUX('F', 8, AF10)>, /* QUADSPI_BK1_IO0 */
-                     <STM32_PINMUX('F', 9, AF10)>, /* QUADSPI_BK1_IO1 */
-                     <STM32_PINMUX('F', 10, AF9)>; /* QUADSPI_CLK */
-            bias-disable;
-            drive-push-pull;
-            slew-rate = <3>;
-        };
-    };
-    uart4_pins_som: uart4_som@0 {
-        pins1 {
-            pinmux = <STM32_PINMUX('G', 11, AF6)>; /* UART4_TX */
-            bias-pull-up;
-            drive-push-pull;
-            slew-rate = <0>;
-        };
-        pins2 {
-            pinmux = <STM32_PINMUX('B', 2, AF8)>; /* UART4_RX */
-            bias-pull-up;
-        };
-    };
-    usb_otg_hs_pins_som: usb_otg_hs_som@0 {
-        pins {
-            pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
-        };
-    };
-};
-
-&bsec{
-    status = "okay";
-    secure-status = "okay";
-
-    /*opt word 59*/
-    som_id: som_id@ec{
-		reg=<0xec 0x4>;
-		status="okay";
-		secure-status="okay";			
-	};
-	
-	/*otp word 60*/
-	board_id: board_id@f0{
-		reg=<0xf0 0x4>;
-		status="okay";
-		secure-status="okay";			
-	};
-};
-
-/* Console */
-&uart4 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&uart4_pins_som>;
-	resets = <&rcc UART4_R>;
-	status = "okay";
-};
-
-/* qspi flash */
-&qspi {
-	#address-cells = <1>;
-	#size-cells = <0>;
-    pinctrl-names = "default";
-    pinctrl-0 = <&quadspi_pins_som>;
-    status = "okay";
-
-    flash0: mx25r1635f@0 {
-		u-boot,dm-pre-reloc;
-		compatible = "spi-flash", "jedec,spi-nor";
-		reg = <0>;
-		spi-rx-bus-width = <4>;
-		spi-tx-bus-width = <4>;
-		spi-max-frequency = <8000000>; /* MX25R1635F is slow */
-
-		/* required for partitions when mtdparts in u-boot are used */
-		#address-cells = <1>;
-		#size-cells = <1>;
-	};
-
-};
-
-&usbotg_hs {
-    pinctrl-names = "default";
-    pinctrl-0 = <&usb_otg_hs_pins_som>;
-    status = "okay";
-};
-
-&usbphyc{
-	status = "okay";
-};
-
-&usbphyc_port0{
-	status = "okay";
-};
-
-&usbphyc_port1{
-	status = "okay";
-};
-
-&rng1 {
-	status = "okay";
-	secure-status = "okay";
-};
-
-&iwdg2 {
-	instance = <0x2>;
-	timeout-sec = <0x20>;
-	status = "okay";
-};
-
-&rcc {
-    status = "okay";
-    secure-status = "okay";
-};
-
-&rtc{
-	status = "okay";
-	secure-status = "okay";
-};
-
diff --git a/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/fixes-for-B1/0001-stm32mp1-flush-data-cache-for-BL33.patch b/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/fixes-for-B1/0001-stm32mp1-flush-data-cache-for-BL33.patch
new file mode 100644
index 0000000000000000000000000000000000000000..921bcc88a60ef241ae9ea457bf692e27c98ba404
--- /dev/null
+++ b/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/fixes-for-B1/0001-stm32mp1-flush-data-cache-for-BL33.patch
@@ -0,0 +1,24 @@
+From 22b5237416bf6f19cf5a64f0b0633328514f4367 Mon Sep 17 00:00:00 2001
+From: bernard puel <bernard.puel@st.com>
+Date: Tue, 11 Sep 2018 10:46:22 +0200
+Subject: [PATCH] stm32mp1: flush data cache for BL33
+
+---
+ plat/st/stm32mp1/bl2_plat_setup.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/plat/st/stm32mp1/bl2_plat_setup.c b/plat/st/stm32mp1/bl2_plat_setup.c
+index a129a93..d890b96 100644
+--- a/plat/st/stm32mp1/bl2_plat_setup.c
++++ b/plat/st/stm32mp1/bl2_plat_setup.c
+@@ -405,6 +405,8 @@ int bl2_plat_handle_post_image_load(unsigned int image_id)
+ 			SPSR_MODE32(MODE32_svc, SPSR_T_ARM, SPSR_E_LITTLE,
+ 				    DISABLE_ALL_EXCEPTIONS);
+ #endif
++		flush_dcache_range(bl_mem_params->image_info.image_base,
++				   bl_mem_params->image_info.image_max_size);
+ 		break;
+
+ #ifdef AARCH32_SP_OPTEE
+--
+2.7.4
diff --git a/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/fixes-for-B1/0002-fix-definition-of-CLK_ADC_PLL4Q.patch b/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/fixes-for-B1/0002-fix-definition-of-CLK_ADC_PLL4Q.patch
new file mode 100644
index 0000000000000000000000000000000000000000..5a181daceaf51c813009b072361830c115bd502d
--- /dev/null
+++ b/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/fixes-for-B1/0002-fix-definition-of-CLK_ADC_PLL4Q.patch
@@ -0,0 +1,25 @@
+From 620a516821352a289d713a82b82f1c9801ff67b7 Mon Sep 17 00:00:00 2001
+From: Eberhard Stoll <eberhard.stoll@exceet.de>
+Date: Thu, 19 Jul 2018 14:47:21 +0200
+Subject: [PATCH 2/4] fix: definition of CLK_ADC_PLL4Q
+
+---
+ fdts/include/dt-bindings/clock/stm32mp1-clksrc.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/fdts/include/dt-bindings/clock/stm32mp1-clksrc.h b/fdts/include/dt-bindings/clock/stm32mp1-clksrc.h
+index de7d160..032a14b 100644
+--- a/fdts/include/dt-bindings/clock/stm32mp1-clksrc.h
++++ b/fdts/include/dt-bindings/clock/stm32mp1-clksrc.h
+@@ -243,7 +243,7 @@
+ #define CLK_DSI_DSIPLL		0x00009240
+ #define CLK_DSI_PLL4P		0x00009241
+ 
+-#define CLK_ADC_PLL4R		0x00009280
++#define CLK_ADC_PLL4Q		0x00009280
+ #define CLK_ADC_CKPER		0x00009281
+ #define CLK_ADC_PLL3Q		0x00009282
+ #define CLK_ADC_DISABLED	0x00009283
+-- 
+2.7.4
+
diff --git a/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/stm32mp-board-default.dtsi b/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/stm32mp-board-default.dtsi
new file mode 100644
index 0000000000000000000000000000000000000000..22f8ac0414fdb057fa7abc58b04a3abf535b2201
--- /dev/null
+++ b/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/stm32mp-board-default.dtsi
@@ -0,0 +1,19 @@
+/* Devicetree file for device
+ *
+ * device   : stm32mp-board-default
+ * revision : prototype
+ *
+ * Kontron Electronics GmbH
+ * Copyright 2018 Kontron Electronics GmbH. All rights reserved.
+ */
+
+/* sd/mmc interface */
+&sdmmc1 {
+	broken-cd;
+	//cd-gpios = <&gpioa 10 GPIO_ACTIVE_HIGH>;
+	st,dirpol;
+	st,negedge;
+	no-1-8-v;
+	bus-width = <4>;
+	status = "okay";
+};
diff --git a/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/stm32mp-board-mini.dtsi b/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/stm32mp-board-mini.dtsi
new file mode 100644
index 0000000000000000000000000000000000000000..a3b9d01ae5ea3927c1f837cc777e219124bd9481
--- /dev/null
+++ b/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/stm32mp-board-mini.dtsi
@@ -0,0 +1,19 @@
+/* Devicetree file for device
+ *
+ * device   : stm32mp-board-mini
+ * revision : prototype
+ *
+ * Kontron Electronics GmbH
+ * Copyright 2018 Kontron Electronics GmbH. All rights reserved.
+ */
+
+/* sd/mmc interface */
+&sdmmc1 {
+	broken-cd;
+	//cd-gpios = <&gpioa 10 GPIO_ACTIVE_HIGH>;
+	st,dirpol;
+	st,negedge;
+	no-1-8-v;
+	bus-width = <4>;
+	status = "okay";
+};
diff --git a/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/stm32mp-board-minimal.dtsi b/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/stm32mp-board-minimal.dtsi
deleted file mode 100644
index 05644207534b14b50bba1c2c7e00bb1575409735..0000000000000000000000000000000000000000
--- a/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/stm32mp-board-minimal.dtsi
+++ /dev/null
@@ -1,20 +0,0 @@
-/* Devicetree file for basic t1000 SOM module
- *
- * These settings should work with most baseboards
- *
- * device   : stm32mp-board-minimal
- * revision : -
- *
- * Kontron Electronics GmbH
- * Copyright 2019 Kontron Electronics GmbH. All rights reserved.
- */
-
-/* sd/mmc interface */
-&sdmmc1 {
-	broken-cd;
-	st,dirpol;
-	st,negedge;
-	no-1-8-v;
-	bus-width = <4>;
-	status = "okay";
-};
diff --git a/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/stm32mp-som-t1000.dtsi b/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/stm32mp-som-t1000.dtsi
index d2e6e7f8061c5b50bb044f8037a3b321ea55aad3..5bb682c6c07720658550fdab58f31729091e2d8f 100644
--- a/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/stm32mp-som-t1000.dtsi
+++ b/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/stm32mp-som-t1000.dtsi
@@ -1,39 +1,20 @@
-/* Devicetree file for fixed components for SOM t1000
+/* Devicetree file for device
  *
- * device    : stm32mp-som-t1000
- * board code: 40099 130
- * revision  : 03
- *
- * Defines fixed SOM components
- * - RAM configuration,
- * - Default clock configuration (rcc node)
- * - Default security configuration (etzpc node)
- * - Pin configurations for fixed SOM peripherals
- *
- * If rcc node or etzpc node shouldn't be include define this variables
- * to leave the configuration as is:
- * - RCC_FROM_MX
- * - ETZPC_FROM_MX
+ * device   : stm32mp-som-t1000
+ * revision : prototype
  *
  * Kontron Electronics GmbH
  * Copyright 2018 Kontron Electronics GmbH. All rights reserved.
  */
 
-
-#include <dt-bindings/power/stm32mp1-power.h>
-
 /* force DDR settings */
 #include "stm32mp157c-t1000-ddr-undef.h"
 #include "stm32mp157c-t1000-ddr3-1x4Gb-1066-binG.h"
 #include "stm32mp15-ddr.dtsi"
 
 / {
-	aliases {
-		serial0 = &uart4;
-	};
-
 	chosen {
-		stdout-path = "serial0:115200n8";
+		stdout-path = "serial3:115200n8";
 	};
 
 	aliases {
@@ -51,14 +32,6 @@
 		gpio25 = &gpioz;
 	};
 
-	/* Regulators */
-	vdd: regulator-vdd {
-		compatible = "regulator-fixed";
-		regulator-name = "vdd";
-		regulator-min-microvolt = <3300000>;
-		regulator-max-microvolt = <3300000>;
-		regulator-always-on;
-	};
 	soc {
 		stgen: stgen@5C008000 {
 			compatible = "st,stm32-stgen";
@@ -70,22 +43,14 @@
 
     clocks {
         clk_lse: clk-lse {
-            /*st,drive=<LSEDRV_MEDIUM_HIGH>;*/
-            st,drive=<LSEDRV_HIGHEST>;
+            st,drive=<LSEDRV_LOWEST>;
         };
     };
 };
 
-#ifndef RCC_FROM_MX
+
 /* force clock settings */
-/* Set all clocks to sensible defaults
- * If you need special settings you have to define your own devicetree and tf-a
- * variant.
- */
 &rcc {
-    st,hsi-cal;
-    st,csi-cal;
-    st,cal-sec = <60>;
     st,clksrc = <
         CLK_MPU_PLL1P
         CLK_AXI_PLL2P
@@ -106,133 +71,71 @@
         1         /*APB3*/
         1         /*APB4*/
         2         /*APB5*/
-        0         /*RTC*/
+        23         /*RTC*/
         0         /*MCO1*/
         0         /*MCO2*/
     >;
     st,pkcs = <
         CLK_CKPER_HSE
+		/*CLK_FMC_ACLK*/
         CLK_QSPI_ACLK
         CLK_ETH_PLL4P
-        CLK_SDMMC12_PLL4P
-		CLK_DSI_DSIPLL /* s disabled */
+        CLK_SDMMC12_PLL3R
+		CLK_DSI_DSIPLL
         CLK_STGEN_HSE
         CLK_USBPHY_HSE
-        CLK_SPI2S1_PLL3Q /* s disabled */
-        CLK_SPI2S23_PLL4P
-        CLK_SPI45_HSI /* s disabled */
-        CLK_SPI6_HSI /* s disabled */
+        CLK_SPI2S1_PLL3Q
+        CLK_SPI2S23_PLL3Q
+        CLK_SPI45_HSI
+        CLK_SPI6_HSI
         CLK_I2C46_HSI
-        CLK_SDMMC3_PLL3R  /* s disabled */
+        CLK_SDMMC3_PLL3R
         CLK_USBO_USBPHY
         CLK_ADC_CKPER
-        CLK_CEC_LSE  /* s disabled */
+        CLK_CEC_LSE
         CLK_I2C12_HSI
-        CLK_I2C35_HSI  /* s disabled */
-        CLK_UART1_HSI  /* s disabled */
-        CLK_UART24_PCLK1
-        CLK_UART35_HSI /* s disabled */
-        CLK_UART6_PCLK2
-        CLK_UART78_HSI /* s disabled */
-        CLK_SPDIF_PLL3Q /* s disabled */
+        CLK_I2C35_HSI
+        CLK_UART1_HSI
+        CLK_UART24_HSI
+        CLK_UART35_HSI
+        CLK_UART6_HSI
+        CLK_UART78_HSI
+        CLK_SPDIF_PLL3Q
         CLK_FDCAN_HSE
-        CLK_SAI1_PLL3Q /* s disabled */
-        CLK_SAI2_PLL3Q /* s disabled */
-        CLK_SAI3_PLL3Q /* s disabled */
-        CLK_SAI4_PLL3Q /* s disabled */
-        CLK_RNG1_CSI
-        CLK_RNG2_CSI
-        CLK_LPTIM1_PCLK1 /* s disabled */
-        CLK_LPTIM23_PCLK3 /* s disabled */
-        CLK_LPTIM45_PCLK3 /* s disabled */
+        CLK_SAI1_PLL3Q
+        CLK_SAI2_PLL3Q
+        CLK_SAI3_PLL3Q
+        CLK_SAI4_PLL3Q
+		CLK_RNG1_CSI
+		CLK_RNG2_CSI
+        CLK_LPTIM1_PCLK1
+        CLK_LPTIM23_PCLK3
+        CLK_LPTIM45_PCLK3
     >;
     pll1:st,pll@0 {
-        cfg = < 2 80 0 1 1 1>; /* P=648MHz, Q=324Hz, R=324MHz */
-        /* frac = < 0x800 >; */
+        cfg = < 2 80 0 0 0 1>;
+        frac = < 0x800 >;
     };
     pll2:st,pll@1 {
-        cfg = < 2 65 1 1 0 7>; /* P=264MHz, Q=264Hz, R=528MHz */
-        /* frac = < 0x1400 >; */
+        cfg = < 2 65 1 0 0 5>;
+        frac = < 0x1400 >;
     };
     pll3:st,pll@2 {
-        cfg = < 1 49 2 2 1 3>; /* P=200MHz, Q=200MHz, R=300MHz */
+        cfg = < 2 97 3 15 7 5>;
+        frac = < 0x9ba >;
     };
     pll4:st,pll@3 {
-        cfg = < 5 124 9 9 9 3>; /* P=50MHz, Q=50Hz, R=50MHz */
+        cfg = < 5 124 9 9 9 3>;
     };
 };
-#endif /* RCC_FROM_MX */
-
-&pwr {
-	pwr-supply = <&vdd>;
-	system_suspend_supported_soc_modes = <
-		STM32_PM_CSLEEP_RUN
-		STM32_PM_CSTOP_ALLOW_LP_STOP
-		STM32_PM_CSTOP_ALLOW_STANDBY_DDR_SR
-	>;
-
-	system_off_soc_mode = <STM32_PM_CSTOP_ALLOW_STANDBY_DDR_OFF>;
-};
-
-#ifndef ETZPC_FROM_MX
-/* Security specific */
-/* Set all peripherals to sensible defaults (DECPROT_NS_RW)
- * If you need special settings you have to define your own devicetree and tf-a
- * variant
- */
-&etzpc{
-    st,decprot = <
-    /*"Cortex-A7 secure" context*/
-    /*"Cortex-A7 non secure" context*/
-    DECPROT(STM32MP1_ETZPC_ADC_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_OTG_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_CRYP1_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_HASH1_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_VREFBUF_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_ETH_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_TT_FDCAN_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_TIM4_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_TIM1_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_SPI1_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_UART4_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_QSPI_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    /*Restriction: STM32MP1_ETZPC_DLYBQ_ID is not managed - please to use User-Section if needed*/
-    DECPROT(STM32MP1_ETZPC_RNG1_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_USART2_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_I2C2_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_I2C4_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_SPI2_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_USART6_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-
-    /*Restriction: following IDs are not managed - please to use User-Section if needed:
-     STM32MP1_ETZPC_DMA1_ID, STM32MP1_ETZPC_DMA2_ID, STM32MP1_ETZPC_DMAMUX_ID,
-     STM32MP1_ETZPC_SRAMx_ID, STM32MP1_ETZPC_RETRAM_ID, STM32MP1_ETZPC_BKPSRAM_ID*/
-
-    /* USER CODE BEGIN etzpc_decprot */
-     /*STM32CubeMX generates a basic and standard configuration for ETZPC.
-     Additional device configurations can be added here if needed.
-     "etzpc" node could be also overloaded in "addons" User-Section.*/
-    /* USER CODE END etzpc_decprot */
-    >;
-    secure-status = "okay";
-
-    /* USER CODE BEGIN etzpc */
-    /* USER CODE END etzpc */
-};
-#endif /* ETZPC_FROM_MX */
 
 &pinctrl {
 	/* som pin mux */
     quadspi_pins_som: quadspi_som@0 {
-        pins1 {
+        pins {
             pinmux = <STM32_PINMUX('B', 6, AF10)>, /* QUADSPI_BK1_NCS */
-                     <STM32_PINMUX('C', 0, AF10)>; /* QUADSPI_BK2_NCS */
-            bias-pull-up;
-            drive-push-pull;
-            slew-rate = <3>;
-        };
-        pins2 {
-            pinmux = <STM32_PINMUX('E', 7, AF10)>, /* QUADSPI_BK2_IO0 */
+                     <STM32_PINMUX('C', 0, AF10)>, /* QUADSPI_BK2_NCS */
+                     <STM32_PINMUX('E', 7, AF10)>, /* QUADSPI_BK2_IO0 */
                      <STM32_PINMUX('E', 8, AF10)>, /* QUADSPI_BK2_IO1 */
                      <STM32_PINMUX('E', 9, AF10)>, /* QUADSPI_BK2_IO2 */
                      <STM32_PINMUX('E', 10, AF10)>, /* QUADSPI_BK2_IO3 */
@@ -280,25 +183,6 @@
     };
 };
 
-&bsec{
-    status = "okay";
-    secure-status = "okay";
-    
-    /*opt word 59*/
-    som_id: som_id@ec{
-		reg=<0xec 0x4>;
-		status="okay";
-		secure-status="okay";			
-	};
-	
-	/*otp word 60*/
-	board_id: board_id@f0{
-		reg=<0xf0 0x4>;
-		status="okay";
-		secure-status="okay";			
-	};
-};
-
 /* Console */
 &uart4 {
 	pinctrl-names = "default";
@@ -309,37 +193,9 @@
 
 /* qspi flash */
 &qspi {
-	#address-cells = <1>;
-	#size-cells = <0>;
     pinctrl-names = "default";
     pinctrl-0 = <&quadspi_pins_som>;
     status = "okay";
-
-    flash0: mx25r1635f@0 {
-		u-boot,dm-pre-reloc;
-		compatible = "spi-flash", "jedec,spi-nor";
-		reg = <0>;
-		spi-rx-bus-width = <4>;
-		spi-tx-bus-width = <4>;
-		spi-max-frequency = <8000000>; /* MX25R1635F is slow */
-
-		/* required for partitions when mtdparts in u-boot are used */
-		#address-cells = <1>;
-		#size-cells = <1>;
-	};
-
-	flash1: spinand@1 {
-		u-boot,dm-pre-reloc;
-		compatible = "spi-nand";
-		reg = <1>;
-		spi-rx-bus-width = <4>;
-		spi-tx-bus-width = <4>;
-		spi-max-frequency = <104000000>;
-
-		/* required for partitions when mtdparts in u-boot are used */
-		#address-cells = <1>;
-		#size-cells = <1>;
-	};
 };
 
 &usbotg_hs {
@@ -350,7 +206,6 @@
 
 &rng1 {
 	status = "okay";
-	secure-status = "okay";
 };
 
 &iwdg2 {
@@ -361,6 +216,5 @@
 
 &rcc {
     status = "okay";
-    secure-status = "okay";
 };
 
diff --git a/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/stm32mp-som-t1001.dtsi b/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/stm32mp-som-t1001.dtsi
deleted file mode 100644
index 75b2d8ef9ce89251df5dd0e87a7350bb26469538..0000000000000000000000000000000000000000
--- a/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/stm32mp-som-t1001.dtsi
+++ /dev/null
@@ -1,355 +0,0 @@
-/* Devicetree file for fixed components for SOM t1001
- *
- * device    : stm32mp-som-t1001
- * board code: 40099 164
- * revision  : 00
- *
- * Defines fixed SOM components
- * - RAM configuration,
- * - Default clock configuration (rcc node)
- * - Default security configuration (etzpc node)
- * - Pin configurations for fixed SOM peripherals
- *
- * If rcc node or etzpc node shouldn't be include define this variables
- * to leave the configuration as is:
- * - RCC_FROM_MX
- * - ETZPC_FROM_MX
- *
- * Kontron Electronics GmbH
- * Copyright 2019 Kontron Electronics GmbH. All rights reserved.
- */
-
-
-#include <dt-bindings/power/stm32mp1-power.h>
-
-/* force DDR settings */
-#include "stm32mp157c-t1000-ddr-undef.h"
-#include "stm32mp157c-t1000-ddr3-1x4Gb-1066-binG.h"
-#include "stm32mp15-ddr.dtsi"
-
-/ {
-	aliases {
-		serial0 = &uart4;
-	};
-
-	chosen {
-		stdout-path = "serial0:115200n8";
-	};
-
-	aliases {
-		gpio0 = &gpioa;
-		gpio1 = &gpiob;
-		gpio2 = &gpioc;
-		gpio3 = &gpiod;
-		gpio4 = &gpioe;
-		gpio5 = &gpiof;
-		gpio6 = &gpiog;
-		gpio7 = &gpioh;
-		gpio8 = &gpioi;
-		gpio9 = &gpioj;
-		gpio10 = &gpiok;
-		gpio25 = &gpioz;
-	};
-
-	/* Regulators */
-	vdd: regulator-vdd {
-		compatible = "regulator-fixed";
-		regulator-name = "vdd";
-		regulator-min-microvolt = <3300000>;
-		regulator-max-microvolt = <3300000>;
-		regulator-always-on;
-	};
-	soc {
-		stgen: stgen@5C008000 {
-			compatible = "st,stm32-stgen";
-			reg = <0x5C008000 0x1000>;
-			status = "okay";
-		};
-
-	};
-
-    clocks {
-        clk_lse: clk-lse {
-            st,drive=<LSEDRV_MEDIUM_HIGH>;
-        };
-    };
-};
-
-#ifndef RCC_FROM_MX
-/* force clock settings */
-/* Set all clocks to sensible defaults
- * If you need special settings you have to define your own devicetree and tf-a
- * variant.
- */
-&rcc {
-    st,hsi-cal;
-    st,csi-cal;
-    st,cal-sec = <60>;
-    st,clksrc = <
-        CLK_MPU_PLL1P
-        CLK_AXI_PLL2P
-        CLK_MCU_PLL3P
-        CLK_PLL12_HSE
-        CLK_PLL3_HSE
-        CLK_PLL4_HSE
-        CLK_RTC_LSE
-        CLK_MCO1_DISABLED
-        CLK_MCO2_DISABLED
-    >;
-    st,clkdiv = <
-        1         /*MPU*/
-        0         /*AXI*/
-        0         /*MCU*/
-        1         /*APB1*/
-        1         /*APB2*/
-        1         /*APB3*/
-        1         /*APB4*/
-        2         /*APB5*/
-        0         /*RTC*/
-        0         /*MCO1*/
-        0         /*MCO2*/
-    >;
-    st,pkcs = <
-        CLK_CKPER_HSE
-        CLK_QSPI_ACLK
-        CLK_ETH_PLL4P
-        CLK_SDMMC12_PLL4P
-		CLK_DSI_DSIPLL
-        CLK_STGEN_HSE
-        CLK_USBPHY_HSE
-        CLK_SPI2S1_PLL3Q
-        CLK_SPI2S23_PLL4P
-        CLK_SPI45_HSI
-        CLK_SPI6_HSI
-        CLK_I2C46_HSI
-        CLK_SDMMC3_PLL3R
-        CLK_USBO_USBPHY
-        CLK_ADC_CKPER
-        CLK_CEC_LSE
-        CLK_I2C12_HSI
-        CLK_I2C35_HSI
-        CLK_UART1_HSI
-        CLK_UART24_PCLK1
-        CLK_UART35_HSI
-        CLK_UART6_PCLK2
-        CLK_UART78_HSI
-        CLK_SPDIF_PLL3Q
-        CLK_FDCAN_HSE
-        CLK_SAI1_PLL3Q
-        CLK_SAI2_PLL3Q
-        CLK_SAI3_PLL3Q
-        CLK_SAI4_PLL3Q
-        CLK_RNG1_CSI
-        CLK_RNG2_CSI
-        CLK_LPTIM1_PCLK1
-        CLK_LPTIM23_PCLK3
-        CLK_LPTIM45_PCLK3
-    >;
-    pll1:st,pll@0 {
-        cfg = < 2 80 0 1 1 1>; /* P=648MHz, Q=324Hz, R=324MHz */
-        /* frac = < 0x800 >; */
-    };
-    pll2:st,pll@1 {
-        cfg = < 2 65 1 1 0 7>; /* P=264MHz, Q=264Hz, R=528MHz */
-        /* frac = < 0x1400 >; */
-    };
-    pll3:st,pll@2 {
-        cfg = < 1 49 2 2 1 3>; /* P=200MHz, Q=200MHz, R=300MHz */
-    };
-    pll4:st,pll@3 {
-        cfg = < 5 124 9 9 9 3>; /* P=50MHz, Q=50Hz, R=50MHz */
-    };
-};
-#endif /* RCC_FROM_MX */
-
-&pwr {
-	pwr-supply = <&vdd>;
-	system_suspend_supported_soc_modes = <
-		STM32_PM_CSLEEP_RUN
-		STM32_PM_CSTOP_ALLOW_LP_STOP
-		STM32_PM_CSTOP_ALLOW_STANDBY_DDR_SR
-	>;
-
-	system_off_soc_mode = <STM32_PM_CSTOP_ALLOW_STANDBY_DDR_OFF>;
-};
-
-#ifndef ETZPC_FROM_MX
-/* Security specific */
-/* Set all peripherals to sensible defaults (DECPROT_NS_RW)
- * If you need special settings you have to define your own devicetree and tf-a
- * variant
- */
-&etzpc{
-    st,decprot = <
-    /*"Cortex-A7 secure" context*/
-    /*"Cortex-A7 non secure" context*/
-    DECPROT(STM32MP1_ETZPC_ADC_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_OTG_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_CRYP1_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_HASH1_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_VREFBUF_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_ETH_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_TT_FDCAN_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_TIM4_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_TIM1_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_SPI1_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_UART4_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_QSPI_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_DLYBQ_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_RNG1_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_USART2_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_I2C2_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_I2C4_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_SPI2_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_USART6_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-
-    /*Restriction: following IDs are not managed - please to use User-Section if needed:
-     STM32MP1_ETZPC_DMA1_ID, STM32MP1_ETZPC_DMA2_ID, STM32MP1_ETZPC_DMAMUX_ID,
-     STM32MP1_ETZPC_SRAMx_ID, STM32MP1_ETZPC_RETRAM_ID, STM32MP1_ETZPC_BKPSRAM_ID*/
-
-    /* USER CODE BEGIN etzpc_decprot */
-     /*STM32CubeMX generates a basic and standard configuration for ETZPC.
-     Additional device configurations can be added here if needed.
-     "etzpc" node could be also overloaded in "addons" User-Section.*/
-    /* USER CODE END etzpc_decprot */
-    >;
-    secure-status = "okay";
-
-    /* USER CODE BEGIN etzpc */
-    /* USER CODE END etzpc */
-};
-#endif /* ETZPC_FROM_MX */
-
-&pinctrl {
-	/* som pin mux */
-    quadspi_pins_som: quadspi_som@0 {
-        pins1 {
-            pinmux = <STM32_PINMUX('B', 6, AF10)>, /* QUADSPI_BK1_NCS */
-                     <STM32_PINMUX('C', 0, AF10)>; /* QUADSPI_BK2_NCS */
-            bias-pull-up;
-            drive-push-pull;
-            slew-rate = <3>;
-        };
-        pins2 {
-            pinmux = <STM32_PINMUX('E', 7, AF10)>, /* QUADSPI_BK2_IO0 */
-                     <STM32_PINMUX('E', 8, AF10)>, /* QUADSPI_BK2_IO1 */
-                     <STM32_PINMUX('E', 9, AF10)>, /* QUADSPI_BK2_IO2 */
-                     <STM32_PINMUX('E', 10, AF10)>, /* QUADSPI_BK2_IO3 */
-                     <STM32_PINMUX('F', 6, AF9)>, /* QUADSPI_BK1_IO3 */
-                     <STM32_PINMUX('F', 7, AF9)>, /* QUADSPI_BK1_IO2 */
-                     <STM32_PINMUX('F', 8, AF10)>, /* QUADSPI_BK1_IO0 */
-                     <STM32_PINMUX('F', 9, AF10)>, /* QUADSPI_BK1_IO1 */
-                     <STM32_PINMUX('F', 10, AF9)>; /* QUADSPI_CLK */
-            bias-disable;
-            drive-push-pull;
-            slew-rate = <3>;
-        };
-    };
-    uart4_pins_som: uart4_som@0 {
-        pins1 {
-            pinmux = <STM32_PINMUX('G', 11, AF6)>; /* UART4_TX */
-            bias-pull-up;
-            drive-push-pull;
-            slew-rate = <0>;
-        };
-        pins2 {
-            pinmux = <STM32_PINMUX('B', 2, AF8)>; /* UART4_RX */
-            bias-pull-up;
-        };
-    };
-    usb_otg_hs_pins_som: usb_otg_hs_som@0 {
-        pins {
-            pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
-        };
-    };
-};
-
-&bsec{
-    status = "okay";
-    secure-status = "okay";
-
-    /*opt word 59*/
-    som_id: som_id@ec{
-		reg=<0xec 0x4>;
-		status="okay";
-		secure-status="okay";			
-	};
-	
-	/*otp word 60*/
-	board_id: board_id@f0{
-		reg=<0xf0 0x4>;
-		status="okay";
-		secure-status="okay";			
-	};
-};
-
-/* Console */
-&uart4 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&uart4_pins_som>;
-	resets = <&rcc UART4_R>;
-	status = "okay";
-};
-
-/* qspi flash */
-&qspi {
-	#address-cells = <1>;
-	#size-cells = <0>;
-    pinctrl-names = "default";
-    pinctrl-0 = <&quadspi_pins_som>;
-    status = "okay";
-
-    flash0: mx25r1635f@0 {
-		u-boot,dm-pre-reloc;
-		compatible = "spi-flash", "jedec,spi-nor";
-		reg = <0>;
-		spi-rx-bus-width = <4>;
-		spi-tx-bus-width = <4>;
-		spi-max-frequency = <8000000>; /* MX25R1635F is slow */
-
-		/* required for partitions when mtdparts in u-boot are used */
-		#address-cells = <1>;
-		#size-cells = <1>;
-	};
-
-};
-
-&usbotg_hs {
-    pinctrl-names = "default";
-    pinctrl-0 = <&usb_otg_hs_pins_som>;
-    status = "okay";
-};
-
-&usbphyc{
-	status = "okay";
-};
-
-&usbphyc_port0{
-	status = "okay";
-};
-
-&usbphyc_port1{
-	status = "okay";
-};
-
-&rng1 {
-	status = "okay";
-	secure-status = "okay";
-};
-
-&iwdg2 {
-	instance = <0x2>;
-	timeout-sec = <0x20>;
-	status = "okay";
-};
-
-&rcc {
-    status = "okay";
-    secure-status = "okay";
-};
-
-&rtc{
-	status = "okay";
-	secure-status = "okay";
-};
-
diff --git a/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/stm32mp-t1000-clkout32k.dts b/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/stm32mp-t1000-clkout32k.dts
deleted file mode 100644
index 6e1e90a029e3fe9af25ce9984773bf35b861fea3..0000000000000000000000000000000000000000
--- a/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/stm32mp-t1000-clkout32k.dts
+++ /dev/null
@@ -1,128 +0,0 @@
-/* Devicetree file for basic t1000 SOM module
- *
- * These settings should work with most baseboards
- *
- * device    : stm32mp-t1000
- * board code: 40099 130
- * revision  : 03
- *
- * Kontron Electronics GmbH
- * Copyright 2019 Kontron Electronics GmbH. All rights reserved.
- */
-
-/* Include CubeMX board configuration
- * - pinmultiplexing and
- * - peripheal activation
- */
-#include "stm32mp157c-t1000-som-minimal-mx.dts"
-
-/* Include fixed SOM components
- * - RAM configuration,
- * - Default clock configuration (rcc node)
- * - Default security configuration (etzpc node)
- * - Pin configs for fixed SOM peripherals
- */
-#include "stm32mp-som-t1000.dtsi"
-
-/* Include baseboard */
-#include "stm32mp-board-minimal.dtsi"
-
-/* Include housing */
-/* NOT AVAILABLE */
-
-&rcc {
-	st,csi-cal;
-	st,hsi-cal;
-	st,cal-sec = <60>;
-	st,clksrc = <
-		CLK_MPU_PLL1P
-		CLK_AXI_PLL2P
-		CLK_MCU_PLL3P
-		CLK_PLL12_HSE
-		CLK_PLL3_HSE
-		CLK_PLL4_HSE
-		CLK_RTC_LSE
-		CLK_MCO1_LSE
-		CLK_MCO2_DISABLED
-	>;
-	st,clkdiv = <
-		1 		/*MPU*/
-		0 		/*AXI*/
-		0 		/*MCU*/
-		1 		/*APB1*/
-		1 		/*APB2*/
-		1 		/*APB3*/
-		1 		/*APB4*/
-		2 		/*APB5*/
-		0 		/*RTC*/
-		0 		/*MCO1*/
-		0 		/*MCO2*/
-	>;
-	st,pkcs = <
-		CLK_CKPER_HSE
-		CLK_QSPI_ACLK
-		CLK_ETH_PLL4P
-		CLK_SDMMC12_PLL4P
-		CLK_STGEN_HSE
-		CLK_USBPHY_HSE
-		CLK_SPI2S1_DISABLED
-		CLK_SPI2S23_DISABLED
-		CLK_SPI45_DISABLED
-		CLK_SPI6_DISABLED
-		CLK_I2C46_DISABLED
-		CLK_SDMMC3_DISABLED
-		CLK_USBO_USBPHY
-		CLK_ADC_CKPER
-		CLK_CEC_DISABLED
-		CLK_I2C12_HSI
-		CLK_I2C35_DISABLED
-		CLK_UART1_DISABLED
-		CLK_UART24_PCLK1
-		CLK_UART35_DISABLED
-		CLK_UART6_DISABLED
-		CLK_UART78_DISABLED
-		CLK_SPDIF_DISABLED
-		CLK_SAI1_DISABLED
-		CLK_SAI2_DISABLED
-		CLK_SAI3_DISABLED
-		CLK_SAI4_DISABLED
-		CLK_RNG1_CSI
-		CLK_LPTIM1_DISABLED
-		CLK_LPTIM23_DISABLED
-		CLK_LPTIM45_DISABLED
-	>;
-	pll1:st,pll@0 {
-		cfg = < 2 80 0 1 1 1>;
-	};
-	pll2:st,pll@1 {
-		cfg = < 2 65 1 1 0 7>;
-	};
-	pll3:st,pll@2 {
-		cfg = < 1 49 2 2 1 1>;
-	};
-	pll4:st,pll@3 {
-		cfg = < 5 124 9 9 9 1>;
-	};
-};
-
-&pinctrl {
-	rcc_pins_mx: rcc_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 13, AF2)>; /* RCC_MCO_1 */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-	};
-};
-
-&rcc{
-	pinctrl-names = "default";
-	pinctrl-0 = <&rcc_pins_mx>;
-};
-
-/* Model identification */
-/ {
-	model = "stm32mp-t1000 (tf-a)";
- 	compatible = "ex,stm32mp-t1000", "st,stm32mp157";
-};
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-t1000-testadapter.dts b/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/stm32mp-t1000-default.dts
similarity index 52%
rename from recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-t1000-testadapter.dts
rename to recipes-bsp/trusted-firmware-a/tf-a-stm32mp/stm32mp-t1000-default.dts
index 02138c0c2c10be249d1fed93b72fc9eca84fdcd9..f19f139cb010b51a1f10936a0fb9c6c790350347 100644
--- a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-t1000-testadapter.dts
+++ b/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/stm32mp-t1000-default.dts
@@ -1,17 +1,18 @@
 /* Devicetree file for device
  *
- * device   : stm32mp-t1000-testadapter
+ * device   : stm32mp-t1000-default
  * revision : prototype
  *
  * Kontron Electronics GmbH
- * Copyright 2019 Kontron Electronics GmbH. All rights reserved.
+ * Copyright 2018 Kontron Electronics GmbH. All rights reserved.
  */
 
 /* Include CubeMX board configuration
  * - pinmultiplexing and
  * - peripheal activation
  */
-#include "stm32mp157c-t1000-s-mx.dts"
+#define CLK_FDCAN_DISABLED	0x000090C3
+#include "stm32mp157c-t1000-default-mx.dts"
 
 /* Include SOM components
  * - SOM components: RAM,
@@ -20,7 +21,7 @@
 #include "stm32mp-som-t1000.dtsi"
 
 /* Include baseboard */
-#include "stm32mp-board-s.dtsi"
+#include "stm32mp-board-default.dtsi"
 
 /* Include housing */
 /* NOT AVAILABLE */
@@ -28,11 +29,6 @@
 
 /* Model identification */
 / {
-	model = "stm32mp-t1000-testadapter (linux)";
- 	compatible = "ex,stm32mp-t1000-testadapter", "st,stm32mp157";
-
- 	device-identification {
- 		device = "t1000-testadapter";
- 		device_code = "unknown";
- 	};
+	model = "stm32mp-t1000-default (tf-a)";
+ 	compatible = "ex,stm32mp-t1000-default", "st,stm32mp157";
 };
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-t1000-k.dts b/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/stm32mp-t1000-mini.dts
similarity index 52%
rename from recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-t1000-k.dts
rename to recipes-bsp/trusted-firmware-a/tf-a-stm32mp/stm32mp-t1000-mini.dts
index 55df37beda804019b42c6babe8c179101e2d4479..7ca4b9f5185c16775f1ced487352a29840ed3d16 100644
--- a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-t1000-k.dts
+++ b/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/stm32mp-t1000-mini.dts
@@ -1,17 +1,18 @@
 /* Devicetree file for device
  *
- * device   : stm32mp-t1000-k
- * revision : 0
+ * device   : stm32mp-t1000-mini
+ * revision : prototype
  *
  * Kontron Electronics GmbH
- * Copyright 2019 Kontron Electronics GmbH. All rights reserved.
+ * Copyright 2018 Kontron Electronics GmbH. All rights reserved.
  */
 
 /* Include CubeMX board configuration
  * - pinmultiplexing and
  * - peripheal activation
  */
-#include "stm32mp157c-t1000-k-mx.dts"
+#define CLK_FDCAN_DISABLED	0x000090C3
+#include "stm32mp157c-t1000-mini-mx.dts"
 
 /* Include SOM components
  * - SOM components: RAM,
@@ -20,7 +21,7 @@
 #include "stm32mp-som-t1000.dtsi"
 
 /* Include baseboard */
-#include "stm32mp-board-k.dtsi"
+#include "stm32mp-board-mini.dtsi"
 
 /* Include housing */
 /* NOT AVAILABLE */
@@ -28,11 +29,6 @@
 
 /* Model identification */
 / {
-	model = "stm32mp-t1000-k (linux)";
- 	compatible = "ex,stm32mp-t1000-k", "st,stm32mp157";
-
- 	device-identification {
- 		device = "t1000-k";
- 		device_code = "50099 045 01";
- 	};
+	model = "stm32mp-t1000-mini (tf-a)";
+ 	compatible = "ex,stm32mp-t1000-mini", "st,stm32mp157";
 };
diff --git a/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/stm32mp-t1000-s.dts b/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/stm32mp-t1000-s.dts
index 16475031e720ebbe37f99f8f5e54a2da49d7ef15..42c2f6534673367222aa38888ec64570167251b9 100644
--- a/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/stm32mp-t1000-s.dts
+++ b/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/stm32mp-t1000-s.dts
@@ -11,13 +11,12 @@
  * - pinmultiplexing and
  * - peripheal activation
  */
+#define CLK_FDCAN_DISABLED	0x000090C3
 #include "stm32mp157c-t1000-s-mx.dts"
 
-/* Include fixed SOM components
- * - RAM configuration,
- * - Default clock configuration (rcc node)
- * - Default security configuration (etzpc node)
- * - Pin configs for fixed SOM peripherals
+/* Include SOM components
+ * - SOM components: RAM,
+ * - Basic Clocks (only tf-a, u-boot)
  */
 #include "stm32mp-som-t1000.dtsi"
 
diff --git a/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/stm32mp-t1000.dts b/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/stm32mp-t1000.dts
deleted file mode 100644
index 4281786ce8160e52774f03cec4f1fa2a707e822d..0000000000000000000000000000000000000000
--- a/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/stm32mp-t1000.dts
+++ /dev/null
@@ -1,38 +0,0 @@
-/* Devicetree file for basic t1000 SOM module
- *
- * These settings should work with most baseboards
- *
- * device    : stm32mp-t1000
- * board code: 40099 130
- * revision  : 03
- *
- * Kontron Electronics GmbH
- * Copyright 2019 Kontron Electronics GmbH. All rights reserved.
- */
-
-/* Include CubeMX board configuration
- * - pinmultiplexing and
- * - peripheal activation
- */
-#include "stm32mp157c-t1000-som-minimal-mx.dts"
-
-/* Include fixed SOM components
- * - RAM configuration,
- * - Default clock configuration (rcc node)
- * - Default security configuration (etzpc node)
- * - Pin configs for fixed SOM peripherals
- */
-#include "stm32mp-som-t1000.dtsi"
-
-/* Include baseboard */
-#include "stm32mp-board-minimal.dtsi"
-
-/* Include housing */
-/* NOT AVAILABLE */
-
-
-/* Model identification */
-/ {
-	model = "stm32mp-t1000 (tf-a)";
- 	compatible = "ex,stm32mp-t1000", "st,stm32mp157";
-};
diff --git a/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/stm32mp-t1001.dts b/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/stm32mp-t1001.dts
deleted file mode 100644
index 308bd8d1ac1c87a4dfcd064fc7f41939d40a6f41..0000000000000000000000000000000000000000
--- a/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/stm32mp-t1001.dts
+++ /dev/null
@@ -1,38 +0,0 @@
-/* Devicetree file for basic t1001 SOM module
- *
- * These settings should work with most baseboards
- *
- * device    : stm32mp-t1001
- * board code: 40099 164
- * revision  : 00
- *
- * Kontron Electronics GmbH
- * Copyright 2019 Kontron Electronics GmbH. All rights reserved.
- */
-
-/* Include CubeMX board configuration
- * - pinmultiplexing and
- * - peripheal activation
- */
-#include "stm32mp157c-t1001-som-minimal-mx.dts"
-
-/* Include fixed SOM components
- * - RAM configuration,
- * - Default clock configuration (rcc node)
- * - Default security configuration (etzpc node)
- * - Pin configs for fixed SOM peripherals
- */
-#include "stm32mp-som-t1001.dtsi"
-
-/* Include baseboard */
-#include "stm32mp-board-minimal.dtsi"
-
-/* Include housing */
-/* NOT AVAILABLE */
-
-
-/* Model identification */
-/ {
-	model = "stm32mp-t1001 (tf-a)";
- 	compatible = "ex,stm32mp-t1001", "st,stm32mp157";
-};
diff --git a/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/stm32mp157c-t1000-ddr3-1x4Gb-1066-binG.h b/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/stm32mp157c-t1000-ddr3-1x4Gb-1066-binG.h
index 8746a4b32a08540cac660161e6024c9546ce9b26..7d9e48b08091620c799a7e6da7907acb3c53ff92 100644
--- a/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/stm32mp157c-t1000-ddr3-1x4Gb-1066-binG.h
+++ b/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/stm32mp157c-t1000-ddr3-1x4Gb-1066-binG.h
@@ -10,17 +10,16 @@
  * DDR type: DDR3 / DDR3L
  * DDR width: 16bits
  * DDR density: 4Gb
- * System frequency: 528000Khz
+ * System frequency: 528Mhz
  * Relaxed Timing Mode: false
  * Address mapping type: RBC
  * tREFI 3,9us
- * Calibration: CubeMX 5.1.0 on #11
  *
- * Save Date: 2019.04.04, save Time: 16:24:24
+ * Save Date: 2019.01.16, save Time: 14:01:31
  */
 
-#define DDR_MEM_NAME	"DDR3-DDR3L 16bits 528Mhz K4B4G1646E (v1,1066-7-7-7,cal)"
-#define DDR_MEM_SPEED	528000
+#define DDR_MEM_NAME	"DDR3-DDR3L 16bits 533Mhz K4B4G1646E (1066-7-7-7-std,calibrated-patched)"
+#define DDR_MEM_SPEED	533
 #define DDR_MEM_SIZE	0x20000000
 
 #define DDR_MSTR 0x00041401
@@ -33,8 +32,12 @@
 #define DDR_HWLPCTL 0x00000000
 #define DDR_RFSHCTL0 0x00210000
 #define DDR_RFSHCTL3 0x00000000
+//#define DDR_RFSHTMG 0x0080008A
+// set tREFI 3.9us
 #define DDR_RFSHTMG 0x0040008A
 #define DDR_CRCPARCTL0 0x00000000
+//#define DDR_DRAMTMG0 0x121B2414
+// set tREFI 3.9us
 #define DDR_DRAMTMG0 0x121B1214
 #define DDR_DRAMTMG1 0x000A041B
 #define DDR_DRAMTMG2 0x0607080F
@@ -55,7 +58,7 @@
 #define DDR_DFIPHYMSTR 0x00000000
 #define DDR_ODTCFG 0x06000600
 #define DDR_ODTMAP 0x00000001
-#define DDR_SCHED 0x00000C01
+#define DDR_SCHED 0x00001201
 #define DDR_SCHED1 0x00000000
 #define DDR_PERFHPR1 0x01000001
 #define DDR_PERFLPR1 0x08000200
@@ -67,15 +70,15 @@
 #define DDR_PCCFG 0x00000010
 #define DDR_PCFGR_0 0x00010000
 #define DDR_PCFGW_0 0x00000000
-#define DDR_PCFGQOS0_0 0x02100C03
+#define DDR_PCFGQOS0_0 0x02100B03
 #define DDR_PCFGQOS1_0 0x00800100
-#define DDR_PCFGWQOS0_0 0x01100C03
+#define DDR_PCFGWQOS0_0 0x01100B03
 #define DDR_PCFGWQOS1_0 0x01000200
 #define DDR_PCFGR_1 0x00010000
 #define DDR_PCFGW_1 0x00000000
-#define DDR_PCFGQOS0_1 0x02100C03
-#define DDR_PCFGQOS1_1 0x00800040
-#define DDR_PCFGWQOS0_1 0x01100C03
+#define DDR_PCFGQOS0_1 0x02100B03
+#define DDR_PCFGQOS1_1 0x00800000
+#define DDR_PCFGWQOS0_1 0x01100B03
 #define DDR_PCFGWQOS1_1 0x01000200
 #define DDR_ADDRMAP1 0x00070707
 #define DDR_ADDRMAP2 0x00000000
@@ -99,18 +102,22 @@
 #define DDR_DTPR2 0x10023600
 #define DDR_MR0 0x00000830
 #define DDR_MR1 0x00000000
-#define DDR_MR2 0x00000248
+#define DDR_MR2 0x00000208
 #define DDR_MR3 0x00000000
 #define DDR_ODTCR 0x00010000
 #define DDR_ZQ0CR1 0x00000038
 #define DDR_DX0GCR 0x0000CE81
+//#define DDR_DX0DLLCR 0x4000C000
+// fix CubeMX calibration bug
 #define DDR_DX0DLLCR 0x40000000
-#define DDR_DX0DQTR 0x55050005
-#define DDR_DX0DQSTR 0x3D202000
+#define DDR_DX0DQTR 0x10100211
+#define DDR_DX0DQSTR 0x3DB02000
 #define DDR_DX1GCR 0x0000CE81
+//#define DDR_DX1DLLCR 0x4000C000
+// fix CubeMX calibration bug
 #define DDR_DX1DLLCR 0x40000000
-#define DDR_DX1DQTR 0x00050500
-#define DDR_DX1DQSTR 0x3DB02000
+#define DDR_DX1DQTR 0x10100211
+#define DDR_DX1DQSTR 0x3D202000
 #define DDR_DX2GCR 0x00000000
 #define DDR_DX2DLLCR 0x00000000
 #define DDR_DX2DQTR 0x00000000
diff --git a/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/stm32mp157c-t1000-default-mx.dts b/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/stm32mp157c-t1000-default-mx.dts
new file mode 100644
index 0000000000000000000000000000000000000000..d1c5d63824c378d8e1a5a9873d2cd6b2a8e4473d
--- /dev/null
+++ b/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/stm32mp157c-t1000-default-mx.dts
@@ -0,0 +1,221 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
+/*
+ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved
+ * Author: STM32CubeMX code generation for STMicroelectronics.
+ */
+
+/dts-v1/;
+#include <dt-bindings/clock/stm32mp1-clksrc.h>
+#include "stm32mp15-mx.h"
+
+#include "stm32mp157c.dtsi"
+#include "stm32mp157cad-pinctrl.dtsi"
+#include "stm32mp15-ddr.dtsi"
+#include "stm32mp157c-security.dtsi"
+
+/* USER CODE BEGIN dts_include */
+/* USER CODE END dts_include */
+
+/ {
+    model = "STMicroelectronics custom STM32CubeMX board";
+	compatible = "st,stm32mp157c-t1000-default-mx", "st,stm32mp157";
+
+	/* USER CODE BEGIN root_prop */
+	/* USER CODE END root_prop */
+
+    clocks {
+        clk_lse: clk-lse {
+            st,drive=<LSEDRV_LOWEST>;
+        };
+    };
+
+	/* USER CODE BEGIN root_subnodes */
+	/* USER CODE END root_subnodes */
+
+	/* USER CODE BEGIN root_board */
+	/* USER CODE END root_board */
+
+	/* USER CODE BEGIN root_platform */
+	/* USER CODE END root_platform */
+
+}; /*root*/
+
+/* USER CODE BEGIN dts_board */
+/* USER CODE END dts_board */
+
+&pinctrl {
+    quadspi_pins_mx: quadspi_mx@0 {
+        pins {
+            pinmux = <STM32_PINMUX('B', 6, AF10)>, /* QUADSPI_BK1_NCS */
+                     <STM32_PINMUX('C', 0, AF10)>, /* QUADSPI_BK2_NCS */
+                     <STM32_PINMUX('E', 7, AF10)>, /* QUADSPI_BK2_IO0 */
+                     <STM32_PINMUX('E', 8, AF10)>, /* QUADSPI_BK2_IO1 */
+                     <STM32_PINMUX('E', 9, AF10)>, /* QUADSPI_BK2_IO2 */
+                     <STM32_PINMUX('E', 10, AF10)>, /* QUADSPI_BK2_IO3 */
+                     <STM32_PINMUX('F', 6, AF9)>, /* QUADSPI_BK1_IO3 */
+                     <STM32_PINMUX('F', 7, AF9)>, /* QUADSPI_BK1_IO2 */
+                     <STM32_PINMUX('F', 8, AF10)>, /* QUADSPI_BK1_IO0 */
+                     <STM32_PINMUX('F', 9, AF10)>, /* QUADSPI_BK1_IO1 */
+                     <STM32_PINMUX('F', 10, AF9)>; /* QUADSPI_CLK */
+            bias-disable;
+            drive-push-pull;
+            slew-rate = <3>;
+        };
+    };
+    sdmmc1_pins_mx: sdmmc1_mx@0 {
+        pins {
+            pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
+                     <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
+                     <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
+                     <STM32_PINMUX('C', 11, AF12)>, /* SDMMC1_D3 */
+                     <STM32_PINMUX('C', 12, AF12)>, /* SDMMC1_CK */
+                     <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
+            bias-pull-up;
+            drive-push-pull;
+            slew-rate = <3>;
+        };
+    };
+    sdmmc2_pins_mx: sdmmc2_mx@0 {
+        pins {
+            pinmux = <STM32_PINMUX('B', 3, AF9)>, /* SDMMC2_D2 */
+                     <STM32_PINMUX('B', 4, AF9)>, /* SDMMC2_D3 */
+                     <STM32_PINMUX('B', 14, AF9)>, /* SDMMC2_D0 */
+                     <STM32_PINMUX('B', 15, AF9)>, /* SDMMC2_D1 */
+                     <STM32_PINMUX('E', 3, AF9)>, /* SDMMC2_CK */
+                     <STM32_PINMUX('G', 6, AF10)>; /* SDMMC2_CMD */
+            bias-pull-up;
+            drive-push-pull;
+            slew-rate = <3>;
+        };
+    };
+    uart4_pins_mx: uart4_mx@0 {
+        pins1 {
+            pinmux = <STM32_PINMUX('G', 11, AF6)>; /* UART4_TX */
+            bias-pull-up;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+        pins2 {
+            pinmux = <STM32_PINMUX('B', 2, AF8)>; /* UART4_RX */
+            bias-pull-up;
+        };
+    };
+    usb_otg_hs_pins_mx: usb_otg_hs_mx@0 {
+        pins {
+            pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
+        };
+    };
+};
+
+&rcc {
+    st,clksrc = <
+        CLK_MPU_PLL1P
+        CLK_AXI_PLL2P
+        CLK_MCU_PLL3P
+        CLK_PLL12_HSE
+        CLK_PLL3_HSE
+        CLK_PLL4_HSE
+        CLK_RTC_LSE
+        CLK_MCO1_DISABLED
+        CLK_MCO2_DISABLED
+    >;
+    st,clkdiv = <
+        1         /*MPU*/
+        0         /*AXI*/
+        0         /*MCU*/
+        1         /*APB1*/
+        1         /*APB2*/
+        1         /*APB3*/
+        1         /*APB4*/
+        2         /*APB5*/
+        23         /*RTC*/
+        0         /*MCO1*/
+        0         /*MCO2*/
+    >;
+    st,pkcs = <
+        CLK_CKPER_HSE
+        CLK_QSPI_ACLK
+        CLK_ETH_PLL4P
+        CLK_SDMMC12_PLL3R
+        CLK_STGEN_HSE
+        CLK_USBPHY_HSE
+        CLK_SPI2S1_DISABLED
+        CLK_SPI2S23_PLL3Q
+        CLK_SPI45_DISABLED
+        CLK_SPI6_DISABLED
+        CLK_I2C46_HSI
+        CLK_SDMMC3_DISABLED
+        CLK_USBO_USBPHY
+        CLK_ADC_CKPER
+        CLK_CEC_DISABLED
+        CLK_I2C12_HSI
+        CLK_I2C35_DISABLED
+        CLK_UART1_DISABLED
+        CLK_UART24_HSI
+        CLK_UART35_HSI
+        CLK_UART6_HSI
+        CLK_UART78_HSI
+        CLK_SPDIF_DISABLED
+        CLK_FDCAN_HSE
+        CLK_SAI1_DISABLED
+        CLK_SAI2_DISABLED
+        CLK_SAI3_DISABLED
+        CLK_SAI4_DISABLED
+        CLK_LPTIM1_DISABLED
+        CLK_LPTIM23_DISABLED
+        CLK_LPTIM45_DISABLED
+    >;
+    pll1:st,pll@0 {
+        cfg = < 2 80 0 0 0 1>;
+        frac = < 0x800 >;
+    };
+    pll2:st,pll@1 {
+        cfg = < 2 65 1 0 0 5>;
+        frac = < 0x1400 >;
+    };
+    pll3:st,pll@2 {
+        cfg = < 2 97 3 15 7 5>;
+        frac = < 0x9ba >;
+    };
+    pll4:st,pll@3 {
+        cfg = < 5 124 9 9 9 3>;
+    };
+};
+
+&qspi {
+    pinctrl-names = "default";
+    pinctrl-0 = <&quadspi_pins_mx>;
+    status = "okay";
+};
+
+&rcc {
+    status = "okay";
+};
+
+&sdmmc1 {
+    pinctrl-names = "default";
+    pinctrl-0 = <&sdmmc1_pins_mx>;
+    status = "okay";
+};
+
+&sdmmc2 {
+    pinctrl-names = "default";
+    pinctrl-0 = <&sdmmc2_pins_mx>;
+    status = "okay";
+};
+
+&uart4 {
+    pinctrl-names = "default";
+    pinctrl-0 = <&uart4_pins_mx>;
+    status = "okay";
+};
+
+&usbotg_hs {
+    pinctrl-names = "default";
+    pinctrl-0 = <&usb_otg_hs_pins_mx>;
+    status = "okay";
+};
+
+/* USER CODE BEGIN dts_soc */
+/* USER CODE END dts_soc */
+
diff --git a/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/stm32mp157c-t1000-mini-mx.dts b/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/stm32mp157c-t1000-mini-mx.dts
new file mode 100644
index 0000000000000000000000000000000000000000..284ac5f13dc53cd4be0c430fc29d33b6b7f0dbb5
--- /dev/null
+++ b/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/stm32mp157c-t1000-mini-mx.dts
@@ -0,0 +1,201 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
+/*
+ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved
+ * Author: STM32CubeMX code generation for STMicroelectronics.
+ */
+
+/dts-v1/;
+#include <dt-bindings/clock/stm32mp1-clksrc.h>
+#include "stm32mp15-mx.h"
+
+#include "stm32mp157c.dtsi"
+#include "stm32mp157cad-pinctrl.dtsi"
+#include "stm32mp15-ddr.dtsi"
+#include "stm32mp157c-security.dtsi"
+
+/* USER CODE BEGIN dts_include */
+/* USER CODE END dts_include */
+
+/ {
+    model = "STMicroelectronics custom STM32CubeMX board";
+	compatible = "st,stm32mp157c-t1000-mini-mx", "st,stm32mp157";
+
+	/* USER CODE BEGIN root_prop */
+	/* USER CODE END root_prop */
+
+    clocks {
+        clk_lse: clk-lse {
+            st,drive=<LSEDRV_LOWEST>;
+        };
+    };
+
+	/* USER CODE BEGIN root_subnodes */
+	/* USER CODE END root_subnodes */
+
+	/* USER CODE BEGIN root_board */
+	/* USER CODE END root_board */
+
+	/* USER CODE BEGIN root_platform */
+	/* USER CODE END root_platform */
+
+}; /*root*/
+
+/* USER CODE BEGIN dts_board */
+/* USER CODE END dts_board */
+
+&pinctrl {
+    quadspi_pins_mx: quadspi_mx@0 {
+        pins {
+            pinmux = <STM32_PINMUX('B', 6, AF10)>, /* QUADSPI_BK1_NCS */
+                     <STM32_PINMUX('C', 0, AF10)>, /* QUADSPI_BK2_NCS */
+                     <STM32_PINMUX('E', 7, AF10)>, /* QUADSPI_BK2_IO0 */
+                     <STM32_PINMUX('E', 8, AF10)>, /* QUADSPI_BK2_IO1 */
+                     <STM32_PINMUX('E', 9, AF10)>, /* QUADSPI_BK2_IO2 */
+                     <STM32_PINMUX('E', 10, AF10)>, /* QUADSPI_BK2_IO3 */
+                     <STM32_PINMUX('F', 6, AF9)>, /* QUADSPI_BK1_IO3 */
+                     <STM32_PINMUX('F', 7, AF9)>, /* QUADSPI_BK1_IO2 */
+                     <STM32_PINMUX('F', 8, AF10)>, /* QUADSPI_BK1_IO0 */
+                     <STM32_PINMUX('F', 9, AF10)>, /* QUADSPI_BK1_IO1 */
+                     <STM32_PINMUX('F', 10, AF9)>; /* QUADSPI_CLK */
+            bias-disable;
+            drive-push-pull;
+            slew-rate = <3>;
+        };
+    };
+    sdmmc1_pins_mx: sdmmc1_mx@0 {
+        pins {
+            pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
+                     <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
+                     <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
+                     <STM32_PINMUX('C', 11, AF12)>, /* SDMMC1_D3 */
+                     <STM32_PINMUX('C', 12, AF12)>, /* SDMMC1_CK */
+                     <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
+            bias-pull-up;
+            drive-push-pull;
+            slew-rate = <3>;
+        };
+    };
+    uart4_pins_mx: uart4_mx@0 {
+        pins1 {
+            pinmux = <STM32_PINMUX('G', 11, AF6)>; /* UART4_TX */
+            bias-pull-up;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+        pins2 {
+            pinmux = <STM32_PINMUX('B', 2, AF8)>; /* UART4_RX */
+            bias-pull-up;
+        };
+    };
+    usb_otg_hs_pins_mx: usb_otg_hs_mx@0 {
+        pins {
+            pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
+        };
+    };
+};
+
+&rcc {
+    st,clksrc = <
+        CLK_MPU_PLL1P
+        CLK_AXI_PLL2P
+        CLK_MCU_PLL3P
+        CLK_PLL12_HSE
+        CLK_PLL3_HSE
+        CLK_PLL4_HSE
+        CLK_RTC_LSE
+        CLK_MCO1_DISABLED
+        CLK_MCO2_DISABLED
+    >;
+    st,clkdiv = <
+        1         /*MPU*/
+        0         /*AXI*/
+        0         /*MCU*/
+        1         /*APB1*/
+        1         /*APB2*/
+        1         /*APB3*/
+        1         /*APB4*/
+        2         /*APB5*/
+        23         /*RTC*/
+        0         /*MCO1*/
+        0         /*MCO2*/
+    >;
+    st,pkcs = <
+        CLK_CKPER_HSE
+        CLK_QSPI_ACLK
+        CLK_ETH_PLL4P
+        CLK_SDMMC12_PLL3R
+        CLK_STGEN_HSE
+        CLK_USBPHY_HSE
+        CLK_SPI2S1_DISABLED
+        CLK_SPI2S23_PLL3Q
+        CLK_SPI45_DISABLED
+        CLK_SPI6_DISABLED
+        CLK_I2C46_HSI
+        CLK_SDMMC3_DISABLED
+        CLK_USBO_USBPHY
+        CLK_ADC_CKPER
+        CLK_CEC_DISABLED
+        CLK_I2C12_HSI
+        CLK_I2C35_DISABLED
+        CLK_UART1_DISABLED
+        CLK_UART24_HSI
+        CLK_UART35_DISABLED
+        CLK_UART78_DISABLED
+        CLK_SPDIF_DISABLED
+        CLK_FDCAN_DISABLED
+        CLK_SAI1_DISABLED
+        CLK_SAI2_DISABLED
+        CLK_SAI3_DISABLED
+        CLK_SAI4_DISABLED
+        CLK_LPTIM1_DISABLED
+        CLK_LPTIM23_DISABLED
+        CLK_LPTIM45_DISABLED
+    >;
+    pll1:st,pll@0 {
+        cfg = < 2 80 0 0 0 1>;
+        frac = < 0x800 >;
+    };
+    pll2:st,pll@1 {
+        cfg = < 2 65 1 0 0 5>;
+        frac = < 0x1400 >;
+    };
+    pll3:st,pll@2 {
+        cfg = < 2 97 3 15 7 5>;
+        frac = < 0x9ba >;
+    };
+    pll4:st,pll@3 {
+        cfg = < 5 124 9 9 9 1>;
+    };
+};
+
+&qspi {
+    pinctrl-names = "default";
+    pinctrl-0 = <&quadspi_pins_mx>;
+    status = "okay";
+};
+
+&rcc {
+    status = "okay";
+};
+
+&sdmmc1 {
+    pinctrl-names = "default";
+    pinctrl-0 = <&sdmmc1_pins_mx>;
+    status = "okay";
+};
+
+&uart4 {
+    pinctrl-names = "default";
+    pinctrl-0 = <&uart4_pins_mx>;
+    status = "okay";
+};
+
+&usbotg_hs {
+    pinctrl-names = "default";
+    pinctrl-0 = <&usb_otg_hs_pins_mx>;
+    status = "okay";
+};
+
+/* USER CODE BEGIN dts_soc */
+/* USER CODE END dts_soc */
+
diff --git a/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/stm32mp157c-t1000-mx.dts b/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/stm32mp157c-t1000-mx.dts
new file mode 100644
index 0000000000000000000000000000000000000000..94926cb8fcc4bf69b5de4bf1c16c51ff713e818a
--- /dev/null
+++ b/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/stm32mp157c-t1000-mx.dts
@@ -0,0 +1,236 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
+/*
+ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved
+ * Author: STM32CubeMX code generation for STMicroelectronics.
+ */
+
+/dts-v1/;
+#include <dt-bindings/clock/stm32mp1-clksrc.h>
+#include "stm32mp15-mx.h"
+
+#include "stm32mp157c.dtsi"
+#include "stm32mp157cad-pinctrl.dtsi"
+#include "stm32mp15-ddr.dtsi"
+#include "stm32mp157c-security.dtsi"
+
+/* USER CODE BEGIN dts_include */
+/* USER CODE END dts_include */
+
+/ {
+    model = "STMicroelectronics custom STM32CubeMX board";
+	compatible = "st,stm32mp157c-t1000-mx", "st,stm32mp157";
+
+	/* USER CODE BEGIN root_prop */
+	/* USER CODE END root_prop */
+
+    clocks {
+        clk_lse: clk-lse {
+            st,drive=<LSEDRV_LOWEST>;
+        };
+    };
+
+	/* USER CODE BEGIN root_subnodes */
+	/* USER CODE END root_subnodes */
+
+	/* USER CODE BEGIN root_board */
+	/* USER CODE END root_board */
+
+	/* USER CODE BEGIN root_platform */
+	/* USER CODE END root_platform */
+
+}; /*root*/
+
+/* USER CODE BEGIN dts_board */
+/* USER CODE END dts_board */
+
+&pinctrl {
+    quadspi_pins_mx: quadspi_mx@0 {
+        pins {
+            pinmux = <STM32_PINMUX('B', 6, AF10)>, /* QUADSPI_BK1_NCS */
+                     <STM32_PINMUX('C', 0, AF10)>, /* QUADSPI_BK2_NCS */
+                     <STM32_PINMUX('E', 7, AF10)>, /* QUADSPI_BK2_IO0 */
+                     <STM32_PINMUX('E', 8, AF10)>, /* QUADSPI_BK2_IO1 */
+                     <STM32_PINMUX('E', 9, AF10)>, /* QUADSPI_BK2_IO2 */
+                     <STM32_PINMUX('E', 10, AF10)>, /* QUADSPI_BK2_IO3 */
+                     <STM32_PINMUX('F', 6, AF9)>, /* QUADSPI_BK1_IO3 */
+                     <STM32_PINMUX('F', 7, AF9)>, /* QUADSPI_BK1_IO2 */
+                     <STM32_PINMUX('F', 8, AF10)>, /* QUADSPI_BK1_IO0 */
+                     <STM32_PINMUX('F', 9, AF10)>, /* QUADSPI_BK1_IO1 */
+                     <STM32_PINMUX('F', 10, AF9)>; /* QUADSPI_CLK */
+            bias-disable;
+            drive-push-pull;
+            slew-rate = <3>;
+        };
+    };
+    sdmmc1_pins_mx: sdmmc1_mx@0 {
+        pins {
+            pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
+                     <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
+                     <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
+                     <STM32_PINMUX('C', 11, AF12)>, /* SDMMC1_D3 */
+                     <STM32_PINMUX('C', 12, AF12)>, /* SDMMC1_CK */
+                     <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
+            bias-pull-up;
+            drive-push-pull;
+            slew-rate = <3>;
+        };
+    };
+    sdmmc2_pins_mx: sdmmc2_mx@0 {
+        pins {
+            pinmux = <STM32_PINMUX('B', 3, AF9)>, /* SDMMC2_D2 */
+                     <STM32_PINMUX('B', 4, AF9)>, /* SDMMC2_D3 */
+                     <STM32_PINMUX('B', 14, AF9)>, /* SDMMC2_D0 */
+                     <STM32_PINMUX('B', 15, AF9)>, /* SDMMC2_D1 */
+                     <STM32_PINMUX('E', 3, AF9)>, /* SDMMC2_CK */
+                     <STM32_PINMUX('G', 6, AF10)>; /* SDMMC2_CMD */
+            bias-pull-up;
+            drive-push-pull;
+            slew-rate = <3>;
+        };
+    };
+    uart4_pins_mx: uart4_mx@0 {
+        pins1 {
+            pinmux = <STM32_PINMUX('G', 11, AF6)>; /* UART4_TX */
+            bias-disable;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+        pins2 {
+            pinmux = <STM32_PINMUX('B', 2, AF8)>; /* UART4_RX */
+            bias-disable;
+        };
+    };
+    usb_otg_hs_pins_mx: usb_otg_hs_mx@0 {
+        pins {
+            pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
+        };
+    };
+};
+
+&rcc {
+    st,clksrc = <
+        CLK_MPU_PLL1P
+        CLK_AXI_PLL2P
+        CLK_MCU_PLL3P
+        CLK_PLL12_HSE
+        CLK_PLL3_HSE
+        CLK_PLL4_HSE
+        CLK_RTC_LSE
+        CLK_MCO1_DISABLED
+        CLK_MCO2_DISABLED
+    >;
+    st,clkdiv = <
+        1         /*MPU*/
+        0         /*AXI*/
+        0         /*MCU*/
+        1         /*APB1*/
+        1         /*APB2*/
+        1         /*APB3*/
+        1         /*APB4*/
+        2         /*APB5*/
+        23         /*RTC*/
+        0         /*MCO1*/
+        0         /*MCO2*/
+    >;
+/* Generated CubeMX configuration from
+ *
+ * changes:
+ *           was    new
+ *   SPI2S23 PLL4P  PLL3Q
+ *   ADC     PLL4Q  CKPER
+ *   UART35  PCLK1  HSI
+ *   UART6   PCLK2  HSI
+ *   UART78  PCKL1  HSI
+ *
+ *   Not configured by CubeMX
+ *   CLK_RNG1_CSI
+ *   CLK_RNG2_CSI
+ *
+ *   */
+    st,pkcs = <
+        CLK_CKPER_HSE
+        CLK_QSPI_ACLK
+        CLK_ETH_PLL4P
+        CLK_SDMMC12_PLL3R
+        CLK_STGEN_HSE
+        CLK_USBPHY_HSE
+        CLK_SPI2S1_DISABLED
+        CLK_SPI2S23_PLL3Q
+        CLK_SPI45_DISABLED
+        CLK_SPI6_DISABLED
+        CLK_I2C46_HSI
+        CLK_SDMMC3_DISABLED
+        CLK_USBO_USBPHY
+        CLK_ADC_CKPER
+        CLK_CEC_DISABLED
+        CLK_I2C12_HSI
+        CLK_I2C35_DISABLED
+        CLK_UART1_DISABLED
+        CLK_UART24_HSI
+        CLK_UART35_HSI
+        CLK_UART6_HSI
+        CLK_UART78_HSI
+        CLK_SPDIF_DISABLED
+        CLK_FDCAN_HSE
+        CLK_SAI1_DISABLED
+        CLK_SAI2_DISABLED
+        CLK_SAI3_DISABLED
+        CLK_SAI4_DISABLED
+        CLK_LPTIM1_DISABLED
+        CLK_LPTIM23_DISABLED
+        CLK_LPTIM45_DISABLED
+    >;
+    pll1:st,pll@0 {
+        cfg = < 2 80 0 0 0 1>;
+        frac = < 0x800 >;
+    };
+    pll2:st,pll@1 {
+        cfg = < 2 65 1 0 0 5>;
+        frac = < 0x1400 >;
+    };
+    pll3:st,pll@2 {
+        cfg = < 2 97 3 15 7 5>;
+        frac = < 0x9ba >;
+    };
+    pll4:st,pll@3 {
+        cfg = < 5 124 9 9 9 3>;
+    };
+};
+
+&qspi {
+    pinctrl-names = "default";
+    pinctrl-0 = <&quadspi_pins_mx>;
+    status = "okay";
+};
+
+&rcc {
+    status = "okay";
+};
+
+&sdmmc1 {
+    pinctrl-names = "default";
+    pinctrl-0 = <&sdmmc1_pins_mx>;
+    status = "okay";
+};
+
+&sdmmc2 {
+    pinctrl-names = "default";
+    pinctrl-0 = <&sdmmc2_pins_mx>;
+    status = "okay";
+};
+
+&uart4 {
+    pinctrl-names = "default";
+    pinctrl-0 = <&uart4_pins_mx>;
+    status = "okay";
+};
+
+&usbotg_hs {
+    pinctrl-names = "default";
+    pinctrl-0 = <&usb_otg_hs_pins_mx>;
+    status = "okay";
+};
+
+/* USER CODE BEGIN dts_soc */
+/* USER CODE END dts_soc */
+
diff --git a/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/stm32mp157c-t1000-s-mx.dts b/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/stm32mp157c-t1000-s-mx.dts
index dcc3d27cb9a37beae4c08414bc1de4ff9ee161bb..4c8a819729ffef36d0185f223c1f1d839f0a6a18 100644
--- a/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/stm32mp157c-t1000-s-mx.dts
+++ b/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/stm32mp157c-t1000-s-mx.dts
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
 /*
- * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
+ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved
  * Author: STM32CubeMX code generation for STMicroelectronics.
  */
 
@@ -13,44 +13,42 @@
 #include "stm32mp15-ddr.dtsi"
 #include "stm32mp157c-security.dtsi"
 
-/* USER CODE BEGIN includes */
-/* USER CODE END includes */
+/* USER CODE BEGIN dts_include */
+/* USER CODE END dts_include */
 
 / {
-	model = "STMicroelectronics custom STM32CubeMX board";
+    model = "STMicroelectronics custom STM32CubeMX board";
 	compatible = "st,stm32mp157c-t1000-s-mx", "st,stm32mp157";
 
-	/* USER CODE BEGIN root */
-	/* USER CODE END root */
+	/* USER CODE BEGIN root_prop */
+	/* USER CODE END root_prop */
 
-clocks {
-    /* USER CODE BEGIN clocks */
-    /* USER CODE END clocks */
-
-    clk_lse: clk-lse {
-        /* USER CODE BEGIN clocks */
-        /* USER CODE END clocks */
-        st,drive=<LSEDRV_MEDIUM_HIGH>;
-    };
-    clk_hse: clk-hse {
-        /* USER CODE BEGIN clocks */
-        /* USER CODE END clocks */
+    clocks {
+        clk_lse: clk-lse {
+            st,drive=<LSEDRV_LOWEST>;
+        };
     };
-};
+
+	/* USER CODE BEGIN root_subnodes */
+	/* USER CODE END root_subnodes */
+
+	/* USER CODE BEGIN root_board */
+	/* USER CODE END root_board */
+
+	/* USER CODE BEGIN root_platform */
+	/* USER CODE END root_platform */
 
 }; /*root*/
 
+/* USER CODE BEGIN dts_board */
+/* USER CODE END dts_board */
+
 &pinctrl {
-    quadspi_pins_mx: quadspi_mx-0 {
-        pins1 {
+    quadspi_pins_mx: quadspi_mx@0 {
+        pins {
             pinmux = <STM32_PINMUX('B', 6, AF10)>, /* QUADSPI_BK1_NCS */
-                     <STM32_PINMUX('C', 0, AF10)>; /* QUADSPI_BK2_NCS */
-            bias-pull-up;
-            drive-push-pull;
-            slew-rate = <3>;
-        };
-        pins2 {
-            pinmux = <STM32_PINMUX('E', 7, AF10)>, /* QUADSPI_BK2_IO0 */
+                     <STM32_PINMUX('C', 0, AF10)>, /* QUADSPI_BK2_NCS */
+                     <STM32_PINMUX('E', 7, AF10)>, /* QUADSPI_BK2_IO0 */
                      <STM32_PINMUX('E', 8, AF10)>, /* QUADSPI_BK2_IO1 */
                      <STM32_PINMUX('E', 9, AF10)>, /* QUADSPI_BK2_IO2 */
                      <STM32_PINMUX('E', 10, AF10)>, /* QUADSPI_BK2_IO3 */
@@ -64,43 +62,33 @@ clocks {
             slew-rate = <3>;
         };
     };
-    sdmmc1_pins_mx: sdmmc1_mx-0 {
-        pins1 {
+    sdmmc1_pins_mx: sdmmc1_mx@0 {
+        pins {
             pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
                      <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
                      <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
                      <STM32_PINMUX('C', 11, AF12)>, /* SDMMC1_D3 */
+                     <STM32_PINMUX('C', 12, AF12)>, /* SDMMC1_CK */
                      <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
             bias-pull-up;
             drive-push-pull;
-            slew-rate = <1>;
-        };
-        pins2 {
-            pinmux = <STM32_PINMUX('C', 12, AF12)>; /* SDMMC1_CK */
-            bias-pull-up;
-            drive-push-pull;
             slew-rate = <3>;
         };
     };
-    sdmmc2_pins_mx: sdmmc2_mx-0 {
-        pins1 {
+    sdmmc2_pins_mx: sdmmc2_mx@0 {
+        pins {
             pinmux = <STM32_PINMUX('B', 3, AF9)>, /* SDMMC2_D2 */
                      <STM32_PINMUX('B', 4, AF9)>, /* SDMMC2_D3 */
                      <STM32_PINMUX('B', 14, AF9)>, /* SDMMC2_D0 */
                      <STM32_PINMUX('B', 15, AF9)>, /* SDMMC2_D1 */
+                     <STM32_PINMUX('E', 3, AF9)>, /* SDMMC2_CK */
                      <STM32_PINMUX('G', 6, AF10)>; /* SDMMC2_CMD */
             bias-pull-up;
             drive-push-pull;
-            slew-rate = <1>;
-        };
-        pins2 {
-            pinmux = <STM32_PINMUX('E', 3, AF9)>; /* SDMMC2_CK */
-            bias-pull-up;
-            drive-push-pull;
             slew-rate = <3>;
         };
     };
-    uart4_pins_mx: uart4_mx-0 {
+    uart4_pins_mx: uart4_mx@0 {
         pins1 {
             pinmux = <STM32_PINMUX('G', 11, AF6)>; /* UART4_TX */
             bias-pull-up;
@@ -112,7 +100,7 @@ clocks {
             bias-pull-up;
         };
     };
-    usb_otg_hs_pins_mx: usb_otg_hs_mx-0 {
+    usb_otg_hs_pins_mx: usb_otg_hs_mx@0 {
         pins {
             pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
         };
@@ -120,9 +108,6 @@ clocks {
 };
 
 &rcc {
-    st,hsi-cal;
-    st,csi-cal;
-    st,cal-sec = <60>;
     st,clksrc = <
         CLK_MPU_PLL1P
         CLK_AXI_PLL2P
@@ -143,7 +128,7 @@ clocks {
         1         /*APB3*/
         1         /*APB4*/
         2         /*APB5*/
-        0         /*RTC*/
+        23         /*RTC*/
         0         /*MCO1*/
         0         /*MCO2*/
     >;
@@ -151,11 +136,11 @@ clocks {
         CLK_CKPER_HSE
         CLK_QSPI_ACLK
         CLK_ETH_PLL4P
-        CLK_SDMMC12_PLL4P
+        CLK_SDMMC12_PLL3R
         CLK_STGEN_HSE
         CLK_USBPHY_HSE
         CLK_SPI2S1_DISABLED
-        CLK_SPI2S23_PLL4P
+        CLK_SPI2S23_PLL3Q
         CLK_SPI45_DISABLED
         CLK_SPI6_DISABLED
         CLK_I2C46_HSI
@@ -166,9 +151,9 @@ clocks {
         CLK_I2C12_HSI
         CLK_I2C35_DISABLED
         CLK_UART1_DISABLED
-        CLK_UART24_PCLK1
+        CLK_UART24_HSI
         CLK_UART35_DISABLED
-        CLK_UART6_PCLK2
+        CLK_UART6_HSI
         CLK_UART78_DISABLED
         CLK_SPDIF_DISABLED
         CLK_FDCAN_HSE
@@ -176,162 +161,61 @@ clocks {
         CLK_SAI2_DISABLED
         CLK_SAI3_DISABLED
         CLK_SAI4_DISABLED
-        CLK_RNG1_CSI
         CLK_LPTIM1_DISABLED
         CLK_LPTIM23_DISABLED
         CLK_LPTIM45_DISABLED
     >;
     pll1:st,pll@0 {
-        cfg = < 2 80 0 1 1 1>;
+        cfg = < 2 80 0 0 0 1>;
+        frac = < 0x800 >;
     };
     pll2:st,pll@1 {
-        cfg = < 2 65 1 1 0 7>;
+        cfg = < 2 65 1 0 0 5>;
+        frac = < 0x1400 >;
     };
     pll3:st,pll@2 {
-        cfg = < 2 97 3 1 1 1>;
+        cfg = < 2 97 3 15 7 5>;
+        frac = < 0x9ba >;
     };
     pll4:st,pll@3 {
         cfg = < 5 124 9 9 9 3>;
     };
 };
 
-&bsec{
-    status = "okay";
-    secure-status = "okay";
-
-    /* USER CODE BEGIN bsec */
-    /* USER CODE END bsec */
-};
-
-&etzpc{
-    st,decprot = <
-    /*"Cortex-A7 secure" context*/
-    /*"Cortex-A7 non secure" context*/
-    DECPROT(STM32MP1_ETZPC_ADC_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_OTG_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_CRYP1_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_HASH1_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_VREFBUF_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_ETH_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_TT_FDCAN_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_TIM4_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_TIM1_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_UART4_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_QSPI_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    /*Restriction: STM32MP1_ETZPC_DLYBQ_ID is not managed - please to use User-Section if needed*/
-    DECPROT(STM32MP1_ETZPC_RNG1_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_USART2_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_I2C2_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_I2C4_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_SPI2_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-    DECPROT(STM32MP1_ETZPC_USART6_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-
-    /*Restriction: following IDs are not managed - please to use User-Section if needed:
-     STM32MP1_ETZPC_DMA1_ID, STM32MP1_ETZPC_DMA2_ID, STM32MP1_ETZPC_DMAMUX_ID,
-     STM32MP1_ETZPC_SRAMx_ID, STM32MP1_ETZPC_RETRAM_ID, STM32MP1_ETZPC_BKPSRAM_ID*/
-
-    /* USER CODE BEGIN etzpc_decprot */
-     /*STM32CubeMX generates a basic and standard configuration for ETZPC.
-     Additional device configurations can be added here if needed.
-     "etzpc" node could be also overloaded in "addons" User-Section.*/
-    /* USER CODE END etzpc_decprot */
-    >;
-    secure-status = "okay";
-
-    /* USER CODE BEGIN etzpc */
-    /* USER CODE END etzpc */
-};
-
-&qspi{
+&qspi {
     pinctrl-names = "default";
     pinctrl-0 = <&quadspi_pins_mx>;
     status = "okay";
-
-    /* USER CODE BEGIN qspi */
-    /* USER CODE END qspi */
-};
-
-&rcc{
-    status = "okay";
-    secure-status = "okay";
-
-    /* USER CODE BEGIN rcc */
-    /* USER CODE END rcc */
-};
-
-&rng1{
-    status = "okay";
-    secure-status = "okay";
-
-    /* USER CODE BEGIN rng1 */
-    /* USER CODE END rng1 */
 };
 
-&rtc{
+&rcc {
     status = "okay";
-    secure-status = "okay";
-
-    /* USER CODE BEGIN rtc */
-    /* USER CODE END rtc */
 };
 
-&sdmmc1{
+&sdmmc1 {
     pinctrl-names = "default";
     pinctrl-0 = <&sdmmc1_pins_mx>;
     status = "okay";
-
-    /* USER CODE BEGIN sdmmc1 */
-    /* USER CODE END sdmmc1 */
 };
 
-&sdmmc2{
+&sdmmc2 {
     pinctrl-names = "default";
     pinctrl-0 = <&sdmmc2_pins_mx>;
     status = "okay";
-
-    /* USER CODE BEGIN sdmmc2 */
-    /* USER CODE END sdmmc2 */
 };
 
-&uart4{
+&uart4 {
     pinctrl-names = "default";
     pinctrl-0 = <&uart4_pins_mx>;
     status = "okay";
-
-    /* USER CODE BEGIN uart4 */
-    /* USER CODE END uart4 */
 };
 
-&usbotg_hs{
+&usbotg_hs {
     pinctrl-names = "default";
     pinctrl-0 = <&usb_otg_hs_pins_mx>;
     status = "okay";
-
-    /* USER CODE BEGIN usbotg_hs */
-    /* USER CODE END usbotg_hs */
-};
-
-&usbphyc{
-    status = "okay";
-
-    /* USER CODE BEGIN usbphyc */
-    /* USER CODE END usbphyc */
-};
-
-&usbphyc_port0{
-    status = "okay";
-
-    /* USER CODE BEGIN usbphyc_port0 */
-    /* USER CODE END usbphyc_port0 */
-};
-
-&usbphyc_port1{
-    status = "okay";
-
-    /* USER CODE BEGIN usbphyc_port1 */
-    /* USER CODE END usbphyc_port1 */
 };
 
-/* USER CODE BEGIN addons */
-/* USER CODE END addons */
+/* USER CODE BEGIN dts_soc */
+/* USER CODE END dts_soc */
 
diff --git a/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/stm32mp157c-t1000-som-minimal-mx.dts b/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/stm32mp157c-t1000-som-minimal-mx.dts
deleted file mode 100644
index a78c61cac5bd5c863b37625b99470ca3e630b3dc..0000000000000000000000000000000000000000
--- a/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/stm32mp157c-t1000-som-minimal-mx.dts
+++ /dev/null
@@ -1,335 +0,0 @@
-/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
-/*
- * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
- * Author: STM32CubeMX code generation for STMicroelectronics.
- */
-
-/dts-v1/;
-#include <dt-bindings/clock/stm32mp1-clksrc.h>
-#include "stm32mp15-mx.h"
-
-#include "stm32mp157c.dtsi"
-#include "stm32mp157cad-pinctrl.dtsi"
-#include "stm32mp15-ddr.dtsi"
-#include "stm32mp157c-security.dtsi"
-
-/* USER CODE BEGIN includes */
-/* USER CODE END includes */
-
-/ {
-	model = "STMicroelectronics custom STM32CubeMX board";
-	compatible = "st,stm32mp157c-t1000-som-minimal-mx", "st,stm32mp157";
-
-	/* USER CODE BEGIN root */
-	/* USER CODE END root */
-
-	clocks {
-		/* USER CODE BEGIN clocks */
-		/* USER CODE END clocks */
-
-		clk_lse: clk-lse {
-			/* USER CODE BEGIN clocks */
-			/* USER CODE END clocks */
-			st,drive=<LSEDRV_MEDIUM_HIGH>;
-		};
-
-		clk_hse: clk-hse {
-			/* USER CODE BEGIN clocks */
-			/* USER CODE END clocks */
-		};
-	};
-
-}; /*root*/
-
-&pinctrl {
-	quadspi_pins_mx: quadspi_mx-0 {
-		pins1 {
-			pinmux = <STM32_PINMUX('B', 6, AF10)>, /* QUADSPI_BK1_NCS */
-					 <STM32_PINMUX('C', 0, AF10)>; /* QUADSPI_BK2_NCS */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins2 {
-			pinmux = <STM32_PINMUX('E', 7, AF10)>, /* QUADSPI_BK2_IO0 */
-					 <STM32_PINMUX('E', 8, AF10)>, /* QUADSPI_BK2_IO1 */
-					 <STM32_PINMUX('E', 9, AF10)>, /* QUADSPI_BK2_IO2 */
-					 <STM32_PINMUX('E', 10, AF10)>, /* QUADSPI_BK2_IO3 */
-					 <STM32_PINMUX('F', 6, AF9)>, /* QUADSPI_BK1_IO3 */
-					 <STM32_PINMUX('F', 7, AF9)>, /* QUADSPI_BK1_IO2 */
-					 <STM32_PINMUX('F', 8, AF10)>, /* QUADSPI_BK1_IO0 */
-					 <STM32_PINMUX('F', 9, AF10)>; /* QUADSPI_BK1_IO1 */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins3 {
-			pinmux = <STM32_PINMUX('F', 10, AF9)>; /* QUADSPI_CLK */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <2>;
-		};
-	};
-
-	rtc_pins_mx: rtc_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('C', 13, ANALOG)>; /* RTC_LSCO */
-		};
-	};
-
-	sdmmc1_pins_mx: sdmmc1_mx-0 {
-		pins1 {
-			pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
-					 <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
-					 <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
-					 <STM32_PINMUX('C', 11, AF12)>, /* SDMMC1_D3 */
-					 <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-		pins2 {
-			pinmux = <STM32_PINMUX('C', 12, AF12)>; /* SDMMC1_CK */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-	};
-
-	uart4_pins_mx: uart4_mx-0 {
-		pins1 {
-			pinmux = <STM32_PINMUX('B', 2, AF8)>; /* UART4_RX */
-			bias-pull-up;
-		};
-		pins2 {
-			pinmux = <STM32_PINMUX('G', 11, AF6)>; /* UART4_TX */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-	};
-
-	usb_otg_hs_pins_mx: usb_otg_hs_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
-		};
-	};
-
-	/* USER CODE BEGIN pinctrl */
-	/* USER CODE END pinctrl */
-};
-
-&pinctrl_z {
-	/* USER CODE BEGIN pinctrl_z */
-	/* USER CODE END pinctrl_z */
-};
-
-&rcc {
-	st,csi-cal;
-	st,hsi-cal;
-	st,cal-sec = <60>;
-	st,clksrc = <
-		CLK_MPU_PLL1P
-		CLK_AXI_PLL2P
-		CLK_MCU_PLL3P
-		CLK_PLL12_HSE
-		CLK_PLL3_HSE
-		CLK_PLL4_HSE
-		CLK_RTC_LSE
-		CLK_MCO1_DISABLED
-		CLK_MCO2_DISABLED
-	>;
-	st,clkdiv = <
-		1 		/*MPU*/
-		0 		/*AXI*/
-		0 		/*MCU*/
-		1 		/*APB1*/
-		1 		/*APB2*/
-		1 		/*APB3*/
-		1 		/*APB4*/
-		2 		/*APB5*/
-		0 		/*RTC*/
-		0 		/*MCO1*/
-		0 		/*MCO2*/
-	>;
-	st,pkcs = <
-		CLK_CKPER_HSE
-		CLK_QSPI_ACLK
-		CLK_ETH_PLL4P
-		CLK_SDMMC12_PLL4P
-		CLK_STGEN_HSE
-		CLK_USBPHY_HSE
-		CLK_SPI2S1_DISABLED
-		CLK_SPI2S23_DISABLED
-		CLK_SPI45_DISABLED
-		CLK_SPI6_DISABLED
-		CLK_I2C46_DISABLED
-		CLK_SDMMC3_DISABLED
-		CLK_USBO_USBPHY
-		CLK_ADC_CKPER
-		CLK_CEC_DISABLED
-		CLK_I2C12_HSI
-		CLK_I2C35_DISABLED
-		CLK_UART1_DISABLED
-		CLK_UART24_PCLK1
-		CLK_UART35_DISABLED
-		CLK_UART6_DISABLED
-		CLK_UART78_DISABLED
-		CLK_SPDIF_DISABLED
-		CLK_SAI1_DISABLED
-		CLK_SAI2_DISABLED
-		CLK_SAI3_DISABLED
-		CLK_SAI4_DISABLED
-		CLK_RNG1_CSI
-		CLK_LPTIM1_DISABLED
-		CLK_LPTIM23_DISABLED
-		CLK_LPTIM45_DISABLED
-	>;
-	pll1:st,pll@0 {
-		cfg = < 2 80 0 1 1 1>;
-	};
-	pll2:st,pll@1 {
-		cfg = < 2 65 1 1 0 7>;
-	};
-	pll3:st,pll@2 {
-		cfg = < 1 49 2 2 1 1>;
-	};
-	pll4:st,pll@3 {
-		cfg = < 5 124 9 9 9 1>;
-	};
-};
-
-&bsec{
-	status = "okay";
-	secure-status = "okay";
-
-	/* USER CODE BEGIN bsec */
-	/* USER CODE END bsec */
-};
-
-&etzpc{
-	st,decprot = <
-	/*"Non Secured" peripherals*/
-	DECPROT(STM32MP1_ETZPC_ADC_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-	DECPROT(STM32MP1_ETZPC_CRYP1_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-	DECPROT(STM32MP1_ETZPC_ETH_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-	DECPROT(STM32MP1_ETZPC_HASH1_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-	DECPROT(STM32MP1_ETZPC_I2C2_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-	DECPROT(STM32MP1_ETZPC_QSPI_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-	DECPROT(STM32MP1_ETZPC_DLYBQ_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-	DECPROT(STM32MP1_ETZPC_RNG1_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-	DECPROT(STM32MP1_ETZPC_UART4_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-	DECPROT(STM32MP1_ETZPC_OTG_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-	DECPROT(STM32MP1_ETZPC_VREFBUF_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-
-	/*Restriction: following IDs are not managed  - please to use User-Section if needed:
-		STM32MP1_ETZPC_DMA1_ID, STM32MP1_ETZPC_DMA2_ID, STM32MP1_ETZPC_DMAMUX_ID,
-		STM32MP1_ETZPC_SRAMx_ID, STM32MP1_ETZPC_RETRAM_ID, STM32MP1_ETZPC_BKPSRAM_ID*/
-
-	/* USER CODE BEGIN etzpc_decprot */
-		/*STM32CubeMX generates a basic and standard configuration for ETZPC.
-		Additional device configurations can be added here if needed.
-		"etzpc" node could be also overloaded in "addons" User-Section.*/
-	/* USER CODE END etzpc_decprot */
-	>;
-
-	secure-status = "okay";
-
-	/* USER CODE BEGIN etzpc */
-	/* USER CODE END etzpc */
-};
-
-&iwdg2{
-	status = "okay";
-	secure-status = "okay";
-
-	/* USER CODE BEGIN iwdg2 */
-	/* USER CODE END iwdg2 */
-};
-
-&qspi{
-	pinctrl-names = "default";
-	pinctrl-0 = <&quadspi_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN qspi */
-	/* USER CODE END qspi */
-};
-
-&rcc{
-	status = "okay";
-	secure-status = "okay";
-
-	/* USER CODE BEGIN rcc */
-	/* USER CODE END rcc */
-};
-
-&rng1{
-	status = "okay";
-	secure-status = "okay";
-
-	/* USER CODE BEGIN rng1 */
-	/* USER CODE END rng1 */
-};
-
-&rtc{
-	pinctrl-names = "default";
-	pinctrl-0 = <&rtc_pins_mx>;
-	status = "okay";
-	secure-status = "okay";
-
-	/* USER CODE BEGIN rtc */
-	/* USER CODE END rtc */
-};
-
-&sdmmc1{
-	pinctrl-names = "default";
-	pinctrl-0 = <&sdmmc1_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN sdmmc1 */
-	/* USER CODE END sdmmc1 */
-};
-
-&uart4{
-	pinctrl-names = "default";
-	pinctrl-0 = <&uart4_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN uart4 */
-	/* USER CODE END uart4 */
-};
-
-&usbotg_hs{
-	pinctrl-names = "default";
-	pinctrl-0 = <&usb_otg_hs_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN usbotg_hs */
-	/* USER CODE END usbotg_hs */
-};
-
-&usbphyc{
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc */
-	/* USER CODE END usbphyc */
-};
-
-&usbphyc_port0{
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc_port0 */
-	/* USER CODE END usbphyc_port0 */
-};
-
-&usbphyc_port1{
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc_port1 */
-	/* USER CODE END usbphyc_port1 */
-};
-
-/* USER CODE BEGIN addons */
-/* USER CODE END addons */
-
diff --git a/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/stm32mp157c-t1001-som-minimal-mx.dts b/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/stm32mp157c-t1001-som-minimal-mx.dts
deleted file mode 100644
index 5c8869c43f47275bb2f5601f9d3f7fcc70a6a9f2..0000000000000000000000000000000000000000
--- a/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/stm32mp157c-t1001-som-minimal-mx.dts
+++ /dev/null
@@ -1,316 +0,0 @@
-/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
-/*
- * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
- * Author: STM32CubeMX code generation for STMicroelectronics.
- */
-
-/dts-v1/;
-#include <dt-bindings/clock/stm32mp1-clksrc.h>
-#include "stm32mp15-mx.h"
-
-#include "stm32mp157c.dtsi"
-#include "stm32mp157cad-pinctrl.dtsi"
-#include "stm32mp15-ddr.dtsi"
-#include "stm32mp157c-security.dtsi"
-
-/* USER CODE BEGIN includes */
-/* USER CODE END includes */
-
-/ {
-	model = "STMicroelectronics custom STM32CubeMX board";
-	compatible = "st,stm32mp157c-t1001-som-minimal-mx", "st,stm32mp157";
-
-	/* USER CODE BEGIN root */
-	/* USER CODE END root */
-
-	clocks {
-		/* USER CODE BEGIN clocks */
-		/* USER CODE END clocks */
-
-		clk_lse: clk-lse {
-			/* USER CODE BEGIN clocks */
-			/* USER CODE END clocks */
-			st,drive=<LSEDRV_MEDIUM_HIGH>;
-		};
-
-		clk_hse: clk-hse {
-			/* USER CODE BEGIN clocks */
-			/* USER CODE END clocks */
-		};
-	};
-
-}; /*root*/
-
-&pinctrl {
-	quadspi_pins_mx: quadspi_mx-0 {
-		pins1 {
-			pinmux = <STM32_PINMUX('B', 6, AF10)>; /* QUADSPI_BK1_NCS */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins2 {
-			pinmux = <STM32_PINMUX('F', 6, AF9)>, /* QUADSPI_BK1_IO3 */
-					 <STM32_PINMUX('F', 7, AF9)>, /* QUADSPI_BK1_IO2 */
-					 <STM32_PINMUX('F', 8, AF10)>, /* QUADSPI_BK1_IO0 */
-					 <STM32_PINMUX('F', 9, AF10)>, /* QUADSPI_BK1_IO1 */
-					 <STM32_PINMUX('F', 10, AF9)>; /* QUADSPI_CLK */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-	};
-
-	sdmmc1_pins_mx: sdmmc1_mx-0 {
-		pins1 {
-			pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
-					 <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
-					 <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
-					 <STM32_PINMUX('C', 11, AF12)>, /* SDMMC1_D3 */
-					 <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-		pins2 {
-			pinmux = <STM32_PINMUX('C', 12, AF12)>; /* SDMMC1_CK */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-	};
-
-	uart4_pins_mx: uart4_mx-0 {
-		pins1 {
-			pinmux = <STM32_PINMUX('B', 2, AF8)>; /* UART4_RX */
-			bias-pull-up;
-		};
-		pins2 {
-			pinmux = <STM32_PINMUX('G', 11, AF6)>; /* UART4_TX */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-	};
-
-	usb_otg_hs_pins_mx: usb_otg_hs_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
-		};
-	};
-
-	/* USER CODE BEGIN pinctrl */
-	/* USER CODE END pinctrl */
-};
-
-&pinctrl_z {
-	/* USER CODE BEGIN pinctrl_z */
-	/* USER CODE END pinctrl_z */
-};
-
-&rcc {
-	st,csi-cal;
-	st,hsi-cal;
-	st,cal-sec = <60>;
-	st,clksrc = <
-		CLK_MPU_PLL1P
-		CLK_AXI_PLL2P
-		CLK_MCU_PLL3P
-		CLK_PLL12_HSE
-		CLK_PLL3_HSE
-		CLK_PLL4_HSE
-		CLK_RTC_LSE
-		CLK_MCO1_DISABLED
-		CLK_MCO2_DISABLED
-	>;
-	st,clkdiv = <
-		1 		/*MPU*/
-		0 		/*AXI*/
-		0 		/*MCU*/
-		1 		/*APB1*/
-		1 		/*APB2*/
-		1 		/*APB3*/
-		1 		/*APB4*/
-		2 		/*APB5*/
-		0 		/*RTC*/
-		0 		/*MCO1*/
-		0 		/*MCO2*/
-	>;
-	st,pkcs = <
-		CLK_CKPER_HSE
-		CLK_QSPI_ACLK
-		CLK_ETH_DISABLED
-		CLK_SDMMC12_PLL4P
-		CLK_STGEN_HSE
-		CLK_USBPHY_HSE
-		CLK_SPI2S1_DISABLED
-		CLK_SPI2S23_DISABLED
-		CLK_SPI45_DISABLED
-		CLK_SPI6_DISABLED
-		CLK_I2C46_DISABLED
-		CLK_SDMMC3_DISABLED
-		CLK_USBO_USBPHY
-		CLK_ADC_CKPER
-		CLK_CEC_DISABLED
-		CLK_I2C12_DISABLED
-		CLK_I2C35_DISABLED
-		CLK_UART1_DISABLED
-		CLK_UART24_PCLK1
-		CLK_UART35_DISABLED
-		CLK_UART6_DISABLED
-		CLK_UART78_DISABLED
-		CLK_SPDIF_DISABLED
-		CLK_SAI1_DISABLED
-		CLK_SAI2_DISABLED
-		CLK_SAI3_DISABLED
-		CLK_SAI4_DISABLED
-		CLK_RNG1_CSI
-		CLK_LPTIM1_DISABLED
-		CLK_LPTIM23_DISABLED
-		CLK_LPTIM45_DISABLED
-	>;
-	pll1:st,pll@0 {
-		cfg = < 2 80 0 1 1 1>;
-	};
-	pll2:st,pll@1 {
-		cfg = < 2 65 1 1 0 7>;
-	};
-	pll3:st,pll@2 {
-		cfg = < 1 49 2 2 1 1>;
-	};
-	pll4:st,pll@3 {
-		cfg = < 5 124 9 9 9 1>;
-	};
-};
-
-&bsec{
-	status = "okay";
-	secure-status = "okay";
-
-	/* USER CODE BEGIN bsec */
-	/* USER CODE END bsec */
-};
-
-&etzpc{
-	st,decprot = <
-	/*"Non Secured" peripherals*/
-	DECPROT(STM32MP1_ETZPC_ADC_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-	DECPROT(STM32MP1_ETZPC_CRYP1_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-	DECPROT(STM32MP1_ETZPC_HASH1_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-	DECPROT(STM32MP1_ETZPC_I2C2_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-	DECPROT(STM32MP1_ETZPC_QSPI_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-	DECPROT(STM32MP1_ETZPC_DLYBQ_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-	DECPROT(STM32MP1_ETZPC_RNG1_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-	DECPROT(STM32MP1_ETZPC_UART4_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-	DECPROT(STM32MP1_ETZPC_OTG_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-	DECPROT(STM32MP1_ETZPC_VREFBUF_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
-
-	/*Restriction: following IDs are not managed  - please to use User-Section if needed:
-		STM32MP1_ETZPC_DMA1_ID, STM32MP1_ETZPC_DMA2_ID, STM32MP1_ETZPC_DMAMUX_ID,
-		STM32MP1_ETZPC_SRAMx_ID, STM32MP1_ETZPC_RETRAM_ID, STM32MP1_ETZPC_BKPSRAM_ID*/
-
-	/* USER CODE BEGIN etzpc_decprot */
-		/*STM32CubeMX generates a basic and standard configuration for ETZPC.
-		Additional device configurations can be added here if needed.
-		"etzpc" node could be also overloaded in "addons" User-Section.*/
-	/* USER CODE END etzpc_decprot */
-	>;
-
-	secure-status = "okay";
-
-	/* USER CODE BEGIN etzpc */
-	/* USER CODE END etzpc */
-};
-
-&iwdg2{
-	status = "okay";
-	secure-status = "okay";
-
-	/* USER CODE BEGIN iwdg2 */
-	/* USER CODE END iwdg2 */
-};
-
-&qspi{
-	pinctrl-names = "default";
-	pinctrl-0 = <&quadspi_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN qspi */
-	/* USER CODE END qspi */
-};
-
-&rcc{
-	status = "okay";
-	secure-status = "okay";
-
-	/* USER CODE BEGIN rcc */
-	/* USER CODE END rcc */
-};
-
-&rng1{
-	status = "okay";
-	secure-status = "okay";
-
-	/* USER CODE BEGIN rng1 */
-	/* USER CODE END rng1 */
-};
-
-&rtc{
-	status = "okay";
-	secure-status = "okay";
-
-	/* USER CODE BEGIN rtc */
-	/* USER CODE END rtc */
-};
-
-&sdmmc1{
-	pinctrl-names = "default";
-	pinctrl-0 = <&sdmmc1_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN sdmmc1 */
-	/* USER CODE END sdmmc1 */
-};
-
-&uart4{
-	pinctrl-names = "default";
-	pinctrl-0 = <&uart4_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN uart4 */
-	/* USER CODE END uart4 */
-};
-
-&usbotg_hs{
-	pinctrl-names = "default";
-	pinctrl-0 = <&usb_otg_hs_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN usbotg_hs */
-	/* USER CODE END usbotg_hs */
-};
-
-&usbphyc{
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc */
-	/* USER CODE END usbphyc */
-};
-
-&usbphyc_port0{
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc_port0 */
-	/* USER CODE END usbphyc_port0 */
-};
-
-&usbphyc_port1{
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc_port1 */
-	/* USER CODE END usbphyc_port1 */
-};
-
-/* USER CODE BEGIN addons */
-/* USER CODE END addons */
-
diff --git a/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/stmxceet-mp157-som.dts b/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/stmxceet-mp157-som.dts
new file mode 100644
index 0000000000000000000000000000000000000000..49d1566f9c14697b4dbeb0bd38c1f58b1fcbc857
--- /dev/null
+++ b/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/stmxceet-mp157-som.dts
@@ -0,0 +1,3 @@
+/* dummy file for board indirection */
+/* use a stripped-down version of the complete device tree indicated by _atf */
+#include "stmxceet-mp157-som_atf.dts"
diff --git a/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/stmxceet-mp157-som_atf.dts b/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/stmxceet-mp157-som_atf.dts
new file mode 100644
index 0000000000000000000000000000000000000000..e10abb655272cb4abc817f422856fe085b519946
--- /dev/null
+++ b/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/stmxceet-mp157-som_atf.dts
@@ -0,0 +1,91 @@
+/*
+ * Copyright : STMicroelectronics 2017
+ *
+ * SPDX-License-Identifier:	GPL-2.0+	BSD-3-Clause
+ */
+
+// Include device multiplexing
+#include "stm32mp157c-t1000-mx.dts"
+#include <dt-bindings/reset/stm32mp1-resets.h>
+/ {
+	model = "stmxceet-mp157-som (atf)";
+	compatible = "ex,stmxceet-mp157-som", "st,stm32mp157";
+
+	chosen {
+		bootargs = "earlyprintk console=ttyS3,115200 root=/dev/ram";
+		stdout-path = "serial3:115200n8";
+	};
+
+	aliases {
+		gpio0 = &gpioa;
+		gpio1 = &gpiob;
+		gpio2 = &gpioc;
+		gpio3 = &gpiod;
+		gpio4 = &gpioe;
+		gpio5 = &gpiof;
+		gpio6 = &gpiog;
+		gpio7 = &gpioh;
+		gpio8 = &gpioi;
+		gpio9 = &gpioj;
+		gpio10 = &gpiok;
+		gpio25 = &gpioz;
+	};
+
+	soc {
+		stgen: stgen@5C008000 {
+			compatible = "st,stm32-stgen";
+			reg = <0x5C008000 0x1000>;
+			status = "okay";
+		};
+
+	};
+};
+
+/* Console */
+&uart4 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart4_pins_mx>;
+	resets = <&rcc UART4_R>;
+	status = "okay";
+};
+
+/* sd/mmc interfaces */
+&sdmmc1 {
+	broken-cd;
+	//cd-gpios = <&gpioa 10 GPIO_ACTIVE_HIGH>;
+	st,dirpol;
+	st,negedge;
+	no-1-8-v;
+	bus-width = <4>;
+	status = "okay";
+};
+
+&sdmmc2 {
+	st,dirpol;
+	st,negedge;
+	status = "disabled";
+};
+
+/* From EV1 board */
+&rng1 {
+	status = "okay";
+};
+
+&iwdg2 {
+	instance = <0x2>;
+	timeout-sec = <0x20>;
+	status = "okay";
+};
+
+/* debugging a2 */
+//&qspi {
+//    status = "disabled";
+//};
+
+//&usbotg_hs {
+//    status = "disabled";
+//};
+
+/* For stability of DDR - see issue #19
+ * Issue 19 requires to be commended out */
+///delete-node/ &clk_csi;
diff --git a/recipes-bsp/trusted-firmware-a/tf-a-stm32mp_%.bbappend b/recipes-bsp/trusted-firmware-a/tf-a-stm32mp_%.bbappend
index 9c59f670a8f14718e2f82d8d9dac5e1f6a1c7fd3..01c6f0933ede1b1440bc22a7603e2fca2b32f8d5 100644
--- a/recipes-bsp/trusted-firmware-a/tf-a-stm32mp_%.bbappend
+++ b/recipes-bsp/trusted-firmware-a/tf-a-stm32mp_%.bbappend
@@ -1,47 +1,52 @@
 FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}/fixes-for-B1:"
 
-####################################################################################
-#Set source to stm git and respective URI
-# Version2.0-r2.0
-####################################################################################
-SRC_URI = "git://github.com/STMicroelectronics/arm-trusted-firmware.git;protocol=https;name=tfa;branch=v2.0-stm32mp"
-SRCREV = "69cc28c5a1b877cf67def7f94dece087f3917b1c"
-SRCREV_bleeding = "${AUTOREV}"
-
-SUBDIR_DIR = "git"
-S = "${WORKDIR}/${SUBDIR_DIR}"
+# add fixes integrated in Beta1
+SRC_URI_append += "\
+    file://0001-stm32mp1-flush-data-cache-for-BL33.patch \
+    "
 
 # add patches
 SRC_URI_append += "\
-    file://0001-bsec-added-write-lock-and-shadow-register-update-aft.patch \
+    file://0001-fix-add-missing-definition-for-stm32mp157cad-pinctrl.patch \
+    file://0002-fix-definition-of-CLK_ADC_PLL4Q.patch \
+    file://0003-fix-add-missing-tag-usbotg_hs.patch \
     "
 
 # add common devicetree configuration for boards
 SRC_URI_append += "\
-    file://stm32mp15-mx.h;subdir=${SUBDIR_DIR}/fdts \
-    file://stm32mp157c-t1000-ddr-undef.h;subdir=${SUBDIR_DIR}/fdts \
-    file://stm32mp157c-t1000-ddr3-1x4Gb-1066-binG.h;subdir=${SUBDIR_DIR}/fdts \
-    file://stm32mp-board-minimal.dtsi;subdir=${SUBDIR_DIR}/fdts \
+    file://stm32mp15-mx.h \
+    file://stm32mp157c-t1000-ddr-undef.h;subdir=git/fdts \
+    file://stm32mp157c-t1000-ddr3-1x4Gb-1066-binG.h;subdir=git/fdts \
+    file://stm32mp-som-t1000.dtsi;subdir=git/fdts \
     "
 
-# add som t1000
+# add board default
 SRC_URI_append += "\
-    file://stm32mp-som-t1000.dtsi;subdir=${SUBDIR_DIR}/fdts \
-    file://stm32mp157c-t1000-som-minimal-mx.dts;subdir=${SUBDIR_DIR}/fdts \
-    file://stm32mp-t1000.dts;subdir=${SUBDIR_DIR}/fdts \
-    file://stm32mp-t1000-clkout32k.dts;subdir=${SUBDIR_DIR}/fdts \
+    file://stm32mp157c-t1000-default-mx.dts;subdir=git/fdts \
+    file://stm32mp-t1000-default.dts;subdir=git/fdts \
+    file://stm32mp-board-default.dtsi;subdir=git/fdts \
     "
 
-# add som t1001
+# add board mini
 SRC_URI_append += "\
-    file://stm32mp-som-t1001.dtsi;subdir=${SUBDIR_DIR}/fdts \
-    file://stm32mp157c-t1001-som-minimal-mx.dts;subdir=${SUBDIR_DIR}/fdts \
-    file://stm32mp-t1001.dts;subdir=${SUBDIR_DIR}/fdts \
+    file://stm32mp157c-t1000-mini-mx.dts;subdir=git/fdts \
+    file://stm32mp-t1000-mini.dts;subdir=git/fdts \
+    file://stm32mp-board-mini.dtsi;subdir=git/fdts \
     "
 
 # add board s
 SRC_URI_append += "\
-    file://stm32mp157c-t1000-s-mx.dts;subdir=${SUBDIR_DIR}/fdts \
-    file://stm32mp-t1000-s.dts;subdir=${SUBDIR_DIR}/fdts \
-    file://stm32mp-board-s.dtsi;subdir=${SUBDIR_DIR}/fdts \
+    file://stm32mp157c-t1000-s-mx.dts;subdir=git/fdts \
+    file://stm32mp-t1000-s.dts;subdir=git/fdts \
+    file://stm32mp-board-s.dtsi;subdir=git/fdts \
     "
+
+# add board stmxceet
+SRC_URI_append += "\
+    file://stmxceet-mp157-som.dts;subdir=git/fdts \
+    file://stmxceet-mp157-som_atf.dts;subdir=git/fdts \
+    file://stm32mp157c-t1000-mx.dts;subdir=git/fdts \
+    file://stm32mp15-mx.h;subdir=git/fdts/include \
+    "
+
diff --git a/recipes-bsp/u-boot/fetch_files_workdir.sh b/recipes-bsp/u-boot/fetch_files_workdir.sh
new file mode 100755
index 0000000000000000000000000000000000000000..305a5bc4987358e40058c1013c9e6836d95ea6bb
--- /dev/null
+++ b/recipes-bsp/u-boot/fetch_files_workdir.sh
@@ -0,0 +1,94 @@
+#!/bin/bash
+
+# fetch_files_workdir <DEVTOOL_WORKDIR>
+
+FILELIST="\
+	arch/arm/dts/stmxceet-mp157-som.dts \
+	arch/arm/dts/stmxceet-mp157-som-spl.dts \
+	arch/arm/dts/stmxceet-mp157-som_ddr.h \
+	arch/arm/dts/stmxceet-mp157-som_rcc.dtsi \
+	arch/arm/dts/stmxceet-mp157-som_pinctrl.dtsi \
+	"
+
+red=`tput setaf 1`
+green=`tput setaf 2`
+yellow=`tput setaf 3`
+reset=`tput sgr0`
+
+DEVTOOL_WORKDIR=${1}
+COMMAND=${2}
+
+print_usage ()
+{
+	echo "fetch_files_workdir <DEVTOOL_WORKDIR> [diff]"
+}
+
+echo "$1"
+if test -z "${DEVTOOL_WORKDIR}"; then
+	print_usage
+	echo -n $red
+	echo "ERROR: No workdir on commandline"
+	echo -n $reset
+	exit 1
+fi
+if test ! -d "${DEVTOOL_WORKDIR}"; then
+	echo -n $red
+	echo "ERROR: Workdir <${DEVTOOL_WORKDIR}> doesn't exist"
+	echo -n $reset
+	exit 1
+fi
+
+# COMMAND configuration
+if test ! -z "${COMMAND}"; then
+	echo "Command: ${COMMAND}"
+fi
+do_onlydiff="no"
+if test "${COMMAND}" == "diff"; then
+	do_onlydiff="yes"
+fi
+
+for wdfile in ${FILELIST}; do
+	file_differ="no"
+	filename=$(basename $wdfile)
+	if test ! -e u-boot-stm32mp/${filename}; then
+		echo -n $yellow
+		echo "new      : $filename"
+		echo -n $reset
+		file_differ="yes"
+	else
+		cmp -s ${DEVTOOL_WORKDIR}/${wdfile} u-boot-stm32mp/${filename}
+		if test $? != 0; then
+			echo -n $red
+			echo "differ   : $filename"
+			echo -n $reset
+			file_differ="yes"
+		else
+			echo -n $green
+			echo "unchanged: $filename"
+			echo -n $reset
+		fi
+	fi
+	
+	if test ${file_differ} = "yes" -a ${do_onlydiff} != "yes" ; then
+	
+		echo "Show differences [Y/n]?"
+		read show_diff
+		if test -z "${show_diff}"; then
+			show_diff="Y"
+		fi
+		if test "${show_diff}" == "Y" -o ${show_diff} == "y"; then
+			meld ${DEVTOOL_WORKDIR}/${wdfile} u-boot-stm32mp/${filename}
+		fi
+				
+		echo "Copy files [y/N]?"
+		read copy_files
+		if test -z "${copy_files}"; then
+			copy_files="N"
+		fi
+		if test "${copy_files}" == "y" -o "${copy_files}" == "y"; then
+			cp ${DEVTOOL_WORKDIR}/${wdfile} u-boot-stm32mp/${filename}
+		fi
+	fi
+
+done
+
diff --git a/recipes-bsp/u-boot/u-boot-basic-stm32mp_2018.03.bbappend b/recipes-bsp/u-boot/u-boot-basic-stm32mp_2018.03.bbappend
new file mode 100644
index 0000000000000000000000000000000000000000..2db6ba68655144ff92ea05d03366ff4ebc16ec5a
--- /dev/null
+++ b/recipes-bsp/u-boot/u-boot-basic-stm32mp_2018.03.bbappend
@@ -0,0 +1,5 @@
+FILESEXTRAPATHS_prepend := "${THISDIR}/u-boot-stm32mp:"
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
+
+require u-boot-stmxceet-common_${PV}.inc
+
diff --git a/recipes-bsp/u-boot/u-boot-fw-utils_%.bbappend b/recipes-bsp/u-boot/u-boot-fw-utils_%.bbappend
index e7543821ca3ef6412ef1d05f79d8c3c7773554ff..09850ec42262577b5adbfd22f068fbc6afc59464 100644
--- a/recipes-bsp/u-boot/u-boot-fw-utils_%.bbappend
+++ b/recipes-bsp/u-boot/u-boot-fw-utils_%.bbappend
@@ -1,7 +1,7 @@
 FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
 
 # Build fw-utils for any default machine
-# Be aware! The default environment doesn't fit to stm32mp1-t1000
+# Be aware! The default environment doesn't fit to stmxceet 
 UBOOT_CONFIG_pn-u-boot-fw-utils = "fw-utils"
 UBOOT_CONFIG[fw-utils] = "spear300_defconfig"
 
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/0001-Fix-timeout-overflow-issue-of-the-stm32mp-watchdog-d.patch b/recipes-bsp/u-boot/u-boot-stm32mp/0001-Fix-timeout-overflow-issue-of-the-stm32mp-watchdog-d.patch
deleted file mode 100644
index 915c8db01325f285d045652b901ce5ddbe2b8e0d..0000000000000000000000000000000000000000
--- a/recipes-bsp/u-boot/u-boot-stm32mp/0001-Fix-timeout-overflow-issue-of-the-stm32mp-watchdog-d.patch
+++ /dev/null
@@ -1,27 +0,0 @@
-From 494409d243bb6783f57f229686139738e2718392 Mon Sep 17 00:00:00 2001
-From: Igor Oblakov <ioblakov@dev.rtsoft.ru>
-Date: Fri, 10 Jul 2020 12:08:58 +0300
-Subject: [PATCH] Fix timeout overflow issue of the stm32mp watchdog driver in
- u-boot
-
-Signed-off-by: Konstantin Kholopov <kkholopov@dev.rtsoft.ru>
----
- drivers/watchdog/stm32mp_wdt.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/drivers/watchdog/stm32mp_wdt.c b/drivers/watchdog/stm32mp_wdt.c
-index ea85e41dae..c22d5caffc 100644
---- a/drivers/watchdog/stm32mp_wdt.c
-+++ b/drivers/watchdog/stm32mp_wdt.c
-@@ -57,7 +57,7 @@ static int stm32mp_wdt_start(struct udevice *dev, u64 timeout, ulong flags)
- 	int ret;
- 
- 	/* Prescaler fixed to 256 */
--	reload = (priv->timeout * 1000) * priv->wdt_clk_rate / 256;
-+	reload = (priv->timeout) * priv->wdt_clk_rate / 256;
- 	if (reload > RLR_MAX + 1)
- 		/* Force to max watchdog counter reload value */
- 		reload = RLR_MAX + 1;
--- 
-2.17.1
-
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/0001-added-t1000-Kconfig.patch b/recipes-bsp/u-boot/u-boot-stm32mp/0001-added-t1000-Kconfig.patch
deleted file mode 100644
index cb5cebb260401d399026c73303711ea3e0d3ebbd..0000000000000000000000000000000000000000
--- a/recipes-bsp/u-boot/u-boot-stm32mp/0001-added-t1000-Kconfig.patch
+++ /dev/null
@@ -1,112 +0,0 @@
-From 4fbe7c3fd9dd6b160c863fa503e40fe7e826ef69 Mon Sep 17 00:00:00 2001
-From: Philipp Beck <Philipp.Beck@exceet.de>
-Date: Tue, 8 Oct 2019 15:35:09 +0200
-Subject: [PATCH] added t1000 Kconfig
-
----
- arch/arm/mach-stm32mp/Kconfig        | 35 ++++++++++++++++++++++++----
- board/kontron/stm32mp1-t1000/Kconfig | 19 +++++++++++++++
- 2 files changed, 50 insertions(+), 4 deletions(-)
- create mode 100644 board/kontron/stm32mp1-t1000/Kconfig
-
-diff --git a/arch/arm/mach-stm32mp/Kconfig b/arch/arm/mach-stm32mp/Kconfig
-index 470b51ff19..04e72ad986 100644
---- a/arch/arm/mach-stm32mp/Kconfig
-+++ b/arch/arm/mach-stm32mp/Kconfig
-@@ -27,6 +27,29 @@ config SPL
- config SYS_SOC
- 	default "stm32mp"
- 
-+choice
-+	prompt "STM32MP1 based boards"
-+	optional
-+
-+config TARGET_STM32MP1_T1000
-+	bool "Kontron stm32mp1 t1000 som"
-+	select ARCH_SUPPORT_PSCI if !STM32MP1_TRUSTED
-+	select CPU_V7A
-+	select CPU_V7_HAS_NONSEC if !STM32MP1_TRUSTED
-+	select CPU_V7_HAS_VIRT
-+	select OF_BOARD_SETUP
-+	select PINCTRL_STM32
-+	select STM32_RCC
-+	select STM32_RESET
-+	select STM32_SERIAL
-+	imply BOOTCOUNT_LIMIT
-+	imply SYSRESET_PSCI if STM32MP1_TRUSTED
-+	imply SYSRESET_SYSCON if !STM32MP1_TRUSTED
-+	help
-+		Kontron SOM with STM32MP1 SOC family
-+
-+source "board/kontron/stm32mp1-t1000/Kconfig"
-+
- config TARGET_STM32MP1
- 	bool "Support stm32mp1xx"
- 	select ARCH_SUPPORT_PSCI if !STM32MP1_TRUSTED
-@@ -45,9 +68,11 @@ config TARGET_STM32MP1
- 	imply SYSRESET_SYSCON if !STM32MP1_TRUSTED
- 	help
- 		target STMicroelectronics SOC STM32MP1 family
--		STM32MP157, STM32MP153 or STM32MP151
-+		STM32MP153 or STM32MP151
- 		STMicroelectronics MPU with core ARMv7
--		dual core A7 for STM32MP157/3, monocore for STM32MP151
-+		dual core A7 for STM32MP153, monocore for STM32MP151
-+
-+endchoice
- 
- config STM32MP1_RESET_HALT_WORKAROUND
- 	bool "workaround for reset halt debug on stm32mp15x"
-@@ -83,7 +108,7 @@ config STM32MP1_OPTEE
- 
- config SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION_MMC2
- 	hex "Partition to use for MMC2 to load U-Boot from"
--	depends on SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION && TARGET_STM32MP1
-+	depends on SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION && (TARGET_STM32MP1 || TARGET_STM32MP1_T1000)
- 	default 1
- 	help
- 	  Partition on the MMC2 to load U-Boot from when the MMC2 is being
-@@ -91,12 +116,14 @@ config SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION_MMC2
- 
- config STM32_ETZPC
- 	bool "STM32 Extended TrustZone Protection"
--	depends on TARGET_STM32MP1
-+	depends on (TARGET_STM32MP1 || TARGET_STM32MP1_T1000)
- 	default y
- 	help
- 	  Say y to enable STM32 Extended TrustZone Protection
- 	  Controller (ETZPC)
- 
-+source "board/st/stm32mp1/Kconfig"
-+
- config CMD_STM32PROG
- 	bool "command stm32prog for STM32CudeProgrammer"
- 	default y
-diff --git a/board/kontron/stm32mp1-t1000/Kconfig b/board/kontron/stm32mp1-t1000/Kconfig
-new file mode 100644
-index 0000000000..00f6659819
---- /dev/null
-+++ b/board/kontron/stm32mp1-t1000/Kconfig
-@@ -0,0 +1,19 @@
-+if TARGET_STM32MP1_T1000
-+
-+config SYS_BOARD
-+	default "stm32mp1-t1000"
-+
-+config SYS_VENDOR
-+	default "kontron"
-+
-+config SYS_CONFIG_NAME
-+	default "stm32mp1-t1000"
-+
-+config CMD_STBOARD
-+	bool "stboard - command for OTP board information"
-+	default y
-+	help
-+	  This compile the stboard command to
-+	  read and write the board in the OTP.
-+
-+endif
--- 
-2.17.1
-
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/0002-extend-extlinux-for-multiple-boards.patch b/recipes-bsp/u-boot/u-boot-stm32mp/0001-extend-extlinux-for-multiple-boards.patch
similarity index 82%
rename from recipes-bsp/u-boot/u-boot-stm32mp/0002-extend-extlinux-for-multiple-boards.patch
rename to recipes-bsp/u-boot/u-boot-stm32mp/0001-extend-extlinux-for-multiple-boards.patch
index 389edf567008f548b95d25f0c2a8e98ecc5692d8..43834d5a9bd363309935c51bf14b802c52fe40bb 100644
--- a/recipes-bsp/u-boot/u-boot-stm32mp/0002-extend-extlinux-for-multiple-boards.patch
+++ b/recipes-bsp/u-boot/u-boot-stm32mp/0001-extend-extlinux-for-multiple-boards.patch
@@ -1,17 +1,17 @@
-From 54c16204defd38132f033a414e3361ef4af20fb7 Mon Sep 17 00:00:00 2001
+From 3d368b3a899c33ccedf7023c42f50ee431949553 Mon Sep 17 00:00:00 2001
 From: Eberhard Stoll <eberhard.stoll@kontron.de>
 Date: Mon, 12 Nov 2018 17:54:59 +0100
-Subject: [PATCH 2/5] extend extlinux for multiple boards
+Subject: [PATCH] extend extlinux for multiple boards
 
 ---
  include/config_distro_bootcmd.h | 1 +
  1 file changed, 1 insertion(+)
 
 diff --git a/include/config_distro_bootcmd.h b/include/config_distro_bootcmd.h
-index 373fee7..0a21eb3 100644
+index f567ceb..f52b9e0 100644
 --- a/include/config_distro_bootcmd.h
 +++ b/include/config_distro_bootcmd.h
-@@ -388,6 +388,7 @@
+@@ -374,6 +374,7 @@
  	"scan_dev_for_boot="                                              \
  		"echo Scanning ${devtype} "                               \
  				"${devnum}:${distro_bootpart}...; "       \
@@ -19,6 +19,6 @@ index 373fee7..0a21eb3 100644
  		"for prefix in ${boot_prefixes}; do "                     \
  			"run scan_dev_for_extlinux; "                     \
  			"run scan_dev_for_scripts; "                      \
---
+-- 
 2.7.4
 
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/0001-fix-missing-eth-phy-clocks.patch b/recipes-bsp/u-boot/u-boot-stm32mp/0001-fix-missing-eth-phy-clocks.patch
deleted file mode 100644
index 234dc57688a4b64871b86aab0513345384937045..0000000000000000000000000000000000000000
--- a/recipes-bsp/u-boot/u-boot-stm32mp/0001-fix-missing-eth-phy-clocks.patch
+++ /dev/null
@@ -1,32 +0,0 @@
-From b08a524b25643cd6a58472b10de0f8b71180f245 Mon Sep 17 00:00:00 2001
-From: Eberhard Stoll <eberhard.stoll@kontron.de>
-Date: Fri, 29 Mar 2019 15:29:25 +0100
-Subject: [PATCH] fix missing eth phy clocks
-
----
- arch/arm/dts/stm32mp157c.dtsi | 6 ++++--
- 1 file changed, 4 insertions(+), 2 deletions(-)
-
-diff --git a/arch/arm/dts/stm32mp157c.dtsi b/arch/arm/dts/stm32mp157c.dtsi
-index 4de499e..8a52d9a 100644
---- a/arch/arm/dts/stm32mp157c.dtsi
-+++ b/arch/arm/dts/stm32mp157c.dtsi
-@@ -1735,11 +1735,13 @@
- 			clock-names = "stmmaceth",
- 				      "mac-clk-tx",
- 				      "mac-clk-rx",
--				      "ethstp";
-+				      "ethstp",
-+				      "eth-ck";
- 			clocks = <&rcc ETHMAC>,
- 				 <&rcc ETHTX>,
- 				 <&rcc ETHRX>,
--				 <&rcc ETHSTP>;
-+				 <&rcc ETHSTP>,
-+				 <&rcc ETHCK>;
- 			st,syscon = <&syscfg 0x4>;
- 			snps,mixed-burst;
- 			snps,pbl = <2>;
--- 
-2.7.4
-
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/0001-qspi-nand-support-added-stm32_qpsi-driver-changes-to.patch b/recipes-bsp/u-boot/u-boot-stm32mp/0001-qspi-nand-support-added-stm32_qpsi-driver-changes-to.patch
deleted file mode 100644
index 90b82d797ad8425c8ac72ffcd8293e3a0901e4be..0000000000000000000000000000000000000000
--- a/recipes-bsp/u-boot/u-boot-stm32mp/0001-qspi-nand-support-added-stm32_qpsi-driver-changes-to.patch
+++ /dev/null
@@ -1,14090 +0,0 @@
-From dd62a7331f2a525493a6e9e2fa2c1462a1689768 Mon Sep 17 00:00:00 2001
-From: pibeck <philipp.beck@exceet.de>
-Date: Thu, 9 May 2019 09:58:20 +0200
-Subject: [PATCH 1/2] qspi nand support added / stm32_qpsi driver changes /
- toshiba nand_driver added
-
----
- drivers/mtd/mtd_uboot.c                       |  185 +-
- drivers/mtd/mtdcore.c                         |   29 +-
- drivers/mtd/mtdpart.c                         |   12 +
- drivers/mtd/nand/raw/Kconfig                  |  106 +-
- drivers/mtd/nand/raw/Makefile                 |    1 +
- drivers/mtd/nand/raw/arasan_nfc.c             |   31 +-
- drivers/mtd/nand/raw/brcmnand/Makefile        |    7 +
- drivers/mtd/nand/raw/brcmnand/bcm63158_nand.c |  123 +
- drivers/mtd/nand/raw/brcmnand/bcm6838_nand.c  |  122 +
- drivers/mtd/nand/raw/brcmnand/bcm6858_nand.c  |  123 +
- drivers/mtd/nand/raw/brcmnand/brcmnand.c      | 2805 +++++++++++++++++
- drivers/mtd/nand/raw/brcmnand/brcmnand.h      |   63 +
- .../mtd/nand/raw/brcmnand/brcmnand_compat.c   |   66 +
- .../mtd/nand/raw/brcmnand/brcmnand_compat.h   |   15 +
- drivers/mtd/nand/raw/davinci_nand.c           |   39 -
- drivers/mtd/nand/raw/denali.c                 |   53 +-
- drivers/mtd/nand/raw/denali.h                 |    3 +
- drivers/mtd/nand/raw/denali_dt.c              |   55 +-
- drivers/mtd/nand/raw/lpc32xx_nand_mlc.c       |    4 +
- drivers/mtd/nand/raw/lpc32xx_nand_slc.c       |   78 +-
- drivers/mtd/nand/raw/mxs_nand.c               |   11 +-
- drivers/mtd/nand/raw/mxs_nand_spl.c           |   19 +-
- drivers/mtd/nand/raw/nand_base.c              | 1017 +++++-
- drivers/mtd/nand/raw/nand_ids.c               |    8 +-
- drivers/mtd/nand/raw/pxa3xx_nand.c            |  143 +-
- drivers/mtd/nand/raw/stm32_fmc2_nand.c        |  246 +-
- drivers/mtd/nand/raw/vf610_nfc.c              |   49 +-
- drivers/mtd/nand/spi/Makefile                 |    2 +-
- drivers/mtd/nand/spi/core.c                   |    3 +
- drivers/mtd/nand/spi/gigadevice.c             |   79 +-
- drivers/mtd/nand/spi/toshiba.c                |  190 ++
- drivers/mtd/spi/Kconfig                       |   58 +-
- drivers/mtd/spi/Makefile                      |   12 +-
- drivers/mtd/spi/sandbox.c                     |   46 +-
- drivers/mtd/spi/sf-uclass.c                   |    9 +
- drivers/mtd/spi/sf_dataflash.c                |   11 +-
- drivers/mtd/spi/sf_internal.h                 |  226 +-
- drivers/mtd/spi/sf_mtd.c                      |   48 +-
- drivers/mtd/spi/sf_probe.c                    |   49 +-
- drivers/mtd/spi/spi-nor-core.c                | 2401 ++++++++++++++
- drivers/mtd/spi/spi-nor-ids.c                 |  305 ++
- drivers/mtd/spi/spi-nor-tiny.c                |  804 +++++
- drivers/mtd/spi/spi_flash.c                   | 1334 --------
- drivers/mtd/spi/spi_flash_ids.c               |  213 --
- drivers/mtd/ubi/debug.h                       |   10 +
- include/linux/mtd/cfi.h                       |   32 +
- include/linux/mtd/mtd.h                       |   20 +-
- include/linux/mtd/rawnand.h                   |   49 +
- include/linux/mtd/spi-nor.h                   |  419 +++
- include/linux/mtd/spinand.h                   |    1 +
- include/spi_flash.h                           |  149 +-
- 51 files changed, 9464 insertions(+), 2419 deletions(-)
- create mode 100644 drivers/mtd/nand/raw/brcmnand/Makefile
- create mode 100644 drivers/mtd/nand/raw/brcmnand/bcm63158_nand.c
- create mode 100644 drivers/mtd/nand/raw/brcmnand/bcm6838_nand.c
- create mode 100644 drivers/mtd/nand/raw/brcmnand/bcm6858_nand.c
- create mode 100644 drivers/mtd/nand/raw/brcmnand/brcmnand.c
- create mode 100644 drivers/mtd/nand/raw/brcmnand/brcmnand.h
- create mode 100644 drivers/mtd/nand/raw/brcmnand/brcmnand_compat.c
- create mode 100644 drivers/mtd/nand/raw/brcmnand/brcmnand_compat.h
- create mode 100644 drivers/mtd/nand/spi/toshiba.c
- create mode 100644 drivers/mtd/spi/spi-nor-core.c
- create mode 100644 drivers/mtd/spi/spi-nor-ids.c
- create mode 100644 drivers/mtd/spi/spi-nor-tiny.c
- delete mode 100644 drivers/mtd/spi/spi_flash.c
- delete mode 100644 drivers/mtd/spi/spi_flash_ids.c
- create mode 100644 include/linux/mtd/cfi.h
- create mode 100644 include/linux/mtd/spi-nor.h
-
-diff --git a/drivers/mtd/mtd_uboot.c b/drivers/mtd/mtd_uboot.c
-index 6c11810b94..0a41ed477c 100644
---- a/drivers/mtd/mtd_uboot.c
-+++ b/drivers/mtd/mtd_uboot.c
-@@ -13,6 +13,29 @@
- 
- #define MTD_NAME_MAX_LEN 20
- 
-+void board_mtdparts_default(const char **mtdids, const char **mtdparts);
-+
-+static const char *get_mtdids(void)
-+{
-+	__maybe_unused const char *mtdparts = NULL;
-+	const char *mtdids = env_get("mtdids");
-+
-+	if (mtdids)
-+		return mtdids;
-+
-+#if defined(CONFIG_SYS_MTDPARTS_RUNTIME)
-+	board_mtdparts_default(&mtdids, &mtdparts);
-+#elif defined(MTDIDS_DEFAULT)
-+	mtdids = MTDIDS_DEFAULT;
-+#elif defined(CONFIG_MTDIDS_DEFAULT)
-+	mtdids = CONFIG_MTDIDS_DEFAULT;
-+#endif
-+
-+	if (mtdids)
-+		env_set("mtdids", mtdids);
-+
-+	return mtdids;
-+}
- 
- /**
-  * mtd_search_alternate_name - Search an alternate name for @mtdname thanks to
-@@ -34,7 +57,7 @@ int mtd_search_alternate_name(const char *mtdname, char *altname,
- 	const char *mtdids, *equal, *comma, *dev_id, *mtd_id;
- 	int dev_id_len, mtd_id_len;
- 
--	mtdids = env_get("mtdids");
-+	mtdids = get_mtdids();
- 	if (!mtdids)
- 		return -EINVAL;
- 
-@@ -92,30 +115,6 @@ static void mtd_probe_uclass_mtd_devs(void) { }
- #endif
- 
- #if defined(CONFIG_MTD_PARTITIONS)
--extern void board_mtdparts_default(const char **mtdids,
--				   const char **mtdparts);
--
--static const char *get_mtdids(void)
--{
--	__maybe_unused const char *mtdparts = NULL;
--	const char *mtdids = env_get("mtdids");
--
--	if (mtdids)
--		return mtdids;
--
--#if defined(CONFIG_SYS_MTDPARTS_RUNTIME)
--	board_mtdparts_default(&mtdids, &mtdparts);
--#elif defined(MTDIDS_DEFAULT)
--	mtdids = MTDIDS_DEFAULT;
--#elif defined(CONFIG_MTDIDS_DEFAULT)
--	mtdids = CONFIG_MTDIDS_DEFAULT;
--#endif
--
--	if (mtdids)
--		env_set("mtdids", mtdids);
--
--	return mtdids;
--}
- 
- #define MTDPARTS_MAXLEN         512
- 
-@@ -147,20 +146,74 @@ static const char *get_mtdparts(void)
- 	return mtdparts;
- }
- 
-+static int mtd_del_parts(struct mtd_info *mtd, bool quiet)
-+{
-+	int ret;
-+
-+	if (!mtd_has_partitions(mtd))
-+		return 0;
-+
-+	/* do not delete partitions if they are in use. */
-+	if (mtd_partitions_used(mtd)) {
-+		if (!quiet)
-+			printf("\"%s\" partitions still in use, can't delete them\n",
-+			       mtd->name);
-+		return -EACCES;
-+	}
-+
-+	ret = del_mtd_partitions(mtd);
-+	if (ret)
-+		return ret;
-+
-+	return 1;
-+}
-+
-+static bool mtd_del_all_parts_failed;
-+
-+static void mtd_del_all_parts(void)
-+{
-+	struct mtd_info *mtd;
-+	int ret = 0;
-+
-+	mtd_del_all_parts_failed = false;
-+
-+	/*
-+	 * It is not safe to remove entries from the mtd_for_each_device loop
-+	 * as it uses idr indexes and the partitions removal is done in bulk
-+	 * (all partitions of one device at the same time), so break and
-+	 * iterate from start each time a new partition is found and deleted.
-+	 */
-+	do {
-+		mtd_for_each_device(mtd) {
-+			ret = mtd_del_parts(mtd, false);
-+			if (ret > 0)
-+				break;
-+			else if (ret < 0)
-+				mtd_del_all_parts_failed = true;
-+		}
-+	} while (ret > 0);
-+}
-+
- int mtd_probe_devices(void)
- {
- 	static char *old_mtdparts;
- 	static char *old_mtdids;
- 	const char *mtdparts = get_mtdparts();
- 	const char *mtdids = get_mtdids();
--	bool remaining_partitions = true;
-+	const char *mtdparts_next = mtdparts;
- 	struct mtd_info *mtd;
- 
- 	mtd_probe_uclass_mtd_devs();
- 
--	/* Check if mtdparts/mtdids changed since last call, otherwise: exit */
-+	/*
-+	 * Check if mtdparts/mtdids changed, if the MTD dev list was updated
-+	 * or if our previous attempt to delete existing partititions failed.
-+	 * In any of these cases we want to update the partitions, otherwise,
-+	 * everything is up-to-date and we can return 0 directly.
-+	 */
- 	if ((!mtdparts && !old_mtdparts && !mtdids && !old_mtdids) ||
- 	    (mtdparts && old_mtdparts && mtdids && old_mtdids &&
-+	     !mtd_dev_list_updated() && !mtd_del_all_parts_failed &&
- 	     !strcmp(mtdparts, old_mtdparts) &&
- 	     !strcmp(mtdids, old_mtdids)))
- 		return 0;
-@@ -171,55 +224,55 @@ int mtd_probe_devices(void)
- 	old_mtdparts = strdup(mtdparts);
- 	old_mtdids = strdup(mtdids);
- 
--	/* If at least one partition is still in use, do not delete anything */
--	mtd_for_each_device(mtd) {
--		if (mtd->usecount) {
--			printf("Partition \"%s\" already in use, aborting\n",
--			       mtd->name);
--			return -EACCES;
--		}
--	}
-+	/*
-+	 * Remove all old parts. Note that partition removal can fail in case
-+	 * one of the partition is still being used by an MTD user, so this
-+	 * does not guarantee that all old partitions are gone.
-+	 */
-+	mtd_del_all_parts();
- 
- 	/*
--	 * Everything looks clear, remove all partitions. It is not safe to
--	 * remove entries from the mtd_for_each_device loop as it uses idr
--	 * indexes and the partitions removal is done in bulk (all partitions of
--	 * one device at the same time), so break and iterate from start each
--	 * time a new partition is found and deleted.
-+	 * Call mtd_dev_list_updated() to clear updates generated by our own
-+	 * parts removal loop.
- 	 */
--	while (remaining_partitions) {
--		remaining_partitions = false;
--		mtd_for_each_device(mtd) {
--			if (!mtd_is_partition(mtd) && mtd_has_partitions(mtd)) {
--				del_mtd_partitions(mtd);
--				remaining_partitions = true;
--				break;
--			}
--		}
--	}
-+	mtd_dev_list_updated();
- 
- 	/* If either mtdparts or mtdids is empty, then exit */
- 	if (!mtdparts || !mtdids)
- 		return 0;
- 
- 	/* Start the parsing by ignoring the extra 'mtdparts=' prefix, if any */
--	if (strstr(mtdparts, "mtdparts="))
-+	if (!strncmp(mtdparts, "mtdparts=", sizeof("mtdparts=") - 1))
- 		mtdparts += 9;
- 
- 	/* For each MTD device in mtdparts */
--	while (mtdparts[0] != '\0') {
-+	for (; mtdparts[0] != '\0'; mtdparts = mtdparts_next) {
- 		char mtd_name[MTD_NAME_MAX_LEN], *colon;
- 		struct mtd_partition *parts;
--		int mtd_name_len, nparts;
--		int ret;
-+		unsigned int mtd_name_len;
-+		int nparts, ret;
-+
-+		mtdparts_next = strchr(mtdparts, ';');
-+		if (!mtdparts_next)
-+			mtdparts_next = mtdparts + strlen(mtdparts);
-+		else
-+			mtdparts_next++;
- 
- 		colon = strchr(mtdparts, ':');
-+		if (colon > mtdparts_next)
-+			colon = NULL;
-+
- 		if (!colon) {
- 			printf("Wrong mtdparts: %s\n", mtdparts);
- 			return -EINVAL;
- 		}
- 
--		mtd_name_len = colon - mtdparts;
-+		mtd_name_len = (unsigned int)(colon - mtdparts);
-+		if (mtd_name_len + 1 > sizeof(mtd_name)) {
-+			printf("MTD name too long: %s\n", mtdparts);
-+			return -EINVAL;
-+		}
-+
- 		strncpy(mtd_name, mtdparts, mtd_name_len);
- 		mtd_name[mtd_name_len] = '\0';
- 		/* Move the pointer forward (including the ':') */
-@@ -246,14 +299,22 @@ int mtd_probe_devices(void)
- 			if (ret || IS_ERR_OR_NULL(mtd)) {
- 				printf("Could not find a valid device for %s\n",
- 				       mtd_name);
--				mtdparts = strchr(mtdparts, ';');
--				if (mtdparts)
--					mtdparts++;
--
-+				mtdparts = mtdparts_next;
- 				continue;
- 			}
- 		}
- 
-+		/*
-+		 * Call mtd_del_parts() again, even if it's already been called
-+		 * in mtd_del_all_parts(). We need to know if old partitions are
-+		 * still around (because they are still being used by someone),
-+		 * and if they are, we shouldn't create new partitions, so just
-+		 * skip this MTD device and try the next one.
-+		 */
-+		ret = mtd_del_parts(mtd, true);
-+		if (ret < 0)
-+			continue;
-+
- 		/*
- 		 * Parse the MTD device partitions. It will update the mtdparts
- 		 * pointer, create an array of parts (that must be freed), and
-@@ -278,6 +339,12 @@ int mtd_probe_devices(void)
- 		put_mtd_device(mtd);
- 	}
- 
-+	/*
-+	 * Call mtd_dev_list_updated() to clear updates generated by our own
-+	 * parts registration loop.
-+	 */
-+	mtd_dev_list_updated();
-+
- 	return 0;
- }
- #else
-diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
-index fb6c779abb..89ac8229f5 100644
---- a/drivers/mtd/mtdcore.c
-+++ b/drivers/mtd/mtdcore.c
-@@ -87,14 +87,17 @@ struct idr_layer {
- 
- struct idr {
- 	struct idr_layer id[MAX_IDR_ID];
-+	bool updated;
- };
- 
- #define DEFINE_IDR(name)	struct idr name;
- 
- void idr_remove(struct idr *idp, int id)
- {
--	if (idp->id[id].used)
-+	if (idp->id[id].used) {
- 		idp->id[id].used = 0;
-+		idp->updated = true;
-+	}
- 
- 	return;
- }
-@@ -134,6 +137,7 @@ int idr_alloc(struct idr *idp, void *ptr, int start, int end, gfp_t gfp_mask)
- 		if (idl->used == 0) {
- 			idl->used = 1;
- 			idl->ptr = ptr;
-+			idp->updated = true;
- 			return i;
- 		}
- 		i++;
-@@ -155,6 +159,16 @@ struct mtd_info *__mtd_next_device(int i)
- }
- EXPORT_SYMBOL_GPL(__mtd_next_device);
- 
-+bool mtd_dev_list_updated(void)
-+{
-+	if (mtd_idr.updated) {
-+		mtd_idr.updated = false;
-+		return true;
-+	}
-+
-+	return false;
-+}
-+
- #ifndef __UBOOT__
- static LIST_HEAD(mtd_notifiers);
- 
-@@ -514,6 +528,13 @@ int del_mtd_device(struct mtd_info *mtd)
- 	struct mtd_notifier *not;
- #endif
- 
-+	ret = del_mtd_partitions(mtd);
-+	if (ret) {
-+		debug("Failed to delete MTD partitions attached to %s (err %d)\n",
-+		      mtd->name, ret);
-+		return ret;
-+	}
-+
- 	mutex_lock(&mtd_table_mutex);
- 
- 	if (idr_find(&mtd_idr, mtd->index) != mtd) {
-@@ -1030,13 +1051,13 @@ static int mtd_check_oob_ops(struct mtd_info *mtd, loff_t offs,
- 		return -EINVAL;
- 
- 	if (ops->ooblen) {
--		u64 maxooblen;
-+		size_t maxooblen;
- 
- 		if (ops->ooboffs >= mtd_oobavail(mtd, ops))
- 			return -EINVAL;
- 
--		maxooblen = ((mtd_div_by_ws(mtd->size, mtd) -
--			      mtd_div_by_ws(offs, mtd)) *
-+		maxooblen = ((size_t)(mtd_div_by_ws(mtd->size, mtd) -
-+				      mtd_div_by_ws(offs, mtd)) *
- 			     mtd_oobavail(mtd, ops)) - ops->ooboffs;
- 		if (ops->ooblen > maxooblen)
- 			return -EINVAL;
-diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
-index 4d2ac8107f..fd8d8e5ea7 100644
---- a/drivers/mtd/mtdpart.c
-+++ b/drivers/mtd/mtdpart.c
-@@ -63,6 +63,18 @@ char *kstrdup(const char *s, gfp_t gfp)
- #define MTD_SIZE_REMAINING		(~0LLU)
- #define MTD_OFFSET_NOT_SPECIFIED	(~0LLU)
- 
-+bool mtd_partitions_used(struct mtd_info *master)
-+{
-+	struct mtd_info *slave;
-+
-+	list_for_each_entry(slave, &master->partitions, node) {
-+		if (slave->usecount)
-+			return true;
-+	}
-+
-+	return false;
-+}
-+
- /**
-  * mtd_parse_partition - Parse @mtdparts partition definition, fill @partition
-  *                       with it and update the @mtdparts string pointer.
-diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig
-index 041957463f..f86035bcce 100644
---- a/drivers/mtd/nand/raw/Kconfig
-+++ b/drivers/mtd/nand/raw/Kconfig
-@@ -9,6 +9,12 @@ config SYS_NAND_SELF_INIT
- 	  This option, if enabled, provides more flexible and linux-like
- 	  NAND initialization process.
- 
-+config SYS_NAND_DRIVER_ECC_LAYOUT
-+	bool
-+	help
-+	  Omit standard ECC layouts to safe space. Select this if your driver
-+	  is known to provide its own ECC layout.
-+
- config NAND_ATMEL
- 	bool "Support Atmel NAND controller"
- 	imply SYS_NAND_USE_FLASH_BBT
-@@ -16,6 +22,69 @@ config NAND_ATMEL
- 	  Enable this driver for NAND flash platforms using an Atmel NAND
- 	  controller.
- 
-+if NAND_ATMEL
-+
-+config ATMEL_NAND_HWECC
-+	bool "Atmel Hardware ECC"
-+	default n
-+
-+config ATMEL_NAND_HW_PMECC
-+	bool "Atmel Programmable Multibit ECC (PMECC)"
-+	select ATMEL_NAND_HWECC
-+	default n
-+	help
-+	  The Programmable Multibit ECC (PMECC) controller is a programmable
-+	  binary BCH(Bose, Chaudhuri and Hocquenghem) encoder and decoder.
-+
-+config PMECC_CAP
-+	int "PMECC Correctable ECC Bits"
-+	depends on ATMEL_NAND_HW_PMECC
-+	default 2
-+	help
-+	  Correctable ECC bits, can be 2, 4, 8, 12, and 24.
-+
-+config PMECC_SECTOR_SIZE
-+	int "PMECC Sector Size"
-+	depends on ATMEL_NAND_HW_PMECC
-+	default 512
-+	help
-+	  Sector size, in bytes, can be 512 or 1024.
-+
-+config SPL_GENERATE_ATMEL_PMECC_HEADER
-+	bool "Atmel PMECC Header Generation"
-+	select ATMEL_NAND_HWECC
-+	select ATMEL_NAND_HW_PMECC
-+	default n
-+	help
-+	  Generate Programmable Multibit ECC (PMECC) header for SPL image.
-+
-+endif
-+
-+config NAND_BRCMNAND
-+	bool "Support Broadcom NAND controller"
-+	depends on OF_CONTROL && DM && MTD
-+	help
-+	  Enable the driver for NAND flash on platforms using a Broadcom NAND
-+	  controller.
-+
-+config NAND_BRCMNAND_6838
-+       bool "Support Broadcom NAND controller on bcm6838"
-+       depends on NAND_BRCMNAND && ARCH_BMIPS && SOC_BMIPS_BCM6838
-+       help
-+         Enable support for broadcom nand driver on bcm6838.
-+
-+config NAND_BRCMNAND_6858
-+       bool "Support Broadcom NAND controller on bcm6858"
-+       depends on NAND_BRCMNAND && ARCH_BCM6858
-+       help
-+         Enable support for broadcom nand driver on bcm6858.
-+
-+config NAND_BRCMNAND_63158
-+       bool "Support Broadcom NAND controller on bcm63158"
-+       depends on NAND_BRCMNAND && ARCH_BCM63158
-+       help
-+         Enable support for broadcom nand driver on bcm63158.
-+
- config NAND_DAVINCI
- 	bool "Support TI Davinci NAND controller"
- 	help
-@@ -81,6 +150,7 @@ config NAND_OMAP_ELM
- config NAND_VF610_NFC
- 	bool "Support for Freescale NFC for VF610"
- 	select SYS_NAND_SELF_INIT
-+	select SYS_NAND_DRIVER_ECC_LAYOUT
- 	imply CMD_NAND
- 	help
- 	  Enables support for NAND Flash Controller on some Freescale
-@@ -88,6 +158,15 @@ config NAND_VF610_NFC
- 	  The driver supports a maximum 2k page size. The driver
- 	  currently does not support hardware ECC.
- 
-+if NAND_VF610_NFC
-+
-+config NAND_VF610_NFC_DT
-+        bool "Support Vybrid's vf610 NAND controller as a DT device"
-+        depends on OF_CONTROL && MTD
-+        help
-+          Enable the driver for Vybrid's vf610 NAND flash on platforms
-+	  using device tree.
-+
- choice
- 	prompt "Hardware ECC strength"
- 	depends on NAND_VF610_NFC
-@@ -103,6 +182,8 @@ config SYS_NAND_VF610_NFC_60_ECC_BYTES
- 
- endchoice
- 
-+endif
-+
- config NAND_PXA3XX
- 	bool "Support for NAND on PXA3xx and Armada 370/XP/38x"
- 	select SYS_NAND_SELF_INIT
-@@ -200,6 +281,17 @@ config NAND_ZYNQ_USE_BOOTLOADER1_TIMINGS
- 	  This flag prevent U-boot reconfigure NAND flash controller and reuse
- 	  the NAND timing from 1st stage bootloader.
- 
-+config NAND_STM32_FMC2
-+	bool "Support for NAND controller on STM32MP SoCs"
-+	depends on ARCH_STM32MP
-+	select SYS_NAND_SELF_INIT
-+	imply CMD_NAND
-+	help
-+	  Enables support for NAND Flash chips on SoCs containing the FMC2
-+	  NAND controller. This controller is found on STM32MP SoCs.
-+	  The controller supports a maximum 8k page size and supports
-+	  a maximum 8-bit correction error per sector of 512 bytes.
-+
- comment "Generic NAND options"
- 
- config SYS_NAND_BLOCK_SIZE
-@@ -243,16 +335,12 @@ config SYS_NAND_BUSWIDTH_16BIT
- 	    not available while configuring controller. So a static CONFIG_NAND_xx
- 	    is needed to know the device's bus-width in advance.
- 
--config NAND_STM32_FMC2
--	bool "STM32 FMC2 NAND driver"
--	depends on ARCH_STM32MP && OF_CONTROL && MTD
--	select SYS_NAND_SELF_INIT
--	imply CMD_NAND
-+config SYS_NAND_MAX_CHIPS
-+	int "NAND max chips"
-+	default 1
-+	depends on NAND_ARASAN
- 	help
--	  Enables support for NAND Flash chips on SoCs containing the FMC2
--	  NAND controller. This controller is found on STM32MP SoCs.
--	  The controller supports a maximum 8k page size and supports
--	  a maximum 8-bit correction error per sector of 512 bytes.
-+	  The maximum number of NAND chips per device to be supported.
- 
- if SPL
- 
-diff --git a/drivers/mtd/nand/raw/Makefile b/drivers/mtd/nand/raw/Makefile
-index b10e718d15..9337f6482e 100644
---- a/drivers/mtd/nand/raw/Makefile
-+++ b/drivers/mtd/nand/raw/Makefile
-@@ -41,6 +41,7 @@ obj-$(CONFIG_NAND_ECC_BCH) += nand_bch.o
- 
- obj-$(CONFIG_NAND_ATMEL) += atmel_nand.o
- obj-$(CONFIG_NAND_ARASAN) += arasan_nfc.o
-+obj-$(CONFIG_NAND_BRCMNAND) += brcmnand/
- obj-$(CONFIG_NAND_DAVINCI) += davinci_nand.o
- obj-$(CONFIG_NAND_DENALI) += denali.o
- obj-$(CONFIG_NAND_DENALI_DT) += denali_dt.o
-diff --git a/drivers/mtd/nand/raw/arasan_nfc.c b/drivers/mtd/nand/raw/arasan_nfc.c
-index 41db9f8bb9..2cd3f64dc6 100644
---- a/drivers/mtd/nand/raw/arasan_nfc.c
-+++ b/drivers/mtd/nand/raw/arasan_nfc.c
-@@ -90,6 +90,8 @@ struct arasan_nand_command_format {
- #define ARASAN_NAND_MEM_ADDR1_PAGE_SHIFT	16
- #define ARASAN_NAND_MEM_ADDR2_PAGE_MASK		0xFF
- #define ARASAN_NAND_MEM_ADDR2_CS_MASK		0xC0000000
-+#define ARASAN_NAND_MEM_ADDR2_CS0_MASK         (0x3 << 30)
-+#define ARASAN_NAND_MEM_ADDR2_CS1_MASK         (0x1 << 30)
- #define ARASAN_NAND_MEM_ADDR2_BCH_MASK		0xE000000
- #define ARASAN_NAND_MEM_ADDR2_BCH_SHIFT		25
- 
-@@ -261,6 +263,16 @@ static struct nand_chip nand_chip[CONFIG_SYS_MAX_NAND_DEVICE];
- 
- static void arasan_nand_select_chip(struct mtd_info *mtd, int chip)
- {
-+	u32 reg_val;
-+
-+	reg_val = readl(&arasan_nand_base->memadr_reg2);
-+	if (chip == 0) {
-+		reg_val &= ~ARASAN_NAND_MEM_ADDR2_CS0_MASK;
-+		writel(reg_val, &arasan_nand_base->memadr_reg2);
-+	} else if (chip == 1) {
-+		reg_val |= ARASAN_NAND_MEM_ADDR2_CS1_MASK;
-+		writel(reg_val, &arasan_nand_base->memadr_reg2);
-+	}
- }
- 
- static void arasan_nand_enable_ecc(void)
-@@ -713,9 +725,6 @@ static int arasan_nand_send_wrcmd(struct arasan_nand_command_format *curr_cmd,
- 	reg_val &= ~ARASAN_NAND_MEM_ADDR2_PAGE_MASK;
- 	reg_val |= (page_addr >> ARASAN_NAND_MEM_ADDR1_PAGE_SHIFT);
- 	writel(reg_val, &arasan_nand_base->memadr_reg2);
--	reg_val = readl(&arasan_nand_base->memadr_reg2);
--	reg_val &= ~ARASAN_NAND_MEM_ADDR2_CS_MASK;
--	writel(reg_val, &arasan_nand_base->memadr_reg2);
- 
- 	return 0;
- }
-@@ -804,9 +813,6 @@ static int arasan_nand_erase(struct arasan_nand_command_format *curr_cmd,
- 	reg_val &= ~ARASAN_NAND_MEM_ADDR2_PAGE_MASK;
- 	reg_val |= (page_addr >> ARASAN_NAND_MEM_ADDR1_PAGE_SHIFT);
- 	writel(reg_val, &arasan_nand_base->memadr_reg2);
--	reg_val = readl(&arasan_nand_base->memadr_reg2);
--	reg_val &= ~ARASAN_NAND_MEM_ADDR2_CS_MASK;
--	writel(reg_val, &arasan_nand_base->memadr_reg2);
- 	writel(curr_cmd->pgm, &arasan_nand_base->pgm_reg);
- 
- 	while (!(readl(&arasan_nand_base->intsts_reg) &
-@@ -859,10 +865,6 @@ static int arasan_nand_read_status(struct arasan_nand_command_format *curr_cmd,
- 	reg_val |= (1 << ARASAN_NAND_PKT_REG_PKT_CNT_SHFT) | 1;
- 	writel(reg_val, &arasan_nand_base->pkt_reg);
- 
--	reg_val = readl(&arasan_nand_base->memadr_reg2);
--	reg_val &= ~ARASAN_NAND_MEM_ADDR2_CS_MASK;
--	writel(reg_val, &arasan_nand_base->memadr_reg2);
--
- 	writel(curr_cmd->pgm, &arasan_nand_base->pgm_reg);
- 	while (!(readl(&arasan_nand_base->intsts_reg) &
- 		ARASAN_NAND_INT_STS_XFR_CMPLT_MASK) && timeout) {
-@@ -932,9 +934,6 @@ static int arasan_nand_send_rdcmd(struct arasan_nand_command_format *curr_cmd,
- 	reg_val |= (page_addr >> ARASAN_NAND_MEM_ADDR1_PAGE_SHIFT);
- 	writel(reg_val, &arasan_nand_base->memadr_reg2);
- 
--	reg_val = readl(&arasan_nand_base->memadr_reg2);
--	reg_val &= ~ARASAN_NAND_MEM_ADDR2_CS_MASK;
--	writel(reg_val, &arasan_nand_base->memadr_reg2);
- 	buf_index = 0;
- 
- 	return 0;
-@@ -1201,6 +1200,10 @@ static int arasan_nand_init(struct nand_chip *nand_chip, int devnum)
- 	mtd = nand_to_mtd(nand_chip);
- 	nand_set_controller_data(nand_chip, nand);
- 
-+#ifdef CONFIG_SYS_NAND_NO_SUBPAGE_WRITE
-+	nand_chip->options |= NAND_NO_SUBPAGE_WRITE;
-+#endif
-+
- 	/* Set the driver entry points for MTD */
- 	nand_chip->cmdfunc = arasan_nand_cmd_function;
- 	nand_chip->select_chip = arasan_nand_select_chip;
-@@ -1215,7 +1218,7 @@ static int arasan_nand_init(struct nand_chip *nand_chip, int devnum)
- 	writel(0x0, &arasan_nand_base->pgm_reg);
- 
- 	/* first scan to find the device and get the page size */
--	if (nand_scan_ident(mtd, 1, NULL)) {
-+	if (nand_scan_ident(mtd, CONFIG_SYS_NAND_MAX_CHIPS, NULL)) {
- 		printf("%s: nand_scan_ident failed\n", __func__);
- 		goto fail;
- 	}
-diff --git a/drivers/mtd/nand/raw/brcmnand/Makefile b/drivers/mtd/nand/raw/brcmnand/Makefile
-new file mode 100644
-index 0000000000..a2363cc80e
---- /dev/null
-+++ b/drivers/mtd/nand/raw/brcmnand/Makefile
-@@ -0,0 +1,7 @@
-+# SPDX-License-Identifier: GPL-2.0+
-+
-+obj-$(CONFIG_NAND_BRCMNAND_63158) += bcm63158_nand.o
-+obj-$(CONFIG_NAND_BRCMNAND_6838) += bcm6838_nand.o
-+obj-$(CONFIG_NAND_BRCMNAND_6858) += bcm6858_nand.o
-+obj-$(CONFIG_NAND_BRCMNAND) += brcmnand.o
-+obj-$(CONFIG_NAND_BRCMNAND) += brcmnand_compat.o
-diff --git a/drivers/mtd/nand/raw/brcmnand/bcm63158_nand.c b/drivers/mtd/nand/raw/brcmnand/bcm63158_nand.c
-new file mode 100644
-index 0000000000..16b0d4440a
---- /dev/null
-+++ b/drivers/mtd/nand/raw/brcmnand/bcm63158_nand.c
-@@ -0,0 +1,123 @@
-+// SPDX-License-Identifier: GPL-2.0+
-+
-+#include <common.h>
-+#include <asm/io.h>
-+#include <memalign.h>
-+#include <nand.h>
-+#include <linux/errno.h>
-+#include <linux/io.h>
-+#include <linux/ioport.h>
-+#include <dm.h>
-+
-+#include "brcmnand.h"
-+
-+struct bcm63158_nand_soc {
-+	struct brcmnand_soc soc;
-+	void __iomem *base;
-+};
-+
-+#define BCM63158_NAND_INT		0x00
-+#define BCM63158_NAND_STATUS_SHIFT	0
-+#define BCM63158_NAND_STATUS_MASK	(0xfff << BCM63158_NAND_STATUS_SHIFT)
-+
-+#define BCM63158_NAND_INT_EN		0x04
-+#define BCM63158_NAND_ENABLE_SHIFT	0
-+#define BCM63158_NAND_ENABLE_MASK	(0xffff << BCM63158_NAND_ENABLE_SHIFT)
-+
-+enum {
-+	BCM63158_NP_READ		= BIT(0),
-+	BCM63158_BLOCK_ERASE	= BIT(1),
-+	BCM63158_COPY_BACK	= BIT(2),
-+	BCM63158_PAGE_PGM	= BIT(3),
-+	BCM63158_CTRL_READY	= BIT(4),
-+	BCM63158_DEV_RBPIN	= BIT(5),
-+	BCM63158_ECC_ERR_UNC	= BIT(6),
-+	BCM63158_ECC_ERR_CORR	= BIT(7),
-+};
-+
-+static bool bcm63158_nand_intc_ack(struct brcmnand_soc *soc)
-+{
-+	struct bcm63158_nand_soc *priv =
-+			container_of(soc, struct bcm63158_nand_soc, soc);
-+	void __iomem *mmio = priv->base + BCM63158_NAND_INT;
-+	u32 val = brcmnand_readl(mmio);
-+
-+	if (val & (BCM63158_CTRL_READY << BCM63158_NAND_STATUS_SHIFT)) {
-+		/* Ack interrupt */
-+		val &= ~BCM63158_NAND_STATUS_MASK;
-+		val |= BCM63158_CTRL_READY << BCM63158_NAND_STATUS_SHIFT;
-+		brcmnand_writel(val, mmio);
-+		return true;
-+	}
-+
-+	return false;
-+}
-+
-+static void bcm63158_nand_intc_set(struct brcmnand_soc *soc, bool en)
-+{
-+	struct bcm63158_nand_soc *priv =
-+			container_of(soc, struct bcm63158_nand_soc, soc);
-+	void __iomem *mmio = priv->base + BCM63158_NAND_INT_EN;
-+	u32 val = brcmnand_readl(mmio);
-+
-+	/* Don't ack any interrupts */
-+	val &= ~BCM63158_NAND_STATUS_MASK;
-+
-+	if (en)
-+		val |= BCM63158_CTRL_READY << BCM63158_NAND_ENABLE_SHIFT;
-+	else
-+		val &= ~(BCM63158_CTRL_READY << BCM63158_NAND_ENABLE_SHIFT);
-+
-+	brcmnand_writel(val, mmio);
-+}
-+
-+static int bcm63158_nand_probe(struct udevice *dev)
-+{
-+	struct udevice *pdev = dev;
-+	struct bcm63158_nand_soc *priv = dev_get_priv(dev);
-+	struct brcmnand_soc *soc;
-+	struct resource res;
-+
-+	soc = &priv->soc;
-+
-+	dev_read_resource_byname(pdev, "nand-int-base", &res);
-+	priv->base = devm_ioremap(dev, res.start, resource_size(&res));
-+	if (IS_ERR(priv->base))
-+		return PTR_ERR(priv->base);
-+
-+	soc->ctlrdy_ack = bcm63158_nand_intc_ack;
-+	soc->ctlrdy_set_enabled = bcm63158_nand_intc_set;
-+
-+	/* Disable and ack all interrupts  */
-+	brcmnand_writel(0, priv->base + BCM63158_NAND_INT_EN);
-+	brcmnand_writel(0, priv->base + BCM63158_NAND_INT);
-+
-+	return brcmnand_probe(pdev, soc);
-+}
-+
-+static const struct udevice_id bcm63158_nand_dt_ids[] = {
-+	{
-+		.compatible = "brcm,nand-bcm63158",
-+	},
-+	{ /* sentinel */ }
-+};
-+
-+U_BOOT_DRIVER(bcm63158_nand) = {
-+	.name = "bcm63158-nand",
-+	.id = UCLASS_MTD,
-+	.of_match = bcm63158_nand_dt_ids,
-+	.probe = bcm63158_nand_probe,
-+	.priv_auto_alloc_size = sizeof(struct bcm63158_nand_soc),
-+};
-+
-+void board_nand_init(void)
-+{
-+	struct udevice *dev;
-+	int ret;
-+
-+	ret = uclass_get_device_by_driver(UCLASS_MTD,
-+					  DM_GET_DRIVER(bcm63158_nand), &dev);
-+	if (ret && ret != -ENODEV)
-+		pr_err("Failed to initialize %s. (error %d)\n", dev->name,
-+		       ret);
-+}
-diff --git a/drivers/mtd/nand/raw/brcmnand/bcm6838_nand.c b/drivers/mtd/nand/raw/brcmnand/bcm6838_nand.c
-new file mode 100644
-index 0000000000..ece944485c
---- /dev/null
-+++ b/drivers/mtd/nand/raw/brcmnand/bcm6838_nand.c
-@@ -0,0 +1,122 @@
-+// SPDX-License-Identifier: GPL-2.0+
-+
-+#include <common.h>
-+#include <asm/io.h>
-+#include <memalign.h>
-+#include <nand.h>
-+#include <linux/errno.h>
-+#include <linux/io.h>
-+#include <linux/ioport.h>
-+#include <dm.h>
-+
-+#include "brcmnand.h"
-+
-+struct bcm6838_nand_soc {
-+	struct brcmnand_soc soc;
-+	void __iomem *base;
-+};
-+
-+#define BCM6838_NAND_INT		0x00
-+#define  BCM6838_NAND_STATUS_SHIFT	0
-+#define  BCM6838_NAND_STATUS_MASK	(0xfff << BCM6838_NAND_STATUS_SHIFT)
-+#define  BCM6838_NAND_ENABLE_SHIFT	16
-+#define  BCM6838_NAND_ENABLE_MASK	(0xffff << BCM6838_NAND_ENABLE_SHIFT)
-+
-+enum {
-+	BCM6838_NP_READ		= BIT(0),
-+	BCM6838_BLOCK_ERASE	= BIT(1),
-+	BCM6838_COPY_BACK	= BIT(2),
-+	BCM6838_PAGE_PGM	= BIT(3),
-+	BCM6838_CTRL_READY	= BIT(4),
-+	BCM6838_DEV_RBPIN	= BIT(5),
-+	BCM6838_ECC_ERR_UNC	= BIT(6),
-+	BCM6838_ECC_ERR_CORR	= BIT(7),
-+};
-+
-+static bool bcm6838_nand_intc_ack(struct brcmnand_soc *soc)
-+{
-+	struct bcm6838_nand_soc *priv =
-+			container_of(soc, struct bcm6838_nand_soc, soc);
-+	void __iomem *mmio = priv->base + BCM6838_NAND_INT;
-+	u32 val = brcmnand_readl(mmio);
-+
-+	if (val & (BCM6838_CTRL_READY << BCM6838_NAND_STATUS_SHIFT)) {
-+		/* Ack interrupt */
-+		val &= ~BCM6838_NAND_STATUS_MASK;
-+		val |= BCM6838_CTRL_READY << BCM6838_NAND_STATUS_SHIFT;
-+		brcmnand_writel(val, mmio);
-+		return true;
-+	}
-+
-+	return false;
-+}
-+
-+static void bcm6838_nand_intc_set(struct brcmnand_soc *soc, bool en)
-+{
-+	struct bcm6838_nand_soc *priv =
-+			container_of(soc, struct bcm6838_nand_soc, soc);
-+	void __iomem *mmio = priv->base + BCM6838_NAND_INT;
-+	u32 val = brcmnand_readl(mmio);
-+
-+	/* Don't ack any interrupts */
-+	val &= ~BCM6838_NAND_STATUS_MASK;
-+
-+	if (en)
-+		val |= BCM6838_CTRL_READY << BCM6838_NAND_ENABLE_SHIFT;
-+	else
-+		val &= ~(BCM6838_CTRL_READY << BCM6838_NAND_ENABLE_SHIFT);
-+
-+	brcmnand_writel(val, mmio);
-+}
-+
-+static int bcm6838_nand_probe(struct udevice *dev)
-+{
-+	struct udevice *pdev = dev;
-+	struct bcm6838_nand_soc *priv = dev_get_priv(dev);
-+	struct brcmnand_soc *soc;
-+	struct resource res;
-+
-+	soc = &priv->soc;
-+
-+	dev_read_resource_byname(pdev, "nand-int-base", &res);
-+	priv->base = ioremap(res.start, resource_size(&res));
-+	if (IS_ERR(priv->base))
-+		return PTR_ERR(priv->base);
-+
-+	soc->ctlrdy_ack = bcm6838_nand_intc_ack;
-+	soc->ctlrdy_set_enabled = bcm6838_nand_intc_set;
-+
-+	/* Disable and ack all interrupts  */
-+	brcmnand_writel(0, priv->base + BCM6838_NAND_INT);
-+	brcmnand_writel(BCM6838_NAND_STATUS_MASK,
-+			priv->base + BCM6838_NAND_INT);
-+
-+	return brcmnand_probe(pdev, soc);
-+}
-+
-+static const struct udevice_id bcm6838_nand_dt_ids[] = {
-+	{
-+		.compatible = "brcm,nand-bcm6838",
-+	},
-+	{ /* sentinel */ }
-+};
-+
-+U_BOOT_DRIVER(bcm6838_nand) = {
-+	.name = "bcm6838-nand",
-+	.id = UCLASS_MTD,
-+	.of_match = bcm6838_nand_dt_ids,
-+	.probe = bcm6838_nand_probe,
-+	.priv_auto_alloc_size = sizeof(struct bcm6838_nand_soc),
-+};
-+
-+void board_nand_init(void)
-+{
-+	struct udevice *dev;
-+	int ret;
-+
-+	ret = uclass_get_device_by_driver(UCLASS_MTD,
-+					  DM_GET_DRIVER(bcm6838_nand), &dev);
-+	if (ret && ret != -ENODEV)
-+		pr_err("Failed to initialize %s. (error %d)\n", dev->name,
-+		       ret);
-+}
-diff --git a/drivers/mtd/nand/raw/brcmnand/bcm6858_nand.c b/drivers/mtd/nand/raw/brcmnand/bcm6858_nand.c
-new file mode 100644
-index 0000000000..3586baa4fa
---- /dev/null
-+++ b/drivers/mtd/nand/raw/brcmnand/bcm6858_nand.c
-@@ -0,0 +1,123 @@
-+// SPDX-License-Identifier: GPL-2.0+
-+
-+#include <common.h>
-+#include <asm/io.h>
-+#include <memalign.h>
-+#include <nand.h>
-+#include <linux/errno.h>
-+#include <linux/io.h>
-+#include <linux/ioport.h>
-+#include <dm.h>
-+
-+#include "brcmnand.h"
-+
-+struct bcm6858_nand_soc {
-+	struct brcmnand_soc soc;
-+	void __iomem *base;
-+};
-+
-+#define BCM6858_NAND_INT		0x00
-+#define BCM6858_NAND_STATUS_SHIFT	0
-+#define BCM6858_NAND_STATUS_MASK	(0xfff << BCM6858_NAND_STATUS_SHIFT)
-+
-+#define BCM6858_NAND_INT_EN		0x04
-+#define BCM6858_NAND_ENABLE_SHIFT	0
-+#define BCM6858_NAND_ENABLE_MASK	(0xffff << BCM6858_NAND_ENABLE_SHIFT)
-+
-+enum {
-+	BCM6858_NP_READ		= BIT(0),
-+	BCM6858_BLOCK_ERASE	= BIT(1),
-+	BCM6858_COPY_BACK	= BIT(2),
-+	BCM6858_PAGE_PGM	= BIT(3),
-+	BCM6858_CTRL_READY	= BIT(4),
-+	BCM6858_DEV_RBPIN	= BIT(5),
-+	BCM6858_ECC_ERR_UNC	= BIT(6),
-+	BCM6858_ECC_ERR_CORR	= BIT(7),
-+};
-+
-+static bool bcm6858_nand_intc_ack(struct brcmnand_soc *soc)
-+{
-+	struct bcm6858_nand_soc *priv =
-+			container_of(soc, struct bcm6858_nand_soc, soc);
-+	void __iomem *mmio = priv->base + BCM6858_NAND_INT;
-+	u32 val = brcmnand_readl(mmio);
-+
-+	if (val & (BCM6858_CTRL_READY << BCM6858_NAND_STATUS_SHIFT)) {
-+		/* Ack interrupt */
-+		val &= ~BCM6858_NAND_STATUS_MASK;
-+		val |= BCM6858_CTRL_READY << BCM6858_NAND_STATUS_SHIFT;
-+		brcmnand_writel(val, mmio);
-+		return true;
-+	}
-+
-+	return false;
-+}
-+
-+static void bcm6858_nand_intc_set(struct brcmnand_soc *soc, bool en)
-+{
-+	struct bcm6858_nand_soc *priv =
-+			container_of(soc, struct bcm6858_nand_soc, soc);
-+	void __iomem *mmio = priv->base + BCM6858_NAND_INT_EN;
-+	u32 val = brcmnand_readl(mmio);
-+
-+	/* Don't ack any interrupts */
-+	val &= ~BCM6858_NAND_STATUS_MASK;
-+
-+	if (en)
-+		val |= BCM6858_CTRL_READY << BCM6858_NAND_ENABLE_SHIFT;
-+	else
-+		val &= ~(BCM6858_CTRL_READY << BCM6858_NAND_ENABLE_SHIFT);
-+
-+	brcmnand_writel(val, mmio);
-+}
-+
-+static int bcm6858_nand_probe(struct udevice *dev)
-+{
-+	struct udevice *pdev = dev;
-+	struct bcm6858_nand_soc *priv = dev_get_priv(dev);
-+	struct brcmnand_soc *soc;
-+	struct resource res;
-+
-+	soc = &priv->soc;
-+
-+	dev_read_resource_byname(pdev, "nand-int-base", &res);
-+	priv->base = devm_ioremap(dev, res.start, resource_size(&res));
-+	if (IS_ERR(priv->base))
-+		return PTR_ERR(priv->base);
-+
-+	soc->ctlrdy_ack = bcm6858_nand_intc_ack;
-+	soc->ctlrdy_set_enabled = bcm6858_nand_intc_set;
-+
-+	/* Disable and ack all interrupts  */
-+	brcmnand_writel(0, priv->base + BCM6858_NAND_INT_EN);
-+	brcmnand_writel(0, priv->base + BCM6858_NAND_INT);
-+
-+	return brcmnand_probe(pdev, soc);
-+}
-+
-+static const struct udevice_id bcm6858_nand_dt_ids[] = {
-+	{
-+		.compatible = "brcm,nand-bcm6858",
-+	},
-+	{ /* sentinel */ }
-+};
-+
-+U_BOOT_DRIVER(bcm6858_nand) = {
-+	.name = "bcm6858-nand",
-+	.id = UCLASS_MTD,
-+	.of_match = bcm6858_nand_dt_ids,
-+	.probe = bcm6858_nand_probe,
-+	.priv_auto_alloc_size = sizeof(struct bcm6858_nand_soc),
-+};
-+
-+void board_nand_init(void)
-+{
-+	struct udevice *dev;
-+	int ret;
-+
-+	ret = uclass_get_device_by_driver(UCLASS_MTD,
-+					  DM_GET_DRIVER(bcm6858_nand), &dev);
-+	if (ret && ret != -ENODEV)
-+		pr_err("Failed to initialize %s. (error %d)\n", dev->name,
-+		       ret);
-+}
-diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand.c b/drivers/mtd/nand/raw/brcmnand/brcmnand.c
-new file mode 100644
-index 0000000000..faa6da42d5
---- /dev/null
-+++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.c
-@@ -0,0 +1,2805 @@
-+// SPDX-License-Identifier: GPL-2.0+
-+/*
-+ * Copyright © 2010-2015 Broadcom Corporation
-+ *
-+ * 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 <common.h>
-+#include <asm/io.h>
-+#include <memalign.h>
-+#include <nand.h>
-+#include <clk.h>
-+#include <linux/ioport.h>
-+#include <linux/completion.h>
-+#include <linux/errno.h>
-+#include <linux/log2.h>
-+#include <asm/processor.h>
-+#include <dm.h>
-+
-+#include "brcmnand.h"
-+#include "brcmnand_compat.h"
-+
-+/*
-+ * This flag controls if WP stays on between erase/write commands to mitigate
-+ * flash corruption due to power glitches. Values:
-+ * 0: NAND_WP is not used or not available
-+ * 1: NAND_WP is set by default, cleared for erase/write operations
-+ * 2: NAND_WP is always cleared
-+ */
-+static int wp_on = 1;
-+module_param(wp_on, int, 0444);
-+
-+/***********************************************************************
-+ * Definitions
-+ ***********************************************************************/
-+
-+#define DRV_NAME			"brcmnand"
-+
-+#define CMD_NULL			0x00
-+#define CMD_PAGE_READ			0x01
-+#define CMD_SPARE_AREA_READ		0x02
-+#define CMD_STATUS_READ			0x03
-+#define CMD_PROGRAM_PAGE		0x04
-+#define CMD_PROGRAM_SPARE_AREA		0x05
-+#define CMD_COPY_BACK			0x06
-+#define CMD_DEVICE_ID_READ		0x07
-+#define CMD_BLOCK_ERASE			0x08
-+#define CMD_FLASH_RESET			0x09
-+#define CMD_BLOCKS_LOCK			0x0a
-+#define CMD_BLOCKS_LOCK_DOWN		0x0b
-+#define CMD_BLOCKS_UNLOCK		0x0c
-+#define CMD_READ_BLOCKS_LOCK_STATUS	0x0d
-+#define CMD_PARAMETER_READ		0x0e
-+#define CMD_PARAMETER_CHANGE_COL	0x0f
-+#define CMD_LOW_LEVEL_OP		0x10
-+
-+struct brcm_nand_dma_desc {
-+	u32 next_desc;
-+	u32 next_desc_ext;
-+	u32 cmd_irq;
-+	u32 dram_addr;
-+	u32 dram_addr_ext;
-+	u32 tfr_len;
-+	u32 total_len;
-+	u32 flash_addr;
-+	u32 flash_addr_ext;
-+	u32 cs;
-+	u32 pad2[5];
-+	u32 status_valid;
-+} __packed;
-+
-+/* Bitfields for brcm_nand_dma_desc::status_valid */
-+#define FLASH_DMA_ECC_ERROR	(1 << 8)
-+#define FLASH_DMA_CORR_ERROR	(1 << 9)
-+
-+/* 512B flash cache in the NAND controller HW */
-+#define FC_SHIFT		9U
-+#define FC_BYTES		512U
-+#define FC_WORDS		(FC_BYTES >> 2)
-+
-+#define BRCMNAND_MIN_PAGESIZE	512
-+#define BRCMNAND_MIN_BLOCKSIZE	(8 * 1024)
-+#define BRCMNAND_MIN_DEVSIZE	(4ULL * 1024 * 1024)
-+
-+#define NAND_CTRL_RDY			(INTFC_CTLR_READY | INTFC_FLASH_READY)
-+#define NAND_POLL_STATUS_TIMEOUT_MS	100
-+
-+/* Controller feature flags */
-+enum {
-+	BRCMNAND_HAS_1K_SECTORS			= BIT(0),
-+	BRCMNAND_HAS_PREFETCH			= BIT(1),
-+	BRCMNAND_HAS_CACHE_MODE			= BIT(2),
-+	BRCMNAND_HAS_WP				= BIT(3),
-+};
-+
-+struct brcmnand_controller {
-+#ifndef __UBOOT__
-+	struct device		*dev;
-+#else
-+	struct udevice		*dev;
-+#endif /* __UBOOT__ */
-+	struct nand_hw_control	controller;
-+	void __iomem		*nand_base;
-+	void __iomem		*nand_fc; /* flash cache */
-+	void __iomem		*flash_dma_base;
-+	unsigned int		irq;
-+	unsigned int		dma_irq;
-+	int			nand_version;
-+	int			parameter_page_big_endian;
-+
-+	/* Some SoCs provide custom interrupt status register(s) */
-+	struct brcmnand_soc	*soc;
-+
-+	/* Some SoCs have a gateable clock for the controller */
-+	struct clk		*clk;
-+
-+	int			cmd_pending;
-+	bool			dma_pending;
-+	struct completion	done;
-+	struct completion	dma_done;
-+
-+	/* List of NAND hosts (one for each chip-select) */
-+	struct list_head host_list;
-+
-+	struct brcm_nand_dma_desc *dma_desc;
-+	dma_addr_t		dma_pa;
-+
-+	/* in-memory cache of the FLASH_CACHE, used only for some commands */
-+	u8			flash_cache[FC_BYTES];
-+
-+	/* Controller revision details */
-+	const u16		*reg_offsets;
-+	unsigned int		reg_spacing; /* between CS1, CS2, ... regs */
-+	const u8		*cs_offsets; /* within each chip-select */
-+	const u8		*cs0_offsets; /* within CS0, if different */
-+	unsigned int		max_block_size;
-+	const unsigned int	*block_sizes;
-+	unsigned int		max_page_size;
-+	const unsigned int	*page_sizes;
-+	unsigned int		max_oob;
-+	u32			features;
-+
-+	/* for low-power standby/resume only */
-+	u32			nand_cs_nand_select;
-+	u32			nand_cs_nand_xor;
-+	u32			corr_stat_threshold;
-+	u32			flash_dma_mode;
-+};
-+
-+struct brcmnand_cfg {
-+	u64			device_size;
-+	unsigned int		block_size;
-+	unsigned int		page_size;
-+	unsigned int		spare_area_size;
-+	unsigned int		device_width;
-+	unsigned int		col_adr_bytes;
-+	unsigned int		blk_adr_bytes;
-+	unsigned int		ful_adr_bytes;
-+	unsigned int		sector_size_1k;
-+	unsigned int		ecc_level;
-+	/* use for low-power standby/resume only */
-+	u32			acc_control;
-+	u32			config;
-+	u32			config_ext;
-+	u32			timing_1;
-+	u32			timing_2;
-+};
-+
-+struct brcmnand_host {
-+	struct list_head	node;
-+
-+	struct nand_chip	chip;
-+#ifndef __UBOOT__
-+	struct platform_device	*pdev;
-+#else
-+	struct udevice	*pdev;
-+#endif /* __UBOOT__ */
-+	int			cs;
-+
-+	unsigned int		last_cmd;
-+	unsigned int		last_byte;
-+	u64			last_addr;
-+	struct brcmnand_cfg	hwcfg;
-+	struct brcmnand_controller *ctrl;
-+};
-+
-+enum brcmnand_reg {
-+	BRCMNAND_CMD_START = 0,
-+	BRCMNAND_CMD_EXT_ADDRESS,
-+	BRCMNAND_CMD_ADDRESS,
-+	BRCMNAND_INTFC_STATUS,
-+	BRCMNAND_CS_SELECT,
-+	BRCMNAND_CS_XOR,
-+	BRCMNAND_LL_OP,
-+	BRCMNAND_CS0_BASE,
-+	BRCMNAND_CS1_BASE,		/* CS1 regs, if non-contiguous */
-+	BRCMNAND_CORR_THRESHOLD,
-+	BRCMNAND_CORR_THRESHOLD_EXT,
-+	BRCMNAND_UNCORR_COUNT,
-+	BRCMNAND_CORR_COUNT,
-+	BRCMNAND_CORR_EXT_ADDR,
-+	BRCMNAND_CORR_ADDR,
-+	BRCMNAND_UNCORR_EXT_ADDR,
-+	BRCMNAND_UNCORR_ADDR,
-+	BRCMNAND_SEMAPHORE,
-+	BRCMNAND_ID,
-+	BRCMNAND_ID_EXT,
-+	BRCMNAND_LL_RDATA,
-+	BRCMNAND_OOB_READ_BASE,
-+	BRCMNAND_OOB_READ_10_BASE,	/* offset 0x10, if non-contiguous */
-+	BRCMNAND_OOB_WRITE_BASE,
-+	BRCMNAND_OOB_WRITE_10_BASE,	/* offset 0x10, if non-contiguous */
-+	BRCMNAND_FC_BASE,
-+};
-+
-+/* BRCMNAND v4.0 */
-+static const u16 brcmnand_regs_v40[] = {
-+	[BRCMNAND_CMD_START]		=  0x04,
-+	[BRCMNAND_CMD_EXT_ADDRESS]	=  0x08,
-+	[BRCMNAND_CMD_ADDRESS]		=  0x0c,
-+	[BRCMNAND_INTFC_STATUS]		=  0x6c,
-+	[BRCMNAND_CS_SELECT]		=  0x14,
-+	[BRCMNAND_CS_XOR]		=  0x18,
-+	[BRCMNAND_LL_OP]		= 0x178,
-+	[BRCMNAND_CS0_BASE]		=  0x40,
-+	[BRCMNAND_CS1_BASE]		=  0xd0,
-+	[BRCMNAND_CORR_THRESHOLD]	=  0x84,
-+	[BRCMNAND_CORR_THRESHOLD_EXT]	=     0,
-+	[BRCMNAND_UNCORR_COUNT]		=     0,
-+	[BRCMNAND_CORR_COUNT]		=     0,
-+	[BRCMNAND_CORR_EXT_ADDR]	=  0x70,
-+	[BRCMNAND_CORR_ADDR]		=  0x74,
-+	[BRCMNAND_UNCORR_EXT_ADDR]	=  0x78,
-+	[BRCMNAND_UNCORR_ADDR]		=  0x7c,
-+	[BRCMNAND_SEMAPHORE]		=  0x58,
-+	[BRCMNAND_ID]			=  0x60,
-+	[BRCMNAND_ID_EXT]		=  0x64,
-+	[BRCMNAND_LL_RDATA]		= 0x17c,
-+	[BRCMNAND_OOB_READ_BASE]	=  0x20,
-+	[BRCMNAND_OOB_READ_10_BASE]	= 0x130,
-+	[BRCMNAND_OOB_WRITE_BASE]	=  0x30,
-+	[BRCMNAND_OOB_WRITE_10_BASE]	=     0,
-+	[BRCMNAND_FC_BASE]		= 0x200,
-+};
-+
-+/* BRCMNAND v5.0 */
-+static const u16 brcmnand_regs_v50[] = {
-+	[BRCMNAND_CMD_START]		=  0x04,
-+	[BRCMNAND_CMD_EXT_ADDRESS]	=  0x08,
-+	[BRCMNAND_CMD_ADDRESS]		=  0x0c,
-+	[BRCMNAND_INTFC_STATUS]		=  0x6c,
-+	[BRCMNAND_CS_SELECT]		=  0x14,
-+	[BRCMNAND_CS_XOR]		=  0x18,
-+	[BRCMNAND_LL_OP]		= 0x178,
-+	[BRCMNAND_CS0_BASE]		=  0x40,
-+	[BRCMNAND_CS1_BASE]		=  0xd0,
-+	[BRCMNAND_CORR_THRESHOLD]	=  0x84,
-+	[BRCMNAND_CORR_THRESHOLD_EXT]	=     0,
-+	[BRCMNAND_UNCORR_COUNT]		=     0,
-+	[BRCMNAND_CORR_COUNT]		=     0,
-+	[BRCMNAND_CORR_EXT_ADDR]	=  0x70,
-+	[BRCMNAND_CORR_ADDR]		=  0x74,
-+	[BRCMNAND_UNCORR_EXT_ADDR]	=  0x78,
-+	[BRCMNAND_UNCORR_ADDR]		=  0x7c,
-+	[BRCMNAND_SEMAPHORE]		=  0x58,
-+	[BRCMNAND_ID]			=  0x60,
-+	[BRCMNAND_ID_EXT]		=  0x64,
-+	[BRCMNAND_LL_RDATA]		= 0x17c,
-+	[BRCMNAND_OOB_READ_BASE]	=  0x20,
-+	[BRCMNAND_OOB_READ_10_BASE]	= 0x130,
-+	[BRCMNAND_OOB_WRITE_BASE]	=  0x30,
-+	[BRCMNAND_OOB_WRITE_10_BASE]	= 0x140,
-+	[BRCMNAND_FC_BASE]		= 0x200,
-+};
-+
-+/* BRCMNAND v6.0 - v7.1 */
-+static const u16 brcmnand_regs_v60[] = {
-+	[BRCMNAND_CMD_START]		=  0x04,
-+	[BRCMNAND_CMD_EXT_ADDRESS]	=  0x08,
-+	[BRCMNAND_CMD_ADDRESS]		=  0x0c,
-+	[BRCMNAND_INTFC_STATUS]		=  0x14,
-+	[BRCMNAND_CS_SELECT]		=  0x18,
-+	[BRCMNAND_CS_XOR]		=  0x1c,
-+	[BRCMNAND_LL_OP]		=  0x20,
-+	[BRCMNAND_CS0_BASE]		=  0x50,
-+	[BRCMNAND_CS1_BASE]		=     0,
-+	[BRCMNAND_CORR_THRESHOLD]	=  0xc0,
-+	[BRCMNAND_CORR_THRESHOLD_EXT]	=  0xc4,
-+	[BRCMNAND_UNCORR_COUNT]		=  0xfc,
-+	[BRCMNAND_CORR_COUNT]		= 0x100,
-+	[BRCMNAND_CORR_EXT_ADDR]	= 0x10c,
-+	[BRCMNAND_CORR_ADDR]		= 0x110,
-+	[BRCMNAND_UNCORR_EXT_ADDR]	= 0x114,
-+	[BRCMNAND_UNCORR_ADDR]		= 0x118,
-+	[BRCMNAND_SEMAPHORE]		= 0x150,
-+	[BRCMNAND_ID]			= 0x194,
-+	[BRCMNAND_ID_EXT]		= 0x198,
-+	[BRCMNAND_LL_RDATA]		= 0x19c,
-+	[BRCMNAND_OOB_READ_BASE]	= 0x200,
-+	[BRCMNAND_OOB_READ_10_BASE]	=     0,
-+	[BRCMNAND_OOB_WRITE_BASE]	= 0x280,
-+	[BRCMNAND_OOB_WRITE_10_BASE]	=     0,
-+	[BRCMNAND_FC_BASE]		= 0x400,
-+};
-+
-+/* BRCMNAND v7.1 */
-+static const u16 brcmnand_regs_v71[] = {
-+	[BRCMNAND_CMD_START]		=  0x04,
-+	[BRCMNAND_CMD_EXT_ADDRESS]	=  0x08,
-+	[BRCMNAND_CMD_ADDRESS]		=  0x0c,
-+	[BRCMNAND_INTFC_STATUS]		=  0x14,
-+	[BRCMNAND_CS_SELECT]		=  0x18,
-+	[BRCMNAND_CS_XOR]		=  0x1c,
-+	[BRCMNAND_LL_OP]		=  0x20,
-+	[BRCMNAND_CS0_BASE]		=  0x50,
-+	[BRCMNAND_CS1_BASE]		=     0,
-+	[BRCMNAND_CORR_THRESHOLD]	=  0xdc,
-+	[BRCMNAND_CORR_THRESHOLD_EXT]	=  0xe0,
-+	[BRCMNAND_UNCORR_COUNT]		=  0xfc,
-+	[BRCMNAND_CORR_COUNT]		= 0x100,
-+	[BRCMNAND_CORR_EXT_ADDR]	= 0x10c,
-+	[BRCMNAND_CORR_ADDR]		= 0x110,
-+	[BRCMNAND_UNCORR_EXT_ADDR]	= 0x114,
-+	[BRCMNAND_UNCORR_ADDR]		= 0x118,
-+	[BRCMNAND_SEMAPHORE]		= 0x150,
-+	[BRCMNAND_ID]			= 0x194,
-+	[BRCMNAND_ID_EXT]		= 0x198,
-+	[BRCMNAND_LL_RDATA]		= 0x19c,
-+	[BRCMNAND_OOB_READ_BASE]	= 0x200,
-+	[BRCMNAND_OOB_READ_10_BASE]	=     0,
-+	[BRCMNAND_OOB_WRITE_BASE]	= 0x280,
-+	[BRCMNAND_OOB_WRITE_10_BASE]	=     0,
-+	[BRCMNAND_FC_BASE]		= 0x400,
-+};
-+
-+/* BRCMNAND v7.2 */
-+static const u16 brcmnand_regs_v72[] = {
-+	[BRCMNAND_CMD_START]		=  0x04,
-+	[BRCMNAND_CMD_EXT_ADDRESS]	=  0x08,
-+	[BRCMNAND_CMD_ADDRESS]		=  0x0c,
-+	[BRCMNAND_INTFC_STATUS]		=  0x14,
-+	[BRCMNAND_CS_SELECT]		=  0x18,
-+	[BRCMNAND_CS_XOR]		=  0x1c,
-+	[BRCMNAND_LL_OP]		=  0x20,
-+	[BRCMNAND_CS0_BASE]		=  0x50,
-+	[BRCMNAND_CS1_BASE]		=     0,
-+	[BRCMNAND_CORR_THRESHOLD]	=  0xdc,
-+	[BRCMNAND_CORR_THRESHOLD_EXT]	=  0xe0,
-+	[BRCMNAND_UNCORR_COUNT]		=  0xfc,
-+	[BRCMNAND_CORR_COUNT]		= 0x100,
-+	[BRCMNAND_CORR_EXT_ADDR]	= 0x10c,
-+	[BRCMNAND_CORR_ADDR]		= 0x110,
-+	[BRCMNAND_UNCORR_EXT_ADDR]	= 0x114,
-+	[BRCMNAND_UNCORR_ADDR]		= 0x118,
-+	[BRCMNAND_SEMAPHORE]		= 0x150,
-+	[BRCMNAND_ID]			= 0x194,
-+	[BRCMNAND_ID_EXT]		= 0x198,
-+	[BRCMNAND_LL_RDATA]		= 0x19c,
-+	[BRCMNAND_OOB_READ_BASE]	= 0x200,
-+	[BRCMNAND_OOB_READ_10_BASE]	=     0,
-+	[BRCMNAND_OOB_WRITE_BASE]	= 0x400,
-+	[BRCMNAND_OOB_WRITE_10_BASE]	=     0,
-+	[BRCMNAND_FC_BASE]		= 0x600,
-+};
-+
-+enum brcmnand_cs_reg {
-+	BRCMNAND_CS_CFG_EXT = 0,
-+	BRCMNAND_CS_CFG,
-+	BRCMNAND_CS_ACC_CONTROL,
-+	BRCMNAND_CS_TIMING1,
-+	BRCMNAND_CS_TIMING2,
-+};
-+
-+/* Per chip-select offsets for v7.1 */
-+static const u8 brcmnand_cs_offsets_v71[] = {
-+	[BRCMNAND_CS_ACC_CONTROL]	= 0x00,
-+	[BRCMNAND_CS_CFG_EXT]		= 0x04,
-+	[BRCMNAND_CS_CFG]		= 0x08,
-+	[BRCMNAND_CS_TIMING1]		= 0x0c,
-+	[BRCMNAND_CS_TIMING2]		= 0x10,
-+};
-+
-+/* Per chip-select offsets for pre v7.1, except CS0 on <= v5.0 */
-+static const u8 brcmnand_cs_offsets[] = {
-+	[BRCMNAND_CS_ACC_CONTROL]	= 0x00,
-+	[BRCMNAND_CS_CFG_EXT]		= 0x04,
-+	[BRCMNAND_CS_CFG]		= 0x04,
-+	[BRCMNAND_CS_TIMING1]		= 0x08,
-+	[BRCMNAND_CS_TIMING2]		= 0x0c,
-+};
-+
-+/* Per chip-select offset for <= v5.0 on CS0 only */
-+static const u8 brcmnand_cs_offsets_cs0[] = {
-+	[BRCMNAND_CS_ACC_CONTROL]	= 0x00,
-+	[BRCMNAND_CS_CFG_EXT]		= 0x08,
-+	[BRCMNAND_CS_CFG]		= 0x08,
-+	[BRCMNAND_CS_TIMING1]		= 0x10,
-+	[BRCMNAND_CS_TIMING2]		= 0x14,
-+};
-+
-+/*
-+ * Bitfields for the CFG and CFG_EXT registers. Pre-v7.1 controllers only had
-+ * one config register, but once the bitfields overflowed, newer controllers
-+ * (v7.1 and newer) added a CFG_EXT register and shuffled a few fields around.
-+ */
-+enum {
-+	CFG_BLK_ADR_BYTES_SHIFT		= 8,
-+	CFG_COL_ADR_BYTES_SHIFT		= 12,
-+	CFG_FUL_ADR_BYTES_SHIFT		= 16,
-+	CFG_BUS_WIDTH_SHIFT		= 23,
-+	CFG_BUS_WIDTH			= BIT(CFG_BUS_WIDTH_SHIFT),
-+	CFG_DEVICE_SIZE_SHIFT		= 24,
-+
-+	/* Only for pre-v7.1 (with no CFG_EXT register) */
-+	CFG_PAGE_SIZE_SHIFT		= 20,
-+	CFG_BLK_SIZE_SHIFT		= 28,
-+
-+	/* Only for v7.1+ (with CFG_EXT register) */
-+	CFG_EXT_PAGE_SIZE_SHIFT		= 0,
-+	CFG_EXT_BLK_SIZE_SHIFT		= 4,
-+};
-+
-+/* BRCMNAND_INTFC_STATUS */
-+enum {
-+	INTFC_FLASH_STATUS		= GENMASK(7, 0),
-+
-+	INTFC_ERASED			= BIT(27),
-+	INTFC_OOB_VALID			= BIT(28),
-+	INTFC_CACHE_VALID		= BIT(29),
-+	INTFC_FLASH_READY		= BIT(30),
-+	INTFC_CTLR_READY		= BIT(31),
-+};
-+
-+static inline u32 nand_readreg(struct brcmnand_controller *ctrl, u32 offs)
-+{
-+	return brcmnand_readl(ctrl->nand_base + offs);
-+}
-+
-+static inline void nand_writereg(struct brcmnand_controller *ctrl, u32 offs,
-+				 u32 val)
-+{
-+	brcmnand_writel(val, ctrl->nand_base + offs);
-+}
-+
-+static int brcmnand_revision_init(struct brcmnand_controller *ctrl)
-+{
-+	static const unsigned int block_sizes_v6[] = { 8, 16, 128, 256, 512, 1024, 2048, 0 };
-+	static const unsigned int block_sizes_v4[] = { 16, 128, 8, 512, 256, 1024, 2048, 0 };
-+	static const unsigned int page_sizes[] = { 512, 2048, 4096, 8192, 0 };
-+
-+	ctrl->nand_version = nand_readreg(ctrl, 0) & 0xffff;
-+
-+	/* Only support v4.0+? */
-+	if (ctrl->nand_version < 0x0400) {
-+		dev_err(ctrl->dev, "version %#x not supported\n",
-+			ctrl->nand_version);
-+		return -ENODEV;
-+	}
-+
-+	/* Register offsets */
-+	if (ctrl->nand_version >= 0x0702)
-+		ctrl->reg_offsets = brcmnand_regs_v72;
-+	else if (ctrl->nand_version >= 0x0701)
-+		ctrl->reg_offsets = brcmnand_regs_v71;
-+	else if (ctrl->nand_version >= 0x0600)
-+		ctrl->reg_offsets = brcmnand_regs_v60;
-+	else if (ctrl->nand_version >= 0x0500)
-+		ctrl->reg_offsets = brcmnand_regs_v50;
-+	else if (ctrl->nand_version >= 0x0400)
-+		ctrl->reg_offsets = brcmnand_regs_v40;
-+
-+	/* Chip-select stride */
-+	if (ctrl->nand_version >= 0x0701)
-+		ctrl->reg_spacing = 0x14;
-+	else
-+		ctrl->reg_spacing = 0x10;
-+
-+	/* Per chip-select registers */
-+	if (ctrl->nand_version >= 0x0701) {
-+		ctrl->cs_offsets = brcmnand_cs_offsets_v71;
-+	} else {
-+		ctrl->cs_offsets = brcmnand_cs_offsets;
-+
-+		/* v5.0 and earlier has a different CS0 offset layout */
-+		if (ctrl->nand_version <= 0x0500)
-+			ctrl->cs0_offsets = brcmnand_cs_offsets_cs0;
-+	}
-+
-+	/* Page / block sizes */
-+	if (ctrl->nand_version >= 0x0701) {
-+		/* >= v7.1 use nice power-of-2 values! */
-+		ctrl->max_page_size = 16 * 1024;
-+		ctrl->max_block_size = 2 * 1024 * 1024;
-+	} else {
-+		ctrl->page_sizes = page_sizes;
-+		if (ctrl->nand_version >= 0x0600)
-+			ctrl->block_sizes = block_sizes_v6;
-+		else
-+			ctrl->block_sizes = block_sizes_v4;
-+
-+		if (ctrl->nand_version < 0x0400) {
-+			ctrl->max_page_size = 4096;
-+			ctrl->max_block_size = 512 * 1024;
-+		}
-+	}
-+
-+	/* Maximum spare area sector size (per 512B) */
-+	if (ctrl->nand_version >= 0x0702)
-+		ctrl->max_oob = 128;
-+	else if (ctrl->nand_version >= 0x0600)
-+		ctrl->max_oob = 64;
-+	else if (ctrl->nand_version >= 0x0500)
-+		ctrl->max_oob = 32;
-+	else
-+		ctrl->max_oob = 16;
-+
-+	/* v6.0 and newer (except v6.1) have prefetch support */
-+	if (ctrl->nand_version >= 0x0600 && ctrl->nand_version != 0x0601)
-+		ctrl->features |= BRCMNAND_HAS_PREFETCH;
-+
-+	/*
-+	 * v6.x has cache mode, but it's implemented differently. Ignore it for
-+	 * now.
-+	 */
-+	if (ctrl->nand_version >= 0x0700)
-+		ctrl->features |= BRCMNAND_HAS_CACHE_MODE;
-+
-+	if (ctrl->nand_version >= 0x0500)
-+		ctrl->features |= BRCMNAND_HAS_1K_SECTORS;
-+
-+	if (ctrl->nand_version >= 0x0700)
-+		ctrl->features |= BRCMNAND_HAS_WP;
-+#ifndef __UBOOT__
-+	else if (of_property_read_bool(ctrl->dev->of_node, "brcm,nand-has-wp"))
-+#else
-+	else if (dev_read_bool(ctrl->dev, "brcm,nand-has-wp"))
-+#endif /* __UBOOT__ */
-+		ctrl->features |= BRCMNAND_HAS_WP;
-+
-+	return 0;
-+}
-+
-+static inline u32 brcmnand_read_reg(struct brcmnand_controller *ctrl,
-+		enum brcmnand_reg reg)
-+{
-+	u16 offs = ctrl->reg_offsets[reg];
-+
-+	if (offs)
-+		return nand_readreg(ctrl, offs);
-+	else
-+		return 0;
-+}
-+
-+static inline void brcmnand_write_reg(struct brcmnand_controller *ctrl,
-+				      enum brcmnand_reg reg, u32 val)
-+{
-+	u16 offs = ctrl->reg_offsets[reg];
-+
-+	if (offs)
-+		nand_writereg(ctrl, offs, val);
-+}
-+
-+static inline void brcmnand_rmw_reg(struct brcmnand_controller *ctrl,
-+				    enum brcmnand_reg reg, u32 mask, unsigned
-+				    int shift, u32 val)
-+{
-+	u32 tmp = brcmnand_read_reg(ctrl, reg);
-+
-+	tmp &= ~mask;
-+	tmp |= val << shift;
-+	brcmnand_write_reg(ctrl, reg, tmp);
-+}
-+
-+static inline u32 brcmnand_read_fc(struct brcmnand_controller *ctrl, int word)
-+{
-+	return __raw_readl(ctrl->nand_fc + word * 4);
-+}
-+
-+static inline void brcmnand_write_fc(struct brcmnand_controller *ctrl,
-+				     int word, u32 val)
-+{
-+	__raw_writel(val, ctrl->nand_fc + word * 4);
-+}
-+
-+static inline u16 brcmnand_cs_offset(struct brcmnand_controller *ctrl, int cs,
-+				     enum brcmnand_cs_reg reg)
-+{
-+	u16 offs_cs0 = ctrl->reg_offsets[BRCMNAND_CS0_BASE];
-+	u16 offs_cs1 = ctrl->reg_offsets[BRCMNAND_CS1_BASE];
-+	u8 cs_offs;
-+
-+	if (cs == 0 && ctrl->cs0_offsets)
-+		cs_offs = ctrl->cs0_offsets[reg];
-+	else
-+		cs_offs = ctrl->cs_offsets[reg];
-+
-+	if (cs && offs_cs1)
-+		return offs_cs1 + (cs - 1) * ctrl->reg_spacing + cs_offs;
-+
-+	return offs_cs0 + cs * ctrl->reg_spacing + cs_offs;
-+}
-+
-+static inline u32 brcmnand_count_corrected(struct brcmnand_controller *ctrl)
-+{
-+	if (ctrl->nand_version < 0x0600)
-+		return 1;
-+	return brcmnand_read_reg(ctrl, BRCMNAND_CORR_COUNT);
-+}
-+
-+static void brcmnand_wr_corr_thresh(struct brcmnand_host *host, u8 val)
-+{
-+	struct brcmnand_controller *ctrl = host->ctrl;
-+	unsigned int shift = 0, bits;
-+	enum brcmnand_reg reg = BRCMNAND_CORR_THRESHOLD;
-+	int cs = host->cs;
-+
-+	if (ctrl->nand_version >= 0x0702)
-+		bits = 7;
-+	else if (ctrl->nand_version >= 0x0600)
-+		bits = 6;
-+	else if (ctrl->nand_version >= 0x0500)
-+		bits = 5;
-+	else
-+		bits = 4;
-+
-+	if (ctrl->nand_version >= 0x0702) {
-+		if (cs >= 4)
-+			reg = BRCMNAND_CORR_THRESHOLD_EXT;
-+		shift = (cs % 4) * bits;
-+	} else if (ctrl->nand_version >= 0x0600) {
-+		if (cs >= 5)
-+			reg = BRCMNAND_CORR_THRESHOLD_EXT;
-+		shift = (cs % 5) * bits;
-+	}
-+	brcmnand_rmw_reg(ctrl, reg, (bits - 1) << shift, shift, val);
-+}
-+
-+static inline int brcmnand_cmd_shift(struct brcmnand_controller *ctrl)
-+{
-+	if (ctrl->nand_version < 0x0602)
-+		return 24;
-+	return 0;
-+}
-+
-+/***********************************************************************
-+ * NAND ACC CONTROL bitfield
-+ *
-+ * Some bits have remained constant throughout hardware revision, while
-+ * others have shifted around.
-+ ***********************************************************************/
-+
-+/* Constant for all versions (where supported) */
-+enum {
-+	/* See BRCMNAND_HAS_CACHE_MODE */
-+	ACC_CONTROL_CACHE_MODE				= BIT(22),
-+
-+	/* See BRCMNAND_HAS_PREFETCH */
-+	ACC_CONTROL_PREFETCH				= BIT(23),
-+
-+	ACC_CONTROL_PAGE_HIT				= BIT(24),
-+	ACC_CONTROL_WR_PREEMPT				= BIT(25),
-+	ACC_CONTROL_PARTIAL_PAGE			= BIT(26),
-+	ACC_CONTROL_RD_ERASED				= BIT(27),
-+	ACC_CONTROL_FAST_PGM_RDIN			= BIT(28),
-+	ACC_CONTROL_WR_ECC				= BIT(30),
-+	ACC_CONTROL_RD_ECC				= BIT(31),
-+};
-+
-+static inline u32 brcmnand_spare_area_mask(struct brcmnand_controller *ctrl)
-+{
-+	if (ctrl->nand_version >= 0x0702)
-+		return GENMASK(7, 0);
-+	else if (ctrl->nand_version >= 0x0600)
-+		return GENMASK(6, 0);
-+	else
-+		return GENMASK(5, 0);
-+}
-+
-+#define NAND_ACC_CONTROL_ECC_SHIFT	16
-+#define NAND_ACC_CONTROL_ECC_EXT_SHIFT	13
-+
-+static inline u32 brcmnand_ecc_level_mask(struct brcmnand_controller *ctrl)
-+{
-+	u32 mask = (ctrl->nand_version >= 0x0600) ? 0x1f : 0x0f;
-+
-+	mask <<= NAND_ACC_CONTROL_ECC_SHIFT;
-+
-+	/* v7.2 includes additional ECC levels */
-+	if (ctrl->nand_version >= 0x0702)
-+		mask |= 0x7 << NAND_ACC_CONTROL_ECC_EXT_SHIFT;
-+
-+	return mask;
-+}
-+
-+static void brcmnand_set_ecc_enabled(struct brcmnand_host *host, int en)
-+{
-+	struct brcmnand_controller *ctrl = host->ctrl;
-+	u16 offs = brcmnand_cs_offset(ctrl, host->cs, BRCMNAND_CS_ACC_CONTROL);
-+	u32 acc_control = nand_readreg(ctrl, offs);
-+	u32 ecc_flags = ACC_CONTROL_WR_ECC | ACC_CONTROL_RD_ECC;
-+
-+	if (en) {
-+		acc_control |= ecc_flags; /* enable RD/WR ECC */
-+		acc_control |= host->hwcfg.ecc_level
-+			       << NAND_ACC_CONTROL_ECC_SHIFT;
-+	} else {
-+		acc_control &= ~ecc_flags; /* disable RD/WR ECC */
-+		acc_control &= ~brcmnand_ecc_level_mask(ctrl);
-+	}
-+
-+	nand_writereg(ctrl, offs, acc_control);
-+}
-+
-+static inline int brcmnand_sector_1k_shift(struct brcmnand_controller *ctrl)
-+{
-+	if (ctrl->nand_version >= 0x0702)
-+		return 9;
-+	else if (ctrl->nand_version >= 0x0600)
-+		return 7;
-+	else if (ctrl->nand_version >= 0x0500)
-+		return 6;
-+	else
-+		return -1;
-+}
-+
-+static int brcmnand_get_sector_size_1k(struct brcmnand_host *host)
-+{
-+	struct brcmnand_controller *ctrl = host->ctrl;
-+	int shift = brcmnand_sector_1k_shift(ctrl);
-+	u16 acc_control_offs = brcmnand_cs_offset(ctrl, host->cs,
-+						  BRCMNAND_CS_ACC_CONTROL);
-+
-+	if (shift < 0)
-+		return 0;
-+
-+	return (nand_readreg(ctrl, acc_control_offs) >> shift) & 0x1;
-+}
-+
-+static void brcmnand_set_sector_size_1k(struct brcmnand_host *host, int val)
-+{
-+	struct brcmnand_controller *ctrl = host->ctrl;
-+	int shift = brcmnand_sector_1k_shift(ctrl);
-+	u16 acc_control_offs = brcmnand_cs_offset(ctrl, host->cs,
-+						  BRCMNAND_CS_ACC_CONTROL);
-+	u32 tmp;
-+
-+	if (shift < 0)
-+		return;
-+
-+	tmp = nand_readreg(ctrl, acc_control_offs);
-+	tmp &= ~(1 << shift);
-+	tmp |= (!!val) << shift;
-+	nand_writereg(ctrl, acc_control_offs, tmp);
-+}
-+
-+/***********************************************************************
-+ * CS_NAND_SELECT
-+ ***********************************************************************/
-+
-+enum {
-+	CS_SELECT_NAND_WP			= BIT(29),
-+	CS_SELECT_AUTO_DEVICE_ID_CFG		= BIT(30),
-+};
-+
-+static int bcmnand_ctrl_poll_status(struct brcmnand_controller *ctrl,
-+				    u32 mask, u32 expected_val,
-+				    unsigned long timeout_ms)
-+{
-+#ifndef __UBOOT__
-+	unsigned long limit;
-+	u32 val;
-+
-+	if (!timeout_ms)
-+		timeout_ms = NAND_POLL_STATUS_TIMEOUT_MS;
-+
-+	limit = jiffies + msecs_to_jiffies(timeout_ms);
-+	do {
-+		val = brcmnand_read_reg(ctrl, BRCMNAND_INTFC_STATUS);
-+		if ((val & mask) == expected_val)
-+			return 0;
-+
-+		cpu_relax();
-+	} while (time_after(limit, jiffies));
-+#else
-+	unsigned long base, limit;
-+	u32 val;
-+
-+	if (!timeout_ms)
-+		timeout_ms = NAND_POLL_STATUS_TIMEOUT_MS;
-+
-+	base = get_timer(0);
-+	limit = CONFIG_SYS_HZ * timeout_ms / 1000;
-+	do {
-+		val = brcmnand_read_reg(ctrl, BRCMNAND_INTFC_STATUS);
-+		if ((val & mask) == expected_val)
-+			return 0;
-+
-+		cpu_relax();
-+	} while (get_timer(base) < limit);
-+#endif /* __UBOOT__ */
-+
-+	dev_warn(ctrl->dev, "timeout on status poll (expected %x got %x)\n",
-+		 expected_val, val & mask);
-+
-+	return -ETIMEDOUT;
-+}
-+
-+static inline void brcmnand_set_wp(struct brcmnand_controller *ctrl, bool en)
-+{
-+	u32 val = en ? CS_SELECT_NAND_WP : 0;
-+
-+	brcmnand_rmw_reg(ctrl, BRCMNAND_CS_SELECT, CS_SELECT_NAND_WP, 0, val);
-+}
-+
-+/***********************************************************************
-+ * Flash DMA
-+ ***********************************************************************/
-+
-+enum flash_dma_reg {
-+	FLASH_DMA_REVISION		= 0x00,
-+	FLASH_DMA_FIRST_DESC		= 0x04,
-+	FLASH_DMA_FIRST_DESC_EXT	= 0x08,
-+	FLASH_DMA_CTRL			= 0x0c,
-+	FLASH_DMA_MODE			= 0x10,
-+	FLASH_DMA_STATUS		= 0x14,
-+	FLASH_DMA_INTERRUPT_DESC	= 0x18,
-+	FLASH_DMA_INTERRUPT_DESC_EXT	= 0x1c,
-+	FLASH_DMA_ERROR_STATUS		= 0x20,
-+	FLASH_DMA_CURRENT_DESC		= 0x24,
-+	FLASH_DMA_CURRENT_DESC_EXT	= 0x28,
-+};
-+
-+static inline bool has_flash_dma(struct brcmnand_controller *ctrl)
-+{
-+	return ctrl->flash_dma_base;
-+}
-+
-+static inline bool flash_dma_buf_ok(const void *buf)
-+{
-+#ifndef __UBOOT__
-+	return buf && !is_vmalloc_addr(buf) &&
-+		likely(IS_ALIGNED((uintptr_t)buf, 4));
-+#else
-+	return buf && likely(IS_ALIGNED((uintptr_t)buf, 4));
-+#endif /* __UBOOT__ */
-+}
-+
-+static inline void flash_dma_writel(struct brcmnand_controller *ctrl, u8 offs,
-+				    u32 val)
-+{
-+	brcmnand_writel(val, ctrl->flash_dma_base + offs);
-+}
-+
-+static inline u32 flash_dma_readl(struct brcmnand_controller *ctrl, u8 offs)
-+{
-+	return brcmnand_readl(ctrl->flash_dma_base + offs);
-+}
-+
-+/* Low-level operation types: command, address, write, or read */
-+enum brcmnand_llop_type {
-+	LL_OP_CMD,
-+	LL_OP_ADDR,
-+	LL_OP_WR,
-+	LL_OP_RD,
-+};
-+
-+/***********************************************************************
-+ * Internal support functions
-+ ***********************************************************************/
-+
-+static inline bool is_hamming_ecc(struct brcmnand_controller *ctrl,
-+				  struct brcmnand_cfg *cfg)
-+{
-+	if (ctrl->nand_version <= 0x0701)
-+		return cfg->sector_size_1k == 0 && cfg->spare_area_size == 16 &&
-+			cfg->ecc_level == 15;
-+	else
-+		return cfg->sector_size_1k == 0 && ((cfg->spare_area_size == 16 &&
-+			cfg->ecc_level == 15) ||
-+			(cfg->spare_area_size == 28 && cfg->ecc_level == 16));
-+}
-+
-+/*
-+ * Set mtd->ooblayout to the appropriate mtd_ooblayout_ops given
-+ * the layout/configuration.
-+ * Returns -ERRCODE on failure.
-+ */
-+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 brcmnand_host *host = nand_get_controller_data(chip);
-+	struct brcmnand_cfg *cfg = &host->hwcfg;
-+	int sas = cfg->spare_area_size << cfg->sector_size_1k;
-+	int sectors = cfg->page_size / (512 << cfg->sector_size_1k);
-+
-+	if (section >= sectors)
-+		return -ERANGE;
-+
-+	oobregion->offset = (section * sas) + 6;
-+	oobregion->length = 3;
-+
-+	return 0;
-+}
-+
-+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 brcmnand_host *host = nand_get_controller_data(chip);
-+	struct brcmnand_cfg *cfg = &host->hwcfg;
-+	int sas = cfg->spare_area_size << cfg->sector_size_1k;
-+	int sectors = cfg->page_size / (512 << cfg->sector_size_1k);
-+
-+	if (section >= sectors * 2)
-+		return -ERANGE;
-+
-+	oobregion->offset = (section / 2) * sas;
-+
-+	if (section & 1) {
-+		oobregion->offset += 9;
-+		oobregion->length = 7;
-+	} else {
-+		oobregion->length = 6;
-+
-+		/* First sector of each page may have BBI */
-+		if (!section) {
-+			/*
-+			 * Small-page NAND use byte 6 for BBI while large-page
-+			 * NAND use byte 0.
-+			 */
-+			if (cfg->page_size > 512)
-+				oobregion->offset++;
-+			oobregion->length--;
-+		}
-+	}
-+
-+	return 0;
-+}
-+
-+static const struct mtd_ooblayout_ops brcmnand_hamming_ooblayout_ops = {
-+	.ecc = brcmnand_hamming_ooblayout_ecc,
-+	.free = brcmnand_hamming_ooblayout_free,
-+};
-+
-+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 brcmnand_host *host = nand_get_controller_data(chip);
-+	struct brcmnand_cfg *cfg = &host->hwcfg;
-+	int sas = cfg->spare_area_size << cfg->sector_size_1k;
-+	int sectors = cfg->page_size / (512 << cfg->sector_size_1k);
-+
-+	if (section >= sectors)
-+		return -ERANGE;
-+
-+	oobregion->offset = (section * (sas + 1)) - chip->ecc.bytes;
-+	oobregion->length = chip->ecc.bytes;
-+
-+	return 0;
-+}
-+
-+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 brcmnand_host *host = nand_get_controller_data(chip);
-+	struct brcmnand_cfg *cfg = &host->hwcfg;
-+	int sas = cfg->spare_area_size << cfg->sector_size_1k;
-+	int sectors = cfg->page_size / (512 << cfg->sector_size_1k);
-+
-+	if (section >= sectors)
-+		return -ERANGE;
-+
-+	if (sas <= chip->ecc.bytes)
-+		return 0;
-+
-+	oobregion->offset = section * sas;
-+	oobregion->length = sas - chip->ecc.bytes;
-+
-+	if (!section) {
-+		oobregion->offset++;
-+		oobregion->length--;
-+	}
-+
-+	return 0;
-+}
-+
-+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 brcmnand_host *host = nand_get_controller_data(chip);
-+	struct brcmnand_cfg *cfg = &host->hwcfg;
-+	int sas = cfg->spare_area_size << cfg->sector_size_1k;
-+
-+	if (section > 1 || sas - chip->ecc.bytes < 6 ||
-+	    (section && sas - chip->ecc.bytes == 6))
-+		return -ERANGE;
-+
-+	if (!section) {
-+		oobregion->offset = 0;
-+		oobregion->length = 5;
-+	} else {
-+		oobregion->offset = 6;
-+		oobregion->length = sas - chip->ecc.bytes - 6;
-+	}
-+
-+	return 0;
-+}
-+
-+static const struct mtd_ooblayout_ops brcmnand_bch_lp_ooblayout_ops = {
-+	.ecc = brcmnand_bch_ooblayout_ecc,
-+	.free = brcmnand_bch_ooblayout_free_lp,
-+};
-+
-+static const struct mtd_ooblayout_ops brcmnand_bch_sp_ooblayout_ops = {
-+	.ecc = brcmnand_bch_ooblayout_ecc,
-+	.free = brcmnand_bch_ooblayout_free_sp,
-+};
-+
-+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 nand_ecc_ctrl *ecc = &host->chip.ecc;
-+	unsigned int ecc_level = p->ecc_level;
-+	int sas = p->spare_area_size << p->sector_size_1k;
-+	int sectors = p->page_size / (512 << p->sector_size_1k);
-+
-+	if (p->sector_size_1k)
-+		ecc_level <<= 1;
-+
-+	if (is_hamming_ecc(host->ctrl, p)) {
-+		ecc->bytes = 3 * sectors;
-+		mtd_set_ooblayout(mtd, &brcmnand_hamming_ooblayout_ops);
-+		return 0;
-+	}
-+
-+	/*
-+	 * CONTROLLER_VERSION:
-+	 *   < v5.0: ECC_REQ = ceil(BCH_T * 13/8)
-+	 *  >= v5.0: ECC_REQ = ceil(BCH_T * 14/8)
-+	 * But we will just be conservative.
-+	 */
-+	ecc->bytes = DIV_ROUND_UP(ecc_level * 14, 8);
-+	if (p->page_size == 512)
-+		mtd_set_ooblayout(mtd, &brcmnand_bch_sp_ooblayout_ops);
-+	else
-+		mtd_set_ooblayout(mtd, &brcmnand_bch_lp_ooblayout_ops);
-+
-+	if (ecc->bytes >= sas) {
-+		dev_err(&host->pdev->dev,
-+			"error: ECC too large for OOB (ECC bytes %d, spare sector %d)\n",
-+			ecc->bytes, sas);
-+		return -EINVAL;
-+	}
-+
-+	return 0;
-+}
-+
-+static void brcmnand_wp(struct mtd_info *mtd, int wp)
-+{
-+	struct nand_chip *chip = mtd_to_nand(mtd);
-+	struct brcmnand_host *host = nand_get_controller_data(chip);
-+	struct brcmnand_controller *ctrl = host->ctrl;
-+
-+	if ((ctrl->features & BRCMNAND_HAS_WP) && wp_on == 1) {
-+		static int old_wp = -1;
-+		int ret;
-+
-+		if (old_wp != wp) {
-+			dev_dbg(ctrl->dev, "WP %s\n", wp ? "on" : "off");
-+			old_wp = wp;
-+		}
-+
-+		/*
-+		 * make sure ctrl/flash ready before and after
-+		 * changing state of #WP pin
-+		 */
-+		ret = bcmnand_ctrl_poll_status(ctrl, NAND_CTRL_RDY |
-+					       NAND_STATUS_READY,
-+					       NAND_CTRL_RDY |
-+					       NAND_STATUS_READY, 0);
-+		if (ret)
-+			return;
-+
-+		brcmnand_set_wp(ctrl, wp);
-+		nand_status_op(chip, NULL);
-+		/* NAND_STATUS_WP 0x00 = protected, 0x80 = not protected */
-+		ret = bcmnand_ctrl_poll_status(ctrl,
-+					       NAND_CTRL_RDY |
-+					       NAND_STATUS_READY |
-+					       NAND_STATUS_WP,
-+					       NAND_CTRL_RDY |
-+					       NAND_STATUS_READY |
-+					       (wp ? 0 : NAND_STATUS_WP), 0);
-+#ifndef __UBOOT__
-+		if (ret)
-+			dev_err_ratelimited(&host->pdev->dev,
-+					    "nand #WP expected %s\n",
-+					    wp ? "on" : "off");
-+#else
-+		if (ret)
-+			dev_err(&host->pdev->dev,
-+					    "nand #WP expected %s\n",
-+					    wp ? "on" : "off");
-+#endif /* __UBOOT__ */
-+	}
-+}
-+
-+/* Helper functions for reading and writing OOB registers */
-+static inline u8 oob_reg_read(struct brcmnand_controller *ctrl, u32 offs)
-+{
-+	u16 offset0, offset10, reg_offs;
-+
-+	offset0 = ctrl->reg_offsets[BRCMNAND_OOB_READ_BASE];
-+	offset10 = ctrl->reg_offsets[BRCMNAND_OOB_READ_10_BASE];
-+
-+	if (offs >= ctrl->max_oob)
-+		return 0x77;
-+
-+	if (offs >= 16 && offset10)
-+		reg_offs = offset10 + ((offs - 0x10) & ~0x03);
-+	else
-+		reg_offs = offset0 + (offs & ~0x03);
-+
-+	return nand_readreg(ctrl, reg_offs) >> (24 - ((offs & 0x03) << 3));
-+}
-+
-+static inline void oob_reg_write(struct brcmnand_controller *ctrl, u32 offs,
-+				 u32 data)
-+{
-+	u16 offset0, offset10, reg_offs;
-+
-+	offset0 = ctrl->reg_offsets[BRCMNAND_OOB_WRITE_BASE];
-+	offset10 = ctrl->reg_offsets[BRCMNAND_OOB_WRITE_10_BASE];
-+
-+	if (offs >= ctrl->max_oob)
-+		return;
-+
-+	if (offs >= 16 && offset10)
-+		reg_offs = offset10 + ((offs - 0x10) & ~0x03);
-+	else
-+		reg_offs = offset0 + (offs & ~0x03);
-+
-+	nand_writereg(ctrl, reg_offs, data);
-+}
-+
-+/*
-+ * read_oob_from_regs - read data from OOB registers
-+ * @ctrl: NAND controller
-+ * @i: sub-page sector index
-+ * @oob: buffer to read to
-+ * @sas: spare area sector size (i.e., OOB size per FLASH_CACHE)
-+ * @sector_1k: 1 for 1KiB sectors, 0 for 512B, other values are illegal
-+ */
-+static int read_oob_from_regs(struct brcmnand_controller *ctrl, int i, u8 *oob,
-+			      int sas, int sector_1k)
-+{
-+	int tbytes = sas << sector_1k;
-+	int j;
-+
-+	/* Adjust OOB values for 1K sector size */
-+	if (sector_1k && (i & 0x01))
-+		tbytes = max(0, tbytes - (int)ctrl->max_oob);
-+	tbytes = min_t(int, tbytes, ctrl->max_oob);
-+
-+	for (j = 0; j < tbytes; j++)
-+		oob[j] = oob_reg_read(ctrl, j);
-+	return tbytes;
-+}
-+
-+/*
-+ * write_oob_to_regs - write data to OOB registers
-+ * @i: sub-page sector index
-+ * @oob: buffer to write from
-+ * @sas: spare area sector size (i.e., OOB size per FLASH_CACHE)
-+ * @sector_1k: 1 for 1KiB sectors, 0 for 512B, other values are illegal
-+ */
-+static int write_oob_to_regs(struct brcmnand_controller *ctrl, int i,
-+			     const u8 *oob, int sas, int sector_1k)
-+{
-+	int tbytes = sas << sector_1k;
-+	int j;
-+
-+	/* Adjust OOB values for 1K sector size */
-+	if (sector_1k && (i & 0x01))
-+		tbytes = max(0, tbytes - (int)ctrl->max_oob);
-+	tbytes = min_t(int, tbytes, ctrl->max_oob);
-+
-+	for (j = 0; j < tbytes; j += 4)
-+		oob_reg_write(ctrl, j,
-+				(oob[j + 0] << 24) |
-+				(oob[j + 1] << 16) |
-+				(oob[j + 2] <<  8) |
-+				(oob[j + 3] <<  0));
-+	return tbytes;
-+}
-+
-+#ifndef __UBOOT__
-+static irqreturn_t brcmnand_ctlrdy_irq(int irq, void *data)
-+{
-+	struct brcmnand_controller *ctrl = data;
-+
-+	/* Discard all NAND_CTLRDY interrupts during DMA */
-+	if (ctrl->dma_pending)
-+		return IRQ_HANDLED;
-+
-+	complete(&ctrl->done);
-+	return IRQ_HANDLED;
-+}
-+
-+/* Handle SoC-specific interrupt hardware */
-+static irqreturn_t brcmnand_irq(int irq, void *data)
-+{
-+	struct brcmnand_controller *ctrl = data;
-+
-+	if (ctrl->soc->ctlrdy_ack(ctrl->soc))
-+		return brcmnand_ctlrdy_irq(irq, data);
-+
-+	return IRQ_NONE;
-+}
-+
-+static irqreturn_t brcmnand_dma_irq(int irq, void *data)
-+{
-+	struct brcmnand_controller *ctrl = data;
-+
-+	complete(&ctrl->dma_done);
-+
-+	return IRQ_HANDLED;
-+}
-+#endif /* __UBOOT__ */
-+
-+static void brcmnand_send_cmd(struct brcmnand_host *host, int cmd)
-+{
-+	struct brcmnand_controller *ctrl = host->ctrl;
-+	int ret;
-+
-+	dev_dbg(ctrl->dev, "send native cmd %d addr_lo 0x%x\n", cmd,
-+		brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS));
-+	BUG_ON(ctrl->cmd_pending != 0);
-+	ctrl->cmd_pending = cmd;
-+
-+	ret = bcmnand_ctrl_poll_status(ctrl, NAND_CTRL_RDY, NAND_CTRL_RDY, 0);
-+	WARN_ON(ret);
-+
-+	mb(); /* flush previous writes */
-+	brcmnand_write_reg(ctrl, BRCMNAND_CMD_START,
-+			   cmd << brcmnand_cmd_shift(ctrl));
-+}
-+
-+/***********************************************************************
-+ * NAND MTD API: read/program/erase
-+ ***********************************************************************/
-+
-+static void brcmnand_cmd_ctrl(struct mtd_info *mtd, int dat,
-+	unsigned int ctrl)
-+{
-+	/* intentionally left blank */
-+}
-+
-+static int brcmnand_waitfunc(struct mtd_info *mtd, struct nand_chip *this)
-+{
-+	struct nand_chip *chip = mtd_to_nand(mtd);
-+	struct brcmnand_host *host = nand_get_controller_data(chip);
-+	struct brcmnand_controller *ctrl = host->ctrl;
-+
-+#ifndef __UBOOT__
-+	unsigned long timeo = msecs_to_jiffies(100);
-+
-+	dev_dbg(ctrl->dev, "wait on native cmd %d\n", ctrl->cmd_pending);
-+	if (ctrl->cmd_pending &&
-+			wait_for_completion_timeout(&ctrl->done, timeo) <= 0) {
-+		u32 cmd = brcmnand_read_reg(ctrl, BRCMNAND_CMD_START)
-+					>> brcmnand_cmd_shift(ctrl);
-+
-+		dev_err_ratelimited(ctrl->dev,
-+			"timeout waiting for command %#02x\n", cmd);
-+		dev_err_ratelimited(ctrl->dev, "intfc status %08x\n",
-+			brcmnand_read_reg(ctrl, BRCMNAND_INTFC_STATUS));
-+	}
-+#else
-+	unsigned long timeo = 100; /* 100 msec */
-+	int ret;
-+
-+	dev_dbg(ctrl->dev, "wait on native cmd %d\n", ctrl->cmd_pending);
-+
-+	ret = bcmnand_ctrl_poll_status(ctrl, NAND_CTRL_RDY, NAND_CTRL_RDY, timeo);
-+	WARN_ON(ret);
-+#endif /* __UBOOT__ */
-+
-+	ctrl->cmd_pending = 0;
-+	return brcmnand_read_reg(ctrl, BRCMNAND_INTFC_STATUS) &
-+				 INTFC_FLASH_STATUS;
-+}
-+
-+enum {
-+	LLOP_RE				= BIT(16),
-+	LLOP_WE				= BIT(17),
-+	LLOP_ALE			= BIT(18),
-+	LLOP_CLE			= BIT(19),
-+	LLOP_RETURN_IDLE		= BIT(31),
-+
-+	LLOP_DATA_MASK			= GENMASK(15, 0),
-+};
-+
-+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 nand_chip *chip = &host->chip;
-+	struct brcmnand_controller *ctrl = host->ctrl;
-+	u32 tmp;
-+
-+	tmp = data & LLOP_DATA_MASK;
-+	switch (type) {
-+	case LL_OP_CMD:
-+		tmp |= LLOP_WE | LLOP_CLE;
-+		break;
-+	case LL_OP_ADDR:
-+		/* WE | ALE */
-+		tmp |= LLOP_WE | LLOP_ALE;
-+		break;
-+	case LL_OP_WR:
-+		/* WE */
-+		tmp |= LLOP_WE;
-+		break;
-+	case LL_OP_RD:
-+		/* RE */
-+		tmp |= LLOP_RE;
-+		break;
-+	}
-+	if (last_op)
-+		/* RETURN_IDLE */
-+		tmp |= LLOP_RETURN_IDLE;
-+
-+	dev_dbg(ctrl->dev, "ll_op cmd %#x\n", tmp);
-+
-+	brcmnand_write_reg(ctrl, BRCMNAND_LL_OP, tmp);
-+	(void)brcmnand_read_reg(ctrl, BRCMNAND_LL_OP);
-+
-+	brcmnand_send_cmd(host, CMD_LOW_LEVEL_OP);
-+	return brcmnand_waitfunc(mtd, chip);
-+}
-+
-+static void brcmnand_cmdfunc(struct mtd_info *mtd, unsigned command,
-+			     int column, int page_addr)
-+{
-+	struct nand_chip *chip = mtd_to_nand(mtd);
-+	struct brcmnand_host *host = nand_get_controller_data(chip);
-+	struct brcmnand_controller *ctrl = host->ctrl;
-+	u64 addr = (u64)page_addr << chip->page_shift;
-+	int native_cmd = 0;
-+
-+	if (command == NAND_CMD_READID || command == NAND_CMD_PARAM ||
-+			command == NAND_CMD_RNDOUT)
-+		addr = (u64)column;
-+	/* Avoid propagating a negative, don't-care address */
-+	else if (page_addr < 0)
-+		addr = 0;
-+
-+	dev_dbg(ctrl->dev, "cmd 0x%x addr 0x%llx\n", command,
-+		(unsigned long long)addr);
-+
-+	host->last_cmd = command;
-+	host->last_byte = 0;
-+	host->last_addr = addr;
-+
-+	switch (command) {
-+	case NAND_CMD_RESET:
-+		native_cmd = CMD_FLASH_RESET;
-+		break;
-+	case NAND_CMD_STATUS:
-+		native_cmd = CMD_STATUS_READ;
-+		break;
-+	case NAND_CMD_READID:
-+		native_cmd = CMD_DEVICE_ID_READ;
-+		break;
-+	case NAND_CMD_READOOB:
-+		native_cmd = CMD_SPARE_AREA_READ;
-+		break;
-+	case NAND_CMD_ERASE1:
-+		native_cmd = CMD_BLOCK_ERASE;
-+		brcmnand_wp(mtd, 0);
-+		break;
-+	case NAND_CMD_PARAM:
-+		native_cmd = CMD_PARAMETER_READ;
-+		break;
-+	case NAND_CMD_SET_FEATURES:
-+	case NAND_CMD_GET_FEATURES:
-+		brcmnand_low_level_op(host, LL_OP_CMD, command, false);
-+		brcmnand_low_level_op(host, LL_OP_ADDR, column, false);
-+		break;
-+	case NAND_CMD_RNDOUT:
-+		native_cmd = CMD_PARAMETER_CHANGE_COL;
-+		addr &= ~((u64)(FC_BYTES - 1));
-+		/*
-+		 * HW quirk: PARAMETER_CHANGE_COL requires SECTOR_SIZE_1K=0
-+		 * NB: hwcfg.sector_size_1k may not be initialized yet
-+		 */
-+		if (brcmnand_get_sector_size_1k(host)) {
-+			host->hwcfg.sector_size_1k =
-+				brcmnand_get_sector_size_1k(host);
-+			brcmnand_set_sector_size_1k(host, 0);
-+		}
-+		break;
-+	}
-+
-+	if (!native_cmd)
-+		return;
-+
-+	brcmnand_write_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS,
-+		(host->cs << 16) | ((addr >> 32) & 0xffff));
-+	(void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS);
-+	brcmnand_write_reg(ctrl, BRCMNAND_CMD_ADDRESS, lower_32_bits(addr));
-+	(void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS);
-+
-+	brcmnand_send_cmd(host, native_cmd);
-+	brcmnand_waitfunc(mtd, chip);
-+
-+	if (native_cmd == CMD_PARAMETER_READ ||
-+			native_cmd == CMD_PARAMETER_CHANGE_COL) {
-+		/* Copy flash cache word-wise */
-+		u32 *flash_cache = (u32 *)ctrl->flash_cache;
-+		int i;
-+
-+		brcmnand_soc_data_bus_prepare(ctrl->soc, true);
-+
-+		/*
-+		 * Must cache the FLASH_CACHE now, since changes in
-+		 * SECTOR_SIZE_1K may invalidate it
-+		 */
-+		for (i = 0; i < FC_WORDS; i++) {
-+			u32 fc;
-+
-+			fc = brcmnand_read_fc(ctrl, i);
-+
-+			/*
-+			 * Flash cache is big endian for parameter pages, at
-+			 * least on STB SoCs
-+			 */
-+			if (ctrl->parameter_page_big_endian)
-+				flash_cache[i] = be32_to_cpu(fc);
-+			else
-+				flash_cache[i] = le32_to_cpu(fc);
-+		}
-+
-+		brcmnand_soc_data_bus_unprepare(ctrl->soc, true);
-+
-+		/* Cleanup from HW quirk: restore SECTOR_SIZE_1K */
-+		if (host->hwcfg.sector_size_1k)
-+			brcmnand_set_sector_size_1k(host,
-+						    host->hwcfg.sector_size_1k);
-+	}
-+
-+	/* Re-enable protection is necessary only after erase */
-+	if (command == NAND_CMD_ERASE1)
-+		brcmnand_wp(mtd, 1);
-+}
-+
-+static uint8_t brcmnand_read_byte(struct mtd_info *mtd)
-+{
-+	struct nand_chip *chip = mtd_to_nand(mtd);
-+	struct brcmnand_host *host = nand_get_controller_data(chip);
-+	struct brcmnand_controller *ctrl = host->ctrl;
-+	uint8_t ret = 0;
-+	int addr, offs;
-+
-+	switch (host->last_cmd) {
-+	case NAND_CMD_READID:
-+		if (host->last_byte < 4)
-+			ret = brcmnand_read_reg(ctrl, BRCMNAND_ID) >>
-+				(24 - (host->last_byte << 3));
-+		else if (host->last_byte < 8)
-+			ret = brcmnand_read_reg(ctrl, BRCMNAND_ID_EXT) >>
-+				(56 - (host->last_byte << 3));
-+		break;
-+
-+	case NAND_CMD_READOOB:
-+		ret = oob_reg_read(ctrl, host->last_byte);
-+		break;
-+
-+	case NAND_CMD_STATUS:
-+		ret = brcmnand_read_reg(ctrl, BRCMNAND_INTFC_STATUS) &
-+					INTFC_FLASH_STATUS;
-+		if (wp_on) /* hide WP status */
-+			ret |= NAND_STATUS_WP;
-+		break;
-+
-+	case NAND_CMD_PARAM:
-+	case NAND_CMD_RNDOUT:
-+		addr = host->last_addr + host->last_byte;
-+		offs = addr & (FC_BYTES - 1);
-+
-+		/* At FC_BYTES boundary, switch to next column */
-+		if (host->last_byte > 0 && offs == 0)
-+			nand_change_read_column_op(chip, addr, NULL, 0, false);
-+
-+		ret = ctrl->flash_cache[offs];
-+		break;
-+	case NAND_CMD_GET_FEATURES:
-+		if (host->last_byte >= ONFI_SUBFEATURE_PARAM_LEN) {
-+			ret = 0;
-+		} else {
-+			bool last = host->last_byte ==
-+				ONFI_SUBFEATURE_PARAM_LEN - 1;
-+			brcmnand_low_level_op(host, LL_OP_RD, 0, last);
-+			ret = brcmnand_read_reg(ctrl, BRCMNAND_LL_RDATA) & 0xff;
-+		}
-+	}
-+
-+	dev_dbg(ctrl->dev, "read byte = 0x%02x\n", ret);
-+	host->last_byte++;
-+
-+	return ret;
-+}
-+
-+static void brcmnand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
-+{
-+	int i;
-+
-+	for (i = 0; i < len; i++, buf++)
-+		*buf = brcmnand_read_byte(mtd);
-+}
-+
-+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 brcmnand_host *host = nand_get_controller_data(chip);
-+
-+	switch (host->last_cmd) {
-+	case NAND_CMD_SET_FEATURES:
-+		for (i = 0; i < len; i++)
-+			brcmnand_low_level_op(host, LL_OP_WR, buf[i],
-+						  (i + 1) == len);
-+		break;
-+	default:
-+		BUG();
-+		break;
-+	}
-+}
-+
-+/**
-+ * Construct a FLASH_DMA descriptor as part of a linked list. You must know the
-+ * following ahead of time:
-+ *  - Is this descriptor the beginning or end of a linked list?
-+ *  - What is the (DMA) address of the next descriptor in the linked list?
-+ */
-+#ifndef __UBOOT__
-+static int brcmnand_fill_dma_desc(struct brcmnand_host *host,
-+				  struct brcm_nand_dma_desc *desc, u64 addr,
-+				  dma_addr_t buf, u32 len, u8 dma_cmd,
-+				  bool begin, bool end,
-+				  dma_addr_t next_desc)
-+{
-+	memset(desc, 0, sizeof(*desc));
-+	/* Descriptors are written in native byte order (wordwise) */
-+	desc->next_desc = lower_32_bits(next_desc);
-+	desc->next_desc_ext = upper_32_bits(next_desc);
-+	desc->cmd_irq = (dma_cmd << 24) |
-+		(end ? (0x03 << 8) : 0) | /* IRQ | STOP */
-+		(!!begin) | ((!!end) << 1); /* head, tail */
-+#ifdef CONFIG_CPU_BIG_ENDIAN
-+	desc->cmd_irq |= 0x01 << 12;
-+#endif
-+	desc->dram_addr = lower_32_bits(buf);
-+	desc->dram_addr_ext = upper_32_bits(buf);
-+	desc->tfr_len = len;
-+	desc->total_len = len;
-+	desc->flash_addr = lower_32_bits(addr);
-+	desc->flash_addr_ext = upper_32_bits(addr);
-+	desc->cs = host->cs;
-+	desc->status_valid = 0x01;
-+	return 0;
-+}
-+
-+/**
-+ * Kick the FLASH_DMA engine, with a given DMA descriptor
-+ */
-+static void brcmnand_dma_run(struct brcmnand_host *host, dma_addr_t desc)
-+{
-+	struct brcmnand_controller *ctrl = host->ctrl;
-+	unsigned long timeo = msecs_to_jiffies(100);
-+
-+	flash_dma_writel(ctrl, FLASH_DMA_FIRST_DESC, lower_32_bits(desc));
-+	(void)flash_dma_readl(ctrl, FLASH_DMA_FIRST_DESC);
-+	flash_dma_writel(ctrl, FLASH_DMA_FIRST_DESC_EXT, upper_32_bits(desc));
-+	(void)flash_dma_readl(ctrl, FLASH_DMA_FIRST_DESC_EXT);
-+
-+	/* Start FLASH_DMA engine */
-+	ctrl->dma_pending = true;
-+	mb(); /* flush previous writes */
-+	flash_dma_writel(ctrl, FLASH_DMA_CTRL, 0x03); /* wake | run */
-+
-+	if (wait_for_completion_timeout(&ctrl->dma_done, timeo) <= 0) {
-+		dev_err(ctrl->dev,
-+				"timeout waiting for DMA; status %#x, error status %#x\n",
-+				flash_dma_readl(ctrl, FLASH_DMA_STATUS),
-+				flash_dma_readl(ctrl, FLASH_DMA_ERROR_STATUS));
-+	}
-+	ctrl->dma_pending = false;
-+	flash_dma_writel(ctrl, FLASH_DMA_CTRL, 0); /* force stop */
-+}
-+
-+static int brcmnand_dma_trans(struct brcmnand_host *host, u64 addr, u32 *buf,
-+			      u32 len, u8 dma_cmd)
-+{
-+	struct brcmnand_controller *ctrl = host->ctrl;
-+	dma_addr_t buf_pa;
-+	int dir = dma_cmd == CMD_PAGE_READ ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
-+
-+	buf_pa = dma_map_single(ctrl->dev, buf, len, dir);
-+	if (dma_mapping_error(ctrl->dev, buf_pa)) {
-+		dev_err(ctrl->dev, "unable to map buffer for DMA\n");
-+		return -ENOMEM;
-+	}
-+
-+	brcmnand_fill_dma_desc(host, ctrl->dma_desc, addr, buf_pa, len,
-+				   dma_cmd, true, true, 0);
-+
-+	brcmnand_dma_run(host, ctrl->dma_pa);
-+
-+	dma_unmap_single(ctrl->dev, buf_pa, len, dir);
-+
-+	if (ctrl->dma_desc->status_valid & FLASH_DMA_ECC_ERROR)
-+		return -EBADMSG;
-+	else if (ctrl->dma_desc->status_valid & FLASH_DMA_CORR_ERROR)
-+		return -EUCLEAN;
-+
-+	return 0;
-+}
-+#endif /* __UBOOT__ */
-+
-+/*
-+ * Assumes proper CS is already set
-+ */
-+static int brcmnand_read_by_pio(struct mtd_info *mtd, struct nand_chip *chip,
-+				u64 addr, unsigned int trans, u32 *buf,
-+				u8 *oob, u64 *err_addr)
-+{
-+	struct brcmnand_host *host = nand_get_controller_data(chip);
-+	struct brcmnand_controller *ctrl = host->ctrl;
-+	int i, j, ret = 0;
-+
-+	/* Clear error addresses */
-+	brcmnand_write_reg(ctrl, BRCMNAND_UNCORR_ADDR, 0);
-+	brcmnand_write_reg(ctrl, BRCMNAND_CORR_ADDR, 0);
-+	brcmnand_write_reg(ctrl, BRCMNAND_UNCORR_EXT_ADDR, 0);
-+	brcmnand_write_reg(ctrl, BRCMNAND_CORR_EXT_ADDR, 0);
-+
-+	brcmnand_write_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS,
-+			(host->cs << 16) | ((addr >> 32) & 0xffff));
-+	(void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS);
-+
-+	for (i = 0; i < trans; i++, addr += FC_BYTES) {
-+		brcmnand_write_reg(ctrl, BRCMNAND_CMD_ADDRESS,
-+				   lower_32_bits(addr));
-+		(void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS);
-+		/* SPARE_AREA_READ does not use ECC, so just use PAGE_READ */
-+		brcmnand_send_cmd(host, CMD_PAGE_READ);
-+		brcmnand_waitfunc(mtd, chip);
-+
-+		if (likely(buf)) {
-+			brcmnand_soc_data_bus_prepare(ctrl->soc, false);
-+
-+			for (j = 0; j < FC_WORDS; j++, buf++)
-+				*buf = brcmnand_read_fc(ctrl, j);
-+
-+			brcmnand_soc_data_bus_unprepare(ctrl->soc, false);
-+		}
-+
-+		if (oob)
-+			oob += read_oob_from_regs(ctrl, i, oob,
-+					mtd->oobsize / trans,
-+					host->hwcfg.sector_size_1k);
-+
-+		if (!ret) {
-+			*err_addr = brcmnand_read_reg(ctrl,
-+					BRCMNAND_UNCORR_ADDR) |
-+				((u64)(brcmnand_read_reg(ctrl,
-+						BRCMNAND_UNCORR_EXT_ADDR)
-+					& 0xffff) << 32);
-+			if (*err_addr)
-+				ret = -EBADMSG;
-+		}
-+
-+		if (!ret) {
-+			*err_addr = brcmnand_read_reg(ctrl,
-+					BRCMNAND_CORR_ADDR) |
-+				((u64)(brcmnand_read_reg(ctrl,
-+						BRCMNAND_CORR_EXT_ADDR)
-+					& 0xffff) << 32);
-+			if (*err_addr)
-+				ret = -EUCLEAN;
-+		}
-+	}
-+
-+	return ret;
-+}
-+
-+/*
-+ * Check a page to see if it is erased (w/ bitflips) after an uncorrectable ECC
-+ * error
-+ *
-+ * Because the HW ECC signals an ECC error if an erase paged has even a single
-+ * bitflip, we must check each ECC error to see if it is actually an erased
-+ * page with bitflips, not a truly corrupted page.
-+ *
-+ * On a real error, return a negative error code (-EBADMSG for ECC error), and
-+ * buf will contain raw data.
-+ * Otherwise, buf gets filled with 0xffs and return the maximum number of
-+ * bitflips-per-ECC-sector to the caller.
-+ *
-+ */
-+static int brcmstb_nand_verify_erased_page(struct mtd_info *mtd,
-+		  struct nand_chip *chip, void *buf, u64 addr)
-+{
-+	int i, sas;
-+	void *oob = chip->oob_poi;
-+	int bitflips = 0;
-+	int page = addr >> chip->page_shift;
-+	int ret;
-+
-+	if (!buf) {
-+#ifndef __UBOOT__
-+		buf = chip->data_buf;
-+#else
-+		buf = chip->buffers->databuf;
-+#endif
-+		/* Invalidate page cache */
-+		chip->pagebuf = -1;
-+	}
-+
-+	sas = mtd->oobsize / chip->ecc.steps;
-+
-+	/* read without ecc for verification */
-+	ret = chip->ecc.read_page_raw(mtd, chip, buf, true, page);
-+	if (ret)
-+		return ret;
-+
-+	for (i = 0; i < chip->ecc.steps; i++, oob += sas) {
-+		ret = nand_check_erased_ecc_chunk(buf, chip->ecc.size,
-+						  oob, sas, NULL, 0,
-+						  chip->ecc.strength);
-+		if (ret < 0)
-+			return ret;
-+
-+		bitflips = max(bitflips, ret);
-+	}
-+
-+	return bitflips;
-+}
-+
-+static int brcmnand_read(struct mtd_info *mtd, struct nand_chip *chip,
-+			 u64 addr, unsigned int trans, u32 *buf, u8 *oob)
-+{
-+	struct brcmnand_host *host = nand_get_controller_data(chip);
-+	struct brcmnand_controller *ctrl = host->ctrl;
-+	u64 err_addr = 0;
-+	int err;
-+	bool retry = true;
-+
-+	dev_dbg(ctrl->dev, "read %llx -> %p\n", (unsigned long long)addr, buf);
-+
-+try_dmaread:
-+	brcmnand_write_reg(ctrl, BRCMNAND_UNCORR_COUNT, 0);
-+
-+#ifndef __UBOOT__
-+	if (has_flash_dma(ctrl) && !oob && flash_dma_buf_ok(buf)) {
-+		err = brcmnand_dma_trans(host, addr, buf, trans * FC_BYTES,
-+					     CMD_PAGE_READ);
-+		if (err) {
-+			if (mtd_is_bitflip_or_eccerr(err))
-+				err_addr = addr;
-+			else
-+				return -EIO;
-+		}
-+	} else {
-+		if (oob)
-+			memset(oob, 0x99, mtd->oobsize);
-+
-+		err = brcmnand_read_by_pio(mtd, chip, addr, trans, buf,
-+					       oob, &err_addr);
-+	}
-+#else
-+	if (oob)
-+		memset(oob, 0x99, mtd->oobsize);
-+
-+	err = brcmnand_read_by_pio(mtd, chip, addr, trans, buf,
-+							   oob, &err_addr);
-+#endif /* __UBOOT__ */
-+
-+	if (mtd_is_eccerr(err)) {
-+		/*
-+		 * On controller version and 7.0, 7.1 , DMA read after a
-+		 * prior PIO read that reported uncorrectable error,
-+		 * the DMA engine captures this error following DMA read
-+		 * cleared only on subsequent DMA read, so just retry once
-+		 * to clear a possible false error reported for current DMA
-+		 * read
-+		 */
-+		if ((ctrl->nand_version == 0x0700) ||
-+		    (ctrl->nand_version == 0x0701)) {
-+			if (retry) {
-+				retry = false;
-+				goto try_dmaread;
-+			}
-+		}
-+
-+		/*
-+		 * Controller version 7.2 has hw encoder to detect erased page
-+		 * bitflips, apply sw verification for older controllers only
-+		 */
-+		if (ctrl->nand_version < 0x0702) {
-+			err = brcmstb_nand_verify_erased_page(mtd, chip, buf,
-+							      addr);
-+			/* erased page bitflips corrected */
-+			if (err >= 0)
-+				return err;
-+		}
-+
-+		dev_dbg(ctrl->dev, "uncorrectable error at 0x%llx\n",
-+			(unsigned long long)err_addr);
-+		mtd->ecc_stats.failed++;
-+		/* NAND layer expects zero on ECC errors */
-+		return 0;
-+	}
-+
-+	if (mtd_is_bitflip(err)) {
-+		unsigned int corrected = brcmnand_count_corrected(ctrl);
-+
-+		dev_dbg(ctrl->dev, "corrected error at 0x%llx\n",
-+			(unsigned long long)err_addr);
-+		mtd->ecc_stats.corrected += corrected;
-+		/* Always exceed the software-imposed threshold */
-+		return max(mtd->bitflip_threshold, corrected);
-+	}
-+
-+	return 0;
-+}
-+
-+static int brcmnand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
-+			      uint8_t *buf, int oob_required, int page)
-+{
-+	struct brcmnand_host *host = nand_get_controller_data(chip);
-+	u8 *oob = oob_required ? (u8 *)chip->oob_poi : NULL;
-+
-+	nand_read_page_op(chip, page, 0, NULL, 0);
-+
-+	return brcmnand_read(mtd, chip, host->last_addr,
-+			mtd->writesize >> FC_SHIFT, (u32 *)buf, oob);
-+}
-+
-+static int brcmnand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
-+				  uint8_t *buf, int oob_required, int page)
-+{
-+	struct brcmnand_host *host = nand_get_controller_data(chip);
-+	u8 *oob = oob_required ? (u8 *)chip->oob_poi : NULL;
-+	int ret;
-+
-+	nand_read_page_op(chip, page, 0, NULL, 0);
-+
-+	brcmnand_set_ecc_enabled(host, 0);
-+	ret = brcmnand_read(mtd, chip, host->last_addr,
-+			mtd->writesize >> FC_SHIFT, (u32 *)buf, oob);
-+	brcmnand_set_ecc_enabled(host, 1);
-+	return ret;
-+}
-+
-+static int brcmnand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
-+			     int page)
-+{
-+	return brcmnand_read(mtd, chip, (u64)page << chip->page_shift,
-+			mtd->writesize >> FC_SHIFT,
-+			NULL, (u8 *)chip->oob_poi);
-+}
-+
-+static int brcmnand_read_oob_raw(struct mtd_info *mtd, struct nand_chip *chip,
-+				 int page)
-+{
-+	struct brcmnand_host *host = nand_get_controller_data(chip);
-+
-+	brcmnand_set_ecc_enabled(host, 0);
-+	brcmnand_read(mtd, chip, (u64)page << chip->page_shift,
-+		mtd->writesize >> FC_SHIFT,
-+		NULL, (u8 *)chip->oob_poi);
-+	brcmnand_set_ecc_enabled(host, 1);
-+	return 0;
-+}
-+
-+static int brcmnand_write(struct mtd_info *mtd, struct nand_chip *chip,
-+			  u64 addr, const u32 *buf, u8 *oob)
-+{
-+	struct brcmnand_host *host = nand_get_controller_data(chip);
-+	struct brcmnand_controller *ctrl = host->ctrl;
-+	unsigned int i, j, trans = mtd->writesize >> FC_SHIFT;
-+	int status, ret = 0;
-+
-+	dev_dbg(ctrl->dev, "write %llx <- %p\n", (unsigned long long)addr, buf);
-+
-+	if (unlikely((unsigned long)buf & 0x03)) {
-+		dev_warn(ctrl->dev, "unaligned buffer: %p\n", buf);
-+		buf = (u32 *)((unsigned long)buf & ~0x03);
-+	}
-+
-+	brcmnand_wp(mtd, 0);
-+
-+	for (i = 0; i < ctrl->max_oob; i += 4)
-+		oob_reg_write(ctrl, i, 0xffffffff);
-+
-+#ifndef __UBOOT__
-+	if (has_flash_dma(ctrl) && !oob && flash_dma_buf_ok(buf)) {
-+		if (brcmnand_dma_trans(host, addr, (u32 *)buf,
-+					mtd->writesize, CMD_PROGRAM_PAGE))
-+			ret = -EIO;
-+		goto out;
-+	}
-+#endif /* __UBOOT__ */
-+
-+	brcmnand_write_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS,
-+			(host->cs << 16) | ((addr >> 32) & 0xffff));
-+	(void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS);
-+
-+	for (i = 0; i < trans; i++, addr += FC_BYTES) {
-+		/* full address MUST be set before populating FC */
-+		brcmnand_write_reg(ctrl, BRCMNAND_CMD_ADDRESS,
-+				   lower_32_bits(addr));
-+		(void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS);
-+
-+		if (buf) {
-+			brcmnand_soc_data_bus_prepare(ctrl->soc, false);
-+
-+			for (j = 0; j < FC_WORDS; j++, buf++)
-+				brcmnand_write_fc(ctrl, j, *buf);
-+
-+			brcmnand_soc_data_bus_unprepare(ctrl->soc, false);
-+		} else if (oob) {
-+			for (j = 0; j < FC_WORDS; j++)
-+				brcmnand_write_fc(ctrl, j, 0xffffffff);
-+		}
-+
-+		if (oob) {
-+			oob += write_oob_to_regs(ctrl, i, oob,
-+					mtd->oobsize / trans,
-+					host->hwcfg.sector_size_1k);
-+		}
-+
-+		/* we cannot use SPARE_AREA_PROGRAM when PARTIAL_PAGE_EN=0 */
-+		brcmnand_send_cmd(host, CMD_PROGRAM_PAGE);
-+		status = brcmnand_waitfunc(mtd, chip);
-+
-+		if (status & NAND_STATUS_FAIL) {
-+			dev_info(ctrl->dev, "program failed at %llx\n",
-+				(unsigned long long)addr);
-+			ret = -EIO;
-+			goto out;
-+		}
-+	}
-+out:
-+	brcmnand_wp(mtd, 1);
-+	return ret;
-+}
-+
-+static int brcmnand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
-+			       const uint8_t *buf, int oob_required, int page)
-+{
-+	struct brcmnand_host *host = nand_get_controller_data(chip);
-+	void *oob = oob_required ? chip->oob_poi : NULL;
-+
-+	nand_prog_page_begin_op(chip, page, 0, NULL, 0);
-+	brcmnand_write(mtd, chip, host->last_addr, (const u32 *)buf, oob);
-+
-+	return nand_prog_page_end_op(chip);
-+}
-+
-+static int brcmnand_write_page_raw(struct mtd_info *mtd,
-+				   struct nand_chip *chip, const uint8_t *buf,
-+				   int oob_required, int page)
-+{
-+	struct brcmnand_host *host = nand_get_controller_data(chip);
-+	void *oob = oob_required ? chip->oob_poi : NULL;
-+
-+	nand_prog_page_begin_op(chip, page, 0, NULL, 0);
-+	brcmnand_set_ecc_enabled(host, 0);
-+	brcmnand_write(mtd, chip, host->last_addr, (const u32 *)buf, oob);
-+	brcmnand_set_ecc_enabled(host, 1);
-+
-+	return nand_prog_page_end_op(chip);
-+}
-+
-+static int brcmnand_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
-+				  int page)
-+{
-+	return brcmnand_write(mtd, chip, (u64)page << chip->page_shift,
-+				  NULL, chip->oob_poi);
-+}
-+
-+static int brcmnand_write_oob_raw(struct mtd_info *mtd, struct nand_chip *chip,
-+				  int page)
-+{
-+	struct brcmnand_host *host = nand_get_controller_data(chip);
-+	int ret;
-+
-+	brcmnand_set_ecc_enabled(host, 0);
-+	ret = brcmnand_write(mtd, chip, (u64)page << chip->page_shift, NULL,
-+				 (u8 *)chip->oob_poi);
-+	brcmnand_set_ecc_enabled(host, 1);
-+
-+	return ret;
-+}
-+
-+/***********************************************************************
-+ * Per-CS setup (1 NAND device)
-+ ***********************************************************************/
-+
-+static int brcmnand_set_cfg(struct brcmnand_host *host,
-+			    struct brcmnand_cfg *cfg)
-+{
-+	struct brcmnand_controller *ctrl = host->ctrl;
-+	struct nand_chip *chip = &host->chip;
-+	u16 cfg_offs = brcmnand_cs_offset(ctrl, host->cs, BRCMNAND_CS_CFG);
-+	u16 cfg_ext_offs = brcmnand_cs_offset(ctrl, host->cs,
-+			BRCMNAND_CS_CFG_EXT);
-+	u16 acc_control_offs = brcmnand_cs_offset(ctrl, host->cs,
-+			BRCMNAND_CS_ACC_CONTROL);
-+	u8 block_size = 0, page_size = 0, device_size = 0;
-+	u32 tmp;
-+
-+	if (ctrl->block_sizes) {
-+		int i, found;
-+
-+		for (i = 0, found = 0; ctrl->block_sizes[i]; i++)
-+			if (ctrl->block_sizes[i] * 1024 == cfg->block_size) {
-+				block_size = i;
-+				found = 1;
-+			}
-+		if (!found) {
-+			dev_warn(ctrl->dev, "invalid block size %u\n",
-+					cfg->block_size);
-+			return -EINVAL;
-+		}
-+	} else {
-+		block_size = ffs(cfg->block_size) - ffs(BRCMNAND_MIN_BLOCKSIZE);
-+	}
-+
-+	if (cfg->block_size < BRCMNAND_MIN_BLOCKSIZE || (ctrl->max_block_size &&
-+				cfg->block_size > ctrl->max_block_size)) {
-+		dev_warn(ctrl->dev, "invalid block size %u\n",
-+				cfg->block_size);
-+		block_size = 0;
-+	}
-+
-+	if (ctrl->page_sizes) {
-+		int i, found;
-+
-+		for (i = 0, found = 0; ctrl->page_sizes[i]; i++)
-+			if (ctrl->page_sizes[i] == cfg->page_size) {
-+				page_size = i;
-+				found = 1;
-+			}
-+		if (!found) {
-+			dev_warn(ctrl->dev, "invalid page size %u\n",
-+					cfg->page_size);
-+			return -EINVAL;
-+		}
-+	} else {
-+		page_size = ffs(cfg->page_size) - ffs(BRCMNAND_MIN_PAGESIZE);
-+	}
-+
-+	if (cfg->page_size < BRCMNAND_MIN_PAGESIZE || (ctrl->max_page_size &&
-+				cfg->page_size > ctrl->max_page_size)) {
-+		dev_warn(ctrl->dev, "invalid page size %u\n", cfg->page_size);
-+		return -EINVAL;
-+	}
-+
-+	if (fls64(cfg->device_size) < fls64(BRCMNAND_MIN_DEVSIZE)) {
-+		dev_warn(ctrl->dev, "invalid device size 0x%llx\n",
-+			(unsigned long long)cfg->device_size);
-+		return -EINVAL;
-+	}
-+	device_size = fls64(cfg->device_size) - fls64(BRCMNAND_MIN_DEVSIZE);
-+
-+	tmp = (cfg->blk_adr_bytes << CFG_BLK_ADR_BYTES_SHIFT) |
-+		(cfg->col_adr_bytes << CFG_COL_ADR_BYTES_SHIFT) |
-+		(cfg->ful_adr_bytes << CFG_FUL_ADR_BYTES_SHIFT) |
-+		(!!(cfg->device_width == 16) << CFG_BUS_WIDTH_SHIFT) |
-+		(device_size << CFG_DEVICE_SIZE_SHIFT);
-+	if (cfg_offs == cfg_ext_offs) {
-+		tmp |= (page_size << CFG_PAGE_SIZE_SHIFT) |
-+		       (block_size << CFG_BLK_SIZE_SHIFT);
-+		nand_writereg(ctrl, cfg_offs, tmp);
-+	} else {
-+		nand_writereg(ctrl, cfg_offs, tmp);
-+		tmp = (page_size << CFG_EXT_PAGE_SIZE_SHIFT) |
-+		      (block_size << CFG_EXT_BLK_SIZE_SHIFT);
-+		nand_writereg(ctrl, cfg_ext_offs, tmp);
-+	}
-+
-+	tmp = nand_readreg(ctrl, acc_control_offs);
-+	tmp &= ~brcmnand_ecc_level_mask(ctrl);
-+	tmp |= cfg->ecc_level << NAND_ACC_CONTROL_ECC_SHIFT;
-+	tmp &= ~brcmnand_spare_area_mask(ctrl);
-+	tmp |= cfg->spare_area_size;
-+	nand_writereg(ctrl, acc_control_offs, tmp);
-+
-+	brcmnand_set_sector_size_1k(host, cfg->sector_size_1k);
-+
-+	/* threshold = ceil(BCH-level * 0.75) */
-+	brcmnand_wr_corr_thresh(host, DIV_ROUND_UP(chip->ecc.strength * 3, 4));
-+
-+	return 0;
-+}
-+
-+static void brcmnand_print_cfg(struct brcmnand_host *host,
-+			       char *buf, struct brcmnand_cfg *cfg)
-+{
-+	buf += sprintf(buf,
-+		"%lluMiB total, %uKiB blocks, %u%s pages, %uB OOB, %u-bit",
-+		(unsigned long long)cfg->device_size >> 20,
-+		cfg->block_size >> 10,
-+		cfg->page_size >= 1024 ? cfg->page_size >> 10 : cfg->page_size,
-+		cfg->page_size >= 1024 ? "KiB" : "B",
-+		cfg->spare_area_size, cfg->device_width);
-+
-+	/* Account for Hamming ECC and for BCH 512B vs 1KiB sectors */
-+	if (is_hamming_ecc(host->ctrl, cfg))
-+		sprintf(buf, ", Hamming ECC");
-+	else if (cfg->sector_size_1k)
-+		sprintf(buf, ", BCH-%u (1KiB sector)", cfg->ecc_level << 1);
-+	else
-+		sprintf(buf, ", BCH-%u", cfg->ecc_level);
-+}
-+
-+/*
-+ * Minimum number of bytes to address a page. Calculated as:
-+ *     roundup(log2(size / page-size) / 8)
-+ *
-+ * NB: the following does not "round up" for non-power-of-2 'size'; but this is
-+ *     OK because many other things will break if 'size' is irregular...
-+ */
-+static inline int get_blk_adr_bytes(u64 size, u32 writesize)
-+{
-+	return ALIGN(ilog2(size) - ilog2(writesize), 8) >> 3;
-+}
-+
-+static int brcmnand_setup_dev(struct brcmnand_host *host)
-+{
-+	struct mtd_info *mtd = nand_to_mtd(&host->chip);
-+	struct nand_chip *chip = &host->chip;
-+	struct brcmnand_controller *ctrl = host->ctrl;
-+	struct brcmnand_cfg *cfg = &host->hwcfg;
-+	char msg[128];
-+	u32 offs, tmp, oob_sector;
-+	int ret;
-+
-+	memset(cfg, 0, sizeof(*cfg));
-+
-+#ifndef __UBOOT__
-+	ret = of_property_read_u32(nand_get_flash_node(chip),
-+				   "brcm,nand-oob-sector-size",
-+				   &oob_sector);
-+#else
-+	ret = ofnode_read_u32(nand_get_flash_node(chip),
-+			      "brcm,nand-oob-sector-size",
-+			      &oob_sector);
-+#endif /* __UBOOT__ */
-+	if (ret) {
-+		/* Use detected size */
-+		cfg->spare_area_size = mtd->oobsize /
-+					(mtd->writesize >> FC_SHIFT);
-+	} else {
-+		cfg->spare_area_size = oob_sector;
-+	}
-+	if (cfg->spare_area_size > ctrl->max_oob)
-+		cfg->spare_area_size = ctrl->max_oob;
-+	/*
-+	 * Set oobsize to be consistent with controller's spare_area_size, as
-+	 * the rest is inaccessible.
-+	 */
-+	mtd->oobsize = cfg->spare_area_size * (mtd->writesize >> FC_SHIFT);
-+
-+	cfg->device_size = mtd->size;
-+	cfg->block_size = mtd->erasesize;
-+	cfg->page_size = mtd->writesize;
-+	cfg->device_width = (chip->options & NAND_BUSWIDTH_16) ? 16 : 8;
-+	cfg->col_adr_bytes = 2;
-+	cfg->blk_adr_bytes = get_blk_adr_bytes(mtd->size, mtd->writesize);
-+
-+	if (chip->ecc.mode != NAND_ECC_HW) {
-+		dev_err(ctrl->dev, "only HW ECC supported; selected: %d\n",
-+			chip->ecc.mode);
-+		return -EINVAL;
-+	}
-+
-+	if (chip->ecc.algo == NAND_ECC_UNKNOWN) {
-+		if (chip->ecc.strength == 1 && chip->ecc.size == 512)
-+			/* Default to Hamming for 1-bit ECC, if unspecified */
-+			chip->ecc.algo = NAND_ECC_HAMMING;
-+		else
-+			/* Otherwise, BCH */
-+			chip->ecc.algo = NAND_ECC_BCH;
-+	}
-+
-+	if (chip->ecc.algo == NAND_ECC_HAMMING && (chip->ecc.strength != 1 ||
-+						   chip->ecc.size != 512)) {
-+		dev_err(ctrl->dev, "invalid Hamming params: %d bits per %d bytes\n",
-+			chip->ecc.strength, chip->ecc.size);
-+		return -EINVAL;
-+	}
-+
-+	switch (chip->ecc.size) {
-+	case 512:
-+		if (chip->ecc.algo == NAND_ECC_HAMMING)
-+			cfg->ecc_level = 15;
-+		else
-+			cfg->ecc_level = chip->ecc.strength;
-+		cfg->sector_size_1k = 0;
-+		break;
-+	case 1024:
-+		if (!(ctrl->features & BRCMNAND_HAS_1K_SECTORS)) {
-+			dev_err(ctrl->dev, "1KB sectors not supported\n");
-+			return -EINVAL;
-+		}
-+		if (chip->ecc.strength & 0x1) {
-+			dev_err(ctrl->dev,
-+				"odd ECC not supported with 1KB sectors\n");
-+			return -EINVAL;
-+		}
-+
-+		cfg->ecc_level = chip->ecc.strength >> 1;
-+		cfg->sector_size_1k = 1;
-+		break;
-+	default:
-+		dev_err(ctrl->dev, "unsupported ECC size: %d\n",
-+			chip->ecc.size);
-+		return -EINVAL;
-+	}
-+
-+	cfg->ful_adr_bytes = cfg->blk_adr_bytes;
-+	if (mtd->writesize > 512)
-+		cfg->ful_adr_bytes += cfg->col_adr_bytes;
-+	else
-+		cfg->ful_adr_bytes += 1;
-+
-+	ret = brcmnand_set_cfg(host, cfg);
-+	if (ret)
-+		return ret;
-+
-+	brcmnand_set_ecc_enabled(host, 1);
-+
-+	brcmnand_print_cfg(host, msg, cfg);
-+	dev_info(ctrl->dev, "detected %s\n", msg);
-+
-+	/* Configure ACC_CONTROL */
-+	offs = brcmnand_cs_offset(ctrl, host->cs, BRCMNAND_CS_ACC_CONTROL);
-+	tmp = nand_readreg(ctrl, offs);
-+	tmp &= ~ACC_CONTROL_PARTIAL_PAGE;
-+	tmp &= ~ACC_CONTROL_RD_ERASED;
-+
-+	/* We need to turn on Read from erased paged protected by ECC */
-+	if (ctrl->nand_version >= 0x0702)
-+		tmp |= ACC_CONTROL_RD_ERASED;
-+	tmp &= ~ACC_CONTROL_FAST_PGM_RDIN;
-+	if (ctrl->features & BRCMNAND_HAS_PREFETCH)
-+		tmp &= ~ACC_CONTROL_PREFETCH;
-+
-+	nand_writereg(ctrl, offs, tmp);
-+
-+	return 0;
-+}
-+
-+#ifndef __UBOOT__
-+static int brcmnand_init_cs(struct brcmnand_host *host, struct device_node *dn)
-+#else
-+static int brcmnand_init_cs(struct brcmnand_host *host, ofnode dn)
-+#endif
-+{
-+	struct brcmnand_controller *ctrl = host->ctrl;
-+#ifndef __UBOOT__
-+	struct platform_device *pdev = host->pdev;
-+#else
-+	struct udevice *pdev = host->pdev;
-+#endif /* __UBOOT__ */
-+	struct mtd_info *mtd;
-+	struct nand_chip *chip;
-+	int ret;
-+	u16 cfg_offs;
-+
-+#ifndef __UBOOT__
-+	ret = of_property_read_u32(dn, "reg", &host->cs);
-+#else
-+	ret = ofnode_read_s32(dn, "reg", &host->cs);
-+#endif
-+	if (ret) {
-+		dev_err(&pdev->dev, "can't get chip-select\n");
-+		return -ENXIO;
-+	}
-+
-+	mtd = nand_to_mtd(&host->chip);
-+	chip = &host->chip;
-+
-+	nand_set_flash_node(chip, dn);
-+	nand_set_controller_data(chip, host);
-+#ifndef __UBOOT__
-+	mtd->name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "brcmnand.%d",
-+				   host->cs);
-+#else
-+	mtd->name = devm_kasprintf(pdev, GFP_KERNEL, "brcmnand.%d",
-+				   host->cs);
-+#endif /* __UBOOT__ */
-+	if (!mtd->name)
-+		return -ENOMEM;
-+
-+	mtd->owner = THIS_MODULE;
-+#ifndef __UBOOT__
-+	mtd->dev.parent = &pdev->dev;
-+#else
-+	mtd->dev->parent = pdev;
-+#endif /* __UBOOT__ */
-+
-+	chip->IO_ADDR_R = (void __iomem *)0xdeadbeef;
-+	chip->IO_ADDR_W = (void __iomem *)0xdeadbeef;
-+
-+	chip->cmd_ctrl = brcmnand_cmd_ctrl;
-+	chip->cmdfunc = brcmnand_cmdfunc;
-+	chip->waitfunc = brcmnand_waitfunc;
-+	chip->read_byte = brcmnand_read_byte;
-+	chip->read_buf = brcmnand_read_buf;
-+	chip->write_buf = brcmnand_write_buf;
-+
-+	chip->ecc.mode = NAND_ECC_HW;
-+	chip->ecc.read_page = brcmnand_read_page;
-+	chip->ecc.write_page = brcmnand_write_page;
-+	chip->ecc.read_page_raw = brcmnand_read_page_raw;
-+	chip->ecc.write_page_raw = brcmnand_write_page_raw;
-+	chip->ecc.write_oob_raw = brcmnand_write_oob_raw;
-+	chip->ecc.read_oob_raw = brcmnand_read_oob_raw;
-+	chip->ecc.read_oob = brcmnand_read_oob;
-+	chip->ecc.write_oob = brcmnand_write_oob;
-+
-+	chip->controller = &ctrl->controller;
-+
-+	/*
-+	 * The bootloader might have configured 16bit mode but
-+	 * NAND READID command only works in 8bit mode. We force
-+	 * 8bit mode here to ensure that NAND READID commands works.
-+	 */
-+	cfg_offs = brcmnand_cs_offset(ctrl, host->cs, BRCMNAND_CS_CFG);
-+	nand_writereg(ctrl, cfg_offs,
-+		      nand_readreg(ctrl, cfg_offs) & ~CFG_BUS_WIDTH);
-+
-+	ret = nand_scan_ident(mtd, 1, NULL);
-+	if (ret)
-+		return ret;
-+
-+	chip->options |= NAND_NO_SUBPAGE_WRITE;
-+	/*
-+	 * Avoid (for instance) kmap()'d buffers from JFFS2, which we can't DMA
-+	 * to/from, and have nand_base pass us a bounce buffer instead, as
-+	 * needed.
-+	 */
-+	chip->options |= NAND_USE_BOUNCE_BUFFER;
-+
-+	if (chip->bbt_options & NAND_BBT_USE_FLASH)
-+		chip->bbt_options |= NAND_BBT_NO_OOB;
-+
-+	if (brcmnand_setup_dev(host))
-+		return -ENXIO;
-+
-+	chip->ecc.size = host->hwcfg.sector_size_1k ? 1024 : 512;
-+	/* only use our internal HW threshold */
-+	mtd->bitflip_threshold = 1;
-+
-+	ret = brcmstb_choose_ecc_layout(host);
-+	if (ret)
-+		return ret;
-+
-+	ret = nand_scan_tail(mtd);
-+	if (ret)
-+		return ret;
-+
-+#ifndef __UBOOT__
-+	ret = mtd_device_register(mtd, NULL, 0);
-+	if (ret)
-+		nand_cleanup(chip);
-+#else
-+	ret = nand_register(0, mtd);
-+#endif /* __UBOOT__ */
-+
-+	return ret;
-+}
-+
-+#ifndef __UBOOT__
-+static void brcmnand_save_restore_cs_config(struct brcmnand_host *host,
-+					    int restore)
-+{
-+	struct brcmnand_controller *ctrl = host->ctrl;
-+	u16 cfg_offs = brcmnand_cs_offset(ctrl, host->cs, BRCMNAND_CS_CFG);
-+	u16 cfg_ext_offs = brcmnand_cs_offset(ctrl, host->cs,
-+			BRCMNAND_CS_CFG_EXT);
-+	u16 acc_control_offs = brcmnand_cs_offset(ctrl, host->cs,
-+			BRCMNAND_CS_ACC_CONTROL);
-+	u16 t1_offs = brcmnand_cs_offset(ctrl, host->cs, BRCMNAND_CS_TIMING1);
-+	u16 t2_offs = brcmnand_cs_offset(ctrl, host->cs, BRCMNAND_CS_TIMING2);
-+
-+	if (restore) {
-+		nand_writereg(ctrl, cfg_offs, host->hwcfg.config);
-+		if (cfg_offs != cfg_ext_offs)
-+			nand_writereg(ctrl, cfg_ext_offs,
-+				      host->hwcfg.config_ext);
-+		nand_writereg(ctrl, acc_control_offs, host->hwcfg.acc_control);
-+		nand_writereg(ctrl, t1_offs, host->hwcfg.timing_1);
-+		nand_writereg(ctrl, t2_offs, host->hwcfg.timing_2);
-+	} else {
-+		host->hwcfg.config = nand_readreg(ctrl, cfg_offs);
-+		if (cfg_offs != cfg_ext_offs)
-+			host->hwcfg.config_ext =
-+				nand_readreg(ctrl, cfg_ext_offs);
-+		host->hwcfg.acc_control = nand_readreg(ctrl, acc_control_offs);
-+		host->hwcfg.timing_1 = nand_readreg(ctrl, t1_offs);
-+		host->hwcfg.timing_2 = nand_readreg(ctrl, t2_offs);
-+	}
-+}
-+
-+static int brcmnand_suspend(struct device *dev)
-+{
-+	struct brcmnand_controller *ctrl = dev_get_drvdata(dev);
-+	struct brcmnand_host *host;
-+
-+	list_for_each_entry(host, &ctrl->host_list, node)
-+		brcmnand_save_restore_cs_config(host, 0);
-+
-+	ctrl->nand_cs_nand_select = brcmnand_read_reg(ctrl, BRCMNAND_CS_SELECT);
-+	ctrl->nand_cs_nand_xor = brcmnand_read_reg(ctrl, BRCMNAND_CS_XOR);
-+	ctrl->corr_stat_threshold =
-+		brcmnand_read_reg(ctrl, BRCMNAND_CORR_THRESHOLD);
-+
-+	if (has_flash_dma(ctrl))
-+		ctrl->flash_dma_mode = flash_dma_readl(ctrl, FLASH_DMA_MODE);
-+
-+	return 0;
-+}
-+
-+static int brcmnand_resume(struct device *dev)
-+{
-+	struct brcmnand_controller *ctrl = dev_get_drvdata(dev);
-+	struct brcmnand_host *host;
-+
-+	if (has_flash_dma(ctrl)) {
-+		flash_dma_writel(ctrl, FLASH_DMA_MODE, ctrl->flash_dma_mode);
-+		flash_dma_writel(ctrl, FLASH_DMA_ERROR_STATUS, 0);
-+	}
-+
-+	brcmnand_write_reg(ctrl, BRCMNAND_CS_SELECT, ctrl->nand_cs_nand_select);
-+	brcmnand_write_reg(ctrl, BRCMNAND_CS_XOR, ctrl->nand_cs_nand_xor);
-+	brcmnand_write_reg(ctrl, BRCMNAND_CORR_THRESHOLD,
-+			ctrl->corr_stat_threshold);
-+	if (ctrl->soc) {
-+		/* Clear/re-enable interrupt */
-+		ctrl->soc->ctlrdy_ack(ctrl->soc);
-+		ctrl->soc->ctlrdy_set_enabled(ctrl->soc, true);
-+	}
-+
-+	list_for_each_entry(host, &ctrl->host_list, node) {
-+		struct nand_chip *chip = &host->chip;
-+
-+		brcmnand_save_restore_cs_config(host, 1);
-+
-+		/* Reset the chip, required by some chips after power-up */
-+		nand_reset_op(chip);
-+	}
-+
-+	return 0;
-+}
-+
-+const struct dev_pm_ops brcmnand_pm_ops = {
-+	.suspend		= brcmnand_suspend,
-+	.resume			= brcmnand_resume,
-+};
-+EXPORT_SYMBOL_GPL(brcmnand_pm_ops);
-+
-+static const struct of_device_id brcmnand_of_match[] = {
-+	{ .compatible = "brcm,brcmnand-v4.0" },
-+	{ .compatible = "brcm,brcmnand-v5.0" },
-+	{ .compatible = "brcm,brcmnand-v6.0" },
-+	{ .compatible = "brcm,brcmnand-v6.1" },
-+	{ .compatible = "brcm,brcmnand-v6.2" },
-+	{ .compatible = "brcm,brcmnand-v7.0" },
-+	{ .compatible = "brcm,brcmnand-v7.1" },
-+	{ .compatible = "brcm,brcmnand-v7.2" },
-+	{},
-+};
-+MODULE_DEVICE_TABLE(of, brcmnand_of_match);
-+#endif  /* __UBOOT__ */
-+
-+/***********************************************************************
-+ * Platform driver setup (per controller)
-+ ***********************************************************************/
-+
-+#ifndef __UBOOT__
-+int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc)
-+#else
-+int brcmnand_probe(struct udevice *dev, struct brcmnand_soc *soc)
-+#endif /* __UBOOT__ */
-+{
-+#ifndef __UBOOT__
-+	struct device *dev = &pdev->dev;
-+	struct device_node *dn = dev->of_node, *child;
-+#else
-+	ofnode child;
-+	struct udevice *pdev = dev;
-+#endif /* __UBOOT__ */
-+	struct brcmnand_controller *ctrl;
-+#ifndef __UBOOT__
-+	struct resource *res;
-+#else
-+	struct resource res;
-+#endif /* __UBOOT__ */
-+	int ret;
-+
-+#ifndef __UBOOT__
-+	/* We only support device-tree instantiation */
-+	if (!dn)
-+		return -ENODEV;
-+
-+	if (!of_match_node(brcmnand_of_match, dn))
-+		return -ENODEV;
-+#endif /* __UBOOT__ */
-+
-+	ctrl = devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL);
-+	if (!ctrl)
-+		return -ENOMEM;
-+
-+#ifndef __UBOOT__
-+	dev_set_drvdata(dev, ctrl);
-+#else
-+	/*
-+	 * in u-boot, the data for the driver is allocated before probing
-+	 * so to keep the reference to ctrl, we store it in the variable soc
-+	 */
-+	soc->ctrl = ctrl;
-+#endif /* __UBOOT__ */
-+	ctrl->dev = dev;
-+
-+	init_completion(&ctrl->done);
-+	init_completion(&ctrl->dma_done);
-+	nand_hw_control_init(&ctrl->controller);
-+	INIT_LIST_HEAD(&ctrl->host_list);
-+
-+	/* Is parameter page in big endian ? */
-+	ctrl->parameter_page_big_endian =
-+	    dev_read_u32_default(dev, "parameter-page-big-endian", 1);
-+
-+	/* NAND register range */
-+#ifndef __UBOOT__
-+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+	ctrl->nand_base = devm_ioremap_resource(dev, res);
-+#else
-+	dev_read_resource(pdev, 0, &res);
-+	ctrl->nand_base = devm_ioremap(pdev, res.start, resource_size(&res));
-+#endif
-+	if (IS_ERR(ctrl->nand_base))
-+		return PTR_ERR(ctrl->nand_base);
-+
-+	/* Enable clock before using NAND registers */
-+	ctrl->clk = devm_clk_get(dev, "nand");
-+	if (!IS_ERR(ctrl->clk)) {
-+		ret = clk_prepare_enable(ctrl->clk);
-+		if (ret)
-+			return ret;
-+	} else {
-+		ret = PTR_ERR(ctrl->clk);
-+		if (ret == -EPROBE_DEFER)
-+			return ret;
-+
-+		ctrl->clk = NULL;
-+	}
-+
-+	/* Initialize NAND revision */
-+	ret = brcmnand_revision_init(ctrl);
-+	if (ret)
-+		goto err;
-+
-+	/*
-+	 * Most chips have this cache at a fixed offset within 'nand' block.
-+	 * Some must specify this region separately.
-+	 */
-+#ifndef __UBOOT__
-+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand-cache");
-+	if (res) {
-+		ctrl->nand_fc = devm_ioremap_resource(dev, res);
-+		if (IS_ERR(ctrl->nand_fc)) {
-+			ret = PTR_ERR(ctrl->nand_fc);
-+			goto err;
-+		}
-+	} else {
-+		ctrl->nand_fc = ctrl->nand_base +
-+				ctrl->reg_offsets[BRCMNAND_FC_BASE];
-+	}
-+#else
-+	if (!dev_read_resource_byname(pdev, "nand-cache", &res)) {
-+		ctrl->nand_fc = devm_ioremap(dev, res.start,
-+					     resource_size(&res));
-+		if (IS_ERR(ctrl->nand_fc)) {
-+			ret = PTR_ERR(ctrl->nand_fc);
-+			goto err;
-+		}
-+	} else {
-+		ctrl->nand_fc = ctrl->nand_base +
-+				ctrl->reg_offsets[BRCMNAND_FC_BASE];
-+	}
-+#endif
-+
-+#ifndef __UBOOT__
-+	/* FLASH_DMA */
-+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "flash-dma");
-+	if (res) {
-+		ctrl->flash_dma_base = devm_ioremap_resource(dev, res);
-+		if (IS_ERR(ctrl->flash_dma_base)) {
-+			ret = PTR_ERR(ctrl->flash_dma_base);
-+			goto err;
-+		}
-+
-+		flash_dma_writel(ctrl, FLASH_DMA_MODE, 1); /* linked-list */
-+		flash_dma_writel(ctrl, FLASH_DMA_ERROR_STATUS, 0);
-+
-+		/* Allocate descriptor(s) */
-+		ctrl->dma_desc = dmam_alloc_coherent(dev,
-+						     sizeof(*ctrl->dma_desc),
-+						     &ctrl->dma_pa, GFP_KERNEL);
-+		if (!ctrl->dma_desc) {
-+			ret = -ENOMEM;
-+			goto err;
-+		}
-+
-+		ctrl->dma_irq = platform_get_irq(pdev, 1);
-+		if ((int)ctrl->dma_irq < 0) {
-+			dev_err(dev, "missing FLASH_DMA IRQ\n");
-+			ret = -ENODEV;
-+			goto err;
-+		}
-+
-+		ret = devm_request_irq(dev, ctrl->dma_irq,
-+				brcmnand_dma_irq, 0, DRV_NAME,
-+				ctrl);
-+		if (ret < 0) {
-+			dev_err(dev, "can't allocate IRQ %d: error %d\n",
-+					ctrl->dma_irq, ret);
-+			goto err;
-+		}
-+
-+		dev_info(dev, "enabling FLASH_DMA\n");
-+	}
-+#endif /* __UBOOT__ */
-+
-+	/* Disable automatic device ID config, direct addressing */
-+	brcmnand_rmw_reg(ctrl, BRCMNAND_CS_SELECT,
-+			 CS_SELECT_AUTO_DEVICE_ID_CFG | 0xff, 0, 0);
-+	/* Disable XOR addressing */
-+	brcmnand_rmw_reg(ctrl, BRCMNAND_CS_XOR, 0xff, 0, 0);
-+
-+	/* Read the write-protect configuration in the device tree */
-+	wp_on = dev_read_u32_default(dev, "write-protect", wp_on);
-+
-+	if (ctrl->features & BRCMNAND_HAS_WP) {
-+		/* Permanently disable write protection */
-+		if (wp_on == 2)
-+			brcmnand_set_wp(ctrl, false);
-+	} else {
-+		wp_on = 0;
-+	}
-+
-+#ifndef __UBOOT__
-+	/* IRQ */
-+	ctrl->irq = platform_get_irq(pdev, 0);
-+	if ((int)ctrl->irq < 0) {
-+		dev_err(dev, "no IRQ defined\n");
-+		ret = -ENODEV;
-+		goto err;
-+	}
-+
-+	/*
-+	 * Some SoCs integrate this controller (e.g., its interrupt bits) in
-+	 * interesting ways
-+	 */
-+	if (soc) {
-+		ctrl->soc = soc;
-+
-+		ret = devm_request_irq(dev, ctrl->irq, brcmnand_irq, 0,
-+				       DRV_NAME, ctrl);
-+
-+		/* Enable interrupt */
-+		ctrl->soc->ctlrdy_ack(ctrl->soc);
-+		ctrl->soc->ctlrdy_set_enabled(ctrl->soc, true);
-+	} else {
-+		/* Use standard interrupt infrastructure */
-+		ret = devm_request_irq(dev, ctrl->irq, brcmnand_ctlrdy_irq, 0,
-+				       DRV_NAME, ctrl);
-+	}
-+	if (ret < 0) {
-+		dev_err(dev, "can't allocate IRQ %d: error %d\n",
-+			ctrl->irq, ret);
-+		goto err;
-+	}
-+#endif /* __UBOOT__ */
-+
-+#ifndef __UBOOT__
-+	for_each_available_child_of_node(dn, child) {
-+		if (of_device_is_compatible(child, "brcm,nandcs")) {
-+			struct brcmnand_host *host;
-+
-+			host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL);
-+			if (!host) {
-+				of_node_put(child);
-+				ret = -ENOMEM;
-+				goto err;
-+			}
-+			host->pdev = pdev;
-+			host->ctrl = ctrl;
-+
-+			ret = brcmnand_init_cs(host, child);
-+			if (ret) {
-+				devm_kfree(dev, host);
-+				continue; /* Try all chip-selects */
-+			}
-+
-+			list_add_tail(&host->node, &ctrl->host_list);
-+		}
-+	}
-+#else
-+	ofnode_for_each_subnode(child, dev_ofnode(dev)) {
-+		if (ofnode_device_is_compatible(child, "brcm,nandcs")) {
-+			struct brcmnand_host *host;
-+
-+			host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL);
-+			if (!host) {
-+				ret = -ENOMEM;
-+				goto err;
-+			}
-+			host->pdev = pdev;
-+			host->ctrl = ctrl;
-+
-+			ret = brcmnand_init_cs(host, child);
-+			if (ret) {
-+				devm_kfree(dev, host);
-+				continue; /* Try all chip-selects */
-+			}
-+
-+			list_add_tail(&host->node, &ctrl->host_list);
-+		}
-+	}
-+#endif /* __UBOOT__ */
-+
-+err:
-+#ifndef __UBOOT__
-+	clk_disable_unprepare(ctrl->clk);
-+#else
-+	if (ctrl->clk)
-+		clk_disable(ctrl->clk);
-+#endif /* __UBOOT__ */
-+	return ret;
-+
-+}
-+EXPORT_SYMBOL_GPL(brcmnand_probe);
-+
-+#ifndef __UBOOT__
-+int brcmnand_remove(struct platform_device *pdev)
-+{
-+	struct brcmnand_controller *ctrl = dev_get_drvdata(&pdev->dev);
-+	struct brcmnand_host *host;
-+
-+	list_for_each_entry(host, &ctrl->host_list, node)
-+		nand_release(nand_to_mtd(&host->chip));
-+
-+	clk_disable_unprepare(ctrl->clk);
-+
-+	dev_set_drvdata(&pdev->dev, NULL);
-+
-+	return 0;
-+}
-+#else
-+int brcmnand_remove(struct udevice *pdev)
-+{
-+	return 0;
-+}
-+#endif /* __UBOOT__ */
-+EXPORT_SYMBOL_GPL(brcmnand_remove);
-+
-+MODULE_LICENSE("GPL v2");
-+MODULE_AUTHOR("Kevin Cernekee");
-+MODULE_AUTHOR("Brian Norris");
-+MODULE_DESCRIPTION("NAND driver for Broadcom chips");
-+MODULE_ALIAS("platform:brcmnand");
-diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand.h b/drivers/mtd/nand/raw/brcmnand/brcmnand.h
-new file mode 100644
-index 0000000000..6946a62b06
---- /dev/null
-+++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.h
-@@ -0,0 +1,63 @@
-+/* SPDX-License-Identifier: GPL-2.0+ */
-+
-+#ifndef __BRCMNAND_H__
-+#define __BRCMNAND_H__
-+
-+#include <linux/types.h>
-+#include <linux/io.h>
-+
-+struct brcmnand_soc {
-+	bool (*ctlrdy_ack)(struct brcmnand_soc *soc);
-+	void (*ctlrdy_set_enabled)(struct brcmnand_soc *soc, bool en);
-+	void (*prepare_data_bus)(struct brcmnand_soc *soc, bool prepare,
-+				 bool is_param);
-+	void *ctrl;
-+};
-+
-+static inline void brcmnand_soc_data_bus_prepare(struct brcmnand_soc *soc,
-+						 bool is_param)
-+{
-+	if (soc && soc->prepare_data_bus)
-+		soc->prepare_data_bus(soc, true, is_param);
-+}
-+
-+static inline void brcmnand_soc_data_bus_unprepare(struct brcmnand_soc *soc,
-+						   bool is_param)
-+{
-+	if (soc && soc->prepare_data_bus)
-+		soc->prepare_data_bus(soc, false, is_param);
-+}
-+
-+static inline u32 brcmnand_readl(void __iomem *addr)
-+{
-+	/*
-+	 * MIPS endianness is configured by boot strap, which also reverses all
-+	 * bus endianness (i.e., big-endian CPU + big endian bus ==> native
-+	 * endian I/O).
-+	 *
-+	 * Other architectures (e.g., ARM) either do not support big endian, or
-+	 * else leave I/O in little endian mode.
-+	 */
-+	if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_SYS_BIG_ENDIAN))
-+		return __raw_readl(addr);
-+	else
-+		return readl_relaxed(addr);
-+}
-+
-+static inline void brcmnand_writel(u32 val, void __iomem *addr)
-+{
-+	/* See brcmnand_readl() comments */
-+	if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_SYS_BIG_ENDIAN))
-+		__raw_writel(val, addr);
-+	else
-+		writel_relaxed(val, addr);
-+}
-+
-+int brcmnand_probe(struct udevice *dev, struct brcmnand_soc *soc);
-+int brcmnand_remove(struct udevice *dev);
-+
-+#ifndef __UBOOT__
-+extern const struct dev_pm_ops brcmnand_pm_ops;
-+#endif /* __UBOOT__ */
-+
-+#endif /* __BRCMNAND_H__ */
-diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand_compat.c b/drivers/mtd/nand/raw/brcmnand/brcmnand_compat.c
-new file mode 100644
-index 0000000000..96b27e6e5a
---- /dev/null
-+++ b/drivers/mtd/nand/raw/brcmnand/brcmnand_compat.c
-@@ -0,0 +1,66 @@
-+// SPDX-License-Identifier: GPL-2.0+
-+
-+#include <common.h>
-+#include "brcmnand_compat.h"
-+
-+struct clk *devm_clk_get(struct udevice *dev, const char *id)
-+{
-+	struct clk *clk;
-+	int ret;
-+
-+	clk = devm_kzalloc(dev, sizeof(*clk), GFP_KERNEL);
-+	if (!clk) {
-+		debug("%s: can't allocate clock\n", __func__);
-+		return ERR_PTR(-ENOMEM);
-+	}
-+
-+	ret = clk_get_by_name(dev, id, clk);
-+	if (ret < 0) {
-+		debug("%s: can't get clock (ret = %d)!\n", __func__, ret);
-+		return ERR_PTR(ret);
-+	}
-+
-+	return clk;
-+}
-+
-+int clk_prepare_enable(struct clk *clk)
-+{
-+	return clk_enable(clk);
-+}
-+
-+void clk_disable_unprepare(struct clk *clk)
-+{
-+	clk_disable(clk);
-+}
-+
-+static char *devm_kvasprintf(struct udevice *dev, gfp_t gfp, const char *fmt,
-+			     va_list ap)
-+{
-+	unsigned int len;
-+	char *p;
-+	va_list aq;
-+
-+	va_copy(aq, ap);
-+	len = vsnprintf(NULL, 0, fmt, aq);
-+	va_end(aq);
-+
-+	p = devm_kmalloc(dev, len + 1, gfp);
-+	if (!p)
-+		return NULL;
-+
-+	vsnprintf(p, len + 1, fmt, ap);
-+
-+	return p;
-+}
-+
-+char *devm_kasprintf(struct udevice *dev, gfp_t gfp, const char *fmt, ...)
-+{
-+	va_list ap;
-+	char *p;
-+
-+	va_start(ap, fmt);
-+	p = devm_kvasprintf(dev, gfp, fmt, ap);
-+	va_end(ap);
-+
-+	return p;
-+}
-diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand_compat.h b/drivers/mtd/nand/raw/brcmnand/brcmnand_compat.h
-new file mode 100644
-index 0000000000..02cab0f828
---- /dev/null
-+++ b/drivers/mtd/nand/raw/brcmnand/brcmnand_compat.h
-@@ -0,0 +1,15 @@
-+/* SPDX-License-Identifier: GPL-2.0+ */
-+
-+#ifndef __BRCMNAND_COMPAT_H
-+#define __BRCMNAND_COMPAT_H
-+
-+#include <clk.h>
-+#include <dm.h>
-+
-+struct clk *devm_clk_get(struct udevice *dev, const char *id);
-+int clk_prepare_enable(struct clk *clk);
-+void clk_disable_unprepare(struct clk *clk);
-+
-+char *devm_kasprintf(struct udevice *dev, gfp_t gfp, const char *fmt, ...);
-+
-+#endif /* __BRCMNAND_COMPAT_H */
-diff --git a/drivers/mtd/nand/raw/davinci_nand.c b/drivers/mtd/nand/raw/davinci_nand.c
-index e6a84a52b4..cfa9b535c8 100644
---- a/drivers/mtd/nand/raw/davinci_nand.c
-+++ b/drivers/mtd/nand/raw/davinci_nand.c
-@@ -730,43 +730,6 @@ static int nand_davinci_dev_ready(struct mtd_info *mtd)
- 	return __raw_readl(&davinci_emif_regs->nandfsr) & 0x1;
- }
- 
--static void nand_flash_init(void)
--{
--	/* This is for DM6446 EVM and *very* similar.  DO NOT GROW THIS!
--	 * Instead, have your board_init() set EMIF timings, based on its
--	 * knowledge of the clocks and what devices are hooked up ... and
--	 * don't even do that unless no UBL handled it.
--	 */
--#ifdef CONFIG_SOC_DM644X
--	u_int32_t	acfg1 = 0x3ffffffc;
--
--	/*------------------------------------------------------------------*
--	 *  NAND FLASH CHIP TIMEOUT @ 459 MHz                               *
--	 *                                                                  *
--	 *  AEMIF.CLK freq   = PLL1/6 = 459/6 = 76.5 MHz                    *
--	 *  AEMIF.CLK period = 1/76.5 MHz = 13.1 ns                         *
--	 *                                                                  *
--	 *------------------------------------------------------------------*/
--	 acfg1 = 0
--		| (0 << 31)	/* selectStrobe */
--		| (0 << 30)	/* extWait */
--		| (1 << 26)	/* writeSetup	10 ns */
--		| (3 << 20)	/* writeStrobe	40 ns */
--		| (1 << 17)	/* writeHold	10 ns */
--		| (1 << 13)	/* readSetup	10 ns */
--		| (5 << 7)	/* readStrobe	60 ns */
--		| (1 << 4)	/* readHold	10 ns */
--		| (3 << 2)	/* turnAround	?? ns */
--		| (0 << 0)	/* asyncSize	8-bit bus */
--		;
--
--	__raw_writel(acfg1, &davinci_emif_regs->ab1cr); /* CS2 */
--
--	/* NAND flash on CS2 */
--	__raw_writel(0x00000101, &davinci_emif_regs->nandfcr);
--#endif
--}
--
- void davinci_nand_init(struct nand_chip *nand)
- {
- #if defined CONFIG_KEYSTONE_RBL_NAND
-@@ -820,8 +783,6 @@ void davinci_nand_init(struct nand_chip *nand)
- 	nand->write_buf = nand_davinci_write_buf;
- 
- 	nand->dev_ready = nand_davinci_dev_ready;
--
--	nand_flash_init();
- }
- 
- int board_nand_init(struct nand_chip *chip) __attribute__((weak));
-diff --git a/drivers/mtd/nand/raw/denali.c b/drivers/mtd/nand/raw/denali.c
-index d1cac063f4..e0eb1339ec 100644
---- a/drivers/mtd/nand/raw/denali.c
-+++ b/drivers/mtd/nand/raw/denali.c
-@@ -69,14 +69,6 @@ static int dma_mapping_error(void *dev, dma_addr_t addr)
- #define DENALI_INVALID_BANK	-1
- #define DENALI_NR_BANKS		4
- 
--/*
-- * The bus interface clock, clk_x, is phase aligned with the core clock.  The
-- * clk_x is an integral multiple N of the core clk.  The value N is configured
-- * at IP delivery time, and its available value is 4, 5, or 6.  We need to align
-- * to the largest value to make it work with any possible configuration.
-- */
--#define DENALI_CLK_X_MULT	6
--
- 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);
-@@ -595,6 +587,12 @@ static int denali_dma_xfer(struct denali_nand_info *denali, void *buf,
- 	}
- 
- 	iowrite32(DMA_ENABLE__FLAG, denali->reg + DMA_ENABLE);
-+	/*
-+	 * The ->setup_dma() hook kicks DMA by using the data/command
-+	 * interface, which belongs to a different AXI port from the
-+	 * register interface.  Read back the register to avoid a race.
-+	 */
-+	ioread32(denali->reg + DMA_ENABLE);
- 
- 	denali_reset_irq(denali);
- 	denali->setup_dma(denali, dma_addr, page, write);
-@@ -946,7 +944,7 @@ static int denali_setup_data_interface(struct mtd_info *mtd, int chipnr,
- {
- 	struct denali_nand_info *denali = mtd_to_denali(mtd);
- 	const struct nand_sdr_timings *timings;
--	unsigned long t_clk;
-+	unsigned long t_x, mult_x;
- 	int acc_clks, re_2_we, re_2_re, we_2_re, addr_2_data;
- 	int rdwr_en_lo, rdwr_en_hi, rdwr_en_lo_hi, cs_setup;
- 	int addr_2_data_mask;
-@@ -957,15 +955,24 @@ static int denali_setup_data_interface(struct mtd_info *mtd, int chipnr,
- 		return PTR_ERR(timings);
- 
- 	/* clk_x period in picoseconds */
--	t_clk = DIV_ROUND_DOWN_ULL(1000000000000ULL, denali->clk_x_rate);
--	if (!t_clk)
-+	t_x = DIV_ROUND_DOWN_ULL(1000000000000ULL, denali->clk_x_rate);
-+	if (!t_x)
-+		return -EINVAL;
-+
-+	/*
-+	 * The bus interface clock, clk_x, is phase aligned with the core clock.
-+	 * The clk_x is an integral multiple N of the core clk.  The value N is
-+	 * configured at IP delivery time, and its available value is 4, 5, 6.
-+	 */
-+	mult_x = DIV_ROUND_CLOSEST_ULL(denali->clk_x_rate, denali->clk_rate);
-+	if (mult_x < 4 || mult_x > 6)
- 		return -EINVAL;
- 
- 	if (chipnr == NAND_DATA_IFACE_CHECK_ONLY)
- 		return 0;
- 
- 	/* tREA -> ACC_CLKS */
--	acc_clks = DIV_ROUND_UP(timings->tREA_max, t_clk);
-+	acc_clks = DIV_ROUND_UP(timings->tREA_max, t_x);
- 	acc_clks = min_t(int, acc_clks, ACC_CLKS__VALUE);
- 
- 	tmp = ioread32(denali->reg + ACC_CLKS);
-@@ -974,7 +981,7 @@ static int denali_setup_data_interface(struct mtd_info *mtd, int chipnr,
- 	iowrite32(tmp, denali->reg + ACC_CLKS);
- 
- 	/* tRWH -> RE_2_WE */
--	re_2_we = DIV_ROUND_UP(timings->tRHW_min, t_clk);
-+	re_2_we = DIV_ROUND_UP(timings->tRHW_min, t_x);
- 	re_2_we = min_t(int, re_2_we, RE_2_WE__VALUE);
- 
- 	tmp = ioread32(denali->reg + RE_2_WE);
-@@ -983,7 +990,7 @@ static int denali_setup_data_interface(struct mtd_info *mtd, int chipnr,
- 	iowrite32(tmp, denali->reg + RE_2_WE);
- 
- 	/* tRHZ -> RE_2_RE */
--	re_2_re = DIV_ROUND_UP(timings->tRHZ_max, t_clk);
-+	re_2_re = DIV_ROUND_UP(timings->tRHZ_max, t_x);
- 	re_2_re = min_t(int, re_2_re, RE_2_RE__VALUE);
- 
- 	tmp = ioread32(denali->reg + RE_2_RE);
-@@ -997,8 +1004,7 @@ static int denali_setup_data_interface(struct mtd_info *mtd, int chipnr,
- 	 * With WE_2_RE properly set, the Denali controller automatically takes
- 	 * care of the delay; the driver need not set NAND_WAIT_TCCS.
- 	 */
--	we_2_re = DIV_ROUND_UP(max(timings->tCCS_min, timings->tWHR_min),
--			       t_clk);
-+	we_2_re = DIV_ROUND_UP(max(timings->tCCS_min, timings->tWHR_min), t_x);
- 	we_2_re = min_t(int, we_2_re, TWHR2_AND_WE_2_RE__WE_2_RE);
- 
- 	tmp = ioread32(denali->reg + TWHR2_AND_WE_2_RE);
-@@ -1013,7 +1019,7 @@ static int denali_setup_data_interface(struct mtd_info *mtd, int chipnr,
- 	if (denali->revision < 0x0501)
- 		addr_2_data_mask >>= 1;
- 
--	addr_2_data = DIV_ROUND_UP(timings->tADL_min, t_clk);
-+	addr_2_data = DIV_ROUND_UP(timings->tADL_min, t_x);
- 	addr_2_data = min_t(int, addr_2_data, addr_2_data_mask);
- 
- 	tmp = ioread32(denali->reg + TCWAW_AND_ADDR_2_DATA);
-@@ -1023,7 +1029,7 @@ static int denali_setup_data_interface(struct mtd_info *mtd, int chipnr,
- 
- 	/* tREH, tWH -> RDWR_EN_HI_CNT */
- 	rdwr_en_hi = DIV_ROUND_UP(max(timings->tREH_min, timings->tWH_min),
--				  t_clk);
-+				  t_x);
- 	rdwr_en_hi = min_t(int, rdwr_en_hi, RDWR_EN_HI_CNT__VALUE);
- 
- 	tmp = ioread32(denali->reg + RDWR_EN_HI_CNT);
-@@ -1032,11 +1038,10 @@ static int denali_setup_data_interface(struct mtd_info *mtd, int chipnr,
- 	iowrite32(tmp, denali->reg + RDWR_EN_HI_CNT);
- 
- 	/* tRP, tWP -> RDWR_EN_LO_CNT */
--	rdwr_en_lo = DIV_ROUND_UP(max(timings->tRP_min, timings->tWP_min),
--				  t_clk);
-+	rdwr_en_lo = DIV_ROUND_UP(max(timings->tRP_min, timings->tWP_min), t_x);
- 	rdwr_en_lo_hi = DIV_ROUND_UP(max(timings->tRC_min, timings->tWC_min),
--				     t_clk);
--	rdwr_en_lo_hi = max(rdwr_en_lo_hi, DENALI_CLK_X_MULT);
-+				     t_x);
-+	rdwr_en_lo_hi = max_t(int, rdwr_en_lo_hi, mult_x);
- 	rdwr_en_lo = max(rdwr_en_lo, rdwr_en_lo_hi - rdwr_en_hi);
- 	rdwr_en_lo = min_t(int, rdwr_en_lo, RDWR_EN_LO_CNT__VALUE);
- 
-@@ -1046,8 +1051,8 @@ static int denali_setup_data_interface(struct mtd_info *mtd, int chipnr,
- 	iowrite32(tmp, denali->reg + RDWR_EN_LO_CNT);
- 
- 	/* tCS, tCEA -> CS_SETUP_CNT */
--	cs_setup = max3((int)DIV_ROUND_UP(timings->tCS_min, t_clk) - rdwr_en_lo,
--			(int)DIV_ROUND_UP(timings->tCEA_max, t_clk) - acc_clks,
-+	cs_setup = max3((int)DIV_ROUND_UP(timings->tCS_min, t_x) - rdwr_en_lo,
-+			(int)DIV_ROUND_UP(timings->tCEA_max, t_x) - acc_clks,
- 			0);
- 	cs_setup = min_t(int, cs_setup, CS_SETUP_CNT__VALUE);
- 
-diff --git a/drivers/mtd/nand/raw/denali.h b/drivers/mtd/nand/raw/denali.h
-index 9b797beffa..63ae828768 100644
---- a/drivers/mtd/nand/raw/denali.h
-+++ b/drivers/mtd/nand/raw/denali.h
-@@ -10,6 +10,7 @@
- #include <linux/bitops.h>
- #include <linux/mtd/rawnand.h>
- #include <linux/types.h>
-+#include <reset.h>
- 
- #define DEVICE_RESET				0x0
- #define     DEVICE_RESET__BANK(bank)			BIT(bank)
-@@ -292,6 +293,7 @@ struct udevice;
- 
- struct denali_nand_info {
- 	struct nand_chip nand;
-+	unsigned long clk_rate;		/* core clock rate */
- 	unsigned long clk_x_rate;	/* bus interface clock rate */
- 	int active_bank;		/* currently selected bank */
- 	struct udevice *dev;
-@@ -314,6 +316,7 @@ struct denali_nand_info {
- 	void (*host_write)(struct denali_nand_info *denali, u32 addr, u32 data);
- 	void (*setup_dma)(struct denali_nand_info *denali, dma_addr_t dma_addr,
- 			  int page, int write);
-+	struct reset_ctl_bulk resets;
- };
- 
- #define DENALI_CAP_HW_ECC_FIXUP			BIT(0)
-diff --git a/drivers/mtd/nand/raw/denali_dt.c b/drivers/mtd/nand/raw/denali_dt.c
-index 65a7797f0f..0ce81324b9 100644
---- a/drivers/mtd/nand/raw/denali_dt.c
-+++ b/drivers/mtd/nand/raw/denali_dt.c
-@@ -62,7 +62,7 @@ static int denali_dt_probe(struct udevice *dev)
- {
- 	struct denali_nand_info *denali = dev_get_priv(dev);
- 	const struct denali_dt_data *data;
--	struct clk clk;
-+	struct clk clk, clk_x, clk_ecc;
- 	struct resource res;
- 	int ret;
- 
-@@ -87,25 +87,74 @@ static int denali_dt_probe(struct udevice *dev)
- 
- 	denali->host = devm_ioremap(dev, res.start, resource_size(&res));
- 
--	ret = clk_get_by_index(dev, 0, &clk);
-+	ret = clk_get_by_name(dev, "nand", &clk);
-+	if (ret)
-+		ret = clk_get_by_index(dev, 0, &clk);
- 	if (ret)
- 		return ret;
- 
-+	ret = clk_get_by_name(dev, "nand_x", &clk_x);
-+	if (ret)
-+		clk_x.dev = NULL;
-+
-+	ret = clk_get_by_name(dev, "ecc", &clk_ecc);
-+	if (ret)
-+		clk_ecc.dev = NULL;
-+
- 	ret = clk_enable(&clk);
- 	if (ret)
- 		return ret;
- 
--	denali->clk_x_rate = clk_get_rate(&clk);
-+	if (clk_x.dev) {
-+		ret = clk_enable(&clk_x);
-+		if (ret)
-+			return ret;
-+	}
-+
-+	if (clk_ecc.dev) {
-+		ret = clk_enable(&clk_ecc);
-+		if (ret)
-+			return ret;
-+	}
-+
-+	if (clk_x.dev) {
-+		denali->clk_rate = clk_get_rate(&clk);
-+		denali->clk_x_rate = clk_get_rate(&clk_x);
-+	} else {
-+		/*
-+		 * Hardcode the clock rates for the backward compatibility.
-+		 * This works for both SOCFPGA and UniPhier.
-+		 */
-+		dev_notice(dev,
-+			   "necessary clock is missing. default clock rates are used.\n");
-+		denali->clk_rate = 50000000;
-+		denali->clk_x_rate = 200000000;
-+	}
-+
-+	ret = reset_get_bulk(dev, &denali->resets);
-+	if (ret)
-+		dev_warn(dev, "Can't get reset: %d\n", ret);
-+	else
-+		reset_deassert_bulk(&denali->resets);
- 
- 	return denali_init(denali);
- }
- 
-+static int denali_dt_remove(struct udevice *dev)
-+{
-+	struct denali_nand_info *denali = dev_get_priv(dev);
-+
-+	return reset_release_bulk(&denali->resets);
-+}
-+
- U_BOOT_DRIVER(denali_nand_dt) = {
- 	.name = "denali-nand-dt",
- 	.id = UCLASS_MISC,
- 	.of_match = denali_nand_dt_ids,
- 	.probe = denali_dt_probe,
- 	.priv_auto_alloc_size = sizeof(struct denali_nand_info),
-+	.remove = denali_dt_remove,
-+	.flags = DM_FLAG_OS_PREPARE,
- };
- 
- void board_nand_init(void)
-diff --git a/drivers/mtd/nand/raw/lpc32xx_nand_mlc.c b/drivers/mtd/nand/raw/lpc32xx_nand_mlc.c
-index 5d4ffea608..79d1489dc7 100644
---- a/drivers/mtd/nand/raw/lpc32xx_nand_mlc.c
-+++ b/drivers/mtd/nand/raw/lpc32xx_nand_mlc.c
-@@ -82,6 +82,10 @@ struct lpc32xx_nand_mlc_registers {
- static struct lpc32xx_nand_mlc_registers __iomem *lpc32xx_nand_mlc_registers
- 	= (struct lpc32xx_nand_mlc_registers __iomem *)MLC_NAND_BASE;
- 
-+#if !defined(CONFIG_SYS_MAX_NAND_CHIPS)
-+#define CONFIG_SYS_MAX_NAND_CHIPS	1
-+#endif
-+
- #define clkdiv(v, w, o) (((1+(clk/v)) & w) << o)
- 
- /**
-diff --git a/drivers/mtd/nand/raw/lpc32xx_nand_slc.c b/drivers/mtd/nand/raw/lpc32xx_nand_slc.c
-index 99f6e15f4e..8615b112a2 100644
---- a/drivers/mtd/nand/raw/lpc32xx_nand_slc.c
-+++ b/drivers/mtd/nand/raw/lpc32xx_nand_slc.c
-@@ -2,13 +2,12 @@
- /*
-  * LPC32xx SLC NAND flash controller driver
-  *
-- * (C) Copyright 2015 Vladimir Zapolskiy <vz@mleia.com>
-+ * (C) Copyright 2015-2018 Vladimir Zapolskiy <vz@mleia.com>
-+ * Copyright (c) 2015 Tyco Fire Protection Products.
-  *
-  * Hardware ECC support original source code
-  * Copyright (C) 2008 by NXP Semiconductors
-  * Author: Kevin Wells
-- *
-- * Copyright (c) 2015 Tyco Fire Protection Products.
-  */
- 
- #include <common.h>
-@@ -22,10 +21,6 @@
- #include <asm/arch/dma.h>
- #include <asm/arch/cpu.h>
- 
--#if defined(CONFIG_DMA_LPC32XX) && defined(CONFIG_SPL_BUILD)
--#warning "DMA support in SPL image is not tested"
--#endif
--
- struct lpc32xx_nand_slc_regs {
- 	u32 data;
- 	u32 addr;
-@@ -78,16 +73,14 @@ struct lpc32xx_nand_slc_regs {
-  * Note: For large page devices, the default layouts are used. */
- static struct nand_ecclayout lpc32xx_nand_oob_16 = {
- 	.eccbytes = 6,
--	.eccpos = {10, 11, 12, 13, 14, 15},
-+	.eccpos = { 10, 11, 12, 13, 14, 15, },
- 	.oobfree = {
--		{.offset = 0,
--		 . length = 4},
--		{.offset = 6,
--		 . length = 4}
--		}
-+		{ .offset = 0, .length = 4, },
-+		{ .offset = 6, .length = 4, },
-+	}
- };
- 
--#if defined(CONFIG_DMA_LPC32XX)
-+#if defined(CONFIG_DMA_LPC32XX) && !defined(CONFIG_SPL_BUILD)
- #define ECCSTEPS	(CONFIG_SYS_NAND_PAGE_SIZE / CONFIG_SYS_NAND_ECCSIZE)
- 
- /*
-@@ -165,7 +158,7 @@ static int lpc32xx_nand_dev_ready(struct mtd_info *mtd)
- 	return readl(&lpc32xx_nand_slc_regs->stat) & STAT_NAND_READY;
- }
- 
--#if defined(CONFIG_DMA_LPC32XX)
-+#if defined(CONFIG_DMA_LPC32XX) && !defined(CONFIG_SPL_BUILD)
- /*
-  * Prepares DMA descriptors for NAND RD/WR operations
-  * If the size is < 256 Bytes then it is assumed to be
-@@ -324,7 +317,6 @@ static void lpc32xx_nand_xfer(struct mtd_info *mtd, const u8 *buf,
- 	if (unlikely(ret < 0))
- 		BUG();
- 
--
- 	/* Wait for NAND to be ready */
- 	while (!lpc32xx_nand_dev_ready(mtd))
- 		;
-@@ -404,46 +396,18 @@ int lpc32xx_correct_data(struct mtd_info *mtd, u_char *dat,
- 
- 	return ret2;
- }
--#endif
- 
--#if defined(CONFIG_DMA_LPC32XX)
- static void lpc32xx_dma_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
- {
- 	lpc32xx_nand_xfer(mtd, buf, len, 1);
- }
--#else
--static void lpc32xx_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
--{
--	while (len-- > 0)
--		*buf++ = readl(&lpc32xx_nand_slc_regs->data);
--}
--#endif
- 
--static uint8_t lpc32xx_read_byte(struct mtd_info *mtd)
--{
--	return readl(&lpc32xx_nand_slc_regs->data);
--}
--
--#if defined(CONFIG_DMA_LPC32XX)
- static void lpc32xx_dma_write_buf(struct mtd_info *mtd, const uint8_t *buf,
- 				  int len)
- {
- 	lpc32xx_nand_xfer(mtd, buf, len, 0);
- }
--#else
--static void lpc32xx_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
--{
--	while (len-- > 0)
--		writel(*buf++, &lpc32xx_nand_slc_regs->data);
--}
--#endif
--
--static void lpc32xx_write_byte(struct mtd_info *mtd, uint8_t byte)
--{
--	writel(byte, &lpc32xx_nand_slc_regs->data);
--}
- 
--#if defined(CONFIG_DMA_LPC32XX)
- /* Reuse the logic from "nand_read_page_hwecc()" */
- static int lpc32xx_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
- 				uint8_t *buf, int oob_required, int page)
-@@ -511,8 +475,30 @@ static int lpc32xx_write_page_hwecc(struct mtd_info *mtd,
- 
- 	return 0;
- }
-+#else
-+static void lpc32xx_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
-+{
-+	while (len-- > 0)
-+		*buf++ = readl(&lpc32xx_nand_slc_regs->data);
-+}
-+
-+static void lpc32xx_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
-+{
-+	while (len-- > 0)
-+		writel(*buf++, &lpc32xx_nand_slc_regs->data);
-+}
- #endif
- 
-+static uint8_t lpc32xx_read_byte(struct mtd_info *mtd)
-+{
-+	return readl(&lpc32xx_nand_slc_regs->data);
-+}
-+
-+static void lpc32xx_write_byte(struct mtd_info *mtd, uint8_t byte)
-+{
-+	writel(byte, &lpc32xx_nand_slc_regs->data);
-+}
-+
- /*
-  * LPC32xx has only one SLC NAND controller, don't utilize
-  * CONFIG_SYS_NAND_SELF_INIT to be able to reuse this function
-@@ -520,7 +506,7 @@ static int lpc32xx_write_page_hwecc(struct mtd_info *mtd,
-  */
- int board_nand_init(struct nand_chip *lpc32xx_chip)
- {
--#if defined(CONFIG_DMA_LPC32XX)
-+#if defined(CONFIG_DMA_LPC32XX) && !defined(CONFIG_SPL_BUILD)
- 	int ret;
- 
- 	/* Acquire a channel for our use */
-@@ -543,7 +529,7 @@ int board_nand_init(struct nand_chip *lpc32xx_chip)
- 	lpc32xx_chip->read_byte  = lpc32xx_read_byte;
- 	lpc32xx_chip->write_byte = lpc32xx_write_byte;
- 
--#if defined(CONFIG_DMA_LPC32XX)
-+#if defined(CONFIG_DMA_LPC32XX) && !defined(CONFIG_SPL_BUILD)
- 	/* Hardware ECC calculation is supported when DMA driver is selected */
- 	lpc32xx_chip->ecc.mode		= NAND_ECC_HW;
- 
-diff --git a/drivers/mtd/nand/raw/mxs_nand.c b/drivers/mtd/nand/raw/mxs_nand.c
-index e3341812a2..be4ee2c7f8 100644
---- a/drivers/mtd/nand/raw/mxs_nand.c
-+++ b/drivers/mtd/nand/raw/mxs_nand.c
-@@ -1092,7 +1092,7 @@ int mxs_nand_alloc_buffers(struct mxs_nand_info *nand_info)
- /*
-  * Initializes the NFC hardware.
-  */
--int mxs_nand_init_dma(struct mxs_nand_info *info)
-+static int mxs_nand_init_dma(struct mxs_nand_info *info)
- {
- 	int i = 0, j, ret = 0;
- 
-@@ -1163,6 +1163,12 @@ int mxs_nand_init_spl(struct nand_chip *nand)
- 
- 	nand_info->gpmi_regs = (struct mxs_gpmi_regs *)MXS_GPMI_BASE;
- 	nand_info->bch_regs = (struct mxs_bch_regs *)MXS_BCH_BASE;
-+
-+	if (is_mx6sx() || is_mx7())
-+		nand_info->max_ecc_strength_supported = 62;
-+	else
-+		nand_info->max_ecc_strength_supported = 40;
-+
- 	err = mxs_nand_alloc_buffers(nand_info);
- 	if (err)
- 		return err;
-@@ -1185,9 +1191,6 @@ int mxs_nand_init_spl(struct nand_chip *nand)
- 	nand->ecc.read_page	= mxs_nand_ecc_read_page;
- 
- 	nand->ecc.mode		= NAND_ECC_HW;
--	nand->ecc.bytes		= 9;
--	nand->ecc.size		= 512;
--	nand->ecc.strength	= 8;
- 
- 	return 0;
- }
-diff --git a/drivers/mtd/nand/raw/mxs_nand_spl.c b/drivers/mtd/nand/raw/mxs_nand_spl.c
-index 2d7bbe83cc..ee7d9cb957 100644
---- a/drivers/mtd/nand/raw/mxs_nand_spl.c
-+++ b/drivers/mtd/nand/raw/mxs_nand_spl.c
-@@ -174,23 +174,25 @@ static int is_badblock(struct mtd_info *mtd, loff_t offs, int allowbbt)
- }
- 
- /* setup mtd and nand structs and init mxs_nand driver */
--static int mxs_nand_init(void)
-+void nand_init(void)
- {
- 	/* return if already initalized */
- 	if (nand_chip.numchips)
--		return 0;
-+		return;
- 
- 	/* init mxs nand driver */
- 	mxs_nand_init_spl(&nand_chip);
- 	mtd = nand_to_mtd(&nand_chip);
- 	/* set mtd functions */
- 	nand_chip.cmdfunc = mxs_nand_command;
-+	nand_chip.scan_bbt = nand_default_bbt;
- 	nand_chip.numchips = 1;
- 
- 	/* identify flash device */
- 	if (mxs_flash_ident(mtd)) {
- 		printf("Failed to identify\n");
--		return -1;
-+		nand_chip.numchips = 0; /* If fail, don't use nand */
-+		return;
- 	}
- 
- 	/* allocate and initialize buffers */
-@@ -200,8 +202,7 @@ static int mxs_nand_init(void)
- 	/* setup flash layout (does not scan as we override that) */
- 	mtd->size = nand_chip.chipsize;
- 	nand_chip.scan_bbt(mtd);
--
--	return 0;
-+	mxs_nand_setup_ecc(mtd);
- }
- 
- int nand_spl_load_image(uint32_t offs, unsigned int size, void *buf)
-@@ -211,9 +212,9 @@ int nand_spl_load_image(uint32_t offs, unsigned int size, void *buf)
- 	unsigned int nand_page_per_block;
- 	unsigned int sz = 0;
- 
--	if (mxs_nand_init())
--		return -ENODEV;
- 	chip = mtd_to_nand(mtd);
-+	if (!chip->numchips)
-+		return -ENODEV;
- 	page = offs >> chip->page_shift;
- 	nand_page_per_block = mtd->erasesize / mtd->writesize;
- 
-@@ -254,10 +255,6 @@ int nand_default_bbt(struct mtd_info *mtd)
- 	return 0;
- }
- 
--void nand_init(void)
--{
--}
--
- void nand_deselect(void)
- {
- }
-diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
-index 92daebe120..aba8ac019d 100644
---- a/drivers/mtd/nand/raw/nand_base.c
-+++ b/drivers/mtd/nand/raw/nand_base.c
-@@ -47,6 +47,7 @@
- #include <linux/errno.h>
- 
- /* Define default oob placement schemes for large and small page devices */
-+#ifndef CONFIG_SYS_NAND_DRIVER_ECC_LAYOUT
- static struct nand_ecclayout nand_oob_8 = {
- 	.eccbytes = 3,
- 	.eccpos = {0, 1, 2},
-@@ -89,6 +90,7 @@ static struct nand_ecclayout nand_oob_128 = {
- 		{.offset = 2,
- 		 .length = 78} }
- };
-+#endif
- 
- static int nand_get_device(struct mtd_info *mtd, int new_state);
- 
-@@ -484,14 +486,19 @@ 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);
-+	u8 status;
-+	int ret;
- 
- 	/* Broken xD cards report WP despite being writable */
- 	if (chip->options & NAND_BROKEN_XD)
- 		return 0;
- 
- 	/* Check the WP bit */
--	chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
--	return (chip->read_byte(mtd) & NAND_STATUS_WP) ? 0 : 1;
-+	ret = nand_status_op(chip, &status);
-+	if (ret)
-+		return ret;
-+
-+	return status & NAND_STATUS_WP ? 0 : 1;
- }
- 
- /**
-@@ -573,11 +580,18 @@ static void nand_wait_status_ready(struct mtd_info *mtd, unsigned long timeo)
- {
- 	register struct nand_chip *chip = mtd_to_nand(mtd);
- 	u32 time_start;
-+	int ret;
- 
- 	timeo = (CONFIG_SYS_HZ * timeo) / 1000;
- 	time_start = get_timer(0);
- 	while (get_timer(time_start) < timeo) {
--		if ((chip->read_byte(mtd) & NAND_STATUS_READY))
-+		u8 status;
-+
-+		ret = nand_read_data_op(chip, &status, sizeof(status), true);
-+		if (ret)
-+			return;
-+
-+		if (status & NAND_STATUS_READY)
- 			break;
- 		WATCHDOG_RESET();
- 	}
-@@ -849,7 +863,15 @@ static void panic_nand_wait(struct mtd_info *mtd, struct nand_chip *chip,
- 			if (chip->dev_ready(mtd))
- 				break;
- 		} else {
--			if (chip->read_byte(mtd) & NAND_STATUS_READY)
-+			int ret;
-+			u8 status;
-+
-+			ret = nand_read_data_op(chip, &status, sizeof(status),
-+						true);
-+			if (ret)
-+				return;
-+
-+			if (status & NAND_STATUS_READY)
- 				break;
- 		}
- 		mdelay(1);
-@@ -865,8 +887,9 @@ static void panic_nand_wait(struct mtd_info *mtd, struct nand_chip *chip,
-  */
- static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
- {
--	int status;
- 	unsigned long timeo = 400;
-+	u8 status;
-+	int ret;
- 
- 	led_trigger_event(nand_led_trigger, LED_FULL);
- 
-@@ -876,7 +899,9 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
- 	 */
- 	ndelay(100);
- 
--	chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
-+	ret = nand_status_op(chip, NULL);
-+	if (ret)
-+		return ret;
- 
-  	u32 timer = (CONFIG_SYS_HZ * timeo) / 1000;
-  	u32 time_start;
-@@ -887,13 +912,21 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
- 			if (chip->dev_ready(mtd))
- 				break;
- 		} else {
--			if (chip->read_byte(mtd) & NAND_STATUS_READY)
-+			ret = nand_read_data_op(chip, &status,
-+						sizeof(status), true);
-+			if (ret)
-+				return ret;
-+
-+			if (status & NAND_STATUS_READY)
- 				break;
- 		}
- 	}
- 	led_trigger_event(nand_led_trigger, LED_OFF);
- 
--	status = (int)chip->read_byte(mtd);
-+	ret = nand_read_data_op(chip, &status, sizeof(status), true);
-+	if (ret)
-+		return ret;
-+
- 	/* This can happen if in case of timeout or buggy dev_ready */
- 	WARN_ON(!(status & NAND_STATUS_READY));
- 	return status;
-@@ -1045,6 +1078,516 @@ static void __maybe_unused nand_release_data_interface(struct nand_chip *chip)
- 	kfree(chip->data_interface);
- }
- 
-+/**
-+ * nand_read_page_op - Do a READ PAGE operation
-+ * @chip: The NAND chip
-+ * @page: page to read
-+ * @offset_in_page: offset within the page
-+ * @buf: buffer used to store the data
-+ * @len: length of the buffer
-+ *
-+ * This function issues a READ PAGE operation.
-+ * This function does not select/unselect the CS line.
-+ *
-+ * Returns 0 on success, a negative error code otherwise.
-+ */
-+int nand_read_page_op(struct nand_chip *chip, unsigned int page,
-+		      unsigned int offset_in_page, void *buf, unsigned int len)
-+{
-+	struct mtd_info *mtd = nand_to_mtd(chip);
-+
-+	if (len && !buf)
-+		return -EINVAL;
-+
-+	if (offset_in_page + len > mtd->writesize + mtd->oobsize)
-+		return -EINVAL;
-+
-+	chip->cmdfunc(mtd, NAND_CMD_READ0, offset_in_page, page);
-+	if (len)
-+		chip->read_buf(mtd, buf, len);
-+
-+	return 0;
-+}
-+EXPORT_SYMBOL_GPL(nand_read_page_op);
-+
-+/**
-+ * nand_read_param_page_op - Do a READ PARAMETER PAGE operation
-+ * @chip: The NAND chip
-+ * @page: parameter page to read
-+ * @buf: buffer used to store the data
-+ * @len: length of the buffer
-+ *
-+ * This function issues a READ PARAMETER PAGE operation.
-+ * This function does not select/unselect the CS line.
-+ *
-+ * Returns 0 on success, a negative error code otherwise.
-+ */
-+static int nand_read_param_page_op(struct nand_chip *chip, u8 page, void *buf,
-+				   unsigned int len)
-+{
-+	struct mtd_info *mtd = nand_to_mtd(chip);
-+	unsigned int i;
-+	u8 *p = buf;
-+
-+	if (len && !buf)
-+		return -EINVAL;
-+
-+	chip->cmdfunc(mtd, NAND_CMD_PARAM, page, -1);
-+	for (i = 0; i < len; i++)
-+		p[i] = chip->read_byte(mtd);
-+
-+	return 0;
-+}
-+
-+/**
-+ * nand_change_read_column_op - Do a CHANGE READ COLUMN operation
-+ * @chip: The NAND chip
-+ * @offset_in_page: offset within the page
-+ * @buf: buffer used to store the data
-+ * @len: length of the buffer
-+ * @force_8bit: force 8-bit bus access
-+ *
-+ * This function issues a CHANGE READ COLUMN operation.
-+ * This function does not select/unselect the CS line.
-+ *
-+ * Returns 0 on success, a negative error code otherwise.
-+ */
-+int nand_change_read_column_op(struct nand_chip *chip,
-+			       unsigned int offset_in_page, void *buf,
-+			       unsigned int len, bool force_8bit)
-+{
-+	struct mtd_info *mtd = nand_to_mtd(chip);
-+
-+	if (len && !buf)
-+		return -EINVAL;
-+
-+	if (offset_in_page + len > mtd->writesize + mtd->oobsize)
-+		return -EINVAL;
-+
-+	chip->cmdfunc(mtd, NAND_CMD_RNDOUT, offset_in_page, -1);
-+	if (len)
-+		chip->read_buf(mtd, buf, len);
-+
-+	return 0;
-+}
-+EXPORT_SYMBOL_GPL(nand_change_read_column_op);
-+
-+/**
-+ * nand_read_oob_op - Do a READ OOB operation
-+ * @chip: The NAND chip
-+ * @page: page to read
-+ * @offset_in_oob: offset within the OOB area
-+ * @buf: buffer used to store the data
-+ * @len: length of the buffer
-+ *
-+ * This function issues a READ OOB operation.
-+ * This function does not select/unselect the CS line.
-+ *
-+ * Returns 0 on success, a negative error code otherwise.
-+ */
-+int nand_read_oob_op(struct nand_chip *chip, unsigned int page,
-+		     unsigned int offset_in_oob, void *buf, unsigned int len)
-+{
-+	struct mtd_info *mtd = nand_to_mtd(chip);
-+
-+	if (len && !buf)
-+		return -EINVAL;
-+
-+	if (offset_in_oob + len > mtd->oobsize)
-+		return -EINVAL;
-+
-+	chip->cmdfunc(mtd, NAND_CMD_READOOB, offset_in_oob, page);
-+	if (len)
-+		chip->read_buf(mtd, buf, len);
-+
-+	return 0;
-+}
-+EXPORT_SYMBOL_GPL(nand_read_oob_op);
-+
-+/**
-+ * nand_prog_page_begin_op - starts a PROG PAGE operation
-+ * @chip: The NAND chip
-+ * @page: page to write
-+ * @offset_in_page: offset within the page
-+ * @buf: buffer containing the data to write to the page
-+ * @len: length of the buffer
-+ *
-+ * This function issues the first half of a PROG PAGE operation.
-+ * This function does not select/unselect the CS line.
-+ *
-+ * Returns 0 on success, a negative error code otherwise.
-+ */
-+int nand_prog_page_begin_op(struct nand_chip *chip, unsigned int page,
-+			    unsigned int offset_in_page, const void *buf,
-+			    unsigned int len)
-+{
-+	struct mtd_info *mtd = nand_to_mtd(chip);
-+
-+	if (len && !buf)
-+		return -EINVAL;
-+
-+	if (offset_in_page + len > mtd->writesize + mtd->oobsize)
-+		return -EINVAL;
-+
-+	chip->cmdfunc(mtd, NAND_CMD_SEQIN, offset_in_page, page);
-+
-+	if (buf)
-+		chip->write_buf(mtd, buf, len);
-+
-+	return 0;
-+}
-+EXPORT_SYMBOL_GPL(nand_prog_page_begin_op);
-+
-+/**
-+ * nand_prog_page_end_op - ends a PROG PAGE operation
-+ * @chip: The NAND chip
-+ *
-+ * This function issues the second half of a PROG PAGE operation.
-+ * This function does not select/unselect the CS line.
-+ *
-+ * Returns 0 on success, a negative error code otherwise.
-+ */
-+int nand_prog_page_end_op(struct nand_chip *chip)
-+{
-+	struct mtd_info *mtd = nand_to_mtd(chip);
-+	int status;
-+
-+	chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
-+
-+	status = chip->waitfunc(mtd, chip);
-+	if (status & NAND_STATUS_FAIL)
-+		return -EIO;
-+
-+	return 0;
-+}
-+EXPORT_SYMBOL_GPL(nand_prog_page_end_op);
-+
-+/**
-+ * nand_prog_page_op - Do a full PROG PAGE operation
-+ * @chip: The NAND chip
-+ * @page: page to write
-+ * @offset_in_page: offset within the page
-+ * @buf: buffer containing the data to write to the page
-+ * @len: length of the buffer
-+ *
-+ * This function issues a full PROG PAGE operation.
-+ * This function does not select/unselect the CS line.
-+ *
-+ * Returns 0 on success, a negative error code otherwise.
-+ */
-+int nand_prog_page_op(struct nand_chip *chip, unsigned int page,
-+		      unsigned int offset_in_page, const void *buf,
-+		      unsigned int len)
-+{
-+	struct mtd_info *mtd = nand_to_mtd(chip);
-+	int status;
-+
-+	if (!len || !buf)
-+		return -EINVAL;
-+
-+	if (offset_in_page + len > mtd->writesize + mtd->oobsize)
-+		return -EINVAL;
-+
-+	chip->cmdfunc(mtd, NAND_CMD_SEQIN, offset_in_page, page);
-+	chip->write_buf(mtd, buf, len);
-+	chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
-+
-+	status = chip->waitfunc(mtd, chip);
-+	if (status & NAND_STATUS_FAIL)
-+		return -EIO;
-+
-+	return 0;
-+}
-+EXPORT_SYMBOL_GPL(nand_prog_page_op);
-+
-+/**
-+ * nand_change_write_column_op - Do a CHANGE WRITE COLUMN operation
-+ * @chip: The NAND chip
-+ * @offset_in_page: offset within the page
-+ * @buf: buffer containing the data to send to the NAND
-+ * @len: length of the buffer
-+ * @force_8bit: force 8-bit bus access
-+ *
-+ * This function issues a CHANGE WRITE COLUMN operation.
-+ * This function does not select/unselect the CS line.
-+ *
-+ * Returns 0 on success, a negative error code otherwise.
-+ */
-+int nand_change_write_column_op(struct nand_chip *chip,
-+				unsigned int offset_in_page,
-+				const void *buf, unsigned int len,
-+				bool force_8bit)
-+{
-+	struct mtd_info *mtd = nand_to_mtd(chip);
-+
-+	if (len && !buf)
-+		return -EINVAL;
-+
-+	if (offset_in_page + len > mtd->writesize + mtd->oobsize)
-+		return -EINVAL;
-+
-+	chip->cmdfunc(mtd, NAND_CMD_RNDIN, offset_in_page, -1);
-+	if (len)
-+		chip->write_buf(mtd, buf, len);
-+
-+	return 0;
-+}
-+EXPORT_SYMBOL_GPL(nand_change_write_column_op);
-+
-+/**
-+ * nand_readid_op - Do a READID operation
-+ * @chip: The NAND chip
-+ * @addr: address cycle to pass after the READID command
-+ * @buf: buffer used to store the ID
-+ * @len: length of the buffer
-+ *
-+ * This function sends a READID command and reads back the ID returned by the
-+ * NAND.
-+ * This function does not select/unselect the CS line.
-+ *
-+ * Returns 0 on success, a negative error code otherwise.
-+ */
-+int nand_readid_op(struct nand_chip *chip, u8 addr, void *buf,
-+		   unsigned int len)
-+{
-+	struct mtd_info *mtd = nand_to_mtd(chip);
-+	unsigned int i;
-+	u8 *id = buf;
-+
-+	if (len && !buf)
-+		return -EINVAL;
-+
-+	chip->cmdfunc(mtd, NAND_CMD_READID, addr, -1);
-+
-+	for (i = 0; i < len; i++)
-+		id[i] = chip->read_byte(mtd);
-+
-+	return 0;
-+}
-+EXPORT_SYMBOL_GPL(nand_readid_op);
-+
-+/**
-+ * nand_status_op - Do a STATUS operation
-+ * @chip: The NAND chip
-+ * @status: out variable to store the NAND status
-+ *
-+ * This function sends a STATUS command and reads back the status returned by
-+ * the NAND.
-+ * This function does not select/unselect the CS line.
-+ *
-+ * Returns 0 on success, a negative error code otherwise.
-+ */
-+int nand_status_op(struct nand_chip *chip, u8 *status)
-+{
-+	struct mtd_info *mtd = nand_to_mtd(chip);
-+
-+	chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
-+	if (status)
-+		*status = chip->read_byte(mtd);
-+
-+	return 0;
-+}
-+EXPORT_SYMBOL_GPL(nand_status_op);
-+
-+/**
-+ * nand_exit_status_op - Exit a STATUS operation
-+ * @chip: The NAND chip
-+ *
-+ * This function sends a READ0 command to cancel the effect of the STATUS
-+ * command to avoid reading only the status until a new read command is sent.
-+ *
-+ * This function does not select/unselect the CS line.
-+ *
-+ * Returns 0 on success, a negative error code otherwise.
-+ */
-+int nand_exit_status_op(struct nand_chip *chip)
-+{
-+	struct mtd_info *mtd = nand_to_mtd(chip);
-+
-+	chip->cmdfunc(mtd, NAND_CMD_READ0, -1, -1);
-+
-+	return 0;
-+}
-+EXPORT_SYMBOL_GPL(nand_exit_status_op);
-+
-+/**
-+ * nand_erase_op - Do an erase operation
-+ * @chip: The NAND chip
-+ * @eraseblock: block to erase
-+ *
-+ * This function sends an ERASE command and waits for the NAND to be ready
-+ * before returning.
-+ * This function does not select/unselect the CS line.
-+ *
-+ * Returns 0 on success, a negative error code otherwise.
-+ */
-+int nand_erase_op(struct nand_chip *chip, unsigned int eraseblock)
-+{
-+	struct mtd_info *mtd = nand_to_mtd(chip);
-+	unsigned int page = eraseblock <<
-+			    (chip->phys_erase_shift - chip->page_shift);
-+	int status;
-+
-+	chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page);
-+	chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1);
-+
-+	status = chip->waitfunc(mtd, chip);
-+	if (status < 0)
-+		return status;
-+
-+	if (status & NAND_STATUS_FAIL)
-+		return -EIO;
-+
-+	return 0;
-+}
-+EXPORT_SYMBOL_GPL(nand_erase_op);
-+
-+/**
-+ * nand_set_features_op - Do a SET FEATURES operation
-+ * @chip: The NAND chip
-+ * @feature: feature id
-+ * @data: 4 bytes of data
-+ *
-+ * This function sends a SET FEATURES command and waits for the NAND to be
-+ * ready before returning.
-+ * This function does not select/unselect the CS line.
-+ *
-+ * Returns 0 on success, a negative error code otherwise.
-+ */
-+static int nand_set_features_op(struct nand_chip *chip, u8 feature,
-+				const void *data)
-+{
-+	struct mtd_info *mtd = nand_to_mtd(chip);
-+	const u8 *params = data;
-+	int i, status;
-+
-+	chip->cmdfunc(mtd, NAND_CMD_SET_FEATURES, feature, -1);
-+	for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
-+		chip->write_byte(mtd, params[i]);
-+
-+	status = chip->waitfunc(mtd, chip);
-+	if (status & NAND_STATUS_FAIL)
-+		return -EIO;
-+
-+	return 0;
-+}
-+
-+/**
-+ * nand_get_features_op - Do a GET FEATURES operation
-+ * @chip: The NAND chip
-+ * @feature: feature id
-+ * @data: 4 bytes of data
-+ *
-+ * This function sends a GET FEATURES command and waits for the NAND to be
-+ * ready before returning.
-+ * This function does not select/unselect the CS line.
-+ *
-+ * Returns 0 on success, a negative error code otherwise.
-+ */
-+static int nand_get_features_op(struct nand_chip *chip, u8 feature,
-+				void *data)
-+{
-+	struct mtd_info *mtd = nand_to_mtd(chip);
-+	u8 *params = data;
-+	int i;
-+
-+	chip->cmdfunc(mtd, NAND_CMD_GET_FEATURES, feature, -1);
-+	for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
-+		params[i] = chip->read_byte(mtd);
-+
-+	return 0;
-+}
-+
-+/**
-+ * nand_reset_op - Do a reset operation
-+ * @chip: The NAND chip
-+ *
-+ * This function sends a RESET command and waits for the NAND to be ready
-+ * before returning.
-+ * This function does not select/unselect the CS line.
-+ *
-+ * Returns 0 on success, a negative error code otherwise.
-+ */
-+int nand_reset_op(struct nand_chip *chip)
-+{
-+	struct mtd_info *mtd = nand_to_mtd(chip);
-+
-+	chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
-+
-+	return 0;
-+}
-+EXPORT_SYMBOL_GPL(nand_reset_op);
-+
-+/**
-+ * nand_read_data_op - Read data from the NAND
-+ * @chip: The NAND chip
-+ * @buf: buffer used to store the data
-+ * @len: length of the buffer
-+ * @force_8bit: force 8-bit bus access
-+ *
-+ * This function does a raw data read on the bus. Usually used after launching
-+ * another NAND operation like nand_read_page_op().
-+ * This function does not select/unselect the CS line.
-+ *
-+ * Returns 0 on success, a negative error code otherwise.
-+ */
-+int nand_read_data_op(struct nand_chip *chip, void *buf, unsigned int len,
-+		      bool force_8bit)
-+{
-+	struct mtd_info *mtd = nand_to_mtd(chip);
-+
-+	if (!len || !buf)
-+		return -EINVAL;
-+
-+	if (force_8bit) {
-+		u8 *p = buf;
-+		unsigned int i;
-+
-+		for (i = 0; i < len; i++)
-+			p[i] = chip->read_byte(mtd);
-+	} else {
-+		chip->read_buf(mtd, buf, len);
-+	}
-+
-+	return 0;
-+}
-+EXPORT_SYMBOL_GPL(nand_read_data_op);
-+
-+/**
-+ * nand_write_data_op - Write data from the NAND
-+ * @chip: The NAND chip
-+ * @buf: buffer containing the data to send on the bus
-+ * @len: length of the buffer
-+ * @force_8bit: force 8-bit bus access
-+ *
-+ * This function does a raw data write on the bus. Usually used after launching
-+ * another NAND operation like nand_write_page_begin_op().
-+ * This function does not select/unselect the CS line.
-+ *
-+ * Returns 0 on success, a negative error code otherwise.
-+ */
-+int nand_write_data_op(struct nand_chip *chip, const void *buf,
-+		       unsigned int len, bool force_8bit)
-+{
-+	struct mtd_info *mtd = nand_to_mtd(chip);
-+
-+	if (!len || !buf)
-+		return -EINVAL;
-+
-+	if (force_8bit) {
-+		const u8 *p = buf;
-+		unsigned int i;
-+
-+		for (i = 0; i < len; i++)
-+			chip->write_byte(mtd, p[i]);
-+	} else {
-+		chip->write_buf(mtd, buf, len);
-+	}
-+
-+	return 0;
-+}
-+EXPORT_SYMBOL_GPL(nand_write_data_op);
-+
- /**
-  * nand_reset - Reset and initialize a NAND device
-  * @chip: The NAND chip
-@@ -1066,8 +1609,10 @@ int nand_reset(struct nand_chip *chip, int chipnr)
- 	 * interface settings, hence this weird ->select_chip() dance.
- 	 */
- 	chip->select_chip(mtd, chipnr);
--	chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
-+	ret = nand_reset_op(chip);
- 	chip->select_chip(mtd, -1);
-+	if (ret)
-+		return ret;
- 
- 	chip->select_chip(mtd, chipnr);
- 	ret = nand_setup_data_interface(chip, chipnr);
-@@ -1218,9 +1763,19 @@ EXPORT_SYMBOL(nand_check_erased_ecc_chunk);
- static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
- 			      uint8_t *buf, int oob_required, int page)
- {
--	chip->read_buf(mtd, buf, mtd->writesize);
--	if (oob_required)
--		chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
-+	int ret;
-+
-+	ret = nand_read_data_op(chip, buf, mtd->writesize, false);
-+	if (ret)
-+		return ret;
-+
-+	if (oob_required) {
-+		ret = nand_read_data_op(chip, chip->oob_poi, mtd->oobsize,
-+					false);
-+		if (ret)
-+			return ret;
-+	}
-+
- 	return 0;
- }
- 
-@@ -1241,29 +1796,46 @@ static int nand_read_page_raw_syndrome(struct mtd_info *mtd,
- 	int eccsize = chip->ecc.size;
- 	int eccbytes = chip->ecc.bytes;
- 	uint8_t *oob = chip->oob_poi;
--	int steps, size;
-+	int steps, size, ret;
- 
- 	for (steps = chip->ecc.steps; steps > 0; steps--) {
--		chip->read_buf(mtd, buf, eccsize);
-+		ret = nand_read_data_op(chip, buf, eccsize, false);
-+		if (ret)
-+			return ret;
-+
- 		buf += eccsize;
- 
- 		if (chip->ecc.prepad) {
--			chip->read_buf(mtd, oob, chip->ecc.prepad);
-+			ret = nand_read_data_op(chip, oob, chip->ecc.prepad,
-+						false);
-+			if (ret)
-+				return ret;
-+
- 			oob += chip->ecc.prepad;
- 		}
- 
--		chip->read_buf(mtd, oob, eccbytes);
-+		ret = nand_read_data_op(chip, oob, eccbytes, false);
-+		if (ret)
-+			return ret;
-+
- 		oob += eccbytes;
- 
- 		if (chip->ecc.postpad) {
--			chip->read_buf(mtd, oob, chip->ecc.postpad);
-+			ret = nand_read_data_op(chip, oob, chip->ecc.postpad,
-+						false);
-+			if (ret)
-+				return ret;
-+
- 			oob += chip->ecc.postpad;
- 		}
- 	}
- 
- 	size = mtd->oobsize - (oob - chip->oob_poi);
--	if (size)
--		chip->read_buf(mtd, oob, size);
-+	if (size) {
-+		ret = nand_read_data_op(chip, oob, size, false);
-+		if (ret)
-+			return ret;
-+	}
- 
- 	return 0;
- }
-@@ -1334,6 +1906,7 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
- 	int busw = (chip->options & NAND_BUSWIDTH_16) ? 2 : 1;
- 	int index;
- 	unsigned int max_bitflips = 0;
-+	int ret;
- 
- 	/* Column address within the page aligned to ECC size (256bytes) */
- 	start_step = data_offs / chip->ecc.size;
-@@ -1351,7 +1924,9 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
- 		chip->cmdfunc(mtd, NAND_CMD_RNDOUT, data_col_addr, -1);
- 
- 	p = bufpoi + data_col_addr;
--	chip->read_buf(mtd, p, datafrag_len);
-+	ret = nand_read_data_op(chip, p, datafrag_len, false);
-+	if (ret)
-+		return ret;
- 
- 	/* Calculate ECC */
- 	for (i = 0; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size)
-@@ -1368,8 +1943,11 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
- 		}
- 	}
- 	if (gaps) {
--		chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize, -1);
--		chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
-+		ret = nand_change_read_column_op(chip, mtd->writesize,
-+						 chip->oob_poi, mtd->oobsize,
-+						 false);
-+		if (ret)
-+			return ret;
- 	} else {
- 		/*
- 		 * Send the command to read the particular ECC bytes take care
-@@ -1382,9 +1960,12 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
- 		if (eccpos[index + (num_steps * chip->ecc.bytes)] & (busw - 1))
- 			aligned_len++;
- 
--		chip->cmdfunc(mtd, NAND_CMD_RNDOUT,
--					mtd->writesize + aligned_pos, -1);
--		chip->read_buf(mtd, &chip->oob_poi[aligned_pos], aligned_len);
-+		ret = nand_change_read_column_op(chip,
-+						 mtd->writesize + aligned_pos,
-+						 &chip->oob_poi[aligned_pos],
-+						 aligned_len, false);
-+		if (ret)
-+			return ret;
- 	}
- 
- 	for (i = 0; i < eccfrag_len; i++)
-@@ -1437,13 +2018,21 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
- 	uint8_t *ecc_code = chip->buffers->ecccode;
- 	uint32_t *eccpos = chip->ecc.layout->eccpos;
- 	unsigned int max_bitflips = 0;
-+	int ret;
- 
- 	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
- 		chip->ecc.hwctl(mtd, NAND_ECC_READ);
--		chip->read_buf(mtd, p, eccsize);
-+
-+		ret = nand_read_data_op(chip, p, eccsize, false);
-+		if (ret)
-+			return ret;
-+
- 		chip->ecc.calculate(mtd, p, &ecc_calc[i]);
- 	}
--	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
-+
-+	ret = nand_read_data_op(chip, chip->oob_poi, mtd->oobsize, false);
-+	if (ret)
-+		return ret;
- 
- 	for (i = 0; i < chip->ecc.total; i++)
- 		ecc_code[i] = chip->oob_poi[eccpos[i]];
-@@ -1499,11 +2088,16 @@ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd,
- 	uint32_t *eccpos = chip->ecc.layout->eccpos;
- 	uint8_t *ecc_calc = chip->buffers->ecccalc;
- 	unsigned int max_bitflips = 0;
-+	int ret;
- 
- 	/* Read the OOB area first */
--	chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
--	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
--	chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
-+	ret = nand_read_oob_op(chip, page, 0, chip->oob_poi, mtd->oobsize);
-+	if (ret)
-+		return ret;
-+
-+	ret = nand_read_page_op(chip, page, 0, NULL, 0);
-+	if (ret)
-+		return ret;
- 
- 	for (i = 0; i < chip->ecc.total; i++)
- 		ecc_code[i] = chip->oob_poi[eccpos[i]];
-@@ -1512,7 +2106,11 @@ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd,
- 		int stat;
- 
- 		chip->ecc.hwctl(mtd, NAND_ECC_READ);
--		chip->read_buf(mtd, p, eccsize);
-+
-+		ret = nand_read_data_op(chip, p, eccsize, false);
-+		if (ret)
-+			return ret;
-+
- 		chip->ecc.calculate(mtd, p, &ecc_calc[i]);
- 
- 		stat = chip->ecc.correct(mtd, p, &ecc_code[i], NULL);
-@@ -1549,7 +2147,7 @@ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd,
- static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
- 				   uint8_t *buf, int oob_required, int page)
- {
--	int i, eccsize = chip->ecc.size;
-+	int ret, i, eccsize = chip->ecc.size;
- 	int eccbytes = chip->ecc.bytes;
- 	int eccsteps = chip->ecc.steps;
- 	int eccpadbytes = eccbytes + chip->ecc.prepad + chip->ecc.postpad;
-@@ -1561,21 +2159,36 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
- 		int stat;
- 
- 		chip->ecc.hwctl(mtd, NAND_ECC_READ);
--		chip->read_buf(mtd, p, eccsize);
-+
-+		ret = nand_read_data_op(chip, p, eccsize, false);
-+		if (ret)
-+			return ret;
- 
- 		if (chip->ecc.prepad) {
--			chip->read_buf(mtd, oob, chip->ecc.prepad);
-+			ret = nand_read_data_op(chip, oob, chip->ecc.prepad,
-+						false);
-+			if (ret)
-+				return ret;
-+
- 			oob += chip->ecc.prepad;
- 		}
- 
- 		chip->ecc.hwctl(mtd, NAND_ECC_READSYN);
--		chip->read_buf(mtd, oob, eccbytes);
-+
-+		ret = nand_read_data_op(chip, oob, eccbytes, false);
-+		if (ret)
-+			return ret;
-+
- 		stat = chip->ecc.correct(mtd, p, oob, NULL);
- 
- 		oob += eccbytes;
- 
- 		if (chip->ecc.postpad) {
--			chip->read_buf(mtd, oob, chip->ecc.postpad);
-+			ret = nand_read_data_op(chip, oob, chip->ecc.postpad,
-+						false);
-+			if (ret)
-+				return ret;
-+
- 			oob += chip->ecc.postpad;
- 		}
- 
-@@ -1599,8 +2212,11 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
- 
- 	/* Calculate remaining oob bytes */
- 	i = mtd->oobsize - (oob - chip->oob_poi);
--	if (i)
--		chip->read_buf(mtd, oob, i);
-+	if (i) {
-+		ret = nand_read_data_op(chip, oob, i, false);
-+		if (ret)
-+			return ret;
-+	}
- 
- 	return max_bitflips;
- }
-@@ -1737,8 +2353,11 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
- 						 __func__, buf);
- 
- read_retry:
--			if (nand_standard_page_accessors(&chip->ecc))
--				chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
-+			if (nand_standard_page_accessors(&chip->ecc)) {
-+				ret = nand_read_page_op(chip, page, 0, NULL, 0);
-+				if (ret)
-+					break;
-+			}
- 
- 			/*
- 			 * Now read the page into the buffer.  Absent an error,
-@@ -1872,9 +2491,7 @@ read_retry:
- static int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
- 			     int page)
- {
--	chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
--	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
--	return 0;
-+	return nand_read_oob_op(chip, page, 0, chip->oob_poi, mtd->oobsize);
- }
- 
- /**
-@@ -1891,25 +2508,43 @@ static int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
- 	int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad;
- 	int eccsize = chip->ecc.size;
- 	uint8_t *bufpoi = chip->oob_poi;
--	int i, toread, sndrnd = 0, pos;
-+	int i, toread, sndrnd = 0, pos, ret;
-+
-+	ret = nand_read_page_op(chip, page, chip->ecc.size, NULL, 0);
-+	if (ret)
-+		return ret;
- 
--	chip->cmdfunc(mtd, NAND_CMD_READ0, chip->ecc.size, page);
- 	for (i = 0; i < chip->ecc.steps; i++) {
- 		if (sndrnd) {
-+			int ret;
-+
- 			pos = eccsize + i * (eccsize + chunk);
- 			if (mtd->writesize > 512)
--				chip->cmdfunc(mtd, NAND_CMD_RNDOUT, pos, -1);
-+				ret = nand_change_read_column_op(chip, pos,
-+								 NULL, 0,
-+								 false);
- 			else
--				chip->cmdfunc(mtd, NAND_CMD_READ0, pos, page);
-+				ret = nand_read_page_op(chip, page, pos, NULL,
-+							0);
-+
-+			if (ret)
-+				return ret;
- 		} else
- 			sndrnd = 1;
- 		toread = min_t(int, length, chunk);
--		chip->read_buf(mtd, bufpoi, toread);
-+
-+		ret = nand_read_data_op(chip, bufpoi, toread, false);
-+		if (ret)
-+			return ret;
-+
- 		bufpoi += toread;
- 		length -= toread;
- 	}
--	if (length > 0)
--		chip->read_buf(mtd, bufpoi, length);
-+	if (length > 0) {
-+		ret = nand_read_data_op(chip, bufpoi, length, false);
-+		if (ret)
-+			return ret;
-+	}
- 
- 	return 0;
- }
-@@ -1923,18 +2558,8 @@ static int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
- static int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
- 			      int page)
- {
--	int status = 0;
--	const uint8_t *buf = chip->oob_poi;
--	int length = mtd->oobsize;
--
--	chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page);
--	chip->write_buf(mtd, buf, length);
--	/* Send command to program the OOB data */
--	chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
--
--	status = chip->waitfunc(mtd, chip);
--
--	return status & NAND_STATUS_FAIL ? -EIO : 0;
-+	return nand_prog_page_op(chip, page, mtd->writesize, chip->oob_poi,
-+				 mtd->oobsize);
- }
- 
- /**
-@@ -1949,7 +2574,7 @@ static int nand_write_oob_syndrome(struct mtd_info *mtd,
- {
- 	int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad;
- 	int eccsize = chip->ecc.size, length = mtd->oobsize;
--	int i, len, pos, status = 0, sndcmd = 0, steps = chip->ecc.steps;
-+	int ret, i, len, pos, sndcmd = 0, steps = chip->ecc.steps;
- 	const uint8_t *bufpoi = chip->oob_poi;
- 
- 	/*
-@@ -1963,7 +2588,10 @@ static int nand_write_oob_syndrome(struct mtd_info *mtd,
- 	} else
- 		pos = eccsize;
- 
--	chip->cmdfunc(mtd, NAND_CMD_SEQIN, pos, page);
-+	ret = nand_prog_page_begin_op(chip, page, pos, NULL, 0);
-+	if (ret)
-+		return ret;
-+
- 	for (i = 0; i < steps; i++) {
- 		if (sndcmd) {
- 			if (mtd->writesize <= 512) {
-@@ -1972,28 +2600,40 @@ static int nand_write_oob_syndrome(struct mtd_info *mtd,
- 				len = eccsize;
- 				while (len > 0) {
- 					int num = min_t(int, len, 4);
--					chip->write_buf(mtd, (uint8_t *)&fill,
--							num);
-+
-+					ret = nand_write_data_op(chip, &fill,
-+								 num, false);
-+					if (ret)
-+						return ret;
-+
- 					len -= num;
- 				}
- 			} else {
- 				pos = eccsize + i * (eccsize + chunk);
--				chip->cmdfunc(mtd, NAND_CMD_RNDIN, pos, -1);
-+				ret = nand_change_write_column_op(chip, pos,
-+								  NULL, 0,
-+								  false);
-+				if (ret)
-+					return ret;
- 			}
- 		} else
- 			sndcmd = 1;
- 		len = min_t(int, length, chunk);
--		chip->write_buf(mtd, bufpoi, len);
-+
-+		ret = nand_write_data_op(chip, bufpoi, len, false);
-+		if (ret)
-+			return ret;
-+
- 		bufpoi += len;
- 		length -= len;
- 	}
--	if (length > 0)
--		chip->write_buf(mtd, bufpoi, length);
--
--	chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
--	status = chip->waitfunc(mtd, chip);
-+	if (length > 0) {
-+		ret = nand_write_data_op(chip, bufpoi, length, false);
-+		if (ret)
-+			return ret;
-+	}
- 
--	return status & NAND_STATUS_FAIL ? -EIO : 0;
-+	return nand_prog_page_end_op(chip);
- }
- 
- /**
-@@ -2152,9 +2792,18 @@ out:
- static int nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
- 			       const uint8_t *buf, int oob_required, int page)
- {
--	chip->write_buf(mtd, buf, mtd->writesize);
--	if (oob_required)
--		chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
-+	int ret;
-+
-+	ret = nand_write_data_op(chip, buf, mtd->writesize, false);
-+	if (ret)
-+		return ret;
-+
-+	if (oob_required) {
-+		ret = nand_write_data_op(chip, chip->oob_poi, mtd->oobsize,
-+					 false);
-+		if (ret)
-+			return ret;
-+	}
- 
- 	return 0;
- }
-@@ -2177,29 +2826,46 @@ static int nand_write_page_raw_syndrome(struct mtd_info *mtd,
- 	int eccsize = chip->ecc.size;
- 	int eccbytes = chip->ecc.bytes;
- 	uint8_t *oob = chip->oob_poi;
--	int steps, size;
-+	int steps, size, ret;
- 
- 	for (steps = chip->ecc.steps; steps > 0; steps--) {
--		chip->write_buf(mtd, buf, eccsize);
-+		ret = nand_write_data_op(chip, buf, eccsize, false);
-+		if (ret)
-+			return ret;
-+
- 		buf += eccsize;
- 
- 		if (chip->ecc.prepad) {
--			chip->write_buf(mtd, oob, chip->ecc.prepad);
-+			ret = nand_write_data_op(chip, oob, chip->ecc.prepad,
-+						 false);
-+			if (ret)
-+				return ret;
-+
- 			oob += chip->ecc.prepad;
- 		}
- 
--		chip->write_buf(mtd, oob, eccbytes);
-+		ret = nand_write_data_op(chip, oob, eccbytes, false);
-+		if (ret)
-+			return ret;
-+
- 		oob += eccbytes;
- 
- 		if (chip->ecc.postpad) {
--			chip->write_buf(mtd, oob, chip->ecc.postpad);
-+			ret = nand_write_data_op(chip, oob, chip->ecc.postpad,
-+						 false);
-+			if (ret)
-+				return ret;
-+
- 			oob += chip->ecc.postpad;
- 		}
- 	}
- 
- 	size = mtd->oobsize - (oob - chip->oob_poi);
--	if (size)
--		chip->write_buf(mtd, oob, size);
-+	if (size) {
-+		ret = nand_write_data_op(chip, oob, size, false);
-+		if (ret)
-+			return ret;
-+	}
- 
- 	return 0;
- }
-@@ -2250,17 +2916,24 @@ static int nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
- 	uint8_t *ecc_calc = chip->buffers->ecccalc;
- 	const uint8_t *p = buf;
- 	uint32_t *eccpos = chip->ecc.layout->eccpos;
-+	int ret;
- 
- 	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
- 		chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
--		chip->write_buf(mtd, p, eccsize);
-+
-+		ret = nand_write_data_op(chip, p, eccsize, false);
-+		if (ret)
-+			return ret;
-+
- 		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->write_buf(mtd, chip->oob_poi, mtd->oobsize);
-+	ret = nand_write_data_op(chip, chip->oob_poi, mtd->oobsize, false);
-+	if (ret)
-+		return ret;
- 
- 	return 0;
- }
-@@ -2291,13 +2964,16 @@ static int nand_write_subpage_hwecc(struct mtd_info *mtd,
- 	uint32_t end_step   = (offset + data_len - 1) / ecc_size;
- 	int oob_bytes       = mtd->oobsize / ecc_steps;
- 	int step, i;
-+	int ret;
- 
- 	for (step = 0; step < ecc_steps; step++) {
- 		/* configure controller for WRITE access */
- 		chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
- 
- 		/* write data (untouched subpages already masked by 0xFF) */
--		chip->write_buf(mtd, buf, ecc_size);
-+		ret = nand_write_data_op(chip, buf, ecc_size, false);
-+		if (ret)
-+			return ret;
- 
- 		/* mask ECC of un-touched subpages by padding 0xFF */
- 		if ((step < start_step) || (step > end_step))
-@@ -2322,7 +2998,9 @@ static int nand_write_subpage_hwecc(struct mtd_info *mtd,
- 		chip->oob_poi[eccpos[i]] = ecc_calc[i];
- 
- 	/* write OOB buffer to NAND device */
--	chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
-+	ret = nand_write_data_op(chip, chip->oob_poi, mtd->oobsize, false);
-+	if (ret)
-+		return ret;
- 
- 	return 0;
- }
-@@ -2349,31 +3027,49 @@ static int nand_write_page_syndrome(struct mtd_info *mtd,
- 	int eccsteps = chip->ecc.steps;
- 	const uint8_t *p = buf;
- 	uint8_t *oob = chip->oob_poi;
-+	int ret;
- 
- 	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
--
- 		chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
--		chip->write_buf(mtd, p, eccsize);
-+
-+		ret = nand_write_data_op(chip, p, eccsize, false);
-+		if (ret)
-+			return ret;
- 
- 		if (chip->ecc.prepad) {
--			chip->write_buf(mtd, oob, chip->ecc.prepad);
-+			ret = nand_write_data_op(chip, oob, chip->ecc.prepad,
-+						 false);
-+			if (ret)
-+				return ret;
-+
- 			oob += chip->ecc.prepad;
- 		}
- 
- 		chip->ecc.calculate(mtd, p, oob);
--		chip->write_buf(mtd, oob, eccbytes);
-+
-+		ret = nand_write_data_op(chip, oob, eccbytes, false);
-+		if (ret)
-+			return ret;
-+
- 		oob += eccbytes;
- 
- 		if (chip->ecc.postpad) {
--			chip->write_buf(mtd, oob, chip->ecc.postpad);
-+			ret = nand_write_data_op(chip, oob, chip->ecc.postpad,
-+						 false);
-+			if (ret)
-+				return ret;
-+
- 			oob += chip->ecc.postpad;
- 		}
- 	}
- 
- 	/* Calculate remaining oob bytes */
- 	i = mtd->oobsize - (oob - chip->oob_poi);
--	if (i)
--		chip->write_buf(mtd, oob, i);
-+	if (i) {
-+		ret = nand_write_data_op(chip, oob, i, false);
-+		if (ret)
-+			return ret;
-+	}
- 
- 	return 0;
- }
-@@ -2401,8 +3097,11 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
- 	else
- 		subpage = 0;
- 
--	if (nand_standard_page_accessors(&chip->ecc))
--		chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
-+	if (nand_standard_page_accessors(&chip->ecc)) {
-+		status = nand_prog_page_begin_op(chip, page, 0, NULL, 0);
-+		if (status)
-+			return status;
-+	}
- 
- 	if (unlikely(raw))
- 		status = chip->ecc.write_page_raw(mtd, chip, buf,
-@@ -2417,13 +3116,8 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
- 	if (status < 0)
- 		return status;
- 
--	if (nand_standard_page_accessors(&chip->ecc)) {
--		chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
--
--		status = chip->waitfunc(mtd, chip);
--		if (status & NAND_STATUS_FAIL)
--			return -EIO;
--	}
-+	if (nand_standard_page_accessors(&chip->ecc))
-+		return nand_prog_page_end_op(chip);
- 
- 	return 0;
- }
-@@ -2783,11 +3477,12 @@ out:
- static int single_erase(struct mtd_info *mtd, int page)
- {
- 	struct nand_chip *chip = mtd_to_nand(mtd);
-+	unsigned int eraseblock;
-+
- 	/* Send commands to erase a block */
--	chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page);
--	chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1);
-+	eraseblock = page >> (chip->phys_erase_shift - chip->page_shift);
- 
--	return chip->waitfunc(mtd, chip);
-+	return nand_erase_op(chip, eraseblock);
- }
- 
- /**
-@@ -2980,9 +3675,6 @@ static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs)
- static int nand_onfi_set_features(struct mtd_info *mtd, struct nand_chip *chip,
- 			int addr, uint8_t *subfeature_param)
- {
--	int status;
--	int i;
--
- #ifdef CONFIG_SYS_NAND_ONFI_DETECTION
- 	if (!chip->onfi_version ||
- 	    !(le16_to_cpu(chip->onfi_params.opt_cmd)
-@@ -2990,14 +3682,7 @@ static int nand_onfi_set_features(struct mtd_info *mtd, struct nand_chip *chip,
- 		return -ENOTSUPP;
- #endif
- 
--	chip->cmdfunc(mtd, NAND_CMD_SET_FEATURES, addr, -1);
--	for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
--		chip->write_byte(mtd, subfeature_param[i]);
--
--	status = chip->waitfunc(mtd, chip);
--	if (status & NAND_STATUS_FAIL)
--		return -EIO;
--	return 0;
-+	return nand_set_features_op(chip, addr, subfeature_param);
- }
- 
- /**
-@@ -3010,8 +3695,6 @@ static int nand_onfi_set_features(struct mtd_info *mtd, struct nand_chip *chip,
- static int nand_onfi_get_features(struct mtd_info *mtd, struct nand_chip *chip,
- 			int addr, uint8_t *subfeature_param)
- {
--	int i;
--
- #ifdef CONFIG_SYS_NAND_ONFI_DETECTION
- 	if (!chip->onfi_version ||
- 	    !(le16_to_cpu(chip->onfi_params.opt_cmd)
-@@ -3019,10 +3702,7 @@ static int nand_onfi_get_features(struct mtd_info *mtd, struct nand_chip *chip,
- 		return -ENOTSUPP;
- #endif
- 
--	chip->cmdfunc(mtd, NAND_CMD_GET_FEATURES, addr, -1);
--	for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
--		*subfeature_param++ = chip->read_byte(mtd);
--	return 0;
-+	return nand_get_features_op(chip, addr, subfeature_param);
- }
- 
- /* Set default functions */
-@@ -3116,7 +3796,7 @@ static int nand_flash_detect_ext_param_page(struct mtd_info *mtd,
- 	struct onfi_ext_section *s;
- 	struct onfi_ext_ecc_info *ecc;
- 	uint8_t *cursor;
--	int ret = -EINVAL;
-+	int ret;
- 	int len;
- 	int i;
- 
-@@ -3126,14 +3806,18 @@ static int nand_flash_detect_ext_param_page(struct mtd_info *mtd,
- 		return -ENOMEM;
- 
- 	/* Send our own NAND_CMD_PARAM. */
--	chip->cmdfunc(mtd, NAND_CMD_PARAM, 0, -1);
-+	ret = nand_read_param_page_op(chip, 0, NULL, 0);
-+	if (ret)
-+		goto ext_out;
- 
- 	/* Use the Change Read Column command to skip the ONFI param pages. */
--	chip->cmdfunc(mtd, NAND_CMD_RNDOUT,
--			sizeof(*p) * p->num_of_param_pages , -1);
-+	ret = nand_change_read_column_op(chip,
-+					 sizeof(*p) * p->num_of_param_pages,
-+					 ep, len, true);
-+	if (ret)
-+		goto ext_out;
- 
--	/* Read out the Extended Parameter Page. */
--	chip->read_buf(mtd, (uint8_t *)ep, len);
-+	ret = -EINVAL;
- 	if ((onfi_crc16(ONFI_CRC_BASE, ((uint8_t *)ep) + 2, len - 2)
- 		!= le16_to_cpu(ep->crc))) {
- 		pr_debug("fail in the CRC.\n");
-@@ -3210,19 +3894,23 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
- 					int *busw)
- {
- 	struct nand_onfi_params *p = &chip->onfi_params;
--	int i, j;
--	int val;
-+	char id[4];
-+	int i, ret, val;
- 
- 	/* Try ONFI for unknown chip or LP */
--	chip->cmdfunc(mtd, NAND_CMD_READID, 0x20, -1);
--	if (chip->read_byte(mtd) != 'O' || chip->read_byte(mtd) != 'N' ||
--		chip->read_byte(mtd) != 'F' || chip->read_byte(mtd) != 'I')
-+	ret = nand_readid_op(chip, 0x20, id, sizeof(id));
-+	if (ret || strncmp(id, "ONFI", 4))
-+		return 0;
-+
-+	ret = nand_read_param_page_op(chip, 0, NULL, 0);
-+	if (ret)
- 		return 0;
- 
--	chip->cmdfunc(mtd, NAND_CMD_PARAM, 0, -1);
- 	for (i = 0; i < 3; i++) {
--		for (j = 0; j < sizeof(*p); j++)
--			((uint8_t *)p)[j] = chip->read_byte(mtd);
-+		ret = nand_read_data_op(chip, p, sizeof(*p), true);
-+		if (ret)
-+			return 0;
-+
- 		if (onfi_crc16(ONFI_CRC_BASE, (uint8_t *)p, 254) ==
- 				le16_to_cpu(p->crc)) {
- 			break;
-@@ -3322,20 +4010,22 @@ static int nand_flash_detect_jedec(struct mtd_info *mtd, struct nand_chip *chip,
- {
- 	struct nand_jedec_params *p = &chip->jedec_params;
- 	struct jedec_ecc_info *ecc;
--	int val;
--	int i, j;
-+	char id[5];
-+	int i, val, ret;
- 
- 	/* Try JEDEC for unknown chip or LP */
--	chip->cmdfunc(mtd, NAND_CMD_READID, 0x40, -1);
--	if (chip->read_byte(mtd) != 'J' || chip->read_byte(mtd) != 'E' ||
--		chip->read_byte(mtd) != 'D' || chip->read_byte(mtd) != 'E' ||
--		chip->read_byte(mtd) != 'C')
-+	ret = nand_readid_op(chip, 0x40, id, sizeof(id));
-+	if (ret || strncmp(id, "JEDEC", sizeof(id)))
-+		return 0;
-+
-+	ret = nand_read_param_page_op(chip, 0x40, NULL, 0);
-+	if (ret)
- 		return 0;
- 
--	chip->cmdfunc(mtd, NAND_CMD_PARAM, 0x40, -1);
- 	for (i = 0; i < 3; i++) {
--		for (j = 0; j < sizeof(*p); j++)
--			((uint8_t *)p)[j] = chip->read_byte(mtd);
-+		ret = nand_read_data_op(chip, p, sizeof(*p), true);
-+		if (ret)
-+			return 0;
- 
- 		if (onfi_crc16(ONFI_CRC_BASE, (uint8_t *)p, 510) ==
- 				le16_to_cpu(p->crc))
-@@ -3706,25 +4396,29 @@ struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
- 						  int *maf_id, int *dev_id,
- 						  struct nand_flash_dev *type)
- {
--	int busw;
--	int i, maf_idx;
-+	int busw, ret;
-+	int maf_idx;
- 	u8 id_data[8];
- 
- 	/*
- 	 * Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx)
- 	 * after power-up.
- 	 */
--	nand_reset(chip, 0);
-+	ret = nand_reset(chip, 0);
-+	if (ret)
-+		return ERR_PTR(ret);
- 
- 	/* Select the device */
- 	chip->select_chip(mtd, 0);
- 
- 	/* Send the command for reading device ID */
--	chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
-+	ret = nand_readid_op(chip, 0, id_data, 2);
-+	if (ret)
-+		return ERR_PTR(ret);
- 
- 	/* Read manufacturer and device IDs */
--	*maf_id = chip->read_byte(mtd);
--	*dev_id = chip->read_byte(mtd);
-+	*maf_id = id_data[0];
-+	*dev_id = id_data[1];
- 
- 	/*
- 	 * Try again to make sure, as some systems the bus-hold or other
-@@ -3733,11 +4427,10 @@ struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
- 	 * not match, ignore the device completely.
- 	 */
- 
--	chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
--
- 	/* Read entire ID string */
--	for (i = 0; i < 8; i++)
--		id_data[i] = chip->read_byte(mtd);
-+	ret = nand_readid_op(chip, 0, id_data, 8);
-+	if (ret)
-+		return ERR_PTR(ret);
- 
- 	if (id_data[0] != *maf_id || id_data[1] != *dev_id) {
- 		pr_info("second ID read did not match %02x,%02x against %02x,%02x\n",
-@@ -3997,15 +4690,17 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
- 
- 	/* Check for a chip array */
- 	for (i = 1; i < maxchips; i++) {
-+		u8 id[2];
-+
- 		/* See comment in nand_get_flash_type for reset */
- 		nand_reset(chip, i);
- 
- 		chip->select_chip(mtd, i);
- 		/* Send the command for reading device ID */
--		chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
-+		nand_readid_op(chip, 0, id, sizeof(id));
-+
- 		/* Read manufacturer and device IDs */
--		if (nand_maf_id != chip->read_byte(mtd) ||
--		    nand_dev_id != chip->read_byte(mtd)) {
-+		if (nand_maf_id != id[0] || nand_dev_id != id[1]) {
- 			chip->select_chip(mtd, -1);
- 			break;
- 		}
-@@ -4339,6 +5034,7 @@ int nand_scan_tail(struct mtd_info *mtd)
- 	 */
- 	if (!ecc->layout && (ecc->mode != NAND_ECC_SOFT_BCH)) {
- 		switch (mtd->oobsize) {
-+#ifndef CONFIG_SYS_NAND_DRIVER_ECC_LAYOUT
- 		case 8:
- 			ecc->layout = &nand_oob_8;
- 			break;
-@@ -4351,6 +5047,7 @@ int nand_scan_tail(struct mtd_info *mtd)
- 		case 128:
- 			ecc->layout = &nand_oob_128;
- 			break;
-+#endif
- 		default:
- 			pr_warn("No oob scheme defined for oobsize %d\n",
- 				   mtd->oobsize);
-diff --git a/drivers/mtd/nand/raw/nand_ids.c b/drivers/mtd/nand/raw/nand_ids.c
-index d457c543c7..3104f879f6 100644
---- a/drivers/mtd/nand/raw/nand_ids.c
-+++ b/drivers/mtd/nand/raw/nand_ids.c
-@@ -52,10 +52,6 @@ struct nand_flash_dev nand_flash_ids[] = {
- 	{"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) },
--	{"S34ML16G2 8G 3.3V 8-bit",
--		{ .id = {0x01, 0xd3, 0xd1, 0x95, 0x5a} },
--		  SZ_2K, SZ_1K, SZ_128K, 0, 5, 128, NAND_ECC_INFO(4, SZ_512),
--		  4 },
- 	{"TC58NVG5D2 32G 3.3V 8-bit",
- 		{ .id = {0x98, 0xd7, 0x94, 0x32, 0x76, 0x56, 0x09, 0x00} },
- 		  SZ_8K, SZ_4K, SZ_1M, 0, 8, 640, NAND_ECC_INFO(40, SZ_1K) },
-@@ -65,6 +61,10 @@ struct nand_flash_dev nand_flash_ids[] = {
- 	{"SDTNRGAMA 64G 3.3V 8-bit",
- 		{ .id = {0x45, 0xde, 0x94, 0x93, 0x76, 0x50} },
- 		  SZ_16K, SZ_8K, SZ_4M, 0, 6, 1280, NAND_ECC_INFO(40, SZ_1K) },
-+	{"H27UBG8T2BTR-BC 32G 3.3V 8-bit",
-+		{ .id = {0xad, 0xd7, 0x94, 0xda, 0x74, 0xc3} },
-+		  SZ_8K, SZ_4K, SZ_2M, NAND_NEED_SCRAMBLING, 6, 640,
-+		  NAND_ECC_INFO(40, SZ_1K), 0 },
- 	{"H27UCG8T2ATR-BC 64G 3.3V 8-bit",
- 		{ .id = {0xad, 0xde, 0x94, 0xda, 0x74, 0xc4} },
- 		  SZ_8K, SZ_8K, SZ_2M, NAND_NEED_SCRAMBLING, 6, 640,
-diff --git a/drivers/mtd/nand/raw/pxa3xx_nand.c b/drivers/mtd/nand/raw/pxa3xx_nand.c
-index 4c783f1e1e..4d2712df4c 100644
---- a/drivers/mtd/nand/raw/pxa3xx_nand.c
-+++ b/drivers/mtd/nand/raw/pxa3xx_nand.c
-@@ -195,6 +195,7 @@ struct pxa3xx_nand_info {
- 
- 	int			cs;
- 	int			use_ecc;	/* use HW ECC ? */
-+	int			force_raw;	/* prevent use_ecc to be set */
- 	int			ecc_bch;	/* using BCH ECC? */
- 	int			use_spare;	/* use spare ? */
- 	int			need_wait;
-@@ -326,14 +327,14 @@ static struct nand_ecclayout ecc_layout_2KB_bch4bit = {
- static struct nand_ecclayout ecc_layout_2KB_bch8bit = {
- 	.eccbytes = 64,
- 	.eccpos = {
--		64,  65,  66,  67,  68,  69,  70,  71,
--		72,  73,  74,  75,  76,  77,  78,  79,
--		80,  81,  82,  83,  84,  85,  86,  87,
--		88,  89,  90,  91,  92,  93,  94,  95,
--		96,  97,  98,  99,  100, 101, 102, 103,
--		104, 105, 106, 107, 108, 109, 110, 111,
--		112, 113, 114, 115, 116, 117, 118, 119,
--		120, 121, 122, 123, 124, 125, 126, 127},
-+		32, 33, 34, 35, 36, 37, 38, 39,
-+		40, 41, 42, 43, 44, 45, 46, 47,
-+		48, 49, 50, 51, 52, 53, 54, 55,
-+		56, 57, 58, 59, 60, 61, 62, 63,
-+		64, 65, 66, 67, 68, 69, 70, 71,
-+		72, 73, 74, 75, 76, 77, 78, 79,
-+		80, 81, 82, 83, 84, 85, 86, 87,
-+		88, 89, 90, 91, 92, 93, 94, 95},
- 	.oobfree = { {1, 4}, {6, 26} }
- };
- 
-@@ -579,7 +580,7 @@ static void disable_int(struct pxa3xx_nand_info *info, uint32_t int_mask)
- 
- static void drain_fifo(struct pxa3xx_nand_info *info, void *data, int len)
- {
--	if (info->ecc_bch) {
-+	if (info->ecc_bch && !info->force_raw) {
- 		u32 ts;
- 
- 		/*
-@@ -612,12 +613,22 @@ static void drain_fifo(struct pxa3xx_nand_info *info, void *data, int len)
- 
- static void handle_data_pio(struct pxa3xx_nand_info *info)
- {
-+	int data_len = info->step_chunk_size;
-+
-+	/*
-+	 * In raw mode, include the spare area and the ECC bytes that are not
-+	 * consumed by the controller in the data section. Do not reorganize
-+	 * here, do it in the ->read_page_raw() handler instead.
-+	 */
-+	if (info->force_raw)
-+		data_len += info->step_spare_size + info->ecc_size;
-+
- 	switch (info->state) {
- 	case STATE_PIO_WRITING:
- 		if (info->step_chunk_size)
- 			writesl(info->mmio_base + NDDB,
- 				info->data_buff + info->data_buff_pos,
--				DIV_ROUND_UP(info->step_chunk_size, 4));
-+				DIV_ROUND_UP(data_len, 4));
- 
- 		if (info->step_spare_size)
- 			writesl(info->mmio_base + NDDB,
-@@ -628,7 +639,10 @@ static void handle_data_pio(struct pxa3xx_nand_info *info)
- 		if (info->step_chunk_size)
- 			drain_fifo(info,
- 				   info->data_buff + info->data_buff_pos,
--				   DIV_ROUND_UP(info->step_chunk_size, 4));
-+				   DIV_ROUND_UP(data_len, 4));
-+
-+		if (info->force_raw)
-+			break;
- 
- 		if (info->step_spare_size)
- 			drain_fifo(info,
-@@ -642,7 +656,7 @@ static void handle_data_pio(struct pxa3xx_nand_info *info)
- 	}
- 
- 	/* Update buffer pointers for multi-page read/write */
--	info->data_buff_pos += info->step_chunk_size;
-+	info->data_buff_pos += data_len;
- 	info->oob_buff_pos += info->step_spare_size;
- }
- 
-@@ -796,7 +810,8 @@ static void prepare_start_command(struct pxa3xx_nand_info *info, int command)
- 	case NAND_CMD_READ0:
- 	case NAND_CMD_READOOB:
- 	case NAND_CMD_PAGEPROG:
--		info->use_ecc = 1;
-+		if (!info->force_raw)
-+			info->use_ecc = 1;
- 		break;
- 	case NAND_CMD_PARAM:
- 		info->use_spare = 0;
-@@ -866,7 +881,13 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command,
- 		 * which is either naked-read or last-read according to the
- 		 * state.
- 		 */
--		if (mtd->writesize == info->chunk_size) {
-+		if (info->force_raw) {
-+			info->ndcb0 |= NDCB0_DBC | (NAND_CMD_READSTART << 8) |
-+				       NDCB0_LEN_OVRD |
-+				       NDCB0_EXT_CMD_TYPE(ext_cmd_type);
-+			info->ndcb3 = info->step_chunk_size +
-+				      info->step_spare_size + info->ecc_size;
-+		} else if (mtd->writesize == info->chunk_size) {
- 			info->ndcb0 |= NDCB0_DBC | (NAND_CMD_READSTART << 8);
- 		} else if (mtd->writesize > info->chunk_size) {
- 			info->ndcb0 |= NDCB0_DBC | (NAND_CMD_READSTART << 8)
-@@ -1216,6 +1237,7 @@ static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd,
- {
- 	struct pxa3xx_nand_host *host = nand_get_controller_data(chip);
- 	struct pxa3xx_nand_info *info = host->info_data;
-+	int bf;
- 
- 	chip->read_buf(mtd, buf, mtd->writesize);
- 	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
-@@ -1223,12 +1245,30 @@ static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd,
- 	if (info->retcode == ERR_CORERR && info->use_ecc) {
- 		mtd->ecc_stats.corrected += info->ecc_err_cnt;
- 
--	} else if (info->retcode == ERR_UNCORERR) {
-+	} else if (info->retcode == ERR_UNCORERR && info->ecc_bch) {
- 		/*
--		 * for blank page (all 0xff), HW will calculate its ECC as
--		 * 0, which is different from the ECC information within
--		 * OOB, ignore such uncorrectable errors
-+		 * Empty pages will trigger uncorrectable errors. Re-read the
-+		 * entire page in raw mode and check for bits not being "1".
-+		 * If there are more than the supported strength, then it means
-+		 * this is an actual uncorrectable error.
- 		 */
-+		chip->ecc.read_page_raw(mtd, chip, buf, oob_required, page);
-+		bf = nand_check_erased_ecc_chunk(buf, mtd->writesize,
-+						 chip->oob_poi, mtd->oobsize,
-+						 NULL, 0, chip->ecc.strength);
-+		if (bf < 0) {
-+			mtd->ecc_stats.failed++;
-+		} else if (bf) {
-+			mtd->ecc_stats.corrected += bf;
-+			info->max_bitflips = max_t(unsigned int,
-+						   info->max_bitflips, bf);
-+			info->retcode = ERR_CORERR;
-+		} else {
-+			info->retcode = ERR_NONE;
-+		}
-+
-+	} else if (info->retcode == ERR_UNCORERR && !info->ecc_bch) {
-+		/* Raw read is not supported with Hamming ECC engine */
- 		if (is_buf_blank(buf, mtd->writesize))
- 			info->retcode = ERR_NONE;
- 		else
-@@ -1238,6 +1278,69 @@ static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd,
- 	return info->max_bitflips;
- }
- 
-+static int pxa3xx_nand_read_page_raw(struct mtd_info *mtd,
-+				     struct nand_chip *chip, uint8_t *buf,
-+				     int oob_required, int page)
-+{
-+	struct pxa3xx_nand_host *host = chip->priv;
-+	struct pxa3xx_nand_info *info = host->info_data;
-+	int chunk, ecc_off_buf;
-+
-+	if (!info->ecc_bch)
-+		return -ENOTSUPP;
-+
-+	/*
-+	 * Set the force_raw boolean, then re-call ->cmdfunc() that will run
-+	 * pxa3xx_nand_start(), which will actually disable the ECC engine.
-+	 */
-+	info->force_raw = true;
-+	chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
-+
-+	ecc_off_buf = (info->nfullchunks * info->spare_size) +
-+		      info->last_spare_size;
-+	for (chunk = 0; chunk < info->nfullchunks; chunk++) {
-+		chip->read_buf(mtd,
-+			       buf + (chunk * info->chunk_size),
-+			       info->chunk_size);
-+		chip->read_buf(mtd,
-+			       chip->oob_poi +
-+			       (chunk * (info->spare_size)),
-+			       info->spare_size);
-+		chip->read_buf(mtd,
-+			       chip->oob_poi + ecc_off_buf +
-+			       (chunk * (info->ecc_size)),
-+			       info->ecc_size - 2);
-+	}
-+
-+	if (info->ntotalchunks > info->nfullchunks) {
-+		chip->read_buf(mtd,
-+			       buf + (info->nfullchunks * info->chunk_size),
-+			       info->last_chunk_size);
-+		chip->read_buf(mtd,
-+			       chip->oob_poi +
-+			       (info->nfullchunks * (info->spare_size)),
-+			       info->last_spare_size);
-+		chip->read_buf(mtd,
-+			       chip->oob_poi + ecc_off_buf +
-+			       (info->nfullchunks * (info->ecc_size)),
-+			       info->ecc_size - 2);
-+	}
-+
-+	info->force_raw = false;
-+
-+	return 0;
-+}
-+
-+static int pxa3xx_nand_read_oob_raw(struct mtd_info *mtd,
-+				    struct nand_chip *chip, int page)
-+{
-+	/* Invalidate page cache */
-+	chip->pagebuf = -1;
-+
-+	return chip->ecc.read_page_raw(mtd, chip, chip->buffers->databuf, true,
-+				       page);
-+}
-+
- static uint8_t pxa3xx_nand_read_byte(struct mtd_info *mtd)
- {
- 	struct nand_chip *chip = mtd_to_nand(mtd);
-@@ -1488,7 +1591,7 @@ static int pxa_ecc_init(struct pxa3xx_nand_info *info,
- 		info->chunk_size = 1024;
- 		info->spare_size = 0;
- 		info->last_chunk_size = 1024;
--		info->last_spare_size = 64;
-+		info->last_spare_size = 32;
- 		info->ecc_size = 32;
- 		ecc->mode = NAND_ECC_HW;
- 		ecc->size = info->chunk_size;
-@@ -1669,6 +1772,8 @@ static int alloc_nand_resource(struct pxa3xx_nand_info *info)
- 
- 		nand_set_controller_data(chip, host);
- 		chip->ecc.read_page	= pxa3xx_nand_read_page_hwecc;
-+		chip->ecc.read_page_raw	= pxa3xx_nand_read_page_raw;
-+		chip->ecc.read_oob_raw	= pxa3xx_nand_read_oob_raw;
- 		chip->ecc.write_page	= pxa3xx_nand_write_page_hwecc;
- 		chip->controller        = &info->controller;
- 		chip->waitfunc		= pxa3xx_nand_waitfunc;
-diff --git a/drivers/mtd/nand/raw/stm32_fmc2_nand.c b/drivers/mtd/nand/raw/stm32_fmc2_nand.c
-index a54af9434a..0a91525ce1 100644
---- a/drivers/mtd/nand/raw/stm32_fmc2_nand.c
-+++ b/drivers/mtd/nand/raw/stm32_fmc2_nand.c
-@@ -1,6 +1,6 @@
- // SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
- /*
-- * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
-+ * Copyright (C) STMicroelectronics 2019
-  * Author: Christophe Kerello <christophe.kerello@st.com>
-  */
- 
-@@ -9,13 +9,8 @@
- #include <dm.h>
- #include <nand.h>
- #include <reset.h>
--#include <syscon.h>
--#include <asm/io.h>
--#include <dm/pinctrl.h>
--#include <linux/bitops.h>
- #include <linux/iopoll.h>
- #include <linux/ioport.h>
--#include <asm/arch/stm32.h>
- 
- /* Bad block marker length */
- #define FMC2_BBM_LEN			2
-@@ -107,7 +102,7 @@
- /* Register: FMC2_BCHDSR0 */
- #define FMC2_BCHDSR0_DUE		BIT(0)
- #define FMC2_BCHDSR0_DEF		BIT(1)
--#define FMC2_BCHDSR0_DEN_MASK		0xf0
-+#define FMC2_BCHDSR0_DEN_MASK		GENMASK(7, 4)
- #define FMC2_BCHDSR0_DEN_SHIFT		4
- 
- /* Register: FMC2_BCHDSR1 */
-@@ -180,10 +175,88 @@ static inline struct stm32_fmc2_nfc *to_stm32_nfc(struct nand_hw_control *base)
- 	return container_of(base, struct stm32_fmc2_nfc, base);
- }
- 
--/* Clear interrupt sources in case of bch is used */
--static inline void stm32_fmc2_clear_bch_irq(struct stm32_fmc2_nfc *fmc2)
-+/* Timings configuration */
-+static void stm32_fmc2_timings_init(struct nand_chip *chip)
- {
--	writel(FMC2_BCHICR_CLEAR_IRQ, fmc2->io_base + FMC2_BCHICR);
-+	struct stm32_fmc2_nfc *fmc2 = to_stm32_nfc(chip->controller);
-+	struct stm32_fmc2_nand *nand = to_fmc2_nand(chip);
-+	struct stm32_fmc2_timings *timings = &nand->timings;
-+	u32 pcr = readl(fmc2->io_base + FMC2_PCR);
-+	u32 pmem, patt;
-+
-+	/* Set tclr/tar timings */
-+	pcr &= ~FMC2_PCR_TCLR_MASK;
-+	pcr |= FMC2_PCR_TCLR(timings->tclr);
-+	pcr &= ~FMC2_PCR_TAR_MASK;
-+	pcr |= FMC2_PCR_TAR(timings->tar);
-+
-+	/* Set tset/twait/thold/thiz timings in common bank */
-+	pmem = FMC2_PMEM_MEMSET(timings->tset_mem);
-+	pmem |= FMC2_PMEM_MEMWAIT(timings->twait);
-+	pmem |= FMC2_PMEM_MEMHOLD(timings->thold_mem);
-+	pmem |= FMC2_PMEM_MEMHIZ(timings->thiz);
-+
-+	/* Set tset/twait/thold/thiz timings in attribut bank */
-+	patt = FMC2_PATT_ATTSET(timings->tset_att);
-+	patt |= FMC2_PATT_ATTWAIT(timings->twait);
-+	patt |= FMC2_PATT_ATTHOLD(timings->thold_att);
-+	patt |= FMC2_PATT_ATTHIZ(timings->thiz);
-+
-+	writel(pcr, fmc2->io_base + FMC2_PCR);
-+	writel(pmem, fmc2->io_base + FMC2_PMEM);
-+	writel(patt, fmc2->io_base + FMC2_PATT);
-+}
-+
-+/* Controller configuration */
-+static void stm32_fmc2_setup(struct nand_chip *chip)
-+{
-+	struct stm32_fmc2_nfc *fmc2 = to_stm32_nfc(chip->controller);
-+	u32 pcr = readl(fmc2->io_base + FMC2_PCR);
-+
-+	/* Configure ECC algorithm (default configuration is Hamming) */
-+	pcr &= ~FMC2_PCR_ECCALG;
-+	pcr &= ~FMC2_PCR_BCHECC;
-+	if (chip->ecc.strength == FMC2_ECC_BCH8) {
-+		pcr |= FMC2_PCR_ECCALG;
-+		pcr |= FMC2_PCR_BCHECC;
-+	} else if (chip->ecc.strength == FMC2_ECC_BCH4) {
-+		pcr |= FMC2_PCR_ECCALG;
-+	}
-+
-+	/* Set buswidth */
-+	pcr &= ~FMC2_PCR_PWID_MASK;
-+	if (chip->options & NAND_BUSWIDTH_16)
-+		pcr |= FMC2_PCR_PWID(FMC2_PCR_PWID_BUSWIDTH_16);
-+
-+	/* Set ECC sector size */
-+	pcr &= ~FMC2_PCR_ECCSS_MASK;
-+	pcr |= FMC2_PCR_ECCSS(FMC2_PCR_ECCSS_512);
-+
-+	writel(pcr, fmc2->io_base + FMC2_PCR);
-+}
-+
-+/* Select target */
-+static void stm32_fmc2_select_chip(struct mtd_info *mtd, int chipnr)
-+{
-+	struct nand_chip *chip = mtd_to_nand(mtd);
-+	struct stm32_fmc2_nfc *fmc2 = to_stm32_nfc(chip->controller);
-+	struct stm32_fmc2_nand *nand = to_fmc2_nand(chip);
-+
-+	if (chipnr < 0 || chipnr >= nand->ncs)
-+		return;
-+
-+	if (nand->cs_used[chipnr] == fmc2->cs_sel)
-+		return;
-+
-+	fmc2->cs_sel = nand->cs_used[chipnr];
-+	chip->IO_ADDR_R = fmc2->data_base[fmc2->cs_sel];
-+	chip->IO_ADDR_W = fmc2->data_base[fmc2->cs_sel];
-+
-+	/* FMC2 setup routine */
-+	stm32_fmc2_setup(chip);
-+
-+	/* Apply timings */
-+	stm32_fmc2_timings_init(chip);
- }
- 
- /* Set bus width to 16-bit or 8-bit */
-@@ -197,7 +270,7 @@ static void stm32_fmc2_set_buswidth_16(struct stm32_fmc2_nfc *fmc2, bool set)
- 	writel(pcr, fmc2->io_base + FMC2_PCR);
- }
- 
--/* Enable/disable ecc */
-+/* Enable/disable ECC */
- static void stm32_fmc2_set_ecc(struct stm32_fmc2_nfc *fmc2, bool enable)
- {
- 	u32 pcr = readl(fmc2->io_base + FMC2_PCR);
-@@ -208,6 +281,12 @@ static void stm32_fmc2_set_ecc(struct stm32_fmc2_nfc *fmc2, bool enable)
- 	writel(pcr, fmc2->io_base + FMC2_PCR);
- }
- 
-+/* Clear irq sources in case of bch is used */
-+static inline void stm32_fmc2_clear_bch_irq(struct stm32_fmc2_nfc *fmc2)
-+{
-+	writel(FMC2_BCHICR_CLEAR_IRQ, fmc2->io_base + FMC2_BCHICR);
-+}
-+
- /* Send command and address cycles */
- static void stm32_fmc2_cmd_ctrl(struct mtd_info *mtd, int cmd,
- 				unsigned int ctrl)
-@@ -227,7 +306,7 @@ static void stm32_fmc2_cmd_ctrl(struct mtd_info *mtd, int cmd,
- }
- 
- /*
-- * Enable ecc logic and reset syndrome/parity bits previously calculated
-+ * Enable ECC logic and reset syndrome/parity bits previously calculated
-  * Syndrome/parity bits is cleared by setting the ECCEN bit to 0
-  */
- static void stm32_fmc2_hwctl(struct mtd_info *mtd, int mode)
-@@ -253,8 +332,8 @@ static void stm32_fmc2_hwctl(struct mtd_info *mtd, int mode)
- }
- 
- /*
-- * Ecc Hamming calculation
-- * Ecc is 3 bytes for 512 bytes of data (supports error correction up to
-+ * ECC Hamming calculation
-+ * ECC is 3 bytes for 512 bytes of data (supports error correction up to
-  * max of 1-bit)
-  */
- static int stm32_fmc2_ham_calculate(struct mtd_info *mtd, const u8 *data,
-@@ -269,7 +348,7 @@ static int stm32_fmc2_ham_calculate(struct mtd_info *mtd, const u8 *data,
- 				 sr & FMC2_SR_NWRF, 10000);
- 	if (ret < 0) {
- 		pr_err("Ham timeout\n");
--		return -ETIMEDOUT;
-+		return ret;
- 	}
- 
- 	heccr = readl(fmc2->io_base + FMC2_HECCR);
-@@ -337,8 +416,8 @@ static int stm32_fmc2_ham_correct(struct mtd_info *mtd, u8 *dat,
- }
- 
- /*
-- * Ecc BCH calculation and correction
-- * Ecc is 7/13 bytes for 512 bytes of data (supports error correction up to
-+ * ECC BCH calculation and correction
-+ * ECC is 7/13 bytes for 512 bytes of data (supports error correction up to
-  * max of 4-bit/8-bit)
-  */
- 
-@@ -350,15 +429,15 @@ static int stm32_fmc2_bch_calculate(struct mtd_info *mtd, const u8 *data,
- 	u32 bchpbr, bchisr;
- 	int ret;
- 
--	/* Wait that the BCH encoder parity is available */
-+	/* Wait until the BCH code is ready */
- 	ret = readl_poll_timeout(fmc2->io_base + FMC2_BCHISR, bchisr,
- 				 bchisr & FMC2_BCHISR_EPBRF, 10000);
- 	if (ret < 0) {
- 		pr_err("Bch timeout\n");
--		return -ETIMEDOUT;
-+		return ret;
- 	}
- 
--	/* Read parity bits (write) or syndrome (read) */
-+	/* Read parity bits */
- 	bchpbr = readl(fmc2->io_base + FMC2_BCHPBR1);
- 	ecc[0] = bchpbr;
- 	ecc[1] = bchpbr >> 8;
-@@ -400,12 +479,12 @@ static int stm32_fmc2_bch_correct(struct mtd_info *mtd, u8 *dat,
- 	int i, ret, den, eccsize = chip->ecc.size;
- 	unsigned int nb_errs = 0;
- 
--	/* Wait that the BCH encoder syndrome is available */
-+	/* Wait until the decoding error is ready */
- 	ret = readl_poll_timeout(fmc2->io_base + FMC2_BCHISR, bchisr,
- 				 bchisr & FMC2_BCHISR_DERF, 10000);
- 	if (ret < 0) {
- 		pr_err("Bch timeout\n");
--		return -ETIMEDOUT;
-+		return ret;
- 	}
- 
- 	bchdsr0 = readl(fmc2->io_base + FMC2_BCHDSR0);
-@@ -414,7 +493,7 @@ static int stm32_fmc2_bch_correct(struct mtd_info *mtd, u8 *dat,
- 	bchdsr3 = readl(fmc2->io_base + FMC2_BCHDSR3);
- 	bchdsr4 = readl(fmc2->io_base + FMC2_BCHDSR4);
- 
--	/* Disable ecc */
-+	/* Disable ECC */
- 	stm32_fmc2_set_ecc(fmc2, false);
- 
- 	/* No errors found */
-@@ -466,7 +545,7 @@ static int stm32_fmc2_read_page(struct mtd_info *mtd,
- 		chip->cmdfunc(mtd, NAND_CMD_RNDOUT, s * eccsize, -1);
- 		chip->read_buf(mtd, p, eccsize);
- 
--		/* Read the corresponding ecc bytes */
-+		/* Read the corresponding ECC bytes */
- 		chip->cmdfunc(mtd, NAND_CMD_RNDOUT, i, -1);
- 		chip->read_buf(mtd, ecc_code, eccbytes);
- 
-@@ -488,44 +567,14 @@ static int stm32_fmc2_read_page(struct mtd_info *mtd,
- 	}
- 
- 	/* Read oob */
--	chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize, -1);
--	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
-+	if (oob_required) {
-+		chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize, -1);
-+		chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
-+	}
- 
- 	return max_bitflips;
- }
- 
--/* Timings configuration */
--static void stm32_fmc2_timings_init(struct nand_chip *chip)
--{
--	struct stm32_fmc2_nfc *fmc2 = to_stm32_nfc(chip->controller);
--	struct stm32_fmc2_nand *nand = to_fmc2_nand(chip);
--	struct stm32_fmc2_timings *timings = &nand->timings;
--	u32 pcr = readl(fmc2->io_base + FMC2_PCR);
--	u32 pmem, patt;
--
--	/* Set tclr/tar timings */
--	pcr &= ~FMC2_PCR_TCLR_MASK;
--	pcr |= FMC2_PCR_TCLR(timings->tclr);
--	pcr &= ~FMC2_PCR_TAR_MASK;
--	pcr |= FMC2_PCR_TAR(timings->tar);
--
--	/* Set tset/twait/thold/thiz timings in common bank */
--	pmem = FMC2_PMEM_MEMSET(timings->tset_mem);
--	pmem |= FMC2_PMEM_MEMWAIT(timings->twait);
--	pmem |= FMC2_PMEM_MEMHOLD(timings->thold_mem);
--	pmem |= FMC2_PMEM_MEMHIZ(timings->thiz);
--
--	/* Set tset/twait/thold/thiz timings in attribut bank */
--	patt = FMC2_PATT_ATTSET(timings->tset_att);
--	patt |= FMC2_PATT_ATTWAIT(timings->twait);
--	patt |= FMC2_PATT_ATTHOLD(timings->thold_att);
--	patt |= FMC2_PATT_ATTHIZ(timings->thiz);
--
--	writel(pcr, fmc2->io_base + FMC2_PCR);
--	writel(pmem, fmc2->io_base + FMC2_PMEM);
--	writel(patt, fmc2->io_base + FMC2_PATT);
--}
--
- /* Controller initialization */
- static void stm32_fmc2_init(struct stm32_fmc2_nfc *fmc2)
- {
-@@ -542,7 +591,7 @@ static void stm32_fmc2_init(struct stm32_fmc2_nfc *fmc2)
- 	/* Set buswidth to 8 bits mode for identification */
- 	pcr &= ~FMC2_PCR_PWID_MASK;
- 
--	/* Ecc logic is disabled */
-+	/* ECC logic is disabled */
- 	pcr &= ~FMC2_PCR_ECCEN;
- 
- 	/* Default mode */
-@@ -550,7 +599,7 @@ static void stm32_fmc2_init(struct stm32_fmc2_nfc *fmc2)
- 	pcr &= ~FMC2_PCR_BCHECC;
- 	pcr &= ~FMC2_PCR_WEN;
- 
--	/* Set default ecc sector size */
-+	/* Set default ECC sector size */
- 	pcr &= ~FMC2_PCR_ECCSS_MASK;
- 	pcr |= FMC2_PCR_ECCSS(FMC2_PCR_ECCSS_2048);
- 
-@@ -569,55 +618,6 @@ static void stm32_fmc2_init(struct stm32_fmc2_nfc *fmc2)
- 	writel(FMC2_PATT_DEFAULT, fmc2->io_base + FMC2_PATT);
- }
- 
--/* Controller configuration */
--static void stm32_fmc2_setup(struct nand_chip *chip)
--{
--	struct stm32_fmc2_nfc *fmc2 = to_stm32_nfc(chip->controller);
--	u32 pcr = readl(fmc2->io_base + FMC2_PCR);
--
--	/* Configure in Hamming by default */
--	if (chip->ecc.strength == FMC2_ECC_BCH8) {
--		pcr |= FMC2_PCR_ECCALG;
--		pcr |= FMC2_PCR_BCHECC;
--	} else if (chip->ecc.strength == FMC2_ECC_BCH4) {
--		pcr |= FMC2_PCR_ECCALG;
--	}
--
--	/* Set buswidth */
--	if (chip->options & NAND_BUSWIDTH_16)
--		pcr |= FMC2_PCR_PWID(FMC2_PCR_PWID_BUSWIDTH_16);
--
--	/* Set ecc sector size */
--	pcr &= ~FMC2_PCR_ECCSS_MASK;
--	pcr |= FMC2_PCR_ECCSS(FMC2_PCR_ECCSS_512);
--
--	writel(pcr, fmc2->io_base + FMC2_PCR);
--}
--
--/* Select function */
--static void stm32_fmc2_select_chip(struct mtd_info *mtd, int chipnr)
--{
--	struct nand_chip *chip = mtd_to_nand(mtd);
--	struct stm32_fmc2_nfc *fmc2 = to_stm32_nfc(chip->controller);
--	struct stm32_fmc2_nand *nand = to_fmc2_nand(chip);
--
--	if (chipnr < 0 || chipnr >= nand->ncs)
--		return;
--
--	if (nand->cs_used[chipnr] == fmc2->cs_sel)
--		return;
--
--	fmc2->cs_sel = nand->cs_used[chipnr];
--	chip->IO_ADDR_R = fmc2->data_base[fmc2->cs_sel];
--	chip->IO_ADDR_W = fmc2->data_base[fmc2->cs_sel];
--
--	/* FMC2 setup routine */
--	stm32_fmc2_setup(chip);
--
--	/* Apply timings */
--	stm32_fmc2_timings_init(chip);
--}
--
- /* Controller timings */
- static void stm32_fmc2_calc_timings(struct nand_chip *chip,
- 				    const struct nand_sdr_timings *sdrt)
-@@ -824,7 +824,7 @@ static int stm32_fmc2_parse_child(struct stm32_fmc2_nfc *fmc2,
- {
- 	struct stm32_fmc2_nand *nand = &fmc2->nand;
- 	u32 cs[FMC2_MAX_CE];
--	int ret, chip_cs;
-+	int ret, i;
- 
- 	if (!ofnode_get_property(node, "reg", &nand->ncs))
- 		return -EINVAL;
-@@ -841,21 +841,21 @@ static int stm32_fmc2_parse_child(struct stm32_fmc2_nfc *fmc2,
- 		return -EINVAL;
- 	}
- 
--	for (chip_cs = 0; chip_cs < nand->ncs; chip_cs++) {
--		if (cs[chip_cs] > FMC2_MAX_CE) {
-+	for (i = 0; i < nand->ncs; i++) {
-+		if (cs[i] > FMC2_MAX_CE) {
- 			pr_err("Invalid reg value: %d\n",
--			       nand->cs_used[chip_cs]);
-+			       nand->cs_used[i]);
- 			return -EINVAL;
- 		}
- 
--		if (fmc2->cs_assigned & BIT(cs[chip_cs])) {
-+		if (fmc2->cs_assigned & BIT(cs[i])) {
- 			pr_err("Cs already assigned: %d\n",
--			       nand->cs_used[chip_cs]);
-+			       nand->cs_used[i]);
- 			return -EINVAL;
- 		}
- 
--		fmc2->cs_assigned |= BIT(cs[chip_cs]);
--		nand->cs_used[chip_cs] = cs[chip_cs];
-+		fmc2->cs_assigned |= BIT(cs[i]);
-+		nand->cs_used[i] = cs[i];
- 	}
- 
- 	nand->chip.flash_node = ofnode_to_offset(node);
-@@ -863,8 +863,8 @@ static int stm32_fmc2_parse_child(struct stm32_fmc2_nfc *fmc2,
- 	return 0;
- }
- 
--static int stm32_fmc2_parse_children(struct udevice *dev,
--				     struct stm32_fmc2_nfc *fmc2)
-+static int stm32_fmc2_parse_dt(struct udevice *dev,
-+			       struct stm32_fmc2_nfc *fmc2)
- {
- 	ofnode child;
- 	int ret, nchips = 0;
-@@ -906,7 +906,7 @@ static int stm32_fmc2_probe(struct udevice *dev)
- 	spin_lock_init(&fmc2->controller.lock);
- 	init_waitqueue_head(&fmc2->controller.wq);
- 
--	ret = stm32_fmc2_parse_children(dev, fmc2);
-+	ret = stm32_fmc2_parse_dt(dev, fmc2);
- 	if (ret)
- 		return ret;
- 
-@@ -948,7 +948,7 @@ static int stm32_fmc2_probe(struct udevice *dev)
- 		fmc2->addr_base[chip_cs] = (void __iomem *)resource.start;
- 	}
- 
--	/* Enable clock */
-+	/* Enable the clock */
- 	ret = clk_get_by_index(dev, 0, &fmc2->clk);
- 	if (ret)
- 		return ret;
-@@ -976,7 +976,7 @@ static int stm32_fmc2_probe(struct udevice *dev)
- 	chip->options |= NAND_BUSWIDTH_AUTO | NAND_NO_SUBPAGE_WRITE |
- 			 NAND_USE_BOUNCE_BUFFER;
- 
--	/* Default settings */
-+	/* Default ECC settings */
- 	chip->ecc.mode = NAND_ECC_HW;
- 	chip->ecc.size = FMC2_ECC_STEP_SIZE;
- 	chip->ecc.strength = FMC2_ECC_BCH8;
-@@ -991,7 +991,7 @@ static int stm32_fmc2_probe(struct udevice *dev)
- 	 * Hamming => ecc.strength = 1
- 	 * BCH4 => ecc.strength = 4
- 	 * BCH8 => ecc.strength = 8
--	 * ecc sector size = 512
-+	 * ECC sector size = 512
- 	 */
- 	if (chip->ecc.mode != NAND_ECC_HW) {
- 		pr_err("Nand_ecc_mode is not well defined in the DT\n");
-diff --git a/drivers/mtd/nand/raw/vf610_nfc.c b/drivers/mtd/nand/raw/vf610_nfc.c
-index 619d0403e9..3326c2b096 100644
---- a/drivers/mtd/nand/raw/vf610_nfc.c
-+++ b/drivers/mtd/nand/raw/vf610_nfc.c
-@@ -31,6 +31,11 @@
- #include <nand.h>
- #include <errno.h>
- #include <asm/io.h>
-+#if CONFIG_NAND_VF610_NFC_DT
-+#include <dm.h>
-+#include <linux/io.h>
-+#include <linux/ioport.h>
-+#endif
- 
- /* Register Offsets */
- #define NFC_FLASH_CMD1			0x3F00
-@@ -641,7 +646,7 @@ static int vf610_nfc_nand_init(int devnum, void __iomem *addr)
- 		.flash_bbt = 1,
- 	};
- 
--	nfc = malloc(sizeof(*nfc));
-+	nfc = calloc(1, sizeof(*nfc));
- 	if (!nfc) {
- 		printf(KERN_ERR "%s: Memory exhausted!\n", __func__);
- 		return -ENOMEM;
-@@ -760,9 +765,51 @@ error:
- 	return err;
- }
- 
-+#if CONFIG_NAND_VF610_NFC_DT
-+static const struct udevice_id vf610_nfc_dt_ids[] = {
-+	{
-+		.compatible = "fsl,vf610-nfc",
-+	},
-+	{ /* sentinel */ }
-+};
-+
-+static int vf610_nfc_dt_probe(struct udevice *dev)
-+{
-+	struct resource res;
-+	int ret;
-+
-+	ret = dev_read_resource(dev, 0, &res);
-+	if (ret)
-+		return ret;
-+
-+	return vf610_nfc_nand_init(0, devm_ioremap(dev, res.start,
-+						   resource_size(&res)));
-+}
-+
-+U_BOOT_DRIVER(vf610_nfc_dt) = {
-+	.name = "vf610-nfc-dt",
-+	.id = UCLASS_MTD,
-+	.of_match = vf610_nfc_dt_ids,
-+	.probe = vf610_nfc_dt_probe,
-+};
-+
-+void board_nand_init(void)
-+{
-+	struct udevice *dev;
-+	int ret;
-+
-+	ret = uclass_get_device_by_driver(UCLASS_MTD,
-+					  DM_GET_DRIVER(vf610_nfc_dt),
-+					  &dev);
-+	if (ret && ret != -ENODEV)
-+		pr_err("Failed to initialize NAND controller. (error %d)\n",
-+		       ret);
-+}
-+#else
- void board_nand_init(void)
- {
- 	int err = vf610_nfc_nand_init(0, (void __iomem *)CONFIG_SYS_NAND_BASE);
- 	if (err)
- 		printf("VF610 NAND init failed (err %d)\n", err);
- }
-+#endif /* CONFIG_NAND_VF610_NFC_DT */
-diff --git a/drivers/mtd/nand/spi/Makefile b/drivers/mtd/nand/spi/Makefile
-index dd6bacae34..6c65b187e8 100644
---- a/drivers/mtd/nand/spi/Makefile
-+++ b/drivers/mtd/nand/spi/Makefile
-@@ -1,4 +1,4 @@
- # SPDX-License-Identifier: GPL-2.0
- 
--spinand-objs := core.o gigadevice.o macronix.o micron.o winbond.o
-+spinand-objs := core.o gigadevice.o macronix.o micron.o toshiba.o winbond.o
- obj-$(CONFIG_MTD_SPI_NAND) += spinand.o
-diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
-index cb8ffa3fa9..0684169abb 100644
---- a/drivers/mtd/nand/spi/core.c
-+++ b/drivers/mtd/nand/spi/core.c
-@@ -833,6 +833,7 @@ static const struct spinand_manufacturer *spinand_manufacturers[] = {
- 	&gigadevice_spinand_manufacturer,
- 	&macronix_spinand_manufacturer,
- 	&micron_spinand_manufacturer,
-+	&toshiba_spinand_manufacturer,
- 	&winbond_spinand_manufacturer,
- };
- 
-@@ -1146,6 +1147,8 @@ static int spinand_probe(struct udevice *dev)
- 	struct nand_device *nand = spinand_to_nand(spinand);
- 	int ret;
- 
-+	debug("%s is called aabb",__func__);
-+
- #ifndef __UBOOT__
- 	spinand = devm_kzalloc(&mem->spi->dev, sizeof(*spinand),
- 			       GFP_KERNEL);
-diff --git a/drivers/mtd/nand/spi/gigadevice.c b/drivers/mtd/nand/spi/gigadevice.c
-index 0bade20808..3681c5eed9 100644
---- a/drivers/mtd/nand/spi/gigadevice.c
-+++ b/drivers/mtd/nand/spi/gigadevice.c
-@@ -12,12 +12,11 @@
- #endif
- #include <linux/mtd/spinand.h>
- 
--#define SPINAND_MFR_GIGADEVICE			0xc8
-+#define SPINAND_MFR_GIGADEVICE			0xC8
-+#define GD5FXGQ4XA_STATUS_ECC_1_7_BITFLIPS	(1 << 4)
-+#define GD5FXGQ4XA_STATUS_ECC_8_BITFLIPS	(3 << 4)
- 
--#define GIGADEVICE_STATUS_ECC_MASK		GENMASK(5, 4)
--#define GIGADEVICE_STATUS_ECC_NO_BITFLIPS	(0 << 4)
--#define GIGADEVICE_STATUS_ECC_1TO7_BITFLIPS	(1 << 4)
--#define GIGADEVICE_STATUS_ECC_8_BITFLIPS	(3 << 4)
-+#define GD5FXGQ4XEXXG_REG_STATUS2		0xf0
- 
- static SPINAND_OP_VARIANTS(read_cache_variants,
- 		SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
-@@ -35,8 +34,8 @@ static SPINAND_OP_VARIANTS(update_cache_variants,
- 		SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
- 		SPINAND_PROG_LOAD(false, 0, NULL, 0));
- 
--static int gd5f1gq4u_ooblayout_ecc(struct mtd_info *mtd, int section,
--				   struct mtd_oob_region *region)
-+static int gd5fxgq4xexxg_ooblayout_ecc(struct mtd_info *mtd, int section,
-+				       struct mtd_oob_region *region)
- {
- 	if (section)
- 		return -ERANGE;
-@@ -47,38 +46,49 @@ static int gd5f1gq4u_ooblayout_ecc(struct mtd_info *mtd, int section,
- 	return 0;
- }
- 
--static int gd5f1gq4u_ooblayout_free(struct mtd_info *mtd, int section,
--				    struct mtd_oob_region *region)
-+static int gd5fxgq4xexxg_ooblayout_free(struct mtd_info *mtd, int section,
-+					struct mtd_oob_region *region)
- {
- 	if (section)
- 		return -ERANGE;
- 
--	/* Reserve 2 bytes for the BBM. */
--	region->offset = 2;
--	region->length = 62;
-+	/* Reserve 1 bytes for the BBM. */
-+	region->offset = 1;
-+	region->length = 63;
- 
- 	return 0;
- }
- 
--static const struct mtd_ooblayout_ops gd5f1gq4u_ooblayout = {
--	.ecc = gd5f1gq4u_ooblayout_ecc,
--	.free = gd5f1gq4u_ooblayout_free,
--};
--
--static int gd5f1gq4u_ecc_get_status(struct spinand_device *spinand,
--				    u8 status)
-+static int gd5fxgq4xexxg_ecc_get_status(struct spinand_device *spinand,
-+					u8 status)
- {
--	if (status)
--		debug("%s (%d): status=%02x\n", __func__, __LINE__, status);
-+	u8 status2;
-+	struct spi_mem_op op = SPINAND_GET_FEATURE_OP(GD5FXGQ4XEXXG_REG_STATUS2,
-+						      &status2);
-+	int ret;
- 
--	switch (status & GIGADEVICE_STATUS_ECC_MASK) {
-+	switch (status & STATUS_ECC_MASK) {
- 	case STATUS_ECC_NO_BITFLIPS:
- 		return 0;
- 
--	case GIGADEVICE_STATUS_ECC_1TO7_BITFLIPS:
--		return 7;
--
--	case GIGADEVICE_STATUS_ECC_8_BITFLIPS:
-+	case GD5FXGQ4XA_STATUS_ECC_1_7_BITFLIPS:
-+		/*
-+		 * Read status2 register to determine a more fine grained
-+		 * bit error status
-+		 */
-+		ret = spi_mem_exec_op(spinand->slave, &op);
-+		if (ret)
-+			return ret;
-+
-+		/*
-+		 * 4 ... 7 bits are flipped (1..4 can't be detected, so
-+		 * report the maximum of 4 in this case
-+		 */
-+		/* bits sorted this way (3...0): ECCS1,ECCS0,ECCSE1,ECCSE0 */
-+		return ((status & STATUS_ECC_MASK) >> 2) |
-+			((status2 & STATUS_ECC_MASK) >> 4);
-+
-+	case GD5FXGQ4XA_STATUS_ECC_8_BITFLIPS:
- 		return 8;
- 
- 	case STATUS_ECC_UNCOR_ERROR:
-@@ -91,16 +101,21 @@ static int gd5f1gq4u_ecc_get_status(struct spinand_device *spinand,
- 	return -EINVAL;
- }
- 
-+static const struct mtd_ooblayout_ops gd5fxgq4xexxg_ooblayout = {
-+	.ecc = gd5fxgq4xexxg_ooblayout_ecc,
-+	.free = gd5fxgq4xexxg_ooblayout_free,
-+};
-+
- static const struct spinand_info gigadevice_spinand_table[] = {
--	SPINAND_INFO("GD5F1GQ4UC", 0xd1,
-+	SPINAND_INFO("GD5F1GQ4UExxG", 0xd1,
- 		     NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
--		     NAND_ECCREQ(8, 2048),
-+		     NAND_ECCREQ(8, 512),
- 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
- 					      &write_cache_variants,
- 					      &update_cache_variants),
- 		     0,
--		     SPINAND_ECCINFO(&gd5f1gq4u_ooblayout,
--				     gd5f1gq4u_ecc_get_status)),
-+		     SPINAND_ECCINFO(&gd5fxgq4xexxg_ooblayout,
-+				     gd5fxgq4xexxg_ecc_get_status)),
- };
- 
- static int gigadevice_spinand_detect(struct spinand_device *spinand)
-@@ -109,8 +124,8 @@ static int gigadevice_spinand_detect(struct spinand_device *spinand)
- 	int ret;
- 
- 	/*
--	 * Gigadevice SPI NAND read ID need a dummy byte,
--	 * so the first byte in raw_id is dummy.
-+	 * For GD NANDs, There is an address byte needed to shift in before IDs
-+	 * are read out, so the first byte in raw_id is dummy.
- 	 */
- 	if (id[1] != SPINAND_MFR_GIGADEVICE)
- 		return 0;
-diff --git a/drivers/mtd/nand/spi/toshiba.c b/drivers/mtd/nand/spi/toshiba.c
-new file mode 100644
-index 0000000000..29846cf4bd
---- /dev/null
-+++ b/drivers/mtd/nand/spi/toshiba.c
-@@ -0,0 +1,190 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * Copyright (c) 2018 exceet electronics GmbH
-+ * Copyright (c) 2018 Kontron Electronics GmbH
-+ *
-+ * Author: Frieder Schrempf <frieder.schrempf@kontron.de>
-+ */
-+
-+#ifndef __UBOOT__
-+#include <linux/device.h>
-+#include <linux/kernel.h>
-+#endif
-+#include <linux/mtd/spinand.h>
-+
-+#define SPINAND_MFR_TOSHIBA		0x98
-+#define TOSH_STATUS_ECC_HAS_BITFLIPS_T	(3 << 4)
-+
-+static SPINAND_OP_VARIANTS(read_cache_variants,
-+		SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
-+		SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
-+		SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
-+		SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
-+
-+static SPINAND_OP_VARIANTS(write_cache_variants,
-+		SPINAND_PROG_LOAD(true, 0, NULL, 0));
-+
-+static SPINAND_OP_VARIANTS(update_cache_variants,
-+		SPINAND_PROG_LOAD(false, 0, NULL, 0));
-+
-+static int tc58cxgxsx_ooblayout_ecc(struct mtd_info *mtd, int section,
-+				     struct mtd_oob_region *region)
-+{
-+	if (section > 0)
-+		return -ERANGE;
-+
-+	region->offset = mtd->oobsize / 2;
-+	region->length = mtd->oobsize / 2;
-+
-+	return 0;
-+}
-+
-+static int tc58cxgxsx_ooblayout_free(struct mtd_info *mtd, int section,
-+				      struct mtd_oob_region *region)
-+{
-+	if (section > 0)
-+		return -ERANGE;
-+
-+	/* 2 bytes reserved for BBM */
-+	region->offset = 2;
-+	region->length = (mtd->oobsize / 2) - 2;
-+
-+	return 0;
-+}
-+
-+static const struct mtd_ooblayout_ops tc58cxgxsx_ooblayout = {
-+	.ecc = tc58cxgxsx_ooblayout_ecc,
-+	.free = tc58cxgxsx_ooblayout_free,
-+};
-+
-+static int tc58cxgxsx_ecc_get_status(struct spinand_device *spinand,
-+				      u8 status)
-+{
-+	struct nand_device *nand = spinand_to_nand(spinand);
-+	u8 mbf = 0;
-+	struct spi_mem_op op = SPINAND_GET_FEATURE_OP(0x30, &mbf);
-+
-+	switch (status & STATUS_ECC_MASK) {
-+	case STATUS_ECC_NO_BITFLIPS:
-+		return 0;
-+
-+	case STATUS_ECC_UNCOR_ERROR:
-+		return -EBADMSG;
-+
-+	case STATUS_ECC_HAS_BITFLIPS:
-+	case TOSH_STATUS_ECC_HAS_BITFLIPS_T:
-+		/*
-+		 * Let's try to retrieve the real maximum number of bitflips
-+		 * in order to avoid forcing the wear-leveling layer to move
-+		 * data around if it's not necessary.
-+		 */
-+		if (spi_mem_exec_op(spinand->slave, &op))
-+			return nand->eccreq.strength;
-+
-+		mbf >>= 4;
-+
-+		if (WARN_ON(mbf > nand->eccreq.strength || !mbf))
-+			return nand->eccreq.strength;
-+
-+		return mbf;
-+
-+	default:
-+		break;
-+	}
-+
-+	return -EINVAL;
-+}
-+
-+static const struct spinand_info toshiba_spinand_table[] = {
-+	/* 3.3V 1Gb */
-+	SPINAND_INFO("TC58CVG0S3", 0xC2,
-+		     NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
-+		     NAND_ECCREQ(8, 512),
-+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
-+					      &write_cache_variants,
-+					      &update_cache_variants),
-+		     0,
-+		     SPINAND_ECCINFO(&tc58cxgxsx_ooblayout,
-+				     tc58cxgxsx_ecc_get_status)),
-+	/* 3.3V 2Gb */
-+	SPINAND_INFO("TC58CVG1S3", 0xCB,
-+		     NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
-+		     NAND_ECCREQ(8, 512),
-+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
-+					      &write_cache_variants,
-+					      &update_cache_variants),
-+		     0,
-+		     SPINAND_ECCINFO(&tc58cxgxsx_ooblayout,
-+				     tc58cxgxsx_ecc_get_status)),
-+	/* 3.3V 4Gb */
-+	SPINAND_INFO("TC58CVG2S0", 0xCD,
-+		     NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
-+		     NAND_ECCREQ(8, 512),
-+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
-+					      &write_cache_variants,
-+					      &update_cache_variants),
-+		     0,
-+		     SPINAND_ECCINFO(&tc58cxgxsx_ooblayout,
-+				     tc58cxgxsx_ecc_get_status)),
-+	/* 1.8V 1Gb */
-+	SPINAND_INFO("TC58CYG0S3", 0xB2,
-+		     NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
-+		     NAND_ECCREQ(8, 512),
-+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
-+					      &write_cache_variants,
-+					      &update_cache_variants),
-+		     0,
-+		     SPINAND_ECCINFO(&tc58cxgxsx_ooblayout,
-+				     tc58cxgxsx_ecc_get_status)),
-+	/* 1.8V 2Gb */
-+	SPINAND_INFO("TC58CYG1S3", 0xBB,
-+		     NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
-+		     NAND_ECCREQ(8, 512),
-+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
-+					      &write_cache_variants,
-+					      &update_cache_variants),
-+		     0,
-+		     SPINAND_ECCINFO(&tc58cxgxsx_ooblayout,
-+				     tc58cxgxsx_ecc_get_status)),
-+	/* 1.8V 4Gb */
-+	SPINAND_INFO("TC58CYG2S0", 0xBD,
-+		     NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
-+		     NAND_ECCREQ(8, 512),
-+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
-+					      &write_cache_variants,
-+					      &update_cache_variants),
-+		     0,
-+		     SPINAND_ECCINFO(&tc58cxgxsx_ooblayout,
-+				     tc58cxgxsx_ecc_get_status)),
-+};
-+
-+static int toshiba_spinand_detect(struct spinand_device *spinand)
-+{
-+	u8 *id = spinand->id.data;
-+	int ret;
-+
-+	/*
-+	 * Toshiba SPI NAND read ID needs a dummy byte,
-+	 * so the first byte in id is garbage.
-+	 */
-+	if (id[1] != SPINAND_MFR_TOSHIBA)
-+		return 0;
-+
-+	ret = spinand_match_and_init(spinand, toshiba_spinand_table,
-+				     ARRAY_SIZE(toshiba_spinand_table),
-+				     id[2]);
-+	if (ret)
-+		return ret;
-+
-+	return 1;
-+}
-+
-+static const struct spinand_manufacturer_ops toshiba_spinand_manuf_ops = {
-+	.detect = toshiba_spinand_detect,
-+};
-+
-+const struct spinand_manufacturer toshiba_spinand_manufacturer = {
-+	.id = SPINAND_MFR_TOSHIBA,
-+	.name = "Toshiba",
-+	.ops = &toshiba_spinand_manuf_ops,
-+};
-diff --git a/drivers/mtd/spi/Kconfig b/drivers/mtd/spi/Kconfig
-index 76d5a1d115..d3b007a731 100644
---- a/drivers/mtd/spi/Kconfig
-+++ b/drivers/mtd/spi/Kconfig
-@@ -27,6 +27,8 @@ config SPI_FLASH_SANDBOX
- 
- config SPI_FLASH
- 	bool "Legacy SPI Flash Interface support"
-+	depends on SPI
-+	select SPI_MEM
- 	help
- 	  Enable the legacy SPI flash support. This will include basic
- 	  standard support for things like probing, read / write, and
-@@ -34,9 +36,60 @@ config SPI_FLASH
- 
- 	  If unsure, say N
- 
-+config SF_DEFAULT_BUS
-+	int "SPI Flash default bus identifier"
-+	depends on SPI_FLASH || DM_SPI_FLASH
-+	default 0
-+	help
-+	  The default bus may be provided by the platform
-+	  to handle the common case when only a single serial
-+	  flash is present on the system.
-+
-+config SF_DEFAULT_CS
-+	int "SPI Flash default Chip-select"
-+	depends on SPI_FLASH || DM_SPI_FLASH
-+	default 0
-+	help
-+	  The default chip select may be provided by the platform
-+	  to handle the common case when only a single serial
-+	  flash is present on the system.
-+
-+config SF_DEFAULT_MODE
-+	hex "SPI Flash default mode (see include/spi.h)"
-+	depends on SPI_FLASH || DM_SPI_FLASH
-+	default 3
-+	help
-+	  The default mode may be provided by the platform
-+	  to handle the common case when only a single serial
-+	  flash is present on the system.
-+	  Not used for boot with device tree; the SPI driver reads
-+	  speed and mode from platdata values computed from
-+	  available node.
-+
-+config SF_DEFAULT_SPEED
-+	int "SPI Flash default speed in Hz"
-+	depends on SPI_FLASH || DM_SPI_FLASH
-+	default 1000000
-+	help
-+	  The default speed may be provided by the platform
-+	  to handle the common case when only a single serial
-+	  flash is present on the system.
-+	  Not used for boot with device tree; the SPI driver reads
-+	  speed and mode from platdata values computed from
-+	  available node.
-+
-+if SPI_FLASH
-+
-+config SPI_FLASH_SFDP_SUPPORT
-+	bool "SFDP table parsing support for SPI NOR flashes"
-+	depends on !SPI_FLASH_BAR
-+	help
-+	 Enable support for parsing and auto discovery of parameters for
-+	 SPI NOR flashes using Serial Flash Discoverable Parameters (SFDP)
-+	 tables as per JESD216 standard.
-+
- config SPI_FLASH_BAR
- 	bool "SPI flash Bank/Extended address register support"
--	depends on SPI_FLASH
- 	help
- 	  Enable the SPI flash Bank/Extended address register support.
- 	  Bank/Extended address registers are used to access the flash
-@@ -44,13 +97,10 @@ config SPI_FLASH_BAR
- 
- config SF_DUAL_FLASH
- 	bool "SPI DUAL flash memory support"
--	depends on SPI_FLASH
- 	help
- 	  Enable this option to support two flash memories connected to a single
- 	  controller. Currently Xilinx Zynq qspi supports this.
- 
--if SPI_FLASH
--
- config SPI_FLASH_ATMEL
- 	bool "Atmel SPI flash support"
- 	help
-diff --git a/drivers/mtd/spi/Makefile b/drivers/mtd/spi/Makefile
-index b4c7e1c98b..f99f6cb16e 100644
---- a/drivers/mtd/spi/Makefile
-+++ b/drivers/mtd/spi/Makefile
-@@ -4,12 +4,20 @@
- # Wolfgang Denk, DENX Software Engineering, wd@denx.de.
- 
- obj-$(CONFIG_DM_SPI_FLASH) += sf-uclass.o
-+spi-nor-y := sf_probe.o spi-nor-ids.o
- 
- ifdef CONFIG_SPL_BUILD
- obj-$(CONFIG_SPL_SPI_BOOT)	+= fsl_espi_spl.o
-+ifeq ($(CONFIG_SPL_SPI_FLASH_TINY),y)
-+spi-nor-y += spi-nor-tiny.o
-+else
-+spi-nor-y += spi-nor-core.o
-+endif
-+else
-+spi-nor-y += spi-nor-core.o
- endif
- 
--obj-$(CONFIG_SPI_FLASH) += sf_probe.o spi_flash.o spi_flash_ids.o sf.o
--obj-$(CONFIG_SPI_FLASH_DATAFLASH) += sf_dataflash.o
-+obj-$(CONFIG_SPI_FLASH) += spi-nor.o
-+obj-$(CONFIG_SPI_FLASH_DATAFLASH) += sf_dataflash.o sf.o
- obj-$(CONFIG_SPI_FLASH_MTD) += sf_mtd.o
- obj-$(CONFIG_SPI_FLASH_SANDBOX) += sandbox.o
-diff --git a/drivers/mtd/spi/sandbox.c b/drivers/mtd/spi/sandbox.c
-index 7fef754c63..084c66e984 100644
---- a/drivers/mtd/spi/sandbox.c
-+++ b/drivers/mtd/spi/sandbox.c
-@@ -57,6 +57,8 @@ static const char *sandbox_sf_state_name(enum sandbox_sf_state state)
- /* Bits for the status register */
- #define STAT_WIP	(1 << 0)
- #define STAT_WEL	(1 << 1)
-+#define STAT_BP_SHIFT	2
-+#define STAT_BP_MASK	(7 << STAT_BP_SHIFT)
- 
- /* Assume all SPI flashes have 3 byte addresses since they do atm */
- #define SF_ADDR_LEN	3
-@@ -90,7 +92,7 @@ struct sandbox_spi_flash {
- 	/* The current flash status (see STAT_XXX defines above) */
- 	u16 status;
- 	/* Data describing the flash we're emulating */
--	const struct spi_flash_info *data;
-+	const struct flash_info *data;
- 	/* The file on disk to serv up data from */
- 	int fd;
- };
-@@ -102,6 +104,14 @@ struct sandbox_spi_flash_plat_data {
- 	int cs;
- };
- 
-+void sandbox_sf_set_block_protect(struct udevice *dev, int bp_mask)
-+{
-+	struct sandbox_spi_flash *sbsf = dev_get_priv(dev);
-+
-+	sbsf->status &= ~STAT_BP_MASK;
-+	sbsf->status |= bp_mask << STAT_BP_SHIFT;
-+}
-+
- /**
-  * This is a very strange probe function. If it has platform data (which may
-  * have come from the device tree) then this function gets the filename and
-@@ -112,7 +122,7 @@ static int sandbox_sf_probe(struct udevice *dev)
- 	/* spec = idcode:file */
- 	struct sandbox_spi_flash *sbsf = dev_get_priv(dev);
- 	size_t len, idname_len;
--	const struct spi_flash_info *data;
-+	const struct flash_info *data;
- 	struct sandbox_spi_flash_plat_data *pdata = dev_get_platdata(dev);
- 	struct sandbox_state *state = state_get_current();
- 	struct dm_spi_slave_platdata *slave_plat;
-@@ -145,7 +155,7 @@ static int sandbox_sf_probe(struct udevice *dev)
- 	idname_len = strlen(spec);
- 	debug("%s: device='%s'\n", __func__, spec);
- 
--	for (data = spi_flash_ids; data->name; data++) {
-+	for (data = spi_nor_ids; data->name; data++) {
- 		len = strlen(data->name);
- 		if (idname_len != len)
- 			continue;
-@@ -233,43 +243,43 @@ static int sandbox_sf_process_cmd(struct sandbox_spi_flash *sbsf, const u8 *rx,
- 
- 	sbsf->cmd = rx[0];
- 	switch (sbsf->cmd) {
--	case CMD_READ_ID:
-+	case SPINOR_OP_RDID:
- 		sbsf->state = SF_ID;
- 		sbsf->cmd = SF_ID;
- 		break;
--	case CMD_READ_ARRAY_FAST:
-+	case SPINOR_OP_READ_FAST:
- 		sbsf->pad_addr_bytes = 1;
--	case CMD_READ_ARRAY_SLOW:
--	case CMD_PAGE_PROGRAM:
-+	case SPINOR_OP_READ:
-+	case SPINOR_OP_PP:
- 		sbsf->state = SF_ADDR;
- 		break;
--	case CMD_WRITE_DISABLE:
-+	case SPINOR_OP_WRDI:
- 		debug(" write disabled\n");
- 		sbsf->status &= ~STAT_WEL;
- 		break;
--	case CMD_READ_STATUS:
-+	case SPINOR_OP_RDSR:
- 		sbsf->state = SF_READ_STATUS;
- 		break;
--	case CMD_READ_STATUS1:
-+	case SPINOR_OP_RDSR2:
- 		sbsf->state = SF_READ_STATUS1;
- 		break;
--	case CMD_WRITE_ENABLE:
-+	case SPINOR_OP_WREN:
- 		debug(" write enabled\n");
- 		sbsf->status |= STAT_WEL;
- 		break;
--	case CMD_WRITE_STATUS:
-+	case SPINOR_OP_WRSR:
- 		sbsf->state = SF_WRITE_STATUS;
- 		break;
- 	default: {
- 		int flags = sbsf->data->flags;
- 
- 		/* we only support erase here */
--		if (sbsf->cmd == CMD_ERASE_CHIP) {
-+		if (sbsf->cmd == SPINOR_OP_CHIP_ERASE) {
- 			sbsf->erase_size = sbsf->data->sector_size *
- 				sbsf->data->n_sectors;
--		} else if (sbsf->cmd == CMD_ERASE_4K && (flags & SECT_4K)) {
-+		} else if (sbsf->cmd == SPINOR_OP_BE_4K && (flags & SECT_4K)) {
- 			sbsf->erase_size = 4 << 10;
--		} else if (sbsf->cmd == CMD_ERASE_64K && !(flags & SECT_4K)) {
-+		} else if (sbsf->cmd == SPINOR_OP_SE && !(flags & SECT_4K)) {
- 			sbsf->erase_size = 64 << 10;
- 		} else {
- 			debug(" cmd unknown: %#x\n", sbsf->cmd);
-@@ -370,11 +380,11 @@ static int sandbox_sf_xfer(struct udevice *dev, unsigned int bitlen,
- 				return -EIO;
- 			}
- 			switch (sbsf->cmd) {
--			case CMD_READ_ARRAY_FAST:
--			case CMD_READ_ARRAY_SLOW:
-+			case SPINOR_OP_READ_FAST:
-+			case SPINOR_OP_READ:
- 				sbsf->state = SF_READ;
- 				break;
--			case CMD_PAGE_PROGRAM:
-+			case SPINOR_OP_PP:
- 				sbsf->state = SF_WRITE;
- 				break;
- 			default:
-diff --git a/drivers/mtd/spi/sf-uclass.c b/drivers/mtd/spi/sf-uclass.c
-index 662525f016..719a2fd23a 100644
---- a/drivers/mtd/spi/sf-uclass.c
-+++ b/drivers/mtd/spi/sf-uclass.c
-@@ -28,6 +28,15 @@ int spi_flash_erase_dm(struct udevice *dev, u32 offset, size_t len)
- 	return log_ret(sf_get_ops(dev)->erase(dev, offset, len));
- }
- 
-+int spl_flash_get_sw_write_prot(struct udevice *dev)
-+{
-+	struct dm_spi_flash_ops *ops = sf_get_ops(dev);
-+
-+	if (!ops->get_sw_write_prot)
-+		return -ENOSYS;
-+	return log_ret(ops->get_sw_write_prot(dev));
-+}
-+
- /*
-  * TODO(sjg@chromium.org): This is an old-style function. We should remove
-  * it when all SPI flash drivers use dm
-diff --git a/drivers/mtd/spi/sf_dataflash.c b/drivers/mtd/spi/sf_dataflash.c
-index 4a60c1b2b4..b6a2631747 100644
---- a/drivers/mtd/spi/sf_dataflash.c
-+++ b/drivers/mtd/spi/sf_dataflash.c
-@@ -18,6 +18,7 @@
- 
- #include "sf_internal.h"
- 
-+#define CMD_READ_ID		0x9f
- /* reads can bypass the buffers */
- #define OP_READ_CONTINUOUS	0xE8
- #define OP_READ_PAGE		0xD2
-@@ -441,7 +442,7 @@ static int add_dataflash(struct udevice *dev, char *name, int nr_pages,
- 	return 0;
- }
- 
--struct flash_info {
-+struct data_flash_info {
- 	char		*name;
- 
- 	/*
-@@ -460,7 +461,7 @@ struct flash_info {
- #define IS_POW2PS	0x0001		/* uses 2^N byte pages */
- };
- 
--static struct flash_info dataflash_data[] = {
-+static struct data_flash_info dataflash_data[] = {
- 	/*
- 	 * NOTE:  chips with SUP_POW2PS (rev D and up) need two entries,
- 	 * one with IS_POW2PS and the other without.  The entry with the
-@@ -501,12 +502,12 @@ static struct flash_info dataflash_data[] = {
- 	{ "at45db642d",  0x1f2800, 8192, 1024, 10, SUP_POW2PS | IS_POW2PS},
- };
- 
--static struct flash_info *jedec_probe(struct spi_slave *spi)
-+static struct data_flash_info *jedec_probe(struct spi_slave *spi)
- {
- 	int			tmp;
- 	uint8_t			id[5];
- 	uint32_t		jedec;
--	struct flash_info	*info;
-+	struct data_flash_info	*info;
- 	int status;
- 
- 	/*
-@@ -583,7 +584,7 @@ static int spi_dataflash_probe(struct udevice *dev)
- {
- 	struct spi_slave *spi = dev_get_parent_priv(dev);
- 	struct spi_flash *spi_flash;
--	struct flash_info *info;
-+	struct data_flash_info *info;
- 	int status;
- 
- 	spi_flash = dev_get_uclass_priv(dev);
-diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h
-index 26f5c7c995..a6bf734830 100644
---- a/drivers/mtd/spi/sf_internal.h
-+++ b/drivers/mtd/spi/sf_internal.h
-@@ -12,142 +12,65 @@
- #include <linux/types.h>
- #include <linux/compiler.h>
- 
--/* Dual SPI flash memories - see SPI_COMM_DUAL_... */
--enum spi_dual_flash {
--	SF_SINGLE_FLASH	= 0,
--	SF_DUAL_STACKED_FLASH	= BIT(0),
--	SF_DUAL_PARALLEL_FLASH	= BIT(1),
--};
--
--enum spi_nor_option_flags {
--	SNOR_F_SST_WR		= BIT(0),
--	SNOR_F_USE_FSR		= BIT(1),
--	SNOR_F_USE_UPAGE	= BIT(3),
--};
-+#define SPI_NOR_MAX_ID_LEN	6
-+#define SPI_NOR_MAX_ADDR_WIDTH	4
- 
--#define SPI_FLASH_3B_ADDR_LEN		3
--#define SPI_FLASH_CMD_LEN		(1 + SPI_FLASH_3B_ADDR_LEN)
--#define SPI_FLASH_16MB_BOUN		0x1000000
--
--/* CFI Manufacture ID's */
--#define SPI_FLASH_CFI_MFR_SPANSION	0x01
--#define SPI_FLASH_CFI_MFR_STMICRO	0x20
--#define SPI_FLASH_CFI_MFR_MICRON	0x2C
--#define SPI_FLASH_CFI_MFR_MACRONIX	0xc2
--#define SPI_FLASH_CFI_MFR_SST		0xbf
--#define SPI_FLASH_CFI_MFR_WINBOND	0xef
--#define SPI_FLASH_CFI_MFR_ATMEL		0x1f
--
--/* Erase commands */
--#define CMD_ERASE_4K			0x20
--#define CMD_ERASE_CHIP			0xc7
--#define CMD_ERASE_64K			0xd8
--
--/* Write commands */
--#define CMD_WRITE_STATUS		0x01
--#define CMD_PAGE_PROGRAM		0x02
--#define CMD_WRITE_DISABLE		0x04
--#define CMD_WRITE_ENABLE		0x06
--#define CMD_QUAD_PAGE_PROGRAM		0x32
--
--/* Read commands */
--#define CMD_READ_ARRAY_SLOW		0x03
--#define CMD_READ_ARRAY_FAST		0x0b
--#define CMD_READ_DUAL_OUTPUT_FAST	0x3b
--#define CMD_READ_DUAL_IO_FAST		0xbb
--#define CMD_READ_QUAD_OUTPUT_FAST	0x6b
--#define CMD_READ_QUAD_IO_FAST		0xeb
--#define CMD_READ_ID			0x9f
--#define CMD_READ_STATUS			0x05
--#define CMD_READ_STATUS1		0x35
--#define CMD_READ_CONFIG			0x35
--#define CMD_FLAG_STATUS			0x70
--
--/* Bank addr access commands */
--#ifdef CONFIG_SPI_FLASH_BAR
--# define CMD_BANKADDR_BRWR		0x17
--# define CMD_BANKADDR_BRRD		0x16
--# define CMD_EXTNADDR_WREAR		0xC5
--# define CMD_EXTNADDR_RDEAR		0xC8
-+struct flash_info {
-+#if !CONFIG_IS_ENABLED(SPI_FLASH_TINY)
-+	char		*name;
- #endif
- 
--/* Common status */
--#define STATUS_WIP			BIT(0)
--#define STATUS_QEB_WINSPAN		BIT(1)
--#define STATUS_QEB_MXIC			BIT(6)
--#define STATUS_PEC			BIT(7)
--#define SR_BP0				BIT(2)  /* Block protect 0 */
--#define SR_BP1				BIT(3)  /* Block protect 1 */
--#define SR_BP2				BIT(4)  /* Block protect 2 */
--
--/* Flash timeout values */
--#define SPI_FLASH_PROG_TIMEOUT		(2 * CONFIG_SYS_HZ)
--#define SPI_FLASH_PAGE_ERASE_TIMEOUT	(5 * CONFIG_SYS_HZ)
--#define SPI_FLASH_SECTOR_ERASE_TIMEOUT	(10 * CONFIG_SYS_HZ)
--
--/* SST specific */
--#ifdef CONFIG_SPI_FLASH_SST
--#define SST26_CMD_READ_BPR		0x72
--#define SST26_CMD_WRITE_BPR		0x42
--
--#define SST26_BPR_8K_NUM		4
--#define SST26_MAX_BPR_REG_LEN		(18 + 1)
--#define SST26_BOUND_REG_SIZE		((32 + SST26_BPR_8K_NUM * 8) * SZ_1K)
--
--enum lock_ctl {
--	SST26_CTL_LOCK,
--	SST26_CTL_UNLOCK,
--	SST26_CTL_CHECK
--};
--
--# define CMD_SST_BP		0x02    /* Byte Program */
--# define CMD_SST_AAI_WP		0xAD	/* Auto Address Incr Word Program */
--
--int sst_write_wp(struct spi_flash *flash, u32 offset, size_t len,
--		const void *buf);
--int sst_write_bp(struct spi_flash *flash, u32 offset, size_t len,
--		const void *buf);
--#endif
--
--#define JEDEC_MFR(info)		((info)->id[0])
--#define JEDEC_ID(info)		(((info)->id[1]) << 8 | ((info)->id[2]))
--#define JEDEC_EXT(info)		(((info)->id[3]) << 8 | ((info)->id[4]))
--#define SPI_FLASH_MAX_ID_LEN	6
--
--struct spi_flash_info {
--	/* Device name ([MANUFLETTER][DEVTYPE][DENSITY][EXTRAINFO]) */
--	const char	*name;
--
- 	/*
- 	 * This array stores the ID bytes.
- 	 * The first three bytes are the JEDIC ID.
- 	 * JEDEC ID zero means "no ID" (mostly older chips).
- 	 */
--	u8		id[SPI_FLASH_MAX_ID_LEN];
-+	u8		id[SPI_NOR_MAX_ID_LEN];
- 	u8		id_len;
- 
--	/*
--	 * The size listed here is what works with SPINOR_OP_SE, which isn't
-+	/* The size listed here is what works with SPINOR_OP_SE, which isn't
- 	 * necessarily called a "sector" by the vendor.
- 	 */
--	u32		sector_size;
--	u32		n_sectors;
-+	unsigned int	sector_size;
-+	u16		n_sectors;
- 
- 	u16		page_size;
-+	u16		addr_width;
- 
- 	u16		flags;
--#define SECT_4K			BIT(0)	/* CMD_ERASE_4K works uniformly */
--#define E_FSR			BIT(1)	/* use flag status register for */
--#define SST_WR			BIT(2)	/* use SST byte/word programming */
--#define WR_QPP			BIT(3)	/* use Quad Page Program */
--#define RD_QUAD			BIT(4)	/* use Quad Read */
--#define RD_DUAL			BIT(5)	/* use Dual Read */
--#define RD_QUADIO		BIT(6)	/* use Quad IO Read */
--#define RD_DUALIO		BIT(7)	/* use Dual IO Read */
--#define RD_FULL			(RD_QUAD | RD_DUAL | RD_QUADIO | RD_DUALIO)
-+#define SECT_4K			BIT(0)	/* SPINOR_OP_BE_4K works uniformly */
-+#define SPI_NOR_NO_ERASE	BIT(1)	/* No erase command needed */
-+#define SST_WRITE		BIT(2)	/* use SST byte programming */
-+#define SPI_NOR_NO_FR		BIT(3)	/* Can't do fastread */
-+#define SECT_4K_PMC		BIT(4)	/* SPINOR_OP_BE_4K_PMC works uniformly */
-+#define SPI_NOR_DUAL_READ	BIT(5)	/* Flash supports Dual Read */
-+#define SPI_NOR_QUAD_READ	BIT(6)	/* Flash supports Quad Read */
-+#define USE_FSR			BIT(7)	/* use flag status register */
-+#define SPI_NOR_HAS_LOCK	BIT(8)	/* Flash supports lock/unlock via SR */
-+#define SPI_NOR_HAS_TB		BIT(9)	/*
-+					 * Flash SR has Top/Bottom (TB) protect
-+					 * bit. Must be used with
-+					 * SPI_NOR_HAS_LOCK.
-+					 */
-+#define	SPI_S3AN		BIT(10)	/*
-+					 * Xilinx Spartan 3AN In-System Flash
-+					 * (MFR cannot be used for probing
-+					 * because it has the same value as
-+					 * ATMEL flashes)
-+					 */
-+#define SPI_NOR_4B_OPCODES	BIT(11)	/*
-+					 * Use dedicated 4byte address op codes
-+					 * to support memory size above 128Mib.
-+					 */
-+#define NO_CHIP_ERASE		BIT(12) /* Chip does not support chip erase */
-+#define SPI_NOR_SKIP_SFDP	BIT(13)	/* Skip parsing of SFDP tables */
-+#define USE_CLSR		BIT(14)	/* use CLSR command */
- };
- 
--extern const struct spi_flash_info spi_flash_ids[];
-+extern const struct flash_info spi_nor_ids[];
-+
-+#define JEDEC_MFR(info)	((info)->id[0])
-+#define JEDEC_ID(info)		(((info)->id[1]) << 8 | ((info)->id[2]))
- 
- /* Send a single-byte command to the device and read the response */
- int spi_flash_cmd(struct spi_slave *spi, u8 cmd, void *response, size_t len);
-@@ -167,75 +90,12 @@ int spi_flash_cmd_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len,
- 		const void *data, size_t data_len);
- 
- 
--/* Flash erase(sectors) operation, support all possible erase commands */
--int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len);
--
--/* Lock stmicro spi flash region */
--int stm_lock(struct spi_flash *flash, u32 ofs, size_t len);
--
--/* Unlock stmicro spi flash region */
--int stm_unlock(struct spi_flash *flash, u32 ofs, size_t len);
--
--/* Check if a stmicro spi flash region is completely locked */
--int stm_is_locked(struct spi_flash *flash, u32 ofs, size_t len);
-+/* Get software write-protect value (BP bits) */
-+int spi_flash_cmd_get_sw_write_prot(struct spi_flash *flash);
- 
--/* Enable writing on the SPI flash */
--static inline int spi_flash_cmd_write_enable(struct spi_flash *flash)
--{
--	return spi_flash_cmd(flash->spi, CMD_WRITE_ENABLE, NULL, 0);
--}
--
--/* Disable writing on the SPI flash */
--static inline int spi_flash_cmd_write_disable(struct spi_flash *flash)
--{
--	return spi_flash_cmd(flash->spi, CMD_WRITE_DISABLE, NULL, 0);
--}
--
--/*
-- * Used for spi_flash write operation
-- * - SPI claim
-- * - spi_flash_cmd_write_enable
-- * - spi_flash_cmd_write
-- * - spi_flash_wait_till_ready
-- * - SPI release
-- */
--int spi_flash_write_common(struct spi_flash *flash, const u8 *cmd,
--		size_t cmd_len, const void *buf, size_t buf_len);
--
--/*
-- * Flash write operation, support all possible write commands.
-- * Write the requested data out breaking it up into multiple write
-- * commands as needed per the write size.
-- */
--int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset,
--		size_t len, const void *buf);
--
--/*
-- * Same as spi_flash_cmd_read() except it also claims/releases the SPI
-- * bus. Used as common part of the ->read() operation.
-- */
--int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd,
--		size_t cmd_len, void *data, size_t data_len);
--
--/* Flash read operation, support all possible read commands */
--int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset,
--		size_t len, void *data);
- 
- #ifdef CONFIG_SPI_FLASH_MTD
- int spi_flash_mtd_register(struct spi_flash *flash);
- void spi_flash_mtd_unregister(void);
- #endif
--
--/**
-- * spi_flash_scan - scan the SPI FLASH
-- * @flash:	the spi flash structure
-- *
-- * The drivers can use this fuction to scan the SPI FLASH.
-- * In the scanning, it will try to get all the necessary information to
-- * fill the spi_flash{}.
-- *
-- * Return: 0 for success, others for failure.
-- */
--int spi_flash_scan(struct spi_flash *flash);
--
- #endif /* _SF_INTERNAL_H_ */
-diff --git a/drivers/mtd/spi/sf_mtd.c b/drivers/mtd/spi/sf_mtd.c
-index 58d7e44399..68c36002be 100644
---- a/drivers/mtd/spi/sf_mtd.c
-+++ b/drivers/mtd/spi/sf_mtd.c
-@@ -10,6 +10,7 @@
- #include <spi_flash.h>
- 
- static struct mtd_info sf_mtd_info;
-+static bool sf_mtd_registered;
- static char sf_mtd_name[8];
- 
- static int spi_flash_mtd_erase(struct mtd_info *mtd, struct erase_info *instr)
-@@ -17,6 +18,9 @@ static int spi_flash_mtd_erase(struct mtd_info *mtd, struct erase_info *instr)
- 	struct spi_flash *flash = mtd->priv;
- 	int err;
- 
-+	if (!flash)
-+		return -ENODEV;
-+
- 	instr->state = MTD_ERASING;
- 
- 	err = spi_flash_erase(flash, instr->addr, instr->len);
-@@ -38,6 +42,9 @@ static int spi_flash_mtd_read(struct mtd_info *mtd, loff_t from, size_t len,
- 	struct spi_flash *flash = mtd->priv;
- 	int err;
- 
-+	if (!flash)
-+		return -ENODEV;
-+
- 	err = spi_flash_read(flash, from, len, buf);
- 	if (!err)
- 		*retlen = len;
-@@ -51,6 +58,9 @@ static int spi_flash_mtd_write(struct mtd_info *mtd, loff_t to, size_t len,
- 	struct spi_flash *flash = mtd->priv;
- 	int err;
- 
-+	if (!flash)
-+		return -ENODEV;
-+
- 	err = spi_flash_write(flash, to, len, buf);
- 	if (!err)
- 		*retlen = len;
-@@ -73,6 +83,17 @@ static int spi_flash_mtd_number(void)
- 
- int spi_flash_mtd_register(struct spi_flash *flash)
- {
-+	int ret;
-+
-+	if (sf_mtd_registered) {
-+		ret = del_mtd_device(&sf_mtd_info);
-+		if (ret)
-+			return ret;
-+
-+		sf_mtd_registered = false;
-+	}
-+
-+	sf_mtd_registered = false;
- 	memset(&sf_mtd_info, 0, sizeof(sf_mtd_info));
- 	sprintf(sf_mtd_name, "nor%d", spi_flash_mtd_number());
- 
-@@ -94,10 +115,33 @@ int spi_flash_mtd_register(struct spi_flash *flash)
- 	sf_mtd_info.numeraseregions = 0;
- 	sf_mtd_info.erasesize = flash->sector_size;
- 
--	return add_mtd_device(&sf_mtd_info);
-+	ret = add_mtd_device(&sf_mtd_info);
-+	if (!ret)
-+		sf_mtd_registered = true;
-+
-+	return ret;
- }
- 
- void spi_flash_mtd_unregister(void)
- {
--	del_mtd_device(&sf_mtd_info);
-+	int ret;
-+
-+	if (!sf_mtd_registered)
-+		return;
-+
-+	ret = del_mtd_device(&sf_mtd_info);
-+	if (!ret) {
-+		sf_mtd_registered = false;
-+		return;
-+	}
-+
-+	/*
-+	 * Setting mtd->priv to NULL is the best we can do. Thanks to that,
-+	 * the MTD layer can still call mtd hooks without risking a
-+	 * use-after-free bug. Still, things should be fixed to prevent the
-+	 * spi_flash object from being destroyed when del_mtd_device() fails.
-+	 */
-+	sf_mtd_info.priv = NULL;
-+	printf("Failed to unregister MTD %s and the spi_flash object is going away: you're in deep trouble!",
-+	       sf_mtd_info.name);
- }
-diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c
-index 94fde2ae7a..73297e1a0a 100644
---- a/drivers/mtd/spi/sf_probe.c
-+++ b/drivers/mtd/spi/sf_probe.c
-@@ -40,7 +40,7 @@ static int spi_flash_probe_slave(struct spi_flash *flash)
- 		return ret;
- 	}
- 
--	ret = spi_flash_scan(flash);
-+	ret = spi_nor_scan(flash);
- 	if (ret)
- 		goto err_read_id;
- 
-@@ -96,32 +96,45 @@ static int spi_flash_std_read(struct udevice *dev, u32 offset, size_t len,
- 			      void *buf)
- {
- 	struct spi_flash *flash = dev_get_uclass_priv(dev);
-+	struct mtd_info *mtd = &flash->mtd;
-+	size_t retlen;
- 
--	return log_ret(spi_flash_cmd_read_ops(flash, offset, len, buf));
-+	return log_ret(mtd->_read(mtd, offset, len, &retlen, buf));
- }
- 
- static int spi_flash_std_write(struct udevice *dev, u32 offset, size_t len,
- 			       const void *buf)
- {
- 	struct spi_flash *flash = dev_get_uclass_priv(dev);
-+	struct mtd_info *mtd = &flash->mtd;
-+	size_t retlen;
- 
--#if defined(CONFIG_SPI_FLASH_SST)
--	if (flash->flags & SNOR_F_SST_WR) {
--		if (flash->spi->mode & SPI_TX_BYTE)
--			return sst_write_bp(flash, offset, len, buf);
--		else
--			return sst_write_wp(flash, offset, len, buf);
-+	return mtd->_write(mtd, offset, len, &retlen, buf);
-+}
-+
-+static int spi_flash_std_erase(struct udevice *dev, u32 offset, size_t len)
-+{
-+	struct spi_flash *flash = dev_get_uclass_priv(dev);
-+	struct mtd_info *mtd = &flash->mtd;
-+	struct erase_info instr;
-+
-+	if (offset % mtd->erasesize || len % mtd->erasesize) {
-+		printf("SF: Erase offset/length not multiple of erase size\n");
-+		return -EINVAL;
- 	}
--#endif
- 
--	return spi_flash_cmd_write_ops(flash, offset, len, buf);
-+	memset(&instr, 0, sizeof(instr));
-+	instr.addr = offset;
-+	instr.len = len;
-+
-+	return mtd->_erase(mtd, &instr);
- }
- 
--static int spi_flash_std_erase(struct udevice *dev, u32 offset, size_t len)
-+static int spi_flash_std_get_sw_write_prot(struct udevice *dev)
- {
- 	struct spi_flash *flash = dev_get_uclass_priv(dev);
- 
--	return spi_flash_cmd_erase_ops(flash, offset, len);
-+	return spi_flash_cmd_get_sw_write_prot(flash);
- }
- 
- static int spi_flash_std_probe(struct udevice *dev)
-@@ -137,14 +150,23 @@ static int spi_flash_std_probe(struct udevice *dev)
- 	return spi_flash_probe_slave(flash);
- }
- 
-+static int spi_flash_std_remove(struct udevice *dev)
-+{
-+#ifdef CONFIG_SPI_FLASH_MTD
-+	spi_flash_mtd_unregister();
-+#endif
-+	return 0;
-+}
-+
- static const struct dm_spi_flash_ops spi_flash_std_ops = {
- 	.read = spi_flash_std_read,
- 	.write = spi_flash_std_write,
- 	.erase = spi_flash_std_erase,
-+	.get_sw_write_prot = spi_flash_std_get_sw_write_prot,
- };
- 
- static const struct udevice_id spi_flash_std_ids[] = {
--	{ .compatible = "spi-flash" },
-+	{ .compatible = "jedec,spi-nor" },
- 	{ }
- };
- 
-@@ -153,6 +175,7 @@ U_BOOT_DRIVER(spi_flash_std) = {
- 	.id		= UCLASS_SPI_FLASH,
- 	.of_match	= spi_flash_std_ids,
- 	.probe		= spi_flash_std_probe,
-+	.remove		= spi_flash_std_remove,
- 	.priv_auto_alloc_size = sizeof(struct spi_flash),
- 	.ops		= &spi_flash_std_ops,
- };
-diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
-new file mode 100644
-index 0000000000..1acff745d1
---- /dev/null
-+++ b/drivers/mtd/spi/spi-nor-core.c
-@@ -0,0 +1,2401 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * Based on m25p80.c, by Mike Lavender (mike@steroidmicros.com), with
-+ * influence from lart.c (Abraham Van Der Merwe) and mtd_dataflash.c
-+ *
-+ * Copyright (C) 2005, Intec Automation Inc.
-+ * Copyright (C) 2014, Freescale Semiconductor, Inc.
-+ *
-+ * Synced from Linux v4.19
-+ */
-+
-+#include <common.h>
-+#include <linux/err.h>
-+#include <linux/errno.h>
-+#include <linux/log2.h>
-+#include <linux/math64.h>
-+#include <linux/sizes.h>
-+
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/spi-nor.h>
-+#include <spi-mem.h>
-+#include <spi.h>
-+
-+#include "sf_internal.h"
-+
-+/* Define max times to check status register before we give up. */
-+
-+/*
-+ * For everything but full-chip erase; probably could be much smaller, but kept
-+ * around for safety for now
-+ */
-+
-+#define HZ					CONFIG_SYS_HZ
-+
-+#define DEFAULT_READY_WAIT_JIFFIES		(40UL * HZ)
-+
-+static int spi_nor_read_write_reg(struct spi_nor *nor, struct spi_mem_op
-+		*op, void *buf)
-+{
-+	if (op->data.dir == SPI_MEM_DATA_IN)
-+		op->data.buf.in = buf;
-+	else
-+		op->data.buf.out = buf;
-+	return spi_mem_exec_op(nor->spi, op);
-+}
-+
-+static int spi_nor_read_reg(struct spi_nor *nor, u8 code, u8 *val, int len)
-+{
-+	struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(code, 1),
-+					  SPI_MEM_OP_NO_ADDR,
-+					  SPI_MEM_OP_NO_DUMMY,
-+					  SPI_MEM_OP_DATA_IN(len, NULL, 1));
-+	int ret;
-+
-+	ret = spi_nor_read_write_reg(nor, &op, val);
-+	if (ret < 0)
-+		dev_dbg(&flash->spimem->spi->dev, "error %d reading %x\n", ret,
-+			code);
-+
-+	return ret;
-+}
-+
-+static int spi_nor_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
-+{
-+	struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(opcode, 1),
-+					  SPI_MEM_OP_NO_ADDR,
-+					  SPI_MEM_OP_NO_DUMMY,
-+					  SPI_MEM_OP_DATA_OUT(len, NULL, 1));
-+
-+	return spi_nor_read_write_reg(nor, &op, buf);
-+}
-+
-+static ssize_t spi_nor_read_data(struct spi_nor *nor, loff_t from, size_t len,
-+				 u_char *buf)
-+{
-+	struct spi_mem_op op =
-+			SPI_MEM_OP(SPI_MEM_OP_CMD(nor->read_opcode, 1),
-+				   SPI_MEM_OP_ADDR(nor->addr_width, from, 1),
-+				   SPI_MEM_OP_DUMMY(nor->read_dummy, 1),
-+				   SPI_MEM_OP_DATA_IN(len, buf, 1));
-+	size_t remaining = len;
-+	int ret;
-+
-+	/* get transfer protocols. */
-+	op.cmd.buswidth = spi_nor_get_protocol_inst_nbits(nor->read_proto);
-+	op.addr.buswidth = spi_nor_get_protocol_addr_nbits(nor->read_proto);
-+	op.dummy.buswidth = op.addr.buswidth;
-+	op.data.buswidth = spi_nor_get_protocol_data_nbits(nor->read_proto);
-+
-+	/* convert the dummy cycles to the number of bytes */
-+	op.dummy.nbytes = (nor->read_dummy * op.dummy.buswidth) / 8;
-+
-+	while (remaining) {
-+		op.data.nbytes = remaining < UINT_MAX ? remaining : UINT_MAX;
-+		ret = spi_mem_adjust_op_size(nor->spi, &op);
-+		if (ret)
-+			return ret;
-+
-+		ret = spi_mem_exec_op(nor->spi, &op);
-+		if (ret)
-+			return ret;
-+
-+		op.addr.val += op.data.nbytes;
-+		remaining -= op.data.nbytes;
-+		op.data.buf.in += op.data.nbytes;
-+	}
-+
-+	return len;
-+}
-+
-+static ssize_t spi_nor_write_data(struct spi_nor *nor, loff_t to, size_t len,
-+				  const u_char *buf)
-+{
-+	struct spi_mem_op op =
-+			SPI_MEM_OP(SPI_MEM_OP_CMD(nor->program_opcode, 1),
-+				   SPI_MEM_OP_ADDR(nor->addr_width, to, 1),
-+				   SPI_MEM_OP_NO_DUMMY,
-+				   SPI_MEM_OP_DATA_OUT(len, buf, 1));
-+	int ret;
-+
-+	/* get transfer protocols. */
-+	op.cmd.buswidth = spi_nor_get_protocol_inst_nbits(nor->write_proto);
-+	op.addr.buswidth = spi_nor_get_protocol_addr_nbits(nor->write_proto);
-+	op.data.buswidth = spi_nor_get_protocol_data_nbits(nor->write_proto);
-+
-+	if (nor->program_opcode == SPINOR_OP_AAI_WP && nor->sst_write_second)
-+		op.addr.nbytes = 0;
-+
-+	ret = spi_mem_adjust_op_size(nor->spi, &op);
-+	if (ret)
-+		return ret;
-+	op.data.nbytes = len < op.data.nbytes ? len : op.data.nbytes;
-+
-+	ret = spi_mem_exec_op(nor->spi, &op);
-+	if (ret)
-+		return ret;
-+
-+	return op.data.nbytes;
-+}
-+
-+/*
-+ * Read the status register, returning its value in the location
-+ * Return the status register value.
-+ * Returns negative if error occurred.
-+ */
-+static int read_sr(struct spi_nor *nor)
-+{
-+	int ret;
-+	u8 val;
-+
-+	ret = nor->read_reg(nor, SPINOR_OP_RDSR, &val, 1);
-+	if (ret < 0) {
-+		pr_debug("error %d reading SR\n", (int)ret);
-+		return ret;
-+	}
-+
-+	return val;
-+}
-+
-+/*
-+ * Read the flag status register, returning its value in the location
-+ * Return the status register value.
-+ * Returns negative if error occurred.
-+ */
-+static int read_fsr(struct spi_nor *nor)
-+{
-+	int ret;
-+	u8 val;
-+
-+	ret = nor->read_reg(nor, SPINOR_OP_RDFSR, &val, 1);
-+	if (ret < 0) {
-+		pr_debug("error %d reading FSR\n", ret);
-+		return ret;
-+	}
-+
-+	return val;
-+}
-+
-+/*
-+ * Read configuration register, returning its value in the
-+ * location. Return the configuration register value.
-+ * Returns negative if error occurred.
-+ */
-+#if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND)
-+static int read_cr(struct spi_nor *nor)
-+{
-+	int ret;
-+	u8 val;
-+
-+	ret = nor->read_reg(nor, SPINOR_OP_RDCR, &val, 1);
-+	if (ret < 0) {
-+		dev_dbg(nor->dev, "error %d reading CR\n", ret);
-+		return ret;
-+	}
-+
-+	return val;
-+}
-+#endif
-+
-+/*
-+ * Write status register 1 byte
-+ * Returns negative if error occurred.
-+ */
-+static int write_sr(struct spi_nor *nor, u8 val)
-+{
-+	nor->cmd_buf[0] = val;
-+	return nor->write_reg(nor, SPINOR_OP_WRSR, nor->cmd_buf, 1);
-+}
-+
-+/*
-+ * Set write enable latch with Write Enable command.
-+ * Returns negative if error occurred.
-+ */
-+static int write_enable(struct spi_nor *nor)
-+{
-+	return nor->write_reg(nor, SPINOR_OP_WREN, NULL, 0);
-+}
-+
-+/*
-+ * Send write disable instruction to the chip.
-+ */
-+static int write_disable(struct spi_nor *nor)
-+{
-+	return nor->write_reg(nor, SPINOR_OP_WRDI, NULL, 0);
-+}
-+
-+static struct spi_nor *mtd_to_spi_nor(struct mtd_info *mtd)
-+{
-+	return mtd->priv;
-+}
-+
-+#ifndef CONFIG_SPI_FLASH_BAR
-+static u8 spi_nor_convert_opcode(u8 opcode, const u8 table[][2], size_t size)
-+{
-+	size_t i;
-+
-+	for (i = 0; i < size; i++)
-+		if (table[i][0] == opcode)
-+			return table[i][1];
-+
-+	/* No conversion found, keep input op code. */
-+	return opcode;
-+}
-+
-+static u8 spi_nor_convert_3to4_read(u8 opcode)
-+{
-+	static const u8 spi_nor_3to4_read[][2] = {
-+		{ SPINOR_OP_READ,	SPINOR_OP_READ_4B },
-+		{ SPINOR_OP_READ_FAST,	SPINOR_OP_READ_FAST_4B },
-+		{ SPINOR_OP_READ_1_1_2,	SPINOR_OP_READ_1_1_2_4B },
-+		{ SPINOR_OP_READ_1_2_2,	SPINOR_OP_READ_1_2_2_4B },
-+		{ SPINOR_OP_READ_1_1_4,	SPINOR_OP_READ_1_1_4_4B },
-+		{ SPINOR_OP_READ_1_4_4,	SPINOR_OP_READ_1_4_4_4B },
-+
-+		{ SPINOR_OP_READ_1_1_1_DTR,	SPINOR_OP_READ_1_1_1_DTR_4B },
-+		{ SPINOR_OP_READ_1_2_2_DTR,	SPINOR_OP_READ_1_2_2_DTR_4B },
-+		{ SPINOR_OP_READ_1_4_4_DTR,	SPINOR_OP_READ_1_4_4_DTR_4B },
-+	};
-+
-+	return spi_nor_convert_opcode(opcode, spi_nor_3to4_read,
-+				      ARRAY_SIZE(spi_nor_3to4_read));
-+}
-+
-+static u8 spi_nor_convert_3to4_program(u8 opcode)
-+{
-+	static const u8 spi_nor_3to4_program[][2] = {
-+		{ SPINOR_OP_PP,		SPINOR_OP_PP_4B },
-+		{ SPINOR_OP_PP_1_1_4,	SPINOR_OP_PP_1_1_4_4B },
-+		{ SPINOR_OP_PP_1_4_4,	SPINOR_OP_PP_1_4_4_4B },
-+	};
-+
-+	return spi_nor_convert_opcode(opcode, spi_nor_3to4_program,
-+				      ARRAY_SIZE(spi_nor_3to4_program));
-+}
-+
-+static u8 spi_nor_convert_3to4_erase(u8 opcode)
-+{
-+	static const u8 spi_nor_3to4_erase[][2] = {
-+		{ SPINOR_OP_BE_4K,	SPINOR_OP_BE_4K_4B },
-+		{ SPINOR_OP_BE_32K,	SPINOR_OP_BE_32K_4B },
-+		{ SPINOR_OP_SE,		SPINOR_OP_SE_4B },
-+	};
-+
-+	return spi_nor_convert_opcode(opcode, spi_nor_3to4_erase,
-+				      ARRAY_SIZE(spi_nor_3to4_erase));
-+}
-+
-+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_convert_3to4_read(nor->read_opcode);
-+	nor->program_opcode = spi_nor_convert_3to4_program(nor->program_opcode);
-+	nor->erase_opcode = spi_nor_convert_3to4_erase(nor->erase_opcode);
-+}
-+#endif /* !CONFIG_SPI_FLASH_BAR */
-+
-+/* Enable/disable 4-byte addressing mode. */
-+static int set_4byte(struct spi_nor *nor, const struct flash_info *info,
-+		     int enable)
-+{
-+	int status;
-+	bool need_wren = false;
-+	u8 cmd;
-+
-+	switch (JEDEC_MFR(info)) {
-+	case SNOR_MFR_ST:
-+	case SNOR_MFR_MICRON:
-+		/* Some Micron need WREN command; all will accept it */
-+		need_wren = true;
-+	case SNOR_MFR_MACRONIX:
-+	case SNOR_MFR_WINBOND:
-+		if (need_wren)
-+			write_enable(nor);
-+
-+		cmd = enable ? SPINOR_OP_EN4B : SPINOR_OP_EX4B;
-+		status = nor->write_reg(nor, cmd, NULL, 0);
-+		if (need_wren)
-+			write_disable(nor);
-+
-+		if (!status && !enable &&
-+		    JEDEC_MFR(info) == SNOR_MFR_WINBOND) {
-+			/*
-+			 * On Winbond W25Q256FV, leaving 4byte mode causes
-+			 * the Extended Address Register to be set to 1, so all
-+			 * 3-byte-address reads come from the second 16M.
-+			 * We must clear the register to enable normal behavior.
-+			 */
-+			write_enable(nor);
-+			nor->cmd_buf[0] = 0;
-+			nor->write_reg(nor, SPINOR_OP_WREAR, nor->cmd_buf, 1);
-+			write_disable(nor);
-+		}
-+
-+		return status;
-+	default:
-+		/* Spansion style */
-+		nor->cmd_buf[0] = enable << 7;
-+		return nor->write_reg(nor, SPINOR_OP_BRWR, nor->cmd_buf, 1);
-+	}
-+}
-+
-+static int spi_nor_sr_ready(struct spi_nor *nor)
-+{
-+	int sr = read_sr(nor);
-+
-+	if (sr < 0)
-+		return sr;
-+
-+	if (nor->flags & SNOR_F_USE_CLSR && sr & (SR_E_ERR | SR_P_ERR)) {
-+		if (sr & SR_E_ERR)
-+			dev_dbg(nor->dev, "Erase Error occurred\n");
-+		else
-+			dev_dbg(nor->dev, "Programming Error occurred\n");
-+
-+		nor->write_reg(nor, SPINOR_OP_CLSR, NULL, 0);
-+		return -EIO;
-+	}
-+
-+	return !(sr & SR_WIP);
-+}
-+
-+static int spi_nor_fsr_ready(struct spi_nor *nor)
-+{
-+	int fsr = read_fsr(nor);
-+
-+	if (fsr < 0)
-+		return fsr;
-+
-+	if (fsr & (FSR_E_ERR | FSR_P_ERR)) {
-+		if (fsr & FSR_E_ERR)
-+			dev_dbg(nor->dev, "Erase operation failed.\n");
-+		else
-+			dev_dbg(nor->dev, "Program operation failed.\n");
-+
-+		if (fsr & FSR_PT_ERR)
-+			dev_dbg(nor->dev,
-+				"Attempted to modify a protected sector.\n");
-+
-+		nor->write_reg(nor, SPINOR_OP_CLFSR, NULL, 0);
-+		return -EIO;
-+	}
-+
-+	return fsr & FSR_READY;
-+}
-+
-+static int spi_nor_ready(struct spi_nor *nor)
-+{
-+	int sr, fsr;
-+
-+	sr = spi_nor_sr_ready(nor);
-+	if (sr < 0)
-+		return sr;
-+	fsr = nor->flags & SNOR_F_USE_FSR ? spi_nor_fsr_ready(nor) : 1;
-+	if (fsr < 0)
-+		return fsr;
-+	return sr && fsr;
-+}
-+
-+/*
-+ * Service routine to read status register until ready, or timeout occurs.
-+ * Returns non-zero if error.
-+ */
-+static int spi_nor_wait_till_ready_with_timeout(struct spi_nor *nor,
-+						unsigned long timeout)
-+{
-+	unsigned long timebase;
-+	int ret;
-+
-+	timebase = get_timer(0);
-+
-+	while (get_timer(timebase) < timeout) {
-+		ret = spi_nor_ready(nor);
-+		if (ret < 0)
-+			return ret;
-+		if (ret)
-+			return 0;
-+	}
-+
-+	dev_err(nor->dev, "flash operation timed out\n");
-+
-+	return -ETIMEDOUT;
-+}
-+
-+static int spi_nor_wait_till_ready(struct spi_nor *nor)
-+{
-+	return spi_nor_wait_till_ready_with_timeout(nor,
-+						    DEFAULT_READY_WAIT_JIFFIES);
-+}
-+
-+#ifdef CONFIG_SPI_FLASH_BAR
-+/*
-+ * This "clean_bar" is necessary in a situation when one was accessing
-+ * spi flash memory > 16 MiB by using Bank Address Register's BA24 bit.
-+ *
-+ * After it the BA24 bit shall be cleared to allow access to correct
-+ * memory region after SW reset (by calling "reset" command).
-+ *
-+ * Otherwise, the BA24 bit may be left set and then after reset, the
-+ * ROM would read/write/erase SPL from 16 MiB * bank_sel address.
-+ */
-+static int clean_bar(struct spi_nor *nor)
-+{
-+	u8 cmd, bank_sel = 0;
-+
-+	if (nor->bank_curr == 0)
-+		return 0;
-+	cmd = nor->bank_write_cmd;
-+	nor->bank_curr = 0;
-+	write_enable(nor);
-+
-+	return nor->write_reg(nor, cmd, &bank_sel, 1);
-+}
-+
-+static int write_bar(struct spi_nor *nor, u32 offset)
-+{
-+	u8 cmd, bank_sel;
-+	int ret;
-+
-+	bank_sel = offset / SZ_16M;
-+	if (bank_sel == nor->bank_curr)
-+		goto bar_end;
-+
-+	cmd = nor->bank_write_cmd;
-+	write_enable(nor);
-+	ret = nor->write_reg(nor, cmd, &bank_sel, 1);
-+	if (ret < 0) {
-+		debug("SF: fail to write bank register\n");
-+		return ret;
-+	}
-+
-+bar_end:
-+	nor->bank_curr = bank_sel;
-+	return nor->bank_curr;
-+}
-+
-+static int read_bar(struct spi_nor *nor, const struct flash_info *info)
-+{
-+	u8 curr_bank = 0;
-+	int ret;
-+
-+	switch (JEDEC_MFR(info)) {
-+	case SNOR_MFR_SPANSION:
-+		nor->bank_read_cmd = SPINOR_OP_BRRD;
-+		nor->bank_write_cmd = SPINOR_OP_BRWR;
-+		break;
-+	default:
-+		nor->bank_read_cmd = SPINOR_OP_RDEAR;
-+		nor->bank_write_cmd = SPINOR_OP_WREAR;
-+	}
-+
-+	ret = nor->read_reg(nor, nor->bank_read_cmd,
-+				    &curr_bank, 1);
-+	if (ret) {
-+		debug("SF: fail to read bank addr register\n");
-+		return ret;
-+	}
-+	nor->bank_curr = curr_bank;
-+
-+	return 0;
-+}
-+#endif
-+
-+/*
-+ * Initiate the erasure of a single sector
-+ */
-+static int spi_nor_erase_sector(struct spi_nor *nor, u32 addr)
-+{
-+	struct spi_mem_op op =
-+		SPI_MEM_OP(SPI_MEM_OP_CMD(nor->erase_opcode, 1),
-+			   SPI_MEM_OP_ADDR(nor->addr_width, addr, 1),
-+			   SPI_MEM_OP_NO_DUMMY,
-+			   SPI_MEM_OP_NO_DATA);
-+
-+	if (nor->erase)
-+		return nor->erase(nor, addr);
-+
-+	/*
-+	 * Default implementation, if driver doesn't have a specialized HW
-+	 * control
-+	 */
-+	return spi_mem_exec_op(nor->spi, &op);
-+}
-+
-+/*
-+ * 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.
-+ */
-+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, rem;
-+	int ret;
-+
-+	dev_dbg(nor->dev, "at 0x%llx, len %lld\n", (long long)instr->addr,
-+		(long long)instr->len);
-+
-+	div_u64_rem(instr->len, mtd->erasesize, &rem);
-+	if (rem)
-+		return -EINVAL;
-+
-+	addr = instr->addr;
-+	len = instr->len;
-+
-+	while (len) {
-+#ifdef CONFIG_SPI_FLASH_BAR
-+		ret = write_bar(nor, addr);
-+		if (ret < 0)
-+			return ret;
-+#endif
-+		write_enable(nor);
-+
-+		ret = spi_nor_erase_sector(nor, addr);
-+		if (ret)
-+			goto erase_err;
-+
-+		addr += mtd->erasesize;
-+		len -= mtd->erasesize;
-+
-+		ret = spi_nor_wait_till_ready(nor);
-+		if (ret)
-+			goto erase_err;
-+	}
-+
-+erase_err:
-+#ifdef CONFIG_SPI_FLASH_BAR
-+	ret = clean_bar(nor);
-+#endif
-+	write_disable(nor);
-+
-+	return ret;
-+}
-+
-+#if defined(CONFIG_SPI_FLASH_STMICRO) || defined(CONFIG_SPI_FLASH_SST)
-+/* Write status register and ensure bits in mask match written values */
-+static int write_sr_and_check(struct spi_nor *nor, u8 status_new, u8 mask)
-+{
-+	int ret;
-+
-+	write_enable(nor);
-+	ret = write_sr(nor, status_new);
-+	if (ret)
-+		return ret;
-+
-+	ret = spi_nor_wait_till_ready(nor);
-+	if (ret)
-+		return ret;
-+
-+	ret = read_sr(nor);
-+	if (ret < 0)
-+		return ret;
-+
-+	return ((ret & mask) != (status_new & mask)) ? -EIO : 0;
-+}
-+
-+static void stm_get_locked_range(struct spi_nor *nor, u8 sr, loff_t *ofs,
-+				 uint64_t *len)
-+{
-+	struct mtd_info *mtd = &nor->mtd;
-+	u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
-+	int shift = ffs(mask) - 1;
-+	int pow;
-+
-+	if (!(sr & mask)) {
-+		/* No protection */
-+		*ofs = 0;
-+		*len = 0;
-+	} else {
-+		pow = ((sr & mask) ^ mask) >> shift;
-+		*len = mtd->size >> pow;
-+		if (nor->flags & SNOR_F_HAS_SR_TB && sr & SR_TB)
-+			*ofs = 0;
-+		else
-+			*ofs = mtd->size - *len;
-+	}
-+}
-+
-+/*
-+ * Return 1 if the entire region is locked (if @locked is true) or unlocked (if
-+ * @locked is false); 0 otherwise
-+ */
-+static int stm_check_lock_status_sr(struct spi_nor *nor, loff_t ofs, u64 len,
-+				    u8 sr, bool locked)
-+{
-+	loff_t lock_offs;
-+	uint64_t lock_len;
-+
-+	if (!len)
-+		return 1;
-+
-+	stm_get_locked_range(nor, sr, &lock_offs, &lock_len);
-+
-+	if (locked)
-+		/* Requested range is a sub-range of locked range */
-+		return (ofs + len <= lock_offs + lock_len) && (ofs >= lock_offs);
-+	else
-+		/* Requested range does not overlap with locked range */
-+		return (ofs >= lock_offs + lock_len) || (ofs + len <= lock_offs);
-+}
-+
-+static int stm_is_locked_sr(struct spi_nor *nor, loff_t ofs, uint64_t len,
-+			    u8 sr)
-+{
-+	return stm_check_lock_status_sr(nor, ofs, len, sr, true);
-+}
-+
-+static int stm_is_unlocked_sr(struct spi_nor *nor, loff_t ofs, uint64_t len,
-+			      u8 sr)
-+{
-+	return stm_check_lock_status_sr(nor, ofs, len, sr, false);
-+}
-+
-+/*
-+ * Lock a region of the flash. Compatible with ST Micro and similar flash.
-+ * Supports the block protection bits BP{0,1,2} in the status register
-+ * (SR). Does not support these features found in newer SR bitfields:
-+ *   - SEC: sector/block protect - only handle SEC=0 (block protect)
-+ *   - CMP: complement protect - only support CMP=0 (range is not complemented)
-+ *
-+ * Support for the following is provided conditionally for some flash:
-+ *   - TB: top/bottom protect
-+ *
-+ * Sample table portion for 8MB flash (Winbond w25q64fw):
-+ *
-+ *   SEC  |  TB   |  BP2  |  BP1  |  BP0  |  Prot Length  | Protected Portion
-+ *  --------------------------------------------------------------------------
-+ *    X   |   X   |   0   |   0   |   0   |  NONE         | NONE
-+ *    0   |   0   |   0   |   0   |   1   |  128 KB       | Upper 1/64
-+ *    0   |   0   |   0   |   1   |   0   |  256 KB       | Upper 1/32
-+ *    0   |   0   |   0   |   1   |   1   |  512 KB       | Upper 1/16
-+ *    0   |   0   |   1   |   0   |   0   |  1 MB         | Upper 1/8
-+ *    0   |   0   |   1   |   0   |   1   |  2 MB         | Upper 1/4
-+ *    0   |   0   |   1   |   1   |   0   |  4 MB         | Upper 1/2
-+ *    X   |   X   |   1   |   1   |   1   |  8 MB         | ALL
-+ *  ------|-------|-------|-------|-------|---------------|-------------------
-+ *    0   |   1   |   0   |   0   |   1   |  128 KB       | Lower 1/64
-+ *    0   |   1   |   0   |   1   |   0   |  256 KB       | Lower 1/32
-+ *    0   |   1   |   0   |   1   |   1   |  512 KB       | Lower 1/16
-+ *    0   |   1   |   1   |   0   |   0   |  1 MB         | Lower 1/8
-+ *    0   |   1   |   1   |   0   |   1   |  2 MB         | Lower 1/4
-+ *    0   |   1   |   1   |   1   |   0   |  4 MB         | Lower 1/2
-+ *
-+ * Returns negative on errors, 0 on success.
-+ */
-+static int stm_lock(struct spi_nor *nor, loff_t ofs, uint64_t len)
-+{
-+	struct mtd_info *mtd = &nor->mtd;
-+	int status_old, status_new;
-+	u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
-+	u8 shift = ffs(mask) - 1, pow, val;
-+	loff_t lock_len;
-+	bool can_be_top = true, can_be_bottom = nor->flags & SNOR_F_HAS_SR_TB;
-+	bool use_top;
-+
-+	status_old = read_sr(nor);
-+	if (status_old < 0)
-+		return status_old;
-+
-+	/* If nothing in our range is unlocked, we don't need to do anything */
-+	if (stm_is_locked_sr(nor, ofs, len, status_old))
-+		return 0;
-+
-+	/* If anything below us is unlocked, we can't use 'bottom' protection */
-+	if (!stm_is_locked_sr(nor, 0, ofs, status_old))
-+		can_be_bottom = false;
-+
-+	/* If anything above us is unlocked, we can't use 'top' protection */
-+	if (!stm_is_locked_sr(nor, ofs + len, mtd->size - (ofs + len),
-+			      status_old))
-+		can_be_top = false;
-+
-+	if (!can_be_bottom && !can_be_top)
-+		return -EINVAL;
-+
-+	/* Prefer top, if both are valid */
-+	use_top = can_be_top;
-+
-+	/* lock_len: length of region that should end up locked */
-+	if (use_top)
-+		lock_len = mtd->size - ofs;
-+	else
-+		lock_len = ofs + len;
-+
-+	/*
-+	 * Need smallest pow such that:
-+	 *
-+	 *   1 / (2^pow) <= (len / size)
-+	 *
-+	 * so (assuming power-of-2 size) we do:
-+	 *
-+	 *   pow = ceil(log2(size / len)) = log2(size) - floor(log2(len))
-+	 */
-+	pow = ilog2(mtd->size) - ilog2(lock_len);
-+	val = mask - (pow << shift);
-+	if (val & ~mask)
-+		return -EINVAL;
-+	/* Don't "lock" with no region! */
-+	if (!(val & mask))
-+		return -EINVAL;
-+
-+	status_new = (status_old & ~mask & ~SR_TB) | val;
-+
-+	/* Disallow further writes if WP pin is asserted */
-+	status_new |= SR_SRWD;
-+
-+	if (!use_top)
-+		status_new |= SR_TB;
-+
-+	/* Don't bother if they're the same */
-+	if (status_new == status_old)
-+		return 0;
-+
-+	/* Only modify protection if it will not unlock other areas */
-+	if ((status_new & mask) < (status_old & mask))
-+		return -EINVAL;
-+
-+	return write_sr_and_check(nor, status_new, mask);
-+}
-+
-+/*
-+ * Unlock a region of the flash. See stm_lock() for more info
-+ *
-+ * Returns negative on errors, 0 on success.
-+ */
-+static int stm_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
-+{
-+	struct mtd_info *mtd = &nor->mtd;
-+	int status_old, status_new;
-+	u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
-+	u8 shift = ffs(mask) - 1, pow, val;
-+	loff_t lock_len;
-+	bool can_be_top = true, can_be_bottom = nor->flags & SNOR_F_HAS_SR_TB;
-+	bool use_top;
-+
-+	status_old = read_sr(nor);
-+	if (status_old < 0)
-+		return status_old;
-+
-+	/* If nothing in our range is locked, we don't need to do anything */
-+	if (stm_is_unlocked_sr(nor, ofs, len, status_old))
-+		return 0;
-+
-+	/* If anything below us is locked, we can't use 'top' protection */
-+	if (!stm_is_unlocked_sr(nor, 0, ofs, status_old))
-+		can_be_top = false;
-+
-+	/* If anything above us is locked, we can't use 'bottom' protection */
-+	if (!stm_is_unlocked_sr(nor, ofs + len, mtd->size - (ofs + len),
-+				status_old))
-+		can_be_bottom = false;
-+
-+	if (!can_be_bottom && !can_be_top)
-+		return -EINVAL;
-+
-+	/* Prefer top, if both are valid */
-+	use_top = can_be_top;
-+
-+	/* lock_len: length of region that should remain locked */
-+	if (use_top)
-+		lock_len = mtd->size - (ofs + len);
-+	else
-+		lock_len = ofs;
-+
-+	/*
-+	 * Need largest pow such that:
-+	 *
-+	 *   1 / (2^pow) >= (len / size)
-+	 *
-+	 * so (assuming power-of-2 size) we do:
-+	 *
-+	 *   pow = floor(log2(size / len)) = log2(size) - ceil(log2(len))
-+	 */
-+	pow = ilog2(mtd->size) - order_base_2(lock_len);
-+	if (lock_len == 0) {
-+		val = 0; /* fully unlocked */
-+	} else {
-+		val = mask - (pow << shift);
-+		/* Some power-of-two sizes are not supported */
-+		if (val & ~mask)
-+			return -EINVAL;
-+	}
-+
-+	status_new = (status_old & ~mask & ~SR_TB) | val;
-+
-+	/* Don't protect status register if we're fully unlocked */
-+	if (lock_len == 0)
-+		status_new &= ~SR_SRWD;
-+
-+	if (!use_top)
-+		status_new |= SR_TB;
-+
-+	/* Don't bother if they're the same */
-+	if (status_new == status_old)
-+		return 0;
-+
-+	/* Only modify protection if it will not lock other areas */
-+	if ((status_new & mask) > (status_old & mask))
-+		return -EINVAL;
-+
-+	return write_sr_and_check(nor, status_new, mask);
-+}
-+
-+/*
-+ * Check if a region of the flash is (completely) locked. See stm_lock() for
-+ * more info.
-+ *
-+ * Returns 1 if entire region is locked, 0 if any portion is unlocked, and
-+ * negative on errors.
-+ */
-+static int stm_is_locked(struct spi_nor *nor, loff_t ofs, uint64_t len)
-+{
-+	int status;
-+
-+	status = read_sr(nor);
-+	if (status < 0)
-+		return status;
-+
-+	return stm_is_locked_sr(nor, ofs, len, status);
-+}
-+#endif /* CONFIG_SPI_FLASH_STMICRO */
-+
-+static const struct flash_info *spi_nor_read_id(struct spi_nor *nor)
-+{
-+	int			tmp;
-+	u8			id[SPI_NOR_MAX_ID_LEN];
-+	const struct flash_info	*info;
-+
-+	tmp = nor->read_reg(nor, SPINOR_OP_RDID, id, SPI_NOR_MAX_ID_LEN);
-+	if (tmp < 0) {
-+		dev_dbg(nor->dev, "error %d reading JEDEC ID\n", tmp);
-+		return ERR_PTR(tmp);
-+	}
-+
-+	info = spi_nor_ids;
-+	for (; info->name; info++) {
-+		if (info->id_len) {
-+			if (!memcmp(info->id, id, info->id_len))
-+				return info;
-+		}
-+	}
-+
-+	dev_err(nor->dev, "unrecognized JEDEC id bytes: %02x, %02x, %02x\n",
-+		id[0], id[1], id[2]);
-+	return ERR_PTR(-ENODEV);
-+}
-+
-+static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len,
-+			size_t *retlen, u_char *buf)
-+{
-+	struct spi_nor *nor = mtd_to_spi_nor(mtd);
-+	int ret;
-+
-+	dev_dbg(nor->dev, "from 0x%08x, len %zd\n", (u32)from, len);
-+
-+	while (len) {
-+		loff_t addr = from;
-+		size_t read_len = len;
-+
-+#ifdef CONFIG_SPI_FLASH_BAR
-+		u32 remain_len;
-+
-+		ret = write_bar(nor, addr);
-+		if (ret < 0)
-+			return log_ret(ret);
-+		remain_len = (SZ_16M * (nor->bank_curr + 1)) - addr;
-+
-+		if (len < remain_len)
-+			read_len = len;
-+		else
-+			read_len = remain_len;
-+#endif
-+
-+		ret = nor->read(nor, addr, read_len, buf);
-+		if (ret == 0) {
-+			/* We shouldn't see 0-length reads */
-+			ret = -EIO;
-+			goto read_err;
-+		}
-+		if (ret < 0)
-+			goto read_err;
-+
-+		*retlen += ret;
-+		buf += ret;
-+		from += ret;
-+		len -= ret;
-+	}
-+	ret = 0;
-+
-+read_err:
-+#ifdef CONFIG_SPI_FLASH_BAR
-+	ret = clean_bar(nor);
-+#endif
-+	return ret;
-+}
-+
-+#ifdef CONFIG_SPI_FLASH_SST
-+static int sst_write_byteprogram(struct spi_nor *nor, loff_t to, size_t len,
-+				 size_t *retlen, const u_char *buf)
-+{
-+	size_t actual;
-+	int ret = 0;
-+
-+	for (actual = 0; actual < len; actual++) {
-+		nor->program_opcode = SPINOR_OP_BP;
-+
-+		write_enable(nor);
-+		/* write one byte. */
-+		ret = nor->write(nor, to, 1, buf + actual);
-+		if (ret < 0)
-+			goto sst_write_err;
-+		ret = spi_nor_wait_till_ready(nor);
-+		if (ret)
-+			goto sst_write_err;
-+		to++;
-+	}
-+
-+sst_write_err:
-+	write_disable(nor);
-+	return ret;
-+}
-+
-+static int sst_write(struct mtd_info *mtd, loff_t to, size_t len,
-+		     size_t *retlen, const u_char *buf)
-+{
-+	struct spi_nor *nor = mtd_to_spi_nor(mtd);
-+	struct spi_slave *spi = nor->spi;
-+	size_t actual;
-+	int ret;
-+
-+	dev_dbg(nor->dev, "to 0x%08x, len %zd\n", (u32)to, len);
-+	if (spi->mode & SPI_TX_BYTE)
-+		return sst_write_byteprogram(nor, to, len, retlen, buf);
-+
-+	write_enable(nor);
-+
-+	nor->sst_write_second = false;
-+
-+	actual = to % 2;
-+	/* Start write from odd address. */
-+	if (actual) {
-+		nor->program_opcode = SPINOR_OP_BP;
-+
-+		/* write one byte. */
-+		ret = nor->write(nor, to, 1, buf);
-+		if (ret < 0)
-+			goto sst_write_err;
-+		ret = spi_nor_wait_till_ready(nor);
-+		if (ret)
-+			goto sst_write_err;
-+	}
-+	to += actual;
-+
-+	/* Write out most of the data here. */
-+	for (; actual < len - 1; actual += 2) {
-+		nor->program_opcode = SPINOR_OP_AAI_WP;
-+
-+		/* write two bytes. */
-+		ret = nor->write(nor, to, 2, buf + actual);
-+		if (ret < 0)
-+			goto sst_write_err;
-+		ret = spi_nor_wait_till_ready(nor);
-+		if (ret)
-+			goto sst_write_err;
-+		to += 2;
-+		nor->sst_write_second = true;
-+	}
-+	nor->sst_write_second = false;
-+
-+	write_disable(nor);
-+	ret = spi_nor_wait_till_ready(nor);
-+	if (ret)
-+		goto sst_write_err;
-+
-+	/* Write out trailing byte if it exists. */
-+	if (actual != len) {
-+		write_enable(nor);
-+
-+		nor->program_opcode = SPINOR_OP_BP;
-+		ret = nor->write(nor, to, 1, buf + actual);
-+		if (ret < 0)
-+			goto sst_write_err;
-+		ret = spi_nor_wait_till_ready(nor);
-+		if (ret)
-+			goto sst_write_err;
-+		write_disable(nor);
-+		actual += 1;
-+	}
-+sst_write_err:
-+	*retlen += actual;
-+	return ret;
-+}
-+#endif
-+/*
-+ * Write an address range to the nor chip.  Data must be written in
-+ * FLASH_PAGESIZE chunks.  The address range may be any size provided
-+ * it is within the physical boundaries.
-+ */
-+static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len,
-+	size_t *retlen, const u_char *buf)
-+{
-+	struct spi_nor *nor = mtd_to_spi_nor(mtd);
-+	size_t page_offset, page_remain, i;
-+	ssize_t ret;
-+
-+	dev_dbg(nor->dev, "to 0x%08x, len %zd\n", (u32)to, len);
-+
-+	for (i = 0; i < len; ) {
-+		ssize_t written;
-+		loff_t addr = to + i;
-+
-+		/*
-+		 * If page_size is a power of two, the offset can be quickly
-+		 * calculated with an AND operation. On the other cases we
-+		 * need to do a modulus operation (more expensive).
-+		 * Power of two numbers have only one bit set and we can use
-+		 * the instruction hweight32 to detect if we need to do a
-+		 * modulus (do_div()) or not.
-+		 */
-+		if (hweight32(nor->page_size) == 1) {
-+			page_offset = addr & (nor->page_size - 1);
-+		} else {
-+			u64 aux = addr;
-+
-+			page_offset = do_div(aux, nor->page_size);
-+		}
-+		/* the size of data remaining on the first page */
-+		page_remain = min_t(size_t,
-+				    nor->page_size - page_offset, len - i);
-+
-+#ifdef CONFIG_SPI_FLASH_BAR
-+		ret = write_bar(nor, addr);
-+		if (ret < 0)
-+			return ret;
-+#endif
-+		write_enable(nor);
-+		ret = nor->write(nor, addr, page_remain, buf + i);
-+		if (ret < 0)
-+			goto write_err;
-+		written = ret;
-+
-+		ret = spi_nor_wait_till_ready(nor);
-+		if (ret)
-+			goto write_err;
-+		*retlen += written;
-+		i += written;
-+	}
-+
-+write_err:
-+#ifdef CONFIG_SPI_FLASH_BAR
-+	ret = clean_bar(nor);
-+#endif
-+	return ret;
-+}
-+
-+#ifdef CONFIG_SPI_FLASH_MACRONIX
-+/**
-+ * macronix_quad_enable() - set QE bit in Status Register.
-+ * @nor:	pointer to a 'struct spi_nor'
-+ *
-+ * Set the Quad Enable (QE) bit in the Status Register.
-+ *
-+ * bit 6 of the Status Register is the QE bit for Macronix like QSPI memories.
-+ *
-+ * Return: 0 on success, -errno otherwise.
-+ */
-+static int macronix_quad_enable(struct spi_nor *nor)
-+{
-+	int ret, val;
-+
-+	val = read_sr(nor);
-+	if (val < 0)
-+		return val;
-+	if (val & SR_QUAD_EN_MX)
-+		return 0;
-+
-+	write_enable(nor);
-+
-+	write_sr(nor, val | SR_QUAD_EN_MX);
-+
-+	ret = spi_nor_wait_till_ready(nor);
-+	if (ret)
-+		return ret;
-+
-+	ret = read_sr(nor);
-+	if (!(ret > 0 && (ret & SR_QUAD_EN_MX))) {
-+		dev_err(nor->dev, "Macronix Quad bit not set\n");
-+		return -EINVAL;
-+	}
-+
-+	return 0;
-+}
-+#endif
-+
-+#if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND)
-+/*
-+ * Write status Register and configuration register with 2 bytes
-+ * The first byte will be written to the status register, while the
-+ * second byte will be written to the configuration register.
-+ * Return negative if error occurred.
-+ */
-+static int write_sr_cr(struct spi_nor *nor, u8 *sr_cr)
-+{
-+	int ret;
-+
-+	write_enable(nor);
-+
-+	ret = nor->write_reg(nor, SPINOR_OP_WRSR, sr_cr, 2);
-+	if (ret < 0) {
-+		dev_dbg(nor->dev,
-+			"error while writing configuration register\n");
-+		return -EINVAL;
-+	}
-+
-+	ret = spi_nor_wait_till_ready(nor);
-+	if (ret) {
-+		dev_dbg(nor->dev,
-+			"timeout while writing configuration register\n");
-+		return ret;
-+	}
-+
-+	return 0;
-+}
-+
-+/**
-+ * spansion_read_cr_quad_enable() - set QE bit in Configuration Register.
-+ * @nor:	pointer to a 'struct spi_nor'
-+ *
-+ * Set the Quad Enable (QE) bit in the Configuration Register.
-+ * This function should be used with QSPI memories supporting the Read
-+ * Configuration Register (35h) instruction.
-+ *
-+ * bit 1 of the Configuration Register is the QE bit for Spansion like QSPI
-+ * memories.
-+ *
-+ * Return: 0 on success, -errno otherwise.
-+ */
-+static int spansion_read_cr_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_dbg(dev, "error while reading configuration register\n");
-+		return -EINVAL;
-+	}
-+
-+	if (ret & CR_QUAD_EN_SPAN)
-+		return 0;
-+
-+	sr_cr[1] = ret | CR_QUAD_EN_SPAN;
-+
-+	/* Keep the current value of the Status Register. */
-+	ret = read_sr(nor);
-+	if (ret < 0) {
-+		dev_dbg(dev, "error while reading status register\n");
-+		return -EINVAL;
-+	}
-+	sr_cr[0] = ret;
-+
-+	ret = write_sr_cr(nor, sr_cr);
-+	if (ret)
-+		return ret;
-+
-+	/* Read back and check it. */
-+	ret = read_cr(nor);
-+	if (!(ret > 0 && (ret & CR_QUAD_EN_SPAN))) {
-+		dev_dbg(nor->dev, "Spansion Quad bit not set\n");
-+		return -EINVAL;
-+	}
-+
-+	return 0;
-+}
-+
-+#if CONFIG_IS_ENABLED(SPI_FLASH_SFDP_SUPPORT)
-+/**
-+ * spansion_no_read_cr_quad_enable() - set QE bit in Configuration Register.
-+ * @nor:	pointer to a 'struct spi_nor'
-+ *
-+ * Set the Quad Enable (QE) bit in the Configuration Register.
-+ * This function should be used with QSPI memories not supporting the Read
-+ * Configuration Register (35h) instruction.
-+ *
-+ * bit 1 of the Configuration Register is the QE bit for Spansion like QSPI
-+ * memories.
-+ *
-+ * Return: 0 on success, -errno otherwise.
-+ */
-+static int spansion_no_read_cr_quad_enable(struct spi_nor *nor)
-+{
-+	u8 sr_cr[2];
-+	int ret;
-+
-+	/* Keep the current value of the Status Register. */
-+	ret = read_sr(nor);
-+	if (ret < 0) {
-+		dev_dbg(nor->dev, "error while reading status register\n");
-+		return -EINVAL;
-+	}
-+	sr_cr[0] = ret;
-+	sr_cr[1] = CR_QUAD_EN_SPAN;
-+
-+	return write_sr_cr(nor, sr_cr);
-+}
-+
-+#endif /* CONFIG_SPI_FLASH_SFDP_SUPPORT */
-+#endif /* CONFIG_SPI_FLASH_SPANSION */
-+
-+struct spi_nor_read_command {
-+	u8			num_mode_clocks;
-+	u8			num_wait_states;
-+	u8			opcode;
-+	enum spi_nor_protocol	proto;
-+};
-+
-+struct spi_nor_pp_command {
-+	u8			opcode;
-+	enum spi_nor_protocol	proto;
-+};
-+
-+enum spi_nor_read_command_index {
-+	SNOR_CMD_READ,
-+	SNOR_CMD_READ_FAST,
-+	SNOR_CMD_READ_1_1_1_DTR,
-+
-+	/* Dual SPI */
-+	SNOR_CMD_READ_1_1_2,
-+	SNOR_CMD_READ_1_2_2,
-+	SNOR_CMD_READ_2_2_2,
-+	SNOR_CMD_READ_1_2_2_DTR,
-+
-+	/* Quad SPI */
-+	SNOR_CMD_READ_1_1_4,
-+	SNOR_CMD_READ_1_4_4,
-+	SNOR_CMD_READ_4_4_4,
-+	SNOR_CMD_READ_1_4_4_DTR,
-+
-+	/* Octo SPI */
-+	SNOR_CMD_READ_1_1_8,
-+	SNOR_CMD_READ_1_8_8,
-+	SNOR_CMD_READ_8_8_8,
-+	SNOR_CMD_READ_1_8_8_DTR,
-+
-+	SNOR_CMD_READ_MAX
-+};
-+
-+enum spi_nor_pp_command_index {
-+	SNOR_CMD_PP,
-+
-+	/* Quad SPI */
-+	SNOR_CMD_PP_1_1_4,
-+	SNOR_CMD_PP_1_4_4,
-+	SNOR_CMD_PP_4_4_4,
-+
-+	/* Octo SPI */
-+	SNOR_CMD_PP_1_1_8,
-+	SNOR_CMD_PP_1_8_8,
-+	SNOR_CMD_PP_8_8_8,
-+
-+	SNOR_CMD_PP_MAX
-+};
-+
-+struct spi_nor_flash_parameter {
-+	u64				size;
-+	u32				page_size;
-+
-+	struct spi_nor_hwcaps		hwcaps;
-+	struct spi_nor_read_command	reads[SNOR_CMD_READ_MAX];
-+	struct spi_nor_pp_command	page_programs[SNOR_CMD_PP_MAX];
-+
-+	int (*quad_enable)(struct spi_nor *nor);
-+};
-+
-+static void
-+spi_nor_set_read_settings(struct spi_nor_read_command *read,
-+			  u8 num_mode_clocks,
-+			  u8 num_wait_states,
-+			  u8 opcode,
-+			  enum spi_nor_protocol proto)
-+{
-+	read->num_mode_clocks = num_mode_clocks;
-+	read->num_wait_states = num_wait_states;
-+	read->opcode = opcode;
-+	read->proto = proto;
-+}
-+
-+static void
-+spi_nor_set_pp_settings(struct spi_nor_pp_command *pp,
-+			u8 opcode,
-+			enum spi_nor_protocol proto)
-+{
-+	pp->opcode = opcode;
-+	pp->proto = proto;
-+}
-+
-+#if CONFIG_IS_ENABLED(SPI_FLASH_SFDP_SUPPORT)
-+/*
-+ * Serial Flash Discoverable Parameters (SFDP) parsing.
-+ */
-+
-+/**
-+ * spi_nor_read_sfdp() - read Serial Flash Discoverable Parameters.
-+ * @nor:	pointer to a 'struct spi_nor'
-+ * @addr:	offset in the SFDP area to start reading data from
-+ * @len:	number of bytes to read
-+ * @buf:	buffer where the SFDP data are copied into (dma-safe memory)
-+ *
-+ * Whatever the actual numbers of bytes for address and dummy cycles are
-+ * for (Fast) Read commands, the Read SFDP (5Ah) instruction is always
-+ * followed by a 3-byte address and 8 dummy clock cycles.
-+ *
-+ * Return: 0 on success, -errno otherwise.
-+ */
-+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;
-+
-+	while (len) {
-+		ret = nor->read(nor, addr, len, (u8 *)buf);
-+		if (!ret || ret > len) {
-+			ret = -EIO;
-+			goto read_err;
-+		}
-+		if (ret < 0)
-+			goto read_err;
-+
-+		buf += ret;
-+		addr += ret;
-+		len -= ret;
-+	}
-+	ret = 0;
-+
-+read_err:
-+	nor->read_opcode = read_opcode;
-+	nor->addr_width = addr_width;
-+	nor->read_dummy = read_dummy;
-+
-+	return ret;
-+}
-+
-+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)	(((p)->id_msb << 8) | (p)->id_lsb)
-+#define SFDP_PARAM_HEADER_PTP(p) \
-+	(((p)->parameter_table_pointer[2] << 16) | \
-+	 ((p)->parameter_table_pointer[1] <<  8) | \
-+	 ((p)->parameter_table_pointer[0] <<  0))
-+
-+#define SFDP_BFPT_ID		0xff00	/* Basic Flash Parameter Table */
-+#define SFDP_SECTOR_MAP_ID	0xff81	/* Sector Map 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; /* Ox50444653U <=> "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 */
-+
-+/*
-+ * JESD216 rev B defines a Basic Flash Parameter Table of 16 DWORDs.
-+ * They are indexed from 1 but C arrays are indexed from 0.
-+ */
-+#define BFPT_DWORD(i)		((i) - 1)
-+#define BFPT_DWORD_MAX		16
-+
-+/* The first version of JESB216 defined only 9 DWORDs. */
-+#define BFPT_DWORD_MAX_JESD216			9
-+
-+/* 1st DWORD. */
-+#define BFPT_DWORD1_FAST_READ_1_1_2		BIT(16)
-+#define BFPT_DWORD1_ADDRESS_BYTES_MASK		GENMASK(18, 17)
-+#define BFPT_DWORD1_ADDRESS_BYTES_3_ONLY	(0x0UL << 17)
-+#define BFPT_DWORD1_ADDRESS_BYTES_3_OR_4	(0x1UL << 17)
-+#define BFPT_DWORD1_ADDRESS_BYTES_4_ONLY	(0x2UL << 17)
-+#define BFPT_DWORD1_DTR				BIT(19)
-+#define BFPT_DWORD1_FAST_READ_1_2_2		BIT(20)
-+#define BFPT_DWORD1_FAST_READ_1_4_4		BIT(21)
-+#define BFPT_DWORD1_FAST_READ_1_1_4		BIT(22)
-+
-+/* 5th DWORD. */
-+#define BFPT_DWORD5_FAST_READ_2_2_2		BIT(0)
-+#define BFPT_DWORD5_FAST_READ_4_4_4		BIT(4)
-+
-+/* 11th DWORD. */
-+#define BFPT_DWORD11_PAGE_SIZE_SHIFT		4
-+#define BFPT_DWORD11_PAGE_SIZE_MASK		GENMASK(7, 4)
-+
-+/* 15th DWORD. */
-+
-+/*
-+ * (from JESD216 rev B)
-+ * 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 phase.
-+ * - 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_DWORD15_QER_MASK			GENMASK(22, 20)
-+#define BFPT_DWORD15_QER_NONE			(0x0UL << 20) /* Micron */
-+#define BFPT_DWORD15_QER_SR2_BIT1_BUGGY		(0x1UL << 20)
-+#define BFPT_DWORD15_QER_SR1_BIT6		(0x2UL << 20) /* Macronix */
-+#define BFPT_DWORD15_QER_SR2_BIT7		(0x3UL << 20)
-+#define BFPT_DWORD15_QER_SR2_BIT1_NO_RD		(0x4UL << 20)
-+#define BFPT_DWORD15_QER_SR2_BIT1		(0x5UL << 20) /* Spansion */
-+
-+struct sfdp_bfpt {
-+	u32	dwords[BFPT_DWORD_MAX];
-+};
-+
-+/* Fast Read settings. */
-+
-+static void
-+spi_nor_set_read_settings_from_bfpt(struct spi_nor_read_command *read,
-+				    u16 half,
-+				    enum spi_nor_protocol proto)
-+{
-+	read->num_mode_clocks = (half >> 5) & 0x07;
-+	read->num_wait_states = (half >> 0) & 0x1f;
-+	read->opcode = (half >> 8) & 0xff;
-+	read->proto = proto;
-+}
-+
-+struct sfdp_bfpt_read {
-+	/* The Fast Read x-y-z hardware capability in params->hwcaps.mask. */
-+	u32			hwcaps;
-+
-+	/*
-+	 * The <supported_bit> bit in <supported_dword> BFPT DWORD tells us
-+	 * whether the Fast Read x-y-z command is supported.
-+	 */
-+	u32			supported_dword;
-+	u32			supported_bit;
-+
-+	/*
-+	 * The half-word at offset <setting_shift> in <setting_dword> BFPT DWORD
-+	 * encodes the op code, the number of mode clocks and the number of wait
-+	 * states to be used by Fast Read x-y-z command.
-+	 */
-+	u32			settings_dword;
-+	u32			settings_shift;
-+
-+	/* The SPI protocol for this Fast Read x-y-z command. */
-+	enum spi_nor_protocol	proto;
-+};
-+
-+static const struct sfdp_bfpt_read sfdp_bfpt_reads[] = {
-+	/* Fast Read 1-1-2 */
-+	{
-+		SNOR_HWCAPS_READ_1_1_2,
-+		BFPT_DWORD(1), BIT(16),	/* Supported bit */
-+		BFPT_DWORD(4), 0,	/* Settings */
-+		SNOR_PROTO_1_1_2,
-+	},
-+
-+	/* Fast Read 1-2-2 */
-+	{
-+		SNOR_HWCAPS_READ_1_2_2,
-+		BFPT_DWORD(1), BIT(20),	/* Supported bit */
-+		BFPT_DWORD(4), 16,	/* Settings */
-+		SNOR_PROTO_1_2_2,
-+	},
-+
-+	/* Fast Read 2-2-2 */
-+	{
-+		SNOR_HWCAPS_READ_2_2_2,
-+		BFPT_DWORD(5),  BIT(0),	/* Supported bit */
-+		BFPT_DWORD(6), 16,	/* Settings */
-+		SNOR_PROTO_2_2_2,
-+	},
-+
-+	/* Fast Read 1-1-4 */
-+	{
-+		SNOR_HWCAPS_READ_1_1_4,
-+		BFPT_DWORD(1), BIT(22),	/* Supported bit */
-+		BFPT_DWORD(3), 16,	/* Settings */
-+		SNOR_PROTO_1_1_4,
-+	},
-+
-+	/* Fast Read 1-4-4 */
-+	{
-+		SNOR_HWCAPS_READ_1_4_4,
-+		BFPT_DWORD(1), BIT(21),	/* Supported bit */
-+		BFPT_DWORD(3), 0,	/* Settings */
-+		SNOR_PROTO_1_4_4,
-+	},
-+
-+	/* Fast Read 4-4-4 */
-+	{
-+		SNOR_HWCAPS_READ_4_4_4,
-+		BFPT_DWORD(5), BIT(4),	/* Supported bit */
-+		BFPT_DWORD(7), 16,	/* Settings */
-+		SNOR_PROTO_4_4_4,
-+	},
-+};
-+
-+struct sfdp_bfpt_erase {
-+	/*
-+	 * The half-word at offset <shift> in DWORD <dwoard> encodes the
-+	 * op code and erase sector size to be used by Sector Erase commands.
-+	 */
-+	u32			dword;
-+	u32			shift;
-+};
-+
-+static const struct sfdp_bfpt_erase sfdp_bfpt_erases[] = {
-+	/* Erase Type 1 in DWORD8 bits[15:0] */
-+	{BFPT_DWORD(8), 0},
-+
-+	/* Erase Type 2 in DWORD8 bits[31:16] */
-+	{BFPT_DWORD(8), 16},
-+
-+	/* Erase Type 3 in DWORD9 bits[15:0] */
-+	{BFPT_DWORD(9), 0},
-+
-+	/* Erase Type 4 in DWORD9 bits[31:16] */
-+	{BFPT_DWORD(9), 16},
-+};
-+
-+static int spi_nor_hwcaps_read2cmd(u32 hwcaps);
-+
-+/**
-+ * spi_nor_parse_bfpt() - read and parse the Basic Flash Parameter Table.
-+ * @nor:		pointer to a 'struct spi_nor'
-+ * @bfpt_header:	pointer to the 'struct sfdp_parameter_header' describing
-+ *			the Basic Flash Parameter Table length and version
-+ * @params:		pointer to the 'struct spi_nor_flash_parameter' to be
-+ *			filled
-+ *
-+ * The Basic Flash Parameter Table is the main and only mandatory table as
-+ * defined by the SFDP (JESD216) specification.
-+ * It provides us with the total size (memory density) of the data array and
-+ * the number of address bytes for Fast Read, Page Program and Sector Erase
-+ * commands.
-+ * For Fast READ commands, it also gives the number of mode clock cycles and
-+ * wait states (regrouped in the number of dummy clock cycles) for each
-+ * supported instruction op code.
-+ * For Page Program, the page size is now available since JESD216 rev A, however
-+ * the supported instruction op codes are still not provided.
-+ * For Sector Erase commands, this table stores the supported instruction op
-+ * codes and the associated sector sizes.
-+ * Finally, the Quad Enable Requirements (QER) are also available since JESD216
-+ * rev A. The QER bits encode the manufacturer dependent procedure to be
-+ * executed to set the Quad Enable (QE) bit in some internal register of the
-+ * Quad SPI memory. Indeed the QE bit, when it exists, must be set before
-+ * sending any Quad SPI command to the memory. Actually, setting the QE bit
-+ * tells the memory to reassign its WP# and HOLD#/RESET# pins to functions IO2
-+ * and IO3 hence enabling 4 (Quad) I/O lines.
-+ *
-+ * Return: 0 on success, -errno otherwise.
-+ */
-+static int spi_nor_parse_bfpt(struct spi_nor *nor,
-+			      const struct sfdp_parameter_header *bfpt_header,
-+			      struct spi_nor_flash_parameter *params)
-+{
-+	struct mtd_info *mtd = &nor->mtd;
-+	struct sfdp_bfpt bfpt;
-+	size_t len;
-+	int i, cmd, err;
-+	u32 addr;
-+	u16 half;
-+
-+	/* JESD216 Basic Flash Parameter Table length is at least 9 DWORDs. */
-+	if (bfpt_header->length < BFPT_DWORD_MAX_JESD216)
-+		return -EINVAL;
-+
-+	/* Read the Basic Flash Parameter Table. */
-+	len = min_t(size_t, sizeof(bfpt),
-+		    bfpt_header->length * sizeof(u32));
-+	addr = SFDP_PARAM_HEADER_PTP(bfpt_header);
-+	memset(&bfpt, 0, sizeof(bfpt));
-+	err = spi_nor_read_sfdp(nor,  addr, len, &bfpt);
-+	if (err < 0)
-+		return err;
-+
-+	/* Fix endianness of the BFPT DWORDs. */
-+	for (i = 0; i < BFPT_DWORD_MAX; i++)
-+		bfpt.dwords[i] = le32_to_cpu(bfpt.dwords[i]);
-+
-+	/* Number of address bytes. */
-+	switch (bfpt.dwords[BFPT_DWORD(1)] & BFPT_DWORD1_ADDRESS_BYTES_MASK) {
-+	case BFPT_DWORD1_ADDRESS_BYTES_3_ONLY:
-+		nor->addr_width = 3;
-+		break;
-+
-+	case BFPT_DWORD1_ADDRESS_BYTES_4_ONLY:
-+		nor->addr_width = 4;
-+		break;
-+
-+	default:
-+		break;
-+	}
-+
-+	/* Flash Memory Density (in bits). */
-+	params->size = bfpt.dwords[BFPT_DWORD(2)];
-+	if (params->size & BIT(31)) {
-+		params->size &= ~BIT(31);
-+
-+		/*
-+		 * Prevent overflows on params->size. Anyway, a NOR of 2^64
-+		 * bits is unlikely to exist so this error probably means
-+		 * the BFPT we are reading is corrupted/wrong.
-+		 */
-+		if (params->size > 63)
-+			return -EINVAL;
-+
-+		params->size = 1ULL << params->size;
-+	} else {
-+		params->size++;
-+	}
-+	params->size >>= 3; /* Convert to bytes. */
-+
-+	/* Fast Read settings. */
-+	for (i = 0; i < ARRAY_SIZE(sfdp_bfpt_reads); i++) {
-+		const struct sfdp_bfpt_read *rd = &sfdp_bfpt_reads[i];
-+		struct spi_nor_read_command *read;
-+
-+		if (!(bfpt.dwords[rd->supported_dword] & rd->supported_bit)) {
-+			params->hwcaps.mask &= ~rd->hwcaps;
-+			continue;
-+		}
-+
-+		params->hwcaps.mask |= rd->hwcaps;
-+		cmd = spi_nor_hwcaps_read2cmd(rd->hwcaps);
-+		read = &params->reads[cmd];
-+		half = bfpt.dwords[rd->settings_dword] >> rd->settings_shift;
-+		spi_nor_set_read_settings_from_bfpt(read, half, rd->proto);
-+	}
-+
-+	/* Sector Erase settings. */
-+	for (i = 0; i < ARRAY_SIZE(sfdp_bfpt_erases); i++) {
-+		const struct sfdp_bfpt_erase *er = &sfdp_bfpt_erases[i];
-+		u32 erasesize;
-+		u8 opcode;
-+
-+		half = bfpt.dwords[er->dword] >> er->shift;
-+		erasesize = half & 0xff;
-+
-+		/* erasesize == 0 means this Erase Type is not supported. */
-+		if (!erasesize)
-+			continue;
-+
-+		erasesize = 1U << erasesize;
-+		opcode = (half >> 8) & 0xff;
-+#ifdef CONFIG_MTD_SPI_NOR_USE_4K_SECTORS
-+		if (erasesize == SZ_4K) {
-+			nor->erase_opcode = opcode;
-+			mtd->erasesize = erasesize;
-+			break;
-+		}
-+#endif
-+		if (!mtd->erasesize || mtd->erasesize < erasesize) {
-+			nor->erase_opcode = opcode;
-+			mtd->erasesize = erasesize;
-+		}
-+	}
-+
-+	/* Stop here if not JESD216 rev A or later. */
-+	if (bfpt_header->length < BFPT_DWORD_MAX)
-+		return 0;
-+
-+	/* Page size: this field specifies 'N' so the page size = 2^N bytes. */
-+	params->page_size = bfpt.dwords[BFPT_DWORD(11)];
-+	params->page_size &= BFPT_DWORD11_PAGE_SIZE_MASK;
-+	params->page_size >>= BFPT_DWORD11_PAGE_SIZE_SHIFT;
-+	params->page_size = 1U << params->page_size;
-+
-+	/* Quad Enable Requirements. */
-+	switch (bfpt.dwords[BFPT_DWORD(15)] & BFPT_DWORD15_QER_MASK) {
-+	case BFPT_DWORD15_QER_NONE:
-+		params->quad_enable = NULL;
-+		break;
-+#if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND)
-+	case BFPT_DWORD15_QER_SR2_BIT1_BUGGY:
-+	case BFPT_DWORD15_QER_SR2_BIT1_NO_RD:
-+		params->quad_enable = spansion_no_read_cr_quad_enable;
-+		break;
-+#endif
-+#ifdef CONFIG_SPI_FLASH_MACRONIX
-+	case BFPT_DWORD15_QER_SR1_BIT6:
-+		params->quad_enable = macronix_quad_enable;
-+		break;
-+#endif
-+#if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND)
-+	case BFPT_DWORD15_QER_SR2_BIT1:
-+		params->quad_enable = spansion_read_cr_quad_enable;
-+		break;
-+#endif
-+	default:
-+		return -EINVAL;
-+	}
-+
-+	return 0;
-+}
-+
-+/**
-+ * spi_nor_parse_sfdp() - parse the Serial Flash Discoverable Parameters.
-+ * @nor:		pointer to a 'struct spi_nor'
-+ * @params:		pointer to the 'struct spi_nor_flash_parameter' to be
-+ *			filled
-+ *
-+ * The Serial Flash Discoverable Parameters are described by the JEDEC JESD216
-+ * specification. This is a standard which tends to supported by almost all
-+ * (Q)SPI memory manufacturers. Those hard-coded tables allow us to learn at
-+ * runtime the main parameters needed to perform basic SPI flash operations such
-+ * as Fast Read, Page Program or Sector Erase commands.
-+ *
-+ * Return: 0 on success, -errno otherwise.
-+ */
-+static int spi_nor_parse_sfdp(struct spi_nor *nor,
-+			      struct spi_nor_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 < 0)
-+		return err;
-+
-+	/* Check the SFDP header version. */
-+	if (le32_to_cpu(header.signature) != SFDP_SIGNATURE ||
-+	    header.major != SFDP_JESD216_MAJOR)
-+		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 then read all parameter headers with a single
-+	 * Read SFDP command. These parameter headers will actually be parsed
-+	 * twice: a first time to get the latest revision of the basic flash
-+	 * parameter table, then a second time to handle the supported optional
-+	 * tables.
-+	 * Hence we read the parameter headers once for all to reduce the
-+	 * processing time. Also we use kmalloc() instead of devm_kmalloc()
-+	 * because we don't need to keep these parameter headers: the allocated
-+	 * memory is always released with kfree() before exiting this function.
-+	 */
-+	if (header.nph) {
-+		psize = header.nph * sizeof(*param_headers);
-+
-+		param_headers = kmalloc(psize, GFP_KERNEL);
-+		if (!param_headers)
-+			return -ENOMEM;
-+
-+		err = spi_nor_read_sfdp(nor, sizeof(header),
-+					psize, param_headers);
-+		if (err < 0) {
-+			dev_err(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;
-+
-+	/* 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_SECTOR_MAP_ID:
-+			dev_info(dev, "non-uniform erase sector maps are not supported yet.\n");
-+			break;
-+
-+		default:
-+			break;
-+		}
-+
-+		if (err)
-+			goto exit;
-+	}
-+
-+exit:
-+	kfree(param_headers);
-+	return err;
-+}
-+#else
-+static int spi_nor_parse_sfdp(struct spi_nor *nor,
-+			      struct spi_nor_flash_parameter *params)
-+{
-+	return -EINVAL;
-+}
-+#endif /* SPI_FLASH_SFDP_SUPPORT */
-+
-+static int spi_nor_init_params(struct spi_nor *nor,
-+			       const struct flash_info *info,
-+			       struct spi_nor_flash_parameter *params)
-+{
-+	/* Set legacy flash parameters as default. */
-+	memset(params, 0, sizeof(*params));
-+
-+	/* Set SPI NOR sizes. */
-+	params->size = info->sector_size * info->n_sectors;
-+	params->page_size = info->page_size;
-+
-+	/* (Fast) Read settings. */
-+	params->hwcaps.mask |= SNOR_HWCAPS_READ;
-+	spi_nor_set_read_settings(&params->reads[SNOR_CMD_READ],
-+				  0, 0, SPINOR_OP_READ,
-+				  SNOR_PROTO_1_1_1);
-+
-+	if (!(info->flags & SPI_NOR_NO_FR)) {
-+		params->hwcaps.mask |= SNOR_HWCAPS_READ_FAST;
-+		spi_nor_set_read_settings(&params->reads[SNOR_CMD_READ_FAST],
-+					  0, 8, SPINOR_OP_READ_FAST,
-+					  SNOR_PROTO_1_1_1);
-+	}
-+
-+	if (info->flags & SPI_NOR_DUAL_READ) {
-+		params->hwcaps.mask |= SNOR_HWCAPS_READ_1_1_2;
-+		spi_nor_set_read_settings(&params->reads[SNOR_CMD_READ_1_1_2],
-+					  0, 8, SPINOR_OP_READ_1_1_2,
-+					  SNOR_PROTO_1_1_2);
-+	}
-+
-+	if (info->flags & SPI_NOR_QUAD_READ) {
-+		params->hwcaps.mask |= SNOR_HWCAPS_READ_1_1_4;
-+		spi_nor_set_read_settings(&params->reads[SNOR_CMD_READ_1_1_4],
-+					  0, 8, SPINOR_OP_READ_1_1_4,
-+					  SNOR_PROTO_1_1_4);
-+	}
-+
-+	/* Page Program settings. */
-+	params->hwcaps.mask |= SNOR_HWCAPS_PP;
-+	spi_nor_set_pp_settings(&params->page_programs[SNOR_CMD_PP],
-+				SPINOR_OP_PP, SNOR_PROTO_1_1_1);
-+
-+	if (info->flags & SPI_NOR_QUAD_READ) {
-+		params->hwcaps.mask |= SNOR_HWCAPS_PP_1_1_4;
-+		spi_nor_set_pp_settings(&params->page_programs[SNOR_CMD_PP_1_1_4],
-+					SPINOR_OP_PP_1_1_4, SNOR_PROTO_1_1_4);
-+	}
-+
-+	/* Select the procedure to set the Quad Enable bit. */
-+	if (params->hwcaps.mask & (SNOR_HWCAPS_READ_QUAD |
-+				   SNOR_HWCAPS_PP_QUAD)) {
-+		switch (JEDEC_MFR(info)) {
-+#ifdef CONFIG_SPI_FLASH_MACRONIX
-+		case SNOR_MFR_MACRONIX:
-+			params->quad_enable = macronix_quad_enable;
-+			break;
-+#endif
-+		case SNOR_MFR_ST:
-+		case SNOR_MFR_MICRON:
-+			break;
-+
-+		default:
-+#if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND)
-+			/* Kept only for backward compatibility purpose. */
-+			params->quad_enable = spansion_read_cr_quad_enable;
-+#endif
-+			break;
-+		}
-+	}
-+
-+	/* Override the parameters with data read from SFDP tables. */
-+	nor->addr_width = 0;
-+	nor->mtd.erasesize = 0;
-+	if ((info->flags & (SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)) &&
-+	    !(info->flags & SPI_NOR_SKIP_SFDP)) {
-+		struct spi_nor_flash_parameter sfdp_params;
-+
-+		memcpy(&sfdp_params, params, sizeof(sfdp_params));
-+		if (spi_nor_parse_sfdp(nor, &sfdp_params)) {
-+			nor->addr_width = 0;
-+			nor->mtd.erasesize = 0;
-+		} else {
-+			memcpy(params, &sfdp_params, sizeof(*params));
-+		}
-+	}
-+
-+	return 0;
-+}
-+
-+static int spi_nor_hwcaps2cmd(u32 hwcaps, const int table[][2], size_t size)
-+{
-+	size_t i;
-+
-+	for (i = 0; i < size; i++)
-+		if (table[i][0] == (int)hwcaps)
-+			return table[i][1];
-+
-+	return -EINVAL;
-+}
-+
-+static int spi_nor_hwcaps_read2cmd(u32 hwcaps)
-+{
-+	static const int hwcaps_read2cmd[][2] = {
-+		{ SNOR_HWCAPS_READ,		SNOR_CMD_READ },
-+		{ SNOR_HWCAPS_READ_FAST,	SNOR_CMD_READ_FAST },
-+		{ SNOR_HWCAPS_READ_1_1_1_DTR,	SNOR_CMD_READ_1_1_1_DTR },
-+		{ SNOR_HWCAPS_READ_1_1_2,	SNOR_CMD_READ_1_1_2 },
-+		{ SNOR_HWCAPS_READ_1_2_2,	SNOR_CMD_READ_1_2_2 },
-+		{ SNOR_HWCAPS_READ_2_2_2,	SNOR_CMD_READ_2_2_2 },
-+		{ SNOR_HWCAPS_READ_1_2_2_DTR,	SNOR_CMD_READ_1_2_2_DTR },
-+		{ SNOR_HWCAPS_READ_1_1_4,	SNOR_CMD_READ_1_1_4 },
-+		{ SNOR_HWCAPS_READ_1_4_4,	SNOR_CMD_READ_1_4_4 },
-+		{ SNOR_HWCAPS_READ_4_4_4,	SNOR_CMD_READ_4_4_4 },
-+		{ SNOR_HWCAPS_READ_1_4_4_DTR,	SNOR_CMD_READ_1_4_4_DTR },
-+		{ SNOR_HWCAPS_READ_1_1_8,	SNOR_CMD_READ_1_1_8 },
-+		{ SNOR_HWCAPS_READ_1_8_8,	SNOR_CMD_READ_1_8_8 },
-+		{ SNOR_HWCAPS_READ_8_8_8,	SNOR_CMD_READ_8_8_8 },
-+		{ SNOR_HWCAPS_READ_1_8_8_DTR,	SNOR_CMD_READ_1_8_8_DTR },
-+	};
-+
-+	return spi_nor_hwcaps2cmd(hwcaps, hwcaps_read2cmd,
-+				  ARRAY_SIZE(hwcaps_read2cmd));
-+}
-+
-+static int spi_nor_hwcaps_pp2cmd(u32 hwcaps)
-+{
-+	static const int hwcaps_pp2cmd[][2] = {
-+		{ SNOR_HWCAPS_PP,		SNOR_CMD_PP },
-+		{ SNOR_HWCAPS_PP_1_1_4,		SNOR_CMD_PP_1_1_4 },
-+		{ SNOR_HWCAPS_PP_1_4_4,		SNOR_CMD_PP_1_4_4 },
-+		{ SNOR_HWCAPS_PP_4_4_4,		SNOR_CMD_PP_4_4_4 },
-+		{ SNOR_HWCAPS_PP_1_1_8,		SNOR_CMD_PP_1_1_8 },
-+		{ SNOR_HWCAPS_PP_1_8_8,		SNOR_CMD_PP_1_8_8 },
-+		{ SNOR_HWCAPS_PP_8_8_8,		SNOR_CMD_PP_8_8_8 },
-+	};
-+
-+	return spi_nor_hwcaps2cmd(hwcaps, hwcaps_pp2cmd,
-+				  ARRAY_SIZE(hwcaps_pp2cmd));
-+}
-+
-+static int spi_nor_select_read(struct spi_nor *nor,
-+			       const struct spi_nor_flash_parameter *params,
-+			       u32 shared_hwcaps)
-+{
-+	int cmd, best_match = fls(shared_hwcaps & SNOR_HWCAPS_READ_MASK) - 1;
-+	const struct spi_nor_read_command *read;
-+
-+	if (best_match < 0)
-+		return -EINVAL;
-+
-+	cmd = spi_nor_hwcaps_read2cmd(BIT(best_match));
-+	if (cmd < 0)
-+		return -EINVAL;
-+
-+	read = &params->reads[cmd];
-+	nor->read_opcode = read->opcode;
-+	nor->read_proto = read->proto;
-+
-+	/*
-+	 * In the spi-nor framework, we don't need to make the difference
-+	 * between mode clock cycles and wait state clock cycles.
-+	 * Indeed, the value of the mode clock cycles is used by a QSPI
-+	 * flash memory to know whether it should enter or leave its 0-4-4
-+	 * (Continuous Read / XIP) mode.
-+	 * eXecution In Place is out of the scope of the mtd sub-system.
-+	 * Hence we choose to merge both mode and wait state clock cycles
-+	 * into the so called dummy clock cycles.
-+	 */
-+	nor->read_dummy = read->num_mode_clocks + read->num_wait_states;
-+	return 0;
-+}
-+
-+static int spi_nor_select_pp(struct spi_nor *nor,
-+			     const struct spi_nor_flash_parameter *params,
-+			     u32 shared_hwcaps)
-+{
-+	int cmd, best_match = fls(shared_hwcaps & SNOR_HWCAPS_PP_MASK) - 1;
-+	const struct spi_nor_pp_command *pp;
-+
-+	if (best_match < 0)
-+		return -EINVAL;
-+
-+	cmd = spi_nor_hwcaps_pp2cmd(BIT(best_match));
-+	if (cmd < 0)
-+		return -EINVAL;
-+
-+	pp = &params->page_programs[cmd];
-+	nor->program_opcode = pp->opcode;
-+	nor->write_proto = pp->proto;
-+	return 0;
-+}
-+
-+static int spi_nor_select_erase(struct spi_nor *nor,
-+				const struct flash_info *info)
-+{
-+	struct mtd_info *mtd = &nor->mtd;
-+
-+	/* Do nothing if already configured from SFDP. */
-+	if (mtd->erasesize)
-+		return 0;
-+
-+#ifdef CONFIG_SPI_FLASH_USE_4K_SECTORS
-+	/* prefer "small sector" erase if possible */
-+	if (info->flags & SECT_4K) {
-+		nor->erase_opcode = SPINOR_OP_BE_4K;
-+		mtd->erasesize = 4096;
-+	} else if (info->flags & SECT_4K_PMC) {
-+		nor->erase_opcode = SPINOR_OP_BE_4K_PMC;
-+		mtd->erasesize = 4096;
-+	} else
-+#endif
-+	{
-+		nor->erase_opcode = SPINOR_OP_SE;
-+		mtd->erasesize = info->sector_size;
-+	}
-+	return 0;
-+}
-+
-+static int spi_nor_setup(struct spi_nor *nor, const struct flash_info *info,
-+			 const struct spi_nor_flash_parameter *params,
-+			 const struct spi_nor_hwcaps *hwcaps)
-+{
-+	u32 ignored_mask, shared_mask;
-+	bool enable_quad_io;
-+	int err;
-+
-+	/*
-+	 * Keep only the hardware capabilities supported by both the SPI
-+	 * controller and the SPI flash memory.
-+	 */
-+	shared_mask = hwcaps->mask & params->hwcaps.mask;
-+
-+	/* SPI n-n-n protocols are not supported yet. */
-+	ignored_mask = (SNOR_HWCAPS_READ_2_2_2 |
-+			SNOR_HWCAPS_READ_4_4_4 |
-+			SNOR_HWCAPS_READ_8_8_8 |
-+			SNOR_HWCAPS_PP_4_4_4 |
-+			SNOR_HWCAPS_PP_8_8_8);
-+	if (shared_mask & ignored_mask) {
-+		dev_dbg(nor->dev,
-+			"SPI n-n-n protocols are not supported yet.\n");
-+		shared_mask &= ~ignored_mask;
-+	}
-+
-+	/* Select the (Fast) Read command. */
-+	err = spi_nor_select_read(nor, params, shared_mask);
-+	if (err) {
-+		dev_dbg(nor->dev,
-+			"can't select read settings supported by both the SPI controller and memory.\n");
-+		return err;
-+	}
-+
-+	/* Select the Page Program command. */
-+	err = spi_nor_select_pp(nor, params, shared_mask);
-+	if (err) {
-+		dev_dbg(nor->dev,
-+			"can't select write settings supported by both the SPI controller and memory.\n");
-+		return err;
-+	}
-+
-+	/* Select the Sector Erase command. */
-+	err = spi_nor_select_erase(nor, info);
-+	if (err) {
-+		dev_dbg(nor->dev,
-+			"can't select erase settings supported by both the SPI controller and memory.\n");
-+		return err;
-+	}
-+
-+	/* Enable Quad I/O if needed. */
-+	enable_quad_io = (spi_nor_get_protocol_width(nor->read_proto) == 4 ||
-+			  spi_nor_get_protocol_width(nor->write_proto) == 4);
-+	if (enable_quad_io && params->quad_enable)
-+		nor->quad_enable = params->quad_enable;
-+	else
-+		nor->quad_enable = NULL;
-+
-+	return 0;
-+}
-+
-+static int spi_nor_init(struct spi_nor *nor)
-+{
-+	int err;
-+
-+	/*
-+	 * Atmel, SST, Intel/Numonyx, and others serial NOR tend to power up
-+	 * with the software protection bits set
-+	 */
-+	if (JEDEC_MFR(nor->info) == SNOR_MFR_ATMEL ||
-+	    JEDEC_MFR(nor->info) == SNOR_MFR_INTEL ||
-+	    JEDEC_MFR(nor->info) == SNOR_MFR_SST ||
-+	    nor->info->flags & SPI_NOR_HAS_LOCK) {
-+		write_enable(nor);
-+		write_sr(nor, 0);
-+		spi_nor_wait_till_ready(nor);
-+	}
-+
-+	if (nor->quad_enable) {
-+		err = nor->quad_enable(nor);
-+		if (err) {
-+			dev_dbg(nor->dev, "quad mode not supported\n");
-+			return err;
-+		}
-+	}
-+
-+	if (nor->addr_width == 4 &&
-+	    (JEDEC_MFR(nor->info) != SNOR_MFR_SPANSION) &&
-+	    !(nor->info->flags & SPI_NOR_4B_OPCODES)) {
-+		/*
-+		 * If the RESET# pin isn't hooked up properly, or the system
-+		 * otherwise doesn't perform a reset command in the boot
-+		 * sequence, it's impossible to 100% protect against unexpected
-+		 * reboots (e.g., crashes). Warn the user (or hopefully, system
-+		 * designer) that this is bad.
-+		 */
-+		if (nor->flags & SNOR_F_BROKEN_RESET)
-+			printf("enabling reset hack; may not recover from unexpected reboots\n");
-+		set_4byte(nor, nor->info, 1);
-+	}
-+
-+	return 0;
-+}
-+
-+int spi_nor_scan(struct spi_nor *nor)
-+{
-+	struct spi_nor_flash_parameter params;
-+	const struct flash_info *info = NULL;
-+	struct mtd_info *mtd = &nor->mtd;
-+	struct spi_nor_hwcaps hwcaps = {
-+		.mask = SNOR_HWCAPS_READ |
-+			SNOR_HWCAPS_READ_FAST |
-+			SNOR_HWCAPS_PP,
-+	};
-+	struct spi_slave *spi = nor->spi;
-+	int 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;
-+	nor->read = spi_nor_read_data;
-+	nor->write = spi_nor_write_data;
-+	nor->read_reg = spi_nor_read_reg;
-+	nor->write_reg = spi_nor_write_reg;
-+
-+	if (spi->mode & SPI_RX_QUAD) {
-+		hwcaps.mask |= SNOR_HWCAPS_READ_1_1_4;
-+
-+		if (spi->mode & SPI_TX_QUAD)
-+			hwcaps.mask |= (SNOR_HWCAPS_READ_1_4_4 |
-+					SNOR_HWCAPS_PP_1_1_4 |
-+					SNOR_HWCAPS_PP_1_4_4);
-+	} else if (spi->mode & SPI_RX_DUAL) {
-+		hwcaps.mask |= SNOR_HWCAPS_READ_1_1_2;
-+
-+		if (spi->mode & SPI_TX_DUAL)
-+			hwcaps.mask |= SNOR_HWCAPS_READ_1_2_2;
-+	}
-+
-+	info = spi_nor_read_id(nor);
-+	if (IS_ERR_OR_NULL(info))
-+		return -ENOENT;
-+	/* Parse the Serial Flash Discoverable Parameters table. */
-+	ret = spi_nor_init_params(nor, info, &params);
-+	if (ret)
-+		return ret;
-+
-+	if (!mtd->name)
-+		mtd->name = info->name;
-+	mtd->priv = nor;
-+	mtd->type = MTD_NORFLASH;
-+	mtd->writesize = 1;
-+	mtd->flags = MTD_CAP_NORFLASH;
-+	mtd->size = params.size;
-+	mtd->_erase = spi_nor_erase;
-+	mtd->_read = spi_nor_read;
-+
-+#if defined(CONFIG_SPI_FLASH_STMICRO) || defined(CONFIG_SPI_FLASH_SST)
-+	/* NOR protection support for STmicro/Micron chips and similar */
-+	if (JEDEC_MFR(info) == SNOR_MFR_ST ||
-+	    JEDEC_MFR(info) == SNOR_MFR_MICRON ||
-+	    JEDEC_MFR(info) == SNOR_MFR_SST ||
-+			info->flags & SPI_NOR_HAS_LOCK) {
-+		nor->flash_lock = stm_lock;
-+		nor->flash_unlock = stm_unlock;
-+		nor->flash_is_locked = stm_is_locked;
-+	}
-+#endif
-+
-+#ifdef CONFIG_SPI_FLASH_SST
-+	/* sst nor chips use AAI word program */
-+	if (info->flags & SST_WRITE)
-+		mtd->_write = sst_write;
-+	else
-+#endif
-+		mtd->_write = spi_nor_write;
-+
-+	if (info->flags & USE_FSR)
-+		nor->flags |= SNOR_F_USE_FSR;
-+	if (info->flags & SPI_NOR_HAS_TB)
-+		nor->flags |= SNOR_F_HAS_SR_TB;
-+	if (info->flags & NO_CHIP_ERASE)
-+		nor->flags |= SNOR_F_NO_OP_CHIP_ERASE;
-+	if (info->flags & USE_CLSR)
-+		nor->flags |= SNOR_F_USE_CLSR;
-+
-+	if (info->flags & SPI_NOR_NO_ERASE)
-+		mtd->flags |= MTD_NO_ERASE;
-+
-+	nor->page_size = params.page_size;
-+	mtd->writebufsize = nor->page_size;
-+
-+	/* Some devices cannot do fast-read, no matter what DT tells us */
-+	if ((info->flags & SPI_NOR_NO_FR) || (spi->mode & SPI_RX_SLOW))
-+		params.hwcaps.mask &= ~SNOR_HWCAPS_READ_FAST;
-+
-+	/*
-+	 * 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, &hwcaps);
-+	if (ret)
-+		return ret;
-+
-+	if (nor->addr_width) {
-+		/* already configured from SFDP */
-+	} else if (info->addr_width) {
-+		nor->addr_width = info->addr_width;
-+	} else if (mtd->size > SZ_16M) {
-+#ifndef CONFIG_SPI_FLASH_BAR
-+		/* enable 4-byte addressing if the device exceeds 16MiB */
-+		nor->addr_width = 4;
-+		if (JEDEC_MFR(info) == SNOR_MFR_SPANSION ||
-+		    info->flags & SPI_NOR_4B_OPCODES)
-+			spi_nor_set_4byte_opcodes(nor, info);
-+#else
-+	/* Configure the BAR - discover bank cmds and read current bank */
-+	nor->addr_width = 3;
-+	ret = read_bar(nor, info);
-+	if (ret < 0)
-+		return ret;
-+#endif
-+	} else {
-+		nor->addr_width = 3;
-+	}
-+
-+	if (nor->addr_width > SPI_NOR_MAX_ADDR_WIDTH) {
-+		dev_dbg(dev, "address width is too large: %u\n",
-+			nor->addr_width);
-+		return -EINVAL;
-+	}
-+
-+	/* Send all the required SPI flash commands to initialize device */
-+	nor->info = info;
-+	ret = spi_nor_init(nor);
-+	if (ret)
-+		return ret;
-+
-+	nor->name = mtd->name;
-+	nor->size = mtd->size;
-+	nor->erase_size = mtd->erasesize;
-+	nor->sector_size = mtd->erasesize;
-+
-+#ifndef CONFIG_SPL_BUILD
-+	printf("SF: Detected %s with page size ", nor->name);
-+	print_size(nor->page_size, ", erase size ");
-+	print_size(nor->erase_size, ", total ");
-+	print_size(nor->size, "");
-+	puts("\n");
-+#endif
-+
-+	return 0;
-+}
-+
-+/* U-Boot specific functions, need to extend MTD to support these */
-+int spi_flash_cmd_get_sw_write_prot(struct spi_nor *nor)
-+{
-+	int sr = read_sr(nor);
-+
-+	if (sr < 0)
-+		return sr;
-+
-+	return (sr >> 2) & 7;
-+}
-diff --git a/drivers/mtd/spi/spi-nor-ids.c b/drivers/mtd/spi/spi-nor-ids.c
-new file mode 100644
-index 0000000000..e3620500f7
---- /dev/null
-+++ b/drivers/mtd/spi/spi-nor-ids.c
-@@ -0,0 +1,305 @@
-+// SPDX-License-Identifier: GPL-2.0+
-+/*
-+ *
-+ * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc.
-+ * Copyright (C) 2016 Jagan Teki <jagan@openedev.com>
-+ * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
-+ */
-+
-+#include <common.h>
-+#include <spi.h>
-+#include <spi_flash.h>
-+
-+#include "sf_internal.h"
-+
-+/* Exclude chip names for SPL to save space */
-+#if !CONFIG_IS_ENABLED(SPI_FLASH_TINY)
-+#define INFO_NAME(_name) .name = _name,
-+#else
-+#define INFO_NAME(_name)
-+#endif
-+
-+/* Used when the "_ext_id" is two bytes at most */
-+#define INFO(_name, _jedec_id, _ext_id, _sector_size, _n_sectors, _flags)	\
-+		INFO_NAME(_name)					\
-+		.id = {							\
-+			((_jedec_id) >> 16) & 0xff,			\
-+			((_jedec_id) >> 8) & 0xff,			\
-+			(_jedec_id) & 0xff,				\
-+			((_ext_id) >> 8) & 0xff,			\
-+			(_ext_id) & 0xff,				\
-+			},						\
-+		.id_len = (!(_jedec_id) ? 0 : (3 + ((_ext_id) ? 2 : 0))),	\
-+		.sector_size = (_sector_size),				\
-+		.n_sectors = (_n_sectors),				\
-+		.page_size = 256,					\
-+		.flags = (_flags),
-+
-+#define INFO6(_name, _jedec_id, _ext_id, _sector_size, _n_sectors, _flags)	\
-+		INFO_NAME(_name)					\
-+		.id = {							\
-+			((_jedec_id) >> 16) & 0xff,			\
-+			((_jedec_id) >> 8) & 0xff,			\
-+			(_jedec_id) & 0xff,				\
-+			((_ext_id) >> 16) & 0xff,			\
-+			((_ext_id) >> 8) & 0xff,			\
-+			(_ext_id) & 0xff,				\
-+			},						\
-+		.id_len = 6,						\
-+		.sector_size = (_sector_size),				\
-+		.n_sectors = (_n_sectors),				\
-+		.page_size = 256,					\
-+		.flags = (_flags),
-+
-+/* NOTE: double check command sets and memory organization when you add
-+ * more nor chips.  This current list focusses on newer chips, which
-+ * have been converging on command sets which including JEDEC ID.
-+ *
-+ * All newly added entries should describe *hardware* and should use SECT_4K
-+ * (or SECT_4K_PMC) if hardware supports erasing 4 KiB sectors. For usage
-+ * scenarios excluding small sectors there is config option that can be
-+ * disabled: CONFIG_MTD_SPI_NOR_USE_4K_SECTORS.
-+ * For historical (and compatibility) reasons (before we got above config) some
-+ * old entries may be missing 4K flag.
-+ */
-+const struct flash_info spi_nor_ids[] = {
-+#ifdef CONFIG_SPI_FLASH_ATMEL		/* ATMEL */
-+	/* Atmel -- some are (confusingly) marketed as "DataFlash" */
-+	{ INFO("at26df321",	0x1f4700, 0, 64 * 1024, 64, SECT_4K) },
-+	{ INFO("at25df321a",	0x1f4701, 0, 64 * 1024, 64, SECT_4K) },
-+
-+	{ INFO("at45db011d",	0x1f2200, 0, 64 * 1024,   4, SECT_4K) },
-+	{ INFO("at45db021d",	0x1f2300, 0, 64 * 1024,   8, SECT_4K) },
-+	{ INFO("at45db041d",	0x1f2400, 0, 64 * 1024,   8, SECT_4K) },
-+	{ INFO("at45db081d",	0x1f2500, 0, 64 * 1024,  16, SECT_4K) },
-+	{ INFO("at45db161d",	0x1f2600, 0, 64 * 1024,  32, SECT_4K) },
-+	{ INFO("at45db321d",	0x1f2700, 0, 64 * 1024,  64, SECT_4K) },
-+	{ INFO("at45db641d",	0x1f2800, 0, 64 * 1024, 128, SECT_4K) },
-+	{ INFO("at26df081a", 	0x1f4501, 0, 64 * 1024,  16, SECT_4K) },
-+#endif
-+#ifdef CONFIG_SPI_FLASH_EON		/* EON */
-+	/* EON -- en25xxx */
-+	{ INFO("en25q32b",   0x1c3016, 0, 64 * 1024,   64, 0) },
-+	{ INFO("en25q64",    0x1c3017, 0, 64 * 1024,  128, SECT_4K) },
-+	{ INFO("en25qh128",  0x1c7018, 0, 64 * 1024,  256, 0) },
-+	{ INFO("en25s64",    0x1c3817, 0, 64 * 1024,  128, SECT_4K) },
-+#endif
-+#ifdef CONFIG_SPI_FLASH_GIGADEVICE	/* GIGADEVICE */
-+	/* GigaDevice */
-+	{
-+		INFO("gd25q16", 0xc84015, 0, 64 * 1024,  32,
-+			SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
-+			SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
-+	},
-+	{
-+		INFO("gd25q32", 0xc84016, 0, 64 * 1024,  64,
-+			SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
-+			SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
-+	},
-+	{
-+		INFO("gd25lq32", 0xc86016, 0, 64 * 1024, 64,
-+			SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
-+			SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
-+	},
-+	{
-+		INFO("gd25q64", 0xc84017, 0, 64 * 1024, 128,
-+			SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
-+			SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
-+	},
-+	{
-+		INFO("gd25lq128", 0xc86018, 0, 64 * 1024, 256,
-+			SECT_4K | SPI_NOR_DUAL_READ |
-+			SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
-+	},
-+#endif
-+#ifdef CONFIG_SPI_FLASH_ISSI		/* ISSI */
-+	/* ISSI */
-+	{ INFO("is25lq040b", 0x9d4013, 0, 64 * 1024,   8,
-+			SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
-+	{ INFO("is25lp032",	0x9d6016, 0, 64 * 1024,  64, 0) },
-+	{ INFO("is25lp064",	0x9d6017, 0, 64 * 1024, 128, 0) },
-+	{ INFO("is25lp128",  0x9d6018, 0, 64 * 1024, 256,
-+			SECT_4K | SPI_NOR_DUAL_READ) },
-+	{ INFO("is25lp256",  0x9d6019, 0, 64 * 1024, 512,
-+			SECT_4K | SPI_NOR_DUAL_READ) },
-+	{ INFO("is25wp032",  0x9d7016, 0, 64 * 1024,  64,
-+			SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
-+	{ INFO("is25wp064",  0x9d7017, 0, 64 * 1024, 128,
-+			SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
-+	{ INFO("is25wp128",  0x9d7018, 0, 64 * 1024, 256,
-+			SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
-+#endif
-+#ifdef CONFIG_SPI_FLASH_MACRONIX	/* MACRONIX */
-+	/* Macronix */
-+	{ INFO("mx25l2005a",  0xc22012, 0, 64 * 1024,   4, SECT_4K) },
-+	{ INFO("mx25l4005a",  0xc22013, 0, 64 * 1024,   8, SECT_4K) },
-+	{ INFO("mx25l8005",   0xc22014, 0, 64 * 1024,  16, 0) },
-+	{ INFO("mx25l1606e",  0xc22015, 0, 64 * 1024,  32, SECT_4K) },
-+	{ INFO("mx25l3205d",  0xc22016, 0, 64 * 1024,  64, SECT_4K) },
-+	{ INFO("mx25l6405d",  0xc22017, 0, 64 * 1024, 128, SECT_4K) },
-+	{ INFO("mx25u2033e",  0xc22532, 0, 64 * 1024,   4, SECT_4K) },
-+	{ INFO("mx25u1635e",  0xc22535, 0, 64 * 1024,  32, SECT_4K) },
-+	{ INFO("mx25u6435f",  0xc22537, 0, 64 * 1024, 128, SECT_4K) },
-+	{ INFO("mx25l12805d", 0xc22018, 0, 64 * 1024, 256, 0) },
-+	{ INFO("mx25l12855e", 0xc22618, 0, 64 * 1024, 256, 0) },
-+	{ INFO("mx25l25635e", 0xc22019, 0, 64 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
-+	{ INFO("mx25u25635f", 0xc22539, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_4B_OPCODES) },
-+	{ INFO("mx25l25655e", 0xc22619, 0, 64 * 1024, 512, 0) },
-+	{ INFO("mx66l51235l", 0xc2201a, 0, 64 * 1024, 1024, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
-+	{ INFO("mx66u51235f", 0xc2253a, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
-+	{ INFO("mx66u2g45g",  0xc2253c, 0, 64 * 1024, 4096, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
-+	{ INFO("mx66l1g45g",  0xc2201b, 0, 64 * 1024, 2048, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
-+	{ INFO("mx25l1633e",  0xc22415, 0, 64 * 1024,   32, SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES | SECT_4K) },
-+	{ INFO("mx25r1635f",  0xc22815, 0, 64 * 1024,   32, SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
-+#endif
-+
-+#ifdef CONFIG_SPI_FLASH_STMICRO		/* STMICRO */
-+	/* Micron */
-+	{ INFO("n25q016a",	 0x20bb15, 0, 64 * 1024,   32, SECT_4K | SPI_NOR_QUAD_READ) },
-+	{ INFO("n25q032",	 0x20ba16, 0, 64 * 1024,   64, SPI_NOR_QUAD_READ) },
-+	{ INFO("n25q032a",	0x20bb16, 0, 64 * 1024,   64, SPI_NOR_QUAD_READ) },
-+	{ INFO("n25q064",     0x20ba17, 0, 64 * 1024,  128, SECT_4K | SPI_NOR_QUAD_READ) },
-+	{ INFO("n25q064a",    0x20bb17, 0, 64 * 1024,  128, SECT_4K | SPI_NOR_QUAD_READ) },
-+	{ INFO("n25q128a11",  0x20bb18, 0, 64 * 1024,  256, SECT_4K | SPI_NOR_QUAD_READ) },
-+	{ INFO("n25q128a13",  0x20ba18, 0, 64 * 1024,  256, SECT_4K | SPI_NOR_QUAD_READ) },
-+	{ INFO("n25q256a",    0x20ba19, 0, 64 * 1024,  512, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
-+	{ INFO("n25q256ax1",  0x20bb19, 0, 64 * 1024,  512, SECT_4K | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
-+	{ INFO("n25q512a",    0x20bb20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
-+	{ INFO("n25q512ax3",  0x20ba20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
-+	{ INFO("n25q00",      0x20ba21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) },
-+	{ INFO("n25q00a",     0x20bb21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) },
-+	{ INFO("mt25qu02g",   0x20bb22, 0, 64 * 1024, 4096, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) },
-+#endif
-+#ifdef CONFIG_SPI_FLASH_SPANSION	/* SPANSION */
-+	/* Spansion/Cypress -- single (large) sector size only, at least
-+	 * for the chips listed here (without boot sectors).
-+	 */
-+	{ INFO("s25sl032p",  0x010215, 0x4d00,  64 * 1024,  64, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
-+	{ INFO("s25sl064p",  0x010216, 0x4d00,  64 * 1024, 128, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
-+	{ INFO("s25fl256s0", 0x010219, 0x4d00, 256 * 1024, 128, USE_CLSR) },
-+	{ INFO("s25fl256s1", 0x010219, 0x4d01,  64 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) },
-+	{ INFO6("s25fl512s",  0x010220, 0x4d0081, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) },
-+	{ INFO("s25fl512s_256k",  0x010220, 0x4d00, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) },
-+	{ INFO("s25fl512s_64k",  0x010220, 0x4d01, 64 * 1024, 1024, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) },
-+	{ INFO("s25fl512s_512k", 0x010220, 0x4f00, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) },
-+	{ INFO("s25sl12800", 0x012018, 0x0300, 256 * 1024,  64, 0) },
-+	{ INFO("s25sl12801", 0x012018, 0x0301,  64 * 1024, 256, 0) },
-+	{ INFO6("s25fl128s",  0x012018, 0x4d0180, 64 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) },
-+	{ INFO("s25fl129p0", 0x012018, 0x4d00, 256 * 1024,  64, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) },
-+	{ INFO("s25fl129p1", 0x012018, 0x4d01,  64 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) },
-+	{ INFO("s25sl008a",  0x010213,      0,  64 * 1024,  16, 0) },
-+	{ INFO("s25sl016a",  0x010214,      0,  64 * 1024,  32, 0) },
-+	{ INFO("s25sl032a",  0x010215,      0,  64 * 1024,  64, 0) },
-+	{ INFO("s25sl064a",  0x010216,      0,  64 * 1024, 128, 0) },
-+	{ INFO("s25fl116k",  0x014015,      0,  64 * 1024,  32, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
-+	{ INFO("s25fl164k",  0x014017,      0,  64 * 1024, 128, SECT_4K) },
-+	{ INFO("s25fl208k",  0x014014,      0,  64 * 1024,  16, SECT_4K | SPI_NOR_DUAL_READ) },
-+	{ INFO("s25fl064l",  0x016017,      0,  64 * 1024, 128, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
-+	{ INFO("s25fl128l",  0x016018,      0,  64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
-+#endif
-+#ifdef CONFIG_SPI_FLASH_SST		/* SST */
-+	/* SST -- large erase sizes are "overlays", "sectors" are 4K */
-+	{ INFO("sst25vf040b", 0xbf258d, 0, 64 * 1024,  8, SECT_4K | SST_WRITE) },
-+	{ INFO("sst25vf080b", 0xbf258e, 0, 64 * 1024, 16, SECT_4K | SST_WRITE) },
-+	{ INFO("sst25vf016b", 0xbf2541, 0, 64 * 1024, 32, SECT_4K | SST_WRITE) },
-+	{ INFO("sst25vf032b", 0xbf254a, 0, 64 * 1024, 64, SECT_4K | SST_WRITE) },
-+	{ INFO("sst25vf064c", 0xbf254b, 0, 64 * 1024, 128, SECT_4K) },
-+	{ INFO("sst25wf512",  0xbf2501, 0, 64 * 1024,  1, SECT_4K | SST_WRITE) },
-+	{ INFO("sst25wf010",  0xbf2502, 0, 64 * 1024,  2, SECT_4K | SST_WRITE) },
-+	{ INFO("sst25wf020",  0xbf2503, 0, 64 * 1024,  4, SECT_4K | SST_WRITE) },
-+	{ INFO("sst25wf020a", 0x621612, 0, 64 * 1024,  4, SECT_4K) },
-+	{ INFO("sst25wf040b", 0x621613, 0, 64 * 1024,  8, SECT_4K) },
-+	{ INFO("sst25wf040",  0xbf2504, 0, 64 * 1024,  8, SECT_4K | SST_WRITE) },
-+	{ INFO("sst25wf080",  0xbf2505, 0, 64 * 1024, 16, SECT_4K | SST_WRITE) },
-+	{ INFO("sst26vf064b", 0xbf2643, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
-+	{ INFO("sst26wf016",  0xbf2651, 0, 64 * 1024,  32, SECT_4K) },
-+	{ INFO("sst26wf032",  0xbf2622, 0, 64 * 1024,  64, SECT_4K) },
-+	{ INFO("sst26wf064",  0xbf2643, 0, 64 * 1024, 128, SECT_4K) },
-+#endif
-+#ifdef CONFIG_SPI_FLASH_STMICRO		/* STMICRO */
-+	/* ST Microelectronics -- newer production may have feature updates */
-+	{ INFO("m25p10",  0x202011,  0,  32 * 1024,   4, 0) },
-+	{ INFO("m25p20",  0x202012,  0,  64 * 1024,   4, 0) },
-+	{ INFO("m25p40",  0x202013,  0,  64 * 1024,   8, 0) },
-+	{ INFO("m25p80",  0x202014,  0,  64 * 1024,  16, 0) },
-+	{ INFO("m25p16",  0x202015,  0,  64 * 1024,  32, 0) },
-+	{ INFO("m25p32",  0x202016,  0,  64 * 1024,  64, 0) },
-+	{ INFO("m25p64",  0x202017,  0,  64 * 1024, 128, 0) },
-+	{ INFO("m25p128", 0x202018,  0, 256 * 1024,  64, 0) },
-+	{ INFO("m25pe16", 0x208015,  0, 64 * 1024, 32, SECT_4K) },
-+	{ INFO("m25px16",    0x207115,  0, 64 * 1024, 32, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
-+	{ INFO("m25px64",    0x207117,  0, 64 * 1024, 128, 0) },
-+#endif
-+#ifdef CONFIG_SPI_FLASH_WINBOND		/* WINBOND */
-+	/* Winbond -- w25x "blocks" are 64K, "sectors" are 4KiB */
-+	{ INFO("w25p80", 0xef2014, 0x0,	64 * 1024,    16, 0) },
-+	{ INFO("w25p16", 0xef2015, 0x0,	64 * 1024,    32, 0) },
-+	{ INFO("w25p32", 0xef2016, 0x0,	64 * 1024,    64, 0) },
-+	{ INFO("w25x05", 0xef3010, 0, 64 * 1024,  1,  SECT_4K) },
-+	{ INFO("w25x40", 0xef3013, 0, 64 * 1024,  8,  SECT_4K) },
-+	{ INFO("w25x16", 0xef3015, 0, 64 * 1024,  32, SECT_4K) },
-+	{
-+		INFO("w25q16dw", 0xef6015, 0, 64 * 1024,  32,
-+			SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
-+			SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
-+	},
-+	{ INFO("w25x32", 0xef3016, 0, 64 * 1024,  64, SECT_4K) },
-+	{ INFO("w25q20cl", 0xef4012, 0, 64 * 1024,  4, SECT_4K) },
-+	{ INFO("w25q20bw", 0xef5012, 0, 64 * 1024,  4, SECT_4K) },
-+	{ INFO("w25q20ew", 0xef6012, 0, 64 * 1024,  4, SECT_4K) },
-+	{ INFO("w25q32", 0xef4016, 0, 64 * 1024,  64, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
-+	{
-+		INFO("w25q32dw", 0xef6016, 0, 64 * 1024,  64,
-+			SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
-+			SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
-+	},
-+	{
-+		INFO("w25q32jv", 0xef7016, 0, 64 * 1024,  64,
-+			SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
-+			SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
-+	},
-+	{ INFO("w25x64", 0xef3017, 0, 64 * 1024, 128, SECT_4K) },
-+	{
-+		INFO("w25q64dw", 0xef6017, 0, 64 * 1024, 128,
-+			SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
-+			SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
-+	},
-+	{
-+		INFO("w25q64jv", 0xef7017, 0, 64 * 1024, 128,
-+			SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
-+			SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
-+	},
-+	{
-+		INFO("w25q128fw", 0xef6018, 0, 64 * 1024, 256,
-+			SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
-+			SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
-+	},
-+	{
-+		INFO("w25q128jv", 0xef7018, 0, 64 * 1024, 256,
-+			SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
-+			SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
-+	},
-+	{
-+		INFO("w25q256fw", 0xef6019, 0, 64 * 1024, 512,
-+			SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
-+			SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
-+	},
-+	{
-+		INFO("w25q256jw", 0xef7019, 0, 64 * 1024, 512,
-+			SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
-+			SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
-+	},
-+	{ INFO("w25q80", 0xef5014, 0, 64 * 1024,  16, SECT_4K) },
-+	{ INFO("w25q80bl", 0xef4014, 0, 64 * 1024,  16, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
-+	{ INFO("w25q16cl", 0xef4015, 0, 64 * 1024,  32, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
-+	{ INFO("w25q64cv", 0xef4017, 0, 64 * 1024,  128, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
-+	{ INFO("w25q128", 0xef4018, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
-+	{ INFO("w25q256", 0xef4019, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
-+#endif
-+#ifdef CONFIG_SPI_FLASH_XMC
-+	/* XMC (Wuhan Xinxin Semiconductor Manufacturing Corp.) */
-+	{ INFO("XM25QH64A", 0x207017, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
-+	{ INFO("XM25QH128A", 0x207018, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
-+#endif
-+	{ },
-+};
-diff --git a/drivers/mtd/spi/spi-nor-tiny.c b/drivers/mtd/spi/spi-nor-tiny.c
-new file mode 100644
-index 0000000000..c19d468d62
---- /dev/null
-+++ b/drivers/mtd/spi/spi-nor-tiny.c
-@@ -0,0 +1,804 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * Based on m25p80.c, by Mike Lavender (mike@steroidmicros.com), with
-+ * influence from lart.c (Abraham Van Der Merwe) and mtd_dataflash.c
-+ *
-+ * Copyright (C) 2005, Intec Automation Inc.
-+ * Copyright (C) 2014, Freescale Semiconductor, Inc.
-+ *
-+ * Synced from Linux v4.19
-+ */
-+
-+#include <common.h>
-+#include <linux/err.h>
-+#include <linux/errno.h>
-+#include <linux/log2.h>
-+#include <linux/math64.h>
-+#include <linux/sizes.h>
-+
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/spi-nor.h>
-+#include <spi-mem.h>
-+#include <spi.h>
-+
-+#include "sf_internal.h"
-+
-+/* Define max times to check status register before we give up. */
-+
-+/*
-+ * For everything but full-chip erase; probably could be much smaller, but kept
-+ * around for safety for now
-+ */
-+
-+#define HZ					CONFIG_SYS_HZ
-+
-+#define DEFAULT_READY_WAIT_JIFFIES		(40UL * HZ)
-+
-+static int spi_nor_read_write_reg(struct spi_nor *nor, struct spi_mem_op
-+		*op, void *buf)
-+{
-+	if (op->data.dir == SPI_MEM_DATA_IN)
-+		op->data.buf.in = buf;
-+	else
-+		op->data.buf.out = buf;
-+	return spi_mem_exec_op(nor->spi, op);
-+}
-+
-+static int spi_nor_read_reg(struct spi_nor *nor, u8 code, u8 *val, int len)
-+{
-+	struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(code, 1),
-+					  SPI_MEM_OP_NO_ADDR,
-+					  SPI_MEM_OP_NO_DUMMY,
-+					  SPI_MEM_OP_DATA_IN(len, NULL, 1));
-+	int ret;
-+
-+	ret = spi_nor_read_write_reg(nor, &op, val);
-+	if (ret < 0)
-+		dev_dbg(&flash->spimem->spi->dev, "error %d reading %x\n", ret,
-+			code);
-+
-+	return ret;
-+}
-+
-+static int spi_nor_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
-+{
-+	struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(opcode, 1),
-+					  SPI_MEM_OP_NO_ADDR,
-+					  SPI_MEM_OP_NO_DUMMY,
-+					  SPI_MEM_OP_DATA_OUT(len, NULL, 1));
-+
-+	return spi_nor_read_write_reg(nor, &op, buf);
-+}
-+
-+static ssize_t spi_nor_read_data(struct spi_nor *nor, loff_t from, size_t len,
-+				 u_char *buf)
-+{
-+	struct spi_mem_op op =
-+			SPI_MEM_OP(SPI_MEM_OP_CMD(nor->read_opcode, 1),
-+				   SPI_MEM_OP_ADDR(nor->addr_width, from, 1),
-+				   SPI_MEM_OP_DUMMY(nor->read_dummy, 1),
-+				   SPI_MEM_OP_DATA_IN(len, buf, 1));
-+	size_t remaining = len;
-+	int ret;
-+
-+	/* get transfer protocols. */
-+	op.cmd.buswidth = spi_nor_get_protocol_inst_nbits(nor->read_proto);
-+	op.addr.buswidth = spi_nor_get_protocol_addr_nbits(nor->read_proto);
-+	op.dummy.buswidth = op.addr.buswidth;
-+	op.data.buswidth = spi_nor_get_protocol_data_nbits(nor->read_proto);
-+
-+	/* convert the dummy cycles to the number of bytes */
-+	op.dummy.nbytes = (nor->read_dummy * op.dummy.buswidth) / 8;
-+
-+	while (remaining) {
-+		op.data.nbytes = remaining < UINT_MAX ? remaining : UINT_MAX;
-+		ret = spi_mem_adjust_op_size(nor->spi, &op);
-+		if (ret)
-+			return ret;
-+
-+		ret = spi_mem_exec_op(nor->spi, &op);
-+		if (ret)
-+			return ret;
-+
-+		op.addr.val += op.data.nbytes;
-+		remaining -= op.data.nbytes;
-+		op.data.buf.in += op.data.nbytes;
-+	}
-+
-+	return len;
-+}
-+
-+#if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND)
-+/*
-+ * Read configuration register, returning its value in the
-+ * location. Return the configuration register value.
-+ * Returns negative if error occurred.
-+ */
-+static int read_cr(struct spi_nor *nor)
-+{
-+	int ret;
-+	u8 val;
-+
-+	ret = spi_nor_read_reg(nor, SPINOR_OP_RDCR, &val, 1);
-+	if (ret < 0) {
-+		dev_dbg(nor->dev, "error %d reading CR\n", ret);
-+		return ret;
-+	}
-+
-+	return val;
-+}
-+#endif
-+
-+/*
-+ * Write status register 1 byte
-+ * Returns negative if error occurred.
-+ */
-+static inline int write_sr(struct spi_nor *nor, u8 val)
-+{
-+	nor->cmd_buf[0] = val;
-+	return spi_nor_write_reg(nor, SPINOR_OP_WRSR, nor->cmd_buf, 1);
-+}
-+
-+/*
-+ * Set write enable latch with Write Enable command.
-+ * Returns negative if error occurred.
-+ */
-+static inline int write_enable(struct spi_nor *nor)
-+{
-+	return spi_nor_write_reg(nor, SPINOR_OP_WREN, NULL, 0);
-+}
-+
-+/*
-+ * Send write disable instruction to the chip.
-+ */
-+static inline int write_disable(struct spi_nor *nor)
-+{
-+	return spi_nor_write_reg(nor, SPINOR_OP_WRDI, NULL, 0);
-+}
-+
-+static inline struct spi_nor *mtd_to_spi_nor(struct mtd_info *mtd)
-+{
-+	return mtd->priv;
-+}
-+
-+static u8 spi_nor_convert_opcode(u8 opcode, const u8 table[][2], size_t size)
-+{
-+	size_t i;
-+
-+	for (i = 0; i < size; i++)
-+		if (table[i][0] == opcode)
-+			return table[i][1];
-+
-+	/* No conversion found, keep input op code. */
-+	return opcode;
-+}
-+
-+static inline u8 spi_nor_convert_3to4_read(u8 opcode)
-+{
-+	static const u8 spi_nor_3to4_read[][2] = {
-+		{ SPINOR_OP_READ,	SPINOR_OP_READ_4B },
-+		{ SPINOR_OP_READ_FAST,	SPINOR_OP_READ_FAST_4B },
-+		{ SPINOR_OP_READ_1_1_2,	SPINOR_OP_READ_1_1_2_4B },
-+		{ SPINOR_OP_READ_1_2_2,	SPINOR_OP_READ_1_2_2_4B },
-+		{ SPINOR_OP_READ_1_1_4,	SPINOR_OP_READ_1_1_4_4B },
-+		{ SPINOR_OP_READ_1_4_4,	SPINOR_OP_READ_1_4_4_4B },
-+	};
-+
-+	return spi_nor_convert_opcode(opcode, spi_nor_3to4_read,
-+				      ARRAY_SIZE(spi_nor_3to4_read));
-+}
-+
-+static void spi_nor_set_4byte_opcodes(struct spi_nor *nor,
-+				      const struct flash_info *info)
-+{
-+	nor->read_opcode = spi_nor_convert_3to4_read(nor->read_opcode);
-+}
-+
-+/* Enable/disable 4-byte addressing mode. */
-+static inline int set_4byte(struct spi_nor *nor, const struct flash_info *info,
-+			    int enable)
-+{
-+	int status;
-+	bool need_wren = false;
-+	u8 cmd;
-+
-+	switch (JEDEC_MFR(info)) {
-+	case SNOR_MFR_ST:
-+	case SNOR_MFR_MICRON:
-+		/* Some Micron need WREN command; all will accept it */
-+		need_wren = true;
-+	case SNOR_MFR_MACRONIX:
-+	case SNOR_MFR_WINBOND:
-+		if (need_wren)
-+			write_enable(nor);
-+
-+		cmd = enable ? SPINOR_OP_EN4B : SPINOR_OP_EX4B;
-+		status = spi_nor_write_reg(nor, cmd, NULL, 0);
-+		if (need_wren)
-+			write_disable(nor);
-+
-+		if (!status && !enable &&
-+		    JEDEC_MFR(info) == SNOR_MFR_WINBOND) {
-+			/*
-+			 * On Winbond W25Q256FV, leaving 4byte mode causes
-+			 * the Extended Address Register to be set to 1, so all
-+			 * 3-byte-address reads come from the second 16M.
-+			 * We must clear the register to enable normal behavior.
-+			 */
-+			write_enable(nor);
-+			nor->cmd_buf[0] = 0;
-+			spi_nor_write_reg(nor, SPINOR_OP_WREAR,
-+					  nor->cmd_buf, 1);
-+			write_disable(nor);
-+		}
-+
-+		return status;
-+	default:
-+		/* Spansion style */
-+		nor->cmd_buf[0] = enable << 7;
-+		return spi_nor_write_reg(nor, SPINOR_OP_BRWR, nor->cmd_buf, 1);
-+	}
-+}
-+
-+#if defined(CONFIG_SPI_FLASH_SPANSION) ||	\
-+	defined(CONFIG_SPI_FLASH_WINBOND) ||	\
-+	defined(CONFIG_SPI_FLASH_MACRONIX)
-+/*
-+ * Read the status register, returning its value in the location
-+ * Return the status register value.
-+ * Returns negative if error occurred.
-+ */
-+static int read_sr(struct spi_nor *nor)
-+{
-+	int ret;
-+	u8 val;
-+
-+	ret = spi_nor_read_reg(nor, SPINOR_OP_RDSR, &val, 1);
-+	if (ret < 0) {
-+		pr_debug("error %d reading SR\n", (int)ret);
-+		return ret;
-+	}
-+
-+	return val;
-+}
-+
-+/*
-+ * Read the flag status register, returning its value in the location
-+ * Return the status register value.
-+ * Returns negative if error occurred.
-+ */
-+static int read_fsr(struct spi_nor *nor)
-+{
-+	int ret;
-+	u8 val;
-+
-+	ret = spi_nor_read_reg(nor, SPINOR_OP_RDFSR, &val, 1);
-+	if (ret < 0) {
-+		pr_debug("error %d reading FSR\n", ret);
-+		return ret;
-+	}
-+
-+	return val;
-+}
-+
-+static int spi_nor_sr_ready(struct spi_nor *nor)
-+{
-+	int sr = read_sr(nor);
-+
-+	if (sr < 0)
-+		return sr;
-+
-+	return !(sr & SR_WIP);
-+}
-+
-+static int spi_nor_fsr_ready(struct spi_nor *nor)
-+{
-+	int fsr = read_fsr(nor);
-+
-+	if (fsr < 0)
-+		return fsr;
-+	return fsr & FSR_READY;
-+}
-+
-+static int spi_nor_ready(struct spi_nor *nor)
-+{
-+	int sr, fsr;
-+
-+	sr = spi_nor_sr_ready(nor);
-+	if (sr < 0)
-+		return sr;
-+	fsr = nor->flags & SNOR_F_USE_FSR ? spi_nor_fsr_ready(nor) : 1;
-+	if (fsr < 0)
-+		return fsr;
-+	return sr && fsr;
-+}
-+
-+/*
-+ * Service routine to read status register until ready, or timeout occurs.
-+ * Returns non-zero if error.
-+ */
-+static int spi_nor_wait_till_ready_with_timeout(struct spi_nor *nor,
-+						unsigned long timeout)
-+{
-+	unsigned long timebase;
-+	int ret;
-+
-+	timebase = get_timer(0);
-+
-+	while (get_timer(timebase) < timeout) {
-+		ret = spi_nor_ready(nor);
-+		if (ret < 0)
-+			return ret;
-+		if (ret)
-+			return 0;
-+	}
-+
-+	dev_err(nor->dev, "flash operation timed out\n");
-+
-+	return -ETIMEDOUT;
-+}
-+
-+static int spi_nor_wait_till_ready(struct spi_nor *nor)
-+{
-+	return spi_nor_wait_till_ready_with_timeout(nor,
-+						    DEFAULT_READY_WAIT_JIFFIES);
-+}
-+#endif /* CONFIG_SPI_FLASH_SPANSION */
-+
-+/*
-+ * 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.
-+ */
-+static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
-+{
-+	return -ENOTSUPP;
-+}
-+
-+static const struct flash_info *spi_nor_read_id(struct spi_nor *nor)
-+{
-+	int			tmp;
-+	u8			id[SPI_NOR_MAX_ID_LEN];
-+	const struct flash_info	*info;
-+
-+	tmp = spi_nor_read_reg(nor, SPINOR_OP_RDID, id, SPI_NOR_MAX_ID_LEN);
-+	if (tmp < 0) {
-+		dev_dbg(nor->dev, "error %d reading JEDEC ID\n", tmp);
-+		return ERR_PTR(tmp);
-+	}
-+
-+	info = spi_nor_ids;
-+	for (; info->sector_size != 0; info++) {
-+		if (info->id_len) {
-+			if (!memcmp(info->id, id, info->id_len))
-+				return info;
-+		}
-+	}
-+	dev_dbg(nor->dev, "unrecognized JEDEC id bytes: %02x, %02x, %02x\n",
-+		id[0], id[1], id[2]);
-+	return ERR_PTR(-ENODEV);
-+}
-+
-+static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len,
-+			size_t *retlen, u_char *buf)
-+{
-+	struct spi_nor *nor = mtd_to_spi_nor(mtd);
-+	int ret;
-+
-+	dev_dbg(nor->dev, "from 0x%08x, len %zd\n", (u32)from, len);
-+
-+	while (len) {
-+		loff_t addr = from;
-+
-+		ret = spi_nor_read_data(nor, addr, len, buf);
-+		if (ret == 0) {
-+			/* We shouldn't see 0-length reads */
-+			ret = -EIO;
-+			goto read_err;
-+		}
-+		if (ret < 0)
-+			goto read_err;
-+
-+		*retlen += ret;
-+		buf += ret;
-+		from += ret;
-+		len -= ret;
-+	}
-+	ret = 0;
-+
-+read_err:
-+	return ret;
-+}
-+
-+/*
-+ * Write an address range to the nor chip.  Data must be written in
-+ * FLASH_PAGESIZE chunks.  The address range may be any size provided
-+ * it is within the physical boundaries.
-+ */
-+static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len,
-+			 size_t *retlen, const u_char *buf)
-+{
-+	return -ENOTSUPP;
-+}
-+
-+#ifdef CONFIG_SPI_FLASH_MACRONIX
-+/**
-+ * macronix_quad_enable() - set QE bit in Status Register.
-+ * @nor:	pointer to a 'struct spi_nor'
-+ *
-+ * Set the Quad Enable (QE) bit in the Status Register.
-+ *
-+ * bit 6 of the Status Register is the QE bit for Macronix like QSPI memories.
-+ *
-+ * Return: 0 on success, -errno otherwise.
-+ */
-+static int macronix_quad_enable(struct spi_nor *nor)
-+{
-+	int ret, val;
-+
-+	val = read_sr(nor);
-+	if (val < 0)
-+		return val;
-+	if (val & SR_QUAD_EN_MX)
-+		return 0;
-+
-+	write_enable(nor);
-+
-+	write_sr(nor, val | SR_QUAD_EN_MX);
-+
-+	ret = spi_nor_wait_till_ready(nor);
-+	if (ret)
-+		return ret;
-+
-+	ret = read_sr(nor);
-+	if (!(ret > 0 && (ret & SR_QUAD_EN_MX))) {
-+		dev_err(nor->dev, "Macronix Quad bit not set\n");
-+		return -EINVAL;
-+	}
-+
-+	return 0;
-+}
-+#endif
-+
-+#if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND)
-+/*
-+ * Write status Register and configuration register with 2 bytes
-+ * The first byte will be written to the status register, while the
-+ * second byte will be written to the configuration register.
-+ * Return negative if error occurred.
-+ */
-+static int write_sr_cr(struct spi_nor *nor, u8 *sr_cr)
-+{
-+	int ret;
-+
-+	write_enable(nor);
-+
-+	ret = spi_nor_write_reg(nor, SPINOR_OP_WRSR, sr_cr, 2);
-+	if (ret < 0) {
-+		dev_dbg(nor->dev,
-+			"error while writing configuration register\n");
-+		return -EINVAL;
-+	}
-+
-+	ret = spi_nor_wait_till_ready(nor);
-+	if (ret) {
-+		dev_dbg(nor->dev,
-+			"timeout while writing configuration register\n");
-+		return ret;
-+	}
-+
-+	return 0;
-+}
-+
-+/**
-+ * spansion_read_cr_quad_enable() - set QE bit in Configuration Register.
-+ * @nor:	pointer to a 'struct spi_nor'
-+ *
-+ * Set the Quad Enable (QE) bit in the Configuration Register.
-+ * This function should be used with QSPI memories supporting the Read
-+ * Configuration Register (35h) instruction.
-+ *
-+ * bit 1 of the Configuration Register is the QE bit for Spansion like QSPI
-+ * memories.
-+ *
-+ * Return: 0 on success, -errno otherwise.
-+ */
-+static int spansion_read_cr_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_dbg(dev, "error while reading configuration register\n");
-+		return -EINVAL;
-+	}
-+
-+	if (ret & CR_QUAD_EN_SPAN)
-+		return 0;
-+
-+	sr_cr[1] = ret | CR_QUAD_EN_SPAN;
-+
-+	/* Keep the current value of the Status Register. */
-+	ret = read_sr(nor);
-+	if (ret < 0) {
-+		dev_dbg(dev, "error while reading status register\n");
-+		return -EINVAL;
-+	}
-+	sr_cr[0] = ret;
-+
-+	ret = write_sr_cr(nor, sr_cr);
-+	if (ret)
-+		return ret;
-+
-+	/* Read back and check it. */
-+	ret = read_cr(nor);
-+	if (!(ret > 0 && (ret & CR_QUAD_EN_SPAN))) {
-+		dev_dbg(nor->dev, "Spansion Quad bit not set\n");
-+		return -EINVAL;
-+	}
-+
-+	return 0;
-+}
-+#endif /* CONFIG_SPI_FLASH_SPANSION */
-+
-+struct spi_nor_read_command {
-+	u8			num_mode_clocks;
-+	u8			num_wait_states;
-+	u8			opcode;
-+	enum spi_nor_protocol	proto;
-+};
-+
-+enum spi_nor_read_command_index {
-+	SNOR_CMD_READ,
-+	SNOR_CMD_READ_FAST,
-+
-+	/* Quad SPI */
-+	SNOR_CMD_READ_1_1_4,
-+
-+	SNOR_CMD_READ_MAX
-+};
-+
-+struct spi_nor_flash_parameter {
-+	struct spi_nor_hwcaps		hwcaps;
-+	struct spi_nor_read_command	reads[SNOR_CMD_READ_MAX];
-+};
-+
-+static void
-+spi_nor_set_read_settings(struct spi_nor_read_command *read,
-+			  u8 num_mode_clocks,
-+			  u8 num_wait_states,
-+			  u8 opcode,
-+			  enum spi_nor_protocol proto)
-+{
-+	read->num_mode_clocks = num_mode_clocks;
-+	read->num_wait_states = num_wait_states;
-+	read->opcode = opcode;
-+	read->proto = proto;
-+}
-+
-+static int spi_nor_init_params(struct spi_nor *nor,
-+			       const struct flash_info *info,
-+			       struct spi_nor_flash_parameter *params)
-+{
-+	/* (Fast) Read settings. */
-+	params->hwcaps.mask = SNOR_HWCAPS_READ;
-+	spi_nor_set_read_settings(&params->reads[SNOR_CMD_READ],
-+				  0, 0, SPINOR_OP_READ,
-+				  SNOR_PROTO_1_1_1);
-+
-+	if (!(info->flags & SPI_NOR_NO_FR)) {
-+		params->hwcaps.mask |= SNOR_HWCAPS_READ_FAST;
-+		spi_nor_set_read_settings(&params->reads[SNOR_CMD_READ_FAST],
-+					  0, 8, SPINOR_OP_READ_FAST,
-+					  SNOR_PROTO_1_1_1);
-+	}
-+
-+	if (info->flags & SPI_NOR_QUAD_READ) {
-+		params->hwcaps.mask |= SNOR_HWCAPS_READ_1_1_4;
-+		spi_nor_set_read_settings(&params->reads[SNOR_CMD_READ_1_1_4],
-+					  0, 8, SPINOR_OP_READ_1_1_4,
-+					  SNOR_PROTO_1_1_4);
-+	}
-+
-+	return 0;
-+}
-+
-+static int spi_nor_select_read(struct spi_nor *nor,
-+			       const struct spi_nor_flash_parameter *params,
-+			       u32 shared_hwcaps)
-+{
-+	int best_match = shared_hwcaps & SNOR_HWCAPS_READ_MASK;
-+	int cmd;
-+	const struct spi_nor_read_command *read;
-+
-+	if (best_match < 0)
-+		return -EINVAL;
-+
-+	if (best_match & SNOR_HWCAPS_READ_1_1_4)
-+		cmd = SNOR_CMD_READ_1_1_4;
-+	else if (best_match & SNOR_HWCAPS_READ_FAST)
-+		cmd = SNOR_CMD_READ_FAST;
-+	else
-+		cmd = SNOR_CMD_READ;
-+
-+	read = &params->reads[cmd];
-+	nor->read_opcode = read->opcode;
-+	nor->read_proto = read->proto;
-+
-+	/*
-+	 * In the spi-nor framework, we don't need to make the difference
-+	 * between mode clock cycles and wait state clock cycles.
-+	 * Indeed, the value of the mode clock cycles is used by a QSPI
-+	 * flash memory to know whether it should enter or leave its 0-4-4
-+	 * (Continuous Read / XIP) mode.
-+	 * eXecution In Place is out of the scope of the mtd sub-system.
-+	 * Hence we choose to merge both mode and wait state clock cycles
-+	 * into the so called dummy clock cycles.
-+	 */
-+	nor->read_dummy = read->num_mode_clocks + read->num_wait_states;
-+	return 0;
-+}
-+
-+static int spi_nor_setup(struct spi_nor *nor, const struct flash_info *info,
-+			 const struct spi_nor_flash_parameter *params,
-+			 const struct spi_nor_hwcaps *hwcaps)
-+{
-+	u32 shared_mask;
-+	int err;
-+
-+	/*
-+	 * Keep only the hardware capabilities supported by both the SPI
-+	 * controller and the SPI flash memory.
-+	 */
-+	shared_mask = hwcaps->mask & params->hwcaps.mask;
-+
-+	/* Select the (Fast) Read command. */
-+	err = spi_nor_select_read(nor, params, shared_mask);
-+	if (err) {
-+		dev_dbg(nor->dev,
-+			"can't select read settings supported by both the SPI controller and memory.\n");
-+		return err;
-+	}
-+
-+	/* Enable Quad I/O if needed. */
-+	if (spi_nor_get_protocol_width(nor->read_proto) == 4) {
-+		switch (JEDEC_MFR(info)) {
-+#ifdef CONFIG_SPI_FLASH_MACRONIX
-+		case SNOR_MFR_MACRONIX:
-+			err = macronix_quad_enable(nor);
-+			break;
-+#endif
-+		case SNOR_MFR_ST:
-+		case SNOR_MFR_MICRON:
-+			break;
-+
-+		default:
-+#if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND)
-+			/* Kept only for backward compatibility purpose. */
-+			err = spansion_read_cr_quad_enable(nor);
-+#endif
-+			break;
-+		}
-+	}
-+	if (err) {
-+		dev_dbg(nor->dev, "quad mode not supported\n");
-+		return err;
-+	}
-+
-+	return 0;
-+}
-+
-+static int spi_nor_init(struct spi_nor *nor)
-+{
-+	if (nor->addr_width == 4 &&
-+	    (JEDEC_MFR(nor->info) != SNOR_MFR_SPANSION) &&
-+	    !(nor->info->flags & SPI_NOR_4B_OPCODES)) {
-+		/*
-+		 * If the RESET# pin isn't hooked up properly, or the system
-+		 * otherwise doesn't perform a reset command in the boot
-+		 * sequence, it's impossible to 100% protect against unexpected
-+		 * reboots (e.g., crashes). Warn the user (or hopefully, system
-+		 * designer) that this is bad.
-+		 */
-+		if (nor->flags & SNOR_F_BROKEN_RESET)
-+			printf("enabling reset hack; may not recover from unexpected reboots\n");
-+		set_4byte(nor, nor->info, 1);
-+	}
-+
-+	return 0;
-+}
-+
-+int spi_nor_scan(struct spi_nor *nor)
-+{
-+	struct spi_nor_flash_parameter params;
-+	const struct flash_info *info = NULL;
-+	struct mtd_info *mtd = &nor->mtd;
-+	struct spi_nor_hwcaps hwcaps = {
-+		.mask = SNOR_HWCAPS_READ |
-+			SNOR_HWCAPS_READ_FAST
-+	};
-+	struct spi_slave *spi = nor->spi;
-+	int 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 (spi->mode & SPI_RX_QUAD)
-+		hwcaps.mask |= SNOR_HWCAPS_READ_1_1_4;
-+
-+	info = spi_nor_read_id(nor);
-+	if (IS_ERR_OR_NULL(info))
-+		return -ENOENT;
-+	/* Parse the Serial Flash Discoverable Parameters table. */
-+	ret = spi_nor_init_params(nor, info, &params);
-+	if (ret)
-+		return ret;
-+
-+	mtd->name = "spi-flash";
-+	mtd->priv = nor;
-+	mtd->type = MTD_NORFLASH;
-+	mtd->writesize = 1;
-+	mtd->flags = MTD_CAP_NORFLASH;
-+	mtd->size = info->sector_size * info->n_sectors;
-+	mtd->_erase = spi_nor_erase;
-+	mtd->_read = spi_nor_read;
-+	mtd->_write = spi_nor_write;
-+
-+	nor->size = mtd->size;
-+
-+	if (info->flags & USE_FSR)
-+		nor->flags |= SNOR_F_USE_FSR;
-+	if (info->flags & USE_CLSR)
-+		nor->flags |= SNOR_F_USE_CLSR;
-+
-+	if (info->flags & SPI_NOR_NO_FR)
-+		params.hwcaps.mask &= ~SNOR_HWCAPS_READ_FAST;
-+
-+	/*
-+	 * 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, &hwcaps);
-+	if (ret)
-+		return ret;
-+
-+	if (nor->addr_width) {
-+		/* already configured from SFDP */
-+	} 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 */
-+		nor->addr_width = 4;
-+		if (JEDEC_MFR(info) == SNOR_MFR_SPANSION ||
-+		    info->flags & SPI_NOR_4B_OPCODES)
-+			spi_nor_set_4byte_opcodes(nor, info);
-+	} else {
-+		nor->addr_width = 3;
-+	}
-+
-+	if (nor->addr_width > SPI_NOR_MAX_ADDR_WIDTH) {
-+		dev_dbg(dev, "address width is too large: %u\n",
-+			nor->addr_width);
-+		return -EINVAL;
-+	}
-+
-+	/* Send all the required SPI flash commands to initialize device */
-+	nor->info = info;
-+	ret = spi_nor_init(nor);
-+	if (ret)
-+		return ret;
-+
-+	return 0;
-+}
-+
-+/* U-Boot specific functions, need to extend MTD to support these */
-+int spi_flash_cmd_get_sw_write_prot(struct spi_nor *nor)
-+{
-+	return -ENOTSUPP;
-+}
-diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c
-deleted file mode 100644
-index 3bd6869020..0000000000
---- a/drivers/mtd/spi/spi_flash.c
-+++ /dev/null
-@@ -1,1334 +0,0 @@
--// SPDX-License-Identifier: GPL-2.0+
--/*
-- * SPI Flash Core
-- *
-- * Copyright (C) 2015 Jagan Teki <jteki@openedev.com>
-- * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc.
-- * Copyright (C) 2010 Reinhard Meyer, EMK Elektronik
-- * Copyright (C) 2008 Atmel Corporation
-- */
--
--#include <common.h>
--#include <errno.h>
--#include <malloc.h>
--#include <mapmem.h>
--#include <spi.h>
--#include <spi_flash.h>
--#include <watchdog.h>
--#include <linux/log2.h>
--#include <linux/sizes.h>
--#include <dma.h>
--
--#include "sf_internal.h"
--
--static void spi_flash_addr(u32 addr, u8 *cmd)
--{
--	/* cmd[0] is actual command */
--	cmd[1] = addr >> 16;
--	cmd[2] = addr >> 8;
--	cmd[3] = addr >> 0;
--}
--
--static int read_sr(struct spi_flash *flash, u8 *rs)
--{
--	int ret;
--	u8 cmd;
--
--	cmd = CMD_READ_STATUS;
--	ret = spi_flash_read_common(flash, &cmd, 1, rs, 1);
--	if (ret < 0) {
--		debug("SF: fail to read status register\n");
--		return ret;
--	}
--
--	return 0;
--}
--
--static int read_fsr(struct spi_flash *flash, u8 *fsr)
--{
--	int ret;
--	const u8 cmd = CMD_FLAG_STATUS;
--
--	ret = spi_flash_read_common(flash, &cmd, 1, fsr, 1);
--	if (ret < 0) {
--		debug("SF: fail to read flag status register\n");
--		return ret;
--	}
--
--	return 0;
--}
--
--static int write_sr(struct spi_flash *flash, u8 ws)
--{
--	u8 cmd;
--	int ret;
--
--	cmd = CMD_WRITE_STATUS;
--	ret = spi_flash_write_common(flash, &cmd, 1, &ws, 1);
--	if (ret < 0) {
--		debug("SF: fail to write status register\n");
--		return ret;
--	}
--
--	return 0;
--}
--
--#if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND)
--static int read_cr(struct spi_flash *flash, u8 *rc)
--{
--	int ret;
--	u8 cmd;
--
--	cmd = CMD_READ_CONFIG;
--	ret = spi_flash_read_common(flash, &cmd, 1, rc, 1);
--	if (ret < 0) {
--		debug("SF: fail to read config register\n");
--		return ret;
--	}
--
--	return 0;
--}
--
--static int write_cr(struct spi_flash *flash, u8 wc)
--{
--	u8 data[2];
--	u8 cmd;
--	int ret;
--
--	ret = read_sr(flash, &data[0]);
--	if (ret < 0)
--		return ret;
--
--	cmd = CMD_WRITE_STATUS;
--	data[1] = wc;
--	ret = spi_flash_write_common(flash, &cmd, 1, &data, 2);
--	if (ret) {
--		debug("SF: fail to write config register\n");
--		return ret;
--	}
--
--	return 0;
--}
--#endif
--
--#ifdef CONFIG_SPI_FLASH_BAR
--/*
-- * This "clean_bar" is necessary in a situation when one was accessing
-- * spi flash memory > 16 MiB by using Bank Address Register's BA24 bit.
-- *
-- * After it the BA24 bit shall be cleared to allow access to correct
-- * memory region after SW reset (by calling "reset" command).
-- *
-- * Otherwise, the BA24 bit may be left set and then after reset, the
-- * ROM would read/write/erase SPL from 16 MiB * bank_sel address.
-- */
--static int clean_bar(struct spi_flash *flash)
--{
--	u8 cmd, bank_sel = 0;
--
--	if (flash->bank_curr == 0)
--		return 0;
--	cmd = flash->bank_write_cmd;
--	flash->bank_curr = 0;
--
--	return spi_flash_write_common(flash, &cmd, 1, &bank_sel, 1);
--}
--
--static int write_bar(struct spi_flash *flash, u32 offset)
--{
--	u8 cmd, bank_sel;
--	int ret;
--
--	bank_sel = offset / (SPI_FLASH_16MB_BOUN << flash->shift);
--	if (bank_sel == flash->bank_curr)
--		goto bar_end;
--
--	cmd = flash->bank_write_cmd;
--	ret = spi_flash_write_common(flash, &cmd, 1, &bank_sel, 1);
--	if (ret < 0) {
--		debug("SF: fail to write bank register\n");
--		return ret;
--	}
--
--bar_end:
--	flash->bank_curr = bank_sel;
--	return flash->bank_curr;
--}
--
--static int read_bar(struct spi_flash *flash, const struct spi_flash_info *info)
--{
--	u8 curr_bank = 0;
--	int ret;
--
--	if (flash->size <= SPI_FLASH_16MB_BOUN)
--		goto bar_end;
--
--	switch (JEDEC_MFR(info)) {
--	case SPI_FLASH_CFI_MFR_SPANSION:
--		flash->bank_read_cmd = CMD_BANKADDR_BRRD;
--		flash->bank_write_cmd = CMD_BANKADDR_BRWR;
--		break;
--	default:
--		flash->bank_read_cmd = CMD_EXTNADDR_RDEAR;
--		flash->bank_write_cmd = CMD_EXTNADDR_WREAR;
--	}
--
--	ret = spi_flash_read_common(flash, &flash->bank_read_cmd, 1,
--				    &curr_bank, 1);
--	if (ret) {
--		debug("SF: fail to read bank addr register\n");
--		return ret;
--	}
--
--bar_end:
--	flash->bank_curr = curr_bank;
--	return 0;
--}
--#endif
--
--#ifdef CONFIG_SF_DUAL_FLASH
--static void spi_flash_dual(struct spi_flash *flash, u32 *addr)
--{
--	switch (flash->dual_flash) {
--	case SF_DUAL_STACKED_FLASH:
--		if (*addr >= (flash->size >> 1)) {
--			*addr -= flash->size >> 1;
--			flash->flags |= SNOR_F_USE_UPAGE;
--		} else {
--			flash->flags &= ~SNOR_F_USE_UPAGE;
--		}
--		break;
--	case SF_DUAL_PARALLEL_FLASH:
--		*addr >>= flash->shift;
--		break;
--	default:
--		debug("SF: Unsupported dual_flash=%d\n", flash->dual_flash);
--		break;
--	}
--}
--#endif
--
--static int spi_flash_sr_ready(struct spi_flash *flash)
--{
--	u8 sr;
--	int ret;
--
--	ret = read_sr(flash, &sr);
--	if (ret < 0)
--		return ret;
--
--	return !(sr & STATUS_WIP);
--}
--
--static int spi_flash_fsr_ready(struct spi_flash *flash)
--{
--	u8 fsr;
--	int ret;
--
--	ret = read_fsr(flash, &fsr);
--	if (ret < 0)
--		return ret;
--
--	return fsr & STATUS_PEC;
--}
--
--static int spi_flash_ready(struct spi_flash *flash)
--{
--	int sr, fsr;
--
--	sr = spi_flash_sr_ready(flash);
--	if (sr < 0)
--		return sr;
--
--	fsr = 1;
--	if (flash->flags & SNOR_F_USE_FSR) {
--		fsr = spi_flash_fsr_ready(flash);
--		if (fsr < 0)
--			return fsr;
--	}
--
--	return sr && fsr;
--}
--
--static int spi_flash_wait_till_ready(struct spi_flash *flash,
--				     unsigned long timeout)
--{
--	unsigned long timebase;
--	int ret;
--
--	timebase = get_timer(0);
--
--	while (get_timer(timebase) < timeout) {
--		ret = spi_flash_ready(flash);
--		if (ret < 0)
--			return ret;
--		if (ret)
--			return 0;
--	}
--
--	printf("SF: Timeout!\n");
--
--	return -ETIMEDOUT;
--}
--
--int spi_flash_write_common(struct spi_flash *flash, const u8 *cmd,
--		size_t cmd_len, const void *buf, size_t buf_len)
--{
--	struct spi_slave *spi = flash->spi;
--	unsigned long timeout = SPI_FLASH_PROG_TIMEOUT;
--	int ret;
--
--	if (buf == NULL)
--		timeout = SPI_FLASH_PAGE_ERASE_TIMEOUT;
--
--	ret = spi_claim_bus(spi);
--	if (ret) {
--		debug("SF: unable to claim SPI bus\n");
--		return ret;
--	}
--
--	ret = spi_flash_cmd_write_enable(flash);
--	if (ret < 0) {
--		debug("SF: enabling write failed\n");
--		return ret;
--	}
--
--	ret = spi_flash_cmd_write(spi, cmd, cmd_len, buf, buf_len);
--	if (ret < 0) {
--		debug("SF: write cmd failed\n");
--		return ret;
--	}
--
--	ret = spi_flash_wait_till_ready(flash, timeout);
--	if (ret < 0) {
--		debug("SF: write %s timed out\n",
--		      timeout == SPI_FLASH_PROG_TIMEOUT ?
--			"program" : "page erase");
--		return ret;
--	}
--
--	spi_release_bus(spi);
--
--	return ret;
--}
--
--int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len)
--{
--	u32 erase_size, erase_addr;
--	u8 cmd[SPI_FLASH_CMD_LEN];
--	int ret = -1;
--
--	erase_size = flash->erase_size;
--	if (offset % erase_size || len % erase_size) {
--		printf("SF: Erase offset/length not multiple of erase size\n");
--		return -1;
--	}
--
--	if (flash->flash_is_locked) {
--		if (flash->flash_is_locked(flash, offset, len) > 0) {
--			printf("offset 0x%x is protected and cannot be erased\n",
--			       offset);
--			return -EINVAL;
--		}
--	}
--
--	cmd[0] = flash->erase_cmd;
--	while (len) {
--		erase_addr = offset;
--
--#ifdef CONFIG_SF_DUAL_FLASH
--		if (flash->dual_flash > SF_SINGLE_FLASH)
--			spi_flash_dual(flash, &erase_addr);
--#endif
--#ifdef CONFIG_SPI_FLASH_BAR
--		ret = write_bar(flash, erase_addr);
--		if (ret < 0)
--			return ret;
--#endif
--		spi_flash_addr(erase_addr, cmd);
--
--		debug("SF: erase %2x %2x %2x %2x (%x)\n", cmd[0], cmd[1],
--		      cmd[2], cmd[3], erase_addr);
--
--		ret = spi_flash_write_common(flash, cmd, sizeof(cmd), NULL, 0);
--		if (ret < 0) {
--			debug("SF: erase failed\n");
--			break;
--		}
--
--		offset += erase_size;
--		len -= erase_size;
--
--		WATCHDOG_RESET();
--	}
--
--#ifdef CONFIG_SPI_FLASH_BAR
--	ret = clean_bar(flash);
--#endif
--
--	return ret;
--}
--
--int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset,
--		size_t len, const void *buf)
--{
--	struct spi_slave *spi = flash->spi;
--	unsigned long byte_addr, page_size;
--	u32 write_addr;
--	size_t chunk_len, actual;
--	u8 cmd[SPI_FLASH_CMD_LEN];
--	int ret = -1;
--
--	page_size = flash->page_size;
--
--	if (flash->flash_is_locked) {
--		if (flash->flash_is_locked(flash, offset, len) > 0) {
--			printf("offset 0x%x is protected and cannot be written\n",
--			       offset);
--			return -EINVAL;
--		}
--	}
--
--	cmd[0] = flash->write_cmd;
--	for (actual = 0; actual < len; actual += chunk_len) {
--		write_addr = offset;
--
--#ifdef CONFIG_SF_DUAL_FLASH
--		if (flash->dual_flash > SF_SINGLE_FLASH)
--			spi_flash_dual(flash, &write_addr);
--#endif
--#ifdef CONFIG_SPI_FLASH_BAR
--		ret = write_bar(flash, write_addr);
--		if (ret < 0)
--			return ret;
--#endif
--		byte_addr = offset % page_size;
--		chunk_len = min(len - actual, (size_t)(page_size - byte_addr));
--
--		if (spi->max_write_size)
--			chunk_len = min(chunk_len,
--					spi->max_write_size - sizeof(cmd));
--
--		spi_flash_addr(write_addr, cmd);
--
--		debug("SF: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %zu\n",
--		      buf + actual, cmd[0], cmd[1], cmd[2], cmd[3], chunk_len);
--
--		ret = spi_flash_write_common(flash, cmd, sizeof(cmd),
--					buf + actual, chunk_len);
--		if (ret < 0) {
--			debug("SF: write failed\n");
--			break;
--		}
--
--		offset += chunk_len;
--
--		WATCHDOG_RESET();
--	}
--
--#ifdef CONFIG_SPI_FLASH_BAR
--	ret = clean_bar(flash);
--#endif
--
--	return ret;
--}
--
--int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd,
--		size_t cmd_len, void *data, size_t data_len)
--{
--	struct spi_slave *spi = flash->spi;
--	int ret;
--
--	ret = spi_claim_bus(spi);
--	if (ret) {
--		debug("SF: unable to claim SPI bus\n");
--		return ret;
--	}
--
--	ret = spi_flash_cmd_read(spi, cmd, cmd_len, data, data_len);
--	if (ret < 0) {
--		debug("SF: read cmd failed\n");
--		return ret;
--	}
--
--	spi_release_bus(spi);
--
--	return ret;
--}
--
--/*
-- * TODO: remove the weak after all the other spi_flash_copy_mmap
-- * implementations removed from drivers
-- */
--void __weak spi_flash_copy_mmap(void *data, void *offset, size_t len)
--{
--#ifdef CONFIG_DMA
--	if (!dma_memcpy(data, offset, len))
--		return;
--#endif
--	memcpy(data, offset, len);
--}
--
--int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset,
--		size_t len, void *data)
--{
--	struct spi_slave *spi = flash->spi;
--	u8 cmdsz;
--	u32 remain_len, read_len, read_addr;
--	int bank_sel = 0;
--	int ret = 0;
--
--	/* Handle memory-mapped SPI */
--	if (flash->memory_map) {
--		ret = spi_claim_bus(spi);
--		if (ret) {
--			debug("SF: unable to claim SPI bus\n");
--			return log_ret(ret);
--		}
--		spi_xfer(spi, 0, NULL, NULL, SPI_XFER_MMAP);
--		spi_flash_copy_mmap(data, flash->memory_map + offset, len);
--		spi_xfer(spi, 0, NULL, NULL, SPI_XFER_MMAP_END);
--		spi_release_bus(spi);
--		return 0;
--	}
--
--	cmdsz = SPI_FLASH_CMD_LEN + flash->dummy_byte;
--	u8 cmd[cmdsz];
--
--	cmd[0] = flash->read_cmd;
--	while (len) {
--		read_addr = offset;
--
--#ifdef CONFIG_SF_DUAL_FLASH
--		if (flash->dual_flash > SF_SINGLE_FLASH)
--			spi_flash_dual(flash, &read_addr);
--#endif
--#ifdef CONFIG_SPI_FLASH_BAR
--		ret = write_bar(flash, read_addr);
--		if (ret < 0)
--			return log_ret(ret);
--		bank_sel = flash->bank_curr;
--#endif
--		remain_len = ((SPI_FLASH_16MB_BOUN << flash->shift) *
--				(bank_sel + 1)) - offset;
--		if (len < remain_len)
--			read_len = len;
--		else
--			read_len = remain_len;
--
--		if (spi->max_read_size)
--			read_len = min(read_len, spi->max_read_size);
--
--		spi_flash_addr(read_addr, cmd);
--
--		ret = spi_flash_read_common(flash, cmd, cmdsz, data, read_len);
--		if (ret < 0) {
--			debug("SF: read failed\n");
--			break;
--		}
--
--		offset += read_len;
--		len -= read_len;
--		data += read_len;
--
--		WATCHDOG_RESET();
--	}
--
--#ifdef CONFIG_SPI_FLASH_BAR
--	ret = clean_bar(flash);
--#endif
--
--	return log_ret(ret);
--}
--
--#ifdef CONFIG_SPI_FLASH_SST
--static bool sst26_process_bpr(u32 bpr_size, u8 *cmd, u32 bit, enum lock_ctl ctl)
--{
--	switch (ctl) {
--		case SST26_CTL_LOCK:
--			cmd[bpr_size - (bit / 8) - 1] |= BIT(bit % 8);
--			break;
--		case SST26_CTL_UNLOCK:
--			cmd[bpr_size - (bit / 8) - 1] &= ~BIT(bit % 8);
--			break;
--		case SST26_CTL_CHECK:
--			return !!(cmd[bpr_size - (bit / 8) - 1] & BIT(bit % 8));
--	}
--
--	return false;
--}
--
--/*
-- * sst26wf016/sst26wf032/sst26wf064 have next block protection:
-- * 4x   - 8  KByte blocks - read & write protection bits - upper addresses
-- * 1x   - 32 KByte blocks - write protection bits
-- * rest - 64 KByte blocks - write protection bits
-- * 1x   - 32 KByte blocks - write protection bits
-- * 4x   - 8  KByte blocks - read & write protection bits - lower addresses
-- *
-- * We'll support only per 64k lock/unlock so lower and upper 64 KByte region
-- * will be treated as single block.
-- */
--
--/*
-- * Lock, unlock or check lock status of the flash region of the flash (depending
-- * on the lock_ctl value)
-- */
--static int sst26_lock_ctl(struct spi_flash *flash, u32 ofs, size_t len, enum lock_ctl ctl)
--{
--	u32 i, bpr_ptr, rptr_64k, lptr_64k, bpr_size;
--	bool lower_64k = false, upper_64k = false;
--	u8 cmd, bpr_buff[SST26_MAX_BPR_REG_LEN] = {};
--	int ret;
--
--	/* Check length and offset for 64k alignment */
--	if ((ofs & (SZ_64K - 1)) || (len & (SZ_64K - 1)))
--		return -EINVAL;
--
--	if (ofs + len > flash->size)
--		return -EINVAL;
--
--	/* SST26 family has only 16 Mbit, 32 Mbit and 64 Mbit IC */
--	if (flash->size != SZ_2M &&
--	    flash->size != SZ_4M &&
--	    flash->size != SZ_8M)
--		return -EINVAL;
--
--	bpr_size = 2 + (flash->size / SZ_64K / 8);
--
--	cmd = SST26_CMD_READ_BPR;
--	ret = spi_flash_read_common(flash, &cmd, 1, bpr_buff, bpr_size);
--	if (ret < 0) {
--		printf("SF: fail to read block-protection register\n");
--		return ret;
--	}
--
--	rptr_64k = min_t(u32, ofs + len , flash->size - SST26_BOUND_REG_SIZE);
--	lptr_64k = max_t(u32, ofs, SST26_BOUND_REG_SIZE);
--
--	upper_64k = ((ofs + len) > (flash->size - SST26_BOUND_REG_SIZE));
--	lower_64k = (ofs < SST26_BOUND_REG_SIZE);
--
--	/* Lower bits in block-protection register are about 64k region */
--	bpr_ptr = lptr_64k / SZ_64K - 1;
--
--	/* Process 64K blocks region */
--	while (lptr_64k < rptr_64k) {
--		if (sst26_process_bpr(bpr_size, bpr_buff, bpr_ptr, ctl))
--			return EACCES;
--
--		bpr_ptr++;
--		lptr_64k += SZ_64K;
--	}
--
--	/* 32K and 8K region bits in BPR are after 64k region bits */
--	bpr_ptr = (flash->size - 2 * SST26_BOUND_REG_SIZE) / SZ_64K;
--
--	/* Process lower 32K block region */
--	if (lower_64k)
--		if (sst26_process_bpr(bpr_size, bpr_buff, bpr_ptr, ctl))
--			return EACCES;
--
--	bpr_ptr++;
--
--	/* Process upper 32K block region */
--	if (upper_64k)
--		if (sst26_process_bpr(bpr_size, bpr_buff, bpr_ptr, ctl))
--			return EACCES;
--
--	bpr_ptr++;
--
--	/* Process lower 8K block regions */
--	for (i = 0; i < SST26_BPR_8K_NUM; i++) {
--		if (lower_64k)
--			if (sst26_process_bpr(bpr_size, bpr_buff, bpr_ptr, ctl))
--				return EACCES;
--
--		/* In 8K area BPR has both read and write protection bits */
--		bpr_ptr += 2;
--	}
--
--	/* Process upper 8K block regions */
--	for (i = 0; i < SST26_BPR_8K_NUM; i++) {
--		if (upper_64k)
--			if (sst26_process_bpr(bpr_size, bpr_buff, bpr_ptr, ctl))
--				return EACCES;
--
--		/* In 8K area BPR has both read and write protection bits */
--		bpr_ptr += 2;
--	}
--
--	/* If we check region status we don't need to write BPR back */
--	if (ctl == SST26_CTL_CHECK)
--		return 0;
--
--	cmd = SST26_CMD_WRITE_BPR;
--	ret = spi_flash_write_common(flash, &cmd, 1, bpr_buff, bpr_size);
--	if (ret < 0) {
--		printf("SF: fail to write block-protection register\n");
--		return ret;
--	}
--
--	return 0;
--}
--
--static int sst26_unlock(struct spi_flash *flash, u32 ofs, size_t len)
--{
--	return sst26_lock_ctl(flash, ofs, len, SST26_CTL_UNLOCK);
--}
--
--static int sst26_lock(struct spi_flash *flash, u32 ofs, size_t len)
--{
--	return sst26_lock_ctl(flash, ofs, len, SST26_CTL_LOCK);
--}
--
--/*
-- * Returns EACCES (positive value) if region is locked, 0 if region is unlocked,
-- * and negative on errors.
-- */
--static int sst26_is_locked(struct spi_flash *flash, u32 ofs, size_t len)
--{
--	/*
--	 * is_locked function is used for check before reading or erasing flash
--	 * region, so offset and length might be not 64k allighned, so adjust
--	 * them to be 64k allighned as sst26_lock_ctl works only with 64k
--	 * allighned regions.
--	 */
--	ofs -= ofs & (SZ_64K - 1);
--	len = len & (SZ_64K - 1) ? (len & ~(SZ_64K - 1)) + SZ_64K : len;
--
--	return sst26_lock_ctl(flash, ofs, len, SST26_CTL_CHECK);
--}
--
--static int sst_byte_write(struct spi_flash *flash, u32 offset, const void *buf)
--{
--	struct spi_slave *spi = flash->spi;
--	int ret;
--	u8 cmd[4] = {
--		CMD_SST_BP,
--		offset >> 16,
--		offset >> 8,
--		offset,
--	};
--
--	debug("BP[%02x]: 0x%p => cmd = { 0x%02x 0x%06x }\n",
--	      spi_w8r8(spi, CMD_READ_STATUS), buf, cmd[0], offset);
--
--	ret = spi_flash_cmd_write_enable(flash);
--	if (ret)
--		return ret;
--
--	ret = spi_flash_cmd_write(spi, cmd, sizeof(cmd), buf, 1);
--	if (ret)
--		return ret;
--
--	return spi_flash_wait_till_ready(flash, SPI_FLASH_PROG_TIMEOUT);
--}
--
--int sst_write_wp(struct spi_flash *flash, u32 offset, size_t len,
--		const void *buf)
--{
--	struct spi_slave *spi = flash->spi;
--	size_t actual, cmd_len;
--	int ret;
--	u8 cmd[4];
--
--	ret = spi_claim_bus(spi);
--	if (ret) {
--		debug("SF: Unable to claim SPI bus\n");
--		return ret;
--	}
--
--	/* If the data is not word aligned, write out leading single byte */
--	actual = offset % 2;
--	if (actual) {
--		ret = sst_byte_write(flash, offset, buf);
--		if (ret)
--			goto done;
--	}
--	offset += actual;
--
--	ret = spi_flash_cmd_write_enable(flash);
--	if (ret)
--		goto done;
--
--	cmd_len = 4;
--	cmd[0] = CMD_SST_AAI_WP;
--	cmd[1] = offset >> 16;
--	cmd[2] = offset >> 8;
--	cmd[3] = offset;
--
--	for (; actual < len - 1; actual += 2) {
--		debug("WP[%02x]: 0x%p => cmd = { 0x%02x 0x%06x }\n",
--		      spi_w8r8(spi, CMD_READ_STATUS), buf + actual,
--		      cmd[0], offset);
--
--		ret = spi_flash_cmd_write(spi, cmd, cmd_len,
--					buf + actual, 2);
--		if (ret) {
--			debug("SF: sst word program failed\n");
--			break;
--		}
--
--		ret = spi_flash_wait_till_ready(flash, SPI_FLASH_PROG_TIMEOUT);
--		if (ret)
--			break;
--
--		cmd_len = 1;
--		offset += 2;
--
--		WATCHDOG_RESET();
--	}
--
--	if (!ret)
--		ret = spi_flash_cmd_write_disable(flash);
--
--	/* If there is a single trailing byte, write it out */
--	if (!ret && actual != len)
--		ret = sst_byte_write(flash, offset, buf + actual);
--
-- done:
--	debug("SF: sst: program %s %zu bytes @ 0x%zx\n",
--	      ret ? "failure" : "success", len, offset - actual);
--
--	spi_release_bus(spi);
--	return ret;
--}
--
--int sst_write_bp(struct spi_flash *flash, u32 offset, size_t len,
--		const void *buf)
--{
--	struct spi_slave *spi = flash->spi;
--	size_t actual;
--	int ret;
--
--	ret = spi_claim_bus(spi);
--	if (ret) {
--		debug("SF: Unable to claim SPI bus\n");
--		return ret;
--	}
--
--	for (actual = 0; actual < len; actual++) {
--		ret = sst_byte_write(flash, offset, buf + actual);
--		if (ret) {
--			debug("SF: sst byte program failed\n");
--			break;
--		}
--		offset++;
--	}
--
--	if (!ret)
--		ret = spi_flash_cmd_write_disable(flash);
--
--	debug("SF: sst: program %s %zu bytes @ 0x%zx\n",
--	      ret ? "failure" : "success", len, offset - actual);
--
--	spi_release_bus(spi);
--	return ret;
--}
--#endif
--
--#if defined(CONFIG_SPI_FLASH_STMICRO) || defined(CONFIG_SPI_FLASH_SST)
--static void stm_get_locked_range(struct spi_flash *flash, u8 sr, loff_t *ofs,
--				 u64 *len)
--{
--	u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
--	int shift = ffs(mask) - 1;
--	int pow;
--
--	if (!(sr & mask)) {
--		/* No protection */
--		*ofs = 0;
--		*len = 0;
--	} else {
--		pow = ((sr & mask) ^ mask) >> shift;
--		*len = flash->size >> pow;
--		*ofs = flash->size - *len;
--	}
--}
--
--/*
-- * Return 1 if the entire region is locked, 0 otherwise
-- */
--static int stm_is_locked_sr(struct spi_flash *flash, loff_t ofs, u64 len,
--			    u8 sr)
--{
--	loff_t lock_offs;
--	u64 lock_len;
--
--	stm_get_locked_range(flash, sr, &lock_offs, &lock_len);
--
--	return (ofs + len <= lock_offs + lock_len) && (ofs >= lock_offs);
--}
--
--/*
-- * Check if a region of the flash is (completely) locked. See stm_lock() for
-- * more info.
-- *
-- * Returns 1 if entire region is locked, 0 if any portion is unlocked, and
-- * negative on errors.
-- */
--int stm_is_locked(struct spi_flash *flash, u32 ofs, size_t len)
--{
--	int status;
--	u8 sr;
--
--	status = read_sr(flash, &sr);
--	if (status < 0)
--		return status;
--
--	return stm_is_locked_sr(flash, ofs, len, sr);
--}
--
--/*
-- * Lock a region of the flash. Compatible with ST Micro and similar flash.
-- * Supports only the block protection bits BP{0,1,2} in the status register
-- * (SR). Does not support these features found in newer SR bitfields:
-- *   - TB: top/bottom protect - only handle TB=0 (top protect)
-- *   - SEC: sector/block protect - only handle SEC=0 (block protect)
-- *   - CMP: complement protect - only support CMP=0 (range is not complemented)
-- *
-- * Sample table portion for 8MB flash (Winbond w25q64fw):
-- *
-- *   SEC  |  TB   |  BP2  |  BP1  |  BP0  |  Prot Length  | Protected Portion
-- *  --------------------------------------------------------------------------
-- *    X   |   X   |   0   |   0   |   0   |  NONE         | NONE
-- *    0   |   0   |   0   |   0   |   1   |  128 KB       | Upper 1/64
-- *    0   |   0   |   0   |   1   |   0   |  256 KB       | Upper 1/32
-- *    0   |   0   |   0   |   1   |   1   |  512 KB       | Upper 1/16
-- *    0   |   0   |   1   |   0   |   0   |  1 MB         | Upper 1/8
-- *    0   |   0   |   1   |   0   |   1   |  2 MB         | Upper 1/4
-- *    0   |   0   |   1   |   1   |   0   |  4 MB         | Upper 1/2
-- *    X   |   X   |   1   |   1   |   1   |  8 MB         | ALL
-- *
-- * Returns negative on errors, 0 on success.
-- */
--int stm_lock(struct spi_flash *flash, u32 ofs, size_t len)
--{
--	u8 status_old, status_new;
--	u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
--	u8 shift = ffs(mask) - 1, pow, val;
--	int ret;
--
--	ret = read_sr(flash, &status_old);
--	if (ret < 0)
--		return ret;
--
--	/* SPI NOR always locks to the end */
--	if (ofs + len != flash->size) {
--		/* Does combined region extend to end? */
--		if (!stm_is_locked_sr(flash, ofs + len, flash->size - ofs - len,
--				      status_old))
--			return -EINVAL;
--		len = flash->size - ofs;
--	}
--
--	/*
--	 * Need smallest pow such that:
--	 *
--	 *   1 / (2^pow) <= (len / size)
--	 *
--	 * so (assuming power-of-2 size) we do:
--	 *
--	 *   pow = ceil(log2(size / len)) = log2(size) - floor(log2(len))
--	 */
--	pow = ilog2(flash->size) - ilog2(len);
--	val = mask - (pow << shift);
--	if (val & ~mask)
--		return -EINVAL;
--
--	/* Don't "lock" with no region! */
--	if (!(val & mask))
--		return -EINVAL;
--
--	status_new = (status_old & ~mask) | val;
--
--	/* Only modify protection if it will not unlock other areas */
--	if ((status_new & mask) <= (status_old & mask))
--		return -EINVAL;
--
--	write_sr(flash, status_new);
--
--	return 0;
--}
--
--/*
-- * Unlock a region of the flash. See stm_lock() for more info
-- *
-- * Returns negative on errors, 0 on success.
-- */
--int stm_unlock(struct spi_flash *flash, u32 ofs, size_t len)
--{
--	uint8_t status_old, status_new;
--	u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
--	u8 shift = ffs(mask) - 1, pow, val;
--	int ret;
--
--	ret = read_sr(flash, &status_old);
--	if (ret < 0)
--		return ret;
--
--	/* Cannot unlock; would unlock larger region than requested */
--	if (stm_is_locked_sr(flash, ofs - flash->erase_size, flash->erase_size,
--			     status_old))
--		return -EINVAL;
--	/*
--	 * Need largest pow such that:
--	 *
--	 *   1 / (2^pow) >= (len / size)
--	 *
--	 * so (assuming power-of-2 size) we do:
--	 *
--	 *   pow = floor(log2(size / len)) = log2(size) - ceil(log2(len))
--	 */
--	pow = ilog2(flash->size) - order_base_2(flash->size - (ofs + len));
--	if (ofs + len == flash->size) {
--		val = 0; /* fully unlocked */
--	} else {
--		val = mask - (pow << shift);
--		/* Some power-of-two sizes are not supported */
--		if (val & ~mask)
--			return -EINVAL;
--	}
--
--	status_new = (status_old & ~mask) | val;
--
--	/* Only modify protection if it will not lock other areas */
--	if ((status_new & mask) >= (status_old & mask))
--		return -EINVAL;
--
--	write_sr(flash, status_new);
--
--	return 0;
--}
--#endif
--
--
--#ifdef CONFIG_SPI_FLASH_MACRONIX
--static int macronix_quad_enable(struct spi_flash *flash)
--{
--	u8 qeb_status;
--	int ret;
--
--	ret = read_sr(flash, &qeb_status);
--	if (ret < 0)
--		return ret;
--
--	if (qeb_status & STATUS_QEB_MXIC)
--		return 0;
--
--	ret = write_sr(flash, qeb_status | STATUS_QEB_MXIC);
--	if (ret < 0)
--		return ret;
--
--	/* read SR and check it */
--	ret = read_sr(flash, &qeb_status);
--	if (!(ret >= 0 && (qeb_status & STATUS_QEB_MXIC))) {
--		printf("SF: Macronix SR Quad bit not clear\n");
--		return -EINVAL;
--	}
--
--	return ret;
--}
--#endif
--
--#if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND)
--static int spansion_quad_enable(struct spi_flash *flash)
--{
--	u8 qeb_status;
--	int ret;
--
--	ret = read_cr(flash, &qeb_status);
--	if (ret < 0)
--		return ret;
--
--	if (qeb_status & STATUS_QEB_WINSPAN)
--		return 0;
--
--	ret = write_cr(flash, qeb_status | STATUS_QEB_WINSPAN);
--	if (ret < 0)
--		return ret;
--
--	/* read CR and check it */
--	ret = read_cr(flash, &qeb_status);
--	if (!(ret >= 0 && (qeb_status & STATUS_QEB_WINSPAN))) {
--		printf("SF: Spansion CR Quad bit not clear\n");
--		return -EINVAL;
--	}
--
--	return ret;
--}
--#endif
--
--static const struct spi_flash_info *spi_flash_read_id(struct spi_flash *flash)
--{
--	int				tmp;
--	u8				id[SPI_FLASH_MAX_ID_LEN];
--	const struct spi_flash_info	*info;
--
--	tmp = spi_flash_cmd(flash->spi, CMD_READ_ID, id, SPI_FLASH_MAX_ID_LEN);
--	if (tmp < 0) {
--		printf("SF: error %d reading JEDEC ID\n", tmp);
--		return ERR_PTR(tmp);
--	}
--
--	info = spi_flash_ids;
--	for (; info->name != NULL; info++) {
--		if (info->id_len) {
--			if (!memcmp(info->id, id, info->id_len))
--				return info;
--		}
--	}
--
--	printf("SF: unrecognized JEDEC id bytes: %02x, %02x, %02x\n",
--	       id[0], id[1], id[2]);
--	return ERR_PTR(-ENODEV);
--}
--
--static int set_quad_mode(struct spi_flash *flash,
--			 const struct spi_flash_info *info)
--{
--	switch (JEDEC_MFR(info)) {
--#ifdef CONFIG_SPI_FLASH_MACRONIX
--	case SPI_FLASH_CFI_MFR_MACRONIX:
--		return macronix_quad_enable(flash);
--#endif
--#if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND)
--	case SPI_FLASH_CFI_MFR_SPANSION:
--	case SPI_FLASH_CFI_MFR_WINBOND:
--		return spansion_quad_enable(flash);
--#endif
--#ifdef CONFIG_SPI_FLASH_STMICRO
--	case SPI_FLASH_CFI_MFR_STMICRO:
--	case SPI_FLASH_CFI_MFR_MICRON:
--		debug("SF: QEB is volatile for %02x flash\n", JEDEC_MFR(info));
--		return 0;
--#endif
--	default:
--		printf("SF: Need set QEB func for %02x flash\n",
--		       JEDEC_MFR(info));
--		return -1;
--	}
--}
--
--#if CONFIG_IS_ENABLED(OF_CONTROL)
--int spi_flash_decode_fdt(struct spi_flash *flash)
--{
--#ifdef CONFIG_DM_SPI_FLASH
--	fdt_addr_t addr;
--	fdt_size_t size;
--
--	addr = dev_read_addr_size(flash->dev, "memory-map", &size);
--	if (addr == FDT_ADDR_T_NONE) {
--		debug("%s: Cannot decode address\n", __func__);
--		return 0;
--	}
--
--	if (flash->size > size) {
--		debug("%s: Memory map must cover entire device\n", __func__);
--		return -1;
--	}
--	flash->memory_map = map_sysmem(addr, size);
--#endif
--
--	return 0;
--}
--#endif /* CONFIG_IS_ENABLED(OF_CONTROL) */
--
--int spi_flash_scan(struct spi_flash *flash)
--{
--	struct spi_slave *spi = flash->spi;
--	const struct spi_flash_info *info = NULL;
--	int ret;
--
--	info = spi_flash_read_id(flash);
--	if (IS_ERR_OR_NULL(info))
--		return -ENOENT;
--
--	/*
--	 * Flash powers up read-only, so clear BP# bits.
--	 *
--	 * Note on some flash (like Macronix), QE (quad enable) bit is in the
--	 * same status register as BP# bits, and we need preserve its original
--	 * value during a reboot cycle as this is required by some platforms
--	 * (like Intel ICH SPI controller working under descriptor mode).
--	 */
--	if (JEDEC_MFR(info) == SPI_FLASH_CFI_MFR_ATMEL ||
--	   (JEDEC_MFR(info) == SPI_FLASH_CFI_MFR_SST) ||
--	   (JEDEC_MFR(info) == SPI_FLASH_CFI_MFR_MACRONIX)) {
--		u8 sr = 0;
--
--		if (JEDEC_MFR(info) == SPI_FLASH_CFI_MFR_MACRONIX) {
--			read_sr(flash, &sr);
--			sr &= STATUS_QEB_MXIC;
--		}
--		write_sr(flash, sr);
--	}
--
--	flash->name = info->name;
--	flash->memory_map = spi->memory_map;
--
--	if (info->flags & SST_WR)
--		flash->flags |= SNOR_F_SST_WR;
--
--#ifndef CONFIG_DM_SPI_FLASH
--	flash->write = spi_flash_cmd_write_ops;
--#if defined(CONFIG_SPI_FLASH_SST)
--	if (flash->flags & SNOR_F_SST_WR) {
--		if (spi->mode & SPI_TX_BYTE)
--			flash->write = sst_write_bp;
--		else
--			flash->write = sst_write_wp;
--	}
--#endif
--	flash->erase = spi_flash_cmd_erase_ops;
--	flash->read = spi_flash_cmd_read_ops;
--#endif
--
--#if defined(CONFIG_SPI_FLASH_STMICRO) || defined(CONFIG_SPI_FLASH_SST)
--	/* NOR protection support for STmicro/Micron chips and similar */
--	if (JEDEC_MFR(info) == SPI_FLASH_CFI_MFR_STMICRO ||
--	    JEDEC_MFR(info) == SPI_FLASH_CFI_MFR_MICRON ||
--	    JEDEC_MFR(info) == SPI_FLASH_CFI_MFR_SST) {
--		flash->flash_lock = stm_lock;
--		flash->flash_unlock = stm_unlock;
--		flash->flash_is_locked = stm_is_locked;
--	}
--#endif
--
--/* sst26wf series block protection implementation differs from other series */
--#if defined(CONFIG_SPI_FLASH_SST)
--	if (JEDEC_MFR(info) == SPI_FLASH_CFI_MFR_SST && info->id[1] == 0x26) {
--		flash->flash_lock = sst26_lock;
--		flash->flash_unlock = sst26_unlock;
--		flash->flash_is_locked = sst26_is_locked;
--	}
--#endif
--
--	/* Compute the flash size */
--	flash->shift = (flash->dual_flash & SF_DUAL_PARALLEL_FLASH) ? 1 : 0;
--	flash->page_size = info->page_size;
--	/*
--	 * The Spansion S25FS512S, S25FL032P and S25FL064P have 256b pages,
--	 * yet use the 0x4d00 Extended JEDEC code. The rest of the Spansion
--	 * flashes with the 0x4d00 Extended JEDEC code have 512b pages.
--	 * All of the others have 256b pages.
--	 */
--	if (JEDEC_EXT(info) == 0x4d00) {
--		if ((JEDEC_ID(info) != 0x0215) &&
--		    (JEDEC_ID(info) != 0x0216) &&
--		    (JEDEC_ID(info) != 0x0220))
--			flash->page_size = 512;
--	}
--	flash->page_size <<= flash->shift;
--	flash->sector_size = info->sector_size << flash->shift;
--	flash->size = flash->sector_size * info->n_sectors << flash->shift;
--#ifdef CONFIG_SF_DUAL_FLASH
--	if (flash->dual_flash & SF_DUAL_STACKED_FLASH)
--		flash->size <<= 1;
--#endif
--
--#ifdef CONFIG_SPI_FLASH_USE_4K_SECTORS
--	/* Compute erase sector and command */
--	if (info->flags & SECT_4K) {
--		flash->erase_cmd = CMD_ERASE_4K;
--		flash->erase_size = 4096 << flash->shift;
--	} else
--#endif
--	{
--		flash->erase_cmd = CMD_ERASE_64K;
--		flash->erase_size = flash->sector_size;
--	}
--
--	/* Now erase size becomes valid sector size */
--	flash->sector_size = flash->erase_size;
--
--	/* Look for read commands */
--	flash->read_cmd = CMD_READ_ARRAY_FAST;
--	if (spi->mode & SPI_RX_SLOW)
--		flash->read_cmd = CMD_READ_ARRAY_SLOW;
--	else if (spi->mode & SPI_RX_QUAD && info->flags & RD_QUAD)
--		flash->read_cmd = CMD_READ_QUAD_OUTPUT_FAST;
--	else if (spi->mode & SPI_RX_DUAL && info->flags & RD_DUAL)
--		flash->read_cmd = CMD_READ_DUAL_OUTPUT_FAST;
--
--	/* Look for write commands */
--	if (info->flags & WR_QPP && spi->mode & SPI_TX_QUAD)
--		flash->write_cmd = CMD_QUAD_PAGE_PROGRAM;
--	else
--		/* Go for default supported write cmd */
--		flash->write_cmd = CMD_PAGE_PROGRAM;
--
--	/* Set the quad enable bit - only for quad commands */
--	if ((flash->read_cmd == CMD_READ_QUAD_OUTPUT_FAST) ||
--	    (flash->read_cmd == CMD_READ_QUAD_IO_FAST) ||
--	    (flash->write_cmd == CMD_QUAD_PAGE_PROGRAM)) {
--		ret = set_quad_mode(flash, info);
--		if (ret) {
--			debug("SF: Fail to set QEB for %02x\n",
--			      JEDEC_MFR(info));
--			return -EINVAL;
--		}
--	}
--
--	/* Read dummy_byte: dummy byte is determined based on the
--	 * dummy cycles of a particular command.
--	 * Fast commands - dummy_byte = dummy_cycles/8
--	 * I/O commands- dummy_byte = (dummy_cycles * no.of lines)/8
--	 * For I/O commands except cmd[0] everything goes on no.of lines
--	 * based on particular command but incase of fast commands except
--	 * data all go on single line irrespective of command.
--	 */
--	switch (flash->read_cmd) {
--	case CMD_READ_QUAD_IO_FAST:
--		flash->dummy_byte = 2;
--		break;
--	case CMD_READ_ARRAY_SLOW:
--		flash->dummy_byte = 0;
--		break;
--	default:
--		flash->dummy_byte = 1;
--	}
--
--#ifdef CONFIG_SPI_FLASH_STMICRO
--	if (info->flags & E_FSR)
--		flash->flags |= SNOR_F_USE_FSR;
--#endif
--
--	/* Configure the BAR - discover bank cmds and read current bank */
--#ifdef CONFIG_SPI_FLASH_BAR
--	ret = read_bar(flash, info);
--	if (ret < 0)
--		return ret;
--#endif
--
--#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
--	ret = spi_flash_decode_fdt(flash);
--	if (ret) {
--		debug("SF: FDT decode error\n");
--		return -EINVAL;
--	}
--#endif
--
--#ifndef CONFIG_SPL_BUILD
--	printf("SF: Detected %s with page size ", flash->name);
--	print_size(flash->page_size, ", erase size ");
--	print_size(flash->erase_size, ", total ");
--	print_size(flash->size, "");
--	if (flash->memory_map)
--		printf(", mapped at %p", flash->memory_map);
--	puts("\n");
--#endif
--
--#ifndef CONFIG_SPI_FLASH_BAR
--	if (((flash->dual_flash == SF_SINGLE_FLASH) &&
--	     (flash->size > SPI_FLASH_16MB_BOUN)) ||
--	     ((flash->dual_flash > SF_SINGLE_FLASH) &&
--	     (flash->size > SPI_FLASH_16MB_BOUN << 1))) {
--		puts("SF: Warning - Only lower 16MiB accessible,");
--		puts(" Full access #define CONFIG_SPI_FLASH_BAR\n");
--	}
--#endif
--
--	return 0;
--}
-diff --git a/drivers/mtd/spi/spi_flash_ids.c b/drivers/mtd/spi/spi_flash_ids.c
-deleted file mode 100644
-index aef54eccce..0000000000
---- a/drivers/mtd/spi/spi_flash_ids.c
-+++ /dev/null
-@@ -1,213 +0,0 @@
--// SPDX-License-Identifier: GPL-2.0+
--/*
-- * SPI Flash ID's.
-- *
-- * Copyright (C) 2016 Jagan Teki <jagan@openedev.com>
-- * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc.
-- */
--
--#include <common.h>
--#include <spi.h>
--#include <spi_flash.h>
--
--#include "sf_internal.h"
--
--/* Used when the "_ext_id" is two bytes at most */
--#define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags)	\
--		.id = {							\
--			((_jedec_id) >> 16) & 0xff,			\
--			((_jedec_id) >> 8) & 0xff,			\
--			(_jedec_id) & 0xff,				\
--			((_ext_id) >> 8) & 0xff,			\
--			(_ext_id) & 0xff,				\
--			},						\
--		.id_len = (!(_jedec_id) ? 0 : (3 + ((_ext_id) ? 2 : 0))),	\
--		.sector_size = (_sector_size),				\
--		.n_sectors = (_n_sectors),				\
--		.page_size = 256,					\
--		.flags = (_flags),
--
--#define INFO6(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags)	\
--		.id = {							\
--			((_jedec_id) >> 16) & 0xff,			\
--			((_jedec_id) >> 8) & 0xff,			\
--			(_jedec_id) & 0xff,				\
--			((_ext_id) >> 16) & 0xff,			\
--			((_ext_id) >> 8) & 0xff,			\
--			(_ext_id) & 0xff,				\
--			},						\
--		.id_len = 6,						\
--		.sector_size = (_sector_size),				\
--		.n_sectors = (_n_sectors),				\
--		.page_size = 256,					\
--		.flags = (_flags),
--
--const struct spi_flash_info spi_flash_ids[] = {
--#ifdef CONFIG_SPI_FLASH_ATMEL		/* ATMEL */
--	{"at45db011d",	   INFO(0x1f2200, 0x0, 64 * 1024,     4, SECT_4K) },
--	{"at45db021d",	   INFO(0x1f2300, 0x0, 64 * 1024,     8, SECT_4K) },
--	{"at45db041d",	   INFO(0x1f2400, 0x0, 64 * 1024,     8, SECT_4K) },
--	{"at45db081d",	   INFO(0x1f2500, 0x0, 64 * 1024,    16, SECT_4K) },
--	{"at45db161d",	   INFO(0x1f2600, 0x0, 64 * 1024,    32, SECT_4K) },
--	{"at45db321d",	   INFO(0x1f2700, 0x0, 64 * 1024,    64, SECT_4K) },
--	{"at45db641d",	   INFO(0x1f2800, 0x0, 64 * 1024,   128, SECT_4K) },
--	{"at25df321a",     INFO(0x1f4701, 0x0, 64 * 1024,    64, SECT_4K) },
--	{"at25df321",      INFO(0x1f4700, 0x0, 64 * 1024,    64, SECT_4K) },
--	{"at26df081a",     INFO(0x1f4501, 0x0, 64 * 1024,    16, SECT_4K) },
--#endif
--#ifdef CONFIG_SPI_FLASH_EON		/* EON */
--	{"en25q32b",	   INFO(0x1c3016, 0x0, 64 * 1024,    64, 0) },
--	{"en25q64",	   INFO(0x1c3017, 0x0, 64 * 1024,   128, SECT_4K) },
--	{"en25q128b",	   INFO(0x1c3018, 0x0, 64 * 1024,   256, 0) },
--	{"en25s64",	   INFO(0x1c3817, 0x0, 64 * 1024,   128, 0) },
--#endif
--#ifdef CONFIG_SPI_FLASH_GIGADEVICE	/* GIGADEVICE */
--	{"gd25q16c",	   INFO(0xc84015, 0x0, 64 * 1024,    32, RD_FULL | WR_QPP | SECT_4K) },
--	{"gd25q64b",	   INFO(0xc84017, 0x0, 64 * 1024,   128, SECT_4K) },
--	{"gd25q32b",       INFO(0xc84016, 0x0, 64 * 1024,    64, SECT_4K) },
--	{"gd25lq32",	   INFO(0xc86016, 0x0, 64 * 1024,    64, SECT_4K) },
--#endif
--#ifdef CONFIG_SPI_FLASH_ISSI		/* ISSI */
--	{"is25lq040b",	   INFO(0x9d4013, 0x0, 64 * 1024,    8, 0)  },
--	{"is25lp032",	   INFO(0x9d6016, 0x0, 64 * 1024,    64, 0) },
--	{"is25lp064",	   INFO(0x9d6017, 0x0, 64 * 1024,   128, 0) },
--	{"is25lp128",	   INFO(0x9d6018, 0x0, 64 * 1024,   256, 0) },
--	{"is25lp256",	   INFO(0x9d6019, 0x0, 64 * 1024,   512, 0) },
--	{"is25wp032",	   INFO(0x9d7016, 0x0, 64 * 1024,    64, RD_FULL | SECT_4K) },
--	{"is25wp064",	   INFO(0x9d7017, 0x0, 64 * 1024,   128, RD_FULL | SECT_4K) },
--	{"is25wp128",	   INFO(0x9d7018, 0x0, 64 * 1024,   256, RD_FULL | SECT_4K) },
--#endif
--#ifdef CONFIG_SPI_FLASH_MACRONIX	/* MACRONIX */
--	{"mx25l2006e",	   INFO(0xc22012, 0x0, 64 * 1024,     4, 0) },
--	{"mx25l4005",	   INFO(0xc22013, 0x0, 64 * 1024,     8, 0) },
--	{"mx25l8005",	   INFO(0xc22014, 0x0, 64 * 1024,    16, 0) },
--	{"mx25l1605d",	   INFO(0xc22015, 0x0, 64 * 1024,    32, 0) },
--	{"mx25l3205d",	   INFO(0xc22016, 0x0, 64 * 1024,    64, 0) },
--	{"mx25l6405d",	   INFO(0xc22017, 0x0, 64 * 1024,   128, 0) },
--	{"mx25v8035",      INFO(0xc22314, 0x0, 64 * 1024,   16,  0) },
--	{"mx25l12805",	   INFO(0xc22018, 0x0, 64 * 1024,   256, RD_FULL | WR_QPP) },
--	{"mx25l25635f",	   INFO(0xc22019, 0x0, 64 * 1024,   512, RD_FULL | WR_QPP) },
--	{"mx25l51235f",	   INFO(0xc2201a, 0x0, 64 * 1024,  1024, RD_FULL | WR_QPP) },
--	{"mx25l1633e",	   INFO(0xc22415, 0x0, 64 * 1024,    32, RD_FULL | WR_QPP | SECT_4K) },
--	{"mx25u6435f",	   INFO(0xc22537, 0x0, 64 * 1024,   128, RD_FULL | WR_QPP) },
--	{"mx25l12855e",	   INFO(0xc22618, 0x0, 64 * 1024,   256, RD_FULL | WR_QPP) },
--	{"mx25u1635e",     INFO(0xc22535, 0x0, 64 * 1024,  32, SECT_4K) },
--	{"mx25u25635f",    INFO(0xc22539, 0x0, 64 * 1024,   512, RD_FULL | WR_QPP) },
--	{"mx66u51235f",    INFO(0xc2253a, 0x0, 64 * 1024,  1024, RD_FULL | WR_QPP) },
--	{"mx66l1g45g",     INFO(0xc2201b, 0x0, 64 * 1024,  2048, RD_FULL | WR_QPP) },
--	{"mx25r1635f",     INFO(0xc22815, 0x0, 64 * 1024,    32, RD_FULL | WR_QPP) },
--#endif
--#ifdef CONFIG_SPI_FLASH_SPANSION	/* SPANSION */
--	{"s25fl008a",	   INFO(0x010213, 0x0, 64 * 1024,    16, 0) },
--	{"s25fl016a",	   INFO(0x010214, 0x0, 64 * 1024,    32, 0) },
--	{"s25fl032a",	   INFO(0x010215, 0x0, 64 * 1024,    64, 0) },
--	{"s25fl064a",	   INFO(0x010216, 0x0, 64 * 1024,   128, 0) },
--	{"s25fl208k",	   INFO(0x014014, 0x0, 64 * 1024,    16, 0) },
--	{"s25fl116k",	   INFO(0x014015, 0x0, 64 * 1024,    32, 0) },
--	{"s25fl164k",	   INFO(0x014017, 0x0140,  64 * 1024,   128, 0) },
--	{"s25fl128p_256k", INFO(0x012018, 0x0300, 256 * 1024,    64, RD_FULL | WR_QPP) },
--	{"s25fl128p_64k",  INFO(0x012018, 0x0301,  64 * 1024,   256, RD_FULL | WR_QPP) },
--	{"s25fl032p",	   INFO(0x010215, 0x4d00,  64 * 1024,    64, RD_FULL | WR_QPP) },
--	{"s25fl064p",	   INFO(0x010216, 0x4d00,  64 * 1024,   128, RD_FULL | WR_QPP) },
--	{"s25fl128s_256k", INFO(0x012018, 0x4d00, 256 * 1024,    64, RD_FULL | WR_QPP) },
--	{"s25fl128s_64k",  INFO(0x012018, 0x4d01,  64 * 1024,   256, RD_FULL | WR_QPP) },
--	{"s25fl128l",      INFO(0x016018, 0, 64 * 1024,    256, RD_FULL | WR_QPP) },
--	{"s25fl256s_256k", INFO(0x010219, 0x4d00, 256 * 1024,   128, RD_FULL | WR_QPP) },
--	{"s25fs256s_64k",  INFO6(0x010219, 0x4d0181, 64 * 1024, 512, RD_FULL | WR_QPP | SECT_4K) },
--	{"s25fl256s_64k",  INFO(0x010219, 0x4d01,  64 * 1024,   512, RD_FULL | WR_QPP) },
--	{"s25fs512s",      INFO6(0x010220, 0x4d0081, 256 * 1024, 256, RD_FULL | WR_QPP | SECT_4K) },
--	{"s25fl512s_256k", INFO(0x010220, 0x4d00, 256 * 1024,   256, RD_FULL | WR_QPP) },
--	{"s25fl512s_64k",  INFO(0x010220, 0x4d01,  64 * 1024,  1024, RD_FULL | WR_QPP) },
--	{"s25fl512s_512k", INFO(0x010220, 0x4f00, 256 * 1024,   256, RD_FULL | WR_QPP) },
--#endif
--#ifdef CONFIG_SPI_FLASH_STMICRO		/* STMICRO */
--	{"m25p10",	   INFO(0x202011, 0x0, 32 * 1024,     4, 0) },
--	{"m25p20",	   INFO(0x202012, 0x0, 64 * 1024,     4, 0) },
--	{"m25p40",	   INFO(0x202013, 0x0, 64 * 1024,     8, 0) },
--	{"m25p80",	   INFO(0x202014, 0x0, 64 * 1024,    16, 0) },
--	{"m25p16",	   INFO(0x202015, 0x0, 64 * 1024,    32, 0) },
--	{"m25pE16",	   INFO(0x208015, 0x1000, 64 * 1024, 32, 0) },
--	{"m25pX16",	   INFO(0x207115, 0x1000, 64 * 1024, 32, RD_QUAD | RD_DUAL) },
--	{"m25p32",	   INFO(0x202016, 0x0,  64 * 1024,    64, 0) },
--	{"m25p64",	   INFO(0x202017, 0x0,  64 * 1024,   128, 0) },
--	{"m25p128",	   INFO(0x202018, 0x0, 256 * 1024,    64, 0) },
--	{"m25pX64",	   INFO(0x207117, 0x0,  64 * 1024,   128, SECT_4K) },
--	{"n25q016a",       INFO(0x20bb15, 0x0,	64 * 1024,    32, SECT_4K) },
--	{"n25q32",	   INFO(0x20ba16, 0x0,  64 * 1024,    64, RD_FULL | WR_QPP | SECT_4K) },
--	{"n25q32a",	   INFO(0x20bb16, 0x0,  64 * 1024,    64, RD_FULL | WR_QPP | SECT_4K) },
--	{"n25q64",	   INFO(0x20ba17, 0x0,  64 * 1024,   128, RD_FULL | WR_QPP | SECT_4K) },
--	{"n25q64a",	   INFO(0x20bb17, 0x0,  64 * 1024,   128, RD_FULL | WR_QPP | SECT_4K) },
--	{"n25q128",	   INFO(0x20ba18, 0x0,  64 * 1024,   256, RD_FULL | WR_QPP) },
--	{"n25q128a",	   INFO(0x20bb18, 0x0,  64 * 1024,   256, RD_FULL | WR_QPP) },
--	{"n25q256",	   INFO(0x20ba19, 0x0,  64 * 1024,   512, RD_FULL | WR_QPP | E_FSR | SECT_4K) },
--	{"n25q256a",	   INFO(0x20bb19, 0x0,  64 * 1024,   512, RD_FULL | WR_QPP | E_FSR | SECT_4K) },
--	{"n25q512",	   INFO(0x20ba20, 0x0,  64 * 1024,  1024, RD_FULL | WR_QPP | E_FSR | SECT_4K) },
--	{"n25q512a",	   INFO(0x20bb20, 0x0,  64 * 1024,  1024, RD_FULL | WR_QPP | E_FSR | SECT_4K) },
--	{"n25q1024",	   INFO(0x20ba21, 0x0,  64 * 1024,  2048, RD_FULL | WR_QPP | E_FSR | SECT_4K) },
--	{"n25q1024a",	   INFO(0x20bb21, 0x0,  64 * 1024,  2048, RD_FULL | WR_QPP | E_FSR | SECT_4K) },
--	{"mt25qu02g",	   INFO(0x20bb22, 0x0,  64 * 1024,  4096, RD_FULL | WR_QPP | E_FSR | SECT_4K) },
--	{"mt25ql02g",	   INFO(0x20ba22, 0x0,  64 * 1024,  4096, RD_FULL | WR_QPP | E_FSR | SECT_4K) },
--	{"mt35xu512g",	   INFO6(0x2c5b1a, 0x104100,  128 * 1024,  512, E_FSR | SECT_4K) },
--#endif
--#ifdef CONFIG_SPI_FLASH_SST		/* SST */
--	{"sst25vf040b",	   INFO(0xbf258d, 0x0,	64 * 1024,     8, SECT_4K | SST_WR) },
--	{"sst25vf080b",	   INFO(0xbf258e, 0x0,	64 * 1024,    16, SECT_4K | SST_WR) },
--	{"sst25vf016b",	   INFO(0xbf2541, 0x0,	64 * 1024,    32, SECT_4K | SST_WR) },
--	{"sst25vf032b",	   INFO(0xbf254a, 0x0,	64 * 1024,    64, SECT_4K | SST_WR) },
--	{"sst25vf064c",	   INFO(0xbf254b, 0x0,	64 * 1024,   128, SECT_4K) },
--	{"sst25wf512",	   INFO(0xbf2501, 0x0,	64 * 1024,     1, SECT_4K | SST_WR) },
--	{"sst25wf010",	   INFO(0xbf2502, 0x0,	64 * 1024,     2, SECT_4K | SST_WR) },
--	{"sst25wf020",	   INFO(0xbf2503, 0x0,	64 * 1024,     4, SECT_4K | SST_WR) },
--	{"sst25wf040",	   INFO(0xbf2504, 0x0,	64 * 1024,     8, SECT_4K | SST_WR) },
--	{"sst25wf040b",	   INFO(0x621613, 0x0,	64 * 1024,     8, SECT_4K) },
--	{"sst25wf080",	   INFO(0xbf2505, 0x0,	64 * 1024,    16, SECT_4K | SST_WR) },
--	{"sst26wf016",	   INFO(0xbf2651, 0x0,	64 * 1024,    32, SECT_4K) },
--	{"sst26wf032",	   INFO(0xbf2622, 0x0,	64 * 1024,    64, SECT_4K) },
--	{"sst26wf064",	   INFO(0xbf2643, 0x0,	64 * 1024,   128, SECT_4K) },
--#endif
--#ifdef CONFIG_SPI_FLASH_WINBOND		/* WINBOND */
--	{"w25p80",	   INFO(0xef2014, 0x0,	64 * 1024,    16, 0) },
--	{"w25p16",	   INFO(0xef2015, 0x0,	64 * 1024,    32, 0) },
--	{"w25p32",	   INFO(0xef2016, 0x0,	64 * 1024,    64, 0) },
--	{"w25x40",	   INFO(0xef3013, 0x0,	64 * 1024,     8, SECT_4K) },
--	{"w25x16",	   INFO(0xef3015, 0x0,	64 * 1024,    32, SECT_4K) },
--	{"w25x32",	   INFO(0xef3016, 0x0,	64 * 1024,    64, SECT_4K) },
--	{"w25x64",	   INFO(0xef3017, 0x0,	64 * 1024,   128, SECT_4K) },
--	{"w25q80bl",	   INFO(0xef4014, 0x0,	64 * 1024,    16, RD_FULL | WR_QPP | SECT_4K) },
--	{"w25q16cl",	   INFO(0xef4015, 0x0,	64 * 1024,    32, RD_FULL | WR_QPP | SECT_4K) },
--	{"w25q32bv",	   INFO(0xef4016, 0x0,	64 * 1024,    64, RD_FULL | WR_QPP | SECT_4K) },
--	{"w25q64cv",	   INFO(0xef4017, 0x0,	64 * 1024,   128, RD_FULL | WR_QPP | SECT_4K) },
--	{"w25q128bv",	   INFO(0xef4018, 0x0,	64 * 1024,   256, RD_FULL | WR_QPP | SECT_4K) },
--	{"w25q256",	   INFO(0xef4019, 0x0,	64 * 1024,   512, RD_FULL | WR_QPP | SECT_4K) },
--	{"w25q80bw",	   INFO(0xef5014, 0x0,	64 * 1024,    16, RD_FULL | WR_QPP | SECT_4K) },
--	{"w25q16dw",	   INFO(0xef6015, 0x0,	64 * 1024,    32, RD_FULL | WR_QPP | SECT_4K) },
--	{"w25q16jv",	   INFO(0xef7015, 0x0,	64 * 1024,    32, RD_FULL | WR_QPP | SECT_4K) },
--	{"w25q32dw",	   INFO(0xef6016, 0x0,	64 * 1024,    64, RD_FULL | WR_QPP | SECT_4K) },
--	{"w25q32jv",	   INFO(0xef7016, 0x0,	64 * 1024,    64, RD_FULL | WR_QPP | SECT_4K) },
--	{"w25q64dw",	   INFO(0xef6017, 0x0,	64 * 1024,   128, RD_FULL | WR_QPP | SECT_4K) },
--	{"w25q64jv",	   INFO(0xef7017, 0x0,	64 * 1024,   128, RD_FULL | WR_QPP | SECT_4K) },
--	{"w25q128fw",	   INFO(0xef6018, 0x0,	64 * 1024,   256, RD_FULL | WR_QPP | SECT_4K) },
--	{"w25q128jv",	   INFO(0xef7018, 0x0,	64 * 1024,   256, RD_FULL | WR_QPP | SECT_4K) },
--	{"w25q256fw",	   INFO(0xef6019, 0x0,	64 * 1024,   512, RD_FULL | WR_QPP | SECT_4K) },
--	{"w25q256jw",	   INFO(0xef7019, 0x0,	64 * 1024,   512, RD_FULL | WR_QPP | SECT_4K) },
--#endif
--#ifdef CONFIG_SPI_FLASH_XMC /* Wuhan Xinxin Semiconductor Manufacturing Corp */
--	{ "xm25qh64a",	   INFO(0x207017, 0x0, 64 * 1024,    128, SECT_4K | RD_DUAL | RD_QUAD) },
--	{ "xm25qh128a",	   INFO(0x207018, 0x0, 64 * 1024,    256, SECT_4K | RD_DUAL | RD_QUAD) },
--#endif
--	{},	/* Empty entry to terminate the list */
--	/*
--	 * Note:
--	 * Below paired flash devices has similar spi_flash params.
--	 * (s25fl129p_64k, s25fl128s_64k)
--	 * (w25q80bl, w25q80bv)
--	 * (w25q16cl, w25q16dv, w25q16jv)
--	 * (w25q32bv, w25q32fv_spi)
--	 * (w25q64cv, w25q64fv_spi)
--	 * (w25q128bv, w25q128fv_spi)
--	 * (w25q32dw, w25q32fv_qpi)
--	 * (w25q64dw, w25q64fv_qpi)
--	 * (w25q128fw, w25q128fv_qpi)
--	 * (w25q256fw, w25q256fv_qpi)
--	 */
--};
-diff --git a/drivers/mtd/ubi/debug.h b/drivers/mtd/ubi/debug.h
-index 8ad0c62733..2c2faaf1b4 100644
---- a/drivers/mtd/ubi/debug.h
-+++ b/drivers/mtd/ubi/debug.h
-@@ -18,6 +18,7 @@ void ubi_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr);
- 
- #include <hexdump.h>
- 
-+#ifndef __UBOOT__
- #define ubi_assert(expr)  do {                                               \
- 	if (unlikely(!(expr))) {                                             \
- 		pr_crit("UBI assert failed in %s at %u (pid %d)\n",          \
-@@ -25,6 +26,15 @@ void ubi_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr);
- 		dump_stack();                                                \
- 	}                                                                    \
- } while (0)
-+#else
-+#define ubi_assert(expr)  do {                                               \
-+	if (unlikely(!(expr))) {                                             \
-+		pr_debug("UBI assert failed in %s at %u\n",                  \
-+		       __func__, __LINE__);                                  \
-+		dump_stack();                                                \
-+	}                                                                    \
-+} while (0)
-+#endif
- 
- #define ubi_dbg_print_hex_dump(ps, pt, r, g, b, len, a)                      \
- 		print_hex_dump(ps, pt, r, g, b, len, a)
-diff --git a/include/linux/mtd/cfi.h b/include/linux/mtd/cfi.h
-new file mode 100644
-index 0000000000..3555518bd3
---- /dev/null
-+++ b/include/linux/mtd/cfi.h
-@@ -0,0 +1,32 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * Copyright © 2000-2010 David Woodhouse <dwmw2@infradead.org> et al.
-+ *
-+ */
-+
-+#ifndef __MTD_CFI_H__
-+#define __MTD_CFI_H__
-+
-+#define CFI_MFR_ANY		0xFFFF
-+#define CFI_ID_ANY		0xFFFF
-+#define CFI_MFR_CONTINUATION	0x007F
-+
-+#define CFI_MFR_AMD		0x0001
-+#define CFI_MFR_AMIC		0x0037
-+#define CFI_MFR_ATMEL		0x001F
-+#define CFI_MFR_EON		0x001C
-+#define CFI_MFR_FUJITSU		0x0004
-+#define CFI_MFR_HYUNDAI		0x00AD
-+#define CFI_MFR_INTEL		0x0089
-+#define CFI_MFR_MACRONIX	0x00C2
-+#define CFI_MFR_NEC		0x0010
-+#define CFI_MFR_PMC		0x009D
-+#define CFI_MFR_SAMSUNG		0x00EC
-+#define CFI_MFR_SHARP		0x00B0
-+#define CFI_MFR_SST		0x00BF
-+#define CFI_MFR_ST		0x0020 /* STMicroelectronics */
-+#define CFI_MFR_MICRON		0x002C	/* Micron */
-+#define CFI_MFR_TOSHIBA		0x0098
-+#define CFI_MFR_WINBOND		0x00DA
-+
-+#endif /* __MTD_CFI_H__ */
-diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
-index 9cb0e438d8..9b7e2cbf0e 100644
---- a/include/linux/mtd/mtd.h
-+++ b/include/linux/mtd/mtd.h
-@@ -366,6 +366,8 @@ static inline bool mtd_has_partitions(const struct mtd_info *mtd)
- 	return !list_empty(&mtd->partitions);
- }
- 
-+bool mtd_partitions_used(struct mtd_info *master);
-+
- int mtd_ooblayout_ecc(struct mtd_info *mtd, int section,
- 		      struct mtd_oob_region *oobecc);
- int mtd_ooblayout_find_eccregion(struct mtd_info *mtd, int eccbyte,
-@@ -390,7 +392,7 @@ static inline void mtd_set_ooblayout(struct mtd_info *mtd,
- 	mtd->ooblayout = ooblayout;
- }
- 
--static inline int mtd_oobavail(struct mtd_info *mtd, struct mtd_oob_ops *ops)
-+static inline u32 mtd_oobavail(struct mtd_info *mtd, struct mtd_oob_ops *ops)
- {
- 	return ops->mode == MTD_OPS_AUTO_OOB ? mtd->oobavail : mtd->oobsize;
- }
-@@ -562,8 +564,23 @@ unsigned mtd_mmap_capabilities(struct mtd_info *mtd);
- /* drivers/mtd/mtdcore.h */
- int add_mtd_device(struct mtd_info *mtd);
- int del_mtd_device(struct mtd_info *mtd);
-+
-+#ifdef CONFIG_MTD_PARTITIONS
- int add_mtd_partitions(struct mtd_info *, const struct mtd_partition *, int);
- int del_mtd_partitions(struct mtd_info *);
-+#else
-+static inline int add_mtd_partitions(struct mtd_info *mtd,
-+				     const struct mtd_partition *parts,
-+				     int nparts)
-+{
-+	return 0;
-+}
-+
-+static inline int del_mtd_partitions(struct mtd_info *mtd)
-+{
-+	return 0;
-+}
-+#endif
- 
- struct mtd_info *__mtd_next_device(int i);
- #define mtd_for_each_device(mtd)			\
-@@ -581,6 +598,7 @@ int mtd_arg_off_size(int argc, char *const argv[], int *idx, loff_t *off,
- void mtd_get_len_incl_bad(struct mtd_info *mtd, uint64_t offset,
- 			  const uint64_t length, uint64_t *len_incl_bad,
- 			  int *truncated);
-+bool mtd_dev_list_updated(void);
- 
- /* drivers/mtd/mtd_uboot.c */
- int mtd_search_alternate_name(const char *mtdname, char *altname,
-diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h
-index 9f5dc81aca..bd373b9617 100644
---- a/include/linux/mtd/rawnand.h
-+++ b/include/linux/mtd/rawnand.h
-@@ -15,6 +15,7 @@
- 
- #include <config.h>
- 
-+#include <dm/device.h>
- #include <linux/compat.h>
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/flashchip.h>
-@@ -498,6 +499,13 @@ struct nand_hw_control {
- 	struct nand_chip *active;
- };
- 
-+static inline void nand_hw_control_init(struct nand_hw_control *nfc)
-+{
-+	nfc->active = NULL;
-+	spin_lock_init(&nfc->lock);
-+	init_waitqueue_head(&nfc->wq);
-+}
-+
- /**
-  * struct nand_ecc_step_info - ECC step information of ECC engine
-  * @stepsize: data bytes per ECC step
-@@ -961,6 +969,17 @@ struct nand_chip {
- 	void *priv;
- };
- 
-+static inline void nand_set_flash_node(struct nand_chip *chip,
-+				       ofnode node)
-+{
-+	chip->flash_node = ofnode_to_offset(node);
-+}
-+
-+static inline ofnode nand_get_flash_node(struct nand_chip *chip)
-+{
-+	return offset_to_ofnode(chip->flash_node);
-+}
-+
- static inline struct nand_chip *mtd_to_nand(struct mtd_info *mtd)
- {
- 	return container_of(mtd, struct nand_chip, mtd);
-@@ -1280,4 +1299,34 @@ int nand_maximize_ecc(struct nand_chip *chip,
- 
- /* Reset and initialize a NAND device */
- int nand_reset(struct nand_chip *chip, int chipnr);
-+
-+/* NAND operation helpers */
-+int nand_reset_op(struct nand_chip *chip);
-+int nand_readid_op(struct nand_chip *chip, u8 addr, void *buf,
-+		   unsigned int len);
-+int nand_status_op(struct nand_chip *chip, u8 *status);
-+int nand_exit_status_op(struct nand_chip *chip);
-+int nand_erase_op(struct nand_chip *chip, unsigned int eraseblock);
-+int nand_read_page_op(struct nand_chip *chip, unsigned int page,
-+		      unsigned int offset_in_page, void *buf, unsigned int len);
-+int nand_change_read_column_op(struct nand_chip *chip,
-+			       unsigned int offset_in_page, void *buf,
-+			       unsigned int len, bool force_8bit);
-+int nand_read_oob_op(struct nand_chip *chip, unsigned int page,
-+		     unsigned int offset_in_page, void *buf, unsigned int len);
-+int nand_prog_page_begin_op(struct nand_chip *chip, unsigned int page,
-+			    unsigned int offset_in_page, const void *buf,
-+			    unsigned int len);
-+int nand_prog_page_end_op(struct nand_chip *chip);
-+int nand_prog_page_op(struct nand_chip *chip, unsigned int page,
-+		      unsigned int offset_in_page, const void *buf,
-+		      unsigned int len);
-+int nand_change_write_column_op(struct nand_chip *chip,
-+				unsigned int offset_in_page, const void *buf,
-+				unsigned int len, bool force_8bit);
-+int nand_read_data_op(struct nand_chip *chip, void *buf, unsigned int len,
-+		      bool force_8bit);
-+int nand_write_data_op(struct nand_chip *chip, const void *buf,
-+		       unsigned int len, bool force_8bit);
-+
- #endif /* __LINUX_MTD_RAWNAND_H */
-diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
-new file mode 100644
-index 0000000000..88e80af579
---- /dev/null
-+++ b/include/linux/mtd/spi-nor.h
-@@ -0,0 +1,419 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * Copyright (C) 2014 Freescale Semiconductor, Inc.
-+ * Synced from Linux v4.19
-+ */
-+
-+#ifndef __LINUX_MTD_SPI_NOR_H
-+#define __LINUX_MTD_SPI_NOR_H
-+
-+#include <linux/bitops.h>
-+#include <linux/mtd/cfi.h>
-+#include <linux/mtd/mtd.h>
-+
-+/*
-+ * Manufacturer IDs
-+ *
-+ * The first byte returned from the flash after sending opcode SPINOR_OP_RDID.
-+ * Sometimes these are the same as CFI IDs, but sometimes they aren't.
-+ */
-+#define SNOR_MFR_ATMEL		CFI_MFR_ATMEL
-+#define SNOR_MFR_GIGADEVICE	0xc8
-+#define SNOR_MFR_INTEL		CFI_MFR_INTEL
-+#define SNOR_MFR_ST		CFI_MFR_ST /* ST Micro <--> Micron */
-+#define SNOR_MFR_MICRON		CFI_MFR_MICRON /* ST Micro <--> Micron */
-+#define SNOR_MFR_MACRONIX	CFI_MFR_MACRONIX
-+#define SNOR_MFR_SPANSION	CFI_MFR_AMD
-+#define SNOR_MFR_SST		CFI_MFR_SST
-+#define SNOR_MFR_WINBOND	0xef /* Also used by some Spansion */
-+
-+/*
-+ * Note on opcode nomenclature: some opcodes have a format like
-+ * SPINOR_OP_FUNCTION{4,}_x_y_z. The numbers x, y, and z stand for the number
-+ * of I/O lines used for the opcode, address, and data (respectively). The
-+ * FUNCTION has an optional suffix of '4', to represent an opcode which
-+ * requires a 4-byte (32-bit) address.
-+ */
-+
-+/* Flash opcodes. */
-+#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) */
-+#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 */
-+#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 */
-+#define SPINOR_OP_CLFSR		0x50	/* Clear flag status register */
-+#define SPINOR_OP_RDEAR		0xc8	/* Read Extended Address Register */
-+#define SPINOR_OP_WREAR		0xc5	/* Write Extended Address Register */
-+
-+/* 4-byte address opcodes - used on Spansion and some Macronix flashes. */
-+#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) */
-+
-+/* Double Transfer Rate opcodes - defined in JEDEC JESD216B. */
-+#define SPINOR_OP_READ_1_1_1_DTR	0x0d
-+#define SPINOR_OP_READ_1_2_2_DTR	0xbd
-+#define SPINOR_OP_READ_1_4_4_DTR	0xed
-+
-+#define SPINOR_OP_READ_1_1_1_DTR_4B	0x0e
-+#define SPINOR_OP_READ_1_2_2_DTR_4B	0xbe
-+#define SPINOR_OP_READ_1_4_4_DTR_4B	0xee
-+
-+/* Used for SST flashes only. */
-+#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 */
-+
-+/* Used for S3AN flashes only */
-+#define SPINOR_OP_XSE		0x50	/* Sector erase */
-+#define SPINOR_OP_XPP		0x82	/* Page program */
-+#define SPINOR_OP_XRDSR		0xd7	/* Read status register */
-+
-+#define XSR_PAGESIZE		BIT(0)	/* Page size in Po2 or Linear */
-+#define XSR_RDY			BIT(7)	/* Ready */
-+
-+/* Used for Macronix and Winbond flashes. */
-+#define SPINOR_OP_EN4B		0xb7	/* Enter 4-byte mode */
-+#define SPINOR_OP_EX4B		0xe9	/* Exit 4-byte mode */
-+
-+/* Used for Spansion flashes only. */
-+#define SPINOR_OP_BRWR		0x17	/* Bank register write */
-+#define SPINOR_OP_BRRD		0x16	/* Bank register read */
-+#define SPINOR_OP_CLSR		0x30	/* Clear status register 1 */
-+
-+/* Used for Micron flashes only. */
-+#define SPINOR_OP_RD_EVCR      0x65    /* Read EVCR register */
-+#define SPINOR_OP_WD_EVCR      0x61    /* Write EVCR register */
-+
-+/* Status Register bits. */
-+#define SR_WIP			BIT(0)	/* Write in progress */
-+#define SR_WEL			BIT(1)	/* Write enable latch */
-+/* meaning of other SR_* bits may differ between vendors */
-+#define SR_BP0			BIT(2)	/* Block protect 0 */
-+#define SR_BP1			BIT(3)	/* Block protect 1 */
-+#define SR_BP2			BIT(4)	/* Block protect 2 */
-+#define SR_TB			BIT(5)	/* Top/Bottom protect */
-+#define SR_SRWD			BIT(7)	/* SR write protect */
-+/* Spansion/Cypress specific status bits */
-+#define SR_E_ERR		BIT(5)
-+#define SR_P_ERR		BIT(6)
-+
-+#define SR_QUAD_EN_MX		BIT(6)	/* Macronix Quad I/O */
-+
-+/* Enhanced Volatile Configuration Register bits */
-+#define EVCR_QUAD_EN_MICRON	BIT(7)	/* Micron Quad I/O */
-+
-+/* Flag Status Register bits */
-+#define FSR_READY		BIT(7)	/* Device status, 0 = Busy, 1 = Ready */
-+#define FSR_E_ERR		BIT(5)	/* Erase operation status */
-+#define FSR_P_ERR		BIT(4)	/* Program operation status */
-+#define FSR_PT_ERR		BIT(1)	/* Protection error bit */
-+
-+/* 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 */
-+#define SNOR_PROTO_INST_MASK	GENMASK(23, 16)
-+#define SNOR_PROTO_INST_SHIFT	16
-+#define SNOR_PROTO_INST(_nbits)	\
-+	((((unsigned long)(_nbits)) << SNOR_PROTO_INST_SHIFT) & \
-+	 SNOR_PROTO_INST_MASK)
-+
-+#define SNOR_PROTO_ADDR_MASK	GENMASK(15, 8)
-+#define SNOR_PROTO_ADDR_SHIFT	8
-+#define SNOR_PROTO_ADDR(_nbits)	\
-+	((((unsigned long)(_nbits)) << SNOR_PROTO_ADDR_SHIFT) & \
-+	 SNOR_PROTO_ADDR_MASK)
-+
-+#define SNOR_PROTO_DATA_MASK	GENMASK(7, 0)
-+#define SNOR_PROTO_DATA_SHIFT	0
-+#define SNOR_PROTO_DATA(_nbits)	\
-+	((((unsigned long)(_nbits)) << SNOR_PROTO_DATA_SHIFT) & \
-+	 SNOR_PROTO_DATA_MASK)
-+
-+#define SNOR_PROTO_IS_DTR	BIT(24)	/* Double Transfer Rate */
-+
-+#define SNOR_PROTO_STR(_inst_nbits, _addr_nbits, _data_nbits)	\
-+	(SNOR_PROTO_INST(_inst_nbits) |				\
-+	 SNOR_PROTO_ADDR(_addr_nbits) |				\
-+	 SNOR_PROTO_DATA(_data_nbits))
-+#define SNOR_PROTO_DTR(_inst_nbits, _addr_nbits, _data_nbits)	\
-+	(SNOR_PROTO_IS_DTR |					\
-+	 SNOR_PROTO_STR(_inst_nbits, _addr_nbits, _data_nbits))
-+
-+enum spi_nor_protocol {
-+	SNOR_PROTO_1_1_1 = SNOR_PROTO_STR(1, 1, 1),
-+	SNOR_PROTO_1_1_2 = SNOR_PROTO_STR(1, 1, 2),
-+	SNOR_PROTO_1_1_4 = SNOR_PROTO_STR(1, 1, 4),
-+	SNOR_PROTO_1_1_8 = SNOR_PROTO_STR(1, 1, 8),
-+	SNOR_PROTO_1_2_2 = SNOR_PROTO_STR(1, 2, 2),
-+	SNOR_PROTO_1_4_4 = SNOR_PROTO_STR(1, 4, 4),
-+	SNOR_PROTO_1_8_8 = SNOR_PROTO_STR(1, 8, 8),
-+	SNOR_PROTO_2_2_2 = SNOR_PROTO_STR(2, 2, 2),
-+	SNOR_PROTO_4_4_4 = SNOR_PROTO_STR(4, 4, 4),
-+	SNOR_PROTO_8_8_8 = SNOR_PROTO_STR(8, 8, 8),
-+
-+	SNOR_PROTO_1_1_1_DTR = SNOR_PROTO_DTR(1, 1, 1),
-+	SNOR_PROTO_1_2_2_DTR = SNOR_PROTO_DTR(1, 2, 2),
-+	SNOR_PROTO_1_4_4_DTR = SNOR_PROTO_DTR(1, 4, 4),
-+	SNOR_PROTO_1_8_8_DTR = SNOR_PROTO_DTR(1, 8, 8),
-+};
-+
-+static inline bool spi_nor_protocol_is_dtr(enum spi_nor_protocol proto)
-+{
-+	return !!(proto & SNOR_PROTO_IS_DTR);
-+}
-+
-+static inline u8 spi_nor_get_protocol_inst_nbits(enum spi_nor_protocol proto)
-+{
-+	return ((unsigned long)(proto & SNOR_PROTO_INST_MASK)) >>
-+		SNOR_PROTO_INST_SHIFT;
-+}
-+
-+static inline u8 spi_nor_get_protocol_addr_nbits(enum spi_nor_protocol proto)
-+{
-+	return ((unsigned long)(proto & SNOR_PROTO_ADDR_MASK)) >>
-+		SNOR_PROTO_ADDR_SHIFT;
-+}
-+
-+static inline u8 spi_nor_get_protocol_data_nbits(enum spi_nor_protocol proto)
-+{
-+	return ((unsigned long)(proto & SNOR_PROTO_DATA_MASK)) >>
-+		SNOR_PROTO_DATA_SHIFT;
-+}
-+
-+static inline u8 spi_nor_get_protocol_width(enum spi_nor_protocol proto)
-+{
-+	return spi_nor_get_protocol_data_nbits(proto);
-+}
-+
-+#define SPI_NOR_MAX_CMD_SIZE	8
-+enum spi_nor_ops {
-+	SPI_NOR_OPS_READ = 0,
-+	SPI_NOR_OPS_WRITE,
-+	SPI_NOR_OPS_ERASE,
-+	SPI_NOR_OPS_LOCK,
-+	SPI_NOR_OPS_UNLOCK,
-+};
-+
-+enum spi_nor_option_flags {
-+	SNOR_F_USE_FSR		= BIT(0),
-+	SNOR_F_HAS_SR_TB	= BIT(1),
-+	SNOR_F_NO_OP_CHIP_ERASE	= BIT(2),
-+	SNOR_F_S3AN_ADDR_DEFAULT = BIT(3),
-+	SNOR_F_READY_XSR_RDY	= BIT(4),
-+	SNOR_F_USE_CLSR		= BIT(5),
-+	SNOR_F_BROKEN_RESET	= BIT(6),
-+};
-+
-+/**
-+ * struct flash_info - Forward declaration of a structure used internally by
-+ *		       spi_nor_scan()
-+ */
-+struct flash_info;
-+
-+/* TODO: Remove, once all users of spi_flash interface are moved to MTD */
-+#define spi_flash spi_nor
-+
-+/**
-+ * struct spi_nor - Structure for defining a the SPI NOR layer
-+ * @mtd:		point to a mtd_info structure
-+ * @lock:		the lock for the read/write/erase/lock/unlock operations
-+ * @dev:		point to a spi device, or a spi nor controller device.
-+ * @info:		spi-nor part JDEC MFR id and other info
-+ * @page_size:		the page size of the SPI NOR
-+ * @addr_width:		number of address bytes
-+ * @erase_opcode:	the opcode for erasing a sector
-+ * @read_opcode:	the read opcode
-+ * @read_dummy:		the dummy needed by the read operation
-+ * @program_opcode:	the program opcode
-+ * @bank_read_cmd:	Bank read cmd
-+ * @bank_write_cmd:	Bank write cmd
-+ * @bank_curr:		Current flash bank
-+ * @sst_write_second:	used by the SST write operation
-+ * @flags:		flag options for the current SPI-NOR (SNOR_F_*)
-+ * @read_proto:		the SPI protocol for read operations
-+ * @write_proto:	the SPI protocol for write operations
-+ * @reg_proto		the SPI protocol for read_reg/write_reg/erase operations
-+ * @cmd_buf:		used by the write_reg
-+ * @prepare:		[OPTIONAL] do some preparations for the
-+ *			read/write/erase/lock/unlock operations
-+ * @unprepare:		[OPTIONAL] do some post work after the
-+ *			read/write/erase/lock/unlock operations
-+ * @read_reg:		[DRIVER-SPECIFIC] read out the register
-+ * @write_reg:		[DRIVER-SPECIFIC] write data to the register
-+ * @read:		[DRIVER-SPECIFIC] read data from the SPI NOR
-+ * @write:		[DRIVER-SPECIFIC] write data to the SPI NOR
-+ * @erase:		[DRIVER-SPECIFIC] erase a sector of the SPI NOR
-+ *			at the offset @offs; if not provided by the driver,
-+ *			spi-nor will send the erase opcode via write_reg()
-+ * @flash_lock:		[FLASH-SPECIFIC] lock a region of the SPI NOR
-+ * @flash_unlock:	[FLASH-SPECIFIC] unlock a region of the SPI NOR
-+ * @flash_is_locked:	[FLASH-SPECIFIC] check if a region of the SPI NOR is
-+ * @quad_enable:	[FLASH-SPECIFIC] enables SPI NOR quad mode
-+ *			completely locked
-+ * @priv:		the private data
-+ */
-+struct spi_nor {
-+	struct mtd_info		mtd;
-+	struct udevice		*dev;
-+	struct spi_slave	*spi;
-+	const struct flash_info	*info;
-+	u32			page_size;
-+	u8			addr_width;
-+	u8			erase_opcode;
-+	u8			read_opcode;
-+	u8			read_dummy;
-+	u8			program_opcode;
-+#ifdef CONFIG_SPI_FLASH_BAR
-+	u8			bank_read_cmd;
-+	u8			bank_write_cmd;
-+	u8			bank_curr;
-+#endif
-+	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];
-+
-+	int (*prepare)(struct spi_nor *nor, enum spi_nor_ops ops);
-+	void (*unprepare)(struct spi_nor *nor, enum spi_nor_ops ops);
-+	int (*read_reg)(struct spi_nor *nor, u8 opcode, u8 *buf, int len);
-+	int (*write_reg)(struct spi_nor *nor, u8 opcode, u8 *buf, int len);
-+
-+	ssize_t (*read)(struct spi_nor *nor, loff_t from,
-+			size_t len, u_char *read_buf);
-+	ssize_t (*write)(struct spi_nor *nor, loff_t to,
-+			 size_t len, const u_char *write_buf);
-+	int (*erase)(struct spi_nor *nor, loff_t offs);
-+
-+	int (*flash_lock)(struct spi_nor *nor, loff_t ofs, uint64_t len);
-+	int (*flash_unlock)(struct spi_nor *nor, loff_t ofs, uint64_t len);
-+	int (*flash_is_locked)(struct spi_nor *nor, loff_t ofs, uint64_t len);
-+	int (*quad_enable)(struct spi_nor *nor);
-+
-+	void *priv;
-+/* Compatibility for spi_flash, remove once sf layer is merged with mtd */
-+	const char *name;
-+	u32 size;
-+	u32 sector_size;
-+	u32 erase_size;
-+};
-+
-+static inline void spi_nor_set_flash_node(struct spi_nor *nor,
-+					  const struct device_node *np)
-+{
-+	mtd_set_of_node(&nor->mtd, np);
-+}
-+
-+static inline const struct
-+device_node *spi_nor_get_flash_node(struct spi_nor *nor)
-+{
-+	return mtd_get_of_node(&nor->mtd);
-+}
-+
-+/**
-+ * struct spi_nor_hwcaps - Structure for describing the hardware capabilies
-+ * supported by the SPI controller (bus master).
-+ * @mask:		the bitmask listing all the supported hw capabilies
-+ */
-+struct spi_nor_hwcaps {
-+	u32	mask;
-+};
-+
-+/*
-+ *(Fast) Read capabilities.
-+ * MUST be ordered by priority: the higher bit position, the higher priority.
-+ * As a matter of performances, it is relevant to use Octo SPI protocols first,
-+ * then Quad SPI protocols before Dual SPI protocols, Fast Read and lastly
-+ * (Slow) Read.
-+ */
-+#define SNOR_HWCAPS_READ_MASK		GENMASK(14, 0)
-+#define SNOR_HWCAPS_READ		BIT(0)
-+#define SNOR_HWCAPS_READ_FAST		BIT(1)
-+#define SNOR_HWCAPS_READ_1_1_1_DTR	BIT(2)
-+
-+#define SNOR_HWCAPS_READ_DUAL		GENMASK(6, 3)
-+#define SNOR_HWCAPS_READ_1_1_2		BIT(3)
-+#define SNOR_HWCAPS_READ_1_2_2		BIT(4)
-+#define SNOR_HWCAPS_READ_2_2_2		BIT(5)
-+#define SNOR_HWCAPS_READ_1_2_2_DTR	BIT(6)
-+
-+#define SNOR_HWCAPS_READ_QUAD		GENMASK(10, 7)
-+#define SNOR_HWCAPS_READ_1_1_4		BIT(7)
-+#define SNOR_HWCAPS_READ_1_4_4		BIT(8)
-+#define SNOR_HWCAPS_READ_4_4_4		BIT(9)
-+#define SNOR_HWCAPS_READ_1_4_4_DTR	BIT(10)
-+
-+#define SNOR_HWCPAS_READ_OCTO		GENMASK(14, 11)
-+#define SNOR_HWCAPS_READ_1_1_8		BIT(11)
-+#define SNOR_HWCAPS_READ_1_8_8		BIT(12)
-+#define SNOR_HWCAPS_READ_8_8_8		BIT(13)
-+#define SNOR_HWCAPS_READ_1_8_8_DTR	BIT(14)
-+
-+/*
-+ * Page Program capabilities.
-+ * MUST be ordered by priority: the higher bit position, the higher priority.
-+ * Like (Fast) Read capabilities, Octo/Quad SPI protocols are preferred to the
-+ * legacy SPI 1-1-1 protocol.
-+ * Note that Dual Page Programs are not supported because there is no existing
-+ * JEDEC/SFDP standard to define them. Also at this moment no SPI flash memory
-+ * implements such commands.
-+ */
-+#define SNOR_HWCAPS_PP_MASK	GENMASK(22, 16)
-+#define SNOR_HWCAPS_PP		BIT(16)
-+
-+#define SNOR_HWCAPS_PP_QUAD	GENMASK(19, 17)
-+#define SNOR_HWCAPS_PP_1_1_4	BIT(17)
-+#define SNOR_HWCAPS_PP_1_4_4	BIT(18)
-+#define SNOR_HWCAPS_PP_4_4_4	BIT(19)
-+
-+#define SNOR_HWCAPS_PP_OCTO	GENMASK(22, 20)
-+#define SNOR_HWCAPS_PP_1_1_8	BIT(20)
-+#define SNOR_HWCAPS_PP_1_8_8	BIT(21)
-+#define SNOR_HWCAPS_PP_8_8_8	BIT(22)
-+
-+/**
-+ * spi_nor_scan() - scan the SPI NOR
-+ * @nor:	the spi_nor structure
-+ *
-+ * The drivers can use this function to scan the SPI NOR.
-+ * In the scanning, it will try to get all the necessary information to
-+ * fill the mtd_info{} and the spi_nor{}.
-+ *
-+ * Return: 0 for success, others for failure.
-+ */
-+int spi_nor_scan(struct spi_nor *nor);
-+
-+#endif
-diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
-index be01e1e82e..83eafb184e 100644
---- a/include/linux/mtd/spinand.h
-+++ b/include/linux/mtd/spinand.h
-@@ -204,6 +204,7 @@ struct spinand_manufacturer {
- extern const struct spinand_manufacturer gigadevice_spinand_manufacturer;
- extern const struct spinand_manufacturer macronix_spinand_manufacturer;
- extern const struct spinand_manufacturer micron_spinand_manufacturer;
-+extern const struct spinand_manufacturer toshiba_spinand_manufacturer;
- extern const struct spinand_manufacturer winbond_spinand_manufacturer;
- 
- /**
-diff --git a/include/spi_flash.h b/include/spi_flash.h
-index 0ec98fb55d..55b4721813 100644
---- a/include/spi_flash.h
-+++ b/include/spi_flash.h
-@@ -11,107 +11,42 @@
- 
- #include <dm.h>	/* Because we dereference struct udevice here */
- #include <linux/types.h>
-+#include <linux/mtd/spi-nor.h>
- 
--#ifndef CONFIG_SF_DEFAULT_SPEED
--# define CONFIG_SF_DEFAULT_SPEED	1000000
-+/* by default ENV use the same parameters than SF command */
-+#ifndef CONFIG_ENV_SPI_BUS
-+# define CONFIG_ENV_SPI_BUS	CONFIG_SF_DEFAULT_BUS
- #endif
--#ifndef CONFIG_SF_DEFAULT_MODE
--# define CONFIG_SF_DEFAULT_MODE		SPI_MODE_3
-+#ifndef CONFIG_ENV_SPI_CS
-+# define CONFIG_ENV_SPI_CS	CONFIG_SF_DEFAULT_CS
- #endif
--#ifndef CONFIG_SF_DEFAULT_CS
--# define CONFIG_SF_DEFAULT_CS		0
-+#ifndef CONFIG_ENV_SPI_MAX_HZ
-+# define CONFIG_ENV_SPI_MAX_HZ	CONFIG_SF_DEFAULT_SPEED
- #endif
--#ifndef CONFIG_SF_DEFAULT_BUS
--# define CONFIG_SF_DEFAULT_BUS		0
-+#ifndef CONFIG_ENV_SPI_MODE
-+# define CONFIG_ENV_SPI_MODE	CONFIG_SF_DEFAULT_MODE
- #endif
- 
- struct spi_slave;
- 
--/**
-- * struct spi_flash - SPI flash structure
-- *
-- * @spi:		SPI slave
-- * @dev:		SPI flash device
-- * @name:		Name of SPI flash
-- * @dual_flash:		Indicates dual flash memories - dual stacked, parallel
-- * @shift:		Flash shift useful in dual parallel
-- * @flags:		Indication of spi flash flags
-- * @size:		Total flash size
-- * @page_size:		Write (page) size
-- * @sector_size:	Sector size
-- * @erase_size:		Erase size
-- * @bank_read_cmd:	Bank read cmd
-- * @bank_write_cmd:	Bank write cmd
-- * @bank_curr:		Current flash bank
-- * @erase_cmd:		Erase cmd 4K, 32K, 64K
-- * @read_cmd:		Read cmd - Array Fast, Extn read and quad read.
-- * @write_cmd:		Write cmd - page and quad program.
-- * @dummy_byte:		Dummy cycles for read operation.
-- * @memory_map:		Address of read-only SPI flash access
-- * @flash_lock:		lock a region of the SPI Flash
-- * @flash_unlock:	unlock a region of the SPI Flash
-- * @flash_is_locked:	check if a region of the SPI Flash is completely locked
-- * @read:		Flash read ops: Read len bytes at offset into buf
-- *			Supported cmds: Fast Array Read
-- * @write:		Flash write ops: Write len bytes from buf into offset
-- *			Supported cmds: Page Program
-- * @erase:		Flash erase ops: Erase len bytes from offset
-- *			Supported cmds: Sector erase 4K, 32K, 64K
-- * return 0 - Success, 1 - Failure
-- */
--struct spi_flash {
--	struct spi_slave *spi;
--#ifdef CONFIG_DM_SPI_FLASH
--	struct udevice *dev;
--#endif
--	const char *name;
--	u8 dual_flash;
--	u8 shift;
--	u16 flags;
--
--	u32 size;
--	u32 page_size;
--	u32 sector_size;
--	u32 erase_size;
--#ifdef CONFIG_SPI_FLASH_BAR
--	u8 bank_read_cmd;
--	u8 bank_write_cmd;
--	u8 bank_curr;
--#endif
--	u8 erase_cmd;
--	u8 read_cmd;
--	u8 write_cmd;
--	u8 dummy_byte;
--
--	void *memory_map;
--
--	int (*flash_lock)(struct spi_flash *flash, u32 ofs, size_t len);
--	int (*flash_unlock)(struct spi_flash *flash, u32 ofs, size_t len);
--	int (*flash_is_locked)(struct spi_flash *flash, u32 ofs, size_t len);
--#ifndef CONFIG_DM_SPI_FLASH
--	/*
--	 * These are not strictly needed for driver model, but keep them here
--	 * while the transition is in progress.
--	 *
--	 * Normally each driver would provide its own operations, but for
--	 * SPI flash most chips use the same algorithms. One approach is
--	 * to create a 'common' SPI flash device which knows how to talk
--	 * to most devices, and then allow other drivers to be used instead
--	 * if required, perhaps with a way of scanning through the list to
--	 * find the driver that matches the device.
--	 */
--	int (*read)(struct spi_flash *flash, u32 offset, size_t len, void *buf);
--	int (*write)(struct spi_flash *flash, u32 offset, size_t len,
--			const void *buf);
--	int (*erase)(struct spi_flash *flash, u32 offset, size_t len);
--#endif
--};
--
- struct dm_spi_flash_ops {
- 	int (*read)(struct udevice *dev, u32 offset, size_t len, void *buf);
- 	int (*write)(struct udevice *dev, u32 offset, size_t len,
- 		     const void *buf);
- 	int (*erase)(struct udevice *dev, u32 offset, size_t len);
-+	/**
-+	 * get_sw_write_prot() - Check state of software write-protect feature
-+	 *
-+	 * SPI flash chips can lock a region of the flash defined by a
-+	 * 'protected area'. This function checks if this protected area is
-+	 * defined.
-+	 *
-+	 * @dev:	SPI flash device
-+	 * @return 0 if no region is write-protected, 1 if a region is
-+	 *	write-protected, -ENOSYS if the driver does not implement this,
-+	 *	other -ve value on error
-+	 */
-+	int (*get_sw_write_prot)(struct udevice *dev);
- };
- 
- /* Access the serial operations for a device */
-@@ -153,6 +88,20 @@ int spi_flash_write_dm(struct udevice *dev, u32 offset, size_t len,
-  */
- int spi_flash_erase_dm(struct udevice *dev, u32 offset, size_t len);
- 
-+/**
-+ * spl_flash_get_sw_write_prot() - Check state of software write-protect feature
-+ *
-+ * SPI flash chips can lock a region of the flash defined by a
-+ * 'protected area'. This function checks if this protected area is
-+ * defined.
-+ *
-+ * @dev:	SPI flash device
-+ * @return 0 if no region is write-protected, 1 if a region is
-+ *	write-protected, -ENOSYS if the driver does not implement this,
-+ *	other -ve value on error
-+ */
-+int spl_flash_get_sw_write_prot(struct udevice *dev);
-+
- int spi_flash_probe_bus_cs(unsigned int busnum, unsigned int cs,
- 			   unsigned int max_hz, unsigned int spi_mode,
- 			   struct udevice **devp);
-@@ -198,19 +147,37 @@ void spi_flash_free(struct spi_flash *flash);
- static inline int spi_flash_read(struct spi_flash *flash, u32 offset,
- 		size_t len, void *buf)
- {
--	return flash->read(flash, offset, len, buf);
-+	struct mtd_info *mtd = &flash->mtd;
-+	size_t retlen;
-+
-+	return mtd->_read(mtd, offset, len, &retlen, buf);
- }
- 
- static inline int spi_flash_write(struct spi_flash *flash, u32 offset,
- 		size_t len, const void *buf)
- {
--	return flash->write(flash, offset, len, buf);
-+	struct mtd_info *mtd = &flash->mtd;
-+	size_t retlen;
-+
-+	return mtd->_write(mtd, offset, len, &retlen, buf);
- }
- 
- static inline int spi_flash_erase(struct spi_flash *flash, u32 offset,
- 		size_t len)
- {
--	return flash->erase(flash, offset, len);
-+	struct mtd_info *mtd = &flash->mtd;
-+	struct erase_info instr;
-+
-+	if (offset % mtd->erasesize || len % mtd->erasesize) {
-+		printf("SF: Erase offset/length not multiple of erase size\n");
-+		return -EINVAL;
-+	}
-+
-+	memset(&instr, 0, sizeof(instr));
-+	instr.addr = offset;
-+	instr.len = len;
-+
-+	return mtd->_erase(mtd, &instr);
- }
- #endif
- 
--- 
-2.17.1
-
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/0001-remove-_defconfig-files-from-gitignore.patch b/recipes-bsp/u-boot/u-boot-stm32mp/0001-remove-_defconfig-files-from-gitignore.patch
new file mode 100644
index 0000000000000000000000000000000000000000..16f617eb79bd1e715ebbc5d6059cefc9a5cb2540
--- /dev/null
+++ b/recipes-bsp/u-boot/u-boot-stm32mp/0001-remove-_defconfig-files-from-gitignore.patch
@@ -0,0 +1,23 @@
+From 328553201004a1be632d2b662712afded489d9c5 Mon Sep 17 00:00:00 2001
+From: Eberhard Stoll <eberhard.stoll@exceet.de>
+Date: Fri, 2 Mar 2018 14:40:02 +0100
+Subject: [PATCH 1/5] remove _defconfig files from gitignore
+
+---
+ .gitignore | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/.gitignore b/.gitignore
+index ae6e1ca..9c0d34d 100644
+--- a/.gitignore
++++ b/.gitignore
+@@ -87,5 +87,5 @@ GTAGS
+ \#*#
+ 
+ /oe-*
+-configs/stm32mp*_devicetree_*_defconfig
++#configs/stm32mp*_devicetree_*_defconfig
+ configs/__configs_file_to_clean.txt
+-- 
+2.7.4
+
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/0001-add-NOR-flash-mx25v8035-and-mx25r1635f.patch b/recipes-bsp/u-boot/u-boot-stm32mp/0002-add-NOR-flash-mx25v8035-and-mx25r1635f.patch
similarity index 71%
rename from recipes-bsp/u-boot/u-boot-stm32mp/0001-add-NOR-flash-mx25v8035-and-mx25r1635f.patch
rename to recipes-bsp/u-boot/u-boot-stm32mp/0002-add-NOR-flash-mx25v8035-and-mx25r1635f.patch
index 34d8778576e2d990c1529f25493fa65b329d01f5..cda2617787ecd63b309809a546b67efa129bcf30 100644
--- a/recipes-bsp/u-boot/u-boot-stm32mp/0001-add-NOR-flash-mx25v8035-and-mx25r1635f.patch
+++ b/recipes-bsp/u-boot/u-boot-stm32mp/0002-add-NOR-flash-mx25v8035-and-mx25r1635f.patch
@@ -1,17 +1,17 @@
-From 3e03181bbd4aeadeb303f2b465b7cb31198dda0c Mon Sep 17 00:00:00 2001
+From aa0b71d14b26973c7a9744bd6270e0bdda7c7c88 Mon Sep 17 00:00:00 2001
 From: Eberhard Stoll <eberhard.stoll@exceet.de>
 Date: Fri, 20 Apr 2018 10:35:42 +0200
-Subject: [PATCH 1/5] add NOR flash mx25v8035 and mx25r1635f
+Subject: [PATCH 2/5] add NOR flash mx25v8035 and mx25r1635f
 
 ---
  drivers/mtd/spi/spi_flash_ids.c | 2 ++
  1 file changed, 2 insertions(+)
 
 diff --git a/drivers/mtd/spi/spi_flash_ids.c b/drivers/mtd/spi/spi_flash_ids.c
-index ad0a0c8..aef54ec 100644
+index b789219..9ced70f 100644
 --- a/drivers/mtd/spi/spi_flash_ids.c
 +++ b/drivers/mtd/spi/spi_flash_ids.c
-@@ -84,6 +84,7 @@ const struct spi_flash_info spi_flash_ids[] = {
+@@ -80,6 +80,7 @@ const struct spi_flash_info spi_flash_ids[] = {
  	{"mx25l1605d",	   INFO(0xc22015, 0x0, 64 * 1024,    32, 0) },
  	{"mx25l3205d",	   INFO(0xc22016, 0x0, 64 * 1024,    64, 0) },
  	{"mx25l6405d",	   INFO(0xc22017, 0x0, 64 * 1024,   128, 0) },
@@ -19,14 +19,14 @@ index ad0a0c8..aef54ec 100644
  	{"mx25l12805",	   INFO(0xc22018, 0x0, 64 * 1024,   256, RD_FULL | WR_QPP) },
  	{"mx25l25635f",	   INFO(0xc22019, 0x0, 64 * 1024,   512, RD_FULL | WR_QPP) },
  	{"mx25l51235f",	   INFO(0xc2201a, 0x0, 64 * 1024,  1024, RD_FULL | WR_QPP) },
-@@ -94,6 +95,7 @@ const struct spi_flash_info spi_flash_ids[] = {
- 	{"mx25u25635f",    INFO(0xc22539, 0x0, 64 * 1024,   512, RD_FULL | WR_QPP) },
+@@ -88,6 +89,7 @@ const struct spi_flash_info spi_flash_ids[] = {
+ 	{"mx25u1635e",     INFO(0xc22535, 0x0, 64 * 1024,  32, SECT_4K) },
  	{"mx66u51235f",    INFO(0xc2253a, 0x0, 64 * 1024,  1024, RD_FULL | WR_QPP) },
  	{"mx66l1g45g",     INFO(0xc2201b, 0x0, 64 * 1024,  2048, RD_FULL | WR_QPP) },
-+	{"mx25r1635f",     INFO(0xc22815, 0x0, 64 * 1024,    32, RD_FULL | WR_QPP) },
++	{"mx25r1635f",     INFO(0xc22815, 0x0, 64 * 1024,    32, 0) },
  #endif
  #ifdef CONFIG_SPI_FLASH_SPANSION	/* SPANSION */
  	{"s25fl008a",	   INFO(0x010213, 0x0, 64 * 1024,    16, 0) },
---
+-- 
 2.7.4
 
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/0002-stm32_qspi-to-previous-working-mtd-compatible-versio.patch b/recipes-bsp/u-boot/u-boot-stm32mp/0002-stm32_qspi-to-previous-working-mtd-compatible-versio.patch
deleted file mode 100644
index 6a692b95bd94fec5417db7f23d9ef66c8d812c64..0000000000000000000000000000000000000000
--- a/recipes-bsp/u-boot/u-boot-stm32mp/0002-stm32_qspi-to-previous-working-mtd-compatible-versio.patch
+++ /dev/null
@@ -1,775 +0,0 @@
-From 25f601952fbd1cfcfa563979217b62b31a2c3b1e Mon Sep 17 00:00:00 2001
-From: Philipp Beck <Philipp.Beck@exceet.de>
-Date: Mon, 7 Oct 2019 16:11:59 +0200
-Subject: [PATCH 2/2] stm32_qspi to previous working mtd compatible version
-
----
- drivers/spi/stm32_qspi.c | 518 +++++++++------------------------------
- 1 file changed, 110 insertions(+), 408 deletions(-)
-
-diff --git a/drivers/spi/stm32_qspi.c b/drivers/spi/stm32_qspi.c
-index 39e95c2bcb..bb1067ff4a 100644
---- a/drivers/spi/stm32_qspi.c
-+++ b/drivers/spi/stm32_qspi.c
-@@ -9,17 +9,11 @@
- 
- #include <common.h>
- #include <clk.h>
--#include <dm.h>
--#include <errno.h>
--#include <malloc.h>
- #include <reset.h>
--#include <spi.h>
--#include <spi_flash.h>
- #include <spi-mem.h>
--#include <asm/io.h>
--#include <asm/arch/stm32.h>
--#include <linux/ioport.h>
- #include <linux/iopoll.h>
-+#include <linux/ioport.h>
-+#include <linux/sizes.h>
- 
- struct stm32_qspi_regs {
- 	u32 cr;		/* 0x00 */
-@@ -47,7 +41,7 @@ struct stm32_qspi_regs {
- #define STM32_QSPI_CR_SSHIFT		BIT(4)
- #define STM32_QSPI_CR_DFM		BIT(6)
- #define STM32_QSPI_CR_FSEL		BIT(7)
--#define STM32_QSPI_CR_FTHRES_SHIFT	(8)
-+#define STM32_QSPI_CR_FTHRES_SHIFT	8
- #define STM32_QSPI_CR_TEIE		BIT(16)
- #define STM32_QSPI_CR_TCIE		BIT(17)
- #define STM32_QSPI_CR_FTIE		BIT(18)
-@@ -56,16 +50,16 @@ struct stm32_qspi_regs {
- #define STM32_QSPI_CR_APMS		BIT(22)
- #define STM32_QSPI_CR_PMM		BIT(23)
- #define STM32_QSPI_CR_PRESCALER_MASK	GENMASK(7, 0)
--#define STM32_QSPI_CR_PRESCALER_SHIFT	(24)
-+#define STM32_QSPI_CR_PRESCALER_SHIFT	24
- 
- /*
-  * QUADSPI device configuration register
-  */
- #define STM32_QSPI_DCR_CKMODE		BIT(0)
- #define STM32_QSPI_DCR_CSHT_MASK	GENMASK(2, 0)
--#define STM32_QSPI_DCR_CSHT_SHIFT	(8)
-+#define STM32_QSPI_DCR_CSHT_SHIFT	8
- #define STM32_QSPI_DCR_FSIZE_MASK	GENMASK(4, 0)
--#define STM32_QSPI_DCR_FSIZE_SHIFT	(16)
-+#define STM32_QSPI_DCR_FSIZE_SHIFT	16
- 
- /*
-  * QUADSPI status register
-@@ -76,8 +70,6 @@ struct stm32_qspi_regs {
- #define STM32_QSPI_SR_SMF		BIT(3)
- #define STM32_QSPI_SR_TOF		BIT(4)
- #define STM32_QSPI_SR_BUSY		BIT(5)
--#define STM32_QSPI_SR_FLEVEL_MASK	GENMASK(5, 0)
--#define STM32_QSPI_SR_FLEVEL_SHIFT	(8)
- 
- /*
-  * QUADSPI flag clear register
-@@ -93,103 +85,40 @@ struct stm32_qspi_regs {
- #define STM32_QSPI_CCR_DDRM		BIT(31)
- #define STM32_QSPI_CCR_DHHC		BIT(30)
- #define STM32_QSPI_CCR_SIOO		BIT(28)
--#define STM32_QSPI_CCR_FMODE_SHIFT	(26)
--#define STM32_QSPI_CCR_DMODE_SHIFT	(24)
--#define STM32_QSPI_CCR_DCYC_SHIFT	(18)
--#define STM32_QSPI_CCR_DCYC_MASK	GENMASK(4, 0)
--#define STM32_QSPI_CCR_ABSIZE_SHIFT	(16)
--#define STM32_QSPI_CCR_ABMODE_SHIFT	(14)
--#define STM32_QSPI_CCR_ADSIZE_SHIFT	(12)
--#define STM32_QSPI_CCR_ADMODE_SHIFT	(10)
--#define STM32_QSPI_CCR_IMODE_SHIFT	(8)
--#define STM32_QSPI_CCR_INSTRUCTION_MASK	GENMASK(7, 0)
--
--enum STM32_QSPI_CCR_IMODE {
--	STM32_QSPI_CCR_IMODE_NONE = 0,
--	STM32_QSPI_CCR_IMODE_ONE_LINE = 1,
--	STM32_QSPI_CCR_IMODE_TWO_LINE = 2,
--	STM32_QSPI_CCR_IMODE_FOUR_LINE = 3,
--};
--
--enum STM32_QSPI_CCR_ADMODE {
--	STM32_QSPI_CCR_ADMODE_NONE = 0,
--	STM32_QSPI_CCR_ADMODE_ONE_LINE = 1,
--	STM32_QSPI_CCR_ADMODE_TWO_LINE = 2,
--	STM32_QSPI_CCR_ADMODE_FOUR_LINE = 3,
--};
--
--enum STM32_QSPI_CCR_ADSIZE {
--	STM32_QSPI_CCR_ADSIZE_8BIT = 0,
--	STM32_QSPI_CCR_ADSIZE_16BIT = 1,
--	STM32_QSPI_CCR_ADSIZE_24BIT = 2,
--	STM32_QSPI_CCR_ADSIZE_32BIT = 3,
--};
--
--enum STM32_QSPI_CCR_ABMODE {
--	STM32_QSPI_CCR_ABMODE_NONE = 0,
--	STM32_QSPI_CCR_ABMODE_ONE_LINE = 1,
--	STM32_QSPI_CCR_ABMODE_TWO_LINE = 2,
--	STM32_QSPI_CCR_ABMODE_FOUR_LINE = 3,
--};
--
--enum STM32_QSPI_CCR_ABSIZE {
--	STM32_QSPI_CCR_ABSIZE_8BIT = 0,
--	STM32_QSPI_CCR_ABSIZE_16BIT = 1,
--	STM32_QSPI_CCR_ABSIZE_24BIT = 2,
--	STM32_QSPI_CCR_ABSIZE_32BIT = 3,
--};
--
--enum STM32_QSPI_CCR_DMODE {
--	STM32_QSPI_CCR_DMODE_NONE = 0,
--	STM32_QSPI_CCR_DMODE_ONE_LINE = 1,
--	STM32_QSPI_CCR_DMODE_TWO_LINE = 2,
--	STM32_QSPI_CCR_DMODE_FOUR_LINE = 3,
--};
--
--enum STM32_QSPI_CCR_FMODE {
--	STM32_QSPI_CCR_IND_WRITE = 0,
--	STM32_QSPI_CCR_IND_READ = 1,
--	STM32_QSPI_CCR_AUTO_POLL = 2,
--	STM32_QSPI_CCR_MEM_MAP = 3,
--};
--
--/* default SCK frequency, unit: HZ */
--#define STM32_QSPI_DEFAULT_SCK_FREQ 108000000
--
--#define STM32_QSPI_MAX_CHIP 2
--
--#define STM32_QSPI_FIFO_TIMEOUT_US 30000
--#define STM32_QSPI_CMD_TIMEOUT_US 1000000
--#define STM32_BUSY_TIMEOUT_US 100000
--#define STM32_ABT_TIMEOUT_US 100000
--
--struct stm32_qspi_platdata {
--	u32 base;
--	u32 memory_map;
--	u32 max_hz;
--};
-+#define STM32_QSPI_CCR_FMODE_SHIFT	26
-+#define STM32_QSPI_CCR_DMODE_SHIFT	24
-+#define STM32_QSPI_CCR_DCYC_SHIFT	18
-+#define STM32_QSPI_CCR_ABSIZE_SHIFT	16
-+#define STM32_QSPI_CCR_ABMODE_SHIFT	14
-+#define STM32_QSPI_CCR_ADSIZE_SHIFT	12
-+#define STM32_QSPI_CCR_ADMODE_SHIFT	10
-+#define STM32_QSPI_CCR_IMODE_SHIFT	8
-+
-+#define STM32_QSPI_CCR_IND_WRITE	0
-+#define STM32_QSPI_CCR_IND_READ		1
-+#define STM32_QSPI_CCR_MEM_MAP		3
-+
-+#define STM32_QSPI_MAX_MMAP_SZ		SZ_256M
-+#define STM32_QSPI_MAX_CHIP		2
-+
-+#define STM32_QSPI_FIFO_TIMEOUT_US	30000
-+#define STM32_QSPI_CMD_TIMEOUT_US	1000000
-+#define STM32_BUSY_TIMEOUT_US		100000
-+#define STM32_ABT_TIMEOUT_US		100000
- 
- struct stm32_qspi_flash {
- 	u32 cr;
- 	u32 dcr;
--	u32 mode;
- 	bool initialized;
- };
- 
- struct stm32_qspi_priv {
- 	struct stm32_qspi_regs *regs;
- 	struct stm32_qspi_flash flash[STM32_QSPI_MAX_CHIP];
-+	void __iomem *mm_base;
-+	resource_size_t mm_size;
- 	ulong clock_rate;
--	u32 max_hz;
--	u32 mode;
- 	int cs_used;
--
--	u32 command;
--	u32 address;
--	u32 dummycycles;
--#define CMD_HAS_ADR	BIT(24)
--#define CMD_HAS_DUMMY	BIT(25)
--#define CMD_HAS_DATA	BIT(26)
- };
- 
- static int _stm32_qspi_wait_for_not_busy(struct stm32_qspi_priv *priv)
-@@ -206,95 +135,13 @@ static int _stm32_qspi_wait_for_not_busy(struct stm32_qspi_priv *priv)
- 	return ret;
- }
- 
--static unsigned int _stm32_qspi_gen_ccr(struct stm32_qspi_priv *priv, u8 fmode)
--{
--	unsigned int ccr_reg = 0;
--	u8 imode, admode, dmode;
--	u32 mode = priv->mode;
--	u32 cmd = (priv->command & STM32_QSPI_CCR_INSTRUCTION_MASK);
--
--	imode = STM32_QSPI_CCR_IMODE_ONE_LINE;
--	admode = STM32_QSPI_CCR_ADMODE_ONE_LINE;
--	dmode = STM32_QSPI_CCR_DMODE_ONE_LINE;
--
--	if ((priv->command & CMD_HAS_ADR) && (priv->command & CMD_HAS_DATA)) {
--		if (fmode == STM32_QSPI_CCR_IND_WRITE) {
--			if (mode & SPI_TX_QUAD)
--				dmode = STM32_QSPI_CCR_DMODE_FOUR_LINE;
--			else if (mode & SPI_TX_DUAL)
--				dmode = STM32_QSPI_CCR_DMODE_TWO_LINE;
--		} else if ((fmode == STM32_QSPI_CCR_MEM_MAP) ||
--			 (fmode == STM32_QSPI_CCR_IND_READ)) {
--			if (mode & SPI_RX_QUAD)
--				dmode = STM32_QSPI_CCR_DMODE_FOUR_LINE;
--			else if (mode & SPI_RX_DUAL)
--				dmode = STM32_QSPI_CCR_DMODE_TWO_LINE;
--		}
--	}
--
--	if (priv->command & CMD_HAS_DATA)
--		ccr_reg |= (dmode << STM32_QSPI_CCR_DMODE_SHIFT);
--
--	if (priv->command & CMD_HAS_DUMMY)
--		ccr_reg |= ((priv->dummycycles & STM32_QSPI_CCR_DCYC_MASK)
--				<< STM32_QSPI_CCR_DCYC_SHIFT);
--
--	if (priv->command & CMD_HAS_ADR) {
--		ccr_reg |= (STM32_QSPI_CCR_ADSIZE_24BIT
--				<< STM32_QSPI_CCR_ADSIZE_SHIFT);
--		ccr_reg |= (admode << STM32_QSPI_CCR_ADMODE_SHIFT);
--	}
--
--	ccr_reg |= (fmode << STM32_QSPI_CCR_FMODE_SHIFT);
--	ccr_reg |= (imode << STM32_QSPI_CCR_IMODE_SHIFT);
--	ccr_reg |= cmd;
--
--	return ccr_reg;
--}
--
--static void _stm32_qspi_enable_mmap(struct stm32_qspi_priv *priv,
--				    struct spi_flash *flash)
--{
--	unsigned int ccr_reg;
--
--	priv->command = flash->read_cmd | CMD_HAS_ADR | CMD_HAS_DATA
--			| CMD_HAS_DUMMY;
--	priv->dummycycles = flash->dummy_byte * 8;
--
--	ccr_reg = _stm32_qspi_gen_ccr(priv, STM32_QSPI_CCR_MEM_MAP);
--
--	_stm32_qspi_wait_for_not_busy(priv);
--
--	writel(ccr_reg, &priv->regs->ccr);
--
--	priv->dummycycles = 0;
--}
--
--static void _stm32_qspi_disable_mmap(struct stm32_qspi_priv *priv)
--{
--	setbits_le32(&priv->regs->cr, STM32_QSPI_CR_ABORT);
--}
--
--static void _stm32_qspi_set_xfer_length(struct stm32_qspi_priv *priv,
--					u32 length)
--{
--	writel(length - 1, &priv->regs->dlr);
--}
--
--static void _stm32_qspi_start_xfer(struct stm32_qspi_priv *priv, u32 cr_reg)
--{
--	writel(cr_reg, &priv->regs->ccr);
--
--	if (priv->command & CMD_HAS_ADR)
--		writel(priv->address, &priv->regs->ar);
--}
--
--static int _stm32_qspi_wait_cmd(struct stm32_qspi_priv *priv, bool wait_nobusy)
-+static int _stm32_qspi_wait_cmd(struct stm32_qspi_priv *priv,
-+				const struct spi_mem_op *op)
- {
- 	u32 sr;
- 	int ret;
- 
--	if (wait_nobusy)
-+	if (!op->data.nbytes)
- 		return _stm32_qspi_wait_for_not_busy(priv);
- 
- 	ret = readl_poll_timeout(&priv->regs->sr, sr,
-@@ -324,20 +171,20 @@ static void _stm32_qspi_write_fifo(u8 *val, void __iomem *addr)
- }
- 
- static int _stm32_qspi_poll(struct stm32_qspi_priv *priv,
--			    const u8 *dout, u8 *din, u32 len)
-+			    const struct spi_mem_op *op)
- {
- 	void (*fifo)(u8 *val, void __iomem *addr);
--	u32 sr;
-+	u32 len = op->data.nbytes, sr;
- 	u8 *buf;
- 	int ret;
- 
--	if (din) {
-+	if (op->data.dir == SPI_MEM_DATA_IN) {
- 		fifo = _stm32_qspi_read_fifo;
--		buf = din;
-+		buf = op->data.buf.in;
- 
- 	} else {
- 		fifo = _stm32_qspi_write_fifo;
--		buf = (u8 *)dout;
-+		buf = (u8 *)op->data.buf.out;
- 	}
- 
- 	while (len--) {
-@@ -355,128 +202,26 @@ static int _stm32_qspi_poll(struct stm32_qspi_priv *priv,
- 	return 0;
- }
- 
--static int _stm32_qspi_xfer(struct stm32_qspi_priv *priv,
--			    struct spi_flash *flash, unsigned int bitlen,
--			    const u8 *dout, u8 *din, unsigned long flags)
-+static int stm32_qspi_mm(struct stm32_qspi_priv *priv,
-+			 const struct spi_mem_op *op)
- {
--	unsigned int words = bitlen / 8;
--	u32 ccr_reg;
--	int ret;
--
--	if (flags & SPI_XFER_MMAP) {
--		_stm32_qspi_enable_mmap(priv, flash);
--		return 0;
--	} else if (flags & SPI_XFER_MMAP_END) {
--		_stm32_qspi_disable_mmap(priv);
--		return 0;
--	}
--
--	if (bitlen == 0)
--		return -1;
--
--	if (bitlen % 8) {
--		debug("spi_xfer: Non byte aligned SPI transfer\n");
--		return -1;
--	}
--
--	if (dout && din) {
--		debug("spi_xfer: QSPI cannot have data in and data out set\n");
--		return -1;
--	}
--
--	if (!dout && (flags & SPI_XFER_BEGIN)) {
--		debug("spi_xfer: QSPI transfer must begin with command\n");
--		return -1;
--	}
--
--	if (dout) {
--		if (flags & SPI_XFER_BEGIN) {
--			/* data is command */
--			priv->command = dout[0] | CMD_HAS_DATA;
--			if (words >= 4) {
--				/* address is here too */
--				priv->address = (dout[1] << 16) |
--						(dout[2] << 8) | dout[3];
--				priv->command |= CMD_HAS_ADR;
--			}
--
--			if (words > 4) {
--				/* rest is dummy bytes */
--				priv->dummycycles = (words - 4) * 8;
--				priv->command |= CMD_HAS_DUMMY;
--			}
--
--			if (flags & SPI_XFER_END) {
--				/* command without data */
--				priv->command &= ~(CMD_HAS_DATA);
--			}
--		}
--
--		if (flags & SPI_XFER_END) {
--			bool cmd_has_data = priv->command & CMD_HAS_DATA;
--
--			ccr_reg = _stm32_qspi_gen_ccr(priv,
--						      STM32_QSPI_CCR_IND_WRITE);
--
--			ret = _stm32_qspi_wait_for_not_busy(priv);
--			if (ret)
--				return ret;
--
--			if (cmd_has_data)
--				_stm32_qspi_set_xfer_length(priv, words);
--
--			_stm32_qspi_start_xfer(priv, ccr_reg);
--
--			debug("%s: write: ccr:0x%08x adr:0x%08x\n",
--			      __func__, priv->regs->ccr, priv->regs->ar);
--
--			if (cmd_has_data) {
--				ret = _stm32_qspi_poll(priv, dout, NULL, words);
--				if (ret)
--					return ret;
--			}
--
--			ret = _stm32_qspi_wait_cmd(priv, !cmd_has_data);
--			if (ret)
--				return ret;
--		}
--	} else if (din) {
--		ccr_reg = _stm32_qspi_gen_ccr(priv, STM32_QSPI_CCR_IND_READ);
--
--		ret = _stm32_qspi_wait_for_not_busy(priv);
--		if (ret)
--			return ret;
--
--		_stm32_qspi_set_xfer_length(priv, words);
--
--		_stm32_qspi_start_xfer(priv, ccr_reg);
--
--		debug("%s: read: ccr:0x%08x adr:0x%08x len:%d\n", __func__,
--		      priv->regs->ccr, priv->regs->ar, priv->regs->dlr);
--
--		ret = _stm32_qspi_poll(priv, NULL, din, words);
--		if (ret)
--			return ret;
--
--		ret = _stm32_qspi_wait_cmd(priv, false);
--		if (ret)
--			return ret;
--	}
-+	memcpy_fromio(op->data.buf.in, priv->mm_base + op->addr.val,
-+		      op->data.nbytes);
- 
- 	return 0;
- }
- 
- static int _stm32_qspi_tx(struct stm32_qspi_priv *priv,
--			  const struct spi_mem_op *op)
-+			  const struct spi_mem_op *op,
-+			  u8 mode)
- {
- 	if (!op->data.nbytes)
- 		return 0;
- 
--	if (op->data.dir == SPI_MEM_DATA_IN)
--		return _stm32_qspi_poll(priv, NULL, op->data.buf.in,
--					op->data.nbytes);
-+	if (mode == STM32_QSPI_CCR_MEM_MAP)
-+		return stm32_qspi_mm(priv, op);
- 
--	return _stm32_qspi_poll(priv, op->data.buf.out, NULL, op->data.nbytes);
-+	return _stm32_qspi_poll(priv, op);
- }
- 
- static int _stm32_qspi_get_mode(u8 buswidth)
-@@ -491,7 +236,8 @@ static int stm32_qspi_exec_op(struct spi_slave *slave,
- 			      const struct spi_mem_op *op)
- {
- 	struct stm32_qspi_priv *priv = dev_get_priv(slave->dev->parent);
--	u32 cr, ccr;
-+	u32 cr, ccr, addr_max;
-+	u8 mode = STM32_QSPI_CCR_IND_WRITE;
- 	int timeout, ret;
- 
- 	debug("%s: cmd:%#x mode:%d.%d.%d.%d addr:%#llx len:%#x\n",
-@@ -503,13 +249,19 @@ static int stm32_qspi_exec_op(struct spi_slave *slave,
- 	if (ret)
- 		return ret;
- 
--	ccr = (STM32_QSPI_CCR_IND_WRITE << STM32_QSPI_CCR_FMODE_SHIFT);
--	if (op->data.dir == SPI_MEM_DATA_IN && op->data.nbytes)
--		ccr = (STM32_QSPI_CCR_IND_READ << STM32_QSPI_CCR_FMODE_SHIFT);
-+	addr_max = op->addr.val + op->data.nbytes + 1;
-+
-+	if (op->data.dir == SPI_MEM_DATA_IN && op->data.nbytes) {
-+		if (addr_max < priv->mm_size && op->addr.buswidth)
-+			mode = STM32_QSPI_CCR_MEM_MAP;
-+		else
-+			mode = STM32_QSPI_CCR_IND_READ;
-+	}
- 
- 	if (op->data.nbytes)
--		_stm32_qspi_set_xfer_length(priv, op->data.nbytes);
-+		writel(op->data.nbytes - 1, &priv->regs->dlr);
- 
-+	ccr = (mode << STM32_QSPI_CCR_FMODE_SHIFT);
- 	ccr |= op->cmd.opcode;
- 	ccr |= (_stm32_qspi_get_mode(op->cmd.buswidth)
- 		<< STM32_QSPI_CCR_IMODE_SHIFT);
-@@ -530,15 +282,22 @@ static int stm32_qspi_exec_op(struct spi_slave *slave,
- 
- 	writel(ccr, &priv->regs->ccr);
- 
--	if (op->addr.nbytes)
-+	if (op->addr.nbytes && mode != STM32_QSPI_CCR_MEM_MAP)
- 		writel(op->addr.val, &priv->regs->ar);
- 
--	ret = _stm32_qspi_tx(priv, op);
--	if (ret)
-+	ret = _stm32_qspi_tx(priv, op, mode);
-+	/*
-+	 * Abort in:
-+	 * -error case
-+	 * -read memory map: prefetching must be stopped if we read the last
-+	 *  byte of device (device size - fifo size). like device size is not
-+	 *  knows, the prefetching is always stop.
-+	 */
-+	if (ret || mode == STM32_QSPI_CCR_MEM_MAP)
- 		goto abort;
- 
--	/* wait end of tx in indirect mode */
--	ret = _stm32_qspi_wait_cmd(priv, !op->data.nbytes);
-+	/* Wait end of tx in indirect mode */
-+	ret = _stm32_qspi_wait_cmd(priv, op);
- 	if (ret)
- 		goto abort;
- 
-@@ -547,7 +306,7 @@ static int stm32_qspi_exec_op(struct spi_slave *slave,
- abort:
- 	setbits_le32(&priv->regs->cr, STM32_QSPI_CR_ABORT);
- 
--	/* wait clear of abort bit by hw */
-+	/* Wait clear of abort bit by hw */
- 	timeout = readl_poll_timeout(&priv->regs->cr, cr,
- 				     !(cr & STM32_QSPI_CR_ABORT),
- 				     STM32_ABT_TIMEOUT_US);
-@@ -555,74 +314,56 @@ abort:
- 	writel(STM32_QSPI_FCR_CTCF, &priv->regs->fcr);
- 
- 	if (ret || timeout)
--		debug("%s ret:%d abort timeout:%d\n", __func__, ret, timeout);
-+		pr_err("%s ret:%d abort timeout:%d\n", __func__, ret, timeout);
- 
- 	return ret;
- }
- 
--static int stm32_qspi_ofdata_to_platdata(struct udevice *bus)
-+static int stm32_qspi_probe(struct udevice *bus)
- {
--	struct resource res_regs, res_mem;
--	struct stm32_qspi_platdata *plat = bus->platdata;
-+	struct stm32_qspi_priv *priv = dev_get_priv(bus);
-+	struct resource res;
-+	struct clk clk;
-+	struct reset_ctl reset_ctl;
- 	int ret;
- 
--	ret = dev_read_resource_byname(bus, "qspi", &res_regs);
-+	ret = dev_read_resource_byname(bus, "qspi", &res);
- 	if (ret) {
--		debug("Error: can't get regs base addresses(ret = %d)!\n", ret);
--		return -ENOMEM;
--	}
--	ret = dev_read_resource_byname(bus, "qspi_mm", &res_mem);
--	if (ret) {
--		debug("Error: can't get mmap base address(ret = %d)!\n", ret);
--		return -ENOMEM;
-+		dev_err(bus, "can't get regs base addresses(ret = %d)!\n", ret);
-+		return ret;
- 	}
- 
--	plat->max_hz = dev_read_u32_default(bus, "spi-max-frequency",
--					    STM32_QSPI_DEFAULT_SCK_FREQ);
--
--	plat->base = res_regs.start;
--	plat->memory_map = res_mem.start;
-+	priv->regs = (struct stm32_qspi_regs *)res.start;
- 
--	debug("%s: regs=<0x%x> mapped=<0x%x>, max-frequency=%d\n",
--	      __func__,
--	      plat->base,
--	      plat->memory_map,
--	      plat->max_hz
--	      );
--
--	return 0;
--}
-+	ret = dev_read_resource_byname(bus, "qspi_mm", &res);
-+	if (ret) {
-+		dev_err(bus, "can't get mmap base address(ret = %d)!\n", ret);
-+		return ret;
-+	}
- 
--static int stm32_qspi_probe(struct udevice *bus)
--{
--	struct stm32_qspi_platdata *plat = dev_get_platdata(bus);
--	struct stm32_qspi_priv *priv = dev_get_priv(bus);
--	struct dm_spi_bus *dm_spi_bus = bus->uclass_priv;
--	struct clk clk;
--	struct reset_ctl reset_ctl;
--	int ret;
-+	priv->mm_base = (void __iomem *)res.start;
- 
--	dm_spi_bus->max_hz = plat->max_hz;
-+	priv->mm_size = resource_size(&res);
-+	if (priv->mm_size > STM32_QSPI_MAX_MMAP_SZ)
-+		return -EINVAL;
- 
--	priv->regs = (struct stm32_qspi_regs *)(uintptr_t)plat->base;
--	priv->cs_used = -1;
--	priv->max_hz = plat->max_hz;
-+	debug("%s: regs=<0x%p> mapped=<0x%p> mapped_size=<0x%lx>\n",
-+	      __func__, priv->regs, priv->mm_base, priv->mm_size);
- 
- 	ret = clk_get_by_index(bus, 0, &clk);
- 	if (ret < 0)
- 		return ret;
- 
- 	ret = clk_enable(&clk);
--
- 	if (ret) {
- 		dev_err(bus, "failed to enable clock\n");
- 		return ret;
- 	}
- 
- 	priv->clock_rate = clk_get_rate(&clk);
--	if (!priv->clock_rate) {
-+	if (priv->clock_rate < 0) {
- 		clk_disable(&clk);
--		return -EINVAL;
-+		return priv->clock_rate;
- 	}
- 
- 	ret = reset_get_by_index(bus, 0, &reset_ctl);
-@@ -639,6 +380,8 @@ static int stm32_qspi_probe(struct udevice *bus)
- 		reset_deassert(&reset_ctl);
- 	}
- 
-+	priv->cs_used = -1;
-+
- 	setbits_le32(&priv->regs->cr, STM32_QSPI_CR_SSHIFT);
- 
- 	/* Set dcr fsize to max address */
-@@ -648,39 +391,31 @@ static int stm32_qspi_probe(struct udevice *bus)
- 	return 0;
- }
- 
--static int stm32_qspi_remove(struct udevice *bus)
--{
--	return 0;
--}
--
- static int stm32_qspi_claim_bus(struct udevice *dev)
- {
- 	struct stm32_qspi_priv *priv = dev_get_priv(dev->parent);
- 	struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev);
--	int slave_cs = slave_plat->cs;
- 
--	if (slave_cs >= STM32_QSPI_MAX_CHIP)
-+	if (slave_plat->cs >= STM32_QSPI_MAX_CHIP)
- 		return -ENODEV;
- 
--	if (priv->cs_used != slave_cs) {
--		struct stm32_qspi_flash *flash = &priv->flash[slave_cs];
-+	if (priv->cs_used != slave_plat->cs) {
-+		struct stm32_qspi_flash *flash = &priv->flash[slave_plat->cs];
- 
--		priv->cs_used = slave_cs;
-+		priv->cs_used = slave_plat->cs;
- 
- 		if (flash->initialized) {
--			/* Set the configuration: speed + mode + cs */
-+			/* Set the configuration: speed + cs */
- 			writel(flash->cr, &priv->regs->cr);
- 			writel(flash->dcr, &priv->regs->dcr);
--			priv->mode = flash->mode;
- 		} else {
- 			/* Set chip select */
- 			clrsetbits_le32(&priv->regs->cr, STM32_QSPI_CR_FSEL,
- 					priv->cs_used ? STM32_QSPI_CR_FSEL : 0);
- 
--			/* Save the configuration: speed + mode + cs */
-+			/* Save the configuration: speed + cs */
- 			flash->cr = readl(&priv->regs->cr);
- 			flash->dcr = readl(&priv->regs->dcr);
--			flash->mode = priv->mode;
- 
- 			flash->initialized = true;
- 		}
-@@ -700,35 +435,20 @@ static int stm32_qspi_release_bus(struct udevice *dev)
- 	return 0;
- }
- 
--static int stm32_qspi_xfer(struct udevice *dev, unsigned int bitlen,
--			   const void *dout, void *din, unsigned long flags)
--{
--	struct stm32_qspi_priv *priv = dev_get_priv(dev->parent);
--	struct spi_flash *flash = dev_get_uclass_priv(dev);
--
--	return _stm32_qspi_xfer(priv, flash, bitlen, (const u8 *)dout,
--				(u8 *)din, flags);
--}
--
- static int stm32_qspi_set_speed(struct udevice *bus, uint speed)
- {
--	struct stm32_qspi_platdata *plat = bus->platdata;
- 	struct stm32_qspi_priv *priv = dev_get_priv(bus);
- 	u32 qspi_clk = priv->clock_rate;
- 	u32 prescaler = 255;
- 	u32 csht;
- 	int ret;
- 
--	if (speed > plat->max_hz)
--		speed = plat->max_hz;
--
- 	if (speed > 0) {
--		prescaler = 0;
--		if (qspi_clk) {
--			prescaler = DIV_ROUND_UP(qspi_clk, speed) - 1;
--			if (prescaler > 255)
--				prescaler = 255;
--		}
-+		prescaler = DIV_ROUND_UP(qspi_clk, speed) - 1;
-+		if (prescaler > 255)
-+			prescaler = 255;
-+		else if (prescaler < 0)
-+			prescaler = 0;
- 	}
- 
- 	csht = DIV_ROUND_UP((5 * qspi_clk) / (prescaler + 1), 100000000);
-@@ -772,20 +492,6 @@ static int stm32_qspi_set_mode(struct udevice *bus, uint mode)
- 	if (mode & SPI_CS_HIGH)
- 		return -ENODEV;
- 
--	if (mode & SPI_RX_QUAD)
--		priv->mode |= SPI_RX_QUAD;
--	else if (mode & SPI_RX_DUAL)
--		priv->mode |= SPI_RX_DUAL;
--	else
--		priv->mode &= ~(SPI_RX_QUAD | SPI_RX_DUAL);
--
--	if (mode & SPI_TX_QUAD)
--		priv->mode |= SPI_TX_QUAD;
--	else if (mode & SPI_TX_DUAL)
--		priv->mode |= SPI_TX_DUAL;
--	else
--		priv->mode &= ~(SPI_TX_QUAD | SPI_TX_DUAL);
--
- 	debug("%s: regs=%p, mode=%d rx: ", __func__, priv->regs, mode);
- 
- 	if (mode & SPI_RX_QUAD)
-@@ -812,7 +518,6 @@ static const struct spi_controller_mem_ops stm32_qspi_mem_ops = {
- static const struct dm_spi_ops stm32_qspi_ops = {
- 	.claim_bus	= stm32_qspi_claim_bus,
- 	.release_bus	= stm32_qspi_release_bus,
--	.xfer		= stm32_qspi_xfer,
- 	.set_speed	= stm32_qspi_set_speed,
- 	.set_mode	= stm32_qspi_set_mode,
- 	.mem_ops	= &stm32_qspi_mem_ops,
-@@ -825,13 +530,10 @@ static const struct udevice_id stm32_qspi_ids[] = {
- };
- 
- U_BOOT_DRIVER(stm32_qspi) = {
--	.name	= "stm32_qspi",
--	.id	= UCLASS_SPI,
-+	.name = "stm32_qspi",
-+	.id = UCLASS_SPI,
- 	.of_match = stm32_qspi_ids,
--	.ops	= &stm32_qspi_ops,
--	.ofdata_to_platdata = stm32_qspi_ofdata_to_platdata,
--	.platdata_auto_alloc_size = sizeof(struct stm32_qspi_platdata),
-+	.ops = &stm32_qspi_ops,
- 	.priv_auto_alloc_size = sizeof(struct stm32_qspi_priv),
--	.probe	= stm32_qspi_probe,
--	.remove = stm32_qspi_remove,
-+	.probe = stm32_qspi_probe,
- };
--- 
-2.17.1
-
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/0003-fix-enable-phy-clock-for-ethernet.patch b/recipes-bsp/u-boot/u-boot-stm32mp/0003-fix-enable-phy-clock-for-ethernet.patch
new file mode 100644
index 0000000000000000000000000000000000000000..e7f31fcb0b221c54656ec08f8c3806c2acef4302
--- /dev/null
+++ b/recipes-bsp/u-boot/u-boot-stm32mp/0003-fix-enable-phy-clock-for-ethernet.patch
@@ -0,0 +1,73 @@
+From 0e1532d0c82f8e134969ae4b7745a28f4e2d2bb9 Mon Sep 17 00:00:00 2001
+From: Eberhard Stoll <eberhard.stoll@exceet.de>
+Date: Wed, 1 Aug 2018 15:52:07 +0200
+Subject: [PATCH 1/4] fix: enable phy clock for ethernet
+
+---
+ drivers/net/dwc_eth_qos.c | 29 +++++++++++++++++++++++++++++
+ 1 file changed, 29 insertions(+)
+
+diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c
+index 846c15e..66fc54c 100644
+--- a/drivers/net/dwc_eth_qos.c
++++ b/drivers/net/dwc_eth_qos.c
+@@ -301,6 +301,7 @@ struct eqos_priv {
+ 	struct clk clk_ptp_ref;
+ 	struct clk clk_tx;
+ 	struct clk clk_slave_bus;
++	struct clk clk_ck;
+ 	struct mii_dev *mii;
+ 	struct phy_device *phy;
+ 	void *descs;
+@@ -312,6 +313,7 @@ struct eqos_priv {
+ 	void *rx_pkt;
+ 	bool started;
+ 	bool reg_access_ok;
++	bool has_clk_ck;
+ };
+ 
+ /*
+@@ -1614,9 +1616,35 @@ static int eqos_probe_resources_stm32(struct udevice *dev)
+ 		goto err_free_clk_rx;
+ 	}
+ 
++    eqos->has_clk_ck = false;
++	ret = clk_get_by_name(dev, "mac-clk-ck", &eqos->clk_ck);
++	if (ret) {
++		pr_err("clk_get_by_name(ck) failed: %d", ret);
++		/* On some devicetrees mac-clk-ck isn't defined (like EV1 and EV2 boar).
++		 * This is because this clock is only needed if the PHY shall be clocked from internal
++		 * clock source. This is not */
++		//goto err_free_clk_tx;
++	}
++	else {
++    	const struct fdt_property *prop;
++	    eqos->has_clk_ck = true;
++	    prop = fdt_get_property(gd->fdt_blob, dev_of_offset(dev), "ex,provide-phy-clk", NULL);
++	    if (prop){
++		    ret = clk_enable(&eqos->clk_ck);
++		    if (ret < 0) {
++			    pr_warn("clk_enable(clk_ck) failed: %d", ret);
++			    goto err_free_clk_tx;
++		    }
++		    printf("PHY clock enabled (%luHz)\n", clk_get_rate(&eqos->clk_ck));
++	    }
++	}
++
+ 	debug("%s: OK\n", __func__);
+ 	return 0;
+ 
++err_free_clk_tx:
++    if (eqos->has_clk_ck)
++    	clk_free(&eqos->clk_tx);
+ err_free_clk_rx:
+ 	clk_free(&eqos->clk_rx);
+ err_free_clk_master_bus:
+@@ -1842,3 +1870,4 @@ U_BOOT_DRIVER(eth_eqos) = {
+ 	.priv_auto_alloc_size = sizeof(struct eqos_priv),
+ 	.platdata_auto_alloc_size = sizeof(struct eth_pdata),
+ };
++
+-- 
+2.7.4
+
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/0004-fix-add-CAD-definition-files.patch b/recipes-bsp/u-boot/u-boot-stm32mp/0004-fix-add-CAD-definition-files.patch
new file mode 100644
index 0000000000000000000000000000000000000000..58383219c94ec2d93d5c99878c1446a2cccd3e6d
--- /dev/null
+++ b/recipes-bsp/u-boot/u-boot-stm32mp/0004-fix-add-CAD-definition-files.patch
@@ -0,0 +1,29 @@
+From f86c924ed5957d11edb9002a4e81559b3bb6e28f Mon Sep 17 00:00:00 2001
+From: Eberhard Stoll <eberhard.stoll@exceet.de>
+Date: Mon, 30 Jul 2018 11:48:27 +0200
+Subject: [PATCH 4/5] fix: add CAD definition files
+
+---
+ arch/arm/dts/stm32mp157cad-pinctrl.dtsi | 1 +
+ arch/arm/dts/stm32mp157cad-u-boot.dtsi  | 1 +
+ 2 files changed, 2 insertions(+)
+ create mode 100644 arch/arm/dts/stm32mp157cad-pinctrl.dtsi
+ create mode 100644 arch/arm/dts/stm32mp157cad-u-boot.dtsi
+
+diff --git a/arch/arm/dts/stm32mp157cad-pinctrl.dtsi b/arch/arm/dts/stm32mp157cad-pinctrl.dtsi
+new file mode 100644
+index 0000000..6c98c38
+--- /dev/null
++++ b/arch/arm/dts/stm32mp157cad-pinctrl.dtsi
+@@ -0,0 +1 @@
++#include "stm32mp157caa-pinctrl.dtsi"
+diff --git a/arch/arm/dts/stm32mp157cad-u-boot.dtsi b/arch/arm/dts/stm32mp157cad-u-boot.dtsi
+new file mode 100644
+index 0000000..be7e589
+--- /dev/null
++++ b/arch/arm/dts/stm32mp157cad-u-boot.dtsi
+@@ -0,0 +1 @@
++#include "stm32mp157caa-u-boot.dtsi"
+-- 
+2.7.4
+
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/0004-set-ethxaddr-in-device-tree-node-with-alias-ethernet.patch b/recipes-bsp/u-boot/u-boot-stm32mp/0004-set-ethxaddr-in-device-tree-node-with-alias-ethernet.patch
deleted file mode 100644
index 174c172e0091b3cb8267abf5670d180956ccf7e1..0000000000000000000000000000000000000000
--- a/recipes-bsp/u-boot/u-boot-stm32mp/0004-set-ethxaddr-in-device-tree-node-with-alias-ethernet.patch
+++ /dev/null
@@ -1,95 +0,0 @@
-From 57f5090c2d52643e7d809e12a1d3cd7bc9be592c Mon Sep 17 00:00:00 2001
-From: pibeck <philipp.beck@exceet.de>
-Date: Mon, 18 Mar 2019 15:12:33 +0100
-Subject: [PATCH 4/5] set ethxaddr in device-tree node with alias ethernetx by
- incrementing ethaddr by x
-
----
- common/fdt_support.c | 59 ++++++++++++++++++++++++++++++++++++++++++++--------
- 1 file changed, 50 insertions(+), 9 deletions(-)
-
-diff --git a/common/fdt_support.c b/common/fdt_support.c
-index e6daa67..82eb547 100644
---- a/common/fdt_support.c
-+++ b/common/fdt_support.c
-@@ -480,11 +480,12 @@ int fdt_fixup_memory(void *blob, u64 start, u64 size)
-
- void fdt_fixup_ethernet(void *fdt)
- {
--	int i = 0, j, prop;
-+	int i = 0, j, prop ,k = 0;
- 	char *tmp, *end;
- 	char mac[16];
- 	const char *path;
- 	unsigned char mac_addr[ARP_HLEN];
-+	char buf[ARP_HLEN_ASCII + 1];
- 	int offset;
- #ifdef FDT_SEQ_MACADDR_FROM_ENV
- 	int nodeoff;
-@@ -537,15 +538,55 @@ void fdt_fixup_ethernet(void *fdt)
- 				continue;
- 			i++;
- #endif
--			tmp = env_get(mac);
--			if (!tmp)
--				continue;
-+		tmp = env_get(mac);
-+			if (!tmp) {
-+
-+				if(i >= 1){
-
--			for (j = 0; j < 6; j++) {
--				mac_addr[j] = tmp ?
--					      simple_strtoul(tmp, &end, 16) : 0;
--				if (tmp)
--					tmp = (*end) ? end + 1 : end;
-+					strcpy(mac, "ethaddr");
-+					tmp = env_get(mac);
-+
-+					if(tmp){
-+
-+						for (j = 0; j < 6; j++) {
-+							mac_addr[j] = tmp ?
-+									simple_strtoul(tmp, &end, 16) : 0;
-+							if (tmp)
-+								tmp = (*end) ? end + 1 : end;
-+						}
-+
-+						for(k = 0 ; k < i ; k++ ){
-+							j = 5;
-+							mac_addr[j] = (mac_addr[j] + 1) & 0xff;
-+
-+							while(mac_addr[j] == 0){
-+								j--;
-+								if(j < 0)
-+									break;
-+
-+								mac_addr[j] = (mac_addr[j] + 1) & 0xff;
-+							}
-+						}
-+
-+
-+						printf("eth%iaddr not defined, thus increment ethaddr by %i to %pM \n",i,i, mac_addr);
-+
-+
-+					}else {
-+						continue;
-+					}
-+				} else {
-+					continue;
-+				}
-+			} else {
-+
-+				for (j = 0; j < 6; j++) {
-+					mac_addr[j] = tmp ?
-+							simple_strtoul(tmp, &end, 16) : 0;
-+					if (tmp)
-+						tmp = (*end) ? end + 1 : end;
-+				}
-+				printf("Writing eth%iaddr %pM to fdt node \n",i, mac_addr);
- 			}
-
- 			do_fixup_by_path(fdt, path, "mac-address",
---
-2.7.4
-
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/0005-add-video_splash-function.patch b/recipes-bsp/u-boot/u-boot-stm32mp/0005-add-video_splash-function.patch
deleted file mode 100644
index 1a84e488c2f8f157874c46e715200e0e79c14442..0000000000000000000000000000000000000000
--- a/recipes-bsp/u-boot/u-boot-stm32mp/0005-add-video_splash-function.patch
+++ /dev/null
@@ -1,71 +0,0 @@
-From 153030663de5202b7509b4cff1b1ae93e1d5bf90 Mon Sep 17 00:00:00 2001
-From: pibeck <philipp.beck@exceet.de>
-Date: Tue, 19 Mar 2019 18:01:22 +0100
-Subject: [PATCH 5/5] add video_splash function
-
----
- common/splash.c  | 30 ++++++++++++++++++++++++++++++
- include/splash.h |  9 +++++++++
- 2 files changed, 39 insertions(+)
-
-diff --git a/common/splash.c b/common/splash.c
-index d251b3b..feb215b 100644
---- a/common/splash.c
-+++ b/common/splash.c
-@@ -94,3 +94,33 @@ int lcd_splash(ulong addr)
- 	return bmp_display(addr, x, y);
- }
- #endif
-+#if defined(CONFIG_SPLASH_SCREEN) && defined(CONFIG_DM_VIDEO)
-+#include <dm.h>
-+#include <video.h>
-+int video_splash(void)
-+{
-+	struct udevice *dev;
-+	int x = 0, y = 0, ret;
-+	char *s;
-+	ulong addr;
-+
-+	s = env_get("splashimage");
-+	if (!s)
-+		return -ENOENT;
-+	addr = simple_strtoul(s, NULL, 16);
-+
-+	ret = splash_screen_prepare();
-+	if (ret)
-+		return ret;
-+
-+	ret = uclass_first_device_err(UCLASS_VIDEO, &dev);
-+	if (ret)
-+		return ret;
-+
-+	video_clear(dev);
-+
-+	splash_get_pos(&x, &y);
-+
-+	return bmp_display(addr, x, y);
-+}
-+#endif
-diff --git a/include/splash.h b/include/splash.h
-index 228aff4..efba3c7 100644
---- a/include/splash.h
-+++ b/include/splash.h
-@@ -75,6 +75,15 @@ static inline int lcd_splash(ulong addr)
- }
- #endif
-
-+#if defined(CONFIG_SPLASH_SCREEN) && defined(CONFIG_DM_VIDEO)
-+int video_splash(void);
-+#else
-+static inline int video_splash()
-+{
-+	return -ENOSYS;
-+}
-+#endif
-+
- #define BMP_ALIGN_CENTER	0x7FFF
-
- #endif
---
-2.7.4
-
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/0005-stmxceet-Kconfig-for-board-stmxceet-mp157-som-added.patch b/recipes-bsp/u-boot/u-boot-stm32mp/0005-stmxceet-Kconfig-for-board-stmxceet-mp157-som-added.patch
new file mode 100644
index 0000000000000000000000000000000000000000..ab6cb0eb41e90a454d679e34c88b97da73ed2110
--- /dev/null
+++ b/recipes-bsp/u-boot/u-boot-stm32mp/0005-stmxceet-Kconfig-for-board-stmxceet-mp157-som-added.patch
@@ -0,0 +1,102 @@
+From bfd9a9c50d27ffea4240d7b9a72af33c15d5c35f Mon Sep 17 00:00:00 2001
+From: Eberhard Stoll <eberhard.stoll@exceet.de>
+Date: Tue, 20 Mar 2018 18:13:26 +0100
+Subject: [PATCH 5/5] stmxceet: Kconfig for board stmxceet-mp157-som added
+
+---
+ arch/arm/mach-stm32mp/Kconfig           | 32 ++++++++++++++++++++++++++++----
+ board/exceet/stmxceet-mp157-som/Kconfig | 15 +++++++++++++++
+ 2 files changed, 43 insertions(+), 4 deletions(-)
+ create mode 100644 board/exceet/stmxceet-mp157-som/Kconfig
+
+diff --git a/arch/arm/mach-stm32mp/Kconfig b/arch/arm/mach-stm32mp/Kconfig
+index 9d70ed9..b11ab31 100644
+--- a/arch/arm/mach-stm32mp/Kconfig
++++ b/arch/arm/mach-stm32mp/Kconfig
+@@ -23,8 +23,30 @@ config SPL
+ 	imply SPL_DISPLAY_PRINT
+ 	imply SPL_LIBDISK_SUPPORT
+ 
++choice
++	prompt "STM32MP1 based boards"
++	optional
++
++config TARGET_STMXCEET_MP157_SOM
++	bool "Exceet stmxceet mp157 som"
++	select ARCH_SUPPORT_PSCI if !STM32MP1_TRUSTED
++	select CPU_V7
++	select CPU_V7_HAS_NONSEC if !STM32MP1_TRUSTED
++	select CPU_V7_HAS_VIRT
++	select OF_BOARD_SETUP
++	select PINCTRL_STM32
++	select STM32_RCC
++	select STM32_RESET
++	select STM32_SERIAL
++	imply BOOTCOUNT_LIMIT
++	imply SYSRESET_SYSCON
++	help
++		Exceet SOM with STM32MP1 SOC family
++
++source "board/exceet/stmxceet-mp157-som/Kconfig"
++
+ config TARGET_STM32MP1
+-	bool "Support stm32mp1xx"
++	bool "ST stm32mp1xx eval boards"
+ 	select ARCH_SUPPORT_PSCI if !STM32MP1_TRUSTED
+ 	select CPU_V7
+ 	select CPU_V7_HAS_NONSEC if !STM32MP1_TRUSTED
+@@ -42,9 +64,11 @@ config TARGET_STM32MP1
+ 		STMicroelectronics MPU with core ARMv7
+ 		dual core A7 for STM32MP153, monocore for STM32MP151
+ 
++endchoice
++
+ config STM32MP15x_REVA
+ 	bool "Support STM32PM15x revision .A"
+-	depends on TARGET_STM32MP1
++	depends on (TARGET_STM32MP1 || TARGET_STMXCEET_MP157_SOM)
+ 	default y
+ 	help
+ 		support for STM32PM15x.A
+@@ -75,7 +99,7 @@ config STM32MP1_OPTEE
+ 
+ config SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION_MMC2
+ 	hex "Partition to use for MMC2 to load U-Boot from"
+-	depends on SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION && TARGET_STM32MP1
++	depends on SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION && (TARGET_STM32MP1 || TARGET_STMXCEET_MP157_SOM)
+ 	default 1
+ 	help
+ 	  Partition on the MMC2 to load U-Boot from when the MMC2 is being
+@@ -83,7 +107,7 @@ config SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION_MMC2
+ 
+ config STM32_ETZPC
+ 	bool "STM32 Extended TrustZone Protection"
+-	depends on TARGET_STM32MP1
++	depends on (TARGET_STM32MP1 || TARGET_STMXCEET_MP157_SOM)
+ 	default y
+ 	help
+ 	  Say y to enable STM32 Extended TrustZone Protection
+diff --git a/board/exceet/stmxceet-mp157-som/Kconfig b/board/exceet/stmxceet-mp157-som/Kconfig
+new file mode 100644
+index 0000000..8c571a0
+--- /dev/null
++++ b/board/exceet/stmxceet-mp157-som/Kconfig
+@@ -0,0 +1,15 @@
++if TARGET_STMXCEET_MP157_SOM
++
++config SYS_BOARD
++	default "stmxceet-mp157-som"
++
++config SYS_VENDOR
++	default "exceet"
++
++config SYS_SOC
++	default "stm32mp"
++
++config SYS_CONFIG_NAME
++	default "stmxceet-mp157-som"
++
++endif
+-- 
+2.7.4
+
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/0009-changed-clock-layout-which-was-corrected-in-r2.1.patch b/recipes-bsp/u-boot/u-boot-stm32mp/0009-changed-clock-layout-which-was-corrected-in-r2.1.patch
deleted file mode 100644
index 336958a5171020fb4c846a613a1a5fcacb1829bb..0000000000000000000000000000000000000000
--- a/recipes-bsp/u-boot/u-boot-stm32mp/0009-changed-clock-layout-which-was-corrected-in-r2.1.patch
+++ /dev/null
@@ -1,25 +0,0 @@
-From a9b96b6c85625351d86f1f0bff835a1139670644 Mon Sep 17 00:00:00 2001
-From: Philipp Beck <Philipp.Beck@exceet.de>
-Date: Thu, 18 Jul 2019 12:39:52 +0200
-Subject: [PATCH 9/9] changed clock layout which was corrected in r2.1
-
----
- arch/arm/dts/stm32mp157c.dtsi | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/arch/arm/dts/stm32mp157c.dtsi b/arch/arm/dts/stm32mp157c.dtsi
-index b08771c201..df3c4766b0 100644
---- a/arch/arm/dts/stm32mp157c.dtsi
-+++ b/arch/arm/dts/stm32mp157c.dtsi
-@@ -1759,7 +1759,7 @@
- 				 <&rcc ETHTX>,
- 				 <&rcc ETHRX>,
- 				 <&rcc ETHSTP>,
--				 <&rcc ETHCK>;
-+				 <&rcc ETHCK_K>;
- 			st,syscon = <&syscfg 0x4>;
- 			snps,mixed-burst;
- 			snps,pbl = <2>;
--- 
-2.17.1
-
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/0100-Add-config-option-for-housing-env-var.patch b/recipes-bsp/u-boot/u-boot-stm32mp/0100-Add-config-option-for-housing-env-var.patch
deleted file mode 100644
index 2144c85a4631eccdb7ea561b4350874fbfd57838..0000000000000000000000000000000000000000
--- a/recipes-bsp/u-boot/u-boot-stm32mp/0100-Add-config-option-for-housing-env-var.patch
+++ /dev/null
@@ -1,31 +0,0 @@
-From d4d056f6ddb321efbab676b0d3c759cdc0543b4c Mon Sep 17 00:00:00 2001
-From: Eberhard Stoll <eberhard.stoll@kontron.de>
-Date: Tue, 6 Aug 2019 18:05:23 +0200
-Subject: [PATCH] Add config option for housing env var The default value for
- the housing environment variable can now be set by u-boot configuration.
-
----
- common/Kconfig | 7 +++++++
- 1 file changed, 7 insertions(+)
-
-diff --git a/common/Kconfig b/common/Kconfig
-index d7300c2..983ebc5 100644
---- a/common/Kconfig
-+++ b/common/Kconfig
-@@ -223,6 +223,13 @@ config BOOTCOMMAND
- 	  This is the string of commands that will be used as bootcmd and if
- 	  AUTOBOOT is set, automatically run.
- 
-+config HOUSING_DEFAULT
-+	string "Set value for housing configuration"
-+	default "-50"
-+	help
-+	  This is the default environment value for HOUSING variable in
-+	  u-boot environment
-+
- menu "Console"
- 
- config MENU
--- 
-2.7.4
-
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-board-default.dtsi b/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-board-default.dtsi
new file mode 100644
index 0000000000000000000000000000000000000000..6df7a0da4d24ead2ce28f83951c76786f96b3180
--- /dev/null
+++ b/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-board-default.dtsi
@@ -0,0 +1,82 @@
+/* Devicetree file for device
+ *
+ * device   : stm32mp-board-default
+ * revision : prototype
+ *
+ * Kontron Electronics GmbH
+ * Copyright 2018 Kontron Electronics GmbH. All rights reserved.
+ */
+
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+	device-identification {
+		board = "s";
+		board_pcb = "1 950 1616";
+		board_code = "40099 130 00";
+	};
+};
+
+/* i2c interfaces */
+&i2c4 {
+	status = "okay";
+	clock-frequency = <100000>;
+};
+
+
+/* spi interfaces */
+&spi2 {
+	cs-gpios = <&gpioa 11 GPIO_ACTIVE_HIGH>;
+	status = "okay";
+};
+
+
+/* ADC settings */
+&adc {
+	/* ADC_INP5 is fast, ADC_INP16 is slow channel */
+
+	/* Use internal reference voltage */
+	/* vref-supply = <&vrefbuf>; */
+
+	/* Use external reference voltage */
+	vref-supply = <&vdda>;
+	status = "okay";
+
+
+	adc1: adc@0 {
+		st,adc-channels = <5 16>;
+		/* 16.5 ck_cycles sampling time */
+		st,min-sample-time-nsecs = <400>;
+		status = "okay";
+	};
+
+	jadc1: jadc@0 {
+		st,adc-channels = <5 16>;
+		/* 16.5 ck_cycles sampling time */
+		st,min-sample-time-nsecs = <400>;
+		status = "okay";
+	};
+
+	adc2: adc@100 {
+		status = "okay";
+	};
+
+	adc_temp: temp {
+		/* temperature sensor on adc2 */
+		status = "okay";
+	};
+
+};
+
+
+/* sd interfaces */
+&sdmmc1 {
+	broken-cd;
+	//cd-gpios = <&gpioa 10 GPIO_ACTIVE_HIGH>;
+	st,dirpol;
+	st,negedge;
+	no-1-8-v;
+	bus-width = <4>;
+	vmmc-supply = <&vdd_sd>;
+	status = "okay";
+};
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-board-k-u-boot.dtsi b/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-board-k-u-boot.dtsi
deleted file mode 100644
index 5c440d934275b3641b4a840b819bf7b6c9764ccd..0000000000000000000000000000000000000000
--- a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-board-k-u-boot.dtsi
+++ /dev/null
@@ -1,37 +0,0 @@
-/* Devicetree file for device
- *
- * device   : stm32mp-board-k
- * revision : 0
- *
- * Kontron Electronics GmbH
- * Copyright 2019 Kontron Electronics GmbH. All rights reserved.
- */
-
-&leds {
-	pinctrl-names = "default";
-	pinctrl-0 = < &led_gpios >;
-};
-
-&pinctrl {
-    led_gpios: led_gpios@0 {
-        u-boot,dm-pre-reloc;
-        pins1 {
-            pinmux = <STM32_PINMUX('A', 13, GPIO)>, /* LED1 */
-                     <STM32_PINMUX('A', 14, GPIO)>; /* LED2 */
-            bias-pull-down;
-            drive-push-pull;
-        };
-    };
-};
-
-&ltdc {
-	u-boot,dm-pre-reloc;
-	/* disable ltdc - data is corrupted when linux kernel is loaded by tftp.
-	 * Leave pinctl-1 as is !!! This is important! */
-	
-	reason="disabled-because-tftp-data-corruption";
-	/delete-property/ pinctrl-0;
-	/delete-property/ pinctrl-1;
-	/delete-property/ pinctrl-names;
-	status = "disabled";
-};
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-board-k.dtsi b/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-board-k.dtsi
deleted file mode 100644
index 6af94f5943dfc9d2ffde776a3698750f42981b01..0000000000000000000000000000000000000000
--- a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-board-k.dtsi
+++ /dev/null
@@ -1,227 +0,0 @@
-/* Devicetree file for device
- *
- * device   : stm32mp-board-k
- * revision : 0
- *
- * Kontron Electronics GmbH
- * Copyright 2019 Kontron Electronics GmbH. All rights reserved.
- */
-
-#include <dt-bindings/gpio/gpio.h>
-
-/ {
-	device-identification {
-		board = "k";
-		board_pcb = "1 951 1825";
-		board_code = "40099 176 00";
-	};
-
-	aliases {
-		serial0 = &uart4;    /* console */
-		serial1 = &usart2;   /* rs485 */
-		serial2 = &usart3;   /* rs232 */
-		ethernet1 = &ethernet1;
-	};
-
-	v5v: regulator-v5v {
-		compatible = "regulator-fixed";
-		regulator-name = "v5v";
-		regulator-min-microvolt = <5000000>;
-		regulator-max-microvolt = <5000000>;
-		regulator-always-on;
-	};
-
-	vdd_sd: regulator-vdd_sd {
-		compatible = "regulator-fixed";
-		regulator-name = "vdd_sd";
-		regulator-min-microvolt = <3300000>;
-		regulator-max-microvolt = <3300000>;
-		regulator-always-on;
-	};
-
-	beeper:pwm-beeper {
-		compatible = "pwm-beeper";
-		/* pwm timers1, Channel 2 */
-		/* Use 440Hz which is default frequency for beep command */
-		pwms = <&pwm_beep 1 2272727>;
-		amp-supply = <&v5v>;
-	};
-
-	/* leds */
-	leds:led {
-		compatible = "gpio-leds";
-		status = "okay";
-		led1 {
-			label = "LED1";
-			gpios = <&gpioa 13 GPIO_ACTIVE_LOW>;
-			default-state = "off";
-			linux,default-trigger = "heartbeat";
-			status = "disabled";
-		};
-		led2 {
-			label = "LED2";
-			gpios = <&gpioa 14 GPIO_ACTIVE_LOW>;
-			default-state = "off";
-			status = "okay";
-		};
-	};
-};
-
-
-&i2c4 {
-	/* External i2c bus */
-	status = "okay";
-};
-
-
-/* Internal ADC reference voltage */
-&vrefbuf {
-	status = "okay";
-	/* Set referece voltage to 2.5V */
-	regulator-max-microvolt = <2500000>;
-	regulator-min-microvolt = <2500000>;
-	vdda-supply = <&vdd>;
-};
-
-/* ADC settings */
-&adc {
-	/* ADC_INP5 is fast, ADC_INP16 is slow channel */
-
-	/* Use internal reference voltage */
-	vref-supply = <&vrefbuf>;
-	status = "okay";
-
-	adc1: adc@0 {
-		st,adc-channels = <5 16>;
-		st,min-sample-time-nsecs = <100000>;
-		status = "okay";
-	};
-
-	adc2: adc@100 {
-		// VREFINT VDDCORE VBAT/4 DAC_OUT1 DAC_OUT2
-		st,adc-channels = <13 14 15 16 17>;
-		st,min-sample-time-nsecs = <100000>;
-		status = "okay";
-	};
-
-	adc_temp: temp {
-		/* temperature sensor on adc2 */
-		status = "okay";
-	};
-
-};
-
-
-/* sd interfaces */
-&sdmmc1 {
-	/* add opendrain pins which aren't generated by cubemx */
-	pinctrl-names = "default", "sleep", "opendrain";
-	pinctrl-0 = <&sdmmc1_pins_mx>;
-	pinctrl-1 = <&sdmmc1_sleep_pins_mx>;
-	pinctrl-2 = <&sdmmc1_opendrain_pins_mx>;
-	broken-cd;
-	no-1-8-v;
-	st,neg-edge;
-	bus-width = <4>;
-	vmmc-supply = <&vdd_sd>;
-	status = "okay";
-};
-
-
-/* emmc interface */
-&sdmmc2 {
-	/* add opendrain pins which aren't generated by cubemx */
-	pinctrl-names = "default", "sleep", "opendrain";
-	pinctrl-0 = <&sdmmc2_pins_mx>;
-	pinctrl-1 = <&sdmmc2_sleep_pins_mx>;
-	pinctrl-2 = <&sdmmc2_opendrain_pins_mx>;
-	non-removable;
-	no-sd;
-	no-sdio;
-	st,neg-edge;
-	mmc-ddr-3_3v;
-	bus-width = <4>;
-	vmmc-supply = <&v3v3>;
-	status = "okay";
-};
-
-
-/* RS485 interface */
-&usart2 {
-	linux,rs485-enabled-at-boot-time;
-    status = "okay";
-};
-
-
-/* timer1: CH2 Beeper */
-&timers1 {
-    status = "okay";
-	/* spare dmas for other usage */
-	/delete-property/dmas;
-	/delete-property/dma-names;
-
-	pwm_beep:pwm {
-		#pwm-cells = <2>;
-		status = "okay";
-	};
-};
-
-
-/* timer4: CH3 Backlight */
-&timers4 {
-    status = "okay";
-	/* spare dmas for other usage */
-	/delete-property/dmas;
-	/delete-property/dma-names;
-
-	pwm_bl:pwm {
-		#pwm-cells = <2>;
-		status = "okay";
-	};
-};
-
-
-/* Add touch connector gpios */
-&pinctrl {
-    touch_pins_dev: touch_pins_dev@0 {
-        pins {
-            /* touch int is initialized by touch driver */
-            pinmux = <STM32_PINMUX('G', 7, GPIO)>, /* TOUCH_INT */
-                     <STM32_PINMUX('E', 0, GPIO)>; /* TOUCH_WAKE */
-            bias-pull-up;
-        };
-    };
-
-};
-
-&usbh_ehci {
-	/*
-	*	node structure for smsc95xx driver to find and pick up mac-address
-	*	eth1addr will be written into local-mac from u-boot
-	*/
-	usb1@1 {
-		compatible = "usb424,9514";
-		reg = <1>;
-		#address-cells = <1>;
-		#size-cells = <0>;
-
-		ethernet1: usbether@1 {
-			compatible = "usb424,ec00";
-			reg = <1>;
-			local-mac-address = [00 00 00 00 00 00];
-		};
-	};
-};
-
-/*
-* Disable usart3 for linux and enable m4 resource
-*/
-&usart3{
-      status = "disabled";
-};
-
-&m4_usart3{
-    status = "okay";
-};
-
-
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-board-mini.dtsi b/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-board-mini.dtsi
new file mode 100644
index 0000000000000000000000000000000000000000..91cc9119b644f78004feee02dda9fe08a6a55830
--- /dev/null
+++ b/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-board-mini.dtsi
@@ -0,0 +1,93 @@
+/* Devicetree file for device
+ *
+ * device   : stm32mp-board-mini
+ * revision : prototype
+ *
+ * Kontron Electronics GmbH
+ * Copyright 2018 Kontron Electronics GmbH. All rights reserved.
+ */
+
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+	device-identification {
+		board = "mini";
+		board_pcb = "1 950 1422";
+		board_code = "40099 113 01 (prototype)";
+	};
+};
+
+/* i2c interfaces */
+&i2c2 {
+	status = "okay";
+
+	/* Vishay VCNL4020 ambient sensor */
+	vcnl4000@13 {
+		compatible = "vishay,vcnl4000";
+		reg = <0x13>;
+	};
+};
+
+&i2c4 {
+	status = "okay";
+	clock-frequency = <100000>;
+};
+
+
+/* spi interfaces */
+&spi2 {
+	cs-gpios = <&gpioa 11 GPIO_ACTIVE_HIGH>;
+	status = "okay";
+};
+
+
+/* ADC settings */
+&adc {
+	/* ADC_INP5 is fast, ADC_INP16 is slow channel */
+
+	/* Use internal reference voltage */
+	/* vref-supply = <&vrefbuf>; */
+
+	/* Use external reference voltage */
+	vref-supply = <&vdda>;
+	status = "okay";
+
+
+	adc1: adc@0 {
+		st,adc-channels = <2 3 5 16>;
+		/* 16.5 ck_cycles sampling time */
+		st,min-sample-time-nsecs = <400>;
+		status = "okay";
+	};
+
+	jadc1: jadc@0 {
+		st,adc-channels = <2 3 5 16>;
+		/* 16.5 ck_cycles sampling time */
+		st,min-sample-time-nsecs = <400>;
+		status = "okay";
+	};
+
+	adc2: adc@100 {
+		status = "okay";
+	};
+
+	adc_temp: temp {
+		/* temperature sensor on adc2 */
+		status = "okay";
+	};
+
+};
+
+
+/* sd/mmc interfaces */
+&sdmmc1 {
+	broken-cd;
+	//cd-gpios = <&gpioa 10 GPIO_ACTIVE_HIGH>;
+	st,dirpol;
+	st,negedge;
+	no-1-8-v;
+	bus-width = <4>;
+	vmmc-supply = <&vdd_sd>;
+	status = "okay";
+};
+
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-board-minimal-u-boot.dtsi b/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-board-minimal-u-boot.dtsi
deleted file mode 100644
index 6c5a93bd836e9527d443652340ab7534c5915725..0000000000000000000000000000000000000000
--- a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-board-minimal-u-boot.dtsi
+++ /dev/null
@@ -1,10 +0,0 @@
-/* Devicetree file for basic t1000 SOM module
- *
- * These settings should work with most baseboards
- *
- * device   : stm32mp-board-minimal
- * revision : -
- *
- * Kontron Electronics GmbH
- * Copyright 2019 Kontron Electronics GmbH. All rights reserved.
- */
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-board-minimal.dtsi b/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-board-minimal.dtsi
deleted file mode 100644
index 08d965543665b2c5f27f4f4be5f774e23b5fc14d..0000000000000000000000000000000000000000
--- a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-board-minimal.dtsi
+++ /dev/null
@@ -1,114 +0,0 @@
-/* Devicetree file for basic t1000 SOM module
- *
- * These settings should work with most baseboards
- *
- * device   : stm32mp-board-minimal
- * revision : -
- *
- * Kontron Electronics GmbH
- * Copyright 2019 Kontron Electronics GmbH. All rights reserved.
- */
-
-#include <dt-bindings/gpio/gpio.h>
-
-/ {
- 	/* Add your board identification (only for informational purpose) */
-	device-identification {
-		board = "minimal";
-		board_pcb = "none";
-		board_code = "none";
-	};
-
-	aliases {
-		serial0 = &uart4;    /* console */
-	};
-
-	/* SD card voltage - may be adapted to board */
-	vdd_sd: regulator-vdd_sd {
-		compatible = "regulator-fixed";
-		regulator-name = "vdd_sd";
-		regulator-min-microvolt = <3300000>;
-		regulator-max-microvolt = <3300000>;
-		regulator-always-on;
-	};
-};
-
-
-/* Internal ADC reference voltage */
-&vrefbuf {
-	status = "okay";
-	/* Set referece voltage to 2.5V */
-	regulator-max-microvolt = <2500000>;
-	regulator-min-microvolt = <2500000>;
-	vdda-supply = <&vdd>;
-};
-
-
-/* ADC settings - Not required, but useful and not disturbing */
-&adc {
-	/* Use internal reference voltage */
-	vref-supply = <&vrefbuf>;
-	status = "okay";
-
-	adc2: adc@100 {
-		// VREFINT VDDCORE VBAT/4 DAC_OUT1 DAC_OUT2
-		st,adc-channels = <13 14 15 16 17>;
-		st,min-sample-time-nsecs = <100000>;
-		status = "okay";
-	};
-
-	adc_temp: temp {
-		/* temperature sensor on adc2 */
-		status = "okay";
-	};
-
-};
-
-
-/* sd interfaces */
-/* Simple sd interface */
-&sdmmc1 {
-	/* add opendrain pins which aren't generated by cubemx */
-	pinctrl-names = "default", "sleep", "opendrain";
-	pinctrl-0 = <&sdmmc1_pins_mx>;
-	pinctrl-1 = <&sdmmc1_sleep_pins_mx>;
-	pinctrl-2 = <&sdmmc1_od_pins>;
-	broken-cd;
-	no-1-8-v;
-	st,neg-edge;
-	bus-width = <4>;
-	vmmc-supply = <&vdd_sd>;
-	status = "okay";
-};
-
-
-&pinctrl {
-	/* add opendrain pin config */
-    sdmmc1_od_pins: sdmmc1_od@0 {
-        pins1 {
-            u-boot,dm-pre-reloc;
-            pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
-                     <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
-                     <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
-                     <STM32_PINMUX('C', 11, AF12)>; /* SDMMC1_D3 */
-            bias-pull-up;
-            drive-push-pull;
-            slew-rate = <1>;
-        };
-        pins2 {
-            u-boot,dm-pre-reloc;
-            pinmux = <STM32_PINMUX('C', 12, AF12)>; /* SDMMC1_CK */
-            bias-pull-up;
-            drive-push-pull;
-            slew-rate = <3>;
-        };
-        pins3 {
-            u-boot,dm-pre-reloc;
-            pinmux = <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
-            bias-pull-up;
-            drive-open-drain;
-            slew-rate = <1>;
-        };
-    };
-};
-
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-board-s.dtsi b/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-board-s.dtsi
index 41e404fb4589afb645d92bd06bfe56b384cc6d0b..ea8c125e994dad4a076a931079cfa49345284a83 100644
--- a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-board-s.dtsi
+++ b/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-board-s.dtsi
@@ -12,17 +12,10 @@
 / {
 	device-identification {
 		board = "s";
-		board_pcb = "1 951 1619";
-		board_code = "40099 131 01";
+		board_pcb = "1 950 1619";
+		board_code = "40099 131 01 (prototype)";
 	};
-
-	aliases {
-		serial0 = &uart4;    /* console */
-		serial1 = &usart2;   /* rs485 */
-		serial2 = &usart6;   /* rs232 */
-		ethernet1 = &ethernet1;
-	};
-
+	
 	v5v: regulator-v5v {
 		compatible = "regulator-fixed";
 		regulator-name = "v5v";
@@ -30,23 +23,14 @@
 		regulator-max-microvolt = <5000000>;
 		regulator-always-on;
 	};
-
-	vdd_sd: regulator-vdd_sd {
-		compatible = "regulator-fixed";
-		regulator-name = "vdd_sd";
-		regulator-min-microvolt = <3300000>;
-		regulator-max-microvolt = <3300000>;
-		regulator-always-on;
-	};
-
-	beeper:pwm-beeper {
+	
+	pwm-beeper {
 		compatible = "pwm-beeper";
-		/* pwm timers1, Channel 2 */
-		/* Use 440Hz which is default frequency for beep command */
-		pwms = <&pwm_beep 1 2272727>;
+		/* pwm timers1, Channel 1 */
+		pwms = <&pwm 0 5000000>;
 		amp-supply = <&v5v>;
 	};
-
+	
 	/* leds */
 	leds:led {
 		compatible = "gpio-leds";
@@ -55,14 +39,14 @@
 			label = "LED1";
 			gpios = <&gpioa 13 GPIO_ACTIVE_LOW>;
 			default-state = "off";
-			//linux,default-trigger = "heartbeat";
-			status = "disabled";
+			linux,default-trigger = "heartbeat";
+			status = "okay";
 		};
 		led2 {
 			label = "LED2";
 			gpios = <&gpioa 14 GPIO_ACTIVE_LOW>;
 			default-state = "off";
-			//linux,default-trigger = "heartbeat";
+			linux,default-trigger = "heartbeat";
 			status = "okay";
 		};
 		led3 {
@@ -73,57 +57,17 @@
 			status = "okay";
 		};
 	};
-
-	/* Sound interface */
-	sound {
-		compatible = "simple-audio-card";
-		simple-audio-card,name = "WM8510";
-		simple-audio-card,format = "i2s";
-		simple-audio-card,bitclock-master = <&sound1_cpu>;
-		simple-audio-card,frame-master = <&sound1_cpu>;
-		simple-audio-card,mclk-fs = <256>; /*factor x for mclk  = x*fs (framesynchro clock)*/
-		simple-audio-card,widgets =
-			"Speaker", "Ext Spk";
-		simple-audio-card,routing =
-			"Ext Spk", "SPKOUTP",
-			"Ext Spk", "SPKOUTN";
-		sound1_cpu: simple-audio-card,cpu {
-			sound-dai = <&i2s2>;
 };
-		sound1_codec: simple-audio-card,codec {
-			sound-dai = <&codec>;
-		};
-	};
 
-};
-
-
-&i2c4 {
+/* i2c interfaces */
+&i2c2 {
 	status = "okay";
-
-	codec: wm8510@1a {
-		#sound-dai-cells = <0>;
-		compatible = "wlf,wm8510";
-		reg = <0x1a>;
-		status = "okay";
-	};
-
-};
-
-&i2s2{
-	clocks = <&rcc SPI2>, <&rcc SPI2_K>, <&rcc PLL3_R>, <&rcc PLL3_Q>;
-	clock-names = "pclk", "i2sclk", "x8k", "x11k";
-	status="okay";
+	clock-frequency = <100000>;
 };
 
-
-/* Internal ADC reference voltage */
-&vrefbuf {
+&i2c4 {
 	status = "okay";
-	/* Set referece voltage to 2.5V */
-	regulator-max-microvolt = <2500000>;
-	regulator-min-microvolt = <2500000>;
-	vdda-supply = <&vdd>;
+	clock-frequency = <100000>;
 };
 
 /* ADC settings */
@@ -150,9 +94,6 @@
 	};
 
 	adc2: adc@100 {
-		// VREFINT VDDCORE VBAT/4 DAC_OUT1 DAC_OUT2
-		st,adc-channels = <13 14 15 16 17>;
-		st,min-sample-time-nsecs = <100000>;
 		status = "okay";
 	};
 
@@ -166,14 +107,11 @@
 
 /* sd interfaces */
 &sdmmc1 {
-	/* add opendrain pins which aren't generated by cubemx */
-	pinctrl-names = "default", "sleep", "opendrain";
-	pinctrl-0 = <&sdmmc1_pins_mx>;
-	pinctrl-1 = <&sdmmc1_sleep_pins_mx>;
-	pinctrl-2 = <&sdmmc1_od_pins>;
 	broken-cd;
+	//cd-gpios = <&gpioa 10 GPIO_ACTIVE_HIGH>;
+	st,dirpol;
+	st,negedge;
 	no-1-8-v;
-	st,neg-edge;
 	bus-width = <4>;
 	vmmc-supply = <&vdd_sd>;
 	status = "okay";
@@ -182,79 +120,17 @@
 
 /* emmc interface */
 &sdmmc2 {
-	/* add opendrain pins which aren't generated by cubemx */
-	pinctrl-names = "default", "sleep", "opendrain";
-	pinctrl-0 = <&sdmmc2_pins_mx>;
-	pinctrl-1 = <&sdmmc2_sleep_pins_mx>;
-	pinctrl-2 = <&sdmmc2_od_pins>;
 	non-removable;
 	no-sd;
 	no-sdio;
-	st,neg-edge;
-	mmc-ddr-3_3v;
+	st,dirpol;
+	st,negedge;
+	no-1-8-v;
 	bus-width = <4>;
 	vmmc-supply = <&v3v3>;
 	status = "okay";
 };
 
-&pinctrl {
-	/* add opendrain pin config */
-    sdmmc1_od_pins: sdmmc1_od@0 {
-        pins1 {
-            u-boot,dm-pre-reloc;
-            pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
-                     <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
-                     <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
-                     <STM32_PINMUX('C', 11, AF12)>; /* SDMMC1_D3 */
-            bias-pull-up;
-            drive-push-pull;
-            slew-rate = <1>;
-        };
-        pins2 {
-            u-boot,dm-pre-reloc;
-            pinmux = <STM32_PINMUX('C', 12, AF12)>; /* SDMMC1_CK */
-            bias-pull-up;
-            drive-push-pull;
-            slew-rate = <3>;
-        };
-        pins3 {
-            u-boot,dm-pre-reloc;
-            pinmux = <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
-            bias-pull-up;
-            drive-open-drain;
-            slew-rate = <1>;
-        };
-    };
-
-    sdmmc2_od_pins: sdmmc2_od@0 {
-        u-boot,dm-pre-reloc;
-        pins1 {
-            u-boot,dm-pre-reloc;
-            pinmux = <STM32_PINMUX('B', 3, AF9)>, /* SDMMC2_D2 */
-                     <STM32_PINMUX('B', 4, AF9)>, /* SDMMC2_D3 */
-                     <STM32_PINMUX('B', 14, AF9)>, /* SDMMC2_D0 */
-                     <STM32_PINMUX('B', 15, AF9)>; /* SDMMC2_D1 */
-            bias-pull-up;
-            drive-push-pull;
-            slew-rate = <1>;
-        };
-        pins2 {
-            u-boot,dm-pre-reloc;
-            pinmux = <STM32_PINMUX('E', 3, AF9)>; /* SDMMC2_CK */
-            bias-pull-up;
-            drive-push-pull;
-            slew-rate = <3>;
-        };
-        pins3 {
-            u-boot,dm-pre-reloc;
-            pinmux = <STM32_PINMUX('G', 6, AF10)>; /* SDMMC2_CMD */
-            bias-pull-up;
-            drive-open-drain;
-            slew-rate = <1>;
-        };
-    };
-};
-
 
 /* RS485 interface */
 &usart2 {
@@ -263,28 +139,14 @@
 };
 
 
-/* timer1: CH2 Beeper */
+/* timer1: CH1 BEEPER, CH3 Backlight */
 &timers1 {
     status = "okay";
 	/* spare dmas for other usage */
 	/delete-property/dmas;
 	/delete-property/dma-names;
-
-	pwm_beep:pwm {
-		#pwm-cells = <2>;
-		status = "okay";
-	};
-};
-
-
-/* timer4: CH3 Backlight */
-&timers4 {
-    status = "okay";
-	/* spare dmas for other usage */
-	/delete-property/dmas;
-	/delete-property/dma-names;
-
-	pwm_bl:pwm {
+    
+	pwm:pwm {
 		#pwm-cells = <2>;
 		status = "okay";
 	};
@@ -295,7 +157,6 @@
 &pinctrl {
     touch_pins_dev: touch_pins_dev@0 {
         pins {
-            /* touch int is initialized by touch driver */
             pinmux = <STM32_PINMUX('D', 9, GPIO)>, /* TOUCH_INT */
                      <STM32_PINMUX('D', 11, GPIO)>; /* TOUCH_WAKE */
             bias-pull-down;
@@ -304,38 +165,43 @@
 
 };
 
-&usbh_ehci {
-	/*
-	*	node structure for smsc95xx driver to find and pick up mac-address
-	*	eth1addr will be written into local-mac from u-boot
-	*/
-	usb1@1 {
-		compatible = "usb424,9514";
-		reg = <1>;
-		#address-cells = <1>;
-		#size-cells = <0>;
 
-		ethernet1: usbether@1 {
-			compatible = "usb424,ec00";
-			reg = <1>;
-			local-mac-address = [00 00 00 00 00 00];
-		};
-	};
-};
-
-/*
-* Disable usart6 for linux and enable m4 resource
-*/
+/* Sound interface */
+#if 0
+/* TODO configure sound interface */
+sound {
+	compatible = "simple-audio-card";
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_sound>;
+	simple-audio-card,name = "WM8510";
+	simple-audio-card,format = "i2s";
+	simple-audio-card,bitclock-master = <&sound1_codec>;
+	simple-audio-card,frame-master = <&sound1_codec>;
+	simple-audio-card,widgets =
+		"Speaker", "Ext Spk";
+	simple-audio-card,routing =
+		"Ext Spk", "SPKOUTP",
+		"Ext Spk", "SPKOUTN";
 
-&usart6{
-
-      status = "disabled";
+	sound1_cpu: simple-audio-card,cpu {
+		sound-dai = <&ssi2>;
+	};
 
+	sound1_codec: simple-audio-card,codec {
+		sound-dai = <&codec>;
+		clocks = <&codec_osc>;
+	};
 };
-&m4_usart6{
-
-    status = "okay";
+#endif
 
-};
+&i2c4 {
+	status = "okay";
 
+	codec: wm8510@1a {
+		#sound-dai-cells = <0>;
+		compatible = "wlf,wm8510";
+		reg = <0x1a>;
+		status = "okay";
+	};
 
+};
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-som-t1000-u-boot.dtsi b/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-som-t1000-u-boot.dtsi
index f9c842e7416175f546b311dbb5700a181916b5ef..c0dd52427c1c58d4f5611b66bb8913006c11c0eb 100644
--- a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-som-t1000-u-boot.dtsi
+++ b/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-som-t1000-u-boot.dtsi
@@ -8,118 +8,12 @@
  */
 
 /* force DDR settings */
-/* UNDEFs */
-#undef DDR_MEM_NAME
-#undef DDR_MEM_SPEED
-#undef DDR_MEM_SIZE
-
-#undef DDR_MSTR
-#undef DDR_MRCTRL0
-#undef DDR_MRCTRL1
-#undef DDR_DERATEEN
-#undef DDR_DERATEINT
-#undef DDR_PWRCTL
-#undef DDR_PWRTMG
-#undef DDR_HWLPCTL
-#undef DDR_RFSHCTL0
-#undef DDR_RFSHCTL3
-#undef DDR_RFSHTMG
-#undef DDR_CRCPARCTL0
-#undef DDR_DRAMTMG0
-#undef DDR_DRAMTMG1
-#undef DDR_DRAMTMG2
-#undef DDR_DRAMTMG3
-#undef DDR_DRAMTMG4
-#undef DDR_DRAMTMG5
-#undef DDR_DRAMTMG6
-#undef DDR_DRAMTMG7
-#undef DDR_DRAMTMG8
-#undef DDR_DRAMTMG14
-#undef DDR_ZQCTL0
-#undef DDR_DFITMG0
-#undef DDR_DFITMG1
-#undef DDR_DFILPCFG0
-#undef DDR_DFIUPD0
-#undef DDR_DFIUPD1
-#undef DDR_DFIUPD2
-#undef DDR_DFIPHYMSTR
-#undef DDR_ODTCFG
-#undef DDR_ODTMAP
-#undef DDR_SCHED
-#undef DDR_SCHED1
-#undef DDR_PERFHPR1
-#undef DDR_PERFLPR1
-#undef DDR_PERFWR1
-#undef DDR_DBG0
-#undef DDR_DBG1
-#undef DDR_DBGCMD
-#undef DDR_POISONCFG
-#undef DDR_PCCFG
-#undef DDR_PCFGR_0
-#undef DDR_PCFGW_0
-#undef DDR_PCFGQOS0_0
-#undef DDR_PCFGQOS1_0
-#undef DDR_PCFGWQOS0_0
-#undef DDR_PCFGWQOS1_0
-#undef DDR_PCFGR_1
-#undef DDR_PCFGW_1
-#undef DDR_PCFGQOS0_1
-#undef DDR_PCFGQOS1_1
-#undef DDR_PCFGWQOS0_1
-#undef DDR_PCFGWQOS1_1
-#undef DDR_ADDRMAP1
-#undef DDR_ADDRMAP2
-#undef DDR_ADDRMAP3
-#undef DDR_ADDRMAP4
-#undef DDR_ADDRMAP5
-#undef DDR_ADDRMAP6
-#undef DDR_ADDRMAP9
-#undef DDR_ADDRMAP10
-#undef DDR_ADDRMAP11
-#undef DDR_PGCR
-#undef DDR_PTR0
-#undef DDR_PTR1
-#undef DDR_PTR2
-#undef DDR_ACIOCR
-#undef DDR_DXCCR
-#undef DDR_DSGCR
-#undef DDR_DCR
-#undef DDR_DTPR0
-#undef DDR_DTPR1
-#undef DDR_DTPR2
-#undef DDR_MR0
-#undef DDR_MR1
-#undef DDR_MR2
-#undef DDR_MR3
-#undef DDR_ODTCR
-#undef DDR_ZQ0CR1
-#undef DDR_DX0GCR
-#undef DDR_DX0DLLCR
-#undef DDR_DX0DQTR
-#undef DDR_DX0DQSTR
-#undef DDR_DX1GCR
-#undef DDR_DX1DLLCR
-#undef DDR_DX1DQTR
-#undef DDR_DX1DQSTR
-#undef DDR_DX2GCR
-#undef DDR_DX2DLLCR
-#undef DDR_DX2DQTR
-#undef DDR_DX2DQSTR
-#undef DDR_DX3GCR
-#undef DDR_DX3DLLCR
-#undef DDR_DX3DQTR
-#undef DDR_DX3DQSTR
-
-//#include "stm32mp157-u-boot.dtsi"
 #include "stm32mp157c-t1000-ddr3-1x4Gb-1066-binG.h"
 #include "stm32mp15-ddr.dtsi"
 
 /* force clock settings */
 &rcc {
     u-boot,dm-pre-reloc;
-    st,hsi-cal;
-    st,csi-cal;
-    st,cal-sec = <60>;
     st,clksrc = <
         CLK_MPU_PLL1P
         CLK_AXI_PLL2P
@@ -140,63 +34,64 @@
         1         /*APB3*/
         1         /*APB4*/
         2         /*APB5*/
-        0         /*RTC*/
+        23         /*RTC*/
         0         /*MCO1*/
         0         /*MCO2*/
     >;
     st,pkcs = <
         CLK_CKPER_HSE
+		/*CLK_FMC_ACLK*/
         CLK_QSPI_ACLK
         CLK_ETH_PLL4P
-        CLK_SDMMC12_PLL4P
-		CLK_DSI_DSIPLL /* s disabled */
+        CLK_SDMMC12_PLL3R
+		CLK_DSI_DSIPLL
         CLK_STGEN_HSE
         CLK_USBPHY_HSE
-        CLK_SPI2S1_PLL3Q /* s disabled */
-        CLK_SPI2S23_PLL4P
-        CLK_SPI45_HSI /* s disabled */
-        CLK_SPI6_HSI /* s disabled */
+        CLK_SPI2S1_PLL3Q
+        CLK_SPI2S23_PLL3Q
+        CLK_SPI45_HSI
+        CLK_SPI6_HSI
         CLK_I2C46_HSI
-        CLK_SDMMC3_PLL3R  /* s disabled */
+        CLK_SDMMC3_PLL3R
         CLK_USBO_USBPHY
         CLK_ADC_CKPER
-        CLK_CEC_LSE  /* s disabled */
+        CLK_CEC_LSE
         CLK_I2C12_HSI
-        CLK_I2C35_HSI  /* s disabled */
-        CLK_UART1_HSI  /* s disabled */
-        CLK_UART24_PCLK1
-        CLK_UART35_HSI /* s disabled */
-        CLK_UART6_PCLK2
-        CLK_UART78_HSI /* s disabled */
-        CLK_SPDIF_PLL3Q /* s disabled */
+        CLK_I2C35_HSI
+        CLK_UART1_HSI
+        CLK_UART24_HSI
+        CLK_UART35_HSI
+        CLK_UART6_HSI
+        CLK_UART78_HSI
+        CLK_SPDIF_PLL3Q
         CLK_FDCAN_HSE
-        CLK_SAI1_PLL3Q /* s disabled */
-        CLK_SAI2_PLL3Q /* s disabled */
-        CLK_SAI3_PLL3Q /* s disabled */
-        CLK_SAI4_PLL3Q /* s disabled */
+        CLK_SAI1_PLL3Q
+        CLK_SAI2_PLL3Q
+        CLK_SAI3_PLL3Q
+        CLK_SAI4_PLL3Q
 		CLK_RNG1_CSI
 		CLK_RNG2_CSI
-        CLK_LPTIM1_PCLK1 /* s disabled */
-        CLK_LPTIM23_PCLK3 /* s disabled */
-        CLK_LPTIM45_PCLK3 /* s disabled */
+        CLK_LPTIM1_PCLK1
+        CLK_LPTIM23_PCLK3
+        CLK_LPTIM45_PCLK3
     >;
     pll1:st,pll@0 {
-        cfg = < 2 80 0 1 1 1>;
-        /*frac = < 0x800 >;*/
+        cfg = < 2 80 0 0 0 1>;
+        frac = < 0x800 >;
         u-boot,dm-pre-reloc;
     };
     pll2:st,pll@1 {
-        cfg = < 2 65 1 1 0 7>;
-        /*frac = < 0x1400 >;*/
+        cfg = < 2 65 1 0 0 5>;
+        frac = < 0x1400 >;
         u-boot,dm-pre-reloc;
     };
     pll3:st,pll@2 {
-		cfg = < 1 49 2 2 1 1>;
-        /*frac = < 0x9ba >;*/
+        cfg = < 2 97 3 15 7 5>;
+        frac = < 0x9ba >;
         u-boot,dm-pre-reloc;
     };
     pll4:st,pll@3 {
-		cfg = < 5 124 9 9 9 1>;
+        cfg = < 5 124 9 9 9 3>;
         u-boot,dm-pre-reloc;
     };
 };
@@ -204,6 +99,27 @@
 
 /* some fixups */
 
+&ethernet0 {
+	/* add missing MAC clock */
+	markerflag-patched-clock;
+
+	clock-names = "stmmaceth",
+		      "mac-clk-tx",
+		      "mac-clk-rx",
+		      "ethstp",
+		      "syscfg-clk",
+			  "mac-clk-ck";
+	clocks = <&rcc ETHMAC>,
+		 <&rcc ETHTX>,
+		 <&rcc ETHRX>,
+		 <&rcc ETHSTP>,
+		 <&rcc SYSCFG>,
+		 <&rcc ETHCK>;
+
+	/* use old mechanism - kernel has already new mechanism */
+	ex,provide-phy-clk; // provide 50MHz clock for phy
+};
+
 &usbotg_hs {
 	g-tx-fifo-size = <576>;
 };
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-som-t1000.dtsi b/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-som-t1000.dtsi
index dc83b42c78c9ddf881ec8e16e6c2f24d6b146282..7e44e0b919f806d2c26e9ac2eff2c439c19d3cfb 100644
--- a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-som-t1000.dtsi
+++ b/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-som-t1000.dtsi
@@ -1,8 +1,7 @@
 /* Devicetree file for device
  *
- * device    : stm32mp-som-t1000
- * board code: 40099 130
- * revision  : prototype
+ * device   : stm32mp-som-t1000
+ * revision : prototype
  *
  * Kontron Electronics GmbH
  * Copyright 2018 Kontron Electronics GmbH. All rights reserved.
@@ -13,17 +12,15 @@
 / {
 	device-identification {
 		som = "t1000";
-		som_pcb = "1 951 1616";
-		som_code = "40099 130 02";
+		som_pcb = "1 950 1616";
+		som_code = "prototype_r000 (40099130_r???)";
 	};
 
 	chosen {
-		bootargs = "earlyprintk console=ttySTM0,115200 root=/dev/ram";
-		stdout-path = "serial0:115200n8";
+		stdout-path = "serial3:115200n8";
 	};
 
 	aliases {
-		serial0 = &uart4;
 		ethernet0 = "/soc/ethernet@5800a000";
 		i2c1 = "/soc/i2c@40013000";
 		i2c2 = "/soc/i2c@5c002000";
@@ -73,6 +70,23 @@
 		regulator-always-on;
 	};
 
+	vdd_sd: regulator-vdd_sd {
+		compatible = "regulator-fixed";
+		regulator-name = "vdd_sd";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-always-on;
+	};
+
+	/* Analog reference voltage - may be adapted to board */
+	vdda: regulator-vdda {
+		compatible = "regulator-fixed";
+		regulator-name = "vdda";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-always-on;
+	};
+
 	/* Set reset_out to low */
 	reset_out: regulator-reset_out {
 		compatible = "regulator-fixed";
@@ -90,62 +104,29 @@
 		#size-cells = <1>;
 		ranges;
 
-		retram: retram@0x38000000 {
-			compatible = "shared-dma-pool";
-			reg = <0x38000000 0x10000>;
-			no-map;
-		};
-
-		mcuram: mcuram@0x30000000 {
-			compatible = "shared-dma-pool";
-			reg = <0x30000000 0x40000>;
-			no-map;
-		};
-
-		mcuram2: mcuram2@0x10000000 {
-			compatible = "shared-dma-pool";
-			reg = <0x10000000 0x40000>;
-			no-map;
-		};
-
-		vdev0vring0: vdev0vring0@10040000 {
+		ipc_share: sram_rproc@10040000 {
 			compatible = "shared-dma-pool";
-			reg = <0x10040000 0x2000>;
+			reg = <0x10040000 0x10000>;
 			no-map;
 		};
 
-		vdev0vring1: vdev0vring1@10042000 {
-			compatible = "shared-dma-pool";
-			reg = <0x10042000 0x2000>;
+		dma1_reserved: sram_dma1@10050000 {
+			reg = <0x10050000 0x8000>;
 			no-map;
 		};
 
-		vdev0buffer: vdev0buffer@10044000 {
-			compatible = "shared-dma-pool";
-			reg = <0x10044000 0x4000>;
+		dma2_reserved: sram_dma2@10058000 {
+			reg = <0x10058000 0x8000>;
 			no-map;
 		};
 
-		gpu_reserved: gpu@dc000000 {
-			/* 64MB reserved for GPU (min 32MB, max 192MB)
-			 * REMARK: RAM starts at 0xC0000000 and this is the end of RAM */
-			reg = <0xdc000000 0x4000000>;
+		gcnano_reserved: gpu@f8000000 {
+			/* 128MB reserved for GPU (min 32MB, max 192MB) */
+			reg = <0xf8000000 0x8000000>;
 			no-map;
 		};
 	};
 
-	sram: sram@10050000 {
-		compatible = "mmio-sram";
-		reg = <0x10050000 0x10000>;
-		#address-cells = <1>;
-		#size-cells = <1>;
-		ranges = <0 0x10050000 0x10000>;
-
-		dma_pool: dma_pool@0 {
-			reg = <0x0 0x10000>;
-			pool;
-		};
-	};
 };
 
 
@@ -188,11 +169,23 @@
 	phy-mode = "rmii";
 	max-speed = <100>;
 	phy-handle = <&phy0>;
-
-	st,eth_ref_clk_sel; /* Use internal clock for PHY (clocktree in tf-a must match) */
-
-	/*local mac address in which ethaddr gets written*/
-	local-mac-address = [00 00 00 00 00 00];
+	st,int-phyclk;	/* Use internal clock for PHY (clocktree in tf-a must match) */
+
+	/* clock eth-ck is missing in ST SOC description. Here it is fixed.
+	 * Should be removed if ST definition is fixed (Beta1) */
+	clock-names = "stmmaceth",
+		      "mac-clk-tx",
+		      "mac-clk-rx",
+		      "ethstp",
+		      "syscfg-clk",
+			  "eth-ck";
+
+	clocks = <&rcc ETHMAC>,
+		 <&rcc ETHTX>,
+		 <&rcc ETHRX>,
+		 <&rcc ETHSTP>,
+		 <&rcc SYSCFG>,
+		 <&rcc ETHCK_K>;
 
 	mdio0 {
 		#address-cells = <1>;
@@ -219,12 +212,10 @@
     pinctrl-0 = <&quadspi_pins_som>;
     pinctrl-1 = <&quadspi_sleep_pins_som>;
 
-	/* QSPI NOR for boot */
 	flash0: mx25r1635f@0 {
 		u-boot,dm-pre-reloc;
 		compatible = "spi-flash", "jedec,spi-nor";
 		reg = <0>;
-
 		spi-rx-bus-width = <4>;
 		spi-tx-bus-width = <4>;
 		spi-max-frequency = <8000000>; /* MX25R1635F is slow */
@@ -233,7 +224,8 @@
 		#address-cells = <1>;
 		#size-cells = <1>;
 	};
-	/* QSPI NAND for rootfs and data */
+#if 0
+	/* this confuses the driver */
 	flash1: spinand@1 {
 		u-boot,dm-pre-reloc;
 		compatible = "spi-nand";
@@ -246,6 +238,7 @@
 		#address-cells = <1>;
 		#size-cells = <1>;
 	};
+#endif
 };
 
 
@@ -272,7 +265,7 @@
 
 /* USB settings */
 &usbh_ohci {
-    status = "okay";
+    status = "disabled";
 };
 
 
@@ -285,9 +278,6 @@
 
 &usbotg_hs {
 	status = "okay";
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&usb_otg_hs_pins_som>;
-	pinctrl-1 = <&usb_otg_hs_sleep_pins_som>;
 	phys = <&usbphyc_port1 0>;
 	phy-names = "usb2-phy";
 	//vbus-supply = <&vbus_otg>;
@@ -299,7 +289,6 @@
 	status = "okay";
 	vdda1v1-supply = <&reg11>;
 	vdda1v8-supply = <&reg18>;
-	vdd3v3-supply = <&vdd_usb>;
 };
 
 
@@ -314,9 +303,9 @@
 
 
 /* GPU settings */
-&gpu {
+&gcnano {
 	status = "okay";
-	contiguous-area = <&gpu_reserved>;
+	contiguous-area = <&gcnano_reserved>;
 };
 
 
@@ -325,20 +314,14 @@
 };
 
 
-&crc1{
-	/* enabling crc currently leads to sd/emmc disfunction */
-    status = "disabled";
-};
-
-
 /* DMA settings */
 &dma1 {
-	sram = <&dma_pool>;
+	memory-region = <&dma1_reserved>;
 };
 
 
 &dma2 {
-	sram = <&dma_pool>;
+	memory-region = <&dma2_reserved>;
 };
 
 
@@ -364,10 +347,9 @@
 /* reserved ressources for m4 */
 &m4_rproc {
 	status = "okay";
-	memory-region = <&retram>, <&mcuram>, <&mcuram2>, <&vdev0vring0>,
-			<&vdev0vring1>, <&vdev0buffer>;
-	mboxes = <&ipcc 0>, <&ipcc 1>, <&ipcc 2>;
-	mbox-names = "vq0", "vq1", "shutdown";
+	memory-region = <&ipc_share>;
+	mboxes = <&ipcc 0>, <&ipcc 1>;
+	mbox-names = "vq0", "vq1";
 	interrupt-parent = <&exti>;
 	interrupts = <68 1>;
 	interrupt-names = "wdg";
@@ -378,42 +360,41 @@
 &pinctrl {
     eth1_pins_som: eth1_som@0 {
         pins1 {
-            pinmux = <STM32_PINMUX('B', 12, AF11)>, /* ETH1_TXD0 */
+            pinmux = <STM32_PINMUX('A', 2, AF11)>, /* ETH1_MDIO */
+                     <STM32_PINMUX('B', 11, AF11)>, /* ETH1_TX_EN */
+                     <STM32_PINMUX('B', 12, AF11)>, /* ETH1_TXD0 */
                      <STM32_PINMUX('B', 13, AF11)>, /* ETH1_TXD1 */
                      <STM32_PINMUX('C', 1, AF11)>, /* ETH1_MDC */
                      <STM32_PINMUX('G', 8, AF2)>; /* ETH1_CLK */
             bias-disable;
             drive-push-pull;
-            slew-rate = <1>;
+            slew-rate = <3>;
         };
         pins2 {
-            pinmux = <STM32_PINMUX('A', 2, AF11)>; /* ETH1_MDIO */
-            bias-disable;
-            drive-push-pull;
-            slew-rate = <0>;
-        };
-        pins3 {
             pinmux = <STM32_PINMUX('A', 7, AF11)>, /* ETH1_CRS_DV */
                      <STM32_PINMUX('C', 4, AF11)>, /* ETH1_RXD0 */
                      <STM32_PINMUX('C', 5, AF11)>; /* ETH1_RXD1 */
             bias-disable;
         };
-        pins4 {
-            pinmux = <STM32_PINMUX('B', 11, AF11)>; /* ETH1_TX_EN */
-        };
     };
 
     eth1_sleep_pins_som: eth1_sleep_som@0 {
-        pins {
-            pinmux = <STM32_PINMUX('A', 2, ANALOG)>, /* ETH1_MDIO */
-                     <STM32_PINMUX('A', 7, ANALOG)>, /* ETH1_CRS_DV */
-                     <STM32_PINMUX('B', 11, ANALOG)>, /* ETH1_TX_EN */
-                     <STM32_PINMUX('B', 12, ANALOG)>, /* ETH1_TXD0 */
-                     <STM32_PINMUX('B', 13, ANALOG)>, /* ETH1_TXD1 */
-                     <STM32_PINMUX('C', 1, ANALOG)>, /* ETH1_MDC */
-                     <STM32_PINMUX('C', 4, ANALOG)>, /* ETH1_RXD0 */
-                     <STM32_PINMUX('C', 5, ANALOG)>, /* ETH1_RXD1 */
-                     <STM32_PINMUX('G', 8, ANALOG)>; /* ETH1_CLK */
+        pins1 {
+            pinmux = <STM32_PINMUX('A', 2, AF11)>, /* ETH1_MDIO */
+                     <STM32_PINMUX('B', 11, AF11)>, /* ETH1_TX_EN */
+                     <STM32_PINMUX('B', 12, AF11)>, /* ETH1_TXD0 */
+                     <STM32_PINMUX('B', 13, AF11)>, /* ETH1_TXD1 */
+                     <STM32_PINMUX('C', 1, AF11)>, /* ETH1_MDC */
+                     <STM32_PINMUX('G', 8, AF2)>; /* ETH1_CLK */
+            bias-disable;
+            drive-push-pull;
+            slew-rate = <3>;
+        };
+        pins2 {
+            pinmux = <STM32_PINMUX('A', 7, AF11)>, /* ETH1_CRS_DV */
+                     <STM32_PINMUX('C', 4, AF11)>, /* ETH1_RXD0 */
+                     <STM32_PINMUX('C', 5, AF11)>; /* ETH1_RXD1 */
+            bias-disable;
         };
     };
 
@@ -429,24 +410,21 @@
 
     i2c2_sleep_pins_som: i2c2_sleep_som@0 {
         pins {
-            pinmux = <STM32_PINMUX('D', 7, ANALOG)>, /* I2C2_SCL */
-                     <STM32_PINMUX('G', 15, ANALOG)>; /* I2C2_SDA */
+            pinmux = <STM32_PINMUX('D', 7, AF4)>, /* I2C2_SCL */
+                     <STM32_PINMUX('G', 15, AF4)>; /* I2C2_SDA */
+            bias-disable;
+            drive-open-drain;
+            slew-rate = <0>;
         };
     };
 
     quadspi_pins_som: quadspi_som@0 {
         u-boot,dm-pre-reloc;
-        pins1 {
+        pins {
             u-boot,dm-pre-reloc;
             pinmux = <STM32_PINMUX('B', 6, AF10)>, /* QUADSPI_BK1_NCS */
-                     <STM32_PINMUX('C', 0, AF10)>; /* QUADSPI_BK2_NCS */
-            bias-pull-up;
-            drive-push-pull;
-            slew-rate = <3>;
-        };
-        pins2 {
-            u-boot,dm-pre-reloc;
-            pinmux = <STM32_PINMUX('E', 7, AF10)>, /* QUADSPI_BK2_IO0 */
+                     <STM32_PINMUX('C', 0, AF10)>, /* QUADSPI_BK2_NCS */
+                     <STM32_PINMUX('E', 7, AF10)>, /* QUADSPI_BK2_IO0 */
                      <STM32_PINMUX('E', 8, AF10)>, /* QUADSPI_BK2_IO1 */
                      <STM32_PINMUX('E', 9, AF10)>, /* QUADSPI_BK2_IO2 */
                      <STM32_PINMUX('E', 10, AF10)>, /* QUADSPI_BK2_IO3 */
@@ -497,28 +475,18 @@
 
     uart4_sleep_pins_som: uart4_sleep_som@0 {
         u-boot,dm-pre-reloc;
-        pins {
-            u-boot,dm-pre-reloc;
-            pinmux = <STM32_PINMUX('B', 2, ANALOG)>, /* UART4_RX */
-                     <STM32_PINMUX('G', 11, ANALOG)>; /* UART4_TX */
-        };
-    };
-
-    usb_otg_hs_pins_som: usb_otg_hs_som-0 {
-        u-boot,dm-pre-reloc;
-        pins {
+        pins1 {
             u-boot,dm-pre-reloc;
-            pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
+            pinmux = <STM32_PINMUX('G', 11, AF6)>; /* UART4_TX */
+            bias-pull-up;
+            drive-push-pull;
+            slew-rate = <0>;
         };
-    };
-
-    usb_otg_hs_sleep_pins_som: usb_otg_hs_sleep_som-0 {
-        u-boot,dm-pre-reloc;
-        pins {
+        pins2 {
             u-boot,dm-pre-reloc;
-            pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
+            pinmux = <STM32_PINMUX('B', 2, AF8)>; /* UART4_RX */
+            bias-pull-up;
         };
     };
-
-
 };
+
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-som-t1001-u-boot.dtsi b/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-som-t1001-u-boot.dtsi
deleted file mode 100644
index f9c842e7416175f546b311dbb5700a181916b5ef..0000000000000000000000000000000000000000
--- a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-som-t1001-u-boot.dtsi
+++ /dev/null
@@ -1,209 +0,0 @@
-/* Devicetree file for device
- *
- * device   : stm32mp-som-t1000-u-boot
- * revision : prototype
- *
- * Kontron Electronics GmbH
- * Copyright 2018 Kontron Electronics GmbH. All rights reserved.
- */
-
-/* force DDR settings */
-/* UNDEFs */
-#undef DDR_MEM_NAME
-#undef DDR_MEM_SPEED
-#undef DDR_MEM_SIZE
-
-#undef DDR_MSTR
-#undef DDR_MRCTRL0
-#undef DDR_MRCTRL1
-#undef DDR_DERATEEN
-#undef DDR_DERATEINT
-#undef DDR_PWRCTL
-#undef DDR_PWRTMG
-#undef DDR_HWLPCTL
-#undef DDR_RFSHCTL0
-#undef DDR_RFSHCTL3
-#undef DDR_RFSHTMG
-#undef DDR_CRCPARCTL0
-#undef DDR_DRAMTMG0
-#undef DDR_DRAMTMG1
-#undef DDR_DRAMTMG2
-#undef DDR_DRAMTMG3
-#undef DDR_DRAMTMG4
-#undef DDR_DRAMTMG5
-#undef DDR_DRAMTMG6
-#undef DDR_DRAMTMG7
-#undef DDR_DRAMTMG8
-#undef DDR_DRAMTMG14
-#undef DDR_ZQCTL0
-#undef DDR_DFITMG0
-#undef DDR_DFITMG1
-#undef DDR_DFILPCFG0
-#undef DDR_DFIUPD0
-#undef DDR_DFIUPD1
-#undef DDR_DFIUPD2
-#undef DDR_DFIPHYMSTR
-#undef DDR_ODTCFG
-#undef DDR_ODTMAP
-#undef DDR_SCHED
-#undef DDR_SCHED1
-#undef DDR_PERFHPR1
-#undef DDR_PERFLPR1
-#undef DDR_PERFWR1
-#undef DDR_DBG0
-#undef DDR_DBG1
-#undef DDR_DBGCMD
-#undef DDR_POISONCFG
-#undef DDR_PCCFG
-#undef DDR_PCFGR_0
-#undef DDR_PCFGW_0
-#undef DDR_PCFGQOS0_0
-#undef DDR_PCFGQOS1_0
-#undef DDR_PCFGWQOS0_0
-#undef DDR_PCFGWQOS1_0
-#undef DDR_PCFGR_1
-#undef DDR_PCFGW_1
-#undef DDR_PCFGQOS0_1
-#undef DDR_PCFGQOS1_1
-#undef DDR_PCFGWQOS0_1
-#undef DDR_PCFGWQOS1_1
-#undef DDR_ADDRMAP1
-#undef DDR_ADDRMAP2
-#undef DDR_ADDRMAP3
-#undef DDR_ADDRMAP4
-#undef DDR_ADDRMAP5
-#undef DDR_ADDRMAP6
-#undef DDR_ADDRMAP9
-#undef DDR_ADDRMAP10
-#undef DDR_ADDRMAP11
-#undef DDR_PGCR
-#undef DDR_PTR0
-#undef DDR_PTR1
-#undef DDR_PTR2
-#undef DDR_ACIOCR
-#undef DDR_DXCCR
-#undef DDR_DSGCR
-#undef DDR_DCR
-#undef DDR_DTPR0
-#undef DDR_DTPR1
-#undef DDR_DTPR2
-#undef DDR_MR0
-#undef DDR_MR1
-#undef DDR_MR2
-#undef DDR_MR3
-#undef DDR_ODTCR
-#undef DDR_ZQ0CR1
-#undef DDR_DX0GCR
-#undef DDR_DX0DLLCR
-#undef DDR_DX0DQTR
-#undef DDR_DX0DQSTR
-#undef DDR_DX1GCR
-#undef DDR_DX1DLLCR
-#undef DDR_DX1DQTR
-#undef DDR_DX1DQSTR
-#undef DDR_DX2GCR
-#undef DDR_DX2DLLCR
-#undef DDR_DX2DQTR
-#undef DDR_DX2DQSTR
-#undef DDR_DX3GCR
-#undef DDR_DX3DLLCR
-#undef DDR_DX3DQTR
-#undef DDR_DX3DQSTR
-
-//#include "stm32mp157-u-boot.dtsi"
-#include "stm32mp157c-t1000-ddr3-1x4Gb-1066-binG.h"
-#include "stm32mp15-ddr.dtsi"
-
-/* force clock settings */
-&rcc {
-    u-boot,dm-pre-reloc;
-    st,hsi-cal;
-    st,csi-cal;
-    st,cal-sec = <60>;
-    st,clksrc = <
-        CLK_MPU_PLL1P
-        CLK_AXI_PLL2P
-        CLK_MCU_PLL3P
-        CLK_PLL12_HSE
-        CLK_PLL3_HSE
-        CLK_PLL4_HSE
-        CLK_RTC_LSE
-        CLK_MCO1_DISABLED
-        CLK_MCO2_DISABLED
-    >;
-    st,clkdiv = <
-        1         /*MPU*/
-        0         /*AXI*/
-        0         /*MCU*/
-        1         /*APB1*/
-        1         /*APB2*/
-        1         /*APB3*/
-        1         /*APB4*/
-        2         /*APB5*/
-        0         /*RTC*/
-        0         /*MCO1*/
-        0         /*MCO2*/
-    >;
-    st,pkcs = <
-        CLK_CKPER_HSE
-        CLK_QSPI_ACLK
-        CLK_ETH_PLL4P
-        CLK_SDMMC12_PLL4P
-		CLK_DSI_DSIPLL /* s disabled */
-        CLK_STGEN_HSE
-        CLK_USBPHY_HSE
-        CLK_SPI2S1_PLL3Q /* s disabled */
-        CLK_SPI2S23_PLL4P
-        CLK_SPI45_HSI /* s disabled */
-        CLK_SPI6_HSI /* s disabled */
-        CLK_I2C46_HSI
-        CLK_SDMMC3_PLL3R  /* s disabled */
-        CLK_USBO_USBPHY
-        CLK_ADC_CKPER
-        CLK_CEC_LSE  /* s disabled */
-        CLK_I2C12_HSI
-        CLK_I2C35_HSI  /* s disabled */
-        CLK_UART1_HSI  /* s disabled */
-        CLK_UART24_PCLK1
-        CLK_UART35_HSI /* s disabled */
-        CLK_UART6_PCLK2
-        CLK_UART78_HSI /* s disabled */
-        CLK_SPDIF_PLL3Q /* s disabled */
-        CLK_FDCAN_HSE
-        CLK_SAI1_PLL3Q /* s disabled */
-        CLK_SAI2_PLL3Q /* s disabled */
-        CLK_SAI3_PLL3Q /* s disabled */
-        CLK_SAI4_PLL3Q /* s disabled */
-		CLK_RNG1_CSI
-		CLK_RNG2_CSI
-        CLK_LPTIM1_PCLK1 /* s disabled */
-        CLK_LPTIM23_PCLK3 /* s disabled */
-        CLK_LPTIM45_PCLK3 /* s disabled */
-    >;
-    pll1:st,pll@0 {
-        cfg = < 2 80 0 1 1 1>;
-        /*frac = < 0x800 >;*/
-        u-boot,dm-pre-reloc;
-    };
-    pll2:st,pll@1 {
-        cfg = < 2 65 1 1 0 7>;
-        /*frac = < 0x1400 >;*/
-        u-boot,dm-pre-reloc;
-    };
-    pll3:st,pll@2 {
-		cfg = < 1 49 2 2 1 1>;
-        /*frac = < 0x9ba >;*/
-        u-boot,dm-pre-reloc;
-    };
-    pll4:st,pll@3 {
-		cfg = < 5 124 9 9 9 1>;
-        u-boot,dm-pre-reloc;
-    };
-};
-
-
-/* some fixups */
-
-&usbotg_hs {
-	g-tx-fifo-size = <576>;
-};
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-som-t1001.dtsi b/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-som-t1001.dtsi
deleted file mode 100644
index a6984c7cc66c3ddb7a0a13fcf8a7e4e83b202dc0..0000000000000000000000000000000000000000
--- a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-som-t1001.dtsi
+++ /dev/null
@@ -1,393 +0,0 @@
-/* Devicetree file for device
- *
- * device    : stm32mp-som-t1001
- * board code: 40099 164
- * revision  : 00
- *
- * Kontron Electronics GmbH
- * Copyright 2019 Kontron Electronics GmbH. All rights reserved.
- */
-
-#include <dt-bindings/gpio/gpio.h>
-
-/ {
-	device-identification {
-		som = "t1001";
-		som_pcb = "1 950 1743";
-		som_code = "40099 164 00";
-	};
-
-	chosen {
-		bootargs = "earlyprintk console=ttySTM0,115200 root=/dev/ram";
-		stdout-path = "serial0:115200n8";
-	};
-
-	aliases {
-		serial0 = &uart4;
-		i2c1 = "/soc/i2c@40013000";
-		mmc0 = "/soc/sdmmc@58005000";
-		spi0 = "/soc/qspi@58003000";
-	};
-
-    /* Regulators */
-	vddcore: regulator-vddcore {
-		compatible = "regulator-fixed";
-		regulator-name = "vddcore";
-		regulator-min-microvolt = <1200000>;
-		regulator-max-microvolt = <1200000>;
-		regulator-always-on;
-	};
-
-	vdd_ddr: regulator-vdd_ddr {
-		compatible = "regulator-fixed";
-		regulator-name = "vdd_ddr";
-		regulator-min-microvolt = <1350000>;
-		regulator-max-microvolt = <1350000>;
-		regulator-always-on;
-	};
-
-	vdd_usb: regulator-vdd_usb {
-		compatible = "regulator-fixed";
-		regulator-name = "vdd_usb";
-		regulator-min-microvolt = <3300000>;
-		regulator-max-microvolt = <3300000>;
-		regulator-always-on;
-	};
-
-	vdd: regulator-vdd {
-		compatible = "regulator-fixed";
-		regulator-name = "vdd";
-		regulator-min-microvolt = <3300000>;
-		regulator-max-microvolt = <3300000>;
-		regulator-always-on;
-	};
-
-	v3v3: regulator-v3v3 {
-		compatible = "regulator-fixed";
-		regulator-name = "v3v3";
-		regulator-min-microvolt = <3300000>;
-		regulator-max-microvolt = <3300000>;
-		regulator-always-on;
-	};
-
-	/* Set reset_out to low */
-	reset_out: regulator-reset_out {
-		compatible = "regulator-fixed";
-		regulator-name = "reset_out";
-		regulator-min-microvolt = <3300000>;
-		regulator-max-microvolt = <3300000>;
-		gpio = <&gpiod 15 GPIO_ACTIVE_HIGH>;
-		regulator-always-on;
-		regulator-boot-on;
-	};
-
-	/* Memory reservations */
-	reserved-memory {
-		#address-cells = <1>;
-		#size-cells = <1>;
-		ranges;
-
-		retram: retram@0x38000000 {
-			compatible = "shared-dma-pool";
-			reg = <0x38000000 0x10000>;
-			no-map;
-		};
-
-		mcuram: mcuram@0x30000000 {
-			compatible = "shared-dma-pool";
-			reg = <0x30000000 0x40000>;
-			no-map;
-		};
-
-		mcuram2: mcuram2@0x10000000 {
-			compatible = "shared-dma-pool";
-			reg = <0x10000000 0x40000>;
-			no-map;
-		};
-
-		vdev0vring0: vdev0vring0@10040000 {
-			compatible = "shared-dma-pool";
-			reg = <0x10040000 0x2000>;
-			no-map;
-		};
-
-		vdev0vring1: vdev0vring1@10042000 {
-			compatible = "shared-dma-pool";
-			reg = <0x10042000 0x2000>;
-			no-map;
-		};
-
-		vdev0buffer: vdev0buffer@10044000 {
-			compatible = "shared-dma-pool";
-			reg = <0x10044000 0x4000>;
-			no-map;
-		};
-
-		gpu_reserved: gpu@dc000000 {
-			/* 64MB reserved for GPU (min 32MB, max 192MB)
-			 * REMARK: RAM starts at 0xC0000000 and this is the end of RAM */
-			reg = <0xdc000000 0x4000000>;
-			no-map;
-		};
-	};
-
-	sram: sram@10050000 {
-		compatible = "mmio-sram";
-		reg = <0x10050000 0x10000>;
-		#address-cells = <1>;
-		#size-cells = <1>;
-		ranges = <0 0x10050000 0x10000>;
-
-		dma_pool: dma_pool@0 {
-			reg = <0x0 0x10000>;
-			pool;
-		};
-	};
-};
-
-
-/* reset and clock distribution */
-&rcc {
-    u-boot,dm-pre-reloc;
-    status = "okay";
-};
-
-
-/* internal rtc */
-&rtc {
-	status = "okay";
-};
-
-
-/* qspi interface */
-&qspi {
-    u-boot,dm-pre-reloc;
-	status = "okay";
-	#address-cells = <1>;
-	#size-cells = <0>;
-    pinctrl-names = "default", "sleep";
-    pinctrl-0 = <&quadspi_pins_som>;
-    pinctrl-1 = <&quadspi_sleep_pins_som>;
-
-	/* QSPI NOR for boot */
-	flash0: mx25r1635f@0 {
-		u-boot,dm-pre-reloc;
-		compatible = "spi-flash", "jedec,spi-nor";
-		reg = <0>;
-
-		spi-rx-bus-width = <4>;
-		spi-tx-bus-width = <4>;
-		spi-max-frequency = <8000000>; /* MX25R1635F is slow */
-
-		/* required for partitions when mtdparts in u-boot are used */
-		#address-cells = <1>;
-		#size-cells = <1>;
-	};
-};
-
-
-/* UART console */
-&uart4 {
-    u-boot,dm-pre-reloc;
-    pinctrl-names = "default", "sleep";
-    pinctrl-0 = <&uart4_pins_som>;
-    pinctrl-1 = <&uart4_sleep_pins_som>;
-    status = "okay";
-};
-
-
-/* Internal ADC reference voltage */
-/* Fallback configuration */
-&vrefbuf {
-	status = "okay";
-	/* Set referece voltage to 2.5V */
-	regulator-max-microvolt = <2500000>;
-	regulator-min-microvolt = <2500000>;
-	/*vdda-supply = <&vdd>;*/
-};
-
-
-/* USB settings */
-&usbh_ohci {
-    status = "okay";
-};
-
-
-&usbh_ehci {
-	status = "okay";
-	phys = <&usbphyc_port0>;
-	phy-names = "usb";
-};
-
-
-&usbotg_hs {
-	status = "okay";
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&usb_otg_hs_pins_som>;
-	pinctrl-1 = <&usb_otg_hs_sleep_pins_som>;
-	phys = <&usbphyc_port1 0>;
-	phy-names = "usb2-phy";
-	//vbus-supply = <&vbus_otg>;
-	usb33d-supply = <&usb33>;
-};
-
-
-&usbphyc {
-	status = "okay";
-	vdda1v1-supply = <&reg11>;
-	vdda1v8-supply = <&reg18>;
-	vdd3v3-supply = <&vdd_usb>;
-};
-
-
-&usbphyc_port0 {
-	phy-supply = <&vdd_usb>;
-};
-
-
-&usbphyc_port1 {
-	phy-supply = <&vdd_usb>;
-};
-
-
-/* GPU settings */
-&gpu {
-	status = "okay";
-	contiguous-area = <&gpu_reserved>;
-};
-
-
-&rng1 {
-	status = "okay";
-};
-
-
-&crc1{
-	/* enabling crc currently leads to sd/emmc disfunction */
-    status = "disabled";
-};
-
-
-/* DMA settings */
-&dma1 {
-	sram = <&dma_pool>;
-};
-
-
-&dma2 {
-	sram = <&dma_pool>;
-};
-
-
-/* Independent watchdog */
-&iwdg2 {
-	status = "okay";
-	timeout-sec = <32>;
-};
-
-
-/* Power control */
-&pwr {
-	pwr-supply = <&vdd>;
-};
-
-
-/* uC interface */
-&ipcc {
-	status = "okay";
-};
-
-
-/* reserved ressources for m4 */
-&m4_rproc {
-	status = "okay";
-	memory-region = <&retram>, <&mcuram>, <&mcuram2>, <&vdev0vring0>,
-			<&vdev0vring1>, <&vdev0buffer>;
-	mboxes = <&ipcc 0>, <&ipcc 1>, <&ipcc 2>;
-	mbox-names = "vq0", "vq1", "shutdown";
-	interrupt-parent = <&exti>;
-	interrupts = <68 1>;
-	interrupt-names = "wdg";
-};
-
-
-/* pin configuration */
-&pinctrl {
-
-    quadspi_pins_som: quadspi_som@0 {
-        u-boot,dm-pre-reloc;
-        pins1 {
-            u-boot,dm-pre-reloc;
-            pinmux = <STM32_PINMUX('B', 6, AF10)>; /* QUADSPI_BK1_NCS */
-            bias-pull-up;
-            drive-push-pull;
-            slew-rate = <3>;
-        };
-        pins2 {
-            u-boot,dm-pre-reloc;
-            pinmux = <STM32_PINMUX('F', 6, AF9)>, /* QUADSPI_BK1_IO3 */
-                     <STM32_PINMUX('F', 7, AF9)>, /* QUADSPI_BK1_IO2 */
-                     <STM32_PINMUX('F', 8, AF10)>, /* QUADSPI_BK1_IO0 */
-                     <STM32_PINMUX('F', 9, AF10)>, /* QUADSPI_BK1_IO1 */
-                     <STM32_PINMUX('F', 10, AF9)>; /* QUADSPI_CLK */
-            bias-disable;
-            drive-push-pull;
-            slew-rate = <3>;
-        };
-    };
-
-    quadspi_sleep_pins_som: quadspi_sleep_som@0 {
-        u-boot,dm-pre-reloc;
-        pins {
-            u-boot,dm-pre-reloc;
-            pinmux = <STM32_PINMUX('F', 6, ANALOG)>, /* QUADSPI_BK1_IO3 */
-                     <STM32_PINMUX('F', 7, ANALOG)>, /* QUADSPI_BK1_IO2 */
-                     <STM32_PINMUX('F', 8, ANALOG)>, /* QUADSPI_BK1_IO0 */
-                     <STM32_PINMUX('F', 9, ANALOG)>, /* QUADSPI_BK1_IO1 */
-                     <STM32_PINMUX('F', 10, ANALOG)>; /* QUADSPI_CLK */
-        };
-    };
-
-    uart4_pins_som: uart4_som@0 {
-        u-boot,dm-pre-reloc;
-        pins1 {
-            u-boot,dm-pre-reloc;
-            pinmux = <STM32_PINMUX('G', 11, AF6)>; /* UART4_TX */
-            bias-pull-up;
-            drive-push-pull;
-            slew-rate = <0>;
-        };
-        pins2 {
-            u-boot,dm-pre-reloc;
-            pinmux = <STM32_PINMUX('B', 2, AF8)>; /* UART4_RX */
-            bias-pull-up;
-        };
-    };
-
-    uart4_sleep_pins_som: uart4_sleep_som@0 {
-        u-boot,dm-pre-reloc;
-        pins {
-            u-boot,dm-pre-reloc;
-            pinmux = <STM32_PINMUX('B', 2, ANALOG)>, /* UART4_RX */
-                     <STM32_PINMUX('G', 11, ANALOG)>; /* UART4_TX */
-        };
-    };
-
-    usb_otg_hs_pins_som: usb_otg_hs_som-0 {
-        u-boot,dm-pre-reloc;
-        pins {
-            u-boot,dm-pre-reloc;
-            pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
-        };
-    };
-
-    usb_otg_hs_sleep_pins_som: usb_otg_hs_sleep_som-0 {
-        u-boot,dm-pre-reloc;
-        pins {
-            u-boot,dm-pre-reloc;
-            pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
-        };
-    };
-
-
-};
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-t1000-testadapter-u-boot.dtsi b/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-t1000-default-u-boot.dtsi
similarity index 58%
rename from recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-t1000-testadapter-u-boot.dtsi
rename to recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-t1000-default-u-boot.dtsi
index ffd60020d41932bf0c09a393065562c42e6ca291..e5becd01fbd83e0cfc7bc1a4ab8544250fd4b119 100644
--- a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-t1000-testadapter-u-boot.dtsi
+++ b/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-t1000-default-u-boot.dtsi
@@ -1,12 +1,12 @@
 /* u-boot devicetree for device
  *
- * device   : stm32mp-t1000-testadapter
+ * device   : stmxceet-t1000-default-u-boot
  * revision : prototype
  *
- * Copyright (c) 2019 exceet electronics GmbH
+ * Copyright (c) 2018 exceet electronics GmbH
  */
 
-#include "stm32mp157c-t1000-s-mx-u-boot.dtsi"
+#include "stm32mp157c-t1000-default-mx-u-boot.dtsi"
 
 /* Include SOM components
  * - SOM components: RAM,
@@ -15,12 +15,12 @@
 #include "stm32mp-som-t1000-u-boot.dtsi"
 
 /* Include baseboard */
-#include "stm32mp-board-s-u-boot.dtsi"
+/* NOT AVAILABLE */
 
 /* Include housing */
 /* NOT AVAILABLE */
 
 /* Model identification */
 / {
-	model = "stm32mp-t1000-testadapter (u-boot)";
+	model = "stm32mp-t1000-default (u-boot)";
 };
diff --git a/recipes-kernel/linux/linux-stm32mp/stm32mp-t1000-testadapter.dts b/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-t1000-default.dts
similarity index 56%
rename from recipes-kernel/linux/linux-stm32mp/stm32mp-t1000-testadapter.dts
rename to recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-t1000-default.dts
index 02138c0c2c10be249d1fed93b72fc9eca84fdcd9..f87a5d7634c6742194b8ca26db29f0fa7388a431 100644
--- a/recipes-kernel/linux/linux-stm32mp/stm32mp-t1000-testadapter.dts
+++ b/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-t1000-default.dts
@@ -1,17 +1,17 @@
 /* Devicetree file for device
  *
- * device   : stm32mp-t1000-testadapter
+ * device   : stm32mp-t1000-default
  * revision : prototype
  *
  * Kontron Electronics GmbH
- * Copyright 2019 Kontron Electronics GmbH. All rights reserved.
+ * Copyright 2018 Kontron Electronics GmbH. All rights reserved.
  */
 
 /* Include CubeMX board configuration
  * - pinmultiplexing and
  * - peripheal activation
  */
-#include "stm32mp157c-t1000-s-mx.dts"
+#include "stm32mp157c-t1000-default-mx.dts"
 
 /* Include SOM components
  * - SOM components: RAM,
@@ -20,7 +20,7 @@
 #include "stm32mp-som-t1000.dtsi"
 
 /* Include baseboard */
-#include "stm32mp-board-s.dtsi"
+#include "stm32mp-board-default.dtsi"
 
 /* Include housing */
 /* NOT AVAILABLE */
@@ -28,11 +28,11 @@
 
 /* Model identification */
 / {
-	model = "stm32mp-t1000-testadapter (linux)";
- 	compatible = "ex,stm32mp-t1000-testadapter", "st,stm32mp157";
+	model = "stm32mp-t1000-default (linux)";
+ 	compatible = "ex,stm32mp-t1000-default", "st,stm32mp157";
 
  	device-identification {
- 		device = "t1000-testadapter";
- 		device_code = "unknown";
+ 		device = "t1000-default";
+ 		device_code = "40099 130 00";
  	};
 };
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-t1000-k-u-boot.dtsi b/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-t1000-k-u-boot.dtsi
deleted file mode 100644
index d5f76cb9552ebe20a766215aa19d87c87a9fb57f..0000000000000000000000000000000000000000
--- a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-t1000-k-u-boot.dtsi
+++ /dev/null
@@ -1,27 +0,0 @@
-/* u-boot devicetree for device
- *
- * device   : stm32mp-t1000-k-u-boot
- * revision : 0
- *
- * Kontron Electronics GmbH
- * Copyright 2019 Kontron Electronics GmbH. All rights reserved.
- */
-
-#include "stm32mp157c-t1000-k-mx-u-boot.dtsi"
-
-/* Include SOM components
- * - SOM components: RAM,
- * - Basic Clocks (only tf-a, u-boot)
- */
-#include "stm32mp-som-t1000-u-boot.dtsi"
-
-/* Include baseboard */
-#include "stm32mp-board-k-u-boot.dtsi"
-
-/* Include housing */
-/* NOT AVAILABLE */
-
-/* Model identification */
-/ {
-	model = "stm32mp-t1000-k (u-boot)";
-};
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-t1000-mini-u-boot.dtsi b/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-t1000-mini-u-boot.dtsi
new file mode 100644
index 0000000000000000000000000000000000000000..958f0cc16086e1d14bc8858734c6a2e3ed28ad4b
--- /dev/null
+++ b/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-t1000-mini-u-boot.dtsi
@@ -0,0 +1,50 @@
+/* u-boot devicetree for device
+ *
+ * device   : stmxceet-t1000-mini-u-boot
+ * revision : prototype
+ *
+ * Copyright (c) 2018 exceet electronics GmbH
+ */
+
+#include "stm32mp157c-t1000-mini-mx-u-boot.dtsi"
+
+/* Include SOM components
+ * - SOM components: RAM,
+ * - Basic Clocks (only tf-a, u-boot)
+ */
+#include "stm32mp-som-t1000-u-boot.dtsi"
+
+/* Include baseboard */
+/* NOT AVAILABLE */
+
+/* Include housing */
+/* NOT AVAILABLE */
+
+/* Model identification */
+/ {
+	model = "stm32mp-t1000-mini (u-boot)";
+
+	config {
+		/* u-boot led configuration */
+		u-boot,dm-pre-reloc;
+		u-boot,red-led = "stm32mp:red:status";
+		u-boot,green-led = "stm32mp:green:user";
+	};
+};
+
+&leds {
+	pinctrl-names = "default";
+	pinctrl-0 = < &led_gpios >;
+};
+&pinctrl {
+    led_gpios: led_gpios@0 {
+        u-boot,dm-pre-reloc;
+        pins1 {
+            pinmux = <STM32_PINMUX('A', 13, GPIO)>, /* LED0 */
+                     <STM32_PINMUX('A', 14, GPIO)>; /* LED1 */
+            bias-pull-down;
+            //bias-pull-up; /* leds are glowing in u-boot */
+            drive-push-pull;
+        };
+    };
+};
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-t1000-mini.dts b/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-t1000-mini.dts
new file mode 100644
index 0000000000000000000000000000000000000000..3d2fef5712ec38cf7c1fcb97ba81aab9d4b137eb
--- /dev/null
+++ b/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-t1000-mini.dts
@@ -0,0 +1,58 @@
+/* Devicetree file for device
+ *
+ * device   : stm32mp-t1000-mini
+ * revision : prototype
+ *
+ * Kontron Electronics GmbH
+ * Copyright 2018 Kontron Electronics GmbH. All rights reserved.
+ */
+
+/* Include CubeMX board configuration
+ * - pinmultiplexing and
+ * - peripheal activation
+ */
+#include "stm32mp157c-t1000-mini-mx.dts"
+
+/* Include SOM components
+ * - SOM components: RAM,
+ * - Basic Clocks (only tf-a, u-boot)
+ */
+#include "stm32mp-som-t1000.dtsi"
+
+/* Include baseboard */
+#include "stm32mp-board-mini.dtsi"
+
+/* Include housing */
+/* NOT AVAILABLE */
+
+
+/* Model identification */
+/ {
+	model = "stm32mp-t1000-mini (linux)";
+ 	compatible = "ex,stm32mp-t1000-mini", "st,stm32mp157";
+
+ 	device-identification {
+ 		device = "t1000-mini";
+ 		device_code = "40099 113 01 (prototype)";
+
+ 	};
+
+	leds:led {
+		compatible = "gpio-leds";
+		status = "okay";
+		red {
+			label = "stm32mp:red:status";
+			gpios = <&gpioa 13 GPIO_ACTIVE_LOW>;
+			default-state = "off";
+			linux,default-trigger = "heartbeat";
+			status = "okay";
+		};
+		green {
+			label = "stm32mp:green:user";
+			gpios = <&gpioa 14 GPIO_ACTIVE_LOW>;
+			default-state = "off";
+			linux,default-trigger = "heartbeat";
+			status = "okay";
+		};
+	};
+};
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-t1000-s-clkout32k-u-boot.dtsi b/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-t1000-s-clkout32k-u-boot.dtsi
deleted file mode 100644
index 634585c4c1e3ac51f4a7fb4d1a30667b362feeab..0000000000000000000000000000000000000000
--- a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-t1000-s-clkout32k-u-boot.dtsi
+++ /dev/null
@@ -1,35 +0,0 @@
-/* u-boot devicetree for device
- *
- * device   : stmxceet-t1000-s-u-boot
- * revision : prototype
- *
- * Copyright (c) 2018 exceet electronics GmbH
- */
-
-#include "stm32mp157c-t1000-s-mx-u-boot.dtsi"
-
-/* Include SOM components
- * - SOM components: RAM,
- * - Basic Clocks (only tf-a, u-boot)
- */
-#include "stm32mp-som-t1000-u-boot.dtsi"
-
-/* Include baseboard */
-#include "stm32mp-board-s-u-boot.dtsi"
-
-/* Include housing */
-/* NOT AVAILABLE */
-
-&led_gpios {
-	pins1 {
-   		pinmux = <STM32_PINMUX('A', 14, GPIO)>; /* LED2 */
-        bias-pull-down;
-        //bias-pull-up; /* leds are glowing in u-boot */
-        drive-push-pull;
-    };
-};
-
-/* Model identification */
-/ {
-	model = "stm32mp-t1000-s clkout32k (u-boot)";
-};
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-t1000-s-clkout32k.dts b/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-t1000-s-clkout32k.dts
deleted file mode 100644
index 19db644f7604a09af4d76d29fbb1923ee484179d..0000000000000000000000000000000000000000
--- a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-t1000-s-clkout32k.dts
+++ /dev/null
@@ -1,57 +0,0 @@
-/* Devicetree file for device
- *
- * device   : stm32mp-t1000-s
- * revision : prototype
- *
- * Kontron Electronics GmbH
- * Copyright 2018 Kontron Electronics GmbH. All rights reserved.
- */
-
-/* Include CubeMX board configuration
- * - pinmultiplexing and
- * - peripheal activation
- */
-#include "stm32mp157c-t1000-s-mx.dts"
-
-/* Include SOM components
- * - SOM components: RAM,
- * - Basic Clocks (only tf-a, u-boot)
- */
-#include "stm32mp-som-t1000.dtsi"
-
-/* Include baseboard */
-#include "stm32mp-board-s.dtsi"
-
-/* Include housing */
-/* NOT AVAILABLE */
-
-&pinctrl {
-	rcc_pins_mx: rcc_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 13, AF2)>; /* RCC_MCO_1 */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-	};
-};
-
-&rcc{
-	pinctrl-names = "default";
-	pinctrl-0 = <&rcc_pins_mx>;
-};
-
-&leds{
-	/delete-node/led1;
-};
-
-/* Model identification */
-/ {
-	model = "stm32mp-t1000-s clkout32k (linux)";
- 	compatible = "ex,stm32mp-t1000-s", "st,stm32mp157";
-
- 	device-identification {
- 		device = "t1000-s";
- 		device_code = "40099 131 01";
- 	};
-};
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-t1000-s.dts b/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-t1000-s.dts
index 6c33e3b983866e360042494c20f2bda6b833ef94..763bac6c726c873db05a62582c76f75430b60b93 100644
--- a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-t1000-s.dts
+++ b/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-t1000-s.dts
@@ -33,6 +33,6 @@
 
  	device-identification {
  		device = "t1000-s";
- 		device_code = "40099 131 01";
+ 		device_code = "40099 131 00 (prototype)";
  	};
 };
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-t1000-u-boot.dtsi b/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-t1000-u-boot.dtsi
deleted file mode 100644
index 1d4c83f8c6715ad106c6d74819e537ad3d621e80..0000000000000000000000000000000000000000
--- a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-t1000-u-boot.dtsi
+++ /dev/null
@@ -1,30 +0,0 @@
-/* u-boot devicetree for basic t1000 SOM module
- *
- * These settings should work with most baseboards
- *
- * device    : stm32mp-t1000
- * board code: 40099 130
- * revision  : 03
- *
- * Kontron Electronics GmbH
- * Copyright 2019 Kontron Electronics GmbH. All rights reserved.
- */
-
-#include "stm32mp157c-t1000-som-minimal-mx-u-boot.dtsi"
-
-/* Include SOM components
- * - SOM components: RAM,
- * - Basic Clocks (only tf-a, u-boot)
- */
-#include "stm32mp-som-t1000-u-boot.dtsi"
-
-/* Include baseboard */
-#include "stm32mp-board-minimal-u-boot.dtsi"
-
-/* Include housing */
-/* NOT AVAILABLE */
-
-/* Model identification */
-/ {
-	model = "stm32mp-t1000 (u-boot)";
-};
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-t1000.dts b/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-t1000.dts
deleted file mode 100644
index 1bcb764efa29133aaf8fdb0727767f5a00df10ce..0000000000000000000000000000000000000000
--- a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-t1000.dts
+++ /dev/null
@@ -1,39 +0,0 @@
-/* Devicetree file for basic t1000 SOM module
- *
- * These settings should work with most baseboards
- *
- * device    : stm32mp-t1000
- * board code: 40099 130
- * revision  : 03
- *
- * Kontron Electronics GmbH
- * Copyright 2019 Kontron Electronics GmbH. All rights reserved.
- */
-
-/* Include (your) CubeMX board configuration
- * - pinmultiplexing and
- * - peripheal activation
- */
-#include "stm32mp157c-t1000-som-minimal-mx.dts"
-
-/* Include SOM components
- * - SOM components: RAM,
- * - Basic Clocks (only tf-a, u-boot)
- */
-#include "stm32mp-som-t1000.dtsi"
-
-/* Include (your) baseboard */
-#include "stm32mp-board-minimal.dtsi"
-
-/* Model identification */
-/ {
-	model = "stm32mp-t1000 (linux)";
- 	compatible = "ex,stm32mp-t1000", "st,stm32mp157";
- 	/* Compatibility string correspondents to extlinux base directory */
-
- 	/* Add your device identification (only for informational purpose) */
- 	device-identification {
- 		device = "t1000";
- 		device_code = "40099 130 03";
- 	};
-};
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-t1001-u-boot.dtsi b/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-t1001-u-boot.dtsi
deleted file mode 100644
index 98f6878058bebbf854a88dbcc8fbf831972625e4..0000000000000000000000000000000000000000
--- a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-t1001-u-boot.dtsi
+++ /dev/null
@@ -1,30 +0,0 @@
-/* u-boot devicetree for basic t1000 SOM module
- *
- * These settings should work with most baseboards
- *
- * device    : stm32mp-som-t1001
- * board code: 40099 164
- * revision  : 00
- *
- * Kontron Electronics GmbH
- * Copyright 2019 Kontron Electronics GmbH. All rights reserved.
- */
-
-#include "stm32mp157c-t1001-som-minimal-mx-u-boot.dtsi"
-
-/* Include SOM components
- * - SOM components: RAM,
- * - Basic Clocks (only tf-a, u-boot)
- */
-#include "stm32mp-som-t1001-u-boot.dtsi"
-
-/* Include baseboard */
-#include "stm32mp-board-minimal-u-boot.dtsi"
-
-/* Include housing */
-/* NOT AVAILABLE */
-
-/* Model identification */
-/ {
-	model = "stm32mp-t1001 (u-boot)";
-};
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-t1001.dts b/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-t1001.dts
deleted file mode 100644
index 3fce988f6b486b07a803fec6492749ff5f885dd4..0000000000000000000000000000000000000000
--- a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-t1001.dts
+++ /dev/null
@@ -1,39 +0,0 @@
-/* Devicetree file for basic t1001 SOM module
- *
- * These settings should work with most baseboards
- *
- * device    : stm32mp-som-t1001
- * board code: 40099 164
- * revision  : 00
- *
- * Kontron Electronics GmbH
- * Copyright 2019 Kontron Electronics GmbH. All rights reserved.
- */
-
-/* Include (your) CubeMX board configuration
- * - pinmultiplexing and
- * - peripheal activation
- */
-#include "stm32mp157c-t1001-som-minimal-mx.dts"
-
-/* Include SOM components
- * - SOM components: RAM,
- * - Basic Clocks (only tf-a, u-boot)
- */
-#include "stm32mp-som-t1001.dtsi"
-
-/* Include (your) baseboard */
-#include "stm32mp-board-minimal.dtsi"
-
-/* Model identification */
-/ {
-	model = "stm32mp-t1001 (linux)";
- 	compatible = "ex,stm32mp-t1001", "st,stm32mp157";
- 	/* Compatibility string correspondents to extlinux base directory */
-
- 	/* Add your device identification (only for informational purpose) */
- 	device-identification {
- 		device = "t1001";
- 		device_code = "40099 164 00";
- 	};
-};
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-t1004-u-boot.dtsi b/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-t1004-u-boot.dtsi
deleted file mode 100644
index 0390edd55fdeca64bcb05dad39871e851c3a5c45..0000000000000000000000000000000000000000
--- a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-t1004-u-boot.dtsi
+++ /dev/null
@@ -1,30 +0,0 @@
-/* u-boot devicetree for basic t1000 SOM module
- *
- * These settings should work with most baseboards
- *
- * device    : stm32mp-t1004
- * board code: 40099 180
- * revision  : 0
- *
- * Kontron Electronics GmbH
- * Copyright 2019 Kontron Electronics GmbH. All rights reserved.
- */
-
-#include "stm32mp157c-t1000-som-minimal-mx-u-boot.dtsi"
-
-/* Include SOM components
- * - SOM components: RAM,
- * - Basic Clocks (only tf-a, u-boot)
- */
-#include "stm32mp-som-t1000-u-boot.dtsi"
-
-/* Include baseboard */
-#include "stm32mp-board-minimal-u-boot.dtsi"
-
-/* Include housing */
-/* NOT AVAILABLE */
-
-/* Model identification */
-/ {
-	model = "stm32mp-t1004 (u-boot)";
-};
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-t1004.dts b/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-t1004.dts
deleted file mode 100644
index 2a2cf3624014fa62cf79ba282c327b02b254b53e..0000000000000000000000000000000000000000
--- a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-t1004.dts
+++ /dev/null
@@ -1,39 +0,0 @@
-/* Devicetree file for basic t1000 SOM module
- *
- * These settings should work with most baseboards
- *
- * device    : stm32mp-t1004
- * board code: 40099 180
- * revision  : 0
- *
- * Kontron Electronics GmbH
- * Copyright 2019 Kontron Electronics GmbH. All rights reserved.
- */
-
-/* Include (your) CubeMX board configuration
- * - pinmultiplexing and
- * - peripheal activation
- */
-#include "stm32mp157c-t1000-som-minimal-mx.dts"
-
-/* Include SOM components
- * - SOM components: RAM,
- * - Basic Clocks (only tf-a, u-boot)
- */
-#include "stm32mp-som-t1000.dtsi"
-
-/* Include (your) baseboard */
-#include "stm32mp-board-minimal.dtsi"
-
-/* Model identification */
-/ {
-	model = "stm32mp-t1004 (linux)";
- 	compatible = "ex,stm32mp-t1004", "st,stm32mp157";
- 	/* Compatibility string correspondents to extlinux base directory */
-
- 	/* Add your device identification (only for informational purpose) */
- 	device-identification {
- 		device = "t1004";
- 		device_code = "40099 180 00";
- 	};
-};
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-t1005-u-boot.dtsi b/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-t1005-u-boot.dtsi
deleted file mode 100644
index 8c3384108bff001007ddcb7090c24446255ecef1..0000000000000000000000000000000000000000
--- a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-t1005-u-boot.dtsi
+++ /dev/null
@@ -1,30 +0,0 @@
-/* u-boot devicetree for basic t1000 SOM module
- *
- * These settings should work with most baseboards
- *
- * device    : stm32mp-t1005
- * board code: 40099 181
- * revision  : 0
- *
- * Kontron Electronics GmbH
- * Copyright 2019 Kontron Electronics GmbH. All rights reserved.
- */
-
-#include "stm32mp157c-t1000-som-minimal-mx-u-boot.dtsi"
-
-/* Include SOM components
- * - SOM components: RAM,
- * - Basic Clocks (only tf-a, u-boot)
- */
-#include "stm32mp-som-t1000-u-boot.dtsi"
-
-/* Include baseboard */
-#include "stm32mp-board-minimal-u-boot.dtsi"
-
-/* Include housing */
-/* NOT AVAILABLE */
-
-/* Model identification */
-/ {
-	model = "stm32mp-t1005 (u-boot)";
-};
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-t1005.dts b/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-t1005.dts
deleted file mode 100644
index 562d387a0981c7b323435becf2d37cb629ee7684..0000000000000000000000000000000000000000
--- a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp-t1005.dts
+++ /dev/null
@@ -1,39 +0,0 @@
-/* Devicetree file for basic t1000 SOM module
- *
- * These settings should work with most baseboards
- *
- * device    : stm32mp-t1005
- * board code: 40099 181
- * revision  : 0
- *
- * Kontron Electronics GmbH
- * Copyright 2019 Kontron Electronics GmbH. All rights reserved.
- */
-
-/* Include (your) CubeMX board configuration
- * - pinmultiplexing and
- * - peripheal activation
- */
-#include "stm32mp157c-t1000-som-minimal-mx.dts"
-
-/* Include SOM components
- * - SOM components: RAM,
- * - Basic Clocks (only tf-a, u-boot)
- */
-#include "stm32mp-som-t1000.dtsi"
-
-/* Include (your) baseboard */
-#include "stm32mp-board-minimal.dtsi"
-
-/* Model identification */
-/ {
-	model = "stm32mp-t1005 (linux)";
- 	compatible = "ex,stm32mp-t1005", "st,stm32mp157";
- 	/* Compatibility string correspondents to extlinux base directory */
-
- 	/* Add your device identification (only for informational purpose) */
- 	device-identification {
- 		device = "t1005";
- 		device_code = "40099 181 00";
- 	};
-};
diff --git a/conf/machine/cubemx/t1000-s/DeviceTree/t1000-s/tf-a/stm32mp15-mx.h b/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp157c-t1000-ddr3-1x4Gb-1066-binF.h
similarity index 70%
rename from conf/machine/cubemx/t1000-s/DeviceTree/t1000-s/tf-a/stm32mp15-mx.h
rename to recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp157c-t1000-ddr3-1x4Gb-1066-binF.h
index 9abe0891ec7d433fb15136da080dc87904a49055..b27fccca9d6ee370ce280ff6ba42340b380bdeae 100644
--- a/conf/machine/cubemx/t1000-s/DeviceTree/t1000-s/tf-a/stm32mp15-mx.h
+++ b/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp157c-t1000-ddr3-1x4Gb-1066-binF.h
@@ -10,15 +10,15 @@
  * DDR type: DDR3 / DDR3L
  * DDR width: 16bits
  * DDR density: 4Gb
- * System frequency: 528000Khz
- * Relaxed Timing Mode: false
+ * System frequency: 528Mhz
+ * Relaxed Timing Mode: true
  * Address mapping type: RBC
  *
- * Save Date: 2019.11.25, save Time: 15:00:39
+ * Save Date: 2018.08.29, save Time: 14:31:58
  */
 
-#define DDR_MEM_NAME	"DDR3-DDR3L 16bits 528000Khz"
-#define DDR_MEM_SPEED	528000
+#define DDR_MEM_NAME	"DDR3-DDR3L 16bits 528Mhz RELAXED-TUNED"
+#define DDR_MEM_SPEED	528
 #define DDR_MEM_SIZE	0x20000000
 
 #define DDR_MSTR 0x00041401
@@ -33,11 +33,11 @@
 #define DDR_RFSHCTL3 0x00000000
 #define DDR_RFSHTMG 0x0040008A
 #define DDR_CRCPARCTL0 0x00000000
-#define DDR_DRAMTMG0 0x121B1214
-#define DDR_DRAMTMG1 0x000A041B
-#define DDR_DRAMTMG2 0x0607080F
+#define DDR_DRAMTMG0 0x131B1215
+#define DDR_DRAMTMG1 0x000A051C
+#define DDR_DRAMTMG2 0x06070910
 #define DDR_DRAMTMG3 0x0050400C
-#define DDR_DRAMTMG4 0x07040607
+#define DDR_DRAMTMG4 0x08040708
 #define DDR_DRAMTMG5 0x06060403
 #define DDR_DRAMTMG6 0x02020002
 #define DDR_DRAMTMG7 0x00000202
@@ -53,7 +53,7 @@
 #define DDR_DFIPHYMSTR 0x00000000
 #define DDR_ODTCFG 0x06000600
 #define DDR_ODTMAP 0x00000001
-#define DDR_SCHED 0x00000C01
+#define DDR_SCHED 0x00001201
 #define DDR_SCHED1 0x00000000
 #define DDR_PERFHPR1 0x01000001
 #define DDR_PERFLPR1 0x08000200
@@ -65,15 +65,15 @@
 #define DDR_PCCFG 0x00000010
 #define DDR_PCFGR_0 0x00010000
 #define DDR_PCFGW_0 0x00000000
-#define DDR_PCFGQOS0_0 0x02100C03
+#define DDR_PCFGQOS0_0 0x02100B03
 #define DDR_PCFGQOS1_0 0x00800100
-#define DDR_PCFGWQOS0_0 0x01100C03
+#define DDR_PCFGWQOS0_0 0x01100B03
 #define DDR_PCFGWQOS1_0 0x01000200
 #define DDR_PCFGR_1 0x00010000
 #define DDR_PCFGW_1 0x00000000
-#define DDR_PCFGQOS0_1 0x02100C03
-#define DDR_PCFGQOS1_1 0x00800040
-#define DDR_PCFGWQOS0_1 0x01100C03
+#define DDR_PCFGQOS0_1 0x02100B03
+#define DDR_PCFGQOS1_1 0x00800000
+#define DDR_PCFGWQOS0_1 0x01100B03
 #define DDR_PCFGWQOS1_1 0x01000200
 #define DDR_ADDRMAP1 0x00070707
 #define DDR_ADDRMAP2 0x00000000
@@ -92,28 +92,28 @@
 #define DDR_DXCCR 0x00000C40
 #define DDR_DSGCR 0xF200001F
 #define DDR_DCR 0x0000000B
-#define DDR_DTPR0 0x36D477D0
-#define DDR_DTPR1 0x098A00D8
+#define DDR_DTPR0 0xB8F588F4
+#define DDR_DTPR1 0x098A00DC
 #define DDR_DTPR2 0x10023600
 #define DDR_MR0 0x00000830
 #define DDR_MR1 0x00000000
-#define DDR_MR2 0x00000248
+#define DDR_MR2 0x00000208
 #define DDR_MR3 0x00000000
 #define DDR_ODTCR 0x00010000
 #define DDR_ZQ0CR1 0x00000038
 #define DDR_DX0GCR 0x0000CE81
-#define DDR_DX0DLLCR 0x40000000
-#define DDR_DX0DQTR 0x55050005
-#define DDR_DX0DQSTR 0x3D202000
+#define DDR_DX0DLLCR 0x4000C000
+#define DDR_DX0DQTR 0x20201200
+#define DDR_DX0DQSTR 0x3DB02000
 #define DDR_DX1GCR 0x0000CE81
-#define DDR_DX1DLLCR 0x40000000
-#define DDR_DX1DQTR 0x00050500
-#define DDR_DX1DQSTR 0x3DB02000
-#define DDR_DX2GCR 0x0000C881
-#define DDR_DX2DLLCR 0x40000000
-#define DDR_DX2DQTR 0xFFFFFFFF
-#define DDR_DX2DQSTR 0x3DB02000
-#define DDR_DX3GCR 0x0000C881
-#define DDR_DX3DLLCR 0x40000000
-#define DDR_DX3DQTR 0xFFFFFFFF
-#define DDR_DX3DQSTR 0x3DB02000
+#define DDR_DX1DLLCR 0x4000C000
+#define DDR_DX1DQTR 0x20201200
+#define DDR_DX1DQSTR 0x3D202000
+#define DDR_DX2GCR 0x00000000
+#define DDR_DX2DLLCR 0x00000000
+#define DDR_DX2DQTR 0x00000000
+#define DDR_DX2DQSTR 0x00000000
+#define DDR_DX3GCR 0x00000000
+#define DDR_DX3DLLCR 0x00000000
+#define DDR_DX3DQTR 0x00000000
+#define DDR_DX3DQSTR 0x00000000
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp157c-t1000-ddr3-1x4Gb-1066-binG.h b/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp157c-t1000-ddr3-1x4Gb-1066-binG.h
index 8746a4b32a08540cac660161e6024c9546ce9b26..7d9e48b08091620c799a7e6da7907acb3c53ff92 100644
--- a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp157c-t1000-ddr3-1x4Gb-1066-binG.h
+++ b/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp157c-t1000-ddr3-1x4Gb-1066-binG.h
@@ -10,17 +10,16 @@
  * DDR type: DDR3 / DDR3L
  * DDR width: 16bits
  * DDR density: 4Gb
- * System frequency: 528000Khz
+ * System frequency: 528Mhz
  * Relaxed Timing Mode: false
  * Address mapping type: RBC
  * tREFI 3,9us
- * Calibration: CubeMX 5.1.0 on #11
  *
- * Save Date: 2019.04.04, save Time: 16:24:24
+ * Save Date: 2019.01.16, save Time: 14:01:31
  */
 
-#define DDR_MEM_NAME	"DDR3-DDR3L 16bits 528Mhz K4B4G1646E (v1,1066-7-7-7,cal)"
-#define DDR_MEM_SPEED	528000
+#define DDR_MEM_NAME	"DDR3-DDR3L 16bits 533Mhz K4B4G1646E (1066-7-7-7-std,calibrated-patched)"
+#define DDR_MEM_SPEED	533
 #define DDR_MEM_SIZE	0x20000000
 
 #define DDR_MSTR 0x00041401
@@ -33,8 +32,12 @@
 #define DDR_HWLPCTL 0x00000000
 #define DDR_RFSHCTL0 0x00210000
 #define DDR_RFSHCTL3 0x00000000
+//#define DDR_RFSHTMG 0x0080008A
+// set tREFI 3.9us
 #define DDR_RFSHTMG 0x0040008A
 #define DDR_CRCPARCTL0 0x00000000
+//#define DDR_DRAMTMG0 0x121B2414
+// set tREFI 3.9us
 #define DDR_DRAMTMG0 0x121B1214
 #define DDR_DRAMTMG1 0x000A041B
 #define DDR_DRAMTMG2 0x0607080F
@@ -55,7 +58,7 @@
 #define DDR_DFIPHYMSTR 0x00000000
 #define DDR_ODTCFG 0x06000600
 #define DDR_ODTMAP 0x00000001
-#define DDR_SCHED 0x00000C01
+#define DDR_SCHED 0x00001201
 #define DDR_SCHED1 0x00000000
 #define DDR_PERFHPR1 0x01000001
 #define DDR_PERFLPR1 0x08000200
@@ -67,15 +70,15 @@
 #define DDR_PCCFG 0x00000010
 #define DDR_PCFGR_0 0x00010000
 #define DDR_PCFGW_0 0x00000000
-#define DDR_PCFGQOS0_0 0x02100C03
+#define DDR_PCFGQOS0_0 0x02100B03
 #define DDR_PCFGQOS1_0 0x00800100
-#define DDR_PCFGWQOS0_0 0x01100C03
+#define DDR_PCFGWQOS0_0 0x01100B03
 #define DDR_PCFGWQOS1_0 0x01000200
 #define DDR_PCFGR_1 0x00010000
 #define DDR_PCFGW_1 0x00000000
-#define DDR_PCFGQOS0_1 0x02100C03
-#define DDR_PCFGQOS1_1 0x00800040
-#define DDR_PCFGWQOS0_1 0x01100C03
+#define DDR_PCFGQOS0_1 0x02100B03
+#define DDR_PCFGQOS1_1 0x00800000
+#define DDR_PCFGWQOS0_1 0x01100B03
 #define DDR_PCFGWQOS1_1 0x01000200
 #define DDR_ADDRMAP1 0x00070707
 #define DDR_ADDRMAP2 0x00000000
@@ -99,18 +102,22 @@
 #define DDR_DTPR2 0x10023600
 #define DDR_MR0 0x00000830
 #define DDR_MR1 0x00000000
-#define DDR_MR2 0x00000248
+#define DDR_MR2 0x00000208
 #define DDR_MR3 0x00000000
 #define DDR_ODTCR 0x00010000
 #define DDR_ZQ0CR1 0x00000038
 #define DDR_DX0GCR 0x0000CE81
+//#define DDR_DX0DLLCR 0x4000C000
+// fix CubeMX calibration bug
 #define DDR_DX0DLLCR 0x40000000
-#define DDR_DX0DQTR 0x55050005
-#define DDR_DX0DQSTR 0x3D202000
+#define DDR_DX0DQTR 0x10100211
+#define DDR_DX0DQSTR 0x3DB02000
 #define DDR_DX1GCR 0x0000CE81
+//#define DDR_DX1DLLCR 0x4000C000
+// fix CubeMX calibration bug
 #define DDR_DX1DLLCR 0x40000000
-#define DDR_DX1DQTR 0x00050500
-#define DDR_DX1DQSTR 0x3DB02000
+#define DDR_DX1DQTR 0x10100211
+#define DDR_DX1DQSTR 0x3D202000
 #define DDR_DX2GCR 0x00000000
 #define DDR_DX2DLLCR 0x00000000
 #define DDR_DX2DQTR 0x00000000
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp157c-t1000-default-mx-u-boot.dtsi b/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp157c-t1000-default-mx-u-boot.dtsi
new file mode 100644
index 0000000000000000000000000000000000000000..741a23e043f51d8ba65a70db769d9f0b7671bd94
--- /dev/null
+++ b/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp157c-t1000-default-mx-u-boot.dtsi
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier:	GPL-2.0+	BSD-3-Clause
+ *
+ */
+
+#include <dt-bindings/clock/stm32mp1-clksrc.h>
+#include "stm32mp15-mx.h"
+
+#include "stm32mp157cad-u-boot.dtsi"
+#include "stm32mp15-ddr.dtsi"
+
+/* USER CODE BEGIN dts_include */
+/* USER CODE END dts_include */
+
+/ {
+
+	/* USER CODE BEGIN root_prop */
+	/* USER CODE END root_prop */
+
+    clocks {
+        u-boot,dm-pre-reloc;
+        clk_hsi: clk-hsi {
+            u-boot,dm-pre-reloc;
+        };
+        clk_usbo_48m: ck_usbo_48m {
+            u-boot,dm-pre-reloc;
+        };
+        clk_lse: clk-lse {
+            st,drive=<LSEDRV_LOWEST>;
+            u-boot,dm-pre-reloc;
+        };
+        clk_hse: clk-hse {
+            u-boot,dm-pre-reloc;
+        };
+    };
+	/* USER CODE BEGIN root_subnodes */
+	/* USER CODE END root_subnodes */
+
+	/* USER CODE BEGIN root_board */
+	/* USER CODE END root_board */
+
+	/* USER CODE BEGIN root_platform */
+	/* USER CODE END root_platform */
+
+}; /*root*/
+
+/* USER CODE BEGIN dts_board */
+/* USER CODE END dts_board */
+
+&gpioa {
+    compatible = "st,stm32-gpio";
+    u-boot,dm-pre-reloc;
+};
+&gpiob {
+    compatible = "st,stm32-gpio";
+    u-boot,dm-pre-reloc;
+};
+&gpioc {
+    compatible = "st,stm32-gpio";
+    u-boot,dm-pre-reloc;
+};
+&gpiod {
+    compatible = "st,stm32-gpio";
+    u-boot,dm-pre-reloc;
+};
+&gpioe {
+    compatible = "st,stm32-gpio";
+    u-boot,dm-pre-reloc;
+};
+&gpiof {
+    compatible = "st,stm32-gpio";
+    u-boot,dm-pre-reloc;
+};
+&gpiog {
+    compatible = "st,stm32-gpio";
+    u-boot,dm-pre-reloc;
+};
+&gpioh {
+    compatible = "st,stm32-gpio";
+    u-boot,dm-pre-reloc;
+};
+&gpioi {
+    compatible = "st,stm32-gpio";
+    u-boot,dm-pre-reloc;
+};
+&gpioj {
+    compatible = "st,stm32-gpio";
+    u-boot,dm-pre-reloc;
+};
+&gpiok {
+    compatible = "st,stm32-gpio";
+    u-boot,dm-pre-reloc;
+};
+&gpioz {
+    compatible = "st,stm32-gpio";
+    u-boot,dm-pre-reloc;
+};
+
+&rcc {
+    u-boot,dm-pre-reloc;
+    st,clksrc = <
+        CLK_MPU_PLL1P
+        CLK_AXI_PLL2P
+        CLK_MCU_PLL3P
+        CLK_PLL12_HSE
+        CLK_PLL3_HSE
+        CLK_PLL4_HSE
+        CLK_RTC_LSE
+        CLK_MCO1_DISABLED
+        CLK_MCO2_DISABLED
+    >;
+    st,clkdiv = <
+        1         /*MPU*/
+        0         /*AXI*/
+        0         /*MCU*/
+        1         /*APB1*/
+        1         /*APB2*/
+        1         /*APB3*/
+        1         /*APB4*/
+        2         /*APB5*/
+        23         /*RTC*/
+        0         /*MCO1*/
+        0         /*MCO2*/
+    >;
+    st,pkcs = <
+        CLK_CKPER_HSE
+        CLK_QSPI_ACLK
+        CLK_ETH_PLL4P
+        CLK_SDMMC12_PLL3R
+        CLK_STGEN_HSE
+        CLK_USBPHY_HSE
+        CLK_SPI2S1_DISABLED
+        CLK_SPI2S23_PLL3Q
+        CLK_SPI45_DISABLED
+        CLK_SPI6_DISABLED
+        CLK_I2C46_HSI
+        CLK_SDMMC3_DISABLED
+        CLK_USBO_USBPHY
+        CLK_ADC_CKPER
+        CLK_CEC_DISABLED
+        CLK_I2C12_HSI
+        CLK_I2C35_DISABLED
+        CLK_UART1_DISABLED
+        CLK_UART24_HSI
+        CLK_UART35_HSI
+        CLK_UART6_HSI
+        CLK_UART78_HSI
+        CLK_SPDIF_DISABLED
+        CLK_FDCAN_HSE
+        CLK_SAI1_DISABLED
+        CLK_SAI2_DISABLED
+        CLK_SAI3_DISABLED
+        CLK_SAI4_DISABLED
+        CLK_LPTIM1_DISABLED
+        CLK_LPTIM23_DISABLED
+        CLK_LPTIM45_DISABLED
+    >;
+    pll1:st,pll@0 {
+        cfg = < 2 80 0 0 0 1>;
+        frac = < 0x800 >;
+        u-boot,dm-pre-reloc;
+    };
+    pll2:st,pll@1 {
+        cfg = < 2 65 1 0 0 5>;
+        frac = < 0x1400 >;
+        u-boot,dm-pre-reloc;
+    };
+    pll3:st,pll@2 {
+        cfg = < 2 97 3 15 7 5>;
+        frac = < 0x9ba >;
+        u-boot,dm-pre-reloc;
+    };
+    pll4:st,pll@3 {
+        cfg = < 5 124 9 9 9 3>;
+        u-boot,dm-pre-reloc;
+    };
+};
+
+/* USER CODE BEGIN dts_soc */
+/* USER CODE END dts_soc */
+
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/bleeding/arch/arm/dts/stm32mp157c-t1000-s-mx.dts b/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp157c-t1000-default-mx.dts
similarity index 59%
rename from recipes-bsp/u-boot/u-boot-stm32mp/bleeding/arch/arm/dts/stm32mp157c-t1000-s-mx.dts
rename to recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp157c-t1000-default-mx.dts
index ddd62b649b0d6e56652f5e9e288e47a8c2e5bd04..17d3d54bd6efd33237aa3158ec724e5f1dddb8ae 100644
--- a/recipes-bsp/u-boot/u-boot-stm32mp/bleeding/arch/arm/dts/stm32mp157c-t1000-s-mx.dts
+++ b/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp157c-t1000-default-mx.dts
@@ -1,112 +1,108 @@
 /* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
 /*
- * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
+ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved
  * Author: STM32CubeMX code generation for STMicroelectronics.
  */
 
 /dts-v1/;
 #include "stm32mp157c.dtsi"
 #include "stm32mp157cad-pinctrl.dtsi"
-#include "stm32mp157c-m4-srm.dtsi"
 
-/* USER CODE BEGIN includes */
-/* USER CODE END includes */
+/* USER CODE BEGIN dts_include */
+/* USER CODE END dts_include */
 
 / {
-	model = "STMicroelectronics custom STM32CubeMX board";
-	compatible = "st,stm32mp157c-t1000-s-mx", "st,stm32mp157";
+    model = "STMicroelectronics custom STM32CubeMX board";
+	compatible = "st,stm32mp157c-t1000-default-mx", "st,stm32mp157";
 
-    memory@c0000000 {
-        reg = <0xc0000000 0x20000000>;
+	memory {
+		reg = <0xC0000000 0x20000000>;
+	};
 
-        /* USER CODE BEGIN memory */
-        /* USER CODE END memory */
-    };
-
-    reserved-memory {
-        #address-cells = <1>;
-        #size-cells = <1>;
-        ranges;
-
-        /* USER CODE BEGIN reserved-memory */
-        /* USER CODE END reserved-memory */
-
-        gpu_reserved: gpu@dc000000 {
-            reg = <0xdc000000 0x4000000>;
-            no-map;
-        };
-    };
-
-	/* USER CODE BEGIN root */
-	/* USER CODE END root */
+	/* USER CODE BEGIN root_prop */
+	/* USER CODE END root_prop */
 
     clocks {
-        /* USER CODE BEGIN clocks */
-        /* USER CODE END clocks */
-
+        u-boot,dm-pre-reloc;
         clk_hsi: clk-hsi {
+            #clock-cells = <0>;
+            compatible = "fixed-clock";
             clock-frequency = <64000000>;
+            u-boot,dm-pre-reloc;
         };
-        clk_csi: clk-csi {
-            clock-frequency = <4000000>;
+        clk_usbo_48m: ck_usbo_48m {
+            #clock-cells = <0>;
+            compatible = "fixed-clock";
+            clock-frequency = <48000000>;
+            u-boot,dm-pre-reloc;
         };
         clk_lse: clk-lse {
+            #clock-cells = <0>;
+            compatible = "fixed-clock";
             clock-frequency = <32768>;
+            u-boot,dm-pre-reloc;
         };
         clk_hse: clk-hse {
+            #clock-cells = <0>;
+            compatible = "fixed-clock";
             clock-frequency = <24000000>;
+            u-boot,dm-pre-reloc;
         };
     };
+	/* USER CODE BEGIN root_subnodes */
+	/* USER CODE END root_subnodes */
+
+	/* USER CODE BEGIN root_board */
+	/* USER CODE END root_board */
+
+	/* USER CODE BEGIN root_platform */
+	/* USER CODE END root_platform */
 
 }; /*root*/
 
+/* USER CODE BEGIN dts_board */
+/* USER CODE END dts_board */
+
 &pinctrl {
     u-boot,dm-pre-reloc;
-    adc_pins_mx: adc_mx-0 {
+    adc_pins_mx: adc_mx@0 {
         pins {
             pinmux = <STM32_PINMUX('A', 0, ANALOG)>, /* ADC1_INP16 */
                      <STM32_PINMUX('B', 1, ANALOG)>; /* ADC1_INP5 */
         };
     };
-    eth1_pins_mx: eth1_mx-0 {
+    eth1_pins_mx: eth1_mx@0 {
         pins1 {
-            pinmux = <STM32_PINMUX('B', 12, AF11)>, /* ETH1_TXD0 */
+            pinmux = <STM32_PINMUX('A', 2, AF11)>, /* ETH1_MDIO */
+                     <STM32_PINMUX('B', 11, AF11)>, /* ETH1_TX_EN */
+                     <STM32_PINMUX('B', 12, AF11)>, /* ETH1_TXD0 */
                      <STM32_PINMUX('B', 13, AF11)>, /* ETH1_TXD1 */
                      <STM32_PINMUX('C', 1, AF11)>, /* ETH1_MDC */
                      <STM32_PINMUX('G', 8, AF2)>; /* ETH1_CLK */
             bias-disable;
             drive-push-pull;
-            slew-rate = <1>;
+            slew-rate = <3>;
         };
         pins2 {
-            pinmux = <STM32_PINMUX('A', 2, AF11)>; /* ETH1_MDIO */
-            bias-disable;
-            drive-push-pull;
-            slew-rate = <0>;
-        };
-        pins3 {
             pinmux = <STM32_PINMUX('A', 7, AF11)>, /* ETH1_CRS_DV */
                      <STM32_PINMUX('C', 4, AF11)>, /* ETH1_RXD0 */
                      <STM32_PINMUX('C', 5, AF11)>; /* ETH1_RXD1 */
             bias-disable;
         };
-        pins4 {
-            pinmux = <STM32_PINMUX('B', 11, AF11)>; /* ETH1_TX_EN */
-        };
     };
-    fdcan1_pins_mx: fdcan1_mx-0 {
+    fdcan1_pins_mx: fdcan1_mx@0 {
         pins1 {
             pinmux = <STM32_PINMUX('D', 1, AF9)>; /* FDCAN1_TX */
             bias-disable;
             drive-push-pull;
-            slew-rate = <0>;
+            slew-rate = <1>;
         };
         pins2 {
             pinmux = <STM32_PINMUX('D', 0, AF9)>; /* FDCAN1_RX */
             bias-disable;
         };
     };
-    i2c2_pins_mx: i2c2_mx-0 {
+    i2c2_pins_mx: i2c2_mx@0 {
         pins {
             pinmux = <STM32_PINMUX('D', 7, AF4)>, /* I2C2_SCL */
                      <STM32_PINMUX('G', 15, AF4)>; /* I2C2_SDA */
@@ -115,7 +111,7 @@
             slew-rate = <0>;
         };
     };
-    i2c4_pins_mx: i2c4_mx-0 {
+    i2c4_pins_mx: i2c4_mx@0 {
         pins {
             pinmux = <STM32_PINMUX('B', 7, AF6)>, /* I2C4_SDA */
                      <STM32_PINMUX('E', 2, AF4)>; /* I2C4_SCL */
@@ -124,22 +120,8 @@
             slew-rate = <0>;
         };
     };
-    i2s2_pins_mx: i2s2_mx-0 {
+    ltdc_pins_mx: ltdc_mx@0 {
         pins {
-            pinmux = <STM32_PINMUX('A', 11, AF5)>, /* I2S2_WS */
-                     <STM32_PINMUX('C', 2, AF5)>, /* I2S2_SDI */
-                     <STM32_PINMUX('C', 3, AF5)>, /* I2S2_SDO */
-                     <STM32_PINMUX('D', 3, AF5)>, /* I2S2_CK */
-                     <STM32_PINMUX('E', 1, AF5)>; /* I2S2_MCK */
-            bias-disable;
-            drive-push-pull;
-            slew-rate = <1>;
-        };
-    };
-    ltdc_pins_mx: ltdc_mx-0 {
-        u-boot,dm-pre-reloc;
-        pins1 {
-            u-boot,dm-pre-reloc;
             pinmux = <STM32_PINMUX('A', 1, AF14)>, /* LTDC_R2 */
                      <STM32_PINMUX('A', 3, AF14)>, /* LTDC_B5 */
                      <STM32_PINMUX('A', 4, AF14)>, /* LTDC_VSYNC */
@@ -147,7 +129,6 @@
                      <STM32_PINMUX('A', 6, AF14)>, /* LTDC_G2 */
                      <STM32_PINMUX('A', 8, AF14)>, /* LTDC_R6 */
                      <STM32_PINMUX('A', 12, AF14)>, /* LTDC_R5 */
-                     <STM32_PINMUX('A', 15, AF14)>, /* LTDC_R1 */
                      <STM32_PINMUX('B', 0, AF9)>, /* LTDC_R3 */
                      <STM32_PINMUX('B', 5, AF14)>, /* LTDC_G7 */
                      <STM32_PINMUX('B', 8, AF14)>, /* LTDC_B6 */
@@ -156,42 +137,25 @@
                      <STM32_PINMUX('C', 6, AF14)>, /* LTDC_HSYNC */
                      <STM32_PINMUX('C', 7, AF14)>, /* LTDC_G6 */
                      <STM32_PINMUX('D', 10, AF14)>, /* LTDC_B3 */
-                     <STM32_PINMUX('E', 4, AF14)>, /* LTDC_B0 */
-                     <STM32_PINMUX('E', 5, AF14)>, /* LTDC_G0 */
-                     <STM32_PINMUX('E', 6, AF14)>, /* LTDC_G1 */
                      <STM32_PINMUX('E', 11, AF14)>, /* LTDC_G3 */
                      <STM32_PINMUX('E', 12, AF14)>, /* LTDC_B4 */
                      <STM32_PINMUX('E', 13, AF14)>, /* LTDC_DE */
+                     <STM32_PINMUX('E', 14, AF14)>, /* LTDC_CLK */
                      <STM32_PINMUX('E', 15, AF14)>, /* LTDC_R7 */
                      <STM32_PINMUX('F', 11, AF14)>, /* LTDC_G5 */
-                     <STM32_PINMUX('G', 10, AF14)>, /* LTDC_B2 */
-                     <STM32_PINMUX('G', 12, AF14)>, /* LTDC_B1 */
-                     <STM32_PINMUX('G', 13, AF14)>; /* LTDC_R0 */
-            bias-disable;
-            drive-push-pull;
-            slew-rate = <0>;
-        };
-        pins2 {
-            u-boot,dm-pre-reloc;
-            pinmux = <STM32_PINMUX('E', 14, AF14)>; /* LTDC_CLK */
+                     <STM32_PINMUX('G', 10, AF14)>; /* LTDC_B2 */
             bias-disable;
             drive-push-pull;
-            slew-rate = <1>;
+            slew-rate = <3>;
         };
     };
-    quadspi_pins_mx: quadspi_mx-0 {
+    quadspi_pins_mx: quadspi_mx@0 {
         u-boot,dm-pre-reloc;
-        pins1 {
+        pins {
             u-boot,dm-pre-reloc;
             pinmux = <STM32_PINMUX('B', 6, AF10)>, /* QUADSPI_BK1_NCS */
-                     <STM32_PINMUX('C', 0, AF10)>; /* QUADSPI_BK2_NCS */
-            bias-pull-up;
-            drive-push-pull;
-            slew-rate = <3>;
-        };
-        pins2 {
-            u-boot,dm-pre-reloc;
-            pinmux = <STM32_PINMUX('E', 7, AF10)>, /* QUADSPI_BK2_IO0 */
+                     <STM32_PINMUX('C', 0, AF10)>, /* QUADSPI_BK2_NCS */
+                     <STM32_PINMUX('E', 7, AF10)>, /* QUADSPI_BK2_IO0 */
                      <STM32_PINMUX('E', 8, AF10)>, /* QUADSPI_BK2_IO1 */
                      <STM32_PINMUX('E', 9, AF10)>, /* QUADSPI_BK2_IO2 */
                      <STM32_PINMUX('E', 10, AF10)>, /* QUADSPI_BK2_IO3 */
@@ -205,65 +169,47 @@
             slew-rate = <3>;
         };
     };
-    sdmmc1_pins_mx: sdmmc1_mx-0 {
+    sdmmc1_pins_mx: sdmmc1_mx@0 {
         u-boot,dm-pre-reloc;
-        pins1 {
+        pins {
             u-boot,dm-pre-reloc;
             pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
                      <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
                      <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
                      <STM32_PINMUX('C', 11, AF12)>, /* SDMMC1_D3 */
+                     <STM32_PINMUX('C', 12, AF12)>, /* SDMMC1_CK */
                      <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
             bias-pull-up;
             drive-push-pull;
-            slew-rate = <1>;
-        };
-        pins2 {
-            u-boot,dm-pre-reloc;
-            pinmux = <STM32_PINMUX('C', 12, AF12)>; /* SDMMC1_CK */
-            bias-pull-up;
-            drive-push-pull;
             slew-rate = <3>;
         };
     };
-    sdmmc2_pins_mx: sdmmc2_mx-0 {
+    sdmmc2_pins_mx: sdmmc2_mx@0 {
         u-boot,dm-pre-reloc;
-        pins1 {
+        pins {
             u-boot,dm-pre-reloc;
             pinmux = <STM32_PINMUX('B', 3, AF9)>, /* SDMMC2_D2 */
                      <STM32_PINMUX('B', 4, AF9)>, /* SDMMC2_D3 */
                      <STM32_PINMUX('B', 14, AF9)>, /* SDMMC2_D0 */
                      <STM32_PINMUX('B', 15, AF9)>, /* SDMMC2_D1 */
+                     <STM32_PINMUX('E', 3, AF9)>, /* SDMMC2_CK */
                      <STM32_PINMUX('G', 6, AF10)>; /* SDMMC2_CMD */
             bias-pull-up;
             drive-push-pull;
-            slew-rate = <1>;
-        };
-        pins2 {
-            u-boot,dm-pre-reloc;
-            pinmux = <STM32_PINMUX('E', 3, AF9)>; /* SDMMC2_CK */
-            bias-pull-up;
-            drive-push-pull;
             slew-rate = <3>;
         };
     };
-    tim1_pwm_pins_mx: tim1_pwm_mx-0 {
-        pins {
-            pinmux = <STM32_PINMUX('A', 9, AF1)>; /* TIM1_CH2 */
-            bias-disable;
-            drive-push-pull;
-            slew-rate = <0>;
-        };
-    };
-    tim4_pwm_pins_mx: tim4_pwm_mx-0 {
+    spi2_pins_mx: spi2_mx@0 {
         pins {
-            pinmux = <STM32_PINMUX('D', 14, AF2)>; /* TIM4_CH3 */
+            pinmux = <STM32_PINMUX('A', 9, AF5)>, /* SPI2_SCK */
+                     <STM32_PINMUX('C', 2, AF5)>, /* SPI2_MISO */
+                     <STM32_PINMUX('C', 3, AF5)>; /* SPI2_MOSI */
             bias-disable;
             drive-push-pull;
-            slew-rate = <0>;
+            slew-rate = <1>;
         };
     };
-    uart4_pins_mx: uart4_mx-0 {
+    uart4_pins_mx: uart4_mx@0 {
         u-boot,dm-pre-reloc;
         pins1 {
             u-boot,dm-pre-reloc;
@@ -278,7 +224,29 @@
             bias-pull-up;
         };
     };
-    usart2_pins_mx: usart2_mx-0 {
+    uart8_pins_mx: uart8_mx@0 {
+        pins1 {
+            pinmux = <STM32_PINMUX('E', 1, AF8)>; /* UART8_TX */
+            bias-pull-up;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+        pins2 {
+            pinmux = <STM32_PINMUX('D', 14, AF8)>; /* UART8_CTS */
+            bias-pull-down;
+        };
+        pins3 {
+            pinmux = <STM32_PINMUX('G', 7, AF8)>; /* UART8_RTS */
+            bias-pull-down;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+        pins4 {
+            pinmux = <STM32_PINMUX('E', 0, AF8)>; /* UART8_RX */
+            bias-pull-up;
+        };
+    };
+    usart2_pins_mx: usart2_mx@0 {
         pins1 {
             pinmux = <STM32_PINMUX('D', 5, AF7)>; /* USART2_TX */
             bias-pull-up;
@@ -286,17 +254,43 @@
             slew-rate = <0>;
         };
         pins2 {
+            pinmux = <STM32_PINMUX('D', 3, AF7)>; /* USART2_CTS */
+            bias-pull-down;
+        };
+        pins3 {
             pinmux = <STM32_PINMUX('D', 4, AF7)>; /* USART2_RTS */
             bias-pull-down;
             drive-push-pull;
             slew-rate = <0>;
         };
-        pins3 {
+        pins4 {
             pinmux = <STM32_PINMUX('D', 6, AF7)>; /* USART2_RX */
             bias-pull-up;
         };
     };
-    usart6_pins_mx: usart6_mx-0 {
+    usart3_pins_mx: usart3_mx@0 {
+        pins1 {
+            pinmux = <STM32_PINMUX('D', 8, AF7)>; /* USART3_TX */
+            bias-pull-up;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+        pins2 {
+            pinmux = <STM32_PINMUX('D', 11, AF7)>; /* USART3_CTS */
+            bias-pull-down;
+        };
+        pins3 {
+            pinmux = <STM32_PINMUX('D', 12, AF7)>; /* USART3_RTS */
+            bias-pull-down;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+        pins4 {
+            pinmux = <STM32_PINMUX('D', 9, AF7)>; /* USART3_RX */
+            bias-pull-up;
+        };
+    };
+    usart6_pins_mx: usart6_mx@0 {
         pins1 {
             pinmux = <STM32_PINMUX('G', 14, AF7)>; /* USART6_TX */
             bias-pull-up;
@@ -308,63 +302,64 @@
             bias-pull-up;
         };
     };
-    usb_otg_hs_pins_mx: usb_otg_hs_mx-0 {
+    usb_otg_hs_pins_mx: usb_otg_hs_mx@0 {
         u-boot,dm-pre-reloc;
         pins {
             u-boot,dm-pre-reloc;
             pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
         };
     };
-    adc_sleep_pins_mx: adc_sleep_mx-0 {
+    adc_sleep_pins_mx: adc_sleep_mx@0 {
         pins {
             pinmux = <STM32_PINMUX('A', 0, ANALOG)>, /* ADC1_INP16 */
                      <STM32_PINMUX('B', 1, ANALOG)>; /* ADC1_INP5 */
         };
     };
-    eth1_sleep_pins_mx: eth1_sleep_mx-0 {
-        pins {
-            pinmux = <STM32_PINMUX('A', 2, ANALOG)>, /* ETH1_MDIO */
-                     <STM32_PINMUX('A', 7, ANALOG)>, /* ETH1_CRS_DV */
-                     <STM32_PINMUX('B', 11, ANALOG)>, /* ETH1_TX_EN */
-                     <STM32_PINMUX('B', 12, ANALOG)>, /* ETH1_TXD0 */
-                     <STM32_PINMUX('B', 13, ANALOG)>, /* ETH1_TXD1 */
-                     <STM32_PINMUX('C', 1, ANALOG)>, /* ETH1_MDC */
-                     <STM32_PINMUX('C', 4, ANALOG)>, /* ETH1_RXD0 */
-                     <STM32_PINMUX('C', 5, ANALOG)>, /* ETH1_RXD1 */
-                     <STM32_PINMUX('G', 8, ANALOG)>; /* ETH1_CLK */
-        };
-    };
-    fdcan1_sleep_pins_mx: fdcan1_sleep_mx-0 {
-        pins {
-            pinmux = <STM32_PINMUX('D', 0, ANALOG)>, /* FDCAN1_RX */
-                     <STM32_PINMUX('D', 1, ANALOG)>; /* FDCAN1_TX */
+    eth1_sleep_pins_mx: eth1_sleep_mx@0 {
+        pins1 {
+            pinmux = <STM32_PINMUX('A', 2, AF11)>, /* ETH1_MDIO */
+                     <STM32_PINMUX('B', 11, AF11)>, /* ETH1_TX_EN */
+                     <STM32_PINMUX('B', 12, AF11)>, /* ETH1_TXD0 */
+                     <STM32_PINMUX('B', 13, AF11)>, /* ETH1_TXD1 */
+                     <STM32_PINMUX('C', 1, AF11)>, /* ETH1_MDC */
+                     <STM32_PINMUX('G', 8, AF2)>; /* ETH1_CLK */
+            bias-disable;
+            drive-push-pull;
+            slew-rate = <3>;
+        };
+        pins2 {
+            pinmux = <STM32_PINMUX('A', 7, AF11)>, /* ETH1_CRS_DV */
+                     <STM32_PINMUX('C', 4, AF11)>, /* ETH1_RXD0 */
+                     <STM32_PINMUX('C', 5, AF11)>; /* ETH1_RXD1 */
+            bias-disable;
         };
     };
-    i2c2_sleep_pins_mx: i2c2_sleep_mx-0 {
+    fdcan1_sleep_pins_mx: fdcan1_sleep_mx@0 {
         pins {
-            pinmux = <STM32_PINMUX('D', 7, ANALOG)>, /* I2C2_SCL */
-                     <STM32_PINMUX('G', 15, ANALOG)>; /* I2C2_SDA */
+            pinmux = <STM32_PINMUX('D', 0, ANALOG)>, /* FDCAN1_RX */
+                     <STM32_PINMUX('D', 1, ANALOG)>; /* FDCAN1_TX */
         };
     };
-    i2c4_sleep_pins_mx: i2c4_sleep_mx-0 {
+    i2c2_sleep_pins_mx: i2c2_sleep_mx@0 {
         pins {
-            pinmux = <STM32_PINMUX('B', 7, ANALOG)>, /* I2C4_SDA */
-                     <STM32_PINMUX('E', 2, ANALOG)>; /* I2C4_SCL */
+            pinmux = <STM32_PINMUX('D', 7, AF4)>, /* I2C2_SCL */
+                     <STM32_PINMUX('G', 15, AF4)>; /* I2C2_SDA */
+            bias-disable;
+            drive-open-drain;
+            slew-rate = <0>;
         };
     };
-    i2s2_sleep_pins_mx: i2s2_sleep_mx-0 {
+    i2c4_sleep_pins_mx: i2c4_sleep_mx@0 {
         pins {
-            pinmux = <STM32_PINMUX('A', 11, ANALOG)>, /* I2S2_WS */
-                     <STM32_PINMUX('C', 2, ANALOG)>, /* I2S2_SDI */
-                     <STM32_PINMUX('C', 3, ANALOG)>, /* I2S2_SDO */
-                     <STM32_PINMUX('D', 3, ANALOG)>, /* I2S2_CK */
-                     <STM32_PINMUX('E', 1, ANALOG)>; /* I2S2_MCK */
+            pinmux = <STM32_PINMUX('B', 7, AF6)>, /* I2C4_SDA */
+                     <STM32_PINMUX('E', 2, AF4)>; /* I2C4_SCL */
+            bias-disable;
+            drive-open-drain;
+            slew-rate = <0>;
         };
     };
-    ltdc_sleep_pins_mx: ltdc_sleep_mx-0 {
-        u-boot,dm-pre-reloc;
+    ltdc_sleep_pins_mx: ltdc_sleep_mx@0 {
         pins {
-            u-boot,dm-pre-reloc;
             pinmux = <STM32_PINMUX('A', 1, ANALOG)>, /* LTDC_R2 */
                      <STM32_PINMUX('A', 3, ANALOG)>, /* LTDC_B5 */
                      <STM32_PINMUX('A', 4, ANALOG)>, /* LTDC_VSYNC */
@@ -372,7 +367,6 @@
                      <STM32_PINMUX('A', 6, ANALOG)>, /* LTDC_G2 */
                      <STM32_PINMUX('A', 8, ANALOG)>, /* LTDC_R6 */
                      <STM32_PINMUX('A', 12, ANALOG)>, /* LTDC_R5 */
-                     <STM32_PINMUX('A', 15, ANALOG)>, /* LTDC_R1 */
                      <STM32_PINMUX('B', 0, ANALOG)>, /* LTDC_R3 */
                      <STM32_PINMUX('B', 5, ANALOG)>, /* LTDC_G7 */
                      <STM32_PINMUX('B', 8, ANALOG)>, /* LTDC_B6 */
@@ -381,21 +375,16 @@
                      <STM32_PINMUX('C', 6, ANALOG)>, /* LTDC_HSYNC */
                      <STM32_PINMUX('C', 7, ANALOG)>, /* LTDC_G6 */
                      <STM32_PINMUX('D', 10, ANALOG)>, /* LTDC_B3 */
-                     <STM32_PINMUX('E', 4, ANALOG)>, /* LTDC_B0 */
-                     <STM32_PINMUX('E', 5, ANALOG)>, /* LTDC_G0 */
-                     <STM32_PINMUX('E', 6, ANALOG)>, /* LTDC_G1 */
                      <STM32_PINMUX('E', 11, ANALOG)>, /* LTDC_G3 */
                      <STM32_PINMUX('E', 12, ANALOG)>, /* LTDC_B4 */
                      <STM32_PINMUX('E', 13, ANALOG)>, /* LTDC_DE */
                      <STM32_PINMUX('E', 14, ANALOG)>, /* LTDC_CLK */
                      <STM32_PINMUX('E', 15, ANALOG)>, /* LTDC_R7 */
                      <STM32_PINMUX('F', 11, ANALOG)>, /* LTDC_G5 */
-                     <STM32_PINMUX('G', 10, ANALOG)>, /* LTDC_B2 */
-                     <STM32_PINMUX('G', 12, ANALOG)>, /* LTDC_B1 */
-                     <STM32_PINMUX('G', 13, ANALOG)>; /* LTDC_R0 */
+                     <STM32_PINMUX('G', 10, ANALOG)>; /* LTDC_B2 */
         };
     };
-    quadspi_sleep_pins_mx: quadspi_sleep_mx-0 {
+    quadspi_sleep_pins_mx: quadspi_sleep_mx@0 {
         u-boot,dm-pre-reloc;
         pins {
             u-boot,dm-pre-reloc;
@@ -412,7 +401,7 @@
                      <STM32_PINMUX('F', 10, ANALOG)>; /* QUADSPI_CLK */
         };
     };
-    sdmmc1_sleep_pins_mx: sdmmc1_sleep_mx-0 {
+    sdmmc1_sleep_pins_mx: sdmmc1_sleep_mx@0 {
         u-boot,dm-pre-reloc;
         pins {
             u-boot,dm-pre-reloc;
@@ -424,7 +413,7 @@
                      <STM32_PINMUX('D', 2, ANALOG)>; /* SDMMC1_CMD */
         };
     };
-    sdmmc2_sleep_pins_mx: sdmmc2_sleep_mx-0 {
+    sdmmc2_sleep_pins_mx: sdmmc2_sleep_mx@0 {
         u-boot,dm-pre-reloc;
         pins {
             u-boot,dm-pre-reloc;
@@ -436,38 +425,110 @@
                      <STM32_PINMUX('G', 6, ANALOG)>; /* SDMMC2_CMD */
         };
     };
-    tim1_pwm_sleep_pins_mx: tim1_pwm_sleep_mx-0 {
+    spi2_sleep_pins_mx: spi2_sleep_mx@0 {
         pins {
-            pinmux = <STM32_PINMUX('A', 9, ANALOG)>; /* TIM1_CH2 */
-        };
-    };
-    tim4_pwm_sleep_pins_mx: tim4_pwm_sleep_mx-0 {
-        pins {
-            pinmux = <STM32_PINMUX('D', 14, ANALOG)>; /* TIM4_CH3 */
+            pinmux = <STM32_PINMUX('A', 9, AF5)>, /* SPI2_SCK */
+                     <STM32_PINMUX('C', 2, AF5)>, /* SPI2_MISO */
+                     <STM32_PINMUX('C', 3, AF5)>; /* SPI2_MOSI */
+            bias-disable;
+            drive-push-pull;
+            slew-rate = <1>;
         };
     };
-    uart4_sleep_pins_mx: uart4_sleep_mx-0 {
+    uart4_sleep_pins_mx: uart4_sleep_mx@0 {
         u-boot,dm-pre-reloc;
-        pins {
+        pins1 {
+            u-boot,dm-pre-reloc;
+            pinmux = <STM32_PINMUX('G', 11, AF6)>; /* UART4_TX */
+            bias-pull-up;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+        pins2 {
             u-boot,dm-pre-reloc;
-            pinmux = <STM32_PINMUX('B', 2, ANALOG)>, /* UART4_RX */
-                     <STM32_PINMUX('G', 11, ANALOG)>; /* UART4_TX */
+            pinmux = <STM32_PINMUX('B', 2, AF8)>; /* UART4_RX */
+            bias-pull-up;
         };
     };
-    usart2_sleep_pins_mx: usart2_sleep_mx-0 {
-        pins {
-            pinmux = <STM32_PINMUX('D', 4, ANALOG)>, /* USART2_RTS */
-                     <STM32_PINMUX('D', 5, ANALOG)>, /* USART2_TX */
-                     <STM32_PINMUX('D', 6, ANALOG)>; /* USART2_RX */
+    uart8_sleep_pins_mx: uart8_sleep_mx@0 {
+        pins1 {
+            pinmux = <STM32_PINMUX('E', 1, AF8)>; /* UART8_TX */
+            bias-pull-up;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+        pins2 {
+            pinmux = <STM32_PINMUX('D', 14, AF8)>; /* UART8_CTS */
+            bias-pull-down;
+        };
+        pins3 {
+            pinmux = <STM32_PINMUX('G', 7, AF8)>; /* UART8_RTS */
+            bias-pull-down;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+        pins4 {
+            pinmux = <STM32_PINMUX('E', 0, AF8)>; /* UART8_RX */
+            bias-pull-up;
         };
     };
-    usart6_sleep_pins_mx: usart6_sleep_mx-0 {
-        pins {
-            pinmux = <STM32_PINMUX('G', 9, ANALOG)>, /* USART6_RX */
-                     <STM32_PINMUX('G', 14, ANALOG)>; /* USART6_TX */
+    usart2_sleep_pins_mx: usart2_sleep_mx@0 {
+        pins1 {
+            pinmux = <STM32_PINMUX('D', 5, AF7)>; /* USART2_TX */
+            bias-pull-up;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+        pins2 {
+            pinmux = <STM32_PINMUX('D', 3, AF7)>; /* USART2_CTS */
+            bias-pull-down;
+        };
+        pins3 {
+            pinmux = <STM32_PINMUX('D', 4, AF7)>; /* USART2_RTS */
+            bias-pull-down;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+        pins4 {
+            pinmux = <STM32_PINMUX('D', 6, AF7)>; /* USART2_RX */
+            bias-pull-up;
         };
     };
-    usb_otg_hs_sleep_pins_mx: usb_otg_hs_sleep_mx-0 {
+    usart3_sleep_pins_mx: usart3_sleep_mx@0 {
+        pins1 {
+            pinmux = <STM32_PINMUX('D', 8, AF7)>; /* USART3_TX */
+            bias-pull-up;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+        pins2 {
+            pinmux = <STM32_PINMUX('D', 11, AF7)>; /* USART3_CTS */
+            bias-pull-down;
+        };
+        pins3 {
+            pinmux = <STM32_PINMUX('D', 12, AF7)>; /* USART3_RTS */
+            bias-pull-down;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+        pins4 {
+            pinmux = <STM32_PINMUX('D', 9, AF7)>; /* USART3_RX */
+            bias-pull-up;
+        };
+    };
+    usart6_sleep_pins_mx: usart6_sleep_mx@0 {
+        pins1 {
+            pinmux = <STM32_PINMUX('G', 14, AF7)>; /* USART6_TX */
+            bias-pull-up;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+        pins2 {
+            pinmux = <STM32_PINMUX('G', 9, AF7)>; /* USART6_RX */
+            bias-pull-up;
+        };
+    };
+    usb_otg_hs_sleep_pins_mx: usb_otg_hs_sleep_mx@0 {
         u-boot,dm-pre-reloc;
         pins {
             u-boot,dm-pre-reloc;
@@ -476,319 +537,136 @@
     };
 };
 
-&m4_rproc{
-    mboxes = <&ipcc 0>, <&ipcc 1>, <&ipcc 2>;
-    mbox-names = "vq0", "vq1", "shutdown";
-    recovery;
-    status = "okay";
-
-    /* USER CODE BEGIN m4_rproc */
-    /* USER CODE END m4_rproc */
-};
-
-&adc{
+&adc {
     pinctrl-names = "default", "sleep";
     pinctrl-0 = <&adc_pins_mx>;
     pinctrl-1 = <&adc_sleep_pins_mx>;
     status = "okay";
-
-    /* USER CODE BEGIN adc */
-    /* USER CODE END adc */
-};
-
-&bsec{
-    status = "okay";
-
-    /* USER CODE BEGIN bsec */
-    /* USER CODE END bsec */
-};
-
-&crc1{
-    status = "okay";
-
-    /* USER CODE BEGIN crc1 */
-    /* USER CODE END crc1 */
-};
-
-&cryp1{
-    status = "okay";
-
-    /* USER CODE BEGIN cryp1 */
-    /* USER CODE END cryp1 */
-};
-
-&dts{
-    status = "okay";
-
-    /* USER CODE BEGIN dts */
-    /* USER CODE END dts */
 };
 
-&ethernet0{
+&ethernet0 {
     pinctrl-names = "default", "sleep";
     pinctrl-0 = <&eth1_pins_mx>;
     pinctrl-1 = <&eth1_sleep_pins_mx>;
     status = "okay";
-
-    /* USER CODE BEGIN ethernet0 */
-    /* USER CODE END ethernet0 */
-};
-
-&gpu{
-    status = "okay";
-
-    /* USER CODE BEGIN gpu */
-    /* USER CODE END gpu */
-};
-
-&hash1{
-    status = "okay";
-
-    /* USER CODE BEGIN hash1 */
-    /* USER CODE END hash1 */
 };
 
-&hsem{
+&m_can1 {
+    pinctrl-names = "default", "sleep";
+    pinctrl-0 = <&fdcan1_pins_mx>;
+    pinctrl-1 = <&fdcan1_sleep_pins_mx>;
     status = "okay";
-
-    /* USER CODE BEGIN hsem */
-    /* USER CODE END hsem */
 };
 
-&i2c2{
+&i2c2 {
     pinctrl-names = "default", "sleep";
     pinctrl-0 = <&i2c2_pins_mx>;
     pinctrl-1 = <&i2c2_sleep_pins_mx>;
     status = "okay";
-
-    /* USER CODE BEGIN i2c2 */
-    /* USER CODE END i2c2 */
 };
 
-&i2c4{
+&i2c4 {
     pinctrl-names = "default", "sleep";
     pinctrl-0 = <&i2c4_pins_mx>;
     pinctrl-1 = <&i2c4_sleep_pins_mx>;
     status = "okay";
-
-    /* USER CODE BEGIN i2c4 */
-    /* USER CODE END i2c4 */
-};
-
-&i2s2{
-    pinctrl-names = "default", "sleep";
-    pinctrl-0 = <&i2s2_pins_mx>;
-    pinctrl-1 = <&i2s2_sleep_pins_mx>;
-    status = "okay";
-
-    /* USER CODE BEGIN i2s2 */
-    /* USER CODE END i2s2 */
-};
-
-&ipcc{
-    status = "okay";
-
-    /* USER CODE BEGIN ipcc */
-    /* USER CODE END ipcc */
 };
 
-&ltdc{
-    u-boot,dm-pre-reloc;
+&ltdc {
     pinctrl-names = "default", "sleep";
     pinctrl-0 = <&ltdc_pins_mx>;
     pinctrl-1 = <&ltdc_sleep_pins_mx>;
     status = "okay";
-
-    /* USER CODE BEGIN ltdc */
-    /* USER CODE END ltdc */
 };
 
-&m_can1{
-    pinctrl-names = "default", "sleep";
-    pinctrl-0 = <&fdcan1_pins_mx>;
-    pinctrl-1 = <&fdcan1_sleep_pins_mx>;
-    status = "okay";
-
-    /* USER CODE BEGIN m_can1 */
-    /* USER CODE END m_can1 */
-};
-
-&qspi{
+&qspi {
     u-boot,dm-pre-reloc;
     pinctrl-names = "default", "sleep";
     pinctrl-0 = <&quadspi_pins_mx>;
     pinctrl-1 = <&quadspi_sleep_pins_mx>;
     status = "okay";
-
-    /* USER CODE BEGIN qspi */
-    /* USER CODE END qspi */
 };
 
-&rcc{
+&rcc {
     u-boot,dm-pre-reloc;
     status = "okay";
-
-    /* USER CODE BEGIN rcc */
-    /* USER CODE END rcc */
 };
 
-&rng1{
+&rtc {
     status = "okay";
-
-    /* USER CODE BEGIN rng1 */
-    /* USER CODE END rng1 */
-};
-
-&rtc{
-    status = "okay";
-
-    /* USER CODE BEGIN rtc */
-    /* USER CODE END rtc */
 };
 
-&sdmmc1{
+&sdmmc1 {
     u-boot,dm-pre-reloc;
     pinctrl-names = "default", "sleep";
     pinctrl-0 = <&sdmmc1_pins_mx>;
     pinctrl-1 = <&sdmmc1_sleep_pins_mx>;
     status = "okay";
-
-    /* USER CODE BEGIN sdmmc1 */
-    /* USER CODE END sdmmc1 */
 };
 
-&sdmmc2{
+&sdmmc2 {
     u-boot,dm-pre-reloc;
     pinctrl-names = "default", "sleep";
     pinctrl-0 = <&sdmmc2_pins_mx>;
     pinctrl-1 = <&sdmmc2_sleep_pins_mx>;
     status = "okay";
-
-    /* USER CODE BEGIN sdmmc2 */
-    /* USER CODE END sdmmc2 */
 };
 
-&timers1{
-    status = "okay";
-
-    /* USER CODE BEGIN timers1 */
-    /* USER CODE END timers1 */
-
-    pwm{
-        pinctrl-names = "default", "sleep";
-        pinctrl-0 = <&tim1_pwm_pins_mx>;
-        pinctrl-1 = <&tim1_pwm_sleep_pins_mx>;
-        status = "okay";
-
-        /* USER CODE BEGIN timers1_pwm */
-        /* USER CODE END timers1_pwm */
-    };
-};
-
-&timers4{
+&spi2 {
+    pinctrl-names = "default", "sleep";
+    pinctrl-0 = <&spi2_pins_mx>;
+    pinctrl-1 = <&spi2_sleep_pins_mx>;
     status = "okay";
-
-    /* USER CODE BEGIN timers4 */
-    /* USER CODE END timers4 */
-
-    pwm{
-        pinctrl-names = "default", "sleep";
-        pinctrl-0 = <&tim4_pwm_pins_mx>;
-        pinctrl-1 = <&tim4_pwm_sleep_pins_mx>;
-        status = "okay";
-
-        /* USER CODE BEGIN timers4_pwm */
-        /* USER CODE END timers4_pwm */
-    };
 };
 
-&uart4{
+&uart4 {
     u-boot,dm-pre-reloc;
     pinctrl-names = "default", "sleep";
     pinctrl-0 = <&uart4_pins_mx>;
     pinctrl-1 = <&uart4_sleep_pins_mx>;
     status = "okay";
-
-    /* USER CODE BEGIN uart4 */
-    /* USER CODE END uart4 */
 };
 
-&usart2{
+&uart8 {
     pinctrl-names = "default", "sleep";
-    pinctrl-0 = <&usart2_pins_mx>;
-    pinctrl-1 = <&usart2_sleep_pins_mx>;
+    pinctrl-0 = <&uart8_pins_mx>;
+    pinctrl-1 = <&uart8_sleep_pins_mx>;
     status = "okay";
-
-    /* USER CODE BEGIN usart2 */
-    /* USER CODE END usart2 */
 };
 
-&usart6{
+&usart2 {
     pinctrl-names = "default", "sleep";
-    pinctrl-0 = <&usart6_pins_mx>;
-    pinctrl-1 = <&usart6_sleep_pins_mx>;
+    pinctrl-0 = <&usart2_pins_mx>;
+    pinctrl-1 = <&usart2_sleep_pins_mx>;
     status = "okay";
-
-    /* USER CODE BEGIN usart6 */
-    /* USER CODE END usart6 */
 };
 
-&usbh_ehci{
+&usart3 {
+    pinctrl-names = "default", "sleep";
+    pinctrl-0 = <&usart3_pins_mx>;
+    pinctrl-1 = <&usart3_sleep_pins_mx>;
     status = "okay";
-
-    /* USER CODE BEGIN usbh_ehci */
-    /* USER CODE END usbh_ehci */
 };
 
-&usbh_ohci{
+&usart6 {
+    pinctrl-names = "default", "sleep";
+    pinctrl-0 = <&usart6_pins_mx>;
+    pinctrl-1 = <&usart6_sleep_pins_mx>;
     status = "okay";
-
-    /* USER CODE BEGIN usbh_ohci */
-    /* USER CODE END usbh_ohci */
 };
 
-&usbotg_hs{
+&usbotg_hs {
     u-boot,dm-pre-reloc;
     pinctrl-names = "default", "sleep";
     pinctrl-0 = <&usb_otg_hs_pins_mx>;
     pinctrl-1 = <&usb_otg_hs_sleep_pins_mx>;
     status = "okay";
-
-    /* USER CODE BEGIN usbotg_hs */
-    /* USER CODE END usbotg_hs */
-};
-
-&usbphyc{
-    u-boot,dm-pre-reloc;
-    status = "okay";
-
-    /* USER CODE BEGIN usbphyc */
-    /* USER CODE END usbphyc */
-};
-
-&usbphyc_port0{
-    u-boot,dm-pre-reloc;
-    status = "okay";
-
-    /* USER CODE BEGIN usbphyc_port0 */
-    /* USER CODE END usbphyc_port0 */
-};
-
-&usbphyc_port1{
-    u-boot,dm-pre-reloc;
-    status = "okay";
-
-    /* USER CODE BEGIN usbphyc_port1 */
-    /* USER CODE END usbphyc_port1 */
 };
 
-&vrefbuf{
+&usbh_ohci {
     status = "okay";
-
-    /* USER CODE BEGIN vrefbuf */
-    /* USER CODE END vrefbuf */
 };
 
-/* USER CODE BEGIN addons */
-/* USER CODE END addons */
+/* USER CODE BEGIN dts_soc */
+/* USER CODE END dts_soc */
 
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp157c-t1000-k-mx-u-boot.dtsi b/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp157c-t1000-k-mx-u-boot.dtsi
deleted file mode 100644
index e17d86f066b05ea28dc62c8477189ebb6738c111..0000000000000000000000000000000000000000
--- a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp157c-t1000-k-mx-u-boot.dtsi
+++ /dev/null
@@ -1,196 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause*/
-/*
- * Copyright (C) 2019, STMicroelectronics - All Rights Reserved
- * Author: STM32CubeMX code generation for STMicroelectronics.
- */
-
-#include <dt-bindings/clock/stm32mp1-clksrc.h>
-#include "stm32mp15-mx.h"
-
-#include "stm32mp157-u-boot.dtsi"
-#include "stm32mp15-ddr.dtsi"
-
-/* USER CODE BEGIN includes */
-/* USER CODE END includes */
-
-/ {
-
-	/* USER CODE BEGIN root */
-	/* USER CODE END root */
-
-	clocks {
-		/* USER CODE BEGIN clocks */
-		/* USER CODE END clocks */
-
-		clk_hsi: clk-hsi {
-			/* USER CODE BEGIN clocks */
-			/* USER CODE END clocks */
-			u-boot,dm-pre-reloc;
-		};
-
-		clk_csi: clk-csi {
-			/* USER CODE BEGIN clocks */
-			/* USER CODE END clocks */
-			u-boot,dm-pre-reloc;
-		};
-
-		clk_lse: clk-lse {
-			/* USER CODE BEGIN clocks */
-			/* USER CODE END clocks */
-			st,drive=<LSEDRV_MEDIUM_HIGH>;
-			u-boot,dm-pre-reloc;
-		};
-
-		clk_hse: clk-hse {
-			/* USER CODE BEGIN clocks */
-			/* USER CODE END clocks */
-			u-boot,dm-pre-reloc;
-		};
-	};
-
-}; /*root*/
-
-&rcc {
-	u-boot,dm-pre-reloc;
-	st,clksrc = <
-		CLK_MPU_PLL1P
-		CLK_AXI_PLL2P
-		CLK_MCU_PLL3P
-		CLK_PLL12_HSE
-		CLK_PLL3_HSE
-		CLK_PLL4_HSE
-		CLK_RTC_LSE
-		CLK_MCO1_DISABLED
-		CLK_MCO2_DISABLED
-	>;
-	st,clkdiv = <
-		1 		/*MPU*/
-		0 		/*AXI*/
-		0 		/*MCU*/
-		1 		/*APB1*/
-		1 		/*APB2*/
-		1 		/*APB3*/
-		1 		/*APB4*/
-		2 		/*APB5*/
-		0 		/*RTC*/
-		0 		/*MCO1*/
-		0 		/*MCO2*/
-	>;
-	st,pkcs = <
-		CLK_CKPER_HSE
-		CLK_QSPI_ACLK
-		CLK_ETH_PLL4P
-		CLK_SDMMC12_PLL4P
-		CLK_STGEN_HSE
-		CLK_USBPHY_HSE
-		CLK_SPI2S1_DISABLED
-		CLK_SPI2S23_DISABLED
-		CLK_SPI45_DISABLED
-		CLK_SPI6_DISABLED
-		CLK_I2C46_HSI
-		CLK_SDMMC3_DISABLED
-		CLK_USBO_USBPHY
-		CLK_ADC_CKPER
-		CLK_CEC_DISABLED
-		CLK_I2C12_HSI
-		CLK_I2C35_DISABLED
-		CLK_UART1_DISABLED
-		CLK_UART24_PCLK1
-		CLK_UART35_PCLK1
-		CLK_UART6_DISABLED
-		CLK_UART78_DISABLED
-		CLK_SPDIF_DISABLED
-		CLK_FDCAN_HSE
-		CLK_SAI1_DISABLED
-		CLK_SAI2_DISABLED
-		CLK_SAI3_DISABLED
-		CLK_SAI4_DISABLED
-		CLK_RNG1_CSI
-		CLK_LPTIM1_DISABLED
-		CLK_LPTIM23_DISABLED
-		CLK_LPTIM45_DISABLED
-	>;
-	pll1:st,pll@0 {
-		cfg = < 2 80 0 1 1 1>;
-		u-boot,dm-pre-reloc;
-	};
-	pll2:st,pll@1 {
-		cfg = < 2 65 1 1 0 7>;
-		u-boot,dm-pre-reloc;
-	};
-	pll3:st,pll@2 {
-		cfg = < 2 97 3 1 1 1>;
-		u-boot,dm-pre-reloc;
-	};
-	pll4:st,pll@3 {
-		cfg = < 5 124 9 9 9 3>;
-		u-boot,dm-pre-reloc;
-	};
-};
-
-&qspi{
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN qspi */
-	/* USER CODE END qspi */
-};
-
-&rcc{
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN rcc */
-	/* USER CODE END rcc */
-};
-
-&sdmmc1{
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN sdmmc1 */
-	/* USER CODE END sdmmc1 */
-};
-
-&sdmmc2{
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN sdmmc2 */
-	/* USER CODE END sdmmc2 */
-};
-
-&uart4{
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN uart4 */
-	/* USER CODE END uart4 */
-};
-
-&usbotg_hs{
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN usbotg_hs */
-	/* USER CODE END usbotg_hs */
-};
-
-&usbphyc{
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN usbphyc */
-	/* USER CODE END usbphyc */
-};
-
-&usbphyc_port0{
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN usbphyc_port0 */
-	/* USER CODE END usbphyc_port0 */
-};
-
-&usbphyc_port1{
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN usbphyc_port1 */
-	/* USER CODE END usbphyc_port1 */
-};
-
-/* USER CODE BEGIN addons */
-/* USER CODE END addons */
-
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp157c-t1000-k-mx.dts b/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp157c-t1000-k-mx.dts
deleted file mode 100644
index 00edeacca2124d6063093a31e4e672d84c745c2c..0000000000000000000000000000000000000000
--- a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp157c-t1000-k-mx.dts
+++ /dev/null
@@ -1,879 +0,0 @@
-/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
-/*
- * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
- * Author: STM32CubeMX code generation for STMicroelectronics.
- */
-
-/dts-v1/;
-#include "stm32mp157c.dtsi"
-#include "stm32mp157c-m4-srm.dtsi"
-#include "stm32mp157cad-pinctrl.dtsi"
-
-/* USER CODE BEGIN includes */
-/* USER CODE END includes */
-
-/ {
-	model = "STMicroelectronics custom STM32CubeMX board";
-	compatible = "st,stm32mp157c-t1000-k-mx", "st,stm32mp157";
-
-	memory@c0000000 {
-		reg = <0xc0000000 0x20000000>;
-
-		/* USER CODE BEGIN memory */
-		/* USER CODE END memory */
-	};
-
-	reserved-memory {
-		#address-cells = <1>;
-		#size-cells = <1>;
-		ranges;
-
-		/* USER CODE BEGIN reserved-memory */
-		/* USER CODE END reserved-memory */
-
-		gpu_reserved: gpu@dc000000 {
-			reg = <0xdc000000 0x4000000>;
-			no-map;
-		};
-	};
-
-	/* USER CODE BEGIN root */
-	/* USER CODE END root */
-
-	clocks {
-		/* USER CODE BEGIN clocks */
-		/* USER CODE END clocks */
-
-		clk_hsi: clk-hsi {
-			clock-frequency = <64000000>;
-		};
-
-		clk_csi: clk-csi {
-			clock-frequency = <4000000>;
-		};
-
-		clk_lse: clk-lse {
-			clock-frequency = <32768>;
-		};
-
-		clk_hse: clk-hse {
-			clock-frequency = <24000000>;
-		};
-	};
-
-}; /*root*/
-
-&pinctrl {
-	u-boot,dm-pre-reloc;
-
-	adc_pins_mx: adc_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 0, ANALOG)>, /* ADC1_INP16 */
-					 <STM32_PINMUX('B', 1, ANALOG)>; /* ADC1_INP5 */
-		};
-	};
-
-	adc_sleep_pins_mx: adc_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 0, ANALOG)>, /* ADC1_INP16 */
-					 <STM32_PINMUX('B', 1, ANALOG)>; /* ADC1_INP5 */
-		};
-	};
-
-	eth1_pins_mx: eth1_mx-0 {
-		pins1 {
-			pinmux = <STM32_PINMUX('A', 2, AF11)>; /* ETH1_MDIO */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-		pins2 {
-			pinmux = <STM32_PINMUX('A', 7, AF11)>, /* ETH1_CRS_DV */
-					 <STM32_PINMUX('C', 4, AF11)>, /* ETH1_RXD0 */
-					 <STM32_PINMUX('C', 5, AF11)>; /* ETH1_RXD1 */
-			bias-disable;
-		};
-		pins3 {
-			pinmux = <STM32_PINMUX('B', 11, AF11)>; /* ETH1_TX_EN */
-		};
-		pins4 {
-			pinmux = <STM32_PINMUX('B', 12, AF11)>, /* ETH1_TXD0 */
-					 <STM32_PINMUX('B', 13, AF11)>, /* ETH1_TXD1 */
-					 <STM32_PINMUX('C', 1, AF11)>, /* ETH1_MDC */
-					 <STM32_PINMUX('G', 8, AF2)>; /* ETH1_CLK */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-	};
-
-	eth1_sleep_pins_mx: eth1_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 2, ANALOG)>, /* ETH1_MDIO */
-					 <STM32_PINMUX('A', 7, ANALOG)>, /* ETH1_CRS_DV */
-					 <STM32_PINMUX('B', 11, ANALOG)>, /* ETH1_TX_EN */
-					 <STM32_PINMUX('B', 12, ANALOG)>, /* ETH1_TXD0 */
-					 <STM32_PINMUX('B', 13, ANALOG)>, /* ETH1_TXD1 */
-					 <STM32_PINMUX('C', 1, ANALOG)>, /* ETH1_MDC */
-					 <STM32_PINMUX('C', 4, ANALOG)>, /* ETH1_RXD0 */
-					 <STM32_PINMUX('C', 5, ANALOG)>, /* ETH1_RXD1 */
-					 <STM32_PINMUX('G', 8, ANALOG)>; /* ETH1_CLK */
-		};
-	};
-
-	fdcan1_pins_mx: fdcan1_mx-0 {
-		pins1 {
-			pinmux = <STM32_PINMUX('D', 0, AF9)>; /* FDCAN1_RX */
-			bias-disable;
-		};
-		pins2 {
-			pinmux = <STM32_PINMUX('D', 1, AF9)>; /* FDCAN1_TX */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-	};
-
-	fdcan1_sleep_pins_mx: fdcan1_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('D', 0, ANALOG)>, /* FDCAN1_RX */
-					 <STM32_PINMUX('D', 1, ANALOG)>; /* FDCAN1_TX */
-		};
-	};
-
-	i2c2_pins_mx: i2c2_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('D', 7, AF4)>, /* I2C2_SCL */
-					 <STM32_PINMUX('G', 15, AF4)>; /* I2C2_SDA */
-			bias-disable;
-			drive-open-drain;
-			slew-rate = <0>;
-		};
-	};
-
-	i2c2_sleep_pins_mx: i2c2_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('D', 7, ANALOG)>, /* I2C2_SCL */
-					 <STM32_PINMUX('G', 15, ANALOG)>; /* I2C2_SDA */
-		};
-	};
-
-	i2c4_pins_mx: i2c4_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('B', 7, AF6)>, /* I2C4_SDA */
-					 <STM32_PINMUX('E', 2, AF4)>; /* I2C4_SCL */
-			bias-disable;
-			drive-open-drain;
-			slew-rate = <0>;
-		};
-	};
-
-	i2c4_sleep_pins_mx: i2c4_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('B', 7, ANALOG)>, /* I2C4_SDA */
-					 <STM32_PINMUX('E', 2, ANALOG)>; /* I2C4_SCL */
-		};
-	};
-
-	ltdc_pins_mx: ltdc_mx-0 {
-		pins1 {
-			pinmux = <STM32_PINMUX('A', 1, AF14)>, /* LTDC_R2 */
-					 <STM32_PINMUX('A', 3, AF14)>, /* LTDC_B5 */
-					 <STM32_PINMUX('A', 4, AF14)>, /* LTDC_VSYNC */
-					 <STM32_PINMUX('A', 5, AF14)>, /* LTDC_R4 */
-					 <STM32_PINMUX('A', 6, AF14)>, /* LTDC_G2 */
-					 <STM32_PINMUX('A', 8, AF14)>, /* LTDC_R6 */
-					 <STM32_PINMUX('A', 12, AF14)>, /* LTDC_R5 */
-					 <STM32_PINMUX('A', 15, AF14)>, /* LTDC_R1 */
-					 <STM32_PINMUX('B', 0, AF9)>, /* LTDC_R3 */
-					 <STM32_PINMUX('B', 5, AF14)>, /* LTDC_G7 */
-					 <STM32_PINMUX('B', 8, AF14)>, /* LTDC_B6 */
-					 <STM32_PINMUX('B', 9, AF14)>, /* LTDC_B7 */
-					 <STM32_PINMUX('B', 10, AF14)>, /* LTDC_G4 */
-					 <STM32_PINMUX('C', 6, AF14)>, /* LTDC_HSYNC */
-					 <STM32_PINMUX('C', 7, AF14)>, /* LTDC_G6 */
-					 <STM32_PINMUX('D', 10, AF14)>, /* LTDC_B3 */
-					 <STM32_PINMUX('E', 4, AF14)>, /* LTDC_B0 */
-					 <STM32_PINMUX('E', 5, AF14)>, /* LTDC_G0 */
-					 <STM32_PINMUX('E', 6, AF14)>, /* LTDC_G1 */
-					 <STM32_PINMUX('E', 11, AF14)>, /* LTDC_G3 */
-					 <STM32_PINMUX('E', 12, AF14)>, /* LTDC_B4 */
-					 <STM32_PINMUX('E', 13, AF14)>, /* LTDC_DE */
-					 <STM32_PINMUX('E', 15, AF14)>, /* LTDC_R7 */
-					 <STM32_PINMUX('F', 11, AF14)>, /* LTDC_G5 */
-					 <STM32_PINMUX('G', 10, AF14)>, /* LTDC_B2 */
-					 <STM32_PINMUX('G', 12, AF14)>, /* LTDC_B1 */
-					 <STM32_PINMUX('G', 13, AF14)>; /* LTDC_R0 */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-		pins2 {
-			pinmux = <STM32_PINMUX('E', 14, AF14)>; /* LTDC_CLK */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-	};
-
-	ltdc_sleep_pins_mx: ltdc_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 1, ANALOG)>, /* LTDC_R2 */
-					 <STM32_PINMUX('A', 3, ANALOG)>, /* LTDC_B5 */
-					 <STM32_PINMUX('A', 4, ANALOG)>, /* LTDC_VSYNC */
-					 <STM32_PINMUX('A', 5, ANALOG)>, /* LTDC_R4 */
-					 <STM32_PINMUX('A', 6, ANALOG)>, /* LTDC_G2 */
-					 <STM32_PINMUX('A', 8, ANALOG)>, /* LTDC_R6 */
-					 <STM32_PINMUX('A', 12, ANALOG)>, /* LTDC_R5 */
-					 <STM32_PINMUX('A', 15, ANALOG)>, /* LTDC_R1 */
-					 <STM32_PINMUX('B', 0, ANALOG)>, /* LTDC_R3 */
-					 <STM32_PINMUX('B', 5, ANALOG)>, /* LTDC_G7 */
-					 <STM32_PINMUX('B', 8, ANALOG)>, /* LTDC_B6 */
-					 <STM32_PINMUX('B', 9, ANALOG)>, /* LTDC_B7 */
-					 <STM32_PINMUX('B', 10, ANALOG)>, /* LTDC_G4 */
-					 <STM32_PINMUX('C', 6, ANALOG)>, /* LTDC_HSYNC */
-					 <STM32_PINMUX('C', 7, ANALOG)>, /* LTDC_G6 */
-					 <STM32_PINMUX('D', 10, ANALOG)>, /* LTDC_B3 */
-					 <STM32_PINMUX('E', 4, ANALOG)>, /* LTDC_B0 */
-					 <STM32_PINMUX('E', 5, ANALOG)>, /* LTDC_G0 */
-					 <STM32_PINMUX('E', 6, ANALOG)>, /* LTDC_G1 */
-					 <STM32_PINMUX('E', 11, ANALOG)>, /* LTDC_G3 */
-					 <STM32_PINMUX('E', 12, ANALOG)>, /* LTDC_B4 */
-					 <STM32_PINMUX('E', 13, ANALOG)>, /* LTDC_DE */
-					 <STM32_PINMUX('E', 14, ANALOG)>, /* LTDC_CLK */
-					 <STM32_PINMUX('E', 15, ANALOG)>, /* LTDC_R7 */
-					 <STM32_PINMUX('F', 11, ANALOG)>, /* LTDC_G5 */
-					 <STM32_PINMUX('G', 10, ANALOG)>, /* LTDC_B2 */
-					 <STM32_PINMUX('G', 12, ANALOG)>, /* LTDC_B1 */
-					 <STM32_PINMUX('G', 13, ANALOG)>; /* LTDC_R0 */
-		};
-	};
-
-	quadspi_pins_mx: quadspi_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 6, AF10)>, /* QUADSPI_BK1_NCS */
-					 <STM32_PINMUX('C', 0, AF10)>; /* QUADSPI_BK2_NCS */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('E', 7, AF10)>, /* QUADSPI_BK2_IO0 */
-					 <STM32_PINMUX('E', 8, AF10)>, /* QUADSPI_BK2_IO1 */
-					 <STM32_PINMUX('E', 9, AF10)>, /* QUADSPI_BK2_IO2 */
-					 <STM32_PINMUX('E', 10, AF10)>, /* QUADSPI_BK2_IO3 */
-					 <STM32_PINMUX('F', 6, AF9)>, /* QUADSPI_BK1_IO3 */
-					 <STM32_PINMUX('F', 7, AF9)>, /* QUADSPI_BK1_IO2 */
-					 <STM32_PINMUX('F', 8, AF10)>, /* QUADSPI_BK1_IO0 */
-					 <STM32_PINMUX('F', 9, AF10)>; /* QUADSPI_BK1_IO1 */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins3 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('F', 10, AF9)>; /* QUADSPI_CLK */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <2>;
-		};
-	};
-
-	quadspi_sleep_pins_mx: quadspi_sleep_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 6, ANALOG)>, /* QUADSPI_BK1_NCS */
-					 <STM32_PINMUX('C', 0, ANALOG)>, /* QUADSPI_BK2_NCS */
-					 <STM32_PINMUX('E', 7, ANALOG)>, /* QUADSPI_BK2_IO0 */
-					 <STM32_PINMUX('E', 8, ANALOG)>, /* QUADSPI_BK2_IO1 */
-					 <STM32_PINMUX('E', 9, ANALOG)>, /* QUADSPI_BK2_IO2 */
-					 <STM32_PINMUX('E', 10, ANALOG)>, /* QUADSPI_BK2_IO3 */
-					 <STM32_PINMUX('F', 6, ANALOG)>, /* QUADSPI_BK1_IO3 */
-					 <STM32_PINMUX('F', 7, ANALOG)>, /* QUADSPI_BK1_IO2 */
-					 <STM32_PINMUX('F', 8, ANALOG)>, /* QUADSPI_BK1_IO0 */
-					 <STM32_PINMUX('F', 9, ANALOG)>, /* QUADSPI_BK1_IO1 */
-					 <STM32_PINMUX('F', 10, ANALOG)>; /* QUADSPI_CLK */
-		};
-	};
-
-	rtc_pins_mx: rtc_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('C', 13, ANALOG)>; /* RTC_LSCO */
-		};
-	};
-
-	rtc_sleep_pins_mx: rtc_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('C', 13, ANALOG)>; /* RTC_LSCO */
-		};
-	};
-
-	sdmmc1_pins_mx: sdmmc1_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
-					 <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
-					 <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
-					 <STM32_PINMUX('C', 11, AF12)>, /* SDMMC1_D3 */
-					 <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 12, AF12)>; /* SDMMC1_CK */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-	};
-
-	sdmmc1_opendrain_pins_mx: sdmmc1_opendrain_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
-					 <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
-					 <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
-					 <STM32_PINMUX('C', 11, AF12)>; /* SDMMC1_D3 */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 12, AF12)>; /* SDMMC1_CK */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins3 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
-			bias-pull-up;
-			drive-open-drain;
-			slew-rate = <1>;
-		};
-	};
-
-	sdmmc1_sleep_pins_mx: sdmmc1_sleep_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 8, ANALOG)>, /* SDMMC1_D0 */
-					 <STM32_PINMUX('C', 9, ANALOG)>, /* SDMMC1_D1 */
-					 <STM32_PINMUX('C', 10, ANALOG)>, /* SDMMC1_D2 */
-					 <STM32_PINMUX('C', 11, ANALOG)>, /* SDMMC1_D3 */
-					 <STM32_PINMUX('C', 12, ANALOG)>, /* SDMMC1_CK */
-					 <STM32_PINMUX('D', 2, ANALOG)>; /* SDMMC1_CMD */
-		};
-	};
-
-	sdmmc2_pins_mx: sdmmc2_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 3, AF9)>, /* SDMMC2_D2 */
-					 <STM32_PINMUX('B', 4, AF9)>, /* SDMMC2_D3 */
-					 <STM32_PINMUX('B', 14, AF9)>, /* SDMMC2_D0 */
-					 <STM32_PINMUX('B', 15, AF9)>, /* SDMMC2_D1 */
-					 <STM32_PINMUX('G', 6, AF10)>; /* SDMMC2_CMD */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('E', 3, AF9)>; /* SDMMC2_CK */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-	};
-
-	sdmmc2_opendrain_pins_mx: sdmmc2_opendrain_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 3, AF9)>, /* SDMMC2_D2 */
-					 <STM32_PINMUX('B', 4, AF9)>, /* SDMMC2_D3 */
-					 <STM32_PINMUX('B', 14, AF9)>, /* SDMMC2_D0 */
-					 <STM32_PINMUX('B', 15, AF9)>; /* SDMMC2_D1 */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('E', 3, AF9)>; /* SDMMC2_CK */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins3 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('G', 6, AF10)>; /* SDMMC2_CMD */
-			bias-pull-up;
-			drive-open-drain;
-			slew-rate = <1>;
-		};
-	};
-
-	sdmmc2_sleep_pins_mx: sdmmc2_sleep_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 3, ANALOG)>, /* SDMMC2_D2 */
-					 <STM32_PINMUX('B', 4, ANALOG)>, /* SDMMC2_D3 */
-					 <STM32_PINMUX('B', 14, ANALOG)>, /* SDMMC2_D0 */
-					 <STM32_PINMUX('B', 15, ANALOG)>, /* SDMMC2_D1 */
-					 <STM32_PINMUX('E', 3, ANALOG)>, /* SDMMC2_CK */
-					 <STM32_PINMUX('G', 6, ANALOG)>; /* SDMMC2_CMD */
-		};
-	};
-
-	tim1_pwm_pins_mx: tim1_pwm_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 9, AF1)>; /* TIM1_CH2 */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-	};
-
-	tim1_pwm_sleep_pins_mx: tim1_pwm_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 9, ANALOG)>; /* TIM1_CH2 */
-		};
-	};
-
-	tim4_pwm_pins_mx: tim4_pwm_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('D', 14, AF2)>; /* TIM4_CH3 */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-	};
-
-	tim4_pwm_sleep_pins_mx: tim4_pwm_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('D', 14, ANALOG)>; /* TIM4_CH3 */
-		};
-	};
-
-	uart4_pins_mx: uart4_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 2, AF8)>; /* UART4_RX */
-			bias-pull-up;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('G', 11, AF6)>; /* UART4_TX */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-	};
-
-	uart4_sleep_pins_mx: uart4_sleep_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 2, ANALOG)>, /* UART4_RX */
-					 <STM32_PINMUX('G', 11, ANALOG)>; /* UART4_TX */
-		};
-	};
-
-	usart2_pins_mx: usart2_mx-0 {
-		pins1 {
-			pinmux = <STM32_PINMUX('D', 4, AF7)>; /* USART2_RTS */
-			bias-pull-down;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-		pins2 {
-			pinmux = <STM32_PINMUX('D', 5, AF7)>; /* USART2_TX */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-		pins3 {
-			pinmux = <STM32_PINMUX('D', 6, AF7)>; /* USART2_RX */
-			bias-pull-up;
-		};
-	};
-
-	usart2_sleep_pins_mx: usart2_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('D', 4, ANALOG)>, /* USART2_RTS */
-					 <STM32_PINMUX('D', 5, ANALOG)>, /* USART2_TX */
-					 <STM32_PINMUX('D', 6, ANALOG)>; /* USART2_RX */
-		};
-	};
-
-	usart3_pins_mx: usart3_mx-0 {
-		pins1 {
-			pinmux = <STM32_PINMUX('D', 9, AF7)>, /* USART3_RX */
-					 <STM32_PINMUX('D', 11, AF7)>; /* USART3_CTS */
-			bias-disable;
-		};
-		pins2 {
-			pinmux = <STM32_PINMUX('D', 8, AF7)>, /* USART3_TX */
-					 <STM32_PINMUX('D', 12, AF7)>; /* USART3_RTS */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-	};
-
-	usart3_sleep_pins_mx: usart3_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('D', 8, ANALOG)>, /* USART3_TX */
-					 <STM32_PINMUX('D', 9, ANALOG)>, /* USART3_RX */
-					 <STM32_PINMUX('D', 11, ANALOG)>, /* USART3_CTS */
-					 <STM32_PINMUX('D', 12, ANALOG)>; /* USART3_RTS */
-		};
-	};
-
-	usb_otg_hs_pins_mx: usb_otg_hs_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
-		};
-	};
-
-	usb_otg_hs_sleep_pins_mx: usb_otg_hs_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
-		};
-	};
-
-	/* USER CODE BEGIN pinctrl */
-	/* USER CODE END pinctrl */
-};
-
-&pinctrl_z {
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN pinctrl_z */
-	/* USER CODE END pinctrl_z */
-};
-
-&m4_rproc{
-	mboxes = <&ipcc 0>, <&ipcc 1>, <&ipcc 2>;
-	mbox-names = "vq0", "vq1", "shutdown";
-	recovery;
-	status = "okay";
-
-	/* USER CODE BEGIN m4_rproc */
-	/* USER CODE END m4_rproc */
-};
-
-&adc{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&adc_pins_mx>;
-	pinctrl-1 = <&adc_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN adc */
-	/* USER CODE END adc */
-};
-
-&bsec{
-	status = "okay";
-
-	/* USER CODE BEGIN bsec */
-	/* USER CODE END bsec */
-};
-
-&crc1{
-	status = "okay";
-
-	/* USER CODE BEGIN crc1 */
-	/* USER CODE END crc1 */
-};
-
-&cryp1{
-	status = "okay";
-
-	/* USER CODE BEGIN cryp1 */
-	/* USER CODE END cryp1 */
-};
-
-&dts{
-	status = "okay";
-
-	/* USER CODE BEGIN dts */
-	/* USER CODE END dts */
-};
-
-&ethernet0{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&eth1_pins_mx>;
-	pinctrl-1 = <&eth1_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN ethernet0 */
-	/* USER CODE END ethernet0 */
-};
-
-&gpu{
-	status = "okay";
-
-	/* USER CODE BEGIN gpu */
-	/* USER CODE END gpu */
-};
-
-&hash1{
-	status = "okay";
-
-	/* USER CODE BEGIN hash1 */
-	/* USER CODE END hash1 */
-};
-
-&hsem{
-	status = "okay";
-
-	/* USER CODE BEGIN hsem */
-	/* USER CODE END hsem */
-};
-
-&i2c2{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&i2c2_pins_mx>;
-	pinctrl-1 = <&i2c2_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN i2c2 */
-	/* USER CODE END i2c2 */
-};
-
-&i2c4{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&i2c4_pins_mx>;
-	pinctrl-1 = <&i2c4_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN i2c4 */
-	/* USER CODE END i2c4 */
-};
-
-&ipcc{
-	status = "okay";
-
-	/* USER CODE BEGIN ipcc */
-	/* USER CODE END ipcc */
-};
-
-&ltdc{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&ltdc_pins_mx>;
-	pinctrl-1 = <&ltdc_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN ltdc */
-	/* USER CODE END ltdc */
-};
-
-&m_can1{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&fdcan1_pins_mx>;
-	pinctrl-1 = <&fdcan1_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN m_can1 */
-	/* USER CODE END m_can1 */
-};
-
-&qspi{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&quadspi_pins_mx>;
-	pinctrl-1 = <&quadspi_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN qspi */
-	/* USER CODE END qspi */
-};
-
-&rcc{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN rcc */
-	/* USER CODE END rcc */
-};
-
-&rng1{
-	status = "okay";
-
-	/* USER CODE BEGIN rng1 */
-	/* USER CODE END rng1 */
-};
-
-&rtc{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&rtc_pins_mx>;
-	pinctrl-1 = <&rtc_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN rtc */
-	/* USER CODE END rtc */
-};
-
-&sdmmc1{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "opendrain", "sleep";
-	pinctrl-0 = <&sdmmc1_pins_mx>;
-	pinctrl-1 = <&sdmmc1_opendrain_pins_mx>;
-	pinctrl-2 = <&sdmmc1_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN sdmmc1 */
-	/* USER CODE END sdmmc1 */
-};
-
-&sdmmc2{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "opendrain", "sleep";
-	pinctrl-0 = <&sdmmc2_pins_mx>;
-	pinctrl-1 = <&sdmmc2_opendrain_pins_mx>;
-	pinctrl-2 = <&sdmmc2_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN sdmmc2 */
-	/* USER CODE END sdmmc2 */
-};
-
-&timers1{
-	status = "okay";
-
-	/* USER CODE BEGIN timers1 */
-	/* USER CODE END timers1 */
-
-	pwm{
-		pinctrl-names = "default", "sleep";
-		pinctrl-0 = <&tim1_pwm_pins_mx>;
-		pinctrl-1 = <&tim1_pwm_sleep_pins_mx>;
-		status = "okay";
-
-		/* USER CODE BEGIN timers1_pwm */
-		/* USER CODE END timers1_pwm */
-	};
-};
-
-&timers4{
-	status = "okay";
-
-	/* USER CODE BEGIN timers4 */
-	/* USER CODE END timers4 */
-
-	pwm{
-		pinctrl-names = "default", "sleep";
-		pinctrl-0 = <&tim4_pwm_pins_mx>;
-		pinctrl-1 = <&tim4_pwm_sleep_pins_mx>;
-		status = "okay";
-
-		/* USER CODE BEGIN timers4_pwm */
-		/* USER CODE END timers4_pwm */
-	};
-};
-
-&uart4{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&uart4_pins_mx>;
-	pinctrl-1 = <&uart4_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN uart4 */
-	/* USER CODE END uart4 */
-};
-
-&usart2{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&usart2_pins_mx>;
-	pinctrl-1 = <&usart2_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN usart2 */
-	/* USER CODE END usart2 */
-};
-
-&usart3{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&usart3_pins_mx>;
-	pinctrl-1 = <&usart3_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN usart3 */
-	/* USER CODE END usart3 */
-};
-
-&usbh_ehci{
-	status = "okay";
-
-	/* USER CODE BEGIN usbh_ehci */
-	/* USER CODE END usbh_ehci */
-};
-
-&usbh_ohci{
-	status = "okay";
-
-	/* USER CODE BEGIN usbh_ohci */
-	/* USER CODE END usbh_ohci */
-};
-
-&usbotg_hs{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&usb_otg_hs_pins_mx>;
-	pinctrl-1 = <&usb_otg_hs_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN usbotg_hs */
-	/* USER CODE END usbotg_hs */
-};
-
-&usbphyc{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc */
-	/* USER CODE END usbphyc */
-};
-
-&usbphyc_port0{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc_port0 */
-	/* USER CODE END usbphyc_port0 */
-};
-
-&usbphyc_port1{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc_port1 */
-	/* USER CODE END usbphyc_port1 */
-};
-
-&vrefbuf{
-	status = "okay";
-
-	/* USER CODE BEGIN vrefbuf */
-	/* USER CODE END vrefbuf */
-};
-
-/* USER CODE BEGIN addons */
-/* USER CODE END addons */
-
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp157c-t1000-mini-mx-u-boot.dtsi b/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp157c-t1000-mini-mx-u-boot.dtsi
new file mode 100644
index 0000000000000000000000000000000000000000..75d9c7a5c487e5f91c5eda032b3f0661297e09b4
--- /dev/null
+++ b/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp157c-t1000-mini-mx-u-boot.dtsi
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier:	GPL-2.0+	BSD-3-Clause
+ *
+ */
+
+#include <dt-bindings/clock/stm32mp1-clksrc.h>
+#include "stm32mp15-mx.h"
+
+#include "stm32mp157cad-u-boot.dtsi"
+#include "stm32mp15-ddr.dtsi"
+
+/* USER CODE BEGIN dts_include */
+/* USER CODE END dts_include */
+
+/ {
+
+	/* USER CODE BEGIN root_prop */
+	/* USER CODE END root_prop */
+
+    clocks {
+        u-boot,dm-pre-reloc;
+        clk_hsi: clk-hsi {
+            u-boot,dm-pre-reloc;
+        };
+        clk_usbo_48m: ck_usbo_48m {
+            u-boot,dm-pre-reloc;
+        };
+        clk_lse: clk-lse {
+            st,drive=<LSEDRV_LOWEST>;
+            u-boot,dm-pre-reloc;
+        };
+        clk_hse: clk-hse {
+            u-boot,dm-pre-reloc;
+        };
+    };
+	/* USER CODE BEGIN root_subnodes */
+	/* USER CODE END root_subnodes */
+
+	/* USER CODE BEGIN root_board */
+	/* USER CODE END root_board */
+
+	/* USER CODE BEGIN root_platform */
+	/* USER CODE END root_platform */
+
+}; /*root*/
+
+/* USER CODE BEGIN dts_board */
+/* USER CODE END dts_board */
+
+&gpioa {
+    compatible = "st,stm32-gpio";
+    u-boot,dm-pre-reloc;
+};
+&gpiob {
+    compatible = "st,stm32-gpio";
+    u-boot,dm-pre-reloc;
+};
+&gpioc {
+    compatible = "st,stm32-gpio";
+    u-boot,dm-pre-reloc;
+};
+&gpiod {
+    compatible = "st,stm32-gpio";
+    u-boot,dm-pre-reloc;
+};
+&gpioe {
+    compatible = "st,stm32-gpio";
+    u-boot,dm-pre-reloc;
+};
+&gpiof {
+    compatible = "st,stm32-gpio";
+    u-boot,dm-pre-reloc;
+};
+&gpiog {
+    compatible = "st,stm32-gpio";
+    u-boot,dm-pre-reloc;
+};
+&gpioh {
+    compatible = "st,stm32-gpio";
+    u-boot,dm-pre-reloc;
+};
+&gpioi {
+    compatible = "st,stm32-gpio";
+    u-boot,dm-pre-reloc;
+};
+&gpioj {
+    compatible = "st,stm32-gpio";
+    u-boot,dm-pre-reloc;
+};
+&gpiok {
+    compatible = "st,stm32-gpio";
+    u-boot,dm-pre-reloc;
+};
+&gpioz {
+    compatible = "st,stm32-gpio";
+    u-boot,dm-pre-reloc;
+};
+
+&rcc {
+    u-boot,dm-pre-reloc;
+    st,clksrc = <
+        CLK_MPU_PLL1P
+        CLK_AXI_PLL2P
+        CLK_MCU_PLL3P
+        CLK_PLL12_HSE
+        CLK_PLL3_HSE
+        CLK_PLL4_HSE
+        CLK_RTC_LSE
+        CLK_MCO1_DISABLED
+        CLK_MCO2_DISABLED
+    >;
+    st,clkdiv = <
+        1         /*MPU*/
+        0         /*AXI*/
+        0         /*MCU*/
+        1         /*APB1*/
+        1         /*APB2*/
+        1         /*APB3*/
+        1         /*APB4*/
+        2         /*APB5*/
+        23         /*RTC*/
+        0         /*MCO1*/
+        0         /*MCO2*/
+    >;
+    st,pkcs = <
+        CLK_CKPER_HSE
+        CLK_QSPI_ACLK
+        CLK_ETH_PLL4P
+        CLK_SDMMC12_PLL3R
+        CLK_STGEN_HSE
+        CLK_USBPHY_HSE
+        CLK_SPI2S1_DISABLED
+        CLK_SPI2S23_PLL3Q
+        CLK_SPI45_DISABLED
+        CLK_SPI6_DISABLED
+        CLK_I2C46_HSI
+        CLK_SDMMC3_DISABLED
+        CLK_USBO_USBPHY
+        CLK_ADC_CKPER
+        CLK_CEC_DISABLED
+        CLK_I2C12_HSI
+        CLK_I2C35_DISABLED
+        CLK_UART1_DISABLED
+        CLK_UART24_HSI
+        CLK_UART35_DISABLED
+        CLK_UART78_DISABLED
+        CLK_SPDIF_DISABLED
+        CLK_FDCAN_DISABLED
+        CLK_SAI1_DISABLED
+        CLK_SAI2_DISABLED
+        CLK_SAI3_DISABLED
+        CLK_SAI4_DISABLED
+        CLK_LPTIM1_DISABLED
+        CLK_LPTIM23_DISABLED
+        CLK_LPTIM45_DISABLED
+    >;
+    pll1:st,pll@0 {
+        cfg = < 2 80 0 0 0 1>;
+        frac = < 0x800 >;
+        u-boot,dm-pre-reloc;
+    };
+    pll2:st,pll@1 {
+        cfg = < 2 65 1 0 0 5>;
+        frac = < 0x1400 >;
+        u-boot,dm-pre-reloc;
+    };
+    pll3:st,pll@2 {
+        cfg = < 2 97 3 15 7 5>;
+        frac = < 0x9ba >;
+        u-boot,dm-pre-reloc;
+    };
+    pll4:st,pll@3 {
+        cfg = < 5 124 9 9 9 1>;
+        u-boot,dm-pre-reloc;
+    };
+};
+
+/* USER CODE BEGIN dts_soc */
+/* USER CODE END dts_soc */
+
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp157c-t1000-mini-mx.dts b/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp157c-t1000-mini-mx.dts
new file mode 100644
index 0000000000000000000000000000000000000000..b1bb31e6651dcd9c21b04bf3c0087a9d7b246625
--- /dev/null
+++ b/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp157c-t1000-mini-mx.dts
@@ -0,0 +1,451 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
+/*
+ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved
+ * Author: STM32CubeMX code generation for STMicroelectronics.
+ */
+
+/dts-v1/;
+#include "stm32mp157c.dtsi"
+#include "stm32mp157cad-pinctrl.dtsi"
+
+/* USER CODE BEGIN dts_include */
+/* USER CODE END dts_include */
+
+/ {
+    model = "STMicroelectronics custom STM32CubeMX board";
+	compatible = "st,stm32mp157c-t1000-mini-mx", "st,stm32mp157";
+
+	memory {
+		reg = <0xC0000000 0x20000000>;
+	};
+
+	/* USER CODE BEGIN root_prop */
+	/* USER CODE END root_prop */
+
+    clocks {
+        u-boot,dm-pre-reloc;
+        clk_hsi: clk-hsi {
+            #clock-cells = <0>;
+            compatible = "fixed-clock";
+            clock-frequency = <64000000>;
+            u-boot,dm-pre-reloc;
+        };
+        clk_usbo_48m: ck_usbo_48m {
+            #clock-cells = <0>;
+            compatible = "fixed-clock";
+            clock-frequency = <48000000>;
+            u-boot,dm-pre-reloc;
+        };
+        clk_lse: clk-lse {
+            #clock-cells = <0>;
+            compatible = "fixed-clock";
+            clock-frequency = <32768>;
+            u-boot,dm-pre-reloc;
+        };
+        clk_hse: clk-hse {
+            #clock-cells = <0>;
+            compatible = "fixed-clock";
+            clock-frequency = <24000000>;
+            u-boot,dm-pre-reloc;
+        };
+    };
+	/* USER CODE BEGIN root_subnodes */
+	/* USER CODE END root_subnodes */
+
+	/* USER CODE BEGIN root_board */
+	/* USER CODE END root_board */
+
+	/* USER CODE BEGIN root_platform */
+	/* USER CODE END root_platform */
+
+}; /*root*/
+
+/* USER CODE BEGIN dts_board */
+/* USER CODE END dts_board */
+
+&pinctrl {
+    u-boot,dm-pre-reloc;
+    adc_pins_mx: adc_mx@0 {
+        pins {
+            pinmux = <STM32_PINMUX('A', 0, ANALOG)>, /* ADC1_INP16 */
+                     <STM32_PINMUX('A', 6, ANALOG)>, /* ADC1_INP3 */
+                     <STM32_PINMUX('B', 1, ANALOG)>, /* ADC1_INP5 */
+                     <STM32_PINMUX('F', 11, ANALOG)>; /* ADC1_INP2 */
+        };
+    };
+    eth1_pins_mx: eth1_mx@0 {
+        pins1 {
+            pinmux = <STM32_PINMUX('A', 2, AF11)>, /* ETH1_MDIO */
+                     <STM32_PINMUX('B', 11, AF11)>, /* ETH1_TX_EN */
+                     <STM32_PINMUX('B', 12, AF11)>, /* ETH1_TXD0 */
+                     <STM32_PINMUX('B', 13, AF11)>, /* ETH1_TXD1 */
+                     <STM32_PINMUX('C', 1, AF11)>, /* ETH1_MDC */
+                     <STM32_PINMUX('G', 8, AF2)>; /* ETH1_CLK */
+            bias-disable;
+            drive-push-pull;
+            slew-rate = <3>;
+        };
+        pins2 {
+            pinmux = <STM32_PINMUX('A', 7, AF11)>, /* ETH1_CRS_DV */
+                     <STM32_PINMUX('C', 4, AF11)>, /* ETH1_RXD0 */
+                     <STM32_PINMUX('C', 5, AF11)>; /* ETH1_RXD1 */
+            bias-disable;
+        };
+    };
+    i2c2_pins_mx: i2c2_mx@0 {
+        pins {
+            pinmux = <STM32_PINMUX('D', 7, AF4)>, /* I2C2_SCL */
+                     <STM32_PINMUX('G', 15, AF4)>; /* I2C2_SDA */
+            bias-disable;
+            drive-open-drain;
+            slew-rate = <0>;
+        };
+    };
+    i2c4_pins_mx: i2c4_mx@0 {
+        pins {
+            pinmux = <STM32_PINMUX('B', 7, AF6)>, /* I2C4_SDA */
+                     <STM32_PINMUX('E', 2, AF4)>; /* I2C4_SCL */
+            bias-disable;
+            drive-open-drain;
+            slew-rate = <0>;
+        };
+    };
+    quadspi_pins_mx: quadspi_mx@0 {
+        u-boot,dm-pre-reloc;
+        pins {
+            u-boot,dm-pre-reloc;
+            pinmux = <STM32_PINMUX('B', 6, AF10)>, /* QUADSPI_BK1_NCS */
+                     <STM32_PINMUX('C', 0, AF10)>, /* QUADSPI_BK2_NCS */
+                     <STM32_PINMUX('E', 7, AF10)>, /* QUADSPI_BK2_IO0 */
+                     <STM32_PINMUX('E', 8, AF10)>, /* QUADSPI_BK2_IO1 */
+                     <STM32_PINMUX('E', 9, AF10)>, /* QUADSPI_BK2_IO2 */
+                     <STM32_PINMUX('E', 10, AF10)>, /* QUADSPI_BK2_IO3 */
+                     <STM32_PINMUX('F', 6, AF9)>, /* QUADSPI_BK1_IO3 */
+                     <STM32_PINMUX('F', 7, AF9)>, /* QUADSPI_BK1_IO2 */
+                     <STM32_PINMUX('F', 8, AF10)>, /* QUADSPI_BK1_IO0 */
+                     <STM32_PINMUX('F', 9, AF10)>, /* QUADSPI_BK1_IO1 */
+                     <STM32_PINMUX('F', 10, AF9)>; /* QUADSPI_CLK */
+            bias-disable;
+            drive-push-pull;
+            slew-rate = <3>;
+        };
+    };
+    sdmmc1_pins_mx: sdmmc1_mx@0 {
+        u-boot,dm-pre-reloc;
+        pins {
+            u-boot,dm-pre-reloc;
+            pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
+                     <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
+                     <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
+                     <STM32_PINMUX('C', 11, AF12)>, /* SDMMC1_D3 */
+                     <STM32_PINMUX('C', 12, AF12)>, /* SDMMC1_CK */
+                     <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
+            bias-pull-up;
+            drive-push-pull;
+            slew-rate = <3>;
+        };
+    };
+    spi2_pins_mx: spi2_mx@0 {
+        pins {
+            pinmux = <STM32_PINMUX('A', 9, AF5)>, /* SPI2_SCK */
+                     <STM32_PINMUX('C', 2, AF5)>, /* SPI2_MISO */
+                     <STM32_PINMUX('C', 3, AF5)>; /* SPI2_MOSI */
+            bias-disable;
+            drive-push-pull;
+            slew-rate = <1>;
+        };
+    };
+    tim1_pwm_pins_mx: tim1_pwm_mx@0 {
+        pins {
+            pinmux = <STM32_PINMUX('A', 8, AF1)>, /* TIM1_CH1 */
+                     <STM32_PINMUX('E', 11, AF1)>, /* TIM1_CH2 */
+                     <STM32_PINMUX('E', 13, AF1)>, /* TIM1_CH3 */
+                     <STM32_PINMUX('E', 14, AF1)>; /* TIM1_CH4 */
+            bias-disable;
+            drive-push-pull;
+            slew-rate = <3>;
+        };
+    };
+    uart4_pins_mx: uart4_mx@0 {
+        u-boot,dm-pre-reloc;
+        pins1 {
+            u-boot,dm-pre-reloc;
+            pinmux = <STM32_PINMUX('G', 11, AF6)>; /* UART4_TX */
+            bias-pull-up;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+        pins2 {
+            u-boot,dm-pre-reloc;
+            pinmux = <STM32_PINMUX('B', 2, AF8)>; /* UART4_RX */
+            bias-pull-up;
+        };
+    };
+    usart2_pins_mx: usart2_mx@0 {
+        pins1 {
+            pinmux = <STM32_PINMUX('D', 5, AF7)>; /* USART2_TX */
+            bias-pull-up;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+        pins2 {
+            pinmux = <STM32_PINMUX('D', 3, AF7)>; /* USART2_CTS */
+            bias-pull-down;
+        };
+        pins3 {
+            pinmux = <STM32_PINMUX('D', 4, AF7)>; /* USART2_RTS */
+            bias-pull-down;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+        pins4 {
+            pinmux = <STM32_PINMUX('D', 6, AF7)>; /* USART2_RX */
+            bias-pull-up;
+        };
+    };
+    usb_otg_hs_pins_mx: usb_otg_hs_mx@0 {
+        u-boot,dm-pre-reloc;
+        pins {
+            u-boot,dm-pre-reloc;
+            pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
+        };
+    };
+    adc_sleep_pins_mx: adc_sleep_mx@0 {
+        pins {
+            pinmux = <STM32_PINMUX('A', 0, ANALOG)>, /* ADC1_INP16 */
+                     <STM32_PINMUX('A', 6, ANALOG)>, /* ADC1_INP3 */
+                     <STM32_PINMUX('B', 1, ANALOG)>, /* ADC1_INP5 */
+                     <STM32_PINMUX('F', 11, ANALOG)>; /* ADC1_INP2 */
+        };
+    };
+    eth1_sleep_pins_mx: eth1_sleep_mx@0 {
+        pins1 {
+            pinmux = <STM32_PINMUX('A', 2, AF11)>, /* ETH1_MDIO */
+                     <STM32_PINMUX('B', 11, AF11)>, /* ETH1_TX_EN */
+                     <STM32_PINMUX('B', 12, AF11)>, /* ETH1_TXD0 */
+                     <STM32_PINMUX('B', 13, AF11)>, /* ETH1_TXD1 */
+                     <STM32_PINMUX('C', 1, AF11)>, /* ETH1_MDC */
+                     <STM32_PINMUX('G', 8, AF2)>; /* ETH1_CLK */
+            bias-disable;
+            drive-push-pull;
+            slew-rate = <3>;
+        };
+        pins2 {
+            pinmux = <STM32_PINMUX('A', 7, AF11)>, /* ETH1_CRS_DV */
+                     <STM32_PINMUX('C', 4, AF11)>, /* ETH1_RXD0 */
+                     <STM32_PINMUX('C', 5, AF11)>; /* ETH1_RXD1 */
+            bias-disable;
+        };
+    };
+    i2c2_sleep_pins_mx: i2c2_sleep_mx@0 {
+        pins {
+            pinmux = <STM32_PINMUX('D', 7, AF4)>, /* I2C2_SCL */
+                     <STM32_PINMUX('G', 15, AF4)>; /* I2C2_SDA */
+            bias-disable;
+            drive-open-drain;
+            slew-rate = <0>;
+        };
+    };
+    i2c4_sleep_pins_mx: i2c4_sleep_mx@0 {
+        pins {
+            pinmux = <STM32_PINMUX('B', 7, AF6)>, /* I2C4_SDA */
+                     <STM32_PINMUX('E', 2, AF4)>; /* I2C4_SCL */
+            bias-disable;
+            drive-open-drain;
+            slew-rate = <0>;
+        };
+    };
+    quadspi_sleep_pins_mx: quadspi_sleep_mx@0 {
+        u-boot,dm-pre-reloc;
+        pins {
+            u-boot,dm-pre-reloc;
+            pinmux = <STM32_PINMUX('B', 6, ANALOG)>, /* QUADSPI_BK1_NCS */
+                     <STM32_PINMUX('C', 0, ANALOG)>, /* QUADSPI_BK2_NCS */
+                     <STM32_PINMUX('E', 7, ANALOG)>, /* QUADSPI_BK2_IO0 */
+                     <STM32_PINMUX('E', 8, ANALOG)>, /* QUADSPI_BK2_IO1 */
+                     <STM32_PINMUX('E', 9, ANALOG)>, /* QUADSPI_BK2_IO2 */
+                     <STM32_PINMUX('E', 10, ANALOG)>, /* QUADSPI_BK2_IO3 */
+                     <STM32_PINMUX('F', 6, ANALOG)>, /* QUADSPI_BK1_IO3 */
+                     <STM32_PINMUX('F', 7, ANALOG)>, /* QUADSPI_BK1_IO2 */
+                     <STM32_PINMUX('F', 8, ANALOG)>, /* QUADSPI_BK1_IO0 */
+                     <STM32_PINMUX('F', 9, ANALOG)>, /* QUADSPI_BK1_IO1 */
+                     <STM32_PINMUX('F', 10, ANALOG)>; /* QUADSPI_CLK */
+        };
+    };
+    sdmmc1_sleep_pins_mx: sdmmc1_sleep_mx@0 {
+        u-boot,dm-pre-reloc;
+        pins {
+            u-boot,dm-pre-reloc;
+            pinmux = <STM32_PINMUX('C', 8, ANALOG)>, /* SDMMC1_D0 */
+                     <STM32_PINMUX('C', 9, ANALOG)>, /* SDMMC1_D1 */
+                     <STM32_PINMUX('C', 10, ANALOG)>, /* SDMMC1_D2 */
+                     <STM32_PINMUX('C', 11, ANALOG)>, /* SDMMC1_D3 */
+                     <STM32_PINMUX('C', 12, ANALOG)>, /* SDMMC1_CK */
+                     <STM32_PINMUX('D', 2, ANALOG)>; /* SDMMC1_CMD */
+        };
+    };
+    spi2_sleep_pins_mx: spi2_sleep_mx@0 {
+        pins {
+            pinmux = <STM32_PINMUX('A', 9, AF5)>, /* SPI2_SCK */
+                     <STM32_PINMUX('C', 2, AF5)>, /* SPI2_MISO */
+                     <STM32_PINMUX('C', 3, AF5)>; /* SPI2_MOSI */
+            bias-disable;
+            drive-push-pull;
+            slew-rate = <1>;
+        };
+    };
+    tim1_pwm_sleep_pins_mx: tim1_pwm_sleep_mx@0 {
+        pins {
+            pinmux = <STM32_PINMUX('A', 8, ANALOG)>, /* TIM1_CH1 */
+                     <STM32_PINMUX('E', 11, ANALOG)>, /* TIM1_CH2 */
+                     <STM32_PINMUX('E', 13, ANALOG)>, /* TIM1_CH3 */
+                     <STM32_PINMUX('E', 14, ANALOG)>; /* TIM1_CH4 */
+        };
+    };
+    uart4_sleep_pins_mx: uart4_sleep_mx@0 {
+        u-boot,dm-pre-reloc;
+        pins1 {
+            u-boot,dm-pre-reloc;
+            pinmux = <STM32_PINMUX('G', 11, AF6)>; /* UART4_TX */
+            bias-pull-up;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+        pins2 {
+            u-boot,dm-pre-reloc;
+            pinmux = <STM32_PINMUX('B', 2, AF8)>; /* UART4_RX */
+            bias-pull-up;
+        };
+    };
+    usart2_sleep_pins_mx: usart2_sleep_mx@0 {
+        pins1 {
+            pinmux = <STM32_PINMUX('D', 5, AF7)>; /* USART2_TX */
+            bias-pull-up;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+        pins2 {
+            pinmux = <STM32_PINMUX('D', 3, AF7)>; /* USART2_CTS */
+            bias-pull-down;
+        };
+        pins3 {
+            pinmux = <STM32_PINMUX('D', 4, AF7)>; /* USART2_RTS */
+            bias-pull-down;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+        pins4 {
+            pinmux = <STM32_PINMUX('D', 6, AF7)>; /* USART2_RX */
+            bias-pull-up;
+        };
+    };
+    usb_otg_hs_sleep_pins_mx: usb_otg_hs_sleep_mx@0 {
+        u-boot,dm-pre-reloc;
+        pins {
+            u-boot,dm-pre-reloc;
+            pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
+        };
+    };
+};
+
+&adc {
+    pinctrl-names = "default", "sleep";
+    pinctrl-0 = <&adc_pins_mx>;
+    pinctrl-1 = <&adc_sleep_pins_mx>;
+    status = "okay";
+};
+
+&ethernet0 {
+    pinctrl-names = "default", "sleep";
+    pinctrl-0 = <&eth1_pins_mx>;
+    pinctrl-1 = <&eth1_sleep_pins_mx>;
+    status = "okay";
+};
+
+&i2c2 {
+    pinctrl-names = "default", "sleep";
+    pinctrl-0 = <&i2c2_pins_mx>;
+    pinctrl-1 = <&i2c2_sleep_pins_mx>;
+    status = "okay";
+};
+
+&i2c4 {
+    pinctrl-names = "default", "sleep";
+    pinctrl-0 = <&i2c4_pins_mx>;
+    pinctrl-1 = <&i2c4_sleep_pins_mx>;
+    status = "okay";
+};
+
+&qspi {
+    u-boot,dm-pre-reloc;
+    pinctrl-names = "default", "sleep";
+    pinctrl-0 = <&quadspi_pins_mx>;
+    pinctrl-1 = <&quadspi_sleep_pins_mx>;
+    status = "okay";
+};
+
+&rcc {
+    u-boot,dm-pre-reloc;
+    status = "okay";
+};
+
+&rtc {
+    status = "okay";
+};
+
+&sdmmc1 {
+    u-boot,dm-pre-reloc;
+    pinctrl-names = "default", "sleep";
+    pinctrl-0 = <&sdmmc1_pins_mx>;
+    pinctrl-1 = <&sdmmc1_sleep_pins_mx>;
+    status = "okay";
+};
+
+&spi2 {
+    pinctrl-names = "default", "sleep";
+    pinctrl-0 = <&spi2_pins_mx>;
+    pinctrl-1 = <&spi2_sleep_pins_mx>;
+    status = "okay";
+};
+
+&timers1 {
+    status = "okay";
+
+    pwm{
+        pinctrl-names = "default", "sleep";
+        pinctrl-0 = <&tim1_pwm_pins_mx>;
+        pinctrl-1 = <&tim1_pwm_sleep_pins_mx>;
+        status = "okay";
+    };
+};
+
+&uart4 {
+    u-boot,dm-pre-reloc;
+    pinctrl-names = "default", "sleep";
+    pinctrl-0 = <&uart4_pins_mx>;
+    pinctrl-1 = <&uart4_sleep_pins_mx>;
+    status = "okay";
+};
+
+&usart2 {
+    pinctrl-names = "default", "sleep";
+    pinctrl-0 = <&usart2_pins_mx>;
+    pinctrl-1 = <&usart2_sleep_pins_mx>;
+    status = "okay";
+};
+
+&usbotg_hs {
+    u-boot,dm-pre-reloc;
+    pinctrl-names = "default", "sleep";
+    pinctrl-0 = <&usb_otg_hs_pins_mx>;
+    pinctrl-1 = <&usb_otg_hs_sleep_pins_mx>;
+    status = "okay";
+};
+
+&usbh_ohci {
+    status = "okay";
+};
+
+/* USER CODE BEGIN dts_soc */
+/* USER CODE END dts_soc */
+
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp157c-t1000-mx-u-boot.dtsi b/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp157c-t1000-mx-u-boot.dtsi
new file mode 100644
index 0000000000000000000000000000000000000000..14c615ddc5afcb3ea6e79e161244c0a04ea262cf
--- /dev/null
+++ b/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp157c-t1000-mx-u-boot.dtsi
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier:	GPL-2.0+	BSD-3-Clause
+ *
+ */
+
+#include <dt-bindings/clock/stm32mp1-clksrc.h>
+//#include "stm32mp15-mx.h"
+#include "stm32mp157c-t1000-ddr3-1x4Gb-1066-binG.h"
+
+#include "stm32mp157cad-u-boot.dtsi"
+#include "stm32mp15-ddr.dtsi"
+
+/* USER CODE BEGIN dts_include */
+/* USER CODE END dts_include */
+
+/ {
+
+	/* USER CODE BEGIN root_prop */
+	/* USER CODE END root_prop */
+
+    clocks {
+        u-boot,dm-pre-reloc;
+        clk_hsi: clk-hsi {
+            u-boot,dm-pre-reloc;
+        };
+        clk_usbo_48m: ck_usbo_48m {
+            u-boot,dm-pre-reloc;
+        };
+        clk_lse: clk-lse {
+            st,drive=<LSEDRV_LOWEST>;
+            u-boot,dm-pre-reloc;
+        };
+        clk_hse: clk-hse {
+            u-boot,dm-pre-reloc;
+        };
+    };
+	/* USER CODE BEGIN root_subnodes */
+	/* USER CODE END root_subnodes */
+
+	/* USER CODE BEGIN root_board */
+	/* USER CODE END root_board */
+
+	/* USER CODE BEGIN root_platform */
+	/* USER CODE END root_platform */
+
+}; /*root*/
+
+/* USER CODE BEGIN dts_board */
+/* USER CODE END dts_board */
+
+&gpioa {
+    compatible = "st,stm32-gpio";
+    u-boot,dm-pre-reloc;
+};
+&gpiob {
+    compatible = "st,stm32-gpio";
+    u-boot,dm-pre-reloc;
+};
+&gpioc {
+    compatible = "st,stm32-gpio";
+    u-boot,dm-pre-reloc;
+};
+&gpiod {
+    compatible = "st,stm32-gpio";
+    u-boot,dm-pre-reloc;
+};
+&gpioe {
+    compatible = "st,stm32-gpio";
+    u-boot,dm-pre-reloc;
+};
+&gpiof {
+    compatible = "st,stm32-gpio";
+    u-boot,dm-pre-reloc;
+};
+&gpiog {
+    compatible = "st,stm32-gpio";
+    u-boot,dm-pre-reloc;
+};
+&gpioh {
+    compatible = "st,stm32-gpio";
+    u-boot,dm-pre-reloc;
+};
+&gpioi {
+    compatible = "st,stm32-gpio";
+    u-boot,dm-pre-reloc;
+};
+&gpioj {
+    compatible = "st,stm32-gpio";
+    u-boot,dm-pre-reloc;
+};
+&gpiok {
+    compatible = "st,stm32-gpio";
+    u-boot,dm-pre-reloc;
+};
+&gpioz {
+    compatible = "st,stm32-gpio";
+    u-boot,dm-pre-reloc;
+};
+
+&rcc {
+    u-boot,dm-pre-reloc;
+    st,clksrc = <
+        CLK_MPU_PLL1P
+        CLK_AXI_PLL2P
+        CLK_MCU_PLL3P
+        CLK_PLL12_HSE
+        CLK_PLL3_HSE
+        CLK_PLL4_HSE
+        CLK_RTC_LSE
+        CLK_MCO1_DISABLED
+        CLK_MCO2_DISABLED
+    >;
+    st,clkdiv = <
+        1         /*MPU*/
+        0         /*AXI*/
+        0         /*MCU*/
+        1         /*APB1*/
+        1         /*APB2*/
+        1         /*APB3*/
+        1         /*APB4*/
+        2         /*APB5*/
+        23         /*RTC*/
+        0         /*MCO1*/
+        0         /*MCO2*/
+    >;
+    st,pkcs = <
+        CLK_CKPER_HSE
+        CLK_QSPI_ACLK
+        CLK_ETH_PLL4P
+        CLK_SDMMC12_PLL3R
+        CLK_STGEN_HSE
+        CLK_USBPHY_HSE
+        CLK_SPI2S1_DISABLED
+        CLK_SPI2S23_PLL3Q
+        CLK_SPI45_DISABLED
+        CLK_SPI6_DISABLED
+        CLK_I2C46_HSI
+        CLK_SDMMC3_DISABLED
+        CLK_USBO_USBPHY
+        CLK_ADC_CKPER
+        CLK_CEC_DISABLED
+        CLK_I2C12_HSI
+        CLK_I2C35_DISABLED
+        CLK_UART1_DISABLED
+        CLK_UART24_HSI
+        CLK_UART35_HSI
+        CLK_UART6_HSI
+        CLK_UART78_HSI
+        CLK_SPDIF_DISABLED
+        CLK_FDCAN_HSE
+        CLK_SAI1_DISABLED
+        CLK_SAI2_DISABLED
+        CLK_SAI3_DISABLED
+        CLK_SAI4_DISABLED
+        CLK_LPTIM1_DISABLED
+        CLK_LPTIM23_DISABLED
+        CLK_LPTIM45_DISABLED
+    >;
+    pll1:st,pll@0 {
+        cfg = < 2 80 0 0 0 1>;
+        frac = < 0x800 >;
+        u-boot,dm-pre-reloc;
+    };
+    pll2:st,pll@1 {
+        cfg = < 2 65 1 0 0 5>;
+        frac = < 0x1400 >;
+        u-boot,dm-pre-reloc;
+    };
+    pll3:st,pll@2 {
+        cfg = < 2 97 3 15 7 5>;
+        frac = < 0x9ba >;
+        u-boot,dm-pre-reloc;
+    };
+    pll4:st,pll@3 {
+        cfg = < 5 124 9 9 9 3>;
+        u-boot,dm-pre-reloc;
+    };
+};
+
+/* USER CODE BEGIN dts_soc */
+/* USER CODE END dts_soc */
+
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp157c-t1000-mx.dts b/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp157c-t1000-mx.dts
new file mode 100644
index 0000000000000000000000000000000000000000..41628a65a07c0a6999bf20cb84f7c58deaa8df1e
--- /dev/null
+++ b/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp157c-t1000-mx.dts
@@ -0,0 +1,644 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
+/*
+ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved
+ * Author: STM32CubeMX code generation for STMicroelectronics.
+ */
+
+/dts-v1/;
+#include "stm32mp157c.dtsi"
+#include "stm32mp157cad-pinctrl.dtsi"
+
+/* USER CODE BEGIN dts_include */
+/* USER CODE END dts_include */
+
+/ {
+    model = "STMicroelectronics custom STM32CubeMX board";
+	compatible = "st,stm32mp157c-t1000-mx", "st,stm32mp157";
+
+	memory {
+		reg = <0xC0000000 0x20000000>;
+	};
+
+	/* USER CODE BEGIN root_prop */
+	/* USER CODE END root_prop */
+
+    clocks {
+        u-boot,dm-pre-reloc;
+        clk_hsi: clk-hsi {
+            #clock-cells = <0>;
+            compatible = "fixed-clock";
+            clock-frequency = <64000000>;
+            u-boot,dm-pre-reloc;
+        };
+        clk_usbo_48m: ck_usbo_48m {
+            #clock-cells = <0>;
+            compatible = "fixed-clock";
+            clock-frequency = <48000000>;
+            u-boot,dm-pre-reloc;
+        };
+        clk_lse: clk-lse {
+            #clock-cells = <0>;
+            compatible = "fixed-clock";
+            clock-frequency = <32768>;
+            u-boot,dm-pre-reloc;
+        };
+        clk_hse: clk-hse {
+            #clock-cells = <0>;
+            compatible = "fixed-clock";
+            clock-frequency = <24000000>;
+            u-boot,dm-pre-reloc;
+        };
+    };
+	/* USER CODE BEGIN root_subnodes */
+	/* USER CODE END root_subnodes */
+
+	/* USER CODE BEGIN root_board */
+	/* USER CODE END root_board */
+
+	/* USER CODE BEGIN root_platform */
+	/* USER CODE END root_platform */
+
+}; /*root*/
+
+/* USER CODE BEGIN dts_board */
+/* USER CODE END dts_board */
+
+&pinctrl {
+    u-boot,dm-pre-reloc;
+    adc_pins_mx: adc_mx@0 {
+        pins {
+            pinmux = <STM32_PINMUX('A', 0, ANALOG)>, /* ADC1_INP16 */
+                     <STM32_PINMUX('B', 1, ANALOG)>; /* ADC1_INP5 */
+        };
+    };
+    eth1_pins_mx: eth1_mx@0 {
+        pins1 {
+            pinmux = <STM32_PINMUX('A', 2, AF11)>, /* ETH1_MDIO */
+                     <STM32_PINMUX('B', 11, AF11)>, /* ETH1_TX_EN */
+                     <STM32_PINMUX('B', 12, AF11)>, /* ETH1_TXD0 */
+                     <STM32_PINMUX('B', 13, AF11)>, /* ETH1_TXD1 */
+                     <STM32_PINMUX('C', 1, AF11)>, /* ETH1_MDC */
+                     <STM32_PINMUX('G', 8, AF2)>; /* ETH1_CLK */
+            bias-disable;
+            drive-push-pull;
+            slew-rate = <3>;
+        };
+        pins2 {
+            pinmux = <STM32_PINMUX('A', 7, AF11)>, /* ETH1_CRS_DV */
+                     <STM32_PINMUX('C', 4, AF11)>, /* ETH1_RXD0 */
+                     <STM32_PINMUX('C', 5, AF11)>; /* ETH1_RXD1 */
+            bias-disable;
+        };
+    };
+    fdcan1_pins_mx: fdcan1_mx@0 {
+        pins1 {
+            pinmux = <STM32_PINMUX('D', 1, AF9)>; /* FDCAN1_TX */
+            bias-disable;
+            drive-push-pull;
+            slew-rate = <1>;
+        };
+        pins2 {
+            pinmux = <STM32_PINMUX('D', 0, AF9)>; /* FDCAN1_RX */
+            bias-disable;
+        };
+    };
+    i2c2_pins_mx: i2c2_mx@0 {
+        pins {
+            pinmux = <STM32_PINMUX('D', 7, AF4)>, /* I2C2_SCL */
+                     <STM32_PINMUX('G', 15, AF4)>; /* I2C2_SDA */
+            bias-disable;
+            drive-open-drain;
+            slew-rate = <0>;
+        };
+    };
+    i2c4_pins_mx: i2c4_mx@0 {
+        pins {
+            pinmux = <STM32_PINMUX('B', 7, AF6)>, /* I2C4_SDA */
+                     <STM32_PINMUX('E', 2, AF4)>; /* I2C4_SCL */
+            bias-disable;
+            drive-open-drain;
+            slew-rate = <0>;
+        };
+    };
+    ltdc_pins_mx: ltdc_mx@0 {
+        pins {
+            pinmux = <STM32_PINMUX('A', 1, AF14)>, /* LTDC_R2 */
+                     <STM32_PINMUX('A', 3, AF14)>, /* LTDC_B5 */
+                     <STM32_PINMUX('A', 4, AF14)>, /* LTDC_VSYNC */
+                     <STM32_PINMUX('A', 5, AF14)>, /* LTDC_R4 */
+                     <STM32_PINMUX('A', 6, AF14)>, /* LTDC_G2 */
+                     <STM32_PINMUX('A', 8, AF14)>, /* LTDC_R6 */
+                     <STM32_PINMUX('A', 12, AF14)>, /* LTDC_R5 */
+                     <STM32_PINMUX('B', 0, AF9)>, /* LTDC_R3 */
+                     <STM32_PINMUX('B', 5, AF14)>, /* LTDC_G7 */
+                     <STM32_PINMUX('B', 8, AF14)>, /* LTDC_B6 */
+                     <STM32_PINMUX('B', 9, AF14)>, /* LTDC_B7 */
+                     <STM32_PINMUX('B', 10, AF14)>, /* LTDC_G4 */
+                     <STM32_PINMUX('C', 6, AF14)>, /* LTDC_HSYNC */
+                     <STM32_PINMUX('C', 7, AF14)>, /* LTDC_G6 */
+                     <STM32_PINMUX('D', 10, AF14)>, /* LTDC_B3 */
+                     <STM32_PINMUX('E', 11, AF14)>, /* LTDC_G3 */
+                     <STM32_PINMUX('E', 12, AF14)>, /* LTDC_B4 */
+                     <STM32_PINMUX('E', 13, AF14)>, /* LTDC_DE */
+                     <STM32_PINMUX('E', 14, AF14)>, /* LTDC_CLK */
+                     <STM32_PINMUX('E', 15, AF14)>, /* LTDC_R7 */
+                     <STM32_PINMUX('F', 11, AF14)>, /* LTDC_G5 */
+                     <STM32_PINMUX('G', 10, AF14)>; /* LTDC_B2 */
+            bias-disable;
+            drive-push-pull;
+            slew-rate = <3>;
+        };
+    };
+    quadspi_pins_mx: quadspi_mx@0 {
+        u-boot,dm-pre-reloc;
+        pins {
+            u-boot,dm-pre-reloc;
+            pinmux = <STM32_PINMUX('B', 6, AF10)>, /* QUADSPI_BK1_NCS */
+                     <STM32_PINMUX('C', 0, AF10)>, /* QUADSPI_BK2_NCS */
+                     <STM32_PINMUX('E', 7, AF10)>, /* QUADSPI_BK2_IO0 */
+                     <STM32_PINMUX('E', 8, AF10)>, /* QUADSPI_BK2_IO1 */
+                     <STM32_PINMUX('E', 9, AF10)>, /* QUADSPI_BK2_IO2 */
+                     <STM32_PINMUX('E', 10, AF10)>, /* QUADSPI_BK2_IO3 */
+                     <STM32_PINMUX('F', 6, AF9)>, /* QUADSPI_BK1_IO3 */
+                     <STM32_PINMUX('F', 7, AF9)>, /* QUADSPI_BK1_IO2 */
+                     <STM32_PINMUX('F', 8, AF10)>, /* QUADSPI_BK1_IO0 */
+                     <STM32_PINMUX('F', 9, AF10)>, /* QUADSPI_BK1_IO1 */
+                     <STM32_PINMUX('F', 10, AF9)>; /* QUADSPI_CLK */
+            bias-disable;
+            drive-push-pull;
+            slew-rate = <3>;
+        };
+    };
+    sdmmc1_pins_mx: sdmmc1_mx@0 {
+        u-boot,dm-pre-reloc;
+        pins {
+            u-boot,dm-pre-reloc;
+            pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
+                     <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
+                     <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
+                     <STM32_PINMUX('C', 11, AF12)>, /* SDMMC1_D3 */
+                     <STM32_PINMUX('C', 12, AF12)>, /* SDMMC1_CK */
+                     <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
+            bias-pull-up;
+            drive-push-pull;
+            slew-rate = <3>;
+        };
+    };
+    sdmmc2_pins_mx: sdmmc2_mx@0 {
+        u-boot,dm-pre-reloc;
+        pins {
+            u-boot,dm-pre-reloc;
+            pinmux = <STM32_PINMUX('B', 3, AF9)>, /* SDMMC2_D2 */
+                     <STM32_PINMUX('B', 4, AF9)>, /* SDMMC2_D3 */
+                     <STM32_PINMUX('B', 14, AF9)>, /* SDMMC2_D0 */
+                     <STM32_PINMUX('B', 15, AF9)>, /* SDMMC2_D1 */
+                     <STM32_PINMUX('E', 3, AF9)>, /* SDMMC2_CK */
+                     <STM32_PINMUX('G', 6, AF10)>; /* SDMMC2_CMD */
+            bias-pull-up;
+            drive-push-pull;
+            slew-rate = <3>;
+        };
+    };
+    spi2_pins_mx: spi2_mx@0 {
+        pins {
+            pinmux = <STM32_PINMUX('A', 9, AF5)>, /* SPI2_SCK */
+                     <STM32_PINMUX('C', 2, AF5)>, /* SPI2_MISO */
+                     <STM32_PINMUX('C', 3, AF5)>; /* SPI2_MOSI */
+            bias-disable;
+            drive-push-pull;
+            slew-rate = <1>;
+        };
+    };
+    uart4_pins_mx: uart4_mx@0 {
+        u-boot,dm-pre-reloc;
+        pins1 {
+            u-boot,dm-pre-reloc;
+            pinmux = <STM32_PINMUX('G', 11, AF6)>; /* UART4_TX */
+            bias-disable;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+        pins2 {
+            u-boot,dm-pre-reloc;
+            pinmux = <STM32_PINMUX('B', 2, AF8)>; /* UART4_RX */
+            bias-disable;
+        };
+    };
+    uart8_pins_mx: uart8_mx@0 {
+        pins1 {
+            pinmux = <STM32_PINMUX('E', 1, AF8)>, /* UART8_TX */
+                     <STM32_PINMUX('G', 7, AF8)>; /* UART8_RTS */
+            bias-disable;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+        pins2 {
+            pinmux = <STM32_PINMUX('D', 14, AF8)>, /* UART8_CTS */
+                     <STM32_PINMUX('E', 0, AF8)>; /* UART8_RX */
+            bias-disable;
+        };
+    };
+    usart2_pins_mx: usart2_mx@0 {
+        pins1 {
+            pinmux = <STM32_PINMUX('D', 5, AF7)>; /* USART2_TX */
+            bias-pull-up;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+        pins2 {
+            pinmux = <STM32_PINMUX('D', 3, AF7)>, /* USART2_CTS */
+                     <STM32_PINMUX('D', 6, AF7)>; /* USART2_RX */
+            bias-disable;
+        };
+        pins3 {
+            pinmux = <STM32_PINMUX('D', 4, AF7)>; /* USART2_RTS */
+            bias-disable;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+    };
+    usart3_pins_mx: usart3_mx@0 {
+        pins1 {
+            pinmux = <STM32_PINMUX('D', 8, AF7)>; /* USART3_TX */
+            bias-pull-up;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+        pins2 {
+            pinmux = <STM32_PINMUX('D', 9, AF7)>, /* USART3_RX */
+                     <STM32_PINMUX('D', 11, AF7)>; /* USART3_CTS */
+            bias-disable;
+        };
+        pins3 {
+            pinmux = <STM32_PINMUX('D', 12, AF7)>; /* USART3_RTS */
+            bias-disable;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+    };
+    usart6_pins_mx: usart6_mx@0 {
+        pins1 {
+            pinmux = <STM32_PINMUX('G', 14, AF7)>; /* USART6_TX */
+            bias-pull-up;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+        pins2 {
+            pinmux = <STM32_PINMUX('G', 9, AF7)>; /* USART6_RX */
+            bias-disable;
+        };
+    };
+    usb_otg_hs_pins_mx: usb_otg_hs_mx@0 {
+        u-boot,dm-pre-reloc;
+        pins {
+            u-boot,dm-pre-reloc;
+            pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
+        };
+    };
+    adc_sleep_pins_mx: adc_sleep_mx@0 {
+        pins {
+            pinmux = <STM32_PINMUX('A', 0, ANALOG)>, /* ADC1_INP16 */
+                     <STM32_PINMUX('B', 1, ANALOG)>; /* ADC1_INP5 */
+        };
+    };
+    eth1_sleep_pins_mx: eth1_sleep_mx@0 {
+        pins1 {
+            pinmux = <STM32_PINMUX('A', 2, AF11)>, /* ETH1_MDIO */
+                     <STM32_PINMUX('B', 11, AF11)>, /* ETH1_TX_EN */
+                     <STM32_PINMUX('B', 12, AF11)>, /* ETH1_TXD0 */
+                     <STM32_PINMUX('B', 13, AF11)>, /* ETH1_TXD1 */
+                     <STM32_PINMUX('C', 1, AF11)>, /* ETH1_MDC */
+                     <STM32_PINMUX('G', 8, AF2)>; /* ETH1_CLK */
+            bias-disable;
+            drive-push-pull;
+            slew-rate = <3>;
+        };
+        pins2 {
+            pinmux = <STM32_PINMUX('A', 7, AF11)>, /* ETH1_CRS_DV */
+                     <STM32_PINMUX('C', 4, AF11)>, /* ETH1_RXD0 */
+                     <STM32_PINMUX('C', 5, AF11)>; /* ETH1_RXD1 */
+            bias-disable;
+        };
+    };
+    fdcan1_sleep_pins_mx: fdcan1_sleep_mx@0 {
+        pins {
+            pinmux = <STM32_PINMUX('D', 0, ANALOG)>, /* FDCAN1_RX */
+                     <STM32_PINMUX('D', 1, ANALOG)>; /* FDCAN1_TX */
+        };
+    };
+    i2c2_sleep_pins_mx: i2c2_sleep_mx@0 {
+        pins {
+            pinmux = <STM32_PINMUX('D', 7, AF4)>, /* I2C2_SCL */
+                     <STM32_PINMUX('G', 15, AF4)>; /* I2C2_SDA */
+            bias-disable;
+            drive-open-drain;
+            slew-rate = <0>;
+        };
+    };
+    i2c4_sleep_pins_mx: i2c4_sleep_mx@0 {
+        pins {
+            pinmux = <STM32_PINMUX('B', 7, AF6)>, /* I2C4_SDA */
+                     <STM32_PINMUX('E', 2, AF4)>; /* I2C4_SCL */
+            bias-disable;
+            drive-open-drain;
+            slew-rate = <0>;
+        };
+    };
+    ltdc_sleep_pins_mx: ltdc_sleep_mx@0 {
+        pins {
+            pinmux = <STM32_PINMUX('A', 1, ANALOG)>, /* LTDC_R2 */
+                     <STM32_PINMUX('A', 3, ANALOG)>, /* LTDC_B5 */
+                     <STM32_PINMUX('A', 4, ANALOG)>, /* LTDC_VSYNC */
+                     <STM32_PINMUX('A', 5, ANALOG)>, /* LTDC_R4 */
+                     <STM32_PINMUX('A', 6, ANALOG)>, /* LTDC_G2 */
+                     <STM32_PINMUX('A', 8, ANALOG)>, /* LTDC_R6 */
+                     <STM32_PINMUX('A', 12, ANALOG)>, /* LTDC_R5 */
+                     <STM32_PINMUX('B', 0, ANALOG)>, /* LTDC_R3 */
+                     <STM32_PINMUX('B', 5, ANALOG)>, /* LTDC_G7 */
+                     <STM32_PINMUX('B', 8, ANALOG)>, /* LTDC_B6 */
+                     <STM32_PINMUX('B', 9, ANALOG)>, /* LTDC_B7 */
+                     <STM32_PINMUX('B', 10, ANALOG)>, /* LTDC_G4 */
+                     <STM32_PINMUX('C', 6, ANALOG)>, /* LTDC_HSYNC */
+                     <STM32_PINMUX('C', 7, ANALOG)>, /* LTDC_G6 */
+                     <STM32_PINMUX('D', 10, ANALOG)>, /* LTDC_B3 */
+                     <STM32_PINMUX('E', 11, ANALOG)>, /* LTDC_G3 */
+                     <STM32_PINMUX('E', 12, ANALOG)>, /* LTDC_B4 */
+                     <STM32_PINMUX('E', 13, ANALOG)>, /* LTDC_DE */
+                     <STM32_PINMUX('E', 14, ANALOG)>, /* LTDC_CLK */
+                     <STM32_PINMUX('E', 15, ANALOG)>, /* LTDC_R7 */
+                     <STM32_PINMUX('F', 11, ANALOG)>, /* LTDC_G5 */
+                     <STM32_PINMUX('G', 10, ANALOG)>; /* LTDC_B2 */
+        };
+    };
+    quadspi_sleep_pins_mx: quadspi_sleep_mx@0 {
+        u-boot,dm-pre-reloc;
+        pins {
+            u-boot,dm-pre-reloc;
+            pinmux = <STM32_PINMUX('B', 6, ANALOG)>, /* QUADSPI_BK1_NCS */
+                     <STM32_PINMUX('C', 0, ANALOG)>, /* QUADSPI_BK2_NCS */
+                     <STM32_PINMUX('E', 7, ANALOG)>, /* QUADSPI_BK2_IO0 */
+                     <STM32_PINMUX('E', 8, ANALOG)>, /* QUADSPI_BK2_IO1 */
+                     <STM32_PINMUX('E', 9, ANALOG)>, /* QUADSPI_BK2_IO2 */
+                     <STM32_PINMUX('E', 10, ANALOG)>, /* QUADSPI_BK2_IO3 */
+                     <STM32_PINMUX('F', 6, ANALOG)>, /* QUADSPI_BK1_IO3 */
+                     <STM32_PINMUX('F', 7, ANALOG)>, /* QUADSPI_BK1_IO2 */
+                     <STM32_PINMUX('F', 8, ANALOG)>, /* QUADSPI_BK1_IO0 */
+                     <STM32_PINMUX('F', 9, ANALOG)>, /* QUADSPI_BK1_IO1 */
+                     <STM32_PINMUX('F', 10, ANALOG)>; /* QUADSPI_CLK */
+        };
+    };
+    sdmmc1_sleep_pins_mx: sdmmc1_sleep_mx@0 {
+        u-boot,dm-pre-reloc;
+        pins {
+            u-boot,dm-pre-reloc;
+            pinmux = <STM32_PINMUX('C', 8, ANALOG)>, /* SDMMC1_D0 */
+                     <STM32_PINMUX('C', 9, ANALOG)>, /* SDMMC1_D1 */
+                     <STM32_PINMUX('C', 10, ANALOG)>, /* SDMMC1_D2 */
+                     <STM32_PINMUX('C', 11, ANALOG)>, /* SDMMC1_D3 */
+                     <STM32_PINMUX('C', 12, ANALOG)>, /* SDMMC1_CK */
+                     <STM32_PINMUX('D', 2, ANALOG)>; /* SDMMC1_CMD */
+        };
+    };
+    sdmmc2_sleep_pins_mx: sdmmc2_sleep_mx@0 {
+        u-boot,dm-pre-reloc;
+        pins {
+            u-boot,dm-pre-reloc;
+            pinmux = <STM32_PINMUX('B', 3, ANALOG)>, /* SDMMC2_D2 */
+                     <STM32_PINMUX('B', 4, ANALOG)>, /* SDMMC2_D3 */
+                     <STM32_PINMUX('B', 14, ANALOG)>, /* SDMMC2_D0 */
+                     <STM32_PINMUX('B', 15, ANALOG)>, /* SDMMC2_D1 */
+                     <STM32_PINMUX('E', 3, ANALOG)>, /* SDMMC2_CK */
+                     <STM32_PINMUX('G', 6, ANALOG)>; /* SDMMC2_CMD */
+        };
+    };
+    spi2_sleep_pins_mx: spi2_sleep_mx@0 {
+        pins {
+            pinmux = <STM32_PINMUX('A', 9, AF5)>, /* SPI2_SCK */
+                     <STM32_PINMUX('C', 2, AF5)>, /* SPI2_MISO */
+                     <STM32_PINMUX('C', 3, AF5)>; /* SPI2_MOSI */
+            bias-disable;
+            drive-push-pull;
+            slew-rate = <1>;
+        };
+    };
+    uart4_sleep_pins_mx: uart4_sleep_mx@0 {
+        u-boot,dm-pre-reloc;
+        pins1 {
+            u-boot,dm-pre-reloc;
+            pinmux = <STM32_PINMUX('G', 11, AF6)>; /* UART4_TX */
+            bias-disable;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+        pins2 {
+            u-boot,dm-pre-reloc;
+            pinmux = <STM32_PINMUX('B', 2, AF8)>; /* UART4_RX */
+            bias-disable;
+        };
+    };
+    uart8_sleep_pins_mx: uart8_sleep_mx@0 {
+        pins1 {
+            pinmux = <STM32_PINMUX('E', 1, AF8)>, /* UART8_TX */
+                     <STM32_PINMUX('G', 7, AF8)>; /* UART8_RTS */
+            bias-disable;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+        pins2 {
+            pinmux = <STM32_PINMUX('D', 14, AF8)>, /* UART8_CTS */
+                     <STM32_PINMUX('E', 0, AF8)>; /* UART8_RX */
+            bias-disable;
+        };
+    };
+    usart2_sleep_pins_mx: usart2_sleep_mx@0 {
+        pins1 {
+            pinmux = <STM32_PINMUX('D', 5, AF7)>; /* USART2_TX */
+            bias-pull-up;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+        pins2 {
+            pinmux = <STM32_PINMUX('D', 3, AF7)>, /* USART2_CTS */
+                     <STM32_PINMUX('D', 6, AF7)>; /* USART2_RX */
+            bias-disable;
+        };
+        pins3 {
+            pinmux = <STM32_PINMUX('D', 4, AF7)>; /* USART2_RTS */
+            bias-disable;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+    };
+    usart3_sleep_pins_mx: usart3_sleep_mx@0 {
+        pins1 {
+            pinmux = <STM32_PINMUX('D', 8, AF7)>; /* USART3_TX */
+            bias-pull-up;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+        pins2 {
+            pinmux = <STM32_PINMUX('D', 9, AF7)>, /* USART3_RX */
+                     <STM32_PINMUX('D', 11, AF7)>; /* USART3_CTS */
+            bias-disable;
+        };
+        pins3 {
+            pinmux = <STM32_PINMUX('D', 12, AF7)>; /* USART3_RTS */
+            bias-disable;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+    };
+    usart6_sleep_pins_mx: usart6_sleep_mx@0 {
+        pins1 {
+            pinmux = <STM32_PINMUX('G', 14, AF7)>; /* USART6_TX */
+            bias-pull-up;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+        pins2 {
+            pinmux = <STM32_PINMUX('G', 9, AF7)>; /* USART6_RX */
+            bias-disable;
+        };
+    };
+    usb_otg_hs_sleep_pins_mx: usb_otg_hs_sleep_mx@0 {
+        u-boot,dm-pre-reloc;
+        pins {
+            u-boot,dm-pre-reloc;
+            pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
+        };
+    };
+};
+
+&adc {
+    pinctrl-names = "default", "sleep";
+    pinctrl-0 = <&adc_pins_mx>;
+    pinctrl-1 = <&adc_sleep_pins_mx>;
+    status = "okay";
+};
+
+&ethernet0 {
+    pinctrl-names = "default", "sleep";
+    pinctrl-0 = <&eth1_pins_mx>;
+    pinctrl-1 = <&eth1_sleep_pins_mx>;
+    status = "okay";
+};
+
+&m_can1 {
+    pinctrl-names = "default", "sleep";
+    pinctrl-0 = <&fdcan1_pins_mx>;
+    pinctrl-1 = <&fdcan1_sleep_pins_mx>;
+    status = "okay";
+};
+
+&i2c2 {
+    pinctrl-names = "default", "sleep";
+    pinctrl-0 = <&i2c2_pins_mx>;
+    pinctrl-1 = <&i2c2_sleep_pins_mx>;
+    status = "okay";
+};
+
+&i2c4 {
+    pinctrl-names = "default", "sleep";
+    pinctrl-0 = <&i2c4_pins_mx>;
+    pinctrl-1 = <&i2c4_sleep_pins_mx>;
+    status = "okay";
+};
+
+&ltdc {
+    pinctrl-names = "default", "sleep";
+    pinctrl-0 = <&ltdc_pins_mx>;
+    pinctrl-1 = <&ltdc_sleep_pins_mx>;
+    status = "okay";
+};
+
+&qspi {
+    u-boot,dm-pre-reloc;
+    pinctrl-names = "default", "sleep";
+    pinctrl-0 = <&quadspi_pins_mx>;
+    pinctrl-1 = <&quadspi_sleep_pins_mx>;
+    status = "okay";
+};
+
+&rcc {
+    u-boot,dm-pre-reloc;
+    status = "okay";
+};
+
+&rtc {
+    status = "okay";
+};
+
+&sdmmc1 {
+    u-boot,dm-pre-reloc;
+    pinctrl-names = "default", "sleep";
+    pinctrl-0 = <&sdmmc1_pins_mx>;
+    pinctrl-1 = <&sdmmc1_sleep_pins_mx>;
+    status = "okay";
+};
+
+&sdmmc2 {
+    u-boot,dm-pre-reloc;
+    pinctrl-names = "default", "sleep";
+    pinctrl-0 = <&sdmmc2_pins_mx>;
+    pinctrl-1 = <&sdmmc2_sleep_pins_mx>;
+    status = "okay";
+};
+
+&spi2 {
+    pinctrl-names = "default", "sleep";
+    pinctrl-0 = <&spi2_pins_mx>;
+    pinctrl-1 = <&spi2_sleep_pins_mx>;
+    status = "okay";
+};
+
+&uart4 {
+    u-boot,dm-pre-reloc;
+    pinctrl-names = "default", "sleep";
+    pinctrl-0 = <&uart4_pins_mx>;
+    pinctrl-1 = <&uart4_sleep_pins_mx>;
+    status = "okay";
+};
+
+&uart8 {
+    pinctrl-names = "default", "sleep";
+    pinctrl-0 = <&uart8_pins_mx>;
+    pinctrl-1 = <&uart8_sleep_pins_mx>;
+    status = "okay";
+};
+
+&usart2 {
+    pinctrl-names = "default", "sleep";
+    pinctrl-0 = <&usart2_pins_mx>;
+    pinctrl-1 = <&usart2_sleep_pins_mx>;
+    status = "okay";
+};
+
+&usart3 {
+    pinctrl-names = "default", "sleep";
+    pinctrl-0 = <&usart3_pins_mx>;
+    pinctrl-1 = <&usart3_sleep_pins_mx>;
+    status = "okay";
+};
+
+&usart6 {
+    pinctrl-names = "default", "sleep";
+    pinctrl-0 = <&usart6_pins_mx>;
+    pinctrl-1 = <&usart6_sleep_pins_mx>;
+    status = "okay";
+};
+
+&usbotg_hs {
+    u-boot,dm-pre-reloc;
+    pinctrl-names = "default", "sleep";
+    pinctrl-0 = <&usb_otg_hs_pins_mx>;
+    pinctrl-1 = <&usb_otg_hs_sleep_pins_mx>;
+    status = "okay";
+};
+
+&usbh_ohci {
+    status = "okay";
+};
+
+/* USER CODE BEGIN dts_soc */
+/* USER CODE END dts_soc */
+
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp157c-t1000-s-mx-u-boot.dtsi b/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp157c-t1000-s-mx-u-boot.dtsi
index 0c8c1e8fbbdf9f748f4e21af15210bd5a5bd4491..4df7e488337d59a1f1872e07ef05b265f93548e0 100644
--- a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp157c-t1000-s-mx-u-boot.dtsi
+++ b/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp157c-t1000-s-mx-u-boot.dtsi
@@ -1,52 +1,54 @@
-/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause*/
 /*
- * Copyright (C) 2019, STMicroelectronics - All Rights Reserved
- * Author: STM32CubeMX code generation for STMicroelectronics.
+ * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier:	GPL-2.0+	BSD-3-Clause
+ *
  */
 
 #include <dt-bindings/clock/stm32mp1-clksrc.h>
 #include "stm32mp15-mx.h"
 
-#include "stm32mp157-u-boot.dtsi"
+#include "stm32mp157cad-u-boot.dtsi"
 #include "stm32mp15-ddr.dtsi"
 
-/* USER CODE BEGIN includes */
-/* USER CODE END includes */
+/* USER CODE BEGIN dts_include */
+/* USER CODE END dts_include */
 
 / {
 
-	/* USER CODE BEGIN root */
-	/* USER CODE END root */
+	/* USER CODE BEGIN root_prop */
+	/* USER CODE END root_prop */
 
-clocks {
-    /* USER CODE BEGIN clocks */
-    /* USER CODE END clocks */
-
-    clk_hsi: clk-hsi {
-        /* USER CODE BEGIN clocks */
-        /* USER CODE END clocks */
-        u-boot,dm-pre-reloc;
-    };
-    clk_csi: clk-csi {
-        /* USER CODE BEGIN clocks */
-        /* USER CODE END clocks */
-        u-boot,dm-pre-reloc;
-    };
-    clk_lse: clk-lse {
-        /* USER CODE BEGIN clocks */
-        /* USER CODE END clocks */
-        st,drive=<LSEDRV_MEDIUM_HIGH>;
-        u-boot,dm-pre-reloc;
-    };
-    clk_hse: clk-hse {
-        /* USER CODE BEGIN clocks */
-        /* USER CODE END clocks */
+    clocks {
         u-boot,dm-pre-reloc;
+        clk_hsi: clk-hsi {
+            u-boot,dm-pre-reloc;
+        };
+        clk_usbo_48m: ck_usbo_48m {
+            u-boot,dm-pre-reloc;
+        };
+        clk_lse: clk-lse {
+            st,drive=<LSEDRV_LOWEST>;
+            u-boot,dm-pre-reloc;
+        };
+        clk_hse: clk-hse {
+            u-boot,dm-pre-reloc;
+        };
     };
-};
+	/* USER CODE BEGIN root_subnodes */
+	/* USER CODE END root_subnodes */
+
+	/* USER CODE BEGIN root_board */
+	/* USER CODE END root_board */
+
+	/* USER CODE BEGIN root_platform */
+	/* USER CODE END root_platform */
 
 }; /*root*/
 
+/* USER CODE BEGIN dts_board */
+/* USER CODE END dts_board */
+
 &gpioa {
     compatible = "st,stm32-gpio";
     u-boot,dm-pre-reloc;
@@ -118,7 +120,7 @@ clocks {
         1         /*APB3*/
         1         /*APB4*/
         2         /*APB5*/
-        0         /*RTC*/
+        23         /*RTC*/
         0         /*MCO1*/
         0         /*MCO2*/
     >;
@@ -126,11 +128,11 @@ clocks {
         CLK_CKPER_HSE
         CLK_QSPI_ACLK
         CLK_ETH_PLL4P
-        CLK_SDMMC12_PLL4P
+        CLK_SDMMC12_PLL3R
         CLK_STGEN_HSE
         CLK_USBPHY_HSE
         CLK_SPI2S1_DISABLED
-        CLK_SPI2S23_PLL4P
+        CLK_SPI2S23_PLL3Q
         CLK_SPI45_DISABLED
         CLK_SPI6_DISABLED
         CLK_I2C46_HSI
@@ -141,9 +143,9 @@ clocks {
         CLK_I2C12_HSI
         CLK_I2C35_DISABLED
         CLK_UART1_DISABLED
-        CLK_UART24_PCLK1
+        CLK_UART24_HSI
         CLK_UART35_DISABLED
-        CLK_UART6_PCLK2
+        CLK_UART6_HSI
         CLK_UART78_DISABLED
         CLK_SPDIF_DISABLED
         CLK_FDCAN_HSE
@@ -151,21 +153,23 @@ clocks {
         CLK_SAI2_DISABLED
         CLK_SAI3_DISABLED
         CLK_SAI4_DISABLED
-        CLK_RNG1_CSI
         CLK_LPTIM1_DISABLED
         CLK_LPTIM23_DISABLED
         CLK_LPTIM45_DISABLED
     >;
     pll1:st,pll@0 {
-        cfg = < 2 80 0 1 1 1>;
+        cfg = < 2 80 0 0 0 1>;
+        frac = < 0x800 >;
         u-boot,dm-pre-reloc;
     };
     pll2:st,pll@1 {
-        cfg = < 2 65 1 1 0 7>;
+        cfg = < 2 65 1 0 0 5>;
+        frac = < 0x1400 >;
         u-boot,dm-pre-reloc;
     };
     pll3:st,pll@2 {
-        cfg = < 2 97 3 1 1 1>;
+        cfg = < 2 97 3 15 7 5>;
+        frac = < 0x9ba >;
         u-boot,dm-pre-reloc;
     };
     pll4:st,pll@3 {
@@ -174,76 +178,6 @@ clocks {
     };
 };
 
-&ltdc{
-    u-boot,dm-pre-reloc;
-
-    /* USER CODE BEGIN ltdc */
-    /* USER CODE END ltdc */
-};
-
-&qspi{
-    u-boot,dm-pre-reloc;
-
-    /* USER CODE BEGIN qspi */
-    /* USER CODE END qspi */
-};
-
-&rcc{
-    u-boot,dm-pre-reloc;
-
-    /* USER CODE BEGIN rcc */
-    /* USER CODE END rcc */
-};
-
-&sdmmc1{
-    u-boot,dm-pre-reloc;
-
-    /* USER CODE BEGIN sdmmc1 */
-    /* USER CODE END sdmmc1 */
-};
-
-&sdmmc2{
-    u-boot,dm-pre-reloc;
-
-    /* USER CODE BEGIN sdmmc2 */
-    /* USER CODE END sdmmc2 */
-};
-
-&uart4{
-    u-boot,dm-pre-reloc;
-
-    /* USER CODE BEGIN uart4 */
-    /* USER CODE END uart4 */
-};
-
-&usbotg_hs{
-    u-boot,dm-pre-reloc;
-
-    /* USER CODE BEGIN usbotg_hs */
-    /* USER CODE END usbotg_hs */
-};
-
-&usbphyc{
-    u-boot,dm-pre-reloc;
-
-    /* USER CODE BEGIN usbphyc */
-    /* USER CODE END usbphyc */
-};
-
-&usbphyc_port0{
-    u-boot,dm-pre-reloc;
-
-    /* USER CODE BEGIN usbphyc_port0 */
-    /* USER CODE END usbphyc_port0 */
-};
-
-&usbphyc_port1{
-    u-boot,dm-pre-reloc;
-
-    /* USER CODE BEGIN usbphyc_port1 */
-    /* USER CODE END usbphyc_port1 */
-};
-
-/* USER CODE BEGIN addons */
-/* USER CODE END addons */
+/* USER CODE BEGIN dts_soc */
+/* USER CODE END dts_soc */
 
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp157c-t1000-s-mx.dts b/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp157c-t1000-s-mx.dts
index 7220006aff9f722dc2d63dd3f2b6abebdf80e612..1a5b7de34bc45ff4536f410c0f1c033c653e248a 100644
--- a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp157c-t1000-s-mx.dts
+++ b/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp157c-t1000-s-mx.dts
@@ -1,112 +1,108 @@
 /* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
 /*
- * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
+ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved
  * Author: STM32CubeMX code generation for STMicroelectronics.
  */
 
 /dts-v1/;
 #include "stm32mp157c.dtsi"
-#include "stm32mp157c-m4-srm.dtsi"
 #include "stm32mp157cad-pinctrl.dtsi"
 
-/* USER CODE BEGIN includes */
-/* USER CODE END includes */
+/* USER CODE BEGIN dts_include */
+/* USER CODE END dts_include */
 
 / {
-	model = "STMicroelectronics custom STM32CubeMX board";
+    model = "STMicroelectronics custom STM32CubeMX board";
 	compatible = "st,stm32mp157c-t1000-s-mx", "st,stm32mp157";
 
-    memory@c0000000 {
-        reg = <0xc0000000 0x20000000>;
+	memory {
+		reg = <0xC0000000 0x20000000>;
+	};
 
-        /* USER CODE BEGIN memory */
-        /* USER CODE END memory */
-    };
-
-    reserved-memory {
-        #address-cells = <1>;
-        #size-cells = <1>;
-        ranges;
-
-        /* USER CODE BEGIN reserved-memory */
-        /* USER CODE END reserved-memory */
-
-        gpu_reserved: gpu@dc000000 {
-            reg = <0xdc000000 0x4000000>;
-            no-map;
-        };
-    };
-
-	/* USER CODE BEGIN root */
-	/* USER CODE END root */
+	/* USER CODE BEGIN root_prop */
+	/* USER CODE END root_prop */
 
     clocks {
-        /* USER CODE BEGIN clocks */
-        /* USER CODE END clocks */
-
+        u-boot,dm-pre-reloc;
         clk_hsi: clk-hsi {
+            #clock-cells = <0>;
+            compatible = "fixed-clock";
             clock-frequency = <64000000>;
+            u-boot,dm-pre-reloc;
         };
-        clk_csi: clk-csi {
-            clock-frequency = <4000000>;
+        clk_usbo_48m: ck_usbo_48m {
+            #clock-cells = <0>;
+            compatible = "fixed-clock";
+            clock-frequency = <48000000>;
+            u-boot,dm-pre-reloc;
         };
         clk_lse: clk-lse {
+            #clock-cells = <0>;
+            compatible = "fixed-clock";
             clock-frequency = <32768>;
+            u-boot,dm-pre-reloc;
         };
         clk_hse: clk-hse {
+            #clock-cells = <0>;
+            compatible = "fixed-clock";
             clock-frequency = <24000000>;
+            u-boot,dm-pre-reloc;
         };
     };
+	/* USER CODE BEGIN root_subnodes */
+	/* USER CODE END root_subnodes */
+
+	/* USER CODE BEGIN root_board */
+	/* USER CODE END root_board */
+
+	/* USER CODE BEGIN root_platform */
+	/* USER CODE END root_platform */
 
 }; /*root*/
 
+/* USER CODE BEGIN dts_board */
+/* USER CODE END dts_board */
+
 &pinctrl {
     u-boot,dm-pre-reloc;
-    adc_pins_mx: adc_mx-0 {
+    adc_pins_mx: adc_mx@0 {
         pins {
             pinmux = <STM32_PINMUX('A', 0, ANALOG)>, /* ADC1_INP16 */
                      <STM32_PINMUX('B', 1, ANALOG)>; /* ADC1_INP5 */
         };
     };
-    eth1_pins_mx: eth1_mx-0 {
+    eth1_pins_mx: eth1_mx@0 {
         pins1 {
-            pinmux = <STM32_PINMUX('B', 12, AF11)>, /* ETH1_TXD0 */
+            pinmux = <STM32_PINMUX('A', 2, AF11)>, /* ETH1_MDIO */
+                     <STM32_PINMUX('B', 11, AF11)>, /* ETH1_TX_EN */
+                     <STM32_PINMUX('B', 12, AF11)>, /* ETH1_TXD0 */
                      <STM32_PINMUX('B', 13, AF11)>, /* ETH1_TXD1 */
                      <STM32_PINMUX('C', 1, AF11)>, /* ETH1_MDC */
                      <STM32_PINMUX('G', 8, AF2)>; /* ETH1_CLK */
             bias-disable;
             drive-push-pull;
-            slew-rate = <1>;
+            slew-rate = <3>;
         };
         pins2 {
-            pinmux = <STM32_PINMUX('A', 2, AF11)>; /* ETH1_MDIO */
-            bias-disable;
-            drive-push-pull;
-            slew-rate = <0>;
-        };
-        pins3 {
             pinmux = <STM32_PINMUX('A', 7, AF11)>, /* ETH1_CRS_DV */
                      <STM32_PINMUX('C', 4, AF11)>, /* ETH1_RXD0 */
                      <STM32_PINMUX('C', 5, AF11)>; /* ETH1_RXD1 */
             bias-disable;
         };
-        pins4 {
-            pinmux = <STM32_PINMUX('B', 11, AF11)>; /* ETH1_TX_EN */
-        };
     };
-    fdcan1_pins_mx: fdcan1_mx-0 {
+    fdcan1_pins_mx: fdcan1_mx@0 {
         pins1 {
             pinmux = <STM32_PINMUX('D', 1, AF9)>; /* FDCAN1_TX */
             bias-disable;
             drive-push-pull;
-            slew-rate = <0>;
+            slew-rate = <1>;
         };
         pins2 {
             pinmux = <STM32_PINMUX('D', 0, AF9)>; /* FDCAN1_RX */
             bias-disable;
         };
     };
-    i2c2_pins_mx: i2c2_mx-0 {
+    i2c2_pins_mx: i2c2_mx@0 {
         pins {
             pinmux = <STM32_PINMUX('D', 7, AF4)>, /* I2C2_SCL */
                      <STM32_PINMUX('G', 15, AF4)>; /* I2C2_SDA */
@@ -115,7 +111,7 @@
             slew-rate = <0>;
         };
     };
-    i2c4_pins_mx: i2c4_mx-0 {
+    i2c4_pins_mx: i2c4_mx@0 {
         pins {
             pinmux = <STM32_PINMUX('B', 7, AF6)>, /* I2C4_SDA */
                      <STM32_PINMUX('E', 2, AF4)>; /* I2C4_SCL */
@@ -124,7 +120,7 @@
             slew-rate = <0>;
         };
     };
-    i2s2_pins_mx: i2s2_mx-0 {
+    i2s2_pins_mx: i2s2_mx@0 {
         pins {
             pinmux = <STM32_PINMUX('A', 11, AF5)>, /* I2S2_WS */
                      <STM32_PINMUX('C', 2, AF5)>, /* I2S2_SDI */
@@ -136,10 +132,8 @@
             slew-rate = <1>;
         };
     };
-    ltdc_pins_mx: ltdc_mx-0 {
-        u-boot,dm-pre-reloc;
-        pins1 {
-            u-boot,dm-pre-reloc;
+    ltdc_pins_mx: ltdc_mx@0 {
+        pins {
             pinmux = <STM32_PINMUX('A', 1, AF14)>, /* LTDC_R2 */
                      <STM32_PINMUX('A', 3, AF14)>, /* LTDC_B5 */
                      <STM32_PINMUX('A', 4, AF14)>, /* LTDC_VSYNC */
@@ -147,7 +141,6 @@
                      <STM32_PINMUX('A', 6, AF14)>, /* LTDC_G2 */
                      <STM32_PINMUX('A', 8, AF14)>, /* LTDC_R6 */
                      <STM32_PINMUX('A', 12, AF14)>, /* LTDC_R5 */
-                     <STM32_PINMUX('A', 15, AF14)>, /* LTDC_R1 */
                      <STM32_PINMUX('B', 0, AF9)>, /* LTDC_R3 */
                      <STM32_PINMUX('B', 5, AF14)>, /* LTDC_G7 */
                      <STM32_PINMUX('B', 8, AF14)>, /* LTDC_B6 */
@@ -156,42 +149,25 @@
                      <STM32_PINMUX('C', 6, AF14)>, /* LTDC_HSYNC */
                      <STM32_PINMUX('C', 7, AF14)>, /* LTDC_G6 */
                      <STM32_PINMUX('D', 10, AF14)>, /* LTDC_B3 */
-                     <STM32_PINMUX('E', 4, AF14)>, /* LTDC_B0 */
-                     <STM32_PINMUX('E', 5, AF14)>, /* LTDC_G0 */
-                     <STM32_PINMUX('E', 6, AF14)>, /* LTDC_G1 */
                      <STM32_PINMUX('E', 11, AF14)>, /* LTDC_G3 */
                      <STM32_PINMUX('E', 12, AF14)>, /* LTDC_B4 */
                      <STM32_PINMUX('E', 13, AF14)>, /* LTDC_DE */
+                     <STM32_PINMUX('E', 14, AF14)>, /* LTDC_CLK */
                      <STM32_PINMUX('E', 15, AF14)>, /* LTDC_R7 */
                      <STM32_PINMUX('F', 11, AF14)>, /* LTDC_G5 */
-                     <STM32_PINMUX('G', 10, AF14)>, /* LTDC_B2 */
-                     <STM32_PINMUX('G', 12, AF14)>, /* LTDC_B1 */
-                     <STM32_PINMUX('G', 13, AF14)>; /* LTDC_R0 */
+                     <STM32_PINMUX('G', 10, AF14)>; /* LTDC_B2 */
             bias-disable;
             drive-push-pull;
-            slew-rate = <0>;
-        };
-        pins2 {
-            u-boot,dm-pre-reloc;
-            pinmux = <STM32_PINMUX('E', 14, AF14)>; /* LTDC_CLK */
-            bias-disable;
-            drive-push-pull;
-            slew-rate = <1>;
+            slew-rate = <3>;
         };
     };
-    quadspi_pins_mx: quadspi_mx-0 {
+    quadspi_pins_mx: quadspi_mx@0 {
         u-boot,dm-pre-reloc;
-        pins1 {
+        pins {
             u-boot,dm-pre-reloc;
             pinmux = <STM32_PINMUX('B', 6, AF10)>, /* QUADSPI_BK1_NCS */
-                     <STM32_PINMUX('C', 0, AF10)>; /* QUADSPI_BK2_NCS */
-            bias-pull-up;
-            drive-push-pull;
-            slew-rate = <3>;
-        };
-        pins2 {
-            u-boot,dm-pre-reloc;
-            pinmux = <STM32_PINMUX('E', 7, AF10)>, /* QUADSPI_BK2_IO0 */
+                     <STM32_PINMUX('C', 0, AF10)>, /* QUADSPI_BK2_NCS */
+                     <STM32_PINMUX('E', 7, AF10)>, /* QUADSPI_BK2_IO0 */
                      <STM32_PINMUX('E', 8, AF10)>, /* QUADSPI_BK2_IO1 */
                      <STM32_PINMUX('E', 9, AF10)>, /* QUADSPI_BK2_IO2 */
                      <STM32_PINMUX('E', 10, AF10)>, /* QUADSPI_BK2_IO3 */
@@ -205,65 +181,46 @@
             slew-rate = <3>;
         };
     };
-    sdmmc1_pins_mx: sdmmc1_mx-0 {
+    sdmmc1_pins_mx: sdmmc1_mx@0 {
         u-boot,dm-pre-reloc;
-        pins1 {
+        pins {
             u-boot,dm-pre-reloc;
             pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
                      <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
                      <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
                      <STM32_PINMUX('C', 11, AF12)>, /* SDMMC1_D3 */
+                     <STM32_PINMUX('C', 12, AF12)>, /* SDMMC1_CK */
                      <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
             bias-pull-up;
             drive-push-pull;
-            slew-rate = <1>;
-        };
-        pins2 {
-            u-boot,dm-pre-reloc;
-            pinmux = <STM32_PINMUX('C', 12, AF12)>; /* SDMMC1_CK */
-            bias-pull-up;
-            drive-push-pull;
             slew-rate = <3>;
         };
     };
-    sdmmc2_pins_mx: sdmmc2_mx-0 {
+    sdmmc2_pins_mx: sdmmc2_mx@0 {
         u-boot,dm-pre-reloc;
-        pins1 {
+        pins {
             u-boot,dm-pre-reloc;
             pinmux = <STM32_PINMUX('B', 3, AF9)>, /* SDMMC2_D2 */
                      <STM32_PINMUX('B', 4, AF9)>, /* SDMMC2_D3 */
                      <STM32_PINMUX('B', 14, AF9)>, /* SDMMC2_D0 */
                      <STM32_PINMUX('B', 15, AF9)>, /* SDMMC2_D1 */
+                     <STM32_PINMUX('E', 3, AF9)>, /* SDMMC2_CK */
                      <STM32_PINMUX('G', 6, AF10)>; /* SDMMC2_CMD */
             bias-pull-up;
             drive-push-pull;
-            slew-rate = <1>;
-        };
-        pins2 {
-            u-boot,dm-pre-reloc;
-            pinmux = <STM32_PINMUX('E', 3, AF9)>; /* SDMMC2_CK */
-            bias-pull-up;
-            drive-push-pull;
             slew-rate = <3>;
         };
     };
-    tim1_pwm_pins_mx: tim1_pwm_mx-0 {
+    tim4_pwm_pins_mx: tim4_pwm_mx@0 {
         pins {
-            pinmux = <STM32_PINMUX('A', 9, AF1)>; /* TIM1_CH2 */
+            pinmux = <STM32_PINMUX('D', 12, AF2)>, /* TIM4_CH1 */
+                     <STM32_PINMUX('D', 14, AF2)>; /* TIM4_CH3 */
             bias-disable;
             drive-push-pull;
-            slew-rate = <0>;
+            slew-rate = <2>;
         };
     };
-    tim4_pwm_pins_mx: tim4_pwm_mx-0 {
-        pins {
-            pinmux = <STM32_PINMUX('D', 14, AF2)>; /* TIM4_CH3 */
-            bias-disable;
-            drive-push-pull;
-            slew-rate = <0>;
-        };
-    };
-    uart4_pins_mx: uart4_mx-0 {
+    uart4_pins_mx: uart4_mx@0 {
         u-boot,dm-pre-reloc;
         pins1 {
             u-boot,dm-pre-reloc;
@@ -278,7 +235,7 @@
             bias-pull-up;
         };
     };
-    usart2_pins_mx: usart2_mx-0 {
+    usart2_pins_mx: usart2_mx@0 {
         pins1 {
             pinmux = <STM32_PINMUX('D', 5, AF7)>; /* USART2_TX */
             bias-pull-up;
@@ -296,7 +253,7 @@
             bias-pull-up;
         };
     };
-    usart6_pins_mx: usart6_mx-0 {
+    usart6_pins_mx: usart6_mx@0 {
         pins1 {
             pinmux = <STM32_PINMUX('G', 14, AF7)>; /* USART6_TX */
             bias-pull-up;
@@ -308,51 +265,63 @@
             bias-pull-up;
         };
     };
-    usb_otg_hs_pins_mx: usb_otg_hs_mx-0 {
+    usb_otg_hs_pins_mx: usb_otg_hs_mx@0 {
         u-boot,dm-pre-reloc;
         pins {
             u-boot,dm-pre-reloc;
             pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
         };
     };
-    adc_sleep_pins_mx: adc_sleep_mx-0 {
+    adc_sleep_pins_mx: adc_sleep_mx@0 {
         pins {
             pinmux = <STM32_PINMUX('A', 0, ANALOG)>, /* ADC1_INP16 */
                      <STM32_PINMUX('B', 1, ANALOG)>; /* ADC1_INP5 */
         };
     };
-    eth1_sleep_pins_mx: eth1_sleep_mx-0 {
-        pins {
-            pinmux = <STM32_PINMUX('A', 2, ANALOG)>, /* ETH1_MDIO */
-                     <STM32_PINMUX('A', 7, ANALOG)>, /* ETH1_CRS_DV */
-                     <STM32_PINMUX('B', 11, ANALOG)>, /* ETH1_TX_EN */
-                     <STM32_PINMUX('B', 12, ANALOG)>, /* ETH1_TXD0 */
-                     <STM32_PINMUX('B', 13, ANALOG)>, /* ETH1_TXD1 */
-                     <STM32_PINMUX('C', 1, ANALOG)>, /* ETH1_MDC */
-                     <STM32_PINMUX('C', 4, ANALOG)>, /* ETH1_RXD0 */
-                     <STM32_PINMUX('C', 5, ANALOG)>, /* ETH1_RXD1 */
-                     <STM32_PINMUX('G', 8, ANALOG)>; /* ETH1_CLK */
-        };
-    };
-    fdcan1_sleep_pins_mx: fdcan1_sleep_mx-0 {
+    eth1_sleep_pins_mx: eth1_sleep_mx@0 {
+        pins1 {
+            pinmux = <STM32_PINMUX('A', 2, AF11)>, /* ETH1_MDIO */
+                     <STM32_PINMUX('B', 11, AF11)>, /* ETH1_TX_EN */
+                     <STM32_PINMUX('B', 12, AF11)>, /* ETH1_TXD0 */
+                     <STM32_PINMUX('B', 13, AF11)>, /* ETH1_TXD1 */
+                     <STM32_PINMUX('C', 1, AF11)>, /* ETH1_MDC */
+                     <STM32_PINMUX('G', 8, AF2)>; /* ETH1_CLK */
+            bias-disable;
+            drive-push-pull;
+            slew-rate = <3>;
+        };
+        pins2 {
+            pinmux = <STM32_PINMUX('A', 7, AF11)>, /* ETH1_CRS_DV */
+                     <STM32_PINMUX('C', 4, AF11)>, /* ETH1_RXD0 */
+                     <STM32_PINMUX('C', 5, AF11)>; /* ETH1_RXD1 */
+            bias-disable;
+        };
+    };
+    fdcan1_sleep_pins_mx: fdcan1_sleep_mx@0 {
         pins {
             pinmux = <STM32_PINMUX('D', 0, ANALOG)>, /* FDCAN1_RX */
                      <STM32_PINMUX('D', 1, ANALOG)>; /* FDCAN1_TX */
         };
     };
-    i2c2_sleep_pins_mx: i2c2_sleep_mx-0 {
+    i2c2_sleep_pins_mx: i2c2_sleep_mx@0 {
         pins {
-            pinmux = <STM32_PINMUX('D', 7, ANALOG)>, /* I2C2_SCL */
-                     <STM32_PINMUX('G', 15, ANALOG)>; /* I2C2_SDA */
+            pinmux = <STM32_PINMUX('D', 7, AF4)>, /* I2C2_SCL */
+                     <STM32_PINMUX('G', 15, AF4)>; /* I2C2_SDA */
+            bias-disable;
+            drive-open-drain;
+            slew-rate = <0>;
         };
     };
-    i2c4_sleep_pins_mx: i2c4_sleep_mx-0 {
+    i2c4_sleep_pins_mx: i2c4_sleep_mx@0 {
         pins {
-            pinmux = <STM32_PINMUX('B', 7, ANALOG)>, /* I2C4_SDA */
-                     <STM32_PINMUX('E', 2, ANALOG)>; /* I2C4_SCL */
+            pinmux = <STM32_PINMUX('B', 7, AF6)>, /* I2C4_SDA */
+                     <STM32_PINMUX('E', 2, AF4)>; /* I2C4_SCL */
+            bias-disable;
+            drive-open-drain;
+            slew-rate = <0>;
         };
     };
-    i2s2_sleep_pins_mx: i2s2_sleep_mx-0 {
+    i2s2_sleep_pins_mx: i2s2_sleep_mx@0 {
         pins {
             pinmux = <STM32_PINMUX('A', 11, ANALOG)>, /* I2S2_WS */
                      <STM32_PINMUX('C', 2, ANALOG)>, /* I2S2_SDI */
@@ -361,10 +330,8 @@
                      <STM32_PINMUX('E', 1, ANALOG)>; /* I2S2_MCK */
         };
     };
-    ltdc_sleep_pins_mx: ltdc_sleep_mx-0 {
-        u-boot,dm-pre-reloc;
+    ltdc_sleep_pins_mx: ltdc_sleep_mx@0 {
         pins {
-            u-boot,dm-pre-reloc;
             pinmux = <STM32_PINMUX('A', 1, ANALOG)>, /* LTDC_R2 */
                      <STM32_PINMUX('A', 3, ANALOG)>, /* LTDC_B5 */
                      <STM32_PINMUX('A', 4, ANALOG)>, /* LTDC_VSYNC */
@@ -372,7 +339,6 @@
                      <STM32_PINMUX('A', 6, ANALOG)>, /* LTDC_G2 */
                      <STM32_PINMUX('A', 8, ANALOG)>, /* LTDC_R6 */
                      <STM32_PINMUX('A', 12, ANALOG)>, /* LTDC_R5 */
-                     <STM32_PINMUX('A', 15, ANALOG)>, /* LTDC_R1 */
                      <STM32_PINMUX('B', 0, ANALOG)>, /* LTDC_R3 */
                      <STM32_PINMUX('B', 5, ANALOG)>, /* LTDC_G7 */
                      <STM32_PINMUX('B', 8, ANALOG)>, /* LTDC_B6 */
@@ -381,21 +347,16 @@
                      <STM32_PINMUX('C', 6, ANALOG)>, /* LTDC_HSYNC */
                      <STM32_PINMUX('C', 7, ANALOG)>, /* LTDC_G6 */
                      <STM32_PINMUX('D', 10, ANALOG)>, /* LTDC_B3 */
-                     <STM32_PINMUX('E', 4, ANALOG)>, /* LTDC_B0 */
-                     <STM32_PINMUX('E', 5, ANALOG)>, /* LTDC_G0 */
-                     <STM32_PINMUX('E', 6, ANALOG)>, /* LTDC_G1 */
                      <STM32_PINMUX('E', 11, ANALOG)>, /* LTDC_G3 */
                      <STM32_PINMUX('E', 12, ANALOG)>, /* LTDC_B4 */
                      <STM32_PINMUX('E', 13, ANALOG)>, /* LTDC_DE */
                      <STM32_PINMUX('E', 14, ANALOG)>, /* LTDC_CLK */
                      <STM32_PINMUX('E', 15, ANALOG)>, /* LTDC_R7 */
                      <STM32_PINMUX('F', 11, ANALOG)>, /* LTDC_G5 */
-                     <STM32_PINMUX('G', 10, ANALOG)>, /* LTDC_B2 */
-                     <STM32_PINMUX('G', 12, ANALOG)>, /* LTDC_B1 */
-                     <STM32_PINMUX('G', 13, ANALOG)>; /* LTDC_R0 */
+                     <STM32_PINMUX('G', 10, ANALOG)>; /* LTDC_B2 */
         };
     };
-    quadspi_sleep_pins_mx: quadspi_sleep_mx-0 {
+    quadspi_sleep_pins_mx: quadspi_sleep_mx@0 {
         u-boot,dm-pre-reloc;
         pins {
             u-boot,dm-pre-reloc;
@@ -412,7 +373,7 @@
                      <STM32_PINMUX('F', 10, ANALOG)>; /* QUADSPI_CLK */
         };
     };
-    sdmmc1_sleep_pins_mx: sdmmc1_sleep_mx-0 {
+    sdmmc1_sleep_pins_mx: sdmmc1_sleep_mx@0 {
         u-boot,dm-pre-reloc;
         pins {
             u-boot,dm-pre-reloc;
@@ -424,7 +385,7 @@
                      <STM32_PINMUX('D', 2, ANALOG)>; /* SDMMC1_CMD */
         };
     };
-    sdmmc2_sleep_pins_mx: sdmmc2_sleep_mx-0 {
+    sdmmc2_sleep_pins_mx: sdmmc2_sleep_mx@0 {
         u-boot,dm-pre-reloc;
         pins {
             u-boot,dm-pre-reloc;
@@ -436,38 +397,58 @@
                      <STM32_PINMUX('G', 6, ANALOG)>; /* SDMMC2_CMD */
         };
     };
-    tim1_pwm_sleep_pins_mx: tim1_pwm_sleep_mx-0 {
+    tim4_pwm_sleep_pins_mx: tim4_pwm_sleep_mx@0 {
         pins {
-            pinmux = <STM32_PINMUX('A', 9, ANALOG)>; /* TIM1_CH2 */
+            pinmux = <STM32_PINMUX('D', 12, ANALOG)>, /* TIM4_CH1 */
+                     <STM32_PINMUX('D', 14, ANALOG)>; /* TIM4_CH3 */
         };
     };
-    tim4_pwm_sleep_pins_mx: tim4_pwm_sleep_mx-0 {
-        pins {
-            pinmux = <STM32_PINMUX('D', 14, ANALOG)>; /* TIM4_CH3 */
-        };
-    };
-    uart4_sleep_pins_mx: uart4_sleep_mx-0 {
+    uart4_sleep_pins_mx: uart4_sleep_mx@0 {
         u-boot,dm-pre-reloc;
-        pins {
+        pins1 {
             u-boot,dm-pre-reloc;
-            pinmux = <STM32_PINMUX('B', 2, ANALOG)>, /* UART4_RX */
-                     <STM32_PINMUX('G', 11, ANALOG)>; /* UART4_TX */
+            pinmux = <STM32_PINMUX('G', 11, AF6)>; /* UART4_TX */
+            bias-pull-up;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+        pins2 {
+            u-boot,dm-pre-reloc;
+            pinmux = <STM32_PINMUX('B', 2, AF8)>; /* UART4_RX */
+            bias-pull-up;
         };
     };
-    usart2_sleep_pins_mx: usart2_sleep_mx-0 {
-        pins {
-            pinmux = <STM32_PINMUX('D', 4, ANALOG)>, /* USART2_RTS */
-                     <STM32_PINMUX('D', 5, ANALOG)>, /* USART2_TX */
-                     <STM32_PINMUX('D', 6, ANALOG)>; /* USART2_RX */
+    usart2_sleep_pins_mx: usart2_sleep_mx@0 {
+        pins1 {
+            pinmux = <STM32_PINMUX('D', 5, AF7)>; /* USART2_TX */
+            bias-pull-up;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+        pins2 {
+            pinmux = <STM32_PINMUX('D', 4, AF7)>; /* USART2_RTS */
+            bias-pull-down;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+        pins3 {
+            pinmux = <STM32_PINMUX('D', 6, AF7)>; /* USART2_RX */
+            bias-pull-up;
         };
     };
-    usart6_sleep_pins_mx: usart6_sleep_mx-0 {
-        pins {
-            pinmux = <STM32_PINMUX('G', 9, ANALOG)>, /* USART6_RX */
-                     <STM32_PINMUX('G', 14, ANALOG)>; /* USART6_TX */
+    usart6_sleep_pins_mx: usart6_sleep_mx@0 {
+        pins1 {
+            pinmux = <STM32_PINMUX('G', 14, AF7)>; /* USART6_TX */
+            bias-pull-up;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+        pins2 {
+            pinmux = <STM32_PINMUX('G', 9, AF7)>; /* USART6_RX */
+            bias-pull-up;
         };
     };
-    usb_otg_hs_sleep_pins_mx: usb_otg_hs_sleep_mx-0 {
+    usb_otg_hs_sleep_pins_mx: usb_otg_hs_sleep_mx@0 {
         u-boot,dm-pre-reloc;
         pins {
             u-boot,dm-pre-reloc;
@@ -476,319 +457,133 @@
     };
 };
 
-&m4_rproc{
-    mboxes = <&ipcc 0>, <&ipcc 1>, <&ipcc 2>;
-    mbox-names = "vq0", "vq1", "shutdown";
-    recovery;
-    status = "okay";
-
-    /* USER CODE BEGIN m4_rproc */
-    /* USER CODE END m4_rproc */
-};
-
-&adc{
+&adc {
     pinctrl-names = "default", "sleep";
     pinctrl-0 = <&adc_pins_mx>;
     pinctrl-1 = <&adc_sleep_pins_mx>;
     status = "okay";
-
-    /* USER CODE BEGIN adc */
-    /* USER CODE END adc */
 };
 
-&bsec{
-    status = "okay";
-
-    /* USER CODE BEGIN bsec */
-    /* USER CODE END bsec */
-};
-
-&crc1{
-    status = "okay";
-
-    /* USER CODE BEGIN crc1 */
-    /* USER CODE END crc1 */
-};
-
-&cryp1{
-    status = "okay";
-
-    /* USER CODE BEGIN cryp1 */
-    /* USER CODE END cryp1 */
-};
-
-&dts{
-    status = "okay";
-
-    /* USER CODE BEGIN dts */
-    /* USER CODE END dts */
-};
-
-&ethernet0{
+&ethernet0 {
     pinctrl-names = "default", "sleep";
     pinctrl-0 = <&eth1_pins_mx>;
     pinctrl-1 = <&eth1_sleep_pins_mx>;
     status = "okay";
-
-    /* USER CODE BEGIN ethernet0 */
-    /* USER CODE END ethernet0 */
-};
-
-&gpu{
-    status = "okay";
-
-    /* USER CODE BEGIN gpu */
-    /* USER CODE END gpu */
 };
 
-&hash1{
-    status = "okay";
-
-    /* USER CODE BEGIN hash1 */
-    /* USER CODE END hash1 */
-};
-
-&hsem{
+&m_can1 {
+    pinctrl-names = "default", "sleep";
+    pinctrl-0 = <&fdcan1_pins_mx>;
+    pinctrl-1 = <&fdcan1_sleep_pins_mx>;
     status = "okay";
-
-    /* USER CODE BEGIN hsem */
-    /* USER CODE END hsem */
 };
 
-&i2c2{
+&i2c2 {
     pinctrl-names = "default", "sleep";
     pinctrl-0 = <&i2c2_pins_mx>;
     pinctrl-1 = <&i2c2_sleep_pins_mx>;
     status = "okay";
-
-    /* USER CODE BEGIN i2c2 */
-    /* USER CODE END i2c2 */
 };
 
-&i2c4{
+&i2c4 {
     pinctrl-names = "default", "sleep";
     pinctrl-0 = <&i2c4_pins_mx>;
     pinctrl-1 = <&i2c4_sleep_pins_mx>;
     status = "okay";
-
-    /* USER CODE BEGIN i2c4 */
-    /* USER CODE END i2c4 */
 };
 
-&i2s2{
+&i2s2 {
     pinctrl-names = "default", "sleep";
     pinctrl-0 = <&i2s2_pins_mx>;
     pinctrl-1 = <&i2s2_sleep_pins_mx>;
     status = "okay";
-
-    /* USER CODE BEGIN i2s2 */
-    /* USER CODE END i2s2 */
-};
-
-&ipcc{
-    status = "okay";
-
-    /* USER CODE BEGIN ipcc */
-    /* USER CODE END ipcc */
 };
 
-&ltdc{
-    u-boot,dm-pre-reloc;
+&ltdc {
     pinctrl-names = "default", "sleep";
     pinctrl-0 = <&ltdc_pins_mx>;
     pinctrl-1 = <&ltdc_sleep_pins_mx>;
     status = "okay";
-
-    /* USER CODE BEGIN ltdc */
-    /* USER CODE END ltdc */
 };
 
-&m_can1{
-    pinctrl-names = "default", "sleep";
-    pinctrl-0 = <&fdcan1_pins_mx>;
-    pinctrl-1 = <&fdcan1_sleep_pins_mx>;
-    status = "okay";
-
-    /* USER CODE BEGIN m_can1 */
-    /* USER CODE END m_can1 */
-};
-
-&qspi{
+&qspi {
     u-boot,dm-pre-reloc;
     pinctrl-names = "default", "sleep";
     pinctrl-0 = <&quadspi_pins_mx>;
     pinctrl-1 = <&quadspi_sleep_pins_mx>;
     status = "okay";
-
-    /* USER CODE BEGIN qspi */
-    /* USER CODE END qspi */
 };
 
-&rcc{
+&rcc {
     u-boot,dm-pre-reloc;
     status = "okay";
-
-    /* USER CODE BEGIN rcc */
-    /* USER CODE END rcc */
-};
-
-&rng1{
-    status = "okay";
-
-    /* USER CODE BEGIN rng1 */
-    /* USER CODE END rng1 */
 };
 
-&rtc{
+&rtc {
     status = "okay";
-
-    /* USER CODE BEGIN rtc */
-    /* USER CODE END rtc */
 };
 
-&sdmmc1{
+&sdmmc1 {
     u-boot,dm-pre-reloc;
     pinctrl-names = "default", "sleep";
     pinctrl-0 = <&sdmmc1_pins_mx>;
     pinctrl-1 = <&sdmmc1_sleep_pins_mx>;
     status = "okay";
-
-    /* USER CODE BEGIN sdmmc1 */
-    /* USER CODE END sdmmc1 */
 };
 
-&sdmmc2{
+&sdmmc2 {
     u-boot,dm-pre-reloc;
     pinctrl-names = "default", "sleep";
     pinctrl-0 = <&sdmmc2_pins_mx>;
     pinctrl-1 = <&sdmmc2_sleep_pins_mx>;
     status = "okay";
-
-    /* USER CODE BEGIN sdmmc2 */
-    /* USER CODE END sdmmc2 */
 };
 
-&timers1{
+&timers4 {
     status = "okay";
 
-    /* USER CODE BEGIN timers1 */
-    /* USER CODE END timers1 */
-
-    pwm{
-        pinctrl-names = "default", "sleep";
-        pinctrl-0 = <&tim1_pwm_pins_mx>;
-        pinctrl-1 = <&tim1_pwm_sleep_pins_mx>;
-        status = "okay";
-
-        /* USER CODE BEGIN timers1_pwm */
-        /* USER CODE END timers1_pwm */
-    };
-};
-
-&timers4{
-    status = "okay";
-
-    /* USER CODE BEGIN timers4 */
-    /* USER CODE END timers4 */
-
     pwm{
         pinctrl-names = "default", "sleep";
         pinctrl-0 = <&tim4_pwm_pins_mx>;
         pinctrl-1 = <&tim4_pwm_sleep_pins_mx>;
         status = "okay";
-
-        /* USER CODE BEGIN timers4_pwm */
-        /* USER CODE END timers4_pwm */
     };
 };
 
-&uart4{
+&uart4 {
     u-boot,dm-pre-reloc;
     pinctrl-names = "default", "sleep";
     pinctrl-0 = <&uart4_pins_mx>;
     pinctrl-1 = <&uart4_sleep_pins_mx>;
     status = "okay";
-
-    /* USER CODE BEGIN uart4 */
-    /* USER CODE END uart4 */
 };
 
-&usart2{
+&usart2 {
     pinctrl-names = "default", "sleep";
     pinctrl-0 = <&usart2_pins_mx>;
     pinctrl-1 = <&usart2_sleep_pins_mx>;
     status = "okay";
-
-    /* USER CODE BEGIN usart2 */
-    /* USER CODE END usart2 */
 };
 
-&usart6{
+&usart6 {
     pinctrl-names = "default", "sleep";
     pinctrl-0 = <&usart6_pins_mx>;
     pinctrl-1 = <&usart6_sleep_pins_mx>;
     status = "okay";
-
-    /* USER CODE BEGIN usart6 */
-    /* USER CODE END usart6 */
-};
-
-&usbh_ehci{
-    status = "okay";
-
-    /* USER CODE BEGIN usbh_ehci */
-    /* USER CODE END usbh_ehci */
 };
 
-&usbh_ohci{
-    status = "okay";
-
-    /* USER CODE BEGIN usbh_ohci */
-    /* USER CODE END usbh_ohci */
-};
-
-&usbotg_hs{
+&usbotg_hs {
     u-boot,dm-pre-reloc;
     pinctrl-names = "default", "sleep";
     pinctrl-0 = <&usb_otg_hs_pins_mx>;
     pinctrl-1 = <&usb_otg_hs_sleep_pins_mx>;
     status = "okay";
-
-    /* USER CODE BEGIN usbotg_hs */
-    /* USER CODE END usbotg_hs */
 };
 
-&usbphyc{
-    u-boot,dm-pre-reloc;
+&usbh_ohci {
     status = "okay";
-
-    /* USER CODE BEGIN usbphyc */
-    /* USER CODE END usbphyc */
-};
-
-&usbphyc_port0{
-    u-boot,dm-pre-reloc;
-    status = "okay";
-
-    /* USER CODE BEGIN usbphyc_port0 */
-    /* USER CODE END usbphyc_port0 */
-};
-
-&usbphyc_port1{
-    u-boot,dm-pre-reloc;
-    status = "okay";
-
-    /* USER CODE BEGIN usbphyc_port1 */
-    /* USER CODE END usbphyc_port1 */
-};
-
-&vrefbuf{
-    status = "okay";
-
-    /* USER CODE BEGIN vrefbuf */
-    /* USER CODE END vrefbuf */
 };
 
-/* USER CODE BEGIN addons */
-/* USER CODE END addons */
+/* USER CODE BEGIN dts_soc */
+/* USER CODE END dts_soc */
 
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp157c-t1000-som-minimal-mx-u-boot.dtsi b/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp157c-t1000-som-minimal-mx-u-boot.dtsi
deleted file mode 100644
index 8ebc1c967a6109012d3239173317972792453151..0000000000000000000000000000000000000000
--- a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp157c-t1000-som-minimal-mx-u-boot.dtsi
+++ /dev/null
@@ -1,188 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause*/
-/*
- * Copyright (C) 2019, STMicroelectronics - All Rights Reserved
- * Author: STM32CubeMX code generation for STMicroelectronics.
- */
-
-#include <dt-bindings/clock/stm32mp1-clksrc.h>
-#include "stm32mp15-mx.h"
-
-#include "stm32mp157-u-boot.dtsi"
-#include "stm32mp15-ddr.dtsi"
-
-/* USER CODE BEGIN includes */
-/* USER CODE END includes */
-
-/ {
-
-	/* USER CODE BEGIN root */
-	/* USER CODE END root */
-
-	clocks {
-		/* USER CODE BEGIN clocks */
-		/* USER CODE END clocks */
-
-		clk_hsi: clk-hsi {
-			/* USER CODE BEGIN clocks */
-			/* USER CODE END clocks */
-			u-boot,dm-pre-reloc;
-		};
-
-		clk_csi: clk-csi {
-			/* USER CODE BEGIN clocks */
-			/* USER CODE END clocks */
-			u-boot,dm-pre-reloc;
-		};
-
-		clk_lse: clk-lse {
-			/* USER CODE BEGIN clocks */
-			/* USER CODE END clocks */
-			st,drive=<LSEDRV_MEDIUM_HIGH>;
-			u-boot,dm-pre-reloc;
-		};
-
-		clk_hse: clk-hse {
-			/* USER CODE BEGIN clocks */
-			/* USER CODE END clocks */
-			u-boot,dm-pre-reloc;
-		};
-	};
-
-}; /*root*/
-
-&rcc {
-	u-boot,dm-pre-reloc;
-	st,clksrc = <
-		CLK_MPU_PLL1P
-		CLK_AXI_PLL2P
-		CLK_MCU_PLL3P
-		CLK_PLL12_HSE
-		CLK_PLL3_HSE
-		CLK_PLL4_HSE
-		CLK_RTC_LSE
-		CLK_MCO1_DISABLED
-		CLK_MCO2_DISABLED
-	>;
-	st,clkdiv = <
-		1 		/*MPU*/
-		0 		/*AXI*/
-		0 		/*MCU*/
-		1 		/*APB1*/
-		1 		/*APB2*/
-		1 		/*APB3*/
-		1 		/*APB4*/
-		2 		/*APB5*/
-		0 		/*RTC*/
-		0 		/*MCO1*/
-		0 		/*MCO2*/
-	>;
-	st,pkcs = <
-		CLK_CKPER_HSE
-		CLK_QSPI_ACLK
-		CLK_ETH_PLL4P
-		CLK_SDMMC12_PLL4P
-		CLK_STGEN_HSE
-		CLK_USBPHY_HSE
-		CLK_SPI2S1_DISABLED
-		CLK_SPI2S23_DISABLED
-		CLK_SPI45_DISABLED
-		CLK_SPI6_DISABLED
-		CLK_I2C46_DISABLED
-		CLK_SDMMC3_DISABLED
-		CLK_USBO_USBPHY
-		CLK_ADC_CKPER
-		CLK_CEC_DISABLED
-		CLK_I2C12_HSI
-		CLK_I2C35_DISABLED
-		CLK_UART1_DISABLED
-		CLK_UART24_PCLK1
-		CLK_UART35_DISABLED
-		CLK_UART6_DISABLED
-		CLK_UART78_DISABLED
-		CLK_SPDIF_DISABLED
-		CLK_SAI1_DISABLED
-		CLK_SAI2_DISABLED
-		CLK_SAI3_DISABLED
-		CLK_SAI4_DISABLED
-		CLK_RNG1_CSI
-		CLK_LPTIM1_DISABLED
-		CLK_LPTIM23_DISABLED
-		CLK_LPTIM45_DISABLED
-	>;
-	pll1:st,pll@0 {
-		cfg = < 2 80 0 1 1 1>;
-		u-boot,dm-pre-reloc;
-	};
-	pll2:st,pll@1 {
-		cfg = < 2 65 1 1 0 7>;
-		u-boot,dm-pre-reloc;
-	};
-	pll3:st,pll@2 {
-		cfg = < 1 49 2 2 1 1>;
-		u-boot,dm-pre-reloc;
-	};
-	pll4:st,pll@3 {
-		cfg = < 5 124 9 9 9 1>;
-		u-boot,dm-pre-reloc;
-	};
-};
-
-&qspi{
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN qspi */
-	/* USER CODE END qspi */
-};
-
-&rcc{
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN rcc */
-	/* USER CODE END rcc */
-};
-
-&sdmmc1{
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN sdmmc1 */
-	/* USER CODE END sdmmc1 */
-};
-
-&uart4{
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN uart4 */
-	/* USER CODE END uart4 */
-};
-
-&usbotg_hs{
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN usbotg_hs */
-	/* USER CODE END usbotg_hs */
-};
-
-&usbphyc{
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN usbphyc */
-	/* USER CODE END usbphyc */
-};
-
-&usbphyc_port0{
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN usbphyc_port0 */
-	/* USER CODE END usbphyc_port0 */
-};
-
-&usbphyc_port1{
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN usbphyc_port1 */
-	/* USER CODE END usbphyc_port1 */
-};
-
-/* USER CODE BEGIN addons */
-/* USER CODE END addons */
-
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp157c-t1000-som-minimal-mx.dts b/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp157c-t1000-som-minimal-mx.dts
deleted file mode 100644
index 016425c712e15ca3a2f98af2a2e28aff7f8fa46a..0000000000000000000000000000000000000000
--- a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp157c-t1000-som-minimal-mx.dts
+++ /dev/null
@@ -1,518 +0,0 @@
-/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
-/*
- * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
- * Author: STM32CubeMX code generation for STMicroelectronics.
- */
-
-/dts-v1/;
-#include "stm32mp157c.dtsi"
-#include "stm32mp157c-m4-srm.dtsi"
-#include "stm32mp157cad-pinctrl.dtsi"
-
-/* USER CODE BEGIN includes */
-/* USER CODE END includes */
-
-/ {
-	model = "STMicroelectronics custom STM32CubeMX board";
-	compatible = "st,stm32mp157c-t1000-som-minimal-mx", "st,stm32mp157";
-
-	memory@c0000000 {
-		reg = <0xc0000000 0x20000000>;
-
-		/* USER CODE BEGIN memory */
-		/* USER CODE END memory */
-	};
-
-	reserved-memory {
-		#address-cells = <1>;
-		#size-cells = <1>;
-		ranges;
-
-		/* USER CODE BEGIN reserved-memory */
-		/* USER CODE END reserved-memory */
-
-		gpu_reserved: gpu@dc000000 {
-			reg = <0xdc000000 0x4000000>;
-			no-map;
-		};
-	};
-
-	/* USER CODE BEGIN root */
-	/* USER CODE END root */
-
-	clocks {
-		/* USER CODE BEGIN clocks */
-		/* USER CODE END clocks */
-
-		clk_hsi: clk-hsi {
-			clock-frequency = <64000000>;
-		};
-
-		clk_csi: clk-csi {
-			clock-frequency = <4000000>;
-		};
-
-		clk_lse: clk-lse {
-			clock-frequency = <32768>;
-		};
-
-		clk_hse: clk-hse {
-			clock-frequency = <24000000>;
-		};
-	};
-
-}; /*root*/
-
-&pinctrl {
-	u-boot,dm-pre-reloc;
-
-	eth1_pins_mx: eth1_mx-0 {
-		pins1 {
-			pinmux = <STM32_PINMUX('A', 2, AF11)>; /* ETH1_MDIO */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-		pins2 {
-			pinmux = <STM32_PINMUX('A', 7, AF11)>, /* ETH1_CRS_DV */
-					 <STM32_PINMUX('C', 4, AF11)>, /* ETH1_RXD0 */
-					 <STM32_PINMUX('C', 5, AF11)>; /* ETH1_RXD1 */
-			bias-disable;
-		};
-		pins3 {
-			pinmux = <STM32_PINMUX('B', 11, AF11)>; /* ETH1_TX_EN */
-		};
-		pins4 {
-			pinmux = <STM32_PINMUX('B', 12, AF11)>, /* ETH1_TXD0 */
-					 <STM32_PINMUX('B', 13, AF11)>, /* ETH1_TXD1 */
-					 <STM32_PINMUX('C', 1, AF11)>, /* ETH1_MDC */
-					 <STM32_PINMUX('G', 8, AF2)>; /* ETH1_CLK */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-	};
-
-	eth1_sleep_pins_mx: eth1_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 2, ANALOG)>, /* ETH1_MDIO */
-					 <STM32_PINMUX('A', 7, ANALOG)>, /* ETH1_CRS_DV */
-					 <STM32_PINMUX('B', 11, ANALOG)>, /* ETH1_TX_EN */
-					 <STM32_PINMUX('B', 12, ANALOG)>, /* ETH1_TXD0 */
-					 <STM32_PINMUX('B', 13, ANALOG)>, /* ETH1_TXD1 */
-					 <STM32_PINMUX('C', 1, ANALOG)>, /* ETH1_MDC */
-					 <STM32_PINMUX('C', 4, ANALOG)>, /* ETH1_RXD0 */
-					 <STM32_PINMUX('C', 5, ANALOG)>, /* ETH1_RXD1 */
-					 <STM32_PINMUX('G', 8, ANALOG)>; /* ETH1_CLK */
-		};
-	};
-
-	i2c2_pins_mx: i2c2_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('D', 7, AF4)>, /* I2C2_SCL */
-					 <STM32_PINMUX('G', 15, AF4)>; /* I2C2_SDA */
-			bias-disable;
-			drive-open-drain;
-			slew-rate = <0>;
-		};
-	};
-
-	i2c2_sleep_pins_mx: i2c2_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('D', 7, ANALOG)>, /* I2C2_SCL */
-					 <STM32_PINMUX('G', 15, ANALOG)>; /* I2C2_SDA */
-		};
-	};
-
-	quadspi_pins_mx: quadspi_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 6, AF10)>, /* QUADSPI_BK1_NCS */
-					 <STM32_PINMUX('C', 0, AF10)>; /* QUADSPI_BK2_NCS */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('E', 7, AF10)>, /* QUADSPI_BK2_IO0 */
-					 <STM32_PINMUX('E', 8, AF10)>, /* QUADSPI_BK2_IO1 */
-					 <STM32_PINMUX('E', 9, AF10)>, /* QUADSPI_BK2_IO2 */
-					 <STM32_PINMUX('E', 10, AF10)>, /* QUADSPI_BK2_IO3 */
-					 <STM32_PINMUX('F', 6, AF9)>, /* QUADSPI_BK1_IO3 */
-					 <STM32_PINMUX('F', 7, AF9)>, /* QUADSPI_BK1_IO2 */
-					 <STM32_PINMUX('F', 8, AF10)>, /* QUADSPI_BK1_IO0 */
-					 <STM32_PINMUX('F', 9, AF10)>; /* QUADSPI_BK1_IO1 */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins3 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('F', 10, AF9)>; /* QUADSPI_CLK */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <2>;
-		};
-	};
-
-	quadspi_sleep_pins_mx: quadspi_sleep_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 6, ANALOG)>, /* QUADSPI_BK1_NCS */
-					 <STM32_PINMUX('C', 0, ANALOG)>, /* QUADSPI_BK2_NCS */
-					 <STM32_PINMUX('E', 7, ANALOG)>, /* QUADSPI_BK2_IO0 */
-					 <STM32_PINMUX('E', 8, ANALOG)>, /* QUADSPI_BK2_IO1 */
-					 <STM32_PINMUX('E', 9, ANALOG)>, /* QUADSPI_BK2_IO2 */
-					 <STM32_PINMUX('E', 10, ANALOG)>, /* QUADSPI_BK2_IO3 */
-					 <STM32_PINMUX('F', 6, ANALOG)>, /* QUADSPI_BK1_IO3 */
-					 <STM32_PINMUX('F', 7, ANALOG)>, /* QUADSPI_BK1_IO2 */
-					 <STM32_PINMUX('F', 8, ANALOG)>, /* QUADSPI_BK1_IO0 */
-					 <STM32_PINMUX('F', 9, ANALOG)>, /* QUADSPI_BK1_IO1 */
-					 <STM32_PINMUX('F', 10, ANALOG)>; /* QUADSPI_CLK */
-		};
-	};
-
-	rtc_pins_mx: rtc_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('C', 13, ANALOG)>; /* RTC_LSCO */
-		};
-	};
-
-	rtc_sleep_pins_mx: rtc_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('C', 13, ANALOG)>; /* RTC_LSCO */
-		};
-	};
-
-	sdmmc1_pins_mx: sdmmc1_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
-					 <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
-					 <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
-					 <STM32_PINMUX('C', 11, AF12)>, /* SDMMC1_D3 */
-					 <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 12, AF12)>; /* SDMMC1_CK */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-	};
-
-	sdmmc1_opendrain_pins_mx: sdmmc1_opendrain_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
-					 <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
-					 <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
-					 <STM32_PINMUX('C', 11, AF12)>; /* SDMMC1_D3 */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 12, AF12)>; /* SDMMC1_CK */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins3 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
-			bias-pull-up;
-			drive-open-drain;
-			slew-rate = <1>;
-		};
-	};
-
-	sdmmc1_sleep_pins_mx: sdmmc1_sleep_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 8, ANALOG)>, /* SDMMC1_D0 */
-					 <STM32_PINMUX('C', 9, ANALOG)>, /* SDMMC1_D1 */
-					 <STM32_PINMUX('C', 10, ANALOG)>, /* SDMMC1_D2 */
-					 <STM32_PINMUX('C', 11, ANALOG)>, /* SDMMC1_D3 */
-					 <STM32_PINMUX('C', 12, ANALOG)>, /* SDMMC1_CK */
-					 <STM32_PINMUX('D', 2, ANALOG)>; /* SDMMC1_CMD */
-		};
-	};
-
-	uart4_pins_mx: uart4_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 2, AF8)>; /* UART4_RX */
-			bias-pull-up;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('G', 11, AF6)>; /* UART4_TX */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-	};
-
-	uart4_sleep_pins_mx: uart4_sleep_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 2, ANALOG)>, /* UART4_RX */
-					 <STM32_PINMUX('G', 11, ANALOG)>; /* UART4_TX */
-		};
-	};
-
-	usb_otg_hs_pins_mx: usb_otg_hs_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
-		};
-	};
-
-	usb_otg_hs_sleep_pins_mx: usb_otg_hs_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
-		};
-	};
-
-	/* USER CODE BEGIN pinctrl */
-	/* USER CODE END pinctrl */
-};
-
-&pinctrl_z {
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN pinctrl_z */
-	/* USER CODE END pinctrl_z */
-};
-
-&m4_rproc{
-	mboxes = <&ipcc 0>, <&ipcc 1>, <&ipcc 2>;
-	mbox-names = "vq0", "vq1", "shutdown";
-	recovery;
-	status = "okay";
-
-	/* USER CODE BEGIN m4_rproc */
-	/* USER CODE END m4_rproc */
-};
-
-&adc{
-	status = "okay";
-
-	/* USER CODE BEGIN adc */
-	/* USER CODE END adc */
-};
-
-&bsec{
-	status = "okay";
-
-	/* USER CODE BEGIN bsec */
-	/* USER CODE END bsec */
-};
-
-&crc1{
-	status = "okay";
-
-	/* USER CODE BEGIN crc1 */
-	/* USER CODE END crc1 */
-};
-
-&cryp1{
-	status = "okay";
-
-	/* USER CODE BEGIN cryp1 */
-	/* USER CODE END cryp1 */
-};
-
-&dts{
-	status = "okay";
-
-	/* USER CODE BEGIN dts */
-	/* USER CODE END dts */
-};
-
-&ethernet0{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&eth1_pins_mx>;
-	pinctrl-1 = <&eth1_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN ethernet0 */
-	/* USER CODE END ethernet0 */
-};
-
-&gpu{
-	status = "okay";
-
-	/* USER CODE BEGIN gpu */
-	/* USER CODE END gpu */
-};
-
-&hash1{
-	status = "okay";
-
-	/* USER CODE BEGIN hash1 */
-	/* USER CODE END hash1 */
-};
-
-&hsem{
-	status = "okay";
-
-	/* USER CODE BEGIN hsem */
-	/* USER CODE END hsem */
-};
-
-&i2c2{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&i2c2_pins_mx>;
-	pinctrl-1 = <&i2c2_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN i2c2 */
-	/* USER CODE END i2c2 */
-};
-
-&ipcc{
-	status = "okay";
-
-	/* USER CODE BEGIN ipcc */
-	/* USER CODE END ipcc */
-};
-
-&iwdg2{
-	status = "okay";
-
-	/* USER CODE BEGIN iwdg2 */
-	/* USER CODE END iwdg2 */
-};
-
-&qspi{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&quadspi_pins_mx>;
-	pinctrl-1 = <&quadspi_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN qspi */
-	/* USER CODE END qspi */
-};
-
-&rcc{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN rcc */
-	/* USER CODE END rcc */
-};
-
-&rng1{
-	status = "okay";
-
-	/* USER CODE BEGIN rng1 */
-	/* USER CODE END rng1 */
-};
-
-&rtc{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&rtc_pins_mx>;
-	pinctrl-1 = <&rtc_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN rtc */
-	/* USER CODE END rtc */
-};
-
-&sdmmc1{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "opendrain", "sleep";
-	pinctrl-0 = <&sdmmc1_pins_mx>;
-	pinctrl-1 = <&sdmmc1_opendrain_pins_mx>;
-	pinctrl-2 = <&sdmmc1_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN sdmmc1 */
-	/* USER CODE END sdmmc1 */
-};
-
-&uart4{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&uart4_pins_mx>;
-	pinctrl-1 = <&uart4_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN uart4 */
-	/* USER CODE END uart4 */
-};
-
-&usbh_ehci{
-	status = "okay";
-
-	/* USER CODE BEGIN usbh_ehci */
-	/* USER CODE END usbh_ehci */
-};
-
-&usbh_ohci{
-	status = "okay";
-
-	/* USER CODE BEGIN usbh_ohci */
-	/* USER CODE END usbh_ohci */
-};
-
-&usbotg_hs{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&usb_otg_hs_pins_mx>;
-	pinctrl-1 = <&usb_otg_hs_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN usbotg_hs */
-	/* USER CODE END usbotg_hs */
-};
-
-&usbphyc{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc */
-	/* USER CODE END usbphyc */
-};
-
-&usbphyc_port0{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc_port0 */
-	/* USER CODE END usbphyc_port0 */
-};
-
-&usbphyc_port1{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc_port1 */
-	/* USER CODE END usbphyc_port1 */
-};
-
-&vrefbuf{
-	status = "okay";
-
-	/* USER CODE BEGIN vrefbuf */
-	/* USER CODE END vrefbuf */
-};
-
-/* USER CODE BEGIN addons */
-/* USER CODE END addons */
-
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp157c-t1001-som-minimal-mx-u-boot.dtsi b/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp157c-t1001-som-minimal-mx-u-boot.dtsi
deleted file mode 100644
index 96c8430a24326975c6fe461bda86533452b7973a..0000000000000000000000000000000000000000
--- a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp157c-t1001-som-minimal-mx-u-boot.dtsi
+++ /dev/null
@@ -1,182 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause*/
-/*
- * Copyright (C) 2019, STMicroelectronics - All Rights Reserved
- * Author: STM32CubeMX code generation for STMicroelectronics.
- */
-
-#include <dt-bindings/clock/stm32mp1-clksrc.h>
-#include "stm32mp15-mx.h"
-
-#include "stm32mp157-u-boot.dtsi"
-#include "stm32mp15-ddr.dtsi"
-
-/* USER CODE BEGIN includes */
-/* USER CODE END includes */
-
-/ {
-
-	/* USER CODE BEGIN root */
-	/* USER CODE END root */
-
-	clocks {
-		/* USER CODE BEGIN clocks */
-		/* USER CODE END clocks */
-
-		clk_csi: clk-csi {
-			/* USER CODE BEGIN clocks */
-			/* USER CODE END clocks */
-			u-boot,dm-pre-reloc;
-		};
-
-		clk_lse: clk-lse {
-			/* USER CODE BEGIN clocks */
-			/* USER CODE END clocks */
-			st,drive=<LSEDRV_MEDIUM_HIGH>;
-			u-boot,dm-pre-reloc;
-		};
-
-		clk_hse: clk-hse {
-			/* USER CODE BEGIN clocks */
-			/* USER CODE END clocks */
-			u-boot,dm-pre-reloc;
-		};
-	};
-
-}; /*root*/
-
-&rcc {
-	u-boot,dm-pre-reloc;
-	st,clksrc = <
-		CLK_MPU_PLL1P
-		CLK_AXI_PLL2P
-		CLK_MCU_PLL3P
-		CLK_PLL12_HSE
-		CLK_PLL3_HSE
-		CLK_PLL4_HSE
-		CLK_RTC_LSE
-		CLK_MCO1_DISABLED
-		CLK_MCO2_DISABLED
-	>;
-	st,clkdiv = <
-		1 		/*MPU*/
-		0 		/*AXI*/
-		0 		/*MCU*/
-		1 		/*APB1*/
-		1 		/*APB2*/
-		1 		/*APB3*/
-		1 		/*APB4*/
-		2 		/*APB5*/
-		0 		/*RTC*/
-		0 		/*MCO1*/
-		0 		/*MCO2*/
-	>;
-	st,pkcs = <
-		CLK_CKPER_HSE
-		CLK_QSPI_ACLK
-		CLK_ETH_DISABLED
-		CLK_SDMMC12_PLL4P
-		CLK_STGEN_HSE
-		CLK_USBPHY_HSE
-		CLK_SPI2S1_DISABLED
-		CLK_SPI2S23_DISABLED
-		CLK_SPI45_DISABLED
-		CLK_SPI6_DISABLED
-		CLK_I2C46_DISABLED
-		CLK_SDMMC3_DISABLED
-		CLK_USBO_USBPHY
-		CLK_ADC_CKPER
-		CLK_CEC_DISABLED
-		CLK_I2C12_DISABLED
-		CLK_I2C35_DISABLED
-		CLK_UART1_DISABLED
-		CLK_UART24_PCLK1
-		CLK_UART35_DISABLED
-		CLK_UART6_DISABLED
-		CLK_UART78_DISABLED
-		CLK_SPDIF_DISABLED
-		CLK_SAI1_DISABLED
-		CLK_SAI2_DISABLED
-		CLK_SAI3_DISABLED
-		CLK_SAI4_DISABLED
-		CLK_RNG1_CSI
-		CLK_LPTIM1_DISABLED
-		CLK_LPTIM23_DISABLED
-		CLK_LPTIM45_DISABLED
-	>;
-	pll1:st,pll@0 {
-		cfg = < 2 80 0 1 1 1>;
-		u-boot,dm-pre-reloc;
-	};
-	pll2:st,pll@1 {
-		cfg = < 2 65 1 1 0 7>;
-		u-boot,dm-pre-reloc;
-	};
-	pll3:st,pll@2 {
-		cfg = < 1 49 2 2 1 1>;
-		u-boot,dm-pre-reloc;
-	};
-	pll4:st,pll@3 {
-		cfg = < 5 124 9 9 9 1>;
-		u-boot,dm-pre-reloc;
-	};
-};
-
-&qspi{
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN qspi */
-	/* USER CODE END qspi */
-};
-
-&rcc{
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN rcc */
-	/* USER CODE END rcc */
-};
-
-&sdmmc1{
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN sdmmc1 */
-	/* USER CODE END sdmmc1 */
-};
-
-&uart4{
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN uart4 */
-	/* USER CODE END uart4 */
-};
-
-&usbotg_hs{
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN usbotg_hs */
-	/* USER CODE END usbotg_hs */
-};
-
-&usbphyc{
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN usbphyc */
-	/* USER CODE END usbphyc */
-};
-
-&usbphyc_port0{
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN usbphyc_port0 */
-	/* USER CODE END usbphyc_port0 */
-};
-
-&usbphyc_port1{
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN usbphyc_port1 */
-	/* USER CODE END usbphyc_port1 */
-};
-
-/* USER CODE BEGIN addons */
-/* USER CODE END addons */
-
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp157c-t1001-som-minimal-mx.dts b/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp157c-t1001-som-minimal-mx.dts
deleted file mode 100644
index a7a6c3f479076a30ac6ae7bdc70ceba6f78005f1..0000000000000000000000000000000000000000
--- a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stm32mp157c-t1001-som-minimal-mx.dts
+++ /dev/null
@@ -1,405 +0,0 @@
-/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
-/*
- * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
- * Author: STM32CubeMX code generation for STMicroelectronics.
- */
-
-/dts-v1/;
-#include "stm32mp157c.dtsi"
-#include "stm32mp157c-m4-srm.dtsi"
-#include "stm32mp157cad-pinctrl.dtsi"
-
-/* USER CODE BEGIN includes */
-/* USER CODE END includes */
-
-/ {
-	model = "STMicroelectronics custom STM32CubeMX board";
-	compatible = "st,stm32mp157c-t1001-som-minimal-mx", "st,stm32mp157";
-
-	memory@c0000000 {
-		reg = <0xc0000000 0x20000000>;
-
-		/* USER CODE BEGIN memory */
-		/* USER CODE END memory */
-	};
-
-	reserved-memory {
-		#address-cells = <1>;
-		#size-cells = <1>;
-		ranges;
-
-		/* USER CODE BEGIN reserved-memory */
-		/* USER CODE END reserved-memory */
-
-		gpu_reserved: gpu@dc000000 {
-			reg = <0xdc000000 0x4000000>;
-			no-map;
-		};
-	};
-
-	/* USER CODE BEGIN root */
-	/* USER CODE END root */
-
-	clocks {
-		/* USER CODE BEGIN clocks */
-		/* USER CODE END clocks */
-
-		clk_csi: clk-csi {
-			clock-frequency = <4000000>;
-		};
-
-		clk_lse: clk-lse {
-			clock-frequency = <32768>;
-		};
-
-		clk_hse: clk-hse {
-			clock-frequency = <24000000>;
-		};
-	};
-
-}; /*root*/
-
-&pinctrl {
-	u-boot,dm-pre-reloc;
-
-	quadspi_pins_mx: quadspi_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 6, AF10)>; /* QUADSPI_BK1_NCS */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('F', 6, AF9)>, /* QUADSPI_BK1_IO3 */
-					 <STM32_PINMUX('F', 7, AF9)>, /* QUADSPI_BK1_IO2 */
-					 <STM32_PINMUX('F', 8, AF10)>, /* QUADSPI_BK1_IO0 */
-					 <STM32_PINMUX('F', 9, AF10)>, /* QUADSPI_BK1_IO1 */
-					 <STM32_PINMUX('F', 10, AF9)>; /* QUADSPI_CLK */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-	};
-
-	quadspi_sleep_pins_mx: quadspi_sleep_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 6, ANALOG)>, /* QUADSPI_BK1_NCS */
-					 <STM32_PINMUX('F', 6, ANALOG)>, /* QUADSPI_BK1_IO3 */
-					 <STM32_PINMUX('F', 7, ANALOG)>, /* QUADSPI_BK1_IO2 */
-					 <STM32_PINMUX('F', 8, ANALOG)>, /* QUADSPI_BK1_IO0 */
-					 <STM32_PINMUX('F', 9, ANALOG)>, /* QUADSPI_BK1_IO1 */
-					 <STM32_PINMUX('F', 10, ANALOG)>; /* QUADSPI_CLK */
-		};
-	};
-
-	sdmmc1_pins_mx: sdmmc1_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
-					 <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
-					 <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
-					 <STM32_PINMUX('C', 11, AF12)>, /* SDMMC1_D3 */
-					 <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 12, AF12)>; /* SDMMC1_CK */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-	};
-
-	sdmmc1_opendrain_pins_mx: sdmmc1_opendrain_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
-					 <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
-					 <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
-					 <STM32_PINMUX('C', 11, AF12)>; /* SDMMC1_D3 */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 12, AF12)>; /* SDMMC1_CK */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins3 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
-			bias-pull-up;
-			drive-open-drain;
-			slew-rate = <1>;
-		};
-	};
-
-	sdmmc1_sleep_pins_mx: sdmmc1_sleep_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 8, ANALOG)>, /* SDMMC1_D0 */
-					 <STM32_PINMUX('C', 9, ANALOG)>, /* SDMMC1_D1 */
-					 <STM32_PINMUX('C', 10, ANALOG)>, /* SDMMC1_D2 */
-					 <STM32_PINMUX('C', 11, ANALOG)>, /* SDMMC1_D3 */
-					 <STM32_PINMUX('C', 12, ANALOG)>, /* SDMMC1_CK */
-					 <STM32_PINMUX('D', 2, ANALOG)>; /* SDMMC1_CMD */
-		};
-	};
-
-	uart4_pins_mx: uart4_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 2, AF8)>; /* UART4_RX */
-			bias-pull-up;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('G', 11, AF6)>; /* UART4_TX */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-	};
-
-	uart4_sleep_pins_mx: uart4_sleep_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 2, ANALOG)>, /* UART4_RX */
-					 <STM32_PINMUX('G', 11, ANALOG)>; /* UART4_TX */
-		};
-	};
-
-	usb_otg_hs_pins_mx: usb_otg_hs_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
-		};
-	};
-
-	usb_otg_hs_sleep_pins_mx: usb_otg_hs_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
-		};
-	};
-
-	/* USER CODE BEGIN pinctrl */
-	/* USER CODE END pinctrl */
-};
-
-&pinctrl_z {
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN pinctrl_z */
-	/* USER CODE END pinctrl_z */
-};
-
-&m4_rproc{
-	mboxes = <&ipcc 0>, <&ipcc 1>, <&ipcc 2>;
-	mbox-names = "vq0", "vq1", "shutdown";
-	recovery;
-	status = "okay";
-
-	/* USER CODE BEGIN m4_rproc */
-	/* USER CODE END m4_rproc */
-};
-
-&adc{
-	status = "okay";
-
-	/* USER CODE BEGIN adc */
-	/* USER CODE END adc */
-};
-
-&bsec{
-	status = "okay";
-
-	/* USER CODE BEGIN bsec */
-	/* USER CODE END bsec */
-};
-
-&crc1{
-	status = "okay";
-
-	/* USER CODE BEGIN crc1 */
-	/* USER CODE END crc1 */
-};
-
-&cryp1{
-	status = "okay";
-
-	/* USER CODE BEGIN cryp1 */
-	/* USER CODE END cryp1 */
-};
-
-&dts{
-	status = "okay";
-
-	/* USER CODE BEGIN dts */
-	/* USER CODE END dts */
-};
-
-&gpu{
-	status = "okay";
-
-	/* USER CODE BEGIN gpu */
-	/* USER CODE END gpu */
-};
-
-&hash1{
-	status = "okay";
-
-	/* USER CODE BEGIN hash1 */
-	/* USER CODE END hash1 */
-};
-
-&hsem{
-	status = "okay";
-
-	/* USER CODE BEGIN hsem */
-	/* USER CODE END hsem */
-};
-
-&ipcc{
-	status = "okay";
-
-	/* USER CODE BEGIN ipcc */
-	/* USER CODE END ipcc */
-};
-
-&iwdg2{
-	status = "okay";
-
-	/* USER CODE BEGIN iwdg2 */
-	/* USER CODE END iwdg2 */
-};
-
-&qspi{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&quadspi_pins_mx>;
-	pinctrl-1 = <&quadspi_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN qspi */
-	/* USER CODE END qspi */
-};
-
-&rcc{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN rcc */
-	/* USER CODE END rcc */
-};
-
-&rng1{
-	status = "okay";
-
-	/* USER CODE BEGIN rng1 */
-	/* USER CODE END rng1 */
-};
-
-&rtc{
-	status = "okay";
-
-	/* USER CODE BEGIN rtc */
-	/* USER CODE END rtc */
-};
-
-&sdmmc1{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "opendrain", "sleep";
-	pinctrl-0 = <&sdmmc1_pins_mx>;
-	pinctrl-1 = <&sdmmc1_opendrain_pins_mx>;
-	pinctrl-2 = <&sdmmc1_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN sdmmc1 */
-	/* USER CODE END sdmmc1 */
-};
-
-&uart4{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&uart4_pins_mx>;
-	pinctrl-1 = <&uart4_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN uart4 */
-	/* USER CODE END uart4 */
-};
-
-&usbh_ehci{
-	status = "okay";
-
-	/* USER CODE BEGIN usbh_ehci */
-	/* USER CODE END usbh_ehci */
-};
-
-&usbh_ohci{
-	status = "okay";
-
-	/* USER CODE BEGIN usbh_ohci */
-	/* USER CODE END usbh_ohci */
-};
-
-&usbotg_hs{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&usb_otg_hs_pins_mx>;
-	pinctrl-1 = <&usb_otg_hs_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN usbotg_hs */
-	/* USER CODE END usbotg_hs */
-};
-
-&usbphyc{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc */
-	/* USER CODE END usbphyc */
-};
-
-&usbphyc_port0{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc_port0 */
-	/* USER CODE END usbphyc_port0 */
-};
-
-&usbphyc_port1{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc_port1 */
-	/* USER CODE END usbphyc_port1 */
-};
-
-&vrefbuf{
-	status = "okay";
-
-	/* USER CODE BEGIN vrefbuf */
-	/* USER CODE END vrefbuf */
-};
-
-/* USER CODE BEGIN addons */
-/* USER CODE END addons */
-
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stmxceet-mp157-som-u-boot.dtsi b/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stmxceet-mp157-som-u-boot.dtsi
new file mode 100644
index 0000000000000000000000000000000000000000..9f31f482c51275ed7f9ef453a6781034aae15074
--- /dev/null
+++ b/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stmxceet-mp157-som-u-boot.dtsi
@@ -0,0 +1,58 @@
+/* u-boot devicetree for device
+ *
+ * device   : stmxceet-mp157-som
+ * revision : prototype
+ *
+ * Copyright (c) 2018 exceet electronics GmbH
+ */
+
+#include "stm32mp157c-t1000-mx-u-boot.dtsi"
+
+/ {
+	compatible = "ex,stmxceet-mp157-som", "st,stm32mp157";
+	model = "stmxceet-mp157-som (u-boot)";
+};
+
+/* Additional gpio settings required in u-boot: pinctrl settings for led */
+&leds {
+	pinctrl-names = "default";
+	pinctrl-0 = < &led_gpios >;
+};
+&pinctrl {
+    led_gpios: led_gpios@0 {
+        u-boot,dm-pre-reloc;
+        pins1 {
+            pinmux = <STM32_PINMUX('A', 13, GPIO)>, /* LED0 */
+                     <STM32_PINMUX('A', 14, GPIO)>; /* LED1 */
+            bias-pull-down;
+            //bias-pull-up; /* leds are glowing in u-boot */
+            drive-push-pull;
+        };
+    };
+};
+
+
+&ethernet0 {
+	/* add missing MAC clock */
+	markerflag-patched-clock;
+
+	clock-names = "stmmaceth",
+		      "mac-clk-tx",
+		      "mac-clk-rx",
+		      "ethstp",
+		      "syscfg-clk",
+			  "mac-clk-ck";
+	clocks = <&rcc ETHMAC>,
+		 <&rcc ETHTX>,
+		 <&rcc ETHRX>,
+		 <&rcc ETHSTP>,
+		 <&rcc SYSCFG>,
+		 <&rcc ETHCK>;
+
+	/* use old mechanism - kernel has already new mechanism */
+	ex,provide-phy-clk; // provide 50MHz clock for phy
+};
+
+&usbotg_hs {
+	g-tx-fifo-size = <576>;
+};
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stmxceet-mp157-som.dts b/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stmxceet-mp157-som.dts
new file mode 100644
index 0000000000000000000000000000000000000000..938725c07dcbc09694aecfaa6fea412a2af0565e
--- /dev/null
+++ b/recipes-bsp/u-boot/u-boot-stm32mp/arch/arm/dts/stmxceet-mp157-som.dts
@@ -0,0 +1,421 @@
+/* u-boot devicetree for device
+ *
+ * device   : stmxceet-mp157-som
+ * revision : prototype
+ *
+ * Copyright (c) 2018 exceet electronics GmbH
+ */
+
+#include <dt-bindings/gpio/gpio.h>
+#include "stm32mp157c-t1000-mx.dts"
+
+/ {
+	model = "stmxceet-mp157-som (linux)";
+	compatible = "ex,stmxceet-mp157-som", "st,stm32mp157";
+
+	chosen {
+		bootargs = "earlyprintk console=ttyS3,115200 root=/dev/ram";
+		stdout-path = "serial3:115200n8";
+	};
+
+	aliases {
+		ethernet0 = "/soc/ethernet@5800a000";
+		i2c1 = "/soc/i2c@40013000";
+		i2c2 = "/soc/i2c@5c002000";
+		mmc0 = "/soc/sdmmc@58005000";
+		mmc1 = "/soc/sdmmc@58007000";
+		spi0 = "/soc/qspi@58003000";
+	};
+
+	config {
+		/* u-boot led configuration */
+		u-boot,dm-pre-reloc;
+		u-boot,red-led = "stm32mp:red:status";
+		u-boot,green-led = "stm32mp:green:user";
+	};
+
+	leds:led {
+		compatible = "gpio-leds";
+		status = "okay";
+		red {
+			label = "stm32mp:red:status";
+			gpios = <&gpioa 13 GPIO_ACTIVE_LOW>;
+			default-state = "off";
+			linux,default-trigger = "heartbeat";
+			status = "okay";
+		};
+		green {
+			label = "stm32mp:green:user";
+			gpios = <&gpioa 14 GPIO_ACTIVE_LOW>;
+			default-state = "off";
+			linux,default-trigger = "heartbeat";
+			status = "okay";
+		};
+	};
+
+    /* Regulators */
+	vddcore: regulator-vddcore {
+		compatible = "regulator-fixed";
+		regulator-name = "vddcore";
+		regulator-min-microvolt = <1200000>;
+		regulator-max-microvolt = <1200000>;
+		regulator-always-on;
+	};
+
+	vdd_ddr: regulator-vdd_ddr {
+		compatible = "regulator-fixed";
+		regulator-name = "vdd_ddr";
+		regulator-min-microvolt = <1350000>;
+		regulator-max-microvolt = <1350000>;
+		regulator-always-on;
+	};
+
+	vdd_usb: regulator-vdd_usb {
+		compatible = "regulator-fixed";
+		regulator-name = "vdd_usb";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-always-on;
+	};
+
+	vdd: regulator-vdd {
+		compatible = "regulator-fixed";
+		regulator-name = "vdd";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-always-on;
+	};
+
+	v3v3: regulator-v3v3 {
+		compatible = "regulator-fixed";
+		regulator-name = "v3v3";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-always-on;
+	};
+
+	vdd_sd: regulator-vdd_sd {
+		compatible = "regulator-fixed";
+		regulator-name = "vdd_sd";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-always-on;
+	};
+
+	/* Analog reference voltage - may be adapted to board */
+	vdda: regulator-vdda {
+		compatible = "regulator-fixed";
+		regulator-name = "vdda";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-always-on;
+	};
+
+	/* Set reset_out to low */
+	reset_out: regulator-reset_out {
+		compatible = "regulator-fixed";
+		regulator-name = "reset_out";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		gpio = <&gpiod 15 GPIO_ACTIVE_HIGH>;
+		regulator-always-on;
+		regulator-boot-on;
+	};
+
+	/* Memory reservations */
+	reserved-memory {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		ipc_share: sram_rproc@10040000 {
+			compatible = "shared-dma-pool";
+			reg = <0x10040000 0x10000>;
+			no-map;
+		};
+
+		dma1_reserved: sram_dma1@10050000 {
+			reg = <0x10050000 0x8000>;
+			no-map;
+		};
+
+		dma2_reserved: sram_dma2@10058000 {
+			reg = <0x10058000 0x8000>;
+			no-map;
+		};
+
+		gcnano_reserved: gpu@f8000000 {
+			/* 128MB reserved for GPU (min 32MB, max 192MB) */
+			reg = <0xf8000000 0x8000000>;
+			no-map;
+		};
+	};
+
+};
+
+/* DEBUG: Disable reboot - REMOVE when not needed any more */
+//&rcc_reboot {
+//	mask = <0x0>;
+//	attention_patched;
+//};
+
+/* internal rtc */
+&rtc {
+	status = "okay";
+};
+
+
+/* i2c interfaces */
+&i2c2 {
+	clock-frequency = <400000>;
+	status = "okay";
+
+	gpio_exp:gpio_exp@20 {
+		compatible = "ti,tca6408";
+		reg = <0x20>;
+		gpio-controller;
+		#gpio-cells = <2>;
+	};
+};
+
+&i2c4 {
+	clock-frequency = <100000>;
+	status = "okay";
+};
+
+
+/* spi interfaces */
+&spi2 {
+	cs-gpios = <&gpioa 11 GPIO_ACTIVE_HIGH>;
+	status = "okay";
+};
+
+
+/* ADC settings */
+&adc {
+	/* ADC_INP5 is fast, ADC_INP16 is slow channel */
+
+	/* Use internal reference voltage */
+	/* vref-supply = <&vrefbuf>; */
+
+	/* Use external reference voltage */
+	vref-supply = <&vdda>;
+	status = "okay";
+
+
+	adc1: adc@0 {
+		st,adc-channels = <5 16>;
+		/* 16.5 ck_cycles sampling time */
+		st,min-sample-time-nsecs = <400>;
+		status = "okay";
+	};
+
+	jadc1: jadc@0 {
+		st,adc-channels = <5 16>;
+		/* 16.5 ck_cycles sampling time */
+		st,min-sample-time-nsecs = <400>;
+		status = "okay";
+	};
+
+	adc2: adc@100 {
+		status = "okay";
+	};
+
+	adc_temp: temp {
+		/* temperature sensor on adc2 */
+		status = "okay";
+	};
+
+};
+
+
+/* ethernet interface */
+&ethernet0 {
+	status = "okay";
+
+	phy-mode = "rmii";
+	max-speed = <100>;
+	phy-handle = <&phy0>;
+	st,int-phyclk;	/* Use internal clock for PHY (clocktree in tf-a must match) */
+
+	/* clock eth-ck is missing in ST SOC description. Here it is fixed.
+	 * Should be removed if ST definition is fixed (Beta1) */
+	clock-names = "stmmaceth",
+		      "mac-clk-tx",
+		      "mac-clk-rx",
+		      "ethstp",
+		      "syscfg-clk",
+			  "eth-ck";
+
+	clocks = <&rcc ETHMAC>,
+		 <&rcc ETHTX>,
+		 <&rcc ETHRX>,
+		 <&rcc ETHSTP>,
+		 <&rcc SYSCFG>,
+		 <&rcc ETHCK_K>;
+
+	mdio0 {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		compatible = "snps,dwmac-mdio";
+		phy0: ethernet-phy@1 {
+			reg = <1>;
+			/* Feature of Micrel PHY: set PHY config for 25MHz/50MHz
+			 * dependend on 'rmii-ref' clock */
+			clock-names = "rmii-ref";
+			clocks = <&rcc ETHCK_K>;
+		};
+	};
+};
+
+
+/* sd/mmc interfaces */
+&sdmmc1 {
+	broken-cd;
+	//cd-gpios = <&gpioa 10 GPIO_ACTIVE_HIGH>;
+	st,dirpol;
+	st,negedge;
+	no-1-8-v;
+	bus-width = <4>;
+	vmmc-supply = <&vdd_sd>;
+	status = "okay";
+};
+
+&sdmmc2 {
+	non-removable;
+	no-sd;
+	no-sdio;
+	st,dirpol;
+	st,negedge;
+	bus-width = <4>;
+	vmmc-supply = <&v3v3>;
+	status = "disabled";
+};
+
+
+/* qspi interface */
+&qspi {
+	#address-cells = <1>;
+	#size-cells = <0>;
+	status = "okay";
+
+	flash0: mx25r1635f@0 {
+		u-boot,dm-pre-reloc;
+		compatible = "spi-flash", "jedec,spi-nor";
+		reg = <0>;
+		spi-rx-bus-width = <4>;
+		spi-tx-bus-width = <4>;
+		spi-max-frequency = <8000000>; /* MX25R1635F is slow */
+
+		/* required for partitions when mtdparts in u-boot are used */
+		#address-cells = <1>;
+		#size-cells = <1>;
+	};
+#if 0
+	/* this confuses the driver */
+	flash1: spinand@1 {
+		u-boot,dm-pre-reloc;
+		compatible = "spi-nand";
+		reg = <1>;
+		spi-rx-bus-width = <4>;
+		spi-tx-bus-width = <4>;
+		spi-max-frequency = <104000000>;
+
+		/* required for partitions when mtdparts in u-boot are used */
+		#address-cells = <1>;
+		#size-cells = <1>;
+	};
+#endif
+};
+
+
+/* Internal ADC reference voltage */
+&vrefbuf {
+	/* Set referece voltage to 2.5V */
+	regulator-max-microvolt = <2500000>;
+	regulator-min-microvolt = <2500000>;
+	/*vdda-supply = <&vdd>;*/
+};
+
+
+/* USB settings */
+&usbh_ohci {
+    status = "disabled";
+};
+
+&usbh_ehci {
+	phys = <&usbphyc_port0>;
+	phy-names = "usb";
+	status = "okay";
+};
+
+&usbotg_hs {
+	phys = <&usbphyc_port1 0>;
+	phy-names = "usb2-phy";
+	//vbus-supply = <&vbus_otg>;
+	usb33d-supply = <&usb33>;
+	status = "okay";
+};
+
+&usbphyc {
+	vdda1v1-supply = <&reg11>;
+	vdda1v8-supply = <&reg18>;
+	status = "okay";
+};
+
+&usbphyc_port0 {
+	phy-supply = <&vdd_usb>;
+};
+
+&usbphyc_port1 {
+	phy-supply = <&vdd_usb>;
+};
+
+/* GPU settings */
+&gcnano {
+	contiguous-area = <&gcnano_reserved>;
+	status = "okay";
+};
+
+&rng1 {
+	status = "okay";
+};
+
+/* DMA settings */
+&dma1 {
+	memory-region = <&dma1_reserved>;
+};
+
+&dma2 {
+	memory-region = <&dma2_reserved>;
+};
+
+
+/* Independent watchdog */
+&iwdg2 {
+	timeout-sec = <32>;
+	status = "okay";
+};
+
+
+/* Power control */
+&pwr {
+	pwr-supply = <&vdd>;
+};
+
+
+/* uC interface */
+&ipcc {
+	status = "okay";
+};
+
+&m4_rproc {
+	memory-region = <&ipc_share>;
+	mboxes = <&ipcc 0>, <&ipcc 1>;
+	mbox-names = "vq0", "vq1";
+	interrupt-parent = <&exti>;
+	interrupts = <68 1>;
+	interrupt-names = "wdg";
+	status = "okay";
+};
+
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/bleeding/arch/arm/dts/stm32mp157c-t1000-k-mx.dts b/recipes-bsp/u-boot/u-boot-stm32mp/bleeding/arch/arm/dts/stm32mp157c-t1000-k-mx.dts
deleted file mode 100644
index 34467b56dfa07fa4fd640fe4b869873916a26a30..0000000000000000000000000000000000000000
--- a/recipes-bsp/u-boot/u-boot-stm32mp/bleeding/arch/arm/dts/stm32mp157c-t1000-k-mx.dts
+++ /dev/null
@@ -1,879 +0,0 @@
-/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
-/*
- * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
- * Author: STM32CubeMX code generation for STMicroelectronics.
- */
-
-/dts-v1/;
-#include "stm32mp157c.dtsi"
-#include "stm32mp157cad-pinctrl.dtsi"
-#include "stm32mp157c-m4-srm.dtsi"
-
-/* USER CODE BEGIN includes */
-/* USER CODE END includes */
-
-/ {
-	model = "STMicroelectronics custom STM32CubeMX board";
-	compatible = "st,stm32mp157c-t1000-k-mx", "st,stm32mp157";
-
-	memory@c0000000 {
-		reg = <0xc0000000 0x20000000>;
-
-		/* USER CODE BEGIN memory */
-		/* USER CODE END memory */
-	};
-
-	reserved-memory {
-		#address-cells = <1>;
-		#size-cells = <1>;
-		ranges;
-
-		/* USER CODE BEGIN reserved-memory */
-		/* USER CODE END reserved-memory */
-
-		gpu_reserved: gpu@dc000000 {
-			reg = <0xdc000000 0x4000000>;
-			no-map;
-		};
-	};
-
-	/* USER CODE BEGIN root */
-	/* USER CODE END root */
-
-	clocks {
-		/* USER CODE BEGIN clocks */
-		/* USER CODE END clocks */
-
-		clk_hsi: clk-hsi {
-			clock-frequency = <64000000>;
-		};
-
-		clk_csi: clk-csi {
-			clock-frequency = <4000000>;
-		};
-
-		clk_lse: clk-lse {
-			clock-frequency = <32768>;
-		};
-
-		clk_hse: clk-hse {
-			clock-frequency = <24000000>;
-		};
-	};
-
-}; /*root*/
-
-&pinctrl {
-	u-boot,dm-pre-reloc;
-
-	adc_pins_mx: adc_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 0, ANALOG)>, /* ADC1_INP16 */
-					 <STM32_PINMUX('B', 1, ANALOG)>; /* ADC1_INP5 */
-		};
-	};
-
-	adc_sleep_pins_mx: adc_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 0, ANALOG)>, /* ADC1_INP16 */
-					 <STM32_PINMUX('B', 1, ANALOG)>; /* ADC1_INP5 */
-		};
-	};
-
-	eth1_pins_mx: eth1_mx-0 {
-		pins1 {
-			pinmux = <STM32_PINMUX('A', 2, AF11)>; /* ETH1_MDIO */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-		pins2 {
-			pinmux = <STM32_PINMUX('A', 7, AF11)>, /* ETH1_CRS_DV */
-					 <STM32_PINMUX('C', 4, AF11)>, /* ETH1_RXD0 */
-					 <STM32_PINMUX('C', 5, AF11)>; /* ETH1_RXD1 */
-			bias-disable;
-		};
-		pins3 {
-			pinmux = <STM32_PINMUX('B', 11, AF11)>; /* ETH1_TX_EN */
-		};
-		pins4 {
-			pinmux = <STM32_PINMUX('B', 12, AF11)>, /* ETH1_TXD0 */
-					 <STM32_PINMUX('B', 13, AF11)>, /* ETH1_TXD1 */
-					 <STM32_PINMUX('C', 1, AF11)>, /* ETH1_MDC */
-					 <STM32_PINMUX('G', 8, AF2)>; /* ETH1_CLK */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-	};
-
-	eth1_sleep_pins_mx: eth1_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 2, ANALOG)>, /* ETH1_MDIO */
-					 <STM32_PINMUX('A', 7, ANALOG)>, /* ETH1_CRS_DV */
-					 <STM32_PINMUX('B', 11, ANALOG)>, /* ETH1_TX_EN */
-					 <STM32_PINMUX('B', 12, ANALOG)>, /* ETH1_TXD0 */
-					 <STM32_PINMUX('B', 13, ANALOG)>, /* ETH1_TXD1 */
-					 <STM32_PINMUX('C', 1, ANALOG)>, /* ETH1_MDC */
-					 <STM32_PINMUX('C', 4, ANALOG)>, /* ETH1_RXD0 */
-					 <STM32_PINMUX('C', 5, ANALOG)>, /* ETH1_RXD1 */
-					 <STM32_PINMUX('G', 8, ANALOG)>; /* ETH1_CLK */
-		};
-	};
-
-	fdcan1_pins_mx: fdcan1_mx-0 {
-		pins1 {
-			pinmux = <STM32_PINMUX('D', 0, AF9)>; /* FDCAN1_RX */
-			bias-disable;
-		};
-		pins2 {
-			pinmux = <STM32_PINMUX('D', 1, AF9)>; /* FDCAN1_TX */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-	};
-
-	fdcan1_sleep_pins_mx: fdcan1_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('D', 0, ANALOG)>, /* FDCAN1_RX */
-					 <STM32_PINMUX('D', 1, ANALOG)>; /* FDCAN1_TX */
-		};
-	};
-
-	i2c2_pins_mx: i2c2_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('D', 7, AF4)>, /* I2C2_SCL */
-					 <STM32_PINMUX('G', 15, AF4)>; /* I2C2_SDA */
-			bias-disable;
-			drive-open-drain;
-			slew-rate = <0>;
-		};
-	};
-
-	i2c2_sleep_pins_mx: i2c2_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('D', 7, ANALOG)>, /* I2C2_SCL */
-					 <STM32_PINMUX('G', 15, ANALOG)>; /* I2C2_SDA */
-		};
-	};
-
-	i2c4_pins_mx: i2c4_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('B', 7, AF6)>, /* I2C4_SDA */
-					 <STM32_PINMUX('E', 2, AF4)>; /* I2C4_SCL */
-			bias-disable;
-			drive-open-drain;
-			slew-rate = <0>;
-		};
-	};
-
-	i2c4_sleep_pins_mx: i2c4_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('B', 7, ANALOG)>, /* I2C4_SDA */
-					 <STM32_PINMUX('E', 2, ANALOG)>; /* I2C4_SCL */
-		};
-	};
-
-	ltdc_pins_mx: ltdc_mx-0 {
-		pins1 {
-			pinmux = <STM32_PINMUX('A', 1, AF14)>, /* LTDC_R2 */
-					 <STM32_PINMUX('A', 3, AF14)>, /* LTDC_B5 */
-					 <STM32_PINMUX('A', 4, AF14)>, /* LTDC_VSYNC */
-					 <STM32_PINMUX('A', 5, AF14)>, /* LTDC_R4 */
-					 <STM32_PINMUX('A', 6, AF14)>, /* LTDC_G2 */
-					 <STM32_PINMUX('A', 8, AF14)>, /* LTDC_R6 */
-					 <STM32_PINMUX('A', 12, AF14)>, /* LTDC_R5 */
-					 <STM32_PINMUX('A', 15, AF14)>, /* LTDC_R1 */
-					 <STM32_PINMUX('B', 0, AF9)>, /* LTDC_R3 */
-					 <STM32_PINMUX('B', 5, AF14)>, /* LTDC_G7 */
-					 <STM32_PINMUX('B', 8, AF14)>, /* LTDC_B6 */
-					 <STM32_PINMUX('B', 9, AF14)>, /* LTDC_B7 */
-					 <STM32_PINMUX('B', 10, AF14)>, /* LTDC_G4 */
-					 <STM32_PINMUX('C', 6, AF14)>, /* LTDC_HSYNC */
-					 <STM32_PINMUX('C', 7, AF14)>, /* LTDC_G6 */
-					 <STM32_PINMUX('D', 10, AF14)>, /* LTDC_B3 */
-					 <STM32_PINMUX('E', 4, AF14)>, /* LTDC_B0 */
-					 <STM32_PINMUX('E', 5, AF14)>, /* LTDC_G0 */
-					 <STM32_PINMUX('E', 6, AF14)>, /* LTDC_G1 */
-					 <STM32_PINMUX('E', 11, AF14)>, /* LTDC_G3 */
-					 <STM32_PINMUX('E', 12, AF14)>, /* LTDC_B4 */
-					 <STM32_PINMUX('E', 13, AF14)>, /* LTDC_DE */
-					 <STM32_PINMUX('E', 15, AF14)>, /* LTDC_R7 */
-					 <STM32_PINMUX('F', 11, AF14)>, /* LTDC_G5 */
-					 <STM32_PINMUX('G', 10, AF14)>, /* LTDC_B2 */
-					 <STM32_PINMUX('G', 12, AF14)>, /* LTDC_B1 */
-					 <STM32_PINMUX('G', 13, AF14)>; /* LTDC_R0 */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-		pins2 {
-			pinmux = <STM32_PINMUX('E', 14, AF14)>; /* LTDC_CLK */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-	};
-
-	ltdc_sleep_pins_mx: ltdc_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 1, ANALOG)>, /* LTDC_R2 */
-					 <STM32_PINMUX('A', 3, ANALOG)>, /* LTDC_B5 */
-					 <STM32_PINMUX('A', 4, ANALOG)>, /* LTDC_VSYNC */
-					 <STM32_PINMUX('A', 5, ANALOG)>, /* LTDC_R4 */
-					 <STM32_PINMUX('A', 6, ANALOG)>, /* LTDC_G2 */
-					 <STM32_PINMUX('A', 8, ANALOG)>, /* LTDC_R6 */
-					 <STM32_PINMUX('A', 12, ANALOG)>, /* LTDC_R5 */
-					 <STM32_PINMUX('A', 15, ANALOG)>, /* LTDC_R1 */
-					 <STM32_PINMUX('B', 0, ANALOG)>, /* LTDC_R3 */
-					 <STM32_PINMUX('B', 5, ANALOG)>, /* LTDC_G7 */
-					 <STM32_PINMUX('B', 8, ANALOG)>, /* LTDC_B6 */
-					 <STM32_PINMUX('B', 9, ANALOG)>, /* LTDC_B7 */
-					 <STM32_PINMUX('B', 10, ANALOG)>, /* LTDC_G4 */
-					 <STM32_PINMUX('C', 6, ANALOG)>, /* LTDC_HSYNC */
-					 <STM32_PINMUX('C', 7, ANALOG)>, /* LTDC_G6 */
-					 <STM32_PINMUX('D', 10, ANALOG)>, /* LTDC_B3 */
-					 <STM32_PINMUX('E', 4, ANALOG)>, /* LTDC_B0 */
-					 <STM32_PINMUX('E', 5, ANALOG)>, /* LTDC_G0 */
-					 <STM32_PINMUX('E', 6, ANALOG)>, /* LTDC_G1 */
-					 <STM32_PINMUX('E', 11, ANALOG)>, /* LTDC_G3 */
-					 <STM32_PINMUX('E', 12, ANALOG)>, /* LTDC_B4 */
-					 <STM32_PINMUX('E', 13, ANALOG)>, /* LTDC_DE */
-					 <STM32_PINMUX('E', 14, ANALOG)>, /* LTDC_CLK */
-					 <STM32_PINMUX('E', 15, ANALOG)>, /* LTDC_R7 */
-					 <STM32_PINMUX('F', 11, ANALOG)>, /* LTDC_G5 */
-					 <STM32_PINMUX('G', 10, ANALOG)>, /* LTDC_B2 */
-					 <STM32_PINMUX('G', 12, ANALOG)>, /* LTDC_B1 */
-					 <STM32_PINMUX('G', 13, ANALOG)>; /* LTDC_R0 */
-		};
-	};
-
-	quadspi_pins_mx: quadspi_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 6, AF10)>, /* QUADSPI_BK1_NCS */
-					 <STM32_PINMUX('C', 0, AF10)>; /* QUADSPI_BK2_NCS */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('E', 7, AF10)>, /* QUADSPI_BK2_IO0 */
-					 <STM32_PINMUX('E', 8, AF10)>, /* QUADSPI_BK2_IO1 */
-					 <STM32_PINMUX('E', 9, AF10)>, /* QUADSPI_BK2_IO2 */
-					 <STM32_PINMUX('E', 10, AF10)>, /* QUADSPI_BK2_IO3 */
-					 <STM32_PINMUX('F', 6, AF9)>, /* QUADSPI_BK1_IO3 */
-					 <STM32_PINMUX('F', 7, AF9)>, /* QUADSPI_BK1_IO2 */
-					 <STM32_PINMUX('F', 8, AF10)>, /* QUADSPI_BK1_IO0 */
-					 <STM32_PINMUX('F', 9, AF10)>; /* QUADSPI_BK1_IO1 */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins3 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('F', 10, AF9)>; /* QUADSPI_CLK */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <2>;
-		};
-	};
-
-	quadspi_sleep_pins_mx: quadspi_sleep_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 6, ANALOG)>, /* QUADSPI_BK1_NCS */
-					 <STM32_PINMUX('C', 0, ANALOG)>, /* QUADSPI_BK2_NCS */
-					 <STM32_PINMUX('E', 7, ANALOG)>, /* QUADSPI_BK2_IO0 */
-					 <STM32_PINMUX('E', 8, ANALOG)>, /* QUADSPI_BK2_IO1 */
-					 <STM32_PINMUX('E', 9, ANALOG)>, /* QUADSPI_BK2_IO2 */
-					 <STM32_PINMUX('E', 10, ANALOG)>, /* QUADSPI_BK2_IO3 */
-					 <STM32_PINMUX('F', 6, ANALOG)>, /* QUADSPI_BK1_IO3 */
-					 <STM32_PINMUX('F', 7, ANALOG)>, /* QUADSPI_BK1_IO2 */
-					 <STM32_PINMUX('F', 8, ANALOG)>, /* QUADSPI_BK1_IO0 */
-					 <STM32_PINMUX('F', 9, ANALOG)>, /* QUADSPI_BK1_IO1 */
-					 <STM32_PINMUX('F', 10, ANALOG)>; /* QUADSPI_CLK */
-		};
-	};
-
-	rtc_pins_mx: rtc_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('C', 13, ANALOG)>; /* RTC_LSCO */
-		};
-	};
-
-	rtc_sleep_pins_mx: rtc_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('C', 13, ANALOG)>; /* RTC_LSCO */
-		};
-	};
-
-	sdmmc1_pins_mx: sdmmc1_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
-					 <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
-					 <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
-					 <STM32_PINMUX('C', 11, AF12)>, /* SDMMC1_D3 */
-					 <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 12, AF12)>; /* SDMMC1_CK */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-	};
-
-	sdmmc1_opendrain_pins_mx: sdmmc1_opendrain_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
-					 <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
-					 <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
-					 <STM32_PINMUX('C', 11, AF12)>; /* SDMMC1_D3 */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 12, AF12)>; /* SDMMC1_CK */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins3 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
-			bias-pull-up;
-			drive-open-drain;
-			slew-rate = <1>;
-		};
-	};
-
-	sdmmc1_sleep_pins_mx: sdmmc1_sleep_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 8, ANALOG)>, /* SDMMC1_D0 */
-					 <STM32_PINMUX('C', 9, ANALOG)>, /* SDMMC1_D1 */
-					 <STM32_PINMUX('C', 10, ANALOG)>, /* SDMMC1_D2 */
-					 <STM32_PINMUX('C', 11, ANALOG)>, /* SDMMC1_D3 */
-					 <STM32_PINMUX('C', 12, ANALOG)>, /* SDMMC1_CK */
-					 <STM32_PINMUX('D', 2, ANALOG)>; /* SDMMC1_CMD */
-		};
-	};
-
-	sdmmc2_pins_mx: sdmmc2_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 3, AF9)>, /* SDMMC2_D2 */
-					 <STM32_PINMUX('B', 4, AF9)>, /* SDMMC2_D3 */
-					 <STM32_PINMUX('B', 14, AF9)>, /* SDMMC2_D0 */
-					 <STM32_PINMUX('B', 15, AF9)>, /* SDMMC2_D1 */
-					 <STM32_PINMUX('G', 6, AF10)>; /* SDMMC2_CMD */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('E', 3, AF9)>; /* SDMMC2_CK */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-	};
-
-	sdmmc2_opendrain_pins_mx: sdmmc2_opendrain_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 3, AF9)>, /* SDMMC2_D2 */
-					 <STM32_PINMUX('B', 4, AF9)>, /* SDMMC2_D3 */
-					 <STM32_PINMUX('B', 14, AF9)>, /* SDMMC2_D0 */
-					 <STM32_PINMUX('B', 15, AF9)>; /* SDMMC2_D1 */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('E', 3, AF9)>; /* SDMMC2_CK */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins3 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('G', 6, AF10)>; /* SDMMC2_CMD */
-			bias-pull-up;
-			drive-open-drain;
-			slew-rate = <1>;
-		};
-	};
-
-	sdmmc2_sleep_pins_mx: sdmmc2_sleep_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 3, ANALOG)>, /* SDMMC2_D2 */
-					 <STM32_PINMUX('B', 4, ANALOG)>, /* SDMMC2_D3 */
-					 <STM32_PINMUX('B', 14, ANALOG)>, /* SDMMC2_D0 */
-					 <STM32_PINMUX('B', 15, ANALOG)>, /* SDMMC2_D1 */
-					 <STM32_PINMUX('E', 3, ANALOG)>, /* SDMMC2_CK */
-					 <STM32_PINMUX('G', 6, ANALOG)>; /* SDMMC2_CMD */
-		};
-	};
-
-	tim1_pwm_pins_mx: tim1_pwm_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 9, AF1)>; /* TIM1_CH2 */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-	};
-
-	tim1_pwm_sleep_pins_mx: tim1_pwm_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 9, ANALOG)>; /* TIM1_CH2 */
-		};
-	};
-
-	tim4_pwm_pins_mx: tim4_pwm_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('D', 14, AF2)>; /* TIM4_CH3 */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-	};
-
-	tim4_pwm_sleep_pins_mx: tim4_pwm_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('D', 14, ANALOG)>; /* TIM4_CH3 */
-		};
-	};
-
-	uart4_pins_mx: uart4_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 2, AF8)>; /* UART4_RX */
-			bias-pull-up;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('G', 11, AF6)>; /* UART4_TX */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-	};
-
-	uart4_sleep_pins_mx: uart4_sleep_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 2, ANALOG)>, /* UART4_RX */
-					 <STM32_PINMUX('G', 11, ANALOG)>; /* UART4_TX */
-		};
-	};
-
-	usart2_pins_mx: usart2_mx-0 {
-		pins1 {
-			pinmux = <STM32_PINMUX('D', 4, AF7)>; /* USART2_RTS */
-			bias-pull-down;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-		pins2 {
-			pinmux = <STM32_PINMUX('D', 5, AF7)>; /* USART2_TX */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-		pins3 {
-			pinmux = <STM32_PINMUX('D', 6, AF7)>; /* USART2_RX */
-			bias-pull-up;
-		};
-	};
-
-	usart2_sleep_pins_mx: usart2_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('D', 4, ANALOG)>, /* USART2_RTS */
-					 <STM32_PINMUX('D', 5, ANALOG)>, /* USART2_TX */
-					 <STM32_PINMUX('D', 6, ANALOG)>; /* USART2_RX */
-		};
-	};
-
-	usart3_pins_mx: usart3_mx-0 {
-		pins1 {
-			pinmux = <STM32_PINMUX('D', 9, AF7)>, /* USART3_RX */
-					 <STM32_PINMUX('D', 11, AF7)>; /* USART3_CTS */
-			bias-disable;
-		};
-		pins2 {
-			pinmux = <STM32_PINMUX('D', 8, AF7)>, /* USART3_TX */
-					 <STM32_PINMUX('D', 12, AF7)>; /* USART3_RTS */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-	};
-
-	usart3_sleep_pins_mx: usart3_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('D', 8, ANALOG)>, /* USART3_TX */
-					 <STM32_PINMUX('D', 9, ANALOG)>, /* USART3_RX */
-					 <STM32_PINMUX('D', 11, ANALOG)>, /* USART3_CTS */
-					 <STM32_PINMUX('D', 12, ANALOG)>; /* USART3_RTS */
-		};
-	};
-
-	usb_otg_hs_pins_mx: usb_otg_hs_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
-		};
-	};
-
-	usb_otg_hs_sleep_pins_mx: usb_otg_hs_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
-		};
-	};
-
-	/* USER CODE BEGIN pinctrl */
-	/* USER CODE END pinctrl */
-};
-
-&pinctrl_z {
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN pinctrl_z */
-	/* USER CODE END pinctrl_z */
-};
-
-&m4_rproc{
-	mboxes = <&ipcc 0>, <&ipcc 1>, <&ipcc 2>;
-	mbox-names = "vq0", "vq1", "shutdown";
-	recovery;
-	status = "okay";
-
-	/* USER CODE BEGIN m4_rproc */
-	/* USER CODE END m4_rproc */
-};
-
-&adc{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&adc_pins_mx>;
-	pinctrl-1 = <&adc_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN adc */
-	/* USER CODE END adc */
-};
-
-&bsec{
-	status = "okay";
-
-	/* USER CODE BEGIN bsec */
-	/* USER CODE END bsec */
-};
-
-&crc1{
-	status = "okay";
-
-	/* USER CODE BEGIN crc1 */
-	/* USER CODE END crc1 */
-};
-
-&cryp1{
-	status = "okay";
-
-	/* USER CODE BEGIN cryp1 */
-	/* USER CODE END cryp1 */
-};
-
-&dts{
-	status = "okay";
-
-	/* USER CODE BEGIN dts */
-	/* USER CODE END dts */
-};
-
-&ethernet0{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&eth1_pins_mx>;
-	pinctrl-1 = <&eth1_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN ethernet0 */
-	/* USER CODE END ethernet0 */
-};
-
-&gpu{
-	status = "okay";
-
-	/* USER CODE BEGIN gpu */
-	/* USER CODE END gpu */
-};
-
-&hash1{
-	status = "okay";
-
-	/* USER CODE BEGIN hash1 */
-	/* USER CODE END hash1 */
-};
-
-&hsem{
-	status = "okay";
-
-	/* USER CODE BEGIN hsem */
-	/* USER CODE END hsem */
-};
-
-&i2c2{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&i2c2_pins_mx>;
-	pinctrl-1 = <&i2c2_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN i2c2 */
-	/* USER CODE END i2c2 */
-};
-
-&i2c4{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&i2c4_pins_mx>;
-	pinctrl-1 = <&i2c4_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN i2c4 */
-	/* USER CODE END i2c4 */
-};
-
-&ipcc{
-	status = "okay";
-
-	/* USER CODE BEGIN ipcc */
-	/* USER CODE END ipcc */
-};
-
-&ltdc{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&ltdc_pins_mx>;
-	pinctrl-1 = <&ltdc_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN ltdc */
-	/* USER CODE END ltdc */
-};
-
-&m_can1{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&fdcan1_pins_mx>;
-	pinctrl-1 = <&fdcan1_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN m_can1 */
-	/* USER CODE END m_can1 */
-};
-
-&qspi{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&quadspi_pins_mx>;
-	pinctrl-1 = <&quadspi_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN qspi */
-	/* USER CODE END qspi */
-};
-
-&rcc{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN rcc */
-	/* USER CODE END rcc */
-};
-
-&rng1{
-	status = "okay";
-
-	/* USER CODE BEGIN rng1 */
-	/* USER CODE END rng1 */
-};
-
-&rtc{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&rtc_pins_mx>;
-	pinctrl-1 = <&rtc_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN rtc */
-	/* USER CODE END rtc */
-};
-
-&sdmmc1{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "opendrain", "sleep";
-	pinctrl-0 = <&sdmmc1_pins_mx>;
-	pinctrl-1 = <&sdmmc1_opendrain_pins_mx>;
-	pinctrl-2 = <&sdmmc1_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN sdmmc1 */
-	/* USER CODE END sdmmc1 */
-};
-
-&sdmmc2{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "opendrain", "sleep";
-	pinctrl-0 = <&sdmmc2_pins_mx>;
-	pinctrl-1 = <&sdmmc2_opendrain_pins_mx>;
-	pinctrl-2 = <&sdmmc2_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN sdmmc2 */
-	/* USER CODE END sdmmc2 */
-};
-
-&timers1{
-	status = "okay";
-
-	/* USER CODE BEGIN timers1 */
-	/* USER CODE END timers1 */
-
-	pwm{
-		pinctrl-names = "default", "sleep";
-		pinctrl-0 = <&tim1_pwm_pins_mx>;
-		pinctrl-1 = <&tim1_pwm_sleep_pins_mx>;
-		status = "okay";
-
-		/* USER CODE BEGIN timers1_pwm */
-		/* USER CODE END timers1_pwm */
-	};
-};
-
-&timers4{
-	status = "okay";
-
-	/* USER CODE BEGIN timers4 */
-	/* USER CODE END timers4 */
-
-	pwm{
-		pinctrl-names = "default", "sleep";
-		pinctrl-0 = <&tim4_pwm_pins_mx>;
-		pinctrl-1 = <&tim4_pwm_sleep_pins_mx>;
-		status = "okay";
-
-		/* USER CODE BEGIN timers4_pwm */
-		/* USER CODE END timers4_pwm */
-	};
-};
-
-&uart4{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&uart4_pins_mx>;
-	pinctrl-1 = <&uart4_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN uart4 */
-	/* USER CODE END uart4 */
-};
-
-&usart2{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&usart2_pins_mx>;
-	pinctrl-1 = <&usart2_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN usart2 */
-	/* USER CODE END usart2 */
-};
-
-&usart3{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&usart3_pins_mx>;
-	pinctrl-1 = <&usart3_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN usart3 */
-	/* USER CODE END usart3 */
-};
-
-&usbh_ehci{
-	status = "okay";
-
-	/* USER CODE BEGIN usbh_ehci */
-	/* USER CODE END usbh_ehci */
-};
-
-&usbh_ohci{
-	status = "okay";
-
-	/* USER CODE BEGIN usbh_ohci */
-	/* USER CODE END usbh_ohci */
-};
-
-&usbotg_hs{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&usb_otg_hs_pins_mx>;
-	pinctrl-1 = <&usb_otg_hs_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN usbotg_hs */
-	/* USER CODE END usbotg_hs */
-};
-
-&usbphyc{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc */
-	/* USER CODE END usbphyc */
-};
-
-&usbphyc_port0{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc_port0 */
-	/* USER CODE END usbphyc_port0 */
-};
-
-&usbphyc_port1{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc_port1 */
-	/* USER CODE END usbphyc_port1 */
-};
-
-&vrefbuf{
-	status = "okay";
-
-	/* USER CODE BEGIN vrefbuf */
-	/* USER CODE END vrefbuf */
-};
-
-/* USER CODE BEGIN addons */
-/* USER CODE END addons */
-
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/bleeding/arch/arm/dts/stm32mp157c-t1000-som-minimal-mx.dts b/recipes-bsp/u-boot/u-boot-stm32mp/bleeding/arch/arm/dts/stm32mp157c-t1000-som-minimal-mx.dts
deleted file mode 100644
index 58e5e7008bd4a9dbb177aa92a133c8a8a39f37bd..0000000000000000000000000000000000000000
--- a/recipes-bsp/u-boot/u-boot-stm32mp/bleeding/arch/arm/dts/stm32mp157c-t1000-som-minimal-mx.dts
+++ /dev/null
@@ -1,518 +0,0 @@
-/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
-/*
- * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
- * Author: STM32CubeMX code generation for STMicroelectronics.
- */
-
-/dts-v1/;
-#include "stm32mp157c.dtsi"
-#include "stm32mp157cad-pinctrl.dtsi"
-#include "stm32mp157c-m4-srm.dtsi"
-
-/* USER CODE BEGIN includes */
-/* USER CODE END includes */
-
-/ {
-	model = "STMicroelectronics custom STM32CubeMX board";
-	compatible = "st,stm32mp157c-t1000-som-minimal-mx", "st,stm32mp157";
-
-	memory@c0000000 {
-		reg = <0xc0000000 0x20000000>;
-
-		/* USER CODE BEGIN memory */
-		/* USER CODE END memory */
-	};
-
-	reserved-memory {
-		#address-cells = <1>;
-		#size-cells = <1>;
-		ranges;
-
-		/* USER CODE BEGIN reserved-memory */
-		/* USER CODE END reserved-memory */
-
-		gpu_reserved: gpu@dc000000 {
-			reg = <0xdc000000 0x4000000>;
-			no-map;
-		};
-	};
-
-	/* USER CODE BEGIN root */
-	/* USER CODE END root */
-
-	clocks {
-		/* USER CODE BEGIN clocks */
-		/* USER CODE END clocks */
-
-		clk_hsi: clk-hsi {
-			clock-frequency = <64000000>;
-		};
-
-		clk_csi: clk-csi {
-			clock-frequency = <4000000>;
-		};
-
-		clk_lse: clk-lse {
-			clock-frequency = <32768>;
-		};
-
-		clk_hse: clk-hse {
-			clock-frequency = <24000000>;
-		};
-	};
-
-}; /*root*/
-
-&pinctrl {
-	u-boot,dm-pre-reloc;
-
-	eth1_pins_mx: eth1_mx-0 {
-		pins1 {
-			pinmux = <STM32_PINMUX('A', 2, AF11)>; /* ETH1_MDIO */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-		pins2 {
-			pinmux = <STM32_PINMUX('A', 7, AF11)>, /* ETH1_CRS_DV */
-					 <STM32_PINMUX('C', 4, AF11)>, /* ETH1_RXD0 */
-					 <STM32_PINMUX('C', 5, AF11)>; /* ETH1_RXD1 */
-			bias-disable;
-		};
-		pins3 {
-			pinmux = <STM32_PINMUX('B', 11, AF11)>; /* ETH1_TX_EN */
-		};
-		pins4 {
-			pinmux = <STM32_PINMUX('B', 12, AF11)>, /* ETH1_TXD0 */
-					 <STM32_PINMUX('B', 13, AF11)>, /* ETH1_TXD1 */
-					 <STM32_PINMUX('C', 1, AF11)>, /* ETH1_MDC */
-					 <STM32_PINMUX('G', 8, AF2)>; /* ETH1_CLK */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-	};
-
-	eth1_sleep_pins_mx: eth1_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 2, ANALOG)>, /* ETH1_MDIO */
-					 <STM32_PINMUX('A', 7, ANALOG)>, /* ETH1_CRS_DV */
-					 <STM32_PINMUX('B', 11, ANALOG)>, /* ETH1_TX_EN */
-					 <STM32_PINMUX('B', 12, ANALOG)>, /* ETH1_TXD0 */
-					 <STM32_PINMUX('B', 13, ANALOG)>, /* ETH1_TXD1 */
-					 <STM32_PINMUX('C', 1, ANALOG)>, /* ETH1_MDC */
-					 <STM32_PINMUX('C', 4, ANALOG)>, /* ETH1_RXD0 */
-					 <STM32_PINMUX('C', 5, ANALOG)>, /* ETH1_RXD1 */
-					 <STM32_PINMUX('G', 8, ANALOG)>; /* ETH1_CLK */
-		};
-	};
-
-	i2c2_pins_mx: i2c2_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('D', 7, AF4)>, /* I2C2_SCL */
-					 <STM32_PINMUX('G', 15, AF4)>; /* I2C2_SDA */
-			bias-disable;
-			drive-open-drain;
-			slew-rate = <0>;
-		};
-	};
-
-	i2c2_sleep_pins_mx: i2c2_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('D', 7, ANALOG)>, /* I2C2_SCL */
-					 <STM32_PINMUX('G', 15, ANALOG)>; /* I2C2_SDA */
-		};
-	};
-
-	quadspi_pins_mx: quadspi_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 6, AF10)>, /* QUADSPI_BK1_NCS */
-					 <STM32_PINMUX('C', 0, AF10)>; /* QUADSPI_BK2_NCS */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('E', 7, AF10)>, /* QUADSPI_BK2_IO0 */
-					 <STM32_PINMUX('E', 8, AF10)>, /* QUADSPI_BK2_IO1 */
-					 <STM32_PINMUX('E', 9, AF10)>, /* QUADSPI_BK2_IO2 */
-					 <STM32_PINMUX('E', 10, AF10)>, /* QUADSPI_BK2_IO3 */
-					 <STM32_PINMUX('F', 6, AF9)>, /* QUADSPI_BK1_IO3 */
-					 <STM32_PINMUX('F', 7, AF9)>, /* QUADSPI_BK1_IO2 */
-					 <STM32_PINMUX('F', 8, AF10)>, /* QUADSPI_BK1_IO0 */
-					 <STM32_PINMUX('F', 9, AF10)>; /* QUADSPI_BK1_IO1 */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins3 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('F', 10, AF9)>; /* QUADSPI_CLK */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <2>;
-		};
-	};
-
-	quadspi_sleep_pins_mx: quadspi_sleep_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 6, ANALOG)>, /* QUADSPI_BK1_NCS */
-					 <STM32_PINMUX('C', 0, ANALOG)>, /* QUADSPI_BK2_NCS */
-					 <STM32_PINMUX('E', 7, ANALOG)>, /* QUADSPI_BK2_IO0 */
-					 <STM32_PINMUX('E', 8, ANALOG)>, /* QUADSPI_BK2_IO1 */
-					 <STM32_PINMUX('E', 9, ANALOG)>, /* QUADSPI_BK2_IO2 */
-					 <STM32_PINMUX('E', 10, ANALOG)>, /* QUADSPI_BK2_IO3 */
-					 <STM32_PINMUX('F', 6, ANALOG)>, /* QUADSPI_BK1_IO3 */
-					 <STM32_PINMUX('F', 7, ANALOG)>, /* QUADSPI_BK1_IO2 */
-					 <STM32_PINMUX('F', 8, ANALOG)>, /* QUADSPI_BK1_IO0 */
-					 <STM32_PINMUX('F', 9, ANALOG)>, /* QUADSPI_BK1_IO1 */
-					 <STM32_PINMUX('F', 10, ANALOG)>; /* QUADSPI_CLK */
-		};
-	};
-
-	rtc_pins_mx: rtc_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('C', 13, ANALOG)>; /* RTC_LSCO */
-		};
-	};
-
-	rtc_sleep_pins_mx: rtc_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('C', 13, ANALOG)>; /* RTC_LSCO */
-		};
-	};
-
-	sdmmc1_pins_mx: sdmmc1_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
-					 <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
-					 <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
-					 <STM32_PINMUX('C', 11, AF12)>, /* SDMMC1_D3 */
-					 <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 12, AF12)>; /* SDMMC1_CK */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-	};
-
-	sdmmc1_opendrain_pins_mx: sdmmc1_opendrain_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
-					 <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
-					 <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
-					 <STM32_PINMUX('C', 11, AF12)>; /* SDMMC1_D3 */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 12, AF12)>; /* SDMMC1_CK */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins3 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
-			bias-pull-up;
-			drive-open-drain;
-			slew-rate = <1>;
-		};
-	};
-
-	sdmmc1_sleep_pins_mx: sdmmc1_sleep_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 8, ANALOG)>, /* SDMMC1_D0 */
-					 <STM32_PINMUX('C', 9, ANALOG)>, /* SDMMC1_D1 */
-					 <STM32_PINMUX('C', 10, ANALOG)>, /* SDMMC1_D2 */
-					 <STM32_PINMUX('C', 11, ANALOG)>, /* SDMMC1_D3 */
-					 <STM32_PINMUX('C', 12, ANALOG)>, /* SDMMC1_CK */
-					 <STM32_PINMUX('D', 2, ANALOG)>; /* SDMMC1_CMD */
-		};
-	};
-
-	uart4_pins_mx: uart4_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 2, AF8)>; /* UART4_RX */
-			bias-pull-up;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('G', 11, AF6)>; /* UART4_TX */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-	};
-
-	uart4_sleep_pins_mx: uart4_sleep_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 2, ANALOG)>, /* UART4_RX */
-					 <STM32_PINMUX('G', 11, ANALOG)>; /* UART4_TX */
-		};
-	};
-
-	usb_otg_hs_pins_mx: usb_otg_hs_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
-		};
-	};
-
-	usb_otg_hs_sleep_pins_mx: usb_otg_hs_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
-		};
-	};
-
-	/* USER CODE BEGIN pinctrl */
-	/* USER CODE END pinctrl */
-};
-
-&pinctrl_z {
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN pinctrl_z */
-	/* USER CODE END pinctrl_z */
-};
-
-&m4_rproc{
-	mboxes = <&ipcc 0>, <&ipcc 1>, <&ipcc 2>;
-	mbox-names = "vq0", "vq1", "shutdown";
-	recovery;
-	status = "okay";
-
-	/* USER CODE BEGIN m4_rproc */
-	/* USER CODE END m4_rproc */
-};
-
-&adc{
-	status = "okay";
-
-	/* USER CODE BEGIN adc */
-	/* USER CODE END adc */
-};
-
-&bsec{
-	status = "okay";
-
-	/* USER CODE BEGIN bsec */
-	/* USER CODE END bsec */
-};
-
-&crc1{
-	status = "okay";
-
-	/* USER CODE BEGIN crc1 */
-	/* USER CODE END crc1 */
-};
-
-&cryp1{
-	status = "okay";
-
-	/* USER CODE BEGIN cryp1 */
-	/* USER CODE END cryp1 */
-};
-
-&dts{
-	status = "okay";
-
-	/* USER CODE BEGIN dts */
-	/* USER CODE END dts */
-};
-
-&ethernet0{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&eth1_pins_mx>;
-	pinctrl-1 = <&eth1_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN ethernet0 */
-	/* USER CODE END ethernet0 */
-};
-
-&gpu{
-	status = "okay";
-
-	/* USER CODE BEGIN gpu */
-	/* USER CODE END gpu */
-};
-
-&hash1{
-	status = "okay";
-
-	/* USER CODE BEGIN hash1 */
-	/* USER CODE END hash1 */
-};
-
-&hsem{
-	status = "okay";
-
-	/* USER CODE BEGIN hsem */
-	/* USER CODE END hsem */
-};
-
-&i2c2{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&i2c2_pins_mx>;
-	pinctrl-1 = <&i2c2_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN i2c2 */
-	/* USER CODE END i2c2 */
-};
-
-&ipcc{
-	status = "okay";
-
-	/* USER CODE BEGIN ipcc */
-	/* USER CODE END ipcc */
-};
-
-&iwdg2{
-	status = "okay";
-
-	/* USER CODE BEGIN iwdg2 */
-	/* USER CODE END iwdg2 */
-};
-
-&qspi{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&quadspi_pins_mx>;
-	pinctrl-1 = <&quadspi_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN qspi */
-	/* USER CODE END qspi */
-};
-
-&rcc{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN rcc */
-	/* USER CODE END rcc */
-};
-
-&rng1{
-	status = "okay";
-
-	/* USER CODE BEGIN rng1 */
-	/* USER CODE END rng1 */
-};
-
-&rtc{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&rtc_pins_mx>;
-	pinctrl-1 = <&rtc_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN rtc */
-	/* USER CODE END rtc */
-};
-
-&sdmmc1{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "opendrain", "sleep";
-	pinctrl-0 = <&sdmmc1_pins_mx>;
-	pinctrl-1 = <&sdmmc1_opendrain_pins_mx>;
-	pinctrl-2 = <&sdmmc1_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN sdmmc1 */
-	/* USER CODE END sdmmc1 */
-};
-
-&uart4{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&uart4_pins_mx>;
-	pinctrl-1 = <&uart4_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN uart4 */
-	/* USER CODE END uart4 */
-};
-
-&usbh_ehci{
-	status = "okay";
-
-	/* USER CODE BEGIN usbh_ehci */
-	/* USER CODE END usbh_ehci */
-};
-
-&usbh_ohci{
-	status = "okay";
-
-	/* USER CODE BEGIN usbh_ohci */
-	/* USER CODE END usbh_ohci */
-};
-
-&usbotg_hs{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&usb_otg_hs_pins_mx>;
-	pinctrl-1 = <&usb_otg_hs_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN usbotg_hs */
-	/* USER CODE END usbotg_hs */
-};
-
-&usbphyc{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc */
-	/* USER CODE END usbphyc */
-};
-
-&usbphyc_port0{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc_port0 */
-	/* USER CODE END usbphyc_port0 */
-};
-
-&usbphyc_port1{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc_port1 */
-	/* USER CODE END usbphyc_port1 */
-};
-
-&vrefbuf{
-	status = "okay";
-
-	/* USER CODE BEGIN vrefbuf */
-	/* USER CODE END vrefbuf */
-};
-
-/* USER CODE BEGIN addons */
-/* USER CODE END addons */
-
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/bleeding/arch/arm/dts/stm32mp157c-t1001-som-minimal-mx.dts b/recipes-bsp/u-boot/u-boot-stm32mp/bleeding/arch/arm/dts/stm32mp157c-t1001-som-minimal-mx.dts
deleted file mode 100644
index 6da864d323868686ea17e9d47a20ba4cb7c96244..0000000000000000000000000000000000000000
--- a/recipes-bsp/u-boot/u-boot-stm32mp/bleeding/arch/arm/dts/stm32mp157c-t1001-som-minimal-mx.dts
+++ /dev/null
@@ -1,405 +0,0 @@
-/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
-/*
- * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
- * Author: STM32CubeMX code generation for STMicroelectronics.
- */
-
-/dts-v1/;
-#include "stm32mp157c.dtsi"
-#include "stm32mp157cad-pinctrl.dtsi"
-#include "stm32mp157c-m4-srm.dtsi"
-
-/* USER CODE BEGIN includes */
-/* USER CODE END includes */
-
-/ {
-	model = "STMicroelectronics custom STM32CubeMX board";
-	compatible = "st,stm32mp157c-t1001-som-minimal-mx", "st,stm32mp157";
-
-	memory@c0000000 {
-		reg = <0xc0000000 0x20000000>;
-
-		/* USER CODE BEGIN memory */
-		/* USER CODE END memory */
-	};
-
-	reserved-memory {
-		#address-cells = <1>;
-		#size-cells = <1>;
-		ranges;
-
-		/* USER CODE BEGIN reserved-memory */
-		/* USER CODE END reserved-memory */
-
-		gpu_reserved: gpu@dc000000 {
-			reg = <0xdc000000 0x4000000>;
-			no-map;
-		};
-	};
-
-	/* USER CODE BEGIN root */
-	/* USER CODE END root */
-
-	clocks {
-		/* USER CODE BEGIN clocks */
-		/* USER CODE END clocks */
-
-		clk_csi: clk-csi {
-			clock-frequency = <4000000>;
-		};
-
-		clk_lse: clk-lse {
-			clock-frequency = <32768>;
-		};
-
-		clk_hse: clk-hse {
-			clock-frequency = <24000000>;
-		};
-	};
-
-}; /*root*/
-
-&pinctrl {
-	u-boot,dm-pre-reloc;
-
-	quadspi_pins_mx: quadspi_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 6, AF10)>; /* QUADSPI_BK1_NCS */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('F', 6, AF9)>, /* QUADSPI_BK1_IO3 */
-					 <STM32_PINMUX('F', 7, AF9)>, /* QUADSPI_BK1_IO2 */
-					 <STM32_PINMUX('F', 8, AF10)>, /* QUADSPI_BK1_IO0 */
-					 <STM32_PINMUX('F', 9, AF10)>, /* QUADSPI_BK1_IO1 */
-					 <STM32_PINMUX('F', 10, AF9)>; /* QUADSPI_CLK */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-	};
-
-	quadspi_sleep_pins_mx: quadspi_sleep_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 6, ANALOG)>, /* QUADSPI_BK1_NCS */
-					 <STM32_PINMUX('F', 6, ANALOG)>, /* QUADSPI_BK1_IO3 */
-					 <STM32_PINMUX('F', 7, ANALOG)>, /* QUADSPI_BK1_IO2 */
-					 <STM32_PINMUX('F', 8, ANALOG)>, /* QUADSPI_BK1_IO0 */
-					 <STM32_PINMUX('F', 9, ANALOG)>, /* QUADSPI_BK1_IO1 */
-					 <STM32_PINMUX('F', 10, ANALOG)>; /* QUADSPI_CLK */
-		};
-	};
-
-	sdmmc1_pins_mx: sdmmc1_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
-					 <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
-					 <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
-					 <STM32_PINMUX('C', 11, AF12)>, /* SDMMC1_D3 */
-					 <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 12, AF12)>; /* SDMMC1_CK */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-	};
-
-	sdmmc1_opendrain_pins_mx: sdmmc1_opendrain_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
-					 <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
-					 <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
-					 <STM32_PINMUX('C', 11, AF12)>; /* SDMMC1_D3 */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 12, AF12)>; /* SDMMC1_CK */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins3 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
-			bias-pull-up;
-			drive-open-drain;
-			slew-rate = <1>;
-		};
-	};
-
-	sdmmc1_sleep_pins_mx: sdmmc1_sleep_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 8, ANALOG)>, /* SDMMC1_D0 */
-					 <STM32_PINMUX('C', 9, ANALOG)>, /* SDMMC1_D1 */
-					 <STM32_PINMUX('C', 10, ANALOG)>, /* SDMMC1_D2 */
-					 <STM32_PINMUX('C', 11, ANALOG)>, /* SDMMC1_D3 */
-					 <STM32_PINMUX('C', 12, ANALOG)>, /* SDMMC1_CK */
-					 <STM32_PINMUX('D', 2, ANALOG)>; /* SDMMC1_CMD */
-		};
-	};
-
-	uart4_pins_mx: uart4_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 2, AF8)>; /* UART4_RX */
-			bias-pull-up;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('G', 11, AF6)>; /* UART4_TX */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-	};
-
-	uart4_sleep_pins_mx: uart4_sleep_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 2, ANALOG)>, /* UART4_RX */
-					 <STM32_PINMUX('G', 11, ANALOG)>; /* UART4_TX */
-		};
-	};
-
-	usb_otg_hs_pins_mx: usb_otg_hs_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
-		};
-	};
-
-	usb_otg_hs_sleep_pins_mx: usb_otg_hs_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
-		};
-	};
-
-	/* USER CODE BEGIN pinctrl */
-	/* USER CODE END pinctrl */
-};
-
-&pinctrl_z {
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN pinctrl_z */
-	/* USER CODE END pinctrl_z */
-};
-
-&m4_rproc{
-	mboxes = <&ipcc 0>, <&ipcc 1>, <&ipcc 2>;
-	mbox-names = "vq0", "vq1", "shutdown";
-	recovery;
-	status = "okay";
-
-	/* USER CODE BEGIN m4_rproc */
-	/* USER CODE END m4_rproc */
-};
-
-&adc{
-	status = "okay";
-
-	/* USER CODE BEGIN adc */
-	/* USER CODE END adc */
-};
-
-&bsec{
-	status = "okay";
-
-	/* USER CODE BEGIN bsec */
-	/* USER CODE END bsec */
-};
-
-&crc1{
-	status = "okay";
-
-	/* USER CODE BEGIN crc1 */
-	/* USER CODE END crc1 */
-};
-
-&cryp1{
-	status = "okay";
-
-	/* USER CODE BEGIN cryp1 */
-	/* USER CODE END cryp1 */
-};
-
-&dts{
-	status = "okay";
-
-	/* USER CODE BEGIN dts */
-	/* USER CODE END dts */
-};
-
-&gpu{
-	status = "okay";
-
-	/* USER CODE BEGIN gpu */
-	/* USER CODE END gpu */
-};
-
-&hash1{
-	status = "okay";
-
-	/* USER CODE BEGIN hash1 */
-	/* USER CODE END hash1 */
-};
-
-&hsem{
-	status = "okay";
-
-	/* USER CODE BEGIN hsem */
-	/* USER CODE END hsem */
-};
-
-&ipcc{
-	status = "okay";
-
-	/* USER CODE BEGIN ipcc */
-	/* USER CODE END ipcc */
-};
-
-&iwdg2{
-	status = "okay";
-
-	/* USER CODE BEGIN iwdg2 */
-	/* USER CODE END iwdg2 */
-};
-
-&qspi{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&quadspi_pins_mx>;
-	pinctrl-1 = <&quadspi_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN qspi */
-	/* USER CODE END qspi */
-};
-
-&rcc{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN rcc */
-	/* USER CODE END rcc */
-};
-
-&rng1{
-	status = "okay";
-
-	/* USER CODE BEGIN rng1 */
-	/* USER CODE END rng1 */
-};
-
-&rtc{
-	status = "okay";
-
-	/* USER CODE BEGIN rtc */
-	/* USER CODE END rtc */
-};
-
-&sdmmc1{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "opendrain", "sleep";
-	pinctrl-0 = <&sdmmc1_pins_mx>;
-	pinctrl-1 = <&sdmmc1_opendrain_pins_mx>;
-	pinctrl-2 = <&sdmmc1_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN sdmmc1 */
-	/* USER CODE END sdmmc1 */
-};
-
-&uart4{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&uart4_pins_mx>;
-	pinctrl-1 = <&uart4_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN uart4 */
-	/* USER CODE END uart4 */
-};
-
-&usbh_ehci{
-	status = "okay";
-
-	/* USER CODE BEGIN usbh_ehci */
-	/* USER CODE END usbh_ehci */
-};
-
-&usbh_ohci{
-	status = "okay";
-
-	/* USER CODE BEGIN usbh_ohci */
-	/* USER CODE END usbh_ohci */
-};
-
-&usbotg_hs{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&usb_otg_hs_pins_mx>;
-	pinctrl-1 = <&usb_otg_hs_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN usbotg_hs */
-	/* USER CODE END usbotg_hs */
-};
-
-&usbphyc{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc */
-	/* USER CODE END usbphyc */
-};
-
-&usbphyc_port0{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc_port0 */
-	/* USER CODE END usbphyc_port0 */
-};
-
-&usbphyc_port1{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc_port1 */
-	/* USER CODE END usbphyc_port1 */
-};
-
-&vrefbuf{
-	status = "okay";
-
-	/* USER CODE BEGIN vrefbuf */
-	/* USER CODE END vrefbuf */
-};
-
-/* USER CODE BEGIN addons */
-/* USER CODE END addons */
-
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/bleeding/board/kontron/stm32mp1-t1000/board.c b/recipes-bsp/u-boot/u-boot-stm32mp/bleeding/board/kontron/stm32mp1-t1000/board.c
deleted file mode 100644
index 3e38aefad3e839125fa81f160952d0f34ebb1904..0000000000000000000000000000000000000000
--- a/recipes-bsp/u-boot/u-boot-stm32mp/bleeding/board/kontron/stm32mp1-t1000/board.c
+++ /dev/null
@@ -1,226 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
-/*
- * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
- */
-
-#include <common.h>
-#include <dm.h>
-#include <asm/io.h>
-#include <asm/arch/ddr.h>
-#include <power/pmic.h>
-#include <power/stpmic1.h>
-
-#ifdef CONFIG_DEBUG_UART_BOARD_INIT
-void board_debug_uart_init(void)
-{
-#if (CONFIG_DEBUG_UART_BASE == STM32_UART4_BASE)
-
-#define RCC_MP_APB1ENSETR (STM32_RCC_BASE + 0x0A00)
-#define RCC_MP_AHB4ENSETR (STM32_RCC_BASE + 0x0A28)
-
-	/* UART4 clock enable */
-	setbits_le32(RCC_MP_APB1ENSETR, BIT(16));
-
-#define GPIOG_BASE 0x50008000
-	/* GPIOG clock enable */
-	writel(BIT(6), RCC_MP_AHB4ENSETR);
-	/* GPIO configuration for EVAL board
-	 * => Uart4 TX = G11
-	 */
-	writel(0xffbfffff, GPIOG_BASE + 0x00);
-	writel(0x00006000, GPIOG_BASE + 0x24);
-#else
-
-#error("CONFIG_DEBUG_UART_BASE: not supported value")
-
-#endif
-}
-#endif
-
-#ifdef CONFIG_PMIC_STPMIC1
-u32 opp_voltage_mv;
-
-void board_vddcore_init(u32 voltage_mv)
-{
-	opp_voltage_mv = voltage_mv;
-}
-
-int board_vddcore_set(void)
-{
-	struct udevice *dev;
-	int ret;
-	u32 value;
-
-	if (!opp_voltage_mv)
-		return 0;
-
-	ret = uclass_get_device_by_driver(UCLASS_PMIC,
-					  DM_GET_DRIVER(pmic_stpmic1), &dev);
-	if (ret)
-		return ret;
-
-	/* VDDCORE= STMPCI1 BUCK1 ramp=+25mV, 5 => 725mV, 36 => 1500mV */
-	value = ((opp_voltage_mv - 725) / 25) + 5;
-	if (value < 5)
-		value = 5;
-	if (value > 36)
-		value = 36;
-
-	return pmic_clrsetbits(dev,
-			       STPMIC1_BUCKX_MAIN_CR(STPMIC1_BUCK1),
-			       STPMIC1_BUCK_VOUT_MASK,
-			       STPMIC1_BUCK_VOUT(value));
-}
-
-int board_ddr_power_init(enum ddr_type ddr_type)
-{
-	struct udevice *dev;
-	bool buck3_at_1800000v = false;
-	int ret;
-	u32 buck2;
-
-	ret = uclass_get_device_by_driver(UCLASS_PMIC,
-					  DM_GET_DRIVER(pmic_stpmic1), &dev);
-	if (ret)
-		/* No PMIC on board */
-		return 0;
-
-	switch (ddr_type) {
-	case STM32MP_DDR3:
-		/* VTT = Set LDO3 to sync mode */
-		ret = pmic_reg_read(dev, STPMIC1_LDOX_MAIN_CR(STPMIC1_LDO3));
-		if (ret < 0)
-			return ret;
-
-		ret &= ~STPMIC1_LDO3_MODE;
-		ret &= ~STPMIC1_LDO12356_VOUT_MASK;
-		ret |= STPMIC1_LDO_VOUT(STPMIC1_LDO3_DDR_SEL);
-
-		ret = pmic_reg_write(dev, STPMIC1_LDOX_MAIN_CR(STPMIC1_LDO3),
-				     ret);
-		if (ret < 0)
-			return ret;
-
-		/* VDD_DDR = Set BUCK2 to 1.35V */
-		ret = pmic_clrsetbits(dev,
-				      STPMIC1_BUCKX_MAIN_CR(STPMIC1_BUCK2),
-				      STPMIC1_BUCK_VOUT_MASK,
-				      STPMIC1_BUCK2_1350000V);
-		if (ret < 0)
-			return ret;
-
-		/* Enable VDD_DDR = BUCK2 */
-		ret = pmic_clrsetbits(dev,
-				      STPMIC1_BUCKX_MAIN_CR(STPMIC1_BUCK2),
-				      STPMIC1_BUCK_ENA, STPMIC1_BUCK_ENA);
-		if (ret < 0)
-			return ret;
-
-		mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS);
-
-		/* Enable VREF */
-		ret = pmic_clrsetbits(dev, STPMIC1_REFDDR_MAIN_CR,
-				      STPMIC1_VREF_ENA, STPMIC1_VREF_ENA);
-		if (ret < 0)
-			return ret;
-
-		mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS);
-
-		/* Enable VTT = LDO3 */
-		ret = pmic_clrsetbits(dev,
-				      STPMIC1_LDOX_MAIN_CR(STPMIC1_LDO3),
-				      STPMIC1_LDO_ENA, STPMIC1_LDO_ENA);
-		if (ret < 0)
-			return ret;
-
-		mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS);
-
-		break;
-
-	case STM32MP_LPDDR2_16:
-	case STM32MP_LPDDR2_32:
-	case STM32MP_LPDDR3_16:
-	case STM32MP_LPDDR3_32:
-		/*
-		 * configure VDD_DDR1 = LDO3
-		 * Set LDO3 to 1.8V
-		 * + bypass mode if BUCK3 = 1.8V
-		 * + normal mode if BUCK3 != 1.8V
-		 */
-		ret = pmic_reg_read(dev,
-				    STPMIC1_BUCKX_MAIN_CR(STPMIC1_BUCK3));
-		if (ret < 0)
-			return ret;
-
-		if ((ret & STPMIC1_BUCK3_1800000V) == STPMIC1_BUCK3_1800000V)
-			buck3_at_1800000v = true;
-
-		ret = pmic_reg_read(dev, STPMIC1_LDOX_MAIN_CR(STPMIC1_LDO3));
-		if (ret < 0)
-			return ret;
-
-		ret &= ~STPMIC1_LDO3_MODE;
-		ret &= ~STPMIC1_LDO12356_VOUT_MASK;
-		ret |= STPMIC1_LDO3_1800000;
-		if (buck3_at_1800000v)
-			ret |= STPMIC1_LDO3_MODE;
-
-		ret = pmic_reg_write(dev, STPMIC1_LDOX_MAIN_CR(STPMIC1_LDO3),
-				     ret);
-		if (ret < 0)
-			return ret;
-
-		/* VDD_DDR2 : Set BUCK2 to 1.2V (16bits) or 1.25V (32 bits)*/
-		switch (ddr_type) {
-		case STM32MP_LPDDR2_32:
-		case STM32MP_LPDDR3_32:
-			buck2 = STPMIC1_BUCK2_1250000V;
-			break;
-		default:
-		case STM32MP_LPDDR2_16:
-		case STM32MP_LPDDR3_16:
-			buck2 = STPMIC1_BUCK2_1200000V;
-			break;
-		}
-
-		ret = pmic_clrsetbits(dev,
-				      STPMIC1_BUCKX_MAIN_CR(STPMIC1_BUCK2),
-				      STPMIC1_BUCK_VOUT_MASK,
-				      buck2);
-		if (ret < 0)
-			return ret;
-
-		/* Enable VDD_DDR1 = LDO3 */
-		ret = pmic_clrsetbits(dev, STPMIC1_LDOX_MAIN_CR(STPMIC1_LDO3),
-				      STPMIC1_LDO_ENA, STPMIC1_LDO_ENA);
-		if (ret < 0)
-			return ret;
-
-		mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS);
-
-		/* Enable VDD_DDR2 =BUCK2 */
-		ret = pmic_clrsetbits(dev,
-				      STPMIC1_BUCKX_MAIN_CR(STPMIC1_BUCK2),
-				      STPMIC1_BUCK_ENA, STPMIC1_BUCK_ENA);
-		if (ret < 0)
-			return ret;
-
-		mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS);
-
-		/* Enable VREF */
-		ret = pmic_clrsetbits(dev, STPMIC1_REFDDR_MAIN_CR,
-				      STPMIC1_VREF_ENA, STPMIC1_VREF_ENA);
-		if (ret < 0)
-			return ret;
-
-		mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS);
-
-		break;
-
-	default:
-		break;
-	};
-
-	return 0;
-}
-#endif
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/bleeding/board/kontron/stm32mp1-t1000/stm32mp1-t1000.c b/recipes-bsp/u-boot/u-boot-stm32mp/bleeding/board/kontron/stm32mp1-t1000/stm32mp1-t1000.c
deleted file mode 100644
index ecbcb463279479949da3f2c419171c18c8c0ac30..0000000000000000000000000000000000000000
--- a/recipes-bsp/u-boot/u-boot-stm32mp/bleeding/board/kontron/stm32mp1-t1000/stm32mp1-t1000.c
+++ /dev/null
@@ -1,1162 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
-/*
- * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
- */
-#include <config.h>
-#include <common.h>
-#include <adc.h>
-#include <bootm.h>
-#include <dm.h>
-#include <clk.h>
-#include <console.h>
-#include <environment.h>
-#include <fdt_support.h>
-#include <generic-phy.h>
-#include <g_dnl.h>
-#include <i2c.h>
-#include <led.h>
-#include <misc.h>
-#include <mtd.h>
-#include <mtd_node.h>
-#include <netdev.h>
-#include <phy.h>
-#include <remoteproc.h>
-#include <reset.h>
-#include <syscon.h>
-#include <usb.h>
-#include <watchdog.h>
-#include <asm/io.h>
-#include <asm/gpio.h>
-#include <asm/arch/stm32.h>
-#include <asm/arch/stm32mp1_smc.h>
-#include <asm/arch/sys_proto.h>
-#include <jffs2/load_kernel.h>
-#include <power/regulator.h>
-#include <usb/dwc2_udc.h>
-
-/* SYSCFG registers */
-#define SYSCFG_BOOTR		0x00
-#define SYSCFG_PMCSETR		0x04
-#define SYSCFG_IOCTRLSETR	0x18
-#define SYSCFG_ICNR		0x1C
-#define SYSCFG_CMPCR		0x20
-#define SYSCFG_CMPENSETR	0x24
-#define SYSCFG_PMCCLRR		0x44
-
-#define SYSCFG_BOOTR_BOOT_MASK		GENMASK(2, 0)
-#define SYSCFG_BOOTR_BOOTPD_SHIFT	4
-
-#define SYSCFG_IOCTRLSETR_HSLVEN_TRACE		BIT(0)
-#define SYSCFG_IOCTRLSETR_HSLVEN_QUADSPI	BIT(1)
-#define SYSCFG_IOCTRLSETR_HSLVEN_ETH		BIT(2)
-#define SYSCFG_IOCTRLSETR_HSLVEN_SDMMC		BIT(3)
-#define SYSCFG_IOCTRLSETR_HSLVEN_SPI		BIT(4)
-
-#define SYSCFG_CMPCR_SW_CTRL		BIT(1)
-#define SYSCFG_CMPCR_READY		BIT(8)
-
-#define SYSCFG_CMPENSETR_MPU_EN		BIT(0)
-
-#define SYSCFG_PMCSETR_ETH_CLK_SEL	BIT(16)
-#define SYSCFG_PMCSETR_ETH_REF_CLK_SEL	BIT(17)
-
-#define SYSCFG_PMCSETR_ETH_SELMII	BIT(20)
-
-#define SYSCFG_PMCSETR_ETH_SEL_MASK	GENMASK(23, 21)
-#define SYSCFG_PMCSETR_ETH_SEL_GMII_MII	(0 << 21)
-#define SYSCFG_PMCSETR_ETH_SEL_RGMII	(1 << 21)
-#define SYSCFG_PMCSETR_ETH_SEL_RMII	(4 << 21)
-
-/*
- * Get a global data pointer
- */
-DECLARE_GLOBAL_DATA_PTR;
-
-#define USB_LOW_THRESHOLD_UV		200000
-#define USB_WARNING_LOW_THRESHOLD_UV	660000
-#define USB_START_LOW_THRESHOLD_UV	1230000
-#define USB_START_HIGH_THRESHOLD_UV	2150000
-
-int checkboard(void)
-{
-	int ret;
-	char *mode;
-	u32 otp;
-	struct udevice *dev;
-	const char *fdt_compat;
-	int fdt_compat_len;
-
-	if (IS_ENABLED(CONFIG_STM32MP1_OPTEE))
-		mode = "op-tee";
-	else if (IS_ENABLED(CONFIG_STM32MP1_TRUSTED))
-		mode = "trusted";
-	else
-		mode = "basic";
-
-	printf("Board: stm32mp1 in %s mode", mode);
-	fdt_compat = fdt_getprop(gd->fdt_blob, 0, "compatible",
-				 &fdt_compat_len);
-	if (fdt_compat && fdt_compat_len)
-		printf(" (%s)", fdt_compat);
-	puts("\n");
-
-	ret = uclass_get_device_by_driver(UCLASS_MISC,
-					  DM_GET_DRIVER(stm32mp_bsec),
-					  &dev);
-
-	if (!ret)
-		ret = misc_read(dev, STM32_BSEC_SHADOW(BSEC_OTP_BOARD),
-				&otp, sizeof(otp));
-	if (!ret && otp) {
-		printf("Board: MB%04x Var%d Rev.%c-%02d\n",
-		       otp >> 16,
-		       (otp >> 12) & 0xF,
-		       ((otp >> 8) & 0xF) - 1 + 'A',
-		       otp & 0xF);
-	}
-
-	return 0;
-}
-
-static void board_key_check(void)
-{
-#if defined(CONFIG_FASTBOOT) || defined(CONFIG_CMD_STM32PROG)
-	ofnode node;
-	struct gpio_desc gpio;
-	enum forced_boot_mode boot_mode = BOOT_NORMAL;
-
-	node = ofnode_path("/config");
-	if (!ofnode_valid(node)) {
-		debug("%s: no /config node?\n", __func__);
-		return;
-	}
-#ifdef CONFIG_FASTBOOT
-	if (gpio_request_by_name_nodev(node, "st,fastboot-gpios", 0,
-				       &gpio, GPIOD_IS_IN)) {
-		debug("%s: could not find a /config/st,fastboot-gpios\n",
-		      __func__);
-	} else {
-		if (dm_gpio_get_value(&gpio)) {
-			puts("Fastboot key pressed, ");
-			boot_mode = BOOT_FASTBOOT;
-		}
-
-		dm_gpio_free(NULL, &gpio);
-	}
-#endif
-#ifdef CONFIG_CMD_STM32PROG
-	if (gpio_request_by_name_nodev(node, "st,stm32prog-gpios", 0,
-				       &gpio, GPIOD_IS_IN)) {
-		debug("%s: could not find a /config/st,stm32prog-gpios\n",
-		      __func__);
-	} else {
-		if (dm_gpio_get_value(&gpio)) {
-			puts("STM32Programmer key pressed, ");
-			boot_mode = BOOT_STM32PROG;
-		}
-		dm_gpio_free(NULL, &gpio);
-	}
-#endif
-
-	if (boot_mode != BOOT_NORMAL) {
-		puts("entering download mode...\n");
-		clrsetbits_le32(TAMP_BOOT_CONTEXT,
-				TAMP_BOOT_FORCED_MASK,
-				boot_mode);
-	}
-#endif
-}
-
-#if defined(CONFIG_USB_GADGET) && defined(CONFIG_USB_GADGET_DWC2_OTG)
-
-/*
- * DWC2 registers should be defined in drivers
- * OTG: drivers/usb/gadget/dwc2_udc_otg_regs.h
- * HOST: ./drivers/usb/host/dwc2.h
- */
-#define DWC2_GOTGCTL_OFFSET		0x00
-#define DWC2_GGPIO_OFFSET		0x38
-
-#define DWC2_GGPIO_VBUS_SENSING		BIT(21)
-
-#define DWC2_GOTGCTL_AVALIDOVEN		BIT(4)
-#define DWC2_GOTGCTL_AVALIDOVVAL	BIT(5)
-#define DWC2_GOTGCTL_BVALIDOVEN		BIT(6)
-#define DWC2_GOTGCTL_BVALIDOVVAL	BIT(7)
-#define DWC2_GOTGCTL_BSVLD		BIT(19)
-
-#define STM32MP_GUSBCFG			0x40002407
-
-static struct dwc2_plat_otg_data stm32mp_otg_data = {
-	.regs_otg = FDT_ADDR_T_NONE,
-	.usb_gusbcfg = STM32MP_GUSBCFG,
-	.priv = NULL, /* pointer to udevice for stusb1600 when present */
-};
-
-static struct reset_ctl usbotg_reset;
-
-/* STMicroelectronics STUSB1600 Type-C controller */
-#define STUSB1600_CC_CONNECTION_STATUS		0x0E
-
-/* STUSB1600_CC_CONNECTION_STATUS bitfields */
-#define STUSB1600_CC_ATTACH			BIT(0)
-
-static int stusb1600_init(ofnode node)
-{
-	struct udevice *dev, *bus;
-	int ret;
-	u32 chip_addr;
-
-	ret = ofnode_read_u32(node, "reg", &chip_addr);
-	if (ret)
-		return -EINVAL;
-
-	ret = uclass_get_device_by_ofnode(UCLASS_I2C, ofnode_get_parent(node),
-					  &bus);
-	if (ret) {
-		printf("bus for stusb1600 not found\n");
-		return -ENODEV;
-	}
-
-	ret = dm_i2c_probe(bus, chip_addr, 0, &dev);
-	if (!ret)
-		stm32mp_otg_data.priv = dev;
-
-	return ret;
-}
-
-static int stusb1600_cable_connected(void)
-{
-	struct udevice *stusb1600_dev = stm32mp_otg_data.priv;
-	u8 status;
-
-	if (dm_i2c_read(stusb1600_dev,
-			STUSB1600_CC_CONNECTION_STATUS,
-			&status, 1))
-		return 0;
-
-	return status & STUSB1600_CC_ATTACH;
-}
-
-static void board_usbotg_init(void)
-{
-	ofnode usb1600_node;
-	int node;
-	int count;
-	struct fdtdec_phandle_args args;
-	struct udevice *dev;
-	const void *blob = gd->fdt_blob;
-	struct clk clk;
-
-	/* find the usb otg node */
-	node = fdt_node_offset_by_compatible(blob, -1, "snps,dwc2");
-	if (node < 0) {
-		debug("Not found usb_otg device\n");
-		return;
-	}
-
-	if (!fdtdec_get_is_enabled(blob, node)) {
-		debug("stm32 usbotg is disabled in the device tree\n");
-		return;
-	}
-
-	/* Enable clock */
-	if (fdtdec_parse_phandle_with_args(blob, node, "clocks",
-					   "#clock-cells", 0, 0, &args)) {
-		debug("usbotg has no clocks defined in the device tree\n");
-		return;
-	}
-
-	if (uclass_get_device_by_of_offset(UCLASS_CLK, args.node, &dev))
-		return;
-
-	if (args.args_count != 1)
-		return;
-
-	clk.dev = dev;
-	clk.id = args.args[0];
-
-	if (clk_enable(&clk)) {
-		debug("Failed to enable usbotg clock\n");
-		return;
-	}
-
-	/* Reset */
-	if (fdtdec_parse_phandle_with_args(blob, node, "resets",
-					   "#reset-cells", 0, 0, &args)) {
-		debug("usbotg has no resets defined in the device tree\n");
-		goto clk_err;
-	}
-
-	if ((uclass_get_device_by_of_offset(UCLASS_RESET, args.node, &dev)) ||
-	    args.args_count != 1)
-		goto clk_err;
-
-	usbotg_reset.dev = dev;
-	usbotg_reset.id = args.args[0];
-
-	/* Phy */
-	if (!(fdtdec_parse_phandle_with_args(blob, node, "phys",
-					     "#phy-cells", 0, 0, &args))) {
-		stm32mp_otg_data.phy_of_node =
-			fdt_parent_offset(blob, args.node);
-		if (stm32mp_otg_data.phy_of_node <= 0) {
-			debug("Not found usbo phy device\n");
-			goto clk_err;
-		}
-		stm32mp_otg_data.regs_phy = fdtdec_get_uint(blob, args.node,
-							    "reg", -1);
-	}
-
-	/* Parse and store data needed for gadget */
-	stm32mp_otg_data.regs_otg = fdtdec_get_addr(blob, node, "reg");
-	if (stm32mp_otg_data.regs_otg == FDT_ADDR_T_NONE) {
-		debug("usbotg: can't get base address\n");
-		goto clk_err;
-	}
-
-	stm32mp_otg_data.rx_fifo_sz = fdtdec_get_int(blob, node,
-						     "g-rx-fifo-size", 0);
-	stm32mp_otg_data.np_tx_fifo_sz = fdtdec_get_int(blob, node,
-							"g-np-tx-fifo-size", 0);
-
-	count = fdtdec_get_int_array_count(blob, node, "g-tx-fifo-size",
-			&stm32mp_otg_data.tx_fifo_sz_array[DWC2_SIZE_OFFS],
-			ARRAY_SIZE(stm32mp_otg_data.tx_fifo_sz_array));
-
-	if (count != -FDT_ERR_NOTFOUND)
-		stm32mp_otg_data.tx_fifo_sz_array[DWC2_SIZE_NB_OFFS] = count;
-
-	/* if node stusb1600 is present, means DK1 or DK2 board */
-	usb1600_node = ofnode_by_compatible(ofnode_null(), "st,stusb1600");
-	if (ofnode_valid(usb1600_node)) {
-		stusb1600_init(usb1600_node);
-		return;
-	}
-
-	/* Enable voltage level detector */
-	if (!(fdtdec_parse_phandle_with_args(blob, node, "usb33d-supply",
-					     NULL, 0, 0, &args)))
-		if (!uclass_get_device_by_of_offset(UCLASS_REGULATOR,
-						    args.node, &dev))
-			if (regulator_set_enable(dev, true)) {
-				debug("Failed to enable usb33d\n");
-				goto clk_err;
-			}
-
-	return;
-
-clk_err:
-	clk_disable(&clk);
-}
-
-int board_usb_init(int index, enum usb_init_type init)
-{
-	if (init == USB_INIT_HOST)
-		return 0;
-
-	if (stm32mp_otg_data.regs_otg == FDT_ADDR_T_NONE)
-		return -EINVAL;
-
-	/* Reset usbotg */
-	reset_assert(&usbotg_reset);
-	udelay(2);
-	reset_deassert(&usbotg_reset);
-
-	/* if the board embed an USB1600 chip */
-	if (stm32mp_otg_data.priv)
-		/* Override A/B session valid bits */
-		stm32mp_otg_data.usb_gotgctl = DWC2_GOTGCTL_AVALIDOVEN |
-					       DWC2_GOTGCTL_AVALIDOVVAL |
-					       DWC2_GOTGCTL_BVALIDOVEN |
-					       DWC2_GOTGCTL_BVALIDOVVAL;
-	else
-		/* Enable vbus sensing */
-		setbits_le32(stm32mp_otg_data.regs_otg + DWC2_GGPIO_OFFSET,
-			     DWC2_GGPIO_VBUS_SENSING);
-
-	return dwc2_udc_probe(&stm32mp_otg_data);
-}
-
-int g_dnl_board_usb_cable_connected(void)
-{
-	if (stm32mp_otg_data.priv)
-		return stusb1600_cable_connected();
-
-	return readl(stm32mp_otg_data.regs_otg + DWC2_GOTGCTL_OFFSET) &
-		DWC2_GOTGCTL_BSVLD;
-}
-
-#define STM32MP1_G_DNL_DFU_PRODUCT_NUM 0xdf11
-#define STM32MP1_G_DNL_FASTBOOT_PRODUCT_NUM 0x0afb
-
-int g_dnl_bind_fixup(struct usb_device_descriptor *dev, const char *name)
-{
-	if (!strcmp(name, "usb_dnl_dfu"))
-		put_unaligned(STM32MP1_G_DNL_DFU_PRODUCT_NUM, &dev->idProduct);
-	else if (!strcmp(name, "usb_dnl_fastboot"))
-		put_unaligned(STM32MP1_G_DNL_FASTBOOT_PRODUCT_NUM,
-			      &dev->idProduct);
-	else
-		put_unaligned(CONFIG_USB_GADGET_PRODUCT_NUM, &dev->idProduct);
-
-	return 0;
-}
-#endif /* CONFIG_USB_GADGET */
-
-/* board interface eth init */
-/* this is a weak define that we are overriding */
-int board_interface_eth_init(int interface_type, bool eth_clk_sel_reg,
-			     bool eth_ref_clk_sel_reg)
-{
-	u8 *syscfg;
-	u32 value;
-
-	syscfg = (u8 *)syscon_get_first_range(STM32MP_SYSCON_SYSCFG);
-
-	if (!syscfg)
-		return -ENODEV;
-
-	switch (interface_type) {
-	case PHY_INTERFACE_MODE_MII:
-		value = SYSCFG_PMCSETR_ETH_SEL_GMII_MII |
-			SYSCFG_PMCSETR_ETH_REF_CLK_SEL;
-		debug("%s: PHY_INTERFACE_MODE_MII\n", __func__);
-		break;
-	case PHY_INTERFACE_MODE_GMII:
-		if (eth_clk_sel_reg)
-			value = SYSCFG_PMCSETR_ETH_SEL_GMII_MII |
-				SYSCFG_PMCSETR_ETH_CLK_SEL;
-		else
-			value = SYSCFG_PMCSETR_ETH_SEL_GMII_MII;
-		debug("%s: PHY_INTERFACE_MODE_GMII\n", __func__);
-		break;
-	case PHY_INTERFACE_MODE_RMII:
-		if (eth_ref_clk_sel_reg)
-			value = SYSCFG_PMCSETR_ETH_SEL_RMII |
-				SYSCFG_PMCSETR_ETH_REF_CLK_SEL;
-		else
-			value = SYSCFG_PMCSETR_ETH_SEL_RMII;
-		debug("%s: PHY_INTERFACE_MODE_RMII\n", __func__);
-		break;
-	case PHY_INTERFACE_MODE_RGMII:
-	case PHY_INTERFACE_MODE_RGMII_ID:
-	case PHY_INTERFACE_MODE_RGMII_RXID:
-	case PHY_INTERFACE_MODE_RGMII_TXID:
-		if (eth_clk_sel_reg)
-			value = SYSCFG_PMCSETR_ETH_SEL_RGMII |
-				SYSCFG_PMCSETR_ETH_CLK_SEL;
-		else
-			value = SYSCFG_PMCSETR_ETH_SEL_RGMII;
-		debug("%s: PHY_INTERFACE_MODE_RGMII\n", __func__);
-		break;
-	default:
-		debug("%s: Do not manage %d interface\n",
-		      __func__, interface_type);
-		/* Do not manage others interfaces */
-		return -EINVAL;
-	}
-
-	/* clear and set ETH configuration bits */
-	writel(SYSCFG_PMCSETR_ETH_SEL_MASK | SYSCFG_PMCSETR_ETH_SELMII |
-	       SYSCFG_PMCSETR_ETH_REF_CLK_SEL | SYSCFG_PMCSETR_ETH_CLK_SEL,
-	       syscfg + SYSCFG_PMCCLRR);
-	writel(value, syscfg + SYSCFG_PMCSETR);
-
-	return 0;
-}
-
-/* board dependend phy configuration */
-int board_phy_config(struct phy_device *phydev)
-{
-	unsigned int mii_reg;
-	pr_debug("enter %s\n", __func__);
-
-	if ((phydev->phy_id & 0xFFFFFFF0) == 0x00221560){
-		/* Micrel KSZ8081 */
-
-		printf("Found Micrel KSZ8081 PHY, enable 50MHz RMII mode\n");
-
-		/* set RMII 50MHz clock mode for phy */
-		mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, 0x1F);
-		phy_write(phydev, MDIO_DEVAD_NONE, 0x1F, mii_reg | 0x80);
-	}
-
-	/* call driver function */
-	if (phydev->drv->config)
-		return phydev->drv->config(phydev);
-	return 0;
-}
-
-#ifdef CONFIG_LED
-static int get_led(struct udevice **dev, char *led_string)
-{
-	char *led_name;
-	int ret;
-
-	led_name = fdtdec_get_config_string(gd->fdt_blob, led_string);
-	if (!led_name) {
-		pr_debug("%s: could not find %s config string\n",
-			 __func__, led_string);
-		return -ENOENT;
-	}
-	ret = led_get_by_label(led_name, dev);
-	if (ret) {
-		debug("%s: get=%d\n", __func__, ret);
-		return ret;
-	}
-
-	return 0;
-}
-
-static int setup_led(enum led_state_t cmd)
-{
-	struct udevice *dev;
-	int ret;
-
-	ret = get_led(&dev, "u-boot,boot-led");
-	if (ret)
-		return ret;
-
-	ret = led_set_state(dev, cmd);
-	return ret;
-}
-#endif /* CONFIG_LED */
-
-static void __maybe_unused led_error_blink(u32 nb_blink)
-{
-#ifdef CONFIG_LED
-	int ret;
-	struct udevice *led;
-	u32 i;
-#endif
-
-	if (!nb_blink)
-		return;
-
-#ifdef CONFIG_LED
-	ret = get_led(&led, "u-boot,error-led");
-	if (!ret) {
-		/* make u-boot,error-led blinking */
-		/* if U32_MAX and 125ms interval, for 17.02 years */
-		for (i = 0; i < 2 * nb_blink; i++) {
-			led_set_state(led, LEDST_TOGGLE);
-			mdelay(125);
-			WATCHDOG_RESET();
-		}
-		led_set_state(led, LEDST_ON);
-	}
-#endif
-
-	/* infinite: the boot process must be stopped */
-	if (nb_blink == U32_MAX)
-		hang();
-}
-
-#ifdef CONFIG_ADC
-static int board_check_usb_power(void)
-{
-	struct ofnode_phandle_args adc_args;
-	struct udevice *adc;
-	ofnode node;
-	unsigned int raw;
-	int max_uV = 0;
-	int min_uV = USB_START_HIGH_THRESHOLD_UV;
-	int ret, uV, adc_count;
-	u32 nb_blink;
-	u8 i;
-	node = ofnode_path("/config");
-	if (!ofnode_valid(node)) {
-		debug("%s: no /config node?\n", __func__);
-		return -ENOENT;
-	}
-
-	/*
-	 * Retrieve the ADC channels devices and get measurement
-	 * for each of them
-	 */
-	adc_count = ofnode_count_phandle_with_args(node, "st,adc_usb_pd",
-						   "#io-channel-cells");
-	if (adc_count < 0) {
-		if (adc_count == -ENOENT)
-			return 0;
-
-		pr_err("%s: can't find adc channel (%d)\n", __func__,
-		       adc_count);
-
-		return adc_count;
-	}
-
-	for (i = 0; i < adc_count; i++) {
-		if (ofnode_parse_phandle_with_args(node, "st,adc_usb_pd",
-						   "#io-channel-cells", 0, i,
-						   &adc_args)) {
-			pr_debug("%s: can't find /config/st,adc_usb_pd\n",
-				 __func__);
-			return 0;
-		}
-
-		ret = uclass_get_device_by_ofnode(UCLASS_ADC, adc_args.node,
-						  &adc);
-
-		if (ret) {
-			pr_err("%s: Can't get adc device(%d)\n", __func__,
-			       ret);
-			return ret;
-		}
-
-		ret = adc_channel_single_shot(adc->name, adc_args.args[0],
-					      &raw);
-		if (ret) {
-			pr_err("%s: single shot failed for %s[%d]!\n",
-			       __func__, adc->name, adc_args.args[0]);
-			return ret;
-		}
-		/* Convert to uV */
-		if (!adc_raw_to_uV(adc, raw, &uV)) {
-			if (uV > max_uV)
-				max_uV = uV;
-			if (uV < min_uV)
-				min_uV = uV;
-			pr_debug("%s: %s[%02d] = %u, %d uV\n", __func__,
-				 adc->name, adc_args.args[0], raw, uV);
-		} else {
-			pr_err("%s: Can't get uV value for %s[%d]\n",
-			       __func__, adc->name, adc_args.args[0]);
-		}
-	}
-
-	/*
-	 * If highest value is inside 1.23 Volts and 2.10 Volts, that means
-	 * board is plugged on an USB-C 3A power supply and boot process can
-	 * continue.
-	 */
-	if (max_uV > USB_START_LOW_THRESHOLD_UV &&
-	    max_uV <= USB_START_HIGH_THRESHOLD_UV &&
-	    min_uV <= USB_LOW_THRESHOLD_UV)
-		return 0;
-
-	pr_err("****************************************************\n");
-
-	/*
-	 * If highest and lowest value are either both below
-	 * USB_LOW_THRESHOLD_UV or both above USB_LOW_THRESHOLD_UV, that
-	 * means USB TYPE-C is in unattached mode, this is an issue, make
-	 * u-boot,error-led blinking and stop boot process.
-	 */
-	if ((max_uV > USB_LOW_THRESHOLD_UV &&
-	     min_uV > USB_LOW_THRESHOLD_UV) ||
-	     (max_uV <= USB_LOW_THRESHOLD_UV &&
-	     min_uV <= USB_LOW_THRESHOLD_UV)) {
-		pr_err("* ERROR USB TYPE-C connection in unattached mode   *\n");
-		pr_err("* Check that USB TYPE-C cable is correctly plugged *\n");
-		/* with 125ms interval, led will blink for 17.02 years ....*/
-		nb_blink = U32_MAX;
-	}
-
-	if (max_uV > USB_LOW_THRESHOLD_UV &&
-	    max_uV <= USB_WARNING_LOW_THRESHOLD_UV &&
-	    min_uV <= USB_LOW_THRESHOLD_UV) {
-		pr_err("*        WARNING 500mA power supply detected       *\n");
-		nb_blink = 2;
-	}
-
-	if (max_uV > USB_WARNING_LOW_THRESHOLD_UV &&
-	    max_uV <= USB_START_LOW_THRESHOLD_UV &&
-	    min_uV <= USB_LOW_THRESHOLD_UV) {
-		pr_err("*       WARNING 1.5mA power supply detected        *\n");
-		nb_blink = 3;
-	}
-
-	/*
-	 * If highest value is above 2.15 Volts that means that the USB TypeC
-	 * supplies more than 3 Amp, this is not compliant with TypeC specification
-	 */
-	if (max_uV > USB_START_HIGH_THRESHOLD_UV) {
-		pr_err("*      USB TYPE-C charger not compliant with       *\n");
-		pr_err("*                   specification                  *\n");
-		pr_err("****************************************************\n\n");
-		/* with 125ms interval, led will blink for 17.02 years ....*/
-		nb_blink = U32_MAX;
-	} else {
-		pr_err("*     Current too low, use a 3A power supply!      *\n");
-		pr_err("****************************************************\n\n");
-	}
-
-	led_error_blink(nb_blink);
-
-	return 0;
-}
-#endif /* CONFIG_ADC */
-
-static void sysconf_init(void)
-{
-#ifndef CONFIG_STM32MP1_TRUSTED
-	u8 *syscfg;
-#ifdef CONFIG_DM_REGULATOR
-	struct udevice *pwr_dev;
-	struct udevice *pwr_reg;
-	struct udevice *dev;
-	int ret;
-	u32 otp = 0;
-#endif
-	u32 bootr;
-
-	syscfg = (u8 *)syscon_get_first_range(STM32MP_SYSCON_SYSCFG);
-	debug("SYSCFG: init @0x%p\n", syscfg);
-
-	/* interconnect update : select master using the port 1 */
-	/* LTDC = AXI_M9 */
-	/* GPU  = AXI_M8 */
-	/* today information is hardcoded in U-Boot */
-	writel(BIT(9), syscfg + SYSCFG_ICNR);
-	debug("[0x%x] SYSCFG.icnr = 0x%08x (LTDC and GPU)\n",
-	      (u32)syscfg + SYSCFG_ICNR, readl(syscfg + SYSCFG_ICNR));
-
-	/* disable Pull-Down for boot pin connected to VDD */
-	bootr = readl(syscfg + SYSCFG_BOOTR);
-	bootr &= ~(SYSCFG_BOOTR_BOOT_MASK << SYSCFG_BOOTR_BOOTPD_SHIFT);
-	bootr |= (bootr & SYSCFG_BOOTR_BOOT_MASK) << SYSCFG_BOOTR_BOOTPD_SHIFT;
-	writel(bootr, syscfg + SYSCFG_BOOTR);
-	debug("[0x%x] SYSCFG.bootr = 0x%08x\n",
-	      (u32)syscfg + SYSCFG_BOOTR, readl(syscfg + SYSCFG_BOOTR));
-
-#ifdef CONFIG_DM_REGULATOR
-	/* High Speed Low Voltage Pad mode Enable for SPI, SDMMC, ETH, QSPI
-	 * and TRACE. Needed above ~50MHz and conditioned by AFMUX selection.
-	 * The customer will have to disable this for low frequencies
-	 * or if AFMUX is selected but the function not used, typically for
-	 * TRACE. Otherwise, impact on power consumption.
-	 *
-	 * WARNING:
-	 *   enabling High Speed mode while VDD>2.7V
-	 *   with the OTP product_below_2v5 (OTP 18, BIT 13)
-	 *   erroneously set to 1 can damage the IC!
-	 *   => U-Boot set the register only if VDD < 2.7V (in DT)
-	 *      but this value need to be consistent with board design
-	 */
-	ret = syscon_get_by_driver_data(STM32MP_SYSCON_PWR, &pwr_dev);
-	if (!ret) {
-		ret = uclass_get_device_by_driver(UCLASS_MISC,
-						  DM_GET_DRIVER(stm32mp_bsec),
-						  &dev);
-		if (ret) {
-			pr_err("Can't find stm32mp_bsec driver\n");
-			return;
-		}
-
-		ret = misc_read(dev, STM32_BSEC_SHADOW(18), &otp, 4);
-		if (!ret)
-			otp = otp & BIT(13);
-
-		ret = uclass_get_device_by_driver(UCLASS_PMIC,
-						  DM_GET_DRIVER(stm32mp_pwr_pmic),
-						  &dev);
-
-		/* get VDD = vdd-supply */
-		ret = device_get_supply_regulator(dev, "vdd-supply", &pwr_reg);
-
-		/* check if VDD is Low Voltage */
-		if (!ret) {
-			if (regulator_get_value(pwr_reg) < 2700000) {
-				writel(SYSCFG_IOCTRLSETR_HSLVEN_TRACE |
-				       SYSCFG_IOCTRLSETR_HSLVEN_QUADSPI |
-				       SYSCFG_IOCTRLSETR_HSLVEN_ETH |
-				       SYSCFG_IOCTRLSETR_HSLVEN_SDMMC |
-				       SYSCFG_IOCTRLSETR_HSLVEN_SPI,
-				       syscfg + SYSCFG_IOCTRLSETR);
-
-				if (!otp)
-					pr_err("product_below_2v5=0: HSLVEN protected by HW\n");
-			} else {
-				if (otp)
-					pr_err("product_below_2v5=1: HSLVEN update is destructive, no update as VDD>2.7V\n");
-			}
-		} else {
-			debug("VDD unknown");
-		}
-	}
-#endif
-	debug("[0x%x] SYSCFG.IOCTRLSETR = 0x%08x\n",
-	      (u32)syscfg + SYSCFG_IOCTRLSETR,
-	      readl(syscfg + SYSCFG_IOCTRLSETR));
-
-	/* activate automatic I/O compensation
-	 * warning: need to ensure CSI enabled and ready in clock driver
-	 */
-	writel(SYSCFG_CMPENSETR_MPU_EN, syscfg + SYSCFG_CMPENSETR);
-
-	while (!(readl(syscfg + SYSCFG_CMPCR) & SYSCFG_CMPCR_READY))
-		;
-	clrbits_le32(syscfg + SYSCFG_CMPCR, SYSCFG_CMPCR_SW_CTRL);
-
-	debug("[0x%x] SYSCFG.cmpcr = 0x%08x\n",
-	      (u32)syscfg + SYSCFG_CMPCR, readl(syscfg + SYSCFG_CMPCR));
-#endif
-}
-
-#ifdef CONFIG_DM_REGULATOR
-/* Fix to make I2C1 usable on DK2 for touchscreen usage in kernel */
-static int dk2_i2c1_fix(void)
-{
-	ofnode node;
-	struct gpio_desc hdmi, audio;
-	int ret = 0;
-
-	node = ofnode_path("/soc/i2c@40012000/hdmi-transmitter@39");
-	if (!ofnode_valid(node)) {
-		pr_debug("%s: no hdmi-transmitter@39 ?\n", __func__);
-		return -ENOENT;
-	}
-
-	if (gpio_request_by_name_nodev(node, "reset-gpios", 0,
-				       &hdmi, GPIOD_IS_OUT)) {
-		pr_debug("%s: could not find reset-gpios\n",
-			 __func__);
-		return -ENOENT;
-	}
-
-	node = ofnode_path("/soc/i2c@40012000/cs42l51@4a");
-	if (!ofnode_valid(node)) {
-		pr_debug("%s: no cs42l51@4a ?\n", __func__);
-		return -ENOENT;
-	}
-
-	if (gpio_request_by_name_nodev(node, "reset-gpios", 0,
-				       &audio, GPIOD_IS_OUT)) {
-		pr_debug("%s: could not find reset-gpios\n",
-			 __func__);
-		return -ENOENT;
-	}
-
-	/* before power up, insure that HDMI anh AUDIO IC is under reset */
-	ret = dm_gpio_set_value(&hdmi, 1);
-	if (ret) {
-		pr_err("%s: can't set_value for hdmi_nrst gpio", __func__);
-		goto error;
-	}
-	ret = dm_gpio_set_value(&audio, 1);
-	if (ret) {
-		pr_err("%s: can't set_value for audio_nrst gpio", __func__);
-		goto error;
-	}
-
-	/* power-up audio IC */
-	regulator_autoset_by_name("v1v8_audio", NULL);
-
-	/* power-up HDMI IC */
-	regulator_autoset_by_name("v1v2_hdmi", NULL);
-	regulator_autoset_by_name("v3v3_hdmi", NULL);
-
-error:
-	return ret;
-}
-#endif
-
-enum env_location env_get_location(enum env_operation op, int prio)
-{
-	u32 bootmode = get_bootmode();
-
-	if (prio)
-		return ENVL_UNKNOWN;
-
-	switch (bootmode & TAMP_BOOT_DEVICE_MASK) {
-	case BOOT_FLASH_SD:
-		return ENVL_MMC;
-	case BOOT_FLASH_EMMC:
-	case BOOT_FLASH_NOR:
-		return ENVL_SPI_FLASH;
-	default:
-		return ENVL_NOWHERE;
-	}
-}
-
-#if defined(CONFIG_ENV_IS_IN_EXT4)
-const char *env_ext4_get_intf(void)
-{
-	u32 bootmode = get_bootmode();
-
-	switch (bootmode & TAMP_BOOT_DEVICE_MASK) {
-	case BOOT_FLASH_SD:
-	case BOOT_FLASH_EMMC:
-		return "mmc";
-	default:
-		return "";
-	}
-}
-
-const char *env_ext4_get_dev_part(void)
-{
-	static char *const dev_part[] = {"0:auto", "1:auto", "2:auto"};
-	u32 bootmode = get_bootmode();
-
-	return dev_part[(bootmode & TAMP_BOOT_INSTANCE_MASK) - 1];
-}
-#endif
-
-static __maybe_unused bool board_is_dk2(void)
-{
-	if (CONFIG_IS_ENABLED(TARGET_STM32MP157C_DK2) &&
-	    of_machine_is_compatible("st,stm32mp157c-dk2"))
-		return true;
-
-	return false;
-}
-
-/* board dependent setup after realloc */
-int board_init(void)
-{
-	struct udevice *dev;
-
-	/* address of boot parameters */
-	gd->bd->bi_boot_params = STM32_DDR_BASE + 0x100;
-
-	/* probe all PINCTRL for hog */
-	for (uclass_first_device(UCLASS_PINCTRL, &dev);
-	     dev;
-	     uclass_next_device(&dev)) {
-		pr_debug("probe pincontrol = %s\n", dev->name);
-	}
-
-	board_key_check();
-
-	if (IS_ENABLED(CONFIG_LED))
-		led_default_state();
-
-#ifdef CONFIG_DM_REGULATOR
-	if (board_is_dk2())
-		dk2_i2c1_fix();
-
-	regulators_enable_boot_on(_DEBUG);
-#endif
-
-#ifdef CONFIG_ADC
-	board_check_usb_power();
-#endif /* CONFIG_ADC */
-
-	sysconf_init();
-
-#if defined(CONFIG_USB_GADGET) && defined(CONFIG_USB_GADGET_DWC2_OTG)
-	board_usbotg_init();
-#endif
-
-	return 0;
-}
-
-int board_late_init(void)
-{
-
-	char *boot_device;
-#ifdef CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG
-	const void *fdt_compat;
-	const void *board_name;
-	int fdt_compat_len;
-	int ret;
-	u32 otp;
-	struct udevice *dev;
-	char buf[10];
-
-	fdt_compat = fdt_getprop(gd->fdt_blob, 0, "compatible",
-				 &fdt_compat_len);
-	if (fdt_compat && fdt_compat_len) {
-		// remove vendor tag (separated by ',') from compat value
-		board_name = strchr(fdt_compat, ',');
-		if (NULL == board_name){
-			board_name = fdt_compat;
-		}
-		else{
-			board_name++;
-		}
-		env_set("board_name", board_name);
-	}
-	ret = uclass_get_device_by_driver(UCLASS_MISC,
-					  DM_GET_DRIVER(stm32mp_bsec),
-					  &dev);
-
-	if (!ret)
-		ret = misc_read(dev, STM32_BSEC_SHADOW(BSEC_OTP_BOARD),
-				&otp, sizeof(otp));
-	if (!ret && otp) {
-		snprintf(buf, sizeof(buf), "0x%04x", otp >> 16);
-		env_set("board_id", buf);
-
-		snprintf(buf, sizeof(buf), "0x%04x",
-			 ((otp >> 8) & 0xF) - 1 + 0xA);
-		env_set("board_rev", buf);
-	}
-#endif
-
-	/* Check the boot-source to disable bootdelay */
-	boot_device = env_get("boot_device");
-	if (!strcmp(boot_device, "serial") || !strcmp(boot_device, "usb"))
-		env_set("bootdelay", "0");
-
-	return 0;
-}
-
-void board_quiesce_devices(void)
-{
-#ifdef CONFIG_LED
-	setup_led(LEDST_OFF);
-#endif
-}
-
-#ifdef CONFIG_SYS_MTDPARTS_RUNTIME
-
-#define MTDPARTS_LEN		256
-#define MTDIDS_LEN		128
-
-/**
- * The mtdparts_nand0 and mtdparts_nor0 variable tends to be long.
- * If we need to access it before the env is relocated, then we need
- * to use our own stack buffer. gd->env_buf will be too small.
- *
- * @param buf temporary buffer pointer MTDPARTS_LEN long
- * @return mtdparts variable string, NULL if not found
- */
-static const char *env_get_mtdparts(const char *str, char *buf)
-{
-	if (gd->flags & GD_FLG_ENV_READY)
-		return env_get(str);
-	if (env_get_f(str, buf, MTDPARTS_LEN) != -1)
-		return buf;
-	return NULL;
-}
-
-/**
- * update the variables "mtdids" and "mtdparts" with content of mtdparts_<dev>
- */
-static void board_get_mtdparts(const char *dev,
-			       char *mtdids,
-			       char *mtdparts)
-{
-	char env_name[32] = "mtdparts_";
-	char tmp_mtdparts[MTDPARTS_LEN];
-	const char *tmp;
-
-	/* name of env variable to read = mtdparts_<dev> */
-	strcat(env_name, dev);
-	tmp = env_get_mtdparts(env_name, tmp_mtdparts);
-	if (tmp) {
-		/* mtdids: "<dev>=<dev>, ...." */
-		if (mtdids[0] != '\0')
-			strcat(mtdids, ",");
-		strcat(mtdids, dev);
-		strcat(mtdids, "=");
-		strcat(mtdids, dev);
-
-		/* mtdparts: "mtdparts=<dev>:<mtdparts_<dev>>;..." */
-		if (mtdparts[0] != '\0')
-			strncat(mtdparts, ";", MTDPARTS_LEN);
-		else
-			strcat(mtdparts, "mtdparts=");
-		strncat(mtdparts, dev, MTDPARTS_LEN);
-		strncat(mtdparts, ":", MTDPARTS_LEN);
-		strncat(mtdparts, tmp, MTDPARTS_LEN);
-	}
-}
-
-void board_mtdparts_default(const char **mtdids, const char **mtdparts)
-{
-	struct mtd_info *mtd;
-	struct udevice *dev;
-	static char parts[3 * MTDPARTS_LEN + 1];
-	static char ids[MTDIDS_LEN + 1];
-	static bool mtd_initialized;
-
-	if (mtd_initialized) {
-		*mtdids = ids;
-		*mtdparts = parts;
-		return;
-	}
-
-	memset(parts, 0, sizeof(parts));
-	memset(ids, 0, sizeof(ids));
-
-	/* probe all MTD devices */
-	for (uclass_first_device(UCLASS_MTD, &dev);
-	     dev;
-	     uclass_next_device(&dev)) {
-		pr_debug("mtd device = %s\n", dev->name);
-	}
-
-	mtd = get_mtd_device_nm("nand0");
-	if (!IS_ERR_OR_NULL(mtd)) {
-		board_get_mtdparts("nand0", ids, parts);
-		put_mtd_device(mtd);
-	}
-
-	mtd = get_mtd_device_nm("spi-nand0");
-	if (!IS_ERR_OR_NULL(mtd)) {
-		board_get_mtdparts("spi-nand0", ids, parts);
-		put_mtd_device(mtd);
-	}
-
-	if (!uclass_get_device(UCLASS_SPI_FLASH, 0, &dev)) {
-		board_get_mtdparts("nor0", ids, parts);
-	}
-
-	mtd_initialized = true;
-	*mtdids = ids;
-	*mtdparts = parts;
-	debug("%s:mtdids=%s & mtdparts=%s\n", __func__, ids, parts);
-}
-#endif
-
-#if defined(CONFIG_OF_BOARD_SETUP)
-int ft_board_setup(void *blob, bd_t *bd)
-{
-	int off;
-#ifdef CONFIG_FDT_FIXUP_PARTITIONS
-	struct node_info nodes[] = {
-		{ "st,stm32f469-qspi",		MTD_DEV_TYPE_NOR,  },
-		{ "st,stm32mp15-fmc2",		MTD_DEV_TYPE_NAND, },
-	};
-	fdt_fixup_mtdparts(blob, nodes, ARRAY_SIZE(nodes));
-#endif
-
-	/* Update DT if coprocessor started */
-	off = fdt_path_offset(blob, "/m4");
-	if (off > 0) {
-		if (env_get("copro_state")) {
-			fdt_setprop_empty(blob, off, "early-booted");
-		} else {
-			fdt_delprop(blob, off, "early-booted");
-			writel(0, TAMP_COPRO_RSC_TBL_ADDRESS);
-		}
-	}
-
-	return 0;
-}
-#endif
-
-static void board_stm32copro_image_process(ulong fw_image, size_t fw_size)
-{
-	int ret, id = 0; /* Copro id fixed to 0 as only one coproc on mp1 */
-	unsigned int rsc_size;
-	ulong rsc_addr;
-
-	if (!rproc_is_initialized())
-		if (rproc_init()) {
-			printf("Remote Processor %d initialization failed\n",
-			       id);
-			return;
-		}
-
-	ret = rproc_load_rsc_table(id, fw_image, fw_size, &rsc_addr, &rsc_size);
-	if (ret && ret != -ENODATA)
-		return;
-
-	ret = rproc_load(id, fw_image, fw_size);
-	printf("Load Remote Processor %d with data@addr=0x%08lx %u bytes:%s\n",
-	       id, fw_image, fw_size, ret ? " Failed!" : " Success!");
-
-	if (!ret) {
-		ret = rproc_start(id);
-		printf("Start firmware:%s\n", ret ? " Failed!" : " Success!");
-		if (!ret)
-			env_set("copro_state", "booted");
-	}
-}
-
-U_BOOT_FIT_LOADABLE_HANDLER(IH_TYPE_STM32COPRO, board_stm32copro_image_process);
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/bleeding/include/configs/stm32mp1-t1000.h b/recipes-bsp/u-boot/u-boot-stm32mp/bleeding/include/configs/stm32mp1-t1000.h
deleted file mode 100644
index ac3554f9667316d56f6fc7ece43004cf17575a6d..0000000000000000000000000000000000000000
--- a/recipes-bsp/u-boot/u-boot-stm32mp/bleeding/include/configs/stm32mp1-t1000.h
+++ /dev/null
@@ -1,297 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */
-/*
- * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
- *
- * Configuration settings for the STM32MP15x CPU
- */
-
-#ifndef __CONFIG_H
-#define __CONFIG_H
-#include <linux/sizes.h>
-#include <asm/arch/stm32.h>
-
-/*
- * Number of clock ticks in 1 sec
- */
-#define CONFIG_SYS_HZ				1000
-
-#ifndef CONFIG_STM32MP1_TRUSTED
-/* PSCI support */
-#define CONFIG_ARMV7_PSCI_1_0
-#define CONFIG_ARMV7_SECURE_BASE		STM32_SYSRAM_BASE
-#define CONFIG_ARMV7_SECURE_MAX_SIZE		STM32_SYSRAM_SIZE
-#endif
-
-/*
- * malloc() pool size
- */
-#define CONFIG_SYS_MALLOC_LEN			SZ_32M
-
-/*
- * Configuration of the external SRAM memory used by U-Boot
- */
-#define CONFIG_SYS_SDRAM_BASE			STM32_DDR_BASE
-#define CONFIG_SYS_INIT_SP_ADDR			CONFIG_SYS_TEXT_BASE
-
-#define CONFIG_DISABLE_CONSOLE
-
-/*
- * Console I/O buffer size
- */
-#define CONFIG_SYS_CBSIZE			SZ_1K
-
-/*
- * Needed by "loadb"
- */
-#define CONFIG_SYS_LOAD_ADDR			STM32_DDR_BASE
-
-/*
- * Env parameters
- */
-#define CONFIG_ENV_OVERWRITE
-#define CONFIG_ENV_SIZE				SZ_16K
-
-/* Environment in SPI NOR */
-#ifdef CONFIG_ENV_IS_IN_SPI_FLASH
-
-#define CONFIG_ENV_OFFSET		(0x18 * SZ_64K)
-#define CONFIG_ENV_SECT_SIZE	(SZ_64K)
-#define CONFIG_ENV_SPI_BUS		(0)
-#define CONFIG_ENV_SPI_CS		(0)
-#define CONFIG_ENV_SPI_MODE 	(SPI_RX_QUAD | SPI_TX_QUAD)
-#define CONFIG_ENV_SPI_MAX_HZ	(8000000)
-
-#endif
-
-// For sd card boot
-#ifdef CONFIG_ENV_IS_IN_MMC
-
-#ifndef CONFIG_SYS_MMC_ENV_DEV
-#define CONFIG_SYS_MMC_ENV_DEV  (0)
-#endif
-
-#ifndef CONFIG_SYS_MMC_ENV_PART
-#define CONFIG_SYS_MMC_ENV_PART (0)
-#endif
-
-// fsbl1 (0x40000), fsbl2 (0x40000), ssbl (0x200000)
-#define CONFIG_ENV_OFFSET		(0x280000-CONFIG_ENV_SIZE)
-#endif
-
-/* ATAGs */
-#define CONFIG_CMDLINE_TAG
-#define CONFIG_SETUP_MEMORY_TAGS
-#define CONFIG_INITRD_TAG
-
-/* Extend size of kernel image for uncompression */
-#define CONFIG_SYS_BOOTM_LEN			SZ_32M
-
-/* SPL support */
-#ifdef CONFIG_SPL
-/* BOOTROM load address */
-#define CONFIG_SPL_TEXT_BASE		0x2FFC2500
-/* SPL use DDR */
-#define CONFIG_SPL_BSS_START_ADDR	0xC0200000
-#define CONFIG_SPL_BSS_MAX_SIZE		0x00100000
-#define CONFIG_SYS_SPL_MALLOC_START	0xC0300000
-#define CONFIG_SYS_SPL_MALLOC_SIZE	0x00100000
-
-/* limit SYSRAM usage to first 128 KB */
-#define CONFIG_SPL_MAX_SIZE		0x00020000
-#define CONFIG_SPL_STACK		(STM32_SYSRAM_BASE + \
-					 STM32_SYSRAM_SIZE)
-#endif /* #ifdef CONFIG_SPL */
-
-#define CONFIG_SYS_MEMTEST_START	STM32_DDR_BASE
-#define CONFIG_SYS_MEMTEST_END		(CONFIG_SYS_MEMTEST_START + SZ_64M)
-#define CONFIG_SYS_MEMTEST_SCRATCH	(CONFIG_SYS_MEMTEST_END + 4)
-
-/*MMC SD*/
-#define CONFIG_SYS_MMC_MAX_DEVICE	3
-#define CONFIG_SUPPORT_EMMC_BOOT
-
-/*
- * define serial used for u-boot
- *
- * */
-#define CONFIG_CONS_INDEX 2
-
-/*****************************************************************************/
-#ifdef CONFIG_DISTRO_DEFAULTS
-/*****************************************************************************/
-
-/* NAND support */
-#define CONFIG_SYS_NAND_ONFI_DETECTION
-#define CONFIG_SYS_MAX_NAND_DEVICE	1
-
-/* SPI nand */
-#define CONFIG_SYS_MAX_NAND_DEVICE	1
-
-/* SPI FLASH support */
-#if defined(CONFIG_SPL_BUILD)
-#define CONFIG_SYS_SPI_U_BOOT_OFFS	0x80000
-#endif
-
-/* FILE SYSTEM */
-
-#if defined(CONFIG_STM32_QSPI) || defined(CONFIG_NAND_STM32_FMC2)
-/* Dynamic MTD partition support */
-#define CONFIG_SYS_MTDPARTS_RUNTIME
-#endif
-
-/* Ethernet need */
-#ifdef CONFIG_DWC_ETH_QOS
-#define CONFIG_SYS_NONCACHED_MEMORY	(1 * SZ_1M)	/* 1M */
-#define CONFIG_SERVERIP			192.168.1.240
-#define CONFIG_BOOTP_SERVERIP
-#define CONFIG_SYS_AUTOLOAD		"no"
-#endif
-
-#ifdef CONFIG_DM_VIDEO
-#define CONFIG_VIDEO_BMP_RLE8
-#define CONFIG_BMP_16BPP
-#define CONFIG_BMP_24BPP
-#define CONFIG_BMP_32BPP
-#endif
-
-#if !defined(CONFIG_SPL_BUILD)
-
-/* default order is SDCARD (SDMMC 0) / eMMC (SDMMC 1) / NAND /  */
-#define BOOT_TARGET_DEVICES(func) \
-	func(MMC, mmc, 0) \
-	func(MMC, mmc, 1) \
-	func(UBIFS, ubifs, 0) \
-	func(PXE, pxe, na)
-
-#include <config_distro_bootcmd.h>
-
-#if defined(CONFIG_CMD_UBIFS) && defined(CONFIG_SPLASH_SCREEN)
-#undef BOOTENV_SHARED_UBIFS
-#define BOOTENV_SHARED_UBIFS \
-	"ubifs_boot=" \
-		"if test ${boot_device} = nand; then " \
-			"env exists bootubivol || " \
-				"env set bootubivol boroot; " \
-			"if ubifsmount ubi${devnum}:${bootubivol}; " \
-			"then " \
-				"setenv devtype ubi; " \
-				"run scan_dev_for_boot; " \
-			"fi;" \
-		"else " \
-			"env exists bootubipart || " \
-				"env set bootubipart UBI; " \
-			"env exists bootubivol || " \
-				"env set bootubivol boroot; " \
-			"if ubi part ${bootubipart} && " \
-				"ubifsmount ubi${devnum}:${bootubivol}; " \
-			"then " \
-				"setenv devtype ubi; " \
-				"run scan_dev_for_boot; " \
-			"fi;" \
-		"fi\0"
-#endif
-
-#define CONFIG_PREBOOT \
-	"dcache off; setenv board_name ${board_name}${housing}; " \
-	"echo \"Boot over ${boot_device}${boot_instance}!\"; " \
-	"if test ${boot_device} = uart; then " \
-		"stm32prog serial ${boot_instance}; " \
-	"else "\
-		"if test ${boot_device} = usb; then " \
-			"stm32prog usb ${boot_instance}; " \
-		"fi; "\
-	"fi; "
-
-#ifdef CONFIG_STM32MP1_OPTEE
-#define CONFIG_SYS_MEM_TOP_HIDE			SZ_32M
-/* with OPTEE: define specific MTD partitions = teeh, teed, teex */
-#define STM32MP_MTDPARTS \
-	"mtdparts_nor0=256k(fsbl1),256k(fsbl2),2m(ssbl),256k(logo),256k(teeh),256k(teed),256k(teex),-(nor_user)\0" \
-	"mtdparts_spi-nand0=-(UBI);\0"
-
-
-#else /* CONFIG_STM32MP1_OPTEE */
-#define STM32MP_MTDPARTS \
-	"mtdparts_nor0=256k(fsbl1),256k(fsbl2),1m(ssbl),64k(env),-(nor_user)\0" \
-	"mtdparts_spi-nand0=-(UBI)\0"
-
-#endif /* CONFIG_STM32MP1_OPTEE */
-
-/*u-boot vars needed for rescue os boot*/
-#define RESCUE_OS_ENV \
-	"res_kernel_img= uImage \0" \
-	"res_os_img= rescue-os.cpio.gz.u-boot \0" \
-	"res_dt= stm32mp-t1000-s-50.dtb \0" \
-	"rescue_os_flag=0\0" \
-	"upgrade_available=0\0" \
-	"altbootcmd=run bootcmd\0" \
-	"boot_rescue_os=" \
-		"for target in ${boot_targets}; do " \
-			"run boot_res_${target}; " \
-		"done\0" \
-	"boot_res_mmc0= " \
-		"env set devnum 0;" \
-		"env set res_part 3;" \
-		"run boot_res_mmcx;\0" \
-	"boot_res_mmc1= " \
-		"env set devnum 1;" \
-		"env set res_part 3;" \
-		"run boot_res_mmcx;\0" \
-	"boot_res_mmcx= " \
-		"if mmc dev ${devnum};" \
-		"then " \
-			"load mmc ${devnum}:${res_part} ${kernel_addr_r} ${res_kernel_img} ;" \
-			"load mmc ${devnum}:${res_part} ${ramdisk_addr_r} ${res_os_img} ;" \
-			"load mmc ${devnum}:${res_part} ${fdt_addr_r} ${res_dt};" \
-			"bootm ${kernel_addr_r} ${ramdisk_addr_r} ${fdt_addr_r};" \
-		"fi;\0" \
-	"boot_res_ubifs0= " \
-		"if ubi part ubi || ubi part UBI ;" \
-		"then " \
-			"ubifsmount ubi0:rescue-os; " \
-			"ubifsload ${kernel_addr_r} ${res_kernel_img} ; " \
-			"ubifsload ${ramdisk_addr_r} ${res_os_img} ;" \
-			"ubifsload ${fdt_addr_r} ${res_dt};" \
-			"bootm ${kernel_addr_r} ${ramdisk_addr_r} ${fdt_addr_r};" \
-		"fi;\0" \
-	"bootcmd=" \
-		"if test ${rescue_os_flag} = 1; then " \
-			"run boot_rescue_os;" \
-		"else " \
-			"run distro_bootcmd;" \
-		"fi\0" \
-	"altbootcmd=" \
-	    "echo ===========================;" \
-	    "echo WARNING: RESCUE BOOT ACTIVE;" \
-	    "echo ===========================;" \
-		"env set rescue_os_flag 1;" \
-		"run bootcmd;\0"\
-
-/*
- * memory layout for 32M uncompressed/compressed kernel,
- * 1M fdt, 1M script, 1M pxe and 1M for splashimage
- * and the ramdisk at the end.
- */
-#define CONFIG_EXTRA_ENV_SETTINGS \
-	"stdin=serial\0" \
-	"stdout=serial\0" \
-	"stderr=serial\0" \
-	"kernel_addr_r=0xc2000000\0" \
-	"fdt_addr_r=0xc4000000\0" \
-	"scriptaddr=0xc4100000\0" \
-	"pxefile_addr_r=0xc4200000\0" \
-	"splashimage=0xc4300000\0"  \
-	"ramdisk_addr_r=0xc4400000\0" \
-	"fdt_high=0xffffffff\0" \
-	"initrd_high=0xffffffff\0" \
-	"usb_pgood_delay=2000\0" \
-	STM32MP_MTDPARTS \
-	BOOTENV \
-	"boot_net_usb_start=true\0" \
-	"housing=" CONFIG_HOUSING_DEFAULT "\0" \
-	RESCUE_OS_ENV
-
-#endif /* ifndef CONFIG_SPL_BUILD */
-#endif /* ifdef CONFIG_DISTRO_DEFAULTS*/
-
-#endif /* __CONFIG_H */
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/board/exceet/stmxceet-mp157-som/Kconfig b/recipes-bsp/u-boot/u-boot-stm32mp/board/exceet/stmxceet-mp157-som/Kconfig
new file mode 100644
index 0000000000000000000000000000000000000000..8c571a045dba0577accdd36bdbefda3fec2cc9ce
--- /dev/null
+++ b/recipes-bsp/u-boot/u-boot-stm32mp/board/exceet/stmxceet-mp157-som/Kconfig
@@ -0,0 +1,15 @@
+if TARGET_STMXCEET_MP157_SOM
+
+config SYS_BOARD
+	default "stmxceet-mp157-som"
+
+config SYS_VENDOR
+	default "exceet"
+
+config SYS_SOC
+	default "stm32mp"
+
+config SYS_CONFIG_NAME
+	default "stmxceet-mp157-som"
+
+endif
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/board/exceet/stmxceet-mp157-som/Makefile b/recipes-bsp/u-boot/u-boot-stm32mp/board/exceet/stmxceet-mp157-som/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..f571af34dd3c257609a4b90040ff8cabc5c078c7
--- /dev/null
+++ b/recipes-bsp/u-boot/u-boot-stm32mp/board/exceet/stmxceet-mp157-som/Makefile
@@ -0,0 +1,15 @@
+#
+# Copyright (C) 2015-2017, STMicroelectronics - All Rights Reserved
+#
+# SPDX-License-Identifier:	GPL-2.0+	BSD-3-Clause
+#
+
+ifdef CONFIG_SPL_BUILD
+obj-y += spl.o
+else
+obj-y += stmxceet-mp157-som.o
+endif
+
+obj-y += board.o
+
+obj-$(CONFIG_HAS_POST) += post-memory.o
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/board/kontron/stm32mp1-t1000/README b/recipes-bsp/u-boot/u-boot-stm32mp/board/exceet/stmxceet-mp157-som/README
similarity index 52%
rename from recipes-bsp/u-boot/u-boot-stm32mp/board/kontron/stm32mp1-t1000/README
rename to recipes-bsp/u-boot/u-boot-stm32mp/board/exceet/stmxceet-mp157-som/README
index 4ebcfb4ad7ce24eb4136fafd63dcfaeffed2e7f3..fa2b5d8086dafc629cd2831917d3e34bb906c955 100644
--- a/recipes-bsp/u-boot/u-boot-stm32mp/board/kontron/stm32mp1-t1000/README
+++ b/recipes-bsp/u-boot/u-boot-stm32mp/board/exceet/stmxceet-mp157-som/README
@@ -1,9 +1,10 @@
-SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
 #
-# Copyright (C) 2018 STMicroelectronics - All Rights Reserved
+# Copyright (C) 2017 STMicroelectronics - All Rights Reserved
+#
+# SPDX-License-Identifier:	GPL-2.0+	BSD-3-Clause
 #
 
-U-Boot on STMicroelectronics STM32MP1
+U-Boot on ST Microelectronics STM32MP1
 ======================================
 
 1. Summary
@@ -12,7 +13,7 @@ This is a quick instruction for setup stm32mp1 boards.
 
 2. Supported devices
 ====================
-U-Boot supports one STMP32MP1 SoCs: STM32MP157
+U-Boot supports one STMP32MP SoCs: STM32MP157
 
 The STM32MP157 is a Cortex-A MPU aimed at various applications.
 It features:
@@ -31,15 +32,15 @@ Everything is supported in Linux but U-Boot is limited to:
 
 And the necessary drivers
 1. I2C
-2. STPMIC1 (PMIC and regulator)
+2. STPMU1 (regulator)
 3. Clock, Reset, Sysreset
 4. Fuse
 
 Currently the following boards are supported:
 + stm32mp157c-ev1
 + stm32mp157c-ed1
-+ stm32mp157a-dk1
-+ stm32mp157c-dk2
++ stm32mp157c-ev2
++ stm32mp157c-ed2
 
 3. Boot Sequences
 =================
@@ -52,10 +53,10 @@ with FSBL = First Stage Bootloader
 2 boot configurations are supported:
 
 1) The "Trusted" boot chain (defconfig_file : stm32mp15_trusted_defconfig)
-   BootRom => FSBL = Trusted Firmware-A (TF-A) => SSBL = U-Boot
-   TF-A performs a full initialization of Secure peripherals and installs a
+   BootRom => FSBL = Arm Trusted Firmware (ATF) => SSBL = U-Boot
+   ATF performs a full initialization of Secure peripherals and installs a
    secure monitor.
-   U-Boot is running in normal world and uses TF-A monitor
+   U-Boot is running in normal world and uses ATF monitor
    to access to secure resources
 
 2) The "Basic" boot chain (defconfig_file : stm32mp15_basic_defconfig)
@@ -64,7 +65,7 @@ with FSBL = First Stage Bootloader
    U-Boot is running in secure mode and provide a secure monitor to the kernel
    with only PSCI support (Power State Coordination Interface defined by ARM)
 
-All the STM32MP1 boards supported by U-Boot use the same generic board
+All the  STM32MP1 board supported by U-Boot use the same generic board
 stm32mp1 which support all the bootable devices.
 
 Each board is configurated only with the associated device tree.
@@ -72,20 +73,24 @@ Each board is configurated only with the associated device tree.
 4. Device Tree Selection
 ========================
 
-You need to select the appropriate device tree for your board,
-the supported device trees for stm32mp157 are:
+You need to select the appropriate device tree for your board and
+the selected boot mode (basic/trusted)
+
+With <mode> = basic or trusted, the supported board for stm32mp157 are:
 
-+ ev1: eval board with pmic stpmic1 (ev1 = mother board + daughter ed1)
-  dts: stm32mp157c-ev1
++ stm32mp157c-ev1: eval board with pmic stpmu1
+  (eval board ev1 = mother board + daughter ed1)
+  dts: stm32mp157c-ev1-<mode>
 
-+ ed1: daughter board with pmic stpmic1
-  dts: stm32mp157c-ed1
++ stm32mp157c-ed1: daughter board with pmic stpmu1
+  dts: stm32mp157c-ed1-<mode>
 
-+ dk1: Discovery board
-  dts: stm32mp157a-dk1
++ stm32mp157c-ev2: eval board with power discret
+  (eval board ev2 = mother board + daughter ed2)
+  dts: stm32mp157c-ev2-<mode>
 
-+ dk2: Discovery board = dk1 with a BT/WiFI combo and a DSI panel
-  dts: stm32mp157c-dk2
++ stm32mp157c-ed2: daughter board power discret
+  dts: stm32mp157c-ed2-<mode>
 
 5. Build Procedure
 ==================
@@ -110,81 +115,46 @@ the supported device trees for stm32mp157 are:
 	# export KBUILD_OUTPUT=stm32mp15_trusted
 	# export KBUILD_OUTPUT=stm32mp15_basic
 
-4. Configure U-Boot:
+4. Configure the U-Boot:
 
-	# make <defconfig_file>
+	#make <defconfig_file>
 
 	- For trusted boot mode : "stm32mp15_trusted_defconfig"
 	- For basic boot mode: "stm32mp15_basic_defconfig"
 
 5. Configure the device-tree and build the U-Boot image:
 
-	# make DEVICE_TREE=<name> all
+	#make DEVICE_TREE=<name> all
+
 
   example:
   a) trusted boot on ev1
 	# export KBUILD_OUTPUT=stm32mp15_trusted
 	# make stm32mp15_trusted_defconfig
-	# make DEVICE_TREE=stm32mp157c-ev1 all
+	# make DEVICE_TREE=stm32mp157c-ev1-trusted all
 
-  b) basic boot on dk2
+  b) basic boot on ev2
 	# export KBUILD_OUTPUT=stm32mp15_basic
 	# make stm32mp15_basic_defconfig
-	# make DEVICE_TREE=stm32mp157c-dk2 all
+	# make DEVICE_TREE=stm32mp157c-ev2-basic all
 
 6. Output files
 
-  BootRom and TF-A expect binaries with STM32 image header
+  BootRom and ATF expect binaries with STM32 image header
   SPL expects file with U-Boot uImage header
 
   So in the output directory (selected by KBUILD_OUTPUT),
   you can found the needed files:
 
   a) For Trusted boot
-   + FSBL = tf-a.stm32 (provided by TF-A compilation)
+   + FSBL = atf.stm32 (provided by ATF compilation)
    + SSBL = u-boot.stm32
 
   b) For Basic boot
    + FSBL = spl/u-boot-spl.stm32
    + SSBL = u-boot.img
 
-6. Switch Setting for Boot Mode
-===============================
-
-You can select the boot mode,
-- on the daugther board ed1 with the switch SW1 : BOOT0, BOOT1, BOOT2
-- on board DK1/DK2 with the switch SW1 (BOOT1 forced to 0)
-
- -----------------------------------
-  Boot Mode   BOOT2   BOOT1   BOOT0
- -----------------------------------
-  Reserved	0	0	0
-  NOR		0	0	1
-  SD-Card	1	1	1
-  SD-Card	1	0	1
-  eMMC		0	1	0
-  NAND		0	1	1
-  Recovery	1	1	0
-  Recovery	0	0	0
-
-- on board DK1/DK2 with the switch SW1 : BOOT0, BOOT2
-  (BOOT1 forced to 0, NOR not supported)
-
- --------------------------
-  Boot Mode   BOOT2  BOOT0
- --------------------------
-  Reserved	1      0
-  SD-Card	1      1
-  Recovery	0      0
-
-Recovery is a boot from serial link (UART/USB) and it is used with
-STM32CubeProgrammer tool to load executable in RAM and to update the flash
-devices available on the board (NOR/NAND/eMMC/SDCARD).
-The communication between HOST and board is based on
-- for UARTs : the uart protocol used with all MCU STM32
-- for USB : based on USB DFU 1.1 (without the ST extensions used on MCU STM32)
-
-7. Prepare an SDCard
+6. Prepare an SDCard
 ===================
 
 The minimal requirements for STMP32MP1 boot up to U-Boot are:
@@ -193,91 +163,74 @@ The minimal requirements for STMP32MP1 boot up to U-Boot are:
 - one ssbl partition for U-Boot
 
 Then the minimal GPT partition is:
-   ----- ------- --------- ---------------
-  | Num | Name  | Size    |  Content     |
-   ----- ------- -------- ----------------
-  |  1  | fsbl1 | 256 KiB |  TF-A or SPL |
-  |  2  | fsbl2 | 256 KiB |  TF-A or SPL |
-  |  3  | ssbl  | enought |  U-Boot      |
-  |  *  |  -    |  -      |  Boot/Rootfs |
-   ----- ------- --------- ---------------
+   ----- ------- --------- -------------
+  | Num | Name  | Size    |  Content    |
+   ----- ------- -------- --------------
+  |  1  | fsbl1 | 256 KiB |  ATF or SPL |
+  |  2  | fsbl2 | 256 KiB |  ATF or SPL |
+  |  3  | ssbl  | enought |  U-Boot     |
+  |  *  |  -    |  -      |  Boot/Rootfs|
+   ----- ------- --------- -------------
 
 (*) add bootable partition for extlinux.conf
     following Generic Distribution
     (doc/README.distro for use)
 
-  according the used card reader select the block device
-  (/dev/sdx or /dev/mmcblk0)
-  in the next example I use /dev/mmcblk0
-
-for example: with gpt table with 128 entries
+for example: if sdcard is mounted on /dev/mmcblk0,
+             gpt table with 128 entries:
 
   a) remove previous formatting
-	# sgdisk -o /dev/<SDCard dev>
+	# sgdisk -o /dev/mmcblk0
 
   b) create minimal image
-	# sgdisk --resize-table=128 -a 1 \
+	# sgdisk	--resize-table=128 -a 1 \
 		-n 1:34:545		-c 1:fsbl1 \
 		-n 2:546:1057		-c 2:fsbl2 \
 		-n 3:1058:5153		-c 3:ssbl \
 		-p /dev/<SDCard dev>
 
-	you can add other partitions for kernel
-	one partition rootfs for example:
-		-n 3:5154:		-c 4:rootfs \
-
   c) copy the FSBL (2 times) and SSBL file on the correct partition.
      in this example in partition 1 to 3
 
-     for basic boot mode : <SDCard dev> = /dev/mmcblk0
+     for basic boot mode :
 	# dd if=u-boot-spl.stm32 of=/dev/mmcblk0p1
 	# dd if=u-boot-spl.stm32 of=/dev/mmcblk0p2
 	# dd if=u-boot.img of=/dev/mmcblk0p3
 
      for trusted boot mode :
-	# dd if=tf-a.stm32 of=/dev/mmcblk0p1
-	# dd if=tf-a.stm32 of=/dev/mmcblk0p2
+	# dd if=atf.stm32 of=/dev/mmcblk0p1
+	# dd if=atf.stm32 of=/dev/mmcblk0p2
 	# dd if=u-boot.stm32 of=/dev/mmcblk0p3
 
-To boot from SDCard, select BootPinMode = 1 1 1 and reset.
-
-8. Prepare eMMC
-===============
-You can use U-Boot to copy binary in eMMC.
-
-In the next example, you need to boot from SDCARD and the images (u-boot-spl.stm32, u-boot.img)
-are presents on SDCARD (mmc 0) in ext4 partition 4 (bootfs).
-
-To boot from SDCard, select BootPinMode = 1 1 1 and reset.
-
-Then you update the eMMC with the next U-Boot command :
-
-a) prepare GPT on eMMC,
-	example with 2 partitions, bootfs and roots:
-
-	# setenv emmc_part "name=ssbl,size=2MiB;name=bootfs,type=linux,bootable,size=64MiB;name=rootfs,type=linux,size=512"
-	# gpt write mmc 1 ${emmc_part}
+7. Switch Setting
+==================
 
-b) copy SPL on eMMC on firts boot partition
-	(SPL max size is 256kB, with LBA 512, 0x200)
+On board stm32mp157c-ed1/ev1/ed2/ed2 you can select the boot mode
+on the daugther board with the switch SW1
 
-	# ext4load mmc 0:4 0xC0000000 u-boot-spl.stm32
-	# mmc dev 1
-	# mmc partconf 1 1 1 1
-	# mmc write ${fileaddr} 0 200
-	# mmc partconf 1 1 1 0
+ -----------------------------------
+  Boot Mode   BOOT2   BOOT1   BOOT0
+ -----------------------------------
+  Reserved	0	0	0
+  NOR		0	0	1
+  SD-Card	1	1	1
+  SD-Card	1	0	1
+  eMMC		0	1	0
+  NAND		0	1	1
+  Recovery	1	1	0
+  Recovery	0	0	0
 
-b) copy U-Boot in first GPT partition of eMMC
 
-	# ext4load mmc 0:4 0xC0000000 u-boot.img
-	# mmc dev 1
-	# part start mmc 1 1 partstart
-	# part size mmc 1 1 partsize
-	# mmc write ${fileaddr} ${partstart} ${partsize}
+To boot from SDCard, select BootPinMode = 1 1 1 and reset.
 
-To boot from eMMC, select BootPinMode = 0 1 0 and reset.
+Recovery is a boot from serial link (UART/USB) and it is used with
+STM32CubeProgrammer tool to load executable in RAM and to update the flash
+devices available on the board (NOR/NAND/eMMC/SDCARD).
+The communication between HOST and board is based on
+- for UARTs : the uart protocol used with all MCU STM32
+- for USB : based on USB DFU 1.1 (without the ST extensions used on MCU STM32)
 
-9. MAC Address
+8. MAC Address
 ==============
 
 Please read doc/README.enetaddr for the implementation guidelines for mac id
@@ -290,8 +243,6 @@ Mac id storage and retrieval in stm32mp otp :
 To program a MAC address on virgin OTP words above, you can use the fuse command
 on bank 0 to access to internal OTP:
 
-    example to set mac address "12:34:56:78:9a:bc"
-
     1- Write OTP
        STM32MP> fuse prog -y 0 57 0x78563412 0x0000bc9a
 
@@ -306,37 +257,3 @@ on bank 0 to access to internal OTP:
     4 check env update
        STM32MP> print ethaddr
        ethaddr=12:34:56:78:9a:bc
-
-10. Coprocessor firmware
-========================
-
-U-Boot can boot the coprocessor before the kernel (coprocessor early boot).
-
-A/ Manuallly by using rproc commands (update the bootcmd)
-     Configurations
-	# env set name_copro "stm32mp15_m4.elf"
-	# env set dev_copro 0
-	# env set loadaddr_copro 0xC1000000
-
-     Load binary from bootfs partition (number 4) on SDCard (mmc 0)
-	# ext4load mmc 0:4 ${loadaddr_copro} ${name_copro}
-	=> ${filesize} updated with the size of the loaded file
-
-     Start M4 firmware with remote proc command
-	# rproc init
-	# rproc load ${dev_copro} ${loadaddr_copro} ${filesize}
-	# rproc load_rsc ${dev_copro} ${loadaddr_copro} ${filesize}
-	# rproc start ${dev_copro}
-
-B/ Automatically by using FIT feature and generic DISTRO bootcmd
-
-   see examples in this directory :
-
-   Generate FIT including kernel + device tree + M4 firmware
-   with cfg with M4 boot
-        $> mkimage -f fit_copro_kernel_dtb.its fit_copro_kernel_dtb.itb
-
-    Then using DISTRO configuration file: see extlinux.conf to select
-    the correct configuration
-	=> stm32mp157c-ev1-m4
-	=> stm32mp157c-dk2-m4
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/board/exceet/stmxceet-mp157-som/board.c b/recipes-bsp/u-boot/u-boot-stm32mp/board/exceet/stmxceet-mp157-som/board.c
new file mode 100644
index 0000000000000000000000000000000000000000..44aa45c219961625fe224abad68397f2f4780e7c
--- /dev/null
+++ b/recipes-bsp/u-boot/u-boot-stm32mp/board/exceet/stmxceet-mp157-som/board.c
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier:	GPL-2.0+	BSD-3-Clause
+ */
+
+#include <common.h>
+#include <debug_uart.h>
+#include <dm.h>
+#include <asm/io.h>
+#include <asm/arch/ddr.h>
+#include <power/pmic.h>
+#include <power/stpmu1.h>
+
+#ifdef CONFIG_DEBUG_UART_BOARD_INIT
+void board_debug_uart_init(void)
+{
+#if (CONFIG_DEBUG_UART_BASE == STM32_UART4_BASE)
+
+#define RCC_MP_APB1ENSETR (STM32_RCC_BASE + 0x0A00)
+#define RCC_MP_AHB4ENSETR (STM32_RCC_BASE + 0x0A28)
+
+	/* UART4 clock enable */
+	setbits_le32(RCC_MP_APB1ENSETR, BIT(16));
+
+#define GPIOG_BASE 0x50008000
+	/* GPIOG clock enable */
+	writel(BIT(6), RCC_MP_AHB4ENSETR);
+	/* GPIO configuration for EVAL board
+	 * => Uart4 TX = G11
+	 */
+	writel(0xffbfffff, GPIOG_BASE + 0x00);
+	writel(0x00006000, GPIOG_BASE + 0x24);
+#else
+
+#error("CONFIG_DEBUG_UART_BASE: not supported value")
+
+#endif
+}
+#endif
+
+#ifdef CONFIG_DM_PMIC
+int board_ddr_power_init(enum ddr_type ddr_type)
+{
+	struct udevice *dev;
+	bool buck3_at_1800000v = false;
+	int ret;
+
+	ret = uclass_get_device_by_driver(UCLASS_PMIC,
+					  DM_GET_DRIVER(pmic_stpmu1), &dev);
+	if (ret)
+		/* No PMIC on power discrete board */
+		return 0;
+
+	switch (ddr_type) {
+	case STM32MP_DDR3:
+		/* Set LDO3 to sync mode */
+		ret = pmic_reg_read(dev, STPMU1_LDOX_CTRL_REG(STPMU1_LDO3));
+		if (ret < 0)
+			return ret;
+
+		ret &= ~STPMU1_LDO3_MODE;
+		ret &= ~STPMU1_LDO12356_OUTPUT_MASK;
+		ret |= STPMU1_LDO3_DDR_SEL << STPMU1_LDO12356_OUTPUT_SHIFT;
+
+		ret = pmic_reg_write(dev, STPMU1_LDOX_CTRL_REG(STPMU1_LDO3),
+				     ret);
+		if (ret < 0)
+			return ret;
+
+		/* Set BUCK2 to 1.35V */
+		ret = pmic_clrsetbits(dev,
+				      STPMU1_BUCKX_CTRL_REG(STPMU1_BUCK2),
+				      STPMU1_BUCK_OUTPUT_MASK,
+				      STPMU1_BUCK2_1350000V);
+		if (ret < 0)
+			return ret;
+
+		/* Enable BUCK2 and VREF */
+		ret = pmic_clrsetbits(dev,
+				      STPMU1_BUCKX_CTRL_REG(STPMU1_BUCK2),
+				      STPMU1_BUCK_EN, STPMU1_BUCK_EN);
+		if (ret < 0)
+			return ret;
+
+		mdelay(STPMU1_DEFAULT_START_UP_DELAY_MS);
+
+		ret = pmic_clrsetbits(dev, STPMU1_VREF_CTRL_REG,
+				      STPMU1_VREF_EN, STPMU1_VREF_EN);
+		if (ret < 0)
+			return ret;
+
+		mdelay(STPMU1_DEFAULT_START_UP_DELAY_MS);
+
+		/* Enable LDO3 */
+		ret = pmic_clrsetbits(dev,
+				      STPMU1_LDOX_CTRL_REG(STPMU1_LDO3),
+				      STPMU1_LDO_EN, STPMU1_LDO_EN);
+		if (ret < 0)
+			return ret;
+
+		mdelay(STPMU1_DEFAULT_START_UP_DELAY_MS);
+
+		break;
+
+	case STM32MP_LPDDR2:
+		/*
+		 * Set LDO3 to 1.8V
+		 * Set LDO3 to bypass mode if BUCK3 = 1.8V
+		 * Set LDO3 to normal mode if BUCK3 != 1.8V
+		 */
+		ret = pmic_reg_read(dev,
+				    STPMU1_BUCKX_CTRL_REG(STPMU1_BUCK3));
+		if (ret < 0)
+			return ret;
+
+		if ((ret & STPMU1_BUCK3_1800000V) == STPMU1_BUCK3_1800000V)
+			buck3_at_1800000v = true;
+
+		ret = pmic_reg_read(dev, STPMU1_LDOX_CTRL_REG(STPMU1_LDO3));
+		if (ret < 0)
+			return ret;
+
+		ret &= ~STPMU1_LDO3_MODE;
+		ret &= ~STPMU1_LDO12356_OUTPUT_MASK;
+		ret |= STPMU1_LDO3_1800000;
+		if (buck3_at_1800000v)
+			ret |= STPMU1_LDO3_MODE;
+
+		ret = pmic_reg_write(dev, STPMU1_LDOX_CTRL_REG(STPMU1_LDO3),
+				     ret);
+		if (ret < 0)
+			return ret;
+
+		/* Set BUCK2 to 1.2V */
+		ret = pmic_clrsetbits(dev,
+				      STPMU1_BUCKX_CTRL_REG(STPMU1_BUCK2),
+				      STPMU1_BUCK_OUTPUT_MASK,
+				      STPMU1_BUCK2_1200000V);
+		if (ret < 0)
+			return ret;
+
+		/* Enable LDO3, BUCK2 and VREF */
+		ret = pmic_clrsetbits(dev, STPMU1_LDOX_CTRL_REG(STPMU1_LDO3),
+				      STPMU1_LDO_EN, STPMU1_LDO_EN);
+		if (ret < 0)
+			return ret;
+
+		mdelay(STPMU1_DEFAULT_START_UP_DELAY_MS);
+
+		ret = pmic_clrsetbits(dev,
+				      STPMU1_BUCKX_CTRL_REG(STPMU1_BUCK2),
+				      STPMU1_BUCK_EN, STPMU1_BUCK_EN);
+		if (ret < 0)
+			return ret;
+
+		mdelay(STPMU1_DEFAULT_START_UP_DELAY_MS);
+
+		ret = pmic_clrsetbits(dev, STPMU1_VREF_CTRL_REG,
+				      STPMU1_VREF_EN, STPMU1_VREF_EN);
+		if (ret < 0)
+			return ret;
+
+		mdelay(STPMU1_DEFAULT_START_UP_DELAY_MS);
+
+		break;
+
+	default:
+		break;
+	};
+
+	return 0;
+}
+#endif
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/board/exceet/stmxceet-mp157-som/post-memory.c b/recipes-bsp/u-boot/u-boot-stm32mp/board/exceet/stmxceet-mp157-som/post-memory.c
new file mode 100644
index 0000000000000000000000000000000000000000..c75c4dc137592cf2c722053d7aa8219f048b9a63
--- /dev/null
+++ b/recipes-bsp/u-boot/u-boot-stm32mp/board/exceet/stmxceet-mp157-som/post-memory.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2015-2017, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier:	GPL-2.0+	BSD-3-Clause
+ */
+
+/* #define DEBUG */
+
+#include <common.h>
+#include <config.h>
+#include "post.h"
+#include "memalign.h"
+
+/*
+ * Get a global data pointer
+ */
+DECLARE_GLOBAL_DATA_PTR;
+
+#ifdef CONFIG_SPL_BUILD
+int post_log(char *format, ...)
+{
+	va_list args;
+
+	va_start(args, format);
+	vprintf(format, args);
+	va_end(args);
+	return 0;
+}
+#endif
+
+int post_hotkeys_pressed(void)
+{
+#ifdef DEBUG
+	printf("\n%s: warning FORCE SLOW test\n", __func__);
+	return 1; /* 1 = FORCE SLOW test */
+#else
+	printf(
+	       "\n%s: TODO : read GPIO/KEY to start slow test only if pressed\n",
+	       __func__);
+	return 0;
+#endif
+}
+
+int arch_memory_test_prepare(u32 *vstart, u32 *size, phys_addr_t *phys_offset)
+{
+#if (!defined(CONFIG_STM32MP1_TRUSTED) && !defined(CONFIG_SPL)) || \
+	defined(CONFIG_SPL_BUILD)
+	*vstart = STM32_DDR_BASE;
+	*size = gd->ram_size;
+#else
+	/* POST MEMORY test done before reallocation */
+	/* MTEST2 CMD test done after reallocation */
+	*vstart = STM32_DDR_BASE + SZ_16M;
+	*size = gd->ram_size - (*vstart - STM32_DDR_BASE) - SZ_2M -
+		CONFIG_SYS_MALLOC_LEN;
+#endif
+
+	debug("%s: 0x%08X %d KB\n", __func__, *vstart, *size / 1024);
+	return 0;
+}
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/board/exceet/stmxceet-mp157-som/spl.c b/recipes-bsp/u-boot/u-boot-stm32mp/board/exceet/stmxceet-mp157-som/spl.c
new file mode 100644
index 0000000000000000000000000000000000000000..d04e50609720e207129af5b147e29cec79d482e7
--- /dev/null
+++ b/recipes-bsp/u-boot/u-boot-stm32mp/board/exceet/stmxceet-mp157-som/spl.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier:	GPL-2.0+	BSD-3-Clause
+ */
+
+#include <config.h>
+#include <common.h>
+#include <spl.h>
+#include <dm.h>
+#include <ram.h>
+#include <asm/io.h>
+#include <post.h>
+#include <power/pmic.h>
+#include <power/stpmu1.h>
+#include <asm/arch/ddr.h>
+
+void spl_board_init(void)
+{
+	/* Keep vdd on during the reset cycle */
+#if defined(CONFIG_PMIC_STPMU1) && defined(CONFIG_SPL_POWER_SUPPORT)
+	struct udevice *dev;
+	int ret;
+
+	ret = uclass_get_device_by_driver(UCLASS_PMIC,
+					  DM_GET_DRIVER(pmic_stpmu1), &dev);
+	if (!ret)
+		pmic_clrsetbits(dev,
+				STPMU1_MASK_RESET_BUCK,
+				STPMU1_MASK_RESET_BUCK3,
+				STPMU1_MASK_RESET_BUCK3);
+
+	/* Check if debug is enabled to program PMIC according to the bit */
+	if ((readl(TAMP_BOOT_CONTEXT) & TAMP_BOOT_DEBUG_ON) && !ret) {
+		printf("Keep debug unit ON\n");
+
+		pmic_clrsetbits(dev, STPMU1_MASK_RESET_BUCK,
+				STPMU1_MASK_RESET_BUCK_DBG,
+				STPMU1_MASK_RESET_BUCK_DBG);
+
+		pmic_clrsetbits(dev, STPMU1_MASK_RESET_LDOS,
+				STPMU1_MASK_RESET_LDOS_DBG,
+				STPMU1_MASK_RESET_LDOS_DBG);
+	}
+
+
+	/* Ticket 42582  - [STPMU1]: Software workaround regarding buck
+	 *                           converter bug
+	 * TEMP => to be removed after PMIC silicon fix
+	 */
+	if (!ret) {
+		printf("STPMU1: BUCK3 and BUCK4 workaround for cut1\n");
+		pmic_clrsetbits(dev,
+				STPMU1_BUCKX_CTRL_REG(STPMU1_BUCK3),
+				STPMU1_BUCK_MODE,
+				STPMU1_BUCK_MODE);
+		pmic_clrsetbits(dev,
+				STPMU1_BUCKX_CTRL_REG(STPMU1_BUCK4),
+				STPMU1_BUCK_MODE,
+				STPMU1_BUCK_MODE);
+	}
+#endif
+}
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/board/kontron/stm32mp1-t1000/stm32mp1-t1000.c b/recipes-bsp/u-boot/u-boot-stm32mp/board/exceet/stmxceet-mp157-som/stmxceet-mp157-som.c
similarity index 61%
rename from recipes-bsp/u-boot/u-boot-stm32mp/board/kontron/stm32mp1-t1000/stm32mp1-t1000.c
rename to recipes-bsp/u-boot/u-boot-stm32mp/board/exceet/stmxceet-mp157-som/stmxceet-mp157-som.c
index 17e7c3b091728c8dbb6e25e0c5887e9296c8954d..90d4361d76f6f718f3701cb983773288e6706988 100644
--- a/recipes-bsp/u-boot/u-boot-stm32mp/board/kontron/stm32mp1-t1000/stm32mp1-t1000.c
+++ b/recipes-bsp/u-boot/u-boot-stm32mp/board/exceet/stmxceet-mp157-som/stmxceet-mp157-som.c
@@ -1,23 +1,22 @@
-// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
 /*
  * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier:	GPL-2.0+	BSD-3-Clause
  */
-
 #include <config.h>
 #include <common.h>
 #include <adc.h>
 #include <dm.h>
 #include <clk.h>
 #include <console.h>
+#include <fuse.h>
 #include <fdt_support.h>
 #include <generic-phy.h>
-#include <i2c.h>
 #include <led.h>
-#include <misc.h>
 #include <mtd_node.h>
 #include <phy.h>
-#include <remoteproc.h>
 #include <reset.h>
+#include <splash.h>
 #include <syscon.h>
 #include <usb.h>
 #include <asm/io.h>
@@ -27,133 +26,59 @@
 #include <jffs2/load_kernel.h>
 #include <power/regulator.h>
 #include <usb/dwc2_udc.h>
+#include <remoteproc.h>
 
-/* SYSCFG registers */
-#define SYSCFG_BOOTR		0x00
-#define SYSCFG_PMCSETR		0x04
-#define SYSCFG_IOCTRLSETR	0x18
-#define SYSCFG_ICNR		0x1C
-#define SYSCFG_CMPCR		0x20
-#define SYSCFG_CMPENSETR	0x24
-#define SYSCFG_PMCCLRR		0x44
-
-#define SYSCFG_IOCTRLSETR_HSLVEN_TRACE		BIT(0)
-#define SYSCFG_IOCTRLSETR_HSLVEN_QUADSPI	BIT(1)
-#define SYSCFG_IOCTRLSETR_HSLVEN_ETH		BIT(2)
-#define SYSCFG_IOCTRLSETR_HSLVEN_SDMMC		BIT(3)
-#define SYSCFG_IOCTRLSETR_HSLVEN_SPI		BIT(4)
-
-#define SYSCFG_CMPCR_SW_CTRL		BIT(1)
-#define SYSCFG_CMPCR_READY		BIT(8)
-
-#define SYSCFG_CMPENSETR_MPU_EN		BIT(0)
-
-#define SYSCFG_PMCSETR_ETH_CLK_SEL	BIT(16)
-#define SYSCFG_PMCSETR_ETH_REF_CLK_SEL	BIT(17)
-
-#define SYSCFG_PMCSETR_ETH_SELMII	BIT(20)
-
-#define SYSCFG_PMCSETR_ETH_SEL_MASK	GENMASK(23, 21)
-#define SYSCFG_PMCSETR_ETH_SEL_GMII_MII	(0 << 21)
-#define SYSCFG_PMCSETR_ETH_SEL_RGMII	(1 << 21)
-#define SYSCFG_PMCSETR_ETH_SEL_RMII	(4 << 21)
-
+#ifdef CONFIG_STM32MP15x_REVA
+#include <asm/arch/sys_proto.h>
+#endif
 /*
  * Get a global data pointer
  */
 DECLARE_GLOBAL_DATA_PTR;
 
-#define USB_WARNING_LOW_THRESHOLD_UV	660000
+#define USB_WARNING_LOW_THRESHOLD_UV     660000
 #define USB_START_LOW_THRESHOLD_UV	1230000
 #define USB_START_HIGH_THRESHOLD_UV	2100000
 
 int checkboard(void)
 {
-	int ret;
 	char *mode;
-	u32 otp;
-	struct udevice *dev;
-	const char *fdt_compat;
-	int fdt_compat_len;
 
 	if (IS_ENABLED(CONFIG_STM32MP1_TRUSTED))
 		mode = "trusted";
 	else
 		mode = "basic";
 
-	printf("Board: stm32mp1 in %s mode", mode);
-	fdt_compat = fdt_getprop(gd->fdt_blob, 0, "compatible",
-				 &fdt_compat_len);
-	if (fdt_compat && fdt_compat_len)
-		printf(" (%s)", fdt_compat);
-	puts("\n");
-
-	ret = uclass_get_device_by_driver(UCLASS_MISC,
-					  DM_GET_DRIVER(stm32mp_bsec),
-					  &dev);
-
-	if (!ret)
-		ret = misc_read(dev, STM32_BSEC_SHADOW(BSEC_OTP_BOARD),
-				&otp, sizeof(otp));
-	if (!ret && otp) {
-		printf("Board: MB%04x Var%d Rev.%c-%02d\n",
-		       otp >> 16,
-		       (otp >> 12) & 0xF,
-		       ((otp >> 8) & 0xF) - 1 + 'A',
-		       otp & 0xF);
-	}
+	printf("Board: stm32mp1 in %s mode\n", mode);
 
 	return 0;
 }
 
-static void board_key_check(void)
+#ifdef CONFIG_FASTBOOT
+static void board_fastboot_check(void)
 {
-#if defined(CONFIG_FASTBOOT) || defined(CONFIG_CMD_STM32PROG)
 	ofnode node;
 	struct gpio_desc gpio;
-	enum forced_boot_mode boot_mode = BOOT_NORMAL;
 
 	node = ofnode_path("/config");
 	if (!ofnode_valid(node)) {
 		debug("%s: no /config node?\n", __func__);
 		return;
 	}
-#ifdef CONFIG_FASTBOOT
 	if (gpio_request_by_name_nodev(node, "st,fastboot-gpios", 0,
 				       &gpio, GPIOD_IS_IN)) {
 		debug("%s: could not find a /config/st,fastboot-gpios\n",
 		      __func__);
-	} else {
-		if (dm_gpio_get_value(&gpio)) {
-			puts("Fastboot key pressed, ");
-			boot_mode = BOOT_FASTBOOT;
-		}
-
-		dm_gpio_free(NULL, &gpio);
-	}
-#endif
-#ifdef CONFIG_CMD_STM32PROG
-	if (gpio_request_by_name_nodev(node, "st,stm32prog-gpios", 0,
-				       &gpio, GPIOD_IS_IN)) {
-		debug("%s: could not find a /config/st,stm32prog-gpios\n",
-		      __func__);
-	} else {
-		if (dm_gpio_get_value(&gpio)) {
-			puts("STM32Programmer key pressed, ");
-			boot_mode = BOOT_STM32PROG;
-		}
-		dm_gpio_free(NULL, &gpio);
+		return;
 	}
-#endif
-
-	if (boot_mode != BOOT_NORMAL) {
-		puts("entering download mode...\n");
+	if (dm_gpio_get_value(&gpio))
 		clrsetbits_le32(TAMP_BOOT_CONTEXT,
 				TAMP_BOOT_FORCED_MASK,
-				boot_mode);
-	}
-#endif
+				BOOT_FASTBOOT);
+
+	dm_gpio_free(NULL, &gpio);
 }
+#endif
 
 bool board_is_dk2(void)
 {
@@ -201,91 +126,39 @@ void board_qspi_init(void)
 }
 #endif /* CONFIG_STM32_QSPI */
 
-#if defined(CONFIG_USB_GADGET) && defined(CONFIG_USB_GADGET_DWC2_OTG)
-
-/*
- * DWC2 registers should be defined in drivers
- * OTG: drivers/usb/gadget/dwc2_udc_otg_regs.h
- * HOST: ./drivers/usb/host/dwc2.h
- */
-#define DWC2_GOTGCTL_OFFSET		0x00
-#define DWC2_GGPIO_OFFSET		0x38
-
-#define DWC2_GGPIO_VBUS_SENSING		BIT(21)
+#ifdef CONFIG_USB_EHCI_GENERIC
+void board_usbh_init(void)
+{
+}
+#endif /* CONFIG_USB_EHCI_GENERIC */
 
-#define DWC2_GOTGCTL_AVALIDOVEN		BIT(4)
-#define DWC2_GOTGCTL_AVALIDOVVAL	BIT(5)
-#define DWC2_GOTGCTL_BVALIDOVEN		BIT(6)
-#define DWC2_GOTGCTL_BVALIDOVVAL	BIT(7)
-#define DWC2_GOTGCTL_BSVLD		BIT(19)
+#if defined(CONFIG_USB_DWC2) || defined(CONFIG_USB_GADGET)
+#define STM32MP_GUSBCFG 0x40002407
+#define STM32MP_GOTGCTL_AVALIDOVEN	BIT(4)
+#define STM32MP_GOTGCTL_AVALIDOVVAL	BIT(5)
+#define STM32MP_GOTGCTL_BVALIDOVEN	BIT(6)
+#define STM32MP_GOTGCTL_BVALIDOVVAL	BIT(7)
 
-#define STM32MP_GUSBCFG			0x40002407
+static bool usb1600;
 
 static struct dwc2_plat_otg_data stm32mp_otg_data = {
 	.regs_otg = FDT_ADDR_T_NONE,
 	.usb_gusbcfg = STM32MP_GUSBCFG,
-	.priv = NULL, /* pointer to udevice for stusb1600 when present */
+	.priv = &usb1600,
 };
 
 static struct reset_ctl usbotg_reset;
 
-/* STMicroelectronics STUSB1600 Type-C controller */
-#define STUSB1600_CC_CONNECTION_STATUS		0x0E
-
-/* STUSB1600_CC_CONNECTION_STATUS bitfields */
-#define STUSB1600_CC_ATTACH			BIT(0)
-
-static int stusb1600_init(void)
-{
-	struct udevice *dev, *bus;
-	ofnode node;
-	int ret;
-	u32 chip_addr;
-
-	node = ofnode_by_compatible(ofnode_null(), "st,stusb1600");
-	if (!ofnode_valid(node)) {
-		printf("stusb1600 not found\n");
-		return -ENODEV;
-	}
-
-	ret = ofnode_read_u32(node, "reg", &chip_addr);
-	if (ret)
-		return -EINVAL;
-
-	ret = uclass_get_device_by_ofnode(UCLASS_I2C, ofnode_get_parent(node),
-					  &bus);
-	if (ret) {
-		printf("bus for stusb1600 not found\n");
-		return -ENODEV;
-	}
-
-	ret = dm_i2c_probe(bus, chip_addr, 0, &dev);
-	if (!ret)
-		stm32mp_otg_data.priv = dev;
-
-	return ret;
-}
-
-static int stusb1600_cable_connected(void)
-{
-	struct udevice *stusb1600_dev = stm32mp_otg_data.priv;
-	u8 status;
-
-	if (dm_i2c_read(stusb1600_dev,
-			STUSB1600_CC_CONNECTION_STATUS,
-			&status, 1))
-		return 0;
-
-	return status & STUSB1600_CC_ATTACH;
-}
-
 void board_usbotg_init(void)
 {
 	int node;
+	int phy_provider;
 	struct fdtdec_phandle_args args;
 	struct udevice *dev;
 	const void *blob = gd->fdt_blob;
 	struct clk clk;
+	struct phy phy;
+	bool *usb1600 = stm32mp_otg_data.priv;
 
 	/* find the usb otg node */
 	node = fdt_node_offset_by_compatible(blob, -1, "snps,dwc2");
@@ -334,24 +207,38 @@ void board_usbotg_init(void)
 	usbotg_reset.dev = dev;
 	usbotg_reset.id = args.args[0];
 
+	reset_assert(&usbotg_reset);
+	udelay(2);
+	reset_deassert(&usbotg_reset);
+
 	/* Phy */
 	if (!(fdtdec_parse_phandle_with_args(blob, node, "phys",
 					     "#phy-cells", 0, 0, &args))) {
-		stm32mp_otg_data.phy_of_node =
-			fdt_parent_offset(blob, args.node);
-		if (stm32mp_otg_data.phy_of_node <= 0) {
-			debug("Not found usbo phy device\n");
+		phy_provider = fdt_parent_offset(blob, args.node);
+
+		if (uclass_get_device_by_of_offset(UCLASS_PHY,
+						   phy_provider, &dev))
+			goto clk_err;
+
+		phy.dev = dev;
+		phy.id = fdtdec_get_uint(blob, args.node, "reg", -1);
+
+		if (generic_phy_power_on(&phy)) {
+			debug("unable to power on the phy\n");
 			goto clk_err;
 		}
-		stm32mp_otg_data.regs_phy = fdtdec_get_uint(blob, args.node,
-							    "reg", -1);
+
+		if (generic_phy_init(&phy)) {
+			debug("failed to init usb phy\n");
+			goto phy_power_err;
+		}
 	}
 
 	/* Parse and store data needed for gadget */
 	stm32mp_otg_data.regs_otg = fdtdec_get_addr(blob, node, "reg");
 	if (stm32mp_otg_data.regs_otg == FDT_ADDR_T_NONE) {
 		debug("usbotg: can't get base address\n");
-		goto clk_err;
+		goto phy_init_err;
 	}
 
 	stm32mp_otg_data.rx_fifo_sz = fdtdec_get_int(blob, node,
@@ -360,11 +247,9 @@ void board_usbotg_init(void)
 							"g-np-tx-fifo-size", 0);
 	stm32mp_otg_data.tx_fifo_sz = fdtdec_get_int(blob, node,
 						     "g-tx-fifo-size", 0);
-
-	if (fdtdec_get_bool(blob, node, "usb1600")) {
-		stusb1600_init();
+	*usb1600 = fdtdec_get_bool(blob, node, "usb1600");
+	if (*usb1600)
 		return;
-	}
 
 	/* Enable voltage level detector */
 	if (!(fdtdec_parse_phandle_with_args(blob, node, "usb33d-supply",
@@ -373,50 +258,60 @@ void board_usbotg_init(void)
 						    args.node, &dev))
 			if (regulator_set_enable(dev, true)) {
 				debug("Failed to enable usb33d\n");
-				goto clk_err;
+				goto phy_init_err;
 			}
 
 	return;
 
+phy_init_err:
+	generic_phy_exit(&phy);
+
+phy_power_err:
+	generic_phy_power_off(&phy);
+
 clk_err:
 	clk_disable(&clk);
 }
+#endif /* CONFIG_USB_DWC2 || CONFIG_USB_GADGET */
 
+#ifdef CONFIG_USB_GADGET
+#define STM32MP_GGPIO 0x38
+#define STM32MP_GGPIO_VBUS_SENSING BIT(21)
 int board_usb_init(int index, enum usb_init_type init)
 {
-	if (init == USB_INIT_HOST)
-		return 0;
+	bool usb1600 = *((bool *)stm32mp_otg_data.priv);
 
 	if (stm32mp_otg_data.regs_otg == FDT_ADDR_T_NONE)
 		return -EINVAL;
 
-	/* Reset usbotg */
-	reset_assert(&usbotg_reset);
-	udelay(2);
-	reset_deassert(&usbotg_reset);
-
 	/* if the board embed an USB1600 chip */
-	if (stm32mp_otg_data.priv)
+	if (usb1600)
 		/* Override A/B session valid bits */
-		stm32mp_otg_data.usb_gotgctl = DWC2_GOTGCTL_AVALIDOVEN |
-					       DWC2_GOTGCTL_AVALIDOVVAL |
-					       DWC2_GOTGCTL_BVALIDOVEN |
-					       DWC2_GOTGCTL_BVALIDOVVAL;
+		stm32mp_otg_data.usb_gotgctl = STM32MP_GOTGCTL_AVALIDOVEN |
+					       STM32MP_GOTGCTL_AVALIDOVVAL |
+					       STM32MP_GOTGCTL_BVALIDOVEN |
+					       STM32MP_GOTGCTL_BVALIDOVVAL;
 	else
 		/* Enable vbus sensing */
-		setbits_le32(stm32mp_otg_data.regs_otg + DWC2_GGPIO_OFFSET,
-			     DWC2_GGPIO_VBUS_SENSING);
+		setbits_le32(stm32mp_otg_data.regs_otg + STM32MP_GGPIO,
+			     STM32MP_GGPIO_VBUS_SENSING);
 
 	return dwc2_udc_probe(&stm32mp_otg_data);
 }
 
-int g_dnl_board_usb_cable_connected(void)
+int board_usb_cleanup(int index, enum usb_init_type init)
 {
-	if (stm32mp_otg_data.priv)
-		return stusb1600_cable_connected();
+	/* Reset usbotg */
+	reset_assert(&usbotg_reset);
+	udelay(2);
+	reset_deassert(&usbotg_reset);
+
+	return 0;
+}
 
-	return readl(stm32mp_otg_data.regs_otg + DWC2_GOTGCTL_OFFSET) &
-		DWC2_GOTGCTL_BSVLD;
+int g_dnl_board_usb_cable_connected(void)
+{
+	return 1;
 }
 
 #define STM32MP1_G_DNL_DFU_PRODUCT_NUM 0xdf11
@@ -431,35 +326,49 @@ int g_dnl_bind_fixup(struct usb_device_descriptor *dev, const char *name)
 }
 #endif /* CONFIG_USB_GADGET */
 
+#define SYSCFG_IOCTLRLR_HSLVEN_TRACE	BIT(0)
+#define SYSCFG_IOCTLRLR_HSLVEN_QUADSPI	BIT(1)
+#define SYSCFG_IOCTLRLR_HSLVEN_ETH	BIT(2)
+#define SYSCFG_IOCTLRLR_HSLVEN_SDMMC	BIT(3)
+#define SYSCFG_IOCTLRLR_HSLVEN_SPI	BIT(4)
+
+#define SYSCFG_CMPCR_CMP_PD	BIT(0)
+#define SYSCFG_CMPCR_SW_CTRL	BIT(1)
+#define SYSCFG_CMPCR_READY	BIT(8)
+
+#define SYSCFG_PMCR_ETH_CLK_SEL	BIT(16)
+#define SYSCFG_PMCR_ETH_REF_CLK_SEL	BIT(17)
+#define SYSCFG_PMCR_ETH_SEL_GMII_MII	0
+#define SYSCFG_PMCR_ETH_SEL_RGMII	BIT(21)
+#define SYSCFG_PMCR_ETH_SEL_RMII	BIT(23)
+
 static void sysconf_init(void)
 {
-	u8 *syscfg;
+	struct stm32_syscfg_regs *syscfg;
 #ifdef CONFIG_DM_REGULATOR
 	struct udevice *pwr_dev;
 	struct udevice *pwr_reg;
-	struct udevice *dev;
 	int ret;
-	u32 otp = 0;
 #endif
 	u32 bootr;
 
-	syscfg = (u8 *)syscon_get_first_range(STM32MP_SYSCON_SYSCFG);
+	syscfg = syscon_get_first_range(STM32MP_SYSCON_SYSCFG);
 	debug("SYSCFG: init @0x%p\n", syscfg);
 
 	/* interconnect update : select master using the port 1 */
 	/* LTDC = AXI_M9 */
 	/* GPU  = AXI_M8 */
 	/* today information is hardcoded in U-Boot */
-	writel(BIT(9), syscfg + SYSCFG_ICNR);
+	writel(BIT(9), &syscfg->icnr);
 	debug("[0x%x] SYSCFG.icnr = 0x%08x (LTDC and GPU)\n",
-	      (u32)syscfg + SYSCFG_ICNR, readl(syscfg + SYSCFG_ICNR));
+	      (u32)&syscfg->icnr, readl(&syscfg->icnr));
 
 	/* disable Pull-Down for boot pin connected to VDD */
-	bootr = readl(syscfg + SYSCFG_BOOTR);
+	bootr = readl(&syscfg->bootr);
 	bootr |= (bootr & 0x7 << 4);
-	writel(bootr, syscfg + SYSCFG_BOOTR);
+	writel(bootr, &syscfg->bootr);
 	debug("[0x%x] SYSCFG.bootr = 0x%08x\n",
-	      (u32)syscfg + SYSCFG_BOOTR, readl(syscfg + SYSCFG_BOOTR));
+	      (u32)&syscfg->bootr, readl(&syscfg->bootr));
 
 #ifdef CONFIG_DM_REGULATOR
 	/* High Speed Low Voltage Pad mode Enable for SPI, SDMMC, ETH, QSPI
@@ -477,19 +386,13 @@ static void sysconf_init(void)
 	 */
 	ret = syscon_get_by_driver_data(STM32MP_SYSCON_PWR, &pwr_dev);
 	if (!ret) {
+#ifdef CONFIG_STM32MP_FUSE
+		u32 otp = 0;
 
-		ret = uclass_get_device_by_driver(UCLASS_MISC,
-						  DM_GET_DRIVER(stm32mp_bsec),
-						  &dev);
-		if (ret) {
-			pr_err("Can't find stm32mp_bsec driver\n");
-			return;
-		}
-
-		ret = misc_read(dev, STM32_BSEC_SHADOW(18), &otp, 4);
+		ret = fuse_sense(0, 18, &otp);
 		if (!ret)
 			otp = otp & BIT(13);
-
+#endif
 		/* get VDD = pwr-supply */
 		ret = device_get_supply_regulator(pwr_dev, "pwr-supply",
 						  &pwr_reg);
@@ -497,97 +400,82 @@ static void sysconf_init(void)
 		/* check if VDD is Low Voltage */
 		if (!ret) {
 			if (regulator_get_value(pwr_reg) < 2700000) {
-				writel(SYSCFG_IOCTRLSETR_HSLVEN_TRACE |
-				       SYSCFG_IOCTRLSETR_HSLVEN_QUADSPI |
-				       SYSCFG_IOCTRLSETR_HSLVEN_ETH |
-				       SYSCFG_IOCTRLSETR_HSLVEN_SDMMC |
-				       SYSCFG_IOCTRLSETR_HSLVEN_SPI,
-				       syscfg + SYSCFG_IOCTRLSETR);
-
+				setbits_le32(&syscfg->ioctrlr,
+					     SYSCFG_IOCTLRLR_HSLVEN_TRACE |
+					     SYSCFG_IOCTLRLR_HSLVEN_QUADSPI |
+					     SYSCFG_IOCTLRLR_HSLVEN_ETH |
+					     SYSCFG_IOCTLRLR_HSLVEN_SDMMC |
+					     SYSCFG_IOCTLRLR_HSLVEN_SPI);
+#ifdef CONFIG_STM32MP_FUSE
 				if (!otp)
-					pr_err("product_below_2v5=0: HSLVEN protected by HW\n");
-			} else {
-				if (otp)
-					pr_err("product_below_2v5=1: HSLVEN update is destructive, no update as VDD>2.7V\n");
+					pr_err(
+					       "product_below_2v5=0: HSLVEN protected by HW\n");
+#endif
 			}
+#ifdef CONFIG_STM32MP_FUSE
+			else if (otp)
+				pr_err(
+				      "product_below_2v5=1: HSLVEN update is destructive, no update as VDD>2.7V\n");
+#endif
 		} else {
 			debug("VDD unknown");
 		}
 	}
 #endif
-	debug("[0x%x] SYSCFG.IOCTRLSETR = 0x%08x\n",
-	      (u32)syscfg + SYSCFG_IOCTRLSETR,
-	      readl(syscfg + SYSCFG_IOCTRLSETR));
+	debug("[0x%x] SYSCFG.ioctrlr = 0x%08x\n",
+	      (u32)&syscfg->ioctrlr, readl(&syscfg->ioctrlr));
 
 	/* activate automatic I/O compensation
 	 * warning: need to ensure CSI enabled and ready in clock driver
 	 */
-	writel(SYSCFG_CMPENSETR_MPU_EN, syscfg + SYSCFG_CMPENSETR);
-
-	while (!(readl(syscfg + SYSCFG_CMPCR) & SYSCFG_CMPCR_READY))
+	setbits_le32(&syscfg->cmpcr, SYSCFG_CMPCR_CMP_PD);
+	while (!(readl(&syscfg->cmpcr) & SYSCFG_CMPCR_READY))
 		;
-	clrbits_le32(syscfg + SYSCFG_CMPCR, SYSCFG_CMPCR_SW_CTRL);
+	clrbits_le32(&syscfg->cmpcr, SYSCFG_CMPCR_SW_CTRL);
 
 	debug("[0x%x] SYSCFG.cmpcr = 0x%08x\n",
-	      (u32)syscfg + SYSCFG_CMPCR, readl(syscfg + SYSCFG_CMPCR));
+	      (u32)&syscfg->cmpcr, readl(&syscfg->cmpcr));
 }
 
 /* board interface eth init */
 /* this is a weak define that we are overriding */
-int board_interface_eth_init(int interface_type, bool eth_clk_sel_reg,
-			     bool eth_ref_clk_sel_reg)
+int board_interface_eth_init(int interface_type)
 {
-	u8 *syscfg;
-	u32 value;
+	struct stm32_syscfg_regs *syscfg;
 
-	syscfg = (u8 *)syscon_get_first_range(STM32MP_SYSCON_SYSCFG);
+	syscfg = syscon_get_first_range(STM32MP_SYSCON_SYSCFG);
 
 	if (!syscfg)
 		return -ENODEV;
 
 	switch (interface_type) {
 	case PHY_INTERFACE_MODE_MII:
-		value = SYSCFG_PMCSETR_ETH_SEL_GMII_MII |
-			SYSCFG_PMCSETR_ETH_REF_CLK_SEL;
-		debug("%s: PHY_INTERFACE_MODE_MII\n", __func__);
+		setbits_le32(&syscfg->pmcr, SYSCFG_PMCR_ETH_SEL_GMII_MII |
+			     SYSCFG_PMCR_ETH_REF_CLK_SEL);
+		debug("SYSCFG init : PHY_INTERFACE_MODE_MII\n");
 		break;
 	case PHY_INTERFACE_MODE_GMII:
-		if (eth_clk_sel_reg)
-			value = SYSCFG_PMCSETR_ETH_SEL_GMII_MII |
-				SYSCFG_PMCSETR_ETH_CLK_SEL;
-		else
-			value = SYSCFG_PMCSETR_ETH_SEL_GMII_MII;
-		debug("%s: PHY_INTERFACE_MODE_GMII\n", __func__);
+		setbits_le32(&syscfg->pmcr, SYSCFG_PMCR_ETH_SEL_GMII_MII |
+			     SYSCFG_PMCR_ETH_CLK_SEL);
+		debug("SYSCFG init : PHY_INTERFACE_MODE_GMII\n");
 		break;
 	case PHY_INTERFACE_MODE_RMII:
-		if (eth_ref_clk_sel_reg)
-			value = SYSCFG_PMCSETR_ETH_SEL_RMII |
-				SYSCFG_PMCSETR_ETH_REF_CLK_SEL;
-		else
-			value = SYSCFG_PMCSETR_ETH_SEL_RMII;
-		debug("%s: PHY_INTERFACE_MODE_RMII\n", __func__);
+		setbits_le32(&syscfg->pmcr, SYSCFG_PMCR_ETH_SEL_RMII | SYSCFG_PMCR_ETH_REF_CLK_SEL);
+		debug("SYSCFG init : PHY_INTERFACE_MODE_RMII\n");
+		/* use internal clock */
+		printf("PHY clock from internal RCC\n");
+		//printf("pmcr 0x%08X\n", syscfg->pmcr);
 		break;
 	case PHY_INTERFACE_MODE_RGMII:
-		if (eth_clk_sel_reg)
-			value = SYSCFG_PMCSETR_ETH_SEL_RGMII |
-				SYSCFG_PMCSETR_ETH_CLK_SEL;
-		else
-			value = SYSCFG_PMCSETR_ETH_SEL_RGMII;
-		debug("%s: PHY_INTERFACE_MODE_RGMII\n", __func__);
+		setbits_le32(&syscfg->pmcr, SYSCFG_PMCR_ETH_SEL_RGMII);
+		debug("SYSCFG init : PHY_INTERFACE_MODE_RGMII\n");
 		break;
 	default:
-		debug("%s: Do not manage %d interface\n",
-		      __func__, interface_type);
+		debug("SYSCFG init :  Do not manage %d interface\n",
+		      interface_type);
 		/* Do not manage others interfaces */
 		return -EINVAL;
 	}
-
-	/* clear and set ETH configuration bits */
-	writel(SYSCFG_PMCSETR_ETH_SEL_MASK | SYSCFG_PMCSETR_ETH_SELMII |
-	       SYSCFG_PMCSETR_ETH_REF_CLK_SEL | SYSCFG_PMCSETR_ETH_CLK_SEL,
-	       syscfg + SYSCFG_PMCCLRR);
-	writel(value, syscfg + SYSCFG_PMCSETR);
-
 	return 0;
 }
 
@@ -612,7 +500,6 @@ int board_phy_config(struct phy_device *phydev)
 		return phydev->drv->config(phydev);
 	return 0;
 }
-
 #ifdef CONFIG_LED
 static int get_led(struct udevice **dev, char *led_string)
 {
@@ -634,7 +521,7 @@ static int get_led(struct udevice **dev, char *led_string)
 	return 0;
 }
 
-static int setup_led(enum led_state_t cmd)
+static int setup_led(void)
 {
 	struct udevice *dev;
 	int ret;
@@ -643,8 +530,11 @@ static int setup_led(enum led_state_t cmd)
 	if (ret)
 		return ret;
 
-	ret = led_set_state(dev, cmd);
-	return ret;
+	ret = led_set_state(dev, LEDST_ON);
+	if (ret)
+		return ret;
+
+	return 0;
 }
 #endif /* CONFIG_LED */
 
@@ -817,28 +707,21 @@ error:
 /* board dependent setup after realloc */
 int board_init(void)
 {
-	struct udevice *dev;
-
+	int ret;
 	/* address of boot parameters */
 	gd->bd->bi_boot_params = STM32_DDR_BASE + 0x100;
 
-	/* probe all PINCTRL for hog */
-	for (uclass_first_device(UCLASS_PINCTRL, &dev);
-	     dev;
-	     uclass_next_device(&dev)) {
-		pr_debug("probe pincontrol = %s\n", dev->name);
-	}
-
-	board_key_check();
-
-	if (IS_ENABLED(CONFIG_LED))
-		led_default_state();
-
 #ifdef CONFIG_DM_REGULATOR
 	if (board_is_dk2())
 		dk2_i2c1_fix();
+#endif
+
+#ifdef CONFIG_LED
+	setup_led();
+#endif /* CONFIG_LED */
 
-	regulators_enable_boot_on(_DEBUG);
+#ifdef CONFIG_FASTBOOT
+	board_fastboot_check();
 #endif
 
 #ifdef CONFIG_ADC
@@ -847,6 +730,11 @@ int board_init(void)
 
 	sysconf_init();
 
+	/* switch on all regulators with tag 'enable-boot-on' in device tree */
+	ret = regulators_enable_boot_on(false);
+	if (ret)
+		pr_err("%s: Error: Cannot enable boot on regulator\n", __func__);
+
 #ifdef CONFIG_STM32_SDMMC2
 	board_mmc_init();
 #endif /* CONFIG_STM32_SDMMC2 */
@@ -855,19 +743,80 @@ int board_init(void)
 	board_qspi_init();
 #endif /* CONFIG_STM32_QSPI */
 
-#if defined(CONFIG_USB_GADGET) && defined(CONFIG_USB_GADGET_DWC2_OTG)
+#ifdef CONFIG_USB_EHCI_GENERIC
+	board_usbh_init();
+#endif /* CONFIG_USB_EHCI_GENERIC */
+
+#if defined(CONFIG_USB_DWC2) || defined(CONFIG_USB_GADGET)
 	board_usbotg_init();
-#endif
+#endif /* CONFIG_USB_DWC2 || CONFIG_USB_GADGET */
 
 	return 0;
 }
 
-void board_quiesce_devices(void)
+#ifdef CONFIG_SPLASH_SCREEN
+static const struct splash_location stm32mp_splash_locations[] = {
+	{
+		.name = "mmc0",
+		.storage = SPLASH_STORAGE_MMC,
+		.flags = SPLASH_STORAGE_FS,
+#ifdef CONFIG_STM32MP1_OPTEE
+		.devpart = "0:7",
+#else
+		.devpart = "0:4",
+#endif
+	},
+	{
+		.name = "mmc1",
+		.storage = SPLASH_STORAGE_MMC,
+		.flags = SPLASH_STORAGE_FS,
+#ifdef CONFIG_STM32MP1_OPTEE
+		.devpart = "1:5",
+#else
+		.devpart = "1:2",
+#endif
+	},
+	{
+		.name = "nor0",
+		.storage = SPLASH_STORAGE_SF,
+		.flags = SPLASH_STORAGE_RAW,
+		.offset = 0x00280000,
+	},
+	{
+		.name = "nand0",
+		.storage = SPLASH_STORAGE_NAND,
+		.flags = SPLASH_STORAGE_FS,
+		.mtdpart = "UBI",
+		.ubivol = "ubi0:boot",
+	},
+};
+
+int splash_screen_prepare(void)
 {
-#ifdef CONFIG_LED
-	setup_led(LEDST_OFF);
+	char buffer[16];
+
+	if (!env_get("splashsource")) {
+		snprintf(buffer, sizeof(buffer), "%s%s",
+			 env_get("boot_device"), env_get("boot_instance"));
+		env_set("splashsource", buffer);
+	}
+	return splash_source_load(
+		(struct splash_location *)&stm32mp_splash_locations,
+		ARRAY_SIZE(stm32mp_splash_locations));
+}
 #endif
+
+#ifdef CONFIG_MISC_INIT_R
+int misc_init_r(void)
+{
+	if (!video_splash()) {
+		env_set("stderr", "serial");
+		env_set("stdout", "serial");
+	}
+
+	return 0;
 }
+#endif
 
 #ifdef CONFIG_SYS_MTDPARTS_RUNTIME
 void board_mtdparts_default(const char **mtdids, const char **mtdparts)
@@ -875,10 +824,15 @@ void board_mtdparts_default(const char **mtdids, const char **mtdparts)
 	struct udevice *dev;
 	char *s_nand0 = NULL, *s_nor0 = NULL;
 	static char parts[256];
-	static char ids[30];
+	static char ids[22];
 
-	if (!uclass_get_device(UCLASS_MTD, 0, &dev))
-		s_nand0 = env_get("mtdparts_spi-nand0");
+	if (!uclass_get_device(UCLASS_NAND, 0, &dev))
+		s_nand0 = env_get("mtdparts_nand0");
+
+#ifdef CONFIG_STM32MP15x_REVA
+	if (s_nand0 && (get_cpu_rev() == CPU_REVA))
+		s_nand0 = env_get("mtdparts_nand0_reva");
+#endif
 
 	if (!uclass_get_device(UCLASS_SPI_FLASH, 0, &dev))
 		s_nor0 = env_get("mtdparts_nor0");
@@ -886,12 +840,12 @@ void board_mtdparts_default(const char **mtdids, const char **mtdparts)
 	strcpy(ids, "");
 	strcpy(parts, "");
 	if (s_nand0 && s_nor0) {
-		snprintf(ids, sizeof(ids), "nor0=nor0,spi-nand0=spi-nand0");
+		snprintf(ids, sizeof(ids), "nor0=nor0,nand0=nand0");
 		snprintf(parts, sizeof(parts),
-			 "mtdparts=nor0:%s;spi-nand0:%s", s_nor0, s_nand0);
+			 "mtdparts=nor0:%s;nand0:%s", s_nor0, s_nand0);
 	} else if (s_nand0) {
-		snprintf(ids, sizeof(ids), "spi-nand0=spi-nand0");
-		snprintf(parts, sizeof(parts), "mtdparts=spi-nand0:%s", s_nand0);
+		snprintf(ids, sizeof(ids), "nand0=nand0");
+		snprintf(parts, sizeof(parts), "mtdparts=nand0:%s", s_nand0);
 	} else if (s_nor0) {
 		snprintf(ids, sizeof(ids), "nor0=nor0");
 		snprintf(parts, sizeof(parts), "mtdparts=nor0:%s", s_nor0);
@@ -905,36 +859,33 @@ void board_mtdparts_default(const char **mtdids, const char **mtdparts)
 #if defined(CONFIG_OF_BOARD_SETUP)
 int ft_board_setup(void *blob, bd_t *bd)
 {
-	ulong copro_rsc_addr, copro_rsc_size;
-	int off;
+	ulong copro_rsc_addr = 0;
+	int copro_rsc_size = 0;
 	char *s_copro = NULL;
 #ifdef CONFIG_FDT_FIXUP_PARTITIONS
 	struct node_info nodes[] = {
 		{ "st,stm32f469-qspi",		MTD_DEV_TYPE_NOR,  },
-		{ "st,stm32mp15-fmc2",		MTD_DEV_TYPE_NAND, },
+		{ "st,stm32mp1-fmc",		MTD_DEV_TYPE_NAND, },
 	};
 	fdt_fixup_mtdparts(blob, nodes, ARRAY_SIZE(nodes));
 #endif
 
 	/* Update DT if coprocessor started */
-	off = fdt_path_offset(blob, "/m4");
-	if (off > 0) {
-		s_copro = env_get("copro_state");
-		copro_rsc_addr  = env_get_hex("copro_rsc_addr", 0);
-		copro_rsc_size  = env_get_hex("copro_rsc_size", 0);
-
-		if (s_copro) {
-			fdt_setprop_empty(blob, off, "early-booted");
-			if (copro_rsc_addr)
-				fdt_setprop_u32(blob, off, "rsc-address",
-						copro_rsc_addr);
-			if (copro_rsc_size)
-				fdt_setprop_u32(blob, off, "rsc-size",
-						copro_rsc_size);
-		} else {
-			fdt_delprop(blob, off, "early-booted");
-		}
-	}
+	s_copro = env_get("copro_state");
+	copro_rsc_addr  = env_get_hex("copro_rsc_addr", 0);
+	copro_rsc_size  = env_get_hex("copro_rsc_size", 0);
+
+	if (s_copro)
+		do_fixup_by_path_u32(blob, "/soc/m4",
+				     "early-booted", 1, 1);
+
+	if (s_copro && copro_rsc_addr)
+		do_fixup_by_path_u32(blob, "/soc/m4",
+				     "rsc-address", copro_rsc_addr, 1);
+
+	if (s_copro && copro_rsc_size)
+		do_fixup_by_path_u32(blob, "/soc/m4",
+				     "rsc-size", copro_rsc_size, 1);
 
 	return 0;
 }
@@ -947,11 +898,7 @@ void board_stm32copro_image_process(ulong fw_image, size_t fw_size)
 	ulong rsc_addr;
 
 	if (!rproc_is_initialized())
-		if (rproc_init()) {
-			printf("Remote Processor %d initialization failed\n",
-			       id);
-			return;
-		}
+		rproc_init();
 
 	ret = rproc_load_rsc_table(id, fw_image, fw_size, &rsc_addr, &rsc_size);
 	if (!ret) {
@@ -970,3 +917,4 @@ void board_stm32copro_image_process(ulong fw_image, size_t fw_size)
 }
 
 U_BOOT_FIT_LOADABLE_HANDLER(IH_TYPE_STM32COPRO, board_stm32copro_image_process);
+
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/board/kontron/stm32mp1-t1000/Kconfig b/recipes-bsp/u-boot/u-boot-stm32mp/board/kontron/stm32mp1-t1000/Kconfig
deleted file mode 100644
index 00f6659819d0d0dfc535b9ba3b65d573ccf4faec..0000000000000000000000000000000000000000
--- a/recipes-bsp/u-boot/u-boot-stm32mp/board/kontron/stm32mp1-t1000/Kconfig
+++ /dev/null
@@ -1,19 +0,0 @@
-if TARGET_STM32MP1_T1000
-
-config SYS_BOARD
-	default "stm32mp1-t1000"
-
-config SYS_VENDOR
-	default "kontron"
-
-config SYS_CONFIG_NAME
-	default "stm32mp1-t1000"
-
-config CMD_STBOARD
-	bool "stboard - command for OTP board information"
-	default y
-	help
-	  This compile the stboard command to
-	  read and write the board in the OTP.
-
-endif
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/board/kontron/stm32mp1-t1000/Makefile b/recipes-bsp/u-boot/u-boot-stm32mp/board/kontron/stm32mp1-t1000/Makefile
deleted file mode 100644
index ec22283f7affa436fd704f00d4639749b5c2f708..0000000000000000000000000000000000000000
--- a/recipes-bsp/u-boot/u-boot-stm32mp/board/kontron/stm32mp1-t1000/Makefile
+++ /dev/null
@@ -1,13 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
-#
-# Copyright (C) 2018, STMicroelectronics - All Rights Reserved
-#
-
-ifdef CONFIG_SPL_BUILD
-obj-y += spl.o
-else
-obj-y += stm32mp1-t1000.o
-obj-$(CONFIG_CMD_STBOARD) += cmd_stboard.o
-endif
-
-obj-y += board.o
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/board/kontron/stm32mp1-t1000/board.c b/recipes-bsp/u-boot/u-boot-stm32mp/board/kontron/stm32mp1-t1000/board.c
deleted file mode 100644
index b6e528878e79c2bb51ea110b718fea90ec57cd83..0000000000000000000000000000000000000000
--- a/recipes-bsp/u-boot/u-boot-stm32mp/board/kontron/stm32mp1-t1000/board.c
+++ /dev/null
@@ -1,177 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
-/*
- * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
- */
-
-#include <common.h>
-#include <dm.h>
-#include <asm/io.h>
-#include <asm/arch/ddr.h>
-#include <power/pmic.h>
-#include <power/stpmic1.h>
-
-#ifdef CONFIG_DEBUG_UART_BOARD_INIT
-void board_debug_uart_init(void)
-{
-#if (CONFIG_DEBUG_UART_BASE == STM32_UART4_BASE)
-
-#define RCC_MP_APB1ENSETR (STM32_RCC_BASE + 0x0A00)
-#define RCC_MP_AHB4ENSETR (STM32_RCC_BASE + 0x0A28)
-
-	/* UART4 clock enable */
-	setbits_le32(RCC_MP_APB1ENSETR, BIT(16));
-
-#define GPIOG_BASE 0x50008000
-	/* GPIOG clock enable */
-	writel(BIT(6), RCC_MP_AHB4ENSETR);
-	/* GPIO configuration for EVAL board
-	 * => Uart4 TX = G11
-	 */
-	writel(0xffbfffff, GPIOG_BASE + 0x00);
-	writel(0x00006000, GPIOG_BASE + 0x24);
-#else
-
-#error("CONFIG_DEBUG_UART_BASE: not supported value")
-
-#endif
-}
-#endif
-
-#ifdef CONFIG_PMIC_STPMIC1
-int board_ddr_power_init(enum ddr_type ddr_type)
-{
-	struct udevice *dev;
-	bool buck3_at_1800000v = false;
-	int ret;
-
-	ret = uclass_get_device_by_driver(UCLASS_PMIC,
-					  DM_GET_DRIVER(pmic_stpmic1), &dev);
-	if (ret)
-		/* No PMIC on power discrete board */
-		return 0;
-
-	switch (ddr_type) {
-	case STM32MP_DDR3:
-		/* VTT = Set LDO3 to sync mode */
-		ret = pmic_reg_read(dev, STPMIC1_LDOX_MAIN_CR(STPMIC1_LDO3));
-		if (ret < 0)
-			return ret;
-
-		ret &= ~STPMIC1_LDO3_MODE;
-		ret &= ~STPMIC1_LDO12356_VOUT_MASK;
-		ret |= STPMIC1_LDO_VOUT(STPMIC1_LDO3_DDR_SEL);
-
-		ret = pmic_reg_write(dev, STPMIC1_LDOX_MAIN_CR(STPMIC1_LDO3),
-				     ret);
-		if (ret < 0)
-			return ret;
-
-		/* VDD_DDR = Set BUCK2 to 1.35V */
-		ret = pmic_clrsetbits(dev,
-				      STPMIC1_BUCKX_MAIN_CR(STPMIC1_BUCK2),
-				      STPMIC1_BUCK_VOUT_MASK,
-				      STPMIC1_BUCK2_1350000V);
-		if (ret < 0)
-			return ret;
-
-		/* Enable VDD_DDR = BUCK2 */
-		ret = pmic_clrsetbits(dev,
-				      STPMIC1_BUCKX_MAIN_CR(STPMIC1_BUCK2),
-				      STPMIC1_BUCK_ENA, STPMIC1_BUCK_ENA);
-		if (ret < 0)
-			return ret;
-
-		mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS);
-
-		/* Enable VREF */
-		ret = pmic_clrsetbits(dev, STPMIC1_REFDDR_MAIN_CR,
-				      STPMIC1_VREF_ENA, STPMIC1_VREF_ENA);
-		if (ret < 0)
-			return ret;
-
-		mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS);
-
-		/* Enable VTT = LDO3 */
-		ret = pmic_clrsetbits(dev,
-				      STPMIC1_LDOX_MAIN_CR(STPMIC1_LDO3),
-				      STPMIC1_LDO_ENA, STPMIC1_LDO_ENA);
-		if (ret < 0)
-			return ret;
-
-		mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS);
-
-		break;
-
-	case STM32MP_LPDDR2:
-	case STM32MP_LPDDR3:
-		/*
-		 * configure VDD_DDR1 = LDO3
-		 * Set LDO3 to 1.8V
-		 * + bypass mode if BUCK3 = 1.8V
-		 * + normal mode if BUCK3 != 1.8V
-		 */
-		ret = pmic_reg_read(dev,
-				    STPMIC1_BUCKX_MAIN_CR(STPMIC1_BUCK3));
-		if (ret < 0)
-			return ret;
-
-		if ((ret & STPMIC1_BUCK3_1800000V) == STPMIC1_BUCK3_1800000V)
-			buck3_at_1800000v = true;
-
-		ret = pmic_reg_read(dev, STPMIC1_LDOX_MAIN_CR(STPMIC1_LDO3));
-		if (ret < 0)
-			return ret;
-
-		ret &= ~STPMIC1_LDO3_MODE;
-		ret &= ~STPMIC1_LDO12356_VOUT_MASK;
-		ret |= STPMIC1_LDO3_1800000;
-		if (buck3_at_1800000v)
-			ret |= STPMIC1_LDO3_MODE;
-
-		ret = pmic_reg_write(dev, STPMIC1_LDOX_MAIN_CR(STPMIC1_LDO3),
-				     ret);
-		if (ret < 0)
-			return ret;
-
-		/* VDD_DDR2 : Set BUCK2 to 1.2V */
-		ret = pmic_clrsetbits(dev,
-				      STPMIC1_BUCKX_MAIN_CR(STPMIC1_BUCK2),
-				      STPMIC1_BUCK_VOUT_MASK,
-				      STPMIC1_BUCK2_1200000V);
-		if (ret < 0)
-			return ret;
-
-		/* Enable VDD_DDR1 = LDO3 */
-		ret = pmic_clrsetbits(dev, STPMIC1_LDOX_MAIN_CR(STPMIC1_LDO3),
-				      STPMIC1_LDO_ENA, STPMIC1_LDO_ENA);
-		if (ret < 0)
-			return ret;
-
-		mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS);
-
-		/* Enable VDD_DDR22 =BUCK2 */
-		ret = pmic_clrsetbits(dev,
-				      STPMIC1_BUCKX_MAIN_CR(STPMIC1_BUCK2),
-				      STPMIC1_BUCK_ENA, STPMIC1_BUCK_ENA);
-		if (ret < 0)
-			return ret;
-
-		mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS);
-
-		/* Enable VREF */
-		ret = pmic_clrsetbits(dev, STPMIC1_REFDDR_MAIN_CR,
-				      STPMIC1_VREF_ENA, STPMIC1_VREF_ENA);
-		if (ret < 0)
-			return ret;
-
-		mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS);
-
-		break;
-
-	default:
-		break;
-	};
-
-	return 0;
-}
-#endif
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/board/kontron/stm32mp1-t1000/cmd_stboard.c b/recipes-bsp/u-boot/u-boot-stm32mp/board/kontron/stm32mp1-t1000/cmd_stboard.c
deleted file mode 100644
index 38b1c1be1e02356c9bdfb8521ccc612605fb93e9..0000000000000000000000000000000000000000
--- a/recipes-bsp/u-boot/u-boot-stm32mp/board/kontron/stm32mp1-t1000/cmd_stboard.c
+++ /dev/null
@@ -1,145 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
-/*
- * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
- */
-
-#include <common.h>
-#include <console.h>
-#include <misc.h>
-#include <dm/device.h>
-#include <dm/uclass.h>
-
-static bool check_stboard(u16 board)
-{
-	int i;
-	const u16 st_board_id[] = {
-		0x1272,
-		0x1263,
-		0x1264,
-		0x1298,
-		0x1341,
-		0x1497,
-	};
-
-	for (i = 0; i < ARRAY_SIZE(st_board_id); i++)
-		if (board == st_board_id[i])
-			return true;
-
-	return false;
-}
-
-static void display_stboard(u32 otp)
-{
-	printf("Board: MB%04x Var%d Rev.%c-%02d\n",
-	       otp >> 16,
-	       (otp >> 12) & 0xF,
-	       ((otp >> 8) & 0xF) - 1 + 'A',
-	       otp & 0xF);
-}
-
-static int do_stboard(cmd_tbl_t *cmdtp, int flag, int argc,
-		      char * const argv[])
-{
-	int ret;
-	u32 otp;
-	u8 revision;
-	unsigned long board, variant, bom;
-	struct udevice *dev;
-	int confirmed = argc == 6 && !strcmp(argv[1], "-y");
-
-	argc -= 1 + confirmed;
-	argv += 1 + confirmed;
-
-	if (argc != 0 && argc != 4)
-		return CMD_RET_USAGE;
-
-	ret = uclass_get_device_by_driver(UCLASS_MISC,
-					  DM_GET_DRIVER(stm32mp_bsec),
-					  &dev);
-
-	ret = misc_read(dev, STM32_BSEC_SHADOW(BSEC_OTP_BOARD),
-			&otp, sizeof(otp));
-
-	if (ret) {
-		puts("OTP read error");
-		return CMD_RET_FAILURE;
-	}
-
-	if (argc == 0) {
-		if (!otp)
-			puts("Board : OTP board FREE\n");
-		else
-			display_stboard(otp);
-		return CMD_RET_SUCCESS;
-	}
-
-	if (otp) {
-		display_stboard(otp);
-		printf("ERROR: OTP board not FREE\n");
-		return CMD_RET_FAILURE;
-	}
-
-	if (strict_strtoul(argv[0], 16, &board) < 0 ||
-	    board == 0 || board > 0xFFFF) {
-		printf("argument %d invalid: %s\n", 1, argv[0]);
-		return CMD_RET_USAGE;
-	}
-
-	if (strict_strtoul(argv[1], 10, &variant) < 0 ||
-	    variant == 0 || variant > 15) {
-		printf("argument %d invalid: %s\n", 2, argv[1]);
-		return CMD_RET_USAGE;
-	}
-
-	revision = argv[2][0] - 'A' + 1;
-	if (strlen(argv[2]) > 1 || revision == 0 || revision > 15) {
-		printf("argument %d invalid: %s\n", 3, argv[2]);
-		return CMD_RET_USAGE;
-	}
-
-	if (strict_strtoul(argv[3], 10, &bom) < 0 ||
-	    bom == 0 || bom > 15) {
-		printf("argument %d invalid: %s\n", 4, argv[3]);
-		return CMD_RET_USAGE;
-	}
-
-	otp = (board << 16) | (variant << 12) | (revision << 8) | bom;
-	display_stboard(otp);
-	printf("=> OTP[%d] = %08X\n", BSEC_OTP_BOARD, otp);
-
-	if (!check_stboard((u16)board)) {
-		printf("Unknown board MB%04x\n", (u16)board);
-		return CMD_RET_FAILURE;
-	}
-	if (!confirmed) {
-		printf("Warning: Programming BOARD in OTP is irreversible!\n");
-		printf("Really perform this OTP programming? <y/N>\n");
-
-		if (!confirm_yesno()) {
-			puts("BOARD programming aborted\n");
-			return CMD_RET_FAILURE;
-		}
-	}
-
-	ret = misc_write(dev, STM32_BSEC_OTP(BSEC_OTP_BOARD),
-			 &otp, sizeof(otp));
-
-	if (ret) {
-		puts("BOARD programming error\n");
-		return CMD_RET_FAILURE;
-	}
-	puts("BOARD programming done\n");
-
-	return CMD_RET_SUCCESS;
-}
-
-U_BOOT_CMD(stboard, 6, 0, do_stboard,
-	   "read/write board reference in OTP",
-	   "\n"
-	   "  Print current board information\n"
-	   "stboard [-y] <Board> <Variant> <Revision> <BOM>\n"
-	   "  Write board information\n"
-	   "  - Board: xxxx, example 1264 for MB1264\n"
-	   "  - Variant: 1 ... 15\n"
-	   "  - Revision: A...O\n"
-	   "  - BOM: 1...15\n");
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/board/kontron/stm32mp1-t1000/extlinux.conf b/recipes-bsp/u-boot/u-boot-stm32mp/board/kontron/stm32mp1-t1000/extlinux.conf
deleted file mode 100644
index 2b4632804df17c21a6e940c04374f909ad48beb3..0000000000000000000000000000000000000000
--- a/recipes-bsp/u-boot/u-boot-stm32mp/board/kontron/stm32mp1-t1000/extlinux.conf
+++ /dev/null
@@ -1,20 +0,0 @@
-# Generic Distro Configuration for STM32MP157
-menu title Select the boot mode
-TIMEOUT 20
-DEFAULT stm32mp157c-ev1
-
-LABEL stm32mp157c-ev1
-	KERNEL /fit_kernel_dtb.itb#ev1
-	APPEND root=/dev/mmcblk0p6 rootwait rw earlyprintk console=ttyS3,115200
-
-LABEL stm32mp157c-ev1-m4
-	KERNEL /fit_copro_kernel_dtb.itb#ev1-m4
-	APPEND root=/dev/mmcblk0p6 rootwait rw earlyprintk console=ttyS3,115200
-
-LABEL stm32mp157c-dk2
-	KERNEL /fit_kernel_dtb.itb#dk2
-	APPEND root=/dev/mmcblk0p6 rootwait rw earlyprintk console=ttyS3,115200
-
-LABEL stm32mp157c-dk2-m4
-	KERNEL /fit_copro_kernel_dtb.itb#dk2-m4
-	APPEND root=/dev/mmcblk0p6 rootwait rw earlyprintk console=ttyS3,115200
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/board/kontron/stm32mp1-t1000/fit_copro_kernel_dtb.its b/recipes-bsp/u-boot/u-boot-stm32mp/board/kontron/stm32mp1-t1000/fit_copro_kernel_dtb.its
deleted file mode 100644
index 7582fc35c5a74f8686dc3390e98e0183b6acbc70..0000000000000000000000000000000000000000
--- a/recipes-bsp/u-boot/u-boot-stm32mp/board/kontron/stm32mp1-t1000/fit_copro_kernel_dtb.its
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Compilation:
- * mkimage -f fit_copro_kernel_dtb.its fit_copro_kernel_dtb.itb
- */
-
-/dts-v1/;
-/ {
-	description = "U-Boot fitImage for stm32mp157";
-	#address-cells = <1>;
-
-	images {
-
-		copro {
-			description = "M4 copro";
-			data = /incbin/("stm32mp15_m4.elf");
-			type = "stm32copro";
-			arch = "arm";
-			compression = "none";
-			load = <0xC0800000>;
-			hash-1 {
-				algo = "sha1";
-			};
-		};
-
-		kernel {
-			description = "Linux kernel";
-			data = /incbin/("zImage");
-			type = "kernel";
-			arch = "arm";
-			os = "linux";
-			compression = "none";
-			load = <0xC0008000>;
-			entry = <0xC0008000>;
-			hash-1 {
-				algo = "sha1";
-			};
-		};
-
-		fdt-dk2 {
-			description = "FDT dk2";
-			data = /incbin/("stm32mp157c-dk2.dtb");
-			type = "flat_dt";
-			arch = "arm";
-			compression = "none";
-			hash-1 {
-				algo = "sha1";
-			};
-		};
-
-		fdt-ev1 {
-			description = "FDT ev1";
-			data = /incbin/("stm32mp157c-ev1.dtb");
-			type = "flat_dt";
-			arch = "arm";
-			compression = "none";
-			hash-1 {
-				algo = "sha1";
-			};
-		};
-	};
-
-	configurations {
-		default = "dk2-m4";
-
-		dk2-m4 {
-			description = "dk2-m4";
-			loadables = "copro";
-			kernel = "kernel";
-			fdt = "fdt-dk2";
-			hash-1 {
-				algo = "sha1";
-			};
-		};
-
-		dk2 {
-			description = "dk2";
-			kernel = "kernel";
-			fdt = "fdt-dk2";
-			hash-1 {
-				algo = "sha1";
-			};
-		};
-
-		ev1-m4 {
-			description = "ev1-m4";
-			loadables = "copro";
-			kernel = "kernel";
-			fdt = "fdt-ev1";
-			hash-1 {
-				algo = "sha1";
-			};
-		};
-
-		ev1 {
-			description = "ev1";
-			kernel = "kernel";
-			fdt = "fdt-ev1";
-			hash-1 {
-				algo = "sha1";
-			};
-		};
-	};
-};
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/board/kontron/stm32mp1-t1000/fit_kernel_dtb.its b/recipes-bsp/u-boot/u-boot-stm32mp/board/kontron/stm32mp1-t1000/fit_kernel_dtb.its
deleted file mode 100644
index 18d03ebf3c030b2aa3bbc4dff47b140fbe7b022a..0000000000000000000000000000000000000000
--- a/recipes-bsp/u-boot/u-boot-stm32mp/board/kontron/stm32mp1-t1000/fit_kernel_dtb.its
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Compilation:
- * mkimage -f fit_kernel_dtb.its fit_kernel_dtb.itb
- *
- * Files in linux build dir:
- * - arch/arm/boot/zImage
- * - arch/arm/boot/dts/stm32mp157c-dk2.dtb
- * - arch/arm/boot/dts/stm32mp157c-ev1.dtb
- *
- * load mmc 0:4 $kernel_addr_r fit_kernel_dtb.itb
- * bootm $kernel_addr_r
- * bootm $kernel_addr_r#dk2
- * bootm $kernel_addr_r#ev1
- *
- * or use extlinux.conf in this directory
- */
-
-/dts-v1/;
-/ {
-	description = "U-Boot fitImage for stm32mp157";
-	#address-cells = <1>;
-
-	images {
-		kernel {
-			description = "Linux kernel";
-			data = /incbin/("zImage");
-			type = "kernel";
-			arch = "arm";
-			os = "linux";
-			compression = "none";
-			load = <0xC0008000>;
-			entry = <0xC0008000>;
-			hash-1 {
-				algo = "sha1";
-			};
-		};
-
-		fdt-dk2 {
-			description = "FDT dk2";
-			data = /incbin/("stm32mp157c-dk2.dtb");
-			type = "flat_dt";
-			arch = "arm";
-			compression = "none";
-			hash-1 {
-				algo = "sha1";
-			};
-		};
-
-		fdt-ev1 {
-			description = "FDT ev1";
-			data = /incbin/("stm32mp157c-ev1.dtb");
-			type = "flat_dt";
-			arch = "arm";
-			compression = "none";
-			hash-1 {
-				algo = "sha1";
-			};
-		};
-	};
-
-	configurations {
-		default = "dk2";
-
-		dk2 {
-			description = "dk2";
-			kernel = "kernel";
-			fdt = "fdt-dk2";
-			hash-1 {
-				algo = "sha1";
-			};
-		};
-
-		ev1 {
-			description = "ev1";
-			kernel = "kernel";
-			fdt = "fdt-ev1";
-			hash-1 {
-				algo = "sha1";
-			};
-		};
-	};
-};
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/board/kontron/stm32mp1-t1000/spl.c b/recipes-bsp/u-boot/u-boot-stm32mp/board/kontron/stm32mp1-t1000/spl.c
deleted file mode 100644
index e65ff288ea1b40995d9f78c62e2423cb0b45f0d9..0000000000000000000000000000000000000000
--- a/recipes-bsp/u-boot/u-boot-stm32mp/board/kontron/stm32mp1-t1000/spl.c
+++ /dev/null
@@ -1,45 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
-/*
- * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
- */
-
-#include <config.h>
-#include <common.h>
-#include <spl.h>
-#include <dm.h>
-#include <ram.h>
-#include <asm/io.h>
-#include <power/pmic.h>
-#include <power/stpmic1.h>
-#include <asm/arch/ddr.h>
-
-void spl_board_init(void)
-{
-	/* Keep vdd on during the reset cycle */
-#if defined(CONFIG_PMIC_STPMIC1) && defined(CONFIG_SPL_POWER_SUPPORT)
-	struct udevice *dev;
-	int ret;
-
-	ret = uclass_get_device_by_driver(UCLASS_PMIC,
-					  DM_GET_DRIVER(pmic_stpmic1), &dev);
-	if (!ret)
-		pmic_clrsetbits(dev,
-				STPMIC1_BUCKS_MRST_CR,
-				STPMIC1_MRST_BUCK(STPMIC1_BUCK3),
-				STPMIC1_MRST_BUCK(STPMIC1_BUCK3));
-
-	/* Check if debug is enabled to program PMIC according to the bit */
-	if ((readl(TAMP_BOOT_CONTEXT) & TAMP_BOOT_DEBUG_ON) && !ret) {
-		printf("Keep debug unit ON\n");
-
-		pmic_clrsetbits(dev, STPMIC1_BUCKS_MRST_CR,
-				STPMIC1_MRST_BUCK_DEBUG,
-				STPMIC1_MRST_BUCK_DEBUG);
-
-		if (STPMIC1_MRST_LDO_DEBUG)
-			pmic_clrsetbits(dev, STPMIC1_LDOS_MRST_CR,
-					STPMIC1_MRST_LDO_DEBUG,
-					STPMIC1_MRST_LDO_DEBUG);
-	}
-#endif
-}
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/configs/stm32mp1-t1000-evk50_defconfig b/recipes-bsp/u-boot/u-boot-stm32mp/configs/stm32mp1-t1000-evk50_defconfig
deleted file mode 100644
index 1460cdf9bdc7e172ede01dafe3e1a0f891bcf202..0000000000000000000000000000000000000000
--- a/recipes-bsp/u-boot/u-boot-stm32mp/configs/stm32mp1-t1000-evk50_defconfig
+++ /dev/null
@@ -1,129 +0,0 @@
-CONFIG_ARM=y
-CONFIG_ARCH_STM32MP=y
-CONFIG_SYS_MALLOC_F_LEN=0x3000
-CONFIG_TARGET_STM32MP1_T1000=y
-CONFIG_DISTRO_DEFAULTS=y
-CONFIG_FIT=y
-CONFIG_BOOTDELAY=1
-CONFIG_SYS_PROMPT="STM32MP> "
-CONFIG_BOOTCOUNT_LIMIT=y
-CONFIG_BOOTCOUNT_GENERIC=y
-# CONFIG_BOOTCOUNT_EXT is not set
-CONFIG_BOOTCOUNT_ENV=y
-# CONFIG_BOOTCOUNT_RAM is not set
-# CONFIG_BOOTCOUNT_I2C is not set
-CONFIG_BOOTCOUNT_BOOTLIMIT=5
-CONFIG_SYS_BOOTCOUNT_MAGIC=0xB001C041
-#CONFIG_SERIAL_SEARCH_ALL=y
-#CONFIG_CONS_INDEX=2
-# CONFIG_CMD_BOOTD is not set
-# CONFIG_CMD_ELF is not set
-# CONFIG_CMD_IMI is not set
-# CONFIG_CMD_XIMG is not set
-# CONFIG_CMD_EXPORTENV is not set
-# CONFIG_CMD_IMPORTENV is not set
-CONFIG_CMD_MEMINFO=y
-CONFIG_CMD_MEMTEST=y
-CONFIG_SYS_ALT_MEMTEST=y
-CONFIG_CMD_ADC=y
-CONFIG_CMD_CLK=y
-CONFIG_CMD_DFU=y
-CONFIG_CMD_FUSE=y
-CONFIG_CMD_GPIO=y
-CONFIG_CMD_I2C=y
-CONFIG_CMD_MMC=y
-CONFIG_CMD_MTD=y
-CONFIG_CMD_REMOTEPROC=y
-CONFIG_CMD_SF=y
-CONFIG_CMD_USB=y
-CONFIG_CMD_USB_MASS_STORAGE=y
-CONFIG_CMD_BMP=y
-CONFIG_CMD_CACHE=y
-CONFIG_CMD_TIME=y
-CONFIG_CMD_TIMER=y
-CONFIG_CMD_PMIC=y
-CONFIG_CMD_REGULATOR=y
-CONFIG_CMD_EXT4_WRITE=y
-CONFIG_CMD_MTDPARTS=y
-CONFIG_CMD_UBI=y
-CONFIG_DEFAULT_DEVICE_TREE="stm32mp-t1000-s"
-CONFIG_ENV_IS_IN_SPI_FLASH=y
-CONFIG_NET_RANDOM_ETHADDR=y
-CONFIG_STM32_ADC=y
-CONFIG_USB_FUNCTION_FASTBOOT=y
-CONFIG_FASTBOOT_BUF_ADDR=0xC0000000
-CONFIG_FASTBOOT_BUF_SIZE=0x02000000
-CONFIG_FASTBOOT_USB_DEV=1
-CONFIG_FASTBOOT_FLASH=y
-CONFIG_FASTBOOT_FLASH_MMC_DEV=1
-CONFIG_DM_HWSPINLOCK=y
-CONFIG_HWSPINLOCK_STM32=y
-CONFIG_DM_I2C=y
-CONFIG_SYS_I2C_STM32F7=y
-CONFIG_LED=y
-CONFIG_LED_GPIO=y
-CONFIG_DM_MAILBOX=y
-CONFIG_STM32_IPCC=y
-CONFIG_DM_MMC=y
-CONFIG_STM32_SDMMC2=y
-CONFIG_MTD=y
-CONFIG_MTD_SPI_NAND=y
-#CONFIG_NAND=y
-#CONFIG_NAND_STM32_FMC2=y
-CONFIG_DM_SPI_FLASH=y
-CONFIG_SPI_FLASH=y
-CONFIG_SPI_FLASH_BAR=y
-CONFIG_SPI_FLASH_MACRONIX=y
-CONFIG_SPI_FLASH_SPANSION=y
-CONFIG_SPI_FLASH_STMICRO=y
-CONFIG_SPI_FLASH_WINBOND=y
-# CONFIG_SPI_FLASH_USE_4K_SECTORS is not set
-CONFIG_SPI_FLASH_MTD=y
-CONFIG_PHY_FIXED=y
-CONFIG_DM_ETH=y
-CONFIG_DWC_ETH_QOS=y
-CONFIG_PHY=y
-CONFIG_PHY_STM32_USBPHYC=y
-CONFIG_PINCONF=y
-CONFIG_PINCTRL_STMFX=y
-CONFIG_DM_PMIC=y
-#CONFIG_PMIC_STPMU1=y
-CONFIG_PMIC_STPMIC1=y
-CONFIG_DM_REGULATOR=y
-CONFIG_DM_REGULATOR_FIXED=y
-CONFIG_DM_REGULATOR_GPIO=y
-CONFIG_DM_REGULATOR_STM32_VREFBUF=y
-CONFIG_DM_REGULATOR_STPMIC1=y
-CONFIG_REMOTEPROC_STM32_COPRO=y
-CONFIG_SERIAL_RX_BUFFER=y
-CONFIG_SPI=y
-CONFIG_DM_SPI=y
-CONFIG_STM32_QSPI=y
-CONFIG_USB=y
-CONFIG_DM_USB=y
-CONFIG_USB_EHCI_HCD=y
-CONFIG_USB_EHCI_GENERIC=y
-CONFIG_USB_DWC2=y
-CONFIG_USB_STORAGE=y
-CONFIG_USB_GADGET=y
-CONFIG_USB_GADGET_MANUFACTURER="STMicroelectronics"
-CONFIG_USB_GADGET_VENDOR_NUM=0x0483
-CONFIG_USB_GADGET_PRODUCT_NUM=0x5720
-CONFIG_USB_GADGET_DWC2_OTG=y
-#BEGINN VIDEO
-CONFIG_DM_VIDEO=y
-CONFIG_BACKLIGHT_GPIO=y
-CONFIG_VIDEO_LCD_ORISETECH_OTM8009A=y
-CONFIG_VIDEO_LCD_RAYDIUM_RM68200=y
-CONFIG_VIDEO_STM32=y
-CONFIG_VIDEO_STM32_DSI=y
-CONFIG_VIDEO_STM32_MAX_XRES=1280
-CONFIG_VIDEO_STM32_MAX_YRES=800
-#END VIDEO
-CONFIG_WDT=y
-CONFIG_WDT_STM32MP=y
-CONFIG_FDT_FIXUP_PARTITIONS=y
-# CONFIG_EFI_LOADER is not set
-#CONFIG_MTDIDS_DEFAULT="nor0=nor0,spi-nand0=spi-nand0"
-#CONFIG_MTDPARTS_DEFAULT="mtdparts=nor0:256k(fsbl1),256k(fsbl2),1m(ssbl),64k(env),-(nor_user);spi-nand0:-(UBI)"
-CONFIG_HOUSING_DEFAULT="-50"
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/configs/stm32mp1-t1000-evk50sdcard_defconfig b/recipes-bsp/u-boot/u-boot-stm32mp/configs/stm32mp1-t1000-evk50sdcard_defconfig
deleted file mode 100644
index 654cb87b28ccb4584bb0637af922c9a67e9e4efb..0000000000000000000000000000000000000000
--- a/recipes-bsp/u-boot/u-boot-stm32mp/configs/stm32mp1-t1000-evk50sdcard_defconfig
+++ /dev/null
@@ -1,113 +0,0 @@
-CONFIG_ARM=y
-CONFIG_ARCH_STM32MP=y
-CONFIG_SYS_MALLOC_F_LEN=0x3000
-CONFIG_TARGET_STM32MP1_T1000=y
-CONFIG_DISTRO_DEFAULTS=y
-CONFIG_FIT=y
-CONFIG_BOOTDELAY=1
-CONFIG_HOUSING_DEFAULT="-50"
-CONFIG_SYS_PROMPT="STM32MP> "
-# CONFIG_CMD_BOOTD is not set
-# CONFIG_CMD_ELF is not set
-# CONFIG_CMD_IMI is not set
-# CONFIG_CMD_XIMG is not set
-# CONFIG_CMD_EXPORTENV is not set
-# CONFIG_CMD_IMPORTENV is not set
-CONFIG_CMD_MEMINFO=y
-CONFIG_CMD_MEMTEST=y
-CONFIG_SYS_ALT_MEMTEST=y
-CONFIG_CMD_ADC=y
-CONFIG_CMD_CLK=y
-CONFIG_CMD_DFU=y
-CONFIG_CMD_FUSE=y
-CONFIG_CMD_GPIO=y
-CONFIG_CMD_I2C=y
-CONFIG_CMD_MMC=y
-CONFIG_CMD_MTD=y
-CONFIG_CMD_REMOTEPROC=y
-CONFIG_CMD_SF=y
-CONFIG_CMD_USB=y
-CONFIG_CMD_USB_MASS_STORAGE=y
-CONFIG_CMD_BMP=y
-CONFIG_CMD_CACHE=y
-CONFIG_CMD_TIME=y
-CONFIG_CMD_TIMER=y
-CONFIG_CMD_PMIC=y
-CONFIG_CMD_REGULATOR=y
-CONFIG_CMD_EXT4_WRITE=y
-CONFIG_CMD_MTDPARTS=y
-CONFIG_CMD_UBI=y
-CONFIG_DEFAULT_DEVICE_TREE="stm32mp-t1000-s"
-CONFIG_ENV_IS_IN_MMC=y
-CONFIG_NET_RANDOM_ETHADDR=y
-CONFIG_STM32_ADC=y
-CONFIG_BOOTCOUNT_ENV=y
-CONFIG_BOOTCOUNT_BOOTLIMIT=5
-CONFIG_USB_FUNCTION_FASTBOOT=y
-CONFIG_FASTBOOT_BUF_ADDR=0xC0000000
-CONFIG_FASTBOOT_BUF_SIZE=0x02000000
-CONFIG_FASTBOOT_USB_DEV=1
-CONFIG_FASTBOOT_FLASH=y
-CONFIG_FASTBOOT_FLASH_MMC_DEV=1
-CONFIG_DM_HWSPINLOCK=y
-CONFIG_HWSPINLOCK_STM32=y
-CONFIG_DM_I2C=y
-CONFIG_SYS_I2C_STM32F7=y
-CONFIG_LED=y
-CONFIG_LED_GPIO=y
-CONFIG_DM_MAILBOX=y
-CONFIG_STM32_IPCC=y
-CONFIG_DM_MMC=y
-CONFIG_STM32_SDMMC2=y
-CONFIG_MTD=y
-CONFIG_MTD_SPI_NAND=y
-CONFIG_DM_SPI_FLASH=y
-CONFIG_SPI_FLASH=y
-CONFIG_SPI_FLASH_BAR=y
-CONFIG_SPI_FLASH_MACRONIX=y
-CONFIG_SPI_FLASH_SPANSION=y
-CONFIG_SPI_FLASH_STMICRO=y
-CONFIG_SPI_FLASH_WINBOND=y
-# CONFIG_SPI_FLASH_USE_4K_SECTORS is not set
-CONFIG_SPI_FLASH_MTD=y
-CONFIG_PHY_FIXED=y
-CONFIG_DM_ETH=y
-CONFIG_DWC_ETH_QOS=y
-CONFIG_PHY=y
-CONFIG_PHY_STM32_USBPHYC=y
-CONFIG_PINCONF=y
-CONFIG_PINCTRL_STMFX=y
-CONFIG_DM_PMIC=y
-CONFIG_PMIC_STPMIC1=y
-CONFIG_DM_REGULATOR_FIXED=y
-CONFIG_DM_REGULATOR_GPIO=y
-CONFIG_DM_REGULATOR_STM32_VREFBUF=y
-CONFIG_DM_REGULATOR_STPMIC1=y
-CONFIG_REMOTEPROC_STM32_COPRO=y
-CONFIG_SERIAL_RX_BUFFER=y
-CONFIG_SPI=y
-CONFIG_DM_SPI=y
-CONFIG_STM32_QSPI=y
-CONFIG_USB=y
-CONFIG_DM_USB=y
-CONFIG_USB_EHCI_HCD=y
-CONFIG_USB_EHCI_GENERIC=y
-CONFIG_USB_DWC2=y
-CONFIG_USB_STORAGE=y
-CONFIG_USB_GADGET=y
-CONFIG_USB_GADGET_MANUFACTURER="STMicroelectronics"
-CONFIG_USB_GADGET_VENDOR_NUM=0x0483
-CONFIG_USB_GADGET_PRODUCT_NUM=0x5720
-CONFIG_USB_GADGET_DWC2_OTG=y
-CONFIG_DM_VIDEO=y
-CONFIG_BACKLIGHT_GPIO=y
-CONFIG_VIDEO_LCD_ORISETECH_OTM8009A=y
-CONFIG_VIDEO_LCD_RAYDIUM_RM68200=y
-CONFIG_VIDEO_STM32=y
-CONFIG_VIDEO_STM32_DSI=y
-CONFIG_VIDEO_STM32_MAX_XRES=1280
-CONFIG_VIDEO_STM32_MAX_YRES=800
-CONFIG_WDT=y
-CONFIG_WDT_STM32MP=y
-CONFIG_FDT_FIXUP_PARTITIONS=y
-# CONFIG_EFI_LOADER is not set
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/configs/stm32mp1-t1000-production_defconfig b/recipes-bsp/u-boot/u-boot-stm32mp/configs/stm32mp1-t1000-production_defconfig
deleted file mode 100644
index 99957477d86af11252fed7f7239e3b8d055d1c05..0000000000000000000000000000000000000000
--- a/recipes-bsp/u-boot/u-boot-stm32mp/configs/stm32mp1-t1000-production_defconfig
+++ /dev/null
@@ -1,116 +0,0 @@
-CONFIG_ARM=y
-CONFIG_ARCH_STM32MP=y
-CONFIG_SYS_MALLOC_F_LEN=0x3000
-CONFIG_TARGET_STM32MP1_T1000=y
-CONFIG_DISTRO_DEFAULTS=y
-CONFIG_ENABLE_PRODUCTION_BOOT=y
-CONFIG_FIT=y
-CONFIG_BOOTDELAY=1
-CONFIG_SYS_PROMPT="STM32MP> "
-# CONFIG_CMD_BOOTD is not set
-# CONFIG_CMD_ELF is not set
-# CONFIG_CMD_IMI is not set
-# CONFIG_CMD_XIMG is not set
-# CONFIG_CMD_EXPORTENV is not set
-CONFIG_CMD_GREPENV=y
-CONFIG_CMD_EEPROM=y
-CONFIG_CMD_MEMINFO=y
-CONFIG_CMD_MEMTEST=y
-CONFIG_SYS_ALT_MEMTEST=y
-CONFIG_CMD_ADC=y
-CONFIG_CMD_CLK=y
-CONFIG_CMD_DFU=y
-CONFIG_CMD_FUSE=y
-CONFIG_CMD_GPIO=y
-CONFIG_CMD_I2C=y
-CONFIG_CMD_MMC=y
-CONFIG_CMD_MTD=y
-CONFIG_CMD_REMOTEPROC=y
-CONFIG_CMD_SF=y
-CONFIG_CMD_USB=y
-CONFIG_CMD_USB_MASS_STORAGE=y
-CONFIG_CMD_BMP=y
-CONFIG_CMD_CACHE=y
-CONFIG_CMD_TIME=y
-CONFIG_CMD_TIMER=y
-CONFIG_CMD_PMIC=y
-CONFIG_CMD_REGULATOR=y
-CONFIG_CMD_EXT4_WRITE=y
-CONFIG_CMD_MTDPARTS=y
-CONFIG_CMD_UBI=y
-CONFIG_DEFAULT_DEVICE_TREE="stm32mp-t1000-s"
-CONFIG_ENV_IS_IN_SPI_FLASH=y
-CONFIG_NET_RANDOM_ETHADDR=y
-CONFIG_STM32_ADC=y
-CONFIG_USB_FUNCTION_FASTBOOT=y
-CONFIG_FASTBOOT_BUF_ADDR=0xC0000000
-CONFIG_FASTBOOT_BUF_SIZE=0x02000000
-CONFIG_FASTBOOT_USB_DEV=1
-CONFIG_FASTBOOT_FLASH=y
-CONFIG_FASTBOOT_FLASH_MMC_DEV=1
-CONFIG_DM_HWSPINLOCK=y
-CONFIG_HWSPINLOCK_STM32=y
-CONFIG_DM_I2C=y
-CONFIG_SYS_I2C_STM32F7=y
-CONFIG_LED=y
-CONFIG_LED_GPIO=y
-CONFIG_DM_MAILBOX=y
-CONFIG_STM32_IPCC=y
-CONFIG_I2C_EEPROM=y
-CONFIG_DM_MMC=y
-CONFIG_STM32_SDMMC2=y
-CONFIG_MTD=y
-CONFIG_MTD_SPI_NAND=y
-CONFIG_DM_SPI_FLASH=y
-CONFIG_SPI_FLASH=y
-CONFIG_SPI_FLASH_BAR=y
-CONFIG_SPI_FLASH_MACRONIX=y
-CONFIG_SPI_FLASH_SPANSION=y
-CONFIG_SPI_FLASH_STMICRO=y
-CONFIG_SPI_FLASH_WINBOND=y
-# CONFIG_SPI_FLASH_USE_4K_SECTORS is not set
-CONFIG_SPI_FLASH_MTD=y
-CONFIG_PHY_FIXED=y
-CONFIG_DM_ETH=y
-CONFIG_DWC_ETH_QOS=y
-CONFIG_PHY=y
-CONFIG_PHY_STM32_USBPHYC=y
-CONFIG_PINCONF=y
-CONFIG_PINCTRL_STMFX=y
-CONFIG_DM_PMIC=y
-CONFIG_PMIC_STPMIC1=y
-CONFIG_DM_REGULATOR_FIXED=y
-CONFIG_DM_REGULATOR_GPIO=y
-CONFIG_DM_REGULATOR_STM32_VREFBUF=y
-CONFIG_DM_REGULATOR_STPMIC1=y
-CONFIG_REMOTEPROC_STM32_COPRO=y
-CONFIG_SERIAL_RX_BUFFER=y
-CONFIG_SPI=y
-CONFIG_DM_SPI=y
-CONFIG_STM32_QSPI=y
-CONFIG_USB=y
-CONFIG_DM_USB=y
-CONFIG_USB_EHCI_HCD=y
-CONFIG_USB_EHCI_GENERIC=y
-CONFIG_USB_DWC2=y
-CONFIG_USB_STORAGE=y
-CONFIG_USB_GADGET=y
-CONFIG_USB_GADGET_MANUFACTURER="STMicroelectronics"
-CONFIG_USB_GADGET_VENDOR_NUM=0x0483
-CONFIG_USB_GADGET_PRODUCT_NUM=0x5720
-CONFIG_USB_GADGET_DWC2_OTG=y
-CONFIG_USB_HOST_ETHER=y
-CONFIG_USB_ETHER_SMSC95XX=y
-CONFIG_DM_VIDEO=y
-CONFIG_BACKLIGHT_GPIO=y
-CONFIG_VIDEO_LCD_ORISETECH_OTM8009A=y
-CONFIG_VIDEO_LCD_RAYDIUM_RM68200=y
-CONFIG_VIDEO_STM32=y
-CONFIG_VIDEO_STM32_DSI=y
-CONFIG_VIDEO_STM32_MAX_XRES=1280
-CONFIG_VIDEO_STM32_MAX_YRES=800
-CONFIG_WDT=y
-CONFIG_WDT_STM32MP=y
-CONFIG_FDT_FIXUP_PARTITIONS=y
-# CONFIG_EFI_LOADER is not set
-CONFIG_HOUSING_DEFAULT=""
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/configs/stm32mp1-t1000_defconfig b/recipes-bsp/u-boot/u-boot-stm32mp/configs/stm32mp1-t1000_defconfig
deleted file mode 100644
index 2e3ca006b396bcf8c1bdebf2fb4f258d9a5ca2a8..0000000000000000000000000000000000000000
--- a/recipes-bsp/u-boot/u-boot-stm32mp/configs/stm32mp1-t1000_defconfig
+++ /dev/null
@@ -1,113 +0,0 @@
-CONFIG_ARM=y
-CONFIG_ARCH_STM32MP=y
-CONFIG_SYS_MALLOC_F_LEN=0x3000
-CONFIG_TARGET_STM32MP1_T1000=y
-CONFIG_DISTRO_DEFAULTS=y
-CONFIG_FIT=y
-CONFIG_BOOTDELAY=1
-CONFIG_HOUSING_DEFAULT=""
-CONFIG_SYS_PROMPT="STM32MP> "
-# CONFIG_CMD_BOOTD is not set
-# CONFIG_CMD_ELF is not set
-# CONFIG_CMD_IMI is not set
-# CONFIG_CMD_XIMG is not set
-# CONFIG_CMD_EXPORTENV is not set
-# CONFIG_CMD_IMPORTENV is not set
-CONFIG_CMD_MEMINFO=y
-CONFIG_CMD_MEMTEST=y
-CONFIG_SYS_ALT_MEMTEST=y
-CONFIG_CMD_ADC=y
-CONFIG_CMD_CLK=y
-CONFIG_CMD_DFU=y
-CONFIG_CMD_FUSE=y
-CONFIG_CMD_GPIO=y
-CONFIG_CMD_I2C=y
-CONFIG_CMD_MMC=y
-CONFIG_CMD_MTD=y
-CONFIG_CMD_REMOTEPROC=y
-CONFIG_CMD_SF=y
-CONFIG_CMD_USB=y
-CONFIG_CMD_USB_MASS_STORAGE=y
-CONFIG_CMD_BMP=y
-CONFIG_CMD_CACHE=y
-CONFIG_CMD_TIME=y
-CONFIG_CMD_TIMER=y
-CONFIG_CMD_PMIC=y
-CONFIG_CMD_REGULATOR=y
-CONFIG_CMD_EXT4_WRITE=y
-CONFIG_CMD_MTDPARTS=y
-CONFIG_CMD_UBI=y
-CONFIG_DEFAULT_DEVICE_TREE="stm32mp-t1000-s"
-CONFIG_ENV_IS_IN_SPI_FLASH=y
-CONFIG_NET_RANDOM_ETHADDR=y
-CONFIG_STM32_ADC=y
-CONFIG_BOOTCOUNT_ENV=y
-CONFIG_BOOTCOUNT_BOOTLIMIT=5
-CONFIG_USB_FUNCTION_FASTBOOT=y
-CONFIG_FASTBOOT_BUF_ADDR=0xC0000000
-CONFIG_FASTBOOT_BUF_SIZE=0x02000000
-CONFIG_FASTBOOT_USB_DEV=1
-CONFIG_FASTBOOT_FLASH=y
-CONFIG_FASTBOOT_FLASH_MMC_DEV=1
-CONFIG_DM_HWSPINLOCK=y
-CONFIG_HWSPINLOCK_STM32=y
-CONFIG_DM_I2C=y
-CONFIG_SYS_I2C_STM32F7=y
-CONFIG_LED=y
-CONFIG_LED_GPIO=y
-CONFIG_DM_MAILBOX=y
-CONFIG_STM32_IPCC=y
-CONFIG_DM_MMC=y
-CONFIG_STM32_SDMMC2=y
-CONFIG_MTD=y
-CONFIG_MTD_SPI_NAND=y
-CONFIG_DM_SPI_FLASH=y
-CONFIG_SPI_FLASH=y
-CONFIG_SPI_FLASH_BAR=y
-CONFIG_SPI_FLASH_MACRONIX=y
-CONFIG_SPI_FLASH_SPANSION=y
-CONFIG_SPI_FLASH_STMICRO=y
-CONFIG_SPI_FLASH_WINBOND=y
-# CONFIG_SPI_FLASH_USE_4K_SECTORS is not set
-CONFIG_SPI_FLASH_MTD=y
-CONFIG_PHY_FIXED=y
-CONFIG_DM_ETH=y
-CONFIG_DWC_ETH_QOS=y
-CONFIG_PHY=y
-CONFIG_PHY_STM32_USBPHYC=y
-CONFIG_PINCONF=y
-CONFIG_PINCTRL_STMFX=y
-CONFIG_DM_PMIC=y
-CONFIG_PMIC_STPMIC1=y
-CONFIG_DM_REGULATOR_FIXED=y
-CONFIG_DM_REGULATOR_GPIO=y
-CONFIG_DM_REGULATOR_STM32_VREFBUF=y
-CONFIG_DM_REGULATOR_STPMIC1=y
-CONFIG_REMOTEPROC_STM32_COPRO=y
-CONFIG_SERIAL_RX_BUFFER=y
-CONFIG_SPI=y
-CONFIG_DM_SPI=y
-CONFIG_STM32_QSPI=y
-CONFIG_USB=y
-CONFIG_DM_USB=y
-CONFIG_USB_EHCI_HCD=y
-CONFIG_USB_EHCI_GENERIC=y
-CONFIG_USB_DWC2=y
-CONFIG_USB_STORAGE=y
-CONFIG_USB_GADGET=y
-CONFIG_USB_GADGET_MANUFACTURER="STMicroelectronics"
-CONFIG_USB_GADGET_VENDOR_NUM=0x0483
-CONFIG_USB_GADGET_PRODUCT_NUM=0x5720
-CONFIG_USB_GADGET_DWC2_OTG=y
-CONFIG_DM_VIDEO=y
-CONFIG_BACKLIGHT_GPIO=y
-CONFIG_VIDEO_LCD_ORISETECH_OTM8009A=y
-CONFIG_VIDEO_LCD_RAYDIUM_RM68200=y
-CONFIG_VIDEO_STM32=y
-CONFIG_VIDEO_STM32_DSI=y
-CONFIG_VIDEO_STM32_MAX_XRES=1280
-CONFIG_VIDEO_STM32_MAX_YRES=800
-CONFIG_WDT=y
-CONFIG_WDT_STM32MP=y
-CONFIG_FDT_FIXUP_PARTITIONS=y
-# CONFIG_EFI_LOADER is not set
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/configs/stm32mp15_basic_calibration_defconfig b/recipes-bsp/u-boot/u-boot-stm32mp/configs/stm32mp15_basic_calibration_defconfig
index e5099ee041a8658e6f3b0825eee01f3f052428f9..b4f24b4e62c5f2cba0573f680907f416511696ac 100644
--- a/recipes-bsp/u-boot/u-boot-stm32mp/configs/stm32mp15_basic_calibration_defconfig
+++ b/recipes-bsp/u-boot/u-boot-stm32mp/configs/stm32mp15_basic_calibration_defconfig
@@ -117,7 +117,5 @@ CONFIG_VIDEO_STM32=y
 CONFIG_VIDEO_STM32_DSI=y
 CONFIG_VIDEO_STM32_MAX_XRES=1280
 CONFIG_VIDEO_STM32_MAX_YRES=800
-CONFIG_WDT=y
-CONFIG_WDT_STM32MP=y
+CONFIG_STM32MP_WATCHDOG=y
 # CONFIG_EFI_LOADER is not set
-CONFIG_HOUSING_DEFAULT=""
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/configs/stm32mp1-t1000-manualtest-som_defconfig b/recipes-bsp/u-boot/u-boot-stm32mp/configs/stmxceet-mp157-som-basic_defconfig
similarity index 66%
rename from recipes-bsp/u-boot/u-boot-stm32mp/configs/stm32mp1-t1000-manualtest-som_defconfig
rename to recipes-bsp/u-boot/u-boot-stm32mp/configs/stmxceet-mp157-som-basic_defconfig
index 55019d7d0957fd4a3a8016b23e72321dfa3c906f..980c3adbd3510d9e69a3778163cf85a3b77d3881 100644
--- a/recipes-bsp/u-boot/u-boot-stm32mp/configs/stm32mp1-t1000-manualtest-som_defconfig
+++ b/recipes-bsp/u-boot/u-boot-stm32mp/configs/stmxceet-mp157-som-basic_defconfig
@@ -1,12 +1,31 @@
 CONFIG_ARM=y
 CONFIG_ARCH_STM32MP=y
-CONFIG_SYS_MALLOC_F_LEN=0x3000
-CONFIG_TARGET_STM32MP1_T1000=y
+CONFIG_SYS_MALLOC_F_LEN=0x2000
+CONFIG_SPL_MMC_SUPPORT=y
+CONFIG_SPL_SPI_FLASH_SUPPORT=y
+CONFIG_SPL_SPI_SUPPORT=y
+CONFIG_SPL=y
+CONFIG_TARGET_STM32MP1=y
+CONFIG_DEFAULT_DEVICE_TREE="stm32mp157c-ev1"
+CONFIG_DEBUG_UART=y
 CONFIG_DISTRO_DEFAULTS=y
 CONFIG_FIT=y
+CONFIG_BOOTSTAGE=y
+CONFIG_BOOTSTAGE_REPORT=y
 CONFIG_BOOTDELAY=1
-CONFIG_HOUSING_DEFAULT="-manualtest-som"
+CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION=y
+CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION=3
+CONFIG_SPL_I2C_SUPPORT=y
+CONFIG_SPL_MTD_SUPPORT=y
+CONFIG_SPL_POST_MEM_SUPPORT=y
+CONFIG_SPL_POWER_SUPPORT=y
 CONFIG_SYS_PROMPT="STM32MP> "
+CONFIG_FASTBOOT=y
+CONFIG_FASTBOOT_BUF_ADDR=0xC0000000
+CONFIG_FASTBOOT_BUF_SIZE=0x02000000
+CONFIG_FASTBOOT_USB_DEV=1
+CONFIG_FASTBOOT_FLASH=y
+CONFIG_FASTBOOT_FLASH_MMC_DEV=1
 # CONFIG_CMD_BOOTD is not set
 # CONFIG_CMD_ELF is not set
 # CONFIG_CMD_IMI is not set
@@ -15,52 +34,41 @@ CONFIG_SYS_PROMPT="STM32MP> "
 # CONFIG_CMD_IMPORTENV is not set
 CONFIG_CMD_MEMINFO=y
 CONFIG_CMD_MEMTEST=y
-CONFIG_SYS_ALT_MEMTEST=y
-CONFIG_CMD_ADC=y
 CONFIG_CMD_CLK=y
 CONFIG_CMD_DFU=y
 CONFIG_CMD_FUSE=y
 CONFIG_CMD_GPIO=y
 CONFIG_CMD_I2C=y
 CONFIG_CMD_MMC=y
-CONFIG_CMD_MTD=y
 CONFIG_CMD_REMOTEPROC=y
 CONFIG_CMD_SF=y
 CONFIG_CMD_USB=y
 CONFIG_CMD_USB_MASS_STORAGE=y
+CONFIG_CMD_ADC=y
 CONFIG_CMD_BMP=y
 CONFIG_CMD_CACHE=y
 CONFIG_CMD_TIME=y
 CONFIG_CMD_TIMER=y
+CONFIG_CMD_BOOTSTAGE=y
 CONFIG_CMD_PMIC=y
 CONFIG_CMD_REGULATOR=y
 CONFIG_CMD_EXT4_WRITE=y
-CONFIG_CMD_MTDPARTS=y
 CONFIG_CMD_UBI=y
-CONFIG_DEFAULT_DEVICE_TREE="stm32mp-t1000-s"
-CONFIG_ENV_IS_IN_MMC=y
-CONFIG_NET_RANDOM_ETHADDR=y
+# CONFIG_SPL_DOS_PARTITION is not set
+# CONFIG_SPL_ISO_PARTITION is not set
+CONFIG_ADC=y
 CONFIG_STM32_ADC=y
-CONFIG_BOOTCOUNT_ENV=y
-CONFIG_BOOTCOUNT_BOOTLIMIT=0
-CONFIG_USB_FUNCTION_FASTBOOT=y
-CONFIG_FASTBOOT_BUF_ADDR=0xC0000000
-CONFIG_FASTBOOT_BUF_SIZE=0x02000000
-CONFIG_FASTBOOT_USB_DEV=1
-CONFIG_FASTBOOT_FLASH=y
-CONFIG_FASTBOOT_FLASH_MMC_DEV=1
-CONFIG_DM_HWSPINLOCK=y
-CONFIG_HWSPINLOCK_STM32=y
+CONFIG_DFU_NAND=y
 CONFIG_DM_I2C=y
 CONFIG_SYS_I2C_STM32F7=y
 CONFIG_LED=y
 CONFIG_LED_GPIO=y
-CONFIG_DM_MAILBOX=y
-CONFIG_STM32_IPCC=y
+CONFIG_STM32MP_FUSE=y
 CONFIG_DM_MMC=y
 CONFIG_STM32_SDMMC2=y
-CONFIG_MTD=y
-CONFIG_MTD_SPI_NAND=y
+CONFIG_NAND=y
+CONFIG_DM_NAND=y
+CONFIG_NAND_STM32_FMC=y
 CONFIG_DM_SPI_FLASH=y
 CONFIG_SPI_FLASH=y
 CONFIG_SPI_FLASH_BAR=y
@@ -70,22 +78,22 @@ CONFIG_SPI_FLASH_STMICRO=y
 CONFIG_SPI_FLASH_WINBOND=y
 # CONFIG_SPI_FLASH_USE_4K_SECTORS is not set
 CONFIG_SPI_FLASH_MTD=y
-CONFIG_PHY_FIXED=y
 CONFIG_DM_ETH=y
 CONFIG_DWC_ETH_QOS=y
 CONFIG_PHY=y
 CONFIG_PHY_STM32_USBPHYC=y
-CONFIG_PINCONF=y
-CONFIG_PINCTRL_STMFX=y
+# CONFIG_PINCTRL_FULL is not set
+# CONFIG_SPL_PINCTRL_FULL is not set
 CONFIG_DM_PMIC=y
-CONFIG_PMIC_STPMIC1=y
+CONFIG_PMIC_STPMU1=y
+CONFIG_DM_REGULATOR=y
 CONFIG_DM_REGULATOR_FIXED=y
 CONFIG_DM_REGULATOR_GPIO=y
 CONFIG_DM_REGULATOR_STM32_VREFBUF=y
-CONFIG_DM_REGULATOR_STPMIC1=y
+CONFIG_DM_REGULATOR_STPMU1=y
+CONFIG_STM32MP1_DDR_INTERACTIVE=y
 CONFIG_REMOTEPROC_STM32_COPRO=y
-CONFIG_SERIAL_RX_BUFFER=y
-CONFIG_SPI=y
+CONFIG_DEBUG_UART_STM32=y
 CONFIG_DM_SPI=y
 CONFIG_STM32_QSPI=y
 CONFIG_USB=y
@@ -99,15 +107,5 @@ CONFIG_USB_GADGET_MANUFACTURER="STMicroelectronics"
 CONFIG_USB_GADGET_VENDOR_NUM=0x0483
 CONFIG_USB_GADGET_PRODUCT_NUM=0x5720
 CONFIG_USB_GADGET_DWC2_OTG=y
-CONFIG_DM_VIDEO=y
-CONFIG_BACKLIGHT_GPIO=y
-CONFIG_VIDEO_LCD_ORISETECH_OTM8009A=y
-CONFIG_VIDEO_LCD_RAYDIUM_RM68200=y
-CONFIG_VIDEO_STM32=y
-CONFIG_VIDEO_STM32_DSI=y
-CONFIG_VIDEO_STM32_MAX_XRES=1280
-CONFIG_VIDEO_STM32_MAX_YRES=800
-CONFIG_WDT=y
-CONFIG_WDT_STM32MP=y
-CONFIG_FDT_FIXUP_PARTITIONS=y
+CONFIG_STM32MP_WATCHDOG=y
 # CONFIG_EFI_LOADER is not set
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/configs/stm32mp1-t1000-sdcard_defconfig b/recipes-bsp/u-boot/u-boot-stm32mp/configs/stmxceet-mp157-som_defconfig
similarity index 69%
rename from recipes-bsp/u-boot/u-boot-stm32mp/configs/stm32mp1-t1000-sdcard_defconfig
rename to recipes-bsp/u-boot/u-boot-stm32mp/configs/stmxceet-mp157-som_defconfig
index 5728d703e66af9859e0306dc5090a07af08dc603..a7ebd75fd6797ce965318fdeb4584ab93a3e69be 100644
--- a/recipes-bsp/u-boot/u-boot-stm32mp/configs/stm32mp1-t1000-sdcard_defconfig
+++ b/recipes-bsp/u-boot/u-boot-stm32mp/configs/stmxceet-mp157-som_defconfig
@@ -1,12 +1,21 @@
 CONFIG_ARM=y
 CONFIG_ARCH_STM32MP=y
-CONFIG_SYS_MALLOC_F_LEN=0x3000
-CONFIG_TARGET_STM32MP1_T1000=y
+CONFIG_SYS_MALLOC_F_LEN=0x2000
+CONFIG_TARGET_STMXCEET_MP157_SOM=y
+CONFIG_DEFAULT_DEVICE_TREE="stmxceet-mp157-som"
+CONFIG_DEBUG_UART=y
 CONFIG_DISTRO_DEFAULTS=y
 CONFIG_FIT=y
+CONFIG_BOOTSTAGE=y
+CONFIG_BOOTSTAGE_REPORT=y
 CONFIG_BOOTDELAY=1
-CONFIG_HOUSING_DEFAULT=""
 CONFIG_SYS_PROMPT="STM32MP> "
+CONFIG_FASTBOOT=y
+CONFIG_FASTBOOT_BUF_ADDR=0xC0000000
+CONFIG_FASTBOOT_BUF_SIZE=0x02000000
+CONFIG_FASTBOOT_USB_DEV=1
+CONFIG_FASTBOOT_FLASH=y
+CONFIG_FASTBOOT_FLASH_MMC_DEV=1
 # CONFIG_CMD_BOOTD is not set
 # CONFIG_CMD_ELF is not set
 # CONFIG_CMD_IMI is not set
@@ -15,52 +24,41 @@ CONFIG_SYS_PROMPT="STM32MP> "
 # CONFIG_CMD_IMPORTENV is not set
 CONFIG_CMD_MEMINFO=y
 CONFIG_CMD_MEMTEST=y
-CONFIG_SYS_ALT_MEMTEST=y
-CONFIG_CMD_ADC=y
 CONFIG_CMD_CLK=y
 CONFIG_CMD_DFU=y
 CONFIG_CMD_FUSE=y
 CONFIG_CMD_GPIO=y
 CONFIG_CMD_I2C=y
 CONFIG_CMD_MMC=y
-CONFIG_CMD_MTD=y
 CONFIG_CMD_REMOTEPROC=y
 CONFIG_CMD_SF=y
 CONFIG_CMD_USB=y
 CONFIG_CMD_USB_MASS_STORAGE=y
+CONFIG_CMD_ADC=y
 CONFIG_CMD_BMP=y
 CONFIG_CMD_CACHE=y
 CONFIG_CMD_TIME=y
 CONFIG_CMD_TIMER=y
+CONFIG_CMD_BOOTSTAGE=y
 CONFIG_CMD_PMIC=y
 CONFIG_CMD_REGULATOR=y
 CONFIG_CMD_EXT4_WRITE=y
-CONFIG_CMD_MTDPARTS=y
 CONFIG_CMD_UBI=y
-CONFIG_DEFAULT_DEVICE_TREE="stm32mp-t1000-s"
-CONFIG_ENV_IS_IN_MMC=y
+CONFIG_ENV_IS_IN_SPI_FLASH=y
 CONFIG_NET_RANDOM_ETHADDR=y
+CONFIG_ADC=y
 CONFIG_STM32_ADC=y
-CONFIG_BOOTCOUNT_ENV=y
-CONFIG_BOOTCOUNT_BOOTLIMIT=5
-CONFIG_USB_FUNCTION_FASTBOOT=y
-CONFIG_FASTBOOT_BUF_ADDR=0xC0000000
-CONFIG_FASTBOOT_BUF_SIZE=0x02000000
-CONFIG_FASTBOOT_USB_DEV=1
-CONFIG_FASTBOOT_FLASH=y
-CONFIG_FASTBOOT_FLASH_MMC_DEV=1
-CONFIG_DM_HWSPINLOCK=y
-CONFIG_HWSPINLOCK_STM32=y
+CONFIG_DFU_NAND=y
 CONFIG_DM_I2C=y
 CONFIG_SYS_I2C_STM32F7=y
 CONFIG_LED=y
 CONFIG_LED_GPIO=y
-CONFIG_DM_MAILBOX=y
-CONFIG_STM32_IPCC=y
+CONFIG_STM32MP_FUSE=y
 CONFIG_DM_MMC=y
 CONFIG_STM32_SDMMC2=y
-CONFIG_MTD=y
-CONFIG_MTD_SPI_NAND=y
+CONFIG_NAND=y
+CONFIG_DM_NAND=y
+CONFIG_NAND_STM32_FMC=y
 CONFIG_DM_SPI_FLASH=y
 CONFIG_SPI_FLASH=y
 CONFIG_SPI_FLASH_BAR=y
@@ -70,22 +68,20 @@ CONFIG_SPI_FLASH_STMICRO=y
 CONFIG_SPI_FLASH_WINBOND=y
 # CONFIG_SPI_FLASH_USE_4K_SECTORS is not set
 CONFIG_SPI_FLASH_MTD=y
-CONFIG_PHY_FIXED=y
 CONFIG_DM_ETH=y
 CONFIG_DWC_ETH_QOS=y
 CONFIG_PHY=y
 CONFIG_PHY_STM32_USBPHYC=y
-CONFIG_PINCONF=y
-CONFIG_PINCTRL_STMFX=y
+# CONFIG_PINCTRL_FULL is not set
 CONFIG_DM_PMIC=y
-CONFIG_PMIC_STPMIC1=y
+CONFIG_PMIC_STPMU1=y
+CONFIG_DM_REGULATOR=y
 CONFIG_DM_REGULATOR_FIXED=y
 CONFIG_DM_REGULATOR_GPIO=y
 CONFIG_DM_REGULATOR_STM32_VREFBUF=y
-CONFIG_DM_REGULATOR_STPMIC1=y
+CONFIG_DM_REGULATOR_STPMU1=y
 CONFIG_REMOTEPROC_STM32_COPRO=y
-CONFIG_SERIAL_RX_BUFFER=y
-CONFIG_SPI=y
+CONFIG_DEBUG_UART_STM32=y
 CONFIG_DM_SPI=y
 CONFIG_STM32_QSPI=y
 CONFIG_USB=y
@@ -99,14 +95,5 @@ CONFIG_USB_GADGET_MANUFACTURER="STMicroelectronics"
 CONFIG_USB_GADGET_VENDOR_NUM=0x0483
 CONFIG_USB_GADGET_PRODUCT_NUM=0x5720
 CONFIG_USB_GADGET_DWC2_OTG=y
-CONFIG_DM_VIDEO=y
-CONFIG_BACKLIGHT_GPIO=y
-CONFIG_VIDEO_LCD_ORISETECH_OTM8009A=y
-CONFIG_VIDEO_LCD_RAYDIUM_RM68200=y
-CONFIG_VIDEO_STM32=y
-CONFIG_VIDEO_STM32_DSI=y
-CONFIG_VIDEO_STM32_MAX_XRES=1280
-CONFIG_VIDEO_STM32_MAX_YRES=800
 CONFIG_STM32MP_WATCHDOG=y
-CONFIG_FDT_FIXUP_PARTITIONS=y
 # CONFIG_EFI_LOADER is not set
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp/include/configs/stm32mp1-t1000.h b/recipes-bsp/u-boot/u-boot-stm32mp/include/configs/stmxceet-mp157-som.h
similarity index 62%
rename from recipes-bsp/u-boot/u-boot-stm32mp/include/configs/stm32mp1-t1000.h
rename to recipes-bsp/u-boot/u-boot-stm32mp/include/configs/stmxceet-mp157-som.h
index 984edadaaf79cbc3753812de5b8caa71c16a4044..a3db8de488a6b9db3a69ffe95dfc5aa06c7ebcdd 100644
--- a/recipes-bsp/u-boot/u-boot-stm32mp/include/configs/stm32mp1-t1000.h
+++ b/recipes-bsp/u-boot/u-boot-stm32mp/include/configs/stmxceet-mp157-som.h
@@ -1,8 +1,9 @@
-/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */
 /*
- * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
+ * Copyright (C) 2015-2017, STMicroelectronics - All Rights Reserved
  *
  * Configuration settings for the STM32MP15x CPU
+ *
+ * SPDX-License-Identifier:	GPL-2.0+	BSD-3-Clause
  */
 
 #ifndef __CONFIG_H
@@ -10,10 +11,14 @@
 #include <linux/sizes.h>
 #include <asm/arch/stm32.h>
 
+#define CONFIG_DISPLAY_BOARDINFO_LATE	/* Calls show_board_info() */
+#define CONFIG_MISC_INIT_R
+
 /*
  * Number of clock ticks in 1 sec
  */
 #define CONFIG_SYS_HZ				1000
+#define CONFIG_SYS_ARCH_TIMER
 
 #ifndef CONFIG_STM32MP1_TRUSTED
 /* PSCI support */
@@ -46,12 +51,15 @@
 #define CONFIG_SYS_SDRAM_BASE			STM32_DDR_BASE
 #define CONFIG_SYS_INIT_SP_ADDR			CONFIG_SYS_TEXT_BASE
 #else
-/* Configuration of the internal SRAM memory used by U-Boot */
+/*
+ * Configuration of the internal SRAM memory used by U-Boot*
+ * NB: -4 for CONFIG_SYS_POST_WORD_ADDR
+ */
 #if (CONFIG_SYS_TEXT_BASE == 0x30000000)
 #define CONFIG_SYS_SDRAM_BASE			STM32_MCU_SRAM_BASE
 #define CONFIG_SYS_SDRAM_SIZE			STM32_MCU_SRAM_SIZE
 #define CONFIG_SYS_INIT_SP_ADDR			(STM32_MCU_SRAM_BASE +\
-						 STM32_MCU_SRAM_SIZE)
+						 STM32_MCU_SRAM_SIZE - 4)
 
 #else /* remaining case = 0x2FFC2500 */
 
@@ -59,7 +67,7 @@
 #define CONFIG_SYS_SDRAM_SIZE			STM32_DDR_SIZE
 #define CONFIG_SYS_INIT_SP_ADDR			(STM32_SYSRAM_BASE +\
 						 STM32_SYSRAM_SIZE +\
-						 STM32_MCU_SRAM_SIZE)
+						 STM32_MCU_SRAM_SIZE - 4)
 #endif
 
 #if defined(CONFIG_SYS_DCACHE_OFF) && defined(CONFIG_SYS_ICACHE_OFF)
@@ -68,6 +76,8 @@
 
 #endif /*(CONFIG_SYS_TEXT_BASE >= STM32_DDR_BASE)*/
 
+#define CONFIG_NR_DRAM_BANKS	1
+
 #define CONFIG_DISABLE_CONSOLE
 
 /*
@@ -84,6 +94,7 @@
  * Env parameters
  */
 #define CONFIG_ENV_SIZE				SZ_16K
+#define CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG
 
 /* Environment in SPI NOR */
 #ifdef CONFIG_ENV_IS_IN_SPI_FLASH
@@ -97,28 +108,13 @@
 
 #endif
 
-// For sd card boot
-#ifdef CONFIG_ENV_IS_IN_MMC
-
-#ifndef CONFIG_SYS_MMC_ENV_DEV
-#define CONFIG_SYS_MMC_ENV_DEV  (0)
-#endif
-
-#ifndef CONFIG_SYS_MMC_ENV_PART
-#define CONFIG_SYS_MMC_ENV_PART (0)
-#endif
-
-// fsbl1 (0x40000), fsbl2 (0x40000), ssbl (0x200000)
-#define CONFIG_ENV_OFFSET		(0x280000-CONFIG_ENV_SIZE)
-#endif
-
 /* ATAGs */
 #define CONFIG_CMDLINE_TAG
 #define CONFIG_SETUP_MEMORY_TAGS
 #define CONFIG_INITRD_TAG
 
 /* Extend size of kernel image for uncompression */
-#define CONFIG_SYS_BOOTM_LEN			SZ_32M
+#define CONFIG_SYS_BOOTM_LEN			SZ_64M
 
 /* SPL support */
 #ifdef CONFIG_SPL
@@ -136,31 +132,19 @@
 					 STM32_SYSRAM_SIZE)
 #endif /* #ifdef CONFIG_SPL */
 
-#define CONFIG_SYS_MEMTEST_START	STM32_DDR_BASE
-#define CONFIG_SYS_MEMTEST_END		(CONFIG_SYS_MEMTEST_START + SZ_64M)
-#define CONFIG_SYS_MEMTEST_SCRATCH	(CONFIG_SYS_MEMTEST_END + 4)
+/* FOR TEST */
+#define CONFIG_SYS_ALT_MEMTEST /* Much more complex memory test */
+/* TEMP: reserved 1MB at base for scripts and scratch,
+ * and 2MB at end for u-boot code and data relocated
+ */
+#define CONFIG_SYS_MEMTEST_START	(STM32_DDR_BASE + SZ_1M)
+#define CONFIG_SYS_MEMTEST_END		(STM32_DDR_BASE + SZ_64M - 2 * SZ_1M)
+#define CONFIG_SYS_MEMTEST_SCRATCH	(CONFIG_SYS_MEMTEST_START - 4)
 
 /*MMC SD*/
 #define CONFIG_SYS_MMC_MAX_DEVICE	3
 #define CONFIG_SUPPORT_EMMC_BOOT
 
-/*
- * define serial used for u-boot
- *
- * */
-#define CONFIG_CONS_INDEX 2
-
-/*
-* QSPI NOR standard settings 
-* 	used for env and dfu stuff
-*/
-#define CONFIG_ENV_SPI_MAX_HZ 8000000
-#define CONFIG_ENV_SPI_MODE (SPI_RX_QUAD | SPI_TX_QUAD)
-
-#define CONFIG_SF_DEFAULT_SPEED 8000000
-#define CONFIG_SF_DEFAULT_MODE (SPI_RX_QUAD | SPI_TX_QUAD)
-//#define CONFIG_SF_DEFAULT_CS 0
-//#define CONFIG_SF_DEFAULT_BUS 0
 /*****************************************************************************/
 #ifdef CONFIG_DISTRO_DEFAULTS
 /*****************************************************************************/
@@ -173,19 +157,24 @@
 #define CONFIG_SYS_MAX_NAND_DEVICE	1
 
 /* Watchdog */
+#if !defined(CONFIG_SPL) || !defined(CONFIG_SPL_BUILD)
 #ifdef CONFIG_STM32MP_WATCHDOG
 #define CONFIG_HW_WATCHDOG
 #endif
+#endif
 
 /* SPI FLASH support */
 #if defined(CONFIG_SPL_BUILD)
+#define CONFIG_SPL_SPI_LOAD
 #define CONFIG_SYS_SPI_U_BOOT_OFFS	0x80000
 #endif
 
 /* FILE SYSTEM */
 
-#if defined(CONFIG_STM32_QSPI) || defined(CONFIG_NAND_STM32_FMC2)
+#if defined(CONFIG_STM32_QSPI) || defined(CONFIG_NAND_STM32_FMC)
 /* Dynamic MTD partition support */
+#define CONFIG_MTD_PARTITIONS
+#define CONFIG_MTD_DEVICE	/* needed for mtdparts commands */
 #define CONFIG_SYS_MTDPARTS_RUNTIME
 #endif
 
@@ -224,7 +213,7 @@
 	"ubifs_boot=" \
 		"if test ${boot_device} = nand; then " \
 			"env exists bootubivol || " \
-				"env set bootubivol boroot; " \
+				"env set bootubivol boot; " \
 			"if ubifsmount ubi${devnum}:${bootubivol}; " \
 			"then " \
 				"setenv devtype ubi; " \
@@ -234,7 +223,7 @@
 			"env exists bootubipart || " \
 				"env set bootubipart UBI; " \
 			"env exists bootubivol || " \
-				"env set bootubivol boroot; " \
+				"env set bootubivol boot; " \
 			"if ubi part ${bootubipart} && " \
 				"ubifsmount ubi${devnum}:${bootubivol}; " \
 			"then " \
@@ -245,7 +234,7 @@
 #endif
 
 #define CONFIG_PREBOOT \
-	"dcache off; setenv board_name ${board_name}${housing}; " \
+	"setenv board_name ${board_name}${housing}; " \
 	"echo \"Boot over ${boot_device}${boot_instance}!\"; " \
 	"if test ${boot_device} = uart; then " \
 		"stm32prog serial ${boot_instance}; " \
@@ -256,100 +245,51 @@
 	"fi; "
 
 #ifdef CONFIG_STM32MP1_OPTEE
-#define CONFIG_SYS_MEM_TOP_HIDE			SZ_32M
 /* with OPTEE: define specific MTD partitions = teeh, teed, teex */
 #define STM32MP_MTDPARTS \
-	"mtdparts_nor0=256k(fsbl1),256k(fsbl2),2m(ssbl),256k(logo),256k(teeh),256k(teed),256k(teex),-(nor_user)\0" \
-	"mtdparts_spi-nand0=-(UBI);\0"
-
+	"mtdparts_nor0=256k(fsbl1),256k(fsbl2),2m(ssbl),256k(teeh),256k(teed),256k(teex),-(nor_user)\0" \
+	"mtdparts_nand0=2m(fsbl),2m(ssbl),512k(teeh),512k(teed),512k(teex),-(UBI);\0"
 
+#ifdef CONFIG_STM32MP15x_REVA
+#define STM32MP_MTDPARTS_REVA \
+	"mtdparts_nand0_reva=2m@0x80000(fsbl),2m(ssbl),512k(teeh),512k(teed),512k(teex),-(UBI);\0"
+#endif
 #else /* CONFIG_STM32MP1_OPTEE */
 #define STM32MP_MTDPARTS \
 	"mtdparts_nor0=256k(fsbl1),256k(fsbl2),1m(ssbl),64k(env),-(nor_user)\0" \
-	"mtdparts_spi-nand0=-(UBI)\0"
-
+	"mtdparts_nand0=2m(fsbl),2m(ssbl),-(UBI)\0"
 
+#ifdef CONFIG_STM32MP15x_REVA
+#define STM32MP_MTDPARTS_REVA \
+	"mtdparts_nand0_reva=2m@0x80000(fsbl),2m(ssbl),-(UBI)\0"
+#endif
 #endif /* CONFIG_STM32MP1_OPTEE */
 
 #ifndef STM32MP_MTDPARTS_REVA
 /* TEMP: to remove */
-//#define STM32MP_MTDPARTS_REVA
+#define STM32MP_MTDPARTS_REVA
 #endif
 
-/*u-boot vars needed for rescue os boot*/
-#define RESCUE_OS_ENV \
-	"res_kernel_img= uImage \0" \
-	"res_os_img= rescue-os.cpio.gz.u-boot \0" \
-	"res_dt= stm32mp-t1000-s-50.dtb \0" \
-	"rescue_os_flag=0\0" \
-	"upgrade_available=0\0" \
-	"altbootcmd=run bootcmd\0" \
-	"boot_rescue_os=" \
-		"for target in ${boot_targets}; do " \
-			"run boot_res_${target}; " \
-		"done\0" \
-	"boot_res_mmc0= " \
-		"env set devnum 0;" \
-		"env set res_part 3;" \
-		"run boot_res_mmcx;\0" \
-	"boot_res_mmc1= " \
-		"env set devnum 1;" \
-		"env set res_part 3;" \
-		"run boot_res_mmcx;\0" \
-	"boot_res_mmcx= " \
-		"if mmc dev ${devnum};" \
-		"then " \
-			"load mmc ${devnum}:${res_part} ${kernel_addr_r} ${res_kernel_img} ;" \
-			"load mmc ${devnum}:${res_part} ${ramdisk_addr_r} ${res_os_img} ;" \
-			"load mmc ${devnum}:${res_part} ${fdt_addr_r} ${res_dt};" \
-			"bootm ${kernel_addr_r} ${ramdisk_addr_r} ${fdt_addr_r};" \
-		"fi;\0" \
-	"boot_res_ubifs0= " \
-		"if ubi part ubi || ubi part UBI ;" \
-		"then " \
-			"ubifsmount ubi0:rescue-os; " \
-			"ubifsload ${kernel_addr_r} ${res_kernel_img} ; " \
-			"ubifsload ${ramdisk_addr_r} ${res_os_img} ;" \
-			"ubifsload ${fdt_addr_r} ${res_dt};" \
-			"bootm ${kernel_addr_r} ${ramdisk_addr_r} ${fdt_addr_r};" \
-		"fi;\0" \
-	"bootcmd=" \
-		"if test ${rescue_os_flag} = 1; then " \
-			"run boot_rescue_os;" \
-		"else " \
-			"run distro_bootcmd;" \
-		"fi\0" \
-	"altbootcmd=" \
-	    "echo ===========================;" \
-	    "echo WARNING: RESCUE BOOT ACTIVE;" \
-	    "echo ===========================;" \
-		"env set rescue_os_flag 1;" \
-		"run bootcmd;\0"\
-
-/*
- * memory layout for 32M uncompressed/compressed kernel,
- * 1M fdt, 1M script, 1M pxe and 1M for splashimage
- * and the ramdisk at the end.
- */
 #define CONFIG_EXTRA_ENV_SETTINGS \
 	"stdin=serial\0" \
 	"stdout=serial\0" \
 	"stderr=serial\0" \
-	"kernel_addr_r=0xc2000000\0" \
-	"fdt_addr_r=0xc4000000\0" \
-	"scriptaddr=0xc4100000\0" \
-	"pxefile_addr_r=0xc4200000\0" \
-	"splashimage=0xc4300000\0"  \
-	"ramdisk_addr_r=0xc4400000\0" \
+	"scriptaddr=0xC0000000\0" \
+	"pxefile_addr_r=0xC0000000\0" \
+	"kernel_addr_r=0xC1000000\0" \
+	"fdt_addr_r=0xC4000000\0" \
+	"ramdisk_addr_r=0xC4100000\0" \
 	"fdt_high=0xffffffff\0" \
 	"initrd_high=0xffffffff\0" \
+	"bootlimit=0\0" \
+	"altbootcmd=run bootcmd\0" \
 	"usb_pgood_delay=2000\0" \
 	"splashpos=m,m\0"  \
+	"splashimage=0xC0800000\0"  \
 	STM32MP_MTDPARTS \
+	STM32MP_MTDPARTS_REVA \
 	BOOTENV \
-	"boot_net_usb_start=true\0" \
-	"housing=" CONFIG_HOUSING_DEFAULT "\0" \
-	RESCUE_OS_ENV
+	"boot_net_usb_start=true\0"
 
 #endif /* ifndef CONFIG_SPL_BUILD */
 #endif /* ifdef CONFIG_DISTRO_DEFAULTS*/
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp1-t1000-common_2018.11.inc b/recipes-bsp/u-boot/u-boot-stm32mp1-t1000-common_2018.11.inc
deleted file mode 100644
index 6ee5cf2ba99c78db674fe4aec25a30de0c79d788..0000000000000000000000000000000000000000
--- a/recipes-bsp/u-boot/u-boot-stm32mp1-t1000-common_2018.11.inc
+++ /dev/null
@@ -1,150 +0,0 @@
-FILESOVERLAY_DIR = "filesoverlay"
-# Use FILESOVERLAY_DIR instead of SUBIDR_DIR. SUBDIR_DIR has problems with devtool
-# and therefore is deprecated!
-SUBDIR_DIR = "git"
-S = "${WORKDIR}/git"
-
-# add patches
-SRC_URI_append += "\
-		file://0100-Add-config-option-for-housing-env-var.patch \
-		file://0001-fix-missing-eth-phy-clocks.patch \
-		file://0001-add-NOR-flash-mx25v8035-and-mx25r1635f.patch \
-		file://0002-extend-extlinux-for-multiple-boards.patch \
-		file://0001-added-t1000-Kconfig.patch \
-		file://0004-set-ethxaddr-in-device-tree-node-with-alias-ethernet.patch \
-		file://0005-add-video_splash-function.patch \
-        file://0009-changed-clock-layout-which-was-corrected-in-r2.1.patch \
-		file://0001-qspi-nand-support-added-stm32_qpsi-driver-changes-to.patch \
-		file://0002-stm32_qspi-to-previous-working-mtd-compatible-versio.patch \
-		file://0001-Fix-timeout-overflow-issue-of-the-stm32mp-watchdog-d.patch \
-	    "
-
-#		file://0001-Fix-timeout-overflow-issue-of-the-stm32mp-watchdog-d.patch \
-#
-#
-
-# add board sourcecode
-SRC_URI_append += "\
-    file://board/kontron/stm32mp1-t1000/board.c;subdir=${FILESOVERLAY_DIR} \
-    file://board/kontron/stm32mp1-t1000/Makefile;subdir=${FILESOVERLAY_DIR} \
-    file://board/kontron/stm32mp1-t1000/README;subdir=${FILESOVERLAY_DIR} \
-    file://board/kontron/stm32mp1-t1000/spl.c;subdir=${FILESOVERLAY_DIR} \
-    file://board/kontron/stm32mp1-t1000/stm32mp1-t1000.c;subdir=${FILESOVERLAY_DIR} \
-    file://board/kontron/stm32mp1-t1000/cmd_stboard.c;subdir=${FILESOVERLAY_DIR} \
-    file://board/kontron/stm32mp1-t1000/extlinux.conf;subdir=${FILESOVERLAY_DIR} \
-    file://board/kontron/stm32mp1-t1000/fit_copro_kernel_dtb.its;subdir=${FILESOVERLAY_DIR} \
-    file://board/kontron/stm32mp1-t1000/fit_kernel_dtb.its;subdir=${FILESOVERLAY_DIR} \
-    file://include/configs/stm32mp1-t1000.h;subdir=${FILESOVERLAY_DIR} \
-    "
-
-# add devicetree configuration for stm32mp1-t1000 and som
-SRC_URI_append += "\
-    file://arch/arm/dts/stm32mp157c-t1000-ddr3-1x4Gb-1066-binG.h;subdir=${FILESOVERLAY_DIR} \
-    \
-    file://configs/stm32mp1-t1000_defconfig;subdir=${FILESOVERLAY_DIR} \
-    file://configs/stm32mp1-t1000-sdcard_defconfig;subdir=${FILESOVERLAY_DIR} \
-    file://configs/stm32mp15_basic_calibration_defconfig;subdir=${FILESOVERLAY_DIR} \
-    file://configs/stm32mp1-t1000-evk50_defconfig;subdir=${FILESOVERLAY_DIR} \
-    file://configs/stm32mp1-t1000-evk50sdcard_defconfig;subdir=${FILESOVERLAY_DIR} \
-    \
-    file://arch/arm/dts/stm32mp15-mx.h;subdir=${FILESOVERLAY_DIR} \
-    file://arch/arm/dts/stm32mp-board-minimal.dtsi;subdir=${FILESOVERLAY_DIR} \
-    file://arch/arm/dts/stm32mp-board-minimal-u-boot.dtsi;subdir=${FILESOVERLAY_DIR} \
-    "
-
-# add som t1000
-SRC_URI_append += "\
-    file://arch/arm/dts/stm32mp157c-t1000-som-minimal-mx.dts;subdir=${FILESOVERLAY_DIR} \
-    file://arch/arm/dts/stm32mp157c-t1000-som-minimal-mx-u-boot.dtsi;subdir=${FILESOVERLAY_DIR} \
-    file://arch/arm/dts/stm32mp-som-t1000-u-boot.dtsi;subdir=${FILESOVERLAY_DIR} \
-    file://arch/arm/dts/stm32mp-som-t1000.dtsi;subdir=${FILESOVERLAY_DIR} \
-    file://arch/arm/dts/stm32mp-t1000-u-boot.dtsi;subdir=${FILESOVERLAY_DIR} \
-    file://arch/arm/dts/stm32mp-t1000.dts;subdir=${FILESOVERLAY_DIR} \
-	"
-
-# add som t1001
-SRC_URI_append += "\
-    file://arch/arm/dts/stm32mp157c-t1001-som-minimal-mx.dts;subdir=${FILESOVERLAY_DIR} \
-    file://arch/arm/dts/stm32mp157c-t1001-som-minimal-mx-u-boot.dtsi;subdir=${FILESOVERLAY_DIR} \
-    file://arch/arm/dts/stm32mp-som-t1001-u-boot.dtsi;subdir=${FILESOVERLAY_DIR} \
-    file://arch/arm/dts/stm32mp-som-t1001.dtsi;subdir=${FILESOVERLAY_DIR} \
-    file://arch/arm/dts/stm32mp-t1001-u-boot.dtsi;subdir=${FILESOVERLAY_DIR} \
-    file://arch/arm/dts/stm32mp-t1001.dts;subdir=${FILESOVERLAY_DIR} \
-	"
-
-# add som t1004
-SRC_URI_append += "\
-    file://arch/arm/dts/stm32mp-t1004-u-boot.dtsi;subdir=${FILESOVERLAY_DIR} \
-    file://arch/arm/dts/stm32mp-t1004.dts;subdir=${FILESOVERLAY_DIR} \
-	"
-
-# add som t1005
-SRC_URI_append += "\
-    file://arch/arm/dts/stm32mp-t1005-u-boot.dtsi;subdir=${FILESOVERLAY_DIR} \
-    file://arch/arm/dts/stm32mp-t1005.dts;subdir=${FILESOVERLAY_DIR} \
-	"
-
-# add board s
-SRC_URI_append += "\
-    file://arch/arm/dts/stm32mp157c-t1000-s-mx.dts;subdir=${FILESOVERLAY_DIR} \
-    file://arch/arm/dts/stm32mp157c-t1000-s-mx-u-boot.dtsi;subdir=${FILESOVERLAY_DIR} \
-    file://arch/arm/dts/stm32mp-board-s.dtsi;subdir=${FILESOVERLAY_DIR} \
-    file://arch/arm/dts/stm32mp-board-s-u-boot.dtsi;subdir=${FILESOVERLAY_DIR} \
-    file://arch/arm/dts/stm32mp-t1000-s.dts;subdir=${FILESOVERLAY_DIR} \
-    file://arch/arm/dts/stm32mp-t1000-s-u-boot.dtsi;subdir=${FILESOVERLAY_DIR} \
-    file://arch/arm/dts/stm32mp-t1000-s-clkout32k.dts;subdir=${FILESOVERLAY_DIR} \
-    file://arch/arm/dts/stm32mp-t1000-s-clkout32k-u-boot.dtsi;subdir=${FILESOVERLAY_DIR} \
-    "
-
-# add board k
-SRC_URI_append += "\
-    file://arch/arm/dts/stm32mp157c-t1000-k-mx.dts;subdir=${FILESOVERLAY_DIR} \
-    file://arch/arm/dts/stm32mp157c-t1000-k-mx-u-boot.dtsi;subdir=${FILESOVERLAY_DIR} \
-    file://arch/arm/dts/stm32mp-board-k.dtsi;subdir=${FILESOVERLAY_DIR} \
-    file://arch/arm/dts/stm32mp-board-k-u-boot.dtsi;subdir=${FILESOVERLAY_DIR} \
-    file://arch/arm/dts/stm32mp-t1000-k.dts;subdir=${FILESOVERLAY_DIR} \
-    file://arch/arm/dts/stm32mp-t1000-k-u-boot.dtsi;subdir=${FILESOVERLAY_DIR} \
-    "
-
-# add board testadapter
-SRC_URI_append += "\
-    file://configs/stm32mp1-t1000-production_defconfig;subdir=${FILESOVERLAY_DIR} \
-    file://arch/arm/dts/stm32mp-t1000-testadapter.dts;subdir=${FILESOVERLAY_DIR} \
-    file://arch/arm/dts/stm32mp-t1000-testadapter-u-boot.dtsi;subdir=${FILESOVERLAY_DIR} \
-    "
-
-do_buildenv[nostamp]="1"
-do_buildenv() {
-	{
-		echo "if test -z \${DEFCONFIG}; then"
-		echo "    export DEFCONFIG"
-		echo "    echo \"ERROR: Set DEFCONFIG in your environment and source again!\""
-		echo "    echo \"Currently available configs:\""
-		echo "    for config in \$(ls -1d \${B}/*_defconfig); do"
-		echo "        echo -n \"    export DEFCONFIG=\""
-		echo "        basename \$config"
-		echo "    done"
-		echo "    unalias makey"
-		echo "else"
-		echo "    export CROSS_COMPILE=\$(echo ${CC} | sed -n \"s/gcc .*//p\")"
-		echo "    export MF=\"-j6 ARCH=arm CROSS_COMPILE=\${CROSS_COMPILE} O=${B}/\${DEFCONFIG} \""
-		echo "    export S=${S}"
-		echo "    export O=${B}/\${DEFCONFIG}"
-		echo "    export D=${D}"
-		echo "    alias makey=\"make \${MF}\""
-		echo "    echo Output directory O=${B}/\${DEFCONFIG}"
-		echo "    echo Makeflags MF=\${MF}"
-		echo "    echo CROSS_COMPILE=\${CROSS_COMPILE}"
-		echo "fi"
-
-	} > ${S}/recipe.env
-}
-
-addtask buildenv after do_configure before do_devshell
-
-do_unpack_append() {
-# unpack is a python function
-    overlays_dir=os.path.join(d.getVar("WORKDIR"), d.getVar("FILESOVERLAY_DIR"))
-    bb.note("copy files from {} to {}".format(overlays_dir, d.getVar("S")))
-    os.system("cp -r {}/* {}".format(overlays_dir, d.getVar("S")))
-}
diff --git a/recipes-bsp/u-boot/u-boot-stm32mp_2018.11.bbappend b/recipes-bsp/u-boot/u-boot-stm32mp_2018.11.bbappend
deleted file mode 100644
index 5c833770f33c6876e8b98959d5f3f596bde8efc1..0000000000000000000000000000000000000000
--- a/recipes-bsp/u-boot/u-boot-stm32mp_2018.11.bbappend
+++ /dev/null
@@ -1,11 +0,0 @@
-FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
-
-####################################################################################
-# Set source to stm git and respective URI
-# Version r3.1
-####################################################################################
-SRCREV = "0521742dac1ad3238bc5512fd07b5af72e4ea9d9"
-SRCREV_bleeding = "${AUTOREV}"
-SRC_URI = "git://github.com/STMicroelectronics/u-boot.git;name=uboot;protocol=https;branch=v2018.11-stm32mp"
-
-require u-boot-stm32mp1-t1000-common_${PV}.inc
diff --git a/recipes-bsp/u-boot/u-boot-stmxceet-common_2018.03.inc b/recipes-bsp/u-boot/u-boot-stmxceet-common_2018.03.inc
new file mode 100644
index 0000000000000000000000000000000000000000..8722200e2ab77b20c285eb5eaba878d0432928a4
--- /dev/null
+++ b/recipes-bsp/u-boot/u-boot-stmxceet-common_2018.03.inc
@@ -0,0 +1,70 @@
+
+# add board sourcecode
+SRC_URI_append += "\
+    file://board/exceet/stmxceet-mp157-som/board.c;subdir=git \
+    file://board/exceet/stmxceet-mp157-som/Makefile;subdir=git \
+    file://board/exceet/stmxceet-mp157-som/post-memory.c;subdir=git \
+    file://board/exceet/stmxceet-mp157-som/README;subdir=git \
+    file://board/exceet/stmxceet-mp157-som/spl.c;subdir=git \
+    file://board/exceet/stmxceet-mp157-som/stmxceet-mp157-som.c;subdir=git \
+    file://include/configs/stmxceet-mp157-som.h;subdir=git \
+    "
+
+# add patches
+SRC_URI_append += "\
+    file://0001-remove-_defconfig-files-from-gitignore.patch \
+    file://0002-add-NOR-flash-mx25v8035-and-mx25r1635f.patch \
+    file://0003-fix-enable-phy-clock-for-ethernet.patch \
+    file://0004-fix-add-CAD-definition-files.patch \
+    file://0005-stmxceet-Kconfig-for-board-stmxceet-mp157-som-added.patch \
+    file://0001-extend-extlinux-for-multiple-boards.patch \
+    "
+
+# add devicetree configuration for board
+SRC_URI_append += "\
+    file://arch/arm/dts/stm32mp157c-t1000-mx.dts;subdir=git \
+    file://arch/arm/dts/stm32mp157c-t1000-mx-u-boot.dtsi;subdir=git \
+    file://arch/arm/dts/stm32mp157c-t1000-ddr3-1x4Gb-1066-binG.h;subdir=git \
+    \
+    file://configs/stmxceet-mp157-som_defconfig;subdir=git \
+    file://configs/stmxceet-mp157-som-basic_defconfig;subdir=git \
+    file://configs/stm32mp15_basic_calibration_defconfig;subdir=git \
+    \
+    file://arch/arm/dts/stm32mp15-mx.h;subdir=git \
+    file://arch/arm/dts/stm32mp-som-t1000-u-boot.dtsi;subdir=git \
+    file://arch/arm/dts/stm32mp-som-t1000.dtsi;subdir=git \
+    "
+
+# add board default
+SRC_URI_append += "\
+    file://arch/arm/dts/stm32mp157c-t1000-default-mx.dts;subdir=git \
+    file://arch/arm/dts/stm32mp157c-t1000-default-mx-u-boot.dtsi;subdir=git \
+    file://arch/arm/dts/stm32mp-board-default.dtsi;subdir=git \
+    file://arch/arm/dts/stm32mp-t1000-default.dts;subdir=git \
+    file://arch/arm/dts/stm32mp-t1000-default-u-boot.dtsi;subdir=git \
+    "
+
+# add board mini
+SRC_URI_append += "\
+    file://arch/arm/dts/stm32mp157c-t1000-mini-mx.dts;subdir=git \
+    file://arch/arm/dts/stm32mp157c-t1000-mini-mx-u-boot.dtsi;subdir=git \
+    file://arch/arm/dts/stm32mp-board-mini.dtsi;subdir=git \
+    file://arch/arm/dts/stm32mp-t1000-mini.dts;subdir=git \
+    file://arch/arm/dts/stm32mp-t1000-mini-u-boot.dtsi;subdir=git \
+    "
+
+# add board s
+SRC_URI_append += "\
+    file://arch/arm/dts/stm32mp157c-t1000-s-mx.dts;subdir=git \
+    file://arch/arm/dts/stm32mp157c-t1000-s-mx-u-boot.dtsi;subdir=git \
+    file://arch/arm/dts/stm32mp-board-s.dtsi;subdir=git \
+    file://arch/arm/dts/stm32mp-board-s-u-boot.dtsi;subdir=git \
+    file://arch/arm/dts/stm32mp-t1000-s.dts;subdir=git \
+    file://arch/arm/dts/stm32mp-t1000-s-u-boot.dtsi;subdir=git \
+    "
+
+# add board stmxceet
+SRC_URI_append += "\
+    file://arch/arm/dts/stmxceet-mp157-som.dts;subdir=git \
+    file://arch/arm/dts/stmxceet-mp157-som-u-boot.dtsi;subdir=git \
+    "
diff --git a/recipes-bsp/u-boot/u-boot-trusted-stm32mp_2018.03.bbappend b/recipes-bsp/u-boot/u-boot-trusted-stm32mp_2018.03.bbappend
new file mode 100644
index 0000000000000000000000000000000000000000..ca13a60f7a9207d0f4eca164fd05745778cf2285
--- /dev/null
+++ b/recipes-bsp/u-boot/u-boot-trusted-stm32mp_2018.03.bbappend
@@ -0,0 +1,4 @@
+FILESEXTRAPATHS_prepend := "${THISDIR}/u-boot-stm32mp:"
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
+
+require u-boot-stmxceet-common_${PV}.inc
diff --git a/recipes-connectivity/wpa-supplicant/wpa-supplicant/wpa_supplicant-wlan0.conf b/recipes-connectivity/wpa-supplicant/wpa-supplicant/wpa_supplicant-wlan0.conf
deleted file mode 100644
index 2e799b085cb6f7861960c3f347bae2a6143e139a..0000000000000000000000000000000000000000
--- a/recipes-connectivity/wpa-supplicant/wpa-supplicant/wpa_supplicant-wlan0.conf
+++ /dev/null
@@ -1,9 +0,0 @@
-ctrl_interface=/var/run/wpa_supplicant
-ctrl_interface_group=0
-update_config=1
-
-# generate credential with: wpa_passphrase YOUR_SSID >> THIS_FILE
-#network={
-#        ssid="YOUR_SSID"
-#        psk=YOUR_KEY
-#}
diff --git a/recipes-connectivity/wpa-supplicant/wpa-supplicant_2.6.bbappend b/recipes-connectivity/wpa-supplicant/wpa-supplicant_2.6.bbappend
index 04ad57feeaaac0dc277a65dc9b69c800f42afc65..ba5c7b4714270dc7dfe22490f41782d4680e6658 100644
--- a/recipes-connectivity/wpa-supplicant/wpa-supplicant_2.6.bbappend
+++ b/recipes-connectivity/wpa-supplicant/wpa-supplicant_2.6.bbappend
@@ -1,12 +1,9 @@
 FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
 
-SRC_URI += "file://wpa_supplicant-mlan0.conf \
-            file://wpa_supplicant-wlan0.conf \
-		   "
+SRC_URI += "file://wpa_supplicant-mlan0.conf"
 
 do_install_append() {
 	install -d ${D}${sysconfdir}
 	install -d ${D}${sysconfdir}/wpa_supplicant
 	install -m 600 ${WORKDIR}/wpa_supplicant-mlan0.conf ${D}${sysconfdir}/wpa_supplicant
-	install -m 600 ${WORKDIR}/wpa_supplicant-wlan0.conf ${D}${sysconfdir}/wpa_supplicant
 }
diff --git a/recipes-core/images/image-ktn-base-append.inc b/recipes-core/images/image-ktn-base-append.inc
deleted file mode 100644
index 6cc54dab4de35240fc3da4623ee16e14fdf53697..0000000000000000000000000000000000000000
--- a/recipes-core/images/image-ktn-base-append.inc
+++ /dev/null
@@ -1,41 +0,0 @@
-# This is graphics dependent
-IMAGE_FEATURES += "\
-	splash \
-	hwcodecs \
-	"
-
-########################################
-##### BASIC PACKAGES ###################
-########################################
-IMAGE_INSTALL += "\
-	os-release \
-	htop \
-	beep \
-	rng-tools \
-	mptool	\
-	m4-fw-autoload \
-	"
-
-# Additional diagnostic packages
-IMAGE_INSTALL_DIAGNOSTICS += "\
-	memtester \
-	cpufrequtils \
-	libgpiod \
-	libiio-tests \
-	i2c-tools \
-	spitools \
-	evtest \
-	ethtool \
-	\
-	mmc-utils \
-	mtd-utils-ubifs \
-	\
-	iperf3 \
-	iproute2 \
-	\
-	libdrm-tests \
-	\
-	board-tools \
-	"
-
-IMAGE_INSTALL += "${IMAGE_INSTALL_DIAGNOSTICS}"
diff --git a/recipes-core/images/image-ktn-minimal-append.inc b/recipes-core/images/image-ktn-minimal-append.inc
deleted file mode 100644
index 4e06ab3539c7edfe4e03e574a995adf095e78fbe..0000000000000000000000000000000000000000
--- a/recipes-core/images/image-ktn-minimal-append.inc
+++ /dev/null
@@ -1,44 +0,0 @@
-########################################
-##### removes from core image ##########
-########################################
-
-IMAGE_INSTALL_remove = "u-boot"
-IMAGE_INSTALL_remove = "kernel-devicetree"
-#IMAGE_INSTALL_remove = "udev-extraconf"
-
-
-
-
-########################################
-
-IMAGE_INSTALL_remove = "systemd-mount-partitions"
-
-IMAGE_INSTALL +="\
-	add-bootcountreset-and-swversion \
-	u-boot-stm32mp-extlinux \
-	kernel-imagebootfs \
-	${@bb.utils.contains('DISTRO_FEATURES', 'systemd', 'systemd-networkd-configuration', '', d)} \
-	${@bb.utils.contains('DISTRO_FEATURES', 'systemd', 'systemd-analyze', '', d)} \
-    u-boot-fw-utils \
-	"
-
-# Fix wrong dependency in OpenST:
-# If we don't have gcnano-userland-binary nobody builds the recipe 'gcnano-driver-stm32mp'
-# In MACHINE_EXTRA_RRECOMMENDS 'kernel-module-galcore' is set when GPU machine feature is
-# activated.
-# -> So building the image fails because kernel-module-galcore is not available
-#    (the linux kernel RPROVIDES all kernel-module-* dependencies by default. But this
-#    doesn't help here because somebody must PROVIDE it)
-# -> The simplest way is to install 'gcnano-driver-stm32mp' directly
-# REMARK: Adding a PROVIDE += "kernel-module-galcore" to the 'gcnano-driver-stm32mp.bb'
-#         recipe seems not to help (proofed), because the "kernel-module-*" dependencies
-#         are fulfilled by the install of the kernel recipe (!?  this is an expectation!)
-#         and therefore after building the linux kernel our recipe 'kernel-module-galcore'
-#         isn't build!
-# REMARK: gcnano-driver-stm32mp has to be built to get the kernel-module-galcore which have
-#         to be installed. So both must be mentionned in IMAGE_INSTALL to be built
-#         (gcnano-driver-stm32mp) and to be installed (kernel-module-galcore). The reason
-#         for this is that the kernel module is named 'galcore.ko' and the recipe named
-#         gcnano-driver-stm32mp. The kernel module package is always named after the *.ko
-#         name of the driver! So gcnano-driver-stm32mp is an empty dummy package.
-IMAGE_INSTALL += "${@bb.utils.contains('MACHINE_FEATURES', 'gpu', 'gcnano-driver-stm32mp', '', d)} "
diff --git a/recipes-core/images/image-ktn-minimal.bbappend b/recipes-core/images/image-ktn-minimal.bbappend
deleted file mode 100644
index f7217d90da6ac6b5f29424051fb08b3223b3b7bc..0000000000000000000000000000000000000000
--- a/recipes-core/images/image-ktn-minimal.bbappend
+++ /dev/null
@@ -1 +0,0 @@
-require recipes-core/images/image-ktn-minimal-append.inc
\ No newline at end of file
diff --git a/recipes-core/images/image-ktn-qt-append.inc b/recipes-core/images/image-ktn-qt-append.inc
deleted file mode 100644
index 25418ed40b24172feaadf932e98d75fe8a89a17a..0000000000000000000000000000000000000000
--- a/recipes-core/images/image-ktn-qt-append.inc
+++ /dev/null
@@ -1,38 +0,0 @@
-# Wayland extensions
-IMAGE_QT_WAYLAND = "\
-    weston \
-    weston-init \
-    qtwayland \
-    qtwayland-plugins \
-    "
-
-IMAGE_QT_WAYLAND_EXAMPLES = "\
-    weston-examples \
-    qtwayland-examples \
-    "
-
-
-# Exceet demo
-IMAGE_QT_DEMO_EXCEET = "\
-    qtmultimedia \
-    qtmultimedia-qmlplugins \
-    "
-#exceet-demo-video
-
-# Demo applications
-IMAGE_QT_DEMOS = "\
-    ${IMAGE_QT_DEMO_EXCEET} \
-    cinematicexperience \
-    cinematicexperience-tools \
-    "
-
-########################################
-##### Additional Qt PACKAGES ###########
-########################################
-IMAGE_INSTALL_append += "\
-    psplash \
-    ${IMAGE_QT_DEMOS} \
-    ${@bb.utils.contains('DISTRO_FEATURES', 'gstreamer', 'packagegroup-gstreamer1-0', '', d)} \
-    ${@bb.utils.contains('DISTRO_FEATURES', 'wayland', '${IMAGE_QT_WAYLAND}', '', d)} \
-    ${@bb.utils.contains('DISTRO_FEATURES', 'wayland', '', 'autostart-eglfs', d)} \
-    "
diff --git a/recipes-core/images/image-ktn-qt.bbappend b/recipes-core/images/image-ktn-qt.bbappend
deleted file mode 100644
index e352a481a6a569388d7214396a3c7421de06cda1..0000000000000000000000000000000000000000
--- a/recipes-core/images/image-ktn-qt.bbappend
+++ /dev/null
@@ -1,3 +0,0 @@
-require recipes-core/images/image-ktn-minimal-append.inc
-require recipes-core/images/image-ktn-base-append.inc
-require recipes-core/images/image-ktn-qt-append.inc
\ No newline at end of file
diff --git a/recipes-core/images/image-ktn.bbappend b/recipes-core/images/image-ktn.bbappend
deleted file mode 100644
index 16b4eb6be713ab32d51a53517e381f7ca65a7b44..0000000000000000000000000000000000000000
--- a/recipes-core/images/image-ktn.bbappend
+++ /dev/null
@@ -1,2 +0,0 @@
-require recipes-core/images/image-ktn-minimal-append.inc
-require recipes-core/images/image-ktn-base-append.inc
\ No newline at end of file
diff --git a/recipes-core/images/image-stm32mp-console.bb b/recipes-core/images/image-stm32mp-console.bb
index 367765485feafd82792b9a7c260e67864b26f4b6..adb9484d99200614c952ea7ab551917a94aa238f 100644
--- a/recipes-core/images/image-stm32mp-console.bb
+++ b/recipes-core/images/image-stm32mp-console.bb
@@ -4,16 +4,6 @@ LICENSE = "MIT"
 inherit core-image
 inherit distro_features_check
 
-# Build additional images for complete device contents
-STM32MP_USERFS_IMAGE = "st-image-userfs"
-STM32MP_USERFS_LABEL = "userfs"
-STM32MP_USERFS_MOUNTPOINT_IMAGE = "/usr/local"
-PARTITIONS_IMAGE = "${STM32MP_USERFS_IMAGE}"
-PARTITIONS_MOUNTPOINT_IMAGE = "${STM32MP_USERFS_MOUNTPOINT_IMAGE}"
-# Provide list of partition to mount
-MOUNT_PARTITIONS_LIST = "${STM32MP_USERFS_LABEL},${STM32MP_USERFS_MOUNTPOINT_IMAGE}"
-
-
 IMAGE_FEATURES += "\
 	package-management \
 	ssh-server-openssh \
@@ -40,8 +30,6 @@ IMAGE_INSTALL += "\
 	u-boot-fw-utils \
 	os-release \
 	htop \
-	beep \
-	rng-tools \
 	"
 
 # Additional diagnostic packages
@@ -50,10 +38,10 @@ IMAGE_INSTALL_DIAGNOSTICS += "\
 	cpufrequtils \
 	libgpiod \
 	libiio-tests \
+	can-utils \
 	i2c-tools \
 	spitools \
 	evtest \
-	ethtool \
 	\
 	mmc-utils \
 	mtd-utils-ubifs \
@@ -62,15 +50,7 @@ IMAGE_INSTALL_DIAGNOSTICS += "\
 	iproute2 \
 	\
 	libdrm-tests \
-	\
-	board-tools \
-	\
-	m4-fw-autoload \
-	mptool	\
-	\
-	add-bootcountreset-and-swversion \
 	"
-
 IMAGE_INSTALL += "${IMAGE_INSTALL_DIAGNOSTICS}"
 
 # Fix wrong dependency in OpenST:
@@ -97,11 +77,10 @@ IMAGE_INSTALL += "${@bb.utils.contains('MACHINE_FEATURES', 'gpu', 'gcnano-driver
 # Add boot files to image
 # This is dependent on bootscheme.
 # Here: extlinux with only one bootfs partition else these packages are included in bootfs image
-IMAGE_INSTALL += "\
-	u-boot-stm32mp-extlinux \
-	kernel-imagebootfs \
-	"
-
+#IMAGE_INSTALL += "\
+#	u-boot-stm32mp-extlinux \
+#	kernel-imagebootfs \
+#	"
 
 # TODO: Currently only available on imx6
 #IMAGE_INSTALL = "production-tool  udev-extraconf"
diff --git a/recipes-core/images/image-stm32mp-qt.bb b/recipes-core/images/image-stm32mp-qt.bb
index 0a9893deaa0055ecbc5f21c64d99cafe6eb474c7..25ad1ecf32defd5312c3328a6e2dbbac34b5b0ed 100644
--- a/recipes-core/images/image-stm32mp-qt.bb
+++ b/recipes-core/images/image-stm32mp-qt.bb
@@ -32,9 +32,8 @@ IMAGE_QT_DEMO_WEBENGINE = "\
 
 # Exceet demo
 IMAGE_QT_DEMO_EXCEET = "\
-    kontron-demo \
-    kontron-demo-slideshow \
-    kontron-demo-autostart \
+    exceet-demo \
+    exceet-demo-slideshow \
     qtmultimedia \
     qtmultimedia-qmlplugins \
     "
@@ -46,14 +45,12 @@ IMAGE_QT_DEMOS = "\
     ${IMAGE_QT_DEMO_EXCEET} \
     animatedtiles \
     cinematicexperience \
-    cinematicexperience-tools \
     "
 
 ########################################
 ##### Additional Qt PACKAGES ###########
 ########################################
 IMAGE_INSTALL_append += "\
-    psplash-drm \
     ${IMAGE_QT_BASE} \
     ${IMAGE_QT_DEMOS} \
     ${@bb.utils.contains('DISTRO_FEATURES', 'gstreamer', 'packagegroup-gstreamer1-0', '', d)} \
diff --git a/recipes-core/psplash/psplash-drm.bbappend b/recipes-core/psplash/psplash-drm.bbappend
deleted file mode 100644
index fc6d62692b753320058e0185bcd7851915fadc27..0000000000000000000000000000000000000000
--- a/recipes-core/psplash/psplash-drm.bbappend
+++ /dev/null
@@ -1,21 +0,0 @@
-FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
-
-SRC_URI_append = "	\
-				file://kontronelectronics_small.png \
-				file://psplash-init-script.sh \		
-				"
-
-INITSCRIPT_NAME = "psplash-init-script.sh"
-INITSCRIPT_PARAMS = "start 00 5 2 . stop 20 0 1 6 ."
-
-inherit update-rc.d 
-
-
-do_install_append() {
-       
-    if ! ${@bb.utils.contains('DISTRO_FEATURES','systemd','true','false',d)}; then
-    	install -d ${D}${sysconfdir}/init.d/
-		install -c -m 755 ${WORKDIR}/${INITSCRIPT_NAME} ${D}${sysconfdir}/init.d/${INITSCRIPT_NAME}
-			
-    fi
-}
\ No newline at end of file
diff --git a/recipes-core/psplash/psplash-drm/image_header.h b/recipes-core/psplash/psplash-drm/image_header.h
deleted file mode 100644
index c1fdc1c6007b3727138429eaa8e85030ff2b2572..0000000000000000000000000000000000000000
--- a/recipes-core/psplash/psplash-drm/image_header.h
+++ /dev/null
@@ -1,3894 +0,0 @@
-/* GdkPixbuf RGBA C-Source image dump 1-byte-run-length-encoded */
-
-#define SPLASH_IMG_ROWSTRIDE (1920)
-#define SPLASH_IMG_WIDTH (480)
-#define SPLASH_IMG_HEIGHT (162)
-#define SPLASH_IMG_BYTES_PER_PIXEL (4) /* 3:RGB, 4:RGBA */
-#define SPLASH_IMG_RLE_PIXEL_DATA ((uint8_t*) \
-  "\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0" \
-  "\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0" \
-  "\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377" \
-  "\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0" \
-  "\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0" \
-  "\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377" \
-  "\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0" \
-  "\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0" \
-  "\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377" \
-  "\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0" \
-  "\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0" \
-  "\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377" \
-  "\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0" \
-  "\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0" \
-  "\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377" \
-  "\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0" \
-  "\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0" \
-  "\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377" \
-  "\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0" \
-  "\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0" \
-  "\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377" \
-  "\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0" \
-  "\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0" \
-  "\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377" \
-  "\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0" \
-  "\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\376\0\0" \
-  "\0\0\1\235\274\327\0\212\0\0\0\0\2\0Ni\0\353\353\377\0\377\0\0\0\0\377" \
-  "\0\0\0\0\377\0\0\0\0\321\0\0\0\0\1\242\276\327\0\206\0\0\0\0\10\377\377" \
-  "\377\13\260\312\337'\231\273\3239\215\263\317@\210\257\315C\225\270\324" \
-  ">\240\277\3314\301\325\344\40\207\0\0\0\0\1\203\260\313\0\377\0\0\0\0" \
-  "\377\0\0\0\0\377\0\0\0\0\311\0\0\0\0\1\222\264\323\0\203\0\0\0\0\24\377" \
-  "\377\377\0\217\264\321DX\217\273f`\225\276\240[\221\274\310H\204\265" \
-  "\326>\177\261\335@\177\260\342>~\257\346;}\255\3479|\255\3507{\253\347" \
-  "4x\252\345/v\250\341,u\247\3335{\252\324D\205\260\277;\201\254\213I\213" \
-  "\263b\220\270\320-\205\0\0\0\0\1}\262\312\0\377\0\0\0\0\377\0\0\0\0\377" \
-  "\0\0\0\0\302\0\0\0\0\1\233\274\330\0\203\0\0\0\0\33\267\315\342#j\231" \
-  "\302hg\230\302\275O\211\271\342M\207\267\355J\205\266\362I\204\266\372" \
-  "H\203\265\377D\201\263\377A\177\261\377>~\260\377<}\257\377:|\256\377" \
-  "7z\254\3774x\253\3772w\251\377/v\250\377,t\247\377*s\246\377(s\245\376" \
-  "$q\243\367\37o\242\361\32m\240\353(x\246\340+|\250\240U\227\272]\377" \
-  "\377\377\5\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\302\0\0\0\0\1\222\264" \
-  "\325\0\202\0\0\0\0\40\377\377\377\7x\243\311[i\230\303\307V\214\274\356" \
-  "R\211\272\366R\212\273\375P\210\271\377M\207\270\377M\206\267\377K\205" \
-  "\267\377I\205\266\377G\203\266\377E\202\264\377C\201\263\377@\177\261" \
-  "\377>}\257\377<|\256\3779{\255\3775y\253\3773x\252\3770v\250\377,t\246" \
-  "\377)r\245\377%q\244\377!o\242\377\34m\240\377\31m\240\377\25k\236\373" \
-  "\16j\235\365\21o\240\354#z\250\243j\246\304J\203\0\0\0\0\1\220\274\323" \
-  "\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\272\0\0\0\0\1\220\263\324\0\202" \
-  "\0\0\0\0$\262\312\342\32y\243\313\204_\222\300\343X\215\275\372X\214" \
-  "\275\376W\214\275\377V\214\274\377U\213\274\377T\213\274\377S\212\273" \
-  "\377R\211\272\377O\210\271\377O\207\270\377K\206\267\377I\205\266\377" \
-  "G\203\265\377E\202\264\377B\200\262\377@~\260\377=}\257\3779{\255\377" \
-  "6y\253\3774x\252\3770v\250\377-t\246\377)r\245\377%q\244\377\40n\241" \
-  "\377\34m\240\377\30l\237\377\21j\235\377\11i\234\377\3h\233\374\1g\231" \
-  "\370\36v\243\330B\213\261b\202\0\0\0\0\2\1c\217\0\252\306\343\0\377\0" \
-  "\0\0\0\377\0\0\0\0\377\0\0\0\0\266\0\0\0\0\1\240\275\333\0\202\0\0\0" \
-  "\0\3\253\305\336\25x\244\313\205b\223\302\352\205[\217\277\377\202Z\216" \
-  "\277\377\36X\215\276\377W\214\275\377V\214\274\377T\213\274\377R\211" \
-  "\272\377Q\211\271\377N\207\270\377K\206\267\377I\204\266\377F\202\264" \
-  "\377D\201\263\377@\177\261\377>}\257\377:{\255\3776y\254\3773x\252\377" \
-  "0v\250\377,t\247\377)s\246\377$q\244\377\40o\242\377\33m\240\377\26k" \
-  "\236\377\17j\235\377\10h\233\377\1f\232\377\1f\231\377\1d\227\374\31" \
-  "q\240\345E\212\260a\202\0\0\0\0\1\377\377\377\0\377\0\0\0\0\377\0\0\0" \
-  "\0\377\0\0\0\0\262\0\0\0\0\1\241\275\333\0\203\0\0\0\0\4\317\335\356" \
-  "\10\201\250\316bh\227\304\342^\220\301\377\205`\222\302\377'_\221\302" \
-  "\377_\221\301\377_\220\301\377]\217\300\377\\\217\277\377[\216\276\377" \
-  "X\215\276\377W\214\275\377T\213\273\377R\211\272\377P\210\271\377M\206" \
-  "\270\377J\205\267\377G\203\265\377D\201\263\377A\200\262\377>~\260\377" \
-  ":|\256\3776y\253\3773w\251\3770v\250\377+t\246\377(r\245\377$p\243\377" \
-  "\36o\242\377\31l\237\377\25k\236\377\15i\234\377\5g\232\377\0f\231\377" \
-  "\0d\227\377\0b\225\377\14h\230\376\247\310\331\314\377\377\377+\0\0\0" \
-  "\0\377\377\377\0\0\0\0\0\377\377\377\0\377\0\0\0\0\377\0\0\0\0\377\0" \
-  "\0\0\0\256\0\0\0\0\1\211\256\321\0\203\0\0\0\0\4\205\255\321+s\237\311" \
-  "\270d\225\304\377b\223\303\377\202d\224\304\377\205e\225\305\377\34d" \
-  "\224\304\377c\224\303\377b\223\303\377`\222\302\377_\221\301\377\\\217" \
-  "\300\377[\216\277\377Y\215\276\377V\213\274\377S\212\273\377Q\211\272" \
-  "\377N\207\270\377K\205\267\377H\203\265\377E\201\263\377B\200\262\377" \
-  ">~\260\377:|\256\3776y\254\3772w\252\377/v\250\377+s\246\377'q\244\377" \
-  "\"p\243\377\35m\240\377\30l\237\377\22j\235\377\12h\233\377\202\3g\232" \
-  "\377\6-\177\251\377\322\343\354\377\377\377\377\377\377\377\377\371\377" \
-  "\377\377\204\377\377\377\10\202\0\0\0\0\2U\220\262\0\377\377\377\0\377" \
-  "\0\0\0\0\377\0\0\0\0\377\0\0\0\0\253\0\0\0\0\1\206\254\321\0\202\0\0" \
-  "\0\0\10\244\277\334\13\177\247\316al\232\307\356b\224\304\377e\226\305" \
-  "\377g\226\306\377i\227\307\377i\230\307\377\204j\231\310\377\40j\230" \
-  "\307\377i\230\307\377h\227\306\377g\226\305\377e\225\305\377c\224\304" \
-  "\377a\222\302\377_\221\301\377\\\220\300\377Z\216\276\377X\214\275\377" \
-  "U\213\274\377R\211\272\377N\207\270\377K\206\267\377H\203\265\377E\201" \
-  "\264\377@\177\262\377=}\257\377:{\255\3776y\254\3772w\251\377.u\247\377" \
-  ")t\246\377%q\244\377!o\242\377\34m\240\377\26k\237\377\17i\234\377\17" \
-  "m\236\377j\245\303\377\374\375\376\377\204\377\377\377\377\2\376\376" \
-  "\377\315\332\347\3560\202\0\0\0\0\202\377\377\377\0\377\0\0\0\0\377\0" \
-  "\0\0\0\377\0\0\0\0\250\0\0\0\0\2\306\306\343\0s\243\313\0\202\0\0\0\0" \
-  "\12\212\256\322\33x\242\313\221i\230\306\377e\225\305\377h\227\307\377" \
-  "j\230\310\377k\231\310\377l\232\311\377m\233\311\377n\233\312\377\204" \
-  "o\233\312\377\35m\233\311\377l\231\311\377k\231\310\377j\230\307\377" \
-  "h\227\306\377e\225\305\377c\224\304\377a\222\302\377^\221\301\377[\217" \
-  "\277\377X\215\276\377V\213\274\377R\211\272\377N\210\271\377K\205\267" \
-  "\377H\203\265\377D\201\263\377@\177\261\377=}\257\3778{\255\3774y\253" \
-  "\3771w\251\377-u\247\377(s\245\377#q\243\377\36n\241\377\34n\240\377" \
-  "1|\252\377\270\323\342\377\205\377\377\377\377\5\366\371\373\377\320" \
-  "\341\353\377\203\257\307\362\210\261\311o\377\377\377\2\202\0\0\0\0\1" \
-  "\377\377\377\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\246\0\0\0\0\2\256" \
-  "\311\344\0""4v\260\0\202\0\0\0\0\13\204\253\320+w\242\313\274e\225\305" \
-  "\377g\227\306\377k\231\310\377m\232\311\377n\233\312\377p\234\313\377" \
-  "r\235\314\377s\236\315\377t\237\315\377\203t\237\316\377\35s\237\315" \
-  "\377r\236\315\377q\235\314\377p\234\313\377n\233\312\377l\232\311\377" \
-  "j\231\307\377h\226\306\377e\224\304\377b\223\303\377_\221\301\377\\\217" \
-  "\300\377Y\215\276\377V\213\274\377R\212\273\377N\207\270\377K\205\266" \
-  "\377H\203\264\377C\200\262\377\77~\260\377;|\256\3777z\254\3773x\252" \
-  "\3770v\250\377*s\246\377#p\242\377)u\246\377b\233\276\377\354\363\367" \
-  "\377\204\377\377\377\377\10\370\373\374\377\333\350\360\377\177\256\310" \
-  "\377:\202\252\377\266\320\336\377\377\377\377\372\377\377\377\215\377" \
-  "\377\377\14\202\0\0\0\0\1v\244\300\0\377\0\0\0\0\377\0\0\0\0\377\0\0" \
-  "\0\0\244\0\0\0\0\2\271\321\350\0\11Q\233\0\202\0\0\0\0\13\200\247\317" \
-  "7u\240\313\331d\224\305\377j\230\307\376m\232\311\377o\233\312\377r\235" \
-  "\314\377s\236\315\377u\240\316\377w\241\317\377x\241\320\377\202y\242" \
-  "\320\377\35y\243\321\377y\242\320\377x\242\320\377w\241\320\377v\241" \
-  "\317\377t\237\316\377s\237\315\377q\235\314\377o\233\312\377l\231\310" \
-  "\377i\230\307\377e\226\305\377b\224\303\377`\222\302\377\\\217\300\377" \
-  "Y\215\276\377U\213\274\377R\211\272\377N\207\270\377J\205\266\377E\202" \
-  "\264\377B\200\262\377\77~\260\377:{\255\3776y\253\3770v\250\377,t\247" \
-  "\377>\201\256\377\237\300\327\377\204\377\377\377\377\13\374\376\376" \
-  "\377\337\354\362\377\220\274\322\377,|\246\377Y\227\271\377\361\366\371" \
-  "\377\377\377\377\377\376\377\377\377\377\377\377\377\377\377\377\243" \
-  "\377\377\377\30\202\0\0\0\0\1\377\377\377\0\377\0\0\0\0\377\0\0\0\0\377" \
-  "\0\0\0\0\243\0\0\0\0\1r\236\310\0\202\0\0\0\0\17\177\247\317=s\236\312" \
-  "\344e\225\305\377k\230\310\377m\232\311\377p\234\313\377s\236\315\377" \
-  "v\240\316\377x\241\320\377y\242\321\377{\244\321\377|\245\322\377}\245" \
-  "\323\377~\245\323\377~\245\322\377\202}\245\323\377\31|\244\322\377{" \
-  "\244\321\377z\242\321\377w\241\317\377t\237\316\377r\236\314\377p\234" \
-  "\313\377l\232\311\377j\230\307\377f\225\305\377c\223\303\377_\221\301" \
-  "\377\\\217\277\377Y\215\276\377U\213\274\377P\211\271\377M\206\267\377" \
-  "I\204\265\377E\202\263\377A\177\261\377=}\257\3774x\253\377:|\255\377" \
-  "d\230\276\377\326\344\356\377\204\377\377\377\377\5\344\356\364\377\247" \
-  "\312\334\3772\204\255\377\36v\244\377\236\303\326\377\205\377\377\377" \
-  "\377\3\336\351\360\377\251\306\327\262R\215\257$\202\0\0\0\0\1\377\377" \
-  "\377\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\244\0\0\0\0\20\201\251\317" \
-  "<r\236\312\346e\225\305\377k\231\310\377n\233\312\377q\235\314\377t\237" \
-  "\315\377w\241\317\377y\243\320\377|\244\322\377~\246\323\377\200\250" \
-  "\324\377\201\250\324\377\202\250\325\377\202\251\325\377\203\251\325" \
-  "\377\202\202\250\325\377\30\201\247\324\377\177\247\324\377~\245\323" \
-  "\377|\244\321\377y\243\321\377v\241\317\377t\237\316\377p\234\313\377" \
-  "n\232\311\377j\230\307\377f\226\305\377c\223\303\377_\221\301\377[\217" \
-  "\277\377W\215\275\377T\212\273\377P\207\270\377L\205\267\377H\203\265" \
-  "\377A\200\262\377;{\256\377M\210\265\377\223\270\322\377\366\371\374" \
-  "\377\203\377\377\377\377\6\353\362\367\377\275\325\344\377Q\222\270\377" \
-  "\12i\233\377M\225\271\377\333\351\361\377\204\377\377\377\377\6\353\363" \
-  "\367\377\255\312\332\377U\220\262\377d\232\270\377\303\327\343\256\377" \
-  "\377\377\33\202\0\0\0\0\1\377\377\377\0\377\0\0\0\0\377\0\0\0\0\377\0" \
-  "\0\0\0\240\0\0\0\0\21\204\253\317\0\0\0\0\0\210\254\3211r\237\311\340" \
-  "e\225\305\377j\231\310\377n\233\312\377q\236\314\377u\237\316\377y\242" \
-  "\317\377|\244\321\377~\246\323\377\201\247\324\377\203\251\325\377\205" \
-  "\252\326\377\206\253\327\377\207\254\330\377\202\207\254\331\377\24\210" \
-  "\254\330\377\207\253\330\377\206\253\327\377\204\252\326\377\203\250" \
-  "\325\377\200\247\324\377}\245\323\377{\244\321\377w\242\320\377t\237" \
-  "\315\377q\234\313\377m\232\311\377j\230\307\377f\225\305\377b\223\303" \
-  "\377^\220\300\377Z\216\276\377V\214\275\377R\211\272\377N\207\270\377" \
-  "\202F\202\265\377\2i\232\302\377\303\326\346\377\203\377\377\377\377" \
-  "\6\364\370\372\377\310\333\350\377s\245\304\377\25i\236\3770}\252\377" \
-  "\216\272\321\377\204\377\377\377\377\14\366\372\373\377\272\323\341\377" \
-  "_\231\271\377.x\242\377\210\262\312\377\371\373\374\377\377\377\377\377" \
-  "\376\376\377\237\377\377\377\25\0\0\0\0\323\337\353\0U\252\252\0\377" \
-  "\0\0\0\0\377\0\0\0\0\377\0\0\0\0\236\0\0\0\0\23\223\264\325\0\0\0\0\0" \
-  "\216\262\323\40s\236\311\314e\224\305\377j\230\307\377n\233\312\377q" \
-  "\235\314\377v\240\316\377y\242\320\377|\245\321\377\177\247\324\377\202" \
-  "\250\326\377\205\252\327\377\207\254\327\377\211\255\330\377\212\255" \
-  "\331\377\212\257\332\377\213\257\332\377\202\214\257\332\377\26\213\256" \
-  "\332\377\212\256\331\377\210\254\331\377\206\253\330\377\204\251\326" \
-  "\377\202\250\325\377~\246\323\377{\244\322\377x\242\320\377t\237\316" \
-  "\377q\234\313\377m\232\311\377i\230\307\377e\225\304\377`\222\302\377" \
-  "]\217\300\377Y\215\276\377T\212\273\377K\204\267\377X\216\274\377\220" \
-  "\265\323\377\345\356\365\377\202\377\377\377\377\7\374\375\376\377\321" \
-  "\340\354\377\214\264\317\3770x\250\377\34l\240\377^\230\274\377\305\332" \
-  "\347\377\204\377\377\377\377\5\306\334\350\377t\250\304\377\37r\237\377" \
-  "D\210\255\377\301\327\343\377\204\377\377\377\377\4\377\377\377\213\377" \
-  "\377\377\15\0\0\0\0\272\315\337\0\232\0\0\0\0\1\34\34\34\0\223\0\0\0" \
-  "\0\1\33\33\33\0\377\0\0\0\0\377\0\0\0\0\355\0\0\0\0\23\252\304\336\0" \
-  "\0\0\0\0\301\322\346\14s\237\311\255c\223\304\377i\227\307\377l\232\311" \
-  "\377q\234\313\377t\237\315\377y\242\320\377|\245\322\377\200\247\324" \
-  "\377\203\251\326\377\206\253\330\377\210\255\331\377\213\256\331\377" \
-  "\215\257\333\377\217\260\333\377\217\261\334\377\202\220\262\334\377" \
-  "\26\220\261\334\377\217\260\334\377\216\260\333\377\214\257\332\377\212" \
-  "\255\332\377\210\254\330\377\205\252\327\377\202\250\325\377~\246\324" \
-  "\377{\244\322\377x\242\320\377t\236\315\377o\234\313\377k\231\310\377" \
-  "g\226\306\377c\224\304\377_\221\301\377Y\215\276\377S\212\273\377q\236" \
-  "\307\377\271\317\343\377\372\374\375\377\202\377\377\377\377\7\333\347" \
-  "\360\377\234\276\326\377M\211\265\377\35j\240\377\77\201\257\377\215" \
-  "\266\320\377\361\366\371\377\203\377\377\377\377\6\324\345\356\377\206" \
-  "\266\316\377&z\245\377\16i\231\377~\256\310\377\353\362\367\377\204\377" \
-  "\377\377\377\6\354\363\366\377\226\270\315\367u\242\275p\267\315\335" \
-  "\6\0\0\0\0\377\377\377\0\232\0\0\0\0\2\33\33\35\3\37\37\35\12\217\37" \
-  "\37\35\13\1\36\36\35\6\377\0\0\0\0\377\0\0\0\0\357\0\0\0\0)\77{\263\0" \
-  "\0\0\0\0x\242\313\204e\226\304\377f\226\306\377k\231\310\377n\234\313" \
-  "\377s\236\315\377w\241\317\377{\244\322\377\200\247\324\377\204\251\326" \
-  "\377\207\253\330\377\212\255\331\377\214\257\332\377\217\261\333\377" \
-  "\221\262\334\377\223\263\335\377\224\264\336\377\225\265\336\377\225" \
-  "\266\337\377\224\265\336\377\223\264\335\377\222\263\335\377\220\262" \
-  "\334\377\216\260\333\377\214\256\332\377\211\255\331\377\205\252\327" \
-  "\377\203\251\325\377~\246\323\377{\244\321\377v\241\317\377r\236\314" \
-  "\377n\233\312\377j\230\307\377f\225\305\377]\217\301\377a\222\301\377" \
-  "\222\265\324\377\333\346\361\377\202\377\377\377\377\7\347\357\365\377" \
-  "\253\307\335\377f\231\300\3771u\252\377)q\246\377e\232\277\377\273\323" \
-  "\343\377\203\377\377\377\377\6\350\361\366\377\231\300\326\377=\213\262" \
-  "\377\0^\223\377=\210\257\377\262\317\337\377\204\377\377\377\377\6\373" \
-  "\374\375\377\262\314\334\377^\224\264\377V\215\257\377\263\314\333\347" \
-  "\370\372\374D\202\0\0\0\0\1\377\377\377\0\231\0\0\0\0\3\34\34\33)\35" \
-  "\35\33\220\35\35\33\231\215\35\35\33\230\3\35\35\33\240\35\35\33U\32" \
-  "\32#\2\377\0\0\0\0\377\0\0\0\0\355\0\0\0\0""2\213\257\322\0\0\0\0\0\206" \
-  "\254\317Lf\226\304\366d\224\304\377i\230\307\377m\232\311\377q\235\314" \
-  "\377v\240\316\377z\243\321\377~\246\323\377\202\251\325\377\206\253\330" \
-  "\377\211\255\331\377\215\257\332\377\220\261\334\377\223\263\335\377" \
-  "\225\265\336\377\227\266\337\377\230\267\337\377\231\270\340\377\231" \
-  "\270\341\377\230\267\340\377\230\267\337\377\227\265\336\377\224\264" \
-  "\336\377\222\262\335\377\217\260\334\377\214\257\333\377\211\255\331" \
-  "\377\205\252\327\377\201\250\325\377}\246\323\377y\242\320\377t\240\316" \
-  "\377q\235\313\377k\231\311\377c\223\304\377u\240\312\377\265\315\342" \
-  "\377\362\366\372\377\377\377\377\377\363\367\372\377\271\317\342\377" \
-  "{\246\312\377F\202\264\3771u\253\377C\201\262\377\216\263\321\377\341" \
-  "\353\363\377\202\377\377\377\377\7\372\374\375\377\254\312\334\377]\231" \
-  "\275\377\15i\234\377\3g\233\377u\254\310\377\330\347\357\377\204\377" \
-  "\377\377\377\12\306\332\346\377d\232\271\3771x\241\377k\235\273\377\331" \
-  "\346\356\377\377\377\377\377\377\377\377\272\376\377\377\35\0\0\0\0\377" \
-  "\377\377\0\231\0\0\0\0\2\34\34\33H\35\35\33\375\217\35\35\33\377\2\35" \
-  "\35\33\225\35\35%\4\365\0\0\0\0\1\34\34\33\0\223\0\0\0\0\1\34\34\34\0" \
-  "\377\0\0\0\0\341\0\0\0\0\25\266\333\333\0\0\0\0\0\271\316\344\21j\230" \
-  "\305\327`\222\302\377f\226\305\377k\231\310\377o\234\313\377s\237\315" \
-  "\377x\242\317\377}\245\322\377\200\247\324\377\204\252\327\377\210\254" \
-  "\331\377\214\257\332\377\220\261\334\377\223\263\335\377\226\265\337" \
-  "\377\230\267\337\377\233\271\340\377\234\272\341\377\202\235\272\341" \
-  "\377\21\234\272\341\377\234\271\341\377\232\270\340\377\230\266\337\377" \
-  "\225\264\336\377\222\263\335\377\217\260\334\377\213\257\332\377\207" \
-  "\254\331\377\204\251\326\377\200\247\324\377{\244\321\377v\241\317\377" \
-  "p\234\314\377l\231\311\377\222\264\326\377\326\343\357\377\202\377\377" \
-  "\377\377\10\310\332\352\377\213\260\321\377X\215\274\377B\200\263\377" \
-  "8y\256\377e\230\300\377\266\316\341\377\371\373\375\377\202\377\377\377" \
-  "\377\7\302\327\345\377q\243\304\377-y\250\377\4`\227\377:\204\256\377" \
-  "\247\312\334\377\370\373\374\377\203\377\377\377\377\6\335\351\360\377" \
-  "y\252\305\377#q\235\377-v\240\377\237\300\323\377\365\370\373\377\203" \
-  "\377\377\377\377\4\377\377\377|\377\377\377\10\0\0\0\0N\205\252\0\230" \
-  "\0\0\0\0\2\34\34\33E\35\35\33\361\217\35\35\33\377\2\35\35\33\216\35" \
-  "\35%\3\366\0\0\0\0\3\34\34\33\11\35\35\33""4\35\35\33Q\216\35\35\33N" \
-  "\2\35\35\33J\34\34\35\4\377\0\0\0\0\342\0\0\0\0""0p\232\310\0\0\0\0\0" \
-  "s\240\310\225_\221\301\377b\224\304\377g\227\306\377l\232\311\377q\235" \
-  "\314\377u\240\316\377z\243\321\377~\246\323\377\202\251\326\377\206\253" \
-  "\327\377\213\256\331\377\217\261\333\377\223\263\335\377\226\265\337" \
-  "\377\231\267\340\377\234\271\341\377\236\273\342\377\240\274\343\377" \
-  "\241\275\344\377\242\275\344\377\242\275\343\377\240\274\343\377\235" \
-  "\273\342\377\233\271\341\377\230\266\337\377\225\265\336\377\221\262" \
-  "\335\377\216\257\333\377\212\256\332\377\206\253\327\377\202\250\325" \
-  "\377}\245\322\377u\237\317\377z\243\317\377\265\314\344\377\360\365\372" \
-  "\377\377\377\377\377\332\345\361\377\230\270\327\377i\230\304\377P\210" \
-  "\272\377H\203\266\377H\204\266\377\214\262\321\377\330\345\357\377\202" \
-  "\377\377\377\377\7\326\344\356\377\203\255\313\377F\207\261\377\31j\237" \
-  "\377\25i\235\377v\250\306\377\321\342\354\377\203\377\377\377\377\6\360" \
-  "\366\371\377\212\266\315\3770|\246\377\10a\224\377X\223\265\377\320\340" \
-  "\352\377\205\377\377\377\377\3\256\307\327\357T\211\254F\0\0\0\1\231" \
-  "\0\0\0\0\2\34\34\33E\35\35\33\361\217\35\35\33\377\2\35\35\33\216\35" \
-  "\35%\3\366\0\0\0\0\3\34\34\33\31\35\35\33\225\35\35\33\347\216\35\35" \
-  "\33\336\2\35\35\33\324\32\32\33\15\377\0\0\0\0\341\0\0\0\0\26\252\304" \
-  "\336\0\0\0\0\0\213\257\3216a\223\301\355_\222\302\377d\225\305\377h\230" \
-  "\307\377m\232\311\377r\236\314\377w\241\317\377|\244\322\377\200\247" \
-  "\324\377\204\252\327\377\211\255\331\377\215\257\332\377\221\263\334" \
-  "\377\225\265\336\377\231\267\340\377\234\271\341\377\237\273\343\377" \
-  "\242\275\344\377\244\277\345\377\203\245\277\345\377\40\244\277\345\377" \
-  "\241\275\344\377\236\273\342\377\233\271\341\377\230\266\337\377\223" \
-  "\264\336\377\220\261\334\377\214\257\333\377\207\254\331\377\203\251" \
-  "\326\377|\244\322\377\223\264\331\377\326\343\361\377\376\376\376\377" \
-  "\353\362\367\377\247\303\336\377w\242\313\377]\220\300\377V\213\275\377" \
-  "L\204\270\377d\226\301\377\262\314\340\377\363\367\372\377\377\377\377" \
-  "\377\352\361\366\377\225\270\324\377X\220\271\377-t\250\377\35k\240\377" \
-  "9\177\255\377\252\310\333\377\355\364\370\377\202\377\377\377\377\7\376" \
-  "\377\377\377\235\304\327\377>\211\257\377\6d\226\377\23j\232\377\226" \
-  "\275\321\377\354\363\366\377\204\377\377\377\377\7\325\343\353\377a\224" \
-  "\263\377;y\240\377\234\273\317\260\337\351\360\22\0\0\0\0\377\377\377" \
-  "\0\227\0\0\0\0\2\34\34\33E\35\35\33\361\217\35\35\33\377\2\35\35\33\216" \
-  "\35\35%\3\366\0\0\0\0\2\34\34\33\36\35\35\33\256\217\35\35\33\377\2\35" \
-  "\35\33\367\31\31\33\20\377\0\0\0\0\341\0\0\0\0\24\0\0/\0\0\0\0\0k\232" \
-  "\304\272\\\217\277\376`\222\302\377d\225\305\377i\230\307\377n\233\312" \
-  "\377s\236\315\377x\242\320\377~\244\321\377\202\250\325\377\206\253\327" \
-  "\377\212\256\332\377\217\260\333\377\223\264\335\377\226\266\337\377" \
-  "\232\270\341\377\236\273\342\377\242\275\344\377\207\245\277\345\377" \
-  "\35\241\275\343\377\236\273\342\377\232\270\341\377\226\265\336\377\222" \
-  "\263\335\377\215\260\333\377\207\254\330\377\203\251\326\377\262\312" \
-  "\345\377\361\365\372\377\367\372\374\377\271\317\346\377\204\252\322" \
-  "\377k\231\310\377`\221\303\377\\\217\300\377S\211\274\377\205\254\317" \
-  "\377\325\342\356\377\377\377\377\377\375\376\376\377\255\311\336\377" \
-  "f\231\300\377>~\260\377/u\250\377#l\242\377k\235\301\377\321\341\354" \
-  "\377\376\376\377\377\202\377\377\377\377\7\272\325\343\377I\223\267\377" \
-  "\22o\237\377\0\\\221\377B\211\257\377\310\334\347\377\373\375\375\377" \
-  "\203\377\377\377\377\10\351\361\365\377}\250\301\377\36h\224\377=|\242" \
-  "\377\261\313\332\377\363\367\371\377\377\377\377K\377\377\377\2\230\0" \
-  "\0\0\0\2\34\34\33E\35\35\33\361\217\35\35\33\377\2\35\35\33\216\35\35" \
-  "%\3\366\0\0\0\0\2\34\34\33\35\35\35\33\253\217\35\35\33\377\2\35\35\33" \
-  "\363\31\31\33\20\377\0\0\0\0\340\0\0\0\0\25\246\277\331\0\0\0\0\0\177" \
-  "\250\315G\\\220\277\357\\\217\300\377`\223\302\377e\226\305\377j\231" \
-  "\310\377o\234\313\377t\237\315\377y\242\320\377~\245\322\377\202\250" \
-  "\325\377\207\254\330\377\213\257\332\377\220\261\334\377\224\264\336" \
-  "\377\230\267\340\377\234\272\341\377\240\274\343\377\244\276\345\377" \
-  "\207\245\277\345\377\33\244\276\344\377\237\274\343\377\233\271\341\377" \
-  "\227\266\337\377\223\264\335\377\214\256\333\377\223\263\334\377\326" \
-  "\343\362\377\366\371\374\377\312\333\355\377\220\263\330\377x\242\317" \
-  "\377k\231\311\377i\227\307\377_\221\302\377e\225\304\377\253\305\336" \
-  "\377\362\366\372\377\377\377\377\377\310\332\351\377w\243\310\377L\210" \
-  "\267\377<|\257\3772w\253\3778{\254\377\243\302\330\377\350\360\365\377" \
-  "\202\377\377\377\377\7\326\346\356\377e\236\300\377\"x\246\377\0c\227" \
-  "\377\2f\231\377\201\262\313\377\351\361\365\377\203\377\377\377\377\6" \
-  "\370\373\374\377\225\272\317\377.u\237\377\12[\213\377l\234\271\377\331" \
-  "\345\354\377\202\377\377\377\377\4\377\377\377\275\377\377\377\21\0\0" \
-  "\0\0\377\377\377\0\226\0\0\0\0\2\34\34\33E\35\35\33\361\217\35\35\33" \
-  "\377\2\35\35\33\216\35\35%\3\366\0\0\0\0\2\34\34\33\35\35\35\33\253\217" \
-  "\35\35\33\377\2\35\35\33\363\31\31\33\20\377\0\0\0\0\340\0\0\0\0\24\"" \
-  "r\256\0\0\0\0\0f\227\302\274Y\216\276\376\\\217\300\377a\223\303\377" \
-  "f\226\305\377j\231\310\377o\234\313\377t\237\315\377z\242\320\377~\246" \
-  "\322\377\203\251\326\377\207\254\331\377\214\257\333\377\220\262\334" \
-  "\377\224\264\336\377\231\270\340\377\235\272\342\377\241\275\344\377" \
-  "\210\245\277\345\377#\244\276\345\377\240\274\343\377\234\272\341\377" \
-  "\227\267\340\377\220\261\334\377\257\307\345\377\356\364\372\377\330" \
-  "\344\363\377\237\274\337\377\204\252\325\377w\241\317\377r\235\315\377" \
-  "n\232\312\377c\224\305\377}\246\316\377\320\337\355\377\377\377\377\377" \
-  "\337\351\363\377\212\257\320\377Z\217\275\377H\203\265\377@\200\262\377" \
-  "3v\253\377^\224\275\377\314\336\352\377\371\373\374\377\377\377\377\377" \
-  "\360\365\371\377\200\254\312\3772}\252\377\26m\237\377\2c\230\377%|\250" \
-  "\377\276\330\345\377\367\372\373\377\203\377\377\377\377\6\261\315\335" \
-  "\377=\201\250\377\0X\213\377\35j\227\377\242\301\323\377\364\370\372" \
-  "\377\204\377\377\377\377\2\377\377\377F\377\377\377\2\227\0\0\0\0\2\34" \
-  "\34\33E\35\35\33\361\217\35\35\33\377\2\35\35\33\216\35\35%\3\366\0\0" \
-  "\0\0\2\34\34\33\35\35\35\33\253\217\35\35\33\377\2\35\35\33\363\31\31" \
-  "\33\20\377\0\0\0\0\341\0\0\0\0\23\206\256\320;W\215\274\350W\215\276" \
-  "\377\\\220\300\377a\223\303\377f\226\305\377j\231\310\377p\234\313\377" \
-  "t\237\316\377z\242\320\377~\246\322\377\204\252\326\377\210\254\331\377" \
-  "\214\257\333\377\220\262\334\377\224\265\336\377\231\270\340\377\235" \
-  "\272\342\377\242\275\344\377\210\245\277\345\377\"\244\276\345\377\240" \
-  "\275\343\377\234\271\341\377\230\267\340\377\321\336\360\377\342\354" \
-  "\366\377\256\307\345\377\216\261\332\377\202\250\325\377|\245\322\377" \
-  "y\242\317\377r\235\315\377n\233\313\377\241\276\334\377\363\366\372\377" \
-  "\356\363\371\377\241\276\333\377g\227\303\377T\212\273\377L\205\267\377" \
-  "E\201\264\377;|\260\377\223\267\323\377\347\357\365\377\377\377\377\377" \
-  "\376\377\377\377\234\276\326\377B\203\257\377%s\245\377\27k\237\377\15" \
-  "g\233\377j\243\302\377\346\360\365\377\376\377\377\377\202\377\377\377" \
-  "\377\7\313\336\351\377M\216\262\377\11a\223\377\0V\212\377N\213\257\377" \
-  "\322\341\352\377\375\376\376\377\205\377\377\377\377\4\351\360\364\271" \
-  "\356\364\366\15\0\0\0\0g\226\267\0\225\0\0\0\0\2\34\34\33E\35\35\33\361" \
-  "\217\35\35\33\377\2\35\35\33\216\35\35%\3\206\0\0\0\0\1\36\36\33\0\222" \
-  "\0\0\0\0\1\37\37\31\0\211\0\0\0\0\1\36\36\32\0\223\0\0\0\0\1\34\34\32" \
-  "\0\215\0\0\0\0\1\34\34\32\0\222\0\0\0\0\1\33\33\32\0\203\0\0\0\0\1\33" \
-  "\33\33\0\215\0\0\0\0\1\35\35\34\0\204\0\0\0\0\1\36\36\33\0\206\0\0\0" \
-  "\0\2\34\34\33\32\35\35\33\252\217\35\35\33\377\2\35\35\33\363\30\30\33" \
-  "\14\207\0\0\0\0\3\35\35\32\0\32\32\32\0\35\35\32\0\222\0\0\0\0\1\35\35" \
-  "\33\0\203\0\0\0\0\2$$$\0\27\27\26\0\214\0\0\0\0\1\24\24\24\0\223\0\0" \
-  "\0\0\1\36\36\36\0\222\0\0\0\0\1))&\0\215\0\0\0\0\1\35\35\32\0\226\0\0" \
-  "\0\0\1\31\31\31\0\215\0\0\0\0\1$$#\0\325\0\0\0\0\26\225\266\323\0\0\0" \
-  "\0\0j\232\303\237U\214\274\372W\214\276\377]\220\300\377a\223\302\377" \
-  "f\226\305\377j\231\310\377o\234\313\377t\237\315\377y\242\320\377~\246" \
-  "\322\377\203\251\326\377\207\254\331\377\214\257\332\377\220\262\334" \
-  "\377\225\264\336\377\231\267\340\377\235\272\342\377\241\275\344\377" \
-  "\244\277\345\377\207\245\277\345\377\40\244\276\344\377\235\272\342\377" \
-  "\256\306\347\377\340\351\365\377\273\320\351\377\225\265\336\377\214" \
-  "\257\332\377\206\253\330\377\202\250\326\377}\245\322\377t\237\316\377" \
-  "}\245\321\377\311\332\354\377\367\372\374\377\271\317\345\377s\237\311" \
-  "\377\\\220\300\377U\213\275\377R\211\272\377G\202\265\377X\216\273\377" \
-  "\300\324\346\377\372\374\375\377\377\377\377\377\272\321\342\377Q\214" \
-  "\267\3773x\251\377'q\244\377\33m\241\377&t\244\377\257\315\336\377\370" \
-  "\373\374\377\202\377\377\377\377\7\345\357\364\377b\235\275\377\13f\227" \
-  "\377\0[\220\377\13b\223\377\206\260\311\377\363\367\371\377\205\377\377" \
-  "\377\377\5\361\365\371\377|\244\277\377\32b\217\377E\177\2458\343\353" \
-  "\367\1\226\0\0\0\0\2\34\34\33E\35\35\33\361\217\35\35\33\377\2\35\35" \
-  "\33\216\35\35%\3\205\0\0\0\0\3\34\34\31\0\0\0\0\0\36\36\33\34\216\36" \
-  "\36\34-\3\36\36\34""1\36\36\34\34\40\40\25\2\207\0\0\0\0\1\33\33\33\0" \
-  "\204\0\0\0\0\10\40\40\31\7\36\36\33""2\35\35\33T\35\35\33o\35\35\33\205" \
-  "\35\35\33\224\35\35\33\240\35\35\33\246\202\35\35\33\250\7\35\35\33\244" \
-  "\35\35\33\231\35\35\33\212\35\35\33v\35\35\33\\\35\35\33=\34\34\32\24" \
-  "\205\0\0\0\0\1\35\35\33\0\212\0\0\0\0\2\34\34\32\25\34\34\32""6\216\34" \
-  "\34\32""5\5\34\34\32""4\32\32\32\33\0\0\0\0\32\32\32\0CC$\0\203\0\0\0" \
-  "\0\13\35\35\33\33\36\36\33Q\35\35\33u\35\35\33\221\35\35\33\237\35\35" \
-  "\33\246\35\35\33\247\35\35\33\233\35\35\33\203\35\35\33\\\35\35\34\"" \
-  "\207\0\0\0\0\3\40\40\34\1\35\35\33\24\34\34\32""8\202\34\34\32""5\3\34" \
-  "\34\32""2\34\34\32L\35\35\33\274\217\35\35\33\377\3\35\35\33\366\34\34" \
-  "\33A\34\34\32""4\203\34\34\32""5\3\34\34\32""6\34\34\32""2\35\35\32\27" \
-  "\203\0\0\0\0\2\34\34\32!\34\34\32""7\215\34\34\32""5\3\34\34\32""6\34" \
-  "\34\32""1\35\35\33\21\202\0\0\0\0\1\36\36\34\0\203\0\0\0\0\13\33\33\34" \
-  "\14\35\35\33C\35\35\33o\35\35\33\216\35\35\33\237\35\35\33\247\35\35" \
-  "\33\246\35\35\33\231\35\35\33\201\34\34\33]\35\35\32)\203\0\0\0\0\1\36" \
-  "\36\34\0\215\0\0\0\0\1\33\33\33\0\205\0\0\0\0\7\36\36\34%\35\35\33J\35" \
-  "\35\33f\35\35\33\177\35\35\33\217\35\35\33\236\35\35\33\245\202\35\35" \
-  "\33\250\7\35\35\33\246\35\35\33\235\35\35\33\217\35\35\33~\35\35\33g" \
-  "\36\36\33I\36\36\33#\205\0\0\0\0\1\36\36\34\0\212\0\0\0\0\3\35\35\32" \
-  "\7\35\35\32/\34\34\32""6\215\34\34\32""5\4\34\34\32""6\35\35\32(\35\35" \
-  "\32\1\40\40\40\0\204\0\0\0\0\14\30\30\27\10\35\35\32A\35\35\33k\35\35" \
-  "\33\210\35\35\33\233\35\35\33\244\35\35\33\250\35\35\33\241\35\35\33" \
-  "\215\34\34\33k\34\34\34""7\20\20\31\1\203\0\0\0\0\1\35\35\31\0\323\0" \
-  "\0\0\0\25\340\350\357\23T\213\272\327R\212\273\377W\215\275\377\\\217" \
-  "\277\377a\222\302\377e\226\305\377j\230\310\377o\233\312\377t\236\315" \
-  "\377y\242\320\377~\245\322\377\202\251\326\377\206\254\330\377\213\256" \
-  "\332\377\217\260\334\377\224\264\335\377\230\266\337\377\234\271\341" \
-  "\377\240\274\343\377\243\276\345\377\207\245\277\345\377'\241\274\343" \
-  "\377\304\326\355\377\306\327\357\377\234\272\340\377\225\264\335\377" \
-  "\215\260\333\377\212\256\332\377\206\253\327\377\201\247\324\377{\244" \
-  "\321\377\230\270\333\377\347\356\366\377\322\340\357\377\205\253\321" \
-  "\377e\225\305\377_\221\301\377Z\216\276\377U\213\274\377J\204\267\377" \
-  "\202\252\315\377\343\354\364\377\377\377\377\377\323\341\355\377h\232" \
-  "\301\377<~\256\3771v\250\377+s\246\377\40n\242\377W\222\271\377\341\354" \
-  "\363\377\375\376\376\377\377\377\377\377\363\370\372\377{\257\311\377" \
-  "\17m\234\377\2a\224\377\0[\217\377.z\244\377\277\326\343\377\205\377" \
-  "\377\377\377\7\363\367\371\377\206\254\304\377\34c\221\377\3R\205\377" \
-  "\0O\203\377\37e\222\224+m\231\10\226\0\0\0\0\2\34\34\33E\35\35\33\361" \
-  "\217\35\35\33\377\2\35\35\33\216\35\35%\3\206\0\0\0\0\2\30\30\20\4\35" \
-  "\35\33\332\215\35\35\33\365\3\35\35\33\367\35\35\33\357\35\35\33^\206" \
-  "\0\0\0\0\1$$\"\0\202\0\0\0\0\12\31\31\33\13\35\35\33U\35\35\33\234\35" \
-  "\35\33\325\35\35\33\364\35\35\33\365\35\35\33\367\35\35\33\371\35\35" \
-  "\33\372\35\35\33\373\205\35\35\33\374\12\35\35\33\373\35\35\33\372\35" \
-  "\35\33\371\35\35\33\370\35\35\33\366\35\35\33\365\35\35\33\343\35\35" \
-  "\33\256\35\35\32m\35\35\33\36\203\0\0\0\0\1!!\26\0\210\0\0\0\0\3\35\35" \
-  "\33`\35\35\33\372\35\35\33\367\215\35\35\33\366\2\35\35\33\360\35\35" \
-  "\33|\203\0\0\0\0\3\35\35\33\27\36\36\33\200\35\35\33\325\202\35\35\33" \
-  "\367\2\35\35\33\371\35\35\33\373\203\35\35\33\374\11\35\35\33\373\35" \
-  "\35\33\372\35\35\33\370\35\35\33\367\35\35\33\323\35\35\33m''\26\3\0" \
-  "\0\0\0\34\34\33\0\202\0\0\0\0\3\34\34\32\5\34\34\32\\\35\35\33\377\202" \
-  "\35\35\33\366\3\35\35\33\365\35\35\33\367\35\35\33\374\220\35\35\33\377" \
-  "\205\35\35\33\366\3\35\35\33\370\35\35\33\351\35\35\33l\203\0\0\0\0\2" \
-  "\35\35\33\226\35\35\33\377\215\35\35\33\366\15\35\35\33\367\35\35\33" \
-  "\340\35\35\33N\0\0\0\0\33\33!\0\0\0\0\0$$\"\3\35\35\33H\35\35\33\266" \
-  "\35\35\33\357\35\35\33\367\35\35\33\371\35\35\33\373\203\35\35\33\374" \
-  "\11\35\35\33\373\35\35\33\372\35\35\33\370\35\35\33\365\35\35\33\336" \
-  "\35\35\33\201\37\37\35\20\0\0\0\0\35\35\33\0\212\0\0\0\0\1\35\35\32\0" \
-  "\203\0\0\0\0\11\35\35\34<\35\35\33\206\35\35\33\303\35\35\33\357\35\35" \
-  "\33\365\35\35\33\367\35\35\33\370\35\35\33\372\35\35\33\373\205\35\35" \
-  "\33\374\202\35\35\33\373\10\35\35\33\372\35\35\33\370\35\35\33\367\35" \
-  "\35\33\366\35\35\33\355\35\35\33\303\35\35\34\204\36\36\34""8\204\0\0" \
-  "\0\0\1\34\34\34\0\207\0\0\0\0\3\35\35\33\"\35\35\33\332\35\35\33\371" \
-  "\215\35\35\33\366\3\35\35\33\371\35\35\33\272\35\35\33\4\202\0\0\0\0" \
-  "\10;;A\0\35\35\32]\35\35\33\274\35\35\33\365\35\35\33\366\35\35\33\371" \
-  "\35\35\33\372\35\35\33\373\203\35\35\33\374\6\35\35\33\373\35\35\33\371" \
-  "\35\35\33\370\35\35\33\346\35\35\33\224\35\35\32\35\202\0\0\0\0\1\35" \
-  "\35\33\0\322\0\0\0\0\26h\230\302\\P\211\271\353Q\210\271\377V\215\275" \
-  "\377[\217\277\377`\222\302\377d\225\305\377i\230\307\377m\233\312\377" \
-  "s\236\315\377x\241\317\377}\245\322\377\201\250\325\377\206\253\330\377" \
-  "\211\256\332\377\217\260\333\377\222\263\335\377\226\266\337\377\233" \
-  "\270\340\377\236\273\342\377\241\275\344\377\244\276\345\377\205\245" \
-  "\277\345\377'\252\303\346\377\276\321\354\377\245\300\344\377\232\271" \
-  "\340\377\225\265\336\377\222\262\334\377\215\260\333\377\211\255\331" \
-  "\377\204\251\326\377\204\252\326\377\271\316\347\377\343\354\365\377" \
-  "\231\271\332\377l\231\311\377h\227\307\377c\224\304\377_\221\301\377" \
-  "X\215\276\377Z\216\276\377\256\310\337\377\374\375\376\377\347\357\365" \
-  "\377\204\255\315\377E\203\263\3778{\256\3774x\252\377.u\250\377*r\245" \
-  "\377\226\273\323\377\373\374\376\377\377\377\377\377\376\376\377\377" \
-  "\237\305\330\377\32v\243\377\0e\230\377\0b\225\377\5c\225\377_\232\273" \
-  "\377\353\362\367\377\204\377\377\377\377\4\371\373\375\377\226\270\315" \
-  "\377\40g\223\377\1Q\203\377\202\0P\203\377\5\0O\202\377\33c\221\364\34" \
-  "d\221\16\0\0\0\0g\226\264\0\224\0\0\0\0\2\34\34\33E\35\35\33\361\217" \
-  "\35\35\33\377\2\35\35\33\216\35\35%\3\204\0\0\0\0\4\35\35\32\0\0\0\0" \
-  "\0\35\35\33n\35\35\33\366\216\35\35\33\377\2\35\35\33\254\35\35\31\30" \
-  "\204\0\0\0\0\1\35\35\32\0\202\0\0\0\0\5\35\35\33;\35\35\33\245\35\35" \
-  "\33\364\35\35\33\373\35\35\33\375\223\35\35\33\377\1\35\35\33\376\202" \
-  "\35\35\33\374\5\35\35\33\312\34\34\33]\377\377\0\0\0\0\0\0\35\35\33\0" \
-  "\207\0\0\0\0\1\35\35\33d\217\35\35\33\377\7\35\35\33\371\35\35\33\201" \
-  "\0\0\0\0\35\35\33\11\35\35\33t\35\35\33\361\35\35\33\376\214\35\35\33" \
-  "\377\11\35\35\33\376\35\35\33\375\35\35\33\334\34\34\33""1\0\0\0\0\35" \
-  "\35\34\0\0\0\0\0\33\33\31\5\34\34\32`\234\35\35\33\377\2\35\35\33\362" \
-  "\35\35\33p\203\0\0\0\0\1\35\35\33\234\217\35\35\33\377\2\35\35\33\351" \
-  "\35\35\33Q\202\0\0\0\0\4\35\35\33""2\35\35\33\277\35\35\33\377\35\35" \
-  "\33\376\214\35\35\33\377\5\35\35\33\374\35\35\33\354\35\35\33Z\0\0\0" \
-  "\0\35\35\33\0\207\0\0\0\0\1\34\34\33\0\202\0\0\0\0\6\35\35\31\35\35\35" \
-  "\33\177\35\35\33\341\35\35\33\373\35\35\33\375\35\35\33\376\222\35\35" \
-  "\33\377\6\35\35\33\376\35\35\33\375\35\35\33\376\35\35\33\340\35\35\33" \
-  "\203\34\34\34\23\202\0\0\0\0\2\33\33\27\0\40\40\40\0\205\0\0\0\0\2\35" \
-  "\35\33#\35\35\33\343\217\35\35\33\377\5\35\35\33\301\35\35\33\4\0\0\0" \
-  "\0\35\35\33@\35\35\33\332\202\35\35\33\376\215\35\35\33\377\5\35\35\33" \
-  "\364\35\35\33f\35\35\33\6\0\0\0\0\36\36\33\0\321\0\0\0\0@a\224\277\260" \
-  "P\211\271\377Q\210\271\377V\214\275\377Z\217\277\377_\221\301\377d\224" \
-  "\304\377h\227\307\377m\232\311\377q\235\314\377w\240\317\377{\244\321" \
-  "\377\200\247\324\377\204\252\327\377\210\255\331\377\214\257\333\377" \
-  "\220\262\334\377\224\264\336\377\230\267\340\377\234\271\340\377\237" \
-  "\273\342\377\241\274\344\377\243\276\345\377\244\277\345\377\245\277" \
-  "\345\377\244\276\345\377\245\277\344\377\247\301\345\377\236\273\342" \
-  "\377\232\270\340\377\227\266\337\377\223\263\335\377\220\261\334\377" \
-  "\214\257\332\377\207\254\330\377\222\263\333\377\317\336\356\377\263" \
-  "\312\345\377v\241\317\377o\234\313\377l\232\311\377g\227\306\377c\224" \
-  "\303\377Z\216\277\377x\242\312\377\327\343\360\377\366\371\373\377\243" \
-  "\301\332\377R\213\272\377@\177\261\377=}\257\3779z\254\3771v\251\377" \
-  "K\210\264\377\321\341\354\377\376\377\377\377\377\377\377\377\275\325" \
-  "\344\3779\203\256\377\4g\233\377\0g\232\377\0d\227\377\30p\237\377\237" \
-  "\303\327\377\204\377\377\377\377\6\367\372\374\377\242\301\324\377%m" \
-  "\230\377\0Q\204\377\0R\204\377\0Q\203\377\203\0P\203\377\3\0O\202\377" \
-  "N\205\250I\203\251\301\2\225\0\0\0\0\2\34\34\33E\35\35\33\361\217\35" \
-  "\35\33\377\2\35\35\33\216\35\35%\3\203\0\0\0\0\4\37\37\32\0\0\0\0\0\35" \
-  "\35\17\1\35\35\33\330\216\35\35\33\377\4\35\35\33\352\35\35\33X\0\0\0" \
-  "\0\35\35\32\0\204\0\0\0\0\3\35\35\32$\35\35\33\266\35\35\33\374\234\35" \
-  "\35\33\377\2\35\35\33\336\35\35\33M\203\0\0\0\0\1\35\35\35\0\204\0\0" \
-  "\0\0\1\35\35\33d\217\35\35\33\377\4\35\35\33\371\35\35\33\200\35\35\33" \
-  "\7\35\35\33\243\222\35\35\33\377\2\35\35\33\366\35\35\34<\202\0\0\0\0" \
-  "\2\34\34\32\5\34\34\32`\234\35\35\33\377\2\35\35\33\361\35\35\33p\203" \
-  "\0\0\0\0\1\35\35\33\233\217\35\35\33\377\5\35\35\33\351\35\35\33P\0\0" \
-  "\0\0\35\35\33X\35\35\33\357\221\35\35\33\377\2\35\35\33\366\35\35\33" \
-  "n\206\0\0\0\0\1\35\35\33\0\202\0\0\0\0\3\33\33\33\15\35\35\33\202\35" \
-  "\35\33\357\234\35\35\33\377\3\35\35\33\366\35\35\33|\36\36\34\10\202" \
-  "\0\0\0\0\1\36\36\33\0\204\0\0\0\0\2\35\35\33#\35\35\33\343\217\35\35" \
-  "\33\377\4\35\35\33\301\35\35\33\2\35\35\33f\35\35\33\376\222\35\35\33" \
-  "\377\2\36\36\33u\36\36\33\10\321\0\0\0\0@\355\361\366\17L\206\267\320" \
-  "K\205\266\377O\210\271\377T\213\274\377X\216\276\377^\220\301\377b\224" \
-  "\303\377g\226\306\377k\231\310\377p\234\313\377t\237\315\377y\242\320" \
-  "\377~\246\323\377\202\251\326\377\207\254\330\377\212\256\331\377\216" \
-  "\260\333\377\222\263\334\377\225\265\336\377\230\267\340\377\233\271" \
-  "\340\377\235\272\341\377\237\273\343\377\237\274\343\377\241\274\343" \
-  "\377\236\272\342\377\275\320\354\377\244\277\344\377\232\270\340\377" \
-  "\227\266\337\377\224\264\336\377\221\262\334\377\215\257\332\377\213" \
-  "\256\331\377\245\301\341\377\300\323\351\377\205\253\325\377v\241\317" \
-  "\377t\236\315\377o\234\312\377j\231\310\377e\226\305\377d\224\304\377" \
-  "\233\273\330\377\354\362\367\377\301\325\346\377c\226\301\377F\202\265" \
-  "\377E\202\264\377@\200\262\377<}\257\3775y\253\377\200\253\312\377\364" \
-  "\370\373\377\376\376\377\377\331\346\357\377Y\225\272\377\22i\235\377" \
-  "\16i\234\377\6h\233\377\4i\233\377=\211\260\377\335\352\361\377\203\377" \
-  "\377\377\377\7\370\373\374\377\260\314\334\377.u\240\377\0R\207\377\0" \
-  "T\207\377\0S\205\377\0R\204\377\204\0P\203\377\3\0O\203\377!g\223\217" \
-  ")l\227\5\225\0\0\0\0\2\34\34\33E\35\35\33\361\217\35\35\33\377\2\35\35" \
-  "\33\216\35\35%\3\205\0\0\0\0\2\35\35\33h\35\35\33\363\216\35\35\33\377" \
-  "\2\35\35\33\240\40\40\30\10\202\0\0\0\0\1''$\0\202\0\0\0\0\2\35\35\33" \
-  "`\35\35\33\356\240\35\35\33\377\2\35\35\33\232\27\27\31\4\206\0\0\0\0" \
-  "\1\35\35\33d\217\35\35\33\377\3\35\35\33\371\35\35\33\213\35\35\33\200" \
-  "\224\35\35\33\377\5\35\35\33\351\35\35\32\20\0\0\0\0\34\34\32\5\34\34" \
-  "\32`\234\35\35\33\377\2\35\35\33\361\35\35\33p\203\0\0\0\0\1\35\35\33" \
-  "\233\217\35\35\33\377\4\35\35\33\350\35\35\33S\35\35\33L\35\35\33\371" \
-  "\223\35\35\33\377\4\35\35\33\356\34\34\32""1\0\0\0\0\34\34\34\0\202\0" \
-  "\0\0\0\1\35\35\33\0\202\0\0\0\0\2\35\35\33""0\35\35\33\304\240\35\35" \
-  "\33\377\3\35\35\33\313\36\36\33\36\37\37\33\0\205\0\0\0\0\2\35\35\33" \
-  "#\35\35\33\343\217\35\35\33\377\2\35\35\33\276\35\35\33L\225\35\35\33" \
-  "\377\4\34\34\33C\34\34\33\2\0\0\0\0\35\35\35\0\316\0\0\0\0\30o\236\305" \
-  "OK\206\267\344I\204\266\377O\207\271\377S\212\273\377X\215\276\377]\217" \
-  "\300\377a\222\302\377e\225\305\377j\230\310\377n\233\312\377s\236\315" \
-  "\377x\241\317\377|\244\321\377\200\247\324\377\205\251\326\377\210\254" \
-  "\330\377\213\257\332\377\217\261\333\377\222\263\334\377\225\265\336" \
-  "\377\230\266\340\377\232\267\340\377\233\271\341\377\202\234\272\341" \
-  "\377$\225\265\337\377\362\366\373\377\357\364\372\377\260\310\347\377" \
-  "\230\267\336\377\221\262\334\377\216\261\333\377\216\260\333\377\250" \
-  "\303\343\377\232\271\335\377{\244\322\377{\243\320\377v\240\316\377q" \
-  "\235\314\377m\232\311\377i\230\307\377w\241\313\377\275\321\345\377\324" \
-  "\342\356\377|\245\313\377N\206\270\377L\206\267\377I\204\266\377C\201" \
-  "\263\377\77\177\261\377K\207\265\377\272\321\342\377\373\375\375\377" \
-  "\346\357\365\377{\251\307\377\40o\242\377\32l\240\377\26l\237\377\16" \
-  "j\235\377\24q\241\377x\256\311\377\202\377\377\377\377\12\376\376\377" \
-  "\377\364\370\372\377\271\322\340\3779\177\247\377\0S\210\377\0V\211\377" \
-  "\0W\212\377\0U\207\377\0S\205\377\0R\204\377\204\0P\203\377\3\0O\202" \
-  "\377\40f\222\340&j\225\10\225\0\0\0\0\2\34\34\33E\35\35\33\361\217\35" \
-  "\35\33\377\2\35\35\33\216\35\35%\3\202\0\0\0\0\4\35\35\35\0\0\0\0\0\377" \
-  "\377\0\0\35\35\33\321\216\35\35\33\377\5\35\35\33\334\35\35\33I\0\0\0" \
-  "\0\36\36\32\0\34\34\34\0\202\0\0\0\0\2\35\35\33s\35\35\33\363\242\35" \
-  "\35\33\377\4\35\35\33\261\35\35!\3\0\0\0\0\35\35\34\0\203\0\0\0\0\1\35" \
-  "\35\33d\217\35\35\33\377\3\35\35\33\372\35\35\33\273\35\35\33\374\224" \
-  "\35\35\33\377\5\35\35\33\376\35\35\33\213\0\0\0\0\34\34\31\5\34\34\32" \
-  "`\234\35\35\33\377\2\35\35\33\361\35\35\33p\203\0\0\0\0\1\35\35\33\233" \
-  "\217\35\35\33\377\3\35\35\33\347\35\35\33\207\35\35\33\342\224\35\35" \
-  "\33\377\2\35\35\33\373\35\35\33\247\203\0\0\0\0\1\32\32\32\0\202\0\0" \
-  "\0\0\2\35\35\33""8\35\35\33\317\242\35\35\33\377\4\35\35\33\342\36\36" \
-  "\33\36\0\0\0\0$$\40\0\203\0\0\0\0\2\35\35\33#\35\35\33\343\217\35\35" \
-  "\33\377\2\35\35\33\314\35\35\33\344\225\35\35\33\377\2\35\35\33\307\35" \
-  "\35\33\15\316\0\0\0\0\36\227\275\325\0\0\0\0\0Y\220\273}I\204\265\363" \
-  "H\204\265\377M\206\267\377Q\212\272\377V\214\275\377[\217\277\377`\221" \
-  "\301\377d\224\304\377i\227\306\377l\232\311\377p\235\313\377u\240\316" \
-  "\377z\242\320\377~\245\322\377\202\250\324\377\205\253\327\377\210\254" \
-  "\331\377\214\257\332\377\216\261\333\377\221\262\334\377\223\264\335" \
-  "\377\225\265\336\377\227\266\337\377\230\267\340\377\227\267\337\377" \
-  "\220\261\334\377\355\363\372\377\202\377\377\377\377\37\324\341\361\377" \
-  "\233\272\337\377\216\260\334\377\224\265\334\377\202\250\326\377\177" \
-  "\247\324\377|\244\322\377y\241\317\377t\237\315\377p\234\313\377o\233" \
-  "\311\377\214\261\324\377\305\327\351\377\232\272\330\377X\215\276\377" \
-  "Q\211\273\377Q\210\272\377L\206\267\377F\203\264\377E\202\264\377s\242" \
-  "\306\377\337\352\362\377\360\365\371\377\230\273\324\3771x\251\377\"" \
-  "o\242\377!p\243\377\32l\240\377\30n\240\3773\201\254\377\275\327\344" \
-  "\377\202\377\377\377\377\13\361\367\371\377\301\330\344\377D\211\257" \
-  "\377\0V\213\377\0W\213\377\0X\214\377\0W\213\377\0V\211\377\0T\207\377" \
-  "\0S\205\377\0R\204\377\205\0P\203\377\3\13X\210\377D\177\244\23\377\377" \
-  "\377\0\224\0\0\0\0\2\34\34\33E\35\35\33\361\217\35\35\33\377\2\35\35" \
-  "\33\216\35\35%\3\204\0\0\0\0\2\35\35\33d\35\35\33\360\216\35\35\33\377" \
-  "\1\35\35\33\225\205\0\0\0\0\2\35\35\33M\35\35\33\345\220\35\35\33\377" \
-  "\3\35\35\33\373\35\35\33\370\35\35\33\372\220\35\35\33\377\2\35\35\33" \
-  "\372\35\35\33\215\205\0\0\0\0\1\35\35\33d\247\35\35\33\377\4\35\35\33" \
-  "\346\0\0\0\0\33\33\31\5\34\34\32`\234\35\35\33\377\2\35\35\33\363\35" \
-  "\35\33q\203\0\0\0\0\1\35\35\33\233\247\35\35\33\377\1\35\35\33\335\205" \
-  "\0\0\0\0\2\35\35\33\36\35\35\33\263\220\35\35\33\377\1\35\35\33\375\202" \
-  "\35\35\33\371\1\35\35\33\375\220\35\35\33\377\2\35\35\33\311\30\30\25" \
-  "\5\204\0\0\0\0\2\35\35\33#\35\35\33\343\247\35\35\33\377\2\35\35\34+" \
-  "\35\35\36\1\317\0\0\0\0\30U\215\272\261G\203\264\377F\203\264\377L\205" \
-  "\267\377P\210\271\377T\213\274\377Y\216\276\377^\220\301\377a\223\303" \
-  "\377f\226\305\377j\231\310\377n\234\312\377r\236\314\377w\240\317\377" \
-  "{\243\321\377~\246\323\377\202\250\325\377\206\252\327\377\210\254\330" \
-  "\377\213\256\332\377\216\260\333\377\220\261\334\377\221\262\334\377" \
-  "\223\262\335\377\202\223\263\335\377\2\214\256\332\377\355\363\371\377" \
-  "\203\377\377\377\377+\372\373\375\377\267\314\347\377\215\260\332\377" \
-  "\201\250\325\377|\245\322\377z\242\320\377v\240\316\377r\235\314\377" \
-  "w\242\315\377\231\271\331\377\250\303\336\377i\230\305\377V\213\276\377" \
-  "W\214\275\377T\212\273\377N\207\270\377J\205\267\377T\214\272\377\240" \
-  "\277\331\377\354\362\367\377\262\314\337\377I\206\263\377*q\246\377)" \
-  "r\246\377&q\243\377\35n\241\377'u\245\377g\236\300\377\363\370\373\377" \
-  "\377\377\377\377\357\365\371\377\305\333\347\377P\222\266\377\0Z\217" \
-  "\377\0Y\216\377\0\\\217\377\0Z\215\377\0X\213\377\0V\212\377\0V\210\377" \
-  "\0T\206\377\0S\205\377\0R\204\377\205\0P\203\377\3\0O\202\377T\212\254" \
-  "Wf\227\265\1\224\0\0\0\0\2\34\34\33E\35\35\33\361\217\35\35\33\377\7" \
-  "\35\35\33\216\35\35%\3\0\0\0\0\40\40\40\0\0\0\0\0\34\34\335\0\35\35\33" \
-  "\310\216\35\35\33\377\4\35\35\33\320\35\35\33""7\0\0\0\0\33\33\33\0\202" \
-  "\0\0\0\0\2\33\33\35\10\35\35\33\273\217\35\35\33\377\7\35\35\33\373\35" \
-  "\35\33\333\35\35\33\250\35\35\33\213\35\35\33\232\35\35\33\313\35\35" \
-  "\33\366\217\35\35\33\377\4\35\35\33\352\35\35\34""0\0\0\0\0\"\"\"\0\202" \
-  "\0\0\0\0\1\35\35\33d\247\35\35\33\377\5\35\35\33\370\34\34\33'\33\33" \
-  "\27\2\34\34\32U\35\35\33\357\202\35\35\33\343\3\35\35\33\342\35\35\33" \
-  "\346\35\35\33\366\217\35\35\33\377\2\35\35\33\376\35\35\33\345\204\35" \
-  "\35\33\343\3\35\35\33\345\35\35\33\327\35\35\33d\203\0\0\0\0\1\35\35" \
-  "\33\233\247\35\35\33\377\2\35\35\33\342\35\35\33\37\204\0\0\0\0\1\35" \
-  "\35\33p\220\35\35\33\377\2\35\35\33\351\35\35\33\273\202\35\35\33\220" \
-  "\2\35\35\33\267\35\35\33\354\220\35\35\33\377\3\35\35\32f\0\0\0\0\36" \
-  "\36\33\0\202\0\0\0\0\2\35\35\33#\35\35\33\343\247\35\35\33\377\2\35\35" \
-  "\33f\35\35\33\3\317\0\0\0\0\34C\201\261\302A\177\261\377F\202\264\377" \
-  "J\204\266\377N\207\271\377R\212\273\377W\214\275\377[\217\277\377_\221" \
-  "\301\377d\224\304\377h\227\306\377l\231\310\377o\234\313\377s\236\315" \
-  "\377w\241\317\377{\244\321\377\177\246\323\377\202\250\325\377\205\252" \
-  "\327\377\207\253\327\377\212\256\331\377\214\257\332\377\215\257\332" \
-  "\377\216\260\333\377\217\261\334\377\217\260\334\377\207\254\331\377" \
-  "\346\356\367\377\205\377\377\377\377)\341\353\365\377\235\273\335\377" \
-  "\202\250\323\377t\237\316\377s\236\314\377z\243\316\377\223\265\327\377" \
-  "\177\246\316\377[\216\300\377^\220\301\377Z\216\277\377V\213\274\377" \
-  "O\207\271\377R\212\272\377n\235\305\377\300\325\346\377\305\327\347\377" \
-  "d\227\277\3771v\251\3770u\250\377-u\247\377'q\244\377$p\243\377:\201" \
-  "\255\377\245\306\332\377\377\377\377\377\360\366\371\377\310\336\351" \
-  "\377^\235\275\377\0_\223\377\0[\220\377\0^\221\377\0]\221\377\0\\\217" \
-  "\377\0Z\215\377\0X\213\377\0V\211\377\0V\210\377\0T\206\377\0R\204\377" \
-  "\0Q\203\377\205\0P\203\377\3\0O\203\377-o\231\2033s\234\1\224\0\0\0\0" \
-  "\2\34\34\33E\35\35\33\361\217\35\35\33\377\7\35\35\33\216\35\35%\3\0" \
-  "\0\0\0\30\30\23\0\0\0\0\0\35\35\33_\35\35\33\355\215\35\35\33\377\2\35" \
-  "\35\33\372\35\35\33\207\205\0\0\0\0\2\35\35\33S\35\35\33\342\217\35\35" \
-  "\33\377\2\35\35\33\274\35\35\33\26\204\0\0\0\0\2\35\35\33\204\35\35\33" \
-  "\367\216\35\35\33\377\2\35\35\33\370\35\35\33\225\204\0\0\0\0\1\35\35" \
-  "\33d\222\35\35\33\377\1\35\35\33\367\202\35\35\33\355\1\35\35\33\366" \
-  "\221\35\35\33\377\5\35\35\33\370\34\34\33G\0\0\0\0\40\40\37\5\37\37\31" \
-  "\16\202\37\37\31\15\3\40\40\30\12\35\35\33)\35\35\33\260\217\35\35\33" \
-  "\377\3\35\35\33\364\35\35\33\34\40\40\30\14\203\37\37\31\15\3\37\37\31" \
-  "\16\37\37\31\15\37\37\33\6\203\0\0\0\0\1\35\35\33\233\222\35\35\33\377" \
-  "\4\35\35\33\364\35\35\33\354\35\35\33\357\35\35\33\373\221\35\35\33\377" \
-  "\2\35\35\33\343\33\33\31&\203\0\0\0\0\2\35\35\33!\35\35\33\263\217\35" \
-  "\35\33\377\2\35\35\33\354\35\35\33B\204\0\0\0\0\2\35\35\33C\35\35\33" \
-  "\342\217\35\35\33\377\1\35\35\33\325\204\0\0\0\0\2\35\35\33#\35\35\33" \
-  "\343\221\35\35\33\377\4\35\35\33\374\35\35\33\357\35\35\33\354\35\35" \
-  "\33\361\222\35\35\33\377\2\35\35\34\206\35\35\34\4\316\0\0\0\0\37\231" \
-  "\274\3250D\202\262\324>~\260\377C\201\263\377I\203\265\377L\206\267\377" \
-  "Q\211\272\377T\213\274\377Y\215\276\377]\220\300\377a\223\303\377e\225" \
-  "\305\377j\230\307\377m\232\311\377p\235\314\377t\237\316\377x\241\317" \
-  "\377{\244\321\377~\246\323\377\201\250\325\377\203\251\326\377\206\253" \
-  "\327\377\210\254\330\377\211\255\331\377\212\255\332\377\212\256\331" \
-  "\377\212\256\332\377\206\253\330\377\266\315\350\377\341\352\366\377" \
-  "\365\370\374\377\205\377\377\377\377'\303\325\353\377\211\255\325\377" \
-  "v\240\315\377x\242\315\377d\225\305\377b\222\303\377`\222\302\377]\217" \
-  "\300\377W\214\275\377S\212\273\377\\\220\276\377\211\257\320\377\273" \
-  "\321\344\377\200\252\313\377<|\256\3775x\253\3775y\253\3771v\251\377" \
-  "'q\245\3770x\250\377b\231\275\377\344\356\364\377\370\373\374\377\312" \
-  "\336\352\377f\243\302\377\0e\231\377\0]\223\377\0a\224\377\0`\223\377" \
-  "\0^\222\377\0\\\220\377\0[\216\377\0Y\214\377\0W\213\377\0W\211\377\0" \
-  "U\207\377\0T\206\377\0R\204\377\0Q\203\377\206\0P\203\377\2\26_\216\247" \
-  "\30a\217\2\224\0\0\0\0\2\34\34\33E\35\35\33\361\217\35\35\33\377\2\35" \
-  "\35\33\216\35\35%\3\202\0\0\0\0\2'',\1\35\35\33\277\216\35\35\33\377" \
-  "\11\35\35\33\307\35\35\33\"\0\0\0\0\37\37\32\0\0\0\0\0\34\34\34\0\0\0" \
-  "\0\0\35\35\33\210\35\35\33\373\216\35\35\33\377\11\35\35\33\352\35\35" \
-  "\33^\0\0\0\0\35\35\33\0\0\0\0\0\34\34\34\0\0\0\0\0\35\35\33'\35\35\33" \
-  "\305\217\35\35\33\377\1\35\35\33\315\204\0\0\0\0\1\35\35\33d\220\35\35" \
-  "\33\377\10\35\35\33\376\35\35\33\326\35\35\33\214\35\35\33a\35\35\33" \
-  "`\35\35\33\207\35\35\33\321\35\35\33\376\217\35\35\33\377\2\35\35\33" \
-  "\370\34\34\33P\206\0\0\0\0\2\33\33\33\33\35\35\33\253\217\35\35\33\377" \
-  "\2\35\35\33\363\31\31\33\15\207\0\0\0\0\1\36\36\33\0\202\0\0\0\0\1\35" \
-  "\35\33\233\220\35\35\33\377\7\35\35\33\372\35\35\33\305\35\35\33}\35" \
-  "\35\33]\35\35\33i\35\35\33\244\35\35\33\352\220\35\35\33\377\2\35\35" \
-  "\33\343\34\34\32&\203\0\0\0\0\2\35\35\33A\35\35\33\341\216\35\35\33\377" \
-  "\11\35\35\33\375\35\35\33\247\0\0\0\0\32\32\27\0$$$\0\34\34\32\0\0\0" \
-  "\0\0\36\36\33\7\35\35\33\202\220\35\35\33\377\1\36\36\32\31\203\0\0\0" \
-  "\0\2\35\35\33#\35\35\33\343\220\35\35\33\377\7\35\35\33\353\35\35\33" \
-  "\243\35\35\33i\35\35\33]\35\35\33t\35\35\33\271\35\35\33\370\220\35\35" \
-  "\33\377\2\35\35\33\217\35\35\33\5\316\0\0\0\0\30j\235\302E@\200\260\335" \
-  "=}\260\377B\200\262\377F\202\264\377J\204\266\377N\207\271\377R\211\272" \
-  "\377V\214\275\377Z\216\277\377^\221\300\377b\223\303\377f\226\305\377" \
-  "j\230\307\377m\232\311\377q\235\314\377t\237\316\377w\241\317\377z\243" \
-  "\321\377}\245\322\377\177\247\324\377\202\250\325\377\203\251\326\377" \
-  "\204\252\327\377\203\206\253\327\377\6\203\251\326\377\260\311\346\377" \
-  "\240\275\340\377\264\313\346\377\336\351\364\377\367\372\374\377\204" \
-  "\377\377\377\377&\355\363\371\377\246\302\336\377x\242\314\377b\223\304" \
-  "\377_\221\302\377]\220\300\377X\215\276\377Y\216\275\377f\227\302\377" \
-  "\222\265\323\377\221\264\322\377L\207\267\3778z\256\377<|\256\3779z\254" \
-  "\3772w\252\377+r\246\377E\205\261\377\227\274\324\377\361\366\371\377" \
-  "\320\341\354\377z\253\310\377\17l\235\377\0`\225\377\0e\230\377\0d\226" \
-  "\377\0a\224\377\0`\223\377\0^\221\377\0\\\217\377\0[\216\377\0Y\214\377" \
-  "\0W\212\377\0V\211\377\0U\207\377\0S\205\377\0R\204\377\0Q\203\377\205" \
-  "\0P\203\377\3\0O\202\377#h\225\332&j\226\3\224\0\0\0\0\2\34\34\33E\35" \
-  "\35\33\361\217\35\35\33\377\2\35\35\33\216\35\35%\3\202\0\0\0\0\2\35" \
-  "\35\33[\35\35\33\352\215\35\35\33\377\4\35\35\33\362\35\35\33t\0\0\0" \
-  "\0\30\30\"\0\204\0\0\0\0\1\35\35\33\243\217\35\35\33\377\2\35\35\33\342" \
-  "\35\35\33G\205\0\0\0\0\2\35\35\35\27\35\35\33\270\217\35\35\33\377\2" \
-  "\35\35\33\330\34\34\34\24\203\0\0\0\0\1\35\35\33d\220\35\35\33\377\2" \
-  "\35\35\33\343\35\35\33,\204\0\0\0\0\2\35\35\33""2\35\35\33\326\217\35" \
-  "\35\33\377\2\35\35\33\370\34\34\33Q\206\0\0\0\0\2\34\34\33\35\35\35\33" \
-  "\253\217\35\35\33\377\2\35\35\33\363\31\31\33\20\212\0\0\0\0\1\35\35" \
-  "\33\233\220\35\35\33\377\2\35\35\33\300\35\35\33\20\204\0\0\0\0\2\35" \
-  "\35\33p\35\35\33\364\217\35\35\33\377\2\35\35\33\343\34\34\32&\203\0" \
-  "\0\0\0\2\35\35\33Q\35\35\33\371\216\35\35\33\377\2\35\35\33\374\35\35" \
-  "\33\210\206\0\0\0\0\1\35\35\33m\217\35\35\33\377\2\35\35\33\374\36\36" \
-  "\32C\203\0\0\0\0\2\35\35\33#\35\35\33\343\220\35\35\33\377\1\35\35\33" \
-  "c\204\0\0\0\0\2\27\27\27\5\35\35\33\244\220\35\35\33\377\2\35\35\33\220" \
-  "\35\35\33\5\316\0\0\0\0\30E\203\262Q9{\255\342;|\256\377\77~\260\377" \
-  "C\200\262\377H\203\265\377L\205\267\377P\207\270\377T\212\273\377X\214" \
-  "\275\377[\216\277\377_\220\302\377b\224\304\377f\226\305\377j\230\307" \
-  "\377m\232\311\377q\234\313\377s\236\315\377v\241\317\377x\242\320\377" \
-  "{\243\321\377}\245\323\377\177\246\323\377\200\246\323\377\203\201\250" \
-  "\325\377\10y\242\322\377\362\366\373\377\355\362\371\377\254\306\343" \
-  "\377\222\263\331\377\261\312\344\377\334\347\363\377\370\372\375\377" \
-  "\204\377\377\377\377#\321\340\356\377\215\261\324\377g\227\304\377U\213" \
-  "\275\377Y\215\276\377i\231\303\377\177\250\314\377a\223\277\377\77}\261" \
-  "\377@\177\262\377>~\260\377:{\255\3771v\251\3775z\253\377h\233\300\377" \
-  "\275\324\343\377\324\343\355\377\203\260\313\377\"s\244\377\6c\230\377" \
-  "\6g\232\377\1g\232\377\0e\230\377\0b\226\377\0a\224\377\0_\222\377\0" \
-  "]\220\377\0\\\217\377\0Z\216\377\0X\214\377\0W\212\377\0U\210\377\0T" \
-  "\207\377\0S\205\377\0Q\204\377\206\0P\203\377\3\0O\202\377\36d\222\367" \
-  "\40e\223\3\224\0\0\0\0\2\34\34\33E\35\35\33\361\217\35\35\33\377\5\35" \
-  "\35\33\216\35\35%\3\0\0\0\0##\23\3\35\35\33\265\216\35\35\33\377\4\35" \
-  "\35\33\276\40\40\30\16\0\0\0\0$$\22\0\204\0\0\0\0\1\35\35\33\251\217" \
-  "\35\35\33\377\2\35\35\33\342\35\35\33H\205\0\0\0\0\2\37\37\35\30\35\35" \
-  "\33\271\217\35\35\33\377\2\35\35\33\332\35\35\33\37\203\0\0\0\0\1\35" \
-  "\35\33d\217\35\35\33\377\11\35\35\33\374\35\35\33\246\0\0\0\0\35\35\33" \
-  "\1\0\0\0\0\35\35\35\0\0\0\0\0\36\36\33\13\35\35\33\216\217\35\35\33\377" \
-  "\2\35\35\33\370\34\34\33Q\206\0\0\0\0\2\34\34\33\35\35\35\33\253\217" \
-  "\35\35\33\377\2\35\35\33\363\31\31\33\20\212\0\0\0\0\1\35\35\33\233\217" \
-  "\35\35\33\377\11\35\35\33\360\35\35\33m\0\0\0\0\35\35\33\0\0\0\0\0\35" \
-  "\35\33\0\0\0\0\0\35\35\33%\35\35\33\277\217\35\35\33\377\2\35\35\33\343" \
-  "\34\34\32&\203\0\0\0\0\1\35\35\33V\217\35\35\33\377\2\35\35\33\374\35" \
-  "\35\33\211\205\0\0\0\0\2""11\7\0\35\35\33n\217\35\35\33\377\2\35\35\33" \
-  "\375\35\35\33O\203\0\0\0\0\2\35\35\33#\35\35\33\343\217\35\35\33\377" \
-  "\1\35\35\33\347\202\0\0\0\0\2+++\0\27\27\27\0\202\0\0\0\0\1\34\34\33" \
-  ">\220\35\35\33\377\2\35\35\33\220\35\35\33\5\316\0\0\0\0\31G\205\263" \
-  "e9{\255\3528z\255\377=}\257\377@\177\261\377E\202\263\377I\204\265\377" \
-  "M\207\267\377Q\211\272\377U\213\273\377Y\215\275\377\\\217\277\377_\222" \
-  "\301\377b\224\304\377g\226\305\377i\230\307\377m\232\311\377o\234\313" \
-  "\377r\236\314\377t\237\316\377w\240\317\377y\241\320\377y\242\320\377" \
-  "{\243\321\377{\245\322\377\202|\245\322\377\2t\237\317\377\351\360\367" \
-  "\377\202\377\377\377\377\6\323\341\360\377\230\270\333\377\202\251\322" \
-  "\377\256\307\341\377\334\347\362\377\374\375\376\377\203\377\377\377" \
-  "\377\"\367\372\374\377\265\315\343\377w\242\312\377]\221\277\377[\220" \
-  "\275\377K\205\267\377E\201\264\377D\201\263\377@\177\261\377<|\257\377" \
-  "2v\252\377N\212\266\377\201\253\312\377\272\321\342\377\222\270\321\377" \
-  "4|\252\377\21f\234\377\22j\236\377\17j\235\377\5h\233\377\0e\232\377" \
-  "\0d\227\377\0b\225\377\0`\223\377\0^\222\377\0]\220\377\0[\216\377\0" \
-  "Z\215\377\0X\213\377\0W\212\377\0U\210\377\0S\206\377\0R\205\377\0Q\203" \
-  "\377\206\0P\203\377\4\0O\203\377\22\\\213\377\13X\210\3\210\252\314\0" \
-  "\223\0\0\0\0\2\34\34\33E\35\35\33\361\217\35\35\33\377\5\35\35\33\216" \
-  "\35\35$\4\0\0\0\0\35\35\33V\35\35\33\346\215\35\35\33\377\4\35\35\33" \
-  "\355\35\35\33Z\0\0\0\0\36\36\32\0\205\0\0\0\0\1\35\35\33\252\217\35\35" \
-  "\33\377\2\35\35\33\342\35\35\33H\205\0\0\0\0\2\37\37\35\30\35\35\33\271" \
-  "\217\35\35\33\377\2\35\35\33\333\35\35\33!\203\0\0\0\0\1\35\35\33d\217" \
-  "\35\35\33\377\2\35\35\33\371\35\35\33\203\205\0\0\0\0\2\37\37\35\3\35" \
-  "\35\33\177\217\35\35\33\377\2\35\35\33\370\34\34\33Q\206\0\0\0\0\2\34" \
-  "\34\33\35\35\35\33\253\217\35\35\33\377\2\35\35\33\363\31\31\33\20\212" \
-  "\0\0\0\0\1\35\35\33\233\217\35\35\33\377\2\35\35\33\351\35\35\33Q\205" \
-  "\0\0\0\0\2\34\34\34\24\35\35\33\256\217\35\35\33\377\2\35\35\33\343\34" \
-  "\34\32&\203\0\0\0\0\1\35\35\33W\217\35\35\33\377\2\35\35\33\374\35\35" \
-  "\33\211\205\0\0\0\0\2//\11\1\35\35\33n\217\35\35\33\377\2\35\35\33\375" \
-  "\35\35\33Q\203\0\0\0\0\2\35\35\33#\35\35\33\343\217\35\35\33\377\3\35" \
-  "\35\33\303\35\35\33\4\30\30\30\0\204\0\0\0\0\1\35\35\33+\220\35\35\33" \
-  "\377\2\35\35\33\220\35\35\33\5\316\0\0\0\0\35P\213\266{9|\254\3636y\254" \
-  "\377;|\256\377\77~\260\377B\200\262\377F\203\264\377J\205\266\377N\207" \
-  "\270\377R\211\272\377U\213\274\377Y\215\276\377\\\217\277\377_\221\301" \
-  "\377c\224\304\377e\226\305\377i\227\307\377k\231\310\377m\233\312\377" \
-  "p\234\313\377r\235\314\377t\237\315\377u\237\316\377v\240\316\377w\241" \
-  "\317\377x\241\317\377x\241\320\377n\233\314\377\352\361\370\377\203\377" \
-  "\377\377\377\7\367\371\374\377\274\321\347\377\207\254\323\377z\244\315" \
-  "\377\255\307\340\377\333\346\361\377\376\377\377\377\203\377\377\377" \
-  "\377\37\340\352\363\377\231\272\327\377_\222\276\377C\200\263\377D\201" \
-  "\263\377B\177\262\377<|\257\377<}\256\377]\223\273\377\205\256\315\377" \
-  "\217\265\320\377D\205\261\377\33k\240\377\33k\237\377\30l\237\377\22" \
-  "k\236\377\13i\234\377\2f\232\377\0e\230\377\0c\226\377\0a\224\377\0_" \
-  "\222\377\0^\221\377\0\\\217\377\0[\216\377\0Y\214\377\0W\212\377\0V\211" \
-  "\377\0U\210\377\0S\206\377\0R\204\377\210\0P\203\377\2\4S\205\377&j\231" \
-  "\4\224\0\0\0\0\2\34\34\33E\35\35\33\361\217\35\35\33\377\4\35\35\33\216" \
-  "\35\35""5\1!!\36\2\35\35\33\254\215\35\35\33\377\2\35\35\33\375\35\35" \
-  "\33\261\210\0\0\0\0\1\35\35\33\252\217\35\35\33\377\2\35\35\33\342\35" \
-  "\35\33H\205\0\0\0\0\2\37\37\35\30\35\35\33\271\217\35\35\33\377\2\35" \
-  "\35\33\333\35\35\33!\203\0\0\0\0\1\35\35\33d\217\35\35\33\377\2\35\35" \
-  "\33\371\35\35\33\200\205\0\0\0\0\2\16\16)\1\35\35\33{\217\35\35\33\377" \
-  "\2\35\35\33\370\34\34\33Q\206\0\0\0\0\2\34\34\33\35\35\35\33\253\217" \
-  "\35\35\33\377\2\35\35\33\363\31\31\33\20\212\0\0\0\0\1\35\35\33\233\217" \
-  "\35\35\33\377\2\35\35\33\351\35\35\33P\205\0\0\0\0\2\33\33\31\24\35\35" \
-  "\33\256\217\35\35\33\377\2\35\35\33\343\34\34\32&\203\0\0\0\0\1\35\35" \
-  "\33W\217\35\35\33\377\2\35\35\33\374\35\35\33\211\205\0\0\0\0\2//\11" \
-  "\1\35\35\33n\217\35\35\33\377\2\35\35\33\375\35\35\33Q\203\0\0\0\0\2" \
-  "\35\35\33#\35\35\33\343\217\35\35\33\377\2\35\35\33\300\35\35\33\4\203" \
-  "\0\0\0\0\3\33\33\33\0\0\0\0\0\35\35\33'\220\35\35\33\377\2\35\35\33\220" \
-  "\35\35\33\5\316\0\0\0\0\31P\213\265\2057{\253\3673x\252\3778{\255\377" \
-  "<|\256\377\77\177\261\377C\201\263\377G\203\265\377J\205\266\377O\207" \
-  "\270\377R\211\272\377V\213\274\377Y\215\275\377\\\217\277\377_\221\301" \
-  "\377a\223\302\377d\225\304\377g\227\305\377j\230\307\377k\231\310\377" \
-  "m\232\311\377o\233\312\377p\234\313\377q\235\314\377r\236\314\377\202" \
-  "r\235\314\377\2j\230\311\377\330\344\361\377\205\377\377\377\377\6\344" \
-  "\354\365\377\247\303\336\377o\233\310\377q\235\310\377\252\305\336\377" \
-  "\334\347\361\377\203\377\377\377\377\36\374\375\376\377\306\330\350\377" \
-  "\177\251\314\377G\204\265\3776x\255\377D\201\261\377U\216\270\377p\240" \
-  "\303\377R\214\267\377%p\244\377!n\242\377\40o\242\377\33m\240\377\25" \
-  "l\237\377\15j\235\377\7h\232\377\0f\232\377\0d\227\377\0b\225\377\0`" \
-  "\223\377\0_\222\377\0]\221\377\0\\\217\377\0Z\215\377\0Y\214\377\0W\212" \
-  "\377\0U\210\377\0U\207\377\0S\205\377\0R\204\377\210\0P\203\377\2\0O" \
-  "\203\377`\217\262\15\224\0\0\0\0\2\34\34\33E\35\35\33\361\217\35\35\33" \
-  "\377\4\35\35\33\217\0\0\0\0\35\35\33O\35\35\33\343\215\35\35\33\377\4" \
-  "\35\35\33\351\35\35\33>\0\0\0\0\35\35\33\0\206\0\0\0\0\1\35\35\33\252" \
-  "\217\35\35\33\377\2\35\35\33\342\35\35\33H\205\0\0\0\0\2\37\37\35\30" \
-  "\35\35\33\271\217\35\35\33\377\2\35\35\33\333\35\35\33!\203\0\0\0\0\1" \
-  "\35\35\33d\217\35\35\33\377\2\35\35\33\371\35\35\33\201\205\0\0\0\0\2" \
-  "\23\23%\1\35\35\33|\217\35\35\33\377\2\35\35\33\370\34\34\33Q\206\0\0" \
-  "\0\0\2\34\34\33\35\35\35\33\253\217\35\35\33\377\2\35\35\33\363\31\31" \
-  "\33\20\212\0\0\0\0\1\35\35\33\233\217\35\35\33\377\2\35\35\33\351\35" \
-  "\35\33Q\205\0\0\0\0\2\33\33\31\24\35\35\33\256\217\35\35\33\377\2\35" \
-  "\35\33\343\34\34\32&\203\0\0\0\0\1\35\35\33W\217\35\35\33\377\2\35\35" \
-  "\33\374\35\35\33\211\205\0\0\0\0\2//\11\1\35\35\33n\217\35\35\33\377" \
-  "\2\35\35\33\375\35\35\33Q\203\0\0\0\0\2\35\35\33#\35\35\33\343\217\35" \
-  "\35\33\377\2\35\35\33\301\35\35\33\4\205\0\0\0\0\1\35\35\33(\220\35\35" \
-  "\33\377\2\35\35\33\220\35\35\33\5\316\0\0\0\0\31M\212\264\2115z\252\371" \
-  "1v\251\3775x\253\3779{\255\377=}\257\377@\177\261\377D\201\263\377G\203" \
-  "\265\377L\206\266\377O\207\270\377R\211\272\377V\213\274\377X\215\275" \
-  "\377[\216\277\377^\220\300\377a\222\302\377c\224\303\377e\225\304\377" \
-  "g\226\306\377i\227\306\377j\230\307\377k\231\311\377l\232\311\377m\232" \
-  "\312\377\202m\233\312\377\4j\230\311\377\231\271\331\377\271\316\345" \
-  "\377\353\361\367\377\204\377\377\377\377\7\376\376\377\377\316\335\354" \
-  "\377\216\262\323\377X\214\276\377q\236\307\377\247\303\334\377\337\351" \
-  "\362\377\203\377\377\377\377\34\355\363\370\377\254\307\335\377_\224" \
-  "\275\377>~\256\377G\205\262\3771w\251\377'q\245\377'r\244\377#p\242\377" \
-  "\35n\241\377\30l\237\377\22k\236\377\11i\234\377\2f\232\377\0e\230\377" \
-  "\0c\226\377\0a\225\377\0`\223\377\0^\221\377\0]\220\377\0[\216\377\0" \
-  "Y\214\377\0X\213\377\0W\212\377\0U\210\377\0T\206\377\0S\205\377\0Q\204" \
-  "\377\211\0P\203\377\1l\231\270\27\224\0\0\0\0\2\34\34\33E\35\35\33\361" \
-  "\217\35\35\33\377\3\35\35\33\214\34\34\36\10\35\35\33\240\215\35\35\33" \
-  "\377\2\35\35\33\373\35\35\33\240\211\0\0\0\0\1\35\35\33\252\217\35\35" \
-  "\33\377\2\35\35\33\342\35\35\33H\205\0\0\0\0\2\37\37\35\30\35\35\33\271" \
-  "\217\35\35\33\377\2\35\35\33\333\35\35\33!\203\0\0\0\0\1\35\35\33d\217" \
-  "\35\35\33\377\2\35\35\33\371\35\35\33\201\205\0\0\0\0\2\23\23%\1\35\35" \
-  "\33|\217\35\35\33\377\2\35\35\33\370\34\34\33Q\206\0\0\0\0\2\34\34\33" \
-  "\35\35\35\33\253\217\35\35\33\377\2\35\35\33\363\31\31\33\20\212\0\0" \
-  "\0\0\1\35\35\33\233\217\35\35\33\377\2\35\35\33\351\35\35\33Q\205\0\0" \
-  "\0\0\2\33\33\31\24\35\35\33\256\217\35\35\33\377\2\35\35\33\343\34\34" \
-  "\32&\203\0\0\0\0\1\35\35\33W\217\35\35\33\377\2\35\35\33\374\35\35\33" \
-  "\211\205\0\0\0\0\2//\11\1\35\35\33n\217\35\35\33\377\2\35\35\33\375\35" \
-  "\35\33Q\203\0\0\0\0\2\35\35\33#\35\35\33\343\217\35\35\33\377\2\35\35" \
-  "\33\301\35\35\33\4\205\0\0\0\0\1\35\35\33(\220\35\35\33\377\2\35\35\33" \
-  "\220\35\35\33\5\316\0\0\0\0\31K\211\263\2062x\251\370-t\250\3773w\252" \
-  "\3776y\254\377:|\256\377>}\257\377A\177\262\377D\202\263\377H\204\265" \
-  "\377K\205\267\377O\207\270\377R\211\272\377T\213\273\377W\214\275\377" \
-  "Y\216\276\377\\\217\300\377^\221\301\377`\222\302\377b\223\303\377d\224" \
-  "\304\377f\225\305\377f\226\306\377h\227\306\377h\227\307\377\202h\230" \
-  "\307\377\6b\224\305\377\275\322\346\377\253\305\340\377\221\263\326\377" \
-  "\264\314\343\377\360\365\371\377\204\377\377\377\377\7\357\364\371\377" \
-  "\272\317\344\377r\237\310\377F\202\265\377p\236\306\377\244\302\333\377" \
-  "\341\353\363\377\203\377\377\377\377\32\331\345\357\377\217\264\320\377" \
-  "<~\256\377$n\243\377(r\245\377%q\243\377\37o\242\377\32m\240\377\25k" \
-  "\237\377\15j\235\377\4h\232\377\0f\231\377\0d\227\377\0b\225\377\0a\224" \
-  "\377\0_\222\377\0]\220\377\0\\\217\377\0Z\215\377\0Y\214\377\0W\212\377" \
-  "\0V\211\377\0U\207\377\0T\206\377\0R\204\377\0Q\203\377\211\0P\203\377" \
-  "\1k\230\273\17\224\0\0\0\0\2\34\34\33E\35\35\33\361\217\35\35\33\377" \
-  "\3\35\35\33\202\35\35\33N\35\35\33\336\215\35\35\33\377\4\35\35\33\344" \
-  "\35\35\33%\0\0\0\0\35\35\33\0\207\0\0\0\0\1\35\35\33\252\217\35\35\33" \
-  "\377\2\35\35\33\342\35\35\33H\205\0\0\0\0\2\37\37\35\30\35\35\33\271" \
-  "\217\35\35\33\377\2\35\35\33\333\35\35\33!\203\0\0\0\0\1\35\35\33d\217" \
-  "\35\35\33\377\2\35\35\33\371\35\35\33\201\205\0\0\0\0\2\23\23%\1\35\35" \
-  "\33|\217\35\35\33\377\2\35\35\33\370\34\34\33Q\206\0\0\0\0\2\34\34\33" \
-  "\35\35\35\33\253\217\35\35\33\377\2\35\35\33\363\31\31\33\20\212\0\0" \
-  "\0\0\1\35\35\33\233\217\35\35\33\377\2\35\35\33\351\35\35\33Q\205\0\0" \
-  "\0\0\2\33\33\31\24\35\35\33\256\217\35\35\33\377\2\35\35\33\343\34\34" \
-  "\32&\203\0\0\0\0\1\35\35\33W\217\35\35\33\377\2\35\35\33\374\35\35\33" \
-  "\211\205\0\0\0\0\2//\11\1\35\35\33n\217\35\35\33\377\2\35\35\33\375\35" \
-  "\35\33Q\203\0\0\0\0\2\35\35\33#\35\35\33\343\217\35\35\33\377\2\35\35" \
-  "\33\301\35\35\33\4\205\0\0\0\0\1\35\35\33(\220\35\35\33\377\2\35\35\33" \
-  "\220\35\35\33\5\316\0\0\0\0\26G\207\262}.w\247\364*s\246\377/u\250\377" \
-  "4w\251\3777y\253\377;|\256\377=}\257\377A\200\262\377D\202\264\377G\203" \
-  "\265\377K\205\267\377M\207\270\377P\210\271\377S\211\272\377U\213\274" \
-  "\377X\214\275\377Z\216\277\377\\\217\300\377^\221\301\377_\221\301\377" \
-  "a\222\302\377\202b\223\303\377\203c\223\303\377\10X\214\300\377\352\361" \
-  "\367\377\365\370\373\377\306\330\352\377\217\262\324\377\200\250\316" \
-  "\377\267\316\343\377\366\371\374\377\204\377\377\377\377\7\335\350\362" \
-  "\377\236\276\330\377Q\211\270\377\77}\261\377k\233\302\377\243\301\331" \
-  "\377\352\361\366\377\202\377\377\377\377\30\365\370\373\377\301\326\345" \
-  "\377i\235\300\377#o\242\377\34k\237\377\34m\241\377\27l\237\377\20j\235" \
-  "\377\10h\233\377\2f\232\377\0e\230\377\0c\226\377\0a\224\377\0`\223\377" \
-  "\0^\221\377\0\\\220\377\0[\216\377\0Z\215\377\0X\213\377\0W\212\377\0" \
-  "U\210\377\0T\206\377\0S\205\377\0R\204\377\211\0P\203\377\2\3R\204\377" \
-  "3p\241\4\224\0\0\0\0\2\34\34\33E\35\35\33\361\217\35\35\33\377\2\35\35" \
-  "\33\222\35\35\33\234\215\35\35\33\377\4\35\35\33\367\35\35\33\177\0\0" \
-  "\0\0""55\33\0\210\0\0\0\0\1\35\35\33\252\217\35\35\33\377\2\35\35\33" \
-  "\342\35\35\33H\205\0\0\0\0\2\37\37\35\30\35\35\33\271\217\35\35\33\377" \
-  "\2\35\35\33\333\35\35\33!\203\0\0\0\0\1\35\35\33d\217\35\35\33\377\2" \
-  "\35\35\33\371\35\35\33\201\205\0\0\0\0\2\23\23%\1\35\35\33|\217\35\35" \
-  "\33\377\2\35\35\33\370\34\34\33Q\206\0\0\0\0\2\34\34\33\35\35\35\33\253" \
-  "\217\35\35\33\377\2\35\35\33\363\31\31\33\20\212\0\0\0\0\1\35\35\33\233" \
-  "\217\35\35\33\377\2\35\35\33\351\35\35\33Q\205\0\0\0\0\2\33\33\31\24" \
-  "\35\35\33\256\217\35\35\33\377\2\35\35\33\343\34\34\32&\203\0\0\0\0\1" \
-  "\35\35\33W\217\35\35\33\377\2\35\35\33\374\35\35\33\211\205\0\0\0\0\2" \
-  "//\11\1\35\35\33n\217\35\35\33\377\2\35\35\33\375\35\35\33Q\203\0\0\0" \
-  "\0\2\35\35\33#\35\35\33\343\217\35\35\33\377\2\35\35\33\301\35\35\33" \
-  "\4\205\0\0\0\0\1\35\35\33(\220\35\35\33\377\2\35\35\33\220\35\35\33\5" \
-  "\316\0\0\0\0\31""9\177\255i)s\245\354'r\245\377,t\247\3770v\250\3773" \
-  "w\252\3777y\253\377:{\255\377>~\260\377@\177\261\377D\201\263\377G\202" \
-  "\264\377J\204\266\377M\206\267\377O\210\271\377Q\211\272\377T\212\273" \
-  "\377V\213\274\377W\214\275\377Y\216\276\377[\217\277\377\\\217\300\377" \
-  "^\217\300\377^\220\301\377^\221\301\377\202_\221\301\377\2T\212\275\377" \
-  "\344\354\365\377\202\377\377\377\377\6\346\356\365\377\263\313\342\377" \
-  "t\240\310\377z\244\313\377\270\317\343\377\371\373\375\377\203\377\377" \
-  "\377\377\10\370\372\374\377\312\333\352\377}\250\312\3777y\255\377\77" \
-  "~\257\377f\230\277\377\241\300\330\377\360\364\371\377\202\377\377\377" \
-  "\377\26\346\357\365\377\247\305\332\377;\201\255\377\21g\234\377\22i" \
-  "\235\377\13i\234\377\4g\232\377\0e\231\377\0d\227\377\0b\225\377\0`\223" \
-  "\377\0_\222\377\0]\220\377\0\\\217\377\0Z\215\377\0Y\214\377\0W\212\377" \
-  "\0V\211\377\0U\207\377\0T\206\377\0S\205\377\0Q\203\377\211\0P\203\377" \
-  "\3\17[\212\377\7U\205\3\236\266\333\0\223\0\0\0\0\2\34\34\33E\35\35\33" \
-  "\361\217\35\35\33\377\2\35\35\33\337\35\35\33\347\215\35\35\33\377\4" \
-  "\35\35\33\362\35\35\33N\0\0\0\0\34\34\34\0\210\0\0\0\0\1\35\35\33\252" \
-  "\217\35\35\33\377\2\35\35\33\342\35\35\33H\205\0\0\0\0\2\37\37\35\30" \
-  "\35\35\33\271\217\35\35\33\377\2\35\35\33\333\35\35\33!\203\0\0\0\0\1" \
-  "\35\35\33d\217\35\35\33\377\2\35\35\33\371\35\35\33\201\205\0\0\0\0\2" \
-  "\23\23%\1\35\35\33|\217\35\35\33\377\2\35\35\33\370\34\34\33Q\206\0\0" \
-  "\0\0\2\34\34\33\35\35\35\33\253\217\35\35\33\377\2\35\35\33\363\31\31" \
-  "\33\20\212\0\0\0\0\1\35\35\33\233\217\35\35\33\377\2\35\35\33\351\35" \
-  "\35\33Q\205\0\0\0\0\2\33\33\31\24\35\35\33\256\217\35\35\33\377\2\35" \
-  "\35\33\343\34\34\32&\203\0\0\0\0\1\35\35\33W\217\35\35\33\377\2\35\35" \
-  "\33\374\35\35\33\211\205\0\0\0\0\2//\11\1\35\35\33n\217\35\35\33\377" \
-  "\2\35\35\33\375\35\35\33Q\203\0\0\0\0\2\35\35\33#\35\35\33\343\217\35" \
-  "\35\33\377\2\35\35\33\301\35\35\33\4\205\0\0\0\0\1\35\35\33(\220\35\35" \
-  "\33\377\2\35\35\33\220\35\35\33\5\316\0\0\0\0\27-x\247R#p\243\343$q\243" \
-  "\377)s\245\377,t\247\377/v\250\3774x\252\3776z\254\377:|\256\377=}\257" \
-  "\377@\177\261\377B\201\263\377F\202\265\377I\204\266\377K\205\267\377" \
-  "N\207\270\377P\210\271\377Q\211\272\377S\212\273\377U\213\274\377V\214" \
-  "\275\377X\214\275\377Y\215\276\377\202Z\216\277\377\4[\217\277\377Z\217" \
-  "\277\377O\207\272\377\347\356\366\377\203\377\377\377\377\6\374\375\376" \
-  "\377\334\347\362\377\224\266\324\377Z\217\275\377v\242\310\377\275\322" \
-  "\344\377\204\377\377\377\377\36\354\362\367\377\262\314\340\377U\215" \
-  "\271\377&n\245\377:}\255\377_\225\274\377\244\303\331\377\367\372\374" \
-  "\377\377\377\377\377\376\376\377\377\330\346\357\377{\254\311\377\17" \
-  "k\235\377\0c\231\377\0f\231\377\0e\230\377\0c\226\377\0a\224\377\0_\222" \
-  "\377\0^\222\377\0\\\220\377\0[\216\377\0Z\215\377\0X\213\377\0W\212\377" \
-  "\0V\210\377\0T\206\377\0S\205\377\0R\204\377\0Q\203\377\210\0P\203\377" \
-  "\3\0O\202\377\35d\221\372\37f\222\3\224\0\0\0\0\2\34\34\33E\35\35\33" \
-  "\361\217\35\35\33\377\2\35\35\33\334\35\35\33\343\215\35\35\33\377\4" \
-  "\35\35\33\374\35\35\33\253\0\0\0\0""22\6\0\210\0\0\0\0\1\35\35\33\252" \
-  "\217\35\35\33\377\2\35\35\33\342\35\35\33H\205\0\0\0\0\2\37\37\35\30" \
-  "\35\35\33\271\217\35\35\33\377\2\35\35\33\333\35\35\33!\203\0\0\0\0\1" \
-  "\35\35\33d\217\35\35\33\377\2\35\35\33\371\35\35\33\201\205\0\0\0\0\2" \
-  "\23\23%\1\35\35\33|\217\35\35\33\377\2\35\35\33\370\34\34\33Q\206\0\0" \
-  "\0\0\2\34\34\33\35\35\35\33\253\217\35\35\33\377\2\35\35\33\363\31\31" \
-  "\33\20\212\0\0\0\0\1\35\35\33\233\217\35\35\33\377\2\35\35\33\351\35" \
-  "\35\33Q\205\0\0\0\0\2\33\33\31\24\35\35\33\256\217\35\35\33\377\2\35" \
-  "\35\33\343\34\34\32&\203\0\0\0\0\1\35\35\33W\217\35\35\33\377\2\35\35" \
-  "\33\374\35\35\33\211\205\0\0\0\0\2//\11\1\35\35\33n\217\35\35\33\377" \
-  "\2\35\35\33\375\35\35\33Q\203\0\0\0\0\2\35\35\33#\35\35\33\343\217\35" \
-  "\35\33\377\2\35\35\33\301\35\35\33\4\205\0\0\0\0\1\35\35\33(\220\35\35" \
-  "\33\377\2\35\35\33\220\35\35\33\5\316\0\0\0\0\30O\217\264G#r\243\336" \
-  "\40o\242\377%q\243\377)r\245\377,t\247\3770v\250\3773w\251\3776y\253" \
-  "\3779|\256\377<}\257\377\77~\260\377A\200\262\377D\201\263\377G\202\264" \
-  "\377I\204\266\377K\205\267\377M\206\270\377O\207\270\377Q\210\271\377" \
-  "R\211\272\377S\211\272\377T\212\273\377T\213\274\377\203U\213\274\377" \
-  "\2L\204\270\377\303\326\347\377\205\377\377\377\377\6\362\366\372\377" \
-  "\312\334\352\377q\237\306\377K\205\267\377s\241\306\377\301\325\346\377" \
-  "\203\377\377\377\377\10\374\375\376\377\335\350\361\377\215\263\317\377" \
-  "3x\252\377\40m\242\3774z\251\377V\221\270\377\253\311\334\377\202\377" \
-  "\377\377\377\22\362\367\372\377\277\330\345\377B\216\263\377\0_\224\377" \
-  "\0b\225\377\0a\224\377\0`\223\377\0_\222\377\0]\221\377\0\\\217\377\0" \
-  "Z\215\377\0Y\214\377\0W\213\377\0V\211\377\0V\210\377\0T\206\377\0S\205" \
-  "\377\0Q\203\377\211\0P\203\377\3\0O\202\377#h\223\340%j\225\3\224\0\0" \
-  "\0\0\2\34\34\33E\35\35\33\361\217\35\35\33\377\2\35\35\33\230\35\35\33" \
-  "\254\216\35\35\33\377\4\35\35\33\350\37\37\31""7\0\0\0\0\34\34\34\0\207" \
-  "\0\0\0\0\1\35\35\33\252\217\35\35\33\377\2\35\35\33\342\35\35\33H\205" \
-  "\0\0\0\0\2\37\37\35\30\35\35\33\271\217\35\35\33\377\2\35\35\33\333\35" \
-  "\35\33!\203\0\0\0\0\1\35\35\33d\217\35\35\33\377\2\35\35\33\371\35\35" \
-  "\33\201\205\0\0\0\0\2\23\23%\1\35\35\33|\217\35\35\33\377\2\35\35\33" \
-  "\370\34\34\33Q\206\0\0\0\0\2\34\34\33\35\35\35\33\253\217\35\35\33\377" \
-  "\2\35\35\33\363\31\31\33\20\212\0\0\0\0\1\35\35\33\233\217\35\35\33\377" \
-  "\2\35\35\33\351\35\35\33Q\205\0\0\0\0\2\33\33\31\24\35\35\33\262\217" \
-  "\35\35\33\377\2\35\35\33\350\33\33\32&\203\0\0\0\0\1\35\35\33W\217\35" \
-  "\35\33\377\2\35\35\33\374\35\35\33\211\205\0\0\0\0\2//\11\1\35\35\33" \
-  "n\217\35\35\33\377\2\35\35\33\375\35\35\33Q\203\0\0\0\0\2\35\35\33#\35" \
-  "\35\33\343\217\35\35\33\377\2\35\35\33\301\35\35\33\4\205\0\0\0\0\1\35" \
-  "\35\33(\220\35\35\33\377\2\35\35\33\220\35\35\33\5\316\0\0\0\0\31\177" \
-  "\256\3125#s\243\326\34m\240\377\"o\242\377%q\244\377)r\245\377,t\247" \
-  "\377/v\250\3773w\252\3776z\253\3778z\255\377;|\256\377>~\260\377@\177" \
-  "\261\377B\200\262\377D\202\264\377F\203\265\377I\204\266\377J\205\266" \
-  "\377K\206\267\377M\206\267\377N\207\270\377P\210\270\377P\210\271\377" \
-  "Q\211\271\377\202Q\210\271\377\4O\207\271\377a\224\300\377}\247\313\377" \
-  "\324\342\356\377\205\377\377\377\377\6\352\361\366\377\255\310\336\377" \
-  "K\206\266\377F\203\263\377o\237\304\377\306\331\350\377\203\377\377\377" \
-  "\377\10\367\372\374\377\310\333\350\377]\225\273\377\33j\237\377\33l" \
-  "\240\377)w\246\377K\215\264\377\262\317\337\377\202\377\377\377\377\20" \
-  "\351\362\366\377\232\301\326\377\20l\234\377\0[\220\377\0_\222\377\0" \
-  "]\221\377\0\\\217\377\0[\216\377\0Y\214\377\0X\213\377\0W\212\377\0V" \
-  "\211\377\0U\206\377\0S\205\377\0R\204\377\0Q\203\377\212\0P\203\377\2" \
-  "\30a\217\255\33c\220\2\224\0\0\0\0\2\34\34\33E\35\35\33\361\217\35\35" \
-  "\33\377\3\35\35\33\203\35\35\33j\35\35\33\354\215\35\35\33\377\4\35\35" \
-  "\33\374\35\35\33\252\0\0\0\0&&\22\0\207\0\0\0\0\1\35\35\33\252\217\35" \
-  "\35\33\377\2\35\35\33\342\35\35\33H\205\0\0\0\0\2\37\37\35\30\35\35\33" \
-  "\271\217\35\35\33\377\2\35\35\33\333\35\35\33!\203\0\0\0\0\1\35\35\33" \
-  "d\217\35\35\33\377\2\35\35\33\371\35\35\33\201\205\0\0\0\0\2\23\23%\1" \
-  "\35\35\33|\217\35\35\33\377\2\35\35\33\370\34\34\33Q\206\0\0\0\0\2\34" \
-  "\34\33\35\35\35\33\253\217\35\35\33\377\2\35\35\33\363\31\31\33\20\212" \
-  "\0\0\0\0\1\35\35\33\233\217\35\35\33\377\2\35\35\33\351\35\35\33Q\205" \
-  "\0\0\0\0\3\35\35\31\20\35\35\33\213\35\35\33\324\215\35\35\33\314\3\35" \
-  "\35\33\316\35\35\33\266\35\35\32\36\203\0\0\0\0\1\35\35\33W\217\35\35" \
-  "\33\377\2\35\35\33\374\35\35\33\211\205\0\0\0\0\2//\11\1\35\35\33n\217" \
-  "\35\35\33\377\2\35\35\33\375\35\35\33Q\203\0\0\0\0\2\35\35\33#\35\35" \
-  "\33\343\217\35\35\33\377\2\35\35\33\301\35\35\33\4\205\0\0\0\0\1\35\35" \
-  "\33(\220\35\35\33\377\2\35\35\33\220\35\35\33\5\316\0\0\0\0\26\377\377" \
-  "\377\6\32n\241\304\27l\237\377\34n\241\377!o\242\377%q\243\377(r\245" \
-  "\377,s\246\377/u\250\3772v\251\3775x\252\3777y\255\377:{\255\377=}\257" \
-  "\377\77~\260\377@\200\262\377B\200\262\377D\202\263\377F\202\264\377" \
-  "G\203\265\377H\204\266\377I\205\266\377\202K\205\267\377\1L\205\267\377" \
-  "\202L\206\267\377\6B\177\263\377\315\335\353\377\236\276\330\377U\214" \
-  "\273\377{\246\312\377\332\346\360\377\204\377\377\377\377\7\372\374\375" \
-  "\377\337\352\362\377\204\255\314\3772w\252\377@\200\260\377m\236\302" \
-  "\377\315\336\352\377\202\377\377\377\377\30\376\376\377\377\360\365\371" \
-  "\377\240\302\330\377.y\250\377\16e\233\377\17j\235\377\27q\241\377D\216" \
-  "\264\377\276\330\345\377\377\377\377\377\375\376\376\377\335\353\361" \
-  "\377e\237\276\377\0Y\215\377\0Z\216\377\0\\\217\377\0Z\215\377\0X\213" \
-  "\377\0W\213\377\0V\211\377\0U\210\377\0T\206\377\0S\205\377\0Q\204\377" \
-  "\212\0P\203\377\3\0O\203\377#h\224\207'k\226\2\224\0\0\0\0\2\34\34\33" \
-  "E\35\35\33\361\217\35\35\33\377\3\35\35\33\211\35\35\34\40\35\35\33\276" \
-  "\216\35\35\33\377\4\35\35\33\343\35\35\33""7\0\0\0\0\30\30\30\0\206\0" \
-  "\0\0\0\1\35\35\33\252\217\35\35\33\377\2\35\35\33\342\35\35\33H\205\0" \
-  "\0\0\0\2\37\37\35\30\35\35\33\271\217\35\35\33\377\2\35\35\33\333\35" \
-  "\35\33!\203\0\0\0\0\1\35\35\33d\217\35\35\33\377\2\35\35\33\371\35\35" \
-  "\33\201\205\0\0\0\0\2\23\23%\1\35\35\33|\217\35\35\33\377\2\35\35\33" \
-  "\370\34\34\33Q\206\0\0\0\0\2\34\34\33\35\35\35\33\253\217\35\35\33\377" \
-  "\2\35\35\33\363\31\31\33\20\212\0\0\0\0\1\35\35\33\233\217\35\35\33\377" \
-  "\2\35\35\33\351\35\35\33Q\205\0\0\0\0\3\35\35\31\2\35\35\33\17\35\35" \
-  "\33\27\216\35\35\33\26\2\35\35\33\24\35\35\32\3\203\0\0\0\0\1\35\35\33" \
-  "W\217\35\35\33\377\2\35\35\33\374\35\35\33\211\205\0\0\0\0\2//\11\1\35" \
-  "\35\33n\217\35\35\33\377\2\35\35\33\375\35\35\33Q\203\0\0\0\0\2\35\35" \
-  "\33#\35\35\33\343\217\35\35\33\377\2\35\35\33\301\35\35\33\4\205\0\0" \
-  "\0\0\1\35\35\33(\220\35\35\33\377\2\35\35\33\220\35\35\33\5\317\0\0\0" \
-  "\0\30(x\246\264\31n\240\377\30l\237\377\34m\240\377\40o\242\377$q\243" \
-  "\377&q\244\377+s\246\377.t\247\3770v\250\3774w\251\3776y\253\3777y\254" \
-  "\377:{\256\377=}\257\377>~\260\377\77\177\261\377A\200\262\377B\200\262" \
-  "\377D\201\263\377E\201\263\377E\202\264\377F\202\264\377G\202\264\377" \
-  "\202G\203\265\377\10:{\260\377\341\353\363\377\374\375\376\377\333\346" \
-  "\360\377q\237\306\377H\204\264\377|\247\311\377\335\351\362\377\204\377" \
-  "\377\377\377\7\366\371\373\377\307\332\350\377V\217\270\377&o\244\377" \
-  "8|\254\377o\241\303\377\330\345\357\377\202\377\377\377\377\26\374\375" \
-  "\376\377\340\353\362\377g\241\300\377\13i\234\377\0d\230\377\2g\232\377" \
-  "\13k\234\377H\217\264\377\317\341\352\377\377\377\377\377\367\372\374" \
-  "\377\304\331\345\377.z\243\377\0S\210\377\0X\214\377\0X\213\377\0W\212" \
-  "\377\0V\211\377\0T\206\377\0S\205\377\0R\204\377\0Q\203\377\212\0P\203" \
-  "\377\3\0O\202\377Q\207\253b_\222\262\1\224\0\0\0\0\2\34\34\33E\35\35" \
-  "\33\361\217\35\35\33\377\4\35\35\33\216\0\0\0\0\35\35\33\202\35\35\33" \
-  "\372\215\35\35\33\377\4\35\35\33\374\35\35\33\245\0\0\0\0\377\377\377" \
-  "\0\206\0\0\0\0\1\35\35\33\252\217\35\35\33\377\2\35\35\33\342\35\35\33" \
-  "H\205\0\0\0\0\2\37\37\35\30\35\35\33\271\217\35\35\33\377\2\35\35\33" \
-  "\333\35\35\33!\203\0\0\0\0\1\35\35\33d\217\35\35\33\377\2\35\35\33\371" \
-  "\35\35\33\201\205\0\0\0\0\2\23\23%\1\35\35\33|\217\35\35\33\377\2\35" \
-  "\35\33\370\34\34\33Q\206\0\0\0\0\2\34\34\33\35\35\35\33\253\217\35\35" \
-  "\33\377\2\35\35\33\363\31\31\33\20\212\0\0\0\0\1\35\35\33\233\217\35" \
-  "\35\33\377\2\35\35\33\351\35\35\33Q\204\0\0\0\0\1\35\35\32\0\223\0\0" \
-  "\0\0\1\35\35\32\0\202\0\0\0\0\1\35\35\33W\217\35\35\33\377\2\35\35\33" \
-  "\374\35\35\33\211\205\0\0\0\0\2//\11\1\35\35\33n\217\35\35\33\377\2\35" \
-  "\35\33\375\35\35\33Q\203\0\0\0\0\2\35\35\33#\35\35\33\343\217\35\35\33" \
-  "\377\2\35\35\33\301\35\35\33\4\205\0\0\0\0\1\35\35\33(\220\35\35\33\377" \
-  "\2\35\35\33\220\35\35\33\5\315\0\0\0\0\26{\254\311\0\0\0\0\0+~\251\210" \
-  "\22m\236\366\23j\235\377\31l\237\377\34m\240\377\37o\242\377#p\243\377" \
-  "&q\244\377)s\245\377,t\246\3770u\250\3771v\251\3773w\252\3775x\253\377" \
-  "8z\255\3779{\255\377;{\255\377<}\257\377=~\260\377\77~\260\377\202@\177" \
-  "\261\377\16B\200\262\377C\200\262\377B\177\262\377A\200\262\3775w\255" \
-  "\377\337\352\362\377\377\377\377\377\376\377\377\377\372\374\375\377" \
-  "\270\317\342\377N\211\267\377B\201\261\377{\246\310\377\340\353\363\377" \
-  "\204\377\377\377\377\7\356\364\370\377\233\275\326\3770w\250\377\"n\242" \
-  "\377.w\250\377o\243\303\377\336\352\361\377\202\377\377\377\377\23\376" \
-  "\376\376\377\274\326\344\377-\201\253\377\0c\227\377\0b\226\377\2c\225" \
-  "\377\10e\226\377U\224\266\377\327\346\356\377\377\377\377\377\362\367" \
-  "\371\377\220\267\315\377\10^\217\377\0S\210\377\0V\211\377\0U\207\377" \
-  "\0S\206\377\0R\205\377\0Q\204\377\213\0P\203\377\3\6T\206\377L\204\247" \
-  "\31\266\315\331\0\224\0\0\0\0\2\34\34\33E\35\35\33\361\217\35\35\33\377" \
-  "\4\35\35\33\216\0\0\0\0\35\35\33""5\35\35\33\323\216\35\35\33\377\4\35" \
-  "\35\33\336\35\35\34""5\0\0\0\0\24\24\24\0\205\0\0\0\0\1\35\35\33\252" \
-  "\217\35\35\33\377\2\35\35\33\342\35\35\33H\205\0\0\0\0\2\37\37\35\30" \
-  "\35\35\33\271\217\35\35\33\377\2\35\35\33\333\35\35\33!\203\0\0\0\0\1" \
-  "\35\35\33d\217\35\35\33\377\2\35\35\33\371\35\35\33\201\205\0\0\0\0\2" \
-  "\23\23%\1\35\35\33|\217\35\35\33\377\2\35\35\33\370\34\34\33Q\206\0\0" \
-  "\0\0\2\34\34\33\35\35\35\33\253\217\35\35\33\377\2\35\35\33\363\31\31" \
-  "\33\20\212\0\0\0\0\1\35\35\33\233\217\35\35\33\377\2\35\35\33\351\35" \
-  "\35\33Q\233\0\0\0\0\1\35\35\33W\217\35\35\33\377\2\35\35\33\374\35\35" \
-  "\33\211\205\0\0\0\0\2//\11\1\35\35\33n\217\35\35\33\377\2\35\35\33\375" \
-  "\35\35\33Q\203\0\0\0\0\2\35\35\33#\35\35\33\343\217\35\35\33\377\2\35" \
-  "\35\33\301\35\35\33\4\205\0\0\0\0\1\35\35\33(\220\35\35\33\377\2\35\35" \
-  "\33\220\35\35\33\5\317\0\0\0\0\26.\201\254Q\13k\235\345\13i\234\377\21" \
-  "k\236\377\27l\237\377\32m\240\377\36n\241\377!p\243\377$q\243\377'r\244" \
-  "\377*s\246\377,t\247\377/u\250\3772v\251\3773x\252\3775y\253\3777y\254" \
-  "\3778z\254\3779z\256\377;|\256\377;}\257\377<}\257\377\202=~\260\377" \
-  "\202>~\260\377\2""1v\252\377\337\352\362\377\203\377\377\377\377\7\376" \
-  "\376\376\377\361\366\371\377\212\260\316\3774x\253\377;|\256\377\177" \
-  "\252\312\377\345\356\364\377\204\377\377\377\377\7\332\347\360\377c\233" \
-  "\277\377\31l\237\377\30l\237\377!s\244\377u\251\306\377\346\360\365\377" \
-  "\202\377\377\377\377\3\367\372\374\377\202\263\314\377\11g\231\377\202" \
-  "\0_\222\377\10\2^\222\377\7`\223\377d\233\272\377\346\357\364\377\377" \
-  "\377\377\377\336\352\360\377T\215\257\377\0P\204\377\202\0S\205\377\1" \
-  "\0Q\204\377\213\0P\203\377\3\0O\202\377\36e\222\354%j\225\11\225\0\0" \
-  "\0\0\2\34\34\33E\35\35\33\361\217\35\35\33\377\4\35\35\33\216\34\34(" \
-  "\3\0\0\0\0\35\35\33\243\216\35\35\33\377\2\35\35\33\374\35\35\33\236" \
-  "\207\0\0\0\0\1\35\35\33\252\217\35\35\33\377\2\35\35\33\342\35\35\33" \
-  "H\205\0\0\0\0\2\37\37\35\30\35\35\33\271\217\35\35\33\377\2\35\35\33" \
-  "\333\35\35\33!\203\0\0\0\0\1\35\35\33d\217\35\35\33\377\2\35\35\33\371" \
-  "\35\35\33\201\205\0\0\0\0\2\23\23%\1\35\35\33|\217\35\35\33\377\2\35" \
-  "\35\33\370\34\34\33Q\206\0\0\0\0\2\34\34\33\35\35\35\33\253\217\35\35" \
-  "\33\377\2\35\35\33\363\31\31\33\20\212\0\0\0\0\1\35\35\33\233\217\35" \
-  "\35\33\377\2\35\35\33\351\35\35\33Q\233\0\0\0\0\1\35\35\33W\217\35\35" \
-  "\33\377\2\35\35\33\374\35\35\33\211\205\0\0\0\0\2//\11\1\35\35\33n\217" \
-  "\35\35\33\377\2\35\35\33\375\35\35\33Q\203\0\0\0\0\2\35\35\33#\35\35" \
-  "\33\343\217\35\35\33\377\2\35\35\33\301\35\35\33\4\205\0\0\0\0\1\35\35" \
-  "\33(\220\35\35\33\377\2\35\35\33\220\35\35\33\5\317\0\0\0\0\22\246\312" \
-  "\335\34\10k\235\324\5g\233\377\14i\234\377\21j\236\377\26l\237\377\31" \
-  "l\240\377\34m\241\377\40o\242\377#p\243\377&q\244\377(r\245\377*s\246" \
-  "\377-t\247\377/u\250\3770v\250\3772w\251\3774x\252\377\2025x\253\377" \
-  "\2026z\254\377\1""8z\255\377\2039z\255\377\3.s\250\377\306\331\347\377" \
-  "\376\376\377\377\204\377\377\377\377\7\376\377\377\377\331\345\357\377" \
-  "[\223\273\377+s\245\3773y\252\377\200\254\312\377\347\357\365\377\203" \
-  "\377\377\377\377\10\375\375\376\377\261\315\337\3774\177\253\377\13g" \
-  "\233\377\7h\233\377\20n\237\377z\257\311\377\354\363\367\377\202\377" \
-  "\377\377\377\16\336\353\361\377F\213\260\377\2^\222\377\0\\\220\377\0" \
-  "\\\217\377\0Z\215\377\10^\217\377o\241\276\377\356\364\367\377\375\376" \
-  "\376\377\266\316\335\377#k\226\377\0N\201\377\0Q\203\377\213\0P\203\377" \
-  "\3\0O\203\377\32b\217\230\40f\222\5\225\0\0\0\0\2\34\34\33E\35\35\33" \
-  "\361\217\35\35\33\377\5\35\35\33\216\35\35%\3\0\0\0\0\35\35\33S\35\35" \
-  "\33\343\216\35\35\33\377\4\35\35\33\331\34\34\32""4\0\0\0\0\34\34\34" \
-  "\0\204\0\0\0\0\1\35\35\33\252\217\35\35\33\377\2\35\35\33\342\35\35\33" \
-  "H\205\0\0\0\0\2\37\37\35\30\35\35\33\271\217\35\35\33\377\2\35\35\33" \
-  "\333\35\35\33!\203\0\0\0\0\1\35\35\33d\217\35\35\33\377\2\35\35\33\371" \
-  "\35\35\33\201\205\0\0\0\0\2\23\23%\1\35\35\33|\217\35\35\33\377\2\35" \
-  "\35\33\370\34\34\33Q\206\0\0\0\0\2\34\34\33\35\35\35\33\253\217\35\35" \
-  "\33\377\2\35\35\33\363\31\31\33\20\212\0\0\0\0\1\35\35\33\233\217\35" \
-  "\35\33\377\2\35\35\33\351\35\35\33Q\233\0\0\0\0\1\35\35\33W\217\35\35" \
-  "\33\377\2\35\35\33\374\35\35\33\211\205\0\0\0\0\2//\11\1\35\35\33n\217" \
-  "\35\35\33\377\2\35\35\33\375\35\35\33Q\203\0\0\0\0\2\35\35\33#\35\35" \
-  "\33\343\217\35\35\33\377\2\35\35\33\301\35\35\33\4\205\0\0\0\0\1\35\35" \
-  "\33(\220\35\35\33\377\2\35\35\33\220\35\35\33\5\316\0\0\0\0\27d\242\302" \
-  "\0\0\0\0\0\34v\243\267\6i\234\377\3g\232\377\10h\233\377\17j\235\377" \
-  "\24k\236\377\27l\237\377\33m\240\377\36n\241\377\40o\242\377#p\243\377" \
-  "%q\243\377(r\244\377)s\245\377+t\247\377,t\247\377/u\250\3770v\250\377" \
-  "0v\251\3772w\251\3773w\251\377\2023x\252\377\2024x\252\377\6""1v\251" \
-  "\377N\211\265\377q\241\304\377\323\342\355\377\372\374\375\377\376\377" \
-  "\377\377\203\377\377\377\377\7\376\376\376\377\253\310\334\3777|\253" \
-  "\377\"o\243\377+u\246\377\202\256\312\377\350\360\365\377\203\377\377" \
-  "\377\377\26\355\364\370\377s\252\307\377\17o\237\377\0e\230\377\0a\225" \
-  "\377\20m\235\377\212\267\316\377\357\366\371\377\376\377\377\377\377" \
-  "\377\377\377\254\312\333\377\34n\233\377\2[\216\377\0Y\214\377\0X\213" \
-  "\377\0U\211\377\16^\217\377\203\254\304\377\364\367\372\377\357\364\370" \
-  "\377x\243\275\377\11V\210\377\213\0P\203\377\3\0O\203\377K\203\250Zn" \
-  "\234\271\3\225\0\0\0\0\2\34\34\33E\35\35\33\361\217\35\35\33\377\5\35" \
-  "\35\33\216\35\35%\3\0\0\0\0\35\35\23\3\35\35\33\275\216\35\35\33\377" \
-  "\2\35\35\33\374\35\35\33\227\206\0\0\0\0\1\35\35\33\252\217\35\35\33" \
-  "\377\2\35\35\33\342\35\35\33H\205\0\0\0\0\2\37\37\35\30\35\35\33\271" \
-  "\217\35\35\33\377\2\35\35\33\333\35\35\33!\203\0\0\0\0\1\35\35\33d\217" \
-  "\35\35\33\377\2\35\35\33\371\35\35\33\201\205\0\0\0\0\2\23\23%\1\35\35" \
-  "\33|\217\35\35\33\377\2\35\35\33\370\34\34\33Q\206\0\0\0\0\2\34\34\33" \
-  "\35\35\35\33\253\217\35\35\33\377\2\35\35\33\363\31\31\33\20\212\0\0" \
-  "\0\0\1\35\35\33\233\217\35\35\33\377\2\35\35\33\351\35\35\33Q\233\0\0" \
-  "\0\0\1\35\35\33W\217\35\35\33\377\2\35\35\33\374\35\35\33\211\205\0\0" \
-  "\0\0\2//\11\1\35\35\33n\217\35\35\33\377\2\35\35\33\375\35\35\33Q\203" \
-  "\0\0\0\0\2\35\35\33#\35\35\33\343\217\35\35\33\377\2\35\35\33\301\35" \
-  "\35\33\4\205\0\0\0\0\1\35\35\33(\220\35\35\33\377\2\35\35\33\220\35\35" \
-  "\33\5\320\0\0\0\0\24&z\247h\4g\231\356\0f\231\377\3g\232\377\7h\233\377" \
-  "\14i\234\377\20j\236\377\26l\237\377\30l\237\377\33m\240\377\36n\241" \
-  "\377\40o\242\377#p\243\377%q\244\377&q\244\377(r\245\377)s\246\377+t" \
-  "\246\377,t\247\377-t\247\377\202.u\250\377\13/u\250\377/v\251\3770v\251" \
-  "\377!m\243\377\343\355\363\377\270\321\341\377C\203\261\377k\235\302" \
-  "\377\320\340\354\377\370\372\374\377\376\376\377\377\203\377\377\377" \
-  "\377\10\355\364\370\377x\250\306\377!q\242\377\25i\236\377$t\244\377" \
-  "\205\262\315\377\344\356\364\377\375\376\376\377\202\377\377\377\377" \
-  "\26\313\340\352\377A\214\262\377\6g\231\377\0a\225\377\0[\220\377\31" \
-  "o\235\377\226\275\322\377\357\365\370\377\377\377\377\377\370\373\374" \
-  "\377p\242\277\377\12^\220\377\1X\212\377\0U\210\377\0T\206\377\0P\203" \
-  "\377\25a\217\377\222\265\312\377\367\371\373\377\316\336\347\377G\201" \
-  "\246\377\2Q\204\377\210\0P\203\377\5\0O\202\377\26_\215\375\34c\223\17" \
-  "\0\0\0\0\0FM\0\224\0\0\0\0\2\34\34\33E\35\35\33\361\217\35\35\33\377" \
-  "\2\35\35\33\216\35\35%\3\202\0\0\0\0\2\35\35\33s\35\35\33\360\216\35" \
-  "\35\33\377\4\35\35\33\324\35\35\33""2\0\0\0\0%%#\0\203\0\0\0\0\1\35\35" \
-  "\33\252\217\35\35\33\377\2\35\35\33\342\35\35\33H\205\0\0\0\0\2\37\37" \
-  "\35\30\35\35\33\271\217\35\35\33\377\2\35\35\33\333\35\35\33!\203\0\0" \
-  "\0\0\1\35\35\33d\217\35\35\33\377\2\35\35\33\371\35\35\33\201\205\0\0" \
-  "\0\0\2\23\23%\1\35\35\33|\217\35\35\33\377\2\35\35\33\370\34\34\33Q\206" \
-  "\0\0\0\0\2\34\34\33\35\35\35\33\253\217\35\35\33\377\2\35\35\33\363\32" \
-  "\32\33\20\212\0\0\0\0\1\35\35\33\233\217\35\35\33\377\2\35\35\33\351" \
-  "\35\35\33Q\233\0\0\0\0\1\35\35\33W\217\35\35\33\377\2\35\35\33\374\35" \
-  "\35\33\211\205\0\0\0\0\2//\11\1\35\35\33n\217\35\35\33\377\2\35\35\33" \
-  "\375\35\35\33Q\203\0\0\0\0\2\35\35\33#\35\35\33\343\217\35\35\33\377" \
-  "\2\35\35\33\301\35\35\33\4\205\0\0\0\0\1\35\35\33(\220\35\35\33\377\2" \
-  "\35\35\33\220\35\35\33\5\320\0\0\0\0\25\224\276\323#\10i\232\334\0e\230" \
-  "\377\0f\231\377\1g\232\377\4g\232\377\11i\234\377\16j\235\377\21j\236" \
-  "\377\25l\237\377\30l\237\377\32m\240\377\35n\241\377\40o\242\377!p\243" \
-  "\377#p\243\377$q\244\377'q\244\377'r\244\377(s\245\377*s\245\377\202" \
-  ")s\246\377\202)t\246\377\12\33k\240\377\333\350\360\377\377\377\377\377" \
-  "\371\373\375\377\205\257\314\377/w\250\377e\231\276\377\315\337\352\377" \
-  "\365\370\373\377\376\376\376\377\203\377\377\377\377\10\311\335\351\377" \
-  "G\213\263\377\24l\237\377\3c\230\377\32s\243\377\207\267\317\377\343" \
-  "\357\364\377\372\374\375\377\202\377\377\377\377\27\226\277\323\377\"" \
-  "u\241\377\3a\223\377\0]\220\377\0U\213\377$s\237\377\246\306\330\377" \
-  "\357\365\370\377\377\377\377\377\323\342\353\377<~\244\377\10Z\213\377" \
-  "\0S\205\377\0R\204\377\0P\203\377\0L\177\377#h\224\377\247\302\324\377" \
-  "\360\365\370\377\233\273\316\377$i\225\377\2R\204\377\0O\202\377\205" \
-  "\0P\203\377\5\0O\202\377\35d\221\237&k\225\11\0\0\0\0\200\252\325\0\224" \
-  "\0\0\0\0\2\34\34\33E\35\35\33\361\217\35\35\33\377\2\35\35\33\216\35" \
-  "\35%\3\202\0\0\0\0\2\35\35\33\34\35\35\33\321\216\35\35\33\377\2\35\35" \
-  "\33\374\35\35\33\217\205\0\0\0\0\1\35\35\33\251\217\35\35\33\377\2\35" \
-  "\35\33\342\35\35\33H\205\0\0\0\0\2\37\37\35\30\35\35\33\271\217\35\35" \
-  "\33\377\2\35\35\33\333\35\35\33!\203\0\0\0\0\1\35\35\33d\217\35\35\33" \
-  "\377\2\35\35\33\371\35\35\33\201\205\0\0\0\0\2\23\23%\1\35\35\33|\217" \
-  "\35\35\33\377\2\35\35\33\370\34\34\33Q\206\0\0\0\0\2\34\34\33\35\35\35" \
-  "\33\253\217\35\35\33\377\2\35\35\33\363\37\37\31\23\212\0\0\0\0\1\35" \
-  "\35\33\233\217\35\35\33\377\2\35\35\33\351\35\35\33Q\233\0\0\0\0\1\35" \
-  "\35\33W\217\35\35\33\377\2\35\35\33\374\35\35\33\211\205\0\0\0\0\2""0" \
-  "0\10\0\35\35\33n\217\35\35\33\377\2\35\35\33\375\35\35\33P\203\0\0\0" \
-  "\0\2\35\35\33#\35\35\33\343\217\35\35\33\377\2\35\35\33\301\35\35\33" \
-  "\4\205\0\0\0\0\1\35\35\33(\220\35\35\33\377\2\35\35\33\220\35\35\33\5" \
-  "\317\0\0\0\0\25[\233\274\0\0\0\0\0#w\243\255\4e\227\375\0c\226\377\0" \
-  "e\230\377\0f\231\377\1g\232\377\5h\233\377\12i\234\377\17j\235\377\21" \
-  "j\236\377\24k\236\377\27l\237\377\31l\237\377\34m\240\377\35n\241\377" \
-  "\37o\241\377\40o\242\377\"o\242\377\"p\243\377\202$p\243\377\1$q\243" \
-  "\377\202$q\244\377\2\25g\235\377\333\347\360\377\203\377\377\377\377" \
-  "\7\327\346\357\377W\223\271\377#q\244\377_\231\275\377\306\333\347\377" \
-  "\361\366\371\377\376\377\377\377\202\377\377\377\377\"\372\374\375\377" \
-  "\221\274\323\377#z\247\377\2g\232\377\0\\\223\377\32t\242\377\214\271" \
-  "\320\377\337\353\361\377\372\374\375\377\377\377\377\377\347\360\365" \
-  "\377a\233\273\377\26j\232\377\0[\216\377\0W\213\377\0P\206\3770x\240" \
-  "\377\253\310\330\377\357\364\370\377\377\377\377\377\232\274\317\377" \
-  "\40h\224\377\5U\206\377\0O\202\377\0P\203\377\0M\201\377\0K\177\3771" \
-  "r\233\377\266\315\334\377\324\341\352\377d\225\264\377\25_\215\377\1" \
-  "Q\203\377\0O\202\377\203\0P\203\377\3\3R\205\377D\177\244H\233\272\315" \
-  "\2\226\0\0\0\0\2\34\34\33E\35\35\33\361\217\35\35\33\377\7\35\35\33\216" \
-  "\35\35%\3\0\0\0\0&&#\0\0\0\0\0\35\35\33\226\35\35\33\371\216\35\35\33" \
-  "\377\4\35\35\33\317\35\35\33""0\0\0\0\0\"\"\40\0\202\0\0\0\0\1\35\35" \
-  "\33\244\217\35\35\33\377\11\35\35\33\344\35\35\32K\0\0\0\0\34\34\33\0" \
-  "\0\0\0\0\36\36\34\0\0\0\0\0\35\35\33\32\35\35\33\273\217\35\35\33\377" \
-  "\2\35\35\33\330\35\35\33\26\203\0\0\0\0\1\35\35\33d\217\35\35\33\377" \
-  "\2\35\35\33\371\35\35\33\201\205\0\0\0\0\2\23\23%\1\35\35\33|\217\35" \
-  "\35\33\377\2\35\35\33\370\34\34\33Q\206\0\0\0\0\2\34\34\33\35\35\35\33" \
-  "\253\217\35\35\33\377\2\35\35\33\364\36\36\33$\204\0\0\0\0\1\32\32\32" \
-  "\0\205\0\0\0\0\1\35\35\33\233\217\35\35\33\377\2\35\35\33\351\35\35\33" \
-  "Q\233\0\0\0\0\2\35\35\33R\35\35\33\373\216\35\35\33\377\11\35\35\33\374" \
-  "\35\35\33\216\0\0\0\0\35\35\33\0\0\0\0\0\34\34\34\0\0\0\0\0\35\35\33" \
-  "\2\35\35\33q\217\35\35\33\377\2\35\35\33\375\34\34\33D\203\0\0\0\0\2" \
-  "\35\35\33#\35\35\33\343\217\35\35\33\377\2\35\35\33\301\35\35\33\4\205" \
-  "\0\0\0\0\1\35\35\33(\220\35\35\33\377\2\35\35\33\220\35\35\33\5\321\0" \
-  "\0\0\0\4>\206\255F\6d\226\353\0b\225\377\0c\226\377\202\0e\230\377\24" \
-  "\0f\232\377\2g\232\377\6h\233\377\11h\233\377\15i\234\377\21j\235\377" \
-  "\22k\236\377\24l\237\377\26l\237\377\31m\240\377\32m\240\377\33n\241" \
-  "\377\34n\241\377\35n\241\377\36n\241\377\36o\242\377\37o\242\377\36o" \
-  "\242\377\20e\234\377\324\344\355\377\205\377\377\377\377\6\252\311\333" \
-  "\3776\200\254\377\26k\237\377W\225\271\377\302\331\346\377\355\364\370" \
-  "\377\203\377\377\377\377'\336\354\362\377_\237\277\377\22o\237\377\0" \
-  "a\225\377\0W\216\377\40t\241\377\224\274\322\377\335\352\360\377\375" \
-  "\376\376\377\377\377\377\377\274\324\341\377=\201\250\377\15a\222\377" \
-  "\0V\212\377\0S\207\377\0M\203\377:{\242\377\265\316\334\377\361\366\370" \
-  "\377\353\361\366\377i\230\265\377\23]\214\377\0P\203\377\0O\202\377\0" \
-  "P\203\377\0L\200\377\0J~\377A}\242\377\277\323\340\377\251\304\325\377" \
-  "\77|\242\377\14X\211\377\0O\202\377\0O\203\377\0N\202\377\40f\222\331" \
-  "\36e\222\17\0\0\0\0\\\217\257\0\225\0\0\0\0\2\34\34\33E\35\35\33\361" \
-  "\217\35\35\33\377\2\35\35\33\216\35\35%\3\203\0\0\0\0\2\35\35\31""6\35" \
-  "\35\33\341\216\35\35\33\377\2\35\35\33\374\35\35\33\210\202\0\0\0\0\4" \
-  "\34\34\34\0\0\0\0\0\35\35\33\213\35\35\33\375\216\35\35\33\377\2\35\35" \
-  "\33\357\35\35\33u\205\0\0\0\0\2\35\35\32=\35\35\33\322\217\35\35\33\377" \
-  "\1\35\35\33\315\204\0\0\0\0\1\35\35\33d\217\35\35\33\377\2\35\35\33\371" \
-  "\35\35\33\201\205\0\0\0\0\2\23\23%\1\35\35\33|\217\35\35\33\377\2\35" \
-  "\35\33\370\34\34\33Q\206\0\0\0\0\2\34\34\33\35\35\35\33\253\217\35\35" \
-  "\33\377\4\35\35\33\371\35\35\33o\35\35\33\10##\34\1\205\0\0\0\0\1\35" \
-  "\35\33\0\202\0\0\0\0\1\35\35\33\233\217\35\35\33\377\2\35\35\33\351\35" \
-  "\35\33Q\233\0\0\0\0\2\35\35\33C\35\35\33\344\216\35\35\33\377\2\35\35" \
-  "\33\376\35\35\33\271\205\0\0\0\0\2\35\35\33\24\35\35\33\232\217\35\35" \
-  "\33\377\2\35\35\33\373\35\35\32!\203\0\0\0\0\2\35\35\33#\35\35\33\343" \
-  "\217\35\35\33\377\2\35\35\33\301\35\35\33\4\205\0\0\0\0\1\35\35\33(\220" \
-  "\35\35\33\377\2\35\35\33\220\35\35\33\5\322\0\0\0\0\22\26m\234\305\2" \
-  "a\224\377\0a\224\377\0b\225\377\0d\227\377\0e\227\377\0f\231\377\0g\232" \
-  "\377\2g\232\377\4h\233\377\6h\233\377\11i\234\377\14j\235\377\20j\235" \
-  "\377\21k\236\377\23k\236\377\24l\236\377\25k\236\377\202\27k\237\377" \
-  "\7\30l\237\377\30m\240\377\30l\237\377\17f\233\377\206\262\315\377\325" \
-  "\344\356\377\363\370\372\377\204\377\377\377\377\7\362\366\371\377x\253" \
-  "\310\377\37u\244\377\3e\231\377P\226\271\377\271\325\343\377\351\362" \
-  "\366\377\203\377\377\377\377\10\264\321\340\377@\211\257\377\13g\230" \
-  "\377\0Z\217\377\0S\212\377)w\242\377\231\275\322\377\332\347\357\377" \
-  "\202\377\377\377\377\31\212\262\312\377)r\235\377\4X\213\377\0S\206\377" \
-  "\0P\204\377\0L\200\377I\203\247\377\274\320\336\377\357\364\370\377\277" \
-  "\323\340\377C~\244\377\15Y\211\377\0M\201\377\0O\203\377\0P\203\377\0" \
-  "J\177\377\0M\201\377Y\215\256\377\262\312\332\377u\241\274\377,n\230" \
-  "\377\5S\205\377\2Q\204\377+m\230hV\212\255\6\227\0\0\0\0\2\34\34\33E" \
-  "\35\35\33\361\217\35\35\33\377\2\35\35\33\216\35\35%\3\204\0\0\0\0\2" \
-  "\35\35\33\265\35\35\33\376\216\35\35\33\377\7\35\35\33\312\35\35\33-" \
-  "\0\0\0\0\35\35\33\0\0\0\0\0\35\35\33Q\35\35\33\342\217\35\35\33\377\7" \
-  "\35\35\33\326\34\34\33G\35\35\33\35\35\35\33\32\35\35\33\34\35\35\33" \
-  "/\35\35\33\251\217\35\35\33\377\4\35\35\33\371\35\35\33\223\0\0\0\0\34" \
-  "\34\34\0\202\0\0\0\0\1\35\35\33d\217\35\35\33\377\2\35\35\33\371\35\35" \
-  "\33\201\205\0\0\0\0\2\23\23%\1\35\35\33|\217\35\35\33\377\2\35\35\33" \
-  "\370\34\34\33Q\206\0\0\0\0\2\34\34\33\31\35\35\33\244\220\35\35\33\377" \
-  "\10\35\35\33\365\35\35\33\207\35\35\33P\35\35\33=\35\35\33""7\35\35\33" \
-  "6\35\35\33""3\35\35\33\30\203\0\0\0\0\1\35\35\33\233\217\35\35\33\377" \
-  "\2\35\35\33\351\35\35\33Q\233\0\0\0\0\2\35\35\33\40\35\35\33\261\217" \
-  "\35\35\33\377\3\35\35\33\373\35\35\33n\35\35\33\"\202\35\35\33\33\3\35" \
-  "\35\33%\35\35\33q\35\35\33\364\217\35\35\33\377\3\35\35\33\325\0\0\0" \
-  "\0""44)\0\202\0\0\0\0\2\35\35\33#\35\35\33\343\217\35\35\33\377\2\35" \
-  "\35\33\301\35\35\33\4\205\0\0\0\0\1\35\35\33(\220\35\35\33\377\2\35\35" \
-  "\33\220\35\35\33\5\320\0\0\0\0\12u\250\305\0\0\0\0\0""9\203\252W\5b\224" \
-  "\363\0_\223\377\0`\223\377\0a\224\377\0b\225\377\0c\226\377\0e\230\377" \
-  "\202\0f\231\377\11\0g\232\377\2g\232\377\4g\232\377\6h\233\377\10h\233" \
-  "\377\13i\234\377\14i\234\377\15i\234\377\17i\235\377\203\20j\235\377" \
-  "\7\21j\235\377\22k\236\377\2a\227\377&x\246\377\200\260\313\377\312\337" \
-  "\352\377\362\367\372\377\204\377\377\377\377\7\310\336\351\377O\225\271" \
-  "\377\12l\236\377\0`\224\377P\225\267\377\263\320\337\377\347\360\365" \
-  "\377\202\377\377\377\377#\363\367\372\377\210\264\314\377-z\245\377\3" \
-  "^\221\377\0V\213\377\0P\206\3770x\242\377\231\274\320\377\330\345\355" \
-  "\377\377\377\377\377\341\354\362\377d\230\267\377\36h\224\377\0O\202" \
-  "\377\0P\202\377\0K\200\377\0L\200\377S\212\254\377\277\323\340\377\342" \
-  "\353\361\377\221\263\311\377-o\231\377\4R\205\377\0L\200\377\0P\203\377" \
-  "\0O\203\377\0H}\377\4S\205\377k\231\267\377\220\263\311\377M\205\250" \
-  "\377(k\227\340'j\227\27\0\0\0\0\3U\200\0\226\0\0\0\0\2\34\34\33E\35\35" \
-  "\33\361\217\35\35\33\377\2\35\35\33\216\35\35%\3\202\0\0\0\0\4\33\33" \
-  "\33\0\0\0\0\0\35\35\33S\35\35\33\356\216\35\35\33\377\2\35\35\33\374" \
-  "\35\35\33\177\203\0\0\0\0\2\35\35\37\10\35\35\33\255\221\35\35\33\377" \
-  "\4\35\35\33\312\35\35\33\261\35\35\33\276\35\35\33\357\220\35\35\33\377" \
-  "\2\35\35\33\334\35\35\33,\204\0\0\0\0\1\35\35\33d\217\35\35\33\377\2" \
-  "\35\35\33\371\35\35\33\201\205\0\0\0\0\2\23\23%\1\35\35\33|\217\35\35" \
-  "\33\377\2\35\35\33\370\34\34\33Q\206\0\0\0\0\2\35\35\33\20\35\35\33\227" \
-  "\227\35\35\33\377\1\35\35\33x\203\0\0\0\0\1\35\35\33\233\217\35\35\33" \
-  "\377\2\35\35\33\351\35\35\33Q\234\0\0\0\0\2\35\35\33e\35\35\33\374\220" \
-  "\35\35\33\377\4\35\35\33\334\35\35\33\264\35\35\33\265\35\35\33\332\220" \
-  "\35\35\33\377\4\35\35\33\375\35\35\34\\\0\0\0\0\24\24\24\0\202\0\0\0" \
-  "\0\2\35\35\33#\35\35\33\343\217\35\35\33\377\2\35\35\33\301\35\35\33" \
-  "\4\205\0\0\0\0\1\35\35\33(\220\35\35\33\377\2\35\35\33\220\35\35\33\5" \
-  "\323\0\0\0\0\4\30l\232\306\1^\222\376\0^\222\377\0`\223\377\202\0a\224" \
-  "\377\4\0b\225\377\0c\226\377\0d\227\377\0e\230\377\202\0f\231\377\202" \
-  "\0g\232\377\4\2g\232\377\3g\232\377\3g\233\377\5h\233\377\202\6h\233" \
-  "\377\203\10h\233\377\7\7h\233\377\2e\231\377\0_\225\377\27s\243\377y" \
-  "\256\312\377\304\333\347\377\357\366\371\377\204\377\377\377\377\7\235" \
-  "\303\327\3776\204\254\377\0`\224\377\0]\221\377R\223\266\377\256\314" \
-  "\334\377\344\356\363\377\202\377\377\377\377!\324\343\354\377e\235\273" \
-  "\377\33l\231\377\0V\212\377\0R\207\377\0L\203\3774y\242\377\232\273\320" \
-  "\377\333\347\356\377\377\377\377\377\271\317\335\377G\202\246\377\15" \
-  "Z\211\377\0K\177\377\0O\202\377\0I~\377\1Q\204\377^\221\261\377\302\325" \
-  "\342\377\304\327\343\377k\232\267\377\35d\221\377\0M\201\377\0N\202\377" \
-  "\0P\203\377\0O\202\377\0G|\377\16Y\211\377v\241\274\377\212\257\306`" \
-  "v\241\272\5\0\0\0\0\200\244\310\0\226\0\0\0\0\2\34\34\33E\35\35\33\361" \
-  "\217\35\35\33\377\2\35\35\33\216\35\35%\3\204\0\0\0\0\2""55\33\2\35\35" \
-  "\33\315\217\35\35\33\377\7\35\35\33\306\35\35\33+\0\0\0\0\35\35\34\0" \
-  "\0\0\0\0\35\35\33=\35\35\33\321\243\35\35\33\377\4\35\35\33\361\35\35" \
-  "\33r\0\0\0\0\34\34\31\0\203\0\0\0\0\1\35\35\33d\217\35\35\33\377\2\35" \
-  "\35\33\371\35\35\33\201\205\0\0\0\0\2\23\23%\1\35\35\33|\217\35\35\33" \
-  "\377\2\35\35\33\370\34\34\33Q\207\0\0\0\0\1\35\35\33{\226\35\35\33\377" \
-  "\2\35\35\33\361\35\35\33p\203\0\0\0\0\1\35\35\33\233\217\35\35\33\377" \
-  "\2\35\35\33\351\35\35\33Q\232\0\0\0\0\4\35\35\32\0\0\0\0\0\35\35\33\27" \
-  "\35\35\33\233\244\35\35\33\377\1\35\35\33\247\205\0\0\0\0\2\35\35\33" \
-  "#\35\35\33\343\217\35\35\33\377\2\35\35\33\301\35\35\33\4\205\0\0\0\0" \
-  "\1\35\35\33(\220\35\35\33\377\2\35\35\33\220\35\35\33\5\321\0\0\0\0\7" \
-  "p\245\302\0\0\0\0\0C\207\255G\10b\224\364\0]\221\377\0^\222\377\0_\223" \
-  "\377\202\0`\223\377\1\0a\224\377\202\0b\225\377\2\0c\226\377\0d\227\377" \
-  "\203\0e\230\377\1\0e\231\377\204\0f\231\377\203\1f\231\377\203\0f\231" \
-  "\377\6\0d\230\377\0]\223\377\25r\240\377o\250\304\377\272\325\343\377" \
-  "\355\364\370\377\203\377\377\377\377\10\345\357\364\377z\254\307\377" \
-  "$w\243\377\0U\213\377\0]\221\377R\221\264\377\245\306\330\377\343\355" \
-  "\363\377\202\377\377\377\377\36\257\313\333\377M\213\256\377\12]\217" \
-  "\377\0R\207\377\0P\205\377\0L\201\377;{\242\377\227\270\315\377\335\347" \
-  "\357\377\372\374\375\377\220\262\311\3774t\234\377\0O\202\377\0L\200" \
-  "\377\0O\202\377\0I~\377\11W\210\377j\231\267\377\267\316\334\377\241" \
-  "\276\321\377S\211\254\377\15Y\211\377\0K\177\377\0O\202\377\0P\203\377" \
-  "\0L\201\377\15Y\211\317\17Z\213\32\0\0\0\0K\207\247\0\227\0\0\0\0\2\34" \
-  "\34\33E\35\35\33\361\217\35\35\33\377\2\35\35\33\216\35\35%\3\203\0\0" \
-  "\0\0\4\37\37\33\0\0\0\0\0\35\35\33x\35\35\33\366\216\35\35\33\377\2\35" \
-  "\35\33\374\35\35\33w\202\0\0\0\0\4\35\35\30\0\0\0\0\0\35\35\33O\35\35" \
-  "\33\315\241\35\35\33\377\2\35\35\33\352\35\35\33~\202\0\0\0\0\1\36\36" \
-  "\36\0\203\0\0\0\0\1\35\35\33d\217\35\35\33\377\2\35\35\33\371\35\35\33" \
-  "\201\205\0\0\0\0\2\23\23%\1\35\35\33|\217\35\35\33\377\2\35\35\33\370" \
-  "\34\34\33Q\205\0\0\0\0\4&&\"\0\0\0\0\0\35\35\33M\35\35\33\355\225\35" \
-  "\35\33\377\2\35\35\33\361\35\35\33p\203\0\0\0\0\1\35\35\33\233\217\35" \
-  "\35\33\377\2\35\35\33\351\35\35\33Q\233\0\0\0\0\5\32\32\30\0\0\0\0\0" \
-  "\35\35\33#\35\35\33\244\35\35\33\373\240\35\35\33\377\5\35\35\33\374" \
-  "\35\35\33\253\31\31\31\17\0\0\0\0\35\35\35\0\203\0\0\0\0\2\35\35\33#" \
-  "\35\35\33\343\217\35\35\33\377\2\35\35\33\301\35\35\33\4\205\0\0\0\0" \
-  "\1\35\35\33(\220\35\35\33\377\2\35\35\33\220\35\35\33\5\324\0\0\0\0\6" \
-  "\"q\235\247\0[\217\377\0]\220\377\0]\221\377\0^\221\377\0_\222\377\203" \
-  "\0`\223\377\202\0a\224\377\1\0b\225\377\203\0c\226\377\213\0d\227\377" \
-  "\7\0c\226\377\0a\225\377\0[\220\377\21l\234\377g\241\277\377\264\320" \
-  "\337\377\354\363\367\377\203\377\377\377\377\27\303\331\345\377]\231" \
-  "\271\377\21g\227\377\0M\205\377\3]\220\377P\215\261\377\240\301\324\377" \
-  "\344\355\363\377\377\377\377\377\361\366\371\377\216\264\312\3777z\241" \
-  "\377\0R\204\377\0P\203\377\0M\201\377\0K\177\377=z\241\377\226\267\315" \
-  "\377\340\352\360\377\334\347\356\377s\237\273\377\40f\222\377\0H~\377" \
-  "\202\0N\202\377\15\0H}\377\23]\214\377t\240\273\377\242\300\322\377\177" \
-  "\247\301\3779w\237\377\0P\203\377\0K\200\377\10U\206\377+m\230U\311\332" \
-  "\345\3\0\0\0\0\242\271\321\0\227\0\0\0\0\2\34\34\33E\35\35\33\361\217" \
-  "\35\35\33\377\2\35\35\33\216\35\35%\3\205\0\0\0\0\2\35\35\33\27\35\35" \
-  "\33\342\217\35\35\33\377\11\35\35\33\302\36\36\33(\0\0\0\0\35\35\34\0" \
-  "##\27\0\0\0\0\0\35\35\33;\35\35\33\247\35\35\33\363\236\35\35\33\377" \
-  "\2\35\35\33\303\35\35\33b\202\0\0\0\0\1\35\35\33\0\204\0\0\0\0\1\35\35" \
-  "\33d\217\35\35\33\377\2\35\35\33\371\35\35\33\201\205\0\0\0\0\2\23\23" \
-  "%\1\35\35\33|\217\35\35\33\377\2\35\35\33\370\34\34\33Q\207\0\0\0\0\2" \
-  "\35\35\33\24\35\35\33\232\225\35\35\33\377\2\35\35\33\361\35\35\33p\203" \
-  "\0\0\0\0\1\35\35\33\233\217\35\35\33\377\2\35\35\33\351\35\35\33Q\233" \
-  "\0\0\0\0\6+++\0\33\33\30\0\0\0\0\0\35\35\33\30\35\35\33\202\35\35\33" \
-  "\336\236\35\35\33\377\5\35\35\33\332\35\35\33\205\31\31\31\15\0\0\0\0" \
-  "\33\33\32\0\204\0\0\0\0\2\35\35\33#\35\35\33\343\217\35\35\33\377\2\35" \
-  "\35\33\301\35\35\33\4\205\0\0\0\0\1\35\35\33(\220\35\35\33\377\2\35\35" \
-  "\33\220\35\35\33\5\322\0\0\0\0\6{\254\304\0\0\0\0\0`\226\270\36\17d\224" \
-  "\341\0[\216\377\0[\217\377\202\0]\220\377\202\0^\221\377\2\0_\222\377" \
-  "\0_\223\377\203\0`\223\377\202\0a\224\377\1\0a\225\377\211\0b\225\377" \
-  "\203\0a\224\377\7\0`\223\377\0^\222\377\0Z\217\377\23k\232\377a\233\273" \
-  "\377\253\312\333\377\355\363\367\377\202\377\377\377\377$\364\370\372" \
-  "\377\240\302\325\377C\206\253\377\0X\214\377\0J\202\377\10]\217\377N" \
-  "\212\255\377\231\273\317\377\350\360\365\377\377\377\377\377\323\341" \
-  "\352\377t\241\274\377\33d\221\377\0K\177\377\0O\202\377\0K\177\377\0" \
-  "M\201\377A}\243\377\226\267\313\377\332\346\355\377\274\321\336\377Y" \
-  "\215\256\377\11V\207\377\0I~\377\0P\203\377\0M\201\377\0H~\377\37f\222" \
-  "\377q\236\272\377\206\254\304\377h\230\266\377$i\224\377\40f\222\242" \
-  "7w\236\21\0\0\0\0F\200\245\0\230\0\0\0\0\2\34\34\33E\35\35\33\361\217" \
-  "\35\35\33\377\2\35\35\33\216\35\35%\3\204\0\0\0\0\4\"\"\37\0\0\0\0\0" \
-  "\35\35\33\234\35\35\33\373\216\35\35\33\377\2\35\35\33\375\35\35\33p" \
-  "\202\0\0\0\0\7\32\32\32\0\40\40\34\0\0\0\0\0\33\33\33\21\35\35\33e\35" \
-  "\35\33\257\35\35\33\352\231\35\35\33\377\4\35\35\33\371\35\35\33\302" \
-  "\35\35\33\177\35\35\31,\202\0\0\0\0\1\36\36\33\0\205\0\0\0\0\1\35\35" \
-  "\33d\217\35\35\33\377\2\35\35\33\371\35\35\33\201\205\0\0\0\0\2\23\23" \
-  "%\1\35\35\33|\217\35\35\33\377\2\35\35\33\370\34\34\33Q\206\0\0\0\0\4" \
-  "\37\37\33\0\0\0\0\0\35\35\33,\35\35\33\261\224\35\35\33\377\2\35\35\33" \
-  "\361\35\35\33p\203\0\0\0\0\1\35\35\33\233\217\35\35\33\377\2\35\35\33" \
-  "\351\35\35\33Q\234\0\0\0\0\2\40\40\40\0\35\35\32\0\202\0\0\0\0\3\35\35" \
-  "\33E\35\35\33\231\35\35\33\330\232\35\35\33\377\3\35\35\33\326\35\35" \
-  "\33\227\35\35\33F\210\0\0\0\0\2\35\35\33#\35\35\33\343\217\35\35\33\377" \
-  "\2\35\35\33\301\35\35\33\4\205\0\0\0\0\1\35\35\33(\220\35\35\33\377\2" \
-  "\35\35\33\220\35\35\33\5\323\0\0\0\0\13<\200\250\0\0\0\0\0""7|\245`\10" \
-  "_\220\377\0Z\215\377\0[\216\377\0\\\217\377\0\\\220\377\0]\220\377\0" \
-  "]\221\377\0^\221\377\202\0^\222\377\202\0_\222\377\204\0`\223\377\1\0" \
-  "a\224\377\203\0`\223\377\1\0a\224\377\203\0`\223\377\202\0`\222\377\1" \
-  "\0^\222\377\202\0^\221\377\6\0Z\217\377\0W\214\377\21g\227\377[\226\267" \
-  "\377\246\306\327\377\355\364\367\377\202\377\377\377\377\37\335\351\360" \
-  "\377\202\256\306\377%o\233\377\0P\205\377\0K\201\377\12\\\214\377K\207" \
-  "\252\377\227\270\315\377\356\363\367\377\377\377\377\377\270\316\334" \
-  "\377Y\216\256\377\3R\204\377\0K\177\377\0O\202\377\0J\177\377\0O\202" \
-  "\377D\177\244\377\226\267\315\377\312\332\345\377\240\276\321\377<y\240" \
-  "\377\0J\177\377\0L\200\377\0P\203\377\0L\200\377\0I~\377*m\230\377d\225" \
-  "\264\377e\225\264\325j\231\2661\233\0\0\0\0\2\34\34\33H\35\35\33\373" \
-  "\217\35\35\33\377\2\35\35\33\224\35\35%\4\204\0\0\0\0\4\24\24\24\0\0" \
-  "\0\0\0\36\36\33/\35\35\33\370\217\35\35\33\377\6\35\35\33\311\35\35\33" \
-  ",\0\0\0\0\"\"\"\0\0\0\0\0\34\34\33\0\202\0\0\0\0\5\35\35\33\32\35\35" \
-  "\33T\35\35\33\211\35\35\33\271\35\35\33\342\223\35\35\33\377\5\35\35" \
-  "\33\356\35\35\33\307\35\35\33\230\35\35\33e\35\35\33,\202\0\0\0\0\2%" \
-  "%\36\0\27\27\27\0\206\0\0\0\0\1\35\35\33h\220\35\35\33\377\1\35\35\33" \
-  "\206\205\0\0\0\0\2\23\23%\1\35\35\33\201\220\35\35\33\377\1\34\34\33" \
-  "T\206\0\0\0\0\1\33\33\33\0\202\0\0\0\0\4\35\35\33\"\35\35\33{\35\35\33" \
-  "\301\35\35\33\362\221\35\35\33\377\2\35\35\33\373\35\35\33u\203\0\0\0" \
-  "\0\1\35\35\33\242\217\35\35\33\377\2\35\35\33\362\35\35\33T\236\0\0\0" \
-  "\0\1\34\34\33\0\202\0\0\0\0\6\40\40\32\11\35\35\33@\35\35\33x\35\35\33" \
-  "\253\35\35\33\325\35\35\33\374\222\35\35\33\377\6\35\35\33\372\35\35" \
-  "\33\325\35\35\33\250\35\35\33w\35\35\33\77\35\35\30\3\203\0\0\0\0\1\32" \
-  "\32\32\0\205\0\0\0\0\2\35\35\33%\35\35\33\354\217\35\35\33\377\2\35\35" \
-  "\33\311\35\35\33\4\205\0\0\0\0\1\35\35\33)\220\35\35\33\377\2\35\35\33" \
-  "\226\35\35\33\5\326\0\0\0\0\1\"o\232\230\202\0Y\214\377\1\0Z\215\377" \
-  "\202\0[\216\377\202\0\\\217\377\2\0\\\220\377\0]\220\377\202\0]\221\377" \
-  "\203\0^\221\377\1\0^\222\377\204\0_\222\377\202\0^\222\377\202\0^\221" \
-  "\377\203\0]\221\377\202\0\\\220\377\202\0[\217\377\6\0Y\214\377\0V\212" \
-  "\377\23f\225\377T\220\262\377\236\277\323\377\354\363\367\377\202\377" \
-  "\377\377\377\37\302\327\343\377e\231\270\377\13\\\214\377\0L\201\377" \
-  "\0J\177\377\15[\213\377G\201\245\377\223\265\312\377\360\365\370\377" \
-  "\363\367\371\377\237\275\321\377;x\240\377\0H}\377\0M\201\377\0O\202" \
-  "\377\0K\177\377\4S\205\377H\201\246\377\221\264\311\377\260\311\331\377" \
-  "\206\254\304\377\40f\223\377\0G}\377\0O\202\377\0P\203\377\0J\177\377" \
-  "\14X\211\371[\217\260\\\377\377\377\1\0\0\0\0h\227\265\0\231\0\0\0\0" \
-  "\3\34\34\33.\35\35\33\240\35\35\33\252\215\35\35\33\251\3\35\35\33\262" \
-  "\35\35\33^\35\35%\2\207\0\0\0\0\1\35\35\33\213\216\35\35\33\251\3\35" \
-  "\35\33\253\35\35\33\244\35\35\33:\204\0\0\0\0\2\"\"\"\0\22\22\14\0\203" \
-  "\0\0\0\0\30\35\35\33&\35\35\33H\35\35\33f\35\35\33\204\35\35\33\241\35" \
-  "\35\33\271\35\35\33\315\35\35\33\335\35\35\33\352\35\35\33\362\35\35" \
-  "\33\370\35\35\33\373\35\35\33\371\35\35\33\364\35\35\33\355\35\35\33" \
-  "\342\35\35\33\323\35\35\33\300\35\35\33\251\35\35\33\216\35\35\33o\35" \
-  "\35\33Q\35\35\33""1\35\35\35\12\203\0\0\0\0\1\33\33\33\0\210\0\0\0\0" \
-  "\3\35\35\33B\35\35\33\254\35\35\33\252\215\35\35\33\251\2\35\35\33\245" \
-  "\35\35\33U\205\0\0\0\0\3\24\24$\1\35\35\33R\35\35\33\263\216\35\35\33" \
-  "\251\2\35\35\33\245\34\34\33""6\207\0\0\0\0\12\37\37\33\0\17\17\33\0" \
-  "\0\0\0\0ZZ\33\0\35\35\33*\35\35\33T\35\35\33r\35\35\33\213\35\35\33\234" \
-  "\35\35\33\244\214\35\35\33\251\3\35\35\33\253\35\35\33\240\35\35\33J" \
-  "\203\0\0\0\0\2\35\35\33g\35\35\33\261\215\35\35\33\251\3\35\35\33\252" \
-  "\35\35\33\233\35\35\33""6\240\0\0\0\0\1\"\"\37\0\203\0\0\0\0\13\35\35" \
-  "\33\31\35\35\33=\35\35\33\\\35\35\33z\35\35\33\231\35\35\33\262\35\35" \
-  "\33\310\35\35\33\330\35\35\33\346\35\35\33\360\35\35\33\366\202\35\35" \
-  "\33\372\13\35\35\33\365\35\35\33\360\35\35\33\346\35\35\33\330\35\35" \
-  "\33\307\35\35\33\261\35\35\33\230\35\35\33y\35\35\33[\35\35\33<\35\35" \
-  "\33\27\204\0\0\0\0\1\35\35\32\0\207\0\0\0\0\3\35\35\33\27\35\35\33\226" \
-  "\35\35\33\254\215\35\35\33\251\3\35\35\33\253\35\35\33\200\35\35\33\3" \
-  "\205\0\0\0\0\2\35\35\33\32\35\35\33\264\216\35\35\33\251\3\35\35\33\256" \
-  "\35\35\33`\35\35\33\3\324\0\0\0\0\10k\237\275\0\0\0\0\0Y\221\263\24\35" \
-  "j\227\306\0V\212\377\0X\213\377\0Y\214\377\0Z\214\377\202\0Z\215\377" \
-  "\203\0[\216\377\202\0[\217\377\1\0\\\217\377\202\0\\\220\377\204\0]\220" \
-  "\377\203\0\\\220\377\1\0\\\217\377\203\0[\217\377\202\0[\216\377\202" \
-  "\0Z\215\377\27\0Y\214\377\0X\214\377\0U\212\377\0S\210\377\22b\222\377" \
-  "K\210\254\377\230\272\317\377\357\364\367\377\377\377\377\377\361\366" \
-  "\370\377\251\306\326\377A~\244\377\0N\202\377\0K\200\377\0I~\377\16Y" \
-  "\212\377@|\242\377\221\263\311\377\356\363\366\377\337\351\357\377\206" \
-  "\254\304\377\27`\216\377\0G|\377\202\0O\202\377\15\0K\177\377\11V\207" \
-  "\377G\201\246\377\205\254\303\377\236\275\320\377d\225\264\377\6T\206" \
-  "\377\0I~\377\6T\206\377\34c\221\213-n\231\14\0\0\0\0\300\324\341\0\232" \
-  "\0\0\0\0\3\36\36\33\7\35\35\33\32\35\35\33\34\215\35\35\33\33\3\35\35" \
-  "\33\35\35\35\33\17\35\35&\0\205\0\0\0\0\3\33\33\33\0\0\0\0\0\35\35\33" \
-  "\21\217\35\35\33\33\2\35\35\33\37\35\35\34\16\207\0\0\0\0\1\34\34\32" \
-  "\0\204\0\0\0\0\21\30\30\27\3\34\34\33\26\35\35\33&\35\35\33""3\35\35" \
-  "\33>\35\35\33F\35\35\33K\35\35\33O\35\35\33Q\35\35\33P\35\35\33M\35\35" \
-  "\33H\35\35\33A\35\35\33""7\35\35\33*\35\35\33\33\33\33\31\11\205\0\0" \
-  "\0\0\1\35\35\34\0\212\0\0\0\0\1\35\35\33\13\202\35\35\33\34\216\35\35" \
-  "\33\33\1\35\35\33\16\205\0\0\0\0\3\25\25#\0\35\35\33\15\35\35\33\35\217" \
-  "\35\35\33\33\1\36\36\35\11\211\0\0\0\0\1\36\36\33\0\204\0\0\0\0\3\35" \
-  "\35\32\7\35\35\33\23\35\35\32\30\214\35\35\33\33\3\35\35\33\34\35\35" \
-  "\33\32\35\35\33\14\203\0\0\0\0\2\35\35\33\21\35\35\33\35\215\35\35\33" \
-  "\33\3\35\35\33\34\35\35\33\31\35\35\33\11\242\0\0\0\0\1\35\35\33\0\205" \
-  "\0\0\0\0\7\33\33\33\20\35\35\33!\35\35\33/\35\35\33:\35\35\33C\35\35" \
-  "\33J\35\35\33N\202\35\35\33P\7\35\35\33M\35\35\33J\35\35\33C\35\35\33" \
-  ":\35\35\33/\35\35\34!\36\36\34\20\205\0\0\0\0\1$$!\0\212\0\0\0\0\3\35" \
-  "\35\33\4\35\35\33\30\35\35\33\34\215\35\35\33\33\3\35\35\33\34\35\35" \
-  "\33\25\35\35\33\0\205\0\0\0\0\2\35\35\33\4\35\35\33\35\216\35\35\33\33" \
-  "\3\35\35\33\34\35\35\33\20\35\35\33\1\325\0\0\0\0\6<\177\246\0\0\0\0" \
-  "\0@\201\246-\25e\223\343\0V\211\377\0W\213\377\202\0X\213\377\203\0Y" \
-  "\214\377\3\0Z\215\377\0[\215\377\0Z\215\377\212\0[\216\377\204\0Z\215" \
-  "\377\202\0Y\214\377\3\0X\214\377\0X\213\377\0W\213\377\202\0W\212\377" \
-  "\"\0V\211\377\0T\207\377\0Q\205\377\21`\217\377D\201\246\377\223\266" \
-  "\313\377\364\367\371\377\377\377\377\377\341\352\360\377\215\261\310" \
-  "\377\33b\220\377\0J\177\377\0M\201\377\0J\177\377\16Y\212\377;y\240\377" \
-  "\217\262\310\377\345\355\362\377\316\335\347\377d\225\264\377\0M\201" \
-  "\377\0J\177\377\0P\203\377\0N\202\377\0L\200\377\16Z\212\377C~\244\377" \
-  "w\241\275\377\210\255\305\377C}\243\377\35c\221\254C\177\244\32\0\0\0" \
-  "\0\0\15O\0\232\0\0\0\0\1\35\35\33\0\223\0\0\0\0\1\35\35\35\0\205\0\0" \
-  "\0\0\1\35\35\33\0\222\0\0\0\0\2\32\32\27\0\"\"\"\0\234\0\0\0\0\2''\32" \
-  "\0\32\32\32\0\214\0\0\0\0\1\35\35\33\0\222\0\0\0\0\1\35\35\33\0\203\0" \
-  "\0\0\0\1\34\34\34\0\223\0\0\0\0\1\35\35\34\0\213\0\0\0\0\1\34\34\31\0" \
-  "\223\0\0\0\0\3\35\35\33\0$$\22\0\31\31!\0\222\0\0\0\0\1\35\35\33\0\245" \
-  "\0\0\0\0\1\36\36\34\0\222\0\0\0\0\2__+\0\32\32\32\0\214\0\0\0\0\1\35" \
-  "\35\33\0\227\0\0\0\0\1\35\35\33\0\223\0\0\0\0\1\35\35\33\0\325\0\0\0" \
-  "\0\6-s\236\0\0\0\0\0""3x\240@\20`\217\363\0U\210\377\0V\212\377\202\0" \
-  "W\212\377\202\0X\213\377\1\0Y\213\377\202\0Y\214\377\2\0X\213\377\0Y" \
-  "\214\377\207\0Z\215\377\204\0Y\214\377\203\0X\213\377\2\0W\212\377\0" \
-  "V\212\377\202\0V\211\377\1\0V\210\377\202\0U\207\377\35\0T\206\377\0" \
-  "Q\204\377\0O\203\377\20]\214\377<y\241\377\217\262\311\377\370\372\374" \
-  "\377\377\377\377\377\321\337\351\377g\227\265\377\0O\203\377\0K\200\377" \
-  "\0N\202\377\0K\200\377\16Y\212\3778w\236\377\213\260\307\377\326\343" \
-  "\353\377\272\317\336\377;y\240\377\0D{\377\0N\201\377\0P\203\377\0N\202" \
-  "\377\0M\201\377\22\\\214\377@|\242\377_\221\261\271\213\256\306%\202" \
-  "\0\0\0\0\1u\236\275\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\237\0\0\0\0" \
-  "\1\231\314\314\0\202\0\0\0\0\4/t\235L\15]\215\370\0S\207\377\0U\210\377" \
-  "\203\0V\211\377\1\0V\212\377\216\0W\212\377\2\0V\211\377\0V\212\377\202" \
-  "\0V\211\377\3\0V\210\377\0U\210\377\0U\207\377\202\0T\206\377\202\0S" \
-  "\205\377\202\0R\204\377\26\0Q\204\377\0O\202\377\0M\201\377\17Z\212\377" \
-  "1q\233\377\210\255\305\377\365\370\372\377\370\372\374\377\273\320\336" \
-  "\377:w\237\377\0I~\377\0N\202\377\0O\202\377\0M\201\377\15Y\211\3774" \
-  "t\234\377\202\251\303\377\311\332\345\377\235\274\317\377\27`\216\377" \
-  "\0F|\377\0O\203\377\202\0P\203\377\2\21\\\213\312V\213\2552\202\0\0\0" \
-  "\0\1h\227\266\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\243\0\0\0\0\7\310" \
-  "\330\344\3/s\234O\16]\214\367\0S\205\377\0T\206\377\0T\207\377\0U\207" \
-  "\377\204\0U\210\377\210\0V\211\377\1\0V\210\377\203\0U\210\377\1\0U\207" \
-  "\377\202\0T\207\377\2\0T\206\377\0S\206\377\202\0S\205\377\203\0R\204" \
-  "\377\202\0Q\203\377\203\0P\203\377\26\0O\202\377\0M\201\377\14X\211\377" \
-  "*m\230\377\210\255\305\377\362\366\371\377\360\365\370\377\225\266\313" \
-  "\377\21[\213\377\0J\177\377\0P\203\377\0O\202\377\0N\201\377\14X\211" \
-  "\377/p\232\377}\246\300\377\271\316\335\377m\233\270\377\0O\202\377\0" \
-  "N\202\377\23]\214\3167v\2357\202\0\0\0\0\1\340\352\357\0\377\0\0\0\0" \
-  "\377\0\0\0\0\377\0\0\0\0\242\0\0\0\0\1u\243\276\0\202\0\0\0\0\6\236\275" \
-  "\320\4.r\233G\21^\215\361\0Q\204\377\0S\205\377\0S\206\377\203\0T\206" \
-  "\377\212\0U\207\377\204\0T\206\377\1\0S\206\377\203\0S\205\377\202\0" \
-  "R\204\377\2\0Q\204\377\0Q\203\377\210\0P\203\377\202\0O\202\377\11\13" \
-  "W\210\377#h\224\377\207\255\304\377\355\363\367\377\344\354\362\377d" \
-  "\225\264\377\0J\177\377\0M\201\377\0P\203\377\202\0O\202\377\6\12W\210" \
-  "\377)l\227\377w\242\275\377\231\271\316\377R\211\254\306\40f\2230\202" \
-  "\0\0\0\0\1=z\241\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\244\0\0\0\0\1" \
-  "p\236\273\0\202\0\0\0\0\4\307\327\347\2""0q\2338\33d\220\340\0P\203\377" \
-  "\202\0R\204\377\1\0R\205\377\215\0S\205\377\204\0R\204\377\2\0Q\204\377" \
-  "\0Q\203\377\216\0P\203\377\20\0O\203\377\0O\202\377\10V\207\377\34c\221" \
-  "\377\201\251\302\377\350\360\364\377\310\330\344\3770q\233\377\0H}\377" \
-  "\0O\203\377\0P\203\377\0O\203\377\0O\202\377\15Y\212\3776u\236\271\273" \
-  "\320\336\37\202\0\0\0\0\1>z\240\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0" \
-  "\246\0\0\0\0\1t\241\275\0\203\0\0\0\0\4""6v\235$\40g\222\266\2R\204\377" \
-  "\0P\203\377\203\0Q\203\377\210\0R\204\377\204\0Q\203\377\1\0Q\204\377" \
-  "\202\0Q\203\377\224\0P\203\377\13\6T\206\377\26_\216\377y\243\276\377" \
-  "\343\354\361\377\232\272\316\377\12W\210\377\0L\200\377\0O\203\377\5" \
-  "S\205\375$h\224\234\210\257\305\15\202\0\0\0\0\1B~\244\0\377\0\0\0\0" \
-  "\377\0\0\0\0\377\0\0\0\0\250\0\0\0\0\2|\242\301\0\0:n\0\202\0\0\0\0\4" \
-  "P\207\251\21)l\227\201\14X\211\377\0O\202\377\204\0P\203\377\204\0Q\203" \
-  "\377\237\0P\203\377\7\3R\205\377\22\\\214\377x\243\276\377\315\334\347" \
-  "\377`\222\263\377\12W\210\357;x\237f\203\0\0\0\0\1\213\257\307\0\377" \
-  "\0\0\0\0\377\0\0\0\0\377\0\0\0\0\253\0\0\0\0\1""5u\234\0\202\0\0\0\0" \
-  "\3\377\377\377\1<y\241G\24^\215\327\252\0P\203\377\3\24]\214\375\222" \
-  "\265\312\277\377\377\377\33\203\0\0\0\0\1t\240\273\0\377\0\0\0\0\377" \
-  "\0\0\0\0\377\0\0\0\0\256\0\0\0\0\1v\240\276\0\202\0\0\0\0\4i\226\266" \
-  "\23,m\230\212\14X\211\362\0O\203\377\245\0P\203\377\3\1Q\204\375\21\\" \
-  "\214\354A}\243h\202\0\0\0\0\1\331\344\354\0\377\0\0\0\0\377\0\0\0\0\377" \
-  "\0\0\0\0\263\0\0\0\0\1F\177\245\0\202\0\0\0\0\4H\202\246*\"g\223\257" \
-  "\11V\207\365\0P\203\375\240\0P\203\377\10\1P\203\377\1Q\204\373\13W\210" \
-  "\3610q\233\217\307\332\344\15\0\0\0\0\0N{\0\217\257\317\0\377\0\0\0\0" \
-  "\377\0\0\0\0\377\0\0\0\0\265\0\0\0\0\2\200\252\277\0\34b\221\0\202\0" \
-  "\0\0\0\5G\202\2465$h\224\260\11V\207\355\2Q\204\372\1Q\203\377\233\0" \
-  "P\203\377\5\2R\204\377\2Q\204\366\16Z\211\352(l\226\221\260\310\332\26" \
-  "\202\0\0\0\0\1k\232\267\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\271\0\0" \
-  "\0\0\2|\250\275\0\0\0K\0\202\0\0\0\0\6n\234\272).n\231\214\14X\211\327" \
-  "\3R\205\356\4R\205\371\2Q\204\377\225\0P\203\377\6\3R\205\377\2R\204" \
-  "\366\3R\204\354\37d\222\3176t\234l\377\377\377\7\202\0\0\0\0\1o\234\272" \
-  "\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\275\0\0\0\0\2\200\237\277\0:z" \
-  "\241\0\203\0\0\0\0\7B}\244E)l\227\233\17[\212\321\6T\206\345\3R\204\355" \
-  "\5T\205\372\4S\205\377\214\0P\203\377\10\2Q\204\377\5T\206\377\4S\205" \
-  "\365\5S\205\354\5S\206\341\36e\222\311!g\223\177x\242\2751\203\0\0\0" \
-  "\0\1\213\260\306\0\377\0\0\0\0\303\0\0\0\0\1\0U\200\0\206\0\0\0\0\1\0" \
-  "P\200\0\212\0\0\0\0\2\0R\200\0\0K\212\0\207\0\0\0\0\1\0O\204\0\246\0" \
-  "\0\0\0\1\0R\205\0\210\0\0\0\0\1\0@\200\0\377\0\0\0\0\262\0\0\0\0\1r\236" \
-  "\272\0\204\0\0\0\0\25y\244\2766\40f\223^(l\226\233\35c\221\301\3S\205" \
-  "\317\7U\206\333\10U\207\342\7T\206\346\4S\205\350\3R\205\350\2R\204\350" \
-  "\4S\205\350\6T\206\347\7U\207\345\11V\207\340\5S\205\327\14Y\211\315" \
-  "%i\224\270\"g\223\204@|\242W\267\317\336\31\204\0\0\0\0\1i\230\266\0" \
-  "\377\0\0\0\0\302\0\0\0\0\1\0P\203\0\205\0\0\0\0\2\0-\201\0\0^t\0\206" \
-  "\0\0\0\0\2\0[x\0\0N\205\0\204\0\0\0\0\1\0O\202\0\202\0\0\0\0\11\0P\203" \
-  "\14\0P\203#\0P\2030\0P\2033\0P\203.\0P\203\37\0M\206\3\0\0\0\0\0O\203" \
-  "\0\203\0\0\0\0\1\0P\203\0\223\0\0\0\0\1\0P\203\0\212\0\0\0\0\1\0O\203" \
-  "\0\205\0\0\0\0\3\0P\206\2\0P\206\3\0L\203\2\205\0\0\0\0\1\0P\203\0\377" \
-  "\0\0\0\0\263\0\0\0\0\1|\250\301\0\206\0\0\0\0\13\233\272\316%g\226\265" \
-  "AH\200\246M,m\230T\36d\222U\25_\216V(k\226U;x\240RR\211\253K|\245\300" \
-  "9\327\344\354\27\206\0\0\0\0\1\205\254\306\0\377\0\0\0\0\304\0\0\0\0" \
-  "\17\0O\203\0\0\0\0\0\0P\203\1\0P\203\40\0P\2035\0P\203A\0P\203S\0P\203" \
-  "V\0P\203W\0P\203L\0P\203B\0P\203<\0P\2034\0P\203*\0P\203\27\205\0\0\0" \
-  "\0\1\0I\200\0\202\0\0\0\0\3\0P\203!\0P\203\177\0P\203\326\203\0P\203" \
-  "\377\5\0P\203\305\0P\203^\0N\203\16\0\0\0\0\0N\202\0\203\0\0\0\0\3\0" \
-  "P\203\5\0P\203\36\0P\203-\217\0P\203,\1\0P\203\27\211\0\0\0\0\2\0L\204" \
-  "\0\0S\202\0\202\0\0\0\0\14\0N\203\26\0P\203/\0P\203\77\0P\203R\0P\203" \
-  "^\0P\203`\0P\203\\\0P\203O\0P\203@\0P\2035\0P\203(\0P\203\16\377\0\0" \
-  "\0\0\307\0\0\0\0\1}\245\300\0\377\0\0\0\0\310\0\0\0\0\6\0U\252\0\0\0" \
-  "\0\0\0L\203\5\0P\203Y\0P\203\273\0P\203\363\207\0P\203\377\3\0P\203\365" \
-  "\0P\203\334\0P\203\210\205\0\0\0\0\4\0T\205\0\0\0\0\0\0P\203)\0P\203" \
-  "\277\202\0P\203\377\3\0P\203\344\0P\203\332\0P\203\367\202\0P\203\377" \
-  "\2\0P\203\204\0H\177\3\204\0\0\0\0\3\0P\203\27\0P\203\231\0P\203\343" \
-  "\205\0P\203\334\204\0P\203\333\205\0P\203\334\2\0P\203\336\0P\203v\211" \
-  "\0\0\0\0\6\0R\202\0\0\0\0\0\0P\203\16\0P\203P\0O\203\242\0P\203\344\207" \
-  "\0P\203\377\3\0P\203\370\0P\203\324\0P\203L\377\0\0\0\0\377\0\0\0\0\377" \
-  "\0\0\0\0\221\0\0\0\0\4\0Oy\0\0\0\0\0\0P\203[\0P\203\371\202\0P\203\377" \
-  "\3\0P\203\362\0P\203\343\0P\203\340\202\0P\203\337\5\0P\203\340\0P\203" \
-  "\343\0P\203\351\0P\203\366\0P\203\255\206\0\0\0\0\2\0N\202\6\0P\203\253" \
-  "\202\0P\203\377\5\0P\203\251\0P\203U\0P\203B\0P\203{\0P\203\347\202\0" \
-  "P\203\377\1\0O\203F\204\0\0\0\0\2\0P\203\34\0P\203\271\220\0P\203\377" \
-  "\1\0P\203\216\210\0\0\0\0\5\0P\203\0\0\0\0\0\0O\203\20\0P\203\200\0P" \
-  "\203\366\202\0P\203\377\12\0P\203\374\0P\203\347\0P\203\336\0P\203\333" \
-  "\0P\203\334\0P\203\336\0P\203\343\0P\203\354\0P\203\371\0P\203S\377\0" \
-  "\0\0\0\377\0\0\0\0\377\0\0\0\0\223\0\0\0\0\1\0P\203\317\202\0P\203\377" \
-  "\4\0P\203\271\0P\203o\0P\203U\0P\203P\202\0P\203O\7\0P\203Q\0P\203U\0" \
-  "P\203Z\0P\203c\0P\203D\0\0\0\0\0P\207\0\204\0\0\0\0\5\0P\203I\0P\203" \
-  "\340\0P\203\377\0P\203\304\0P\203\26\203\0\0\0\0\4\0P\203y\0P\203\376" \
-  "\0P\203\377\0P\203\261\204\0\0\0\0\3\0P\203\17\0P\203b\0P\203\221\204" \
-  "\0P\203\214\2\0P\203\205\0P\203\323\202\0P\203\377\2\0P\203\250\0P\203" \
-  "\211\204\0P\203\214\2\0P\203\215\0P\203K\211\0\0\0\0\20\0P\203\1\0P\203" \
-  "k\0P\203\371\0P\203\377\0P\203\365\0P\203\270\0P\203~\0P\203\\\0P\203" \
-  "M\0P\203I\0P\203J\0P\203N\0P\203T\0P\203`\0P\203m\0O\203\32\377\0\0\0" \
-  "\0\377\0\0\0\0\377\0\0\0\0\222\0\0\0\0\5\0P\202'\0P\203\346\0P\203\377" \
-  "\0P\203\360\0P\203\40\212\0\0\0\0\1\0P\203\1\205\0\0\0\0\14\0P\203p\0" \
-  "P\203\360\0P\203\377\0P\203\177\0P\203\12\0\0\0\0\0P\201\0\0\0\0\0\0" \
-  "P\203%\0P\203\375\0P\203\377\0P\203\330\203\0\0\0\0\1\0P\203\0\210\0" \
-  "\0\0\0\1\0P\203\227\202\0P\203\377\1\0P\2031\207\0\0\0\0\1\0P\203\0\206" \
-  "\0\0\0\0\10\0P\203\0\0\0\0\0\0P\203-\0P\203\310\0P\203\377\0P\203\373" \
-  "\0P\203\226\0P\203\26\212\0\0\0\0\1\0O\203\0\377\0\0\0\0\377\0\0\0\0" \
-  "\377\0\0\0\0\221\0\0\0\0\5\0P\202A\0P\203\350\0P\203\377\0P\203\274\0" \
-  "P\203\4\220\0\0\0\0\14\0P\203l\0P\203\356\0P\203\377\0P\203\251\0P\203" \
-  "\17\0\0\0\0\0O\202\0\0\0\0\0\0Q\204<\0P\203\375\0P\203\377\0P\203\307" \
-  "\214\0\0\0\0\1\0P\203\235\202\0P\203\377\1\0P\203=\220\0\0\0\0\1\0P\203" \
-  "^\202\0P\203\377\2\0P\203\276\0P\203#\202\0\0\0\0\1\0O\203\0\222\0\0" \
-  "\0\0\2\0f\231\0\0J}\0\204\0\0\0\0\1\0P\202\0\203\0\0\0\0\1\0R\205\0\206" \
-  "\0\0\0\0\1\0N\205\0\240\0\0\0\0\1\0R\207\0\205\0\0\0\0\1\0P\203\0\377" \
-  "\0\0\0\0\377\0\0\0\0\316\0\0\0\0\5\0P\203J\0P\203\352\0P\203\377\0P\203" \
-  "\251\0P\203\7\220\0\0\0\0\5\0P\203:\0P\203\331\0P\203\377\0P\203\367" \
-  "\0P\203O\203\0\0\0\0\4\0P\203\251\0P\203\376\0P\203\377\0P\203s\214\0" \
-  "\0\0\0\1\0P\203\235\202\0P\203\377\1\0P\203=\217\0\0\0\0\2\0N\203\13" \
-  "\0P\203\212\202\0P\203\377\1\0P\203z\202\0\0\0\0\1\0U\200\0\214\0\0\0" \
-  "\0\1\0P\203\0\204\0\0\0\0\1\0P\204\0\204\0\0\0\0\3\0Q\204\20\0P\202\16" \
-  "\0P\201\2\202\0\0\0\0\1\0P\204\0\203\0\0\0\0\4\0P\203\5\0P\203\20\0N" \
-  "\203\23\0M\200\12\204\0\0\0\0\1\0P\202\0\203\0\0\0\0\1\0P\203\0\205\0" \
-  "\0\0\0\1\0O\202\0\204\0\0\0\0\1\0Q\204\0\204\0\0\0\0\3\0P\203\0\0\0\0" \
-  "\0\0P\202\0\205\0\0\0\0\1\0Q\202\0\203\0\0\0\0\3\0R\206\5\0O\203\23\0" \
-  "N\203\7\203\0\0\0\0\1\0P\204\0\377\0\0\0\0\377\0\0\0\0\314\0\0\0\0\5" \
-  "\0P\203B\0P\203\350\0P\203\377\0P\203\271\0O\204\5\221\0\0\0\0\13\0P" \
-  "\203\235\0P\203\376\0P\203\377\0P\203\331\0P\203/\0P\203\35\0P\203\221" \
-  "\0P\203\370\0P\203\377\0P\203\315\0R\203\22\214\0\0\0\0\1\0P\203\235" \
-  "\202\0P\203\377\1\0P\203=\217\0\0\0\0\7\0P\203\37\0P\203\257\0P\203\377" \
-  "\0P\203\356\0P\203W\0\0\0\0\0O\203\0\216\0\0\0\0\4\0P\203\24\0P\203\205" \
-  "\0P\203m\0P\205\30\202\0\0\0\0\23\0P\204#\0P\203s\0P\203\242\0P\203\275" \
-  "\0P\203m\0P\203\16\0\0\0\0\0P\203\1\0\0\0\0\0P\205\26\0P\203f\0P\203" \
-  "\231\0P\203\255\0P\203\265\0P\203\266\0P\203\260\0P\203\244\0P\203}\0" \
-  "P\2036\202\0\0\0\0\1\0P\203\0\203\0\0\0\0\5\0P\203#\0P\203n\0P\203\212" \
-  "\0P\203H\0N\201\7\206\0\0\0\0\4\0Q\204+\0P\203\177\0P\203\201\0P\203" \
-  ">\203\0\0\0\0\16\0P\201\2\0P\2030\0P\203\213\0P\203d\0P\203\11\0\0\0" \
-  "\0\0O\204\11\0P\203R\0P\203\217\0P\203\256\0P\203\266\0P\203\261\0P\203" \
-  "\222\0P\2042\202\0\0\0\0\1\0Q\203\0\377\0\0\0\0\377\0\0\0\0\313\0\0\0" \
-  "\0\5\0Q\203\36\0P\203\345\0P\203\377\0P\203\361\0Q\202\25\202\0\0\0\0" \
-  "\1\0P\201\0\214\0\0\0\0\4\0P\203\0\0\0\0\0\0P\203(\0P\203\317\202\0P" \
-  "\203\377\10\0P\203\306\0P\203\304\0P\203\376\0P\203\377\0P\203\315\0" \
-  "P\2032\0\0\0\0\0Q\203\0\213\0\0\0\0\1\0P\203\235\202\0P\203\377\1\0P" \
-  "\203=\217\0\0\0\0\5\0P\203-\0P\203\310\0P\203\377\0P\203\331\0P\203C" \
-  "\220\0\0\0\0\10\0P\203'\0P\203\377\0P\203\331\0P\2036\0Q\203\12\0P\203" \
-  "z\0P\203\312\0P\203\367\202\0P\203\377\2\0P\203\215\0P\204\13\202\0\0" \
-  "\0\0\3\0P\203\77\0P\203\267\0P\203\354\206\0P\203\377\3\0P\203\371\0" \
-  "P\203\320\0P\203u\202\0\0\0\0\1\0\200\200\0\202\0\0\0\0\5\0P\203D\0P" \
-  "\203\327\0P\203\377\0P\203\213\0N\201\15\206\0\0\0\0\4\0Q\204S\0P\203" \
-  "\367\0P\203\372\0P\203z\203\0\0\0\0\10\0P\201\5\0P\203]\0P\203\377\0" \
-  "P\203\305\0P\203\33\0P\203;\0P\203\257\0P\203\347\205\0P\203\377\5\0" \
-  "P\203\327\0Q\203\77\0R\203\2\0\0\0\0\0`\200\0\377\0\0\0\0\377\0\0\0\0" \
-  "\313\0\0\0\0\1\0P\203\304\202\0P\203\377\2\0P\203\267\0P\203B\205\0\0" \
-  "\0\0\1\0N\203\0\210\0\0\0\0\5\0P\200\0\0M\203\0\0\0\0\0\0P\203E\0P\203" \
-  "\342\203\0P\203\377\5\0P\203\372\0P\203\227\0P\203+\0\0\0\0\0N\202\0" \
-  "\214\0\0\0\0\1\0P\203\235\202\0P\203\377\1\0P\203=\217\0\0\0\0\5\0P\203" \
-  "4\0P\203\326\0P\203\377\0P\203\311\0P\2034\210\0\0\0\0\1\0P\203\1\204" \
-  "\0\0\0\0\1\0P\204\0\202\0\0\0\0\17\0P\203(\0P\203\377\0P\203\352\0P\203" \
-  "\224\0P\203\260\0P\203\374\0P\203\377\0P\203\360\0P\203\277\0P\203\263" \
-  "\0P\203I\0T\221\1\0\0\0\0\0P\203\40\0P\203\306\202\0P\203\377\6\0P\203" \
-  "\336\0P\203\225\0P\203w\0P\203s\0P\203\205\0P\203\275\202\0P\203\377" \
-  "\4\0P\203\352\0P\203f\0\0\0\0\0G\204\0\202\0\0\0\0\5\0P\203E\0P\203\334" \
-  "\0P\203\377\0P\203\217\0N\201\16\206\0\0\0\0\4\0Q\204U\0P\203\375\0P" \
-  "\203\377\0P\203}\203\0\0\0\0\14\0P\201\5\0P\203`\0P\203\377\0P\203\334" \
-  "\0P\203\221\0P\203\336\0P\203\377\0P\203\353\0P\203\242\0P\204\200\0" \
-  "P\203\215\0P\203\334\202\0P\203\377\4\0P\203\310\0Q\203\23\0\0\0\0\0" \
-  "H\204\0\377\0\0\0\0\377\0\0\0\0\311\0\0\0\0\4\0Q\203\0\0\0\0\0\0P\203" \
-  "H\0P\203\366\202\0P\203\377\5\0P\203\340\0P\203\311\0P\203\233\0P\203" \
-  "d\0P\203.\204\0\0\0\0\1\0P\201\0\204\0\0\0\0\1\0P\202\0\202\0\0\0\0\3" \
-  "\0P\203+\0P\203\247\0P\203\366\203\0P\203\377\2\0P\203\275\0S\203\20" \
-  "\202\0\0\0\0\1\0U\206\0\214\0\0\0\0\1\0P\203\235\202\0P\203\377\1\0P" \
-  "\203=\217\0\0\0\0\5\0P\2038\0P\203\336\0P\203\377\0P\203\301\0P\203," \
-  "\211\0\0\0\0\1\0P\203\200\202\0P\203\247\1\0P\205\17\203\0\0\0\0\13\0" \
-  "P\203'\0P\203\377\0P\203\374\0P\203\367\0P\203\377\0P\203\306\0P\203" \
-  "b\0P\203-\0P\203\37\0P\203\32\0P\203\11\202\0\0\0\0\13\0P\203\215\0P" \
-  "\203\372\0P\203\377\0Q\203\277\0P\2031\0O\203\22\0P\205\11\0N\203\7\0" \
-  "P\203\15\0P\203!\0P\203o\202\0P\203\377\2\0P\203\310\0S\203\20\203\0" \
-  "\0\0\0\5\0P\203E\0P\203\333\0P\203\377\0P\203\216\0N\201\16\206\0\0\0" \
-  "\0\4\0Q\204U\0P\203\374\0P\203\377\0P\203}\203\0\0\0\0\15\0P\201\5\0" \
-  "P\203_\0P\203\377\0P\203\371\0P\203\375\0P\203\363\0P\203\200\0P\203" \
-  "-\0Q\204\25\0Q\205\13\0P\203\16\0P\203+\0P\203\310\202\0P\203\377\2\0" \
-  "P\203N\0P\203\3\377\0\0\0\0\377\0\0\0\0\314\0\0\0\0\3\0U\210\1\0O\202" \
-  "X\0P\203\352\203\0P\203\377\6\0P\203\372\0P\203\355\0P\203\340\0P\203" \
-  "\316\0P\203\227\0P\203C\202\0\0\0\0\1\0P\204\0\202\0\0\0\0\1\0O\202\0" \
-  "\202\0\0\0\0\5\0P\203f\0P\203\326\0P\203\374\0P\203\377\0P\203\370\202" \
-  "\0P\203\377\4\0P\203\365\0P\203X\0\0\0\0\0P\203\0\205\0\0\0\0\1\0Q\203" \
-  "\0\207\0\0\0\0\1\0P\203\235\202\0P\203\377\1\0P\203=\217\0\0\0\0\5\0" \
-  "P\203<\0P\203\345\0P\203\377\0P\203\275\0P\203(\211\0\0\0\0\4\0P\203" \
-  "\302\0P\203\375\0P\203\374\0Q\202\27\203\0\0\0\0\1\0P\203'\202\0P\203" \
-  "\377\4\0P\203\326\0Q\203P\0P\204\27\0P\202\4\205\0\0\0\0\2\0J\203\5\0" \
-  "P\203\314\202\0P\203\377\1\0P\2035\206\0\0\0\0\5\0P\203\24\0P\203\273" \
-  "\0P\203\377\0P\203\346\0P\203P\203\0\0\0\0\5\0P\203E\0P\203\333\0P\203" \
-  "\377\0P\203\216\0N\201\16\206\0\0\0\0\4\0Q\204U\0P\203\374\0P\203\377" \
-  "\0P\203}\203\0\0\0\0\2\0P\201\5\0P\203_\202\0P\203\377\3\0P\203\303\0" \
-  "Q\204>\0P\202\10\205\0\0\0\0\5\0P\204k\0P\203\355\0P\203\377\0P\203\224" \
-  "\0P\203\13\377\0\0\0\0\377\0\0\0\0\313\0\0\0\0\7\0P\203\0\0\0\0\0\0N" \
-  "\201\4\0O\203\40\0P\203l\0P\203\265\0P\203\363\204\0P\203\377\7\0P\203" \
-  "\371\0P\203\352\0P\203\241\0P\206\20\0\0\0\0\0Q\205\0\0f\231\0\202\0" \
-  "\0\0\0\2\0P\203u\0P\203\356\202\0P\203\377\3\0P\203\225\0P\203%\0P\203" \
-  "\302\202\0P\203\377\10\0P\203\357\0P\203-\0\0\0\0\0P\203\1\0P\203.\0" \
-  "P\203\200\0P\203E\0R\203\25\210\0\0\0\0\1\0P\203\235\202\0P\203\377\1" \
-  "\0P\203=\217\0\0\0\0\5\0P\203=\0P\203\346\0P\203\377\0P\203\273\0P\203" \
-  "&\211\0\0\0\0\4\0P\203\303\0P\203\377\0P\203\376\0Q\202\27\203\0\0\0" \
-  "\0\1\0P\203'\202\0P\203\377\1\0P\203\254\203\0\0\0\0\2\0L\211\0\0R\200" \
-  "\0\203\0\0\0\0\7\0P\203,\0P\203\334\0P\203\377\0P\203\320\0P\203\20\0" \
-  "\0\0\0\0X\212\0\202\0\0\0\0\7\0O\203\0\0\0\0\0\0Q\203\6\0Q\203m\0P\203" \
-  "\377\0P\203\363\0P\203}\203\0\0\0\0\5\0P\203E\0P\203\333\0P\203\377\0" \
-  "P\203\216\0N\201\16\206\0\0\0\0\4\0Q\204U\0P\203\374\0P\203\377\0P\203" \
-  "}\203\0\0\0\0\5\0P\201\5\0P\203_\0P\203\377\0P\203\360\0P\203u\203\0" \
-  "\0\0\0\11\0Q\201\0\0\0\0\0\0O\203\0\0\0\0\0\0Q\203,\0P\203\332\0P\203" \
-  "\377\0P\203\303\0P\203\21\377\0\0\0\0\377\0\0\0\0\314\0\0\0\0\1\0O\202" \
-  "\0\202\0\0\0\0\7\0P\203\6\0P\203\17\0P\203\27\0O\202<\0P\203|\0P\203" \
-  "\275\0P\203\375\202\0P\203\377\2\0P\203\374\0P\203\236\202\0\0\0\0\4" \
-  "\0I|\0\0\0\0\0\0P\203V\0P\203\345\202\0P\203\377\5\0P\203m\0O\202\16" \
-  "\0\0\0\0\0O\204\35\0P\203\341\202\0P\203\377\7\0P\203\330\0P\203\14\0" \
-  "P\202\3\0P\203\204\0P\203\375\0P\203\353\0P\203\223\210\0\0\0\0\1\0P" \
-  "\203\235\202\0P\203\377\1\0P\203=\217\0\0\0\0\5\0P\2039\0P\203\340\0" \
-  "P\203\377\0P\203\276\0P\203)\211\0\0\0\0\1\0P\203\303\202\0P\203\376" \
-  "\1\0Q\202\27\203\0\0\0\0\1\0P\203'\202\0P\203\377\4\0P\203\250\0\0\0" \
-  "\0\0P~\0\0U\252\0\205\0\0\0\0\7\0P\203L\0P\203\345\0P\203\377\0P\203" \
-  "\247\0P\203\14\0\0\0\0\0N\200\0\204\0\0\0\0\5\0Q\205\1\0P\203C\0P\203" \
-  "\377\0P\203\374\0P\203\234\203\0\0\0\0\5\0P\203E\0P\203\333\0P\203\377" \
-  "\0P\203\216\0N\201\16\206\0\0\0\0\4\0Q\204U\0P\203\374\0P\203\377\0P" \
-  "\203}\203\0\0\0\0\7\0P\201\5\0P\203_\0P\203\377\0P\203\356\0P\203m\0" \
-  "\0\0\0\0Q\204\0\205\0\0\0\0\5\0Q\203\14\0P\203\320\0P\203\377\0P\203" \
-  "\343\0P\203\25\377\0\0\0\0\377\0\0\0\0\315\0\0\0\0\1\0L\204\0\204\0\0" \
-  "\0\0\5\0N\177\1\0P\203\6\0P\203\13\0P\204\32\0P\203z\202\0P\203\377\2" \
-  "\0P\203\335\0P\203H\202\0\0\0\0\2\0P\203\25\0P\203\252\202\0P\203\377" \
-  "\2\0P\203~\0P\203\13\203\0\0\0\0\2\0P\203:\0P\203\365\202\0P\203\377" \
-  "\6\0P\203\265\0[\245\1\0P\203\335\0P\203\377\0P\203\360\0Q\203`\210\0" \
-  "\0\0\0\1\0P\203\235\202\0P\203\377\1\0P\203=\217\0\0\0\0\5\0P\2036\0" \
-  "P\203\331\0P\203\377\0P\203\303\0P\203.\211\0\0\0\0\1\0P\203\303\202" \
-  "\0P\203\376\1\0Q\202\27\203\0\0\0\0\1\0P\203'\202\0P\203\377\1\0P\203" \
-  "\250\210\0\0\0\0\5\0P\203Y\0P\203\350\0P\203\377\0P\203\225\0P\203\13" \
-  "\207\0\0\0\0\1\0P\2022\202\0P\203\377\1\0P\203\250\203\0\0\0\0\5\0P\203" \
-  "E\0P\203\333\0P\203\377\0P\203\216\0N\201\16\206\0\0\0\0\4\0Q\204U\0" \
-  "P\203\374\0P\203\377\0P\203}\203\0\0\0\0\5\0P\201\5\0P\203_\0P\203\377" \
-  "\0P\203\356\0P\203n\210\0\0\0\0\4\0P\203\313\0P\203\377\0P\203\361\0" \
-  "P\203\26\377\0\0\0\0\377\0\0\0\0\326\0\0\0\0\5\0P\203\20\0P\203\214\0" \
-  "P\203\377\0P\203\367\0P\203\201\202\0\0\0\0\5\0P\203F\0P\203\332\0P\203" \
-  "\377\0P\203\326\0P\2033\202\0\0\0\0\1\0O\203\0\202\0\0\0\0\5\0Q\203c" \
-  "\0P\203\375\0P\203\377\0P\203\375\0P\203\277\202\0P\203\377\2\0P\203" \
-  "\341\0R\205\14\210\0\0\0\0\1\0P\203\235\202\0P\203\377\1\0P\203=\217" \
-  "\0\0\0\0\5\0P\203.\0P\203\312\0P\203\377\0P\203\317\0P\203:\211\0\0\0" \
-  "\0\1\0P\203\303\202\0P\203\376\1\0Q\202\27\203\0\0\0\0\1\0P\203'\202" \
-  "\0P\203\377\1\0P\203\250\210\0\0\0\0\5\0P\203a\0P\203\352\0P\203\377" \
-  "\0P\203\217\0P\203\12\207\0\0\0\0\1\0P\203+\202\0P\203\377\1\0P\203\260" \
-  "\203\0\0\0\0\5\0P\203E\0P\203\333\0P\203\377\0P\203\216\0N\201\16\206" \
-  "\0\0\0\0\4\0Q\204U\0P\203\374\0P\203\377\0P\203}\203\0\0\0\0\5\0P\201" \
-  "\5\0P\203_\0P\203\377\0P\203\356\0P\203n\210\0\0\0\0\4\0P\203\311\0P" \
-  "\203\377\0P\203\371\0P\203\27\377\0\0\0\0\377\0\0\0\0\323\0\0\0\0\5\0" \
-  "N\211\0\0R}\0\0\0\0\0\0P\203\0\0P\203K\202\0P\203\377\1\0P\203\235\202" \
-  "\0\0\0\0\11\0P\203]\0P\203\360\0P\203\377\0P\203\253\0P\203\35\0\0\0" \
-  "\0\0P\203\0\0\0\0\0\0P\203\0\202\0\0\0\0\2\0P\203\225\0P\203\376\203" \
-  "\0P\203\377\2\0P\203\370\0P\203\217\211\0\0\0\0\1\0P\203\235\202\0P\203" \
-  "\377\1\0P\203=\217\0\0\0\0\5\0P\203!\0P\203\263\0P\203\377\0P\203\337" \
-  "\0P\203J\211\0\0\0\0\1\0P\203\303\202\0P\203\376\1\0Q\202\27\203\0\0" \
-  "\0\0\1\0P\203'\202\0P\203\377\1\0P\203\250\210\0\0\0\0\5\0P\203X\0P\203" \
-  "\350\0P\203\377\0P\203\225\0P\203\13\207\0\0\0\0\1\0Q\2032\202\0P\203" \
-  "\377\1\0P\203\250\203\0\0\0\0\5\0P\203E\0P\203\333\0P\203\377\0P\203" \
-  "\216\0N\201\16\206\0\0\0\0\4\0Q\204U\0P\203\374\0P\203\377\0P\203}\203" \
-  "\0\0\0\0\5\0P\201\5\0P\203_\0P\203\377\0P\203\356\0P\203n\210\0\0\0\0" \
-  "\4\0P\203\313\0P\203\377\0P\203\361\0P\203\26\377\0\0\0\0\377\0\0\0\0" \
-  "\327\0\0\0\0\1\0Q\203:\202\0P\203\377\1\0P\203\246\202\0\0\0\0\7\0P\203" \
-  "\\\0P\203\357\0P\203\377\0P\203\266\0P\203\"\0\0\0\0\0P\203\0\205\0\0" \
-  "\0\0\1\0P\203\277\203\0P\203\377\4\0P\203\346\0P\203\27\0\0\0\0\0P\204" \
-  "\0\207\0\0\0\0\1\0P\203\235\202\0P\203\377\1\0P\203=\217\0\0\0\0\5\0" \
-  "P\203\23\0P\203\230\0P\203\377\0P\203\374\0P\203f\207\0\0\0\0\3\0P\202" \
-  "\0\0\0\0\0\0P\203\303\202\0P\203\376\1\0Q\202\27\203\0\0\0\0\1\0P\203" \
-  "'\202\0P\203\377\1\0P\203\250\210\0\0\0\0\7\0P\203L\0P\203\345\0P\203" \
-  "\377\0P\203\250\0P\203\15\0\0\0\0\0P\203\0\204\0\0\0\0\5\0N\203\2\0P" \
-  "\203E\0P\203\377\0P\203\374\0P\203\234\203\0\0\0\0\5\0P\203E\0P\203\333" \
-  "\0P\203\377\0P\203\216\0N\201\16\204\0\0\0\0\6\0Q\205\0\0\0\0\0\0Q\204" \
-  "U\0P\203\374\0P\203\377\0P\203}\203\0\0\0\0\5\0P\201\5\0P\203_\0P\203" \
-  "\377\0P\203\356\0P\203n\207\0\0\0\0\5\0M\206\11\0P\203\317\0P\203\377" \
-  "\0P\203\345\0P\203\25\377\0\0\0\0\377\0\0\0\0\324\0\0\0\0\1\0P\204\0" \
-  "\202\0\0\0\0\1\0P\203D\202\0P\203\377\1\0P\203\237\202\0\0\0\0\5\0P\203" \
-  "D\0P\203\331\0P\203\377\0P\203\360\0P\203B\202\0\0\0\0\3\0P\202\0\0\200" \
-  "\200\0\0A\204\0\202\0\0\0\0\1\0P\2039\203\0P\203\377\2\0P\203\335\0Q" \
-  "\203\31\202\0\0\0\0\1\0P\203\0\206\0\0\0\0\1\0P\203\235\202\0P\203\377" \
-  "\1\0P\203=\220\0\0\0\0\1\0P\203o\202\0P\203\377\4\0P\203\222\0P\203\7" \
-  "\0\0\0\0\0P\203\0\202\0\0\0\0\1\0O\202\0\203\0\0\0\0\1\0P\203\304\202" \
-  "\0P\203\376\1\0Q\202\27\203\0\0\0\0\1\0P\203'\202\0P\203\377\1\0P\203" \
-  "\250\210\0\0\0\0\5\0P\203,\0P\203\333\0P\203\377\0P\203\320\0P\203\21" \
-  "\202\0\0\0\0\11\0N\211\0\0\0\0\0\0P\203\0\0\0\0\0\0O\203\7\0O\203n\0" \
-  "P\203\377\0P\203\362\0P\203|\203\0\0\0\0\5\0P\203E\0P\203\333\0P\203" \
-  "\377\0P\203\216\0P\203\16\202\0\0\0\0\1\0N\201\0\203\0\0\0\0\4\0Q\204" \
-  "Y\0P\203\374\0P\203\377\0P\203}\203\0\0\0\0\10\0P\201\5\0P\203_\0P\203" \
-  "\377\0P\203\356\0P\203m\0\0\0\0\0L}\0\0Q\206\0\202\0\0\0\0\7\0R\204\0" \
-  "\0\0\0\0\0P\203)\0P\203\331\0P\203\377\0P\203\304\0P\203\21\377\0\0\0" \
-  "\0\377\0\0\0\0\313\0\0\0\0\1\0P\203\0\212\0\0\0\0\5\0P\203\12\0P\203" \
-  "w\0P\203\377\0P\203\374\0P\203\216\202\0\0\0\0\2\0P\203\25\0P\203\253" \
-  "\202\0P\203\377\2\0P\203\237\0P\203\32\204\0\0\0\0\3\0P\203\3\0P\202" \
-  "\40\0P\203\332\203\0P\203\377\3\0P\203\376\0P\203\307\0P\204\21\202\0" \
-  "\0\0\0\1\0Q\204\0\205\0\0\0\0\1\0P\203\235\202\0P\203\377\1\0P\203=\216" \
-  "\0\0\0\0\7\0Q\203\0\0\0\0\0\0P\203E\0P\203\351\0P\203\377\0P\203\330" \
-  "\0P\203D\205\0\0\0\0\7\0L\177\1\0P\204\7\0P\202R\0P\203\355\0P\203\377" \
-  "\0P\203\376\0Q\202\27\203\0\0\0\0\1\0P\203'\202\0P\203\377\1\0P\203\250" \
-  "\210\0\0\0\0\2\0H\203\3\0P\203\315\202\0P\203\377\1\0P\2033\206\0\0\0" \
-  "\0\5\0O\203\24\0O\203\275\0P\203\377\0P\203\345\0P\203Q\203\0\0\0\0\5" \
-  "\0P\203C\0P\203\331\0P\203\377\0P\203\231\0O\203\23\204\0\0\0\0\6\0N" \
-  "\202\6\0Q\205&\0P\203\275\0P\203\376\0P\203\377\0P\203}\203\0\0\0\0\5" \
-  "\0P\201\5\0P\203_\0P\203\377\0P\203\356\0P\203p\207\0\0\0\0\5\0P\203" \
-  "i\0P\203\354\0P\203\377\0P\203\227\0P\203\14\377\0\0\0\0\377\0\0\0\0" \
-  "\312\0\0\0\0\6\0M\200\0\0\0\0\0\0P\203\20\0P\203\24\0P\203\23\0P\203" \
-  "\22\202\0P\203\21\202\0P\203\20\14\0P\203\22\0P\203\26\0P\203K\0P\203" \
-  "\351\0P\203\377\0P\203\352\0P\203c\0\0\0\0\0J}\0\0\0\0\0\0P\203[\0P\203" \
-  "\352\202\0P\203\377\7\0P\203\217\0P\203\"\0P\203\17\0P\203\20\0R\203" \
-  "\24\0P\203[\0P\203\353\202\0P\203\377\2\0P\203\340\0P\203\365\202\0P" \
-  "\203\377\3\0P\203\300\0P\203\33\0T\207\1\206\0\0\0\0\1\0P\203\235\202" \
-  "\0P\203\377\1\0P\203=\220\0\0\0\0\2\0P\203\27\0P\203\240\202\0P\203\377" \
-  "\2\0P\203\275\0P\2037\202\0P\203\16\11\0P\203\17\0P\203\22\0O\2027\0" \
-  "P\203\260\0P\203\377\0P\203\367\0P\203\377\0P\203\376\0Q\202\27\203\0" \
-  "\0\0\0\1\0P\203'\202\0P\203\377\1\0P\203\250\207\0\0\0\0\15\0O\203\0" \
-  "\0\0\0\0\0P\203\215\0P\203\370\0P\203\377\0P\203\307\0P\203$\0P\203\15" \
-  "\0P\203\11\0P\203\10\0P\203\13\0P\203\27\0P\203q\202\0P\203\377\2\0P" \
-  "\203\311\0P\203\15\203\0\0\0\0\14\0P\2038\0P\203\315\0P\203\377\0P\203" \
-  "\317\0P\204=\0P\202\7\0P\203\13\0P\203\17\0O\202\40\0O\203\206\0P\203" \
-  "\374\0P\203\372\202\0P\203\377\1\0P\203}\203\0\0\0\0\11\0P\201\5\0P\203" \
-  "_\0P\203\377\0P\203\370\0P\203\252\0P\2048\0P\203\27\0P\203\20\0P\203" \
-  "\15\202\0O\203\13\2\0R\204)\0P\203\314\202\0P\203\377\2\0Q\204N\0R\205" \
-  "\3\377\0\0\0\0\377\0\0\0\0\314\0\0\0\0\12\0P\203\253\0P\203\323\0P\203" \
-  "\312\0P\203\301\0P\203\273\0P\203\266\0P\203\262\0P\203\264\0P\203\277" \
-  "\0P\203\335\203\0P\203\377\4\0P\203\274\0N\203\30\0\0\0\0\0f\231\0\202" \
-  "\0\0\0\0\2\0P\203\200\0P\203\364\202\0P\203\377\4\0P\203\352\0P\203\267" \
-  "\0P\203\260\0P\203\346\202\0P\203\377\5\0P\203\372\0P\203\312\0P\205" \
-  "\37\0P\204x\0P\203\371\202\0P\203\377\2\0P\203\310\0R\205\27\206\0\0" \
-  "\0\0\1\0P\203\236\202\0P\203\377\1\0P\203=\217\0\0\0\0\4\0P\207\0\0\0" \
-  "\0\0\0P\203D\0P\203\336\202\0P\203\377\5\0P\203\370\0P\203\302\0P\203" \
-  "\242\0P\203\251\0P\203\327\202\0P\203\377\5\0P\203\330\0P\203\210\0P" \
-  "\203\376\0P\203\377\0Q\202\27\203\0\0\0\0\1\0P\203(\202\0P\203\377\1" \
-  "\0P\203\251\211\0\0\0\0\2\0P\203\33\0P\203\312\202\0P\203\377\6\0P\203" \
-  "\360\0P\203\240\0P\203~\0P\203x\0P\203\217\0P\203\314\202\0P\203\377" \
-  "\4\0P\203\350\0P\203g\0\0\0\0\0P\203\0\202\0\0\0\0\2\0R\203\25\0P\203" \
-  "\246\202\0P\203\377\13\0P\203\327\0P\203\224\0P\203\211\0P\203\265\0" \
-  "P\203\376\0P\203\377\0P\203\355\0P\204\203\0P\203\365\0P\203\377\0P\203" \
-  "}\203\0\0\0\0\4\0P\201\5\0P\203_\0P\203\377\0P\203\375\202\0P\203\377" \
-  "\6\0P\203\360\0P\203\271\0P\203\231\0P\203\217\0P\203\247\0P\203\360" \
-  "\202\0P\203\377\4\0P\203\312\0O\203\25\0\0\0\0\0W\205\0\377\0\0\0\0\377" \
-  "\0\0\0\0\313\0\0\0\0\3\0P\203\311\0P\203\370\0P\203\376\207\0P\203\377" \
-  "\15\0P\203\373\0P\203\355\0P\203\302\0P\203B\0\0\0\0\0O\203\0\0\0\0\0" \
-  "\0P\204\0\0\0\0\0\0A\222\2\0P\203u\0P\203\330\0P\203\363\204\0P\203\377" \
-  "\4\0P\203\365\0P\203\340\0P\203\233\0P\206\14\202\0\0\0\0\5\0P\203}\0" \
-  "P\203\362\0P\203\374\0P\203\235\0O\207\4\206\0\0\0\0\4\0P\203\225\0P" \
-  "\203\375\0P\203\377\0P\203:\217\0\0\0\0\1\0P\200\0\202\0\0\0\0\3\0P\203" \
-  "U\0P\203\324\0P\203\366\204\0P\203\377\10\0P\203\372\0P\203\344\0P\203" \
-  "\247\0Q\203\32\0P\203\"\0P\203\357\0P\203\361\0Q\202\26\203\0\0\0\0\4" \
-  "\0P\203%\0P\203\366\0P\203\367\0P\203\237\210\0\0\0\0\6\0P\203\0\0\0" \
-  "\0\0\0P\2037\0P\203\301\0P\203\354\0P\203\376\205\0P\203\377\3\0P\203" \
-  "\363\0P\203\327\0P\203w\204\0\0\0\0\5\0Qz\0\0\0\0\0\0P\203Q\0P\203\330" \
-  "\0P\203\376\204\0P\203\377\7\0P\203\350\0P\203\274\0P\202>\0\0\0\0\0" \
-  "P\203\320\0P\203\362\0P\203v\203\0\0\0\0\10\0P\201\5\0P\203_\0P\203\377" \
-  "\0P\203\355\0P\203\261\0P\203\273\0P\203\352\0P\203\375\204\0P\203\377" \
-  "\6\0P\203\365\0P\203\325\0Q\2045\0\\\227\1\0\0\0\0\0@\200\0\377\0\0\0" \
-  "\0\377\0\0\0\0\313\0\0\0\0\17\0P\203L\0P\203w\0P\203\225\0P\203\253\0" \
-  "P\203\274\0P\203\302\0P\203\305\0P\203\306\0P\203\303\0P\203\270\0P\203" \
-  "\231\0P\203_\0N\203\23\0\0\0\0\0P\203\1\203\0\0\0\0\1\0O\204\0\202\0" \
-  "\0\0\0\10\0P\203(\0P\203|\0P\203\263\0P\203\304\0P\203\306\0P\203\266" \
-  "\0P\203\204\0P\2032\202\0\0\0\0\1\0P\203\0\202\0\0\0\0\5\0P\203a\0P\203" \
-  "\246\0P\203\13\0\0\0\0\0P\204\0\205\0\0\0\0\1\0P\203L\202\0P\203\201" \
-  "\1\0P\203\35\220\0\0\0\0\1\0P\204\0\202\0\0\0\0\10\0P\203$\0P\203\202" \
-  "\0P\203\271\0P\203\310\0P\203\307\0P\203\266\0P\203\206\0Q\2035\202\0" \
-  "\0\0\0\4\0V\201\7\0P\203y\0P\203z\0Q\203\13\203\0\0\0\0\4\0P\203\23\0" \
-  "P\203|\0P\203}\0P\203P\211\0\0\0\0\14\0P\203\1\0\0\0\0\0P\207\11\0P\203" \
-  "a\0P\203\237\0P\203\300\0P\203\306\0P\203\307\0P\203\302\0P\203\260\0" \
-  "P\203|\0P\203*\202\0\0\0\0\1\0N\204\0\202\0\0\0\0\1\0Q\206\0\202\0\0" \
-  "\0\0\7\0P\203<\0P\203\240\0P\203\304\0P\203\310\0P\203\275\0P\203\220" \
-  "\0Q\203E\203\0\0\0\0\3\0P\203b\0P\203z\0P\204;\203\0\0\0\0\16\0P\201" \
-  "\5\0P\203_\0P\203\377\0P\203\352\0P\203^\0\0\0\0\0P\203J\0P\203\213\0" \
-  "P\203\263\0P\203\304\0P\203\305\0P\203\263\0P\203\177\0O\204\32\202\0" \
-  "\0\0\0\1\0Q\205\0\377\0\0\0\0\377\0\0\0\0\312\0\0\0\0\2\0R\200\0\0L\211" \
-  "\0\215\0\0\0\0\1\0O\203\0\205\0\0\0\0\2\0S\200\0\0B\221\0\211\0\0\0\0" \
-  "\3\0U\252\0\0\0\0\0\0P\203\0\204\0\0\0\0\1\0P\203\0\204\0\0\0\0\2\0U" \
-  "\252\0\0O~\1\204\0\0\0\0\1\0P\203\0\220\0\0\0\0\2\0M\202\0\0[\207\0\211" \
-  "\0\0\0\0\1\0O\202\0\204\0\0\0\0\3\0Q\203\0\0\0\0\0\0P\203\0\204\0\0\0" \
-  "\0\1\0P\203\1\211\0\0\0\0\1\0P\204\0\212\0\0\0\0\2\0L\205\0\0U\200\0" \
-  "\204\0\0\0\0\1\0R\205\0\211\0\0\0\0\2\0Qy\0\0P\203\0\203\0\0\0\0\1\0" \
-  "P\204\0\202\0\0\0\0\5\0P\201\5\0P\203_\0P\203\377\0P\203\355\0P\203m" \
-  "\212\0\0\0\0\1\0O\204\0\377\0\0\0\0\377\0\0\0\0\321\0\0\0\0\1\0U\210" \
-  "\0\205\0\0\0\0\1\0U\252\0\213\0\0\0\0\1\0I\222\0\204\0\0\0\0\1\0R\203" \
-  "\0\205\0\0\0\0\1\0T\202\0\202\0\0\0\0\1\0T\202\0\237\0\0\0\0\1\0P\204" \
-  "\0\204\0\0\0\0\1\0T\202\0\233\0\0\0\0\1\0U\200\0\204\0\0\0\0\1\0S\204" \
-  "\0\212\0\0\0\0\2\0`\200\0\0\0\244\0\203\0\0\0\0\2\0\27\202\0\0\200\200" \
-  "\0\211\0\0\0\0\5\0P\201\5\0P\203_\0P\203\377\0P\203\356\0P\203n\202\0" \
-  "\0\0\0\1\0U\200\0\204\0\0\0\0\1\0P\200\0\377\0\0\0\0\377\0\0\0\0\377" \
-  "\0\0\0\0\326\0\0\0\0\5\0P\201\5\0P\203_\0P\203\377\0P\203\356\0P\203" \
-  "n\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\336\0\0\0\0\5\0P\201\5\0P\203_" \
-  "\0P\203\377\0P\203\356\0P\203n\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\336" \
-  "\0\0\0\0\5\0P\201\5\0P\203b\0P\203\377\0P\203\366\0P\203q\377\0\0\0\0" \
-  "\377\0\0\0\0\377\0\0\0\0\336\0\0\0\0\5\0Q\203\3\0P\203F\0P\203\310\0" \
-  "P\203\257\0P\203P\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\336\0\0\0\0\5\0" \
-  "S\206\1\0Q\204\17\0P\203*\0P\203%\0P\203\21\377\0\0\0\0\377\0\0\0\0\377" \
-  "\0\0\0\0\335\0\0\0\0\1\0Q\204\0\205\0\0\0\0\1\0P\203\0\377\0\0\0\0\377" \
-  "\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0" \
-  "\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0" \
-  "\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377" \
-  "\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0" \
-  "\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0" \
-  "\0\0\321\0\0\0\0")
-
-
-/* GdkPixbuf RGBA C-Source image dump 1-byte-run-length-encoded */
-
-#define SPLASH_IMG_ROT_ROWSTRIDE (1920)
-#define SPLASH_IMG_ROT_WIDTH (480)
-#define SPLASH_IMG_ROT_HEIGHT (162)
-#define SPLASH_IMG_ROT_BYTES_PER_PIXEL (4) /* 3:RGB, 4:RGBA */
-#define SPLASH_IMG_ROT_RLE_PIXEL_DATA ((uint8_t*) \
-  "\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0" \
-  "\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0" \
-  "\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377" \
-  "\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0" \
-  "\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0" \
-  "\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377" \
-  "\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0" \
-  "\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0" \
-  "\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377" \
-  "\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0" \
-  "\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0" \
-  "\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377" \
-  "\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0" \
-  "\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0" \
-  "\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377" \
-  "\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0" \
-  "\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0" \
-  "\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377" \
-  "\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0" \
-  "\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0" \
-  "\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377" \
-  "\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0" \
-  "\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0" \
-  "\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377" \
-  "\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0" \
-  "\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\376\0\0" \
-  "\0\0\1\235\274\327\0\212\0\0\0\0\2\0Ni\0\353\353\377\0\377\0\0\0\0\377" \
-  "\0\0\0\0\377\0\0\0\0\321\0\0\0\0\1\242\276\327\0\206\0\0\0\0\10\377\377" \
-  "\377\13\260\312\337'\231\273\3239\215\263\317@\210\257\315C\225\270\324" \
-  ">\240\277\3314\301\325\344\40\207\0\0\0\0\1\203\260\313\0\377\0\0\0\0" \
-  "\377\0\0\0\0\377\0\0\0\0\311\0\0\0\0\1\222\264\323\0\203\0\0\0\0\24\377" \
-  "\377\377\0\217\264\321DX\217\273f`\225\276\240[\221\274\310H\204\265" \
-  "\326>\177\261\335@\177\260\342>~\257\346;}\255\3479|\255\3507{\253\347" \
-  "4x\252\345/v\250\341,u\247\3335{\252\324D\205\260\277;\201\254\213I\213" \
-  "\263b\220\270\320-\205\0\0\0\0\1}\262\312\0\377\0\0\0\0\377\0\0\0\0\377" \
-  "\0\0\0\0\302\0\0\0\0\1\233\274\330\0\203\0\0\0\0\33\267\315\342#j\231" \
-  "\302hg\230\302\275O\211\271\342M\207\267\355J\205\266\362I\204\266\372" \
-  "H\203\265\377D\201\263\377A\177\261\377>~\260\377<}\257\377:|\256\377" \
-  "7z\254\3774x\253\3772w\251\377/v\250\377,t\247\377*s\246\377(s\245\376" \
-  "$q\243\367\37o\242\361\32m\240\353(x\246\340+|\250\240U\227\272]\377" \
-  "\377\377\5\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\302\0\0\0\0\1\222\264" \
-  "\325\0\202\0\0\0\0\40\377\377\377\7x\243\311[i\230\303\307V\214\274\356" \
-  "R\211\272\366R\212\273\375P\210\271\377M\207\270\377M\206\267\377K\205" \
-  "\267\377I\205\266\377G\203\266\377E\202\264\377C\201\263\377@\177\261" \
-  "\377>}\257\377<|\256\3779{\255\3775y\253\3773x\252\3770v\250\377,t\246" \
-  "\377)r\245\377%q\244\377!o\242\377\34m\240\377\31m\240\377\25k\236\373" \
-  "\16j\235\365\21o\240\354#z\250\243j\246\304J\203\0\0\0\0\1\220\274\323" \
-  "\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\272\0\0\0\0\1\220\263\324\0\202" \
-  "\0\0\0\0$\262\312\342\32y\243\313\204_\222\300\343X\215\275\372X\214" \
-  "\275\376W\214\275\377V\214\274\377U\213\274\377T\213\274\377S\212\273" \
-  "\377R\211\272\377O\210\271\377O\207\270\377K\206\267\377I\205\266\377" \
-  "G\203\265\377E\202\264\377B\200\262\377@~\260\377=}\257\3779{\255\377" \
-  "6y\253\3774x\252\3770v\250\377-t\246\377)r\245\377%q\244\377\40n\241" \
-  "\377\34m\240\377\30l\237\377\21j\235\377\11i\234\377\3h\233\374\1g\231" \
-  "\370\36v\243\330B\213\261b\202\0\0\0\0\2\1c\217\0\252\306\343\0\377\0" \
-  "\0\0\0\377\0\0\0\0\377\0\0\0\0\266\0\0\0\0\1\240\275\333\0\202\0\0\0" \
-  "\0\3\253\305\336\25x\244\313\205b\223\302\352\205[\217\277\377\202Z\216" \
-  "\277\377\36X\215\276\377W\214\275\377V\214\274\377T\213\274\377R\211" \
-  "\272\377Q\211\271\377N\207\270\377K\206\267\377I\204\266\377F\202\264" \
-  "\377D\201\263\377@\177\261\377>}\257\377:{\255\3776y\254\3773x\252\377" \
-  "0v\250\377,t\247\377)s\246\377$q\244\377\40o\242\377\33m\240\377\26k" \
-  "\236\377\17j\235\377\10h\233\377\1f\232\377\1f\231\377\1d\227\374\31" \
-  "q\240\345E\212\260a\202\0\0\0\0\1\377\377\377\0\377\0\0\0\0\377\0\0\0" \
-  "\0\377\0\0\0\0\262\0\0\0\0\1\241\275\333\0\203\0\0\0\0\4\317\335\356" \
-  "\10\201\250\316bh\227\304\342^\220\301\377\205`\222\302\377'_\221\302" \
-  "\377_\221\301\377_\220\301\377]\217\300\377\\\217\277\377[\216\276\377" \
-  "X\215\276\377W\214\275\377T\213\273\377R\211\272\377P\210\271\377M\206" \
-  "\270\377J\205\267\377G\203\265\377D\201\263\377A\200\262\377>~\260\377" \
-  ":|\256\3776y\253\3773w\251\3770v\250\377+t\246\377(r\245\377$p\243\377" \
-  "\36o\242\377\31l\237\377\25k\236\377\15i\234\377\5g\232\377\0f\231\377" \
-  "\0d\227\377\0b\225\377\14h\230\376\247\310\331\314\377\377\377+\0\0\0" \
-  "\0\377\377\377\0\0\0\0\0\377\377\377\0\377\0\0\0\0\377\0\0\0\0\377\0" \
-  "\0\0\0\256\0\0\0\0\1\211\256\321\0\203\0\0\0\0\4\205\255\321+s\237\311" \
-  "\270d\225\304\377b\223\303\377\202d\224\304\377\205e\225\305\377\34d" \
-  "\224\304\377c\224\303\377b\223\303\377`\222\302\377_\221\301\377\\\217" \
-  "\300\377[\216\277\377Y\215\276\377V\213\274\377S\212\273\377Q\211\272" \
-  "\377N\207\270\377K\205\267\377H\203\265\377E\201\263\377B\200\262\377" \
-  ">~\260\377:|\256\3776y\254\3772w\252\377/v\250\377+s\246\377'q\244\377" \
-  "\"p\243\377\35m\240\377\30l\237\377\22j\235\377\12h\233\377\202\3g\232" \
-  "\377\6-\177\251\377\322\343\354\377\377\377\377\377\377\377\377\371\377" \
-  "\377\377\204\377\377\377\10\202\0\0\0\0\2U\220\262\0\377\377\377\0\377" \
-  "\0\0\0\0\377\0\0\0\0\377\0\0\0\0\253\0\0\0\0\1\206\254\321\0\202\0\0" \
-  "\0\0\10\244\277\334\13\177\247\316al\232\307\356b\224\304\377e\226\305" \
-  "\377g\226\306\377i\227\307\377i\230\307\377\204j\231\310\377\40j\230" \
-  "\307\377i\230\307\377h\227\306\377g\226\305\377e\225\305\377c\224\304" \
-  "\377a\222\302\377_\221\301\377\\\220\300\377Z\216\276\377X\214\275\377" \
-  "U\213\274\377R\211\272\377N\207\270\377K\206\267\377H\203\265\377E\201" \
-  "\264\377@\177\262\377=}\257\377:{\255\3776y\254\3772w\251\377.u\247\377" \
-  ")t\246\377%q\244\377!o\242\377\34m\240\377\26k\237\377\17i\234\377\17" \
-  "m\236\377j\245\303\377\374\375\376\377\204\377\377\377\377\2\376\376" \
-  "\377\315\332\347\3560\202\0\0\0\0\202\377\377\377\0\377\0\0\0\0\377\0" \
-  "\0\0\0\377\0\0\0\0\250\0\0\0\0\2\306\306\343\0s\243\313\0\202\0\0\0\0" \
-  "\12\212\256\322\33x\242\313\221i\230\306\377e\225\305\377h\227\307\377" \
-  "j\230\310\377k\231\310\377l\232\311\377m\233\311\377n\233\312\377\204" \
-  "o\233\312\377\35m\233\311\377l\231\311\377k\231\310\377j\230\307\377" \
-  "h\227\306\377e\225\305\377c\224\304\377a\222\302\377^\221\301\377[\217" \
-  "\277\377X\215\276\377V\213\274\377R\211\272\377N\210\271\377K\205\267" \
-  "\377H\203\265\377D\201\263\377@\177\261\377=}\257\3778{\255\3774y\253" \
-  "\3771w\251\377-u\247\377(s\245\377#q\243\377\36n\241\377\34n\240\377" \
-  "1|\252\377\270\323\342\377\205\377\377\377\377\5\366\371\373\377\320" \
-  "\341\353\377\203\257\307\362\210\261\311o\377\377\377\2\202\0\0\0\0\1" \
-  "\377\377\377\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\246\0\0\0\0\2\256" \
-  "\311\344\0""4v\260\0\202\0\0\0\0\13\204\253\320+w\242\313\274e\225\305" \
-  "\377g\227\306\377k\231\310\377m\232\311\377n\233\312\377p\234\313\377" \
-  "r\235\314\377s\236\315\377t\237\315\377\203t\237\316\377\35s\237\315" \
-  "\377r\236\315\377q\235\314\377p\234\313\377n\233\312\377l\232\311\377" \
-  "j\231\307\377h\226\306\377e\224\304\377b\223\303\377_\221\301\377\\\217" \
-  "\300\377Y\215\276\377V\213\274\377R\212\273\377N\207\270\377K\205\266" \
-  "\377H\203\264\377C\200\262\377\77~\260\377;|\256\3777z\254\3773x\252" \
-  "\3770v\250\377*s\246\377#p\242\377)u\246\377b\233\276\377\354\363\367" \
-  "\377\204\377\377\377\377\10\370\373\374\377\333\350\360\377\177\256\310" \
-  "\377:\202\252\377\266\320\336\377\377\377\377\372\377\377\377\215\377" \
-  "\377\377\14\202\0\0\0\0\1v\244\300\0\377\0\0\0\0\377\0\0\0\0\377\0\0" \
-  "\0\0\244\0\0\0\0\2\271\321\350\0\11Q\233\0\202\0\0\0\0\13\200\247\317" \
-  "7u\240\313\331d\224\305\377j\230\307\376m\232\311\377o\233\312\377r\235" \
-  "\314\377s\236\315\377u\240\316\377w\241\317\377x\241\320\377\202y\242" \
-  "\320\377\35y\243\321\377y\242\320\377x\242\320\377w\241\320\377v\241" \
-  "\317\377t\237\316\377s\237\315\377q\235\314\377o\233\312\377l\231\310" \
-  "\377i\230\307\377e\226\305\377b\224\303\377`\222\302\377\\\217\300\377" \
-  "Y\215\276\377U\213\274\377R\211\272\377N\207\270\377J\205\266\377E\202" \
-  "\264\377B\200\262\377\77~\260\377:{\255\3776y\253\3770v\250\377,t\247" \
-  "\377>\201\256\377\237\300\327\377\204\377\377\377\377\13\374\376\376" \
-  "\377\337\354\362\377\220\274\322\377,|\246\377Y\227\271\377\361\366\371" \
-  "\377\377\377\377\377\376\377\377\377\377\377\377\377\377\377\377\243" \
-  "\377\377\377\30\202\0\0\0\0\1\377\377\377\0\377\0\0\0\0\377\0\0\0\0\377" \
-  "\0\0\0\0\243\0\0\0\0\1r\236\310\0\202\0\0\0\0\17\177\247\317=s\236\312" \
-  "\344e\225\305\377k\230\310\377m\232\311\377p\234\313\377s\236\315\377" \
-  "v\240\316\377x\241\320\377y\242\321\377{\244\321\377|\245\322\377}\245" \
-  "\323\377~\245\323\377~\245\322\377\202}\245\323\377\31|\244\322\377{" \
-  "\244\321\377z\242\321\377w\241\317\377t\237\316\377r\236\314\377p\234" \
-  "\313\377l\232\311\377j\230\307\377f\225\305\377c\223\303\377_\221\301" \
-  "\377\\\217\277\377Y\215\276\377U\213\274\377P\211\271\377M\206\267\377" \
-  "I\204\265\377E\202\263\377A\177\261\377=}\257\3774x\253\377:|\255\377" \
-  "d\230\276\377\326\344\356\377\204\377\377\377\377\5\344\356\364\377\247" \
-  "\312\334\3772\204\255\377\36v\244\377\236\303\326\377\205\377\377\377" \
-  "\377\3\336\351\360\377\251\306\327\262R\215\257$\202\0\0\0\0\1\377\377" \
-  "\377\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\244\0\0\0\0\20\201\251\317" \
-  "<r\236\312\346e\225\305\377k\231\310\377n\233\312\377q\235\314\377t\237" \
-  "\315\377w\241\317\377y\243\320\377|\244\322\377~\246\323\377\200\250" \
-  "\324\377\201\250\324\377\202\250\325\377\202\251\325\377\203\251\325" \
-  "\377\202\202\250\325\377\30\201\247\324\377\177\247\324\377~\245\323" \
-  "\377|\244\321\377y\243\321\377v\241\317\377t\237\316\377p\234\313\377" \
-  "n\232\311\377j\230\307\377f\226\305\377c\223\303\377_\221\301\377[\217" \
-  "\277\377W\215\275\377T\212\273\377P\207\270\377L\205\267\377H\203\265" \
-  "\377A\200\262\377;{\256\377M\210\265\377\223\270\322\377\366\371\374" \
-  "\377\203\377\377\377\377\6\353\362\367\377\275\325\344\377Q\222\270\377" \
-  "\12i\233\377M\225\271\377\333\351\361\377\204\377\377\377\377\6\353\363" \
-  "\367\377\255\312\332\377U\220\262\377d\232\270\377\303\327\343\256\377" \
-  "\377\377\33\202\0\0\0\0\1\377\377\377\0\377\0\0\0\0\377\0\0\0\0\377\0" \
-  "\0\0\0\240\0\0\0\0\21\204\253\317\0\0\0\0\0\210\254\3211r\237\311\340" \
-  "e\225\305\377j\231\310\377n\233\312\377q\236\314\377u\237\316\377y\242" \
-  "\317\377|\244\321\377~\246\323\377\201\247\324\377\203\251\325\377\205" \
-  "\252\326\377\206\253\327\377\207\254\330\377\202\207\254\331\377\24\210" \
-  "\254\330\377\207\253\330\377\206\253\327\377\204\252\326\377\203\250" \
-  "\325\377\200\247\324\377}\245\323\377{\244\321\377w\242\320\377t\237" \
-  "\315\377q\234\313\377m\232\311\377j\230\307\377f\225\305\377b\223\303" \
-  "\377^\220\300\377Z\216\276\377V\214\275\377R\211\272\377N\207\270\377" \
-  "\202F\202\265\377\2i\232\302\377\303\326\346\377\203\377\377\377\377" \
-  "\6\364\370\372\377\310\333\350\377s\245\304\377\25i\236\3770}\252\377" \
-  "\216\272\321\377\204\377\377\377\377\14\366\372\373\377\272\323\341\377" \
-  "_\231\271\377.x\242\377\210\262\312\377\371\373\374\377\377\377\377\377" \
-  "\376\376\377\237\377\377\377\25\0\0\0\0\323\337\353\0U\252\252\0\377" \
-  "\0\0\0\0\377\0\0\0\0\377\0\0\0\0\236\0\0\0\0\23\223\264\325\0\0\0\0\0" \
-  "\216\262\323\40s\236\311\314e\224\305\377j\230\307\377n\233\312\377q" \
-  "\235\314\377v\240\316\377y\242\320\377|\245\321\377\177\247\324\377\202" \
-  "\250\326\377\205\252\327\377\207\254\327\377\211\255\330\377\212\255" \
-  "\331\377\212\257\332\377\213\257\332\377\202\214\257\332\377\26\213\256" \
-  "\332\377\212\256\331\377\210\254\331\377\206\253\330\377\204\251\326" \
-  "\377\202\250\325\377~\246\323\377{\244\322\377x\242\320\377t\237\316" \
-  "\377q\234\313\377m\232\311\377i\230\307\377e\225\304\377`\222\302\377" \
-  "]\217\300\377Y\215\276\377T\212\273\377K\204\267\377X\216\274\377\220" \
-  "\265\323\377\345\356\365\377\202\377\377\377\377\7\374\375\376\377\321" \
-  "\340\354\377\214\264\317\3770x\250\377\34l\240\377^\230\274\377\305\332" \
-  "\347\377\204\377\377\377\377\5\306\334\350\377t\250\304\377\37r\237\377" \
-  "D\210\255\377\301\327\343\377\204\377\377\377\377\4\377\377\377\213\377" \
-  "\377\377\15\0\0\0\0\272\315\337\0\232\0\0\0\0\1\34\34\34\0\223\0\0\0" \
-  "\0\1\33\33\33\0\377\0\0\0\0\377\0\0\0\0\355\0\0\0\0\23\252\304\336\0" \
-  "\0\0\0\0\301\322\346\14s\237\311\255c\223\304\377i\227\307\377l\232\311" \
-  "\377q\234\313\377t\237\315\377y\242\320\377|\245\322\377\200\247\324" \
-  "\377\203\251\326\377\206\253\330\377\210\255\331\377\213\256\331\377" \
-  "\215\257\333\377\217\260\333\377\217\261\334\377\202\220\262\334\377" \
-  "\26\220\261\334\377\217\260\334\377\216\260\333\377\214\257\332\377\212" \
-  "\255\332\377\210\254\330\377\205\252\327\377\202\250\325\377~\246\324" \
-  "\377{\244\322\377x\242\320\377t\236\315\377o\234\313\377k\231\310\377" \
-  "g\226\306\377c\224\304\377_\221\301\377Y\215\276\377S\212\273\377q\236" \
-  "\307\377\271\317\343\377\372\374\375\377\202\377\377\377\377\7\333\347" \
-  "\360\377\234\276\326\377M\211\265\377\35j\240\377\77\201\257\377\215" \
-  "\266\320\377\361\366\371\377\203\377\377\377\377\6\324\345\356\377\206" \
-  "\266\316\377&z\245\377\16i\231\377~\256\310\377\353\362\367\377\204\377" \
-  "\377\377\377\6\354\363\366\377\226\270\315\367u\242\275p\267\315\335" \
-  "\6\0\0\0\0\377\377\377\0\232\0\0\0\0\2\33\33\35\3\37\37\35\12\217\37" \
-  "\37\35\13\1\36\36\35\6\377\0\0\0\0\377\0\0\0\0\357\0\0\0\0)\77{\263\0" \
-  "\0\0\0\0x\242\313\204e\226\304\377f\226\306\377k\231\310\377n\234\313" \
-  "\377s\236\315\377w\241\317\377{\244\322\377\200\247\324\377\204\251\326" \
-  "\377\207\253\330\377\212\255\331\377\214\257\332\377\217\261\333\377" \
-  "\221\262\334\377\223\263\335\377\224\264\336\377\225\265\336\377\225" \
-  "\266\337\377\224\265\336\377\223\264\335\377\222\263\335\377\220\262" \
-  "\334\377\216\260\333\377\214\256\332\377\211\255\331\377\205\252\327" \
-  "\377\203\251\325\377~\246\323\377{\244\321\377v\241\317\377r\236\314" \
-  "\377n\233\312\377j\230\307\377f\225\305\377]\217\301\377a\222\301\377" \
-  "\222\265\324\377\333\346\361\377\202\377\377\377\377\7\347\357\365\377" \
-  "\253\307\335\377f\231\300\3771u\252\377)q\246\377e\232\277\377\273\323" \
-  "\343\377\203\377\377\377\377\6\350\361\366\377\231\300\326\377=\213\262" \
-  "\377\0^\223\377=\210\257\377\262\317\337\377\204\377\377\377\377\6\373" \
-  "\374\375\377\262\314\334\377^\224\264\377V\215\257\377\263\314\333\347" \
-  "\370\372\374D\202\0\0\0\0\1\377\377\377\0\231\0\0\0\0\3\34\34\33)\35" \
-  "\35\33\220\35\35\33\231\215\35\35\33\230\3\35\35\33\240\35\35\33U\32" \
-  "\32#\2\377\0\0\0\0\377\0\0\0\0\355\0\0\0\0""2\213\257\322\0\0\0\0\0\206" \
-  "\254\317Lf\226\304\366d\224\304\377i\230\307\377m\232\311\377q\235\314" \
-  "\377v\240\316\377z\243\321\377~\246\323\377\202\251\325\377\206\253\330" \
-  "\377\211\255\331\377\215\257\332\377\220\261\334\377\223\263\335\377" \
-  "\225\265\336\377\227\266\337\377\230\267\337\377\231\270\340\377\231" \
-  "\270\341\377\230\267\340\377\230\267\337\377\227\265\336\377\224\264" \
-  "\336\377\222\262\335\377\217\260\334\377\214\257\333\377\211\255\331" \
-  "\377\205\252\327\377\201\250\325\377}\246\323\377y\242\320\377t\240\316" \
-  "\377q\235\313\377k\231\311\377c\223\304\377u\240\312\377\265\315\342" \
-  "\377\362\366\372\377\377\377\377\377\363\367\372\377\271\317\342\377" \
-  "{\246\312\377F\202\264\3771u\253\377C\201\262\377\216\263\321\377\341" \
-  "\353\363\377\202\377\377\377\377\7\372\374\375\377\254\312\334\377]\231" \
-  "\275\377\15i\234\377\3g\233\377u\254\310\377\330\347\357\377\204\377" \
-  "\377\377\377\12\306\332\346\377d\232\271\3771x\241\377k\235\273\377\331" \
-  "\346\356\377\377\377\377\377\377\377\377\272\376\377\377\35\0\0\0\0\377" \
-  "\377\377\0\231\0\0\0\0\2\34\34\33H\35\35\33\375\217\35\35\33\377\2\35" \
-  "\35\33\225\35\35%\4\365\0\0\0\0\1\34\34\33\0\223\0\0\0\0\1\34\34\34\0" \
-  "\377\0\0\0\0\341\0\0\0\0\25\266\333\333\0\0\0\0\0\271\316\344\21j\230" \
-  "\305\327`\222\302\377f\226\305\377k\231\310\377o\234\313\377s\237\315" \
-  "\377x\242\317\377}\245\322\377\200\247\324\377\204\252\327\377\210\254" \
-  "\331\377\214\257\332\377\220\261\334\377\223\263\335\377\226\265\337" \
-  "\377\230\267\337\377\233\271\340\377\234\272\341\377\202\235\272\341" \
-  "\377\21\234\272\341\377\234\271\341\377\232\270\340\377\230\266\337\377" \
-  "\225\264\336\377\222\263\335\377\217\260\334\377\213\257\332\377\207" \
-  "\254\331\377\204\251\326\377\200\247\324\377{\244\321\377v\241\317\377" \
-  "p\234\314\377l\231\311\377\222\264\326\377\326\343\357\377\202\377\377" \
-  "\377\377\10\310\332\352\377\213\260\321\377X\215\274\377B\200\263\377" \
-  "8y\256\377e\230\300\377\266\316\341\377\371\373\375\377\202\377\377\377" \
-  "\377\7\302\327\345\377q\243\304\377-y\250\377\4`\227\377:\204\256\377" \
-  "\247\312\334\377\370\373\374\377\203\377\377\377\377\6\335\351\360\377" \
-  "y\252\305\377#q\235\377-v\240\377\237\300\323\377\365\370\373\377\203" \
-  "\377\377\377\377\4\377\377\377|\377\377\377\10\0\0\0\0N\205\252\0\230" \
-  "\0\0\0\0\2\34\34\33E\35\35\33\361\217\35\35\33\377\2\35\35\33\216\35" \
-  "\35%\3\366\0\0\0\0\3\34\34\33\11\35\35\33""4\35\35\33Q\216\35\35\33N" \
-  "\2\35\35\33J\34\34\35\4\377\0\0\0\0\342\0\0\0\0""0p\232\310\0\0\0\0\0" \
-  "s\240\310\225_\221\301\377b\224\304\377g\227\306\377l\232\311\377q\235" \
-  "\314\377u\240\316\377z\243\321\377~\246\323\377\202\251\326\377\206\253" \
-  "\327\377\213\256\331\377\217\261\333\377\223\263\335\377\226\265\337" \
-  "\377\231\267\340\377\234\271\341\377\236\273\342\377\240\274\343\377" \
-  "\241\275\344\377\242\275\344\377\242\275\343\377\240\274\343\377\235" \
-  "\273\342\377\233\271\341\377\230\266\337\377\225\265\336\377\221\262" \
-  "\335\377\216\257\333\377\212\256\332\377\206\253\327\377\202\250\325" \
-  "\377}\245\322\377u\237\317\377z\243\317\377\265\314\344\377\360\365\372" \
-  "\377\377\377\377\377\332\345\361\377\230\270\327\377i\230\304\377P\210" \
-  "\272\377H\203\266\377H\204\266\377\214\262\321\377\330\345\357\377\202" \
-  "\377\377\377\377\7\326\344\356\377\203\255\313\377F\207\261\377\31j\237" \
-  "\377\25i\235\377v\250\306\377\321\342\354\377\203\377\377\377\377\6\360" \
-  "\366\371\377\212\266\315\3770|\246\377\10a\224\377X\223\265\377\320\340" \
-  "\352\377\205\377\377\377\377\3\256\307\327\357T\211\254F\0\0\0\1\231" \
-  "\0\0\0\0\2\34\34\33E\35\35\33\361\217\35\35\33\377\2\35\35\33\216\35" \
-  "\35%\3\366\0\0\0\0\3\34\34\33\31\35\35\33\225\35\35\33\347\216\35\35" \
-  "\33\336\2\35\35\33\324\32\32\33\15\377\0\0\0\0\341\0\0\0\0\26\252\304" \
-  "\336\0\0\0\0\0\213\257\3216a\223\301\355_\222\302\377d\225\305\377h\230" \
-  "\307\377m\232\311\377r\236\314\377w\241\317\377|\244\322\377\200\247" \
-  "\324\377\204\252\327\377\211\255\331\377\215\257\332\377\221\263\334" \
-  "\377\225\265\336\377\231\267\340\377\234\271\341\377\237\273\343\377" \
-  "\242\275\344\377\244\277\345\377\203\245\277\345\377\40\244\277\345\377" \
-  "\241\275\344\377\236\273\342\377\233\271\341\377\230\266\337\377\223" \
-  "\264\336\377\220\261\334\377\214\257\333\377\207\254\331\377\203\251" \
-  "\326\377|\244\322\377\223\264\331\377\326\343\361\377\376\376\376\377" \
-  "\353\362\367\377\247\303\336\377w\242\313\377]\220\300\377V\213\275\377" \
-  "L\204\270\377d\226\301\377\262\314\340\377\363\367\372\377\377\377\377" \
-  "\377\352\361\366\377\225\270\324\377X\220\271\377-t\250\377\35k\240\377" \
-  "9\177\255\377\252\310\333\377\355\364\370\377\202\377\377\377\377\7\376" \
-  "\377\377\377\235\304\327\377>\211\257\377\6d\226\377\23j\232\377\226" \
-  "\275\321\377\354\363\366\377\204\377\377\377\377\7\325\343\353\377a\224" \
-  "\263\377;y\240\377\234\273\317\260\337\351\360\22\0\0\0\0\377\377\377" \
-  "\0\227\0\0\0\0\2\34\34\33E\35\35\33\361\217\35\35\33\377\2\35\35\33\216" \
-  "\35\35%\3\366\0\0\0\0\2\34\34\33\36\35\35\33\256\217\35\35\33\377\2\35" \
-  "\35\33\367\31\31\33\20\377\0\0\0\0\341\0\0\0\0\24\0\0/\0\0\0\0\0k\232" \
-  "\304\272\\\217\277\376`\222\302\377d\225\305\377i\230\307\377n\233\312" \
-  "\377s\236\315\377x\242\320\377~\244\321\377\202\250\325\377\206\253\327" \
-  "\377\212\256\332\377\217\260\333\377\223\264\335\377\226\266\337\377" \
-  "\232\270\341\377\236\273\342\377\242\275\344\377\207\245\277\345\377" \
-  "\35\241\275\343\377\236\273\342\377\232\270\341\377\226\265\336\377\222" \
-  "\263\335\377\215\260\333\377\207\254\330\377\203\251\326\377\262\312" \
-  "\345\377\361\365\372\377\367\372\374\377\271\317\346\377\204\252\322" \
-  "\377k\231\310\377`\221\303\377\\\217\300\377S\211\274\377\205\254\317" \
-  "\377\325\342\356\377\377\377\377\377\375\376\376\377\255\311\336\377" \
-  "f\231\300\377>~\260\377/u\250\377#l\242\377k\235\301\377\321\341\354" \
-  "\377\376\376\377\377\202\377\377\377\377\7\272\325\343\377I\223\267\377" \
-  "\22o\237\377\0\\\221\377B\211\257\377\310\334\347\377\373\375\375\377" \
-  "\203\377\377\377\377\10\351\361\365\377}\250\301\377\36h\224\377=|\242" \
-  "\377\261\313\332\377\363\367\371\377\377\377\377K\377\377\377\2\230\0" \
-  "\0\0\0\2\34\34\33E\35\35\33\361\217\35\35\33\377\2\35\35\33\216\35\35" \
-  "%\3\366\0\0\0\0\2\34\34\33\35\35\35\33\253\217\35\35\33\377\2\35\35\33" \
-  "\363\31\31\33\20\377\0\0\0\0\340\0\0\0\0\25\246\277\331\0\0\0\0\0\177" \
-  "\250\315G\\\220\277\357\\\217\300\377`\223\302\377e\226\305\377j\231" \
-  "\310\377o\234\313\377t\237\315\377y\242\320\377~\245\322\377\202\250" \
-  "\325\377\207\254\330\377\213\257\332\377\220\261\334\377\224\264\336" \
-  "\377\230\267\340\377\234\272\341\377\240\274\343\377\244\276\345\377" \
-  "\207\245\277\345\377\33\244\276\344\377\237\274\343\377\233\271\341\377" \
-  "\227\266\337\377\223\264\335\377\214\256\333\377\223\263\334\377\326" \
-  "\343\362\377\366\371\374\377\312\333\355\377\220\263\330\377x\242\317" \
-  "\377k\231\311\377i\227\307\377_\221\302\377e\225\304\377\253\305\336" \
-  "\377\362\366\372\377\377\377\377\377\310\332\351\377w\243\310\377L\210" \
-  "\267\377<|\257\3772w\253\3778{\254\377\243\302\330\377\350\360\365\377" \
-  "\202\377\377\377\377\7\326\346\356\377e\236\300\377\"x\246\377\0c\227" \
-  "\377\2f\231\377\201\262\313\377\351\361\365\377\203\377\377\377\377\6" \
-  "\370\373\374\377\225\272\317\377.u\237\377\12[\213\377l\234\271\377\331" \
-  "\345\354\377\202\377\377\377\377\4\377\377\377\275\377\377\377\21\0\0" \
-  "\0\0\377\377\377\0\226\0\0\0\0\2\34\34\33E\35\35\33\361\217\35\35\33" \
-  "\377\2\35\35\33\216\35\35%\3\366\0\0\0\0\2\34\34\33\35\35\35\33\253\217" \
-  "\35\35\33\377\2\35\35\33\363\31\31\33\20\377\0\0\0\0\340\0\0\0\0\24\"" \
-  "r\256\0\0\0\0\0f\227\302\274Y\216\276\376\\\217\300\377a\223\303\377" \
-  "f\226\305\377j\231\310\377o\234\313\377t\237\315\377z\242\320\377~\246" \
-  "\322\377\203\251\326\377\207\254\331\377\214\257\333\377\220\262\334" \
-  "\377\224\264\336\377\231\270\340\377\235\272\342\377\241\275\344\377" \
-  "\210\245\277\345\377#\244\276\345\377\240\274\343\377\234\272\341\377" \
-  "\227\267\340\377\220\261\334\377\257\307\345\377\356\364\372\377\330" \
-  "\344\363\377\237\274\337\377\204\252\325\377w\241\317\377r\235\315\377" \
-  "n\232\312\377c\224\305\377}\246\316\377\320\337\355\377\377\377\377\377" \
-  "\337\351\363\377\212\257\320\377Z\217\275\377H\203\265\377@\200\262\377" \
-  "3v\253\377^\224\275\377\314\336\352\377\371\373\374\377\377\377\377\377" \
-  "\360\365\371\377\200\254\312\3772}\252\377\26m\237\377\2c\230\377%|\250" \
-  "\377\276\330\345\377\367\372\373\377\203\377\377\377\377\6\261\315\335" \
-  "\377=\201\250\377\0X\213\377\35j\227\377\242\301\323\377\364\370\372" \
-  "\377\204\377\377\377\377\2\377\377\377F\377\377\377\2\227\0\0\0\0\2\34" \
-  "\34\33E\35\35\33\361\217\35\35\33\377\2\35\35\33\216\35\35%\3\366\0\0" \
-  "\0\0\2\34\34\33\35\35\35\33\253\217\35\35\33\377\2\35\35\33\363\31\31" \
-  "\33\20\377\0\0\0\0\341\0\0\0\0\23\206\256\320;W\215\274\350W\215\276" \
-  "\377\\\220\300\377a\223\303\377f\226\305\377j\231\310\377p\234\313\377" \
-  "t\237\316\377z\242\320\377~\246\322\377\204\252\326\377\210\254\331\377" \
-  "\214\257\333\377\220\262\334\377\224\265\336\377\231\270\340\377\235" \
-  "\272\342\377\242\275\344\377\210\245\277\345\377\"\244\276\345\377\240" \
-  "\275\343\377\234\271\341\377\230\267\340\377\321\336\360\377\342\354" \
-  "\366\377\256\307\345\377\216\261\332\377\202\250\325\377|\245\322\377" \
-  "y\242\317\377r\235\315\377n\233\313\377\241\276\334\377\363\366\372\377" \
-  "\356\363\371\377\241\276\333\377g\227\303\377T\212\273\377L\205\267\377" \
-  "E\201\264\377;|\260\377\223\267\323\377\347\357\365\377\377\377\377\377" \
-  "\376\377\377\377\234\276\326\377B\203\257\377%s\245\377\27k\237\377\15" \
-  "g\233\377j\243\302\377\346\360\365\377\376\377\377\377\202\377\377\377" \
-  "\377\7\313\336\351\377M\216\262\377\11a\223\377\0V\212\377N\213\257\377" \
-  "\322\341\352\377\375\376\376\377\205\377\377\377\377\4\351\360\364\271" \
-  "\356\364\366\15\0\0\0\0g\226\267\0\225\0\0\0\0\2\34\34\33E\35\35\33\361" \
-  "\217\35\35\33\377\2\35\35\33\216\35\35%\3\206\0\0\0\0\1\36\36\33\0\222" \
-  "\0\0\0\0\1\37\37\31\0\211\0\0\0\0\1\36\36\32\0\223\0\0\0\0\1\34\34\32" \
-  "\0\215\0\0\0\0\1\34\34\32\0\222\0\0\0\0\1\33\33\32\0\203\0\0\0\0\1\33" \
-  "\33\33\0\215\0\0\0\0\1\35\35\34\0\204\0\0\0\0\1\36\36\33\0\206\0\0\0" \
-  "\0\2\34\34\33\32\35\35\33\252\217\35\35\33\377\2\35\35\33\363\30\30\33" \
-  "\14\207\0\0\0\0\3\35\35\32\0\32\32\32\0\35\35\32\0\222\0\0\0\0\1\35\35" \
-  "\33\0\203\0\0\0\0\2$$$\0\27\27\26\0\214\0\0\0\0\1\24\24\24\0\223\0\0" \
-  "\0\0\1\36\36\36\0\222\0\0\0\0\1))&\0\215\0\0\0\0\1\35\35\32\0\226\0\0" \
-  "\0\0\1\31\31\31\0\215\0\0\0\0\1$$#\0\325\0\0\0\0\26\225\266\323\0\0\0" \
-  "\0\0j\232\303\237U\214\274\372W\214\276\377]\220\300\377a\223\302\377" \
-  "f\226\305\377j\231\310\377o\234\313\377t\237\315\377y\242\320\377~\246" \
-  "\322\377\203\251\326\377\207\254\331\377\214\257\332\377\220\262\334" \
-  "\377\225\264\336\377\231\267\340\377\235\272\342\377\241\275\344\377" \
-  "\244\277\345\377\207\245\277\345\377\40\244\276\344\377\235\272\342\377" \
-  "\256\306\347\377\340\351\365\377\273\320\351\377\225\265\336\377\214" \
-  "\257\332\377\206\253\330\377\202\250\326\377}\245\322\377t\237\316\377" \
-  "}\245\321\377\311\332\354\377\367\372\374\377\271\317\345\377s\237\311" \
-  "\377\\\220\300\377U\213\275\377R\211\272\377G\202\265\377X\216\273\377" \
-  "\300\324\346\377\372\374\375\377\377\377\377\377\272\321\342\377Q\214" \
-  "\267\3773x\251\377'q\244\377\33m\241\377&t\244\377\257\315\336\377\370" \
-  "\373\374\377\202\377\377\377\377\7\345\357\364\377b\235\275\377\13f\227" \
-  "\377\0[\220\377\13b\223\377\206\260\311\377\363\367\371\377\205\377\377" \
-  "\377\377\5\361\365\371\377|\244\277\377\32b\217\377E\177\2458\343\353" \
-  "\367\1\226\0\0\0\0\2\34\34\33E\35\35\33\361\217\35\35\33\377\2\35\35" \
-  "\33\216\35\35%\3\205\0\0\0\0\3\34\34\31\0\0\0\0\0\36\36\33\34\216\36" \
-  "\36\34-\3\36\36\34""1\36\36\34\34\40\40\25\2\207\0\0\0\0\1\33\33\33\0" \
-  "\204\0\0\0\0\10\40\40\31\7\36\36\33""2\35\35\33T\35\35\33o\35\35\33\205" \
-  "\35\35\33\224\35\35\33\240\35\35\33\246\202\35\35\33\250\7\35\35\33\244" \
-  "\35\35\33\231\35\35\33\212\35\35\33v\35\35\33\\\35\35\33=\34\34\32\24" \
-  "\205\0\0\0\0\1\35\35\33\0\212\0\0\0\0\2\34\34\32\25\34\34\32""6\216\34" \
-  "\34\32""5\5\34\34\32""4\32\32\32\33\0\0\0\0\32\32\32\0CC$\0\203\0\0\0" \
-  "\0\13\35\35\33\33\36\36\33Q\35\35\33u\35\35\33\221\35\35\33\237\35\35" \
-  "\33\246\35\35\33\247\35\35\33\233\35\35\33\203\35\35\33\\\35\35\34\"" \
-  "\207\0\0\0\0\3\40\40\34\1\35\35\33\24\34\34\32""8\202\34\34\32""5\3\34" \
-  "\34\32""2\34\34\32L\35\35\33\274\217\35\35\33\377\3\35\35\33\366\34\34" \
-  "\33A\34\34\32""4\203\34\34\32""5\3\34\34\32""6\34\34\32""2\35\35\32\27" \
-  "\203\0\0\0\0\2\34\34\32!\34\34\32""7\215\34\34\32""5\3\34\34\32""6\34" \
-  "\34\32""1\35\35\33\21\202\0\0\0\0\1\36\36\34\0\203\0\0\0\0\13\33\33\34" \
-  "\14\35\35\33C\35\35\33o\35\35\33\216\35\35\33\237\35\35\33\247\35\35" \
-  "\33\246\35\35\33\231\35\35\33\201\34\34\33]\35\35\32)\203\0\0\0\0\1\36" \
-  "\36\34\0\215\0\0\0\0\1\33\33\33\0\205\0\0\0\0\7\36\36\34%\35\35\33J\35" \
-  "\35\33f\35\35\33\177\35\35\33\217\35\35\33\236\35\35\33\245\202\35\35" \
-  "\33\250\7\35\35\33\246\35\35\33\235\35\35\33\217\35\35\33~\35\35\33g" \
-  "\36\36\33I\36\36\33#\205\0\0\0\0\1\36\36\34\0\212\0\0\0\0\3\35\35\32" \
-  "\7\35\35\32/\34\34\32""6\215\34\34\32""5\4\34\34\32""6\35\35\32(\35\35" \
-  "\32\1\40\40\40\0\204\0\0\0\0\14\30\30\27\10\35\35\32A\35\35\33k\35\35" \
-  "\33\210\35\35\33\233\35\35\33\244\35\35\33\250\35\35\33\241\35\35\33" \
-  "\215\34\34\33k\34\34\34""7\20\20\31\1\203\0\0\0\0\1\35\35\31\0\323\0" \
-  "\0\0\0\25\340\350\357\23T\213\272\327R\212\273\377W\215\275\377\\\217" \
-  "\277\377a\222\302\377e\226\305\377j\230\310\377o\233\312\377t\236\315" \
-  "\377y\242\320\377~\245\322\377\202\251\326\377\206\254\330\377\213\256" \
-  "\332\377\217\260\334\377\224\264\335\377\230\266\337\377\234\271\341" \
-  "\377\240\274\343\377\243\276\345\377\207\245\277\345\377'\241\274\343" \
-  "\377\304\326\355\377\306\327\357\377\234\272\340\377\225\264\335\377" \
-  "\215\260\333\377\212\256\332\377\206\253\327\377\201\247\324\377{\244" \
-  "\321\377\230\270\333\377\347\356\366\377\322\340\357\377\205\253\321" \
-  "\377e\225\305\377_\221\301\377Z\216\276\377U\213\274\377J\204\267\377" \
-  "\202\252\315\377\343\354\364\377\377\377\377\377\323\341\355\377h\232" \
-  "\301\377<~\256\3771v\250\377+s\246\377\40n\242\377W\222\271\377\341\354" \
-  "\363\377\375\376\376\377\377\377\377\377\363\370\372\377{\257\311\377" \
-  "\17m\234\377\2a\224\377\0[\217\377.z\244\377\277\326\343\377\205\377" \
-  "\377\377\377\7\363\367\371\377\206\254\304\377\34c\221\377\3R\205\377" \
-  "\0O\203\377\37e\222\224+m\231\10\226\0\0\0\0\2\34\34\33E\35\35\33\361" \
-  "\217\35\35\33\377\2\35\35\33\216\35\35%\3\206\0\0\0\0\2\30\30\20\4\35" \
-  "\35\33\332\215\35\35\33\365\3\35\35\33\367\35\35\33\357\35\35\33^\206" \
-  "\0\0\0\0\1$$\"\0\202\0\0\0\0\12\31\31\33\13\35\35\33U\35\35\33\234\35" \
-  "\35\33\325\35\35\33\364\35\35\33\365\35\35\33\367\35\35\33\371\35\35" \
-  "\33\372\35\35\33\373\205\35\35\33\374\12\35\35\33\373\35\35\33\372\35" \
-  "\35\33\371\35\35\33\370\35\35\33\366\35\35\33\365\35\35\33\343\35\35" \
-  "\33\256\35\35\32m\35\35\33\36\203\0\0\0\0\1!!\26\0\210\0\0\0\0\3\35\35" \
-  "\33`\35\35\33\372\35\35\33\367\215\35\35\33\366\2\35\35\33\360\35\35" \
-  "\33|\203\0\0\0\0\3\35\35\33\27\36\36\33\200\35\35\33\325\202\35\35\33" \
-  "\367\2\35\35\33\371\35\35\33\373\203\35\35\33\374\11\35\35\33\373\35" \
-  "\35\33\372\35\35\33\370\35\35\33\367\35\35\33\323\35\35\33m''\26\3\0" \
-  "\0\0\0\34\34\33\0\202\0\0\0\0\3\34\34\32\5\34\34\32\\\35\35\33\377\202" \
-  "\35\35\33\366\3\35\35\33\365\35\35\33\367\35\35\33\374\220\35\35\33\377" \
-  "\205\35\35\33\366\3\35\35\33\370\35\35\33\351\35\35\33l\203\0\0\0\0\2" \
-  "\35\35\33\226\35\35\33\377\215\35\35\33\366\15\35\35\33\367\35\35\33" \
-  "\340\35\35\33N\0\0\0\0\33\33!\0\0\0\0\0$$\"\3\35\35\33H\35\35\33\266" \
-  "\35\35\33\357\35\35\33\367\35\35\33\371\35\35\33\373\203\35\35\33\374" \
-  "\11\35\35\33\373\35\35\33\372\35\35\33\370\35\35\33\365\35\35\33\336" \
-  "\35\35\33\201\37\37\35\20\0\0\0\0\35\35\33\0\212\0\0\0\0\1\35\35\32\0" \
-  "\203\0\0\0\0\11\35\35\34<\35\35\33\206\35\35\33\303\35\35\33\357\35\35" \
-  "\33\365\35\35\33\367\35\35\33\370\35\35\33\372\35\35\33\373\205\35\35" \
-  "\33\374\202\35\35\33\373\10\35\35\33\372\35\35\33\370\35\35\33\367\35" \
-  "\35\33\366\35\35\33\355\35\35\33\303\35\35\34\204\36\36\34""8\204\0\0" \
-  "\0\0\1\34\34\34\0\207\0\0\0\0\3\35\35\33\"\35\35\33\332\35\35\33\371" \
-  "\215\35\35\33\366\3\35\35\33\371\35\35\33\272\35\35\33\4\202\0\0\0\0" \
-  "\10;;A\0\35\35\32]\35\35\33\274\35\35\33\365\35\35\33\366\35\35\33\371" \
-  "\35\35\33\372\35\35\33\373\203\35\35\33\374\6\35\35\33\373\35\35\33\371" \
-  "\35\35\33\370\35\35\33\346\35\35\33\224\35\35\32\35\202\0\0\0\0\1\35" \
-  "\35\33\0\322\0\0\0\0\26h\230\302\\P\211\271\353Q\210\271\377V\215\275" \
-  "\377[\217\277\377`\222\302\377d\225\305\377i\230\307\377m\233\312\377" \
-  "s\236\315\377x\241\317\377}\245\322\377\201\250\325\377\206\253\330\377" \
-  "\211\256\332\377\217\260\333\377\222\263\335\377\226\266\337\377\233" \
-  "\270\340\377\236\273\342\377\241\275\344\377\244\276\345\377\205\245" \
-  "\277\345\377'\252\303\346\377\276\321\354\377\245\300\344\377\232\271" \
-  "\340\377\225\265\336\377\222\262\334\377\215\260\333\377\211\255\331" \
-  "\377\204\251\326\377\204\252\326\377\271\316\347\377\343\354\365\377" \
-  "\231\271\332\377l\231\311\377h\227\307\377c\224\304\377_\221\301\377" \
-  "X\215\276\377Z\216\276\377\256\310\337\377\374\375\376\377\347\357\365" \
-  "\377\204\255\315\377E\203\263\3778{\256\3774x\252\377.u\250\377*r\245" \
-  "\377\226\273\323\377\373\374\376\377\377\377\377\377\376\376\377\377" \
-  "\237\305\330\377\32v\243\377\0e\230\377\0b\225\377\5c\225\377_\232\273" \
-  "\377\353\362\367\377\204\377\377\377\377\4\371\373\375\377\226\270\315" \
-  "\377\40g\223\377\1Q\203\377\202\0P\203\377\5\0O\202\377\33c\221\364\34" \
-  "d\221\16\0\0\0\0g\226\264\0\224\0\0\0\0\2\34\34\33E\35\35\33\361\217" \
-  "\35\35\33\377\2\35\35\33\216\35\35%\3\204\0\0\0\0\4\35\35\32\0\0\0\0" \
-  "\0\35\35\33n\35\35\33\366\216\35\35\33\377\2\35\35\33\254\35\35\31\30" \
-  "\204\0\0\0\0\1\35\35\32\0\202\0\0\0\0\5\35\35\33;\35\35\33\245\35\35" \
-  "\33\364\35\35\33\373\35\35\33\375\223\35\35\33\377\1\35\35\33\376\202" \
-  "\35\35\33\374\5\35\35\33\312\34\34\33]\377\377\0\0\0\0\0\0\35\35\33\0" \
-  "\207\0\0\0\0\1\35\35\33d\217\35\35\33\377\7\35\35\33\371\35\35\33\201" \
-  "\0\0\0\0\35\35\33\11\35\35\33t\35\35\33\361\35\35\33\376\214\35\35\33" \
-  "\377\11\35\35\33\376\35\35\33\375\35\35\33\334\34\34\33""1\0\0\0\0\35" \
-  "\35\34\0\0\0\0\0\33\33\31\5\34\34\32`\234\35\35\33\377\2\35\35\33\362" \
-  "\35\35\33p\203\0\0\0\0\1\35\35\33\234\217\35\35\33\377\2\35\35\33\351" \
-  "\35\35\33Q\202\0\0\0\0\4\35\35\33""2\35\35\33\277\35\35\33\377\35\35" \
-  "\33\376\214\35\35\33\377\5\35\35\33\374\35\35\33\354\35\35\33Z\0\0\0" \
-  "\0\35\35\33\0\207\0\0\0\0\1\34\34\33\0\202\0\0\0\0\6\35\35\31\35\35\35" \
-  "\33\177\35\35\33\341\35\35\33\373\35\35\33\375\35\35\33\376\222\35\35" \
-  "\33\377\6\35\35\33\376\35\35\33\375\35\35\33\376\35\35\33\340\35\35\33" \
-  "\203\34\34\34\23\202\0\0\0\0\2\33\33\27\0\40\40\40\0\205\0\0\0\0\2\35" \
-  "\35\33#\35\35\33\343\217\35\35\33\377\5\35\35\33\301\35\35\33\4\0\0\0" \
-  "\0\35\35\33@\35\35\33\332\202\35\35\33\376\215\35\35\33\377\5\35\35\33" \
-  "\364\35\35\33f\35\35\33\6\0\0\0\0\36\36\33\0\321\0\0\0\0@a\224\277\260" \
-  "P\211\271\377Q\210\271\377V\214\275\377Z\217\277\377_\221\301\377d\224" \
-  "\304\377h\227\307\377m\232\311\377q\235\314\377w\240\317\377{\244\321" \
-  "\377\200\247\324\377\204\252\327\377\210\255\331\377\214\257\333\377" \
-  "\220\262\334\377\224\264\336\377\230\267\340\377\234\271\340\377\237" \
-  "\273\342\377\241\274\344\377\243\276\345\377\244\277\345\377\245\277" \
-  "\345\377\244\276\345\377\245\277\344\377\247\301\345\377\236\273\342" \
-  "\377\232\270\340\377\227\266\337\377\223\263\335\377\220\261\334\377" \
-  "\214\257\332\377\207\254\330\377\222\263\333\377\317\336\356\377\263" \
-  "\312\345\377v\241\317\377o\234\313\377l\232\311\377g\227\306\377c\224" \
-  "\303\377Z\216\277\377x\242\312\377\327\343\360\377\366\371\373\377\243" \
-  "\301\332\377R\213\272\377@\177\261\377=}\257\3779z\254\3771v\251\377" \
-  "K\210\264\377\321\341\354\377\376\377\377\377\377\377\377\377\275\325" \
-  "\344\3779\203\256\377\4g\233\377\0g\232\377\0d\227\377\30p\237\377\237" \
-  "\303\327\377\204\377\377\377\377\6\367\372\374\377\242\301\324\377%m" \
-  "\230\377\0Q\204\377\0R\204\377\0Q\203\377\203\0P\203\377\3\0O\202\377" \
-  "N\205\250I\203\251\301\2\225\0\0\0\0\2\34\34\33E\35\35\33\361\217\35" \
-  "\35\33\377\2\35\35\33\216\35\35%\3\203\0\0\0\0\4\37\37\32\0\0\0\0\0\35" \
-  "\35\17\1\35\35\33\330\216\35\35\33\377\4\35\35\33\352\35\35\33X\0\0\0" \
-  "\0\35\35\32\0\204\0\0\0\0\3\35\35\32$\35\35\33\266\35\35\33\374\234\35" \
-  "\35\33\377\2\35\35\33\336\35\35\33M\203\0\0\0\0\1\35\35\35\0\204\0\0" \
-  "\0\0\1\35\35\33d\217\35\35\33\377\4\35\35\33\371\35\35\33\200\35\35\33" \
-  "\7\35\35\33\243\222\35\35\33\377\2\35\35\33\366\35\35\34<\202\0\0\0\0" \
-  "\2\34\34\32\5\34\34\32`\234\35\35\33\377\2\35\35\33\361\35\35\33p\203" \
-  "\0\0\0\0\1\35\35\33\233\217\35\35\33\377\5\35\35\33\351\35\35\33P\0\0" \
-  "\0\0\35\35\33X\35\35\33\357\221\35\35\33\377\2\35\35\33\366\35\35\33" \
-  "n\206\0\0\0\0\1\35\35\33\0\202\0\0\0\0\3\33\33\33\15\35\35\33\202\35" \
-  "\35\33\357\234\35\35\33\377\3\35\35\33\366\35\35\33|\36\36\34\10\202" \
-  "\0\0\0\0\1\36\36\33\0\204\0\0\0\0\2\35\35\33#\35\35\33\343\217\35\35" \
-  "\33\377\4\35\35\33\301\35\35\33\2\35\35\33f\35\35\33\376\222\35\35\33" \
-  "\377\2\36\36\33u\36\36\33\10\321\0\0\0\0@\355\361\366\17L\206\267\320" \
-  "K\205\266\377O\210\271\377T\213\274\377X\216\276\377^\220\301\377b\224" \
-  "\303\377g\226\306\377k\231\310\377p\234\313\377t\237\315\377y\242\320" \
-  "\377~\246\323\377\202\251\326\377\207\254\330\377\212\256\331\377\216" \
-  "\260\333\377\222\263\334\377\225\265\336\377\230\267\340\377\233\271" \
-  "\340\377\235\272\341\377\237\273\343\377\237\274\343\377\241\274\343" \
-  "\377\236\272\342\377\275\320\354\377\244\277\344\377\232\270\340\377" \
-  "\227\266\337\377\224\264\336\377\221\262\334\377\215\257\332\377\213" \
-  "\256\331\377\245\301\341\377\300\323\351\377\205\253\325\377v\241\317" \
-  "\377t\236\315\377o\234\312\377j\231\310\377e\226\305\377d\224\304\377" \
-  "\233\273\330\377\354\362\367\377\301\325\346\377c\226\301\377F\202\265" \
-  "\377E\202\264\377@\200\262\377<}\257\3775y\253\377\200\253\312\377\364" \
-  "\370\373\377\376\376\377\377\331\346\357\377Y\225\272\377\22i\235\377" \
-  "\16i\234\377\6h\233\377\4i\233\377=\211\260\377\335\352\361\377\203\377" \
-  "\377\377\377\7\370\373\374\377\260\314\334\377.u\240\377\0R\207\377\0" \
-  "T\207\377\0S\205\377\0R\204\377\204\0P\203\377\3\0O\203\377!g\223\217" \
-  ")l\227\5\225\0\0\0\0\2\34\34\33E\35\35\33\361\217\35\35\33\377\2\35\35" \
-  "\33\216\35\35%\3\205\0\0\0\0\2\35\35\33h\35\35\33\363\216\35\35\33\377" \
-  "\2\35\35\33\240\40\40\30\10\202\0\0\0\0\1''$\0\202\0\0\0\0\2\35\35\33" \
-  "`\35\35\33\356\240\35\35\33\377\2\35\35\33\232\27\27\31\4\206\0\0\0\0" \
-  "\1\35\35\33d\217\35\35\33\377\3\35\35\33\371\35\35\33\213\35\35\33\200" \
-  "\224\35\35\33\377\5\35\35\33\351\35\35\32\20\0\0\0\0\34\34\32\5\34\34" \
-  "\32`\234\35\35\33\377\2\35\35\33\361\35\35\33p\203\0\0\0\0\1\35\35\33" \
-  "\233\217\35\35\33\377\4\35\35\33\350\35\35\33S\35\35\33L\35\35\33\371" \
-  "\223\35\35\33\377\4\35\35\33\356\34\34\32""1\0\0\0\0\34\34\34\0\202\0" \
-  "\0\0\0\1\35\35\33\0\202\0\0\0\0\2\35\35\33""0\35\35\33\304\240\35\35" \
-  "\33\377\3\35\35\33\313\36\36\33\36\37\37\33\0\205\0\0\0\0\2\35\35\33" \
-  "#\35\35\33\343\217\35\35\33\377\2\35\35\33\276\35\35\33L\225\35\35\33" \
-  "\377\4\34\34\33C\34\34\33\2\0\0\0\0\35\35\35\0\316\0\0\0\0\30o\236\305" \
-  "OK\206\267\344I\204\266\377O\207\271\377S\212\273\377X\215\276\377]\217" \
-  "\300\377a\222\302\377e\225\305\377j\230\310\377n\233\312\377s\236\315" \
-  "\377x\241\317\377|\244\321\377\200\247\324\377\205\251\326\377\210\254" \
-  "\330\377\213\257\332\377\217\261\333\377\222\263\334\377\225\265\336" \
-  "\377\230\266\340\377\232\267\340\377\233\271\341\377\202\234\272\341" \
-  "\377$\225\265\337\377\362\366\373\377\357\364\372\377\260\310\347\377" \
-  "\230\267\336\377\221\262\334\377\216\261\333\377\216\260\333\377\250" \
-  "\303\343\377\232\271\335\377{\244\322\377{\243\320\377v\240\316\377q" \
-  "\235\314\377m\232\311\377i\230\307\377w\241\313\377\275\321\345\377\324" \
-  "\342\356\377|\245\313\377N\206\270\377L\206\267\377I\204\266\377C\201" \
-  "\263\377\77\177\261\377K\207\265\377\272\321\342\377\373\375\375\377" \
-  "\346\357\365\377{\251\307\377\40o\242\377\32l\240\377\26l\237\377\16" \
-  "j\235\377\24q\241\377x\256\311\377\202\377\377\377\377\12\376\376\377" \
-  "\377\364\370\372\377\271\322\340\3779\177\247\377\0S\210\377\0V\211\377" \
-  "\0W\212\377\0U\207\377\0S\205\377\0R\204\377\204\0P\203\377\3\0O\202" \
-  "\377\40f\222\340&j\225\10\225\0\0\0\0\2\34\34\33E\35\35\33\361\217\35" \
-  "\35\33\377\2\35\35\33\216\35\35%\3\202\0\0\0\0\4\35\35\35\0\0\0\0\0\377" \
-  "\377\0\0\35\35\33\321\216\35\35\33\377\5\35\35\33\334\35\35\33I\0\0\0" \
-  "\0\36\36\32\0\34\34\34\0\202\0\0\0\0\2\35\35\33s\35\35\33\363\242\35" \
-  "\35\33\377\4\35\35\33\261\35\35!\3\0\0\0\0\35\35\34\0\203\0\0\0\0\1\35" \
-  "\35\33d\217\35\35\33\377\3\35\35\33\372\35\35\33\273\35\35\33\374\224" \
-  "\35\35\33\377\5\35\35\33\376\35\35\33\213\0\0\0\0\34\34\31\5\34\34\32" \
-  "`\234\35\35\33\377\2\35\35\33\361\35\35\33p\203\0\0\0\0\1\35\35\33\233" \
-  "\217\35\35\33\377\3\35\35\33\347\35\35\33\207\35\35\33\342\224\35\35" \
-  "\33\377\2\35\35\33\373\35\35\33\247\203\0\0\0\0\1\32\32\32\0\202\0\0" \
-  "\0\0\2\35\35\33""8\35\35\33\317\242\35\35\33\377\4\35\35\33\342\36\36" \
-  "\33\36\0\0\0\0$$\40\0\203\0\0\0\0\2\35\35\33#\35\35\33\343\217\35\35" \
-  "\33\377\2\35\35\33\314\35\35\33\344\225\35\35\33\377\2\35\35\33\307\35" \
-  "\35\33\15\316\0\0\0\0\36\227\275\325\0\0\0\0\0Y\220\273}I\204\265\363" \
-  "H\204\265\377M\206\267\377Q\212\272\377V\214\275\377[\217\277\377`\221" \
-  "\301\377d\224\304\377i\227\306\377l\232\311\377p\235\313\377u\240\316" \
-  "\377z\242\320\377~\245\322\377\202\250\324\377\205\253\327\377\210\254" \
-  "\331\377\214\257\332\377\216\261\333\377\221\262\334\377\223\264\335" \
-  "\377\225\265\336\377\227\266\337\377\230\267\340\377\227\267\337\377" \
-  "\220\261\334\377\355\363\372\377\202\377\377\377\377\37\324\341\361\377" \
-  "\233\272\337\377\216\260\334\377\224\265\334\377\202\250\326\377\177" \
-  "\247\324\377|\244\322\377y\241\317\377t\237\315\377p\234\313\377o\233" \
-  "\311\377\214\261\324\377\305\327\351\377\232\272\330\377X\215\276\377" \
-  "Q\211\273\377Q\210\272\377L\206\267\377F\203\264\377E\202\264\377s\242" \
-  "\306\377\337\352\362\377\360\365\371\377\230\273\324\3771x\251\377\"" \
-  "o\242\377!p\243\377\32l\240\377\30n\240\3773\201\254\377\275\327\344" \
-  "\377\202\377\377\377\377\13\361\367\371\377\301\330\344\377D\211\257" \
-  "\377\0V\213\377\0W\213\377\0X\214\377\0W\213\377\0V\211\377\0T\207\377" \
-  "\0S\205\377\0R\204\377\205\0P\203\377\3\13X\210\377D\177\244\23\377\377" \
-  "\377\0\224\0\0\0\0\2\34\34\33E\35\35\33\361\217\35\35\33\377\2\35\35" \
-  "\33\216\35\35%\3\204\0\0\0\0\2\35\35\33d\35\35\33\360\216\35\35\33\377" \
-  "\1\35\35\33\225\205\0\0\0\0\2\35\35\33M\35\35\33\345\220\35\35\33\377" \
-  "\3\35\35\33\373\35\35\33\370\35\35\33\372\220\35\35\33\377\2\35\35\33" \
-  "\372\35\35\33\215\205\0\0\0\0\1\35\35\33d\247\35\35\33\377\4\35\35\33" \
-  "\346\0\0\0\0\33\33\31\5\34\34\32`\234\35\35\33\377\2\35\35\33\363\35" \
-  "\35\33q\203\0\0\0\0\1\35\35\33\233\247\35\35\33\377\1\35\35\33\335\205" \
-  "\0\0\0\0\2\35\35\33\36\35\35\33\263\220\35\35\33\377\1\35\35\33\375\202" \
-  "\35\35\33\371\1\35\35\33\375\220\35\35\33\377\2\35\35\33\311\30\30\25" \
-  "\5\204\0\0\0\0\2\35\35\33#\35\35\33\343\247\35\35\33\377\2\35\35\34+" \
-  "\35\35\36\1\317\0\0\0\0\30U\215\272\261G\203\264\377F\203\264\377L\205" \
-  "\267\377P\210\271\377T\213\274\377Y\216\276\377^\220\301\377a\223\303" \
-  "\377f\226\305\377j\231\310\377n\234\312\377r\236\314\377w\240\317\377" \
-  "{\243\321\377~\246\323\377\202\250\325\377\206\252\327\377\210\254\330" \
-  "\377\213\256\332\377\216\260\333\377\220\261\334\377\221\262\334\377" \
-  "\223\262\335\377\202\223\263\335\377\2\214\256\332\377\355\363\371\377" \
-  "\203\377\377\377\377+\372\373\375\377\267\314\347\377\215\260\332\377" \
-  "\201\250\325\377|\245\322\377z\242\320\377v\240\316\377r\235\314\377" \
-  "w\242\315\377\231\271\331\377\250\303\336\377i\230\305\377V\213\276\377" \
-  "W\214\275\377T\212\273\377N\207\270\377J\205\267\377T\214\272\377\240" \
-  "\277\331\377\354\362\367\377\262\314\337\377I\206\263\377*q\246\377)" \
-  "r\246\377&q\243\377\35n\241\377'u\245\377g\236\300\377\363\370\373\377" \
-  "\377\377\377\377\357\365\371\377\305\333\347\377P\222\266\377\0Z\217" \
-  "\377\0Y\216\377\0\\\217\377\0Z\215\377\0X\213\377\0V\212\377\0V\210\377" \
-  "\0T\206\377\0S\205\377\0R\204\377\205\0P\203\377\3\0O\202\377T\212\254" \
-  "Wf\227\265\1\224\0\0\0\0\2\34\34\33E\35\35\33\361\217\35\35\33\377\7" \
-  "\35\35\33\216\35\35%\3\0\0\0\0\40\40\40\0\0\0\0\0\34\34\335\0\35\35\33" \
-  "\310\216\35\35\33\377\4\35\35\33\320\35\35\33""7\0\0\0\0\33\33\33\0\202" \
-  "\0\0\0\0\2\33\33\35\10\35\35\33\273\217\35\35\33\377\7\35\35\33\373\35" \
-  "\35\33\333\35\35\33\250\35\35\33\213\35\35\33\232\35\35\33\313\35\35" \
-  "\33\366\217\35\35\33\377\4\35\35\33\352\35\35\34""0\0\0\0\0\"\"\"\0\202" \
-  "\0\0\0\0\1\35\35\33d\247\35\35\33\377\5\35\35\33\370\34\34\33'\33\33" \
-  "\27\2\34\34\32U\35\35\33\357\202\35\35\33\343\3\35\35\33\342\35\35\33" \
-  "\346\35\35\33\366\217\35\35\33\377\2\35\35\33\376\35\35\33\345\204\35" \
-  "\35\33\343\3\35\35\33\345\35\35\33\327\35\35\33d\203\0\0\0\0\1\35\35" \
-  "\33\233\247\35\35\33\377\2\35\35\33\342\35\35\33\37\204\0\0\0\0\1\35" \
-  "\35\33p\220\35\35\33\377\2\35\35\33\351\35\35\33\273\202\35\35\33\220" \
-  "\2\35\35\33\267\35\35\33\354\220\35\35\33\377\3\35\35\32f\0\0\0\0\36" \
-  "\36\33\0\202\0\0\0\0\2\35\35\33#\35\35\33\343\247\35\35\33\377\2\35\35" \
-  "\33f\35\35\33\3\317\0\0\0\0\34C\201\261\302A\177\261\377F\202\264\377" \
-  "J\204\266\377N\207\271\377R\212\273\377W\214\275\377[\217\277\377_\221" \
-  "\301\377d\224\304\377h\227\306\377l\231\310\377o\234\313\377s\236\315" \
-  "\377w\241\317\377{\244\321\377\177\246\323\377\202\250\325\377\205\252" \
-  "\327\377\207\253\327\377\212\256\331\377\214\257\332\377\215\257\332" \
-  "\377\216\260\333\377\217\261\334\377\217\260\334\377\207\254\331\377" \
-  "\346\356\367\377\205\377\377\377\377)\341\353\365\377\235\273\335\377" \
-  "\202\250\323\377t\237\316\377s\236\314\377z\243\316\377\223\265\327\377" \
-  "\177\246\316\377[\216\300\377^\220\301\377Z\216\277\377V\213\274\377" \
-  "O\207\271\377R\212\272\377n\235\305\377\300\325\346\377\305\327\347\377" \
-  "d\227\277\3771v\251\3770u\250\377-u\247\377'q\244\377$p\243\377:\201" \
-  "\255\377\245\306\332\377\377\377\377\377\360\366\371\377\310\336\351" \
-  "\377^\235\275\377\0_\223\377\0[\220\377\0^\221\377\0]\221\377\0\\\217" \
-  "\377\0Z\215\377\0X\213\377\0V\211\377\0V\210\377\0T\206\377\0R\204\377" \
-  "\0Q\203\377\205\0P\203\377\3\0O\203\377-o\231\2033s\234\1\224\0\0\0\0" \
-  "\2\34\34\33E\35\35\33\361\217\35\35\33\377\7\35\35\33\216\35\35%\3\0" \
-  "\0\0\0\30\30\23\0\0\0\0\0\35\35\33_\35\35\33\355\215\35\35\33\377\2\35" \
-  "\35\33\372\35\35\33\207\205\0\0\0\0\2\35\35\33S\35\35\33\342\217\35\35" \
-  "\33\377\2\35\35\33\274\35\35\33\26\204\0\0\0\0\2\35\35\33\204\35\35\33" \
-  "\367\216\35\35\33\377\2\35\35\33\370\35\35\33\225\204\0\0\0\0\1\35\35" \
-  "\33d\222\35\35\33\377\1\35\35\33\367\202\35\35\33\355\1\35\35\33\366" \
-  "\221\35\35\33\377\5\35\35\33\370\34\34\33G\0\0\0\0\40\40\37\5\37\37\31" \
-  "\16\202\37\37\31\15\3\40\40\30\12\35\35\33)\35\35\33\260\217\35\35\33" \
-  "\377\3\35\35\33\364\35\35\33\34\40\40\30\14\203\37\37\31\15\3\37\37\31" \
-  "\16\37\37\31\15\37\37\33\6\203\0\0\0\0\1\35\35\33\233\222\35\35\33\377" \
-  "\4\35\35\33\364\35\35\33\354\35\35\33\357\35\35\33\373\221\35\35\33\377" \
-  "\2\35\35\33\343\33\33\31&\203\0\0\0\0\2\35\35\33!\35\35\33\263\217\35" \
-  "\35\33\377\2\35\35\33\354\35\35\33B\204\0\0\0\0\2\35\35\33C\35\35\33" \
-  "\342\217\35\35\33\377\1\35\35\33\325\204\0\0\0\0\2\35\35\33#\35\35\33" \
-  "\343\221\35\35\33\377\4\35\35\33\374\35\35\33\357\35\35\33\354\35\35" \
-  "\33\361\222\35\35\33\377\2\35\35\34\206\35\35\34\4\316\0\0\0\0\37\231" \
-  "\274\3250D\202\262\324>~\260\377C\201\263\377I\203\265\377L\206\267\377" \
-  "Q\211\272\377T\213\274\377Y\215\276\377]\220\300\377a\223\303\377e\225" \
-  "\305\377j\230\307\377m\232\311\377p\235\314\377t\237\316\377x\241\317" \
-  "\377{\244\321\377~\246\323\377\201\250\325\377\203\251\326\377\206\253" \
-  "\327\377\210\254\330\377\211\255\331\377\212\255\332\377\212\256\331" \
-  "\377\212\256\332\377\206\253\330\377\266\315\350\377\341\352\366\377" \
-  "\365\370\374\377\205\377\377\377\377'\303\325\353\377\211\255\325\377" \
-  "v\240\315\377x\242\315\377d\225\305\377b\222\303\377`\222\302\377]\217" \
-  "\300\377W\214\275\377S\212\273\377\\\220\276\377\211\257\320\377\273" \
-  "\321\344\377\200\252\313\377<|\256\3775x\253\3775y\253\3771v\251\377" \
-  "'q\245\3770x\250\377b\231\275\377\344\356\364\377\370\373\374\377\312" \
-  "\336\352\377f\243\302\377\0e\231\377\0]\223\377\0a\224\377\0`\223\377" \
-  "\0^\222\377\0\\\220\377\0[\216\377\0Y\214\377\0W\213\377\0W\211\377\0" \
-  "U\207\377\0T\206\377\0R\204\377\0Q\203\377\206\0P\203\377\2\26_\216\247" \
-  "\30a\217\2\224\0\0\0\0\2\34\34\33E\35\35\33\361\217\35\35\33\377\2\35" \
-  "\35\33\216\35\35%\3\202\0\0\0\0\2'',\1\35\35\33\277\216\35\35\33\377" \
-  "\11\35\35\33\307\35\35\33\"\0\0\0\0\37\37\32\0\0\0\0\0\34\34\34\0\0\0" \
-  "\0\0\35\35\33\210\35\35\33\373\216\35\35\33\377\11\35\35\33\352\35\35" \
-  "\33^\0\0\0\0\35\35\33\0\0\0\0\0\34\34\34\0\0\0\0\0\35\35\33'\35\35\33" \
-  "\305\217\35\35\33\377\1\35\35\33\315\204\0\0\0\0\1\35\35\33d\220\35\35" \
-  "\33\377\10\35\35\33\376\35\35\33\326\35\35\33\214\35\35\33a\35\35\33" \
-  "`\35\35\33\207\35\35\33\321\35\35\33\376\217\35\35\33\377\2\35\35\33" \
-  "\370\34\34\33P\206\0\0\0\0\2\33\33\33\33\35\35\33\253\217\35\35\33\377" \
-  "\2\35\35\33\363\31\31\33\15\207\0\0\0\0\1\36\36\33\0\202\0\0\0\0\1\35" \
-  "\35\33\233\220\35\35\33\377\7\35\35\33\372\35\35\33\305\35\35\33}\35" \
-  "\35\33]\35\35\33i\35\35\33\244\35\35\33\352\220\35\35\33\377\2\35\35" \
-  "\33\343\34\34\32&\203\0\0\0\0\2\35\35\33A\35\35\33\341\216\35\35\33\377" \
-  "\11\35\35\33\375\35\35\33\247\0\0\0\0\32\32\27\0$$$\0\34\34\32\0\0\0" \
-  "\0\0\36\36\33\7\35\35\33\202\220\35\35\33\377\1\36\36\32\31\203\0\0\0" \
-  "\0\2\35\35\33#\35\35\33\343\220\35\35\33\377\7\35\35\33\353\35\35\33" \
-  "\243\35\35\33i\35\35\33]\35\35\33t\35\35\33\271\35\35\33\370\220\35\35" \
-  "\33\377\2\35\35\33\217\35\35\33\5\316\0\0\0\0\30j\235\302E@\200\260\335" \
-  "=}\260\377B\200\262\377F\202\264\377J\204\266\377N\207\271\377R\211\272" \
-  "\377V\214\275\377Z\216\277\377^\221\300\377b\223\303\377f\226\305\377" \
-  "j\230\307\377m\232\311\377q\235\314\377t\237\316\377w\241\317\377z\243" \
-  "\321\377}\245\322\377\177\247\324\377\202\250\325\377\203\251\326\377" \
-  "\204\252\327\377\203\206\253\327\377\6\203\251\326\377\260\311\346\377" \
-  "\240\275\340\377\264\313\346\377\336\351\364\377\367\372\374\377\204" \
-  "\377\377\377\377&\355\363\371\377\246\302\336\377x\242\314\377b\223\304" \
-  "\377_\221\302\377]\220\300\377X\215\276\377Y\216\275\377f\227\302\377" \
-  "\222\265\323\377\221\264\322\377L\207\267\3778z\256\377<|\256\3779z\254" \
-  "\3772w\252\377+r\246\377E\205\261\377\227\274\324\377\361\366\371\377" \
-  "\320\341\354\377z\253\310\377\17l\235\377\0`\225\377\0e\230\377\0d\226" \
-  "\377\0a\224\377\0`\223\377\0^\221\377\0\\\217\377\0[\216\377\0Y\214\377" \
-  "\0W\212\377\0V\211\377\0U\207\377\0S\205\377\0R\204\377\0Q\203\377\205" \
-  "\0P\203\377\3\0O\202\377#h\225\332&j\226\3\224\0\0\0\0\2\34\34\33E\35" \
-  "\35\33\361\217\35\35\33\377\2\35\35\33\216\35\35%\3\202\0\0\0\0\2\35" \
-  "\35\33[\35\35\33\352\215\35\35\33\377\4\35\35\33\362\35\35\33t\0\0\0" \
-  "\0\30\30\"\0\204\0\0\0\0\1\35\35\33\243\217\35\35\33\377\2\35\35\33\342" \
-  "\35\35\33G\205\0\0\0\0\2\35\35\35\27\35\35\33\270\217\35\35\33\377\2" \
-  "\35\35\33\330\34\34\34\24\203\0\0\0\0\1\35\35\33d\220\35\35\33\377\2" \
-  "\35\35\33\343\35\35\33,\204\0\0\0\0\2\35\35\33""2\35\35\33\326\217\35" \
-  "\35\33\377\2\35\35\33\370\34\34\33Q\206\0\0\0\0\2\34\34\33\35\35\35\33" \
-  "\253\217\35\35\33\377\2\35\35\33\363\31\31\33\20\212\0\0\0\0\1\35\35" \
-  "\33\233\220\35\35\33\377\2\35\35\33\300\35\35\33\20\204\0\0\0\0\2\35" \
-  "\35\33p\35\35\33\364\217\35\35\33\377\2\35\35\33\343\34\34\32&\203\0" \
-  "\0\0\0\2\35\35\33Q\35\35\33\371\216\35\35\33\377\2\35\35\33\374\35\35" \
-  "\33\210\206\0\0\0\0\1\35\35\33m\217\35\35\33\377\2\35\35\33\374\36\36" \
-  "\32C\203\0\0\0\0\2\35\35\33#\35\35\33\343\220\35\35\33\377\1\35\35\33" \
-  "c\204\0\0\0\0\2\27\27\27\5\35\35\33\244\220\35\35\33\377\2\35\35\33\220" \
-  "\35\35\33\5\316\0\0\0\0\30E\203\262Q9{\255\342;|\256\377\77~\260\377" \
-  "C\200\262\377H\203\265\377L\205\267\377P\207\270\377T\212\273\377X\214" \
-  "\275\377[\216\277\377_\220\302\377b\224\304\377f\226\305\377j\230\307" \
-  "\377m\232\311\377q\234\313\377s\236\315\377v\241\317\377x\242\320\377" \
-  "{\243\321\377}\245\323\377\177\246\323\377\200\246\323\377\203\201\250" \
-  "\325\377\10y\242\322\377\362\366\373\377\355\362\371\377\254\306\343" \
-  "\377\222\263\331\377\261\312\344\377\334\347\363\377\370\372\375\377" \
-  "\204\377\377\377\377#\321\340\356\377\215\261\324\377g\227\304\377U\213" \
-  "\275\377Y\215\276\377i\231\303\377\177\250\314\377a\223\277\377\77}\261" \
-  "\377@\177\262\377>~\260\377:{\255\3771v\251\3775z\253\377h\233\300\377" \
-  "\275\324\343\377\324\343\355\377\203\260\313\377\"s\244\377\6c\230\377" \
-  "\6g\232\377\1g\232\377\0e\230\377\0b\226\377\0a\224\377\0_\222\377\0" \
-  "]\220\377\0\\\217\377\0Z\216\377\0X\214\377\0W\212\377\0U\210\377\0T" \
-  "\207\377\0S\205\377\0Q\204\377\206\0P\203\377\3\0O\202\377\36d\222\367" \
-  "\40e\223\3\224\0\0\0\0\2\34\34\33E\35\35\33\361\217\35\35\33\377\5\35" \
-  "\35\33\216\35\35%\3\0\0\0\0##\23\3\35\35\33\265\216\35\35\33\377\4\35" \
-  "\35\33\276\40\40\30\16\0\0\0\0$$\22\0\204\0\0\0\0\1\35\35\33\251\217" \
-  "\35\35\33\377\2\35\35\33\342\35\35\33H\205\0\0\0\0\2\37\37\35\30\35\35" \
-  "\33\271\217\35\35\33\377\2\35\35\33\332\35\35\33\37\203\0\0\0\0\1\35" \
-  "\35\33d\217\35\35\33\377\11\35\35\33\374\35\35\33\246\0\0\0\0\35\35\33" \
-  "\1\0\0\0\0\35\35\35\0\0\0\0\0\36\36\33\13\35\35\33\216\217\35\35\33\377" \
-  "\2\35\35\33\370\34\34\33Q\206\0\0\0\0\2\34\34\33\35\35\35\33\253\217" \
-  "\35\35\33\377\2\35\35\33\363\31\31\33\20\212\0\0\0\0\1\35\35\33\233\217" \
-  "\35\35\33\377\11\35\35\33\360\35\35\33m\0\0\0\0\35\35\33\0\0\0\0\0\35" \
-  "\35\33\0\0\0\0\0\35\35\33%\35\35\33\277\217\35\35\33\377\2\35\35\33\343" \
-  "\34\34\32&\203\0\0\0\0\1\35\35\33V\217\35\35\33\377\2\35\35\33\374\35" \
-  "\35\33\211\205\0\0\0\0\2""11\7\0\35\35\33n\217\35\35\33\377\2\35\35\33" \
-  "\375\35\35\33O\203\0\0\0\0\2\35\35\33#\35\35\33\343\217\35\35\33\377" \
-  "\1\35\35\33\347\202\0\0\0\0\2+++\0\27\27\27\0\202\0\0\0\0\1\34\34\33" \
-  ">\220\35\35\33\377\2\35\35\33\220\35\35\33\5\316\0\0\0\0\31G\205\263" \
-  "e9{\255\3528z\255\377=}\257\377@\177\261\377E\202\263\377I\204\265\377" \
-  "M\207\267\377Q\211\272\377U\213\273\377Y\215\275\377\\\217\277\377_\222" \
-  "\301\377b\224\304\377g\226\305\377i\230\307\377m\232\311\377o\234\313" \
-  "\377r\236\314\377t\237\316\377w\240\317\377y\241\320\377y\242\320\377" \
-  "{\243\321\377{\245\322\377\202|\245\322\377\2t\237\317\377\351\360\367" \
-  "\377\202\377\377\377\377\6\323\341\360\377\230\270\333\377\202\251\322" \
-  "\377\256\307\341\377\334\347\362\377\374\375\376\377\203\377\377\377" \
-  "\377\"\367\372\374\377\265\315\343\377w\242\312\377]\221\277\377[\220" \
-  "\275\377K\205\267\377E\201\264\377D\201\263\377@\177\261\377<|\257\377" \
-  "2v\252\377N\212\266\377\201\253\312\377\272\321\342\377\222\270\321\377" \
-  "4|\252\377\21f\234\377\22j\236\377\17j\235\377\5h\233\377\0e\232\377" \
-  "\0d\227\377\0b\225\377\0`\223\377\0^\222\377\0]\220\377\0[\216\377\0" \
-  "Z\215\377\0X\213\377\0W\212\377\0U\210\377\0S\206\377\0R\205\377\0Q\203" \
-  "\377\206\0P\203\377\4\0O\203\377\22\\\213\377\13X\210\3\210\252\314\0" \
-  "\223\0\0\0\0\2\34\34\33E\35\35\33\361\217\35\35\33\377\5\35\35\33\216" \
-  "\35\35$\4\0\0\0\0\35\35\33V\35\35\33\346\215\35\35\33\377\4\35\35\33" \
-  "\355\35\35\33Z\0\0\0\0\36\36\32\0\205\0\0\0\0\1\35\35\33\252\217\35\35" \
-  "\33\377\2\35\35\33\342\35\35\33H\205\0\0\0\0\2\37\37\35\30\35\35\33\271" \
-  "\217\35\35\33\377\2\35\35\33\333\35\35\33!\203\0\0\0\0\1\35\35\33d\217" \
-  "\35\35\33\377\2\35\35\33\371\35\35\33\203\205\0\0\0\0\2\37\37\35\3\35" \
-  "\35\33\177\217\35\35\33\377\2\35\35\33\370\34\34\33Q\206\0\0\0\0\2\34" \
-  "\34\33\35\35\35\33\253\217\35\35\33\377\2\35\35\33\363\31\31\33\20\212" \
-  "\0\0\0\0\1\35\35\33\233\217\35\35\33\377\2\35\35\33\351\35\35\33Q\205" \
-  "\0\0\0\0\2\34\34\34\24\35\35\33\256\217\35\35\33\377\2\35\35\33\343\34" \
-  "\34\32&\203\0\0\0\0\1\35\35\33W\217\35\35\33\377\2\35\35\33\374\35\35" \
-  "\33\211\205\0\0\0\0\2//\11\1\35\35\33n\217\35\35\33\377\2\35\35\33\375" \
-  "\35\35\33Q\203\0\0\0\0\2\35\35\33#\35\35\33\343\217\35\35\33\377\3\35" \
-  "\35\33\303\35\35\33\4\30\30\30\0\204\0\0\0\0\1\35\35\33+\220\35\35\33" \
-  "\377\2\35\35\33\220\35\35\33\5\316\0\0\0\0\35P\213\266{9|\254\3636y\254" \
-  "\377;|\256\377\77~\260\377B\200\262\377F\203\264\377J\205\266\377N\207" \
-  "\270\377R\211\272\377U\213\274\377Y\215\276\377\\\217\277\377_\221\301" \
-  "\377c\224\304\377e\226\305\377i\227\307\377k\231\310\377m\233\312\377" \
-  "p\234\313\377r\235\314\377t\237\315\377u\237\316\377v\240\316\377w\241" \
-  "\317\377x\241\317\377x\241\320\377n\233\314\377\352\361\370\377\203\377" \
-  "\377\377\377\7\367\371\374\377\274\321\347\377\207\254\323\377z\244\315" \
-  "\377\255\307\340\377\333\346\361\377\376\377\377\377\203\377\377\377" \
-  "\377\37\340\352\363\377\231\272\327\377_\222\276\377C\200\263\377D\201" \
-  "\263\377B\177\262\377<|\257\377<}\256\377]\223\273\377\205\256\315\377" \
-  "\217\265\320\377D\205\261\377\33k\240\377\33k\237\377\30l\237\377\22" \
-  "k\236\377\13i\234\377\2f\232\377\0e\230\377\0c\226\377\0a\224\377\0_" \
-  "\222\377\0^\221\377\0\\\217\377\0[\216\377\0Y\214\377\0W\212\377\0V\211" \
-  "\377\0U\210\377\0S\206\377\0R\204\377\210\0P\203\377\2\4S\205\377&j\231" \
-  "\4\224\0\0\0\0\2\34\34\33E\35\35\33\361\217\35\35\33\377\4\35\35\33\216" \
-  "\35\35""5\1!!\36\2\35\35\33\254\215\35\35\33\377\2\35\35\33\375\35\35" \
-  "\33\261\210\0\0\0\0\1\35\35\33\252\217\35\35\33\377\2\35\35\33\342\35" \
-  "\35\33H\205\0\0\0\0\2\37\37\35\30\35\35\33\271\217\35\35\33\377\2\35" \
-  "\35\33\333\35\35\33!\203\0\0\0\0\1\35\35\33d\217\35\35\33\377\2\35\35" \
-  "\33\371\35\35\33\200\205\0\0\0\0\2\16\16)\1\35\35\33{\217\35\35\33\377" \
-  "\2\35\35\33\370\34\34\33Q\206\0\0\0\0\2\34\34\33\35\35\35\33\253\217" \
-  "\35\35\33\377\2\35\35\33\363\31\31\33\20\212\0\0\0\0\1\35\35\33\233\217" \
-  "\35\35\33\377\2\35\35\33\351\35\35\33P\205\0\0\0\0\2\33\33\31\24\35\35" \
-  "\33\256\217\35\35\33\377\2\35\35\33\343\34\34\32&\203\0\0\0\0\1\35\35" \
-  "\33W\217\35\35\33\377\2\35\35\33\374\35\35\33\211\205\0\0\0\0\2//\11" \
-  "\1\35\35\33n\217\35\35\33\377\2\35\35\33\375\35\35\33Q\203\0\0\0\0\2" \
-  "\35\35\33#\35\35\33\343\217\35\35\33\377\2\35\35\33\300\35\35\33\4\203" \
-  "\0\0\0\0\3\33\33\33\0\0\0\0\0\35\35\33'\220\35\35\33\377\2\35\35\33\220" \
-  "\35\35\33\5\316\0\0\0\0\31P\213\265\2057{\253\3673x\252\3778{\255\377" \
-  "<|\256\377\77\177\261\377C\201\263\377G\203\265\377J\205\266\377O\207" \
-  "\270\377R\211\272\377V\213\274\377Y\215\275\377\\\217\277\377_\221\301" \
-  "\377a\223\302\377d\225\304\377g\227\305\377j\230\307\377k\231\310\377" \
-  "m\232\311\377o\233\312\377p\234\313\377q\235\314\377r\236\314\377\202" \
-  "r\235\314\377\2j\230\311\377\330\344\361\377\205\377\377\377\377\6\344" \
-  "\354\365\377\247\303\336\377o\233\310\377q\235\310\377\252\305\336\377" \
-  "\334\347\361\377\203\377\377\377\377\36\374\375\376\377\306\330\350\377" \
-  "\177\251\314\377G\204\265\3776x\255\377D\201\261\377U\216\270\377p\240" \
-  "\303\377R\214\267\377%p\244\377!n\242\377\40o\242\377\33m\240\377\25" \
-  "l\237\377\15j\235\377\7h\232\377\0f\232\377\0d\227\377\0b\225\377\0`" \
-  "\223\377\0_\222\377\0]\221\377\0\\\217\377\0Z\215\377\0Y\214\377\0W\212" \
-  "\377\0U\210\377\0U\207\377\0S\205\377\0R\204\377\210\0P\203\377\2\0O" \
-  "\203\377`\217\262\15\224\0\0\0\0\2\34\34\33E\35\35\33\361\217\35\35\33" \
-  "\377\4\35\35\33\217\0\0\0\0\35\35\33O\35\35\33\343\215\35\35\33\377\4" \
-  "\35\35\33\351\35\35\33>\0\0\0\0\35\35\33\0\206\0\0\0\0\1\35\35\33\252" \
-  "\217\35\35\33\377\2\35\35\33\342\35\35\33H\205\0\0\0\0\2\37\37\35\30" \
-  "\35\35\33\271\217\35\35\33\377\2\35\35\33\333\35\35\33!\203\0\0\0\0\1" \
-  "\35\35\33d\217\35\35\33\377\2\35\35\33\371\35\35\33\201\205\0\0\0\0\2" \
-  "\23\23%\1\35\35\33|\217\35\35\33\377\2\35\35\33\370\34\34\33Q\206\0\0" \
-  "\0\0\2\34\34\33\35\35\35\33\253\217\35\35\33\377\2\35\35\33\363\31\31" \
-  "\33\20\212\0\0\0\0\1\35\35\33\233\217\35\35\33\377\2\35\35\33\351\35" \
-  "\35\33Q\205\0\0\0\0\2\33\33\31\24\35\35\33\256\217\35\35\33\377\2\35" \
-  "\35\33\343\34\34\32&\203\0\0\0\0\1\35\35\33W\217\35\35\33\377\2\35\35" \
-  "\33\374\35\35\33\211\205\0\0\0\0\2//\11\1\35\35\33n\217\35\35\33\377" \
-  "\2\35\35\33\375\35\35\33Q\203\0\0\0\0\2\35\35\33#\35\35\33\343\217\35" \
-  "\35\33\377\2\35\35\33\301\35\35\33\4\205\0\0\0\0\1\35\35\33(\220\35\35" \
-  "\33\377\2\35\35\33\220\35\35\33\5\316\0\0\0\0\31M\212\264\2115z\252\371" \
-  "1v\251\3775x\253\3779{\255\377=}\257\377@\177\261\377D\201\263\377G\203" \
-  "\265\377L\206\266\377O\207\270\377R\211\272\377V\213\274\377X\215\275" \
-  "\377[\216\277\377^\220\300\377a\222\302\377c\224\303\377e\225\304\377" \
-  "g\226\306\377i\227\306\377j\230\307\377k\231\311\377l\232\311\377m\232" \
-  "\312\377\202m\233\312\377\4j\230\311\377\231\271\331\377\271\316\345" \
-  "\377\353\361\367\377\204\377\377\377\377\7\376\376\377\377\316\335\354" \
-  "\377\216\262\323\377X\214\276\377q\236\307\377\247\303\334\377\337\351" \
-  "\362\377\203\377\377\377\377\34\355\363\370\377\254\307\335\377_\224" \
-  "\275\377>~\256\377G\205\262\3771w\251\377'q\245\377'r\244\377#p\242\377" \
-  "\35n\241\377\30l\237\377\22k\236\377\11i\234\377\2f\232\377\0e\230\377" \
-  "\0c\226\377\0a\225\377\0`\223\377\0^\221\377\0]\220\377\0[\216\377\0" \
-  "Y\214\377\0X\213\377\0W\212\377\0U\210\377\0T\206\377\0S\205\377\0Q\204" \
-  "\377\211\0P\203\377\1l\231\270\27\224\0\0\0\0\2\34\34\33E\35\35\33\361" \
-  "\217\35\35\33\377\3\35\35\33\214\34\34\36\10\35\35\33\240\215\35\35\33" \
-  "\377\2\35\35\33\373\35\35\33\240\211\0\0\0\0\1\35\35\33\252\217\35\35" \
-  "\33\377\2\35\35\33\342\35\35\33H\205\0\0\0\0\2\37\37\35\30\35\35\33\271" \
-  "\217\35\35\33\377\2\35\35\33\333\35\35\33!\203\0\0\0\0\1\35\35\33d\217" \
-  "\35\35\33\377\2\35\35\33\371\35\35\33\201\205\0\0\0\0\2\23\23%\1\35\35" \
-  "\33|\217\35\35\33\377\2\35\35\33\370\34\34\33Q\206\0\0\0\0\2\34\34\33" \
-  "\35\35\35\33\253\217\35\35\33\377\2\35\35\33\363\31\31\33\20\212\0\0" \
-  "\0\0\1\35\35\33\233\217\35\35\33\377\2\35\35\33\351\35\35\33Q\205\0\0" \
-  "\0\0\2\33\33\31\24\35\35\33\256\217\35\35\33\377\2\35\35\33\343\34\34" \
-  "\32&\203\0\0\0\0\1\35\35\33W\217\35\35\33\377\2\35\35\33\374\35\35\33" \
-  "\211\205\0\0\0\0\2//\11\1\35\35\33n\217\35\35\33\377\2\35\35\33\375\35" \
-  "\35\33Q\203\0\0\0\0\2\35\35\33#\35\35\33\343\217\35\35\33\377\2\35\35" \
-  "\33\301\35\35\33\4\205\0\0\0\0\1\35\35\33(\220\35\35\33\377\2\35\35\33" \
-  "\220\35\35\33\5\316\0\0\0\0\31K\211\263\2062x\251\370-t\250\3773w\252" \
-  "\3776y\254\377:|\256\377>}\257\377A\177\262\377D\202\263\377H\204\265" \
-  "\377K\205\267\377O\207\270\377R\211\272\377T\213\273\377W\214\275\377" \
-  "Y\216\276\377\\\217\300\377^\221\301\377`\222\302\377b\223\303\377d\224" \
-  "\304\377f\225\305\377f\226\306\377h\227\306\377h\227\307\377\202h\230" \
-  "\307\377\6b\224\305\377\275\322\346\377\253\305\340\377\221\263\326\377" \
-  "\264\314\343\377\360\365\371\377\204\377\377\377\377\7\357\364\371\377" \
-  "\272\317\344\377r\237\310\377F\202\265\377p\236\306\377\244\302\333\377" \
-  "\341\353\363\377\203\377\377\377\377\32\331\345\357\377\217\264\320\377" \
-  "<~\256\377$n\243\377(r\245\377%q\243\377\37o\242\377\32m\240\377\25k" \
-  "\237\377\15j\235\377\4h\232\377\0f\231\377\0d\227\377\0b\225\377\0a\224" \
-  "\377\0_\222\377\0]\220\377\0\\\217\377\0Z\215\377\0Y\214\377\0W\212\377" \
-  "\0V\211\377\0U\207\377\0T\206\377\0R\204\377\0Q\203\377\211\0P\203\377" \
-  "\1k\230\273\17\224\0\0\0\0\2\34\34\33E\35\35\33\361\217\35\35\33\377" \
-  "\3\35\35\33\202\35\35\33N\35\35\33\336\215\35\35\33\377\4\35\35\33\344" \
-  "\35\35\33%\0\0\0\0\35\35\33\0\207\0\0\0\0\1\35\35\33\252\217\35\35\33" \
-  "\377\2\35\35\33\342\35\35\33H\205\0\0\0\0\2\37\37\35\30\35\35\33\271" \
-  "\217\35\35\33\377\2\35\35\33\333\35\35\33!\203\0\0\0\0\1\35\35\33d\217" \
-  "\35\35\33\377\2\35\35\33\371\35\35\33\201\205\0\0\0\0\2\23\23%\1\35\35" \
-  "\33|\217\35\35\33\377\2\35\35\33\370\34\34\33Q\206\0\0\0\0\2\34\34\33" \
-  "\35\35\35\33\253\217\35\35\33\377\2\35\35\33\363\31\31\33\20\212\0\0" \
-  "\0\0\1\35\35\33\233\217\35\35\33\377\2\35\35\33\351\35\35\33Q\205\0\0" \
-  "\0\0\2\33\33\31\24\35\35\33\256\217\35\35\33\377\2\35\35\33\343\34\34" \
-  "\32&\203\0\0\0\0\1\35\35\33W\217\35\35\33\377\2\35\35\33\374\35\35\33" \
-  "\211\205\0\0\0\0\2//\11\1\35\35\33n\217\35\35\33\377\2\35\35\33\375\35" \
-  "\35\33Q\203\0\0\0\0\2\35\35\33#\35\35\33\343\217\35\35\33\377\2\35\35" \
-  "\33\301\35\35\33\4\205\0\0\0\0\1\35\35\33(\220\35\35\33\377\2\35\35\33" \
-  "\220\35\35\33\5\316\0\0\0\0\26G\207\262}.w\247\364*s\246\377/u\250\377" \
-  "4w\251\3777y\253\377;|\256\377=}\257\377A\200\262\377D\202\264\377G\203" \
-  "\265\377K\205\267\377M\207\270\377P\210\271\377S\211\272\377U\213\274" \
-  "\377X\214\275\377Z\216\277\377\\\217\300\377^\221\301\377_\221\301\377" \
-  "a\222\302\377\202b\223\303\377\203c\223\303\377\10X\214\300\377\352\361" \
-  "\367\377\365\370\373\377\306\330\352\377\217\262\324\377\200\250\316" \
-  "\377\267\316\343\377\366\371\374\377\204\377\377\377\377\7\335\350\362" \
-  "\377\236\276\330\377Q\211\270\377\77}\261\377k\233\302\377\243\301\331" \
-  "\377\352\361\366\377\202\377\377\377\377\30\365\370\373\377\301\326\345" \
-  "\377i\235\300\377#o\242\377\34k\237\377\34m\241\377\27l\237\377\20j\235" \
-  "\377\10h\233\377\2f\232\377\0e\230\377\0c\226\377\0a\224\377\0`\223\377" \
-  "\0^\221\377\0\\\220\377\0[\216\377\0Z\215\377\0X\213\377\0W\212\377\0" \
-  "U\210\377\0T\206\377\0S\205\377\0R\204\377\211\0P\203\377\2\3R\204\377" \
-  "3p\241\4\224\0\0\0\0\2\34\34\33E\35\35\33\361\217\35\35\33\377\2\35\35" \
-  "\33\222\35\35\33\234\215\35\35\33\377\4\35\35\33\367\35\35\33\177\0\0" \
-  "\0\0""55\33\0\210\0\0\0\0\1\35\35\33\252\217\35\35\33\377\2\35\35\33" \
-  "\342\35\35\33H\205\0\0\0\0\2\37\37\35\30\35\35\33\271\217\35\35\33\377" \
-  "\2\35\35\33\333\35\35\33!\203\0\0\0\0\1\35\35\33d\217\35\35\33\377\2" \
-  "\35\35\33\371\35\35\33\201\205\0\0\0\0\2\23\23%\1\35\35\33|\217\35\35" \
-  "\33\377\2\35\35\33\370\34\34\33Q\206\0\0\0\0\2\34\34\33\35\35\35\33\253" \
-  "\217\35\35\33\377\2\35\35\33\363\31\31\33\20\212\0\0\0\0\1\35\35\33\233" \
-  "\217\35\35\33\377\2\35\35\33\351\35\35\33Q\205\0\0\0\0\2\33\33\31\24" \
-  "\35\35\33\256\217\35\35\33\377\2\35\35\33\343\34\34\32&\203\0\0\0\0\1" \
-  "\35\35\33W\217\35\35\33\377\2\35\35\33\374\35\35\33\211\205\0\0\0\0\2" \
-  "//\11\1\35\35\33n\217\35\35\33\377\2\35\35\33\375\35\35\33Q\203\0\0\0" \
-  "\0\2\35\35\33#\35\35\33\343\217\35\35\33\377\2\35\35\33\301\35\35\33" \
-  "\4\205\0\0\0\0\1\35\35\33(\220\35\35\33\377\2\35\35\33\220\35\35\33\5" \
-  "\316\0\0\0\0\31""9\177\255i)s\245\354'r\245\377,t\247\3770v\250\3773" \
-  "w\252\3777y\253\377:{\255\377>~\260\377@\177\261\377D\201\263\377G\202" \
-  "\264\377J\204\266\377M\206\267\377O\210\271\377Q\211\272\377T\212\273" \
-  "\377V\213\274\377W\214\275\377Y\216\276\377[\217\277\377\\\217\300\377" \
-  "^\217\300\377^\220\301\377^\221\301\377\202_\221\301\377\2T\212\275\377" \
-  "\344\354\365\377\202\377\377\377\377\6\346\356\365\377\263\313\342\377" \
-  "t\240\310\377z\244\313\377\270\317\343\377\371\373\375\377\203\377\377" \
-  "\377\377\10\370\372\374\377\312\333\352\377}\250\312\3777y\255\377\77" \
-  "~\257\377f\230\277\377\241\300\330\377\360\364\371\377\202\377\377\377" \
-  "\377\26\346\357\365\377\247\305\332\377;\201\255\377\21g\234\377\22i" \
-  "\235\377\13i\234\377\4g\232\377\0e\231\377\0d\227\377\0b\225\377\0`\223" \
-  "\377\0_\222\377\0]\220\377\0\\\217\377\0Z\215\377\0Y\214\377\0W\212\377" \
-  "\0V\211\377\0U\207\377\0T\206\377\0S\205\377\0Q\203\377\211\0P\203\377" \
-  "\3\17[\212\377\7U\205\3\236\266\333\0\223\0\0\0\0\2\34\34\33E\35\35\33" \
-  "\361\217\35\35\33\377\2\35\35\33\337\35\35\33\347\215\35\35\33\377\4" \
-  "\35\35\33\362\35\35\33N\0\0\0\0\34\34\34\0\210\0\0\0\0\1\35\35\33\252" \
-  "\217\35\35\33\377\2\35\35\33\342\35\35\33H\205\0\0\0\0\2\37\37\35\30" \
-  "\35\35\33\271\217\35\35\33\377\2\35\35\33\333\35\35\33!\203\0\0\0\0\1" \
-  "\35\35\33d\217\35\35\33\377\2\35\35\33\371\35\35\33\201\205\0\0\0\0\2" \
-  "\23\23%\1\35\35\33|\217\35\35\33\377\2\35\35\33\370\34\34\33Q\206\0\0" \
-  "\0\0\2\34\34\33\35\35\35\33\253\217\35\35\33\377\2\35\35\33\363\31\31" \
-  "\33\20\212\0\0\0\0\1\35\35\33\233\217\35\35\33\377\2\35\35\33\351\35" \
-  "\35\33Q\205\0\0\0\0\2\33\33\31\24\35\35\33\256\217\35\35\33\377\2\35" \
-  "\35\33\343\34\34\32&\203\0\0\0\0\1\35\35\33W\217\35\35\33\377\2\35\35" \
-  "\33\374\35\35\33\211\205\0\0\0\0\2//\11\1\35\35\33n\217\35\35\33\377" \
-  "\2\35\35\33\375\35\35\33Q\203\0\0\0\0\2\35\35\33#\35\35\33\343\217\35" \
-  "\35\33\377\2\35\35\33\301\35\35\33\4\205\0\0\0\0\1\35\35\33(\220\35\35" \
-  "\33\377\2\35\35\33\220\35\35\33\5\316\0\0\0\0\27-x\247R#p\243\343$q\243" \
-  "\377)s\245\377,t\247\377/v\250\3774x\252\3776z\254\377:|\256\377=}\257" \
-  "\377@\177\261\377B\201\263\377F\202\265\377I\204\266\377K\205\267\377" \
-  "N\207\270\377P\210\271\377Q\211\272\377S\212\273\377U\213\274\377V\214" \
-  "\275\377X\214\275\377Y\215\276\377\202Z\216\277\377\4[\217\277\377Z\217" \
-  "\277\377O\207\272\377\347\356\366\377\203\377\377\377\377\6\374\375\376" \
-  "\377\334\347\362\377\224\266\324\377Z\217\275\377v\242\310\377\275\322" \
-  "\344\377\204\377\377\377\377\36\354\362\367\377\262\314\340\377U\215" \
-  "\271\377&n\245\377:}\255\377_\225\274\377\244\303\331\377\367\372\374" \
-  "\377\377\377\377\377\376\376\377\377\330\346\357\377{\254\311\377\17" \
-  "k\235\377\0c\231\377\0f\231\377\0e\230\377\0c\226\377\0a\224\377\0_\222" \
-  "\377\0^\222\377\0\\\220\377\0[\216\377\0Z\215\377\0X\213\377\0W\212\377" \
-  "\0V\210\377\0T\206\377\0S\205\377\0R\204\377\0Q\203\377\210\0P\203\377" \
-  "\3\0O\202\377\35d\221\372\37f\222\3\224\0\0\0\0\2\34\34\33E\35\35\33" \
-  "\361\217\35\35\33\377\2\35\35\33\334\35\35\33\343\215\35\35\33\377\4" \
-  "\35\35\33\374\35\35\33\253\0\0\0\0""22\6\0\210\0\0\0\0\1\35\35\33\252" \
-  "\217\35\35\33\377\2\35\35\33\342\35\35\33H\205\0\0\0\0\2\37\37\35\30" \
-  "\35\35\33\271\217\35\35\33\377\2\35\35\33\333\35\35\33!\203\0\0\0\0\1" \
-  "\35\35\33d\217\35\35\33\377\2\35\35\33\371\35\35\33\201\205\0\0\0\0\2" \
-  "\23\23%\1\35\35\33|\217\35\35\33\377\2\35\35\33\370\34\34\33Q\206\0\0" \
-  "\0\0\2\34\34\33\35\35\35\33\253\217\35\35\33\377\2\35\35\33\363\31\31" \
-  "\33\20\212\0\0\0\0\1\35\35\33\233\217\35\35\33\377\2\35\35\33\351\35" \
-  "\35\33Q\205\0\0\0\0\2\33\33\31\24\35\35\33\256\217\35\35\33\377\2\35" \
-  "\35\33\343\34\34\32&\203\0\0\0\0\1\35\35\33W\217\35\35\33\377\2\35\35" \
-  "\33\374\35\35\33\211\205\0\0\0\0\2//\11\1\35\35\33n\217\35\35\33\377" \
-  "\2\35\35\33\375\35\35\33Q\203\0\0\0\0\2\35\35\33#\35\35\33\343\217\35" \
-  "\35\33\377\2\35\35\33\301\35\35\33\4\205\0\0\0\0\1\35\35\33(\220\35\35" \
-  "\33\377\2\35\35\33\220\35\35\33\5\316\0\0\0\0\30O\217\264G#r\243\336" \
-  "\40o\242\377%q\243\377)r\245\377,t\247\3770v\250\3773w\251\3776y\253" \
-  "\3779|\256\377<}\257\377\77~\260\377A\200\262\377D\201\263\377G\202\264" \
-  "\377I\204\266\377K\205\267\377M\206\270\377O\207\270\377Q\210\271\377" \
-  "R\211\272\377S\211\272\377T\212\273\377T\213\274\377\203U\213\274\377" \
-  "\2L\204\270\377\303\326\347\377\205\377\377\377\377\6\362\366\372\377" \
-  "\312\334\352\377q\237\306\377K\205\267\377s\241\306\377\301\325\346\377" \
-  "\203\377\377\377\377\10\374\375\376\377\335\350\361\377\215\263\317\377" \
-  "3x\252\377\40m\242\3774z\251\377V\221\270\377\253\311\334\377\202\377" \
-  "\377\377\377\22\362\367\372\377\277\330\345\377B\216\263\377\0_\224\377" \
-  "\0b\225\377\0a\224\377\0`\223\377\0_\222\377\0]\221\377\0\\\217\377\0" \
-  "Z\215\377\0Y\214\377\0W\213\377\0V\211\377\0V\210\377\0T\206\377\0S\205" \
-  "\377\0Q\203\377\211\0P\203\377\3\0O\202\377#h\223\340%j\225\3\224\0\0" \
-  "\0\0\2\34\34\33E\35\35\33\361\217\35\35\33\377\2\35\35\33\230\35\35\33" \
-  "\254\216\35\35\33\377\4\35\35\33\350\37\37\31""7\0\0\0\0\34\34\34\0\207" \
-  "\0\0\0\0\1\35\35\33\252\217\35\35\33\377\2\35\35\33\342\35\35\33H\205" \
-  "\0\0\0\0\2\37\37\35\30\35\35\33\271\217\35\35\33\377\2\35\35\33\333\35" \
-  "\35\33!\203\0\0\0\0\1\35\35\33d\217\35\35\33\377\2\35\35\33\371\35\35" \
-  "\33\201\205\0\0\0\0\2\23\23%\1\35\35\33|\217\35\35\33\377\2\35\35\33" \
-  "\370\34\34\33Q\206\0\0\0\0\2\34\34\33\35\35\35\33\253\217\35\35\33\377" \
-  "\2\35\35\33\363\31\31\33\20\212\0\0\0\0\1\35\35\33\233\217\35\35\33\377" \
-  "\2\35\35\33\351\35\35\33Q\205\0\0\0\0\2\33\33\31\24\35\35\33\262\217" \
-  "\35\35\33\377\2\35\35\33\350\33\33\32&\203\0\0\0\0\1\35\35\33W\217\35" \
-  "\35\33\377\2\35\35\33\374\35\35\33\211\205\0\0\0\0\2//\11\1\35\35\33" \
-  "n\217\35\35\33\377\2\35\35\33\375\35\35\33Q\203\0\0\0\0\2\35\35\33#\35" \
-  "\35\33\343\217\35\35\33\377\2\35\35\33\301\35\35\33\4\205\0\0\0\0\1\35" \
-  "\35\33(\220\35\35\33\377\2\35\35\33\220\35\35\33\5\316\0\0\0\0\31\177" \
-  "\256\3125#s\243\326\34m\240\377\"o\242\377%q\244\377)r\245\377,t\247" \
-  "\377/v\250\3773w\252\3776z\253\3778z\255\377;|\256\377>~\260\377@\177" \
-  "\261\377B\200\262\377D\202\264\377F\203\265\377I\204\266\377J\205\266" \
-  "\377K\206\267\377M\206\267\377N\207\270\377P\210\270\377P\210\271\377" \
-  "Q\211\271\377\202Q\210\271\377\4O\207\271\377a\224\300\377}\247\313\377" \
-  "\324\342\356\377\205\377\377\377\377\6\352\361\366\377\255\310\336\377" \
-  "K\206\266\377F\203\263\377o\237\304\377\306\331\350\377\203\377\377\377" \
-  "\377\10\367\372\374\377\310\333\350\377]\225\273\377\33j\237\377\33l" \
-  "\240\377)w\246\377K\215\264\377\262\317\337\377\202\377\377\377\377\20" \
-  "\351\362\366\377\232\301\326\377\20l\234\377\0[\220\377\0_\222\377\0" \
-  "]\221\377\0\\\217\377\0[\216\377\0Y\214\377\0X\213\377\0W\212\377\0V" \
-  "\211\377\0U\206\377\0S\205\377\0R\204\377\0Q\203\377\212\0P\203\377\2" \
-  "\30a\217\255\33c\220\2\224\0\0\0\0\2\34\34\33E\35\35\33\361\217\35\35" \
-  "\33\377\3\35\35\33\203\35\35\33j\35\35\33\354\215\35\35\33\377\4\35\35" \
-  "\33\374\35\35\33\252\0\0\0\0&&\22\0\207\0\0\0\0\1\35\35\33\252\217\35" \
-  "\35\33\377\2\35\35\33\342\35\35\33H\205\0\0\0\0\2\37\37\35\30\35\35\33" \
-  "\271\217\35\35\33\377\2\35\35\33\333\35\35\33!\203\0\0\0\0\1\35\35\33" \
-  "d\217\35\35\33\377\2\35\35\33\371\35\35\33\201\205\0\0\0\0\2\23\23%\1" \
-  "\35\35\33|\217\35\35\33\377\2\35\35\33\370\34\34\33Q\206\0\0\0\0\2\34" \
-  "\34\33\35\35\35\33\253\217\35\35\33\377\2\35\35\33\363\31\31\33\20\212" \
-  "\0\0\0\0\1\35\35\33\233\217\35\35\33\377\2\35\35\33\351\35\35\33Q\205" \
-  "\0\0\0\0\3\35\35\31\20\35\35\33\213\35\35\33\324\215\35\35\33\314\3\35" \
-  "\35\33\316\35\35\33\266\35\35\32\36\203\0\0\0\0\1\35\35\33W\217\35\35" \
-  "\33\377\2\35\35\33\374\35\35\33\211\205\0\0\0\0\2//\11\1\35\35\33n\217" \
-  "\35\35\33\377\2\35\35\33\375\35\35\33Q\203\0\0\0\0\2\35\35\33#\35\35" \
-  "\33\343\217\35\35\33\377\2\35\35\33\301\35\35\33\4\205\0\0\0\0\1\35\35" \
-  "\33(\220\35\35\33\377\2\35\35\33\220\35\35\33\5\316\0\0\0\0\26\377\377" \
-  "\377\6\32n\241\304\27l\237\377\34n\241\377!o\242\377%q\243\377(r\245" \
-  "\377,s\246\377/u\250\3772v\251\3775x\252\3777y\255\377:{\255\377=}\257" \
-  "\377\77~\260\377@\200\262\377B\200\262\377D\202\263\377F\202\264\377" \
-  "G\203\265\377H\204\266\377I\205\266\377\202K\205\267\377\1L\205\267\377" \
-  "\202L\206\267\377\6B\177\263\377\315\335\353\377\236\276\330\377U\214" \
-  "\273\377{\246\312\377\332\346\360\377\204\377\377\377\377\7\372\374\375" \
-  "\377\337\352\362\377\204\255\314\3772w\252\377@\200\260\377m\236\302" \
-  "\377\315\336\352\377\202\377\377\377\377\30\376\376\377\377\360\365\371" \
-  "\377\240\302\330\377.y\250\377\16e\233\377\17j\235\377\27q\241\377D\216" \
-  "\264\377\276\330\345\377\377\377\377\377\375\376\376\377\335\353\361" \
-  "\377e\237\276\377\0Y\215\377\0Z\216\377\0\\\217\377\0Z\215\377\0X\213" \
-  "\377\0W\213\377\0V\211\377\0U\210\377\0T\206\377\0S\205\377\0Q\204\377" \
-  "\212\0P\203\377\3\0O\203\377#h\224\207'k\226\2\224\0\0\0\0\2\34\34\33" \
-  "E\35\35\33\361\217\35\35\33\377\3\35\35\33\211\35\35\34\40\35\35\33\276" \
-  "\216\35\35\33\377\4\35\35\33\343\35\35\33""7\0\0\0\0\30\30\30\0\206\0" \
-  "\0\0\0\1\35\35\33\252\217\35\35\33\377\2\35\35\33\342\35\35\33H\205\0" \
-  "\0\0\0\2\37\37\35\30\35\35\33\271\217\35\35\33\377\2\35\35\33\333\35" \
-  "\35\33!\203\0\0\0\0\1\35\35\33d\217\35\35\33\377\2\35\35\33\371\35\35" \
-  "\33\201\205\0\0\0\0\2\23\23%\1\35\35\33|\217\35\35\33\377\2\35\35\33" \
-  "\370\34\34\33Q\206\0\0\0\0\2\34\34\33\35\35\35\33\253\217\35\35\33\377" \
-  "\2\35\35\33\363\31\31\33\20\212\0\0\0\0\1\35\35\33\233\217\35\35\33\377" \
-  "\2\35\35\33\351\35\35\33Q\205\0\0\0\0\3\35\35\31\2\35\35\33\17\35\35" \
-  "\33\27\216\35\35\33\26\2\35\35\33\24\35\35\32\3\203\0\0\0\0\1\35\35\33" \
-  "W\217\35\35\33\377\2\35\35\33\374\35\35\33\211\205\0\0\0\0\2//\11\1\35" \
-  "\35\33n\217\35\35\33\377\2\35\35\33\375\35\35\33Q\203\0\0\0\0\2\35\35" \
-  "\33#\35\35\33\343\217\35\35\33\377\2\35\35\33\301\35\35\33\4\205\0\0" \
-  "\0\0\1\35\35\33(\220\35\35\33\377\2\35\35\33\220\35\35\33\5\317\0\0\0" \
-  "\0\30(x\246\264\31n\240\377\30l\237\377\34m\240\377\40o\242\377$q\243" \
-  "\377&q\244\377+s\246\377.t\247\3770v\250\3774w\251\3776y\253\3777y\254" \
-  "\377:{\256\377=}\257\377>~\260\377\77\177\261\377A\200\262\377B\200\262" \
-  "\377D\201\263\377E\201\263\377E\202\264\377F\202\264\377G\202\264\377" \
-  "\202G\203\265\377\10:{\260\377\341\353\363\377\374\375\376\377\333\346" \
-  "\360\377q\237\306\377H\204\264\377|\247\311\377\335\351\362\377\204\377" \
-  "\377\377\377\7\366\371\373\377\307\332\350\377V\217\270\377&o\244\377" \
-  "8|\254\377o\241\303\377\330\345\357\377\202\377\377\377\377\26\374\375" \
-  "\376\377\340\353\362\377g\241\300\377\13i\234\377\0d\230\377\2g\232\377" \
-  "\13k\234\377H\217\264\377\317\341\352\377\377\377\377\377\367\372\374" \
-  "\377\304\331\345\377.z\243\377\0S\210\377\0X\214\377\0X\213\377\0W\212" \
-  "\377\0V\211\377\0T\206\377\0S\205\377\0R\204\377\0Q\203\377\212\0P\203" \
-  "\377\3\0O\202\377Q\207\253b_\222\262\1\224\0\0\0\0\2\34\34\33E\35\35" \
-  "\33\361\217\35\35\33\377\4\35\35\33\216\0\0\0\0\35\35\33\202\35\35\33" \
-  "\372\215\35\35\33\377\4\35\35\33\374\35\35\33\245\0\0\0\0\377\377\377" \
-  "\0\206\0\0\0\0\1\35\35\33\252\217\35\35\33\377\2\35\35\33\342\35\35\33" \
-  "H\205\0\0\0\0\2\37\37\35\30\35\35\33\271\217\35\35\33\377\2\35\35\33" \
-  "\333\35\35\33!\203\0\0\0\0\1\35\35\33d\217\35\35\33\377\2\35\35\33\371" \
-  "\35\35\33\201\205\0\0\0\0\2\23\23%\1\35\35\33|\217\35\35\33\377\2\35" \
-  "\35\33\370\34\34\33Q\206\0\0\0\0\2\34\34\33\35\35\35\33\253\217\35\35" \
-  "\33\377\2\35\35\33\363\31\31\33\20\212\0\0\0\0\1\35\35\33\233\217\35" \
-  "\35\33\377\2\35\35\33\351\35\35\33Q\204\0\0\0\0\1\35\35\32\0\223\0\0" \
-  "\0\0\1\35\35\32\0\202\0\0\0\0\1\35\35\33W\217\35\35\33\377\2\35\35\33" \
-  "\374\35\35\33\211\205\0\0\0\0\2//\11\1\35\35\33n\217\35\35\33\377\2\35" \
-  "\35\33\375\35\35\33Q\203\0\0\0\0\2\35\35\33#\35\35\33\343\217\35\35\33" \
-  "\377\2\35\35\33\301\35\35\33\4\205\0\0\0\0\1\35\35\33(\220\35\35\33\377" \
-  "\2\35\35\33\220\35\35\33\5\315\0\0\0\0\26{\254\311\0\0\0\0\0+~\251\210" \
-  "\22m\236\366\23j\235\377\31l\237\377\34m\240\377\37o\242\377#p\243\377" \
-  "&q\244\377)s\245\377,t\246\3770u\250\3771v\251\3773w\252\3775x\253\377" \
-  "8z\255\3779{\255\377;{\255\377<}\257\377=~\260\377\77~\260\377\202@\177" \
-  "\261\377\16B\200\262\377C\200\262\377B\177\262\377A\200\262\3775w\255" \
-  "\377\337\352\362\377\377\377\377\377\376\377\377\377\372\374\375\377" \
-  "\270\317\342\377N\211\267\377B\201\261\377{\246\310\377\340\353\363\377" \
-  "\204\377\377\377\377\7\356\364\370\377\233\275\326\3770w\250\377\"n\242" \
-  "\377.w\250\377o\243\303\377\336\352\361\377\202\377\377\377\377\23\376" \
-  "\376\376\377\274\326\344\377-\201\253\377\0c\227\377\0b\226\377\2c\225" \
-  "\377\10e\226\377U\224\266\377\327\346\356\377\377\377\377\377\362\367" \
-  "\371\377\220\267\315\377\10^\217\377\0S\210\377\0V\211\377\0U\207\377" \
-  "\0S\206\377\0R\205\377\0Q\204\377\213\0P\203\377\3\6T\206\377L\204\247" \
-  "\31\266\315\331\0\224\0\0\0\0\2\34\34\33E\35\35\33\361\217\35\35\33\377" \
-  "\4\35\35\33\216\0\0\0\0\35\35\33""5\35\35\33\323\216\35\35\33\377\4\35" \
-  "\35\33\336\35\35\34""5\0\0\0\0\24\24\24\0\205\0\0\0\0\1\35\35\33\252" \
-  "\217\35\35\33\377\2\35\35\33\342\35\35\33H\205\0\0\0\0\2\37\37\35\30" \
-  "\35\35\33\271\217\35\35\33\377\2\35\35\33\333\35\35\33!\203\0\0\0\0\1" \
-  "\35\35\33d\217\35\35\33\377\2\35\35\33\371\35\35\33\201\205\0\0\0\0\2" \
-  "\23\23%\1\35\35\33|\217\35\35\33\377\2\35\35\33\370\34\34\33Q\206\0\0" \
-  "\0\0\2\34\34\33\35\35\35\33\253\217\35\35\33\377\2\35\35\33\363\31\31" \
-  "\33\20\212\0\0\0\0\1\35\35\33\233\217\35\35\33\377\2\35\35\33\351\35" \
-  "\35\33Q\233\0\0\0\0\1\35\35\33W\217\35\35\33\377\2\35\35\33\374\35\35" \
-  "\33\211\205\0\0\0\0\2//\11\1\35\35\33n\217\35\35\33\377\2\35\35\33\375" \
-  "\35\35\33Q\203\0\0\0\0\2\35\35\33#\35\35\33\343\217\35\35\33\377\2\35" \
-  "\35\33\301\35\35\33\4\205\0\0\0\0\1\35\35\33(\220\35\35\33\377\2\35\35" \
-  "\33\220\35\35\33\5\317\0\0\0\0\26.\201\254Q\13k\235\345\13i\234\377\21" \
-  "k\236\377\27l\237\377\32m\240\377\36n\241\377!p\243\377$q\243\377'r\244" \
-  "\377*s\246\377,t\247\377/u\250\3772v\251\3773x\252\3775y\253\3777y\254" \
-  "\3778z\254\3779z\256\377;|\256\377;}\257\377<}\257\377\202=~\260\377" \
-  "\202>~\260\377\2""1v\252\377\337\352\362\377\203\377\377\377\377\7\376" \
-  "\376\376\377\361\366\371\377\212\260\316\3774x\253\377;|\256\377\177" \
-  "\252\312\377\345\356\364\377\204\377\377\377\377\7\332\347\360\377c\233" \
-  "\277\377\31l\237\377\30l\237\377!s\244\377u\251\306\377\346\360\365\377" \
-  "\202\377\377\377\377\3\367\372\374\377\202\263\314\377\11g\231\377\202" \
-  "\0_\222\377\10\2^\222\377\7`\223\377d\233\272\377\346\357\364\377\377" \
-  "\377\377\377\336\352\360\377T\215\257\377\0P\204\377\202\0S\205\377\1" \
-  "\0Q\204\377\213\0P\203\377\3\0O\202\377\36e\222\354%j\225\11\225\0\0" \
-  "\0\0\2\34\34\33E\35\35\33\361\217\35\35\33\377\4\35\35\33\216\34\34(" \
-  "\3\0\0\0\0\35\35\33\243\216\35\35\33\377\2\35\35\33\374\35\35\33\236" \
-  "\207\0\0\0\0\1\35\35\33\252\217\35\35\33\377\2\35\35\33\342\35\35\33" \
-  "H\205\0\0\0\0\2\37\37\35\30\35\35\33\271\217\35\35\33\377\2\35\35\33" \
-  "\333\35\35\33!\203\0\0\0\0\1\35\35\33d\217\35\35\33\377\2\35\35\33\371" \
-  "\35\35\33\201\205\0\0\0\0\2\23\23%\1\35\35\33|\217\35\35\33\377\2\35" \
-  "\35\33\370\34\34\33Q\206\0\0\0\0\2\34\34\33\35\35\35\33\253\217\35\35" \
-  "\33\377\2\35\35\33\363\31\31\33\20\212\0\0\0\0\1\35\35\33\233\217\35" \
-  "\35\33\377\2\35\35\33\351\35\35\33Q\233\0\0\0\0\1\35\35\33W\217\35\35" \
-  "\33\377\2\35\35\33\374\35\35\33\211\205\0\0\0\0\2//\11\1\35\35\33n\217" \
-  "\35\35\33\377\2\35\35\33\375\35\35\33Q\203\0\0\0\0\2\35\35\33#\35\35" \
-  "\33\343\217\35\35\33\377\2\35\35\33\301\35\35\33\4\205\0\0\0\0\1\35\35" \
-  "\33(\220\35\35\33\377\2\35\35\33\220\35\35\33\5\317\0\0\0\0\22\246\312" \
-  "\335\34\10k\235\324\5g\233\377\14i\234\377\21j\236\377\26l\237\377\31" \
-  "l\240\377\34m\241\377\40o\242\377#p\243\377&q\244\377(r\245\377*s\246" \
-  "\377-t\247\377/u\250\3770v\250\3772w\251\3774x\252\377\2025x\253\377" \
-  "\2026z\254\377\1""8z\255\377\2039z\255\377\3.s\250\377\306\331\347\377" \
-  "\376\376\377\377\204\377\377\377\377\7\376\377\377\377\331\345\357\377" \
-  "[\223\273\377+s\245\3773y\252\377\200\254\312\377\347\357\365\377\203" \
-  "\377\377\377\377\10\375\375\376\377\261\315\337\3774\177\253\377\13g" \
-  "\233\377\7h\233\377\20n\237\377z\257\311\377\354\363\367\377\202\377" \
-  "\377\377\377\16\336\353\361\377F\213\260\377\2^\222\377\0\\\220\377\0" \
-  "\\\217\377\0Z\215\377\10^\217\377o\241\276\377\356\364\367\377\375\376" \
-  "\376\377\266\316\335\377#k\226\377\0N\201\377\0Q\203\377\213\0P\203\377" \
-  "\3\0O\203\377\32b\217\230\40f\222\5\225\0\0\0\0\2\34\34\33E\35\35\33" \
-  "\361\217\35\35\33\377\5\35\35\33\216\35\35%\3\0\0\0\0\35\35\33S\35\35" \
-  "\33\343\216\35\35\33\377\4\35\35\33\331\34\34\32""4\0\0\0\0\34\34\34" \
-  "\0\204\0\0\0\0\1\35\35\33\252\217\35\35\33\377\2\35\35\33\342\35\35\33" \
-  "H\205\0\0\0\0\2\37\37\35\30\35\35\33\271\217\35\35\33\377\2\35\35\33" \
-  "\333\35\35\33!\203\0\0\0\0\1\35\35\33d\217\35\35\33\377\2\35\35\33\371" \
-  "\35\35\33\201\205\0\0\0\0\2\23\23%\1\35\35\33|\217\35\35\33\377\2\35" \
-  "\35\33\370\34\34\33Q\206\0\0\0\0\2\34\34\33\35\35\35\33\253\217\35\35" \
-  "\33\377\2\35\35\33\363\31\31\33\20\212\0\0\0\0\1\35\35\33\233\217\35" \
-  "\35\33\377\2\35\35\33\351\35\35\33Q\233\0\0\0\0\1\35\35\33W\217\35\35" \
-  "\33\377\2\35\35\33\374\35\35\33\211\205\0\0\0\0\2//\11\1\35\35\33n\217" \
-  "\35\35\33\377\2\35\35\33\375\35\35\33Q\203\0\0\0\0\2\35\35\33#\35\35" \
-  "\33\343\217\35\35\33\377\2\35\35\33\301\35\35\33\4\205\0\0\0\0\1\35\35" \
-  "\33(\220\35\35\33\377\2\35\35\33\220\35\35\33\5\316\0\0\0\0\27d\242\302" \
-  "\0\0\0\0\0\34v\243\267\6i\234\377\3g\232\377\10h\233\377\17j\235\377" \
-  "\24k\236\377\27l\237\377\33m\240\377\36n\241\377\40o\242\377#p\243\377" \
-  "%q\243\377(r\244\377)s\245\377+t\247\377,t\247\377/u\250\3770v\250\377" \
-  "0v\251\3772w\251\3773w\251\377\2023x\252\377\2024x\252\377\6""1v\251" \
-  "\377N\211\265\377q\241\304\377\323\342\355\377\372\374\375\377\376\377" \
-  "\377\377\203\377\377\377\377\7\376\376\376\377\253\310\334\3777|\253" \
-  "\377\"o\243\377+u\246\377\202\256\312\377\350\360\365\377\203\377\377" \
-  "\377\377\26\355\364\370\377s\252\307\377\17o\237\377\0e\230\377\0a\225" \
-  "\377\20m\235\377\212\267\316\377\357\366\371\377\376\377\377\377\377" \
-  "\377\377\377\254\312\333\377\34n\233\377\2[\216\377\0Y\214\377\0X\213" \
-  "\377\0U\211\377\16^\217\377\203\254\304\377\364\367\372\377\357\364\370" \
-  "\377x\243\275\377\11V\210\377\213\0P\203\377\3\0O\203\377K\203\250Zn" \
-  "\234\271\3\225\0\0\0\0\2\34\34\33E\35\35\33\361\217\35\35\33\377\5\35" \
-  "\35\33\216\35\35%\3\0\0\0\0\35\35\23\3\35\35\33\275\216\35\35\33\377" \
-  "\2\35\35\33\374\35\35\33\227\206\0\0\0\0\1\35\35\33\252\217\35\35\33" \
-  "\377\2\35\35\33\342\35\35\33H\205\0\0\0\0\2\37\37\35\30\35\35\33\271" \
-  "\217\35\35\33\377\2\35\35\33\333\35\35\33!\203\0\0\0\0\1\35\35\33d\217" \
-  "\35\35\33\377\2\35\35\33\371\35\35\33\201\205\0\0\0\0\2\23\23%\1\35\35" \
-  "\33|\217\35\35\33\377\2\35\35\33\370\34\34\33Q\206\0\0\0\0\2\34\34\33" \
-  "\35\35\35\33\253\217\35\35\33\377\2\35\35\33\363\31\31\33\20\212\0\0" \
-  "\0\0\1\35\35\33\233\217\35\35\33\377\2\35\35\33\351\35\35\33Q\233\0\0" \
-  "\0\0\1\35\35\33W\217\35\35\33\377\2\35\35\33\374\35\35\33\211\205\0\0" \
-  "\0\0\2//\11\1\35\35\33n\217\35\35\33\377\2\35\35\33\375\35\35\33Q\203" \
-  "\0\0\0\0\2\35\35\33#\35\35\33\343\217\35\35\33\377\2\35\35\33\301\35" \
-  "\35\33\4\205\0\0\0\0\1\35\35\33(\220\35\35\33\377\2\35\35\33\220\35\35" \
-  "\33\5\320\0\0\0\0\24&z\247h\4g\231\356\0f\231\377\3g\232\377\7h\233\377" \
-  "\14i\234\377\20j\236\377\26l\237\377\30l\237\377\33m\240\377\36n\241" \
-  "\377\40o\242\377#p\243\377%q\244\377&q\244\377(r\245\377)s\246\377+t" \
-  "\246\377,t\247\377-t\247\377\202.u\250\377\13/u\250\377/v\251\3770v\251" \
-  "\377!m\243\377\343\355\363\377\270\321\341\377C\203\261\377k\235\302" \
-  "\377\320\340\354\377\370\372\374\377\376\376\377\377\203\377\377\377" \
-  "\377\10\355\364\370\377x\250\306\377!q\242\377\25i\236\377$t\244\377" \
-  "\205\262\315\377\344\356\364\377\375\376\376\377\202\377\377\377\377" \
-  "\26\313\340\352\377A\214\262\377\6g\231\377\0a\225\377\0[\220\377\31" \
-  "o\235\377\226\275\322\377\357\365\370\377\377\377\377\377\370\373\374" \
-  "\377p\242\277\377\12^\220\377\1X\212\377\0U\210\377\0T\206\377\0P\203" \
-  "\377\25a\217\377\222\265\312\377\367\371\373\377\316\336\347\377G\201" \
-  "\246\377\2Q\204\377\210\0P\203\377\5\0O\202\377\26_\215\375\34c\223\17" \
-  "\0\0\0\0\0FM\0\224\0\0\0\0\2\34\34\33E\35\35\33\361\217\35\35\33\377" \
-  "\2\35\35\33\216\35\35%\3\202\0\0\0\0\2\35\35\33s\35\35\33\360\216\35" \
-  "\35\33\377\4\35\35\33\324\35\35\33""2\0\0\0\0%%#\0\203\0\0\0\0\1\35\35" \
-  "\33\252\217\35\35\33\377\2\35\35\33\342\35\35\33H\205\0\0\0\0\2\37\37" \
-  "\35\30\35\35\33\271\217\35\35\33\377\2\35\35\33\333\35\35\33!\203\0\0" \
-  "\0\0\1\35\35\33d\217\35\35\33\377\2\35\35\33\371\35\35\33\201\205\0\0" \
-  "\0\0\2\23\23%\1\35\35\33|\217\35\35\33\377\2\35\35\33\370\34\34\33Q\206" \
-  "\0\0\0\0\2\34\34\33\35\35\35\33\253\217\35\35\33\377\2\35\35\33\363\32" \
-  "\32\33\20\212\0\0\0\0\1\35\35\33\233\217\35\35\33\377\2\35\35\33\351" \
-  "\35\35\33Q\233\0\0\0\0\1\35\35\33W\217\35\35\33\377\2\35\35\33\374\35" \
-  "\35\33\211\205\0\0\0\0\2//\11\1\35\35\33n\217\35\35\33\377\2\35\35\33" \
-  "\375\35\35\33Q\203\0\0\0\0\2\35\35\33#\35\35\33\343\217\35\35\33\377" \
-  "\2\35\35\33\301\35\35\33\4\205\0\0\0\0\1\35\35\33(\220\35\35\33\377\2" \
-  "\35\35\33\220\35\35\33\5\320\0\0\0\0\25\224\276\323#\10i\232\334\0e\230" \
-  "\377\0f\231\377\1g\232\377\4g\232\377\11i\234\377\16j\235\377\21j\236" \
-  "\377\25l\237\377\30l\237\377\32m\240\377\35n\241\377\40o\242\377!p\243" \
-  "\377#p\243\377$q\244\377'q\244\377'r\244\377(s\245\377*s\245\377\202" \
-  ")s\246\377\202)t\246\377\12\33k\240\377\333\350\360\377\377\377\377\377" \
-  "\371\373\375\377\205\257\314\377/w\250\377e\231\276\377\315\337\352\377" \
-  "\365\370\373\377\376\376\376\377\203\377\377\377\377\10\311\335\351\377" \
-  "G\213\263\377\24l\237\377\3c\230\377\32s\243\377\207\267\317\377\343" \
-  "\357\364\377\372\374\375\377\202\377\377\377\377\27\226\277\323\377\"" \
-  "u\241\377\3a\223\377\0]\220\377\0U\213\377$s\237\377\246\306\330\377" \
-  "\357\365\370\377\377\377\377\377\323\342\353\377<~\244\377\10Z\213\377" \
-  "\0S\205\377\0R\204\377\0P\203\377\0L\177\377#h\224\377\247\302\324\377" \
-  "\360\365\370\377\233\273\316\377$i\225\377\2R\204\377\0O\202\377\205" \
-  "\0P\203\377\5\0O\202\377\35d\221\237&k\225\11\0\0\0\0\200\252\325\0\224" \
-  "\0\0\0\0\2\34\34\33E\35\35\33\361\217\35\35\33\377\2\35\35\33\216\35" \
-  "\35%\3\202\0\0\0\0\2\35\35\33\34\35\35\33\321\216\35\35\33\377\2\35\35" \
-  "\33\374\35\35\33\217\205\0\0\0\0\1\35\35\33\251\217\35\35\33\377\2\35" \
-  "\35\33\342\35\35\33H\205\0\0\0\0\2\37\37\35\30\35\35\33\271\217\35\35" \
-  "\33\377\2\35\35\33\333\35\35\33!\203\0\0\0\0\1\35\35\33d\217\35\35\33" \
-  "\377\2\35\35\33\371\35\35\33\201\205\0\0\0\0\2\23\23%\1\35\35\33|\217" \
-  "\35\35\33\377\2\35\35\33\370\34\34\33Q\206\0\0\0\0\2\34\34\33\35\35\35" \
-  "\33\253\217\35\35\33\377\2\35\35\33\363\37\37\31\23\212\0\0\0\0\1\35" \
-  "\35\33\233\217\35\35\33\377\2\35\35\33\351\35\35\33Q\233\0\0\0\0\1\35" \
-  "\35\33W\217\35\35\33\377\2\35\35\33\374\35\35\33\211\205\0\0\0\0\2""0" \
-  "0\10\0\35\35\33n\217\35\35\33\377\2\35\35\33\375\35\35\33P\203\0\0\0" \
-  "\0\2\35\35\33#\35\35\33\343\217\35\35\33\377\2\35\35\33\301\35\35\33" \
-  "\4\205\0\0\0\0\1\35\35\33(\220\35\35\33\377\2\35\35\33\220\35\35\33\5" \
-  "\317\0\0\0\0\25[\233\274\0\0\0\0\0#w\243\255\4e\227\375\0c\226\377\0" \
-  "e\230\377\0f\231\377\1g\232\377\5h\233\377\12i\234\377\17j\235\377\21" \
-  "j\236\377\24k\236\377\27l\237\377\31l\237\377\34m\240\377\35n\241\377" \
-  "\37o\241\377\40o\242\377\"o\242\377\"p\243\377\202$p\243\377\1$q\243" \
-  "\377\202$q\244\377\2\25g\235\377\333\347\360\377\203\377\377\377\377" \
-  "\7\327\346\357\377W\223\271\377#q\244\377_\231\275\377\306\333\347\377" \
-  "\361\366\371\377\376\377\377\377\202\377\377\377\377\"\372\374\375\377" \
-  "\221\274\323\377#z\247\377\2g\232\377\0\\\223\377\32t\242\377\214\271" \
-  "\320\377\337\353\361\377\372\374\375\377\377\377\377\377\347\360\365" \
-  "\377a\233\273\377\26j\232\377\0[\216\377\0W\213\377\0P\206\3770x\240" \
-  "\377\253\310\330\377\357\364\370\377\377\377\377\377\232\274\317\377" \
-  "\40h\224\377\5U\206\377\0O\202\377\0P\203\377\0M\201\377\0K\177\3771" \
-  "r\233\377\266\315\334\377\324\341\352\377d\225\264\377\25_\215\377\1" \
-  "Q\203\377\0O\202\377\203\0P\203\377\3\3R\205\377D\177\244H\233\272\315" \
-  "\2\226\0\0\0\0\2\34\34\33E\35\35\33\361\217\35\35\33\377\7\35\35\33\216" \
-  "\35\35%\3\0\0\0\0&&#\0\0\0\0\0\35\35\33\226\35\35\33\371\216\35\35\33" \
-  "\377\4\35\35\33\317\35\35\33""0\0\0\0\0\"\"\40\0\202\0\0\0\0\1\35\35" \
-  "\33\244\217\35\35\33\377\11\35\35\33\344\35\35\32K\0\0\0\0\34\34\33\0" \
-  "\0\0\0\0\36\36\34\0\0\0\0\0\35\35\33\32\35\35\33\273\217\35\35\33\377" \
-  "\2\35\35\33\330\35\35\33\26\203\0\0\0\0\1\35\35\33d\217\35\35\33\377" \
-  "\2\35\35\33\371\35\35\33\201\205\0\0\0\0\2\23\23%\1\35\35\33|\217\35" \
-  "\35\33\377\2\35\35\33\370\34\34\33Q\206\0\0\0\0\2\34\34\33\35\35\35\33" \
-  "\253\217\35\35\33\377\2\35\35\33\364\36\36\33$\204\0\0\0\0\1\32\32\32" \
-  "\0\205\0\0\0\0\1\35\35\33\233\217\35\35\33\377\2\35\35\33\351\35\35\33" \
-  "Q\233\0\0\0\0\2\35\35\33R\35\35\33\373\216\35\35\33\377\11\35\35\33\374" \
-  "\35\35\33\216\0\0\0\0\35\35\33\0\0\0\0\0\34\34\34\0\0\0\0\0\35\35\33" \
-  "\2\35\35\33q\217\35\35\33\377\2\35\35\33\375\34\34\33D\203\0\0\0\0\2" \
-  "\35\35\33#\35\35\33\343\217\35\35\33\377\2\35\35\33\301\35\35\33\4\205" \
-  "\0\0\0\0\1\35\35\33(\220\35\35\33\377\2\35\35\33\220\35\35\33\5\321\0" \
-  "\0\0\0\4>\206\255F\6d\226\353\0b\225\377\0c\226\377\202\0e\230\377\24" \
-  "\0f\232\377\2g\232\377\6h\233\377\11h\233\377\15i\234\377\21j\235\377" \
-  "\22k\236\377\24l\237\377\26l\237\377\31m\240\377\32m\240\377\33n\241" \
-  "\377\34n\241\377\35n\241\377\36n\241\377\36o\242\377\37o\242\377\36o" \
-  "\242\377\20e\234\377\324\344\355\377\205\377\377\377\377\6\252\311\333" \
-  "\3776\200\254\377\26k\237\377W\225\271\377\302\331\346\377\355\364\370" \
-  "\377\203\377\377\377\377'\336\354\362\377_\237\277\377\22o\237\377\0" \
-  "a\225\377\0W\216\377\40t\241\377\224\274\322\377\335\352\360\377\375" \
-  "\376\376\377\377\377\377\377\274\324\341\377=\201\250\377\15a\222\377" \
-  "\0V\212\377\0S\207\377\0M\203\377:{\242\377\265\316\334\377\361\366\370" \
-  "\377\353\361\366\377i\230\265\377\23]\214\377\0P\203\377\0O\202\377\0" \
-  "P\203\377\0L\200\377\0J~\377A}\242\377\277\323\340\377\251\304\325\377" \
-  "\77|\242\377\14X\211\377\0O\202\377\0O\203\377\0N\202\377\40f\222\331" \
-  "\36e\222\17\0\0\0\0\\\217\257\0\225\0\0\0\0\2\34\34\33E\35\35\33\361" \
-  "\217\35\35\33\377\2\35\35\33\216\35\35%\3\203\0\0\0\0\2\35\35\31""6\35" \
-  "\35\33\341\216\35\35\33\377\2\35\35\33\374\35\35\33\210\202\0\0\0\0\4" \
-  "\34\34\34\0\0\0\0\0\35\35\33\213\35\35\33\375\216\35\35\33\377\2\35\35" \
-  "\33\357\35\35\33u\205\0\0\0\0\2\35\35\32=\35\35\33\322\217\35\35\33\377" \
-  "\1\35\35\33\315\204\0\0\0\0\1\35\35\33d\217\35\35\33\377\2\35\35\33\371" \
-  "\35\35\33\201\205\0\0\0\0\2\23\23%\1\35\35\33|\217\35\35\33\377\2\35" \
-  "\35\33\370\34\34\33Q\206\0\0\0\0\2\34\34\33\35\35\35\33\253\217\35\35" \
-  "\33\377\4\35\35\33\371\35\35\33o\35\35\33\10##\34\1\205\0\0\0\0\1\35" \
-  "\35\33\0\202\0\0\0\0\1\35\35\33\233\217\35\35\33\377\2\35\35\33\351\35" \
-  "\35\33Q\233\0\0\0\0\2\35\35\33C\35\35\33\344\216\35\35\33\377\2\35\35" \
-  "\33\376\35\35\33\271\205\0\0\0\0\2\35\35\33\24\35\35\33\232\217\35\35" \
-  "\33\377\2\35\35\33\373\35\35\32!\203\0\0\0\0\2\35\35\33#\35\35\33\343" \
-  "\217\35\35\33\377\2\35\35\33\301\35\35\33\4\205\0\0\0\0\1\35\35\33(\220" \
-  "\35\35\33\377\2\35\35\33\220\35\35\33\5\322\0\0\0\0\22\26m\234\305\2" \
-  "a\224\377\0a\224\377\0b\225\377\0d\227\377\0e\227\377\0f\231\377\0g\232" \
-  "\377\2g\232\377\4h\233\377\6h\233\377\11i\234\377\14j\235\377\20j\235" \
-  "\377\21k\236\377\23k\236\377\24l\236\377\25k\236\377\202\27k\237\377" \
-  "\7\30l\237\377\30m\240\377\30l\237\377\17f\233\377\206\262\315\377\325" \
-  "\344\356\377\363\370\372\377\204\377\377\377\377\7\362\366\371\377x\253" \
-  "\310\377\37u\244\377\3e\231\377P\226\271\377\271\325\343\377\351\362" \
-  "\366\377\203\377\377\377\377\10\264\321\340\377@\211\257\377\13g\230" \
-  "\377\0Z\217\377\0S\212\377)w\242\377\231\275\322\377\332\347\357\377" \
-  "\202\377\377\377\377\31\212\262\312\377)r\235\377\4X\213\377\0S\206\377" \
-  "\0P\204\377\0L\200\377I\203\247\377\274\320\336\377\357\364\370\377\277" \
-  "\323\340\377C~\244\377\15Y\211\377\0M\201\377\0O\203\377\0P\203\377\0" \
-  "J\177\377\0M\201\377Y\215\256\377\262\312\332\377u\241\274\377,n\230" \
-  "\377\5S\205\377\2Q\204\377+m\230hV\212\255\6\227\0\0\0\0\2\34\34\33E" \
-  "\35\35\33\361\217\35\35\33\377\2\35\35\33\216\35\35%\3\204\0\0\0\0\2" \
-  "\35\35\33\265\35\35\33\376\216\35\35\33\377\7\35\35\33\312\35\35\33-" \
-  "\0\0\0\0\35\35\33\0\0\0\0\0\35\35\33Q\35\35\33\342\217\35\35\33\377\7" \
-  "\35\35\33\326\34\34\33G\35\35\33\35\35\35\33\32\35\35\33\34\35\35\33" \
-  "/\35\35\33\251\217\35\35\33\377\4\35\35\33\371\35\35\33\223\0\0\0\0\34" \
-  "\34\34\0\202\0\0\0\0\1\35\35\33d\217\35\35\33\377\2\35\35\33\371\35\35" \
-  "\33\201\205\0\0\0\0\2\23\23%\1\35\35\33|\217\35\35\33\377\2\35\35\33" \
-  "\370\34\34\33Q\206\0\0\0\0\2\34\34\33\31\35\35\33\244\220\35\35\33\377" \
-  "\10\35\35\33\365\35\35\33\207\35\35\33P\35\35\33=\35\35\33""7\35\35\33" \
-  "6\35\35\33""3\35\35\33\30\203\0\0\0\0\1\35\35\33\233\217\35\35\33\377" \
-  "\2\35\35\33\351\35\35\33Q\233\0\0\0\0\2\35\35\33\40\35\35\33\261\217" \
-  "\35\35\33\377\3\35\35\33\373\35\35\33n\35\35\33\"\202\35\35\33\33\3\35" \
-  "\35\33%\35\35\33q\35\35\33\364\217\35\35\33\377\3\35\35\33\325\0\0\0" \
-  "\0""44)\0\202\0\0\0\0\2\35\35\33#\35\35\33\343\217\35\35\33\377\2\35" \
-  "\35\33\301\35\35\33\4\205\0\0\0\0\1\35\35\33(\220\35\35\33\377\2\35\35" \
-  "\33\220\35\35\33\5\320\0\0\0\0\12u\250\305\0\0\0\0\0""9\203\252W\5b\224" \
-  "\363\0_\223\377\0`\223\377\0a\224\377\0b\225\377\0c\226\377\0e\230\377" \
-  "\202\0f\231\377\11\0g\232\377\2g\232\377\4g\232\377\6h\233\377\10h\233" \
-  "\377\13i\234\377\14i\234\377\15i\234\377\17i\235\377\203\20j\235\377" \
-  "\7\21j\235\377\22k\236\377\2a\227\377&x\246\377\200\260\313\377\312\337" \
-  "\352\377\362\367\372\377\204\377\377\377\377\7\310\336\351\377O\225\271" \
-  "\377\12l\236\377\0`\224\377P\225\267\377\263\320\337\377\347\360\365" \
-  "\377\202\377\377\377\377#\363\367\372\377\210\264\314\377-z\245\377\3" \
-  "^\221\377\0V\213\377\0P\206\3770x\242\377\231\274\320\377\330\345\355" \
-  "\377\377\377\377\377\341\354\362\377d\230\267\377\36h\224\377\0O\202" \
-  "\377\0P\202\377\0K\200\377\0L\200\377S\212\254\377\277\323\340\377\342" \
-  "\353\361\377\221\263\311\377-o\231\377\4R\205\377\0L\200\377\0P\203\377" \
-  "\0O\203\377\0H}\377\4S\205\377k\231\267\377\220\263\311\377M\205\250" \
-  "\377(k\227\340'j\227\27\0\0\0\0\3U\200\0\226\0\0\0\0\2\34\34\33E\35\35" \
-  "\33\361\217\35\35\33\377\2\35\35\33\216\35\35%\3\202\0\0\0\0\4\33\33" \
-  "\33\0\0\0\0\0\35\35\33S\35\35\33\356\216\35\35\33\377\2\35\35\33\374" \
-  "\35\35\33\177\203\0\0\0\0\2\35\35\37\10\35\35\33\255\221\35\35\33\377" \
-  "\4\35\35\33\312\35\35\33\261\35\35\33\276\35\35\33\357\220\35\35\33\377" \
-  "\2\35\35\33\334\35\35\33,\204\0\0\0\0\1\35\35\33d\217\35\35\33\377\2" \
-  "\35\35\33\371\35\35\33\201\205\0\0\0\0\2\23\23%\1\35\35\33|\217\35\35" \
-  "\33\377\2\35\35\33\370\34\34\33Q\206\0\0\0\0\2\35\35\33\20\35\35\33\227" \
-  "\227\35\35\33\377\1\35\35\33x\203\0\0\0\0\1\35\35\33\233\217\35\35\33" \
-  "\377\2\35\35\33\351\35\35\33Q\234\0\0\0\0\2\35\35\33e\35\35\33\374\220" \
-  "\35\35\33\377\4\35\35\33\334\35\35\33\264\35\35\33\265\35\35\33\332\220" \
-  "\35\35\33\377\4\35\35\33\375\35\35\34\\\0\0\0\0\24\24\24\0\202\0\0\0" \
-  "\0\2\35\35\33#\35\35\33\343\217\35\35\33\377\2\35\35\33\301\35\35\33" \
-  "\4\205\0\0\0\0\1\35\35\33(\220\35\35\33\377\2\35\35\33\220\35\35\33\5" \
-  "\323\0\0\0\0\4\30l\232\306\1^\222\376\0^\222\377\0`\223\377\202\0a\224" \
-  "\377\4\0b\225\377\0c\226\377\0d\227\377\0e\230\377\202\0f\231\377\202" \
-  "\0g\232\377\4\2g\232\377\3g\232\377\3g\233\377\5h\233\377\202\6h\233" \
-  "\377\203\10h\233\377\7\7h\233\377\2e\231\377\0_\225\377\27s\243\377y" \
-  "\256\312\377\304\333\347\377\357\366\371\377\204\377\377\377\377\7\235" \
-  "\303\327\3776\204\254\377\0`\224\377\0]\221\377R\223\266\377\256\314" \
-  "\334\377\344\356\363\377\202\377\377\377\377!\324\343\354\377e\235\273" \
-  "\377\33l\231\377\0V\212\377\0R\207\377\0L\203\3774y\242\377\232\273\320" \
-  "\377\333\347\356\377\377\377\377\377\271\317\335\377G\202\246\377\15" \
-  "Z\211\377\0K\177\377\0O\202\377\0I~\377\1Q\204\377^\221\261\377\302\325" \
-  "\342\377\304\327\343\377k\232\267\377\35d\221\377\0M\201\377\0N\202\377" \
-  "\0P\203\377\0O\202\377\0G|\377\16Y\211\377v\241\274\377\212\257\306`" \
-  "v\241\272\5\0\0\0\0\200\244\310\0\226\0\0\0\0\2\34\34\33E\35\35\33\361" \
-  "\217\35\35\33\377\2\35\35\33\216\35\35%\3\204\0\0\0\0\2""55\33\2\35\35" \
-  "\33\315\217\35\35\33\377\7\35\35\33\306\35\35\33+\0\0\0\0\35\35\34\0" \
-  "\0\0\0\0\35\35\33=\35\35\33\321\243\35\35\33\377\4\35\35\33\361\35\35" \
-  "\33r\0\0\0\0\34\34\31\0\203\0\0\0\0\1\35\35\33d\217\35\35\33\377\2\35" \
-  "\35\33\371\35\35\33\201\205\0\0\0\0\2\23\23%\1\35\35\33|\217\35\35\33" \
-  "\377\2\35\35\33\370\34\34\33Q\207\0\0\0\0\1\35\35\33{\226\35\35\33\377" \
-  "\2\35\35\33\361\35\35\33p\203\0\0\0\0\1\35\35\33\233\217\35\35\33\377" \
-  "\2\35\35\33\351\35\35\33Q\232\0\0\0\0\4\35\35\32\0\0\0\0\0\35\35\33\27" \
-  "\35\35\33\233\244\35\35\33\377\1\35\35\33\247\205\0\0\0\0\2\35\35\33" \
-  "#\35\35\33\343\217\35\35\33\377\2\35\35\33\301\35\35\33\4\205\0\0\0\0" \
-  "\1\35\35\33(\220\35\35\33\377\2\35\35\33\220\35\35\33\5\321\0\0\0\0\7" \
-  "p\245\302\0\0\0\0\0C\207\255G\10b\224\364\0]\221\377\0^\222\377\0_\223" \
-  "\377\202\0`\223\377\1\0a\224\377\202\0b\225\377\2\0c\226\377\0d\227\377" \
-  "\203\0e\230\377\1\0e\231\377\204\0f\231\377\203\1f\231\377\203\0f\231" \
-  "\377\6\0d\230\377\0]\223\377\25r\240\377o\250\304\377\272\325\343\377" \
-  "\355\364\370\377\203\377\377\377\377\10\345\357\364\377z\254\307\377" \
-  "$w\243\377\0U\213\377\0]\221\377R\221\264\377\245\306\330\377\343\355" \
-  "\363\377\202\377\377\377\377\36\257\313\333\377M\213\256\377\12]\217" \
-  "\377\0R\207\377\0P\205\377\0L\201\377;{\242\377\227\270\315\377\335\347" \
-  "\357\377\372\374\375\377\220\262\311\3774t\234\377\0O\202\377\0L\200" \
-  "\377\0O\202\377\0I~\377\11W\210\377j\231\267\377\267\316\334\377\241" \
-  "\276\321\377S\211\254\377\15Y\211\377\0K\177\377\0O\202\377\0P\203\377" \
-  "\0L\201\377\15Y\211\317\17Z\213\32\0\0\0\0K\207\247\0\227\0\0\0\0\2\34" \
-  "\34\33E\35\35\33\361\217\35\35\33\377\2\35\35\33\216\35\35%\3\203\0\0" \
-  "\0\0\4\37\37\33\0\0\0\0\0\35\35\33x\35\35\33\366\216\35\35\33\377\2\35" \
-  "\35\33\374\35\35\33w\202\0\0\0\0\4\35\35\30\0\0\0\0\0\35\35\33O\35\35" \
-  "\33\315\241\35\35\33\377\2\35\35\33\352\35\35\33~\202\0\0\0\0\1\36\36" \
-  "\36\0\203\0\0\0\0\1\35\35\33d\217\35\35\33\377\2\35\35\33\371\35\35\33" \
-  "\201\205\0\0\0\0\2\23\23%\1\35\35\33|\217\35\35\33\377\2\35\35\33\370" \
-  "\34\34\33Q\205\0\0\0\0\4&&\"\0\0\0\0\0\35\35\33M\35\35\33\355\225\35" \
-  "\35\33\377\2\35\35\33\361\35\35\33p\203\0\0\0\0\1\35\35\33\233\217\35" \
-  "\35\33\377\2\35\35\33\351\35\35\33Q\233\0\0\0\0\5\32\32\30\0\0\0\0\0" \
-  "\35\35\33#\35\35\33\244\35\35\33\373\240\35\35\33\377\5\35\35\33\374" \
-  "\35\35\33\253\31\31\31\17\0\0\0\0\35\35\35\0\203\0\0\0\0\2\35\35\33#" \
-  "\35\35\33\343\217\35\35\33\377\2\35\35\33\301\35\35\33\4\205\0\0\0\0" \
-  "\1\35\35\33(\220\35\35\33\377\2\35\35\33\220\35\35\33\5\324\0\0\0\0\6" \
-  "\"q\235\247\0[\217\377\0]\220\377\0]\221\377\0^\221\377\0_\222\377\203" \
-  "\0`\223\377\202\0a\224\377\1\0b\225\377\203\0c\226\377\213\0d\227\377" \
-  "\7\0c\226\377\0a\225\377\0[\220\377\21l\234\377g\241\277\377\264\320" \
-  "\337\377\354\363\367\377\203\377\377\377\377\27\303\331\345\377]\231" \
-  "\271\377\21g\227\377\0M\205\377\3]\220\377P\215\261\377\240\301\324\377" \
-  "\344\355\363\377\377\377\377\377\361\366\371\377\216\264\312\3777z\241" \
-  "\377\0R\204\377\0P\203\377\0M\201\377\0K\177\377=z\241\377\226\267\315" \
-  "\377\340\352\360\377\334\347\356\377s\237\273\377\40f\222\377\0H~\377" \
-  "\202\0N\202\377\15\0H}\377\23]\214\377t\240\273\377\242\300\322\377\177" \
-  "\247\301\3779w\237\377\0P\203\377\0K\200\377\10U\206\377+m\230U\311\332" \
-  "\345\3\0\0\0\0\242\271\321\0\227\0\0\0\0\2\34\34\33E\35\35\33\361\217" \
-  "\35\35\33\377\2\35\35\33\216\35\35%\3\205\0\0\0\0\2\35\35\33\27\35\35" \
-  "\33\342\217\35\35\33\377\11\35\35\33\302\36\36\33(\0\0\0\0\35\35\34\0" \
-  "##\27\0\0\0\0\0\35\35\33;\35\35\33\247\35\35\33\363\236\35\35\33\377" \
-  "\2\35\35\33\303\35\35\33b\202\0\0\0\0\1\35\35\33\0\204\0\0\0\0\1\35\35" \
-  "\33d\217\35\35\33\377\2\35\35\33\371\35\35\33\201\205\0\0\0\0\2\23\23" \
-  "%\1\35\35\33|\217\35\35\33\377\2\35\35\33\370\34\34\33Q\207\0\0\0\0\2" \
-  "\35\35\33\24\35\35\33\232\225\35\35\33\377\2\35\35\33\361\35\35\33p\203" \
-  "\0\0\0\0\1\35\35\33\233\217\35\35\33\377\2\35\35\33\351\35\35\33Q\233" \
-  "\0\0\0\0\6+++\0\33\33\30\0\0\0\0\0\35\35\33\30\35\35\33\202\35\35\33" \
-  "\336\236\35\35\33\377\5\35\35\33\332\35\35\33\205\31\31\31\15\0\0\0\0" \
-  "\33\33\32\0\204\0\0\0\0\2\35\35\33#\35\35\33\343\217\35\35\33\377\2\35" \
-  "\35\33\301\35\35\33\4\205\0\0\0\0\1\35\35\33(\220\35\35\33\377\2\35\35" \
-  "\33\220\35\35\33\5\322\0\0\0\0\6{\254\304\0\0\0\0\0`\226\270\36\17d\224" \
-  "\341\0[\216\377\0[\217\377\202\0]\220\377\202\0^\221\377\2\0_\222\377" \
-  "\0_\223\377\203\0`\223\377\202\0a\224\377\1\0a\225\377\211\0b\225\377" \
-  "\203\0a\224\377\7\0`\223\377\0^\222\377\0Z\217\377\23k\232\377a\233\273" \
-  "\377\253\312\333\377\355\363\367\377\202\377\377\377\377$\364\370\372" \
-  "\377\240\302\325\377C\206\253\377\0X\214\377\0J\202\377\10]\217\377N" \
-  "\212\255\377\231\273\317\377\350\360\365\377\377\377\377\377\323\341" \
-  "\352\377t\241\274\377\33d\221\377\0K\177\377\0O\202\377\0K\177\377\0" \
-  "M\201\377A}\243\377\226\267\313\377\332\346\355\377\274\321\336\377Y" \
-  "\215\256\377\11V\207\377\0I~\377\0P\203\377\0M\201\377\0H~\377\37f\222" \
-  "\377q\236\272\377\206\254\304\377h\230\266\377$i\224\377\40f\222\242" \
-  "7w\236\21\0\0\0\0F\200\245\0\230\0\0\0\0\2\34\34\33E\35\35\33\361\217" \
-  "\35\35\33\377\2\35\35\33\216\35\35%\3\204\0\0\0\0\4\"\"\37\0\0\0\0\0" \
-  "\35\35\33\234\35\35\33\373\216\35\35\33\377\2\35\35\33\375\35\35\33p" \
-  "\202\0\0\0\0\7\32\32\32\0\40\40\34\0\0\0\0\0\33\33\33\21\35\35\33e\35" \
-  "\35\33\257\35\35\33\352\231\35\35\33\377\4\35\35\33\371\35\35\33\302" \
-  "\35\35\33\177\35\35\31,\202\0\0\0\0\1\36\36\33\0\205\0\0\0\0\1\35\35" \
-  "\33d\217\35\35\33\377\2\35\35\33\371\35\35\33\201\205\0\0\0\0\2\23\23" \
-  "%\1\35\35\33|\217\35\35\33\377\2\35\35\33\370\34\34\33Q\206\0\0\0\0\4" \
-  "\37\37\33\0\0\0\0\0\35\35\33,\35\35\33\261\224\35\35\33\377\2\35\35\33" \
-  "\361\35\35\33p\203\0\0\0\0\1\35\35\33\233\217\35\35\33\377\2\35\35\33" \
-  "\351\35\35\33Q\234\0\0\0\0\2\40\40\40\0\35\35\32\0\202\0\0\0\0\3\35\35" \
-  "\33E\35\35\33\231\35\35\33\330\232\35\35\33\377\3\35\35\33\326\35\35" \
-  "\33\227\35\35\33F\210\0\0\0\0\2\35\35\33#\35\35\33\343\217\35\35\33\377" \
-  "\2\35\35\33\301\35\35\33\4\205\0\0\0\0\1\35\35\33(\220\35\35\33\377\2" \
-  "\35\35\33\220\35\35\33\5\323\0\0\0\0\13<\200\250\0\0\0\0\0""7|\245`\10" \
-  "_\220\377\0Z\215\377\0[\216\377\0\\\217\377\0\\\220\377\0]\220\377\0" \
-  "]\221\377\0^\221\377\202\0^\222\377\202\0_\222\377\204\0`\223\377\1\0" \
-  "a\224\377\203\0`\223\377\1\0a\224\377\203\0`\223\377\202\0`\222\377\1" \
-  "\0^\222\377\202\0^\221\377\6\0Z\217\377\0W\214\377\21g\227\377[\226\267" \
-  "\377\246\306\327\377\355\364\367\377\202\377\377\377\377\37\335\351\360" \
-  "\377\202\256\306\377%o\233\377\0P\205\377\0K\201\377\12\\\214\377K\207" \
-  "\252\377\227\270\315\377\356\363\367\377\377\377\377\377\270\316\334" \
-  "\377Y\216\256\377\3R\204\377\0K\177\377\0O\202\377\0J\177\377\0O\202" \
-  "\377D\177\244\377\226\267\315\377\312\332\345\377\240\276\321\377<y\240" \
-  "\377\0J\177\377\0L\200\377\0P\203\377\0L\200\377\0I~\377*m\230\377d\225" \
-  "\264\377e\225\264\325j\231\2661\233\0\0\0\0\2\34\34\33H\35\35\33\373" \
-  "\217\35\35\33\377\2\35\35\33\224\35\35%\4\204\0\0\0\0\4\24\24\24\0\0" \
-  "\0\0\0\36\36\33/\35\35\33\370\217\35\35\33\377\6\35\35\33\311\35\35\33" \
-  ",\0\0\0\0\"\"\"\0\0\0\0\0\34\34\33\0\202\0\0\0\0\5\35\35\33\32\35\35" \
-  "\33T\35\35\33\211\35\35\33\271\35\35\33\342\223\35\35\33\377\5\35\35" \
-  "\33\356\35\35\33\307\35\35\33\230\35\35\33e\35\35\33,\202\0\0\0\0\2%" \
-  "%\36\0\27\27\27\0\206\0\0\0\0\1\35\35\33h\220\35\35\33\377\1\35\35\33" \
-  "\206\205\0\0\0\0\2\23\23%\1\35\35\33\201\220\35\35\33\377\1\34\34\33" \
-  "T\206\0\0\0\0\1\33\33\33\0\202\0\0\0\0\4\35\35\33\"\35\35\33{\35\35\33" \
-  "\301\35\35\33\362\221\35\35\33\377\2\35\35\33\373\35\35\33u\203\0\0\0" \
-  "\0\1\35\35\33\242\217\35\35\33\377\2\35\35\33\362\35\35\33T\236\0\0\0" \
-  "\0\1\34\34\33\0\202\0\0\0\0\6\40\40\32\11\35\35\33@\35\35\33x\35\35\33" \
-  "\253\35\35\33\325\35\35\33\374\222\35\35\33\377\6\35\35\33\372\35\35" \
-  "\33\325\35\35\33\250\35\35\33w\35\35\33\77\35\35\30\3\203\0\0\0\0\1\32" \
-  "\32\32\0\205\0\0\0\0\2\35\35\33%\35\35\33\354\217\35\35\33\377\2\35\35" \
-  "\33\311\35\35\33\4\205\0\0\0\0\1\35\35\33)\220\35\35\33\377\2\35\35\33" \
-  "\226\35\35\33\5\326\0\0\0\0\1\"o\232\230\202\0Y\214\377\1\0Z\215\377" \
-  "\202\0[\216\377\202\0\\\217\377\2\0\\\220\377\0]\220\377\202\0]\221\377" \
-  "\203\0^\221\377\1\0^\222\377\204\0_\222\377\202\0^\222\377\202\0^\221" \
-  "\377\203\0]\221\377\202\0\\\220\377\202\0[\217\377\6\0Y\214\377\0V\212" \
-  "\377\23f\225\377T\220\262\377\236\277\323\377\354\363\367\377\202\377" \
-  "\377\377\377\37\302\327\343\377e\231\270\377\13\\\214\377\0L\201\377" \
-  "\0J\177\377\15[\213\377G\201\245\377\223\265\312\377\360\365\370\377" \
-  "\363\367\371\377\237\275\321\377;x\240\377\0H}\377\0M\201\377\0O\202" \
-  "\377\0K\177\377\4S\205\377H\201\246\377\221\264\311\377\260\311\331\377" \
-  "\206\254\304\377\40f\223\377\0G}\377\0O\202\377\0P\203\377\0J\177\377" \
-  "\14X\211\371[\217\260\\\377\377\377\1\0\0\0\0h\227\265\0\231\0\0\0\0" \
-  "\3\34\34\33.\35\35\33\240\35\35\33\252\215\35\35\33\251\3\35\35\33\262" \
-  "\35\35\33^\35\35%\2\207\0\0\0\0\1\35\35\33\213\216\35\35\33\251\3\35" \
-  "\35\33\253\35\35\33\244\35\35\33:\204\0\0\0\0\2\"\"\"\0\22\22\14\0\203" \
-  "\0\0\0\0\30\35\35\33&\35\35\33H\35\35\33f\35\35\33\204\35\35\33\241\35" \
-  "\35\33\271\35\35\33\315\35\35\33\335\35\35\33\352\35\35\33\362\35\35" \
-  "\33\370\35\35\33\373\35\35\33\371\35\35\33\364\35\35\33\355\35\35\33" \
-  "\342\35\35\33\323\35\35\33\300\35\35\33\251\35\35\33\216\35\35\33o\35" \
-  "\35\33Q\35\35\33""1\35\35\35\12\203\0\0\0\0\1\33\33\33\0\210\0\0\0\0" \
-  "\3\35\35\33B\35\35\33\254\35\35\33\252\215\35\35\33\251\2\35\35\33\245" \
-  "\35\35\33U\205\0\0\0\0\3\24\24$\1\35\35\33R\35\35\33\263\216\35\35\33" \
-  "\251\2\35\35\33\245\34\34\33""6\207\0\0\0\0\12\37\37\33\0\17\17\33\0" \
-  "\0\0\0\0ZZ\33\0\35\35\33*\35\35\33T\35\35\33r\35\35\33\213\35\35\33\234" \
-  "\35\35\33\244\214\35\35\33\251\3\35\35\33\253\35\35\33\240\35\35\33J" \
-  "\203\0\0\0\0\2\35\35\33g\35\35\33\261\215\35\35\33\251\3\35\35\33\252" \
-  "\35\35\33\233\35\35\33""6\240\0\0\0\0\1\"\"\37\0\203\0\0\0\0\13\35\35" \
-  "\33\31\35\35\33=\35\35\33\\\35\35\33z\35\35\33\231\35\35\33\262\35\35" \
-  "\33\310\35\35\33\330\35\35\33\346\35\35\33\360\35\35\33\366\202\35\35" \
-  "\33\372\13\35\35\33\365\35\35\33\360\35\35\33\346\35\35\33\330\35\35" \
-  "\33\307\35\35\33\261\35\35\33\230\35\35\33y\35\35\33[\35\35\33<\35\35" \
-  "\33\27\204\0\0\0\0\1\35\35\32\0\207\0\0\0\0\3\35\35\33\27\35\35\33\226" \
-  "\35\35\33\254\215\35\35\33\251\3\35\35\33\253\35\35\33\200\35\35\33\3" \
-  "\205\0\0\0\0\2\35\35\33\32\35\35\33\264\216\35\35\33\251\3\35\35\33\256" \
-  "\35\35\33`\35\35\33\3\324\0\0\0\0\10k\237\275\0\0\0\0\0Y\221\263\24\35" \
-  "j\227\306\0V\212\377\0X\213\377\0Y\214\377\0Z\214\377\202\0Z\215\377" \
-  "\203\0[\216\377\202\0[\217\377\1\0\\\217\377\202\0\\\220\377\204\0]\220" \
-  "\377\203\0\\\220\377\1\0\\\217\377\203\0[\217\377\202\0[\216\377\202" \
-  "\0Z\215\377\27\0Y\214\377\0X\214\377\0U\212\377\0S\210\377\22b\222\377" \
-  "K\210\254\377\230\272\317\377\357\364\367\377\377\377\377\377\361\366" \
-  "\370\377\251\306\326\377A~\244\377\0N\202\377\0K\200\377\0I~\377\16Y" \
-  "\212\377@|\242\377\221\263\311\377\356\363\366\377\337\351\357\377\206" \
-  "\254\304\377\27`\216\377\0G|\377\202\0O\202\377\15\0K\177\377\11V\207" \
-  "\377G\201\246\377\205\254\303\377\236\275\320\377d\225\264\377\6T\206" \
-  "\377\0I~\377\6T\206\377\34c\221\213-n\231\14\0\0\0\0\300\324\341\0\232" \
-  "\0\0\0\0\3\36\36\33\7\35\35\33\32\35\35\33\34\215\35\35\33\33\3\35\35" \
-  "\33\35\35\35\33\17\35\35&\0\205\0\0\0\0\3\33\33\33\0\0\0\0\0\35\35\33" \
-  "\21\217\35\35\33\33\2\35\35\33\37\35\35\34\16\207\0\0\0\0\1\34\34\32" \
-  "\0\204\0\0\0\0\21\30\30\27\3\34\34\33\26\35\35\33&\35\35\33""3\35\35" \
-  "\33>\35\35\33F\35\35\33K\35\35\33O\35\35\33Q\35\35\33P\35\35\33M\35\35" \
-  "\33H\35\35\33A\35\35\33""7\35\35\33*\35\35\33\33\33\33\31\11\205\0\0" \
-  "\0\0\1\35\35\34\0\212\0\0\0\0\1\35\35\33\13\202\35\35\33\34\216\35\35" \
-  "\33\33\1\35\35\33\16\205\0\0\0\0\3\25\25#\0\35\35\33\15\35\35\33\35\217" \
-  "\35\35\33\33\1\36\36\35\11\211\0\0\0\0\1\36\36\33\0\204\0\0\0\0\3\35" \
-  "\35\32\7\35\35\33\23\35\35\32\30\214\35\35\33\33\3\35\35\33\34\35\35" \
-  "\33\32\35\35\33\14\203\0\0\0\0\2\35\35\33\21\35\35\33\35\215\35\35\33" \
-  "\33\3\35\35\33\34\35\35\33\31\35\35\33\11\242\0\0\0\0\1\35\35\33\0\205" \
-  "\0\0\0\0\7\33\33\33\20\35\35\33!\35\35\33/\35\35\33:\35\35\33C\35\35" \
-  "\33J\35\35\33N\202\35\35\33P\7\35\35\33M\35\35\33J\35\35\33C\35\35\33" \
-  ":\35\35\33/\35\35\34!\36\36\34\20\205\0\0\0\0\1$$!\0\212\0\0\0\0\3\35" \
-  "\35\33\4\35\35\33\30\35\35\33\34\215\35\35\33\33\3\35\35\33\34\35\35" \
-  "\33\25\35\35\33\0\205\0\0\0\0\2\35\35\33\4\35\35\33\35\216\35\35\33\33" \
-  "\3\35\35\33\34\35\35\33\20\35\35\33\1\325\0\0\0\0\6<\177\246\0\0\0\0" \
-  "\0@\201\246-\25e\223\343\0V\211\377\0W\213\377\202\0X\213\377\203\0Y" \
-  "\214\377\3\0Z\215\377\0[\215\377\0Z\215\377\212\0[\216\377\204\0Z\215" \
-  "\377\202\0Y\214\377\3\0X\214\377\0X\213\377\0W\213\377\202\0W\212\377" \
-  "\"\0V\211\377\0T\207\377\0Q\205\377\21`\217\377D\201\246\377\223\266" \
-  "\313\377\364\367\371\377\377\377\377\377\341\352\360\377\215\261\310" \
-  "\377\33b\220\377\0J\177\377\0M\201\377\0J\177\377\16Y\212\377;y\240\377" \
-  "\217\262\310\377\345\355\362\377\316\335\347\377d\225\264\377\0M\201" \
-  "\377\0J\177\377\0P\203\377\0N\202\377\0L\200\377\16Z\212\377C~\244\377" \
-  "w\241\275\377\210\255\305\377C}\243\377\35c\221\254C\177\244\32\0\0\0" \
-  "\0\0\15O\0\232\0\0\0\0\1\35\35\33\0\223\0\0\0\0\1\35\35\35\0\205\0\0" \
-  "\0\0\1\35\35\33\0\222\0\0\0\0\2\32\32\27\0\"\"\"\0\234\0\0\0\0\2''\32" \
-  "\0\32\32\32\0\214\0\0\0\0\1\35\35\33\0\222\0\0\0\0\1\35\35\33\0\203\0" \
-  "\0\0\0\1\34\34\34\0\223\0\0\0\0\1\35\35\34\0\213\0\0\0\0\1\34\34\31\0" \
-  "\223\0\0\0\0\3\35\35\33\0$$\22\0\31\31!\0\222\0\0\0\0\1\35\35\33\0\245" \
-  "\0\0\0\0\1\36\36\34\0\222\0\0\0\0\2__+\0\32\32\32\0\214\0\0\0\0\1\35" \
-  "\35\33\0\227\0\0\0\0\1\35\35\33\0\223\0\0\0\0\1\35\35\33\0\325\0\0\0" \
-  "\0\6-s\236\0\0\0\0\0""3x\240@\20`\217\363\0U\210\377\0V\212\377\202\0" \
-  "W\212\377\202\0X\213\377\1\0Y\213\377\202\0Y\214\377\2\0X\213\377\0Y" \
-  "\214\377\207\0Z\215\377\204\0Y\214\377\203\0X\213\377\2\0W\212\377\0" \
-  "V\212\377\202\0V\211\377\1\0V\210\377\202\0U\207\377\35\0T\206\377\0" \
-  "Q\204\377\0O\203\377\20]\214\377<y\241\377\217\262\311\377\370\372\374" \
-  "\377\377\377\377\377\321\337\351\377g\227\265\377\0O\203\377\0K\200\377" \
-  "\0N\202\377\0K\200\377\16Y\212\3778w\236\377\213\260\307\377\326\343" \
-  "\353\377\272\317\336\377;y\240\377\0D{\377\0N\201\377\0P\203\377\0N\202" \
-  "\377\0M\201\377\22\\\214\377@|\242\377_\221\261\271\213\256\306%\202" \
-  "\0\0\0\0\1u\236\275\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\237\0\0\0\0" \
-  "\1\231\314\314\0\202\0\0\0\0\4/t\235L\15]\215\370\0S\207\377\0U\210\377" \
-  "\203\0V\211\377\1\0V\212\377\216\0W\212\377\2\0V\211\377\0V\212\377\202" \
-  "\0V\211\377\3\0V\210\377\0U\210\377\0U\207\377\202\0T\206\377\202\0S" \
-  "\205\377\202\0R\204\377\26\0Q\204\377\0O\202\377\0M\201\377\17Z\212\377" \
-  "1q\233\377\210\255\305\377\365\370\372\377\370\372\374\377\273\320\336" \
-  "\377:w\237\377\0I~\377\0N\202\377\0O\202\377\0M\201\377\15Y\211\3774" \
-  "t\234\377\202\251\303\377\311\332\345\377\235\274\317\377\27`\216\377" \
-  "\0F|\377\0O\203\377\202\0P\203\377\2\21\\\213\312V\213\2552\202\0\0\0" \
-  "\0\1h\227\266\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\243\0\0\0\0\7\310" \
-  "\330\344\3/s\234O\16]\214\367\0S\205\377\0T\206\377\0T\207\377\0U\207" \
-  "\377\204\0U\210\377\210\0V\211\377\1\0V\210\377\203\0U\210\377\1\0U\207" \
-  "\377\202\0T\207\377\2\0T\206\377\0S\206\377\202\0S\205\377\203\0R\204" \
-  "\377\202\0Q\203\377\203\0P\203\377\26\0O\202\377\0M\201\377\14X\211\377" \
-  "*m\230\377\210\255\305\377\362\366\371\377\360\365\370\377\225\266\313" \
-  "\377\21[\213\377\0J\177\377\0P\203\377\0O\202\377\0N\201\377\14X\211" \
-  "\377/p\232\377}\246\300\377\271\316\335\377m\233\270\377\0O\202\377\0" \
-  "N\202\377\23]\214\3167v\2357\202\0\0\0\0\1\340\352\357\0\377\0\0\0\0" \
-  "\377\0\0\0\0\377\0\0\0\0\242\0\0\0\0\1u\243\276\0\202\0\0\0\0\6\236\275" \
-  "\320\4.r\233G\21^\215\361\0Q\204\377\0S\205\377\0S\206\377\203\0T\206" \
-  "\377\212\0U\207\377\204\0T\206\377\1\0S\206\377\203\0S\205\377\202\0" \
-  "R\204\377\2\0Q\204\377\0Q\203\377\210\0P\203\377\202\0O\202\377\11\13" \
-  "W\210\377#h\224\377\207\255\304\377\355\363\367\377\344\354\362\377d" \
-  "\225\264\377\0J\177\377\0M\201\377\0P\203\377\202\0O\202\377\6\12W\210" \
-  "\377)l\227\377w\242\275\377\231\271\316\377R\211\254\306\40f\2230\202" \
-  "\0\0\0\0\1=z\241\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\244\0\0\0\0\1" \
-  "p\236\273\0\202\0\0\0\0\4\307\327\347\2""0q\2338\33d\220\340\0P\203\377" \
-  "\202\0R\204\377\1\0R\205\377\215\0S\205\377\204\0R\204\377\2\0Q\204\377" \
-  "\0Q\203\377\216\0P\203\377\20\0O\203\377\0O\202\377\10V\207\377\34c\221" \
-  "\377\201\251\302\377\350\360\364\377\310\330\344\3770q\233\377\0H}\377" \
-  "\0O\203\377\0P\203\377\0O\203\377\0O\202\377\15Y\212\3776u\236\271\273" \
-  "\320\336\37\202\0\0\0\0\1>z\240\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0" \
-  "\246\0\0\0\0\1t\241\275\0\203\0\0\0\0\4""6v\235$\40g\222\266\2R\204\377" \
-  "\0P\203\377\203\0Q\203\377\210\0R\204\377\204\0Q\203\377\1\0Q\204\377" \
-  "\202\0Q\203\377\224\0P\203\377\13\6T\206\377\26_\216\377y\243\276\377" \
-  "\343\354\361\377\232\272\316\377\12W\210\377\0L\200\377\0O\203\377\5" \
-  "S\205\375$h\224\234\210\257\305\15\202\0\0\0\0\1B~\244\0\377\0\0\0\0" \
-  "\377\0\0\0\0\377\0\0\0\0\250\0\0\0\0\2|\242\301\0\0:n\0\202\0\0\0\0\4" \
-  "P\207\251\21)l\227\201\14X\211\377\0O\202\377\204\0P\203\377\204\0Q\203" \
-  "\377\237\0P\203\377\7\3R\205\377\22\\\214\377x\243\276\377\315\334\347" \
-  "\377`\222\263\377\12W\210\357;x\237f\203\0\0\0\0\1\213\257\307\0\377" \
-  "\0\0\0\0\377\0\0\0\0\377\0\0\0\0\253\0\0\0\0\1""5u\234\0\202\0\0\0\0" \
-  "\3\377\377\377\1<y\241G\24^\215\327\252\0P\203\377\3\24]\214\375\222" \
-  "\265\312\277\377\377\377\33\203\0\0\0\0\1t\240\273\0\377\0\0\0\0\377" \
-  "\0\0\0\0\377\0\0\0\0\256\0\0\0\0\1v\240\276\0\202\0\0\0\0\4i\226\266" \
-  "\23,m\230\212\14X\211\362\0O\203\377\245\0P\203\377\3\1Q\204\375\21\\" \
-  "\214\354A}\243h\202\0\0\0\0\1\331\344\354\0\377\0\0\0\0\377\0\0\0\0\377" \
-  "\0\0\0\0\263\0\0\0\0\1F\177\245\0\202\0\0\0\0\4H\202\246*\"g\223\257" \
-  "\11V\207\365\0P\203\375\240\0P\203\377\10\1P\203\377\1Q\204\373\13W\210" \
-  "\3610q\233\217\307\332\344\15\0\0\0\0\0N{\0\217\257\317\0\377\0\0\0\0" \
-  "\377\0\0\0\0\377\0\0\0\0\265\0\0\0\0\2\200\252\277\0\34b\221\0\202\0" \
-  "\0\0\0\5G\202\2465$h\224\260\11V\207\355\2Q\204\372\1Q\203\377\233\0" \
-  "P\203\377\5\2R\204\377\2Q\204\366\16Z\211\352(l\226\221\260\310\332\26" \
-  "\202\0\0\0\0\1k\232\267\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\271\0\0" \
-  "\0\0\2|\250\275\0\0\0K\0\202\0\0\0\0\6n\234\272).n\231\214\14X\211\327" \
-  "\3R\205\356\4R\205\371\2Q\204\377\225\0P\203\377\6\3R\205\377\2R\204" \
-  "\366\3R\204\354\37d\222\3176t\234l\377\377\377\7\202\0\0\0\0\1o\234\272" \
-  "\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\275\0\0\0\0\2\200\237\277\0:z" \
-  "\241\0\203\0\0\0\0\7B}\244E)l\227\233\17[\212\321\6T\206\345\3R\204\355" \
-  "\5T\205\372\4S\205\377\214\0P\203\377\10\2Q\204\377\5T\206\377\4S\205" \
-  "\365\5S\205\354\5S\206\341\36e\222\311!g\223\177x\242\2751\203\0\0\0" \
-  "\0\1\213\260\306\0\377\0\0\0\0\303\0\0\0\0\1\0U\200\0\206\0\0\0\0\1\0" \
-  "P\200\0\212\0\0\0\0\2\0R\200\0\0K\212\0\207\0\0\0\0\1\0O\204\0\246\0" \
-  "\0\0\0\1\0R\205\0\210\0\0\0\0\1\0@\200\0\377\0\0\0\0\262\0\0\0\0\1r\236" \
-  "\272\0\204\0\0\0\0\25y\244\2766\40f\223^(l\226\233\35c\221\301\3S\205" \
-  "\317\7U\206\333\10U\207\342\7T\206\346\4S\205\350\3R\205\350\2R\204\350" \
-  "\4S\205\350\6T\206\347\7U\207\345\11V\207\340\5S\205\327\14Y\211\315" \
-  "%i\224\270\"g\223\204@|\242W\267\317\336\31\204\0\0\0\0\1i\230\266\0" \
-  "\377\0\0\0\0\302\0\0\0\0\1\0P\203\0\205\0\0\0\0\2\0-\201\0\0^t\0\206" \
-  "\0\0\0\0\2\0[x\0\0N\205\0\204\0\0\0\0\1\0O\202\0\202\0\0\0\0\11\0P\203" \
-  "\14\0P\203#\0P\2030\0P\2033\0P\203.\0P\203\37\0M\206\3\0\0\0\0\0O\203" \
-  "\0\203\0\0\0\0\1\0P\203\0\223\0\0\0\0\1\0P\203\0\212\0\0\0\0\1\0O\203" \
-  "\0\205\0\0\0\0\3\0P\206\2\0P\206\3\0L\203\2\205\0\0\0\0\1\0P\203\0\377" \
-  "\0\0\0\0\263\0\0\0\0\1|\250\301\0\206\0\0\0\0\13\233\272\316%g\226\265" \
-  "AH\200\246M,m\230T\36d\222U\25_\216V(k\226U;x\240RR\211\253K|\245\300" \
-  "9\327\344\354\27\206\0\0\0\0\1\205\254\306\0\377\0\0\0\0\304\0\0\0\0" \
-  "\17\0O\203\0\0\0\0\0\0P\203\1\0P\203\40\0P\2035\0P\203A\0P\203S\0P\203" \
-  "V\0P\203W\0P\203L\0P\203B\0P\203<\0P\2034\0P\203*\0P\203\27\205\0\0\0" \
-  "\0\1\0I\200\0\202\0\0\0\0\3\0P\203!\0P\203\177\0P\203\326\203\0P\203" \
-  "\377\5\0P\203\305\0P\203^\0N\203\16\0\0\0\0\0N\202\0\203\0\0\0\0\3\0" \
-  "P\203\5\0P\203\36\0P\203-\217\0P\203,\1\0P\203\27\211\0\0\0\0\2\0L\204" \
-  "\0\0S\202\0\202\0\0\0\0\14\0N\203\26\0P\203/\0P\203\77\0P\203R\0P\203" \
-  "^\0P\203`\0P\203\\\0P\203O\0P\203@\0P\2035\0P\203(\0P\203\16\377\0\0" \
-  "\0\0\307\0\0\0\0\1}\245\300\0\377\0\0\0\0\310\0\0\0\0\6\0U\252\0\0\0" \
-  "\0\0\0L\203\5\0P\203Y\0P\203\273\0P\203\363\207\0P\203\377\3\0P\203\365" \
-  "\0P\203\334\0P\203\210\205\0\0\0\0\4\0T\205\0\0\0\0\0\0P\203)\0P\203" \
-  "\277\202\0P\203\377\3\0P\203\344\0P\203\332\0P\203\367\202\0P\203\377" \
-  "\2\0P\203\204\0H\177\3\204\0\0\0\0\3\0P\203\27\0P\203\231\0P\203\343" \
-  "\205\0P\203\334\204\0P\203\333\205\0P\203\334\2\0P\203\336\0P\203v\211" \
-  "\0\0\0\0\6\0R\202\0\0\0\0\0\0P\203\16\0P\203P\0O\203\242\0P\203\344\207" \
-  "\0P\203\377\3\0P\203\370\0P\203\324\0P\203L\377\0\0\0\0\377\0\0\0\0\377" \
-  "\0\0\0\0\221\0\0\0\0\4\0Oy\0\0\0\0\0\0P\203[\0P\203\371\202\0P\203\377" \
-  "\3\0P\203\362\0P\203\343\0P\203\340\202\0P\203\337\5\0P\203\340\0P\203" \
-  "\343\0P\203\351\0P\203\366\0P\203\255\206\0\0\0\0\2\0N\202\6\0P\203\253" \
-  "\202\0P\203\377\5\0P\203\251\0P\203U\0P\203B\0P\203{\0P\203\347\202\0" \
-  "P\203\377\1\0O\203F\204\0\0\0\0\2\0P\203\34\0P\203\271\220\0P\203\377" \
-  "\1\0P\203\216\210\0\0\0\0\5\0P\203\0\0\0\0\0\0O\203\20\0P\203\200\0P" \
-  "\203\366\202\0P\203\377\12\0P\203\374\0P\203\347\0P\203\336\0P\203\333" \
-  "\0P\203\334\0P\203\336\0P\203\343\0P\203\354\0P\203\371\0P\203S\377\0" \
-  "\0\0\0\377\0\0\0\0\377\0\0\0\0\223\0\0\0\0\1\0P\203\317\202\0P\203\377" \
-  "\4\0P\203\271\0P\203o\0P\203U\0P\203P\202\0P\203O\7\0P\203Q\0P\203U\0" \
-  "P\203Z\0P\203c\0P\203D\0\0\0\0\0P\207\0\204\0\0\0\0\5\0P\203I\0P\203" \
-  "\340\0P\203\377\0P\203\304\0P\203\26\203\0\0\0\0\4\0P\203y\0P\203\376" \
-  "\0P\203\377\0P\203\261\204\0\0\0\0\3\0P\203\17\0P\203b\0P\203\221\204" \
-  "\0P\203\214\2\0P\203\205\0P\203\323\202\0P\203\377\2\0P\203\250\0P\203" \
-  "\211\204\0P\203\214\2\0P\203\215\0P\203K\211\0\0\0\0\20\0P\203\1\0P\203" \
-  "k\0P\203\371\0P\203\377\0P\203\365\0P\203\270\0P\203~\0P\203\\\0P\203" \
-  "M\0P\203I\0P\203J\0P\203N\0P\203T\0P\203`\0P\203m\0O\203\32\377\0\0\0" \
-  "\0\377\0\0\0\0\377\0\0\0\0\222\0\0\0\0\5\0P\202'\0P\203\346\0P\203\377" \
-  "\0P\203\360\0P\203\40\212\0\0\0\0\1\0P\203\1\205\0\0\0\0\14\0P\203p\0" \
-  "P\203\360\0P\203\377\0P\203\177\0P\203\12\0\0\0\0\0P\201\0\0\0\0\0\0" \
-  "P\203%\0P\203\375\0P\203\377\0P\203\330\203\0\0\0\0\1\0P\203\0\210\0" \
-  "\0\0\0\1\0P\203\227\202\0P\203\377\1\0P\2031\207\0\0\0\0\1\0P\203\0\206" \
-  "\0\0\0\0\10\0P\203\0\0\0\0\0\0P\203-\0P\203\310\0P\203\377\0P\203\373" \
-  "\0P\203\226\0P\203\26\212\0\0\0\0\1\0O\203\0\377\0\0\0\0\377\0\0\0\0" \
-  "\377\0\0\0\0\221\0\0\0\0\5\0P\202A\0P\203\350\0P\203\377\0P\203\274\0" \
-  "P\203\4\220\0\0\0\0\14\0P\203l\0P\203\356\0P\203\377\0P\203\251\0P\203" \
-  "\17\0\0\0\0\0O\202\0\0\0\0\0\0Q\204<\0P\203\375\0P\203\377\0P\203\307" \
-  "\214\0\0\0\0\1\0P\203\235\202\0P\203\377\1\0P\203=\220\0\0\0\0\1\0P\203" \
-  "^\202\0P\203\377\2\0P\203\276\0P\203#\202\0\0\0\0\1\0O\203\0\222\0\0" \
-  "\0\0\2\0f\231\0\0J}\0\204\0\0\0\0\1\0P\202\0\203\0\0\0\0\1\0R\205\0\206" \
-  "\0\0\0\0\1\0N\205\0\240\0\0\0\0\1\0R\207\0\205\0\0\0\0\1\0P\203\0\377" \
-  "\0\0\0\0\377\0\0\0\0\316\0\0\0\0\5\0P\203J\0P\203\352\0P\203\377\0P\203" \
-  "\251\0P\203\7\220\0\0\0\0\5\0P\203:\0P\203\331\0P\203\377\0P\203\367" \
-  "\0P\203O\203\0\0\0\0\4\0P\203\251\0P\203\376\0P\203\377\0P\203s\214\0" \
-  "\0\0\0\1\0P\203\235\202\0P\203\377\1\0P\203=\217\0\0\0\0\2\0N\203\13" \
-  "\0P\203\212\202\0P\203\377\1\0P\203z\202\0\0\0\0\1\0U\200\0\214\0\0\0" \
-  "\0\1\0P\203\0\204\0\0\0\0\1\0P\204\0\204\0\0\0\0\3\0Q\204\20\0P\202\16" \
-  "\0P\201\2\202\0\0\0\0\1\0P\204\0\203\0\0\0\0\4\0P\203\5\0P\203\20\0N" \
-  "\203\23\0M\200\12\204\0\0\0\0\1\0P\202\0\203\0\0\0\0\1\0P\203\0\205\0" \
-  "\0\0\0\1\0O\202\0\204\0\0\0\0\1\0Q\204\0\204\0\0\0\0\3\0P\203\0\0\0\0" \
-  "\0\0P\202\0\205\0\0\0\0\1\0Q\202\0\203\0\0\0\0\3\0R\206\5\0O\203\23\0" \
-  "N\203\7\203\0\0\0\0\1\0P\204\0\377\0\0\0\0\377\0\0\0\0\314\0\0\0\0\5" \
-  "\0P\203B\0P\203\350\0P\203\377\0P\203\271\0O\204\5\221\0\0\0\0\13\0P" \
-  "\203\235\0P\203\376\0P\203\377\0P\203\331\0P\203/\0P\203\35\0P\203\221" \
-  "\0P\203\370\0P\203\377\0P\203\315\0R\203\22\214\0\0\0\0\1\0P\203\235" \
-  "\202\0P\203\377\1\0P\203=\217\0\0\0\0\7\0P\203\37\0P\203\257\0P\203\377" \
-  "\0P\203\356\0P\203W\0\0\0\0\0O\203\0\216\0\0\0\0\4\0P\203\24\0P\203\205" \
-  "\0P\203m\0P\205\30\202\0\0\0\0\23\0P\204#\0P\203s\0P\203\242\0P\203\275" \
-  "\0P\203m\0P\203\16\0\0\0\0\0P\203\1\0\0\0\0\0P\205\26\0P\203f\0P\203" \
-  "\231\0P\203\255\0P\203\265\0P\203\266\0P\203\260\0P\203\244\0P\203}\0" \
-  "P\2036\202\0\0\0\0\1\0P\203\0\203\0\0\0\0\5\0P\203#\0P\203n\0P\203\212" \
-  "\0P\203H\0N\201\7\206\0\0\0\0\4\0Q\204+\0P\203\177\0P\203\201\0P\203" \
-  ">\203\0\0\0\0\16\0P\201\2\0P\2030\0P\203\213\0P\203d\0P\203\11\0\0\0" \
-  "\0\0O\204\11\0P\203R\0P\203\217\0P\203\256\0P\203\266\0P\203\261\0P\203" \
-  "\222\0P\2042\202\0\0\0\0\1\0Q\203\0\377\0\0\0\0\377\0\0\0\0\313\0\0\0" \
-  "\0\5\0Q\203\36\0P\203\345\0P\203\377\0P\203\361\0Q\202\25\202\0\0\0\0" \
-  "\1\0P\201\0\214\0\0\0\0\4\0P\203\0\0\0\0\0\0P\203(\0P\203\317\202\0P" \
-  "\203\377\10\0P\203\306\0P\203\304\0P\203\376\0P\203\377\0P\203\315\0" \
-  "P\2032\0\0\0\0\0Q\203\0\213\0\0\0\0\1\0P\203\235\202\0P\203\377\1\0P" \
-  "\203=\217\0\0\0\0\5\0P\203-\0P\203\310\0P\203\377\0P\203\331\0P\203C" \
-  "\220\0\0\0\0\10\0P\203'\0P\203\377\0P\203\331\0P\2036\0Q\203\12\0P\203" \
-  "z\0P\203\312\0P\203\367\202\0P\203\377\2\0P\203\215\0P\204\13\202\0\0" \
-  "\0\0\3\0P\203\77\0P\203\267\0P\203\354\206\0P\203\377\3\0P\203\371\0" \
-  "P\203\320\0P\203u\202\0\0\0\0\1\0\200\200\0\202\0\0\0\0\5\0P\203D\0P" \
-  "\203\327\0P\203\377\0P\203\213\0N\201\15\206\0\0\0\0\4\0Q\204S\0P\203" \
-  "\367\0P\203\372\0P\203z\203\0\0\0\0\10\0P\201\5\0P\203]\0P\203\377\0" \
-  "P\203\305\0P\203\33\0P\203;\0P\203\257\0P\203\347\205\0P\203\377\5\0" \
-  "P\203\327\0Q\203\77\0R\203\2\0\0\0\0\0`\200\0\377\0\0\0\0\377\0\0\0\0" \
-  "\313\0\0\0\0\1\0P\203\304\202\0P\203\377\2\0P\203\267\0P\203B\205\0\0" \
-  "\0\0\1\0N\203\0\210\0\0\0\0\5\0P\200\0\0M\203\0\0\0\0\0\0P\203E\0P\203" \
-  "\342\203\0P\203\377\5\0P\203\372\0P\203\227\0P\203+\0\0\0\0\0N\202\0" \
-  "\214\0\0\0\0\1\0P\203\235\202\0P\203\377\1\0P\203=\217\0\0\0\0\5\0P\203" \
-  "4\0P\203\326\0P\203\377\0P\203\311\0P\2034\210\0\0\0\0\1\0P\203\1\204" \
-  "\0\0\0\0\1\0P\204\0\202\0\0\0\0\17\0P\203(\0P\203\377\0P\203\352\0P\203" \
-  "\224\0P\203\260\0P\203\374\0P\203\377\0P\203\360\0P\203\277\0P\203\263" \
-  "\0P\203I\0T\221\1\0\0\0\0\0P\203\40\0P\203\306\202\0P\203\377\6\0P\203" \
-  "\336\0P\203\225\0P\203w\0P\203s\0P\203\205\0P\203\275\202\0P\203\377" \
-  "\4\0P\203\352\0P\203f\0\0\0\0\0G\204\0\202\0\0\0\0\5\0P\203E\0P\203\334" \
-  "\0P\203\377\0P\203\217\0N\201\16\206\0\0\0\0\4\0Q\204U\0P\203\375\0P" \
-  "\203\377\0P\203}\203\0\0\0\0\14\0P\201\5\0P\203`\0P\203\377\0P\203\334" \
-  "\0P\203\221\0P\203\336\0P\203\377\0P\203\353\0P\203\242\0P\204\200\0" \
-  "P\203\215\0P\203\334\202\0P\203\377\4\0P\203\310\0Q\203\23\0\0\0\0\0" \
-  "H\204\0\377\0\0\0\0\377\0\0\0\0\311\0\0\0\0\4\0Q\203\0\0\0\0\0\0P\203" \
-  "H\0P\203\366\202\0P\203\377\5\0P\203\340\0P\203\311\0P\203\233\0P\203" \
-  "d\0P\203.\204\0\0\0\0\1\0P\201\0\204\0\0\0\0\1\0P\202\0\202\0\0\0\0\3" \
-  "\0P\203+\0P\203\247\0P\203\366\203\0P\203\377\2\0P\203\275\0S\203\20" \
-  "\202\0\0\0\0\1\0U\206\0\214\0\0\0\0\1\0P\203\235\202\0P\203\377\1\0P" \
-  "\203=\217\0\0\0\0\5\0P\2038\0P\203\336\0P\203\377\0P\203\301\0P\203," \
-  "\211\0\0\0\0\1\0P\203\200\202\0P\203\247\1\0P\205\17\203\0\0\0\0\13\0" \
-  "P\203'\0P\203\377\0P\203\374\0P\203\367\0P\203\377\0P\203\306\0P\203" \
-  "b\0P\203-\0P\203\37\0P\203\32\0P\203\11\202\0\0\0\0\13\0P\203\215\0P" \
-  "\203\372\0P\203\377\0Q\203\277\0P\2031\0O\203\22\0P\205\11\0N\203\7\0" \
-  "P\203\15\0P\203!\0P\203o\202\0P\203\377\2\0P\203\310\0S\203\20\203\0" \
-  "\0\0\0\5\0P\203E\0P\203\333\0P\203\377\0P\203\216\0N\201\16\206\0\0\0" \
-  "\0\4\0Q\204U\0P\203\374\0P\203\377\0P\203}\203\0\0\0\0\15\0P\201\5\0" \
-  "P\203_\0P\203\377\0P\203\371\0P\203\375\0P\203\363\0P\203\200\0P\203" \
-  "-\0Q\204\25\0Q\205\13\0P\203\16\0P\203+\0P\203\310\202\0P\203\377\2\0" \
-  "P\203N\0P\203\3\377\0\0\0\0\377\0\0\0\0\314\0\0\0\0\3\0U\210\1\0O\202" \
-  "X\0P\203\352\203\0P\203\377\6\0P\203\372\0P\203\355\0P\203\340\0P\203" \
-  "\316\0P\203\227\0P\203C\202\0\0\0\0\1\0P\204\0\202\0\0\0\0\1\0O\202\0" \
-  "\202\0\0\0\0\5\0P\203f\0P\203\326\0P\203\374\0P\203\377\0P\203\370\202" \
-  "\0P\203\377\4\0P\203\365\0P\203X\0\0\0\0\0P\203\0\205\0\0\0\0\1\0Q\203" \
-  "\0\207\0\0\0\0\1\0P\203\235\202\0P\203\377\1\0P\203=\217\0\0\0\0\5\0" \
-  "P\203<\0P\203\345\0P\203\377\0P\203\275\0P\203(\211\0\0\0\0\4\0P\203" \
-  "\302\0P\203\375\0P\203\374\0Q\202\27\203\0\0\0\0\1\0P\203'\202\0P\203" \
-  "\377\4\0P\203\326\0Q\203P\0P\204\27\0P\202\4\205\0\0\0\0\2\0J\203\5\0" \
-  "P\203\314\202\0P\203\377\1\0P\2035\206\0\0\0\0\5\0P\203\24\0P\203\273" \
-  "\0P\203\377\0P\203\346\0P\203P\203\0\0\0\0\5\0P\203E\0P\203\333\0P\203" \
-  "\377\0P\203\216\0N\201\16\206\0\0\0\0\4\0Q\204U\0P\203\374\0P\203\377" \
-  "\0P\203}\203\0\0\0\0\2\0P\201\5\0P\203_\202\0P\203\377\3\0P\203\303\0" \
-  "Q\204>\0P\202\10\205\0\0\0\0\5\0P\204k\0P\203\355\0P\203\377\0P\203\224" \
-  "\0P\203\13\377\0\0\0\0\377\0\0\0\0\313\0\0\0\0\7\0P\203\0\0\0\0\0\0N" \
-  "\201\4\0O\203\40\0P\203l\0P\203\265\0P\203\363\204\0P\203\377\7\0P\203" \
-  "\371\0P\203\352\0P\203\241\0P\206\20\0\0\0\0\0Q\205\0\0f\231\0\202\0" \
-  "\0\0\0\2\0P\203u\0P\203\356\202\0P\203\377\3\0P\203\225\0P\203%\0P\203" \
-  "\302\202\0P\203\377\10\0P\203\357\0P\203-\0\0\0\0\0P\203\1\0P\203.\0" \
-  "P\203\200\0P\203E\0R\203\25\210\0\0\0\0\1\0P\203\235\202\0P\203\377\1" \
-  "\0P\203=\217\0\0\0\0\5\0P\203=\0P\203\346\0P\203\377\0P\203\273\0P\203" \
-  "&\211\0\0\0\0\4\0P\203\303\0P\203\377\0P\203\376\0Q\202\27\203\0\0\0" \
-  "\0\1\0P\203'\202\0P\203\377\1\0P\203\254\203\0\0\0\0\2\0L\211\0\0R\200" \
-  "\0\203\0\0\0\0\7\0P\203,\0P\203\334\0P\203\377\0P\203\320\0P\203\20\0" \
-  "\0\0\0\0X\212\0\202\0\0\0\0\7\0O\203\0\0\0\0\0\0Q\203\6\0Q\203m\0P\203" \
-  "\377\0P\203\363\0P\203}\203\0\0\0\0\5\0P\203E\0P\203\333\0P\203\377\0" \
-  "P\203\216\0N\201\16\206\0\0\0\0\4\0Q\204U\0P\203\374\0P\203\377\0P\203" \
-  "}\203\0\0\0\0\5\0P\201\5\0P\203_\0P\203\377\0P\203\360\0P\203u\203\0" \
-  "\0\0\0\11\0Q\201\0\0\0\0\0\0O\203\0\0\0\0\0\0Q\203,\0P\203\332\0P\203" \
-  "\377\0P\203\303\0P\203\21\377\0\0\0\0\377\0\0\0\0\314\0\0\0\0\1\0O\202" \
-  "\0\202\0\0\0\0\7\0P\203\6\0P\203\17\0P\203\27\0O\202<\0P\203|\0P\203" \
-  "\275\0P\203\375\202\0P\203\377\2\0P\203\374\0P\203\236\202\0\0\0\0\4" \
-  "\0I|\0\0\0\0\0\0P\203V\0P\203\345\202\0P\203\377\5\0P\203m\0O\202\16" \
-  "\0\0\0\0\0O\204\35\0P\203\341\202\0P\203\377\7\0P\203\330\0P\203\14\0" \
-  "P\202\3\0P\203\204\0P\203\375\0P\203\353\0P\203\223\210\0\0\0\0\1\0P" \
-  "\203\235\202\0P\203\377\1\0P\203=\217\0\0\0\0\5\0P\2039\0P\203\340\0" \
-  "P\203\377\0P\203\276\0P\203)\211\0\0\0\0\1\0P\203\303\202\0P\203\376" \
-  "\1\0Q\202\27\203\0\0\0\0\1\0P\203'\202\0P\203\377\4\0P\203\250\0\0\0" \
-  "\0\0P~\0\0U\252\0\205\0\0\0\0\7\0P\203L\0P\203\345\0P\203\377\0P\203" \
-  "\247\0P\203\14\0\0\0\0\0N\200\0\204\0\0\0\0\5\0Q\205\1\0P\203C\0P\203" \
-  "\377\0P\203\374\0P\203\234\203\0\0\0\0\5\0P\203E\0P\203\333\0P\203\377" \
-  "\0P\203\216\0N\201\16\206\0\0\0\0\4\0Q\204U\0P\203\374\0P\203\377\0P" \
-  "\203}\203\0\0\0\0\7\0P\201\5\0P\203_\0P\203\377\0P\203\356\0P\203m\0" \
-  "\0\0\0\0Q\204\0\205\0\0\0\0\5\0Q\203\14\0P\203\320\0P\203\377\0P\203" \
-  "\343\0P\203\25\377\0\0\0\0\377\0\0\0\0\315\0\0\0\0\1\0L\204\0\204\0\0" \
-  "\0\0\5\0N\177\1\0P\203\6\0P\203\13\0P\204\32\0P\203z\202\0P\203\377\2" \
-  "\0P\203\335\0P\203H\202\0\0\0\0\2\0P\203\25\0P\203\252\202\0P\203\377" \
-  "\2\0P\203~\0P\203\13\203\0\0\0\0\2\0P\203:\0P\203\365\202\0P\203\377" \
-  "\6\0P\203\265\0[\245\1\0P\203\335\0P\203\377\0P\203\360\0Q\203`\210\0" \
-  "\0\0\0\1\0P\203\235\202\0P\203\377\1\0P\203=\217\0\0\0\0\5\0P\2036\0" \
-  "P\203\331\0P\203\377\0P\203\303\0P\203.\211\0\0\0\0\1\0P\203\303\202" \
-  "\0P\203\376\1\0Q\202\27\203\0\0\0\0\1\0P\203'\202\0P\203\377\1\0P\203" \
-  "\250\210\0\0\0\0\5\0P\203Y\0P\203\350\0P\203\377\0P\203\225\0P\203\13" \
-  "\207\0\0\0\0\1\0P\2022\202\0P\203\377\1\0P\203\250\203\0\0\0\0\5\0P\203" \
-  "E\0P\203\333\0P\203\377\0P\203\216\0N\201\16\206\0\0\0\0\4\0Q\204U\0" \
-  "P\203\374\0P\203\377\0P\203}\203\0\0\0\0\5\0P\201\5\0P\203_\0P\203\377" \
-  "\0P\203\356\0P\203n\210\0\0\0\0\4\0P\203\313\0P\203\377\0P\203\361\0" \
-  "P\203\26\377\0\0\0\0\377\0\0\0\0\326\0\0\0\0\5\0P\203\20\0P\203\214\0" \
-  "P\203\377\0P\203\367\0P\203\201\202\0\0\0\0\5\0P\203F\0P\203\332\0P\203" \
-  "\377\0P\203\326\0P\2033\202\0\0\0\0\1\0O\203\0\202\0\0\0\0\5\0Q\203c" \
-  "\0P\203\375\0P\203\377\0P\203\375\0P\203\277\202\0P\203\377\2\0P\203" \
-  "\341\0R\205\14\210\0\0\0\0\1\0P\203\235\202\0P\203\377\1\0P\203=\217" \
-  "\0\0\0\0\5\0P\203.\0P\203\312\0P\203\377\0P\203\317\0P\203:\211\0\0\0" \
-  "\0\1\0P\203\303\202\0P\203\376\1\0Q\202\27\203\0\0\0\0\1\0P\203'\202" \
-  "\0P\203\377\1\0P\203\250\210\0\0\0\0\5\0P\203a\0P\203\352\0P\203\377" \
-  "\0P\203\217\0P\203\12\207\0\0\0\0\1\0P\203+\202\0P\203\377\1\0P\203\260" \
-  "\203\0\0\0\0\5\0P\203E\0P\203\333\0P\203\377\0P\203\216\0N\201\16\206" \
-  "\0\0\0\0\4\0Q\204U\0P\203\374\0P\203\377\0P\203}\203\0\0\0\0\5\0P\201" \
-  "\5\0P\203_\0P\203\377\0P\203\356\0P\203n\210\0\0\0\0\4\0P\203\311\0P" \
-  "\203\377\0P\203\371\0P\203\27\377\0\0\0\0\377\0\0\0\0\323\0\0\0\0\5\0" \
-  "N\211\0\0R}\0\0\0\0\0\0P\203\0\0P\203K\202\0P\203\377\1\0P\203\235\202" \
-  "\0\0\0\0\11\0P\203]\0P\203\360\0P\203\377\0P\203\253\0P\203\35\0\0\0" \
-  "\0\0P\203\0\0\0\0\0\0P\203\0\202\0\0\0\0\2\0P\203\225\0P\203\376\203" \
-  "\0P\203\377\2\0P\203\370\0P\203\217\211\0\0\0\0\1\0P\203\235\202\0P\203" \
-  "\377\1\0P\203=\217\0\0\0\0\5\0P\203!\0P\203\263\0P\203\377\0P\203\337" \
-  "\0P\203J\211\0\0\0\0\1\0P\203\303\202\0P\203\376\1\0Q\202\27\203\0\0" \
-  "\0\0\1\0P\203'\202\0P\203\377\1\0P\203\250\210\0\0\0\0\5\0P\203X\0P\203" \
-  "\350\0P\203\377\0P\203\225\0P\203\13\207\0\0\0\0\1\0Q\2032\202\0P\203" \
-  "\377\1\0P\203\250\203\0\0\0\0\5\0P\203E\0P\203\333\0P\203\377\0P\203" \
-  "\216\0N\201\16\206\0\0\0\0\4\0Q\204U\0P\203\374\0P\203\377\0P\203}\203" \
-  "\0\0\0\0\5\0P\201\5\0P\203_\0P\203\377\0P\203\356\0P\203n\210\0\0\0\0" \
-  "\4\0P\203\313\0P\203\377\0P\203\361\0P\203\26\377\0\0\0\0\377\0\0\0\0" \
-  "\327\0\0\0\0\1\0Q\203:\202\0P\203\377\1\0P\203\246\202\0\0\0\0\7\0P\203" \
-  "\\\0P\203\357\0P\203\377\0P\203\266\0P\203\"\0\0\0\0\0P\203\0\205\0\0" \
-  "\0\0\1\0P\203\277\203\0P\203\377\4\0P\203\346\0P\203\27\0\0\0\0\0P\204" \
-  "\0\207\0\0\0\0\1\0P\203\235\202\0P\203\377\1\0P\203=\217\0\0\0\0\5\0" \
-  "P\203\23\0P\203\230\0P\203\377\0P\203\374\0P\203f\207\0\0\0\0\3\0P\202" \
-  "\0\0\0\0\0\0P\203\303\202\0P\203\376\1\0Q\202\27\203\0\0\0\0\1\0P\203" \
-  "'\202\0P\203\377\1\0P\203\250\210\0\0\0\0\7\0P\203L\0P\203\345\0P\203" \
-  "\377\0P\203\250\0P\203\15\0\0\0\0\0P\203\0\204\0\0\0\0\5\0N\203\2\0P" \
-  "\203E\0P\203\377\0P\203\374\0P\203\234\203\0\0\0\0\5\0P\203E\0P\203\333" \
-  "\0P\203\377\0P\203\216\0N\201\16\204\0\0\0\0\6\0Q\205\0\0\0\0\0\0Q\204" \
-  "U\0P\203\374\0P\203\377\0P\203}\203\0\0\0\0\5\0P\201\5\0P\203_\0P\203" \
-  "\377\0P\203\356\0P\203n\207\0\0\0\0\5\0M\206\11\0P\203\317\0P\203\377" \
-  "\0P\203\345\0P\203\25\377\0\0\0\0\377\0\0\0\0\324\0\0\0\0\1\0P\204\0" \
-  "\202\0\0\0\0\1\0P\203D\202\0P\203\377\1\0P\203\237\202\0\0\0\0\5\0P\203" \
-  "D\0P\203\331\0P\203\377\0P\203\360\0P\203B\202\0\0\0\0\3\0P\202\0\0\200" \
-  "\200\0\0A\204\0\202\0\0\0\0\1\0P\2039\203\0P\203\377\2\0P\203\335\0Q" \
-  "\203\31\202\0\0\0\0\1\0P\203\0\206\0\0\0\0\1\0P\203\235\202\0P\203\377" \
-  "\1\0P\203=\220\0\0\0\0\1\0P\203o\202\0P\203\377\4\0P\203\222\0P\203\7" \
-  "\0\0\0\0\0P\203\0\202\0\0\0\0\1\0O\202\0\203\0\0\0\0\1\0P\203\304\202" \
-  "\0P\203\376\1\0Q\202\27\203\0\0\0\0\1\0P\203'\202\0P\203\377\1\0P\203" \
-  "\250\210\0\0\0\0\5\0P\203,\0P\203\333\0P\203\377\0P\203\320\0P\203\21" \
-  "\202\0\0\0\0\11\0N\211\0\0\0\0\0\0P\203\0\0\0\0\0\0O\203\7\0O\203n\0" \
-  "P\203\377\0P\203\362\0P\203|\203\0\0\0\0\5\0P\203E\0P\203\333\0P\203" \
-  "\377\0P\203\216\0P\203\16\202\0\0\0\0\1\0N\201\0\203\0\0\0\0\4\0Q\204" \
-  "Y\0P\203\374\0P\203\377\0P\203}\203\0\0\0\0\10\0P\201\5\0P\203_\0P\203" \
-  "\377\0P\203\356\0P\203m\0\0\0\0\0L}\0\0Q\206\0\202\0\0\0\0\7\0R\204\0" \
-  "\0\0\0\0\0P\203)\0P\203\331\0P\203\377\0P\203\304\0P\203\21\377\0\0\0" \
-  "\0\377\0\0\0\0\313\0\0\0\0\1\0P\203\0\212\0\0\0\0\5\0P\203\12\0P\203" \
-  "w\0P\203\377\0P\203\374\0P\203\216\202\0\0\0\0\2\0P\203\25\0P\203\253" \
-  "\202\0P\203\377\2\0P\203\237\0P\203\32\204\0\0\0\0\3\0P\203\3\0P\202" \
-  "\40\0P\203\332\203\0P\203\377\3\0P\203\376\0P\203\307\0P\204\21\202\0" \
-  "\0\0\0\1\0Q\204\0\205\0\0\0\0\1\0P\203\235\202\0P\203\377\1\0P\203=\216" \
-  "\0\0\0\0\7\0Q\203\0\0\0\0\0\0P\203E\0P\203\351\0P\203\377\0P\203\330" \
-  "\0P\203D\205\0\0\0\0\7\0L\177\1\0P\204\7\0P\202R\0P\203\355\0P\203\377" \
-  "\0P\203\376\0Q\202\27\203\0\0\0\0\1\0P\203'\202\0P\203\377\1\0P\203\250" \
-  "\210\0\0\0\0\2\0H\203\3\0P\203\315\202\0P\203\377\1\0P\2033\206\0\0\0" \
-  "\0\5\0O\203\24\0O\203\275\0P\203\377\0P\203\345\0P\203Q\203\0\0\0\0\5" \
-  "\0P\203C\0P\203\331\0P\203\377\0P\203\231\0O\203\23\204\0\0\0\0\6\0N" \
-  "\202\6\0Q\205&\0P\203\275\0P\203\376\0P\203\377\0P\203}\203\0\0\0\0\5" \
-  "\0P\201\5\0P\203_\0P\203\377\0P\203\356\0P\203p\207\0\0\0\0\5\0P\203" \
-  "i\0P\203\354\0P\203\377\0P\203\227\0P\203\14\377\0\0\0\0\377\0\0\0\0" \
-  "\312\0\0\0\0\6\0M\200\0\0\0\0\0\0P\203\20\0P\203\24\0P\203\23\0P\203" \
-  "\22\202\0P\203\21\202\0P\203\20\14\0P\203\22\0P\203\26\0P\203K\0P\203" \
-  "\351\0P\203\377\0P\203\352\0P\203c\0\0\0\0\0J}\0\0\0\0\0\0P\203[\0P\203" \
-  "\352\202\0P\203\377\7\0P\203\217\0P\203\"\0P\203\17\0P\203\20\0R\203" \
-  "\24\0P\203[\0P\203\353\202\0P\203\377\2\0P\203\340\0P\203\365\202\0P" \
-  "\203\377\3\0P\203\300\0P\203\33\0T\207\1\206\0\0\0\0\1\0P\203\235\202" \
-  "\0P\203\377\1\0P\203=\220\0\0\0\0\2\0P\203\27\0P\203\240\202\0P\203\377" \
-  "\2\0P\203\275\0P\2037\202\0P\203\16\11\0P\203\17\0P\203\22\0O\2027\0" \
-  "P\203\260\0P\203\377\0P\203\367\0P\203\377\0P\203\376\0Q\202\27\203\0" \
-  "\0\0\0\1\0P\203'\202\0P\203\377\1\0P\203\250\207\0\0\0\0\15\0O\203\0" \
-  "\0\0\0\0\0P\203\215\0P\203\370\0P\203\377\0P\203\307\0P\203$\0P\203\15" \
-  "\0P\203\11\0P\203\10\0P\203\13\0P\203\27\0P\203q\202\0P\203\377\2\0P" \
-  "\203\311\0P\203\15\203\0\0\0\0\14\0P\2038\0P\203\315\0P\203\377\0P\203" \
-  "\317\0P\204=\0P\202\7\0P\203\13\0P\203\17\0O\202\40\0O\203\206\0P\203" \
-  "\374\0P\203\372\202\0P\203\377\1\0P\203}\203\0\0\0\0\11\0P\201\5\0P\203" \
-  "_\0P\203\377\0P\203\370\0P\203\252\0P\2048\0P\203\27\0P\203\20\0P\203" \
-  "\15\202\0O\203\13\2\0R\204)\0P\203\314\202\0P\203\377\2\0Q\204N\0R\205" \
-  "\3\377\0\0\0\0\377\0\0\0\0\314\0\0\0\0\12\0P\203\253\0P\203\323\0P\203" \
-  "\312\0P\203\301\0P\203\273\0P\203\266\0P\203\262\0P\203\264\0P\203\277" \
-  "\0P\203\335\203\0P\203\377\4\0P\203\274\0N\203\30\0\0\0\0\0f\231\0\202" \
-  "\0\0\0\0\2\0P\203\200\0P\203\364\202\0P\203\377\4\0P\203\352\0P\203\267" \
-  "\0P\203\260\0P\203\346\202\0P\203\377\5\0P\203\372\0P\203\312\0P\205" \
-  "\37\0P\204x\0P\203\371\202\0P\203\377\2\0P\203\310\0R\205\27\206\0\0" \
-  "\0\0\1\0P\203\236\202\0P\203\377\1\0P\203=\217\0\0\0\0\4\0P\207\0\0\0" \
-  "\0\0\0P\203D\0P\203\336\202\0P\203\377\5\0P\203\370\0P\203\302\0P\203" \
-  "\242\0P\203\251\0P\203\327\202\0P\203\377\5\0P\203\330\0P\203\210\0P" \
-  "\203\376\0P\203\377\0Q\202\27\203\0\0\0\0\1\0P\203(\202\0P\203\377\1" \
-  "\0P\203\251\211\0\0\0\0\2\0P\203\33\0P\203\312\202\0P\203\377\6\0P\203" \
-  "\360\0P\203\240\0P\203~\0P\203x\0P\203\217\0P\203\314\202\0P\203\377" \
-  "\4\0P\203\350\0P\203g\0\0\0\0\0P\203\0\202\0\0\0\0\2\0R\203\25\0P\203" \
-  "\246\202\0P\203\377\13\0P\203\327\0P\203\224\0P\203\211\0P\203\265\0" \
-  "P\203\376\0P\203\377\0P\203\355\0P\204\203\0P\203\365\0P\203\377\0P\203" \
-  "}\203\0\0\0\0\4\0P\201\5\0P\203_\0P\203\377\0P\203\375\202\0P\203\377" \
-  "\6\0P\203\360\0P\203\271\0P\203\231\0P\203\217\0P\203\247\0P\203\360" \
-  "\202\0P\203\377\4\0P\203\312\0O\203\25\0\0\0\0\0W\205\0\377\0\0\0\0\377" \
-  "\0\0\0\0\313\0\0\0\0\3\0P\203\311\0P\203\370\0P\203\376\207\0P\203\377" \
-  "\15\0P\203\373\0P\203\355\0P\203\302\0P\203B\0\0\0\0\0O\203\0\0\0\0\0" \
-  "\0P\204\0\0\0\0\0\0A\222\2\0P\203u\0P\203\330\0P\203\363\204\0P\203\377" \
-  "\4\0P\203\365\0P\203\340\0P\203\233\0P\206\14\202\0\0\0\0\5\0P\203}\0" \
-  "P\203\362\0P\203\374\0P\203\235\0O\207\4\206\0\0\0\0\4\0P\203\225\0P" \
-  "\203\375\0P\203\377\0P\203:\217\0\0\0\0\1\0P\200\0\202\0\0\0\0\3\0P\203" \
-  "U\0P\203\324\0P\203\366\204\0P\203\377\10\0P\203\372\0P\203\344\0P\203" \
-  "\247\0Q\203\32\0P\203\"\0P\203\357\0P\203\361\0Q\202\26\203\0\0\0\0\4" \
-  "\0P\203%\0P\203\366\0P\203\367\0P\203\237\210\0\0\0\0\6\0P\203\0\0\0" \
-  "\0\0\0P\2037\0P\203\301\0P\203\354\0P\203\376\205\0P\203\377\3\0P\203" \
-  "\363\0P\203\327\0P\203w\204\0\0\0\0\5\0Qz\0\0\0\0\0\0P\203Q\0P\203\330" \
-  "\0P\203\376\204\0P\203\377\7\0P\203\350\0P\203\274\0P\202>\0\0\0\0\0" \
-  "P\203\320\0P\203\362\0P\203v\203\0\0\0\0\10\0P\201\5\0P\203_\0P\203\377" \
-  "\0P\203\355\0P\203\261\0P\203\273\0P\203\352\0P\203\375\204\0P\203\377" \
-  "\6\0P\203\365\0P\203\325\0Q\2045\0\\\227\1\0\0\0\0\0@\200\0\377\0\0\0" \
-  "\0\377\0\0\0\0\313\0\0\0\0\17\0P\203L\0P\203w\0P\203\225\0P\203\253\0" \
-  "P\203\274\0P\203\302\0P\203\305\0P\203\306\0P\203\303\0P\203\270\0P\203" \
-  "\231\0P\203_\0N\203\23\0\0\0\0\0P\203\1\203\0\0\0\0\1\0O\204\0\202\0" \
-  "\0\0\0\10\0P\203(\0P\203|\0P\203\263\0P\203\304\0P\203\306\0P\203\266" \
-  "\0P\203\204\0P\2032\202\0\0\0\0\1\0P\203\0\202\0\0\0\0\5\0P\203a\0P\203" \
-  "\246\0P\203\13\0\0\0\0\0P\204\0\205\0\0\0\0\1\0P\203L\202\0P\203\201" \
-  "\1\0P\203\35\220\0\0\0\0\1\0P\204\0\202\0\0\0\0\10\0P\203$\0P\203\202" \
-  "\0P\203\271\0P\203\310\0P\203\307\0P\203\266\0P\203\206\0Q\2035\202\0" \
-  "\0\0\0\4\0V\201\7\0P\203y\0P\203z\0Q\203\13\203\0\0\0\0\4\0P\203\23\0" \
-  "P\203|\0P\203}\0P\203P\211\0\0\0\0\14\0P\203\1\0\0\0\0\0P\207\11\0P\203" \
-  "a\0P\203\237\0P\203\300\0P\203\306\0P\203\307\0P\203\302\0P\203\260\0" \
-  "P\203|\0P\203*\202\0\0\0\0\1\0N\204\0\202\0\0\0\0\1\0Q\206\0\202\0\0" \
-  "\0\0\7\0P\203<\0P\203\240\0P\203\304\0P\203\310\0P\203\275\0P\203\220" \
-  "\0Q\203E\203\0\0\0\0\3\0P\203b\0P\203z\0P\204;\203\0\0\0\0\16\0P\201" \
-  "\5\0P\203_\0P\203\377\0P\203\352\0P\203^\0\0\0\0\0P\203J\0P\203\213\0" \
-  "P\203\263\0P\203\304\0P\203\305\0P\203\263\0P\203\177\0O\204\32\202\0" \
-  "\0\0\0\1\0Q\205\0\377\0\0\0\0\377\0\0\0\0\312\0\0\0\0\2\0R\200\0\0L\211" \
-  "\0\215\0\0\0\0\1\0O\203\0\205\0\0\0\0\2\0S\200\0\0B\221\0\211\0\0\0\0" \
-  "\3\0U\252\0\0\0\0\0\0P\203\0\204\0\0\0\0\1\0P\203\0\204\0\0\0\0\2\0U" \
-  "\252\0\0O~\1\204\0\0\0\0\1\0P\203\0\220\0\0\0\0\2\0M\202\0\0[\207\0\211" \
-  "\0\0\0\0\1\0O\202\0\204\0\0\0\0\3\0Q\203\0\0\0\0\0\0P\203\0\204\0\0\0" \
-  "\0\1\0P\203\1\211\0\0\0\0\1\0P\204\0\212\0\0\0\0\2\0L\205\0\0U\200\0" \
-  "\204\0\0\0\0\1\0R\205\0\211\0\0\0\0\2\0Qy\0\0P\203\0\203\0\0\0\0\1\0" \
-  "P\204\0\202\0\0\0\0\5\0P\201\5\0P\203_\0P\203\377\0P\203\355\0P\203m" \
-  "\212\0\0\0\0\1\0O\204\0\377\0\0\0\0\377\0\0\0\0\321\0\0\0\0\1\0U\210" \
-  "\0\205\0\0\0\0\1\0U\252\0\213\0\0\0\0\1\0I\222\0\204\0\0\0\0\1\0R\203" \
-  "\0\205\0\0\0\0\1\0T\202\0\202\0\0\0\0\1\0T\202\0\237\0\0\0\0\1\0P\204" \
-  "\0\204\0\0\0\0\1\0T\202\0\233\0\0\0\0\1\0U\200\0\204\0\0\0\0\1\0S\204" \
-  "\0\212\0\0\0\0\2\0`\200\0\0\0\244\0\203\0\0\0\0\2\0\27\202\0\0\200\200" \
-  "\0\211\0\0\0\0\5\0P\201\5\0P\203_\0P\203\377\0P\203\356\0P\203n\202\0" \
-  "\0\0\0\1\0U\200\0\204\0\0\0\0\1\0P\200\0\377\0\0\0\0\377\0\0\0\0\377" \
-  "\0\0\0\0\326\0\0\0\0\5\0P\201\5\0P\203_\0P\203\377\0P\203\356\0P\203" \
-  "n\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\336\0\0\0\0\5\0P\201\5\0P\203_" \
-  "\0P\203\377\0P\203\356\0P\203n\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\336" \
-  "\0\0\0\0\5\0P\201\5\0P\203b\0P\203\377\0P\203\366\0P\203q\377\0\0\0\0" \
-  "\377\0\0\0\0\377\0\0\0\0\336\0\0\0\0\5\0Q\203\3\0P\203F\0P\203\310\0" \
-  "P\203\257\0P\203P\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\336\0\0\0\0\5\0" \
-  "S\206\1\0Q\204\17\0P\203*\0P\203%\0P\203\21\377\0\0\0\0\377\0\0\0\0\377" \
-  "\0\0\0\0\335\0\0\0\0\1\0Q\204\0\205\0\0\0\0\1\0P\203\0\377\0\0\0\0\377" \
-  "\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0" \
-  "\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0" \
-  "\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377" \
-  "\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0" \
-  "\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0\0\0\377\0\0" \
-  "\0\0\321\0\0\0\0")
-
-
diff --git a/recipes-core/psplash/psplash-drm/kontronelectronics_small.png b/recipes-core/psplash/psplash-drm/kontronelectronics_small.png
deleted file mode 100755
index cbaeb42bf6d51be75c1b789fe0b7b51b679c703f..0000000000000000000000000000000000000000
Binary files a/recipes-core/psplash/psplash-drm/kontronelectronics_small.png and /dev/null differ
diff --git a/recipes-core/psplash/psplash-drm/psplash-init-script.sh b/recipes-core/psplash/psplash-drm/psplash-init-script.sh
deleted file mode 100644
index aa31035d09cec79ad9d709663d383f1f19db316d..0000000000000000000000000000000000000000
--- a/recipes-core/psplash/psplash-drm/psplash-init-script.sh
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/sh
-
-script_path="/usr/bin/psplash-drm"
-script_stop_path="/usr/bin/psplash-drm-quit"
-
-case "$1" in
-
-start)
-	if test -f $script_path;then
-		$script_path &
-	fi
-	;;
-
-stop)
-	if test -f $script_stop_path;then
-		$script_stop_path &
-	fi
-	;;
-
-esac
diff --git a/recipes-core/systemd/systemd-networkd-configuration.bb b/recipes-core/systemd/systemd-networkd-configuration.bb
index cb2f4b7246659791a4c4cc4f1a1161c7f9ef2133..153a57b0069b7888057a2984fed314fefe4714ad 100644
--- a/recipes-core/systemd/systemd-networkd-configuration.bb
+++ b/recipes-core/systemd/systemd-networkd-configuration.bb
@@ -9,10 +9,7 @@ DEPENDS = "systemd"
 PR = "r0"
 SRC_URI_append += "\
     file://45-eth0.network \
-    file://50-wired.network \
     file://50-wireless.network \
-    file://45-eth0.network.sample \
-    file://45-eth1.network.sample \
     "
 
 inherit systemd
@@ -20,18 +17,9 @@ inherit systemd
 SYSTEMD_PACKAGES = "${@bb.utils.contains('DISTRO_FEATURES','systemd','${PN}','',d)}"
 
 do_install() {
-    install -d ${D}${sysconfdir}/systemd/network
-	install -m 644 ${WORKDIR}/45-eth0.network.sample ${D}${sysconfdir}/systemd/network
-	install -m 644 ${WORKDIR}/45-eth1.network.sample ${D}${sysconfdir}/systemd/network
-    
     install -d ${D}${systemd_unitdir}/network
     install -m 644 ${WORKDIR}/45-eth0.network ${D}${systemd_unitdir}/network
-    install -m 644 ${WORKDIR}/50-wired.network ${D}${systemd_unitdir}/network
     install -m 644 ${WORKDIR}/50-wireless.network ${D}${systemd_unitdir}/network
 }
 
-FILES_${PN} = "\
-	${systemd_unitdir}/network \
- 	${systemd_unitdir}/system \
- 	${base_sbindir} \
- 	${sysconfdir}"
+FILES_${PN} = "${systemd_unitdir}/network ${systemd_unitdir}/system ${base_sbindir}"
diff --git a/recipes-core/systemd/systemd-networkd-configuration/45-eth0.network b/recipes-core/systemd/systemd-networkd-configuration/45-eth0.network
index 9809d97b32addd4f30f4f87ba0f558db99b43d44..ae4e1e29f973d2f4dd7679e0a9bdb4ed9b1007bf 100644
--- a/recipes-core/systemd/systemd-networkd-configuration/45-eth0.network
+++ b/recipes-core/systemd/systemd-networkd-configuration/45-eth0.network
@@ -4,7 +4,6 @@ Name=eth0
 KernelCommandLine=!ip
 
 [Network]
-RouteMetric=10
 MulticastDNS=yes
 
 # dhcp configuration
diff --git a/recipes-core/systemd/systemd-networkd-configuration/45-eth0.network.sample b/recipes-core/systemd/systemd-networkd-configuration/45-eth0.network.sample
deleted file mode 100644
index 9809d97b32addd4f30f4f87ba0f558db99b43d44..0000000000000000000000000000000000000000
--- a/recipes-core/systemd/systemd-networkd-configuration/45-eth0.network.sample
+++ /dev/null
@@ -1,17 +0,0 @@
-[Match]
-Name=eth0
-# Leave interface untouched when booting over nfs
-KernelCommandLine=!ip
-
-[Network]
-RouteMetric=10
-MulticastDNS=yes
-
-# dhcp configuration
-DHCP=ipv4
-
-# static configuration
-#Address=192.168.1.239/24
-#Gateway=192.168.1.240
-#DNS=172.17.10.225 172.17.10.221
-
diff --git a/recipes-core/systemd/systemd-networkd-configuration/45-eth1.network.sample b/recipes-core/systemd/systemd-networkd-configuration/45-eth1.network.sample
deleted file mode 100644
index ca94eb765984ca1c5f4a87b96eeb8d55b82ef80b..0000000000000000000000000000000000000000
--- a/recipes-core/systemd/systemd-networkd-configuration/45-eth1.network.sample
+++ /dev/null
@@ -1,15 +0,0 @@
-[Match]
-Name=eth1
-
-[Network]
-# eth0 is the interface with most priority
-RouteMetric=20
-MulticastDNS=yes
-
-# dhcp configuration
-DHCP=ipv4
-
-# static configuration
-#Address=192.168.1.239/24
-#Gateway=192.168.1.240
-#DNS=172.17.10.225 172.17.10.221
diff --git a/recipes-core/systemd/systemd-networkd-configuration/50-wired.network b/recipes-core/systemd/systemd-networkd-configuration/50-wired.network
deleted file mode 100644
index 90642131aa1b998d72b57b20fe206441782bb904..0000000000000000000000000000000000000000
--- a/recipes-core/systemd/systemd-networkd-configuration/50-wired.network
+++ /dev/null
@@ -1,9 +0,0 @@
-[Match]
-Name=eth[1-9]
-
-[Network]
-RouteMetric=15
-MulticastDNS=yes
-
-# dhcp configuration
-DHCP=ipv4
diff --git a/recipes-devtools/sdcard-raw-tools/sdcard-raw-tools.bbappend b/recipes-devtools/sdcard-raw-tools/sdcard-raw-tools.bbappend
deleted file mode 100644
index f3f7a96cc63e5e1f9c0f4f061ac4e85215d3805a..0000000000000000000000000000000000000000
--- a/recipes-devtools/sdcard-raw-tools/sdcard-raw-tools.bbappend
+++ /dev/null
@@ -1,10 +0,0 @@
-FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
-
-# Disable deploy task for nativesdk
-# Else with meta-toolchain-qt5 the recipes
-#   nativesdk-sdcard-raw-toolchain and
-#   sdcard-raw-toolchain-native
-# will install the same file in deploy/images directory, which leads to an error.  
-do_deploy_class-nativesdk() {
-	echo "deploy task disabled for nativesdk"
-}
diff --git a/recipes-devtools/sdcard-raw-tools/sdcard-raw-tools/create_sdcard_from_flashlayout.sh b/recipes-devtools/sdcard-raw-tools/sdcard-raw-tools/create_sdcard_from_flashlayout.sh
deleted file mode 100755
index dcbe37c1e5b2df4a9b396825d9ef66b34e2c4ac7..0000000000000000000000000000000000000000
--- a/recipes-devtools/sdcard-raw-tools/sdcard-raw-tools/create_sdcard_from_flashlayout.sh
+++ /dev/null
@@ -1,839 +0,0 @@
-#!/bin/bash -
-#===============================================================================
-#
-#          FILE: create_sdcard_from_flashlayout.sh
-#
-#         USAGE: ./create_sdcard_from_flashlayout.sh
-#
-#   DESCRIPTION: generate raw image with information from flash layout
-#
-# SPDX-License-Identifier: MIT
-#        AUTHOR: Christophe Priouzeau (christophe.priouzeau@st.com),
-#  ORGANIZATION: STMicroelectronics
-#     COPYRIGHT: Copyright (C) 2017, STMicroelectronics - All Rights Reserved
-#       CREATED: 11/22/2017 15:03
-#      REVISION:  ---
-#===============================================================================
-#TODO: Pre-requisite tools
-# sgdisk
-# du
-# dd
-
-unset FLASHLAYOUT_data
-unset FLASHLAYOUT_filename
-unset FLASHLAYOUT_rawname
-unset FLASHLAYOUT_filename_path
-unset FLASHLAYOUT_prefix_image_path
-unset FLASHLAYOUT_number_of_line
-
-declare -A FLASHLAYOUT_data
-
-SDCARD_TOKEN=mmc0
-
-# Size of 2GB
-#DEFAULT_RAW_SIZE=2048
-# Size of 1.5GB
-#DEFAULT_RAW_SIZE=1536
-# Size of ~1G
-DEFAULT_RAW_SIZE=950
-
-# size of 768MB
-DEFAULT_ROOTFS_PARTITION_SIZE=768432
-# size of 1024MB
-#DEFAULT_ROOTFS_PARTITION_SIZE=1232896
-
-
-# 32 MB of Padding on B
-DEFAULT_PADDING_SIZE=33554432
-
-# Columns name on FLASHLAYOUT_data
-COL_SELECTED_OPT=0
-COL_PARTID=1
-COL_PARTNAME=2
-COL_PARTYPE=3
-COL_IP=4
-COL_OFFSET=5
-COL_BIN2FLASH=6
-COL_BIN2BOOT=7
-
-# SELECTED/OPT variable meaning:
-# - : boot stage
-# P: programme
-# E: erase
-# D: delete
-
-WARNING_TEXT=""
-
-usage() {
-	echo "Usage: $0 <flashlayout>"
-	exit 0
-}
-
-debug() {
-	if [ $DEBUG ];
-	then
-		echo ""
-		echo "[DEBUG]: $@"
-	fi
-}
-
-function exec_print() {
-	if [ $DEBUG ];
-	then
-		echo ""
-		echo "[DEBUG]: $@"
-		$@
-	else
-		$@ 2> /dev/null > /dev/null
-	fi
-}
-
-# Read Flash Layout file and put information on array: FLASHLAYOUT_data
-function read_flash_layout() {
-	local i=0
-	declare -a flashlayout_data     # Create an indexed array (necessary for the read command).
-	FLASHLAYOUT_number_of_line=$(wc -l "$FLASHLAYOUT_filename" | cut -sf 1 -d ' ')
-	debug "Number of line: $FLASHLAYOUT_number_of_line"
-	while read -ra flashlayout_data; do
-		selected=${flashlayout_data[0]}
-		if [ "$selected" == "P" ] || [ "$selected" == "E" ];
-		then
-			# Selected=
-			FLASHLAYOUT_data[$i,$COL_SELECTED_OPT]=${flashlayout_data[0]}
-			# PartId
-			FLASHLAYOUT_data[$i,$COL_PARTID]=${flashlayout_data[1]}
-			#PartName
-			FLASHLAYOUT_data[$i,$COL_PARTNAME]=${flashlayout_data[2]}
-			#PartType
-			FLASHLAYOUT_data[$i,$COL_PARTYPE]=${flashlayout_data[3]}
-			#IP
-			FLASHLAYOUT_data[$i,$COL_IP]=${flashlayout_data[4]}
-			#Offset
-			FLASHLAYOUT_data[$i,$COL_OFFSET]=${flashlayout_data[5]}
-			#Bin2flash
-			FLASHLAYOUT_data[$i,$COL_BIN2FLASH]=${flashlayout_data[6]}
-			#Bin2boot
-			FLASHLAYOUT_data[$i,$COL_BIN2BOOT]=${flashlayout_data[7]}
-
-			i=$(($i+1))
-
-			debug "READ: ${flashlayout_data[0]} ${flashlayout_data[1]} ${flashlayout_data[2]} ${flashlayout_data[3]} ..."
-		fi
-	done < "$FLASHLAYOUT_filename"
-
-	FLASHLAYOUT_number_of_line=$i
-}
-
-function debug_dump_flashlayout_data_array() {
-	columns=8
-	for ((i=0;i<FLASHLAYOUT_number_of_line;i++)) do
-		for ((j=0;j<columns;j++)) do
-			echo -n " ${FLASHLAYOUT_data[$i,$j]}"
-		done
-		echo ""
-	done
-}
-
-# Verify and precise the path to image specified on Flash layout
-function get_last_image_path() {
-	local i=0
-	last_image=""
-	for ((i=0;i<FLASHLAYOUT_number_of_line;i++))
-	do
-		selected=${FLASHLAYOUT_data[$i,$COL_SELECTED_OPT]}
-		ip=${FLASHLAYOUT_data[$i,$COL_IP]}
-		bin2flash=${FLASHLAYOUT_data[$i,$COL_BIN2FLASH]}
-
-		if [ "$ip" == "$SDCARD_TOKEN" ];
-		then
-			case "$selected" in
-			1|P)
-				last_image=$bin2flash
-				;;
-			*)
-				;;
-			esac
-		fi
-		i=$(($i+1))
-	done
-	if [ -n $last_image ];
-	then
-		if [ -f $FLASHLAYOUT_filename_path/$last_image ];
-		then
-			FLASHLAYOUT_prefix_image_path="$FLASHLAYOUT_filename_path"
-		else
-			if [ -f $FLASHLAYOUT_filename_path/../$last_image ];
-			then
-				FLASHLAYOUT_prefix_image_path="$FLASHLAYOUT_filename_path/.."
-			else
-				echo "[ERROR]: do not found image associated to this FLash layout on the directory:"
-				echo "[ERROR]:    $FLASHLAYOUT_filename_path"
-				echo "[ERROR]: or $FLASHLAYOUT_filename_path/.."
-				echo ""
-				exit 0
-			fi
-		fi
-	fi
-}
-
-# -------------------------------
-# calculate number of parition enable
-function calculate_number_of_partition() {
-	num=0
-	for ((i=0;i<FLASHLAYOUT_number_of_line;i++))
-	do
-		selected=${FLASHLAYOUT_data[$i,$COL_SELECTED_OPT]}
-		ip=${FLASHLAYOUT_data[$i,$COL_IP]}
-		if [ "$ip" == "$SDCARD_TOKEN" ]
-		then
-			if [ "$selected" == "P" ] || [ "$selected" == "E" ];
-			then
-				num=$(($num+1))
-			fi
-		fi
-	done
-
-	echo "$num"
-}
-
-# ----------------------------------------
-# move_partition_offset <begin_index_to_change> <new offset_b>
-function move_partition_offset() {
-	ind=$1
-	new_offset=$2
-	offset_hexa=$(printf "%x\n" $new_offset)
-
-	for ((k=$ind;k<FLASHLAYOUT_number_of_line;k++))
-	do
-		selected=${FLASHLAYOUT_data[$k,$COL_SELECTED_OPT]}
-		ip=${FLASHLAYOUT_data[$k,$COL_IP]}
-
-		if [ "$ip" == "$SDCARD_TOKEN" ]
-		then
-			if [ "$selected" == "P" ] || [ "$selected" == "E" ] ;
-			then
-				#calculate actual size of partition (before update)
-				# in case of last partition, we doesn't take care of tmp_next_offset
-				# because there is no other partition to move.
-				tmp_next_offset=${FLASHLAYOUT_data[$(($k+1)),$COL_OFFSET]}
-				tmp_cur_offset=${FLASHLAYOUT_data[$k,$COL_OFFSET]}
-				tmp_partition_size=$(($tmp_next_offset - $tmp_cur_offset))
-
-				#set new offset
-				offset_hexa=$(printf "0x%x\n" $new_offset)
-
-				debug "${FLASHLAYOUT_data[$k,$COL_PARTNAME]}: Change Offset from ${FLASHLAYOUT_data[$k,$COL_OFFSET]}" \
-					" to $offset_hexa"
-				FLASHLAYOUT_data[$k,$COL_OFFSET]=$offset_hexa
-
-				#calculate offset of next partition
-				new_offset=$(($new_offset + $tmp_partition_size))
-			fi
-		fi
-	done
-}
-
-# ----------------------------------------
-function generate_gpt_partition_table_from_flash_layout() {
-	local j=1
-	local p=0
-	local index_of_rootfs=20
-	new_next_partition_offset_b=0
-	number_of_partition=$( calculate_number_of_partition )
-
-	exec_print "sgdisk -og -a 1 $FLASHLAYOUT_rawname"
-
-	echo "Create partition table:"
-
-	for ((i=0;i<FLASHLAYOUT_number_of_line;i++))
-	do
-		selected=${FLASHLAYOUT_data[$i,$COL_SELECTED_OPT]}
-		partId=${FLASHLAYOUT_data[$i,$COL_PARTID]}
-		partName=${FLASHLAYOUT_data[$i,$COL_PARTNAME]}
-		partType=${FLASHLAYOUT_data[$i,$COL_PARTYPE]}
-		ip=${FLASHLAYOUT_data[$i,$COL_IP]}
-		offset=${FLASHLAYOUT_data[$i,$COL_OFFSET]}
-		bin2flash=${FLASHLAYOUT_data[$i,$COL_BIN2FLASH]}
-		debug "DUMP Process for $partName partition"
-
-		case "$selected" in
-		P|E|1)
-			# partition are present and must be created
-			;;
-		*)
-			continue
-			;;
-		esac
-		# add boot flags on gpt parition
-		if [ "$partName" == "bootfs" ];
-		then
-			bootfs_param=" -A $j:set:2"
-		else
-			bootfs_param=""
-		fi
-
-		# get size of image to put on partition
-		if [ -n "$bin2flash" ];
-		then
-			if [ -e $FLASHLAYOUT_prefix_image_path/$bin2flash ];
-			then
-				image_size=$(du -Lb $FLASHLAYOUT_prefix_image_path/$bin2flash | tr '\t' ' ' | cut -d ' ' -f1)
-				image_size_in_mb=$((image_size/1024/1024))
-			else
-				image_size=0
-				image_size_in_mb=0
-			fi
-		else
-			image_size=0
-			image_size_in_mb=0
-		fi
-
-		# get offset
-		offset=$(echo $offset | sed -e "s/0x//")
-		offset_b=$(echo $((16#$offset)) )
-
-		offset=$((2 * $offset_b / 1024))
-
-		if [ $p -ne $(($number_of_partition -1)) ];
-		then
-			# get the begin offset of next partition
-			next_offset=${FLASHLAYOUT_data[$(($i+1)),$COL_OFFSET]}
-			next_offset=$(echo $next_offset | sed -e "s/0x//")
-			next_offset_b=$(echo $((16#$next_offset)))
-			if [ "$partName" == "rootfs" ];
-			then
-				#force the size of rootfs parition to 768MB
-				new_next_partition_offset_b=$(($offset_b + 1024*$DEFAULT_ROOTFS_PARTITION_SIZE))
-				next_offset_b=$new_next_partition_offset_b
-
-				move_partition_offset $(($i+1)) $new_next_partition_offset_b
-				index_of_rootfs=$i
-			fi
-
-			if [ $i -gt $index_of_rootfs ];
-			then
-				if [ $(($next_offset_b + $image_size)) -gt $(($DEFAULT_RAW_SIZE * 1024*1024)) ]
-				then
-					echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
-					echo "[ERROR]: The rootfs and/or other partitions doesn't enter on a SDCARD size of $DEFAULT_RAW_SIZE MB"
-					echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
-					exit 1
-				fi
-			fi
-			next_offset=$((2 * $next_offset_b / 1024))
-			next_offset=$(($next_offset -1))
-			if [ $next_offset -eq -1 ];
-			then
-			next_offset=" "
-			next_offset_b="0"
-			fi
-		else
-			next_offset=" "
-			next_offset_b="0"
-		fi
-
-		# calculate the size of partition
-		partition_size=$(($next_offset_b - $offset_b))
-		if [ $partition_size -lt 0 ];
-		then
-			partition_size=0
-		fi
-
-		if [ $i -ne $(($FLASHLAYOUT_number_of_line -1)) ];
-		then
-			free_size=$(($partition_size - $image_size))
-		else
-			free_size=0
-			partition_size=0
-		fi
-
-		if [ "$ip" == "$SDCARD_TOKEN" ];
-		then
-			debug "   DUMP selected  $selected"
-			#debug "   DUMP partId    $partId"
-			debug "   DUMP partName  $partName"
-			#debug "   DUMP partType  $partType"
-			#debug "   DUMP ip        $ip"
-			debug "   DUMP offset    ${FLASHLAYOUT_data[$i,$COL_OFFSET]} ($offset)"
-			#debug "   DUMP bin2flash $bin2flash"
-			debug "   DUMP image size     $image_size"
-			debug "   DUMP partition size $partition_size"
-			debug "   DUMP free size      $free_size "
-			if [ "$selected" == "P" ] || [ "$selected" == "E" ];
-			then
-				if [ $free_size -lt 0 ];
-				then
-					if [ "$partName" == "rootfs" ];
-					then
-						echo "[WARNING]: IMAGE TOO BIG [$partName:$bin2flash $image_size B [requested $partition_size B]"
-						echo "[WARNING]: try to move last partition"
-						# rootfs are too big for the partition, we increase the size of
-						# partition of real rootfs image size + DEFAULT_PADDING_SIZE
-						new_next_partition_offset_b=$(($offset_b + $image_size + $DEFAULT_PADDING_SIZE))
-
-						move_partition_offset $(($i+1)) $new_next_partition_offset_b
-
-						if [ $new_next_partition_offset_b -gt $(($DEFAULT_RAW_SIZE * 1024*1024)) ]
-						then
-							echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
-							echo "[ERROR]: IMAGE TOO BIG [$partName:$bin2flash $image_size_in_mb MB [requested $partition_size B]"
-							echo "[ERROR]: IMAGE + OFFSET of rootfs partition are superior of SDCARD size ($DEFAULT_RAW_SIZE)"
-							echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
-							exit 1
-						fi
-						next_offset=$((2 * $new_next_partition_offset_b / 1024))
-						next_offset=$(($next_offset -1))
-					else
-						echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
-						echo "[ERROR]: IMAGE TOO BIG [$partName:$bin2flash $image_size_in_mb MB [requested $partition_size B]"
-						echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
-						exit 1
-					fi
-				fi
-
-				if [ $p -eq $(($number_of_partition -1)) ];
-				then
-					temp_end_offset_b=$(($offset_b + $image_size))
-
-					if [ $temp_end_offset_b -gt $(($DEFAULT_RAW_SIZE * 1024*1024)) ];
-					then
-						echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
-						echo "[ERROR]: IMAGE TOO BIG [$partName:$bin2flash $image_size_in_mb MB]"
-						echo "[ERROR]: There is not enough place on last partition($partName)"
-						echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
-						exit 1
-					fi
-				fi
-
-				printf "part %d: %8s ..." $j "$partName"
-				exec_print "sgdisk -a 1 -n $j:$offset:$next_offset -c $j:$partName -t $j:8300 $bootfs_param $FLASHLAYOUT_rawname"
-				partition_size=$(sgdisk -p $FLASHLAYOUT_rawname | grep $partName | awk '{ print $4}')
-				partition_size_type=$(sgdisk -p $FLASHLAYOUT_rawname | grep $partName | awk '{ print $5}')
-				printf "\r[CREATED] part %d: %8s [partition size %s %s]\n" $j "$partName"  "$partition_size" "$partition_size_type"
-
-			j=$(($j+1))
-			fi
-		fi
-		p=$(($p+1))
-	done
-
-	echo ""
-	echo "Partition table from $FLASHLAYOUT_rawname"
-	sgdisk -p $FLASHLAYOUT_rawname
-	echo ""
-}
-
-function generate_empty_raw_image() {
-	# Initialize image file (due to bs we force seek on K)
-	echo "Create Raw empty image: $FLASHLAYOUT_rawname of ${DEFAULT_RAW_SIZE}MB"
-	exec_print "dd if=/dev/zero of=$FLASHLAYOUT_rawname bs=1024 count=0 seek=${DEFAULT_RAW_SIZE}K"
-}
-
-function populate_gpt_partition_table_from_flash_layout() {
-	local i=1
-	local j=1
-	echo "Populate raw image with image content:"
-
-	for ((i=0;i<FLASHLAYOUT_number_of_line;i++))
-	do
-		#debug "DUMP LINE=${FLASHLAYOUT_data[$i]}"
-		selected=${FLASHLAYOUT_data[$i,$COL_SELECTED_OPT]}
-		partId=${FLASHLAYOUT_data[$i,$COL_PARTID]}
-		partName=${FLASHLAYOUT_data[$i,$COL_PARTNAME]}
-		partType=${FLASHLAYOUT_data[$i,$COL_PARTYPE]}
-		ip=${FLASHLAYOUT_data[$i,$COL_IP]}
-		offset=${FLASHLAYOUT_data[$i,$COL_OFFSET]}
-		bin2flash=${FLASHLAYOUT_data[$i,$COL_BIN2FLASH]}
-
-		offset=$(echo $offset | sed -e "s/0x//")
-		offset=$(echo $((16#$offset)))
-
-		debug "   DUMP $selected $partId $partName $partType"
-		if [ "$ip" == "$SDCARD_TOKEN" ];
-		then
-			#debug "   DUMP selected  $selected"
-			#debug "   DUMP partId    $partId"
-			#debug "   DUMP partName  $partName"
-			#debug "   DUMP partType  $partType"
-			#debug "   DUMP ip        $ip"
-			#debug "   DUMP offset    $offset "
-			#debug "   DUMP bin2flash $bin2flash"
-			if [ "$selected" == "P" ];
-			then
-				# Populate only the partition in "P"
-				if [ -e $FLASHLAYOUT_prefix_image_path/$bin2flash ];
-				then
-					printf "part %d: %8s, image: %s ..." $j "$partName" "$bin2flash"
-					exec_print "dd if=$FLASHLAYOUT_prefix_image_path/$bin2flash of=$FLASHLAYOUT_rawname conv=fdatasync,notrunc seek=1 bs=$offset"
-					printf "\r[ FILLED ] part %d: %8s, image: %s \n" $j "$partName" "$bin2flash"
-				else
-					printf "\r[UNFILLED] part %d: %8s, image: %s (not present) \n" $j "$partName" "$bin2flash"
-					echo "   [WARNING]: THE FILE $FLASHLAYOUT_prefix_image_path/$bin2flash ARE NOT PRESENT."
-					echo "   [WARNING]: THE PARTITION $partName ARE NOT FILL."
-					WARNING_TEXT+="[WARNING]: THE PARTITION $partName ARE NOT FILL (file $FLASHLAYOUT_prefix_image_path/$bin2flash are not present) #"
-				fi
-				j=$(($j+1))
-			else
-				if [ "$selected" == "E" ];
-				then
-					printf "\r[UNFILLED] part %d: %8s, \n" $j "$partName"
-					j=$(($j+1))
-				fi
-			fi
-
-		fi
-	done
-}
-
-# ----------------------------------------
-# ----------------------------------------
-function print_shema_on_infofile() {
-	local j=1
-	local i=1
-	# print schema of partition
-	i=1
-	for ((i=0;i<FLASHLAYOUT_number_of_line;i++))
-	do
-		selected=${FLASHLAYOUT_data[$i,$COL_SELECTED_OPT]}
-		ip=${FLASHLAYOUT_data[$i,$COL_IP]}
-		if [ "$ip" == "$SDCARD_TOKEN" ];
-		then
-			if [ "$selected" == "P" ] || [ "$selected" == "E" ];
-			then
-				echo -n "=============" >> $FLASHLAYOUT_infoname
-			fi
-		fi
-	done
-	echo "=" >> $FLASHLAYOUT_infoname
-
-	#empty line
-	for ((i=0;i<FLASHLAYOUT_number_of_line;i++))
-	do
-		selected=${FLASHLAYOUT_data[$i,$COL_SELECTED_OPT]}
-		ip=${FLASHLAYOUT_data[$i,$COL_IP]}
-		if [ "$ip" == "$SDCARD_TOKEN" ];
-		then
-			if [ "$selected" == "P" ] || [ "$selected" == "E" ];
-			then
-				echo -n "=            " >> $FLASHLAYOUT_infoname
-			fi
-		fi
-	done
-	echo "=" >> $FLASHLAYOUT_infoname
-	# part name
-	for ((i=0;i<FLASHLAYOUT_number_of_line;i++))
-	do
-		selected=${FLASHLAYOUT_data[$i,$COL_SELECTED_OPT]}
-		ip=${FLASHLAYOUT_data[$i,$COL_IP]}
-		partName=${FLASHLAYOUT_data[$i,$COL_PARTNAME]}
-		if [ "$ip" == "$SDCARD_TOKEN" ];
-		then
-			if [ "$selected" == "P" ] || [ "$selected" == "E" ];
-			then
-				printf "=  %08s  " "$partName" >> $FLASHLAYOUT_infoname
-			fi
-		fi
-	done
-	echo "=" >> $FLASHLAYOUT_infoname
-	#empty
-	for ((i=0;i<FLASHLAYOUT_number_of_line;i++))
-	do
-		selected=${FLASHLAYOUT_data[$i,$COL_SELECTED_OPT]}
-		ip=${FLASHLAYOUT_data[$i,$COL_IP]}
-		if [ "$ip" == "$SDCARD_TOKEN" ];
-		then
-			if [ "$selected" == "P" ] || [ "$selected" == "E" ];
-			then
-				echo -n "=            " >> $FLASHLAYOUT_infoname
-			fi
-		fi
-	done
-	echo "=" >> $FLASHLAYOUT_infoname
-	# partition number
-	for ((i=0;i<FLASHLAYOUT_number_of_line;i++))
-	do
-		selected=${FLASHLAYOUT_data[$i,$COL_SELECTED_OPT]}
-		ip=${FLASHLAYOUT_data[$i,$COL_IP]}
-		if [ "$ip" == "$SDCARD_TOKEN" ];
-		then
-			if [ "$selected" == "P" ] || [ "$selected" == "E" ];
-			then
-				printf "= %08s%-2d " "mmcblk0p" $j>> $FLASHLAYOUT_infoname
-				j=$(($j+1))
-			fi
-		fi
-	done
-	echo "=" >> $FLASHLAYOUT_infoname
-	j=1
-	for ((i=0;i<FLASHLAYOUT_number_of_line;i++))
-	do
-		selected=${FLASHLAYOUT_data[$i,$COL_SELECTED_OPT]}
-		ip=${FLASHLAYOUT_data[$i,$COL_IP]}
-		if [ "$ip" == "$SDCARD_TOKEN" ];
-		then
-			if [ "$selected" == "P" ] || [ "$selected" == "E" ];
-			then
-				printf "=    (%-2d)    " $j>> $FLASHLAYOUT_infoname
-				j=$(($j+1))
-			fi
-		fi
-	done
-	echo "=" >> $FLASHLAYOUT_infoname
-	for ((i=0;i<FLASHLAYOUT_number_of_line;i++))
-	do
-		selected=${FLASHLAYOUT_data[$i,$COL_SELECTED_OPT]}
-		ip=${FLASHLAYOUT_data[$i,$COL_IP]}
-		if [ "$ip" == "$SDCARD_TOKEN" ];
-		then
-			if [ "$selected" == "P" ] || [ "$selected" == "E" ];
-			then
-				echo -n "=            " >> $FLASHLAYOUT_infoname
-			fi
-		fi
-	done
-	echo "=" >> $FLASHLAYOUT_infoname
-	for ((i=0;i<FLASHLAYOUT_number_of_line;i++))
-	do
-		selected=${FLASHLAYOUT_data[$i,$COL_SELECTED_OPT]}
-		ip=${FLASHLAYOUT_data[$i,$COL_IP]}
-		if [ "$ip" == "$SDCARD_TOKEN" ];
-		then
-			if [ "$selected" == "P" ] || [ "$selected" == "E" ];
-			then
-				echo -n "=============" >> $FLASHLAYOUT_infoname
-			fi
-		fi
-	done
-	echo "=" >> $FLASHLAYOUT_infoname
-	# print legend of partition
-	j=1
-	for ((i=0;i<FLASHLAYOUT_number_of_line;i++))
-	do
-		selected=${FLASHLAYOUT_data[$i,$COL_SELECTED_OPT]}
-		ip=${FLASHLAYOUT_data[$i,$COL_IP]}
-		partName=${FLASHLAYOUT_data[$i,$COL_PARTNAME]}
-		bin2flash=${FLASHLAYOUT_data[$i,$COL_BIN2FLASH]}
-		if [ "$ip" == "$SDCARD_TOKEN" ];
-		then
-			if [ "$selected" == "P" ] || [ "$selected" == "E" ];
-			then
-				echo "($j):" >> $FLASHLAYOUT_infoname
-				echo "    Device: /dev/mmcblk0p$j" >> $FLASHLAYOUT_infoname
-				echo "    Label:  $partName" >> $FLASHLAYOUT_infoname
-				if [ -n "$bin2flash" ];
-				then
-					echo "    Image:  $bin2flash" >> $FLASHLAYOUT_infoname
-				else
-					echo "    Image:" >> $FLASHLAYOUT_infoname
-				fi
-				j=$(($j+1))
-			fi
-		fi
-	done
-}
-
-function print_populate_on_infofile() {
-	local j=1
-	for ((i=0;i<FLASHLAYOUT_number_of_line;i++))
-	do
-		selected=${FLASHLAYOUT_data[$i,$COL_SELECTED_OPT]}
-		ip=${FLASHLAYOUT_data[$i,$COL_IP]}
-		partName=${FLASHLAYOUT_data[$i,$COL_PARTNAME]}
-		bin2flash=${FLASHLAYOUT_data[$i,$COL_BIN2FLASH]}
-		if [ "$ip" == "$SDCARD_TOKEN" ];
-		then
-			if [ "$selected" == "P" ] || [ "$selected" == "E" ];
-			then
-				echo "- Populate partition $partName (/dev/mmcblk0p$j)" >> $FLASHLAYOUT_infoname
-				echo "    dd if=$bin2flash of=/dev/mmcblk0p$j bs=1M conv=fdatasync status=progress" >> $FLASHLAYOUT_infoname
-				echo "" >> $FLASHLAYOUT_infoname
-				j=$(($j+1))
-			fi
-			if [ "$selected" == "E" ];
-			then
-				echo "- Populate partition $partName (/dev/mmcblk0p$j)" >> $FLASHLAYOUT_infoname
-				if [ -n "$bin2flash" ];
-				then
-					echo "    dd if=$bin2flash of=/dev/mmcblk0p$j bs=1M conv=fdatasync status=progress" >> $FLASHLAYOUT_infoname
-				else
-					echo "    dd if=<raw image of $partName> of=/dev/mmcblk0p$j bs=1M conv=fdatasync status=progress" >> $FLASHLAYOUT_infoname
-				fi
-				echo "" >> $FLASHLAYOUT_infoname
-				j=$(($j+1))
-			fi
-		fi
-	done
-}
-
-function create_info() {
-
-cat > $FLASHLAYOUT_infoname  << EOF
-This file describe How to update manually the partition of SDCARD:
-1. SDCARD schema of partition
-2. How to populate each partition
-3. How to update the kernel/devicetree
-
-1. SDCARD schema of partition:
-------------------------------
-
-EOF
-print_shema_on_infofile
-
-cat >> $FLASHLAYOUT_infoname  << EOF
-
-2. How to populate each partition
----------------------------------
-EOF
-
-print_populate_on_infofile
-
-cat >> $FLASHLAYOUT_infoname  << EOF
-
-3. How to update the kernel/devicetree
---------------------------------------
-The kernel and devicetree are present on "bootfs" partition.
-To change kernel and devicetree, you can copy the file on this partitions:
-- plug SDCARD on your PC
-- copy kernel uImage on SDCARD
-   sudo cp uImage /media/\$USER/bootfs/
-- copy devicetree uImage on SDCARD
-   sudo cp stm32mp1*.dtb /media/\$USER/bootfs/
-- umount partitions of SDCARD
-   sudo umount /media/\$USER/bootfs/
-   (dont't forget to umount the other partitions of SDCARD:
-   sudo umount \`lsblk --list | grep mmcblk0 | grep part | gawk '{ print \$7 }' | tr '\\n' ' '\`
-   )
-
-EOF
-
-}
-# ----------------------------------------
-# ----------------------------------------
-
-function print_info() {
-	echo ""
-	echo "###########################################################################"
-	echo "###########################################################################"
-	echo ""
-	echo "RAW IMAGE generated: $FLASHLAYOUT_rawname"
-	echo ""
-	echo "WARNING: before to use the command dd, please umount all the partitions"
-	echo "	associated to SDCARD."
-	echo "    sudo umount \`lsblk --list | grep mmcblk0 | grep part | gawk '{ print \$7 }' | tr '\\n' ' '\`"
-	echo ""
-	echo "To put this raw image on sdcard:"
-	echo "    sudo dd if=$FLASHLAYOUT_rawname of=/dev/mmcblk0 bs=8M conv=fdatasync status=progress"
-	echo ""
-	echo "(mmcblk0 can be replaced by:"
-	echo "     sdX if it's a device dedicated to receive the raw image "
-	echo "          (where X can be a, b, c, d, e)"
-	echo ""
-	echo "###########################################################################"
-	echo "###########################################################################"
-}
-
-function print_warning() {
-	if [ -n "$WARNING_TEXT" ];
-	then
-		echo ""
-		echo "???????????????????????????????????????????????????????????????????????????"
-		echo "???????????????????????????????????????????????????????????????????????????"
-		for t in "`echo $WARNING_TEXT | tr '#' '\n'`";
-		do
-			echo "$t"
-		done
-		echo "[WARNING]: IT'S POSSIBLE, THE BOARD DOES NOT BOOT CORRECTLY DUE TO "
-		echo "           FILE(s) NOT PRESENT."
-		echo "???????????????????????????????????????????????????????????????????????????"
-		echo "???????????????????????????????????????????????????????????????????????????"
-	fi
-}
-
-function usage() {
-	echo ""
-	echo "Help:"
-	echo "   $0 <FlashLayout file>"
-	echo ""
-	exit 1
-}
-# ------------------
-#        Main
-# ------------------
-# check opt args
-if [ $# -ne 1 ];
-then
-	echo "[ERROR]: bad number of parameters"
-	echo ""
-	usage
-else
-	FLASHLAYOUT_filename=$1
-	FLASHLAYOUT_filename_path=$(dirname $FLASHLAYOUT_filename)
-	FLASHLAYOUT_filename_name=$(basename $FLASHLAYOUT_filename)
-	FLASHLAYOUT_dirname=$(basename $FLASHLAYOUT_filename_path)
-
-	_extension="${FLASHLAYOUT_filename##*.}"
-	if [ ! "$_extension" == "tsv" ];
-	then
-		echo ""
-		echo "[ERROR]: bad extension of Flashlayout file."
-		echo "[ERROR]: the flashlayout must have a tsv extension."
-		usage
-	fi
-	# File have a correct extension
-	#
-	if echo $FLASHLAYOUT_dirname | grep -q flashlayout
-	then
-		# add directory name as prefix for raw image
-		new_filename=$(echo "$FLASHLAYOUT_dirname/$FLASHLAYOUT_filename_name" | sed -e "s|/|_|g")
-		filename_for_raw_to_use="$FLASHLAYOUT_filename_path/$new_filename"
-	else
-		filename_for_raw_to_use=$FLASHLAYOUT_filename
-	fi
-	FLASHLAYOUT_rawname=$(basename $filename_for_raw_to_use | sed -e "s/tsv/raw/")
-	FLASHLAYOUT_infoname=$(basename $filename_for_raw_to_use | sed -e "s/tsv/how_to_update.txt/")
-
-	# check if flashlayout have sdcard name
-	if [ $(grep -i $SDCARD_TOKEN $FLASHLAYOUT_filename| wc -l) -eq 0 ];
-	then
-		echo ""
-		echo "[WARNING]: THE FLASHLAYOUT NAME DOES NOT CONTAINS SDCARD REFERENCE."
-		echo "[WARNING]: SDCARD TYPE = $SDCARD_TOKEN"
-		echo "[WARNING]: FILE=$FLASHLAYOUT_filename"
-		echo "Terminated without generated raw file."
-		exit 0
-	fi
-
-	read_flash_layout
-	#debug_dump_flashlayout_data_array
-	get_last_image_path
-
-	#put the raw image generate near the binaries images
-	FLASHLAYOUT_rawname=$FLASHLAYOUT_prefix_image_path/$FLASHLAYOUT_rawname
-	FLASHLAYOUT_infoname=$FLASHLAYOUT_prefix_image_path/$FLASHLAYOUT_infoname
-
-	# erase previous raw image
-	if [ -f $FLASHLAYOUT_rawname ];
-	then
-		echo ""
-		echo "[WARNING]: A previous raw image are present on this directory"
-		echo "[WARNING]:    $FLASHLAYOUT_rawname"
-		echo "[WARNING]: would you like to erase it: [Y/n]"
-		read answer
-		if [[ "$answer" =~ ^[Yy]+[ESes]* ]]; then
-			rm -f $FLASHLAYOUT_rawname $FLASHLAYOUT_infoname
-		fi
-	fi
-
-	debug "DUMP FlashLayout name:      $FLASHLAYOUT_filename"
-	debug "DUMP FlashLayout dir path:  $FLASHLAYOUT_filename_path"
-	debug "DUMP images dir path:       $FLASHLAYOUT_prefix_image_path"
-	debug "DUMP RAW SDCARD image name: $FLASHLAYOUT_rawname"
-fi
-
-generate_empty_raw_image
-generate_gpt_partition_table_from_flash_layout
-populate_gpt_partition_table_from_flash_layout
-
-create_info
-print_info
-print_warning
diff --git a/recipes-exceet/production-tool/files/stm32mp-t1000/prod-env.sh b/recipes-exceet/production-tool/files/stm32mp-t1000/prod-env.sh
new file mode 100755
index 0000000000000000000000000000000000000000..70d5108fd14595d92672c7b2b0b7332f3c4dd437
--- /dev/null
+++ b/recipes-exceet/production-tool/files/stm32mp-t1000/prod-env.sh
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+# DUMMY FILE FOR - stm32mp-t1000
+
+# NOR is mtd0 because "normal" mtd0: NAND is missing
+MTD_UBOOT=/dev/dummy
+MTD_UBOOT_ENV=/dev/dummy
+ROOT_EXT=dummy.ext4
+
+# bootconfiguration
+BOOT_CONFIG=DUMMY
+
+b_flash_emmc=0
+b_flash_ubi=0
+b_lan2_mac_otp=0
diff --git a/recipes-ktn/kontron-demo/kontron-demo_%.bbappend b/recipes-exceet/production-tool/production-tool_%.bbappend
similarity index 100%
rename from recipes-ktn/kontron-demo/kontron-demo_%.bbappend
rename to recipes-exceet/production-tool/production-tool_%.bbappend
diff --git a/recipes-extended/m4-fw-autoload/files/binary/m4_ktn-eval-usart6.elf b/recipes-extended/m4-fw-autoload/files/binary/m4_ktn-eval-usart6.elf
deleted file mode 100755
index d1bf3654f4cccb31b0b6e69110158b3a3cd975d6..0000000000000000000000000000000000000000
Binary files a/recipes-extended/m4-fw-autoload/files/binary/m4_ktn-eval-usart6.elf and /dev/null differ
diff --git a/recipes-extended/m4-fw-autoload/files/binary/m4_ktn-simple-monitor.elf b/recipes-extended/m4-fw-autoload/files/binary/m4_ktn-simple-monitor.elf
deleted file mode 100755
index 0a6b790bec95c488b9263e02a3ec36f01b48c0ee..0000000000000000000000000000000000000000
Binary files a/recipes-extended/m4-fw-autoload/files/binary/m4_ktn-simple-monitor.elf and /dev/null differ
diff --git a/recipes-extended/m4-fw-autoload/files/m4_fw-autoload.conf b/recipes-extended/m4-fw-autoload/files/m4_fw-autoload.conf
deleted file mode 100644
index fbb76f64115017b1c26bc89dcce3da3ece8a33f9..0000000000000000000000000000000000000000
--- a/recipes-extended/m4-fw-autoload/files/m4_fw-autoload.conf
+++ /dev/null
@@ -1,5 +0,0 @@
-# config name of the firmware which will be used
-
-APPLICATION_NAME="m4_ktn-simple-monitor.elf"
-#or
-#APPLICATION_NAME="m4_ktn-eval-usart6.elf"
diff --git a/recipes-extended/m4-fw-autoload/files/m4_fw-autoload.service b/recipes-extended/m4-fw-autoload/files/m4_fw-autoload.service
deleted file mode 100644
index e738fd5fecdeeaa4fb71c898aec32e4650cf7bdd..0000000000000000000000000000000000000000
--- a/recipes-extended/m4-fw-autoload/files/m4_fw-autoload.service
+++ /dev/null
@@ -1,14 +0,0 @@
-[Unit] 
-Description = start stop m4 firmware with name defined in config
-
-
-[Service]
-Type=oneshot
-
-ExecStart=/usr/bin/m4_fw-autoload.sh start
-RemainAfterExit=true
-ExecStop=/usr/bin/m4_fw-autoload.sh stop
-
-[Install]
-WantedBy=multi-user.target
-
diff --git a/recipes-extended/m4-fw-autoload/files/m4_fw-autoload.sh b/recipes-extended/m4-fw-autoload/files/m4_fw-autoload.sh
deleted file mode 100644
index 977b56874b92aa49f8ff87bc9bdf2d9a0c02603a..0000000000000000000000000000000000000000
--- a/recipes-extended/m4-fw-autoload/files/m4_fw-autoload.sh
+++ /dev/null
@@ -1,24 +0,0 @@
-#!/bin/sh
-
-#copy firmware name to remoteproc service and start it
-
-rproc_dir="/sys/class/remoteproc/remoteproc0"
-source_config="/etc/default/m4_fw-autoload.conf"
-
-if [ $1 == "start" ];then
-	if test -f $source_config;then
-		. $source_config
-	fi
-	if test -e /usr/projects/${APPLICATION_NAME}; then
-		cp /usr/projects/$APPLICATION_NAME /lib/firmware
-		echo -n $APPLICATION_NAME > $rproc_dir/firmware
-		echo -n start > $rproc_dir/state
-	else
-		echo "m4_fw-autoload: no application specified"
-	fi
-fi
-
-if [ $1 == "stop" ];then
-	echo -n stop > $rproc_dir/state
-fi
-
diff --git a/recipes-extended/m4-fw-autoload/m4-fw-autoload.bb b/recipes-extended/m4-fw-autoload/m4-fw-autoload.bb
deleted file mode 100644
index d1238293852806e6f6f7ff347d6dc632b1f0d71a..0000000000000000000000000000000000000000
--- a/recipes-extended/m4-fw-autoload/m4-fw-autoload.bb
+++ /dev/null
@@ -1,52 +0,0 @@
-FILESEXTRAPATHS_prepend := "${THISDIR}/files:"
-
-DESCRIPTION = "installs autostart service for m4 firmware "
-
-LICENSE = "GPLv2"
-LIC_FILES_CHKSUM = "file://${COREBASE}/meta/COPYING.GPLv2;md5=751419260aa954499f7abaabaa882bbe"
-
-SRC_URI = "\
-	file://m4_fw-autoload.service \
-	file://m4_fw-autoload.sh \
-	file://m4_fw-autoload.conf \
-	file://binary/m4_ktn-simple-monitor.elf \
-	file://binary/m4_ktn-eval-usart6.elf 	\
-	"
-
-PROJECT_LIST = "m4_ktn-simple-monitor.elf \
-				m4_ktn-eval-usart6.elf	\
-				"
-FILES_${PN} += "/usr/projects/"
-
-S="${WORKDIR}"
-
-SYSTEMD_SERVICE_${PN} = "m4_fw-autoload.service"
-
-INITSCRIPT_NAME = "m4_fw-autoload.sh"
-INITSCRIPT_PARAMS = "start 99 5 2 . stop 20 0 1 6 ."
-
-inherit update-rc.d systemd
-
-#FILES_${PN} = "${bindir}/*"
-
-do_install () {
-	#binary files
-	install -d ${D}${prefix}${USERFS_ROOTPATH}/projects/
-	for project in ${PROJECT_LIST} ; do
-		install -m 0755 ${WORKDIR}/binary/${project} ${D}${prefix}${USERFS_ROOTPATH}/projects/
-	done
-	
-	install -Dm 0644 ${WORKDIR}/m4_fw-autoload.conf ${D}${sysconfdir}/default/m4_fw-autoload.conf
-	#systemd vs initscript 
-	if ${@bb.utils.contains('DISTRO_FEATURES', 'systemd', 'true', 'false', d)};then
-		install -Dm 0644 ${WORKDIR}/m4_fw-autoload.service ${D}${systemd_system_unitdir}/m4_fw-autoload.service
-    	install -Dm 0755 ${WORKDIR}/m4_fw-autoload.sh ${D}${bindir}/m4_fw-autoload.sh
-    	
-	else
-		install -d ${D}${sysconfdir}/init.d/
-		install -c -m 755 ${WORKDIR}/${INITSCRIPT_NAME} ${D}${sysconfdir}/init.d/${INITSCRIPT_NAME}
-		
-	fi
-}
-
-
diff --git a/recipes-graphics/gcnano-userland/gcnano-userland-multi-binary-stm32mp.bbappend b/recipes-graphics/gcnano-userland/gcnano-userland-multi-binary-stm32mp.bbappend
index aaa4b4e68fdc23aa80f9316399e9efe6fc7753c1..9222e93f2d3a09cfed3f1c64dfa37d9fde2b3020 100644
--- a/recipes-graphics/gcnano-userland/gcnano-userland-multi-binary-stm32mp.bbappend
+++ b/recipes-graphics/gcnano-userland/gcnano-userland-multi-binary-stm32mp.bbappend
@@ -23,16 +23,3 @@
 
 DEPENDS_remove = "gcnano-driver-stm32mp"
 RDEPENDS_${PN} += " gcnano-driver-stm32mp"
-
-#DEPENDS_remove += "${@bb.utils.contains('DISTRO_FEATURES', 'wayland', '', 'wayland', d)}"
-
-# Remove libwayland libraries even if GCNANO_USERLAND_USE_VENDOR_DIR is set to zero. This is a bug
-# in OpenST layers.
-do_install_append (){
-    # remove remove libwayland-egl which are now provided by wayland
-    if test -f ${D}${GCNANO_USERLAND_OUTPUT_LIBDIR}/libwayland-egl.so ;
-    then
-        rm ${D}${GCNANO_USERLAND_OUTPUT_LIBDIR}/libwayland-egl.so*
-        rm ${D}${libdir}/pkgconfig/wayland-egl.pc
-    fi
-}
diff --git a/recipes-graphics/wayland/weston/0001-compositor-drm-Make-scanout-view-preparation-more-st.patch b/recipes-graphics/wayland/weston/0001-compositor-drm-Make-scanout-view-preparation-more-st.patch
new file mode 100644
index 0000000000000000000000000000000000000000..6ab87ae4eae6408f45a6c9632936dc2982e3e1fa
--- /dev/null
+++ b/recipes-graphics/wayland/weston/0001-compositor-drm-Make-scanout-view-preparation-more-st.patch
@@ -0,0 +1,99 @@
+From 1efdfb8b9a53114da0c75efca009782d1f1b530d Mon Sep 17 00:00:00 2001
+From: Daniel Stone <daniels@collabora.com>
+Date: Fri, 21 Oct 2016 18:08:37 +0100
+Subject: [PATCH] compositor-drm: Make scanout view preparation more stringent
+
+Don't import buffers which span multiple outputs, short-cut any attempt
+to import SHM buffers, and ignore buffers with a global alpha set.
+
+I'm not convinced all of these conditions entirely make sense, but this
+at least makes them equally nonsensical.
+
+Differential Revision: https://phabricator.freedesktop.org/D1414
+
+Signed-off-by: Daniel Stone <daniels@collabora.com>
+Reviewed-by: Derek Foreman <derekf@osg.samsung.com>
+---
+ libweston/compositor-drm.c | 35 ++++++++++++++++++++++++-----------
+ 1 file changed, 24 insertions(+), 11 deletions(-)
+
+diff --git a/libweston/compositor-drm.c b/libweston/compositor-drm.c
+index 1d38f05..6425011 100644
+--- a/libweston/compositor-drm.c
++++ b/libweston/compositor-drm.c
+@@ -499,6 +499,13 @@ drm_output_release_fb(struct drm_output *output, struct drm_fb *fb)
+ 	}
+ }
+ 
++static int
++drm_view_transform_supported(struct weston_view *ev)
++{
++	return !ev->transform.enabled ||
++		(ev->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
++}
++
+ static uint32_t
+ drm_output_check_scanout_format(struct drm_output *output,
+ 				struct weston_surface *es, struct gbm_bo *bo)
+@@ -539,27 +546,40 @@ drm_output_prepare_scanout_view(struct drm_output *output,
+ 	struct gbm_bo *bo;
+ 	uint32_t format;
+ 
++	/* Don't import buffers which span multiple outputs. */
++	if (ev->output_mask != (1u << output->base.id))
++		return NULL;
++
+ 	/* We use GBM to import buffers. */
+ 	if (b->gbm == NULL)
+ 		return NULL;
+ 
+ 	if (buffer == NULL)
+ 		return NULL;
++	if (wl_shm_buffer_get(buffer->resource))
++		return NULL;
+ 
+ 	/* Make sure our view is exactly compatible with the output. */
+ 	if (ev->geometry.x != output->base.x ||
+ 	    ev->geometry.y != output->base.y)
+ 		return NULL;
++	if (buffer->width != output->base.current_mode->width ||
++	    buffer->height != output->base.current_mode->height)
++		return NULL;
++
+ 	if (ev->transform.enabled)
+ 		return NULL;
+ 	if (ev->geometry.scissor_enabled)
+ 		return NULL;
+-
+-	if (buffer->width != output->base.current_mode->width ||
+-	    buffer->height != output->base.current_mode->height)
+-		return NULL;
+ 	if (viewport->buffer.transform != output->base.transform)
+ 		return NULL;
++	if (viewport->buffer.scale != output->base.current_scale)
++		return NULL;
++	if (!drm_view_transform_supported(ev))
++		return NULL;
++
++	if (ev->alpha != 1.0f)
++		return NULL;
+ 
+ 	bo = gbm_bo_import(b->gbm, GBM_BO_IMPORT_WL_BUFFER,
+ 			   buffer->resource, GBM_BO_USE_SCANOUT);
+@@ -973,13 +993,6 @@ drm_output_check_sprite_format(struct drm_sprite *s,
+ 	return 0;
+ }
+ 
+-static int
+-drm_view_transform_supported(struct weston_view *ev)
+-{
+-	return !ev->transform.enabled ||
+-		(ev->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
+-}
+-
+ static struct weston_plane *
+ drm_output_prepare_overlay_view(struct drm_output *output,
+ 				struct weston_view *ev)
+-- 
+2.7.4
+
diff --git a/recipes-graphics/wayland/weston_2.0.0.bbappend b/recipes-graphics/wayland/weston_2.0.0.bbappend
new file mode 100644
index 0000000000000000000000000000000000000000..5a4ac65155d898c06d82eea5b6f9cebff0c90472
--- /dev/null
+++ b/recipes-graphics/wayland/weston_2.0.0.bbappend
@@ -0,0 +1,4 @@
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
+
+SRC_URI += "file://0001-compositor-drm-Make-scanout-view-preparation-more-st.patch"
+
diff --git a/recipes-kernel/linux/fetch_files_workdir.sh b/recipes-kernel/linux/fetch_files_workdir.sh
new file mode 100755
index 0000000000000000000000000000000000000000..946bbbdebb8e9a6442700b6c522f348be152a18c
--- /dev/null
+++ b/recipes-kernel/linux/fetch_files_workdir.sh
@@ -0,0 +1,94 @@
+#!/bin/bash
+
+# fetch_files_workdir <DEVTOOL_WORKDIR>
+
+FILELIST="\
+	arch/arm/boot/dts/stmxceet-mp157-som.dts \
+	arch/arm/boot/dts/stmxceet-mp157-som-spl.dts \
+	arch/arm/boot/dts/stmxceet-mp157-som_pinctrl.dtsi \
+	"
+
+PATCHDIR="linux-stm32mp"
+
+red=`tput setaf 1`
+green=`tput setaf 2`
+yellow=`tput setaf 3`
+reset=`tput sgr0`
+
+DEVTOOL_WORKDIR=${1}
+COMMAND=${2}
+
+print_usage ()
+{
+	echo "fetch_files_workdir <DEVTOOL_WORKDIR> [diff]"
+}
+
+echo "$1"
+if test -z "${DEVTOOL_WORKDIR}"; then
+	print_usage
+	echo -n $red
+	echo "ERROR: No workdir on commandline"
+	echo -n $reset
+	exit 1
+fi
+if test ! -d "${DEVTOOL_WORKDIR}"; then
+	echo -n $red
+	echo "ERROR: Workdir <${DEVTOOL_WORKDIR}> doesn't exist"
+	echo -n $reset
+	exit 1
+fi
+
+# COMMAND configuration
+if test ! -z "${COMMAND}"; then
+	echo "Command: ${COMMAND}"
+fi
+do_onlydiff="no"
+if test "${COMMAND}" == "diff"; then
+	do_onlydiff="yes"
+fi
+
+for wdfile in ${FILELIST}; do
+	file_differ="no"
+	filename=$(basename $wdfile)
+	if test ! -e ${PATCHDIR}/${filename}; then
+		echo -n $yellow
+		echo "new      : $filename (${PATCHDIR}/${filename})"
+		echo -n $reset
+		file_differ="yes"
+	else
+		cmp -s ${DEVTOOL_WORKDIR}/${wdfile} ${PATCHDIR}/${filename}
+		if test $? != 0; then
+			echo -n $red
+			echo "differ   : $filename)"
+			echo -n $reset
+			file_differ="yes"
+		else
+			echo -n $green
+			echo "unchanged: $filename"
+			echo -n $reset
+		fi
+	fi
+	
+	if test ${file_differ} = "yes" -a ${do_onlydiff} != "yes" ; then
+	
+		echo "Show differences [Y/n]?"
+		read show_diff
+		if test -z "${show_diff}"; then
+			show_diff="Y"
+		fi
+		if test "${show_diff}" == "Y" -o ${show_diff} == "y"; then
+			meld ${DEVTOOL_WORKDIR}/${wdfile} ${PATCHDIR}/${filename}
+		fi
+				
+		echo "Copy files [y/N]?"
+		read copy_files
+		if test -z "${copy_files}"; then
+			copy_files="N"
+		fi
+		if test "${copy_files}" == "y" -o "${copy_files}" == "y"; then
+			cp ${DEVTOOL_WORKDIR}/${wdfile} ${PATCHDIR}/${filename}
+		fi
+	fi
+
+done
+
diff --git a/recipes-kernel/linux/linux-stm32mp/4.14/defconfig b/recipes-kernel/linux/linux-stm32mp/4.14/defconfig
new file mode 100644
index 0000000000000000000000000000000000000000..d8220f352e9465519e780ceaa33daff9bfc8b048
--- /dev/null
+++ b/recipes-kernel/linux/linux-stm32mp/4.14/defconfig
@@ -0,0 +1,542 @@
+CONFIG_SYSVIPC=y
+CONFIG_USELIB=y
+CONFIG_IRQ_DOMAIN_DEBUG=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_TASKSTATS=y
+CONFIG_TASK_DELAY_ACCT=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=16
+CONFIG_CGROUPS=y
+CONFIG_BLK_CGROUP=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CPUSETS=y
+CONFIG_CGROUP_DEVICE=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_CGROUP_DEBUG=y
+CONFIG_CHECKPOINT_RESTORE=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_EMBEDDED=y
+CONFIG_PROFILING=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_CMDLINE_PARTITION=y
+CONFIG_ARCH_STM32=y
+CONFIG_ARM_THUMBEE=y
+# CONFIG_CACHE_L2X0 is not set
+CONFIG_ARM_ERRATA_430973=y
+CONFIG_ARM_ERRATA_720789=y
+CONFIG_ARM_ERRATA_754322=y
+CONFIG_ARM_ERRATA_754327=y
+CONFIG_ARM_ERRATA_764369=y
+CONFIG_ARM_ERRATA_775420=y
+CONFIG_ARM_ERRATA_798181=y
+CONFIG_SMP=y
+CONFIG_MCPM=y
+CONFIG_PREEMPT=y
+CONFIG_HIGHMEM=y
+CONFIG_CMA=y
+CONFIG_FORCE_MAX_ZONEORDER=12
+CONFIG_SECCOMP=y
+# CONFIG_ATAGS is not set
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_ARM_APPENDED_DTB=y
+CONFIG_ARM_ATAG_DTB_COMPAT=y
+CONFIG_VFP=y
+CONFIG_NEON=y
+CONFIG_KERNEL_MODE_NEON=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_IPCOMP=m
+CONFIG_IPV6_MIP6=m
+CONFIG_IPV6_TUNNEL=m
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_NET_DSA=m
+CONFIG_CAN=y
+CONFIG_CAN_M_CAN=y
+CONFIG_BT=m
+CONFIG_BT_MRVL=m
+CONFIG_BT_MRVL_SDIO=m
+CONFIG_CFG80211=m
+CONFIG_MAC80211=m
+CONFIG_RFKILL=y
+CONFIG_RFKILL_INPUT=y
+CONFIG_RFKILL_GPIO=y
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_DMA_CMA=y
+CONFIG_CMA_SIZE_MBYTES=128
+CONFIG_BRCMSTB_GISB_ARB=y
+CONFIG_SIMPLE_PM_BUS=y
+CONFIG_VEXPRESS_CONFIG=y
+CONFIG_MTD=y
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_BLOCK=y
+CONFIG_MTD_M25P80=y
+CONFIG_MTD_NAND=y
+CONFIG_MTD_NAND_DENALI_DT=y
+CONFIG_MTD_NAND_BRCMNAND=y
+CONFIG_MTD_NAND_STM32_FMC=y
+CONFIG_MTD_SPI_NOR=y
+CONFIG_SPI_STM32_QUADSPI=y
+CONFIG_MTD_UBI=y
+CONFIG_OF_OVERLAY=y
+CONFIG_OF_CONFIGFS=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=65536
+CONFIG_VIRTIO_BLK=y
+CONFIG_AD525X_DPOT=y
+CONFIG_AD525X_DPOT_I2C=y
+CONFIG_ICS932S401=y
+CONFIG_APDS9802ALS=y
+CONFIG_ISL29003=y
+CONFIG_SRAM=y
+CONFIG_EEPROM_AT24=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_BLK_DEV_SR=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_ATA=y
+CONFIG_SATA_AHCI_PLATFORM=y
+CONFIG_NETDEVICES=y
+CONFIG_VIRTIO_NET=y
+CONFIG_B53_SPI_DRIVER=m
+CONFIG_B53_MDIO_DRIVER=m
+CONFIG_B53_MMAP_DRIVER=m
+CONFIG_B53_SRAB_DRIVER=m
+CONFIG_NET_DSA_BCM_SF2=m
+CONFIG_MACB=y
+CONFIG_BCMGENET=m
+CONFIG_SYSTEMPORT=m
+CONFIG_HIX5HD2_GMAC=y
+CONFIG_MVMDIO=y
+CONFIG_KS8851=y
+CONFIG_SMSC911X=y
+CONFIG_STMMAC_ETH=y
+CONFIG_DWMAC_DWC_QOS_ETH=y
+CONFIG_MDIO_BITBANG=y
+CONFIG_AT803X_PHY=y
+CONFIG_BROADCOM_PHY=y
+CONFIG_ICPLUS_PHY=y
+CONFIG_MARVELL_PHY=y
+CONFIG_MICREL_PHY=y
+CONFIG_REALTEK_PHY=y
+CONFIG_ROCKCHIP_PHY=y
+CONFIG_SMSC_PHY=y
+CONFIG_SLIP=y
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_USB_PEGASUS=y
+CONFIG_USB_RTL8152=m
+CONFIG_USB_USBNET=y
+CONFIG_USB_NET_SMSC75XX=y
+CONFIG_USB_NET_SMSC95XX=y
+CONFIG_BRCMFMAC=m
+CONFIG_MWIFIEX=m
+CONFIG_MWIFIEX_SDIO=m
+CONFIG_RT2X00=m
+CONFIG_RT2800USB=m
+CONFIG_INPUT_JOYDEV=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_KEYBOARD_QT1070=m
+CONFIG_KEYBOARD_GPIO=y
+CONFIG_KEYBOARD_SAMSUNG=m
+CONFIG_KEYBOARD_CROS_EC=m
+CONFIG_KEYBOARD_BCM=y
+CONFIG_MOUSE_PS2_ELANTECH=y
+CONFIG_MOUSE_CYAPA=m
+CONFIG_MOUSE_ELAN_I2C=y
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ATMEL_MXT=m
+CONFIG_TOUCHSCREEN_MMS114=m
+CONFIG_TOUCHSCREEN_ST1232=m
+CONFIG_TOUCHSCREEN_STMPE=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_MAX77693_HAPTIC=m
+CONFIG_INPUT_MAX8997_HAPTIC=m
+CONFIG_INPUT_AXP20X_PEK=m
+CONFIG_INPUT_ADXL34X=m
+CONFIG_INPUT_STPMU1_ONKEY=y
+CONFIG_SERIAL_NONSTANDARD=y
+CONFIG_SERIAL_STM32=y
+CONFIG_SERIAL_STM32_CONSOLE=y
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_STM32=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_ARB_GPIO_CHALLENGE=m
+CONFIG_I2C_MUX_PCA954x=y
+CONFIG_I2C_MUX_PINCTRL=y
+CONFIG_I2C_DEMUX_PINCTRL=y
+CONFIG_I2C_STM32F7=y
+CONFIG_I2C_CROS_EC_TUNNEL=m
+CONFIG_SPI=y
+CONFIG_SPI_CADENCE=y
+CONFIG_SPI_GPIO=m
+CONFIG_SPI_ROCKCHIP=m
+CONFIG_SPI_STM32=y
+CONFIG_SPI_XILINX=y
+CONFIG_SPI_SPIDEV=y
+CONFIG_SPMI=y
+CONFIG_PINCTRL_AS3722=y
+CONFIG_PINCTRL_SINGLE=y
+CONFIG_PINCTRL_PALMAS=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_DWAPB=y
+CONFIG_GPIO_SYSCON=y
+CONFIG_GPIO_XILINX=y
+CONFIG_GPIO_PALMAS=y
+CONFIG_GPIO_ST_MFX=y
+CONFIG_GPIO_TPS6586X=y
+CONFIG_GPIO_TPS65910=y
+CONFIG_GPIO_TWL4030=y
+CONFIG_POWER_RESET=y
+CONFIG_POWER_RESET_AS3722=y
+CONFIG_POWER_RESET_BRCMKONA=y
+CONFIG_POWER_RESET_BRCMSTB=y
+CONFIG_POWER_RESET_GPIO=y
+CONFIG_POWER_RESET_GPIO_RESTART=y
+CONFIG_POWER_RESET_VEXPRESS=y
+CONFIG_POWER_RESET_SYSCON=y
+CONFIG_POWER_RESET_SYSCON_POWEROFF=y
+# CONFIG_HWMON is not set
+CONFIG_WATCHDOG=y
+CONFIG_DA9063_WATCHDOG=m
+CONFIG_XILINX_WATCHDOG=y
+CONFIG_DW_WATCHDOG=y
+CONFIG_STPMU1_WATCHDOG=y
+CONFIG_BCMA=y
+CONFIG_BCMA_HOST_SOC=y
+CONFIG_BCMA_DRIVER_GMAC_CMN=y
+CONFIG_BCMA_DRIVER_GPIO=y
+CONFIG_MFD_ACT8945A=y
+CONFIG_MFD_AS3711=y
+CONFIG_MFD_AS3722=y
+CONFIG_MFD_ATMEL_FLEXCOM=y
+CONFIG_MFD_ATMEL_HLCDC=m
+CONFIG_MFD_BCM590XX=y
+CONFIG_MFD_AXP20X_I2C=y
+CONFIG_MFD_CROS_EC=m
+CONFIG_MFD_CROS_EC_I2C=m
+CONFIG_MFD_CROS_EC_SPI=m
+CONFIG_MFD_DA9063=m
+CONFIG_MFD_MAX14577=y
+CONFIG_MFD_MAX77686=y
+CONFIG_MFD_MAX77693=m
+CONFIG_MFD_MAX8907=y
+CONFIG_MFD_MAX8997=y
+CONFIG_MFD_MAX8998=y
+CONFIG_MFD_PM8XXX=y
+CONFIG_MFD_RK808=y
+CONFIG_MFD_SEC_CORE=y
+CONFIG_ABX500_CORE=y
+CONFIG_MFD_STMPE=y
+CONFIG_MFD_PALMAS=y
+CONFIG_MFD_TPS65090=y
+CONFIG_MFD_TPS65217=y
+CONFIG_MFD_TPS65218=y
+CONFIG_MFD_TPS6586X=y
+CONFIG_MFD_TPS65910=y
+CONFIG_TWL4030_CORE=y
+CONFIG_TWL4030_POWER=y
+CONFIG_MFD_WM8994=y
+CONFIG_MFD_STM32_LPTIMER=y
+CONFIG_MFD_ST_MFX=y
+CONFIG_MFD_STPMU1=y
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_REGULATOR_ACT8865=y
+CONFIG_REGULATOR_ACT8945A=y
+CONFIG_REGULATOR_ANATOP=y
+CONFIG_REGULATOR_AS3711=y
+CONFIG_REGULATOR_AS3722=y
+CONFIG_REGULATOR_AXP20X=y
+CONFIG_REGULATOR_BCM590XX=y
+CONFIG_REGULATOR_DA9210=y
+CONFIG_REGULATOR_FAN53555=y
+CONFIG_REGULATOR_GPIO=y
+CONFIG_REGULATOR_LP872X=y
+CONFIG_REGULATOR_MAX14577=m
+CONFIG_REGULATOR_MAX8907=y
+CONFIG_REGULATOR_MAX8997=m
+CONFIG_REGULATOR_MAX8998=m
+CONFIG_REGULATOR_MAX77686=y
+CONFIG_REGULATOR_MAX77693=m
+CONFIG_REGULATOR_MAX77802=m
+CONFIG_REGULATOR_PALMAS=y
+CONFIG_REGULATOR_PWM=y
+CONFIG_REGULATOR_RK808=y
+CONFIG_REGULATOR_S2MPS11=y
+CONFIG_REGULATOR_S5M8767=y
+CONFIG_REGULATOR_STM32_VREFBUF=y
+CONFIG_REGULATOR_STM32_PWR=y
+CONFIG_REGULATOR_STPMU1=y
+CONFIG_REGULATOR_TPS51632=y
+CONFIG_REGULATOR_TPS62360=y
+CONFIG_REGULATOR_TPS65090=y
+CONFIG_REGULATOR_TPS65217=y
+CONFIG_REGULATOR_TPS65218=y
+CONFIG_REGULATOR_TPS6586X=y
+CONFIG_REGULATOR_TPS65910=y
+CONFIG_REGULATOR_TWL4030=y
+CONFIG_REGULATOR_VEXPRESS=y
+CONFIG_REGULATOR_WM8994=m
+CONFIG_MEDIA_SUPPORT=m
+CONFIG_MEDIA_CAMERA_SUPPORT=y
+CONFIG_MEDIA_CEC_SUPPORT=y
+CONFIG_MEDIA_CONTROLLER=y
+CONFIG_VIDEO_V4L2_SUBDEV_API=y
+CONFIG_MEDIA_USB_SUPPORT=y
+CONFIG_USB_VIDEO_CLASS=m
+CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_VIDEO_STM32_DCMI=m
+CONFIG_SOC_CAMERA=m
+CONFIG_SOC_CAMERA_PLATFORM=m
+CONFIG_V4L_MEM2MEM_DRIVERS=y
+CONFIG_V4L_TEST_DRIVERS=y
+CONFIG_VIDEO_VIVID=m
+CONFIG_CEC_PLATFORM_DRIVERS=y
+CONFIG_VIDEO_STM32_HDMI_CEC=m
+# CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set
+CONFIG_VIDEO_ADV7180=m
+CONFIG_VIDEO_ML86V7667=m
+CONFIG_VIDEO_OV5640=m
+CONFIG_DRM=y
+CONFIG_DRM_EXYNOS=m
+CONFIG_DRM_EXYNOS_FIMD=y
+CONFIG_DRM_EXYNOS_MIXER=y
+CONFIG_DRM_EXYNOS_DPI=y
+CONFIG_DRM_EXYNOS_DSI=y
+CONFIG_DRM_EXYNOS_HDMI=y
+CONFIG_DRM_ATMEL_HLCDC=m
+CONFIG_DRM_STM=y
+CONFIG_DRM_STM_DSI=y
+CONFIG_DRM_PANEL_SIMPLE=y
+CONFIG_DRM_PANEL_SAMSUNG_LD9040=m
+CONFIG_DRM_PANEL_RAYDIUM_RM68200=y
+CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0=m
+CONFIG_DRM_DUMB_VGA_DAC=m
+CONFIG_DRM_NXP_PTN3460=m
+CONFIG_DRM_PARADE_PS8622=m
+CONFIG_DRM_I2C_ADV7511=y
+CONFIG_DRM_I2C_ADV7511_AUDIO=y
+CONFIG_DRM_STI=m
+CONFIG_FB_MODE_HELPERS=y
+CONFIG_FB_SIMPLE=y
+CONFIG_LCD_CLASS_DEVICE=y
+CONFIG_LCD_PLATFORM=m
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_BACKLIGHT_PWM=y
+CONFIG_BACKLIGHT_AS3711=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_DYNAMIC_MINORS=y
+CONFIG_SND_USB_AUDIO=m
+CONFIG_SND_SOC=y
+CONFIG_SND_ATMEL_SOC=m
+CONFIG_SND_SOC_FSL_SAI=m
+CONFIG_SND_SOC_STM32_SAI=y
+CONFIG_SND_SOC_STM32_I2S=y
+CONFIG_SND_SOC_STM32_SPDIFRX=m
+CONFIG_SND_SOC_AK4642=m
+CONFIG_SND_SOC_DMIC=y
+CONFIG_SND_SOC_SGTL5000=m
+CONFIG_SND_SOC_SPDIF=y
+CONFIG_SND_SOC_STI_SAS=m
+CONFIG_SND_SOC_TLV320AIC23_I2C=m
+CONFIG_SND_SOC_TS3A227E=m
+CONFIG_SND_SOC_WM8753=m
+CONFIG_SND_SOC_WM8903=m
+CONFIG_SND_SOC_WM8978=m
+CONFIG_SND_SOC_WM8994=y
+CONFIG_SND_SIMPLE_CARD=m
+CONFIG_SND_SIMPLE_SCU_CARD=m
+CONFIG_SND_AUDIO_GRAPH_CARD=y
+CONFIG_USB=y
+CONFIG_USB_XHCI_HCD=y
+CONFIG_USB_XHCI_PLATFORM=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_HCD_PLATFORM=y
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_OHCI_HCD_PLATFORM=y
+CONFIG_USB_R8A66597_HCD=m
+CONFIG_USB_ACM=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_UAS=y
+CONFIG_USB_DWC2=y
+CONFIG_USB_CHIPIDEA=y
+CONFIG_USB_CHIPIDEA_UDC=y
+CONFIG_USB_CHIPIDEA_HOST=y
+CONFIG_USB_ISP1760=y
+CONFIG_USB_GPIO_VBUS=y
+CONFIG_USB_ISP1301=y
+CONFIG_USB_ULPI=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_SNP_UDC_PLAT=y
+CONFIG_USB_BDC_UDC=y
+CONFIG_USB_CONFIGFS=y
+CONFIG_USB_CONFIGFS_MASS_STORAGE=y
+CONFIG_USB_CONFIGFS_F_LB_SS=y
+CONFIG_USB_CONFIGFS_F_FS=y
+CONFIG_USB_CONFIGFS_F_HID=y
+CONFIG_USB_ZERO=m
+CONFIG_USB_ETH=m
+CONFIG_USB_MASS_STORAGE=m
+CONFIG_USB_G_HID=m
+CONFIG_MMC=y
+CONFIG_MMC_BLOCK_MINORS=16
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_MMC_SDHCI_OF_ARASAN=y
+CONFIG_MMC_SDHCI_OF_AT91=y
+CONFIG_MMC_DW=y
+CONFIG_MMC_DW_EXYNOS=y
+CONFIG_MMC_STM32_SDMMC=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_CLASS_FLASH=m
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_PWM=y
+CONFIG_LEDS_MAX77693=m
+CONFIG_LEDS_MAX8997=m
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_LEDS_TRIGGER_ONESHOT=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_LEDS_TRIGGER_BACKLIGHT=y
+CONFIG_LEDS_TRIGGER_CPU=y
+CONFIG_LEDS_TRIGGER_GPIO=y
+CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
+CONFIG_LEDS_TRIGGER_TRANSIENT=y
+CONFIG_LEDS_TRIGGER_CAMERA=y
+CONFIG_EDAC=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_AS3722=y
+CONFIG_RTC_DRV_DS1307=y
+CONFIG_RTC_DRV_HYM8563=m
+CONFIG_RTC_DRV_MAX8907=y
+CONFIG_RTC_DRV_MAX8998=m
+CONFIG_RTC_DRV_MAX8997=m
+CONFIG_RTC_DRV_MAX77686=y
+CONFIG_RTC_DRV_RK808=m
+CONFIG_RTC_DRV_RS5C372=m
+CONFIG_RTC_DRV_TWL4030=y
+CONFIG_RTC_DRV_PALMAS=y
+CONFIG_RTC_DRV_TPS6586X=y
+CONFIG_RTC_DRV_TPS65910=y
+CONFIG_RTC_DRV_S35390A=m
+CONFIG_RTC_DRV_RX8581=m
+CONFIG_RTC_DRV_EM3027=y
+CONFIG_RTC_DRV_S5M=m
+CONFIG_RTC_DRV_DA9063=m
+CONFIG_RTC_DRV_STM32=y
+CONFIG_DMADEVICES=y
+CONFIG_FSL_EDMA=y
+CONFIG_STM32_DMA=y
+CONFIG_STM32_DMAMUX=y
+CONFIG_STM32_MDMA=y
+CONFIG_DW_DMAC=y
+CONFIG_VIRTIO_MMIO=y
+CONFIG_CROS_EC_CHARDEV=m
+CONFIG_COMMON_CLK_MAX77686=y
+CONFIG_COMMON_CLK_RK808=m
+CONFIG_COMMON_CLK_S2MPS11=m
+CONFIG_CLK_QORIQ=y
+CONFIG_ARM_TIMER_SP804=y
+CONFIG_MAILBOX_TEST=y
+CONFIG_STM32_IPCC=y
+# CONFIG_IOMMU_SUPPORT is not set
+CONFIG_REMOTEPROC=y
+CONFIG_STM32_RPROC=y
+CONFIG_RPMSG_TTY=y
+CONFIG_IIO=y
+CONFIG_IIO_SW_TRIGGER=y
+CONFIG_STM32_ADC_CORE=y
+CONFIG_STM32_ADC=y
+CONFIG_VF610_ADC=m
+CONFIG_STM32_LPTIMER_CNT=y
+CONFIG_STM32_DAC=y
+CONFIG_MPU3050_I2C=y
+CONFIG_CM36651=m
+CONFIG_SENSORS_ISL29018=y
+CONFIG_SENSORS_ISL29028=y
+CONFIG_AK8975=y
+CONFIG_IIO_HRTIMER_TRIGGER=y
+CONFIG_IIO_STM32_LPTIMER_TRIGGER=y
+CONFIG_IIO_SYSFS_TRIGGER=y
+CONFIG_PWM=y
+CONFIG_PWM_ATMEL_HLCDC_PWM=m
+CONFIG_PWM_FSL_FTM=m
+CONFIG_PWM_STM32=y
+CONFIG_PWM_STM32_LP=y
+CONFIG_PHY_SAMSUNG_USB2=m
+CONFIG_PHY_STM32_USBPHYC=y
+CONFIG_RAS=y
+CONFIG_EXT4_FS=y
+CONFIG_AUTOFS4_FS=y
+CONFIG_FUSE_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_NTFS_FS=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_UBIFS_FS=y
+CONFIG_SQUASHFS=y
+CONFIG_SQUASHFS_LZO=y
+CONFIG_SQUASHFS_XZ=y
+CONFIG_PSTORE=y
+CONFIG_PSTORE_CONSOLE=y
+CONFIG_PSTORE_PMSG=y
+CONFIG_PSTORE_RAM=y
+CONFIG_SYSV_FS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_ROOT_NFS=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_UTF8=y
+CONFIG_PRINTK_TIME=y
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_DEBUG_INFO=y
+CONFIG_GDB_SCRIPTS=y
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_DEBUG_SECTION_MISMATCH=y
+# CONFIG_SECTION_MISMATCH_WARN_ONLY is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_SCHED_DEBUG is not set
+CONFIG_RCU_TRACE=y
+CONFIG_DEBUG_USER=y
+CONFIG_DEBUG_LL=y
+CONFIG_STM32F7_DEBUG_UART=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_CRYPTO_USER=m
+CONFIG_CRYPTO_CRYPTD=m
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_CHACHA20=m
+CONFIG_CRYPTO_USER_API_HASH=y
+CONFIG_CRYPTO_USER_API_SKCIPHER=m
+CONFIG_CRYPTO_USER_API_RNG=m
+CONFIG_CRYPTO_USER_API_AEAD=m
+CONFIG_CRC_DEV_STM32=y
+CONFIG_HASH_DEV_STM32=y
+CONFIG_CRC_ITU_T=y
+CONFIG_CRC7=y
diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/fragment-01-config-gz.config b/recipes-kernel/linux/linux-stm32mp/4.14/fragment-01-config-gz.config
similarity index 100%
rename from recipes-kernel/linux/linux-stm32mp/4.19/fragment-01-config-gz.config
rename to recipes-kernel/linux/linux-stm32mp/4.14/fragment-01-config-gz.config
diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/fragment-02-pca953x.config b/recipes-kernel/linux/linux-stm32mp/4.14/fragment-02-pca953x.config
similarity index 100%
rename from recipes-kernel/linux/linux-stm32mp/4.19/fragment-02-pca953x.config
rename to recipes-kernel/linux/linux-stm32mp/4.14/fragment-02-pca953x.config
diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/fragment-03-vcnl4000.config b/recipes-kernel/linux/linux-stm32mp/4.14/fragment-03-vcnl4000.config
similarity index 100%
rename from recipes-kernel/linux/linux-stm32mp/4.19/fragment-03-vcnl4000.config
rename to recipes-kernel/linux/linux-stm32mp/4.14/fragment-03-vcnl4000.config
diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/fragment-04-spinand.config b/recipes-kernel/linux/linux-stm32mp/4.14/fragment-04-spinand.config
similarity index 100%
rename from recipes-kernel/linux/linux-stm32mp/4.19/fragment-04-spinand.config
rename to recipes-kernel/linux/linux-stm32mp/4.14/fragment-04-spinand.config
diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/fragment-05-cpufreq.config b/recipes-kernel/linux/linux-stm32mp/4.14/fragment-05-cpufreq.config
similarity index 100%
rename from recipes-kernel/linux/linux-stm32mp/4.19/fragment-05-cpufreq.config
rename to recipes-kernel/linux/linux-stm32mp/4.14/fragment-05-cpufreq.config
diff --git a/recipes-kernel/linux/linux-stm32mp/4.14/fragment-06-fbdev-emulation.config b/recipes-kernel/linux/linux-stm32mp/4.14/fragment-06-fbdev-emulation.config
new file mode 100644
index 0000000000000000000000000000000000000000..f957d62ed0ce853fafa79a19ea905b0fe5a94d55
--- /dev/null
+++ b/recipes-kernel/linux/linux-stm32mp/4.14/fragment-06-fbdev-emulation.config
@@ -0,0 +1,2 @@
+CONFIG_DRM_FBDEV_EMULATION=y
+CONFIG_DRM_FBDEV_OVERALLOC=300
diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/fragment-07-wlan-marvell.config b/recipes-kernel/linux/linux-stm32mp/4.14/fragment-07-wlan-marvell.config
similarity index 100%
rename from recipes-kernel/linux/linux-stm32mp/4.19/fragment-07-wlan-marvell.config
rename to recipes-kernel/linux/linux-stm32mp/4.14/fragment-07-wlan-marvell.config
diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/fragment-08-pwm-beeper.config b/recipes-kernel/linux/linux-stm32mp/4.14/fragment-08-pwm-beeper.config
similarity index 100%
rename from recipes-kernel/linux/linux-stm32mp/4.19/fragment-08-pwm-beeper.config
rename to recipes-kernel/linux/linux-stm32mp/4.14/fragment-08-pwm-beeper.config
diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/fragment-06-fbdev-emulation.config b/recipes-kernel/linux/linux-stm32mp/4.19/fragment-06-fbdev-emulation.config
deleted file mode 100644
index 40e1605d072a8b3f0b930dcaed3b541a51fc9144..0000000000000000000000000000000000000000
--- a/recipes-kernel/linux/linux-stm32mp/4.19/fragment-06-fbdev-emulation.config
+++ /dev/null
@@ -1,2 +0,0 @@
-CONFIG_DRM_FBDEV_EMULATION=y
-
diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/fragment-09-early_printk.config b/recipes-kernel/linux/linux-stm32mp/4.19/fragment-09-early_printk.config
deleted file mode 100644
index 0f1ba7a064a6826dd396b08a413f60296cb7fcca..0000000000000000000000000000000000000000
--- a/recipes-kernel/linux/linux-stm32mp/4.19/fragment-09-early_printk.config
+++ /dev/null
@@ -1,12 +0,0 @@
-CONFIG_DEBUG_LL=y
-CONFIG_STM32MP1_DEBUG_UART=y
-# CONFIG_DEBUG_ICEDCC is not set
-# CONFIG_DEBUG_SEMIHOSTING is not set
-# CONFIG_DEBUG_LL_UART_8250 is not set
-# CONFIG_DEBUG_LL_UART_PL01X is not set
-CONFIG_DEBUG_STM32_UART=y
-CONFIG_DEBUG_LL_INCLUDE="debug/stm32.S"
-CONFIG_DEBUG_UART_PHYS=0x40010000
-CONFIG_DEBUG_UART_VIRT=0xfe010000
-# CONFIG_DEBUG_UNCOMPRESS is not set
-CONFIG_EARLY_PRINTK=y
diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/fragment-10-gpio-sysfs.config b/recipes-kernel/linux/linux-stm32mp/4.19/fragment-10-gpio-sysfs.config
deleted file mode 100644
index 52708d181d7f852ef1628b523904ea1018752801..0000000000000000000000000000000000000000
--- a/recipes-kernel/linux/linux-stm32mp/4.19/fragment-10-gpio-sysfs.config
+++ /dev/null
@@ -1 +0,0 @@
-CONFIG_GPIO_SYSFS=y
diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/fragment-100-fbtft-st7789.config b/recipes-kernel/linux/linux-stm32mp/4.19/fragment-100-fbtft-st7789.config
deleted file mode 100644
index 4b32f7936ed04e22938a59972bf0a6a1a066f3c1..0000000000000000000000000000000000000000
--- a/recipes-kernel/linux/linux-stm32mp/4.19/fragment-100-fbtft-st7789.config
+++ /dev/null
@@ -1,125 +0,0 @@
-CONFIG_FB_BACKLIGHT=y
-CONFIG_STAGING=y
-# CONFIG_PRISM2_USB is not set
-# CONFIG_COMEDI is not set
-# CONFIG_RTLLIB is not set
-# CONFIG_RTL8723BS is not set
-# CONFIG_R8712U is not set
-# CONFIG_R8188EU is not set
-# CONFIG_VT6656 is not set
-
-#
-# IIO staging drivers
-#
-
-#
-# Accelerometers
-#
-# CONFIG_ADIS16203 is not set
-# CONFIG_ADIS16240 is not set
-
-#
-# Analog to digital converters
-#
-# CONFIG_AD7606 is not set
-# CONFIG_AD7780 is not set
-# CONFIG_AD7816 is not set
-# CONFIG_AD7192 is not set
-# CONFIG_AD7280 is not set
-
-#
-# Analog digital bi-direction converters
-#
-# CONFIG_ADT7316 is not set
-
-#
-# Capacitance to digital converters
-#
-# CONFIG_AD7150 is not set
-# CONFIG_AD7152 is not set
-# CONFIG_AD7746 is not set
-
-#
-# Direct Digital Synthesis
-#
-# CONFIG_AD9832 is not set
-# CONFIG_AD9834 is not set
-
-#
-# Network Analyzer, Impedance Converters
-#
-# CONFIG_AD5933 is not set
-
-#
-# Active energy metering IC
-#
-# CONFIG_ADE7854 is not set
-
-#
-# Resolver to digital converters
-#
-# CONFIG_AD2S90 is not set
-# CONFIG_AD2S1210 is not set
-
-#
-# Speakup console speech
-#
-# CONFIG_SPEAKUP is not set
-# CONFIG_STAGING_MEDIA is not set
-
-#
-# Android
-#
-# CONFIG_STAGING_BOARD is not set
-# CONFIG_LTE_GDM724X is not set
-# CONFIG_MTD_SPINAND_MT29F is not set
-# CONFIG_GS_FPGABOOT is not set
-# CONFIG_UNISYSSPAR is not set
-# CONFIG_COMMON_CLK_XLNX_CLKWZRD is not set
-CONFIG_FB_TFT=y
-# CONFIG_FB_TFT_AGM1264K_FL is not set
-# CONFIG_FB_TFT_BD663474 is not set
-# CONFIG_FB_TFT_HX8340BN is not set
-# CONFIG_FB_TFT_HX8347D is not set
-# CONFIG_FB_TFT_HX8353D is not set
-# CONFIG_FB_TFT_HX8357D is not set
-# CONFIG_FB_TFT_ILI9163 is not set
-# CONFIG_FB_TFT_ILI9320 is not set
-# CONFIG_FB_TFT_ILI9325 is not set
-# CONFIG_FB_TFT_ILI9340 is not set
-# CONFIG_FB_TFT_ILI9341 is not set
-# CONFIG_FB_TFT_ILI9481 is not set
-# CONFIG_FB_TFT_ILI9486 is not set
-# CONFIG_FB_TFT_PCD8544 is not set
-# CONFIG_FB_TFT_RA8875 is not set
-# CONFIG_FB_TFT_S6D02A1 is not set
-# CONFIG_FB_TFT_S6D1121 is not set
-# CONFIG_FB_TFT_SH1106 is not set
-# CONFIG_FB_TFT_SSD1289 is not set
-# CONFIG_FB_TFT_SSD1305 is not set
-# CONFIG_FB_TFT_SSD1306 is not set
-# CONFIG_FB_TFT_SSD1331 is not set
-# CONFIG_FB_TFT_SSD1351 is not set
-# CONFIG_FB_TFT_ST7735R is not set
-CONFIG_FB_TFT_ST7789V=y
-# CONFIG_FB_TFT_TINYLCD is not set
-# CONFIG_FB_TFT_TLS8204 is not set
-# CONFIG_FB_TFT_UC1611 is not set
-# CONFIG_FB_TFT_UC1701 is not set
-# CONFIG_FB_TFT_UPD161704 is not set
-# CONFIG_FB_TFT_WATTEROTT is not set
-# CONFIG_FB_FLEX is not set
-# CONFIG_FB_TFT_FBTFT_DEVICE is not set
-# CONFIG_WILC1000_SDIO is not set
-# CONFIG_WILC1000_SPI is not set
-# CONFIG_MOST is not set
-# CONFIG_KS7010 is not set
-# CONFIG_GREYBUS is not set
-# CONFIG_PI433 is not set
-# CONFIG_MTK_MMC is not set
-
-#
-# Gasket devices
-#
-# CONFIG_XIL_AXIS_FIFO is not set
-# CONFIG_EROFS_FS is not set
diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/fragment-101-wlan-ralink53xx.config b/recipes-kernel/linux/linux-stm32mp/4.19/fragment-101-wlan-ralink53xx.config
deleted file mode 100644
index b896dc2ee99d7b270b66c42fa10cbcb2edcc4e8b..0000000000000000000000000000000000000000
--- a/recipes-kernel/linux/linux-stm32mp/4.19/fragment-101-wlan-ralink53xx.config
+++ /dev/null
@@ -1 +0,0 @@
-CONFIG_RT2800USB_RT53XX=y
diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/fragment-102-lvds-bridge-sn65dsi.config b/recipes-kernel/linux/linux-stm32mp/4.19/fragment-102-lvds-bridge-sn65dsi.config
deleted file mode 100644
index c75990979c5c186fc1610d4b99d999bf8d751810..0000000000000000000000000000000000000000
--- a/recipes-kernel/linux/linux-stm32mp/4.19/fragment-102-lvds-bridge-sn65dsi.config
+++ /dev/null
@@ -1 +0,0 @@
-CONFIG_DRM_I2C_SN65DSI83=y
diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/fragment-103-hdmi-bridge-adv.config b/recipes-kernel/linux/linux-stm32mp/4.19/fragment-103-hdmi-bridge-adv.config
deleted file mode 100644
index 65272d7f0713b1f06265c49e99a9e8c2bfcc4ee9..0000000000000000000000000000000000000000
--- a/recipes-kernel/linux/linux-stm32mp/4.19/fragment-103-hdmi-bridge-adv.config
+++ /dev/null
@@ -1,3 +0,0 @@
-CONFIG_VIDEO_ADV7511=m
-CONFIG_DRM_I2C_ADV7511=y
-CONFIG_DRM_I2C_ADV7511_AUDIO=y
diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/fragment-104-touch-sis.config b/recipes-kernel/linux/linux-stm32mp/4.19/fragment-104-touch-sis.config
deleted file mode 100644
index c1e1ca264b31f21da53892d84eef65cdf2b46fc6..0000000000000000000000000000000000000000
--- a/recipes-kernel/linux/linux-stm32mp/4.19/fragment-104-touch-sis.config
+++ /dev/null
@@ -1 +0,0 @@
-CONFIG_TOUCHSCREEN_SIS_I2C=y
diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/fragment-11-wm8510-driver.config b/recipes-kernel/linux/linux-stm32mp/4.19/fragment-11-wm8510-driver.config
deleted file mode 100644
index 2c2614566ea16d3b0fde11a43e3649c9c19710e8..0000000000000000000000000000000000000000
--- a/recipes-kernel/linux/linux-stm32mp/4.19/fragment-11-wm8510-driver.config
+++ /dev/null
@@ -1 +0,0 @@
-CONFIG_SND_SOC_WM8510=m
diff --git a/recipes-kernel/linux/linux-stm32mp/bleeding/patches/0500-linux-stm32mp-disable-spidev-warning-message.patch b/recipes-kernel/linux/linux-stm32mp/bleeding/patches/0500-linux-stm32mp-disable-spidev-warning-message.patch
deleted file mode 100644
index d89a9ccc102a5ad03ecdff000edd90fa943a67a1..0000000000000000000000000000000000000000
--- a/recipes-kernel/linux/linux-stm32mp/bleeding/patches/0500-linux-stm32mp-disable-spidev-warning-message.patch
+++ /dev/null
@@ -1,30 +0,0 @@
-From 30242676ba7af2e91c49d5e4c8b0061d5f060217 Mon Sep 17 00:00:00 2001
-From: Eberhard Stoll <eberhard.stoll@exceet.de>
-Date: Mon, 29 Oct 2018 13:31:43 +0100
-Subject: [PATCH] linux-stm32mp: disable spidev warning message
-
----
- drivers/spi/spidev.c | 3 +++
- 1 file changed, 3 insertions(+)
-
-diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c
-index 028725573e63..19a0fa99259f 100644
---- a/drivers/spi/spidev.c
-+++ b/drivers/spi/spidev.c
-@@ -722,6 +722,8 @@ static int spidev_probe(struct spi_device *spi)
- 	int			status;
- 	unsigned long		minor;
- 
-+	/* Disable spidev warning */
-+#if 0
- 	/*
- 	 * spidev should never be referenced in DT without a specific
- 	 * compatible string, it is a Linux implementation thing
-@@ -730,6 +732,7 @@ static int spidev_probe(struct spi_device *spi)
- 	WARN(spi->dev.of_node &&
- 	     of_device_is_compatible(spi->dev.of_node, "spidev"),
- 	     "%pOF: buggy DT: spidev listed directly in DT\n", spi->dev.of_node);
-+#endif
- 
- 	spidev_probe_acpi(spi);
- 
diff --git a/recipes-kernel/linux/linux-stm32mp/bleeding/patches/0504-drm-panel-simple-Add-support-for-Admatec-T070P133T0S.patch b/recipes-kernel/linux/linux-stm32mp/bleeding/patches/0504-drm-panel-simple-Add-support-for-Admatec-T070P133T0S.patch
deleted file mode 100644
index 5080d741809ee96502e3fd370545638d81e03cd1..0000000000000000000000000000000000000000
--- a/recipes-kernel/linux/linux-stm32mp/bleeding/patches/0504-drm-panel-simple-Add-support-for-Admatec-T070P133T0S.patch
+++ /dev/null
@@ -1,56 +0,0 @@
-From 514691d936701ec2e90c96b04df4b5ee1aee420b Mon Sep 17 00:00:00 2001
-From: Frieder Schrempf <frieder.schrempf@exceet.de>
-Date: Thu, 2 Aug 2018 10:59:57 +0200
-Subject: [PATCH] drm/panel: simple: Add support for Admatec T070P133T0S301
-
----
- drivers/gpu/drm/panel/panel-simple.c | 29 ++++++++++++++++++++++++++++
- 1 file changed, 29 insertions(+)
-
-diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c
-index 65ae2a41e4c2..c654d7e2893f 100644
---- a/drivers/gpu/drm/panel/panel-simple.c
-+++ b/drivers/gpu/drm/panel/panel-simple.c
-@@ -386,6 +386,32 @@ static void panel_simple_shutdown(struct device *dev)
- 	panel_simple_unprepare(&panel->base);
- }
- 
-+static const struct drm_display_mode admatec_t070p133t0s301_mode = {
-+	.clock = 37000,
-+	.hdisplay = 800,
-+	.hsync_start = 800 + 327,
-+	.hsync_end =  800  + 327 + 1,
-+	.htotal = 800 + 48 + 327 + 1,
-+	.vdisplay = 480,
-+	.vsync_start = 480 + 25,
-+	.vsync_end = 480 + 25 + 1,
-+	.vtotal = 480 + 20 + 25 + 1,
-+	.vrefresh = 60,
-+	.flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC,
-+};
-+
-+static const struct panel_desc admatec_t070p133t0s301 = {
-+	.modes = &admatec_t070p133t0s301_mode,
-+	.num_modes = 1,
-+	.bpc = 8,
-+	.size = {
-+		.width = 95,
-+		.height = 54,
-+	},
-+	.bus_format = MEDIA_BUS_FMT_RGB888_1X24,
-+	.bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_POSEDGE,
-+};
-+
- static const struct drm_display_mode admatec_t043c004800272t2a_mode = {
- 	.clock = 9200,
- 	.hdisplay = 480,
-@@ -2376,6 +2402,9 @@ static const struct panel_desc winstar_wf35ltiacd = {
- 
- static const struct of_device_id platform_of_match[] = {
- 	{
-+		.compatible = "admatec,t070p133t0s301",
-+		.data = &admatec_t070p133t0s301,
-+	}, {
- 		.compatible = "admatec,t043c004800272t2a",
- 		.data = &admatec_t043c004800272t2a,
- 	}, {
diff --git a/recipes-kernel/linux/linux-stm32mp/bleeding/patches/0509-pinctl-disable-strict-checking.patch b/recipes-kernel/linux/linux-stm32mp/bleeding/patches/0509-pinctl-disable-strict-checking.patch
deleted file mode 100644
index 31105d58ae83d33ba46ebac020dc8f9f9eb89c68..0000000000000000000000000000000000000000
--- a/recipes-kernel/linux/linux-stm32mp/bleeding/patches/0509-pinctl-disable-strict-checking.patch
+++ /dev/null
@@ -1,23 +0,0 @@
-From ae285127c11bcdeb3094957f9fa9e0d762d7dcb2 Mon Sep 17 00:00:00 2001
-From: Eberhard Stoll <eberhard.stoll@kontron.de>
-Date: Tue, 8 Oct 2019 14:39:47 +0200
-Subject: [PATCH] pinctl disable strict checking
-
----
- drivers/pinctrl/stm32/pinctrl-stm32.c | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
-diff --git a/drivers/pinctrl/stm32/pinctrl-stm32.c b/drivers/pinctrl/stm32/pinctrl-stm32.c
-index 4f2676b86d6e..4c1a8e3b7cc1 100644
---- a/drivers/pinctrl/stm32/pinctrl-stm32.c
-+++ b/drivers/pinctrl/stm32/pinctrl-stm32.c
-@@ -785,7 +785,8 @@ static const struct pinmux_ops stm32_pmx_ops = {
- 	.get_function_groups	= stm32_pmx_get_func_groups,
- 	.set_mux		= stm32_pmx_set_mux,
- 	.gpio_set_direction	= stm32_pmx_gpio_set_direction,
--	.strict			= true,
-+	.strict			= false,
-+	/*.strict			= true,*/
- };
- 
- /* Pinconf functions */
diff --git a/recipes-kernel/linux/linux-stm32mp/bleeding/patches/0510-adv7511-mainline-5.4.x-code-integrated.patch b/recipes-kernel/linux/linux-stm32mp/bleeding/patches/0510-adv7511-mainline-5.4.x-code-integrated.patch
deleted file mode 100644
index a35408b60d5453d66a332ed1490a381dd9a09e51..0000000000000000000000000000000000000000
--- a/recipes-kernel/linux/linux-stm32mp/bleeding/patches/0510-adv7511-mainline-5.4.x-code-integrated.patch
+++ /dev/null
@@ -1,220 +0,0 @@
-From bea82c67f6b0bbe6e47aa271adc2020ba361336a Mon Sep 17 00:00:00 2001
-From: Eberhard Stoll <eberhard.stoll@kontron.de>
-Date: Thu, 5 Dec 2019 14:16:57 +0100
-Subject: [PATCH] adv7511: mainline 5.4.x code integrated
-
----
- drivers/gpu/drm/bridge/adv7511/Kconfig        |  1 +
- drivers/gpu/drm/bridge/adv7511/Makefile       |  1 +
- drivers/gpu/drm/bridge/adv7511/adv7511.h      | 11 +++---
- .../gpu/drm/bridge/adv7511/adv7511_audio.c    |  3 +-
- drivers/gpu/drm/bridge/adv7511/adv7511_drv.c  | 38 +++++++++----------
- drivers/gpu/drm/bridge/adv7511/adv7533.c      | 12 +-----
- 6 files changed, 30 insertions(+), 36 deletions(-)
-
-diff --git a/drivers/gpu/drm/bridge/adv7511/Kconfig b/drivers/gpu/drm/bridge/adv7511/Kconfig
-index 944e440c4fde..8a56ff81f4fb 100644
---- a/drivers/gpu/drm/bridge/adv7511/Kconfig
-+++ b/drivers/gpu/drm/bridge/adv7511/Kconfig
-@@ -1,3 +1,4 @@
-+# SPDX-License-Identifier: GPL-2.0-only
- config DRM_I2C_ADV7511
- 	tristate "ADV7511 encoder"
- 	depends on OF
-diff --git a/drivers/gpu/drm/bridge/adv7511/Makefile b/drivers/gpu/drm/bridge/adv7511/Makefile
-index 5bb384938a71..b46ebeb35fd4 100644
---- a/drivers/gpu/drm/bridge/adv7511/Makefile
-+++ b/drivers/gpu/drm/bridge/adv7511/Makefile
-@@ -1,3 +1,4 @@
-+# SPDX-License-Identifier: GPL-2.0-only
- adv7511-y := adv7511_drv.o
- adv7511-$(CONFIG_DRM_I2C_ADV7511_AUDIO) += adv7511_audio.o
- adv7511-$(CONFIG_DRM_I2C_ADV7511_CEC) += adv7511_cec.o
-diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511.h b/drivers/gpu/drm/bridge/adv7511/adv7511.h
-index 73d8ccb97742..52b2adfdc877 100644
---- a/drivers/gpu/drm/bridge/adv7511/adv7511.h
-+++ b/drivers/gpu/drm/bridge/adv7511/adv7511.h
-@@ -1,9 +1,8 @@
-+/* SPDX-License-Identifier: GPL-2.0-only */
- /*
-  * Analog Devices ADV7511 HDMI transmitter driver
-  *
-  * Copyright 2012 Analog Devices Inc.
-- *
-- * Licensed under the GPL-2.
-  */
- 
- #ifndef __DRM_I2C_ADV7511_H__
-@@ -14,8 +13,10 @@
- #include <linux/regmap.h>
- #include <linux/regulator/consumer.h>
- 
--#include <drm/drm_crtc_helper.h>
-+#include <drm/drm_bridge.h>
-+#include <drm/drm_connector.h>
- #include <drm/drm_mipi_dsi.h>
-+#include <drm/drm_modes.h>
- 
- #define ADV7511_REG_CHIP_REVISION		0x00
- #define ADV7511_REG_N0				0x01
-@@ -395,7 +396,7 @@ static inline int adv7511_cec_init(struct device *dev, struct adv7511 *adv7511)
- #ifdef CONFIG_DRM_I2C_ADV7533
- void adv7533_dsi_power_on(struct adv7511 *adv);
- void adv7533_dsi_power_off(struct adv7511 *adv);
--void adv7533_mode_set(struct adv7511 *adv, struct drm_display_mode *mode);
-+void adv7533_mode_set(struct adv7511 *adv, const struct drm_display_mode *mode);
- int adv7533_patch_registers(struct adv7511 *adv);
- int adv7533_patch_cec_registers(struct adv7511 *adv);
- int adv7533_attach_dsi(struct adv7511 *adv);
-@@ -411,7 +412,7 @@ static inline void adv7533_dsi_power_off(struct adv7511 *adv)
- }
- 
- static inline void adv7533_mode_set(struct adv7511 *adv,
--				    struct drm_display_mode *mode)
-+				    const struct drm_display_mode *mode)
- {
- }
- 
-diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_audio.c b/drivers/gpu/drm/bridge/adv7511/adv7511_audio.c
-index 1b4783d45c53..a428185be2c1 100644
---- a/drivers/gpu/drm/bridge/adv7511/adv7511_audio.c
-+++ b/drivers/gpu/drm/bridge/adv7511/adv7511_audio.c
-@@ -1,10 +1,9 @@
-+// SPDX-License-Identifier: GPL-2.0-only
- /*
-  * Analog Devices ADV7511 HDMI transmitter driver
-  *
-  * Copyright 2012 Analog Devices Inc.
-  * Copyright (c) 2016, Linaro Limited
-- *
-- * Licensed under the GPL-2.
-  */
- 
- #include <sound/core.h>
-diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
-index e7ddd3e3db92..9e13e466e72c 100644
---- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
-+++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
-@@ -1,24 +1,24 @@
-+// SPDX-License-Identifier: GPL-2.0-only
- /*
-  * Analog Devices ADV7511 HDMI transmitter driver
-  *
-  * Copyright 2012 Analog Devices Inc.
-- *
-- * Licensed under the GPL-2.
-  */
- 
-+#include <linux/clk.h>
- #include <linux/device.h>
- #include <linux/gpio/consumer.h>
- #include <linux/module.h>
- #include <linux/of_device.h>
- #include <linux/slab.h>
--#include <linux/clk.h>
- 
--#include <drm/drmP.h>
-+#include <media/cec.h>
-+
- #include <drm/drm_atomic.h>
- #include <drm/drm_atomic_helper.h>
- #include <drm/drm_edid.h>
--
--#include <media/cec.h>
-+#include <drm/drm_print.h>
-+#include <drm/drm_probe_helper.h>
- 
- #include "adv7511.h"
- 
-@@ -676,8 +676,8 @@ static enum drm_mode_status adv7511_mode_valid(struct adv7511 *adv7511,
- }
- 
- static void adv7511_mode_set(struct adv7511 *adv7511,
--			     struct drm_display_mode *mode,
--			     struct drm_display_mode *adj_mode)
-+			     const struct drm_display_mode *mode,
-+			     const struct drm_display_mode *adj_mode)
- {
- 	unsigned int low_refresh_rate;
- 	unsigned int hsync_polarity = 0;
-@@ -839,8 +839,8 @@ static void adv7511_bridge_disable(struct drm_bridge *bridge)
- }
- 
- static void adv7511_bridge_mode_set(struct drm_bridge *bridge,
--				    struct drm_display_mode *mode,
--				    struct drm_display_mode *adj_mode)
-+				    const struct drm_display_mode *mode,
-+				    const struct drm_display_mode *adj_mode)
- {
- 	struct adv7511 *adv = bridge_to_adv7511(bridge);
- 
-@@ -981,10 +981,10 @@ static int adv7511_init_cec_regmap(struct adv7511 *adv)
- {
- 	int ret;
- 
--	adv->i2c_cec = i2c_new_secondary_device(adv->i2c_main, "cec",
-+	adv->i2c_cec = i2c_new_ancillary_device(adv->i2c_main, "cec",
- 						ADV7511_CEC_I2C_ADDR_DEFAULT);
--	if (!adv->i2c_cec)
--		return -EINVAL;
-+	if (IS_ERR(adv->i2c_cec))
-+		return PTR_ERR(adv->i2c_cec);
- 	i2c_set_clientdata(adv->i2c_cec, adv);
- 
- 	adv->regmap_cec = devm_regmap_init_i2c(adv->i2c_cec,
-@@ -1165,20 +1165,20 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
- 
- 	adv7511_packet_disable(adv7511, 0xffff);
- 
--	adv7511->i2c_edid = i2c_new_secondary_device(i2c, "edid",
-+	adv7511->i2c_edid = i2c_new_ancillary_device(i2c, "edid",
- 					ADV7511_EDID_I2C_ADDR_DEFAULT);
--	if (!adv7511->i2c_edid) {
--		ret = -EINVAL;
-+	if (IS_ERR(adv7511->i2c_edid)) {
-+		ret = PTR_ERR(adv7511->i2c_edid);
- 		goto uninit_regulators;
- 	}
- 
- 	regmap_write(adv7511->regmap, ADV7511_REG_EDID_I2C_ADDR,
- 		     adv7511->i2c_edid->addr << 1);
- 
--	adv7511->i2c_packet = i2c_new_secondary_device(i2c, "packet",
-+	adv7511->i2c_packet = i2c_new_ancillary_device(i2c, "packet",
- 					ADV7511_PACKET_I2C_ADDR_DEFAULT);
--	if (!adv7511->i2c_packet) {
--		ret = -EINVAL;
-+	if (IS_ERR(adv7511->i2c_packet)) {
-+		ret = PTR_ERR(adv7511->i2c_packet);
- 		goto err_i2c_unregister_edid;
- 	}
- 
-diff --git a/drivers/gpu/drm/bridge/adv7511/adv7533.c b/drivers/gpu/drm/bridge/adv7511/adv7533.c
-index 185b6d842166..aa19d5a40e31 100644
---- a/drivers/gpu/drm/bridge/adv7511/adv7533.c
-+++ b/drivers/gpu/drm/bridge/adv7511/adv7533.c
-@@ -1,14 +1,6 @@
-+// SPDX-License-Identifier: GPL-2.0-only
- /*
-  * Copyright (c) 2016, The Linux Foundation. All rights reserved.
-- *
-- * This program is free software; you can redistribute it and/or modify
-- * it under the terms of the GNU General Public License version 2 and
-- * only 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/of_graph.h>
-@@ -108,7 +100,7 @@ void adv7533_dsi_power_off(struct adv7511 *adv)
- 	regmap_write(adv->regmap_cec, 0x27, 0x0b);
- }
- 
--void adv7533_mode_set(struct adv7511 *adv, struct drm_display_mode *mode)
-+void adv7533_mode_set(struct adv7511 *adv, const struct drm_display_mode *mode)
- {
- 	struct mipi_dsi_device *dsi = adv->dsi;
- 	int lanes, ret;
diff --git a/recipes-kernel/linux/linux-stm32mp/bleeding/stm32mp157c-t1000-k-mx.dts b/recipes-kernel/linux/linux-stm32mp/bleeding/stm32mp157c-t1000-k-mx.dts
deleted file mode 100644
index 48c38f7ded4bef1a03b8cfa9a84dbed9383c9db5..0000000000000000000000000000000000000000
--- a/recipes-kernel/linux/linux-stm32mp/bleeding/stm32mp157c-t1000-k-mx.dts
+++ /dev/null
@@ -1,879 +0,0 @@
-/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
-/*
- * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
- * Author: STM32CubeMX code generation for STMicroelectronics.
- */
-
-/dts-v1/;
-#include "stm32mp157c.dtsi"
-#include "stm32mp157cad-pinctrl.dtsi"
-#include "stm32mp157c-m4-srm.dtsi"
-
-/* USER CODE BEGIN includes */
-/* USER CODE END includes */
-
-/ {
-	model = "STMicroelectronics custom STM32CubeMX board";
-	compatible = "st,stm32mp157c-t1000-k-mx", "st,stm32mp157";
-
-	memory@c0000000 {
-		reg = <0xc0000000 0x20000000>;
-
-		/* USER CODE BEGIN memory */
-		/* USER CODE END memory */
-	};
-
-	reserved-memory {
-		#address-cells = <1>;
-		#size-cells = <1>;
-		ranges;
-
-		/* USER CODE BEGIN reserved-memory */
-		/* USER CODE END reserved-memory */
-
-		gpu_reserved: gpu@dc000000 {
-			reg = <0xdc000000 0x4000000>;
-			no-map;
-		};
-	};
-
-	/* USER CODE BEGIN root */
-	/* USER CODE END root */
-
-	clocks {
-		/* USER CODE BEGIN clocks */
-		/* USER CODE END clocks */
-
-		clk_hsi: clk-hsi {
-			clock-frequency = <64000000>;
-		};
-
-		clk_csi: clk-csi {
-			clock-frequency = <4000000>;
-		};
-
-		clk_lse: clk-lse {
-			clock-frequency = <32768>;
-		};
-
-		clk_hse: clk-hse {
-			clock-frequency = <24000000>;
-		};
-	};
-
-}; /*root*/
-
-&pinctrl {
-	u-boot,dm-pre-reloc;
-
-	adc_pins_mx: adc_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 0, ANALOG)>, /* ADC1_INP16 */
-					 <STM32_PINMUX('B', 1, ANALOG)>; /* ADC1_INP5 */
-		};
-	};
-
-	adc_sleep_pins_mx: adc_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 0, ANALOG)>, /* ADC1_INP16 */
-					 <STM32_PINMUX('B', 1, ANALOG)>; /* ADC1_INP5 */
-		};
-	};
-
-	eth1_pins_mx: eth1_mx-0 {
-		pins1 {
-			pinmux = <STM32_PINMUX('A', 2, AF11)>; /* ETH1_MDIO */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-		pins2 {
-			pinmux = <STM32_PINMUX('A', 7, AF11)>, /* ETH1_CRS_DV */
-					 <STM32_PINMUX('C', 4, AF11)>, /* ETH1_RXD0 */
-					 <STM32_PINMUX('C', 5, AF11)>; /* ETH1_RXD1 */
-			bias-disable;
-		};
-		pins3 {
-			pinmux = <STM32_PINMUX('B', 11, AF11)>; /* ETH1_TX_EN */
-		};
-		pins4 {
-			pinmux = <STM32_PINMUX('B', 12, AF11)>, /* ETH1_TXD0 */
-					 <STM32_PINMUX('B', 13, AF11)>, /* ETH1_TXD1 */
-					 <STM32_PINMUX('C', 1, AF11)>, /* ETH1_MDC */
-					 <STM32_PINMUX('G', 8, AF2)>; /* ETH1_CLK */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-	};
-
-	eth1_sleep_pins_mx: eth1_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 2, ANALOG)>, /* ETH1_MDIO */
-					 <STM32_PINMUX('A', 7, ANALOG)>, /* ETH1_CRS_DV */
-					 <STM32_PINMUX('B', 11, ANALOG)>, /* ETH1_TX_EN */
-					 <STM32_PINMUX('B', 12, ANALOG)>, /* ETH1_TXD0 */
-					 <STM32_PINMUX('B', 13, ANALOG)>, /* ETH1_TXD1 */
-					 <STM32_PINMUX('C', 1, ANALOG)>, /* ETH1_MDC */
-					 <STM32_PINMUX('C', 4, ANALOG)>, /* ETH1_RXD0 */
-					 <STM32_PINMUX('C', 5, ANALOG)>, /* ETH1_RXD1 */
-					 <STM32_PINMUX('G', 8, ANALOG)>; /* ETH1_CLK */
-		};
-	};
-
-	fdcan1_pins_mx: fdcan1_mx-0 {
-		pins1 {
-			pinmux = <STM32_PINMUX('D', 0, AF9)>; /* FDCAN1_RX */
-			bias-disable;
-		};
-		pins2 {
-			pinmux = <STM32_PINMUX('D', 1, AF9)>; /* FDCAN1_TX */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-	};
-
-	fdcan1_sleep_pins_mx: fdcan1_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('D', 0, ANALOG)>, /* FDCAN1_RX */
-					 <STM32_PINMUX('D', 1, ANALOG)>; /* FDCAN1_TX */
-		};
-	};
-
-	i2c2_pins_mx: i2c2_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('D', 7, AF4)>, /* I2C2_SCL */
-					 <STM32_PINMUX('G', 15, AF4)>; /* I2C2_SDA */
-			bias-disable;
-			drive-open-drain;
-			slew-rate = <0>;
-		};
-	};
-
-	i2c2_sleep_pins_mx: i2c2_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('D', 7, ANALOG)>, /* I2C2_SCL */
-					 <STM32_PINMUX('G', 15, ANALOG)>; /* I2C2_SDA */
-		};
-	};
-
-	i2c4_pins_mx: i2c4_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('B', 7, AF6)>, /* I2C4_SDA */
-					 <STM32_PINMUX('E', 2, AF4)>; /* I2C4_SCL */
-			bias-disable;
-			drive-open-drain;
-			slew-rate = <0>;
-		};
-	};
-
-	i2c4_sleep_pins_mx: i2c4_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('B', 7, ANALOG)>, /* I2C4_SDA */
-					 <STM32_PINMUX('E', 2, ANALOG)>; /* I2C4_SCL */
-		};
-	};
-
-	ltdc_pins_mx: ltdc_mx-0 {
-		pins1 {
-			pinmux = <STM32_PINMUX('A', 1, AF14)>, /* LTDC_R2 */
-					 <STM32_PINMUX('A', 3, AF14)>, /* LTDC_B5 */
-					 <STM32_PINMUX('A', 4, AF14)>, /* LTDC_VSYNC */
-					 <STM32_PINMUX('A', 5, AF14)>, /* LTDC_R4 */
-					 <STM32_PINMUX('A', 6, AF14)>, /* LTDC_G2 */
-					 <STM32_PINMUX('A', 8, AF14)>, /* LTDC_R6 */
-					 <STM32_PINMUX('A', 12, AF14)>, /* LTDC_R5 */
-					 <STM32_PINMUX('A', 15, AF14)>, /* LTDC_R1 */
-					 <STM32_PINMUX('B', 0, AF9)>, /* LTDC_R3 */
-					 <STM32_PINMUX('B', 5, AF14)>, /* LTDC_G7 */
-					 <STM32_PINMUX('B', 8, AF14)>, /* LTDC_B6 */
-					 <STM32_PINMUX('B', 9, AF14)>, /* LTDC_B7 */
-					 <STM32_PINMUX('B', 10, AF14)>, /* LTDC_G4 */
-					 <STM32_PINMUX('C', 6, AF14)>, /* LTDC_HSYNC */
-					 <STM32_PINMUX('C', 7, AF14)>, /* LTDC_G6 */
-					 <STM32_PINMUX('D', 10, AF14)>, /* LTDC_B3 */
-					 <STM32_PINMUX('E', 4, AF14)>, /* LTDC_B0 */
-					 <STM32_PINMUX('E', 5, AF14)>, /* LTDC_G0 */
-					 <STM32_PINMUX('E', 6, AF14)>, /* LTDC_G1 */
-					 <STM32_PINMUX('E', 11, AF14)>, /* LTDC_G3 */
-					 <STM32_PINMUX('E', 12, AF14)>, /* LTDC_B4 */
-					 <STM32_PINMUX('E', 13, AF14)>, /* LTDC_DE */
-					 <STM32_PINMUX('E', 15, AF14)>, /* LTDC_R7 */
-					 <STM32_PINMUX('F', 11, AF14)>, /* LTDC_G5 */
-					 <STM32_PINMUX('G', 10, AF14)>, /* LTDC_B2 */
-					 <STM32_PINMUX('G', 12, AF14)>, /* LTDC_B1 */
-					 <STM32_PINMUX('G', 13, AF14)>; /* LTDC_R0 */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-		pins2 {
-			pinmux = <STM32_PINMUX('E', 14, AF14)>; /* LTDC_CLK */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-	};
-
-	ltdc_sleep_pins_mx: ltdc_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 1, ANALOG)>, /* LTDC_R2 */
-					 <STM32_PINMUX('A', 3, ANALOG)>, /* LTDC_B5 */
-					 <STM32_PINMUX('A', 4, ANALOG)>, /* LTDC_VSYNC */
-					 <STM32_PINMUX('A', 5, ANALOG)>, /* LTDC_R4 */
-					 <STM32_PINMUX('A', 6, ANALOG)>, /* LTDC_G2 */
-					 <STM32_PINMUX('A', 8, ANALOG)>, /* LTDC_R6 */
-					 <STM32_PINMUX('A', 12, ANALOG)>, /* LTDC_R5 */
-					 <STM32_PINMUX('A', 15, ANALOG)>, /* LTDC_R1 */
-					 <STM32_PINMUX('B', 0, ANALOG)>, /* LTDC_R3 */
-					 <STM32_PINMUX('B', 5, ANALOG)>, /* LTDC_G7 */
-					 <STM32_PINMUX('B', 8, ANALOG)>, /* LTDC_B6 */
-					 <STM32_PINMUX('B', 9, ANALOG)>, /* LTDC_B7 */
-					 <STM32_PINMUX('B', 10, ANALOG)>, /* LTDC_G4 */
-					 <STM32_PINMUX('C', 6, ANALOG)>, /* LTDC_HSYNC */
-					 <STM32_PINMUX('C', 7, ANALOG)>, /* LTDC_G6 */
-					 <STM32_PINMUX('D', 10, ANALOG)>, /* LTDC_B3 */
-					 <STM32_PINMUX('E', 4, ANALOG)>, /* LTDC_B0 */
-					 <STM32_PINMUX('E', 5, ANALOG)>, /* LTDC_G0 */
-					 <STM32_PINMUX('E', 6, ANALOG)>, /* LTDC_G1 */
-					 <STM32_PINMUX('E', 11, ANALOG)>, /* LTDC_G3 */
-					 <STM32_PINMUX('E', 12, ANALOG)>, /* LTDC_B4 */
-					 <STM32_PINMUX('E', 13, ANALOG)>, /* LTDC_DE */
-					 <STM32_PINMUX('E', 14, ANALOG)>, /* LTDC_CLK */
-					 <STM32_PINMUX('E', 15, ANALOG)>, /* LTDC_R7 */
-					 <STM32_PINMUX('F', 11, ANALOG)>, /* LTDC_G5 */
-					 <STM32_PINMUX('G', 10, ANALOG)>, /* LTDC_B2 */
-					 <STM32_PINMUX('G', 12, ANALOG)>, /* LTDC_B1 */
-					 <STM32_PINMUX('G', 13, ANALOG)>; /* LTDC_R0 */
-		};
-	};
-
-	quadspi_pins_mx: quadspi_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 6, AF10)>, /* QUADSPI_BK1_NCS */
-					 <STM32_PINMUX('C', 0, AF10)>; /* QUADSPI_BK2_NCS */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('E', 7, AF10)>, /* QUADSPI_BK2_IO0 */
-					 <STM32_PINMUX('E', 8, AF10)>, /* QUADSPI_BK2_IO1 */
-					 <STM32_PINMUX('E', 9, AF10)>, /* QUADSPI_BK2_IO2 */
-					 <STM32_PINMUX('E', 10, AF10)>, /* QUADSPI_BK2_IO3 */
-					 <STM32_PINMUX('F', 6, AF9)>, /* QUADSPI_BK1_IO3 */
-					 <STM32_PINMUX('F', 7, AF9)>, /* QUADSPI_BK1_IO2 */
-					 <STM32_PINMUX('F', 8, AF10)>, /* QUADSPI_BK1_IO0 */
-					 <STM32_PINMUX('F', 9, AF10)>; /* QUADSPI_BK1_IO1 */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins3 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('F', 10, AF9)>; /* QUADSPI_CLK */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <2>;
-		};
-	};
-
-	quadspi_sleep_pins_mx: quadspi_sleep_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 6, ANALOG)>, /* QUADSPI_BK1_NCS */
-					 <STM32_PINMUX('C', 0, ANALOG)>, /* QUADSPI_BK2_NCS */
-					 <STM32_PINMUX('E', 7, ANALOG)>, /* QUADSPI_BK2_IO0 */
-					 <STM32_PINMUX('E', 8, ANALOG)>, /* QUADSPI_BK2_IO1 */
-					 <STM32_PINMUX('E', 9, ANALOG)>, /* QUADSPI_BK2_IO2 */
-					 <STM32_PINMUX('E', 10, ANALOG)>, /* QUADSPI_BK2_IO3 */
-					 <STM32_PINMUX('F', 6, ANALOG)>, /* QUADSPI_BK1_IO3 */
-					 <STM32_PINMUX('F', 7, ANALOG)>, /* QUADSPI_BK1_IO2 */
-					 <STM32_PINMUX('F', 8, ANALOG)>, /* QUADSPI_BK1_IO0 */
-					 <STM32_PINMUX('F', 9, ANALOG)>, /* QUADSPI_BK1_IO1 */
-					 <STM32_PINMUX('F', 10, ANALOG)>; /* QUADSPI_CLK */
-		};
-	};
-
-	rtc_pins_mx: rtc_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('C', 13, ANALOG)>; /* RTC_LSCO */
-		};
-	};
-
-	rtc_sleep_pins_mx: rtc_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('C', 13, ANALOG)>; /* RTC_LSCO */
-		};
-	};
-
-	sdmmc1_pins_mx: sdmmc1_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
-					 <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
-					 <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
-					 <STM32_PINMUX('C', 11, AF12)>, /* SDMMC1_D3 */
-					 <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 12, AF12)>; /* SDMMC1_CK */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-	};
-
-	sdmmc1_opendrain_pins_mx: sdmmc1_opendrain_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
-					 <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
-					 <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
-					 <STM32_PINMUX('C', 11, AF12)>; /* SDMMC1_D3 */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 12, AF12)>; /* SDMMC1_CK */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins3 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
-			bias-pull-up;
-			drive-open-drain;
-			slew-rate = <1>;
-		};
-	};
-
-	sdmmc1_sleep_pins_mx: sdmmc1_sleep_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 8, ANALOG)>, /* SDMMC1_D0 */
-					 <STM32_PINMUX('C', 9, ANALOG)>, /* SDMMC1_D1 */
-					 <STM32_PINMUX('C', 10, ANALOG)>, /* SDMMC1_D2 */
-					 <STM32_PINMUX('C', 11, ANALOG)>, /* SDMMC1_D3 */
-					 <STM32_PINMUX('C', 12, ANALOG)>, /* SDMMC1_CK */
-					 <STM32_PINMUX('D', 2, ANALOG)>; /* SDMMC1_CMD */
-		};
-	};
-
-	sdmmc2_pins_mx: sdmmc2_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 3, AF9)>, /* SDMMC2_D2 */
-					 <STM32_PINMUX('B', 4, AF9)>, /* SDMMC2_D3 */
-					 <STM32_PINMUX('B', 14, AF9)>, /* SDMMC2_D0 */
-					 <STM32_PINMUX('B', 15, AF9)>, /* SDMMC2_D1 */
-					 <STM32_PINMUX('G', 6, AF10)>; /* SDMMC2_CMD */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('E', 3, AF9)>; /* SDMMC2_CK */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-	};
-
-	sdmmc2_opendrain_pins_mx: sdmmc2_opendrain_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 3, AF9)>, /* SDMMC2_D2 */
-					 <STM32_PINMUX('B', 4, AF9)>, /* SDMMC2_D3 */
-					 <STM32_PINMUX('B', 14, AF9)>, /* SDMMC2_D0 */
-					 <STM32_PINMUX('B', 15, AF9)>; /* SDMMC2_D1 */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('E', 3, AF9)>; /* SDMMC2_CK */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins3 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('G', 6, AF10)>; /* SDMMC2_CMD */
-			bias-pull-up;
-			drive-open-drain;
-			slew-rate = <1>;
-		};
-	};
-
-	sdmmc2_sleep_pins_mx: sdmmc2_sleep_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 3, ANALOG)>, /* SDMMC2_D2 */
-					 <STM32_PINMUX('B', 4, ANALOG)>, /* SDMMC2_D3 */
-					 <STM32_PINMUX('B', 14, ANALOG)>, /* SDMMC2_D0 */
-					 <STM32_PINMUX('B', 15, ANALOG)>, /* SDMMC2_D1 */
-					 <STM32_PINMUX('E', 3, ANALOG)>, /* SDMMC2_CK */
-					 <STM32_PINMUX('G', 6, ANALOG)>; /* SDMMC2_CMD */
-		};
-	};
-
-	tim1_pwm_pins_mx: tim1_pwm_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 9, AF1)>; /* TIM1_CH2 */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-	};
-
-	tim1_pwm_sleep_pins_mx: tim1_pwm_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 9, ANALOG)>; /* TIM1_CH2 */
-		};
-	};
-
-	tim4_pwm_pins_mx: tim4_pwm_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('D', 14, AF2)>; /* TIM4_CH3 */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-	};
-
-	tim4_pwm_sleep_pins_mx: tim4_pwm_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('D', 14, ANALOG)>; /* TIM4_CH3 */
-		};
-	};
-
-	uart4_pins_mx: uart4_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 2, AF8)>; /* UART4_RX */
-			bias-pull-up;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('G', 11, AF6)>; /* UART4_TX */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-	};
-
-	uart4_sleep_pins_mx: uart4_sleep_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 2, ANALOG)>, /* UART4_RX */
-					 <STM32_PINMUX('G', 11, ANALOG)>; /* UART4_TX */
-		};
-	};
-
-	usart2_pins_mx: usart2_mx-0 {
-		pins1 {
-			pinmux = <STM32_PINMUX('D', 4, AF7)>; /* USART2_RTS */
-			bias-pull-down;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-		pins2 {
-			pinmux = <STM32_PINMUX('D', 5, AF7)>; /* USART2_TX */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-		pins3 {
-			pinmux = <STM32_PINMUX('D', 6, AF7)>; /* USART2_RX */
-			bias-pull-up;
-		};
-	};
-
-	usart2_sleep_pins_mx: usart2_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('D', 4, ANALOG)>, /* USART2_RTS */
-					 <STM32_PINMUX('D', 5, ANALOG)>, /* USART2_TX */
-					 <STM32_PINMUX('D', 6, ANALOG)>; /* USART2_RX */
-		};
-	};
-
-	usart3_pins_mx: usart3_mx-0 {
-		pins1 {
-			pinmux = <STM32_PINMUX('D', 9, AF7)>, /* USART3_RX */
-					 <STM32_PINMUX('D', 11, AF7)>; /* USART3_CTS */
-			bias-disable;
-		};
-		pins2 {
-			pinmux = <STM32_PINMUX('D', 8, AF7)>, /* USART3_TX */
-					 <STM32_PINMUX('D', 12, AF7)>; /* USART3_RTS */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-	};
-
-	usart3_sleep_pins_mx: usart3_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('D', 8, ANALOG)>, /* USART3_TX */
-					 <STM32_PINMUX('D', 9, ANALOG)>, /* USART3_RX */
-					 <STM32_PINMUX('D', 11, ANALOG)>, /* USART3_CTS */
-					 <STM32_PINMUX('D', 12, ANALOG)>; /* USART3_RTS */
-		};
-	};
-
-	usb_otg_hs_pins_mx: usb_otg_hs_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
-		};
-	};
-
-	usb_otg_hs_sleep_pins_mx: usb_otg_hs_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
-		};
-	};
-
-	/* USER CODE BEGIN pinctrl */
-	/* USER CODE END pinctrl */
-};
-
-&pinctrl_z {
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN pinctrl_z */
-	/* USER CODE END pinctrl_z */
-};
-
-&m4_rproc{
-	mboxes = <&ipcc 0>, <&ipcc 1>, <&ipcc 2>;
-	mbox-names = "vq0", "vq1", "shutdown";
-	recovery;
-	status = "okay";
-
-	/* USER CODE BEGIN m4_rproc */
-	/* USER CODE END m4_rproc */
-};
-
-&adc{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&adc_pins_mx>;
-	pinctrl-1 = <&adc_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN adc */
-	/* USER CODE END adc */
-};
-
-&bsec{
-	status = "okay";
-
-	/* USER CODE BEGIN bsec */
-	/* USER CODE END bsec */
-};
-
-&crc1{
-	status = "okay";
-
-	/* USER CODE BEGIN crc1 */
-	/* USER CODE END crc1 */
-};
-
-&cryp1{
-	status = "okay";
-
-	/* USER CODE BEGIN cryp1 */
-	/* USER CODE END cryp1 */
-};
-
-&dts{
-	status = "okay";
-
-	/* USER CODE BEGIN dts */
-	/* USER CODE END dts */
-};
-
-&ethernet0{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&eth1_pins_mx>;
-	pinctrl-1 = <&eth1_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN ethernet0 */
-	/* USER CODE END ethernet0 */
-};
-
-&gpu{
-	status = "okay";
-
-	/* USER CODE BEGIN gpu */
-	/* USER CODE END gpu */
-};
-
-&hash1{
-	status = "okay";
-
-	/* USER CODE BEGIN hash1 */
-	/* USER CODE END hash1 */
-};
-
-&hsem{
-	status = "okay";
-
-	/* USER CODE BEGIN hsem */
-	/* USER CODE END hsem */
-};
-
-&i2c2{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&i2c2_pins_mx>;
-	pinctrl-1 = <&i2c2_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN i2c2 */
-	/* USER CODE END i2c2 */
-};
-
-&i2c4{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&i2c4_pins_mx>;
-	pinctrl-1 = <&i2c4_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN i2c4 */
-	/* USER CODE END i2c4 */
-};
-
-&ipcc{
-	status = "okay";
-
-	/* USER CODE BEGIN ipcc */
-	/* USER CODE END ipcc */
-};
-
-&ltdc{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&ltdc_pins_mx>;
-	pinctrl-1 = <&ltdc_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN ltdc */
-	/* USER CODE END ltdc */
-};
-
-&m_can1{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&fdcan1_pins_mx>;
-	pinctrl-1 = <&fdcan1_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN m_can1 */
-	/* USER CODE END m_can1 */
-};
-
-&qspi{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&quadspi_pins_mx>;
-	pinctrl-1 = <&quadspi_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN qspi */
-	/* USER CODE END qspi */
-};
-
-&rcc{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN rcc */
-	/* USER CODE END rcc */
-};
-
-&rng1{
-	status = "okay";
-
-	/* USER CODE BEGIN rng1 */
-	/* USER CODE END rng1 */
-};
-
-&rtc{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&rtc_pins_mx>;
-	pinctrl-1 = <&rtc_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN rtc */
-	/* USER CODE END rtc */
-};
-
-&sdmmc1{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "opendrain", "sleep";
-	pinctrl-0 = <&sdmmc1_pins_mx>;
-	pinctrl-1 = <&sdmmc1_opendrain_pins_mx>;
-	pinctrl-2 = <&sdmmc1_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN sdmmc1 */
-	/* USER CODE END sdmmc1 */
-};
-
-&sdmmc2{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "opendrain", "sleep";
-	pinctrl-0 = <&sdmmc2_pins_mx>;
-	pinctrl-1 = <&sdmmc2_opendrain_pins_mx>;
-	pinctrl-2 = <&sdmmc2_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN sdmmc2 */
-	/* USER CODE END sdmmc2 */
-};
-
-&timers1{
-	status = "okay";
-
-	/* USER CODE BEGIN timers1 */
-	/* USER CODE END timers1 */
-
-	pwm{
-		pinctrl-names = "default", "sleep";
-		pinctrl-0 = <&tim1_pwm_pins_mx>;
-		pinctrl-1 = <&tim1_pwm_sleep_pins_mx>;
-		status = "okay";
-
-		/* USER CODE BEGIN timers1_pwm */
-		/* USER CODE END timers1_pwm */
-	};
-};
-
-&timers4{
-	status = "okay";
-
-	/* USER CODE BEGIN timers4 */
-	/* USER CODE END timers4 */
-
-	pwm{
-		pinctrl-names = "default", "sleep";
-		pinctrl-0 = <&tim4_pwm_pins_mx>;
-		pinctrl-1 = <&tim4_pwm_sleep_pins_mx>;
-		status = "okay";
-
-		/* USER CODE BEGIN timers4_pwm */
-		/* USER CODE END timers4_pwm */
-	};
-};
-
-&uart4{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&uart4_pins_mx>;
-	pinctrl-1 = <&uart4_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN uart4 */
-	/* USER CODE END uart4 */
-};
-
-&usart2{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&usart2_pins_mx>;
-	pinctrl-1 = <&usart2_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN usart2 */
-	/* USER CODE END usart2 */
-};
-
-&usart3{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&usart3_pins_mx>;
-	pinctrl-1 = <&usart3_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN usart3 */
-	/* USER CODE END usart3 */
-};
-
-&usbh_ehci{
-	status = "okay";
-
-	/* USER CODE BEGIN usbh_ehci */
-	/* USER CODE END usbh_ehci */
-};
-
-&usbh_ohci{
-	status = "okay";
-
-	/* USER CODE BEGIN usbh_ohci */
-	/* USER CODE END usbh_ohci */
-};
-
-&usbotg_hs{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&usb_otg_hs_pins_mx>;
-	pinctrl-1 = <&usb_otg_hs_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN usbotg_hs */
-	/* USER CODE END usbotg_hs */
-};
-
-&usbphyc{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc */
-	/* USER CODE END usbphyc */
-};
-
-&usbphyc_port0{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc_port0 */
-	/* USER CODE END usbphyc_port0 */
-};
-
-&usbphyc_port1{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc_port1 */
-	/* USER CODE END usbphyc_port1 */
-};
-
-&vrefbuf{
-	status = "okay";
-
-	/* USER CODE BEGIN vrefbuf */
-	/* USER CODE END vrefbuf */
-};
-
-/* USER CODE BEGIN addons */
-/* USER CODE END addons */
-
diff --git a/recipes-kernel/linux/linux-stm32mp/bleeding/stm32mp157c-t1000-som-minimal-mx.dts b/recipes-kernel/linux/linux-stm32mp/bleeding/stm32mp157c-t1000-som-minimal-mx.dts
deleted file mode 100644
index 27a7de735406905b7bd36c68bb8e00c226141311..0000000000000000000000000000000000000000
--- a/recipes-kernel/linux/linux-stm32mp/bleeding/stm32mp157c-t1000-som-minimal-mx.dts
+++ /dev/null
@@ -1,518 +0,0 @@
-/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
-/*
- * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
- * Author: STM32CubeMX code generation for STMicroelectronics.
- */
-
-/dts-v1/;
-#include "stm32mp157c.dtsi"
-#include "stm32mp157cad-pinctrl.dtsi"
-#include "stm32mp157c-m4-srm.dtsi"
-
-/* USER CODE BEGIN includes */
-/* USER CODE END includes */
-
-/ {
-	model = "STMicroelectronics custom STM32CubeMX board";
-	compatible = "st,stm32mp157c-t1000-som-minimal-mx", "st,stm32mp157";
-
-	memory@c0000000 {
-		reg = <0xc0000000 0x20000000>;
-
-		/* USER CODE BEGIN memory */
-		/* USER CODE END memory */
-	};
-
-	reserved-memory {
-		#address-cells = <1>;
-		#size-cells = <1>;
-		ranges;
-
-		/* USER CODE BEGIN reserved-memory */
-		/* USER CODE END reserved-memory */
-
-		gpu_reserved: gpu@dc000000 {
-			reg = <0xdc000000 0x4000000>;
-			no-map;
-		};
-	};
-
-	/* USER CODE BEGIN root */
-	/* USER CODE END root */
-
-	clocks {
-		/* USER CODE BEGIN clocks */
-		/* USER CODE END clocks */
-
-		clk_hsi: clk-hsi {
-			clock-frequency = <64000000>;
-		};
-
-		clk_csi: clk-csi {
-			clock-frequency = <4000000>;
-		};
-
-		clk_lse: clk-lse {
-			clock-frequency = <32768>;
-		};
-
-		clk_hse: clk-hse {
-			clock-frequency = <24000000>;
-		};
-	};
-
-}; /*root*/
-
-&pinctrl {
-	u-boot,dm-pre-reloc;
-
-	eth1_pins_mx: eth1_mx-0 {
-		pins1 {
-			pinmux = <STM32_PINMUX('A', 2, AF11)>; /* ETH1_MDIO */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-		pins2 {
-			pinmux = <STM32_PINMUX('A', 7, AF11)>, /* ETH1_CRS_DV */
-					 <STM32_PINMUX('C', 4, AF11)>, /* ETH1_RXD0 */
-					 <STM32_PINMUX('C', 5, AF11)>; /* ETH1_RXD1 */
-			bias-disable;
-		};
-		pins3 {
-			pinmux = <STM32_PINMUX('B', 11, AF11)>; /* ETH1_TX_EN */
-		};
-		pins4 {
-			pinmux = <STM32_PINMUX('B', 12, AF11)>, /* ETH1_TXD0 */
-					 <STM32_PINMUX('B', 13, AF11)>, /* ETH1_TXD1 */
-					 <STM32_PINMUX('C', 1, AF11)>, /* ETH1_MDC */
-					 <STM32_PINMUX('G', 8, AF2)>; /* ETH1_CLK */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-	};
-
-	eth1_sleep_pins_mx: eth1_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 2, ANALOG)>, /* ETH1_MDIO */
-					 <STM32_PINMUX('A', 7, ANALOG)>, /* ETH1_CRS_DV */
-					 <STM32_PINMUX('B', 11, ANALOG)>, /* ETH1_TX_EN */
-					 <STM32_PINMUX('B', 12, ANALOG)>, /* ETH1_TXD0 */
-					 <STM32_PINMUX('B', 13, ANALOG)>, /* ETH1_TXD1 */
-					 <STM32_PINMUX('C', 1, ANALOG)>, /* ETH1_MDC */
-					 <STM32_PINMUX('C', 4, ANALOG)>, /* ETH1_RXD0 */
-					 <STM32_PINMUX('C', 5, ANALOG)>, /* ETH1_RXD1 */
-					 <STM32_PINMUX('G', 8, ANALOG)>; /* ETH1_CLK */
-		};
-	};
-
-	i2c2_pins_mx: i2c2_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('D', 7, AF4)>, /* I2C2_SCL */
-					 <STM32_PINMUX('G', 15, AF4)>; /* I2C2_SDA */
-			bias-disable;
-			drive-open-drain;
-			slew-rate = <0>;
-		};
-	};
-
-	i2c2_sleep_pins_mx: i2c2_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('D', 7, ANALOG)>, /* I2C2_SCL */
-					 <STM32_PINMUX('G', 15, ANALOG)>; /* I2C2_SDA */
-		};
-	};
-
-	quadspi_pins_mx: quadspi_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 6, AF10)>, /* QUADSPI_BK1_NCS */
-					 <STM32_PINMUX('C', 0, AF10)>; /* QUADSPI_BK2_NCS */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('E', 7, AF10)>, /* QUADSPI_BK2_IO0 */
-					 <STM32_PINMUX('E', 8, AF10)>, /* QUADSPI_BK2_IO1 */
-					 <STM32_PINMUX('E', 9, AF10)>, /* QUADSPI_BK2_IO2 */
-					 <STM32_PINMUX('E', 10, AF10)>, /* QUADSPI_BK2_IO3 */
-					 <STM32_PINMUX('F', 6, AF9)>, /* QUADSPI_BK1_IO3 */
-					 <STM32_PINMUX('F', 7, AF9)>, /* QUADSPI_BK1_IO2 */
-					 <STM32_PINMUX('F', 8, AF10)>, /* QUADSPI_BK1_IO0 */
-					 <STM32_PINMUX('F', 9, AF10)>; /* QUADSPI_BK1_IO1 */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins3 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('F', 10, AF9)>; /* QUADSPI_CLK */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <2>;
-		};
-	};
-
-	quadspi_sleep_pins_mx: quadspi_sleep_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 6, ANALOG)>, /* QUADSPI_BK1_NCS */
-					 <STM32_PINMUX('C', 0, ANALOG)>, /* QUADSPI_BK2_NCS */
-					 <STM32_PINMUX('E', 7, ANALOG)>, /* QUADSPI_BK2_IO0 */
-					 <STM32_PINMUX('E', 8, ANALOG)>, /* QUADSPI_BK2_IO1 */
-					 <STM32_PINMUX('E', 9, ANALOG)>, /* QUADSPI_BK2_IO2 */
-					 <STM32_PINMUX('E', 10, ANALOG)>, /* QUADSPI_BK2_IO3 */
-					 <STM32_PINMUX('F', 6, ANALOG)>, /* QUADSPI_BK1_IO3 */
-					 <STM32_PINMUX('F', 7, ANALOG)>, /* QUADSPI_BK1_IO2 */
-					 <STM32_PINMUX('F', 8, ANALOG)>, /* QUADSPI_BK1_IO0 */
-					 <STM32_PINMUX('F', 9, ANALOG)>, /* QUADSPI_BK1_IO1 */
-					 <STM32_PINMUX('F', 10, ANALOG)>; /* QUADSPI_CLK */
-		};
-	};
-
-	rtc_pins_mx: rtc_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('C', 13, ANALOG)>; /* RTC_LSCO */
-		};
-	};
-
-	rtc_sleep_pins_mx: rtc_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('C', 13, ANALOG)>; /* RTC_LSCO */
-		};
-	};
-
-	sdmmc1_pins_mx: sdmmc1_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
-					 <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
-					 <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
-					 <STM32_PINMUX('C', 11, AF12)>, /* SDMMC1_D3 */
-					 <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 12, AF12)>; /* SDMMC1_CK */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-	};
-
-	sdmmc1_opendrain_pins_mx: sdmmc1_opendrain_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
-					 <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
-					 <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
-					 <STM32_PINMUX('C', 11, AF12)>; /* SDMMC1_D3 */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 12, AF12)>; /* SDMMC1_CK */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins3 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
-			bias-pull-up;
-			drive-open-drain;
-			slew-rate = <1>;
-		};
-	};
-
-	sdmmc1_sleep_pins_mx: sdmmc1_sleep_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 8, ANALOG)>, /* SDMMC1_D0 */
-					 <STM32_PINMUX('C', 9, ANALOG)>, /* SDMMC1_D1 */
-					 <STM32_PINMUX('C', 10, ANALOG)>, /* SDMMC1_D2 */
-					 <STM32_PINMUX('C', 11, ANALOG)>, /* SDMMC1_D3 */
-					 <STM32_PINMUX('C', 12, ANALOG)>, /* SDMMC1_CK */
-					 <STM32_PINMUX('D', 2, ANALOG)>; /* SDMMC1_CMD */
-		};
-	};
-
-	uart4_pins_mx: uart4_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 2, AF8)>; /* UART4_RX */
-			bias-pull-up;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('G', 11, AF6)>; /* UART4_TX */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-	};
-
-	uart4_sleep_pins_mx: uart4_sleep_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 2, ANALOG)>, /* UART4_RX */
-					 <STM32_PINMUX('G', 11, ANALOG)>; /* UART4_TX */
-		};
-	};
-
-	usb_otg_hs_pins_mx: usb_otg_hs_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
-		};
-	};
-
-	usb_otg_hs_sleep_pins_mx: usb_otg_hs_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
-		};
-	};
-
-	/* USER CODE BEGIN pinctrl */
-	/* USER CODE END pinctrl */
-};
-
-&pinctrl_z {
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN pinctrl_z */
-	/* USER CODE END pinctrl_z */
-};
-
-&m4_rproc{
-	mboxes = <&ipcc 0>, <&ipcc 1>, <&ipcc 2>;
-	mbox-names = "vq0", "vq1", "shutdown";
-	recovery;
-	status = "okay";
-
-	/* USER CODE BEGIN m4_rproc */
-	/* USER CODE END m4_rproc */
-};
-
-&adc{
-	status = "okay";
-
-	/* USER CODE BEGIN adc */
-	/* USER CODE END adc */
-};
-
-&bsec{
-	status = "okay";
-
-	/* USER CODE BEGIN bsec */
-	/* USER CODE END bsec */
-};
-
-&crc1{
-	status = "okay";
-
-	/* USER CODE BEGIN crc1 */
-	/* USER CODE END crc1 */
-};
-
-&cryp1{
-	status = "okay";
-
-	/* USER CODE BEGIN cryp1 */
-	/* USER CODE END cryp1 */
-};
-
-&dts{
-	status = "okay";
-
-	/* USER CODE BEGIN dts */
-	/* USER CODE END dts */
-};
-
-&ethernet0{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&eth1_pins_mx>;
-	pinctrl-1 = <&eth1_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN ethernet0 */
-	/* USER CODE END ethernet0 */
-};
-
-&gpu{
-	status = "okay";
-
-	/* USER CODE BEGIN gpu */
-	/* USER CODE END gpu */
-};
-
-&hash1{
-	status = "okay";
-
-	/* USER CODE BEGIN hash1 */
-	/* USER CODE END hash1 */
-};
-
-&hsem{
-	status = "okay";
-
-	/* USER CODE BEGIN hsem */
-	/* USER CODE END hsem */
-};
-
-&i2c2{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&i2c2_pins_mx>;
-	pinctrl-1 = <&i2c2_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN i2c2 */
-	/* USER CODE END i2c2 */
-};
-
-&ipcc{
-	status = "okay";
-
-	/* USER CODE BEGIN ipcc */
-	/* USER CODE END ipcc */
-};
-
-&iwdg2{
-	status = "okay";
-
-	/* USER CODE BEGIN iwdg2 */
-	/* USER CODE END iwdg2 */
-};
-
-&qspi{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&quadspi_pins_mx>;
-	pinctrl-1 = <&quadspi_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN qspi */
-	/* USER CODE END qspi */
-};
-
-&rcc{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN rcc */
-	/* USER CODE END rcc */
-};
-
-&rng1{
-	status = "okay";
-
-	/* USER CODE BEGIN rng1 */
-	/* USER CODE END rng1 */
-};
-
-&rtc{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&rtc_pins_mx>;
-	pinctrl-1 = <&rtc_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN rtc */
-	/* USER CODE END rtc */
-};
-
-&sdmmc1{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "opendrain", "sleep";
-	pinctrl-0 = <&sdmmc1_pins_mx>;
-	pinctrl-1 = <&sdmmc1_opendrain_pins_mx>;
-	pinctrl-2 = <&sdmmc1_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN sdmmc1 */
-	/* USER CODE END sdmmc1 */
-};
-
-&uart4{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&uart4_pins_mx>;
-	pinctrl-1 = <&uart4_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN uart4 */
-	/* USER CODE END uart4 */
-};
-
-&usbh_ehci{
-	status = "okay";
-
-	/* USER CODE BEGIN usbh_ehci */
-	/* USER CODE END usbh_ehci */
-};
-
-&usbh_ohci{
-	status = "okay";
-
-	/* USER CODE BEGIN usbh_ohci */
-	/* USER CODE END usbh_ohci */
-};
-
-&usbotg_hs{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&usb_otg_hs_pins_mx>;
-	pinctrl-1 = <&usb_otg_hs_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN usbotg_hs */
-	/* USER CODE END usbotg_hs */
-};
-
-&usbphyc{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc */
-	/* USER CODE END usbphyc */
-};
-
-&usbphyc_port0{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc_port0 */
-	/* USER CODE END usbphyc_port0 */
-};
-
-&usbphyc_port1{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc_port1 */
-	/* USER CODE END usbphyc_port1 */
-};
-
-&vrefbuf{
-	status = "okay";
-
-	/* USER CODE BEGIN vrefbuf */
-	/* USER CODE END vrefbuf */
-};
-
-/* USER CODE BEGIN addons */
-/* USER CODE END addons */
-
diff --git a/recipes-kernel/linux/linux-stm32mp/bleeding/stm32mp157c-t1001-som-minimal-mx.dts b/recipes-kernel/linux/linux-stm32mp/bleeding/stm32mp157c-t1001-som-minimal-mx.dts
deleted file mode 100644
index a648a9ba1245e93eca38a53eea209c4c9049a737..0000000000000000000000000000000000000000
--- a/recipes-kernel/linux/linux-stm32mp/bleeding/stm32mp157c-t1001-som-minimal-mx.dts
+++ /dev/null
@@ -1,405 +0,0 @@
-/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
-/*
- * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
- * Author: STM32CubeMX code generation for STMicroelectronics.
- */
-
-/dts-v1/;
-#include "stm32mp157c.dtsi"
-#include "stm32mp157cad-pinctrl.dtsi"
-#include "stm32mp157c-m4-srm.dtsi"
-
-/* USER CODE BEGIN includes */
-/* USER CODE END includes */
-
-/ {
-	model = "STMicroelectronics custom STM32CubeMX board";
-	compatible = "st,stm32mp157c-t1001-som-minimal-mx", "st,stm32mp157";
-
-	memory@c0000000 {
-		reg = <0xc0000000 0x20000000>;
-
-		/* USER CODE BEGIN memory */
-		/* USER CODE END memory */
-	};
-
-	reserved-memory {
-		#address-cells = <1>;
-		#size-cells = <1>;
-		ranges;
-
-		/* USER CODE BEGIN reserved-memory */
-		/* USER CODE END reserved-memory */
-
-		gpu_reserved: gpu@dc000000 {
-			reg = <0xdc000000 0x4000000>;
-			no-map;
-		};
-	};
-
-	/* USER CODE BEGIN root */
-	/* USER CODE END root */
-
-	clocks {
-		/* USER CODE BEGIN clocks */
-		/* USER CODE END clocks */
-
-		clk_csi: clk-csi {
-			clock-frequency = <4000000>;
-		};
-
-		clk_lse: clk-lse {
-			clock-frequency = <32768>;
-		};
-
-		clk_hse: clk-hse {
-			clock-frequency = <24000000>;
-		};
-	};
-
-}; /*root*/
-
-&pinctrl {
-	u-boot,dm-pre-reloc;
-
-	quadspi_pins_mx: quadspi_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 6, AF10)>; /* QUADSPI_BK1_NCS */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('F', 6, AF9)>, /* QUADSPI_BK1_IO3 */
-					 <STM32_PINMUX('F', 7, AF9)>, /* QUADSPI_BK1_IO2 */
-					 <STM32_PINMUX('F', 8, AF10)>, /* QUADSPI_BK1_IO0 */
-					 <STM32_PINMUX('F', 9, AF10)>, /* QUADSPI_BK1_IO1 */
-					 <STM32_PINMUX('F', 10, AF9)>; /* QUADSPI_CLK */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-	};
-
-	quadspi_sleep_pins_mx: quadspi_sleep_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 6, ANALOG)>, /* QUADSPI_BK1_NCS */
-					 <STM32_PINMUX('F', 6, ANALOG)>, /* QUADSPI_BK1_IO3 */
-					 <STM32_PINMUX('F', 7, ANALOG)>, /* QUADSPI_BK1_IO2 */
-					 <STM32_PINMUX('F', 8, ANALOG)>, /* QUADSPI_BK1_IO0 */
-					 <STM32_PINMUX('F', 9, ANALOG)>, /* QUADSPI_BK1_IO1 */
-					 <STM32_PINMUX('F', 10, ANALOG)>; /* QUADSPI_CLK */
-		};
-	};
-
-	sdmmc1_pins_mx: sdmmc1_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
-					 <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
-					 <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
-					 <STM32_PINMUX('C', 11, AF12)>, /* SDMMC1_D3 */
-					 <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 12, AF12)>; /* SDMMC1_CK */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-	};
-
-	sdmmc1_opendrain_pins_mx: sdmmc1_opendrain_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
-					 <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
-					 <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
-					 <STM32_PINMUX('C', 11, AF12)>; /* SDMMC1_D3 */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 12, AF12)>; /* SDMMC1_CK */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins3 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
-			bias-pull-up;
-			drive-open-drain;
-			slew-rate = <1>;
-		};
-	};
-
-	sdmmc1_sleep_pins_mx: sdmmc1_sleep_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 8, ANALOG)>, /* SDMMC1_D0 */
-					 <STM32_PINMUX('C', 9, ANALOG)>, /* SDMMC1_D1 */
-					 <STM32_PINMUX('C', 10, ANALOG)>, /* SDMMC1_D2 */
-					 <STM32_PINMUX('C', 11, ANALOG)>, /* SDMMC1_D3 */
-					 <STM32_PINMUX('C', 12, ANALOG)>, /* SDMMC1_CK */
-					 <STM32_PINMUX('D', 2, ANALOG)>; /* SDMMC1_CMD */
-		};
-	};
-
-	uart4_pins_mx: uart4_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 2, AF8)>; /* UART4_RX */
-			bias-pull-up;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('G', 11, AF6)>; /* UART4_TX */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-	};
-
-	uart4_sleep_pins_mx: uart4_sleep_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 2, ANALOG)>, /* UART4_RX */
-					 <STM32_PINMUX('G', 11, ANALOG)>; /* UART4_TX */
-		};
-	};
-
-	usb_otg_hs_pins_mx: usb_otg_hs_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
-		};
-	};
-
-	usb_otg_hs_sleep_pins_mx: usb_otg_hs_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
-		};
-	};
-
-	/* USER CODE BEGIN pinctrl */
-	/* USER CODE END pinctrl */
-};
-
-&pinctrl_z {
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN pinctrl_z */
-	/* USER CODE END pinctrl_z */
-};
-
-&m4_rproc{
-	mboxes = <&ipcc 0>, <&ipcc 1>, <&ipcc 2>;
-	mbox-names = "vq0", "vq1", "shutdown";
-	recovery;
-	status = "okay";
-
-	/* USER CODE BEGIN m4_rproc */
-	/* USER CODE END m4_rproc */
-};
-
-&adc{
-	status = "okay";
-
-	/* USER CODE BEGIN adc */
-	/* USER CODE END adc */
-};
-
-&bsec{
-	status = "okay";
-
-	/* USER CODE BEGIN bsec */
-	/* USER CODE END bsec */
-};
-
-&crc1{
-	status = "okay";
-
-	/* USER CODE BEGIN crc1 */
-	/* USER CODE END crc1 */
-};
-
-&cryp1{
-	status = "okay";
-
-	/* USER CODE BEGIN cryp1 */
-	/* USER CODE END cryp1 */
-};
-
-&dts{
-	status = "okay";
-
-	/* USER CODE BEGIN dts */
-	/* USER CODE END dts */
-};
-
-&gpu{
-	status = "okay";
-
-	/* USER CODE BEGIN gpu */
-	/* USER CODE END gpu */
-};
-
-&hash1{
-	status = "okay";
-
-	/* USER CODE BEGIN hash1 */
-	/* USER CODE END hash1 */
-};
-
-&hsem{
-	status = "okay";
-
-	/* USER CODE BEGIN hsem */
-	/* USER CODE END hsem */
-};
-
-&ipcc{
-	status = "okay";
-
-	/* USER CODE BEGIN ipcc */
-	/* USER CODE END ipcc */
-};
-
-&iwdg2{
-	status = "okay";
-
-	/* USER CODE BEGIN iwdg2 */
-	/* USER CODE END iwdg2 */
-};
-
-&qspi{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&quadspi_pins_mx>;
-	pinctrl-1 = <&quadspi_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN qspi */
-	/* USER CODE END qspi */
-};
-
-&rcc{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN rcc */
-	/* USER CODE END rcc */
-};
-
-&rng1{
-	status = "okay";
-
-	/* USER CODE BEGIN rng1 */
-	/* USER CODE END rng1 */
-};
-
-&rtc{
-	status = "okay";
-
-	/* USER CODE BEGIN rtc */
-	/* USER CODE END rtc */
-};
-
-&sdmmc1{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "opendrain", "sleep";
-	pinctrl-0 = <&sdmmc1_pins_mx>;
-	pinctrl-1 = <&sdmmc1_opendrain_pins_mx>;
-	pinctrl-2 = <&sdmmc1_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN sdmmc1 */
-	/* USER CODE END sdmmc1 */
-};
-
-&uart4{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&uart4_pins_mx>;
-	pinctrl-1 = <&uart4_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN uart4 */
-	/* USER CODE END uart4 */
-};
-
-&usbh_ehci{
-	status = "okay";
-
-	/* USER CODE BEGIN usbh_ehci */
-	/* USER CODE END usbh_ehci */
-};
-
-&usbh_ohci{
-	status = "okay";
-
-	/* USER CODE BEGIN usbh_ohci */
-	/* USER CODE END usbh_ohci */
-};
-
-&usbotg_hs{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&usb_otg_hs_pins_mx>;
-	pinctrl-1 = <&usb_otg_hs_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN usbotg_hs */
-	/* USER CODE END usbotg_hs */
-};
-
-&usbphyc{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc */
-	/* USER CODE END usbphyc */
-};
-
-&usbphyc_port0{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc_port0 */
-	/* USER CODE END usbphyc_port0 */
-};
-
-&usbphyc_port1{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc_port1 */
-	/* USER CODE END usbphyc_port1 */
-};
-
-&vrefbuf{
-	status = "okay";
-
-	/* USER CODE BEGIN vrefbuf */
-	/* USER CODE END vrefbuf */
-};
-
-/* USER CODE BEGIN addons */
-/* USER CODE END addons */
-
diff --git a/recipes-kernel/linux/linux-stm32mp/download-kernelpatches.sh b/recipes-kernel/linux/linux-stm32mp/download-kernelpatches.sh
deleted file mode 100644
index 1c72ddad67f2937a207f2b1b24d350ec506fcc1a..0000000000000000000000000000000000000000
--- a/recipes-kernel/linux/linux-stm32mp/download-kernelpatches.sh
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/sh
-cd patches
-startwith=49
-endwith=288
-i=$startwith
-count=1000
-echo PATCHLIST = \"\\ > ../kernelpatches.bbappend
-while([ "$i" -lt "$((endwith))" ])
-do
-  echo $i-$((i + 1))
-  curl https://cdn.kernel.org/pub/linux/kernel/v4.x/incr/patch-4.19.$i-$((i + 1)).xz -o patch-4.19.$i-$((i + 1)).xz
-  xz -d -v patch-4.19.$i-$((i + 1)).xz
-  mv patch-4.19.$i-$((i + 1)) ${count}-patch-4.19.$i-$((i + 1)).patch
-  echo "	 file://patches/${count}-patch-4.19.$i-$((i + 1)).patch \\" >> ../kernelpatches.bbappend 
-  i=$((i+1))
-  count=$((count+1))
-done 
-echo "	\"" >> ../kernelpatches.bbappend
-#https://cdn.kernel.org/pub/linux/kernel/v4.x/incr/patch-4.19.49-50.xz
-
diff --git a/recipes-kernel/linux/linux-stm32mp/kernelpatches.bbappend b/recipes-kernel/linux/linux-stm32mp/kernelpatches.bbappend
deleted file mode 100644
index 193559453fce30d3b046cc01b2d87567c29f3b2d..0000000000000000000000000000000000000000
--- a/recipes-kernel/linux/linux-stm32mp/kernelpatches.bbappend
+++ /dev/null
@@ -1,241 +0,0 @@
-PATCHLIST = "\
-	 file://patches/1000-patch-4.19.49-50.patch \
-	 file://patches/1001-patch-4.19.50-51.patch \
-	 file://patches/1002-patch-4.19.51-52.patch \
-	 file://patches/1003-patch-4.19.52-53.patch \
-	 file://patches/1004-patch-4.19.53-54.patch \
-	 file://patches/1005-patch-4.19.54-55.patch \
-	 file://patches/1006-patch-4.19.55-56.patch \
-	 file://patches/1007-patch-4.19.56-57.patch \
-	 file://patches/1008-patch-4.19.57-58.patch \
-	 file://patches/1009-patch-4.19.58-59.patch \
-	 file://patches/1010-patch-4.19.59-60.patch \
-	 file://patches/1011-patch-4.19.60-61.patch \
-	 file://patches/1012-patch-4.19.61-62.patch \
-	 file://patches/1013-patch-4.19.62-63.patch \
-	 file://patches/1014-patch-4.19.63-64.patch \
-	 file://patches/1015-patch-4.19.64-65.patch \
-	 file://patches/1016-patch-4.19.65-66.patch \
-	 file://patches/1017-patch-4.19.66-67.patch \
-	 file://patches/1018-patch-4.19.67-68.patch \
-	 file://patches/1019-patch-4.19.68-69.patch \
-	 file://patches/1020-patch-4.19.69-70.patch \
-	 file://patches/1021-patch-4.19.70-71.patch \
-	 file://patches/1022-patch-4.19.71-72.patch \
-	 file://patches/1023-patch-4.19.72-73.patch \
-	 file://patches/1024-patch-4.19.73-74.patch \
-	 file://patches/1025-patch-4.19.74-75.patch \
-	 file://patches/1026-patch-4.19.75-76.patch \
-	 file://patches/1027-patch-4.19.76-77.patch \
-	 file://patches/1028-patch-4.19.77-78.patch \
-	 file://patches/1029-patch-4.19.78-79.patch \
-	 file://patches/1030-patch-4.19.79-80.patch \
-	 file://patches/1031-patch-4.19.80-81.patch \
-	 file://patches/1032-patch-4.19.81-82.patch \
-	 file://patches/1033-patch-4.19.82-83.patch \
-	 file://patches/1034-patch-4.19.83-84.patch \
-	 file://patches/1035-patch-4.19.84-85.patch \
-	 file://patches/1036-patch-4.19.85-86.patch \
-	 file://patches/1037-patch-4.19.86-87.patch \
-	 file://patches/1038-patch-4.19.87-88.patch \
-	 file://patches/1039-patch-4.19.88-89.patch \
-	 file://patches/1040-patch-4.19.89-90.patch \
-	 file://patches/1041-patch-4.19.90-91.patch \
-	 file://patches/1042-patch-4.19.91-92.patch \
-	 file://patches/1043-patch-4.19.92-93.patch \
-	 file://patches/1044-patch-4.19.93-94.patch \
-	 file://patches/1045-patch-4.19.94-95.patch \
-	 file://patches/1046-patch-4.19.95-96.patch \
-	 file://patches/1047-patch-4.19.96-97.patch \
-	 file://patches/1048-patch-4.19.97-98.patch \
-	 file://patches/1049-patch-4.19.98-99.patch \
-	 file://patches/1050-patch-4.19.99-100.patch \
-	 file://patches/1051-patch-4.19.100-101.patch \
-	 file://patches/1052-patch-4.19.101-102.patch \
-	 file://patches/1053-patch-4.19.102-103.patch \
-	 file://patches/1054-patch-4.19.103-104.patch \
-	 file://patches/1055-patch-4.19.104-105.patch \
-	 file://patches/1056-patch-4.19.105-106.patch \
-	 file://patches/1057-patch-4.19.106-107.patch \
-	 file://patches/1058-patch-4.19.107-108.patch \
-	 file://patches/1059-patch-4.19.108-109.patch \
-	 file://patches/1060-patch-4.19.109-110.patch \
-	 file://patches/1061-patch-4.19.110-111.patch \
-	 file://patches/1062-patch-4.19.111-112.patch \
-	 file://patches/1063-patch-4.19.112-113.patch \
-	 file://patches/1064-patch-4.19.113-114.patch \
-	 file://patches/1065-patch-4.19.114-115.patch \
-	 file://patches/1066-patch-4.19.115-116.patch \
-	 file://patches/1067-patch-4.19.116-117.patch \
-	 file://patches/1068-patch-4.19.117-118.patch \
-	 file://patches/1069-patch-4.19.118-119.patch \
-	 file://patches/1070-patch-4.19.119-120.patch \
-	 file://patches/1071-patch-4.19.120-121.patch \
-	 file://patches/1072-patch-4.19.121-122.patch \
-	 file://patches/1073-patch-4.19.122-123.patch \
-	 file://patches/1074-patch-4.19.123-124.patch \
-	 file://patches/1075-patch-4.19.124-125.patch \
-	 file://patches/1076-patch-4.19.125-126.patch \
-	 file://patches/1077-patch-4.19.126-127.patch \
-	 file://patches/1078-patch-4.19.127-128.patch \
-	 file://patches/1079-patch-4.19.128-129.patch \
-	 file://patches/1080-patch-4.19.129-130.patch \
-	 file://patches/1081-patch-4.19.130-131.patch \
-	 file://patches/1082-patch-4.19.131-132.patch \
-	 file://patches/1083-patch-4.19.132-133.patch \
-	 file://patches/1084-patch-4.19.133-134.patch \
-	 file://patches/1085-patch-4.19.134-135.patch \
-	 file://patches/1086-patch-4.19.135-136.patch \
-	 file://patches/1087-patch-4.19.136-137.patch \
-	 file://patches/1088-patch-4.19.137-138.patch \
-	 file://patches/1089-patch-4.19.138-139.patch \
-	 file://patches/1090-patch-4.19.139-140.patch \
-	 file://patches/1091-patch-4.19.140-141.patch \
-	 file://patches/1092-patch-4.19.141-142.patch \
-	 file://patches/1093-patch-4.19.142-143.patch \
-	 file://patches/1094-patch-4.19.143-144.patch \
-	 file://patches/1095-patch-4.19.144-145.patch \
-	 file://patches/1096-patch-4.19.145-146.patch \
-	 file://patches/1097-patch-4.19.146-147.patch \
-	 file://patches/1098-patch-4.19.147-148.patch \
-	 file://patches/1099-patch-4.19.148-149.patch \
-	 file://patches/1100-patch-4.19.149-150.patch \
-	 file://patches/1101-patch-4.19.150-151.patch \
-	 file://patches/1102-patch-4.19.151-152.patch \
-	 file://patches/1103-patch-4.19.152-153.patch \
-	 file://patches/1104-patch-4.19.153-154.patch \
-	 file://patches/1105-patch-4.19.154-155.patch \
-	 file://patches/1106-patch-4.19.155-156.patch \
-	 file://patches/1107-patch-4.19.156-157.patch \
-	 file://patches/1108-patch-4.19.157-158.patch \
-	 file://patches/1109-patch-4.19.158-159.patch \
-	 file://patches/1110-patch-4.19.159-160.patch \
-	 file://patches/1111-patch-4.19.160-161.patch \
-	 file://patches/1112-patch-4.19.161-162.patch \
-	 file://patches/1113-patch-4.19.162-163.patch \
-	 file://patches/1114-patch-4.19.163-164.patch \
-	 file://patches/1115-patch-4.19.164-165.patch \
-	 file://patches/1116-patch-4.19.165-166.patch \
-	 file://patches/1117-patch-4.19.166-167.patch \
-	 file://patches/1118-patch-4.19.167-168.patch \
-	 file://patches/1119-patch-4.19.168-169.patch \
-	 file://patches/1120-patch-4.19.169-170.patch \
-	 file://patches/1121-patch-4.19.170-171.patch \
-	 file://patches/1122-patch-4.19.171-172.patch \
-	 file://patches/1123-patch-4.19.172-173.patch \
-	 file://patches/1124-patch-4.19.173-174.patch \
-	 file://patches/1125-patch-4.19.174-175.patch \
-	 file://patches/1126-patch-4.19.175-176.patch \
-	 file://patches/1127-patch-4.19.176-177.patch \
-	 file://patches/1128-patch-4.19.177-178.patch \
-	 file://patches/1129-patch-4.19.178-179.patch \
-	 file://patches/1130-patch-4.19.179-180.patch \
-	 file://patches/1131-patch-4.19.180-181.patch \
-	 file://patches/1132-patch-4.19.181-182.patch \
-	 file://patches/1133-patch-4.19.182-183.patch \
-	 file://patches/1134-patch-4.19.183-184.patch \
-	 file://patches/1135-patch-4.19.184-185.patch \
-	 file://patches/1136-patch-4.19.185-186.patch \
-	 file://patches/1137-patch-4.19.186-187.patch \
-	 file://patches/1138-patch-4.19.187-188.patch \
-	 file://patches/1139-patch-4.19.188-189.patch \
-	 file://patches/1140-patch-4.19.189-190.patch \
-	 file://patches/1141-patch-4.19.190-191.patch \
-	 file://patches/1142-patch-4.19.191-192.patch \
-	 file://patches/1143-patch-4.19.192-193.patch \
-	 file://patches/1144-patch-4.19.193-194.patch \
-	 file://patches/1145-patch-4.19.194-195.patch \
-	 file://patches/1146-patch-4.19.195-196.patch \
-	 file://patches/1147-patch-4.19.196-197.patch \
-	 file://patches/1148-patch-4.19.197-198.patch \
-	 file://patches/1149-patch-4.19.198-199.patch \
-	 file://patches/1150-patch-4.19.199-200.patch \
-	 file://patches/1151-patch-4.19.200-201.patch \
-	 file://patches/1152-patch-4.19.201-202.patch \
-	 file://patches/1153-patch-4.19.202-203.patch \
-	 file://patches/1154-patch-4.19.203-204.patch \
-	 file://patches/1155-patch-4.19.204-205.patch \
-	 file://patches/1156-patch-4.19.205-206.patch \
-	 file://patches/1157-patch-4.19.206-207.patch \
-	 file://patches/1158-patch-4.19.207-208.patch \
-	 file://patches/1159-patch-4.19.208-209.patch \
-	 file://patches/1160-patch-4.19.209-210.patch \
-	 file://patches/1161-patch-4.19.210-211.patch \
-	 file://patches/1162-patch-4.19.211-212.patch \
-	 file://patches/1163-patch-4.19.212-213.patch \
-	 file://patches/1164-patch-4.19.213-214.patch \
-	 file://patches/1165-patch-4.19.214-215.patch \
-	 file://patches/1166-patch-4.19.215-216.patch \
-	 file://patches/1167-patch-4.19.216-217.patch \
-	 file://patches/1168-patch-4.19.217-218.patch \
-	 file://patches/1169-patch-4.19.218-219.patch \
-	 file://patches/1170-patch-4.19.219-220.patch \
-	 file://patches/1171-patch-4.19.220-221.patch \
-	 file://patches/1172-patch-4.19.221-222.patch \
-	 file://patches/1173-patch-4.19.222-223.patch \
-	 file://patches/1174-patch-4.19.223-224.patch \
-	 file://patches/1175-patch-4.19.224-225.patch \
-	 file://patches/1176-patch-4.19.225-226.patch \
-	 file://patches/1177-patch-4.19.226-227.patch \
-	 file://patches/1178-patch-4.19.227-228.patch \
-	 file://patches/1179-patch-4.19.228-229.patch \
-	 file://patches/1180-patch-4.19.229-230.patch \
-	 file://patches/1181-patch-4.19.230-231.patch \
-	 file://patches/1182-patch-4.19.231-232.patch \
-	 file://patches/1183-patch-4.19.232-233.patch \
-	 file://patches/1184-patch-4.19.233-234.patch \
-	 file://patches/1185-patch-4.19.234-235.patch \
-	 file://patches/1186-patch-4.19.235-236.patch \
-	 file://patches/1187-patch-4.19.236-237.patch \
-	 file://patches/1188-patch-4.19.237-238.patch \
-	 file://patches/1189-patch-4.19.238-239.patch \
-	 file://patches/1190-patch-4.19.239-240.patch \
-	 file://patches/1191-patch-4.19.240-241.patch \
-	 file://patches/1192-patch-4.19.241-242.patch \
-	 file://patches/1193-patch-4.19.242-243.patch \
-	 file://patches/1194-patch-4.19.243-244.patch \
-	 file://patches/1195-patch-4.19.244-245.patch \
-	 file://patches/1196-patch-4.19.245-246.patch \
-	 file://patches/1197-patch-4.19.246-247.patch \
-	 file://patches/1198-patch-4.19.247-248.patch \
-	 file://patches/1199-patch-4.19.248-249.patch \
-	 file://patches/1200-patch-4.19.249-250.patch \
-	 file://patches/1201-patch-4.19.250-251.patch \
-	 file://patches/1202-patch-4.19.251-252.patch \
-	 file://patches/1203-patch-4.19.252-253.patch \
-	 file://patches/1204-patch-4.19.253-254.patch \
-	 file://patches/1205-patch-4.19.254-255.patch \
-	 file://patches/1206-patch-4.19.255-256.patch \
-	 file://patches/1207-patch-4.19.256-257.patch \
-	 file://patches/1208-patch-4.19.257-258.patch \
-	 file://patches/1209-patch-4.19.258-259.patch \
-	 file://patches/1210-patch-4.19.259-260.patch \
-	 file://patches/1211-patch-4.19.260-261.patch \
-	 file://patches/1212-patch-4.19.261-262.patch \
-	 file://patches/1213-patch-4.19.262-263.patch \
-	 file://patches/1214-patch-4.19.263-264.patch \
-	 file://patches/1215-patch-4.19.264-265.patch \
-	 file://patches/1216-patch-4.19.265-266.patch \
-	 file://patches/1217-patch-4.19.266-267.patch \
-	 file://patches/1218-patch-4.19.267-268.patch \
-	 file://patches/1219-patch-4.19.268-269.patch \
-	 file://patches/1220-patch-4.19.269-270.patch \
-	 file://patches/1221-patch-4.19.270-271.patch \
-	 file://patches/1222-patch-4.19.271-272.patch \
-	 file://patches/1223-patch-4.19.272-273.patch \
-	 file://patches/1224-patch-4.19.273-274.patch \
-	 file://patches/1225-patch-4.19.274-275.patch \
-	 file://patches/1226-patch-4.19.275-276.patch \
-	 file://patches/1227-patch-4.19.276-277.patch \
-	 file://patches/1228-patch-4.19.277-278.patch \
-	 file://patches/1229-patch-4.19.278-279.patch \
-	 file://patches/1230-patch-4.19.279-280.patch \
-	 file://patches/1231-patch-4.19.280-281.patch \
-	 file://patches/1232-patch-4.19.281-282.patch \
-	 file://patches/1233-patch-4.19.282-283.patch \
-	 file://patches/1234-patch-4.19.283-284.patch \
-	 file://patches/1235-patch-4.19.284-285.patch \
-	 file://patches/1236-patch-4.19.285-286.patch \
-	 file://patches/1237-patch-4.19.286-287.patch \
-	 file://patches/1238-patch-4.19.287-288.patch \
-	"
diff --git a/recipes-kernel/linux/linux-stm32mp/patches/0504-drm-panel-simple-Add-support-for-Admatec-T070P133T0S.patch b/recipes-kernel/linux/linux-stm32mp/patches/0001-drm-panel-simple-Add-support-for-Admatec-T070P133T0S.patch
similarity index 86%
rename from recipes-kernel/linux/linux-stm32mp/patches/0504-drm-panel-simple-Add-support-for-Admatec-T070P133T0S.patch
rename to recipes-kernel/linux/linux-stm32mp/patches/0001-drm-panel-simple-Add-support-for-Admatec-T070P133T0S.patch
index c7eca0238bfd5286a7d2e8c10ae32d71ecb408e8..9fb36e74e3b606a831e376e8e9fa9f0899f09ed1 100644
--- a/recipes-kernel/linux/linux-stm32mp/patches/0504-drm-panel-simple-Add-support-for-Admatec-T070P133T0S.patch
+++ b/recipes-kernel/linux/linux-stm32mp/patches/0001-drm-panel-simple-Add-support-for-Admatec-T070P133T0S.patch
@@ -1,17 +1,17 @@
-From 17a7a3a94b5ef73e9427ddc2ca96be4e1417280f Mon Sep 17 00:00:00 2001
+From b03ec3782dd2c3df4f1aee027556a62fcda709e3 Mon Sep 17 00:00:00 2001
 From: Frieder Schrempf <frieder.schrempf@exceet.de>
 Date: Thu, 2 Aug 2018 10:59:57 +0200
 Subject: [PATCH] drm/panel: simple: Add support for Admatec T070P133T0S301
 
 ---
- drivers/gpu/drm/panel/panel-simple.c | 29 ++++++++++++++++++++++++++++
+ drivers/gpu/drm/panel/panel-simple.c | 29 +++++++++++++++++++++++++++++
  1 file changed, 29 insertions(+)
 
 diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c
-index 736fe680b2a3..16c57cb608d0 100644
+index 59a6fdf..f0a9d52 100644
 --- a/drivers/gpu/drm/panel/panel-simple.c
 +++ b/drivers/gpu/drm/panel/panel-simple.c
-@@ -386,6 +386,32 @@ static void panel_simple_shutdown(struct device *dev)
+@@ -388,6 +388,32 @@ static void panel_simple_shutdown(struct device *dev)
  	panel_simple_unprepare(&panel->base);
  }
  
@@ -44,7 +44,7 @@ index 736fe680b2a3..16c57cb608d0 100644
  static const struct drm_display_mode admatec_t043c004800272t2a_mode = {
  	.clock = 9200,
  	.hdisplay = 480,
-@@ -2350,6 +2376,9 @@ static const struct panel_desc winstar_wf35ltiacd = {
+@@ -1966,6 +1992,9 @@ static const struct panel_desc winstar_wf35ltiacd = {
  
  static const struct of_device_id platform_of_match[] = {
  	{
@@ -54,3 +54,6 @@ index 736fe680b2a3..16c57cb608d0 100644
  		.compatible = "admatec,t043c004800272t2a",
  		.data = &admatec_t043c004800272t2a,
  	}, {
+-- 
+2.7.4
+
diff --git a/recipes-kernel/linux/linux-stm32mp/patches/0001-fix-add-CAD-definition-files.patch b/recipes-kernel/linux/linux-stm32mp/patches/0001-fix-add-CAD-definition-files.patch
new file mode 100644
index 0000000000000000000000000000000000000000..6afb8034ac452506aa5047a484ebb7f5d620fbf7
--- /dev/null
+++ b/recipes-kernel/linux/linux-stm32mp/patches/0001-fix-add-CAD-definition-files.patch
@@ -0,0 +1,21 @@
+From 4d1747f081d126d029cee7a7d6809e2f6a73c16e Mon Sep 17 00:00:00 2001
+From: Eberhard Stoll <eberhard.stoll@exceet.de>
+Date: Fri, 3 Aug 2018 15:35:51 +0200
+Subject: [PATCH 1/4] fix: add CAD definition files
+
+---
+ arch/arm/boot/dts/stm32mp157cad-pinctrl.dtsi | 2 ++
+ 1 file changed, 2 insertions(+)
+ create mode 100644 arch/arm/boot/dts/stm32mp157cad-pinctrl.dtsi
+
+diff --git a/arch/arm/boot/dts/stm32mp157cad-pinctrl.dtsi b/arch/arm/boot/dts/stm32mp157cad-pinctrl.dtsi
+new file mode 100644
+index 0000000..395c1f9
+--- /dev/null
++++ b/arch/arm/boot/dts/stm32mp157cad-pinctrl.dtsi
+@@ -0,0 +1,2 @@
++#include "stm32mp157caa-pinctrl.dtsi"
++
+-- 
+2.7.4
+
diff --git a/recipes-kernel/linux/linux-stm32mp/patches/0001-mtd-Add-sanity-checks-in-mtd_write-read_oob.patch b/recipes-kernel/linux/linux-stm32mp/patches/0001-mtd-Add-sanity-checks-in-mtd_write-read_oob.patch
new file mode 100644
index 0000000000000000000000000000000000000000..7b2bb00260a9c19e0eedca34f23c63ff5d34ab59
--- /dev/null
+++ b/recipes-kernel/linux/linux-stm32mp/patches/0001-mtd-Add-sanity-checks-in-mtd_write-read_oob.patch
@@ -0,0 +1,96 @@
+From 1bdf1fc737a628151ffa0da290642c5568e6daf9 Mon Sep 17 00:00:00 2001
+From: Boris Brezillon <boris.brezillon@free-electrons.com>
+Date: Tue, 27 Jun 2017 21:22:21 +0200
+Subject: [PATCH 01/28] mtd: Add sanity checks in mtd_write/read_oob()
+
+Unlike what's done in mtd_read/write(), there are no checks to make sure
+the parameters passed to mtd_read/write_oob() are consistent, which
+forces implementers of ->_read/write_oob() to do it, which in turn leads
+to code duplication and possibly errors in the logic.
+
+Do general sanity checks, like ops fields consistency and range checking.
+
+Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
+Cc: Peter Pan <peterpandong@micron.com>
+Signed-off-by: Richard Weinberger <richard@nod.at>
+---
+ drivers/mtd/mtdcore.c | 44 ++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 44 insertions(+)
+
+diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
+index e7ea842..70d5957 100644
+--- a/drivers/mtd/mtdcore.c
++++ b/drivers/mtd/mtdcore.c
+@@ -1093,6 +1093,39 @@ int mtd_panic_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
+ }
+ EXPORT_SYMBOL_GPL(mtd_panic_write);
+ 
++static int mtd_check_oob_ops(struct mtd_info *mtd, loff_t offs,
++			     struct mtd_oob_ops *ops)
++{
++	/*
++	 * Some users are setting ->datbuf or ->oobbuf to NULL, but are leaving
++	 * ->len or ->ooblen uninitialized. Force ->len and ->ooblen to 0 in
++	 *  this case.
++	 */
++	if (!ops->datbuf)
++		ops->len = 0;
++
++	if (!ops->oobbuf)
++		ops->ooblen = 0;
++
++	if (offs < 0 || offs + ops->len >= mtd->size)
++		return -EINVAL;
++
++	if (ops->ooblen) {
++		u64 maxooblen;
++
++		if (ops->ooboffs >= mtd_oobavail(mtd, ops))
++			return -EINVAL;
++
++		maxooblen = ((mtd_div_by_ws(mtd->size, mtd) -
++			      mtd_div_by_ws(offs, mtd)) *
++			     mtd_oobavail(mtd, ops)) - ops->ooboffs;
++		if (ops->ooblen > maxooblen)
++			return -EINVAL;
++	}
++
++	return 0;
++}
++
+ int mtd_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops)
+ {
+ 	int ret_code;
+@@ -1100,6 +1133,10 @@ int mtd_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops)
+ 	if (!mtd->_read_oob)
+ 		return -EOPNOTSUPP;
+ 
++	ret_code = mtd_check_oob_ops(mtd, from, ops);
++	if (ret_code)
++		return ret_code;
++
+ 	ledtrig_mtd_activity();
+ 	/*
+ 	 * In cases where ops->datbuf != NULL, mtd->_read_oob() has semantics
+@@ -1119,11 +1156,18 @@ EXPORT_SYMBOL_GPL(mtd_read_oob);
+ int mtd_write_oob(struct mtd_info *mtd, loff_t to,
+ 				struct mtd_oob_ops *ops)
+ {
++	int ret;
++
+ 	ops->retlen = ops->oobretlen = 0;
+ 	if (!mtd->_write_oob)
+ 		return -EOPNOTSUPP;
+ 	if (!(mtd->flags & MTD_WRITEABLE))
+ 		return -EROFS;
++
++	ret = mtd_check_oob_ops(mtd, to, ops);
++	if (ret)
++		return ret;
++
+ 	ledtrig_mtd_activity();
+ 	return mtd->_write_oob(mtd, to, ops);
+ }
+-- 
+2.7.4
+
diff --git a/recipes-kernel/linux/linux-stm32mp/patches/0500-linux-stm32mp-disable-spidev-warning-message.patch b/recipes-kernel/linux/linux-stm32mp/patches/0002-linux-stm32mp-disable-spidev-warning-message.patch
similarity index 81%
rename from recipes-kernel/linux/linux-stm32mp/patches/0500-linux-stm32mp-disable-spidev-warning-message.patch
rename to recipes-kernel/linux/linux-stm32mp/patches/0002-linux-stm32mp-disable-spidev-warning-message.patch
index d240e980d08d5d03cb78f8555a641d3512a425bc..046a181eeefcd21029a961d0af759c6eb9a86d12 100644
--- a/recipes-kernel/linux/linux-stm32mp/patches/0500-linux-stm32mp-disable-spidev-warning-message.patch
+++ b/recipes-kernel/linux/linux-stm32mp/patches/0002-linux-stm32mp-disable-spidev-warning-message.patch
@@ -1,14 +1,14 @@
-From dd3eaa4f77d58cc2adf66fd330609876a305b130 Mon Sep 17 00:00:00 2001
+From 512717b20f6b4910ba8ee0109d59cfb8d7e89f6c Mon Sep 17 00:00:00 2001
 From: Eberhard Stoll <eberhard.stoll@exceet.de>
 Date: Mon, 29 Oct 2018 13:31:43 +0100
-Subject: [PATCH] linux-stm32mp: disable spidev warning message
+Subject: [PATCH 2/2] linux-stm32mp: disable spidev warning message
 
 ---
  drivers/spi/spidev.c | 3 +++
  1 file changed, 3 insertions(+)
 
 diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c
-index cda10719d1d1..f81494a41aab 100644
+index cda1071..f81494a 100644
 --- a/drivers/spi/spidev.c
 +++ b/drivers/spi/spidev.c
 @@ -719,6 +719,8 @@ static int spidev_probe(struct spi_device *spi)
@@ -28,3 +28,6 @@ index cda10719d1d1..f81494a41aab 100644
  
  	spidev_probe_acpi(spi);
  
+-- 
+2.7.4
+
diff --git a/recipes-kernel/linux/linux-stm32mp/patches/0002-mtd-mtdpart-Make-ECC-stat-handling-consistent.patch b/recipes-kernel/linux/linux-stm32mp/patches/0002-mtd-mtdpart-Make-ECC-stat-handling-consistent.patch
new file mode 100644
index 0000000000000000000000000000000000000000..9820f80091bfdad9da1c644eaf5099bc1806b99b
--- /dev/null
+++ b/recipes-kernel/linux/linux-stm32mp/patches/0002-mtd-mtdpart-Make-ECC-stat-handling-consistent.patch
@@ -0,0 +1,59 @@
+From 306aa99af5f86e1534228502883b37b536e8828e Mon Sep 17 00:00:00 2001
+From: Boris Brezillon <boris.brezillon@free-electrons.com>
+Date: Tue, 9 Jan 2018 09:50:33 +0100
+Subject: [PATCH 02/28] mtd: mtdpart: Make ECC stat handling consistent
+
+part_read() and part_read_oob() were counting ECC failures and
+bitflips differently. Adjust part_read_oob() to mimic what is done in
+part_read(). This is needed to use ->_read_oob() as a fallback when
+when ->_read() is not implemented.
+
+Note that bitflips and ECC failure accounting on MTD partitions is
+broken by design, because nothing prevents concurrent accesses to the
+underlying master MTD device between the moment we save the stats in a
+local variable and the moment master->_read[_oob]() returns. It's not
+something that can easily be fixed, so leave it like that for now.
+
+Suggested-by: Brian Norris <computersforpeace@gmail.com>
+Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
+Tested-by: Ladislav Michl <ladis@linux-mips.org>
+---
+ drivers/mtd/mtdpart.c | 14 ++++++++------
+ 1 file changed, 8 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
+index a308e70..ad80cbc 100644
+--- a/drivers/mtd/mtdpart.c
++++ b/drivers/mtd/mtdpart.c
+@@ -117,6 +117,7 @@ static int part_read_oob(struct mtd_info *mtd, loff_t from,
+ 		struct mtd_oob_ops *ops)
+ {
+ 	struct mtd_part *part = mtd_to_part(mtd);
++	struct mtd_ecc_stats stats;
+ 	int res;
+ 
+ 	if (from >= mtd->size)
+@@ -138,13 +139,14 @@ static int part_read_oob(struct mtd_info *mtd, loff_t from,
+ 			return -EINVAL;
+ 	}
+ 
++	stats = part->parent->ecc_stats;
+ 	res = part->parent->_read_oob(part->parent, from + part->offset, ops);
+-	if (unlikely(res)) {
+-		if (mtd_is_bitflip(res))
+-			mtd->ecc_stats.corrected++;
+-		if (mtd_is_eccerr(res))
+-			mtd->ecc_stats.failed++;
+-	}
++	if (unlikely(mtd_is_eccerr(res)))
++		mtd->ecc_stats.failed +=
++			part->parent->ecc_stats.failed - stats.failed;
++	else
++		mtd->ecc_stats.corrected +=
++			part->parent->ecc_stats.corrected - stats.corrected;
+ 	return res;
+ }
+ 
+-- 
+2.7.4
+
diff --git a/recipes-kernel/linux/linux-stm32mp/patches/0003-mtd-Fallback-to-_read-write_oob-when-_read-write-is-.patch b/recipes-kernel/linux/linux-stm32mp/patches/0003-mtd-Fallback-to-_read-write_oob-when-_read-write-is-.patch
new file mode 100644
index 0000000000000000000000000000000000000000..6259ece69eacc793e665e35b17a729793c6ba2fe
--- /dev/null
+++ b/recipes-kernel/linux/linux-stm32mp/patches/0003-mtd-Fallback-to-_read-write_oob-when-_read-write-is-.patch
@@ -0,0 +1,355 @@
+From 1cfcca96ba9b64dce39859d334e4b045c60b8d6e Mon Sep 17 00:00:00 2001
+From: Boris Brezillon <boris.brezillon@free-electrons.com>
+Date: Tue, 9 Jan 2018 09:50:34 +0100
+Subject: [PATCH 03/28] mtd: Fallback to ->_read/write_oob() when
+ ->_read/write() is missing
+
+Some MTD sublayers/drivers are implementing ->_read/write_oob() and
+provide dummy wrappers for their ->_read/write() implementations.
+Let the core handle this case instead of duplicating the logic.
+
+Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
+Acked-by: Robert Jarzmik <robert.jarzmik@free.fr>
+Acked-by: Brian Norris <computersforpeace@gmail.com>
+Reviewed-by: Miquel Raynal <miquel.raynal@free-electrons.com>
+Tested-by: Ladislav Michl <ladis@linux-mips.org>
+---
+ drivers/mtd/devices/docg3.c        | 65 --------------------------------------
+ drivers/mtd/mtdcore.c              | 31 ++++++++++++++++--
+ drivers/mtd/mtdpart.c              |  6 ++--
+ drivers/mtd/nand/nand_base.c       | 56 --------------------------------
+ drivers/mtd/onenand/onenand_base.c | 63 ------------------------------------
+ 5 files changed, 33 insertions(+), 188 deletions(-)
+
+diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c
+index 0806f72..5fb5e93 100644
+--- a/drivers/mtd/devices/docg3.c
++++ b/drivers/mtd/devices/docg3.c
+@@ -990,36 +990,6 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t from,
+ 	goto out;
+ }
+ 
+-/**
+- * doc_read - Read bytes from flash
+- * @mtd: the device
+- * @from: the offset from first block and first page, in bytes, aligned on page
+- *        size
+- * @len: the number of bytes to read (must be a multiple of 4)
+- * @retlen: the number of bytes actually read
+- * @buf: the filled in buffer
+- *
+- * Reads flash memory pages. This function does not read the OOB chunk, but only
+- * the page data.
+- *
+- * Returns 0 if read successful, of -EIO, -EINVAL if an error occurred
+- */
+-static int doc_read(struct mtd_info *mtd, loff_t from, size_t len,
+-	     size_t *retlen, u_char *buf)
+-{
+-	struct mtd_oob_ops ops;
+-	size_t ret;
+-
+-	memset(&ops, 0, sizeof(ops));
+-	ops.datbuf = buf;
+-	ops.len = len;
+-	ops.mode = MTD_OPS_AUTO_OOB;
+-
+-	ret = doc_read_oob(mtd, from, &ops);
+-	*retlen = ops.retlen;
+-	return ret;
+-}
+-
+ static int doc_reload_bbt(struct docg3 *docg3)
+ {
+ 	int block = DOC_LAYOUT_BLOCK_BBT;
+@@ -1513,39 +1483,6 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs,
+ 	return ret;
+ }
+ 
+-/**
+- * doc_write - Write a buffer to the chip
+- * @mtd: the device
+- * @to: the offset from first block and first page, in bytes, aligned on page
+- *      size
+- * @len: the number of bytes to write (must be a full page size, ie. 512)
+- * @retlen: the number of bytes actually written (0 or 512)
+- * @buf: the buffer to get bytes from
+- *
+- * Writes data to the chip.
+- *
+- * Returns 0 if write successful, -EIO if write error
+- */
+-static int doc_write(struct mtd_info *mtd, loff_t to, size_t len,
+-		     size_t *retlen, const u_char *buf)
+-{
+-	struct docg3 *docg3 = mtd->priv;
+-	int ret;
+-	struct mtd_oob_ops ops;
+-
+-	doc_dbg("doc_write(to=%lld, len=%zu)\n", to, len);
+-	ops.datbuf = (char *)buf;
+-	ops.len = len;
+-	ops.mode = MTD_OPS_PLACE_OOB;
+-	ops.oobbuf = NULL;
+-	ops.ooblen = 0;
+-	ops.ooboffs = 0;
+-
+-	ret = doc_write_oob(mtd, to, &ops);
+-	*retlen = ops.retlen;
+-	return ret;
+-}
+-
+ static struct docg3 *sysfs_dev2docg3(struct device *dev,
+ 				     struct device_attribute *attr)
+ {
+@@ -1866,8 +1803,6 @@ static int __init doc_set_driver_info(int chip_id, struct mtd_info *mtd)
+ 	mtd->writebufsize = mtd->writesize = DOC_LAYOUT_PAGE_SIZE;
+ 	mtd->oobsize = DOC_LAYOUT_OOB_SIZE;
+ 	mtd->_erase = doc_erase;
+-	mtd->_read = doc_read;
+-	mtd->_write = doc_write;
+ 	mtd->_read_oob = doc_read_oob;
+ 	mtd->_write_oob = doc_write_oob;
+ 	mtd->_block_isbad = doc_block_isbad;
+diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
+index 70d5957..de8da62 100644
+--- a/drivers/mtd/mtdcore.c
++++ b/drivers/mtd/mtdcore.c
+@@ -1046,7 +1046,20 @@ int mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
+ 	 * representing the maximum number of bitflips that were corrected on
+ 	 * any one ecc region (if applicable; zero otherwise).
+ 	 */
+-	ret_code = mtd->_read(mtd, from, len, retlen, buf);
++	if (mtd->_read) {
++		ret_code = mtd->_read(mtd, from, len, retlen, buf);
++	} else if (mtd->_read_oob) {
++		struct mtd_oob_ops ops = {
++			.len = len,
++			.datbuf = buf,
++		};
++
++		ret_code = mtd->_read_oob(mtd, from, &ops);
++		*retlen = ops.retlen;
++	} else {
++		return -ENOTSUPP;
++	}
++
+ 	if (unlikely(ret_code < 0))
+ 		return ret_code;
+ 	if (mtd->ecc_strength == 0)
+@@ -1061,11 +1074,25 @@ int mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
+ 	*retlen = 0;
+ 	if (to < 0 || to >= mtd->size || len > mtd->size - to)
+ 		return -EINVAL;
+-	if (!mtd->_write || !(mtd->flags & MTD_WRITEABLE))
++	if ((!mtd->_write && !mtd->_write_oob) ||
++	    !(mtd->flags & MTD_WRITEABLE))
+ 		return -EROFS;
+ 	if (!len)
+ 		return 0;
+ 	ledtrig_mtd_activity();
++
++	if (!mtd->_write) {
++		struct mtd_oob_ops ops = {
++			.len = len,
++			.datbuf = (u8 *)buf,
++		};
++		int ret;
++
++		ret = mtd->_write_oob(mtd, to, &ops);
++		*retlen = ops.retlen;
++		return ret;
++	}
++
+ 	return mtd->_write(mtd, to, len, retlen, buf);
+ }
+ EXPORT_SYMBOL_GPL(mtd_write);
+diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
+index ad80cbc..2803585 100644
+--- a/drivers/mtd/mtdpart.c
++++ b/drivers/mtd/mtdpart.c
+@@ -449,8 +449,10 @@ static struct mtd_part *allocate_partition(struct mtd_info *parent,
+ 				parent->dev.parent;
+ 	slave->mtd.dev.of_node = part->of_node;
+ 
+-	slave->mtd._read = part_read;
+-	slave->mtd._write = part_write;
++	if (parent->_read)
++		slave->mtd._read = part_read;
++	if (parent->_write)
++		slave->mtd._write = part_write;
+ 
+ 	if (parent->_panic_write)
+ 		slave->mtd._panic_write = part_panic_write;
+diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
+index 3f1d806..4495861 100644
+--- a/drivers/mtd/nand/nand_base.c
++++ b/drivers/mtd/nand/nand_base.c
+@@ -2029,33 +2029,6 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
+ }
+ 
+ /**
+- * nand_read - [MTD Interface] MTD compatibility function for nand_do_read_ecc
+- * @mtd: MTD device structure
+- * @from: offset to read from
+- * @len: number of bytes to read
+- * @retlen: pointer to variable to store the number of read bytes
+- * @buf: the databuffer to put data
+- *
+- * 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)
+-{
+-	struct mtd_oob_ops ops;
+-	int ret;
+-
+-	nand_get_device(mtd, FL_READING);
+-	memset(&ops, 0, sizeof(ops));
+-	ops.len = len;
+-	ops.datbuf = buf;
+-	ops.mode = MTD_OPS_PLACE_OOB;
+-	ret = nand_do_read_ops(mtd, from, &ops);
+-	*retlen = ops.retlen;
+-	nand_release_device(mtd);
+-	return ret;
+-}
+-
+-/**
+  * nand_read_oob_std - [REPLACEABLE] the most common OOB data read function
+  * @mtd: mtd info structure
+  * @chip: nand chip info structure
+@@ -2824,33 +2797,6 @@ static int panic_nand_write(struct mtd_info *mtd, loff_t to, size_t len,
+ }
+ 
+ /**
+- * nand_write - [MTD Interface] NAND write with ECC
+- * @mtd: MTD device structure
+- * @to: offset to write to
+- * @len: number of bytes to write
+- * @retlen: pointer to variable to store the number of written bytes
+- * @buf: the data to write
+- *
+- * 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)
+-{
+-	struct mtd_oob_ops ops;
+-	int ret;
+-
+-	nand_get_device(mtd, FL_WRITING);
+-	memset(&ops, 0, sizeof(ops));
+-	ops.len = len;
+-	ops.datbuf = (uint8_t *)buf;
+-	ops.mode = MTD_OPS_PLACE_OOB;
+-	ret = nand_do_write_ops(mtd, to, &ops);
+-	*retlen = ops.retlen;
+-	nand_release_device(mtd);
+-	return ret;
+-}
+-
+-/**
+  * nand_do_write_oob - [MTD Interface] NAND write out-of-band
+  * @mtd: MTD device structure
+  * @to: offset to write to
+@@ -4903,8 +4849,6 @@ int nand_scan_tail(struct mtd_info *mtd)
+ 	mtd->_erase = nand_erase;
+ 	mtd->_point = NULL;
+ 	mtd->_unpoint = NULL;
+-	mtd->_read = nand_read;
+-	mtd->_write = nand_write;
+ 	mtd->_panic_write = panic_nand_write;
+ 	mtd->_read_oob = nand_read_oob;
+ 	mtd->_write_oob = nand_write_oob;
+diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c
+index 1a6d0e3..050ba8a 100644
+--- a/drivers/mtd/onenand/onenand_base.c
++++ b/drivers/mtd/onenand/onenand_base.c
+@@ -1448,38 +1448,6 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from,
+ }
+ 
+ /**
+- * onenand_read - [MTD Interface] Read data from flash
+- * @param mtd		MTD device structure
+- * @param from		offset to read from
+- * @param len		number of bytes to read
+- * @param retlen	pointer to variable to store the number of read bytes
+- * @param buf		the databuffer to put data
+- *
+- * Read with ecc
+-*/
+-static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
+-	size_t *retlen, u_char *buf)
+-{
+-	struct onenand_chip *this = mtd->priv;
+-	struct mtd_oob_ops ops = {
+-		.len	= len,
+-		.ooblen	= 0,
+-		.datbuf	= buf,
+-		.oobbuf	= NULL,
+-	};
+-	int ret;
+-
+-	onenand_get_device(mtd, FL_READING);
+-	ret = ONENAND_IS_4KB_PAGE(this) ?
+-		onenand_mlc_read_ops_nolock(mtd, from, &ops) :
+-		onenand_read_ops_nolock(mtd, from, &ops);
+-	onenand_release_device(mtd);
+-
+-	*retlen = ops.retlen;
+-	return ret;
+-}
+-
+-/**
+  * onenand_read_oob - [MTD Interface] Read main and/or out-of-band
+  * @param mtd:		MTD device structure
+  * @param from:		offset to read from
+@@ -2129,35 +2097,6 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to,
+ }
+ 
+ /**
+- * onenand_write - [MTD Interface] write buffer to FLASH
+- * @param mtd		MTD device structure
+- * @param to		offset to write to
+- * @param len		number of bytes to write
+- * @param retlen	pointer to variable to store the number of written bytes
+- * @param buf		the data to write
+- *
+- * Write with ECC
+- */
+-static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len,
+-	size_t *retlen, const u_char *buf)
+-{
+-	struct mtd_oob_ops ops = {
+-		.len	= len,
+-		.ooblen	= 0,
+-		.datbuf	= (u_char *) buf,
+-		.oobbuf	= NULL,
+-	};
+-	int ret;
+-
+-	onenand_get_device(mtd, FL_WRITING);
+-	ret = onenand_write_ops_nolock(mtd, to, &ops);
+-	onenand_release_device(mtd);
+-
+-	*retlen = ops.retlen;
+-	return ret;
+-}
+-
+-/**
+  * onenand_write_oob - [MTD Interface] NAND write data and/or out-of-band
+  * @param mtd:		MTD device structure
+  * @param to:		offset to write
+@@ -4038,8 +3977,6 @@ int onenand_scan(struct mtd_info *mtd, int maxchips)
+ 	mtd->_erase = onenand_erase;
+ 	mtd->_point = NULL;
+ 	mtd->_unpoint = NULL;
+-	mtd->_read = onenand_read;
+-	mtd->_write = onenand_write;
+ 	mtd->_read_oob = onenand_read_oob;
+ 	mtd->_write_oob = onenand_write_oob;
+ 	mtd->_panic_write = onenand_panic_write;
+-- 
+2.7.4
+
diff --git a/recipes-kernel/linux/linux-stm32mp/patches/0004-spi-Check-presence-the-of-transfer-_xxx-before-regis.patch b/recipes-kernel/linux/linux-stm32mp/patches/0004-spi-Check-presence-the-of-transfer-_xxx-before-regis.patch
new file mode 100644
index 0000000000000000000000000000000000000000..c3e47d18d7916bad119d0dc00e34b311058050fa
--- /dev/null
+++ b/recipes-kernel/linux/linux-stm32mp/patches/0004-spi-Check-presence-the-of-transfer-_xxx-before-regis.patch
@@ -0,0 +1,60 @@
+From 30d80008375e31ff31e0f82f167c0d297b24899c Mon Sep 17 00:00:00 2001
+From: Boris Brezillon <boris.brezillon@bootlin.com>
+Date: Tue, 10 Apr 2018 22:00:53 +0200
+Subject: [PATCH 04/28] spi: Check presence the of ->transfer[_xxx]() before
+ registering a controller
+
+Right now, no checks are done on the presence of a ->transfer[_xxx]()
+method, which can lead to a NULL pointer dereference when someone
+starts sending something on the bus.
+
+Do the check at registration time and refuse to add the controller if
+all ->transfer[_xxx]() pointers are NULL.
+
+Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
+---
+ drivers/spi/spi.c | 21 +++++++++++++++++++++
+ 1 file changed, 21 insertions(+)
+
+diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
+index 3ff0ee8..6829518 100644
+--- a/drivers/spi/spi.c
++++ b/drivers/spi/spi.c
+@@ -2057,6 +2057,19 @@ static int of_spi_register_master(struct spi_controller *ctlr)
+ }
+ #endif
+ 
++static int spi_controller_check_ops(struct spi_controller *ctlr)
++{
++	/*
++	 * The controller must at least implement one of the ->transfer()
++	 * hooks.
++	 */
++	if (!ctlr->transfer && !ctlr->transfer_one &&
++	    !ctlr->transfer_one_message)
++		return -EINVAL;
++
++	return 0;
++}
++
+ /**
+  * spi_register_controller - register SPI master or slave controller
+  * @ctlr: initialized master, originally from spi_alloc_master() or
+@@ -2090,6 +2103,14 @@ int spi_register_controller(struct spi_controller *ctlr)
+ 	if (!dev)
+ 		return -ENODEV;
+ 
++	/*
++	 * Make sure all necessary hooks are implemented before registering
++	 * the SPI controller.
++	 */
++	status = spi_controller_check_ops(ctlr);
++	if (status)
++		return status;
++
+ 	if (!spi_controller_is_slave(ctlr)) {
+ 		status = of_spi_register_master(ctlr);
+ 		if (status)
+-- 
+2.7.4
+
diff --git a/recipes-kernel/linux/linux-stm32mp/patches/0005-spi-Expose-spi_-map-unmap-_buf-for-internal-use.patch b/recipes-kernel/linux/linux-stm32mp/patches/0005-spi-Expose-spi_-map-unmap-_buf-for-internal-use.patch
new file mode 100644
index 0000000000000000000000000000000000000000..c899b0c9e73d2e136dec5029abdc19f13c4c86cc
--- /dev/null
+++ b/recipes-kernel/linux/linux-stm32mp/patches/0005-spi-Expose-spi_-map-unmap-_buf-for-internal-use.patch
@@ -0,0 +1,126 @@
+From 35d1c599dbc71b4ee73a25bc03ba6fff118cec25 Mon Sep 17 00:00:00 2001
+From: Boris Brezillon <boris.brezillon@bootlin.com>
+Date: Tue, 10 Apr 2018 23:07:19 +0200
+Subject: [PATCH 05/28] spi: Expose spi_{map,unmap}_buf() for internal use
+
+spi_{map,unmap}_buf() are needed by the spi-mem logic that is about to
+be introduced to prepare data buffer for DMA operations.
+
+Remove the static specifier on these functions and add their prototypes
+to include/linux/spi/spi.h. We do not export the symbols here because
+both SPI_MEM and SPI can't be enabled as modules and we'd like to
+prevent controller/device drivers from using these functions.
+
+Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
+---
+I see 2 other options to not expose internal stuff to spi users or
+controller drivers:
+
+1/ we do not expose spi_map/unmap_buf() and instead implement
+   spi_controller_dma_map/unmap_mem_op_data() directly in spi.c
+2/ we create a new header (drivers/spi/internals.h?) for all
+   definitions that are meant for internal use (shared between spi.c
+   and spi-mem.c)
+
+I personally prefer #2 as it provides a better separation between spi
+and spi-mem code.
+---
+ drivers/spi/spi.c       | 23 +++++------------------
+ include/linux/spi/spi.h | 26 ++++++++++++++++++++++++++
+ 2 files changed, 31 insertions(+), 18 deletions(-)
+
+diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
+index 6829518..81ff208 100644
+--- a/drivers/spi/spi.c
++++ b/drivers/spi/spi.c
+@@ -740,9 +740,9 @@ static void spi_set_cs(struct spi_device *spi, bool enable)
+ }
+ 
+ #ifdef CONFIG_HAS_DMA
+-static int spi_map_buf(struct spi_controller *ctlr, struct device *dev,
+-		       struct sg_table *sgt, void *buf, size_t len,
+-		       enum dma_data_direction dir)
++int spi_map_buf(struct spi_controller *ctlr, struct device *dev,
++		struct sg_table *sgt, void *buf, size_t len,
++		enum dma_data_direction dir)
+ {
+ 	const bool vmalloced_buf = is_vmalloc_addr(buf);
+ 	unsigned int max_seg_size = dma_get_max_seg_size(dev);
+@@ -815,8 +815,8 @@ static int spi_map_buf(struct spi_controller *ctlr, struct device *dev,
+ 	return 0;
+ }
+ 
+-static void spi_unmap_buf(struct spi_controller *ctlr, struct device *dev,
+-			  struct sg_table *sgt, enum dma_data_direction dir)
++void spi_unmap_buf(struct spi_controller *ctlr, struct device *dev,
++		   struct sg_table *sgt, enum dma_data_direction dir)
+ {
+ 	if (sgt->orig_nents) {
+ 		dma_unmap_sg(dev, sgt->sgl, sgt->orig_nents, dir);
+@@ -901,19 +901,6 @@ static int __spi_unmap_msg(struct spi_controller *ctlr, struct spi_message *msg)
+ 	return 0;
+ }
+ #else /* !CONFIG_HAS_DMA */
+-static inline int spi_map_buf(struct spi_controller *ctlr, struct device *dev,
+-			      struct sg_table *sgt, void *buf, size_t len,
+-			      enum dma_data_direction dir)
+-{
+-	return -EINVAL;
+-}
+-
+-static inline void spi_unmap_buf(struct spi_controller *ctlr,
+-				 struct device *dev, struct sg_table *sgt,
+-				 enum dma_data_direction dir)
+-{
+-}
+-
+ static inline int __spi_map_msg(struct spi_controller *ctlr,
+ 				struct spi_message *msg)
+ {
+diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
+index 7b2170b..90923de 100644
+--- a/include/linux/spi/spi.h
++++ b/include/linux/spi/spi.h
+@@ -16,6 +16,7 @@
+ #define __LINUX_SPI_H
+ 
+ #include <linux/device.h>
++#include <linux/dma-direction.h>
+ #include <linux/mod_devicetable.h>
+ #include <linux/slab.h>
+ #include <linux/kthread.h>
+@@ -614,6 +615,31 @@ static inline bool spi_controller_is_slave(struct spi_controller *ctlr)
+ extern int spi_controller_suspend(struct spi_controller *ctlr);
+ extern int spi_controller_resume(struct spi_controller *ctlr);
+ 
++/*
++ * Helpers needed by the spi-mem logic. Should not be used outside of
++ * spi-mem.c
++ */
++#ifdef CONFIG_HAS_DMA
++int spi_map_buf(struct spi_controller *ctlr, struct device *dev,
++		struct sg_table *sgt, void *buf, size_t len,
++		enum dma_data_direction dir);
++void spi_unmap_buf(struct spi_controller *ctlr, struct device *dev,
++		   struct sg_table *sgt, enum dma_data_direction dir);
++#else /* !CONFIG_HAS_DMA */
++static inline int spi_map_buf(struct spi_controller *ctlr, struct device *dev,
++			      struct sg_table *sgt, void *buf, size_t len,
++			      enum dma_data_direction dir)
++{
++	return -EINVAL;
++}
++
++static inline void spi_unmap_buf(struct spi_controller *ctlr,
++				 struct device *dev, struct sg_table *sgt,
++				 enum dma_data_direction dir)
++{
++}
++#endif /* CONFIG_HAS_DMA */
++
+ /* Calls the driver make to interact with the message queue */
+ extern struct spi_message *spi_get_next_queued_message(struct spi_controller *ctlr);
+ extern void spi_finalize_current_message(struct spi_controller *ctlr);
+-- 
+2.7.4
+
diff --git a/recipes-kernel/linux/linux-stm32mp/patches/0006-spi-Add-an-helper-to-flush-the-message-queue.patch b/recipes-kernel/linux/linux-stm32mp/patches/0006-spi-Add-an-helper-to-flush-the-message-queue.patch
new file mode 100644
index 0000000000000000000000000000000000000000..1c3ba9d1076f664c7fac82e38bbc63b7e22fa6ec
--- /dev/null
+++ b/recipes-kernel/linux/linux-stm32mp/patches/0006-spi-Add-an-helper-to-flush-the-message-queue.patch
@@ -0,0 +1,62 @@
+From a260aba3aff85d96d6e9e46e0fec63545e346b4e Mon Sep 17 00:00:00 2001
+From: Boris Brezillon <boris.brezillon@bootlin.com>
+Date: Tue, 10 Apr 2018 23:09:55 +0200
+Subject: [PATCH 06/28] spi: Add an helper to flush the message queue
+
+This is needed by the spi-mem logic to force all messages that have been
+queued before a memory operation to be sent before we start the memory
+operation. We do that in order to guarantee that spi-mem operations do
+not preempt regular SPI transfers.
+
+Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
+---
+As for the spi_map/unmap_buf() I'd suggest to move the prototype
+definition to an internal header file.
+---
+ drivers/spi/spi.c       | 16 ++++++++++++++++
+ include/linux/spi/spi.h |  2 ++
+ 2 files changed, 18 insertions(+)
+
+diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
+index 81ff208..b0c1fcf 100644
+--- a/drivers/spi/spi.c
++++ b/drivers/spi/spi.c
+@@ -1514,6 +1514,22 @@ static int spi_controller_initialize_queue(struct spi_controller *ctlr)
+ 	return ret;
+ }
+ 
++/**
++ * spi_flush_queue - Send all pending messages in the queue from the callers'
++ *		     context
++ * @ctlr: controller to process queue for
++ *
++ * This should be used when one wants to ensure all pending messages have been
++ * sent before doing something. Is used by the spi-mem code to make sure SPI
++ * memory operations do not preempt regular SPI transfers that have been queued
++ * before the spi-mem operation.
++ */
++void spi_flush_queue(struct spi_controller *ctlr)
++{
++	if (ctlr->transfer == spi_queued_transfer)
++		__spi_pump_messages(ctlr, false);
++}
++
+ /*-------------------------------------------------------------------------*/
+ 
+ #if defined(CONFIG_OF)
+diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
+index 90923de..5c7618c 100644
+--- a/include/linux/spi/spi.h
++++ b/include/linux/spi/spi.h
+@@ -619,6 +619,8 @@ extern int spi_controller_resume(struct spi_controller *ctlr);
+  * Helpers needed by the spi-mem logic. Should not be used outside of
+  * spi-mem.c
+  */
++void spi_flush_queue(struct spi_controller *ctrl);
++
+ #ifdef CONFIG_HAS_DMA
+ int spi_map_buf(struct spi_controller *ctlr, struct device *dev,
+ 		struct sg_table *sgt, void *buf, size_t len,
+-- 
+2.7.4
+
diff --git a/recipes-kernel/linux/linux-stm32mp/patches/0007-spi-Extend-the-core-to-ease-integration-of-SPI-memor.patch b/recipes-kernel/linux/linux-stm32mp/patches/0007-spi-Extend-the-core-to-ease-integration-of-SPI-memor.patch
new file mode 100644
index 0000000000000000000000000000000000000000..d5cdccfccb6195de3e170cca2ba4ca2c75224e73
--- /dev/null
+++ b/recipes-kernel/linux/linux-stm32mp/patches/0007-spi-Extend-the-core-to-ease-integration-of-SPI-memor.patch
@@ -0,0 +1,770 @@
+From 15baaa975254e7a81dbe556b4e37026db009e5d3 Mon Sep 17 00:00:00 2001
+From: Boris Brezillon <boris.brezillon@bootlin.com>
+Date: Thu, 25 Jan 2018 14:58:12 +0100
+Subject: [PATCH 07/28] spi: Extend the core to ease integration of SPI memory
+ controllers
+
+Some controllers are exposing high-level interfaces to access various
+kind of SPI memories. Unfortunately they do not fit in the current
+spi_controller model and usually have drivers placed in
+drivers/mtd/spi-nor which are only supporting SPI NORs and not SPI
+memories in general.
+
+This is an attempt at defining a SPI memory interface which works for
+all kinds of SPI memories (NORs, NANDs, SRAMs).
+
+Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
+---
+Changes in v2:
+- Move all changes not directly related to spi_mem out of this commit
+- Do not abuse ternary operation
+- Reword a few comments and fix typos
+- Do not make the default buswidth check in spi_mem_support_ops() if
+  the controller implements this hook
+- Make the addr value an u64 instead of an array of byte
+- Move all spi-mem code/defs to separate header/source files and add a
+  new Kconfig option to enable this interface
+---
+ drivers/spi/Kconfig         |   7 +
+ drivers/spi/Makefile        |   1 +
+ drivers/spi/spi-mem.c       | 408 ++++++++++++++++++++++++++++++++++++++++++++
+ include/linux/spi/spi-mem.h | 249 +++++++++++++++++++++++++++
+ include/linux/spi/spi.h     |   7 +
+ 5 files changed, 672 insertions(+)
+ create mode 100644 drivers/spi/spi-mem.c
+ create mode 100644 include/linux/spi/spi-mem.h
+
+diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
+index a75f2a2..378e6a4 100644
+--- a/drivers/spi/Kconfig
++++ b/drivers/spi/Kconfig
+@@ -51,6 +51,13 @@ config SPI_MASTER
+ 
+ if SPI_MASTER
+ 
++config SPI_MEM
++	bool "SPI memory extension"
++	help
++	  Enable this option if you want to enable the SPI memory extension.
++	  This extension is meant to simplify interaction with SPI memories
++	  by providing an high-level interface to send memory-like commands.
++
+ comment "SPI Master Controller Drivers"
+ 
+ config SPI_ALTERA
+diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
+index 8e0cda7..d95bfe9 100644
+--- a/drivers/spi/Makefile
++++ b/drivers/spi/Makefile
+@@ -8,6 +8,7 @@ ccflags-$(CONFIG_SPI_DEBUG) := -DDEBUG
+ # small core, mostly translating board-specific
+ # config declarations into driver model code
+ obj-$(CONFIG_SPI_MASTER)		+= spi.o
++obj-$(CONFIG_SPI_MEM)			+= spi-mem.o
+ obj-$(CONFIG_SPI_SPIDEV)		+= spidev.o
+ obj-$(CONFIG_SPI_LOOPBACK_TEST)		+= spi-loopback-test.o
+ 
+diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c
+new file mode 100644
+index 0000000..ecaa8d7
+--- /dev/null
++++ b/drivers/spi/spi-mem.c
+@@ -0,0 +1,408 @@
++// SPDX-License-Identifier: GPL-2.0+
++/*
++ * Copyright (C) 2018 Exceet Electronics GmbH
++ * Copyright (C) 2018 Bootlin
++ *
++ * Author: Boris Brezillon <boris.brezillon@bootlin.com>
++ */
++#include <linux/dmaengine.h>
++#include <linux/pm_runtime.h>
++#include <linux/spi/spi.h>
++#include <linux/spi/spi-mem.h>
++
++/**
++ * spi_controller_dma_map_mem_op_data() - DMA-map the buffer attached to a
++ *					  memory operation
++ * @ctlr: the SPI controller requesting this dma_map()
++ * @op: the memory operation containing the buffer to map
++ * @sgt: a pointer to a non-initialized sg_table that will be filled by this
++ *	 function
++ *
++ * Some controllers might want to do DMA on the data buffer embedded in @op.
++ * This helper prepares everything for you and provides a ready-to-use
++ * sg_table. This function is not intended to be called from spi drivers.
++ * Only SPI controller drivers should use it.
++ * Note that the caller must ensure the memory region pointed by
++ * op->data.buf.{in,out} is DMA-able before calling this function.
++ *
++ * Return: 0 in case of success, a negative error code otherwise.
++ */
++int spi_controller_dma_map_mem_op_data(struct spi_controller *ctlr,
++				       const struct spi_mem_op *op,
++				       struct sg_table *sgt)
++{
++	struct device *dmadev;
++
++	if (!op->data.nbytes)
++		return -EINVAL;
++
++	if (op->data.dir == SPI_MEM_DATA_OUT && ctlr->dma_tx)
++		dmadev = ctlr->dma_tx->device->dev;
++	else if (op->data.dir == SPI_MEM_DATA_IN && ctlr->dma_rx)
++		dmadev = ctlr->dma_rx->device->dev;
++	else
++		dmadev = ctlr->dev.parent;
++
++	if (!dmadev)
++		return -EINVAL;
++
++	return spi_map_buf(ctlr, dmadev, sgt, op->data.buf.in, op->data.nbytes,
++			   op->data.dir == SPI_MEM_DATA_IN ?
++			   DMA_FROM_DEVICE : DMA_TO_DEVICE);
++}
++EXPORT_SYMBOL_GPL(spi_controller_dma_map_mem_op_data);
++
++/**
++ * spi_controller_dma_unmap_mem_op_data() - DMA-unmap the buffer attached to a
++ *					    memory operation
++ * @ctlr: the SPI controller requesting this dma_unmap()
++ * @op: the memory operation containing the buffer to unmap
++ * @sgt: a pointer to an sg_table previously initialized by
++ *	 spi_controller_dma_map_mem_op_data()
++ *
++ * Some controllers might want to do DMA on the data buffer embedded in @op.
++ * This helper prepares things so that the CPU can access the
++ * op->data.buf.{in,out} buffer again.
++ *
++ * This function is not intended to be called from SPI drivers. Only SPI
++ * controller drivers should use it.
++ *
++ * This function should be called after the DMA operation has finished and is
++ * only valid if the previous spi_controller_dma_map_mem_op_data() call
++ * returned 0.
++ *
++ * Return: 0 in case of success, a negative error code otherwise.
++ */
++void spi_controller_dma_unmap_mem_op_data(struct spi_controller *ctlr,
++					  const struct spi_mem_op *op,
++					  struct sg_table *sgt)
++{
++	struct device *dmadev;
++
++	if (!op->data.nbytes)
++		return;
++
++	if (op->data.dir == SPI_MEM_DATA_OUT && ctlr->dma_tx)
++		dmadev = ctlr->dma_tx->device->dev;
++	else if (op->data.dir == SPI_MEM_DATA_IN && ctlr->dma_rx)
++		dmadev = ctlr->dma_rx->device->dev;
++	else
++		dmadev = ctlr->dev.parent;
++
++	spi_unmap_buf(ctlr, dmadev, sgt,
++		      op->data.dir == SPI_MEM_DATA_IN ?
++		      DMA_FROM_DEVICE : DMA_TO_DEVICE);
++}
++EXPORT_SYMBOL_GPL(spi_controller_dma_unmap_mem_op_data);
++
++static int spi_check_buswidth_req(struct spi_mem *mem, u8 buswidth, bool tx)
++{
++	u32 mode = mem->spi->mode;
++
++	switch (buswidth) {
++	case 1:
++		return 0;
++
++	case 2:
++		if ((tx && (mode & (SPI_TX_DUAL | SPI_TX_QUAD))) ||
++		    (!tx && (mode & (SPI_RX_DUAL | SPI_RX_QUAD))))
++			return 0;
++
++		break;
++
++	case 4:
++		if ((tx && (mode & SPI_TX_QUAD)) ||
++		    (!tx && (mode & SPI_RX_QUAD)))
++			return 0;
++
++		break;
++
++	default:
++		break;
++	}
++
++	return -ENOTSUPP;
++}
++
++static bool spi_mem_default_supports_op(struct spi_mem *mem,
++					const struct spi_mem_op *op)
++{
++	if (spi_check_buswidth_req(mem, op->cmd.buswidth, true))
++		return false;
++
++	if (op->addr.nbytes &&
++	    spi_check_buswidth_req(mem, op->addr.buswidth, true))
++		return false;
++
++	if (op->dummy.nbytes &&
++	    spi_check_buswidth_req(mem, op->dummy.buswidth, true))
++		return false;
++
++	if (op->data.nbytes &&
++	    spi_check_buswidth_req(mem, op->data.buswidth,
++				   op->data.dir == SPI_MEM_DATA_OUT))
++		return false;
++
++	return true;
++}
++EXPORT_SYMBOL_GPL(spi_mem_default_supports_op);
++
++/**
++ * spi_mem_supports_op() - Check if a memory device and the controller it is
++ *			   connected to support a specific memory operation
++ * @mem: the SPI memory
++ * @op: the memory operation to check
++ *
++ * Some controllers are only supporting Single or Dual IOs, others might only
++ * support specific opcodes, or it can even be that the controller and device
++ * both support Quad IOs but the hardware prevents you from using it because
++ * only 2 IO lines are connected.
++ *
++ * This function checks whether a specific operation is supported.
++ *
++ * Return: true if @op is supported, false otherwise.
++ */
++bool spi_mem_supports_op(struct spi_mem *mem, const struct spi_mem_op *op)
++{
++	struct spi_controller *ctlr = mem->spi->controller;
++
++	if (ctlr->mem_ops && ctlr->mem_ops->supports_op)
++		return ctlr->mem_ops->supports_op(mem, op);
++
++	return spi_mem_default_supports_op(mem, op);
++}
++EXPORT_SYMBOL_GPL(spi_mem_supports_op);
++
++/**
++ * spi_mem_exec_op() - Execute a memory operation
++ * @mem: the SPI memory
++ * @op: the memory operation to execute
++ *
++ * Executes a memory operation.
++ *
++ * This function first checks that @op is supported and then tries to execute
++ * it.
++ *
++ * Return: 0 in case of success, a negative error code otherwise.
++ */
++int spi_mem_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
++{
++	unsigned int tmpbufsize, xferpos = 0, totalxferlen = 0;
++	struct spi_controller *ctlr = mem->spi->controller;
++	struct spi_transfer xfers[4] = { };
++	struct spi_message msg;
++	u8 *tmpbuf;
++	int ret;
++
++	if (!spi_mem_supports_op(mem, op))
++		return -ENOTSUPP;
++
++	if (ctlr->mem_ops) {
++		/*
++		 * Flush the message queue before executing our SPI memory
++		 * operation to prevent preemption of regular SPI transfers.
++		 */
++		spi_flush_queue(ctlr);
++
++		if (ctlr->auto_runtime_pm) {
++			ret = pm_runtime_get_sync(ctlr->dev.parent);
++			if (ret < 0) {
++				dev_err(&ctlr->dev,
++					"Failed to power device: %d\n",
++					ret);
++				return ret;
++			}
++		}
++
++		mutex_lock(&ctlr->bus_lock_mutex);
++		mutex_lock(&ctlr->io_mutex);
++		ret = ctlr->mem_ops->exec_op(mem, op);
++		mutex_unlock(&ctlr->io_mutex);
++		mutex_unlock(&ctlr->bus_lock_mutex);
++
++		if (ctlr->auto_runtime_pm)
++			pm_runtime_put(ctlr->dev.parent);
++
++		/*
++		 * Some controllers only optimize specific paths (typically the
++		 * read path) and expect the core to use the regular SPI
++		 * interface in other cases.
++		 */
++		if (!ret || ret != -ENOTSUPP)
++			return ret;
++	}
++
++	tmpbufsize = sizeof(op->cmd.opcode) + op->addr.nbytes +
++		     op->dummy.nbytes;
++
++	/*
++	 * Allocate a buffer to transmit the CMD, ADDR cycles with kmalloc() so
++	 * we're guaranteed that this buffer is DMA-able, as required by the
++	 * SPI layer.
++	 */
++	tmpbuf = kzalloc(tmpbufsize, GFP_KERNEL | GFP_DMA);
++	if (!tmpbuf)
++		return -ENOMEM;
++
++	spi_message_init(&msg);
++
++	tmpbuf[0] = op->cmd.opcode;
++	xfers[xferpos].tx_buf = tmpbuf;
++	xfers[xferpos].len = sizeof(op->cmd.opcode);
++	xfers[xferpos].tx_nbits = op->cmd.buswidth;
++	spi_message_add_tail(&xfers[xferpos], &msg);
++	xferpos++;
++	totalxferlen++;
++
++	if (op->addr.nbytes) {
++		int i;
++
++		for (i = 0; i < op->addr.nbytes; i++)
++			tmpbuf[i + 1] = op->addr.val >>
++					(8 * (op->addr.nbytes - i - 1));
++
++		xfers[xferpos].tx_buf = tmpbuf + 1;
++		xfers[xferpos].len = op->addr.nbytes;
++		xfers[xferpos].tx_nbits = op->addr.buswidth;
++		spi_message_add_tail(&xfers[xferpos], &msg);
++		xferpos++;
++		totalxferlen += op->addr.nbytes;
++	}
++
++	if (op->dummy.nbytes) {
++		memset(tmpbuf + op->addr.nbytes + 1, 0xff, op->dummy.nbytes);
++		xfers[xferpos].tx_buf = tmpbuf + op->addr.nbytes + 1;
++		xfers[xferpos].len = op->dummy.nbytes;
++		xfers[xferpos].tx_nbits = op->dummy.buswidth;
++		spi_message_add_tail(&xfers[xferpos], &msg);
++		xferpos++;
++		totalxferlen += op->dummy.nbytes;
++	}
++
++	if (op->data.nbytes) {
++		if (op->data.dir == SPI_MEM_DATA_IN) {
++			xfers[xferpos].rx_buf = op->data.buf.in;
++			xfers[xferpos].rx_nbits = op->data.buswidth;
++		} else {
++			xfers[xferpos].tx_buf = op->data.buf.out;
++			xfers[xferpos].tx_nbits = op->data.buswidth;
++		}
++
++		xfers[xferpos].len = op->data.nbytes;
++		spi_message_add_tail(&xfers[xferpos], &msg);
++		xferpos++;
++		totalxferlen += op->data.nbytes;
++	}
++
++	ret = spi_sync(mem->spi, &msg);
++
++	kfree(tmpbuf);
++
++	if (ret)
++		return ret;
++
++	if (msg.actual_length != totalxferlen)
++		return -EIO;
++
++	return 0;
++}
++EXPORT_SYMBOL_GPL(spi_mem_exec_op);
++
++/**
++ * spi_mem_adjust_op_size() - Adjust the data size of a SPI mem operation to
++ *			      match controller limitations
++ * @mem: the SPI memory
++ * @op: the operation to adjust
++ *
++ * Some controllers have FIFO limitations and must split a data transfer
++ * operation into multiple ones, others require a specific alignment for
++ * optimized accesses. This function allows SPI mem drivers to split a single
++ * operation into multiple sub-operations when required.
++ *
++ * Return: a negative error code if the controller can't properly adjust @op,
++ *	   0 otherwise. Note that @op->data.nbytes will be updated if @op
++ *	   can't be handled in a single step.
++ */
++int spi_mem_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op)
++{
++	struct spi_controller *ctlr = mem->spi->controller;
++
++	if (ctlr->mem_ops && ctlr->mem_ops->adjust_op_size)
++		return ctlr->mem_ops->adjust_op_size(mem, op);
++
++	return 0;
++}
++EXPORT_SYMBOL_GPL(spi_mem_adjust_op_size);
++
++static inline struct spi_mem_driver *to_spi_mem_drv(struct device_driver *drv)
++{
++	return container_of(drv, struct spi_mem_driver, spidrv.driver);
++}
++
++static int spi_mem_probe(struct spi_device *spi)
++{
++	struct spi_mem_driver *memdrv = to_spi_mem_drv(spi->dev.driver);
++	struct spi_mem *mem;
++
++	mem = devm_kzalloc(&spi->dev, sizeof(*mem), GFP_KERNEL);
++	if (!mem)
++		return -ENOMEM;
++
++	mem->spi = spi;
++	spi_set_drvdata(spi, mem);
++
++	return memdrv->probe(mem);
++}
++
++static int spi_mem_remove(struct spi_device *spi)
++{
++	struct spi_mem_driver *memdrv = to_spi_mem_drv(spi->dev.driver);
++	struct spi_mem *mem = spi_get_drvdata(spi);
++
++	if (memdrv->remove)
++		return memdrv->remove(mem);
++
++	return 0;
++}
++
++static void spi_mem_shutdown(struct spi_device *spi)
++{
++	struct spi_mem_driver *memdrv = to_spi_mem_drv(spi->dev.driver);
++	struct spi_mem *mem = spi_get_drvdata(spi);
++
++	if (memdrv->shutdown)
++		memdrv->shutdown(mem);
++}
++
++/**
++ * spi_mem_driver_register_with_owner() - Register a SPI memory driver
++ * @memdrv: the SPI memory driver to register
++ * @owner: the owner of this driver
++ *
++ * Registers a SPI memory driver.
++ *
++ * Return: 0 in case of success, a negative error core otherwise.
++ */
++
++int spi_mem_driver_register_with_owner(struct spi_mem_driver *memdrv,
++				       struct module *owner)
++{
++	memdrv->spidrv.probe = spi_mem_probe;
++	memdrv->spidrv.remove = spi_mem_remove;
++	memdrv->spidrv.shutdown = spi_mem_shutdown;
++
++	return __spi_register_driver(owner, &memdrv->spidrv);
++}
++EXPORT_SYMBOL_GPL(spi_mem_driver_register_with_owner);
++
++/**
++ * spi_mem_driver_unregister_with_owner() - Unregister a SPI memory driver
++ * @memdrv: the SPI memory driver to unregister
++ *
++ * Unregisters a SPI memory driver.
++ */
++void spi_mem_driver_unregister(struct spi_mem_driver *memdrv)
++{
++	spi_unregister_driver(&memdrv->spidrv);
++}
++EXPORT_SYMBOL_GPL(spi_mem_driver_unregister);
+diff --git a/include/linux/spi/spi-mem.h b/include/linux/spi/spi-mem.h
+new file mode 100644
+index 0000000..ac2e8d8
+--- /dev/null
++++ b/include/linux/spi/spi-mem.h
+@@ -0,0 +1,249 @@
++// SPDX-License-Identifier: GPL-2.0+
++/*
++ * Copyright (C) 2018 Exceet Electronics GmbH
++ * Copyright (C) 2018 Bootlin
++ *
++ * Author: Boris Brezillon <boris.brezillon@bootlin.com>
++ */
++
++#ifndef __LINUX_SPI_MEM_H
++#define __LINUX_SPI_MEM_H
++
++#include <linux/spi/spi.h>
++
++#define SPI_MEM_OP_CMD(__opcode, __buswidth)			\
++	{							\
++		.buswidth = __buswidth,				\
++		.opcode = __opcode,				\
++	}
++
++#define SPI_MEM_OP_ADDR(__nbytes, __val, __buswidth)		\
++	{							\
++		.nbytes = __nbytes,				\
++		.val = __val,					\
++		.buswidth = __buswidth,				\
++	}
++
++#define SPI_MEM_OP_NO_ADDR	{ }
++
++#define SPI_MEM_OP_DUMMY(__nbytes, __buswidth)			\
++	{							\
++		.nbytes = __nbytes,				\
++		.buswidth = __buswidth,				\
++	}
++
++#define SPI_MEM_OP_NO_DUMMY	{ }
++
++#define SPI_MEM_OP_DATA_IN(__nbytes, __buf, __buswidth)		\
++	{							\
++		.dir = SPI_MEM_DATA_IN,				\
++		.nbytes = __nbytes,				\
++		.buf.in = __buf,				\
++		.buswidth = __buswidth,				\
++	}
++
++#define SPI_MEM_OP_DATA_OUT(__nbytes, __buf, __buswidth)	\
++	{							\
++		.dir = SPI_MEM_DATA_OUT,			\
++		.nbytes = __nbytes,				\
++		.buf.out = __buf,				\
++		.buswidth = __buswidth,				\
++	}
++
++#define SPI_MEM_OP_NO_DATA	{ }
++
++/**
++ * enum spi_mem_data_dir - describes the direction of a SPI memory data
++ *			   transfer from the controller perspective
++ * @SPI_MEM_DATA_IN: data coming from the SPI memory
++ * @SPI_MEM_DATA_OUT: data sent the SPI memory
++ */
++enum spi_mem_data_dir {
++	SPI_MEM_DATA_IN,
++	SPI_MEM_DATA_OUT,
++};
++
++/**
++ * struct spi_mem_op - describes a SPI memory operation
++ * @cmd.buswidth: number of IO lines used to transmit the command
++ * @cmd.opcode: operation opcode
++ * @addr.nbytes: number of address bytes to send. Can be zero if the operation
++ *		 does not need to send an address
++ * @addr.buswidth: number of IO lines used to transmit the address cycles
++ * @addr.val: address value. This value is always sent MSB first on the bus.
++ *	      Note that only @addr.nbytes are taken into account in this
++ *	      address value, so users should make sure the value fits in the
++ *	      assigned number of bytes.
++ * @dummy.nbytes: number of dummy bytes to send after an opcode or address. Can
++ *		  be zero if the operation does not require dummy bytes
++ * @dummy.buswidth: number of IO lanes used to transmit the dummy bytes
++ * @data.buswidth: number of IO lanes used to send/receive the data
++ * @data.dir: direction of the transfer
++ * @data.buf.in: input buffer
++ * @data.buf.out: output buffer
++ */
++struct spi_mem_op {
++	struct {
++		u8 buswidth;
++		u8 opcode;
++	} cmd;
++
++	struct {
++		u8 nbytes;
++		u8 buswidth;
++		u64 val;
++	} addr;
++
++	struct {
++		u8 nbytes;
++		u8 buswidth;
++	} dummy;
++
++	struct {
++		u8 buswidth;
++		enum spi_mem_data_dir dir;
++		unsigned int nbytes;
++		/* buf.{in,out} must be DMA-able. */
++		union {
++			void *in;
++			const void *out;
++		} buf;
++	} data;
++};
++
++#define SPI_MEM_OP(__cmd, __addr, __dummy, __data)		\
++	{							\
++		.cmd = __cmd,					\
++		.addr = __addr,					\
++		.dummy = __dummy,				\
++		.data = __data,					\
++	}
++
++/**
++ * struct spi_mem - describes a SPI memory device
++ * @spi: the underlying SPI device
++ * @drvpriv: spi_mem_drviver private data
++ *
++ * Extra information that describe the SPI memory device and may be needed by
++ * the controller to properly handle this device should be placed here.
++ *
++ * One example would be the device size since some controller expose their SPI
++ * mem devices through a io-mapped region.
++ */
++struct spi_mem {
++	struct spi_device *spi;
++	void *drvpriv;
++};
++
++/**
++ * struct spi_mem_set_drvdata() - attach driver private data to a SPI mem
++ *				  device
++ * @mem: memory device
++ * @data: data to attach to the memory device
++ */
++static inline void spi_mem_set_drvdata(struct spi_mem *mem, void *data)
++{
++	mem->drvpriv = data;
++}
++
++/**
++ * struct spi_mem_get_drvdata() - get driver private data attached to a SPI mem
++ *				  device
++ * @mem: memory device
++ *
++ * Return: the data attached to the mem device.
++ */
++static inline void *spi_mem_get_drvdata(struct spi_mem *mem)
++{
++	return mem->drvpriv;
++}
++
++/**
++ * struct spi_controller_mem_ops - SPI memory operations
++ * @adjust_op_size: shrink the data xfer of an operation to match controller's
++ *		    limitations (can be alignment of max RX/TX size
++ *		    limitations)
++ * @supports_op: check if an operation is supported by the controller
++ * @exec_op: execute a SPI memory operation
++ *
++ * This interface should be implemented by SPI controllers providing an
++ * high-level interface to execute SPI memory operation, which is usually the
++ * case for QSPI controllers.
++ */
++struct spi_controller_mem_ops {
++	int (*adjust_op_size)(struct spi_mem *mem, struct spi_mem_op *op);
++	bool (*supports_op)(struct spi_mem *mem,
++			    const struct spi_mem_op *op);
++	int (*exec_op)(struct spi_mem *mem,
++		       const struct spi_mem_op *op);
++};
++
++/**
++ * struct spi_mem_driver - SPI memory driver
++ * @spidrv: inherit from a SPI driver
++ * @probe: probe a SPI memory. Usually where detection/initialization takes
++ *	   place
++ * @remove: remove a SPI memory
++ * @shutdown: take appropriate action when the system is shutdown
++ *
++ * This is just a thin wrapper around a spi_driver. The core takes care of
++ * allocating the spi_mem object and forwarding the probe/remove/shutdown
++ * request to the spi_mem_driver. The reason we use this wrapper is because
++ * we might have to stuff more information into the spi_mem struct to let
++ * SPI controllers know more about the SPI memory they interact with, and
++ * having this intermediate layer allows us to do that without adding more
++ * useless fields to the spi_device object.
++ */
++struct spi_mem_driver {
++	struct spi_driver spidrv;
++	int (*probe)(struct spi_mem *mem);
++	int (*remove)(struct spi_mem *mem);
++	void (*shutdown)(struct spi_mem *mem);
++};
++
++#if IS_ENABLED(CONFIG_SPI_MEM)
++int spi_controller_dma_map_mem_op_data(struct spi_controller *ctlr,
++				       const struct spi_mem_op *op,
++				       struct sg_table *sg);
++
++void spi_controller_dma_unmap_mem_op_data(struct spi_controller *ctlr,
++					  const struct spi_mem_op *op,
++					  struct sg_table *sg);
++#else
++static inline int
++spi_controller_dma_map_mem_op_data(struct spi_controller *ctlr,
++				   const struct spi_mem_op *op,
++				   struct sg_table *sg)
++{
++	return -ENOTSUPP;
++}
++
++static inline void
++spi_controller_dma_unmap_mem_op_data(struct spi_controller *ctlr,
++				     const struct spi_mem_op *op,
++				     struct sg_table *sg)
++{
++}
++#endif /* CONFIG_SPI_MEM */
++
++int spi_mem_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op);
++
++bool spi_mem_supports_op(struct spi_mem *mem,
++			 const struct spi_mem_op *op);
++
++int spi_mem_exec_op(struct spi_mem *mem,
++		    const struct spi_mem_op *op);
++
++int spi_mem_driver_register_with_owner(struct spi_mem_driver *drv,
++				       struct module *owner);
++
++void spi_mem_driver_unregister(struct spi_mem_driver *drv);
++
++#define spi_mem_driver_register(__drv)                                  \
++	spi_mem_driver_register_with_owner(__drv, THIS_MODULE)
++
++#define module_spi_mem_driver(__drv)                                    \
++	module_driver(__drv, spi_mem_driver_register,                   \
++		      spi_mem_driver_unregister)
++
++#endif /* __LINUX_SPI_MEM_H */
+diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
+index 5c7618c..002e7e9 100644
+--- a/include/linux/spi/spi.h
++++ b/include/linux/spi/spi.h
+@@ -28,6 +28,7 @@ struct property_entry;
+ struct spi_controller;
+ struct spi_transfer;
+ struct spi_flash_read_message;
++struct spi_controller_mem_ops;
+ 
+ /*
+  * INTERFACES between SPI master-side drivers and SPI slave protocol handlers,
+@@ -377,6 +378,9 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv)
+  *                    transfer_one callback.
+  * @handle_err: the subsystem calls the driver to handle an error that occurs
+  *		in the generic implementation of transfer_one_message().
++ * @mem_ops: optimized/dedicated operations for interactions with SPI memory.
++ *	     This field is optional and should only be implemented if the
++ *	     controller has native support for memory like operations.
+  * @unprepare_message: undo any work done by prepare_message().
+  * @slave_abort: abort the ongoing transfer request on an SPI slave controller
+  * @spi_flash_read: to support spi-controller hardwares that provide
+@@ -565,6 +569,9 @@ struct spi_controller {
+ 	void (*handle_err)(struct spi_controller *ctlr,
+ 			   struct spi_message *message);
+ 
++	/* Optimized handlers for SPI memory-like operations. */
++	const struct spi_controller_mem_ops *mem_ops;
++
+ 	/* gpio chip select */
+ 	int			*cs_gpios;
+ 
+-- 
+2.7.4
+
diff --git a/recipes-kernel/linux/linux-stm32mp/patches/0008-spi-Make-support-for-regular-transfers-optional-when.patch b/recipes-kernel/linux/linux-stm32mp/patches/0008-spi-Make-support-for-regular-transfers-optional-when.patch
new file mode 100644
index 0000000000000000000000000000000000000000..a2ec2439cc605a16104fa1db31a003e71857a982
--- /dev/null
+++ b/recipes-kernel/linux/linux-stm32mp/patches/0008-spi-Make-support-for-regular-transfers-optional-when.patch
@@ -0,0 +1,96 @@
+From db84459b1f228ce0e4ccaae162a4e4a632360bad Mon Sep 17 00:00:00 2001
+From: Boris Brezillon <boris.brezillon@bootlin.com>
+Date: Tue, 10 Apr 2018 22:11:41 +0200
+Subject: [PATCH 08/28] spi: Make support for regular transfers optional when
+ ->mem_ops != NULL
+
+Some SPI/QuadSPI controllers only expose a high-level SPI memory
+interface, thus preventing any regular SPI transfers from being done.
+
+In that case, SPI controller drivers can leave all ->transfer_xxx()
+hooks empty and only implement the spi_mem_ops interface.
+
+Adjust the core to allow such situations:
+- extend spi_controller_check_ops() to accept situations where all
+  ->transfer_xxx() pointers are NULL only if ->mem_ops != NULL
+- make sure we do not initialize the SPI message queue if
+  ctlr->transfer_one and ctlr->transfer_one_message are missing
+- return -ENOTSUPP if someone tries to do a regular SPI transfer on
+  a controller that does not support it
+
+Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
+---
+ drivers/spi/spi.c | 33 ++++++++++++++++++++++++++-------
+ 1 file changed, 26 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
+index b0c1fcf..e81df02 100644
+--- a/drivers/spi/spi.c
++++ b/drivers/spi/spi.c
+@@ -28,6 +28,7 @@
+ #include <linux/slab.h>
+ #include <linux/mod_devicetable.h>
+ #include <linux/spi/spi.h>
++#include <linux/spi/spi-mem.h>
+ #include <linux/of_gpio.h>
+ #include <linux/pm_runtime.h>
+ #include <linux/pm_domain.h>
+@@ -2063,12 +2064,19 @@ static int of_spi_register_master(struct spi_controller *ctlr)
+ static int spi_controller_check_ops(struct spi_controller *ctlr)
+ {
+ 	/*
+-	 * The controller must at least implement one of the ->transfer()
+-	 * hooks.
++	 * The controller may implement only the high-level SPI-memory like
++	 * operations if it does not support regular SPI transfers, and this is
++	 * valid use case.
++	 * If ->mem_ops is NULL, we request that at least one of the
++	 * ->transfer_xxx() method be implemented.
+ 	 */
+-	if (!ctlr->transfer && !ctlr->transfer_one &&
+-	    !ctlr->transfer_one_message)
++	if (ctlr->mem_ops) {
++		if (!ctlr->mem_ops->exec_op)
++			return -EINVAL;
++	} else if (!ctlr->transfer && !ctlr->transfer_one &&
++		   !ctlr->transfer_one_message) {
+ 		return -EINVAL;
++	}
+ 
+ 	return 0;
+ }
+@@ -2179,10 +2187,14 @@ int spi_register_controller(struct spi_controller *ctlr)
+ 			spi_controller_is_slave(ctlr) ? "slave" : "master",
+ 			dev_name(&ctlr->dev));
+ 
+-	/* If we're using a queued driver, start the queue */
+-	if (ctlr->transfer)
++	/*
++	 * If we're using a queued driver, start the queue. Note that we don't
++	 * need the queueing logic if the driver is only supporting high-level
++	 * memory operations.
++	 */
++	if (ctlr->transfer) {
+ 		dev_info(dev, "controller is unqueued, this is deprecated\n");
+-	else {
++	} else if (ctlr->transfer_one || ctlr->transfer_one_message) {
+ 		status = spi_controller_initialize_queue(ctlr);
+ 		if (status) {
+ 			device_del(&ctlr->dev);
+@@ -2915,6 +2927,13 @@ static int __spi_async(struct spi_device *spi, struct spi_message *message)
+ {
+ 	struct spi_controller *ctlr = spi->controller;
+ 
++	/*
++	 * Some controllers do not support doing regular SPI transfers. Return
++	 * ENOTSUPP when this is the case.
++	 */
++	if (!ctlr->transfer)
++		return -ENOTSUPP;
++
+ 	message->spi = spi;
+ 
+ 	SPI_STATISTICS_INCREMENT_FIELD(&ctlr->statistics, spi_async);
+-- 
+2.7.4
+
diff --git a/recipes-kernel/linux/linux-stm32mp/patches/0009-spi-bcm-qspi-Implement-the-spi_mem-interface.patch b/recipes-kernel/linux/linux-stm32mp/patches/0009-spi-bcm-qspi-Implement-the-spi_mem-interface.patch
new file mode 100644
index 0000000000000000000000000000000000000000..95e92293bc0211de05a4eda75394a0352d206512
--- /dev/null
+++ b/recipes-kernel/linux/linux-stm32mp/patches/0009-spi-bcm-qspi-Implement-the-spi_mem-interface.patch
@@ -0,0 +1,438 @@
+From bdbe3609ab49264cb5dae8a998af452726ac483f Mon Sep 17 00:00:00 2001
+From: Boris Brezillon <boris.brezillon@bootlin.com>
+Date: Wed, 31 Jan 2018 22:19:06 +0100
+Subject: [PATCH 09/28] spi: bcm-qspi: Implement the spi_mem interface
+
+The spi_mem interface is meant to replace the ->spi_flash_read() one.
+Implement the ->exec_op() method to ease removal of the old interface.
+
+Not that ->spi_flash_read() is now implemented as a wrapper around the
+new bcm_qspi_exec_mem_op() function so that we can easily get rid of
+it when ->spi_flash_read() is removed.
+
+Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
+---
+Changes in v2:
+- include spi-mem.h
+- treat op->addr.val differently since it's now an u64
+---
+ drivers/spi/spi-bcm-qspi.c | 190 ++++++++++++++++++++++++++-------------------
+ 1 file changed, 111 insertions(+), 79 deletions(-)
+
+diff --git a/drivers/spi/spi-bcm-qspi.c b/drivers/spi/spi-bcm-qspi.c
+index a172ab2..227921a 100644
+--- a/drivers/spi/spi-bcm-qspi.c
++++ b/drivers/spi/spi-bcm-qspi.c
+@@ -30,6 +30,7 @@
+ #include <linux/platform_device.h>
+ #include <linux/slab.h>
+ #include <linux/spi/spi.h>
++#include <linux/spi/spi-mem.h>
+ #include <linux/sysfs.h>
+ #include <linux/types.h>
+ #include "spi-bcm-qspi.h"
+@@ -215,10 +216,10 @@ struct bcm_qspi {
+ 	int bspi_maj_rev;
+ 	int bspi_min_rev;
+ 	int bspi_enabled;
+-	struct spi_flash_read_message *bspi_rf_msg;
+-	u32 bspi_rf_msg_idx;
+-	u32 bspi_rf_msg_len;
+-	u32 bspi_rf_msg_status;
++	const struct spi_mem_op *bspi_rf_op;
++	u32 bspi_rf_op_idx;
++	u32 bspi_rf_op_len;
++	u32 bspi_rf_op_status;
+ 	struct bcm_xfer_mode xfer_mode;
+ 	u32 s3_strap_override_ctrl;
+ 	bool bspi_mode;
+@@ -313,26 +314,26 @@ static inline void bcm_qspi_bspi_lr_clear(struct bcm_qspi *qspi)
+ 
+ static void bcm_qspi_bspi_lr_data_read(struct bcm_qspi *qspi)
+ {
+-	u32 *buf = (u32 *)qspi->bspi_rf_msg->buf;
++	u32 *buf = (u32 *)qspi->bspi_rf_op->data.buf.in;
+ 	u32 data = 0;
+ 
+-	dev_dbg(&qspi->pdev->dev, "xfer %p rx %p rxlen %d\n", qspi->bspi_rf_msg,
+-		qspi->bspi_rf_msg->buf, qspi->bspi_rf_msg_len);
++	dev_dbg(&qspi->pdev->dev, "xfer %p rx %p rxlen %d\n", qspi->bspi_rf_op,
++		qspi->bspi_rf_op->data.buf.in, qspi->bspi_rf_op_len);
+ 	while (!bcm_qspi_bspi_lr_is_fifo_empty(qspi)) {
+ 		data = bcm_qspi_bspi_lr_read_fifo(qspi);
+-		if (likely(qspi->bspi_rf_msg_len >= 4) &&
++		if (likely(qspi->bspi_rf_op_len >= 4) &&
+ 		    IS_ALIGNED((uintptr_t)buf, 4)) {
+-			buf[qspi->bspi_rf_msg_idx++] = data;
+-			qspi->bspi_rf_msg_len -= 4;
++			buf[qspi->bspi_rf_op_idx++] = data;
++			qspi->bspi_rf_op_len -= 4;
+ 		} else {
+ 			/* Read out remaining bytes, make sure*/
+-			u8 *cbuf = (u8 *)&buf[qspi->bspi_rf_msg_idx];
++			u8 *cbuf = (u8 *)&buf[qspi->bspi_rf_op_idx];
+ 
+ 			data = cpu_to_le32(data);
+-			while (qspi->bspi_rf_msg_len) {
++			while (qspi->bspi_rf_op_len) {
+ 				*cbuf++ = (u8)data;
+ 				data >>= 8;
+-				qspi->bspi_rf_msg_len--;
++				qspi->bspi_rf_op_len--;
+ 			}
+ 		}
+ 	}
+@@ -349,14 +350,12 @@ static void bcm_qspi_bspi_set_xfer_params(struct bcm_qspi *qspi, u8 cmd_byte,
+ }
+ 
+ static int bcm_qspi_bspi_set_flex_mode(struct bcm_qspi *qspi,
+-				       struct spi_flash_read_message *msg,
+-				       int hp)
++				       const struct spi_mem_op *op, int hp)
+ {
+ 	int bpc = 0, bpp = 0;
+-	u8 command = msg->read_opcode;
+-	int width  = msg->data_nbits ? msg->data_nbits : SPI_NBITS_SINGLE;
+-	int addrlen = msg->addr_width;
+-	int addr_nbits = msg->addr_nbits ? msg->addr_nbits : SPI_NBITS_SINGLE;
++	u8 command = op->cmd.opcode;
++	int width  = op->cmd.buswidth ? op->cmd.buswidth : SPI_NBITS_SINGLE;
++	int addrlen = op->addr.nbytes * 8;
+ 	int flex_mode = 1;
+ 
+ 	dev_dbg(&qspi->pdev->dev, "set flex mode w %x addrlen %x hp %d\n",
+@@ -365,7 +364,7 @@ static int bcm_qspi_bspi_set_flex_mode(struct bcm_qspi *qspi,
+ 	if (addrlen == BSPI_ADDRLEN_4BYTES)
+ 		bpp = BSPI_BPP_ADDR_SELECT_MASK;
+ 
+-	bpp |= msg->dummy_bytes * (8/addr_nbits);
++	bpp |= (op->dummy.nbytes * 8) / op->dummy.buswidth;
+ 
+ 	switch (width) {
+ 	case SPI_NBITS_SINGLE:
+@@ -397,11 +396,10 @@ static int bcm_qspi_bspi_set_flex_mode(struct bcm_qspi *qspi,
+ }
+ 
+ static int bcm_qspi_bspi_set_override(struct bcm_qspi *qspi,
+-				      struct spi_flash_read_message *msg,
+-				      int hp)
++				      const struct spi_mem_op *op, int hp)
+ {
+-	int width = msg->data_nbits ? msg->data_nbits : SPI_NBITS_SINGLE;
+-	int addrlen = msg->addr_width;
++	int width = op->data.buswidth ? op->data.buswidth : SPI_NBITS_SINGLE;
++	int addrlen = op->addr.nbytes;
+ 	u32 data = bcm_qspi_read(qspi, BSPI, BSPI_STRAP_OVERRIDE_CTRL);
+ 
+ 	dev_dbg(&qspi->pdev->dev, "set override mode w %x addrlen %x hp %d\n",
+@@ -437,17 +435,17 @@ static int bcm_qspi_bspi_set_override(struct bcm_qspi *qspi,
+ 	/* set the override mode */
+ 	data |=	BSPI_STRAP_OVERRIDE_CTRL_OVERRIDE;
+ 	bcm_qspi_write(qspi, BSPI, BSPI_STRAP_OVERRIDE_CTRL, data);
+-	bcm_qspi_bspi_set_xfer_params(qspi, msg->read_opcode, 0, 0, 0);
++	bcm_qspi_bspi_set_xfer_params(qspi, op->cmd.opcode, 0, 0, 0);
+ 
+ 	return 0;
+ }
+ 
+ static int bcm_qspi_bspi_set_mode(struct bcm_qspi *qspi,
+-				  struct spi_flash_read_message *msg, int hp)
++				  const struct spi_mem_op *op, int hp)
+ {
+ 	int error = 0;
+-	int width = msg->data_nbits ? msg->data_nbits : SPI_NBITS_SINGLE;
+-	int addrlen = msg->addr_width;
++	int width = op->data.buswidth ? op->data.buswidth : SPI_NBITS_SINGLE;
++	int addrlen = op->addr.nbytes;
+ 
+ 	/* default mode */
+ 	qspi->xfer_mode.flex_mode = true;
+@@ -460,12 +458,12 @@ static int bcm_qspi_bspi_set_mode(struct bcm_qspi *qspi,
+ 		if (val & mask || qspi->s3_strap_override_ctrl & mask) {
+ 			qspi->xfer_mode.flex_mode = false;
+ 			bcm_qspi_write(qspi, BSPI, BSPI_FLEX_MODE_ENABLE, 0);
+-			error = bcm_qspi_bspi_set_override(qspi, msg, hp);
++			error = bcm_qspi_bspi_set_override(qspi, op, hp);
+ 		}
+ 	}
+ 
+ 	if (qspi->xfer_mode.flex_mode)
+-		error = bcm_qspi_bspi_set_flex_mode(qspi, msg, hp);
++		error = bcm_qspi_bspi_set_flex_mode(qspi, op, hp);
+ 
+ 	if (error) {
+ 		dev_warn(&qspi->pdev->dev,
+@@ -794,19 +792,20 @@ static int write_to_hw(struct bcm_qspi *qspi, struct spi_device *spi)
+ 	return slot;
+ }
+ 
+-static int bcm_qspi_bspi_flash_read(struct spi_device *spi,
+-				    struct spi_flash_read_message *msg)
++static int bcm_qspi_bspi_exec_mem_op(struct spi_device *spi,
++				     const struct spi_mem_op *op)
+ {
+ 	struct bcm_qspi *qspi = spi_master_get_devdata(spi->master);
+-	u32 addr = 0, len, rdlen, len_words;
++	u32 addr = 0, len, rdlen, len_words, from = 0;
+ 	int ret = 0;
+ 	unsigned long timeo = msecs_to_jiffies(100);
+ 	struct bcm_qspi_soc_intc *soc_intc = qspi->soc_intc;
+ 
+ 	if (bcm_qspi_bspi_ver_three(qspi))
+-		if (msg->addr_width == BSPI_ADDRLEN_4BYTES)
++		if (op->addr.nbytes == BSPI_ADDRLEN_4BYTES)
+ 			return -EIO;
+ 
++	from = op->addr.val;
+ 	bcm_qspi_chip_select(qspi, spi->chip_select);
+ 	bcm_qspi_write(qspi, MSPI, MSPI_WRITE_LOCK, 0);
+ 
+@@ -815,15 +814,15 @@ static int bcm_qspi_bspi_flash_read(struct spi_device *spi,
+ 	 * the upper address byte to bspi
+ 	 */
+ 	if (bcm_qspi_bspi_ver_three(qspi) == false) {
+-		addr = msg->from & 0xff000000;
++		addr = from & 0xff000000;
+ 		bcm_qspi_write(qspi, BSPI,
+ 			       BSPI_BSPI_FLASH_UPPER_ADDR_BYTE, addr);
+ 	}
+ 
+ 	if (!qspi->xfer_mode.flex_mode)
+-		addr = msg->from;
++		addr = from;
+ 	else
+-		addr = msg->from & 0x00ffffff;
++		addr = from & 0x00ffffff;
+ 
+ 	if (bcm_qspi_bspi_ver_three(qspi) == true)
+ 		addr = (addr + 0xc00000) & 0xffffff;
+@@ -832,8 +831,8 @@ static int bcm_qspi_bspi_flash_read(struct spi_device *spi,
+ 	 * read into the entire buffer by breaking the reads
+ 	 * into RAF buffer read lengths
+ 	 */
+-	len = msg->len;
+-	qspi->bspi_rf_msg_idx = 0;
++	len = op->data.nbytes;
++	qspi->bspi_rf_op_idx = 0;
+ 
+ 	do {
+ 		if (len > BSPI_READ_LENGTH)
+@@ -844,9 +843,9 @@ static int bcm_qspi_bspi_flash_read(struct spi_device *spi,
+ 		reinit_completion(&qspi->bspi_done);
+ 		bcm_qspi_enable_bspi(qspi);
+ 		len_words = (rdlen + 3) >> 2;
+-		qspi->bspi_rf_msg = msg;
+-		qspi->bspi_rf_msg_status = 0;
+-		qspi->bspi_rf_msg_len = rdlen;
++		qspi->bspi_rf_op = op;
++		qspi->bspi_rf_op_status = 0;
++		qspi->bspi_rf_op_len = rdlen;
+ 		dev_dbg(&qspi->pdev->dev,
+ 			"bspi xfr addr 0x%x len 0x%x", addr, rdlen);
+ 		bcm_qspi_write(qspi, BSPI, BSPI_RAF_START_ADDR, addr);
+@@ -871,7 +870,6 @@ static int bcm_qspi_bspi_flash_read(struct spi_device *spi,
+ 		}
+ 
+ 		/* set msg return length */
+-		msg->retlen += rdlen;
+ 		addr += rdlen;
+ 		len -= rdlen;
+ 	} while (len);
+@@ -906,61 +904,62 @@ static int bcm_qspi_transfer_one(struct spi_master *master,
+ 	return 0;
+ }
+ 
+-static int bcm_qspi_mspi_flash_read(struct spi_device *spi,
+-				    struct spi_flash_read_message *msg)
++static int bcm_qspi_mspi_exec_mem_op(struct spi_device *spi,
++				     const struct spi_mem_op *op)
+ {
+-	struct bcm_qspi *qspi = spi_master_get_devdata(spi->master);
++	struct spi_master *master = spi->master;
++	struct bcm_qspi *qspi = spi_master_get_devdata(master);
+ 	struct spi_transfer t[2];
+-	u8 cmd[6];
+-	int ret;
++	u8 cmd[6] = { };
++	int ret, i;
+ 
+ 	memset(cmd, 0, sizeof(cmd));
+ 	memset(t, 0, sizeof(t));
+ 
+ 	/* tx */
+ 	/* opcode is in cmd[0] */
+-	cmd[0] = msg->read_opcode;
+-	cmd[1] = msg->from >> (msg->addr_width * 8 -  8);
+-	cmd[2] = msg->from >> (msg->addr_width * 8 - 16);
+-	cmd[3] = msg->from >> (msg->addr_width * 8 - 24);
+-	cmd[4] = msg->from >> (msg->addr_width * 8 - 32);
++	cmd[0] = op->cmd.opcode;
++	for (i = 0; i < op->addr.nbytes; i++)
++		cmd[1 + i] = op->addr.val >> (8 * (op->addr.nbytes - i - 1));
++
+ 	t[0].tx_buf = cmd;
+-	t[0].len = msg->addr_width + msg->dummy_bytes + 1;
++	t[0].len = op->addr.nbytes + op->dummy.nbytes + 1;
+ 	t[0].bits_per_word = spi->bits_per_word;
+-	t[0].tx_nbits = msg->opcode_nbits;
++	t[0].tx_nbits = op->cmd.buswidth;
+ 	/* lets mspi know that this is not last transfer */
+ 	qspi->trans_pos.mspi_last_trans = false;
+-	ret = bcm_qspi_transfer_one(spi->master, spi, &t[0]);
++	ret = bcm_qspi_transfer_one(master, spi, &t[0]);
+ 
+ 	/* rx */
+ 	qspi->trans_pos.mspi_last_trans = true;
+ 	if (!ret) {
+ 		/* rx */
+-		t[1].rx_buf = msg->buf;
+-		t[1].len = msg->len;
+-		t[1].rx_nbits =  msg->data_nbits;
++		t[1].rx_buf = op->data.buf.in;
++		t[1].len = op->data.nbytes;
++		t[1].rx_nbits =  op->data.buswidth;
+ 		t[1].bits_per_word = spi->bits_per_word;
+-		ret = bcm_qspi_transfer_one(spi->master, spi, &t[1]);
++		ret = bcm_qspi_transfer_one(master, spi, &t[1]);
+ 	}
+ 
+-	if (!ret)
+-		msg->retlen = msg->len;
+-
+ 	return ret;
+ }
+ 
+-static int bcm_qspi_flash_read(struct spi_device *spi,
+-			       struct spi_flash_read_message *msg)
++static int bcm_qspi_exec_mem_op(struct spi_device *spi,
++				const struct spi_mem_op *op)
+ {
+ 	struct bcm_qspi *qspi = spi_master_get_devdata(spi->master);
+ 	int ret = 0;
+ 	bool mspi_read = false;
+-	u32 addr, len;
++	u32 addr = 0, len;
+ 	u_char *buf;
+ 
+-	buf = msg->buf;
+-	addr = msg->from;
+-	len = msg->len;
++	if (!op->data.nbytes || !op->addr.nbytes || op->addr.nbytes > 4 ||
++	    op->data.dir != SPI_MEM_DATA_IN)
++		return -ENOTSUPP;
++
++	buf = op->data.buf.in;
++	addr = op->addr.val;
++	len = op->data.nbytes;
+ 
+ 	if (bcm_qspi_bspi_ver_three(qspi) == true) {
+ 		/*
+@@ -982,12 +981,40 @@ static int bcm_qspi_flash_read(struct spi_device *spi,
+ 		mspi_read = true;
+ 
+ 	if (mspi_read)
+-		return bcm_qspi_mspi_flash_read(spi, msg);
++		return bcm_qspi_mspi_exec_mem_op(spi, op);
+ 
+-	ret = bcm_qspi_bspi_set_mode(qspi, msg, -1);
++	ret = bcm_qspi_bspi_set_mode(qspi, op, -1);
+ 
+ 	if (!ret)
+-		ret = bcm_qspi_bspi_flash_read(spi, msg);
++		ret = bcm_qspi_bspi_exec_mem_op(spi, op);
++
++	return ret;
++}
++
++static int bcm_qspi_exec_mem_op_wrapper(struct spi_mem *mem,
++					const struct spi_mem_op *op)
++{
++	return bcm_qspi_exec_mem_op(mem->spi, op);
++}
++
++static int bcm_qspi_flash_read_wrapper(struct spi_device *spi,
++				       struct spi_flash_read_message *msg)
++{
++	int ret;
++	struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(msg->read_opcode, 1),
++					  SPI_MEM_OP_ADDR(msg->addr_width,
++							  msg->from,
++							  msg->addr_nbits),
++					  SPI_MEM_OP_DUMMY(msg->dummy_bytes,
++							   msg->addr_nbits),
++					  SPI_MEM_OP_DATA_IN(msg->len,
++							     msg->buf,
++							     msg->data_nbits));
++
++	msg->retlen = 0;
++	ret = bcm_qspi_exec_mem_op(spi, &op);
++	if (!ret)
++		msg->retlen = msg->len;
+ 
+ 	return ret;
+ }
+@@ -1026,10 +1053,10 @@ static irqreturn_t bcm_qspi_bspi_lr_l2_isr(int irq, void *dev_id)
+ 	struct bcm_qspi_soc_intc *soc_intc = qspi->soc_intc;
+ 	u32 status = qspi_dev_id->irqp->mask;
+ 
+-	if (qspi->bspi_enabled && qspi->bspi_rf_msg) {
++	if (qspi->bspi_enabled && qspi->bspi_rf_op) {
+ 		bcm_qspi_bspi_lr_data_read(qspi);
+-		if (qspi->bspi_rf_msg_len == 0) {
+-			qspi->bspi_rf_msg = NULL;
++		if (qspi->bspi_rf_op_len == 0) {
++			qspi->bspi_rf_op = NULL;
+ 			if (qspi->soc_intc) {
+ 				/* disable soc BSPI interrupt */
+ 				soc_intc->bcm_qspi_int_set(soc_intc, BSPI_DONE,
+@@ -1038,7 +1065,7 @@ static irqreturn_t bcm_qspi_bspi_lr_l2_isr(int irq, void *dev_id)
+ 				status = INTR_BSPI_LR_SESSION_DONE_MASK;
+ 			}
+ 
+-			if (qspi->bspi_rf_msg_status)
++			if (qspi->bspi_rf_op_status)
+ 				bcm_qspi_bspi_lr_clear(qspi);
+ 			else
+ 				bcm_qspi_bspi_flush_prefetch_buffers(qspi);
+@@ -1050,7 +1077,7 @@ static irqreturn_t bcm_qspi_bspi_lr_l2_isr(int irq, void *dev_id)
+ 	}
+ 
+ 	status &= INTR_BSPI_LR_SESSION_DONE_MASK;
+-	if (qspi->bspi_enabled && status && qspi->bspi_rf_msg_len == 0)
++	if (qspi->bspi_enabled && status && qspi->bspi_rf_op_len == 0)
+ 		complete(&qspi->bspi_done);
+ 
+ 	return IRQ_HANDLED;
+@@ -1063,7 +1090,7 @@ static irqreturn_t bcm_qspi_bspi_lr_err_l2_isr(int irq, void *dev_id)
+ 	struct bcm_qspi_soc_intc *soc_intc = qspi->soc_intc;
+ 
+ 	dev_err(&qspi->pdev->dev, "BSPI INT error\n");
+-	qspi->bspi_rf_msg_status = -EIO;
++	qspi->bspi_rf_op_status = -EIO;
+ 	if (qspi->soc_intc)
+ 		/* clear soc interrupt */
+ 		soc_intc->bcm_qspi_int_ack(soc_intc, BSPI_ERR);
+@@ -1186,6 +1213,10 @@ static void bcm_qspi_hw_uninit(struct bcm_qspi *qspi)
+ 
+ }
+ 
++static const struct spi_controller_mem_ops bcm_qspi_mem_ops = {
++	.exec_op = bcm_qspi_exec_mem_op_wrapper,
++};
++
+ static const struct of_device_id bcm_qspi_of_match[] = {
+ 	{ .compatible = "brcm,spi-bcm-qspi" },
+ 	{},
+@@ -1228,7 +1259,8 @@ int bcm_qspi_probe(struct platform_device *pdev,
+ 	master->mode_bits = SPI_CPHA | SPI_CPOL | SPI_RX_DUAL | SPI_RX_QUAD;
+ 	master->setup = bcm_qspi_setup;
+ 	master->transfer_one = bcm_qspi_transfer_one;
+-	master->spi_flash_read = bcm_qspi_flash_read;
++	master->spi_flash_read = bcm_qspi_flash_read_wrapper;
++	master->mem_ops = &bcm_qspi_mem_ops;
+ 	master->cleanup = bcm_qspi_cleanup;
+ 	master->dev.of_node = dev->of_node;
+ 	master->num_chipselect = NUM_CHIPSELECT;
+-- 
+2.7.4
+
diff --git a/recipes-kernel/linux/linux-stm32mp/patches/0010-spi-bcm53xx-Implement-the-spi_mem-interface.patch b/recipes-kernel/linux/linux-stm32mp/patches/0010-spi-bcm53xx-Implement-the-spi_mem-interface.patch
new file mode 100644
index 0000000000000000000000000000000000000000..b5c49c4abc9ee65759c20bdc48f2b6a23b8f57fc
--- /dev/null
+++ b/recipes-kernel/linux/linux-stm32mp/patches/0010-spi-bcm53xx-Implement-the-spi_mem-interface.patch
@@ -0,0 +1,96 @@
+From fa58baab9b932b859ecfc5c07c57f13f72d6a192 Mon Sep 17 00:00:00 2001
+From: Boris Brezillon <boris.brezillon@bootlin.com>
+Date: Wed, 31 Jan 2018 22:58:05 +0100
+Subject: [PATCH 10/28] spi: bcm53xx: Implement the spi_mem interface
+
+The spi_mem interface is meant to replace the spi_flash_read() one.
+Implement the ->exec_op() method so that we can smoothly get rid of the
+old interface.
+
+Note that the current ->flash_read() implementation looks a bit fragile
+since it does not take the ->read_opcode passed by the spi-nor layer
+into account, which means if might not work with all kind of NORs.
+
+Anyway, I left the logic unchanged and added a few extra checks to make
+sure we're receiving something that looks like a NOR read operation.
+
+Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
+---
+Changes in v2:
+- include spi-mem.h
+- treat op->addr.val differently since it's now an u64
+---
+ drivers/spi/spi-bcm2835.c |  1 +
+ drivers/spi/spi-bcm53xx.c | 36 +++++++++++++++++++++++++++++++++++-
+ 2 files changed, 36 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c
+index f35cc10..41ed371 100644
+--- a/drivers/spi/spi-bcm2835.c
++++ b/drivers/spi/spi-bcm2835.c
+@@ -37,6 +37,7 @@
+ #include <linux/of_gpio.h>
+ #include <linux/of_irq.h>
+ #include <linux/spi/spi.h>
++#include <linux/spi/spi-mem.h>
+ 
+ /* SPI register offsets */
+ #define BCM2835_SPI_CS			0x00
+diff --git a/drivers/spi/spi-bcm53xx.c b/drivers/spi/spi-bcm53xx.c
+index 6e409ea..0900c79 100644
+--- a/drivers/spi/spi-bcm53xx.c
++++ b/drivers/spi/spi-bcm53xx.c
+@@ -263,6 +263,38 @@ static int bcm53xxspi_transfer_one(struct spi_master *master,
+ 	return 0;
+ }
+ 
++static int bcm53xxspi_exec_mem_op(struct spi_mem *mem,
++				  const struct spi_mem_op *op)
++{
++	struct bcm53xxspi *b53spi = spi_master_get_devdata(mem->spi->master);
++	u32 from;
++
++	/*
++	 * FIXME: There's nothing in this driver programming the opcode and
++	 * buswidth to be used when a read is done on the mmio window, but it
++	 * seems to be used to access a SPI NOR device, so restrict access
++	 * access to SPINOR_OP_READ commands.
++	 */
++	if (!op->data.nbytes || op->data.dir != SPI_MEM_DATA_IN ||
++	    op->addr.nbytes != 3 || op->cmd.opcode != 0x3)
++		return -ENOTSUPP;
++
++	/* Return -ENOTSUPP so that the core can fall back to normal reads. */
++	from = op->addr.val;
++	if (from + op->data.nbytes > BCM53XXSPI_FLASH_WINDOW)
++		return -ENOTSUPP;
++
++	bcm53xxspi_enable_bspi(b53spi);
++	memcpy_fromio(op->data.buf.in, b53spi->mmio_base + from,
++		      op->data.nbytes);
++
++	return 0;
++}
++
++static const struct spi_controller_mem_ops bcm53xxspi_mem_ops = {
++	.exec_op = bcm53xxspi_exec_mem_op,
++};
++
+ static int bcm53xxspi_flash_read(struct spi_device *spi,
+ 				 struct spi_flash_read_message *msg)
+ {
+@@ -317,8 +349,10 @@ static int bcm53xxspi_bcma_probe(struct bcma_device *core)
+ 
+ 	master->dev.of_node = dev->of_node;
+ 	master->transfer_one = bcm53xxspi_transfer_one;
+-	if (b53spi->mmio_base)
++	if (b53spi->mmio_base) {
++		master->mem_ops = &bcm53xxspi_mem_ops;
+ 		master->spi_flash_read = bcm53xxspi_flash_read;
++	}
+ 
+ 	bcma_set_drvdata(core, b53spi);
+ 
+-- 
+2.7.4
+
diff --git a/recipes-kernel/linux/linux-stm32mp/patches/0011-spi-ti-qspi-Implement-the-spi_mem-interface.patch b/recipes-kernel/linux/linux-stm32mp/patches/0011-spi-ti-qspi-Implement-the-spi_mem-interface.patch
new file mode 100644
index 0000000000000000000000000000000000000000..4976a2cd43115ac3990a4cbcdee790c4245043ad
--- /dev/null
+++ b/recipes-kernel/linux/linux-stm32mp/patches/0011-spi-ti-qspi-Implement-the-spi_mem-interface.patch
@@ -0,0 +1,190 @@
+From 3e664906586099c7447c70dd184b52a94ef492e5 Mon Sep 17 00:00:00 2001
+From: Boris Brezillon <boris.brezillon@bootlin.com>
+Date: Wed, 31 Jan 2018 23:00:43 +0100
+Subject: [PATCH 11/28] spi: ti-qspi: Implement the spi_mem interface
+
+The spi_mem interface is meant to replace the spi_flash_read() one.
+Implement the ->exec_op() method so that we can smoothly get rid of the
+old interface.
+
+Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
+---
+Changes in v2:
+- include spi-mem.h
+- treat op->addr.val differently since it's now an u64
+- Fix 'buf is DMA-able' check
+- Extract max mmap size from resource_size()
+---
+ drivers/spi/spi-ti-qspi.c | 84 +++++++++++++++++++++++++++++++++++++++--------
+ 1 file changed, 71 insertions(+), 13 deletions(-)
+
+diff --git a/drivers/spi/spi-ti-qspi.c b/drivers/spi/spi-ti-qspi.c
+index c24d9b4..a37db01 100644
+--- a/drivers/spi/spi-ti-qspi.c
++++ b/drivers/spi/spi-ti-qspi.c
+@@ -36,6 +36,7 @@
+ #include <linux/sizes.h>
+ 
+ #include <linux/spi/spi.h>
++#include <linux/spi/spi-mem.h>
+ 
+ struct ti_qspi_regs {
+ 	u32 clkctrl;
+@@ -50,6 +51,7 @@ struct ti_qspi {
+ 	struct spi_master	*master;
+ 	void __iomem            *base;
+ 	void __iomem            *mmap_base;
++	size_t			mmap_size;
+ 	struct regmap		*ctrl_base;
+ 	unsigned int		ctrl_reg;
+ 	struct clk		*fclk;
+@@ -434,12 +436,10 @@ static int ti_qspi_dma_xfer(struct ti_qspi *qspi, dma_addr_t dma_dst,
+ 	return 0;
+ }
+ 
+-static int ti_qspi_dma_bounce_buffer(struct ti_qspi *qspi,
+-				     struct spi_flash_read_message *msg)
++static int ti_qspi_dma_bounce_buffer(struct ti_qspi *qspi, loff_t offs,
++				     void *to, size_t readsize)
+ {
+-	size_t readsize = msg->len;
+-	void *to = msg->buf;
+-	dma_addr_t dma_src = qspi->mmap_phys_base + msg->from;
++	dma_addr_t dma_src = qspi->mmap_phys_base + offs;
+ 	int ret = 0;
+ 
+ 	/*
+@@ -507,13 +507,14 @@ static void ti_qspi_disable_memory_map(struct spi_device *spi)
+ 	qspi->mmap_enabled = false;
+ }
+ 
+-static void ti_qspi_setup_mmap_read(struct spi_device *spi,
+-				    struct spi_flash_read_message *msg)
++static void ti_qspi_setup_mmap_read(struct spi_device *spi, u8 opcode,
++				    u8 data_nbits, u8 addr_width,
++				    u8 dummy_bytes)
+ {
+ 	struct ti_qspi  *qspi = spi_master_get_devdata(spi->master);
+-	u32 memval = msg->read_opcode;
++	u32 memval = opcode;
+ 
+-	switch (msg->data_nbits) {
++	switch (data_nbits) {
+ 	case SPI_NBITS_QUAD:
+ 		memval |= QSPI_SETUP_RD_QUAD;
+ 		break;
+@@ -524,8 +525,8 @@ static void ti_qspi_setup_mmap_read(struct spi_device *spi,
+ 		memval |= QSPI_SETUP_RD_NORMAL;
+ 		break;
+ 	}
+-	memval |= ((msg->addr_width - 1) << QSPI_SETUP_ADDR_SHIFT |
+-		   msg->dummy_bytes << QSPI_SETUP_DUMMY_SHIFT);
++	memval |= ((addr_width - 1) << QSPI_SETUP_ADDR_SHIFT |
++		   dummy_bytes << QSPI_SETUP_DUMMY_SHIFT);
+ 	ti_qspi_write(qspi, memval,
+ 		      QSPI_SPI_SETUP_REG(spi->chip_select));
+ }
+@@ -546,13 +547,15 @@ static int ti_qspi_spi_flash_read(struct spi_device *spi,
+ 
+ 	if (!qspi->mmap_enabled)
+ 		ti_qspi_enable_memory_map(spi);
+-	ti_qspi_setup_mmap_read(spi, msg);
++	ti_qspi_setup_mmap_read(spi, msg->read_opcode, msg->data_nbits,
++				msg->addr_width, msg->dummy_bytes);
+ 
+ 	if (qspi->rx_chan) {
+ 		if (msg->cur_msg_mapped)
+ 			ret = ti_qspi_dma_xfer_sg(qspi, msg->rx_sg, msg->from);
+ 		else
+-			ret = ti_qspi_dma_bounce_buffer(qspi, msg);
++			ret = ti_qspi_dma_bounce_buffer(qspi, msg->from,
++							msg->buf, msg->len);
+ 		if (ret)
+ 			goto err_unlock;
+ 	} else {
+@@ -566,6 +569,58 @@ static int ti_qspi_spi_flash_read(struct spi_device *spi,
+ 	return ret;
+ }
+ 
++static int ti_qspi_exec_mem_op(struct spi_mem *mem,
++			       const struct spi_mem_op *op)
++{
++	struct ti_qspi *qspi = spi_master_get_devdata(mem->spi->master);
++	u32 from = 0;
++	int ret = 0;
++
++	/* Only optimize read path. */
++	if (!op->data.nbytes || op->data.dir != SPI_MEM_DATA_IN ||
++	    !op->addr.nbytes || op->addr.nbytes > 4)
++		return -ENOTSUPP;
++
++	/* Address exceeds MMIO window size, fall back to regular mode. */
++	from = op->addr.val;
++	if (from + op->data.nbytes > qspi->mmap_size)
++		return -ENOTSUPP;
++
++	mutex_lock(&qspi->list_lock);
++
++	if (!qspi->mmap_enabled)
++		ti_qspi_enable_memory_map(mem->spi);
++	ti_qspi_setup_mmap_read(mem->spi, op->cmd.opcode, op->data.buswidth,
++				op->addr.nbytes, op->dummy.nbytes);
++
++	if (qspi->rx_chan) {
++		struct sg_table sgt;
++
++		if (virt_addr_valid(op->data.buf.in) &&
++		    !spi_controller_dma_map_mem_op_data(mem->spi->master, op,
++							&sgt)) {
++			ret = ti_qspi_dma_xfer_sg(qspi, sgt, from);
++			spi_controller_dma_unmap_mem_op_data(mem->spi->master,
++							     op, &sgt);
++		} else {
++			ret = ti_qspi_dma_bounce_buffer(qspi, from,
++							op->data.buf.in,
++							op->data.nbytes);
++		}
++	} else {
++		memcpy_fromio(op->data.buf.in, qspi->mmap_base + from,
++			      op->data.nbytes);
++	}
++
++	mutex_unlock(&qspi->list_lock);
++
++	return ret;
++}
++
++static const struct spi_controller_mem_ops ti_qspi_mem_ops = {
++	.exec_op = ti_qspi_exec_mem_op,
++};
++
+ static int ti_qspi_start_transfer_one(struct spi_master *master,
+ 		struct spi_message *m)
+ {
+@@ -673,6 +728,7 @@ static int ti_qspi_probe(struct platform_device *pdev)
+ 	master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(16) |
+ 				     SPI_BPW_MASK(8);
+ 	master->spi_flash_read = ti_qspi_spi_flash_read;
++	master->mem_ops = &ti_qspi_mem_ops;
+ 
+ 	if (!of_property_read_u32(np, "num-cs", &num_cs))
+ 		master->num_chipselect = num_cs;
+@@ -778,6 +834,7 @@ static int ti_qspi_probe(struct platform_device *pdev)
+ 
+ no_dma:
+ 	if (!qspi->rx_chan && res_mmap) {
++		qspi->mmap_size = resource_size(res_mmap);
+ 		qspi->mmap_base = devm_ioremap_resource(&pdev->dev, res_mmap);
+ 		if (IS_ERR(qspi->mmap_base)) {
+ 			dev_info(&pdev->dev,
+@@ -785,6 +842,7 @@ static int ti_qspi_probe(struct platform_device *pdev)
+ 				 PTR_ERR(qspi->mmap_base));
+ 			qspi->mmap_base = NULL;
+ 			master->spi_flash_read = NULL;
++			master->mem_ops = NULL;
+ 		}
+ 	}
+ 	qspi->mmap_enabled = false;
+-- 
+2.7.4
+
diff --git a/recipes-kernel/linux/linux-stm32mp/patches/0012-mtd-spi-nor-Use-the-spi_mem_xx-API.patch b/recipes-kernel/linux/linux-stm32mp/patches/0012-mtd-spi-nor-Use-the-spi_mem_xx-API.patch
new file mode 100644
index 0000000000000000000000000000000000000000..856f66307514171b2b818a7785a0ca0340c04779
--- /dev/null
+++ b/recipes-kernel/linux/linux-stm32mp/patches/0012-mtd-spi-nor-Use-the-spi_mem_xx-API.patch
@@ -0,0 +1,387 @@
+From d3aa83aba2d2135a31387d20db20b27fde9954f1 Mon Sep 17 00:00:00 2001
+From: Boris Brezillon <boris.brezillon@bootlin.com>
+Date: Mon, 29 Jan 2018 00:05:28 +0100
+Subject: [PATCH 12/28] mtd: spi-nor: Use the spi_mem_xx() API
+
+The spi_mem_xxx() API has been introduced to replace the
+spi_flash_read() one. Make use of it so we can get rid of
+spi_flash_read().
+
+Note that using spi_mem_xx() also simplifies the code because this API
+takes care of using the regular spi_sync() interface when the optimized
+->mem_ops interface is not implemented by the controller.
+
+Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
+---
+Changes in v2:
+- include spi-mem.h
+- treat op->addr.val differently since it's now an u64
+- Replace SPI_MEM_OP_DATA_OUT() by SPI_MEM_OP_DATA_IN() in m25p80_read()
+---
+ drivers/mtd/devices/Kconfig  |   1 +
+ drivers/mtd/devices/m25p80.c | 232 ++++++++++++++-----------------------------
+ 2 files changed, 78 insertions(+), 155 deletions(-)
+
+diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig
+index 6def544..57b02c4b 100644
+--- a/drivers/mtd/devices/Kconfig
++++ b/drivers/mtd/devices/Kconfig
+@@ -81,6 +81,7 @@ config MTD_DATAFLASH_OTP
+ config MTD_M25P80
+ 	tristate "Support most SPI Flash chips (AT26DF, M25P, W25X, ...)"
+ 	depends on SPI_MASTER && MTD_SPI_NOR
++	select SPI_MEM
+ 	help
+ 	  This enables access to most modern SPI flash chips, used for
+ 	  program and data storage.   Series supported include Atmel AT26DF,
+diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
+index 00eea6f..87e5fcf 100644
+--- a/drivers/mtd/devices/m25p80.c
++++ b/drivers/mtd/devices/m25p80.c
+@@ -24,12 +24,13 @@
+ #include <linux/mtd/partitions.h>
+ 
+ #include <linux/spi/spi.h>
++#include <linux/spi/spi-mem.h>
+ #include <linux/spi/flash.h>
+ #include <linux/mtd/spi-nor.h>
+ 
+ #define	MAX_CMD_SIZE		6
+ struct m25p {
+-	struct spi_device	*spi;
++	struct spi_mem		*spimem;
+ 	struct spi_nor		spi_nor;
+ 	u8			command[MAX_CMD_SIZE];
+ };
+@@ -37,97 +38,68 @@ struct m25p {
+ 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;
++	struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(code, 1),
++					  SPI_MEM_OP_NO_ADDR,
++					  SPI_MEM_OP_NO_DUMMY,
++					  SPI_MEM_OP_DATA_IN(len, val, 1));
+ 	int ret;
+ 
+-	ret = spi_write_then_read(spi, &code, 1, val, len);
++	ret = spi_mem_exec_op(flash->spimem, &op);
+ 	if (ret < 0)
+-		dev_err(&spi->dev, "error %d reading %x\n", ret, code);
++		dev_err(&flash->spimem->spi->dev, "error %d reading %x\n", ret,
++			code);
+ 
+ 	return ret;
+ }
+ 
+-static void m25p_addr2cmd(struct spi_nor *nor, unsigned int addr, u8 *cmd)
+-{
+-	/* opcode is in cmd[0] */
+-	cmd[1] = addr >> (nor->addr_width * 8 -  8);
+-	cmd[2] = addr >> (nor->addr_width * 8 - 16);
+-	cmd[3] = addr >> (nor->addr_width * 8 - 24);
+-	cmd[4] = addr >> (nor->addr_width * 8 - 32);
+-}
+-
+-static int m25p_cmdsz(struct spi_nor *nor)
+-{
+-	return 1 + nor->addr_width;
+-}
+-
+ 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;
+-
+-	flash->command[0] = opcode;
+-	if (buf)
+-		memcpy(&flash->command[1], buf, len);
++	struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(opcode, 1),
++					  SPI_MEM_OP_NO_ADDR,
++					  SPI_MEM_OP_NO_DUMMY,
++					  SPI_MEM_OP_DATA_OUT(len, buf, 1));
+ 
+-	return spi_write(spi, flash->command, len + 1);
++	return spi_mem_exec_op(flash->spimem, &op);
+ }
+ 
+ static ssize_t m25p80_write(struct spi_nor *nor, loff_t to, size_t len,
+ 			    const u_char *buf)
+ {
+ 	struct m25p *flash = nor->priv;
+-	struct spi_device *spi = flash->spi;
+-	unsigned int inst_nbits, addr_nbits, data_nbits, data_idx;
+-	struct spi_transfer t[3] = {};
+-	struct spi_message m;
+-	int cmd_sz = m25p_cmdsz(nor);
+-	ssize_t ret;
++	struct spi_mem_op op =
++			SPI_MEM_OP(SPI_MEM_OP_CMD(nor->program_opcode, 1),
++				   SPI_MEM_OP_ADDR(nor->addr_width, to, 1),
++				   SPI_MEM_OP_DUMMY(0, 1),
++				   SPI_MEM_OP_DATA_OUT(len, buf, 1));
++	size_t remaining = len;
++	int ret;
+ 
+ 	/* get transfer protocols. */
+-	inst_nbits = spi_nor_get_protocol_inst_nbits(nor->write_proto);
+-	addr_nbits = spi_nor_get_protocol_addr_nbits(nor->write_proto);
+-	data_nbits = spi_nor_get_protocol_data_nbits(nor->write_proto);
+-
+-	spi_message_init(&m);
++	op.cmd.buswidth = spi_nor_get_protocol_inst_nbits(nor->write_proto);
++	op.addr.buswidth = spi_nor_get_protocol_addr_nbits(nor->write_proto);
++	op.dummy.buswidth = op.addr.buswidth;
++	op.data.buswidth = spi_nor_get_protocol_data_nbits(nor->write_proto);
+ 
+ 	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);
++		op.addr.nbytes = 0;
+ 
+-	t[0].tx_buf = flash->command;
+-	t[0].tx_nbits = inst_nbits;
+-	t[0].len = cmd_sz;
+-	spi_message_add_tail(&t[0], &m);
+-
+-	/* split the op code and address bytes into two transfers if needed. */
+-	data_idx = 1;
+-	if (addr_nbits != inst_nbits) {
+-		t[0].len = 1;
++	while (remaining) {
++		op.data.nbytes = remaining < UINT_MAX ? remaining : UINT_MAX;
++		ret = spi_mem_adjust_op_size(flash->spimem, &op);
++		if (ret)
++			return ret;
+ 
+-		t[1].tx_buf = &flash->command[1];
+-		t[1].tx_nbits = addr_nbits;
+-		t[1].len = cmd_sz - 1;
+-		spi_message_add_tail(&t[1], &m);
++		ret = spi_mem_exec_op(flash->spimem, &op);
++		if (ret)
++			return ret;
+ 
+-		data_idx = 2;
++		op.addr.val += op.data.nbytes;
++		remaining -= op.data.nbytes;
++		op.data.buf.out += op.data.nbytes;
+ 	}
+ 
+-	t[data_idx].tx_buf = buf;
+-	t[data_idx].tx_nbits = data_nbits;
+-	t[data_idx].len = len;
+-	spi_message_add_tail(&t[data_idx], &m);
+-
+-	ret = spi_sync(spi, &m);
+-	if (ret)
+-		return ret;
+-
+-	ret = m.actual_length - cmd_sz;
+-	if (ret < 0)
+-		return -EIO;
+-	return ret;
++	return len;
+ }
+ 
+ /*
+@@ -138,92 +110,39 @@ static ssize_t m25p80_read(struct spi_nor *nor, loff_t from, size_t len,
+ 			   u_char *buf)
+ {
+ 	struct m25p *flash = nor->priv;
+-	struct spi_device *spi = flash->spi;
+-	unsigned int inst_nbits, addr_nbits, data_nbits, data_idx;
+-	struct spi_transfer t[3];
+-	struct spi_message m;
+-	unsigned int dummy = nor->read_dummy;
+-	ssize_t ret;
+-	int cmd_sz;
++	struct spi_mem_op op =
++			SPI_MEM_OP(SPI_MEM_OP_CMD(nor->read_opcode, 1),
++				   SPI_MEM_OP_ADDR(nor->addr_width, from, 1),
++				   SPI_MEM_OP_DUMMY(nor->read_dummy, 1),
++				   SPI_MEM_OP_DATA_IN(len, buf, 1));
++	size_t remaining = len;
++	int ret;
+ 
+ 	/* get transfer protocols. */
+-	inst_nbits = spi_nor_get_protocol_inst_nbits(nor->read_proto);
+-	addr_nbits = spi_nor_get_protocol_addr_nbits(nor->read_proto);
+-	data_nbits = spi_nor_get_protocol_data_nbits(nor->read_proto);
++	op.cmd.buswidth = spi_nor_get_protocol_inst_nbits(nor->read_proto);
++	op.addr.buswidth = spi_nor_get_protocol_addr_nbits(nor->read_proto);
++	op.dummy.buswidth = op.addr.buswidth;
++	op.data.buswidth = spi_nor_get_protocol_data_nbits(nor->read_proto);
+ 
+ 	/* convert the dummy cycles to the number of bytes */
+-	dummy = (dummy * addr_nbits) / 8;
+-
+-	if (spi_flash_read_supported(spi)) {
+-		struct spi_flash_read_message msg;
+-
+-		memset(&msg, 0, sizeof(msg));
++	op.dummy.nbytes = (nor->read_dummy * op.dummy.buswidth) / 8;
+ 
+-		msg.buf = buf;
+-		msg.from = from;
+-		msg.len = len;
+-		msg.read_opcode = nor->read_opcode;
+-		msg.addr_width = nor->addr_width;
+-		msg.dummy_bytes = dummy;
+-		msg.opcode_nbits = inst_nbits;
+-		msg.addr_nbits = addr_nbits;
+-		msg.data_nbits = data_nbits;
+-
+-		ret = spi_flash_read(spi, &msg);
+-		if (ret < 0)
++	while (remaining) {
++		op.data.nbytes = remaining < UINT_MAX ? remaining : UINT_MAX;
++		ret = spi_mem_adjust_op_size(flash->spimem, &op);
++		if (ret)
+ 			return ret;
+-		return msg.retlen;
+-	}
+ 
+-	spi_message_init(&m);
+-	memset(t, 0, (sizeof t));
+-
+-	flash->command[0] = nor->read_opcode;
+-	m25p_addr2cmd(nor, from, flash->command);
+-
+-	t[0].tx_buf = flash->command;
+-	t[0].tx_nbits = inst_nbits;
+-	t[0].len = m25p_cmdsz(nor) + dummy;
+-	spi_message_add_tail(&t[0], &m);
+-
+-	/*
+-	 * Set all dummy/mode cycle bits to avoid sending some manufacturer
+-	 * specific pattern, which might make the memory enter its Continuous
+-	 * Read mode by mistake.
+-	 * Based on the different mode cycle bit patterns listed and described
+-	 * in the JESD216B specification, the 0xff value works for all memories
+-	 * and all manufacturers.
+-	 */
+-	cmd_sz = t[0].len;
+-	memset(flash->command + cmd_sz - dummy, 0xff, dummy);
+-
+-	/* split the op code and address bytes into two transfers if needed. */
+-	data_idx = 1;
+-	if (addr_nbits != inst_nbits) {
+-		t[0].len = 1;
+-
+-		t[1].tx_buf = &flash->command[1];
+-		t[1].tx_nbits = addr_nbits;
+-		t[1].len = cmd_sz - 1;
+-		spi_message_add_tail(&t[1], &m);
++		ret = spi_mem_exec_op(flash->spimem, &op);
++		if (ret)
++			return ret;
+ 
+-		data_idx = 2;
++		op.addr.val += op.data.nbytes;
++		remaining -= op.data.nbytes;
++		op.data.buf.in += op.data.nbytes;
+ 	}
+ 
+-	t[data_idx].rx_buf = buf;
+-	t[data_idx].rx_nbits = data_nbits;
+-	t[data_idx].len = min3(len, spi_max_transfer_size(spi),
+-			       spi_max_message_size(spi) - cmd_sz);
+-	spi_message_add_tail(&t[data_idx], &m);
+-
+-	ret = spi_sync(spi, &m);
+-	if (ret)
+-		return ret;
+-
+-	ret = m.actual_length - cmd_sz;
+-	if (ret < 0)
+-		return -EIO;
+-	return ret;
++	return len;
+ }
+ 
+ /*
+@@ -231,8 +150,9 @@ static ssize_t m25p80_read(struct spi_nor *nor, loff_t from, size_t len,
+  * matches what the READ command supports, at least until this driver
+  * understands FAST_READ (for clocks over 25 MHz).
+  */
+-static int m25p_probe(struct spi_device *spi)
++static int m25p_probe(struct spi_mem *spimem)
+ {
++	struct spi_device *spi = spimem->spi;
+ 	struct flash_platform_data	*data;
+ 	struct m25p *flash;
+ 	struct spi_nor *nor;
+@@ -244,9 +164,9 @@ static int m25p_probe(struct spi_device *spi)
+ 	char *flash_name;
+ 	int ret;
+ 
+-	data = dev_get_platdata(&spi->dev);
++	data = dev_get_platdata(&spimem->spi->dev);
+ 
+-	flash = devm_kzalloc(&spi->dev, sizeof(*flash), GFP_KERNEL);
++	flash = devm_kzalloc(&spimem->spi->dev, sizeof(*flash), GFP_KERNEL);
+ 	if (!flash)
+ 		return -ENOMEM;
+ 
+@@ -258,12 +178,12 @@ static int m25p_probe(struct spi_device *spi)
+ 	nor->write_reg = m25p80_write_reg;
+ 	nor->read_reg = m25p80_read_reg;
+ 
+-	nor->dev = &spi->dev;
++	nor->dev = &spimem->spi->dev;
+ 	spi_nor_set_flash_node(nor, spi->dev.of_node);
+ 	nor->priv = flash;
+ 
+ 	spi_set_drvdata(spi, flash);
+-	flash->spi = spi;
++	flash->spimem = spimem;
+ 
+ 	if (spi->mode & SPI_RX_QUAD) {
+ 		hwcaps.mask |= SNOR_HWCAPS_READ_1_1_4;
+@@ -303,9 +223,9 @@ static int m25p_probe(struct spi_device *spi)
+ }
+ 
+ 
+-static int m25p_remove(struct spi_device *spi)
++static int m25p_remove(struct spi_mem *spimem)
+ {
+-	struct m25p	*flash = spi_get_drvdata(spi);
++	struct m25p	*flash = spi_mem_get_drvdata(spimem);
+ 
+ 	/* Clean up MTD stuff. */
+ 	return mtd_device_unregister(&flash->spi_nor.mtd);
+@@ -377,12 +297,14 @@ static const struct of_device_id m25p_of_table[] = {
+ };
+ MODULE_DEVICE_TABLE(of, m25p_of_table);
+ 
+-static struct spi_driver m25p80_driver = {
+-	.driver = {
+-		.name	= "m25p80",
+-		.of_match_table = m25p_of_table,
++static struct spi_mem_driver m25p80_driver = {
++	.spidrv = {
++		.driver = {
++			.name	= "m25p80",
++			.of_match_table = m25p_of_table,
++		},
++		.id_table	= m25p_ids,
+ 	},
+-	.id_table	= m25p_ids,
+ 	.probe	= m25p_probe,
+ 	.remove	= m25p_remove,
+ 
+@@ -392,7 +314,7 @@ static struct spi_driver m25p80_driver = {
+ 	 */
+ };
+ 
+-module_spi_driver(m25p80_driver);
++module_spi_mem_driver(m25p80_driver);
+ 
+ MODULE_LICENSE("GPL");
+ MODULE_AUTHOR("Mike Lavender");
+-- 
+2.7.4
+
diff --git a/recipes-kernel/linux/linux-stm32mp/patches/0013-spi-Get-rid-of-the-spi_flash_read-API.patch b/recipes-kernel/linux/linux-stm32mp/patches/0013-spi-Get-rid-of-the-spi_flash_read-API.patch
new file mode 100644
index 0000000000000000000000000000000000000000..06aa87136f2e5a3d048a599d4a4beee3dad337c4
--- /dev/null
+++ b/recipes-kernel/linux/linux-stm32mp/patches/0013-spi-Get-rid-of-the-spi_flash_read-API.patch
@@ -0,0 +1,355 @@
+From 14f5055c8abf9c62b5d9be989a085ffd36147add Mon Sep 17 00:00:00 2001
+From: Boris Brezillon <boris.brezillon@bootlin.com>
+Date: Wed, 31 Jan 2018 23:25:19 +0100
+Subject: [PATCH 13/28] spi: Get rid of the spi_flash_read() API
+
+This API has been replaced by the spi_mem_xx() one, its only user
+(spi-nor) has been converted to spi_mem_xx() and all SPI controller
+drivers that were implementing the ->spi_flash_xxx() hooks are also
+implementing the spi_mem ones. So we can safely get rid of this API.
+
+Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
+---
+ drivers/spi/spi-bcm-qspi.c | 34 +++------------------------
+ drivers/spi/spi-bcm53xx.c  | 20 +---------------
+ drivers/spi/spi-ti-qspi.c  | 41 ---------------------------------
+ drivers/spi/spi.c          | 57 ----------------------------------------------
+ include/linux/spi/spi.h    | 53 ------------------------------------------
+ 5 files changed, 4 insertions(+), 201 deletions(-)
+
+diff --git a/drivers/spi/spi-bcm-qspi.c b/drivers/spi/spi-bcm-qspi.c
+index 227921a..a5ba3de0 100644
+--- a/drivers/spi/spi-bcm-qspi.c
++++ b/drivers/spi/spi-bcm-qspi.c
+@@ -944,9 +944,10 @@ static int bcm_qspi_mspi_exec_mem_op(struct spi_device *spi,
+ 	return ret;
+ }
+ 
+-static int bcm_qspi_exec_mem_op(struct spi_device *spi,
++static int bcm_qspi_exec_mem_op(struct spi_mem *mem,
+ 				const struct spi_mem_op *op)
+ {
++	struct spi_device *spi = mem->spi;
+ 	struct bcm_qspi *qspi = spi_master_get_devdata(spi->master);
+ 	int ret = 0;
+ 	bool mspi_read = false;
+@@ -991,34 +992,6 @@ static int bcm_qspi_exec_mem_op(struct spi_device *spi,
+ 	return ret;
+ }
+ 
+-static int bcm_qspi_exec_mem_op_wrapper(struct spi_mem *mem,
+-					const struct spi_mem_op *op)
+-{
+-	return bcm_qspi_exec_mem_op(mem->spi, op);
+-}
+-
+-static int bcm_qspi_flash_read_wrapper(struct spi_device *spi,
+-				       struct spi_flash_read_message *msg)
+-{
+-	int ret;
+-	struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(msg->read_opcode, 1),
+-					  SPI_MEM_OP_ADDR(msg->addr_width,
+-							  msg->from,
+-							  msg->addr_nbits),
+-					  SPI_MEM_OP_DUMMY(msg->dummy_bytes,
+-							   msg->addr_nbits),
+-					  SPI_MEM_OP_DATA_IN(msg->len,
+-							     msg->buf,
+-							     msg->data_nbits));
+-
+-	msg->retlen = 0;
+-	ret = bcm_qspi_exec_mem_op(spi, &op);
+-	if (!ret)
+-		msg->retlen = msg->len;
+-
+-	return ret;
+-}
+-
+ static void bcm_qspi_cleanup(struct spi_device *spi)
+ {
+ 	struct bcm_qspi_parms *xp = spi_get_ctldata(spi);
+@@ -1214,7 +1187,7 @@ static void bcm_qspi_hw_uninit(struct bcm_qspi *qspi)
+ }
+ 
+ static const struct spi_controller_mem_ops bcm_qspi_mem_ops = {
+-	.exec_op = bcm_qspi_exec_mem_op_wrapper,
++	.exec_op = bcm_qspi_exec_mem_op,
+ };
+ 
+ static const struct of_device_id bcm_qspi_of_match[] = {
+@@ -1259,7 +1232,6 @@ int bcm_qspi_probe(struct platform_device *pdev,
+ 	master->mode_bits = SPI_CPHA | SPI_CPOL | SPI_RX_DUAL | SPI_RX_QUAD;
+ 	master->setup = bcm_qspi_setup;
+ 	master->transfer_one = bcm_qspi_transfer_one;
+-	master->spi_flash_read = bcm_qspi_flash_read_wrapper;
+ 	master->mem_ops = &bcm_qspi_mem_ops;
+ 	master->cleanup = bcm_qspi_cleanup;
+ 	master->dev.of_node = dev->of_node;
+diff --git a/drivers/spi/spi-bcm53xx.c b/drivers/spi/spi-bcm53xx.c
+index 0900c79..3594ba9 100644
+--- a/drivers/spi/spi-bcm53xx.c
++++ b/drivers/spi/spi-bcm53xx.c
+@@ -295,22 +295,6 @@ static const struct spi_controller_mem_ops bcm53xxspi_mem_ops = {
+ 	.exec_op = bcm53xxspi_exec_mem_op,
+ };
+ 
+-static int bcm53xxspi_flash_read(struct spi_device *spi,
+-				 struct spi_flash_read_message *msg)
+-{
+-	struct bcm53xxspi *b53spi = spi_master_get_devdata(spi->master);
+-	int ret = 0;
+-
+-	if (msg->from + msg->len > BCM53XXSPI_FLASH_WINDOW)
+-		return -EINVAL;
+-
+-	bcm53xxspi_enable_bspi(b53spi);
+-	memcpy_fromio(msg->buf, b53spi->mmio_base + msg->from, msg->len);
+-	msg->retlen = msg->len;
+-
+-	return ret;
+-}
+-
+ /**************************************************
+  * BCMA
+  **************************************************/
+@@ -349,10 +333,8 @@ static int bcm53xxspi_bcma_probe(struct bcma_device *core)
+ 
+ 	master->dev.of_node = dev->of_node;
+ 	master->transfer_one = bcm53xxspi_transfer_one;
+-	if (b53spi->mmio_base) {
++	if (b53spi->mmio_base)
+ 		master->mem_ops = &bcm53xxspi_mem_ops;
+-		master->spi_flash_read = bcm53xxspi_flash_read;
+-	}
+ 
+ 	bcma_set_drvdata(core, b53spi);
+ 
+diff --git a/drivers/spi/spi-ti-qspi.c b/drivers/spi/spi-ti-qspi.c
+index a37db01..694902d 100644
+--- a/drivers/spi/spi-ti-qspi.c
++++ b/drivers/spi/spi-ti-qspi.c
+@@ -531,44 +531,6 @@ static void ti_qspi_setup_mmap_read(struct spi_device *spi, u8 opcode,
+ 		      QSPI_SPI_SETUP_REG(spi->chip_select));
+ }
+ 
+-static bool ti_qspi_spi_flash_can_dma(struct spi_device *spi,
+-				      struct spi_flash_read_message *msg)
+-{
+-	return virt_addr_valid(msg->buf);
+-}
+-
+-static int ti_qspi_spi_flash_read(struct spi_device *spi,
+-				  struct spi_flash_read_message *msg)
+-{
+-	struct ti_qspi *qspi = spi_master_get_devdata(spi->master);
+-	int ret = 0;
+-
+-	mutex_lock(&qspi->list_lock);
+-
+-	if (!qspi->mmap_enabled)
+-		ti_qspi_enable_memory_map(spi);
+-	ti_qspi_setup_mmap_read(spi, msg->read_opcode, msg->data_nbits,
+-				msg->addr_width, msg->dummy_bytes);
+-
+-	if (qspi->rx_chan) {
+-		if (msg->cur_msg_mapped)
+-			ret = ti_qspi_dma_xfer_sg(qspi, msg->rx_sg, msg->from);
+-		else
+-			ret = ti_qspi_dma_bounce_buffer(qspi, msg->from,
+-							msg->buf, msg->len);
+-		if (ret)
+-			goto err_unlock;
+-	} else {
+-		memcpy_fromio(msg->buf, qspi->mmap_base + msg->from, msg->len);
+-	}
+-	msg->retlen = msg->len;
+-
+-err_unlock:
+-	mutex_unlock(&qspi->list_lock);
+-
+-	return ret;
+-}
+-
+ static int ti_qspi_exec_mem_op(struct spi_mem *mem,
+ 			       const struct spi_mem_op *op)
+ {
+@@ -727,7 +689,6 @@ static int ti_qspi_probe(struct platform_device *pdev)
+ 	master->dev.of_node = pdev->dev.of_node;
+ 	master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(16) |
+ 				     SPI_BPW_MASK(8);
+-	master->spi_flash_read = ti_qspi_spi_flash_read;
+ 	master->mem_ops = &ti_qspi_mem_ops;
+ 
+ 	if (!of_property_read_u32(np, "num-cs", &num_cs))
+@@ -826,7 +787,6 @@ static int ti_qspi_probe(struct platform_device *pdev)
+ 		dma_release_channel(qspi->rx_chan);
+ 		goto no_dma;
+ 	}
+-	master->spi_flash_can_dma = ti_qspi_spi_flash_can_dma;
+ 	master->dma_rx = qspi->rx_chan;
+ 	init_completion(&qspi->transfer_complete);
+ 	if (res_mmap)
+@@ -841,7 +801,6 @@ static int ti_qspi_probe(struct platform_device *pdev)
+ 				 "mmap failed with error %ld using PIO mode\n",
+ 				 PTR_ERR(qspi->mmap_base));
+ 			qspi->mmap_base = NULL;
+-			master->spi_flash_read = NULL;
+ 			master->mem_ops = NULL;
+ 		}
+ 	}
+diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
+index e81df02..2786595 100644
+--- a/drivers/spi/spi.c
++++ b/drivers/spi/spi.c
+@@ -3050,63 +3050,6 @@ int spi_async_locked(struct spi_device *spi, struct spi_message *message)
+ }
+ EXPORT_SYMBOL_GPL(spi_async_locked);
+ 
+-
+-int spi_flash_read(struct spi_device *spi,
+-		   struct spi_flash_read_message *msg)
+-
+-{
+-	struct spi_controller *master = spi->controller;
+-	struct device *rx_dev = NULL;
+-	int ret;
+-
+-	if ((msg->opcode_nbits == SPI_NBITS_DUAL ||
+-	     msg->addr_nbits == SPI_NBITS_DUAL) &&
+-	    !(spi->mode & (SPI_TX_DUAL | SPI_TX_QUAD)))
+-		return -EINVAL;
+-	if ((msg->opcode_nbits == SPI_NBITS_QUAD ||
+-	     msg->addr_nbits == SPI_NBITS_QUAD) &&
+-	    !(spi->mode & SPI_TX_QUAD))
+-		return -EINVAL;
+-	if (msg->data_nbits == SPI_NBITS_DUAL &&
+-	    !(spi->mode & (SPI_RX_DUAL | SPI_RX_QUAD)))
+-		return -EINVAL;
+-	if (msg->data_nbits == SPI_NBITS_QUAD &&
+-	    !(spi->mode &  SPI_RX_QUAD))
+-		return -EINVAL;
+-
+-	if (master->auto_runtime_pm) {
+-		ret = pm_runtime_get_sync(master->dev.parent);
+-		if (ret < 0) {
+-			dev_err(&master->dev, "Failed to power device: %d\n",
+-				ret);
+-			return ret;
+-		}
+-	}
+-
+-	mutex_lock(&master->bus_lock_mutex);
+-	mutex_lock(&master->io_mutex);
+-	if (master->dma_rx && master->spi_flash_can_dma(spi, msg)) {
+-		rx_dev = master->dma_rx->device->dev;
+-		ret = spi_map_buf(master, rx_dev, &msg->rx_sg,
+-				  msg->buf, msg->len,
+-				  DMA_FROM_DEVICE);
+-		if (!ret)
+-			msg->cur_msg_mapped = true;
+-	}
+-	ret = master->spi_flash_read(spi, msg);
+-	if (msg->cur_msg_mapped)
+-		spi_unmap_buf(master, rx_dev, &msg->rx_sg,
+-			      DMA_FROM_DEVICE);
+-	mutex_unlock(&master->io_mutex);
+-	mutex_unlock(&master->bus_lock_mutex);
+-
+-	if (master->auto_runtime_pm)
+-		pm_runtime_put(master->dev.parent);
+-
+-	return ret;
+-}
+-EXPORT_SYMBOL_GPL(spi_flash_read);
+-
+ /*-------------------------------------------------------------------------*/
+ 
+ /* Utility methods for SPI protocol drivers, layered on
+diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
+index 002e7e9..fe4e8c9 100644
+--- a/include/linux/spi/spi.h
++++ b/include/linux/spi/spi.h
+@@ -27,7 +27,6 @@ struct dma_chan;
+ struct property_entry;
+ struct spi_controller;
+ struct spi_transfer;
+-struct spi_flash_read_message;
+ struct spi_controller_mem_ops;
+ 
+ /*
+@@ -383,11 +382,6 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv)
+  *	     controller has native support for memory like operations.
+  * @unprepare_message: undo any work done by prepare_message().
+  * @slave_abort: abort the ongoing transfer request on an SPI slave controller
+- * @spi_flash_read: to support spi-controller hardwares that provide
+- *                  accelerated interface to read from flash devices.
+- * @spi_flash_can_dma: analogous to can_dma() interface, but for
+- *		       controllers implementing spi_flash_read.
+- * @flash_read_supported: spi device supports flash read
+  * @cs_gpios: Array of GPIOs to use as chip select lines; one per CS
+  *	number. Any individual value may be -ENOENT for CS lines that
+  *	are not GPIOs (driven by the SPI controller itself).
+@@ -553,11 +547,6 @@ struct spi_controller {
+ 	int (*unprepare_message)(struct spi_controller *ctlr,
+ 				 struct spi_message *message);
+ 	int (*slave_abort)(struct spi_controller *ctlr);
+-	int (*spi_flash_read)(struct  spi_device *spi,
+-			      struct spi_flash_read_message *msg);
+-	bool (*spi_flash_can_dma)(struct spi_device *spi,
+-				  struct spi_flash_read_message *msg);
+-	bool (*flash_read_supported)(struct spi_device *spi);
+ 
+ 	/*
+ 	 * These hooks are for drivers that use a generic implementation
+@@ -1218,48 +1207,6 @@ static inline ssize_t spi_w8r16be(struct spi_device *spi, u8 cmd)
+ 	return be16_to_cpu(result);
+ }
+ 
+-/**
+- * struct spi_flash_read_message - flash specific information for
+- * spi-masters that provide accelerated flash read interfaces
+- * @buf: buffer to read data
+- * @from: offset within the flash from where data is to be read
+- * @len: length of data to be read
+- * @retlen: actual length of data read
+- * @read_opcode: read_opcode to be used to communicate with flash
+- * @addr_width: number of address bytes
+- * @dummy_bytes: number of dummy bytes
+- * @opcode_nbits: number of lines to send opcode
+- * @addr_nbits: number of lines to send address
+- * @data_nbits: number of lines for data
+- * @rx_sg: Scatterlist for receive data read from flash
+- * @cur_msg_mapped: message has been mapped for DMA
+- */
+-struct spi_flash_read_message {
+-	void *buf;
+-	loff_t from;
+-	size_t len;
+-	size_t retlen;
+-	u8 read_opcode;
+-	u8 addr_width;
+-	u8 dummy_bytes;
+-	u8 opcode_nbits;
+-	u8 addr_nbits;
+-	u8 data_nbits;
+-	struct sg_table rx_sg;
+-	bool cur_msg_mapped;
+-};
+-
+-/* SPI core interface for flash read support */
+-static inline bool spi_flash_read_supported(struct spi_device *spi)
+-{
+-	return spi->controller->spi_flash_read &&
+-	       (!spi->controller->flash_read_supported ||
+-	       spi->controller->flash_read_supported(spi));
+-}
+-
+-int spi_flash_read(struct spi_device *spi,
+-		   struct spi_flash_read_message *msg);
+-
+ /*---------------------------------------------------------------------------*/
+ 
+ /*
+-- 
+2.7.4
+
diff --git a/recipes-kernel/linux/linux-stm32mp/patches/0014-mtd-nand-move-raw-NAND-related-code-to-the-raw-subdi.patch b/recipes-kernel/linux/linux-stm32mp/patches/0014-mtd-nand-move-raw-NAND-related-code-to-the-raw-subdi.patch
new file mode 100644
index 0000000000000000000000000000000000000000..55661b6bf74a7f418ad77e3280018bdf7ffd4f43
--- /dev/null
+++ b/recipes-kernel/linux/linux-stm32mp/patches/0014-mtd-nand-move-raw-NAND-related-code-to-the-raw-subdi.patch
@@ -0,0 +1,134541 @@
+From 9990ca2ef18cc23f3b114fb2f15ead4ea30f2487 Mon Sep 17 00:00:00 2001
+From: Frieder Schrempf <frieder.schrempf@exceet.de>
+Date: Thu, 12 Apr 2018 15:58:23 +0200
+Subject: [PATCH 14/28] mtd: nand: move raw NAND related code to the raw/
+ subdir
+
+upstream commit: 93db446a424cee9387b532995e6b516667079555
+
+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@bootlin.com>
+---
+ drivers/mtd/nand/Kconfig                           |  574 +--
+ drivers/mtd/nand/Makefile                          |   67 +-
+ drivers/mtd/nand/ams-delta.c                       |  290 --
+ drivers/mtd/nand/atmel/Makefile                    |    4 -
+ drivers/mtd/nand/atmel/nand-controller.c           | 2560 ----------
+ drivers/mtd/nand/atmel/pmecc.c                     | 1011 ----
+ drivers/mtd/nand/atmel/pmecc.h                     |   73 -
+ drivers/mtd/nand/au1550nd.c                        |  518 --
+ drivers/mtd/nand/bcm47xxnflash/Makefile            |    4 -
+ drivers/mtd/nand/bcm47xxnflash/bcm47xxnflash.h     |   26 -
+ drivers/mtd/nand/bcm47xxnflash/main.c              |   81 -
+ drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c       |  456 --
+ drivers/mtd/nand/bf5xx_nand.c                      |  860 ----
+ drivers/mtd/nand/brcmnand/Makefile                 |    8 -
+ drivers/mtd/nand/brcmnand/bcm63138_nand.c          |  109 -
+ drivers/mtd/nand/brcmnand/bcm6368_nand.c           |  142 -
+ drivers/mtd/nand/brcmnand/brcmnand.c               | 2618 ----------
+ drivers/mtd/nand/brcmnand/brcmnand.h               |   74 -
+ drivers/mtd/nand/brcmnand/brcmstb_nand.c           |   44 -
+ drivers/mtd/nand/brcmnand/iproc_nand.c             |  160 -
+ drivers/mtd/nand/cafe_nand.c                       |  899 ----
+ drivers/mtd/nand/cmx270_nand.c                     |  246 -
+ drivers/mtd/nand/cs553x_nand.c                     |  357 --
+ drivers/mtd/nand/davinci_nand.c                    |  879 ----
+ drivers/mtd/nand/denali.c                          | 1453 ------
+ drivers/mtd/nand/denali.h                          |  339 --
+ drivers/mtd/nand/denali_dt.c                       |  163 -
+ drivers/mtd/nand/denali_pci.c                      |  126 -
+ drivers/mtd/nand/diskonchip.c                      | 1712 -------
+ drivers/mtd/nand/docg4.c                           | 1412 ------
+ drivers/mtd/nand/fsl_elbc_nand.c                   |  979 ----
+ drivers/mtd/nand/fsl_ifc_nand.c                    | 1110 -----
+ drivers/mtd/nand/fsl_upm.c                         |  363 --
+ drivers/mtd/nand/fsmc_nand.c                       | 1176 -----
+ drivers/mtd/nand/gpio.c                            |  327 --
+ drivers/mtd/nand/gpmi-nand/Makefile                |    3 -
+ drivers/mtd/nand/gpmi-nand/bch-regs.h              |  128 -
+ drivers/mtd/nand/gpmi-nand/gpmi-lib.c              | 1510 ------
+ drivers/mtd/nand/gpmi-nand/gpmi-nand.c             | 2201 ---------
+ drivers/mtd/nand/gpmi-nand/gpmi-nand.h             |  315 --
+ drivers/mtd/nand/gpmi-nand/gpmi-regs.h             |  187 -
+ drivers/mtd/nand/hisi504_nand.c                    |  898 ----
+ drivers/mtd/nand/jz4740_nand.c                     |  536 ---
+ drivers/mtd/nand/jz4780_bch.c                      |  380 --
+ drivers/mtd/nand/jz4780_bch.h                      |   43 -
+ drivers/mtd/nand/jz4780_nand.c                     |  416 --
+ drivers/mtd/nand/lpc32xx_mlc.c                     |  906 ----
+ drivers/mtd/nand/lpc32xx_slc.c                     | 1039 ----
+ drivers/mtd/nand/mpc5121_nfc.c                     |  857 ----
+ drivers/mtd/nand/mtk_ecc.c                         |  544 ---
+ drivers/mtd/nand/mtk_ecc.h                         |   50 -
+ drivers/mtd/nand/mtk_nand.c                        | 1585 -------
+ drivers/mtd/nand/mxc_nand.c                        | 1854 --------
+ drivers/mtd/nand/nand_amd.c                        |   51 -
+ drivers/mtd/nand/nand_base.c                       | 4997 --------------------
+ drivers/mtd/nand/nand_bbt.c                        | 1452 ------
+ drivers/mtd/nand/nand_bch.c                        |  234 -
+ drivers/mtd/nand/nand_ecc.c                        |  533 ---
+ drivers/mtd/nand/nand_hynix.c                      |  631 ---
+ drivers/mtd/nand/nand_ids.c                        |  207 -
+ drivers/mtd/nand/nand_macronix.c                   |   30 -
+ drivers/mtd/nand/nand_micron.c                     |  308 --
+ drivers/mtd/nand/nand_samsung.c                    |  115 -
+ drivers/mtd/nand/nand_timings.c                    |  335 --
+ drivers/mtd/nand/nand_toshiba.c                    |   51 -
+ drivers/mtd/nand/nandsim.c                         | 2392 ----------
+ drivers/mtd/nand/ndfc.c                            |  286 --
+ drivers/mtd/nand/nuc900_nand.c                     |  306 --
+ drivers/mtd/nand/omap2.c                           | 2332 ---------
+ drivers/mtd/nand/omap_elm.c                        |  578 ---
+ drivers/mtd/nand/orion_nand.c                      |  234 -
+ drivers/mtd/nand/oxnas_nand.c                      |  206 -
+ drivers/mtd/nand/pasemi_nand.c                     |  232 -
+ drivers/mtd/nand/plat_nand.c                       |  144 -
+ drivers/mtd/nand/pxa3xx_nand.c                     | 2074 --------
+ drivers/mtd/nand/qcom_nandc.c                      | 2821 -----------
+ drivers/mtd/nand/r852.c                            | 1082 -----
+ drivers/mtd/nand/r852.h                            |  160 -
+ drivers/mtd/nand/raw/Kconfig                       |  573 +++
+ drivers/mtd/nand/raw/Makefile                      |   71 +
+ drivers/mtd/nand/raw/ams-delta.c                   |  290 ++
+ drivers/mtd/nand/raw/atmel/Makefile                |    4 +
+ drivers/mtd/nand/raw/atmel/nand-controller.c       | 2560 ++++++++++
+ drivers/mtd/nand/raw/atmel/pmecc.c                 | 1011 ++++
+ drivers/mtd/nand/raw/atmel/pmecc.h                 |   73 +
+ drivers/mtd/nand/raw/au1550nd.c                    |  518 ++
+ drivers/mtd/nand/raw/bcm47xxnflash/Makefile        |    4 +
+ drivers/mtd/nand/raw/bcm47xxnflash/bcm47xxnflash.h |   26 +
+ drivers/mtd/nand/raw/bcm47xxnflash/main.c          |   81 +
+ drivers/mtd/nand/raw/bcm47xxnflash/ops_bcm4706.c   |  456 ++
+ drivers/mtd/nand/raw/bf5xx_nand.c                  |  860 ++++
+ drivers/mtd/nand/raw/brcmnand/Makefile             |    8 +
+ drivers/mtd/nand/raw/brcmnand/bcm63138_nand.c      |  109 +
+ drivers/mtd/nand/raw/brcmnand/bcm6368_nand.c       |  142 +
+ drivers/mtd/nand/raw/brcmnand/brcmnand.c           | 2618 ++++++++++
+ drivers/mtd/nand/raw/brcmnand/brcmnand.h           |   74 +
+ drivers/mtd/nand/raw/brcmnand/brcmstb_nand.c       |   44 +
+ drivers/mtd/nand/raw/brcmnand/iproc_nand.c         |  160 +
+ drivers/mtd/nand/raw/cafe_nand.c                   |  899 ++++
+ drivers/mtd/nand/raw/cmx270_nand.c                 |  246 +
+ drivers/mtd/nand/raw/cs553x_nand.c                 |  357 ++
+ drivers/mtd/nand/raw/davinci_nand.c                |  879 ++++
+ drivers/mtd/nand/raw/denali.c                      | 1453 ++++++
+ drivers/mtd/nand/raw/denali.h                      |  339 ++
+ drivers/mtd/nand/raw/denali_dt.c                   |  163 +
+ drivers/mtd/nand/raw/denali_pci.c                  |  126 +
+ drivers/mtd/nand/raw/diskonchip.c                  | 1712 +++++++
+ drivers/mtd/nand/raw/docg4.c                       | 1412 ++++++
+ drivers/mtd/nand/raw/fsl_elbc_nand.c               |  979 ++++
+ drivers/mtd/nand/raw/fsl_ifc_nand.c                | 1110 +++++
+ drivers/mtd/nand/raw/fsl_upm.c                     |  363 ++
+ drivers/mtd/nand/raw/fsmc_nand.c                   | 1176 +++++
+ drivers/mtd/nand/raw/gpio.c                        |  327 ++
+ drivers/mtd/nand/raw/gpmi-nand/Makefile            |    3 +
+ drivers/mtd/nand/raw/gpmi-nand/bch-regs.h          |  128 +
+ drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c          | 1510 ++++++
+ drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c         | 2201 +++++++++
+ drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.h         |  315 ++
+ drivers/mtd/nand/raw/gpmi-nand/gpmi-regs.h         |  187 +
+ drivers/mtd/nand/raw/hisi504_nand.c                |  898 ++++
+ drivers/mtd/nand/raw/jz4740_nand.c                 |  536 +++
+ drivers/mtd/nand/raw/jz4780_bch.c                  |  380 ++
+ drivers/mtd/nand/raw/jz4780_bch.h                  |   43 +
+ drivers/mtd/nand/raw/jz4780_nand.c                 |  416 ++
+ drivers/mtd/nand/raw/lpc32xx_mlc.c                 |  906 ++++
+ drivers/mtd/nand/raw/lpc32xx_slc.c                 | 1039 ++++
+ drivers/mtd/nand/raw/mpc5121_nfc.c                 |  857 ++++
+ drivers/mtd/nand/raw/mtk_ecc.c                     |  544 +++
+ drivers/mtd/nand/raw/mtk_ecc.h                     |   50 +
+ drivers/mtd/nand/raw/mtk_nand.c                    | 1585 +++++++
+ drivers/mtd/nand/raw/mxc_nand.c                    | 1854 ++++++++
+ drivers/mtd/nand/raw/nand_amd.c                    |   51 +
+ drivers/mtd/nand/raw/nand_base.c                   | 4997 ++++++++++++++++++++
+ drivers/mtd/nand/raw/nand_bbt.c                    | 1452 ++++++
+ drivers/mtd/nand/raw/nand_bch.c                    |  234 +
+ drivers/mtd/nand/raw/nand_ecc.c                    |  533 +++
+ drivers/mtd/nand/raw/nand_hynix.c                  |  631 +++
+ drivers/mtd/nand/raw/nand_ids.c                    |  207 +
+ drivers/mtd/nand/raw/nand_macronix.c               |   30 +
+ drivers/mtd/nand/raw/nand_micron.c                 |  308 ++
+ drivers/mtd/nand/raw/nand_samsung.c                |  115 +
+ drivers/mtd/nand/raw/nand_timings.c                |  335 ++
+ drivers/mtd/nand/raw/nand_toshiba.c                |   51 +
+ drivers/mtd/nand/raw/nandsim.c                     | 2392 ++++++++++
+ drivers/mtd/nand/raw/ndfc.c                        |  286 ++
+ drivers/mtd/nand/raw/nuc900_nand.c                 |  306 ++
+ drivers/mtd/nand/raw/omap2.c                       | 2332 +++++++++
+ drivers/mtd/nand/raw/omap_elm.c                    |  578 +++
+ drivers/mtd/nand/raw/orion_nand.c                  |  234 +
+ drivers/mtd/nand/raw/oxnas_nand.c                  |  206 +
+ drivers/mtd/nand/raw/pasemi_nand.c                 |  232 +
+ drivers/mtd/nand/raw/plat_nand.c                   |  144 +
+ drivers/mtd/nand/raw/pxa3xx_nand.c                 | 2074 ++++++++
+ drivers/mtd/nand/raw/qcom_nandc.c                  | 2821 +++++++++++
+ drivers/mtd/nand/raw/r852.c                        | 1082 +++++
+ drivers/mtd/nand/raw/r852.h                        |  160 +
+ drivers/mtd/nand/raw/s3c2410.c                     | 1296 +++++
+ drivers/mtd/nand/raw/sh_flctl.c                    | 1253 +++++
+ drivers/mtd/nand/raw/sharpsl.c                     |  235 +
+ drivers/mtd/nand/raw/sm_common.c                   |  202 +
+ drivers/mtd/nand/raw/sm_common.h                   |   61 +
+ drivers/mtd/nand/raw/socrates_nand.c               |  243 +
+ drivers/mtd/nand/raw/stm32_fmc.c                   | 1743 +++++++
+ drivers/mtd/nand/raw/sunxi_nand.c                  | 2310 +++++++++
+ drivers/mtd/nand/raw/tango_nand.c                  |  699 +++
+ drivers/mtd/nand/raw/tmio_nand.c                   |  512 ++
+ drivers/mtd/nand/raw/txx9ndfmc.c                   |  423 ++
+ drivers/mtd/nand/raw/vf610_nfc.c                   |  847 ++++
+ drivers/mtd/nand/raw/xway_nand.c                   |  245 +
+ drivers/mtd/nand/s3c2410.c                         | 1296 -----
+ drivers/mtd/nand/sh_flctl.c                        | 1253 -----
+ drivers/mtd/nand/sharpsl.c                         |  235 -
+ drivers/mtd/nand/sm_common.c                       |  202 -
+ drivers/mtd/nand/sm_common.h                       |   61 -
+ drivers/mtd/nand/socrates_nand.c                   |  243 -
+ drivers/mtd/nand/stm32_fmc.c                       | 1743 -------
+ drivers/mtd/nand/sunxi_nand.c                      | 2310 ---------
+ drivers/mtd/nand/tango_nand.c                      |  699 ---
+ drivers/mtd/nand/tmio_nand.c                       |  512 --
+ drivers/mtd/nand/txx9ndfmc.c                       |  423 --
+ drivers/mtd/nand/vf610_nfc.c                       |  847 ----
+ drivers/mtd/nand/xway_nand.c                       |  245 -
+ 182 files changed, 66537 insertions(+), 66530 deletions(-)
+ delete mode 100644 drivers/mtd/nand/ams-delta.c
+ delete mode 100644 drivers/mtd/nand/atmel/Makefile
+ delete mode 100644 drivers/mtd/nand/atmel/nand-controller.c
+ delete mode 100644 drivers/mtd/nand/atmel/pmecc.c
+ delete mode 100644 drivers/mtd/nand/atmel/pmecc.h
+ delete mode 100644 drivers/mtd/nand/au1550nd.c
+ delete mode 100644 drivers/mtd/nand/bcm47xxnflash/Makefile
+ delete mode 100644 drivers/mtd/nand/bcm47xxnflash/bcm47xxnflash.h
+ delete mode 100644 drivers/mtd/nand/bcm47xxnflash/main.c
+ delete mode 100644 drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c
+ delete mode 100644 drivers/mtd/nand/bf5xx_nand.c
+ delete mode 100644 drivers/mtd/nand/brcmnand/Makefile
+ delete mode 100644 drivers/mtd/nand/brcmnand/bcm63138_nand.c
+ delete mode 100644 drivers/mtd/nand/brcmnand/bcm6368_nand.c
+ delete mode 100644 drivers/mtd/nand/brcmnand/brcmnand.c
+ delete mode 100644 drivers/mtd/nand/brcmnand/brcmnand.h
+ delete mode 100644 drivers/mtd/nand/brcmnand/brcmstb_nand.c
+ delete mode 100644 drivers/mtd/nand/brcmnand/iproc_nand.c
+ delete mode 100644 drivers/mtd/nand/cafe_nand.c
+ delete mode 100644 drivers/mtd/nand/cmx270_nand.c
+ delete mode 100644 drivers/mtd/nand/cs553x_nand.c
+ delete mode 100644 drivers/mtd/nand/davinci_nand.c
+ delete mode 100644 drivers/mtd/nand/denali.c
+ delete mode 100644 drivers/mtd/nand/denali.h
+ delete mode 100644 drivers/mtd/nand/denali_dt.c
+ delete mode 100644 drivers/mtd/nand/denali_pci.c
+ delete mode 100644 drivers/mtd/nand/diskonchip.c
+ delete mode 100644 drivers/mtd/nand/docg4.c
+ delete mode 100644 drivers/mtd/nand/fsl_elbc_nand.c
+ delete mode 100644 drivers/mtd/nand/fsl_ifc_nand.c
+ delete mode 100644 drivers/mtd/nand/fsl_upm.c
+ delete mode 100644 drivers/mtd/nand/fsmc_nand.c
+ delete mode 100644 drivers/mtd/nand/gpio.c
+ delete mode 100644 drivers/mtd/nand/gpmi-nand/Makefile
+ delete mode 100644 drivers/mtd/nand/gpmi-nand/bch-regs.h
+ delete mode 100644 drivers/mtd/nand/gpmi-nand/gpmi-lib.c
+ delete mode 100644 drivers/mtd/nand/gpmi-nand/gpmi-nand.c
+ delete mode 100644 drivers/mtd/nand/gpmi-nand/gpmi-nand.h
+ delete mode 100644 drivers/mtd/nand/gpmi-nand/gpmi-regs.h
+ delete mode 100644 drivers/mtd/nand/hisi504_nand.c
+ delete mode 100644 drivers/mtd/nand/jz4740_nand.c
+ delete mode 100644 drivers/mtd/nand/jz4780_bch.c
+ delete mode 100644 drivers/mtd/nand/jz4780_bch.h
+ delete mode 100644 drivers/mtd/nand/jz4780_nand.c
+ delete mode 100644 drivers/mtd/nand/lpc32xx_mlc.c
+ delete mode 100644 drivers/mtd/nand/lpc32xx_slc.c
+ delete mode 100644 drivers/mtd/nand/mpc5121_nfc.c
+ delete mode 100644 drivers/mtd/nand/mtk_ecc.c
+ delete mode 100644 drivers/mtd/nand/mtk_ecc.h
+ delete mode 100644 drivers/mtd/nand/mtk_nand.c
+ delete mode 100644 drivers/mtd/nand/mxc_nand.c
+ delete mode 100644 drivers/mtd/nand/nand_amd.c
+ delete mode 100644 drivers/mtd/nand/nand_base.c
+ delete mode 100644 drivers/mtd/nand/nand_bbt.c
+ delete mode 100644 drivers/mtd/nand/nand_bch.c
+ delete mode 100644 drivers/mtd/nand/nand_ecc.c
+ delete mode 100644 drivers/mtd/nand/nand_hynix.c
+ delete mode 100644 drivers/mtd/nand/nand_ids.c
+ delete mode 100644 drivers/mtd/nand/nand_macronix.c
+ delete mode 100644 drivers/mtd/nand/nand_micron.c
+ delete mode 100644 drivers/mtd/nand/nand_samsung.c
+ delete mode 100644 drivers/mtd/nand/nand_timings.c
+ delete mode 100644 drivers/mtd/nand/nand_toshiba.c
+ delete mode 100644 drivers/mtd/nand/nandsim.c
+ delete mode 100644 drivers/mtd/nand/ndfc.c
+ delete mode 100644 drivers/mtd/nand/nuc900_nand.c
+ delete mode 100644 drivers/mtd/nand/omap2.c
+ delete mode 100644 drivers/mtd/nand/omap_elm.c
+ delete mode 100644 drivers/mtd/nand/orion_nand.c
+ delete mode 100644 drivers/mtd/nand/oxnas_nand.c
+ delete mode 100644 drivers/mtd/nand/pasemi_nand.c
+ delete mode 100644 drivers/mtd/nand/plat_nand.c
+ delete mode 100644 drivers/mtd/nand/pxa3xx_nand.c
+ delete mode 100644 drivers/mtd/nand/qcom_nandc.c
+ delete mode 100644 drivers/mtd/nand/r852.c
+ delete mode 100644 drivers/mtd/nand/r852.h
+ create mode 100644 drivers/mtd/nand/raw/Kconfig
+ create mode 100644 drivers/mtd/nand/raw/Makefile
+ create mode 100644 drivers/mtd/nand/raw/ams-delta.c
+ create mode 100644 drivers/mtd/nand/raw/atmel/Makefile
+ create mode 100644 drivers/mtd/nand/raw/atmel/nand-controller.c
+ create mode 100644 drivers/mtd/nand/raw/atmel/pmecc.c
+ create mode 100644 drivers/mtd/nand/raw/atmel/pmecc.h
+ create mode 100644 drivers/mtd/nand/raw/au1550nd.c
+ create mode 100644 drivers/mtd/nand/raw/bcm47xxnflash/Makefile
+ create mode 100644 drivers/mtd/nand/raw/bcm47xxnflash/bcm47xxnflash.h
+ create mode 100644 drivers/mtd/nand/raw/bcm47xxnflash/main.c
+ create mode 100644 drivers/mtd/nand/raw/bcm47xxnflash/ops_bcm4706.c
+ create mode 100644 drivers/mtd/nand/raw/bf5xx_nand.c
+ create mode 100644 drivers/mtd/nand/raw/brcmnand/Makefile
+ create mode 100644 drivers/mtd/nand/raw/brcmnand/bcm63138_nand.c
+ create mode 100644 drivers/mtd/nand/raw/brcmnand/bcm6368_nand.c
+ create mode 100644 drivers/mtd/nand/raw/brcmnand/brcmnand.c
+ create mode 100644 drivers/mtd/nand/raw/brcmnand/brcmnand.h
+ create mode 100644 drivers/mtd/nand/raw/brcmnand/brcmstb_nand.c
+ create mode 100644 drivers/mtd/nand/raw/brcmnand/iproc_nand.c
+ create mode 100644 drivers/mtd/nand/raw/cafe_nand.c
+ create mode 100644 drivers/mtd/nand/raw/cmx270_nand.c
+ create mode 100644 drivers/mtd/nand/raw/cs553x_nand.c
+ create mode 100644 drivers/mtd/nand/raw/davinci_nand.c
+ create mode 100644 drivers/mtd/nand/raw/denali.c
+ create mode 100644 drivers/mtd/nand/raw/denali.h
+ create mode 100644 drivers/mtd/nand/raw/denali_dt.c
+ create mode 100644 drivers/mtd/nand/raw/denali_pci.c
+ create mode 100644 drivers/mtd/nand/raw/diskonchip.c
+ create mode 100644 drivers/mtd/nand/raw/docg4.c
+ create mode 100644 drivers/mtd/nand/raw/fsl_elbc_nand.c
+ create mode 100644 drivers/mtd/nand/raw/fsl_ifc_nand.c
+ create mode 100644 drivers/mtd/nand/raw/fsl_upm.c
+ create mode 100644 drivers/mtd/nand/raw/fsmc_nand.c
+ create mode 100644 drivers/mtd/nand/raw/gpio.c
+ create mode 100644 drivers/mtd/nand/raw/gpmi-nand/Makefile
+ create mode 100644 drivers/mtd/nand/raw/gpmi-nand/bch-regs.h
+ create mode 100644 drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c
+ create mode 100644 drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c
+ create mode 100644 drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.h
+ create mode 100644 drivers/mtd/nand/raw/gpmi-nand/gpmi-regs.h
+ create mode 100644 drivers/mtd/nand/raw/hisi504_nand.c
+ create mode 100644 drivers/mtd/nand/raw/jz4740_nand.c
+ create mode 100644 drivers/mtd/nand/raw/jz4780_bch.c
+ create mode 100644 drivers/mtd/nand/raw/jz4780_bch.h
+ create mode 100644 drivers/mtd/nand/raw/jz4780_nand.c
+ create mode 100644 drivers/mtd/nand/raw/lpc32xx_mlc.c
+ create mode 100644 drivers/mtd/nand/raw/lpc32xx_slc.c
+ create mode 100644 drivers/mtd/nand/raw/mpc5121_nfc.c
+ create mode 100644 drivers/mtd/nand/raw/mtk_ecc.c
+ create mode 100644 drivers/mtd/nand/raw/mtk_ecc.h
+ create mode 100644 drivers/mtd/nand/raw/mtk_nand.c
+ create mode 100644 drivers/mtd/nand/raw/mxc_nand.c
+ create mode 100644 drivers/mtd/nand/raw/nand_amd.c
+ create mode 100644 drivers/mtd/nand/raw/nand_base.c
+ create mode 100644 drivers/mtd/nand/raw/nand_bbt.c
+ create mode 100644 drivers/mtd/nand/raw/nand_bch.c
+ create mode 100644 drivers/mtd/nand/raw/nand_ecc.c
+ create mode 100644 drivers/mtd/nand/raw/nand_hynix.c
+ create mode 100644 drivers/mtd/nand/raw/nand_ids.c
+ create mode 100644 drivers/mtd/nand/raw/nand_macronix.c
+ create mode 100644 drivers/mtd/nand/raw/nand_micron.c
+ create mode 100644 drivers/mtd/nand/raw/nand_samsung.c
+ create mode 100644 drivers/mtd/nand/raw/nand_timings.c
+ create mode 100644 drivers/mtd/nand/raw/nand_toshiba.c
+ create mode 100644 drivers/mtd/nand/raw/nandsim.c
+ create mode 100644 drivers/mtd/nand/raw/ndfc.c
+ create mode 100644 drivers/mtd/nand/raw/nuc900_nand.c
+ create mode 100644 drivers/mtd/nand/raw/omap2.c
+ create mode 100644 drivers/mtd/nand/raw/omap_elm.c
+ create mode 100644 drivers/mtd/nand/raw/orion_nand.c
+ create mode 100644 drivers/mtd/nand/raw/oxnas_nand.c
+ create mode 100644 drivers/mtd/nand/raw/pasemi_nand.c
+ create mode 100644 drivers/mtd/nand/raw/plat_nand.c
+ create mode 100644 drivers/mtd/nand/raw/pxa3xx_nand.c
+ create mode 100644 drivers/mtd/nand/raw/qcom_nandc.c
+ create mode 100644 drivers/mtd/nand/raw/r852.c
+ create mode 100644 drivers/mtd/nand/raw/r852.h
+ create mode 100644 drivers/mtd/nand/raw/s3c2410.c
+ create mode 100644 drivers/mtd/nand/raw/sh_flctl.c
+ create mode 100644 drivers/mtd/nand/raw/sharpsl.c
+ create mode 100644 drivers/mtd/nand/raw/sm_common.c
+ create mode 100644 drivers/mtd/nand/raw/sm_common.h
+ create mode 100644 drivers/mtd/nand/raw/socrates_nand.c
+ create mode 100644 drivers/mtd/nand/raw/stm32_fmc.c
+ create mode 100644 drivers/mtd/nand/raw/sunxi_nand.c
+ create mode 100644 drivers/mtd/nand/raw/tango_nand.c
+ create mode 100644 drivers/mtd/nand/raw/tmio_nand.c
+ create mode 100644 drivers/mtd/nand/raw/txx9ndfmc.c
+ create mode 100644 drivers/mtd/nand/raw/vf610_nfc.c
+ create mode 100644 drivers/mtd/nand/raw/xway_nand.c
+ delete mode 100644 drivers/mtd/nand/s3c2410.c
+ delete mode 100644 drivers/mtd/nand/sh_flctl.c
+ delete mode 100644 drivers/mtd/nand/sharpsl.c
+ delete mode 100644 drivers/mtd/nand/sm_common.c
+ delete mode 100644 drivers/mtd/nand/sm_common.h
+ delete mode 100644 drivers/mtd/nand/socrates_nand.c
+ delete mode 100644 drivers/mtd/nand/stm32_fmc.c
+ delete mode 100644 drivers/mtd/nand/sunxi_nand.c
+ delete mode 100644 drivers/mtd/nand/tango_nand.c
+ delete mode 100644 drivers/mtd/nand/tmio_nand.c
+ delete mode 100644 drivers/mtd/nand/txx9ndfmc.c
+ delete mode 100644 drivers/mtd/nand/vf610_nfc.c
+ delete mode 100644 drivers/mtd/nand/xway_nand.c
+
+diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
+index 0c179e6..6d53734 100644
+--- a/drivers/mtd/nand/Kconfig
++++ b/drivers/mtd/nand/Kconfig
+@@ -1,573 +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_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_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_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_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_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
+-	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"
+-	depends on ARCH_AT91
+-	select MFD_ATMEL_SMC
+-	help
+-	  Enables support for NAND Flash / Smart Media Card interface
+-	  on Atmel AT91 processors.
+-
+-config MTD_NAND_PXA3xx
+-	tristate "NAND support on PXA3xx and Armada 370/XP"
+-	depends on PXA3xx || ARCH_MMP || PLAT_ORION || ARCH_MVEBU
+-	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_OXNAS
+-	tristate "NAND Flash support for Oxford Semiconductor SoC"
+-	depends on ARCH_OXNAS || COMPILE_TEST
+-	depends on HAS_IOMEM
+-	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
+-	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 || SOC_LS1021A
+-	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 OF
+-	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
+-	bool "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 ARCH_HISI || COMPILE_TEST
+-	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 ARCH_MEDIATEK || COMPILE_TEST
+-	depends on HAS_DMA
+-	help
+-	  Enables support for NAND controller on MTK SoCs.
+-	  This controller is found on mt27xx, mt81xx, mt65xx SoCs.
+-
+-config MTD_NAND_STM32_FMC
+-	tristate "Support for NAND controller on STM32"
+-	depends on ARCH_STM32
+-	help
+-	  Enables support for NAND Flash chips on the ST Microelectronics
+-	  Flexible Memory Controller (FMC)
+-
+-endif # MTD_NAND
++source "drivers/mtd/nand/raw/Kconfig"
+diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
+index 5cd596b..f168a5b 100644
+--- a/drivers/mtd/nand/Makefile
++++ b/drivers/mtd/nand/Makefile
+@@ -3,69 +3,4 @@
+ # 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_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_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
+-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/
+-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_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
+-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
+-obj-$(CONFIG_MTD_NAND_STM32_FMC)	+= stm32_fmc.o
+-
+-nand-objs := nand_base.o nand_bbt.o nand_timings.o nand_ids.o
+-nand-objs += nand_amd.o
+-nand-objs += nand_hynix.o
+-nand-objs += nand_macronix.o
+-nand-objs += nand_micron.o
+-nand-objs += nand_samsung.o
+-nand-objs += nand_toshiba.o
++obj-y	+= raw/
+diff --git a/drivers/mtd/nand/ams-delta.c b/drivers/mtd/nand/ams-delta.c
+deleted file mode 100644
+index dcec9cf..0000000
+--- a/drivers/mtd/nand/ams-delta.c
++++ /dev/null
+@@ -1,290 +0,0 @@
+-/*
+- *  drivers/mtd/nand/ams-delta.c
+- *
+- *  Copyright (C) 2006 Jonathan McDowell <noodles@earth.li>
+- *
+- *  Derived from drivers/mtd/toto.c
+- *  Converted to platform driver by Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>
+- *  Partially stolen from drivers/mtd/nand/plat_nand.c
+- *
+- * 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.
+- *
+- *  Overview:
+- *   This is a device driver for the NAND flash device found on the
+- *   Amstrad E3 (Delta).
+- */
+-
+-#include <linux/slab.h>
+-#include <linux/module.h>
+-#include <linux/delay.h>
+-#include <linux/mtd/mtd.h>
+-#include <linux/mtd/rawnand.h>
+-#include <linux/mtd/partitions.h>
+-#include <linux/gpio.h>
+-#include <linux/platform_data/gpio-omap.h>
+-
+-#include <asm/io.h>
+-#include <asm/sizes.h>
+-
+-#include <mach/board-ams-delta.h>
+-
+-#include <mach/hardware.h>
+-
+-/*
+- * MTD structure for E3 (Delta)
+- */
+-static struct mtd_info *ams_delta_mtd = NULL;
+-
+-/*
+- * Define partitions for flash devices
+- */
+-
+-static struct mtd_partition partition_info[] = {
+-	{ .name		= "Kernel",
+-	  .offset	= 0,
+-	  .size		= 3 * SZ_1M + SZ_512K },
+-	{ .name		= "u-boot",
+-	  .offset	= 3 * SZ_1M + SZ_512K,
+-	  .size		= SZ_256K },
+-	{ .name		= "u-boot params",
+-	  .offset	= 3 * SZ_1M + SZ_512K + SZ_256K,
+-	  .size		= SZ_256K },
+-	{ .name		= "Amstrad LDR",
+-	  .offset	= 4 * SZ_1M,
+-	  .size		= SZ_256K },
+-	{ .name		= "File system",
+-	  .offset	= 4 * SZ_1M + 1 * SZ_256K,
+-	  .size		= 27 * SZ_1M },
+-	{ .name		= "PBL reserved",
+-	  .offset	= 32 * SZ_1M - 3 * SZ_256K,
+-	  .size		=  3 * SZ_256K },
+-};
+-
+-static void ams_delta_write_byte(struct mtd_info *mtd, u_char byte)
+-{
+-	struct nand_chip *this = mtd_to_nand(mtd);
+-	void __iomem *io_base = (void __iomem *)nand_get_controller_data(this);
+-
+-	writew(0, io_base + OMAP_MPUIO_IO_CNTL);
+-	writew(byte, this->IO_ADDR_W);
+-	gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_NWE, 0);
+-	ndelay(40);
+-	gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_NWE, 1);
+-}
+-
+-static u_char ams_delta_read_byte(struct mtd_info *mtd)
+-{
+-	u_char res;
+-	struct nand_chip *this = mtd_to_nand(mtd);
+-	void __iomem *io_base = (void __iomem *)nand_get_controller_data(this);
+-
+-	gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_NRE, 0);
+-	ndelay(40);
+-	writew(~0, io_base + OMAP_MPUIO_IO_CNTL);
+-	res = readw(this->IO_ADDR_R);
+-	gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_NRE, 1);
+-
+-	return res;
+-}
+-
+-static void ams_delta_write_buf(struct mtd_info *mtd, const u_char *buf,
+-				int len)
+-{
+-	int i;
+-
+-	for (i=0; i<len; i++)
+-		ams_delta_write_byte(mtd, buf[i]);
+-}
+-
+-static void ams_delta_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+-{
+-	int i;
+-
+-	for (i=0; i<len; i++)
+-		buf[i] = ams_delta_read_byte(mtd);
+-}
+-
+-/*
+- * Command control function
+- *
+- * ctrl:
+- * NAND_NCE: bit 0 -> bit 2
+- * NAND_CLE: bit 1 -> bit 7
+- * NAND_ALE: bit 2 -> bit 6
+- */
+-static void ams_delta_hwcontrol(struct mtd_info *mtd, int cmd,
+-				unsigned int ctrl)
+-{
+-
+-	if (ctrl & NAND_CTRL_CHANGE) {
+-		gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_NCE,
+-				(ctrl & NAND_NCE) == 0);
+-		gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_CLE,
+-				(ctrl & NAND_CLE) != 0);
+-		gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_ALE,
+-				(ctrl & NAND_ALE) != 0);
+-	}
+-
+-	if (cmd != NAND_CMD_NONE)
+-		ams_delta_write_byte(mtd, cmd);
+-}
+-
+-static int ams_delta_nand_ready(struct mtd_info *mtd)
+-{
+-	return gpio_get_value(AMS_DELTA_GPIO_PIN_NAND_RB);
+-}
+-
+-static const struct gpio _mandatory_gpio[] = {
+-	{
+-		.gpio	= AMS_DELTA_GPIO_PIN_NAND_NCE,
+-		.flags	= GPIOF_OUT_INIT_HIGH,
+-		.label	= "nand_nce",
+-	},
+-	{
+-		.gpio	= AMS_DELTA_GPIO_PIN_NAND_NRE,
+-		.flags	= GPIOF_OUT_INIT_HIGH,
+-		.label	= "nand_nre",
+-	},
+-	{
+-		.gpio	= AMS_DELTA_GPIO_PIN_NAND_NWP,
+-		.flags	= GPIOF_OUT_INIT_HIGH,
+-		.label	= "nand_nwp",
+-	},
+-	{
+-		.gpio	= AMS_DELTA_GPIO_PIN_NAND_NWE,
+-		.flags	= GPIOF_OUT_INIT_HIGH,
+-		.label	= "nand_nwe",
+-	},
+-	{
+-		.gpio	= AMS_DELTA_GPIO_PIN_NAND_ALE,
+-		.flags	= GPIOF_OUT_INIT_LOW,
+-		.label	= "nand_ale",
+-	},
+-	{
+-		.gpio	= AMS_DELTA_GPIO_PIN_NAND_CLE,
+-		.flags	= GPIOF_OUT_INIT_LOW,
+-		.label	= "nand_cle",
+-	},
+-};
+-
+-/*
+- * Main initialization routine
+- */
+-static int ams_delta_init(struct platform_device *pdev)
+-{
+-	struct nand_chip *this;
+-	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+-	void __iomem *io_base;
+-	int err = 0;
+-
+-	if (!res)
+-		return -ENXIO;
+-
+-	/* Allocate memory for MTD device structure and private data */
+-	this = kzalloc(sizeof(struct nand_chip), GFP_KERNEL);
+-	if (!this) {
+-		printk (KERN_WARNING "Unable to allocate E3 NAND MTD device structure.\n");
+-		err = -ENOMEM;
+-		goto out;
+-	}
+-
+-	ams_delta_mtd = nand_to_mtd(this);
+-	ams_delta_mtd->owner = THIS_MODULE;
+-
+-	/*
+-	 * Don't try to request the memory region from here,
+-	 * it should have been already requested from the
+-	 * gpio-omap driver and requesting it again would fail.
+-	 */
+-
+-	io_base = ioremap(res->start, resource_size(res));
+-	if (io_base == NULL) {
+-		dev_err(&pdev->dev, "ioremap failed\n");
+-		err = -EIO;
+-		goto out_free;
+-	}
+-
+-	nand_set_controller_data(this, (void *)io_base);
+-
+-	/* Set address of NAND IO lines */
+-	this->IO_ADDR_R = io_base + OMAP_MPUIO_INPUT_LATCH;
+-	this->IO_ADDR_W = io_base + OMAP_MPUIO_OUTPUT;
+-	this->read_byte = ams_delta_read_byte;
+-	this->write_buf = ams_delta_write_buf;
+-	this->read_buf = ams_delta_read_buf;
+-	this->cmd_ctrl = ams_delta_hwcontrol;
+-	if (gpio_request(AMS_DELTA_GPIO_PIN_NAND_RB, "nand_rdy") == 0) {
+-		this->dev_ready = ams_delta_nand_ready;
+-	} else {
+-		this->dev_ready = NULL;
+-		printk(KERN_NOTICE "Couldn't request gpio for Delta NAND ready.\n");
+-	}
+-	/* 25 us command delay time */
+-	this->chip_delay = 30;
+-	this->ecc.mode = NAND_ECC_SOFT;
+-	this->ecc.algo = NAND_ECC_HAMMING;
+-
+-	platform_set_drvdata(pdev, io_base);
+-
+-	/* Set chip enabled, but  */
+-	err = gpio_request_array(_mandatory_gpio, ARRAY_SIZE(_mandatory_gpio));
+-	if (err)
+-		goto out_gpio;
+-
+-	/* Scan to find existence of the device */
+-	err = nand_scan(ams_delta_mtd, 1);
+-	if (err)
+-		goto out_mtd;
+-
+-	/* Register the partitions */
+-	mtd_device_register(ams_delta_mtd, partition_info,
+-			    ARRAY_SIZE(partition_info));
+-
+-	goto out;
+-
+- out_mtd:
+-	gpio_free_array(_mandatory_gpio, ARRAY_SIZE(_mandatory_gpio));
+-out_gpio:
+-	gpio_free(AMS_DELTA_GPIO_PIN_NAND_RB);
+-	iounmap(io_base);
+-out_free:
+-	kfree(this);
+- out:
+-	return err;
+-}
+-
+-/*
+- * Clean up routine
+- */
+-static int ams_delta_cleanup(struct platform_device *pdev)
+-{
+-	void __iomem *io_base = platform_get_drvdata(pdev);
+-
+-	/* Release resources, unregister device */
+-	nand_release(ams_delta_mtd);
+-
+-	gpio_free_array(_mandatory_gpio, ARRAY_SIZE(_mandatory_gpio));
+-	gpio_free(AMS_DELTA_GPIO_PIN_NAND_RB);
+-	iounmap(io_base);
+-
+-	/* Free the MTD device structure */
+-	kfree(mtd_to_nand(ams_delta_mtd));
+-
+-	return 0;
+-}
+-
+-static struct platform_driver ams_delta_nand_driver = {
+-	.probe		= ams_delta_init,
+-	.remove		= ams_delta_cleanup,
+-	.driver		= {
+-		.name	= "ams-delta-nand",
+-	},
+-};
+-
+-module_platform_driver(ams_delta_nand_driver);
+-
+-MODULE_LICENSE("GPL");
+-MODULE_AUTHOR("Jonathan McDowell <noodles@earth.li>");
+-MODULE_DESCRIPTION("Glue layer for NAND flash on Amstrad E3 (Delta)");
+diff --git a/drivers/mtd/nand/atmel/Makefile b/drivers/mtd/nand/atmel/Makefile
+deleted file mode 100644
+index 288db4f..0000000
+--- a/drivers/mtd/nand/atmel/Makefile
++++ /dev/null
+@@ -1,4 +0,0 @@
+-obj-$(CONFIG_MTD_NAND_ATMEL)	+= atmel-nand-controller.o atmel-pmecc.o
+-
+-atmel-nand-controller-objs	:= nand-controller.o
+-atmel-pmecc-objs		:= pmecc.o
+diff --git a/drivers/mtd/nand/atmel/nand-controller.c b/drivers/mtd/nand/atmel/nand-controller.c
+deleted file mode 100644
+index 68c9d98..0000000
+--- a/drivers/mtd/nand/atmel/nand-controller.c
++++ /dev/null
+@@ -1,2560 +0,0 @@
+-/*
+- * Copyright 2017 ATMEL
+- * Copyright 2017 Free Electrons
+- *
+- * Author: Boris Brezillon <boris.brezillon@free-electrons.com>
+- *
+- * Derived from the atmel_nand.c driver which contained the following
+- * copyrights:
+- *
+- *   Copyright 2003 Rick Bronson
+- *
+- *   Derived from drivers/mtd/nand/autcpu12.c
+- *	Copyright 2001 Thomas Gleixner (gleixner@autronix.de)
+- *
+- *   Derived from drivers/mtd/spia.c
+- *	Copyright 2000 Steven J. Hill (sjhill@cotw.com)
+- *
+- *
+- *   Add Hardware ECC support for AT91SAM9260 / AT91SAM9263
+- *	Richard Genoud (richard.genoud@gmail.com), Adeneo Copyright 2007
+- *
+- *   Derived from Das U-Boot source code
+- *	(u-boot-1.1.5/board/atmel/at91sam9263ek/nand.c)
+- *	Copyright 2006 ATMEL Rousset, Lacressonniere Nicolas
+- *
+- *   Add Programmable Multibit ECC support for various AT91 SoC
+- *	Copyright 2012 ATMEL, Hong Xu
+- *
+- *   Add Nand Flash Controller support for SAMA5 SoC
+- *	Copyright 2013 ATMEL, Josh Wu (josh.wu@atmel.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.
+- *
+- * A few words about the naming convention in this file. This convention
+- * applies to structure and function names.
+- *
+- * Prefixes:
+- *
+- * - atmel_nand_: all generic structures/functions
+- * - atmel_smc_nand_: all structures/functions specific to the SMC interface
+- *		      (at91sam9 and avr32 SoCs)
+- * - atmel_hsmc_nand_: all structures/functions specific to the HSMC interface
+- *		       (sama5 SoCs and later)
+- * - atmel_nfc_: all structures/functions used to manipulate the NFC sub-block
+- *		 that is available in the HSMC block
+- * - <soc>_nand_: all SoC specific structures/functions
+- */
+-
+-#include <linux/clk.h>
+-#include <linux/dma-mapping.h>
+-#include <linux/dmaengine.h>
+-#include <linux/genalloc.h>
+-#include <linux/gpio.h>
+-#include <linux/gpio/consumer.h>
+-#include <linux/interrupt.h>
+-#include <linux/mfd/syscon.h>
+-#include <linux/mfd/syscon/atmel-matrix.h>
+-#include <linux/mfd/syscon/atmel-smc.h>
+-#include <linux/module.h>
+-#include <linux/mtd/rawnand.h>
+-#include <linux/of_address.h>
+-#include <linux/of_irq.h>
+-#include <linux/of_platform.h>
+-#include <linux/iopoll.h>
+-#include <linux/platform_device.h>
+-#include <linux/regmap.h>
+-
+-#include "pmecc.h"
+-
+-#define ATMEL_HSMC_NFC_CFG			0x0
+-#define ATMEL_HSMC_NFC_CFG_SPARESIZE(x)		(((x) / 4) << 24)
+-#define ATMEL_HSMC_NFC_CFG_SPARESIZE_MASK	GENMASK(30, 24)
+-#define ATMEL_HSMC_NFC_CFG_DTO(cyc, mul)	(((cyc) << 16) | ((mul) << 20))
+-#define ATMEL_HSMC_NFC_CFG_DTO_MAX		GENMASK(22, 16)
+-#define ATMEL_HSMC_NFC_CFG_RBEDGE		BIT(13)
+-#define ATMEL_HSMC_NFC_CFG_FALLING_EDGE		BIT(12)
+-#define ATMEL_HSMC_NFC_CFG_RSPARE		BIT(9)
+-#define ATMEL_HSMC_NFC_CFG_WSPARE		BIT(8)
+-#define ATMEL_HSMC_NFC_CFG_PAGESIZE_MASK	GENMASK(2, 0)
+-#define ATMEL_HSMC_NFC_CFG_PAGESIZE(x)		(fls((x) / 512) - 1)
+-
+-#define ATMEL_HSMC_NFC_CTRL			0x4
+-#define ATMEL_HSMC_NFC_CTRL_EN			BIT(0)
+-#define ATMEL_HSMC_NFC_CTRL_DIS			BIT(1)
+-
+-#define ATMEL_HSMC_NFC_SR			0x8
+-#define ATMEL_HSMC_NFC_IER			0xc
+-#define ATMEL_HSMC_NFC_IDR			0x10
+-#define ATMEL_HSMC_NFC_IMR			0x14
+-#define ATMEL_HSMC_NFC_SR_ENABLED		BIT(1)
+-#define ATMEL_HSMC_NFC_SR_RB_RISE		BIT(4)
+-#define ATMEL_HSMC_NFC_SR_RB_FALL		BIT(5)
+-#define ATMEL_HSMC_NFC_SR_BUSY			BIT(8)
+-#define ATMEL_HSMC_NFC_SR_WR			BIT(11)
+-#define ATMEL_HSMC_NFC_SR_CSID			GENMASK(14, 12)
+-#define ATMEL_HSMC_NFC_SR_XFRDONE		BIT(16)
+-#define ATMEL_HSMC_NFC_SR_CMDDONE		BIT(17)
+-#define ATMEL_HSMC_NFC_SR_DTOE			BIT(20)
+-#define ATMEL_HSMC_NFC_SR_UNDEF			BIT(21)
+-#define ATMEL_HSMC_NFC_SR_AWB			BIT(22)
+-#define ATMEL_HSMC_NFC_SR_NFCASE		BIT(23)
+-#define ATMEL_HSMC_NFC_SR_ERRORS		(ATMEL_HSMC_NFC_SR_DTOE | \
+-						 ATMEL_HSMC_NFC_SR_UNDEF | \
+-						 ATMEL_HSMC_NFC_SR_AWB | \
+-						 ATMEL_HSMC_NFC_SR_NFCASE)
+-#define ATMEL_HSMC_NFC_SR_RBEDGE(x)		BIT((x) + 24)
+-
+-#define ATMEL_HSMC_NFC_ADDR			0x18
+-#define ATMEL_HSMC_NFC_BANK			0x1c
+-
+-#define ATMEL_NFC_MAX_RB_ID			7
+-
+-#define ATMEL_NFC_SRAM_SIZE			0x2400
+-
+-#define ATMEL_NFC_CMD(pos, cmd)			((cmd) << (((pos) * 8) + 2))
+-#define ATMEL_NFC_VCMD2				BIT(18)
+-#define ATMEL_NFC_ACYCLE(naddrs)		((naddrs) << 19)
+-#define ATMEL_NFC_CSID(cs)			((cs) << 22)
+-#define ATMEL_NFC_DATAEN			BIT(25)
+-#define ATMEL_NFC_NFCWR				BIT(26)
+-
+-#define ATMEL_NFC_MAX_ADDR_CYCLES		5
+-
+-#define ATMEL_NAND_ALE_OFFSET			BIT(21)
+-#define ATMEL_NAND_CLE_OFFSET			BIT(22)
+-
+-#define DEFAULT_TIMEOUT_MS			1000
+-#define MIN_DMA_LEN				128
+-
+-enum atmel_nand_rb_type {
+-	ATMEL_NAND_NO_RB,
+-	ATMEL_NAND_NATIVE_RB,
+-	ATMEL_NAND_GPIO_RB,
+-};
+-
+-struct atmel_nand_rb {
+-	enum atmel_nand_rb_type type;
+-	union {
+-		struct gpio_desc *gpio;
+-		int id;
+-	};
+-};
+-
+-struct atmel_nand_cs {
+-	int id;
+-	struct atmel_nand_rb rb;
+-	struct gpio_desc *csgpio;
+-	struct {
+-		void __iomem *virt;
+-		dma_addr_t dma;
+-	} io;
+-
+-	struct atmel_smc_cs_conf smcconf;
+-};
+-
+-struct atmel_nand {
+-	struct list_head node;
+-	struct device *dev;
+-	struct nand_chip base;
+-	struct atmel_nand_cs *activecs;
+-	struct atmel_pmecc_user *pmecc;
+-	struct gpio_desc *cdgpio;
+-	int numcs;
+-	struct atmel_nand_cs cs[];
+-};
+-
+-static inline struct atmel_nand *to_atmel_nand(struct nand_chip *chip)
+-{
+-	return container_of(chip, struct atmel_nand, base);
+-}
+-
+-enum atmel_nfc_data_xfer {
+-	ATMEL_NFC_NO_DATA,
+-	ATMEL_NFC_READ_DATA,
+-	ATMEL_NFC_WRITE_DATA,
+-};
+-
+-struct atmel_nfc_op {
+-	u8 cs;
+-	u8 ncmds;
+-	u8 cmds[2];
+-	u8 naddrs;
+-	u8 addrs[5];
+-	enum atmel_nfc_data_xfer data;
+-	u32 wait;
+-	u32 errors;
+-};
+-
+-struct atmel_nand_controller;
+-struct atmel_nand_controller_caps;
+-
+-struct atmel_nand_controller_ops {
+-	int (*probe)(struct platform_device *pdev,
+-		     const struct atmel_nand_controller_caps *caps);
+-	int (*remove)(struct atmel_nand_controller *nc);
+-	void (*nand_init)(struct atmel_nand_controller *nc,
+-			  struct atmel_nand *nand);
+-	int (*ecc_init)(struct atmel_nand *nand);
+-	int (*setup_data_interface)(struct atmel_nand *nand, int csline,
+-				    const struct nand_data_interface *conf);
+-};
+-
+-struct atmel_nand_controller_caps {
+-	bool has_dma;
+-	bool legacy_of_bindings;
+-	u32 ale_offs;
+-	u32 cle_offs;
+-	const struct atmel_nand_controller_ops *ops;
+-};
+-
+-struct atmel_nand_controller {
+-	struct nand_hw_control base;
+-	const struct atmel_nand_controller_caps *caps;
+-	struct device *dev;
+-	struct regmap *smc;
+-	struct dma_chan *dmac;
+-	struct atmel_pmecc *pmecc;
+-	struct list_head chips;
+-	struct clk *mck;
+-};
+-
+-static inline struct atmel_nand_controller *
+-to_nand_controller(struct nand_hw_control *ctl)
+-{
+-	return container_of(ctl, struct atmel_nand_controller, base);
+-}
+-
+-struct atmel_smc_nand_controller {
+-	struct atmel_nand_controller base;
+-	struct regmap *matrix;
+-	unsigned int ebi_csa_offs;
+-};
+-
+-static inline struct atmel_smc_nand_controller *
+-to_smc_nand_controller(struct nand_hw_control *ctl)
+-{
+-	return container_of(to_nand_controller(ctl),
+-			    struct atmel_smc_nand_controller, base);
+-}
+-
+-struct atmel_hsmc_nand_controller {
+-	struct atmel_nand_controller base;
+-	struct {
+-		struct gen_pool *pool;
+-		void __iomem *virt;
+-		dma_addr_t dma;
+-	} sram;
+-	const struct atmel_hsmc_reg_layout *hsmc_layout;
+-	struct regmap *io;
+-	struct atmel_nfc_op op;
+-	struct completion complete;
+-	int irq;
+-
+-	/* Only used when instantiating from legacy DT bindings. */
+-	struct clk *clk;
+-};
+-
+-static inline struct atmel_hsmc_nand_controller *
+-to_hsmc_nand_controller(struct nand_hw_control *ctl)
+-{
+-	return container_of(to_nand_controller(ctl),
+-			    struct atmel_hsmc_nand_controller, base);
+-}
+-
+-static bool atmel_nfc_op_done(struct atmel_nfc_op *op, u32 status)
+-{
+-	op->errors |= status & ATMEL_HSMC_NFC_SR_ERRORS;
+-	op->wait ^= status & op->wait;
+-
+-	return !op->wait || op->errors;
+-}
+-
+-static irqreturn_t atmel_nfc_interrupt(int irq, void *data)
+-{
+-	struct atmel_hsmc_nand_controller *nc = data;
+-	u32 sr, rcvd;
+-	bool done;
+-
+-	regmap_read(nc->base.smc, ATMEL_HSMC_NFC_SR, &sr);
+-
+-	rcvd = sr & (nc->op.wait | ATMEL_HSMC_NFC_SR_ERRORS);
+-	done = atmel_nfc_op_done(&nc->op, sr);
+-
+-	if (rcvd)
+-		regmap_write(nc->base.smc, ATMEL_HSMC_NFC_IDR, rcvd);
+-
+-	if (done)
+-		complete(&nc->complete);
+-
+-	return rcvd ? IRQ_HANDLED : IRQ_NONE;
+-}
+-
+-static int atmel_nfc_wait(struct atmel_hsmc_nand_controller *nc, bool poll,
+-			  unsigned int timeout_ms)
+-{
+-	int ret;
+-
+-	if (!timeout_ms)
+-		timeout_ms = DEFAULT_TIMEOUT_MS;
+-
+-	if (poll) {
+-		u32 status;
+-
+-		ret = regmap_read_poll_timeout(nc->base.smc,
+-					       ATMEL_HSMC_NFC_SR, status,
+-					       atmel_nfc_op_done(&nc->op,
+-								 status),
+-					       0, timeout_ms * 1000);
+-	} else {
+-		init_completion(&nc->complete);
+-		regmap_write(nc->base.smc, ATMEL_HSMC_NFC_IER,
+-			     nc->op.wait | ATMEL_HSMC_NFC_SR_ERRORS);
+-		ret = wait_for_completion_timeout(&nc->complete,
+-						msecs_to_jiffies(timeout_ms));
+-		if (!ret)
+-			ret = -ETIMEDOUT;
+-		else
+-			ret = 0;
+-
+-		regmap_write(nc->base.smc, ATMEL_HSMC_NFC_IDR, 0xffffffff);
+-	}
+-
+-	if (nc->op.errors & ATMEL_HSMC_NFC_SR_DTOE) {
+-		dev_err(nc->base.dev, "Waiting NAND R/B Timeout\n");
+-		ret = -ETIMEDOUT;
+-	}
+-
+-	if (nc->op.errors & ATMEL_HSMC_NFC_SR_UNDEF) {
+-		dev_err(nc->base.dev, "Access to an undefined area\n");
+-		ret = -EIO;
+-	}
+-
+-	if (nc->op.errors & ATMEL_HSMC_NFC_SR_AWB) {
+-		dev_err(nc->base.dev, "Access while busy\n");
+-		ret = -EIO;
+-	}
+-
+-	if (nc->op.errors & ATMEL_HSMC_NFC_SR_NFCASE) {
+-		dev_err(nc->base.dev, "Wrong access size\n");
+-		ret = -EIO;
+-	}
+-
+-	return ret;
+-}
+-
+-static void atmel_nand_dma_transfer_finished(void *data)
+-{
+-	struct completion *finished = data;
+-
+-	complete(finished);
+-}
+-
+-static int atmel_nand_dma_transfer(struct atmel_nand_controller *nc,
+-				   void *buf, dma_addr_t dev_dma, size_t len,
+-				   enum dma_data_direction dir)
+-{
+-	DECLARE_COMPLETION_ONSTACK(finished);
+-	dma_addr_t src_dma, dst_dma, buf_dma;
+-	struct dma_async_tx_descriptor *tx;
+-	dma_cookie_t cookie;
+-
+-	buf_dma = dma_map_single(nc->dev, buf, len, dir);
+-	if (dma_mapping_error(nc->dev, dev_dma)) {
+-		dev_err(nc->dev,
+-			"Failed to prepare a buffer for DMA access\n");
+-		goto err;
+-	}
+-
+-	if (dir == DMA_FROM_DEVICE) {
+-		src_dma = dev_dma;
+-		dst_dma = buf_dma;
+-	} else {
+-		src_dma = buf_dma;
+-		dst_dma = dev_dma;
+-	}
+-
+-	tx = dmaengine_prep_dma_memcpy(nc->dmac, dst_dma, src_dma, len,
+-				       DMA_CTRL_ACK | DMA_PREP_INTERRUPT);
+-	if (!tx) {
+-		dev_err(nc->dev, "Failed to prepare DMA memcpy\n");
+-		goto err_unmap;
+-	}
+-
+-	tx->callback = atmel_nand_dma_transfer_finished;
+-	tx->callback_param = &finished;
+-
+-	cookie = dmaengine_submit(tx);
+-	if (dma_submit_error(cookie)) {
+-		dev_err(nc->dev, "Failed to do DMA tx_submit\n");
+-		goto err_unmap;
+-	}
+-
+-	dma_async_issue_pending(nc->dmac);
+-	wait_for_completion(&finished);
+-
+-	return 0;
+-
+-err_unmap:
+-	dma_unmap_single(nc->dev, buf_dma, len, dir);
+-
+-err:
+-	dev_dbg(nc->dev, "Fall back to CPU I/O\n");
+-
+-	return -EIO;
+-}
+-
+-static u8 atmel_nand_read_byte(struct mtd_info *mtd)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct atmel_nand *nand = to_atmel_nand(chip);
+-
+-	return ioread8(nand->activecs->io.virt);
+-}
+-
+-static u16 atmel_nand_read_word(struct mtd_info *mtd)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct atmel_nand *nand = to_atmel_nand(chip);
+-
+-	return ioread16(nand->activecs->io.virt);
+-}
+-
+-static void atmel_nand_write_byte(struct mtd_info *mtd, u8 byte)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct atmel_nand *nand = to_atmel_nand(chip);
+-
+-	if (chip->options & NAND_BUSWIDTH_16)
+-		iowrite16(byte | (byte << 8), nand->activecs->io.virt);
+-	else
+-		iowrite8(byte, nand->activecs->io.virt);
+-}
+-
+-static void atmel_nand_read_buf(struct mtd_info *mtd, u8 *buf, int len)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct atmel_nand *nand = to_atmel_nand(chip);
+-	struct atmel_nand_controller *nc;
+-
+-	nc = to_nand_controller(chip->controller);
+-
+-	/*
+-	 * If the controller supports DMA, the buffer address is DMA-able and
+-	 * len is long enough to make DMA transfers profitable, let's trigger
+-	 * a DMA transfer. If it fails, fallback to PIO mode.
+-	 */
+-	if (nc->dmac && virt_addr_valid(buf) &&
+-	    len >= MIN_DMA_LEN &&
+-	    !atmel_nand_dma_transfer(nc, buf, nand->activecs->io.dma, len,
+-				     DMA_FROM_DEVICE))
+-		return;
+-
+-	if (chip->options & NAND_BUSWIDTH_16)
+-		ioread16_rep(nand->activecs->io.virt, buf, len / 2);
+-	else
+-		ioread8_rep(nand->activecs->io.virt, buf, len);
+-}
+-
+-static void atmel_nand_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct atmel_nand *nand = to_atmel_nand(chip);
+-	struct atmel_nand_controller *nc;
+-
+-	nc = to_nand_controller(chip->controller);
+-
+-	/*
+-	 * If the controller supports DMA, the buffer address is DMA-able and
+-	 * len is long enough to make DMA transfers profitable, let's trigger
+-	 * a DMA transfer. If it fails, fallback to PIO mode.
+-	 */
+-	if (nc->dmac && virt_addr_valid(buf) &&
+-	    len >= MIN_DMA_LEN &&
+-	    !atmel_nand_dma_transfer(nc, (void *)buf, nand->activecs->io.dma,
+-				     len, DMA_TO_DEVICE))
+-		return;
+-
+-	if (chip->options & NAND_BUSWIDTH_16)
+-		iowrite16_rep(nand->activecs->io.virt, buf, len / 2);
+-	else
+-		iowrite8_rep(nand->activecs->io.virt, buf, len);
+-}
+-
+-static int atmel_nand_dev_ready(struct mtd_info *mtd)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct atmel_nand *nand = to_atmel_nand(chip);
+-
+-	return gpiod_get_value(nand->activecs->rb.gpio);
+-}
+-
+-static void atmel_nand_select_chip(struct mtd_info *mtd, int cs)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct atmel_nand *nand = to_atmel_nand(chip);
+-
+-	if (cs < 0 || cs >= nand->numcs) {
+-		nand->activecs = NULL;
+-		chip->dev_ready = NULL;
+-		return;
+-	}
+-
+-	nand->activecs = &nand->cs[cs];
+-
+-	if (nand->activecs->rb.type == ATMEL_NAND_GPIO_RB)
+-		chip->dev_ready = atmel_nand_dev_ready;
+-}
+-
+-static int atmel_hsmc_nand_dev_ready(struct mtd_info *mtd)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct atmel_nand *nand = to_atmel_nand(chip);
+-	struct atmel_hsmc_nand_controller *nc;
+-	u32 status;
+-
+-	nc = to_hsmc_nand_controller(chip->controller);
+-
+-	regmap_read(nc->base.smc, ATMEL_HSMC_NFC_SR, &status);
+-
+-	return status & ATMEL_HSMC_NFC_SR_RBEDGE(nand->activecs->rb.id);
+-}
+-
+-static void atmel_hsmc_nand_select_chip(struct mtd_info *mtd, int cs)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct atmel_nand *nand = to_atmel_nand(chip);
+-	struct atmel_hsmc_nand_controller *nc;
+-
+-	nc = to_hsmc_nand_controller(chip->controller);
+-
+-	atmel_nand_select_chip(mtd, cs);
+-
+-	if (!nand->activecs) {
+-		regmap_write(nc->base.smc, ATMEL_HSMC_NFC_CTRL,
+-			     ATMEL_HSMC_NFC_CTRL_DIS);
+-		return;
+-	}
+-
+-	if (nand->activecs->rb.type == ATMEL_NAND_NATIVE_RB)
+-		chip->dev_ready = atmel_hsmc_nand_dev_ready;
+-
+-	regmap_update_bits(nc->base.smc, ATMEL_HSMC_NFC_CFG,
+-			   ATMEL_HSMC_NFC_CFG_PAGESIZE_MASK |
+-			   ATMEL_HSMC_NFC_CFG_SPARESIZE_MASK |
+-			   ATMEL_HSMC_NFC_CFG_RSPARE |
+-			   ATMEL_HSMC_NFC_CFG_WSPARE,
+-			   ATMEL_HSMC_NFC_CFG_PAGESIZE(mtd->writesize) |
+-			   ATMEL_HSMC_NFC_CFG_SPARESIZE(mtd->oobsize) |
+-			   ATMEL_HSMC_NFC_CFG_RSPARE);
+-	regmap_write(nc->base.smc, ATMEL_HSMC_NFC_CTRL,
+-		     ATMEL_HSMC_NFC_CTRL_EN);
+-}
+-
+-static int atmel_nfc_exec_op(struct atmel_hsmc_nand_controller *nc, bool poll)
+-{
+-	u8 *addrs = nc->op.addrs;
+-	unsigned int op = 0;
+-	u32 addr, val;
+-	int i, ret;
+-
+-	nc->op.wait = ATMEL_HSMC_NFC_SR_CMDDONE;
+-
+-	for (i = 0; i < nc->op.ncmds; i++)
+-		op |= ATMEL_NFC_CMD(i, nc->op.cmds[i]);
+-
+-	if (nc->op.naddrs == ATMEL_NFC_MAX_ADDR_CYCLES)
+-		regmap_write(nc->base.smc, ATMEL_HSMC_NFC_ADDR, *addrs++);
+-
+-	op |= ATMEL_NFC_CSID(nc->op.cs) |
+-	      ATMEL_NFC_ACYCLE(nc->op.naddrs);
+-
+-	if (nc->op.ncmds > 1)
+-		op |= ATMEL_NFC_VCMD2;
+-
+-	addr = addrs[0] | (addrs[1] << 8) | (addrs[2] << 16) |
+-	       (addrs[3] << 24);
+-
+-	if (nc->op.data != ATMEL_NFC_NO_DATA) {
+-		op |= ATMEL_NFC_DATAEN;
+-		nc->op.wait |= ATMEL_HSMC_NFC_SR_XFRDONE;
+-
+-		if (nc->op.data == ATMEL_NFC_WRITE_DATA)
+-			op |= ATMEL_NFC_NFCWR;
+-	}
+-
+-	/* Clear all flags. */
+-	regmap_read(nc->base.smc, ATMEL_HSMC_NFC_SR, &val);
+-
+-	/* Send the command. */
+-	regmap_write(nc->io, op, addr);
+-
+-	ret = atmel_nfc_wait(nc, poll, 0);
+-	if (ret)
+-		dev_err(nc->base.dev,
+-			"Failed to send NAND command (err = %d)!",
+-			ret);
+-
+-	/* Reset the op state. */
+-	memset(&nc->op, 0, sizeof(nc->op));
+-
+-	return ret;
+-}
+-
+-static void atmel_hsmc_nand_cmd_ctrl(struct mtd_info *mtd, int dat,
+-				     unsigned int ctrl)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct atmel_nand *nand = to_atmel_nand(chip);
+-	struct atmel_hsmc_nand_controller *nc;
+-
+-	nc = to_hsmc_nand_controller(chip->controller);
+-
+-	if (ctrl & NAND_ALE) {
+-		if (nc->op.naddrs == ATMEL_NFC_MAX_ADDR_CYCLES)
+-			return;
+-
+-		nc->op.addrs[nc->op.naddrs++] = dat;
+-	} else if (ctrl & NAND_CLE) {
+-		if (nc->op.ncmds > 1)
+-			return;
+-
+-		nc->op.cmds[nc->op.ncmds++] = dat;
+-	}
+-
+-	if (dat == NAND_CMD_NONE) {
+-		nc->op.cs = nand->activecs->id;
+-		atmel_nfc_exec_op(nc, true);
+-	}
+-}
+-
+-static void atmel_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
+-				unsigned int ctrl)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct atmel_nand *nand = to_atmel_nand(chip);
+-	struct atmel_nand_controller *nc;
+-
+-	nc = to_nand_controller(chip->controller);
+-
+-	if ((ctrl & NAND_CTRL_CHANGE) && nand->activecs->csgpio) {
+-		if (ctrl & NAND_NCE)
+-			gpiod_set_value(nand->activecs->csgpio, 0);
+-		else
+-			gpiod_set_value(nand->activecs->csgpio, 1);
+-	}
+-
+-	if (ctrl & NAND_ALE)
+-		writeb(cmd, nand->activecs->io.virt + nc->caps->ale_offs);
+-	else if (ctrl & NAND_CLE)
+-		writeb(cmd, nand->activecs->io.virt + nc->caps->cle_offs);
+-}
+-
+-static void atmel_nfc_copy_to_sram(struct nand_chip *chip, const u8 *buf,
+-				   bool oob_required)
+-{
+-	struct mtd_info *mtd = nand_to_mtd(chip);
+-	struct atmel_hsmc_nand_controller *nc;
+-	int ret = -EIO;
+-
+-	nc = to_hsmc_nand_controller(chip->controller);
+-
+-	if (nc->base.dmac)
+-		ret = atmel_nand_dma_transfer(&nc->base, (void *)buf,
+-					      nc->sram.dma, mtd->writesize,
+-					      DMA_TO_DEVICE);
+-
+-	/* Falling back to CPU copy. */
+-	if (ret)
+-		memcpy_toio(nc->sram.virt, buf, mtd->writesize);
+-
+-	if (oob_required)
+-		memcpy_toio(nc->sram.virt + mtd->writesize, chip->oob_poi,
+-			    mtd->oobsize);
+-}
+-
+-static void atmel_nfc_copy_from_sram(struct nand_chip *chip, u8 *buf,
+-				     bool oob_required)
+-{
+-	struct mtd_info *mtd = nand_to_mtd(chip);
+-	struct atmel_hsmc_nand_controller *nc;
+-	int ret = -EIO;
+-
+-	nc = to_hsmc_nand_controller(chip->controller);
+-
+-	if (nc->base.dmac)
+-		ret = atmel_nand_dma_transfer(&nc->base, buf, nc->sram.dma,
+-					      mtd->writesize, DMA_FROM_DEVICE);
+-
+-	/* Falling back to CPU copy. */
+-	if (ret)
+-		memcpy_fromio(buf, nc->sram.virt, mtd->writesize);
+-
+-	if (oob_required)
+-		memcpy_fromio(chip->oob_poi, nc->sram.virt + mtd->writesize,
+-			      mtd->oobsize);
+-}
+-
+-static void atmel_nfc_set_op_addr(struct nand_chip *chip, int page, int column)
+-{
+-	struct mtd_info *mtd = nand_to_mtd(chip);
+-	struct atmel_hsmc_nand_controller *nc;
+-
+-	nc = to_hsmc_nand_controller(chip->controller);
+-
+-	if (column >= 0) {
+-		nc->op.addrs[nc->op.naddrs++] = column;
+-
+-		/*
+-		 * 2 address cycles for the column offset on large page NANDs.
+-		 */
+-		if (mtd->writesize > 512)
+-			nc->op.addrs[nc->op.naddrs++] = column >> 8;
+-	}
+-
+-	if (page >= 0) {
+-		nc->op.addrs[nc->op.naddrs++] = page;
+-		nc->op.addrs[nc->op.naddrs++] = page >> 8;
+-
+-		if ((mtd->writesize > 512 && chip->chipsize > SZ_128M) ||
+-		    (mtd->writesize <= 512 && chip->chipsize > SZ_32M))
+-			nc->op.addrs[nc->op.naddrs++] = page >> 16;
+-	}
+-}
+-
+-static int atmel_nand_pmecc_enable(struct nand_chip *chip, int op, bool raw)
+-{
+-	struct atmel_nand *nand = to_atmel_nand(chip);
+-	struct atmel_nand_controller *nc;
+-	int ret;
+-
+-	nc = to_nand_controller(chip->controller);
+-
+-	if (raw)
+-		return 0;
+-
+-	ret = atmel_pmecc_enable(nand->pmecc, op);
+-	if (ret)
+-		dev_err(nc->dev,
+-			"Failed to enable ECC engine (err = %d)\n", ret);
+-
+-	return ret;
+-}
+-
+-static void atmel_nand_pmecc_disable(struct nand_chip *chip, bool raw)
+-{
+-	struct atmel_nand *nand = to_atmel_nand(chip);
+-
+-	if (!raw)
+-		atmel_pmecc_disable(nand->pmecc);
+-}
+-
+-static int atmel_nand_pmecc_generate_eccbytes(struct nand_chip *chip, bool raw)
+-{
+-	struct atmel_nand *nand = to_atmel_nand(chip);
+-	struct mtd_info *mtd = nand_to_mtd(chip);
+-	struct atmel_nand_controller *nc;
+-	struct mtd_oob_region oobregion;
+-	void *eccbuf;
+-	int ret, i;
+-
+-	nc = to_nand_controller(chip->controller);
+-
+-	if (raw)
+-		return 0;
+-
+-	ret = atmel_pmecc_wait_rdy(nand->pmecc);
+-	if (ret) {
+-		dev_err(nc->dev,
+-			"Failed to transfer NAND page data (err = %d)\n",
+-			ret);
+-		return ret;
+-	}
+-
+-	mtd_ooblayout_ecc(mtd, 0, &oobregion);
+-	eccbuf = chip->oob_poi + oobregion.offset;
+-
+-	for (i = 0; i < chip->ecc.steps; i++) {
+-		atmel_pmecc_get_generated_eccbytes(nand->pmecc, i,
+-						   eccbuf);
+-		eccbuf += chip->ecc.bytes;
+-	}
+-
+-	return 0;
+-}
+-
+-static int atmel_nand_pmecc_correct_data(struct nand_chip *chip, void *buf,
+-					 bool raw)
+-{
+-	struct atmel_nand *nand = to_atmel_nand(chip);
+-	struct mtd_info *mtd = nand_to_mtd(chip);
+-	struct atmel_nand_controller *nc;
+-	struct mtd_oob_region oobregion;
+-	int ret, i, max_bitflips = 0;
+-	void *databuf, *eccbuf;
+-
+-	nc = to_nand_controller(chip->controller);
+-
+-	if (raw)
+-		return 0;
+-
+-	ret = atmel_pmecc_wait_rdy(nand->pmecc);
+-	if (ret) {
+-		dev_err(nc->dev,
+-			"Failed to read NAND page data (err = %d)\n",
+-			ret);
+-		return ret;
+-	}
+-
+-	mtd_ooblayout_ecc(mtd, 0, &oobregion);
+-	eccbuf = chip->oob_poi + oobregion.offset;
+-	databuf = buf;
+-
+-	for (i = 0; i < chip->ecc.steps; i++) {
+-		ret = atmel_pmecc_correct_sector(nand->pmecc, i, databuf,
+-						 eccbuf);
+-		if (ret < 0 && !atmel_pmecc_correct_erased_chunks(nand->pmecc))
+-			ret = nand_check_erased_ecc_chunk(databuf,
+-							  chip->ecc.size,
+-							  eccbuf,
+-							  chip->ecc.bytes,
+-							  NULL, 0,
+-							  chip->ecc.strength);
+-
+-		if (ret >= 0)
+-			max_bitflips = max(ret, max_bitflips);
+-		else
+-			mtd->ecc_stats.failed++;
+-
+-		databuf += chip->ecc.size;
+-		eccbuf += chip->ecc.bytes;
+-	}
+-
+-	return max_bitflips;
+-}
+-
+-static int atmel_nand_pmecc_write_pg(struct nand_chip *chip, const u8 *buf,
+-				     bool oob_required, int page, bool raw)
+-{
+-	struct mtd_info *mtd = nand_to_mtd(chip);
+-	struct atmel_nand *nand = to_atmel_nand(chip);
+-	int ret;
+-
+-	ret = atmel_nand_pmecc_enable(chip, NAND_ECC_WRITE, raw);
+-	if (ret)
+-		return ret;
+-
+-	atmel_nand_write_buf(mtd, buf, mtd->writesize);
+-
+-	ret = atmel_nand_pmecc_generate_eccbytes(chip, raw);
+-	if (ret) {
+-		atmel_pmecc_disable(nand->pmecc);
+-		return ret;
+-	}
+-
+-	atmel_nand_pmecc_disable(chip, raw);
+-
+-	atmel_nand_write_buf(mtd, chip->oob_poi, mtd->oobsize);
+-
+-	return 0;
+-}
+-
+-static int atmel_nand_pmecc_write_page(struct mtd_info *mtd,
+-				       struct nand_chip *chip, const u8 *buf,
+-				       int oob_required, int page)
+-{
+-	return atmel_nand_pmecc_write_pg(chip, buf, oob_required, page, false);
+-}
+-
+-static int atmel_nand_pmecc_write_page_raw(struct mtd_info *mtd,
+-					   struct nand_chip *chip,
+-					   const u8 *buf, int oob_required,
+-					   int page)
+-{
+-	return atmel_nand_pmecc_write_pg(chip, buf, oob_required, page, true);
+-}
+-
+-static int atmel_nand_pmecc_read_pg(struct nand_chip *chip, u8 *buf,
+-				    bool oob_required, int page, bool raw)
+-{
+-	struct mtd_info *mtd = nand_to_mtd(chip);
+-	int ret;
+-
+-	ret = atmel_nand_pmecc_enable(chip, NAND_ECC_READ, raw);
+-	if (ret)
+-		return ret;
+-
+-	atmel_nand_read_buf(mtd, buf, mtd->writesize);
+-	atmel_nand_read_buf(mtd, chip->oob_poi, mtd->oobsize);
+-
+-	ret = atmel_nand_pmecc_correct_data(chip, buf, raw);
+-
+-	atmel_nand_pmecc_disable(chip, raw);
+-
+-	return ret;
+-}
+-
+-static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,
+-				      struct nand_chip *chip, u8 *buf,
+-				      int oob_required, int page)
+-{
+-	return atmel_nand_pmecc_read_pg(chip, buf, oob_required, page, false);
+-}
+-
+-static int atmel_nand_pmecc_read_page_raw(struct mtd_info *mtd,
+-					  struct nand_chip *chip, u8 *buf,
+-					  int oob_required, int page)
+-{
+-	return atmel_nand_pmecc_read_pg(chip, buf, oob_required, page, true);
+-}
+-
+-static int atmel_hsmc_nand_pmecc_write_pg(struct nand_chip *chip,
+-					  const u8 *buf, bool oob_required,
+-					  int page, bool raw)
+-{
+-	struct mtd_info *mtd = nand_to_mtd(chip);
+-	struct atmel_nand *nand = to_atmel_nand(chip);
+-	struct atmel_hsmc_nand_controller *nc;
+-	int ret, status;
+-
+-	nc = to_hsmc_nand_controller(chip->controller);
+-
+-	atmel_nfc_copy_to_sram(chip, buf, false);
+-
+-	nc->op.cmds[0] = NAND_CMD_SEQIN;
+-	nc->op.ncmds = 1;
+-	atmel_nfc_set_op_addr(chip, page, 0x0);
+-	nc->op.cs = nand->activecs->id;
+-	nc->op.data = ATMEL_NFC_WRITE_DATA;
+-
+-	ret = atmel_nand_pmecc_enable(chip, NAND_ECC_WRITE, raw);
+-	if (ret)
+-		return ret;
+-
+-	ret = atmel_nfc_exec_op(nc, false);
+-	if (ret) {
+-		atmel_nand_pmecc_disable(chip, raw);
+-		dev_err(nc->base.dev,
+-			"Failed to transfer NAND page data (err = %d)\n",
+-			ret);
+-		return ret;
+-	}
+-
+-	ret = atmel_nand_pmecc_generate_eccbytes(chip, raw);
+-
+-	atmel_nand_pmecc_disable(chip, raw);
+-
+-	if (ret)
+-		return ret;
+-
+-	atmel_nand_write_buf(mtd, chip->oob_poi, mtd->oobsize);
+-
+-	nc->op.cmds[0] = NAND_CMD_PAGEPROG;
+-	nc->op.ncmds = 1;
+-	nc->op.cs = nand->activecs->id;
+-	ret = atmel_nfc_exec_op(nc, false);
+-	if (ret)
+-		dev_err(nc->base.dev, "Failed to program NAND page (err = %d)\n",
+-			ret);
+-
+-	status = chip->waitfunc(mtd, chip);
+-	if (status & NAND_STATUS_FAIL)
+-		return -EIO;
+-
+-	return ret;
+-}
+-
+-static int atmel_hsmc_nand_pmecc_write_page(struct mtd_info *mtd,
+-					    struct nand_chip *chip,
+-					    const u8 *buf, int oob_required,
+-					    int page)
+-{
+-	return atmel_hsmc_nand_pmecc_write_pg(chip, buf, oob_required, page,
+-					      false);
+-}
+-
+-static int atmel_hsmc_nand_pmecc_write_page_raw(struct mtd_info *mtd,
+-						struct nand_chip *chip,
+-						const u8 *buf,
+-						int oob_required, int page)
+-{
+-	return atmel_hsmc_nand_pmecc_write_pg(chip, buf, oob_required, page,
+-					      true);
+-}
+-
+-static int atmel_hsmc_nand_pmecc_read_pg(struct nand_chip *chip, u8 *buf,
+-					 bool oob_required, int page,
+-					 bool raw)
+-{
+-	struct mtd_info *mtd = nand_to_mtd(chip);
+-	struct atmel_nand *nand = to_atmel_nand(chip);
+-	struct atmel_hsmc_nand_controller *nc;
+-	int ret;
+-
+-	nc = to_hsmc_nand_controller(chip->controller);
+-
+-	/*
+-	 * Optimized read page accessors only work when the NAND R/B pin is
+-	 * connected to a native SoC R/B pin. If that's not the case, fallback
+-	 * to the non-optimized one.
+-	 */
+-	if (nand->activecs->rb.type != ATMEL_NAND_NATIVE_RB) {
+-		chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
+-
+-		return atmel_nand_pmecc_read_pg(chip, buf, oob_required, page,
+-						raw);
+-	}
+-
+-	nc->op.cmds[nc->op.ncmds++] = NAND_CMD_READ0;
+-
+-	if (mtd->writesize > 512)
+-		nc->op.cmds[nc->op.ncmds++] = NAND_CMD_READSTART;
+-
+-	atmel_nfc_set_op_addr(chip, page, 0x0);
+-	nc->op.cs = nand->activecs->id;
+-	nc->op.data = ATMEL_NFC_READ_DATA;
+-
+-	ret = atmel_nand_pmecc_enable(chip, NAND_ECC_READ, raw);
+-	if (ret)
+-		return ret;
+-
+-	ret = atmel_nfc_exec_op(nc, false);
+-	if (ret) {
+-		atmel_nand_pmecc_disable(chip, raw);
+-		dev_err(nc->base.dev,
+-			"Failed to load NAND page data (err = %d)\n",
+-			ret);
+-		return ret;
+-	}
+-
+-	atmel_nfc_copy_from_sram(chip, buf, true);
+-
+-	ret = atmel_nand_pmecc_correct_data(chip, buf, raw);
+-
+-	atmel_nand_pmecc_disable(chip, raw);
+-
+-	return ret;
+-}
+-
+-static int atmel_hsmc_nand_pmecc_read_page(struct mtd_info *mtd,
+-					   struct nand_chip *chip, u8 *buf,
+-					   int oob_required, int page)
+-{
+-	return atmel_hsmc_nand_pmecc_read_pg(chip, buf, oob_required, page,
+-					     false);
+-}
+-
+-static int atmel_hsmc_nand_pmecc_read_page_raw(struct mtd_info *mtd,
+-					       struct nand_chip *chip,
+-					       u8 *buf, int oob_required,
+-					       int page)
+-{
+-	return atmel_hsmc_nand_pmecc_read_pg(chip, buf, oob_required, page,
+-					     true);
+-}
+-
+-static int atmel_nand_pmecc_init(struct nand_chip *chip)
+-{
+-	struct mtd_info *mtd = nand_to_mtd(chip);
+-	struct atmel_nand *nand = to_atmel_nand(chip);
+-	struct atmel_nand_controller *nc;
+-	struct atmel_pmecc_user_req req;
+-
+-	nc = to_nand_controller(chip->controller);
+-
+-	if (!nc->pmecc) {
+-		dev_err(nc->dev, "HW ECC not supported\n");
+-		return -ENOTSUPP;
+-	}
+-
+-	if (nc->caps->legacy_of_bindings) {
+-		u32 val;
+-
+-		if (!of_property_read_u32(nc->dev->of_node, "atmel,pmecc-cap",
+-					  &val))
+-			chip->ecc.strength = val;
+-
+-		if (!of_property_read_u32(nc->dev->of_node,
+-					  "atmel,pmecc-sector-size",
+-					  &val))
+-			chip->ecc.size = val;
+-	}
+-
+-	if (chip->ecc.options & NAND_ECC_MAXIMIZE)
+-		req.ecc.strength = ATMEL_PMECC_MAXIMIZE_ECC_STRENGTH;
+-	else if (chip->ecc.strength)
+-		req.ecc.strength = chip->ecc.strength;
+-	else if (chip->ecc_strength_ds)
+-		req.ecc.strength = chip->ecc_strength_ds;
+-	else
+-		req.ecc.strength = ATMEL_PMECC_MAXIMIZE_ECC_STRENGTH;
+-
+-	if (chip->ecc.size)
+-		req.ecc.sectorsize = chip->ecc.size;
+-	else if (chip->ecc_step_ds)
+-		req.ecc.sectorsize = chip->ecc_step_ds;
+-	else
+-		req.ecc.sectorsize = ATMEL_PMECC_SECTOR_SIZE_AUTO;
+-
+-	req.pagesize = mtd->writesize;
+-	req.oobsize = mtd->oobsize;
+-
+-	if (mtd->writesize <= 512) {
+-		req.ecc.bytes = 4;
+-		req.ecc.ooboffset = 0;
+-	} else {
+-		req.ecc.bytes = mtd->oobsize - 2;
+-		req.ecc.ooboffset = ATMEL_PMECC_OOBOFFSET_AUTO;
+-	}
+-
+-	nand->pmecc = atmel_pmecc_create_user(nc->pmecc, &req);
+-	if (IS_ERR(nand->pmecc))
+-		return PTR_ERR(nand->pmecc);
+-
+-	chip->ecc.algo = NAND_ECC_BCH;
+-	chip->ecc.size = req.ecc.sectorsize;
+-	chip->ecc.bytes = req.ecc.bytes / req.ecc.nsectors;
+-	chip->ecc.strength = req.ecc.strength;
+-
+-	chip->options |= NAND_NO_SUBPAGE_WRITE;
+-
+-	mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
+-
+-	return 0;
+-}
+-
+-static int atmel_nand_ecc_init(struct atmel_nand *nand)
+-{
+-	struct nand_chip *chip = &nand->base;
+-	struct atmel_nand_controller *nc;
+-	int ret;
+-
+-	nc = to_nand_controller(chip->controller);
+-
+-	switch (chip->ecc.mode) {
+-	case NAND_ECC_NONE:
+-	case NAND_ECC_SOFT:
+-		/*
+-		 * Nothing to do, the core will initialize everything for us.
+-		 */
+-		break;
+-
+-	case NAND_ECC_HW:
+-		ret = atmel_nand_pmecc_init(chip);
+-		if (ret)
+-			return ret;
+-
+-		chip->ecc.read_page = atmel_nand_pmecc_read_page;
+-		chip->ecc.write_page = atmel_nand_pmecc_write_page;
+-		chip->ecc.read_page_raw = atmel_nand_pmecc_read_page_raw;
+-		chip->ecc.write_page_raw = atmel_nand_pmecc_write_page_raw;
+-		break;
+-
+-	default:
+-		/* Other modes are not supported. */
+-		dev_err(nc->dev, "Unsupported ECC mode: %d\n",
+-			chip->ecc.mode);
+-		return -ENOTSUPP;
+-	}
+-
+-	return 0;
+-}
+-
+-static int atmel_hsmc_nand_ecc_init(struct atmel_nand *nand)
+-{
+-	struct nand_chip *chip = &nand->base;
+-	int ret;
+-
+-	ret = atmel_nand_ecc_init(nand);
+-	if (ret)
+-		return ret;
+-
+-	if (chip->ecc.mode != NAND_ECC_HW)
+-		return 0;
+-
+-	/* Adjust the ECC operations for the HSMC IP. */
+-	chip->ecc.read_page = atmel_hsmc_nand_pmecc_read_page;
+-	chip->ecc.write_page = atmel_hsmc_nand_pmecc_write_page;
+-	chip->ecc.read_page_raw = atmel_hsmc_nand_pmecc_read_page_raw;
+-	chip->ecc.write_page_raw = atmel_hsmc_nand_pmecc_write_page_raw;
+-	chip->ecc.options |= NAND_ECC_CUSTOM_PAGE_ACCESS;
+-
+-	return 0;
+-}
+-
+-static int atmel_smc_nand_prepare_smcconf(struct atmel_nand *nand,
+-					const struct nand_data_interface *conf,
+-					struct atmel_smc_cs_conf *smcconf)
+-{
+-	u32 ncycles, totalcycles, timeps, mckperiodps;
+-	struct atmel_nand_controller *nc;
+-	int ret;
+-
+-	nc = to_nand_controller(nand->base.controller);
+-
+-	/* DDR interface not supported. */
+-	if (conf->type != NAND_SDR_IFACE)
+-		return -ENOTSUPP;
+-
+-	/*
+-	 * tRC < 30ns implies EDO mode. This controller does not support this
+-	 * mode.
+-	 */
+-	if (conf->timings.sdr.tRC_min < 30000)
+-		return -ENOTSUPP;
+-
+-	atmel_smc_cs_conf_init(smcconf);
+-
+-	mckperiodps = NSEC_PER_SEC / clk_get_rate(nc->mck);
+-	mckperiodps *= 1000;
+-
+-	/*
+-	 * Set write pulse timing. This one is easy to extract:
+-	 *
+-	 * NWE_PULSE = tWP
+-	 */
+-	ncycles = DIV_ROUND_UP(conf->timings.sdr.tWP_min, mckperiodps);
+-	totalcycles = ncycles;
+-	ret = atmel_smc_cs_conf_set_pulse(smcconf, ATMEL_SMC_NWE_SHIFT,
+-					  ncycles);
+-	if (ret)
+-		return ret;
+-
+-	/*
+-	 * The write setup timing depends on the operation done on the NAND.
+-	 * All operations goes through the same data bus, but the operation
+-	 * type depends on the address we are writing to (ALE/CLE address
+-	 * lines).
+-	 * Since we have no way to differentiate the different operations at
+-	 * the SMC level, we must consider the worst case (the biggest setup
+-	 * time among all operation types):
+-	 *
+-	 * NWE_SETUP = max(tCLS, tCS, tALS, tDS) - NWE_PULSE
+-	 */
+-	timeps = max3(conf->timings.sdr.tCLS_min, conf->timings.sdr.tCS_min,
+-		      conf->timings.sdr.tALS_min);
+-	timeps = max(timeps, conf->timings.sdr.tDS_min);
+-	ncycles = DIV_ROUND_UP(timeps, mckperiodps);
+-	ncycles = ncycles > totalcycles ? ncycles - totalcycles : 0;
+-	totalcycles += ncycles;
+-	ret = atmel_smc_cs_conf_set_setup(smcconf, ATMEL_SMC_NWE_SHIFT,
+-					  ncycles);
+-	if (ret)
+-		return ret;
+-
+-	/*
+-	 * As for the write setup timing, the write hold timing depends on the
+-	 * operation done on the NAND:
+-	 *
+-	 * NWE_HOLD = max(tCLH, tCH, tALH, tDH, tWH)
+-	 */
+-	timeps = max3(conf->timings.sdr.tCLH_min, conf->timings.sdr.tCH_min,
+-		      conf->timings.sdr.tALH_min);
+-	timeps = max3(timeps, conf->timings.sdr.tDH_min,
+-		      conf->timings.sdr.tWH_min);
+-	ncycles = DIV_ROUND_UP(timeps, mckperiodps);
+-	totalcycles += ncycles;
+-
+-	/*
+-	 * The write cycle timing is directly matching tWC, but is also
+-	 * dependent on the other timings on the setup and hold timings we
+-	 * calculated earlier, which gives:
+-	 *
+-	 * NWE_CYCLE = max(tWC, NWE_SETUP + NWE_PULSE + NWE_HOLD)
+-	 */
+-	ncycles = DIV_ROUND_UP(conf->timings.sdr.tWC_min, mckperiodps);
+-	ncycles = max(totalcycles, ncycles);
+-	ret = atmel_smc_cs_conf_set_cycle(smcconf, ATMEL_SMC_NWE_SHIFT,
+-					  ncycles);
+-	if (ret)
+-		return ret;
+-
+-	/*
+-	 * We don't want the CS line to be toggled between each byte/word
+-	 * transfer to the NAND. The only way to guarantee that is to have the
+-	 * NCS_{WR,RD}_{SETUP,HOLD} timings set to 0, which in turn means:
+-	 *
+-	 * NCS_WR_PULSE = NWE_CYCLE
+-	 */
+-	ret = atmel_smc_cs_conf_set_pulse(smcconf, ATMEL_SMC_NCS_WR_SHIFT,
+-					  ncycles);
+-	if (ret)
+-		return ret;
+-
+-	/*
+-	 * As for the write setup timing, the read hold timing depends on the
+-	 * operation done on the NAND:
+-	 *
+-	 * NRD_HOLD = max(tREH, tRHOH)
+-	 */
+-	timeps = max(conf->timings.sdr.tREH_min, conf->timings.sdr.tRHOH_min);
+-	ncycles = DIV_ROUND_UP(timeps, mckperiodps);
+-	totalcycles = ncycles;
+-
+-	/*
+-	 * TDF = tRHZ - NRD_HOLD
+-	 */
+-	ncycles = DIV_ROUND_UP(conf->timings.sdr.tRHZ_max, mckperiodps);
+-	ncycles -= totalcycles;
+-
+-	/*
+-	 * In ONFI 4.0 specs, tRHZ has been increased to support EDO NANDs and
+-	 * we might end up with a config that does not fit in the TDF field.
+-	 * Just take the max value in this case and hope that the NAND is more
+-	 * tolerant than advertised.
+-	 */
+-	if (ncycles > ATMEL_SMC_MODE_TDF_MAX)
+-		ncycles = ATMEL_SMC_MODE_TDF_MAX;
+-	else if (ncycles < ATMEL_SMC_MODE_TDF_MIN)
+-		ncycles = ATMEL_SMC_MODE_TDF_MIN;
+-
+-	smcconf->mode |= ATMEL_SMC_MODE_TDF(ncycles) |
+-			 ATMEL_SMC_MODE_TDFMODE_OPTIMIZED;
+-
+-	/*
+-	 * Read pulse timing directly matches tRP:
+-	 *
+-	 * NRD_PULSE = tRP
+-	 */
+-	ncycles = DIV_ROUND_UP(conf->timings.sdr.tRP_min, mckperiodps);
+-	totalcycles += ncycles;
+-	ret = atmel_smc_cs_conf_set_pulse(smcconf, ATMEL_SMC_NRD_SHIFT,
+-					  ncycles);
+-	if (ret)
+-		return ret;
+-
+-	/*
+-	 * The write cycle timing is directly matching tWC, but is also
+-	 * dependent on the setup and hold timings we calculated earlier,
+-	 * which gives:
+-	 *
+-	 * NRD_CYCLE = max(tRC, NRD_PULSE + NRD_HOLD)
+-	 *
+-	 * NRD_SETUP is always 0.
+-	 */
+-	ncycles = DIV_ROUND_UP(conf->timings.sdr.tRC_min, mckperiodps);
+-	ncycles = max(totalcycles, ncycles);
+-	ret = atmel_smc_cs_conf_set_cycle(smcconf, ATMEL_SMC_NRD_SHIFT,
+-					  ncycles);
+-	if (ret)
+-		return ret;
+-
+-	/*
+-	 * We don't want the CS line to be toggled between each byte/word
+-	 * transfer from the NAND. The only way to guarantee that is to have
+-	 * the NCS_{WR,RD}_{SETUP,HOLD} timings set to 0, which in turn means:
+-	 *
+-	 * NCS_RD_PULSE = NRD_CYCLE
+-	 */
+-	ret = atmel_smc_cs_conf_set_pulse(smcconf, ATMEL_SMC_NCS_RD_SHIFT,
+-					  ncycles);
+-	if (ret)
+-		return ret;
+-
+-	/* Txxx timings are directly matching tXXX ones. */
+-	ncycles = DIV_ROUND_UP(conf->timings.sdr.tCLR_min, mckperiodps);
+-	ret = atmel_smc_cs_conf_set_timing(smcconf,
+-					   ATMEL_HSMC_TIMINGS_TCLR_SHIFT,
+-					   ncycles);
+-	if (ret)
+-		return ret;
+-
+-	ncycles = DIV_ROUND_UP(conf->timings.sdr.tADL_min, mckperiodps);
+-	ret = atmel_smc_cs_conf_set_timing(smcconf,
+-					   ATMEL_HSMC_TIMINGS_TADL_SHIFT,
+-					   ncycles);
+-	/*
+-	 * Version 4 of the ONFI spec mandates that tADL be at least 400
+-	 * nanoseconds, but, depending on the master clock rate, 400 ns may not
+-	 * fit in the tADL field of the SMC reg. We need to relax the check and
+-	 * accept the -ERANGE return code.
+-	 *
+-	 * Note that previous versions of the ONFI spec had a lower tADL_min
+-	 * (100 or 200 ns). It's not clear why this timing constraint got
+-	 * increased but it seems most NANDs are fine with values lower than
+-	 * 400ns, so we should be safe.
+-	 */
+-	if (ret && ret != -ERANGE)
+-		return ret;
+-
+-	ncycles = DIV_ROUND_UP(conf->timings.sdr.tAR_min, mckperiodps);
+-	ret = atmel_smc_cs_conf_set_timing(smcconf,
+-					   ATMEL_HSMC_TIMINGS_TAR_SHIFT,
+-					   ncycles);
+-	if (ret)
+-		return ret;
+-
+-	ncycles = DIV_ROUND_UP(conf->timings.sdr.tRR_min, mckperiodps);
+-	ret = atmel_smc_cs_conf_set_timing(smcconf,
+-					   ATMEL_HSMC_TIMINGS_TRR_SHIFT,
+-					   ncycles);
+-	if (ret)
+-		return ret;
+-
+-	ncycles = DIV_ROUND_UP(conf->timings.sdr.tWB_max, mckperiodps);
+-	ret = atmel_smc_cs_conf_set_timing(smcconf,
+-					   ATMEL_HSMC_TIMINGS_TWB_SHIFT,
+-					   ncycles);
+-	if (ret)
+-		return ret;
+-
+-	/* Attach the CS line to the NFC logic. */
+-	smcconf->timings |= ATMEL_HSMC_TIMINGS_NFSEL;
+-
+-	/* Set the appropriate data bus width. */
+-	if (nand->base.options & NAND_BUSWIDTH_16)
+-		smcconf->mode |= ATMEL_SMC_MODE_DBW_16;
+-
+-	/* Operate in NRD/NWE READ/WRITEMODE. */
+-	smcconf->mode |= ATMEL_SMC_MODE_READMODE_NRD |
+-			 ATMEL_SMC_MODE_WRITEMODE_NWE;
+-
+-	return 0;
+-}
+-
+-static int atmel_smc_nand_setup_data_interface(struct atmel_nand *nand,
+-					int csline,
+-					const struct nand_data_interface *conf)
+-{
+-	struct atmel_nand_controller *nc;
+-	struct atmel_smc_cs_conf smcconf;
+-	struct atmel_nand_cs *cs;
+-	int ret;
+-
+-	nc = to_nand_controller(nand->base.controller);
+-
+-	ret = atmel_smc_nand_prepare_smcconf(nand, conf, &smcconf);
+-	if (ret)
+-		return ret;
+-
+-	if (csline == NAND_DATA_IFACE_CHECK_ONLY)
+-		return 0;
+-
+-	cs = &nand->cs[csline];
+-	cs->smcconf = smcconf;
+-	atmel_smc_cs_conf_apply(nc->smc, cs->id, &cs->smcconf);
+-
+-	return 0;
+-}
+-
+-static int atmel_hsmc_nand_setup_data_interface(struct atmel_nand *nand,
+-					int csline,
+-					const struct nand_data_interface *conf)
+-{
+-	struct atmel_hsmc_nand_controller *nc;
+-	struct atmel_smc_cs_conf smcconf;
+-	struct atmel_nand_cs *cs;
+-	int ret;
+-
+-	nc = to_hsmc_nand_controller(nand->base.controller);
+-
+-	ret = atmel_smc_nand_prepare_smcconf(nand, conf, &smcconf);
+-	if (ret)
+-		return ret;
+-
+-	if (csline == NAND_DATA_IFACE_CHECK_ONLY)
+-		return 0;
+-
+-	cs = &nand->cs[csline];
+-	cs->smcconf = smcconf;
+-
+-	if (cs->rb.type == ATMEL_NAND_NATIVE_RB)
+-		cs->smcconf.timings |= ATMEL_HSMC_TIMINGS_RBNSEL(cs->rb.id);
+-
+-	atmel_hsmc_cs_conf_apply(nc->base.smc, nc->hsmc_layout, cs->id,
+-				 &cs->smcconf);
+-
+-	return 0;
+-}
+-
+-static int atmel_nand_setup_data_interface(struct mtd_info *mtd, int csline,
+-					const struct nand_data_interface *conf)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct atmel_nand *nand = to_atmel_nand(chip);
+-	struct atmel_nand_controller *nc;
+-
+-	nc = to_nand_controller(nand->base.controller);
+-
+-	if (csline >= nand->numcs ||
+-	    (csline < 0 && csline != NAND_DATA_IFACE_CHECK_ONLY))
+-		return -EINVAL;
+-
+-	return nc->caps->ops->setup_data_interface(nand, csline, conf);
+-}
+-
+-static void atmel_nand_init(struct atmel_nand_controller *nc,
+-			    struct atmel_nand *nand)
+-{
+-	struct nand_chip *chip = &nand->base;
+-	struct mtd_info *mtd = nand_to_mtd(chip);
+-
+-	mtd->dev.parent = nc->dev;
+-	nand->base.controller = &nc->base;
+-
+-	chip->cmd_ctrl = atmel_nand_cmd_ctrl;
+-	chip->read_byte = atmel_nand_read_byte;
+-	chip->read_word = atmel_nand_read_word;
+-	chip->write_byte = atmel_nand_write_byte;
+-	chip->read_buf = atmel_nand_read_buf;
+-	chip->write_buf = atmel_nand_write_buf;
+-	chip->select_chip = atmel_nand_select_chip;
+-
+-	if (nc->mck && nc->caps->ops->setup_data_interface)
+-		chip->setup_data_interface = atmel_nand_setup_data_interface;
+-
+-	/* Some NANDs require a longer delay than the default one (20us). */
+-	chip->chip_delay = 40;
+-
+-	/*
+-	 * Use a bounce buffer when the buffer passed by the MTD user is not
+-	 * suitable for DMA.
+-	 */
+-	if (nc->dmac)
+-		chip->options |= NAND_USE_BOUNCE_BUFFER;
+-
+-	/* Default to HW ECC if pmecc is available. */
+-	if (nc->pmecc)
+-		chip->ecc.mode = NAND_ECC_HW;
+-}
+-
+-static void atmel_smc_nand_init(struct atmel_nand_controller *nc,
+-				struct atmel_nand *nand)
+-{
+-	struct nand_chip *chip = &nand->base;
+-	struct atmel_smc_nand_controller *smc_nc;
+-	int i;
+-
+-	atmel_nand_init(nc, nand);
+-
+-	smc_nc = to_smc_nand_controller(chip->controller);
+-	if (!smc_nc->matrix)
+-		return;
+-
+-	/* Attach the CS to the NAND Flash logic. */
+-	for (i = 0; i < nand->numcs; i++)
+-		regmap_update_bits(smc_nc->matrix, smc_nc->ebi_csa_offs,
+-				   BIT(nand->cs[i].id), BIT(nand->cs[i].id));
+-}
+-
+-static void atmel_hsmc_nand_init(struct atmel_nand_controller *nc,
+-				 struct atmel_nand *nand)
+-{
+-	struct nand_chip *chip = &nand->base;
+-
+-	atmel_nand_init(nc, nand);
+-
+-	/* Overload some methods for the HSMC controller. */
+-	chip->cmd_ctrl = atmel_hsmc_nand_cmd_ctrl;
+-	chip->select_chip = atmel_hsmc_nand_select_chip;
+-}
+-
+-static int atmel_nand_detect(struct atmel_nand *nand)
+-{
+-	struct nand_chip *chip = &nand->base;
+-	struct mtd_info *mtd = nand_to_mtd(chip);
+-	struct atmel_nand_controller *nc;
+-	int ret;
+-
+-	nc = to_nand_controller(chip->controller);
+-
+-	ret = nand_scan_ident(mtd, nand->numcs, NULL);
+-	if (ret)
+-		dev_err(nc->dev, "nand_scan_ident() failed: %d\n", ret);
+-
+-	return ret;
+-}
+-
+-static int atmel_nand_unregister(struct atmel_nand *nand)
+-{
+-	struct nand_chip *chip = &nand->base;
+-	struct mtd_info *mtd = nand_to_mtd(chip);
+-	int ret;
+-
+-	ret = mtd_device_unregister(mtd);
+-	if (ret)
+-		return ret;
+-
+-	nand_cleanup(chip);
+-	list_del(&nand->node);
+-
+-	return 0;
+-}
+-
+-static int atmel_nand_register(struct atmel_nand *nand)
+-{
+-	struct nand_chip *chip = &nand->base;
+-	struct mtd_info *mtd = nand_to_mtd(chip);
+-	struct atmel_nand_controller *nc;
+-	int ret;
+-
+-	nc = to_nand_controller(chip->controller);
+-
+-	if (nc->caps->legacy_of_bindings || !nc->dev->of_node) {
+-		/*
+-		 * We keep the MTD name unchanged to avoid breaking platforms
+-		 * where the MTD cmdline parser is used and the bootloader
+-		 * has not been updated to use the new naming scheme.
+-		 */
+-		mtd->name = "atmel_nand";
+-	} else if (!mtd->name) {
+-		/*
+-		 * If the new bindings are used and the bootloader has not been
+-		 * updated to pass a new mtdparts parameter on the cmdline, you
+-		 * should define the following property in your nand node:
+-		 *
+-		 *	label = "atmel_nand";
+-		 *
+-		 * This way, mtd->name will be set by the core when
+-		 * nand_set_flash_node() is called.
+-		 */
+-		mtd->name = devm_kasprintf(nc->dev, GFP_KERNEL,
+-					   "%s:nand.%d", dev_name(nc->dev),
+-					   nand->cs[0].id);
+-		if (!mtd->name) {
+-			dev_err(nc->dev, "Failed to allocate mtd->name\n");
+-			return -ENOMEM;
+-		}
+-	}
+-
+-	ret = nand_scan_tail(mtd);
+-	if (ret) {
+-		dev_err(nc->dev, "nand_scan_tail() failed: %d\n", ret);
+-		return ret;
+-	}
+-
+-	ret = mtd_device_register(mtd, NULL, 0);
+-	if (ret) {
+-		dev_err(nc->dev, "Failed to register mtd device: %d\n", ret);
+-		nand_cleanup(chip);
+-		return ret;
+-	}
+-
+-	list_add_tail(&nand->node, &nc->chips);
+-
+-	return 0;
+-}
+-
+-static struct atmel_nand *atmel_nand_create(struct atmel_nand_controller *nc,
+-					    struct device_node *np,
+-					    int reg_cells)
+-{
+-	struct atmel_nand *nand;
+-	struct gpio_desc *gpio;
+-	int numcs, ret, i;
+-
+-	numcs = of_property_count_elems_of_size(np, "reg",
+-						reg_cells * sizeof(u32));
+-	if (numcs < 1) {
+-		dev_err(nc->dev, "Missing or invalid reg property\n");
+-		return ERR_PTR(-EINVAL);
+-	}
+-
+-	nand = devm_kzalloc(nc->dev,
+-			    sizeof(*nand) + (numcs * sizeof(*nand->cs)),
+-			    GFP_KERNEL);
+-	if (!nand) {
+-		dev_err(nc->dev, "Failed to allocate NAND object\n");
+-		return ERR_PTR(-ENOMEM);
+-	}
+-
+-	nand->numcs = numcs;
+-
+-	gpio = devm_fwnode_get_index_gpiod_from_child(nc->dev, "det", 0,
+-						      &np->fwnode, GPIOD_IN,
+-						      "nand-det");
+-	if (IS_ERR(gpio) && PTR_ERR(gpio) != -ENOENT) {
+-		dev_err(nc->dev,
+-			"Failed to get detect gpio (err = %ld)\n",
+-			PTR_ERR(gpio));
+-		return ERR_CAST(gpio);
+-	}
+-
+-	if (!IS_ERR(gpio))
+-		nand->cdgpio = gpio;
+-
+-	for (i = 0; i < numcs; i++) {
+-		struct resource res;
+-		u32 val;
+-
+-		ret = of_address_to_resource(np, 0, &res);
+-		if (ret) {
+-			dev_err(nc->dev, "Invalid reg property (err = %d)\n",
+-				ret);
+-			return ERR_PTR(ret);
+-		}
+-
+-		ret = of_property_read_u32_index(np, "reg", i * reg_cells,
+-						 &val);
+-		if (ret) {
+-			dev_err(nc->dev, "Invalid reg property (err = %d)\n",
+-				ret);
+-			return ERR_PTR(ret);
+-		}
+-
+-		nand->cs[i].id = val;
+-
+-		nand->cs[i].io.dma = res.start;
+-		nand->cs[i].io.virt = devm_ioremap_resource(nc->dev, &res);
+-		if (IS_ERR(nand->cs[i].io.virt))
+-			return ERR_CAST(nand->cs[i].io.virt);
+-
+-		if (!of_property_read_u32(np, "atmel,rb", &val)) {
+-			if (val > ATMEL_NFC_MAX_RB_ID)
+-				return ERR_PTR(-EINVAL);
+-
+-			nand->cs[i].rb.type = ATMEL_NAND_NATIVE_RB;
+-			nand->cs[i].rb.id = val;
+-		} else {
+-			gpio = devm_fwnode_get_index_gpiod_from_child(nc->dev,
+-							"rb", i, &np->fwnode,
+-							GPIOD_IN, "nand-rb");
+-			if (IS_ERR(gpio) && PTR_ERR(gpio) != -ENOENT) {
+-				dev_err(nc->dev,
+-					"Failed to get R/B gpio (err = %ld)\n",
+-					PTR_ERR(gpio));
+-				return ERR_CAST(gpio);
+-			}
+-
+-			if (!IS_ERR(gpio)) {
+-				nand->cs[i].rb.type = ATMEL_NAND_GPIO_RB;
+-				nand->cs[i].rb.gpio = gpio;
+-			}
+-		}
+-
+-		gpio = devm_fwnode_get_index_gpiod_from_child(nc->dev, "cs",
+-							      i, &np->fwnode,
+-							      GPIOD_OUT_HIGH,
+-							      "nand-cs");
+-		if (IS_ERR(gpio) && PTR_ERR(gpio) != -ENOENT) {
+-			dev_err(nc->dev,
+-				"Failed to get CS gpio (err = %ld)\n",
+-				PTR_ERR(gpio));
+-			return ERR_CAST(gpio);
+-		}
+-
+-		if (!IS_ERR(gpio))
+-			nand->cs[i].csgpio = gpio;
+-	}
+-
+-	nand_set_flash_node(&nand->base, np);
+-
+-	return nand;
+-}
+-
+-static int
+-atmel_nand_controller_add_nand(struct atmel_nand_controller *nc,
+-			       struct atmel_nand *nand)
+-{
+-	int ret;
+-
+-	/* No card inserted, skip this NAND. */
+-	if (nand->cdgpio && gpiod_get_value(nand->cdgpio)) {
+-		dev_info(nc->dev, "No SmartMedia card inserted.\n");
+-		return 0;
+-	}
+-
+-	nc->caps->ops->nand_init(nc, nand);
+-
+-	ret = atmel_nand_detect(nand);
+-	if (ret)
+-		return ret;
+-
+-	ret = nc->caps->ops->ecc_init(nand);
+-	if (ret)
+-		return ret;
+-
+-	return atmel_nand_register(nand);
+-}
+-
+-static int
+-atmel_nand_controller_remove_nands(struct atmel_nand_controller *nc)
+-{
+-	struct atmel_nand *nand, *tmp;
+-	int ret;
+-
+-	list_for_each_entry_safe(nand, tmp, &nc->chips, node) {
+-		ret = atmel_nand_unregister(nand);
+-		if (ret)
+-			return ret;
+-	}
+-
+-	return 0;
+-}
+-
+-static int
+-atmel_nand_controller_legacy_add_nands(struct atmel_nand_controller *nc)
+-{
+-	struct device *dev = nc->dev;
+-	struct platform_device *pdev = to_platform_device(dev);
+-	struct atmel_nand *nand;
+-	struct gpio_desc *gpio;
+-	struct resource *res;
+-
+-	/*
+-	 * Legacy bindings only allow connecting a single NAND with a unique CS
+-	 * line to the controller.
+-	 */
+-	nand = devm_kzalloc(nc->dev, sizeof(*nand) + sizeof(*nand->cs),
+-			    GFP_KERNEL);
+-	if (!nand)
+-		return -ENOMEM;
+-
+-	nand->numcs = 1;
+-
+-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+-	nand->cs[0].io.virt = devm_ioremap_resource(dev, res);
+-	if (IS_ERR(nand->cs[0].io.virt))
+-		return PTR_ERR(nand->cs[0].io.virt);
+-
+-	nand->cs[0].io.dma = res->start;
+-
+-	/*
+-	 * The old driver was hardcoding the CS id to 3 for all sama5
+-	 * controllers. Since this id is only meaningful for the sama5
+-	 * controller we can safely assign this id to 3 no matter the
+-	 * controller.
+-	 * If one wants to connect a NAND to a different CS line, he will
+-	 * have to use the new bindings.
+-	 */
+-	nand->cs[0].id = 3;
+-
+-	/* R/B GPIO. */
+-	gpio = devm_gpiod_get_index_optional(dev, NULL, 0,  GPIOD_IN);
+-	if (IS_ERR(gpio)) {
+-		dev_err(dev, "Failed to get R/B gpio (err = %ld)\n",
+-			PTR_ERR(gpio));
+-		return PTR_ERR(gpio);
+-	}
+-
+-	if (gpio) {
+-		nand->cs[0].rb.type = ATMEL_NAND_GPIO_RB;
+-		nand->cs[0].rb.gpio = gpio;
+-	}
+-
+-	/* CS GPIO. */
+-	gpio = devm_gpiod_get_index_optional(dev, NULL, 1, GPIOD_OUT_HIGH);
+-	if (IS_ERR(gpio)) {
+-		dev_err(dev, "Failed to get CS gpio (err = %ld)\n",
+-			PTR_ERR(gpio));
+-		return PTR_ERR(gpio);
+-	}
+-
+-	nand->cs[0].csgpio = gpio;
+-
+-	/* Card detect GPIO. */
+-	gpio = devm_gpiod_get_index_optional(nc->dev, NULL, 2, GPIOD_IN);
+-	if (IS_ERR(gpio)) {
+-		dev_err(dev,
+-			"Failed to get detect gpio (err = %ld)\n",
+-			PTR_ERR(gpio));
+-		return PTR_ERR(gpio);
+-	}
+-
+-	nand->cdgpio = gpio;
+-
+-	nand_set_flash_node(&nand->base, nc->dev->of_node);
+-
+-	return atmel_nand_controller_add_nand(nc, nand);
+-}
+-
+-static int atmel_nand_controller_add_nands(struct atmel_nand_controller *nc)
+-{
+-	struct device_node *np, *nand_np;
+-	struct device *dev = nc->dev;
+-	int ret, reg_cells;
+-	u32 val;
+-
+-	/* We do not retrieve the SMC syscon when parsing old DTs. */
+-	if (nc->caps->legacy_of_bindings)
+-		return atmel_nand_controller_legacy_add_nands(nc);
+-
+-	np = dev->of_node;
+-
+-	ret = of_property_read_u32(np, "#address-cells", &val);
+-	if (ret) {
+-		dev_err(dev, "missing #address-cells property\n");
+-		return ret;
+-	}
+-
+-	reg_cells = val;
+-
+-	ret = of_property_read_u32(np, "#size-cells", &val);
+-	if (ret) {
+-		dev_err(dev, "missing #address-cells property\n");
+-		return ret;
+-	}
+-
+-	reg_cells += val;
+-
+-	for_each_child_of_node(np, nand_np) {
+-		struct atmel_nand *nand;
+-
+-		nand = atmel_nand_create(nc, nand_np, reg_cells);
+-		if (IS_ERR(nand)) {
+-			ret = PTR_ERR(nand);
+-			goto err;
+-		}
+-
+-		ret = atmel_nand_controller_add_nand(nc, nand);
+-		if (ret)
+-			goto err;
+-	}
+-
+-	return 0;
+-
+-err:
+-	atmel_nand_controller_remove_nands(nc);
+-
+-	return ret;
+-}
+-
+-static void atmel_nand_controller_cleanup(struct atmel_nand_controller *nc)
+-{
+-	if (nc->dmac)
+-		dma_release_channel(nc->dmac);
+-
+-	clk_put(nc->mck);
+-}
+-
+-static const struct of_device_id atmel_matrix_of_ids[] = {
+-	{
+-		.compatible = "atmel,at91sam9260-matrix",
+-		.data = (void *)AT91SAM9260_MATRIX_EBICSA,
+-	},
+-	{
+-		.compatible = "atmel,at91sam9261-matrix",
+-		.data = (void *)AT91SAM9261_MATRIX_EBICSA,
+-	},
+-	{
+-		.compatible = "atmel,at91sam9263-matrix",
+-		.data = (void *)AT91SAM9263_MATRIX_EBI0CSA,
+-	},
+-	{
+-		.compatible = "atmel,at91sam9rl-matrix",
+-		.data = (void *)AT91SAM9RL_MATRIX_EBICSA,
+-	},
+-	{
+-		.compatible = "atmel,at91sam9g45-matrix",
+-		.data = (void *)AT91SAM9G45_MATRIX_EBICSA,
+-	},
+-	{
+-		.compatible = "atmel,at91sam9n12-matrix",
+-		.data = (void *)AT91SAM9N12_MATRIX_EBICSA,
+-	},
+-	{
+-		.compatible = "atmel,at91sam9x5-matrix",
+-		.data = (void *)AT91SAM9X5_MATRIX_EBICSA,
+-	},
+-	{ /* sentinel */ },
+-};
+-
+-static int atmel_nand_controller_init(struct atmel_nand_controller *nc,
+-				struct platform_device *pdev,
+-				const struct atmel_nand_controller_caps *caps)
+-{
+-	struct device *dev = &pdev->dev;
+-	struct device_node *np = dev->of_node;
+-	int ret;
+-
+-	nand_hw_control_init(&nc->base);
+-	INIT_LIST_HEAD(&nc->chips);
+-	nc->dev = dev;
+-	nc->caps = caps;
+-
+-	platform_set_drvdata(pdev, nc);
+-
+-	nc->pmecc = devm_atmel_pmecc_get(dev);
+-	if (IS_ERR(nc->pmecc)) {
+-		ret = PTR_ERR(nc->pmecc);
+-		if (ret != -EPROBE_DEFER)
+-			dev_err(dev, "Could not get PMECC object (err = %d)\n",
+-				ret);
+-		return ret;
+-	}
+-
+-	if (nc->caps->has_dma) {
+-		dma_cap_mask_t mask;
+-
+-		dma_cap_zero(mask);
+-		dma_cap_set(DMA_MEMCPY, mask);
+-
+-		nc->dmac = dma_request_channel(mask, NULL, NULL);
+-		if (!nc->dmac)
+-			dev_err(nc->dev, "Failed to request DMA channel\n");
+-	}
+-
+-	/* We do not retrieve the SMC syscon when parsing old DTs. */
+-	if (nc->caps->legacy_of_bindings)
+-		return 0;
+-
+-	nc->mck = of_clk_get(dev->parent->of_node, 0);
+-	if (IS_ERR(nc->mck)) {
+-		dev_err(dev, "Failed to retrieve MCK clk\n");
+-		return PTR_ERR(nc->mck);
+-	}
+-
+-	np = of_parse_phandle(dev->parent->of_node, "atmel,smc", 0);
+-	if (!np) {
+-		dev_err(dev, "Missing or invalid atmel,smc property\n");
+-		return -EINVAL;
+-	}
+-
+-	nc->smc = syscon_node_to_regmap(np);
+-	of_node_put(np);
+-	if (IS_ERR(nc->smc)) {
+-		ret = PTR_ERR(nc->smc);
+-		dev_err(dev, "Could not get SMC regmap (err = %d)\n", ret);
+-		return ret;
+-	}
+-
+-	return 0;
+-}
+-
+-static int
+-atmel_smc_nand_controller_init(struct atmel_smc_nand_controller *nc)
+-{
+-	struct device *dev = nc->base.dev;
+-	const struct of_device_id *match;
+-	struct device_node *np;
+-	int ret;
+-
+-	/* We do not retrieve the matrix syscon when parsing old DTs. */
+-	if (nc->base.caps->legacy_of_bindings)
+-		return 0;
+-
+-	np = of_parse_phandle(dev->parent->of_node, "atmel,matrix", 0);
+-	if (!np)
+-		return 0;
+-
+-	match = of_match_node(atmel_matrix_of_ids, np);
+-	if (!match) {
+-		of_node_put(np);
+-		return 0;
+-	}
+-
+-	nc->matrix = syscon_node_to_regmap(np);
+-	of_node_put(np);
+-	if (IS_ERR(nc->matrix)) {
+-		ret = PTR_ERR(nc->matrix);
+-		dev_err(dev, "Could not get Matrix regmap (err = %d)\n", ret);
+-		return ret;
+-	}
+-
+-	nc->ebi_csa_offs = (unsigned int)match->data;
+-
+-	/*
+-	 * The at91sam9263 has 2 EBIs, if the NAND controller is under EBI1
+-	 * add 4 to ->ebi_csa_offs.
+-	 */
+-	if (of_device_is_compatible(dev->parent->of_node,
+-				    "atmel,at91sam9263-ebi1"))
+-		nc->ebi_csa_offs += 4;
+-
+-	return 0;
+-}
+-
+-static int
+-atmel_hsmc_nand_controller_legacy_init(struct atmel_hsmc_nand_controller *nc)
+-{
+-	struct regmap_config regmap_conf = {
+-		.reg_bits = 32,
+-		.val_bits = 32,
+-		.reg_stride = 4,
+-	};
+-
+-	struct device *dev = nc->base.dev;
+-	struct device_node *nand_np, *nfc_np;
+-	void __iomem *iomem;
+-	struct resource res;
+-	int ret;
+-
+-	nand_np = dev->of_node;
+-	nfc_np = of_find_compatible_node(dev->of_node, NULL,
+-					 "atmel,sama5d3-nfc");
+-
+-	nc->clk = of_clk_get(nfc_np, 0);
+-	if (IS_ERR(nc->clk)) {
+-		ret = PTR_ERR(nc->clk);
+-		dev_err(dev, "Failed to retrieve HSMC clock (err = %d)\n",
+-			ret);
+-		goto out;
+-	}
+-
+-	ret = clk_prepare_enable(nc->clk);
+-	if (ret) {
+-		dev_err(dev, "Failed to enable the HSMC clock (err = %d)\n",
+-			ret);
+-		goto out;
+-	}
+-
+-	nc->irq = of_irq_get(nand_np, 0);
+-	if (nc->irq <= 0) {
+-		ret = nc->irq ?: -ENXIO;
+-		if (ret != -EPROBE_DEFER)
+-			dev_err(dev, "Failed to get IRQ number (err = %d)\n",
+-				ret);
+-		goto out;
+-	}
+-
+-	ret = of_address_to_resource(nfc_np, 0, &res);
+-	if (ret) {
+-		dev_err(dev, "Invalid or missing NFC IO resource (err = %d)\n",
+-			ret);
+-		goto out;
+-	}
+-
+-	iomem = devm_ioremap_resource(dev, &res);
+-	if (IS_ERR(iomem)) {
+-		ret = PTR_ERR(iomem);
+-		goto out;
+-	}
+-
+-	regmap_conf.name = "nfc-io";
+-	regmap_conf.max_register = resource_size(&res) - 4;
+-	nc->io = devm_regmap_init_mmio(dev, iomem, &regmap_conf);
+-	if (IS_ERR(nc->io)) {
+-		ret = PTR_ERR(nc->io);
+-		dev_err(dev, "Could not create NFC IO regmap (err = %d)\n",
+-			ret);
+-		goto out;
+-	}
+-
+-	ret = of_address_to_resource(nfc_np, 1, &res);
+-	if (ret) {
+-		dev_err(dev, "Invalid or missing HSMC resource (err = %d)\n",
+-			ret);
+-		goto out;
+-	}
+-
+-	iomem = devm_ioremap_resource(dev, &res);
+-	if (IS_ERR(iomem)) {
+-		ret = PTR_ERR(iomem);
+-		goto out;
+-	}
+-
+-	regmap_conf.name = "smc";
+-	regmap_conf.max_register = resource_size(&res) - 4;
+-	nc->base.smc = devm_regmap_init_mmio(dev, iomem, &regmap_conf);
+-	if (IS_ERR(nc->base.smc)) {
+-		ret = PTR_ERR(nc->base.smc);
+-		dev_err(dev, "Could not create NFC IO regmap (err = %d)\n",
+-			ret);
+-		goto out;
+-	}
+-
+-	ret = of_address_to_resource(nfc_np, 2, &res);
+-	if (ret) {
+-		dev_err(dev, "Invalid or missing SRAM resource (err = %d)\n",
+-			ret);
+-		goto out;
+-	}
+-
+-	nc->sram.virt = devm_ioremap_resource(dev, &res);
+-	if (IS_ERR(nc->sram.virt)) {
+-		ret = PTR_ERR(nc->sram.virt);
+-		goto out;
+-	}
+-
+-	nc->sram.dma = res.start;
+-
+-out:
+-	of_node_put(nfc_np);
+-
+-	return ret;
+-}
+-
+-static int
+-atmel_hsmc_nand_controller_init(struct atmel_hsmc_nand_controller *nc)
+-{
+-	struct device *dev = nc->base.dev;
+-	struct device_node *np;
+-	int ret;
+-
+-	np = of_parse_phandle(dev->parent->of_node, "atmel,smc", 0);
+-	if (!np) {
+-		dev_err(dev, "Missing or invalid atmel,smc property\n");
+-		return -EINVAL;
+-	}
+-
+-	nc->hsmc_layout = atmel_hsmc_get_reg_layout(np);
+-
+-	nc->irq = of_irq_get(np, 0);
+-	of_node_put(np);
+-	if (nc->irq <= 0) {
+-		ret = nc->irq ?: -ENXIO;
+-		if (ret != -EPROBE_DEFER)
+-			dev_err(dev, "Failed to get IRQ number (err = %d)\n",
+-				ret);
+-		return ret;
+-	}
+-
+-	np = of_parse_phandle(dev->of_node, "atmel,nfc-io", 0);
+-	if (!np) {
+-		dev_err(dev, "Missing or invalid atmel,nfc-io property\n");
+-		return -EINVAL;
+-	}
+-
+-	nc->io = syscon_node_to_regmap(np);
+-	of_node_put(np);
+-	if (IS_ERR(nc->io)) {
+-		ret = PTR_ERR(nc->io);
+-		dev_err(dev, "Could not get NFC IO regmap (err = %d)\n", ret);
+-		return ret;
+-	}
+-
+-	nc->sram.pool = of_gen_pool_get(nc->base.dev->of_node,
+-					 "atmel,nfc-sram", 0);
+-	if (!nc->sram.pool) {
+-		dev_err(nc->base.dev, "Missing SRAM\n");
+-		return -ENOMEM;
+-	}
+-
+-	nc->sram.virt = gen_pool_dma_alloc(nc->sram.pool,
+-					    ATMEL_NFC_SRAM_SIZE,
+-					    &nc->sram.dma);
+-	if (!nc->sram.virt) {
+-		dev_err(nc->base.dev,
+-			"Could not allocate memory from the NFC SRAM pool\n");
+-		return -ENOMEM;
+-	}
+-
+-	return 0;
+-}
+-
+-static int
+-atmel_hsmc_nand_controller_remove(struct atmel_nand_controller *nc)
+-{
+-	struct atmel_hsmc_nand_controller *hsmc_nc;
+-	int ret;
+-
+-	ret = atmel_nand_controller_remove_nands(nc);
+-	if (ret)
+-		return ret;
+-
+-	hsmc_nc = container_of(nc, struct atmel_hsmc_nand_controller, base);
+-	if (hsmc_nc->sram.pool)
+-		gen_pool_free(hsmc_nc->sram.pool,
+-			      (unsigned long)hsmc_nc->sram.virt,
+-			      ATMEL_NFC_SRAM_SIZE);
+-
+-	if (hsmc_nc->clk) {
+-		clk_disable_unprepare(hsmc_nc->clk);
+-		clk_put(hsmc_nc->clk);
+-	}
+-
+-	atmel_nand_controller_cleanup(nc);
+-
+-	return 0;
+-}
+-
+-static int atmel_hsmc_nand_controller_probe(struct platform_device *pdev,
+-				const struct atmel_nand_controller_caps *caps)
+-{
+-	struct device *dev = &pdev->dev;
+-	struct atmel_hsmc_nand_controller *nc;
+-	int ret;
+-
+-	nc = devm_kzalloc(dev, sizeof(*nc), GFP_KERNEL);
+-	if (!nc)
+-		return -ENOMEM;
+-
+-	ret = atmel_nand_controller_init(&nc->base, pdev, caps);
+-	if (ret)
+-		return ret;
+-
+-	if (caps->legacy_of_bindings)
+-		ret = atmel_hsmc_nand_controller_legacy_init(nc);
+-	else
+-		ret = atmel_hsmc_nand_controller_init(nc);
+-
+-	if (ret)
+-		return ret;
+-
+-	/* Make sure all irqs are masked before registering our IRQ handler. */
+-	regmap_write(nc->base.smc, ATMEL_HSMC_NFC_IDR, 0xffffffff);
+-	ret = devm_request_irq(dev, nc->irq, atmel_nfc_interrupt,
+-			       IRQF_SHARED, "nfc", nc);
+-	if (ret) {
+-		dev_err(dev,
+-			"Could not get register NFC interrupt handler (err = %d)\n",
+-			ret);
+-		goto err;
+-	}
+-
+-	/* Initial NFC configuration. */
+-	regmap_write(nc->base.smc, ATMEL_HSMC_NFC_CFG,
+-		     ATMEL_HSMC_NFC_CFG_DTO_MAX);
+-
+-	ret = atmel_nand_controller_add_nands(&nc->base);
+-	if (ret)
+-		goto err;
+-
+-	return 0;
+-
+-err:
+-	atmel_hsmc_nand_controller_remove(&nc->base);
+-
+-	return ret;
+-}
+-
+-static const struct atmel_nand_controller_ops atmel_hsmc_nc_ops = {
+-	.probe = atmel_hsmc_nand_controller_probe,
+-	.remove = atmel_hsmc_nand_controller_remove,
+-	.ecc_init = atmel_hsmc_nand_ecc_init,
+-	.nand_init = atmel_hsmc_nand_init,
+-	.setup_data_interface = atmel_hsmc_nand_setup_data_interface,
+-};
+-
+-static const struct atmel_nand_controller_caps atmel_sama5_nc_caps = {
+-	.has_dma = true,
+-	.ale_offs = BIT(21),
+-	.cle_offs = BIT(22),
+-	.ops = &atmel_hsmc_nc_ops,
+-};
+-
+-/* Only used to parse old bindings. */
+-static const struct atmel_nand_controller_caps atmel_sama5_nand_caps = {
+-	.has_dma = true,
+-	.ale_offs = BIT(21),
+-	.cle_offs = BIT(22),
+-	.ops = &atmel_hsmc_nc_ops,
+-	.legacy_of_bindings = true,
+-};
+-
+-static int atmel_smc_nand_controller_probe(struct platform_device *pdev,
+-				const struct atmel_nand_controller_caps *caps)
+-{
+-	struct device *dev = &pdev->dev;
+-	struct atmel_smc_nand_controller *nc;
+-	int ret;
+-
+-	nc = devm_kzalloc(dev, sizeof(*nc), GFP_KERNEL);
+-	if (!nc)
+-		return -ENOMEM;
+-
+-	ret = atmel_nand_controller_init(&nc->base, pdev, caps);
+-	if (ret)
+-		return ret;
+-
+-	ret = atmel_smc_nand_controller_init(nc);
+-	if (ret)
+-		return ret;
+-
+-	return atmel_nand_controller_add_nands(&nc->base);
+-}
+-
+-static int
+-atmel_smc_nand_controller_remove(struct atmel_nand_controller *nc)
+-{
+-	int ret;
+-
+-	ret = atmel_nand_controller_remove_nands(nc);
+-	if (ret)
+-		return ret;
+-
+-	atmel_nand_controller_cleanup(nc);
+-
+-	return 0;
+-}
+-
+-/*
+- * The SMC reg layout of at91rm9200 is completely different which prevents us
+- * from re-using atmel_smc_nand_setup_data_interface() for the
+- * ->setup_data_interface() hook.
+- * At this point, there's no support for the at91rm9200 SMC IP, so we leave
+- * ->setup_data_interface() unassigned.
+- */
+-static const struct atmel_nand_controller_ops at91rm9200_nc_ops = {
+-	.probe = atmel_smc_nand_controller_probe,
+-	.remove = atmel_smc_nand_controller_remove,
+-	.ecc_init = atmel_nand_ecc_init,
+-	.nand_init = atmel_smc_nand_init,
+-};
+-
+-static const struct atmel_nand_controller_caps atmel_rm9200_nc_caps = {
+-	.ale_offs = BIT(21),
+-	.cle_offs = BIT(22),
+-	.ops = &at91rm9200_nc_ops,
+-};
+-
+-static const struct atmel_nand_controller_ops atmel_smc_nc_ops = {
+-	.probe = atmel_smc_nand_controller_probe,
+-	.remove = atmel_smc_nand_controller_remove,
+-	.ecc_init = atmel_nand_ecc_init,
+-	.nand_init = atmel_smc_nand_init,
+-	.setup_data_interface = atmel_smc_nand_setup_data_interface,
+-};
+-
+-static const struct atmel_nand_controller_caps atmel_sam9260_nc_caps = {
+-	.ale_offs = BIT(21),
+-	.cle_offs = BIT(22),
+-	.ops = &atmel_smc_nc_ops,
+-};
+-
+-static const struct atmel_nand_controller_caps atmel_sam9261_nc_caps = {
+-	.ale_offs = BIT(22),
+-	.cle_offs = BIT(21),
+-	.ops = &atmel_smc_nc_ops,
+-};
+-
+-static const struct atmel_nand_controller_caps atmel_sam9g45_nc_caps = {
+-	.has_dma = true,
+-	.ale_offs = BIT(21),
+-	.cle_offs = BIT(22),
+-	.ops = &atmel_smc_nc_ops,
+-};
+-
+-/* Only used to parse old bindings. */
+-static const struct atmel_nand_controller_caps atmel_rm9200_nand_caps = {
+-	.ale_offs = BIT(21),
+-	.cle_offs = BIT(22),
+-	.ops = &atmel_smc_nc_ops,
+-	.legacy_of_bindings = true,
+-};
+-
+-static const struct atmel_nand_controller_caps atmel_sam9261_nand_caps = {
+-	.ale_offs = BIT(22),
+-	.cle_offs = BIT(21),
+-	.ops = &atmel_smc_nc_ops,
+-	.legacy_of_bindings = true,
+-};
+-
+-static const struct atmel_nand_controller_caps atmel_sam9g45_nand_caps = {
+-	.has_dma = true,
+-	.ale_offs = BIT(21),
+-	.cle_offs = BIT(22),
+-	.ops = &atmel_smc_nc_ops,
+-	.legacy_of_bindings = true,
+-};
+-
+-static const struct of_device_id atmel_nand_controller_of_ids[] = {
+-	{
+-		.compatible = "atmel,at91rm9200-nand-controller",
+-		.data = &atmel_rm9200_nc_caps,
+-	},
+-	{
+-		.compatible = "atmel,at91sam9260-nand-controller",
+-		.data = &atmel_sam9260_nc_caps,
+-	},
+-	{
+-		.compatible = "atmel,at91sam9261-nand-controller",
+-		.data = &atmel_sam9261_nc_caps,
+-	},
+-	{
+-		.compatible = "atmel,at91sam9g45-nand-controller",
+-		.data = &atmel_sam9g45_nc_caps,
+-	},
+-	{
+-		.compatible = "atmel,sama5d3-nand-controller",
+-		.data = &atmel_sama5_nc_caps,
+-	},
+-	/* Support for old/deprecated bindings: */
+-	{
+-		.compatible = "atmel,at91rm9200-nand",
+-		.data = &atmel_rm9200_nand_caps,
+-	},
+-	{
+-		.compatible = "atmel,sama5d4-nand",
+-		.data = &atmel_rm9200_nand_caps,
+-	},
+-	{
+-		.compatible = "atmel,sama5d2-nand",
+-		.data = &atmel_rm9200_nand_caps,
+-	},
+-	{ /* sentinel */ },
+-};
+-MODULE_DEVICE_TABLE(of, atmel_nand_controller_of_ids);
+-
+-static int atmel_nand_controller_probe(struct platform_device *pdev)
+-{
+-	const struct atmel_nand_controller_caps *caps;
+-
+-	if (pdev->id_entry)
+-		caps = (void *)pdev->id_entry->driver_data;
+-	else
+-		caps = of_device_get_match_data(&pdev->dev);
+-
+-	if (!caps) {
+-		dev_err(&pdev->dev, "Could not retrieve NFC caps\n");
+-		return -EINVAL;
+-	}
+-
+-	if (caps->legacy_of_bindings) {
+-		u32 ale_offs = 21;
+-
+-		/*
+-		 * If we are parsing legacy DT props and the DT contains a
+-		 * valid NFC node, forward the request to the sama5 logic.
+-		 */
+-		if (of_find_compatible_node(pdev->dev.of_node, NULL,
+-					    "atmel,sama5d3-nfc"))
+-			caps = &atmel_sama5_nand_caps;
+-
+-		/*
+-		 * Even if the compatible says we are dealing with an
+-		 * at91rm9200 controller, the atmel,nand-has-dma specify that
+-		 * this controller supports DMA, which means we are in fact
+-		 * dealing with an at91sam9g45+ controller.
+-		 */
+-		if (!caps->has_dma &&
+-		    of_property_read_bool(pdev->dev.of_node,
+-					  "atmel,nand-has-dma"))
+-			caps = &atmel_sam9g45_nand_caps;
+-
+-		/*
+-		 * All SoCs except the at91sam9261 are assigning ALE to A21 and
+-		 * CLE to A22. If atmel,nand-addr-offset != 21 this means we're
+-		 * actually dealing with an at91sam9261 controller.
+-		 */
+-		of_property_read_u32(pdev->dev.of_node,
+-				     "atmel,nand-addr-offset", &ale_offs);
+-		if (ale_offs != 21)
+-			caps = &atmel_sam9261_nand_caps;
+-	}
+-
+-	return caps->ops->probe(pdev, caps);
+-}
+-
+-static int atmel_nand_controller_remove(struct platform_device *pdev)
+-{
+-	struct atmel_nand_controller *nc = platform_get_drvdata(pdev);
+-
+-	return nc->caps->ops->remove(nc);
+-}
+-
+-static __maybe_unused int atmel_nand_controller_resume(struct device *dev)
+-{
+-	struct atmel_nand_controller *nc = dev_get_drvdata(dev);
+-	struct atmel_nand *nand;
+-
+-	list_for_each_entry(nand, &nc->chips, node) {
+-		int i;
+-
+-		for (i = 0; i < nand->numcs; i++)
+-			nand_reset(&nand->base, i);
+-	}
+-
+-	return 0;
+-}
+-
+-static SIMPLE_DEV_PM_OPS(atmel_nand_controller_pm_ops, NULL,
+-			 atmel_nand_controller_resume);
+-
+-static struct platform_driver atmel_nand_controller_driver = {
+-	.driver = {
+-		.name = "atmel-nand-controller",
+-		.of_match_table = of_match_ptr(atmel_nand_controller_of_ids),
+-		.pm = &atmel_nand_controller_pm_ops,
+-	},
+-	.probe = atmel_nand_controller_probe,
+-	.remove = atmel_nand_controller_remove,
+-};
+-module_platform_driver(atmel_nand_controller_driver);
+-
+-MODULE_LICENSE("GPL");
+-MODULE_AUTHOR("Boris Brezillon <boris.brezillon@free-electrons.com>");
+-MODULE_DESCRIPTION("NAND Flash Controller driver for Atmel SoCs");
+-MODULE_ALIAS("platform:atmel-nand-controller");
+diff --git a/drivers/mtd/nand/atmel/pmecc.c b/drivers/mtd/nand/atmel/pmecc.c
+deleted file mode 100644
+index 8268636..0000000
+--- a/drivers/mtd/nand/atmel/pmecc.c
++++ /dev/null
+@@ -1,1011 +0,0 @@
+-/*
+- * Copyright 2017 ATMEL
+- * Copyright 2017 Free Electrons
+- *
+- * Author: Boris Brezillon <boris.brezillon@free-electrons.com>
+- *
+- * Derived from the atmel_nand.c driver which contained the following
+- * copyrights:
+- *
+- *   Copyright 2003 Rick Bronson
+- *
+- *   Derived from drivers/mtd/nand/autcpu12.c
+- *	Copyright 2001 Thomas Gleixner (gleixner@autronix.de)
+- *
+- *   Derived from drivers/mtd/spia.c
+- *	Copyright 2000 Steven J. Hill (sjhill@cotw.com)
+- *
+- *   Add Hardware ECC support for AT91SAM9260 / AT91SAM9263
+- *	Richard Genoud (richard.genoud@gmail.com), Adeneo Copyright 2007
+- *
+- *   Derived from Das U-Boot source code
+- *	(u-boot-1.1.5/board/atmel/at91sam9263ek/nand.c)
+- *      Copyright 2006 ATMEL Rousset, Lacressonniere Nicolas
+- *
+- *   Add Programmable Multibit ECC support for various AT91 SoC
+- *	Copyright 2012 ATMEL, Hong Xu
+- *
+- *   Add Nand Flash Controller support for SAMA5 SoC
+- *	Copyright 2013 ATMEL, Josh Wu (josh.wu@atmel.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.
+- *
+- * The PMECC is an hardware assisted BCH engine, which means part of the
+- * ECC algorithm is left to the software. The hardware/software repartition
+- * is explained in the "PMECC Controller Functional Description" chapter in
+- * Atmel datasheets, and some of the functions in this file are directly
+- * implementing the algorithms described in the "Software Implementation"
+- * sub-section.
+- *
+- * TODO: it seems that the software BCH implementation in lib/bch.c is already
+- * providing some of the logic we are implementing here. It would be smart
+- * to expose the needed lib/bch.c helpers/functions and re-use them here.
+- */
+-
+-#include <linux/genalloc.h>
+-#include <linux/iopoll.h>
+-#include <linux/module.h>
+-#include <linux/mtd/rawnand.h>
+-#include <linux/of_irq.h>
+-#include <linux/of_platform.h>
+-#include <linux/platform_device.h>
+-#include <linux/slab.h>
+-
+-#include "pmecc.h"
+-
+-/* Galois field dimension */
+-#define PMECC_GF_DIMENSION_13			13
+-#define PMECC_GF_DIMENSION_14			14
+-
+-/* Primitive Polynomial used by PMECC */
+-#define PMECC_GF_13_PRIMITIVE_POLY		0x201b
+-#define PMECC_GF_14_PRIMITIVE_POLY		0x4443
+-
+-#define PMECC_LOOKUP_TABLE_SIZE_512		0x2000
+-#define PMECC_LOOKUP_TABLE_SIZE_1024		0x4000
+-
+-/* Time out value for reading PMECC status register */
+-#define PMECC_MAX_TIMEOUT_MS			100
+-
+-/* PMECC Register Definitions */
+-#define ATMEL_PMECC_CFG				0x0
+-#define PMECC_CFG_BCH_STRENGTH(x)		(x)
+-#define PMECC_CFG_BCH_STRENGTH_MASK		GENMASK(2, 0)
+-#define PMECC_CFG_SECTOR512			(0 << 4)
+-#define PMECC_CFG_SECTOR1024			(1 << 4)
+-#define PMECC_CFG_NSECTORS(x)			((fls(x) - 1) << 8)
+-#define PMECC_CFG_READ_OP			(0 << 12)
+-#define PMECC_CFG_WRITE_OP			(1 << 12)
+-#define PMECC_CFG_SPARE_ENABLE			BIT(16)
+-#define PMECC_CFG_AUTO_ENABLE			BIT(20)
+-
+-#define ATMEL_PMECC_SAREA			0x4
+-#define ATMEL_PMECC_SADDR			0x8
+-#define ATMEL_PMECC_EADDR			0xc
+-
+-#define ATMEL_PMECC_CLK				0x10
+-#define PMECC_CLK_133MHZ			(2 << 0)
+-
+-#define ATMEL_PMECC_CTRL			0x14
+-#define PMECC_CTRL_RST				BIT(0)
+-#define PMECC_CTRL_DATA				BIT(1)
+-#define PMECC_CTRL_USER				BIT(2)
+-#define PMECC_CTRL_ENABLE			BIT(4)
+-#define PMECC_CTRL_DISABLE			BIT(5)
+-
+-#define ATMEL_PMECC_SR				0x18
+-#define PMECC_SR_BUSY				BIT(0)
+-#define PMECC_SR_ENABLE				BIT(4)
+-
+-#define ATMEL_PMECC_IER				0x1c
+-#define ATMEL_PMECC_IDR				0x20
+-#define ATMEL_PMECC_IMR				0x24
+-#define ATMEL_PMECC_ISR				0x28
+-#define PMECC_ERROR_INT				BIT(0)
+-
+-#define ATMEL_PMECC_ECC(sector, n)		\
+-	((((sector) + 1) * 0x40) + (n))
+-
+-#define ATMEL_PMECC_REM(sector, n)		\
+-	((((sector) + 1) * 0x40) + ((n) * 4) + 0x200)
+-
+-/* PMERRLOC Register Definitions */
+-#define ATMEL_PMERRLOC_ELCFG			0x0
+-#define PMERRLOC_ELCFG_SECTOR_512		(0 << 0)
+-#define PMERRLOC_ELCFG_SECTOR_1024		(1 << 0)
+-#define PMERRLOC_ELCFG_NUM_ERRORS(n)		((n) << 16)
+-
+-#define ATMEL_PMERRLOC_ELPRIM			0x4
+-#define ATMEL_PMERRLOC_ELEN			0x8
+-#define ATMEL_PMERRLOC_ELDIS			0xc
+-#define PMERRLOC_DISABLE			BIT(0)
+-
+-#define ATMEL_PMERRLOC_ELSR			0x10
+-#define PMERRLOC_ELSR_BUSY			BIT(0)
+-
+-#define ATMEL_PMERRLOC_ELIER			0x14
+-#define ATMEL_PMERRLOC_ELIDR			0x18
+-#define ATMEL_PMERRLOC_ELIMR			0x1c
+-#define ATMEL_PMERRLOC_ELISR			0x20
+-#define PMERRLOC_ERR_NUM_MASK			GENMASK(12, 8)
+-#define PMERRLOC_CALC_DONE			BIT(0)
+-
+-#define ATMEL_PMERRLOC_SIGMA(x)			(((x) * 0x4) + 0x28)
+-
+-#define ATMEL_PMERRLOC_EL(offs, x)		(((x) * 0x4) + (offs))
+-
+-struct atmel_pmecc_gf_tables {
+-	u16 *alpha_to;
+-	u16 *index_of;
+-};
+-
+-struct atmel_pmecc_caps {
+-	const int *strengths;
+-	int nstrengths;
+-	int el_offset;
+-	bool correct_erased_chunks;
+-};
+-
+-struct atmel_pmecc {
+-	struct device *dev;
+-	const struct atmel_pmecc_caps *caps;
+-
+-	struct {
+-		void __iomem *base;
+-		void __iomem *errloc;
+-	} regs;
+-
+-	struct mutex lock;
+-};
+-
+-struct atmel_pmecc_user_conf_cache {
+-	u32 cfg;
+-	u32 sarea;
+-	u32 saddr;
+-	u32 eaddr;
+-};
+-
+-struct atmel_pmecc_user {
+-	struct atmel_pmecc_user_conf_cache cache;
+-	struct atmel_pmecc *pmecc;
+-	const struct atmel_pmecc_gf_tables *gf_tables;
+-	int eccbytes;
+-	s16 *partial_syn;
+-	s16 *si;
+-	s16 *lmu;
+-	s16 *smu;
+-	s32 *mu;
+-	s32 *dmu;
+-	s32 *delta;
+-	u32 isr;
+-};
+-
+-static DEFINE_MUTEX(pmecc_gf_tables_lock);
+-static const struct atmel_pmecc_gf_tables *pmecc_gf_tables_512;
+-static const struct atmel_pmecc_gf_tables *pmecc_gf_tables_1024;
+-
+-static inline int deg(unsigned int poly)
+-{
+-	/* polynomial degree is the most-significant bit index */
+-	return fls(poly) - 1;
+-}
+-
+-static int atmel_pmecc_build_gf_tables(int mm, unsigned int poly,
+-				       struct atmel_pmecc_gf_tables *gf_tables)
+-{
+-	unsigned int i, x = 1;
+-	const unsigned int k = BIT(deg(poly));
+-	unsigned int nn = BIT(mm) - 1;
+-
+-	/* primitive polynomial must be of degree m */
+-	if (k != (1u << mm))
+-		return -EINVAL;
+-
+-	for (i = 0; i < nn; i++) {
+-		gf_tables->alpha_to[i] = x;
+-		gf_tables->index_of[x] = i;
+-		if (i && (x == 1))
+-			/* polynomial is not primitive (a^i=1 with 0<i<2^m-1) */
+-			return -EINVAL;
+-		x <<= 1;
+-		if (x & k)
+-			x ^= poly;
+-	}
+-	gf_tables->alpha_to[nn] = 1;
+-	gf_tables->index_of[0] = 0;
+-
+-	return 0;
+-}
+-
+-static const struct atmel_pmecc_gf_tables *
+-atmel_pmecc_create_gf_tables(const struct atmel_pmecc_user_req *req)
+-{
+-	struct atmel_pmecc_gf_tables *gf_tables;
+-	unsigned int poly, degree, table_size;
+-	int ret;
+-
+-	if (req->ecc.sectorsize == 512) {
+-		degree = PMECC_GF_DIMENSION_13;
+-		poly = PMECC_GF_13_PRIMITIVE_POLY;
+-		table_size = PMECC_LOOKUP_TABLE_SIZE_512;
+-	} else {
+-		degree = PMECC_GF_DIMENSION_14;
+-		poly = PMECC_GF_14_PRIMITIVE_POLY;
+-		table_size = PMECC_LOOKUP_TABLE_SIZE_1024;
+-	}
+-
+-	gf_tables = kzalloc(sizeof(*gf_tables) +
+-			    (2 * table_size * sizeof(u16)),
+-			    GFP_KERNEL);
+-	if (!gf_tables)
+-		return ERR_PTR(-ENOMEM);
+-
+-	gf_tables->alpha_to = (void *)(gf_tables + 1);
+-	gf_tables->index_of = gf_tables->alpha_to + table_size;
+-
+-	ret = atmel_pmecc_build_gf_tables(degree, poly, gf_tables);
+-	if (ret) {
+-		kfree(gf_tables);
+-		return ERR_PTR(ret);
+-	}
+-
+-	return gf_tables;
+-}
+-
+-static const struct atmel_pmecc_gf_tables *
+-atmel_pmecc_get_gf_tables(const struct atmel_pmecc_user_req *req)
+-{
+-	const struct atmel_pmecc_gf_tables **gf_tables, *ret;
+-
+-	mutex_lock(&pmecc_gf_tables_lock);
+-	if (req->ecc.sectorsize == 512)
+-		gf_tables = &pmecc_gf_tables_512;
+-	else
+-		gf_tables = &pmecc_gf_tables_1024;
+-
+-	ret = *gf_tables;
+-
+-	if (!ret) {
+-		ret = atmel_pmecc_create_gf_tables(req);
+-		if (!IS_ERR(ret))
+-			*gf_tables = ret;
+-	}
+-	mutex_unlock(&pmecc_gf_tables_lock);
+-
+-	return ret;
+-}
+-
+-static int atmel_pmecc_prepare_user_req(struct atmel_pmecc *pmecc,
+-					struct atmel_pmecc_user_req *req)
+-{
+-	int i, max_eccbytes, eccbytes = 0, eccstrength = 0;
+-
+-	if (req->pagesize <= 0 || req->oobsize <= 0 || req->ecc.bytes <= 0)
+-		return -EINVAL;
+-
+-	if (req->ecc.ooboffset >= 0 &&
+-	    req->ecc.ooboffset + req->ecc.bytes > req->oobsize)
+-		return -EINVAL;
+-
+-	if (req->ecc.sectorsize == ATMEL_PMECC_SECTOR_SIZE_AUTO) {
+-		if (req->ecc.strength != ATMEL_PMECC_MAXIMIZE_ECC_STRENGTH)
+-			return -EINVAL;
+-
+-		if (req->pagesize > 512)
+-			req->ecc.sectorsize = 1024;
+-		else
+-			req->ecc.sectorsize = 512;
+-	}
+-
+-	if (req->ecc.sectorsize != 512 && req->ecc.sectorsize != 1024)
+-		return -EINVAL;
+-
+-	if (req->pagesize % req->ecc.sectorsize)
+-		return -EINVAL;
+-
+-	req->ecc.nsectors = req->pagesize / req->ecc.sectorsize;
+-
+-	max_eccbytes = req->ecc.bytes;
+-
+-	for (i = 0; i < pmecc->caps->nstrengths; i++) {
+-		int nbytes, strength = pmecc->caps->strengths[i];
+-
+-		if (req->ecc.strength != ATMEL_PMECC_MAXIMIZE_ECC_STRENGTH &&
+-		    strength < req->ecc.strength)
+-			continue;
+-
+-		nbytes = DIV_ROUND_UP(strength * fls(8 * req->ecc.sectorsize),
+-				      8);
+-		nbytes *= req->ecc.nsectors;
+-
+-		if (nbytes > max_eccbytes)
+-			break;
+-
+-		eccstrength = strength;
+-		eccbytes = nbytes;
+-
+-		if (req->ecc.strength != ATMEL_PMECC_MAXIMIZE_ECC_STRENGTH)
+-			break;
+-	}
+-
+-	if (!eccstrength)
+-		return -EINVAL;
+-
+-	req->ecc.bytes = eccbytes;
+-	req->ecc.strength = eccstrength;
+-
+-	if (req->ecc.ooboffset < 0)
+-		req->ecc.ooboffset = req->oobsize - eccbytes;
+-
+-	return 0;
+-}
+-
+-struct atmel_pmecc_user *
+-atmel_pmecc_create_user(struct atmel_pmecc *pmecc,
+-			struct atmel_pmecc_user_req *req)
+-{
+-	struct atmel_pmecc_user *user;
+-	const struct atmel_pmecc_gf_tables *gf_tables;
+-	int strength, size, ret;
+-
+-	ret = atmel_pmecc_prepare_user_req(pmecc, req);
+-	if (ret)
+-		return ERR_PTR(ret);
+-
+-	size = sizeof(*user);
+-	size = ALIGN(size, sizeof(u16));
+-	/* Reserve space for partial_syn, si and smu */
+-	size += ((2 * req->ecc.strength) + 1) * sizeof(u16) *
+-		(2 + req->ecc.strength + 2);
+-	/* Reserve space for lmu. */
+-	size += (req->ecc.strength + 1) * sizeof(u16);
+-	/* Reserve space for mu, dmu and delta. */
+-	size = ALIGN(size, sizeof(s32));
+-	size += (req->ecc.strength + 1) * sizeof(s32) * 3;
+-
+-	user = kzalloc(size, GFP_KERNEL);
+-	if (!user)
+-		return ERR_PTR(-ENOMEM);
+-
+-	user->pmecc = pmecc;
+-
+-	user->partial_syn = (s16 *)PTR_ALIGN(user + 1, sizeof(u16));
+-	user->si = user->partial_syn + ((2 * req->ecc.strength) + 1);
+-	user->lmu = user->si + ((2 * req->ecc.strength) + 1);
+-	user->smu = user->lmu + (req->ecc.strength + 1);
+-	user->mu = (s32 *)PTR_ALIGN(user->smu +
+-				    (((2 * req->ecc.strength) + 1) *
+-				     (req->ecc.strength + 2)),
+-				    sizeof(s32));
+-	user->dmu = user->mu + req->ecc.strength + 1;
+-	user->delta = user->dmu + req->ecc.strength + 1;
+-
+-	gf_tables = atmel_pmecc_get_gf_tables(req);
+-	if (IS_ERR(gf_tables)) {
+-		kfree(user);
+-		return ERR_CAST(gf_tables);
+-	}
+-
+-	user->gf_tables = gf_tables;
+-
+-	user->eccbytes = req->ecc.bytes / req->ecc.nsectors;
+-
+-	for (strength = 0; strength < pmecc->caps->nstrengths; strength++) {
+-		if (pmecc->caps->strengths[strength] == req->ecc.strength)
+-			break;
+-	}
+-
+-	user->cache.cfg = PMECC_CFG_BCH_STRENGTH(strength) |
+-			  PMECC_CFG_NSECTORS(req->ecc.nsectors);
+-
+-	if (req->ecc.sectorsize == 1024)
+-		user->cache.cfg |= PMECC_CFG_SECTOR1024;
+-
+-	user->cache.sarea = req->oobsize - 1;
+-	user->cache.saddr = req->ecc.ooboffset;
+-	user->cache.eaddr = req->ecc.ooboffset + req->ecc.bytes - 1;
+-
+-	return user;
+-}
+-EXPORT_SYMBOL_GPL(atmel_pmecc_create_user);
+-
+-void atmel_pmecc_destroy_user(struct atmel_pmecc_user *user)
+-{
+-	kfree(user);
+-}
+-EXPORT_SYMBOL_GPL(atmel_pmecc_destroy_user);
+-
+-static int get_strength(struct atmel_pmecc_user *user)
+-{
+-	const int *strengths = user->pmecc->caps->strengths;
+-
+-	return strengths[user->cache.cfg & PMECC_CFG_BCH_STRENGTH_MASK];
+-}
+-
+-static int get_sectorsize(struct atmel_pmecc_user *user)
+-{
+-	return user->cache.cfg & PMECC_LOOKUP_TABLE_SIZE_1024 ? 1024 : 512;
+-}
+-
+-static void atmel_pmecc_gen_syndrome(struct atmel_pmecc_user *user, int sector)
+-{
+-	int strength = get_strength(user);
+-	u32 value;
+-	int i;
+-
+-	/* Fill odd syndromes */
+-	for (i = 0; i < strength; i++) {
+-		value = readl_relaxed(user->pmecc->regs.base +
+-				      ATMEL_PMECC_REM(sector, i / 2));
+-		if (i & 1)
+-			value >>= 16;
+-
+-		user->partial_syn[(2 * i) + 1] = value;
+-	}
+-}
+-
+-static void atmel_pmecc_substitute(struct atmel_pmecc_user *user)
+-{
+-	int degree = get_sectorsize(user) == 512 ? 13 : 14;
+-	int cw_len = BIT(degree) - 1;
+-	int strength = get_strength(user);
+-	s16 *alpha_to = user->gf_tables->alpha_to;
+-	s16 *index_of = user->gf_tables->index_of;
+-	s16 *partial_syn = user->partial_syn;
+-	s16 *si;
+-	int i, j;
+-
+-	/*
+-	 * si[] is a table that holds the current syndrome value,
+-	 * an element of that table belongs to the field
+-	 */
+-	si = user->si;
+-
+-	memset(&si[1], 0, sizeof(s16) * ((2 * strength) - 1));
+-
+-	/* Computation 2t syndromes based on S(x) */
+-	/* Odd syndromes */
+-	for (i = 1; i < 2 * strength; i += 2) {
+-		for (j = 0; j < degree; j++) {
+-			if (partial_syn[i] & BIT(j))
+-				si[i] = alpha_to[i * j] ^ si[i];
+-		}
+-	}
+-	/* Even syndrome = (Odd syndrome) ** 2 */
+-	for (i = 2, j = 1; j <= strength; i = ++j << 1) {
+-		if (si[j] == 0) {
+-			si[i] = 0;
+-		} else {
+-			s16 tmp;
+-
+-			tmp = index_of[si[j]];
+-			tmp = (tmp * 2) % cw_len;
+-			si[i] = alpha_to[tmp];
+-		}
+-	}
+-}
+-
+-static void atmel_pmecc_get_sigma(struct atmel_pmecc_user *user)
+-{
+-	s16 *lmu = user->lmu;
+-	s16 *si = user->si;
+-	s32 *mu = user->mu;
+-	s32 *dmu = user->dmu;
+-	s32 *delta = user->delta;
+-	int degree = get_sectorsize(user) == 512 ? 13 : 14;
+-	int cw_len = BIT(degree) - 1;
+-	int strength = get_strength(user);
+-	int num = 2 * strength + 1;
+-	s16 *index_of = user->gf_tables->index_of;
+-	s16 *alpha_to = user->gf_tables->alpha_to;
+-	int i, j, k;
+-	u32 dmu_0_count, tmp;
+-	s16 *smu = user->smu;
+-
+-	/* index of largest delta */
+-	int ro;
+-	int largest;
+-	int diff;
+-
+-	dmu_0_count = 0;
+-
+-	/* First Row */
+-
+-	/* Mu */
+-	mu[0] = -1;
+-
+-	memset(smu, 0, sizeof(s16) * num);
+-	smu[0] = 1;
+-
+-	/* discrepancy set to 1 */
+-	dmu[0] = 1;
+-	/* polynom order set to 0 */
+-	lmu[0] = 0;
+-	delta[0] = (mu[0] * 2 - lmu[0]) >> 1;
+-
+-	/* Second Row */
+-
+-	/* Mu */
+-	mu[1] = 0;
+-	/* Sigma(x) set to 1 */
+-	memset(&smu[num], 0, sizeof(s16) * num);
+-	smu[num] = 1;
+-
+-	/* discrepancy set to S1 */
+-	dmu[1] = si[1];
+-
+-	/* polynom order set to 0 */
+-	lmu[1] = 0;
+-
+-	delta[1] = (mu[1] * 2 - lmu[1]) >> 1;
+-
+-	/* Init the Sigma(x) last row */
+-	memset(&smu[(strength + 1) * num], 0, sizeof(s16) * num);
+-
+-	for (i = 1; i <= strength; i++) {
+-		mu[i + 1] = i << 1;
+-		/* Begin Computing Sigma (Mu+1) and L(mu) */
+-		/* check if discrepancy is set to 0 */
+-		if (dmu[i] == 0) {
+-			dmu_0_count++;
+-
+-			tmp = ((strength - (lmu[i] >> 1) - 1) / 2);
+-			if ((strength - (lmu[i] >> 1) - 1) & 0x1)
+-				tmp += 2;
+-			else
+-				tmp += 1;
+-
+-			if (dmu_0_count == tmp) {
+-				for (j = 0; j <= (lmu[i] >> 1) + 1; j++)
+-					smu[(strength + 1) * num + j] =
+-							smu[i * num + j];
+-
+-				lmu[strength + 1] = lmu[i];
+-				return;
+-			}
+-
+-			/* copy polynom */
+-			for (j = 0; j <= lmu[i] >> 1; j++)
+-				smu[(i + 1) * num + j] = smu[i * num + j];
+-
+-			/* copy previous polynom order to the next */
+-			lmu[i + 1] = lmu[i];
+-		} else {
+-			ro = 0;
+-			largest = -1;
+-			/* find largest delta with dmu != 0 */
+-			for (j = 0; j < i; j++) {
+-				if ((dmu[j]) && (delta[j] > largest)) {
+-					largest = delta[j];
+-					ro = j;
+-				}
+-			}
+-
+-			/* compute difference */
+-			diff = (mu[i] - mu[ro]);
+-
+-			/* Compute degree of the new smu polynomial */
+-			if ((lmu[i] >> 1) > ((lmu[ro] >> 1) + diff))
+-				lmu[i + 1] = lmu[i];
+-			else
+-				lmu[i + 1] = ((lmu[ro] >> 1) + diff) * 2;
+-
+-			/* Init smu[i+1] with 0 */
+-			for (k = 0; k < num; k++)
+-				smu[(i + 1) * num + k] = 0;
+-
+-			/* Compute smu[i+1] */
+-			for (k = 0; k <= lmu[ro] >> 1; k++) {
+-				s16 a, b, c;
+-
+-				if (!(smu[ro * num + k] && dmu[i]))
+-					continue;
+-
+-				a = index_of[dmu[i]];
+-				b = index_of[dmu[ro]];
+-				c = index_of[smu[ro * num + k]];
+-				tmp = a + (cw_len - b) + c;
+-				a = alpha_to[tmp % cw_len];
+-				smu[(i + 1) * num + (k + diff)] = a;
+-			}
+-
+-			for (k = 0; k <= lmu[i] >> 1; k++)
+-				smu[(i + 1) * num + k] ^= smu[i * num + k];
+-		}
+-
+-		/* End Computing Sigma (Mu+1) and L(mu) */
+-		/* In either case compute delta */
+-		delta[i + 1] = (mu[i + 1] * 2 - lmu[i + 1]) >> 1;
+-
+-		/* Do not compute discrepancy for the last iteration */
+-		if (i >= strength)
+-			continue;
+-
+-		for (k = 0; k <= (lmu[i + 1] >> 1); k++) {
+-			tmp = 2 * (i - 1);
+-			if (k == 0) {
+-				dmu[i + 1] = si[tmp + 3];
+-			} else if (smu[(i + 1) * num + k] && si[tmp + 3 - k]) {
+-				s16 a, b, c;
+-
+-				a = index_of[smu[(i + 1) * num + k]];
+-				b = si[2 * (i - 1) + 3 - k];
+-				c = index_of[b];
+-				tmp = a + c;
+-				tmp %= cw_len;
+-				dmu[i + 1] = alpha_to[tmp] ^ dmu[i + 1];
+-			}
+-		}
+-	}
+-}
+-
+-static int atmel_pmecc_err_location(struct atmel_pmecc_user *user)
+-{
+-	int sector_size = get_sectorsize(user);
+-	int degree = sector_size == 512 ? 13 : 14;
+-	struct atmel_pmecc *pmecc = user->pmecc;
+-	int strength = get_strength(user);
+-	int ret, roots_nbr, i, err_nbr = 0;
+-	int num = (2 * strength) + 1;
+-	s16 *smu = user->smu;
+-	u32 val;
+-
+-	writel(PMERRLOC_DISABLE, pmecc->regs.errloc + ATMEL_PMERRLOC_ELDIS);
+-
+-	for (i = 0; i <= user->lmu[strength + 1] >> 1; i++) {
+-		writel_relaxed(smu[(strength + 1) * num + i],
+-			       pmecc->regs.errloc + ATMEL_PMERRLOC_SIGMA(i));
+-		err_nbr++;
+-	}
+-
+-	val = (err_nbr - 1) << 16;
+-	if (sector_size == 1024)
+-		val |= 1;
+-
+-	writel(val, pmecc->regs.errloc + ATMEL_PMERRLOC_ELCFG);
+-	writel((sector_size * 8) + (degree * strength),
+-	       pmecc->regs.errloc + ATMEL_PMERRLOC_ELEN);
+-
+-	ret = readl_relaxed_poll_timeout(pmecc->regs.errloc +
+-					 ATMEL_PMERRLOC_ELISR,
+-					 val, val & PMERRLOC_CALC_DONE, 0,
+-					 PMECC_MAX_TIMEOUT_MS * 1000);
+-	if (ret) {
+-		dev_err(pmecc->dev,
+-			"PMECC: Timeout to calculate error location.\n");
+-		return ret;
+-	}
+-
+-	roots_nbr = (val & PMERRLOC_ERR_NUM_MASK) >> 8;
+-	/* Number of roots == degree of smu hence <= cap */
+-	if (roots_nbr == user->lmu[strength + 1] >> 1)
+-		return err_nbr - 1;
+-
+-	/*
+-	 * Number of roots does not match the degree of smu
+-	 * unable to correct error.
+-	 */
+-	return -EBADMSG;
+-}
+-
+-int atmel_pmecc_correct_sector(struct atmel_pmecc_user *user, int sector,
+-			       void *data, void *ecc)
+-{
+-	struct atmel_pmecc *pmecc = user->pmecc;
+-	int sectorsize = get_sectorsize(user);
+-	int eccbytes = user->eccbytes;
+-	int i, nerrors;
+-
+-	if (!(user->isr & BIT(sector)))
+-		return 0;
+-
+-	atmel_pmecc_gen_syndrome(user, sector);
+-	atmel_pmecc_substitute(user);
+-	atmel_pmecc_get_sigma(user);
+-
+-	nerrors = atmel_pmecc_err_location(user);
+-	if (nerrors < 0)
+-		return nerrors;
+-
+-	for (i = 0; i < nerrors; i++) {
+-		const char *area;
+-		int byte, bit;
+-		u32 errpos;
+-		u8 *ptr;
+-
+-		errpos = readl_relaxed(pmecc->regs.errloc +
+-				ATMEL_PMERRLOC_EL(pmecc->caps->el_offset, i));
+-		errpos--;
+-
+-		byte = errpos / 8;
+-		bit = errpos % 8;
+-
+-		if (byte < sectorsize) {
+-			ptr = data + byte;
+-			area = "data";
+-		} else if (byte < sectorsize + eccbytes) {
+-			ptr = ecc + byte - sectorsize;
+-			area = "ECC";
+-		} else {
+-			dev_dbg(pmecc->dev,
+-				"Invalid errpos value (%d, max is %d)\n",
+-				errpos, (sectorsize + eccbytes) * 8);
+-			return -EINVAL;
+-		}
+-
+-		dev_dbg(pmecc->dev,
+-			"Bit flip in %s area, byte %d: 0x%02x -> 0x%02x\n",
+-			area, byte, *ptr, (unsigned int)(*ptr ^ BIT(bit)));
+-
+-		*ptr ^= BIT(bit);
+-	}
+-
+-	return nerrors;
+-}
+-EXPORT_SYMBOL_GPL(atmel_pmecc_correct_sector);
+-
+-bool atmel_pmecc_correct_erased_chunks(struct atmel_pmecc_user *user)
+-{
+-	return user->pmecc->caps->correct_erased_chunks;
+-}
+-EXPORT_SYMBOL_GPL(atmel_pmecc_correct_erased_chunks);
+-
+-void atmel_pmecc_get_generated_eccbytes(struct atmel_pmecc_user *user,
+-					int sector, void *ecc)
+-{
+-	struct atmel_pmecc *pmecc = user->pmecc;
+-	u8 *ptr = ecc;
+-	int i;
+-
+-	for (i = 0; i < user->eccbytes; i++)
+-		ptr[i] = readb_relaxed(pmecc->regs.base +
+-				       ATMEL_PMECC_ECC(sector, i));
+-}
+-EXPORT_SYMBOL_GPL(atmel_pmecc_get_generated_eccbytes);
+-
+-int atmel_pmecc_enable(struct atmel_pmecc_user *user, int op)
+-{
+-	struct atmel_pmecc *pmecc = user->pmecc;
+-	u32 cfg;
+-
+-	if (op != NAND_ECC_READ && op != NAND_ECC_WRITE) {
+-		dev_err(pmecc->dev, "Bad ECC operation!");
+-		return -EINVAL;
+-	}
+-
+-	mutex_lock(&user->pmecc->lock);
+-
+-	cfg = user->cache.cfg;
+-	if (op == NAND_ECC_WRITE)
+-		cfg |= PMECC_CFG_WRITE_OP;
+-	else
+-		cfg |= PMECC_CFG_AUTO_ENABLE;
+-
+-	writel(cfg, pmecc->regs.base + ATMEL_PMECC_CFG);
+-	writel(user->cache.sarea, pmecc->regs.base + ATMEL_PMECC_SAREA);
+-	writel(user->cache.saddr, pmecc->regs.base + ATMEL_PMECC_SADDR);
+-	writel(user->cache.eaddr, pmecc->regs.base + ATMEL_PMECC_EADDR);
+-
+-	writel(PMECC_CTRL_ENABLE, pmecc->regs.base + ATMEL_PMECC_CTRL);
+-	writel(PMECC_CTRL_DATA, pmecc->regs.base + ATMEL_PMECC_CTRL);
+-
+-	return 0;
+-}
+-EXPORT_SYMBOL_GPL(atmel_pmecc_enable);
+-
+-void atmel_pmecc_disable(struct atmel_pmecc_user *user)
+-{
+-	struct atmel_pmecc *pmecc = user->pmecc;
+-
+-	writel(PMECC_CTRL_RST, pmecc->regs.base + ATMEL_PMECC_CTRL);
+-	writel(PMECC_CTRL_DISABLE, pmecc->regs.base + ATMEL_PMECC_CTRL);
+-	mutex_unlock(&user->pmecc->lock);
+-}
+-EXPORT_SYMBOL_GPL(atmel_pmecc_disable);
+-
+-int atmel_pmecc_wait_rdy(struct atmel_pmecc_user *user)
+-{
+-	struct atmel_pmecc *pmecc = user->pmecc;
+-	u32 status;
+-	int ret;
+-
+-	ret = readl_relaxed_poll_timeout(pmecc->regs.base +
+-					 ATMEL_PMECC_SR,
+-					 status, !(status & PMECC_SR_BUSY), 0,
+-					 PMECC_MAX_TIMEOUT_MS * 1000);
+-	if (ret) {
+-		dev_err(pmecc->dev,
+-			"Timeout while waiting for PMECC ready.\n");
+-		return ret;
+-	}
+-
+-	user->isr = readl_relaxed(pmecc->regs.base + ATMEL_PMECC_ISR);
+-
+-	return 0;
+-}
+-EXPORT_SYMBOL_GPL(atmel_pmecc_wait_rdy);
+-
+-static struct atmel_pmecc *atmel_pmecc_create(struct platform_device *pdev,
+-					const struct atmel_pmecc_caps *caps,
+-					int pmecc_res_idx, int errloc_res_idx)
+-{
+-	struct device *dev = &pdev->dev;
+-	struct atmel_pmecc *pmecc;
+-	struct resource *res;
+-
+-	pmecc = devm_kzalloc(dev, sizeof(*pmecc), GFP_KERNEL);
+-	if (!pmecc)
+-		return ERR_PTR(-ENOMEM);
+-
+-	pmecc->caps = caps;
+-	pmecc->dev = dev;
+-	mutex_init(&pmecc->lock);
+-
+-	res = platform_get_resource(pdev, IORESOURCE_MEM, pmecc_res_idx);
+-	pmecc->regs.base = devm_ioremap_resource(dev, res);
+-	if (IS_ERR(pmecc->regs.base))
+-		return ERR_CAST(pmecc->regs.base);
+-
+-	res = platform_get_resource(pdev, IORESOURCE_MEM, errloc_res_idx);
+-	pmecc->regs.errloc = devm_ioremap_resource(dev, res);
+-	if (IS_ERR(pmecc->regs.errloc))
+-		return ERR_CAST(pmecc->regs.errloc);
+-
+-	/* Disable all interrupts before registering the PMECC handler. */
+-	writel(0xffffffff, pmecc->regs.base + ATMEL_PMECC_IDR);
+-
+-	/* Reset the ECC engine */
+-	writel(PMECC_CTRL_RST, pmecc->regs.base + ATMEL_PMECC_CTRL);
+-	writel(PMECC_CTRL_DISABLE, pmecc->regs.base + ATMEL_PMECC_CTRL);
+-
+-	return pmecc;
+-}
+-
+-static void devm_atmel_pmecc_put(struct device *dev, void *res)
+-{
+-	struct atmel_pmecc **pmecc = res;
+-
+-	put_device((*pmecc)->dev);
+-}
+-
+-static struct atmel_pmecc *atmel_pmecc_get_by_node(struct device *userdev,
+-						   struct device_node *np)
+-{
+-	struct platform_device *pdev;
+-	struct atmel_pmecc *pmecc, **ptr;
+-
+-	pdev = of_find_device_by_node(np);
+-	if (!pdev || !platform_get_drvdata(pdev))
+-		return ERR_PTR(-EPROBE_DEFER);
+-
+-	ptr = devres_alloc(devm_atmel_pmecc_put, sizeof(*ptr), GFP_KERNEL);
+-	if (!ptr)
+-		return ERR_PTR(-ENOMEM);
+-
+-	get_device(&pdev->dev);
+-	pmecc = platform_get_drvdata(pdev);
+-
+-	*ptr = pmecc;
+-
+-	devres_add(userdev, ptr);
+-
+-	return pmecc;
+-}
+-
+-static const int atmel_pmecc_strengths[] = { 2, 4, 8, 12, 24, 32 };
+-
+-static struct atmel_pmecc_caps at91sam9g45_caps = {
+-	.strengths = atmel_pmecc_strengths,
+-	.nstrengths = 5,
+-	.el_offset = 0x8c,
+-};
+-
+-static struct atmel_pmecc_caps sama5d4_caps = {
+-	.strengths = atmel_pmecc_strengths,
+-	.nstrengths = 5,
+-	.el_offset = 0x8c,
+-	.correct_erased_chunks = true,
+-};
+-
+-static struct atmel_pmecc_caps sama5d2_caps = {
+-	.strengths = atmel_pmecc_strengths,
+-	.nstrengths = 6,
+-	.el_offset = 0xac,
+-	.correct_erased_chunks = true,
+-};
+-
+-static const struct of_device_id atmel_pmecc_legacy_match[] = {
+-	{ .compatible = "atmel,sama5d4-nand", &sama5d4_caps },
+-	{ .compatible = "atmel,sama5d2-nand", &sama5d2_caps },
+-	{ /* sentinel */ }
+-};
+-
+-struct atmel_pmecc *devm_atmel_pmecc_get(struct device *userdev)
+-{
+-	struct atmel_pmecc *pmecc;
+-	struct device_node *np;
+-
+-	if (!userdev)
+-		return ERR_PTR(-EINVAL);
+-
+-	if (!userdev->of_node)
+-		return NULL;
+-
+-	np = of_parse_phandle(userdev->of_node, "ecc-engine", 0);
+-	if (np) {
+-		pmecc = atmel_pmecc_get_by_node(userdev, np);
+-		of_node_put(np);
+-	} else {
+-		/*
+-		 * Support old DT bindings: in this case the PMECC iomem
+-		 * resources are directly defined in the user pdev at position
+-		 * 1 and 2. Extract all relevant information from there.
+-		 */
+-		struct platform_device *pdev = to_platform_device(userdev);
+-		const struct atmel_pmecc_caps *caps;
+-		const struct of_device_id *match;
+-
+-		/* No PMECC engine available. */
+-		if (!of_property_read_bool(userdev->of_node,
+-					   "atmel,has-pmecc"))
+-			return NULL;
+-
+-		caps = &at91sam9g45_caps;
+-
+-		/* Find the caps associated to the NAND dev node. */
+-		match = of_match_node(atmel_pmecc_legacy_match,
+-				      userdev->of_node);
+-		if (match && match->data)
+-			caps = match->data;
+-
+-		pmecc = atmel_pmecc_create(pdev, caps, 1, 2);
+-	}
+-
+-	return pmecc;
+-}
+-EXPORT_SYMBOL(devm_atmel_pmecc_get);
+-
+-static const struct of_device_id atmel_pmecc_match[] = {
+-	{ .compatible = "atmel,at91sam9g45-pmecc", &at91sam9g45_caps },
+-	{ .compatible = "atmel,sama5d4-pmecc", &sama5d4_caps },
+-	{ .compatible = "atmel,sama5d2-pmecc", &sama5d2_caps },
+-	{ /* sentinel */ }
+-};
+-MODULE_DEVICE_TABLE(of, atmel_pmecc_match);
+-
+-static int atmel_pmecc_probe(struct platform_device *pdev)
+-{
+-	struct device *dev = &pdev->dev;
+-	const struct atmel_pmecc_caps *caps;
+-	struct atmel_pmecc *pmecc;
+-
+-	caps = of_device_get_match_data(&pdev->dev);
+-	if (!caps) {
+-		dev_err(dev, "Invalid caps\n");
+-		return -EINVAL;
+-	}
+-
+-	pmecc = atmel_pmecc_create(pdev, caps, 0, 1);
+-	if (IS_ERR(pmecc))
+-		return PTR_ERR(pmecc);
+-
+-	platform_set_drvdata(pdev, pmecc);
+-
+-	return 0;
+-}
+-
+-static struct platform_driver atmel_pmecc_driver = {
+-	.driver = {
+-		.name = "atmel-pmecc",
+-		.of_match_table = of_match_ptr(atmel_pmecc_match),
+-	},
+-	.probe = atmel_pmecc_probe,
+-};
+-module_platform_driver(atmel_pmecc_driver);
+-
+-MODULE_LICENSE("GPL");
+-MODULE_AUTHOR("Boris Brezillon <boris.brezillon@free-electrons.com>");
+-MODULE_DESCRIPTION("PMECC engine driver");
+-MODULE_ALIAS("platform:atmel_pmecc");
+diff --git a/drivers/mtd/nand/atmel/pmecc.h b/drivers/mtd/nand/atmel/pmecc.h
+deleted file mode 100644
+index a8ddbfc..0000000
+--- a/drivers/mtd/nand/atmel/pmecc.h
++++ /dev/null
+@@ -1,73 +0,0 @@
+-/*
+- * © Copyright 2016 ATMEL
+- * © Copyright 2016 Free Electrons
+- *
+- * Author: Boris Brezillon <boris.brezillon@free-electrons.com>
+- *
+- * Derived from the atmel_nand.c driver which contained the following
+- * copyrights:
+- *
+- *    Copyright © 2003 Rick Bronson
+- *
+- *    Derived from drivers/mtd/nand/autcpu12.c
+- *        Copyright © 2001 Thomas Gleixner (gleixner@autronix.de)
+- *
+- *    Derived from drivers/mtd/spia.c
+- *        Copyright © 2000 Steven J. Hill (sjhill@cotw.com)
+- *
+- *
+- *    Add Hardware ECC support for AT91SAM9260 / AT91SAM9263
+- *        Richard Genoud (richard.genoud@gmail.com), Adeneo Copyright © 2007
+- *
+- *        Derived from Das U-Boot source code
+- *              (u-boot-1.1.5/board/atmel/at91sam9263ek/nand.c)
+- *        © Copyright 2006 ATMEL Rousset, Lacressonniere Nicolas
+- *
+- *    Add Programmable Multibit ECC support for various AT91 SoC
+- *        © Copyright 2012 ATMEL, Hong Xu
+- *
+- *    Add Nand Flash Controller support for SAMA5 SoC
+- *        © Copyright 2013 ATMEL, Josh Wu (josh.wu@atmel.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 ATMEL_PMECC_H
+-#define ATMEL_PMECC_H
+-
+-#define ATMEL_PMECC_MAXIMIZE_ECC_STRENGTH	0
+-#define ATMEL_PMECC_SECTOR_SIZE_AUTO		0
+-#define ATMEL_PMECC_OOBOFFSET_AUTO		-1
+-
+-struct atmel_pmecc_user_req {
+-	int pagesize;
+-	int oobsize;
+-	struct {
+-		int strength;
+-		int bytes;
+-		int sectorsize;
+-		int nsectors;
+-		int ooboffset;
+-	} ecc;
+-};
+-
+-struct atmel_pmecc *devm_atmel_pmecc_get(struct device *dev);
+-
+-struct atmel_pmecc_user *
+-atmel_pmecc_create_user(struct atmel_pmecc *pmecc,
+-			struct atmel_pmecc_user_req *req);
+-void atmel_pmecc_destroy_user(struct atmel_pmecc_user *user);
+-
+-int atmel_pmecc_enable(struct atmel_pmecc_user *user, int op);
+-void atmel_pmecc_disable(struct atmel_pmecc_user *user);
+-int atmel_pmecc_wait_rdy(struct atmel_pmecc_user *user);
+-int atmel_pmecc_correct_sector(struct atmel_pmecc_user *user, int sector,
+-			       void *data, void *ecc);
+-bool atmel_pmecc_correct_erased_chunks(struct atmel_pmecc_user *user);
+-void atmel_pmecc_get_generated_eccbytes(struct atmel_pmecc_user *user,
+-					int sector, void *ecc);
+-
+-#endif /* ATMEL_PMECC_H */
+diff --git a/drivers/mtd/nand/au1550nd.c b/drivers/mtd/nand/au1550nd.c
+deleted file mode 100644
+index 9d4a28f..0000000
+--- a/drivers/mtd/nand/au1550nd.c
++++ /dev/null
+@@ -1,518 +0,0 @@
+-/*
+- *  drivers/mtd/nand/au1550nd.c
+- *
+- *  Copyright (C) 2004 Embedded Edge, LLC
+- *
+- * 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/slab.h>
+-#include <linux/gpio.h>
+-#include <linux/module.h>
+-#include <linux/interrupt.h>
+-#include <linux/mtd/mtd.h>
+-#include <linux/mtd/rawnand.h>
+-#include <linux/mtd/partitions.h>
+-#include <linux/platform_device.h>
+-#include <asm/io.h>
+-#include <asm/mach-au1x00/au1000.h>
+-#include <asm/mach-au1x00/au1550nd.h>
+-
+-
+-struct au1550nd_ctx {
+-	struct nand_chip chip;
+-
+-	int cs;
+-	void __iomem *base;
+-	void (*write_byte)(struct mtd_info *, u_char);
+-};
+-
+-/**
+- * au_read_byte -  read one byte from the chip
+- * @mtd:	MTD device structure
+- *
+- * read function for 8bit buswidth
+- */
+-static u_char au_read_byte(struct mtd_info *mtd)
+-{
+-	struct nand_chip *this = mtd_to_nand(mtd);
+-	u_char ret = readb(this->IO_ADDR_R);
+-	wmb(); /* drain writebuffer */
+-	return ret;
+-}
+-
+-/**
+- * au_write_byte -  write one byte to the chip
+- * @mtd:	MTD device structure
+- * @byte:	pointer to data byte to write
+- *
+- * write function for 8it buswidth
+- */
+-static void au_write_byte(struct mtd_info *mtd, u_char byte)
+-{
+-	struct nand_chip *this = mtd_to_nand(mtd);
+-	writeb(byte, this->IO_ADDR_W);
+-	wmb(); /* drain writebuffer */
+-}
+-
+-/**
+- * au_read_byte16 -  read one byte endianness aware from the chip
+- * @mtd:	MTD device structure
+- *
+- * read function for 16bit buswidth with endianness conversion
+- */
+-static u_char au_read_byte16(struct mtd_info *mtd)
+-{
+-	struct nand_chip *this = mtd_to_nand(mtd);
+-	u_char ret = (u_char) cpu_to_le16(readw(this->IO_ADDR_R));
+-	wmb(); /* drain writebuffer */
+-	return ret;
+-}
+-
+-/**
+- * au_write_byte16 -  write one byte endianness aware to the chip
+- * @mtd:	MTD device structure
+- * @byte:	pointer to data byte to write
+- *
+- * write function for 16bit buswidth with endianness conversion
+- */
+-static void au_write_byte16(struct mtd_info *mtd, u_char byte)
+-{
+-	struct nand_chip *this = mtd_to_nand(mtd);
+-	writew(le16_to_cpu((u16) byte), this->IO_ADDR_W);
+-	wmb(); /* drain writebuffer */
+-}
+-
+-/**
+- * au_read_word -  read one word from the chip
+- * @mtd:	MTD device structure
+- *
+- * read function for 16bit buswidth without endianness conversion
+- */
+-static u16 au_read_word(struct mtd_info *mtd)
+-{
+-	struct nand_chip *this = mtd_to_nand(mtd);
+-	u16 ret = readw(this->IO_ADDR_R);
+-	wmb(); /* drain writebuffer */
+-	return ret;
+-}
+-
+-/**
+- * au_write_buf -  write buffer to chip
+- * @mtd:	MTD device structure
+- * @buf:	data buffer
+- * @len:	number of bytes to write
+- *
+- * write function for 8bit buswidth
+- */
+-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);
+-
+-	for (i = 0; i < len; i++) {
+-		writeb(buf[i], this->IO_ADDR_W);
+-		wmb(); /* drain writebuffer */
+-	}
+-}
+-
+-/**
+- * au_read_buf -  read chip data into buffer
+- * @mtd:	MTD device structure
+- * @buf:	buffer to store date
+- * @len:	number of bytes to read
+- *
+- * read function for 8bit buswidth
+- */
+-static void au_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+-{
+-	int i;
+-	struct nand_chip *this = mtd_to_nand(mtd);
+-
+-	for (i = 0; i < len; i++) {
+-		buf[i] = readb(this->IO_ADDR_R);
+-		wmb(); /* drain writebuffer */
+-	}
+-}
+-
+-/**
+- * au_write_buf16 -  write buffer to chip
+- * @mtd:	MTD device structure
+- * @buf:	data buffer
+- * @len:	number of bytes to write
+- *
+- * write function for 16bit buswidth
+- */
+-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);
+-	u16 *p = (u16 *) buf;
+-	len >>= 1;
+-
+-	for (i = 0; i < len; i++) {
+-		writew(p[i], this->IO_ADDR_W);
+-		wmb(); /* drain writebuffer */
+-	}
+-
+-}
+-
+-/**
+- * au_read_buf16 -  read chip data into buffer
+- * @mtd:	MTD device structure
+- * @buf:	buffer to store date
+- * @len:	number of bytes to read
+- *
+- * read function for 16bit buswidth
+- */
+-static void au_read_buf16(struct mtd_info *mtd, u_char *buf, int len)
+-{
+-	int i;
+-	struct nand_chip *this = mtd_to_nand(mtd);
+-	u16 *p = (u16 *) buf;
+-	len >>= 1;
+-
+-	for (i = 0; i < len; i++) {
+-		p[i] = readw(this->IO_ADDR_R);
+-		wmb(); /* drain writebuffer */
+-	}
+-}
+-
+-/* Select the chip by setting nCE to low */
+-#define NAND_CTL_SETNCE		1
+-/* Deselect the chip by setting nCE to high */
+-#define NAND_CTL_CLRNCE		2
+-/* Select the command latch by setting CLE to high */
+-#define NAND_CTL_SETCLE		3
+-/* Deselect the command latch by setting CLE to low */
+-#define NAND_CTL_CLRCLE		4
+-/* Select the address latch by setting ALE to high */
+-#define NAND_CTL_SETALE		5
+-/* Deselect the address latch by setting ALE to low */
+-#define NAND_CTL_CLRALE		6
+-
+-static void au1550_hwcontrol(struct mtd_info *mtd, int cmd)
+-{
+-	struct nand_chip *this = mtd_to_nand(mtd);
+-	struct au1550nd_ctx *ctx = container_of(this, struct au1550nd_ctx,
+-						chip);
+-
+-	switch (cmd) {
+-
+-	case NAND_CTL_SETCLE:
+-		this->IO_ADDR_W = ctx->base + MEM_STNAND_CMD;
+-		break;
+-
+-	case NAND_CTL_CLRCLE:
+-		this->IO_ADDR_W = ctx->base + MEM_STNAND_DATA;
+-		break;
+-
+-	case NAND_CTL_SETALE:
+-		this->IO_ADDR_W = ctx->base + MEM_STNAND_ADDR;
+-		break;
+-
+-	case NAND_CTL_CLRALE:
+-		this->IO_ADDR_W = ctx->base + MEM_STNAND_DATA;
+-		/* FIXME: Nobody knows why this is necessary,
+-		 * but it works only that way */
+-		udelay(1);
+-		break;
+-
+-	case NAND_CTL_SETNCE:
+-		/* assert (force assert) chip enable */
+-		alchemy_wrsmem((1 << (4 + ctx->cs)), AU1000_MEM_STNDCTL);
+-		break;
+-
+-	case NAND_CTL_CLRNCE:
+-		/* deassert chip enable */
+-		alchemy_wrsmem(0, AU1000_MEM_STNDCTL);
+-		break;
+-	}
+-
+-	this->IO_ADDR_R = this->IO_ADDR_W;
+-
+-	wmb(); /* Drain the writebuffer */
+-}
+-
+-int au1550_device_ready(struct mtd_info *mtd)
+-{
+-	return (alchemy_rdsmem(AU1000_MEM_STSTAT) & 0x1) ? 1 : 0;
+-}
+-
+-/**
+- * au1550_select_chip - control -CE line
+- *	Forbid driving -CE manually permitting the NAND controller to do this.
+- *	Keeping -CE asserted during the whole sector reads interferes with the
+- *	NOR flash and PCMCIA drivers as it causes contention on the static bus.
+- *	We only have to hold -CE low for the NAND read commands since the flash
+- *	chip needs it to be asserted during chip not ready time but the NAND
+- *	controller keeps it released.
+- *
+- * @mtd:	MTD device structure
+- * @chip:	chipnumber to select, -1 for deselect
+- */
+-static void au1550_select_chip(struct mtd_info *mtd, int chip)
+-{
+-}
+-
+-/**
+- * au1550_command - Send command to NAND device
+- * @mtd:	MTD device structure
+- * @command:	the command to be sent
+- * @column:	the column address for this command, -1 if none
+- * @page_addr:	the page address for this command, -1 if none
+- */
+-static void au1550_command(struct mtd_info *mtd, unsigned command, int column, int page_addr)
+-{
+-	struct nand_chip *this = mtd_to_nand(mtd);
+-	struct au1550nd_ctx *ctx = container_of(this, struct au1550nd_ctx,
+-						chip);
+-	int ce_override = 0, i;
+-	unsigned long flags = 0;
+-
+-	/* Begin command latch cycle */
+-	au1550_hwcontrol(mtd, NAND_CTL_SETCLE);
+-	/*
+-	 * Write out the command to the device.
+-	 */
+-	if (command == NAND_CMD_SEQIN) {
+-		int readcmd;
+-
+-		if (column >= mtd->writesize) {
+-			/* OOB area */
+-			column -= mtd->writesize;
+-			readcmd = NAND_CMD_READOOB;
+-		} else if (column < 256) {
+-			/* First 256 bytes --> READ0 */
+-			readcmd = NAND_CMD_READ0;
+-		} else {
+-			column -= 256;
+-			readcmd = NAND_CMD_READ1;
+-		}
+-		ctx->write_byte(mtd, readcmd);
+-	}
+-	ctx->write_byte(mtd, command);
+-
+-	/* Set ALE and clear CLE to start address cycle */
+-	au1550_hwcontrol(mtd, NAND_CTL_CLRCLE);
+-
+-	if (column != -1 || page_addr != -1) {
+-		au1550_hwcontrol(mtd, NAND_CTL_SETALE);
+-
+-		/* Serially input address */
+-		if (column != -1) {
+-			/* Adjust columns for 16 bit buswidth */
+-			if (this->options & NAND_BUSWIDTH_16 &&
+-					!nand_opcode_8bits(command))
+-				column >>= 1;
+-			ctx->write_byte(mtd, column);
+-		}
+-		if (page_addr != -1) {
+-			ctx->write_byte(mtd, (u8)(page_addr & 0xff));
+-
+-			if (command == NAND_CMD_READ0 ||
+-			    command == NAND_CMD_READ1 ||
+-			    command == NAND_CMD_READOOB) {
+-				/*
+-				 * NAND controller will release -CE after
+-				 * the last address byte is written, so we'll
+-				 * have to forcibly assert it. No interrupts
+-				 * are allowed while we do this as we don't
+-				 * want the NOR flash or PCMCIA drivers to
+-				 * steal our precious bytes of data...
+-				 */
+-				ce_override = 1;
+-				local_irq_save(flags);
+-				au1550_hwcontrol(mtd, NAND_CTL_SETNCE);
+-			}
+-
+-			ctx->write_byte(mtd, (u8)(page_addr >> 8));
+-
+-			/* One more address cycle for devices > 32MiB */
+-			if (this->chipsize > (32 << 20))
+-				ctx->write_byte(mtd,
+-						((page_addr >> 16) & 0x0f));
+-		}
+-		/* Latch in address */
+-		au1550_hwcontrol(mtd, NAND_CTL_CLRALE);
+-	}
+-
+-	/*
+-	 * Program and erase have their own busy handlers.
+-	 * Status and sequential in need no delay.
+-	 */
+-	switch (command) {
+-
+-	case NAND_CMD_PAGEPROG:
+-	case NAND_CMD_ERASE1:
+-	case NAND_CMD_ERASE2:
+-	case NAND_CMD_SEQIN:
+-	case NAND_CMD_STATUS:
+-		return;
+-
+-	case NAND_CMD_RESET:
+-		break;
+-
+-	case NAND_CMD_READ0:
+-	case NAND_CMD_READ1:
+-	case NAND_CMD_READOOB:
+-		/* Check if we're really driving -CE low (just in case) */
+-		if (unlikely(!ce_override))
+-			break;
+-
+-		/* Apply a short delay always to ensure that we do wait tWB. */
+-		ndelay(100);
+-		/* Wait for a chip to become ready... */
+-		for (i = this->chip_delay; !this->dev_ready(mtd) && i > 0; --i)
+-			udelay(1);
+-
+-		/* Release -CE and re-enable interrupts. */
+-		au1550_hwcontrol(mtd, NAND_CTL_CLRNCE);
+-		local_irq_restore(flags);
+-		return;
+-	}
+-	/* Apply this short delay always to ensure that we do wait tWB. */
+-	ndelay(100);
+-
+-	while(!this->dev_ready(mtd));
+-}
+-
+-static int find_nand_cs(unsigned long nand_base)
+-{
+-	void __iomem *base =
+-			(void __iomem *)KSEG1ADDR(AU1000_STATIC_MEM_PHYS_ADDR);
+-	unsigned long addr, staddr, start, mask, end;
+-	int i;
+-
+-	for (i = 0; i < 4; i++) {
+-		addr = 0x1000 + (i * 0x10);			/* CSx */
+-		staddr = __raw_readl(base + addr + 0x08);	/* STADDRx */
+-		/* figure out the decoded range of this CS */
+-		start = (staddr << 4) & 0xfffc0000;
+-		mask = (staddr << 18) & 0xfffc0000;
+-		end = (start | (start - 1)) & ~(start ^ mask);
+-		if ((nand_base >= start) && (nand_base < end))
+-			return i;
+-	}
+-
+-	return -ENODEV;
+-}
+-
+-static int au1550nd_probe(struct platform_device *pdev)
+-{
+-	struct au1550nd_platdata *pd;
+-	struct au1550nd_ctx *ctx;
+-	struct nand_chip *this;
+-	struct mtd_info *mtd;
+-	struct resource *r;
+-	int ret, cs;
+-
+-	pd = dev_get_platdata(&pdev->dev);
+-	if (!pd) {
+-		dev_err(&pdev->dev, "missing platform data\n");
+-		return -ENODEV;
+-	}
+-
+-	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+-	if (!ctx)
+-		return -ENOMEM;
+-
+-	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+-	if (!r) {
+-		dev_err(&pdev->dev, "no NAND memory resource\n");
+-		ret = -ENODEV;
+-		goto out1;
+-	}
+-	if (request_mem_region(r->start, resource_size(r), "au1550-nand")) {
+-		dev_err(&pdev->dev, "cannot claim NAND memory area\n");
+-		ret = -ENOMEM;
+-		goto out1;
+-	}
+-
+-	ctx->base = ioremap_nocache(r->start, 0x1000);
+-	if (!ctx->base) {
+-		dev_err(&pdev->dev, "cannot remap NAND memory area\n");
+-		ret = -ENODEV;
+-		goto out2;
+-	}
+-
+-	this = &ctx->chip;
+-	mtd = nand_to_mtd(this);
+-	mtd->dev.parent = &pdev->dev;
+-
+-	/* figure out which CS# r->start belongs to */
+-	cs = find_nand_cs(r->start);
+-	if (cs < 0) {
+-		dev_err(&pdev->dev, "cannot detect NAND chipselect\n");
+-		ret = -ENODEV;
+-		goto out3;
+-	}
+-	ctx->cs = cs;
+-
+-	this->dev_ready = au1550_device_ready;
+-	this->select_chip = au1550_select_chip;
+-	this->cmdfunc = au1550_command;
+-
+-	/* 30 us command delay time */
+-	this->chip_delay = 30;
+-	this->ecc.mode = NAND_ECC_SOFT;
+-	this->ecc.algo = NAND_ECC_HAMMING;
+-
+-	if (pd->devwidth)
+-		this->options |= NAND_BUSWIDTH_16;
+-
+-	this->read_byte = (pd->devwidth) ? au_read_byte16 : au_read_byte;
+-	ctx->write_byte = (pd->devwidth) ? au_write_byte16 : au_write_byte;
+-	this->read_word = au_read_word;
+-	this->write_buf = (pd->devwidth) ? au_write_buf16 : au_write_buf;
+-	this->read_buf = (pd->devwidth) ? au_read_buf16 : au_read_buf;
+-
+-	ret = nand_scan(mtd, 1);
+-	if (ret) {
+-		dev_err(&pdev->dev, "NAND scan failed with %d\n", ret);
+-		goto out3;
+-	}
+-
+-	mtd_device_register(mtd, pd->parts, pd->num_parts);
+-
+-	platform_set_drvdata(pdev, ctx);
+-
+-	return 0;
+-
+-out3:
+-	iounmap(ctx->base);
+-out2:
+-	release_mem_region(r->start, resource_size(r));
+-out1:
+-	kfree(ctx);
+-	return ret;
+-}
+-
+-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));
+-	iounmap(ctx->base);
+-	release_mem_region(r->start, 0x1000);
+-	kfree(ctx);
+-	return 0;
+-}
+-
+-static struct platform_driver au1550nd_driver = {
+-	.driver = {
+-		.name	= "au1550-nand",
+-	},
+-	.probe		= au1550nd_probe,
+-	.remove		= au1550nd_remove,
+-};
+-
+-module_platform_driver(au1550nd_driver);
+-
+-MODULE_LICENSE("GPL");
+-MODULE_AUTHOR("Embedded Edge, LLC");
+-MODULE_DESCRIPTION("Board-specific glue layer for NAND flash on Pb1550 board");
+diff --git a/drivers/mtd/nand/bcm47xxnflash/Makefile b/drivers/mtd/nand/bcm47xxnflash/Makefile
+deleted file mode 100644
+index f05b119..0000000
+--- a/drivers/mtd/nand/bcm47xxnflash/Makefile
++++ /dev/null
+@@ -1,4 +0,0 @@
+-bcm47xxnflash-y				+= main.o
+-bcm47xxnflash-y				+= ops_bcm4706.o
+-
+-obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH)	+= bcm47xxnflash.o
+diff --git a/drivers/mtd/nand/bcm47xxnflash/bcm47xxnflash.h b/drivers/mtd/nand/bcm47xxnflash/bcm47xxnflash.h
+deleted file mode 100644
+index 201b9baa..0000000
+--- a/drivers/mtd/nand/bcm47xxnflash/bcm47xxnflash.h
++++ /dev/null
+@@ -1,26 +0,0 @@
+-/* SPDX-License-Identifier: GPL-2.0 */
+-#ifndef __BCM47XXNFLASH_H
+-#define __BCM47XXNFLASH_H
+-
+-#ifndef pr_fmt
+-#define pr_fmt(fmt)		KBUILD_MODNAME ": " fmt
+-#endif
+-
+-#include <linux/mtd/mtd.h>
+-#include <linux/mtd/rawnand.h>
+-
+-struct bcm47xxnflash {
+-	struct bcma_drv_cc *cc;
+-
+-	struct nand_chip nand_chip;
+-
+-	unsigned curr_command;
+-	int curr_page_addr;
+-	int curr_column;
+-
+-	u8 id_data[8];
+-};
+-
+-int bcm47xxnflash_ops_bcm4706_init(struct bcm47xxnflash *b47n);
+-
+-#endif /* BCM47XXNFLASH */
+diff --git a/drivers/mtd/nand/bcm47xxnflash/main.c b/drivers/mtd/nand/bcm47xxnflash/main.c
+deleted file mode 100644
+index fb31429..0000000
+--- a/drivers/mtd/nand/bcm47xxnflash/main.c
++++ /dev/null
+@@ -1,81 +0,0 @@
+-/*
+- * BCM47XX NAND flash driver
+- *
+- * Copyright (C) 2012 Rafał Miłecki <zajec5@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 "bcm47xxnflash.h"
+-
+-#include <linux/module.h>
+-#include <linux/kernel.h>
+-#include <linux/slab.h>
+-#include <linux/platform_device.h>
+-#include <linux/bcma/bcma.h>
+-
+-MODULE_DESCRIPTION("NAND flash driver for BCMA bus");
+-MODULE_LICENSE("GPL");
+-MODULE_AUTHOR("Rafał Miłecki");
+-
+-static const char *probes[] = { "bcm47xxpart", NULL };
+-
+-static int bcm47xxnflash_probe(struct platform_device *pdev)
+-{
+-	struct bcma_nflash *nflash = dev_get_platdata(&pdev->dev);
+-	struct bcm47xxnflash *b47n;
+-	struct mtd_info *mtd;
+-	int err = 0;
+-
+-	b47n = devm_kzalloc(&pdev->dev, sizeof(*b47n), GFP_KERNEL);
+-	if (!b47n)
+-		return -ENOMEM;
+-
+-	nand_set_controller_data(&b47n->nand_chip, b47n);
+-	mtd = nand_to_mtd(&b47n->nand_chip);
+-	mtd->dev.parent = &pdev->dev;
+-	b47n->cc = container_of(nflash, struct bcma_drv_cc, nflash);
+-
+-	if (b47n->cc->core->bus->chipinfo.id == BCMA_CHIP_ID_BCM4706) {
+-		err = bcm47xxnflash_ops_bcm4706_init(b47n);
+-	} else {
+-		pr_err("Device not supported\n");
+-		err = -ENOTSUPP;
+-	}
+-	if (err) {
+-		pr_err("Initialization failed: %d\n", err);
+-		return err;
+-	}
+-
+-	platform_set_drvdata(pdev, b47n);
+-
+-	err = mtd_device_parse_register(mtd, probes, NULL, NULL, 0);
+-	if (err) {
+-		pr_err("Failed to register MTD device: %d\n", err);
+-		return err;
+-	}
+-
+-	return 0;
+-}
+-
+-static int bcm47xxnflash_remove(struct platform_device *pdev)
+-{
+-	struct bcm47xxnflash *nflash = platform_get_drvdata(pdev);
+-
+-	nand_release(nand_to_mtd(&nflash->nand_chip));
+-
+-	return 0;
+-}
+-
+-static struct platform_driver bcm47xxnflash_driver = {
+-	.probe	= bcm47xxnflash_probe,
+-	.remove = bcm47xxnflash_remove,
+-	.driver = {
+-		.name = "bcma_nflash",
+-	},
+-};
+-
+-module_platform_driver(bcm47xxnflash_driver);
+diff --git a/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c b/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c
+deleted file mode 100644
+index 54bac5b..0000000
+--- a/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c
++++ /dev/null
+@@ -1,456 +0,0 @@
+-/*
+- * BCM47XX NAND flash driver
+- *
+- * Copyright (C) 2012 Rafał Miłecki <zajec5@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 "bcm47xxnflash.h"
+-
+-#include <linux/module.h>
+-#include <linux/kernel.h>
+-#include <linux/slab.h>
+-#include <linux/delay.h>
+-#include <linux/bcma/bcma.h>
+-
+-/* Broadcom uses 1'000'000 but it seems to be too many. Tests on WNDR4500 has
+- * shown ~1000 retries as maxiumum. */
+-#define NFLASH_READY_RETRIES		10000
+-
+-#define NFLASH_SECTOR_SIZE		512
+-
+-#define NCTL_CMD0			0x00010000
+-#define NCTL_COL			0x00020000	/* Update column with value from BCMA_CC_NFLASH_COL_ADDR */
+-#define NCTL_ROW			0x00040000	/* Update row (page) with value from BCMA_CC_NFLASH_ROW_ADDR */
+-#define NCTL_CMD1W			0x00080000
+-#define NCTL_READ			0x00100000
+-#define NCTL_WRITE			0x00200000
+-#define NCTL_SPECADDR			0x01000000
+-#define NCTL_READY			0x04000000
+-#define NCTL_ERR			0x08000000
+-#define NCTL_CSA			0x40000000
+-#define NCTL_START			0x80000000
+-
+-/**************************************************
+- * Various helpers
+- **************************************************/
+-
+-static inline u8 bcm47xxnflash_ops_bcm4706_ns_to_cycle(u16 ns, u16 clock)
+-{
+-	return ((ns * 1000 * clock) / 1000000) + 1;
+-}
+-
+-static int bcm47xxnflash_ops_bcm4706_ctl_cmd(struct bcma_drv_cc *cc, u32 code)
+-{
+-	int i = 0;
+-
+-	bcma_cc_write32(cc, BCMA_CC_NFLASH_CTL, NCTL_START | code);
+-	for (i = 0; i < NFLASH_READY_RETRIES; i++) {
+-		if (!(bcma_cc_read32(cc, BCMA_CC_NFLASH_CTL) & NCTL_START)) {
+-			i = 0;
+-			break;
+-		}
+-	}
+-	if (i) {
+-		pr_err("NFLASH control command not ready!\n");
+-		return -EBUSY;
+-	}
+-	return 0;
+-}
+-
+-static int bcm47xxnflash_ops_bcm4706_poll(struct bcma_drv_cc *cc)
+-{
+-	int i;
+-
+-	for (i = 0; i < NFLASH_READY_RETRIES; i++) {
+-		if (bcma_cc_read32(cc, BCMA_CC_NFLASH_CTL) & NCTL_READY) {
+-			if (bcma_cc_read32(cc, BCMA_CC_NFLASH_CTL) &
+-			    BCMA_CC_NFLASH_CTL_ERR) {
+-				pr_err("Error on polling\n");
+-				return -EBUSY;
+-			} else {
+-				return 0;
+-			}
+-		}
+-	}
+-
+-	pr_err("Polling timeout!\n");
+-	return -EBUSY;
+-}
+-
+-/**************************************************
+- * R/W
+- **************************************************/
+-
+-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 bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
+-
+-	u32 ctlcode;
+-	u32 *dest = (u32 *)buf;
+-	int i;
+-	int toread;
+-
+-	BUG_ON(b47n->curr_page_addr & ~nand_chip->pagemask);
+-	/* Don't validate column using nand_chip->page_shift, it may be bigger
+-	 * when accessing OOB */
+-
+-	while (len) {
+-		/* We can read maximum of 0x200 bytes at once */
+-		toread = min(len, 0x200);
+-
+-		/* Set page and column */
+-		bcma_cc_write32(b47n->cc, BCMA_CC_NFLASH_COL_ADDR,
+-				b47n->curr_column);
+-		bcma_cc_write32(b47n->cc, BCMA_CC_NFLASH_ROW_ADDR,
+-				b47n->curr_page_addr);
+-
+-		/* Prepare to read */
+-		ctlcode = NCTL_CSA | NCTL_CMD1W | NCTL_ROW | NCTL_COL |
+-			  NCTL_CMD0;
+-		ctlcode |= NAND_CMD_READSTART << 8;
+-		if (bcm47xxnflash_ops_bcm4706_ctl_cmd(b47n->cc, ctlcode))
+-			return;
+-		if (bcm47xxnflash_ops_bcm4706_poll(b47n->cc))
+-			return;
+-
+-		/* Eventually read some data :) */
+-		for (i = 0; i < toread; i += 4, dest++) {
+-			ctlcode = NCTL_CSA | 0x30000000 | NCTL_READ;
+-			if (i == toread - 4) /* Last read goes without that */
+-				ctlcode &= ~NCTL_CSA;
+-			if (bcm47xxnflash_ops_bcm4706_ctl_cmd(b47n->cc,
+-							      ctlcode))
+-				return;
+-			*dest = bcma_cc_read32(b47n->cc, BCMA_CC_NFLASH_DATA);
+-		}
+-
+-		b47n->curr_column += toread;
+-		len -= toread;
+-	}
+-}
+-
+-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 bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
+-	struct bcma_drv_cc *cc = b47n->cc;
+-
+-	u32 ctlcode;
+-	const u32 *data = (u32 *)buf;
+-	int i;
+-
+-	BUG_ON(b47n->curr_page_addr & ~nand_chip->pagemask);
+-	/* Don't validate column using nand_chip->page_shift, it may be bigger
+-	 * when accessing OOB */
+-
+-	for (i = 0; i < len; i += 4, data++) {
+-		bcma_cc_write32(cc, BCMA_CC_NFLASH_DATA, *data);
+-
+-		ctlcode = NCTL_CSA | 0x30000000 | NCTL_WRITE;
+-		if (i == len - 4) /* Last read goes without that */
+-			ctlcode &= ~NCTL_CSA;
+-		if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, ctlcode)) {
+-			pr_err("%s ctl_cmd didn't work!\n", __func__);
+-			return;
+-		}
+-	}
+-
+-	b47n->curr_column += len;
+-}
+-
+-/**************************************************
+- * NAND chip ops
+- **************************************************/
+-
+-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 bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
+-	u32 code = 0;
+-
+-	if (cmd == NAND_CMD_NONE)
+-		return;
+-
+-	if (cmd & NAND_CTRL_CLE)
+-		code = cmd | NCTL_CMD0;
+-
+-	/* nCS is not needed for reset command */
+-	if (cmd != NAND_CMD_RESET)
+-		code |= NCTL_CSA;
+-
+-	bcm47xxnflash_ops_bcm4706_ctl_cmd(b47n->cc, code);
+-}
+-
+-/* Default nand_select_chip calls cmd_ctrl, which is not used in BCM4706 */
+-static void bcm47xxnflash_ops_bcm4706_select_chip(struct mtd_info *mtd,
+-						  int chip)
+-{
+-	return;
+-}
+-
+-static int bcm47xxnflash_ops_bcm4706_dev_ready(struct mtd_info *mtd)
+-{
+-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+-	struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
+-
+-	return !!(bcma_cc_read32(b47n->cc, BCMA_CC_NFLASH_CTL) & NCTL_READY);
+-}
+-
+-/*
+- * Default nand_command and nand_command_lp don't match BCM4706 hardware layout.
+- * For example, reading chip id is performed in a non-standard way.
+- * Setting column and page is also handled differently, we use a special
+- * registers of ChipCommon core. Hacking cmd_ctrl to understand and convert
+- * standard commands would be much more complicated.
+- */
+-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 bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
+-	struct bcma_drv_cc *cc = b47n->cc;
+-	u32 ctlcode;
+-	int i;
+-
+-	if (column != -1)
+-		b47n->curr_column = column;
+-	if (page_addr != -1)
+-		b47n->curr_page_addr = page_addr;
+-
+-	switch (command) {
+-	case NAND_CMD_RESET:
+-		nand_chip->cmd_ctrl(mtd, command, NAND_CTRL_CLE);
+-
+-		ndelay(100);
+-		nand_wait_ready(mtd);
+-		break;
+-	case NAND_CMD_READID:
+-		ctlcode = NCTL_CSA | 0x01000000 | NCTL_CMD1W | NCTL_CMD0;
+-		ctlcode |= NAND_CMD_READID;
+-		if (bcm47xxnflash_ops_bcm4706_ctl_cmd(b47n->cc, ctlcode)) {
+-			pr_err("READID error\n");
+-			break;
+-		}
+-
+-		/*
+-		 * Reading is specific, last one has to go without NCTL_CSA
+-		 * bit. We don't know how many reads NAND subsystem is going
+-		 * to perform, so cache everything.
+-		 */
+-		for (i = 0; i < ARRAY_SIZE(b47n->id_data); i++) {
+-			ctlcode = NCTL_CSA | NCTL_READ;
+-			if (i == ARRAY_SIZE(b47n->id_data) - 1)
+-				ctlcode &= ~NCTL_CSA;
+-			if (bcm47xxnflash_ops_bcm4706_ctl_cmd(b47n->cc,
+-							      ctlcode)) {
+-				pr_err("READID error\n");
+-				break;
+-			}
+-			b47n->id_data[i] =
+-				bcma_cc_read32(b47n->cc, BCMA_CC_NFLASH_DATA)
+-				& 0xFF;
+-		}
+-
+-		break;
+-	case NAND_CMD_STATUS:
+-		ctlcode = NCTL_CSA | NCTL_CMD0 | NAND_CMD_STATUS;
+-		if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, ctlcode))
+-			pr_err("STATUS command error\n");
+-		break;
+-	case NAND_CMD_READ0:
+-		break;
+-	case NAND_CMD_READOOB:
+-		if (page_addr != -1)
+-			b47n->curr_column += mtd->writesize;
+-		break;
+-	case NAND_CMD_ERASE1:
+-		bcma_cc_write32(cc, BCMA_CC_NFLASH_ROW_ADDR,
+-				b47n->curr_page_addr);
+-		ctlcode = NCTL_ROW | NCTL_CMD1W | NCTL_CMD0 |
+-			  NAND_CMD_ERASE1 | (NAND_CMD_ERASE2 << 8);
+-		if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, ctlcode))
+-			pr_err("ERASE1 failed\n");
+-		break;
+-	case NAND_CMD_ERASE2:
+-		break;
+-	case NAND_CMD_SEQIN:
+-		/* Set page and column */
+-		bcma_cc_write32(cc, BCMA_CC_NFLASH_COL_ADDR,
+-				b47n->curr_column);
+-		bcma_cc_write32(cc, BCMA_CC_NFLASH_ROW_ADDR,
+-				b47n->curr_page_addr);
+-
+-		/* Prepare to write */
+-		ctlcode = 0x40000000 | NCTL_ROW | NCTL_COL | NCTL_CMD0;
+-		ctlcode |= NAND_CMD_SEQIN;
+-		if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, ctlcode))
+-			pr_err("SEQIN failed\n");
+-		break;
+-	case NAND_CMD_PAGEPROG:
+-		if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, NCTL_CMD0 |
+-							  NAND_CMD_PAGEPROG))
+-			pr_err("PAGEPROG failed\n");
+-		if (bcm47xxnflash_ops_bcm4706_poll(cc))
+-			pr_err("PAGEPROG not ready\n");
+-		break;
+-	default:
+-		pr_err("Command 0x%X unsupported\n", command);
+-		break;
+-	}
+-	b47n->curr_command = command;
+-}
+-
+-static u8 bcm47xxnflash_ops_bcm4706_read_byte(struct mtd_info *mtd)
+-{
+-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+-	struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
+-	struct bcma_drv_cc *cc = b47n->cc;
+-	u32 tmp = 0;
+-
+-	switch (b47n->curr_command) {
+-	case NAND_CMD_READID:
+-		if (b47n->curr_column >= ARRAY_SIZE(b47n->id_data)) {
+-			pr_err("Requested invalid id_data: %d\n",
+-			       b47n->curr_column);
+-			return 0;
+-		}
+-		return b47n->id_data[b47n->curr_column++];
+-	case NAND_CMD_STATUS:
+-		if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, NCTL_READ))
+-			return 0;
+-		return bcma_cc_read32(cc, BCMA_CC_NFLASH_DATA) & 0xff;
+-	case NAND_CMD_READOOB:
+-		bcm47xxnflash_ops_bcm4706_read(mtd, (u8 *)&tmp, 4);
+-		return tmp & 0xFF;
+-	}
+-
+-	pr_err("Invalid command for byte read: 0x%X\n", b47n->curr_command);
+-	return 0;
+-}
+-
+-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 bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
+-
+-	switch (b47n->curr_command) {
+-	case NAND_CMD_READ0:
+-	case NAND_CMD_READOOB:
+-		bcm47xxnflash_ops_bcm4706_read(mtd, buf, len);
+-		return;
+-	}
+-
+-	pr_err("Invalid command for buf read: 0x%X\n", b47n->curr_command);
+-}
+-
+-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 bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
+-
+-	switch (b47n->curr_command) {
+-	case NAND_CMD_SEQIN:
+-		bcm47xxnflash_ops_bcm4706_write(mtd, buf, len);
+-		return;
+-	}
+-
+-	pr_err("Invalid command for buf write: 0x%X\n", b47n->curr_command);
+-}
+-
+-/**************************************************
+- * Init
+- **************************************************/
+-
+-int bcm47xxnflash_ops_bcm4706_init(struct bcm47xxnflash *b47n)
+-{
+-	struct nand_chip *nand_chip = (struct nand_chip *)&b47n->nand_chip;
+-	int err;
+-	u32 freq;
+-	u16 clock;
+-	u8 w0, w1, w2, w3, w4;
+-
+-	unsigned long chipsize; /* MiB */
+-	u8 tbits, col_bits, col_size, row_bits, row_bsize;
+-	u32 val;
+-
+-	b47n->nand_chip.select_chip = bcm47xxnflash_ops_bcm4706_select_chip;
+-	nand_chip->cmd_ctrl = bcm47xxnflash_ops_bcm4706_cmd_ctrl;
+-	nand_chip->dev_ready = bcm47xxnflash_ops_bcm4706_dev_ready;
+-	b47n->nand_chip.cmdfunc = bcm47xxnflash_ops_bcm4706_cmdfunc;
+-	b47n->nand_chip.read_byte = bcm47xxnflash_ops_bcm4706_read_byte;
+-	b47n->nand_chip.read_buf = bcm47xxnflash_ops_bcm4706_read_buf;
+-	b47n->nand_chip.write_buf = bcm47xxnflash_ops_bcm4706_write_buf;
+-	b47n->nand_chip.onfi_set_features = nand_onfi_get_set_features_notsupp;
+-	b47n->nand_chip.onfi_get_features = nand_onfi_get_set_features_notsupp;
+-
+-	nand_chip->chip_delay = 50;
+-	b47n->nand_chip.bbt_options = NAND_BBT_USE_FLASH;
+-	b47n->nand_chip.ecc.mode = NAND_ECC_NONE; /* TODO: implement ECC */
+-
+-	/* Enable NAND flash access */
+-	bcma_cc_set32(b47n->cc, BCMA_CC_4706_FLASHSCFG,
+-		      BCMA_CC_4706_FLASHSCFG_NF1);
+-
+-	/* Configure wait counters */
+-	if (b47n->cc->status & BCMA_CC_CHIPST_4706_PKG_OPTION) {
+-		/* 400 MHz */
+-		freq = 400000000 / 4;
+-	} else {
+-		freq = bcma_chipco_pll_read(b47n->cc, 4);
+-		freq = (freq & 0xFFF) >> 3;
+-		/* Fixed reference clock 25 MHz and m = 2 */
+-		freq = (freq * 25000000 / 2) / 4;
+-	}
+-	clock = freq / 1000000;
+-	w0 = bcm47xxnflash_ops_bcm4706_ns_to_cycle(15, clock);
+-	w1 = bcm47xxnflash_ops_bcm4706_ns_to_cycle(20, clock);
+-	w2 = bcm47xxnflash_ops_bcm4706_ns_to_cycle(10, clock);
+-	w3 = bcm47xxnflash_ops_bcm4706_ns_to_cycle(10, clock);
+-	w4 = bcm47xxnflash_ops_bcm4706_ns_to_cycle(100, clock);
+-	bcma_cc_write32(b47n->cc, BCMA_CC_NFLASH_WAITCNT0,
+-			(w4 << 24 | w3 << 18 | w2 << 12 | w1 << 6 | w0));
+-
+-	/* Scan NAND */
+-	err = nand_scan(nand_to_mtd(&b47n->nand_chip), 1);
+-	if (err) {
+-		pr_err("Could not scan NAND flash: %d\n", err);
+-		goto exit;
+-	}
+-
+-	/* Configure FLASH */
+-	chipsize = b47n->nand_chip.chipsize >> 20;
+-	tbits = ffs(chipsize); /* find first bit set */
+-	if (!tbits || tbits != fls(chipsize)) {
+-		pr_err("Invalid flash size: 0x%lX\n", chipsize);
+-		err = -ENOTSUPP;
+-		goto exit;
+-	}
+-	tbits += 19; /* Broadcom increases *index* by 20, we increase *pos* */
+-
+-	col_bits = b47n->nand_chip.page_shift + 1;
+-	col_size = (col_bits + 7) / 8;
+-
+-	row_bits = tbits - col_bits + 1;
+-	row_bsize = (row_bits + 7) / 8;
+-
+-	val = ((row_bsize - 1) << 6) | ((col_size - 1) << 4) | 2;
+-	bcma_cc_write32(b47n->cc, BCMA_CC_NFLASH_CONF, val);
+-
+-exit:
+-	if (err)
+-		bcma_cc_mask32(b47n->cc, BCMA_CC_4706_FLASHSCFG,
+-			       ~BCMA_CC_4706_FLASHSCFG_NF1);
+-	return err;
+-}
+diff --git a/drivers/mtd/nand/bf5xx_nand.c b/drivers/mtd/nand/bf5xx_nand.c
+deleted file mode 100644
+index 5655dca..0000000
+--- a/drivers/mtd/nand/bf5xx_nand.c
++++ /dev/null
+@@ -1,860 +0,0 @@
+-/* linux/drivers/mtd/nand/bf5xx_nand.c
+- *
+- * Copyright 2006-2008 Analog Devices Inc.
+- *	http://blackfin.uclinux.org/
+- *	Bryan Wu <bryan.wu@analog.com>
+- *
+- * Blackfin BF5xx on-chip NAND flash controller driver
+- *
+- * Derived from drivers/mtd/nand/s3c2410.c
+- * Copyright (c) 2007 Ben Dooks <ben@simtec.co.uk>
+- *
+- * Derived from drivers/mtd/nand/cafe.c
+- * Copyright © 2006 Red Hat, Inc.
+- * Copyright © 2006 David Woodhouse <dwmw2@infradead.org>
+- *
+- * Changelog:
+- *	12-Jun-2007  Bryan Wu:  Initial version
+- *	18-Jul-2007  Bryan Wu:
+- *		- ECC_HW and ECC_SW supported
+- *		- DMA supported in ECC_HW
+- *		- YAFFS tested as rootfs in both ECC_HW and ECC_SW
+- *
+- * 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.
+- *
+- * You should have received a copy of the GNU General Public License
+- * along with this program; if not, write to the Free Software
+- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+-*/
+-
+-#include <linux/module.h>
+-#include <linux/types.h>
+-#include <linux/kernel.h>
+-#include <linux/string.h>
+-#include <linux/ioport.h>
+-#include <linux/platform_device.h>
+-#include <linux/delay.h>
+-#include <linux/dma-mapping.h>
+-#include <linux/err.h>
+-#include <linux/slab.h>
+-#include <linux/io.h>
+-#include <linux/bitops.h>
+-
+-#include <linux/mtd/mtd.h>
+-#include <linux/mtd/rawnand.h>
+-#include <linux/mtd/nand_ecc.h>
+-#include <linux/mtd/partitions.h>
+-
+-#include <asm/blackfin.h>
+-#include <asm/dma.h>
+-#include <asm/cacheflush.h>
+-#include <asm/nand.h>
+-#include <asm/portmux.h>
+-
+-#define DRV_NAME	"bf5xx-nand"
+-#define DRV_VERSION	"1.2"
+-#define DRV_AUTHOR	"Bryan Wu <bryan.wu@analog.com>"
+-#define DRV_DESC	"BF5xx on-chip NAND FLash Controller Driver"
+-
+-/* NFC_STAT Masks */
+-#define NBUSY       0x01  /* Not Busy */
+-#define WB_FULL     0x02  /* Write Buffer Full */
+-#define PG_WR_STAT  0x04  /* Page Write Pending */
+-#define PG_RD_STAT  0x08  /* Page Read Pending */
+-#define WB_EMPTY    0x10  /* Write Buffer Empty */
+-
+-/* NFC_IRQSTAT Masks */
+-#define NBUSYIRQ    0x01  /* Not Busy IRQ */
+-#define WB_OVF      0x02  /* Write Buffer Overflow */
+-#define WB_EDGE     0x04  /* Write Buffer Edge Detect */
+-#define RD_RDY      0x08  /* Read Data Ready */
+-#define WR_DONE     0x10  /* Page Write Done */
+-
+-/* NFC_RST Masks */
+-#define ECC_RST     0x01  /* ECC (and NFC counters) Reset */
+-
+-/* NFC_PGCTL Masks */
+-#define PG_RD_START 0x01  /* Page Read Start */
+-#define PG_WR_START 0x02  /* Page Write Start */
+-
+-#ifdef CONFIG_MTD_NAND_BF5XX_HWECC
+-static int hardware_ecc = 1;
+-#else
+-static int hardware_ecc;
+-#endif
+-
+-static const unsigned short bfin_nfc_pin_req[] =
+-	{P_NAND_CE,
+-	 P_NAND_RB,
+-	 P_NAND_D0,
+-	 P_NAND_D1,
+-	 P_NAND_D2,
+-	 P_NAND_D3,
+-	 P_NAND_D4,
+-	 P_NAND_D5,
+-	 P_NAND_D6,
+-	 P_NAND_D7,
+-	 P_NAND_WE,
+-	 P_NAND_RE,
+-	 P_NAND_CLE,
+-	 P_NAND_ALE,
+-	 0};
+-
+-#ifdef CONFIG_MTD_NAND_BF5XX_BOOTROM_ECC
+-static int bootrom_ooblayout_ecc(struct mtd_info *mtd, int section,
+-				 struct mtd_oob_region *oobregion)
+-{
+-	if (section > 7)
+-		return -ERANGE;
+-
+-	oobregion->offset = section * 8;
+-	oobregion->length = 3;
+-
+-	return 0;
+-}
+-
+-static int bootrom_ooblayout_free(struct mtd_info *mtd, int section,
+-				  struct mtd_oob_region *oobregion)
+-{
+-	if (section > 7)
+-		return -ERANGE;
+-
+-	oobregion->offset = (section * 8) + 3;
+-	oobregion->length = 5;
+-
+-	return 0;
+-}
+-
+-static const struct mtd_ooblayout_ops bootrom_ooblayout_ops = {
+-	.ecc = bootrom_ooblayout_ecc,
+-	.free = bootrom_ooblayout_free,
+-};
+-#endif
+-
+-/*
+- * Data structures for bf5xx nand flash controller driver
+- */
+-
+-/* bf5xx nand info */
+-struct bf5xx_nand_info {
+-	/* mtd info */
+-	struct nand_hw_control		controller;
+-	struct nand_chip		chip;
+-
+-	/* platform info */
+-	struct bf5xx_nand_platform	*platform;
+-
+-	/* device info */
+-	struct device			*device;
+-
+-	/* DMA stuff */
+-	struct completion		dma_completion;
+-};
+-
+-/*
+- * Conversion functions
+- */
+-static struct bf5xx_nand_info *mtd_to_nand_info(struct mtd_info *mtd)
+-{
+-	return container_of(mtd_to_nand(mtd), struct bf5xx_nand_info,
+-			    chip);
+-}
+-
+-static struct bf5xx_nand_info *to_nand_info(struct platform_device *pdev)
+-{
+-	return platform_get_drvdata(pdev);
+-}
+-
+-static struct bf5xx_nand_platform *to_nand_plat(struct platform_device *pdev)
+-{
+-	return dev_get_platdata(&pdev->dev);
+-}
+-
+-/*
+- * struct nand_chip interface function pointers
+- */
+-
+-/*
+- * bf5xx_nand_hwcontrol
+- *
+- * Issue command and address cycles to the chip
+- */
+-static void bf5xx_nand_hwcontrol(struct mtd_info *mtd, int cmd,
+-				   unsigned int ctrl)
+-{
+-	if (cmd == NAND_CMD_NONE)
+-		return;
+-
+-	while (bfin_read_NFC_STAT() & WB_FULL)
+-		cpu_relax();
+-
+-	if (ctrl & NAND_CLE)
+-		bfin_write_NFC_CMD(cmd);
+-	else if (ctrl & NAND_ALE)
+-		bfin_write_NFC_ADDR(cmd);
+-	SSYNC();
+-}
+-
+-/*
+- * bf5xx_nand_devready()
+- *
+- * returns 0 if the nand is busy, 1 if it is ready
+- */
+-static int bf5xx_nand_devready(struct mtd_info *mtd)
+-{
+-	unsigned short val = bfin_read_NFC_STAT();
+-
+-	if ((val & NBUSY) == NBUSY)
+-		return 1;
+-	else
+-		return 0;
+-}
+-
+-/*
+- * ECC functions
+- * These allow the bf5xx to use the controller's ECC
+- * generator block to ECC the data as it passes through
+- */
+-
+-/*
+- * ECC error correction function
+- */
+-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);
+-	u32 syndrome[5];
+-	u32 calced, stored;
+-	int i;
+-	unsigned short failing_bit, failing_byte;
+-	u_char data;
+-
+-	calced = calc_ecc[0] | (calc_ecc[1] << 8) | (calc_ecc[2] << 16);
+-	stored = read_ecc[0] | (read_ecc[1] << 8) | (read_ecc[2] << 16);
+-
+-	syndrome[0] = (calced ^ stored);
+-
+-	/*
+-	 * syndrome 0: all zero
+-	 * No error in data
+-	 * No action
+-	 */
+-	if (!syndrome[0] || !calced || !stored)
+-		return 0;
+-
+-	/*
+-	 * sysdrome 0: only one bit is one
+-	 * ECC data was incorrect
+-	 * No action
+-	 */
+-	if (hweight32(syndrome[0]) == 1) {
+-		dev_err(info->device, "ECC data was incorrect!\n");
+-		return -EBADMSG;
+-	}
+-
+-	syndrome[1] = (calced & 0x7FF) ^ (stored & 0x7FF);
+-	syndrome[2] = (calced & 0x7FF) ^ ((calced >> 11) & 0x7FF);
+-	syndrome[3] = (stored & 0x7FF) ^ ((stored >> 11) & 0x7FF);
+-	syndrome[4] = syndrome[2] ^ syndrome[3];
+-
+-	for (i = 0; i < 5; i++)
+-		dev_info(info->device, "syndrome[%d] 0x%08x\n", i, syndrome[i]);
+-
+-	dev_info(info->device,
+-		"calced[0x%08x], stored[0x%08x]\n",
+-		calced, stored);
+-
+-	/*
+-	 * sysdrome 0: exactly 11 bits are one, each parity
+-	 * and parity' pair is 1 & 0 or 0 & 1.
+-	 * 1-bit correctable error
+-	 * Correct the error
+-	 */
+-	if (hweight32(syndrome[0]) == 11 && syndrome[4] == 0x7FF) {
+-		dev_info(info->device,
+-			"1-bit correctable error, correct it.\n");
+-		dev_info(info->device,
+-			"syndrome[1] 0x%08x\n", syndrome[1]);
+-
+-		failing_bit = syndrome[1] & 0x7;
+-		failing_byte = syndrome[1] >> 0x3;
+-		data = *(dat + failing_byte);
+-		data = data ^ (0x1 << failing_bit);
+-		*(dat + failing_byte) = data;
+-
+-		return 1;
+-	}
+-
+-	/*
+-	 * sysdrome 0: random data
+-	 * More than 1-bit error, non-correctable error
+-	 * Discard data, mark bad block
+-	 */
+-	dev_err(info->device,
+-		"More than 1-bit error, non-correctable error.\n");
+-	dev_err(info->device,
+-		"Please discard data, mark bad block\n");
+-
+-	return -EBADMSG;
+-}
+-
+-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);
+-	int ret, bitflips = 0;
+-
+-	ret = bf5xx_nand_correct_data_256(mtd, dat, read_ecc, calc_ecc);
+-	if (ret < 0)
+-		return ret;
+-
+-	bitflips = ret;
+-
+-	/* If ecc size is 512, correct second 256 bytes */
+-	if (chip->ecc.size == 512) {
+-		dat += 256;
+-		read_ecc += 3;
+-		calc_ecc += 3;
+-		ret = bf5xx_nand_correct_data_256(mtd, dat, read_ecc, calc_ecc);
+-		if (ret < 0)
+-			return ret;
+-
+-		bitflips += ret;
+-	}
+-
+-	return bitflips;
+-}
+-
+-static void bf5xx_nand_enable_hwecc(struct mtd_info *mtd, int mode)
+-{
+-	return;
+-}
+-
+-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);
+-	u16 ecc0, ecc1;
+-	u32 code[2];
+-	u8 *p;
+-
+-	/* first 3 bytes ECC code for 256 page size */
+-	ecc0 = bfin_read_NFC_ECC0();
+-	ecc1 = bfin_read_NFC_ECC1();
+-
+-	code[0] = (ecc0 & 0x7ff) | ((ecc1 & 0x7ff) << 11);
+-
+-	dev_dbg(info->device, "returning ecc 0x%08x\n", code[0]);
+-
+-	p = (u8 *) code;
+-	memcpy(ecc_code, p, 3);
+-
+-	/* second 3 bytes ECC code for 512 ecc size */
+-	if (chip->ecc.size == 512) {
+-		ecc0 = bfin_read_NFC_ECC2();
+-		ecc1 = bfin_read_NFC_ECC3();
+-		code[1] = (ecc0 & 0x7ff) | ((ecc1 & 0x7ff) << 11);
+-
+-		/* second 3 bytes in ecc_code for second 256
+-		 * bytes of 512 page size
+-		 */
+-		p = (u8 *) (code + 1);
+-		memcpy((ecc_code + 3), p, 3);
+-		dev_dbg(info->device, "returning ecc 0x%08x\n", code[1]);
+-	}
+-
+-	return 0;
+-}
+-
+-/*
+- * PIO mode for buffer writing and reading
+- */
+-static void bf5xx_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+-{
+-	int i;
+-	unsigned short val;
+-
+-	/*
+-	 * Data reads are requested by first writing to NFC_DATA_RD
+-	 * and then reading back from NFC_READ.
+-	 */
+-	for (i = 0; i < len; i++) {
+-		while (bfin_read_NFC_STAT() & WB_FULL)
+-			cpu_relax();
+-
+-		/* Contents do not matter */
+-		bfin_write_NFC_DATA_RD(0x0000);
+-		SSYNC();
+-
+-		while ((bfin_read_NFC_IRQSTAT() & RD_RDY) != RD_RDY)
+-			cpu_relax();
+-
+-		buf[i] = bfin_read_NFC_READ();
+-
+-		val = bfin_read_NFC_IRQSTAT();
+-		val |= RD_RDY;
+-		bfin_write_NFC_IRQSTAT(val);
+-		SSYNC();
+-	}
+-}
+-
+-static uint8_t bf5xx_nand_read_byte(struct mtd_info *mtd)
+-{
+-	uint8_t val;
+-
+-	bf5xx_nand_read_buf(mtd, &val, 1);
+-
+-	return val;
+-}
+-
+-static void bf5xx_nand_write_buf(struct mtd_info *mtd,
+-				const uint8_t *buf, int len)
+-{
+-	int i;
+-
+-	for (i = 0; i < len; i++) {
+-		while (bfin_read_NFC_STAT() & WB_FULL)
+-			cpu_relax();
+-
+-		bfin_write_NFC_DATA_WR(buf[i]);
+-		SSYNC();
+-	}
+-}
+-
+-static void bf5xx_nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
+-{
+-	int i;
+-	u16 *p = (u16 *) buf;
+-	len >>= 1;
+-
+-	/*
+-	 * Data reads are requested by first writing to NFC_DATA_RD
+-	 * and then reading back from NFC_READ.
+-	 */
+-	bfin_write_NFC_DATA_RD(0x5555);
+-
+-	SSYNC();
+-
+-	for (i = 0; i < len; i++)
+-		p[i] = bfin_read_NFC_READ();
+-}
+-
+-static void bf5xx_nand_write_buf16(struct mtd_info *mtd,
+-				const uint8_t *buf, int len)
+-{
+-	int i;
+-	u16 *p = (u16 *) buf;
+-	len >>= 1;
+-
+-	for (i = 0; i < len; i++)
+-		bfin_write_NFC_DATA_WR(p[i]);
+-
+-	SSYNC();
+-}
+-
+-/*
+- * DMA functions for buffer writing and reading
+- */
+-static irqreturn_t bf5xx_nand_dma_irq(int irq, void *dev_id)
+-{
+-	struct bf5xx_nand_info *info = dev_id;
+-
+-	clear_dma_irqstat(CH_NFC);
+-	disable_dma(CH_NFC);
+-	complete(&info->dma_completion);
+-
+-	return IRQ_HANDLED;
+-}
+-
+-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);
+-	unsigned short val;
+-
+-	dev_dbg(info->device, " mtd->%p, buf->%p, is_read %d\n",
+-			mtd, buf, is_read);
+-
+-	/*
+-	 * Before starting a dma transfer, be sure to invalidate/flush
+-	 * the cache over the address range of your DMA buffer to
+-	 * prevent cache coherency problems. Otherwise very subtle bugs
+-	 * can be introduced to your driver.
+-	 */
+-	if (is_read)
+-		invalidate_dcache_range((unsigned int)buf,
+-				(unsigned int)(buf + chip->ecc.size));
+-	else
+-		flush_dcache_range((unsigned int)buf,
+-				(unsigned int)(buf + chip->ecc.size));
+-
+-	/*
+-	 * This register must be written before each page is
+-	 * transferred to generate the correct ECC register
+-	 * values.
+-	 */
+-	bfin_write_NFC_RST(ECC_RST);
+-	SSYNC();
+-	while (bfin_read_NFC_RST() & ECC_RST)
+-		cpu_relax();
+-
+-	disable_dma(CH_NFC);
+-	clear_dma_irqstat(CH_NFC);
+-
+-	/* setup DMA register with Blackfin DMA API */
+-	set_dma_config(CH_NFC, 0x0);
+-	set_dma_start_addr(CH_NFC, (unsigned long) buf);
+-
+-	/* The DMAs have different size on BF52x and BF54x */
+-#ifdef CONFIG_BF52x
+-	set_dma_x_count(CH_NFC, (chip->ecc.size >> 1));
+-	set_dma_x_modify(CH_NFC, 2);
+-	val = DI_EN | WDSIZE_16;
+-#endif
+-
+-#ifdef CONFIG_BF54x
+-	set_dma_x_count(CH_NFC, (chip->ecc.size >> 2));
+-	set_dma_x_modify(CH_NFC, 4);
+-	val = DI_EN | WDSIZE_32;
+-#endif
+-	/* setup write or read operation */
+-	if (is_read)
+-		val |= WNR;
+-	set_dma_config(CH_NFC, val);
+-	enable_dma(CH_NFC);
+-
+-	/* Start PAGE read/write operation */
+-	if (is_read)
+-		bfin_write_NFC_PGCTL(PG_RD_START);
+-	else
+-		bfin_write_NFC_PGCTL(PG_WR_START);
+-	wait_for_completion(&info->dma_completion);
+-}
+-
+-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);
+-
+-	dev_dbg(info->device, "mtd->%p, buf->%p, int %d\n", mtd, buf, len);
+-
+-	if (len == chip->ecc.size)
+-		bf5xx_nand_dma_rw(mtd, buf, 1);
+-	else
+-		bf5xx_nand_read_buf(mtd, buf, len);
+-}
+-
+-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);
+-
+-	dev_dbg(info->device, "mtd->%p, buf->%p, len %d\n", mtd, buf, len);
+-
+-	if (len == chip->ecc.size)
+-		bf5xx_nand_dma_rw(mtd, (uint8_t *)buf, 0);
+-	else
+-		bf5xx_nand_write_buf(mtd, buf, len);
+-}
+-
+-static int bf5xx_nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+-		uint8_t *buf, int oob_required, int page)
+-{
+-	bf5xx_nand_read_buf(mtd, buf, mtd->writesize);
+-	bf5xx_nand_read_buf(mtd, chip->oob_poi, mtd->oobsize);
+-
+-	return 0;
+-}
+-
+-static int bf5xx_nand_write_page_raw(struct mtd_info *mtd,
+-		struct nand_chip *chip,	const uint8_t *buf, int oob_required,
+-		int page)
+-{
+-	bf5xx_nand_write_buf(mtd, buf, mtd->writesize);
+-	bf5xx_nand_write_buf(mtd, chip->oob_poi, mtd->oobsize);
+-
+-	return 0;
+-}
+-
+-/*
+- * System initialization functions
+- */
+-static int bf5xx_nand_dma_init(struct bf5xx_nand_info *info)
+-{
+-	int ret;
+-
+-	/* Do not use dma */
+-	if (!hardware_ecc)
+-		return 0;
+-
+-	init_completion(&info->dma_completion);
+-
+-	/* Request NFC DMA channel */
+-	ret = request_dma(CH_NFC, "BF5XX NFC driver");
+-	if (ret < 0) {
+-		dev_err(info->device, " unable to get DMA channel\n");
+-		return ret;
+-	}
+-
+-#ifdef CONFIG_BF54x
+-	/* Setup DMAC1 channel mux for NFC which shared with SDH */
+-	bfin_write_DMAC1_PERIMUX(bfin_read_DMAC1_PERIMUX() & ~1);
+-	SSYNC();
+-#endif
+-
+-	set_dma_callback(CH_NFC, bf5xx_nand_dma_irq, info);
+-
+-	/* Turn off the DMA channel first */
+-	disable_dma(CH_NFC);
+-	return 0;
+-}
+-
+-static void bf5xx_nand_dma_remove(struct bf5xx_nand_info *info)
+-{
+-	/* Free NFC DMA channel */
+-	if (hardware_ecc)
+-		free_dma(CH_NFC);
+-}
+-
+-/*
+- * BF5XX NFC hardware initialization
+- *  - pin mux setup
+- *  - clear interrupt status
+- */
+-static int bf5xx_nand_hw_init(struct bf5xx_nand_info *info)
+-{
+-	int err = 0;
+-	unsigned short val;
+-	struct bf5xx_nand_platform *plat = info->platform;
+-
+-	/* setup NFC_CTL register */
+-	dev_info(info->device,
+-		"data_width=%d, wr_dly=%d, rd_dly=%d\n",
+-		(plat->data_width ? 16 : 8),
+-		plat->wr_dly, plat->rd_dly);
+-
+-	val = (1 << NFC_PG_SIZE_OFFSET) |
+-		(plat->data_width << NFC_NWIDTH_OFFSET) |
+-		(plat->rd_dly << NFC_RDDLY_OFFSET) |
+-		(plat->wr_dly << NFC_WRDLY_OFFSET);
+-	dev_dbg(info->device, "NFC_CTL is 0x%04x\n", val);
+-
+-	bfin_write_NFC_CTL(val);
+-	SSYNC();
+-
+-	/* clear interrupt status */
+-	bfin_write_NFC_IRQMASK(0x0);
+-	SSYNC();
+-	val = bfin_read_NFC_IRQSTAT();
+-	bfin_write_NFC_IRQSTAT(val);
+-	SSYNC();
+-
+-	/* DMA initialization  */
+-	if (bf5xx_nand_dma_init(info))
+-		err = -ENXIO;
+-
+-	return err;
+-}
+-
+-/*
+- * Device management interface
+- */
+-static int bf5xx_nand_add_partition(struct bf5xx_nand_info *info)
+-{
+-	struct mtd_info *mtd = nand_to_mtd(&info->chip);
+-	struct mtd_partition *parts = info->platform->partitions;
+-	int nr = info->platform->nr_partitions;
+-
+-	return mtd_device_register(mtd, parts, nr);
+-}
+-
+-static int bf5xx_nand_remove(struct platform_device *pdev)
+-{
+-	struct bf5xx_nand_info *info = to_nand_info(pdev);
+-
+-	/* first thing we need to do is release all our mtds
+-	 * and their partitions, then go through freeing the
+-	 * resources used
+-	 */
+-	nand_release(nand_to_mtd(&info->chip));
+-
+-	peripheral_free_list(bfin_nfc_pin_req);
+-	bf5xx_nand_dma_remove(info);
+-
+-	return 0;
+-}
+-
+-static int bf5xx_nand_scan(struct mtd_info *mtd)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	int ret;
+-
+-	ret = nand_scan_ident(mtd, 1, NULL);
+-	if (ret)
+-		return ret;
+-
+-	if (hardware_ecc) {
+-		/*
+-		 * for nand with page size > 512B, think it as several sections with 512B
+-		 */
+-		if (likely(mtd->writesize >= 512)) {
+-			chip->ecc.size = 512;
+-			chip->ecc.bytes = 6;
+-			chip->ecc.strength = 2;
+-		} else {
+-			chip->ecc.size = 256;
+-			chip->ecc.bytes = 3;
+-			chip->ecc.strength = 1;
+-			bfin_write_NFC_CTL(bfin_read_NFC_CTL() & ~(1 << NFC_PG_SIZE_OFFSET));
+-			SSYNC();
+-		}
+-	}
+-
+-	return	nand_scan_tail(mtd);
+-}
+-
+-/*
+- * bf5xx_nand_probe
+- *
+- * called by device layer when it finds a device matching
+- * one our driver can handled. This code checks to see if
+- * it can allocate all necessary resources then calls the
+- * nand layer to look for devices
+- */
+-static int bf5xx_nand_probe(struct platform_device *pdev)
+-{
+-	struct bf5xx_nand_platform *plat = to_nand_plat(pdev);
+-	struct bf5xx_nand_info *info = NULL;
+-	struct nand_chip *chip = NULL;
+-	struct mtd_info *mtd = NULL;
+-	int err = 0;
+-
+-	dev_dbg(&pdev->dev, "(%p)\n", pdev);
+-
+-	if (!plat) {
+-		dev_err(&pdev->dev, "no platform specific information\n");
+-		return -EINVAL;
+-	}
+-
+-	if (peripheral_request_list(bfin_nfc_pin_req, DRV_NAME)) {
+-		dev_err(&pdev->dev, "requesting Peripherals failed\n");
+-		return -EFAULT;
+-	}
+-
+-	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
+-	if (info == NULL) {
+-		err = -ENOMEM;
+-		goto out_err;
+-	}
+-
+-	platform_set_drvdata(pdev, info);
+-
+-	nand_hw_control_init(&info->controller);
+-
+-	info->device     = &pdev->dev;
+-	info->platform   = plat;
+-
+-	/* initialise chip data struct */
+-	chip = &info->chip;
+-	mtd = nand_to_mtd(&info->chip);
+-
+-	if (plat->data_width)
+-		chip->options |= NAND_BUSWIDTH_16;
+-
+-	chip->options |= NAND_CACHEPRG | NAND_SKIP_BBTSCAN;
+-
+-	chip->read_buf = (plat->data_width) ?
+-		bf5xx_nand_read_buf16 : bf5xx_nand_read_buf;
+-	chip->write_buf = (plat->data_width) ?
+-		bf5xx_nand_write_buf16 : bf5xx_nand_write_buf;
+-
+-	chip->read_byte    = bf5xx_nand_read_byte;
+-
+-	chip->cmd_ctrl     = bf5xx_nand_hwcontrol;
+-	chip->dev_ready    = bf5xx_nand_devready;
+-
+-	nand_set_controller_data(chip, mtd);
+-	chip->controller   = &info->controller;
+-
+-	chip->IO_ADDR_R    = (void __iomem *) NFC_READ;
+-	chip->IO_ADDR_W    = (void __iomem *) NFC_DATA_WR;
+-
+-	chip->chip_delay   = 0;
+-
+-	/* initialise mtd info data struct */
+-	mtd->dev.parent = &pdev->dev;
+-
+-	/* initialise the hardware */
+-	err = bf5xx_nand_hw_init(info);
+-	if (err)
+-		goto out_err;
+-
+-	/* setup hardware ECC data struct */
+-	if (hardware_ecc) {
+-#ifdef CONFIG_MTD_NAND_BF5XX_BOOTROM_ECC
+-		mtd_set_ooblayout(mtd, &bootrom_ooblayout_ops);
+-#endif
+-		chip->read_buf      = bf5xx_nand_dma_read_buf;
+-		chip->write_buf     = bf5xx_nand_dma_write_buf;
+-		chip->ecc.calculate = bf5xx_nand_calculate_ecc;
+-		chip->ecc.correct   = bf5xx_nand_correct_data;
+-		chip->ecc.mode	    = NAND_ECC_HW;
+-		chip->ecc.hwctl	    = bf5xx_nand_enable_hwecc;
+-		chip->ecc.read_page_raw = bf5xx_nand_read_page_raw;
+-		chip->ecc.write_page_raw = bf5xx_nand_write_page_raw;
+-	} else {
+-		chip->ecc.mode	    = NAND_ECC_SOFT;
+-		chip->ecc.algo	= NAND_ECC_HAMMING;
+-	}
+-
+-	/* scan hardware nand chip and setup mtd info data struct */
+-	if (bf5xx_nand_scan(mtd)) {
+-		err = -ENXIO;
+-		goto out_err_nand_scan;
+-	}
+-
+-#ifdef CONFIG_MTD_NAND_BF5XX_BOOTROM_ECC
+-	chip->badblockpos = 63;
+-#endif
+-
+-	/* add NAND partition */
+-	bf5xx_nand_add_partition(info);
+-
+-	dev_dbg(&pdev->dev, "initialised ok\n");
+-	return 0;
+-
+-out_err_nand_scan:
+-	bf5xx_nand_dma_remove(info);
+-out_err:
+-	peripheral_free_list(bfin_nfc_pin_req);
+-
+-	return err;
+-}
+-
+-/* driver device registration */
+-static struct platform_driver bf5xx_nand_driver = {
+-	.probe		= bf5xx_nand_probe,
+-	.remove		= bf5xx_nand_remove,
+-	.driver		= {
+-		.name	= DRV_NAME,
+-	},
+-};
+-
+-module_platform_driver(bf5xx_nand_driver);
+-
+-MODULE_LICENSE("GPL");
+-MODULE_AUTHOR(DRV_AUTHOR);
+-MODULE_DESCRIPTION(DRV_DESC);
+-MODULE_ALIAS("platform:" DRV_NAME);
+diff --git a/drivers/mtd/nand/brcmnand/Makefile b/drivers/mtd/nand/brcmnand/Makefile
+deleted file mode 100644
+index 195b845..0000000
+--- a/drivers/mtd/nand/brcmnand/Makefile
++++ /dev/null
+@@ -1,8 +0,0 @@
+-# SPDX-License-Identifier: GPL-2.0
+-# link order matters; don't link the more generic brcmstb_nand.o before the
+-# more specific iproc_nand.o, for instance
+-obj-$(CONFIG_MTD_NAND_BRCMNAND)		+= iproc_nand.o
+-obj-$(CONFIG_MTD_NAND_BRCMNAND)		+= bcm63138_nand.o
+-obj-$(CONFIG_MTD_NAND_BRCMNAND)		+= bcm6368_nand.o
+-obj-$(CONFIG_MTD_NAND_BRCMNAND)		+= brcmstb_nand.o
+-obj-$(CONFIG_MTD_NAND_BRCMNAND)		+= brcmnand.o
+diff --git a/drivers/mtd/nand/brcmnand/bcm63138_nand.c b/drivers/mtd/nand/brcmnand/bcm63138_nand.c
+deleted file mode 100644
+index 59444b3..0000000
+--- a/drivers/mtd/nand/brcmnand/bcm63138_nand.c
++++ /dev/null
+@@ -1,109 +0,0 @@
+-/*
+- * Copyright © 2015 Broadcom Corporation
+- *
+- * 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/device.h>
+-#include <linux/io.h>
+-#include <linux/ioport.h>
+-#include <linux/module.h>
+-#include <linux/of.h>
+-#include <linux/of_address.h>
+-#include <linux/platform_device.h>
+-#include <linux/slab.h>
+-
+-#include "brcmnand.h"
+-
+-struct bcm63138_nand_soc {
+-	struct brcmnand_soc soc;
+-	void __iomem *base;
+-};
+-
+-#define BCM63138_NAND_INT_STATUS		0x00
+-#define BCM63138_NAND_INT_EN			0x04
+-
+-enum {
+-	BCM63138_CTLRDY		= BIT(4),
+-};
+-
+-static bool bcm63138_nand_intc_ack(struct brcmnand_soc *soc)
+-{
+-	struct bcm63138_nand_soc *priv =
+-			container_of(soc, struct bcm63138_nand_soc, soc);
+-	void __iomem *mmio = priv->base + BCM63138_NAND_INT_STATUS;
+-	u32 val = brcmnand_readl(mmio);
+-
+-	if (val & BCM63138_CTLRDY) {
+-		brcmnand_writel(val & ~BCM63138_CTLRDY, mmio);
+-		return true;
+-	}
+-
+-	return false;
+-}
+-
+-static void bcm63138_nand_intc_set(struct brcmnand_soc *soc, bool en)
+-{
+-	struct bcm63138_nand_soc *priv =
+-			container_of(soc, struct bcm63138_nand_soc, soc);
+-	void __iomem *mmio = priv->base + BCM63138_NAND_INT_EN;
+-	u32 val = brcmnand_readl(mmio);
+-
+-	if (en)
+-		val |= BCM63138_CTLRDY;
+-	else
+-		val &= ~BCM63138_CTLRDY;
+-
+-	brcmnand_writel(val, mmio);
+-}
+-
+-static int bcm63138_nand_probe(struct platform_device *pdev)
+-{
+-	struct device *dev = &pdev->dev;
+-	struct bcm63138_nand_soc *priv;
+-	struct brcmnand_soc *soc;
+-	struct resource *res;
+-
+-	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+-	if (!priv)
+-		return -ENOMEM;
+-	soc = &priv->soc;
+-
+-	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand-int-base");
+-	priv->base = devm_ioremap_resource(dev, res);
+-	if (IS_ERR(priv->base))
+-		return PTR_ERR(priv->base);
+-
+-	soc->ctlrdy_ack = bcm63138_nand_intc_ack;
+-	soc->ctlrdy_set_enabled = bcm63138_nand_intc_set;
+-
+-	return brcmnand_probe(pdev, soc);
+-}
+-
+-static const struct of_device_id bcm63138_nand_of_match[] = {
+-	{ .compatible = "brcm,nand-bcm63138" },
+-	{},
+-};
+-MODULE_DEVICE_TABLE(of, bcm63138_nand_of_match);
+-
+-static struct platform_driver bcm63138_nand_driver = {
+-	.probe			= bcm63138_nand_probe,
+-	.remove			= brcmnand_remove,
+-	.driver = {
+-		.name		= "bcm63138_nand",
+-		.pm		= &brcmnand_pm_ops,
+-		.of_match_table	= bcm63138_nand_of_match,
+-	}
+-};
+-module_platform_driver(bcm63138_nand_driver);
+-
+-MODULE_LICENSE("GPL v2");
+-MODULE_AUTHOR("Brian Norris");
+-MODULE_DESCRIPTION("NAND driver for BCM63138");
+diff --git a/drivers/mtd/nand/brcmnand/bcm6368_nand.c b/drivers/mtd/nand/brcmnand/bcm6368_nand.c
+deleted file mode 100644
+index 34c91b0..0000000
+--- a/drivers/mtd/nand/brcmnand/bcm6368_nand.c
++++ /dev/null
+@@ -1,142 +0,0 @@
+-/*
+- * Copyright 2015 Simon Arlott
+- *
+- * 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.
+- *
+- * Derived from bcm63138_nand.c:
+- * Copyright © 2015 Broadcom Corporation
+- *
+- * Derived from bcm963xx_4.12L.06B_consumer/shared/opensource/include/bcm963xx/63268_map_part.h:
+- * Copyright 2000-2010 Broadcom Corporation
+- *
+- * Derived from bcm963xx_4.12L.06B_consumer/shared/opensource/flash/nandflash.c:
+- * Copyright 2000-2010 Broadcom Corporation
+- */
+-
+-#include <linux/device.h>
+-#include <linux/io.h>
+-#include <linux/ioport.h>
+-#include <linux/module.h>
+-#include <linux/of.h>
+-#include <linux/of_address.h>
+-#include <linux/platform_device.h>
+-#include <linux/slab.h>
+-
+-#include "brcmnand.h"
+-
+-struct bcm6368_nand_soc {
+-	struct brcmnand_soc soc;
+-	void __iomem *base;
+-};
+-
+-#define BCM6368_NAND_INT		0x00
+-#define  BCM6368_NAND_STATUS_SHIFT	0
+-#define  BCM6368_NAND_STATUS_MASK	(0xfff << BCM6368_NAND_STATUS_SHIFT)
+-#define  BCM6368_NAND_ENABLE_SHIFT	16
+-#define  BCM6368_NAND_ENABLE_MASK	(0xffff << BCM6368_NAND_ENABLE_SHIFT)
+-#define BCM6368_NAND_BASE_ADDR0	0x04
+-#define BCM6368_NAND_BASE_ADDR1	0x0c
+-
+-enum {
+-	BCM6368_NP_READ		= BIT(0),
+-	BCM6368_BLOCK_ERASE	= BIT(1),
+-	BCM6368_COPY_BACK	= BIT(2),
+-	BCM6368_PAGE_PGM	= BIT(3),
+-	BCM6368_CTRL_READY	= BIT(4),
+-	BCM6368_DEV_RBPIN	= BIT(5),
+-	BCM6368_ECC_ERR_UNC	= BIT(6),
+-	BCM6368_ECC_ERR_CORR	= BIT(7),
+-};
+-
+-static bool bcm6368_nand_intc_ack(struct brcmnand_soc *soc)
+-{
+-	struct bcm6368_nand_soc *priv =
+-			container_of(soc, struct bcm6368_nand_soc, soc);
+-	void __iomem *mmio = priv->base + BCM6368_NAND_INT;
+-	u32 val = brcmnand_readl(mmio);
+-
+-	if (val & (BCM6368_CTRL_READY << BCM6368_NAND_STATUS_SHIFT)) {
+-		/* Ack interrupt */
+-		val &= ~BCM6368_NAND_STATUS_MASK;
+-		val |= BCM6368_CTRL_READY << BCM6368_NAND_STATUS_SHIFT;
+-		brcmnand_writel(val, mmio);
+-		return true;
+-	}
+-
+-	return false;
+-}
+-
+-static void bcm6368_nand_intc_set(struct brcmnand_soc *soc, bool en)
+-{
+-	struct bcm6368_nand_soc *priv =
+-			container_of(soc, struct bcm6368_nand_soc, soc);
+-	void __iomem *mmio = priv->base + BCM6368_NAND_INT;
+-	u32 val = brcmnand_readl(mmio);
+-
+-	/* Don't ack any interrupts */
+-	val &= ~BCM6368_NAND_STATUS_MASK;
+-
+-	if (en)
+-		val |= BCM6368_CTRL_READY << BCM6368_NAND_ENABLE_SHIFT;
+-	else
+-		val &= ~(BCM6368_CTRL_READY << BCM6368_NAND_ENABLE_SHIFT);
+-
+-	brcmnand_writel(val, mmio);
+-}
+-
+-static int bcm6368_nand_probe(struct platform_device *pdev)
+-{
+-	struct device *dev = &pdev->dev;
+-	struct bcm6368_nand_soc *priv;
+-	struct brcmnand_soc *soc;
+-	struct resource *res;
+-
+-	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+-	if (!priv)
+-		return -ENOMEM;
+-	soc = &priv->soc;
+-
+-	res = platform_get_resource_byname(pdev,
+-		IORESOURCE_MEM, "nand-int-base");
+-	priv->base = devm_ioremap_resource(dev, res);
+-	if (IS_ERR(priv->base))
+-		return PTR_ERR(priv->base);
+-
+-	soc->ctlrdy_ack = bcm6368_nand_intc_ack;
+-	soc->ctlrdy_set_enabled = bcm6368_nand_intc_set;
+-
+-	/* Disable and ack all interrupts  */
+-	brcmnand_writel(0, priv->base + BCM6368_NAND_INT);
+-	brcmnand_writel(BCM6368_NAND_STATUS_MASK,
+-			priv->base + BCM6368_NAND_INT);
+-
+-	return brcmnand_probe(pdev, soc);
+-}
+-
+-static const struct of_device_id bcm6368_nand_of_match[] = {
+-	{ .compatible = "brcm,nand-bcm6368" },
+-	{},
+-};
+-MODULE_DEVICE_TABLE(of, bcm6368_nand_of_match);
+-
+-static struct platform_driver bcm6368_nand_driver = {
+-	.probe			= bcm6368_nand_probe,
+-	.remove			= brcmnand_remove,
+-	.driver = {
+-		.name		= "bcm6368_nand",
+-		.pm		= &brcmnand_pm_ops,
+-		.of_match_table	= bcm6368_nand_of_match,
+-	}
+-};
+-module_platform_driver(bcm6368_nand_driver);
+-
+-MODULE_LICENSE("GPL");
+-MODULE_AUTHOR("Simon Arlott");
+-MODULE_DESCRIPTION("NAND driver for BCM6368");
+diff --git a/drivers/mtd/nand/brcmnand/brcmnand.c b/drivers/mtd/nand/brcmnand/brcmnand.c
+deleted file mode 100644
+index e0eb51d..0000000
+--- a/drivers/mtd/nand/brcmnand/brcmnand.c
++++ /dev/null
+@@ -1,2618 +0,0 @@
+-/*
+- * Copyright © 2010-2015 Broadcom Corporation
+- *
+- * 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/clk.h>
+-#include <linux/version.h>
+-#include <linux/module.h>
+-#include <linux/init.h>
+-#include <linux/delay.h>
+-#include <linux/device.h>
+-#include <linux/platform_device.h>
+-#include <linux/err.h>
+-#include <linux/completion.h>
+-#include <linux/interrupt.h>
+-#include <linux/spinlock.h>
+-#include <linux/dma-mapping.h>
+-#include <linux/ioport.h>
+-#include <linux/bug.h>
+-#include <linux/kernel.h>
+-#include <linux/bitops.h>
+-#include <linux/mm.h>
+-#include <linux/mtd/mtd.h>
+-#include <linux/mtd/rawnand.h>
+-#include <linux/mtd/partitions.h>
+-#include <linux/of.h>
+-#include <linux/of_platform.h>
+-#include <linux/slab.h>
+-#include <linux/list.h>
+-#include <linux/log2.h>
+-
+-#include "brcmnand.h"
+-
+-/*
+- * This flag controls if WP stays on between erase/write commands to mitigate
+- * flash corruption due to power glitches. Values:
+- * 0: NAND_WP is not used or not available
+- * 1: NAND_WP is set by default, cleared for erase/write operations
+- * 2: NAND_WP is always cleared
+- */
+-static int wp_on = 1;
+-module_param(wp_on, int, 0444);
+-
+-/***********************************************************************
+- * Definitions
+- ***********************************************************************/
+-
+-#define DRV_NAME			"brcmnand"
+-
+-#define CMD_NULL			0x00
+-#define CMD_PAGE_READ			0x01
+-#define CMD_SPARE_AREA_READ		0x02
+-#define CMD_STATUS_READ			0x03
+-#define CMD_PROGRAM_PAGE		0x04
+-#define CMD_PROGRAM_SPARE_AREA		0x05
+-#define CMD_COPY_BACK			0x06
+-#define CMD_DEVICE_ID_READ		0x07
+-#define CMD_BLOCK_ERASE			0x08
+-#define CMD_FLASH_RESET			0x09
+-#define CMD_BLOCKS_LOCK			0x0a
+-#define CMD_BLOCKS_LOCK_DOWN		0x0b
+-#define CMD_BLOCKS_UNLOCK		0x0c
+-#define CMD_READ_BLOCKS_LOCK_STATUS	0x0d
+-#define CMD_PARAMETER_READ		0x0e
+-#define CMD_PARAMETER_CHANGE_COL	0x0f
+-#define CMD_LOW_LEVEL_OP		0x10
+-
+-struct brcm_nand_dma_desc {
+-	u32 next_desc;
+-	u32 next_desc_ext;
+-	u32 cmd_irq;
+-	u32 dram_addr;
+-	u32 dram_addr_ext;
+-	u32 tfr_len;
+-	u32 total_len;
+-	u32 flash_addr;
+-	u32 flash_addr_ext;
+-	u32 cs;
+-	u32 pad2[5];
+-	u32 status_valid;
+-} __packed;
+-
+-/* Bitfields for brcm_nand_dma_desc::status_valid */
+-#define FLASH_DMA_ECC_ERROR	(1 << 8)
+-#define FLASH_DMA_CORR_ERROR	(1 << 9)
+-
+-/* 512B flash cache in the NAND controller HW */
+-#define FC_SHIFT		9U
+-#define FC_BYTES		512U
+-#define FC_WORDS		(FC_BYTES >> 2)
+-
+-#define BRCMNAND_MIN_PAGESIZE	512
+-#define BRCMNAND_MIN_BLOCKSIZE	(8 * 1024)
+-#define BRCMNAND_MIN_DEVSIZE	(4ULL * 1024 * 1024)
+-
+-#define NAND_CTRL_RDY			(INTFC_CTLR_READY | INTFC_FLASH_READY)
+-#define NAND_POLL_STATUS_TIMEOUT_MS	100
+-
+-/* Controller feature flags */
+-enum {
+-	BRCMNAND_HAS_1K_SECTORS			= BIT(0),
+-	BRCMNAND_HAS_PREFETCH			= BIT(1),
+-	BRCMNAND_HAS_CACHE_MODE			= BIT(2),
+-	BRCMNAND_HAS_WP				= BIT(3),
+-};
+-
+-struct brcmnand_controller {
+-	struct device		*dev;
+-	struct nand_hw_control	controller;
+-	void __iomem		*nand_base;
+-	void __iomem		*nand_fc; /* flash cache */
+-	void __iomem		*flash_dma_base;
+-	unsigned int		irq;
+-	unsigned int		dma_irq;
+-	int			nand_version;
+-
+-	/* Some SoCs provide custom interrupt status register(s) */
+-	struct brcmnand_soc	*soc;
+-
+-	/* Some SoCs have a gateable clock for the controller */
+-	struct clk		*clk;
+-
+-	int			cmd_pending;
+-	bool			dma_pending;
+-	struct completion	done;
+-	struct completion	dma_done;
+-
+-	/* List of NAND hosts (one for each chip-select) */
+-	struct list_head host_list;
+-
+-	struct brcm_nand_dma_desc *dma_desc;
+-	dma_addr_t		dma_pa;
+-
+-	/* in-memory cache of the FLASH_CACHE, used only for some commands */
+-	u8			flash_cache[FC_BYTES];
+-
+-	/* Controller revision details */
+-	const u16		*reg_offsets;
+-	unsigned int		reg_spacing; /* between CS1, CS2, ... regs */
+-	const u8		*cs_offsets; /* within each chip-select */
+-	const u8		*cs0_offsets; /* within CS0, if different */
+-	unsigned int		max_block_size;
+-	const unsigned int	*block_sizes;
+-	unsigned int		max_page_size;
+-	const unsigned int	*page_sizes;
+-	unsigned int		max_oob;
+-	u32			features;
+-
+-	/* for low-power standby/resume only */
+-	u32			nand_cs_nand_select;
+-	u32			nand_cs_nand_xor;
+-	u32			corr_stat_threshold;
+-	u32			flash_dma_mode;
+-};
+-
+-struct brcmnand_cfg {
+-	u64			device_size;
+-	unsigned int		block_size;
+-	unsigned int		page_size;
+-	unsigned int		spare_area_size;
+-	unsigned int		device_width;
+-	unsigned int		col_adr_bytes;
+-	unsigned int		blk_adr_bytes;
+-	unsigned int		ful_adr_bytes;
+-	unsigned int		sector_size_1k;
+-	unsigned int		ecc_level;
+-	/* use for low-power standby/resume only */
+-	u32			acc_control;
+-	u32			config;
+-	u32			config_ext;
+-	u32			timing_1;
+-	u32			timing_2;
+-};
+-
+-struct brcmnand_host {
+-	struct list_head	node;
+-
+-	struct nand_chip	chip;
+-	struct platform_device	*pdev;
+-	int			cs;
+-
+-	unsigned int		last_cmd;
+-	unsigned int		last_byte;
+-	u64			last_addr;
+-	struct brcmnand_cfg	hwcfg;
+-	struct brcmnand_controller *ctrl;
+-};
+-
+-enum brcmnand_reg {
+-	BRCMNAND_CMD_START = 0,
+-	BRCMNAND_CMD_EXT_ADDRESS,
+-	BRCMNAND_CMD_ADDRESS,
+-	BRCMNAND_INTFC_STATUS,
+-	BRCMNAND_CS_SELECT,
+-	BRCMNAND_CS_XOR,
+-	BRCMNAND_LL_OP,
+-	BRCMNAND_CS0_BASE,
+-	BRCMNAND_CS1_BASE,		/* CS1 regs, if non-contiguous */
+-	BRCMNAND_CORR_THRESHOLD,
+-	BRCMNAND_CORR_THRESHOLD_EXT,
+-	BRCMNAND_UNCORR_COUNT,
+-	BRCMNAND_CORR_COUNT,
+-	BRCMNAND_CORR_EXT_ADDR,
+-	BRCMNAND_CORR_ADDR,
+-	BRCMNAND_UNCORR_EXT_ADDR,
+-	BRCMNAND_UNCORR_ADDR,
+-	BRCMNAND_SEMAPHORE,
+-	BRCMNAND_ID,
+-	BRCMNAND_ID_EXT,
+-	BRCMNAND_LL_RDATA,
+-	BRCMNAND_OOB_READ_BASE,
+-	BRCMNAND_OOB_READ_10_BASE,	/* offset 0x10, if non-contiguous */
+-	BRCMNAND_OOB_WRITE_BASE,
+-	BRCMNAND_OOB_WRITE_10_BASE,	/* offset 0x10, if non-contiguous */
+-	BRCMNAND_FC_BASE,
+-};
+-
+-/* BRCMNAND v4.0 */
+-static const u16 brcmnand_regs_v40[] = {
+-	[BRCMNAND_CMD_START]		=  0x04,
+-	[BRCMNAND_CMD_EXT_ADDRESS]	=  0x08,
+-	[BRCMNAND_CMD_ADDRESS]		=  0x0c,
+-	[BRCMNAND_INTFC_STATUS]		=  0x6c,
+-	[BRCMNAND_CS_SELECT]		=  0x14,
+-	[BRCMNAND_CS_XOR]		=  0x18,
+-	[BRCMNAND_LL_OP]		= 0x178,
+-	[BRCMNAND_CS0_BASE]		=  0x40,
+-	[BRCMNAND_CS1_BASE]		=  0xd0,
+-	[BRCMNAND_CORR_THRESHOLD]	=  0x84,
+-	[BRCMNAND_CORR_THRESHOLD_EXT]	=     0,
+-	[BRCMNAND_UNCORR_COUNT]		=     0,
+-	[BRCMNAND_CORR_COUNT]		=     0,
+-	[BRCMNAND_CORR_EXT_ADDR]	=  0x70,
+-	[BRCMNAND_CORR_ADDR]		=  0x74,
+-	[BRCMNAND_UNCORR_EXT_ADDR]	=  0x78,
+-	[BRCMNAND_UNCORR_ADDR]		=  0x7c,
+-	[BRCMNAND_SEMAPHORE]		=  0x58,
+-	[BRCMNAND_ID]			=  0x60,
+-	[BRCMNAND_ID_EXT]		=  0x64,
+-	[BRCMNAND_LL_RDATA]		= 0x17c,
+-	[BRCMNAND_OOB_READ_BASE]	=  0x20,
+-	[BRCMNAND_OOB_READ_10_BASE]	= 0x130,
+-	[BRCMNAND_OOB_WRITE_BASE]	=  0x30,
+-	[BRCMNAND_OOB_WRITE_10_BASE]	=     0,
+-	[BRCMNAND_FC_BASE]		= 0x200,
+-};
+-
+-/* BRCMNAND v5.0 */
+-static const u16 brcmnand_regs_v50[] = {
+-	[BRCMNAND_CMD_START]		=  0x04,
+-	[BRCMNAND_CMD_EXT_ADDRESS]	=  0x08,
+-	[BRCMNAND_CMD_ADDRESS]		=  0x0c,
+-	[BRCMNAND_INTFC_STATUS]		=  0x6c,
+-	[BRCMNAND_CS_SELECT]		=  0x14,
+-	[BRCMNAND_CS_XOR]		=  0x18,
+-	[BRCMNAND_LL_OP]		= 0x178,
+-	[BRCMNAND_CS0_BASE]		=  0x40,
+-	[BRCMNAND_CS1_BASE]		=  0xd0,
+-	[BRCMNAND_CORR_THRESHOLD]	=  0x84,
+-	[BRCMNAND_CORR_THRESHOLD_EXT]	=     0,
+-	[BRCMNAND_UNCORR_COUNT]		=     0,
+-	[BRCMNAND_CORR_COUNT]		=     0,
+-	[BRCMNAND_CORR_EXT_ADDR]	=  0x70,
+-	[BRCMNAND_CORR_ADDR]		=  0x74,
+-	[BRCMNAND_UNCORR_EXT_ADDR]	=  0x78,
+-	[BRCMNAND_UNCORR_ADDR]		=  0x7c,
+-	[BRCMNAND_SEMAPHORE]		=  0x58,
+-	[BRCMNAND_ID]			=  0x60,
+-	[BRCMNAND_ID_EXT]		=  0x64,
+-	[BRCMNAND_LL_RDATA]		= 0x17c,
+-	[BRCMNAND_OOB_READ_BASE]	=  0x20,
+-	[BRCMNAND_OOB_READ_10_BASE]	= 0x130,
+-	[BRCMNAND_OOB_WRITE_BASE]	=  0x30,
+-	[BRCMNAND_OOB_WRITE_10_BASE]	= 0x140,
+-	[BRCMNAND_FC_BASE]		= 0x200,
+-};
+-
+-/* BRCMNAND v6.0 - v7.1 */
+-static const u16 brcmnand_regs_v60[] = {
+-	[BRCMNAND_CMD_START]		=  0x04,
+-	[BRCMNAND_CMD_EXT_ADDRESS]	=  0x08,
+-	[BRCMNAND_CMD_ADDRESS]		=  0x0c,
+-	[BRCMNAND_INTFC_STATUS]		=  0x14,
+-	[BRCMNAND_CS_SELECT]		=  0x18,
+-	[BRCMNAND_CS_XOR]		=  0x1c,
+-	[BRCMNAND_LL_OP]		=  0x20,
+-	[BRCMNAND_CS0_BASE]		=  0x50,
+-	[BRCMNAND_CS1_BASE]		=     0,
+-	[BRCMNAND_CORR_THRESHOLD]	=  0xc0,
+-	[BRCMNAND_CORR_THRESHOLD_EXT]	=  0xc4,
+-	[BRCMNAND_UNCORR_COUNT]		=  0xfc,
+-	[BRCMNAND_CORR_COUNT]		= 0x100,
+-	[BRCMNAND_CORR_EXT_ADDR]	= 0x10c,
+-	[BRCMNAND_CORR_ADDR]		= 0x110,
+-	[BRCMNAND_UNCORR_EXT_ADDR]	= 0x114,
+-	[BRCMNAND_UNCORR_ADDR]		= 0x118,
+-	[BRCMNAND_SEMAPHORE]		= 0x150,
+-	[BRCMNAND_ID]			= 0x194,
+-	[BRCMNAND_ID_EXT]		= 0x198,
+-	[BRCMNAND_LL_RDATA]		= 0x19c,
+-	[BRCMNAND_OOB_READ_BASE]	= 0x200,
+-	[BRCMNAND_OOB_READ_10_BASE]	=     0,
+-	[BRCMNAND_OOB_WRITE_BASE]	= 0x280,
+-	[BRCMNAND_OOB_WRITE_10_BASE]	=     0,
+-	[BRCMNAND_FC_BASE]		= 0x400,
+-};
+-
+-/* BRCMNAND v7.1 */
+-static const u16 brcmnand_regs_v71[] = {
+-	[BRCMNAND_CMD_START]		=  0x04,
+-	[BRCMNAND_CMD_EXT_ADDRESS]	=  0x08,
+-	[BRCMNAND_CMD_ADDRESS]		=  0x0c,
+-	[BRCMNAND_INTFC_STATUS]		=  0x14,
+-	[BRCMNAND_CS_SELECT]		=  0x18,
+-	[BRCMNAND_CS_XOR]		=  0x1c,
+-	[BRCMNAND_LL_OP]		=  0x20,
+-	[BRCMNAND_CS0_BASE]		=  0x50,
+-	[BRCMNAND_CS1_BASE]		=     0,
+-	[BRCMNAND_CORR_THRESHOLD]	=  0xdc,
+-	[BRCMNAND_CORR_THRESHOLD_EXT]	=  0xe0,
+-	[BRCMNAND_UNCORR_COUNT]		=  0xfc,
+-	[BRCMNAND_CORR_COUNT]		= 0x100,
+-	[BRCMNAND_CORR_EXT_ADDR]	= 0x10c,
+-	[BRCMNAND_CORR_ADDR]		= 0x110,
+-	[BRCMNAND_UNCORR_EXT_ADDR]	= 0x114,
+-	[BRCMNAND_UNCORR_ADDR]		= 0x118,
+-	[BRCMNAND_SEMAPHORE]		= 0x150,
+-	[BRCMNAND_ID]			= 0x194,
+-	[BRCMNAND_ID_EXT]		= 0x198,
+-	[BRCMNAND_LL_RDATA]		= 0x19c,
+-	[BRCMNAND_OOB_READ_BASE]	= 0x200,
+-	[BRCMNAND_OOB_READ_10_BASE]	=     0,
+-	[BRCMNAND_OOB_WRITE_BASE]	= 0x280,
+-	[BRCMNAND_OOB_WRITE_10_BASE]	=     0,
+-	[BRCMNAND_FC_BASE]		= 0x400,
+-};
+-
+-/* BRCMNAND v7.2 */
+-static const u16 brcmnand_regs_v72[] = {
+-	[BRCMNAND_CMD_START]		=  0x04,
+-	[BRCMNAND_CMD_EXT_ADDRESS]	=  0x08,
+-	[BRCMNAND_CMD_ADDRESS]		=  0x0c,
+-	[BRCMNAND_INTFC_STATUS]		=  0x14,
+-	[BRCMNAND_CS_SELECT]		=  0x18,
+-	[BRCMNAND_CS_XOR]		=  0x1c,
+-	[BRCMNAND_LL_OP]		=  0x20,
+-	[BRCMNAND_CS0_BASE]		=  0x50,
+-	[BRCMNAND_CS1_BASE]		=     0,
+-	[BRCMNAND_CORR_THRESHOLD]	=  0xdc,
+-	[BRCMNAND_CORR_THRESHOLD_EXT]	=  0xe0,
+-	[BRCMNAND_UNCORR_COUNT]		=  0xfc,
+-	[BRCMNAND_CORR_COUNT]		= 0x100,
+-	[BRCMNAND_CORR_EXT_ADDR]	= 0x10c,
+-	[BRCMNAND_CORR_ADDR]		= 0x110,
+-	[BRCMNAND_UNCORR_EXT_ADDR]	= 0x114,
+-	[BRCMNAND_UNCORR_ADDR]		= 0x118,
+-	[BRCMNAND_SEMAPHORE]		= 0x150,
+-	[BRCMNAND_ID]			= 0x194,
+-	[BRCMNAND_ID_EXT]		= 0x198,
+-	[BRCMNAND_LL_RDATA]		= 0x19c,
+-	[BRCMNAND_OOB_READ_BASE]	= 0x200,
+-	[BRCMNAND_OOB_READ_10_BASE]	=     0,
+-	[BRCMNAND_OOB_WRITE_BASE]	= 0x400,
+-	[BRCMNAND_OOB_WRITE_10_BASE]	=     0,
+-	[BRCMNAND_FC_BASE]		= 0x600,
+-};
+-
+-enum brcmnand_cs_reg {
+-	BRCMNAND_CS_CFG_EXT = 0,
+-	BRCMNAND_CS_CFG,
+-	BRCMNAND_CS_ACC_CONTROL,
+-	BRCMNAND_CS_TIMING1,
+-	BRCMNAND_CS_TIMING2,
+-};
+-
+-/* Per chip-select offsets for v7.1 */
+-static const u8 brcmnand_cs_offsets_v71[] = {
+-	[BRCMNAND_CS_ACC_CONTROL]	= 0x00,
+-	[BRCMNAND_CS_CFG_EXT]		= 0x04,
+-	[BRCMNAND_CS_CFG]		= 0x08,
+-	[BRCMNAND_CS_TIMING1]		= 0x0c,
+-	[BRCMNAND_CS_TIMING2]		= 0x10,
+-};
+-
+-/* Per chip-select offsets for pre v7.1, except CS0 on <= v5.0 */
+-static const u8 brcmnand_cs_offsets[] = {
+-	[BRCMNAND_CS_ACC_CONTROL]	= 0x00,
+-	[BRCMNAND_CS_CFG_EXT]		= 0x04,
+-	[BRCMNAND_CS_CFG]		= 0x04,
+-	[BRCMNAND_CS_TIMING1]		= 0x08,
+-	[BRCMNAND_CS_TIMING2]		= 0x0c,
+-};
+-
+-/* Per chip-select offset for <= v5.0 on CS0 only */
+-static const u8 brcmnand_cs_offsets_cs0[] = {
+-	[BRCMNAND_CS_ACC_CONTROL]	= 0x00,
+-	[BRCMNAND_CS_CFG_EXT]		= 0x08,
+-	[BRCMNAND_CS_CFG]		= 0x08,
+-	[BRCMNAND_CS_TIMING1]		= 0x10,
+-	[BRCMNAND_CS_TIMING2]		= 0x14,
+-};
+-
+-/*
+- * Bitfields for the CFG and CFG_EXT registers. Pre-v7.1 controllers only had
+- * one config register, but once the bitfields overflowed, newer controllers
+- * (v7.1 and newer) added a CFG_EXT register and shuffled a few fields around.
+- */
+-enum {
+-	CFG_BLK_ADR_BYTES_SHIFT		= 8,
+-	CFG_COL_ADR_BYTES_SHIFT		= 12,
+-	CFG_FUL_ADR_BYTES_SHIFT		= 16,
+-	CFG_BUS_WIDTH_SHIFT		= 23,
+-	CFG_BUS_WIDTH			= BIT(CFG_BUS_WIDTH_SHIFT),
+-	CFG_DEVICE_SIZE_SHIFT		= 24,
+-
+-	/* Only for pre-v7.1 (with no CFG_EXT register) */
+-	CFG_PAGE_SIZE_SHIFT		= 20,
+-	CFG_BLK_SIZE_SHIFT		= 28,
+-
+-	/* Only for v7.1+ (with CFG_EXT register) */
+-	CFG_EXT_PAGE_SIZE_SHIFT		= 0,
+-	CFG_EXT_BLK_SIZE_SHIFT		= 4,
+-};
+-
+-/* BRCMNAND_INTFC_STATUS */
+-enum {
+-	INTFC_FLASH_STATUS		= GENMASK(7, 0),
+-
+-	INTFC_ERASED			= BIT(27),
+-	INTFC_OOB_VALID			= BIT(28),
+-	INTFC_CACHE_VALID		= BIT(29),
+-	INTFC_FLASH_READY		= BIT(30),
+-	INTFC_CTLR_READY		= BIT(31),
+-};
+-
+-static inline u32 nand_readreg(struct brcmnand_controller *ctrl, u32 offs)
+-{
+-	return brcmnand_readl(ctrl->nand_base + offs);
+-}
+-
+-static inline void nand_writereg(struct brcmnand_controller *ctrl, u32 offs,
+-				 u32 val)
+-{
+-	brcmnand_writel(val, ctrl->nand_base + offs);
+-}
+-
+-static int brcmnand_revision_init(struct brcmnand_controller *ctrl)
+-{
+-	static const unsigned int block_sizes_v6[] = { 8, 16, 128, 256, 512, 1024, 2048, 0 };
+-	static const unsigned int block_sizes_v4[] = { 16, 128, 8, 512, 256, 1024, 2048, 0 };
+-	static const unsigned int page_sizes[] = { 512, 2048, 4096, 8192, 0 };
+-
+-	ctrl->nand_version = nand_readreg(ctrl, 0) & 0xffff;
+-
+-	/* Only support v4.0+? */
+-	if (ctrl->nand_version < 0x0400) {
+-		dev_err(ctrl->dev, "version %#x not supported\n",
+-			ctrl->nand_version);
+-		return -ENODEV;
+-	}
+-
+-	/* Register offsets */
+-	if (ctrl->nand_version >= 0x0702)
+-		ctrl->reg_offsets = brcmnand_regs_v72;
+-	else if (ctrl->nand_version >= 0x0701)
+-		ctrl->reg_offsets = brcmnand_regs_v71;
+-	else if (ctrl->nand_version >= 0x0600)
+-		ctrl->reg_offsets = brcmnand_regs_v60;
+-	else if (ctrl->nand_version >= 0x0500)
+-		ctrl->reg_offsets = brcmnand_regs_v50;
+-	else if (ctrl->nand_version >= 0x0400)
+-		ctrl->reg_offsets = brcmnand_regs_v40;
+-
+-	/* Chip-select stride */
+-	if (ctrl->nand_version >= 0x0701)
+-		ctrl->reg_spacing = 0x14;
+-	else
+-		ctrl->reg_spacing = 0x10;
+-
+-	/* Per chip-select registers */
+-	if (ctrl->nand_version >= 0x0701) {
+-		ctrl->cs_offsets = brcmnand_cs_offsets_v71;
+-	} else {
+-		ctrl->cs_offsets = brcmnand_cs_offsets;
+-
+-		/* v5.0 and earlier has a different CS0 offset layout */
+-		if (ctrl->nand_version <= 0x0500)
+-			ctrl->cs0_offsets = brcmnand_cs_offsets_cs0;
+-	}
+-
+-	/* Page / block sizes */
+-	if (ctrl->nand_version >= 0x0701) {
+-		/* >= v7.1 use nice power-of-2 values! */
+-		ctrl->max_page_size = 16 * 1024;
+-		ctrl->max_block_size = 2 * 1024 * 1024;
+-	} else {
+-		ctrl->page_sizes = page_sizes;
+-		if (ctrl->nand_version >= 0x0600)
+-			ctrl->block_sizes = block_sizes_v6;
+-		else
+-			ctrl->block_sizes = block_sizes_v4;
+-
+-		if (ctrl->nand_version < 0x0400) {
+-			ctrl->max_page_size = 4096;
+-			ctrl->max_block_size = 512 * 1024;
+-		}
+-	}
+-
+-	/* Maximum spare area sector size (per 512B) */
+-	if (ctrl->nand_version >= 0x0702)
+-		ctrl->max_oob = 128;
+-	else if (ctrl->nand_version >= 0x0600)
+-		ctrl->max_oob = 64;
+-	else if (ctrl->nand_version >= 0x0500)
+-		ctrl->max_oob = 32;
+-	else
+-		ctrl->max_oob = 16;
+-
+-	/* v6.0 and newer (except v6.1) have prefetch support */
+-	if (ctrl->nand_version >= 0x0600 && ctrl->nand_version != 0x0601)
+-		ctrl->features |= BRCMNAND_HAS_PREFETCH;
+-
+-	/*
+-	 * v6.x has cache mode, but it's implemented differently. Ignore it for
+-	 * now.
+-	 */
+-	if (ctrl->nand_version >= 0x0700)
+-		ctrl->features |= BRCMNAND_HAS_CACHE_MODE;
+-
+-	if (ctrl->nand_version >= 0x0500)
+-		ctrl->features |= BRCMNAND_HAS_1K_SECTORS;
+-
+-	if (ctrl->nand_version >= 0x0700)
+-		ctrl->features |= BRCMNAND_HAS_WP;
+-	else if (of_property_read_bool(ctrl->dev->of_node, "brcm,nand-has-wp"))
+-		ctrl->features |= BRCMNAND_HAS_WP;
+-
+-	return 0;
+-}
+-
+-static inline u32 brcmnand_read_reg(struct brcmnand_controller *ctrl,
+-		enum brcmnand_reg reg)
+-{
+-	u16 offs = ctrl->reg_offsets[reg];
+-
+-	if (offs)
+-		return nand_readreg(ctrl, offs);
+-	else
+-		return 0;
+-}
+-
+-static inline void brcmnand_write_reg(struct brcmnand_controller *ctrl,
+-				      enum brcmnand_reg reg, u32 val)
+-{
+-	u16 offs = ctrl->reg_offsets[reg];
+-
+-	if (offs)
+-		nand_writereg(ctrl, offs, val);
+-}
+-
+-static inline void brcmnand_rmw_reg(struct brcmnand_controller *ctrl,
+-				    enum brcmnand_reg reg, u32 mask, unsigned
+-				    int shift, u32 val)
+-{
+-	u32 tmp = brcmnand_read_reg(ctrl, reg);
+-
+-	tmp &= ~mask;
+-	tmp |= val << shift;
+-	brcmnand_write_reg(ctrl, reg, tmp);
+-}
+-
+-static inline u32 brcmnand_read_fc(struct brcmnand_controller *ctrl, int word)
+-{
+-	return __raw_readl(ctrl->nand_fc + word * 4);
+-}
+-
+-static inline void brcmnand_write_fc(struct brcmnand_controller *ctrl,
+-				     int word, u32 val)
+-{
+-	__raw_writel(val, ctrl->nand_fc + word * 4);
+-}
+-
+-static inline u16 brcmnand_cs_offset(struct brcmnand_controller *ctrl, int cs,
+-				     enum brcmnand_cs_reg reg)
+-{
+-	u16 offs_cs0 = ctrl->reg_offsets[BRCMNAND_CS0_BASE];
+-	u16 offs_cs1 = ctrl->reg_offsets[BRCMNAND_CS1_BASE];
+-	u8 cs_offs;
+-
+-	if (cs == 0 && ctrl->cs0_offsets)
+-		cs_offs = ctrl->cs0_offsets[reg];
+-	else
+-		cs_offs = ctrl->cs_offsets[reg];
+-
+-	if (cs && offs_cs1)
+-		return offs_cs1 + (cs - 1) * ctrl->reg_spacing + cs_offs;
+-
+-	return offs_cs0 + cs * ctrl->reg_spacing + cs_offs;
+-}
+-
+-static inline u32 brcmnand_count_corrected(struct brcmnand_controller *ctrl)
+-{
+-	if (ctrl->nand_version < 0x0600)
+-		return 1;
+-	return brcmnand_read_reg(ctrl, BRCMNAND_CORR_COUNT);
+-}
+-
+-static void brcmnand_wr_corr_thresh(struct brcmnand_host *host, u8 val)
+-{
+-	struct brcmnand_controller *ctrl = host->ctrl;
+-	unsigned int shift = 0, bits;
+-	enum brcmnand_reg reg = BRCMNAND_CORR_THRESHOLD;
+-	int cs = host->cs;
+-
+-	if (ctrl->nand_version >= 0x0702)
+-		bits = 7;
+-	else if (ctrl->nand_version >= 0x0600)
+-		bits = 6;
+-	else if (ctrl->nand_version >= 0x0500)
+-		bits = 5;
+-	else
+-		bits = 4;
+-
+-	if (ctrl->nand_version >= 0x0702) {
+-		if (cs >= 4)
+-			reg = BRCMNAND_CORR_THRESHOLD_EXT;
+-		shift = (cs % 4) * bits;
+-	} else if (ctrl->nand_version >= 0x0600) {
+-		if (cs >= 5)
+-			reg = BRCMNAND_CORR_THRESHOLD_EXT;
+-		shift = (cs % 5) * bits;
+-	}
+-	brcmnand_rmw_reg(ctrl, reg, (bits - 1) << shift, shift, val);
+-}
+-
+-static inline int brcmnand_cmd_shift(struct brcmnand_controller *ctrl)
+-{
+-	if (ctrl->nand_version < 0x0602)
+-		return 24;
+-	return 0;
+-}
+-
+-/***********************************************************************
+- * NAND ACC CONTROL bitfield
+- *
+- * Some bits have remained constant throughout hardware revision, while
+- * others have shifted around.
+- ***********************************************************************/
+-
+-/* Constant for all versions (where supported) */
+-enum {
+-	/* See BRCMNAND_HAS_CACHE_MODE */
+-	ACC_CONTROL_CACHE_MODE				= BIT(22),
+-
+-	/* See BRCMNAND_HAS_PREFETCH */
+-	ACC_CONTROL_PREFETCH				= BIT(23),
+-
+-	ACC_CONTROL_PAGE_HIT				= BIT(24),
+-	ACC_CONTROL_WR_PREEMPT				= BIT(25),
+-	ACC_CONTROL_PARTIAL_PAGE			= BIT(26),
+-	ACC_CONTROL_RD_ERASED				= BIT(27),
+-	ACC_CONTROL_FAST_PGM_RDIN			= BIT(28),
+-	ACC_CONTROL_WR_ECC				= BIT(30),
+-	ACC_CONTROL_RD_ECC				= BIT(31),
+-};
+-
+-static inline u32 brcmnand_spare_area_mask(struct brcmnand_controller *ctrl)
+-{
+-	if (ctrl->nand_version >= 0x0702)
+-		return GENMASK(7, 0);
+-	else if (ctrl->nand_version >= 0x0600)
+-		return GENMASK(6, 0);
+-	else
+-		return GENMASK(5, 0);
+-}
+-
+-#define NAND_ACC_CONTROL_ECC_SHIFT	16
+-#define NAND_ACC_CONTROL_ECC_EXT_SHIFT	13
+-
+-static inline u32 brcmnand_ecc_level_mask(struct brcmnand_controller *ctrl)
+-{
+-	u32 mask = (ctrl->nand_version >= 0x0600) ? 0x1f : 0x0f;
+-
+-	mask <<= NAND_ACC_CONTROL_ECC_SHIFT;
+-
+-	/* v7.2 includes additional ECC levels */
+-	if (ctrl->nand_version >= 0x0702)
+-		mask |= 0x7 << NAND_ACC_CONTROL_ECC_EXT_SHIFT;
+-
+-	return mask;
+-}
+-
+-static void brcmnand_set_ecc_enabled(struct brcmnand_host *host, int en)
+-{
+-	struct brcmnand_controller *ctrl = host->ctrl;
+-	u16 offs = brcmnand_cs_offset(ctrl, host->cs, BRCMNAND_CS_ACC_CONTROL);
+-	u32 acc_control = nand_readreg(ctrl, offs);
+-	u32 ecc_flags = ACC_CONTROL_WR_ECC | ACC_CONTROL_RD_ECC;
+-
+-	if (en) {
+-		acc_control |= ecc_flags; /* enable RD/WR ECC */
+-		acc_control |= host->hwcfg.ecc_level
+-			       << NAND_ACC_CONTROL_ECC_SHIFT;
+-	} else {
+-		acc_control &= ~ecc_flags; /* disable RD/WR ECC */
+-		acc_control &= ~brcmnand_ecc_level_mask(ctrl);
+-	}
+-
+-	nand_writereg(ctrl, offs, acc_control);
+-}
+-
+-static inline int brcmnand_sector_1k_shift(struct brcmnand_controller *ctrl)
+-{
+-	if (ctrl->nand_version >= 0x0702)
+-		return 9;
+-	else if (ctrl->nand_version >= 0x0600)
+-		return 7;
+-	else if (ctrl->nand_version >= 0x0500)
+-		return 6;
+-	else
+-		return -1;
+-}
+-
+-static int brcmnand_get_sector_size_1k(struct brcmnand_host *host)
+-{
+-	struct brcmnand_controller *ctrl = host->ctrl;
+-	int shift = brcmnand_sector_1k_shift(ctrl);
+-	u16 acc_control_offs = brcmnand_cs_offset(ctrl, host->cs,
+-						  BRCMNAND_CS_ACC_CONTROL);
+-
+-	if (shift < 0)
+-		return 0;
+-
+-	return (nand_readreg(ctrl, acc_control_offs) >> shift) & 0x1;
+-}
+-
+-static void brcmnand_set_sector_size_1k(struct brcmnand_host *host, int val)
+-{
+-	struct brcmnand_controller *ctrl = host->ctrl;
+-	int shift = brcmnand_sector_1k_shift(ctrl);
+-	u16 acc_control_offs = brcmnand_cs_offset(ctrl, host->cs,
+-						  BRCMNAND_CS_ACC_CONTROL);
+-	u32 tmp;
+-
+-	if (shift < 0)
+-		return;
+-
+-	tmp = nand_readreg(ctrl, acc_control_offs);
+-	tmp &= ~(1 << shift);
+-	tmp |= (!!val) << shift;
+-	nand_writereg(ctrl, acc_control_offs, tmp);
+-}
+-
+-/***********************************************************************
+- * CS_NAND_SELECT
+- ***********************************************************************/
+-
+-enum {
+-	CS_SELECT_NAND_WP			= BIT(29),
+-	CS_SELECT_AUTO_DEVICE_ID_CFG		= BIT(30),
+-};
+-
+-static int bcmnand_ctrl_poll_status(struct brcmnand_controller *ctrl,
+-				    u32 mask, u32 expected_val,
+-				    unsigned long timeout_ms)
+-{
+-	unsigned long limit;
+-	u32 val;
+-
+-	if (!timeout_ms)
+-		timeout_ms = NAND_POLL_STATUS_TIMEOUT_MS;
+-
+-	limit = jiffies + msecs_to_jiffies(timeout_ms);
+-	do {
+-		val = brcmnand_read_reg(ctrl, BRCMNAND_INTFC_STATUS);
+-		if ((val & mask) == expected_val)
+-			return 0;
+-
+-		cpu_relax();
+-	} while (time_after(limit, jiffies));
+-
+-	dev_warn(ctrl->dev, "timeout on status poll (expected %x got %x)\n",
+-		 expected_val, val & mask);
+-
+-	return -ETIMEDOUT;
+-}
+-
+-static inline void brcmnand_set_wp(struct brcmnand_controller *ctrl, bool en)
+-{
+-	u32 val = en ? CS_SELECT_NAND_WP : 0;
+-
+-	brcmnand_rmw_reg(ctrl, BRCMNAND_CS_SELECT, CS_SELECT_NAND_WP, 0, val);
+-}
+-
+-/***********************************************************************
+- * Flash DMA
+- ***********************************************************************/
+-
+-enum flash_dma_reg {
+-	FLASH_DMA_REVISION		= 0x00,
+-	FLASH_DMA_FIRST_DESC		= 0x04,
+-	FLASH_DMA_FIRST_DESC_EXT	= 0x08,
+-	FLASH_DMA_CTRL			= 0x0c,
+-	FLASH_DMA_MODE			= 0x10,
+-	FLASH_DMA_STATUS		= 0x14,
+-	FLASH_DMA_INTERRUPT_DESC	= 0x18,
+-	FLASH_DMA_INTERRUPT_DESC_EXT	= 0x1c,
+-	FLASH_DMA_ERROR_STATUS		= 0x20,
+-	FLASH_DMA_CURRENT_DESC		= 0x24,
+-	FLASH_DMA_CURRENT_DESC_EXT	= 0x28,
+-};
+-
+-static inline bool has_flash_dma(struct brcmnand_controller *ctrl)
+-{
+-	return ctrl->flash_dma_base;
+-}
+-
+-static inline bool flash_dma_buf_ok(const void *buf)
+-{
+-	return buf && !is_vmalloc_addr(buf) &&
+-		likely(IS_ALIGNED((uintptr_t)buf, 4));
+-}
+-
+-static inline void flash_dma_writel(struct brcmnand_controller *ctrl, u8 offs,
+-				    u32 val)
+-{
+-	brcmnand_writel(val, ctrl->flash_dma_base + offs);
+-}
+-
+-static inline u32 flash_dma_readl(struct brcmnand_controller *ctrl, u8 offs)
+-{
+-	return brcmnand_readl(ctrl->flash_dma_base + offs);
+-}
+-
+-/* Low-level operation types: command, address, write, or read */
+-enum brcmnand_llop_type {
+-	LL_OP_CMD,
+-	LL_OP_ADDR,
+-	LL_OP_WR,
+-	LL_OP_RD,
+-};
+-
+-/***********************************************************************
+- * Internal support functions
+- ***********************************************************************/
+-
+-static inline bool is_hamming_ecc(struct brcmnand_controller *ctrl,
+-				  struct brcmnand_cfg *cfg)
+-{
+-	if (ctrl->nand_version <= 0x0701)
+-		return cfg->sector_size_1k == 0 && cfg->spare_area_size == 16 &&
+-			cfg->ecc_level == 15;
+-	else
+-		return cfg->sector_size_1k == 0 && ((cfg->spare_area_size == 16 &&
+-			cfg->ecc_level == 15) ||
+-			(cfg->spare_area_size == 28 && cfg->ecc_level == 16));
+-}
+-
+-/*
+- * Set mtd->ooblayout to the appropriate mtd_ooblayout_ops given
+- * the layout/configuration.
+- * Returns -ERRCODE on failure.
+- */
+-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 brcmnand_host *host = nand_get_controller_data(chip);
+-	struct brcmnand_cfg *cfg = &host->hwcfg;
+-	int sas = cfg->spare_area_size << cfg->sector_size_1k;
+-	int sectors = cfg->page_size / (512 << cfg->sector_size_1k);
+-
+-	if (section >= sectors)
+-		return -ERANGE;
+-
+-	oobregion->offset = (section * sas) + 6;
+-	oobregion->length = 3;
+-
+-	return 0;
+-}
+-
+-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 brcmnand_host *host = nand_get_controller_data(chip);
+-	struct brcmnand_cfg *cfg = &host->hwcfg;
+-	int sas = cfg->spare_area_size << cfg->sector_size_1k;
+-	int sectors = cfg->page_size / (512 << cfg->sector_size_1k);
+-
+-	if (section >= sectors * 2)
+-		return -ERANGE;
+-
+-	oobregion->offset = (section / 2) * sas;
+-
+-	if (section & 1) {
+-		oobregion->offset += 9;
+-		oobregion->length = 7;
+-	} else {
+-		oobregion->length = 6;
+-
+-		/* First sector of each page may have BBI */
+-		if (!section) {
+-			/*
+-			 * Small-page NAND use byte 6 for BBI while large-page
+-			 * NAND use byte 0.
+-			 */
+-			if (cfg->page_size > 512)
+-				oobregion->offset++;
+-			oobregion->length--;
+-		}
+-	}
+-
+-	return 0;
+-}
+-
+-static const struct mtd_ooblayout_ops brcmnand_hamming_ooblayout_ops = {
+-	.ecc = brcmnand_hamming_ooblayout_ecc,
+-	.free = brcmnand_hamming_ooblayout_free,
+-};
+-
+-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 brcmnand_host *host = nand_get_controller_data(chip);
+-	struct brcmnand_cfg *cfg = &host->hwcfg;
+-	int sas = cfg->spare_area_size << cfg->sector_size_1k;
+-	int sectors = cfg->page_size / (512 << cfg->sector_size_1k);
+-
+-	if (section >= sectors)
+-		return -ERANGE;
+-
+-	oobregion->offset = (section * (sas + 1)) - chip->ecc.bytes;
+-	oobregion->length = chip->ecc.bytes;
+-
+-	return 0;
+-}
+-
+-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 brcmnand_host *host = nand_get_controller_data(chip);
+-	struct brcmnand_cfg *cfg = &host->hwcfg;
+-	int sas = cfg->spare_area_size << cfg->sector_size_1k;
+-	int sectors = cfg->page_size / (512 << cfg->sector_size_1k);
+-
+-	if (section >= sectors)
+-		return -ERANGE;
+-
+-	if (sas <= chip->ecc.bytes)
+-		return 0;
+-
+-	oobregion->offset = section * sas;
+-	oobregion->length = sas - chip->ecc.bytes;
+-
+-	if (!section) {
+-		oobregion->offset++;
+-		oobregion->length--;
+-	}
+-
+-	return 0;
+-}
+-
+-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 brcmnand_host *host = nand_get_controller_data(chip);
+-	struct brcmnand_cfg *cfg = &host->hwcfg;
+-	int sas = cfg->spare_area_size << cfg->sector_size_1k;
+-
+-	if (section > 1 || sas - chip->ecc.bytes < 6 ||
+-	    (section && sas - chip->ecc.bytes == 6))
+-		return -ERANGE;
+-
+-	if (!section) {
+-		oobregion->offset = 0;
+-		oobregion->length = 5;
+-	} else {
+-		oobregion->offset = 6;
+-		oobregion->length = sas - chip->ecc.bytes - 6;
+-	}
+-
+-	return 0;
+-}
+-
+-static const struct mtd_ooblayout_ops brcmnand_bch_lp_ooblayout_ops = {
+-	.ecc = brcmnand_bch_ooblayout_ecc,
+-	.free = brcmnand_bch_ooblayout_free_lp,
+-};
+-
+-static const struct mtd_ooblayout_ops brcmnand_bch_sp_ooblayout_ops = {
+-	.ecc = brcmnand_bch_ooblayout_ecc,
+-	.free = brcmnand_bch_ooblayout_free_sp,
+-};
+-
+-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 nand_ecc_ctrl *ecc = &host->chip.ecc;
+-	unsigned int ecc_level = p->ecc_level;
+-	int sas = p->spare_area_size << p->sector_size_1k;
+-	int sectors = p->page_size / (512 << p->sector_size_1k);
+-
+-	if (p->sector_size_1k)
+-		ecc_level <<= 1;
+-
+-	if (is_hamming_ecc(host->ctrl, p)) {
+-		ecc->bytes = 3 * sectors;
+-		mtd_set_ooblayout(mtd, &brcmnand_hamming_ooblayout_ops);
+-		return 0;
+-	}
+-
+-	/*
+-	 * CONTROLLER_VERSION:
+-	 *   < v5.0: ECC_REQ = ceil(BCH_T * 13/8)
+-	 *  >= v5.0: ECC_REQ = ceil(BCH_T * 14/8)
+-	 * But we will just be conservative.
+-	 */
+-	ecc->bytes = DIV_ROUND_UP(ecc_level * 14, 8);
+-	if (p->page_size == 512)
+-		mtd_set_ooblayout(mtd, &brcmnand_bch_sp_ooblayout_ops);
+-	else
+-		mtd_set_ooblayout(mtd, &brcmnand_bch_lp_ooblayout_ops);
+-
+-	if (ecc->bytes >= sas) {
+-		dev_err(&host->pdev->dev,
+-			"error: ECC too large for OOB (ECC bytes %d, spare sector %d)\n",
+-			ecc->bytes, sas);
+-		return -EINVAL;
+-	}
+-
+-	return 0;
+-}
+-
+-static void brcmnand_wp(struct mtd_info *mtd, int wp)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct brcmnand_host *host = nand_get_controller_data(chip);
+-	struct brcmnand_controller *ctrl = host->ctrl;
+-
+-	if ((ctrl->features & BRCMNAND_HAS_WP) && wp_on == 1) {
+-		static int old_wp = -1;
+-		int ret;
+-
+-		if (old_wp != wp) {
+-			dev_dbg(ctrl->dev, "WP %s\n", wp ? "on" : "off");
+-			old_wp = wp;
+-		}
+-
+-		/*
+-		 * make sure ctrl/flash ready before and after
+-		 * changing state of #WP pin
+-		 */
+-		ret = bcmnand_ctrl_poll_status(ctrl, NAND_CTRL_RDY |
+-					       NAND_STATUS_READY,
+-					       NAND_CTRL_RDY |
+-					       NAND_STATUS_READY, 0);
+-		if (ret)
+-			return;
+-
+-		brcmnand_set_wp(ctrl, wp);
+-		chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
+-		/* NAND_STATUS_WP 0x00 = protected, 0x80 = not protected */
+-		ret = bcmnand_ctrl_poll_status(ctrl,
+-					       NAND_CTRL_RDY |
+-					       NAND_STATUS_READY |
+-					       NAND_STATUS_WP,
+-					       NAND_CTRL_RDY |
+-					       NAND_STATUS_READY |
+-					       (wp ? 0 : NAND_STATUS_WP), 0);
+-
+-		if (ret)
+-			dev_err_ratelimited(&host->pdev->dev,
+-					    "nand #WP expected %s\n",
+-					    wp ? "on" : "off");
+-	}
+-}
+-
+-/* Helper functions for reading and writing OOB registers */
+-static inline u8 oob_reg_read(struct brcmnand_controller *ctrl, u32 offs)
+-{
+-	u16 offset0, offset10, reg_offs;
+-
+-	offset0 = ctrl->reg_offsets[BRCMNAND_OOB_READ_BASE];
+-	offset10 = ctrl->reg_offsets[BRCMNAND_OOB_READ_10_BASE];
+-
+-	if (offs >= ctrl->max_oob)
+-		return 0x77;
+-
+-	if (offs >= 16 && offset10)
+-		reg_offs = offset10 + ((offs - 0x10) & ~0x03);
+-	else
+-		reg_offs = offset0 + (offs & ~0x03);
+-
+-	return nand_readreg(ctrl, reg_offs) >> (24 - ((offs & 0x03) << 3));
+-}
+-
+-static inline void oob_reg_write(struct brcmnand_controller *ctrl, u32 offs,
+-				 u32 data)
+-{
+-	u16 offset0, offset10, reg_offs;
+-
+-	offset0 = ctrl->reg_offsets[BRCMNAND_OOB_WRITE_BASE];
+-	offset10 = ctrl->reg_offsets[BRCMNAND_OOB_WRITE_10_BASE];
+-
+-	if (offs >= ctrl->max_oob)
+-		return;
+-
+-	if (offs >= 16 && offset10)
+-		reg_offs = offset10 + ((offs - 0x10) & ~0x03);
+-	else
+-		reg_offs = offset0 + (offs & ~0x03);
+-
+-	nand_writereg(ctrl, reg_offs, data);
+-}
+-
+-/*
+- * read_oob_from_regs - read data from OOB registers
+- * @ctrl: NAND controller
+- * @i: sub-page sector index
+- * @oob: buffer to read to
+- * @sas: spare area sector size (i.e., OOB size per FLASH_CACHE)
+- * @sector_1k: 1 for 1KiB sectors, 0 for 512B, other values are illegal
+- */
+-static int read_oob_from_regs(struct brcmnand_controller *ctrl, int i, u8 *oob,
+-			      int sas, int sector_1k)
+-{
+-	int tbytes = sas << sector_1k;
+-	int j;
+-
+-	/* Adjust OOB values for 1K sector size */
+-	if (sector_1k && (i & 0x01))
+-		tbytes = max(0, tbytes - (int)ctrl->max_oob);
+-	tbytes = min_t(int, tbytes, ctrl->max_oob);
+-
+-	for (j = 0; j < tbytes; j++)
+-		oob[j] = oob_reg_read(ctrl, j);
+-	return tbytes;
+-}
+-
+-/*
+- * write_oob_to_regs - write data to OOB registers
+- * @i: sub-page sector index
+- * @oob: buffer to write from
+- * @sas: spare area sector size (i.e., OOB size per FLASH_CACHE)
+- * @sector_1k: 1 for 1KiB sectors, 0 for 512B, other values are illegal
+- */
+-static int write_oob_to_regs(struct brcmnand_controller *ctrl, int i,
+-			     const u8 *oob, int sas, int sector_1k)
+-{
+-	int tbytes = sas << sector_1k;
+-	int j;
+-
+-	/* Adjust OOB values for 1K sector size */
+-	if (sector_1k && (i & 0x01))
+-		tbytes = max(0, tbytes - (int)ctrl->max_oob);
+-	tbytes = min_t(int, tbytes, ctrl->max_oob);
+-
+-	for (j = 0; j < tbytes; j += 4)
+-		oob_reg_write(ctrl, j,
+-				(oob[j + 0] << 24) |
+-				(oob[j + 1] << 16) |
+-				(oob[j + 2] <<  8) |
+-				(oob[j + 3] <<  0));
+-	return tbytes;
+-}
+-
+-static irqreturn_t brcmnand_ctlrdy_irq(int irq, void *data)
+-{
+-	struct brcmnand_controller *ctrl = data;
+-
+-	/* Discard all NAND_CTLRDY interrupts during DMA */
+-	if (ctrl->dma_pending)
+-		return IRQ_HANDLED;
+-
+-	complete(&ctrl->done);
+-	return IRQ_HANDLED;
+-}
+-
+-/* Handle SoC-specific interrupt hardware */
+-static irqreturn_t brcmnand_irq(int irq, void *data)
+-{
+-	struct brcmnand_controller *ctrl = data;
+-
+-	if (ctrl->soc->ctlrdy_ack(ctrl->soc))
+-		return brcmnand_ctlrdy_irq(irq, data);
+-
+-	return IRQ_NONE;
+-}
+-
+-static irqreturn_t brcmnand_dma_irq(int irq, void *data)
+-{
+-	struct brcmnand_controller *ctrl = data;
+-
+-	complete(&ctrl->dma_done);
+-
+-	return IRQ_HANDLED;
+-}
+-
+-static void brcmnand_send_cmd(struct brcmnand_host *host, int cmd)
+-{
+-	struct brcmnand_controller *ctrl = host->ctrl;
+-	int ret;
+-
+-	dev_dbg(ctrl->dev, "send native cmd %d addr_lo 0x%x\n", cmd,
+-		brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS));
+-	BUG_ON(ctrl->cmd_pending != 0);
+-	ctrl->cmd_pending = cmd;
+-
+-	ret = bcmnand_ctrl_poll_status(ctrl, NAND_CTRL_RDY, NAND_CTRL_RDY, 0);
+-	WARN_ON(ret);
+-
+-	mb(); /* flush previous writes */
+-	brcmnand_write_reg(ctrl, BRCMNAND_CMD_START,
+-			   cmd << brcmnand_cmd_shift(ctrl));
+-}
+-
+-/***********************************************************************
+- * NAND MTD API: read/program/erase
+- ***********************************************************************/
+-
+-static void brcmnand_cmd_ctrl(struct mtd_info *mtd, int dat,
+-	unsigned int ctrl)
+-{
+-	/* intentionally left blank */
+-}
+-
+-static int brcmnand_waitfunc(struct mtd_info *mtd, struct nand_chip *this)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct brcmnand_host *host = nand_get_controller_data(chip);
+-	struct brcmnand_controller *ctrl = host->ctrl;
+-	unsigned long timeo = msecs_to_jiffies(100);
+-
+-	dev_dbg(ctrl->dev, "wait on native cmd %d\n", ctrl->cmd_pending);
+-	if (ctrl->cmd_pending &&
+-			wait_for_completion_timeout(&ctrl->done, timeo) <= 0) {
+-		u32 cmd = brcmnand_read_reg(ctrl, BRCMNAND_CMD_START)
+-					>> brcmnand_cmd_shift(ctrl);
+-
+-		dev_err_ratelimited(ctrl->dev,
+-			"timeout waiting for command %#02x\n", cmd);
+-		dev_err_ratelimited(ctrl->dev, "intfc status %08x\n",
+-			brcmnand_read_reg(ctrl, BRCMNAND_INTFC_STATUS));
+-	}
+-	ctrl->cmd_pending = 0;
+-	return brcmnand_read_reg(ctrl, BRCMNAND_INTFC_STATUS) &
+-				 INTFC_FLASH_STATUS;
+-}
+-
+-enum {
+-	LLOP_RE				= BIT(16),
+-	LLOP_WE				= BIT(17),
+-	LLOP_ALE			= BIT(18),
+-	LLOP_CLE			= BIT(19),
+-	LLOP_RETURN_IDLE		= BIT(31),
+-
+-	LLOP_DATA_MASK			= GENMASK(15, 0),
+-};
+-
+-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 nand_chip *chip = &host->chip;
+-	struct brcmnand_controller *ctrl = host->ctrl;
+-	u32 tmp;
+-
+-	tmp = data & LLOP_DATA_MASK;
+-	switch (type) {
+-	case LL_OP_CMD:
+-		tmp |= LLOP_WE | LLOP_CLE;
+-		break;
+-	case LL_OP_ADDR:
+-		/* WE | ALE */
+-		tmp |= LLOP_WE | LLOP_ALE;
+-		break;
+-	case LL_OP_WR:
+-		/* WE */
+-		tmp |= LLOP_WE;
+-		break;
+-	case LL_OP_RD:
+-		/* RE */
+-		tmp |= LLOP_RE;
+-		break;
+-	}
+-	if (last_op)
+-		/* RETURN_IDLE */
+-		tmp |= LLOP_RETURN_IDLE;
+-
+-	dev_dbg(ctrl->dev, "ll_op cmd %#x\n", tmp);
+-
+-	brcmnand_write_reg(ctrl, BRCMNAND_LL_OP, tmp);
+-	(void)brcmnand_read_reg(ctrl, BRCMNAND_LL_OP);
+-
+-	brcmnand_send_cmd(host, CMD_LOW_LEVEL_OP);
+-	return brcmnand_waitfunc(mtd, chip);
+-}
+-
+-static void brcmnand_cmdfunc(struct mtd_info *mtd, unsigned command,
+-			     int column, int page_addr)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct brcmnand_host *host = nand_get_controller_data(chip);
+-	struct brcmnand_controller *ctrl = host->ctrl;
+-	u64 addr = (u64)page_addr << chip->page_shift;
+-	int native_cmd = 0;
+-
+-	if (command == NAND_CMD_READID || command == NAND_CMD_PARAM ||
+-			command == NAND_CMD_RNDOUT)
+-		addr = (u64)column;
+-	/* Avoid propagating a negative, don't-care address */
+-	else if (page_addr < 0)
+-		addr = 0;
+-
+-	dev_dbg(ctrl->dev, "cmd 0x%x addr 0x%llx\n", command,
+-		(unsigned long long)addr);
+-
+-	host->last_cmd = command;
+-	host->last_byte = 0;
+-	host->last_addr = addr;
+-
+-	switch (command) {
+-	case NAND_CMD_RESET:
+-		native_cmd = CMD_FLASH_RESET;
+-		break;
+-	case NAND_CMD_STATUS:
+-		native_cmd = CMD_STATUS_READ;
+-		break;
+-	case NAND_CMD_READID:
+-		native_cmd = CMD_DEVICE_ID_READ;
+-		break;
+-	case NAND_CMD_READOOB:
+-		native_cmd = CMD_SPARE_AREA_READ;
+-		break;
+-	case NAND_CMD_ERASE1:
+-		native_cmd = CMD_BLOCK_ERASE;
+-		brcmnand_wp(mtd, 0);
+-		break;
+-	case NAND_CMD_PARAM:
+-		native_cmd = CMD_PARAMETER_READ;
+-		break;
+-	case NAND_CMD_SET_FEATURES:
+-	case NAND_CMD_GET_FEATURES:
+-		brcmnand_low_level_op(host, LL_OP_CMD, command, false);
+-		brcmnand_low_level_op(host, LL_OP_ADDR, column, false);
+-		break;
+-	case NAND_CMD_RNDOUT:
+-		native_cmd = CMD_PARAMETER_CHANGE_COL;
+-		addr &= ~((u64)(FC_BYTES - 1));
+-		/*
+-		 * HW quirk: PARAMETER_CHANGE_COL requires SECTOR_SIZE_1K=0
+-		 * NB: hwcfg.sector_size_1k may not be initialized yet
+-		 */
+-		if (brcmnand_get_sector_size_1k(host)) {
+-			host->hwcfg.sector_size_1k =
+-				brcmnand_get_sector_size_1k(host);
+-			brcmnand_set_sector_size_1k(host, 0);
+-		}
+-		break;
+-	}
+-
+-	if (!native_cmd)
+-		return;
+-
+-	brcmnand_write_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS,
+-		(host->cs << 16) | ((addr >> 32) & 0xffff));
+-	(void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS);
+-	brcmnand_write_reg(ctrl, BRCMNAND_CMD_ADDRESS, lower_32_bits(addr));
+-	(void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS);
+-
+-	brcmnand_send_cmd(host, native_cmd);
+-	brcmnand_waitfunc(mtd, chip);
+-
+-	if (native_cmd == CMD_PARAMETER_READ ||
+-			native_cmd == CMD_PARAMETER_CHANGE_COL) {
+-		/* Copy flash cache word-wise */
+-		u32 *flash_cache = (u32 *)ctrl->flash_cache;
+-		int i;
+-
+-		brcmnand_soc_data_bus_prepare(ctrl->soc, true);
+-
+-		/*
+-		 * Must cache the FLASH_CACHE now, since changes in
+-		 * SECTOR_SIZE_1K may invalidate it
+-		 */
+-		for (i = 0; i < FC_WORDS; i++)
+-			/*
+-			 * Flash cache is big endian for parameter pages, at
+-			 * least on STB SoCs
+-			 */
+-			flash_cache[i] = be32_to_cpu(brcmnand_read_fc(ctrl, i));
+-
+-		brcmnand_soc_data_bus_unprepare(ctrl->soc, true);
+-
+-		/* Cleanup from HW quirk: restore SECTOR_SIZE_1K */
+-		if (host->hwcfg.sector_size_1k)
+-			brcmnand_set_sector_size_1k(host,
+-						    host->hwcfg.sector_size_1k);
+-	}
+-
+-	/* Re-enable protection is necessary only after erase */
+-	if (command == NAND_CMD_ERASE1)
+-		brcmnand_wp(mtd, 1);
+-}
+-
+-static uint8_t brcmnand_read_byte(struct mtd_info *mtd)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct brcmnand_host *host = nand_get_controller_data(chip);
+-	struct brcmnand_controller *ctrl = host->ctrl;
+-	uint8_t ret = 0;
+-	int addr, offs;
+-
+-	switch (host->last_cmd) {
+-	case NAND_CMD_READID:
+-		if (host->last_byte < 4)
+-			ret = brcmnand_read_reg(ctrl, BRCMNAND_ID) >>
+-				(24 - (host->last_byte << 3));
+-		else if (host->last_byte < 8)
+-			ret = brcmnand_read_reg(ctrl, BRCMNAND_ID_EXT) >>
+-				(56 - (host->last_byte << 3));
+-		break;
+-
+-	case NAND_CMD_READOOB:
+-		ret = oob_reg_read(ctrl, host->last_byte);
+-		break;
+-
+-	case NAND_CMD_STATUS:
+-		ret = brcmnand_read_reg(ctrl, BRCMNAND_INTFC_STATUS) &
+-					INTFC_FLASH_STATUS;
+-		if (wp_on) /* hide WP status */
+-			ret |= NAND_STATUS_WP;
+-		break;
+-
+-	case NAND_CMD_PARAM:
+-	case NAND_CMD_RNDOUT:
+-		addr = host->last_addr + host->last_byte;
+-		offs = addr & (FC_BYTES - 1);
+-
+-		/* At FC_BYTES boundary, switch to next column */
+-		if (host->last_byte > 0 && offs == 0)
+-			chip->cmdfunc(mtd, NAND_CMD_RNDOUT, addr, -1);
+-
+-		ret = ctrl->flash_cache[offs];
+-		break;
+-	case NAND_CMD_GET_FEATURES:
+-		if (host->last_byte >= ONFI_SUBFEATURE_PARAM_LEN) {
+-			ret = 0;
+-		} else {
+-			bool last = host->last_byte ==
+-				ONFI_SUBFEATURE_PARAM_LEN - 1;
+-			brcmnand_low_level_op(host, LL_OP_RD, 0, last);
+-			ret = brcmnand_read_reg(ctrl, BRCMNAND_LL_RDATA) & 0xff;
+-		}
+-	}
+-
+-	dev_dbg(ctrl->dev, "read byte = 0x%02x\n", ret);
+-	host->last_byte++;
+-
+-	return ret;
+-}
+-
+-static void brcmnand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+-{
+-	int i;
+-
+-	for (i = 0; i < len; i++, buf++)
+-		*buf = brcmnand_read_byte(mtd);
+-}
+-
+-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 brcmnand_host *host = nand_get_controller_data(chip);
+-
+-	switch (host->last_cmd) {
+-	case NAND_CMD_SET_FEATURES:
+-		for (i = 0; i < len; i++)
+-			brcmnand_low_level_op(host, LL_OP_WR, buf[i],
+-						  (i + 1) == len);
+-		break;
+-	default:
+-		BUG();
+-		break;
+-	}
+-}
+-
+-/**
+- * Construct a FLASH_DMA descriptor as part of a linked list. You must know the
+- * following ahead of time:
+- *  - Is this descriptor the beginning or end of a linked list?
+- *  - What is the (DMA) address of the next descriptor in the linked list?
+- */
+-static int brcmnand_fill_dma_desc(struct brcmnand_host *host,
+-				  struct brcm_nand_dma_desc *desc, u64 addr,
+-				  dma_addr_t buf, u32 len, u8 dma_cmd,
+-				  bool begin, bool end,
+-				  dma_addr_t next_desc)
+-{
+-	memset(desc, 0, sizeof(*desc));
+-	/* Descriptors are written in native byte order (wordwise) */
+-	desc->next_desc = lower_32_bits(next_desc);
+-	desc->next_desc_ext = upper_32_bits(next_desc);
+-	desc->cmd_irq = (dma_cmd << 24) |
+-		(end ? (0x03 << 8) : 0) | /* IRQ | STOP */
+-		(!!begin) | ((!!end) << 1); /* head, tail */
+-#ifdef CONFIG_CPU_BIG_ENDIAN
+-	desc->cmd_irq |= 0x01 << 12;
+-#endif
+-	desc->dram_addr = lower_32_bits(buf);
+-	desc->dram_addr_ext = upper_32_bits(buf);
+-	desc->tfr_len = len;
+-	desc->total_len = len;
+-	desc->flash_addr = lower_32_bits(addr);
+-	desc->flash_addr_ext = upper_32_bits(addr);
+-	desc->cs = host->cs;
+-	desc->status_valid = 0x01;
+-	return 0;
+-}
+-
+-/**
+- * Kick the FLASH_DMA engine, with a given DMA descriptor
+- */
+-static void brcmnand_dma_run(struct brcmnand_host *host, dma_addr_t desc)
+-{
+-	struct brcmnand_controller *ctrl = host->ctrl;
+-	unsigned long timeo = msecs_to_jiffies(100);
+-
+-	flash_dma_writel(ctrl, FLASH_DMA_FIRST_DESC, lower_32_bits(desc));
+-	(void)flash_dma_readl(ctrl, FLASH_DMA_FIRST_DESC);
+-	flash_dma_writel(ctrl, FLASH_DMA_FIRST_DESC_EXT, upper_32_bits(desc));
+-	(void)flash_dma_readl(ctrl, FLASH_DMA_FIRST_DESC_EXT);
+-
+-	/* Start FLASH_DMA engine */
+-	ctrl->dma_pending = true;
+-	mb(); /* flush previous writes */
+-	flash_dma_writel(ctrl, FLASH_DMA_CTRL, 0x03); /* wake | run */
+-
+-	if (wait_for_completion_timeout(&ctrl->dma_done, timeo) <= 0) {
+-		dev_err(ctrl->dev,
+-				"timeout waiting for DMA; status %#x, error status %#x\n",
+-				flash_dma_readl(ctrl, FLASH_DMA_STATUS),
+-				flash_dma_readl(ctrl, FLASH_DMA_ERROR_STATUS));
+-	}
+-	ctrl->dma_pending = false;
+-	flash_dma_writel(ctrl, FLASH_DMA_CTRL, 0); /* force stop */
+-}
+-
+-static int brcmnand_dma_trans(struct brcmnand_host *host, u64 addr, u32 *buf,
+-			      u32 len, u8 dma_cmd)
+-{
+-	struct brcmnand_controller *ctrl = host->ctrl;
+-	dma_addr_t buf_pa;
+-	int dir = dma_cmd == CMD_PAGE_READ ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+-
+-	buf_pa = dma_map_single(ctrl->dev, buf, len, dir);
+-	if (dma_mapping_error(ctrl->dev, buf_pa)) {
+-		dev_err(ctrl->dev, "unable to map buffer for DMA\n");
+-		return -ENOMEM;
+-	}
+-
+-	brcmnand_fill_dma_desc(host, ctrl->dma_desc, addr, buf_pa, len,
+-				   dma_cmd, true, true, 0);
+-
+-	brcmnand_dma_run(host, ctrl->dma_pa);
+-
+-	dma_unmap_single(ctrl->dev, buf_pa, len, dir);
+-
+-	if (ctrl->dma_desc->status_valid & FLASH_DMA_ECC_ERROR)
+-		return -EBADMSG;
+-	else if (ctrl->dma_desc->status_valid & FLASH_DMA_CORR_ERROR)
+-		return -EUCLEAN;
+-
+-	return 0;
+-}
+-
+-/*
+- * Assumes proper CS is already set
+- */
+-static int brcmnand_read_by_pio(struct mtd_info *mtd, struct nand_chip *chip,
+-				u64 addr, unsigned int trans, u32 *buf,
+-				u8 *oob, u64 *err_addr)
+-{
+-	struct brcmnand_host *host = nand_get_controller_data(chip);
+-	struct brcmnand_controller *ctrl = host->ctrl;
+-	int i, j, ret = 0;
+-
+-	/* Clear error addresses */
+-	brcmnand_write_reg(ctrl, BRCMNAND_UNCORR_ADDR, 0);
+-	brcmnand_write_reg(ctrl, BRCMNAND_CORR_ADDR, 0);
+-	brcmnand_write_reg(ctrl, BRCMNAND_UNCORR_EXT_ADDR, 0);
+-	brcmnand_write_reg(ctrl, BRCMNAND_CORR_EXT_ADDR, 0);
+-
+-	brcmnand_write_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS,
+-			(host->cs << 16) | ((addr >> 32) & 0xffff));
+-	(void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS);
+-
+-	for (i = 0; i < trans; i++, addr += FC_BYTES) {
+-		brcmnand_write_reg(ctrl, BRCMNAND_CMD_ADDRESS,
+-				   lower_32_bits(addr));
+-		(void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS);
+-		/* SPARE_AREA_READ does not use ECC, so just use PAGE_READ */
+-		brcmnand_send_cmd(host, CMD_PAGE_READ);
+-		brcmnand_waitfunc(mtd, chip);
+-
+-		if (likely(buf)) {
+-			brcmnand_soc_data_bus_prepare(ctrl->soc, false);
+-
+-			for (j = 0; j < FC_WORDS; j++, buf++)
+-				*buf = brcmnand_read_fc(ctrl, j);
+-
+-			brcmnand_soc_data_bus_unprepare(ctrl->soc, false);
+-		}
+-
+-		if (oob)
+-			oob += read_oob_from_regs(ctrl, i, oob,
+-					mtd->oobsize / trans,
+-					host->hwcfg.sector_size_1k);
+-
+-		if (!ret) {
+-			*err_addr = brcmnand_read_reg(ctrl,
+-					BRCMNAND_UNCORR_ADDR) |
+-				((u64)(brcmnand_read_reg(ctrl,
+-						BRCMNAND_UNCORR_EXT_ADDR)
+-					& 0xffff) << 32);
+-			if (*err_addr)
+-				ret = -EBADMSG;
+-		}
+-
+-		if (!ret) {
+-			*err_addr = brcmnand_read_reg(ctrl,
+-					BRCMNAND_CORR_ADDR) |
+-				((u64)(brcmnand_read_reg(ctrl,
+-						BRCMNAND_CORR_EXT_ADDR)
+-					& 0xffff) << 32);
+-			if (*err_addr)
+-				ret = -EUCLEAN;
+-		}
+-	}
+-
+-	return ret;
+-}
+-
+-/*
+- * Check a page to see if it is erased (w/ bitflips) after an uncorrectable ECC
+- * error
+- *
+- * Because the HW ECC signals an ECC error if an erase paged has even a single
+- * bitflip, we must check each ECC error to see if it is actually an erased
+- * page with bitflips, not a truly corrupted page.
+- *
+- * On a real error, return a negative error code (-EBADMSG for ECC error), and
+- * buf will contain raw data.
+- * Otherwise, buf gets filled with 0xffs and return the maximum number of
+- * bitflips-per-ECC-sector to the caller.
+- *
+- */
+-static int brcmstb_nand_verify_erased_page(struct mtd_info *mtd,
+-		  struct nand_chip *chip, void *buf, u64 addr)
+-{
+-	int i, sas;
+-	void *oob = chip->oob_poi;
+-	int bitflips = 0;
+-	int page = addr >> chip->page_shift;
+-	int ret;
+-
+-	if (!buf) {
+-		buf = chip->buffers->databuf;
+-		/* Invalidate page cache */
+-		chip->pagebuf = -1;
+-	}
+-
+-	sas = mtd->oobsize / chip->ecc.steps;
+-
+-	/* read without ecc for verification */
+-	chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
+-	ret = chip->ecc.read_page_raw(mtd, chip, buf, true, page);
+-	if (ret)
+-		return ret;
+-
+-	for (i = 0; i < chip->ecc.steps; i++, oob += sas) {
+-		ret = nand_check_erased_ecc_chunk(buf, chip->ecc.size,
+-						  oob, sas, NULL, 0,
+-						  chip->ecc.strength);
+-		if (ret < 0)
+-			return ret;
+-
+-		bitflips = max(bitflips, ret);
+-	}
+-
+-	return bitflips;
+-}
+-
+-static int brcmnand_read(struct mtd_info *mtd, struct nand_chip *chip,
+-			 u64 addr, unsigned int trans, u32 *buf, u8 *oob)
+-{
+-	struct brcmnand_host *host = nand_get_controller_data(chip);
+-	struct brcmnand_controller *ctrl = host->ctrl;
+-	u64 err_addr = 0;
+-	int err;
+-	bool retry = true;
+-
+-	dev_dbg(ctrl->dev, "read %llx -> %p\n", (unsigned long long)addr, buf);
+-
+-try_dmaread:
+-	brcmnand_write_reg(ctrl, BRCMNAND_UNCORR_COUNT, 0);
+-
+-	if (has_flash_dma(ctrl) && !oob && flash_dma_buf_ok(buf)) {
+-		err = brcmnand_dma_trans(host, addr, buf, trans * FC_BYTES,
+-					     CMD_PAGE_READ);
+-		if (err) {
+-			if (mtd_is_bitflip_or_eccerr(err))
+-				err_addr = addr;
+-			else
+-				return -EIO;
+-		}
+-	} else {
+-		if (oob)
+-			memset(oob, 0x99, mtd->oobsize);
+-
+-		err = brcmnand_read_by_pio(mtd, chip, addr, trans, buf,
+-					       oob, &err_addr);
+-	}
+-
+-	if (mtd_is_eccerr(err)) {
+-		/*
+-		 * On controller version and 7.0, 7.1 , DMA read after a
+-		 * prior PIO read that reported uncorrectable error,
+-		 * the DMA engine captures this error following DMA read
+-		 * cleared only on subsequent DMA read, so just retry once
+-		 * to clear a possible false error reported for current DMA
+-		 * read
+-		 */
+-		if ((ctrl->nand_version == 0x0700) ||
+-		    (ctrl->nand_version == 0x0701)) {
+-			if (retry) {
+-				retry = false;
+-				goto try_dmaread;
+-			}
+-		}
+-
+-		/*
+-		 * Controller version 7.2 has hw encoder to detect erased page
+-		 * bitflips, apply sw verification for older controllers only
+-		 */
+-		if (ctrl->nand_version < 0x0702) {
+-			err = brcmstb_nand_verify_erased_page(mtd, chip, buf,
+-							      addr);
+-			/* erased page bitflips corrected */
+-			if (err > 0)
+-				return err;
+-		}
+-
+-		dev_dbg(ctrl->dev, "uncorrectable error at 0x%llx\n",
+-			(unsigned long long)err_addr);
+-		mtd->ecc_stats.failed++;
+-		/* NAND layer expects zero on ECC errors */
+-		return 0;
+-	}
+-
+-	if (mtd_is_bitflip(err)) {
+-		unsigned int corrected = brcmnand_count_corrected(ctrl);
+-
+-		dev_dbg(ctrl->dev, "corrected error at 0x%llx\n",
+-			(unsigned long long)err_addr);
+-		mtd->ecc_stats.corrected += corrected;
+-		/* Always exceed the software-imposed threshold */
+-		return max(mtd->bitflip_threshold, corrected);
+-	}
+-
+-	return 0;
+-}
+-
+-static int brcmnand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
+-			      uint8_t *buf, int oob_required, int page)
+-{
+-	struct brcmnand_host *host = nand_get_controller_data(chip);
+-	u8 *oob = oob_required ? (u8 *)chip->oob_poi : NULL;
+-
+-	return brcmnand_read(mtd, chip, host->last_addr,
+-			mtd->writesize >> FC_SHIFT, (u32 *)buf, oob);
+-}
+-
+-static int brcmnand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+-				  uint8_t *buf, int oob_required, int page)
+-{
+-	struct brcmnand_host *host = nand_get_controller_data(chip);
+-	u8 *oob = oob_required ? (u8 *)chip->oob_poi : NULL;
+-	int ret;
+-
+-	brcmnand_set_ecc_enabled(host, 0);
+-	ret = brcmnand_read(mtd, chip, host->last_addr,
+-			mtd->writesize >> FC_SHIFT, (u32 *)buf, oob);
+-	brcmnand_set_ecc_enabled(host, 1);
+-	return ret;
+-}
+-
+-static int brcmnand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
+-			     int page)
+-{
+-	return brcmnand_read(mtd, chip, (u64)page << chip->page_shift,
+-			mtd->writesize >> FC_SHIFT,
+-			NULL, (u8 *)chip->oob_poi);
+-}
+-
+-static int brcmnand_read_oob_raw(struct mtd_info *mtd, struct nand_chip *chip,
+-				 int page)
+-{
+-	struct brcmnand_host *host = nand_get_controller_data(chip);
+-
+-	brcmnand_set_ecc_enabled(host, 0);
+-	brcmnand_read(mtd, chip, (u64)page << chip->page_shift,
+-		mtd->writesize >> FC_SHIFT,
+-		NULL, (u8 *)chip->oob_poi);
+-	brcmnand_set_ecc_enabled(host, 1);
+-	return 0;
+-}
+-
+-static int brcmnand_write(struct mtd_info *mtd, struct nand_chip *chip,
+-			  u64 addr, const u32 *buf, u8 *oob)
+-{
+-	struct brcmnand_host *host = nand_get_controller_data(chip);
+-	struct brcmnand_controller *ctrl = host->ctrl;
+-	unsigned int i, j, trans = mtd->writesize >> FC_SHIFT;
+-	int status, ret = 0;
+-
+-	dev_dbg(ctrl->dev, "write %llx <- %p\n", (unsigned long long)addr, buf);
+-
+-	if (unlikely((unsigned long)buf & 0x03)) {
+-		dev_warn(ctrl->dev, "unaligned buffer: %p\n", buf);
+-		buf = (u32 *)((unsigned long)buf & ~0x03);
+-	}
+-
+-	brcmnand_wp(mtd, 0);
+-
+-	for (i = 0; i < ctrl->max_oob; i += 4)
+-		oob_reg_write(ctrl, i, 0xffffffff);
+-
+-	if (has_flash_dma(ctrl) && !oob && flash_dma_buf_ok(buf)) {
+-		if (brcmnand_dma_trans(host, addr, (u32 *)buf,
+-					mtd->writesize, CMD_PROGRAM_PAGE))
+-			ret = -EIO;
+-		goto out;
+-	}
+-
+-	brcmnand_write_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS,
+-			(host->cs << 16) | ((addr >> 32) & 0xffff));
+-	(void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS);
+-
+-	for (i = 0; i < trans; i++, addr += FC_BYTES) {
+-		/* full address MUST be set before populating FC */
+-		brcmnand_write_reg(ctrl, BRCMNAND_CMD_ADDRESS,
+-				   lower_32_bits(addr));
+-		(void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS);
+-
+-		if (buf) {
+-			brcmnand_soc_data_bus_prepare(ctrl->soc, false);
+-
+-			for (j = 0; j < FC_WORDS; j++, buf++)
+-				brcmnand_write_fc(ctrl, j, *buf);
+-
+-			brcmnand_soc_data_bus_unprepare(ctrl->soc, false);
+-		} else if (oob) {
+-			for (j = 0; j < FC_WORDS; j++)
+-				brcmnand_write_fc(ctrl, j, 0xffffffff);
+-		}
+-
+-		if (oob) {
+-			oob += write_oob_to_regs(ctrl, i, oob,
+-					mtd->oobsize / trans,
+-					host->hwcfg.sector_size_1k);
+-		}
+-
+-		/* we cannot use SPARE_AREA_PROGRAM when PARTIAL_PAGE_EN=0 */
+-		brcmnand_send_cmd(host, CMD_PROGRAM_PAGE);
+-		status = brcmnand_waitfunc(mtd, chip);
+-
+-		if (status & NAND_STATUS_FAIL) {
+-			dev_info(ctrl->dev, "program failed at %llx\n",
+-				(unsigned long long)addr);
+-			ret = -EIO;
+-			goto out;
+-		}
+-	}
+-out:
+-	brcmnand_wp(mtd, 1);
+-	return ret;
+-}
+-
+-static int brcmnand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
+-			       const uint8_t *buf, int oob_required, int page)
+-{
+-	struct brcmnand_host *host = nand_get_controller_data(chip);
+-	void *oob = oob_required ? chip->oob_poi : NULL;
+-
+-	brcmnand_write(mtd, chip, host->last_addr, (const u32 *)buf, oob);
+-	return 0;
+-}
+-
+-static int brcmnand_write_page_raw(struct mtd_info *mtd,
+-				   struct nand_chip *chip, const uint8_t *buf,
+-				   int oob_required, int page)
+-{
+-	struct brcmnand_host *host = nand_get_controller_data(chip);
+-	void *oob = oob_required ? chip->oob_poi : NULL;
+-
+-	brcmnand_set_ecc_enabled(host, 0);
+-	brcmnand_write(mtd, chip, host->last_addr, (const u32 *)buf, oob);
+-	brcmnand_set_ecc_enabled(host, 1);
+-	return 0;
+-}
+-
+-static int brcmnand_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
+-				  int page)
+-{
+-	return brcmnand_write(mtd, chip, (u64)page << chip->page_shift,
+-				  NULL, chip->oob_poi);
+-}
+-
+-static int brcmnand_write_oob_raw(struct mtd_info *mtd, struct nand_chip *chip,
+-				  int page)
+-{
+-	struct brcmnand_host *host = nand_get_controller_data(chip);
+-	int ret;
+-
+-	brcmnand_set_ecc_enabled(host, 0);
+-	ret = brcmnand_write(mtd, chip, (u64)page << chip->page_shift, NULL,
+-				 (u8 *)chip->oob_poi);
+-	brcmnand_set_ecc_enabled(host, 1);
+-
+-	return ret;
+-}
+-
+-/***********************************************************************
+- * Per-CS setup (1 NAND device)
+- ***********************************************************************/
+-
+-static int brcmnand_set_cfg(struct brcmnand_host *host,
+-			    struct brcmnand_cfg *cfg)
+-{
+-	struct brcmnand_controller *ctrl = host->ctrl;
+-	struct nand_chip *chip = &host->chip;
+-	u16 cfg_offs = brcmnand_cs_offset(ctrl, host->cs, BRCMNAND_CS_CFG);
+-	u16 cfg_ext_offs = brcmnand_cs_offset(ctrl, host->cs,
+-			BRCMNAND_CS_CFG_EXT);
+-	u16 acc_control_offs = brcmnand_cs_offset(ctrl, host->cs,
+-			BRCMNAND_CS_ACC_CONTROL);
+-	u8 block_size = 0, page_size = 0, device_size = 0;
+-	u32 tmp;
+-
+-	if (ctrl->block_sizes) {
+-		int i, found;
+-
+-		for (i = 0, found = 0; ctrl->block_sizes[i]; i++)
+-			if (ctrl->block_sizes[i] * 1024 == cfg->block_size) {
+-				block_size = i;
+-				found = 1;
+-			}
+-		if (!found) {
+-			dev_warn(ctrl->dev, "invalid block size %u\n",
+-					cfg->block_size);
+-			return -EINVAL;
+-		}
+-	} else {
+-		block_size = ffs(cfg->block_size) - ffs(BRCMNAND_MIN_BLOCKSIZE);
+-	}
+-
+-	if (cfg->block_size < BRCMNAND_MIN_BLOCKSIZE || (ctrl->max_block_size &&
+-				cfg->block_size > ctrl->max_block_size)) {
+-		dev_warn(ctrl->dev, "invalid block size %u\n",
+-				cfg->block_size);
+-		block_size = 0;
+-	}
+-
+-	if (ctrl->page_sizes) {
+-		int i, found;
+-
+-		for (i = 0, found = 0; ctrl->page_sizes[i]; i++)
+-			if (ctrl->page_sizes[i] == cfg->page_size) {
+-				page_size = i;
+-				found = 1;
+-			}
+-		if (!found) {
+-			dev_warn(ctrl->dev, "invalid page size %u\n",
+-					cfg->page_size);
+-			return -EINVAL;
+-		}
+-	} else {
+-		page_size = ffs(cfg->page_size) - ffs(BRCMNAND_MIN_PAGESIZE);
+-	}
+-
+-	if (cfg->page_size < BRCMNAND_MIN_PAGESIZE || (ctrl->max_page_size &&
+-				cfg->page_size > ctrl->max_page_size)) {
+-		dev_warn(ctrl->dev, "invalid page size %u\n", cfg->page_size);
+-		return -EINVAL;
+-	}
+-
+-	if (fls64(cfg->device_size) < fls64(BRCMNAND_MIN_DEVSIZE)) {
+-		dev_warn(ctrl->dev, "invalid device size 0x%llx\n",
+-			(unsigned long long)cfg->device_size);
+-		return -EINVAL;
+-	}
+-	device_size = fls64(cfg->device_size) - fls64(BRCMNAND_MIN_DEVSIZE);
+-
+-	tmp = (cfg->blk_adr_bytes << CFG_BLK_ADR_BYTES_SHIFT) |
+-		(cfg->col_adr_bytes << CFG_COL_ADR_BYTES_SHIFT) |
+-		(cfg->ful_adr_bytes << CFG_FUL_ADR_BYTES_SHIFT) |
+-		(!!(cfg->device_width == 16) << CFG_BUS_WIDTH_SHIFT) |
+-		(device_size << CFG_DEVICE_SIZE_SHIFT);
+-	if (cfg_offs == cfg_ext_offs) {
+-		tmp |= (page_size << CFG_PAGE_SIZE_SHIFT) |
+-		       (block_size << CFG_BLK_SIZE_SHIFT);
+-		nand_writereg(ctrl, cfg_offs, tmp);
+-	} else {
+-		nand_writereg(ctrl, cfg_offs, tmp);
+-		tmp = (page_size << CFG_EXT_PAGE_SIZE_SHIFT) |
+-		      (block_size << CFG_EXT_BLK_SIZE_SHIFT);
+-		nand_writereg(ctrl, cfg_ext_offs, tmp);
+-	}
+-
+-	tmp = nand_readreg(ctrl, acc_control_offs);
+-	tmp &= ~brcmnand_ecc_level_mask(ctrl);
+-	tmp |= cfg->ecc_level << NAND_ACC_CONTROL_ECC_SHIFT;
+-	tmp &= ~brcmnand_spare_area_mask(ctrl);
+-	tmp |= cfg->spare_area_size;
+-	nand_writereg(ctrl, acc_control_offs, tmp);
+-
+-	brcmnand_set_sector_size_1k(host, cfg->sector_size_1k);
+-
+-	/* threshold = ceil(BCH-level * 0.75) */
+-	brcmnand_wr_corr_thresh(host, DIV_ROUND_UP(chip->ecc.strength * 3, 4));
+-
+-	return 0;
+-}
+-
+-static void brcmnand_print_cfg(struct brcmnand_host *host,
+-			       char *buf, struct brcmnand_cfg *cfg)
+-{
+-	buf += sprintf(buf,
+-		"%lluMiB total, %uKiB blocks, %u%s pages, %uB OOB, %u-bit",
+-		(unsigned long long)cfg->device_size >> 20,
+-		cfg->block_size >> 10,
+-		cfg->page_size >= 1024 ? cfg->page_size >> 10 : cfg->page_size,
+-		cfg->page_size >= 1024 ? "KiB" : "B",
+-		cfg->spare_area_size, cfg->device_width);
+-
+-	/* Account for Hamming ECC and for BCH 512B vs 1KiB sectors */
+-	if (is_hamming_ecc(host->ctrl, cfg))
+-		sprintf(buf, ", Hamming ECC");
+-	else if (cfg->sector_size_1k)
+-		sprintf(buf, ", BCH-%u (1KiB sector)", cfg->ecc_level << 1);
+-	else
+-		sprintf(buf, ", BCH-%u", cfg->ecc_level);
+-}
+-
+-/*
+- * Minimum number of bytes to address a page. Calculated as:
+- *     roundup(log2(size / page-size) / 8)
+- *
+- * NB: the following does not "round up" for non-power-of-2 'size'; but this is
+- *     OK because many other things will break if 'size' is irregular...
+- */
+-static inline int get_blk_adr_bytes(u64 size, u32 writesize)
+-{
+-	return ALIGN(ilog2(size) - ilog2(writesize), 8) >> 3;
+-}
+-
+-static int brcmnand_setup_dev(struct brcmnand_host *host)
+-{
+-	struct mtd_info *mtd = nand_to_mtd(&host->chip);
+-	struct nand_chip *chip = &host->chip;
+-	struct brcmnand_controller *ctrl = host->ctrl;
+-	struct brcmnand_cfg *cfg = &host->hwcfg;
+-	char msg[128];
+-	u32 offs, tmp, oob_sector;
+-	int ret;
+-
+-	memset(cfg, 0, sizeof(*cfg));
+-
+-	ret = of_property_read_u32(nand_get_flash_node(chip),
+-				   "brcm,nand-oob-sector-size",
+-				   &oob_sector);
+-	if (ret) {
+-		/* Use detected size */
+-		cfg->spare_area_size = mtd->oobsize /
+-					(mtd->writesize >> FC_SHIFT);
+-	} else {
+-		cfg->spare_area_size = oob_sector;
+-	}
+-	if (cfg->spare_area_size > ctrl->max_oob)
+-		cfg->spare_area_size = ctrl->max_oob;
+-	/*
+-	 * Set oobsize to be consistent with controller's spare_area_size, as
+-	 * the rest is inaccessible.
+-	 */
+-	mtd->oobsize = cfg->spare_area_size * (mtd->writesize >> FC_SHIFT);
+-
+-	cfg->device_size = mtd->size;
+-	cfg->block_size = mtd->erasesize;
+-	cfg->page_size = mtd->writesize;
+-	cfg->device_width = (chip->options & NAND_BUSWIDTH_16) ? 16 : 8;
+-	cfg->col_adr_bytes = 2;
+-	cfg->blk_adr_bytes = get_blk_adr_bytes(mtd->size, mtd->writesize);
+-
+-	if (chip->ecc.mode != NAND_ECC_HW) {
+-		dev_err(ctrl->dev, "only HW ECC supported; selected: %d\n",
+-			chip->ecc.mode);
+-		return -EINVAL;
+-	}
+-
+-	if (chip->ecc.algo == NAND_ECC_UNKNOWN) {
+-		if (chip->ecc.strength == 1 && chip->ecc.size == 512)
+-			/* Default to Hamming for 1-bit ECC, if unspecified */
+-			chip->ecc.algo = NAND_ECC_HAMMING;
+-		else
+-			/* Otherwise, BCH */
+-			chip->ecc.algo = NAND_ECC_BCH;
+-	}
+-
+-	if (chip->ecc.algo == NAND_ECC_HAMMING && (chip->ecc.strength != 1 ||
+-						   chip->ecc.size != 512)) {
+-		dev_err(ctrl->dev, "invalid Hamming params: %d bits per %d bytes\n",
+-			chip->ecc.strength, chip->ecc.size);
+-		return -EINVAL;
+-	}
+-
+-	switch (chip->ecc.size) {
+-	case 512:
+-		if (chip->ecc.algo == NAND_ECC_HAMMING)
+-			cfg->ecc_level = 15;
+-		else
+-			cfg->ecc_level = chip->ecc.strength;
+-		cfg->sector_size_1k = 0;
+-		break;
+-	case 1024:
+-		if (!(ctrl->features & BRCMNAND_HAS_1K_SECTORS)) {
+-			dev_err(ctrl->dev, "1KB sectors not supported\n");
+-			return -EINVAL;
+-		}
+-		if (chip->ecc.strength & 0x1) {
+-			dev_err(ctrl->dev,
+-				"odd ECC not supported with 1KB sectors\n");
+-			return -EINVAL;
+-		}
+-
+-		cfg->ecc_level = chip->ecc.strength >> 1;
+-		cfg->sector_size_1k = 1;
+-		break;
+-	default:
+-		dev_err(ctrl->dev, "unsupported ECC size: %d\n",
+-			chip->ecc.size);
+-		return -EINVAL;
+-	}
+-
+-	cfg->ful_adr_bytes = cfg->blk_adr_bytes;
+-	if (mtd->writesize > 512)
+-		cfg->ful_adr_bytes += cfg->col_adr_bytes;
+-	else
+-		cfg->ful_adr_bytes += 1;
+-
+-	ret = brcmnand_set_cfg(host, cfg);
+-	if (ret)
+-		return ret;
+-
+-	brcmnand_set_ecc_enabled(host, 1);
+-
+-	brcmnand_print_cfg(host, msg, cfg);
+-	dev_info(ctrl->dev, "detected %s\n", msg);
+-
+-	/* Configure ACC_CONTROL */
+-	offs = brcmnand_cs_offset(ctrl, host->cs, BRCMNAND_CS_ACC_CONTROL);
+-	tmp = nand_readreg(ctrl, offs);
+-	tmp &= ~ACC_CONTROL_PARTIAL_PAGE;
+-	tmp &= ~ACC_CONTROL_RD_ERASED;
+-
+-	/* We need to turn on Read from erased paged protected by ECC */
+-	if (ctrl->nand_version >= 0x0702)
+-		tmp |= ACC_CONTROL_RD_ERASED;
+-	tmp &= ~ACC_CONTROL_FAST_PGM_RDIN;
+-	if (ctrl->features & BRCMNAND_HAS_PREFETCH) {
+-		/*
+-		 * FIXME: Flash DMA + prefetch may see spurious erased-page ECC
+-		 * errors
+-		 */
+-		if (has_flash_dma(ctrl))
+-			tmp &= ~ACC_CONTROL_PREFETCH;
+-		else
+-			tmp |= ACC_CONTROL_PREFETCH;
+-	}
+-	nand_writereg(ctrl, offs, tmp);
+-
+-	return 0;
+-}
+-
+-static int brcmnand_init_cs(struct brcmnand_host *host, struct device_node *dn)
+-{
+-	struct brcmnand_controller *ctrl = host->ctrl;
+-	struct platform_device *pdev = host->pdev;
+-	struct mtd_info *mtd;
+-	struct nand_chip *chip;
+-	int ret;
+-	u16 cfg_offs;
+-
+-	ret = of_property_read_u32(dn, "reg", &host->cs);
+-	if (ret) {
+-		dev_err(&pdev->dev, "can't get chip-select\n");
+-		return -ENXIO;
+-	}
+-
+-	mtd = nand_to_mtd(&host->chip);
+-	chip = &host->chip;
+-
+-	nand_set_flash_node(chip, dn);
+-	nand_set_controller_data(chip, host);
+-	mtd->name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "brcmnand.%d",
+-				   host->cs);
+-	mtd->owner = THIS_MODULE;
+-	mtd->dev.parent = &pdev->dev;
+-
+-	chip->IO_ADDR_R = (void __iomem *)0xdeadbeef;
+-	chip->IO_ADDR_W = (void __iomem *)0xdeadbeef;
+-
+-	chip->cmd_ctrl = brcmnand_cmd_ctrl;
+-	chip->cmdfunc = brcmnand_cmdfunc;
+-	chip->waitfunc = brcmnand_waitfunc;
+-	chip->read_byte = brcmnand_read_byte;
+-	chip->read_buf = brcmnand_read_buf;
+-	chip->write_buf = brcmnand_write_buf;
+-
+-	chip->ecc.mode = NAND_ECC_HW;
+-	chip->ecc.read_page = brcmnand_read_page;
+-	chip->ecc.write_page = brcmnand_write_page;
+-	chip->ecc.read_page_raw = brcmnand_read_page_raw;
+-	chip->ecc.write_page_raw = brcmnand_write_page_raw;
+-	chip->ecc.write_oob_raw = brcmnand_write_oob_raw;
+-	chip->ecc.read_oob_raw = brcmnand_read_oob_raw;
+-	chip->ecc.read_oob = brcmnand_read_oob;
+-	chip->ecc.write_oob = brcmnand_write_oob;
+-
+-	chip->controller = &ctrl->controller;
+-
+-	/*
+-	 * The bootloader might have configured 16bit mode but
+-	 * NAND READID command only works in 8bit mode. We force
+-	 * 8bit mode here to ensure that NAND READID commands works.
+-	 */
+-	cfg_offs = brcmnand_cs_offset(ctrl, host->cs, BRCMNAND_CS_CFG);
+-	nand_writereg(ctrl, cfg_offs,
+-		      nand_readreg(ctrl, cfg_offs) & ~CFG_BUS_WIDTH);
+-
+-	ret = nand_scan_ident(mtd, 1, NULL);
+-	if (ret)
+-		return ret;
+-
+-	chip->options |= NAND_NO_SUBPAGE_WRITE;
+-	/*
+-	 * Avoid (for instance) kmap()'d buffers from JFFS2, which we can't DMA
+-	 * to/from, and have nand_base pass us a bounce buffer instead, as
+-	 * needed.
+-	 */
+-	chip->options |= NAND_USE_BOUNCE_BUFFER;
+-
+-	if (chip->bbt_options & NAND_BBT_USE_FLASH)
+-		chip->bbt_options |= NAND_BBT_NO_OOB;
+-
+-	if (brcmnand_setup_dev(host))
+-		return -ENXIO;
+-
+-	chip->ecc.size = host->hwcfg.sector_size_1k ? 1024 : 512;
+-	/* only use our internal HW threshold */
+-	mtd->bitflip_threshold = 1;
+-
+-	ret = brcmstb_choose_ecc_layout(host);
+-	if (ret)
+-		return ret;
+-
+-	ret = nand_scan_tail(mtd);
+-	if (ret)
+-		return ret;
+-
+-	return mtd_device_register(mtd, NULL, 0);
+-}
+-
+-static void brcmnand_save_restore_cs_config(struct brcmnand_host *host,
+-					    int restore)
+-{
+-	struct brcmnand_controller *ctrl = host->ctrl;
+-	u16 cfg_offs = brcmnand_cs_offset(ctrl, host->cs, BRCMNAND_CS_CFG);
+-	u16 cfg_ext_offs = brcmnand_cs_offset(ctrl, host->cs,
+-			BRCMNAND_CS_CFG_EXT);
+-	u16 acc_control_offs = brcmnand_cs_offset(ctrl, host->cs,
+-			BRCMNAND_CS_ACC_CONTROL);
+-	u16 t1_offs = brcmnand_cs_offset(ctrl, host->cs, BRCMNAND_CS_TIMING1);
+-	u16 t2_offs = brcmnand_cs_offset(ctrl, host->cs, BRCMNAND_CS_TIMING2);
+-
+-	if (restore) {
+-		nand_writereg(ctrl, cfg_offs, host->hwcfg.config);
+-		if (cfg_offs != cfg_ext_offs)
+-			nand_writereg(ctrl, cfg_ext_offs,
+-				      host->hwcfg.config_ext);
+-		nand_writereg(ctrl, acc_control_offs, host->hwcfg.acc_control);
+-		nand_writereg(ctrl, t1_offs, host->hwcfg.timing_1);
+-		nand_writereg(ctrl, t2_offs, host->hwcfg.timing_2);
+-	} else {
+-		host->hwcfg.config = nand_readreg(ctrl, cfg_offs);
+-		if (cfg_offs != cfg_ext_offs)
+-			host->hwcfg.config_ext =
+-				nand_readreg(ctrl, cfg_ext_offs);
+-		host->hwcfg.acc_control = nand_readreg(ctrl, acc_control_offs);
+-		host->hwcfg.timing_1 = nand_readreg(ctrl, t1_offs);
+-		host->hwcfg.timing_2 = nand_readreg(ctrl, t2_offs);
+-	}
+-}
+-
+-static int brcmnand_suspend(struct device *dev)
+-{
+-	struct brcmnand_controller *ctrl = dev_get_drvdata(dev);
+-	struct brcmnand_host *host;
+-
+-	list_for_each_entry(host, &ctrl->host_list, node)
+-		brcmnand_save_restore_cs_config(host, 0);
+-
+-	ctrl->nand_cs_nand_select = brcmnand_read_reg(ctrl, BRCMNAND_CS_SELECT);
+-	ctrl->nand_cs_nand_xor = brcmnand_read_reg(ctrl, BRCMNAND_CS_XOR);
+-	ctrl->corr_stat_threshold =
+-		brcmnand_read_reg(ctrl, BRCMNAND_CORR_THRESHOLD);
+-
+-	if (has_flash_dma(ctrl))
+-		ctrl->flash_dma_mode = flash_dma_readl(ctrl, FLASH_DMA_MODE);
+-
+-	return 0;
+-}
+-
+-static int brcmnand_resume(struct device *dev)
+-{
+-	struct brcmnand_controller *ctrl = dev_get_drvdata(dev);
+-	struct brcmnand_host *host;
+-
+-	if (has_flash_dma(ctrl)) {
+-		flash_dma_writel(ctrl, FLASH_DMA_MODE, ctrl->flash_dma_mode);
+-		flash_dma_writel(ctrl, FLASH_DMA_ERROR_STATUS, 0);
+-	}
+-
+-	brcmnand_write_reg(ctrl, BRCMNAND_CS_SELECT, ctrl->nand_cs_nand_select);
+-	brcmnand_write_reg(ctrl, BRCMNAND_CS_XOR, ctrl->nand_cs_nand_xor);
+-	brcmnand_write_reg(ctrl, BRCMNAND_CORR_THRESHOLD,
+-			ctrl->corr_stat_threshold);
+-	if (ctrl->soc) {
+-		/* Clear/re-enable interrupt */
+-		ctrl->soc->ctlrdy_ack(ctrl->soc);
+-		ctrl->soc->ctlrdy_set_enabled(ctrl->soc, true);
+-	}
+-
+-	list_for_each_entry(host, &ctrl->host_list, node) {
+-		struct nand_chip *chip = &host->chip;
+-		struct mtd_info *mtd = nand_to_mtd(chip);
+-
+-		brcmnand_save_restore_cs_config(host, 1);
+-
+-		/* Reset the chip, required by some chips after power-up */
+-		chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
+-	}
+-
+-	return 0;
+-}
+-
+-const struct dev_pm_ops brcmnand_pm_ops = {
+-	.suspend		= brcmnand_suspend,
+-	.resume			= brcmnand_resume,
+-};
+-EXPORT_SYMBOL_GPL(brcmnand_pm_ops);
+-
+-static const struct of_device_id brcmnand_of_match[] = {
+-	{ .compatible = "brcm,brcmnand-v4.0" },
+-	{ .compatible = "brcm,brcmnand-v5.0" },
+-	{ .compatible = "brcm,brcmnand-v6.0" },
+-	{ .compatible = "brcm,brcmnand-v6.1" },
+-	{ .compatible = "brcm,brcmnand-v6.2" },
+-	{ .compatible = "brcm,brcmnand-v7.0" },
+-	{ .compatible = "brcm,brcmnand-v7.1" },
+-	{ .compatible = "brcm,brcmnand-v7.2" },
+-	{},
+-};
+-MODULE_DEVICE_TABLE(of, brcmnand_of_match);
+-
+-/***********************************************************************
+- * Platform driver setup (per controller)
+- ***********************************************************************/
+-
+-int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc)
+-{
+-	struct device *dev = &pdev->dev;
+-	struct device_node *dn = dev->of_node, *child;
+-	struct brcmnand_controller *ctrl;
+-	struct resource *res;
+-	int ret;
+-
+-	/* We only support device-tree instantiation */
+-	if (!dn)
+-		return -ENODEV;
+-
+-	if (!of_match_node(brcmnand_of_match, dn))
+-		return -ENODEV;
+-
+-	ctrl = devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL);
+-	if (!ctrl)
+-		return -ENOMEM;
+-
+-	dev_set_drvdata(dev, ctrl);
+-	ctrl->dev = dev;
+-
+-	init_completion(&ctrl->done);
+-	init_completion(&ctrl->dma_done);
+-	nand_hw_control_init(&ctrl->controller);
+-	INIT_LIST_HEAD(&ctrl->host_list);
+-
+-	/* NAND register range */
+-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+-	ctrl->nand_base = devm_ioremap_resource(dev, res);
+-	if (IS_ERR(ctrl->nand_base))
+-		return PTR_ERR(ctrl->nand_base);
+-
+-	/* Enable clock before using NAND registers */
+-	ctrl->clk = devm_clk_get(dev, "nand");
+-	if (!IS_ERR(ctrl->clk)) {
+-		ret = clk_prepare_enable(ctrl->clk);
+-		if (ret)
+-			return ret;
+-	} else {
+-		ret = PTR_ERR(ctrl->clk);
+-		if (ret == -EPROBE_DEFER)
+-			return ret;
+-
+-		ctrl->clk = NULL;
+-	}
+-
+-	/* Initialize NAND revision */
+-	ret = brcmnand_revision_init(ctrl);
+-	if (ret)
+-		goto err;
+-
+-	/*
+-	 * Most chips have this cache at a fixed offset within 'nand' block.
+-	 * Some must specify this region separately.
+-	 */
+-	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand-cache");
+-	if (res) {
+-		ctrl->nand_fc = devm_ioremap_resource(dev, res);
+-		if (IS_ERR(ctrl->nand_fc)) {
+-			ret = PTR_ERR(ctrl->nand_fc);
+-			goto err;
+-		}
+-	} else {
+-		ctrl->nand_fc = ctrl->nand_base +
+-				ctrl->reg_offsets[BRCMNAND_FC_BASE];
+-	}
+-
+-	/* FLASH_DMA */
+-	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "flash-dma");
+-	if (res) {
+-		ctrl->flash_dma_base = devm_ioremap_resource(dev, res);
+-		if (IS_ERR(ctrl->flash_dma_base)) {
+-			ret = PTR_ERR(ctrl->flash_dma_base);
+-			goto err;
+-		}
+-
+-		flash_dma_writel(ctrl, FLASH_DMA_MODE, 1); /* linked-list */
+-		flash_dma_writel(ctrl, FLASH_DMA_ERROR_STATUS, 0);
+-
+-		/* Allocate descriptor(s) */
+-		ctrl->dma_desc = dmam_alloc_coherent(dev,
+-						     sizeof(*ctrl->dma_desc),
+-						     &ctrl->dma_pa, GFP_KERNEL);
+-		if (!ctrl->dma_desc) {
+-			ret = -ENOMEM;
+-			goto err;
+-		}
+-
+-		ctrl->dma_irq = platform_get_irq(pdev, 1);
+-		if ((int)ctrl->dma_irq < 0) {
+-			dev_err(dev, "missing FLASH_DMA IRQ\n");
+-			ret = -ENODEV;
+-			goto err;
+-		}
+-
+-		ret = devm_request_irq(dev, ctrl->dma_irq,
+-				brcmnand_dma_irq, 0, DRV_NAME,
+-				ctrl);
+-		if (ret < 0) {
+-			dev_err(dev, "can't allocate IRQ %d: error %d\n",
+-					ctrl->dma_irq, ret);
+-			goto err;
+-		}
+-
+-		dev_info(dev, "enabling FLASH_DMA\n");
+-	}
+-
+-	/* Disable automatic device ID config, direct addressing */
+-	brcmnand_rmw_reg(ctrl, BRCMNAND_CS_SELECT,
+-			 CS_SELECT_AUTO_DEVICE_ID_CFG | 0xff, 0, 0);
+-	/* Disable XOR addressing */
+-	brcmnand_rmw_reg(ctrl, BRCMNAND_CS_XOR, 0xff, 0, 0);
+-
+-	if (ctrl->features & BRCMNAND_HAS_WP) {
+-		/* Permanently disable write protection */
+-		if (wp_on == 2)
+-			brcmnand_set_wp(ctrl, false);
+-	} else {
+-		wp_on = 0;
+-	}
+-
+-	/* IRQ */
+-	ctrl->irq = platform_get_irq(pdev, 0);
+-	if ((int)ctrl->irq < 0) {
+-		dev_err(dev, "no IRQ defined\n");
+-		ret = -ENODEV;
+-		goto err;
+-	}
+-
+-	/*
+-	 * Some SoCs integrate this controller (e.g., its interrupt bits) in
+-	 * interesting ways
+-	 */
+-	if (soc) {
+-		ctrl->soc = soc;
+-
+-		ret = devm_request_irq(dev, ctrl->irq, brcmnand_irq, 0,
+-				       DRV_NAME, ctrl);
+-
+-		/* Enable interrupt */
+-		ctrl->soc->ctlrdy_ack(ctrl->soc);
+-		ctrl->soc->ctlrdy_set_enabled(ctrl->soc, true);
+-	} else {
+-		/* Use standard interrupt infrastructure */
+-		ret = devm_request_irq(dev, ctrl->irq, brcmnand_ctlrdy_irq, 0,
+-				       DRV_NAME, ctrl);
+-	}
+-	if (ret < 0) {
+-		dev_err(dev, "can't allocate IRQ %d: error %d\n",
+-			ctrl->irq, ret);
+-		goto err;
+-	}
+-
+-	for_each_available_child_of_node(dn, child) {
+-		if (of_device_is_compatible(child, "brcm,nandcs")) {
+-			struct brcmnand_host *host;
+-
+-			host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL);
+-			if (!host) {
+-				of_node_put(child);
+-				ret = -ENOMEM;
+-				goto err;
+-			}
+-			host->pdev = pdev;
+-			host->ctrl = ctrl;
+-
+-			ret = brcmnand_init_cs(host, child);
+-			if (ret) {
+-				devm_kfree(dev, host);
+-				continue; /* Try all chip-selects */
+-			}
+-
+-			list_add_tail(&host->node, &ctrl->host_list);
+-		}
+-	}
+-
+-	/* No chip-selects could initialize properly */
+-	if (list_empty(&ctrl->host_list)) {
+-		ret = -ENODEV;
+-		goto err;
+-	}
+-
+-	return 0;
+-
+-err:
+-	clk_disable_unprepare(ctrl->clk);
+-	return ret;
+-
+-}
+-EXPORT_SYMBOL_GPL(brcmnand_probe);
+-
+-int brcmnand_remove(struct platform_device *pdev)
+-{
+-	struct brcmnand_controller *ctrl = dev_get_drvdata(&pdev->dev);
+-	struct brcmnand_host *host;
+-
+-	list_for_each_entry(host, &ctrl->host_list, node)
+-		nand_release(nand_to_mtd(&host->chip));
+-
+-	clk_disable_unprepare(ctrl->clk);
+-
+-	dev_set_drvdata(&pdev->dev, NULL);
+-
+-	return 0;
+-}
+-EXPORT_SYMBOL_GPL(brcmnand_remove);
+-
+-MODULE_LICENSE("GPL v2");
+-MODULE_AUTHOR("Kevin Cernekee");
+-MODULE_AUTHOR("Brian Norris");
+-MODULE_DESCRIPTION("NAND driver for Broadcom chips");
+-MODULE_ALIAS("platform:brcmnand");
+diff --git a/drivers/mtd/nand/brcmnand/brcmnand.h b/drivers/mtd/nand/brcmnand/brcmnand.h
+deleted file mode 100644
+index 5c44cd4..0000000
+--- a/drivers/mtd/nand/brcmnand/brcmnand.h
++++ /dev/null
+@@ -1,74 +0,0 @@
+-/*
+- * Copyright © 2015 Broadcom Corporation
+- *
+- * 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.
+- */
+-
+-#ifndef __BRCMNAND_H__
+-#define __BRCMNAND_H__
+-
+-#include <linux/types.h>
+-#include <linux/io.h>
+-
+-struct platform_device;
+-struct dev_pm_ops;
+-
+-struct brcmnand_soc {
+-	bool (*ctlrdy_ack)(struct brcmnand_soc *soc);
+-	void (*ctlrdy_set_enabled)(struct brcmnand_soc *soc, bool en);
+-	void (*prepare_data_bus)(struct brcmnand_soc *soc, bool prepare,
+-				 bool is_param);
+-};
+-
+-static inline void brcmnand_soc_data_bus_prepare(struct brcmnand_soc *soc,
+-						 bool is_param)
+-{
+-	if (soc && soc->prepare_data_bus)
+-		soc->prepare_data_bus(soc, true, is_param);
+-}
+-
+-static inline void brcmnand_soc_data_bus_unprepare(struct brcmnand_soc *soc,
+-						   bool is_param)
+-{
+-	if (soc && soc->prepare_data_bus)
+-		soc->prepare_data_bus(soc, false, is_param);
+-}
+-
+-static inline u32 brcmnand_readl(void __iomem *addr)
+-{
+-	/*
+-	 * MIPS endianness is configured by boot strap, which also reverses all
+-	 * bus endianness (i.e., big-endian CPU + big endian bus ==> native
+-	 * endian I/O).
+-	 *
+-	 * Other architectures (e.g., ARM) either do not support big endian, or
+-	 * else leave I/O in little endian mode.
+-	 */
+-	if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
+-		return __raw_readl(addr);
+-	else
+-		return readl_relaxed(addr);
+-}
+-
+-static inline void brcmnand_writel(u32 val, void __iomem *addr)
+-{
+-	/* See brcmnand_readl() comments */
+-	if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
+-		__raw_writel(val, addr);
+-	else
+-		writel_relaxed(val, addr);
+-}
+-
+-int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc);
+-int brcmnand_remove(struct platform_device *pdev);
+-
+-extern const struct dev_pm_ops brcmnand_pm_ops;
+-
+-#endif /* __BRCMNAND_H__ */
+diff --git a/drivers/mtd/nand/brcmnand/brcmstb_nand.c b/drivers/mtd/nand/brcmnand/brcmstb_nand.c
+deleted file mode 100644
+index 5c271077..0000000
+--- a/drivers/mtd/nand/brcmnand/brcmstb_nand.c
++++ /dev/null
+@@ -1,44 +0,0 @@
+-/*
+- * Copyright © 2015 Broadcom Corporation
+- *
+- * 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/device.h>
+-#include <linux/module.h>
+-#include <linux/platform_device.h>
+-
+-#include "brcmnand.h"
+-
+-static const struct of_device_id brcmstb_nand_of_match[] = {
+-	{ .compatible = "brcm,brcmnand" },
+-	{},
+-};
+-MODULE_DEVICE_TABLE(of, brcmstb_nand_of_match);
+-
+-static int brcmstb_nand_probe(struct platform_device *pdev)
+-{
+-	return brcmnand_probe(pdev, NULL);
+-}
+-
+-static struct platform_driver brcmstb_nand_driver = {
+-	.probe			= brcmstb_nand_probe,
+-	.remove			= brcmnand_remove,
+-	.driver = {
+-		.name		= "brcmstb_nand",
+-		.pm		= &brcmnand_pm_ops,
+-		.of_match_table = brcmstb_nand_of_match,
+-	}
+-};
+-module_platform_driver(brcmstb_nand_driver);
+-
+-MODULE_LICENSE("GPL v2");
+-MODULE_AUTHOR("Brian Norris");
+-MODULE_DESCRIPTION("NAND driver for Broadcom STB chips");
+diff --git a/drivers/mtd/nand/brcmnand/iproc_nand.c b/drivers/mtd/nand/brcmnand/iproc_nand.c
+deleted file mode 100644
+index 4c6ae11..0000000
+--- a/drivers/mtd/nand/brcmnand/iproc_nand.c
++++ /dev/null
+@@ -1,160 +0,0 @@
+-/*
+- * Copyright © 2015 Broadcom Corporation
+- *
+- * 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/device.h>
+-#include <linux/io.h>
+-#include <linux/ioport.h>
+-#include <linux/module.h>
+-#include <linux/of.h>
+-#include <linux/of_address.h>
+-#include <linux/platform_device.h>
+-#include <linux/slab.h>
+-
+-#include "brcmnand.h"
+-
+-struct iproc_nand_soc {
+-	struct brcmnand_soc soc;
+-
+-	void __iomem *idm_base;
+-	void __iomem *ext_base;
+-	spinlock_t idm_lock;
+-};
+-
+-#define IPROC_NAND_CTLR_READY_OFFSET       0x10
+-#define IPROC_NAND_CTLR_READY              BIT(0)
+-
+-#define IPROC_NAND_IO_CTRL_OFFSET          0x00
+-#define IPROC_NAND_APB_LE_MODE             BIT(24)
+-#define IPROC_NAND_INT_CTRL_READ_ENABLE    BIT(6)
+-
+-static bool iproc_nand_intc_ack(struct brcmnand_soc *soc)
+-{
+-	struct iproc_nand_soc *priv =
+-			container_of(soc, struct iproc_nand_soc, soc);
+-	void __iomem *mmio = priv->ext_base + IPROC_NAND_CTLR_READY_OFFSET;
+-	u32 val = brcmnand_readl(mmio);
+-
+-	if (val & IPROC_NAND_CTLR_READY) {
+-		brcmnand_writel(IPROC_NAND_CTLR_READY, mmio);
+-		return true;
+-	}
+-
+-	return false;
+-}
+-
+-static void iproc_nand_intc_set(struct brcmnand_soc *soc, bool en)
+-{
+-	struct iproc_nand_soc *priv =
+-			container_of(soc, struct iproc_nand_soc, soc);
+-	void __iomem *mmio = priv->idm_base + IPROC_NAND_IO_CTRL_OFFSET;
+-	u32 val;
+-	unsigned long flags;
+-
+-	spin_lock_irqsave(&priv->idm_lock, flags);
+-
+-	val = brcmnand_readl(mmio);
+-
+-	if (en)
+-		val |= IPROC_NAND_INT_CTRL_READ_ENABLE;
+-	else
+-		val &= ~IPROC_NAND_INT_CTRL_READ_ENABLE;
+-
+-	brcmnand_writel(val, mmio);
+-
+-	spin_unlock_irqrestore(&priv->idm_lock, flags);
+-}
+-
+-static void iproc_nand_apb_access(struct brcmnand_soc *soc, bool prepare,
+-				  bool is_param)
+-{
+-	struct iproc_nand_soc *priv =
+-			container_of(soc, struct iproc_nand_soc, soc);
+-	void __iomem *mmio = priv->idm_base + IPROC_NAND_IO_CTRL_OFFSET;
+-	u32 val;
+-	unsigned long flags;
+-
+-	spin_lock_irqsave(&priv->idm_lock, flags);
+-
+-	val = brcmnand_readl(mmio);
+-
+-	/*
+-	 * In the case of BE or when dealing with NAND data, alway configure
+-	 * the APB bus to LE mode before accessing the FIFO and back to BE mode
+-	 * after the access is done
+-	 */
+-	if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) || !is_param) {
+-		if (prepare)
+-			val |= IPROC_NAND_APB_LE_MODE;
+-		else
+-			val &= ~IPROC_NAND_APB_LE_MODE;
+-	} else { /* when in LE accessing the parameter page, keep APB in BE */
+-		val &= ~IPROC_NAND_APB_LE_MODE;
+-	}
+-
+-	brcmnand_writel(val, mmio);
+-
+-	spin_unlock_irqrestore(&priv->idm_lock, flags);
+-}
+-
+-static int iproc_nand_probe(struct platform_device *pdev)
+-{
+-	struct device *dev = &pdev->dev;
+-	struct iproc_nand_soc *priv;
+-	struct brcmnand_soc *soc;
+-	struct resource *res;
+-
+-	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+-	if (!priv)
+-		return -ENOMEM;
+-	soc = &priv->soc;
+-
+-	spin_lock_init(&priv->idm_lock);
+-
+-	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "iproc-idm");
+-	priv->idm_base = devm_ioremap_resource(dev, res);
+-	if (IS_ERR(priv->idm_base))
+-		return PTR_ERR(priv->idm_base);
+-
+-	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "iproc-ext");
+-	priv->ext_base = devm_ioremap_resource(dev, res);
+-	if (IS_ERR(priv->ext_base))
+-		return PTR_ERR(priv->ext_base);
+-
+-	soc->ctlrdy_ack = iproc_nand_intc_ack;
+-	soc->ctlrdy_set_enabled = iproc_nand_intc_set;
+-	soc->prepare_data_bus = iproc_nand_apb_access;
+-
+-	return brcmnand_probe(pdev, soc);
+-}
+-
+-static const struct of_device_id iproc_nand_of_match[] = {
+-	{ .compatible = "brcm,nand-iproc" },
+-	{},
+-};
+-MODULE_DEVICE_TABLE(of, iproc_nand_of_match);
+-
+-static struct platform_driver iproc_nand_driver = {
+-	.probe			= iproc_nand_probe,
+-	.remove			= brcmnand_remove,
+-	.driver = {
+-		.name		= "iproc_nand",
+-		.pm		= &brcmnand_pm_ops,
+-		.of_match_table	= iproc_nand_of_match,
+-	}
+-};
+-module_platform_driver(iproc_nand_driver);
+-
+-MODULE_LICENSE("GPL v2");
+-MODULE_AUTHOR("Brian Norris");
+-MODULE_AUTHOR("Ray Jui");
+-MODULE_DESCRIPTION("NAND driver for Broadcom IPROC-based SoCs");
+diff --git a/drivers/mtd/nand/cafe_nand.c b/drivers/mtd/nand/cafe_nand.c
+deleted file mode 100644
+index bc558c4..0000000
+--- a/drivers/mtd/nand/cafe_nand.c
++++ /dev/null
+@@ -1,899 +0,0 @@
+-/*
+- * Driver for One Laptop Per Child ‘CAFÉ’ controller, aka Marvell 88ALP01
+- *
+- * The data sheet for this device can be found at:
+- *    http://wiki.laptop.org/go/Datasheets 
+- *
+- * Copyright © 2006 Red Hat, Inc.
+- * Copyright © 2006 David Woodhouse <dwmw2@infradead.org>
+- */
+-
+-#define DEBUG
+-
+-#include <linux/device.h>
+-#undef DEBUG
+-#include <linux/mtd/mtd.h>
+-#include <linux/mtd/rawnand.h>
+-#include <linux/mtd/partitions.h>
+-#include <linux/rslib.h>
+-#include <linux/pci.h>
+-#include <linux/delay.h>
+-#include <linux/interrupt.h>
+-#include <linux/dma-mapping.h>
+-#include <linux/slab.h>
+-#include <linux/module.h>
+-#include <asm/io.h>
+-
+-#define CAFE_NAND_CTRL1		0x00
+-#define CAFE_NAND_CTRL2		0x04
+-#define CAFE_NAND_CTRL3		0x08
+-#define CAFE_NAND_STATUS	0x0c
+-#define CAFE_NAND_IRQ		0x10
+-#define CAFE_NAND_IRQ_MASK	0x14
+-#define CAFE_NAND_DATA_LEN	0x18
+-#define CAFE_NAND_ADDR1		0x1c
+-#define CAFE_NAND_ADDR2		0x20
+-#define CAFE_NAND_TIMING1	0x24
+-#define CAFE_NAND_TIMING2	0x28
+-#define CAFE_NAND_TIMING3	0x2c
+-#define CAFE_NAND_NONMEM	0x30
+-#define CAFE_NAND_ECC_RESULT	0x3C
+-#define CAFE_NAND_DMA_CTRL	0x40
+-#define CAFE_NAND_DMA_ADDR0	0x44
+-#define CAFE_NAND_DMA_ADDR1	0x48
+-#define CAFE_NAND_ECC_SYN01	0x50
+-#define CAFE_NAND_ECC_SYN23	0x54
+-#define CAFE_NAND_ECC_SYN45	0x58
+-#define CAFE_NAND_ECC_SYN67	0x5c
+-#define CAFE_NAND_READ_DATA	0x1000
+-#define CAFE_NAND_WRITE_DATA	0x2000
+-
+-#define CAFE_GLOBAL_CTRL	0x3004
+-#define CAFE_GLOBAL_IRQ		0x3008
+-#define CAFE_GLOBAL_IRQ_MASK	0x300c
+-#define CAFE_NAND_RESET		0x3034
+-
+-/* Missing from the datasheet: bit 19 of CTRL1 sets CE0 vs. CE1 */
+-#define CTRL1_CHIPSELECT	(1<<19)
+-
+-struct cafe_priv {
+-	struct nand_chip nand;
+-	struct pci_dev *pdev;
+-	void __iomem *mmio;
+-	struct rs_control *rs;
+-	uint32_t ctl1;
+-	uint32_t ctl2;
+-	int datalen;
+-	int nr_data;
+-	int data_pos;
+-	int page_addr;
+-	dma_addr_t dmaaddr;
+-	unsigned char *dmabuf;
+-};
+-
+-static int usedma = 1;
+-module_param(usedma, int, 0644);
+-
+-static int skipbbt = 0;
+-module_param(skipbbt, int, 0644);
+-
+-static int debug = 0;
+-module_param(debug, int, 0644);
+-
+-static int regdebug = 0;
+-module_param(regdebug, int, 0644);
+-
+-static int checkecc = 1;
+-module_param(checkecc, int, 0644);
+-
+-static unsigned int numtimings;
+-static int timing[3];
+-module_param_array(timing, int, &numtimings, 0644);
+-
+-static const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL };
+-
+-/* Hrm. Why isn't this already conditional on something in the struct device? */
+-#define cafe_dev_dbg(dev, args...) do { if (debug) dev_dbg(dev, ##args); } while(0)
+-
+-/* Make it easier to switch to PIO if we need to */
+-#define cafe_readl(cafe, addr)			readl((cafe)->mmio + CAFE_##addr)
+-#define cafe_writel(cafe, datum, addr)		writel(datum, (cafe)->mmio + CAFE_##addr)
+-
+-static int cafe_device_ready(struct mtd_info *mtd)
+-{
+-	struct nand_chip *chip = mtd_to_nand(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);
+-
+-	cafe_writel(cafe, irqs, NAND_IRQ);
+-
+-	cafe_dev_dbg(&cafe->pdev->dev, "NAND device is%s ready, IRQ %x (%x) (%x,%x)\n",
+-		result?"":" not", irqs, cafe_readl(cafe, NAND_IRQ),
+-		cafe_readl(cafe, GLOBAL_IRQ), cafe_readl(cafe, GLOBAL_IRQ_MASK));
+-
+-	return result;
+-}
+-
+-
+-static void cafe_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct cafe_priv *cafe = nand_get_controller_data(chip);
+-
+-	if (usedma)
+-		memcpy(cafe->dmabuf + cafe->datalen, buf, len);
+-	else
+-		memcpy_toio(cafe->mmio + CAFE_NAND_WRITE_DATA + cafe->datalen, buf, len);
+-
+-	cafe->datalen += len;
+-
+-	cafe_dev_dbg(&cafe->pdev->dev, "Copy 0x%x bytes to write buffer. datalen 0x%x\n",
+-		len, cafe->datalen);
+-}
+-
+-static void cafe_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct cafe_priv *cafe = nand_get_controller_data(chip);
+-
+-	if (usedma)
+-		memcpy(buf, cafe->dmabuf + cafe->datalen, len);
+-	else
+-		memcpy_fromio(buf, cafe->mmio + CAFE_NAND_READ_DATA + cafe->datalen, len);
+-
+-	cafe_dev_dbg(&cafe->pdev->dev, "Copy 0x%x bytes from position 0x%x in read buffer.\n",
+-		  len, cafe->datalen);
+-	cafe->datalen += len;
+-}
+-
+-static uint8_t cafe_read_byte(struct mtd_info *mtd)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct cafe_priv *cafe = nand_get_controller_data(chip);
+-	uint8_t d;
+-
+-	cafe_read_buf(mtd, &d, 1);
+-	cafe_dev_dbg(&cafe->pdev->dev, "Read %02x\n", d);
+-
+-	return d;
+-}
+-
+-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 cafe_priv *cafe = nand_get_controller_data(chip);
+-	int adrbytes = 0;
+-	uint32_t ctl1;
+-	uint32_t doneint = 0x80000000;
+-
+-	cafe_dev_dbg(&cafe->pdev->dev, "cmdfunc %02x, 0x%x, 0x%x\n",
+-		command, column, page_addr);
+-
+-	if (command == NAND_CMD_ERASE2 || command == NAND_CMD_PAGEPROG) {
+-		/* Second half of a command we already calculated */
+-		cafe_writel(cafe, cafe->ctl2 | 0x100 | command, NAND_CTRL2);
+-		ctl1 = cafe->ctl1;
+-		cafe->ctl2 &= ~(1<<30);
+-		cafe_dev_dbg(&cafe->pdev->dev, "Continue command, ctl1 %08x, #data %d\n",
+-			  cafe->ctl1, cafe->nr_data);
+-		goto do_command;
+-	}
+-	/* Reset ECC engine */
+-	cafe_writel(cafe, 0, NAND_CTRL2);
+-
+-	/* Emulate NAND_CMD_READOOB on large-page chips */
+-	if (mtd->writesize > 512 &&
+-	    command == NAND_CMD_READOOB) {
+-		column += mtd->writesize;
+-		command = NAND_CMD_READ0;
+-	}
+-
+-	/* FIXME: Do we need to send read command before sending data
+-	   for small-page chips, to position the buffer correctly? */
+-
+-	if (column != -1) {
+-		cafe_writel(cafe, column, NAND_ADDR1);
+-		adrbytes = 2;
+-		if (page_addr != -1)
+-			goto write_adr2;
+-	} else if (page_addr != -1) {
+-		cafe_writel(cafe, page_addr & 0xffff, NAND_ADDR1);
+-		page_addr >>= 16;
+-	write_adr2:
+-		cafe_writel(cafe, page_addr, NAND_ADDR2);
+-		adrbytes += 2;
+-		if (mtd->size > mtd->writesize << 16)
+-			adrbytes++;
+-	}
+-
+-	cafe->data_pos = cafe->datalen = 0;
+-
+-	/* Set command valid bit, mask in the chip select bit  */
+-	ctl1 = 0x80000000 | command | (cafe->ctl1 & CTRL1_CHIPSELECT);
+-
+-	/* Set RD or WR bits as appropriate */
+-	if (command == NAND_CMD_READID || command == NAND_CMD_STATUS) {
+-		ctl1 |= (1<<26); /* rd */
+-		/* Always 5 bytes, for now */
+-		cafe->datalen = 4;
+-		/* And one address cycle -- even for STATUS, since the controller doesn't work without */
+-		adrbytes = 1;
+-	} else if (command == NAND_CMD_READ0 || command == NAND_CMD_READ1 ||
+-		   command == NAND_CMD_READOOB || command == NAND_CMD_RNDOUT) {
+-		ctl1 |= 1<<26; /* rd */
+-		/* For now, assume just read to end of page */
+-		cafe->datalen = mtd->writesize + mtd->oobsize - column;
+-	} else if (command == NAND_CMD_SEQIN)
+-		ctl1 |= 1<<25; /* wr */
+-
+-	/* Set number of address bytes */
+-	if (adrbytes)
+-		ctl1 |= ((adrbytes-1)|8) << 27;
+-
+-	if (command == NAND_CMD_SEQIN || command == NAND_CMD_ERASE1) {
+-		/* Ignore the first command of a pair; the hardware
+-		   deals with them both at once, later */
+-		cafe->ctl1 = ctl1;
+-		cafe_dev_dbg(&cafe->pdev->dev, "Setup for delayed command, ctl1 %08x, dlen %x\n",
+-			  cafe->ctl1, cafe->datalen);
+-		return;
+-	}
+-	/* RNDOUT and READ0 commands need a following byte */
+-	if (command == NAND_CMD_RNDOUT)
+-		cafe_writel(cafe, cafe->ctl2 | 0x100 | NAND_CMD_RNDOUTSTART, NAND_CTRL2);
+-	else if (command == NAND_CMD_READ0 && mtd->writesize > 512)
+-		cafe_writel(cafe, cafe->ctl2 | 0x100 | NAND_CMD_READSTART, NAND_CTRL2);
+-
+- do_command:
+-	cafe_dev_dbg(&cafe->pdev->dev, "dlen %x, ctl1 %x, ctl2 %x\n",
+-		cafe->datalen, ctl1, cafe_readl(cafe, NAND_CTRL2));
+-
+-	/* NB: The datasheet lies -- we really should be subtracting 1 here */
+-	cafe_writel(cafe, cafe->datalen, NAND_DATA_LEN);
+-	cafe_writel(cafe, 0x90000000, NAND_IRQ);
+-	if (usedma && (ctl1 & (3<<25))) {
+-		uint32_t dmactl = 0xc0000000 + cafe->datalen;
+-		/* If WR or RD bits set, set up DMA */
+-		if (ctl1 & (1<<26)) {
+-			/* It's a read */
+-			dmactl |= (1<<29);
+-			/* ... so it's done when the DMA is done, not just
+-			   the command. */
+-			doneint = 0x10000000;
+-		}
+-		cafe_writel(cafe, dmactl, NAND_DMA_CTRL);
+-	}
+-	cafe->datalen = 0;
+-
+-	if (unlikely(regdebug)) {
+-		int i;
+-		printk("About to write command %08x to register 0\n", ctl1);
+-		for (i=4; i< 0x5c; i+=4)
+-			printk("Register %x: %08x\n", i, readl(cafe->mmio + i));
+-	}
+-
+-	cafe_writel(cafe, ctl1, NAND_CTRL1);
+-	/* Apply this short delay always to ensure that we do wait tWB in
+-	 * any case on any machine. */
+-	ndelay(100);
+-
+-	if (1) {
+-		int c;
+-		uint32_t irqs;
+-
+-		for (c = 500000; c != 0; c--) {
+-			irqs = cafe_readl(cafe, NAND_IRQ);
+-			if (irqs & doneint)
+-				break;
+-			udelay(1);
+-			if (!(c % 100000))
+-				cafe_dev_dbg(&cafe->pdev->dev, "Wait for ready, IRQ %x\n", irqs);
+-			cpu_relax();
+-		}
+-		cafe_writel(cafe, doneint, NAND_IRQ);
+-		cafe_dev_dbg(&cafe->pdev->dev, "Command %x completed after %d usec, irqs %x (%x)\n",
+-			     command, 500000-c, irqs, cafe_readl(cafe, NAND_IRQ));
+-	}
+-
+-	WARN_ON(cafe->ctl2 & (1<<30));
+-
+-	switch (command) {
+-
+-	case NAND_CMD_CACHEDPROG:
+-	case NAND_CMD_PAGEPROG:
+-	case NAND_CMD_ERASE1:
+-	case NAND_CMD_ERASE2:
+-	case NAND_CMD_SEQIN:
+-	case NAND_CMD_RNDIN:
+-	case NAND_CMD_STATUS:
+-	case NAND_CMD_RNDOUT:
+-		cafe_writel(cafe, cafe->ctl2, NAND_CTRL2);
+-		return;
+-	}
+-	nand_wait_ready(mtd);
+-	cafe_writel(cafe, cafe->ctl2, NAND_CTRL2);
+-}
+-
+-static void cafe_select_chip(struct mtd_info *mtd, int chipnr)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct cafe_priv *cafe = nand_get_controller_data(chip);
+-
+-	cafe_dev_dbg(&cafe->pdev->dev, "select_chip %d\n", chipnr);
+-
+-	/* Mask the appropriate bit into the stored value of ctl1
+-	   which will be used by cafe_nand_cmdfunc() */
+-	if (chipnr)
+-		cafe->ctl1 |= CTRL1_CHIPSELECT;
+-	else
+-		cafe->ctl1 &= ~CTRL1_CHIPSELECT;
+-}
+-
+-static irqreturn_t cafe_nand_interrupt(int irq, void *id)
+-{
+-	struct mtd_info *mtd = id;
+-	struct nand_chip *chip = mtd_to_nand(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);
+-	if (!irqs)
+-		return IRQ_NONE;
+-
+-	cafe_dev_dbg(&cafe->pdev->dev, "irq, bits %x (%x)\n", irqs, cafe_readl(cafe, NAND_IRQ));
+-	return IRQ_HANDLED;
+-}
+-
+-static void cafe_nand_bug(struct mtd_info *mtd)
+-{
+-	BUG();
+-}
+-
+-static int cafe_nand_write_oob(struct mtd_info *mtd,
+-			       struct nand_chip *chip, int page)
+-{
+-	int status = 0;
+-
+-	chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page);
+-	chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+-	chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+-	status = chip->waitfunc(mtd, chip);
+-
+-	return status & NAND_STATUS_FAIL ? -EIO : 0;
+-}
+-
+-/* Don't use -- use nand_read_oob_std for now */
+-static int cafe_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
+-			      int page)
+-{
+-	chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
+-	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+-	return 0;
+-}
+-/**
+- * cafe_nand_read_page_syndrome - [REPLACEABLE] hardware ecc syndrome based page read
+- * @mtd:	mtd info structure
+- * @chip:	nand chip info structure
+- * @buf:	buffer to store read data
+- * @oob_required:	caller expects OOB data read to chip->oob_poi
+- *
+- * The hw generator calculates the error syndrome automatically. Therefore
+- * we need a special oob layout and handling.
+- */
+-static int cafe_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
+-			       uint8_t *buf, int oob_required, int page)
+-{
+-	struct cafe_priv *cafe = nand_get_controller_data(chip);
+-	unsigned int max_bitflips = 0;
+-
+-	cafe_dev_dbg(&cafe->pdev->dev, "ECC result %08x SYN1,2 %08x\n",
+-		     cafe_readl(cafe, NAND_ECC_RESULT),
+-		     cafe_readl(cafe, NAND_ECC_SYN01));
+-
+-	chip->read_buf(mtd, buf, mtd->writesize);
+-	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+-
+-	if (checkecc && cafe_readl(cafe, NAND_ECC_RESULT) & (1<<18)) {
+-		unsigned short syn[8], pat[4];
+-		int pos[4];
+-		u8 *oob = chip->oob_poi;
+-		int i, n;
+-
+-		for (i=0; i<8; i+=2) {
+-			uint32_t tmp = cafe_readl(cafe, NAND_ECC_SYN01 + (i*2));
+-			syn[i] = cafe->rs->index_of[tmp & 0xfff];
+-			syn[i+1] = cafe->rs->index_of[(tmp >> 16) & 0xfff];
+-		}
+-
+-		n = decode_rs16(cafe->rs, NULL, NULL, 1367, syn, 0, pos, 0,
+-		                pat);
+-
+-		for (i = 0; i < n; i++) {
+-			int p = pos[i];
+-
+-			/* The 12-bit symbols are mapped to bytes here */
+-
+-			if (p > 1374) {
+-				/* out of range */
+-				n = -1374;
+-			} else if (p == 0) {
+-				/* high four bits do not correspond to data */
+-				if (pat[i] > 0xff)
+-					n = -2048;
+-				else
+-					buf[0] ^= pat[i];
+-			} else if (p == 1365) {
+-				buf[2047] ^= pat[i] >> 4;
+-				oob[0] ^= pat[i] << 4;
+-			} else if (p > 1365) {
+-				if ((p & 1) == 1) {
+-					oob[3*p/2 - 2048] ^= pat[i] >> 4;
+-					oob[3*p/2 - 2047] ^= pat[i] << 4;
+-				} else {
+-					oob[3*p/2 - 2049] ^= pat[i] >> 8;
+-					oob[3*p/2 - 2048] ^= pat[i];
+-				}
+-			} else if ((p & 1) == 1) {
+-				buf[3*p/2] ^= pat[i] >> 4;
+-				buf[3*p/2 + 1] ^= pat[i] << 4;
+-			} else {
+-				buf[3*p/2 - 1] ^= pat[i] >> 8;
+-				buf[3*p/2] ^= pat[i];
+-			}
+-		}
+-
+-		if (n < 0) {
+-			dev_dbg(&cafe->pdev->dev, "Failed to correct ECC at %08x\n",
+-				cafe_readl(cafe, NAND_ADDR2) * 2048);
+-			for (i = 0; i < 0x5c; i += 4)
+-				printk("Register %x: %08x\n", i, readl(cafe->mmio + i));
+-			mtd->ecc_stats.failed++;
+-		} else {
+-			dev_dbg(&cafe->pdev->dev, "Corrected %d symbol errors\n", n);
+-			mtd->ecc_stats.corrected += n;
+-			max_bitflips = max_t(unsigned int, max_bitflips, n);
+-		}
+-	}
+-
+-	return max_bitflips;
+-}
+-
+-static int cafe_ooblayout_ecc(struct mtd_info *mtd, int section,
+-			      struct mtd_oob_region *oobregion)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-
+-	if (section)
+-		return -ERANGE;
+-
+-	oobregion->offset = 0;
+-	oobregion->length = chip->ecc.total;
+-
+-	return 0;
+-}
+-
+-static int cafe_ooblayout_free(struct mtd_info *mtd, int section,
+-			       struct mtd_oob_region *oobregion)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-
+-	if (section)
+-		return -ERANGE;
+-
+-	oobregion->offset = chip->ecc.total;
+-	oobregion->length = mtd->oobsize - chip->ecc.total;
+-
+-	return 0;
+-}
+-
+-static const struct mtd_ooblayout_ops cafe_ooblayout_ops = {
+-	.ecc = cafe_ooblayout_ecc,
+-	.free = cafe_ooblayout_free,
+-};
+-
+-/* Ick. The BBT code really ought to be able to work this bit out
+-   for itself from the above, at least for the 2KiB case */
+-static uint8_t cafe_bbt_pattern_2048[] = { 'B', 'b', 't', '0' };
+-static uint8_t cafe_mirror_pattern_2048[] = { '1', 't', 'b', 'B' };
+-
+-static uint8_t cafe_bbt_pattern_512[] = { 0xBB };
+-static uint8_t cafe_mirror_pattern_512[] = { 0xBC };
+-
+-
+-static struct nand_bbt_descr cafe_bbt_main_descr_2048 = {
+-	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
+-		| NAND_BBT_2BIT | NAND_BBT_VERSION,
+-	.offs =	14,
+-	.len = 4,
+-	.veroffs = 18,
+-	.maxblocks = 4,
+-	.pattern = cafe_bbt_pattern_2048
+-};
+-
+-static struct nand_bbt_descr cafe_bbt_mirror_descr_2048 = {
+-	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
+-		| NAND_BBT_2BIT | NAND_BBT_VERSION,
+-	.offs =	14,
+-	.len = 4,
+-	.veroffs = 18,
+-	.maxblocks = 4,
+-	.pattern = cafe_mirror_pattern_2048
+-};
+-
+-static struct nand_bbt_descr cafe_bbt_main_descr_512 = {
+-	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
+-		| NAND_BBT_2BIT | NAND_BBT_VERSION,
+-	.offs =	14,
+-	.len = 1,
+-	.veroffs = 15,
+-	.maxblocks = 4,
+-	.pattern = cafe_bbt_pattern_512
+-};
+-
+-static struct nand_bbt_descr cafe_bbt_mirror_descr_512 = {
+-	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
+-		| NAND_BBT_2BIT | NAND_BBT_VERSION,
+-	.offs =	14,
+-	.len = 1,
+-	.veroffs = 15,
+-	.maxblocks = 4,
+-	.pattern = cafe_mirror_pattern_512
+-};
+-
+-
+-static int cafe_nand_write_page_lowlevel(struct mtd_info *mtd,
+-					  struct nand_chip *chip,
+-					  const uint8_t *buf, int oob_required,
+-					  int page)
+-{
+-	struct cafe_priv *cafe = nand_get_controller_data(chip);
+-
+-	chip->write_buf(mtd, buf, mtd->writesize);
+-	chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+-
+-	/* Set up ECC autogeneration */
+-	cafe->ctl2 |= (1<<30);
+-
+-	return 0;
+-}
+-
+-static int cafe_nand_block_bad(struct mtd_info *mtd, loff_t ofs)
+-{
+-	return 0;
+-}
+-
+-/* F_2[X]/(X**6+X+1)  */
+-static unsigned short gf64_mul(u8 a, u8 b)
+-{
+-	u8 c;
+-	unsigned int i;
+-
+-	c = 0;
+-	for (i = 0; i < 6; i++) {
+-		if (a & 1)
+-			c ^= b;
+-		a >>= 1;
+-		b <<= 1;
+-		if ((b & 0x40) != 0)
+-			b ^= 0x43;
+-	}
+-
+-	return c;
+-}
+-
+-/* F_64[X]/(X**2+X+A**-1) with A the generator of F_64[X]  */
+-static u16 gf4096_mul(u16 a, u16 b)
+-{
+-	u8 ah, al, bh, bl, ch, cl;
+-
+-	ah = a >> 6;
+-	al = a & 0x3f;
+-	bh = b >> 6;
+-	bl = b & 0x3f;
+-
+-	ch = gf64_mul(ah ^ al, bh ^ bl) ^ gf64_mul(al, bl);
+-	cl = gf64_mul(gf64_mul(ah, bh), 0x21) ^ gf64_mul(al, bl);
+-
+-	return (ch << 6) ^ cl;
+-}
+-
+-static int cafe_mul(int x)
+-{
+-	if (x == 0)
+-		return 1;
+-	return gf4096_mul(x, 0xe01);
+-}
+-
+-static int cafe_nand_probe(struct pci_dev *pdev,
+-				     const struct pci_device_id *ent)
+-{
+-	struct mtd_info *mtd;
+-	struct cafe_priv *cafe;
+-	uint32_t ctrl;
+-	int err = 0;
+-	int old_dma;
+-	struct nand_buffers *nbuf;
+-
+-	/* Very old versions shared the same PCI ident for all three
+-	   functions on the chip. Verify the class too... */
+-	if ((pdev->class >> 8) != PCI_CLASS_MEMORY_FLASH)
+-		return -ENODEV;
+-
+-	err = pci_enable_device(pdev);
+-	if (err)
+-		return err;
+-
+-	pci_set_master(pdev);
+-
+-	cafe = kzalloc(sizeof(*cafe), GFP_KERNEL);
+-	if (!cafe)
+-		return  -ENOMEM;
+-
+-	mtd = nand_to_mtd(&cafe->nand);
+-	mtd->dev.parent = &pdev->dev;
+-	nand_set_controller_data(&cafe->nand, cafe);
+-
+-	cafe->pdev = pdev;
+-	cafe->mmio = pci_iomap(pdev, 0, 0);
+-	if (!cafe->mmio) {
+-		dev_warn(&pdev->dev, "failed to iomap\n");
+-		err = -ENOMEM;
+-		goto out_free_mtd;
+-	}
+-
+-	cafe->rs = init_rs_non_canonical(12, &cafe_mul, 0, 1, 8);
+-	if (!cafe->rs) {
+-		err = -ENOMEM;
+-		goto out_ior;
+-	}
+-
+-	cafe->nand.cmdfunc = cafe_nand_cmdfunc;
+-	cafe->nand.dev_ready = cafe_device_ready;
+-	cafe->nand.read_byte = cafe_read_byte;
+-	cafe->nand.read_buf = cafe_read_buf;
+-	cafe->nand.write_buf = cafe_write_buf;
+-	cafe->nand.select_chip = cafe_select_chip;
+-	cafe->nand.onfi_set_features = nand_onfi_get_set_features_notsupp;
+-	cafe->nand.onfi_get_features = nand_onfi_get_set_features_notsupp;
+-
+-	cafe->nand.chip_delay = 0;
+-
+-	/* Enable the following for a flash based bad block table */
+-	cafe->nand.bbt_options = NAND_BBT_USE_FLASH;
+-	cafe->nand.options = NAND_OWN_BUFFERS;
+-
+-	if (skipbbt) {
+-		cafe->nand.options |= NAND_SKIP_BBTSCAN;
+-		cafe->nand.block_bad = cafe_nand_block_bad;
+-	}
+-
+-	if (numtimings && numtimings != 3) {
+-		dev_warn(&cafe->pdev->dev, "%d timing register values ignored; precisely three are required\n", numtimings);
+-	}
+-
+-	if (numtimings == 3) {
+-		cafe_dev_dbg(&cafe->pdev->dev, "Using provided timings (%08x %08x %08x)\n",
+-			     timing[0], timing[1], timing[2]);
+-	} else {
+-		timing[0] = cafe_readl(cafe, NAND_TIMING1);
+-		timing[1] = cafe_readl(cafe, NAND_TIMING2);
+-		timing[2] = cafe_readl(cafe, NAND_TIMING3);
+-
+-		if (timing[0] | timing[1] | timing[2]) {
+-			cafe_dev_dbg(&cafe->pdev->dev, "Timing registers already set (%08x %08x %08x)\n",
+-				     timing[0], timing[1], timing[2]);
+-		} else {
+-			dev_warn(&cafe->pdev->dev, "Timing registers unset; using most conservative defaults\n");
+-			timing[0] = timing[1] = timing[2] = 0xffffffff;
+-		}
+-	}
+-
+-	/* Start off by resetting the NAND controller completely */
+-	cafe_writel(cafe, 1, NAND_RESET);
+-	cafe_writel(cafe, 0, NAND_RESET);
+-
+-	cafe_writel(cafe, timing[0], NAND_TIMING1);
+-	cafe_writel(cafe, timing[1], NAND_TIMING2);
+-	cafe_writel(cafe, timing[2], NAND_TIMING3);
+-
+-	cafe_writel(cafe, 0xffffffff, NAND_IRQ_MASK);
+-	err = request_irq(pdev->irq, &cafe_nand_interrupt, IRQF_SHARED,
+-			  "CAFE NAND", mtd);
+-	if (err) {
+-		dev_warn(&pdev->dev, "Could not register IRQ %d\n", pdev->irq);
+-		goto out_ior;
+-	}
+-
+-	/* Disable master reset, enable NAND clock */
+-	ctrl = cafe_readl(cafe, GLOBAL_CTRL);
+-	ctrl &= 0xffffeff0;
+-	ctrl |= 0x00007000;
+-	cafe_writel(cafe, ctrl | 0x05, GLOBAL_CTRL);
+-	cafe_writel(cafe, ctrl | 0x0a, GLOBAL_CTRL);
+-	cafe_writel(cafe, 0, NAND_DMA_CTRL);
+-
+-	cafe_writel(cafe, 0x7006, GLOBAL_CTRL);
+-	cafe_writel(cafe, 0x700a, GLOBAL_CTRL);
+-
+-	/* Enable NAND IRQ in global IRQ mask register */
+-	cafe_writel(cafe, 0x80000007, GLOBAL_IRQ_MASK);
+-	cafe_dev_dbg(&cafe->pdev->dev, "Control %x, IRQ mask %x\n",
+-		cafe_readl(cafe, GLOBAL_CTRL),
+-		cafe_readl(cafe, GLOBAL_IRQ_MASK));
+-
+-	/* Do not use the DMA for the nand_scan_ident() */
+-	old_dma = usedma;
+-	usedma = 0;
+-
+-	/* Scan to find existence of the device */
+-	err = nand_scan_ident(mtd, 2, NULL);
+-	if (err)
+-		goto out_irq;
+-
+-	cafe->dmabuf = dma_alloc_coherent(&cafe->pdev->dev,
+-				2112 + sizeof(struct nand_buffers) +
+-				mtd->writesize + mtd->oobsize,
+-				&cafe->dmaaddr, GFP_KERNEL);
+-	if (!cafe->dmabuf) {
+-		err = -ENOMEM;
+-		goto out_irq;
+-	}
+-	cafe->nand.buffers = nbuf = (void *)cafe->dmabuf + 2112;
+-
+-	/* Set up DMA address */
+-	cafe_writel(cafe, cafe->dmaaddr & 0xffffffff, NAND_DMA_ADDR0);
+-	if (sizeof(cafe->dmaaddr) > 4)
+-		/* Shift in two parts to shut the compiler up */
+-		cafe_writel(cafe, (cafe->dmaaddr >> 16) >> 16, NAND_DMA_ADDR1);
+-	else
+-		cafe_writel(cafe, 0, NAND_DMA_ADDR1);
+-
+-	cafe_dev_dbg(&cafe->pdev->dev, "Set DMA address to %x (virt %p)\n",
+-		cafe_readl(cafe, NAND_DMA_ADDR0), cafe->dmabuf);
+-
+-	/* this driver does not need the @ecccalc and @ecccode */
+-	nbuf->ecccalc = NULL;
+-	nbuf->ecccode = NULL;
+-	nbuf->databuf = (uint8_t *)(nbuf + 1);
+-
+-	/* Restore the DMA flag */
+-	usedma = old_dma;
+-
+-	cafe->ctl2 = 1<<27; /* Reed-Solomon ECC */
+-	if (mtd->writesize == 2048)
+-		cafe->ctl2 |= 1<<29; /* 2KiB page size */
+-
+-	/* Set up ECC according to the type of chip we found */
+-	mtd_set_ooblayout(mtd, &cafe_ooblayout_ops);
+-	if (mtd->writesize == 2048) {
+-		cafe->nand.bbt_td = &cafe_bbt_main_descr_2048;
+-		cafe->nand.bbt_md = &cafe_bbt_mirror_descr_2048;
+-	} else if (mtd->writesize == 512) {
+-		cafe->nand.bbt_td = &cafe_bbt_main_descr_512;
+-		cafe->nand.bbt_md = &cafe_bbt_mirror_descr_512;
+-	} else {
+-		printk(KERN_WARNING "Unexpected NAND flash writesize %d. Aborting\n",
+-		       mtd->writesize);
+-		goto out_free_dma;
+-	}
+-	cafe->nand.ecc.mode = NAND_ECC_HW_SYNDROME;
+-	cafe->nand.ecc.size = mtd->writesize;
+-	cafe->nand.ecc.bytes = 14;
+-	cafe->nand.ecc.strength = 4;
+-	cafe->nand.ecc.hwctl  = (void *)cafe_nand_bug;
+-	cafe->nand.ecc.calculate = (void *)cafe_nand_bug;
+-	cafe->nand.ecc.correct  = (void *)cafe_nand_bug;
+-	cafe->nand.ecc.write_page = cafe_nand_write_page_lowlevel;
+-	cafe->nand.ecc.write_oob = cafe_nand_write_oob;
+-	cafe->nand.ecc.read_page = cafe_nand_read_page;
+-	cafe->nand.ecc.read_oob = cafe_nand_read_oob;
+-
+-	err = nand_scan_tail(mtd);
+-	if (err)
+-		goto out_free_dma;
+-
+-	pci_set_drvdata(pdev, mtd);
+-
+-	mtd->name = "cafe_nand";
+-	mtd_device_parse_register(mtd, part_probes, NULL, NULL, 0);
+-
+-	goto out;
+-
+- out_free_dma:
+-	dma_free_coherent(&cafe->pdev->dev,
+-			2112 + sizeof(struct nand_buffers) +
+-			mtd->writesize + mtd->oobsize,
+-			cafe->dmabuf, cafe->dmaaddr);
+- out_irq:
+-	/* Disable NAND IRQ in global IRQ mask register */
+-	cafe_writel(cafe, ~1 & cafe_readl(cafe, GLOBAL_IRQ_MASK), GLOBAL_IRQ_MASK);
+-	free_irq(pdev->irq, mtd);
+- out_ior:
+-	pci_iounmap(pdev, cafe->mmio);
+- out_free_mtd:
+-	kfree(cafe);
+- out:
+-	return err;
+-}
+-
+-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 cafe_priv *cafe = nand_get_controller_data(chip);
+-
+-	/* Disable NAND IRQ in global IRQ mask register */
+-	cafe_writel(cafe, ~1 & cafe_readl(cafe, GLOBAL_IRQ_MASK), GLOBAL_IRQ_MASK);
+-	free_irq(pdev->irq, mtd);
+-	nand_release(mtd);
+-	free_rs(cafe->rs);
+-	pci_iounmap(pdev, cafe->mmio);
+-	dma_free_coherent(&cafe->pdev->dev,
+-			2112 + sizeof(struct nand_buffers) +
+-			mtd->writesize + mtd->oobsize,
+-			cafe->dmabuf, cafe->dmaaddr);
+-	kfree(cafe);
+-}
+-
+-static const struct pci_device_id cafe_nand_tbl[] = {
+-	{ PCI_VENDOR_ID_MARVELL, PCI_DEVICE_ID_MARVELL_88ALP01_NAND,
+-	  PCI_ANY_ID, PCI_ANY_ID },
+-	{ }
+-};
+-
+-MODULE_DEVICE_TABLE(pci, cafe_nand_tbl);
+-
+-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 cafe_priv *cafe = nand_get_controller_data(chip);
+-
+-       /* Start off by resetting the NAND controller completely */
+-	cafe_writel(cafe, 1, NAND_RESET);
+-	cafe_writel(cafe, 0, NAND_RESET);
+-	cafe_writel(cafe, 0xffffffff, NAND_IRQ_MASK);
+-
+-	/* Restore timing configuration */
+-	cafe_writel(cafe, timing[0], NAND_TIMING1);
+-	cafe_writel(cafe, timing[1], NAND_TIMING2);
+-	cafe_writel(cafe, timing[2], NAND_TIMING3);
+-
+-        /* Disable master reset, enable NAND clock */
+-	ctrl = cafe_readl(cafe, GLOBAL_CTRL);
+-	ctrl &= 0xffffeff0;
+-	ctrl |= 0x00007000;
+-	cafe_writel(cafe, ctrl | 0x05, GLOBAL_CTRL);
+-	cafe_writel(cafe, ctrl | 0x0a, GLOBAL_CTRL);
+-	cafe_writel(cafe, 0, NAND_DMA_CTRL);
+-	cafe_writel(cafe, 0x7006, GLOBAL_CTRL);
+-	cafe_writel(cafe, 0x700a, GLOBAL_CTRL);
+-
+-	/* Set up DMA address */
+-	cafe_writel(cafe, cafe->dmaaddr & 0xffffffff, NAND_DMA_ADDR0);
+-	if (sizeof(cafe->dmaaddr) > 4)
+-	/* Shift in two parts to shut the compiler up */
+-		cafe_writel(cafe, (cafe->dmaaddr >> 16) >> 16, NAND_DMA_ADDR1);
+-	else
+-		cafe_writel(cafe, 0, NAND_DMA_ADDR1);
+-
+-	/* Enable NAND IRQ in global IRQ mask register */
+-	cafe_writel(cafe, 0x80000007, GLOBAL_IRQ_MASK);
+-	return 0;
+-}
+-
+-static struct pci_driver cafe_nand_pci_driver = {
+-	.name = "CAFÉ NAND",
+-	.id_table = cafe_nand_tbl,
+-	.probe = cafe_nand_probe,
+-	.remove = cafe_nand_remove,
+-	.resume = cafe_nand_resume,
+-};
+-
+-module_pci_driver(cafe_nand_pci_driver);
+-
+-MODULE_LICENSE("GPL");
+-MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
+-MODULE_DESCRIPTION("NAND flash driver for OLPC CAFÉ chip");
+diff --git a/drivers/mtd/nand/cmx270_nand.c b/drivers/mtd/nand/cmx270_nand.c
+deleted file mode 100644
+index 1fc435f..0000000
+--- a/drivers/mtd/nand/cmx270_nand.c
++++ /dev/null
+@@ -1,246 +0,0 @@
+-/*
+- *  linux/drivers/mtd/nand/cmx270-nand.c
+- *
+- *  Copyright (C) 2006 Compulab, Ltd.
+- *  Mike Rapoport <mike@compulab.co.il>
+- *
+- *  Derived from drivers/mtd/nand/h1910.c
+- *       Copyright (C) 2002 Marius Gröger (mag@sysgo.de)
+- *       Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de)
+- *
+- *
+- * 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.
+- *
+- *  Overview:
+- *   This is a device driver for the NAND flash device found on the
+- *   CM-X270 board.
+- */
+-
+-#include <linux/mtd/rawnand.h>
+-#include <linux/mtd/partitions.h>
+-#include <linux/slab.h>
+-#include <linux/gpio.h>
+-#include <linux/module.h>
+-
+-#include <asm/io.h>
+-#include <asm/irq.h>
+-#include <asm/mach-types.h>
+-
+-#include <mach/pxa2xx-regs.h>
+-
+-#define GPIO_NAND_CS	(11)
+-#define GPIO_NAND_RB	(89)
+-
+-/* MTD structure for CM-X270 board */
+-static struct mtd_info *cmx270_nand_mtd;
+-
+-/* remaped IO address of the device */
+-static void __iomem *cmx270_nand_io;
+-
+-/*
+- * Define static partitions for flash device
+- */
+-static struct mtd_partition partition_info[] = {
+-	[0] = {
+-		.name	= "cmx270-0",
+-		.offset	= 0,
+-		.size	= MTDPART_SIZ_FULL
+-	}
+-};
+-#define NUM_PARTITIONS (ARRAY_SIZE(partition_info))
+-
+-static u_char cmx270_read_byte(struct mtd_info *mtd)
+-{
+-	struct nand_chip *this = mtd_to_nand(mtd);
+-
+-	return (readl(this->IO_ADDR_R) >> 16);
+-}
+-
+-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);
+-
+-	for (i=0; i<len; i++)
+-		writel((*buf++ << 16), this->IO_ADDR_W);
+-}
+-
+-static void cmx270_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+-{
+-	int i;
+-	struct nand_chip *this = mtd_to_nand(mtd);
+-
+-	for (i=0; i<len; i++)
+-		*buf++ = readl(this->IO_ADDR_R) >> 16;
+-}
+-
+-static inline void nand_cs_on(void)
+-{
+-	gpio_set_value(GPIO_NAND_CS, 0);
+-}
+-
+-static void nand_cs_off(void)
+-{
+-	dsb();
+-
+-	gpio_set_value(GPIO_NAND_CS, 1);
+-}
+-
+-/*
+- *	hardware specific access to control-lines
+- */
+-static void cmx270_hwcontrol(struct mtd_info *mtd, int dat,
+-			     unsigned int ctrl)
+-{
+-	struct nand_chip *this = mtd_to_nand(mtd);
+-	unsigned int nandaddr = (unsigned int)this->IO_ADDR_W;
+-
+-	dsb();
+-
+-	if (ctrl & NAND_CTRL_CHANGE) {
+-		if ( ctrl & NAND_ALE )
+-			nandaddr |=  (1 << 3);
+-		else
+-			nandaddr &= ~(1 << 3);
+-		if ( ctrl & NAND_CLE )
+-			nandaddr |=  (1 << 2);
+-		else
+-			nandaddr &= ~(1 << 2);
+-		if ( ctrl & NAND_NCE )
+-			nand_cs_on();
+-		else
+-			nand_cs_off();
+-	}
+-
+-	dsb();
+-	this->IO_ADDR_W = (void __iomem*)nandaddr;
+-	if (dat != NAND_CMD_NONE)
+-		writel((dat << 16), this->IO_ADDR_W);
+-
+-	dsb();
+-}
+-
+-/*
+- *	read device ready pin
+- */
+-static int cmx270_device_ready(struct mtd_info *mtd)
+-{
+-	dsb();
+-
+-	return (gpio_get_value(GPIO_NAND_RB));
+-}
+-
+-/*
+- * Main initialization routine
+- */
+-static int __init cmx270_init(void)
+-{
+-	struct nand_chip *this;
+-	int ret;
+-
+-	if (!(machine_is_armcore() && cpu_is_pxa27x()))
+-		return -ENODEV;
+-
+-	ret = gpio_request(GPIO_NAND_CS, "NAND CS");
+-	if (ret) {
+-		pr_warn("CM-X270: failed to request NAND CS gpio\n");
+-		return ret;
+-	}
+-
+-	gpio_direction_output(GPIO_NAND_CS, 1);
+-
+-	ret = gpio_request(GPIO_NAND_RB, "NAND R/B");
+-	if (ret) {
+-		pr_warn("CM-X270: failed to request NAND R/B gpio\n");
+-		goto err_gpio_request;
+-	}
+-
+-	gpio_direction_input(GPIO_NAND_RB);
+-
+-	/* Allocate memory for MTD device structure and private data */
+-	this = kzalloc(sizeof(struct nand_chip), GFP_KERNEL);
+-	if (!this) {
+-		ret = -ENOMEM;
+-		goto err_kzalloc;
+-	}
+-
+-	cmx270_nand_io = ioremap(PXA_CS1_PHYS, 12);
+-	if (!cmx270_nand_io) {
+-		pr_debug("Unable to ioremap NAND device\n");
+-		ret = -EINVAL;
+-		goto err_ioremap;
+-	}
+-
+-	cmx270_nand_mtd = nand_to_mtd(this);
+-
+-	/* Link the private data with the MTD structure */
+-	cmx270_nand_mtd->owner = THIS_MODULE;
+-
+-	/* insert callbacks */
+-	this->IO_ADDR_R = cmx270_nand_io;
+-	this->IO_ADDR_W = cmx270_nand_io;
+-	this->cmd_ctrl = cmx270_hwcontrol;
+-	this->dev_ready = cmx270_device_ready;
+-
+-	/* 15 us command delay time */
+-	this->chip_delay = 20;
+-	this->ecc.mode = NAND_ECC_SOFT;
+-	this->ecc.algo = NAND_ECC_HAMMING;
+-
+-	/* read/write functions */
+-	this->read_byte = cmx270_read_byte;
+-	this->read_buf = cmx270_read_buf;
+-	this->write_buf = cmx270_write_buf;
+-
+-	/* Scan to find existence of the device */
+-	ret = nand_scan(cmx270_nand_mtd, 1);
+-	if (ret) {
+-		pr_notice("No NAND device\n");
+-		goto err_scan;
+-	}
+-
+-	/* Register the partitions */
+-	ret = mtd_device_parse_register(cmx270_nand_mtd, NULL, NULL,
+-					partition_info, NUM_PARTITIONS);
+-	if (ret)
+-		goto err_scan;
+-
+-	/* Return happy */
+-	return 0;
+-
+-err_scan:
+-	iounmap(cmx270_nand_io);
+-err_ioremap:
+-	kfree(this);
+-err_kzalloc:
+-	gpio_free(GPIO_NAND_RB);
+-err_gpio_request:
+-	gpio_free(GPIO_NAND_CS);
+-
+-	return ret;
+-
+-}
+-module_init(cmx270_init);
+-
+-/*
+- * Clean up routine
+- */
+-static void __exit cmx270_cleanup(void)
+-{
+-	/* Release resources, unregister device */
+-	nand_release(cmx270_nand_mtd);
+-
+-	gpio_free(GPIO_NAND_RB);
+-	gpio_free(GPIO_NAND_CS);
+-
+-	iounmap(cmx270_nand_io);
+-
+-	kfree(mtd_to_nand(cmx270_nand_mtd));
+-}
+-module_exit(cmx270_cleanup);
+-
+-MODULE_LICENSE("GPL");
+-MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>");
+-MODULE_DESCRIPTION("NAND flash driver for Compulab CM-X270 Module");
+diff --git a/drivers/mtd/nand/cs553x_nand.c b/drivers/mtd/nand/cs553x_nand.c
+deleted file mode 100644
+index d488775..0000000
+--- a/drivers/mtd/nand/cs553x_nand.c
++++ /dev/null
+@@ -1,357 +0,0 @@
+-/*
+- * drivers/mtd/nand/cs553x_nand.c
+- *
+- * (C) 2005, 2006 Red Hat Inc.
+- *
+- * Author: David Woodhouse <dwmw2@infradead.org>
+- *	   Tom Sylla <tom.sylla@amd.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.
+- *
+- *  Overview:
+- *   This is a device driver for the NAND flash controller found on
+- *   the AMD CS5535/CS5536 companion chipsets for the Geode processor.
+- *   mtd-id for command line partitioning is cs553x_nand_cs[0-3]
+- *   where 0-3 reflects the chip select for NAND.
+- *
+- */
+-
+-#include <linux/kernel.h>
+-#include <linux/slab.h>
+-#include <linux/init.h>
+-#include <linux/module.h>
+-#include <linux/delay.h>
+-#include <linux/mtd/mtd.h>
+-#include <linux/mtd/rawnand.h>
+-#include <linux/mtd/nand_ecc.h>
+-#include <linux/mtd/partitions.h>
+-
+-#include <asm/msr.h>
+-#include <asm/io.h>
+-
+-#define NR_CS553X_CONTROLLERS	4
+-
+-#define MSR_DIVIL_GLD_CAP	0x51400000	/* DIVIL capabilitiies */
+-#define CAP_CS5535		0x2df000ULL
+-#define CAP_CS5536		0x5df500ULL
+-
+-/* NAND Timing MSRs */
+-#define MSR_NANDF_DATA		0x5140001b	/* NAND Flash Data Timing MSR */
+-#define MSR_NANDF_CTL		0x5140001c	/* NAND Flash Control Timing */
+-#define MSR_NANDF_RSVD		0x5140001d	/* Reserved */
+-
+-/* NAND BAR MSRs */
+-#define MSR_DIVIL_LBAR_FLSH0	0x51400010	/* Flash Chip Select 0 */
+-#define MSR_DIVIL_LBAR_FLSH1	0x51400011	/* Flash Chip Select 1 */
+-#define MSR_DIVIL_LBAR_FLSH2	0x51400012	/* Flash Chip Select 2 */
+-#define MSR_DIVIL_LBAR_FLSH3	0x51400013	/* Flash Chip Select 3 */
+-	/* Each made up of... */
+-#define FLSH_LBAR_EN		(1ULL<<32)
+-#define FLSH_NOR_NAND		(1ULL<<33)	/* 1 for NAND */
+-#define FLSH_MEM_IO		(1ULL<<34)	/* 1 for MMIO */
+-	/* I/O BARs have BASE_ADDR in bits 15:4, IO_MASK in 47:36 */
+-	/* MMIO BARs have BASE_ADDR in bits 31:12, MEM_MASK in 63:44 */
+-
+-/* Pin function selection MSR (IDE vs. flash on the IDE pins) */
+-#define MSR_DIVIL_BALL_OPTS	0x51400015
+-#define PIN_OPT_IDE		(1<<0)	/* 0 for flash, 1 for IDE */
+-
+-/* Registers within the NAND flash controller BAR -- memory mapped */
+-#define MM_NAND_DATA		0x00	/* 0 to 0x7ff, in fact */
+-#define MM_NAND_CTL		0x800	/* Any even address 0x800-0x80e */
+-#define MM_NAND_IO		0x801	/* Any odd address 0x801-0x80f */
+-#define MM_NAND_STS		0x810
+-#define MM_NAND_ECC_LSB		0x811
+-#define MM_NAND_ECC_MSB		0x812
+-#define MM_NAND_ECC_COL		0x813
+-#define MM_NAND_LAC		0x814
+-#define MM_NAND_ECC_CTL		0x815
+-
+-/* Registers within the NAND flash controller BAR -- I/O mapped */
+-#define IO_NAND_DATA		0x00	/* 0 to 3, in fact */
+-#define IO_NAND_CTL		0x04
+-#define IO_NAND_IO		0x05
+-#define IO_NAND_STS		0x06
+-#define IO_NAND_ECC_CTL		0x08
+-#define IO_NAND_ECC_LSB		0x09
+-#define IO_NAND_ECC_MSB		0x0a
+-#define IO_NAND_ECC_COL		0x0b
+-#define IO_NAND_LAC		0x0c
+-
+-#define CS_NAND_CTL_DIST_EN	(1<<4)	/* Enable NAND Distract interrupt */
+-#define CS_NAND_CTL_RDY_INT_MASK	(1<<3)	/* Enable RDY/BUSY# interrupt */
+-#define CS_NAND_CTL_ALE		(1<<2)
+-#define CS_NAND_CTL_CLE		(1<<1)
+-#define CS_NAND_CTL_CE		(1<<0)	/* Keep low; 1 to reset */
+-
+-#define CS_NAND_STS_FLASH_RDY	(1<<3)
+-#define CS_NAND_CTLR_BUSY	(1<<2)
+-#define CS_NAND_CMD_COMP	(1<<1)
+-#define CS_NAND_DIST_ST		(1<<0)
+-
+-#define CS_NAND_ECC_PARITY	(1<<2)
+-#define CS_NAND_ECC_CLRECC	(1<<1)
+-#define CS_NAND_ECC_ENECC	(1<<0)
+-
+-static void cs553x_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+-{
+-	struct nand_chip *this = mtd_to_nand(mtd);
+-
+-	while (unlikely(len > 0x800)) {
+-		memcpy_fromio(buf, this->IO_ADDR_R, 0x800);
+-		buf += 0x800;
+-		len -= 0x800;
+-	}
+-	memcpy_fromio(buf, this->IO_ADDR_R, len);
+-}
+-
+-static void cs553x_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
+-{
+-	struct nand_chip *this = mtd_to_nand(mtd);
+-
+-	while (unlikely(len > 0x800)) {
+-		memcpy_toio(this->IO_ADDR_R, buf, 0x800);
+-		buf += 0x800;
+-		len -= 0x800;
+-	}
+-	memcpy_toio(this->IO_ADDR_R, buf, len);
+-}
+-
+-static unsigned char cs553x_read_byte(struct mtd_info *mtd)
+-{
+-	struct nand_chip *this = mtd_to_nand(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);
+-	int i = 100000;
+-
+-	while (i && readb(this->IO_ADDR_R + MM_NAND_STS) & CS_NAND_CTLR_BUSY) {
+-		udelay(1);
+-		i--;
+-	}
+-	writeb(byte, this->IO_ADDR_W + 0x801);
+-}
+-
+-static void cs553x_hwcontrol(struct mtd_info *mtd, int cmd,
+-			     unsigned int ctrl)
+-{
+-	struct nand_chip *this = mtd_to_nand(mtd);
+-	void __iomem *mmio_base = this->IO_ADDR_R;
+-	if (ctrl & NAND_CTRL_CHANGE) {
+-		unsigned char ctl = (ctrl & ~NAND_CTRL_CHANGE ) ^ 0x01;
+-		writeb(ctl, mmio_base + MM_NAND_CTL);
+-	}
+-	if (cmd != NAND_CMD_NONE)
+-		cs553x_write_byte(mtd, cmd);
+-}
+-
+-static int cs553x_device_ready(struct mtd_info *mtd)
+-{
+-	struct nand_chip *this = mtd_to_nand(mtd);
+-	void __iomem *mmio_base = this->IO_ADDR_R;
+-	unsigned char foo = readb(mmio_base + MM_NAND_STS);
+-
+-	return (foo & CS_NAND_STS_FLASH_RDY) && !(foo & CS_NAND_CTLR_BUSY);
+-}
+-
+-static void cs_enable_hwecc(struct mtd_info *mtd, int mode)
+-{
+-	struct nand_chip *this = mtd_to_nand(mtd);
+-	void __iomem *mmio_base = this->IO_ADDR_R;
+-
+-	writeb(0x07, mmio_base + MM_NAND_ECC_CTL);
+-}
+-
+-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);
+-	void __iomem *mmio_base = this->IO_ADDR_R;
+-
+-	ecc = readl(mmio_base + MM_NAND_STS);
+-
+-	ecc_code[1] = ecc >> 8;
+-	ecc_code[0] = ecc >> 16;
+-	ecc_code[2] = ecc >> 24;
+-	return 0;
+-}
+-
+-static struct mtd_info *cs553x_mtd[4];
+-
+-static int __init cs553x_init_one(int cs, int mmio, unsigned long adr)
+-{
+-	int err = 0;
+-	struct nand_chip *this;
+-	struct mtd_info *new_mtd;
+-
+-	printk(KERN_NOTICE "Probing CS553x NAND controller CS#%d at %sIO 0x%08lx\n", cs, mmio?"MM":"P", adr);
+-
+-	if (!mmio) {
+-		printk(KERN_NOTICE "PIO mode not yet implemented for CS553X NAND controller\n");
+-		return -ENXIO;
+-	}
+-
+-	/* Allocate memory for MTD device structure and private data */
+-	this = kzalloc(sizeof(struct nand_chip), GFP_KERNEL);
+-	if (!this) {
+-		err = -ENOMEM;
+-		goto out;
+-	}
+-
+-	new_mtd = nand_to_mtd(this);
+-
+-	/* Link the private data with the MTD structure */
+-	new_mtd->owner = THIS_MODULE;
+-
+-	/* map physical address */
+-	this->IO_ADDR_R = this->IO_ADDR_W = ioremap(adr, 4096);
+-	if (!this->IO_ADDR_R) {
+-		printk(KERN_WARNING "ioremap cs553x NAND @0x%08lx failed\n", adr);
+-		err = -EIO;
+-		goto out_mtd;
+-	}
+-
+-	this->cmd_ctrl = cs553x_hwcontrol;
+-	this->dev_ready = cs553x_device_ready;
+-	this->read_byte = cs553x_read_byte;
+-	this->read_buf = cs553x_read_buf;
+-	this->write_buf = cs553x_write_buf;
+-
+-	this->chip_delay = 0;
+-
+-	this->ecc.mode = NAND_ECC_HW;
+-	this->ecc.size = 256;
+-	this->ecc.bytes = 3;
+-	this->ecc.hwctl  = cs_enable_hwecc;
+-	this->ecc.calculate = cs_calculate_ecc;
+-	this->ecc.correct  = nand_correct_data;
+-	this->ecc.strength = 1;
+-
+-	/* Enable the following for a flash based bad block table */
+-	this->bbt_options = NAND_BBT_USE_FLASH;
+-
+-	new_mtd->name = kasprintf(GFP_KERNEL, "cs553x_nand_cs%d", cs);
+-	if (!new_mtd->name) {
+-		err = -ENOMEM;
+-		goto out_ior;
+-	}
+-
+-	/* Scan to find existence of the device */
+-	err = nand_scan(new_mtd, 1);
+-	if (err)
+-		goto out_free;
+-
+-	cs553x_mtd[cs] = new_mtd;
+-	goto out;
+-
+-out_free:
+-	kfree(new_mtd->name);
+-out_ior:
+-	iounmap(this->IO_ADDR_R);
+-out_mtd:
+-	kfree(this);
+-out:
+-	return err;
+-}
+-
+-static int is_geode(void)
+-{
+-	/* These are the CPUs which will have a CS553[56] companion chip */
+-	if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD &&
+-	    boot_cpu_data.x86 == 5 &&
+-	    boot_cpu_data.x86_model == 10)
+-		return 1; /* Geode LX */
+-
+-	if ((boot_cpu_data.x86_vendor == X86_VENDOR_NSC ||
+-	     boot_cpu_data.x86_vendor == X86_VENDOR_CYRIX) &&
+-	    boot_cpu_data.x86 == 5 &&
+-	    boot_cpu_data.x86_model == 5)
+-		return 1; /* Geode GX (née GX2) */
+-
+-	return 0;
+-}
+-
+-static int __init cs553x_init(void)
+-{
+-	int err = -ENXIO;
+-	int i;
+-	uint64_t val;
+-
+-	/* If the CPU isn't a Geode GX or LX, abort */
+-	if (!is_geode())
+-		return -ENXIO;
+-
+-	/* If it doesn't have the CS553[56], abort */
+-	rdmsrl(MSR_DIVIL_GLD_CAP, val);
+-	val &= ~0xFFULL;
+-	if (val != CAP_CS5535 && val != CAP_CS5536)
+-		return -ENXIO;
+-
+-	/* If it doesn't have the NAND controller enabled, abort */
+-	rdmsrl(MSR_DIVIL_BALL_OPTS, val);
+-	if (val & PIN_OPT_IDE) {
+-		printk(KERN_INFO "CS553x NAND controller: Flash I/O not enabled in MSR_DIVIL_BALL_OPTS.\n");
+-		return -ENXIO;
+-	}
+-
+-	for (i = 0; i < NR_CS553X_CONTROLLERS; i++) {
+-		rdmsrl(MSR_DIVIL_LBAR_FLSH0 + i, val);
+-
+-		if ((val & (FLSH_LBAR_EN|FLSH_NOR_NAND)) == (FLSH_LBAR_EN|FLSH_NOR_NAND))
+-			err = cs553x_init_one(i, !!(val & FLSH_MEM_IO), val & 0xFFFFFFFF);
+-	}
+-
+-	/* Register all devices together here. This means we can easily hack it to
+-	   do mtdconcat etc. if we want to. */
+-	for (i = 0; i < NR_CS553X_CONTROLLERS; i++) {
+-		if (cs553x_mtd[i]) {
+-			/* If any devices registered, return success. Else the last error. */
+-			mtd_device_parse_register(cs553x_mtd[i], NULL, NULL,
+-						  NULL, 0);
+-			err = 0;
+-		}
+-	}
+-
+-	return err;
+-}
+-
+-module_init(cs553x_init);
+-
+-static void __exit cs553x_cleanup(void)
+-{
+-	int i;
+-
+-	for (i = 0; i < NR_CS553X_CONTROLLERS; i++) {
+-		struct mtd_info *mtd = cs553x_mtd[i];
+-		struct nand_chip *this;
+-		void __iomem *mmio_base;
+-
+-		if (!mtd)
+-			continue;
+-
+-		this = mtd_to_nand(mtd);
+-		mmio_base = this->IO_ADDR_R;
+-
+-		/* Release resources, unregister device */
+-		nand_release(mtd);
+-		kfree(mtd->name);
+-		cs553x_mtd[i] = NULL;
+-
+-		/* unmap physical address */
+-		iounmap(mmio_base);
+-
+-		/* Free the MTD device structure */
+-		kfree(this);
+-	}
+-}
+-
+-module_exit(cs553x_cleanup);
+-
+-MODULE_LICENSE("GPL");
+-MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
+-MODULE_DESCRIPTION("NAND controller driver for AMD CS5535/CS5536 companion chip");
+diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c
+deleted file mode 100644
+index ccc8c43..0000000
+--- a/drivers/mtd/nand/davinci_nand.c
++++ /dev/null
+@@ -1,879 +0,0 @@
+-/*
+- * davinci_nand.c - NAND Flash Driver for DaVinci family chips
+- *
+- * Copyright © 2006 Texas Instruments.
+- *
+- * Port to 2.6.23 Copyright © 2008 by:
+- *   Sander Huijsen <Shuijsen@optelecom-nkf.com>
+- *   Troy Kisky <troy.kisky@boundarydevices.com>
+- *   Dirk Behme <Dirk.Behme@gmail.com>
+- *
+- * 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.
+- *
+- * You should have received a copy of the GNU General Public License
+- * along with this program; if not, write to the Free Software
+- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+- */
+-
+-#include <linux/kernel.h>
+-#include <linux/module.h>
+-#include <linux/platform_device.h>
+-#include <linux/err.h>
+-#include <linux/clk.h>
+-#include <linux/io.h>
+-#include <linux/mtd/rawnand.h>
+-#include <linux/mtd/partitions.h>
+-#include <linux/slab.h>
+-#include <linux/of_device.h>
+-#include <linux/of.h>
+-
+-#include <linux/platform_data/mtd-davinci.h>
+-#include <linux/platform_data/mtd-davinci-aemif.h>
+-
+-/*
+- * This is a device driver for the NAND flash controller found on the
+- * various DaVinci family chips.  It handles up to four SoC chipselects,
+- * and some flavors of secondary chipselect (e.g. based on A12) as used
+- * with multichip packages.
+- *
+- * The 1-bit ECC hardware is supported, as well as the newer 4-bit ECC
+- * available on chips like the DM355 and OMAP-L137 and needed with the
+- * more error-prone MLC NAND chips.
+- *
+- * This driver assumes EM_WAIT connects all the NAND devices' RDY/nBUSY
+- * outputs in a "wire-AND" configuration, with no per-chip signals.
+- */
+-struct davinci_nand_info {
+-	struct nand_chip	chip;
+-
+-	struct device		*dev;
+-	struct clk		*clk;
+-
+-	bool			is_readmode;
+-
+-	void __iomem		*base;
+-	void __iomem		*vaddr;
+-
+-	uint32_t		ioaddr;
+-	uint32_t		current_cs;
+-
+-	uint32_t		mask_chipsel;
+-	uint32_t		mask_ale;
+-	uint32_t		mask_cle;
+-
+-	uint32_t		core_chipsel;
+-
+-	struct davinci_aemif_timing	*timing;
+-};
+-
+-static DEFINE_SPINLOCK(davinci_nand_lock);
+-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);
+-}
+-
+-static inline unsigned int davinci_nand_readl(struct davinci_nand_info *info,
+-		int offset)
+-{
+-	return __raw_readl(info->base + offset);
+-}
+-
+-static inline void davinci_nand_writel(struct davinci_nand_info *info,
+-		int offset, unsigned long value)
+-{
+-	__raw_writel(value, info->base + offset);
+-}
+-
+-/*----------------------------------------------------------------------*/
+-
+-/*
+- * Access to hardware control lines:  ALE, CLE, secondary chipselect.
+- */
+-
+-static void nand_davinci_hwcontrol(struct mtd_info *mtd, int cmd,
+-				   unsigned int ctrl)
+-{
+-	struct davinci_nand_info	*info = to_davinci_nand(mtd);
+-	uint32_t			addr = info->current_cs;
+-	struct nand_chip		*nand = mtd_to_nand(mtd);
+-
+-	/* Did the control lines change? */
+-	if (ctrl & NAND_CTRL_CHANGE) {
+-		if ((ctrl & NAND_CTRL_CLE) == NAND_CTRL_CLE)
+-			addr |= info->mask_cle;
+-		else if ((ctrl & NAND_CTRL_ALE) == NAND_CTRL_ALE)
+-			addr |= info->mask_ale;
+-
+-		nand->IO_ADDR_W = (void __iomem __force *)addr;
+-	}
+-
+-	if (cmd != NAND_CMD_NONE)
+-		iowrite8(cmd, nand->IO_ADDR_W);
+-}
+-
+-static void nand_davinci_select_chip(struct mtd_info *mtd, int chip)
+-{
+-	struct davinci_nand_info	*info = to_davinci_nand(mtd);
+-	uint32_t			addr = info->ioaddr;
+-
+-	/* maybe kick in a second chipselect */
+-	if (chip > 0)
+-		addr |= info->mask_chipsel;
+-	info->current_cs = addr;
+-
+-	info->chip.IO_ADDR_W = (void __iomem __force *)addr;
+-	info->chip.IO_ADDR_R = info->chip.IO_ADDR_W;
+-}
+-
+-/*----------------------------------------------------------------------*/
+-
+-/*
+- * 1-bit hardware ECC ... context maintained for each core chipselect
+- */
+-
+-static inline uint32_t nand_davinci_readecc_1bit(struct mtd_info *mtd)
+-{
+-	struct davinci_nand_info *info = to_davinci_nand(mtd);
+-
+-	return davinci_nand_readl(info, NANDF1ECC_OFFSET
+-			+ 4 * info->core_chipsel);
+-}
+-
+-static void nand_davinci_hwctl_1bit(struct mtd_info *mtd, int mode)
+-{
+-	struct davinci_nand_info *info;
+-	uint32_t nandcfr;
+-	unsigned long flags;
+-
+-	info = to_davinci_nand(mtd);
+-
+-	/* Reset ECC hardware */
+-	nand_davinci_readecc_1bit(mtd);
+-
+-	spin_lock_irqsave(&davinci_nand_lock, flags);
+-
+-	/* Restart ECC hardware */
+-	nandcfr = davinci_nand_readl(info, NANDFCR_OFFSET);
+-	nandcfr |= BIT(8 + info->core_chipsel);
+-	davinci_nand_writel(info, NANDFCR_OFFSET, nandcfr);
+-
+-	spin_unlock_irqrestore(&davinci_nand_lock, flags);
+-}
+-
+-/*
+- * Read hardware ECC value and pack into three bytes
+- */
+-static int nand_davinci_calculate_1bit(struct mtd_info *mtd,
+-				      const u_char *dat, u_char *ecc_code)
+-{
+-	unsigned int ecc_val = nand_davinci_readecc_1bit(mtd);
+-	unsigned int ecc24 = (ecc_val & 0x0fff) | ((ecc_val & 0x0fff0000) >> 4);
+-
+-	/* invert so that erased block ecc is correct */
+-	ecc24 = ~ecc24;
+-	ecc_code[0] = (u_char)(ecc24);
+-	ecc_code[1] = (u_char)(ecc24 >> 8);
+-	ecc_code[2] = (u_char)(ecc24 >> 16);
+-
+-	return 0;
+-}
+-
+-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);
+-	uint32_t eccNand = read_ecc[0] | (read_ecc[1] << 8) |
+-					  (read_ecc[2] << 16);
+-	uint32_t eccCalc = calc_ecc[0] | (calc_ecc[1] << 8) |
+-					  (calc_ecc[2] << 16);
+-	uint32_t diff = eccCalc ^ eccNand;
+-
+-	if (diff) {
+-		if ((((diff >> 12) ^ diff) & 0xfff) == 0xfff) {
+-			/* Correctable error */
+-			if ((diff >> (12 + 3)) < chip->ecc.size) {
+-				dat[diff >> (12 + 3)] ^= BIT((diff >> 12) & 7);
+-				return 1;
+-			} else {
+-				return -EBADMSG;
+-			}
+-		} else if (!(diff & (diff - 1))) {
+-			/* Single bit ECC error in the ECC itself,
+-			 * nothing to fix */
+-			return 1;
+-		} else {
+-			/* Uncorrectable error */
+-			return -EBADMSG;
+-		}
+-
+-	}
+-	return 0;
+-}
+-
+-/*----------------------------------------------------------------------*/
+-
+-/*
+- * 4-bit hardware ECC ... context maintained over entire AEMIF
+- *
+- * This is a syndrome engine, but we avoid NAND_ECC_HW_SYNDROME
+- * since that forces use of a problematic "infix OOB" layout.
+- * Among other things, it trashes manufacturer bad block markers.
+- * Also, and specific to this hardware, it ECC-protects the "prepad"
+- * in the OOB ... while having ECC protection for parts of OOB would
+- * seem useful, the current MTD stack sometimes wants to update the
+- * OOB without recomputing ECC.
+- */
+-
+-static void nand_davinci_hwctl_4bit(struct mtd_info *mtd, int mode)
+-{
+-	struct davinci_nand_info *info = to_davinci_nand(mtd);
+-	unsigned long flags;
+-	u32 val;
+-
+-	/* Reset ECC hardware */
+-	davinci_nand_readl(info, NAND_4BIT_ECC1_OFFSET);
+-
+-	spin_lock_irqsave(&davinci_nand_lock, flags);
+-
+-	/* Start 4-bit ECC calculation for read/write */
+-	val = davinci_nand_readl(info, NANDFCR_OFFSET);
+-	val &= ~(0x03 << 4);
+-	val |= (info->core_chipsel << 4) | BIT(12);
+-	davinci_nand_writel(info, NANDFCR_OFFSET, val);
+-
+-	info->is_readmode = (mode == NAND_ECC_READ);
+-
+-	spin_unlock_irqrestore(&davinci_nand_lock, flags);
+-}
+-
+-/* Read raw ECC code after writing to NAND. */
+-static void
+-nand_davinci_readecc_4bit(struct davinci_nand_info *info, u32 code[4])
+-{
+-	const u32 mask = 0x03ff03ff;
+-
+-	code[0] = davinci_nand_readl(info, NAND_4BIT_ECC1_OFFSET) & mask;
+-	code[1] = davinci_nand_readl(info, NAND_4BIT_ECC2_OFFSET) & mask;
+-	code[2] = davinci_nand_readl(info, NAND_4BIT_ECC3_OFFSET) & mask;
+-	code[3] = davinci_nand_readl(info, NAND_4BIT_ECC4_OFFSET) & mask;
+-}
+-
+-/* Terminate read ECC; or return ECC (as bytes) of data written to NAND. */
+-static int nand_davinci_calculate_4bit(struct mtd_info *mtd,
+-		const u_char *dat, u_char *ecc_code)
+-{
+-	struct davinci_nand_info *info = to_davinci_nand(mtd);
+-	u32 raw_ecc[4], *p;
+-	unsigned i;
+-
+-	/* After a read, terminate ECC calculation by a dummy read
+-	 * of some 4-bit ECC register.  ECC covers everything that
+-	 * was read; correct() just uses the hardware state, so
+-	 * ecc_code is not needed.
+-	 */
+-	if (info->is_readmode) {
+-		davinci_nand_readl(info, NAND_4BIT_ECC1_OFFSET);
+-		return 0;
+-	}
+-
+-	/* Pack eight raw 10-bit ecc values into ten bytes, making
+-	 * two passes which each convert four values (in upper and
+-	 * lower halves of two 32-bit words) into five bytes.  The
+-	 * ROM boot loader uses this same packing scheme.
+-	 */
+-	nand_davinci_readecc_4bit(info, raw_ecc);
+-	for (i = 0, p = raw_ecc; i < 2; i++, p += 2) {
+-		*ecc_code++ =   p[0]        & 0xff;
+-		*ecc_code++ = ((p[0] >>  8) & 0x03) | ((p[0] >> 14) & 0xfc);
+-		*ecc_code++ = ((p[0] >> 22) & 0x0f) | ((p[1] <<  4) & 0xf0);
+-		*ecc_code++ = ((p[1] >>  4) & 0x3f) | ((p[1] >> 10) & 0xc0);
+-		*ecc_code++ =  (p[1] >> 18) & 0xff;
+-	}
+-
+-	return 0;
+-}
+-
+-/* Correct up to 4 bits in data we just read, using state left in the
+- * hardware plus the ecc_code computed when it was first written.
+- */
+-static int nand_davinci_correct_4bit(struct mtd_info *mtd,
+-		u_char *data, u_char *ecc_code, u_char *null)
+-{
+-	int i;
+-	struct davinci_nand_info *info = to_davinci_nand(mtd);
+-	unsigned short ecc10[8];
+-	unsigned short *ecc16;
+-	u32 syndrome[4];
+-	u32 ecc_state;
+-	unsigned num_errors, corrected;
+-	unsigned long timeo;
+-
+-	/* Unpack ten bytes into eight 10 bit values.  We know we're
+-	 * little-endian, and use type punning for less shifting/masking.
+-	 */
+-	if (WARN_ON(0x01 & (unsigned) ecc_code))
+-		return -EINVAL;
+-	ecc16 = (unsigned short *)ecc_code;
+-
+-	ecc10[0] =  (ecc16[0] >>  0) & 0x3ff;
+-	ecc10[1] = ((ecc16[0] >> 10) & 0x3f) | ((ecc16[1] << 6) & 0x3c0);
+-	ecc10[2] =  (ecc16[1] >>  4) & 0x3ff;
+-	ecc10[3] = ((ecc16[1] >> 14) & 0x3)  | ((ecc16[2] << 2) & 0x3fc);
+-	ecc10[4] =  (ecc16[2] >>  8)         | ((ecc16[3] << 8) & 0x300);
+-	ecc10[5] =  (ecc16[3] >>  2) & 0x3ff;
+-	ecc10[6] = ((ecc16[3] >> 12) & 0xf)  | ((ecc16[4] << 4) & 0x3f0);
+-	ecc10[7] =  (ecc16[4] >>  6) & 0x3ff;
+-
+-	/* Tell ECC controller about the expected ECC codes. */
+-	for (i = 7; i >= 0; i--)
+-		davinci_nand_writel(info, NAND_4BIT_ECC_LOAD_OFFSET, ecc10[i]);
+-
+-	/* Allow time for syndrome calculation ... then read it.
+-	 * A syndrome of all zeroes 0 means no detected errors.
+-	 */
+-	davinci_nand_readl(info, NANDFSR_OFFSET);
+-	nand_davinci_readecc_4bit(info, syndrome);
+-	if (!(syndrome[0] | syndrome[1] | syndrome[2] | syndrome[3]))
+-		return 0;
+-
+-	/*
+-	 * Clear any previous address calculation by doing a dummy read of an
+-	 * error address register.
+-	 */
+-	davinci_nand_readl(info, NAND_ERR_ADD1_OFFSET);
+-
+-	/* Start address calculation, and wait for it to complete.
+-	 * We _could_ start reading more data while this is working,
+-	 * to speed up the overall page read.
+-	 */
+-	davinci_nand_writel(info, NANDFCR_OFFSET,
+-			davinci_nand_readl(info, NANDFCR_OFFSET) | BIT(13));
+-
+-	/*
+-	 * ECC_STATE field reads 0x3 (Error correction complete) immediately
+-	 * after setting the 4BITECC_ADD_CALC_START bit. So if you immediately
+-	 * begin trying to poll for the state, you may fall right out of your
+-	 * loop without any of the correction calculations having taken place.
+-	 * The recommendation from the hardware team is to initially delay as
+-	 * long as ECC_STATE reads less than 4. After that, ECC HW has entered
+-	 * correction state.
+-	 */
+-	timeo = jiffies + usecs_to_jiffies(100);
+-	do {
+-		ecc_state = (davinci_nand_readl(info,
+-				NANDFSR_OFFSET) >> 8) & 0x0f;
+-		cpu_relax();
+-	} while ((ecc_state < 4) && time_before(jiffies, timeo));
+-
+-	for (;;) {
+-		u32	fsr = davinci_nand_readl(info, NANDFSR_OFFSET);
+-
+-		switch ((fsr >> 8) & 0x0f) {
+-		case 0:		/* no error, should not happen */
+-			davinci_nand_readl(info, NAND_ERR_ERRVAL1_OFFSET);
+-			return 0;
+-		case 1:		/* five or more errors detected */
+-			davinci_nand_readl(info, NAND_ERR_ERRVAL1_OFFSET);
+-			return -EBADMSG;
+-		case 2:		/* error addresses computed */
+-		case 3:
+-			num_errors = 1 + ((fsr >> 16) & 0x03);
+-			goto correct;
+-		default:	/* still working on it */
+-			cpu_relax();
+-			continue;
+-		}
+-	}
+-
+-correct:
+-	/* correct each error */
+-	for (i = 0, corrected = 0; i < num_errors; i++) {
+-		int error_address, error_value;
+-
+-		if (i > 1) {
+-			error_address = davinci_nand_readl(info,
+-						NAND_ERR_ADD2_OFFSET);
+-			error_value = davinci_nand_readl(info,
+-						NAND_ERR_ERRVAL2_OFFSET);
+-		} else {
+-			error_address = davinci_nand_readl(info,
+-						NAND_ERR_ADD1_OFFSET);
+-			error_value = davinci_nand_readl(info,
+-						NAND_ERR_ERRVAL1_OFFSET);
+-		}
+-
+-		if (i & 1) {
+-			error_address >>= 16;
+-			error_value >>= 16;
+-		}
+-		error_address &= 0x3ff;
+-		error_address = (512 + 7) - error_address;
+-
+-		if (error_address < 512) {
+-			data[error_address] ^= error_value;
+-			corrected++;
+-		}
+-	}
+-
+-	return corrected;
+-}
+-
+-/*----------------------------------------------------------------------*/
+-
+-/*
+- * NOTE:  NAND boot requires ALE == EM_A[1], CLE == EM_A[2], so that's
+- * how these chips are normally wired.  This translates to both 8 and 16
+- * bit busses using ALE == BIT(3) in byte addresses, and CLE == BIT(4).
+- *
+- * For now we assume that configuration, or any other one which ignores
+- * the two LSBs for NAND access ... so we can issue 32-bit reads/writes
+- * and have that transparently morphed into multiple NAND operations.
+- */
+-static void nand_davinci_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-
+-	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
+-		ioread8_rep(chip->IO_ADDR_R, buf, 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);
+-
+-	if ((0x03 & ((unsigned)buf)) == 0 && (0x03 & len) == 0)
+-		iowrite32_rep(chip->IO_ADDR_R, buf, len >> 2);
+-	else if ((0x01 & ((unsigned)buf)) == 0 && (0x01 & len) == 0)
+-		iowrite16_rep(chip->IO_ADDR_R, buf, len >> 1);
+-	else
+-		iowrite8_rep(chip->IO_ADDR_R, buf, len);
+-}
+-
+-/*
+- * Check hardware register for wait status. Returns 1 if device is ready,
+- * 0 if it is still busy.
+- */
+-static int nand_davinci_dev_ready(struct mtd_info *mtd)
+-{
+-	struct davinci_nand_info *info = to_davinci_nand(mtd);
+-
+-	return davinci_nand_readl(info, NANDFSR_OFFSET) & BIT(0);
+-}
+-
+-/*----------------------------------------------------------------------*/
+-
+-/* An ECC layout for using 4-bit ECC with small-page flash, storing
+- * ten ECC bytes plus the manufacturer's bad block marker byte, and
+- * and not overlapping the default BBT markers.
+- */
+-static int hwecc4_ooblayout_small_ecc(struct mtd_info *mtd, int section,
+-				      struct mtd_oob_region *oobregion)
+-{
+-	if (section > 2)
+-		return -ERANGE;
+-
+-	if (!section) {
+-		oobregion->offset = 0;
+-		oobregion->length = 5;
+-	} else if (section == 1) {
+-		oobregion->offset = 6;
+-		oobregion->length = 2;
+-	} else {
+-		oobregion->offset = 13;
+-		oobregion->length = 3;
+-	}
+-
+-	return 0;
+-}
+-
+-static int hwecc4_ooblayout_small_free(struct mtd_info *mtd, int section,
+-				       struct mtd_oob_region *oobregion)
+-{
+-	if (section > 1)
+-		return -ERANGE;
+-
+-	if (!section) {
+-		oobregion->offset = 8;
+-		oobregion->length = 5;
+-	} else {
+-		oobregion->offset = 16;
+-		oobregion->length = mtd->oobsize - 16;
+-	}
+-
+-	return 0;
+-}
+-
+-static const struct mtd_ooblayout_ops hwecc4_small_ooblayout_ops = {
+-	.ecc = hwecc4_ooblayout_small_ecc,
+-	.free = hwecc4_ooblayout_small_free,
+-};
+-
+-#if defined(CONFIG_OF)
+-static const struct of_device_id davinci_nand_of_match[] = {
+-	{.compatible = "ti,davinci-nand", },
+-	{.compatible = "ti,keystone-nand", },
+-	{},
+-};
+-MODULE_DEVICE_TABLE(of, davinci_nand_of_match);
+-
+-static struct davinci_nand_pdata
+-	*nand_davinci_get_pdata(struct platform_device *pdev)
+-{
+-	if (!dev_get_platdata(&pdev->dev) && pdev->dev.of_node) {
+-		struct davinci_nand_pdata *pdata;
+-		const char *mode;
+-		u32 prop;
+-
+-		pdata =  devm_kzalloc(&pdev->dev,
+-				sizeof(struct davinci_nand_pdata),
+-				GFP_KERNEL);
+-		pdev->dev.platform_data = pdata;
+-		if (!pdata)
+-			return ERR_PTR(-ENOMEM);
+-		if (!of_property_read_u32(pdev->dev.of_node,
+-			"ti,davinci-chipselect", &prop))
+-			pdev->id = prop;
+-		else
+-			return ERR_PTR(-EINVAL);
+-
+-		if (!of_property_read_u32(pdev->dev.of_node,
+-			"ti,davinci-mask-ale", &prop))
+-			pdata->mask_ale = prop;
+-		if (!of_property_read_u32(pdev->dev.of_node,
+-			"ti,davinci-mask-cle", &prop))
+-			pdata->mask_cle = prop;
+-		if (!of_property_read_u32(pdev->dev.of_node,
+-			"ti,davinci-mask-chipsel", &prop))
+-			pdata->mask_chipsel = prop;
+-		if (!of_property_read_string(pdev->dev.of_node,
+-			"ti,davinci-ecc-mode", &mode)) {
+-			if (!strncmp("none", mode, 4))
+-				pdata->ecc_mode = NAND_ECC_NONE;
+-			if (!strncmp("soft", mode, 4))
+-				pdata->ecc_mode = NAND_ECC_SOFT;
+-			if (!strncmp("hw", mode, 2))
+-				pdata->ecc_mode = NAND_ECC_HW;
+-		}
+-		if (!of_property_read_u32(pdev->dev.of_node,
+-			"ti,davinci-ecc-bits", &prop))
+-			pdata->ecc_bits = prop;
+-
+-		if (!of_property_read_u32(pdev->dev.of_node,
+-			"ti,davinci-nand-buswidth", &prop) && prop == 16)
+-			pdata->options |= NAND_BUSWIDTH_16;
+-
+-		if (of_property_read_bool(pdev->dev.of_node,
+-			"ti,davinci-nand-use-bbt"))
+-			pdata->bbt_options = NAND_BBT_USE_FLASH;
+-
+-		/*
+-		 * Since kernel v4.8, this driver has been fixed to enable
+-		 * use of 4-bit hardware ECC with subpages and verified on
+-		 * TI's keystone EVMs (K2L, K2HK and K2E).
+-		 * However, in the interest of not breaking systems using
+-		 * existing UBI partitions, sub-page writes are not being
+-		 * (re)enabled. If you want to use subpage writes on Keystone
+-		 * platforms (i.e. do not have any existing UBI partitions),
+-		 * then use "ti,davinci-nand" as the compatible in your
+-		 * device-tree file.
+-		 */
+-		if (of_device_is_compatible(pdev->dev.of_node,
+-					    "ti,keystone-nand")) {
+-			pdata->options |= NAND_NO_SUBPAGE_WRITE;
+-		}
+-	}
+-
+-	return dev_get_platdata(&pdev->dev);
+-}
+-#else
+-static struct davinci_nand_pdata
+-	*nand_davinci_get_pdata(struct platform_device *pdev)
+-{
+-	return dev_get_platdata(&pdev->dev);
+-}
+-#endif
+-
+-static int nand_davinci_probe(struct platform_device *pdev)
+-{
+-	struct davinci_nand_pdata	*pdata;
+-	struct davinci_nand_info	*info;
+-	struct resource			*res1;
+-	struct resource			*res2;
+-	void __iomem			*vaddr;
+-	void __iomem			*base;
+-	int				ret;
+-	uint32_t			val;
+-	struct mtd_info			*mtd;
+-
+-	pdata = nand_davinci_get_pdata(pdev);
+-	if (IS_ERR(pdata))
+-		return PTR_ERR(pdata);
+-
+-	/* insist on board-specific configuration */
+-	if (!pdata)
+-		return -ENODEV;
+-
+-	/* which external chipselect will we be managing? */
+-	if (pdev->id < 0 || pdev->id > 3)
+-		return -ENODEV;
+-
+-	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
+-	if (!info)
+-		return -ENOMEM;
+-
+-	platform_set_drvdata(pdev, info);
+-
+-	res1 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+-	res2 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+-	if (!res1 || !res2) {
+-		dev_err(&pdev->dev, "resource missing\n");
+-		return -EINVAL;
+-	}
+-
+-	vaddr = devm_ioremap_resource(&pdev->dev, res1);
+-	if (IS_ERR(vaddr))
+-		return PTR_ERR(vaddr);
+-
+-	/*
+-	 * This registers range is used to setup NAND settings. In case with
+-	 * TI AEMIF driver, the same memory address range is requested already
+-	 * by AEMIF, so we cannot request it twice, just ioremap.
+-	 * The AEMIF and NAND drivers not use the same registers in this range.
+-	 */
+-	base = devm_ioremap(&pdev->dev, res2->start, resource_size(res2));
+-	if (!base) {
+-		dev_err(&pdev->dev, "ioremap failed for resource %pR\n", res2);
+-		return -EADDRNOTAVAIL;
+-	}
+-
+-	info->dev		= &pdev->dev;
+-	info->base		= base;
+-	info->vaddr		= vaddr;
+-
+-	mtd			= nand_to_mtd(&info->chip);
+-	mtd->dev.parent		= &pdev->dev;
+-	nand_set_flash_node(&info->chip, pdev->dev.of_node);
+-
+-	info->chip.IO_ADDR_R	= vaddr;
+-	info->chip.IO_ADDR_W	= vaddr;
+-	info->chip.chip_delay	= 0;
+-	info->chip.select_chip	= nand_davinci_select_chip;
+-
+-	/* options such as NAND_BBT_USE_FLASH */
+-	info->chip.bbt_options	= pdata->bbt_options;
+-	/* options such as 16-bit widths */
+-	info->chip.options	= pdata->options;
+-	info->chip.bbt_td	= pdata->bbt_td;
+-	info->chip.bbt_md	= pdata->bbt_md;
+-	info->timing		= pdata->timing;
+-
+-	info->ioaddr		= (uint32_t __force) vaddr;
+-
+-	info->current_cs	= info->ioaddr;
+-	info->core_chipsel	= pdev->id;
+-	info->mask_chipsel	= pdata->mask_chipsel;
+-
+-	/* use nandboot-capable ALE/CLE masks by default */
+-	info->mask_ale		= pdata->mask_ale ? : MASK_ALE;
+-	info->mask_cle		= pdata->mask_cle ? : MASK_CLE;
+-
+-	/* Set address of hardware control function */
+-	info->chip.cmd_ctrl	= nand_davinci_hwcontrol;
+-	info->chip.dev_ready	= nand_davinci_dev_ready;
+-
+-	/* Speed up buffer I/O */
+-	info->chip.read_buf     = nand_davinci_read_buf;
+-	info->chip.write_buf    = nand_davinci_write_buf;
+-
+-	/* Use board-specific ECC config */
+-	info->chip.ecc.mode	= pdata->ecc_mode;
+-
+-	ret = -EINVAL;
+-
+-	info->clk = devm_clk_get(&pdev->dev, "aemif");
+-	if (IS_ERR(info->clk)) {
+-		ret = PTR_ERR(info->clk);
+-		dev_dbg(&pdev->dev, "unable to get AEMIF clock, err %d\n", ret);
+-		return ret;
+-	}
+-
+-	ret = clk_prepare_enable(info->clk);
+-	if (ret < 0) {
+-		dev_dbg(&pdev->dev, "unable to enable AEMIF clock, err %d\n",
+-			ret);
+-		goto err_clk_enable;
+-	}
+-
+-	spin_lock_irq(&davinci_nand_lock);
+-
+-	/* put CSxNAND into NAND mode */
+-	val = davinci_nand_readl(info, NANDFCR_OFFSET);
+-	val |= BIT(info->core_chipsel);
+-	davinci_nand_writel(info, NANDFCR_OFFSET, val);
+-
+-	spin_unlock_irq(&davinci_nand_lock);
+-
+-	/* Scan to find existence of the device(s) */
+-	ret = nand_scan_ident(mtd, pdata->mask_chipsel ? 2 : 1, NULL);
+-	if (ret < 0) {
+-		dev_dbg(&pdev->dev, "no NAND chip(s) found\n");
+-		goto err;
+-	}
+-
+-	switch (info->chip.ecc.mode) {
+-	case NAND_ECC_NONE:
+-		pdata->ecc_bits = 0;
+-		break;
+-	case NAND_ECC_SOFT:
+-		pdata->ecc_bits = 0;
+-		/*
+-		 * 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
+-		 * davinci_nand_pdata.
+-		 */
+-		info->chip.ecc.algo = NAND_ECC_HAMMING;
+-		break;
+-	case NAND_ECC_HW:
+-		if (pdata->ecc_bits == 4) {
+-			/* No sanity checks:  CPUs must support this,
+-			 * and the chips may not use NAND_BUSWIDTH_16.
+-			 */
+-
+-			/* No sharing 4-bit hardware between chipselects yet */
+-			spin_lock_irq(&davinci_nand_lock);
+-			if (ecc4_busy)
+-				ret = -EBUSY;
+-			else
+-				ecc4_busy = true;
+-			spin_unlock_irq(&davinci_nand_lock);
+-
+-			if (ret == -EBUSY)
+-				return ret;
+-
+-			info->chip.ecc.calculate = nand_davinci_calculate_4bit;
+-			info->chip.ecc.correct = nand_davinci_correct_4bit;
+-			info->chip.ecc.hwctl = nand_davinci_hwctl_4bit;
+-			info->chip.ecc.bytes = 10;
+-			info->chip.ecc.options = NAND_ECC_GENERIC_ERASED_CHECK;
+-			info->chip.ecc.algo = NAND_ECC_BCH;
+-		} else {
+-			/* 1bit ecc hamming */
+-			info->chip.ecc.calculate = nand_davinci_calculate_1bit;
+-			info->chip.ecc.correct = nand_davinci_correct_1bit;
+-			info->chip.ecc.hwctl = nand_davinci_hwctl_1bit;
+-			info->chip.ecc.bytes = 3;
+-			info->chip.ecc.algo = NAND_ECC_HAMMING;
+-		}
+-		info->chip.ecc.size = 512;
+-		info->chip.ecc.strength = pdata->ecc_bits;
+-		break;
+-	default:
+-		return -EINVAL;
+-	}
+-
+-	/* Update ECC layout if needed ... for 1-bit HW ECC, the default
+-	 * is OK, but it allocates 6 bytes when only 3 are needed (for
+-	 * each 512 bytes).  For the 4-bit HW ECC, that default is not
+-	 * usable:  10 bytes are needed, not 6.
+-	 */
+-	if (pdata->ecc_bits == 4) {
+-		int	chunks = mtd->writesize / 512;
+-
+-		if (!chunks || mtd->oobsize < 16) {
+-			dev_dbg(&pdev->dev, "too small\n");
+-			ret = -EINVAL;
+-			goto err;
+-		}
+-
+-		/* For small page chips, preserve the manufacturer's
+-		 * badblock marking data ... and make sure a flash BBT
+-		 * table marker fits in the free bytes.
+-		 */
+-		if (chunks == 1) {
+-			mtd_set_ooblayout(mtd, &hwecc4_small_ooblayout_ops);
+-		} else if (chunks == 4 || chunks == 8) {
+-			mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
+-			info->chip.ecc.mode = NAND_ECC_HW_OOB_FIRST;
+-		} else {
+-			ret = -EIO;
+-			goto err;
+-		}
+-	}
+-
+-	ret = nand_scan_tail(mtd);
+-	if (ret < 0)
+-		goto err;
+-
+-	if (pdata->parts)
+-		ret = mtd_device_parse_register(mtd, NULL, NULL,
+-					pdata->parts, pdata->nr_parts);
+-	else
+-		ret = mtd_device_register(mtd, NULL, 0);
+-	if (ret < 0)
+-		goto err;
+-
+-	val = davinci_nand_readl(info, NRCSR_OFFSET);
+-	dev_info(&pdev->dev, "controller rev. %d.%d\n",
+-	       (val >> 8) & 0xff, val & 0xff);
+-
+-	return 0;
+-
+-err:
+-	clk_disable_unprepare(info->clk);
+-
+-err_clk_enable:
+-	spin_lock_irq(&davinci_nand_lock);
+-	if (info->chip.ecc.mode == NAND_ECC_HW_SYNDROME)
+-		ecc4_busy = false;
+-	spin_unlock_irq(&davinci_nand_lock);
+-	return ret;
+-}
+-
+-static int nand_davinci_remove(struct platform_device *pdev)
+-{
+-	struct davinci_nand_info *info = platform_get_drvdata(pdev);
+-
+-	spin_lock_irq(&davinci_nand_lock);
+-	if (info->chip.ecc.mode == NAND_ECC_HW_SYNDROME)
+-		ecc4_busy = false;
+-	spin_unlock_irq(&davinci_nand_lock);
+-
+-	nand_release(nand_to_mtd(&info->chip));
+-
+-	clk_disable_unprepare(info->clk);
+-
+-	return 0;
+-}
+-
+-static struct platform_driver nand_davinci_driver = {
+-	.probe		= nand_davinci_probe,
+-	.remove		= nand_davinci_remove,
+-	.driver		= {
+-		.name	= "davinci_nand",
+-		.of_match_table = of_match_ptr(davinci_nand_of_match),
+-	},
+-};
+-MODULE_ALIAS("platform:davinci_nand");
+-
+-module_platform_driver(nand_davinci_driver);
+-
+-MODULE_LICENSE("GPL");
+-MODULE_AUTHOR("Texas Instruments");
+-MODULE_DESCRIPTION("Davinci NAND flash driver");
+-
+diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c
+deleted file mode 100644
+index 3087b0b..0000000
+--- a/drivers/mtd/nand/denali.c
++++ /dev/null
+@@ -1,1453 +0,0 @@
+-/*
+- * NAND Flash Controller Device Driver
+- * Copyright © 2009-2010, Intel Corporation and its suppliers.
+- *
+- * 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, write to the Free Software Foundation, Inc.,
+- * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+- *
+- */
+-#include <linux/interrupt.h>
+-#include <linux/delay.h>
+-#include <linux/dma-mapping.h>
+-#include <linux/wait.h>
+-#include <linux/mutex.h>
+-#include <linux/mtd/mtd.h>
+-#include <linux/module.h>
+-#include <linux/slab.h>
+-
+-#include "denali.h"
+-
+-MODULE_LICENSE("GPL");
+-
+-#define DENALI_NAND_NAME    "denali-nand"
+-
+-/* Host Data/Command Interface */
+-#define DENALI_HOST_ADDR	0x00
+-#define DENALI_HOST_DATA	0x10
+-
+-#define DENALI_MAP00		(0 << 26)	/* direct access to buffer */
+-#define DENALI_MAP01		(1 << 26)	/* read/write pages in PIO */
+-#define DENALI_MAP10		(2 << 26)	/* high-level control plane */
+-#define DENALI_MAP11		(3 << 26)	/* direct controller access */
+-
+-/* MAP11 access cycle type */
+-#define DENALI_MAP11_CMD	((DENALI_MAP11) | 0)	/* command cycle */
+-#define DENALI_MAP11_ADDR	((DENALI_MAP11) | 1)	/* address cycle */
+-#define DENALI_MAP11_DATA	((DENALI_MAP11) | 2)	/* data cycle */
+-
+-/* MAP10 commands */
+-#define DENALI_ERASE		0x01
+-
+-#define DENALI_BANK(denali)	((denali)->active_bank << 24)
+-
+-#define DENALI_INVALID_BANK	-1
+-#define DENALI_NR_BANKS		4
+-
+-/*
+- * The bus interface clock, clk_x, is phase aligned with the core clock.  The
+- * clk_x is an integral multiple N of the core clk.  The value N is configured
+- * at IP delivery time, and its available value is 4, 5, or 6.  We need to align
+- * to the largest value to make it work with any possible configuration.
+- */
+-#define DENALI_CLK_X_MULT	6
+-
+-/*
+- * this macro allows us to convert from an MTD structure to our own
+- * device context (denali) structure.
+- */
+-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);
+-}
+-
+-static void denali_host_write(struct denali_nand_info *denali,
+-			      uint32_t addr, uint32_t data)
+-{
+-	iowrite32(addr, denali->host + DENALI_HOST_ADDR);
+-	iowrite32(data, denali->host + DENALI_HOST_DATA);
+-}
+-
+-/*
+- * Use the configuration feature register to determine the maximum number of
+- * banks that the hardware supports.
+- */
+-static void detect_max_banks(struct denali_nand_info *denali)
+-{
+-	uint32_t features = ioread32(denali->reg + FEATURES);
+-
+-	denali->max_banks = 1 << (features & FEATURES__N_BANKS);
+-
+-	/* the encoding changed from rev 5.0 to 5.1 */
+-	if (denali->revision < 0x0501)
+-		denali->max_banks <<= 1;
+-}
+-
+-static void denali_enable_irq(struct denali_nand_info *denali)
+-{
+-	int i;
+-
+-	for (i = 0; i < DENALI_NR_BANKS; i++)
+-		iowrite32(U32_MAX, denali->reg + INTR_EN(i));
+-	iowrite32(GLOBAL_INT_EN_FLAG, denali->reg + GLOBAL_INT_ENABLE);
+-}
+-
+-static void denali_disable_irq(struct denali_nand_info *denali)
+-{
+-	int i;
+-
+-	for (i = 0; i < DENALI_NR_BANKS; i++)
+-		iowrite32(0, denali->reg + INTR_EN(i));
+-	iowrite32(0, denali->reg + GLOBAL_INT_ENABLE);
+-}
+-
+-static void denali_clear_irq(struct denali_nand_info *denali,
+-			     int bank, uint32_t irq_status)
+-{
+-	/* write one to clear bits */
+-	iowrite32(irq_status, denali->reg + INTR_STATUS(bank));
+-}
+-
+-static void denali_clear_irq_all(struct denali_nand_info *denali)
+-{
+-	int i;
+-
+-	for (i = 0; i < DENALI_NR_BANKS; i++)
+-		denali_clear_irq(denali, i, U32_MAX);
+-}
+-
+-static irqreturn_t denali_isr(int irq, void *dev_id)
+-{
+-	struct denali_nand_info *denali = dev_id;
+-	irqreturn_t ret = IRQ_NONE;
+-	uint32_t irq_status;
+-	int i;
+-
+-	spin_lock(&denali->irq_lock);
+-
+-	for (i = 0; i < DENALI_NR_BANKS; i++) {
+-		irq_status = ioread32(denali->reg + INTR_STATUS(i));
+-		if (irq_status)
+-			ret = IRQ_HANDLED;
+-
+-		denali_clear_irq(denali, i, irq_status);
+-
+-		if (i != denali->active_bank)
+-			continue;
+-
+-		denali->irq_status |= irq_status;
+-
+-		if (denali->irq_status & denali->irq_mask)
+-			complete(&denali->complete);
+-	}
+-
+-	spin_unlock(&denali->irq_lock);
+-
+-	return ret;
+-}
+-
+-static void denali_reset_irq(struct denali_nand_info *denali)
+-{
+-	unsigned long flags;
+-
+-	spin_lock_irqsave(&denali->irq_lock, flags);
+-	denali->irq_status = 0;
+-	denali->irq_mask = 0;
+-	spin_unlock_irqrestore(&denali->irq_lock, flags);
+-}
+-
+-static uint32_t denali_wait_for_irq(struct denali_nand_info *denali,
+-				    uint32_t irq_mask)
+-{
+-	unsigned long time_left, flags;
+-	uint32_t irq_status;
+-
+-	spin_lock_irqsave(&denali->irq_lock, flags);
+-
+-	irq_status = denali->irq_status;
+-
+-	if (irq_mask & irq_status) {
+-		/* return immediately if the IRQ has already happened. */
+-		spin_unlock_irqrestore(&denali->irq_lock, flags);
+-		return irq_status;
+-	}
+-
+-	denali->irq_mask = irq_mask;
+-	reinit_completion(&denali->complete);
+-	spin_unlock_irqrestore(&denali->irq_lock, flags);
+-
+-	time_left = wait_for_completion_timeout(&denali->complete,
+-						msecs_to_jiffies(1000));
+-	if (!time_left) {
+-		dev_err(denali->dev, "timeout while waiting for irq 0x%x\n",
+-			denali->irq_mask);
+-		return 0;
+-	}
+-
+-	return denali->irq_status;
+-}
+-
+-static uint32_t denali_check_irq(struct denali_nand_info *denali)
+-{
+-	unsigned long flags;
+-	uint32_t irq_status;
+-
+-	spin_lock_irqsave(&denali->irq_lock, flags);
+-	irq_status = denali->irq_status;
+-	spin_unlock_irqrestore(&denali->irq_lock, flags);
+-
+-	return irq_status;
+-}
+-
+-/*
+- * This helper function setups the registers for ECC and whether or not
+- * the spare area will be transferred.
+- */
+-static void setup_ecc_for_xfer(struct denali_nand_info *denali, bool ecc_en,
+-				bool transfer_spare)
+-{
+-	int ecc_en_flag, transfer_spare_flag;
+-
+-	/* set ECC, transfer spare bits if needed */
+-	ecc_en_flag = ecc_en ? ECC_ENABLE__FLAG : 0;
+-	transfer_spare_flag = transfer_spare ? TRANSFER_SPARE_REG__FLAG : 0;
+-
+-	/* Enable spare area/ECC per user's request. */
+-	iowrite32(ecc_en_flag, denali->reg + ECC_ENABLE);
+-	iowrite32(transfer_spare_flag, denali->reg + TRANSFER_SPARE_REG);
+-}
+-
+-static void denali_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+-{
+-	struct denali_nand_info *denali = mtd_to_denali(mtd);
+-	int i;
+-
+-	iowrite32(DENALI_MAP11_DATA | DENALI_BANK(denali),
+-		  denali->host + DENALI_HOST_ADDR);
+-
+-	for (i = 0; i < len; i++)
+-		buf[i] = ioread32(denali->host + DENALI_HOST_DATA);
+-}
+-
+-static void denali_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+-{
+-	struct denali_nand_info *denali = mtd_to_denali(mtd);
+-	int i;
+-
+-	iowrite32(DENALI_MAP11_DATA | DENALI_BANK(denali),
+-		  denali->host + DENALI_HOST_ADDR);
+-
+-	for (i = 0; i < len; i++)
+-		iowrite32(buf[i], denali->host + DENALI_HOST_DATA);
+-}
+-
+-static void denali_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
+-{
+-	struct denali_nand_info *denali = mtd_to_denali(mtd);
+-	uint16_t *buf16 = (uint16_t *)buf;
+-	int i;
+-
+-	iowrite32(DENALI_MAP11_DATA | DENALI_BANK(denali),
+-		  denali->host + DENALI_HOST_ADDR);
+-
+-	for (i = 0; i < len / 2; i++)
+-		buf16[i] = ioread32(denali->host + DENALI_HOST_DATA);
+-}
+-
+-static void denali_write_buf16(struct mtd_info *mtd, const uint8_t *buf,
+-			       int len)
+-{
+-	struct denali_nand_info *denali = mtd_to_denali(mtd);
+-	const uint16_t *buf16 = (const uint16_t *)buf;
+-	int i;
+-
+-	iowrite32(DENALI_MAP11_DATA | DENALI_BANK(denali),
+-		  denali->host + DENALI_HOST_ADDR);
+-
+-	for (i = 0; i < len / 2; i++)
+-		iowrite32(buf16[i], denali->host + DENALI_HOST_DATA);
+-}
+-
+-static uint8_t denali_read_byte(struct mtd_info *mtd)
+-{
+-	uint8_t byte;
+-
+-	denali_read_buf(mtd, &byte, 1);
+-
+-	return byte;
+-}
+-
+-static void denali_write_byte(struct mtd_info *mtd, uint8_t byte)
+-{
+-	denali_write_buf(mtd, &byte, 1);
+-}
+-
+-static uint16_t denali_read_word(struct mtd_info *mtd)
+-{
+-	uint16_t word;
+-
+-	denali_read_buf16(mtd, (uint8_t *)&word, 2);
+-
+-	return word;
+-}
+-
+-static void denali_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
+-{
+-	struct denali_nand_info *denali = mtd_to_denali(mtd);
+-	uint32_t type;
+-
+-	if (ctrl & NAND_CLE)
+-		type = DENALI_MAP11_CMD;
+-	else if (ctrl & NAND_ALE)
+-		type = DENALI_MAP11_ADDR;
+-	else
+-		return;
+-
+-	/*
+-	 * Some commands are followed by chip->dev_ready or chip->waitfunc.
+-	 * irq_status must be cleared here to catch the R/B# interrupt later.
+-	 */
+-	if (ctrl & NAND_CTRL_CHANGE)
+-		denali_reset_irq(denali);
+-
+-	denali_host_write(denali, DENALI_BANK(denali) | type, dat);
+-}
+-
+-static int denali_dev_ready(struct mtd_info *mtd)
+-{
+-	struct denali_nand_info *denali = mtd_to_denali(mtd);
+-
+-	return !!(denali_check_irq(denali) & INTR__INT_ACT);
+-}
+-
+-static int denali_check_erased_page(struct mtd_info *mtd,
+-				    struct nand_chip *chip, uint8_t *buf,
+-				    unsigned long uncor_ecc_flags,
+-				    unsigned int max_bitflips)
+-{
+-	uint8_t *ecc_code = chip->buffers->ecccode;
+-	int ecc_steps = chip->ecc.steps;
+-	int ecc_size = chip->ecc.size;
+-	int ecc_bytes = chip->ecc.bytes;
+-	int i, ret, stat;
+-
+-	ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, chip->oob_poi, 0,
+-					 chip->ecc.total);
+-	if (ret)
+-		return ret;
+-
+-	for (i = 0; i < ecc_steps; i++) {
+-		if (!(uncor_ecc_flags & BIT(i)))
+-			continue;
+-
+-		stat = nand_check_erased_ecc_chunk(buf, ecc_size,
+-						  ecc_code, ecc_bytes,
+-						  NULL, 0,
+-						  chip->ecc.strength);
+-		if (stat < 0) {
+-			mtd->ecc_stats.failed++;
+-		} else {
+-			mtd->ecc_stats.corrected += stat;
+-			max_bitflips = max_t(unsigned int, max_bitflips, stat);
+-		}
+-
+-		buf += ecc_size;
+-		ecc_code += ecc_bytes;
+-	}
+-
+-	return max_bitflips;
+-}
+-
+-static int denali_hw_ecc_fixup(struct mtd_info *mtd,
+-			       struct denali_nand_info *denali,
+-			       unsigned long *uncor_ecc_flags)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	int bank = denali->active_bank;
+-	uint32_t ecc_cor;
+-	unsigned int max_bitflips;
+-
+-	ecc_cor = ioread32(denali->reg + ECC_COR_INFO(bank));
+-	ecc_cor >>= ECC_COR_INFO__SHIFT(bank);
+-
+-	if (ecc_cor & ECC_COR_INFO__UNCOR_ERR) {
+-		/*
+-		 * This flag is set when uncorrectable error occurs at least in
+-		 * one ECC sector.  We can not know "how many sectors", or
+-		 * "which sector(s)".  We need erase-page check for all sectors.
+-		 */
+-		*uncor_ecc_flags = GENMASK(chip->ecc.steps - 1, 0);
+-		return 0;
+-	}
+-
+-	max_bitflips = ecc_cor & ECC_COR_INFO__MAX_ERRORS;
+-
+-	/*
+-	 * The register holds the maximum of per-sector corrected bitflips.
+-	 * This is suitable for the return value of the ->read_page() callback.
+-	 * Unfortunately, we can not know the total number of corrected bits in
+-	 * the page.  Increase the stats by max_bitflips. (compromised solution)
+-	 */
+-	mtd->ecc_stats.corrected += max_bitflips;
+-
+-	return max_bitflips;
+-}
+-
+-#define ECC_SECTOR(x)	(((x) & ECC_ERROR_ADDRESS__SECTOR_NR) >> 12)
+-#define ECC_BYTE(x)	(((x) & ECC_ERROR_ADDRESS__OFFSET))
+-#define ECC_CORRECTION_VALUE(x) ((x) & ERR_CORRECTION_INFO__BYTEMASK)
+-#define ECC_ERROR_UNCORRECTABLE(x) ((x) & ERR_CORRECTION_INFO__ERROR_TYPE)
+-#define ECC_ERR_DEVICE(x)	(((x) & ERR_CORRECTION_INFO__DEVICE_NR) >> 8)
+-#define ECC_LAST_ERR(x)		((x) & ERR_CORRECTION_INFO__LAST_ERR_INFO)
+-
+-static int denali_sw_ecc_fixup(struct mtd_info *mtd,
+-			       struct denali_nand_info *denali,
+-			       unsigned long *uncor_ecc_flags, uint8_t *buf)
+-{
+-	unsigned int ecc_size = denali->nand.ecc.size;
+-	unsigned int bitflips = 0;
+-	unsigned int max_bitflips = 0;
+-	uint32_t err_addr, err_cor_info;
+-	unsigned int err_byte, err_sector, err_device;
+-	uint8_t err_cor_value;
+-	unsigned int prev_sector = 0;
+-	uint32_t irq_status;
+-
+-	denali_reset_irq(denali);
+-
+-	do {
+-		err_addr = ioread32(denali->reg + ECC_ERROR_ADDRESS);
+-		err_sector = ECC_SECTOR(err_addr);
+-		err_byte = ECC_BYTE(err_addr);
+-
+-		err_cor_info = ioread32(denali->reg + ERR_CORRECTION_INFO);
+-		err_cor_value = ECC_CORRECTION_VALUE(err_cor_info);
+-		err_device = ECC_ERR_DEVICE(err_cor_info);
+-
+-		/* reset the bitflip counter when crossing ECC sector */
+-		if (err_sector != prev_sector)
+-			bitflips = 0;
+-
+-		if (ECC_ERROR_UNCORRECTABLE(err_cor_info)) {
+-			/*
+-			 * Check later if this is a real ECC error, or
+-			 * an erased sector.
+-			 */
+-			*uncor_ecc_flags |= BIT(err_sector);
+-		} else if (err_byte < ecc_size) {
+-			/*
+-			 * If err_byte is larger than ecc_size, means error
+-			 * happened in OOB, so we ignore it. It's no need for
+-			 * us to correct it err_device is represented the NAND
+-			 * error bits are happened in if there are more than
+-			 * one NAND connected.
+-			 */
+-			int offset;
+-			unsigned int flips_in_byte;
+-
+-			offset = (err_sector * ecc_size + err_byte) *
+-					denali->devs_per_cs + err_device;
+-
+-			/* correct the ECC error */
+-			flips_in_byte = hweight8(buf[offset] ^ err_cor_value);
+-			buf[offset] ^= err_cor_value;
+-			mtd->ecc_stats.corrected += flips_in_byte;
+-			bitflips += flips_in_byte;
+-
+-			max_bitflips = max(max_bitflips, bitflips);
+-		}
+-
+-		prev_sector = err_sector;
+-	} while (!ECC_LAST_ERR(err_cor_info));
+-
+-	/*
+-	 * Once handle all ecc errors, controller will trigger a
+-	 * ECC_TRANSACTION_DONE interrupt, so here just wait for
+-	 * a while for this interrupt
+-	 */
+-	irq_status = denali_wait_for_irq(denali, INTR__ECC_TRANSACTION_DONE);
+-	if (!(irq_status & INTR__ECC_TRANSACTION_DONE))
+-		return -EIO;
+-
+-	return max_bitflips;
+-}
+-
+-/* programs the controller to either enable/disable DMA transfers */
+-static void denali_enable_dma(struct denali_nand_info *denali, bool en)
+-{
+-	iowrite32(en ? DMA_ENABLE__FLAG : 0, denali->reg + DMA_ENABLE);
+-	ioread32(denali->reg + DMA_ENABLE);
+-}
+-
+-static void denali_setup_dma64(struct denali_nand_info *denali,
+-			       dma_addr_t dma_addr, int page, int write)
+-{
+-	uint32_t mode;
+-	const int page_count = 1;
+-
+-	mode = DENALI_MAP10 | DENALI_BANK(denali) | page;
+-
+-	/* DMA is a three step process */
+-
+-	/*
+-	 * 1. setup transfer type, interrupt when complete,
+-	 *    burst len = 64 bytes, the number of pages
+-	 */
+-	denali_host_write(denali, mode,
+-			  0x01002000 | (64 << 16) | (write << 8) | page_count);
+-
+-	/* 2. set memory low address */
+-	denali_host_write(denali, mode, dma_addr);
+-
+-	/* 3. set memory high address */
+-	denali_host_write(denali, mode, (uint64_t)dma_addr >> 32);
+-}
+-
+-static void denali_setup_dma32(struct denali_nand_info *denali,
+-			       dma_addr_t dma_addr, int page, int write)
+-{
+-	uint32_t mode;
+-	const int page_count = 1;
+-
+-	mode = DENALI_MAP10 | DENALI_BANK(denali);
+-
+-	/* DMA is a four step process */
+-
+-	/* 1. setup transfer type and # of pages */
+-	denali_host_write(denali, mode | page,
+-			  0x2000 | (write << 8) | page_count);
+-
+-	/* 2. set memory high address bits 23:8 */
+-	denali_host_write(denali, mode | ((dma_addr >> 16) << 8), 0x2200);
+-
+-	/* 3. set memory low address bits 23:8 */
+-	denali_host_write(denali, mode | ((dma_addr & 0xffff) << 8), 0x2300);
+-
+-	/* 4. interrupt when complete, burst len = 64 bytes */
+-	denali_host_write(denali, mode | 0x14000, 0x2400);
+-}
+-
+-static void denali_setup_dma(struct denali_nand_info *denali,
+-			     dma_addr_t dma_addr, int page, int write)
+-{
+-	if (denali->caps & DENALI_CAP_DMA_64BIT)
+-		denali_setup_dma64(denali, dma_addr, page, write);
+-	else
+-		denali_setup_dma32(denali, dma_addr, page, write);
+-}
+-
+-static int denali_pio_read(struct denali_nand_info *denali, void *buf,
+-			   size_t size, int page, int raw)
+-{
+-	uint32_t addr = DENALI_BANK(denali) | page;
+-	uint32_t *buf32 = (uint32_t *)buf;
+-	uint32_t irq_status, ecc_err_mask;
+-	int i;
+-
+-	if (denali->caps & DENALI_CAP_HW_ECC_FIXUP)
+-		ecc_err_mask = INTR__ECC_UNCOR_ERR;
+-	else
+-		ecc_err_mask = INTR__ECC_ERR;
+-
+-	denali_reset_irq(denali);
+-
+-	iowrite32(DENALI_MAP01 | addr, denali->host + DENALI_HOST_ADDR);
+-	for (i = 0; i < size / 4; i++)
+-		*buf32++ = ioread32(denali->host + DENALI_HOST_DATA);
+-
+-	irq_status = denali_wait_for_irq(denali, INTR__PAGE_XFER_INC);
+-	if (!(irq_status & INTR__PAGE_XFER_INC))
+-		return -EIO;
+-
+-	if (irq_status & INTR__ERASED_PAGE)
+-		memset(buf, 0xff, size);
+-
+-	return irq_status & ecc_err_mask ? -EBADMSG : 0;
+-}
+-
+-static int denali_pio_write(struct denali_nand_info *denali,
+-			    const void *buf, size_t size, int page, int raw)
+-{
+-	uint32_t addr = DENALI_BANK(denali) | page;
+-	const uint32_t *buf32 = (uint32_t *)buf;
+-	uint32_t irq_status;
+-	int i;
+-
+-	denali_reset_irq(denali);
+-
+-	iowrite32(DENALI_MAP01 | addr, denali->host + DENALI_HOST_ADDR);
+-	for (i = 0; i < size / 4; i++)
+-		iowrite32(*buf32++, denali->host + DENALI_HOST_DATA);
+-
+-	irq_status = denali_wait_for_irq(denali,
+-				INTR__PROGRAM_COMP | INTR__PROGRAM_FAIL);
+-	if (!(irq_status & INTR__PROGRAM_COMP))
+-		return -EIO;
+-
+-	return 0;
+-}
+-
+-static int denali_pio_xfer(struct denali_nand_info *denali, void *buf,
+-			   size_t size, int page, int raw, int write)
+-{
+-	if (write)
+-		return denali_pio_write(denali, buf, size, page, raw);
+-	else
+-		return denali_pio_read(denali, buf, size, page, raw);
+-}
+-
+-static int denali_dma_xfer(struct denali_nand_info *denali, void *buf,
+-			   size_t size, int page, int raw, int write)
+-{
+-	dma_addr_t dma_addr;
+-	uint32_t irq_mask, irq_status, ecc_err_mask;
+-	enum dma_data_direction dir = write ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
+-	int ret = 0;
+-
+-	dma_addr = dma_map_single(denali->dev, buf, size, dir);
+-	if (dma_mapping_error(denali->dev, dma_addr)) {
+-		dev_dbg(denali->dev, "Failed to DMA-map buffer. Trying PIO.\n");
+-		return denali_pio_xfer(denali, buf, size, page, raw, write);
+-	}
+-
+-	if (write) {
+-		/*
+-		 * INTR__PROGRAM_COMP is never asserted for the DMA transfer.
+-		 * We can use INTR__DMA_CMD_COMP instead.  This flag is asserted
+-		 * when the page program is completed.
+-		 */
+-		irq_mask = INTR__DMA_CMD_COMP | INTR__PROGRAM_FAIL;
+-		ecc_err_mask = 0;
+-	} else if (denali->caps & DENALI_CAP_HW_ECC_FIXUP) {
+-		irq_mask = INTR__DMA_CMD_COMP;
+-		ecc_err_mask = INTR__ECC_UNCOR_ERR;
+-	} else {
+-		irq_mask = INTR__DMA_CMD_COMP;
+-		ecc_err_mask = INTR__ECC_ERR;
+-	}
+-
+-	denali_enable_dma(denali, true);
+-
+-	denali_reset_irq(denali);
+-	denali_setup_dma(denali, dma_addr, page, write);
+-
+-	/* wait for operation to complete */
+-	irq_status = denali_wait_for_irq(denali, irq_mask);
+-	if (!(irq_status & INTR__DMA_CMD_COMP))
+-		ret = -EIO;
+-	else if (irq_status & ecc_err_mask)
+-		ret = -EBADMSG;
+-
+-	denali_enable_dma(denali, false);
+-	dma_unmap_single(denali->dev, dma_addr, size, dir);
+-
+-	if (irq_status & INTR__ERASED_PAGE)
+-		memset(buf, 0xff, size);
+-
+-	return ret;
+-}
+-
+-static int denali_data_xfer(struct denali_nand_info *denali, void *buf,
+-			    size_t size, int page, int raw, int write)
+-{
+-	setup_ecc_for_xfer(denali, !raw, raw);
+-
+-	if (denali->dma_avail)
+-		return denali_dma_xfer(denali, buf, size, page, raw, write);
+-	else
+-		return denali_pio_xfer(denali, buf, size, page, raw, write);
+-}
+-
+-static void denali_oob_xfer(struct mtd_info *mtd, struct nand_chip *chip,
+-			    int page, int write)
+-{
+-	struct denali_nand_info *denali = mtd_to_denali(mtd);
+-	unsigned int start_cmd = write ? NAND_CMD_SEQIN : NAND_CMD_READ0;
+-	unsigned int rnd_cmd = write ? NAND_CMD_RNDIN : NAND_CMD_RNDOUT;
+-	int writesize = mtd->writesize;
+-	int oobsize = mtd->oobsize;
+-	uint8_t *bufpoi = chip->oob_poi;
+-	int ecc_steps = chip->ecc.steps;
+-	int ecc_size = chip->ecc.size;
+-	int ecc_bytes = chip->ecc.bytes;
+-	int oob_skip = denali->oob_skip_bytes;
+-	size_t size = writesize + oobsize;
+-	int i, pos, len;
+-
+-	/* BBM at the beginning of the OOB area */
+-	chip->cmdfunc(mtd, start_cmd, writesize, page);
+-	if (write)
+-		chip->write_buf(mtd, bufpoi, oob_skip);
+-	else
+-		chip->read_buf(mtd, bufpoi, oob_skip);
+-	bufpoi += oob_skip;
+-
+-	/* OOB ECC */
+-	for (i = 0; i < ecc_steps; i++) {
+-		pos = ecc_size + i * (ecc_size + ecc_bytes);
+-		len = ecc_bytes;
+-
+-		if (pos >= writesize)
+-			pos += oob_skip;
+-		else if (pos + len > writesize)
+-			len = writesize - pos;
+-
+-		chip->cmdfunc(mtd, rnd_cmd, pos, -1);
+-		if (write)
+-			chip->write_buf(mtd, bufpoi, len);
+-		else
+-			chip->read_buf(mtd, bufpoi, len);
+-		bufpoi += len;
+-		if (len < ecc_bytes) {
+-			len = ecc_bytes - len;
+-			chip->cmdfunc(mtd, rnd_cmd, writesize + oob_skip, -1);
+-			if (write)
+-				chip->write_buf(mtd, bufpoi, len);
+-			else
+-				chip->read_buf(mtd, bufpoi, len);
+-			bufpoi += len;
+-		}
+-	}
+-
+-	/* OOB free */
+-	len = oobsize - (bufpoi - chip->oob_poi);
+-	chip->cmdfunc(mtd, rnd_cmd, size - len, -1);
+-	if (write)
+-		chip->write_buf(mtd, bufpoi, len);
+-	else
+-		chip->read_buf(mtd, bufpoi, len);
+-}
+-
+-static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+-				uint8_t *buf, int oob_required, int page)
+-{
+-	struct denali_nand_info *denali = mtd_to_denali(mtd);
+-	int writesize = mtd->writesize;
+-	int oobsize = mtd->oobsize;
+-	int ecc_steps = chip->ecc.steps;
+-	int ecc_size = chip->ecc.size;
+-	int ecc_bytes = chip->ecc.bytes;
+-	void *dma_buf = denali->buf;
+-	int oob_skip = denali->oob_skip_bytes;
+-	size_t size = writesize + oobsize;
+-	int ret, i, pos, len;
+-
+-	ret = denali_data_xfer(denali, dma_buf, size, page, 1, 0);
+-	if (ret)
+-		return ret;
+-
+-	/* Arrange the buffer for syndrome payload/ecc layout */
+-	if (buf) {
+-		for (i = 0; i < ecc_steps; i++) {
+-			pos = i * (ecc_size + ecc_bytes);
+-			len = ecc_size;
+-
+-			if (pos >= writesize)
+-				pos += oob_skip;
+-			else if (pos + len > writesize)
+-				len = writesize - pos;
+-
+-			memcpy(buf, dma_buf + pos, len);
+-			buf += len;
+-			if (len < ecc_size) {
+-				len = ecc_size - len;
+-				memcpy(buf, dma_buf + writesize + oob_skip,
+-				       len);
+-				buf += len;
+-			}
+-		}
+-	}
+-
+-	if (oob_required) {
+-		uint8_t *oob = chip->oob_poi;
+-
+-		/* BBM at the beginning of the OOB area */
+-		memcpy(oob, dma_buf + writesize, oob_skip);
+-		oob += oob_skip;
+-
+-		/* OOB ECC */
+-		for (i = 0; i < ecc_steps; i++) {
+-			pos = ecc_size + i * (ecc_size + ecc_bytes);
+-			len = ecc_bytes;
+-
+-			if (pos >= writesize)
+-				pos += oob_skip;
+-			else if (pos + len > writesize)
+-				len = writesize - pos;
+-
+-			memcpy(oob, dma_buf + pos, len);
+-			oob += len;
+-			if (len < ecc_bytes) {
+-				len = ecc_bytes - len;
+-				memcpy(oob, dma_buf + writesize + oob_skip,
+-				       len);
+-				oob += len;
+-			}
+-		}
+-
+-		/* OOB free */
+-		len = oobsize - (oob - chip->oob_poi);
+-		memcpy(oob, dma_buf + size - len, len);
+-	}
+-
+-	return 0;
+-}
+-
+-static int denali_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
+-			   int page)
+-{
+-	denali_oob_xfer(mtd, chip, page, 0);
+-
+-	return 0;
+-}
+-
+-static int denali_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
+-			    int page)
+-{
+-	struct denali_nand_info *denali = mtd_to_denali(mtd);
+-	int status;
+-
+-	denali_reset_irq(denali);
+-
+-	denali_oob_xfer(mtd, chip, page, 1);
+-
+-	chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+-	status = chip->waitfunc(mtd, chip);
+-
+-	return status & NAND_STATUS_FAIL ? -EIO : 0;
+-}
+-
+-static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
+-			    uint8_t *buf, int oob_required, int page)
+-{
+-	struct denali_nand_info *denali = mtd_to_denali(mtd);
+-	unsigned long uncor_ecc_flags = 0;
+-	int stat = 0;
+-	int ret;
+-
+-	ret = denali_data_xfer(denali, buf, mtd->writesize, page, 0, 0);
+-	if (ret && ret != -EBADMSG)
+-		return ret;
+-
+-	if (denali->caps & DENALI_CAP_HW_ECC_FIXUP)
+-		stat = denali_hw_ecc_fixup(mtd, denali, &uncor_ecc_flags);
+-	else if (ret == -EBADMSG)
+-		stat = denali_sw_ecc_fixup(mtd, denali, &uncor_ecc_flags, buf);
+-
+-	if (stat < 0)
+-		return stat;
+-
+-	if (uncor_ecc_flags) {
+-		ret = denali_read_oob(mtd, chip, page);
+-		if (ret)
+-			return ret;
+-
+-		stat = denali_check_erased_page(mtd, chip, buf,
+-						uncor_ecc_flags, stat);
+-	}
+-
+-	return stat;
+-}
+-
+-static int denali_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+-				 const uint8_t *buf, int oob_required, int page)
+-{
+-	struct denali_nand_info *denali = mtd_to_denali(mtd);
+-	int writesize = mtd->writesize;
+-	int oobsize = mtd->oobsize;
+-	int ecc_steps = chip->ecc.steps;
+-	int ecc_size = chip->ecc.size;
+-	int ecc_bytes = chip->ecc.bytes;
+-	void *dma_buf = denali->buf;
+-	int oob_skip = denali->oob_skip_bytes;
+-	size_t size = writesize + oobsize;
+-	int i, pos, len;
+-
+-	/*
+-	 * Fill the buffer with 0xff first except the full page transfer.
+-	 * This simplifies the logic.
+-	 */
+-	if (!buf || !oob_required)
+-		memset(dma_buf, 0xff, size);
+-
+-	/* Arrange the buffer for syndrome payload/ecc layout */
+-	if (buf) {
+-		for (i = 0; i < ecc_steps; i++) {
+-			pos = i * (ecc_size + ecc_bytes);
+-			len = ecc_size;
+-
+-			if (pos >= writesize)
+-				pos += oob_skip;
+-			else if (pos + len > writesize)
+-				len = writesize - pos;
+-
+-			memcpy(dma_buf + pos, buf, len);
+-			buf += len;
+-			if (len < ecc_size) {
+-				len = ecc_size - len;
+-				memcpy(dma_buf + writesize + oob_skip, buf,
+-				       len);
+-				buf += len;
+-			}
+-		}
+-	}
+-
+-	if (oob_required) {
+-		const uint8_t *oob = chip->oob_poi;
+-
+-		/* BBM at the beginning of the OOB area */
+-		memcpy(dma_buf + writesize, oob, oob_skip);
+-		oob += oob_skip;
+-
+-		/* OOB ECC */
+-		for (i = 0; i < ecc_steps; i++) {
+-			pos = ecc_size + i * (ecc_size + ecc_bytes);
+-			len = ecc_bytes;
+-
+-			if (pos >= writesize)
+-				pos += oob_skip;
+-			else if (pos + len > writesize)
+-				len = writesize - pos;
+-
+-			memcpy(dma_buf + pos, oob, len);
+-			oob += len;
+-			if (len < ecc_bytes) {
+-				len = ecc_bytes - len;
+-				memcpy(dma_buf + writesize + oob_skip, oob,
+-				       len);
+-				oob += len;
+-			}
+-		}
+-
+-		/* OOB free */
+-		len = oobsize - (oob - chip->oob_poi);
+-		memcpy(dma_buf + size - len, oob, len);
+-	}
+-
+-	return denali_data_xfer(denali, dma_buf, size, page, 1, 1);
+-}
+-
+-static int denali_write_page(struct mtd_info *mtd, struct nand_chip *chip,
+-			     const uint8_t *buf, int oob_required, int page)
+-{
+-	struct denali_nand_info *denali = mtd_to_denali(mtd);
+-
+-	return denali_data_xfer(denali, (void *)buf, mtd->writesize,
+-				page, 0, 1);
+-}
+-
+-static void denali_select_chip(struct mtd_info *mtd, int chip)
+-{
+-	struct denali_nand_info *denali = mtd_to_denali(mtd);
+-
+-	denali->active_bank = chip;
+-}
+-
+-static int denali_waitfunc(struct mtd_info *mtd, struct nand_chip *chip)
+-{
+-	struct denali_nand_info *denali = mtd_to_denali(mtd);
+-	uint32_t irq_status;
+-
+-	/* R/B# pin transitioned from low to high? */
+-	irq_status = denali_wait_for_irq(denali, INTR__INT_ACT);
+-
+-	return irq_status & INTR__INT_ACT ? 0 : NAND_STATUS_FAIL;
+-}
+-
+-static int denali_erase(struct mtd_info *mtd, int page)
+-{
+-	struct denali_nand_info *denali = mtd_to_denali(mtd);
+-	uint32_t irq_status;
+-
+-	denali_reset_irq(denali);
+-
+-	denali_host_write(denali, DENALI_MAP10 | DENALI_BANK(denali) | page,
+-			  DENALI_ERASE);
+-
+-	/* wait for erase to complete or failure to occur */
+-	irq_status = denali_wait_for_irq(denali,
+-					 INTR__ERASE_COMP | INTR__ERASE_FAIL);
+-
+-	return irq_status & INTR__ERASE_COMP ? 0 : NAND_STATUS_FAIL;
+-}
+-
+-static int denali_setup_data_interface(struct mtd_info *mtd, int chipnr,
+-				       const struct nand_data_interface *conf)
+-{
+-	struct denali_nand_info *denali = mtd_to_denali(mtd);
+-	const struct nand_sdr_timings *timings;
+-	unsigned long t_clk;
+-	int acc_clks, re_2_we, re_2_re, we_2_re, addr_2_data;
+-	int rdwr_en_lo, rdwr_en_hi, rdwr_en_lo_hi, cs_setup;
+-	int addr_2_data_mask;
+-	uint32_t tmp;
+-
+-	timings = nand_get_sdr_timings(conf);
+-	if (IS_ERR(timings))
+-		return PTR_ERR(timings);
+-
+-	/* clk_x period in picoseconds */
+-	t_clk = DIV_ROUND_DOWN_ULL(1000000000000ULL, denali->clk_x_rate);
+-	if (!t_clk)
+-		return -EINVAL;
+-
+-	if (chipnr == NAND_DATA_IFACE_CHECK_ONLY)
+-		return 0;
+-
+-	/* tREA -> ACC_CLKS */
+-	acc_clks = DIV_ROUND_UP(timings->tREA_max, t_clk);
+-	acc_clks = min_t(int, acc_clks, ACC_CLKS__VALUE);
+-
+-	tmp = ioread32(denali->reg + ACC_CLKS);
+-	tmp &= ~ACC_CLKS__VALUE;
+-	tmp |= acc_clks;
+-	iowrite32(tmp, denali->reg + ACC_CLKS);
+-
+-	/* tRWH -> RE_2_WE */
+-	re_2_we = DIV_ROUND_UP(timings->tRHW_min, t_clk);
+-	re_2_we = min_t(int, re_2_we, RE_2_WE__VALUE);
+-
+-	tmp = ioread32(denali->reg + RE_2_WE);
+-	tmp &= ~RE_2_WE__VALUE;
+-	tmp |= re_2_we;
+-	iowrite32(tmp, denali->reg + RE_2_WE);
+-
+-	/* tRHZ -> RE_2_RE */
+-	re_2_re = DIV_ROUND_UP(timings->tRHZ_max, t_clk);
+-	re_2_re = min_t(int, re_2_re, RE_2_RE__VALUE);
+-
+-	tmp = ioread32(denali->reg + RE_2_RE);
+-	tmp &= ~RE_2_RE__VALUE;
+-	tmp |= re_2_re;
+-	iowrite32(tmp, denali->reg + RE_2_RE);
+-
+-	/* tWHR -> WE_2_RE */
+-	we_2_re = DIV_ROUND_UP(timings->tWHR_min, t_clk);
+-	we_2_re = min_t(int, we_2_re, TWHR2_AND_WE_2_RE__WE_2_RE);
+-
+-	tmp = ioread32(denali->reg + TWHR2_AND_WE_2_RE);
+-	tmp &= ~TWHR2_AND_WE_2_RE__WE_2_RE;
+-	tmp |= we_2_re;
+-	iowrite32(tmp, denali->reg + TWHR2_AND_WE_2_RE);
+-
+-	/* tADL -> ADDR_2_DATA */
+-
+-	/* for older versions, ADDR_2_DATA is only 6 bit wide */
+-	addr_2_data_mask = TCWAW_AND_ADDR_2_DATA__ADDR_2_DATA;
+-	if (denali->revision < 0x0501)
+-		addr_2_data_mask >>= 1;
+-
+-	addr_2_data = DIV_ROUND_UP(timings->tADL_min, t_clk);
+-	addr_2_data = min_t(int, addr_2_data, addr_2_data_mask);
+-
+-	tmp = ioread32(denali->reg + TCWAW_AND_ADDR_2_DATA);
+-	tmp &= ~addr_2_data_mask;
+-	tmp |= addr_2_data;
+-	iowrite32(tmp, denali->reg + TCWAW_AND_ADDR_2_DATA);
+-
+-	/* tREH, tWH -> RDWR_EN_HI_CNT */
+-	rdwr_en_hi = DIV_ROUND_UP(max(timings->tREH_min, timings->tWH_min),
+-				  t_clk);
+-	rdwr_en_hi = min_t(int, rdwr_en_hi, RDWR_EN_HI_CNT__VALUE);
+-
+-	tmp = ioread32(denali->reg + RDWR_EN_HI_CNT);
+-	tmp &= ~RDWR_EN_HI_CNT__VALUE;
+-	tmp |= rdwr_en_hi;
+-	iowrite32(tmp, denali->reg + RDWR_EN_HI_CNT);
+-
+-	/* tRP, tWP -> RDWR_EN_LO_CNT */
+-	rdwr_en_lo = DIV_ROUND_UP(max(timings->tRP_min, timings->tWP_min),
+-				  t_clk);
+-	rdwr_en_lo_hi = DIV_ROUND_UP(max(timings->tRC_min, timings->tWC_min),
+-				     t_clk);
+-	rdwr_en_lo_hi = max(rdwr_en_lo_hi, DENALI_CLK_X_MULT);
+-	rdwr_en_lo = max(rdwr_en_lo, rdwr_en_lo_hi - rdwr_en_hi);
+-	rdwr_en_lo = min_t(int, rdwr_en_lo, RDWR_EN_LO_CNT__VALUE);
+-
+-	tmp = ioread32(denali->reg + RDWR_EN_LO_CNT);
+-	tmp &= ~RDWR_EN_LO_CNT__VALUE;
+-	tmp |= rdwr_en_lo;
+-	iowrite32(tmp, denali->reg + RDWR_EN_LO_CNT);
+-
+-	/* tCS, tCEA -> CS_SETUP_CNT */
+-	cs_setup = max3((int)DIV_ROUND_UP(timings->tCS_min, t_clk) - rdwr_en_lo,
+-			(int)DIV_ROUND_UP(timings->tCEA_max, t_clk) - acc_clks,
+-			0);
+-	cs_setup = min_t(int, cs_setup, CS_SETUP_CNT__VALUE);
+-
+-	tmp = ioread32(denali->reg + CS_SETUP_CNT);
+-	tmp &= ~CS_SETUP_CNT__VALUE;
+-	tmp |= cs_setup;
+-	iowrite32(tmp, denali->reg + CS_SETUP_CNT);
+-
+-	return 0;
+-}
+-
+-static void denali_reset_banks(struct denali_nand_info *denali)
+-{
+-	u32 irq_status;
+-	int i;
+-
+-	for (i = 0; i < denali->max_banks; i++) {
+-		denali->active_bank = i;
+-
+-		denali_reset_irq(denali);
+-
+-		iowrite32(DEVICE_RESET__BANK(i),
+-			  denali->reg + DEVICE_RESET);
+-
+-		irq_status = denali_wait_for_irq(denali,
+-			INTR__RST_COMP | INTR__INT_ACT | INTR__TIME_OUT);
+-		if (!(irq_status & INTR__INT_ACT))
+-			break;
+-	}
+-
+-	dev_dbg(denali->dev, "%d chips connected\n", i);
+-	denali->max_banks = i;
+-}
+-
+-static void denali_hw_init(struct denali_nand_info *denali)
+-{
+-	/*
+-	 * The REVISION register may not be reliable.  Platforms are allowed to
+-	 * override it.
+-	 */
+-	if (!denali->revision)
+-		denali->revision = swab16(ioread32(denali->reg + REVISION));
+-
+-	/*
+-	 * tell driver how many bit controller will skip before
+-	 * writing ECC code in OOB, this register may be already
+-	 * set by firmware. So we read this value out.
+-	 * if this value is 0, just let it be.
+-	 */
+-	denali->oob_skip_bytes = ioread32(denali->reg + SPARE_AREA_SKIP_BYTES);
+-	detect_max_banks(denali);
+-	iowrite32(0x0F, denali->reg + RB_PIN_ENABLED);
+-	iowrite32(CHIP_EN_DONT_CARE__FLAG, denali->reg + CHIP_ENABLE_DONT_CARE);
+-
+-	iowrite32(0xffff, denali->reg + SPARE_AREA_MARKER);
+-
+-	/* Should set value for these registers when init */
+-	iowrite32(0, denali->reg + TWO_ROW_ADDR_CYCLES);
+-	iowrite32(1, denali->reg + ECC_ENABLE);
+-}
+-
+-int denali_calc_ecc_bytes(int step_size, int strength)
+-{
+-	/* BCH code.  Denali requires ecc.bytes to be multiple of 2 */
+-	return DIV_ROUND_UP(strength * fls(step_size * 8), 16) * 2;
+-}
+-EXPORT_SYMBOL(denali_calc_ecc_bytes);
+-
+-static int denali_ecc_setup(struct mtd_info *mtd, struct nand_chip *chip,
+-			    struct denali_nand_info *denali)
+-{
+-	int oobavail = mtd->oobsize - denali->oob_skip_bytes;
+-	int ret;
+-
+-	/*
+-	 * If .size and .strength are already set (usually by DT),
+-	 * check if they are supported by this controller.
+-	 */
+-	if (chip->ecc.size && chip->ecc.strength)
+-		return nand_check_ecc_caps(chip, denali->ecc_caps, oobavail);
+-
+-	/*
+-	 * We want .size and .strength closest to the chip's requirement
+-	 * unless NAND_ECC_MAXIMIZE is requested.
+-	 */
+-	if (!(chip->ecc.options & NAND_ECC_MAXIMIZE)) {
+-		ret = nand_match_ecc_req(chip, denali->ecc_caps, oobavail);
+-		if (!ret)
+-			return 0;
+-	}
+-
+-	/* Max ECC strength is the last thing we can do */
+-	return nand_maximize_ecc(chip, denali->ecc_caps, oobavail);
+-}
+-
+-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);
+-
+-	if (section)
+-		return -ERANGE;
+-
+-	oobregion->offset = denali->oob_skip_bytes;
+-	oobregion->length = chip->ecc.total;
+-
+-	return 0;
+-}
+-
+-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);
+-
+-	if (section)
+-		return -ERANGE;
+-
+-	oobregion->offset = chip->ecc.total + denali->oob_skip_bytes;
+-	oobregion->length = mtd->oobsize - oobregion->offset;
+-
+-	return 0;
+-}
+-
+-static const struct mtd_ooblayout_ops denali_ooblayout_ops = {
+-	.ecc = denali_ooblayout_ecc,
+-	.free = denali_ooblayout_free,
+-};
+-
+-/* initialize driver data structures */
+-static void denali_drv_init(struct denali_nand_info *denali)
+-{
+-	/*
+-	 * the completion object will be used to notify
+-	 * the callee that the interrupt is done
+-	 */
+-	init_completion(&denali->complete);
+-
+-	/*
+-	 * the spinlock will be used to synchronize the ISR with any
+-	 * element that might be access shared data (interrupt status)
+-	 */
+-	spin_lock_init(&denali->irq_lock);
+-}
+-
+-static int denali_multidev_fixup(struct denali_nand_info *denali)
+-{
+-	struct nand_chip *chip = &denali->nand;
+-	struct mtd_info *mtd = nand_to_mtd(chip);
+-
+-	/*
+-	 * Support for multi device:
+-	 * When the IP configuration is x16 capable and two x8 chips are
+-	 * connected in parallel, DEVICES_CONNECTED should be set to 2.
+-	 * In this case, the core framework knows nothing about this fact,
+-	 * so we should tell it the _logical_ pagesize and anything necessary.
+-	 */
+-	denali->devs_per_cs = ioread32(denali->reg + DEVICES_CONNECTED);
+-
+-	/*
+-	 * On some SoCs, DEVICES_CONNECTED is not auto-detected.
+-	 * For those, DEVICES_CONNECTED is left to 0.  Set 1 if it is the case.
+-	 */
+-	if (denali->devs_per_cs == 0) {
+-		denali->devs_per_cs = 1;
+-		iowrite32(1, denali->reg + DEVICES_CONNECTED);
+-	}
+-
+-	if (denali->devs_per_cs == 1)
+-		return 0;
+-
+-	if (denali->devs_per_cs != 2) {
+-		dev_err(denali->dev, "unsupported number of devices %d\n",
+-			denali->devs_per_cs);
+-		return -EINVAL;
+-	}
+-
+-	/* 2 chips in parallel */
+-	mtd->size <<= 1;
+-	mtd->erasesize <<= 1;
+-	mtd->writesize <<= 1;
+-	mtd->oobsize <<= 1;
+-	chip->chipsize <<= 1;
+-	chip->page_shift += 1;
+-	chip->phys_erase_shift += 1;
+-	chip->bbt_erase_shift += 1;
+-	chip->chip_shift += 1;
+-	chip->pagemask <<= 1;
+-	chip->ecc.size <<= 1;
+-	chip->ecc.bytes <<= 1;
+-	chip->ecc.strength <<= 1;
+-	denali->oob_skip_bytes <<= 1;
+-
+-	return 0;
+-}
+-
+-int denali_init(struct denali_nand_info *denali)
+-{
+-	struct nand_chip *chip = &denali->nand;
+-	struct mtd_info *mtd = nand_to_mtd(chip);
+-	int ret;
+-
+-	mtd->dev.parent = denali->dev;
+-	denali_hw_init(denali);
+-	denali_drv_init(denali);
+-
+-	denali_clear_irq_all(denali);
+-
+-	/* Request IRQ after all the hardware initialization is finished */
+-	ret = devm_request_irq(denali->dev, denali->irq, denali_isr,
+-			       IRQF_SHARED, DENALI_NAND_NAME, denali);
+-	if (ret) {
+-		dev_err(denali->dev, "Unable to request IRQ\n");
+-		return ret;
+-	}
+-
+-	denali_enable_irq(denali);
+-	denali_reset_banks(denali);
+-
+-	denali->active_bank = DENALI_INVALID_BANK;
+-
+-	nand_set_flash_node(chip, denali->dev->of_node);
+-	/* Fallback to the default name if DT did not give "label" property */
+-	if (!mtd->name)
+-		mtd->name = "denali-nand";
+-
+-	/* register the driver with the NAND core subsystem */
+-	chip->select_chip = denali_select_chip;
+-	chip->read_byte = denali_read_byte;
+-	chip->write_byte = denali_write_byte;
+-	chip->read_word = denali_read_word;
+-	chip->cmd_ctrl = denali_cmd_ctrl;
+-	chip->dev_ready = denali_dev_ready;
+-	chip->waitfunc = denali_waitfunc;
+-
+-	/* clk rate info is needed for setup_data_interface */
+-	if (denali->clk_x_rate)
+-		chip->setup_data_interface = denali_setup_data_interface;
+-
+-	/*
+-	 * scan for NAND devices attached to the controller
+-	 * this is the first stage in a two step process to register
+-	 * with the nand subsystem
+-	 */
+-	ret = nand_scan_ident(mtd, denali->max_banks, NULL);
+-	if (ret)
+-		goto disable_irq;
+-
+-	if (ioread32(denali->reg + FEATURES) & FEATURES__DMA)
+-		denali->dma_avail = 1;
+-
+-	if (denali->dma_avail) {
+-		int dma_bit = denali->caps & DENALI_CAP_DMA_64BIT ? 64 : 32;
+-
+-		ret = dma_set_mask(denali->dev, DMA_BIT_MASK(dma_bit));
+-		if (ret) {
+-			dev_info(denali->dev,
+-				 "Failed to set DMA mask. Disabling DMA.\n");
+-			denali->dma_avail = 0;
+-		}
+-	}
+-
+-	if (denali->dma_avail) {
+-		chip->options |= NAND_USE_BOUNCE_BUFFER;
+-		chip->buf_align = 16;
+-	}
+-
+-	/*
+-	 * second stage of the NAND scan
+-	 * this stage requires information regarding ECC and
+-	 * bad block management.
+-	 */
+-
+-	chip->bbt_options |= NAND_BBT_USE_FLASH;
+-	chip->bbt_options |= NAND_BBT_NO_OOB;
+-
+-	chip->ecc.mode = NAND_ECC_HW_SYNDROME;
+-
+-	/* no subpage writes on denali */
+-	chip->options |= NAND_NO_SUBPAGE_WRITE;
+-
+-	ret = denali_ecc_setup(mtd, chip, denali);
+-	if (ret) {
+-		dev_err(denali->dev, "Failed to setup ECC settings.\n");
+-		goto disable_irq;
+-	}
+-
+-	dev_dbg(denali->dev,
+-		"chosen ECC settings: step=%d, strength=%d, bytes=%d\n",
+-		chip->ecc.size, chip->ecc.strength, chip->ecc.bytes);
+-
+-	iowrite32(MAKE_ECC_CORRECTION(chip->ecc.strength, 1),
+-		  denali->reg + ECC_CORRECTION);
+-	iowrite32(mtd->erasesize / mtd->writesize,
+-		  denali->reg + PAGES_PER_BLOCK);
+-	iowrite32(chip->options & NAND_BUSWIDTH_16 ? 1 : 0,
+-		  denali->reg + DEVICE_WIDTH);
+-	iowrite32(mtd->writesize, denali->reg + DEVICE_MAIN_AREA_SIZE);
+-	iowrite32(mtd->oobsize, denali->reg + DEVICE_SPARE_AREA_SIZE);
+-
+-	iowrite32(chip->ecc.size, denali->reg + CFG_DATA_BLOCK_SIZE);
+-	iowrite32(chip->ecc.size, denali->reg + CFG_LAST_DATA_BLOCK_SIZE);
+-	/* chip->ecc.steps is set by nand_scan_tail(); not available here */
+-	iowrite32(mtd->writesize / chip->ecc.size,
+-		  denali->reg + CFG_NUM_DATA_BLOCKS);
+-
+-	mtd_set_ooblayout(mtd, &denali_ooblayout_ops);
+-
+-	if (chip->options & NAND_BUSWIDTH_16) {
+-		chip->read_buf = denali_read_buf16;
+-		chip->write_buf = denali_write_buf16;
+-	} else {
+-		chip->read_buf = denali_read_buf;
+-		chip->write_buf = denali_write_buf;
+-	}
+-	chip->ecc.options |= NAND_ECC_CUSTOM_PAGE_ACCESS;
+-	chip->ecc.read_page = denali_read_page;
+-	chip->ecc.read_page_raw = denali_read_page_raw;
+-	chip->ecc.write_page = denali_write_page;
+-	chip->ecc.write_page_raw = denali_write_page_raw;
+-	chip->ecc.read_oob = denali_read_oob;
+-	chip->ecc.write_oob = denali_write_oob;
+-	chip->erase = denali_erase;
+-
+-	ret = denali_multidev_fixup(denali);
+-	if (ret)
+-		goto disable_irq;
+-
+-	/*
+-	 * This buffer is DMA-mapped by denali_{read,write}_page_raw.  Do not
+-	 * use devm_kmalloc() because the memory allocated by devm_ does not
+-	 * guarantee DMA-safe alignment.
+-	 */
+-	denali->buf = kmalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL);
+-	if (!denali->buf) {
+-		ret = -ENOMEM;
+-		goto disable_irq;
+-	}
+-
+-	ret = nand_scan_tail(mtd);
+-	if (ret)
+-		goto free_buf;
+-
+-	ret = mtd_device_register(mtd, NULL, 0);
+-	if (ret) {
+-		dev_err(denali->dev, "Failed to register MTD: %d\n", ret);
+-		goto free_buf;
+-	}
+-	return 0;
+-
+-free_buf:
+-	kfree(denali->buf);
+-disable_irq:
+-	denali_disable_irq(denali);
+-
+-	return ret;
+-}
+-EXPORT_SYMBOL(denali_init);
+-
+-/* driver exit point */
+-void denali_remove(struct denali_nand_info *denali)
+-{
+-	struct mtd_info *mtd = nand_to_mtd(&denali->nand);
+-
+-	nand_release(mtd);
+-	kfree(denali->buf);
+-	denali_disable_irq(denali);
+-}
+-EXPORT_SYMBOL(denali_remove);
+diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h
+deleted file mode 100644
+index 9239e67..0000000
+--- a/drivers/mtd/nand/denali.h
++++ /dev/null
+@@ -1,339 +0,0 @@
+-/*
+- * NAND Flash Controller Device Driver
+- * Copyright (c) 2009 - 2010, Intel Corporation and its suppliers.
+- *
+- * 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, write to the Free Software Foundation, Inc.,
+- * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+- *
+- */
+-
+-#ifndef __DENALI_H__
+-#define __DENALI_H__
+-
+-#include <linux/bitops.h>
+-#include <linux/mtd/rawnand.h>
+-
+-#define DEVICE_RESET				0x0
+-#define     DEVICE_RESET__BANK(bank)			BIT(bank)
+-
+-#define TRANSFER_SPARE_REG			0x10
+-#define     TRANSFER_SPARE_REG__FLAG			BIT(0)
+-
+-#define LOAD_WAIT_CNT				0x20
+-#define     LOAD_WAIT_CNT__VALUE			GENMASK(15, 0)
+-
+-#define PROGRAM_WAIT_CNT			0x30
+-#define     PROGRAM_WAIT_CNT__VALUE			GENMASK(15, 0)
+-
+-#define ERASE_WAIT_CNT				0x40
+-#define     ERASE_WAIT_CNT__VALUE			GENMASK(15, 0)
+-
+-#define INT_MON_CYCCNT				0x50
+-#define     INT_MON_CYCCNT__VALUE			GENMASK(15, 0)
+-
+-#define RB_PIN_ENABLED				0x60
+-#define     RB_PIN_ENABLED__BANK(bank)			BIT(bank)
+-
+-#define MULTIPLANE_OPERATION			0x70
+-#define     MULTIPLANE_OPERATION__FLAG			BIT(0)
+-
+-#define MULTIPLANE_READ_ENABLE			0x80
+-#define     MULTIPLANE_READ_ENABLE__FLAG		BIT(0)
+-
+-#define COPYBACK_DISABLE			0x90
+-#define     COPYBACK_DISABLE__FLAG			BIT(0)
+-
+-#define CACHE_WRITE_ENABLE			0xa0
+-#define     CACHE_WRITE_ENABLE__FLAG			BIT(0)
+-
+-#define CACHE_READ_ENABLE			0xb0
+-#define     CACHE_READ_ENABLE__FLAG			BIT(0)
+-
+-#define PREFETCH_MODE				0xc0
+-#define     PREFETCH_MODE__PREFETCH_EN			BIT(0)
+-#define     PREFETCH_MODE__PREFETCH_BURST_LENGTH	GENMASK(15, 4)
+-
+-#define CHIP_ENABLE_DONT_CARE			0xd0
+-#define     CHIP_EN_DONT_CARE__FLAG			BIT(0)
+-
+-#define ECC_ENABLE				0xe0
+-#define     ECC_ENABLE__FLAG				BIT(0)
+-
+-#define GLOBAL_INT_ENABLE			0xf0
+-#define     GLOBAL_INT_EN_FLAG				BIT(0)
+-
+-#define TWHR2_AND_WE_2_RE			0x100
+-#define     TWHR2_AND_WE_2_RE__WE_2_RE			GENMASK(5, 0)
+-#define     TWHR2_AND_WE_2_RE__TWHR2			GENMASK(13, 8)
+-
+-#define TCWAW_AND_ADDR_2_DATA			0x110
+-/* The width of ADDR_2_DATA is 6 bit for old IP, 7 bit for new IP */
+-#define     TCWAW_AND_ADDR_2_DATA__ADDR_2_DATA		GENMASK(6, 0)
+-#define     TCWAW_AND_ADDR_2_DATA__TCWAW		GENMASK(13, 8)
+-
+-#define RE_2_WE					0x120
+-#define     RE_2_WE__VALUE				GENMASK(5, 0)
+-
+-#define ACC_CLKS				0x130
+-#define     ACC_CLKS__VALUE				GENMASK(3, 0)
+-
+-#define NUMBER_OF_PLANES			0x140
+-#define     NUMBER_OF_PLANES__VALUE			GENMASK(2, 0)
+-
+-#define PAGES_PER_BLOCK				0x150
+-#define     PAGES_PER_BLOCK__VALUE			GENMASK(15, 0)
+-
+-#define DEVICE_WIDTH				0x160
+-#define     DEVICE_WIDTH__VALUE				GENMASK(1, 0)
+-
+-#define DEVICE_MAIN_AREA_SIZE			0x170
+-#define     DEVICE_MAIN_AREA_SIZE__VALUE		GENMASK(15, 0)
+-
+-#define DEVICE_SPARE_AREA_SIZE			0x180
+-#define     DEVICE_SPARE_AREA_SIZE__VALUE		GENMASK(15, 0)
+-
+-#define TWO_ROW_ADDR_CYCLES			0x190
+-#define     TWO_ROW_ADDR_CYCLES__FLAG			BIT(0)
+-
+-#define MULTIPLANE_ADDR_RESTRICT		0x1a0
+-#define     MULTIPLANE_ADDR_RESTRICT__FLAG		BIT(0)
+-
+-#define ECC_CORRECTION				0x1b0
+-#define     ECC_CORRECTION__VALUE			GENMASK(4, 0)
+-#define     ECC_CORRECTION__ERASE_THRESHOLD		GENMASK(31, 16)
+-#define     MAKE_ECC_CORRECTION(val, thresh)		\
+-			(((val) & (ECC_CORRECTION__VALUE)) | \
+-			(((thresh) << 16) & (ECC_CORRECTION__ERASE_THRESHOLD)))
+-
+-#define READ_MODE				0x1c0
+-#define     READ_MODE__VALUE				GENMASK(3, 0)
+-
+-#define WRITE_MODE				0x1d0
+-#define     WRITE_MODE__VALUE				GENMASK(3, 0)
+-
+-#define COPYBACK_MODE				0x1e0
+-#define     COPYBACK_MODE__VALUE			GENMASK(3, 0)
+-
+-#define RDWR_EN_LO_CNT				0x1f0
+-#define     RDWR_EN_LO_CNT__VALUE			GENMASK(4, 0)
+-
+-#define RDWR_EN_HI_CNT				0x200
+-#define     RDWR_EN_HI_CNT__VALUE			GENMASK(4, 0)
+-
+-#define MAX_RD_DELAY				0x210
+-#define     MAX_RD_DELAY__VALUE				GENMASK(3, 0)
+-
+-#define CS_SETUP_CNT				0x220
+-#define     CS_SETUP_CNT__VALUE				GENMASK(4, 0)
+-#define     CS_SETUP_CNT__TWB				GENMASK(17, 12)
+-
+-#define SPARE_AREA_SKIP_BYTES			0x230
+-#define     SPARE_AREA_SKIP_BYTES__VALUE		GENMASK(5, 0)
+-
+-#define SPARE_AREA_MARKER			0x240
+-#define     SPARE_AREA_MARKER__VALUE			GENMASK(15, 0)
+-
+-#define DEVICES_CONNECTED			0x250
+-#define     DEVICES_CONNECTED__VALUE			GENMASK(2, 0)
+-
+-#define DIE_MASK				0x260
+-#define     DIE_MASK__VALUE				GENMASK(7, 0)
+-
+-#define FIRST_BLOCK_OF_NEXT_PLANE		0x270
+-#define     FIRST_BLOCK_OF_NEXT_PLANE__VALUE		GENMASK(15, 0)
+-
+-#define WRITE_PROTECT				0x280
+-#define     WRITE_PROTECT__FLAG				BIT(0)
+-
+-#define RE_2_RE					0x290
+-#define     RE_2_RE__VALUE				GENMASK(5, 0)
+-
+-#define MANUFACTURER_ID				0x300
+-#define     MANUFACTURER_ID__VALUE			GENMASK(7, 0)
+-
+-#define DEVICE_ID				0x310
+-#define     DEVICE_ID__VALUE				GENMASK(7, 0)
+-
+-#define DEVICE_PARAM_0				0x320
+-#define     DEVICE_PARAM_0__VALUE			GENMASK(7, 0)
+-
+-#define DEVICE_PARAM_1				0x330
+-#define     DEVICE_PARAM_1__VALUE			GENMASK(7, 0)
+-
+-#define DEVICE_PARAM_2				0x340
+-#define     DEVICE_PARAM_2__VALUE			GENMASK(7, 0)
+-
+-#define LOGICAL_PAGE_DATA_SIZE			0x350
+-#define     LOGICAL_PAGE_DATA_SIZE__VALUE		GENMASK(15, 0)
+-
+-#define LOGICAL_PAGE_SPARE_SIZE			0x360
+-#define     LOGICAL_PAGE_SPARE_SIZE__VALUE		GENMASK(15, 0)
+-
+-#define REVISION				0x370
+-#define     REVISION__VALUE				GENMASK(15, 0)
+-
+-#define ONFI_DEVICE_FEATURES			0x380
+-#define     ONFI_DEVICE_FEATURES__VALUE			GENMASK(5, 0)
+-
+-#define ONFI_OPTIONAL_COMMANDS			0x390
+-#define     ONFI_OPTIONAL_COMMANDS__VALUE		GENMASK(5, 0)
+-
+-#define ONFI_TIMING_MODE			0x3a0
+-#define     ONFI_TIMING_MODE__VALUE			GENMASK(5, 0)
+-
+-#define ONFI_PGM_CACHE_TIMING_MODE		0x3b0
+-#define     ONFI_PGM_CACHE_TIMING_MODE__VALUE		GENMASK(5, 0)
+-
+-#define ONFI_DEVICE_NO_OF_LUNS			0x3c0
+-#define     ONFI_DEVICE_NO_OF_LUNS__NO_OF_LUNS		GENMASK(7, 0)
+-#define     ONFI_DEVICE_NO_OF_LUNS__ONFI_DEVICE		BIT(8)
+-
+-#define ONFI_DEVICE_NO_OF_BLOCKS_PER_LUN_L	0x3d0
+-#define     ONFI_DEVICE_NO_OF_BLOCKS_PER_LUN_L__VALUE	GENMASK(15, 0)
+-
+-#define ONFI_DEVICE_NO_OF_BLOCKS_PER_LUN_U	0x3e0
+-#define     ONFI_DEVICE_NO_OF_BLOCKS_PER_LUN_U__VALUE	GENMASK(15, 0)
+-
+-#define FEATURES				0x3f0
+-#define     FEATURES__N_BANKS				GENMASK(1, 0)
+-#define     FEATURES__ECC_MAX_ERR			GENMASK(5, 2)
+-#define     FEATURES__DMA				BIT(6)
+-#define     FEATURES__CMD_DMA				BIT(7)
+-#define     FEATURES__PARTITION				BIT(8)
+-#define     FEATURES__XDMA_SIDEBAND			BIT(9)
+-#define     FEATURES__GPREG				BIT(10)
+-#define     FEATURES__INDEX_ADDR			BIT(11)
+-
+-#define TRANSFER_MODE				0x400
+-#define     TRANSFER_MODE__VALUE			GENMASK(1, 0)
+-
+-#define INTR_STATUS(bank)			(0x410 + (bank) * 0x50)
+-#define INTR_EN(bank)				(0x420 + (bank) * 0x50)
+-/* bit[1:0] is used differently depending on IP version */
+-#define     INTR__ECC_UNCOR_ERR				BIT(0)	/* new IP */
+-#define     INTR__ECC_TRANSACTION_DONE			BIT(0)	/* old IP */
+-#define     INTR__ECC_ERR				BIT(1)	/* old IP */
+-#define     INTR__DMA_CMD_COMP				BIT(2)
+-#define     INTR__TIME_OUT				BIT(3)
+-#define     INTR__PROGRAM_FAIL				BIT(4)
+-#define     INTR__ERASE_FAIL				BIT(5)
+-#define     INTR__LOAD_COMP				BIT(6)
+-#define     INTR__PROGRAM_COMP				BIT(7)
+-#define     INTR__ERASE_COMP				BIT(8)
+-#define     INTR__PIPE_CPYBCK_CMD_COMP			BIT(9)
+-#define     INTR__LOCKED_BLK				BIT(10)
+-#define     INTR__UNSUP_CMD				BIT(11)
+-#define     INTR__INT_ACT				BIT(12)
+-#define     INTR__RST_COMP				BIT(13)
+-#define     INTR__PIPE_CMD_ERR				BIT(14)
+-#define     INTR__PAGE_XFER_INC				BIT(15)
+-#define     INTR__ERASED_PAGE				BIT(16)
+-
+-#define PAGE_CNT(bank)				(0x430 + (bank) * 0x50)
+-#define ERR_PAGE_ADDR(bank)			(0x440 + (bank) * 0x50)
+-#define ERR_BLOCK_ADDR(bank)			(0x450 + (bank) * 0x50)
+-
+-#define ECC_THRESHOLD				0x600
+-#define     ECC_THRESHOLD__VALUE			GENMASK(9, 0)
+-
+-#define ECC_ERROR_BLOCK_ADDRESS			0x610
+-#define     ECC_ERROR_BLOCK_ADDRESS__VALUE		GENMASK(15, 0)
+-
+-#define ECC_ERROR_PAGE_ADDRESS			0x620
+-#define     ECC_ERROR_PAGE_ADDRESS__VALUE		GENMASK(11, 0)
+-#define     ECC_ERROR_PAGE_ADDRESS__BANK		GENMASK(15, 12)
+-
+-#define ECC_ERROR_ADDRESS			0x630
+-#define     ECC_ERROR_ADDRESS__OFFSET			GENMASK(11, 0)
+-#define     ECC_ERROR_ADDRESS__SECTOR_NR		GENMASK(15, 12)
+-
+-#define ERR_CORRECTION_INFO			0x640
+-#define     ERR_CORRECTION_INFO__BYTEMASK		GENMASK(7, 0)
+-#define     ERR_CORRECTION_INFO__DEVICE_NR		GENMASK(11, 8)
+-#define     ERR_CORRECTION_INFO__ERROR_TYPE		BIT(14)
+-#define     ERR_CORRECTION_INFO__LAST_ERR_INFO		BIT(15)
+-
+-#define ECC_COR_INFO(bank)			(0x650 + (bank) / 2 * 0x10)
+-#define     ECC_COR_INFO__SHIFT(bank)			((bank) % 2 * 8)
+-#define     ECC_COR_INFO__MAX_ERRORS			GENMASK(6, 0)
+-#define     ECC_COR_INFO__UNCOR_ERR			BIT(7)
+-
+-#define CFG_DATA_BLOCK_SIZE			0x6b0
+-
+-#define CFG_LAST_DATA_BLOCK_SIZE		0x6c0
+-
+-#define CFG_NUM_DATA_BLOCKS			0x6d0
+-
+-#define CFG_META_DATA_SIZE			0x6e0
+-
+-#define DMA_ENABLE				0x700
+-#define     DMA_ENABLE__FLAG				BIT(0)
+-
+-#define IGNORE_ECC_DONE				0x710
+-#define     IGNORE_ECC_DONE__FLAG			BIT(0)
+-
+-#define DMA_INTR				0x720
+-#define DMA_INTR_EN				0x730
+-#define     DMA_INTR__TARGET_ERROR			BIT(0)
+-#define     DMA_INTR__DESC_COMP_CHANNEL0		BIT(1)
+-#define     DMA_INTR__DESC_COMP_CHANNEL1		BIT(2)
+-#define     DMA_INTR__DESC_COMP_CHANNEL2		BIT(3)
+-#define     DMA_INTR__DESC_COMP_CHANNEL3		BIT(4)
+-#define     DMA_INTR__MEMCOPY_DESC_COMP			BIT(5)
+-
+-#define TARGET_ERR_ADDR_LO			0x740
+-#define     TARGET_ERR_ADDR_LO__VALUE			GENMASK(15, 0)
+-
+-#define TARGET_ERR_ADDR_HI			0x750
+-#define     TARGET_ERR_ADDR_HI__VALUE			GENMASK(15, 0)
+-
+-#define CHNL_ACTIVE				0x760
+-#define     CHNL_ACTIVE__CHANNEL0			BIT(0)
+-#define     CHNL_ACTIVE__CHANNEL1			BIT(1)
+-#define     CHNL_ACTIVE__CHANNEL2			BIT(2)
+-#define     CHNL_ACTIVE__CHANNEL3			BIT(3)
+-
+-struct denali_nand_info {
+-	struct nand_chip nand;
+-	unsigned long clk_x_rate;	/* bus interface clock rate */
+-	int active_bank;		/* currently selected bank */
+-	struct device *dev;
+-	void __iomem *reg;		/* Register Interface */
+-	void __iomem *host;		/* Host Data/Command Interface */
+-
+-	/* elements used by ISR */
+-	struct completion complete;
+-	spinlock_t irq_lock;
+-	uint32_t irq_mask;
+-	uint32_t irq_status;
+-	int irq;
+-
+-	void *buf;
+-	dma_addr_t dma_addr;
+-	int dma_avail;
+-	int devs_per_cs;		/* devices connected in parallel */
+-	int oob_skip_bytes;
+-	int max_banks;
+-	unsigned int revision;
+-	unsigned int caps;
+-	const struct nand_ecc_caps *ecc_caps;
+-};
+-
+-#define DENALI_CAP_HW_ECC_FIXUP			BIT(0)
+-#define DENALI_CAP_DMA_64BIT			BIT(1)
+-
+-int denali_calc_ecc_bytes(int step_size, int strength);
+-extern int denali_init(struct denali_nand_info *denali);
+-extern void denali_remove(struct denali_nand_info *denali);
+-
+-#endif /* __DENALI_H__ */
+diff --git a/drivers/mtd/nand/denali_dt.c b/drivers/mtd/nand/denali_dt.c
+deleted file mode 100644
+index 56e2e17..0000000
+--- a/drivers/mtd/nand/denali_dt.c
++++ /dev/null
+@@ -1,163 +0,0 @@
+-/*
+- * NAND Flash Controller Device Driver for DT
+- *
+- * Copyright © 2011, Picochip.
+- *
+- * 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.
+- */
+-#include <linux/clk.h>
+-#include <linux/err.h>
+-#include <linux/io.h>
+-#include <linux/ioport.h>
+-#include <linux/kernel.h>
+-#include <linux/module.h>
+-#include <linux/platform_device.h>
+-#include <linux/of.h>
+-#include <linux/of_device.h>
+-
+-#include "denali.h"
+-
+-struct denali_dt {
+-	struct denali_nand_info	denali;
+-	struct clk		*clk;
+-};
+-
+-struct denali_dt_data {
+-	unsigned int revision;
+-	unsigned int caps;
+-	const struct nand_ecc_caps *ecc_caps;
+-};
+-
+-NAND_ECC_CAPS_SINGLE(denali_socfpga_ecc_caps, denali_calc_ecc_bytes,
+-		     512, 8, 15);
+-static const struct denali_dt_data denali_socfpga_data = {
+-	.caps = DENALI_CAP_HW_ECC_FIXUP,
+-	.ecc_caps = &denali_socfpga_ecc_caps,
+-};
+-
+-NAND_ECC_CAPS_SINGLE(denali_uniphier_v5a_ecc_caps, denali_calc_ecc_bytes,
+-		     1024, 8, 16, 24);
+-static const struct denali_dt_data denali_uniphier_v5a_data = {
+-	.caps = DENALI_CAP_HW_ECC_FIXUP |
+-		DENALI_CAP_DMA_64BIT,
+-	.ecc_caps = &denali_uniphier_v5a_ecc_caps,
+-};
+-
+-NAND_ECC_CAPS_SINGLE(denali_uniphier_v5b_ecc_caps, denali_calc_ecc_bytes,
+-		     1024, 8, 16);
+-static const struct denali_dt_data denali_uniphier_v5b_data = {
+-	.revision = 0x0501,
+-	.caps = DENALI_CAP_HW_ECC_FIXUP |
+-		DENALI_CAP_DMA_64BIT,
+-	.ecc_caps = &denali_uniphier_v5b_ecc_caps,
+-};
+-
+-static const struct of_device_id denali_nand_dt_ids[] = {
+-	{
+-		.compatible = "altr,socfpga-denali-nand",
+-		.data = &denali_socfpga_data,
+-	},
+-	{
+-		.compatible = "socionext,uniphier-denali-nand-v5a",
+-		.data = &denali_uniphier_v5a_data,
+-	},
+-	{
+-		.compatible = "socionext,uniphier-denali-nand-v5b",
+-		.data = &denali_uniphier_v5b_data,
+-	},
+-	{ /* sentinel */ }
+-};
+-MODULE_DEVICE_TABLE(of, denali_nand_dt_ids);
+-
+-static int denali_dt_probe(struct platform_device *pdev)
+-{
+-	struct resource *res;
+-	struct denali_dt *dt;
+-	const struct denali_dt_data *data;
+-	struct denali_nand_info *denali;
+-	int ret;
+-
+-	dt = devm_kzalloc(&pdev->dev, sizeof(*dt), GFP_KERNEL);
+-	if (!dt)
+-		return -ENOMEM;
+-	denali = &dt->denali;
+-
+-	data = of_device_get_match_data(&pdev->dev);
+-	if (data) {
+-		denali->revision = data->revision;
+-		denali->caps = data->caps;
+-		denali->ecc_caps = data->ecc_caps;
+-	}
+-
+-	denali->dev = &pdev->dev;
+-	denali->irq = platform_get_irq(pdev, 0);
+-	if (denali->irq < 0) {
+-		dev_err(&pdev->dev, "no irq defined\n");
+-		return denali->irq;
+-	}
+-
+-	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "denali_reg");
+-	denali->reg = devm_ioremap_resource(&pdev->dev, res);
+-	if (IS_ERR(denali->reg))
+-		return PTR_ERR(denali->reg);
+-
+-	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_data");
+-	denali->host = devm_ioremap_resource(&pdev->dev, res);
+-	if (IS_ERR(denali->host))
+-		return PTR_ERR(denali->host);
+-
+-	dt->clk = devm_clk_get(&pdev->dev, NULL);
+-	if (IS_ERR(dt->clk)) {
+-		dev_err(&pdev->dev, "no clk available\n");
+-		return PTR_ERR(dt->clk);
+-	}
+-	ret = clk_prepare_enable(dt->clk);
+-	if (ret)
+-		return ret;
+-
+-	denali->clk_x_rate = clk_get_rate(dt->clk);
+-
+-	ret = denali_init(denali);
+-	if (ret)
+-		goto out_disable_clk;
+-
+-	platform_set_drvdata(pdev, dt);
+-	return 0;
+-
+-out_disable_clk:
+-	clk_disable_unprepare(dt->clk);
+-
+-	return ret;
+-}
+-
+-static int denali_dt_remove(struct platform_device *pdev)
+-{
+-	struct denali_dt *dt = platform_get_drvdata(pdev);
+-
+-	denali_remove(&dt->denali);
+-	clk_disable_unprepare(dt->clk);
+-
+-	return 0;
+-}
+-
+-static struct platform_driver denali_dt_driver = {
+-	.probe		= denali_dt_probe,
+-	.remove		= denali_dt_remove,
+-	.driver		= {
+-		.name	= "denali-nand-dt",
+-		.of_match_table	= denali_nand_dt_ids,
+-	},
+-};
+-
+-module_platform_driver(denali_dt_driver);
+-
+-MODULE_LICENSE("GPL");
+-MODULE_AUTHOR("Jamie Iles");
+-MODULE_DESCRIPTION("DT driver for Denali NAND controller");
+diff --git a/drivers/mtd/nand/denali_pci.c b/drivers/mtd/nand/denali_pci.c
+deleted file mode 100644
+index 81370c7..0000000
+--- a/drivers/mtd/nand/denali_pci.c
++++ /dev/null
+@@ -1,126 +0,0 @@
+-/*
+- * NAND Flash Controller Device Driver
+- * Copyright © 2009-2010, Intel Corporation and its suppliers.
+- *
+- * 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.
+- */
+-#include <linux/kernel.h>
+-#include <linux/module.h>
+-#include <linux/pci.h>
+-
+-#include "denali.h"
+-
+-#define DENALI_NAND_NAME    "denali-nand-pci"
+-
+-#define INTEL_CE4100	1
+-#define INTEL_MRST	2
+-
+-/* List of platforms this NAND controller has be integrated into */
+-static const struct pci_device_id denali_pci_ids[] = {
+-	{ PCI_VDEVICE(INTEL, 0x0701), INTEL_CE4100 },
+-	{ PCI_VDEVICE(INTEL, 0x0809), INTEL_MRST },
+-	{ /* end: all zeroes */ }
+-};
+-MODULE_DEVICE_TABLE(pci, denali_pci_ids);
+-
+-NAND_ECC_CAPS_SINGLE(denali_pci_ecc_caps, denali_calc_ecc_bytes, 512, 8, 15);
+-
+-static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
+-{
+-	int ret;
+-	resource_size_t csr_base, mem_base;
+-	unsigned long csr_len, mem_len;
+-	struct denali_nand_info *denali;
+-
+-	denali = devm_kzalloc(&dev->dev, sizeof(*denali), GFP_KERNEL);
+-	if (!denali)
+-		return -ENOMEM;
+-
+-	ret = pcim_enable_device(dev);
+-	if (ret) {
+-		dev_err(&dev->dev, "Spectra: pci_enable_device failed.\n");
+-		return ret;
+-	}
+-
+-	if (id->driver_data == INTEL_CE4100) {
+-		mem_base = pci_resource_start(dev, 0);
+-		mem_len = pci_resource_len(dev, 1);
+-		csr_base = pci_resource_start(dev, 1);
+-		csr_len = pci_resource_len(dev, 1);
+-	} else {
+-		csr_base = pci_resource_start(dev, 0);
+-		csr_len = pci_resource_len(dev, 0);
+-		mem_base = pci_resource_start(dev, 1);
+-		mem_len = pci_resource_len(dev, 1);
+-		if (!mem_len) {
+-			mem_base = csr_base + csr_len;
+-			mem_len = csr_len;
+-		}
+-	}
+-
+-	pci_set_master(dev);
+-	denali->dev = &dev->dev;
+-	denali->irq = dev->irq;
+-	denali->ecc_caps = &denali_pci_ecc_caps;
+-	denali->nand.ecc.options |= NAND_ECC_MAXIMIZE;
+-	denali->clk_x_rate = 200000000;		/* 200 MHz */
+-
+-	ret = pci_request_regions(dev, DENALI_NAND_NAME);
+-	if (ret) {
+-		dev_err(&dev->dev, "Spectra: Unable to request memory regions\n");
+-		return ret;
+-	}
+-
+-	denali->reg = ioremap_nocache(csr_base, csr_len);
+-	if (!denali->reg) {
+-		dev_err(&dev->dev, "Spectra: Unable to remap memory region\n");
+-		return -ENOMEM;
+-	}
+-
+-	denali->host = ioremap_nocache(mem_base, mem_len);
+-	if (!denali->host) {
+-		dev_err(&dev->dev, "Spectra: ioremap_nocache failed!");
+-		ret = -ENOMEM;
+-		goto failed_remap_reg;
+-	}
+-
+-	ret = denali_init(denali);
+-	if (ret)
+-		goto failed_remap_mem;
+-
+-	pci_set_drvdata(dev, denali);
+-
+-	return 0;
+-
+-failed_remap_mem:
+-	iounmap(denali->host);
+-failed_remap_reg:
+-	iounmap(denali->reg);
+-	return ret;
+-}
+-
+-/* driver exit point */
+-static void denali_pci_remove(struct pci_dev *dev)
+-{
+-	struct denali_nand_info *denali = pci_get_drvdata(dev);
+-
+-	denali_remove(denali);
+-	iounmap(denali->reg);
+-	iounmap(denali->host);
+-}
+-
+-static struct pci_driver denali_pci_driver = {
+-	.name = DENALI_NAND_NAME,
+-	.id_table = denali_pci_ids,
+-	.probe = denali_pci_probe,
+-	.remove = denali_pci_remove,
+-};
+-
+-module_pci_driver(denali_pci_driver);
+diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c
+deleted file mode 100644
+index c3aa53c..0000000
+--- a/drivers/mtd/nand/diskonchip.c
++++ /dev/null
+@@ -1,1712 +0,0 @@
+-/*
+- * drivers/mtd/nand/diskonchip.c
+- *
+- * (C) 2003 Red Hat, Inc.
+- * (C) 2004 Dan Brown <dan_brown@ieee.org>
+- * (C) 2004 Kalev Lember <kalev@smartlink.ee>
+- *
+- * Author: David Woodhouse <dwmw2@infradead.org>
+- * Additional Diskonchip 2000 and Millennium support by Dan Brown <dan_brown@ieee.org>
+- * Diskonchip Millennium Plus support by Kalev Lember <kalev@smartlink.ee>
+- *
+- * Error correction code lifted from the old docecc code
+- * Author: Fabrice Bellard (fabrice.bellard@netgem.com)
+- * Copyright (C) 2000 Netgem S.A.
+- * converted to the generic Reed-Solomon library by Thomas Gleixner <tglx@linutronix.de>
+- *
+- * Interface to generic NAND code for M-Systems DiskOnChip devices
+- */
+-
+-#include <linux/kernel.h>
+-#include <linux/init.h>
+-#include <linux/sched.h>
+-#include <linux/delay.h>
+-#include <linux/rslib.h>
+-#include <linux/moduleparam.h>
+-#include <linux/slab.h>
+-#include <linux/io.h>
+-
+-#include <linux/mtd/mtd.h>
+-#include <linux/mtd/rawnand.h>
+-#include <linux/mtd/doc2000.h>
+-#include <linux/mtd/partitions.h>
+-#include <linux/mtd/inftl.h>
+-#include <linux/module.h>
+-
+-/* Where to look for the devices? */
+-#ifndef CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS
+-#define CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS 0
+-#endif
+-
+-static unsigned long doc_locations[] __initdata = {
+-#if defined (__alpha__) || defined(__i386__) || defined(__x86_64__)
+-#ifdef CONFIG_MTD_NAND_DISKONCHIP_PROBE_HIGH
+-	0xfffc8000, 0xfffca000, 0xfffcc000, 0xfffce000,
+-	0xfffd0000, 0xfffd2000, 0xfffd4000, 0xfffd6000,
+-	0xfffd8000, 0xfffda000, 0xfffdc000, 0xfffde000,
+-	0xfffe0000, 0xfffe2000, 0xfffe4000, 0xfffe6000,
+-	0xfffe8000, 0xfffea000, 0xfffec000, 0xfffee000,
+-#else
+-	0xc8000, 0xca000, 0xcc000, 0xce000,
+-	0xd0000, 0xd2000, 0xd4000, 0xd6000,
+-	0xd8000, 0xda000, 0xdc000, 0xde000,
+-	0xe0000, 0xe2000, 0xe4000, 0xe6000,
+-	0xe8000, 0xea000, 0xec000, 0xee000,
+-#endif
+-#endif
+-	0xffffffff };
+-
+-static struct mtd_info *doclist = NULL;
+-
+-struct doc_priv {
+-	void __iomem *virtadr;
+-	unsigned long physadr;
+-	u_char ChipID;
+-	u_char CDSNControl;
+-	int chips_per_floor;	/* The number of chips detected on each floor */
+-	int curfloor;
+-	int curchip;
+-	int mh0_page;
+-	int mh1_page;
+-	struct mtd_info *nextdoc;
+-
+-	/* Handle the last stage of initialization (BBT scan, partitioning) */
+-	int (*late_init)(struct mtd_info *mtd);
+-};
+-
+-/* This is the ecc value computed by the HW ecc generator upon writing an empty
+-   page, one with all 0xff for data. */
+-static u_char empty_write_ecc[6] = { 0x4b, 0x00, 0xe2, 0x0e, 0x93, 0xf7 };
+-
+-#define INFTL_BBT_RESERVED_BLOCKS 4
+-
+-#define DoC_is_MillenniumPlus(doc) ((doc)->ChipID == DOC_ChipID_DocMilPlus16 || (doc)->ChipID == DOC_ChipID_DocMilPlus32)
+-#define DoC_is_Millennium(doc) ((doc)->ChipID == DOC_ChipID_DocMil)
+-#define DoC_is_2000(doc) ((doc)->ChipID == DOC_ChipID_Doc2k)
+-
+-static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd,
+-			      unsigned int bitmask);
+-static void doc200x_select_chip(struct mtd_info *mtd, int chip);
+-
+-static int debug = 0;
+-module_param(debug, int, 0);
+-
+-static int try_dword = 1;
+-module_param(try_dword, int, 0);
+-
+-static int no_ecc_failures = 0;
+-module_param(no_ecc_failures, int, 0);
+-
+-static int no_autopart = 0;
+-module_param(no_autopart, int, 0);
+-
+-static int show_firmware_partition = 0;
+-module_param(show_firmware_partition, int, 0);
+-
+-#ifdef CONFIG_MTD_NAND_DISKONCHIP_BBTWRITE
+-static int inftl_bbt_write = 1;
+-#else
+-static int inftl_bbt_write = 0;
+-#endif
+-module_param(inftl_bbt_write, int, 0);
+-
+-static unsigned long doc_config_location = CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS;
+-module_param(doc_config_location, ulong, 0);
+-MODULE_PARM_DESC(doc_config_location, "Physical memory address at which to probe for DiskOnChip");
+-
+-/* Sector size for HW ECC */
+-#define SECTOR_SIZE 512
+-/* The sector bytes are packed into NB_DATA 10 bit words */
+-#define NB_DATA (((SECTOR_SIZE + 1) * 8 + 6) / 10)
+-/* Number of roots */
+-#define NROOTS 4
+-/* First consective root */
+-#define FCR 510
+-/* Number of symbols */
+-#define NN 1023
+-
+-/* the Reed Solomon control structure */
+-static struct rs_control *rs_decoder;
+-
+-/*
+- * The HW decoder in the DoC ASIC's provides us a error syndrome,
+- * which we must convert to a standard syndrome usable by the generic
+- * Reed-Solomon library code.
+- *
+- * Fabrice Bellard figured this out in the old docecc code. I added
+- * some comments, improved a minor bit and converted it to make use
+- * of the generic Reed-Solomon library. tglx
+- */
+-static int doc_ecc_decode(struct rs_control *rs, uint8_t *data, uint8_t *ecc)
+-{
+-	int i, j, nerr, errpos[8];
+-	uint8_t parity;
+-	uint16_t ds[4], s[5], tmp, errval[8], syn[4];
+-
+-	memset(syn, 0, sizeof(syn));
+-	/* Convert the ecc bytes into words */
+-	ds[0] = ((ecc[4] & 0xff) >> 0) | ((ecc[5] & 0x03) << 8);
+-	ds[1] = ((ecc[5] & 0xfc) >> 2) | ((ecc[2] & 0x0f) << 6);
+-	ds[2] = ((ecc[2] & 0xf0) >> 4) | ((ecc[3] & 0x3f) << 4);
+-	ds[3] = ((ecc[3] & 0xc0) >> 6) | ((ecc[0] & 0xff) << 2);
+-	parity = ecc[1];
+-
+-	/* Initialize the syndrome buffer */
+-	for (i = 0; i < NROOTS; i++)
+-		s[i] = ds[0];
+-	/*
+-	 *  Evaluate
+-	 *  s[i] = ds[3]x^3 + ds[2]x^2 + ds[1]x^1 + ds[0]
+-	 *  where x = alpha^(FCR + i)
+-	 */
+-	for (j = 1; j < NROOTS; j++) {
+-		if (ds[j] == 0)
+-			continue;
+-		tmp = rs->index_of[ds[j]];
+-		for (i = 0; i < NROOTS; i++)
+-			s[i] ^= rs->alpha_to[rs_modnn(rs, tmp + (FCR + i) * j)];
+-	}
+-
+-	/* Calc syn[i] = s[i] / alpha^(v + i) */
+-	for (i = 0; i < NROOTS; i++) {
+-		if (s[i])
+-			syn[i] = rs_modnn(rs, rs->index_of[s[i]] + (NN - FCR - i));
+-	}
+-	/* Call the decoder library */
+-	nerr = decode_rs16(rs, NULL, NULL, 1019, syn, 0, errpos, 0, errval);
+-
+-	/* Incorrectable errors ? */
+-	if (nerr < 0)
+-		return nerr;
+-
+-	/*
+-	 * Correct the errors. The bitpositions are a bit of magic,
+-	 * but they are given by the design of the de/encoder circuit
+-	 * in the DoC ASIC's.
+-	 */
+-	for (i = 0; i < nerr; i++) {
+-		int index, bitpos, pos = 1015 - errpos[i];
+-		uint8_t val;
+-		if (pos >= NB_DATA && pos < 1019)
+-			continue;
+-		if (pos < NB_DATA) {
+-			/* extract bit position (MSB first) */
+-			pos = 10 * (NB_DATA - 1 - pos) - 6;
+-			/* now correct the following 10 bits. At most two bytes
+-			   can be modified since pos is even */
+-			index = (pos >> 3) ^ 1;
+-			bitpos = pos & 7;
+-			if ((index >= 0 && index < SECTOR_SIZE) || index == (SECTOR_SIZE + 1)) {
+-				val = (uint8_t) (errval[i] >> (2 + bitpos));
+-				parity ^= val;
+-				if (index < SECTOR_SIZE)
+-					data[index] ^= val;
+-			}
+-			index = ((pos >> 3) + 1) ^ 1;
+-			bitpos = (bitpos + 10) & 7;
+-			if (bitpos == 0)
+-				bitpos = 8;
+-			if ((index >= 0 && index < SECTOR_SIZE) || index == (SECTOR_SIZE + 1)) {
+-				val = (uint8_t) (errval[i] << (8 - bitpos));
+-				parity ^= val;
+-				if (index < SECTOR_SIZE)
+-					data[index] ^= val;
+-			}
+-		}
+-	}
+-	/* If the parity is wrong, no rescue possible */
+-	return parity ? -EBADMSG : nerr;
+-}
+-
+-static void DoC_Delay(struct doc_priv *doc, unsigned short cycles)
+-{
+-	volatile char dummy;
+-	int i;
+-
+-	for (i = 0; i < cycles; i++) {
+-		if (DoC_is_Millennium(doc))
+-			dummy = ReadDOC(doc->virtadr, NOP);
+-		else if (DoC_is_MillenniumPlus(doc))
+-			dummy = ReadDOC(doc->virtadr, Mplus_NOP);
+-		else
+-			dummy = ReadDOC(doc->virtadr, DOCStatus);
+-	}
+-
+-}
+-
+-#define CDSN_CTRL_FR_B_MASK	(CDSN_CTRL_FR_B0 | CDSN_CTRL_FR_B1)
+-
+-/* DOC_WaitReady: Wait for RDY line to be asserted by the flash chip */
+-static int _DoC_WaitReady(struct doc_priv *doc)
+-{
+-	void __iomem *docptr = doc->virtadr;
+-	unsigned long timeo = jiffies + (HZ * 10);
+-
+-	if (debug)
+-		printk("_DoC_WaitReady...\n");
+-	/* Out-of-line routine to wait for chip response */
+-	if (DoC_is_MillenniumPlus(doc)) {
+-		while ((ReadDOC(docptr, Mplus_FlashControl) & CDSN_CTRL_FR_B_MASK) != CDSN_CTRL_FR_B_MASK) {
+-			if (time_after(jiffies, timeo)) {
+-				printk("_DoC_WaitReady timed out.\n");
+-				return -EIO;
+-			}
+-			udelay(1);
+-			cond_resched();
+-		}
+-	} else {
+-		while (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B)) {
+-			if (time_after(jiffies, timeo)) {
+-				printk("_DoC_WaitReady timed out.\n");
+-				return -EIO;
+-			}
+-			udelay(1);
+-			cond_resched();
+-		}
+-	}
+-
+-	return 0;
+-}
+-
+-static inline int DoC_WaitReady(struct doc_priv *doc)
+-{
+-	void __iomem *docptr = doc->virtadr;
+-	int ret = 0;
+-
+-	if (DoC_is_MillenniumPlus(doc)) {
+-		DoC_Delay(doc, 4);
+-
+-		if ((ReadDOC(docptr, Mplus_FlashControl) & CDSN_CTRL_FR_B_MASK) != CDSN_CTRL_FR_B_MASK)
+-			/* Call the out-of-line routine to wait */
+-			ret = _DoC_WaitReady(doc);
+-	} else {
+-		DoC_Delay(doc, 4);
+-
+-		if (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B))
+-			/* Call the out-of-line routine to wait */
+-			ret = _DoC_WaitReady(doc);
+-		DoC_Delay(doc, 2);
+-	}
+-
+-	if (debug)
+-		printk("DoC_WaitReady OK\n");
+-	return ret;
+-}
+-
+-static void doc2000_write_byte(struct mtd_info *mtd, u_char datum)
+-{
+-	struct nand_chip *this = mtd_to_nand(mtd);
+-	struct doc_priv *doc = nand_get_controller_data(this);
+-	void __iomem *docptr = doc->virtadr;
+-
+-	if (debug)
+-		printk("write_byte %02x\n", datum);
+-	WriteDOC(datum, docptr, CDSNSlowIO);
+-	WriteDOC(datum, docptr, 2k_CDSN_IO);
+-}
+-
+-static u_char doc2000_read_byte(struct mtd_info *mtd)
+-{
+-	struct nand_chip *this = mtd_to_nand(mtd);
+-	struct doc_priv *doc = nand_get_controller_data(this);
+-	void __iomem *docptr = doc->virtadr;
+-	u_char ret;
+-
+-	ReadDOC(docptr, CDSNSlowIO);
+-	DoC_Delay(doc, 2);
+-	ret = ReadDOC(docptr, 2k_CDSN_IO);
+-	if (debug)
+-		printk("read_byte returns %02x\n", ret);
+-	return ret;
+-}
+-
+-static void doc2000_writebuf(struct mtd_info *mtd, const u_char *buf, int len)
+-{
+-	struct nand_chip *this = mtd_to_nand(mtd);
+-	struct doc_priv *doc = nand_get_controller_data(this);
+-	void __iomem *docptr = doc->virtadr;
+-	int i;
+-	if (debug)
+-		printk("writebuf of %d bytes: ", len);
+-	for (i = 0; i < len; i++) {
+-		WriteDOC_(buf[i], docptr, DoC_2k_CDSN_IO + i);
+-		if (debug && i < 16)
+-			printk("%02x ", buf[i]);
+-	}
+-	if (debug)
+-		printk("\n");
+-}
+-
+-static void doc2000_readbuf(struct mtd_info *mtd, u_char *buf, int len)
+-{
+-	struct nand_chip *this = mtd_to_nand(mtd);
+-	struct doc_priv *doc = nand_get_controller_data(this);
+-	void __iomem *docptr = doc->virtadr;
+-	int i;
+-
+-	if (debug)
+-		printk("readbuf of %d bytes: ", len);
+-
+-	for (i = 0; i < len; i++) {
+-		buf[i] = ReadDOC(docptr, 2k_CDSN_IO + i);
+-	}
+-}
+-
+-static void doc2000_readbuf_dword(struct mtd_info *mtd, u_char *buf, int len)
+-{
+-	struct nand_chip *this = mtd_to_nand(mtd);
+-	struct doc_priv *doc = nand_get_controller_data(this);
+-	void __iomem *docptr = doc->virtadr;
+-	int i;
+-
+-	if (debug)
+-		printk("readbuf_dword of %d bytes: ", len);
+-
+-	if (unlikely((((unsigned long)buf) | len) & 3)) {
+-		for (i = 0; i < len; i++) {
+-			*(uint8_t *) (&buf[i]) = ReadDOC(docptr, 2k_CDSN_IO + i);
+-		}
+-	} else {
+-		for (i = 0; i < len; i += 4) {
+-			*(uint32_t *) (&buf[i]) = readl(docptr + DoC_2k_CDSN_IO + i);
+-		}
+-	}
+-}
+-
+-static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr)
+-{
+-	struct nand_chip *this = mtd_to_nand(mtd);
+-	struct doc_priv *doc = nand_get_controller_data(this);
+-	uint16_t ret;
+-
+-	doc200x_select_chip(mtd, nr);
+-	doc200x_hwcontrol(mtd, NAND_CMD_READID,
+-			  NAND_CTRL_CLE | NAND_CTRL_CHANGE);
+-	doc200x_hwcontrol(mtd, 0, NAND_CTRL_ALE | NAND_CTRL_CHANGE);
+-	doc200x_hwcontrol(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
+-
+-	/* We can't use dev_ready here, but at least we wait for the
+-	 * command to complete
+-	 */
+-	udelay(50);
+-
+-	ret = this->read_byte(mtd) << 8;
+-	ret |= this->read_byte(mtd);
+-
+-	if (doc->ChipID == DOC_ChipID_Doc2k && try_dword && !nr) {
+-		/* First chip probe. See if we get same results by 32-bit access */
+-		union {
+-			uint32_t dword;
+-			uint8_t byte[4];
+-		} ident;
+-		void __iomem *docptr = doc->virtadr;
+-
+-		doc200x_hwcontrol(mtd, NAND_CMD_READID,
+-				  NAND_CTRL_CLE | NAND_CTRL_CHANGE);
+-		doc200x_hwcontrol(mtd, 0, NAND_CTRL_ALE | NAND_CTRL_CHANGE);
+-		doc200x_hwcontrol(mtd, NAND_CMD_NONE,
+-				  NAND_NCE | NAND_CTRL_CHANGE);
+-
+-		udelay(50);
+-
+-		ident.dword = readl(docptr + DoC_2k_CDSN_IO);
+-		if (((ident.byte[0] << 8) | ident.byte[1]) == ret) {
+-			printk(KERN_INFO "DiskOnChip 2000 responds to DWORD access\n");
+-			this->read_buf = &doc2000_readbuf_dword;
+-		}
+-	}
+-
+-	return ret;
+-}
+-
+-static void __init doc2000_count_chips(struct mtd_info *mtd)
+-{
+-	struct nand_chip *this = mtd_to_nand(mtd);
+-	struct doc_priv *doc = nand_get_controller_data(this);
+-	uint16_t mfrid;
+-	int i;
+-
+-	/* Max 4 chips per floor on DiskOnChip 2000 */
+-	doc->chips_per_floor = 4;
+-
+-	/* Find out what the first chip is */
+-	mfrid = doc200x_ident_chip(mtd, 0);
+-
+-	/* Find how many chips in each floor. */
+-	for (i = 1; i < 4; i++) {
+-		if (doc200x_ident_chip(mtd, i) != mfrid)
+-			break;
+-	}
+-	doc->chips_per_floor = i;
+-	printk(KERN_DEBUG "Detected %d chips per floor.\n", i);
+-}
+-
+-static int doc200x_wait(struct mtd_info *mtd, struct nand_chip *this)
+-{
+-	struct doc_priv *doc = nand_get_controller_data(this);
+-
+-	int status;
+-
+-	DoC_WaitReady(doc);
+-	this->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
+-	DoC_WaitReady(doc);
+-	status = (int)this->read_byte(mtd);
+-
+-	return status;
+-}
+-
+-static void doc2001_write_byte(struct mtd_info *mtd, u_char datum)
+-{
+-	struct nand_chip *this = mtd_to_nand(mtd);
+-	struct doc_priv *doc = nand_get_controller_data(this);
+-	void __iomem *docptr = doc->virtadr;
+-
+-	WriteDOC(datum, docptr, CDSNSlowIO);
+-	WriteDOC(datum, docptr, Mil_CDSN_IO);
+-	WriteDOC(datum, docptr, WritePipeTerm);
+-}
+-
+-static u_char doc2001_read_byte(struct mtd_info *mtd)
+-{
+-	struct nand_chip *this = mtd_to_nand(mtd);
+-	struct doc_priv *doc = nand_get_controller_data(this);
+-	void __iomem *docptr = doc->virtadr;
+-
+-	//ReadDOC(docptr, CDSNSlowIO);
+-	/* 11.4.5 -- delay twice to allow extended length cycle */
+-	DoC_Delay(doc, 2);
+-	ReadDOC(docptr, ReadPipeInit);
+-	//return ReadDOC(docptr, Mil_CDSN_IO);
+-	return ReadDOC(docptr, LastDataRead);
+-}
+-
+-static void doc2001_writebuf(struct mtd_info *mtd, const u_char *buf, int len)
+-{
+-	struct nand_chip *this = mtd_to_nand(mtd);
+-	struct doc_priv *doc = nand_get_controller_data(this);
+-	void __iomem *docptr = doc->virtadr;
+-	int i;
+-
+-	for (i = 0; i < len; i++)
+-		WriteDOC_(buf[i], docptr, DoC_Mil_CDSN_IO + i);
+-	/* Terminate write pipeline */
+-	WriteDOC(0x00, docptr, WritePipeTerm);
+-}
+-
+-static void doc2001_readbuf(struct mtd_info *mtd, u_char *buf, int len)
+-{
+-	struct nand_chip *this = mtd_to_nand(mtd);
+-	struct doc_priv *doc = nand_get_controller_data(this);
+-	void __iomem *docptr = doc->virtadr;
+-	int i;
+-
+-	/* Start read pipeline */
+-	ReadDOC(docptr, ReadPipeInit);
+-
+-	for (i = 0; i < len - 1; i++)
+-		buf[i] = ReadDOC(docptr, Mil_CDSN_IO + (i & 0xff));
+-
+-	/* Terminate read pipeline */
+-	buf[i] = ReadDOC(docptr, LastDataRead);
+-}
+-
+-static u_char doc2001plus_read_byte(struct mtd_info *mtd)
+-{
+-	struct nand_chip *this = mtd_to_nand(mtd);
+-	struct doc_priv *doc = nand_get_controller_data(this);
+-	void __iomem *docptr = doc->virtadr;
+-	u_char ret;
+-
+-	ReadDOC(docptr, Mplus_ReadPipeInit);
+-	ReadDOC(docptr, Mplus_ReadPipeInit);
+-	ret = ReadDOC(docptr, Mplus_LastDataRead);
+-	if (debug)
+-		printk("read_byte returns %02x\n", ret);
+-	return ret;
+-}
+-
+-static void doc2001plus_writebuf(struct mtd_info *mtd, const u_char *buf, int len)
+-{
+-	struct nand_chip *this = mtd_to_nand(mtd);
+-	struct doc_priv *doc = nand_get_controller_data(this);
+-	void __iomem *docptr = doc->virtadr;
+-	int i;
+-
+-	if (debug)
+-		printk("writebuf of %d bytes: ", len);
+-	for (i = 0; i < len; i++) {
+-		WriteDOC_(buf[i], docptr, DoC_Mil_CDSN_IO + i);
+-		if (debug && i < 16)
+-			printk("%02x ", buf[i]);
+-	}
+-	if (debug)
+-		printk("\n");
+-}
+-
+-static void doc2001plus_readbuf(struct mtd_info *mtd, u_char *buf, int len)
+-{
+-	struct nand_chip *this = mtd_to_nand(mtd);
+-	struct doc_priv *doc = nand_get_controller_data(this);
+-	void __iomem *docptr = doc->virtadr;
+-	int i;
+-
+-	if (debug)
+-		printk("readbuf of %d bytes: ", len);
+-
+-	/* Start read pipeline */
+-	ReadDOC(docptr, Mplus_ReadPipeInit);
+-	ReadDOC(docptr, Mplus_ReadPipeInit);
+-
+-	for (i = 0; i < len - 2; i++) {
+-		buf[i] = ReadDOC(docptr, Mil_CDSN_IO);
+-		if (debug && i < 16)
+-			printk("%02x ", buf[i]);
+-	}
+-
+-	/* Terminate read pipeline */
+-	buf[len - 2] = ReadDOC(docptr, Mplus_LastDataRead);
+-	if (debug && i < 16)
+-		printk("%02x ", buf[len - 2]);
+-	buf[len - 1] = ReadDOC(docptr, Mplus_LastDataRead);
+-	if (debug && i < 16)
+-		printk("%02x ", buf[len - 1]);
+-	if (debug)
+-		printk("\n");
+-}
+-
+-static void doc2001plus_select_chip(struct mtd_info *mtd, int chip)
+-{
+-	struct nand_chip *this = mtd_to_nand(mtd);
+-	struct doc_priv *doc = nand_get_controller_data(this);
+-	void __iomem *docptr = doc->virtadr;
+-	int floor = 0;
+-
+-	if (debug)
+-		printk("select chip (%d)\n", chip);
+-
+-	if (chip == -1) {
+-		/* Disable flash internally */
+-		WriteDOC(0, docptr, Mplus_FlashSelect);
+-		return;
+-	}
+-
+-	floor = chip / doc->chips_per_floor;
+-	chip -= (floor * doc->chips_per_floor);
+-
+-	/* Assert ChipEnable and deassert WriteProtect */
+-	WriteDOC((DOC_FLASH_CE), docptr, Mplus_FlashSelect);
+-	this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
+-
+-	doc->curchip = chip;
+-	doc->curfloor = floor;
+-}
+-
+-static void doc200x_select_chip(struct mtd_info *mtd, int chip)
+-{
+-	struct nand_chip *this = mtd_to_nand(mtd);
+-	struct doc_priv *doc = nand_get_controller_data(this);
+-	void __iomem *docptr = doc->virtadr;
+-	int floor = 0;
+-
+-	if (debug)
+-		printk("select chip (%d)\n", chip);
+-
+-	if (chip == -1)
+-		return;
+-
+-	floor = chip / doc->chips_per_floor;
+-	chip -= (floor * doc->chips_per_floor);
+-
+-	/* 11.4.4 -- deassert CE before changing chip */
+-	doc200x_hwcontrol(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE);
+-
+-	WriteDOC(floor, docptr, FloorSelect);
+-	WriteDOC(chip, docptr, CDSNDeviceSelect);
+-
+-	doc200x_hwcontrol(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
+-
+-	doc->curchip = chip;
+-	doc->curfloor = floor;
+-}
+-
+-#define CDSN_CTRL_MSK (CDSN_CTRL_CE | CDSN_CTRL_CLE | CDSN_CTRL_ALE)
+-
+-static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd,
+-			      unsigned int ctrl)
+-{
+-	struct nand_chip *this = mtd_to_nand(mtd);
+-	struct doc_priv *doc = nand_get_controller_data(this);
+-	void __iomem *docptr = doc->virtadr;
+-
+-	if (ctrl & NAND_CTRL_CHANGE) {
+-		doc->CDSNControl &= ~CDSN_CTRL_MSK;
+-		doc->CDSNControl |= ctrl & CDSN_CTRL_MSK;
+-		if (debug)
+-			printk("hwcontrol(%d): %02x\n", cmd, doc->CDSNControl);
+-		WriteDOC(doc->CDSNControl, docptr, CDSNControl);
+-		/* 11.4.3 -- 4 NOPs after CSDNControl write */
+-		DoC_Delay(doc, 4);
+-	}
+-	if (cmd != NAND_CMD_NONE) {
+-		if (DoC_is_2000(doc))
+-			doc2000_write_byte(mtd, cmd);
+-		else
+-			doc2001_write_byte(mtd, 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 doc_priv *doc = nand_get_controller_data(this);
+-	void __iomem *docptr = doc->virtadr;
+-
+-	/*
+-	 * Must terminate write pipeline before sending any commands
+-	 * to the device.
+-	 */
+-	if (command == NAND_CMD_PAGEPROG) {
+-		WriteDOC(0x00, docptr, Mplus_WritePipeTerm);
+-		WriteDOC(0x00, docptr, Mplus_WritePipeTerm);
+-	}
+-
+-	/*
+-	 * Write out the command to the device.
+-	 */
+-	if (command == NAND_CMD_SEQIN) {
+-		int readcmd;
+-
+-		if (column >= mtd->writesize) {
+-			/* OOB area */
+-			column -= mtd->writesize;
+-			readcmd = NAND_CMD_READOOB;
+-		} else if (column < 256) {
+-			/* First 256 bytes --> READ0 */
+-			readcmd = NAND_CMD_READ0;
+-		} else {
+-			column -= 256;
+-			readcmd = NAND_CMD_READ1;
+-		}
+-		WriteDOC(readcmd, docptr, Mplus_FlashCmd);
+-	}
+-	WriteDOC(command, docptr, Mplus_FlashCmd);
+-	WriteDOC(0, docptr, Mplus_WritePipeTerm);
+-	WriteDOC(0, docptr, Mplus_WritePipeTerm);
+-
+-	if (column != -1 || page_addr != -1) {
+-		/* Serially input address */
+-		if (column != -1) {
+-			/* Adjust columns for 16 bit buswidth */
+-			if (this->options & NAND_BUSWIDTH_16 &&
+-					!nand_opcode_8bits(command))
+-				column >>= 1;
+-			WriteDOC(column, docptr, Mplus_FlashAddress);
+-		}
+-		if (page_addr != -1) {
+-			WriteDOC((unsigned char)(page_addr & 0xff), docptr, Mplus_FlashAddress);
+-			WriteDOC((unsigned char)((page_addr >> 8) & 0xff), docptr, Mplus_FlashAddress);
+-			/* One more address cycle for higher density devices */
+-			if (this->chipsize & 0x0c000000) {
+-				WriteDOC((unsigned char)((page_addr >> 16) & 0x0f), docptr, Mplus_FlashAddress);
+-				printk("high density\n");
+-			}
+-		}
+-		WriteDOC(0, docptr, Mplus_WritePipeTerm);
+-		WriteDOC(0, docptr, Mplus_WritePipeTerm);
+-		/* deassert ALE */
+-		if (command == NAND_CMD_READ0 || command == NAND_CMD_READ1 ||
+-		    command == NAND_CMD_READOOB || command == NAND_CMD_READID)
+-			WriteDOC(0, docptr, Mplus_FlashControl);
+-	}
+-
+-	/*
+-	 * program and erase have their own busy handlers
+-	 * status and sequential in needs no delay
+-	 */
+-	switch (command) {
+-
+-	case NAND_CMD_PAGEPROG:
+-	case NAND_CMD_ERASE1:
+-	case NAND_CMD_ERASE2:
+-	case NAND_CMD_SEQIN:
+-	case NAND_CMD_STATUS:
+-		return;
+-
+-	case NAND_CMD_RESET:
+-		if (this->dev_ready)
+-			break;
+-		udelay(this->chip_delay);
+-		WriteDOC(NAND_CMD_STATUS, docptr, Mplus_FlashCmd);
+-		WriteDOC(0, docptr, Mplus_WritePipeTerm);
+-		WriteDOC(0, docptr, Mplus_WritePipeTerm);
+-		while (!(this->read_byte(mtd) & 0x40)) ;
+-		return;
+-
+-		/* This applies to read commands */
+-	default:
+-		/*
+-		 * If we don't have access to the busy pin, we apply the given
+-		 * command delay
+-		 */
+-		if (!this->dev_ready) {
+-			udelay(this->chip_delay);
+-			return;
+-		}
+-	}
+-
+-	/* Apply this short delay always to ensure that we do wait tWB in
+-	 * any case on any machine. */
+-	ndelay(100);
+-	/* wait until command is processed */
+-	while (!this->dev_ready(mtd)) ;
+-}
+-
+-static int doc200x_dev_ready(struct mtd_info *mtd)
+-{
+-	struct nand_chip *this = mtd_to_nand(mtd);
+-	struct doc_priv *doc = nand_get_controller_data(this);
+-	void __iomem *docptr = doc->virtadr;
+-
+-	if (DoC_is_MillenniumPlus(doc)) {
+-		/* 11.4.2 -- must NOP four times before checking FR/B# */
+-		DoC_Delay(doc, 4);
+-		if ((ReadDOC(docptr, Mplus_FlashControl) & CDSN_CTRL_FR_B_MASK) != CDSN_CTRL_FR_B_MASK) {
+-			if (debug)
+-				printk("not ready\n");
+-			return 0;
+-		}
+-		if (debug)
+-			printk("was ready\n");
+-		return 1;
+-	} else {
+-		/* 11.4.2 -- must NOP four times before checking FR/B# */
+-		DoC_Delay(doc, 4);
+-		if (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B)) {
+-			if (debug)
+-				printk("not ready\n");
+-			return 0;
+-		}
+-		/* 11.4.2 -- Must NOP twice if it's ready */
+-		DoC_Delay(doc, 2);
+-		if (debug)
+-			printk("was ready\n");
+-		return 1;
+-	}
+-}
+-
+-static int doc200x_block_bad(struct mtd_info *mtd, loff_t ofs)
+-{
+-	/* This is our last resort if we couldn't find or create a BBT.  Just
+-	   pretend all blocks are good. */
+-	return 0;
+-}
+-
+-static void doc200x_enable_hwecc(struct mtd_info *mtd, int mode)
+-{
+-	struct nand_chip *this = mtd_to_nand(mtd);
+-	struct doc_priv *doc = nand_get_controller_data(this);
+-	void __iomem *docptr = doc->virtadr;
+-
+-	/* Prime the ECC engine */
+-	switch (mode) {
+-	case NAND_ECC_READ:
+-		WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
+-		WriteDOC(DOC_ECC_EN, docptr, ECCConf);
+-		break;
+-	case NAND_ECC_WRITE:
+-		WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
+-		WriteDOC(DOC_ECC_EN | DOC_ECC_RW, docptr, ECCConf);
+-		break;
+-	}
+-}
+-
+-static void doc2001plus_enable_hwecc(struct mtd_info *mtd, int mode)
+-{
+-	struct nand_chip *this = mtd_to_nand(mtd);
+-	struct doc_priv *doc = nand_get_controller_data(this);
+-	void __iomem *docptr = doc->virtadr;
+-
+-	/* Prime the ECC engine */
+-	switch (mode) {
+-	case NAND_ECC_READ:
+-		WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf);
+-		WriteDOC(DOC_ECC_EN, docptr, Mplus_ECCConf);
+-		break;
+-	case NAND_ECC_WRITE:
+-		WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf);
+-		WriteDOC(DOC_ECC_EN | DOC_ECC_RW, docptr, Mplus_ECCConf);
+-		break;
+-	}
+-}
+-
+-/* 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 doc_priv *doc = nand_get_controller_data(this);
+-	void __iomem *docptr = doc->virtadr;
+-	int i;
+-	int emptymatch = 1;
+-
+-	/* flush the pipeline */
+-	if (DoC_is_2000(doc)) {
+-		WriteDOC(doc->CDSNControl & ~CDSN_CTRL_FLASH_IO, docptr, CDSNControl);
+-		WriteDOC(0, docptr, 2k_CDSN_IO);
+-		WriteDOC(0, docptr, 2k_CDSN_IO);
+-		WriteDOC(0, docptr, 2k_CDSN_IO);
+-		WriteDOC(doc->CDSNControl, docptr, CDSNControl);
+-	} else if (DoC_is_MillenniumPlus(doc)) {
+-		WriteDOC(0, docptr, Mplus_NOP);
+-		WriteDOC(0, docptr, Mplus_NOP);
+-		WriteDOC(0, docptr, Mplus_NOP);
+-	} else {
+-		WriteDOC(0, docptr, NOP);
+-		WriteDOC(0, docptr, NOP);
+-		WriteDOC(0, docptr, NOP);
+-	}
+-
+-	for (i = 0; i < 6; i++) {
+-		if (DoC_is_MillenniumPlus(doc))
+-			ecc_code[i] = ReadDOC_(docptr, DoC_Mplus_ECCSyndrome0 + i);
+-		else
+-			ecc_code[i] = ReadDOC_(docptr, DoC_ECCSyndrome0 + i);
+-		if (ecc_code[i] != empty_write_ecc[i])
+-			emptymatch = 0;
+-	}
+-	if (DoC_is_MillenniumPlus(doc))
+-		WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf);
+-	else
+-		WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
+-#if 0
+-	/* If emptymatch=1, we might have an all-0xff data buffer.  Check. */
+-	if (emptymatch) {
+-		/* Note: this somewhat expensive test should not be triggered
+-		   often.  It could be optimized away by examining the data in
+-		   the writebuf routine, and remembering the result. */
+-		for (i = 0; i < 512; i++) {
+-			if (dat[i] == 0xff)
+-				continue;
+-			emptymatch = 0;
+-			break;
+-		}
+-	}
+-	/* If emptymatch still =1, we do have an all-0xff data buffer.
+-	   Return all-0xff ecc value instead of the computed one, so
+-	   it'll look just like a freshly-erased page. */
+-	if (emptymatch)
+-		memset(ecc_code, 0xff, 6);
+-#endif
+-	return 0;
+-}
+-
+-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 doc_priv *doc = nand_get_controller_data(this);
+-	void __iomem *docptr = doc->virtadr;
+-	uint8_t calc_ecc[6];
+-	volatile u_char dummy;
+-
+-	/* flush the pipeline */
+-	if (DoC_is_2000(doc)) {
+-		dummy = ReadDOC(docptr, 2k_ECCStatus);
+-		dummy = ReadDOC(docptr, 2k_ECCStatus);
+-		dummy = ReadDOC(docptr, 2k_ECCStatus);
+-	} else if (DoC_is_MillenniumPlus(doc)) {
+-		dummy = ReadDOC(docptr, Mplus_ECCConf);
+-		dummy = ReadDOC(docptr, Mplus_ECCConf);
+-		dummy = ReadDOC(docptr, Mplus_ECCConf);
+-	} else {
+-		dummy = ReadDOC(docptr, ECCConf);
+-		dummy = ReadDOC(docptr, ECCConf);
+-		dummy = ReadDOC(docptr, ECCConf);
+-	}
+-
+-	/* Error occurred ? */
+-	if (dummy & 0x80) {
+-		for (i = 0; i < 6; i++) {
+-			if (DoC_is_MillenniumPlus(doc))
+-				calc_ecc[i] = ReadDOC_(docptr, DoC_Mplus_ECCSyndrome0 + i);
+-			else
+-				calc_ecc[i] = ReadDOC_(docptr, DoC_ECCSyndrome0 + i);
+-		}
+-
+-		ret = doc_ecc_decode(rs_decoder, dat, calc_ecc);
+-		if (ret > 0)
+-			printk(KERN_ERR "doc200x_correct_data corrected %d errors\n", ret);
+-	}
+-	if (DoC_is_MillenniumPlus(doc))
+-		WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf);
+-	else
+-		WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
+-	if (no_ecc_failures && mtd_is_eccerr(ret)) {
+-		printk(KERN_ERR "suppressing ECC failure\n");
+-		ret = 0;
+-	}
+-	return ret;
+-}
+-
+-//u_char mydatabuf[528];
+-
+-static int doc200x_ooblayout_ecc(struct mtd_info *mtd, int section,
+-				 struct mtd_oob_region *oobregion)
+-{
+-	if (section)
+-		return -ERANGE;
+-
+-	oobregion->offset = 0;
+-	oobregion->length = 6;
+-
+-	return 0;
+-}
+-
+-static int doc200x_ooblayout_free(struct mtd_info *mtd, int section,
+-				  struct mtd_oob_region *oobregion)
+-{
+-	if (section > 1)
+-		return -ERANGE;
+-
+-	/*
+-	 * The strange out-of-order free bytes definition is a (possibly
+-	 * unneeded) attempt to retain compatibility.  It used to read:
+-	 *	.oobfree = { {8, 8} }
+-	 * Since that leaves two bytes unusable, it was changed.  But the
+-	 * following scheme might affect existing jffs2 installs by moving the
+-	 * cleanmarker:
+-	 *	.oobfree = { {6, 10} }
+-	 * jffs2 seems to handle the above gracefully, but the current scheme
+-	 * seems safer. The only problem with it is that any code retrieving
+-	 * free bytes position must be able to handle out-of-order segments.
+-	 */
+-	if (!section) {
+-		oobregion->offset = 8;
+-		oobregion->length = 8;
+-	} else {
+-		oobregion->offset = 6;
+-		oobregion->length = 2;
+-	}
+-
+-	return 0;
+-}
+-
+-static const struct mtd_ooblayout_ops doc200x_ooblayout_ops = {
+-	.ecc = doc200x_ooblayout_ecc,
+-	.free = doc200x_ooblayout_free,
+-};
+-
+-/* Find the (I)NFTL Media Header, and optionally also the mirror media header.
+-   On successful return, buf will contain a copy of the media header for
+-   further processing.  id is the string to scan for, and will presumably be
+-   either "ANAND" or "BNAND".  If findmirror=1, also look for the mirror media
+-   header.  The page #s of the found media headers are placed in mh0_page and
+-   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 doc_priv *doc = nand_get_controller_data(this);
+-	unsigned offs;
+-	int ret;
+-	size_t retlen;
+-
+-	for (offs = 0; offs < mtd->size; offs += mtd->erasesize) {
+-		ret = mtd_read(mtd, offs, mtd->writesize, &retlen, buf);
+-		if (retlen != mtd->writesize)
+-			continue;
+-		if (ret) {
+-			printk(KERN_WARNING "ECC error scanning DOC at 0x%x\n", offs);
+-		}
+-		if (memcmp(buf, id, 6))
+-			continue;
+-		printk(KERN_INFO "Found DiskOnChip %s Media Header at 0x%x\n", id, offs);
+-		if (doc->mh0_page == -1) {
+-			doc->mh0_page = offs >> this->page_shift;
+-			if (!findmirror)
+-				return 1;
+-			continue;
+-		}
+-		doc->mh1_page = offs >> this->page_shift;
+-		return 2;
+-	}
+-	if (doc->mh0_page == -1) {
+-		printk(KERN_WARNING "DiskOnChip %s Media Header not found.\n", id);
+-		return 0;
+-	}
+-	/* Only one mediaheader was found.  We want buf to contain a
+-	   mediaheader on return, so we'll have to re-read the one we found. */
+-	offs = doc->mh0_page << this->page_shift;
+-	ret = mtd_read(mtd, offs, mtd->writesize, &retlen, buf);
+-	if (retlen != mtd->writesize) {
+-		/* Insanity.  Give up. */
+-		printk(KERN_ERR "Read DiskOnChip Media Header once, but can't reread it???\n");
+-		return 0;
+-	}
+-	return 1;
+-}
+-
+-static inline int __init nftl_partscan(struct mtd_info *mtd, struct mtd_partition *parts)
+-{
+-	struct nand_chip *this = mtd_to_nand(mtd);
+-	struct doc_priv *doc = nand_get_controller_data(this);
+-	int ret = 0;
+-	u_char *buf;
+-	struct NFTLMediaHeader *mh;
+-	const unsigned psize = 1 << this->page_shift;
+-	int numparts = 0;
+-	unsigned blocks, maxblocks;
+-	int offs, numheaders;
+-
+-	buf = kmalloc(mtd->writesize, GFP_KERNEL);
+-	if (!buf) {
+-		return 0;
+-	}
+-	if (!(numheaders = find_media_headers(mtd, buf, "ANAND", 1)))
+-		goto out;
+-	mh = (struct NFTLMediaHeader *)buf;
+-
+-	le16_to_cpus(&mh->NumEraseUnits);
+-	le16_to_cpus(&mh->FirstPhysicalEUN);
+-	le32_to_cpus(&mh->FormattedSize);
+-
+-	printk(KERN_INFO "    DataOrgID        = %s\n"
+-			 "    NumEraseUnits    = %d\n"
+-			 "    FirstPhysicalEUN = %d\n"
+-			 "    FormattedSize    = %d\n"
+-			 "    UnitSizeFactor   = %d\n",
+-		mh->DataOrgID, mh->NumEraseUnits,
+-		mh->FirstPhysicalEUN, mh->FormattedSize,
+-		mh->UnitSizeFactor);
+-
+-	blocks = mtd->size >> this->phys_erase_shift;
+-	maxblocks = min(32768U, mtd->erasesize - psize);
+-
+-	if (mh->UnitSizeFactor == 0x00) {
+-		/* Auto-determine UnitSizeFactor.  The constraints are:
+-		   - There can be at most 32768 virtual blocks.
+-		   - There can be at most (virtual block size - page size)
+-		   virtual blocks (because MediaHeader+BBT must fit in 1).
+-		 */
+-		mh->UnitSizeFactor = 0xff;
+-		while (blocks > maxblocks) {
+-			blocks >>= 1;
+-			maxblocks = min(32768U, (maxblocks << 1) + psize);
+-			mh->UnitSizeFactor--;
+-		}
+-		printk(KERN_WARNING "UnitSizeFactor=0x00 detected.  Correct value is assumed to be 0x%02x.\n", mh->UnitSizeFactor);
+-	}
+-
+-	/* NOTE: The lines below modify internal variables of the NAND and MTD
+-	   layers; variables with have already been configured by nand_scan.
+-	   Unfortunately, we didn't know before this point what these values
+-	   should be.  Thus, this code is somewhat dependent on the exact
+-	   implementation of the NAND layer.  */
+-	if (mh->UnitSizeFactor != 0xff) {
+-		this->bbt_erase_shift += (0xff - mh->UnitSizeFactor);
+-		mtd->erasesize <<= (0xff - mh->UnitSizeFactor);
+-		printk(KERN_INFO "Setting virtual erase size to %d\n", mtd->erasesize);
+-		blocks = mtd->size >> this->bbt_erase_shift;
+-		maxblocks = min(32768U, mtd->erasesize - psize);
+-	}
+-
+-	if (blocks > maxblocks) {
+-		printk(KERN_ERR "UnitSizeFactor of 0x%02x is inconsistent with device size.  Aborting.\n", mh->UnitSizeFactor);
+-		goto out;
+-	}
+-
+-	/* Skip past the media headers. */
+-	offs = max(doc->mh0_page, doc->mh1_page);
+-	offs <<= this->page_shift;
+-	offs += mtd->erasesize;
+-
+-	if (show_firmware_partition == 1) {
+-		parts[0].name = " DiskOnChip Firmware / Media Header partition";
+-		parts[0].offset = 0;
+-		parts[0].size = offs;
+-		numparts = 1;
+-	}
+-
+-	parts[numparts].name = " DiskOnChip BDTL partition";
+-	parts[numparts].offset = offs;
+-	parts[numparts].size = (mh->NumEraseUnits - numheaders) << this->bbt_erase_shift;
+-
+-	offs += parts[numparts].size;
+-	numparts++;
+-
+-	if (offs < mtd->size) {
+-		parts[numparts].name = " DiskOnChip Remainder partition";
+-		parts[numparts].offset = offs;
+-		parts[numparts].size = mtd->size - offs;
+-		numparts++;
+-	}
+-
+-	ret = numparts;
+- out:
+-	kfree(buf);
+-	return ret;
+-}
+-
+-/* 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 doc_priv *doc = nand_get_controller_data(this);
+-	int ret = 0;
+-	u_char *buf;
+-	struct INFTLMediaHeader *mh;
+-	struct INFTLPartition *ip;
+-	int numparts = 0;
+-	int blocks;
+-	int vshift, lastvunit = 0;
+-	int i;
+-	int end = mtd->size;
+-
+-	if (inftl_bbt_write)
+-		end -= (INFTL_BBT_RESERVED_BLOCKS << this->phys_erase_shift);
+-
+-	buf = kmalloc(mtd->writesize, GFP_KERNEL);
+-	if (!buf) {
+-		return 0;
+-	}
+-
+-	if (!find_media_headers(mtd, buf, "BNAND", 0))
+-		goto out;
+-	doc->mh1_page = doc->mh0_page + (4096 >> this->page_shift);
+-	mh = (struct INFTLMediaHeader *)buf;
+-
+-	le32_to_cpus(&mh->NoOfBootImageBlocks);
+-	le32_to_cpus(&mh->NoOfBinaryPartitions);
+-	le32_to_cpus(&mh->NoOfBDTLPartitions);
+-	le32_to_cpus(&mh->BlockMultiplierBits);
+-	le32_to_cpus(&mh->FormatFlags);
+-	le32_to_cpus(&mh->PercentUsed);
+-
+-	printk(KERN_INFO "    bootRecordID          = %s\n"
+-			 "    NoOfBootImageBlocks   = %d\n"
+-			 "    NoOfBinaryPartitions  = %d\n"
+-			 "    NoOfBDTLPartitions    = %d\n"
+-			 "    BlockMultiplerBits    = %d\n"
+-			 "    FormatFlgs            = %d\n"
+-			 "    OsakVersion           = %d.%d.%d.%d\n"
+-			 "    PercentUsed           = %d\n",
+-		mh->bootRecordID, mh->NoOfBootImageBlocks,
+-		mh->NoOfBinaryPartitions,
+-		mh->NoOfBDTLPartitions,
+-		mh->BlockMultiplierBits, mh->FormatFlags,
+-		((unsigned char *) &mh->OsakVersion)[0] & 0xf,
+-		((unsigned char *) &mh->OsakVersion)[1] & 0xf,
+-		((unsigned char *) &mh->OsakVersion)[2] & 0xf,
+-		((unsigned char *) &mh->OsakVersion)[3] & 0xf,
+-		mh->PercentUsed);
+-
+-	vshift = this->phys_erase_shift + mh->BlockMultiplierBits;
+-
+-	blocks = mtd->size >> vshift;
+-	if (blocks > 32768) {
+-		printk(KERN_ERR "BlockMultiplierBits=%d is inconsistent with device size.  Aborting.\n", mh->BlockMultiplierBits);
+-		goto out;
+-	}
+-
+-	blocks = doc->chips_per_floor << (this->chip_shift - this->phys_erase_shift);
+-	if (inftl_bbt_write && (blocks > mtd->erasesize)) {
+-		printk(KERN_ERR "Writeable BBTs spanning more than one erase block are not yet supported.  FIX ME!\n");
+-		goto out;
+-	}
+-
+-	/* Scan the partitions */
+-	for (i = 0; (i < 4); i++) {
+-		ip = &(mh->Partitions[i]);
+-		le32_to_cpus(&ip->virtualUnits);
+-		le32_to_cpus(&ip->firstUnit);
+-		le32_to_cpus(&ip->lastUnit);
+-		le32_to_cpus(&ip->flags);
+-		le32_to_cpus(&ip->spareUnits);
+-		le32_to_cpus(&ip->Reserved0);
+-
+-		printk(KERN_INFO	"    PARTITION[%d] ->\n"
+-			"        virtualUnits    = %d\n"
+-			"        firstUnit       = %d\n"
+-			"        lastUnit        = %d\n"
+-			"        flags           = 0x%x\n"
+-			"        spareUnits      = %d\n",
+-			i, ip->virtualUnits, ip->firstUnit,
+-			ip->lastUnit, ip->flags,
+-			ip->spareUnits);
+-
+-		if ((show_firmware_partition == 1) &&
+-		    (i == 0) && (ip->firstUnit > 0)) {
+-			parts[0].name = " DiskOnChip IPL / Media Header partition";
+-			parts[0].offset = 0;
+-			parts[0].size = mtd->erasesize * ip->firstUnit;
+-			numparts = 1;
+-		}
+-
+-		if (ip->flags & INFTL_BINARY)
+-			parts[numparts].name = " DiskOnChip BDK partition";
+-		else
+-			parts[numparts].name = " DiskOnChip BDTL partition";
+-		parts[numparts].offset = ip->firstUnit << vshift;
+-		parts[numparts].size = (1 + ip->lastUnit - ip->firstUnit) << vshift;
+-		numparts++;
+-		if (ip->lastUnit > lastvunit)
+-			lastvunit = ip->lastUnit;
+-		if (ip->flags & INFTL_LAST)
+-			break;
+-	}
+-	lastvunit++;
+-	if ((lastvunit << vshift) < end) {
+-		parts[numparts].name = " DiskOnChip Remainder partition";
+-		parts[numparts].offset = lastvunit << vshift;
+-		parts[numparts].size = end - parts[numparts].offset;
+-		numparts++;
+-	}
+-	ret = numparts;
+- out:
+-	kfree(buf);
+-	return ret;
+-}
+-
+-static int __init nftl_scan_bbt(struct mtd_info *mtd)
+-{
+-	int ret, numparts;
+-	struct nand_chip *this = mtd_to_nand(mtd);
+-	struct doc_priv *doc = nand_get_controller_data(this);
+-	struct mtd_partition parts[2];
+-
+-	memset((char *)parts, 0, sizeof(parts));
+-	/* On NFTL, we have to find the media headers before we can read the
+-	   BBTs, since they're stored in the media header eraseblocks. */
+-	numparts = nftl_partscan(mtd, parts);
+-	if (!numparts)
+-		return -EIO;
+-	this->bbt_td->options = NAND_BBT_ABSPAGE | NAND_BBT_8BIT |
+-				NAND_BBT_SAVECONTENT | NAND_BBT_WRITE |
+-				NAND_BBT_VERSION;
+-	this->bbt_td->veroffs = 7;
+-	this->bbt_td->pages[0] = doc->mh0_page + 1;
+-	if (doc->mh1_page != -1) {
+-		this->bbt_md->options = NAND_BBT_ABSPAGE | NAND_BBT_8BIT |
+-					NAND_BBT_SAVECONTENT | NAND_BBT_WRITE |
+-					NAND_BBT_VERSION;
+-		this->bbt_md->veroffs = 7;
+-		this->bbt_md->pages[0] = doc->mh1_page + 1;
+-	} else {
+-		this->bbt_md = NULL;
+-	}
+-
+-	ret = this->scan_bbt(mtd);
+-	if (ret)
+-		return ret;
+-
+-	return mtd_device_register(mtd, parts, no_autopart ? 0 : numparts);
+-}
+-
+-static int __init inftl_scan_bbt(struct mtd_info *mtd)
+-{
+-	int ret, numparts;
+-	struct nand_chip *this = mtd_to_nand(mtd);
+-	struct doc_priv *doc = nand_get_controller_data(this);
+-	struct mtd_partition parts[5];
+-
+-	if (this->numchips > doc->chips_per_floor) {
+-		printk(KERN_ERR "Multi-floor INFTL devices not yet supported.\n");
+-		return -EIO;
+-	}
+-
+-	if (DoC_is_MillenniumPlus(doc)) {
+-		this->bbt_td->options = NAND_BBT_2BIT | NAND_BBT_ABSPAGE;
+-		if (inftl_bbt_write)
+-			this->bbt_td->options |= NAND_BBT_WRITE;
+-		this->bbt_td->pages[0] = 2;
+-		this->bbt_md = NULL;
+-	} else {
+-		this->bbt_td->options = NAND_BBT_LASTBLOCK | NAND_BBT_8BIT | NAND_BBT_VERSION;
+-		if (inftl_bbt_write)
+-			this->bbt_td->options |= NAND_BBT_WRITE;
+-		this->bbt_td->offs = 8;
+-		this->bbt_td->len = 8;
+-		this->bbt_td->veroffs = 7;
+-		this->bbt_td->maxblocks = INFTL_BBT_RESERVED_BLOCKS;
+-		this->bbt_td->reserved_block_code = 0x01;
+-		this->bbt_td->pattern = "MSYS_BBT";
+-
+-		this->bbt_md->options = NAND_BBT_LASTBLOCK | NAND_BBT_8BIT | NAND_BBT_VERSION;
+-		if (inftl_bbt_write)
+-			this->bbt_md->options |= NAND_BBT_WRITE;
+-		this->bbt_md->offs = 8;
+-		this->bbt_md->len = 8;
+-		this->bbt_md->veroffs = 7;
+-		this->bbt_md->maxblocks = INFTL_BBT_RESERVED_BLOCKS;
+-		this->bbt_md->reserved_block_code = 0x01;
+-		this->bbt_md->pattern = "TBB_SYSM";
+-	}
+-
+-	ret = this->scan_bbt(mtd);
+-	if (ret)
+-		return ret;
+-
+-	memset((char *)parts, 0, sizeof(parts));
+-	numparts = inftl_partscan(mtd, parts);
+-	/* At least for now, require the INFTL Media Header.  We could probably
+-	   do without it for non-INFTL use, since all it gives us is
+-	   autopartitioning, but I want to give it more thought. */
+-	if (!numparts)
+-		return -EIO;
+-	return mtd_device_register(mtd, parts, no_autopart ? 0 : numparts);
+-}
+-
+-static inline int __init doc2000_init(struct mtd_info *mtd)
+-{
+-	struct nand_chip *this = mtd_to_nand(mtd);
+-	struct doc_priv *doc = nand_get_controller_data(this);
+-
+-	this->read_byte = doc2000_read_byte;
+-	this->write_buf = doc2000_writebuf;
+-	this->read_buf = doc2000_readbuf;
+-	doc->late_init = nftl_scan_bbt;
+-
+-	doc->CDSNControl = CDSN_CTRL_FLASH_IO | CDSN_CTRL_ECC_IO;
+-	doc2000_count_chips(mtd);
+-	mtd->name = "DiskOnChip 2000 (NFTL Model)";
+-	return (4 * doc->chips_per_floor);
+-}
+-
+-static inline int __init doc2001_init(struct mtd_info *mtd)
+-{
+-	struct nand_chip *this = mtd_to_nand(mtd);
+-	struct doc_priv *doc = nand_get_controller_data(this);
+-
+-	this->read_byte = doc2001_read_byte;
+-	this->write_buf = doc2001_writebuf;
+-	this->read_buf = doc2001_readbuf;
+-
+-	ReadDOC(doc->virtadr, ChipID);
+-	ReadDOC(doc->virtadr, ChipID);
+-	ReadDOC(doc->virtadr, ChipID);
+-	if (ReadDOC(doc->virtadr, ChipID) != DOC_ChipID_DocMil) {
+-		/* It's not a Millennium; it's one of the newer
+-		   DiskOnChip 2000 units with a similar ASIC.
+-		   Treat it like a Millennium, except that it
+-		   can have multiple chips. */
+-		doc2000_count_chips(mtd);
+-		mtd->name = "DiskOnChip 2000 (INFTL Model)";
+-		doc->late_init = inftl_scan_bbt;
+-		return (4 * doc->chips_per_floor);
+-	} else {
+-		/* Bog-standard Millennium */
+-		doc->chips_per_floor = 1;
+-		mtd->name = "DiskOnChip Millennium";
+-		doc->late_init = nftl_scan_bbt;
+-		return 1;
+-	}
+-}
+-
+-static inline int __init doc2001plus_init(struct mtd_info *mtd)
+-{
+-	struct nand_chip *this = mtd_to_nand(mtd);
+-	struct doc_priv *doc = nand_get_controller_data(this);
+-
+-	this->read_byte = doc2001plus_read_byte;
+-	this->write_buf = doc2001plus_writebuf;
+-	this->read_buf = doc2001plus_readbuf;
+-	doc->late_init = inftl_scan_bbt;
+-	this->cmd_ctrl = NULL;
+-	this->select_chip = doc2001plus_select_chip;
+-	this->cmdfunc = doc2001plus_command;
+-	this->ecc.hwctl = doc2001plus_enable_hwecc;
+-
+-	doc->chips_per_floor = 1;
+-	mtd->name = "DiskOnChip Millennium Plus";
+-
+-	return 1;
+-}
+-
+-static int __init doc_probe(unsigned long physadr)
+-{
+-	unsigned char ChipID;
+-	struct mtd_info *mtd;
+-	struct nand_chip *nand;
+-	struct doc_priv *doc;
+-	void __iomem *virtadr;
+-	unsigned char save_control;
+-	unsigned char tmp, tmpb, tmpc;
+-	int reg, len, numchips;
+-	int ret = 0;
+-
+-	if (!request_mem_region(physadr, DOC_IOREMAP_LEN, "DiskOnChip"))
+-		return -EBUSY;
+-	virtadr = ioremap(physadr, DOC_IOREMAP_LEN);
+-	if (!virtadr) {
+-		printk(KERN_ERR "Diskonchip ioremap failed: 0x%x bytes at 0x%lx\n", DOC_IOREMAP_LEN, physadr);
+-		ret = -EIO;
+-		goto error_ioremap;
+-	}
+-
+-	/* It's not possible to cleanly detect the DiskOnChip - the
+-	 * bootup procedure will put the device into reset mode, and
+-	 * it's not possible to talk to it without actually writing
+-	 * to the DOCControl register. So we store the current contents
+-	 * of the DOCControl register's location, in case we later decide
+-	 * that it's not a DiskOnChip, and want to put it back how we
+-	 * found it.
+-	 */
+-	save_control = ReadDOC(virtadr, DOCControl);
+-
+-	/* Reset the DiskOnChip ASIC */
+-	WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, virtadr, DOCControl);
+-	WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, virtadr, DOCControl);
+-
+-	/* Enable the DiskOnChip ASIC */
+-	WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, virtadr, DOCControl);
+-	WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, virtadr, DOCControl);
+-
+-	ChipID = ReadDOC(virtadr, ChipID);
+-
+-	switch (ChipID) {
+-	case DOC_ChipID_Doc2k:
+-		reg = DoC_2k_ECCStatus;
+-		break;
+-	case DOC_ChipID_DocMil:
+-		reg = DoC_ECCConf;
+-		break;
+-	case DOC_ChipID_DocMilPlus16:
+-	case DOC_ChipID_DocMilPlus32:
+-	case 0:
+-		/* Possible Millennium Plus, need to do more checks */
+-		/* Possibly release from power down mode */
+-		for (tmp = 0; (tmp < 4); tmp++)
+-			ReadDOC(virtadr, Mplus_Power);
+-
+-		/* Reset the Millennium Plus ASIC */
+-		tmp = DOC_MODE_RESET | DOC_MODE_MDWREN | DOC_MODE_RST_LAT | DOC_MODE_BDECT;
+-		WriteDOC(tmp, virtadr, Mplus_DOCControl);
+-		WriteDOC(~tmp, virtadr, Mplus_CtrlConfirm);
+-
+-		mdelay(1);
+-		/* Enable the Millennium Plus ASIC */
+-		tmp = DOC_MODE_NORMAL | DOC_MODE_MDWREN | DOC_MODE_RST_LAT | DOC_MODE_BDECT;
+-		WriteDOC(tmp, virtadr, Mplus_DOCControl);
+-		WriteDOC(~tmp, virtadr, Mplus_CtrlConfirm);
+-		mdelay(1);
+-
+-		ChipID = ReadDOC(virtadr, ChipID);
+-
+-		switch (ChipID) {
+-		case DOC_ChipID_DocMilPlus16:
+-			reg = DoC_Mplus_Toggle;
+-			break;
+-		case DOC_ChipID_DocMilPlus32:
+-			printk(KERN_ERR "DiskOnChip Millennium Plus 32MB is not supported, ignoring.\n");
+-		default:
+-			ret = -ENODEV;
+-			goto notfound;
+-		}
+-		break;
+-
+-	default:
+-		ret = -ENODEV;
+-		goto notfound;
+-	}
+-	/* Check the TOGGLE bit in the ECC register */
+-	tmp = ReadDOC_(virtadr, reg) & DOC_TOGGLE_BIT;
+-	tmpb = ReadDOC_(virtadr, reg) & DOC_TOGGLE_BIT;
+-	tmpc = ReadDOC_(virtadr, reg) & DOC_TOGGLE_BIT;
+-	if ((tmp == tmpb) || (tmp != tmpc)) {
+-		printk(KERN_WARNING "Possible DiskOnChip at 0x%lx failed TOGGLE test, dropping.\n", physadr);
+-		ret = -ENODEV;
+-		goto notfound;
+-	}
+-
+-	for (mtd = doclist; mtd; mtd = doc->nextdoc) {
+-		unsigned char oldval;
+-		unsigned char newval;
+-		nand = mtd_to_nand(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
+-		   to one chip's alias resolution register change the value on
+-		   the other chip, they're the same chip. */
+-		if (ChipID == DOC_ChipID_DocMilPlus16) {
+-			oldval = ReadDOC(doc->virtadr, Mplus_AliasResolution);
+-			newval = ReadDOC(virtadr, Mplus_AliasResolution);
+-		} else {
+-			oldval = ReadDOC(doc->virtadr, AliasResolution);
+-			newval = ReadDOC(virtadr, AliasResolution);
+-		}
+-		if (oldval != newval)
+-			continue;
+-		if (ChipID == DOC_ChipID_DocMilPlus16) {
+-			WriteDOC(~newval, virtadr, Mplus_AliasResolution);
+-			oldval = ReadDOC(doc->virtadr, Mplus_AliasResolution);
+-			WriteDOC(newval, virtadr, Mplus_AliasResolution);	// restore it
+-		} else {
+-			WriteDOC(~newval, virtadr, AliasResolution);
+-			oldval = ReadDOC(doc->virtadr, AliasResolution);
+-			WriteDOC(newval, virtadr, AliasResolution);	// restore it
+-		}
+-		newval = ~newval;
+-		if (oldval == newval) {
+-			printk(KERN_DEBUG "Found alias of DOC at 0x%lx to 0x%lx\n", doc->physadr, physadr);
+-			goto notfound;
+-		}
+-	}
+-
+-	printk(KERN_NOTICE "DiskOnChip found at 0x%lx\n", physadr);
+-
+-	len = sizeof(struct nand_chip) + sizeof(struct doc_priv) +
+-	      (2 * sizeof(struct nand_bbt_descr));
+-	nand = kzalloc(len, GFP_KERNEL);
+-	if (!nand) {
+-		ret = -ENOMEM;
+-		goto fail;
+-	}
+-
+-	mtd			= nand_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;
+-
+-	mtd->owner		= THIS_MODULE;
+-	mtd_set_ooblayout(mtd, &doc200x_ooblayout_ops);
+-
+-	nand_set_controller_data(nand, doc);
+-	nand->select_chip	= doc200x_select_chip;
+-	nand->cmd_ctrl		= doc200x_hwcontrol;
+-	nand->dev_ready		= doc200x_dev_ready;
+-	nand->waitfunc		= doc200x_wait;
+-	nand->block_bad		= doc200x_block_bad;
+-	nand->ecc.hwctl		= doc200x_enable_hwecc;
+-	nand->ecc.calculate	= doc200x_calculate_ecc;
+-	nand->ecc.correct	= doc200x_correct_data;
+-
+-	nand->ecc.mode		= NAND_ECC_HW_SYNDROME;
+-	nand->ecc.size		= 512;
+-	nand->ecc.bytes		= 6;
+-	nand->ecc.strength	= 2;
+-	nand->ecc.options	= NAND_ECC_GENERIC_ERASED_CHECK;
+-	nand->bbt_options	= NAND_BBT_USE_FLASH;
+-	/* Skip the automatic BBT scan so we can run it manually */
+-	nand->options		|= NAND_SKIP_BBTSCAN;
+-
+-	doc->physadr		= physadr;
+-	doc->virtadr		= virtadr;
+-	doc->ChipID		= ChipID;
+-	doc->curfloor		= -1;
+-	doc->curchip		= -1;
+-	doc->mh0_page		= -1;
+-	doc->mh1_page		= -1;
+-	doc->nextdoc		= doclist;
+-
+-	if (ChipID == DOC_ChipID_Doc2k)
+-		numchips = doc2000_init(mtd);
+-	else if (ChipID == DOC_ChipID_DocMilPlus16)
+-		numchips = doc2001plus_init(mtd);
+-	else
+-		numchips = doc2001_init(mtd);
+-
+-	if ((ret = nand_scan(mtd, numchips)) || (ret = doc->late_init(mtd))) {
+-		/* DBB note: i believe nand_release is necessary here, as
+-		   buffers may have been allocated in nand_base.  Check with
+-		   Thomas. FIX ME! */
+-		/* nand_release will call mtd_device_unregister, but we
+-		   haven't yet added it.  This is handled without incident by
+-		   mtd_device_unregister, as far as I can tell. */
+-		nand_release(mtd);
+-		kfree(nand);
+-		goto fail;
+-	}
+-
+-	/* Success! */
+-	doclist = mtd;
+-	return 0;
+-
+- notfound:
+-	/* Put back the contents of the DOCControl register, in case it's not
+-	   actually a DiskOnChip.  */
+-	WriteDOC(save_control, virtadr, DOCControl);
+- fail:
+-	iounmap(virtadr);
+-
+-error_ioremap:
+-	release_mem_region(physadr, DOC_IOREMAP_LEN);
+-
+-	return ret;
+-}
+-
+-static void release_nanddoc(void)
+-{
+-	struct mtd_info *mtd, *nextmtd;
+-	struct nand_chip *nand;
+-	struct doc_priv *doc;
+-
+-	for (mtd = doclist; mtd; mtd = nextmtd) {
+-		nand = mtd_to_nand(mtd);
+-		doc = nand_get_controller_data(nand);
+-
+-		nextmtd = doc->nextdoc;
+-		nand_release(mtd);
+-		iounmap(doc->virtadr);
+-		release_mem_region(doc->physadr, DOC_IOREMAP_LEN);
+-		kfree(nand);
+-	}
+-}
+-
+-static int __init init_nanddoc(void)
+-{
+-	int i, ret = 0;
+-
+-	/* We could create the decoder on demand, if memory is a concern.
+-	 * This way we have it handy, if an error happens
+-	 *
+-	 * Symbolsize is 10 (bits)
+-	 * Primitve polynomial is x^10+x^3+1
+-	 * first consecutive root is 510
+-	 * primitve element to generate roots = 1
+-	 * generator polinomial degree = 4
+-	 */
+-	rs_decoder = init_rs(10, 0x409, FCR, 1, NROOTS);
+-	if (!rs_decoder) {
+-		printk(KERN_ERR "DiskOnChip: Could not create a RS decoder\n");
+-		return -ENOMEM;
+-	}
+-
+-	if (doc_config_location) {
+-		printk(KERN_INFO "Using configured DiskOnChip probe address 0x%lx\n", doc_config_location);
+-		ret = doc_probe(doc_config_location);
+-		if (ret < 0)
+-			goto outerr;
+-	} else {
+-		for (i = 0; (doc_locations[i] != 0xffffffff); i++) {
+-			doc_probe(doc_locations[i]);
+-		}
+-	}
+-	/* No banner message any more. Print a message if no DiskOnChip
+-	   found, so the user knows we at least tried. */
+-	if (!doclist) {
+-		printk(KERN_INFO "No valid DiskOnChip devices found\n");
+-		ret = -ENODEV;
+-		goto outerr;
+-	}
+-	return 0;
+- outerr:
+-	free_rs(rs_decoder);
+-	return ret;
+-}
+-
+-static void __exit cleanup_nanddoc(void)
+-{
+-	/* Cleanup the nand/DoC resources */
+-	release_nanddoc();
+-
+-	/* Free the reed solomon resources */
+-	if (rs_decoder) {
+-		free_rs(rs_decoder);
+-	}
+-}
+-
+-module_init(init_nanddoc);
+-module_exit(cleanup_nanddoc);
+-
+-MODULE_LICENSE("GPL");
+-MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
+-MODULE_DESCRIPTION("M-Systems DiskOnChip 2000, Millennium and Millennium Plus device driver");
+diff --git a/drivers/mtd/nand/docg4.c b/drivers/mtd/nand/docg4.c
+deleted file mode 100644
+index 2436cbc..0000000
+--- a/drivers/mtd/nand/docg4.c
++++ /dev/null
+@@ -1,1412 +0,0 @@
+-/*
+- *  Copyright © 2012 Mike Dunn <mikedunn@newsguy.com>
+- *
+- * mtd nand driver for M-Systems DiskOnChip G4
+- *
+- * 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.
+- *
+- * Tested on the Palm Treo 680.  The G4 is also present on Toshiba Portege, Asus
+- * P526, some HTC smartphones (Wizard, Prophet, ...), O2 XDA Zinc, maybe others.
+- * Should work on these as well.  Let me know!
+- *
+- * TODO:
+- *
+- *  Mechanism for management of password-protected areas
+- *
+- *  Hamming ecc when reading oob only
+- *
+- *  According to the M-Sys documentation, this device is also available in a
+- *  "dual-die" configuration having a 256MB capacity, but no mechanism for
+- *  detecting this variant is documented.  Currently this driver assumes 128MB
+- *  capacity.
+- *
+- *  Support for multiple cascaded devices ("floors").  Not sure which gadgets
+- *  contain multiple G4s in a cascaded configuration, if any.
+- *
+- */
+-
+-#include <linux/kernel.h>
+-#include <linux/slab.h>
+-#include <linux/init.h>
+-#include <linux/string.h>
+-#include <linux/sched.h>
+-#include <linux/delay.h>
+-#include <linux/module.h>
+-#include <linux/export.h>
+-#include <linux/platform_device.h>
+-#include <linux/io.h>
+-#include <linux/bitops.h>
+-#include <linux/mtd/partitions.h>
+-#include <linux/mtd/mtd.h>
+-#include <linux/mtd/rawnand.h>
+-#include <linux/bch.h>
+-#include <linux/bitrev.h>
+-#include <linux/jiffies.h>
+-
+-/*
+- * In "reliable mode" consecutive 2k pages are used in parallel (in some
+- * fashion) to store the same data.  The data can be read back from the
+- * even-numbered pages in the normal manner; odd-numbered pages will appear to
+- * contain junk.  Systems that boot from the docg4 typically write the secondary
+- * program loader (SPL) code in this mode.  The SPL is loaded by the initial
+- * program loader (IPL, stored in the docg4's 2k NOR-like region that is mapped
+- * to the reset vector address).  This module parameter enables you to use this
+- * driver to write the SPL.  When in this mode, no more than 2k of data can be
+- * written at a time, because the addresses do not increment in the normal
+- * manner, and the starting offset must be within an even-numbered 2k region;
+- * i.e., invalid starting offsets are 0x800, 0xa00, 0xc00, 0xe00, 0x1800,
+- * 0x1a00, ...  Reliable mode is a special case and should not be used unless
+- * you know what you're doing.
+- */
+-static bool reliable_mode;
+-module_param(reliable_mode, bool, 0);
+-MODULE_PARM_DESC(reliable_mode, "pages are programmed in reliable mode");
+-
+-/*
+- * You'll want to ignore badblocks if you're reading a partition that contains
+- * data written by the TrueFFS library (i.e., by PalmOS, Windows, etc), since
+- * it does not use mtd nand's method for marking bad blocks (using oob area).
+- * This will also skip the check of the "page written" flag.
+- */
+-static bool ignore_badblocks;
+-module_param(ignore_badblocks, bool, 0);
+-MODULE_PARM_DESC(ignore_badblocks, "no badblock checking performed");
+-
+-struct docg4_priv {
+-	struct mtd_info	*mtd;
+-	struct device *dev;
+-	void __iomem *virtadr;
+-	int status;
+-	struct {
+-		unsigned int command;
+-		int column;
+-		int page;
+-	} last_command;
+-	uint8_t oob_buf[16];
+-	uint8_t ecc_buf[7];
+-	int oob_page;
+-	struct bch_control *bch;
+-};
+-
+-/*
+- * Defines prefixed with DOCG4 are unique to the diskonchip G4.  All others are
+- * shared with other diskonchip devices (P3, G3 at least).
+- *
+- * Functions with names prefixed with docg4_ are mtd / nand interface functions
+- * (though they may also be called internally).  All others are internal.
+- */
+-
+-#define DOC_IOSPACE_DATA		0x0800
+-
+-/* register offsets */
+-#define DOC_CHIPID			0x1000
+-#define DOC_DEVICESELECT		0x100a
+-#define DOC_ASICMODE			0x100c
+-#define DOC_DATAEND			0x101e
+-#define DOC_NOP				0x103e
+-
+-#define DOC_FLASHSEQUENCE		0x1032
+-#define DOC_FLASHCOMMAND		0x1034
+-#define DOC_FLASHADDRESS		0x1036
+-#define DOC_FLASHCONTROL		0x1038
+-#define DOC_ECCCONF0			0x1040
+-#define DOC_ECCCONF1			0x1042
+-#define DOC_HAMMINGPARITY		0x1046
+-#define DOC_BCH_SYNDROM(idx)		(0x1048 + idx)
+-
+-#define DOC_ASICMODECONFIRM		0x1072
+-#define DOC_CHIPID_INV			0x1074
+-#define DOC_POWERMODE			0x107c
+-
+-#define DOCG4_MYSTERY_REG		0x1050
+-
+-/* apparently used only to write oob bytes 6 and 7 */
+-#define DOCG4_OOB_6_7			0x1052
+-
+-/* DOC_FLASHSEQUENCE register commands */
+-#define DOC_SEQ_RESET			0x00
+-#define DOCG4_SEQ_PAGE_READ		0x03
+-#define DOCG4_SEQ_FLUSH			0x29
+-#define DOCG4_SEQ_PAGEWRITE		0x16
+-#define DOCG4_SEQ_PAGEPROG		0x1e
+-#define DOCG4_SEQ_BLOCKERASE		0x24
+-#define DOCG4_SEQ_SETMODE		0x45
+-
+-/* DOC_FLASHCOMMAND register commands */
+-#define DOCG4_CMD_PAGE_READ             0x00
+-#define DOC_CMD_ERASECYCLE2		0xd0
+-#define DOCG4_CMD_FLUSH                 0x70
+-#define DOCG4_CMD_READ2                 0x30
+-#define DOC_CMD_PROG_BLOCK_ADDR		0x60
+-#define DOCG4_CMD_PAGEWRITE		0x80
+-#define DOC_CMD_PROG_CYCLE2		0x10
+-#define DOCG4_CMD_FAST_MODE		0xa3 /* functionality guessed */
+-#define DOC_CMD_RELIABLE_MODE		0x22
+-#define DOC_CMD_RESET			0xff
+-
+-/* DOC_POWERMODE register bits */
+-#define DOC_POWERDOWN_READY		0x80
+-
+-/* DOC_FLASHCONTROL register bits */
+-#define DOC_CTRL_CE			0x10
+-#define DOC_CTRL_UNKNOWN		0x40
+-#define DOC_CTRL_FLASHREADY		0x01
+-
+-/* DOC_ECCCONF0 register bits */
+-#define DOC_ECCCONF0_READ_MODE		0x8000
+-#define DOC_ECCCONF0_UNKNOWN		0x2000
+-#define DOC_ECCCONF0_ECC_ENABLE	        0x1000
+-#define DOC_ECCCONF0_DATA_BYTES_MASK	0x07ff
+-
+-/* DOC_ECCCONF1 register bits */
+-#define DOC_ECCCONF1_BCH_SYNDROM_ERR	0x80
+-#define DOC_ECCCONF1_ECC_ENABLE         0x07
+-#define DOC_ECCCONF1_PAGE_IS_WRITTEN	0x20
+-
+-/* DOC_ASICMODE register bits */
+-#define DOC_ASICMODE_RESET		0x00
+-#define DOC_ASICMODE_NORMAL		0x01
+-#define DOC_ASICMODE_POWERDOWN		0x02
+-#define DOC_ASICMODE_MDWREN		0x04
+-#define DOC_ASICMODE_BDETCT_RESET	0x08
+-#define DOC_ASICMODE_RSTIN_RESET	0x10
+-#define DOC_ASICMODE_RAM_WE		0x20
+-
+-/* good status values read after read/write/erase operations */
+-#define DOCG4_PROGSTATUS_GOOD          0x51
+-#define DOCG4_PROGSTATUS_GOOD_2        0xe0
+-
+-/*
+- * On read operations (page and oob-only), the first byte read from I/O reg is a
+- * status.  On error, it reads 0x73; otherwise, it reads either 0x71 (first read
+- * after reset only) or 0x51, so bit 1 is presumed to be an error indicator.
+- */
+-#define DOCG4_READ_ERROR           0x02 /* bit 1 indicates read error */
+-
+-/* anatomy of the device */
+-#define DOCG4_CHIP_SIZE        0x8000000
+-#define DOCG4_PAGE_SIZE        0x200
+-#define DOCG4_PAGES_PER_BLOCK  0x200
+-#define DOCG4_BLOCK_SIZE       (DOCG4_PAGES_PER_BLOCK * DOCG4_PAGE_SIZE)
+-#define DOCG4_NUMBLOCKS        (DOCG4_CHIP_SIZE / DOCG4_BLOCK_SIZE)
+-#define DOCG4_OOB_SIZE         0x10
+-#define DOCG4_CHIP_SHIFT       27    /* log_2(DOCG4_CHIP_SIZE) */
+-#define DOCG4_PAGE_SHIFT       9     /* log_2(DOCG4_PAGE_SIZE) */
+-#define DOCG4_ERASE_SHIFT      18    /* log_2(DOCG4_BLOCK_SIZE) */
+-
+-/* all but the last byte is included in ecc calculation */
+-#define DOCG4_BCH_SIZE         (DOCG4_PAGE_SIZE + DOCG4_OOB_SIZE - 1)
+-
+-#define DOCG4_USERDATA_LEN     520 /* 512 byte page plus 8 oob avail to user */
+-
+-/* expected values from the ID registers */
+-#define DOCG4_IDREG1_VALUE     0x0400
+-#define DOCG4_IDREG2_VALUE     0xfbff
+-
+-/* primitive polynomial used to build the Galois field used by hw ecc gen */
+-#define DOCG4_PRIMITIVE_POLY   0x4443
+-
+-#define DOCG4_M                14  /* Galois field is of order 2^14 */
+-#define DOCG4_T                4   /* BCH alg corrects up to 4 bit errors */
+-
+-#define DOCG4_FACTORY_BBT_PAGE 16 /* page where read-only factory bbt lives */
+-#define DOCG4_REDUNDANT_BBT_PAGE 24 /* page where redundant factory bbt lives */
+-
+-/*
+- * Bytes 0, 1 are used as badblock marker.
+- * Bytes 2 - 6 are available to the user.
+- * Byte 7 is hamming ecc for first 7 oob bytes only.
+- * Bytes 8 - 14 are hw-generated ecc covering entire page + oob bytes 0 - 14.
+- * Byte 15 (the last) is used by the driver as a "page written" flag.
+- */
+-static int docg4_ooblayout_ecc(struct mtd_info *mtd, int section,
+-			       struct mtd_oob_region *oobregion)
+-{
+-	if (section)
+-		return -ERANGE;
+-
+-	oobregion->offset = 7;
+-	oobregion->length = 9;
+-
+-	return 0;
+-}
+-
+-static int docg4_ooblayout_free(struct mtd_info *mtd, int section,
+-				struct mtd_oob_region *oobregion)
+-{
+-	if (section)
+-		return -ERANGE;
+-
+-	oobregion->offset = 2;
+-	oobregion->length = 5;
+-
+-	return 0;
+-}
+-
+-static const struct mtd_ooblayout_ops docg4_ooblayout_ops = {
+-	.ecc = docg4_ooblayout_ecc,
+-	.free = docg4_ooblayout_free,
+-};
+-
+-/*
+- * The device has a nop register which M-Sys claims is for the purpose of
+- * inserting precise delays.  But beware; at least some operations fail if the
+- * nop writes are replaced with a generic delay!
+- */
+-static inline void write_nop(void __iomem *docptr)
+-{
+-	writew(0, docptr + DOC_NOP);
+-}
+-
+-static void docg4_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+-{
+-	int i;
+-	struct nand_chip *nand = mtd_to_nand(mtd);
+-	uint16_t *p = (uint16_t *) buf;
+-	len >>= 1;
+-
+-	for (i = 0; i < len; i++)
+-		p[i] = readw(nand->IO_ADDR_R);
+-}
+-
+-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);
+-	uint16_t *p = (uint16_t *) buf;
+-	len >>= 1;
+-
+-	for (i = 0; i < len; i++)
+-		writew(p[i], nand->IO_ADDR_W);
+-}
+-
+-static int poll_status(struct docg4_priv *doc)
+-{
+-	/*
+-	 * Busy-wait for the FLASHREADY bit to be set in the FLASHCONTROL
+-	 * register.  Operations known to take a long time (e.g., block erase)
+-	 * should sleep for a while before calling this.
+-	 */
+-
+-	uint16_t flash_status;
+-	unsigned long timeo;
+-	void __iomem *docptr = doc->virtadr;
+-
+-	dev_dbg(doc->dev, "%s...\n", __func__);
+-
+-	/* hardware quirk requires reading twice initially */
+-	flash_status = readw(docptr + DOC_FLASHCONTROL);
+-
+-	timeo = jiffies + msecs_to_jiffies(200); /* generous timeout */
+-	do {
+-		cpu_relax();
+-		flash_status = readb(docptr + DOC_FLASHCONTROL);
+-	} while (!(flash_status & DOC_CTRL_FLASHREADY) &&
+-		 time_before(jiffies, timeo));
+-
+-	if (unlikely(!(flash_status & DOC_CTRL_FLASHREADY))) {
+-		dev_err(doc->dev, "%s: timed out!\n", __func__);
+-		return NAND_STATUS_FAIL;
+-	}
+-
+-	return 0;
+-}
+-
+-
+-static int docg4_wait(struct mtd_info *mtd, struct nand_chip *nand)
+-{
+-
+-	struct docg4_priv *doc = nand_get_controller_data(nand);
+-	int status = NAND_STATUS_WP;       /* inverse logic?? */
+-	dev_dbg(doc->dev, "%s...\n", __func__);
+-
+-	/* report any previously unreported error */
+-	if (doc->status) {
+-		status |= doc->status;
+-		doc->status = 0;
+-		return status;
+-	}
+-
+-	status |= poll_status(doc);
+-	return status;
+-}
+-
+-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 docg4_priv *doc = nand_get_controller_data(nand);
+-	void __iomem *docptr = doc->virtadr;
+-
+-	dev_dbg(doc->dev, "%s: chip %d\n", __func__, chip);
+-
+-	if (chip < 0)
+-		return;		/* deselected */
+-
+-	if (chip > 0)
+-		dev_warn(doc->dev, "multiple floors currently unsupported\n");
+-
+-	writew(0, docptr + DOC_DEVICESELECT);
+-}
+-
+-static void reset(struct mtd_info *mtd)
+-{
+-	/* full device reset */
+-
+-	struct nand_chip *nand = mtd_to_nand(mtd);
+-	struct docg4_priv *doc = nand_get_controller_data(nand);
+-	void __iomem *docptr = doc->virtadr;
+-
+-	writew(DOC_ASICMODE_RESET | DOC_ASICMODE_MDWREN,
+-	       docptr + DOC_ASICMODE);
+-	writew(~(DOC_ASICMODE_RESET | DOC_ASICMODE_MDWREN),
+-	       docptr + DOC_ASICMODECONFIRM);
+-	write_nop(docptr);
+-
+-	writew(DOC_ASICMODE_NORMAL | DOC_ASICMODE_MDWREN,
+-	       docptr + DOC_ASICMODE);
+-	writew(~(DOC_ASICMODE_NORMAL | DOC_ASICMODE_MDWREN),
+-	       docptr + DOC_ASICMODECONFIRM);
+-
+-	writew(DOC_ECCCONF1_ECC_ENABLE, docptr + DOC_ECCCONF1);
+-
+-	poll_status(doc);
+-}
+-
+-static void read_hw_ecc(void __iomem *docptr, uint8_t *ecc_buf)
+-{
+-	/* read the 7 hw-generated ecc bytes */
+-
+-	int i;
+-	for (i = 0; i < 7; i++) { /* hw quirk; read twice */
+-		ecc_buf[i] = readb(docptr + DOC_BCH_SYNDROM(i));
+-		ecc_buf[i] = readb(docptr + DOC_BCH_SYNDROM(i));
+-	}
+-}
+-
+-static int correct_data(struct mtd_info *mtd, uint8_t *buf, int page)
+-{
+-	/*
+-	 * Called after a page read when hardware reports bitflips.
+-	 * Up to four bitflips can be corrected.
+-	 */
+-
+-	struct nand_chip *nand = mtd_to_nand(mtd);
+-	struct docg4_priv *doc = nand_get_controller_data(nand);
+-	void __iomem *docptr = doc->virtadr;
+-	int i, numerrs, errpos[4];
+-	const uint8_t blank_read_hwecc[8] = {
+-		0xcf, 0x72, 0xfc, 0x1b, 0xa9, 0xc7, 0xb9, 0 };
+-
+-	read_hw_ecc(docptr, doc->ecc_buf); /* read 7 hw-generated ecc bytes */
+-
+-	/* check if read error is due to a blank page */
+-	if (!memcmp(doc->ecc_buf, blank_read_hwecc, 7))
+-		return 0;	/* yes */
+-
+-	/* skip additional check of "written flag" if ignore_badblocks */
+-	if (ignore_badblocks == false) {
+-
+-		/*
+-		 * If the hw ecc bytes are not those of a blank page, there's
+-		 * still a chance that the page is blank, but was read with
+-		 * errors.  Check the "written flag" in last oob byte, which
+-		 * is set to zero when a page is written.  If more than half
+-		 * the bits are set, assume a blank page.  Unfortunately, the
+-		 * bit flips(s) are not reported in stats.
+-		 */
+-
+-		if (nand->oob_poi[15]) {
+-			int bit, numsetbits = 0;
+-			unsigned long written_flag = nand->oob_poi[15];
+-			for_each_set_bit(bit, &written_flag, 8)
+-				numsetbits++;
+-			if (numsetbits > 4) { /* assume blank */
+-				dev_warn(doc->dev,
+-					 "error(s) in blank page "
+-					 "at offset %08x\n",
+-					 page * DOCG4_PAGE_SIZE);
+-				return 0;
+-			}
+-		}
+-	}
+-
+-	/*
+-	 * The hardware ecc unit produces oob_ecc ^ calc_ecc.  The kernel's bch
+-	 * algorithm is used to decode this.  However the hw operates on page
+-	 * data in a bit order that is the reverse of that of the bch alg,
+-	 * requiring that the bits be reversed on the result.  Thanks to Ivan
+-	 * Djelic for his analysis!
+-	 */
+-	for (i = 0; i < 7; i++)
+-		doc->ecc_buf[i] = bitrev8(doc->ecc_buf[i]);
+-
+-	numerrs = decode_bch(doc->bch, NULL, DOCG4_USERDATA_LEN, NULL,
+-			     doc->ecc_buf, NULL, errpos);
+-
+-	if (numerrs == -EBADMSG) {
+-		dev_warn(doc->dev, "uncorrectable errors at offset %08x\n",
+-			 page * DOCG4_PAGE_SIZE);
+-		return -EBADMSG;
+-	}
+-
+-	BUG_ON(numerrs < 0);	/* -EINVAL, or anything other than -EBADMSG */
+-
+-	/* undo last step in BCH alg (modulo mirroring not needed) */
+-	for (i = 0; i < numerrs; i++)
+-		errpos[i] = (errpos[i] & ~7)|(7-(errpos[i] & 7));
+-
+-	/* fix the errors */
+-	for (i = 0; i < numerrs; i++) {
+-
+-		/* ignore if error within oob ecc bytes */
+-		if (errpos[i] > DOCG4_USERDATA_LEN * 8)
+-			continue;
+-
+-		/* if error within oob area preceeding ecc bytes... */
+-		if (errpos[i] > DOCG4_PAGE_SIZE * 8)
+-			change_bit(errpos[i] - DOCG4_PAGE_SIZE * 8,
+-				   (unsigned long *)nand->oob_poi);
+-
+-		else    /* error in page data */
+-			change_bit(errpos[i], (unsigned long *)buf);
+-	}
+-
+-	dev_notice(doc->dev, "%d error(s) corrected at offset %08x\n",
+-		   numerrs, page * DOCG4_PAGE_SIZE);
+-
+-	return numerrs;
+-}
+-
+-static uint8_t docg4_read_byte(struct mtd_info *mtd)
+-{
+-	struct nand_chip *nand = mtd_to_nand(mtd);
+-	struct docg4_priv *doc = nand_get_controller_data(nand);
+-
+-	dev_dbg(doc->dev, "%s\n", __func__);
+-
+-	if (doc->last_command.command == NAND_CMD_STATUS) {
+-		int status;
+-
+-		/*
+-		 * Previous nand command was status request, so nand
+-		 * infrastructure code expects to read the status here.  If an
+-		 * error occurred in a previous operation, report it.
+-		 */
+-		doc->last_command.command = 0;
+-
+-		if (doc->status) {
+-			status = doc->status;
+-			doc->status = 0;
+-		}
+-
+-		/* why is NAND_STATUS_WP inverse logic?? */
+-		else
+-			status = NAND_STATUS_WP | NAND_STATUS_READY;
+-
+-		return status;
+-	}
+-
+-	dev_warn(doc->dev, "unexpected call to read_byte()\n");
+-
+-	return 0;
+-}
+-
+-static void write_addr(struct docg4_priv *doc, uint32_t docg4_addr)
+-{
+-	/* write the four address bytes packed in docg4_addr to the device */
+-
+-	void __iomem *docptr = doc->virtadr;
+-	writeb(docg4_addr & 0xff, docptr + DOC_FLASHADDRESS);
+-	docg4_addr >>= 8;
+-	writeb(docg4_addr & 0xff, docptr + DOC_FLASHADDRESS);
+-	docg4_addr >>= 8;
+-	writeb(docg4_addr & 0xff, docptr + DOC_FLASHADDRESS);
+-	docg4_addr >>= 8;
+-	writeb(docg4_addr & 0xff, docptr + DOC_FLASHADDRESS);
+-}
+-
+-static int read_progstatus(struct docg4_priv *doc)
+-{
+-	/*
+-	 * This apparently checks the status of programming.  Done after an
+-	 * erasure, and after page data is written.  On error, the status is
+-	 * saved, to be later retrieved by the nand infrastructure code.
+-	 */
+-	void __iomem *docptr = doc->virtadr;
+-
+-	/* status is read from the I/O reg */
+-	uint16_t status1 = readw(docptr + DOC_IOSPACE_DATA);
+-	uint16_t status2 = readw(docptr + DOC_IOSPACE_DATA);
+-	uint16_t status3 = readw(docptr + DOCG4_MYSTERY_REG);
+-
+-	dev_dbg(doc->dev, "docg4: %s: %02x %02x %02x\n",
+-	      __func__, status1, status2, status3);
+-
+-	if (status1 != DOCG4_PROGSTATUS_GOOD
+-	    || status2 != DOCG4_PROGSTATUS_GOOD_2
+-	    || status3 != DOCG4_PROGSTATUS_GOOD_2) {
+-		doc->status = NAND_STATUS_FAIL;
+-		dev_warn(doc->dev, "read_progstatus failed: "
+-			 "%02x, %02x, %02x\n", status1, status2, status3);
+-		return -EIO;
+-	}
+-	return 0;
+-}
+-
+-static int pageprog(struct mtd_info *mtd)
+-{
+-	/*
+-	 * Final step in writing a page.  Writes the contents of its
+-	 * internal buffer out to the flash array, or some such.
+-	 */
+-
+-	struct nand_chip *nand = mtd_to_nand(mtd);
+-	struct docg4_priv *doc = nand_get_controller_data(nand);
+-	void __iomem *docptr = doc->virtadr;
+-	int retval = 0;
+-
+-	dev_dbg(doc->dev, "docg4: %s\n", __func__);
+-
+-	writew(DOCG4_SEQ_PAGEPROG, docptr + DOC_FLASHSEQUENCE);
+-	writew(DOC_CMD_PROG_CYCLE2, docptr + DOC_FLASHCOMMAND);
+-	write_nop(docptr);
+-	write_nop(docptr);
+-
+-	/* Just busy-wait; usleep_range() slows things down noticeably. */
+-	poll_status(doc);
+-
+-	writew(DOCG4_SEQ_FLUSH, docptr + DOC_FLASHSEQUENCE);
+-	writew(DOCG4_CMD_FLUSH, docptr + DOC_FLASHCOMMAND);
+-	writew(DOC_ECCCONF0_READ_MODE | 4, docptr + DOC_ECCCONF0);
+-	write_nop(docptr);
+-	write_nop(docptr);
+-	write_nop(docptr);
+-	write_nop(docptr);
+-	write_nop(docptr);
+-
+-	retval = read_progstatus(doc);
+-	writew(0, docptr + DOC_DATAEND);
+-	write_nop(docptr);
+-	poll_status(doc);
+-	write_nop(docptr);
+-
+-	return retval;
+-}
+-
+-static void sequence_reset(struct mtd_info *mtd)
+-{
+-	/* common starting sequence for all operations */
+-
+-	struct nand_chip *nand = mtd_to_nand(mtd);
+-	struct docg4_priv *doc = nand_get_controller_data(nand);
+-	void __iomem *docptr = doc->virtadr;
+-
+-	writew(DOC_CTRL_UNKNOWN | DOC_CTRL_CE, docptr + DOC_FLASHCONTROL);
+-	writew(DOC_SEQ_RESET, docptr + DOC_FLASHSEQUENCE);
+-	writew(DOC_CMD_RESET, docptr + DOC_FLASHCOMMAND);
+-	write_nop(docptr);
+-	write_nop(docptr);
+-	poll_status(doc);
+-	write_nop(docptr);
+-}
+-
+-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 docg4_priv *doc = nand_get_controller_data(nand);
+-	void __iomem *docptr = doc->virtadr;
+-
+-	dev_dbg(doc->dev,
+-	      "docg4: %s: g4 page %08x\n", __func__, docg4_addr);
+-
+-	sequence_reset(mtd);
+-
+-	writew(DOCG4_SEQ_PAGE_READ, docptr + DOC_FLASHSEQUENCE);
+-	writew(DOCG4_CMD_PAGE_READ, docptr + DOC_FLASHCOMMAND);
+-	write_nop(docptr);
+-
+-	write_addr(doc, docg4_addr);
+-
+-	write_nop(docptr);
+-	writew(DOCG4_CMD_READ2, docptr + DOC_FLASHCOMMAND);
+-	write_nop(docptr);
+-	write_nop(docptr);
+-
+-	poll_status(doc);
+-}
+-
+-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 docg4_priv *doc = nand_get_controller_data(nand);
+-	void __iomem *docptr = doc->virtadr;
+-
+-	dev_dbg(doc->dev,
+-	      "docg4: %s: g4 addr: %x\n", __func__, docg4_addr);
+-	sequence_reset(mtd);
+-
+-	if (unlikely(reliable_mode)) {
+-		writew(DOCG4_SEQ_SETMODE, docptr + DOC_FLASHSEQUENCE);
+-		writew(DOCG4_CMD_FAST_MODE, docptr + DOC_FLASHCOMMAND);
+-		writew(DOC_CMD_RELIABLE_MODE, docptr + DOC_FLASHCOMMAND);
+-		write_nop(docptr);
+-	}
+-
+-	writew(DOCG4_SEQ_PAGEWRITE, docptr + DOC_FLASHSEQUENCE);
+-	writew(DOCG4_CMD_PAGEWRITE, docptr + DOC_FLASHCOMMAND);
+-	write_nop(docptr);
+-	write_addr(doc, docg4_addr);
+-	write_nop(docptr);
+-	write_nop(docptr);
+-	poll_status(doc);
+-}
+-
+-static uint32_t mtd_to_docg4_address(int page, int column)
+-{
+-	/*
+-	 * Convert mtd address to format used by the device, 32 bit packed.
+-	 *
+-	 * Some notes on G4 addressing... The M-Sys documentation on this device
+-	 * claims that pages are 2K in length, and indeed, the format of the
+-	 * address used by the device reflects that.  But within each page are
+-	 * four 512 byte "sub-pages", each with its own oob data that is
+-	 * read/written immediately after the 512 bytes of page data.  This oob
+-	 * data contains the ecc bytes for the preceeding 512 bytes.
+-	 *
+-	 * Rather than tell the mtd nand infrastructure that page size is 2k,
+-	 * with four sub-pages each, we engage in a little subterfuge and tell
+-	 * the infrastructure code that pages are 512 bytes in size.  This is
+-	 * done because during the course of reverse-engineering the device, I
+-	 * never observed an instance where an entire 2K "page" was read or
+-	 * written as a unit.  Each "sub-page" is always addressed individually,
+-	 * its data read/written, and ecc handled before the next "sub-page" is
+-	 * addressed.
+-	 *
+-	 * This requires us to convert addresses passed by the mtd nand
+-	 * infrastructure code to those used by the device.
+-	 *
+-	 * The address that is written to the device consists of four bytes: the
+-	 * first two are the 2k page number, and the second is the index into
+-	 * the page.  The index is in terms of 16-bit half-words and includes
+-	 * the preceeding oob data, so e.g., the index into the second
+-	 * "sub-page" is 0x108, and the full device address of the start of mtd
+-	 * page 0x201 is 0x00800108.
+-	 */
+-	int g4_page = page / 4;	                      /* device's 2K page */
+-	int g4_index = (page % 4) * 0x108 + column/2; /* offset into page */
+-	return (g4_page << 16) | g4_index;	      /* pack */
+-}
+-
+-static void docg4_command(struct mtd_info *mtd, unsigned command, int column,
+-			  int page_addr)
+-{
+-	/* handle standard nand commands */
+-
+-	struct nand_chip *nand = mtd_to_nand(mtd);
+-	struct docg4_priv *doc = nand_get_controller_data(nand);
+-	uint32_t g4_addr = mtd_to_docg4_address(page_addr, column);
+-
+-	dev_dbg(doc->dev, "%s %x, page_addr=%x, column=%x\n",
+-	      __func__, command, page_addr, column);
+-
+-	/*
+-	 * Save the command and its arguments.  This enables emulation of
+-	 * standard flash devices, and also some optimizations.
+-	 */
+-	doc->last_command.command = command;
+-	doc->last_command.column = column;
+-	doc->last_command.page = page_addr;
+-
+-	switch (command) {
+-
+-	case NAND_CMD_RESET:
+-		reset(mtd);
+-		break;
+-
+-	case NAND_CMD_READ0:
+-		read_page_prologue(mtd, g4_addr);
+-		break;
+-
+-	case NAND_CMD_STATUS:
+-		/* next call to read_byte() will expect a status */
+-		break;
+-
+-	case NAND_CMD_SEQIN:
+-		if (unlikely(reliable_mode)) {
+-			uint16_t g4_page = g4_addr >> 16;
+-
+-			/* writes to odd-numbered 2k pages are invalid */
+-			if (g4_page & 0x01)
+-				dev_warn(doc->dev,
+-					 "invalid reliable mode address\n");
+-		}
+-
+-		write_page_prologue(mtd, g4_addr);
+-
+-		/* hack for deferred write of oob bytes */
+-		if (doc->oob_page == page_addr)
+-			memcpy(nand->oob_poi, doc->oob_buf, 16);
+-		break;
+-
+-	case NAND_CMD_PAGEPROG:
+-		pageprog(mtd);
+-		break;
+-
+-	/* we don't expect these, based on review of nand_base.c */
+-	case NAND_CMD_READOOB:
+-	case NAND_CMD_READID:
+-	case NAND_CMD_ERASE1:
+-	case NAND_CMD_ERASE2:
+-		dev_warn(doc->dev, "docg4_command: "
+-			 "unexpected nand command 0x%x\n", command);
+-		break;
+-
+-	}
+-}
+-
+-static int read_page(struct mtd_info *mtd, struct nand_chip *nand,
+-		     uint8_t *buf, int page, bool use_ecc)
+-{
+-	struct docg4_priv *doc = nand_get_controller_data(nand);
+-	void __iomem *docptr = doc->virtadr;
+-	uint16_t status, edc_err, *buf16;
+-	int bits_corrected = 0;
+-
+-	dev_dbg(doc->dev, "%s: page %08x\n", __func__, page);
+-
+-	writew(DOC_ECCCONF0_READ_MODE |
+-	       DOC_ECCCONF0_ECC_ENABLE |
+-	       DOC_ECCCONF0_UNKNOWN |
+-	       DOCG4_BCH_SIZE,
+-	       docptr + DOC_ECCCONF0);
+-	write_nop(docptr);
+-	write_nop(docptr);
+-	write_nop(docptr);
+-	write_nop(docptr);
+-	write_nop(docptr);
+-
+-	/* the 1st byte from the I/O reg is a status; the rest is page data */
+-	status = readw(docptr + DOC_IOSPACE_DATA);
+-	if (status & DOCG4_READ_ERROR) {
+-		dev_err(doc->dev,
+-			"docg4_read_page: bad status: 0x%02x\n", status);
+-		writew(0, docptr + DOC_DATAEND);
+-		return -EIO;
+-	}
+-
+-	dev_dbg(doc->dev, "%s: status = 0x%x\n", __func__, status);
+-
+-	docg4_read_buf(mtd, buf, DOCG4_PAGE_SIZE); /* read the page data */
+-
+-	/* this device always reads oob after page data */
+-	/* first 14 oob bytes read from I/O reg */
+-	docg4_read_buf(mtd, nand->oob_poi, 14);
+-
+-	/* last 2 read from another reg */
+-	buf16 = (uint16_t *)(nand->oob_poi + 14);
+-	*buf16 = readw(docptr + DOCG4_MYSTERY_REG);
+-
+-	write_nop(docptr);
+-
+-	if (likely(use_ecc == true)) {
+-
+-		/* read the register that tells us if bitflip(s) detected  */
+-		edc_err = readw(docptr + DOC_ECCCONF1);
+-		edc_err = readw(docptr + DOC_ECCCONF1);
+-		dev_dbg(doc->dev, "%s: edc_err = 0x%02x\n", __func__, edc_err);
+-
+-		/* If bitflips are reported, attempt to correct with ecc */
+-		if (edc_err & DOC_ECCCONF1_BCH_SYNDROM_ERR) {
+-			bits_corrected = correct_data(mtd, buf, page);
+-			if (bits_corrected == -EBADMSG)
+-				mtd->ecc_stats.failed++;
+-			else
+-				mtd->ecc_stats.corrected += bits_corrected;
+-		}
+-	}
+-
+-	writew(0, docptr + DOC_DATAEND);
+-	if (bits_corrected == -EBADMSG)	  /* uncorrectable errors */
+-		return 0;
+-	return bits_corrected;
+-}
+-
+-
+-static int docg4_read_page_raw(struct mtd_info *mtd, struct nand_chip *nand,
+-			       uint8_t *buf, int oob_required, int page)
+-{
+-	return read_page(mtd, nand, buf, page, false);
+-}
+-
+-static int docg4_read_page(struct mtd_info *mtd, struct nand_chip *nand,
+-			   uint8_t *buf, int oob_required, int page)
+-{
+-	return read_page(mtd, nand, buf, page, true);
+-}
+-
+-static int docg4_read_oob(struct mtd_info *mtd, struct nand_chip *nand,
+-			  int page)
+-{
+-	struct docg4_priv *doc = nand_get_controller_data(nand);
+-	void __iomem *docptr = doc->virtadr;
+-	uint16_t status;
+-
+-	dev_dbg(doc->dev, "%s: page %x\n", __func__, page);
+-
+-	docg4_command(mtd, NAND_CMD_READ0, nand->ecc.size, page);
+-
+-	writew(DOC_ECCCONF0_READ_MODE | DOCG4_OOB_SIZE, docptr + DOC_ECCCONF0);
+-	write_nop(docptr);
+-	write_nop(docptr);
+-	write_nop(docptr);
+-	write_nop(docptr);
+-	write_nop(docptr);
+-
+-	/* the 1st byte from the I/O reg is a status; the rest is oob data */
+-	status = readw(docptr + DOC_IOSPACE_DATA);
+-	if (status & DOCG4_READ_ERROR) {
+-		dev_warn(doc->dev,
+-			 "docg4_read_oob failed: status = 0x%02x\n", status);
+-		return -EIO;
+-	}
+-
+-	dev_dbg(doc->dev, "%s: status = 0x%x\n", __func__, status);
+-
+-	docg4_read_buf(mtd, nand->oob_poi, 16);
+-
+-	write_nop(docptr);
+-	write_nop(docptr);
+-	write_nop(docptr);
+-	writew(0, docptr + DOC_DATAEND);
+-	write_nop(docptr);
+-
+-	return 0;
+-}
+-
+-static int docg4_erase_block(struct mtd_info *mtd, int page)
+-{
+-	struct nand_chip *nand = mtd_to_nand(mtd);
+-	struct docg4_priv *doc = nand_get_controller_data(nand);
+-	void __iomem *docptr = doc->virtadr;
+-	uint16_t g4_page;
+-
+-	dev_dbg(doc->dev, "%s: page %04x\n", __func__, page);
+-
+-	sequence_reset(mtd);
+-
+-	writew(DOCG4_SEQ_BLOCKERASE, docptr + DOC_FLASHSEQUENCE);
+-	writew(DOC_CMD_PROG_BLOCK_ADDR, docptr + DOC_FLASHCOMMAND);
+-	write_nop(docptr);
+-
+-	/* only 2 bytes of address are written to specify erase block */
+-	g4_page = (uint16_t)(page / 4);  /* to g4's 2k page addressing */
+-	writeb(g4_page & 0xff, docptr + DOC_FLASHADDRESS);
+-	g4_page >>= 8;
+-	writeb(g4_page & 0xff, docptr + DOC_FLASHADDRESS);
+-	write_nop(docptr);
+-
+-	/* start the erasure */
+-	writew(DOC_CMD_ERASECYCLE2, docptr + DOC_FLASHCOMMAND);
+-	write_nop(docptr);
+-	write_nop(docptr);
+-
+-	usleep_range(500, 1000); /* erasure is long; take a snooze */
+-	poll_status(doc);
+-	writew(DOCG4_SEQ_FLUSH, docptr + DOC_FLASHSEQUENCE);
+-	writew(DOCG4_CMD_FLUSH, docptr + DOC_FLASHCOMMAND);
+-	writew(DOC_ECCCONF0_READ_MODE | 4, docptr + DOC_ECCCONF0);
+-	write_nop(docptr);
+-	write_nop(docptr);
+-	write_nop(docptr);
+-	write_nop(docptr);
+-	write_nop(docptr);
+-
+-	read_progstatus(doc);
+-
+-	writew(0, docptr + DOC_DATAEND);
+-	write_nop(docptr);
+-	poll_status(doc);
+-	write_nop(docptr);
+-
+-	return nand->waitfunc(mtd, nand);
+-}
+-
+-static int write_page(struct mtd_info *mtd, struct nand_chip *nand,
+-		       const uint8_t *buf, bool use_ecc)
+-{
+-	struct docg4_priv *doc = nand_get_controller_data(nand);
+-	void __iomem *docptr = doc->virtadr;
+-	uint8_t ecc_buf[8];
+-
+-	dev_dbg(doc->dev, "%s...\n", __func__);
+-
+-	writew(DOC_ECCCONF0_ECC_ENABLE |
+-	       DOC_ECCCONF0_UNKNOWN |
+-	       DOCG4_BCH_SIZE,
+-	       docptr + DOC_ECCCONF0);
+-	write_nop(docptr);
+-
+-	/* write the page data */
+-	docg4_write_buf16(mtd, buf, DOCG4_PAGE_SIZE);
+-
+-	/* oob bytes 0 through 5 are written to I/O reg */
+-	docg4_write_buf16(mtd, nand->oob_poi, 6);
+-
+-	/* oob byte 6 written to a separate reg */
+-	writew(nand->oob_poi[6], docptr + DOCG4_OOB_6_7);
+-
+-	write_nop(docptr);
+-	write_nop(docptr);
+-
+-	/* write hw-generated ecc bytes to oob */
+-	if (likely(use_ecc == true)) {
+-		/* oob byte 7 is hamming code */
+-		uint8_t hamming = readb(docptr + DOC_HAMMINGPARITY);
+-		hamming = readb(docptr + DOC_HAMMINGPARITY); /* 2nd read */
+-		writew(hamming, docptr + DOCG4_OOB_6_7);
+-		write_nop(docptr);
+-
+-		/* read the 7 bch bytes from ecc regs */
+-		read_hw_ecc(docptr, ecc_buf);
+-		ecc_buf[7] = 0;         /* clear the "page written" flag */
+-	}
+-
+-	/* write user-supplied bytes to oob */
+-	else {
+-		writew(nand->oob_poi[7], docptr + DOCG4_OOB_6_7);
+-		write_nop(docptr);
+-		memcpy(ecc_buf, &nand->oob_poi[8], 8);
+-	}
+-
+-	docg4_write_buf16(mtd, ecc_buf, 8);
+-	write_nop(docptr);
+-	write_nop(docptr);
+-	writew(0, docptr + DOC_DATAEND);
+-	write_nop(docptr);
+-
+-	return 0;
+-}
+-
+-static int docg4_write_page_raw(struct mtd_info *mtd, struct nand_chip *nand,
+-				const uint8_t *buf, int oob_required, int page)
+-{
+-	return write_page(mtd, nand, buf, false);
+-}
+-
+-static int docg4_write_page(struct mtd_info *mtd, struct nand_chip *nand,
+-			     const uint8_t *buf, int oob_required, int page)
+-{
+-	return write_page(mtd, nand, buf, true);
+-}
+-
+-static int docg4_write_oob(struct mtd_info *mtd, struct nand_chip *nand,
+-			   int page)
+-{
+-	/*
+-	 * Writing oob-only is not really supported, because MLC nand must write
+-	 * oob bytes at the same time as page data.  Nonetheless, we save the
+-	 * oob buffer contents here, and then write it along with the page data
+-	 * if the same page is subsequently written.  This allows user space
+-	 * utilities that write the oob data prior to the page data to work
+-	 * (e.g., nandwrite).  The disdvantage is that, if the intention was to
+-	 * write oob only, the operation is quietly ignored.  Also, oob can get
+-	 * corrupted if two concurrent processes are running nandwrite.
+-	 */
+-
+-	/* note that bytes 7..14 are hw generated hamming/ecc and overwritten */
+-	struct docg4_priv *doc = nand_get_controller_data(nand);
+-	doc->oob_page = page;
+-	memcpy(doc->oob_buf, nand->oob_poi, 16);
+-	return 0;
+-}
+-
+-static int __init read_factory_bbt(struct mtd_info *mtd)
+-{
+-	/*
+-	 * The device contains a read-only factory bad block table.  Read it and
+-	 * update the memory-based bbt accordingly.
+-	 */
+-
+-	struct nand_chip *nand = mtd_to_nand(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;
+-	int i, block;
+-	__u32 eccfailed_stats = mtd->ecc_stats.failed;
+-
+-	buf = kzalloc(DOCG4_PAGE_SIZE, GFP_KERNEL);
+-	if (buf == NULL)
+-		return -ENOMEM;
+-
+-	read_page_prologue(mtd, g4_addr);
+-	docg4_read_page(mtd, nand, buf, 0, DOCG4_FACTORY_BBT_PAGE);
+-
+-	/*
+-	 * If no memory-based bbt was created, exit.  This will happen if module
+-	 * parameter ignore_badblocks is set.  Then why even call this function?
+-	 * For an unknown reason, block erase always fails if it's the first
+-	 * operation after device power-up.  The above read ensures it never is.
+-	 * Ugly, I know.
+-	 */
+-	if (nand->bbt == NULL)  /* no memory-based bbt */
+-		goto exit;
+-
+-	if (mtd->ecc_stats.failed > eccfailed_stats) {
+-		/*
+-		 * Whoops, an ecc failure ocurred reading the factory bbt.
+-		 * It is stored redundantly, so we get another chance.
+-		 */
+-		eccfailed_stats = mtd->ecc_stats.failed;
+-		docg4_read_page(mtd, nand, buf, 0, DOCG4_REDUNDANT_BBT_PAGE);
+-		if (mtd->ecc_stats.failed > eccfailed_stats) {
+-			dev_warn(doc->dev,
+-				 "The factory bbt could not be read!\n");
+-			goto exit;
+-		}
+-	}
+-
+-	/*
+-	 * Parse factory bbt and update memory-based bbt.  Factory bbt format is
+-	 * simple: one bit per block, block numbers increase left to right (msb
+-	 * to lsb).  Bit clear means bad block.
+-	 */
+-	for (i = block = 0; block < DOCG4_NUMBLOCKS; block += 8, i++) {
+-		int bitnum;
+-		unsigned long bits = ~buf[i];
+-		for_each_set_bit(bitnum, &bits, 8) {
+-			int badblock = block + 7 - bitnum;
+-			nand->bbt[badblock / 4] |=
+-				0x03 << ((badblock % 4) * 2);
+-			mtd->ecc_stats.badblocks++;
+-			dev_notice(doc->dev, "factory-marked bad block: %d\n",
+-				   badblock);
+-		}
+-	}
+- exit:
+-	kfree(buf);
+-	return 0;
+-}
+-
+-static int docg4_block_markbad(struct mtd_info *mtd, loff_t ofs)
+-{
+-	/*
+-	 * Mark a block as bad.  Bad blocks are marked in the oob area of the
+-	 * first page of the block.  The default scan_bbt() in the nand
+-	 * infrastructure code works fine for building the memory-based bbt
+-	 * during initialization, as does the nand infrastructure function that
+-	 * checks if a block is bad by reading the bbt.  This function replaces
+-	 * the nand default because writes to oob-only are not supported.
+-	 */
+-
+-	int ret, i;
+-	uint8_t *buf;
+-	struct nand_chip *nand = mtd_to_nand(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);
+-	uint32_t g4_addr = mtd_to_docg4_address(page, 0);
+-
+-	dev_dbg(doc->dev, "%s: %08llx\n", __func__, ofs);
+-
+-	if (unlikely(ofs & (DOCG4_BLOCK_SIZE - 1)))
+-		dev_warn(doc->dev, "%s: ofs %llx not start of block!\n",
+-			 __func__, ofs);
+-
+-	/* allocate blank buffer for page data */
+-	buf = kzalloc(DOCG4_PAGE_SIZE, GFP_KERNEL);
+-	if (buf == NULL)
+-		return -ENOMEM;
+-
+-	/* write bit-wise negation of pattern to oob buffer */
+-	memset(nand->oob_poi, 0xff, mtd->oobsize);
+-	for (i = 0; i < bbtd->len; i++)
+-		nand->oob_poi[bbtd->offs + i] = ~bbtd->pattern[i];
+-
+-	/* write first page of block */
+-	write_page_prologue(mtd, g4_addr);
+-	docg4_write_page(mtd, nand, buf, 1, page);
+-	ret = pageprog(mtd);
+-
+-	kfree(buf);
+-
+-	return ret;
+-}
+-
+-static int docg4_block_neverbad(struct mtd_info *mtd, loff_t ofs)
+-{
+-	/* only called when module_param ignore_badblocks is set */
+-	return 0;
+-}
+-
+-static int docg4_suspend(struct platform_device *pdev, pm_message_t state)
+-{
+-	/*
+-	 * Put the device into "deep power-down" mode.  Note that CE# must be
+-	 * deasserted for this to take effect.  The xscale, e.g., can be
+-	 * configured to float this signal when the processor enters power-down,
+-	 * and a suitable pull-up ensures its deassertion.
+-	 */
+-
+-	int i;
+-	uint8_t pwr_down;
+-	struct docg4_priv *doc = platform_get_drvdata(pdev);
+-	void __iomem *docptr = doc->virtadr;
+-
+-	dev_dbg(doc->dev, "%s...\n", __func__);
+-
+-	/* poll the register that tells us we're ready to go to sleep */
+-	for (i = 0; i < 10; i++) {
+-		pwr_down = readb(docptr + DOC_POWERMODE);
+-		if (pwr_down & DOC_POWERDOWN_READY)
+-			break;
+-		usleep_range(1000, 4000);
+-	}
+-
+-	if (pwr_down & DOC_POWERDOWN_READY) {
+-		dev_err(doc->dev, "suspend failed; "
+-			"timeout polling DOC_POWERDOWN_READY\n");
+-		return -EIO;
+-	}
+-
+-	writew(DOC_ASICMODE_POWERDOWN | DOC_ASICMODE_MDWREN,
+-	       docptr + DOC_ASICMODE);
+-	writew(~(DOC_ASICMODE_POWERDOWN | DOC_ASICMODE_MDWREN),
+-	       docptr + DOC_ASICMODECONFIRM);
+-
+-	write_nop(docptr);
+-
+-	return 0;
+-}
+-
+-static int docg4_resume(struct platform_device *pdev)
+-{
+-
+-	/*
+-	 * Exit power-down.  Twelve consecutive reads of the address below
+-	 * accomplishes this, assuming CE# has been asserted.
+-	 */
+-
+-	struct docg4_priv *doc = platform_get_drvdata(pdev);
+-	void __iomem *docptr = doc->virtadr;
+-	int i;
+-
+-	dev_dbg(doc->dev, "%s...\n", __func__);
+-
+-	for (i = 0; i < 12; i++)
+-		readb(docptr + 0x1fff);
+-
+-	return 0;
+-}
+-
+-static void __init init_mtd_structs(struct mtd_info *mtd)
+-{
+-	/* initialize mtd and nand data structures */
+-
+-	/*
+-	 * Note that some of the following initializations are not usually
+-	 * required within a nand driver because they are performed by the nand
+-	 * infrastructure code as part of nand_scan().  In this case they need
+-	 * to be initialized here because we skip call to nand_scan_ident() (the
+-	 * first half of nand_scan()).  The call to nand_scan_ident() is skipped
+-	 * because for this device the chip id is not read in the manner of a
+-	 * standard nand device.  Unfortunately, nand_scan_ident() does other
+-	 * things as well, such as call nand_set_defaults().
+-	 */
+-
+-	struct nand_chip *nand = mtd_to_nand(mtd);
+-	struct docg4_priv *doc = nand_get_controller_data(nand);
+-
+-	mtd->size = DOCG4_CHIP_SIZE;
+-	mtd->name = "Msys_Diskonchip_G4";
+-	mtd->writesize = DOCG4_PAGE_SIZE;
+-	mtd->erasesize = DOCG4_BLOCK_SIZE;
+-	mtd->oobsize = DOCG4_OOB_SIZE;
+-	mtd_set_ooblayout(mtd, &docg4_ooblayout_ops);
+-	nand->chipsize = DOCG4_CHIP_SIZE;
+-	nand->chip_shift = DOCG4_CHIP_SHIFT;
+-	nand->bbt_erase_shift = nand->phys_erase_shift = DOCG4_ERASE_SHIFT;
+-	nand->chip_delay = 20;
+-	nand->page_shift = DOCG4_PAGE_SHIFT;
+-	nand->pagemask = 0x3ffff;
+-	nand->badblockpos = NAND_LARGE_BADBLOCK_POS;
+-	nand->badblockbits = 8;
+-	nand->ecc.mode = NAND_ECC_HW_SYNDROME;
+-	nand->ecc.size = DOCG4_PAGE_SIZE;
+-	nand->ecc.prepad = 8;
+-	nand->ecc.bytes	= 8;
+-	nand->ecc.strength = DOCG4_T;
+-	nand->options = NAND_BUSWIDTH_16 | NAND_NO_SUBPAGE_WRITE;
+-	nand->IO_ADDR_R = nand->IO_ADDR_W = doc->virtadr + DOC_IOSPACE_DATA;
+-	nand->controller = &nand->hwcontrol;
+-	nand_hw_control_init(nand->controller);
+-
+-	/* methods */
+-	nand->cmdfunc = docg4_command;
+-	nand->waitfunc = docg4_wait;
+-	nand->select_chip = docg4_select_chip;
+-	nand->read_byte = docg4_read_byte;
+-	nand->block_markbad = docg4_block_markbad;
+-	nand->read_buf = docg4_read_buf;
+-	nand->write_buf = docg4_write_buf16;
+-	nand->erase = docg4_erase_block;
+-	nand->onfi_set_features = nand_onfi_get_set_features_notsupp;
+-	nand->onfi_get_features = nand_onfi_get_set_features_notsupp;
+-	nand->ecc.read_page = docg4_read_page;
+-	nand->ecc.write_page = docg4_write_page;
+-	nand->ecc.read_page_raw = docg4_read_page_raw;
+-	nand->ecc.write_page_raw = docg4_write_page_raw;
+-	nand->ecc.read_oob = docg4_read_oob;
+-	nand->ecc.write_oob = docg4_write_oob;
+-
+-	/*
+-	 * The way the nand infrastructure code is written, a memory-based bbt
+-	 * is not created if NAND_SKIP_BBTSCAN is set.  With no memory bbt,
+-	 * nand->block_bad() is used.  So when ignoring bad blocks, we skip the
+-	 * scan and define a dummy block_bad() which always returns 0.
+-	 */
+-	if (ignore_badblocks) {
+-		nand->options |= NAND_SKIP_BBTSCAN;
+-		nand->block_bad	= docg4_block_neverbad;
+-	}
+-
+-}
+-
+-static int __init read_id_reg(struct mtd_info *mtd)
+-{
+-	struct nand_chip *nand = mtd_to_nand(mtd);
+-	struct docg4_priv *doc = nand_get_controller_data(nand);
+-	void __iomem *docptr = doc->virtadr;
+-	uint16_t id1, id2;
+-
+-	/* check for presence of g4 chip by reading id registers */
+-	id1 = readw(docptr + DOC_CHIPID);
+-	id1 = readw(docptr + DOCG4_MYSTERY_REG);
+-	id2 = readw(docptr + DOC_CHIPID_INV);
+-	id2 = readw(docptr + DOCG4_MYSTERY_REG);
+-
+-	if (id1 == DOCG4_IDREG1_VALUE && id2 == DOCG4_IDREG2_VALUE) {
+-		dev_info(doc->dev,
+-			 "NAND device: 128MiB Diskonchip G4 detected\n");
+-		return 0;
+-	}
+-
+-	return -ENODEV;
+-}
+-
+-static char const *part_probes[] = { "cmdlinepart", "saftlpart", NULL };
+-
+-static int __init probe_docg4(struct platform_device *pdev)
+-{
+-	struct mtd_info *mtd;
+-	struct nand_chip *nand;
+-	void __iomem *virtadr;
+-	struct docg4_priv *doc;
+-	int len, retval;
+-	struct resource *r;
+-	struct device *dev = &pdev->dev;
+-
+-	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+-	if (r == NULL) {
+-		dev_err(dev, "no io memory resource defined!\n");
+-		return -ENODEV;
+-	}
+-
+-	virtadr = ioremap(r->start, resource_size(r));
+-	if (!virtadr) {
+-		dev_err(dev, "Diskonchip ioremap failed: %pR\n", r);
+-		return -EIO;
+-	}
+-
+-	len = sizeof(struct nand_chip) + sizeof(struct docg4_priv);
+-	nand = kzalloc(len, GFP_KERNEL);
+-	if (nand == NULL) {
+-		retval = -ENOMEM;
+-		goto fail_unmap;
+-	}
+-
+-	mtd = nand_to_mtd(nand);
+-	doc = (struct docg4_priv *) (nand + 1);
+-	nand_set_controller_data(nand, doc);
+-	mtd->dev.parent = &pdev->dev;
+-	doc->virtadr = virtadr;
+-	doc->dev = dev;
+-
+-	init_mtd_structs(mtd);
+-
+-	/* initialize kernel bch algorithm */
+-	doc->bch = init_bch(DOCG4_M, DOCG4_T, DOCG4_PRIMITIVE_POLY);
+-	if (doc->bch == NULL) {
+-		retval = -EINVAL;
+-		goto fail;
+-	}
+-
+-	platform_set_drvdata(pdev, doc);
+-
+-	reset(mtd);
+-	retval = read_id_reg(mtd);
+-	if (retval == -ENODEV) {
+-		dev_warn(dev, "No diskonchip G4 device found.\n");
+-		goto fail;
+-	}
+-
+-	retval = nand_scan_tail(mtd);
+-	if (retval)
+-		goto fail;
+-
+-	retval = read_factory_bbt(mtd);
+-	if (retval)
+-		goto fail;
+-
+-	retval = mtd_device_parse_register(mtd, part_probes, NULL, NULL, 0);
+-	if (retval)
+-		goto fail;
+-
+-	doc->mtd = mtd;
+-	return 0;
+-
+-fail:
+-	nand_release(mtd); /* deletes partitions and mtd devices */
+-	free_bch(doc->bch);
+-	kfree(nand);
+-
+-fail_unmap:
+-	iounmap(virtadr);
+-
+-	return retval;
+-}
+-
+-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));
+-	iounmap(doc->virtadr);
+-	return 0;
+-}
+-
+-static struct platform_driver docg4_driver = {
+-	.driver		= {
+-		.name	= "docg4",
+-	},
+-	.suspend	= docg4_suspend,
+-	.resume		= docg4_resume,
+-	.remove		= __exit_p(cleanup_docg4),
+-};
+-
+-module_platform_driver_probe(docg4_driver, probe_docg4);
+-
+-MODULE_LICENSE("GPL");
+-MODULE_AUTHOR("Mike Dunn");
+-MODULE_DESCRIPTION("M-Systems DiskOnChip G4 device driver");
+diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c
+deleted file mode 100644
+index 17db2f9..0000000
+--- a/drivers/mtd/nand/fsl_elbc_nand.c
++++ /dev/null
+@@ -1,979 +0,0 @@
+-/* Freescale Enhanced Local Bus Controller NAND driver
+- *
+- * Copyright © 2006-2007, 2010 Freescale Semiconductor
+- *
+- * Authors: Nick Spence <nick.spence@freescale.com>,
+- *          Scott Wood <scottwood@freescale.com>
+- *          Jack Lan <jack.lan@freescale.com>
+- *          Roy Zang <tie-fei.zang@freescale.com>
+- *
+- * 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.
+- *
+- * You should have received a copy of the GNU General Public License
+- * along with this program; if not, write to the Free Software
+- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+- */
+-
+-#include <linux/module.h>
+-#include <linux/types.h>
+-#include <linux/kernel.h>
+-#include <linux/string.h>
+-#include <linux/ioport.h>
+-#include <linux/of_address.h>
+-#include <linux/of_platform.h>
+-#include <linux/platform_device.h>
+-#include <linux/slab.h>
+-#include <linux/interrupt.h>
+-
+-#include <linux/mtd/mtd.h>
+-#include <linux/mtd/rawnand.h>
+-#include <linux/mtd/nand_ecc.h>
+-#include <linux/mtd/partitions.h>
+-
+-#include <asm/io.h>
+-#include <asm/fsl_lbc.h>
+-
+-#define MAX_BANKS 8
+-#define ERR_BYTE 0xFF /* Value returned for read bytes when read failed */
+-#define FCM_TIMEOUT_MSECS 500 /* Maximum number of mSecs to wait for FCM */
+-
+-/* mtd information per set */
+-
+-struct fsl_elbc_mtd {
+-	struct nand_chip chip;
+-	struct fsl_lbc_ctrl *ctrl;
+-
+-	struct device *dev;
+-	int bank;               /* Chip select bank number           */
+-	u8 __iomem *vbase;      /* Chip select base virtual address  */
+-	int page_size;          /* NAND page size (0=512, 1=2048)    */
+-	unsigned int fmr;       /* FCM Flash Mode Register value     */
+-};
+-
+-/* Freescale eLBC FCM controller information */
+-
+-struct fsl_elbc_fcm_ctrl {
+-	struct nand_hw_control controller;
+-	struct fsl_elbc_mtd *chips[MAX_BANKS];
+-
+-	u8 __iomem *addr;        /* Address of assigned FCM buffer        */
+-	unsigned int page;       /* Last page written to / read from      */
+-	unsigned int read_bytes; /* Number of bytes read during command   */
+-	unsigned int column;     /* Saved column from SEQIN               */
+-	unsigned int index;      /* Pointer to next byte to 'read'        */
+-	unsigned int status;     /* status read from LTESR after last op  */
+-	unsigned int mdr;        /* UPM/FCM Data Register value           */
+-	unsigned int use_mdr;    /* Non zero if the MDR is to be set      */
+-	unsigned int oob;        /* Non zero if operating on OOB data     */
+-	unsigned int counter;	 /* counter for the initializations	  */
+-	unsigned int max_bitflips;  /* Saved during READ0 cmd		  */
+-};
+-
+-/* These map to the positions used by the FCM hardware ECC generator */
+-
+-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 fsl_elbc_mtd *priv = nand_get_controller_data(chip);
+-
+-	if (section >= chip->ecc.steps)
+-		return -ERANGE;
+-
+-	oobregion->offset = (16 * section) + 6;
+-	if (priv->fmr & FMR_ECCM)
+-		oobregion->offset += 2;
+-
+-	oobregion->length = chip->ecc.bytes;
+-
+-	return 0;
+-}
+-
+-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 fsl_elbc_mtd *priv = nand_get_controller_data(chip);
+-
+-	if (section > chip->ecc.steps)
+-		return -ERANGE;
+-
+-	if (!section) {
+-		oobregion->offset = 0;
+-		if (mtd->writesize > 512)
+-			oobregion->offset++;
+-		oobregion->length = (priv->fmr & FMR_ECCM) ? 7 : 5;
+-	} else {
+-		oobregion->offset = (16 * section) -
+-				    ((priv->fmr & FMR_ECCM) ? 5 : 7);
+-		if (section < chip->ecc.steps)
+-			oobregion->length = 13;
+-		else
+-			oobregion->length = mtd->oobsize - oobregion->offset;
+-	}
+-
+-	return 0;
+-}
+-
+-static const struct mtd_ooblayout_ops fsl_elbc_ooblayout_ops = {
+-	.ecc = fsl_elbc_ooblayout_ecc,
+-	.free = fsl_elbc_ooblayout_free,
+-};
+-
+-/*
+- * ELBC may use HW ECC, so that OOB offsets, that NAND core uses for bbt,
+- * interfere with ECC positions, that's why we implement our own descriptors.
+- * OOB {11, 5}, works for both SP and LP chips, with ECCM = 1 and ECCM = 0.
+- */
+-static u8 bbt_pattern[] = {'B', 'b', 't', '0' };
+-static u8 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,
+-	.offs =	11,
+-	.len = 4,
+-	.veroffs = 15,
+-	.maxblocks = 4,
+-	.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,
+-	.offs =	11,
+-	.len = 4,
+-	.veroffs = 15,
+-	.maxblocks = 4,
+-	.pattern = mirror_pattern,
+-};
+-
+-/*=================================*/
+-
+-/*
+- * Set up the FCM hardware block and page address fields, and the fcm
+- * structure addr field to point to the correct FCM buffer in memory
+- */
+-static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob)
+-{
+-	struct nand_chip *chip = mtd_to_nand(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;
+-	struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand;
+-	int buf_num;
+-
+-	elbc_fcm_ctrl->page = page_addr;
+-
+-	if (priv->page_size) {
+-		/*
+-		 * large page size chip : FPAR[PI] save the lowest 6 bits,
+-		 *                        FBAR[BLK] save the other bits.
+-		 */
+-		out_be32(&lbc->fbar, page_addr >> 6);
+-		out_be32(&lbc->fpar,
+-		         ((page_addr << FPAR_LP_PI_SHIFT) & FPAR_LP_PI) |
+-		         (oob ? FPAR_LP_MS : 0) | column);
+-		buf_num = (page_addr & 1) << 2;
+-	} else {
+-		/*
+-		 * small page size chip : FPAR[PI] save the lowest 5 bits,
+-		 *                        FBAR[BLK] save the other bits.
+-		 */
+-		out_be32(&lbc->fbar, page_addr >> 5);
+-		out_be32(&lbc->fpar,
+-		         ((page_addr << FPAR_SP_PI_SHIFT) & FPAR_SP_PI) |
+-		         (oob ? FPAR_SP_MS : 0) | column);
+-		buf_num = page_addr & 7;
+-	}
+-
+-	elbc_fcm_ctrl->addr = priv->vbase + buf_num * 1024;
+-	elbc_fcm_ctrl->index = column;
+-
+-	/* for OOB data point to the second half of the buffer */
+-	if (oob)
+-		elbc_fcm_ctrl->index += priv->page_size ? 2048 : 512;
+-
+-	dev_vdbg(priv->dev, "set_addr: bank=%d, "
+-			    "elbc_fcm_ctrl->addr=0x%p (0x%p), "
+-	                    "index %x, pes %d ps %d\n",
+-		 buf_num, elbc_fcm_ctrl->addr, priv->vbase,
+-		 elbc_fcm_ctrl->index,
+-	         chip->phys_erase_shift, chip->page_shift);
+-}
+-
+-/*
+- * execute FCM command and wait for it to complete
+- */
+-static int fsl_elbc_run_command(struct mtd_info *mtd)
+-{
+-	struct nand_chip *chip = mtd_to_nand(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;
+-	struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
+-
+-	/* Setup the FMR[OP] to execute without write protection */
+-	out_be32(&lbc->fmr, priv->fmr | 3);
+-	if (elbc_fcm_ctrl->use_mdr)
+-		out_be32(&lbc->mdr, elbc_fcm_ctrl->mdr);
+-
+-	dev_vdbg(priv->dev,
+-	         "fsl_elbc_run_command: fmr=%08x fir=%08x fcr=%08x\n",
+-	         in_be32(&lbc->fmr), in_be32(&lbc->fir), in_be32(&lbc->fcr));
+-	dev_vdbg(priv->dev,
+-	         "fsl_elbc_run_command: fbar=%08x fpar=%08x "
+-	         "fbcr=%08x bank=%d\n",
+-	         in_be32(&lbc->fbar), in_be32(&lbc->fpar),
+-	         in_be32(&lbc->fbcr), priv->bank);
+-
+-	ctrl->irq_status = 0;
+-	/* execute special operation */
+-	out_be32(&lbc->lsor, priv->bank);
+-
+-	/* wait for FCM complete flag or timeout */
+-	wait_event_timeout(ctrl->irq_wait, ctrl->irq_status,
+-	                   FCM_TIMEOUT_MSECS * HZ/1000);
+-	elbc_fcm_ctrl->status = ctrl->irq_status;
+-	/* store mdr value in case it was needed */
+-	if (elbc_fcm_ctrl->use_mdr)
+-		elbc_fcm_ctrl->mdr = in_be32(&lbc->mdr);
+-
+-	elbc_fcm_ctrl->use_mdr = 0;
+-
+-	if (elbc_fcm_ctrl->status != LTESR_CC) {
+-		dev_info(priv->dev,
+-		         "command failed: fir %x fcr %x status %x mdr %x\n",
+-		         in_be32(&lbc->fir), in_be32(&lbc->fcr),
+-			 elbc_fcm_ctrl->status, elbc_fcm_ctrl->mdr);
+-		return -EIO;
+-	}
+-
+-	if (chip->ecc.mode != NAND_ECC_HW)
+-		return 0;
+-
+-	elbc_fcm_ctrl->max_bitflips = 0;
+-
+-	if (elbc_fcm_ctrl->read_bytes == mtd->writesize + mtd->oobsize) {
+-		uint32_t lteccr = in_be32(&lbc->lteccr);
+-		/*
+-		 * if command was a full page read and the ELBC
+-		 * has the LTECCR register, then bits 12-15 (ppc order) of
+-		 * LTECCR indicates which 512 byte sub-pages had fixed errors.
+-		 * bits 28-31 are uncorrectable errors, marked elsewhere.
+-		 * for small page nand only 1 bit is used.
+-		 * if the ELBC doesn't have the lteccr register it reads 0
+-		 * FIXME: 4 bits can be corrected on NANDs with 2k pages, so
+-		 * count the number of sub-pages with bitflips and update
+-		 * ecc_stats.corrected accordingly.
+-		 */
+-		if (lteccr & 0x000F000F)
+-			out_be32(&lbc->lteccr, 0x000F000F); /* clear lteccr */
+-		if (lteccr & 0x000F0000) {
+-			mtd->ecc_stats.corrected++;
+-			elbc_fcm_ctrl->max_bitflips = 1;
+-		}
+-	}
+-
+-	return 0;
+-}
+-
+-static void fsl_elbc_do_read(struct nand_chip *chip, int oob)
+-{
+-	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;
+-
+-	if (priv->page_size) {
+-		out_be32(&lbc->fir,
+-		         (FIR_OP_CM0 << FIR_OP0_SHIFT) |
+-		         (FIR_OP_CA  << FIR_OP1_SHIFT) |
+-		         (FIR_OP_PA  << FIR_OP2_SHIFT) |
+-		         (FIR_OP_CM1 << FIR_OP3_SHIFT) |
+-		         (FIR_OP_RBW << FIR_OP4_SHIFT));
+-
+-		out_be32(&lbc->fcr, (NAND_CMD_READ0 << FCR_CMD0_SHIFT) |
+-		                    (NAND_CMD_READSTART << FCR_CMD1_SHIFT));
+-	} else {
+-		out_be32(&lbc->fir,
+-		         (FIR_OP_CM0 << FIR_OP0_SHIFT) |
+-		         (FIR_OP_CA  << FIR_OP1_SHIFT) |
+-		         (FIR_OP_PA  << FIR_OP2_SHIFT) |
+-		         (FIR_OP_RBW << FIR_OP3_SHIFT));
+-
+-		if (oob)
+-			out_be32(&lbc->fcr, NAND_CMD_READOOB << FCR_CMD0_SHIFT);
+-		else
+-			out_be32(&lbc->fcr, NAND_CMD_READ0 << FCR_CMD0_SHIFT);
+-	}
+-}
+-
+-/* cmdfunc send commands to the FCM */
+-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 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;
+-	struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
+-
+-	elbc_fcm_ctrl->use_mdr = 0;
+-
+-	/* clear the read buffer */
+-	elbc_fcm_ctrl->read_bytes = 0;
+-	if (command != NAND_CMD_PAGEPROG)
+-		elbc_fcm_ctrl->index = 0;
+-
+-	switch (command) {
+-	/* READ0 and READ1 read the entire buffer to use hardware ECC. */
+-	case NAND_CMD_READ1:
+-		column += 256;
+-
+-	/* fall-through */
+-	case NAND_CMD_READ0:
+-		dev_dbg(priv->dev,
+-		        "fsl_elbc_cmdfunc: NAND_CMD_READ0, page_addr:"
+-		        " 0x%x, column: 0x%x.\n", page_addr, column);
+-
+-
+-		out_be32(&lbc->fbcr, 0); /* read entire page to enable ECC */
+-		set_addr(mtd, 0, page_addr, 0);
+-
+-		elbc_fcm_ctrl->read_bytes = mtd->writesize + mtd->oobsize;
+-		elbc_fcm_ctrl->index += column;
+-
+-		fsl_elbc_do_read(chip, 0);
+-		fsl_elbc_run_command(mtd);
+-		return;
+-
+-	/* READOOB reads only the OOB because no ECC is performed. */
+-	case NAND_CMD_READOOB:
+-		dev_vdbg(priv->dev,
+-		         "fsl_elbc_cmdfunc: NAND_CMD_READOOB, page_addr:"
+-			 " 0x%x, column: 0x%x.\n", page_addr, column);
+-
+-		out_be32(&lbc->fbcr, mtd->oobsize - column);
+-		set_addr(mtd, column, page_addr, 1);
+-
+-		elbc_fcm_ctrl->read_bytes = mtd->writesize + mtd->oobsize;
+-
+-		fsl_elbc_do_read(chip, 1);
+-		fsl_elbc_run_command(mtd);
+-		return;
+-
+-	case NAND_CMD_READID:
+-	case NAND_CMD_PARAM:
+-		dev_vdbg(priv->dev, "fsl_elbc_cmdfunc: NAND_CMD %x\n", command);
+-
+-		out_be32(&lbc->fir, (FIR_OP_CM0 << FIR_OP0_SHIFT) |
+-		                    (FIR_OP_UA  << FIR_OP1_SHIFT) |
+-		                    (FIR_OP_RBW << FIR_OP2_SHIFT));
+-		out_be32(&lbc->fcr, command << FCR_CMD0_SHIFT);
+-		/*
+-		 * although currently it's 8 bytes for READID, we always read
+-		 * the maximum 256 bytes(for PARAM)
+-		 */
+-		out_be32(&lbc->fbcr, 256);
+-		elbc_fcm_ctrl->read_bytes = 256;
+-		elbc_fcm_ctrl->use_mdr = 1;
+-		elbc_fcm_ctrl->mdr = column;
+-		set_addr(mtd, 0, 0, 0);
+-		fsl_elbc_run_command(mtd);
+-		return;
+-
+-	/* ERASE1 stores the block and page address */
+-	case NAND_CMD_ERASE1:
+-		dev_vdbg(priv->dev,
+-		         "fsl_elbc_cmdfunc: NAND_CMD_ERASE1, "
+-		         "page_addr: 0x%x.\n", page_addr);
+-		set_addr(mtd, 0, page_addr, 0);
+-		return;
+-
+-	/* ERASE2 uses the block and page address from ERASE1 */
+-	case NAND_CMD_ERASE2:
+-		dev_vdbg(priv->dev, "fsl_elbc_cmdfunc: NAND_CMD_ERASE2.\n");
+-
+-		out_be32(&lbc->fir,
+-		         (FIR_OP_CM0 << FIR_OP0_SHIFT) |
+-		         (FIR_OP_PA  << FIR_OP1_SHIFT) |
+-		         (FIR_OP_CM2 << FIR_OP2_SHIFT) |
+-		         (FIR_OP_CW1 << FIR_OP3_SHIFT) |
+-		         (FIR_OP_RS  << FIR_OP4_SHIFT));
+-
+-		out_be32(&lbc->fcr,
+-		         (NAND_CMD_ERASE1 << FCR_CMD0_SHIFT) |
+-		         (NAND_CMD_STATUS << FCR_CMD1_SHIFT) |
+-		         (NAND_CMD_ERASE2 << FCR_CMD2_SHIFT));
+-
+-		out_be32(&lbc->fbcr, 0);
+-		elbc_fcm_ctrl->read_bytes = 0;
+-		elbc_fcm_ctrl->use_mdr = 1;
+-
+-		fsl_elbc_run_command(mtd);
+-		return;
+-
+-	/* SEQIN sets up the addr buffer and all registers except the length */
+-	case NAND_CMD_SEQIN: {
+-		__be32 fcr;
+-		dev_vdbg(priv->dev,
+-			 "fsl_elbc_cmdfunc: NAND_CMD_SEQIN/PAGE_PROG, "
+-		         "page_addr: 0x%x, column: 0x%x.\n",
+-		         page_addr, column);
+-
+-		elbc_fcm_ctrl->column = column;
+-		elbc_fcm_ctrl->use_mdr = 1;
+-
+-		if (column >= mtd->writesize) {
+-			/* OOB area */
+-			column -= mtd->writesize;
+-			elbc_fcm_ctrl->oob = 1;
+-		} else {
+-			WARN_ON(column != 0);
+-			elbc_fcm_ctrl->oob = 0;
+-		}
+-
+-		fcr = (NAND_CMD_STATUS   << FCR_CMD1_SHIFT) |
+-		      (NAND_CMD_SEQIN    << FCR_CMD2_SHIFT) |
+-		      (NAND_CMD_PAGEPROG << FCR_CMD3_SHIFT);
+-
+-		if (priv->page_size) {
+-			out_be32(&lbc->fir,
+-			         (FIR_OP_CM2 << FIR_OP0_SHIFT) |
+-			         (FIR_OP_CA  << FIR_OP1_SHIFT) |
+-			         (FIR_OP_PA  << FIR_OP2_SHIFT) |
+-			         (FIR_OP_WB  << FIR_OP3_SHIFT) |
+-			         (FIR_OP_CM3 << FIR_OP4_SHIFT) |
+-			         (FIR_OP_CW1 << FIR_OP5_SHIFT) |
+-			         (FIR_OP_RS  << FIR_OP6_SHIFT));
+-		} else {
+-			out_be32(&lbc->fir,
+-			         (FIR_OP_CM0 << FIR_OP0_SHIFT) |
+-			         (FIR_OP_CM2 << FIR_OP1_SHIFT) |
+-			         (FIR_OP_CA  << FIR_OP2_SHIFT) |
+-			         (FIR_OP_PA  << FIR_OP3_SHIFT) |
+-			         (FIR_OP_WB  << FIR_OP4_SHIFT) |
+-			         (FIR_OP_CM3 << FIR_OP5_SHIFT) |
+-			         (FIR_OP_CW1 << FIR_OP6_SHIFT) |
+-			         (FIR_OP_RS  << FIR_OP7_SHIFT));
+-
+-			if (elbc_fcm_ctrl->oob)
+-				/* OOB area --> READOOB */
+-				fcr |= NAND_CMD_READOOB << FCR_CMD0_SHIFT;
+-			else
+-				/* First 256 bytes --> READ0 */
+-				fcr |= NAND_CMD_READ0 << FCR_CMD0_SHIFT;
+-		}
+-
+-		out_be32(&lbc->fcr, fcr);
+-		set_addr(mtd, column, page_addr, elbc_fcm_ctrl->oob);
+-		return;
+-	}
+-
+-	/* PAGEPROG reuses all of the setup from SEQIN and adds the length */
+-	case NAND_CMD_PAGEPROG: {
+-		dev_vdbg(priv->dev,
+-		         "fsl_elbc_cmdfunc: NAND_CMD_PAGEPROG "
+-			 "writing %d bytes.\n", elbc_fcm_ctrl->index);
+-
+-		/* if the write did not start at 0 or is not a full page
+-		 * then set the exact length, otherwise use a full page
+-		 * write so the HW generates the ECC.
+-		 */
+-		if (elbc_fcm_ctrl->oob || elbc_fcm_ctrl->column != 0 ||
+-		    elbc_fcm_ctrl->index != mtd->writesize + mtd->oobsize)
+-			out_be32(&lbc->fbcr,
+-				elbc_fcm_ctrl->index - elbc_fcm_ctrl->column);
+-		else
+-			out_be32(&lbc->fbcr, 0);
+-
+-		fsl_elbc_run_command(mtd);
+-		return;
+-	}
+-
+-	/* CMD_STATUS must read the status byte while CEB is active */
+-	/* Note - it does not wait for the ready line */
+-	case NAND_CMD_STATUS:
+-		out_be32(&lbc->fir,
+-		         (FIR_OP_CM0 << FIR_OP0_SHIFT) |
+-		         (FIR_OP_RBW << FIR_OP1_SHIFT));
+-		out_be32(&lbc->fcr, NAND_CMD_STATUS << FCR_CMD0_SHIFT);
+-		out_be32(&lbc->fbcr, 1);
+-		set_addr(mtd, 0, 0, 0);
+-		elbc_fcm_ctrl->read_bytes = 1;
+-
+-		fsl_elbc_run_command(mtd);
+-
+-		/* The chip always seems to report that it is
+-		 * write-protected, even when it is not.
+-		 */
+-		setbits8(elbc_fcm_ctrl->addr, NAND_STATUS_WP);
+-		return;
+-
+-	/* RESET without waiting for the ready line */
+-	case NAND_CMD_RESET:
+-		dev_dbg(priv->dev, "fsl_elbc_cmdfunc: NAND_CMD_RESET.\n");
+-		out_be32(&lbc->fir, FIR_OP_CM0 << FIR_OP0_SHIFT);
+-		out_be32(&lbc->fcr, NAND_CMD_RESET << FCR_CMD0_SHIFT);
+-		fsl_elbc_run_command(mtd);
+-		return;
+-
+-	default:
+-		dev_err(priv->dev,
+-		        "fsl_elbc_cmdfunc: error, unsupported command 0x%x.\n",
+-		        command);
+-	}
+-}
+-
+-static void fsl_elbc_select_chip(struct mtd_info *mtd, int chip)
+-{
+-	/* The hardware does not seem to support multiple
+-	 * chips per bank.
+-	 */
+-}
+-
+-/*
+- * Write buf to the FCM Controller Data Buffer
+- */
+-static void fsl_elbc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
+-{
+-	struct nand_chip *chip = mtd_to_nand(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;
+-
+-	if (len <= 0) {
+-		dev_err(priv->dev, "write_buf of %d bytes", len);
+-		elbc_fcm_ctrl->status = 0;
+-		return;
+-	}
+-
+-	if ((unsigned int)len > bufsize - elbc_fcm_ctrl->index) {
+-		dev_err(priv->dev,
+-		        "write_buf beyond end of buffer "
+-		        "(%d requested, %u available)\n",
+-			len, bufsize - elbc_fcm_ctrl->index);
+-		len = bufsize - elbc_fcm_ctrl->index;
+-	}
+-
+-	memcpy_toio(&elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index], buf, len);
+-	/*
+-	 * This is workaround for the weird elbc hangs during nand write,
+-	 * Scott Wood says: "...perhaps difference in how long it takes a
+-	 * write to make it through the localbus compared to a write to IMMR
+-	 * is causing problems, and sync isn't helping for some reason."
+-	 * Reading back the last byte helps though.
+-	 */
+-	in_8(&elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index] + len - 1);
+-
+-	elbc_fcm_ctrl->index += len;
+-}
+-
+-/*
+- * read a byte from either the FCM hardware buffer if it has any data left
+- * otherwise issue a command to read a single byte.
+- */
+-static u8 fsl_elbc_read_byte(struct mtd_info *mtd)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
+-	struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
+-
+-	/* If there are still bytes in the FCM, then use the next byte. */
+-	if (elbc_fcm_ctrl->index < elbc_fcm_ctrl->read_bytes)
+-		return in_8(&elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index++]);
+-
+-	dev_err(priv->dev, "read_byte beyond end of buffer\n");
+-	return ERR_BYTE;
+-}
+-
+-/*
+- * Read from the FCM Controller Data Buffer
+- */
+-static void fsl_elbc_read_buf(struct mtd_info *mtd, u8 *buf, int len)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
+-	struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
+-	int avail;
+-
+-	if (len < 0)
+-		return;
+-
+-	avail = min((unsigned int)len,
+-			elbc_fcm_ctrl->read_bytes - elbc_fcm_ctrl->index);
+-	memcpy_fromio(buf, &elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index], avail);
+-	elbc_fcm_ctrl->index += avail;
+-
+-	if (len > avail)
+-		dev_err(priv->dev,
+-		        "read_buf beyond end of buffer "
+-		        "(%d requested, %d available)\n",
+-		        len, avail);
+-}
+-
+-/* This function is called after Program and Erase Operations to
+- * check for success or failure.
+- */
+-static int fsl_elbc_wait(struct mtd_info *mtd, struct nand_chip *chip)
+-{
+-	struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
+-	struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
+-
+-	if (elbc_fcm_ctrl->status != LTESR_CC)
+-		return NAND_STATUS_FAIL;
+-
+-	/* The chip always seems to report that it is
+-	 * write-protected, even when it is not.
+-	 */
+-	return (elbc_fcm_ctrl->mdr & 0xff) | NAND_STATUS_WP;
+-}
+-
+-static int fsl_elbc_chip_init_tail(struct mtd_info *mtd)
+-{
+-	struct nand_chip *chip = mtd_to_nand(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;
+-	unsigned int al;
+-
+-	/* calculate FMR Address Length field */
+-	al = 0;
+-	if (chip->pagemask & 0xffff0000)
+-		al++;
+-	if (chip->pagemask & 0xff000000)
+-		al++;
+-
+-	priv->fmr |= al << FMR_AL_SHIFT;
+-
+-	dev_dbg(priv->dev, "fsl_elbc_init: nand->numchips = %d\n",
+-	        chip->numchips);
+-	dev_dbg(priv->dev, "fsl_elbc_init: nand->chipsize = %lld\n",
+-	        chip->chipsize);
+-	dev_dbg(priv->dev, "fsl_elbc_init: nand->pagemask = %8x\n",
+-	        chip->pagemask);
+-	dev_dbg(priv->dev, "fsl_elbc_init: nand->chip_delay = %d\n",
+-	        chip->chip_delay);
+-	dev_dbg(priv->dev, "fsl_elbc_init: nand->badblockpos = %d\n",
+-	        chip->badblockpos);
+-	dev_dbg(priv->dev, "fsl_elbc_init: nand->chip_shift = %d\n",
+-	        chip->chip_shift);
+-	dev_dbg(priv->dev, "fsl_elbc_init: nand->page_shift = %d\n",
+-	        chip->page_shift);
+-	dev_dbg(priv->dev, "fsl_elbc_init: nand->phys_erase_shift = %d\n",
+-	        chip->phys_erase_shift);
+-	dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.mode = %d\n",
+-	        chip->ecc.mode);
+-	dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.steps = %d\n",
+-	        chip->ecc.steps);
+-	dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.bytes = %d\n",
+-	        chip->ecc.bytes);
+-	dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.total = %d\n",
+-	        chip->ecc.total);
+-	dev_dbg(priv->dev, "fsl_elbc_init: mtd->ooblayout = %p\n",
+-		mtd->ooblayout);
+-	dev_dbg(priv->dev, "fsl_elbc_init: mtd->flags = %08x\n", mtd->flags);
+-	dev_dbg(priv->dev, "fsl_elbc_init: mtd->size = %lld\n", mtd->size);
+-	dev_dbg(priv->dev, "fsl_elbc_init: mtd->erasesize = %d\n",
+-	        mtd->erasesize);
+-	dev_dbg(priv->dev, "fsl_elbc_init: mtd->writesize = %d\n",
+-	        mtd->writesize);
+-	dev_dbg(priv->dev, "fsl_elbc_init: mtd->oobsize = %d\n",
+-	        mtd->oobsize);
+-
+-	/* adjust Option Register and ECC to match Flash page size */
+-	if (mtd->writesize == 512) {
+-		priv->page_size = 0;
+-		clrbits32(&lbc->bank[priv->bank].or, OR_FCM_PGS);
+-	} else if (mtd->writesize == 2048) {
+-		priv->page_size = 1;
+-		setbits32(&lbc->bank[priv->bank].or, OR_FCM_PGS);
+-	} else {
+-		dev_err(priv->dev,
+-		        "fsl_elbc_init: page size %d is not supported\n",
+-		        mtd->writesize);
+-		return -1;
+-	}
+-
+-	return 0;
+-}
+-
+-static int fsl_elbc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
+-			      uint8_t *buf, int oob_required, int page)
+-{
+-	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;
+-
+-	fsl_elbc_read_buf(mtd, buf, mtd->writesize);
+-	if (oob_required)
+-		fsl_elbc_read_buf(mtd, chip->oob_poi, mtd->oobsize);
+-
+-	if (fsl_elbc_wait(mtd, chip) & NAND_STATUS_FAIL)
+-		mtd->ecc_stats.failed++;
+-
+-	return elbc_fcm_ctrl->max_bitflips;
+-}
+-
+-/* ECC will be calculated automatically, and errors will be detected in
+- * waitfunc.
+- */
+-static int fsl_elbc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
+-				const uint8_t *buf, int oob_required, int page)
+-{
+-	fsl_elbc_write_buf(mtd, buf, mtd->writesize);
+-	fsl_elbc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
+-
+-	return 0;
+-}
+-
+-/* ECC will be calculated automatically, and errors will be detected in
+- * waitfunc.
+- */
+-static int fsl_elbc_write_subpage(struct mtd_info *mtd, struct nand_chip *chip,
+-				uint32_t offset, uint32_t data_len,
+-				const uint8_t *buf, int oob_required, int page)
+-{
+-	fsl_elbc_write_buf(mtd, buf, mtd->writesize);
+-	fsl_elbc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
+-
+-	return 0;
+-}
+-
+-static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv)
+-{
+-	struct fsl_lbc_ctrl *ctrl = priv->ctrl;
+-	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);
+-
+-	dev_dbg(priv->dev, "eLBC Set Information for bank %d\n", priv->bank);
+-
+-	/* Fill in fsl_elbc_mtd structure */
+-	mtd->dev.parent = priv->dev;
+-	nand_set_flash_node(chip, priv->dev->of_node);
+-
+-	/* set timeout to maximum */
+-	priv->fmr = 15 << FMR_CWTO_SHIFT;
+-	if (in_be32(&lbc->bank[priv->bank].or) & OR_FCM_PGS)
+-		priv->fmr |= FMR_ECCM;
+-
+-	/* fill in nand_chip structure */
+-	/* set up function call table */
+-	chip->read_byte = fsl_elbc_read_byte;
+-	chip->write_buf = fsl_elbc_write_buf;
+-	chip->read_buf = fsl_elbc_read_buf;
+-	chip->select_chip = fsl_elbc_select_chip;
+-	chip->cmdfunc = fsl_elbc_cmdfunc;
+-	chip->waitfunc = fsl_elbc_wait;
+-	chip->onfi_set_features = nand_onfi_get_set_features_notsupp;
+-	chip->onfi_get_features = nand_onfi_get_set_features_notsupp;
+-
+-	chip->bbt_td = &bbt_main_descr;
+-	chip->bbt_md = &bbt_mirror_descr;
+-
+-	/* set up nand options */
+-	chip->bbt_options = NAND_BBT_USE_FLASH;
+-
+-	chip->controller = &elbc_fcm_ctrl->controller;
+-	nand_set_controller_data(chip, priv);
+-
+-	chip->ecc.read_page = fsl_elbc_read_page;
+-	chip->ecc.write_page = fsl_elbc_write_page;
+-	chip->ecc.write_subpage = fsl_elbc_write_subpage;
+-
+-	/* If CS Base Register selects full hardware ECC then use it */
+-	if ((in_be32(&lbc->bank[priv->bank].br) & BR_DECC) ==
+-	    BR_DECC_CHK_GEN) {
+-		chip->ecc.mode = NAND_ECC_HW;
+-		mtd_set_ooblayout(mtd, &fsl_elbc_ooblayout_ops);
+-		chip->ecc.size = 512;
+-		chip->ecc.bytes = 3;
+-		chip->ecc.strength = 1;
+-	} else {
+-		/* otherwise fall back to default software ECC */
+-		chip->ecc.mode = NAND_ECC_SOFT;
+-		chip->ecc.algo = NAND_ECC_HAMMING;
+-	}
+-
+-	return 0;
+-}
+-
+-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);
+-
+-	nand_release(mtd);
+-
+-	kfree(mtd->name);
+-
+-	if (priv->vbase)
+-		iounmap(priv->vbase);
+-
+-	elbc_fcm_ctrl->chips[priv->bank] = NULL;
+-	kfree(priv);
+-	return 0;
+-}
+-
+-static DEFINE_MUTEX(fsl_elbc_nand_mutex);
+-
+-static int fsl_elbc_nand_probe(struct platform_device *pdev)
+-{
+-	struct fsl_lbc_regs __iomem *lbc;
+-	struct fsl_elbc_mtd *priv;
+-	struct resource res;
+-	struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl;
+-	static const char *part_probe_types[]
+-		= { "cmdlinepart", "RedBoot", "ofpart", NULL };
+-	int ret;
+-	int bank;
+-	struct device *dev;
+-	struct device_node *node = pdev->dev.of_node;
+-	struct mtd_info *mtd;
+-
+-	if (!fsl_lbc_ctrl_dev || !fsl_lbc_ctrl_dev->regs)
+-		return -ENODEV;
+-	lbc = fsl_lbc_ctrl_dev->regs;
+-	dev = fsl_lbc_ctrl_dev->dev;
+-
+-	/* get, allocate and map the memory resource */
+-	ret = of_address_to_resource(node, 0, &res);
+-	if (ret) {
+-		dev_err(dev, "failed to get resource\n");
+-		return ret;
+-	}
+-
+-	/* find which chip select it is connected to */
+-	for (bank = 0; bank < MAX_BANKS; bank++)
+-		if ((in_be32(&lbc->bank[bank].br) & BR_V) &&
+-		    (in_be32(&lbc->bank[bank].br) & BR_MSEL) == BR_MS_FCM &&
+-		    (in_be32(&lbc->bank[bank].br) &
+-		     in_be32(&lbc->bank[bank].or) & BR_BA)
+-		     == fsl_lbc_addr(res.start))
+-			break;
+-
+-	if (bank >= MAX_BANKS) {
+-		dev_err(dev, "address did not match any chip selects\n");
+-		return -ENODEV;
+-	}
+-
+-	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+-	if (!priv)
+-		return -ENOMEM;
+-
+-	mutex_lock(&fsl_elbc_nand_mutex);
+-	if (!fsl_lbc_ctrl_dev->nand) {
+-		elbc_fcm_ctrl = kzalloc(sizeof(*elbc_fcm_ctrl), GFP_KERNEL);
+-		if (!elbc_fcm_ctrl) {
+-			mutex_unlock(&fsl_elbc_nand_mutex);
+-			ret = -ENOMEM;
+-			goto err;
+-		}
+-		elbc_fcm_ctrl->counter++;
+-
+-		nand_hw_control_init(&elbc_fcm_ctrl->controller);
+-		fsl_lbc_ctrl_dev->nand = elbc_fcm_ctrl;
+-	} else {
+-		elbc_fcm_ctrl = fsl_lbc_ctrl_dev->nand;
+-	}
+-	mutex_unlock(&fsl_elbc_nand_mutex);
+-
+-	elbc_fcm_ctrl->chips[bank] = priv;
+-	priv->bank = bank;
+-	priv->ctrl = fsl_lbc_ctrl_dev;
+-	priv->dev = &pdev->dev;
+-	dev_set_drvdata(priv->dev, priv);
+-
+-	priv->vbase = ioremap(res.start, resource_size(&res));
+-	if (!priv->vbase) {
+-		dev_err(dev, "failed to map chip region\n");
+-		ret = -ENOMEM;
+-		goto err;
+-	}
+-
+-	mtd = nand_to_mtd(&priv->chip);
+-	mtd->name = kasprintf(GFP_KERNEL, "%llx.flash", (u64)res.start);
+-	if (!nand_to_mtd(&priv->chip)->name) {
+-		ret = -ENOMEM;
+-		goto err;
+-	}
+-
+-	ret = fsl_elbc_chip_init(priv);
+-	if (ret)
+-		goto err;
+-
+-	ret = nand_scan_ident(mtd, 1, NULL);
+-	if (ret)
+-		goto err;
+-
+-	ret = fsl_elbc_chip_init_tail(mtd);
+-	if (ret)
+-		goto err;
+-
+-	ret = nand_scan_tail(mtd);
+-	if (ret)
+-		goto err;
+-
+-	/* First look for RedBoot table or partitions on the command
+-	 * line, these take precedence over device tree information */
+-	mtd_device_parse_register(mtd, part_probe_types, NULL,
+-				  NULL, 0);
+-
+-	printk(KERN_INFO "eLBC NAND device at 0x%llx, bank %d\n",
+-	       (unsigned long long)res.start, priv->bank);
+-	return 0;
+-
+-err:
+-	fsl_elbc_chip_remove(priv);
+-	return ret;
+-}
+-
+-static int fsl_elbc_nand_remove(struct platform_device *pdev)
+-{
+-	struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = fsl_lbc_ctrl_dev->nand;
+-	struct fsl_elbc_mtd *priv = dev_get_drvdata(&pdev->dev);
+-
+-	fsl_elbc_chip_remove(priv);
+-
+-	mutex_lock(&fsl_elbc_nand_mutex);
+-	elbc_fcm_ctrl->counter--;
+-	if (!elbc_fcm_ctrl->counter) {
+-		fsl_lbc_ctrl_dev->nand = NULL;
+-		kfree(elbc_fcm_ctrl);
+-	}
+-	mutex_unlock(&fsl_elbc_nand_mutex);
+-
+-	return 0;
+-
+-}
+-
+-static const struct of_device_id fsl_elbc_nand_match[] = {
+-	{ .compatible = "fsl,elbc-fcm-nand", },
+-	{}
+-};
+-MODULE_DEVICE_TABLE(of, fsl_elbc_nand_match);
+-
+-static struct platform_driver fsl_elbc_nand_driver = {
+-	.driver = {
+-		.name = "fsl,elbc-fcm-nand",
+-		.of_match_table = fsl_elbc_nand_match,
+-	},
+-	.probe = fsl_elbc_nand_probe,
+-	.remove = fsl_elbc_nand_remove,
+-};
+-
+-module_platform_driver(fsl_elbc_nand_driver);
+-
+-MODULE_LICENSE("GPL");
+-MODULE_AUTHOR("Freescale");
+-MODULE_DESCRIPTION("Freescale Enhanced Local Bus Controller MTD NAND driver");
+diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c
+deleted file mode 100644
+index 9e03bac..0000000
+--- a/drivers/mtd/nand/fsl_ifc_nand.c
++++ /dev/null
+@@ -1,1110 +0,0 @@
+-/*
+- * Freescale Integrated Flash Controller NAND driver
+- *
+- * Copyright 2011-2012 Freescale Semiconductor, Inc
+- *
+- * Author: Dipen Dudhat <Dipen.Dudhat@freescale.com>
+- *
+- * 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.
+- *
+- * You should have received a copy of the GNU General Public License
+- * along with this program; if not, write to the Free Software
+- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+- */
+-
+-#include <linux/module.h>
+-#include <linux/types.h>
+-#include <linux/kernel.h>
+-#include <linux/of_address.h>
+-#include <linux/slab.h>
+-#include <linux/mtd/mtd.h>
+-#include <linux/mtd/rawnand.h>
+-#include <linux/mtd/partitions.h>
+-#include <linux/mtd/nand_ecc.h>
+-#include <linux/fsl_ifc.h>
+-
+-#define ERR_BYTE		0xFF /* Value returned for read
+-					bytes when read failed	*/
+-#define IFC_TIMEOUT_MSECS	500  /* Maximum number of mSecs to wait
+-					for IFC NAND Machine	*/
+-
+-struct fsl_ifc_ctrl;
+-
+-/* mtd information per set */
+-struct fsl_ifc_mtd {
+-	struct nand_chip chip;
+-	struct fsl_ifc_ctrl *ctrl;
+-
+-	struct device *dev;
+-	int bank;		/* Chip select bank number		*/
+-	unsigned int bufnum_mask; /* bufnum = page & bufnum_mask */
+-	u8 __iomem *vbase;      /* Chip select base virtual address	*/
+-};
+-
+-/* overview of the fsl ifc controller */
+-struct fsl_ifc_nand_ctrl {
+-	struct nand_hw_control controller;
+-	struct fsl_ifc_mtd *chips[FSL_IFC_BANK_COUNT];
+-
+-	void __iomem *addr;	/* Address of assigned IFC buffer	*/
+-	unsigned int page;	/* Last page written to / read from	*/
+-	unsigned int read_bytes;/* Number of bytes read during command	*/
+-	unsigned int column;	/* Saved column from SEQIN		*/
+-	unsigned int index;	/* Pointer to next byte to 'read'	*/
+-	unsigned int oob;	/* Non zero if operating on OOB data	*/
+-	unsigned int eccread;	/* Non zero for a full-page ECC read	*/
+-	unsigned int counter;	/* counter for the initializations	*/
+-	unsigned int max_bitflips;  /* Saved during READ0 cmd		*/
+-};
+-
+-static struct fsl_ifc_nand_ctrl *ifc_nand_ctrl;
+-
+-/*
+- * Generic flash bbt descriptors
+- */
+-static u8 bbt_pattern[] = {'B', 'b', 't', '0' };
+-static u8 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,
+-	.offs =	2, /* 0 on 8-bit small page */
+-	.len = 4,
+-	.veroffs = 6,
+-	.maxblocks = 4,
+-	.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,
+-	.offs =	2, /* 0 on 8-bit small page */
+-	.len = 4,
+-	.veroffs = 6,
+-	.maxblocks = 4,
+-	.pattern = mirror_pattern,
+-};
+-
+-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);
+-
+-	if (section)
+-		return -ERANGE;
+-
+-	oobregion->offset = 8;
+-	oobregion->length = chip->ecc.total;
+-
+-	return 0;
+-}
+-
+-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);
+-
+-	if (section > 1)
+-		return -ERANGE;
+-
+-	if (mtd->writesize == 512 &&
+-	    !(chip->options & NAND_BUSWIDTH_16)) {
+-		if (!section) {
+-			oobregion->offset = 0;
+-			oobregion->length = 5;
+-		} else {
+-			oobregion->offset = 6;
+-			oobregion->length = 2;
+-		}
+-
+-		return 0;
+-	}
+-
+-	if (!section) {
+-		oobregion->offset = 2;
+-		oobregion->length = 6;
+-	} else {
+-		oobregion->offset = chip->ecc.total + 8;
+-		oobregion->length = mtd->oobsize - oobregion->offset;
+-	}
+-
+-	return 0;
+-}
+-
+-static const struct mtd_ooblayout_ops fsl_ifc_ooblayout_ops = {
+-	.ecc = fsl_ifc_ooblayout_ecc,
+-	.free = fsl_ifc_ooblayout_free,
+-};
+-
+-/*
+- * Set up the IFC hardware block and page address fields, and the ifc nand
+- * structure addr field to point to the correct IFC buffer in memory
+- */
+-static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob)
+-{
+-	struct nand_chip *chip = mtd_to_nand(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;
+-	int buf_num;
+-
+-	ifc_nand_ctrl->page = page_addr;
+-	/* Program ROW0/COL0 */
+-	ifc_out32(page_addr, &ifc->ifc_nand.row0);
+-	ifc_out32((oob ? IFC_NAND_COL_MS : 0) | column, &ifc->ifc_nand.col0);
+-
+-	buf_num = page_addr & priv->bufnum_mask;
+-
+-	ifc_nand_ctrl->addr = priv->vbase + buf_num * (mtd->writesize * 2);
+-	ifc_nand_ctrl->index = column;
+-
+-	/* for OOB data point to the second half of the buffer */
+-	if (oob)
+-		ifc_nand_ctrl->index += mtd->writesize;
+-}
+-
+-/* returns nonzero if entire page is blank */
+-static int check_read_ecc(struct mtd_info *mtd, struct fsl_ifc_ctrl *ctrl,
+-			  u32 *eccstat, unsigned int bufnum)
+-{
+-	u32 reg = eccstat[bufnum / 4];
+-	int errors;
+-
+-	errors = (reg >> ((3 - bufnum % 4) * 8)) & 15;
+-
+-	return errors;
+-}
+-
+-/*
+- * execute IFC NAND command and wait for it to complete
+- */
+-static void fsl_ifc_run_command(struct mtd_info *mtd)
+-{
+-	struct nand_chip *chip = mtd_to_nand(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;
+-	struct fsl_ifc_runtime __iomem *ifc = ctrl->rregs;
+-	u32 eccstat[4];
+-	int i;
+-
+-	/* set the chip select for NAND Transaction */
+-	ifc_out32(priv->bank << IFC_NAND_CSEL_SHIFT,
+-		  &ifc->ifc_nand.nand_csel);
+-
+-	dev_vdbg(priv->dev,
+-			"%s: fir0=%08x fcr0=%08x\n",
+-			__func__,
+-			ifc_in32(&ifc->ifc_nand.nand_fir0),
+-			ifc_in32(&ifc->ifc_nand.nand_fcr0));
+-
+-	ctrl->nand_stat = 0;
+-
+-	/* start read/write seq */
+-	ifc_out32(IFC_NAND_SEQ_STRT_FIR_STRT, &ifc->ifc_nand.nandseq_strt);
+-
+-	/* wait for command complete flag or timeout */
+-	wait_event_timeout(ctrl->nand_wait, ctrl->nand_stat,
+-			   msecs_to_jiffies(IFC_TIMEOUT_MSECS));
+-
+-	/* ctrl->nand_stat will be updated from IRQ context */
+-	if (!ctrl->nand_stat)
+-		dev_err(priv->dev, "Controller is not responding\n");
+-	if (ctrl->nand_stat & IFC_NAND_EVTER_STAT_FTOER)
+-		dev_err(priv->dev, "NAND Flash Timeout Error\n");
+-	if (ctrl->nand_stat & IFC_NAND_EVTER_STAT_WPER)
+-		dev_err(priv->dev, "NAND Flash Write Protect Error\n");
+-
+-	nctrl->max_bitflips = 0;
+-
+-	if (nctrl->eccread) {
+-		int errors;
+-		int bufnum = nctrl->page & priv->bufnum_mask;
+-		int sector = bufnum * chip->ecc.steps;
+-		int sector_end = sector + chip->ecc.steps - 1;
+-		__be32 *eccstat_regs;
+-
+-		if (ctrl->version >= FSL_IFC_VERSION_2_0_0)
+-			eccstat_regs = ifc->ifc_nand.v2_nand_eccstat;
+-		else
+-			eccstat_regs = ifc->ifc_nand.v1_nand_eccstat;
+-
+-		for (i = sector / 4; i <= sector_end / 4; i++)
+-			eccstat[i] = ifc_in32(&eccstat_regs[i]);
+-
+-		for (i = sector; i <= sector_end; i++) {
+-			errors = check_read_ecc(mtd, ctrl, eccstat, i);
+-
+-			if (errors == 15) {
+-				/*
+-				 * Uncorrectable error.
+-				 * We'll check for blank pages later.
+-				 *
+-				 * We disable ECCER reporting due to...
+-				 * erratum IFC-A002770 -- so report it now if we
+-				 * see an uncorrectable error in ECCSTAT.
+-				 */
+-				ctrl->nand_stat |= IFC_NAND_EVTER_STAT_ECCER;
+-				continue;
+-			}
+-
+-			mtd->ecc_stats.corrected += errors;
+-			nctrl->max_bitflips = max_t(unsigned int,
+-						    nctrl->max_bitflips,
+-						    errors);
+-		}
+-
+-		nctrl->eccread = 0;
+-	}
+-}
+-
+-static void fsl_ifc_do_read(struct nand_chip *chip,
+-			    int oob,
+-			    struct mtd_info *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;
+-
+-	/* Program FIR/IFC_NAND_FCR0 for Small/Large page */
+-	if (mtd->writesize > 512) {
+-		ifc_out32((IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
+-			  (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) |
+-			  (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP2_SHIFT) |
+-			  (IFC_FIR_OP_CMD1 << IFC_NAND_FIR0_OP3_SHIFT) |
+-			  (IFC_FIR_OP_RBCD << IFC_NAND_FIR0_OP4_SHIFT),
+-			  &ifc->ifc_nand.nand_fir0);
+-		ifc_out32(0x0, &ifc->ifc_nand.nand_fir1);
+-
+-		ifc_out32((NAND_CMD_READ0 << IFC_NAND_FCR0_CMD0_SHIFT) |
+-			  (NAND_CMD_READSTART << IFC_NAND_FCR0_CMD1_SHIFT),
+-			  &ifc->ifc_nand.nand_fcr0);
+-	} else {
+-		ifc_out32((IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
+-			  (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) |
+-			  (IFC_FIR_OP_RA0  << IFC_NAND_FIR0_OP2_SHIFT) |
+-			  (IFC_FIR_OP_RBCD << IFC_NAND_FIR0_OP3_SHIFT),
+-			  &ifc->ifc_nand.nand_fir0);
+-		ifc_out32(0x0, &ifc->ifc_nand.nand_fir1);
+-
+-		if (oob)
+-			ifc_out32(NAND_CMD_READOOB <<
+-				  IFC_NAND_FCR0_CMD0_SHIFT,
+-				  &ifc->ifc_nand.nand_fcr0);
+-		else
+-			ifc_out32(NAND_CMD_READ0 <<
+-				  IFC_NAND_FCR0_CMD0_SHIFT,
+-				  &ifc->ifc_nand.nand_fcr0);
+-	}
+-}
+-
+-/* 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 fsl_ifc_mtd *priv = nand_get_controller_data(chip);
+-	struct fsl_ifc_ctrl *ctrl = priv->ctrl;
+-	struct fsl_ifc_runtime __iomem *ifc = ctrl->rregs;
+-
+-	/* clear the read buffer */
+-	ifc_nand_ctrl->read_bytes = 0;
+-	if (command != NAND_CMD_PAGEPROG)
+-		ifc_nand_ctrl->index = 0;
+-
+-	switch (command) {
+-	/* READ0 read the entire buffer to use hardware ECC. */
+-	case NAND_CMD_READ0:
+-		ifc_out32(0, &ifc->ifc_nand.nand_fbcr);
+-		set_addr(mtd, 0, page_addr, 0);
+-
+-		ifc_nand_ctrl->read_bytes = mtd->writesize + mtd->oobsize;
+-		ifc_nand_ctrl->index += column;
+-
+-		if (chip->ecc.mode == NAND_ECC_HW)
+-			ifc_nand_ctrl->eccread = 1;
+-
+-		fsl_ifc_do_read(chip, 0, mtd);
+-		fsl_ifc_run_command(mtd);
+-		return;
+-
+-	/* READOOB reads only the OOB because no ECC is performed. */
+-	case NAND_CMD_READOOB:
+-		ifc_out32(mtd->oobsize - column, &ifc->ifc_nand.nand_fbcr);
+-		set_addr(mtd, column, page_addr, 1);
+-
+-		ifc_nand_ctrl->read_bytes = mtd->writesize + mtd->oobsize;
+-
+-		fsl_ifc_do_read(chip, 1, mtd);
+-		fsl_ifc_run_command(mtd);
+-
+-		return;
+-
+-	case NAND_CMD_READID:
+-	case NAND_CMD_PARAM: {
+-		int timing = IFC_FIR_OP_RB;
+-		if (command == NAND_CMD_PARAM)
+-			timing = IFC_FIR_OP_RBCD;
+-
+-		ifc_out32((IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
+-			  (IFC_FIR_OP_UA  << IFC_NAND_FIR0_OP1_SHIFT) |
+-			  (timing << IFC_NAND_FIR0_OP2_SHIFT),
+-			  &ifc->ifc_nand.nand_fir0);
+-		ifc_out32(command << IFC_NAND_FCR0_CMD0_SHIFT,
+-			  &ifc->ifc_nand.nand_fcr0);
+-		ifc_out32(column, &ifc->ifc_nand.row3);
+-
+-		/*
+-		 * although currently it's 8 bytes for READID, we always read
+-		 * the maximum 256 bytes(for PARAM)
+-		 */
+-		ifc_out32(256, &ifc->ifc_nand.nand_fbcr);
+-		ifc_nand_ctrl->read_bytes = 256;
+-
+-		set_addr(mtd, 0, 0, 0);
+-		fsl_ifc_run_command(mtd);
+-		return;
+-	}
+-
+-	/* ERASE1 stores the block and page address */
+-	case NAND_CMD_ERASE1:
+-		set_addr(mtd, 0, page_addr, 0);
+-		return;
+-
+-	/* ERASE2 uses the block and page address from ERASE1 */
+-	case NAND_CMD_ERASE2:
+-		ifc_out32((IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
+-			  (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP1_SHIFT) |
+-			  (IFC_FIR_OP_CMD1 << IFC_NAND_FIR0_OP2_SHIFT),
+-			  &ifc->ifc_nand.nand_fir0);
+-
+-		ifc_out32((NAND_CMD_ERASE1 << IFC_NAND_FCR0_CMD0_SHIFT) |
+-			  (NAND_CMD_ERASE2 << IFC_NAND_FCR0_CMD1_SHIFT),
+-			  &ifc->ifc_nand.nand_fcr0);
+-
+-		ifc_out32(0, &ifc->ifc_nand.nand_fbcr);
+-		ifc_nand_ctrl->read_bytes = 0;
+-		fsl_ifc_run_command(mtd);
+-		return;
+-
+-	/* SEQIN sets up the addr buffer and all registers except the length */
+-	case NAND_CMD_SEQIN: {
+-		u32 nand_fcr0;
+-		ifc_nand_ctrl->column = column;
+-		ifc_nand_ctrl->oob = 0;
+-
+-		if (mtd->writesize > 512) {
+-			nand_fcr0 =
+-				(NAND_CMD_SEQIN << IFC_NAND_FCR0_CMD0_SHIFT) |
+-				(NAND_CMD_STATUS << IFC_NAND_FCR0_CMD1_SHIFT) |
+-				(NAND_CMD_PAGEPROG << IFC_NAND_FCR0_CMD2_SHIFT);
+-
+-			ifc_out32(
+-				(IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
+-				(IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) |
+-				(IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP2_SHIFT) |
+-				(IFC_FIR_OP_WBCD << IFC_NAND_FIR0_OP3_SHIFT) |
+-				(IFC_FIR_OP_CMD2 << IFC_NAND_FIR0_OP4_SHIFT),
+-				&ifc->ifc_nand.nand_fir0);
+-			ifc_out32(
+-				(IFC_FIR_OP_CW1 << IFC_NAND_FIR1_OP5_SHIFT) |
+-				(IFC_FIR_OP_RDSTAT << IFC_NAND_FIR1_OP6_SHIFT) |
+-				(IFC_FIR_OP_NOP << IFC_NAND_FIR1_OP7_SHIFT),
+-				&ifc->ifc_nand.nand_fir1);
+-		} else {
+-			nand_fcr0 = ((NAND_CMD_PAGEPROG <<
+-					IFC_NAND_FCR0_CMD1_SHIFT) |
+-				    (NAND_CMD_SEQIN <<
+-					IFC_NAND_FCR0_CMD2_SHIFT) |
+-				    (NAND_CMD_STATUS <<
+-					IFC_NAND_FCR0_CMD3_SHIFT));
+-
+-			ifc_out32(
+-				(IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
+-				(IFC_FIR_OP_CMD2 << IFC_NAND_FIR0_OP1_SHIFT) |
+-				(IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP2_SHIFT) |
+-				(IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP3_SHIFT) |
+-				(IFC_FIR_OP_WBCD << IFC_NAND_FIR0_OP4_SHIFT),
+-				&ifc->ifc_nand.nand_fir0);
+-			ifc_out32(
+-				(IFC_FIR_OP_CMD1 << IFC_NAND_FIR1_OP5_SHIFT) |
+-				(IFC_FIR_OP_CW3 << IFC_NAND_FIR1_OP6_SHIFT) |
+-				(IFC_FIR_OP_RDSTAT << IFC_NAND_FIR1_OP7_SHIFT) |
+-				(IFC_FIR_OP_NOP << IFC_NAND_FIR1_OP8_SHIFT),
+-				&ifc->ifc_nand.nand_fir1);
+-
+-			if (column >= mtd->writesize)
+-				nand_fcr0 |=
+-				NAND_CMD_READOOB << IFC_NAND_FCR0_CMD0_SHIFT;
+-			else
+-				nand_fcr0 |=
+-				NAND_CMD_READ0 << IFC_NAND_FCR0_CMD0_SHIFT;
+-		}
+-
+-		if (column >= mtd->writesize) {
+-			/* OOB area --> READOOB */
+-			column -= mtd->writesize;
+-			ifc_nand_ctrl->oob = 1;
+-		}
+-		ifc_out32(nand_fcr0, &ifc->ifc_nand.nand_fcr0);
+-		set_addr(mtd, column, page_addr, ifc_nand_ctrl->oob);
+-		return;
+-	}
+-
+-	/* PAGEPROG reuses all of the setup from SEQIN and adds the length */
+-	case NAND_CMD_PAGEPROG: {
+-		if (ifc_nand_ctrl->oob) {
+-			ifc_out32(ifc_nand_ctrl->index -
+-				  ifc_nand_ctrl->column,
+-				  &ifc->ifc_nand.nand_fbcr);
+-		} else {
+-			ifc_out32(0, &ifc->ifc_nand.nand_fbcr);
+-		}
+-
+-		fsl_ifc_run_command(mtd);
+-		return;
+-	}
+-
+-	case NAND_CMD_STATUS: {
+-		void __iomem *addr;
+-
+-		ifc_out32((IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
+-			  (IFC_FIR_OP_RB << IFC_NAND_FIR0_OP1_SHIFT),
+-			  &ifc->ifc_nand.nand_fir0);
+-		ifc_out32(NAND_CMD_STATUS << IFC_NAND_FCR0_CMD0_SHIFT,
+-			  &ifc->ifc_nand.nand_fcr0);
+-		ifc_out32(1, &ifc->ifc_nand.nand_fbcr);
+-		set_addr(mtd, 0, 0, 0);
+-		ifc_nand_ctrl->read_bytes = 1;
+-
+-		fsl_ifc_run_command(mtd);
+-
+-		/*
+-		 * The chip always seems to report that it is
+-		 * write-protected, even when it is not.
+-		 */
+-		addr = ifc_nand_ctrl->addr;
+-		if (chip->options & NAND_BUSWIDTH_16)
+-			ifc_out16(ifc_in16(addr) | (NAND_STATUS_WP), addr);
+-		else
+-			ifc_out8(ifc_in8(addr) | (NAND_STATUS_WP), addr);
+-		return;
+-	}
+-
+-	case NAND_CMD_RESET:
+-		ifc_out32(IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT,
+-			  &ifc->ifc_nand.nand_fir0);
+-		ifc_out32(NAND_CMD_RESET << IFC_NAND_FCR0_CMD0_SHIFT,
+-			  &ifc->ifc_nand.nand_fcr0);
+-		fsl_ifc_run_command(mtd);
+-		return;
+-
+-	default:
+-		dev_err(priv->dev, "%s: error, unsupported command 0x%x.\n",
+-					__func__, command);
+-	}
+-}
+-
+-static void fsl_ifc_select_chip(struct mtd_info *mtd, int chip)
+-{
+-	/* The hardware does not seem to support multiple
+-	 * chips per bank.
+-	 */
+-}
+-
+-/*
+- * Write buf to the IFC NAND Controller Data Buffer
+- */
+-static void fsl_ifc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
+-	unsigned int bufsize = mtd->writesize + mtd->oobsize;
+-
+-	if (len <= 0) {
+-		dev_err(priv->dev, "%s: len %d bytes", __func__, len);
+-		return;
+-	}
+-
+-	if ((unsigned int)len > bufsize - ifc_nand_ctrl->index) {
+-		dev_err(priv->dev,
+-			"%s: beyond end of buffer (%d requested, %u available)\n",
+-			__func__, len, bufsize - ifc_nand_ctrl->index);
+-		len = bufsize - ifc_nand_ctrl->index;
+-	}
+-
+-	memcpy_toio(ifc_nand_ctrl->addr + ifc_nand_ctrl->index, buf, len);
+-	ifc_nand_ctrl->index += len;
+-}
+-
+-/*
+- * Read a byte from either the IFC hardware buffer
+- * read function for 8-bit buswidth
+- */
+-static uint8_t fsl_ifc_read_byte(struct mtd_info *mtd)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
+-	unsigned int offset;
+-
+-	/*
+-	 * If there are still bytes in the IFC buffer, then use the
+-	 * next byte.
+-	 */
+-	if (ifc_nand_ctrl->index < ifc_nand_ctrl->read_bytes) {
+-		offset = ifc_nand_ctrl->index++;
+-		return ifc_in8(ifc_nand_ctrl->addr + offset);
+-	}
+-
+-	dev_err(priv->dev, "%s: beyond end of buffer\n", __func__);
+-	return ERR_BYTE;
+-}
+-
+-/*
+- * Read two bytes from the IFC hardware buffer
+- * read function for 16-bit buswith
+- */
+-static uint8_t fsl_ifc_read_byte16(struct mtd_info *mtd)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
+-	uint16_t data;
+-
+-	/*
+-	 * If there are still bytes in the IFC buffer, then use the
+-	 * next byte.
+-	 */
+-	if (ifc_nand_ctrl->index < ifc_nand_ctrl->read_bytes) {
+-		data = ifc_in16(ifc_nand_ctrl->addr + ifc_nand_ctrl->index);
+-		ifc_nand_ctrl->index += 2;
+-		return (uint8_t) data;
+-	}
+-
+-	dev_err(priv->dev, "%s: beyond end of buffer\n", __func__);
+-	return ERR_BYTE;
+-}
+-
+-/*
+- * Read from the IFC Controller Data Buffer
+- */
+-static void fsl_ifc_read_buf(struct mtd_info *mtd, u8 *buf, int len)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
+-	int avail;
+-
+-	if (len < 0) {
+-		dev_err(priv->dev, "%s: len %d bytes", __func__, len);
+-		return;
+-	}
+-
+-	avail = min((unsigned int)len,
+-			ifc_nand_ctrl->read_bytes - ifc_nand_ctrl->index);
+-	memcpy_fromio(buf, ifc_nand_ctrl->addr + ifc_nand_ctrl->index, avail);
+-	ifc_nand_ctrl->index += avail;
+-
+-	if (len > avail)
+-		dev_err(priv->dev,
+-			"%s: beyond end of buffer (%d requested, %d available)\n",
+-			__func__, len, avail);
+-}
+-
+-/*
+- * This function is called after Program and Erase Operations to
+- * check for success or failure.
+- */
+-static int fsl_ifc_wait(struct mtd_info *mtd, struct nand_chip *chip)
+-{
+-	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;
+-	u32 nand_fsr;
+-
+-	/* Use READ_STATUS command, but wait for the device to be ready */
+-	ifc_out32((IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
+-		  (IFC_FIR_OP_RDSTAT << IFC_NAND_FIR0_OP1_SHIFT),
+-		  &ifc->ifc_nand.nand_fir0);
+-	ifc_out32(NAND_CMD_STATUS << IFC_NAND_FCR0_CMD0_SHIFT,
+-		  &ifc->ifc_nand.nand_fcr0);
+-	ifc_out32(1, &ifc->ifc_nand.nand_fbcr);
+-	set_addr(mtd, 0, 0, 0);
+-	ifc_nand_ctrl->read_bytes = 1;
+-
+-	fsl_ifc_run_command(mtd);
+-
+-	nand_fsr = ifc_in32(&ifc->ifc_nand.nand_fsr);
+-
+-	/*
+-	 * The chip always seems to report that it is
+-	 * write-protected, even when it is not.
+-	 */
+-	return nand_fsr | NAND_STATUS_WP;
+-}
+-
+-/*
+- * 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)
+-{
+-	struct mtd_info *mtd = nand_to_mtd(chip);
+-	u8 *ecc = chip->oob_poi;
+-	const int ecc_size = chip->ecc.bytes;
+-	const int pkt_size = chip->ecc.size;
+-	int i, res, bitflips = 0;
+-	struct mtd_oob_region oobregion = { };
+-
+-	mtd_ooblayout_ecc(mtd, 0, &oobregion);
+-	ecc += oobregion.offset;
+-
+-	for (i = 0; i < chip->ecc.steps; ++i) {
+-		res = nand_check_erased_ecc_chunk(buf, pkt_size, ecc, ecc_size,
+-						  NULL, 0,
+-						  chip->ecc.strength);
+-		if (res < 0)
+-			mtd->ecc_stats.failed++;
+-		else
+-			mtd->ecc_stats.corrected += res;
+-
+-		bitflips = max(res, bitflips);
+-		buf += pkt_size;
+-		ecc += ecc_size;
+-	}
+-
+-	return bitflips;
+-}
+-
+-static int fsl_ifc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
+-			     uint8_t *buf, int oob_required, int page)
+-{
+-	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;
+-
+-	fsl_ifc_read_buf(mtd, buf, mtd->writesize);
+-	if (oob_required)
+-		fsl_ifc_read_buf(mtd, chip->oob_poi, mtd->oobsize);
+-
+-	if (ctrl->nand_stat & IFC_NAND_EVTER_STAT_ECCER) {
+-		if (!oob_required)
+-			fsl_ifc_read_buf(mtd, chip->oob_poi, mtd->oobsize);
+-
+-		return check_erased_page(chip, buf);
+-	}
+-
+-	if (ctrl->nand_stat != IFC_NAND_EVTER_STAT_OPC)
+-		mtd->ecc_stats.failed++;
+-
+-	return nctrl->max_bitflips;
+-}
+-
+-/* ECC will be calculated automatically, and errors will be detected in
+- * waitfunc.
+- */
+-static int fsl_ifc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
+-			       const uint8_t *buf, int oob_required, int page)
+-{
+-	fsl_ifc_write_buf(mtd, buf, mtd->writesize);
+-	fsl_ifc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
+-
+-	return 0;
+-}
+-
+-static int fsl_ifc_chip_init_tail(struct mtd_info *mtd)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
+-
+-	dev_dbg(priv->dev, "%s: nand->numchips = %d\n", __func__,
+-							chip->numchips);
+-	dev_dbg(priv->dev, "%s: nand->chipsize = %lld\n", __func__,
+-							chip->chipsize);
+-	dev_dbg(priv->dev, "%s: nand->pagemask = %8x\n", __func__,
+-							chip->pagemask);
+-	dev_dbg(priv->dev, "%s: nand->chip_delay = %d\n", __func__,
+-							chip->chip_delay);
+-	dev_dbg(priv->dev, "%s: nand->badblockpos = %d\n", __func__,
+-							chip->badblockpos);
+-	dev_dbg(priv->dev, "%s: nand->chip_shift = %d\n", __func__,
+-							chip->chip_shift);
+-	dev_dbg(priv->dev, "%s: nand->page_shift = %d\n", __func__,
+-							chip->page_shift);
+-	dev_dbg(priv->dev, "%s: nand->phys_erase_shift = %d\n", __func__,
+-							chip->phys_erase_shift);
+-	dev_dbg(priv->dev, "%s: nand->ecc.mode = %d\n", __func__,
+-							chip->ecc.mode);
+-	dev_dbg(priv->dev, "%s: nand->ecc.steps = %d\n", __func__,
+-							chip->ecc.steps);
+-	dev_dbg(priv->dev, "%s: nand->ecc.bytes = %d\n", __func__,
+-							chip->ecc.bytes);
+-	dev_dbg(priv->dev, "%s: nand->ecc.total = %d\n", __func__,
+-							chip->ecc.total);
+-	dev_dbg(priv->dev, "%s: mtd->ooblayout = %p\n", __func__,
+-							mtd->ooblayout);
+-	dev_dbg(priv->dev, "%s: mtd->flags = %08x\n", __func__, mtd->flags);
+-	dev_dbg(priv->dev, "%s: mtd->size = %lld\n", __func__, mtd->size);
+-	dev_dbg(priv->dev, "%s: mtd->erasesize = %d\n", __func__,
+-							mtd->erasesize);
+-	dev_dbg(priv->dev, "%s: mtd->writesize = %d\n", __func__,
+-							mtd->writesize);
+-	dev_dbg(priv->dev, "%s: mtd->oobsize = %d\n", __func__,
+-							mtd->oobsize);
+-
+-	return 0;
+-}
+-
+-static void fsl_ifc_sram_init(struct fsl_ifc_mtd *priv)
+-{
+-	struct fsl_ifc_ctrl *ctrl = priv->ctrl;
+-	struct fsl_ifc_runtime __iomem *ifc_runtime = ctrl->rregs;
+-	struct fsl_ifc_global __iomem *ifc_global = ctrl->gregs;
+-	uint32_t csor = 0, csor_8k = 0, csor_ext = 0;
+-	uint32_t cs = priv->bank;
+-
+-	/* Save CSOR and CSOR_ext */
+-	csor = ifc_in32(&ifc_global->csor_cs[cs].csor);
+-	csor_ext = ifc_in32(&ifc_global->csor_cs[cs].csor_ext);
+-
+-	/* chage PageSize 8K and SpareSize 1K*/
+-	csor_8k = (csor & ~(CSOR_NAND_PGS_MASK)) | 0x0018C000;
+-	ifc_out32(csor_8k, &ifc_global->csor_cs[cs].csor);
+-	ifc_out32(0x0000400, &ifc_global->csor_cs[cs].csor_ext);
+-
+-	/* READID */
+-	ifc_out32((IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
+-		    (IFC_FIR_OP_UA  << IFC_NAND_FIR0_OP1_SHIFT) |
+-		    (IFC_FIR_OP_RB << IFC_NAND_FIR0_OP2_SHIFT),
+-		    &ifc_runtime->ifc_nand.nand_fir0);
+-	ifc_out32(NAND_CMD_READID << IFC_NAND_FCR0_CMD0_SHIFT,
+-		    &ifc_runtime->ifc_nand.nand_fcr0);
+-	ifc_out32(0x0, &ifc_runtime->ifc_nand.row3);
+-
+-	ifc_out32(0x0, &ifc_runtime->ifc_nand.nand_fbcr);
+-
+-	/* Program ROW0/COL0 */
+-	ifc_out32(0x0, &ifc_runtime->ifc_nand.row0);
+-	ifc_out32(0x0, &ifc_runtime->ifc_nand.col0);
+-
+-	/* set the chip select for NAND Transaction */
+-	ifc_out32(cs << IFC_NAND_CSEL_SHIFT,
+-		&ifc_runtime->ifc_nand.nand_csel);
+-
+-	/* start read seq */
+-	ifc_out32(IFC_NAND_SEQ_STRT_FIR_STRT,
+-		&ifc_runtime->ifc_nand.nandseq_strt);
+-
+-	/* wait for command complete flag or timeout */
+-	wait_event_timeout(ctrl->nand_wait, ctrl->nand_stat,
+-			   msecs_to_jiffies(IFC_TIMEOUT_MSECS));
+-
+-	if (ctrl->nand_stat != IFC_NAND_EVTER_STAT_OPC)
+-		printk(KERN_ERR "fsl-ifc: Failed to Initialise SRAM\n");
+-
+-	/* Restore CSOR and CSOR_ext */
+-	ifc_out32(csor, &ifc_global->csor_cs[cs].csor);
+-	ifc_out32(csor_ext, &ifc_global->csor_cs[cs].csor_ext);
+-}
+-
+-static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
+-{
+-	struct fsl_ifc_ctrl *ctrl = priv->ctrl;
+-	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);
+-	u32 csor;
+-
+-	/* Fill in fsl_ifc_mtd structure */
+-	mtd->dev.parent = priv->dev;
+-	nand_set_flash_node(chip, priv->dev->of_node);
+-
+-	/* fill in nand_chip structure */
+-	/* set up function call table */
+-	if ((ifc_in32(&ifc_global->cspr_cs[priv->bank].cspr))
+-		& CSPR_PORT_SIZE_16)
+-		chip->read_byte = fsl_ifc_read_byte16;
+-	else
+-		chip->read_byte = fsl_ifc_read_byte;
+-
+-	chip->write_buf = fsl_ifc_write_buf;
+-	chip->read_buf = fsl_ifc_read_buf;
+-	chip->select_chip = fsl_ifc_select_chip;
+-	chip->cmdfunc = fsl_ifc_cmdfunc;
+-	chip->waitfunc = fsl_ifc_wait;
+-	chip->onfi_set_features = nand_onfi_get_set_features_notsupp;
+-	chip->onfi_get_features = nand_onfi_get_set_features_notsupp;
+-
+-	chip->bbt_td = &bbt_main_descr;
+-	chip->bbt_md = &bbt_mirror_descr;
+-
+-	ifc_out32(0x0, &ifc_runtime->ifc_nand.ncfgr);
+-
+-	/* set up nand options */
+-	chip->bbt_options = NAND_BBT_USE_FLASH;
+-	chip->options = NAND_NO_SUBPAGE_WRITE;
+-
+-	if (ifc_in32(&ifc_global->cspr_cs[priv->bank].cspr)
+-		& CSPR_PORT_SIZE_16) {
+-		chip->read_byte = fsl_ifc_read_byte16;
+-		chip->options |= NAND_BUSWIDTH_16;
+-	} else {
+-		chip->read_byte = fsl_ifc_read_byte;
+-	}
+-
+-	chip->controller = &ifc_nand_ctrl->controller;
+-	nand_set_controller_data(chip, priv);
+-
+-	chip->ecc.read_page = fsl_ifc_read_page;
+-	chip->ecc.write_page = fsl_ifc_write_page;
+-
+-	csor = ifc_in32(&ifc_global->csor_cs[priv->bank].csor);
+-
+-	switch (csor & CSOR_NAND_PGS_MASK) {
+-	case CSOR_NAND_PGS_512:
+-		if (!(chip->options & NAND_BUSWIDTH_16)) {
+-			/* Avoid conflict with bad block marker */
+-			bbt_main_descr.offs = 0;
+-			bbt_mirror_descr.offs = 0;
+-		}
+-
+-		priv->bufnum_mask = 15;
+-		break;
+-
+-	case CSOR_NAND_PGS_2K:
+-		priv->bufnum_mask = 3;
+-		break;
+-
+-	case CSOR_NAND_PGS_4K:
+-		priv->bufnum_mask = 1;
+-		break;
+-
+-	case CSOR_NAND_PGS_8K:
+-		priv->bufnum_mask = 0;
+-		break;
+-
+-	default:
+-		dev_err(priv->dev, "bad csor %#x: bad page size\n", csor);
+-		return -ENODEV;
+-	}
+-
+-	/* Must also set CSOR_NAND_ECC_ENC_EN if DEC_EN set */
+-	if (csor & CSOR_NAND_ECC_DEC_EN) {
+-		chip->ecc.mode = NAND_ECC_HW;
+-		mtd_set_ooblayout(mtd, &fsl_ifc_ooblayout_ops);
+-
+-		/* Hardware generates ECC per 512 Bytes */
+-		chip->ecc.size = 512;
+-		if ((csor & CSOR_NAND_ECC_MODE_MASK) == CSOR_NAND_ECC_MODE_4) {
+-			chip->ecc.bytes = 8;
+-			chip->ecc.strength = 4;
+-		} else {
+-			chip->ecc.bytes = 16;
+-			chip->ecc.strength = 8;
+-		}
+-	} else {
+-		chip->ecc.mode = NAND_ECC_SOFT;
+-		chip->ecc.algo = NAND_ECC_HAMMING;
+-	}
+-
+-	if (ctrl->version >= FSL_IFC_VERSION_1_1_0)
+-		fsl_ifc_sram_init(priv);
+-
+-	return 0;
+-}
+-
+-static int fsl_ifc_chip_remove(struct fsl_ifc_mtd *priv)
+-{
+-	struct mtd_info *mtd = nand_to_mtd(&priv->chip);
+-
+-	nand_release(mtd);
+-
+-	kfree(mtd->name);
+-
+-	if (priv->vbase)
+-		iounmap(priv->vbase);
+-
+-	ifc_nand_ctrl->chips[priv->bank] = NULL;
+-
+-	return 0;
+-}
+-
+-static int match_bank(struct fsl_ifc_global __iomem *ifc_global, int bank,
+-		      phys_addr_t addr)
+-{
+-	u32 cspr = ifc_in32(&ifc_global->cspr_cs[bank].cspr);
+-
+-	if (!(cspr & CSPR_V))
+-		return 0;
+-	if ((cspr & CSPR_MSEL) != CSPR_MSEL_NAND)
+-		return 0;
+-
+-	return (cspr & CSPR_BA) == convert_ifc_address(addr);
+-}
+-
+-static DEFINE_MUTEX(fsl_ifc_nand_mutex);
+-
+-static int fsl_ifc_nand_probe(struct platform_device *dev)
+-{
+-	struct fsl_ifc_runtime __iomem *ifc;
+-	struct fsl_ifc_mtd *priv;
+-	struct resource res;
+-	static const char *part_probe_types[]
+-		= { "cmdlinepart", "RedBoot", "ofpart", NULL };
+-	int ret;
+-	int bank;
+-	struct device_node *node = dev->dev.of_node;
+-	struct mtd_info *mtd;
+-
+-	if (!fsl_ifc_ctrl_dev || !fsl_ifc_ctrl_dev->rregs)
+-		return -ENODEV;
+-	ifc = fsl_ifc_ctrl_dev->rregs;
+-
+-	/* get, allocate and map the memory resource */
+-	ret = of_address_to_resource(node, 0, &res);
+-	if (ret) {
+-		dev_err(&dev->dev, "%s: failed to get resource\n", __func__);
+-		return ret;
+-	}
+-
+-	/* find which chip select it is connected to */
+-	for (bank = 0; bank < fsl_ifc_ctrl_dev->banks; bank++) {
+-		if (match_bank(fsl_ifc_ctrl_dev->gregs, bank, res.start))
+-			break;
+-	}
+-
+-	if (bank >= fsl_ifc_ctrl_dev->banks) {
+-		dev_err(&dev->dev, "%s: address did not match any chip selects\n",
+-			__func__);
+-		return -ENODEV;
+-	}
+-
+-	priv = devm_kzalloc(&dev->dev, sizeof(*priv), GFP_KERNEL);
+-	if (!priv)
+-		return -ENOMEM;
+-
+-	mutex_lock(&fsl_ifc_nand_mutex);
+-	if (!fsl_ifc_ctrl_dev->nand) {
+-		ifc_nand_ctrl = kzalloc(sizeof(*ifc_nand_ctrl), GFP_KERNEL);
+-		if (!ifc_nand_ctrl) {
+-			mutex_unlock(&fsl_ifc_nand_mutex);
+-			return -ENOMEM;
+-		}
+-
+-		ifc_nand_ctrl->read_bytes = 0;
+-		ifc_nand_ctrl->index = 0;
+-		ifc_nand_ctrl->addr = NULL;
+-		fsl_ifc_ctrl_dev->nand = ifc_nand_ctrl;
+-
+-		nand_hw_control_init(&ifc_nand_ctrl->controller);
+-	} else {
+-		ifc_nand_ctrl = fsl_ifc_ctrl_dev->nand;
+-	}
+-	mutex_unlock(&fsl_ifc_nand_mutex);
+-
+-	ifc_nand_ctrl->chips[bank] = priv;
+-	priv->bank = bank;
+-	priv->ctrl = fsl_ifc_ctrl_dev;
+-	priv->dev = &dev->dev;
+-
+-	priv->vbase = ioremap(res.start, resource_size(&res));
+-	if (!priv->vbase) {
+-		dev_err(priv->dev, "%s: failed to map chip region\n", __func__);
+-		ret = -ENOMEM;
+-		goto err;
+-	}
+-
+-	dev_set_drvdata(priv->dev, priv);
+-
+-	ifc_out32(IFC_NAND_EVTER_EN_OPC_EN |
+-		  IFC_NAND_EVTER_EN_FTOER_EN |
+-		  IFC_NAND_EVTER_EN_WPER_EN,
+-		  &ifc->ifc_nand.nand_evter_en);
+-
+-	/* enable NAND Machine Interrupts */
+-	ifc_out32(IFC_NAND_EVTER_INTR_OPCIR_EN |
+-		  IFC_NAND_EVTER_INTR_FTOERIR_EN |
+-		  IFC_NAND_EVTER_INTR_WPERIR_EN,
+-		  &ifc->ifc_nand.nand_evter_intr_en);
+-
+-	mtd = nand_to_mtd(&priv->chip);
+-	mtd->name = kasprintf(GFP_KERNEL, "%llx.flash", (u64)res.start);
+-	if (!mtd->name) {
+-		ret = -ENOMEM;
+-		goto err;
+-	}
+-
+-	ret = fsl_ifc_chip_init(priv);
+-	if (ret)
+-		goto err;
+-
+-	ret = nand_scan_ident(mtd, 1, NULL);
+-	if (ret)
+-		goto err;
+-
+-	ret = fsl_ifc_chip_init_tail(mtd);
+-	if (ret)
+-		goto err;
+-
+-	ret = nand_scan_tail(mtd);
+-	if (ret)
+-		goto err;
+-
+-	/* First look for RedBoot table or partitions on the command
+-	 * line, these take precedence over device tree information */
+-	mtd_device_parse_register(mtd, part_probe_types, NULL, NULL, 0);
+-
+-	dev_info(priv->dev, "IFC NAND device at 0x%llx, bank %d\n",
+-		 (unsigned long long)res.start, priv->bank);
+-	return 0;
+-
+-err:
+-	fsl_ifc_chip_remove(priv);
+-	return ret;
+-}
+-
+-static int fsl_ifc_nand_remove(struct platform_device *dev)
+-{
+-	struct fsl_ifc_mtd *priv = dev_get_drvdata(&dev->dev);
+-
+-	fsl_ifc_chip_remove(priv);
+-
+-	mutex_lock(&fsl_ifc_nand_mutex);
+-	ifc_nand_ctrl->counter--;
+-	if (!ifc_nand_ctrl->counter) {
+-		fsl_ifc_ctrl_dev->nand = NULL;
+-		kfree(ifc_nand_ctrl);
+-	}
+-	mutex_unlock(&fsl_ifc_nand_mutex);
+-
+-	return 0;
+-}
+-
+-static const struct of_device_id fsl_ifc_nand_match[] = {
+-	{
+-		.compatible = "fsl,ifc-nand",
+-	},
+-	{}
+-};
+-MODULE_DEVICE_TABLE(of, fsl_ifc_nand_match);
+-
+-static struct platform_driver fsl_ifc_nand_driver = {
+-	.driver = {
+-		.name	= "fsl,ifc-nand",
+-		.of_match_table = fsl_ifc_nand_match,
+-	},
+-	.probe       = fsl_ifc_nand_probe,
+-	.remove      = fsl_ifc_nand_remove,
+-};
+-
+-module_platform_driver(fsl_ifc_nand_driver);
+-
+-MODULE_LICENSE("GPL");
+-MODULE_AUTHOR("Freescale");
+-MODULE_DESCRIPTION("Freescale Integrated Flash Controller MTD NAND driver");
+diff --git a/drivers/mtd/nand/fsl_upm.c b/drivers/mtd/nand/fsl_upm.c
+deleted file mode 100644
+index a88e2cf..0000000
+--- a/drivers/mtd/nand/fsl_upm.c
++++ /dev/null
+@@ -1,363 +0,0 @@
+-/*
+- * Freescale UPM NAND driver.
+- *
+- * Copyright © 2007-2008  MontaVista Software, Inc.
+- *
+- * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
+- *
+- * 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/kernel.h>
+-#include <linux/module.h>
+-#include <linux/delay.h>
+-#include <linux/mtd/rawnand.h>
+-#include <linux/mtd/nand_ecc.h>
+-#include <linux/mtd/partitions.h>
+-#include <linux/mtd/mtd.h>
+-#include <linux/of_address.h>
+-#include <linux/of_platform.h>
+-#include <linux/of_gpio.h>
+-#include <linux/io.h>
+-#include <linux/slab.h>
+-#include <asm/fsl_lbc.h>
+-
+-#define FSL_UPM_WAIT_RUN_PATTERN  0x1
+-#define FSL_UPM_WAIT_WRITE_BYTE   0x2
+-#define FSL_UPM_WAIT_WRITE_BUFFER 0x4
+-
+-struct fsl_upm_nand {
+-	struct device *dev;
+-	struct nand_chip chip;
+-	int last_ctrl;
+-	struct mtd_partition *parts;
+-	struct fsl_upm upm;
+-	uint8_t upm_addr_offset;
+-	uint8_t upm_cmd_offset;
+-	void __iomem *io_base;
+-	int rnb_gpio[NAND_MAX_CHIPS];
+-	uint32_t mchip_offsets[NAND_MAX_CHIPS];
+-	uint32_t mchip_count;
+-	uint32_t mchip_number;
+-	int chip_delay;
+-	uint32_t wait_flags;
+-};
+-
+-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,
+-			    chip);
+-}
+-
+-static int fun_chip_ready(struct mtd_info *mtd)
+-{
+-	struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd);
+-
+-	if (gpio_get_value(fun->rnb_gpio[fun->mchip_number]))
+-		return 1;
+-
+-	dev_vdbg(fun->dev, "busy\n");
+-	return 0;
+-}
+-
+-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);
+-		int cnt = 1000000;
+-
+-		while (--cnt && !fun_chip_ready(mtd))
+-			cpu_relax();
+-		if (!cnt)
+-			dev_err(fun->dev, "tired waiting for RNB\n");
+-	} else {
+-		ndelay(100);
+-	}
+-}
+-
+-static void fun_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd);
+-	u32 mar;
+-
+-	if (!(ctrl & fun->last_ctrl)) {
+-		fsl_upm_end_pattern(&fun->upm);
+-
+-		if (cmd == NAND_CMD_NONE)
+-			return;
+-
+-		fun->last_ctrl = ctrl & (NAND_ALE | NAND_CLE);
+-	}
+-
+-	if (ctrl & NAND_CTRL_CHANGE) {
+-		if (ctrl & NAND_ALE)
+-			fsl_upm_start_pattern(&fun->upm, fun->upm_addr_offset);
+-		else if (ctrl & NAND_CLE)
+-			fsl_upm_start_pattern(&fun->upm, fun->upm_cmd_offset);
+-	}
+-
+-	mar = (cmd << (32 - fun->upm.width)) |
+-		fun->mchip_offsets[fun->mchip_number];
+-	fsl_upm_run_pattern(&fun->upm, chip->IO_ADDR_R, mar);
+-
+-	if (fun->wait_flags & FSL_UPM_WAIT_RUN_PATTERN)
+-		fun_wait_rnb(fun);
+-}
+-
+-static void fun_select_chip(struct mtd_info *mtd, int mchip_nr)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd);
+-
+-	if (mchip_nr == -1) {
+-		chip->cmd_ctrl(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE);
+-	} else if (mchip_nr >= 0 && mchip_nr < NAND_MAX_CHIPS) {
+-		fun->mchip_number = mchip_nr;
+-		chip->IO_ADDR_R = fun->io_base + fun->mchip_offsets[mchip_nr];
+-		chip->IO_ADDR_W = chip->IO_ADDR_R;
+-	} else {
+-		BUG();
+-	}
+-}
+-
+-static uint8_t fun_read_byte(struct mtd_info *mtd)
+-{
+-	struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd);
+-
+-	return in_8(fun->chip.IO_ADDR_R);
+-}
+-
+-static void fun_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+-{
+-	struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd);
+-	int i;
+-
+-	for (i = 0; i < len; i++)
+-		buf[i] = in_8(fun->chip.IO_ADDR_R);
+-}
+-
+-static void fun_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+-{
+-	struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd);
+-	int i;
+-
+-	for (i = 0; i < len; i++) {
+-		out_8(fun->chip.IO_ADDR_W, buf[i]);
+-		if (fun->wait_flags & FSL_UPM_WAIT_WRITE_BYTE)
+-			fun_wait_rnb(fun);
+-	}
+-	if (fun->wait_flags & FSL_UPM_WAIT_WRITE_BUFFER)
+-		fun_wait_rnb(fun);
+-}
+-
+-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);
+-	int ret;
+-	struct device_node *flash_np;
+-
+-	fun->chip.IO_ADDR_R = fun->io_base;
+-	fun->chip.IO_ADDR_W = fun->io_base;
+-	fun->chip.cmd_ctrl = fun_cmd_ctrl;
+-	fun->chip.chip_delay = fun->chip_delay;
+-	fun->chip.read_byte = fun_read_byte;
+-	fun->chip.read_buf = fun_read_buf;
+-	fun->chip.write_buf = fun_write_buf;
+-	fun->chip.ecc.mode = NAND_ECC_SOFT;
+-	fun->chip.ecc.algo = NAND_ECC_HAMMING;
+-	if (fun->mchip_count > 1)
+-		fun->chip.select_chip = fun_select_chip;
+-
+-	if (fun->rnb_gpio[0] >= 0)
+-		fun->chip.dev_ready = fun_chip_ready;
+-
+-	mtd->dev.parent = fun->dev;
+-
+-	flash_np = of_get_next_child(upm_np, NULL);
+-	if (!flash_np)
+-		return -ENODEV;
+-
+-	nand_set_flash_node(&fun->chip, flash_np);
+-	mtd->name = kasprintf(GFP_KERNEL, "0x%llx.%s", (u64)io_res->start,
+-			      flash_np->name);
+-	if (!mtd->name) {
+-		ret = -ENOMEM;
+-		goto err;
+-	}
+-
+-	ret = nand_scan(mtd, fun->mchip_count);
+-	if (ret)
+-		goto err;
+-
+-	ret = mtd_device_register(mtd, NULL, 0);
+-err:
+-	of_node_put(flash_np);
+-	if (ret)
+-		kfree(mtd->name);
+-	return ret;
+-}
+-
+-static int fun_probe(struct platform_device *ofdev)
+-{
+-	struct fsl_upm_nand *fun;
+-	struct resource io_res;
+-	const __be32 *prop;
+-	int rnb_gpio;
+-	int ret;
+-	int size;
+-	int i;
+-
+-	fun = kzalloc(sizeof(*fun), GFP_KERNEL);
+-	if (!fun)
+-		return -ENOMEM;
+-
+-	ret = of_address_to_resource(ofdev->dev.of_node, 0, &io_res);
+-	if (ret) {
+-		dev_err(&ofdev->dev, "can't get IO base\n");
+-		goto err1;
+-	}
+-
+-	ret = fsl_upm_find(io_res.start, &fun->upm);
+-	if (ret) {
+-		dev_err(&ofdev->dev, "can't find UPM\n");
+-		goto err1;
+-	}
+-
+-	prop = of_get_property(ofdev->dev.of_node, "fsl,upm-addr-offset",
+-			       &size);
+-	if (!prop || size != sizeof(uint32_t)) {
+-		dev_err(&ofdev->dev, "can't get UPM address offset\n");
+-		ret = -EINVAL;
+-		goto err1;
+-	}
+-	fun->upm_addr_offset = *prop;
+-
+-	prop = of_get_property(ofdev->dev.of_node, "fsl,upm-cmd-offset", &size);
+-	if (!prop || size != sizeof(uint32_t)) {
+-		dev_err(&ofdev->dev, "can't get UPM command offset\n");
+-		ret = -EINVAL;
+-		goto err1;
+-	}
+-	fun->upm_cmd_offset = *prop;
+-
+-	prop = of_get_property(ofdev->dev.of_node,
+-			       "fsl,upm-addr-line-cs-offsets", &size);
+-	if (prop && (size / sizeof(uint32_t)) > 0) {
+-		fun->mchip_count = size / sizeof(uint32_t);
+-		if (fun->mchip_count >= NAND_MAX_CHIPS) {
+-			dev_err(&ofdev->dev, "too much multiple chips\n");
+-			goto err1;
+-		}
+-		for (i = 0; i < fun->mchip_count; i++)
+-			fun->mchip_offsets[i] = be32_to_cpu(prop[i]);
+-	} else {
+-		fun->mchip_count = 1;
+-	}
+-
+-	for (i = 0; i < fun->mchip_count; i++) {
+-		fun->rnb_gpio[i] = -1;
+-		rnb_gpio = of_get_gpio(ofdev->dev.of_node, i);
+-		if (rnb_gpio >= 0) {
+-			ret = gpio_request(rnb_gpio, dev_name(&ofdev->dev));
+-			if (ret) {
+-				dev_err(&ofdev->dev,
+-					"can't request RNB gpio #%d\n", i);
+-				goto err2;
+-			}
+-			gpio_direction_input(rnb_gpio);
+-			fun->rnb_gpio[i] = rnb_gpio;
+-		} else if (rnb_gpio == -EINVAL) {
+-			dev_err(&ofdev->dev, "RNB gpio #%d is invalid\n", i);
+-			goto err2;
+-		}
+-	}
+-
+-	prop = of_get_property(ofdev->dev.of_node, "chip-delay", NULL);
+-	if (prop)
+-		fun->chip_delay = be32_to_cpup(prop);
+-	else
+-		fun->chip_delay = 50;
+-
+-	prop = of_get_property(ofdev->dev.of_node, "fsl,upm-wait-flags", &size);
+-	if (prop && size == sizeof(uint32_t))
+-		fun->wait_flags = be32_to_cpup(prop);
+-	else
+-		fun->wait_flags = FSL_UPM_WAIT_RUN_PATTERN |
+-				  FSL_UPM_WAIT_WRITE_BYTE;
+-
+-	fun->io_base = devm_ioremap_nocache(&ofdev->dev, io_res.start,
+-					    resource_size(&io_res));
+-	if (!fun->io_base) {
+-		ret = -ENOMEM;
+-		goto err2;
+-	}
+-
+-	fun->dev = &ofdev->dev;
+-	fun->last_ctrl = NAND_CLE;
+-
+-	ret = fun_chip_init(fun, ofdev->dev.of_node, &io_res);
+-	if (ret)
+-		goto err2;
+-
+-	dev_set_drvdata(&ofdev->dev, fun);
+-
+-	return 0;
+-err2:
+-	for (i = 0; i < fun->mchip_count; i++) {
+-		if (fun->rnb_gpio[i] < 0)
+-			break;
+-		gpio_free(fun->rnb_gpio[i]);
+-	}
+-err1:
+-	kfree(fun);
+-
+-	return ret;
+-}
+-
+-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);
+-	int i;
+-
+-	nand_release(mtd);
+-	kfree(mtd->name);
+-
+-	for (i = 0; i < fun->mchip_count; i++) {
+-		if (fun->rnb_gpio[i] < 0)
+-			break;
+-		gpio_free(fun->rnb_gpio[i]);
+-	}
+-
+-	kfree(fun);
+-
+-	return 0;
+-}
+-
+-static const struct of_device_id of_fun_match[] = {
+-	{ .compatible = "fsl,upm-nand" },
+-	{},
+-};
+-MODULE_DEVICE_TABLE(of, of_fun_match);
+-
+-static struct platform_driver of_fun_driver = {
+-	.driver = {
+-		.name = "fsl,upm-nand",
+-		.of_match_table = of_fun_match,
+-	},
+-	.probe		= fun_probe,
+-	.remove		= fun_remove,
+-};
+-
+-module_platform_driver(of_fun_driver);
+-
+-MODULE_LICENSE("GPL");
+-MODULE_AUTHOR("Anton Vorontsov <avorontsov@ru.mvista.com>");
+-MODULE_DESCRIPTION("Driver for NAND chips working through Freescale "
+-		   "LocalBus User-Programmable Machine");
+diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c
+deleted file mode 100644
+index eac15d9..0000000
+--- a/drivers/mtd/nand/fsmc_nand.c
++++ /dev/null
+@@ -1,1176 +0,0 @@
+-/*
+- * drivers/mtd/nand/fsmc_nand.c
+- *
+- * ST Microelectronics
+- * Flexible Static Memory Controller (FSMC)
+- * Driver for NAND portions
+- *
+- * Copyright © 2010 ST Microelectronics
+- * Vipin Kumar <vipin.kumar@st.com>
+- * Ashish Priyadarshi
+- *
+- * Based on drivers/mtd/nand/nomadik_nand.c
+- *
+- * This file is licensed under the terms of the GNU General Public
+- * License version 2. This program is licensed "as is" without any
+- * warranty of any kind, whether express or implied.
+- */
+-
+-#include <linux/clk.h>
+-#include <linux/completion.h>
+-#include <linux/dmaengine.h>
+-#include <linux/dma-direction.h>
+-#include <linux/dma-mapping.h>
+-#include <linux/err.h>
+-#include <linux/init.h>
+-#include <linux/module.h>
+-#include <linux/resource.h>
+-#include <linux/sched.h>
+-#include <linux/types.h>
+-#include <linux/mtd/mtd.h>
+-#include <linux/mtd/rawnand.h>
+-#include <linux/mtd/nand_ecc.h>
+-#include <linux/platform_device.h>
+-#include <linux/of.h>
+-#include <linux/mtd/partitions.h>
+-#include <linux/io.h>
+-#include <linux/slab.h>
+-#include <linux/amba/bus.h>
+-#include <mtd/mtd-abi.h>
+-
+-/* fsmc controller registers for NOR flash */
+-#define CTRL			0x0
+-	/* ctrl register definitions */
+-	#define BANK_ENABLE		(1 << 0)
+-	#define MUXED			(1 << 1)
+-	#define NOR_DEV			(2 << 2)
+-	#define WIDTH_8			(0 << 4)
+-	#define WIDTH_16		(1 << 4)
+-	#define RSTPWRDWN		(1 << 6)
+-	#define WPROT			(1 << 7)
+-	#define WRT_ENABLE		(1 << 12)
+-	#define WAIT_ENB		(1 << 13)
+-
+-#define CTRL_TIM		0x4
+-	/* ctrl_tim register definitions */
+-
+-#define FSMC_NOR_BANK_SZ	0x8
+-#define FSMC_NOR_REG_SIZE	0x40
+-
+-#define FSMC_NOR_REG(base, bank, reg)		(base + \
+-						FSMC_NOR_BANK_SZ * (bank) + \
+-						reg)
+-
+-/* fsmc controller registers for NAND flash */
+-#define PC			0x00
+-	/* pc register definitions */
+-	#define FSMC_RESET		(1 << 0)
+-	#define FSMC_WAITON		(1 << 1)
+-	#define FSMC_ENABLE		(1 << 2)
+-	#define FSMC_DEVTYPE_NAND	(1 << 3)
+-	#define FSMC_DEVWID_8		(0 << 4)
+-	#define FSMC_DEVWID_16		(1 << 4)
+-	#define FSMC_ECCEN		(1 << 6)
+-	#define FSMC_ECCPLEN_512	(0 << 7)
+-	#define FSMC_ECCPLEN_256	(1 << 7)
+-	#define FSMC_TCLR_1		(1)
+-	#define FSMC_TCLR_SHIFT		(9)
+-	#define FSMC_TCLR_MASK		(0xF)
+-	#define FSMC_TAR_1		(1)
+-	#define FSMC_TAR_SHIFT		(13)
+-	#define FSMC_TAR_MASK		(0xF)
+-#define STS			0x04
+-	/* sts register definitions */
+-	#define FSMC_CODE_RDY		(1 << 15)
+-#define COMM			0x08
+-	/* comm register definitions */
+-	#define FSMC_TSET_0		0
+-	#define FSMC_TSET_SHIFT		0
+-	#define FSMC_TSET_MASK		0xFF
+-	#define FSMC_TWAIT_6		6
+-	#define FSMC_TWAIT_SHIFT	8
+-	#define FSMC_TWAIT_MASK		0xFF
+-	#define FSMC_THOLD_4		4
+-	#define FSMC_THOLD_SHIFT	16
+-	#define FSMC_THOLD_MASK		0xFF
+-	#define FSMC_THIZ_1		1
+-	#define FSMC_THIZ_SHIFT		24
+-	#define FSMC_THIZ_MASK		0xFF
+-#define ATTRIB			0x0C
+-#define IOATA			0x10
+-#define ECC1			0x14
+-#define ECC2			0x18
+-#define ECC3			0x1C
+-#define FSMC_NAND_BANK_SZ	0x20
+-
+-#define FSMC_NAND_REG(base, bank, reg)		(base + FSMC_NOR_REG_SIZE + \
+-						(FSMC_NAND_BANK_SZ * (bank)) + \
+-						reg)
+-
+-#define FSMC_BUSY_WAIT_TIMEOUT	(1 * HZ)
+-
+-struct fsmc_nand_timings {
+-	uint8_t tclr;
+-	uint8_t tar;
+-	uint8_t thiz;
+-	uint8_t thold;
+-	uint8_t twait;
+-	uint8_t tset;
+-};
+-
+-enum access_mode {
+-	USE_DMA_ACCESS = 1,
+-	USE_WORD_ACCESS,
+-};
+-
+-/**
+- * struct fsmc_nand_data - structure for FSMC NAND device state
+- *
+- * @pid:		Part ID on the AMBA PrimeCell format
+- * @mtd:		MTD info for a NAND flash.
+- * @nand:		Chip related info for a NAND flash.
+- * @partitions:		Partition info for a NAND Flash.
+- * @nr_partitions:	Total number of partition of a NAND flash.
+- *
+- * @bank:		Bank number for probed device.
+- * @clk:		Clock structure for FSMC.
+- *
+- * @read_dma_chan:	DMA channel for read access
+- * @write_dma_chan:	DMA channel for write access to NAND
+- * @dma_access_complete: Completion structure
+- *
+- * @data_pa:		NAND Physical port for Data.
+- * @data_va:		NAND port for Data.
+- * @cmd_va:		NAND port for Command.
+- * @addr_va:		NAND port for Address.
+- * @regs_va:		FSMC regs base address.
+- */
+-struct fsmc_nand_data {
+-	u32			pid;
+-	struct nand_chip	nand;
+-
+-	unsigned int		bank;
+-	struct device		*dev;
+-	enum access_mode	mode;
+-	struct clk		*clk;
+-
+-	/* DMA related objects */
+-	struct dma_chan		*read_dma_chan;
+-	struct dma_chan		*write_dma_chan;
+-	struct completion	dma_access_complete;
+-
+-	struct fsmc_nand_timings *dev_timings;
+-
+-	dma_addr_t		data_pa;
+-	void __iomem		*data_va;
+-	void __iomem		*cmd_va;
+-	void __iomem		*addr_va;
+-	void __iomem		*regs_va;
+-};
+-
+-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);
+-
+-	if (section >= chip->ecc.steps)
+-		return -ERANGE;
+-
+-	oobregion->offset = (section * 16) + 2;
+-	oobregion->length = 3;
+-
+-	return 0;
+-}
+-
+-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);
+-
+-	if (section >= chip->ecc.steps)
+-		return -ERANGE;
+-
+-	oobregion->offset = (section * 16) + 8;
+-
+-	if (section < chip->ecc.steps - 1)
+-		oobregion->length = 8;
+-	else
+-		oobregion->length = mtd->oobsize - oobregion->offset;
+-
+-	return 0;
+-}
+-
+-static const struct mtd_ooblayout_ops fsmc_ecc1_ooblayout_ops = {
+-	.ecc = fsmc_ecc1_ooblayout_ecc,
+-	.free = fsmc_ecc1_ooblayout_free,
+-};
+-
+-/*
+- * ECC placement definitions in oobfree type format.
+- * There are 13 bytes of ecc for every 512 byte block and it has to be read
+- * consecutively and immediately after the 512 byte data block for hardware to
+- * generate the error bit offsets in 512 byte data.
+- */
+-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);
+-
+-	if (section >= chip->ecc.steps)
+-		return -ERANGE;
+-
+-	oobregion->length = chip->ecc.bytes;
+-
+-	if (!section && mtd->writesize <= 512)
+-		oobregion->offset = 0;
+-	else
+-		oobregion->offset = (section * 16) + 2;
+-
+-	return 0;
+-}
+-
+-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);
+-
+-	if (section >= chip->ecc.steps)
+-		return -ERANGE;
+-
+-	oobregion->offset = (section * 16) + 15;
+-
+-	if (section < chip->ecc.steps - 1)
+-		oobregion->length = 3;
+-	else
+-		oobregion->length = mtd->oobsize - oobregion->offset;
+-
+-	return 0;
+-}
+-
+-static const struct mtd_ooblayout_ops fsmc_ecc4_ooblayout_ops = {
+-	.ecc = fsmc_ecc4_ooblayout_ecc,
+-	.free = fsmc_ecc4_ooblayout_free,
+-};
+-
+-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);
+-}
+-
+-/*
+- * fsmc_cmd_ctrl - For facilitaing Hardware access
+- * This routine allows hardware specific access to control-lines(ALE,CLE)
+- */
+-static void fsmc_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+-{
+-	struct nand_chip *this = mtd_to_nand(mtd);
+-	struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
+-	void __iomem *regs = host->regs_va;
+-	unsigned int bank = host->bank;
+-
+-	if (ctrl & NAND_CTRL_CHANGE) {
+-		u32 pc;
+-
+-		if (ctrl & NAND_CLE) {
+-			this->IO_ADDR_R = host->cmd_va;
+-			this->IO_ADDR_W = host->cmd_va;
+-		} else if (ctrl & NAND_ALE) {
+-			this->IO_ADDR_R = host->addr_va;
+-			this->IO_ADDR_W = host->addr_va;
+-		} else {
+-			this->IO_ADDR_R = host->data_va;
+-			this->IO_ADDR_W = host->data_va;
+-		}
+-
+-		pc = readl(FSMC_NAND_REG(regs, bank, PC));
+-		if (ctrl & NAND_NCE)
+-			pc |= FSMC_ENABLE;
+-		else
+-			pc &= ~FSMC_ENABLE;
+-		writel_relaxed(pc, FSMC_NAND_REG(regs, bank, PC));
+-	}
+-
+-	mb();
+-
+-	if (cmd != NAND_CMD_NONE)
+-		writeb_relaxed(cmd, this->IO_ADDR_W);
+-}
+-
+-/*
+- * fsmc_nand_setup - FSMC (Flexible Static Memory Controller) init routine
+- *
+- * This routine initializes timing parameters related to NAND memory access in
+- * FSMC registers
+- */
+-static void fsmc_nand_setup(struct fsmc_nand_data *host,
+-			    struct fsmc_nand_timings *tims)
+-{
+-	uint32_t value = FSMC_DEVTYPE_NAND | FSMC_ENABLE | FSMC_WAITON;
+-	uint32_t tclr, tar, thiz, thold, twait, tset;
+-	unsigned int bank = host->bank;
+-	void __iomem *regs = host->regs_va;
+-
+-	tclr = (tims->tclr & FSMC_TCLR_MASK) << FSMC_TCLR_SHIFT;
+-	tar = (tims->tar & FSMC_TAR_MASK) << FSMC_TAR_SHIFT;
+-	thiz = (tims->thiz & FSMC_THIZ_MASK) << FSMC_THIZ_SHIFT;
+-	thold = (tims->thold & FSMC_THOLD_MASK) << FSMC_THOLD_SHIFT;
+-	twait = (tims->twait & FSMC_TWAIT_MASK) << FSMC_TWAIT_SHIFT;
+-	tset = (tims->tset & FSMC_TSET_MASK) << FSMC_TSET_SHIFT;
+-
+-	if (host->nand.options & NAND_BUSWIDTH_16)
+-		writel_relaxed(value | FSMC_DEVWID_16,
+-				FSMC_NAND_REG(regs, bank, PC));
+-	else
+-		writel_relaxed(value | FSMC_DEVWID_8,
+-				FSMC_NAND_REG(regs, bank, PC));
+-
+-	writel_relaxed(readl(FSMC_NAND_REG(regs, bank, PC)) | tclr | tar,
+-			FSMC_NAND_REG(regs, bank, PC));
+-	writel_relaxed(thiz | thold | twait | tset,
+-			FSMC_NAND_REG(regs, bank, COMM));
+-	writel_relaxed(thiz | thold | twait | tset,
+-			FSMC_NAND_REG(regs, bank, ATTRIB));
+-}
+-
+-static int fsmc_calc_timings(struct fsmc_nand_data *host,
+-			     const struct nand_sdr_timings *sdrt,
+-			     struct fsmc_nand_timings *tims)
+-{
+-	unsigned long hclk = clk_get_rate(host->clk);
+-	unsigned long hclkn = NSEC_PER_SEC / hclk;
+-	uint32_t thiz, thold, twait, tset;
+-
+-	if (sdrt->tRC_min < 30000)
+-		return -EOPNOTSUPP;
+-
+-	tims->tar = DIV_ROUND_UP(sdrt->tAR_min / 1000, hclkn) - 1;
+-	if (tims->tar > FSMC_TAR_MASK)
+-		tims->tar = FSMC_TAR_MASK;
+-	tims->tclr = DIV_ROUND_UP(sdrt->tCLR_min / 1000, hclkn) - 1;
+-	if (tims->tclr > FSMC_TCLR_MASK)
+-		tims->tclr = FSMC_TCLR_MASK;
+-
+-	thiz = sdrt->tCS_min - sdrt->tWP_min;
+-	tims->thiz = DIV_ROUND_UP(thiz / 1000, hclkn);
+-
+-	thold = sdrt->tDH_min;
+-	if (thold < sdrt->tCH_min)
+-		thold = sdrt->tCH_min;
+-	if (thold < sdrt->tCLH_min)
+-		thold = sdrt->tCLH_min;
+-	if (thold < sdrt->tWH_min)
+-		thold = sdrt->tWH_min;
+-	if (thold < sdrt->tALH_min)
+-		thold = sdrt->tALH_min;
+-	if (thold < sdrt->tREH_min)
+-		thold = sdrt->tREH_min;
+-	tims->thold = DIV_ROUND_UP(thold / 1000, hclkn);
+-	if (tims->thold == 0)
+-		tims->thold = 1;
+-	else if (tims->thold > FSMC_THOLD_MASK)
+-		tims->thold = FSMC_THOLD_MASK;
+-
+-	twait = max(sdrt->tRP_min, sdrt->tWP_min);
+-	tims->twait = DIV_ROUND_UP(twait / 1000, hclkn) - 1;
+-	if (tims->twait == 0)
+-		tims->twait = 1;
+-	else if (tims->twait > FSMC_TWAIT_MASK)
+-		tims->twait = FSMC_TWAIT_MASK;
+-
+-	tset = max(sdrt->tCS_min - sdrt->tWP_min,
+-		   sdrt->tCEA_max - sdrt->tREA_max);
+-	tims->tset = DIV_ROUND_UP(tset / 1000, hclkn) - 1;
+-	if (tims->tset == 0)
+-		tims->tset = 1;
+-	else if (tims->tset > FSMC_TSET_MASK)
+-		tims->tset = FSMC_TSET_MASK;
+-
+-	return 0;
+-}
+-
+-static int fsmc_setup_data_interface(struct mtd_info *mtd, int csline,
+-				     const struct nand_data_interface *conf)
+-{
+-	struct nand_chip *nand = mtd_to_nand(mtd);
+-	struct fsmc_nand_data *host = nand_get_controller_data(nand);
+-	struct fsmc_nand_timings tims;
+-	const struct nand_sdr_timings *sdrt;
+-	int ret;
+-
+-	sdrt = nand_get_sdr_timings(conf);
+-	if (IS_ERR(sdrt))
+-		return PTR_ERR(sdrt);
+-
+-	ret = fsmc_calc_timings(host, sdrt, &tims);
+-	if (ret)
+-		return ret;
+-
+-	if (csline == NAND_DATA_IFACE_CHECK_ONLY)
+-		return 0;
+-
+-	fsmc_nand_setup(host, &tims);
+-
+-	return 0;
+-}
+-
+-/*
+- * fsmc_enable_hwecc - Enables Hardware ECC through FSMC registers
+- */
+-static void fsmc_enable_hwecc(struct mtd_info *mtd, int mode)
+-{
+-	struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
+-	void __iomem *regs = host->regs_va;
+-	uint32_t bank = host->bank;
+-
+-	writel_relaxed(readl(FSMC_NAND_REG(regs, bank, PC)) & ~FSMC_ECCPLEN_256,
+-			FSMC_NAND_REG(regs, bank, PC));
+-	writel_relaxed(readl(FSMC_NAND_REG(regs, bank, PC)) & ~FSMC_ECCEN,
+-			FSMC_NAND_REG(regs, bank, PC));
+-	writel_relaxed(readl(FSMC_NAND_REG(regs, bank, PC)) | FSMC_ECCEN,
+-			FSMC_NAND_REG(regs, bank, PC));
+-}
+-
+-/*
+- * fsmc_read_hwecc_ecc4 - Hardware ECC calculator for ecc4 option supported by
+- * FSMC. ECC is 13 bytes for 512 bytes of data (supports error correction up to
+- * max of 8-bits)
+- */
+-static int fsmc_read_hwecc_ecc4(struct mtd_info *mtd, const uint8_t *data,
+-				uint8_t *ecc)
+-{
+-	struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
+-	void __iomem *regs = host->regs_va;
+-	uint32_t bank = host->bank;
+-	uint32_t ecc_tmp;
+-	unsigned long deadline = jiffies + FSMC_BUSY_WAIT_TIMEOUT;
+-
+-	do {
+-		if (readl_relaxed(FSMC_NAND_REG(regs, bank, STS)) & FSMC_CODE_RDY)
+-			break;
+-		else
+-			cond_resched();
+-	} while (!time_after_eq(jiffies, deadline));
+-
+-	if (time_after_eq(jiffies, deadline)) {
+-		dev_err(host->dev, "calculate ecc timed out\n");
+-		return -ETIMEDOUT;
+-	}
+-
+-	ecc_tmp = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC1));
+-	ecc[0] = (uint8_t) (ecc_tmp >> 0);
+-	ecc[1] = (uint8_t) (ecc_tmp >> 8);
+-	ecc[2] = (uint8_t) (ecc_tmp >> 16);
+-	ecc[3] = (uint8_t) (ecc_tmp >> 24);
+-
+-	ecc_tmp = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC2));
+-	ecc[4] = (uint8_t) (ecc_tmp >> 0);
+-	ecc[5] = (uint8_t) (ecc_tmp >> 8);
+-	ecc[6] = (uint8_t) (ecc_tmp >> 16);
+-	ecc[7] = (uint8_t) (ecc_tmp >> 24);
+-
+-	ecc_tmp = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC3));
+-	ecc[8] = (uint8_t) (ecc_tmp >> 0);
+-	ecc[9] = (uint8_t) (ecc_tmp >> 8);
+-	ecc[10] = (uint8_t) (ecc_tmp >> 16);
+-	ecc[11] = (uint8_t) (ecc_tmp >> 24);
+-
+-	ecc_tmp = readl_relaxed(FSMC_NAND_REG(regs, bank, STS));
+-	ecc[12] = (uint8_t) (ecc_tmp >> 16);
+-
+-	return 0;
+-}
+-
+-/*
+- * fsmc_read_hwecc_ecc1 - Hardware ECC calculator for ecc1 option supported by
+- * FSMC. ECC is 3 bytes for 512 bytes of data (supports error correction up to
+- * max of 1-bit)
+- */
+-static int fsmc_read_hwecc_ecc1(struct mtd_info *mtd, const uint8_t *data,
+-				uint8_t *ecc)
+-{
+-	struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
+-	void __iomem *regs = host->regs_va;
+-	uint32_t bank = host->bank;
+-	uint32_t ecc_tmp;
+-
+-	ecc_tmp = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC1));
+-	ecc[0] = (uint8_t) (ecc_tmp >> 0);
+-	ecc[1] = (uint8_t) (ecc_tmp >> 8);
+-	ecc[2] = (uint8_t) (ecc_tmp >> 16);
+-
+-	return 0;
+-}
+-
+-/* Count the number of 0's in buff upto a max of max_bits */
+-static int count_written_bits(uint8_t *buff, int size, int max_bits)
+-{
+-	int k, written_bits = 0;
+-
+-	for (k = 0; k < size; k++) {
+-		written_bits += hweight8(~buff[k]);
+-		if (written_bits > max_bits)
+-			break;
+-	}
+-
+-	return written_bits;
+-}
+-
+-static void dma_complete(void *param)
+-{
+-	struct fsmc_nand_data *host = param;
+-
+-	complete(&host->dma_access_complete);
+-}
+-
+-static int dma_xfer(struct fsmc_nand_data *host, void *buffer, int len,
+-		enum dma_data_direction direction)
+-{
+-	struct dma_chan *chan;
+-	struct dma_device *dma_dev;
+-	struct dma_async_tx_descriptor *tx;
+-	dma_addr_t dma_dst, dma_src, dma_addr;
+-	dma_cookie_t cookie;
+-	unsigned long flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
+-	int ret;
+-	unsigned long time_left;
+-
+-	if (direction == DMA_TO_DEVICE)
+-		chan = host->write_dma_chan;
+-	else if (direction == DMA_FROM_DEVICE)
+-		chan = host->read_dma_chan;
+-	else
+-		return -EINVAL;
+-
+-	dma_dev = chan->device;
+-	dma_addr = dma_map_single(dma_dev->dev, buffer, len, direction);
+-
+-	if (direction == DMA_TO_DEVICE) {
+-		dma_src = dma_addr;
+-		dma_dst = host->data_pa;
+-	} else {
+-		dma_src = host->data_pa;
+-		dma_dst = dma_addr;
+-	}
+-
+-	tx = dma_dev->device_prep_dma_memcpy(chan, dma_dst, dma_src,
+-			len, flags);
+-	if (!tx) {
+-		dev_err(host->dev, "device_prep_dma_memcpy error\n");
+-		ret = -EIO;
+-		goto unmap_dma;
+-	}
+-
+-	tx->callback = dma_complete;
+-	tx->callback_param = host;
+-	cookie = tx->tx_submit(tx);
+-
+-	ret = dma_submit_error(cookie);
+-	if (ret) {
+-		dev_err(host->dev, "dma_submit_error %d\n", cookie);
+-		goto unmap_dma;
+-	}
+-
+-	dma_async_issue_pending(chan);
+-
+-	time_left =
+-	wait_for_completion_timeout(&host->dma_access_complete,
+-				msecs_to_jiffies(3000));
+-	if (time_left == 0) {
+-		dmaengine_terminate_all(chan);
+-		dev_err(host->dev, "wait_for_completion_timeout\n");
+-		ret = -ETIMEDOUT;
+-		goto unmap_dma;
+-	}
+-
+-	ret = 0;
+-
+-unmap_dma:
+-	dma_unmap_single(dma_dev->dev, dma_addr, len, direction);
+-
+-	return ret;
+-}
+-
+-/*
+- * fsmc_write_buf - write buffer to chip
+- * @mtd:	MTD device structure
+- * @buf:	data buffer
+- * @len:	number of bytes to write
+- */
+-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);
+-
+-	if (IS_ALIGNED((uint32_t)buf, sizeof(uint32_t)) &&
+-			IS_ALIGNED(len, sizeof(uint32_t))) {
+-		uint32_t *p = (uint32_t *)buf;
+-		len = len >> 2;
+-		for (i = 0; i < len; i++)
+-			writel_relaxed(p[i], chip->IO_ADDR_W);
+-	} else {
+-		for (i = 0; i < len; i++)
+-			writeb_relaxed(buf[i], chip->IO_ADDR_W);
+-	}
+-}
+-
+-/*
+- * fsmc_read_buf - read chip data into buffer
+- * @mtd:	MTD device structure
+- * @buf:	buffer to store date
+- * @len:	number of bytes to read
+- */
+-static void fsmc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+-{
+-	int i;
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-
+-	if (IS_ALIGNED((uint32_t)buf, sizeof(uint32_t)) &&
+-			IS_ALIGNED(len, sizeof(uint32_t))) {
+-		uint32_t *p = (uint32_t *)buf;
+-		len = len >> 2;
+-		for (i = 0; i < len; i++)
+-			p[i] = readl_relaxed(chip->IO_ADDR_R);
+-	} else {
+-		for (i = 0; i < len; i++)
+-			buf[i] = readb_relaxed(chip->IO_ADDR_R);
+-	}
+-}
+-
+-/*
+- * fsmc_read_buf_dma - read chip data into buffer
+- * @mtd:	MTD device structure
+- * @buf:	buffer to store date
+- * @len:	number of bytes to read
+- */
+-static void fsmc_read_buf_dma(struct mtd_info *mtd, uint8_t *buf, int len)
+-{
+-	struct fsmc_nand_data *host  = mtd_to_fsmc(mtd);
+-
+-	dma_xfer(host, buf, len, DMA_FROM_DEVICE);
+-}
+-
+-/*
+- * fsmc_write_buf_dma - write buffer to chip
+- * @mtd:	MTD device structure
+- * @buf:	data buffer
+- * @len:	number of bytes to write
+- */
+-static void fsmc_write_buf_dma(struct mtd_info *mtd, const uint8_t *buf,
+-		int len)
+-{
+-	struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
+-
+-	dma_xfer(host, (void *)buf, len, DMA_TO_DEVICE);
+-}
+-
+-/*
+- * fsmc_read_page_hwecc
+- * @mtd:	mtd info structure
+- * @chip:	nand chip info structure
+- * @buf:	buffer to store read data
+- * @oob_required:	caller expects OOB data read to chip->oob_poi
+- * @page:	page number to read
+- *
+- * This routine is needed for fsmc version 8 as reading from NAND chip has to be
+- * performed in a strict sequence as follows:
+- * data(512 byte) -> ecc(13 byte)
+- * After this read, fsmc hardware generates and reports error data bits(up to a
+- * max of 8 bits)
+- */
+-static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
+-				 uint8_t *buf, int oob_required, int page)
+-{
+-	int i, j, s, stat, 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;
+-	int off, len, group = 0;
+-	/*
+-	 * ecc_oob is intentionally taken as uint16_t. In 16bit devices, we
+-	 * end up reading 14 bytes (7 words) from oob. The local array is
+-	 * to maintain word alignment
+-	 */
+-	uint16_t ecc_oob[7];
+-	uint8_t *oob = (uint8_t *)&ecc_oob[0];
+-	unsigned int max_bitflips = 0;
+-
+-	for (i = 0, s = 0; s < eccsteps; s++, i += eccbytes, p += eccsize) {
+-		chip->cmdfunc(mtd, NAND_CMD_READ0, s * eccsize, page);
+-		chip->ecc.hwctl(mtd, NAND_ECC_READ);
+-		chip->read_buf(mtd, p, eccsize);
+-
+-		for (j = 0; j < eccbytes;) {
+-			struct mtd_oob_region oobregion;
+-			int ret;
+-
+-			ret = mtd_ooblayout_ecc(mtd, group++, &oobregion);
+-			if (ret)
+-				return ret;
+-
+-			off = oobregion.offset;
+-			len = oobregion.length;
+-
+-			/*
+-			 * length is intentionally kept a higher multiple of 2
+-			 * to read at least 13 bytes even in case of 16 bit NAND
+-			 * devices
+-			 */
+-			if (chip->options & NAND_BUSWIDTH_16)
+-				len = roundup(len, 2);
+-
+-			chip->cmdfunc(mtd, NAND_CMD_READOOB, off, page);
+-			chip->read_buf(mtd, oob + j, len);
+-			j += len;
+-		}
+-
+-		memcpy(&ecc_code[i], oob, chip->ecc.bytes);
+-		chip->ecc.calculate(mtd, p, &ecc_calc[i]);
+-
+-		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;
+-			max_bitflips = max_t(unsigned int, max_bitflips, stat);
+-		}
+-	}
+-
+-	return max_bitflips;
+-}
+-
+-/*
+- * fsmc_bch8_correct_data
+- * @mtd:	mtd info structure
+- * @dat:	buffer of read data
+- * @read_ecc:	ecc read from device spare area
+- * @calc_ecc:	ecc calculated from read data
+- *
+- * calc_ecc is a 104 bit information containing maximum of 8 error
+- * offset informations of 13 bits each in 512 bytes of read data.
+- */
+-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 fsmc_nand_data *host = mtd_to_fsmc(mtd);
+-	void __iomem *regs = host->regs_va;
+-	unsigned int bank = host->bank;
+-	uint32_t err_idx[8];
+-	uint32_t num_err, i;
+-	uint32_t ecc1, ecc2, ecc3, ecc4;
+-
+-	num_err = (readl_relaxed(FSMC_NAND_REG(regs, bank, STS)) >> 10) & 0xF;
+-
+-	/* no bit flipping */
+-	if (likely(num_err == 0))
+-		return 0;
+-
+-	/* too many errors */
+-	if (unlikely(num_err > 8)) {
+-		/*
+-		 * This is a temporary erase check. A newly erased page read
+-		 * would result in an ecc error because the oob data is also
+-		 * erased to FF and the calculated ecc for an FF data is not
+-		 * FF..FF.
+-		 * This is a workaround to skip performing correction in case
+-		 * data is FF..FF
+-		 *
+-		 * Logic:
+-		 * For every page, each bit written as 0 is counted until these
+-		 * number of bits are greater than 8 (the maximum correction
+-		 * capability of FSMC for each 512 + 13 bytes)
+-		 */
+-
+-		int bits_ecc = count_written_bits(read_ecc, chip->ecc.bytes, 8);
+-		int bits_data = count_written_bits(dat, chip->ecc.size, 8);
+-
+-		if ((bits_ecc + bits_data) <= 8) {
+-			if (bits_data)
+-				memset(dat, 0xff, chip->ecc.size);
+-			return bits_data;
+-		}
+-
+-		return -EBADMSG;
+-	}
+-
+-	/*
+-	 * ------------------- calc_ecc[] bit wise -----------|--13 bits--|
+-	 * |---idx[7]--|--.....-----|---idx[2]--||---idx[1]--||---idx[0]--|
+-	 *
+-	 * calc_ecc is a 104 bit information containing maximum of 8 error
+-	 * offset informations of 13 bits each. calc_ecc is copied into a
+-	 * uint64_t array and error offset indexes are populated in err_idx
+-	 * array
+-	 */
+-	ecc1 = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC1));
+-	ecc2 = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC2));
+-	ecc3 = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC3));
+-	ecc4 = readl_relaxed(FSMC_NAND_REG(regs, bank, STS));
+-
+-	err_idx[0] = (ecc1 >> 0) & 0x1FFF;
+-	err_idx[1] = (ecc1 >> 13) & 0x1FFF;
+-	err_idx[2] = (((ecc2 >> 0) & 0x7F) << 6) | ((ecc1 >> 26) & 0x3F);
+-	err_idx[3] = (ecc2 >> 7) & 0x1FFF;
+-	err_idx[4] = (((ecc3 >> 0) & 0x1) << 12) | ((ecc2 >> 20) & 0xFFF);
+-	err_idx[5] = (ecc3 >> 1) & 0x1FFF;
+-	err_idx[6] = (ecc3 >> 14) & 0x1FFF;
+-	err_idx[7] = (((ecc4 >> 16) & 0xFF) << 5) | ((ecc3 >> 27) & 0x1F);
+-
+-	i = 0;
+-	while (num_err--) {
+-		change_bit(0, (unsigned long *)&err_idx[i]);
+-		change_bit(1, (unsigned long *)&err_idx[i]);
+-
+-		if (err_idx[i] < chip->ecc.size * 8) {
+-			change_bit(err_idx[i], (unsigned long *)dat);
+-			i++;
+-		}
+-	}
+-	return i;
+-}
+-
+-static bool filter(struct dma_chan *chan, void *slave)
+-{
+-	chan->private = slave;
+-	return true;
+-}
+-
+-static int fsmc_nand_probe_config_dt(struct platform_device *pdev,
+-				     struct fsmc_nand_data *host,
+-				     struct nand_chip *nand)
+-{
+-	struct device_node *np = pdev->dev.of_node;
+-	u32 val;
+-	int ret;
+-
+-	nand->options = 0;
+-
+-	if (!of_property_read_u32(np, "bank-width", &val)) {
+-		if (val == 2) {
+-			nand->options |= NAND_BUSWIDTH_16;
+-		} else if (val != 1) {
+-			dev_err(&pdev->dev, "invalid bank-width %u\n", val);
+-			return -EINVAL;
+-		}
+-	}
+-
+-	if (of_get_property(np, "nand-skip-bbtscan", NULL))
+-		nand->options |= NAND_SKIP_BBTSCAN;
+-
+-	host->dev_timings = devm_kzalloc(&pdev->dev,
+-				sizeof(*host->dev_timings), GFP_KERNEL);
+-	if (!host->dev_timings)
+-		return -ENOMEM;
+-	ret = of_property_read_u8_array(np, "timings", (u8 *)host->dev_timings,
+-						sizeof(*host->dev_timings));
+-	if (ret)
+-		host->dev_timings = NULL;
+-
+-	/* Set default NAND bank to 0 */
+-	host->bank = 0;
+-	if (!of_property_read_u32(np, "bank", &val)) {
+-		if (val > 3) {
+-			dev_err(&pdev->dev, "invalid bank %u\n", val);
+-			return -EINVAL;
+-		}
+-		host->bank = val;
+-	}
+-	return 0;
+-}
+-
+-/*
+- * fsmc_nand_probe - Probe function
+- * @pdev:       platform device structure
+- */
+-static int __init fsmc_nand_probe(struct platform_device *pdev)
+-{
+-	struct fsmc_nand_data *host;
+-	struct mtd_info *mtd;
+-	struct nand_chip *nand;
+-	struct resource *res;
+-	dma_cap_mask_t mask;
+-	int ret = 0;
+-	u32 pid;
+-	int i;
+-
+-	/* Allocate memory for the device structure (and zero it) */
+-	host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
+-	if (!host)
+-		return -ENOMEM;
+-
+-	nand = &host->nand;
+-
+-	ret = fsmc_nand_probe_config_dt(pdev, host, nand);
+-	if (ret)
+-		return ret;
+-
+-	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_data");
+-	host->data_va = devm_ioremap_resource(&pdev->dev, res);
+-	if (IS_ERR(host->data_va))
+-		return PTR_ERR(host->data_va);
+-
+-	host->data_pa = (dma_addr_t)res->start;
+-
+-	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_addr");
+-	host->addr_va = devm_ioremap_resource(&pdev->dev, res);
+-	if (IS_ERR(host->addr_va))
+-		return PTR_ERR(host->addr_va);
+-
+-	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_cmd");
+-	host->cmd_va = devm_ioremap_resource(&pdev->dev, res);
+-	if (IS_ERR(host->cmd_va))
+-		return PTR_ERR(host->cmd_va);
+-
+-	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fsmc_regs");
+-	host->regs_va = devm_ioremap_resource(&pdev->dev, res);
+-	if (IS_ERR(host->regs_va))
+-		return PTR_ERR(host->regs_va);
+-
+-	host->clk = devm_clk_get(&pdev->dev, NULL);
+-	if (IS_ERR(host->clk)) {
+-		dev_err(&pdev->dev, "failed to fetch block clock\n");
+-		return PTR_ERR(host->clk);
+-	}
+-
+-	ret = clk_prepare_enable(host->clk);
+-	if (ret)
+-		return ret;
+-
+-	/*
+-	 * This device ID is actually a common AMBA ID as used on the
+-	 * AMBA PrimeCell bus. However it is not a PrimeCell.
+-	 */
+-	for (pid = 0, i = 0; i < 4; i++)
+-		pid |= (readl(host->regs_va + resource_size(res) - 0x20 + 4 * i) & 255) << (i * 8);
+-	host->pid = pid;
+-	dev_info(&pdev->dev, "FSMC device partno %03x, manufacturer %02x, "
+-		 "revision %02x, config %02x\n",
+-		 AMBA_PART_BITS(pid), AMBA_MANF_BITS(pid),
+-		 AMBA_REV_BITS(pid), AMBA_CONFIG_BITS(pid));
+-
+-	host->dev = &pdev->dev;
+-
+-	if (host->mode == USE_DMA_ACCESS)
+-		init_completion(&host->dma_access_complete);
+-
+-	/* Link all private pointers */
+-	mtd = nand_to_mtd(&host->nand);
+-	nand_set_controller_data(nand, host);
+-	nand_set_flash_node(nand, pdev->dev.of_node);
+-
+-	mtd->dev.parent = &pdev->dev;
+-	nand->IO_ADDR_R = host->data_va;
+-	nand->IO_ADDR_W = host->data_va;
+-	nand->cmd_ctrl = fsmc_cmd_ctrl;
+-	nand->chip_delay = 30;
+-
+-	/*
+-	 * Setup default ECC mode. nand_dt_init() called from nand_scan_ident()
+-	 * can overwrite this value if the DT provides a different value.
+-	 */
+-	nand->ecc.mode = NAND_ECC_HW;
+-	nand->ecc.hwctl = fsmc_enable_hwecc;
+-	nand->ecc.size = 512;
+-	nand->badblockbits = 7;
+-
+-	switch (host->mode) {
+-	case USE_DMA_ACCESS:
+-		dma_cap_zero(mask);
+-		dma_cap_set(DMA_MEMCPY, mask);
+-		host->read_dma_chan = dma_request_channel(mask, filter, NULL);
+-		if (!host->read_dma_chan) {
+-			dev_err(&pdev->dev, "Unable to get read dma channel\n");
+-			goto err_req_read_chnl;
+-		}
+-		host->write_dma_chan = dma_request_channel(mask, filter, NULL);
+-		if (!host->write_dma_chan) {
+-			dev_err(&pdev->dev, "Unable to get write dma channel\n");
+-			goto err_req_write_chnl;
+-		}
+-		nand->read_buf = fsmc_read_buf_dma;
+-		nand->write_buf = fsmc_write_buf_dma;
+-		break;
+-
+-	default:
+-	case USE_WORD_ACCESS:
+-		nand->read_buf = fsmc_read_buf;
+-		nand->write_buf = fsmc_write_buf;
+-		break;
+-	}
+-
+-	if (host->dev_timings)
+-		fsmc_nand_setup(host, host->dev_timings);
+-	else
+-		nand->setup_data_interface = fsmc_setup_data_interface;
+-
+-	if (AMBA_REV_BITS(host->pid) >= 8) {
+-		nand->ecc.read_page = fsmc_read_page_hwecc;
+-		nand->ecc.calculate = fsmc_read_hwecc_ecc4;
+-		nand->ecc.correct = fsmc_bch8_correct_data;
+-		nand->ecc.bytes = 13;
+-		nand->ecc.strength = 8;
+-	}
+-
+-	/*
+-	 * Scan to find existence of the device
+-	 */
+-	ret = nand_scan_ident(mtd, 1, NULL);
+-	if (ret) {
+-		dev_err(&pdev->dev, "No NAND Device found!\n");
+-		goto err_scan_ident;
+-	}
+-
+-	if (AMBA_REV_BITS(host->pid) >= 8) {
+-		switch (mtd->oobsize) {
+-		case 16:
+-		case 64:
+-		case 128:
+-		case 224:
+-		case 256:
+-			break;
+-		default:
+-			dev_warn(&pdev->dev, "No oob scheme defined for oobsize %d\n",
+-				 mtd->oobsize);
+-			ret = -EINVAL;
+-			goto err_probe;
+-		}
+-
+-		mtd_set_ooblayout(mtd, &fsmc_ecc4_ooblayout_ops);
+-	} else {
+-		switch (nand->ecc.mode) {
+-		case NAND_ECC_HW:
+-			dev_info(&pdev->dev, "Using 1-bit HW ECC scheme\n");
+-			nand->ecc.calculate = fsmc_read_hwecc_ecc1;
+-			nand->ecc.correct = nand_correct_data;
+-			nand->ecc.bytes = 3;
+-			nand->ecc.strength = 1;
+-			break;
+-
+-		case NAND_ECC_SOFT:
+-			if (nand->ecc.algo == NAND_ECC_BCH) {
+-				dev_info(&pdev->dev, "Using 4-bit SW BCH ECC scheme\n");
+-				break;
+-			}
+-
+-		case NAND_ECC_ON_DIE:
+-			break;
+-
+-		default:
+-			dev_err(&pdev->dev, "Unsupported ECC mode!\n");
+-			goto err_probe;
+-		}
+-
+-		/*
+-		 * Don't set layout for BCH4 SW ECC. This will be
+-		 * generated later in nand_bch_init() later.
+-		 */
+-		if (nand->ecc.mode == NAND_ECC_HW) {
+-			switch (mtd->oobsize) {
+-			case 16:
+-			case 64:
+-			case 128:
+-				mtd_set_ooblayout(mtd,
+-						  &fsmc_ecc1_ooblayout_ops);
+-				break;
+-			default:
+-				dev_warn(&pdev->dev,
+-					 "No oob scheme defined for oobsize %d\n",
+-					 mtd->oobsize);
+-				ret = -EINVAL;
+-				goto err_probe;
+-			}
+-		}
+-	}
+-
+-	/* Second stage of scan to fill MTD data-structures */
+-	ret = nand_scan_tail(mtd);
+-	if (ret)
+-		goto err_probe;
+-
+-	mtd->name = "nand";
+-	ret = mtd_device_register(mtd, NULL, 0);
+-	if (ret)
+-		goto err_probe;
+-
+-	platform_set_drvdata(pdev, host);
+-	dev_info(&pdev->dev, "FSMC NAND driver registration successful\n");
+-	return 0;
+-
+-err_probe:
+-err_scan_ident:
+-	if (host->mode == USE_DMA_ACCESS)
+-		dma_release_channel(host->write_dma_chan);
+-err_req_write_chnl:
+-	if (host->mode == USE_DMA_ACCESS)
+-		dma_release_channel(host->read_dma_chan);
+-err_req_read_chnl:
+-	clk_disable_unprepare(host->clk);
+-	return ret;
+-}
+-
+-/*
+- * Clean up routine
+- */
+-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));
+-
+-		if (host->mode == USE_DMA_ACCESS) {
+-			dma_release_channel(host->write_dma_chan);
+-			dma_release_channel(host->read_dma_chan);
+-		}
+-		clk_disable_unprepare(host->clk);
+-	}
+-
+-	return 0;
+-}
+-
+-#ifdef CONFIG_PM_SLEEP
+-static int fsmc_nand_suspend(struct device *dev)
+-{
+-	struct fsmc_nand_data *host = dev_get_drvdata(dev);
+-	if (host)
+-		clk_disable_unprepare(host->clk);
+-	return 0;
+-}
+-
+-static int fsmc_nand_resume(struct device *dev)
+-{
+-	struct fsmc_nand_data *host = dev_get_drvdata(dev);
+-	if (host) {
+-		clk_prepare_enable(host->clk);
+-		if (host->dev_timings)
+-			fsmc_nand_setup(host, host->dev_timings);
+-	}
+-	return 0;
+-}
+-#endif
+-
+-static SIMPLE_DEV_PM_OPS(fsmc_nand_pm_ops, fsmc_nand_suspend, fsmc_nand_resume);
+-
+-static const struct of_device_id fsmc_nand_id_table[] = {
+-	{ .compatible = "st,spear600-fsmc-nand" },
+-	{ .compatible = "stericsson,fsmc-nand" },
+-	{}
+-};
+-MODULE_DEVICE_TABLE(of, fsmc_nand_id_table);
+-
+-static struct platform_driver fsmc_nand_driver = {
+-	.remove = fsmc_nand_remove,
+-	.driver = {
+-		.name = "fsmc-nand",
+-		.of_match_table = fsmc_nand_id_table,
+-		.pm = &fsmc_nand_pm_ops,
+-	},
+-};
+-
+-module_platform_driver_probe(fsmc_nand_driver, fsmc_nand_probe);
+-
+-MODULE_LICENSE("GPL");
+-MODULE_AUTHOR("Vipin Kumar <vipin.kumar@st.com>, Ashish Priyadarshi");
+-MODULE_DESCRIPTION("NAND driver for SPEAr Platforms");
+diff --git a/drivers/mtd/nand/gpio.c b/drivers/mtd/nand/gpio.c
+deleted file mode 100644
+index fd36489..0000000
+--- a/drivers/mtd/nand/gpio.c
++++ /dev/null
+@@ -1,327 +0,0 @@
+-/*
+- * drivers/mtd/nand/gpio.c
+- *
+- * Updated, and converted to generic GPIO based driver by Russell King.
+- *
+- * Written by Ben Dooks <ben@simtec.co.uk>
+- *   Based on 2.4 version by Mark Whittaker
+- *
+- * © 2004 Simtec Electronics
+- *
+- * Device driver for NAND flash that uses a memory mapped interface to
+- * read/write the NAND commands and data, and GPIO pins for control signals
+- * (the DT binding refers to this as "GPIO assisted NAND flash")
+- *
+- * 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/kernel.h>
+-#include <linux/err.h>
+-#include <linux/slab.h>
+-#include <linux/module.h>
+-#include <linux/platform_device.h>
+-#include <linux/gpio.h>
+-#include <linux/io.h>
+-#include <linux/mtd/mtd.h>
+-#include <linux/mtd/rawnand.h>
+-#include <linux/mtd/partitions.h>
+-#include <linux/mtd/nand-gpio.h>
+-#include <linux/of.h>
+-#include <linux/of_address.h>
+-#include <linux/of_gpio.h>
+-
+-struct gpiomtd {
+-	void __iomem		*io_sync;
+-	struct nand_chip	nand_chip;
+-	struct gpio_nand_platdata plat;
+-};
+-
+-static inline struct gpiomtd *gpio_nand_getpriv(struct mtd_info *mtd)
+-{
+-	return container_of(mtd_to_nand(mtd), struct gpiomtd, nand_chip);
+-}
+-
+-
+-#ifdef CONFIG_ARM
+-/* gpio_nand_dosync()
+- *
+- * Make sure the GPIO state changes occur in-order with writes to NAND
+- * memory region.
+- * Needed on PXA due to bus-reordering within the SoC itself (see section on
+- * I/O ordering in PXA manual (section 2.3, p35)
+- */
+-static void gpio_nand_dosync(struct gpiomtd *gpiomtd)
+-{
+-	unsigned long tmp;
+-
+-	if (gpiomtd->io_sync) {
+-		/*
+-		 * Linux memory barriers don't cater for what's required here.
+-		 * What's required is what's here - a read from a separate
+-		 * region with a dependency on that read.
+-		 */
+-		tmp = readl(gpiomtd->io_sync);
+-		asm volatile("mov %1, %0\n" : "=r" (tmp) : "r" (tmp));
+-	}
+-}
+-#else
+-static inline void gpio_nand_dosync(struct gpiomtd *gpiomtd) {}
+-#endif
+-
+-static void gpio_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+-{
+-	struct gpiomtd *gpiomtd = gpio_nand_getpriv(mtd);
+-
+-	gpio_nand_dosync(gpiomtd);
+-
+-	if (ctrl & NAND_CTRL_CHANGE) {
+-		if (gpio_is_valid(gpiomtd->plat.gpio_nce))
+-			gpio_set_value(gpiomtd->plat.gpio_nce,
+-				       !(ctrl & NAND_NCE));
+-		gpio_set_value(gpiomtd->plat.gpio_cle, !!(ctrl & NAND_CLE));
+-		gpio_set_value(gpiomtd->plat.gpio_ale, !!(ctrl & NAND_ALE));
+-		gpio_nand_dosync(gpiomtd);
+-	}
+-	if (cmd == NAND_CMD_NONE)
+-		return;
+-
+-	writeb(cmd, gpiomtd->nand_chip.IO_ADDR_W);
+-	gpio_nand_dosync(gpiomtd);
+-}
+-
+-static int gpio_nand_devready(struct mtd_info *mtd)
+-{
+-	struct gpiomtd *gpiomtd = gpio_nand_getpriv(mtd);
+-
+-	return gpio_get_value(gpiomtd->plat.gpio_rdy);
+-}
+-
+-#ifdef CONFIG_OF
+-static const struct of_device_id gpio_nand_id_table[] = {
+-	{ .compatible = "gpio-control-nand" },
+-	{}
+-};
+-MODULE_DEVICE_TABLE(of, gpio_nand_id_table);
+-
+-static int gpio_nand_get_config_of(const struct device *dev,
+-				   struct gpio_nand_platdata *plat)
+-{
+-	u32 val;
+-
+-	if (!dev->of_node)
+-		return -ENODEV;
+-
+-	if (!of_property_read_u32(dev->of_node, "bank-width", &val)) {
+-		if (val == 2) {
+-			plat->options |= NAND_BUSWIDTH_16;
+-		} else if (val != 1) {
+-			dev_err(dev, "invalid bank-width %u\n", val);
+-			return -EINVAL;
+-		}
+-	}
+-
+-	plat->gpio_rdy = of_get_gpio(dev->of_node, 0);
+-	plat->gpio_nce = of_get_gpio(dev->of_node, 1);
+-	plat->gpio_ale = of_get_gpio(dev->of_node, 2);
+-	plat->gpio_cle = of_get_gpio(dev->of_node, 3);
+-	plat->gpio_nwp = of_get_gpio(dev->of_node, 4);
+-
+-	if (!of_property_read_u32(dev->of_node, "chip-delay", &val))
+-		plat->chip_delay = val;
+-
+-	return 0;
+-}
+-
+-static struct resource *gpio_nand_get_io_sync_of(struct platform_device *pdev)
+-{
+-	struct resource *r;
+-	u64 addr;
+-
+-	if (of_property_read_u64(pdev->dev.of_node,
+-				       "gpio-control-nand,io-sync-reg", &addr))
+-		return NULL;
+-
+-	r = devm_kzalloc(&pdev->dev, sizeof(*r), GFP_KERNEL);
+-	if (!r)
+-		return NULL;
+-
+-	r->start = addr;
+-	r->end = r->start + 0x3;
+-	r->flags = IORESOURCE_MEM;
+-
+-	return r;
+-}
+-#else /* CONFIG_OF */
+-static inline int gpio_nand_get_config_of(const struct device *dev,
+-					  struct gpio_nand_platdata *plat)
+-{
+-	return -ENOSYS;
+-}
+-
+-static inline struct resource *
+-gpio_nand_get_io_sync_of(struct platform_device *pdev)
+-{
+-	return NULL;
+-}
+-#endif /* CONFIG_OF */
+-
+-static inline int gpio_nand_get_config(const struct device *dev,
+-				       struct gpio_nand_platdata *plat)
+-{
+-	int ret = gpio_nand_get_config_of(dev, plat);
+-
+-	if (!ret)
+-		return ret;
+-
+-	if (dev_get_platdata(dev)) {
+-		memcpy(plat, dev_get_platdata(dev), sizeof(*plat));
+-		return 0;
+-	}
+-
+-	return -EINVAL;
+-}
+-
+-static inline struct resource *
+-gpio_nand_get_io_sync(struct platform_device *pdev)
+-{
+-	struct resource *r = gpio_nand_get_io_sync_of(pdev);
+-
+-	if (r)
+-		return r;
+-
+-	return platform_get_resource(pdev, IORESOURCE_MEM, 1);
+-}
+-
+-static int gpio_nand_remove(struct platform_device *pdev)
+-{
+-	struct gpiomtd *gpiomtd = platform_get_drvdata(pdev);
+-
+-	nand_release(nand_to_mtd(&gpiomtd->nand_chip));
+-
+-	if (gpio_is_valid(gpiomtd->plat.gpio_nwp))
+-		gpio_set_value(gpiomtd->plat.gpio_nwp, 0);
+-	if (gpio_is_valid(gpiomtd->plat.gpio_nce))
+-		gpio_set_value(gpiomtd->plat.gpio_nce, 1);
+-
+-	return 0;
+-}
+-
+-static int gpio_nand_probe(struct platform_device *pdev)
+-{
+-	struct gpiomtd *gpiomtd;
+-	struct nand_chip *chip;
+-	struct mtd_info *mtd;
+-	struct resource *res;
+-	int ret = 0;
+-
+-	if (!pdev->dev.of_node && !dev_get_platdata(&pdev->dev))
+-		return -EINVAL;
+-
+-	gpiomtd = devm_kzalloc(&pdev->dev, sizeof(*gpiomtd), GFP_KERNEL);
+-	if (!gpiomtd)
+-		return -ENOMEM;
+-
+-	chip = &gpiomtd->nand_chip;
+-
+-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+-	chip->IO_ADDR_R = devm_ioremap_resource(&pdev->dev, res);
+-	if (IS_ERR(chip->IO_ADDR_R))
+-		return PTR_ERR(chip->IO_ADDR_R);
+-
+-	res = gpio_nand_get_io_sync(pdev);
+-	if (res) {
+-		gpiomtd->io_sync = devm_ioremap_resource(&pdev->dev, res);
+-		if (IS_ERR(gpiomtd->io_sync))
+-			return PTR_ERR(gpiomtd->io_sync);
+-	}
+-
+-	ret = gpio_nand_get_config(&pdev->dev, &gpiomtd->plat);
+-	if (ret)
+-		return ret;
+-
+-	if (gpio_is_valid(gpiomtd->plat.gpio_nce)) {
+-		ret = devm_gpio_request(&pdev->dev, gpiomtd->plat.gpio_nce,
+-					"NAND NCE");
+-		if (ret)
+-			return ret;
+-		gpio_direction_output(gpiomtd->plat.gpio_nce, 1);
+-	}
+-
+-	if (gpio_is_valid(gpiomtd->plat.gpio_nwp)) {
+-		ret = devm_gpio_request(&pdev->dev, gpiomtd->plat.gpio_nwp,
+-					"NAND NWP");
+-		if (ret)
+-			return ret;
+-	}
+-
+-	ret = devm_gpio_request(&pdev->dev, gpiomtd->plat.gpio_ale, "NAND ALE");
+-	if (ret)
+-		return ret;
+-	gpio_direction_output(gpiomtd->plat.gpio_ale, 0);
+-
+-	ret = devm_gpio_request(&pdev->dev, gpiomtd->plat.gpio_cle, "NAND CLE");
+-	if (ret)
+-		return ret;
+-	gpio_direction_output(gpiomtd->plat.gpio_cle, 0);
+-
+-	if (gpio_is_valid(gpiomtd->plat.gpio_rdy)) {
+-		ret = devm_gpio_request(&pdev->dev, gpiomtd->plat.gpio_rdy,
+-					"NAND RDY");
+-		if (ret)
+-			return ret;
+-		gpio_direction_input(gpiomtd->plat.gpio_rdy);
+-		chip->dev_ready = gpio_nand_devready;
+-	}
+-
+-	nand_set_flash_node(chip, pdev->dev.of_node);
+-	chip->IO_ADDR_W		= chip->IO_ADDR_R;
+-	chip->ecc.mode		= NAND_ECC_SOFT;
+-	chip->ecc.algo		= NAND_ECC_HAMMING;
+-	chip->options		= gpiomtd->plat.options;
+-	chip->chip_delay	= gpiomtd->plat.chip_delay;
+-	chip->cmd_ctrl		= gpio_nand_cmd_ctrl;
+-
+-	mtd			= nand_to_mtd(chip);
+-	mtd->dev.parent		= &pdev->dev;
+-
+-	platform_set_drvdata(pdev, gpiomtd);
+-
+-	if (gpio_is_valid(gpiomtd->plat.gpio_nwp))
+-		gpio_direction_output(gpiomtd->plat.gpio_nwp, 1);
+-
+-	ret = nand_scan(mtd, 1);
+-	if (ret)
+-		goto err_wp;
+-
+-	if (gpiomtd->plat.adjust_parts)
+-		gpiomtd->plat.adjust_parts(&gpiomtd->plat, mtd->size);
+-
+-	ret = mtd_device_register(mtd, gpiomtd->plat.parts,
+-				  gpiomtd->plat.num_parts);
+-	if (!ret)
+-		return 0;
+-
+-err_wp:
+-	if (gpio_is_valid(gpiomtd->plat.gpio_nwp))
+-		gpio_set_value(gpiomtd->plat.gpio_nwp, 0);
+-
+-	return ret;
+-}
+-
+-static struct platform_driver gpio_nand_driver = {
+-	.probe		= gpio_nand_probe,
+-	.remove		= gpio_nand_remove,
+-	.driver		= {
+-		.name	= "gpio-nand",
+-		.of_match_table = of_match_ptr(gpio_nand_id_table),
+-	},
+-};
+-
+-module_platform_driver(gpio_nand_driver);
+-
+-MODULE_LICENSE("GPL");
+-MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
+-MODULE_DESCRIPTION("GPIO NAND Driver");
+diff --git a/drivers/mtd/nand/gpmi-nand/Makefile b/drivers/mtd/nand/gpmi-nand/Makefile
+deleted file mode 100644
+index 3a46248..0000000
+--- a/drivers/mtd/nand/gpmi-nand/Makefile
++++ /dev/null
+@@ -1,3 +0,0 @@
+-obj-$(CONFIG_MTD_NAND_GPMI_NAND) += gpmi_nand.o
+-gpmi_nand-objs += gpmi-nand.o
+-gpmi_nand-objs += gpmi-lib.o
+diff --git a/drivers/mtd/nand/gpmi-nand/bch-regs.h b/drivers/mtd/nand/gpmi-nand/bch-regs.h
+deleted file mode 100644
+index 05bb91f..0000000
+--- a/drivers/mtd/nand/gpmi-nand/bch-regs.h
++++ /dev/null
+@@ -1,128 +0,0 @@
+-/*
+- * Freescale GPMI NAND Flash Driver
+- *
+- * Copyright 2008-2011 Freescale Semiconductor, Inc.
+- * Copyright 2008 Embedded Alley Solutions, Inc.
+- *
+- * 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.
+- *
+- * You should have received a copy of the GNU General Public License along
+- * with this program; if not, write to the Free Software Foundation, Inc.,
+- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+- */
+-#ifndef __GPMI_NAND_BCH_REGS_H
+-#define __GPMI_NAND_BCH_REGS_H
+-
+-#define HW_BCH_CTRL				0x00000000
+-#define HW_BCH_CTRL_SET				0x00000004
+-#define HW_BCH_CTRL_CLR				0x00000008
+-#define HW_BCH_CTRL_TOG				0x0000000c
+-
+-#define BM_BCH_CTRL_COMPLETE_IRQ_EN		(1 << 8)
+-#define BM_BCH_CTRL_COMPLETE_IRQ		(1 << 0)
+-
+-#define HW_BCH_STATUS0				0x00000010
+-#define HW_BCH_MODE				0x00000020
+-#define HW_BCH_ENCODEPTR			0x00000030
+-#define HW_BCH_DATAPTR				0x00000040
+-#define HW_BCH_METAPTR				0x00000050
+-#define HW_BCH_LAYOUTSELECT			0x00000070
+-
+-#define HW_BCH_FLASH0LAYOUT0			0x00000080
+-
+-#define BP_BCH_FLASH0LAYOUT0_NBLOCKS		24
+-#define BM_BCH_FLASH0LAYOUT0_NBLOCKS	(0xff << BP_BCH_FLASH0LAYOUT0_NBLOCKS)
+-#define BF_BCH_FLASH0LAYOUT0_NBLOCKS(v)		\
+-	(((v) << BP_BCH_FLASH0LAYOUT0_NBLOCKS) & BM_BCH_FLASH0LAYOUT0_NBLOCKS)
+-
+-#define BP_BCH_FLASH0LAYOUT0_META_SIZE		16
+-#define BM_BCH_FLASH0LAYOUT0_META_SIZE	(0xff << BP_BCH_FLASH0LAYOUT0_META_SIZE)
+-#define BF_BCH_FLASH0LAYOUT0_META_SIZE(v)	\
+-	(((v) << BP_BCH_FLASH0LAYOUT0_META_SIZE)\
+-					 & BM_BCH_FLASH0LAYOUT0_META_SIZE)
+-
+-#define BP_BCH_FLASH0LAYOUT0_ECC0		12
+-#define BM_BCH_FLASH0LAYOUT0_ECC0	(0xf << BP_BCH_FLASH0LAYOUT0_ECC0)
+-#define MX6Q_BP_BCH_FLASH0LAYOUT0_ECC0		11
+-#define MX6Q_BM_BCH_FLASH0LAYOUT0_ECC0	(0x1f << MX6Q_BP_BCH_FLASH0LAYOUT0_ECC0)
+-#define BF_BCH_FLASH0LAYOUT0_ECC0(v, x)				\
+-	(GPMI_IS_MX6(x)					\
+-		? (((v) << MX6Q_BP_BCH_FLASH0LAYOUT0_ECC0)	\
+-			& MX6Q_BM_BCH_FLASH0LAYOUT0_ECC0)	\
+-		: (((v) << BP_BCH_FLASH0LAYOUT0_ECC0)		\
+-			& BM_BCH_FLASH0LAYOUT0_ECC0)		\
+-	)
+-
+-#define MX6Q_BP_BCH_FLASH0LAYOUT0_GF_13_14	10
+-#define MX6Q_BM_BCH_FLASH0LAYOUT0_GF_13_14			\
+-				(0x1 << MX6Q_BP_BCH_FLASH0LAYOUT0_GF_13_14)
+-#define BF_BCH_FLASH0LAYOUT0_GF(v, x)				\
+-	((GPMI_IS_MX6(x) && ((v) == 14))			\
+-		? (((1) << MX6Q_BP_BCH_FLASH0LAYOUT0_GF_13_14)	\
+-			& MX6Q_BM_BCH_FLASH0LAYOUT0_GF_13_14)	\
+-		: 0						\
+-	)
+-
+-#define BP_BCH_FLASH0LAYOUT0_DATA0_SIZE		0
+-#define BM_BCH_FLASH0LAYOUT0_DATA0_SIZE		\
+-			(0xfff << BP_BCH_FLASH0LAYOUT0_DATA0_SIZE)
+-#define MX6Q_BM_BCH_FLASH0LAYOUT0_DATA0_SIZE	\
+-			(0x3ff << BP_BCH_FLASH0LAYOUT0_DATA0_SIZE)
+-#define BF_BCH_FLASH0LAYOUT0_DATA0_SIZE(v, x)				\
+-	(GPMI_IS_MX6(x)						\
+-		? (((v) >> 2) & MX6Q_BM_BCH_FLASH0LAYOUT0_DATA0_SIZE)	\
+-		: ((v) & BM_BCH_FLASH0LAYOUT0_DATA0_SIZE)		\
+-	)
+-
+-#define HW_BCH_FLASH0LAYOUT1			0x00000090
+-
+-#define BP_BCH_FLASH0LAYOUT1_PAGE_SIZE		16
+-#define BM_BCH_FLASH0LAYOUT1_PAGE_SIZE		\
+-			(0xffff << BP_BCH_FLASH0LAYOUT1_PAGE_SIZE)
+-#define BF_BCH_FLASH0LAYOUT1_PAGE_SIZE(v)	\
+-	(((v) << BP_BCH_FLASH0LAYOUT1_PAGE_SIZE) \
+-					 & BM_BCH_FLASH0LAYOUT1_PAGE_SIZE)
+-
+-#define BP_BCH_FLASH0LAYOUT1_ECCN		12
+-#define BM_BCH_FLASH0LAYOUT1_ECCN	(0xf << BP_BCH_FLASH0LAYOUT1_ECCN)
+-#define MX6Q_BP_BCH_FLASH0LAYOUT1_ECCN		11
+-#define MX6Q_BM_BCH_FLASH0LAYOUT1_ECCN	(0x1f << MX6Q_BP_BCH_FLASH0LAYOUT1_ECCN)
+-#define BF_BCH_FLASH0LAYOUT1_ECCN(v, x)				\
+-	(GPMI_IS_MX6(x)					\
+-		? (((v) << MX6Q_BP_BCH_FLASH0LAYOUT1_ECCN)	\
+-			& MX6Q_BM_BCH_FLASH0LAYOUT1_ECCN)	\
+-		: (((v) << BP_BCH_FLASH0LAYOUT1_ECCN)		\
+-			& BM_BCH_FLASH0LAYOUT1_ECCN)		\
+-	)
+-
+-#define MX6Q_BP_BCH_FLASH0LAYOUT1_GF_13_14	10
+-#define MX6Q_BM_BCH_FLASH0LAYOUT1_GF_13_14			\
+-				(0x1 << MX6Q_BP_BCH_FLASH0LAYOUT1_GF_13_14)
+-#define BF_BCH_FLASH0LAYOUT1_GF(v, x)				\
+-	((GPMI_IS_MX6(x) && ((v) == 14))			\
+-		? (((1) << MX6Q_BP_BCH_FLASH0LAYOUT1_GF_13_14)	\
+-			& MX6Q_BM_BCH_FLASH0LAYOUT1_GF_13_14)	\
+-		: 0						\
+-	)
+-
+-#define BP_BCH_FLASH0LAYOUT1_DATAN_SIZE		0
+-#define BM_BCH_FLASH0LAYOUT1_DATAN_SIZE		\
+-			(0xfff << BP_BCH_FLASH0LAYOUT1_DATAN_SIZE)
+-#define MX6Q_BM_BCH_FLASH0LAYOUT1_DATAN_SIZE	\
+-			(0x3ff << BP_BCH_FLASH0LAYOUT1_DATAN_SIZE)
+-#define BF_BCH_FLASH0LAYOUT1_DATAN_SIZE(v, x)				\
+-	(GPMI_IS_MX6(x)						\
+-		? (((v) >> 2) & MX6Q_BM_BCH_FLASH0LAYOUT1_DATAN_SIZE)	\
+-		: ((v) & BM_BCH_FLASH0LAYOUT1_DATAN_SIZE)		\
+-	)
+-
+-#define HW_BCH_VERSION				0x00000160
+-#endif
+diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c
+deleted file mode 100644
+index 9778724..0000000
+--- a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c
++++ /dev/null
+@@ -1,1510 +0,0 @@
+-/*
+- * Freescale GPMI NAND Flash Driver
+- *
+- * Copyright (C) 2008-2011 Freescale Semiconductor, Inc.
+- * Copyright (C) 2008 Embedded Alley Solutions, Inc.
+- *
+- * 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.
+- *
+- * You should have received a copy of the GNU General Public License along
+- * with this program; if not, write to the Free Software Foundation, Inc.,
+- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+- */
+-#include <linux/delay.h>
+-#include <linux/clk.h>
+-#include <linux/slab.h>
+-
+-#include "gpmi-nand.h"
+-#include "gpmi-regs.h"
+-#include "bch-regs.h"
+-
+-static struct timing_threshold timing_default_threshold = {
+-	.max_data_setup_cycles       = (BM_GPMI_TIMING0_DATA_SETUP >>
+-						BP_GPMI_TIMING0_DATA_SETUP),
+-	.internal_data_setup_in_ns   = 0,
+-	.max_sample_delay_factor     = (BM_GPMI_CTRL1_RDN_DELAY >>
+-						BP_GPMI_CTRL1_RDN_DELAY),
+-	.max_dll_clock_period_in_ns  = 32,
+-	.max_dll_delay_in_ns         = 16,
+-};
+-
+-#define MXS_SET_ADDR		0x4
+-#define MXS_CLR_ADDR		0x8
+-/*
+- * Clear the bit and poll it cleared.  This is usually called with
+- * a reset address and mask being either SFTRST(bit 31) or CLKGATE
+- * (bit 30).
+- */
+-static int clear_poll_bit(void __iomem *addr, u32 mask)
+-{
+-	int timeout = 0x400;
+-
+-	/* clear the bit */
+-	writel(mask, addr + MXS_CLR_ADDR);
+-
+-	/*
+-	 * SFTRST needs 3 GPMI clocks to settle, the reference manual
+-	 * recommends to wait 1us.
+-	 */
+-	udelay(1);
+-
+-	/* poll the bit becoming clear */
+-	while ((readl(addr) & mask) && --timeout)
+-		/* nothing */;
+-
+-	return !timeout;
+-}
+-
+-#define MODULE_CLKGATE		(1 << 30)
+-#define MODULE_SFTRST		(1 << 31)
+-/*
+- * The current mxs_reset_block() will do two things:
+- *  [1] enable the module.
+- *  [2] reset the module.
+- *
+- * In most of the cases, it's ok.
+- * But in MX23, there is a hardware bug in the BCH block (see erratum #2847).
+- * If you try to soft reset the BCH block, it becomes unusable until
+- * the next hard reset. This case occurs in the NAND boot mode. When the board
+- * boots by NAND, the ROM of the chip will initialize the BCH blocks itself.
+- * So If the driver tries to reset the BCH again, the BCH will not work anymore.
+- * You will see a DMA timeout in this case. The bug has been fixed
+- * in the following chips, such as MX28.
+- *
+- * To avoid this bug, just add a new parameter `just_enable` for
+- * the mxs_reset_block(), and rewrite it here.
+- */
+-static int gpmi_reset_block(void __iomem *reset_addr, bool just_enable)
+-{
+-	int ret;
+-	int timeout = 0x400;
+-
+-	/* clear and poll SFTRST */
+-	ret = clear_poll_bit(reset_addr, MODULE_SFTRST);
+-	if (unlikely(ret))
+-		goto error;
+-
+-	/* clear CLKGATE */
+-	writel(MODULE_CLKGATE, reset_addr + MXS_CLR_ADDR);
+-
+-	if (!just_enable) {
+-		/* set SFTRST to reset the block */
+-		writel(MODULE_SFTRST, reset_addr + MXS_SET_ADDR);
+-		udelay(1);
+-
+-		/* poll CLKGATE becoming set */
+-		while ((!(readl(reset_addr) & MODULE_CLKGATE)) && --timeout)
+-			/* nothing */;
+-		if (unlikely(!timeout))
+-			goto error;
+-	}
+-
+-	/* clear and poll SFTRST */
+-	ret = clear_poll_bit(reset_addr, MODULE_SFTRST);
+-	if (unlikely(ret))
+-		goto error;
+-
+-	/* clear and poll CLKGATE */
+-	ret = clear_poll_bit(reset_addr, MODULE_CLKGATE);
+-	if (unlikely(ret))
+-		goto error;
+-
+-	return 0;
+-
+-error:
+-	pr_err("%s(%p): module reset timeout\n", __func__, reset_addr);
+-	return -ETIMEDOUT;
+-}
+-
+-static int __gpmi_enable_clk(struct gpmi_nand_data *this, bool v)
+-{
+-	struct clk *clk;
+-	int ret;
+-	int i;
+-
+-	for (i = 0; i < GPMI_CLK_MAX; i++) {
+-		clk = this->resources.clock[i];
+-		if (!clk)
+-			break;
+-
+-		if (v) {
+-			ret = clk_prepare_enable(clk);
+-			if (ret)
+-				goto err_clk;
+-		} else {
+-			clk_disable_unprepare(clk);
+-		}
+-	}
+-	return 0;
+-
+-err_clk:
+-	for (; i > 0; i--)
+-		clk_disable_unprepare(this->resources.clock[i - 1]);
+-	return ret;
+-}
+-
+-#define gpmi_enable_clk(x) __gpmi_enable_clk(x, true)
+-#define gpmi_disable_clk(x) __gpmi_enable_clk(x, false)
+-
+-int gpmi_init(struct gpmi_nand_data *this)
+-{
+-	struct resources *r = &this->resources;
+-	int ret;
+-
+-	ret = gpmi_enable_clk(this);
+-	if (ret)
+-		return ret;
+-	ret = gpmi_reset_block(r->gpmi_regs, false);
+-	if (ret)
+-		goto err_out;
+-
+-	/*
+-	 * Reset BCH here, too. We got failures otherwise :(
+-	 * See later BCH reset for explanation of MX23 handling
+-	 */
+-	ret = gpmi_reset_block(r->bch_regs, GPMI_IS_MX23(this));
+-	if (ret)
+-		goto err_out;
+-
+-
+-	/* Choose NAND mode. */
+-	writel(BM_GPMI_CTRL1_GPMI_MODE, r->gpmi_regs + HW_GPMI_CTRL1_CLR);
+-
+-	/* Set the IRQ polarity. */
+-	writel(BM_GPMI_CTRL1_ATA_IRQRDY_POLARITY,
+-				r->gpmi_regs + HW_GPMI_CTRL1_SET);
+-
+-	/* Disable Write-Protection. */
+-	writel(BM_GPMI_CTRL1_DEV_RESET, r->gpmi_regs + HW_GPMI_CTRL1_SET);
+-
+-	/* Select BCH ECC. */
+-	writel(BM_GPMI_CTRL1_BCH_MODE, r->gpmi_regs + HW_GPMI_CTRL1_SET);
+-
+-	/*
+-	 * Decouple the chip select from dma channel. We use dma0 for all
+-	 * the chips.
+-	 */
+-	writel(BM_GPMI_CTRL1_DECOUPLE_CS, r->gpmi_regs + HW_GPMI_CTRL1_SET);
+-
+-	gpmi_disable_clk(this);
+-	return 0;
+-err_out:
+-	gpmi_disable_clk(this);
+-	return ret;
+-}
+-
+-/* This function is very useful. It is called only when the bug occur. */
+-void gpmi_dump_info(struct gpmi_nand_data *this)
+-{
+-	struct resources *r = &this->resources;
+-	struct bch_geometry *geo = &this->bch_geometry;
+-	u32 reg;
+-	int i;
+-
+-	dev_err(this->dev, "Show GPMI registers :\n");
+-	for (i = 0; i <= HW_GPMI_DEBUG / 0x10 + 1; i++) {
+-		reg = readl(r->gpmi_regs + i * 0x10);
+-		dev_err(this->dev, "offset 0x%.3x : 0x%.8x\n", i * 0x10, reg);
+-	}
+-
+-	/* start to print out the BCH info */
+-	dev_err(this->dev, "Show BCH registers :\n");
+-	for (i = 0; i <= HW_BCH_VERSION / 0x10 + 1; i++) {
+-		reg = readl(r->bch_regs + i * 0x10);
+-		dev_err(this->dev, "offset 0x%.3x : 0x%.8x\n", i * 0x10, reg);
+-	}
+-	dev_err(this->dev, "BCH Geometry :\n"
+-		"GF length              : %u\n"
+-		"ECC Strength           : %u\n"
+-		"Page Size in Bytes     : %u\n"
+-		"Metadata Size in Bytes : %u\n"
+-		"ECC Chunk Size in Bytes: %u\n"
+-		"ECC Chunk Count        : %u\n"
+-		"Payload Size in Bytes  : %u\n"
+-		"Auxiliary Size in Bytes: %u\n"
+-		"Auxiliary Status Offset: %u\n"
+-		"Block Mark Byte Offset : %u\n"
+-		"Block Mark Bit Offset  : %u\n",
+-		geo->gf_len,
+-		geo->ecc_strength,
+-		geo->page_size,
+-		geo->metadata_size,
+-		geo->ecc_chunk_size,
+-		geo->ecc_chunk_count,
+-		geo->payload_size,
+-		geo->auxiliary_size,
+-		geo->auxiliary_status_offset,
+-		geo->block_mark_byte_offset,
+-		geo->block_mark_bit_offset);
+-}
+-
+-/* Configures the geometry for BCH.  */
+-int bch_set_geometry(struct gpmi_nand_data *this)
+-{
+-	struct resources *r = &this->resources;
+-	struct bch_geometry *bch_geo = &this->bch_geometry;
+-	unsigned int block_count;
+-	unsigned int block_size;
+-	unsigned int metadata_size;
+-	unsigned int ecc_strength;
+-	unsigned int page_size;
+-	unsigned int gf_len;
+-	int ret;
+-
+-	if (common_nfc_set_geometry(this))
+-		return !0;
+-
+-	block_count   = bch_geo->ecc_chunk_count - 1;
+-	block_size    = bch_geo->ecc_chunk_size;
+-	metadata_size = bch_geo->metadata_size;
+-	ecc_strength  = bch_geo->ecc_strength >> 1;
+-	page_size     = bch_geo->page_size;
+-	gf_len        = bch_geo->gf_len;
+-
+-	ret = gpmi_enable_clk(this);
+-	if (ret)
+-		return ret;
+-
+-	/*
+-	* Due to erratum #2847 of the MX23, the BCH cannot be soft reset on this
+-	* chip, otherwise it will lock up. So we skip resetting BCH on the MX23.
+-	* On the other hand, the MX28 needs the reset, because one case has been
+-	* seen where the BCH produced ECC errors constantly after 10000
+-	* consecutive reboots. The latter case has not been seen on the MX23
+-	* yet, still we don't know if it could happen there as well.
+-	*/
+-	ret = gpmi_reset_block(r->bch_regs, GPMI_IS_MX23(this));
+-	if (ret)
+-		goto err_out;
+-
+-	/* Configure layout 0. */
+-	writel(BF_BCH_FLASH0LAYOUT0_NBLOCKS(block_count)
+-			| BF_BCH_FLASH0LAYOUT0_META_SIZE(metadata_size)
+-			| BF_BCH_FLASH0LAYOUT0_ECC0(ecc_strength, this)
+-			| BF_BCH_FLASH0LAYOUT0_GF(gf_len, this)
+-			| BF_BCH_FLASH0LAYOUT0_DATA0_SIZE(block_size, this),
+-			r->bch_regs + HW_BCH_FLASH0LAYOUT0);
+-
+-	writel(BF_BCH_FLASH0LAYOUT1_PAGE_SIZE(page_size)
+-			| BF_BCH_FLASH0LAYOUT1_ECCN(ecc_strength, this)
+-			| BF_BCH_FLASH0LAYOUT1_GF(gf_len, this)
+-			| BF_BCH_FLASH0LAYOUT1_DATAN_SIZE(block_size, this),
+-			r->bch_regs + HW_BCH_FLASH0LAYOUT1);
+-
+-	/* Set *all* chip selects to use layout 0. */
+-	writel(0, r->bch_regs + HW_BCH_LAYOUTSELECT);
+-
+-	/* Enable interrupts. */
+-	writel(BM_BCH_CTRL_COMPLETE_IRQ_EN,
+-				r->bch_regs + HW_BCH_CTRL_SET);
+-
+-	gpmi_disable_clk(this);
+-	return 0;
+-err_out:
+-	gpmi_disable_clk(this);
+-	return ret;
+-}
+-
+-/* Converts time in nanoseconds to cycles. */
+-static unsigned int ns_to_cycles(unsigned int time,
+-			unsigned int period, unsigned int min)
+-{
+-	unsigned int k;
+-
+-	k = (time + period - 1) / period;
+-	return max(k, min);
+-}
+-
+-#define DEF_MIN_PROP_DELAY	5
+-#define DEF_MAX_PROP_DELAY	9
+-/* Apply timing to current hardware conditions. */
+-static int gpmi_nfc_compute_hardware_timing(struct gpmi_nand_data *this,
+-					struct gpmi_nfc_hardware_timing *hw)
+-{
+-	struct timing_threshold *nfc = &timing_default_threshold;
+-	struct resources *r = &this->resources;
+-	struct nand_chip *nand = &this->nand;
+-	struct nand_timing target = this->timing;
+-	bool improved_timing_is_available;
+-	unsigned long clock_frequency_in_hz;
+-	unsigned int clock_period_in_ns;
+-	bool dll_use_half_periods;
+-	unsigned int dll_delay_shift;
+-	unsigned int max_sample_delay_in_ns;
+-	unsigned int address_setup_in_cycles;
+-	unsigned int data_setup_in_ns;
+-	unsigned int data_setup_in_cycles;
+-	unsigned int data_hold_in_cycles;
+-	int ideal_sample_delay_in_ns;
+-	unsigned int sample_delay_factor;
+-	int tEYE;
+-	unsigned int min_prop_delay_in_ns = DEF_MIN_PROP_DELAY;
+-	unsigned int max_prop_delay_in_ns = DEF_MAX_PROP_DELAY;
+-
+-	/*
+-	 * If there are multiple chips, we need to relax the timings to allow
+-	 * for signal distortion due to higher capacitance.
+-	 */
+-	if (nand->numchips > 2) {
+-		target.data_setup_in_ns    += 10;
+-		target.data_hold_in_ns     += 10;
+-		target.address_setup_in_ns += 10;
+-	} else if (nand->numchips > 1) {
+-		target.data_setup_in_ns    += 5;
+-		target.data_hold_in_ns     += 5;
+-		target.address_setup_in_ns += 5;
+-	}
+-
+-	/* Check if improved timing information is available. */
+-	improved_timing_is_available =
+-		(target.tREA_in_ns  >= 0) &&
+-		(target.tRLOH_in_ns >= 0) &&
+-		(target.tRHOH_in_ns >= 0);
+-
+-	/* Inspect the clock. */
+-	nfc->clock_frequency_in_hz = clk_get_rate(r->clock[0]);
+-	clock_frequency_in_hz = nfc->clock_frequency_in_hz;
+-	clock_period_in_ns    = NSEC_PER_SEC / clock_frequency_in_hz;
+-
+-	/*
+-	 * The NFC quantizes setup and hold parameters in terms of clock cycles.
+-	 * Here, we quantize the setup and hold timing parameters to the
+-	 * next-highest clock period to make sure we apply at least the
+-	 * specified times.
+-	 *
+-	 * For data setup and data hold, the hardware interprets a value of zero
+-	 * as the largest possible delay. This is not what's intended by a zero
+-	 * in the input parameter, so we impose a minimum of one cycle.
+-	 */
+-	data_setup_in_cycles    = ns_to_cycles(target.data_setup_in_ns,
+-							clock_period_in_ns, 1);
+-	data_hold_in_cycles     = ns_to_cycles(target.data_hold_in_ns,
+-							clock_period_in_ns, 1);
+-	address_setup_in_cycles = ns_to_cycles(target.address_setup_in_ns,
+-							clock_period_in_ns, 0);
+-
+-	/*
+-	 * The clock's period affects the sample delay in a number of ways:
+-	 *
+-	 * (1) The NFC HAL tells us the maximum clock period the sample delay
+-	 *     DLL can tolerate. If the clock period is greater than half that
+-	 *     maximum, we must configure the DLL to be driven by half periods.
+-	 *
+-	 * (2) We need to convert from an ideal sample delay, in ns, to a
+-	 *     "sample delay factor," which the NFC uses. This factor depends on
+-	 *     whether we're driving the DLL with full or half periods.
+-	 *     Paraphrasing the reference manual:
+-	 *
+-	 *         AD = SDF x 0.125 x RP
+-	 *
+-	 * where:
+-	 *
+-	 *     AD   is the applied delay, in ns.
+-	 *     SDF  is the sample delay factor, which is dimensionless.
+-	 *     RP   is the reference period, in ns, which is a full clock period
+-	 *          if the DLL is being driven by full periods, or half that if
+-	 *          the DLL is being driven by half periods.
+-	 *
+-	 * Let's re-arrange this in a way that's more useful to us:
+-	 *
+-	 *                        8
+-	 *         SDF  =  AD x ----
+-	 *                       RP
+-	 *
+-	 * The reference period is either the clock period or half that, so this
+-	 * is:
+-	 *
+-	 *                        8       AD x DDF
+-	 *         SDF  =  AD x -----  =  --------
+-	 *                      f x P        P
+-	 *
+-	 * where:
+-	 *
+-	 *       f  is 1 or 1/2, depending on how we're driving the DLL.
+-	 *       P  is the clock period.
+-	 *     DDF  is the DLL Delay Factor, a dimensionless value that
+-	 *          incorporates all the constants in the conversion.
+-	 *
+-	 * DDF will be either 8 or 16, both of which are powers of two. We can
+-	 * reduce the cost of this conversion by using bit shifts instead of
+-	 * multiplication or division. Thus:
+-	 *
+-	 *                 AD << DDS
+-	 *         SDF  =  ---------
+-	 *                     P
+-	 *
+-	 *     or
+-	 *
+-	 *         AD  =  (SDF >> DDS) x P
+-	 *
+-	 * where:
+-	 *
+-	 *     DDS  is the DLL Delay Shift, the logarithm to base 2 of the DDF.
+-	 */
+-	if (clock_period_in_ns > (nfc->max_dll_clock_period_in_ns >> 1)) {
+-		dll_use_half_periods = true;
+-		dll_delay_shift      = 3 + 1;
+-	} else {
+-		dll_use_half_periods = false;
+-		dll_delay_shift      = 3;
+-	}
+-
+-	/*
+-	 * Compute the maximum sample delay the NFC allows, under current
+-	 * conditions. If the clock is running too slowly, no sample delay is
+-	 * possible.
+-	 */
+-	if (clock_period_in_ns > nfc->max_dll_clock_period_in_ns)
+-		max_sample_delay_in_ns = 0;
+-	else {
+-		/*
+-		 * Compute the delay implied by the largest sample delay factor
+-		 * the NFC allows.
+-		 */
+-		max_sample_delay_in_ns =
+-			(nfc->max_sample_delay_factor * clock_period_in_ns) >>
+-								dll_delay_shift;
+-
+-		/*
+-		 * Check if the implied sample delay larger than the NFC
+-		 * actually allows.
+-		 */
+-		if (max_sample_delay_in_ns > nfc->max_dll_delay_in_ns)
+-			max_sample_delay_in_ns = nfc->max_dll_delay_in_ns;
+-	}
+-
+-	/*
+-	 * Check if improved timing information is available. If not, we have to
+-	 * use a less-sophisticated algorithm.
+-	 */
+-	if (!improved_timing_is_available) {
+-		/*
+-		 * Fold the read setup time required by the NFC into the ideal
+-		 * sample delay.
+-		 */
+-		ideal_sample_delay_in_ns = target.gpmi_sample_delay_in_ns +
+-						nfc->internal_data_setup_in_ns;
+-
+-		/*
+-		 * The ideal sample delay may be greater than the maximum
+-		 * allowed by the NFC. If so, we can trade off sample delay time
+-		 * for more data setup time.
+-		 *
+-		 * In each iteration of the following loop, we add a cycle to
+-		 * the data setup time and subtract a corresponding amount from
+-		 * the sample delay until we've satisified the constraints or
+-		 * can't do any better.
+-		 */
+-		while ((ideal_sample_delay_in_ns > max_sample_delay_in_ns) &&
+-			(data_setup_in_cycles < nfc->max_data_setup_cycles)) {
+-
+-			data_setup_in_cycles++;
+-			ideal_sample_delay_in_ns -= clock_period_in_ns;
+-
+-			if (ideal_sample_delay_in_ns < 0)
+-				ideal_sample_delay_in_ns = 0;
+-
+-		}
+-
+-		/*
+-		 * Compute the sample delay factor that corresponds most closely
+-		 * to the ideal sample delay. If the result is too large for the
+-		 * NFC, use the maximum value.
+-		 *
+-		 * Notice that we use the ns_to_cycles function to compute the
+-		 * sample delay factor. We do this because the form of the
+-		 * computation is the same as that for calculating cycles.
+-		 */
+-		sample_delay_factor =
+-			ns_to_cycles(
+-				ideal_sample_delay_in_ns << dll_delay_shift,
+-							clock_period_in_ns, 0);
+-
+-		if (sample_delay_factor > nfc->max_sample_delay_factor)
+-			sample_delay_factor = nfc->max_sample_delay_factor;
+-
+-		/* Skip to the part where we return our results. */
+-		goto return_results;
+-	}
+-
+-	/*
+-	 * If control arrives here, we have more detailed timing information,
+-	 * so we can use a better algorithm.
+-	 */
+-
+-	/*
+-	 * Fold the read setup time required by the NFC into the maximum
+-	 * propagation delay.
+-	 */
+-	max_prop_delay_in_ns += nfc->internal_data_setup_in_ns;
+-
+-	/*
+-	 * Earlier, we computed the number of clock cycles required to satisfy
+-	 * the data setup time. Now, we need to know the actual nanoseconds.
+-	 */
+-	data_setup_in_ns = clock_period_in_ns * data_setup_in_cycles;
+-
+-	/*
+-	 * Compute tEYE, the width of the data eye when reading from the NAND
+-	 * Flash. The eye width is fundamentally determined by the data setup
+-	 * time, perturbed by propagation delays and some characteristics of the
+-	 * NAND Flash device.
+-	 *
+-	 * start of the eye = max_prop_delay + tREA
+-	 * end of the eye   = min_prop_delay + tRHOH + data_setup
+-	 */
+-	tEYE = (int)min_prop_delay_in_ns + (int)target.tRHOH_in_ns +
+-							(int)data_setup_in_ns;
+-
+-	tEYE -= (int)max_prop_delay_in_ns + (int)target.tREA_in_ns;
+-
+-	/*
+-	 * The eye must be open. If it's not, we can try to open it by
+-	 * increasing its main forcer, the data setup time.
+-	 *
+-	 * In each iteration of the following loop, we increase the data setup
+-	 * time by a single clock cycle. We do this until either the eye is
+-	 * open or we run into NFC limits.
+-	 */
+-	while ((tEYE <= 0) &&
+-			(data_setup_in_cycles < nfc->max_data_setup_cycles)) {
+-		/* Give a cycle to data setup. */
+-		data_setup_in_cycles++;
+-		/* Synchronize the data setup time with the cycles. */
+-		data_setup_in_ns += clock_period_in_ns;
+-		/* Adjust tEYE accordingly. */
+-		tEYE += clock_period_in_ns;
+-	}
+-
+-	/*
+-	 * When control arrives here, the eye is open. The ideal time to sample
+-	 * the data is in the center of the eye:
+-	 *
+-	 *     end of the eye + start of the eye
+-	 *     ---------------------------------  -  data_setup
+-	 *                    2
+-	 *
+-	 * After some algebra, this simplifies to the code immediately below.
+-	 */
+-	ideal_sample_delay_in_ns =
+-		((int)max_prop_delay_in_ns +
+-			(int)target.tREA_in_ns +
+-				(int)min_prop_delay_in_ns +
+-					(int)target.tRHOH_in_ns -
+-						(int)data_setup_in_ns) >> 1;
+-
+-	/*
+-	 * The following figure illustrates some aspects of a NAND Flash read:
+-	 *
+-	 *
+-	 *           __                   _____________________________________
+-	 * RDN         \_________________/
+-	 *
+-	 *                                         <---- tEYE ----->
+-	 *                                        /-----------------\
+-	 * Read Data ----------------------------<                   >---------
+-	 *                                        \-----------------/
+-	 *             ^                 ^                 ^              ^
+-	 *             |                 |                 |              |
+-	 *             |<--Data Setup -->|<--Delay Time -->|              |
+-	 *             |                 |                 |              |
+-	 *             |                 |                                |
+-	 *             |                 |<--   Quantized Delay Time   -->|
+-	 *             |                 |                                |
+-	 *
+-	 *
+-	 * We have some issues we must now address:
+-	 *
+-	 * (1) The *ideal* sample delay time must not be negative. If it is, we
+-	 *     jam it to zero.
+-	 *
+-	 * (2) The *ideal* sample delay time must not be greater than that
+-	 *     allowed by the NFC. If it is, we can increase the data setup
+-	 *     time, which will reduce the delay between the end of the data
+-	 *     setup and the center of the eye. It will also make the eye
+-	 *     larger, which might help with the next issue...
+-	 *
+-	 * (3) The *quantized* sample delay time must not fall either before the
+-	 *     eye opens or after it closes (the latter is the problem
+-	 *     illustrated in the above figure).
+-	 */
+-
+-	/* Jam a negative ideal sample delay to zero. */
+-	if (ideal_sample_delay_in_ns < 0)
+-		ideal_sample_delay_in_ns = 0;
+-
+-	/*
+-	 * Extend the data setup as needed to reduce the ideal sample delay
+-	 * below the maximum permitted by the NFC.
+-	 */
+-	while ((ideal_sample_delay_in_ns > max_sample_delay_in_ns) &&
+-			(data_setup_in_cycles < nfc->max_data_setup_cycles)) {
+-
+-		/* Give a cycle to data setup. */
+-		data_setup_in_cycles++;
+-		/* Synchronize the data setup time with the cycles. */
+-		data_setup_in_ns += clock_period_in_ns;
+-		/* Adjust tEYE accordingly. */
+-		tEYE += clock_period_in_ns;
+-
+-		/*
+-		 * Decrease the ideal sample delay by one half cycle, to keep it
+-		 * in the middle of the eye.
+-		 */
+-		ideal_sample_delay_in_ns -= (clock_period_in_ns >> 1);
+-
+-		/* Jam a negative ideal sample delay to zero. */
+-		if (ideal_sample_delay_in_ns < 0)
+-			ideal_sample_delay_in_ns = 0;
+-	}
+-
+-	/*
+-	 * Compute the sample delay factor that corresponds to the ideal sample
+-	 * delay. If the result is too large, then use the maximum allowed
+-	 * value.
+-	 *
+-	 * Notice that we use the ns_to_cycles function to compute the sample
+-	 * delay factor. We do this because the form of the computation is the
+-	 * same as that for calculating cycles.
+-	 */
+-	sample_delay_factor =
+-		ns_to_cycles(ideal_sample_delay_in_ns << dll_delay_shift,
+-							clock_period_in_ns, 0);
+-
+-	if (sample_delay_factor > nfc->max_sample_delay_factor)
+-		sample_delay_factor = nfc->max_sample_delay_factor;
+-
+-	/*
+-	 * These macros conveniently encapsulate a computation we'll use to
+-	 * continuously evaluate whether or not the data sample delay is inside
+-	 * the eye.
+-	 */
+-	#define IDEAL_DELAY  ((int) ideal_sample_delay_in_ns)
+-
+-	#define QUANTIZED_DELAY  \
+-		((int) ((sample_delay_factor * clock_period_in_ns) >> \
+-							dll_delay_shift))
+-
+-	#define DELAY_ERROR  (abs(QUANTIZED_DELAY - IDEAL_DELAY))
+-
+-	#define SAMPLE_IS_NOT_WITHIN_THE_EYE  (DELAY_ERROR > (tEYE >> 1))
+-
+-	/*
+-	 * While the quantized sample time falls outside the eye, reduce the
+-	 * sample delay or extend the data setup to move the sampling point back
+-	 * toward the eye. Do not allow the number of data setup cycles to
+-	 * exceed the maximum allowed by the NFC.
+-	 */
+-	while (SAMPLE_IS_NOT_WITHIN_THE_EYE &&
+-			(data_setup_in_cycles < nfc->max_data_setup_cycles)) {
+-		/*
+-		 * If control arrives here, the quantized sample delay falls
+-		 * outside the eye. Check if it's before the eye opens, or after
+-		 * the eye closes.
+-		 */
+-		if (QUANTIZED_DELAY > IDEAL_DELAY) {
+-			/*
+-			 * If control arrives here, the quantized sample delay
+-			 * falls after the eye closes. Decrease the quantized
+-			 * delay time and then go back to re-evaluate.
+-			 */
+-			if (sample_delay_factor != 0)
+-				sample_delay_factor--;
+-			continue;
+-		}
+-
+-		/*
+-		 * If control arrives here, the quantized sample delay falls
+-		 * before the eye opens. Shift the sample point by increasing
+-		 * data setup time. This will also make the eye larger.
+-		 */
+-
+-		/* Give a cycle to data setup. */
+-		data_setup_in_cycles++;
+-		/* Synchronize the data setup time with the cycles. */
+-		data_setup_in_ns += clock_period_in_ns;
+-		/* Adjust tEYE accordingly. */
+-		tEYE += clock_period_in_ns;
+-
+-		/*
+-		 * Decrease the ideal sample delay by one half cycle, to keep it
+-		 * in the middle of the eye.
+-		 */
+-		ideal_sample_delay_in_ns -= (clock_period_in_ns >> 1);
+-
+-		/* ...and one less period for the delay time. */
+-		ideal_sample_delay_in_ns -= clock_period_in_ns;
+-
+-		/* Jam a negative ideal sample delay to zero. */
+-		if (ideal_sample_delay_in_ns < 0)
+-			ideal_sample_delay_in_ns = 0;
+-
+-		/*
+-		 * We have a new ideal sample delay, so re-compute the quantized
+-		 * delay.
+-		 */
+-		sample_delay_factor =
+-			ns_to_cycles(
+-				ideal_sample_delay_in_ns << dll_delay_shift,
+-							clock_period_in_ns, 0);
+-
+-		if (sample_delay_factor > nfc->max_sample_delay_factor)
+-			sample_delay_factor = nfc->max_sample_delay_factor;
+-	}
+-
+-	/* Control arrives here when we're ready to return our results. */
+-return_results:
+-	hw->data_setup_in_cycles    = data_setup_in_cycles;
+-	hw->data_hold_in_cycles     = data_hold_in_cycles;
+-	hw->address_setup_in_cycles = address_setup_in_cycles;
+-	hw->use_half_periods        = dll_use_half_periods;
+-	hw->sample_delay_factor     = sample_delay_factor;
+-	hw->device_busy_timeout     = GPMI_DEFAULT_BUSY_TIMEOUT;
+-	hw->wrn_dly_sel             = BV_GPMI_CTRL1_WRN_DLY_SEL_4_TO_8NS;
+-
+-	/* Return success. */
+-	return 0;
+-}
+-
+-/*
+- * <1> Firstly, we should know what's the GPMI-clock means.
+- *     The GPMI-clock is the internal clock in the gpmi nand controller.
+- *     If you set 100MHz to gpmi nand controller, the GPMI-clock's period
+- *     is 10ns. Mark the GPMI-clock's period as GPMI-clock-period.
+- *
+- * <2> Secondly, we should know what's the frequency on the nand chip pins.
+- *     The frequency on the nand chip pins is derived from the GPMI-clock.
+- *     We can get it from the following equation:
+- *
+- *         F = G / (DS + DH)
+- *
+- *         F  : the frequency on the nand chip pins.
+- *         G  : the GPMI clock, such as 100MHz.
+- *         DS : GPMI_HW_GPMI_TIMING0:DATA_SETUP
+- *         DH : GPMI_HW_GPMI_TIMING0:DATA_HOLD
+- *
+- * <3> Thirdly, when the frequency on the nand chip pins is above 33MHz,
+- *     the nand EDO(extended Data Out) timing could be applied.
+- *     The GPMI implements a feedback read strobe to sample the read data.
+- *     The feedback read strobe can be delayed to support the nand EDO timing
+- *     where the read strobe may deasserts before the read data is valid, and
+- *     read data is valid for some time after read strobe.
+- *
+- *     The following figure illustrates some aspects of a NAND Flash read:
+- *
+- *                   |<---tREA---->|
+- *                   |             |
+- *                   |         |   |
+- *                   |<--tRP-->|   |
+- *                   |         |   |
+- *                  __          ___|__________________________________
+- *     RDN            \________/   |
+- *                                 |
+- *                                 /---------\
+- *     Read Data    --------------<           >---------
+- *                                 \---------/
+- *                                |     |
+- *                                |<-D->|
+- *     FeedbackRDN  ________             ____________
+- *                          \___________/
+- *
+- *          D stands for delay, set in the HW_GPMI_CTRL1:RDN_DELAY.
+- *
+- *
+- * <4> Now, we begin to describe how to compute the right RDN_DELAY.
+- *
+- *  4.1) From the aspect of the nand chip pins:
+- *        Delay = (tREA + C - tRP)               {1}
+- *
+- *        tREA : the maximum read access time. From the ONFI nand standards,
+- *               we know that tREA is 16ns in mode 5, tREA is 20ns is mode 4.
+- *               Please check it in : www.onfi.org
+- *        C    : a constant for adjust the delay. default is 4.
+- *        tRP  : the read pulse width.
+- *               Specified by the HW_GPMI_TIMING0:DATA_SETUP:
+- *                    tRP = (GPMI-clock-period) * DATA_SETUP
+- *
+- *  4.2) From the aspect of the GPMI nand controller:
+- *         Delay = RDN_DELAY * 0.125 * RP        {2}
+- *
+- *         RP   : the DLL reference period.
+- *            if (GPMI-clock-period > DLL_THRETHOLD)
+- *                   RP = GPMI-clock-period / 2;
+- *            else
+- *                   RP = GPMI-clock-period;
+- *
+- *            Set the HW_GPMI_CTRL1:HALF_PERIOD if GPMI-clock-period
+- *            is greater DLL_THRETHOLD. In other SOCs, the DLL_THRETHOLD
+- *            is 16ns, but in mx6q, we use 12ns.
+- *
+- *  4.3) since {1} equals {2}, we get:
+- *
+- *                    (tREA + 4 - tRP) * 8
+- *         RDN_DELAY = ---------------------     {3}
+- *                           RP
+- *
+- *  4.4) We only support the fastest asynchronous mode of ONFI nand.
+- *       For some ONFI nand, the mode 4 is the fastest mode;
+- *       while for some ONFI nand, the mode 5 is the fastest mode.
+- *       So we only support the mode 4 and mode 5. It is no need to
+- *       support other modes.
+- */
+-static void gpmi_compute_edo_timing(struct gpmi_nand_data *this,
+-			struct gpmi_nfc_hardware_timing *hw)
+-{
+-	struct resources *r = &this->resources;
+-	unsigned long rate = clk_get_rate(r->clock[0]);
+-	int mode = this->timing_mode;
+-	int dll_threshold = this->devdata->max_chain_delay;
+-	unsigned long delay;
+-	unsigned long clk_period;
+-	int t_rea;
+-	int c = 4;
+-	int t_rp;
+-	int rp;
+-
+-	/*
+-	 * [1] for GPMI_HW_GPMI_TIMING0:
+-	 *     The async mode requires 40MHz for mode 4, 50MHz for mode 5.
+-	 *     The GPMI can support 100MHz at most. So if we want to
+-	 *     get the 40MHz or 50MHz, we have to set DS=1, DH=1.
+-	 *     Set the ADDRESS_SETUP to 0 in mode 4.
+-	 */
+-	hw->data_setup_in_cycles = 1;
+-	hw->data_hold_in_cycles = 1;
+-	hw->address_setup_in_cycles = ((mode == 5) ? 1 : 0);
+-
+-	/* [2] for GPMI_HW_GPMI_TIMING1 */
+-	hw->device_busy_timeout = 0x9000;
+-
+-	/* [3] for GPMI_HW_GPMI_CTRL1 */
+-	hw->wrn_dly_sel = BV_GPMI_CTRL1_WRN_DLY_SEL_NO_DELAY;
+-
+-	/*
+-	 * Enlarge 10 times for the numerator and denominator in {3}.
+-	 * This make us to get more accurate result.
+-	 */
+-	clk_period = NSEC_PER_SEC / (rate / 10);
+-	dll_threshold *= 10;
+-	t_rea = ((mode == 5) ? 16 : 20) * 10;
+-	c *= 10;
+-
+-	t_rp = clk_period * 1; /* DATA_SETUP is 1 */
+-
+-	if (clk_period > dll_threshold) {
+-		hw->use_half_periods = 1;
+-		rp = clk_period / 2;
+-	} else {
+-		hw->use_half_periods = 0;
+-		rp = clk_period;
+-	}
+-
+-	/*
+-	 * Multiply the numerator with 10, we could do a round off:
+-	 *      7.8 round up to 8; 7.4 round down to 7.
+-	 */
+-	delay  = (((t_rea + c - t_rp) * 8) * 10) / rp;
+-	delay = (delay + 5) / 10;
+-
+-	hw->sample_delay_factor = delay;
+-}
+-
+-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);
+-	uint8_t *feature;
+-	unsigned long rate;
+-	int ret;
+-
+-	feature = kzalloc(ONFI_SUBFEATURE_PARAM_LEN, GFP_KERNEL);
+-	if (!feature)
+-		return -ENOMEM;
+-
+-	nand->select_chip(mtd, 0);
+-
+-	/* [1] send SET FEATURE command to NAND */
+-	feature[0] = mode;
+-	ret = nand->onfi_set_features(mtd, nand,
+-				ONFI_FEATURE_ADDR_TIMING_MODE, feature);
+-	if (ret)
+-		goto err_out;
+-
+-	/* [2] send GET FEATURE command to double-check the timing mode */
+-	memset(feature, 0, ONFI_SUBFEATURE_PARAM_LEN);
+-	ret = nand->onfi_get_features(mtd, nand,
+-				ONFI_FEATURE_ADDR_TIMING_MODE, feature);
+-	if (ret || feature[0] != mode)
+-		goto err_out;
+-
+-	nand->select_chip(mtd, -1);
+-
+-	/* [3] set the main IO clock, 100MHz for mode 5, 80MHz for mode 4. */
+-	rate = (mode == 5) ? 100000000 : 80000000;
+-	clk_set_rate(r->clock[0], rate);
+-
+-	/* Let the gpmi_begin() re-compute the timing again. */
+-	this->flags &= ~GPMI_TIMING_INIT_OK;
+-
+-	this->flags |= GPMI_ASYNC_EDO_ENABLED;
+-	this->timing_mode = mode;
+-	kfree(feature);
+-	dev_info(this->dev, "enable the asynchronous EDO mode %d\n", mode);
+-	return 0;
+-
+-err_out:
+-	nand->select_chip(mtd, -1);
+-	kfree(feature);
+-	dev_err(this->dev, "mode:%d ,failed in set feature.\n", mode);
+-	return -EINVAL;
+-}
+-
+-int gpmi_extra_init(struct gpmi_nand_data *this)
+-{
+-	struct nand_chip *chip = &this->nand;
+-
+-	/* Enable the asynchronous EDO feature. */
+-	if (GPMI_IS_MX6(this) && chip->onfi_version) {
+-		int mode = onfi_get_async_timing_mode(chip);
+-
+-		/* We only support the timing mode 4 and mode 5. */
+-		if (mode & ONFI_TIMING_MODE_5)
+-			mode = 5;
+-		else if (mode & ONFI_TIMING_MODE_4)
+-			mode = 4;
+-		else
+-			return 0;
+-
+-		return enable_edo_mode(this, mode);
+-	}
+-	return 0;
+-}
+-
+-/* Begin the I/O */
+-void gpmi_begin(struct gpmi_nand_data *this)
+-{
+-	struct resources *r = &this->resources;
+-	void __iomem *gpmi_regs = r->gpmi_regs;
+-	unsigned int   clock_period_in_ns;
+-	uint32_t       reg;
+-	unsigned int   dll_wait_time_in_us;
+-	struct gpmi_nfc_hardware_timing  hw;
+-	int ret;
+-
+-	/* Enable the clock. */
+-	ret = gpmi_enable_clk(this);
+-	if (ret) {
+-		dev_err(this->dev, "We failed in enable the clk\n");
+-		goto err_out;
+-	}
+-
+-	/* Only initialize the timing once */
+-	if (this->flags & GPMI_TIMING_INIT_OK)
+-		return;
+-	this->flags |= GPMI_TIMING_INIT_OK;
+-
+-	if (this->flags & GPMI_ASYNC_EDO_ENABLED)
+-		gpmi_compute_edo_timing(this, &hw);
+-	else
+-		gpmi_nfc_compute_hardware_timing(this, &hw);
+-
+-	/* [1] Set HW_GPMI_TIMING0 */
+-	reg = BF_GPMI_TIMING0_ADDRESS_SETUP(hw.address_setup_in_cycles) |
+-		BF_GPMI_TIMING0_DATA_HOLD(hw.data_hold_in_cycles)         |
+-		BF_GPMI_TIMING0_DATA_SETUP(hw.data_setup_in_cycles);
+-
+-	writel(reg, gpmi_regs + HW_GPMI_TIMING0);
+-
+-	/* [2] Set HW_GPMI_TIMING1 */
+-	writel(BF_GPMI_TIMING1_BUSY_TIMEOUT(hw.device_busy_timeout),
+-		gpmi_regs + HW_GPMI_TIMING1);
+-
+-	/* [3] The following code is to set the HW_GPMI_CTRL1. */
+-
+-	/* Set the WRN_DLY_SEL */
+-	writel(BM_GPMI_CTRL1_WRN_DLY_SEL, gpmi_regs + HW_GPMI_CTRL1_CLR);
+-	writel(BF_GPMI_CTRL1_WRN_DLY_SEL(hw.wrn_dly_sel),
+-					gpmi_regs + HW_GPMI_CTRL1_SET);
+-
+-	/* DLL_ENABLE must be set to 0 when setting RDN_DELAY or HALF_PERIOD. */
+-	writel(BM_GPMI_CTRL1_DLL_ENABLE, gpmi_regs + HW_GPMI_CTRL1_CLR);
+-
+-	/* Clear out the DLL control fields. */
+-	reg = BM_GPMI_CTRL1_RDN_DELAY | BM_GPMI_CTRL1_HALF_PERIOD;
+-	writel(reg, gpmi_regs + HW_GPMI_CTRL1_CLR);
+-
+-	/* If no sample delay is called for, return immediately. */
+-	if (!hw.sample_delay_factor)
+-		return;
+-
+-	/* Set RDN_DELAY or HALF_PERIOD. */
+-	reg = ((hw.use_half_periods) ? BM_GPMI_CTRL1_HALF_PERIOD : 0)
+-		| BF_GPMI_CTRL1_RDN_DELAY(hw.sample_delay_factor);
+-
+-	writel(reg, gpmi_regs + HW_GPMI_CTRL1_SET);
+-
+-	/* At last, we enable the DLL. */
+-	writel(BM_GPMI_CTRL1_DLL_ENABLE, gpmi_regs + HW_GPMI_CTRL1_SET);
+-
+-	/*
+-	 * After we enable the GPMI DLL, we have to wait 64 clock cycles before
+-	 * we can use the GPMI. Calculate the amount of time we need to wait,
+-	 * in microseconds.
+-	 */
+-	clock_period_in_ns = NSEC_PER_SEC / clk_get_rate(r->clock[0]);
+-	dll_wait_time_in_us = (clock_period_in_ns * 64) / 1000;
+-
+-	if (!dll_wait_time_in_us)
+-		dll_wait_time_in_us = 1;
+-
+-	/* Wait for the DLL to settle. */
+-	udelay(dll_wait_time_in_us);
+-
+-err_out:
+-	return;
+-}
+-
+-void gpmi_end(struct gpmi_nand_data *this)
+-{
+-	gpmi_disable_clk(this);
+-}
+-
+-/* Clears a BCH interrupt. */
+-void gpmi_clear_bch(struct gpmi_nand_data *this)
+-{
+-	struct resources *r = &this->resources;
+-	writel(BM_BCH_CTRL_COMPLETE_IRQ, r->bch_regs + HW_BCH_CTRL_CLR);
+-}
+-
+-/* Returns the Ready/Busy status of the given chip. */
+-int gpmi_is_ready(struct gpmi_nand_data *this, unsigned chip)
+-{
+-	struct resources *r = &this->resources;
+-	uint32_t mask = 0;
+-	uint32_t reg = 0;
+-
+-	if (GPMI_IS_MX23(this)) {
+-		mask = MX23_BM_GPMI_DEBUG_READY0 << chip;
+-		reg = readl(r->gpmi_regs + HW_GPMI_DEBUG);
+-	} else if (GPMI_IS_MX28(this) || GPMI_IS_MX6(this)) {
+-		/*
+-		 * In the imx6, all the ready/busy pins are bound
+-		 * together. So we only need to check chip 0.
+-		 */
+-		if (GPMI_IS_MX6(this))
+-			chip = 0;
+-
+-		/* MX28 shares the same R/B register as MX6Q. */
+-		mask = MX28_BF_GPMI_STAT_READY_BUSY(1 << chip);
+-		reg = readl(r->gpmi_regs + HW_GPMI_STAT);
+-	} else
+-		dev_err(this->dev, "unknown arch.\n");
+-	return reg & mask;
+-}
+-
+-static inline void set_dma_type(struct gpmi_nand_data *this,
+-					enum dma_ops_type type)
+-{
+-	this->last_dma_type = this->dma_type;
+-	this->dma_type = type;
+-}
+-
+-int gpmi_send_command(struct gpmi_nand_data *this)
+-{
+-	struct dma_chan *channel = get_dma_chan(this);
+-	struct dma_async_tx_descriptor *desc;
+-	struct scatterlist *sgl;
+-	int chip = this->current_chip;
+-	u32 pio[3];
+-
+-	/* [1] send out the PIO words */
+-	pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(BV_GPMI_CTRL0_COMMAND_MODE__WRITE)
+-		| BM_GPMI_CTRL0_WORD_LENGTH
+-		| BF_GPMI_CTRL0_CS(chip, this)
+-		| BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this)
+-		| BF_GPMI_CTRL0_ADDRESS(BV_GPMI_CTRL0_ADDRESS__NAND_CLE)
+-		| BM_GPMI_CTRL0_ADDRESS_INCREMENT
+-		| BF_GPMI_CTRL0_XFER_COUNT(this->command_length);
+-	pio[1] = pio[2] = 0;
+-	desc = dmaengine_prep_slave_sg(channel,
+-					(struct scatterlist *)pio,
+-					ARRAY_SIZE(pio), DMA_TRANS_NONE, 0);
+-	if (!desc)
+-		return -EINVAL;
+-
+-	/* [2] send out the COMMAND + ADDRESS string stored in @buffer */
+-	sgl = &this->cmd_sgl;
+-
+-	sg_init_one(sgl, this->cmd_buffer, this->command_length);
+-	dma_map_sg(this->dev, sgl, 1, DMA_TO_DEVICE);
+-	desc = dmaengine_prep_slave_sg(channel,
+-				sgl, 1, DMA_MEM_TO_DEV,
+-				DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+-	if (!desc)
+-		return -EINVAL;
+-
+-	/* [3] submit the DMA */
+-	set_dma_type(this, DMA_FOR_COMMAND);
+-	return start_dma_without_bch_irq(this, desc);
+-}
+-
+-int gpmi_send_data(struct gpmi_nand_data *this)
+-{
+-	struct dma_async_tx_descriptor *desc;
+-	struct dma_chan *channel = get_dma_chan(this);
+-	int chip = this->current_chip;
+-	uint32_t command_mode;
+-	uint32_t address;
+-	u32 pio[2];
+-
+-	/* [1] PIO */
+-	command_mode = BV_GPMI_CTRL0_COMMAND_MODE__WRITE;
+-	address      = BV_GPMI_CTRL0_ADDRESS__NAND_DATA;
+-
+-	pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(command_mode)
+-		| BM_GPMI_CTRL0_WORD_LENGTH
+-		| BF_GPMI_CTRL0_CS(chip, this)
+-		| BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this)
+-		| BF_GPMI_CTRL0_ADDRESS(address)
+-		| BF_GPMI_CTRL0_XFER_COUNT(this->upper_len);
+-	pio[1] = 0;
+-	desc = dmaengine_prep_slave_sg(channel, (struct scatterlist *)pio,
+-					ARRAY_SIZE(pio), DMA_TRANS_NONE, 0);
+-	if (!desc)
+-		return -EINVAL;
+-
+-	/* [2] send DMA request */
+-	prepare_data_dma(this, DMA_TO_DEVICE);
+-	desc = dmaengine_prep_slave_sg(channel, &this->data_sgl,
+-					1, DMA_MEM_TO_DEV,
+-					DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+-	if (!desc)
+-		return -EINVAL;
+-
+-	/* [3] submit the DMA */
+-	set_dma_type(this, DMA_FOR_WRITE_DATA);
+-	return start_dma_without_bch_irq(this, desc);
+-}
+-
+-int gpmi_read_data(struct gpmi_nand_data *this)
+-{
+-	struct dma_async_tx_descriptor *desc;
+-	struct dma_chan *channel = get_dma_chan(this);
+-	int chip = this->current_chip;
+-	u32 pio[2];
+-
+-	/* [1] : send PIO */
+-	pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(BV_GPMI_CTRL0_COMMAND_MODE__READ)
+-		| BM_GPMI_CTRL0_WORD_LENGTH
+-		| BF_GPMI_CTRL0_CS(chip, this)
+-		| BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this)
+-		| BF_GPMI_CTRL0_ADDRESS(BV_GPMI_CTRL0_ADDRESS__NAND_DATA)
+-		| BF_GPMI_CTRL0_XFER_COUNT(this->upper_len);
+-	pio[1] = 0;
+-	desc = dmaengine_prep_slave_sg(channel,
+-					(struct scatterlist *)pio,
+-					ARRAY_SIZE(pio), DMA_TRANS_NONE, 0);
+-	if (!desc)
+-		return -EINVAL;
+-
+-	/* [2] : send DMA request */
+-	prepare_data_dma(this, DMA_FROM_DEVICE);
+-	desc = dmaengine_prep_slave_sg(channel, &this->data_sgl,
+-					1, DMA_DEV_TO_MEM,
+-					DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+-	if (!desc)
+-		return -EINVAL;
+-
+-	/* [3] : submit the DMA */
+-	set_dma_type(this, DMA_FOR_READ_DATA);
+-	return start_dma_without_bch_irq(this, desc);
+-}
+-
+-int gpmi_send_page(struct gpmi_nand_data *this,
+-			dma_addr_t payload, dma_addr_t auxiliary)
+-{
+-	struct bch_geometry *geo = &this->bch_geometry;
+-	uint32_t command_mode;
+-	uint32_t address;
+-	uint32_t ecc_command;
+-	uint32_t buffer_mask;
+-	struct dma_async_tx_descriptor *desc;
+-	struct dma_chan *channel = get_dma_chan(this);
+-	int chip = this->current_chip;
+-	u32 pio[6];
+-
+-	/* A DMA descriptor that does an ECC page read. */
+-	command_mode = BV_GPMI_CTRL0_COMMAND_MODE__WRITE;
+-	address      = BV_GPMI_CTRL0_ADDRESS__NAND_DATA;
+-	ecc_command  = BV_GPMI_ECCCTRL_ECC_CMD__BCH_ENCODE;
+-	buffer_mask  = BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_PAGE |
+-				BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_AUXONLY;
+-
+-	pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(command_mode)
+-		| BM_GPMI_CTRL0_WORD_LENGTH
+-		| BF_GPMI_CTRL0_CS(chip, this)
+-		| BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this)
+-		| BF_GPMI_CTRL0_ADDRESS(address)
+-		| BF_GPMI_CTRL0_XFER_COUNT(0);
+-	pio[1] = 0;
+-	pio[2] = BM_GPMI_ECCCTRL_ENABLE_ECC
+-		| BF_GPMI_ECCCTRL_ECC_CMD(ecc_command)
+-		| BF_GPMI_ECCCTRL_BUFFER_MASK(buffer_mask);
+-	pio[3] = geo->page_size;
+-	pio[4] = payload;
+-	pio[5] = auxiliary;
+-
+-	desc = dmaengine_prep_slave_sg(channel,
+-					(struct scatterlist *)pio,
+-					ARRAY_SIZE(pio), DMA_TRANS_NONE,
+-					DMA_CTRL_ACK);
+-	if (!desc)
+-		return -EINVAL;
+-
+-	set_dma_type(this, DMA_FOR_WRITE_ECC_PAGE);
+-	return start_dma_with_bch_irq(this, desc);
+-}
+-
+-int gpmi_read_page(struct gpmi_nand_data *this,
+-				dma_addr_t payload, dma_addr_t auxiliary)
+-{
+-	struct bch_geometry *geo = &this->bch_geometry;
+-	uint32_t command_mode;
+-	uint32_t address;
+-	uint32_t ecc_command;
+-	uint32_t buffer_mask;
+-	struct dma_async_tx_descriptor *desc;
+-	struct dma_chan *channel = get_dma_chan(this);
+-	int chip = this->current_chip;
+-	u32 pio[6];
+-
+-	/* [1] Wait for the chip to report ready. */
+-	command_mode = BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY;
+-	address      = BV_GPMI_CTRL0_ADDRESS__NAND_DATA;
+-
+-	pio[0] =  BF_GPMI_CTRL0_COMMAND_MODE(command_mode)
+-		| BM_GPMI_CTRL0_WORD_LENGTH
+-		| BF_GPMI_CTRL0_CS(chip, this)
+-		| BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this)
+-		| BF_GPMI_CTRL0_ADDRESS(address)
+-		| BF_GPMI_CTRL0_XFER_COUNT(0);
+-	pio[1] = 0;
+-	desc = dmaengine_prep_slave_sg(channel,
+-				(struct scatterlist *)pio, 2,
+-				DMA_TRANS_NONE, 0);
+-	if (!desc)
+-		return -EINVAL;
+-
+-	/* [2] Enable the BCH block and read. */
+-	command_mode = BV_GPMI_CTRL0_COMMAND_MODE__READ;
+-	address      = BV_GPMI_CTRL0_ADDRESS__NAND_DATA;
+-	ecc_command  = BV_GPMI_ECCCTRL_ECC_CMD__BCH_DECODE;
+-	buffer_mask  = BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_PAGE
+-			| BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_AUXONLY;
+-
+-	pio[0] =  BF_GPMI_CTRL0_COMMAND_MODE(command_mode)
+-		| BM_GPMI_CTRL0_WORD_LENGTH
+-		| BF_GPMI_CTRL0_CS(chip, this)
+-		| BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this)
+-		| BF_GPMI_CTRL0_ADDRESS(address)
+-		| BF_GPMI_CTRL0_XFER_COUNT(geo->page_size);
+-
+-	pio[1] = 0;
+-	pio[2] =  BM_GPMI_ECCCTRL_ENABLE_ECC
+-		| BF_GPMI_ECCCTRL_ECC_CMD(ecc_command)
+-		| BF_GPMI_ECCCTRL_BUFFER_MASK(buffer_mask);
+-	pio[3] = geo->page_size;
+-	pio[4] = payload;
+-	pio[5] = auxiliary;
+-	desc = dmaengine_prep_slave_sg(channel,
+-					(struct scatterlist *)pio,
+-					ARRAY_SIZE(pio), DMA_TRANS_NONE,
+-					DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+-	if (!desc)
+-		return -EINVAL;
+-
+-	/* [3] Disable the BCH block */
+-	command_mode = BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY;
+-	address      = BV_GPMI_CTRL0_ADDRESS__NAND_DATA;
+-
+-	pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(command_mode)
+-		| BM_GPMI_CTRL0_WORD_LENGTH
+-		| BF_GPMI_CTRL0_CS(chip, this)
+-		| BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this)
+-		| BF_GPMI_CTRL0_ADDRESS(address)
+-		| BF_GPMI_CTRL0_XFER_COUNT(geo->page_size);
+-	pio[1] = 0;
+-	pio[2] = 0; /* clear GPMI_HW_GPMI_ECCCTRL, disable the BCH. */
+-	desc = dmaengine_prep_slave_sg(channel,
+-				(struct scatterlist *)pio, 3,
+-				DMA_TRANS_NONE,
+-				DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+-	if (!desc)
+-		return -EINVAL;
+-
+-	/* [4] submit the DMA */
+-	set_dma_type(this, DMA_FOR_READ_ECC_PAGE);
+-	return start_dma_with_bch_irq(this, desc);
+-}
+-
+-/**
+- * gpmi_copy_bits - copy bits from one memory region to another
+- * @dst: destination buffer
+- * @dst_bit_off: bit offset we're starting to write at
+- * @src: source buffer
+- * @src_bit_off: bit offset we're starting to read from
+- * @nbits: number of bits to copy
+- *
+- * This functions copies bits from one memory region to another, and is used by
+- * the GPMI driver to copy ECC sections which are not guaranteed to be byte
+- * aligned.
+- *
+- * src and dst should not overlap.
+- *
+- */
+-void gpmi_copy_bits(u8 *dst, size_t dst_bit_off,
+-		    const u8 *src, size_t src_bit_off,
+-		    size_t nbits)
+-{
+-	size_t i;
+-	size_t nbytes;
+-	u32 src_buffer = 0;
+-	size_t bits_in_src_buffer = 0;
+-
+-	if (!nbits)
+-		return;
+-
+-	/*
+-	 * Move src and dst pointers to the closest byte pointer and store bit
+-	 * offsets within a byte.
+-	 */
+-	src += src_bit_off / 8;
+-	src_bit_off %= 8;
+-
+-	dst += dst_bit_off / 8;
+-	dst_bit_off %= 8;
+-
+-	/*
+-	 * Initialize the src_buffer value with bits available in the first
+-	 * byte of data so that we end up with a byte aligned src pointer.
+-	 */
+-	if (src_bit_off) {
+-		src_buffer = src[0] >> src_bit_off;
+-		if (nbits >= (8 - src_bit_off)) {
+-			bits_in_src_buffer += 8 - src_bit_off;
+-		} else {
+-			src_buffer &= GENMASK(nbits - 1, 0);
+-			bits_in_src_buffer += nbits;
+-		}
+-		nbits -= bits_in_src_buffer;
+-		src++;
+-	}
+-
+-	/* Calculate the number of bytes that can be copied from src to dst. */
+-	nbytes = nbits / 8;
+-
+-	/* Try to align dst to a byte boundary. */
+-	if (dst_bit_off) {
+-		if (bits_in_src_buffer < (8 - dst_bit_off) && nbytes) {
+-			src_buffer |= src[0] << bits_in_src_buffer;
+-			bits_in_src_buffer += 8;
+-			src++;
+-			nbytes--;
+-		}
+-
+-		if (bits_in_src_buffer >= (8 - dst_bit_off)) {
+-			dst[0] &= GENMASK(dst_bit_off - 1, 0);
+-			dst[0] |= src_buffer << dst_bit_off;
+-			src_buffer >>= (8 - dst_bit_off);
+-			bits_in_src_buffer -= (8 - dst_bit_off);
+-			dst_bit_off = 0;
+-			dst++;
+-			if (bits_in_src_buffer > 7) {
+-				bits_in_src_buffer -= 8;
+-				dst[0] = src_buffer;
+-				dst++;
+-				src_buffer >>= 8;
+-			}
+-		}
+-	}
+-
+-	if (!bits_in_src_buffer && !dst_bit_off) {
+-		/*
+-		 * Both src and dst pointers are byte aligned, thus we can
+-		 * just use the optimized memcpy function.
+-		 */
+-		if (nbytes)
+-			memcpy(dst, src, nbytes);
+-	} else {
+-		/*
+-		 * src buffer is not byte aligned, hence we have to copy each
+-		 * src byte to the src_buffer variable before extracting a byte
+-		 * to store in dst.
+-		 */
+-		for (i = 0; i < nbytes; i++) {
+-			src_buffer |= src[i] << bits_in_src_buffer;
+-			dst[i] = src_buffer;
+-			src_buffer >>= 8;
+-		}
+-	}
+-	/* Update dst and src pointers */
+-	dst += nbytes;
+-	src += nbytes;
+-
+-	/*
+-	 * nbits is the number of remaining bits. It should not exceed 8 as
+-	 * we've already copied as much bytes as possible.
+-	 */
+-	nbits %= 8;
+-
+-	/*
+-	 * If there's no more bits to copy to the destination and src buffer
+-	 * was already byte aligned, then we're done.
+-	 */
+-	if (!nbits && !bits_in_src_buffer)
+-		return;
+-
+-	/* Copy the remaining bits to src_buffer */
+-	if (nbits)
+-		src_buffer |= (*src & GENMASK(nbits - 1, 0)) <<
+-			      bits_in_src_buffer;
+-	bits_in_src_buffer += nbits;
+-
+-	/*
+-	 * In case there were not enough bits to get a byte aligned dst buffer
+-	 * prepare the src_buffer variable to match the dst organization (shift
+-	 * src_buffer by dst_bit_off and retrieve the least significant bits
+-	 * from dst).
+-	 */
+-	if (dst_bit_off)
+-		src_buffer = (src_buffer << dst_bit_off) |
+-			     (*dst & GENMASK(dst_bit_off - 1, 0));
+-	bits_in_src_buffer += dst_bit_off;
+-
+-	/*
+-	 * Keep most significant bits from dst if we end up with an unaligned
+-	 * number of bits.
+-	 */
+-	nbytes = bits_in_src_buffer / 8;
+-	if (bits_in_src_buffer % 8) {
+-		src_buffer |= (dst[nbytes] &
+-			       GENMASK(7, bits_in_src_buffer % 8)) <<
+-			      (nbytes * 8);
+-		nbytes++;
+-	}
+-
+-	/* Copy the remaining bytes to dst */
+-	for (i = 0; i < nbytes; i++) {
+-		dst[i] = src_buffer;
+-		src_buffer >>= 8;
+-	}
+-}
+diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
+deleted file mode 100644
+index 50f8d4a..0000000
+--- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
++++ /dev/null
+@@ -1,2201 +0,0 @@
+-/*
+- * Freescale GPMI NAND Flash Driver
+- *
+- * Copyright (C) 2010-2015 Freescale Semiconductor, Inc.
+- * Copyright (C) 2008 Embedded Alley Solutions, Inc.
+- *
+- * 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.
+- *
+- * You should have received a copy of the GNU General Public License along
+- * with this program; if not, write to the Free Software Foundation, Inc.,
+- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+- */
+-#include <linux/clk.h>
+-#include <linux/slab.h>
+-#include <linux/sched/task_stack.h>
+-#include <linux/interrupt.h>
+-#include <linux/module.h>
+-#include <linux/mtd/partitions.h>
+-#include <linux/of.h>
+-#include <linux/of_device.h>
+-#include "gpmi-nand.h"
+-#include "bch-regs.h"
+-
+-/* Resource names for the GPMI NAND driver. */
+-#define GPMI_NAND_GPMI_REGS_ADDR_RES_NAME  "gpmi-nand"
+-#define GPMI_NAND_BCH_REGS_ADDR_RES_NAME   "bch"
+-#define GPMI_NAND_BCH_INTERRUPT_RES_NAME   "bch"
+-
+-/* add our owner bbt descriptor */
+-static uint8_t scan_ff_pattern[] = { 0xff };
+-static struct nand_bbt_descr gpmi_bbt_descr = {
+-	.options	= 0,
+-	.offs		= 0,
+-	.len		= 1,
+-	.pattern	= scan_ff_pattern
+-};
+-
+-/*
+- * We may change the layout if we can get the ECC info from the datasheet,
+- * else we will use all the (page + OOB).
+- */
+-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 gpmi_nand_data *this = nand_get_controller_data(chip);
+-	struct bch_geometry *geo = &this->bch_geometry;
+-
+-	if (section)
+-		return -ERANGE;
+-
+-	oobregion->offset = 0;
+-	oobregion->length = geo->page_size - mtd->writesize;
+-
+-	return 0;
+-}
+-
+-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 gpmi_nand_data *this = nand_get_controller_data(chip);
+-	struct bch_geometry *geo = &this->bch_geometry;
+-
+-	if (section)
+-		return -ERANGE;
+-
+-	/* The available oob size we have. */
+-	if (geo->page_size < mtd->writesize + mtd->oobsize) {
+-		oobregion->offset = geo->page_size - mtd->writesize;
+-		oobregion->length = mtd->oobsize - oobregion->offset;
+-	}
+-
+-	return 0;
+-}
+-
+-static const char * const gpmi_clks_for_mx2x[] = {
+-	"gpmi_io",
+-};
+-
+-static const struct mtd_ooblayout_ops gpmi_ooblayout_ops = {
+-	.ecc = gpmi_ooblayout_ecc,
+-	.free = gpmi_ooblayout_free,
+-};
+-
+-static const struct gpmi_devdata gpmi_devdata_imx23 = {
+-	.type = IS_MX23,
+-	.bch_max_ecc_strength = 20,
+-	.max_chain_delay = 16,
+-	.clks = gpmi_clks_for_mx2x,
+-	.clks_count = ARRAY_SIZE(gpmi_clks_for_mx2x),
+-};
+-
+-static const struct gpmi_devdata gpmi_devdata_imx28 = {
+-	.type = IS_MX28,
+-	.bch_max_ecc_strength = 20,
+-	.max_chain_delay = 16,
+-	.clks = gpmi_clks_for_mx2x,
+-	.clks_count = ARRAY_SIZE(gpmi_clks_for_mx2x),
+-};
+-
+-static const char * const gpmi_clks_for_mx6[] = {
+-	"gpmi_io", "gpmi_apb", "gpmi_bch", "gpmi_bch_apb", "per1_bch",
+-};
+-
+-static const struct gpmi_devdata gpmi_devdata_imx6q = {
+-	.type = IS_MX6Q,
+-	.bch_max_ecc_strength = 40,
+-	.max_chain_delay = 12,
+-	.clks = gpmi_clks_for_mx6,
+-	.clks_count = ARRAY_SIZE(gpmi_clks_for_mx6),
+-};
+-
+-static const struct gpmi_devdata gpmi_devdata_imx6sx = {
+-	.type = IS_MX6SX,
+-	.bch_max_ecc_strength = 62,
+-	.max_chain_delay = 12,
+-	.clks = gpmi_clks_for_mx6,
+-	.clks_count = ARRAY_SIZE(gpmi_clks_for_mx6),
+-};
+-
+-static const char * const gpmi_clks_for_mx7d[] = {
+-	"gpmi_io", "gpmi_bch_apb",
+-};
+-
+-static const struct gpmi_devdata gpmi_devdata_imx7d = {
+-	.type = IS_MX7D,
+-	.bch_max_ecc_strength = 62,
+-	.max_chain_delay = 12,
+-	.clks = gpmi_clks_for_mx7d,
+-	.clks_count = ARRAY_SIZE(gpmi_clks_for_mx7d),
+-};
+-
+-static irqreturn_t bch_irq(int irq, void *cookie)
+-{
+-	struct gpmi_nand_data *this = cookie;
+-
+-	gpmi_clear_bch(this);
+-	complete(&this->bch_done);
+-	return IRQ_HANDLED;
+-}
+-
+-/*
+- *  Calculate the ECC strength by hand:
+- *	E : The ECC strength.
+- *	G : the length of Galois Field.
+- *	N : The chunk count of per page.
+- *	O : the oobsize of the NAND chip.
+- *	M : the metasize of per page.
+- *
+- *	The formula is :
+- *		E * G * N
+- *	      ------------ <= (O - M)
+- *                  8
+- *
+- *      So, we get E by:
+- *                    (O - M) * 8
+- *              E <= -------------
+- *                       G * N
+- */
+-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);
+-	int ecc_strength;
+-
+-	ecc_strength = ((mtd->oobsize - geo->metadata_size) * 8)
+-			/ (geo->gf_len * geo->ecc_chunk_count);
+-
+-	/* We need the minor even number. */
+-	return round_down(ecc_strength, 2);
+-}
+-
+-static inline bool gpmi_check_ecc(struct gpmi_nand_data *this)
+-{
+-	struct bch_geometry *geo = &this->bch_geometry;
+-
+-	/* Do the sanity check. */
+-	if (GPMI_IS_MX23(this) || GPMI_IS_MX28(this)) {
+-		/* The mx23/mx28 only support the GF13. */
+-		if (geo->gf_len == 14)
+-			return false;
+-	}
+-	return geo->ecc_strength <= this->devdata->bch_max_ecc_strength;
+-}
+-
+-/*
+- * If we can get the ECC information from the nand chip, we do not
+- * need to calculate them ourselves.
+- *
+- * We may have available oob space in this case.
+- */
+-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);
+-	unsigned int block_mark_bit_offset;
+-
+-	if (!(chip->ecc_strength_ds > 0 && chip->ecc_step_ds > 0))
+-		return -EINVAL;
+-
+-	switch (chip->ecc_step_ds) {
+-	case SZ_512:
+-		geo->gf_len = 13;
+-		break;
+-	case SZ_1K:
+-		geo->gf_len = 14;
+-		break;
+-	default:
+-		dev_err(this->dev,
+-			"unsupported nand chip. ecc bits : %d, ecc size : %d\n",
+-			chip->ecc_strength_ds, chip->ecc_step_ds);
+-		return -EINVAL;
+-	}
+-	geo->ecc_chunk_size = chip->ecc_step_ds;
+-	geo->ecc_strength = round_up(chip->ecc_strength_ds, 2);
+-	if (!gpmi_check_ecc(this))
+-		return -EINVAL;
+-
+-	/* Keep the C >= O */
+-	if (geo->ecc_chunk_size < mtd->oobsize) {
+-		dev_err(this->dev,
+-			"unsupported nand chip. ecc size: %d, oob size : %d\n",
+-			chip->ecc_step_ds, mtd->oobsize);
+-		return -EINVAL;
+-	}
+-
+-	/* The default value, see comment in the legacy_set_geometry(). */
+-	geo->metadata_size = 10;
+-
+-	geo->ecc_chunk_count = mtd->writesize / geo->ecc_chunk_size;
+-
+-	/*
+-	 * Now, the NAND chip with 2K page(data chunk is 512byte) shows below:
+-	 *
+-	 *    |                          P                            |
+-	 *    |<----------------------------------------------------->|
+-	 *    |                                                       |
+-	 *    |                                        (Block Mark)   |
+-	 *    |                      P'                      |      | |     |
+-	 *    |<-------------------------------------------->|  D   | |  O' |
+-	 *    |                                              |<---->| |<--->|
+-	 *    V                                              V      V V     V
+-	 *    +---+----------+-+----------+-+----------+-+----------+-+-----+
+-	 *    | M |   data   |E|   data   |E|   data   |E|   data   |E|     |
+-	 *    +---+----------+-+----------+-+----------+-+----------+-+-----+
+-	 *                                                   ^              ^
+-	 *                                                   |      O       |
+-	 *                                                   |<------------>|
+-	 *                                                   |              |
+-	 *
+-	 *	P : the page size for BCH module.
+-	 *	E : The ECC strength.
+-	 *	G : the length of Galois Field.
+-	 *	N : The chunk count of per page.
+-	 *	M : the metasize of per page.
+-	 *	C : the ecc chunk size, aka the "data" above.
+-	 *	P': the nand chip's page size.
+-	 *	O : the nand chip's oob size.
+-	 *	O': the free oob.
+-	 *
+-	 *	The formula for P is :
+-	 *
+-	 *	            E * G * N
+-	 *	       P = ------------ + P' + M
+-	 *                      8
+-	 *
+-	 * The position of block mark moves forward in the ECC-based view
+-	 * of page, and the delta is:
+-	 *
+-	 *                   E * G * (N - 1)
+-	 *             D = (---------------- + M)
+-	 *                          8
+-	 *
+-	 * Please see the comment in legacy_set_geometry().
+-	 * With the condition C >= O , we still can get same result.
+-	 * So the bit position of the physical block mark within the ECC-based
+-	 * view of the page is :
+-	 *             (P' - D) * 8
+-	 */
+-	geo->page_size = mtd->writesize + geo->metadata_size +
+-		(geo->gf_len * geo->ecc_strength * geo->ecc_chunk_count) / 8;
+-
+-	geo->payload_size = mtd->writesize;
+-
+-	geo->auxiliary_status_offset = ALIGN(geo->metadata_size, 4);
+-	geo->auxiliary_size = ALIGN(geo->metadata_size, 4)
+-				+ ALIGN(geo->ecc_chunk_count, 4);
+-
+-	if (!this->swap_block_mark)
+-		return 0;
+-
+-	/* For bit swap. */
+-	block_mark_bit_offset = mtd->writesize * 8 -
+-		(geo->ecc_strength * geo->gf_len * (geo->ecc_chunk_count - 1)
+-				+ geo->metadata_size * 8);
+-
+-	geo->block_mark_byte_offset = block_mark_bit_offset / 8;
+-	geo->block_mark_bit_offset  = block_mark_bit_offset % 8;
+-	return 0;
+-}
+-
+-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);
+-	unsigned int metadata_size;
+-	unsigned int status_size;
+-	unsigned int block_mark_bit_offset;
+-
+-	/*
+-	 * The size of the metadata can be changed, though we set it to 10
+-	 * bytes now. But it can't be too large, because we have to save
+-	 * enough space for BCH.
+-	 */
+-	geo->metadata_size = 10;
+-
+-	/* The default for the length of Galois Field. */
+-	geo->gf_len = 13;
+-
+-	/* The default for chunk size. */
+-	geo->ecc_chunk_size = 512;
+-	while (geo->ecc_chunk_size < mtd->oobsize) {
+-		geo->ecc_chunk_size *= 2; /* keep C >= O */
+-		geo->gf_len = 14;
+-	}
+-
+-	geo->ecc_chunk_count = mtd->writesize / geo->ecc_chunk_size;
+-
+-	/* We use the same ECC strength for all chunks. */
+-	geo->ecc_strength = get_ecc_strength(this);
+-	if (!gpmi_check_ecc(this)) {
+-		dev_err(this->dev,
+-			"ecc strength: %d cannot be supported by the controller (%d)\n"
+-			"try to use minimum ecc strength that NAND chip required\n",
+-			geo->ecc_strength,
+-			this->devdata->bch_max_ecc_strength);
+-		return -EINVAL;
+-	}
+-
+-	geo->page_size = mtd->writesize + geo->metadata_size +
+-		(geo->gf_len * geo->ecc_strength * geo->ecc_chunk_count) / 8;
+-	geo->payload_size = mtd->writesize;
+-
+-	/*
+-	 * The auxiliary buffer contains the metadata and the ECC status. The
+-	 * metadata is padded to the nearest 32-bit boundary. The ECC status
+-	 * contains one byte for every ECC chunk, and is also padded to the
+-	 * nearest 32-bit boundary.
+-	 */
+-	metadata_size = ALIGN(geo->metadata_size, 4);
+-	status_size   = ALIGN(geo->ecc_chunk_count, 4);
+-
+-	geo->auxiliary_size = metadata_size + status_size;
+-	geo->auxiliary_status_offset = metadata_size;
+-
+-	if (!this->swap_block_mark)
+-		return 0;
+-
+-	/*
+-	 * We need to compute the byte and bit offsets of
+-	 * the physical block mark within the ECC-based view of the page.
+-	 *
+-	 * NAND chip with 2K page shows below:
+-	 *                                             (Block Mark)
+-	 *                                                   |      |
+-	 *                                                   |  D   |
+-	 *                                                   |<---->|
+-	 *                                                   V      V
+-	 *    +---+----------+-+----------+-+----------+-+----------+-+
+-	 *    | M |   data   |E|   data   |E|   data   |E|   data   |E|
+-	 *    +---+----------+-+----------+-+----------+-+----------+-+
+-	 *
+-	 * The position of block mark moves forward in the ECC-based view
+-	 * of page, and the delta is:
+-	 *
+-	 *                   E * G * (N - 1)
+-	 *             D = (---------------- + M)
+-	 *                          8
+-	 *
+-	 * With the formula to compute the ECC strength, and the condition
+-	 *       : C >= O         (C is the ecc chunk size)
+-	 *
+-	 * It's easy to deduce to the following result:
+-	 *
+-	 *         E * G       (O - M)      C - M         C - M
+-	 *      ----------- <= ------- <=  --------  <  ---------
+-	 *           8            N           N          (N - 1)
+-	 *
+-	 *  So, we get:
+-	 *
+-	 *                   E * G * (N - 1)
+-	 *             D = (---------------- + M) < C
+-	 *                          8
+-	 *
+-	 *  The above inequality means the position of block mark
+-	 *  within the ECC-based view of the page is still in the data chunk,
+-	 *  and it's NOT in the ECC bits of the chunk.
+-	 *
+-	 *  Use the following to compute the bit position of the
+-	 *  physical block mark within the ECC-based view of the page:
+-	 *          (page_size - D) * 8
+-	 *
+-	 *  --Huang Shijie
+-	 */
+-	block_mark_bit_offset = mtd->writesize * 8 -
+-		(geo->ecc_strength * geo->gf_len * (geo->ecc_chunk_count - 1)
+-				+ geo->metadata_size * 8);
+-
+-	geo->block_mark_byte_offset = block_mark_bit_offset / 8;
+-	geo->block_mark_bit_offset  = block_mark_bit_offset % 8;
+-	return 0;
+-}
+-
+-int common_nfc_set_geometry(struct gpmi_nand_data *this)
+-{
+-	if ((of_property_read_bool(this->dev->of_node, "fsl,use-minimum-ecc"))
+-				|| legacy_set_geometry(this))
+-		return set_geometry_by_ecc_info(this);
+-
+-	return 0;
+-}
+-
+-struct dma_chan *get_dma_chan(struct gpmi_nand_data *this)
+-{
+-	/* We use the DMA channel 0 to access all the nand chips. */
+-	return this->dma_chans[0];
+-}
+-
+-/* Can we use the upper's buffer directly for DMA? */
+-void prepare_data_dma(struct gpmi_nand_data *this, enum dma_data_direction dr)
+-{
+-	struct scatterlist *sgl = &this->data_sgl;
+-	int ret;
+-
+-	/* first try to map the upper buffer directly */
+-	if (virt_addr_valid(this->upper_buf) &&
+-		!object_is_on_stack(this->upper_buf)) {
+-		sg_init_one(sgl, this->upper_buf, this->upper_len);
+-		ret = dma_map_sg(this->dev, sgl, 1, dr);
+-		if (ret == 0)
+-			goto map_fail;
+-
+-		this->direct_dma_map_ok = true;
+-		return;
+-	}
+-
+-map_fail:
+-	/* We have to use our own DMA buffer. */
+-	sg_init_one(sgl, this->data_buffer_dma, this->upper_len);
+-
+-	if (dr == DMA_TO_DEVICE)
+-		memcpy(this->data_buffer_dma, this->upper_buf, this->upper_len);
+-
+-	dma_map_sg(this->dev, sgl, 1, dr);
+-
+-	this->direct_dma_map_ok = false;
+-}
+-
+-/* This will be called after the DMA operation is finished. */
+-static void dma_irq_callback(void *param)
+-{
+-	struct gpmi_nand_data *this = param;
+-	struct completion *dma_c = &this->dma_done;
+-
+-	switch (this->dma_type) {
+-	case DMA_FOR_COMMAND:
+-		dma_unmap_sg(this->dev, &this->cmd_sgl, 1, DMA_TO_DEVICE);
+-		break;
+-
+-	case DMA_FOR_READ_DATA:
+-		dma_unmap_sg(this->dev, &this->data_sgl, 1, DMA_FROM_DEVICE);
+-		if (this->direct_dma_map_ok == false)
+-			memcpy(this->upper_buf, this->data_buffer_dma,
+-				this->upper_len);
+-		break;
+-
+-	case DMA_FOR_WRITE_DATA:
+-		dma_unmap_sg(this->dev, &this->data_sgl, 1, DMA_TO_DEVICE);
+-		break;
+-
+-	case DMA_FOR_READ_ECC_PAGE:
+-	case DMA_FOR_WRITE_ECC_PAGE:
+-		/* We have to wait the BCH interrupt to finish. */
+-		break;
+-
+-	default:
+-		dev_err(this->dev, "in wrong DMA operation.\n");
+-	}
+-
+-	complete(dma_c);
+-}
+-
+-int start_dma_without_bch_irq(struct gpmi_nand_data *this,
+-				struct dma_async_tx_descriptor *desc)
+-{
+-	struct completion *dma_c = &this->dma_done;
+-	unsigned long timeout;
+-
+-	init_completion(dma_c);
+-
+-	desc->callback		= dma_irq_callback;
+-	desc->callback_param	= this;
+-	dmaengine_submit(desc);
+-	dma_async_issue_pending(get_dma_chan(this));
+-
+-	/* Wait for the interrupt from the DMA block. */
+-	timeout = wait_for_completion_timeout(dma_c, msecs_to_jiffies(1000));
+-	if (!timeout) {
+-		dev_err(this->dev, "DMA timeout, last DMA :%d\n",
+-			this->last_dma_type);
+-		gpmi_dump_info(this);
+-		return -ETIMEDOUT;
+-	}
+-	return 0;
+-}
+-
+-/*
+- * This function is used in BCH reading or BCH writing pages.
+- * It will wait for the BCH interrupt as long as ONE second.
+- * Actually, we must wait for two interrupts :
+- *	[1] firstly the DMA interrupt and
+- *	[2] secondly the BCH interrupt.
+- */
+-int start_dma_with_bch_irq(struct gpmi_nand_data *this,
+-			struct dma_async_tx_descriptor *desc)
+-{
+-	struct completion *bch_c = &this->bch_done;
+-	unsigned long timeout;
+-
+-	/* Prepare to receive an interrupt from the BCH block. */
+-	init_completion(bch_c);
+-
+-	/* start the DMA */
+-	start_dma_without_bch_irq(this, desc);
+-
+-	/* Wait for the interrupt from the BCH block. */
+-	timeout = wait_for_completion_timeout(bch_c, msecs_to_jiffies(1000));
+-	if (!timeout) {
+-		dev_err(this->dev, "BCH timeout, last DMA :%d\n",
+-			this->last_dma_type);
+-		gpmi_dump_info(this);
+-		return -ETIMEDOUT;
+-	}
+-	return 0;
+-}
+-
+-static int acquire_register_block(struct gpmi_nand_data *this,
+-				  const char *res_name)
+-{
+-	struct platform_device *pdev = this->pdev;
+-	struct resources *res = &this->resources;
+-	struct resource *r;
+-	void __iomem *p;
+-
+-	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, res_name);
+-	p = devm_ioremap_resource(&pdev->dev, r);
+-	if (IS_ERR(p))
+-		return PTR_ERR(p);
+-
+-	if (!strcmp(res_name, GPMI_NAND_GPMI_REGS_ADDR_RES_NAME))
+-		res->gpmi_regs = p;
+-	else if (!strcmp(res_name, GPMI_NAND_BCH_REGS_ADDR_RES_NAME))
+-		res->bch_regs = p;
+-	else
+-		dev_err(this->dev, "unknown resource name : %s\n", res_name);
+-
+-	return 0;
+-}
+-
+-static int acquire_bch_irq(struct gpmi_nand_data *this, irq_handler_t irq_h)
+-{
+-	struct platform_device *pdev = this->pdev;
+-	const char *res_name = GPMI_NAND_BCH_INTERRUPT_RES_NAME;
+-	struct resource *r;
+-	int err;
+-
+-	r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, res_name);
+-	if (!r) {
+-		dev_err(this->dev, "Can't get resource for %s\n", res_name);
+-		return -ENODEV;
+-	}
+-
+-	err = devm_request_irq(this->dev, r->start, irq_h, 0, res_name, this);
+-	if (err)
+-		dev_err(this->dev, "error requesting BCH IRQ\n");
+-
+-	return err;
+-}
+-
+-static void release_dma_channels(struct gpmi_nand_data *this)
+-{
+-	unsigned int i;
+-	for (i = 0; i < DMA_CHANS; i++)
+-		if (this->dma_chans[i]) {
+-			dma_release_channel(this->dma_chans[i]);
+-			this->dma_chans[i] = NULL;
+-		}
+-}
+-
+-static int acquire_dma_channels(struct gpmi_nand_data *this)
+-{
+-	struct platform_device *pdev = this->pdev;
+-	struct dma_chan *dma_chan;
+-
+-	/* request dma channel */
+-	dma_chan = dma_request_slave_channel(&pdev->dev, "rx-tx");
+-	if (!dma_chan) {
+-		dev_err(this->dev, "Failed to request DMA channel.\n");
+-		goto acquire_err;
+-	}
+-
+-	this->dma_chans[0] = dma_chan;
+-	return 0;
+-
+-acquire_err:
+-	release_dma_channels(this);
+-	return -EINVAL;
+-}
+-
+-static int gpmi_get_clks(struct gpmi_nand_data *this)
+-{
+-	struct resources *r = &this->resources;
+-	struct clk *clk;
+-	int err, i;
+-
+-	for (i = 0; i < this->devdata->clks_count; i++) {
+-		clk = devm_clk_get(this->dev, this->devdata->clks[i]);
+-		if (IS_ERR(clk)) {
+-			err = PTR_ERR(clk);
+-			goto err_clock;
+-		}
+-
+-		r->clock[i] = clk;
+-	}
+-
+-	if (GPMI_IS_MX6(this))
+-		/*
+-		 * Set the default value for the gpmi clock.
+-		 *
+-		 * If you want to use the ONFI nand which is in the
+-		 * Synchronous Mode, you should change the clock as you need.
+-		 */
+-		clk_set_rate(r->clock[0], 22000000);
+-
+-	return 0;
+-
+-err_clock:
+-	dev_dbg(this->dev, "failed in finding the clocks.\n");
+-	return err;
+-}
+-
+-static int acquire_resources(struct gpmi_nand_data *this)
+-{
+-	int ret;
+-
+-	ret = acquire_register_block(this, GPMI_NAND_GPMI_REGS_ADDR_RES_NAME);
+-	if (ret)
+-		goto exit_regs;
+-
+-	ret = acquire_register_block(this, GPMI_NAND_BCH_REGS_ADDR_RES_NAME);
+-	if (ret)
+-		goto exit_regs;
+-
+-	ret = acquire_bch_irq(this, bch_irq);
+-	if (ret)
+-		goto exit_regs;
+-
+-	ret = acquire_dma_channels(this);
+-	if (ret)
+-		goto exit_regs;
+-
+-	ret = gpmi_get_clks(this);
+-	if (ret)
+-		goto exit_clock;
+-	return 0;
+-
+-exit_clock:
+-	release_dma_channels(this);
+-exit_regs:
+-	return ret;
+-}
+-
+-static void release_resources(struct gpmi_nand_data *this)
+-{
+-	release_dma_channels(this);
+-}
+-
+-static int init_hardware(struct gpmi_nand_data *this)
+-{
+-	int ret;
+-
+-	/*
+-	 * This structure contains the "safe" GPMI timing that should succeed
+-	 * with any NAND Flash device
+-	 * (although, with less-than-optimal performance).
+-	 */
+-	struct nand_timing  safe_timing = {
+-		.data_setup_in_ns        = 80,
+-		.data_hold_in_ns         = 60,
+-		.address_setup_in_ns     = 25,
+-		.gpmi_sample_delay_in_ns =  6,
+-		.tREA_in_ns              = -1,
+-		.tRLOH_in_ns             = -1,
+-		.tRHOH_in_ns             = -1,
+-	};
+-
+-	/* Initialize the hardwares. */
+-	ret = gpmi_init(this);
+-	if (ret)
+-		return ret;
+-
+-	this->timing = safe_timing;
+-	return 0;
+-}
+-
+-static int read_page_prepare(struct gpmi_nand_data *this,
+-			void *destination, unsigned length,
+-			void *alt_virt, dma_addr_t alt_phys, unsigned alt_size,
+-			void **use_virt, dma_addr_t *use_phys)
+-{
+-	struct device *dev = this->dev;
+-
+-	if (virt_addr_valid(destination)) {
+-		dma_addr_t dest_phys;
+-
+-		dest_phys = dma_map_single(dev, destination,
+-						length, DMA_FROM_DEVICE);
+-		if (dma_mapping_error(dev, dest_phys)) {
+-			if (alt_size < length) {
+-				dev_err(dev, "Alternate buffer is too small\n");
+-				return -ENOMEM;
+-			}
+-			goto map_failed;
+-		}
+-		*use_virt = destination;
+-		*use_phys = dest_phys;
+-		this->direct_dma_map_ok = true;
+-		return 0;
+-	}
+-
+-map_failed:
+-	*use_virt = alt_virt;
+-	*use_phys = alt_phys;
+-	this->direct_dma_map_ok = false;
+-	return 0;
+-}
+-
+-static inline void read_page_end(struct gpmi_nand_data *this,
+-			void *destination, unsigned length,
+-			void *alt_virt, dma_addr_t alt_phys, unsigned alt_size,
+-			void *used_virt, dma_addr_t used_phys)
+-{
+-	if (this->direct_dma_map_ok)
+-		dma_unmap_single(this->dev, used_phys, length, DMA_FROM_DEVICE);
+-}
+-
+-static inline void read_page_swap_end(struct gpmi_nand_data *this,
+-			void *destination, unsigned length,
+-			void *alt_virt, dma_addr_t alt_phys, unsigned alt_size,
+-			void *used_virt, dma_addr_t used_phys)
+-{
+-	if (!this->direct_dma_map_ok)
+-		memcpy(destination, alt_virt, length);
+-}
+-
+-static int send_page_prepare(struct gpmi_nand_data *this,
+-			const void *source, unsigned length,
+-			void *alt_virt, dma_addr_t alt_phys, unsigned alt_size,
+-			const void **use_virt, dma_addr_t *use_phys)
+-{
+-	struct device *dev = this->dev;
+-
+-	if (virt_addr_valid(source)) {
+-		dma_addr_t source_phys;
+-
+-		source_phys = dma_map_single(dev, (void *)source, length,
+-						DMA_TO_DEVICE);
+-		if (dma_mapping_error(dev, source_phys)) {
+-			if (alt_size < length) {
+-				dev_err(dev, "Alternate buffer is too small\n");
+-				return -ENOMEM;
+-			}
+-			goto map_failed;
+-		}
+-		*use_virt = source;
+-		*use_phys = source_phys;
+-		return 0;
+-	}
+-map_failed:
+-	/*
+-	 * Copy the content of the source buffer into the alternate
+-	 * buffer and set up the return values accordingly.
+-	 */
+-	memcpy(alt_virt, source, length);
+-
+-	*use_virt = alt_virt;
+-	*use_phys = alt_phys;
+-	return 0;
+-}
+-
+-static void send_page_end(struct gpmi_nand_data *this,
+-			const void *source, unsigned length,
+-			void *alt_virt, dma_addr_t alt_phys, unsigned alt_size,
+-			const void *used_virt, dma_addr_t used_phys)
+-{
+-	struct device *dev = this->dev;
+-	if (used_virt == source)
+-		dma_unmap_single(dev, used_phys, length, DMA_TO_DEVICE);
+-}
+-
+-static void gpmi_free_dma_buffer(struct gpmi_nand_data *this)
+-{
+-	struct device *dev = this->dev;
+-
+-	if (this->page_buffer_virt && virt_addr_valid(this->page_buffer_virt))
+-		dma_free_coherent(dev, this->page_buffer_size,
+-					this->page_buffer_virt,
+-					this->page_buffer_phys);
+-	kfree(this->cmd_buffer);
+-	kfree(this->data_buffer_dma);
+-	kfree(this->raw_buffer);
+-
+-	this->cmd_buffer	= NULL;
+-	this->data_buffer_dma	= NULL;
+-	this->raw_buffer	= NULL;
+-	this->page_buffer_virt	= NULL;
+-	this->page_buffer_size	=  0;
+-}
+-
+-/* Allocate the DMA buffers */
+-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);
+-
+-	/* [1] Allocate a command buffer. PAGE_SIZE is enough. */
+-	this->cmd_buffer = kzalloc(PAGE_SIZE, GFP_DMA | GFP_KERNEL);
+-	if (this->cmd_buffer == NULL)
+-		goto error_alloc;
+-
+-	/*
+-	 * [2] Allocate a read/write data buffer.
+-	 *     The gpmi_alloc_dma_buffer can be called twice.
+-	 *     We allocate a PAGE_SIZE length buffer if gpmi_alloc_dma_buffer
+-	 *     is called before the nand_scan_ident; and we allocate a buffer
+-	 *     of the real NAND page size when the gpmi_alloc_dma_buffer is
+-	 *     called after the nand_scan_ident.
+-	 */
+-	this->data_buffer_dma = kzalloc(mtd->writesize ?: PAGE_SIZE,
+-					GFP_DMA | GFP_KERNEL);
+-	if (this->data_buffer_dma == NULL)
+-		goto error_alloc;
+-
+-	/*
+-	 * [3] Allocate the page buffer.
+-	 *
+-	 * Both the payload buffer and the auxiliary buffer must appear on
+-	 * 32-bit boundaries. We presume the size of the payload buffer is a
+-	 * power of two and is much larger than four, which guarantees the
+-	 * auxiliary buffer will appear on a 32-bit boundary.
+-	 */
+-	this->page_buffer_size = geo->payload_size + geo->auxiliary_size;
+-	this->page_buffer_virt = dma_alloc_coherent(dev, this->page_buffer_size,
+-					&this->page_buffer_phys, GFP_DMA);
+-	if (!this->page_buffer_virt)
+-		goto error_alloc;
+-
+-	this->raw_buffer = kzalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL);
+-	if (!this->raw_buffer)
+-		goto error_alloc;
+-
+-	/* Slice up the page buffer. */
+-	this->payload_virt = this->page_buffer_virt;
+-	this->payload_phys = this->page_buffer_phys;
+-	this->auxiliary_virt = this->payload_virt + geo->payload_size;
+-	this->auxiliary_phys = this->payload_phys + geo->payload_size;
+-	return 0;
+-
+-error_alloc:
+-	gpmi_free_dma_buffer(this);
+-	return -ENOMEM;
+-}
+-
+-static void gpmi_cmd_ctrl(struct mtd_info *mtd, int data, unsigned int ctrl)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct gpmi_nand_data *this = nand_get_controller_data(chip);
+-	int ret;
+-
+-	/*
+-	 * Every operation begins with a command byte and a series of zero or
+-	 * more address bytes. These are distinguished by either the Address
+-	 * Latch Enable (ALE) or Command Latch Enable (CLE) signals being
+-	 * asserted. When MTD is ready to execute the command, it will deassert
+-	 * both latch enables.
+-	 *
+-	 * Rather than run a separate DMA operation for every single byte, we
+-	 * queue them up and run a single DMA operation for the entire series
+-	 * of command and data bytes. NAND_CMD_NONE means the END of the queue.
+-	 */
+-	if ((ctrl & (NAND_ALE | NAND_CLE))) {
+-		if (data != NAND_CMD_NONE)
+-			this->cmd_buffer[this->command_length++] = data;
+-		return;
+-	}
+-
+-	if (!this->command_length)
+-		return;
+-
+-	ret = gpmi_send_command(this);
+-	if (ret)
+-		dev_err(this->dev, "Chip: %u, Error %d\n",
+-			this->current_chip, ret);
+-
+-	this->command_length = 0;
+-}
+-
+-static int gpmi_dev_ready(struct mtd_info *mtd)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct gpmi_nand_data *this = nand_get_controller_data(chip);
+-
+-	return gpmi_is_ready(this, this->current_chip);
+-}
+-
+-static void gpmi_select_chip(struct mtd_info *mtd, int chipnr)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct gpmi_nand_data *this = nand_get_controller_data(chip);
+-
+-	if ((this->current_chip < 0) && (chipnr >= 0))
+-		gpmi_begin(this);
+-	else if ((this->current_chip >= 0) && (chipnr < 0))
+-		gpmi_end(this);
+-
+-	this->current_chip = chipnr;
+-}
+-
+-static void gpmi_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct gpmi_nand_data *this = nand_get_controller_data(chip);
+-
+-	dev_dbg(this->dev, "len is %d\n", len);
+-	this->upper_buf	= buf;
+-	this->upper_len	= len;
+-
+-	gpmi_read_data(this);
+-}
+-
+-static void gpmi_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct gpmi_nand_data *this = nand_get_controller_data(chip);
+-
+-	dev_dbg(this->dev, "len is %d\n", len);
+-	this->upper_buf	= (uint8_t *)buf;
+-	this->upper_len	= len;
+-
+-	gpmi_send_data(this);
+-}
+-
+-static uint8_t gpmi_read_byte(struct mtd_info *mtd)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct gpmi_nand_data *this = nand_get_controller_data(chip);
+-	uint8_t *buf = this->data_buffer_dma;
+-
+-	gpmi_read_buf(mtd, buf, 1);
+-	return buf[0];
+-}
+-
+-/*
+- * Handles block mark swapping.
+- * It can be called in swapping the block mark, or swapping it back,
+- * because the the operations are the same.
+- */
+-static void block_mark_swapping(struct gpmi_nand_data *this,
+-				void *payload, void *auxiliary)
+-{
+-	struct bch_geometry *nfc_geo = &this->bch_geometry;
+-	unsigned char *p;
+-	unsigned char *a;
+-	unsigned int  bit;
+-	unsigned char mask;
+-	unsigned char from_data;
+-	unsigned char from_oob;
+-
+-	if (!this->swap_block_mark)
+-		return;
+-
+-	/*
+-	 * If control arrives here, we're swapping. Make some convenience
+-	 * variables.
+-	 */
+-	bit = nfc_geo->block_mark_bit_offset;
+-	p   = payload + nfc_geo->block_mark_byte_offset;
+-	a   = auxiliary;
+-
+-	/*
+-	 * Get the byte from the data area that overlays the block mark. Since
+-	 * the ECC engine applies its own view to the bits in the page, the
+-	 * physical block mark won't (in general) appear on a byte boundary in
+-	 * the data.
+-	 */
+-	from_data = (p[0] >> bit) | (p[1] << (8 - bit));
+-
+-	/* Get the byte from the OOB. */
+-	from_oob = a[0];
+-
+-	/* Swap them. */
+-	a[0] = from_data;
+-
+-	mask = (0x1 << bit) - 1;
+-	p[0] = (p[0] & mask) | (from_oob << bit);
+-
+-	mask = ~0 << bit;
+-	p[1] = (p[1] & mask) | (from_oob >> (8 - bit));
+-}
+-
+-static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
+-				uint8_t *buf, int oob_required, int page)
+-{
+-	struct gpmi_nand_data *this = nand_get_controller_data(chip);
+-	struct bch_geometry *nfc_geo = &this->bch_geometry;
+-	void          *payload_virt;
+-	dma_addr_t    payload_phys;
+-	void          *auxiliary_virt;
+-	dma_addr_t    auxiliary_phys;
+-	unsigned int  i;
+-	unsigned char *status;
+-	unsigned int  max_bitflips = 0;
+-	int           ret;
+-
+-	dev_dbg(this->dev, "page number is : %d\n", page);
+-	ret = read_page_prepare(this, buf, nfc_geo->payload_size,
+-					this->payload_virt, this->payload_phys,
+-					nfc_geo->payload_size,
+-					&payload_virt, &payload_phys);
+-	if (ret) {
+-		dev_err(this->dev, "Inadequate DMA buffer\n");
+-		ret = -ENOMEM;
+-		return ret;
+-	}
+-	auxiliary_virt = this->auxiliary_virt;
+-	auxiliary_phys = this->auxiliary_phys;
+-
+-	/* go! */
+-	ret = gpmi_read_page(this, payload_phys, auxiliary_phys);
+-	read_page_end(this, buf, nfc_geo->payload_size,
+-			this->payload_virt, this->payload_phys,
+-			nfc_geo->payload_size,
+-			payload_virt, payload_phys);
+-	if (ret) {
+-		dev_err(this->dev, "Error in ECC-based read: %d\n", ret);
+-		return ret;
+-	}
+-
+-	/* handle the block mark swapping */
+-	block_mark_swapping(this, payload_virt, auxiliary_virt);
+-
+-	/* Loop over status bytes, accumulating ECC status. */
+-	status = auxiliary_virt + nfc_geo->auxiliary_status_offset;
+-
+-	read_page_swap_end(this, buf, nfc_geo->payload_size,
+-			   this->payload_virt, this->payload_phys,
+-			   nfc_geo->payload_size,
+-			   payload_virt, payload_phys);
+-
+-	for (i = 0; i < nfc_geo->ecc_chunk_count; i++, status++) {
+-		if ((*status == STATUS_GOOD) || (*status == STATUS_ERASED))
+-			continue;
+-
+-		if (*status == STATUS_UNCORRECTABLE) {
+-			int eccbits = nfc_geo->ecc_strength * nfc_geo->gf_len;
+-			u8 *eccbuf = this->raw_buffer;
+-			int offset, bitoffset;
+-			int eccbytes;
+-			int flips;
+-
+-			/* Read ECC bytes into our internal raw_buffer */
+-			offset = nfc_geo->metadata_size * 8;
+-			offset += ((8 * nfc_geo->ecc_chunk_size) + eccbits) * (i + 1);
+-			offset -= eccbits;
+-			bitoffset = offset % 8;
+-			eccbytes = DIV_ROUND_UP(offset + eccbits, 8);
+-			offset /= 8;
+-			eccbytes -= offset;
+-			chip->cmdfunc(mtd, NAND_CMD_RNDOUT, offset, -1);
+-			chip->read_buf(mtd, eccbuf, eccbytes);
+-
+-			/*
+-			 * ECC data are not byte aligned and we may have
+-			 * in-band data in the first and last byte of
+-			 * eccbuf. Set non-eccbits to one so that
+-			 * nand_check_erased_ecc_chunk() does not count them
+-			 * as bitflips.
+-			 */
+-			if (bitoffset)
+-				eccbuf[0] |= GENMASK(bitoffset - 1, 0);
+-
+-			bitoffset = (bitoffset + eccbits) % 8;
+-			if (bitoffset)
+-				eccbuf[eccbytes - 1] |= GENMASK(7, bitoffset);
+-
+-			/*
+-			 * The ECC hardware has an uncorrectable ECC status
+-			 * code in case we have bitflips in an erased page. As
+-			 * nothing was written into this subpage the ECC is
+-			 * obviously wrong and we can not trust it. We assume
+-			 * at this point that we are reading an erased page and
+-			 * try to correct the bitflips in buffer up to
+-			 * ecc_strength bitflips. If this is a page with random
+-			 * data, we exceed this number of bitflips and have a
+-			 * ECC failure. Otherwise we use the corrected buffer.
+-			 */
+-			if (i == 0) {
+-				/* The first block includes metadata */
+-				flips = nand_check_erased_ecc_chunk(
+-						buf + i * nfc_geo->ecc_chunk_size,
+-						nfc_geo->ecc_chunk_size,
+-						eccbuf, eccbytes,
+-						auxiliary_virt,
+-						nfc_geo->metadata_size,
+-						nfc_geo->ecc_strength);
+-			} else {
+-				flips = nand_check_erased_ecc_chunk(
+-						buf + i * nfc_geo->ecc_chunk_size,
+-						nfc_geo->ecc_chunk_size,
+-						eccbuf, eccbytes,
+-						NULL, 0,
+-						nfc_geo->ecc_strength);
+-			}
+-
+-			if (flips > 0) {
+-				max_bitflips = max_t(unsigned int, max_bitflips,
+-						     flips);
+-				mtd->ecc_stats.corrected += flips;
+-				continue;
+-			}
+-
+-			mtd->ecc_stats.failed++;
+-			continue;
+-		}
+-
+-		mtd->ecc_stats.corrected += *status;
+-		max_bitflips = max_t(unsigned int, max_bitflips, *status);
+-	}
+-
+-	if (oob_required) {
+-		/*
+-		 * It's time to deliver the OOB bytes. See gpmi_ecc_read_oob()
+-		 * for details about our policy for delivering the OOB.
+-		 *
+-		 * We fill the caller's buffer with set bits, and then copy the
+-		 * block mark to th caller's buffer. Note that, if block mark
+-		 * swapping was necessary, it has already been done, so we can
+-		 * rely on the first byte of the auxiliary buffer to contain
+-		 * the block mark.
+-		 */
+-		memset(chip->oob_poi, ~0, mtd->oobsize);
+-		chip->oob_poi[0] = ((uint8_t *) auxiliary_virt)[0];
+-	}
+-
+-	return max_bitflips;
+-}
+-
+-/* Fake a virtual small page for the subpage read */
+-static int gpmi_ecc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
+-			uint32_t offs, uint32_t len, uint8_t *buf, int page)
+-{
+-	struct gpmi_nand_data *this = nand_get_controller_data(chip);
+-	void __iomem *bch_regs = this->resources.bch_regs;
+-	struct bch_geometry old_geo = this->bch_geometry;
+-	struct bch_geometry *geo = &this->bch_geometry;
+-	int size = chip->ecc.size; /* ECC chunk size */
+-	int meta, n, page_size;
+-	u32 r1_old, r2_old, r1_new, r2_new;
+-	unsigned int max_bitflips;
+-	int first, last, marker_pos;
+-	int ecc_parity_size;
+-	int col = 0;
+-	int old_swap_block_mark = this->swap_block_mark;
+-
+-	/* The size of ECC parity */
+-	ecc_parity_size = geo->gf_len * geo->ecc_strength / 8;
+-
+-	/* Align it with the chunk size */
+-	first = offs / size;
+-	last = (offs + len - 1) / size;
+-
+-	if (this->swap_block_mark) {
+-		/*
+-		 * Find the chunk which contains the Block Marker.
+-		 * If this chunk is in the range of [first, last],
+-		 * we have to read out the whole page.
+-		 * Why? since we had swapped the data at the position of Block
+-		 * Marker to the metadata which is bound with the chunk 0.
+-		 */
+-		marker_pos = geo->block_mark_byte_offset / size;
+-		if (last >= marker_pos && first <= marker_pos) {
+-			dev_dbg(this->dev,
+-				"page:%d, first:%d, last:%d, marker at:%d\n",
+-				page, first, last, marker_pos);
+-			return gpmi_ecc_read_page(mtd, chip, buf, 0, page);
+-		}
+-	}
+-
+-	meta = geo->metadata_size;
+-	if (first) {
+-		col = meta + (size + ecc_parity_size) * first;
+-		chip->cmdfunc(mtd, NAND_CMD_RNDOUT, col, -1);
+-
+-		meta = 0;
+-		buf = buf + first * size;
+-	}
+-
+-	/* Save the old environment */
+-	r1_old = r1_new = readl(bch_regs + HW_BCH_FLASH0LAYOUT0);
+-	r2_old = r2_new = readl(bch_regs + HW_BCH_FLASH0LAYOUT1);
+-
+-	/* change the BCH registers and bch_geometry{} */
+-	n = last - first + 1;
+-	page_size = meta + (size + ecc_parity_size) * n;
+-
+-	r1_new &= ~(BM_BCH_FLASH0LAYOUT0_NBLOCKS |
+-			BM_BCH_FLASH0LAYOUT0_META_SIZE);
+-	r1_new |= BF_BCH_FLASH0LAYOUT0_NBLOCKS(n - 1)
+-			| BF_BCH_FLASH0LAYOUT0_META_SIZE(meta);
+-	writel(r1_new, bch_regs + HW_BCH_FLASH0LAYOUT0);
+-
+-	r2_new &= ~BM_BCH_FLASH0LAYOUT1_PAGE_SIZE;
+-	r2_new |= BF_BCH_FLASH0LAYOUT1_PAGE_SIZE(page_size);
+-	writel(r2_new, bch_regs + HW_BCH_FLASH0LAYOUT1);
+-
+-	geo->ecc_chunk_count = n;
+-	geo->payload_size = n * size;
+-	geo->page_size = page_size;
+-	geo->auxiliary_status_offset = ALIGN(meta, 4);
+-
+-	dev_dbg(this->dev, "page:%d(%d:%d)%d, chunk:(%d:%d), BCH PG size:%d\n",
+-		page, offs, len, col, first, n, page_size);
+-
+-	/* Read the subpage now */
+-	this->swap_block_mark = false;
+-	max_bitflips = gpmi_ecc_read_page(mtd, chip, buf, 0, page);
+-
+-	/* Restore */
+-	writel(r1_old, bch_regs + HW_BCH_FLASH0LAYOUT0);
+-	writel(r2_old, bch_regs + HW_BCH_FLASH0LAYOUT1);
+-	this->bch_geometry = old_geo;
+-	this->swap_block_mark = old_swap_block_mark;
+-
+-	return max_bitflips;
+-}
+-
+-static int gpmi_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
+-				const uint8_t *buf, int oob_required, int page)
+-{
+-	struct gpmi_nand_data *this = nand_get_controller_data(chip);
+-	struct bch_geometry *nfc_geo = &this->bch_geometry;
+-	const void *payload_virt;
+-	dma_addr_t payload_phys;
+-	const void *auxiliary_virt;
+-	dma_addr_t auxiliary_phys;
+-	int        ret;
+-
+-	dev_dbg(this->dev, "ecc write page.\n");
+-	if (this->swap_block_mark) {
+-		/*
+-		 * If control arrives here, we're doing block mark swapping.
+-		 * Since we can't modify the caller's buffers, we must copy them
+-		 * into our own.
+-		 */
+-		memcpy(this->payload_virt, buf, mtd->writesize);
+-		payload_virt = this->payload_virt;
+-		payload_phys = this->payload_phys;
+-
+-		memcpy(this->auxiliary_virt, chip->oob_poi,
+-				nfc_geo->auxiliary_size);
+-		auxiliary_virt = this->auxiliary_virt;
+-		auxiliary_phys = this->auxiliary_phys;
+-
+-		/* Handle block mark swapping. */
+-		block_mark_swapping(this,
+-				(void *)payload_virt, (void *)auxiliary_virt);
+-	} else {
+-		/*
+-		 * If control arrives here, we're not doing block mark swapping,
+-		 * so we can to try and use the caller's buffers.
+-		 */
+-		ret = send_page_prepare(this,
+-				buf, mtd->writesize,
+-				this->payload_virt, this->payload_phys,
+-				nfc_geo->payload_size,
+-				&payload_virt, &payload_phys);
+-		if (ret) {
+-			dev_err(this->dev, "Inadequate payload DMA buffer\n");
+-			return 0;
+-		}
+-
+-		ret = send_page_prepare(this,
+-				chip->oob_poi, mtd->oobsize,
+-				this->auxiliary_virt, this->auxiliary_phys,
+-				nfc_geo->auxiliary_size,
+-				&auxiliary_virt, &auxiliary_phys);
+-		if (ret) {
+-			dev_err(this->dev, "Inadequate auxiliary DMA buffer\n");
+-			goto exit_auxiliary;
+-		}
+-	}
+-
+-	/* Ask the NFC. */
+-	ret = gpmi_send_page(this, payload_phys, auxiliary_phys);
+-	if (ret)
+-		dev_err(this->dev, "Error in ECC-based write: %d\n", ret);
+-
+-	if (!this->swap_block_mark) {
+-		send_page_end(this, chip->oob_poi, mtd->oobsize,
+-				this->auxiliary_virt, this->auxiliary_phys,
+-				nfc_geo->auxiliary_size,
+-				auxiliary_virt, auxiliary_phys);
+-exit_auxiliary:
+-		send_page_end(this, buf, mtd->writesize,
+-				this->payload_virt, this->payload_phys,
+-				nfc_geo->payload_size,
+-				payload_virt, payload_phys);
+-	}
+-
+-	return 0;
+-}
+-
+-/*
+- * There are several places in this driver where we have to handle the OOB and
+- * block marks. This is the function where things are the most complicated, so
+- * this is where we try to explain it all. All the other places refer back to
+- * here.
+- *
+- * These are the rules, in order of decreasing importance:
+- *
+- * 1) Nothing the caller does can be allowed to imperil the block mark.
+- *
+- * 2) In read operations, the first byte of the OOB we return must reflect the
+- *    true state of the block mark, no matter where that block mark appears in
+- *    the physical page.
+- *
+- * 3) ECC-based read operations return an OOB full of set bits (since we never
+- *    allow ECC-based writes to the OOB, it doesn't matter what ECC-based reads
+- *    return).
+- *
+- * 4) "Raw" read operations return a direct view of the physical bytes in the
+- *    page, using the conventional definition of which bytes are data and which
+- *    are OOB. This gives the caller a way to see the actual, physical bytes
+- *    in the page, without the distortions applied by our ECC engine.
+- *
+- *
+- * What we do for this specific read operation depends on two questions:
+- *
+- * 1) Are we doing a "raw" read, or an ECC-based read?
+- *
+- * 2) Are we using block mark swapping or transcription?
+- *
+- * There are four cases, illustrated by the following Karnaugh map:
+- *
+- *                    |           Raw           |         ECC-based       |
+- *       -------------+-------------------------+-------------------------+
+- *                    | Read the conventional   |                         |
+- *                    | OOB at the end of the   |                         |
+- *       Swapping     | page and return it. It  |                         |
+- *                    | contains exactly what   |                         |
+- *                    | we want.                | Read the block mark and |
+- *       -------------+-------------------------+ return it in a buffer   |
+- *                    | Read the conventional   | full of set bits.       |
+- *                    | OOB at the end of the   |                         |
+- *                    | page and also the block |                         |
+- *       Transcribing | mark in the metadata.   |                         |
+- *                    | Copy the block mark     |                         |
+- *                    | into the first byte of  |                         |
+- *                    | the OOB.                |                         |
+- *       -------------+-------------------------+-------------------------+
+- *
+- * Note that we break rule #4 in the Transcribing/Raw case because we're not
+- * giving an accurate view of the actual, physical bytes in the page (we're
+- * overwriting the block mark). That's OK because it's more important to follow
+- * rule #2.
+- *
+- * It turns out that knowing whether we want an "ECC-based" or "raw" read is not
+- * easy. When reading a page, for example, the NAND Flash MTD code calls our
+- * ecc.read_page or ecc.read_page_raw function. Thus, the fact that MTD wants an
+- * ECC-based or raw view of the page is implicit in which function it calls
+- * (there is a similar pair of ECC-based/raw functions for writing).
+- */
+-static int gpmi_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
+-				int page)
+-{
+-	struct gpmi_nand_data *this = nand_get_controller_data(chip);
+-
+-	dev_dbg(this->dev, "page number is %d\n", page);
+-	/* clear the OOB buffer */
+-	memset(chip->oob_poi, ~0, mtd->oobsize);
+-
+-	/* Read out the conventional OOB. */
+-	chip->cmdfunc(mtd, NAND_CMD_READ0, mtd->writesize, page);
+-	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+-
+-	/*
+-	 * Now, we want to make sure the block mark is correct. In the
+-	 * non-transcribing case (!GPMI_IS_MX23()), we already have it.
+-	 * Otherwise, we need to explicitly read it.
+-	 */
+-	if (GPMI_IS_MX23(this)) {
+-		/* Read the block mark into the first byte of the OOB buffer. */
+-		chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
+-		chip->oob_poi[0] = chip->read_byte(mtd);
+-	}
+-
+-	return 0;
+-}
+-
+-static int
+-gpmi_ecc_write_oob(struct mtd_info *mtd, struct nand_chip *chip, int page)
+-{
+-	struct mtd_oob_region of = { };
+-	int status = 0;
+-
+-	/* Do we have available oob area? */
+-	mtd_ooblayout_free(mtd, 0, &of);
+-	if (!of.length)
+-		return -EPERM;
+-
+-	if (!nand_is_slc(chip))
+-		return -EPERM;
+-
+-	chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize + of.offset, page);
+-	chip->write_buf(mtd, chip->oob_poi + of.offset, of.length);
+-	chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+-
+-	status = chip->waitfunc(mtd, chip);
+-	return status & NAND_STATUS_FAIL ? -EIO : 0;
+-}
+-
+-/*
+- * This function reads a NAND page without involving the ECC engine (no HW
+- * ECC correction).
+- * The tricky part in the GPMI/BCH controller is that it stores ECC bits
+- * inline (interleaved with payload DATA), and do not align data chunk on
+- * byte boundaries.
+- * We thus need to take care moving the payload data and ECC bits stored in the
+- * page into the provided buffers, which is why we're using gpmi_copy_bits.
+- *
+- * See set_geometry_by_ecc_info inline comments to have a full description
+- * of the layout used by the GPMI controller.
+- */
+-static int gpmi_ecc_read_page_raw(struct mtd_info *mtd,
+-				  struct nand_chip *chip, uint8_t *buf,
+-				  int oob_required, int page)
+-{
+-	struct gpmi_nand_data *this = nand_get_controller_data(chip);
+-	struct bch_geometry *nfc_geo = &this->bch_geometry;
+-	int eccsize = nfc_geo->ecc_chunk_size;
+-	int eccbits = nfc_geo->ecc_strength * nfc_geo->gf_len;
+-	u8 *tmp_buf = this->raw_buffer;
+-	size_t src_bit_off;
+-	size_t oob_bit_off;
+-	size_t oob_byte_off;
+-	uint8_t *oob = chip->oob_poi;
+-	int step;
+-
+-	chip->read_buf(mtd, tmp_buf,
+-		       mtd->writesize + mtd->oobsize);
+-
+-	/*
+-	 * If required, swap the bad block marker and the data stored in the
+-	 * metadata section, so that we don't wrongly consider a block as bad.
+-	 *
+-	 * See the layout description for a detailed explanation on why this
+-	 * is needed.
+-	 */
+-	if (this->swap_block_mark) {
+-		u8 swap = tmp_buf[0];
+-
+-		tmp_buf[0] = tmp_buf[mtd->writesize];
+-		tmp_buf[mtd->writesize] = swap;
+-	}
+-
+-	/*
+-	 * Copy the metadata section into the oob buffer (this section is
+-	 * guaranteed to be aligned on a byte boundary).
+-	 */
+-	if (oob_required)
+-		memcpy(oob, tmp_buf, nfc_geo->metadata_size);
+-
+-	oob_bit_off = nfc_geo->metadata_size * 8;
+-	src_bit_off = oob_bit_off;
+-
+-	/* Extract interleaved payload data and ECC bits */
+-	for (step = 0; step < nfc_geo->ecc_chunk_count; step++) {
+-		if (buf)
+-			gpmi_copy_bits(buf, step * eccsize * 8,
+-				       tmp_buf, src_bit_off,
+-				       eccsize * 8);
+-		src_bit_off += eccsize * 8;
+-
+-		/* Align last ECC block to align a byte boundary */
+-		if (step == nfc_geo->ecc_chunk_count - 1 &&
+-		    (oob_bit_off + eccbits) % 8)
+-			eccbits += 8 - ((oob_bit_off + eccbits) % 8);
+-
+-		if (oob_required)
+-			gpmi_copy_bits(oob, oob_bit_off,
+-				       tmp_buf, src_bit_off,
+-				       eccbits);
+-
+-		src_bit_off += eccbits;
+-		oob_bit_off += eccbits;
+-	}
+-
+-	if (oob_required) {
+-		oob_byte_off = oob_bit_off / 8;
+-
+-		if (oob_byte_off < mtd->oobsize)
+-			memcpy(oob + oob_byte_off,
+-			       tmp_buf + mtd->writesize + oob_byte_off,
+-			       mtd->oobsize - oob_byte_off);
+-	}
+-
+-	return 0;
+-}
+-
+-/*
+- * This function writes a NAND page without involving the ECC engine (no HW
+- * ECC generation).
+- * The tricky part in the GPMI/BCH controller is that it stores ECC bits
+- * inline (interleaved with payload DATA), and do not align data chunk on
+- * byte boundaries.
+- * We thus need to take care moving the OOB area at the right place in the
+- * final page, which is why we're using gpmi_copy_bits.
+- *
+- * See set_geometry_by_ecc_info inline comments to have a full description
+- * of the layout used by the GPMI controller.
+- */
+-static int gpmi_ecc_write_page_raw(struct mtd_info *mtd,
+-				   struct nand_chip *chip,
+-				   const uint8_t *buf,
+-				   int oob_required, int page)
+-{
+-	struct gpmi_nand_data *this = nand_get_controller_data(chip);
+-	struct bch_geometry *nfc_geo = &this->bch_geometry;
+-	int eccsize = nfc_geo->ecc_chunk_size;
+-	int eccbits = nfc_geo->ecc_strength * nfc_geo->gf_len;
+-	u8 *tmp_buf = this->raw_buffer;
+-	uint8_t *oob = chip->oob_poi;
+-	size_t dst_bit_off;
+-	size_t oob_bit_off;
+-	size_t oob_byte_off;
+-	int step;
+-
+-	/*
+-	 * Initialize all bits to 1 in case we don't have a buffer for the
+-	 * payload or oob data in order to leave unspecified bits of data
+-	 * to their initial state.
+-	 */
+-	if (!buf || !oob_required)
+-		memset(tmp_buf, 0xff, mtd->writesize + mtd->oobsize);
+-
+-	/*
+-	 * First copy the metadata section (stored in oob buffer) at the
+-	 * beginning of the page, as imposed by the GPMI layout.
+-	 */
+-	memcpy(tmp_buf, oob, nfc_geo->metadata_size);
+-	oob_bit_off = nfc_geo->metadata_size * 8;
+-	dst_bit_off = oob_bit_off;
+-
+-	/* Interleave payload data and ECC bits */
+-	for (step = 0; step < nfc_geo->ecc_chunk_count; step++) {
+-		if (buf)
+-			gpmi_copy_bits(tmp_buf, dst_bit_off,
+-				       buf, step * eccsize * 8, eccsize * 8);
+-		dst_bit_off += eccsize * 8;
+-
+-		/* Align last ECC block to align a byte boundary */
+-		if (step == nfc_geo->ecc_chunk_count - 1 &&
+-		    (oob_bit_off + eccbits) % 8)
+-			eccbits += 8 - ((oob_bit_off + eccbits) % 8);
+-
+-		if (oob_required)
+-			gpmi_copy_bits(tmp_buf, dst_bit_off,
+-				       oob, oob_bit_off, eccbits);
+-
+-		dst_bit_off += eccbits;
+-		oob_bit_off += eccbits;
+-	}
+-
+-	oob_byte_off = oob_bit_off / 8;
+-
+-	if (oob_required && oob_byte_off < mtd->oobsize)
+-		memcpy(tmp_buf + mtd->writesize + oob_byte_off,
+-		       oob + oob_byte_off, mtd->oobsize - oob_byte_off);
+-
+-	/*
+-	 * If required, swap the bad block marker and the first byte of the
+-	 * metadata section, so that we don't modify the bad block marker.
+-	 *
+-	 * See the layout description for a detailed explanation on why this
+-	 * is needed.
+-	 */
+-	if (this->swap_block_mark) {
+-		u8 swap = tmp_buf[0];
+-
+-		tmp_buf[0] = tmp_buf[mtd->writesize];
+-		tmp_buf[mtd->writesize] = swap;
+-	}
+-
+-	chip->write_buf(mtd, tmp_buf, mtd->writesize + mtd->oobsize);
+-
+-	return 0;
+-}
+-
+-static int gpmi_ecc_read_oob_raw(struct mtd_info *mtd, struct nand_chip *chip,
+-				 int page)
+-{
+-	chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
+-
+-	return gpmi_ecc_read_page_raw(mtd, chip, NULL, 1, page);
+-}
+-
+-static int gpmi_ecc_write_oob_raw(struct mtd_info *mtd, struct nand_chip *chip,
+-				 int page)
+-{
+-	chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0, page);
+-
+-	return gpmi_ecc_write_page_raw(mtd, chip, NULL, 1, page);
+-}
+-
+-static int gpmi_block_markbad(struct mtd_info *mtd, loff_t ofs)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct gpmi_nand_data *this = nand_get_controller_data(chip);
+-	int ret = 0;
+-	uint8_t *block_mark;
+-	int column, page, status, chipnr;
+-
+-	chipnr = (int)(ofs >> chip->chip_shift);
+-	chip->select_chip(mtd, chipnr);
+-
+-	column = !GPMI_IS_MX23(this) ? mtd->writesize : 0;
+-
+-	/* Write the block mark. */
+-	block_mark = this->data_buffer_dma;
+-	block_mark[0] = 0; /* bad block marker */
+-
+-	/* Shift to get page */
+-	page = (int)(ofs >> chip->page_shift);
+-
+-	chip->cmdfunc(mtd, NAND_CMD_SEQIN, column, page);
+-	chip->write_buf(mtd, block_mark, 1);
+-	chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+-
+-	status = chip->waitfunc(mtd, chip);
+-	if (status & NAND_STATUS_FAIL)
+-		ret = -EIO;
+-
+-	chip->select_chip(mtd, -1);
+-
+-	return ret;
+-}
+-
+-static int nand_boot_set_geometry(struct gpmi_nand_data *this)
+-{
+-	struct boot_rom_geometry *geometry = &this->rom_geometry;
+-
+-	/*
+-	 * Set the boot block stride size.
+-	 *
+-	 * In principle, we should be reading this from the OTP bits, since
+-	 * that's where the ROM is going to get it. In fact, we don't have any
+-	 * way to read the OTP bits, so we go with the default and hope for the
+-	 * best.
+-	 */
+-	geometry->stride_size_in_pages = 64;
+-
+-	/*
+-	 * Set the search area stride exponent.
+-	 *
+-	 * In principle, we should be reading this from the OTP bits, since
+-	 * that's where the ROM is going to get it. In fact, we don't have any
+-	 * way to read the OTP bits, so we go with the default and hope for the
+-	 * best.
+-	 */
+-	geometry->search_area_stride_exponent = 2;
+-	return 0;
+-}
+-
+-static const char  *fingerprint = "STMP";
+-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);
+-	unsigned int search_area_size_in_strides;
+-	unsigned int stride;
+-	unsigned int page;
+-	uint8_t *buffer = chip->buffers->databuf;
+-	int saved_chip_number;
+-	int found_an_ncb_fingerprint = false;
+-
+-	/* Compute the number of strides in a search area. */
+-	search_area_size_in_strides = 1 << rom_geo->search_area_stride_exponent;
+-
+-	saved_chip_number = this->current_chip;
+-	chip->select_chip(mtd, 0);
+-
+-	/*
+-	 * Loop through the first search area, looking for the NCB fingerprint.
+-	 */
+-	dev_dbg(dev, "Scanning for an NCB fingerprint...\n");
+-
+-	for (stride = 0; stride < search_area_size_in_strides; stride++) {
+-		/* Compute the page addresses. */
+-		page = stride * rom_geo->stride_size_in_pages;
+-
+-		dev_dbg(dev, "Looking for a fingerprint in page 0x%x\n", page);
+-
+-		/*
+-		 * Read the NCB fingerprint. The fingerprint is four bytes long
+-		 * and starts in the 12th byte of the page.
+-		 */
+-		chip->cmdfunc(mtd, NAND_CMD_READ0, 12, page);
+-		chip->read_buf(mtd, buffer, strlen(fingerprint));
+-
+-		/* Look for the fingerprint. */
+-		if (!memcmp(buffer, fingerprint, strlen(fingerprint))) {
+-			found_an_ncb_fingerprint = true;
+-			break;
+-		}
+-
+-	}
+-
+-	chip->select_chip(mtd, saved_chip_number);
+-
+-	if (found_an_ncb_fingerprint)
+-		dev_dbg(dev, "\tFound a fingerprint\n");
+-	else
+-		dev_dbg(dev, "\tNo fingerprint found\n");
+-	return found_an_ncb_fingerprint;
+-}
+-
+-/* Writes a transcription stamp. */
+-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);
+-	unsigned int block_size_in_pages;
+-	unsigned int search_area_size_in_strides;
+-	unsigned int search_area_size_in_pages;
+-	unsigned int search_area_size_in_blocks;
+-	unsigned int block;
+-	unsigned int stride;
+-	unsigned int page;
+-	uint8_t      *buffer = chip->buffers->databuf;
+-	int saved_chip_number;
+-	int status;
+-
+-	/* Compute the search area geometry. */
+-	block_size_in_pages = mtd->erasesize / mtd->writesize;
+-	search_area_size_in_strides = 1 << rom_geo->search_area_stride_exponent;
+-	search_area_size_in_pages = search_area_size_in_strides *
+-					rom_geo->stride_size_in_pages;
+-	search_area_size_in_blocks =
+-		  (search_area_size_in_pages + (block_size_in_pages - 1)) /
+-				    block_size_in_pages;
+-
+-	dev_dbg(dev, "Search Area Geometry :\n");
+-	dev_dbg(dev, "\tin Blocks : %u\n", search_area_size_in_blocks);
+-	dev_dbg(dev, "\tin Strides: %u\n", search_area_size_in_strides);
+-	dev_dbg(dev, "\tin Pages  : %u\n", search_area_size_in_pages);
+-
+-	/* Select chip 0. */
+-	saved_chip_number = this->current_chip;
+-	chip->select_chip(mtd, 0);
+-
+-	/* Loop over blocks in the first search area, erasing them. */
+-	dev_dbg(dev, "Erasing the search area...\n");
+-
+-	for (block = 0; block < search_area_size_in_blocks; block++) {
+-		/* Compute the page address. */
+-		page = block * block_size_in_pages;
+-
+-		/* Erase this block. */
+-		dev_dbg(dev, "\tErasing block 0x%x\n", block);
+-		chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page);
+-		chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1);
+-
+-		/* Wait for the erase to finish. */
+-		status = chip->waitfunc(mtd, chip);
+-		if (status & NAND_STATUS_FAIL)
+-			dev_err(dev, "[%s] Erase failed.\n", __func__);
+-	}
+-
+-	/* Write the NCB fingerprint into the page buffer. */
+-	memset(buffer, ~0, mtd->writesize);
+-	memcpy(buffer + 12, fingerprint, strlen(fingerprint));
+-
+-	/* Loop through the first search area, writing NCB fingerprints. */
+-	dev_dbg(dev, "Writing NCB fingerprints...\n");
+-	for (stride = 0; stride < search_area_size_in_strides; stride++) {
+-		/* Compute the page addresses. */
+-		page = stride * rom_geo->stride_size_in_pages;
+-
+-		/* Write the first page of the current stride. */
+-		dev_dbg(dev, "Writing an NCB fingerprint in page 0x%x\n", page);
+-		chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
+-		chip->ecc.write_page_raw(mtd, chip, buffer, 0, page);
+-		chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+-
+-		/* Wait for the write to finish. */
+-		status = chip->waitfunc(mtd, chip);
+-		if (status & NAND_STATUS_FAIL)
+-			dev_err(dev, "[%s] Write failed.\n", __func__);
+-	}
+-
+-	/* Deselect chip 0. */
+-	chip->select_chip(mtd, saved_chip_number);
+-	return 0;
+-}
+-
+-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);
+-	unsigned int block_count;
+-	unsigned int block;
+-	int     chipnr;
+-	int     page;
+-	loff_t  byte;
+-	uint8_t block_mark;
+-	int     ret = 0;
+-
+-	/*
+-	 * If control arrives here, we can't use block mark swapping, which
+-	 * means we're forced to use transcription. First, scan for the
+-	 * transcription stamp. If we find it, then we don't have to do
+-	 * anything -- the block marks are already transcribed.
+-	 */
+-	if (mx23_check_transcription_stamp(this))
+-		return 0;
+-
+-	/*
+-	 * If control arrives here, we couldn't find a transcription stamp, so
+-	 * so we presume the block marks are in the conventional location.
+-	 */
+-	dev_dbg(dev, "Transcribing bad block marks...\n");
+-
+-	/* Compute the number of blocks in the entire medium. */
+-	block_count = chip->chipsize >> chip->phys_erase_shift;
+-
+-	/*
+-	 * Loop over all the blocks in the medium, transcribing block marks as
+-	 * we go.
+-	 */
+-	for (block = 0; block < block_count; block++) {
+-		/*
+-		 * Compute the chip, page and byte addresses for this block's
+-		 * conventional mark.
+-		 */
+-		chipnr = block >> (chip->chip_shift - chip->phys_erase_shift);
+-		page = block << (chip->phys_erase_shift - chip->page_shift);
+-		byte = block <<  chip->phys_erase_shift;
+-
+-		/* Send the command to read the conventional block mark. */
+-		chip->select_chip(mtd, chipnr);
+-		chip->cmdfunc(mtd, NAND_CMD_READ0, mtd->writesize, page);
+-		block_mark = chip->read_byte(mtd);
+-		chip->select_chip(mtd, -1);
+-
+-		/*
+-		 * Check if the block is marked bad. If so, we need to mark it
+-		 * again, but this time the result will be a mark in the
+-		 * location where we transcribe block marks.
+-		 */
+-		if (block_mark != 0xff) {
+-			dev_dbg(dev, "Transcribing mark in block %u\n", block);
+-			ret = chip->block_markbad(mtd, byte);
+-			if (ret)
+-				dev_err(dev,
+-					"Failed to mark block bad with ret %d\n",
+-					ret);
+-		}
+-	}
+-
+-	/* Write the stamp that indicates we've transcribed the block marks. */
+-	mx23_write_transcription_stamp(this);
+-	return 0;
+-}
+-
+-static int nand_boot_init(struct gpmi_nand_data  *this)
+-{
+-	nand_boot_set_geometry(this);
+-
+-	/* This is ROM arch-specific initilization before the BBT scanning. */
+-	if (GPMI_IS_MX23(this))
+-		return mx23_boot_init(this);
+-	return 0;
+-}
+-
+-static int gpmi_set_geometry(struct gpmi_nand_data *this)
+-{
+-	int ret;
+-
+-	/* Free the temporary DMA memory for reading ID. */
+-	gpmi_free_dma_buffer(this);
+-
+-	/* Set up the NFC geometry which is used by BCH. */
+-	ret = bch_set_geometry(this);
+-	if (ret) {
+-		dev_err(this->dev, "Error setting BCH geometry : %d\n", ret);
+-		return ret;
+-	}
+-
+-	/* Alloc the new DMA buffers according to the pagesize and oobsize */
+-	return gpmi_alloc_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 nand_ecc_ctrl *ecc = &chip->ecc;
+-	struct bch_geometry *bch_geo = &this->bch_geometry;
+-	int ret;
+-
+-	/* Set up the medium geometry */
+-	ret = gpmi_set_geometry(this);
+-	if (ret)
+-		return ret;
+-
+-	/* Init the nand_ecc_ctrl{} */
+-	ecc->read_page	= gpmi_ecc_read_page;
+-	ecc->write_page	= gpmi_ecc_write_page;
+-	ecc->read_oob	= gpmi_ecc_read_oob;
+-	ecc->write_oob	= gpmi_ecc_write_oob;
+-	ecc->read_page_raw = gpmi_ecc_read_page_raw;
+-	ecc->write_page_raw = gpmi_ecc_write_page_raw;
+-	ecc->read_oob_raw = gpmi_ecc_read_oob_raw;
+-	ecc->write_oob_raw = gpmi_ecc_write_oob_raw;
+-	ecc->mode	= NAND_ECC_HW;
+-	ecc->size	= bch_geo->ecc_chunk_size;
+-	ecc->strength	= bch_geo->ecc_strength;
+-	mtd_set_ooblayout(mtd, &gpmi_ooblayout_ops);
+-
+-	/*
+-	 * We only enable the subpage read when:
+-	 *  (1) the chip is imx6, and
+-	 *  (2) the size of the ECC parity is byte aligned.
+-	 */
+-	if (GPMI_IS_MX6(this) &&
+-		((bch_geo->gf_len * bch_geo->ecc_strength) % 8) == 0) {
+-		ecc->read_subpage = gpmi_ecc_read_subpage;
+-		chip->options |= NAND_SUBPAGE_READ;
+-	}
+-
+-	/*
+-	 * Can we enable the extra features? such as EDO or Sync mode.
+-	 *
+-	 * We do not check the return value now. That's means if we fail in
+-	 * enable the extra features, we still can run in the normal way.
+-	 */
+-	gpmi_extra_init(this);
+-
+-	return 0;
+-}
+-
+-static int gpmi_nand_init(struct gpmi_nand_data *this)
+-{
+-	struct nand_chip *chip = &this->nand;
+-	struct mtd_info  *mtd = nand_to_mtd(chip);
+-	int ret;
+-
+-	/* init current chip */
+-	this->current_chip	= -1;
+-
+-	/* init the MTD data structures */
+-	mtd->name		= "gpmi-nand";
+-	mtd->dev.parent		= this->dev;
+-
+-	/* init the nand_chip{}, we don't support a 16-bit NAND Flash bus. */
+-	nand_set_controller_data(chip, this);
+-	nand_set_flash_node(chip, this->pdev->dev.of_node);
+-	chip->select_chip	= gpmi_select_chip;
+-	chip->cmd_ctrl		= gpmi_cmd_ctrl;
+-	chip->dev_ready		= gpmi_dev_ready;
+-	chip->read_byte		= gpmi_read_byte;
+-	chip->read_buf		= gpmi_read_buf;
+-	chip->write_buf		= gpmi_write_buf;
+-	chip->badblock_pattern	= &gpmi_bbt_descr;
+-	chip->block_markbad	= gpmi_block_markbad;
+-	chip->options		|= NAND_NO_SUBPAGE_WRITE;
+-
+-	/* Set up swap_block_mark, must be set before the gpmi_set_geometry() */
+-	this->swap_block_mark = !GPMI_IS_MX23(this);
+-
+-	/*
+-	 * Allocate a temporary DMA buffer for reading ID in the
+-	 * nand_scan_ident().
+-	 */
+-	this->bch_geometry.payload_size = 1024;
+-	this->bch_geometry.auxiliary_size = 128;
+-	ret = gpmi_alloc_dma_buffer(this);
+-	if (ret)
+-		goto err_out;
+-
+-	ret = nand_scan_ident(mtd, GPMI_IS_MX6(this) ? 2 : 1, NULL);
+-	if (ret)
+-		goto err_out;
+-
+-	if (chip->bbt_options & NAND_BBT_USE_FLASH) {
+-		chip->bbt_options |= NAND_BBT_NO_OOB;
+-
+-		if (of_property_read_bool(this->dev->of_node,
+-						"fsl,no-blockmark-swap"))
+-			this->swap_block_mark = false;
+-	}
+-	dev_dbg(this->dev, "Blockmark swapping %sabled\n",
+-		this->swap_block_mark ? "en" : "dis");
+-
+-	ret = gpmi_init_last(this);
+-	if (ret)
+-		goto err_out;
+-
+-	chip->options |= NAND_SKIP_BBTSCAN;
+-	ret = nand_scan_tail(mtd);
+-	if (ret)
+-		goto err_out;
+-
+-	ret = nand_boot_init(this);
+-	if (ret)
+-		goto err_nand_cleanup;
+-	ret = chip->scan_bbt(mtd);
+-	if (ret)
+-		goto err_nand_cleanup;
+-
+-	ret = mtd_device_register(mtd, NULL, 0);
+-	if (ret)
+-		goto err_nand_cleanup;
+-	return 0;
+-
+-err_nand_cleanup:
+-	nand_cleanup(chip);
+-err_out:
+-	gpmi_free_dma_buffer(this);
+-	return ret;
+-}
+-
+-static const struct of_device_id gpmi_nand_id_table[] = {
+-	{
+-		.compatible = "fsl,imx23-gpmi-nand",
+-		.data = &gpmi_devdata_imx23,
+-	}, {
+-		.compatible = "fsl,imx28-gpmi-nand",
+-		.data = &gpmi_devdata_imx28,
+-	}, {
+-		.compatible = "fsl,imx6q-gpmi-nand",
+-		.data = &gpmi_devdata_imx6q,
+-	}, {
+-		.compatible = "fsl,imx6sx-gpmi-nand",
+-		.data = &gpmi_devdata_imx6sx,
+-	}, {
+-		.compatible = "fsl,imx7d-gpmi-nand",
+-		.data = &gpmi_devdata_imx7d,
+-	}, {}
+-};
+-MODULE_DEVICE_TABLE(of, gpmi_nand_id_table);
+-
+-static int gpmi_nand_probe(struct platform_device *pdev)
+-{
+-	struct gpmi_nand_data *this;
+-	const struct of_device_id *of_id;
+-	int ret;
+-
+-	this = devm_kzalloc(&pdev->dev, sizeof(*this), GFP_KERNEL);
+-	if (!this)
+-		return -ENOMEM;
+-
+-	of_id = of_match_device(gpmi_nand_id_table, &pdev->dev);
+-	if (of_id) {
+-		this->devdata = of_id->data;
+-	} else {
+-		dev_err(&pdev->dev, "Failed to find the right device id.\n");
+-		return -ENODEV;
+-	}
+-
+-	platform_set_drvdata(pdev, this);
+-	this->pdev  = pdev;
+-	this->dev   = &pdev->dev;
+-
+-	ret = acquire_resources(this);
+-	if (ret)
+-		goto exit_acquire_resources;
+-
+-	ret = init_hardware(this);
+-	if (ret)
+-		goto exit_nfc_init;
+-
+-	ret = gpmi_nand_init(this);
+-	if (ret)
+-		goto exit_nfc_init;
+-
+-	dev_info(this->dev, "driver registered.\n");
+-
+-	return 0;
+-
+-exit_nfc_init:
+-	release_resources(this);
+-exit_acquire_resources:
+-
+-	return ret;
+-}
+-
+-static int gpmi_nand_remove(struct platform_device *pdev)
+-{
+-	struct gpmi_nand_data *this = platform_get_drvdata(pdev);
+-
+-	nand_release(nand_to_mtd(&this->nand));
+-	gpmi_free_dma_buffer(this);
+-	release_resources(this);
+-	return 0;
+-}
+-
+-#ifdef CONFIG_PM_SLEEP
+-static int gpmi_pm_suspend(struct device *dev)
+-{
+-	struct gpmi_nand_data *this = dev_get_drvdata(dev);
+-
+-	release_dma_channels(this);
+-	return 0;
+-}
+-
+-static int gpmi_pm_resume(struct device *dev)
+-{
+-	struct gpmi_nand_data *this = dev_get_drvdata(dev);
+-	int ret;
+-
+-	ret = acquire_dma_channels(this);
+-	if (ret < 0)
+-		return ret;
+-
+-	/* re-init the GPMI registers */
+-	this->flags &= ~GPMI_TIMING_INIT_OK;
+-	ret = gpmi_init(this);
+-	if (ret) {
+-		dev_err(this->dev, "Error setting GPMI : %d\n", ret);
+-		return ret;
+-	}
+-
+-	/* re-init the BCH registers */
+-	ret = bch_set_geometry(this);
+-	if (ret) {
+-		dev_err(this->dev, "Error setting BCH : %d\n", ret);
+-		return ret;
+-	}
+-
+-	/* re-init others */
+-	gpmi_extra_init(this);
+-
+-	return 0;
+-}
+-#endif /* CONFIG_PM_SLEEP */
+-
+-static const struct dev_pm_ops gpmi_pm_ops = {
+-	SET_SYSTEM_SLEEP_PM_OPS(gpmi_pm_suspend, gpmi_pm_resume)
+-};
+-
+-static struct platform_driver gpmi_nand_driver = {
+-	.driver = {
+-		.name = "gpmi-nand",
+-		.pm = &gpmi_pm_ops,
+-		.of_match_table = gpmi_nand_id_table,
+-	},
+-	.probe   = gpmi_nand_probe,
+-	.remove  = gpmi_nand_remove,
+-};
+-module_platform_driver(gpmi_nand_driver);
+-
+-MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+-MODULE_DESCRIPTION("i.MX GPMI NAND Flash Controller Driver");
+-MODULE_LICENSE("GPL");
+diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.h b/drivers/mtd/nand/gpmi-nand/gpmi-nand.h
+deleted file mode 100644
+index a45e4ce..0000000
+--- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.h
++++ /dev/null
+@@ -1,315 +0,0 @@
+-/*
+- * Freescale GPMI NAND Flash Driver
+- *
+- * Copyright (C) 2010-2011 Freescale Semiconductor, Inc.
+- * Copyright (C) 2008 Embedded Alley Solutions, Inc.
+- *
+- * 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.
+- */
+-#ifndef __DRIVERS_MTD_NAND_GPMI_NAND_H
+-#define __DRIVERS_MTD_NAND_GPMI_NAND_H
+-
+-#include <linux/mtd/rawnand.h>
+-#include <linux/platform_device.h>
+-#include <linux/dma-mapping.h>
+-#include <linux/dmaengine.h>
+-
+-#define GPMI_CLK_MAX 5 /* MX6Q needs five clocks */
+-struct resources {
+-	void __iomem  *gpmi_regs;
+-	void __iomem  *bch_regs;
+-	unsigned int  dma_low_channel;
+-	unsigned int  dma_high_channel;
+-	struct clk    *clock[GPMI_CLK_MAX];
+-};
+-
+-/**
+- * struct bch_geometry - BCH geometry description.
+- * @gf_len:                   The length of Galois Field. (e.g., 13 or 14)
+- * @ecc_strength:             A number that describes the strength of the ECC
+- *                            algorithm.
+- * @page_size:                The size, in bytes, of a physical page, including
+- *                            both data and OOB.
+- * @metadata_size:            The size, in bytes, of the metadata.
+- * @ecc_chunk_size:           The size, in bytes, of a single ECC chunk. Note
+- *                            the first chunk in the page includes both data and
+- *                            metadata, so it's a bit larger than this value.
+- * @ecc_chunk_count:          The number of ECC chunks in the page,
+- * @payload_size:             The size, in bytes, of the payload buffer.
+- * @auxiliary_size:           The size, in bytes, of the auxiliary buffer.
+- * @auxiliary_status_offset:  The offset into the auxiliary buffer at which
+- *                            the ECC status appears.
+- * @block_mark_byte_offset:   The byte offset in the ECC-based page view at
+- *                            which the underlying physical block mark appears.
+- * @block_mark_bit_offset:    The bit offset into the ECC-based page view at
+- *                            which the underlying physical block mark appears.
+- */
+-struct bch_geometry {
+-	unsigned int  gf_len;
+-	unsigned int  ecc_strength;
+-	unsigned int  page_size;
+-	unsigned int  metadata_size;
+-	unsigned int  ecc_chunk_size;
+-	unsigned int  ecc_chunk_count;
+-	unsigned int  payload_size;
+-	unsigned int  auxiliary_size;
+-	unsigned int  auxiliary_status_offset;
+-	unsigned int  block_mark_byte_offset;
+-	unsigned int  block_mark_bit_offset;
+-};
+-
+-/**
+- * struct boot_rom_geometry - Boot ROM geometry description.
+- * @stride_size_in_pages:        The size of a boot block stride, in pages.
+- * @search_area_stride_exponent: The logarithm to base 2 of the size of a
+- *                               search area in boot block strides.
+- */
+-struct boot_rom_geometry {
+-	unsigned int  stride_size_in_pages;
+-	unsigned int  search_area_stride_exponent;
+-};
+-
+-/* DMA operations types */
+-enum dma_ops_type {
+-	DMA_FOR_COMMAND = 1,
+-	DMA_FOR_READ_DATA,
+-	DMA_FOR_WRITE_DATA,
+-	DMA_FOR_READ_ECC_PAGE,
+-	DMA_FOR_WRITE_ECC_PAGE
+-};
+-
+-/**
+- * struct nand_timing - Fundamental timing attributes for NAND.
+- * @data_setup_in_ns:         The data setup time, in nanoseconds. Usually the
+- *                            maximum of tDS and tWP. A negative value
+- *                            indicates this characteristic isn't known.
+- * @data_hold_in_ns:          The data hold time, in nanoseconds. Usually the
+- *                            maximum of tDH, tWH and tREH. A negative value
+- *                            indicates this characteristic isn't known.
+- * @address_setup_in_ns:      The address setup time, in nanoseconds. Usually
+- *                            the maximum of tCLS, tCS and tALS. A negative
+- *                            value indicates this characteristic isn't known.
+- * @gpmi_sample_delay_in_ns:  A GPMI-specific timing parameter. A negative value
+- *                            indicates this characteristic isn't known.
+- * @tREA_in_ns:               tREA, in nanoseconds, from the data sheet. A
+- *                            negative value indicates this characteristic isn't
+- *                            known.
+- * @tRLOH_in_ns:              tRLOH, in nanoseconds, from the data sheet. A
+- *                            negative value indicates this characteristic isn't
+- *                            known.
+- * @tRHOH_in_ns:              tRHOH, in nanoseconds, from the data sheet. A
+- *                            negative value indicates this characteristic isn't
+- *                            known.
+- */
+-struct nand_timing {
+-	int8_t  data_setup_in_ns;
+-	int8_t  data_hold_in_ns;
+-	int8_t  address_setup_in_ns;
+-	int8_t  gpmi_sample_delay_in_ns;
+-	int8_t  tREA_in_ns;
+-	int8_t  tRLOH_in_ns;
+-	int8_t  tRHOH_in_ns;
+-};
+-
+-enum gpmi_type {
+-	IS_MX23,
+-	IS_MX28,
+-	IS_MX6Q,
+-	IS_MX6SX,
+-	IS_MX7D,
+-};
+-
+-struct gpmi_devdata {
+-	enum gpmi_type type;
+-	int bch_max_ecc_strength;
+-	int max_chain_delay; /* See the async EDO mode */
+-	const char * const *clks;
+-	const int clks_count;
+-};
+-
+-struct gpmi_nand_data {
+-	/* flags */
+-#define GPMI_ASYNC_EDO_ENABLED	(1 << 0)
+-#define GPMI_TIMING_INIT_OK	(1 << 1)
+-	int			flags;
+-	const struct gpmi_devdata *devdata;
+-
+-	/* System Interface */
+-	struct device		*dev;
+-	struct platform_device	*pdev;
+-
+-	/* Resources */
+-	struct resources	resources;
+-
+-	/* Flash Hardware */
+-	struct nand_timing	timing;
+-	int			timing_mode;
+-
+-	/* BCH */
+-	struct bch_geometry	bch_geometry;
+-	struct completion	bch_done;
+-
+-	/* NAND Boot issue */
+-	bool			swap_block_mark;
+-	struct boot_rom_geometry rom_geometry;
+-
+-	/* MTD / NAND */
+-	struct nand_chip	nand;
+-
+-	/* General-use Variables */
+-	int			current_chip;
+-	unsigned int		command_length;
+-
+-	/* passed from upper layer */
+-	uint8_t			*upper_buf;
+-	int			upper_len;
+-
+-	/* for DMA operations */
+-	bool			direct_dma_map_ok;
+-
+-	struct scatterlist	cmd_sgl;
+-	char			*cmd_buffer;
+-
+-	struct scatterlist	data_sgl;
+-	char			*data_buffer_dma;
+-
+-	void			*page_buffer_virt;
+-	dma_addr_t		page_buffer_phys;
+-	unsigned int		page_buffer_size;
+-
+-	void			*payload_virt;
+-	dma_addr_t		payload_phys;
+-
+-	void			*auxiliary_virt;
+-	dma_addr_t		auxiliary_phys;
+-
+-	void			*raw_buffer;
+-
+-	/* DMA channels */
+-#define DMA_CHANS		8
+-	struct dma_chan		*dma_chans[DMA_CHANS];
+-	enum dma_ops_type	last_dma_type;
+-	enum dma_ops_type	dma_type;
+-	struct completion	dma_done;
+-
+-	/* private */
+-	void			*private;
+-};
+-
+-/**
+- * struct gpmi_nfc_hardware_timing - GPMI hardware timing parameters.
+- * @data_setup_in_cycles:      The data setup time, in cycles.
+- * @data_hold_in_cycles:       The data hold time, in cycles.
+- * @address_setup_in_cycles:   The address setup time, in cycles.
+- * @device_busy_timeout:       The timeout waiting for NAND Ready/Busy,
+- *                             this value is the number of cycles multiplied
+- *                             by 4096.
+- * @use_half_periods:          Indicates the clock is running slowly, so the
+- *                             NFC DLL should use half-periods.
+- * @sample_delay_factor:       The sample delay factor.
+- * @wrn_dly_sel:               The delay on the GPMI write strobe.
+- */
+-struct gpmi_nfc_hardware_timing {
+-	/* for HW_GPMI_TIMING0 */
+-	uint8_t  data_setup_in_cycles;
+-	uint8_t  data_hold_in_cycles;
+-	uint8_t  address_setup_in_cycles;
+-
+-	/* for HW_GPMI_TIMING1 */
+-	uint16_t device_busy_timeout;
+-#define GPMI_DEFAULT_BUSY_TIMEOUT	0x500 /* default busy timeout value.*/
+-
+-	/* for HW_GPMI_CTRL1 */
+-	bool     use_half_periods;
+-	uint8_t  sample_delay_factor;
+-	uint8_t  wrn_dly_sel;
+-};
+-
+-/**
+- * struct timing_threshold - Timing threshold
+- * @max_data_setup_cycles:       The maximum number of data setup cycles that
+- *                               can be expressed in the hardware.
+- * @internal_data_setup_in_ns:   The time, in ns, that the NFC hardware requires
+- *                               for data read internal setup. In the Reference
+- *                               Manual, see the chapter "High-Speed NAND
+- *                               Timing" for more details.
+- * @max_sample_delay_factor:     The maximum sample delay factor that can be
+- *                               expressed in the hardware.
+- * @max_dll_clock_period_in_ns:  The maximum period of the GPMI clock that the
+- *                               sample delay DLL hardware can possibly work
+- *                               with (the DLL is unusable with longer periods).
+- *                               If the full-cycle period is greater than HALF
+- *                               this value, the DLL must be configured to use
+- *                               half-periods.
+- * @max_dll_delay_in_ns:         The maximum amount of delay, in ns, that the
+- *                               DLL can implement.
+- * @clock_frequency_in_hz:       The clock frequency, in Hz, during the current
+- *                               I/O transaction. If no I/O transaction is in
+- *                               progress, this is the clock frequency during
+- *                               the most recent I/O transaction.
+- */
+-struct timing_threshold {
+-	const unsigned int      max_chip_count;
+-	const unsigned int      max_data_setup_cycles;
+-	const unsigned int      internal_data_setup_in_ns;
+-	const unsigned int      max_sample_delay_factor;
+-	const unsigned int      max_dll_clock_period_in_ns;
+-	const unsigned int      max_dll_delay_in_ns;
+-	unsigned long           clock_frequency_in_hz;
+-
+-};
+-
+-/* Common Services */
+-extern int common_nfc_set_geometry(struct gpmi_nand_data *);
+-extern struct dma_chan *get_dma_chan(struct gpmi_nand_data *);
+-extern void prepare_data_dma(struct gpmi_nand_data *,
+-				enum dma_data_direction dr);
+-extern int start_dma_without_bch_irq(struct gpmi_nand_data *,
+-				struct dma_async_tx_descriptor *);
+-extern int start_dma_with_bch_irq(struct gpmi_nand_data *,
+-				struct dma_async_tx_descriptor *);
+-
+-/* GPMI-NAND helper function library */
+-extern int gpmi_init(struct gpmi_nand_data *);
+-extern int gpmi_extra_init(struct gpmi_nand_data *);
+-extern void gpmi_clear_bch(struct gpmi_nand_data *);
+-extern void gpmi_dump_info(struct gpmi_nand_data *);
+-extern int bch_set_geometry(struct gpmi_nand_data *);
+-extern int gpmi_is_ready(struct gpmi_nand_data *, unsigned chip);
+-extern int gpmi_send_command(struct gpmi_nand_data *);
+-extern void gpmi_begin(struct gpmi_nand_data *);
+-extern void gpmi_end(struct gpmi_nand_data *);
+-extern int gpmi_read_data(struct gpmi_nand_data *);
+-extern int gpmi_send_data(struct gpmi_nand_data *);
+-extern int gpmi_send_page(struct gpmi_nand_data *,
+-			dma_addr_t payload, dma_addr_t auxiliary);
+-extern int gpmi_read_page(struct gpmi_nand_data *,
+-			dma_addr_t payload, dma_addr_t auxiliary);
+-
+-void gpmi_copy_bits(u8 *dst, size_t dst_bit_off,
+-		    const u8 *src, size_t src_bit_off,
+-		    size_t nbits);
+-
+-/* BCH : Status Block Completion Codes */
+-#define STATUS_GOOD		0x00
+-#define STATUS_ERASED		0xff
+-#define STATUS_UNCORRECTABLE	0xfe
+-
+-/* Use the devdata to distinguish different Archs. */
+-#define GPMI_IS_MX23(x)		((x)->devdata->type == IS_MX23)
+-#define GPMI_IS_MX28(x)		((x)->devdata->type == IS_MX28)
+-#define GPMI_IS_MX6Q(x)		((x)->devdata->type == IS_MX6Q)
+-#define GPMI_IS_MX6SX(x)	((x)->devdata->type == IS_MX6SX)
+-#define GPMI_IS_MX7D(x)		((x)->devdata->type == IS_MX7D)
+-
+-#define GPMI_IS_MX6(x)		(GPMI_IS_MX6Q(x) || GPMI_IS_MX6SX(x) || \
+-				 GPMI_IS_MX7D(x))
+-#endif
+diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-regs.h b/drivers/mtd/nand/gpmi-nand/gpmi-regs.h
+deleted file mode 100644
+index 82114cd..0000000
+--- a/drivers/mtd/nand/gpmi-nand/gpmi-regs.h
++++ /dev/null
+@@ -1,187 +0,0 @@
+-/*
+- * Freescale GPMI NAND Flash Driver
+- *
+- * Copyright 2008-2011 Freescale Semiconductor, Inc.
+- * Copyright 2008 Embedded Alley Solutions, Inc.
+- *
+- * 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.
+- *
+- * You should have received a copy of the GNU General Public License along
+- * with this program; if not, write to the Free Software Foundation, Inc.,
+- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+- */
+-#ifndef __GPMI_NAND_GPMI_REGS_H
+-#define __GPMI_NAND_GPMI_REGS_H
+-
+-#define HW_GPMI_CTRL0					0x00000000
+-#define HW_GPMI_CTRL0_SET				0x00000004
+-#define HW_GPMI_CTRL0_CLR				0x00000008
+-#define HW_GPMI_CTRL0_TOG				0x0000000c
+-
+-#define BP_GPMI_CTRL0_COMMAND_MODE			24
+-#define BM_GPMI_CTRL0_COMMAND_MODE	(3 << BP_GPMI_CTRL0_COMMAND_MODE)
+-#define BF_GPMI_CTRL0_COMMAND_MODE(v)	\
+-	(((v) << BP_GPMI_CTRL0_COMMAND_MODE) & BM_GPMI_CTRL0_COMMAND_MODE)
+-#define BV_GPMI_CTRL0_COMMAND_MODE__WRITE		0x0
+-#define BV_GPMI_CTRL0_COMMAND_MODE__READ		0x1
+-#define BV_GPMI_CTRL0_COMMAND_MODE__READ_AND_COMPARE	0x2
+-#define BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY	0x3
+-
+-#define BM_GPMI_CTRL0_WORD_LENGTH			(1 << 23)
+-#define BV_GPMI_CTRL0_WORD_LENGTH__16_BIT		0x0
+-#define BV_GPMI_CTRL0_WORD_LENGTH__8_BIT		0x1
+-
+-/*
+- *  Difference in LOCK_CS between imx23 and imx28 :
+- *  This bit may impact the _POWER_ consumption. So some chips
+- *  do not set it.
+- */
+-#define MX23_BP_GPMI_CTRL0_LOCK_CS			22
+-#define MX28_BP_GPMI_CTRL0_LOCK_CS			27
+-#define LOCK_CS_ENABLE					0x1
+-#define BF_GPMI_CTRL0_LOCK_CS(v, x)			0x0
+-
+-/* Difference in CS between imx23 and imx28 */
+-#define BP_GPMI_CTRL0_CS				20
+-#define MX23_BM_GPMI_CTRL0_CS		(3 << BP_GPMI_CTRL0_CS)
+-#define MX28_BM_GPMI_CTRL0_CS		(7 << BP_GPMI_CTRL0_CS)
+-#define BF_GPMI_CTRL0_CS(v, x)		(((v) << BP_GPMI_CTRL0_CS) & \
+-						(GPMI_IS_MX23((x)) \
+-						? MX23_BM_GPMI_CTRL0_CS	\
+-						: MX28_BM_GPMI_CTRL0_CS))
+-
+-#define BP_GPMI_CTRL0_ADDRESS				17
+-#define BM_GPMI_CTRL0_ADDRESS		(3 << BP_GPMI_CTRL0_ADDRESS)
+-#define BF_GPMI_CTRL0_ADDRESS(v)	\
+-		(((v) << BP_GPMI_CTRL0_ADDRESS) & BM_GPMI_CTRL0_ADDRESS)
+-#define BV_GPMI_CTRL0_ADDRESS__NAND_DATA		0x0
+-#define BV_GPMI_CTRL0_ADDRESS__NAND_CLE			0x1
+-#define BV_GPMI_CTRL0_ADDRESS__NAND_ALE			0x2
+-
+-#define BM_GPMI_CTRL0_ADDRESS_INCREMENT			(1 << 16)
+-#define BV_GPMI_CTRL0_ADDRESS_INCREMENT__DISABLED	0x0
+-#define BV_GPMI_CTRL0_ADDRESS_INCREMENT__ENABLED	0x1
+-
+-#define BP_GPMI_CTRL0_XFER_COUNT			0
+-#define BM_GPMI_CTRL0_XFER_COUNT	(0xffff << BP_GPMI_CTRL0_XFER_COUNT)
+-#define BF_GPMI_CTRL0_XFER_COUNT(v)	\
+-		(((v) << BP_GPMI_CTRL0_XFER_COUNT) & BM_GPMI_CTRL0_XFER_COUNT)
+-
+-#define HW_GPMI_COMPARE					0x00000010
+-
+-#define HW_GPMI_ECCCTRL					0x00000020
+-#define HW_GPMI_ECCCTRL_SET				0x00000024
+-#define HW_GPMI_ECCCTRL_CLR				0x00000028
+-#define HW_GPMI_ECCCTRL_TOG				0x0000002c
+-
+-#define BP_GPMI_ECCCTRL_ECC_CMD				13
+-#define BM_GPMI_ECCCTRL_ECC_CMD		(3 << BP_GPMI_ECCCTRL_ECC_CMD)
+-#define BF_GPMI_ECCCTRL_ECC_CMD(v)	\
+-		(((v) << BP_GPMI_ECCCTRL_ECC_CMD) & BM_GPMI_ECCCTRL_ECC_CMD)
+-#define BV_GPMI_ECCCTRL_ECC_CMD__BCH_DECODE		0x0
+-#define BV_GPMI_ECCCTRL_ECC_CMD__BCH_ENCODE		0x1
+-
+-#define BM_GPMI_ECCCTRL_ENABLE_ECC			(1 << 12)
+-#define BV_GPMI_ECCCTRL_ENABLE_ECC__ENABLE		0x1
+-#define BV_GPMI_ECCCTRL_ENABLE_ECC__DISABLE		0x0
+-
+-#define BP_GPMI_ECCCTRL_BUFFER_MASK			0
+-#define BM_GPMI_ECCCTRL_BUFFER_MASK	(0x1ff << BP_GPMI_ECCCTRL_BUFFER_MASK)
+-#define BF_GPMI_ECCCTRL_BUFFER_MASK(v)	\
+-	(((v) << BP_GPMI_ECCCTRL_BUFFER_MASK) & BM_GPMI_ECCCTRL_BUFFER_MASK)
+-#define BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_AUXONLY	0x100
+-#define BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_PAGE		0x1FF
+-
+-#define HW_GPMI_ECCCOUNT				0x00000030
+-#define HW_GPMI_PAYLOAD					0x00000040
+-#define HW_GPMI_AUXILIARY				0x00000050
+-#define HW_GPMI_CTRL1					0x00000060
+-#define HW_GPMI_CTRL1_SET				0x00000064
+-#define HW_GPMI_CTRL1_CLR				0x00000068
+-#define HW_GPMI_CTRL1_TOG				0x0000006c
+-
+-#define BP_GPMI_CTRL1_DECOUPLE_CS			24
+-#define BM_GPMI_CTRL1_DECOUPLE_CS	(1 << BP_GPMI_CTRL1_DECOUPLE_CS)
+-
+-#define BP_GPMI_CTRL1_WRN_DLY_SEL			22
+-#define BM_GPMI_CTRL1_WRN_DLY_SEL	(0x3 << BP_GPMI_CTRL1_WRN_DLY_SEL)
+-#define BF_GPMI_CTRL1_WRN_DLY_SEL(v)  \
+-	(((v) << BP_GPMI_CTRL1_WRN_DLY_SEL) & BM_GPMI_CTRL1_WRN_DLY_SEL)
+-#define BV_GPMI_CTRL1_WRN_DLY_SEL_4_TO_8NS		0x0
+-#define BV_GPMI_CTRL1_WRN_DLY_SEL_6_TO_10NS		0x1
+-#define BV_GPMI_CTRL1_WRN_DLY_SEL_7_TO_12NS		0x2
+-#define BV_GPMI_CTRL1_WRN_DLY_SEL_NO_DELAY		0x3
+-
+-#define BM_GPMI_CTRL1_BCH_MODE				(1 << 18)
+-
+-#define BP_GPMI_CTRL1_DLL_ENABLE			17
+-#define BM_GPMI_CTRL1_DLL_ENABLE	(1 << BP_GPMI_CTRL1_DLL_ENABLE)
+-
+-#define BP_GPMI_CTRL1_HALF_PERIOD			16
+-#define BM_GPMI_CTRL1_HALF_PERIOD	(1 << BP_GPMI_CTRL1_HALF_PERIOD)
+-
+-#define BP_GPMI_CTRL1_RDN_DELAY				12
+-#define BM_GPMI_CTRL1_RDN_DELAY		(0xf << BP_GPMI_CTRL1_RDN_DELAY)
+-#define BF_GPMI_CTRL1_RDN_DELAY(v)	\
+-		(((v) << BP_GPMI_CTRL1_RDN_DELAY) & BM_GPMI_CTRL1_RDN_DELAY)
+-
+-#define BM_GPMI_CTRL1_DEV_RESET				(1 << 3)
+-#define BV_GPMI_CTRL1_DEV_RESET__ENABLED		0x0
+-#define BV_GPMI_CTRL1_DEV_RESET__DISABLED		0x1
+-
+-#define BM_GPMI_CTRL1_ATA_IRQRDY_POLARITY		(1 << 2)
+-#define BV_GPMI_CTRL1_ATA_IRQRDY_POLARITY__ACTIVELOW	0x0
+-#define BV_GPMI_CTRL1_ATA_IRQRDY_POLARITY__ACTIVEHIGH	0x1
+-
+-#define BM_GPMI_CTRL1_CAMERA_MODE			(1 << 1)
+-#define BV_GPMI_CTRL1_GPMI_MODE__NAND			0x0
+-#define BV_GPMI_CTRL1_GPMI_MODE__ATA			0x1
+-
+-#define BM_GPMI_CTRL1_GPMI_MODE				(1 << 0)
+-
+-#define HW_GPMI_TIMING0					0x00000070
+-
+-#define BP_GPMI_TIMING0_ADDRESS_SETUP			16
+-#define BM_GPMI_TIMING0_ADDRESS_SETUP	(0xff << BP_GPMI_TIMING0_ADDRESS_SETUP)
+-#define BF_GPMI_TIMING0_ADDRESS_SETUP(v)	\
+-	(((v) << BP_GPMI_TIMING0_ADDRESS_SETUP) & BM_GPMI_TIMING0_ADDRESS_SETUP)
+-
+-#define BP_GPMI_TIMING0_DATA_HOLD			8
+-#define BM_GPMI_TIMING0_DATA_HOLD	(0xff << BP_GPMI_TIMING0_DATA_HOLD)
+-#define BF_GPMI_TIMING0_DATA_HOLD(v)		\
+-	(((v) << BP_GPMI_TIMING0_DATA_HOLD) & BM_GPMI_TIMING0_DATA_HOLD)
+-
+-#define BP_GPMI_TIMING0_DATA_SETUP			0
+-#define BM_GPMI_TIMING0_DATA_SETUP	(0xff << BP_GPMI_TIMING0_DATA_SETUP)
+-#define BF_GPMI_TIMING0_DATA_SETUP(v)		\
+-	(((v) << BP_GPMI_TIMING0_DATA_SETUP) & BM_GPMI_TIMING0_DATA_SETUP)
+-
+-#define HW_GPMI_TIMING1					0x00000080
+-#define BP_GPMI_TIMING1_BUSY_TIMEOUT			16
+-#define BM_GPMI_TIMING1_BUSY_TIMEOUT	(0xffff << BP_GPMI_TIMING1_BUSY_TIMEOUT)
+-#define BF_GPMI_TIMING1_BUSY_TIMEOUT(v)		\
+-	(((v) << BP_GPMI_TIMING1_BUSY_TIMEOUT) & BM_GPMI_TIMING1_BUSY_TIMEOUT)
+-
+-#define HW_GPMI_TIMING2					0x00000090
+-#define HW_GPMI_DATA					0x000000a0
+-
+-/* MX28 uses this to detect READY. */
+-#define HW_GPMI_STAT					0x000000b0
+-#define MX28_BP_GPMI_STAT_READY_BUSY			24
+-#define MX28_BM_GPMI_STAT_READY_BUSY	(0xff << MX28_BP_GPMI_STAT_READY_BUSY)
+-#define MX28_BF_GPMI_STAT_READY_BUSY(v)		\
+-	(((v) << MX28_BP_GPMI_STAT_READY_BUSY) & MX28_BM_GPMI_STAT_READY_BUSY)
+-
+-/* MX23 uses this to detect READY. */
+-#define HW_GPMI_DEBUG					0x000000c0
+-#define MX23_BP_GPMI_DEBUG_READY0			28
+-#define MX23_BM_GPMI_DEBUG_READY0	(1 << MX23_BP_GPMI_DEBUG_READY0)
+-#endif
+diff --git a/drivers/mtd/nand/hisi504_nand.c b/drivers/mtd/nand/hisi504_nand.c
+deleted file mode 100644
+index d9ee1a7..0000000
+--- a/drivers/mtd/nand/hisi504_nand.c
++++ /dev/null
+@@ -1,898 +0,0 @@
+-/*
+- * Hisilicon NAND Flash controller driver
+- *
+- * Copyright © 2012-2014 HiSilicon Technologies Co., Ltd.
+- *              http://www.hisilicon.com
+- *
+- * Author: Zhou Wang <wangzhou.bry@gmail.com>
+- * The initial developer of the original code is Zhiyong Cai
+- * <caizhiyong@huawei.com>
+- *
+- * 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/of.h>
+-#include <linux/mtd/mtd.h>
+-#include <linux/sizes.h>
+-#include <linux/clk.h>
+-#include <linux/slab.h>
+-#include <linux/module.h>
+-#include <linux/delay.h>
+-#include <linux/interrupt.h>
+-#include <linux/mtd/rawnand.h>
+-#include <linux/dma-mapping.h>
+-#include <linux/platform_device.h>
+-#include <linux/mtd/partitions.h>
+-
+-#define HINFC504_MAX_CHIP                               (4)
+-#define HINFC504_W_LATCH                                (5)
+-#define HINFC504_R_LATCH                                (7)
+-#define HINFC504_RW_LATCH                               (3)
+-
+-#define HINFC504_NFC_TIMEOUT				(2 * HZ)
+-#define HINFC504_NFC_PM_TIMEOUT				(1 * HZ)
+-#define HINFC504_NFC_DMA_TIMEOUT			(5 * HZ)
+-#define HINFC504_CHIP_DELAY				(25)
+-
+-#define HINFC504_REG_BASE_ADDRESS_LEN			(0x100)
+-#define HINFC504_BUFFER_BASE_ADDRESS_LEN		(2048 + 128)
+-
+-#define HINFC504_ADDR_CYCLE_MASK			0x4
+-
+-#define HINFC504_CON					0x00
+-#define HINFC504_CON_OP_MODE_NORMAL			BIT(0)
+-#define HINFC504_CON_PAGEISZE_SHIFT			(1)
+-#define HINFC504_CON_PAGESIZE_MASK			(0x07)
+-#define HINFC504_CON_BUS_WIDTH				BIT(4)
+-#define HINFC504_CON_READY_BUSY_SEL			BIT(8)
+-#define HINFC504_CON_ECCTYPE_SHIFT			(9)
+-#define HINFC504_CON_ECCTYPE_MASK			(0x07)
+-
+-#define HINFC504_PWIDTH					0x04
+-#define SET_HINFC504_PWIDTH(_w_lcnt, _r_lcnt, _rw_hcnt) \
+-	((_w_lcnt) | (((_r_lcnt) & 0x0F) << 4) | (((_rw_hcnt) & 0x0F) << 8))
+-
+-#define HINFC504_CMD					0x0C
+-#define HINFC504_ADDRL					0x10
+-#define HINFC504_ADDRH					0x14
+-#define HINFC504_DATA_NUM				0x18
+-
+-#define HINFC504_OP					0x1C
+-#define HINFC504_OP_READ_DATA_EN			BIT(1)
+-#define HINFC504_OP_WAIT_READY_EN			BIT(2)
+-#define HINFC504_OP_CMD2_EN				BIT(3)
+-#define HINFC504_OP_WRITE_DATA_EN			BIT(4)
+-#define HINFC504_OP_ADDR_EN				BIT(5)
+-#define HINFC504_OP_CMD1_EN				BIT(6)
+-#define HINFC504_OP_NF_CS_SHIFT                         (7)
+-#define HINFC504_OP_NF_CS_MASK				(3)
+-#define HINFC504_OP_ADDR_CYCLE_SHIFT			(9)
+-#define HINFC504_OP_ADDR_CYCLE_MASK			(7)
+-
+-#define HINFC504_STATUS                                 0x20
+-#define HINFC504_READY					BIT(0)
+-
+-#define HINFC504_INTEN					0x24
+-#define HINFC504_INTEN_DMA				BIT(9)
+-#define HINFC504_INTEN_UE				BIT(6)
+-#define HINFC504_INTEN_CE				BIT(5)
+-
+-#define HINFC504_INTS					0x28
+-#define HINFC504_INTS_DMA				BIT(9)
+-#define HINFC504_INTS_UE				BIT(6)
+-#define HINFC504_INTS_CE				BIT(5)
+-
+-#define HINFC504_INTCLR                                 0x2C
+-#define HINFC504_INTCLR_DMA				BIT(9)
+-#define HINFC504_INTCLR_UE				BIT(6)
+-#define HINFC504_INTCLR_CE				BIT(5)
+-
+-#define HINFC504_ECC_STATUS                             0x5C
+-#define HINFC504_ECC_16_BIT_SHIFT                       12
+-
+-#define HINFC504_DMA_CTRL				0x60
+-#define HINFC504_DMA_CTRL_DMA_START			BIT(0)
+-#define HINFC504_DMA_CTRL_WE				BIT(1)
+-#define HINFC504_DMA_CTRL_DATA_AREA_EN			BIT(2)
+-#define HINFC504_DMA_CTRL_OOB_AREA_EN			BIT(3)
+-#define HINFC504_DMA_CTRL_BURST4_EN			BIT(4)
+-#define HINFC504_DMA_CTRL_BURST8_EN			BIT(5)
+-#define HINFC504_DMA_CTRL_BURST16_EN			BIT(6)
+-#define HINFC504_DMA_CTRL_ADDR_NUM_SHIFT		(7)
+-#define HINFC504_DMA_CTRL_ADDR_NUM_MASK                 (1)
+-#define HINFC504_DMA_CTRL_CS_SHIFT			(8)
+-#define HINFC504_DMA_CTRL_CS_MASK			(0x03)
+-
+-#define HINFC504_DMA_ADDR_DATA				0x64
+-#define HINFC504_DMA_ADDR_OOB				0x68
+-
+-#define HINFC504_DMA_LEN				0x6C
+-#define HINFC504_DMA_LEN_OOB_SHIFT			(16)
+-#define HINFC504_DMA_LEN_OOB_MASK			(0xFFF)
+-
+-#define HINFC504_DMA_PARA				0x70
+-#define HINFC504_DMA_PARA_DATA_RW_EN			BIT(0)
+-#define HINFC504_DMA_PARA_OOB_RW_EN			BIT(1)
+-#define HINFC504_DMA_PARA_DATA_EDC_EN			BIT(2)
+-#define HINFC504_DMA_PARA_OOB_EDC_EN			BIT(3)
+-#define HINFC504_DMA_PARA_DATA_ECC_EN			BIT(4)
+-#define HINFC504_DMA_PARA_OOB_ECC_EN			BIT(5)
+-
+-#define HINFC_VERSION                                   0x74
+-#define HINFC504_LOG_READ_ADDR				0x7C
+-#define HINFC504_LOG_READ_LEN				0x80
+-
+-#define HINFC504_NANDINFO_LEN				0x10
+-
+-struct hinfc_host {
+-	struct nand_chip	chip;
+-	struct device		*dev;
+-	void __iomem		*iobase;
+-	void __iomem		*mmio;
+-	struct completion       cmd_complete;
+-	unsigned int		offset;
+-	unsigned int		command;
+-	int			chipselect;
+-	unsigned int		addr_cycle;
+-	u32                     addr_value[2];
+-	u32                     cache_addr_value[2];
+-	char			*buffer;
+-	dma_addr_t		dma_buffer;
+-	dma_addr_t		dma_oob;
+-	int			version;
+-	unsigned int            irq_status; /* interrupt status */
+-};
+-
+-static inline unsigned int hinfc_read(struct hinfc_host *host, unsigned int reg)
+-{
+-	return readl(host->iobase + reg);
+-}
+-
+-static inline void hinfc_write(struct hinfc_host *host, unsigned int value,
+-			       unsigned int reg)
+-{
+-	writel(value, host->iobase + reg);
+-}
+-
+-static void wait_controller_finished(struct hinfc_host *host)
+-{
+-	unsigned long timeout = jiffies + HINFC504_NFC_TIMEOUT;
+-	int val;
+-
+-	while (time_before(jiffies, timeout)) {
+-		val = hinfc_read(host, HINFC504_STATUS);
+-		if (host->command == NAND_CMD_ERASE2) {
+-			/* nfc is ready */
+-			while (!(val & HINFC504_READY))	{
+-				usleep_range(500, 1000);
+-				val = hinfc_read(host, HINFC504_STATUS);
+-			}
+-			return;
+-		}
+-
+-		if (val & HINFC504_READY)
+-			return;
+-	}
+-
+-	/* wait cmd timeout */
+-	dev_err(host->dev, "Wait NAND controller exec cmd timeout.\n");
+-}
+-
+-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);
+-	unsigned long val;
+-	int ret;
+-
+-	hinfc_write(host, host->dma_buffer, HINFC504_DMA_ADDR_DATA);
+-	hinfc_write(host, host->dma_oob, HINFC504_DMA_ADDR_OOB);
+-
+-	if (chip->ecc.mode == NAND_ECC_NONE) {
+-		hinfc_write(host, ((mtd->oobsize & HINFC504_DMA_LEN_OOB_MASK)
+-			<< HINFC504_DMA_LEN_OOB_SHIFT), HINFC504_DMA_LEN);
+-
+-		hinfc_write(host, HINFC504_DMA_PARA_DATA_RW_EN
+-			| HINFC504_DMA_PARA_OOB_RW_EN, HINFC504_DMA_PARA);
+-	} else {
+-		if (host->command == NAND_CMD_READOOB)
+-			hinfc_write(host, HINFC504_DMA_PARA_OOB_RW_EN
+-			| HINFC504_DMA_PARA_OOB_EDC_EN
+-			| HINFC504_DMA_PARA_OOB_ECC_EN, HINFC504_DMA_PARA);
+-		else
+-			hinfc_write(host, HINFC504_DMA_PARA_DATA_RW_EN
+-			| HINFC504_DMA_PARA_OOB_RW_EN
+-			| HINFC504_DMA_PARA_DATA_EDC_EN
+-			| HINFC504_DMA_PARA_OOB_EDC_EN
+-			| HINFC504_DMA_PARA_DATA_ECC_EN
+-			| HINFC504_DMA_PARA_OOB_ECC_EN, HINFC504_DMA_PARA);
+-
+-	}
+-
+-	val = (HINFC504_DMA_CTRL_DMA_START | HINFC504_DMA_CTRL_BURST4_EN
+-		| HINFC504_DMA_CTRL_BURST8_EN | HINFC504_DMA_CTRL_BURST16_EN
+-		| HINFC504_DMA_CTRL_DATA_AREA_EN | HINFC504_DMA_CTRL_OOB_AREA_EN
+-		| ((host->addr_cycle == 4 ? 1 : 0)
+-			<< HINFC504_DMA_CTRL_ADDR_NUM_SHIFT)
+-		| ((host->chipselect & HINFC504_DMA_CTRL_CS_MASK)
+-			<< HINFC504_DMA_CTRL_CS_SHIFT));
+-
+-	if (todev)
+-		val |= HINFC504_DMA_CTRL_WE;
+-
+-	init_completion(&host->cmd_complete);
+-
+-	hinfc_write(host, val, HINFC504_DMA_CTRL);
+-	ret = wait_for_completion_timeout(&host->cmd_complete,
+-			HINFC504_NFC_DMA_TIMEOUT);
+-
+-	if (!ret) {
+-		dev_err(host->dev, "DMA operation(irq) timeout!\n");
+-		/* sanity check */
+-		val = hinfc_read(host, HINFC504_DMA_CTRL);
+-		if (!(val & HINFC504_DMA_CTRL_DMA_START))
+-			dev_err(host->dev, "DMA is already done but without irq ACK!\n");
+-		else
+-			dev_err(host->dev, "DMA is really timeout!\n");
+-	}
+-}
+-
+-static int hisi_nfc_send_cmd_pageprog(struct hinfc_host *host)
+-{
+-	host->addr_value[0] &= 0xffff0000;
+-
+-	hinfc_write(host, host->addr_value[0], HINFC504_ADDRL);
+-	hinfc_write(host, host->addr_value[1], HINFC504_ADDRH);
+-	hinfc_write(host, NAND_CMD_PAGEPROG << 8 | NAND_CMD_SEQIN,
+-		    HINFC504_CMD);
+-
+-	hisi_nfc_dma_transfer(host, 1);
+-
+-	return 0;
+-}
+-
+-static int hisi_nfc_send_cmd_readstart(struct hinfc_host *host)
+-{
+-	struct mtd_info	*mtd = nand_to_mtd(&host->chip);
+-
+-	if ((host->addr_value[0] == host->cache_addr_value[0]) &&
+-	    (host->addr_value[1] == host->cache_addr_value[1]))
+-		return 0;
+-
+-	host->addr_value[0] &= 0xffff0000;
+-
+-	hinfc_write(host, host->addr_value[0], HINFC504_ADDRL);
+-	hinfc_write(host, host->addr_value[1], HINFC504_ADDRH);
+-	hinfc_write(host, NAND_CMD_READSTART << 8 | NAND_CMD_READ0,
+-		    HINFC504_CMD);
+-
+-	hinfc_write(host, 0, HINFC504_LOG_READ_ADDR);
+-	hinfc_write(host, mtd->writesize + mtd->oobsize,
+-		    HINFC504_LOG_READ_LEN);
+-
+-	hisi_nfc_dma_transfer(host, 0);
+-
+-	host->cache_addr_value[0] = host->addr_value[0];
+-	host->cache_addr_value[1] = host->addr_value[1];
+-
+-	return 0;
+-}
+-
+-static int hisi_nfc_send_cmd_erase(struct hinfc_host *host)
+-{
+-	hinfc_write(host, host->addr_value[0], HINFC504_ADDRL);
+-	hinfc_write(host, (NAND_CMD_ERASE2 << 8) | NAND_CMD_ERASE1,
+-		    HINFC504_CMD);
+-
+-	hinfc_write(host, HINFC504_OP_WAIT_READY_EN
+-		| HINFC504_OP_CMD2_EN
+-		| HINFC504_OP_CMD1_EN
+-		| HINFC504_OP_ADDR_EN
+-		| ((host->chipselect & HINFC504_OP_NF_CS_MASK)
+-			<< HINFC504_OP_NF_CS_SHIFT)
+-		| ((host->addr_cycle & HINFC504_OP_ADDR_CYCLE_MASK)
+-			<< HINFC504_OP_ADDR_CYCLE_SHIFT),
+-		HINFC504_OP);
+-
+-	wait_controller_finished(host);
+-
+-	return 0;
+-}
+-
+-static int hisi_nfc_send_cmd_readid(struct hinfc_host *host)
+-{
+-	hinfc_write(host, HINFC504_NANDINFO_LEN, HINFC504_DATA_NUM);
+-	hinfc_write(host, NAND_CMD_READID, HINFC504_CMD);
+-	hinfc_write(host, 0, HINFC504_ADDRL);
+-
+-	hinfc_write(host, HINFC504_OP_CMD1_EN | HINFC504_OP_ADDR_EN
+-		| HINFC504_OP_READ_DATA_EN
+-		| ((host->chipselect & HINFC504_OP_NF_CS_MASK)
+-			<< HINFC504_OP_NF_CS_SHIFT)
+-		| 1 << HINFC504_OP_ADDR_CYCLE_SHIFT, HINFC504_OP);
+-
+-	wait_controller_finished(host);
+-
+-	return 0;
+-}
+-
+-static int hisi_nfc_send_cmd_status(struct hinfc_host *host)
+-{
+-	hinfc_write(host, HINFC504_NANDINFO_LEN, HINFC504_DATA_NUM);
+-	hinfc_write(host, NAND_CMD_STATUS, HINFC504_CMD);
+-	hinfc_write(host, HINFC504_OP_CMD1_EN
+-		| HINFC504_OP_READ_DATA_EN
+-		| ((host->chipselect & HINFC504_OP_NF_CS_MASK)
+-			<< HINFC504_OP_NF_CS_SHIFT),
+-		HINFC504_OP);
+-
+-	wait_controller_finished(host);
+-
+-	return 0;
+-}
+-
+-static int hisi_nfc_send_cmd_reset(struct hinfc_host *host, int chipselect)
+-{
+-	hinfc_write(host, NAND_CMD_RESET, HINFC504_CMD);
+-
+-	hinfc_write(host, HINFC504_OP_CMD1_EN
+-		| ((chipselect & HINFC504_OP_NF_CS_MASK)
+-			<< HINFC504_OP_NF_CS_SHIFT)
+-		| HINFC504_OP_WAIT_READY_EN,
+-		HINFC504_OP);
+-
+-	wait_controller_finished(host);
+-
+-	return 0;
+-}
+-
+-static void hisi_nfc_select_chip(struct mtd_info *mtd, int chipselect)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct hinfc_host *host = nand_get_controller_data(chip);
+-
+-	if (chipselect < 0)
+-		return;
+-
+-	host->chipselect = chipselect;
+-}
+-
+-static uint8_t hisi_nfc_read_byte(struct mtd_info *mtd)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct hinfc_host *host = nand_get_controller_data(chip);
+-
+-	if (host->command == NAND_CMD_STATUS)
+-		return *(uint8_t *)(host->mmio);
+-
+-	host->offset++;
+-
+-	if (host->command == NAND_CMD_READID)
+-		return *(uint8_t *)(host->mmio + host->offset - 1);
+-
+-	return *(uint8_t *)(host->buffer + host->offset - 1);
+-}
+-
+-static u16 hisi_nfc_read_word(struct mtd_info *mtd)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct hinfc_host *host = nand_get_controller_data(chip);
+-
+-	host->offset += 2;
+-	return *(u16 *)(host->buffer + host->offset - 2);
+-}
+-
+-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 hinfc_host *host = nand_get_controller_data(chip);
+-
+-	memcpy(host->buffer + host->offset, buf, len);
+-	host->offset += 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 hinfc_host *host = nand_get_controller_data(chip);
+-
+-	memcpy(buf, host->buffer + host->offset, len);
+-	host->offset += len;
+-}
+-
+-static void set_addr(struct mtd_info *mtd, int column, int page_addr)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct hinfc_host *host = nand_get_controller_data(chip);
+-	unsigned int command = host->command;
+-
+-	host->addr_cycle    = 0;
+-	host->addr_value[0] = 0;
+-	host->addr_value[1] = 0;
+-
+-	/* Serially input address */
+-	if (column != -1) {
+-		/* Adjust columns for 16 bit buswidth */
+-		if (chip->options & NAND_BUSWIDTH_16 &&
+-				!nand_opcode_8bits(command))
+-			column >>= 1;
+-
+-		host->addr_value[0] = column & 0xffff;
+-		host->addr_cycle    = 2;
+-	}
+-	if (page_addr != -1) {
+-		host->addr_value[0] |= (page_addr & 0xffff)
+-			<< (host->addr_cycle * 8);
+-		host->addr_cycle    += 2;
+-		/* One more address cycle for devices > 128MiB */
+-		if (chip->chipsize > (128 << 20)) {
+-			host->addr_cycle += 1;
+-			if (host->command == NAND_CMD_ERASE1)
+-				host->addr_value[0] |= ((page_addr >> 16) & 0xff) << 16;
+-			else
+-				host->addr_value[1] |= ((page_addr >> 16) & 0xff);
+-		}
+-	}
+-}
+-
+-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 hinfc_host *host = nand_get_controller_data(chip);
+-	int is_cache_invalid = 1;
+-	unsigned int flag = 0;
+-
+-	host->command =  command;
+-
+-	switch (command) {
+-	case NAND_CMD_READ0:
+-	case NAND_CMD_READOOB:
+-		if (command == NAND_CMD_READ0)
+-			host->offset = column;
+-		else
+-			host->offset = column + mtd->writesize;
+-
+-		is_cache_invalid = 0;
+-		set_addr(mtd, column, page_addr);
+-		hisi_nfc_send_cmd_readstart(host);
+-		break;
+-
+-	case NAND_CMD_SEQIN:
+-		host->offset = column;
+-		set_addr(mtd, column, page_addr);
+-		break;
+-
+-	case NAND_CMD_ERASE1:
+-		set_addr(mtd, column, page_addr);
+-		break;
+-
+-	case NAND_CMD_PAGEPROG:
+-		hisi_nfc_send_cmd_pageprog(host);
+-		break;
+-
+-	case NAND_CMD_ERASE2:
+-		hisi_nfc_send_cmd_erase(host);
+-		break;
+-
+-	case NAND_CMD_READID:
+-		host->offset = column;
+-		memset(host->mmio, 0, 0x10);
+-		hisi_nfc_send_cmd_readid(host);
+-		break;
+-
+-	case NAND_CMD_STATUS:
+-		flag = hinfc_read(host, HINFC504_CON);
+-		if (chip->ecc.mode == NAND_ECC_HW)
+-			hinfc_write(host,
+-				    flag & ~(HINFC504_CON_ECCTYPE_MASK <<
+-				    HINFC504_CON_ECCTYPE_SHIFT), HINFC504_CON);
+-
+-		host->offset = 0;
+-		memset(host->mmio, 0, 0x10);
+-		hisi_nfc_send_cmd_status(host);
+-		hinfc_write(host, flag, HINFC504_CON);
+-		break;
+-
+-	case NAND_CMD_RESET:
+-		hisi_nfc_send_cmd_reset(host, host->chipselect);
+-		break;
+-
+-	default:
+-		dev_err(host->dev, "Error: unsupported cmd(cmd=%x, col=%x, page=%x)\n",
+-			command, column, page_addr);
+-	}
+-
+-	if (is_cache_invalid) {
+-		host->cache_addr_value[0] = ~0;
+-		host->cache_addr_value[1] = ~0;
+-	}
+-}
+-
+-static irqreturn_t hinfc_irq_handle(int irq, void *devid)
+-{
+-	struct hinfc_host *host = devid;
+-	unsigned int flag;
+-
+-	flag = hinfc_read(host, HINFC504_INTS);
+-	/* store interrupts state */
+-	host->irq_status |= flag;
+-
+-	if (flag & HINFC504_INTS_DMA) {
+-		hinfc_write(host, HINFC504_INTCLR_DMA, HINFC504_INTCLR);
+-		complete(&host->cmd_complete);
+-	} else if (flag & HINFC504_INTS_CE) {
+-		hinfc_write(host, HINFC504_INTCLR_CE, HINFC504_INTCLR);
+-	} else if (flag & HINFC504_INTS_UE) {
+-		hinfc_write(host, HINFC504_INTCLR_UE, HINFC504_INTCLR);
+-	}
+-
+-	return IRQ_HANDLED;
+-}
+-
+-static int hisi_nand_read_page_hwecc(struct mtd_info *mtd,
+-	struct nand_chip *chip, uint8_t *buf, int oob_required, int page)
+-{
+-	struct hinfc_host *host = nand_get_controller_data(chip);
+-	int max_bitflips = 0, stat = 0, stat_max = 0, status_ecc;
+-	int stat_1, stat_2;
+-
+-	chip->read_buf(mtd, buf, mtd->writesize);
+-	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+-
+-	/* errors which can not be corrected by ECC */
+-	if (host->irq_status & HINFC504_INTS_UE) {
+-		mtd->ecc_stats.failed++;
+-	} else if (host->irq_status & HINFC504_INTS_CE) {
+-		/* TODO: need add other ECC modes! */
+-		switch (chip->ecc.strength) {
+-		case 16:
+-			status_ecc = hinfc_read(host, HINFC504_ECC_STATUS) >>
+-					HINFC504_ECC_16_BIT_SHIFT & 0x0fff;
+-			stat_2 = status_ecc & 0x3f;
+-			stat_1 = status_ecc >> 6 & 0x3f;
+-			stat = stat_1 + stat_2;
+-			stat_max = max_t(int, stat_1, stat_2);
+-		}
+-		mtd->ecc_stats.corrected += stat;
+-		max_bitflips = max_t(int, max_bitflips, stat_max);
+-	}
+-	host->irq_status = 0;
+-
+-	return max_bitflips;
+-}
+-
+-static int hisi_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
+-				int page)
+-{
+-	struct hinfc_host *host = nand_get_controller_data(chip);
+-
+-	chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
+-	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+-
+-	if (host->irq_status & HINFC504_INTS_UE) {
+-		host->irq_status = 0;
+-		return -EBADMSG;
+-	}
+-
+-	host->irq_status = 0;
+-	return 0;
+-}
+-
+-static int hisi_nand_write_page_hwecc(struct mtd_info *mtd,
+-		struct nand_chip *chip, const uint8_t *buf, int oob_required,
+-		int page)
+-{
+-	chip->write_buf(mtd, buf, mtd->writesize);
+-	if (oob_required)
+-		chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+-
+-	return 0;
+-}
+-
+-static void hisi_nfc_host_init(struct hinfc_host *host)
+-{
+-	struct nand_chip *chip = &host->chip;
+-	unsigned int flag = 0;
+-
+-	host->version = hinfc_read(host, HINFC_VERSION);
+-	host->addr_cycle		= 0;
+-	host->addr_value[0]		= 0;
+-	host->addr_value[1]		= 0;
+-	host->cache_addr_value[0]	= ~0;
+-	host->cache_addr_value[1]	= ~0;
+-	host->chipselect		= 0;
+-
+-	/* default page size: 2K, ecc_none. need modify */
+-	flag = HINFC504_CON_OP_MODE_NORMAL | HINFC504_CON_READY_BUSY_SEL
+-		| ((0x001 & HINFC504_CON_PAGESIZE_MASK)
+-			<< HINFC504_CON_PAGEISZE_SHIFT)
+-		| ((0x0 & HINFC504_CON_ECCTYPE_MASK)
+-			<< HINFC504_CON_ECCTYPE_SHIFT)
+-		| ((chip->options & NAND_BUSWIDTH_16) ?
+-			HINFC504_CON_BUS_WIDTH : 0);
+-	hinfc_write(host, flag, HINFC504_CON);
+-
+-	memset(host->mmio, 0xff, HINFC504_BUFFER_BASE_ADDRESS_LEN);
+-
+-	hinfc_write(host, SET_HINFC504_PWIDTH(HINFC504_W_LATCH,
+-		    HINFC504_R_LATCH, HINFC504_RW_LATCH), HINFC504_PWIDTH);
+-
+-	/* enable DMA irq */
+-	hinfc_write(host, HINFC504_INTEN_DMA, HINFC504_INTEN);
+-}
+-
+-static int hisi_ooblayout_ecc(struct mtd_info *mtd, int section,
+-			      struct mtd_oob_region *oobregion)
+-{
+-	/* FIXME: add ECC bytes position */
+-	return -ENOTSUPP;
+-}
+-
+-static int hisi_ooblayout_free(struct mtd_info *mtd, int section,
+-			       struct mtd_oob_region *oobregion)
+-{
+-	if (section)
+-		return -ERANGE;
+-
+-	oobregion->offset = 2;
+-	oobregion->length = 6;
+-
+-	return 0;
+-}
+-
+-static const struct mtd_ooblayout_ops hisi_ooblayout_ops = {
+-	.ecc = hisi_ooblayout_ecc,
+-	.free = hisi_ooblayout_free,
+-};
+-
+-static int hisi_nfc_ecc_probe(struct hinfc_host *host)
+-{
+-	unsigned int flag;
+-	int size, strength, ecc_bits;
+-	struct device *dev = host->dev;
+-	struct nand_chip *chip = &host->chip;
+-	struct mtd_info *mtd = nand_to_mtd(chip);
+-
+-	size = chip->ecc.size;
+-	strength = chip->ecc.strength;
+-	if (size != 1024) {
+-		dev_err(dev, "error ecc size: %d\n", size);
+-		return -EINVAL;
+-	}
+-
+-	if ((size == 1024) && ((strength != 8) && (strength != 16) &&
+-				(strength != 24) && (strength != 40))) {
+-		dev_err(dev, "ecc size and strength do not match\n");
+-		return -EINVAL;
+-	}
+-
+-	chip->ecc.size = size;
+-	chip->ecc.strength = strength;
+-
+-	chip->ecc.read_page = hisi_nand_read_page_hwecc;
+-	chip->ecc.read_oob = hisi_nand_read_oob;
+-	chip->ecc.write_page = hisi_nand_write_page_hwecc;
+-
+-	switch (chip->ecc.strength) {
+-	case 16:
+-		ecc_bits = 6;
+-		if (mtd->writesize == 2048)
+-			mtd_set_ooblayout(mtd, &hisi_ooblayout_ops);
+-
+-		/* TODO: add more page size support */
+-		break;
+-
+-	/* TODO: add more ecc strength support */
+-	default:
+-		dev_err(dev, "not support strength: %d\n", chip->ecc.strength);
+-		return -EINVAL;
+-	}
+-
+-	flag = hinfc_read(host, HINFC504_CON);
+-	/* add ecc type configure */
+-	flag |= ((ecc_bits & HINFC504_CON_ECCTYPE_MASK)
+-						<< HINFC504_CON_ECCTYPE_SHIFT);
+-	hinfc_write(host, flag, HINFC504_CON);
+-
+-	/* enable ecc irq */
+-	flag = hinfc_read(host, HINFC504_INTEN) & 0xfff;
+-	hinfc_write(host, flag | HINFC504_INTEN_UE | HINFC504_INTEN_CE,
+-		    HINFC504_INTEN);
+-
+-	return 0;
+-}
+-
+-static int hisi_nfc_probe(struct platform_device *pdev)
+-{
+-	int ret = 0, irq, flag, max_chips = HINFC504_MAX_CHIP;
+-	struct device *dev = &pdev->dev;
+-	struct hinfc_host *host;
+-	struct nand_chip  *chip;
+-	struct mtd_info   *mtd;
+-	struct resource	  *res;
+-	struct device_node *np = dev->of_node;
+-
+-	host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL);
+-	if (!host)
+-		return -ENOMEM;
+-	host->dev = dev;
+-
+-	platform_set_drvdata(pdev, host);
+-	chip = &host->chip;
+-	mtd  = nand_to_mtd(chip);
+-
+-	irq = platform_get_irq(pdev, 0);
+-	if (irq < 0) {
+-		dev_err(dev, "no IRQ resource defined\n");
+-		ret = -ENXIO;
+-		goto err_res;
+-	}
+-
+-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+-	host->iobase = devm_ioremap_resource(dev, res);
+-	if (IS_ERR(host->iobase)) {
+-		ret = PTR_ERR(host->iobase);
+-		goto err_res;
+-	}
+-
+-	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+-	host->mmio = devm_ioremap_resource(dev, res);
+-	if (IS_ERR(host->mmio)) {
+-		ret = PTR_ERR(host->mmio);
+-		dev_err(dev, "devm_ioremap_resource[1] fail\n");
+-		goto err_res;
+-	}
+-
+-	mtd->name		= "hisi_nand";
+-	mtd->dev.parent         = &pdev->dev;
+-
+-	nand_set_controller_data(chip, host);
+-	nand_set_flash_node(chip, np);
+-	chip->cmdfunc		= hisi_nfc_cmdfunc;
+-	chip->select_chip	= hisi_nfc_select_chip;
+-	chip->read_byte		= hisi_nfc_read_byte;
+-	chip->read_word		= hisi_nfc_read_word;
+-	chip->write_buf		= hisi_nfc_write_buf;
+-	chip->read_buf		= hisi_nfc_read_buf;
+-	chip->chip_delay	= HINFC504_CHIP_DELAY;
+-	chip->onfi_set_features	= nand_onfi_get_set_features_notsupp;
+-	chip->onfi_get_features	= nand_onfi_get_set_features_notsupp;
+-
+-	hisi_nfc_host_init(host);
+-
+-	ret = devm_request_irq(dev, irq, hinfc_irq_handle, 0x0, "nandc", host);
+-	if (ret) {
+-		dev_err(dev, "failed to request IRQ\n");
+-		goto err_res;
+-	}
+-
+-	ret = nand_scan_ident(mtd, max_chips, NULL);
+-	if (ret)
+-		goto err_res;
+-
+-	host->buffer = dmam_alloc_coherent(dev, mtd->writesize + mtd->oobsize,
+-		&host->dma_buffer, GFP_KERNEL);
+-	if (!host->buffer) {
+-		ret = -ENOMEM;
+-		goto err_res;
+-	}
+-
+-	host->dma_oob = host->dma_buffer + mtd->writesize;
+-	memset(host->buffer, 0xff, mtd->writesize + mtd->oobsize);
+-
+-	flag = hinfc_read(host, HINFC504_CON);
+-	flag &= ~(HINFC504_CON_PAGESIZE_MASK << HINFC504_CON_PAGEISZE_SHIFT);
+-	switch (mtd->writesize) {
+-	case 2048:
+-		flag |= (0x001 << HINFC504_CON_PAGEISZE_SHIFT); break;
+-	/*
+-	 * TODO: add more pagesize support,
+-	 * default pagesize has been set in hisi_nfc_host_init
+-	 */
+-	default:
+-		dev_err(dev, "NON-2KB page size nand flash\n");
+-		ret = -EINVAL;
+-		goto err_res;
+-	}
+-	hinfc_write(host, flag, HINFC504_CON);
+-
+-	if (chip->ecc.mode == NAND_ECC_HW)
+-		hisi_nfc_ecc_probe(host);
+-
+-	ret = nand_scan_tail(mtd);
+-	if (ret) {
+-		dev_err(dev, "nand_scan_tail failed: %d\n", ret);
+-		goto err_res;
+-	}
+-
+-	ret = mtd_device_register(mtd, NULL, 0);
+-	if (ret) {
+-		dev_err(dev, "Err MTD partition=%d\n", ret);
+-		goto err_mtd;
+-	}
+-
+-	return 0;
+-
+-err_mtd:
+-	nand_release(mtd);
+-err_res:
+-	return ret;
+-}
+-
+-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);
+-
+-	nand_release(mtd);
+-
+-	return 0;
+-}
+-
+-#ifdef CONFIG_PM_SLEEP
+-static int hisi_nfc_suspend(struct device *dev)
+-{
+-	struct hinfc_host *host = dev_get_drvdata(dev);
+-	unsigned long timeout = jiffies + HINFC504_NFC_PM_TIMEOUT;
+-
+-	while (time_before(jiffies, timeout)) {
+-		if (((hinfc_read(host, HINFC504_STATUS) & 0x1) == 0x0) &&
+-		    (hinfc_read(host, HINFC504_DMA_CTRL) &
+-		     HINFC504_DMA_CTRL_DMA_START)) {
+-			cond_resched();
+-			return 0;
+-		}
+-	}
+-
+-	dev_err(host->dev, "nand controller suspend timeout.\n");
+-
+-	return -EAGAIN;
+-}
+-
+-static int hisi_nfc_resume(struct device *dev)
+-{
+-	int cs;
+-	struct hinfc_host *host = dev_get_drvdata(dev);
+-	struct nand_chip *chip = &host->chip;
+-
+-	for (cs = 0; cs < chip->numchips; cs++)
+-		hisi_nfc_send_cmd_reset(host, cs);
+-	hinfc_write(host, SET_HINFC504_PWIDTH(HINFC504_W_LATCH,
+-		    HINFC504_R_LATCH, HINFC504_RW_LATCH), HINFC504_PWIDTH);
+-
+-	return 0;
+-}
+-#endif
+-static SIMPLE_DEV_PM_OPS(hisi_nfc_pm_ops, hisi_nfc_suspend, hisi_nfc_resume);
+-
+-static const struct of_device_id nfc_id_table[] = {
+-	{ .compatible = "hisilicon,504-nfc" },
+-	{}
+-};
+-MODULE_DEVICE_TABLE(of, nfc_id_table);
+-
+-static struct platform_driver hisi_nfc_driver = {
+-	.driver = {
+-		.name  = "hisi_nand",
+-		.of_match_table = nfc_id_table,
+-		.pm = &hisi_nfc_pm_ops,
+-	},
+-	.probe		= hisi_nfc_probe,
+-	.remove		= hisi_nfc_remove,
+-};
+-
+-module_platform_driver(hisi_nfc_driver);
+-
+-MODULE_LICENSE("GPL");
+-MODULE_AUTHOR("Zhou Wang");
+-MODULE_AUTHOR("Zhiyong Cai");
+-MODULE_DESCRIPTION("Hisilicon Nand Flash Controller Driver");
+diff --git a/drivers/mtd/nand/jz4740_nand.c b/drivers/mtd/nand/jz4740_nand.c
+deleted file mode 100644
+index ad827d4..0000000
+--- a/drivers/mtd/nand/jz4740_nand.c
++++ /dev/null
+@@ -1,536 +0,0 @@
+-/*
+- *  Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
+- *  JZ4740 SoC NAND controller driver
+- *
+- *  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.
+- *
+- *  You should have received a copy of the GNU General Public License along
+- *  with this program; if not, write to the Free Software Foundation, Inc.,
+- *  675 Mass Ave, Cambridge, MA 02139, USA.
+- *
+- */
+-
+-#include <linux/ioport.h>
+-#include <linux/kernel.h>
+-#include <linux/module.h>
+-#include <linux/platform_device.h>
+-#include <linux/slab.h>
+-
+-#include <linux/mtd/mtd.h>
+-#include <linux/mtd/rawnand.h>
+-#include <linux/mtd/partitions.h>
+-
+-#include <linux/gpio.h>
+-
+-#include <asm/mach-jz4740/jz4740_nand.h>
+-
+-#define JZ_REG_NAND_CTRL	0x50
+-#define JZ_REG_NAND_ECC_CTRL	0x100
+-#define JZ_REG_NAND_DATA	0x104
+-#define JZ_REG_NAND_PAR0	0x108
+-#define JZ_REG_NAND_PAR1	0x10C
+-#define JZ_REG_NAND_PAR2	0x110
+-#define JZ_REG_NAND_IRQ_STAT	0x114
+-#define JZ_REG_NAND_IRQ_CTRL	0x118
+-#define JZ_REG_NAND_ERR(x)	(0x11C + ((x) << 2))
+-
+-#define JZ_NAND_ECC_CTRL_PAR_READY	BIT(4)
+-#define JZ_NAND_ECC_CTRL_ENCODING	BIT(3)
+-#define JZ_NAND_ECC_CTRL_RS		BIT(2)
+-#define JZ_NAND_ECC_CTRL_RESET		BIT(1)
+-#define JZ_NAND_ECC_CTRL_ENABLE		BIT(0)
+-
+-#define JZ_NAND_STATUS_ERR_COUNT	(BIT(31) | BIT(30) | BIT(29))
+-#define JZ_NAND_STATUS_PAD_FINISH	BIT(4)
+-#define JZ_NAND_STATUS_DEC_FINISH	BIT(3)
+-#define JZ_NAND_STATUS_ENC_FINISH	BIT(2)
+-#define JZ_NAND_STATUS_UNCOR_ERROR	BIT(1)
+-#define JZ_NAND_STATUS_ERROR		BIT(0)
+-
+-#define JZ_NAND_CTRL_ENABLE_CHIP(x) BIT((x) << 1)
+-#define JZ_NAND_CTRL_ASSERT_CHIP(x) BIT(((x) << 1) + 1)
+-#define JZ_NAND_CTRL_ASSERT_CHIP_MASK 0xaa
+-
+-#define JZ_NAND_MEM_CMD_OFFSET 0x08000
+-#define JZ_NAND_MEM_ADDR_OFFSET 0x10000
+-
+-struct jz_nand {
+-	struct nand_chip chip;
+-	void __iomem *base;
+-	struct resource *mem;
+-
+-	unsigned char banks[JZ_NAND_NUM_BANKS];
+-	void __iomem *bank_base[JZ_NAND_NUM_BANKS];
+-	struct resource *bank_mem[JZ_NAND_NUM_BANKS];
+-
+-	int selected_bank;
+-
+-	struct gpio_desc *busy_gpio;
+-	bool is_reading;
+-};
+-
+-static inline struct jz_nand *mtd_to_jz_nand(struct mtd_info *mtd)
+-{
+-	return container_of(mtd_to_nand(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);
+-	uint32_t ctrl;
+-	int banknr;
+-
+-	ctrl = readl(nand->base + JZ_REG_NAND_CTRL);
+-	ctrl &= ~JZ_NAND_CTRL_ASSERT_CHIP_MASK;
+-
+-	if (chipnr == -1) {
+-		banknr = -1;
+-	} else {
+-		banknr = nand->banks[chipnr] - 1;
+-		chip->IO_ADDR_R = nand->bank_base[banknr];
+-		chip->IO_ADDR_W = nand->bank_base[banknr];
+-	}
+-	writel(ctrl, nand->base + JZ_REG_NAND_CTRL);
+-
+-	nand->selected_bank = banknr;
+-}
+-
+-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);
+-	uint32_t reg;
+-	void __iomem *bank_base = nand->bank_base[nand->selected_bank];
+-
+-	BUG_ON(nand->selected_bank < 0);
+-
+-	if (ctrl & NAND_CTRL_CHANGE) {
+-		BUG_ON((ctrl & NAND_ALE) && (ctrl & NAND_CLE));
+-		if (ctrl & NAND_ALE)
+-			bank_base += JZ_NAND_MEM_ADDR_OFFSET;
+-		else if (ctrl & NAND_CLE)
+-			bank_base += JZ_NAND_MEM_CMD_OFFSET;
+-		chip->IO_ADDR_W = bank_base;
+-
+-		reg = readl(nand->base + JZ_REG_NAND_CTRL);
+-		if (ctrl & NAND_NCE)
+-			reg |= JZ_NAND_CTRL_ASSERT_CHIP(nand->selected_bank);
+-		else
+-			reg &= ~JZ_NAND_CTRL_ASSERT_CHIP(nand->selected_bank);
+-		writel(reg, nand->base + JZ_REG_NAND_CTRL);
+-	}
+-	if (dat != NAND_CMD_NONE)
+-		writeb(dat, chip->IO_ADDR_W);
+-}
+-
+-static int jz_nand_dev_ready(struct mtd_info *mtd)
+-{
+-	struct jz_nand *nand = mtd_to_jz_nand(mtd);
+-	return gpiod_get_value_cansleep(nand->busy_gpio);
+-}
+-
+-static void jz_nand_hwctl(struct mtd_info *mtd, int mode)
+-{
+-	struct jz_nand *nand = mtd_to_jz_nand(mtd);
+-	uint32_t reg;
+-
+-	writel(0, nand->base + JZ_REG_NAND_IRQ_STAT);
+-	reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL);
+-
+-	reg |= JZ_NAND_ECC_CTRL_RESET;
+-	reg |= JZ_NAND_ECC_CTRL_ENABLE;
+-	reg |= JZ_NAND_ECC_CTRL_RS;
+-
+-	switch (mode) {
+-	case NAND_ECC_READ:
+-		reg &= ~JZ_NAND_ECC_CTRL_ENCODING;
+-		nand->is_reading = true;
+-		break;
+-	case NAND_ECC_WRITE:
+-		reg |= JZ_NAND_ECC_CTRL_ENCODING;
+-		nand->is_reading = false;
+-		break;
+-	default:
+-		break;
+-	}
+-
+-	writel(reg, nand->base + JZ_REG_NAND_ECC_CTRL);
+-}
+-
+-static int jz_nand_calculate_ecc_rs(struct mtd_info *mtd, const uint8_t *dat,
+-	uint8_t *ecc_code)
+-{
+-	struct jz_nand *nand = mtd_to_jz_nand(mtd);
+-	uint32_t reg, status;
+-	int i;
+-	unsigned int timeout = 1000;
+-	static uint8_t empty_block_ecc[] = {0xcd, 0x9d, 0x90, 0x58, 0xf4,
+-						0x8b, 0xff, 0xb7, 0x6f};
+-
+-	if (nand->is_reading)
+-		return 0;
+-
+-	do {
+-		status = readl(nand->base + JZ_REG_NAND_IRQ_STAT);
+-	} while (!(status & JZ_NAND_STATUS_ENC_FINISH) && --timeout);
+-
+-	if (timeout == 0)
+-	    return -1;
+-
+-	reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL);
+-	reg &= ~JZ_NAND_ECC_CTRL_ENABLE;
+-	writel(reg, nand->base + JZ_REG_NAND_ECC_CTRL);
+-
+-	for (i = 0; i < 9; ++i)
+-		ecc_code[i] = readb(nand->base + JZ_REG_NAND_PAR0 + i);
+-
+-	/* If the written data is completly 0xff, we also want to write 0xff as
+-	 * ecc, otherwise we will get in trouble when doing subpage writes. */
+-	if (memcmp(ecc_code, empty_block_ecc, 9) == 0)
+-		memset(ecc_code, 0xff, 9);
+-
+-	return 0;
+-}
+-
+-static void jz_nand_correct_data(uint8_t *dat, int index, int mask)
+-{
+-	int offset = index & 0x7;
+-	uint16_t data;
+-
+-	index += (index >> 3);
+-
+-	data = dat[index];
+-	data |= dat[index+1] << 8;
+-
+-	mask ^= (data >> offset) & 0x1ff;
+-	data &= ~(0x1ff << offset);
+-	data |= (mask << offset);
+-
+-	dat[index] = data & 0xff;
+-	dat[index+1] = (data >> 8) & 0xff;
+-}
+-
+-static int jz_nand_correct_ecc_rs(struct mtd_info *mtd, uint8_t *dat,
+-	uint8_t *read_ecc, uint8_t *calc_ecc)
+-{
+-	struct jz_nand *nand = mtd_to_jz_nand(mtd);
+-	int i, error_count, index;
+-	uint32_t reg, status, error;
+-	unsigned int timeout = 1000;
+-
+-	for (i = 0; i < 9; ++i)
+-		writeb(read_ecc[i], nand->base + JZ_REG_NAND_PAR0 + i);
+-
+-	reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL);
+-	reg |= JZ_NAND_ECC_CTRL_PAR_READY;
+-	writel(reg, nand->base + JZ_REG_NAND_ECC_CTRL);
+-
+-	do {
+-		status = readl(nand->base + JZ_REG_NAND_IRQ_STAT);
+-	} while (!(status & JZ_NAND_STATUS_DEC_FINISH) && --timeout);
+-
+-	if (timeout == 0)
+-		return -ETIMEDOUT;
+-
+-	reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL);
+-	reg &= ~JZ_NAND_ECC_CTRL_ENABLE;
+-	writel(reg, nand->base + JZ_REG_NAND_ECC_CTRL);
+-
+-	if (status & JZ_NAND_STATUS_ERROR) {
+-		if (status & JZ_NAND_STATUS_UNCOR_ERROR)
+-			return -EBADMSG;
+-
+-		error_count = (status & JZ_NAND_STATUS_ERR_COUNT) >> 29;
+-
+-		for (i = 0; i < error_count; ++i) {
+-			error = readl(nand->base + JZ_REG_NAND_ERR(i));
+-			index = ((error >> 16) & 0x1ff) - 1;
+-			if (index >= 0 && index < 512)
+-				jz_nand_correct_data(dat, index, error & 0x1ff);
+-		}
+-
+-		return error_count;
+-	}
+-
+-	return 0;
+-}
+-
+-static int jz_nand_ioremap_resource(struct platform_device *pdev,
+-	const char *name, struct resource **res, void *__iomem *base)
+-{
+-	int ret;
+-
+-	*res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
+-	if (!*res) {
+-		dev_err(&pdev->dev, "Failed to get platform %s memory\n", name);
+-		ret = -ENXIO;
+-		goto err;
+-	}
+-
+-	*res = request_mem_region((*res)->start, resource_size(*res),
+-				pdev->name);
+-	if (!*res) {
+-		dev_err(&pdev->dev, "Failed to request %s memory region\n", name);
+-		ret = -EBUSY;
+-		goto err;
+-	}
+-
+-	*base = ioremap((*res)->start, resource_size(*res));
+-	if (!*base) {
+-		dev_err(&pdev->dev, "Failed to ioremap %s memory region\n", name);
+-		ret = -EBUSY;
+-		goto err_release_mem;
+-	}
+-
+-	return 0;
+-
+-err_release_mem:
+-	release_mem_region((*res)->start, resource_size(*res));
+-err:
+-	*res = NULL;
+-	*base = NULL;
+-	return ret;
+-}
+-
+-static inline void jz_nand_iounmap_resource(struct resource *res,
+-					    void __iomem *base)
+-{
+-	iounmap(base);
+-	release_mem_region(res->start, resource_size(res));
+-}
+-
+-static int jz_nand_detect_bank(struct platform_device *pdev,
+-			       struct jz_nand *nand, unsigned char bank,
+-			       size_t chipnr, uint8_t *nand_maf_id,
+-			       uint8_t *nand_dev_id)
+-{
+-	int ret;
+-	char res_name[6];
+-	uint32_t ctrl;
+-	struct nand_chip *chip = &nand->chip;
+-	struct mtd_info *mtd = nand_to_mtd(chip);
+-
+-	/* Request I/O resource. */
+-	sprintf(res_name, "bank%d", bank);
+-	ret = jz_nand_ioremap_resource(pdev, res_name,
+-					&nand->bank_mem[bank - 1],
+-					&nand->bank_base[bank - 1]);
+-	if (ret)
+-		return ret;
+-
+-	/* Enable chip in bank. */
+-	ctrl = readl(nand->base + JZ_REG_NAND_CTRL);
+-	ctrl |= JZ_NAND_CTRL_ENABLE_CHIP(bank - 1);
+-	writel(ctrl, nand->base + JZ_REG_NAND_CTRL);
+-
+-	if (chipnr == 0) {
+-		/* Detect first chip. */
+-		ret = nand_scan_ident(mtd, 1, NULL);
+-		if (ret)
+-			goto notfound_id;
+-
+-		/* Retrieve the IDs from the first chip. */
+-		chip->select_chip(mtd, 0);
+-		chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
+-		chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
+-		*nand_maf_id = chip->read_byte(mtd);
+-		*nand_dev_id = chip->read_byte(mtd);
+-	} else {
+-		/* Detect additional chip. */
+-		chip->select_chip(mtd, chipnr);
+-		chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
+-		chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
+-		if (*nand_maf_id != chip->read_byte(mtd)
+-		 || *nand_dev_id != chip->read_byte(mtd)) {
+-			ret = -ENODEV;
+-			goto notfound_id;
+-		}
+-
+-		/* Update size of the MTD. */
+-		chip->numchips++;
+-		mtd->size += chip->chipsize;
+-	}
+-
+-	dev_info(&pdev->dev, "Found chip %i on bank %i\n", chipnr, bank);
+-	return 0;
+-
+-notfound_id:
+-	dev_info(&pdev->dev, "No chip found on bank %i\n", bank);
+-	ctrl &= ~(JZ_NAND_CTRL_ENABLE_CHIP(bank - 1));
+-	writel(ctrl, nand->base + JZ_REG_NAND_CTRL);
+-	jz_nand_iounmap_resource(nand->bank_mem[bank - 1],
+-				 nand->bank_base[bank - 1]);
+-	return ret;
+-}
+-
+-static int jz_nand_probe(struct platform_device *pdev)
+-{
+-	int ret;
+-	struct jz_nand *nand;
+-	struct nand_chip *chip;
+-	struct mtd_info *mtd;
+-	struct jz_nand_platform_data *pdata = dev_get_platdata(&pdev->dev);
+-	size_t chipnr, bank_idx;
+-	uint8_t nand_maf_id = 0, nand_dev_id = 0;
+-
+-	nand = kzalloc(sizeof(*nand), GFP_KERNEL);
+-	if (!nand)
+-		return -ENOMEM;
+-
+-	ret = jz_nand_ioremap_resource(pdev, "mmio", &nand->mem, &nand->base);
+-	if (ret)
+-		goto err_free;
+-
+-	nand->busy_gpio = devm_gpiod_get_optional(&pdev->dev, "busy", GPIOD_IN);
+-	if (IS_ERR(nand->busy_gpio)) {
+-		ret = PTR_ERR(nand->busy_gpio);
+-		dev_err(&pdev->dev, "Failed to request busy gpio %d\n",
+-		    ret);
+-		goto err_iounmap_mmio;
+-	}
+-
+-	chip		= &nand->chip;
+-	mtd		= nand_to_mtd(chip);
+-	mtd->dev.parent = &pdev->dev;
+-	mtd->name	= "jz4740-nand";
+-
+-	chip->ecc.hwctl		= jz_nand_hwctl;
+-	chip->ecc.calculate	= jz_nand_calculate_ecc_rs;
+-	chip->ecc.correct	= jz_nand_correct_ecc_rs;
+-	chip->ecc.mode		= NAND_ECC_HW_OOB_FIRST;
+-	chip->ecc.size		= 512;
+-	chip->ecc.bytes		= 9;
+-	chip->ecc.strength	= 4;
+-	chip->ecc.options	= NAND_ECC_GENERIC_ERASED_CHECK;
+-
+-	chip->chip_delay = 50;
+-	chip->cmd_ctrl = jz_nand_cmd_ctrl;
+-	chip->select_chip = jz_nand_select_chip;
+-
+-	if (nand->busy_gpio)
+-		chip->dev_ready = jz_nand_dev_ready;
+-
+-	platform_set_drvdata(pdev, nand);
+-
+-	/* We are going to autodetect NAND chips in the banks specified in the
+-	 * platform data. Although nand_scan_ident() can detect multiple chips,
+-	 * it requires those chips to be numbered consecuitively, which is not
+-	 * always the case for external memory banks. And a fixed chip-to-bank
+-	 * mapping is not practical either, since for example Dingoo units
+-	 * produced at different times have NAND chips in different banks.
+-	 */
+-	chipnr = 0;
+-	for (bank_idx = 0; bank_idx < JZ_NAND_NUM_BANKS; bank_idx++) {
+-		unsigned char bank;
+-
+-		/* If there is no platform data, look for NAND in bank 1,
+-		 * which is the most likely bank since it is the only one
+-		 * that can be booted from.
+-		 */
+-		bank = pdata ? pdata->banks[bank_idx] : bank_idx ^ 1;
+-		if (bank == 0)
+-			break;
+-		if (bank > JZ_NAND_NUM_BANKS) {
+-			dev_warn(&pdev->dev,
+-				"Skipping non-existing bank: %d\n", bank);
+-			continue;
+-		}
+-		/* The detection routine will directly or indirectly call
+-		 * jz_nand_select_chip(), so nand->banks has to contain the
+-		 * bank we're checking.
+-		 */
+-		nand->banks[chipnr] = bank;
+-		if (jz_nand_detect_bank(pdev, nand, bank, chipnr,
+-					&nand_maf_id, &nand_dev_id) == 0)
+-			chipnr++;
+-		else
+-			nand->banks[chipnr] = 0;
+-	}
+-	if (chipnr == 0) {
+-		dev_err(&pdev->dev, "No NAND chips found\n");
+-		goto err_iounmap_mmio;
+-	}
+-
+-	if (pdata && pdata->ident_callback) {
+-		pdata->ident_callback(pdev, mtd, &pdata->partitions,
+-					&pdata->num_partitions);
+-	}
+-
+-	ret = nand_scan_tail(mtd);
+-	if (ret) {
+-		dev_err(&pdev->dev,  "Failed to scan NAND\n");
+-		goto err_unclaim_banks;
+-	}
+-
+-	ret = mtd_device_parse_register(mtd, NULL, NULL,
+-					pdata ? pdata->partitions : NULL,
+-					pdata ? pdata->num_partitions : 0);
+-
+-	if (ret) {
+-		dev_err(&pdev->dev, "Failed to add mtd device\n");
+-		goto err_nand_release;
+-	}
+-
+-	dev_info(&pdev->dev, "Successfully registered JZ4740 NAND driver\n");
+-
+-	return 0;
+-
+-err_nand_release:
+-	nand_release(mtd);
+-err_unclaim_banks:
+-	while (chipnr--) {
+-		unsigned char bank = nand->banks[chipnr];
+-		jz_nand_iounmap_resource(nand->bank_mem[bank - 1],
+-					 nand->bank_base[bank - 1]);
+-	}
+-	writel(0, nand->base + JZ_REG_NAND_CTRL);
+-err_iounmap_mmio:
+-	jz_nand_iounmap_resource(nand->mem, nand->base);
+-err_free:
+-	kfree(nand);
+-	return ret;
+-}
+-
+-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));
+-
+-	/* Deassert and disable all chips */
+-	writel(0, nand->base + JZ_REG_NAND_CTRL);
+-
+-	for (i = 0; i < JZ_NAND_NUM_BANKS; ++i) {
+-		unsigned char bank = nand->banks[i];
+-		if (bank != 0) {
+-			jz_nand_iounmap_resource(nand->bank_mem[bank - 1],
+-						 nand->bank_base[bank - 1]);
+-		}
+-	}
+-
+-	jz_nand_iounmap_resource(nand->mem, nand->base);
+-
+-	kfree(nand);
+-
+-	return 0;
+-}
+-
+-static struct platform_driver jz_nand_driver = {
+-	.probe = jz_nand_probe,
+-	.remove = jz_nand_remove,
+-	.driver = {
+-		.name = "jz4740-nand",
+-	},
+-};
+-
+-module_platform_driver(jz_nand_driver);
+-
+-MODULE_LICENSE("GPL");
+-MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+-MODULE_DESCRIPTION("NAND controller driver for JZ4740 SoC");
+-MODULE_ALIAS("platform:jz4740-nand");
+diff --git a/drivers/mtd/nand/jz4780_bch.c b/drivers/mtd/nand/jz4780_bch.c
+deleted file mode 100644
+index 731c605..0000000
+--- a/drivers/mtd/nand/jz4780_bch.c
++++ /dev/null
+@@ -1,380 +0,0 @@
+-/*
+- * JZ4780 BCH controller
+- *
+- * Copyright (c) 2015 Imagination Technologies
+- * Author: Alex Smith <alex.smith@imgtec.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/bitops.h>
+-#include <linux/clk.h>
+-#include <linux/delay.h>
+-#include <linux/init.h>
+-#include <linux/iopoll.h>
+-#include <linux/module.h>
+-#include <linux/mutex.h>
+-#include <linux/of.h>
+-#include <linux/of_platform.h>
+-#include <linux/platform_device.h>
+-#include <linux/sched.h>
+-#include <linux/slab.h>
+-
+-#include "jz4780_bch.h"
+-
+-#define BCH_BHCR			0x0
+-#define BCH_BHCCR			0x8
+-#define BCH_BHCNT			0xc
+-#define BCH_BHDR			0x10
+-#define BCH_BHPAR0			0x14
+-#define BCH_BHERR0			0x84
+-#define BCH_BHINT			0x184
+-#define BCH_BHINTES			0x188
+-#define BCH_BHINTEC			0x18c
+-#define BCH_BHINTE			0x190
+-
+-#define BCH_BHCR_BSEL_SHIFT		4
+-#define BCH_BHCR_BSEL_MASK		(0x7f << BCH_BHCR_BSEL_SHIFT)
+-#define BCH_BHCR_ENCE			BIT(2)
+-#define BCH_BHCR_INIT			BIT(1)
+-#define BCH_BHCR_BCHE			BIT(0)
+-
+-#define BCH_BHCNT_PARITYSIZE_SHIFT	16
+-#define BCH_BHCNT_PARITYSIZE_MASK	(0x7f << BCH_BHCNT_PARITYSIZE_SHIFT)
+-#define BCH_BHCNT_BLOCKSIZE_SHIFT	0
+-#define BCH_BHCNT_BLOCKSIZE_MASK	(0x7ff << BCH_BHCNT_BLOCKSIZE_SHIFT)
+-
+-#define BCH_BHERR_MASK_SHIFT		16
+-#define BCH_BHERR_MASK_MASK		(0xffff << BCH_BHERR_MASK_SHIFT)
+-#define BCH_BHERR_INDEX_SHIFT		0
+-#define BCH_BHERR_INDEX_MASK		(0x7ff << BCH_BHERR_INDEX_SHIFT)
+-
+-#define BCH_BHINT_ERRC_SHIFT		24
+-#define BCH_BHINT_ERRC_MASK		(0x7f << BCH_BHINT_ERRC_SHIFT)
+-#define BCH_BHINT_TERRC_SHIFT		16
+-#define BCH_BHINT_TERRC_MASK		(0x7f << BCH_BHINT_TERRC_SHIFT)
+-#define BCH_BHINT_DECF			BIT(3)
+-#define BCH_BHINT_ENCF			BIT(2)
+-#define BCH_BHINT_UNCOR			BIT(1)
+-#define BCH_BHINT_ERR			BIT(0)
+-
+-#define BCH_CLK_RATE			(200 * 1000 * 1000)
+-
+-/* Timeout for BCH calculation/correction. */
+-#define BCH_TIMEOUT_US			100000
+-
+-struct jz4780_bch {
+-	struct device *dev;
+-	void __iomem *base;
+-	struct clk *clk;
+-	struct mutex lock;
+-};
+-
+-static void jz4780_bch_init(struct jz4780_bch *bch,
+-			    struct jz4780_bch_params *params, bool encode)
+-{
+-	u32 reg;
+-
+-	/* Clear interrupt status. */
+-	writel(readl(bch->base + BCH_BHINT), bch->base + BCH_BHINT);
+-
+-	/* Set up BCH count register. */
+-	reg = params->size << BCH_BHCNT_BLOCKSIZE_SHIFT;
+-	reg |= params->bytes << BCH_BHCNT_PARITYSIZE_SHIFT;
+-	writel(reg, bch->base + BCH_BHCNT);
+-
+-	/* Initialise and enable BCH. */
+-	reg = BCH_BHCR_BCHE | BCH_BHCR_INIT;
+-	reg |= params->strength << BCH_BHCR_BSEL_SHIFT;
+-	if (encode)
+-		reg |= BCH_BHCR_ENCE;
+-	writel(reg, bch->base + BCH_BHCR);
+-}
+-
+-static void jz4780_bch_disable(struct jz4780_bch *bch)
+-{
+-	writel(readl(bch->base + BCH_BHINT), bch->base + BCH_BHINT);
+-	writel(BCH_BHCR_BCHE, bch->base + BCH_BHCCR);
+-}
+-
+-static void jz4780_bch_write_data(struct jz4780_bch *bch, const void *buf,
+-				  size_t size)
+-{
+-	size_t size32 = size / sizeof(u32);
+-	size_t size8 = size % sizeof(u32);
+-	const u32 *src32;
+-	const u8 *src8;
+-
+-	src32 = (const u32 *)buf;
+-	while (size32--)
+-		writel(*src32++, bch->base + BCH_BHDR);
+-
+-	src8 = (const u8 *)src32;
+-	while (size8--)
+-		writeb(*src8++, bch->base + BCH_BHDR);
+-}
+-
+-static void jz4780_bch_read_parity(struct jz4780_bch *bch, void *buf,
+-				   size_t size)
+-{
+-	size_t size32 = size / sizeof(u32);
+-	size_t size8 = size % sizeof(u32);
+-	u32 *dest32;
+-	u8 *dest8;
+-	u32 val, offset = 0;
+-
+-	dest32 = (u32 *)buf;
+-	while (size32--) {
+-		*dest32++ = readl(bch->base + BCH_BHPAR0 + offset);
+-		offset += sizeof(u32);
+-	}
+-
+-	dest8 = (u8 *)dest32;
+-	val = readl(bch->base + BCH_BHPAR0 + offset);
+-	switch (size8) {
+-	case 3:
+-		dest8[2] = (val >> 16) & 0xff;
+-	case 2:
+-		dest8[1] = (val >> 8) & 0xff;
+-	case 1:
+-		dest8[0] = val & 0xff;
+-		break;
+-	}
+-}
+-
+-static bool jz4780_bch_wait_complete(struct jz4780_bch *bch, unsigned int irq,
+-				     u32 *status)
+-{
+-	u32 reg;
+-	int ret;
+-
+-	/*
+-	 * While we could use interrupts here and sleep until the operation
+-	 * completes, the controller works fairly quickly (usually a few
+-	 * microseconds) and so the overhead of sleeping until we get an
+-	 * interrupt quite noticeably decreases performance.
+-	 */
+-	ret = readl_poll_timeout(bch->base + BCH_BHINT, reg,
+-				 (reg & irq) == irq, 0, BCH_TIMEOUT_US);
+-	if (ret)
+-		return false;
+-
+-	if (status)
+-		*status = reg;
+-
+-	writel(reg, bch->base + BCH_BHINT);
+-	return true;
+-}
+-
+-/**
+- * jz4780_bch_calculate() - calculate ECC for a data buffer
+- * @bch: BCH device.
+- * @params: BCH parameters.
+- * @buf: input buffer with raw data.
+- * @ecc_code: output buffer with ECC.
+- *
+- * Return: 0 on success, -ETIMEDOUT if timed out while waiting for BCH
+- * controller.
+- */
+-int jz4780_bch_calculate(struct jz4780_bch *bch, struct jz4780_bch_params *params,
+-			 const u8 *buf, u8 *ecc_code)
+-{
+-	int ret = 0;
+-
+-	mutex_lock(&bch->lock);
+-	jz4780_bch_init(bch, params, true);
+-	jz4780_bch_write_data(bch, buf, params->size);
+-
+-	if (jz4780_bch_wait_complete(bch, BCH_BHINT_ENCF, NULL)) {
+-		jz4780_bch_read_parity(bch, ecc_code, params->bytes);
+-	} else {
+-		dev_err(bch->dev, "timed out while calculating ECC\n");
+-		ret = -ETIMEDOUT;
+-	}
+-
+-	jz4780_bch_disable(bch);
+-	mutex_unlock(&bch->lock);
+-	return ret;
+-}
+-EXPORT_SYMBOL(jz4780_bch_calculate);
+-
+-/**
+- * jz4780_bch_correct() - detect and correct bit errors
+- * @bch: BCH device.
+- * @params: BCH parameters.
+- * @buf: raw data read from the chip.
+- * @ecc_code: ECC read from the chip.
+- *
+- * Given the raw data and the ECC read from the NAND device, detects and
+- * corrects errors in the data.
+- *
+- * Return: the number of bit errors corrected, -EBADMSG if there are too many
+- * errors to correct or -ETIMEDOUT if we timed out waiting for the controller.
+- */
+-int jz4780_bch_correct(struct jz4780_bch *bch, struct jz4780_bch_params *params,
+-		       u8 *buf, u8 *ecc_code)
+-{
+-	u32 reg, mask, index;
+-	int i, ret, count;
+-
+-	mutex_lock(&bch->lock);
+-
+-	jz4780_bch_init(bch, params, false);
+-	jz4780_bch_write_data(bch, buf, params->size);
+-	jz4780_bch_write_data(bch, ecc_code, params->bytes);
+-
+-	if (!jz4780_bch_wait_complete(bch, BCH_BHINT_DECF, &reg)) {
+-		dev_err(bch->dev, "timed out while correcting data\n");
+-		ret = -ETIMEDOUT;
+-		goto out;
+-	}
+-
+-	if (reg & BCH_BHINT_UNCOR) {
+-		dev_warn(bch->dev, "uncorrectable ECC error\n");
+-		ret = -EBADMSG;
+-		goto out;
+-	}
+-
+-	/* Correct any detected errors. */
+-	if (reg & BCH_BHINT_ERR) {
+-		count = (reg & BCH_BHINT_ERRC_MASK) >> BCH_BHINT_ERRC_SHIFT;
+-		ret = (reg & BCH_BHINT_TERRC_MASK) >> BCH_BHINT_TERRC_SHIFT;
+-
+-		for (i = 0; i < count; i++) {
+-			reg = readl(bch->base + BCH_BHERR0 + (i * 4));
+-			mask = (reg & BCH_BHERR_MASK_MASK) >>
+-						BCH_BHERR_MASK_SHIFT;
+-			index = (reg & BCH_BHERR_INDEX_MASK) >>
+-						BCH_BHERR_INDEX_SHIFT;
+-			buf[(index * 2) + 0] ^= mask;
+-			buf[(index * 2) + 1] ^= mask >> 8;
+-		}
+-	} else {
+-		ret = 0;
+-	}
+-
+-out:
+-	jz4780_bch_disable(bch);
+-	mutex_unlock(&bch->lock);
+-	return ret;
+-}
+-EXPORT_SYMBOL(jz4780_bch_correct);
+-
+-/**
+- * jz4780_bch_get() - get the BCH controller device
+- * @np: BCH device tree node.
+- *
+- * Gets the BCH controller device from the specified device tree node. The
+- * device must be released with jz4780_bch_release() when it is no longer being
+- * used.
+- *
+- * Return: a pointer to jz4780_bch, errors are encoded into the pointer.
+- * PTR_ERR(-EPROBE_DEFER) if the device hasn't been initialised yet.
+- */
+-static struct jz4780_bch *jz4780_bch_get(struct device_node *np)
+-{
+-	struct platform_device *pdev;
+-	struct jz4780_bch *bch;
+-
+-	pdev = of_find_device_by_node(np);
+-	if (!pdev || !platform_get_drvdata(pdev))
+-		return ERR_PTR(-EPROBE_DEFER);
+-
+-	get_device(&pdev->dev);
+-
+-	bch = platform_get_drvdata(pdev);
+-	clk_prepare_enable(bch->clk);
+-
+-	return bch;
+-}
+-
+-/**
+- * of_jz4780_bch_get() - get the BCH controller from a DT node
+- * @of_node: the node that contains a bch-controller property.
+- *
+- * Get the bch-controller property from the given device tree
+- * node and pass it to jz4780_bch_get to do the work.
+- *
+- * Return: a pointer to jz4780_bch, errors are encoded into the pointer.
+- * PTR_ERR(-EPROBE_DEFER) if the device hasn't been initialised yet.
+- */
+-struct jz4780_bch *of_jz4780_bch_get(struct device_node *of_node)
+-{
+-	struct jz4780_bch *bch = NULL;
+-	struct device_node *np;
+-
+-	np = of_parse_phandle(of_node, "ingenic,bch-controller", 0);
+-
+-	if (np) {
+-		bch = jz4780_bch_get(np);
+-		of_node_put(np);
+-	}
+-	return bch;
+-}
+-EXPORT_SYMBOL(of_jz4780_bch_get);
+-
+-/**
+- * jz4780_bch_release() - release the BCH controller device
+- * @bch: BCH device.
+- */
+-void jz4780_bch_release(struct jz4780_bch *bch)
+-{
+-	clk_disable_unprepare(bch->clk);
+-	put_device(bch->dev);
+-}
+-EXPORT_SYMBOL(jz4780_bch_release);
+-
+-static int jz4780_bch_probe(struct platform_device *pdev)
+-{
+-	struct device *dev = &pdev->dev;
+-	struct jz4780_bch *bch;
+-	struct resource *res;
+-
+-	bch = devm_kzalloc(dev, sizeof(*bch), GFP_KERNEL);
+-	if (!bch)
+-		return -ENOMEM;
+-
+-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+-	bch->base = devm_ioremap_resource(dev, res);
+-	if (IS_ERR(bch->base))
+-		return PTR_ERR(bch->base);
+-
+-	jz4780_bch_disable(bch);
+-
+-	bch->clk = devm_clk_get(dev, NULL);
+-	if (IS_ERR(bch->clk)) {
+-		dev_err(dev, "failed to get clock: %ld\n", PTR_ERR(bch->clk));
+-		return PTR_ERR(bch->clk);
+-	}
+-
+-	clk_set_rate(bch->clk, BCH_CLK_RATE);
+-
+-	mutex_init(&bch->lock);
+-
+-	bch->dev = dev;
+-	platform_set_drvdata(pdev, bch);
+-
+-	return 0;
+-}
+-
+-static const struct of_device_id jz4780_bch_dt_match[] = {
+-	{ .compatible = "ingenic,jz4780-bch" },
+-	{},
+-};
+-MODULE_DEVICE_TABLE(of, jz4780_bch_dt_match);
+-
+-static struct platform_driver jz4780_bch_driver = {
+-	.probe		= jz4780_bch_probe,
+-	.driver	= {
+-		.name	= "jz4780-bch",
+-		.of_match_table = of_match_ptr(jz4780_bch_dt_match),
+-	},
+-};
+-module_platform_driver(jz4780_bch_driver);
+-
+-MODULE_AUTHOR("Alex Smith <alex@alex-smith.me.uk>");
+-MODULE_AUTHOR("Harvey Hunt <harveyhuntnexus@gmail.com>");
+-MODULE_DESCRIPTION("Ingenic JZ4780 BCH error correction driver");
+-MODULE_LICENSE("GPL v2");
+diff --git a/drivers/mtd/nand/jz4780_bch.h b/drivers/mtd/nand/jz4780_bch.h
+deleted file mode 100644
+index bf471808..0000000
+--- a/drivers/mtd/nand/jz4780_bch.h
++++ /dev/null
+@@ -1,43 +0,0 @@
+-/*
+- * JZ4780 BCH controller
+- *
+- * Copyright (c) 2015 Imagination Technologies
+- * Author: Alex Smith <alex.smith@imgtec.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 __DRIVERS_MTD_NAND_JZ4780_BCH_H__
+-#define __DRIVERS_MTD_NAND_JZ4780_BCH_H__
+-
+-#include <linux/types.h>
+-
+-struct device;
+-struct device_node;
+-struct jz4780_bch;
+-
+-/**
+- * struct jz4780_bch_params - BCH parameters
+- * @size: data bytes per ECC step.
+- * @bytes: ECC bytes per step.
+- * @strength: number of correctable bits per ECC step.
+- */
+-struct jz4780_bch_params {
+-	int size;
+-	int bytes;
+-	int strength;
+-};
+-
+-int jz4780_bch_calculate(struct jz4780_bch *bch,
+-				struct jz4780_bch_params *params,
+-				const u8 *buf, u8 *ecc_code);
+-int jz4780_bch_correct(struct jz4780_bch *bch,
+-			      struct jz4780_bch_params *params, u8 *buf,
+-			      u8 *ecc_code);
+-
+-void jz4780_bch_release(struct jz4780_bch *bch);
+-struct jz4780_bch *of_jz4780_bch_get(struct device_node *np);
+-
+-#endif /* __DRIVERS_MTD_NAND_JZ4780_BCH_H__ */
+diff --git a/drivers/mtd/nand/jz4780_nand.c b/drivers/mtd/nand/jz4780_nand.c
+deleted file mode 100644
+index e69f6ae..0000000
+--- a/drivers/mtd/nand/jz4780_nand.c
++++ /dev/null
+@@ -1,416 +0,0 @@
+-/*
+- * JZ4780 NAND driver
+- *
+- * Copyright (c) 2015 Imagination Technologies
+- * Author: Alex Smith <alex.smith@imgtec.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/delay.h>
+-#include <linux/init.h>
+-#include <linux/io.h>
+-#include <linux/list.h>
+-#include <linux/module.h>
+-#include <linux/of.h>
+-#include <linux/of_address.h>
+-#include <linux/gpio/consumer.h>
+-#include <linux/platform_device.h>
+-#include <linux/slab.h>
+-#include <linux/mtd/mtd.h>
+-#include <linux/mtd/rawnand.h>
+-#include <linux/mtd/partitions.h>
+-
+-#include <linux/jz4780-nemc.h>
+-
+-#include "jz4780_bch.h"
+-
+-#define DRV_NAME	"jz4780-nand"
+-
+-#define OFFSET_DATA	0x00000000
+-#define OFFSET_CMD	0x00400000
+-#define OFFSET_ADDR	0x00800000
+-
+-/* Command delay when there is no R/B pin. */
+-#define RB_DELAY_US	100
+-
+-struct jz4780_nand_cs {
+-	unsigned int bank;
+-	void __iomem *base;
+-};
+-
+-struct jz4780_nand_controller {
+-	struct device *dev;
+-	struct jz4780_bch *bch;
+-	struct nand_hw_control controller;
+-	unsigned int num_banks;
+-	struct list_head chips;
+-	int selected;
+-	struct jz4780_nand_cs cs[];
+-};
+-
+-struct jz4780_nand_chip {
+-	struct nand_chip chip;
+-	struct list_head chip_list;
+-
+-	struct gpio_desc *busy_gpio;
+-	struct gpio_desc *wp_gpio;
+-	unsigned int reading: 1;
+-};
+-
+-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);
+-}
+-
+-static inline struct jz4780_nand_controller *to_jz4780_nand_controller(struct nand_hw_control *ctrl)
+-{
+-	return container_of(ctrl, struct jz4780_nand_controller, controller);
+-}
+-
+-static void jz4780_nand_select_chip(struct mtd_info *mtd, int chipnr)
+-{
+-	struct jz4780_nand_chip *nand = to_jz4780_nand_chip(mtd);
+-	struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(nand->chip.controller);
+-	struct jz4780_nand_cs *cs;
+-
+-	/* Ensure the currently selected chip is deasserted. */
+-	if (chipnr == -1 && nfc->selected >= 0) {
+-		cs = &nfc->cs[nfc->selected];
+-		jz4780_nemc_assert(nfc->dev, cs->bank, false);
+-	}
+-
+-	nfc->selected = chipnr;
+-}
+-
+-static void jz4780_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
+-				 unsigned int ctrl)
+-{
+-	struct jz4780_nand_chip *nand = to_jz4780_nand_chip(mtd);
+-	struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(nand->chip.controller);
+-	struct jz4780_nand_cs *cs;
+-
+-	if (WARN_ON(nfc->selected < 0))
+-		return;
+-
+-	cs = &nfc->cs[nfc->selected];
+-
+-	jz4780_nemc_assert(nfc->dev, cs->bank, ctrl & NAND_NCE);
+-
+-	if (cmd == NAND_CMD_NONE)
+-		return;
+-
+-	if (ctrl & NAND_ALE)
+-		writeb(cmd, cs->base + OFFSET_ADDR);
+-	else if (ctrl & NAND_CLE)
+-		writeb(cmd, cs->base + OFFSET_CMD);
+-}
+-
+-static int jz4780_nand_dev_ready(struct mtd_info *mtd)
+-{
+-	struct jz4780_nand_chip *nand = to_jz4780_nand_chip(mtd);
+-
+-	return !gpiod_get_value_cansleep(nand->busy_gpio);
+-}
+-
+-static void jz4780_nand_ecc_hwctl(struct mtd_info *mtd, int mode)
+-{
+-	struct jz4780_nand_chip *nand = to_jz4780_nand_chip(mtd);
+-
+-	nand->reading = (mode == NAND_ECC_READ);
+-}
+-
+-static int jz4780_nand_ecc_calculate(struct mtd_info *mtd, const u8 *dat,
+-				     u8 *ecc_code)
+-{
+-	struct jz4780_nand_chip *nand = to_jz4780_nand_chip(mtd);
+-	struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(nand->chip.controller);
+-	struct jz4780_bch_params params;
+-
+-	/*
+-	 * Don't need to generate the ECC when reading, BCH does it for us as
+-	 * part of decoding/correction.
+-	 */
+-	if (nand->reading)
+-		return 0;
+-
+-	params.size = nand->chip.ecc.size;
+-	params.bytes = nand->chip.ecc.bytes;
+-	params.strength = nand->chip.ecc.strength;
+-
+-	return jz4780_bch_calculate(nfc->bch, &params, dat, ecc_code);
+-}
+-
+-static int jz4780_nand_ecc_correct(struct mtd_info *mtd, u8 *dat,
+-				   u8 *read_ecc, u8 *calc_ecc)
+-{
+-	struct jz4780_nand_chip *nand = to_jz4780_nand_chip(mtd);
+-	struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(nand->chip.controller);
+-	struct jz4780_bch_params params;
+-
+-	params.size = nand->chip.ecc.size;
+-	params.bytes = nand->chip.ecc.bytes;
+-	params.strength = nand->chip.ecc.strength;
+-
+-	return jz4780_bch_correct(nfc->bch, &params, dat, read_ecc);
+-}
+-
+-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 jz4780_nand_controller *nfc = to_jz4780_nand_controller(chip->controller);
+-	int eccbytes;
+-
+-	chip->ecc.bytes = fls((1 + 8) * chip->ecc.size)	*
+-				(chip->ecc.strength / 8);
+-
+-	switch (chip->ecc.mode) {
+-	case NAND_ECC_HW:
+-		if (!nfc->bch) {
+-			dev_err(dev, "HW BCH selected, but BCH controller not found\n");
+-			return -ENODEV;
+-		}
+-
+-		chip->ecc.hwctl = jz4780_nand_ecc_hwctl;
+-		chip->ecc.calculate = jz4780_nand_ecc_calculate;
+-		chip->ecc.correct = jz4780_nand_ecc_correct;
+-		/* fall through */
+-	case NAND_ECC_SOFT:
+-		dev_info(dev, "using %s (strength %d, size %d, bytes %d)\n",
+-			(nfc->bch) ? "hardware BCH" : "software ECC",
+-			chip->ecc.strength, chip->ecc.size, chip->ecc.bytes);
+-		break;
+-	case NAND_ECC_NONE:
+-		dev_info(dev, "not using ECC\n");
+-		break;
+-	default:
+-		dev_err(dev, "ECC mode %d not supported\n", chip->ecc.mode);
+-		return -EINVAL;
+-	}
+-
+-	/* The NAND core will generate the ECC layout for SW ECC */
+-	if (chip->ecc.mode != NAND_ECC_HW)
+-		return 0;
+-
+-	/* Generate ECC layout. ECC codes are right aligned in the OOB area. */
+-	eccbytes = mtd->writesize / chip->ecc.size * chip->ecc.bytes;
+-
+-	if (eccbytes > mtd->oobsize - 2) {
+-		dev_err(dev,
+-			"invalid ECC config: required %d ECC bytes, but only %d are available",
+-			eccbytes, mtd->oobsize - 2);
+-		return -EINVAL;
+-	}
+-
+-	mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
+-
+-	return 0;
+-}
+-
+-static int jz4780_nand_init_chip(struct platform_device *pdev,
+-				struct jz4780_nand_controller *nfc,
+-				struct device_node *np,
+-				unsigned int chipnr)
+-{
+-	struct device *dev = &pdev->dev;
+-	struct jz4780_nand_chip *nand;
+-	struct jz4780_nand_cs *cs;
+-	struct resource *res;
+-	struct nand_chip *chip;
+-	struct mtd_info *mtd;
+-	const __be32 *reg;
+-	int ret = 0;
+-
+-	cs = &nfc->cs[chipnr];
+-
+-	reg = of_get_property(np, "reg", NULL);
+-	if (!reg)
+-		return -EINVAL;
+-
+-	cs->bank = be32_to_cpu(*reg);
+-
+-	jz4780_nemc_set_type(nfc->dev, cs->bank, JZ4780_NEMC_BANK_NAND);
+-
+-	res = platform_get_resource(pdev, IORESOURCE_MEM, chipnr);
+-	cs->base = devm_ioremap_resource(dev, res);
+-	if (IS_ERR(cs->base))
+-		return PTR_ERR(cs->base);
+-
+-	nand = devm_kzalloc(dev, sizeof(*nand), GFP_KERNEL);
+-	if (!nand)
+-		return -ENOMEM;
+-
+-	nand->busy_gpio = devm_gpiod_get_optional(dev, "rb", GPIOD_IN);
+-
+-	if (IS_ERR(nand->busy_gpio)) {
+-		ret = PTR_ERR(nand->busy_gpio);
+-		dev_err(dev, "failed to request busy GPIO: %d\n", ret);
+-		return ret;
+-	} else if (nand->busy_gpio) {
+-		nand->chip.dev_ready = jz4780_nand_dev_ready;
+-	}
+-
+-	nand->wp_gpio = devm_gpiod_get_optional(dev, "wp", GPIOD_OUT_LOW);
+-
+-	if (IS_ERR(nand->wp_gpio)) {
+-		ret = PTR_ERR(nand->wp_gpio);
+-		dev_err(dev, "failed to request WP GPIO: %d\n", ret);
+-		return ret;
+-	}
+-
+-	chip = &nand->chip;
+-	mtd = nand_to_mtd(chip);
+-	mtd->name = devm_kasprintf(dev, GFP_KERNEL, "%s.%d", dev_name(dev),
+-				   cs->bank);
+-	if (!mtd->name)
+-		return -ENOMEM;
+-	mtd->dev.parent = dev;
+-
+-	chip->IO_ADDR_R = cs->base + OFFSET_DATA;
+-	chip->IO_ADDR_W = cs->base + OFFSET_DATA;
+-	chip->chip_delay = RB_DELAY_US;
+-	chip->options = NAND_NO_SUBPAGE_WRITE;
+-	chip->select_chip = jz4780_nand_select_chip;
+-	chip->cmd_ctrl = jz4780_nand_cmd_ctrl;
+-	chip->ecc.mode = NAND_ECC_HW;
+-	chip->controller = &nfc->controller;
+-	nand_set_flash_node(chip, np);
+-
+-	ret = nand_scan_ident(mtd, 1, NULL);
+-	if (ret)
+-		return ret;
+-
+-	ret = jz4780_nand_init_ecc(nand, dev);
+-	if (ret)
+-		return ret;
+-
+-	ret = nand_scan_tail(mtd);
+-	if (ret)
+-		return ret;
+-
+-	ret = mtd_device_register(mtd, NULL, 0);
+-	if (ret) {
+-		nand_release(mtd);
+-		return ret;
+-	}
+-
+-	list_add_tail(&nand->chip_list, &nfc->chips);
+-
+-	return 0;
+-}
+-
+-static void jz4780_nand_cleanup_chips(struct jz4780_nand_controller *nfc)
+-{
+-	struct jz4780_nand_chip *chip;
+-
+-	while (!list_empty(&nfc->chips)) {
+-		chip = list_first_entry(&nfc->chips, struct jz4780_nand_chip, chip_list);
+-		nand_release(nand_to_mtd(&chip->chip));
+-		list_del(&chip->chip_list);
+-	}
+-}
+-
+-static int jz4780_nand_init_chips(struct jz4780_nand_controller *nfc,
+-				  struct platform_device *pdev)
+-{
+-	struct device *dev = &pdev->dev;
+-	struct device_node *np;
+-	int i = 0;
+-	int ret;
+-	int num_chips = of_get_child_count(dev->of_node);
+-
+-	if (num_chips > nfc->num_banks) {
+-		dev_err(dev, "found %d chips but only %d banks\n", num_chips, nfc->num_banks);
+-		return -EINVAL;
+-	}
+-
+-	for_each_child_of_node(dev->of_node, np) {
+-		ret = jz4780_nand_init_chip(pdev, nfc, np, i);
+-		if (ret) {
+-			jz4780_nand_cleanup_chips(nfc);
+-			return ret;
+-		}
+-
+-		i++;
+-	}
+-
+-	return 0;
+-}
+-
+-static int jz4780_nand_probe(struct platform_device *pdev)
+-{
+-	struct device *dev = &pdev->dev;
+-	unsigned int num_banks;
+-	struct jz4780_nand_controller *nfc;
+-	int ret;
+-
+-	num_banks = jz4780_nemc_num_banks(dev);
+-	if (num_banks == 0) {
+-		dev_err(dev, "no banks found\n");
+-		return -ENODEV;
+-	}
+-
+-	nfc = devm_kzalloc(dev, sizeof(*nfc) + (sizeof(nfc->cs[0]) * num_banks), GFP_KERNEL);
+-	if (!nfc)
+-		return -ENOMEM;
+-
+-	/*
+-	 * Check for BCH HW before we call nand_scan_ident, to prevent us from
+-	 * having to call it again if the BCH driver returns -EPROBE_DEFER.
+-	 */
+-	nfc->bch = of_jz4780_bch_get(dev->of_node);
+-	if (IS_ERR(nfc->bch))
+-		return PTR_ERR(nfc->bch);
+-
+-	nfc->dev = dev;
+-	nfc->num_banks = num_banks;
+-
+-	nand_hw_control_init(&nfc->controller);
+-	INIT_LIST_HEAD(&nfc->chips);
+-
+-	ret = jz4780_nand_init_chips(nfc, pdev);
+-	if (ret) {
+-		if (nfc->bch)
+-			jz4780_bch_release(nfc->bch);
+-		return ret;
+-	}
+-
+-	platform_set_drvdata(pdev, nfc);
+-	return 0;
+-}
+-
+-static int jz4780_nand_remove(struct platform_device *pdev)
+-{
+-	struct jz4780_nand_controller *nfc = platform_get_drvdata(pdev);
+-
+-	if (nfc->bch)
+-		jz4780_bch_release(nfc->bch);
+-
+-	jz4780_nand_cleanup_chips(nfc);
+-
+-	return 0;
+-}
+-
+-static const struct of_device_id jz4780_nand_dt_match[] = {
+-	{ .compatible = "ingenic,jz4780-nand" },
+-	{},
+-};
+-MODULE_DEVICE_TABLE(of, jz4780_nand_dt_match);
+-
+-static struct platform_driver jz4780_nand_driver = {
+-	.probe		= jz4780_nand_probe,
+-	.remove		= jz4780_nand_remove,
+-	.driver	= {
+-		.name	= DRV_NAME,
+-		.of_match_table = of_match_ptr(jz4780_nand_dt_match),
+-	},
+-};
+-module_platform_driver(jz4780_nand_driver);
+-
+-MODULE_AUTHOR("Alex Smith <alex@alex-smith.me.uk>");
+-MODULE_AUTHOR("Harvey Hunt <harveyhuntnexus@gmail.com>");
+-MODULE_DESCRIPTION("Ingenic JZ4780 NAND driver");
+-MODULE_LICENSE("GPL v2");
+diff --git a/drivers/mtd/nand/lpc32xx_mlc.c b/drivers/mtd/nand/lpc32xx_mlc.c
+deleted file mode 100644
+index 5796468..0000000
+--- a/drivers/mtd/nand/lpc32xx_mlc.c
++++ /dev/null
+@@ -1,906 +0,0 @@
+-/*
+- * Driver for NAND MLC Controller in LPC32xx
+- *
+- * Author: Roland Stigge <stigge@antcom.de>
+- *
+- * Copyright © 2011 WORK Microwave GmbH
+- * Copyright © 2011, 2012 Roland Stigge
+- *
+- * 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.
+- *
+- *
+- * NAND Flash Controller Operation:
+- * - Read: Auto Decode
+- * - Write: Auto Encode
+- * - Tested Page Sizes: 2048, 4096
+- */
+-
+-#include <linux/slab.h>
+-#include <linux/module.h>
+-#include <linux/platform_device.h>
+-#include <linux/mtd/mtd.h>
+-#include <linux/mtd/rawnand.h>
+-#include <linux/mtd/partitions.h>
+-#include <linux/clk.h>
+-#include <linux/err.h>
+-#include <linux/delay.h>
+-#include <linux/completion.h>
+-#include <linux/interrupt.h>
+-#include <linux/of.h>
+-#include <linux/of_gpio.h>
+-#include <linux/mtd/lpc32xx_mlc.h>
+-#include <linux/io.h>
+-#include <linux/mm.h>
+-#include <linux/dma-mapping.h>
+-#include <linux/dmaengine.h>
+-#include <linux/mtd/nand_ecc.h>
+-
+-#define DRV_NAME "lpc32xx_mlc"
+-
+-/**********************************************************************
+-* MLC NAND controller register offsets
+-**********************************************************************/
+-
+-#define MLC_BUFF(x)			(x + 0x00000)
+-#define MLC_DATA(x)			(x + 0x08000)
+-#define MLC_CMD(x)			(x + 0x10000)
+-#define MLC_ADDR(x)			(x + 0x10004)
+-#define MLC_ECC_ENC_REG(x)		(x + 0x10008)
+-#define MLC_ECC_DEC_REG(x)		(x + 0x1000C)
+-#define MLC_ECC_AUTO_ENC_REG(x)		(x + 0x10010)
+-#define MLC_ECC_AUTO_DEC_REG(x)		(x + 0x10014)
+-#define MLC_RPR(x)			(x + 0x10018)
+-#define MLC_WPR(x)			(x + 0x1001C)
+-#define MLC_RUBP(x)			(x + 0x10020)
+-#define MLC_ROBP(x)			(x + 0x10024)
+-#define MLC_SW_WP_ADD_LOW(x)		(x + 0x10028)
+-#define MLC_SW_WP_ADD_HIG(x)		(x + 0x1002C)
+-#define MLC_ICR(x)			(x + 0x10030)
+-#define MLC_TIME_REG(x)			(x + 0x10034)
+-#define MLC_IRQ_MR(x)			(x + 0x10038)
+-#define MLC_IRQ_SR(x)			(x + 0x1003C)
+-#define MLC_LOCK_PR(x)			(x + 0x10044)
+-#define MLC_ISR(x)			(x + 0x10048)
+-#define MLC_CEH(x)			(x + 0x1004C)
+-
+-/**********************************************************************
+-* MLC_CMD bit definitions
+-**********************************************************************/
+-#define MLCCMD_RESET			0xFF
+-
+-/**********************************************************************
+-* MLC_ICR bit definitions
+-**********************************************************************/
+-#define MLCICR_WPROT			(1 << 3)
+-#define MLCICR_LARGEBLOCK		(1 << 2)
+-#define MLCICR_LONGADDR			(1 << 1)
+-#define MLCICR_16BIT			(1 << 0)  /* unsupported by LPC32x0! */
+-
+-/**********************************************************************
+-* MLC_TIME_REG bit definitions
+-**********************************************************************/
+-#define MLCTIMEREG_TCEA_DELAY(n)	(((n) & 0x03) << 24)
+-#define MLCTIMEREG_BUSY_DELAY(n)	(((n) & 0x1F) << 19)
+-#define MLCTIMEREG_NAND_TA(n)		(((n) & 0x07) << 16)
+-#define MLCTIMEREG_RD_HIGH(n)		(((n) & 0x0F) << 12)
+-#define MLCTIMEREG_RD_LOW(n)		(((n) & 0x0F) << 8)
+-#define MLCTIMEREG_WR_HIGH(n)		(((n) & 0x0F) << 4)
+-#define MLCTIMEREG_WR_LOW(n)		(((n) & 0x0F) << 0)
+-
+-/**********************************************************************
+-* MLC_IRQ_MR and MLC_IRQ_SR bit definitions
+-**********************************************************************/
+-#define MLCIRQ_NAND_READY		(1 << 5)
+-#define MLCIRQ_CONTROLLER_READY		(1 << 4)
+-#define MLCIRQ_DECODE_FAILURE		(1 << 3)
+-#define MLCIRQ_DECODE_ERROR		(1 << 2)
+-#define MLCIRQ_ECC_READY		(1 << 1)
+-#define MLCIRQ_WRPROT_FAULT		(1 << 0)
+-
+-/**********************************************************************
+-* MLC_LOCK_PR bit definitions
+-**********************************************************************/
+-#define MLCLOCKPR_MAGIC			0xA25E
+-
+-/**********************************************************************
+-* MLC_ISR bit definitions
+-**********************************************************************/
+-#define MLCISR_DECODER_FAILURE		(1 << 6)
+-#define MLCISR_ERRORS			((1 << 4) | (1 << 5))
+-#define MLCISR_ERRORS_DETECTED		(1 << 3)
+-#define MLCISR_ECC_READY		(1 << 2)
+-#define MLCISR_CONTROLLER_READY		(1 << 1)
+-#define MLCISR_NAND_READY		(1 << 0)
+-
+-/**********************************************************************
+-* MLC_CEH bit definitions
+-**********************************************************************/
+-#define MLCCEH_NORMAL			(1 << 0)
+-
+-struct lpc32xx_nand_cfg_mlc {
+-	uint32_t tcea_delay;
+-	uint32_t busy_delay;
+-	uint32_t nand_ta;
+-	uint32_t rd_high;
+-	uint32_t rd_low;
+-	uint32_t wr_high;
+-	uint32_t wr_low;
+-	int wp_gpio;
+-	struct mtd_partition *parts;
+-	unsigned num_parts;
+-};
+-
+-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);
+-
+-	if (section >= nand_chip->ecc.steps)
+-		return -ERANGE;
+-
+-	oobregion->offset = ((section + 1) * 16) - nand_chip->ecc.bytes;
+-	oobregion->length = nand_chip->ecc.bytes;
+-
+-	return 0;
+-}
+-
+-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);
+-
+-	if (section >= nand_chip->ecc.steps)
+-		return -ERANGE;
+-
+-	oobregion->offset = 16 * section;
+-	oobregion->length = 16 - nand_chip->ecc.bytes;
+-
+-	return 0;
+-}
+-
+-static const struct mtd_ooblayout_ops lpc32xx_ooblayout_ops = {
+-	.ecc = lpc32xx_ooblayout_ecc,
+-	.free = lpc32xx_ooblayout_free,
+-};
+-
+-static struct nand_bbt_descr lpc32xx_nand_bbt = {
+-	.options = NAND_BBT_ABSPAGE | NAND_BBT_2BIT | NAND_BBT_NO_OOB |
+-		   NAND_BBT_WRITE,
+-	.pages = { 524224, 0, 0, 0, 0, 0, 0, 0 },
+-};
+-
+-static struct nand_bbt_descr lpc32xx_nand_bbt_mirror = {
+-	.options = NAND_BBT_ABSPAGE | NAND_BBT_2BIT | NAND_BBT_NO_OOB |
+-		   NAND_BBT_WRITE,
+-	.pages = { 524160, 0, 0, 0, 0, 0, 0, 0 },
+-};
+-
+-struct lpc32xx_nand_host {
+-	struct nand_chip	nand_chip;
+-	struct lpc32xx_mlc_platform_data *pdata;
+-	struct clk		*clk;
+-	void __iomem		*io_base;
+-	int			irq;
+-	struct lpc32xx_nand_cfg_mlc	*ncfg;
+-	struct completion       comp_nand;
+-	struct completion       comp_controller;
+-	uint32_t llptr;
+-	/*
+-	 * Physical addresses of ECC buffer, DMA data buffers, OOB data buffer
+-	 */
+-	dma_addr_t		oob_buf_phy;
+-	/*
+-	 * Virtual addresses of ECC buffer, DMA data buffers, OOB data buffer
+-	 */
+-	uint8_t			*oob_buf;
+-	/* Physical address of DMA base address */
+-	dma_addr_t		io_base_phy;
+-
+-	struct completion	comp_dma;
+-	struct dma_chan		*dma_chan;
+-	struct dma_slave_config	dma_slave_config;
+-	struct scatterlist	sgl;
+-	uint8_t			*dma_buf;
+-	uint8_t			*dummy_buf;
+-	int			mlcsubpages; /* number of 512bytes-subpages */
+-};
+-
+-/*
+- * Activate/Deactivate DMA Operation:
+- *
+- * Using the PL080 DMA Controller for transferring the 512 byte subpages
+- * instead of doing readl() / writel() in a loop slows it down significantly.
+- * Measurements via getnstimeofday() upon 512 byte subpage reads reveal:
+- *
+- * - readl() of 128 x 32 bits in a loop: ~20us
+- * - DMA read of 512 bytes (32 bit, 4...128 words bursts): ~60us
+- * - DMA read of 512 bytes (32 bit, no bursts): ~100us
+- *
+- * This applies to the transfer itself. In the DMA case: only the
+- * wait_for_completion() (DMA setup _not_ included).
+- *
+- * Note that the 512 bytes subpage transfer is done directly from/to a
+- * FIFO/buffer inside the NAND controller. Most of the time (~400-800us for a
+- * 2048 bytes page) is spent waiting for the NAND IRQ, anyway. (The NAND
+- * controller transferring data between its internal buffer to/from the NAND
+- * chip.)
+- *
+- * Therefore, using the PL080 DMA is disabled by default, for now.
+- *
+- */
+-static int use_dma;
+-
+-static void lpc32xx_nand_setup(struct lpc32xx_nand_host *host)
+-{
+-	uint32_t clkrate, tmp;
+-
+-	/* Reset MLC controller */
+-	writel(MLCCMD_RESET, MLC_CMD(host->io_base));
+-	udelay(1000);
+-
+-	/* Get base clock for MLC block */
+-	clkrate = clk_get_rate(host->clk);
+-	if (clkrate == 0)
+-		clkrate = 104000000;
+-
+-	/* Unlock MLC_ICR
+-	 * (among others, will be locked again automatically) */
+-	writew(MLCLOCKPR_MAGIC, MLC_LOCK_PR(host->io_base));
+-
+-	/* Configure MLC Controller: Large Block, 5 Byte Address */
+-	tmp = MLCICR_LARGEBLOCK | MLCICR_LONGADDR;
+-	writel(tmp, MLC_ICR(host->io_base));
+-
+-	/* Unlock MLC_TIME_REG
+-	 * (among others, will be locked again automatically) */
+-	writew(MLCLOCKPR_MAGIC, MLC_LOCK_PR(host->io_base));
+-
+-	/* Compute clock setup values, see LPC and NAND manual */
+-	tmp = 0;
+-	tmp |= MLCTIMEREG_TCEA_DELAY(clkrate / host->ncfg->tcea_delay + 1);
+-	tmp |= MLCTIMEREG_BUSY_DELAY(clkrate / host->ncfg->busy_delay + 1);
+-	tmp |= MLCTIMEREG_NAND_TA(clkrate / host->ncfg->nand_ta + 1);
+-	tmp |= MLCTIMEREG_RD_HIGH(clkrate / host->ncfg->rd_high + 1);
+-	tmp |= MLCTIMEREG_RD_LOW(clkrate / host->ncfg->rd_low);
+-	tmp |= MLCTIMEREG_WR_HIGH(clkrate / host->ncfg->wr_high + 1);
+-	tmp |= MLCTIMEREG_WR_LOW(clkrate / host->ncfg->wr_low);
+-	writel(tmp, MLC_TIME_REG(host->io_base));
+-
+-	/* Enable IRQ for CONTROLLER_READY and NAND_READY */
+-	writeb(MLCIRQ_CONTROLLER_READY | MLCIRQ_NAND_READY,
+-			MLC_IRQ_MR(host->io_base));
+-
+-	/* Normal nCE operation: nCE controlled by controller */
+-	writel(MLCCEH_NORMAL, MLC_CEH(host->io_base));
+-}
+-
+-/*
+- * Hardware specific access to control lines
+- */
+-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 lpc32xx_nand_host *host = nand_get_controller_data(nand_chip);
+-
+-	if (cmd != NAND_CMD_NONE) {
+-		if (ctrl & NAND_CLE)
+-			writel(cmd, MLC_CMD(host->io_base));
+-		else
+-			writel(cmd, MLC_ADDR(host->io_base));
+-	}
+-}
+-
+-/*
+- * Read Device Ready (NAND device _and_ controller ready)
+- */
+-static int lpc32xx_nand_device_ready(struct mtd_info *mtd)
+-{
+-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+-	struct lpc32xx_nand_host *host = nand_get_controller_data(nand_chip);
+-
+-	if ((readb(MLC_ISR(host->io_base)) &
+-	     (MLCISR_CONTROLLER_READY | MLCISR_NAND_READY)) ==
+-	    (MLCISR_CONTROLLER_READY | MLCISR_NAND_READY))
+-		return  1;
+-
+-	return 0;
+-}
+-
+-static irqreturn_t lpc3xxx_nand_irq(int irq, struct lpc32xx_nand_host *host)
+-{
+-	uint8_t sr;
+-
+-	/* Clear interrupt flag by reading status */
+-	sr = readb(MLC_IRQ_SR(host->io_base));
+-	if (sr & MLCIRQ_NAND_READY)
+-		complete(&host->comp_nand);
+-	if (sr & MLCIRQ_CONTROLLER_READY)
+-		complete(&host->comp_controller);
+-
+-	return IRQ_HANDLED;
+-}
+-
+-static int lpc32xx_waitfunc_nand(struct mtd_info *mtd, struct nand_chip *chip)
+-{
+-	struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
+-
+-	if (readb(MLC_ISR(host->io_base)) & MLCISR_NAND_READY)
+-		goto exit;
+-
+-	wait_for_completion(&host->comp_nand);
+-
+-	while (!(readb(MLC_ISR(host->io_base)) & MLCISR_NAND_READY)) {
+-		/* Seems to be delayed sometimes by controller */
+-		dev_dbg(&mtd->dev, "Warning: NAND not ready.\n");
+-		cpu_relax();
+-	}
+-
+-exit:
+-	return NAND_STATUS_READY;
+-}
+-
+-static int lpc32xx_waitfunc_controller(struct mtd_info *mtd,
+-				       struct nand_chip *chip)
+-{
+-	struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
+-
+-	if (readb(MLC_ISR(host->io_base)) & MLCISR_CONTROLLER_READY)
+-		goto exit;
+-
+-	wait_for_completion(&host->comp_controller);
+-
+-	while (!(readb(MLC_ISR(host->io_base)) &
+-		 MLCISR_CONTROLLER_READY)) {
+-		dev_dbg(&mtd->dev, "Warning: Controller not ready.\n");
+-		cpu_relax();
+-	}
+-
+-exit:
+-	return NAND_STATUS_READY;
+-}
+-
+-static int lpc32xx_waitfunc(struct mtd_info *mtd, struct nand_chip *chip)
+-{
+-	lpc32xx_waitfunc_nand(mtd, chip);
+-	lpc32xx_waitfunc_controller(mtd, chip);
+-
+-	return NAND_STATUS_READY;
+-}
+-
+-/*
+- * Enable NAND write protect
+- */
+-static void lpc32xx_wp_enable(struct lpc32xx_nand_host *host)
+-{
+-	if (gpio_is_valid(host->ncfg->wp_gpio))
+-		gpio_set_value(host->ncfg->wp_gpio, 0);
+-}
+-
+-/*
+- * Disable NAND write protect
+- */
+-static void lpc32xx_wp_disable(struct lpc32xx_nand_host *host)
+-{
+-	if (gpio_is_valid(host->ncfg->wp_gpio))
+-		gpio_set_value(host->ncfg->wp_gpio, 1);
+-}
+-
+-static void lpc32xx_dma_complete_func(void *completion)
+-{
+-	complete(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 lpc32xx_nand_host *host = nand_get_controller_data(chip);
+-	struct dma_async_tx_descriptor *desc;
+-	int flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
+-	int res;
+-
+-	sg_init_one(&host->sgl, mem, len);
+-
+-	res = dma_map_sg(host->dma_chan->device->dev, &host->sgl, 1,
+-			 DMA_BIDIRECTIONAL);
+-	if (res != 1) {
+-		dev_err(mtd->dev.parent, "Failed to map sg list\n");
+-		return -ENXIO;
+-	}
+-	desc = dmaengine_prep_slave_sg(host->dma_chan, &host->sgl, 1, dir,
+-				       flags);
+-	if (!desc) {
+-		dev_err(mtd->dev.parent, "Failed to prepare slave sg\n");
+-		goto out1;
+-	}
+-
+-	init_completion(&host->comp_dma);
+-	desc->callback = lpc32xx_dma_complete_func;
+-	desc->callback_param = &host->comp_dma;
+-
+-	dmaengine_submit(desc);
+-	dma_async_issue_pending(host->dma_chan);
+-
+-	wait_for_completion_timeout(&host->comp_dma, msecs_to_jiffies(1000));
+-
+-	dma_unmap_sg(host->dma_chan->device->dev, &host->sgl, 1,
+-		     DMA_BIDIRECTIONAL);
+-	return 0;
+-out1:
+-	dma_unmap_sg(host->dma_chan->device->dev, &host->sgl, 1,
+-		     DMA_BIDIRECTIONAL);
+-	return -ENXIO;
+-}
+-
+-static int lpc32xx_read_page(struct mtd_info *mtd, struct nand_chip *chip,
+-			     uint8_t *buf, int oob_required, int page)
+-{
+-	struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
+-	int i, j;
+-	uint8_t *oobbuf = chip->oob_poi;
+-	uint32_t mlc_isr;
+-	int res;
+-	uint8_t *dma_buf;
+-	bool dma_mapped;
+-
+-	if ((void *)buf <= high_memory) {
+-		dma_buf = buf;
+-		dma_mapped = true;
+-	} else {
+-		dma_buf = host->dma_buf;
+-		dma_mapped = false;
+-	}
+-
+-	/* Writing Command and Address */
+-	chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
+-
+-	/* For all sub-pages */
+-	for (i = 0; i < host->mlcsubpages; i++) {
+-		/* Start Auto Decode Command */
+-		writeb(0x00, MLC_ECC_AUTO_DEC_REG(host->io_base));
+-
+-		/* Wait for Controller Ready */
+-		lpc32xx_waitfunc_controller(mtd, chip);
+-
+-		/* Check ECC Error status */
+-		mlc_isr = readl(MLC_ISR(host->io_base));
+-		if (mlc_isr & MLCISR_DECODER_FAILURE) {
+-			mtd->ecc_stats.failed++;
+-			dev_warn(&mtd->dev, "%s: DECODER_FAILURE\n", __func__);
+-		} else if (mlc_isr & MLCISR_ERRORS_DETECTED) {
+-			mtd->ecc_stats.corrected += ((mlc_isr >> 4) & 0x3) + 1;
+-		}
+-
+-		/* Read 512 + 16 Bytes */
+-		if (use_dma) {
+-			res = lpc32xx_xmit_dma(mtd, dma_buf + i * 512, 512,
+-					       DMA_DEV_TO_MEM);
+-			if (res)
+-				return res;
+-		} else {
+-			for (j = 0; j < (512 >> 2); j++) {
+-				*((uint32_t *)(buf)) =
+-					readl(MLC_BUFF(host->io_base));
+-				buf += 4;
+-			}
+-		}
+-		for (j = 0; j < (16 >> 2); j++) {
+-			*((uint32_t *)(oobbuf)) =
+-				readl(MLC_BUFF(host->io_base));
+-			oobbuf += 4;
+-		}
+-	}
+-
+-	if (use_dma && !dma_mapped)
+-		memcpy(buf, dma_buf, mtd->writesize);
+-
+-	return 0;
+-}
+-
+-static int lpc32xx_write_page_lowlevel(struct mtd_info *mtd,
+-				       struct nand_chip *chip,
+-				       const uint8_t *buf, int oob_required,
+-				       int page)
+-{
+-	struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
+-	const uint8_t *oobbuf = chip->oob_poi;
+-	uint8_t *dma_buf = (uint8_t *)buf;
+-	int res;
+-	int i, j;
+-
+-	if (use_dma && (void *)buf >= high_memory) {
+-		dma_buf = host->dma_buf;
+-		memcpy(dma_buf, buf, mtd->writesize);
+-	}
+-
+-	for (i = 0; i < host->mlcsubpages; i++) {
+-		/* Start Encode */
+-		writeb(0x00, MLC_ECC_ENC_REG(host->io_base));
+-
+-		/* Write 512 + 6 Bytes to Buffer */
+-		if (use_dma) {
+-			res = lpc32xx_xmit_dma(mtd, dma_buf + i * 512, 512,
+-					       DMA_MEM_TO_DEV);
+-			if (res)
+-				return res;
+-		} else {
+-			for (j = 0; j < (512 >> 2); j++) {
+-				writel(*((uint32_t *)(buf)),
+-				       MLC_BUFF(host->io_base));
+-				buf += 4;
+-			}
+-		}
+-		writel(*((uint32_t *)(oobbuf)), MLC_BUFF(host->io_base));
+-		oobbuf += 4;
+-		writew(*((uint16_t *)(oobbuf)), MLC_BUFF(host->io_base));
+-		oobbuf += 12;
+-
+-		/* Auto Encode w/ Bit 8 = 0 (see LPC MLC Controller manual) */
+-		writeb(0x00, MLC_ECC_AUTO_ENC_REG(host->io_base));
+-
+-		/* Wait for Controller Ready */
+-		lpc32xx_waitfunc_controller(mtd, chip);
+-	}
+-	return 0;
+-}
+-
+-static int lpc32xx_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
+-			    int page)
+-{
+-	struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
+-
+-	/* Read whole page - necessary with MLC controller! */
+-	lpc32xx_read_page(mtd, chip, host->dummy_buf, 1, page);
+-
+-	return 0;
+-}
+-
+-static int lpc32xx_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
+-			      int page)
+-{
+-	/* None, write_oob conflicts with the automatic LPC MLC ECC decoder! */
+-	return 0;
+-}
+-
+-/* Prepares MLC for transfers with H/W ECC enabled: always enabled anyway */
+-static void lpc32xx_ecc_enable(struct mtd_info *mtd, int mode)
+-{
+-	/* Always enabled! */
+-}
+-
+-static int lpc32xx_dma_setup(struct lpc32xx_nand_host *host)
+-{
+-	struct mtd_info *mtd = nand_to_mtd(&host->nand_chip);
+-	dma_cap_mask_t mask;
+-
+-	if (!host->pdata || !host->pdata->dma_filter) {
+-		dev_err(mtd->dev.parent, "no DMA platform data\n");
+-		return -ENOENT;
+-	}
+-
+-	dma_cap_zero(mask);
+-	dma_cap_set(DMA_SLAVE, mask);
+-	host->dma_chan = dma_request_channel(mask, host->pdata->dma_filter,
+-					     "nand-mlc");
+-	if (!host->dma_chan) {
+-		dev_err(mtd->dev.parent, "Failed to request DMA channel\n");
+-		return -EBUSY;
+-	}
+-
+-	/*
+-	 * Set direction to a sensible value even if the dmaengine driver
+-	 * should ignore it. With the default (DMA_MEM_TO_MEM), the amba-pl08x
+-	 * driver criticizes it as "alien transfer direction".
+-	 */
+-	host->dma_slave_config.direction = DMA_DEV_TO_MEM;
+-	host->dma_slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+-	host->dma_slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+-	host->dma_slave_config.src_maxburst = 128;
+-	host->dma_slave_config.dst_maxburst = 128;
+-	/* DMA controller does flow control: */
+-	host->dma_slave_config.device_fc = false;
+-	host->dma_slave_config.src_addr = MLC_BUFF(host->io_base_phy);
+-	host->dma_slave_config.dst_addr = MLC_BUFF(host->io_base_phy);
+-	if (dmaengine_slave_config(host->dma_chan, &host->dma_slave_config)) {
+-		dev_err(mtd->dev.parent, "Failed to setup DMA slave\n");
+-		goto out1;
+-	}
+-
+-	return 0;
+-out1:
+-	dma_release_channel(host->dma_chan);
+-	return -ENXIO;
+-}
+-
+-static struct lpc32xx_nand_cfg_mlc *lpc32xx_parse_dt(struct device *dev)
+-{
+-	struct lpc32xx_nand_cfg_mlc *ncfg;
+-	struct device_node *np = dev->of_node;
+-
+-	ncfg = devm_kzalloc(dev, sizeof(*ncfg), GFP_KERNEL);
+-	if (!ncfg)
+-		return NULL;
+-
+-	of_property_read_u32(np, "nxp,tcea-delay", &ncfg->tcea_delay);
+-	of_property_read_u32(np, "nxp,busy-delay", &ncfg->busy_delay);
+-	of_property_read_u32(np, "nxp,nand-ta", &ncfg->nand_ta);
+-	of_property_read_u32(np, "nxp,rd-high", &ncfg->rd_high);
+-	of_property_read_u32(np, "nxp,rd-low", &ncfg->rd_low);
+-	of_property_read_u32(np, "nxp,wr-high", &ncfg->wr_high);
+-	of_property_read_u32(np, "nxp,wr-low", &ncfg->wr_low);
+-
+-	if (!ncfg->tcea_delay || !ncfg->busy_delay || !ncfg->nand_ta ||
+-	    !ncfg->rd_high || !ncfg->rd_low || !ncfg->wr_high ||
+-	    !ncfg->wr_low) {
+-		dev_err(dev, "chip parameters not specified correctly\n");
+-		return NULL;
+-	}
+-
+-	ncfg->wp_gpio = of_get_named_gpio(np, "gpios", 0);
+-
+-	return ncfg;
+-}
+-
+-/*
+- * Probe for NAND controller
+- */
+-static int lpc32xx_nand_probe(struct platform_device *pdev)
+-{
+-	struct lpc32xx_nand_host *host;
+-	struct mtd_info *mtd;
+-	struct nand_chip *nand_chip;
+-	struct resource *rc;
+-	int res;
+-
+-	/* Allocate memory for the device structure (and zero it) */
+-	host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
+-	if (!host)
+-		return -ENOMEM;
+-
+-	rc = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+-	host->io_base = devm_ioremap_resource(&pdev->dev, rc);
+-	if (IS_ERR(host->io_base))
+-		return PTR_ERR(host->io_base);
+-	
+-	host->io_base_phy = rc->start;
+-
+-	nand_chip = &host->nand_chip;
+-	mtd = nand_to_mtd(nand_chip);
+-	if (pdev->dev.of_node)
+-		host->ncfg = lpc32xx_parse_dt(&pdev->dev);
+-	if (!host->ncfg) {
+-		dev_err(&pdev->dev,
+-			"Missing or bad NAND config from device tree\n");
+-		return -ENOENT;
+-	}
+-	if (host->ncfg->wp_gpio == -EPROBE_DEFER)
+-		return -EPROBE_DEFER;
+-	if (gpio_is_valid(host->ncfg->wp_gpio) &&
+-			gpio_request(host->ncfg->wp_gpio, "NAND WP")) {
+-		dev_err(&pdev->dev, "GPIO not available\n");
+-		return -EBUSY;
+-	}
+-	lpc32xx_wp_disable(host);
+-
+-	host->pdata = dev_get_platdata(&pdev->dev);
+-
+-	/* link the private data structures */
+-	nand_set_controller_data(nand_chip, host);
+-	nand_set_flash_node(nand_chip, pdev->dev.of_node);
+-	mtd->dev.parent = &pdev->dev;
+-
+-	/* Get NAND clock */
+-	host->clk = clk_get(&pdev->dev, NULL);
+-	if (IS_ERR(host->clk)) {
+-		dev_err(&pdev->dev, "Clock initialization failure\n");
+-		res = -ENOENT;
+-		goto err_exit1;
+-	}
+-	res = clk_prepare_enable(host->clk);
+-	if (res)
+-		goto err_put_clk;
+-
+-	nand_chip->cmd_ctrl = lpc32xx_nand_cmd_ctrl;
+-	nand_chip->dev_ready = lpc32xx_nand_device_ready;
+-	nand_chip->chip_delay = 25; /* us */
+-	nand_chip->IO_ADDR_R = MLC_DATA(host->io_base);
+-	nand_chip->IO_ADDR_W = MLC_DATA(host->io_base);
+-
+-	/* Init NAND controller */
+-	lpc32xx_nand_setup(host);
+-
+-	platform_set_drvdata(pdev, host);
+-
+-	/* Initialize function pointers */
+-	nand_chip->ecc.hwctl = lpc32xx_ecc_enable;
+-	nand_chip->ecc.read_page_raw = lpc32xx_read_page;
+-	nand_chip->ecc.read_page = lpc32xx_read_page;
+-	nand_chip->ecc.write_page_raw = lpc32xx_write_page_lowlevel;
+-	nand_chip->ecc.write_page = lpc32xx_write_page_lowlevel;
+-	nand_chip->ecc.write_oob = lpc32xx_write_oob;
+-	nand_chip->ecc.read_oob = lpc32xx_read_oob;
+-	nand_chip->ecc.strength = 4;
+-	nand_chip->ecc.bytes = 10;
+-	nand_chip->waitfunc = lpc32xx_waitfunc;
+-
+-	nand_chip->options = NAND_NO_SUBPAGE_WRITE;
+-	nand_chip->bbt_options = NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB;
+-	nand_chip->bbt_td = &lpc32xx_nand_bbt;
+-	nand_chip->bbt_md = &lpc32xx_nand_bbt_mirror;
+-
+-	if (use_dma) {
+-		res = lpc32xx_dma_setup(host);
+-		if (res) {
+-			res = -EIO;
+-			goto err_exit2;
+-		}
+-	}
+-
+-	/*
+-	 * Scan to find existance of the device and
+-	 * Get the type of NAND device SMALL block or LARGE block
+-	 */
+-	res = nand_scan_ident(mtd, 1, NULL);
+-	if (res)
+-		goto err_exit3;
+-
+-	host->dma_buf = devm_kzalloc(&pdev->dev, mtd->writesize, GFP_KERNEL);
+-	if (!host->dma_buf) {
+-		res = -ENOMEM;
+-		goto err_exit3;
+-	}
+-
+-	host->dummy_buf = devm_kzalloc(&pdev->dev, mtd->writesize, GFP_KERNEL);
+-	if (!host->dummy_buf) {
+-		res = -ENOMEM;
+-		goto err_exit3;
+-	}
+-
+-	nand_chip->ecc.mode = NAND_ECC_HW;
+-	nand_chip->ecc.size = 512;
+-	mtd_set_ooblayout(mtd, &lpc32xx_ooblayout_ops);
+-	host->mlcsubpages = mtd->writesize / 512;
+-
+-	/* initially clear interrupt status */
+-	readb(MLC_IRQ_SR(host->io_base));
+-
+-	init_completion(&host->comp_nand);
+-	init_completion(&host->comp_controller);
+-
+-	host->irq = platform_get_irq(pdev, 0);
+-	if (host->irq < 0) {
+-		dev_err(&pdev->dev, "failed to get platform irq\n");
+-		res = -EINVAL;
+-		goto err_exit3;
+-	}
+-
+-	if (request_irq(host->irq, (irq_handler_t)&lpc3xxx_nand_irq,
+-			IRQF_TRIGGER_HIGH, DRV_NAME, host)) {
+-		dev_err(&pdev->dev, "Error requesting NAND IRQ\n");
+-		res = -ENXIO;
+-		goto err_exit3;
+-	}
+-
+-	/*
+-	 * Fills out all the uninitialized function pointers with the defaults
+-	 * And scans for a bad block table if appropriate.
+-	 */
+-	res = nand_scan_tail(mtd);
+-	if (res)
+-		goto err_exit4;
+-
+-	mtd->name = DRV_NAME;
+-
+-	res = mtd_device_register(mtd, host->ncfg->parts,
+-				  host->ncfg->num_parts);
+-	if (!res)
+-		return res;
+-
+-	nand_release(mtd);
+-
+-err_exit4:
+-	free_irq(host->irq, host);
+-err_exit3:
+-	if (use_dma)
+-		dma_release_channel(host->dma_chan);
+-err_exit2:
+-	clk_disable_unprepare(host->clk);
+-err_put_clk:
+-	clk_put(host->clk);
+-err_exit1:
+-	lpc32xx_wp_enable(host);
+-	gpio_free(host->ncfg->wp_gpio);
+-
+-	return res;
+-}
+-
+-/*
+- * Remove NAND device
+- */
+-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);
+-
+-	nand_release(mtd);
+-	free_irq(host->irq, host);
+-	if (use_dma)
+-		dma_release_channel(host->dma_chan);
+-
+-	clk_disable_unprepare(host->clk);
+-	clk_put(host->clk);
+-
+-	lpc32xx_wp_enable(host);
+-	gpio_free(host->ncfg->wp_gpio);
+-
+-	return 0;
+-}
+-
+-#ifdef CONFIG_PM
+-static int lpc32xx_nand_resume(struct platform_device *pdev)
+-{
+-	struct lpc32xx_nand_host *host = platform_get_drvdata(pdev);
+-	int ret;
+-
+-	/* Re-enable NAND clock */
+-	ret = clk_prepare_enable(host->clk);
+-	if (ret)
+-		return ret;
+-
+-	/* Fresh init of NAND controller */
+-	lpc32xx_nand_setup(host);
+-
+-	/* Disable write protect */
+-	lpc32xx_wp_disable(host);
+-
+-	return 0;
+-}
+-
+-static int lpc32xx_nand_suspend(struct platform_device *pdev, pm_message_t pm)
+-{
+-	struct lpc32xx_nand_host *host = platform_get_drvdata(pdev);
+-
+-	/* Enable write protect for safety */
+-	lpc32xx_wp_enable(host);
+-
+-	/* Disable clock */
+-	clk_disable_unprepare(host->clk);
+-	return 0;
+-}
+-
+-#else
+-#define lpc32xx_nand_resume NULL
+-#define lpc32xx_nand_suspend NULL
+-#endif
+-
+-static const struct of_device_id lpc32xx_nand_match[] = {
+-	{ .compatible = "nxp,lpc3220-mlc" },
+-	{ /* sentinel */ },
+-};
+-MODULE_DEVICE_TABLE(of, lpc32xx_nand_match);
+-
+-static struct platform_driver lpc32xx_nand_driver = {
+-	.probe		= lpc32xx_nand_probe,
+-	.remove		= lpc32xx_nand_remove,
+-	.resume		= lpc32xx_nand_resume,
+-	.suspend	= lpc32xx_nand_suspend,
+-	.driver		= {
+-		.name	= DRV_NAME,
+-		.of_match_table = lpc32xx_nand_match,
+-	},
+-};
+-
+-module_platform_driver(lpc32xx_nand_driver);
+-
+-MODULE_LICENSE("GPL");
+-MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>");
+-MODULE_DESCRIPTION("NAND driver for the NXP LPC32XX MLC controller");
+diff --git a/drivers/mtd/nand/lpc32xx_slc.c b/drivers/mtd/nand/lpc32xx_slc.c
+deleted file mode 100644
+index b61f28a..0000000
+--- a/drivers/mtd/nand/lpc32xx_slc.c
++++ /dev/null
+@@ -1,1039 +0,0 @@
+-/*
+- * NXP LPC32XX NAND SLC driver
+- *
+- * Authors:
+- *    Kevin Wells <kevin.wells@nxp.com>
+- *    Roland Stigge <stigge@antcom.de>
+- *
+- * Copyright © 2011 NXP Semiconductors
+- * Copyright © 2012 Roland Stigge
+- *
+- * 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/slab.h>
+-#include <linux/module.h>
+-#include <linux/platform_device.h>
+-#include <linux/mtd/mtd.h>
+-#include <linux/mtd/rawnand.h>
+-#include <linux/mtd/partitions.h>
+-#include <linux/clk.h>
+-#include <linux/err.h>
+-#include <linux/delay.h>
+-#include <linux/io.h>
+-#include <linux/mm.h>
+-#include <linux/dma-mapping.h>
+-#include <linux/dmaengine.h>
+-#include <linux/mtd/nand_ecc.h>
+-#include <linux/gpio.h>
+-#include <linux/of.h>
+-#include <linux/of_gpio.h>
+-#include <linux/mtd/lpc32xx_slc.h>
+-
+-#define LPC32XX_MODNAME		"lpc32xx-nand"
+-
+-/**********************************************************************
+-* SLC NAND controller register offsets
+-**********************************************************************/
+-
+-#define SLC_DATA(x)		(x + 0x000)
+-#define SLC_ADDR(x)		(x + 0x004)
+-#define SLC_CMD(x)		(x + 0x008)
+-#define SLC_STOP(x)		(x + 0x00C)
+-#define SLC_CTRL(x)		(x + 0x010)
+-#define SLC_CFG(x)		(x + 0x014)
+-#define SLC_STAT(x)		(x + 0x018)
+-#define SLC_INT_STAT(x)		(x + 0x01C)
+-#define SLC_IEN(x)		(x + 0x020)
+-#define SLC_ISR(x)		(x + 0x024)
+-#define SLC_ICR(x)		(x + 0x028)
+-#define SLC_TAC(x)		(x + 0x02C)
+-#define SLC_TC(x)		(x + 0x030)
+-#define SLC_ECC(x)		(x + 0x034)
+-#define SLC_DMA_DATA(x)		(x + 0x038)
+-
+-/**********************************************************************
+-* slc_ctrl register definitions
+-**********************************************************************/
+-#define SLCCTRL_SW_RESET	(1 << 2) /* Reset the NAND controller bit */
+-#define SLCCTRL_ECC_CLEAR	(1 << 1) /* Reset ECC bit */
+-#define SLCCTRL_DMA_START	(1 << 0) /* Start DMA channel bit */
+-
+-/**********************************************************************
+-* slc_cfg register definitions
+-**********************************************************************/
+-#define SLCCFG_CE_LOW		(1 << 5) /* Force CE low bit */
+-#define SLCCFG_DMA_ECC		(1 << 4) /* Enable DMA ECC bit */
+-#define SLCCFG_ECC_EN		(1 << 3) /* ECC enable bit */
+-#define SLCCFG_DMA_BURST	(1 << 2) /* DMA burst bit */
+-#define SLCCFG_DMA_DIR		(1 << 1) /* DMA write(0)/read(1) bit */
+-#define SLCCFG_WIDTH		(1 << 0) /* External device width, 0=8bit */
+-
+-/**********************************************************************
+-* slc_stat register definitions
+-**********************************************************************/
+-#define SLCSTAT_DMA_FIFO	(1 << 2) /* DMA FIFO has data bit */
+-#define SLCSTAT_SLC_FIFO	(1 << 1) /* SLC FIFO has data bit */
+-#define SLCSTAT_NAND_READY	(1 << 0) /* NAND device is ready bit */
+-
+-/**********************************************************************
+-* slc_int_stat, slc_ien, slc_isr, and slc_icr register definitions
+-**********************************************************************/
+-#define SLCSTAT_INT_TC		(1 << 1) /* Transfer count bit */
+-#define SLCSTAT_INT_RDY_EN	(1 << 0) /* Ready interrupt bit */
+-
+-/**********************************************************************
+-* slc_tac register definitions
+-**********************************************************************/
+-/* Computation of clock cycles on basis of controller and device clock rates */
+-#define SLCTAC_CLOCKS(c, n, s)	(min_t(u32, DIV_ROUND_UP(c, n) - 1, 0xF) << s)
+-
+-/* Clock setting for RDY write sample wait time in 2*n clocks */
+-#define SLCTAC_WDR(n)		(((n) & 0xF) << 28)
+-/* Write pulse width in clock cycles, 1 to 16 clocks */
+-#define SLCTAC_WWIDTH(c, n)	(SLCTAC_CLOCKS(c, n, 24))
+-/* Write hold time of control and data signals, 1 to 16 clocks */
+-#define SLCTAC_WHOLD(c, n)	(SLCTAC_CLOCKS(c, n, 20))
+-/* Write setup time of control and data signals, 1 to 16 clocks */
+-#define SLCTAC_WSETUP(c, n)	(SLCTAC_CLOCKS(c, n, 16))
+-/* Clock setting for RDY read sample wait time in 2*n clocks */
+-#define SLCTAC_RDR(n)		(((n) & 0xF) << 12)
+-/* Read pulse width in clock cycles, 1 to 16 clocks */
+-#define SLCTAC_RWIDTH(c, n)	(SLCTAC_CLOCKS(c, n, 8))
+-/* Read hold time of control and data signals, 1 to 16 clocks */
+-#define SLCTAC_RHOLD(c, n)	(SLCTAC_CLOCKS(c, n, 4))
+-/* Read setup time of control and data signals, 1 to 16 clocks */
+-#define SLCTAC_RSETUP(c, n)	(SLCTAC_CLOCKS(c, n, 0))
+-
+-/**********************************************************************
+-* slc_ecc register definitions
+-**********************************************************************/
+-/* ECC line party fetch macro */
+-#define SLCECC_TO_LINEPAR(n)	(((n) >> 6) & 0x7FFF)
+-#define SLCECC_TO_COLPAR(n)	((n) & 0x3F)
+-
+-/*
+- * DMA requires storage space for the DMA local buffer and the hardware ECC
+- * storage area. The DMA local buffer is only used if DMA mapping fails
+- * during runtime.
+- */
+-#define LPC32XX_DMA_DATA_SIZE		4096
+-#define LPC32XX_ECC_SAVE_SIZE		((4096 / 256) * 4)
+-
+-/* Number of bytes used for ECC stored in NAND per 256 bytes */
+-#define LPC32XX_SLC_DEV_ECC_BYTES	3
+-
+-/*
+- * If the NAND base clock frequency can't be fetched, this frequency will be
+- * used instead as the base. This rate is used to setup the timing registers
+- * used for NAND accesses.
+- */
+-#define LPC32XX_DEF_BUS_RATE		133250000
+-
+-/* Milliseconds for DMA FIFO timeout (unlikely anyway) */
+-#define LPC32XX_DMA_TIMEOUT		100
+-
+-/*
+- * NAND ECC Layout for small page NAND devices
+- * Note: For large and huge page devices, the default layouts are used
+- */
+-static int lpc32xx_ooblayout_ecc(struct mtd_info *mtd, int section,
+-				 struct mtd_oob_region *oobregion)
+-{
+-	if (section)
+-		return -ERANGE;
+-
+-	oobregion->length = 6;
+-	oobregion->offset = 10;
+-
+-	return 0;
+-}
+-
+-static int lpc32xx_ooblayout_free(struct mtd_info *mtd, int section,
+-				  struct mtd_oob_region *oobregion)
+-{
+-	if (section > 1)
+-		return -ERANGE;
+-
+-	if (!section) {
+-		oobregion->offset = 0;
+-		oobregion->length = 4;
+-	} else {
+-		oobregion->offset = 6;
+-		oobregion->length = 4;
+-	}
+-
+-	return 0;
+-}
+-
+-static const struct mtd_ooblayout_ops lpc32xx_ooblayout_ops = {
+-	.ecc = lpc32xx_ooblayout_ecc,
+-	.free = lpc32xx_ooblayout_free,
+-};
+-
+-static u8 bbt_pattern[] = {'B', 'b', 't', '0' };
+-static u8 mirror_pattern[] = {'1', 't', 'b', 'B' };
+-
+-/*
+- * Small page FLASH BBT descriptors, marker at offset 0, version at offset 6
+- * Note: Large page devices used the default layout
+- */
+-static struct nand_bbt_descr bbt_smallpage_main_descr = {
+-	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
+-		| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
+-	.offs =	0,
+-	.len = 4,
+-	.veroffs = 6,
+-	.maxblocks = 4,
+-	.pattern = bbt_pattern
+-};
+-
+-static struct nand_bbt_descr bbt_smallpage_mirror_descr = {
+-	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
+-		| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
+-	.offs =	0,
+-	.len = 4,
+-	.veroffs = 6,
+-	.maxblocks = 4,
+-	.pattern = mirror_pattern
+-};
+-
+-/*
+- * NAND platform configuration structure
+- */
+-struct lpc32xx_nand_cfg_slc {
+-	uint32_t wdr_clks;
+-	uint32_t wwidth;
+-	uint32_t whold;
+-	uint32_t wsetup;
+-	uint32_t rdr_clks;
+-	uint32_t rwidth;
+-	uint32_t rhold;
+-	uint32_t rsetup;
+-	int wp_gpio;
+-	struct mtd_partition *parts;
+-	unsigned num_parts;
+-};
+-
+-struct lpc32xx_nand_host {
+-	struct nand_chip	nand_chip;
+-	struct lpc32xx_slc_platform_data *pdata;
+-	struct clk		*clk;
+-	void __iomem		*io_base;
+-	struct lpc32xx_nand_cfg_slc *ncfg;
+-
+-	struct completion	comp;
+-	struct dma_chan		*dma_chan;
+-	uint32_t		dma_buf_len;
+-	struct dma_slave_config	dma_slave_config;
+-	struct scatterlist	sgl;
+-
+-	/*
+-	 * DMA and CPU addresses of ECC work area and data buffer
+-	 */
+-	uint32_t		*ecc_buf;
+-	uint8_t			*data_buf;
+-	dma_addr_t		io_base_dma;
+-};
+-
+-static void lpc32xx_nand_setup(struct lpc32xx_nand_host *host)
+-{
+-	uint32_t clkrate, tmp;
+-
+-	/* Reset SLC controller */
+-	writel(SLCCTRL_SW_RESET, SLC_CTRL(host->io_base));
+-	udelay(1000);
+-
+-	/* Basic setup */
+-	writel(0, SLC_CFG(host->io_base));
+-	writel(0, SLC_IEN(host->io_base));
+-	writel((SLCSTAT_INT_TC | SLCSTAT_INT_RDY_EN),
+-		SLC_ICR(host->io_base));
+-
+-	/* Get base clock for SLC block */
+-	clkrate = clk_get_rate(host->clk);
+-	if (clkrate == 0)
+-		clkrate = LPC32XX_DEF_BUS_RATE;
+-
+-	/* Compute clock setup values */
+-	tmp = SLCTAC_WDR(host->ncfg->wdr_clks) |
+-		SLCTAC_WWIDTH(clkrate, host->ncfg->wwidth) |
+-		SLCTAC_WHOLD(clkrate, host->ncfg->whold) |
+-		SLCTAC_WSETUP(clkrate, host->ncfg->wsetup) |
+-		SLCTAC_RDR(host->ncfg->rdr_clks) |
+-		SLCTAC_RWIDTH(clkrate, host->ncfg->rwidth) |
+-		SLCTAC_RHOLD(clkrate, host->ncfg->rhold) |
+-		SLCTAC_RSETUP(clkrate, host->ncfg->rsetup);
+-	writel(tmp, SLC_TAC(host->io_base));
+-}
+-
+-/*
+- * Hardware specific access to control lines
+- */
+-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 lpc32xx_nand_host *host = nand_get_controller_data(chip);
+-
+-	/* Does CE state need to be changed? */
+-	tmp = readl(SLC_CFG(host->io_base));
+-	if (ctrl & NAND_NCE)
+-		tmp |= SLCCFG_CE_LOW;
+-	else
+-		tmp &= ~SLCCFG_CE_LOW;
+-	writel(tmp, SLC_CFG(host->io_base));
+-
+-	if (cmd != NAND_CMD_NONE) {
+-		if (ctrl & NAND_CLE)
+-			writel(cmd, SLC_CMD(host->io_base));
+-		else
+-			writel(cmd, SLC_ADDR(host->io_base));
+-	}
+-}
+-
+-/*
+- * Read the Device Ready pin
+- */
+-static int lpc32xx_nand_device_ready(struct mtd_info *mtd)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
+-	int rdy = 0;
+-
+-	if ((readl(SLC_STAT(host->io_base)) & SLCSTAT_NAND_READY) != 0)
+-		rdy = 1;
+-
+-	return rdy;
+-}
+-
+-/*
+- * Enable NAND write protect
+- */
+-static void lpc32xx_wp_enable(struct lpc32xx_nand_host *host)
+-{
+-	if (gpio_is_valid(host->ncfg->wp_gpio))
+-		gpio_set_value(host->ncfg->wp_gpio, 0);
+-}
+-
+-/*
+- * Disable NAND write protect
+- */
+-static void lpc32xx_wp_disable(struct lpc32xx_nand_host *host)
+-{
+-	if (gpio_is_valid(host->ncfg->wp_gpio))
+-		gpio_set_value(host->ncfg->wp_gpio, 1);
+-}
+-
+-/*
+- * Prepares SLC for transfers with H/W ECC enabled
+- */
+-static void lpc32xx_nand_ecc_enable(struct mtd_info *mtd, int mode)
+-{
+-	/* Hardware ECC is enabled automatically in hardware as needed */
+-}
+-
+-/*
+- * Calculates the ECC for the data
+- */
+-static int lpc32xx_nand_ecc_calculate(struct mtd_info *mtd,
+-				      const unsigned char *buf,
+-				      unsigned char *code)
+-{
+-	/*
+-	 * ECC is calculated automatically in hardware during syndrome read
+-	 * and write operations, so it doesn't need to be calculated here.
+-	 */
+-	return 0;
+-}
+-
+-/*
+- * Read a single byte from NAND device
+- */
+-static uint8_t lpc32xx_nand_read_byte(struct mtd_info *mtd)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
+-
+-	return (uint8_t)readl(SLC_DATA(host->io_base));
+-}
+-
+-/*
+- * Simple device read without ECC
+- */
+-static void lpc32xx_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
+-
+-	/* Direct device read with no ECC */
+-	while (len-- > 0)
+-		*buf++ = (uint8_t)readl(SLC_DATA(host->io_base));
+-}
+-
+-/*
+- * Simple device write without ECC
+- */
+-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 lpc32xx_nand_host *host = nand_get_controller_data(chip);
+-
+-	/* Direct device write with no ECC */
+-	while (len-- > 0)
+-		writel((uint32_t)*buf++, SLC_DATA(host->io_base));
+-}
+-
+-/*
+- * Read the OOB data from the device without ECC using FIFO method
+- */
+-static int lpc32xx_nand_read_oob_syndrome(struct mtd_info *mtd,
+-					  struct nand_chip *chip, int page)
+-{
+-	chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
+-	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+-
+-	return 0;
+-}
+-
+-/*
+- * Write the OOB data to the device without ECC using FIFO method
+- */
+-static int lpc32xx_nand_write_oob_syndrome(struct mtd_info *mtd,
+-	struct nand_chip *chip, int page)
+-{
+-	int status;
+-
+-	chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page);
+-	chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+-
+-	/* Send command to program the OOB data */
+-	chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+-
+-	status = chip->waitfunc(mtd, chip);
+-
+-	return status & NAND_STATUS_FAIL ? -EIO : 0;
+-}
+-
+-/*
+- * Fills in the ECC fields in the OOB buffer with the hardware generated ECC
+- */
+-static void lpc32xx_slc_ecc_copy(uint8_t *spare, const uint32_t *ecc, int count)
+-{
+-	int i;
+-
+-	for (i = 0; i < (count * 3); i += 3) {
+-		uint32_t ce = ecc[i / 3];
+-		ce = ~(ce << 2) & 0xFFFFFF;
+-		spare[i + 2] = (uint8_t)(ce & 0xFF);
+-		ce >>= 8;
+-		spare[i + 1] = (uint8_t)(ce & 0xFF);
+-		ce >>= 8;
+-		spare[i] = (uint8_t)(ce & 0xFF);
+-	}
+-}
+-
+-static void lpc32xx_dma_complete_func(void *completion)
+-{
+-	complete(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 lpc32xx_nand_host *host = nand_get_controller_data(chip);
+-	struct dma_async_tx_descriptor *desc;
+-	int flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
+-	int res;
+-
+-	host->dma_slave_config.direction = dir;
+-	host->dma_slave_config.src_addr = dma;
+-	host->dma_slave_config.dst_addr = dma;
+-	host->dma_slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+-	host->dma_slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+-	host->dma_slave_config.src_maxburst = 4;
+-	host->dma_slave_config.dst_maxburst = 4;
+-	/* DMA controller does flow control: */
+-	host->dma_slave_config.device_fc = false;
+-	if (dmaengine_slave_config(host->dma_chan, &host->dma_slave_config)) {
+-		dev_err(mtd->dev.parent, "Failed to setup DMA slave\n");
+-		return -ENXIO;
+-	}
+-
+-	sg_init_one(&host->sgl, mem, len);
+-
+-	res = dma_map_sg(host->dma_chan->device->dev, &host->sgl, 1,
+-			 DMA_BIDIRECTIONAL);
+-	if (res != 1) {
+-		dev_err(mtd->dev.parent, "Failed to map sg list\n");
+-		return -ENXIO;
+-	}
+-	desc = dmaengine_prep_slave_sg(host->dma_chan, &host->sgl, 1, dir,
+-				       flags);
+-	if (!desc) {
+-		dev_err(mtd->dev.parent, "Failed to prepare slave sg\n");
+-		goto out1;
+-	}
+-
+-	init_completion(&host->comp);
+-	desc->callback = lpc32xx_dma_complete_func;
+-	desc->callback_param = &host->comp;
+-
+-	dmaengine_submit(desc);
+-	dma_async_issue_pending(host->dma_chan);
+-
+-	wait_for_completion_timeout(&host->comp, msecs_to_jiffies(1000));
+-
+-	dma_unmap_sg(host->dma_chan->device->dev, &host->sgl, 1,
+-		     DMA_BIDIRECTIONAL);
+-
+-	return 0;
+-out1:
+-	dma_unmap_sg(host->dma_chan->device->dev, &host->sgl, 1,
+-		     DMA_BIDIRECTIONAL);
+-	return -ENXIO;
+-}
+-
+-/*
+- * DMA read/write transfers with ECC support
+- */
+-static int lpc32xx_xfer(struct mtd_info *mtd, uint8_t *buf, int eccsubpages,
+-			int read)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
+-	int i, status = 0;
+-	unsigned long timeout;
+-	int res;
+-	enum dma_transfer_direction dir =
+-		read ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV;
+-	uint8_t *dma_buf;
+-	bool dma_mapped;
+-
+-	if ((void *)buf <= high_memory) {
+-		dma_buf = buf;
+-		dma_mapped = true;
+-	} else {
+-		dma_buf = host->data_buf;
+-		dma_mapped = false;
+-		if (!read)
+-			memcpy(host->data_buf, buf, mtd->writesize);
+-	}
+-
+-	if (read) {
+-		writel(readl(SLC_CFG(host->io_base)) |
+-		       SLCCFG_DMA_DIR | SLCCFG_ECC_EN | SLCCFG_DMA_ECC |
+-		       SLCCFG_DMA_BURST, SLC_CFG(host->io_base));
+-	} else {
+-		writel((readl(SLC_CFG(host->io_base)) |
+-			SLCCFG_ECC_EN | SLCCFG_DMA_ECC | SLCCFG_DMA_BURST) &
+-		       ~SLCCFG_DMA_DIR,
+-			SLC_CFG(host->io_base));
+-	}
+-
+-	/* Clear initial ECC */
+-	writel(SLCCTRL_ECC_CLEAR, SLC_CTRL(host->io_base));
+-
+-	/* Transfer size is data area only */
+-	writel(mtd->writesize, SLC_TC(host->io_base));
+-
+-	/* Start transfer in the NAND controller */
+-	writel(readl(SLC_CTRL(host->io_base)) | SLCCTRL_DMA_START,
+-	       SLC_CTRL(host->io_base));
+-
+-	for (i = 0; i < chip->ecc.steps; i++) {
+-		/* Data */
+-		res = lpc32xx_xmit_dma(mtd, SLC_DMA_DATA(host->io_base_dma),
+-				       dma_buf + i * chip->ecc.size,
+-				       mtd->writesize / chip->ecc.steps, dir);
+-		if (res)
+-			return res;
+-
+-		/* Always _read_ ECC */
+-		if (i == chip->ecc.steps - 1)
+-			break;
+-		if (!read) /* ECC availability delayed on write */
+-			udelay(10);
+-		res = lpc32xx_xmit_dma(mtd, SLC_ECC(host->io_base_dma),
+-				       &host->ecc_buf[i], 4, DMA_DEV_TO_MEM);
+-		if (res)
+-			return res;
+-	}
+-
+-	/*
+-	 * According to NXP, the DMA can be finished here, but the NAND
+-	 * controller may still have buffered data. After porting to using the
+-	 * dmaengine DMA driver (amba-pl080), the condition (DMA_FIFO empty)
+-	 * appears to be always true, according to tests. Keeping the check for
+-	 * safety reasons for now.
+-	 */
+-	if (readl(SLC_STAT(host->io_base)) & SLCSTAT_DMA_FIFO) {
+-		dev_warn(mtd->dev.parent, "FIFO not empty!\n");
+-		timeout = jiffies + msecs_to_jiffies(LPC32XX_DMA_TIMEOUT);
+-		while ((readl(SLC_STAT(host->io_base)) & SLCSTAT_DMA_FIFO) &&
+-		       time_before(jiffies, timeout))
+-			cpu_relax();
+-		if (!time_before(jiffies, timeout)) {
+-			dev_err(mtd->dev.parent, "FIFO held data too long\n");
+-			status = -EIO;
+-		}
+-	}
+-
+-	/* Read last calculated ECC value */
+-	if (!read)
+-		udelay(10);
+-	host->ecc_buf[chip->ecc.steps - 1] =
+-		readl(SLC_ECC(host->io_base));
+-
+-	/* Flush DMA */
+-	dmaengine_terminate_all(host->dma_chan);
+-
+-	if (readl(SLC_STAT(host->io_base)) & SLCSTAT_DMA_FIFO ||
+-	    readl(SLC_TC(host->io_base))) {
+-		/* Something is left in the FIFO, something is wrong */
+-		dev_err(mtd->dev.parent, "DMA FIFO failure\n");
+-		status = -EIO;
+-	}
+-
+-	/* Stop DMA & HW ECC */
+-	writel(readl(SLC_CTRL(host->io_base)) & ~SLCCTRL_DMA_START,
+-	       SLC_CTRL(host->io_base));
+-	writel(readl(SLC_CFG(host->io_base)) &
+-	       ~(SLCCFG_DMA_DIR | SLCCFG_ECC_EN | SLCCFG_DMA_ECC |
+-		 SLCCFG_DMA_BURST), SLC_CFG(host->io_base));
+-
+-	if (!dma_mapped && read)
+-		memcpy(buf, host->data_buf, mtd->writesize);
+-
+-	return status;
+-}
+-
+-/*
+- * Read the data and OOB data from the device, use ECC correction with the
+- * data, disable ECC for the OOB data
+- */
+-static int lpc32xx_nand_read_page_syndrome(struct mtd_info *mtd,
+-					   struct nand_chip *chip, uint8_t *buf,
+-					   int oob_required, int page)
+-{
+-	struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
+-	struct mtd_oob_region oobregion = { };
+-	int stat, i, status, error;
+-	uint8_t *oobecc, tmpecc[LPC32XX_ECC_SAVE_SIZE];
+-
+-	/* Issue read command */
+-	chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
+-
+-	/* Read data and oob, calculate ECC */
+-	status = lpc32xx_xfer(mtd, buf, chip->ecc.steps, 1);
+-
+-	/* Get OOB data */
+-	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+-
+-	/* Convert to stored ECC format */
+-	lpc32xx_slc_ecc_copy(tmpecc, (uint32_t *) host->ecc_buf, chip->ecc.steps);
+-
+-	/* Pointer to ECC data retrieved from NAND spare area */
+-	error = mtd_ooblayout_ecc(mtd, 0, &oobregion);
+-	if (error)
+-		return error;
+-
+-	oobecc = chip->oob_poi + oobregion.offset;
+-
+-	for (i = 0; i < chip->ecc.steps; i++) {
+-		stat = chip->ecc.correct(mtd, buf, oobecc,
+-					 &tmpecc[i * chip->ecc.bytes]);
+-		if (stat < 0)
+-			mtd->ecc_stats.failed++;
+-		else
+-			mtd->ecc_stats.corrected += stat;
+-
+-		buf += chip->ecc.size;
+-		oobecc += chip->ecc.bytes;
+-	}
+-
+-	return status;
+-}
+-
+-/*
+- * Read the data and OOB data from the device, no ECC correction with the
+- * data or OOB data
+- */
+-static int lpc32xx_nand_read_page_raw_syndrome(struct mtd_info *mtd,
+-					       struct nand_chip *chip,
+-					       uint8_t *buf, int oob_required,
+-					       int page)
+-{
+-	/* Issue read command */
+-	chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
+-
+-	/* Raw reads can just use the FIFO interface */
+-	chip->read_buf(mtd, buf, chip->ecc.size * chip->ecc.steps);
+-	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+-
+-	return 0;
+-}
+-
+-/*
+- * Write the data and OOB data to the device, use ECC with the data,
+- * disable ECC for the OOB data
+- */
+-static int lpc32xx_nand_write_page_syndrome(struct mtd_info *mtd,
+-					    struct nand_chip *chip,
+-					    const uint8_t *buf,
+-					    int oob_required, int page)
+-{
+-	struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
+-	struct mtd_oob_region oobregion = { };
+-	uint8_t *pb;
+-	int error;
+-
+-	/* Write data, calculate ECC on outbound data */
+-	error = lpc32xx_xfer(mtd, (uint8_t *)buf, chip->ecc.steps, 0);
+-	if (error)
+-		return error;
+-
+-	/*
+-	 * The calculated ECC needs some manual work done to it before
+-	 * committing it to NAND. Process the calculated ECC and place
+-	 * the resultant values directly into the OOB buffer. */
+-	error = mtd_ooblayout_ecc(mtd, 0, &oobregion);
+-	if (error)
+-		return error;
+-
+-	pb = chip->oob_poi + oobregion.offset;
+-	lpc32xx_slc_ecc_copy(pb, (uint32_t *)host->ecc_buf, chip->ecc.steps);
+-
+-	/* Write ECC data to device */
+-	chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+-	return 0;
+-}
+-
+-/*
+- * Write the data and OOB data to the device, no ECC correction with the
+- * data or OOB data
+- */
+-static int lpc32xx_nand_write_page_raw_syndrome(struct mtd_info *mtd,
+-						struct nand_chip *chip,
+-						const uint8_t *buf,
+-						int oob_required, int page)
+-{
+-	/* Raw writes can just use the FIFO interface */
+-	chip->write_buf(mtd, buf, chip->ecc.size * chip->ecc.steps);
+-	chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+-	return 0;
+-}
+-
+-static int lpc32xx_nand_dma_setup(struct lpc32xx_nand_host *host)
+-{
+-	struct mtd_info *mtd = nand_to_mtd(&host->nand_chip);
+-	dma_cap_mask_t mask;
+-
+-	if (!host->pdata || !host->pdata->dma_filter) {
+-		dev_err(mtd->dev.parent, "no DMA platform data\n");
+-		return -ENOENT;
+-	}
+-
+-	dma_cap_zero(mask);
+-	dma_cap_set(DMA_SLAVE, mask);
+-	host->dma_chan = dma_request_channel(mask, host->pdata->dma_filter,
+-					     "nand-slc");
+-	if (!host->dma_chan) {
+-		dev_err(mtd->dev.parent, "Failed to request DMA channel\n");
+-		return -EBUSY;
+-	}
+-
+-	return 0;
+-}
+-
+-static struct lpc32xx_nand_cfg_slc *lpc32xx_parse_dt(struct device *dev)
+-{
+-	struct lpc32xx_nand_cfg_slc *ncfg;
+-	struct device_node *np = dev->of_node;
+-
+-	ncfg = devm_kzalloc(dev, sizeof(*ncfg), GFP_KERNEL);
+-	if (!ncfg)
+-		return NULL;
+-
+-	of_property_read_u32(np, "nxp,wdr-clks", &ncfg->wdr_clks);
+-	of_property_read_u32(np, "nxp,wwidth", &ncfg->wwidth);
+-	of_property_read_u32(np, "nxp,whold", &ncfg->whold);
+-	of_property_read_u32(np, "nxp,wsetup", &ncfg->wsetup);
+-	of_property_read_u32(np, "nxp,rdr-clks", &ncfg->rdr_clks);
+-	of_property_read_u32(np, "nxp,rwidth", &ncfg->rwidth);
+-	of_property_read_u32(np, "nxp,rhold", &ncfg->rhold);
+-	of_property_read_u32(np, "nxp,rsetup", &ncfg->rsetup);
+-
+-	if (!ncfg->wdr_clks || !ncfg->wwidth || !ncfg->whold ||
+-	    !ncfg->wsetup || !ncfg->rdr_clks || !ncfg->rwidth ||
+-	    !ncfg->rhold || !ncfg->rsetup) {
+-		dev_err(dev, "chip parameters not specified correctly\n");
+-		return NULL;
+-	}
+-
+-	ncfg->wp_gpio = of_get_named_gpio(np, "gpios", 0);
+-
+-	return ncfg;
+-}
+-
+-/*
+- * Probe for NAND controller
+- */
+-static int lpc32xx_nand_probe(struct platform_device *pdev)
+-{
+-	struct lpc32xx_nand_host *host;
+-	struct mtd_info *mtd;
+-	struct nand_chip *chip;
+-	struct resource *rc;
+-	int res;
+-
+-	/* Allocate memory for the device structure (and zero it) */
+-	host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
+-	if (!host)
+-		return -ENOMEM;
+-
+-	rc = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+-	host->io_base = devm_ioremap_resource(&pdev->dev, rc);
+-	if (IS_ERR(host->io_base))
+-		return PTR_ERR(host->io_base);
+-
+-	host->io_base_dma = rc->start;
+-	if (pdev->dev.of_node)
+-		host->ncfg = lpc32xx_parse_dt(&pdev->dev);
+-	if (!host->ncfg) {
+-		dev_err(&pdev->dev,
+-			"Missing or bad NAND config from device tree\n");
+-		return -ENOENT;
+-	}
+-	if (host->ncfg->wp_gpio == -EPROBE_DEFER)
+-		return -EPROBE_DEFER;
+-	if (gpio_is_valid(host->ncfg->wp_gpio) && devm_gpio_request(&pdev->dev,
+-			host->ncfg->wp_gpio, "NAND WP")) {
+-		dev_err(&pdev->dev, "GPIO not available\n");
+-		return -EBUSY;
+-	}
+-	lpc32xx_wp_disable(host);
+-
+-	host->pdata = dev_get_platdata(&pdev->dev);
+-
+-	chip = &host->nand_chip;
+-	mtd = nand_to_mtd(chip);
+-	nand_set_controller_data(chip, host);
+-	nand_set_flash_node(chip, pdev->dev.of_node);
+-	mtd->owner = THIS_MODULE;
+-	mtd->dev.parent = &pdev->dev;
+-
+-	/* Get NAND clock */
+-	host->clk = devm_clk_get(&pdev->dev, NULL);
+-	if (IS_ERR(host->clk)) {
+-		dev_err(&pdev->dev, "Clock failure\n");
+-		res = -ENOENT;
+-		goto err_exit1;
+-	}
+-	res = clk_prepare_enable(host->clk);
+-	if (res)
+-		goto err_exit1;
+-
+-	/* Set NAND IO addresses and command/ready functions */
+-	chip->IO_ADDR_R = SLC_DATA(host->io_base);
+-	chip->IO_ADDR_W = SLC_DATA(host->io_base);
+-	chip->cmd_ctrl = lpc32xx_nand_cmd_ctrl;
+-	chip->dev_ready = lpc32xx_nand_device_ready;
+-	chip->chip_delay = 20; /* 20us command delay time */
+-
+-	/* Init NAND controller */
+-	lpc32xx_nand_setup(host);
+-
+-	platform_set_drvdata(pdev, host);
+-
+-	/* NAND callbacks for LPC32xx SLC hardware */
+-	chip->ecc.mode = NAND_ECC_HW_SYNDROME;
+-	chip->read_byte = lpc32xx_nand_read_byte;
+-	chip->read_buf = lpc32xx_nand_read_buf;
+-	chip->write_buf = lpc32xx_nand_write_buf;
+-	chip->ecc.read_page_raw = lpc32xx_nand_read_page_raw_syndrome;
+-	chip->ecc.read_page = lpc32xx_nand_read_page_syndrome;
+-	chip->ecc.write_page_raw = lpc32xx_nand_write_page_raw_syndrome;
+-	chip->ecc.write_page = lpc32xx_nand_write_page_syndrome;
+-	chip->ecc.write_oob = lpc32xx_nand_write_oob_syndrome;
+-	chip->ecc.read_oob = lpc32xx_nand_read_oob_syndrome;
+-	chip->ecc.calculate = lpc32xx_nand_ecc_calculate;
+-	chip->ecc.correct = nand_correct_data;
+-	chip->ecc.strength = 1;
+-	chip->ecc.hwctl = lpc32xx_nand_ecc_enable;
+-
+-	/*
+-	 * Allocate a large enough buffer for a single huge page plus
+-	 * extra space for the spare area and ECC storage area
+-	 */
+-	host->dma_buf_len = LPC32XX_DMA_DATA_SIZE + LPC32XX_ECC_SAVE_SIZE;
+-	host->data_buf = devm_kzalloc(&pdev->dev, host->dma_buf_len,
+-				      GFP_KERNEL);
+-	if (host->data_buf == NULL) {
+-		res = -ENOMEM;
+-		goto err_exit2;
+-	}
+-
+-	res = lpc32xx_nand_dma_setup(host);
+-	if (res) {
+-		res = -EIO;
+-		goto err_exit2;
+-	}
+-
+-	/* Find NAND device */
+-	res = nand_scan_ident(mtd, 1, NULL);
+-	if (res)
+-		goto err_exit3;
+-
+-	/* OOB and ECC CPU and DMA work areas */
+-	host->ecc_buf = (uint32_t *)(host->data_buf + LPC32XX_DMA_DATA_SIZE);
+-
+-	/*
+-	 * Small page FLASH has a unique OOB layout, but large and huge
+-	 * page FLASH use the standard layout. Small page FLASH uses a
+-	 * custom BBT marker layout.
+-	 */
+-	if (mtd->writesize <= 512)
+-		mtd_set_ooblayout(mtd, &lpc32xx_ooblayout_ops);
+-
+-	/* These sizes remain the same regardless of page size */
+-	chip->ecc.size = 256;
+-	chip->ecc.bytes = LPC32XX_SLC_DEV_ECC_BYTES;
+-	chip->ecc.prepad = chip->ecc.postpad = 0;
+-
+-	/*
+-	 * Use a custom BBT marker setup for small page FLASH that
+-	 * won't interfere with the ECC layout. Large and huge page
+-	 * FLASH use the standard layout.
+-	 */
+-	if ((chip->bbt_options & NAND_BBT_USE_FLASH) &&
+-	    mtd->writesize <= 512) {
+-		chip->bbt_td = &bbt_smallpage_main_descr;
+-		chip->bbt_md = &bbt_smallpage_mirror_descr;
+-	}
+-
+-	/*
+-	 * Fills out all the uninitialized function pointers with the defaults
+-	 */
+-	res = nand_scan_tail(mtd);
+-	if (res)
+-		goto err_exit3;
+-
+-	mtd->name = "nxp_lpc3220_slc";
+-	res = mtd_device_register(mtd, host->ncfg->parts,
+-				  host->ncfg->num_parts);
+-	if (!res)
+-		return res;
+-
+-	nand_release(mtd);
+-
+-err_exit3:
+-	dma_release_channel(host->dma_chan);
+-err_exit2:
+-	clk_disable_unprepare(host->clk);
+-err_exit1:
+-	lpc32xx_wp_enable(host);
+-
+-	return res;
+-}
+-
+-/*
+- * Remove NAND device.
+- */
+-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);
+-
+-	nand_release(mtd);
+-	dma_release_channel(host->dma_chan);
+-
+-	/* Force CE high */
+-	tmp = readl(SLC_CTRL(host->io_base));
+-	tmp &= ~SLCCFG_CE_LOW;
+-	writel(tmp, SLC_CTRL(host->io_base));
+-
+-	clk_disable_unprepare(host->clk);
+-	lpc32xx_wp_enable(host);
+-
+-	return 0;
+-}
+-
+-#ifdef CONFIG_PM
+-static int lpc32xx_nand_resume(struct platform_device *pdev)
+-{
+-	struct lpc32xx_nand_host *host = platform_get_drvdata(pdev);
+-	int ret;
+-
+-	/* Re-enable NAND clock */
+-	ret = clk_prepare_enable(host->clk);
+-	if (ret)
+-		return ret;
+-
+-	/* Fresh init of NAND controller */
+-	lpc32xx_nand_setup(host);
+-
+-	/* Disable write protect */
+-	lpc32xx_wp_disable(host);
+-
+-	return 0;
+-}
+-
+-static int lpc32xx_nand_suspend(struct platform_device *pdev, pm_message_t pm)
+-{
+-	uint32_t tmp;
+-	struct lpc32xx_nand_host *host = platform_get_drvdata(pdev);
+-
+-	/* Force CE high */
+-	tmp = readl(SLC_CTRL(host->io_base));
+-	tmp &= ~SLCCFG_CE_LOW;
+-	writel(tmp, SLC_CTRL(host->io_base));
+-
+-	/* Enable write protect for safety */
+-	lpc32xx_wp_enable(host);
+-
+-	/* Disable clock */
+-	clk_disable_unprepare(host->clk);
+-
+-	return 0;
+-}
+-
+-#else
+-#define lpc32xx_nand_resume NULL
+-#define lpc32xx_nand_suspend NULL
+-#endif
+-
+-static const struct of_device_id lpc32xx_nand_match[] = {
+-	{ .compatible = "nxp,lpc3220-slc" },
+-	{ /* sentinel */ },
+-};
+-MODULE_DEVICE_TABLE(of, lpc32xx_nand_match);
+-
+-static struct platform_driver lpc32xx_nand_driver = {
+-	.probe		= lpc32xx_nand_probe,
+-	.remove		= lpc32xx_nand_remove,
+-	.resume		= lpc32xx_nand_resume,
+-	.suspend	= lpc32xx_nand_suspend,
+-	.driver		= {
+-		.name	= LPC32XX_MODNAME,
+-		.of_match_table = lpc32xx_nand_match,
+-	},
+-};
+-
+-module_platform_driver(lpc32xx_nand_driver);
+-
+-MODULE_LICENSE("GPL");
+-MODULE_AUTHOR("Kevin Wells <kevin.wells@nxp.com>");
+-MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>");
+-MODULE_DESCRIPTION("NAND driver for the NXP LPC32XX SLC controller");
+diff --git a/drivers/mtd/nand/mpc5121_nfc.c b/drivers/mtd/nand/mpc5121_nfc.c
+deleted file mode 100644
+index b6b97cc9..0000000
+--- a/drivers/mtd/nand/mpc5121_nfc.c
++++ /dev/null
+@@ -1,857 +0,0 @@
+-/*
+- * Copyright 2004-2008 Freescale Semiconductor, Inc.
+- * Copyright 2009 Semihalf.
+- *
+- * Approved as OSADL project by a majority of OSADL members and funded
+- * by OSADL membership fees in 2009;  for details see www.osadl.org.
+- *
+- * Based on original driver from Freescale Semiconductor
+- * written by John Rigby <jrigby@freescale.com> on basis
+- * of drivers/mtd/nand/mxc_nand.c. Reworked and extended
+- * Piotr Ziecik <kosmo@semihalf.com>.
+- *
+- * 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.
+- *
+- * You should have received a copy of the GNU General Public License
+- * along with this program; if not, write to the Free Software
+- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+- * MA 02110-1301, USA.
+- */
+-
+-#include <linux/module.h>
+-#include <linux/clk.h>
+-#include <linux/gfp.h>
+-#include <linux/delay.h>
+-#include <linux/err.h>
+-#include <linux/interrupt.h>
+-#include <linux/io.h>
+-#include <linux/mtd/mtd.h>
+-#include <linux/mtd/rawnand.h>
+-#include <linux/mtd/partitions.h>
+-#include <linux/of_address.h>
+-#include <linux/of_device.h>
+-#include <linux/of_irq.h>
+-#include <linux/of_platform.h>
+-
+-#include <asm/mpc5121.h>
+-
+-/* Addresses for NFC MAIN RAM BUFFER areas */
+-#define NFC_MAIN_AREA(n)	((n) *  0x200)
+-
+-/* Addresses for NFC SPARE BUFFER areas */
+-#define NFC_SPARE_BUFFERS	8
+-#define NFC_SPARE_LEN		0x40
+-#define NFC_SPARE_AREA(n)	(0x1000 + ((n) * NFC_SPARE_LEN))
+-
+-/* MPC5121 NFC registers */
+-#define NFC_BUF_ADDR		0x1E04
+-#define NFC_FLASH_ADDR		0x1E06
+-#define NFC_FLASH_CMD		0x1E08
+-#define NFC_CONFIG		0x1E0A
+-#define NFC_ECC_STATUS1		0x1E0C
+-#define NFC_ECC_STATUS2		0x1E0E
+-#define NFC_SPAS		0x1E10
+-#define NFC_WRPROT		0x1E12
+-#define NFC_NF_WRPRST		0x1E18
+-#define NFC_CONFIG1		0x1E1A
+-#define NFC_CONFIG2		0x1E1C
+-#define NFC_UNLOCKSTART_BLK0	0x1E20
+-#define NFC_UNLOCKEND_BLK0	0x1E22
+-#define NFC_UNLOCKSTART_BLK1	0x1E24
+-#define NFC_UNLOCKEND_BLK1	0x1E26
+-#define NFC_UNLOCKSTART_BLK2	0x1E28
+-#define NFC_UNLOCKEND_BLK2	0x1E2A
+-#define NFC_UNLOCKSTART_BLK3	0x1E2C
+-#define NFC_UNLOCKEND_BLK3	0x1E2E
+-
+-/* Bit Definitions: NFC_BUF_ADDR */
+-#define NFC_RBA_MASK		(7 << 0)
+-#define NFC_ACTIVE_CS_SHIFT	5
+-#define NFC_ACTIVE_CS_MASK	(3 << NFC_ACTIVE_CS_SHIFT)
+-
+-/* Bit Definitions: NFC_CONFIG */
+-#define NFC_BLS_UNLOCKED	(1 << 1)
+-
+-/* Bit Definitions: NFC_CONFIG1 */
+-#define NFC_ECC_4BIT		(1 << 0)
+-#define NFC_FULL_PAGE_DMA	(1 << 1)
+-#define NFC_SPARE_ONLY		(1 << 2)
+-#define NFC_ECC_ENABLE		(1 << 3)
+-#define NFC_INT_MASK		(1 << 4)
+-#define NFC_BIG_ENDIAN		(1 << 5)
+-#define NFC_RESET		(1 << 6)
+-#define NFC_CE			(1 << 7)
+-#define NFC_ONE_CYCLE		(1 << 8)
+-#define NFC_PPB_32		(0 << 9)
+-#define NFC_PPB_64		(1 << 9)
+-#define NFC_PPB_128		(2 << 9)
+-#define NFC_PPB_256		(3 << 9)
+-#define NFC_PPB_MASK		(3 << 9)
+-#define NFC_FULL_PAGE_INT	(1 << 11)
+-
+-/* Bit Definitions: NFC_CONFIG2 */
+-#define NFC_COMMAND		(1 << 0)
+-#define NFC_ADDRESS		(1 << 1)
+-#define NFC_INPUT		(1 << 2)
+-#define NFC_OUTPUT		(1 << 3)
+-#define NFC_ID			(1 << 4)
+-#define NFC_STATUS		(1 << 5)
+-#define NFC_CMD_FAIL		(1 << 15)
+-#define NFC_INT			(1 << 15)
+-
+-/* Bit Definitions: NFC_WRPROT */
+-#define NFC_WPC_LOCK_TIGHT	(1 << 0)
+-#define NFC_WPC_LOCK		(1 << 1)
+-#define NFC_WPC_UNLOCK		(1 << 2)
+-
+-#define	DRV_NAME		"mpc5121_nfc"
+-
+-/* Timeouts */
+-#define NFC_RESET_TIMEOUT	1000		/* 1 ms */
+-#define NFC_TIMEOUT		(HZ / 10)	/* 1/10 s */
+-
+-struct mpc5121_nfc_prv {
+-	struct nand_chip	chip;
+-	int			irq;
+-	void __iomem		*regs;
+-	struct clk		*clk;
+-	wait_queue_head_t	irq_waitq;
+-	uint			column;
+-	int			spareonly;
+-	void __iomem		*csreg;
+-	struct device		*dev;
+-};
+-
+-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 mpc5121_nfc_prv *prv = nand_get_controller_data(chip);
+-
+-	return in_be16(prv->regs + 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 mpc5121_nfc_prv *prv = nand_get_controller_data(chip);
+-
+-	out_be16(prv->regs + reg, val);
+-}
+-
+-/* Set bits in NFC register */
+-static inline void nfc_set(struct mtd_info *mtd, uint reg, u16 bits)
+-{
+-	nfc_write(mtd, reg, nfc_read(mtd, reg) | bits);
+-}
+-
+-/* Clear bits in NFC register */
+-static inline void nfc_clear(struct mtd_info *mtd, uint reg, u16 bits)
+-{
+-	nfc_write(mtd, reg, nfc_read(mtd, reg) & ~bits);
+-}
+-
+-/* Invoke address cycle */
+-static inline void mpc5121_nfc_send_addr(struct mtd_info *mtd, u16 addr)
+-{
+-	nfc_write(mtd, NFC_FLASH_ADDR, addr);
+-	nfc_write(mtd, NFC_CONFIG2, NFC_ADDRESS);
+-	mpc5121_nfc_done(mtd);
+-}
+-
+-/* Invoke command cycle */
+-static inline void mpc5121_nfc_send_cmd(struct mtd_info *mtd, u16 cmd)
+-{
+-	nfc_write(mtd, NFC_FLASH_CMD, cmd);
+-	nfc_write(mtd, NFC_CONFIG2, NFC_COMMAND);
+-	mpc5121_nfc_done(mtd);
+-}
+-
+-/* Send data from NFC buffers to NAND flash */
+-static inline void mpc5121_nfc_send_prog_page(struct mtd_info *mtd)
+-{
+-	nfc_clear(mtd, NFC_BUF_ADDR, NFC_RBA_MASK);
+-	nfc_write(mtd, NFC_CONFIG2, NFC_INPUT);
+-	mpc5121_nfc_done(mtd);
+-}
+-
+-/* Receive data from NAND flash */
+-static inline void mpc5121_nfc_send_read_page(struct mtd_info *mtd)
+-{
+-	nfc_clear(mtd, NFC_BUF_ADDR, NFC_RBA_MASK);
+-	nfc_write(mtd, NFC_CONFIG2, NFC_OUTPUT);
+-	mpc5121_nfc_done(mtd);
+-}
+-
+-/* Receive ID from NAND flash */
+-static inline void mpc5121_nfc_send_read_id(struct mtd_info *mtd)
+-{
+-	nfc_clear(mtd, NFC_BUF_ADDR, NFC_RBA_MASK);
+-	nfc_write(mtd, NFC_CONFIG2, NFC_ID);
+-	mpc5121_nfc_done(mtd);
+-}
+-
+-/* Receive status from NAND flash */
+-static inline void mpc5121_nfc_send_read_status(struct mtd_info *mtd)
+-{
+-	nfc_clear(mtd, NFC_BUF_ADDR, NFC_RBA_MASK);
+-	nfc_write(mtd, NFC_CONFIG2, NFC_STATUS);
+-	mpc5121_nfc_done(mtd);
+-}
+-
+-/* NFC interrupt handler */
+-static irqreturn_t mpc5121_nfc_irq(int irq, void *data)
+-{
+-	struct mtd_info *mtd = data;
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip);
+-
+-	nfc_set(mtd, NFC_CONFIG1, NFC_INT_MASK);
+-	wake_up(&prv->irq_waitq);
+-
+-	return IRQ_HANDLED;
+-}
+-
+-/* Wait for operation complete */
+-static void mpc5121_nfc_done(struct mtd_info *mtd)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip);
+-	int rv;
+-
+-	if ((nfc_read(mtd, NFC_CONFIG2) & NFC_INT) == 0) {
+-		nfc_clear(mtd, NFC_CONFIG1, NFC_INT_MASK);
+-		rv = wait_event_timeout(prv->irq_waitq,
+-			(nfc_read(mtd, NFC_CONFIG2) & NFC_INT), NFC_TIMEOUT);
+-
+-		if (!rv)
+-			dev_warn(prv->dev,
+-				"Timeout while waiting for interrupt.\n");
+-	}
+-
+-	nfc_clear(mtd, NFC_CONFIG2, NFC_INT);
+-}
+-
+-/* 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);
+-	u32 pagemask = chip->pagemask;
+-
+-	if (column != -1) {
+-		mpc5121_nfc_send_addr(mtd, column);
+-		if (mtd->writesize > 512)
+-			mpc5121_nfc_send_addr(mtd, column >> 8);
+-	}
+-
+-	if (page != -1) {
+-		do {
+-			mpc5121_nfc_send_addr(mtd, page & 0xFF);
+-			page >>= 8;
+-			pagemask >>= 8;
+-		} while (pagemask);
+-	}
+-}
+-
+-/* Control chip select signals */
+-static void mpc5121_nfc_select_chip(struct mtd_info *mtd, int chip)
+-{
+-	if (chip < 0) {
+-		nfc_clear(mtd, NFC_CONFIG1, NFC_CE);
+-		return;
+-	}
+-
+-	nfc_clear(mtd, NFC_BUF_ADDR, NFC_ACTIVE_CS_MASK);
+-	nfc_set(mtd, NFC_BUF_ADDR, (chip << NFC_ACTIVE_CS_SHIFT) &
+-							NFC_ACTIVE_CS_MASK);
+-	nfc_set(mtd, NFC_CONFIG1, NFC_CE);
+-}
+-
+-/* 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 mpc5121_nfc_prv *prv = nand_get_controller_data(chip);
+-	struct device_node *dn;
+-
+-	dn = of_find_compatible_node(NULL, NULL, "fsl,mpc5121ads-cpld");
+-	if (dn) {
+-		prv->csreg = of_iomap(dn, 0);
+-		of_node_put(dn);
+-		if (!prv->csreg)
+-			return -ENOMEM;
+-
+-		/* CPLD Register 9 controls NAND /CE Lines */
+-		prv->csreg += 9;
+-		return 0;
+-	}
+-
+-	return -EINVAL;
+-}
+-
+-/* 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 mpc5121_nfc_prv *prv = nand_get_controller_data(nand);
+-	u8 v;
+-
+-	v = in_8(prv->csreg);
+-	v |= 0x0F;
+-
+-	if (chip >= 0) {
+-		mpc5121_nfc_select_chip(mtd, 0);
+-		v &= ~(1 << chip);
+-	} else
+-		mpc5121_nfc_select_chip(mtd, -1);
+-
+-	out_8(prv->csreg, v);
+-}
+-
+-/* Read NAND Ready/Busy signal */
+-static int mpc5121_nfc_dev_ready(struct mtd_info *mtd)
+-{
+-	/*
+-	 * NFC handles ready/busy signal internally. Therefore, this function
+-	 * always returns status as ready.
+-	 */
+-	return 1;
+-}
+-
+-/* Write command to NAND flash */
+-static void mpc5121_nfc_command(struct mtd_info *mtd, unsigned command,
+-							int column, int page)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip);
+-
+-	prv->column = (column >= 0) ? column : 0;
+-	prv->spareonly = 0;
+-
+-	switch (command) {
+-	case NAND_CMD_PAGEPROG:
+-		mpc5121_nfc_send_prog_page(mtd);
+-		break;
+-	/*
+-	 * NFC does not support sub-page reads and writes,
+-	 * so emulate them using full page transfers.
+-	 */
+-	case NAND_CMD_READ0:
+-		column = 0;
+-		break;
+-
+-	case NAND_CMD_READ1:
+-		prv->column += 256;
+-		command = NAND_CMD_READ0;
+-		column = 0;
+-		break;
+-
+-	case NAND_CMD_READOOB:
+-		prv->spareonly = 1;
+-		command = NAND_CMD_READ0;
+-		column = 0;
+-		break;
+-
+-	case NAND_CMD_SEQIN:
+-		mpc5121_nfc_command(mtd, NAND_CMD_READ0, column, page);
+-		column = 0;
+-		break;
+-
+-	case NAND_CMD_ERASE1:
+-	case NAND_CMD_ERASE2:
+-	case NAND_CMD_READID:
+-	case NAND_CMD_STATUS:
+-		break;
+-
+-	default:
+-		return;
+-	}
+-
+-	mpc5121_nfc_send_cmd(mtd, command);
+-	mpc5121_nfc_addr_cycle(mtd, column, page);
+-
+-	switch (command) {
+-	case NAND_CMD_READ0:
+-		if (mtd->writesize > 512)
+-			mpc5121_nfc_send_cmd(mtd, NAND_CMD_READSTART);
+-		mpc5121_nfc_send_read_page(mtd);
+-		break;
+-
+-	case NAND_CMD_READID:
+-		mpc5121_nfc_send_read_id(mtd);
+-		break;
+-
+-	case NAND_CMD_STATUS:
+-		mpc5121_nfc_send_read_status(mtd);
+-		if (chip->options & NAND_BUSWIDTH_16)
+-			prv->column = 1;
+-		else
+-			prv->column = 0;
+-		break;
+-	}
+-}
+-
+-/* Copy data from/to NFC spare buffers. */
+-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 mpc5121_nfc_prv *prv = nand_get_controller_data(nand);
+-	uint o, s, sbsize, blksize;
+-
+-	/*
+-	 * NAND spare area is available through NFC spare buffers.
+-	 * The NFC divides spare area into (page_size / 512) chunks.
+-	 * Each chunk is placed into separate spare memory area, using
+-	 * first (spare_size / num_of_chunks) bytes of the buffer.
+-	 *
+-	 * For NAND device in which the spare area is not divided fully
+-	 * by the number of chunks, number of used bytes in each spare
+-	 * buffer is rounded down to the nearest even number of bytes,
+-	 * and all remaining bytes are added to the last used spare area.
+-	 *
+-	 * For more information read section 26.6.10 of MPC5121e
+-	 * Microcontroller Reference Manual, Rev. 3.
+-	 */
+-
+-	/* Calculate number of valid bytes in each spare buffer */
+-	sbsize = (mtd->oobsize / (mtd->writesize / 512)) & ~1;
+-
+-	while (size) {
+-		/* Calculate spare buffer number */
+-		s = offset / sbsize;
+-		if (s > NFC_SPARE_BUFFERS - 1)
+-			s = NFC_SPARE_BUFFERS - 1;
+-
+-		/*
+-		 * Calculate offset to requested data block in selected spare
+-		 * buffer and its size.
+-		 */
+-		o = offset - (s * sbsize);
+-		blksize = min(sbsize - o, size);
+-
+-		if (wr)
+-			memcpy_toio(prv->regs + NFC_SPARE_AREA(s) + o,
+-							buffer, blksize);
+-		else
+-			memcpy_fromio(buffer,
+-				prv->regs + NFC_SPARE_AREA(s) + o, blksize);
+-
+-		buffer += blksize;
+-		offset += blksize;
+-		size -= blksize;
+-	};
+-}
+-
+-/* Copy data from/to NFC main and spare buffers */
+-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 mpc5121_nfc_prv *prv = nand_get_controller_data(chip);
+-	uint c = prv->column;
+-	uint l;
+-
+-	/* Handle spare area access */
+-	if (prv->spareonly || c >= mtd->writesize) {
+-		/* Calculate offset from beginning of spare area */
+-		if (c >= mtd->writesize)
+-			c -= mtd->writesize;
+-
+-		prv->column += len;
+-		mpc5121_nfc_copy_spare(mtd, c, buf, len, wr);
+-		return;
+-	}
+-
+-	/*
+-	 * Handle main area access - limit copy length to prevent
+-	 * crossing main/spare boundary.
+-	 */
+-	l = min((uint)len, mtd->writesize - c);
+-	prv->column += l;
+-
+-	if (wr)
+-		memcpy_toio(prv->regs + NFC_MAIN_AREA(0) + c, buf, l);
+-	else
+-		memcpy_fromio(buf, prv->regs + NFC_MAIN_AREA(0) + c, l);
+-
+-	/* Handle crossing main/spare boundary */
+-	if (l != len) {
+-		buf += l;
+-		len -= l;
+-		mpc5121_nfc_buf_copy(mtd, buf, len, wr);
+-	}
+-}
+-
+-/* Read data from NFC buffers */
+-static void mpc5121_nfc_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+-{
+-	mpc5121_nfc_buf_copy(mtd, buf, len, 0);
+-}
+-
+-/* Write data to NFC buffers */
+-static void mpc5121_nfc_write_buf(struct mtd_info *mtd,
+-						const u_char *buf, int len)
+-{
+-	mpc5121_nfc_buf_copy(mtd, (u_char *)buf, len, 1);
+-}
+-
+-/* Read byte from NFC buffers */
+-static u8 mpc5121_nfc_read_byte(struct mtd_info *mtd)
+-{
+-	u8 tmp;
+-
+-	mpc5121_nfc_read_buf(mtd, &tmp, sizeof(tmp));
+-
+-	return tmp;
+-}
+-
+-/* Read word from NFC buffers */
+-static u16 mpc5121_nfc_read_word(struct mtd_info *mtd)
+-{
+-	u16 tmp;
+-
+-	mpc5121_nfc_read_buf(mtd, (u_char *)&tmp, sizeof(tmp));
+-
+-	return tmp;
+-}
+-
+-/*
+- * Read NFC configuration from Reset Config Word
+- *
+- * NFC is configured during reset in basis of information stored
+- * in Reset Config Word. There is no other way to set NAND block
+- * size, spare size and bus width.
+- */
+-static int mpc5121_nfc_read_hw_config(struct mtd_info *mtd)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip);
+-	struct mpc512x_reset_module *rm;
+-	struct device_node *rmnode;
+-	uint rcw_pagesize = 0;
+-	uint rcw_sparesize = 0;
+-	uint rcw_width;
+-	uint rcwh;
+-	uint romloc, ps;
+-	int ret = 0;
+-
+-	rmnode = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-reset");
+-	if (!rmnode) {
+-		dev_err(prv->dev, "Missing 'fsl,mpc5121-reset' "
+-					"node in device tree!\n");
+-		return -ENODEV;
+-	}
+-
+-	rm = of_iomap(rmnode, 0);
+-	if (!rm) {
+-		dev_err(prv->dev, "Error mapping reset module node!\n");
+-		ret = -EBUSY;
+-		goto out;
+-	}
+-
+-	rcwh = in_be32(&rm->rcwhr);
+-
+-	/* Bit 6: NFC bus width */
+-	rcw_width = ((rcwh >> 6) & 0x1) ? 2 : 1;
+-
+-	/* Bit 7: NFC Page/Spare size */
+-	ps = (rcwh >> 7) & 0x1;
+-
+-	/* Bits [22:21]: ROM Location */
+-	romloc = (rcwh >> 21) & 0x3;
+-
+-	/* Decode RCW bits */
+-	switch ((ps << 2) | romloc) {
+-	case 0x00:
+-	case 0x01:
+-		rcw_pagesize = 512;
+-		rcw_sparesize = 16;
+-		break;
+-	case 0x02:
+-	case 0x03:
+-		rcw_pagesize = 4096;
+-		rcw_sparesize = 128;
+-		break;
+-	case 0x04:
+-	case 0x05:
+-		rcw_pagesize = 2048;
+-		rcw_sparesize = 64;
+-		break;
+-	case 0x06:
+-	case 0x07:
+-		rcw_pagesize = 4096;
+-		rcw_sparesize = 218;
+-		break;
+-	}
+-
+-	mtd->writesize = rcw_pagesize;
+-	mtd->oobsize = rcw_sparesize;
+-	if (rcw_width == 2)
+-		chip->options |= NAND_BUSWIDTH_16;
+-
+-	dev_notice(prv->dev, "Configured for "
+-				"%u-bit NAND, page size %u "
+-				"with %u spare.\n",
+-				rcw_width * 8, rcw_pagesize,
+-				rcw_sparesize);
+-	iounmap(rm);
+-out:
+-	of_node_put(rmnode);
+-	return ret;
+-}
+-
+-/* Free driver resources */
+-static void mpc5121_nfc_free(struct device *dev, struct mtd_info *mtd)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip);
+-
+-	if (prv->clk)
+-		clk_disable_unprepare(prv->clk);
+-
+-	if (prv->csreg)
+-		iounmap(prv->csreg);
+-}
+-
+-static int mpc5121_nfc_probe(struct platform_device *op)
+-{
+-	struct device_node *dn = op->dev.of_node;
+-	struct clk *clk;
+-	struct device *dev = &op->dev;
+-	struct mpc5121_nfc_prv *prv;
+-	struct resource res;
+-	struct mtd_info *mtd;
+-	struct nand_chip *chip;
+-	unsigned long regs_paddr, regs_size;
+-	const __be32 *chips_no;
+-	int resettime = 0;
+-	int retval = 0;
+-	int rev, len;
+-
+-	/*
+-	 * Check SoC revision. This driver supports only NFC
+-	 * in MPC5121 revision 2 and MPC5123 revision 3.
+-	 */
+-	rev = (mfspr(SPRN_SVR) >> 4) & 0xF;
+-	if ((rev != 2) && (rev != 3)) {
+-		dev_err(dev, "SoC revision %u is not supported!\n", rev);
+-		return -ENXIO;
+-	}
+-
+-	prv = devm_kzalloc(dev, sizeof(*prv), GFP_KERNEL);
+-	if (!prv)
+-		return -ENOMEM;
+-
+-	chip = &prv->chip;
+-	mtd = nand_to_mtd(chip);
+-
+-	mtd->dev.parent = dev;
+-	nand_set_controller_data(chip, prv);
+-	nand_set_flash_node(chip, dn);
+-	prv->dev = dev;
+-
+-	/* Read NFC configuration from Reset Config Word */
+-	retval = mpc5121_nfc_read_hw_config(mtd);
+-	if (retval) {
+-		dev_err(dev, "Unable to read NFC config!\n");
+-		return retval;
+-	}
+-
+-	prv->irq = irq_of_parse_and_map(dn, 0);
+-	if (prv->irq == NO_IRQ) {
+-		dev_err(dev, "Error mapping IRQ!\n");
+-		return -EINVAL;
+-	}
+-
+-	retval = of_address_to_resource(dn, 0, &res);
+-	if (retval) {
+-		dev_err(dev, "Error parsing memory region!\n");
+-		return retval;
+-	}
+-
+-	chips_no = of_get_property(dn, "chips", &len);
+-	if (!chips_no || len != sizeof(*chips_no)) {
+-		dev_err(dev, "Invalid/missing 'chips' property!\n");
+-		return -EINVAL;
+-	}
+-
+-	regs_paddr = res.start;
+-	regs_size = resource_size(&res);
+-
+-	if (!devm_request_mem_region(dev, regs_paddr, regs_size, DRV_NAME)) {
+-		dev_err(dev, "Error requesting memory region!\n");
+-		return -EBUSY;
+-	}
+-
+-	prv->regs = devm_ioremap(dev, regs_paddr, regs_size);
+-	if (!prv->regs) {
+-		dev_err(dev, "Error mapping memory region!\n");
+-		return -ENOMEM;
+-	}
+-
+-	mtd->name = "MPC5121 NAND";
+-	chip->dev_ready = mpc5121_nfc_dev_ready;
+-	chip->cmdfunc = mpc5121_nfc_command;
+-	chip->read_byte = mpc5121_nfc_read_byte;
+-	chip->read_word = mpc5121_nfc_read_word;
+-	chip->read_buf = mpc5121_nfc_read_buf;
+-	chip->write_buf = mpc5121_nfc_write_buf;
+-	chip->select_chip = mpc5121_nfc_select_chip;
+-	chip->onfi_set_features	= nand_onfi_get_set_features_notsupp;
+-	chip->onfi_get_features	= nand_onfi_get_set_features_notsupp;
+-	chip->bbt_options = NAND_BBT_USE_FLASH;
+-	chip->ecc.mode = NAND_ECC_SOFT;
+-	chip->ecc.algo = NAND_ECC_HAMMING;
+-
+-	/* Support external chip-select logic on ADS5121 board */
+-	if (of_machine_is_compatible("fsl,mpc5121ads")) {
+-		retval = ads5121_chipselect_init(mtd);
+-		if (retval) {
+-			dev_err(dev, "Chipselect init error!\n");
+-			return retval;
+-		}
+-
+-		chip->select_chip = ads5121_select_chip;
+-	}
+-
+-	/* Enable NFC clock */
+-	clk = devm_clk_get(dev, "ipg");
+-	if (IS_ERR(clk)) {
+-		dev_err(dev, "Unable to acquire NFC clock!\n");
+-		retval = PTR_ERR(clk);
+-		goto error;
+-	}
+-	retval = clk_prepare_enable(clk);
+-	if (retval) {
+-		dev_err(dev, "Unable to enable NFC clock!\n");
+-		goto error;
+-	}
+-	prv->clk = clk;
+-
+-	/* Reset NAND Flash controller */
+-	nfc_set(mtd, NFC_CONFIG1, NFC_RESET);
+-	while (nfc_read(mtd, NFC_CONFIG1) & NFC_RESET) {
+-		if (resettime++ >= NFC_RESET_TIMEOUT) {
+-			dev_err(dev, "Timeout while resetting NFC!\n");
+-			retval = -EINVAL;
+-			goto error;
+-		}
+-
+-		udelay(1);
+-	}
+-
+-	/* Enable write to NFC memory */
+-	nfc_write(mtd, NFC_CONFIG, NFC_BLS_UNLOCKED);
+-
+-	/* Enable write to all NAND pages */
+-	nfc_write(mtd, NFC_UNLOCKSTART_BLK0, 0x0000);
+-	nfc_write(mtd, NFC_UNLOCKEND_BLK0, 0xFFFF);
+-	nfc_write(mtd, NFC_WRPROT, NFC_WPC_UNLOCK);
+-
+-	/*
+-	 * Setup NFC:
+-	 *	- Big Endian transfers,
+-	 *	- Interrupt after full page read/write.
+-	 */
+-	nfc_write(mtd, NFC_CONFIG1, NFC_BIG_ENDIAN | NFC_INT_MASK |
+-							NFC_FULL_PAGE_INT);
+-
+-	/* Set spare area size */
+-	nfc_write(mtd, NFC_SPAS, mtd->oobsize >> 1);
+-
+-	init_waitqueue_head(&prv->irq_waitq);
+-	retval = devm_request_irq(dev, prv->irq, &mpc5121_nfc_irq, 0, DRV_NAME,
+-									mtd);
+-	if (retval) {
+-		dev_err(dev, "Error requesting IRQ!\n");
+-		goto error;
+-	}
+-
+-	/* Detect NAND chips */
+-	retval = nand_scan(mtd, be32_to_cpup(chips_no));
+-	if (retval) {
+-		dev_err(dev, "NAND Flash not found !\n");
+-		goto error;
+-	}
+-
+-	/* Set erase block size */
+-	switch (mtd->erasesize / mtd->writesize) {
+-	case 32:
+-		nfc_set(mtd, NFC_CONFIG1, NFC_PPB_32);
+-		break;
+-
+-	case 64:
+-		nfc_set(mtd, NFC_CONFIG1, NFC_PPB_64);
+-		break;
+-
+-	case 128:
+-		nfc_set(mtd, NFC_CONFIG1, NFC_PPB_128);
+-		break;
+-
+-	case 256:
+-		nfc_set(mtd, NFC_CONFIG1, NFC_PPB_256);
+-		break;
+-
+-	default:
+-		dev_err(dev, "Unsupported NAND flash!\n");
+-		retval = -ENXIO;
+-		goto error;
+-	}
+-
+-	dev_set_drvdata(dev, mtd);
+-
+-	/* Register device in MTD */
+-	retval = mtd_device_register(mtd, NULL, 0);
+-	if (retval) {
+-		dev_err(dev, "Error adding MTD device!\n");
+-		goto error;
+-	}
+-
+-	return 0;
+-error:
+-	mpc5121_nfc_free(dev, mtd);
+-	return retval;
+-}
+-
+-static int mpc5121_nfc_remove(struct platform_device *op)
+-{
+-	struct device *dev = &op->dev;
+-	struct mtd_info *mtd = dev_get_drvdata(dev);
+-
+-	nand_release(mtd);
+-	mpc5121_nfc_free(dev, mtd);
+-
+-	return 0;
+-}
+-
+-static const struct of_device_id mpc5121_nfc_match[] = {
+-	{ .compatible = "fsl,mpc5121-nfc", },
+-	{},
+-};
+-MODULE_DEVICE_TABLE(of, mpc5121_nfc_match);
+-
+-static struct platform_driver mpc5121_nfc_driver = {
+-	.probe		= mpc5121_nfc_probe,
+-	.remove		= mpc5121_nfc_remove,
+-	.driver		= {
+-		.name = DRV_NAME,
+-		.of_match_table = mpc5121_nfc_match,
+-	},
+-};
+-
+-module_platform_driver(mpc5121_nfc_driver);
+-
+-MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+-MODULE_DESCRIPTION("MPC5121 NAND MTD driver");
+-MODULE_LICENSE("GPL");
+diff --git a/drivers/mtd/nand/mtk_ecc.c b/drivers/mtd/nand/mtk_ecc.c
+deleted file mode 100644
+index c51d214..0000000
+--- a/drivers/mtd/nand/mtk_ecc.c
++++ /dev/null
+@@ -1,544 +0,0 @@
+-/*
+- * MTK ECC controller driver.
+- * Copyright (C) 2016  MediaTek Inc.
+- * Authors:	Xiaolei Li		<xiaolei.li@mediatek.com>
+- *		Jorge Ramirez-Ortiz	<jorge.ramirez-ortiz@linaro.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.
+- *
+- * 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/platform_device.h>
+-#include <linux/dma-mapping.h>
+-#include <linux/interrupt.h>
+-#include <linux/clk.h>
+-#include <linux/module.h>
+-#include <linux/iopoll.h>
+-#include <linux/of.h>
+-#include <linux/of_platform.h>
+-#include <linux/mutex.h>
+-
+-#include "mtk_ecc.h"
+-
+-#define ECC_IDLE_MASK		BIT(0)
+-#define ECC_IRQ_EN		BIT(0)
+-#define ECC_PG_IRQ_SEL		BIT(1)
+-#define ECC_OP_ENABLE		(1)
+-#define ECC_OP_DISABLE		(0)
+-
+-#define ECC_ENCCON		(0x00)
+-#define ECC_ENCCNFG		(0x04)
+-#define		ECC_MODE_SHIFT		(5)
+-#define		ECC_MS_SHIFT		(16)
+-#define ECC_ENCDIADDR		(0x08)
+-#define ECC_ENCIDLE		(0x0C)
+-#define ECC_ENCIRQ_EN		(0x80)
+-#define ECC_ENCIRQ_STA		(0x84)
+-#define ECC_DECCON		(0x100)
+-#define ECC_DECCNFG		(0x104)
+-#define		DEC_EMPTY_EN		BIT(31)
+-#define		DEC_CNFG_CORRECT	(0x3 << 12)
+-#define ECC_DECIDLE		(0x10C)
+-#define ECC_DECENUM0		(0x114)
+-#define ECC_DECDONE		(0x124)
+-#define ECC_DECIRQ_EN		(0x200)
+-#define ECC_DECIRQ_STA		(0x204)
+-
+-#define ECC_TIMEOUT		(500000)
+-
+-#define ECC_IDLE_REG(op)	((op) == ECC_ENCODE ? ECC_ENCIDLE : ECC_DECIDLE)
+-#define ECC_CTL_REG(op)		((op) == ECC_ENCODE ? ECC_ENCCON : ECC_DECCON)
+-#define ECC_IRQ_REG(op)		((op) == ECC_ENCODE ? \
+-					ECC_ENCIRQ_EN : ECC_DECIRQ_EN)
+-
+-struct mtk_ecc_caps {
+-	u32 err_mask;
+-	const u8 *ecc_strength;
+-	u8 num_ecc_strength;
+-	u32 encode_parity_reg0;
+-	int pg_irq_sel;
+-};
+-
+-struct mtk_ecc {
+-	struct device *dev;
+-	const struct mtk_ecc_caps *caps;
+-	void __iomem *regs;
+-	struct clk *clk;
+-
+-	struct completion done;
+-	struct mutex lock;
+-	u32 sectors;
+-
+-	u8 *eccdata;
+-};
+-
+-/* ecc strength that each IP supports */
+-static const u8 ecc_strength_mt2701[] = {
+-	4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 28, 32, 36,
+-	40, 44, 48, 52, 56, 60
+-};
+-
+-static const u8 ecc_strength_mt2712[] = {
+-	4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 28, 32, 36,
+-	40, 44, 48, 52, 56, 60, 68, 72, 80
+-};
+-
+-static inline void mtk_ecc_wait_idle(struct mtk_ecc *ecc,
+-				     enum mtk_ecc_operation op)
+-{
+-	struct device *dev = ecc->dev;
+-	u32 val;
+-	int ret;
+-
+-	ret = readl_poll_timeout_atomic(ecc->regs + ECC_IDLE_REG(op), val,
+-					val & ECC_IDLE_MASK,
+-					10, ECC_TIMEOUT);
+-	if (ret)
+-		dev_warn(dev, "%s NOT idle\n",
+-			 op == ECC_ENCODE ? "encoder" : "decoder");
+-}
+-
+-static irqreturn_t mtk_ecc_irq(int irq, void *id)
+-{
+-	struct mtk_ecc *ecc = id;
+-	enum mtk_ecc_operation op;
+-	u32 dec, enc;
+-
+-	dec = readw(ecc->regs + ECC_DECIRQ_STA) & ECC_IRQ_EN;
+-	if (dec) {
+-		op = ECC_DECODE;
+-		dec = readw(ecc->regs + ECC_DECDONE);
+-		if (dec & ecc->sectors) {
+-			/*
+-			 * Clear decode IRQ status once again to ensure that
+-			 * there will be no extra IRQ.
+-			 */
+-			readw(ecc->regs + ECC_DECIRQ_STA);
+-			ecc->sectors = 0;
+-			complete(&ecc->done);
+-		} else {
+-			return IRQ_HANDLED;
+-		}
+-	} else {
+-		enc = readl(ecc->regs + ECC_ENCIRQ_STA) & ECC_IRQ_EN;
+-		if (enc) {
+-			op = ECC_ENCODE;
+-			complete(&ecc->done);
+-		} else {
+-			return IRQ_NONE;
+-		}
+-	}
+-
+-	return IRQ_HANDLED;
+-}
+-
+-static int mtk_ecc_config(struct mtk_ecc *ecc, struct mtk_ecc_config *config)
+-{
+-	u32 ecc_bit, dec_sz, enc_sz;
+-	u32 reg, i;
+-
+-	for (i = 0; i < ecc->caps->num_ecc_strength; i++) {
+-		if (ecc->caps->ecc_strength[i] == config->strength)
+-			break;
+-	}
+-
+-	if (i == ecc->caps->num_ecc_strength) {
+-		dev_err(ecc->dev, "invalid ecc strength %d\n",
+-			config->strength);
+-		return -EINVAL;
+-	}
+-
+-	ecc_bit = i;
+-
+-	if (config->op == ECC_ENCODE) {
+-		/* configure ECC encoder (in bits) */
+-		enc_sz = config->len << 3;
+-
+-		reg = ecc_bit | (config->mode << ECC_MODE_SHIFT);
+-		reg |= (enc_sz << ECC_MS_SHIFT);
+-		writel(reg, ecc->regs + ECC_ENCCNFG);
+-
+-		if (config->mode != ECC_NFI_MODE)
+-			writel(lower_32_bits(config->addr),
+-			       ecc->regs + ECC_ENCDIADDR);
+-
+-	} else {
+-		/* configure ECC decoder (in bits) */
+-		dec_sz = (config->len << 3) +
+-					config->strength * ECC_PARITY_BITS;
+-
+-		reg = ecc_bit | (config->mode << ECC_MODE_SHIFT);
+-		reg |= (dec_sz << ECC_MS_SHIFT) | DEC_CNFG_CORRECT;
+-		reg |= DEC_EMPTY_EN;
+-		writel(reg, ecc->regs + ECC_DECCNFG);
+-
+-		if (config->sectors)
+-			ecc->sectors = 1 << (config->sectors - 1);
+-	}
+-
+-	return 0;
+-}
+-
+-void mtk_ecc_get_stats(struct mtk_ecc *ecc, struct mtk_ecc_stats *stats,
+-		       int sectors)
+-{
+-	u32 offset, i, err;
+-	u32 bitflips = 0;
+-
+-	stats->corrected = 0;
+-	stats->failed = 0;
+-
+-	for (i = 0; i < sectors; i++) {
+-		offset = (i >> 2) << 2;
+-		err = readl(ecc->regs + ECC_DECENUM0 + offset);
+-		err = err >> ((i % 4) * 8);
+-		err &= ecc->caps->err_mask;
+-		if (err == ecc->caps->err_mask) {
+-			/* uncorrectable errors */
+-			stats->failed++;
+-			continue;
+-		}
+-
+-		stats->corrected += err;
+-		bitflips = max_t(u32, bitflips, err);
+-	}
+-
+-	stats->bitflips = bitflips;
+-}
+-EXPORT_SYMBOL(mtk_ecc_get_stats);
+-
+-void mtk_ecc_release(struct mtk_ecc *ecc)
+-{
+-	clk_disable_unprepare(ecc->clk);
+-	put_device(ecc->dev);
+-}
+-EXPORT_SYMBOL(mtk_ecc_release);
+-
+-static void mtk_ecc_hw_init(struct mtk_ecc *ecc)
+-{
+-	mtk_ecc_wait_idle(ecc, ECC_ENCODE);
+-	writew(ECC_OP_DISABLE, ecc->regs + ECC_ENCCON);
+-
+-	mtk_ecc_wait_idle(ecc, ECC_DECODE);
+-	writel(ECC_OP_DISABLE, ecc->regs + ECC_DECCON);
+-}
+-
+-static struct mtk_ecc *mtk_ecc_get(struct device_node *np)
+-{
+-	struct platform_device *pdev;
+-	struct mtk_ecc *ecc;
+-
+-	pdev = of_find_device_by_node(np);
+-	if (!pdev || !platform_get_drvdata(pdev))
+-		return ERR_PTR(-EPROBE_DEFER);
+-
+-	get_device(&pdev->dev);
+-	ecc = platform_get_drvdata(pdev);
+-	clk_prepare_enable(ecc->clk);
+-	mtk_ecc_hw_init(ecc);
+-
+-	return ecc;
+-}
+-
+-struct mtk_ecc *of_mtk_ecc_get(struct device_node *of_node)
+-{
+-	struct mtk_ecc *ecc = NULL;
+-	struct device_node *np;
+-
+-	np = of_parse_phandle(of_node, "ecc-engine", 0);
+-	if (np) {
+-		ecc = mtk_ecc_get(np);
+-		of_node_put(np);
+-	}
+-
+-	return ecc;
+-}
+-EXPORT_SYMBOL(of_mtk_ecc_get);
+-
+-int mtk_ecc_enable(struct mtk_ecc *ecc, struct mtk_ecc_config *config)
+-{
+-	enum mtk_ecc_operation op = config->op;
+-	u16 reg_val;
+-	int ret;
+-
+-	ret = mutex_lock_interruptible(&ecc->lock);
+-	if (ret) {
+-		dev_err(ecc->dev, "interrupted when attempting to lock\n");
+-		return ret;
+-	}
+-
+-	mtk_ecc_wait_idle(ecc, op);
+-
+-	ret = mtk_ecc_config(ecc, config);
+-	if (ret) {
+-		mutex_unlock(&ecc->lock);
+-		return ret;
+-	}
+-
+-	if (config->mode != ECC_NFI_MODE || op != ECC_ENCODE) {
+-		init_completion(&ecc->done);
+-		reg_val = ECC_IRQ_EN;
+-		/*
+-		 * For ECC_NFI_MODE, if ecc->caps->pg_irq_sel is 1, then it
+-		 * means this chip can only generate one ecc irq during page
+-		 * read / write. If is 0, generate one ecc irq each ecc step.
+-		 */
+-		if (ecc->caps->pg_irq_sel && config->mode == ECC_NFI_MODE)
+-			reg_val |= ECC_PG_IRQ_SEL;
+-		writew(reg_val, ecc->regs + ECC_IRQ_REG(op));
+-	}
+-
+-	writew(ECC_OP_ENABLE, ecc->regs + ECC_CTL_REG(op));
+-
+-	return 0;
+-}
+-EXPORT_SYMBOL(mtk_ecc_enable);
+-
+-void mtk_ecc_disable(struct mtk_ecc *ecc)
+-{
+-	enum mtk_ecc_operation op = ECC_ENCODE;
+-
+-	/* find out the running operation */
+-	if (readw(ecc->regs + ECC_CTL_REG(op)) != ECC_OP_ENABLE)
+-		op = ECC_DECODE;
+-
+-	/* disable it */
+-	mtk_ecc_wait_idle(ecc, op);
+-	if (op == ECC_DECODE)
+-		/*
+-		 * Clear decode IRQ status in case there is a timeout to wait
+-		 * decode IRQ.
+-		 */
+-		readw(ecc->regs + ECC_DECIRQ_STA);
+-	writew(0, ecc->regs + ECC_IRQ_REG(op));
+-	writew(ECC_OP_DISABLE, ecc->regs + ECC_CTL_REG(op));
+-
+-	mutex_unlock(&ecc->lock);
+-}
+-EXPORT_SYMBOL(mtk_ecc_disable);
+-
+-int mtk_ecc_wait_done(struct mtk_ecc *ecc, enum mtk_ecc_operation op)
+-{
+-	int ret;
+-
+-	ret = wait_for_completion_timeout(&ecc->done, msecs_to_jiffies(500));
+-	if (!ret) {
+-		dev_err(ecc->dev, "%s timeout - interrupt did not arrive)\n",
+-			(op == ECC_ENCODE) ? "encoder" : "decoder");
+-		return -ETIMEDOUT;
+-	}
+-
+-	return 0;
+-}
+-EXPORT_SYMBOL(mtk_ecc_wait_done);
+-
+-int mtk_ecc_encode(struct mtk_ecc *ecc, struct mtk_ecc_config *config,
+-		   u8 *data, u32 bytes)
+-{
+-	dma_addr_t addr;
+-	u32 len;
+-	int ret;
+-
+-	addr = dma_map_single(ecc->dev, data, bytes, DMA_TO_DEVICE);
+-	ret = dma_mapping_error(ecc->dev, addr);
+-	if (ret) {
+-		dev_err(ecc->dev, "dma mapping error\n");
+-		return -EINVAL;
+-	}
+-
+-	config->op = ECC_ENCODE;
+-	config->addr = addr;
+-	ret = mtk_ecc_enable(ecc, config);
+-	if (ret) {
+-		dma_unmap_single(ecc->dev, addr, bytes, DMA_TO_DEVICE);
+-		return ret;
+-	}
+-
+-	ret = mtk_ecc_wait_done(ecc, ECC_ENCODE);
+-	if (ret)
+-		goto timeout;
+-
+-	mtk_ecc_wait_idle(ecc, ECC_ENCODE);
+-
+-	/* Program ECC bytes to OOB: per sector oob = FDM + ECC + SPARE */
+-	len = (config->strength * ECC_PARITY_BITS + 7) >> 3;
+-
+-	/* write the parity bytes generated by the ECC back to temp buffer */
+-	__ioread32_copy(ecc->eccdata,
+-			ecc->regs + ecc->caps->encode_parity_reg0,
+-			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);
+-	mtk_ecc_disable(ecc);
+-
+-	return ret;
+-}
+-EXPORT_SYMBOL(mtk_ecc_encode);
+-
+-void mtk_ecc_adjust_strength(struct mtk_ecc *ecc, u32 *p)
+-{
+-	const u8 *ecc_strength = ecc->caps->ecc_strength;
+-	int i;
+-
+-	for (i = 0; i < ecc->caps->num_ecc_strength; i++) {
+-		if (*p <= ecc_strength[i]) {
+-			if (!i)
+-				*p = ecc_strength[i];
+-			else if (*p != ecc_strength[i])
+-				*p = ecc_strength[i - 1];
+-			return;
+-		}
+-	}
+-
+-	*p = ecc_strength[ecc->caps->num_ecc_strength - 1];
+-}
+-EXPORT_SYMBOL(mtk_ecc_adjust_strength);
+-
+-static const struct mtk_ecc_caps mtk_ecc_caps_mt2701 = {
+-	.err_mask = 0x3f,
+-	.ecc_strength = ecc_strength_mt2701,
+-	.num_ecc_strength = 20,
+-	.encode_parity_reg0 = 0x10,
+-	.pg_irq_sel = 0,
+-};
+-
+-static const struct mtk_ecc_caps mtk_ecc_caps_mt2712 = {
+-	.err_mask = 0x7f,
+-	.ecc_strength = ecc_strength_mt2712,
+-	.num_ecc_strength = 23,
+-	.encode_parity_reg0 = 0x300,
+-	.pg_irq_sel = 1,
+-};
+-
+-static const struct of_device_id mtk_ecc_dt_match[] = {
+-	{
+-		.compatible = "mediatek,mt2701-ecc",
+-		.data = &mtk_ecc_caps_mt2701,
+-	}, {
+-		.compatible = "mediatek,mt2712-ecc",
+-		.data = &mtk_ecc_caps_mt2712,
+-	},
+-	{},
+-};
+-
+-static int mtk_ecc_probe(struct platform_device *pdev)
+-{
+-	struct device *dev = &pdev->dev;
+-	struct mtk_ecc *ecc;
+-	struct resource *res;
+-	const struct of_device_id *of_ecc_id = NULL;
+-	u32 max_eccdata_size;
+-	int irq, ret;
+-
+-	ecc = devm_kzalloc(dev, sizeof(*ecc), GFP_KERNEL);
+-	if (!ecc)
+-		return -ENOMEM;
+-
+-	of_ecc_id = of_match_device(mtk_ecc_dt_match, &pdev->dev);
+-	if (!of_ecc_id)
+-		return -ENODEV;
+-
+-	ecc->caps = of_ecc_id->data;
+-
+-	max_eccdata_size = ecc->caps->num_ecc_strength - 1;
+-	max_eccdata_size = ecc->caps->ecc_strength[max_eccdata_size];
+-	max_eccdata_size = (max_eccdata_size * ECC_PARITY_BITS + 7) >> 3;
+-	max_eccdata_size = round_up(max_eccdata_size, 4);
+-	ecc->eccdata = devm_kzalloc(dev, max_eccdata_size, GFP_KERNEL);
+-	if (!ecc->eccdata)
+-		return -ENOMEM;
+-
+-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+-	ecc->regs = devm_ioremap_resource(dev, res);
+-	if (IS_ERR(ecc->regs)) {
+-		dev_err(dev, "failed to map regs: %ld\n", PTR_ERR(ecc->regs));
+-		return PTR_ERR(ecc->regs);
+-	}
+-
+-	ecc->clk = devm_clk_get(dev, NULL);
+-	if (IS_ERR(ecc->clk)) {
+-		dev_err(dev, "failed to get clock: %ld\n", PTR_ERR(ecc->clk));
+-		return PTR_ERR(ecc->clk);
+-	}
+-
+-	irq = platform_get_irq(pdev, 0);
+-	if (irq < 0) {
+-		dev_err(dev, "failed to get irq: %d\n", irq);
+-		return irq;
+-	}
+-
+-	ret = dma_set_mask(dev, DMA_BIT_MASK(32));
+-	if (ret) {
+-		dev_err(dev, "failed to set DMA mask\n");
+-		return ret;
+-	}
+-
+-	ret = devm_request_irq(dev, irq, mtk_ecc_irq, 0x0, "mtk-ecc", ecc);
+-	if (ret) {
+-		dev_err(dev, "failed to request irq\n");
+-		return -EINVAL;
+-	}
+-
+-	ecc->dev = dev;
+-	mutex_init(&ecc->lock);
+-	platform_set_drvdata(pdev, ecc);
+-	dev_info(dev, "probed\n");
+-
+-	return 0;
+-}
+-
+-#ifdef CONFIG_PM_SLEEP
+-static int mtk_ecc_suspend(struct device *dev)
+-{
+-	struct mtk_ecc *ecc = dev_get_drvdata(dev);
+-
+-	clk_disable_unprepare(ecc->clk);
+-
+-	return 0;
+-}
+-
+-static int mtk_ecc_resume(struct device *dev)
+-{
+-	struct mtk_ecc *ecc = dev_get_drvdata(dev);
+-	int ret;
+-
+-	ret = clk_prepare_enable(ecc->clk);
+-	if (ret) {
+-		dev_err(dev, "failed to enable clk\n");
+-		return ret;
+-	}
+-
+-	return 0;
+-}
+-
+-static SIMPLE_DEV_PM_OPS(mtk_ecc_pm_ops, mtk_ecc_suspend, mtk_ecc_resume);
+-#endif
+-
+-MODULE_DEVICE_TABLE(of, mtk_ecc_dt_match);
+-
+-static struct platform_driver mtk_ecc_driver = {
+-	.probe  = mtk_ecc_probe,
+-	.driver = {
+-		.name  = "mtk-ecc",
+-		.of_match_table = of_match_ptr(mtk_ecc_dt_match),
+-#ifdef CONFIG_PM_SLEEP
+-		.pm = &mtk_ecc_pm_ops,
+-#endif
+-	},
+-};
+-
+-module_platform_driver(mtk_ecc_driver);
+-
+-MODULE_AUTHOR("Xiaolei Li <xiaolei.li@mediatek.com>");
+-MODULE_DESCRIPTION("MTK Nand ECC Driver");
+-MODULE_LICENSE("GPL");
+diff --git a/drivers/mtd/nand/mtk_ecc.h b/drivers/mtd/nand/mtk_ecc.h
+deleted file mode 100644
+index d245c14..0000000
+--- a/drivers/mtd/nand/mtk_ecc.h
++++ /dev/null
+@@ -1,50 +0,0 @@
+-/*
+- * MTK SDG1 ECC controller
+- *
+- * Copyright (c) 2016 Mediatek
+- * Authors:	Xiaolei Li		<xiaolei.li@mediatek.com>
+- *		Jorge Ramirez-Ortiz	<jorge.ramirez-ortiz@linaro.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.
+- */
+-
+-#ifndef __DRIVERS_MTD_NAND_MTK_ECC_H__
+-#define __DRIVERS_MTD_NAND_MTK_ECC_H__
+-
+-#include <linux/types.h>
+-
+-#define ECC_PARITY_BITS		(14)
+-
+-enum mtk_ecc_mode {ECC_DMA_MODE = 0, ECC_NFI_MODE = 1};
+-enum mtk_ecc_operation {ECC_ENCODE, ECC_DECODE};
+-
+-struct device_node;
+-struct mtk_ecc;
+-
+-struct mtk_ecc_stats {
+-	u32 corrected;
+-	u32 bitflips;
+-	u32 failed;
+-};
+-
+-struct mtk_ecc_config {
+-	enum mtk_ecc_operation op;
+-	enum mtk_ecc_mode mode;
+-	dma_addr_t addr;
+-	u32 strength;
+-	u32 sectors;
+-	u32 len;
+-};
+-
+-int mtk_ecc_encode(struct mtk_ecc *, struct mtk_ecc_config *, u8 *, u32);
+-void mtk_ecc_get_stats(struct mtk_ecc *, struct mtk_ecc_stats *, int);
+-int mtk_ecc_wait_done(struct mtk_ecc *, enum mtk_ecc_operation);
+-int mtk_ecc_enable(struct mtk_ecc *, struct mtk_ecc_config *);
+-void mtk_ecc_disable(struct mtk_ecc *);
+-void mtk_ecc_adjust_strength(struct mtk_ecc *ecc, u32 *p);
+-
+-struct mtk_ecc *of_mtk_ecc_get(struct device_node *);
+-void mtk_ecc_release(struct mtk_ecc *);
+-
+-#endif
+diff --git a/drivers/mtd/nand/mtk_nand.c b/drivers/mtd/nand/mtk_nand.c
+deleted file mode 100644
+index d86a7d1..0000000
+--- a/drivers/mtd/nand/mtk_nand.c
++++ /dev/null
+@@ -1,1585 +0,0 @@
+-/*
+- * MTK NAND Flash controller driver.
+- * Copyright (C) 2016 MediaTek Inc.
+- * Authors:	Xiaolei Li		<xiaolei.li@mediatek.com>
+- *		Jorge Ramirez-Ortiz	<jorge.ramirez-ortiz@linaro.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.
+- *
+- * 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/platform_device.h>
+-#include <linux/dma-mapping.h>
+-#include <linux/interrupt.h>
+-#include <linux/delay.h>
+-#include <linux/clk.h>
+-#include <linux/mtd/rawnand.h>
+-#include <linux/mtd/mtd.h>
+-#include <linux/module.h>
+-#include <linux/iopoll.h>
+-#include <linux/of.h>
+-#include <linux/of_device.h>
+-#include "mtk_ecc.h"
+-
+-/* NAND controller register definition */
+-#define NFI_CNFG		(0x00)
+-#define		CNFG_AHB		BIT(0)
+-#define		CNFG_READ_EN		BIT(1)
+-#define		CNFG_DMA_BURST_EN	BIT(2)
+-#define		CNFG_BYTE_RW		BIT(6)
+-#define		CNFG_HW_ECC_EN		BIT(8)
+-#define		CNFG_AUTO_FMT_EN	BIT(9)
+-#define		CNFG_OP_CUST		(6 << 12)
+-#define NFI_PAGEFMT		(0x04)
+-#define		PAGEFMT_FDM_ECC_SHIFT	(12)
+-#define		PAGEFMT_FDM_SHIFT	(8)
+-#define		PAGEFMT_SEC_SEL_512	BIT(2)
+-#define		PAGEFMT_512_2K		(0)
+-#define		PAGEFMT_2K_4K		(1)
+-#define		PAGEFMT_4K_8K		(2)
+-#define		PAGEFMT_8K_16K		(3)
+-/* NFI control */
+-#define NFI_CON			(0x08)
+-#define		CON_FIFO_FLUSH		BIT(0)
+-#define		CON_NFI_RST		BIT(1)
+-#define		CON_BRD			BIT(8)  /* burst  read */
+-#define		CON_BWR			BIT(9)	/* burst  write */
+-#define		CON_SEC_SHIFT		(12)
+-/* Timming control register */
+-#define NFI_ACCCON		(0x0C)
+-#define NFI_INTR_EN		(0x10)
+-#define		INTR_AHB_DONE_EN	BIT(6)
+-#define NFI_INTR_STA		(0x14)
+-#define NFI_CMD			(0x20)
+-#define NFI_ADDRNOB		(0x30)
+-#define NFI_COLADDR		(0x34)
+-#define NFI_ROWADDR		(0x38)
+-#define NFI_STRDATA		(0x40)
+-#define		STAR_EN			(1)
+-#define		STAR_DE			(0)
+-#define NFI_CNRNB		(0x44)
+-#define NFI_DATAW		(0x50)
+-#define NFI_DATAR		(0x54)
+-#define NFI_PIO_DIRDY		(0x58)
+-#define		PIO_DI_RDY		(0x01)
+-#define NFI_STA			(0x60)
+-#define		STA_CMD			BIT(0)
+-#define		STA_ADDR		BIT(1)
+-#define		STA_BUSY		BIT(8)
+-#define		STA_EMP_PAGE		BIT(12)
+-#define		NFI_FSM_CUSTDATA	(0xe << 16)
+-#define		NFI_FSM_MASK		(0xf << 16)
+-#define NFI_ADDRCNTR		(0x70)
+-#define		CNTR_MASK		GENMASK(16, 12)
+-#define		ADDRCNTR_SEC_SHIFT	(12)
+-#define		ADDRCNTR_SEC(val) \
+-		(((val) & CNTR_MASK) >> ADDRCNTR_SEC_SHIFT)
+-#define NFI_STRADDR		(0x80)
+-#define NFI_BYTELEN		(0x84)
+-#define NFI_CSEL		(0x90)
+-#define NFI_FDML(x)		(0xA0 + (x) * sizeof(u32) * 2)
+-#define NFI_FDMM(x)		(0xA4 + (x) * sizeof(u32) * 2)
+-#define NFI_FDM_MAX_SIZE	(8)
+-#define NFI_FDM_MIN_SIZE	(1)
+-#define NFI_MASTER_STA		(0x224)
+-#define		MASTER_STA_MASK		(0x0FFF)
+-#define NFI_EMPTY_THRESH	(0x23C)
+-
+-#define MTK_NAME		"mtk-nand"
+-#define KB(x)			((x) * 1024UL)
+-#define MB(x)			(KB(x) * 1024UL)
+-
+-#define MTK_TIMEOUT		(500000)
+-#define MTK_RESET_TIMEOUT	(1000000)
+-#define MTK_MAX_SECTOR		(16)
+-#define MTK_NAND_MAX_NSELS	(2)
+-#define MTK_NFC_MIN_SPARE	(16)
+-#define ACCTIMING(tpoecs, tprecs, tc2r, tw2r, twh, twst, trlt) \
+-	((tpoecs) << 28 | (tprecs) << 22 | (tc2r) << 16 | \
+-	(tw2r) << 12 | (twh) << 8 | (twst) << 4 | (trlt))
+-
+-struct mtk_nfc_caps {
+-	const u8 *spare_size;
+-	u8 num_spare_size;
+-	u8 pageformat_spare_shift;
+-	u8 nfi_clk_div;
+-};
+-
+-struct mtk_nfc_bad_mark_ctl {
+-	void (*bm_swap)(struct mtd_info *, u8 *buf, int raw);
+-	u32 sec;
+-	u32 pos;
+-};
+-
+-/*
+- * FDM: region used to store free OOB data
+- */
+-struct mtk_nfc_fdm {
+-	u32 reg_size;
+-	u32 ecc_size;
+-};
+-
+-struct mtk_nfc_nand_chip {
+-	struct list_head node;
+-	struct nand_chip nand;
+-
+-	struct mtk_nfc_bad_mark_ctl bad_mark;
+-	struct mtk_nfc_fdm fdm;
+-	u32 spare_per_sector;
+-
+-	int nsels;
+-	u8 sels[0];
+-	/* nothing after this field */
+-};
+-
+-struct mtk_nfc_clk {
+-	struct clk *nfi_clk;
+-	struct clk *pad_clk;
+-};
+-
+-struct mtk_nfc {
+-	struct nand_hw_control controller;
+-	struct mtk_ecc_config ecc_cfg;
+-	struct mtk_nfc_clk clk;
+-	struct mtk_ecc *ecc;
+-
+-	struct device *dev;
+-	const struct mtk_nfc_caps *caps;
+-	void __iomem *regs;
+-
+-	struct completion done;
+-	struct list_head chips;
+-
+-	u8 *buffer;
+-};
+-
+-/*
+- * supported spare size of each IP.
+- * order should be the same with the spare size bitfiled defination of
+- * register NFI_PAGEFMT.
+- */
+-static const u8 spare_size_mt2701[] = {
+-	16, 26, 27, 28, 32, 36, 40, 44,	48, 49, 50, 51, 52, 62, 63, 64
+-};
+-
+-static const u8 spare_size_mt2712[] = {
+-	16, 26, 27, 28, 32, 36, 40, 44, 48, 49, 50, 51, 52, 62, 61, 63, 64, 67,
+-	74
+-};
+-
+-static inline struct mtk_nfc_nand_chip *to_mtk_nand(struct nand_chip *nand)
+-{
+-	return container_of(nand, struct mtk_nfc_nand_chip, nand);
+-}
+-
+-static inline u8 *data_ptr(struct nand_chip *chip, const u8 *p, int i)
+-{
+-	return (u8 *)p + i * chip->ecc.size;
+-}
+-
+-static inline u8 *oob_ptr(struct nand_chip *chip, int i)
+-{
+-	struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+-	u8 *poi;
+-
+-	/* map the sector's FDM data to free oob:
+-	 * the beginning of the oob area stores the FDM data of bad mark sectors
+-	 */
+-
+-	if (i < mtk_nand->bad_mark.sec)
+-		poi = chip->oob_poi + (i + 1) * mtk_nand->fdm.reg_size;
+-	else if (i == mtk_nand->bad_mark.sec)
+-		poi = chip->oob_poi;
+-	else
+-		poi = chip->oob_poi + i * mtk_nand->fdm.reg_size;
+-
+-	return poi;
+-}
+-
+-static inline int mtk_data_len(struct nand_chip *chip)
+-{
+-	struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+-
+-	return chip->ecc.size + mtk_nand->spare_per_sector;
+-}
+-
+-static inline u8 *mtk_data_ptr(struct nand_chip *chip,  int i)
+-{
+-	struct mtk_nfc *nfc = nand_get_controller_data(chip);
+-
+-	return nfc->buffer + i * mtk_data_len(chip);
+-}
+-
+-static inline u8 *mtk_oob_ptr(struct nand_chip *chip, int i)
+-{
+-	struct mtk_nfc *nfc = nand_get_controller_data(chip);
+-
+-	return nfc->buffer + i * mtk_data_len(chip) + chip->ecc.size;
+-}
+-
+-static inline void nfi_writel(struct mtk_nfc *nfc, u32 val, u32 reg)
+-{
+-	writel(val, nfc->regs + reg);
+-}
+-
+-static inline void nfi_writew(struct mtk_nfc *nfc, u16 val, u32 reg)
+-{
+-	writew(val, nfc->regs + reg);
+-}
+-
+-static inline void nfi_writeb(struct mtk_nfc *nfc, u8 val, u32 reg)
+-{
+-	writeb(val, nfc->regs + reg);
+-}
+-
+-static inline u32 nfi_readl(struct mtk_nfc *nfc, u32 reg)
+-{
+-	return readl_relaxed(nfc->regs + reg);
+-}
+-
+-static inline u16 nfi_readw(struct mtk_nfc *nfc, u32 reg)
+-{
+-	return readw_relaxed(nfc->regs + reg);
+-}
+-
+-static inline u8 nfi_readb(struct mtk_nfc *nfc, u32 reg)
+-{
+-	return readb_relaxed(nfc->regs + reg);
+-}
+-
+-static void mtk_nfc_hw_reset(struct mtk_nfc *nfc)
+-{
+-	struct device *dev = nfc->dev;
+-	u32 val;
+-	int ret;
+-
+-	/* reset all registers and force the NFI master to terminate */
+-	nfi_writel(nfc, CON_FIFO_FLUSH | CON_NFI_RST, NFI_CON);
+-
+-	/* wait for the master to finish the last transaction */
+-	ret = readl_poll_timeout(nfc->regs + NFI_MASTER_STA, val,
+-				 !(val & MASTER_STA_MASK), 50,
+-				 MTK_RESET_TIMEOUT);
+-	if (ret)
+-		dev_warn(dev, "master active in reset [0x%x] = 0x%x\n",
+-			 NFI_MASTER_STA, val);
+-
+-	/* ensure any status register affected by the NFI master is reset */
+-	nfi_writel(nfc, CON_FIFO_FLUSH | CON_NFI_RST, NFI_CON);
+-	nfi_writew(nfc, STAR_DE, NFI_STRDATA);
+-}
+-
+-static int mtk_nfc_send_command(struct mtk_nfc *nfc, u8 command)
+-{
+-	struct device *dev = nfc->dev;
+-	u32 val;
+-	int ret;
+-
+-	nfi_writel(nfc, command, NFI_CMD);
+-
+-	ret = readl_poll_timeout_atomic(nfc->regs + NFI_STA, val,
+-					!(val & STA_CMD), 10,  MTK_TIMEOUT);
+-	if (ret) {
+-		dev_warn(dev, "nfi core timed out entering command mode\n");
+-		return -EIO;
+-	}
+-
+-	return 0;
+-}
+-
+-static int mtk_nfc_send_address(struct mtk_nfc *nfc, int addr)
+-{
+-	struct device *dev = nfc->dev;
+-	u32 val;
+-	int ret;
+-
+-	nfi_writel(nfc, addr, NFI_COLADDR);
+-	nfi_writel(nfc, 0, NFI_ROWADDR);
+-	nfi_writew(nfc, 1, NFI_ADDRNOB);
+-
+-	ret = readl_poll_timeout_atomic(nfc->regs + NFI_STA, val,
+-					!(val & STA_ADDR), 10, MTK_TIMEOUT);
+-	if (ret) {
+-		dev_warn(dev, "nfi core timed out entering address mode\n");
+-		return -EIO;
+-	}
+-
+-	return 0;
+-}
+-
+-static int mtk_nfc_hw_runtime_config(struct mtd_info *mtd)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+-	struct mtk_nfc *nfc = nand_get_controller_data(chip);
+-	u32 fmt, spare, i;
+-
+-	if (!mtd->writesize)
+-		return 0;
+-
+-	spare = mtk_nand->spare_per_sector;
+-
+-	switch (mtd->writesize) {
+-	case 512:
+-		fmt = PAGEFMT_512_2K | PAGEFMT_SEC_SEL_512;
+-		break;
+-	case KB(2):
+-		if (chip->ecc.size == 512)
+-			fmt = PAGEFMT_2K_4K | PAGEFMT_SEC_SEL_512;
+-		else
+-			fmt = PAGEFMT_512_2K;
+-		break;
+-	case KB(4):
+-		if (chip->ecc.size == 512)
+-			fmt = PAGEFMT_4K_8K | PAGEFMT_SEC_SEL_512;
+-		else
+-			fmt = PAGEFMT_2K_4K;
+-		break;
+-	case KB(8):
+-		if (chip->ecc.size == 512)
+-			fmt = PAGEFMT_8K_16K | PAGEFMT_SEC_SEL_512;
+-		else
+-			fmt = PAGEFMT_4K_8K;
+-		break;
+-	case KB(16):
+-		fmt = PAGEFMT_8K_16K;
+-		break;
+-	default:
+-		dev_err(nfc->dev, "invalid page len: %d\n", mtd->writesize);
+-		return -EINVAL;
+-	}
+-
+-	/*
+-	 * the hardware will double the value for this eccsize, so we need to
+-	 * halve it
+-	 */
+-	if (chip->ecc.size == 1024)
+-		spare >>= 1;
+-
+-	for (i = 0; i < nfc->caps->num_spare_size; i++) {
+-		if (nfc->caps->spare_size[i] == spare)
+-			break;
+-	}
+-
+-	if (i == nfc->caps->num_spare_size) {
+-		dev_err(nfc->dev, "invalid spare size %d\n", spare);
+-		return -EINVAL;
+-	}
+-
+-	fmt |= i << nfc->caps->pageformat_spare_shift;
+-
+-	fmt |= mtk_nand->fdm.reg_size << PAGEFMT_FDM_SHIFT;
+-	fmt |= mtk_nand->fdm.ecc_size << PAGEFMT_FDM_ECC_SHIFT;
+-	nfi_writel(nfc, fmt, NFI_PAGEFMT);
+-
+-	nfc->ecc_cfg.strength = chip->ecc.strength;
+-	nfc->ecc_cfg.len = chip->ecc.size + mtk_nand->fdm.ecc_size;
+-
+-	return 0;
+-}
+-
+-static void mtk_nfc_select_chip(struct mtd_info *mtd, int chip)
+-{
+-	struct nand_chip *nand = mtd_to_nand(mtd);
+-	struct mtk_nfc *nfc = nand_get_controller_data(nand);
+-	struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(nand);
+-
+-	if (chip < 0)
+-		return;
+-
+-	mtk_nfc_hw_runtime_config(mtd);
+-
+-	nfi_writel(nfc, mtk_nand->sels[chip], NFI_CSEL);
+-}
+-
+-static int mtk_nfc_dev_ready(struct mtd_info *mtd)
+-{
+-	struct mtk_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd));
+-
+-	if (nfi_readl(nfc, NFI_STA) & STA_BUSY)
+-		return 0;
+-
+-	return 1;
+-}
+-
+-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));
+-
+-	if (ctrl & NAND_ALE) {
+-		mtk_nfc_send_address(nfc, dat);
+-	} else if (ctrl & NAND_CLE) {
+-		mtk_nfc_hw_reset(nfc);
+-
+-		nfi_writew(nfc, CNFG_OP_CUST, NFI_CNFG);
+-		mtk_nfc_send_command(nfc, dat);
+-	}
+-}
+-
+-static inline void mtk_nfc_wait_ioready(struct mtk_nfc *nfc)
+-{
+-	int rc;
+-	u8 val;
+-
+-	rc = readb_poll_timeout_atomic(nfc->regs + NFI_PIO_DIRDY, val,
+-				       val & PIO_DI_RDY, 10, MTK_TIMEOUT);
+-	if (rc < 0)
+-		dev_err(nfc->dev, "data not ready\n");
+-}
+-
+-static inline u8 mtk_nfc_read_byte(struct mtd_info *mtd)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct mtk_nfc *nfc = nand_get_controller_data(chip);
+-	u32 reg;
+-
+-	/* after each byte read, the NFI_STA reg is reset by the hardware */
+-	reg = nfi_readl(nfc, NFI_STA) & NFI_FSM_MASK;
+-	if (reg != NFI_FSM_CUSTDATA) {
+-		reg = nfi_readw(nfc, NFI_CNFG);
+-		reg |= CNFG_BYTE_RW | CNFG_READ_EN;
+-		nfi_writew(nfc, reg, NFI_CNFG);
+-
+-		/*
+-		 * set to max sector to allow the HW to continue reading over
+-		 * unaligned accesses
+-		 */
+-		reg = (MTK_MAX_SECTOR << CON_SEC_SHIFT) | CON_BRD;
+-		nfi_writel(nfc, reg, NFI_CON);
+-
+-		/* trigger to fetch data */
+-		nfi_writew(nfc, STAR_EN, NFI_STRDATA);
+-	}
+-
+-	mtk_nfc_wait_ioready(nfc);
+-
+-	return nfi_readb(nfc, NFI_DATAR);
+-}
+-
+-static void mtk_nfc_read_buf(struct mtd_info *mtd, u8 *buf, int len)
+-{
+-	int i;
+-
+-	for (i = 0; i < len; i++)
+-		buf[i] = mtk_nfc_read_byte(mtd);
+-}
+-
+-static void mtk_nfc_write_byte(struct mtd_info *mtd, u8 byte)
+-{
+-	struct mtk_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd));
+-	u32 reg;
+-
+-	reg = nfi_readl(nfc, NFI_STA) & NFI_FSM_MASK;
+-
+-	if (reg != NFI_FSM_CUSTDATA) {
+-		reg = nfi_readw(nfc, NFI_CNFG) | CNFG_BYTE_RW;
+-		nfi_writew(nfc, reg, NFI_CNFG);
+-
+-		reg = MTK_MAX_SECTOR << CON_SEC_SHIFT | CON_BWR;
+-		nfi_writel(nfc, reg, NFI_CON);
+-
+-		nfi_writew(nfc, STAR_EN, NFI_STRDATA);
+-	}
+-
+-	mtk_nfc_wait_ioready(nfc);
+-	nfi_writeb(nfc, byte, NFI_DATAW);
+-}
+-
+-static void mtk_nfc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
+-{
+-	int i;
+-
+-	for (i = 0; i < len; i++)
+-		mtk_nfc_write_byte(mtd, buf[i]);
+-}
+-
+-static int mtk_nfc_setup_data_interface(struct mtd_info *mtd, int csline,
+-					const struct nand_data_interface *conf)
+-{
+-	struct mtk_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd));
+-	const struct nand_sdr_timings *timings;
+-	u32 rate, tpoecs, tprecs, tc2r, tw2r, twh, twst, trlt;
+-
+-	timings = nand_get_sdr_timings(conf);
+-	if (IS_ERR(timings))
+-		return -ENOTSUPP;
+-
+-	if (csline == NAND_DATA_IFACE_CHECK_ONLY)
+-		return 0;
+-
+-	rate = clk_get_rate(nfc->clk.nfi_clk);
+-	/* There is a frequency divider in some IPs */
+-	rate /= nfc->caps->nfi_clk_div;
+-
+-	/* turn clock rate into KHZ */
+-	rate /= 1000;
+-
+-	tpoecs = max(timings->tALH_min, timings->tCLH_min) / 1000;
+-	tpoecs = DIV_ROUND_UP(tpoecs * rate, 1000000);
+-	tpoecs &= 0xf;
+-
+-	tprecs = max(timings->tCLS_min, timings->tALS_min) / 1000;
+-	tprecs = DIV_ROUND_UP(tprecs * rate, 1000000);
+-	tprecs &= 0x3f;
+-
+-	/* sdr interface has no tCR which means CE# low to RE# low */
+-	tc2r = 0;
+-
+-	tw2r = timings->tWHR_min / 1000;
+-	tw2r = DIV_ROUND_UP(tw2r * rate, 1000000);
+-	tw2r = DIV_ROUND_UP(tw2r - 1, 2);
+-	tw2r &= 0xf;
+-
+-	twh = max(timings->tREH_min, timings->tWH_min) / 1000;
+-	twh = DIV_ROUND_UP(twh * rate, 1000000) - 1;
+-	twh &= 0xf;
+-
+-	twst = timings->tWP_min / 1000;
+-	twst = DIV_ROUND_UP(twst * rate, 1000000) - 1;
+-	twst &= 0xf;
+-
+-	trlt = max(timings->tREA_max, timings->tRP_min) / 1000;
+-	trlt = DIV_ROUND_UP(trlt * rate, 1000000) - 1;
+-	trlt &= 0xf;
+-
+-	/*
+-	 * ACCON: access timing control register
+-	 * -------------------------------------
+-	 * 31:28: tpoecs, minimum required time for CS post pulling down after
+-	 *        accessing the device
+-	 * 27:22: tprecs, minimum required time for CS pre pulling down before
+-	 *        accessing the device
+-	 * 21:16: tc2r, minimum required time from NCEB low to NREB low
+-	 * 15:12: tw2r, minimum required time from NWEB high to NREB low.
+-	 * 11:08: twh, write enable hold time
+-	 * 07:04: twst, write wait states
+-	 * 03:00: trlt, read wait states
+-	 */
+-	trlt = ACCTIMING(tpoecs, tprecs, tc2r, tw2r, twh, twst, trlt);
+-	nfi_writel(nfc, trlt, NFI_ACCCON);
+-
+-	return 0;
+-}
+-
+-static int mtk_nfc_sector_encode(struct nand_chip *chip, u8 *data)
+-{
+-	struct mtk_nfc *nfc = nand_get_controller_data(chip);
+-	struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+-	int size = chip->ecc.size + mtk_nand->fdm.reg_size;
+-
+-	nfc->ecc_cfg.mode = ECC_DMA_MODE;
+-	nfc->ecc_cfg.op = ECC_ENCODE;
+-
+-	return mtk_ecc_encode(nfc->ecc, &nfc->ecc_cfg, data, size);
+-}
+-
+-static void mtk_nfc_no_bad_mark_swap(struct mtd_info *a, u8 *b, int c)
+-{
+-	/* nop */
+-}
+-
+-static void mtk_nfc_bad_mark_swap(struct mtd_info *mtd, u8 *buf, int raw)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct mtk_nfc_nand_chip *nand = to_mtk_nand(chip);
+-	u32 bad_pos = nand->bad_mark.pos;
+-
+-	if (raw)
+-		bad_pos += nand->bad_mark.sec * mtk_data_len(chip);
+-	else
+-		bad_pos += nand->bad_mark.sec * chip->ecc.size;
+-
+-	swap(chip->oob_poi[0], buf[bad_pos]);
+-}
+-
+-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 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;
+-	u32 start, end;
+-	int i, ret;
+-
+-	start = offset / chip->ecc.size;
+-	end = DIV_ROUND_UP(offset + len, chip->ecc.size);
+-
+-	memset(nfc->buffer, 0xff, mtd->writesize + mtd->oobsize);
+-	for (i = 0; i < chip->ecc.steps; i++) {
+-		memcpy(mtk_data_ptr(chip, i), data_ptr(chip, buf, i),
+-		       chip->ecc.size);
+-
+-		if (start > i || i >= end)
+-			continue;
+-
+-		if (i == mtk_nand->bad_mark.sec)
+-			mtk_nand->bad_mark.bm_swap(mtd, nfc->buffer, 1);
+-
+-		memcpy(mtk_oob_ptr(chip, i), oob_ptr(chip, i), fdm->reg_size);
+-
+-		/* program the CRC back to the OOB */
+-		ret = mtk_nfc_sector_encode(chip, mtk_data_ptr(chip, i));
+-		if (ret < 0)
+-			return ret;
+-	}
+-
+-	return 0;
+-}
+-
+-static void mtk_nfc_format_page(struct mtd_info *mtd, const u8 *buf)
+-{
+-	struct nand_chip *chip = mtd_to_nand(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;
+-	u32 i;
+-
+-	memset(nfc->buffer, 0xff, mtd->writesize + mtd->oobsize);
+-	for (i = 0; i < chip->ecc.steps; i++) {
+-		if (buf)
+-			memcpy(mtk_data_ptr(chip, i), data_ptr(chip, buf, i),
+-			       chip->ecc.size);
+-
+-		if (i == mtk_nand->bad_mark.sec)
+-			mtk_nand->bad_mark.bm_swap(mtd, nfc->buffer, 1);
+-
+-		memcpy(mtk_oob_ptr(chip, i), oob_ptr(chip, i), fdm->reg_size);
+-	}
+-}
+-
+-static inline void mtk_nfc_read_fdm(struct nand_chip *chip, u32 start,
+-				    u32 sectors)
+-{
+-	struct mtk_nfc *nfc = nand_get_controller_data(chip);
+-	struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+-	struct mtk_nfc_fdm *fdm = &mtk_nand->fdm;
+-	u32 vall, valm;
+-	u8 *oobptr;
+-	int i, j;
+-
+-	for (i = 0; i < sectors; i++) {
+-		oobptr = oob_ptr(chip, start + i);
+-		vall = nfi_readl(nfc, NFI_FDML(i));
+-		valm = nfi_readl(nfc, NFI_FDMM(i));
+-
+-		for (j = 0; j < fdm->reg_size; j++)
+-			oobptr[j] = (j >= 4 ? valm : vall) >> ((j % 4) * 8);
+-	}
+-}
+-
+-static inline void mtk_nfc_write_fdm(struct nand_chip *chip)
+-{
+-	struct mtk_nfc *nfc = nand_get_controller_data(chip);
+-	struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+-	struct mtk_nfc_fdm *fdm = &mtk_nand->fdm;
+-	u32 vall, valm;
+-	u8 *oobptr;
+-	int i, j;
+-
+-	for (i = 0; i < chip->ecc.steps; i++) {
+-		oobptr = oob_ptr(chip, i);
+-		vall = 0;
+-		valm = 0;
+-		for (j = 0; j < 8; j++) {
+-			if (j < 4)
+-				vall |= (j < fdm->reg_size ? oobptr[j] : 0xff)
+-						<< (j * 8);
+-			else
+-				valm |= (j < fdm->reg_size ? oobptr[j] : 0xff)
+-						<< ((j - 4) * 8);
+-		}
+-		nfi_writel(nfc, vall, NFI_FDML(i));
+-		nfi_writel(nfc, valm, NFI_FDMM(i));
+-	}
+-}
+-
+-static int mtk_nfc_do_write_page(struct mtd_info *mtd, struct nand_chip *chip,
+-				 const u8 *buf, int page, int len)
+-{
+-	struct mtk_nfc *nfc = nand_get_controller_data(chip);
+-	struct device *dev = nfc->dev;
+-	dma_addr_t addr;
+-	u32 reg;
+-	int ret;
+-
+-	addr = dma_map_single(dev, (void *)buf, len, DMA_TO_DEVICE);
+-	ret = dma_mapping_error(nfc->dev, addr);
+-	if (ret) {
+-		dev_err(nfc->dev, "dma mapping error\n");
+-		return -EINVAL;
+-	}
+-
+-	reg = nfi_readw(nfc, NFI_CNFG) | CNFG_AHB | CNFG_DMA_BURST_EN;
+-	nfi_writew(nfc, reg, NFI_CNFG);
+-
+-	nfi_writel(nfc, chip->ecc.steps << CON_SEC_SHIFT, NFI_CON);
+-	nfi_writel(nfc, lower_32_bits(addr), NFI_STRADDR);
+-	nfi_writew(nfc, INTR_AHB_DONE_EN, NFI_INTR_EN);
+-
+-	init_completion(&nfc->done);
+-
+-	reg = nfi_readl(nfc, NFI_CON) | CON_BWR;
+-	nfi_writel(nfc, reg, NFI_CON);
+-	nfi_writew(nfc, STAR_EN, NFI_STRDATA);
+-
+-	ret = wait_for_completion_timeout(&nfc->done, msecs_to_jiffies(500));
+-	if (!ret) {
+-		dev_err(dev, "program ahb done timeout\n");
+-		nfi_writew(nfc, 0, NFI_INTR_EN);
+-		ret = -ETIMEDOUT;
+-		goto timeout;
+-	}
+-
+-	ret = readl_poll_timeout_atomic(nfc->regs + NFI_ADDRCNTR, reg,
+-					ADDRCNTR_SEC(reg) >= chip->ecc.steps,
+-					10, MTK_TIMEOUT);
+-	if (ret)
+-		dev_err(dev, "hwecc write timeout\n");
+-
+-timeout:
+-
+-	dma_unmap_single(nfc->dev, addr, len, DMA_TO_DEVICE);
+-	nfi_writel(nfc, 0, NFI_CON);
+-
+-	return ret;
+-}
+-
+-static int mtk_nfc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
+-			      const u8 *buf, int page, int raw)
+-{
+-	struct mtk_nfc *nfc = nand_get_controller_data(chip);
+-	struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+-	size_t len;
+-	const u8 *bufpoi;
+-	u32 reg;
+-	int ret;
+-
+-	if (!raw) {
+-		/* OOB => FDM: from register,  ECC: from HW */
+-		reg = nfi_readw(nfc, NFI_CNFG) | CNFG_AUTO_FMT_EN;
+-		nfi_writew(nfc, reg | CNFG_HW_ECC_EN, NFI_CNFG);
+-
+-		nfc->ecc_cfg.op = ECC_ENCODE;
+-		nfc->ecc_cfg.mode = ECC_NFI_MODE;
+-		ret = mtk_ecc_enable(nfc->ecc, &nfc->ecc_cfg);
+-		if (ret) {
+-			/* clear NFI config */
+-			reg = nfi_readw(nfc, NFI_CNFG);
+-			reg &= ~(CNFG_AUTO_FMT_EN | CNFG_HW_ECC_EN);
+-			nfi_writew(nfc, reg, NFI_CNFG);
+-
+-			return ret;
+-		}
+-
+-		memcpy(nfc->buffer, buf, mtd->writesize);
+-		mtk_nand->bad_mark.bm_swap(mtd, nfc->buffer, raw);
+-		bufpoi = nfc->buffer;
+-
+-		/* write OOB into the FDM registers (OOB area in MTK NAND) */
+-		mtk_nfc_write_fdm(chip);
+-	} else {
+-		bufpoi = buf;
+-	}
+-
+-	len = mtd->writesize + (raw ? mtd->oobsize : 0);
+-	ret = mtk_nfc_do_write_page(mtd, chip, bufpoi, page, len);
+-
+-	if (!raw)
+-		mtk_ecc_disable(nfc->ecc);
+-
+-	return ret;
+-}
+-
+-static int mtk_nfc_write_page_hwecc(struct mtd_info *mtd,
+-				    struct nand_chip *chip, const u8 *buf,
+-				    int oob_on, int page)
+-{
+-	return mtk_nfc_write_page(mtd, chip, buf, page, 0);
+-}
+-
+-static int mtk_nfc_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+-				  const u8 *buf, int oob_on, int pg)
+-{
+-	struct mtk_nfc *nfc = nand_get_controller_data(chip);
+-
+-	mtk_nfc_format_page(mtd, buf);
+-	return mtk_nfc_write_page(mtd, chip, nfc->buffer, pg, 1);
+-}
+-
+-static int mtk_nfc_write_subpage_hwecc(struct mtd_info *mtd,
+-				       struct nand_chip *chip, u32 offset,
+-				       u32 data_len, const u8 *buf,
+-				       int oob_on, int page)
+-{
+-	struct mtk_nfc *nfc = nand_get_controller_data(chip);
+-	int ret;
+-
+-	ret = mtk_nfc_format_subpage(mtd, offset, data_len, buf);
+-	if (ret < 0)
+-		return ret;
+-
+-	/* use the data in the private buffer (now with FDM and CRC) */
+-	return mtk_nfc_write_page(mtd, chip, nfc->buffer, page, 1);
+-}
+-
+-static int mtk_nfc_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
+-				 int page)
+-{
+-	int ret;
+-
+-	chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
+-
+-	ret = mtk_nfc_write_page_raw(mtd, chip, NULL, 1, page);
+-	if (ret < 0)
+-		return -EIO;
+-
+-	chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+-	ret = chip->waitfunc(mtd, chip);
+-
+-	return ret & NAND_STATUS_FAIL ? -EIO : 0;
+-}
+-
+-static int mtk_nfc_update_ecc_stats(struct mtd_info *mtd, u8 *buf, u32 sectors)
+-{
+-	struct nand_chip *chip = mtd_to_nand(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;
+-	int rc, i;
+-
+-	rc = nfi_readl(nfc, NFI_STA) & STA_EMP_PAGE;
+-	if (rc) {
+-		memset(buf, 0xff, sectors * chip->ecc.size);
+-		for (i = 0; i < sectors; i++)
+-			memset(oob_ptr(chip, i), 0xff, mtk_nand->fdm.reg_size);
+-		return 0;
+-	}
+-
+-	mtk_ecc_get_stats(nfc->ecc, &stats, sectors);
+-	mtd->ecc_stats.corrected += stats.corrected;
+-	mtd->ecc_stats.failed += stats.failed;
+-
+-	return stats.bitflips;
+-}
+-
+-static int mtk_nfc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
+-				u32 data_offs, u32 readlen,
+-				u8 *bufpoi, int page, int raw)
+-{
+-	struct mtk_nfc *nfc = nand_get_controller_data(chip);
+-	struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+-	u32 spare = mtk_nand->spare_per_sector;
+-	u32 column, sectors, start, end, reg;
+-	dma_addr_t addr;
+-	int bitflips;
+-	size_t len;
+-	u8 *buf;
+-	int rc;
+-
+-	start = data_offs / chip->ecc.size;
+-	end = DIV_ROUND_UP(data_offs + readlen, chip->ecc.size);
+-
+-	sectors = end - start;
+-	column = start * (chip->ecc.size + spare);
+-
+-	len = sectors * chip->ecc.size + (raw ? sectors * spare : 0);
+-	buf = bufpoi + start * chip->ecc.size;
+-
+-	if (column != 0)
+-		chip->cmdfunc(mtd, NAND_CMD_RNDOUT, column, -1);
+-
+-	addr = dma_map_single(nfc->dev, buf, len, DMA_FROM_DEVICE);
+-	rc = dma_mapping_error(nfc->dev, addr);
+-	if (rc) {
+-		dev_err(nfc->dev, "dma mapping error\n");
+-
+-		return -EINVAL;
+-	}
+-
+-	reg = nfi_readw(nfc, NFI_CNFG);
+-	reg |= CNFG_READ_EN | CNFG_DMA_BURST_EN | CNFG_AHB;
+-	if (!raw) {
+-		reg |= CNFG_AUTO_FMT_EN | CNFG_HW_ECC_EN;
+-		nfi_writew(nfc, reg, NFI_CNFG);
+-
+-		nfc->ecc_cfg.mode = ECC_NFI_MODE;
+-		nfc->ecc_cfg.sectors = sectors;
+-		nfc->ecc_cfg.op = ECC_DECODE;
+-		rc = mtk_ecc_enable(nfc->ecc, &nfc->ecc_cfg);
+-		if (rc) {
+-			dev_err(nfc->dev, "ecc enable\n");
+-			/* clear NFI_CNFG */
+-			reg &= ~(CNFG_DMA_BURST_EN | CNFG_AHB | CNFG_READ_EN |
+-				CNFG_AUTO_FMT_EN | CNFG_HW_ECC_EN);
+-			nfi_writew(nfc, reg, NFI_CNFG);
+-			dma_unmap_single(nfc->dev, addr, len, DMA_FROM_DEVICE);
+-
+-			return rc;
+-		}
+-	} else {
+-		nfi_writew(nfc, reg, NFI_CNFG);
+-	}
+-
+-	nfi_writel(nfc, sectors << CON_SEC_SHIFT, NFI_CON);
+-	nfi_writew(nfc, INTR_AHB_DONE_EN, NFI_INTR_EN);
+-	nfi_writel(nfc, lower_32_bits(addr), NFI_STRADDR);
+-
+-	init_completion(&nfc->done);
+-	reg = nfi_readl(nfc, NFI_CON) | CON_BRD;
+-	nfi_writel(nfc, reg, NFI_CON);
+-	nfi_writew(nfc, STAR_EN, NFI_STRDATA);
+-
+-	rc = wait_for_completion_timeout(&nfc->done, msecs_to_jiffies(500));
+-	if (!rc)
+-		dev_warn(nfc->dev, "read ahb/dma done timeout\n");
+-
+-	rc = readl_poll_timeout_atomic(nfc->regs + NFI_BYTELEN, reg,
+-				       ADDRCNTR_SEC(reg) >= sectors, 10,
+-				       MTK_TIMEOUT);
+-	if (rc < 0) {
+-		dev_err(nfc->dev, "subpage done timeout\n");
+-		bitflips = -EIO;
+-	} else {
+-		bitflips = 0;
+-		if (!raw) {
+-			rc = mtk_ecc_wait_done(nfc->ecc, ECC_DECODE);
+-			bitflips = rc < 0 ? -ETIMEDOUT :
+-				mtk_nfc_update_ecc_stats(mtd, buf, sectors);
+-			mtk_nfc_read_fdm(chip, start, sectors);
+-		}
+-	}
+-
+-	dma_unmap_single(nfc->dev, addr, len, DMA_FROM_DEVICE);
+-
+-	if (raw)
+-		goto done;
+-
+-	mtk_ecc_disable(nfc->ecc);
+-
+-	if (clamp(mtk_nand->bad_mark.sec, start, end) == mtk_nand->bad_mark.sec)
+-		mtk_nand->bad_mark.bm_swap(mtd, bufpoi, raw);
+-done:
+-	nfi_writel(nfc, 0, NFI_CON);
+-
+-	return bitflips;
+-}
+-
+-static int mtk_nfc_read_subpage_hwecc(struct mtd_info *mtd,
+-				      struct nand_chip *chip, u32 off,
+-				      u32 len, u8 *p, int pg)
+-{
+-	return mtk_nfc_read_subpage(mtd, chip, off, len, p, pg, 0);
+-}
+-
+-static int mtk_nfc_read_page_hwecc(struct mtd_info *mtd,
+-				   struct nand_chip *chip, u8 *p,
+-				   int oob_on, int pg)
+-{
+-	return mtk_nfc_read_subpage(mtd, chip, 0, mtd->writesize, p, pg, 0);
+-}
+-
+-static int mtk_nfc_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+-				 u8 *buf, int oob_on, int page)
+-{
+-	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;
+-	int i, ret;
+-
+-	memset(nfc->buffer, 0xff, mtd->writesize + mtd->oobsize);
+-	ret = mtk_nfc_read_subpage(mtd, chip, 0, mtd->writesize, nfc->buffer,
+-				   page, 1);
+-	if (ret < 0)
+-		return ret;
+-
+-	for (i = 0; i < chip->ecc.steps; i++) {
+-		memcpy(oob_ptr(chip, i), mtk_oob_ptr(chip, i), fdm->reg_size);
+-
+-		if (i == mtk_nand->bad_mark.sec)
+-			mtk_nand->bad_mark.bm_swap(mtd, nfc->buffer, 1);
+-
+-		if (buf)
+-			memcpy(data_ptr(chip, buf, i), mtk_data_ptr(chip, i),
+-			       chip->ecc.size);
+-	}
+-
+-	return ret;
+-}
+-
+-static int mtk_nfc_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
+-				int page)
+-{
+-	chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
+-
+-	return mtk_nfc_read_page_raw(mtd, chip, NULL, 1, page);
+-}
+-
+-static inline void mtk_nfc_hw_init(struct mtk_nfc *nfc)
+-{
+-	/*
+-	 * CNRNB: nand ready/busy register
+-	 * -------------------------------
+-	 * 7:4: timeout register for polling the NAND busy/ready signal
+-	 * 0  : poll the status of the busy/ready signal after [7:4]*16 cycles.
+-	 */
+-	nfi_writew(nfc, 0xf1, NFI_CNRNB);
+-	nfi_writel(nfc, PAGEFMT_8K_16K, NFI_PAGEFMT);
+-
+-	mtk_nfc_hw_reset(nfc);
+-
+-	nfi_readl(nfc, NFI_INTR_STA);
+-	nfi_writel(nfc, 0, NFI_INTR_EN);
+-}
+-
+-static irqreturn_t mtk_nfc_irq(int irq, void *id)
+-{
+-	struct mtk_nfc *nfc = id;
+-	u16 sta, ien;
+-
+-	sta = nfi_readw(nfc, NFI_INTR_STA);
+-	ien = nfi_readw(nfc, NFI_INTR_EN);
+-
+-	if (!(sta & ien))
+-		return IRQ_NONE;
+-
+-	nfi_writew(nfc, ~sta & ien, NFI_INTR_EN);
+-	complete(&nfc->done);
+-
+-	return IRQ_HANDLED;
+-}
+-
+-static int mtk_nfc_enable_clk(struct device *dev, struct mtk_nfc_clk *clk)
+-{
+-	int ret;
+-
+-	ret = clk_prepare_enable(clk->nfi_clk);
+-	if (ret) {
+-		dev_err(dev, "failed to enable nfi clk\n");
+-		return ret;
+-	}
+-
+-	ret = clk_prepare_enable(clk->pad_clk);
+-	if (ret) {
+-		dev_err(dev, "failed to enable pad clk\n");
+-		clk_disable_unprepare(clk->nfi_clk);
+-		return ret;
+-	}
+-
+-	return 0;
+-}
+-
+-static void mtk_nfc_disable_clk(struct mtk_nfc_clk *clk)
+-{
+-	clk_disable_unprepare(clk->nfi_clk);
+-	clk_disable_unprepare(clk->pad_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 mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+-	struct mtk_nfc_fdm *fdm = &mtk_nand->fdm;
+-	u32 eccsteps;
+-
+-	eccsteps = mtd->writesize / chip->ecc.size;
+-
+-	if (section >= eccsteps)
+-		return -ERANGE;
+-
+-	oob_region->length = fdm->reg_size - fdm->ecc_size;
+-	oob_region->offset = section * fdm->reg_size + fdm->ecc_size;
+-
+-	return 0;
+-}
+-
+-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 mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+-	u32 eccsteps;
+-
+-	if (section)
+-		return -ERANGE;
+-
+-	eccsteps = mtd->writesize / chip->ecc.size;
+-	oob_region->offset = mtk_nand->fdm.reg_size * eccsteps;
+-	oob_region->length = mtd->oobsize - oob_region->offset;
+-
+-	return 0;
+-}
+-
+-static const struct mtd_ooblayout_ops mtk_nfc_ooblayout_ops = {
+-	.free = mtk_nfc_ooblayout_free,
+-	.ecc = mtk_nfc_ooblayout_ecc,
+-};
+-
+-static void mtk_nfc_set_fdm(struct mtk_nfc_fdm *fdm, struct mtd_info *mtd)
+-{
+-	struct nand_chip *nand = mtd_to_nand(mtd);
+-	struct mtk_nfc_nand_chip *chip = to_mtk_nand(nand);
+-	u32 ecc_bytes;
+-
+-	ecc_bytes = DIV_ROUND_UP(nand->ecc.strength * ECC_PARITY_BITS, 8);
+-
+-	fdm->reg_size = chip->spare_per_sector - ecc_bytes;
+-	if (fdm->reg_size > NFI_FDM_MAX_SIZE)
+-		fdm->reg_size = NFI_FDM_MAX_SIZE;
+-
+-	/* bad block mark storage */
+-	fdm->ecc_size = 1;
+-}
+-
+-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);
+-
+-	if (mtd->writesize == 512) {
+-		bm_ctl->bm_swap = mtk_nfc_no_bad_mark_swap;
+-	} else {
+-		bm_ctl->bm_swap = mtk_nfc_bad_mark_swap;
+-		bm_ctl->sec = mtd->writesize / mtk_data_len(nand);
+-		bm_ctl->pos = mtd->writesize % mtk_data_len(nand);
+-	}
+-}
+-
+-static int mtk_nfc_set_spare_per_sector(u32 *sps, struct mtd_info *mtd)
+-{
+-	struct nand_chip *nand = mtd_to_nand(mtd);
+-	struct mtk_nfc *nfc = nand_get_controller_data(nand);
+-	const u8 *spare = nfc->caps->spare_size;
+-	u32 eccsteps, i, closest_spare = 0;
+-
+-	eccsteps = mtd->writesize / nand->ecc.size;
+-	*sps = mtd->oobsize / eccsteps;
+-
+-	if (nand->ecc.size == 1024)
+-		*sps >>= 1;
+-
+-	if (*sps < MTK_NFC_MIN_SPARE)
+-		return -EINVAL;
+-
+-	for (i = 0; i < nfc->caps->num_spare_size; i++) {
+-		if (*sps >= spare[i] && spare[i] >= spare[closest_spare]) {
+-			closest_spare = i;
+-			if (*sps == spare[i])
+-				break;
+-		}
+-	}
+-
+-	*sps = spare[closest_spare];
+-
+-	if (nand->ecc.size == 1024)
+-		*sps <<= 1;
+-
+-	return 0;
+-}
+-
+-static int mtk_nfc_ecc_init(struct device *dev, struct mtd_info *mtd)
+-{
+-	struct nand_chip *nand = mtd_to_nand(mtd);
+-	struct mtk_nfc *nfc = nand_get_controller_data(nand);
+-	u32 spare;
+-	int free, ret;
+-
+-	/* support only ecc hw mode */
+-	if (nand->ecc.mode != NAND_ECC_HW) {
+-		dev_err(dev, "ecc.mode not supported\n");
+-		return -EINVAL;
+-	}
+-
+-	/* if optional dt settings not present */
+-	if (!nand->ecc.size || !nand->ecc.strength) {
+-		/* use datasheet requirements */
+-		nand->ecc.strength = nand->ecc_strength_ds;
+-		nand->ecc.size = nand->ecc_step_ds;
+-
+-		/*
+-		 * align eccstrength and eccsize
+-		 * this controller only supports 512 and 1024 sizes
+-		 */
+-		if (nand->ecc.size < 1024) {
+-			if (mtd->writesize > 512) {
+-				nand->ecc.size = 1024;
+-				nand->ecc.strength <<= 1;
+-			} else {
+-				nand->ecc.size = 512;
+-			}
+-		} else {
+-			nand->ecc.size = 1024;
+-		}
+-
+-		ret = mtk_nfc_set_spare_per_sector(&spare, mtd);
+-		if (ret)
+-			return ret;
+-
+-		/* calculate oob bytes except ecc parity data */
+-		free = ((nand->ecc.strength * ECC_PARITY_BITS) + 7) >> 3;
+-		free = spare - free;
+-
+-		/*
+-		 * enhance ecc strength if oob left is bigger than max FDM size
+-		 * or reduce ecc strength if oob size is not enough for ecc
+-		 * parity data.
+-		 */
+-		if (free > NFI_FDM_MAX_SIZE) {
+-			spare -= NFI_FDM_MAX_SIZE;
+-			nand->ecc.strength = (spare << 3) / ECC_PARITY_BITS;
+-		} else if (free < 0) {
+-			spare -= NFI_FDM_MIN_SIZE;
+-			nand->ecc.strength = (spare << 3) / ECC_PARITY_BITS;
+-		}
+-	}
+-
+-	mtk_ecc_adjust_strength(nfc->ecc, &nand->ecc.strength);
+-
+-	dev_info(dev, "eccsize %d eccstrength %d\n",
+-		 nand->ecc.size, nand->ecc.strength);
+-
+-	return 0;
+-}
+-
+-static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc,
+-				  struct device_node *np)
+-{
+-	struct mtk_nfc_nand_chip *chip;
+-	struct nand_chip *nand;
+-	struct mtd_info *mtd;
+-	int nsels, len;
+-	u32 tmp;
+-	int ret;
+-	int i;
+-
+-	if (!of_get_property(np, "reg", &nsels))
+-		return -ENODEV;
+-
+-	nsels /= sizeof(u32);
+-	if (!nsels || nsels > MTK_NAND_MAX_NSELS) {
+-		dev_err(dev, "invalid reg property size %d\n", nsels);
+-		return -EINVAL;
+-	}
+-
+-	chip = devm_kzalloc(dev, sizeof(*chip) + nsels * sizeof(u8),
+-			    GFP_KERNEL);
+-	if (!chip)
+-		return -ENOMEM;
+-
+-	chip->nsels = nsels;
+-	for (i = 0; i < nsels; i++) {
+-		ret = of_property_read_u32_index(np, "reg", i, &tmp);
+-		if (ret) {
+-			dev_err(dev, "reg property failure : %d\n", ret);
+-			return ret;
+-		}
+-		chip->sels[i] = tmp;
+-	}
+-
+-	nand = &chip->nand;
+-	nand->controller = &nfc->controller;
+-
+-	nand_set_flash_node(nand, np);
+-	nand_set_controller_data(nand, nfc);
+-
+-	nand->options |= NAND_USE_BOUNCE_BUFFER | NAND_SUBPAGE_READ;
+-	nand->dev_ready = mtk_nfc_dev_ready;
+-	nand->select_chip = mtk_nfc_select_chip;
+-	nand->write_byte = mtk_nfc_write_byte;
+-	nand->write_buf = mtk_nfc_write_buf;
+-	nand->read_byte = mtk_nfc_read_byte;
+-	nand->read_buf = mtk_nfc_read_buf;
+-	nand->cmd_ctrl = mtk_nfc_cmd_ctrl;
+-	nand->setup_data_interface = mtk_nfc_setup_data_interface;
+-
+-	/* set default mode in case dt entry is missing */
+-	nand->ecc.mode = NAND_ECC_HW;
+-
+-	nand->ecc.write_subpage = mtk_nfc_write_subpage_hwecc;
+-	nand->ecc.write_page_raw = mtk_nfc_write_page_raw;
+-	nand->ecc.write_page = mtk_nfc_write_page_hwecc;
+-	nand->ecc.write_oob_raw = mtk_nfc_write_oob_std;
+-	nand->ecc.write_oob = mtk_nfc_write_oob_std;
+-
+-	nand->ecc.read_subpage = mtk_nfc_read_subpage_hwecc;
+-	nand->ecc.read_page_raw = mtk_nfc_read_page_raw;
+-	nand->ecc.read_page = mtk_nfc_read_page_hwecc;
+-	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->owner = THIS_MODULE;
+-	mtd->dev.parent = dev;
+-	mtd->name = MTK_NAME;
+-	mtd_set_ooblayout(mtd, &mtk_nfc_ooblayout_ops);
+-
+-	mtk_nfc_hw_init(nfc);
+-
+-	ret = nand_scan_ident(mtd, nsels, NULL);
+-	if (ret)
+-		return ret;
+-
+-	/* store bbt magic in page, cause OOB is not protected */
+-	if (nand->bbt_options & NAND_BBT_USE_FLASH)
+-		nand->bbt_options |= NAND_BBT_NO_OOB;
+-
+-	ret = mtk_nfc_ecc_init(dev, mtd);
+-	if (ret)
+-		return -EINVAL;
+-
+-	if (nand->options & NAND_BUSWIDTH_16) {
+-		dev_err(dev, "16bits buswidth not supported");
+-		return -EINVAL;
+-	}
+-
+-	ret = mtk_nfc_set_spare_per_sector(&chip->spare_per_sector, mtd);
+-	if (ret)
+-		return ret;
+-
+-	mtk_nfc_set_fdm(&chip->fdm, mtd);
+-	mtk_nfc_set_bad_mark_ctl(&chip->bad_mark, mtd);
+-
+-	len = mtd->writesize + mtd->oobsize;
+-	nfc->buffer = devm_kzalloc(dev, len, GFP_KERNEL);
+-	if (!nfc->buffer)
+-		return  -ENOMEM;
+-
+-	ret = nand_scan_tail(mtd);
+-	if (ret)
+-		return ret;
+-
+-	ret = mtd_device_parse_register(mtd, NULL, NULL, NULL, 0);
+-	if (ret) {
+-		dev_err(dev, "mtd parse partition error\n");
+-		nand_release(mtd);
+-		return ret;
+-	}
+-
+-	list_add_tail(&chip->node, &nfc->chips);
+-
+-	return 0;
+-}
+-
+-static int mtk_nfc_nand_chips_init(struct device *dev, struct mtk_nfc *nfc)
+-{
+-	struct device_node *np = dev->of_node;
+-	struct device_node *nand_np;
+-	int ret;
+-
+-	for_each_child_of_node(np, nand_np) {
+-		ret = mtk_nfc_nand_chip_init(dev, nfc, nand_np);
+-		if (ret) {
+-			of_node_put(nand_np);
+-			return ret;
+-		}
+-	}
+-
+-	return 0;
+-}
+-
+-static const struct mtk_nfc_caps mtk_nfc_caps_mt2701 = {
+-	.spare_size = spare_size_mt2701,
+-	.num_spare_size = 16,
+-	.pageformat_spare_shift = 4,
+-	.nfi_clk_div = 1,
+-};
+-
+-static const struct mtk_nfc_caps mtk_nfc_caps_mt2712 = {
+-	.spare_size = spare_size_mt2712,
+-	.num_spare_size = 19,
+-	.pageformat_spare_shift = 16,
+-	.nfi_clk_div = 2,
+-};
+-
+-static const struct of_device_id mtk_nfc_id_table[] = {
+-	{
+-		.compatible = "mediatek,mt2701-nfc",
+-		.data = &mtk_nfc_caps_mt2701,
+-	}, {
+-		.compatible = "mediatek,mt2712-nfc",
+-		.data = &mtk_nfc_caps_mt2712,
+-	},
+-	{}
+-};
+-MODULE_DEVICE_TABLE(of, mtk_nfc_id_table);
+-
+-static int mtk_nfc_probe(struct platform_device *pdev)
+-{
+-	struct device *dev = &pdev->dev;
+-	struct device_node *np = dev->of_node;
+-	struct mtk_nfc *nfc;
+-	struct resource *res;
+-	const struct of_device_id *of_nfc_id = NULL;
+-	int ret, irq;
+-
+-	nfc = devm_kzalloc(dev, sizeof(*nfc), GFP_KERNEL);
+-	if (!nfc)
+-		return -ENOMEM;
+-
+-	spin_lock_init(&nfc->controller.lock);
+-	init_waitqueue_head(&nfc->controller.wq);
+-	INIT_LIST_HEAD(&nfc->chips);
+-
+-	/* probe defer if not ready */
+-	nfc->ecc = of_mtk_ecc_get(np);
+-	if (IS_ERR(nfc->ecc))
+-		return PTR_ERR(nfc->ecc);
+-	else if (!nfc->ecc)
+-		return -ENODEV;
+-
+-	nfc->dev = dev;
+-
+-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+-	nfc->regs = devm_ioremap_resource(dev, res);
+-	if (IS_ERR(nfc->regs)) {
+-		ret = PTR_ERR(nfc->regs);
+-		goto release_ecc;
+-	}
+-
+-	nfc->clk.nfi_clk = devm_clk_get(dev, "nfi_clk");
+-	if (IS_ERR(nfc->clk.nfi_clk)) {
+-		dev_err(dev, "no clk\n");
+-		ret = PTR_ERR(nfc->clk.nfi_clk);
+-		goto release_ecc;
+-	}
+-
+-	nfc->clk.pad_clk = devm_clk_get(dev, "pad_clk");
+-	if (IS_ERR(nfc->clk.pad_clk)) {
+-		dev_err(dev, "no pad clk\n");
+-		ret = PTR_ERR(nfc->clk.pad_clk);
+-		goto release_ecc;
+-	}
+-
+-	ret = mtk_nfc_enable_clk(dev, &nfc->clk);
+-	if (ret)
+-		goto release_ecc;
+-
+-	irq = platform_get_irq(pdev, 0);
+-	if (irq < 0) {
+-		dev_err(dev, "no nfi irq resource\n");
+-		ret = -EINVAL;
+-		goto clk_disable;
+-	}
+-
+-	ret = devm_request_irq(dev, irq, mtk_nfc_irq, 0x0, "mtk-nand", nfc);
+-	if (ret) {
+-		dev_err(dev, "failed to request nfi irq\n");
+-		goto clk_disable;
+-	}
+-
+-	ret = dma_set_mask(dev, DMA_BIT_MASK(32));
+-	if (ret) {
+-		dev_err(dev, "failed to set dma mask\n");
+-		goto clk_disable;
+-	}
+-
+-	of_nfc_id = of_match_device(mtk_nfc_id_table, &pdev->dev);
+-	if (!of_nfc_id) {
+-		ret = -ENODEV;
+-		goto clk_disable;
+-	}
+-
+-	nfc->caps = of_nfc_id->data;
+-
+-	platform_set_drvdata(pdev, nfc);
+-
+-	ret = mtk_nfc_nand_chips_init(dev, nfc);
+-	if (ret) {
+-		dev_err(dev, "failed to init nand chips\n");
+-		goto clk_disable;
+-	}
+-
+-	return 0;
+-
+-clk_disable:
+-	mtk_nfc_disable_clk(&nfc->clk);
+-
+-release_ecc:
+-	mtk_ecc_release(nfc->ecc);
+-
+-	return ret;
+-}
+-
+-static int mtk_nfc_remove(struct platform_device *pdev)
+-{
+-	struct mtk_nfc *nfc = platform_get_drvdata(pdev);
+-	struct mtk_nfc_nand_chip *chip;
+-
+-	while (!list_empty(&nfc->chips)) {
+-		chip = list_first_entry(&nfc->chips, struct mtk_nfc_nand_chip,
+-					node);
+-		nand_release(nand_to_mtd(&chip->nand));
+-		list_del(&chip->node);
+-	}
+-
+-	mtk_ecc_release(nfc->ecc);
+-	mtk_nfc_disable_clk(&nfc->clk);
+-
+-	return 0;
+-}
+-
+-#ifdef CONFIG_PM_SLEEP
+-static int mtk_nfc_suspend(struct device *dev)
+-{
+-	struct mtk_nfc *nfc = dev_get_drvdata(dev);
+-
+-	mtk_nfc_disable_clk(&nfc->clk);
+-
+-	return 0;
+-}
+-
+-static int mtk_nfc_resume(struct device *dev)
+-{
+-	struct mtk_nfc *nfc = dev_get_drvdata(dev);
+-	struct mtk_nfc_nand_chip *chip;
+-	struct nand_chip *nand;
+-	struct mtd_info *mtd;
+-	int ret;
+-	u32 i;
+-
+-	udelay(200);
+-
+-	ret = mtk_nfc_enable_clk(dev, &nfc->clk);
+-	if (ret)
+-		return ret;
+-
+-	/* reset NAND chip if VCC was powered off */
+-	list_for_each_entry(chip, &nfc->chips, node) {
+-		nand = &chip->nand;
+-		mtd = nand_to_mtd(nand);
+-		for (i = 0; i < chip->nsels; i++) {
+-			nand->select_chip(mtd, i);
+-			nand->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
+-		}
+-	}
+-
+-	return 0;
+-}
+-
+-static SIMPLE_DEV_PM_OPS(mtk_nfc_pm_ops, mtk_nfc_suspend, mtk_nfc_resume);
+-#endif
+-
+-static struct platform_driver mtk_nfc_driver = {
+-	.probe  = mtk_nfc_probe,
+-	.remove = mtk_nfc_remove,
+-	.driver = {
+-		.name  = MTK_NAME,
+-		.of_match_table = mtk_nfc_id_table,
+-#ifdef CONFIG_PM_SLEEP
+-		.pm = &mtk_nfc_pm_ops,
+-#endif
+-	},
+-};
+-
+-module_platform_driver(mtk_nfc_driver);
+-
+-MODULE_LICENSE("GPL");
+-MODULE_AUTHOR("Xiaolei Li <xiaolei.li@mediatek.com>");
+-MODULE_DESCRIPTION("MTK Nand Flash Controller Driver");
+diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c
+deleted file mode 100644
+index 53e5e03..0000000
+--- a/drivers/mtd/nand/mxc_nand.c
++++ /dev/null
+@@ -1,1854 +0,0 @@
+-/*
+- * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
+- * Copyright 2008 Sascha Hauer, kernel@pengutronix.de
+- *
+- * 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.
+- *
+- * You should have received a copy of the GNU General Public License
+- * along with this program; if not, write to the Free Software
+- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+- * MA 02110-1301, USA.
+- */
+-
+-#include <linux/delay.h>
+-#include <linux/slab.h>
+-#include <linux/init.h>
+-#include <linux/module.h>
+-#include <linux/mtd/mtd.h>
+-#include <linux/mtd/rawnand.h>
+-#include <linux/mtd/partitions.h>
+-#include <linux/interrupt.h>
+-#include <linux/device.h>
+-#include <linux/platform_device.h>
+-#include <linux/clk.h>
+-#include <linux/err.h>
+-#include <linux/io.h>
+-#include <linux/irq.h>
+-#include <linux/completion.h>
+-#include <linux/of.h>
+-#include <linux/of_device.h>
+-
+-#include <asm/mach/flash.h>
+-#include <linux/platform_data/mtd-mxc_nand.h>
+-
+-#define DRIVER_NAME "mxc_nand"
+-
+-/* Addresses for NFC registers */
+-#define NFC_V1_V2_BUF_SIZE		(host->regs + 0x00)
+-#define NFC_V1_V2_BUF_ADDR		(host->regs + 0x04)
+-#define NFC_V1_V2_FLASH_ADDR		(host->regs + 0x06)
+-#define NFC_V1_V2_FLASH_CMD		(host->regs + 0x08)
+-#define NFC_V1_V2_CONFIG		(host->regs + 0x0a)
+-#define NFC_V1_V2_ECC_STATUS_RESULT	(host->regs + 0x0c)
+-#define NFC_V1_V2_RSLTMAIN_AREA		(host->regs + 0x0e)
+-#define NFC_V1_V2_RSLTSPARE_AREA	(host->regs + 0x10)
+-#define NFC_V1_V2_WRPROT		(host->regs + 0x12)
+-#define NFC_V1_UNLOCKSTART_BLKADDR	(host->regs + 0x14)
+-#define NFC_V1_UNLOCKEND_BLKADDR	(host->regs + 0x16)
+-#define NFC_V21_UNLOCKSTART_BLKADDR0	(host->regs + 0x20)
+-#define NFC_V21_UNLOCKSTART_BLKADDR1	(host->regs + 0x24)
+-#define NFC_V21_UNLOCKSTART_BLKADDR2	(host->regs + 0x28)
+-#define NFC_V21_UNLOCKSTART_BLKADDR3	(host->regs + 0x2c)
+-#define NFC_V21_UNLOCKEND_BLKADDR0	(host->regs + 0x22)
+-#define NFC_V21_UNLOCKEND_BLKADDR1	(host->regs + 0x26)
+-#define NFC_V21_UNLOCKEND_BLKADDR2	(host->regs + 0x2a)
+-#define NFC_V21_UNLOCKEND_BLKADDR3	(host->regs + 0x2e)
+-#define NFC_V1_V2_NF_WRPRST		(host->regs + 0x18)
+-#define NFC_V1_V2_CONFIG1		(host->regs + 0x1a)
+-#define NFC_V1_V2_CONFIG2		(host->regs + 0x1c)
+-
+-#define NFC_V2_CONFIG1_ECC_MODE_4	(1 << 0)
+-#define NFC_V1_V2_CONFIG1_SP_EN		(1 << 2)
+-#define NFC_V1_V2_CONFIG1_ECC_EN	(1 << 3)
+-#define NFC_V1_V2_CONFIG1_INT_MSK	(1 << 4)
+-#define NFC_V1_V2_CONFIG1_BIG		(1 << 5)
+-#define NFC_V1_V2_CONFIG1_RST		(1 << 6)
+-#define NFC_V1_V2_CONFIG1_CE		(1 << 7)
+-#define NFC_V2_CONFIG1_ONE_CYCLE	(1 << 8)
+-#define NFC_V2_CONFIG1_PPB(x)		(((x) & 0x3) << 9)
+-#define NFC_V2_CONFIG1_FP_INT		(1 << 11)
+-
+-#define NFC_V1_V2_CONFIG2_INT		(1 << 15)
+-
+-/*
+- * Operation modes for the NFC. Valid for v1, v2 and v3
+- * type controllers.
+- */
+-#define NFC_CMD				(1 << 0)
+-#define NFC_ADDR			(1 << 1)
+-#define NFC_INPUT			(1 << 2)
+-#define NFC_OUTPUT			(1 << 3)
+-#define NFC_ID				(1 << 4)
+-#define NFC_STATUS			(1 << 5)
+-
+-#define NFC_V3_FLASH_CMD		(host->regs_axi + 0x00)
+-#define NFC_V3_FLASH_ADDR0		(host->regs_axi + 0x04)
+-
+-#define NFC_V3_CONFIG1			(host->regs_axi + 0x34)
+-#define NFC_V3_CONFIG1_SP_EN		(1 << 0)
+-#define NFC_V3_CONFIG1_RBA(x)		(((x) & 0x7 ) << 4)
+-
+-#define NFC_V3_ECC_STATUS_RESULT	(host->regs_axi + 0x38)
+-
+-#define NFC_V3_LAUNCH			(host->regs_axi + 0x40)
+-
+-#define NFC_V3_WRPROT			(host->regs_ip + 0x0)
+-#define NFC_V3_WRPROT_LOCK_TIGHT	(1 << 0)
+-#define NFC_V3_WRPROT_LOCK		(1 << 1)
+-#define NFC_V3_WRPROT_UNLOCK		(1 << 2)
+-#define NFC_V3_WRPROT_BLS_UNLOCK	(2 << 6)
+-
+-#define NFC_V3_WRPROT_UNLOCK_BLK_ADD0   (host->regs_ip + 0x04)
+-
+-#define NFC_V3_CONFIG2			(host->regs_ip + 0x24)
+-#define NFC_V3_CONFIG2_PS_512			(0 << 0)
+-#define NFC_V3_CONFIG2_PS_2048			(1 << 0)
+-#define NFC_V3_CONFIG2_PS_4096			(2 << 0)
+-#define NFC_V3_CONFIG2_ONE_CYCLE		(1 << 2)
+-#define NFC_V3_CONFIG2_ECC_EN			(1 << 3)
+-#define NFC_V3_CONFIG2_2CMD_PHASES		(1 << 4)
+-#define NFC_V3_CONFIG2_NUM_ADDR_PHASE0		(1 << 5)
+-#define NFC_V3_CONFIG2_ECC_MODE_8		(1 << 6)
+-#define NFC_V3_CONFIG2_PPB(x, shift)		(((x) & 0x3) << shift)
+-#define NFC_V3_CONFIG2_NUM_ADDR_PHASE1(x)	(((x) & 0x3) << 12)
+-#define NFC_V3_CONFIG2_INT_MSK			(1 << 15)
+-#define NFC_V3_CONFIG2_ST_CMD(x)		(((x) & 0xff) << 24)
+-#define NFC_V3_CONFIG2_SPAS(x)			(((x) & 0xff) << 16)
+-
+-#define NFC_V3_CONFIG3				(host->regs_ip + 0x28)
+-#define NFC_V3_CONFIG3_ADD_OP(x)		(((x) & 0x3) << 0)
+-#define NFC_V3_CONFIG3_FW8			(1 << 3)
+-#define NFC_V3_CONFIG3_SBB(x)			(((x) & 0x7) << 8)
+-#define NFC_V3_CONFIG3_NUM_OF_DEVICES(x)	(((x) & 0x7) << 12)
+-#define NFC_V3_CONFIG3_RBB_MODE			(1 << 15)
+-#define NFC_V3_CONFIG3_NO_SDMA			(1 << 20)
+-
+-#define NFC_V3_IPC			(host->regs_ip + 0x2C)
+-#define NFC_V3_IPC_CREQ			(1 << 0)
+-#define NFC_V3_IPC_INT			(1 << 31)
+-
+-#define NFC_V3_DELAY_LINE		(host->regs_ip + 0x34)
+-
+-struct mxc_nand_host;
+-
+-struct mxc_nand_devtype_data {
+-	void (*preset)(struct mtd_info *);
+-	void (*send_cmd)(struct mxc_nand_host *, uint16_t, int);
+-	void (*send_addr)(struct mxc_nand_host *, uint16_t, int);
+-	void (*send_page)(struct mtd_info *, unsigned int);
+-	void (*send_read_id)(struct mxc_nand_host *);
+-	uint16_t (*get_dev_status)(struct mxc_nand_host *);
+-	int (*check_int)(struct mxc_nand_host *);
+-	void (*irq_control)(struct mxc_nand_host *, int);
+-	u32 (*get_ecc_status)(struct mxc_nand_host *);
+-	const struct mtd_ooblayout_ops *ooblayout;
+-	void (*select_chip)(struct mtd_info *mtd, int chip);
+-	int (*correct_data)(struct mtd_info *mtd, u_char *dat,
+-			u_char *read_ecc, u_char *calc_ecc);
+-	int (*setup_data_interface)(struct mtd_info *mtd, int csline,
+-				    const struct nand_data_interface *conf);
+-
+-	/*
+-	 * On i.MX21 the CONFIG2:INT bit cannot be read if interrupts are masked
+-	 * (CONFIG1:INT_MSK is set). To handle this the driver uses
+-	 * enable_irq/disable_irq_nosync instead of CONFIG1:INT_MSK
+-	 */
+-	int irqpending_quirk;
+-	int needs_ip;
+-
+-	size_t regs_offset;
+-	size_t spare0_offset;
+-	size_t axi_offset;
+-
+-	int spare_len;
+-	int eccbytes;
+-	int eccsize;
+-	int ppb_shift;
+-};
+-
+-struct mxc_nand_host {
+-	struct nand_chip	nand;
+-	struct device		*dev;
+-
+-	void __iomem		*spare0;
+-	void __iomem		*main_area0;
+-
+-	void __iomem		*base;
+-	void __iomem		*regs;
+-	void __iomem		*regs_axi;
+-	void __iomem		*regs_ip;
+-	int			status_request;
+-	struct clk		*clk;
+-	int			clk_act;
+-	int			irq;
+-	int			eccsize;
+-	int			used_oobsize;
+-	int			active_cs;
+-
+-	struct completion	op_completion;
+-
+-	uint8_t			*data_buf;
+-	unsigned int		buf_start;
+-
+-	const struct mxc_nand_devtype_data *devtype_data;
+-	struct mxc_nand_platform_data pdata;
+-};
+-
+-static const char * const part_probes[] = {
+-	"cmdlinepart", "RedBoot", "ofpart", NULL };
+-
+-static void memcpy32_fromio(void *trg, const void __iomem  *src, size_t size)
+-{
+-	int i;
+-	u32 *t = trg;
+-	const __iomem u32 *s = src;
+-
+-	for (i = 0; i < (size >> 2); i++)
+-		*t++ = __raw_readl(s++);
+-}
+-
+-static void memcpy16_fromio(void *trg, const void __iomem  *src, size_t size)
+-{
+-	int i;
+-	u16 *t = trg;
+-	const __iomem u16 *s = src;
+-
+-	/* We assume that src (IO) is always 32bit aligned */
+-	if (PTR_ALIGN(trg, 4) == trg && IS_ALIGNED(size, 4)) {
+-		memcpy32_fromio(trg, src, size);
+-		return;
+-	}
+-
+-	for (i = 0; i < (size >> 1); i++)
+-		*t++ = __raw_readw(s++);
+-}
+-
+-static inline void memcpy32_toio(void __iomem *trg, const void *src, int size)
+-{
+-	/* __iowrite32_copy use 32bit size values so divide by 4 */
+-	__iowrite32_copy(trg, src, size / 4);
+-}
+-
+-static void memcpy16_toio(void __iomem *trg, const void *src, int size)
+-{
+-	int i;
+-	__iomem u16 *t = trg;
+-	const u16 *s = src;
+-
+-	/* We assume that trg (IO) is always 32bit aligned */
+-	if (PTR_ALIGN(src, 4) == src && IS_ALIGNED(size, 4)) {
+-		memcpy32_toio(trg, src, size);
+-		return;
+-	}
+-
+-	for (i = 0; i < (size >> 1); i++)
+-		__raw_writew(*s++, t++);
+-}
+-
+-static int check_int_v3(struct mxc_nand_host *host)
+-{
+-	uint32_t tmp;
+-
+-	tmp = readl(NFC_V3_IPC);
+-	if (!(tmp & NFC_V3_IPC_INT))
+-		return 0;
+-
+-	tmp &= ~NFC_V3_IPC_INT;
+-	writel(tmp, NFC_V3_IPC);
+-
+-	return 1;
+-}
+-
+-static int check_int_v1_v2(struct mxc_nand_host *host)
+-{
+-	uint32_t tmp;
+-
+-	tmp = readw(NFC_V1_V2_CONFIG2);
+-	if (!(tmp & NFC_V1_V2_CONFIG2_INT))
+-		return 0;
+-
+-	if (!host->devtype_data->irqpending_quirk)
+-		writew(tmp & ~NFC_V1_V2_CONFIG2_INT, NFC_V1_V2_CONFIG2);
+-
+-	return 1;
+-}
+-
+-static void irq_control_v1_v2(struct mxc_nand_host *host, int activate)
+-{
+-	uint16_t tmp;
+-
+-	tmp = readw(NFC_V1_V2_CONFIG1);
+-
+-	if (activate)
+-		tmp &= ~NFC_V1_V2_CONFIG1_INT_MSK;
+-	else
+-		tmp |= NFC_V1_V2_CONFIG1_INT_MSK;
+-
+-	writew(tmp, NFC_V1_V2_CONFIG1);
+-}
+-
+-static void irq_control_v3(struct mxc_nand_host *host, int activate)
+-{
+-	uint32_t tmp;
+-
+-	tmp = readl(NFC_V3_CONFIG2);
+-
+-	if (activate)
+-		tmp &= ~NFC_V3_CONFIG2_INT_MSK;
+-	else
+-		tmp |= NFC_V3_CONFIG2_INT_MSK;
+-
+-	writel(tmp, NFC_V3_CONFIG2);
+-}
+-
+-static void irq_control(struct mxc_nand_host *host, int activate)
+-{
+-	if (host->devtype_data->irqpending_quirk) {
+-		if (activate)
+-			enable_irq(host->irq);
+-		else
+-			disable_irq_nosync(host->irq);
+-	} else {
+-		host->devtype_data->irq_control(host, activate);
+-	}
+-}
+-
+-static u32 get_ecc_status_v1(struct mxc_nand_host *host)
+-{
+-	return readw(NFC_V1_V2_ECC_STATUS_RESULT);
+-}
+-
+-static u32 get_ecc_status_v2(struct mxc_nand_host *host)
+-{
+-	return readl(NFC_V1_V2_ECC_STATUS_RESULT);
+-}
+-
+-static u32 get_ecc_status_v3(struct mxc_nand_host *host)
+-{
+-	return readl(NFC_V3_ECC_STATUS_RESULT);
+-}
+-
+-static irqreturn_t mxc_nfc_irq(int irq, void *dev_id)
+-{
+-	struct mxc_nand_host *host = dev_id;
+-
+-	if (!host->devtype_data->check_int(host))
+-		return IRQ_NONE;
+-
+-	irq_control(host, 0);
+-
+-	complete(&host->op_completion);
+-
+-	return IRQ_HANDLED;
+-}
+-
+-/* This function polls the NANDFC to wait for the basic operation to
+- * complete by checking the INT bit of config2 register.
+- */
+-static int wait_op_done(struct mxc_nand_host *host, int useirq)
+-{
+-	int ret = 0;
+-
+-	/*
+-	 * If operation is already complete, don't bother to setup an irq or a
+-	 * loop.
+-	 */
+-	if (host->devtype_data->check_int(host))
+-		return 0;
+-
+-	if (useirq) {
+-		unsigned long timeout;
+-
+-		reinit_completion(&host->op_completion);
+-
+-		irq_control(host, 1);
+-
+-		timeout = wait_for_completion_timeout(&host->op_completion, HZ);
+-		if (!timeout && !host->devtype_data->check_int(host)) {
+-			dev_dbg(host->dev, "timeout waiting for irq\n");
+-			ret = -ETIMEDOUT;
+-		}
+-	} else {
+-		int max_retries = 8000;
+-		int done;
+-
+-		do {
+-			udelay(1);
+-
+-			done = host->devtype_data->check_int(host);
+-			if (done)
+-				break;
+-
+-		} while (--max_retries);
+-
+-		if (!done) {
+-			dev_dbg(host->dev, "timeout polling for completion\n");
+-			ret = -ETIMEDOUT;
+-		}
+-	}
+-
+-	WARN_ONCE(ret < 0, "timeout! useirq=%d\n", useirq);
+-
+-	return ret;
+-}
+-
+-static void send_cmd_v3(struct mxc_nand_host *host, uint16_t cmd, int useirq)
+-{
+-	/* fill command */
+-	writel(cmd, NFC_V3_FLASH_CMD);
+-
+-	/* send out command */
+-	writel(NFC_CMD, NFC_V3_LAUNCH);
+-
+-	/* Wait for operation to complete */
+-	wait_op_done(host, useirq);
+-}
+-
+-/* This function issues the specified command to the NAND device and
+- * waits for completion. */
+-static void send_cmd_v1_v2(struct mxc_nand_host *host, uint16_t cmd, int useirq)
+-{
+-	pr_debug("send_cmd(host, 0x%x, %d)\n", cmd, useirq);
+-
+-	writew(cmd, NFC_V1_V2_FLASH_CMD);
+-	writew(NFC_CMD, NFC_V1_V2_CONFIG2);
+-
+-	if (host->devtype_data->irqpending_quirk && (cmd == NAND_CMD_RESET)) {
+-		int max_retries = 100;
+-		/* Reset completion is indicated by NFC_CONFIG2 */
+-		/* being set to 0 */
+-		while (max_retries-- > 0) {
+-			if (readw(NFC_V1_V2_CONFIG2) == 0) {
+-				break;
+-			}
+-			udelay(1);
+-		}
+-		if (max_retries < 0)
+-			pr_debug("%s: RESET failed\n", __func__);
+-	} else {
+-		/* Wait for operation to complete */
+-		wait_op_done(host, useirq);
+-	}
+-}
+-
+-static void send_addr_v3(struct mxc_nand_host *host, uint16_t addr, int islast)
+-{
+-	/* fill address */
+-	writel(addr, NFC_V3_FLASH_ADDR0);
+-
+-	/* send out address */
+-	writel(NFC_ADDR, NFC_V3_LAUNCH);
+-
+-	wait_op_done(host, 0);
+-}
+-
+-/* This function sends an address (or partial address) to the
+- * NAND device. The address is used to select the source/destination for
+- * a NAND command. */
+-static void send_addr_v1_v2(struct mxc_nand_host *host, uint16_t addr, int islast)
+-{
+-	pr_debug("send_addr(host, 0x%x %d)\n", addr, islast);
+-
+-	writew(addr, NFC_V1_V2_FLASH_ADDR);
+-	writew(NFC_ADDR, NFC_V1_V2_CONFIG2);
+-
+-	/* Wait for operation to complete */
+-	wait_op_done(host, islast);
+-}
+-
+-static void send_page_v3(struct mtd_info *mtd, unsigned int ops)
+-{
+-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+-	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
+-	uint32_t tmp;
+-
+-	tmp = readl(NFC_V3_CONFIG1);
+-	tmp &= ~(7 << 4);
+-	writel(tmp, NFC_V3_CONFIG1);
+-
+-	/* transfer data from NFC ram to nand */
+-	writel(ops, NFC_V3_LAUNCH);
+-
+-	wait_op_done(host, false);
+-}
+-
+-static void send_page_v2(struct mtd_info *mtd, unsigned int ops)
+-{
+-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+-	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
+-
+-	/* NANDFC buffer 0 is used for page read/write */
+-	writew(host->active_cs << 4, NFC_V1_V2_BUF_ADDR);
+-
+-	writew(ops, NFC_V1_V2_CONFIG2);
+-
+-	/* Wait for operation to complete */
+-	wait_op_done(host, true);
+-}
+-
+-static void send_page_v1(struct mtd_info *mtd, unsigned int ops)
+-{
+-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+-	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
+-	int bufs, i;
+-
+-	if (mtd->writesize > 512)
+-		bufs = 4;
+-	else
+-		bufs = 1;
+-
+-	for (i = 0; i < bufs; i++) {
+-
+-		/* NANDFC buffer 0 is used for page read/write */
+-		writew((host->active_cs << 4) | i, NFC_V1_V2_BUF_ADDR);
+-
+-		writew(ops, NFC_V1_V2_CONFIG2);
+-
+-		/* Wait for operation to complete */
+-		wait_op_done(host, true);
+-	}
+-}
+-
+-static void send_read_id_v3(struct mxc_nand_host *host)
+-{
+-	/* Read ID into main buffer */
+-	writel(NFC_ID, NFC_V3_LAUNCH);
+-
+-	wait_op_done(host, true);
+-
+-	memcpy32_fromio(host->data_buf, host->main_area0, 16);
+-}
+-
+-/* Request the NANDFC to perform a read of the NAND device ID. */
+-static void send_read_id_v1_v2(struct mxc_nand_host *host)
+-{
+-	/* NANDFC buffer 0 is used for device ID output */
+-	writew(host->active_cs << 4, NFC_V1_V2_BUF_ADDR);
+-
+-	writew(NFC_ID, NFC_V1_V2_CONFIG2);
+-
+-	/* Wait for operation to complete */
+-	wait_op_done(host, true);
+-
+-	memcpy32_fromio(host->data_buf, host->main_area0, 16);
+-}
+-
+-static uint16_t get_dev_status_v3(struct mxc_nand_host *host)
+-{
+-	writew(NFC_STATUS, NFC_V3_LAUNCH);
+-	wait_op_done(host, true);
+-
+-	return readl(NFC_V3_CONFIG1) >> 16;
+-}
+-
+-/* This function requests the NANDFC to perform a read of the
+- * NAND device status and returns the current status. */
+-static uint16_t get_dev_status_v1_v2(struct mxc_nand_host *host)
+-{
+-	void __iomem *main_buf = host->main_area0;
+-	uint32_t store;
+-	uint16_t ret;
+-
+-	writew(host->active_cs << 4, NFC_V1_V2_BUF_ADDR);
+-
+-	/*
+-	 * The device status is stored in main_area0. To
+-	 * prevent corruption of the buffer save the value
+-	 * and restore it afterwards.
+-	 */
+-	store = readl(main_buf);
+-
+-	writew(NFC_STATUS, NFC_V1_V2_CONFIG2);
+-	wait_op_done(host, true);
+-
+-	ret = readw(main_buf);
+-
+-	writel(store, main_buf);
+-
+-	return ret;
+-}
+-
+-/* This functions is used by upper layer to checks if device is ready */
+-static int mxc_nand_dev_ready(struct mtd_info *mtd)
+-{
+-	/*
+-	 * NFC handles R/B internally. Therefore, this function
+-	 * always returns status as ready.
+-	 */
+-	return 1;
+-}
+-
+-static void mxc_nand_enable_hwecc(struct mtd_info *mtd, int mode)
+-{
+-	/*
+-	 * If HW ECC is enabled, we turn it on during init. There is
+-	 * no need to enable again here.
+-	 */
+-}
+-
+-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 mxc_nand_host *host = nand_get_controller_data(nand_chip);
+-
+-	/*
+-	 * 1-Bit errors are automatically corrected in HW.  No need for
+-	 * additional correction.  2-Bit errors cannot be corrected by
+-	 * HW ECC, so we need to return failure
+-	 */
+-	uint16_t ecc_status = get_ecc_status_v1(host);
+-
+-	if (((ecc_status & 0x3) == 2) || ((ecc_status >> 2) == 2)) {
+-		pr_debug("MXC_NAND: HWECC uncorrectable 2-bit ECC error\n");
+-		return -EBADMSG;
+-	}
+-
+-	return 0;
+-}
+-
+-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 mxc_nand_host *host = nand_get_controller_data(nand_chip);
+-	u32 ecc_stat, err;
+-	int no_subpages = 1;
+-	int ret = 0;
+-	u8 ecc_bit_mask, err_limit;
+-
+-	ecc_bit_mask = (host->eccsize == 4) ? 0x7 : 0xf;
+-	err_limit = (host->eccsize == 4) ? 0x4 : 0x8;
+-
+-	no_subpages = mtd->writesize >> 9;
+-
+-	ecc_stat = host->devtype_data->get_ecc_status(host);
+-
+-	do {
+-		err = ecc_stat & ecc_bit_mask;
+-		if (err > err_limit) {
+-			printk(KERN_WARNING "UnCorrectable RS-ECC Error\n");
+-			return -EBADMSG;
+-		} else {
+-			ret += err;
+-		}
+-		ecc_stat >>= 4;
+-	} while (--no_subpages);
+-
+-	pr_debug("%d Symbol Correctable RS-ECC Error\n", ret);
+-
+-	return ret;
+-}
+-
+-static int mxc_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
+-				  u_char *ecc_code)
+-{
+-	return 0;
+-}
+-
+-static u_char mxc_nand_read_byte(struct mtd_info *mtd)
+-{
+-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+-	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
+-	uint8_t ret;
+-
+-	/* Check for status request */
+-	if (host->status_request)
+-		return host->devtype_data->get_dev_status(host) & 0xFF;
+-
+-	if (nand_chip->options & NAND_BUSWIDTH_16) {
+-		/* only take the lower byte of each word */
+-		ret = *(uint16_t *)(host->data_buf + host->buf_start);
+-
+-		host->buf_start += 2;
+-	} else {
+-		ret = *(uint8_t *)(host->data_buf + host->buf_start);
+-		host->buf_start++;
+-	}
+-
+-	pr_debug("%s: ret=0x%hhx (start=%u)\n", __func__, ret, host->buf_start);
+-	return ret;
+-}
+-
+-static uint16_t mxc_nand_read_word(struct mtd_info *mtd)
+-{
+-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+-	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
+-	uint16_t ret;
+-
+-	ret = *(uint16_t *)(host->data_buf + host->buf_start);
+-	host->buf_start += 2;
+-
+-	return ret;
+-}
+-
+-/* Write data of length len to buffer buf. The data to be
+- * written on NAND Flash is first copied to RAMbuffer. After the Data Input
+- * Operation by the NFC, the data is written to NAND Flash */
+-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 mxc_nand_host *host = nand_get_controller_data(nand_chip);
+-	u16 col = host->buf_start;
+-	int n = mtd->oobsize + mtd->writesize - col;
+-
+-	n = min(n, len);
+-
+-	memcpy(host->data_buf + col, buf, n);
+-
+-	host->buf_start += n;
+-}
+-
+-/* Read the data buffer from the NAND Flash. To read the data from NAND
+- * Flash first the data output cycle is initiated by the NFC, which copies
+- * the data to RAMbuffer. This data of length len is then copied to buffer buf.
+- */
+-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 mxc_nand_host *host = nand_get_controller_data(nand_chip);
+-	u16 col = host->buf_start;
+-	int n = mtd->oobsize + mtd->writesize - col;
+-
+-	n = min(n, len);
+-
+-	memcpy(buf, host->data_buf + col, n);
+-
+-	host->buf_start += n;
+-}
+-
+-/* This function is used by upper layer for select and
+- * 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 mxc_nand_host *host = nand_get_controller_data(nand_chip);
+-
+-	if (chip == -1) {
+-		/* Disable the NFC clock */
+-		if (host->clk_act) {
+-			clk_disable_unprepare(host->clk);
+-			host->clk_act = 0;
+-		}
+-		return;
+-	}
+-
+-	if (!host->clk_act) {
+-		/* Enable the NFC clock */
+-		clk_prepare_enable(host->clk);
+-		host->clk_act = 1;
+-	}
+-}
+-
+-static void mxc_nand_select_chip_v2(struct mtd_info *mtd, int chip)
+-{
+-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+-	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
+-
+-	if (chip == -1) {
+-		/* Disable the NFC clock */
+-		if (host->clk_act) {
+-			clk_disable_unprepare(host->clk);
+-			host->clk_act = 0;
+-		}
+-		return;
+-	}
+-
+-	if (!host->clk_act) {
+-		/* Enable the NFC clock */
+-		clk_prepare_enable(host->clk);
+-		host->clk_act = 1;
+-	}
+-
+-	host->active_cs = chip;
+-	writew(host->active_cs << 4, NFC_V1_V2_BUF_ADDR);
+-}
+-
+-/*
+- * The controller splits a page into data chunks of 512 bytes + partial oob.
+- * There are writesize / 512 such chunks, the size of the partial oob parts is
+- * oobsize / #chunks rounded down to a multiple of 2. The last oob chunk then
+- * contains additionally the byte lost by rounding (if any).
+- * This function handles the needed shuffling between host->data_buf (which
+- * holds a page in natural order, i.e. writesize bytes data + oobsize bytes
+- * spare) and the NFC buffer.
+- */
+-static void copy_spare(struct mtd_info *mtd, bool bfrom)
+-{
+-	struct nand_chip *this = mtd_to_nand(mtd);
+-	struct mxc_nand_host *host = nand_get_controller_data(this);
+-	u16 i, oob_chunk_size;
+-	u16 num_chunks = mtd->writesize / 512;
+-
+-	u8 *d = host->data_buf + mtd->writesize;
+-	u8 __iomem *s = host->spare0;
+-	u16 sparebuf_size = host->devtype_data->spare_len;
+-
+-	/* size of oob chunk for all but possibly the last one */
+-	oob_chunk_size = (host->used_oobsize / num_chunks) & ~1;
+-
+-	if (bfrom) {
+-		for (i = 0; i < num_chunks - 1; i++)
+-			memcpy16_fromio(d + i * oob_chunk_size,
+-					s + i * sparebuf_size,
+-					oob_chunk_size);
+-
+-		/* the last chunk */
+-		memcpy16_fromio(d + i * oob_chunk_size,
+-				s + i * sparebuf_size,
+-				host->used_oobsize - i * oob_chunk_size);
+-	} else {
+-		for (i = 0; i < num_chunks - 1; i++)
+-			memcpy16_toio(&s[i * sparebuf_size],
+-				      &d[i * oob_chunk_size],
+-				      oob_chunk_size);
+-
+-		/* the last chunk */
+-		memcpy16_toio(&s[i * sparebuf_size],
+-			      &d[i * oob_chunk_size],
+-			      host->used_oobsize - i * oob_chunk_size);
+-	}
+-}
+-
+-/*
+- * MXC NANDFC can only perform full page+spare or spare-only read/write.  When
+- * the upper layers perform a read/write buf operation, the saved column address
+- * is used to index into the full page. So usually this function is called with
+- * column == 0 (unless no column cycle is needed indicated by column == -1)
+- */
+-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 mxc_nand_host *host = nand_get_controller_data(nand_chip);
+-
+-	/* Write out column address, if necessary */
+-	if (column != -1) {
+-		host->devtype_data->send_addr(host, column & 0xff,
+-					      page_addr == -1);
+-		if (mtd->writesize > 512)
+-			/* another col addr cycle for 2k page */
+-			host->devtype_data->send_addr(host,
+-						      (column >> 8) & 0xff,
+-						      false);
+-	}
+-
+-	/* Write out page address, if necessary */
+-	if (page_addr != -1) {
+-		/* paddr_0 - p_addr_7 */
+-		host->devtype_data->send_addr(host, (page_addr & 0xff), false);
+-
+-		if (mtd->writesize > 512) {
+-			if (mtd->size >= 0x10000000) {
+-				/* paddr_8 - paddr_15 */
+-				host->devtype_data->send_addr(host,
+-						(page_addr >> 8) & 0xff,
+-						false);
+-				host->devtype_data->send_addr(host,
+-						(page_addr >> 16) & 0xff,
+-						true);
+-			} else
+-				/* paddr_8 - paddr_15 */
+-				host->devtype_data->send_addr(host,
+-						(page_addr >> 8) & 0xff, true);
+-		} else {
+-			/* One more address cycle for higher density devices */
+-			if (mtd->size >= 0x4000000) {
+-				/* paddr_8 - paddr_15 */
+-				host->devtype_data->send_addr(host,
+-						(page_addr >> 8) & 0xff,
+-						false);
+-				host->devtype_data->send_addr(host,
+-						(page_addr >> 16) & 0xff,
+-						true);
+-			} else
+-				/* paddr_8 - paddr_15 */
+-				host->devtype_data->send_addr(host,
+-						(page_addr >> 8) & 0xff, true);
+-		}
+-	}
+-}
+-
+-#define MXC_V1_ECCBYTES		5
+-
+-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);
+-
+-	if (section >= nand_chip->ecc.steps)
+-		return -ERANGE;
+-
+-	oobregion->offset = (section * 16) + 6;
+-	oobregion->length = MXC_V1_ECCBYTES;
+-
+-	return 0;
+-}
+-
+-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);
+-
+-	if (section > nand_chip->ecc.steps)
+-		return -ERANGE;
+-
+-	if (!section) {
+-		if (mtd->writesize <= 512) {
+-			oobregion->offset = 0;
+-			oobregion->length = 5;
+-		} else {
+-			oobregion->offset = 2;
+-			oobregion->length = 4;
+-		}
+-	} else {
+-		oobregion->offset = ((section - 1) * 16) + MXC_V1_ECCBYTES + 6;
+-		if (section < nand_chip->ecc.steps)
+-			oobregion->length = (section * 16) + 6 -
+-					    oobregion->offset;
+-		else
+-			oobregion->length = mtd->oobsize - oobregion->offset;
+-	}
+-
+-	return 0;
+-}
+-
+-static const struct mtd_ooblayout_ops mxc_v1_ooblayout_ops = {
+-	.ecc = mxc_v1_ooblayout_ecc,
+-	.free = mxc_v1_ooblayout_free,
+-};
+-
+-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);
+-	int stepsize = nand_chip->ecc.bytes == 9 ? 16 : 26;
+-
+-	if (section >= nand_chip->ecc.steps)
+-		return -ERANGE;
+-
+-	oobregion->offset = (section * stepsize) + 7;
+-	oobregion->length = nand_chip->ecc.bytes;
+-
+-	return 0;
+-}
+-
+-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);
+-	int stepsize = nand_chip->ecc.bytes == 9 ? 16 : 26;
+-
+-	if (section >= nand_chip->ecc.steps)
+-		return -ERANGE;
+-
+-	if (!section) {
+-		if (mtd->writesize <= 512) {
+-			oobregion->offset = 0;
+-			oobregion->length = 5;
+-		} else {
+-			oobregion->offset = 2;
+-			oobregion->length = 4;
+-		}
+-	} else {
+-		oobregion->offset = section * stepsize;
+-		oobregion->length = 7;
+-	}
+-
+-	return 0;
+-}
+-
+-static const struct mtd_ooblayout_ops mxc_v2_ooblayout_ops = {
+-	.ecc = mxc_v2_ooblayout_ecc,
+-	.free = mxc_v2_ooblayout_free,
+-};
+-
+-/*
+- * v2 and v3 type controllers can do 4bit or 8bit ecc depending
+- * on how much oob the nand chip has. For 8bit ecc we need at least
+- * 26 bytes of oob data per 512 byte block.
+- */
+-static int get_eccsize(struct mtd_info *mtd)
+-{
+-	int oobbytes_per_512 = 0;
+-
+-	oobbytes_per_512 = mtd->oobsize * 512 / mtd->writesize;
+-
+-	if (oobbytes_per_512 < 26)
+-		return 4;
+-	else
+-		return 8;
+-}
+-
+-static void preset_v1(struct mtd_info *mtd)
+-{
+-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+-	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
+-	uint16_t config1 = 0;
+-
+-	if (nand_chip->ecc.mode == NAND_ECC_HW && mtd->writesize)
+-		config1 |= NFC_V1_V2_CONFIG1_ECC_EN;
+-
+-	if (!host->devtype_data->irqpending_quirk)
+-		config1 |= NFC_V1_V2_CONFIG1_INT_MSK;
+-
+-	host->eccsize = 1;
+-
+-	writew(config1, NFC_V1_V2_CONFIG1);
+-	/* preset operation */
+-
+-	/* Unlock the internal RAM Buffer */
+-	writew(0x2, NFC_V1_V2_CONFIG);
+-
+-	/* Blocks to be unlocked */
+-	writew(0x0, NFC_V1_UNLOCKSTART_BLKADDR);
+-	writew(0xffff, NFC_V1_UNLOCKEND_BLKADDR);
+-
+-	/* Unlock Block Command for given address range */
+-	writew(0x4, NFC_V1_V2_WRPROT);
+-}
+-
+-static int mxc_nand_v2_setup_data_interface(struct mtd_info *mtd, int csline,
+-					const struct nand_data_interface *conf)
+-{
+-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+-	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
+-	int tRC_min_ns, tRC_ps, ret;
+-	unsigned long rate, rate_round;
+-	const struct nand_sdr_timings *timings;
+-	u16 config1;
+-
+-	timings = nand_get_sdr_timings(conf);
+-	if (IS_ERR(timings))
+-		return -ENOTSUPP;
+-
+-	config1 = readw(NFC_V1_V2_CONFIG1);
+-
+-	tRC_min_ns = timings->tRC_min / 1000;
+-	rate = 1000000000 / tRC_min_ns;
+-
+-	/*
+-	 * For tRC < 30ns we have to use EDO mode. In this case the controller
+-	 * does one access per clock cycle. Otherwise the controller does one
+-	 * access in two clock cycles, thus we have to double the rate to the
+-	 * controller.
+-	 */
+-	if (tRC_min_ns < 30) {
+-		rate_round = clk_round_rate(host->clk, rate);
+-		config1 |= NFC_V2_CONFIG1_ONE_CYCLE;
+-		tRC_ps = 1000000000 / (rate_round / 1000);
+-	} else {
+-		rate *= 2;
+-		rate_round = clk_round_rate(host->clk, rate);
+-		config1 &= ~NFC_V2_CONFIG1_ONE_CYCLE;
+-		tRC_ps = 1000000000 / (rate_round / 1000 / 2);
+-	}
+-
+-	/*
+-	 * The timing values compared against are from the i.MX25 Automotive
+-	 * datasheet, Table 50. NFC Timing Parameters
+-	 */
+-	if (timings->tCLS_min > tRC_ps - 1000 ||
+-	    timings->tCLH_min > tRC_ps - 2000 ||
+-	    timings->tCS_min > tRC_ps - 1000 ||
+-	    timings->tCH_min > tRC_ps - 2000 ||
+-	    timings->tWP_min > tRC_ps - 1500 ||
+-	    timings->tALS_min > tRC_ps ||
+-	    timings->tALH_min > tRC_ps - 3000 ||
+-	    timings->tDS_min > tRC_ps ||
+-	    timings->tDH_min > tRC_ps - 5000 ||
+-	    timings->tWC_min > 2 * tRC_ps ||
+-	    timings->tWH_min > tRC_ps - 2500 ||
+-	    timings->tRR_min > 6 * tRC_ps ||
+-	    timings->tRP_min > 3 * tRC_ps / 2 ||
+-	    timings->tRC_min > 2 * tRC_ps ||
+-	    timings->tREH_min > (tRC_ps / 2) - 2500) {
+-		dev_dbg(host->dev, "Timing out of bounds\n");
+-		return -EINVAL;
+-	}
+-
+-	if (csline == NAND_DATA_IFACE_CHECK_ONLY)
+-		return 0;
+-
+-	ret = clk_set_rate(host->clk, rate);
+-	if (ret)
+-		return ret;
+-
+-	writew(config1, NFC_V1_V2_CONFIG1);
+-
+-	dev_dbg(host->dev, "Setting rate to %ldHz, %s mode\n", rate_round,
+-		config1 & NFC_V2_CONFIG1_ONE_CYCLE ? "One cycle (EDO)" :
+-		"normal");
+-
+-	return 0;
+-}
+-
+-static void preset_v2(struct mtd_info *mtd)
+-{
+-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+-	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
+-	uint16_t config1 = 0;
+-
+-	config1 |= NFC_V2_CONFIG1_FP_INT;
+-
+-	if (!host->devtype_data->irqpending_quirk)
+-		config1 |= NFC_V1_V2_CONFIG1_INT_MSK;
+-
+-	if (mtd->writesize) {
+-		uint16_t pages_per_block = mtd->erasesize / mtd->writesize;
+-
+-		if (nand_chip->ecc.mode == NAND_ECC_HW)
+-			config1 |= NFC_V1_V2_CONFIG1_ECC_EN;
+-
+-		host->eccsize = get_eccsize(mtd);
+-		if (host->eccsize == 4)
+-			config1 |= NFC_V2_CONFIG1_ECC_MODE_4;
+-
+-		config1 |= NFC_V2_CONFIG1_PPB(ffs(pages_per_block) - 6);
+-	} else {
+-		host->eccsize = 1;
+-	}
+-
+-	writew(config1, NFC_V1_V2_CONFIG1);
+-	/* preset operation */
+-
+-	/* Unlock the internal RAM Buffer */
+-	writew(0x2, NFC_V1_V2_CONFIG);
+-
+-	/* Blocks to be unlocked */
+-	writew(0x0, NFC_V21_UNLOCKSTART_BLKADDR0);
+-	writew(0x0, NFC_V21_UNLOCKSTART_BLKADDR1);
+-	writew(0x0, NFC_V21_UNLOCKSTART_BLKADDR2);
+-	writew(0x0, NFC_V21_UNLOCKSTART_BLKADDR3);
+-	writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR0);
+-	writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR1);
+-	writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR2);
+-	writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR3);
+-
+-	/* Unlock Block Command for given address range */
+-	writew(0x4, NFC_V1_V2_WRPROT);
+-}
+-
+-static void preset_v3(struct mtd_info *mtd)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct mxc_nand_host *host = nand_get_controller_data(chip);
+-	uint32_t config2, config3;
+-	int i, addr_phases;
+-
+-	writel(NFC_V3_CONFIG1_RBA(0), NFC_V3_CONFIG1);
+-	writel(NFC_V3_IPC_CREQ, NFC_V3_IPC);
+-
+-	/* Unlock the internal RAM Buffer */
+-	writel(NFC_V3_WRPROT_BLS_UNLOCK | NFC_V3_WRPROT_UNLOCK,
+-			NFC_V3_WRPROT);
+-
+-	/* Blocks to be unlocked */
+-	for (i = 0; i < NAND_MAX_CHIPS; i++)
+-		writel(0xffff << 16, NFC_V3_WRPROT_UNLOCK_BLK_ADD0 + (i << 2));
+-
+-	writel(0, NFC_V3_IPC);
+-
+-	config2 = NFC_V3_CONFIG2_ONE_CYCLE |
+-		NFC_V3_CONFIG2_2CMD_PHASES |
+-		NFC_V3_CONFIG2_SPAS(mtd->oobsize >> 1) |
+-		NFC_V3_CONFIG2_ST_CMD(0x70) |
+-		NFC_V3_CONFIG2_INT_MSK |
+-		NFC_V3_CONFIG2_NUM_ADDR_PHASE0;
+-
+-	addr_phases = fls(chip->pagemask) >> 3;
+-
+-	if (mtd->writesize == 2048) {
+-		config2 |= NFC_V3_CONFIG2_PS_2048;
+-		config2 |= NFC_V3_CONFIG2_NUM_ADDR_PHASE1(addr_phases);
+-	} else if (mtd->writesize == 4096) {
+-		config2 |= NFC_V3_CONFIG2_PS_4096;
+-		config2 |= NFC_V3_CONFIG2_NUM_ADDR_PHASE1(addr_phases);
+-	} else {
+-		config2 |= NFC_V3_CONFIG2_PS_512;
+-		config2 |= NFC_V3_CONFIG2_NUM_ADDR_PHASE1(addr_phases - 1);
+-	}
+-
+-	if (mtd->writesize) {
+-		if (chip->ecc.mode == NAND_ECC_HW)
+-			config2 |= NFC_V3_CONFIG2_ECC_EN;
+-
+-		config2 |= NFC_V3_CONFIG2_PPB(
+-				ffs(mtd->erasesize / mtd->writesize) - 6,
+-				host->devtype_data->ppb_shift);
+-		host->eccsize = get_eccsize(mtd);
+-		if (host->eccsize == 8)
+-			config2 |= NFC_V3_CONFIG2_ECC_MODE_8;
+-	}
+-
+-	writel(config2, NFC_V3_CONFIG2);
+-
+-	config3 = NFC_V3_CONFIG3_NUM_OF_DEVICES(0) |
+-			NFC_V3_CONFIG3_NO_SDMA |
+-			NFC_V3_CONFIG3_RBB_MODE |
+-			NFC_V3_CONFIG3_SBB(6) | /* Reset default */
+-			NFC_V3_CONFIG3_ADD_OP(0);
+-
+-	if (!(chip->options & NAND_BUSWIDTH_16))
+-		config3 |= NFC_V3_CONFIG3_FW8;
+-
+-	writel(config3, NFC_V3_CONFIG3);
+-
+-	writel(0, NFC_V3_DELAY_LINE);
+-}
+-
+-/* Used by the upper layer to write command to NAND Flash for
+- * different operations to be carried out on NAND Flash */
+-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 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",
+-	      command, column, page_addr);
+-
+-	/* Reset command state information */
+-	host->status_request = false;
+-
+-	/* Command pre-processing step */
+-	switch (command) {
+-	case NAND_CMD_RESET:
+-		host->devtype_data->preset(mtd);
+-		host->devtype_data->send_cmd(host, command, false);
+-		break;
+-
+-	case NAND_CMD_STATUS:
+-		host->buf_start = 0;
+-		host->status_request = true;
+-
+-		host->devtype_data->send_cmd(host, command, true);
+-		WARN_ONCE(column != -1 || page_addr != -1,
+-			  "Unexpected column/row value (cmd=%u, col=%d, row=%d)\n",
+-			  command, column, page_addr);
+-		mxc_do_addr_cycle(mtd, column, page_addr);
+-		break;
+-
+-	case NAND_CMD_READ0:
+-	case NAND_CMD_READOOB:
+-		if (command == NAND_CMD_READ0)
+-			host->buf_start = column;
+-		else
+-			host->buf_start = column + mtd->writesize;
+-
+-		command = NAND_CMD_READ0; /* only READ0 is valid */
+-
+-		host->devtype_data->send_cmd(host, command, false);
+-		WARN_ONCE(column < 0,
+-			  "Unexpected column/row value (cmd=%u, col=%d, row=%d)\n",
+-			  command, column, page_addr);
+-		mxc_do_addr_cycle(mtd, 0, page_addr);
+-
+-		if (mtd->writesize > 512)
+-			host->devtype_data->send_cmd(host,
+-					NAND_CMD_READSTART, true);
+-
+-		host->devtype_data->send_page(mtd, NFC_OUTPUT);
+-
+-		memcpy32_fromio(host->data_buf, host->main_area0,
+-				mtd->writesize);
+-		copy_spare(mtd, true);
+-		break;
+-
+-	case NAND_CMD_SEQIN:
+-		if (column >= mtd->writesize)
+-			/* call ourself to read a page */
+-			mxc_nand_command(mtd, NAND_CMD_READ0, 0, page_addr);
+-
+-		host->buf_start = column;
+-
+-		host->devtype_data->send_cmd(host, command, false);
+-		WARN_ONCE(column < -1,
+-			  "Unexpected column/row value (cmd=%u, col=%d, row=%d)\n",
+-			  command, column, page_addr);
+-		mxc_do_addr_cycle(mtd, 0, page_addr);
+-		break;
+-
+-	case NAND_CMD_PAGEPROG:
+-		memcpy32_toio(host->main_area0, host->data_buf, mtd->writesize);
+-		copy_spare(mtd, false);
+-		host->devtype_data->send_page(mtd, NFC_INPUT);
+-		host->devtype_data->send_cmd(host, command, true);
+-		WARN_ONCE(column != -1 || page_addr != -1,
+-			  "Unexpected column/row value (cmd=%u, col=%d, row=%d)\n",
+-			  command, column, page_addr);
+-		mxc_do_addr_cycle(mtd, column, page_addr);
+-		break;
+-
+-	case NAND_CMD_READID:
+-		host->devtype_data->send_cmd(host, command, true);
+-		mxc_do_addr_cycle(mtd, column, page_addr);
+-		host->devtype_data->send_read_id(host);
+-		host->buf_start = 0;
+-		break;
+-
+-	case NAND_CMD_ERASE1:
+-	case NAND_CMD_ERASE2:
+-		host->devtype_data->send_cmd(host, command, false);
+-		WARN_ONCE(column != -1,
+-			  "Unexpected column value (cmd=%u, col=%d)\n",
+-			  command, column);
+-		mxc_do_addr_cycle(mtd, column, page_addr);
+-
+-		break;
+-	case NAND_CMD_PARAM:
+-		host->devtype_data->send_cmd(host, command, false);
+-		mxc_do_addr_cycle(mtd, column, page_addr);
+-		host->devtype_data->send_page(mtd, NFC_OUTPUT);
+-		memcpy32_fromio(host->data_buf, host->main_area0, 512);
+-		host->buf_start = 0;
+-		break;
+-	default:
+-		WARN_ONCE(1, "Unimplemented command (cmd=%u)\n",
+-			  command);
+-		break;
+-	}
+-}
+-
+-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 mxc_nand_host *host = nand_get_controller_data(nand_chip);
+-	int i;
+-
+-	if (!chip->onfi_version ||
+-	    !(le16_to_cpu(chip->onfi_params.opt_cmd)
+-	      & ONFI_OPT_CMD_SET_GET_FEATURES))
+-		return -EINVAL;
+-
+-	host->buf_start = 0;
+-
+-	for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
+-		chip->write_byte(mtd, subfeature_param[i]);
+-
+-	memcpy32_toio(host->main_area0, host->data_buf, mtd->writesize);
+-	host->devtype_data->send_cmd(host, NAND_CMD_SET_FEATURES, false);
+-	mxc_do_addr_cycle(mtd, addr, -1);
+-	host->devtype_data->send_page(mtd, NFC_INPUT);
+-
+-	return 0;
+-}
+-
+-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 mxc_nand_host *host = nand_get_controller_data(nand_chip);
+-	int i;
+-
+-	if (!chip->onfi_version ||
+-	    !(le16_to_cpu(chip->onfi_params.opt_cmd)
+-	      & ONFI_OPT_CMD_SET_GET_FEATURES))
+-		return -EINVAL;
+-
+-	host->devtype_data->send_cmd(host, NAND_CMD_GET_FEATURES, false);
+-	mxc_do_addr_cycle(mtd, addr, -1);
+-	host->devtype_data->send_page(mtd, NFC_OUTPUT);
+-	memcpy32_fromio(host->data_buf, host->main_area0, 512);
+-	host->buf_start = 0;
+-
+-	for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
+-		*subfeature_param++ = chip->read_byte(mtd);
+-
+-	return 0;
+-}
+-
+-/*
+- * The generic flash bbt decriptors overlap with our ecc
+- * hardware, so define some i.MX specific ones.
+- */
+-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 = 0,
+-	.len = 4,
+-	.veroffs = 4,
+-	.maxblocks = 4,
+-	.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 = 0,
+-	.len = 4,
+-	.veroffs = 4,
+-	.maxblocks = 4,
+-	.pattern = mirror_pattern,
+-};
+-
+-/* v1 + irqpending_quirk: i.MX21 */
+-static const struct mxc_nand_devtype_data imx21_nand_devtype_data = {
+-	.preset = preset_v1,
+-	.send_cmd = send_cmd_v1_v2,
+-	.send_addr = send_addr_v1_v2,
+-	.send_page = send_page_v1,
+-	.send_read_id = send_read_id_v1_v2,
+-	.get_dev_status = get_dev_status_v1_v2,
+-	.check_int = check_int_v1_v2,
+-	.irq_control = irq_control_v1_v2,
+-	.get_ecc_status = get_ecc_status_v1,
+-	.ooblayout = &mxc_v1_ooblayout_ops,
+-	.select_chip = mxc_nand_select_chip_v1_v3,
+-	.correct_data = mxc_nand_correct_data_v1,
+-	.irqpending_quirk = 1,
+-	.needs_ip = 0,
+-	.regs_offset = 0xe00,
+-	.spare0_offset = 0x800,
+-	.spare_len = 16,
+-	.eccbytes = 3,
+-	.eccsize = 1,
+-};
+-
+-/* v1 + !irqpending_quirk: i.MX27, i.MX31 */
+-static const struct mxc_nand_devtype_data imx27_nand_devtype_data = {
+-	.preset = preset_v1,
+-	.send_cmd = send_cmd_v1_v2,
+-	.send_addr = send_addr_v1_v2,
+-	.send_page = send_page_v1,
+-	.send_read_id = send_read_id_v1_v2,
+-	.get_dev_status = get_dev_status_v1_v2,
+-	.check_int = check_int_v1_v2,
+-	.irq_control = irq_control_v1_v2,
+-	.get_ecc_status = get_ecc_status_v1,
+-	.ooblayout = &mxc_v1_ooblayout_ops,
+-	.select_chip = mxc_nand_select_chip_v1_v3,
+-	.correct_data = mxc_nand_correct_data_v1,
+-	.irqpending_quirk = 0,
+-	.needs_ip = 0,
+-	.regs_offset = 0xe00,
+-	.spare0_offset = 0x800,
+-	.axi_offset = 0,
+-	.spare_len = 16,
+-	.eccbytes = 3,
+-	.eccsize = 1,
+-};
+-
+-/* v21: i.MX25, i.MX35 */
+-static const struct mxc_nand_devtype_data imx25_nand_devtype_data = {
+-	.preset = preset_v2,
+-	.send_cmd = send_cmd_v1_v2,
+-	.send_addr = send_addr_v1_v2,
+-	.send_page = send_page_v2,
+-	.send_read_id = send_read_id_v1_v2,
+-	.get_dev_status = get_dev_status_v1_v2,
+-	.check_int = check_int_v1_v2,
+-	.irq_control = irq_control_v1_v2,
+-	.get_ecc_status = get_ecc_status_v2,
+-	.ooblayout = &mxc_v2_ooblayout_ops,
+-	.select_chip = mxc_nand_select_chip_v2,
+-	.correct_data = mxc_nand_correct_data_v2_v3,
+-	.setup_data_interface = mxc_nand_v2_setup_data_interface,
+-	.irqpending_quirk = 0,
+-	.needs_ip = 0,
+-	.regs_offset = 0x1e00,
+-	.spare0_offset = 0x1000,
+-	.axi_offset = 0,
+-	.spare_len = 64,
+-	.eccbytes = 9,
+-	.eccsize = 0,
+-};
+-
+-/* v3.2a: i.MX51 */
+-static const struct mxc_nand_devtype_data imx51_nand_devtype_data = {
+-	.preset = preset_v3,
+-	.send_cmd = send_cmd_v3,
+-	.send_addr = send_addr_v3,
+-	.send_page = send_page_v3,
+-	.send_read_id = send_read_id_v3,
+-	.get_dev_status = get_dev_status_v3,
+-	.check_int = check_int_v3,
+-	.irq_control = irq_control_v3,
+-	.get_ecc_status = get_ecc_status_v3,
+-	.ooblayout = &mxc_v2_ooblayout_ops,
+-	.select_chip = mxc_nand_select_chip_v1_v3,
+-	.correct_data = mxc_nand_correct_data_v2_v3,
+-	.irqpending_quirk = 0,
+-	.needs_ip = 1,
+-	.regs_offset = 0,
+-	.spare0_offset = 0x1000,
+-	.axi_offset = 0x1e00,
+-	.spare_len = 64,
+-	.eccbytes = 0,
+-	.eccsize = 0,
+-	.ppb_shift = 7,
+-};
+-
+-/* v3.2b: i.MX53 */
+-static const struct mxc_nand_devtype_data imx53_nand_devtype_data = {
+-	.preset = preset_v3,
+-	.send_cmd = send_cmd_v3,
+-	.send_addr = send_addr_v3,
+-	.send_page = send_page_v3,
+-	.send_read_id = send_read_id_v3,
+-	.get_dev_status = get_dev_status_v3,
+-	.check_int = check_int_v3,
+-	.irq_control = irq_control_v3,
+-	.get_ecc_status = get_ecc_status_v3,
+-	.ooblayout = &mxc_v2_ooblayout_ops,
+-	.select_chip = mxc_nand_select_chip_v1_v3,
+-	.correct_data = mxc_nand_correct_data_v2_v3,
+-	.irqpending_quirk = 0,
+-	.needs_ip = 1,
+-	.regs_offset = 0,
+-	.spare0_offset = 0x1000,
+-	.axi_offset = 0x1e00,
+-	.spare_len = 64,
+-	.eccbytes = 0,
+-	.eccsize = 0,
+-	.ppb_shift = 8,
+-};
+-
+-static inline int is_imx21_nfc(struct mxc_nand_host *host)
+-{
+-	return host->devtype_data == &imx21_nand_devtype_data;
+-}
+-
+-static inline int is_imx27_nfc(struct mxc_nand_host *host)
+-{
+-	return host->devtype_data == &imx27_nand_devtype_data;
+-}
+-
+-static inline int is_imx25_nfc(struct mxc_nand_host *host)
+-{
+-	return host->devtype_data == &imx25_nand_devtype_data;
+-}
+-
+-static inline int is_imx51_nfc(struct mxc_nand_host *host)
+-{
+-	return host->devtype_data == &imx51_nand_devtype_data;
+-}
+-
+-static inline int is_imx53_nfc(struct mxc_nand_host *host)
+-{
+-	return host->devtype_data == &imx53_nand_devtype_data;
+-}
+-
+-static const struct platform_device_id mxcnd_devtype[] = {
+-	{
+-		.name = "imx21-nand",
+-		.driver_data = (kernel_ulong_t) &imx21_nand_devtype_data,
+-	}, {
+-		.name = "imx27-nand",
+-		.driver_data = (kernel_ulong_t) &imx27_nand_devtype_data,
+-	}, {
+-		.name = "imx25-nand",
+-		.driver_data = (kernel_ulong_t) &imx25_nand_devtype_data,
+-	}, {
+-		.name = "imx51-nand",
+-		.driver_data = (kernel_ulong_t) &imx51_nand_devtype_data,
+-	}, {
+-		.name = "imx53-nand",
+-		.driver_data = (kernel_ulong_t) &imx53_nand_devtype_data,
+-	}, {
+-		/* sentinel */
+-	}
+-};
+-MODULE_DEVICE_TABLE(platform, mxcnd_devtype);
+-
+-#ifdef CONFIG_OF
+-static const struct of_device_id mxcnd_dt_ids[] = {
+-	{
+-		.compatible = "fsl,imx21-nand",
+-		.data = &imx21_nand_devtype_data,
+-	}, {
+-		.compatible = "fsl,imx27-nand",
+-		.data = &imx27_nand_devtype_data,
+-	}, {
+-		.compatible = "fsl,imx25-nand",
+-		.data = &imx25_nand_devtype_data,
+-	}, {
+-		.compatible = "fsl,imx51-nand",
+-		.data = &imx51_nand_devtype_data,
+-	}, {
+-		.compatible = "fsl,imx53-nand",
+-		.data = &imx53_nand_devtype_data,
+-	},
+-	{ /* sentinel */ }
+-};
+-MODULE_DEVICE_TABLE(of, mxcnd_dt_ids);
+-
+-static int __init mxcnd_probe_dt(struct mxc_nand_host *host)
+-{
+-	struct device_node *np = host->dev->of_node;
+-	const struct of_device_id *of_id =
+-		of_match_device(mxcnd_dt_ids, host->dev);
+-
+-	if (!np)
+-		return 1;
+-
+-	host->devtype_data = of_id->data;
+-
+-	return 0;
+-}
+-#else
+-static int __init mxcnd_probe_dt(struct mxc_nand_host *host)
+-{
+-	return 1;
+-}
+-#endif
+-
+-static int mxcnd_probe(struct platform_device *pdev)
+-{
+-	struct nand_chip *this;
+-	struct mtd_info *mtd;
+-	struct mxc_nand_host *host;
+-	struct resource *res;
+-	int err = 0;
+-
+-	/* Allocate memory for MTD device structure and private data */
+-	host = devm_kzalloc(&pdev->dev, sizeof(struct mxc_nand_host),
+-			GFP_KERNEL);
+-	if (!host)
+-		return -ENOMEM;
+-
+-	/* allocate a temporary buffer for the nand_scan_ident() */
+-	host->data_buf = devm_kzalloc(&pdev->dev, PAGE_SIZE, GFP_KERNEL);
+-	if (!host->data_buf)
+-		return -ENOMEM;
+-
+-	host->dev = &pdev->dev;
+-	/* structures must be linked */
+-	this = &host->nand;
+-	mtd = nand_to_mtd(this);
+-	mtd->dev.parent = &pdev->dev;
+-	mtd->name = DRIVER_NAME;
+-
+-	/* 50 us command delay time */
+-	this->chip_delay = 5;
+-
+-	nand_set_controller_data(this, host);
+-	nand_set_flash_node(this, pdev->dev.of_node),
+-	this->dev_ready = mxc_nand_dev_ready;
+-	this->cmdfunc = mxc_nand_command;
+-	this->read_byte = mxc_nand_read_byte;
+-	this->read_word = mxc_nand_read_word;
+-	this->write_buf = mxc_nand_write_buf;
+-	this->read_buf = mxc_nand_read_buf;
+-	this->onfi_set_features = mxc_nand_onfi_set_features;
+-	this->onfi_get_features = mxc_nand_onfi_get_features;
+-
+-	host->clk = devm_clk_get(&pdev->dev, NULL);
+-	if (IS_ERR(host->clk))
+-		return PTR_ERR(host->clk);
+-
+-	err = mxcnd_probe_dt(host);
+-	if (err > 0) {
+-		struct mxc_nand_platform_data *pdata =
+-					dev_get_platdata(&pdev->dev);
+-		if (pdata) {
+-			host->pdata = *pdata;
+-			host->devtype_data = (struct mxc_nand_devtype_data *)
+-						pdev->id_entry->driver_data;
+-		} else {
+-			err = -ENODEV;
+-		}
+-	}
+-	if (err < 0)
+-		return err;
+-
+-	this->setup_data_interface = host->devtype_data->setup_data_interface;
+-
+-	if (host->devtype_data->needs_ip) {
+-		res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+-		host->regs_ip = devm_ioremap_resource(&pdev->dev, res);
+-		if (IS_ERR(host->regs_ip))
+-			return PTR_ERR(host->regs_ip);
+-
+-		res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+-	} else {
+-		res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+-	}
+-
+-	host->base = devm_ioremap_resource(&pdev->dev, res);
+-	if (IS_ERR(host->base))
+-		return PTR_ERR(host->base);
+-
+-	host->main_area0 = host->base;
+-
+-	if (host->devtype_data->regs_offset)
+-		host->regs = host->base + host->devtype_data->regs_offset;
+-	host->spare0 = host->base + host->devtype_data->spare0_offset;
+-	if (host->devtype_data->axi_offset)
+-		host->regs_axi = host->base + host->devtype_data->axi_offset;
+-
+-	this->ecc.bytes = host->devtype_data->eccbytes;
+-	host->eccsize = host->devtype_data->eccsize;
+-
+-	this->select_chip = host->devtype_data->select_chip;
+-	this->ecc.size = 512;
+-	mtd_set_ooblayout(mtd, host->devtype_data->ooblayout);
+-
+-	if (host->pdata.hw_ecc) {
+-		this->ecc.mode = NAND_ECC_HW;
+-	} else {
+-		this->ecc.mode = NAND_ECC_SOFT;
+-		this->ecc.algo = NAND_ECC_HAMMING;
+-	}
+-
+-	/* NAND bus width determines access functions used by upper layer */
+-	if (host->pdata.width == 2)
+-		this->options |= NAND_BUSWIDTH_16;
+-
+-	/* update flash based bbt */
+-	if (host->pdata.flash_bbt)
+-		this->bbt_options |= NAND_BBT_USE_FLASH;
+-
+-	init_completion(&host->op_completion);
+-
+-	host->irq = platform_get_irq(pdev, 0);
+-	if (host->irq < 0)
+-		return host->irq;
+-
+-	/*
+-	 * Use host->devtype_data->irq_control() here instead of irq_control()
+-	 * because we must not disable_irq_nosync without having requested the
+-	 * irq.
+-	 */
+-	host->devtype_data->irq_control(host, 0);
+-
+-	err = devm_request_irq(&pdev->dev, host->irq, mxc_nfc_irq,
+-			0, DRIVER_NAME, host);
+-	if (err)
+-		return err;
+-
+-	err = clk_prepare_enable(host->clk);
+-	if (err)
+-		return err;
+-	host->clk_act = 1;
+-
+-	/*
+-	 * Now that we "own" the interrupt make sure the interrupt mask bit is
+-	 * cleared on i.MX21. Otherwise we can't read the interrupt status bit
+-	 * on this machine.
+-	 */
+-	if (host->devtype_data->irqpending_quirk) {
+-		disable_irq_nosync(host->irq);
+-		host->devtype_data->irq_control(host, 1);
+-	}
+-
+-	/* first scan to find the device and get the page size */
+-	err = nand_scan_ident(mtd, is_imx25_nfc(host) ? 4 : 1, NULL);
+-	if (err)
+-		goto escan;
+-
+-	switch (this->ecc.mode) {
+-	case NAND_ECC_HW:
+-		this->ecc.calculate = mxc_nand_calculate_ecc;
+-		this->ecc.hwctl = mxc_nand_enable_hwecc;
+-		this->ecc.correct = host->devtype_data->correct_data;
+-		break;
+-
+-	case NAND_ECC_SOFT:
+-		break;
+-
+-	default:
+-		err = -EINVAL;
+-		goto escan;
+-	}
+-
+-	if (this->bbt_options & NAND_BBT_USE_FLASH) {
+-		this->bbt_td = &bbt_main_descr;
+-		this->bbt_md = &bbt_mirror_descr;
+-	}
+-
+-	/* allocate the right size buffer now */
+-	devm_kfree(&pdev->dev, (void *)host->data_buf);
+-	host->data_buf = devm_kzalloc(&pdev->dev, mtd->writesize + mtd->oobsize,
+-					GFP_KERNEL);
+-	if (!host->data_buf) {
+-		err = -ENOMEM;
+-		goto escan;
+-	}
+-
+-	/* Call preset again, with correct writesize this time */
+-	host->devtype_data->preset(mtd);
+-
+-	if (!this->ecc.bytes) {
+-		if (host->eccsize == 8)
+-			this->ecc.bytes = 18;
+-		else if (host->eccsize == 4)
+-			this->ecc.bytes = 9;
+-	}
+-
+-	/*
+-	 * Experimentation shows that i.MX NFC can only handle up to 218 oob
+-	 * bytes. Limit used_oobsize to 218 so as to not confuse copy_spare()
+-	 * into copying invalid data to/from the spare IO buffer, as this
+-	 * might cause ECC data corruption when doing sub-page write to a
+-	 * partially written page.
+-	 */
+-	host->used_oobsize = min(mtd->oobsize, 218U);
+-
+-	if (this->ecc.mode == NAND_ECC_HW) {
+-		if (is_imx21_nfc(host) || is_imx27_nfc(host))
+-			this->ecc.strength = 1;
+-		else
+-			this->ecc.strength = (host->eccsize == 4) ? 4 : 8;
+-	}
+-
+-	/* second phase scan */
+-	err = nand_scan_tail(mtd);
+-	if (err)
+-		goto escan;
+-
+-	/* Register the partitions */
+-	mtd_device_parse_register(mtd, part_probes,
+-			NULL,
+-			host->pdata.parts,
+-			host->pdata.nr_parts);
+-
+-	platform_set_drvdata(pdev, host);
+-
+-	return 0;
+-
+-escan:
+-	if (host->clk_act)
+-		clk_disable_unprepare(host->clk);
+-
+-	return err;
+-}
+-
+-static int mxcnd_remove(struct platform_device *pdev)
+-{
+-	struct mxc_nand_host *host = platform_get_drvdata(pdev);
+-
+-	nand_release(nand_to_mtd(&host->nand));
+-	if (host->clk_act)
+-		clk_disable_unprepare(host->clk);
+-
+-	return 0;
+-}
+-
+-static struct platform_driver mxcnd_driver = {
+-	.driver = {
+-		   .name = DRIVER_NAME,
+-		   .of_match_table = of_match_ptr(mxcnd_dt_ids),
+-	},
+-	.id_table = mxcnd_devtype,
+-	.probe = mxcnd_probe,
+-	.remove = mxcnd_remove,
+-};
+-module_platform_driver(mxcnd_driver);
+-
+-MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+-MODULE_DESCRIPTION("MXC NAND MTD driver");
+-MODULE_LICENSE("GPL");
+diff --git a/drivers/mtd/nand/nand_amd.c b/drivers/mtd/nand/nand_amd.c
+deleted file mode 100644
+index 22f060f..0000000
+--- a/drivers/mtd/nand/nand_amd.c
++++ /dev/null
+@@ -1,51 +0,0 @@
+-/*
+- * Copyright (C) 2017 Free Electrons
+- * Copyright (C) 2017 NextThing Co
+- *
+- * Author: Boris Brezillon <boris.brezillon@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 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/mtd/rawnand.h>
+-
+-static void amd_nand_decode_id(struct nand_chip *chip)
+-{
+-	struct mtd_info *mtd = nand_to_mtd(chip);
+-
+-	nand_decode_ext_id(chip);
+-
+-	/*
+-	 * Check for Spansion/AMD ID + repeating 5th, 6th byte since
+-	 * some Spansion chips have erasesize that conflicts with size
+-	 * listed in nand_ids table.
+-	 * Data sheet (5 byte ID): Spansion S30ML-P ORNAND (p.39)
+-	 */
+-	if (chip->id.data[4] != 0x00 && chip->id.data[5] == 0x00 &&
+-	    chip->id.data[6] == 0x00 && chip->id.data[7] == 0x00 &&
+-	    mtd->writesize == 512) {
+-		mtd->erasesize = 128 * 1024;
+-		mtd->erasesize <<= ((chip->id.data[3] & 0x03) << 1);
+-	}
+-}
+-
+-static int amd_nand_init(struct nand_chip *chip)
+-{
+-	if (nand_is_slc(chip))
+-		chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
+-
+-	return 0;
+-}
+-
+-const struct nand_manufacturer_ops amd_nand_manuf_ops = {
+-	.detect = amd_nand_decode_id,
+-	.init = amd_nand_init,
+-};
+diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
+deleted file mode 100644
+index 4495861..0000000
+--- a/drivers/mtd/nand/nand_base.c
++++ /dev/null
+@@ -1,4997 +0,0 @@
+-/*
+- *  Overview:
+- *   This is the generic MTD driver for NAND flash devices. It should be
+- *   capable of working with almost all NAND chips currently available.
+- *
+- *	Additional technical information is available on
+- *	http://www.linux-mtd.infradead.org/doc/nand.html
+- *
+- *  Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
+- *		  2002-2006 Thomas Gleixner (tglx@linutronix.de)
+- *
+- *  Credits:
+- *	David Woodhouse for adding multichip support
+- *
+- *	Aleph One Ltd. and Toby Churchill Ltd. for supporting the
+- *	rework for 2K page size chips
+- *
+- *  TODO:
+- *	Enable cached programming for 2k page size chips
+- *	Check, if mtd->ecctype should be set to MTD_ECC_HW
+- *	if we have HW ECC support.
+- *	BBT table is not serialized, has to be fixed
+- *
+- * 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.
+- *
+- */
+-
+-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+-
+-#include <linux/module.h>
+-#include <linux/delay.h>
+-#include <linux/errno.h>
+-#include <linux/err.h>
+-#include <linux/sched.h>
+-#include <linux/slab.h>
+-#include <linux/mm.h>
+-#include <linux/nmi.h>
+-#include <linux/types.h>
+-#include <linux/mtd/mtd.h>
+-#include <linux/mtd/rawnand.h>
+-#include <linux/mtd/nand_ecc.h>
+-#include <linux/mtd/nand_bch.h>
+-#include <linux/interrupt.h>
+-#include <linux/bitops.h>
+-#include <linux/io.h>
+-#include <linux/mtd/partitions.h>
+-#include <linux/of.h>
+-
+-static int nand_get_device(struct mtd_info *mtd, int new_state);
+-
+-static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
+-			     struct mtd_oob_ops *ops);
+-
+-/* Define default oob placement schemes for large and small page devices */
+-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_ecc_ctrl *ecc = &chip->ecc;
+-
+-	if (section > 1)
+-		return -ERANGE;
+-
+-	if (!section) {
+-		oobregion->offset = 0;
+-		if (mtd->oobsize == 16)
+-			oobregion->length = 4;
+-		else
+-			oobregion->length = 3;
+-	} else {
+-		if (mtd->oobsize == 8)
+-			return -ERANGE;
+-
+-		oobregion->offset = 6;
+-		oobregion->length = ecc->total - 4;
+-	}
+-
+-	return 0;
+-}
+-
+-static int nand_ooblayout_free_sp(struct mtd_info *mtd, int section,
+-				  struct mtd_oob_region *oobregion)
+-{
+-	if (section > 1)
+-		return -ERANGE;
+-
+-	if (mtd->oobsize == 16) {
+-		if (section)
+-			return -ERANGE;
+-
+-		oobregion->length = 8;
+-		oobregion->offset = 8;
+-	} else {
+-		oobregion->length = 2;
+-		if (!section)
+-			oobregion->offset = 3;
+-		else
+-			oobregion->offset = 6;
+-	}
+-
+-	return 0;
+-}
+-
+-const struct mtd_ooblayout_ops nand_ooblayout_sp_ops = {
+-	.ecc = nand_ooblayout_ecc_sp,
+-	.free = nand_ooblayout_free_sp,
+-};
+-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_ecc_ctrl *ecc = &chip->ecc;
+-
+-	if (section)
+-		return -ERANGE;
+-
+-	oobregion->length = ecc->total;
+-	oobregion->offset = mtd->oobsize - oobregion->length;
+-
+-	return 0;
+-}
+-
+-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_ecc_ctrl *ecc = &chip->ecc;
+-
+-	if (section)
+-		return -ERANGE;
+-
+-	oobregion->length = mtd->oobsize - ecc->total - 2;
+-	oobregion->offset = 2;
+-
+-	return 0;
+-}
+-
+-const struct mtd_ooblayout_ops nand_ooblayout_lp_ops = {
+-	.ecc = nand_ooblayout_ecc_lp,
+-	.free = nand_ooblayout_free_lp,
+-};
+-EXPORT_SYMBOL_GPL(nand_ooblayout_lp_ops);
+-
+-/*
+- * Support the old "large page" layout used for 1-bit Hamming ECC where ECC
+- * are placed at a fixed offset.
+- */
+-static int nand_ooblayout_ecc_lp_hamming(struct mtd_info *mtd, int section,
+-					 struct mtd_oob_region *oobregion)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct nand_ecc_ctrl *ecc = &chip->ecc;
+-
+-	if (section)
+-		return -ERANGE;
+-
+-	switch (mtd->oobsize) {
+-	case 64:
+-		oobregion->offset = 40;
+-		break;
+-	case 128:
+-		oobregion->offset = 80;
+-		break;
+-	default:
+-		return -EINVAL;
+-	}
+-
+-	oobregion->length = ecc->total;
+-	if (oobregion->offset + oobregion->length > mtd->oobsize)
+-		return -ERANGE;
+-
+-	return 0;
+-}
+-
+-static int nand_ooblayout_free_lp_hamming(struct mtd_info *mtd, int section,
+-					  struct mtd_oob_region *oobregion)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct nand_ecc_ctrl *ecc = &chip->ecc;
+-	int ecc_offset = 0;
+-
+-	if (section < 0 || section > 1)
+-		return -ERANGE;
+-
+-	switch (mtd->oobsize) {
+-	case 64:
+-		ecc_offset = 40;
+-		break;
+-	case 128:
+-		ecc_offset = 80;
+-		break;
+-	default:
+-		return -EINVAL;
+-	}
+-
+-	if (section == 0) {
+-		oobregion->offset = 2;
+-		oobregion->length = ecc_offset - 2;
+-	} else {
+-		oobregion->offset = ecc_offset + ecc->total;
+-		oobregion->length = mtd->oobsize - oobregion->offset;
+-	}
+-
+-	return 0;
+-}
+-
+-static const struct mtd_ooblayout_ops nand_ooblayout_lp_hamming_ops = {
+-	.ecc = nand_ooblayout_ecc_lp_hamming,
+-	.free = nand_ooblayout_free_lp_hamming,
+-};
+-
+-static int check_offs_len(struct mtd_info *mtd,
+-					loff_t ofs, uint64_t len)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	int ret = 0;
+-
+-	/* Start address must align on block boundary */
+-	if (ofs & ((1ULL << chip->phys_erase_shift) - 1)) {
+-		pr_debug("%s: unaligned address\n", __func__);
+-		ret = -EINVAL;
+-	}
+-
+-	/* Length must align on block boundary */
+-	if (len & ((1ULL << chip->phys_erase_shift) - 1)) {
+-		pr_debug("%s: length not block aligned\n", __func__);
+-		ret = -EINVAL;
+-	}
+-
+-	return ret;
+-}
+-
+-/**
+- * nand_release_device - [GENERIC] release chip
+- * @mtd: MTD device structure
+- *
+- * Release chip lock and wake up anyone waiting on the device.
+- */
+-static void nand_release_device(struct mtd_info *mtd)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-
+-	/* Release the controller and the chip */
+-	spin_lock(&chip->controller->lock);
+-	chip->controller->active = NULL;
+-	chip->state = FL_READY;
+-	wake_up(&chip->controller->wq);
+-	spin_unlock(&chip->controller->lock);
+-}
+-
+-/**
+- * nand_read_byte - [DEFAULT] read one byte from the chip
+- * @mtd: MTD device structure
+- *
+- * Default read function for 8bit buswidth
+- */
+-static uint8_t nand_read_byte(struct mtd_info *mtd)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	return readb(chip->IO_ADDR_R);
+-}
+-
+-/**
+- * nand_read_byte16 - [DEFAULT] read one byte endianness aware from the chip
+- * @mtd: MTD device structure
+- *
+- * Default read function for 16bit buswidth with endianness conversion.
+- *
+- */
+-static uint8_t nand_read_byte16(struct mtd_info *mtd)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	return (uint8_t) cpu_to_le16(readw(chip->IO_ADDR_R));
+-}
+-
+-/**
+- * nand_read_word - [DEFAULT] read one word from the chip
+- * @mtd: MTD device structure
+- *
+- * Default read function for 16bit buswidth without endianness conversion.
+- */
+-static u16 nand_read_word(struct mtd_info *mtd)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	return readw(chip->IO_ADDR_R);
+-}
+-
+-/**
+- * nand_select_chip - [DEFAULT] control CE line
+- * @mtd: MTD device structure
+- * @chipnr: chipnumber to select, -1 for deselect
+- *
+- * Default select function for 1 chip devices.
+- */
+-static void nand_select_chip(struct mtd_info *mtd, int chipnr)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-
+-	switch (chipnr) {
+-	case -1:
+-		chip->cmd_ctrl(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE);
+-		break;
+-	case 0:
+-		break;
+-
+-	default:
+-		BUG();
+-	}
+-}
+-
+-/**
+- * nand_write_byte - [DEFAULT] write single byte to chip
+- * @mtd: MTD device structure
+- * @byte: value to write
+- *
+- * Default function to write a byte to I/O[7:0]
+- */
+-static void nand_write_byte(struct mtd_info *mtd, uint8_t byte)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-
+-	chip->write_buf(mtd, &byte, 1);
+-}
+-
+-/**
+- * nand_write_byte16 - [DEFAULT] write single byte to a chip with width 16
+- * @mtd: MTD device structure
+- * @byte: value to write
+- *
+- * Default function to write a byte to I/O[7:0] on a 16-bit wide chip.
+- */
+-static void nand_write_byte16(struct mtd_info *mtd, uint8_t byte)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	uint16_t word = byte;
+-
+-	/*
+-	 * It's not entirely clear what should happen to I/O[15:8] when writing
+-	 * a byte. The ONFi spec (Revision 3.1; 2012-09-19, Section 2.16) reads:
+-	 *
+-	 *    When the host supports a 16-bit bus width, only data is
+-	 *    transferred at the 16-bit width. All address and command line
+-	 *    transfers shall use only the lower 8-bits of the data bus. During
+-	 *    command transfers, the host may place any value on the upper
+-	 *    8-bits of the data bus. During address transfers, the host shall
+-	 *    set the upper 8-bits of the data bus to 00h.
+-	 *
+-	 * One user of the write_byte callback is nand_onfi_set_features. The
+-	 * four parameters are specified to be written to I/O[7:0], but this is
+-	 * neither an address nor a command transfer. Let's assume a 0 on the
+-	 * upper I/O lines is OK.
+-	 */
+-	chip->write_buf(mtd, (uint8_t *)&word, 2);
+-}
+-
+-/**
+- * nand_write_buf - [DEFAULT] write buffer to chip
+- * @mtd: MTD device structure
+- * @buf: data buffer
+- * @len: number of bytes to write
+- *
+- * Default write function for 8bit buswidth.
+- */
+-static void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-
+-	iowrite8_rep(chip->IO_ADDR_W, buf, len);
+-}
+-
+-/**
+- * nand_read_buf - [DEFAULT] read chip data into buffer
+- * @mtd: MTD device structure
+- * @buf: buffer to store date
+- * @len: number of bytes to read
+- *
+- * Default read function for 8bit buswidth.
+- */
+-static void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-
+-	ioread8_rep(chip->IO_ADDR_R, buf, len);
+-}
+-
+-/**
+- * nand_write_buf16 - [DEFAULT] write buffer to chip
+- * @mtd: MTD device structure
+- * @buf: data buffer
+- * @len: number of bytes to write
+- *
+- * Default write function for 16bit buswidth.
+- */
+-static void nand_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	u16 *p = (u16 *) buf;
+-
+-	iowrite16_rep(chip->IO_ADDR_W, p, len >> 1);
+-}
+-
+-/**
+- * nand_read_buf16 - [DEFAULT] read chip data into buffer
+- * @mtd: MTD device structure
+- * @buf: buffer to store date
+- * @len: number of bytes to read
+- *
+- * Default read function for 16bit buswidth.
+- */
+-static void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	u16 *p = (u16 *) buf;
+-
+-	ioread16_rep(chip->IO_ADDR_R, p, len >> 1);
+-}
+-
+-/**
+- * nand_block_bad - [DEFAULT] Read bad block marker from the chip
+- * @mtd: MTD device structure
+- * @ofs: offset from device start
+- *
+- * Check, if the block is bad.
+- */
+-static int nand_block_bad(struct mtd_info *mtd, loff_t ofs)
+-{
+-	int page, page_end, res;
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	u8 bad;
+-
+-	if (chip->bbt_options & NAND_BBT_SCANLASTPAGE)
+-		ofs += mtd->erasesize - mtd->writesize;
+-
+-	page = (int)(ofs >> chip->page_shift) & chip->pagemask;
+-	page_end = page + (chip->bbt_options & NAND_BBT_SCAN2NDPAGE ? 2 : 1);
+-
+-	for (; page < page_end; page++) {
+-		res = chip->ecc.read_oob(mtd, chip, page);
+-		if (res)
+-			return res;
+-
+-		bad = chip->oob_poi[chip->badblockpos];
+-
+-		if (likely(chip->badblockbits == 8))
+-			res = bad != 0xFF;
+-		else
+-			res = hweight8(bad) < chip->badblockbits;
+-		if (res)
+-			return res;
+-	}
+-
+-	return 0;
+-}
+-
+-/**
+- * nand_default_block_markbad - [DEFAULT] mark a block bad via bad block marker
+- * @mtd: MTD device structure
+- * @ofs: offset from device start
+- *
+- * This is the default implementation, which can be overridden by a hardware
+- * specific driver. It provides the details for writing a bad block marker to a
+- * block.
+- */
+-static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct mtd_oob_ops ops;
+-	uint8_t buf[2] = { 0, 0 };
+-	int ret = 0, res, i = 0;
+-
+-	memset(&ops, 0, sizeof(ops));
+-	ops.oobbuf = buf;
+-	ops.ooboffs = chip->badblockpos;
+-	if (chip->options & NAND_BUSWIDTH_16) {
+-		ops.ooboffs &= ~0x01;
+-		ops.len = ops.ooblen = 2;
+-	} else {
+-		ops.len = ops.ooblen = 1;
+-	}
+-	ops.mode = MTD_OPS_PLACE_OOB;
+-
+-	/* Write to first/last page(s) if necessary */
+-	if (chip->bbt_options & NAND_BBT_SCANLASTPAGE)
+-		ofs += mtd->erasesize - mtd->writesize;
+-	do {
+-		res = nand_do_write_oob(mtd, ofs, &ops);
+-		if (!ret)
+-			ret = res;
+-
+-		i++;
+-		ofs += mtd->writesize;
+-	} while ((chip->bbt_options & NAND_BBT_SCAN2NDPAGE) && i < 2);
+-
+-	return ret;
+-}
+-
+-/**
+- * nand_block_markbad_lowlevel - mark a block bad
+- * @mtd: MTD device structure
+- * @ofs: offset from device start
+- *
+- * This function performs the generic NAND bad block marking steps (i.e., bad
+- * block table(s) and/or marker(s)). We only allow the hardware driver to
+- * specify how to write bad block markers to OOB (chip->block_markbad).
+- *
+- * We try operations in the following order:
+- *
+- *  (1) erase the affected block, to allow OOB marker to be written cleanly
+- *  (2) write bad block marker to OOB area of affected block (unless flag
+- *      NAND_BBT_NO_OOB_BBM is present)
+- *  (3) update the BBT
+- *
+- * Note that we retain the first error encountered in (2) or (3), finish the
+- * procedures, and dump the error in the end.
+-*/
+-static int nand_block_markbad_lowlevel(struct mtd_info *mtd, loff_t ofs)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	int res, ret = 0;
+-
+-	if (!(chip->bbt_options & NAND_BBT_NO_OOB_BBM)) {
+-		struct erase_info einfo;
+-
+-		/* Attempt erase before marking OOB */
+-		memset(&einfo, 0, sizeof(einfo));
+-		einfo.mtd = mtd;
+-		einfo.addr = ofs;
+-		einfo.len = 1ULL << chip->phys_erase_shift;
+-		nand_erase_nand(mtd, &einfo, 0);
+-
+-		/* Write bad block marker to OOB */
+-		nand_get_device(mtd, FL_WRITING);
+-		ret = chip->block_markbad(mtd, ofs);
+-		nand_release_device(mtd);
+-	}
+-
+-	/* Mark block bad in BBT */
+-	if (chip->bbt) {
+-		res = nand_markbad_bbt(mtd, ofs);
+-		if (!ret)
+-			ret = res;
+-	}
+-
+-	if (!ret)
+-		mtd->ecc_stats.badblocks++;
+-
+-	return ret;
+-}
+-
+-/**
+- * nand_check_wp - [GENERIC] check if the chip is write protected
+- * @mtd: MTD device structure
+- *
+- * Check, if the device is write protected. The function expects, that the
+- * device is already selected.
+- */
+-static int nand_check_wp(struct mtd_info *mtd)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-
+-	/* Broken xD cards report WP despite being writable */
+-	if (chip->options & NAND_BROKEN_XD)
+-		return 0;
+-
+-	/* Check the WP bit */
+-	chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
+-	return (chip->read_byte(mtd) & NAND_STATUS_WP) ? 0 : 1;
+-}
+-
+-/**
+- * nand_block_isreserved - [GENERIC] Check if a block is marked reserved.
+- * @mtd: MTD device structure
+- * @ofs: offset from device start
+- *
+- * Check if the block is marked as reserved.
+- */
+-static int nand_block_isreserved(struct mtd_info *mtd, loff_t ofs)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-
+-	if (!chip->bbt)
+-		return 0;
+-	/* Return info from the table */
+-	return nand_isreserved_bbt(mtd, ofs);
+-}
+-
+-/**
+- * nand_block_checkbad - [GENERIC] Check if a block is marked bad
+- * @mtd: MTD device structure
+- * @ofs: offset from device start
+- * @allowbbt: 1, if its allowed to access the bbt area
+- *
+- * Check, if the block is bad. Either by reading the bad block table or
+- * calling of the scan function.
+- */
+-static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int allowbbt)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-
+-	if (!chip->bbt)
+-		return chip->block_bad(mtd, ofs);
+-
+-	/* Return info from the table */
+-	return nand_isbad_bbt(mtd, ofs, allowbbt);
+-}
+-
+-/**
+- * panic_nand_wait_ready - [GENERIC] Wait for the ready pin after commands.
+- * @mtd: MTD device structure
+- * @timeo: Timeout
+- *
+- * Helper function for nand_wait_ready used when needing to wait in interrupt
+- * context.
+- */
+-static void panic_nand_wait_ready(struct mtd_info *mtd, unsigned long timeo)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	int i;
+-
+-	/* Wait for the device to get ready */
+-	for (i = 0; i < timeo; i++) {
+-		if (chip->dev_ready(mtd))
+-			break;
+-		touch_softlockup_watchdog();
+-		mdelay(1);
+-	}
+-}
+-
+-/**
+- * nand_wait_ready - [GENERIC] Wait for the ready pin after commands.
+- * @mtd: MTD device structure
+- *
+- * Wait for the ready pin after a command, and warn if a timeout occurs.
+- */
+-void nand_wait_ready(struct mtd_info *mtd)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	unsigned long timeo = 400;
+-
+-	if (in_interrupt() || oops_in_progress)
+-		return panic_nand_wait_ready(mtd, timeo);
+-
+-	/* Wait until command is processed or timeout occurs */
+-	timeo = jiffies + msecs_to_jiffies(timeo);
+-	do {
+-		if (chip->dev_ready(mtd))
+-			return;
+-		cond_resched();
+-	} while (time_before(jiffies, timeo));
+-
+-	if (!chip->dev_ready(mtd))
+-		pr_warn_ratelimited("timeout while waiting for chip to become ready\n");
+-}
+-EXPORT_SYMBOL_GPL(nand_wait_ready);
+-
+-/**
+- * nand_wait_status_ready - [GENERIC] Wait for the ready status after commands.
+- * @mtd: MTD device structure
+- * @timeo: Timeout in ms
+- *
+- * Wait for status ready (i.e. command done) or timeout.
+- */
+-static void nand_wait_status_ready(struct mtd_info *mtd, unsigned long timeo)
+-{
+-	register struct nand_chip *chip = mtd_to_nand(mtd);
+-
+-	timeo = jiffies + msecs_to_jiffies(timeo);
+-	do {
+-		if ((chip->read_byte(mtd) & NAND_STATUS_READY))
+-			break;
+-		touch_softlockup_watchdog();
+-	} while (time_before(jiffies, timeo));
+-};
+-
+-/**
+- * nand_command - [DEFAULT] Send command to NAND device
+- * @mtd: MTD device structure
+- * @command: the command to be sent
+- * @column: the column address for this command, -1 if none
+- * @page_addr: the page address for this command, -1 if none
+- *
+- * Send command to NAND device. This function is used for small page devices
+- * (512 Bytes per page).
+- */
+-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);
+-	int ctrl = NAND_CTRL_CLE | NAND_CTRL_CHANGE;
+-
+-	/* Write out the command to the device */
+-	if (command == NAND_CMD_SEQIN) {
+-		int readcmd;
+-
+-		if (column >= mtd->writesize) {
+-			/* OOB area */
+-			column -= mtd->writesize;
+-			readcmd = NAND_CMD_READOOB;
+-		} else if (column < 256) {
+-			/* First 256 bytes --> READ0 */
+-			readcmd = NAND_CMD_READ0;
+-		} else {
+-			column -= 256;
+-			readcmd = NAND_CMD_READ1;
+-		}
+-		chip->cmd_ctrl(mtd, readcmd, ctrl);
+-		ctrl &= ~NAND_CTRL_CHANGE;
+-	}
+-	chip->cmd_ctrl(mtd, command, ctrl);
+-
+-	/* Address cycle, when necessary */
+-	ctrl = NAND_CTRL_ALE | NAND_CTRL_CHANGE;
+-	/* Serially input address */
+-	if (column != -1) {
+-		/* Adjust columns for 16 bit buswidth */
+-		if (chip->options & NAND_BUSWIDTH_16 &&
+-				!nand_opcode_8bits(command))
+-			column >>= 1;
+-		chip->cmd_ctrl(mtd, column, ctrl);
+-		ctrl &= ~NAND_CTRL_CHANGE;
+-	}
+-	if (page_addr != -1) {
+-		chip->cmd_ctrl(mtd, page_addr, ctrl);
+-		ctrl &= ~NAND_CTRL_CHANGE;
+-		chip->cmd_ctrl(mtd, page_addr >> 8, ctrl);
+-		/* One more address cycle for devices > 32MiB */
+-		if (chip->chipsize > (32 << 20))
+-			chip->cmd_ctrl(mtd, page_addr >> 16, ctrl);
+-	}
+-	chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
+-
+-	/*
+-	 * Program and erase have their own busy handlers status and sequential
+-	 * in needs no delay
+-	 */
+-	switch (command) {
+-
+-	case NAND_CMD_PAGEPROG:
+-	case NAND_CMD_ERASE1:
+-	case NAND_CMD_ERASE2:
+-	case NAND_CMD_SEQIN:
+-	case NAND_CMD_STATUS:
+-	case NAND_CMD_READID:
+-	case NAND_CMD_SET_FEATURES:
+-		return;
+-
+-	case NAND_CMD_RESET:
+-		if (chip->dev_ready)
+-			break;
+-		udelay(chip->chip_delay);
+-		chip->cmd_ctrl(mtd, NAND_CMD_STATUS,
+-			       NAND_CTRL_CLE | NAND_CTRL_CHANGE);
+-		chip->cmd_ctrl(mtd,
+-			       NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
+-		/* EZ-NAND can take upto 250ms as per ONFi v4.0 */
+-		nand_wait_status_ready(mtd, 250);
+-		return;
+-
+-		/* This applies to read commands */
+-	case NAND_CMD_READ0:
+-		/*
+-		 * READ0 is sometimes used to exit GET STATUS mode. When this
+-		 * is the case no address cycles are requested, and we can use
+-		 * this information to detect that we should not wait for the
+-		 * device to be ready.
+-		 */
+-		if (column == -1 && page_addr == -1)
+-			return;
+-
+-	default:
+-		/*
+-		 * If we don't have access to the busy pin, we apply the given
+-		 * command delay
+-		 */
+-		if (!chip->dev_ready) {
+-			udelay(chip->chip_delay);
+-			return;
+-		}
+-	}
+-	/*
+-	 * Apply this short delay always to ensure that we do wait tWB in
+-	 * any case on any machine.
+-	 */
+-	ndelay(100);
+-
+-	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
+- * @command: the command to be sent
+- * @column: the column address for this command, -1 if none
+- * @page_addr: the page address for this command, -1 if none
+- *
+- * Send command to NAND device. This is the version for the new large page
+- * devices. We don't have the separate regions as we have in the small page
+- * devices. We must emulate NAND_CMD_READOOB to keep the code compatible.
+- */
+-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);
+-
+-	/* Emulate NAND_CMD_READOOB */
+-	if (command == NAND_CMD_READOOB) {
+-		column += mtd->writesize;
+-		command = NAND_CMD_READ0;
+-	}
+-
+-	/* Command latch cycle */
+-	chip->cmd_ctrl(mtd, command, NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
+-
+-	if (column != -1 || page_addr != -1) {
+-		int ctrl = NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE;
+-
+-		/* Serially input address */
+-		if (column != -1) {
+-			/* Adjust columns for 16 bit buswidth */
+-			if (chip->options & NAND_BUSWIDTH_16 &&
+-					!nand_opcode_8bits(command))
+-				column >>= 1;
+-			chip->cmd_ctrl(mtd, column, ctrl);
+-			ctrl &= ~NAND_CTRL_CHANGE;
+-
+-			/* Only output a single addr cycle for 8bits opcodes. */
+-			if (!nand_opcode_8bits(command))
+-				chip->cmd_ctrl(mtd, column >> 8, ctrl);
+-		}
+-		if (page_addr != -1) {
+-			chip->cmd_ctrl(mtd, page_addr, ctrl);
+-			chip->cmd_ctrl(mtd, page_addr >> 8,
+-				       NAND_NCE | NAND_ALE);
+-			/* One more address cycle for devices > 128MiB */
+-			if (chip->chipsize > (128 << 20))
+-				chip->cmd_ctrl(mtd, page_addr >> 16,
+-					       NAND_NCE | NAND_ALE);
+-		}
+-	}
+-	chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
+-
+-	/*
+-	 * Program and erase have their own busy handlers status, sequential
+-	 * in and status need no delay.
+-	 */
+-	switch (command) {
+-
+-	case NAND_CMD_CACHEDPROG:
+-	case NAND_CMD_PAGEPROG:
+-	case NAND_CMD_ERASE1:
+-	case NAND_CMD_ERASE2:
+-	case NAND_CMD_SEQIN:
+-	case NAND_CMD_STATUS:
+-	case NAND_CMD_READID:
+-	case NAND_CMD_SET_FEATURES:
+-		return;
+-
+-	case NAND_CMD_RNDIN:
+-		nand_ccs_delay(chip);
+-		return;
+-
+-	case NAND_CMD_RESET:
+-		if (chip->dev_ready)
+-			break;
+-		udelay(chip->chip_delay);
+-		chip->cmd_ctrl(mtd, NAND_CMD_STATUS,
+-			       NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
+-		chip->cmd_ctrl(mtd, NAND_CMD_NONE,
+-			       NAND_NCE | NAND_CTRL_CHANGE);
+-		/* EZ-NAND can take upto 250ms as per ONFi v4.0 */
+-		nand_wait_status_ready(mtd, 250);
+-		return;
+-
+-	case NAND_CMD_RNDOUT:
+-		/* No ready / busy check necessary */
+-		chip->cmd_ctrl(mtd, NAND_CMD_RNDOUTSTART,
+-			       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:
+-		/*
+-		 * READ0 is sometimes used to exit GET STATUS mode. When this
+-		 * is the case no address cycles are requested, and we can use
+-		 * this information to detect that READSTART should not be
+-		 * issued.
+-		 */
+-		if (column == -1 && page_addr == -1)
+-			return;
+-
+-		chip->cmd_ctrl(mtd, NAND_CMD_READSTART,
+-			       NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
+-		chip->cmd_ctrl(mtd, NAND_CMD_NONE,
+-			       NAND_NCE | NAND_CTRL_CHANGE);
+-
+-		/* This applies to read commands */
+-	default:
+-		/*
+-		 * If we don't have access to the busy pin, we apply the given
+-		 * command delay.
+-		 */
+-		if (!chip->dev_ready) {
+-			udelay(chip->chip_delay);
+-			return;
+-		}
+-	}
+-
+-	/*
+-	 * Apply this short delay always to ensure that we do wait tWB in
+-	 * any case on any machine.
+-	 */
+-	ndelay(100);
+-
+-	nand_wait_ready(mtd);
+-}
+-
+-/**
+- * panic_nand_get_device - [GENERIC] Get chip for selected access
+- * @chip: the nand chip descriptor
+- * @mtd: MTD device structure
+- * @new_state: the state which is requested
+- *
+- * Used when in panic, no locks are taken.
+- */
+-static void panic_nand_get_device(struct nand_chip *chip,
+-		      struct mtd_info *mtd, int new_state)
+-{
+-	/* Hardware controller shared among independent devices */
+-	chip->controller->active = chip;
+-	chip->state = new_state;
+-}
+-
+-/**
+- * nand_get_device - [GENERIC] Get chip for selected access
+- * @mtd: MTD device structure
+- * @new_state: the state which is requested
+- *
+- * Get the device and lock it for exclusive access
+- */
+-static int
+-nand_get_device(struct mtd_info *mtd, int new_state)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	spinlock_t *lock = &chip->controller->lock;
+-	wait_queue_head_t *wq = &chip->controller->wq;
+-	DECLARE_WAITQUEUE(wait, current);
+-retry:
+-	spin_lock(lock);
+-
+-	/* Hardware controller shared among independent devices */
+-	if (!chip->controller->active)
+-		chip->controller->active = chip;
+-
+-	if (chip->controller->active == chip && chip->state == FL_READY) {
+-		chip->state = new_state;
+-		spin_unlock(lock);
+-		return 0;
+-	}
+-	if (new_state == FL_PM_SUSPENDED) {
+-		if (chip->controller->active->state == FL_PM_SUSPENDED) {
+-			chip->state = FL_PM_SUSPENDED;
+-			spin_unlock(lock);
+-			return 0;
+-		}
+-	}
+-	set_current_state(TASK_UNINTERRUPTIBLE);
+-	add_wait_queue(wq, &wait);
+-	spin_unlock(lock);
+-	schedule();
+-	remove_wait_queue(wq, &wait);
+-	goto retry;
+-}
+-
+-/**
+- * panic_nand_wait - [GENERIC] wait until the command is done
+- * @mtd: MTD device structure
+- * @chip: NAND chip structure
+- * @timeo: timeout
+- *
+- * Wait for command done. This is a helper function for nand_wait used when
+- * we are in interrupt context. May happen when in panic and trying to write
+- * an oops through mtdoops.
+- */
+-static void panic_nand_wait(struct mtd_info *mtd, struct nand_chip *chip,
+-			    unsigned long timeo)
+-{
+-	int i;
+-	for (i = 0; i < timeo; i++) {
+-		if (chip->dev_ready) {
+-			if (chip->dev_ready(mtd))
+-				break;
+-		} else {
+-			if (chip->read_byte(mtd) & NAND_STATUS_READY)
+-				break;
+-		}
+-		mdelay(1);
+-	}
+-}
+-
+-/**
+- * nand_wait - [DEFAULT] wait until the command is done
+- * @mtd: MTD device structure
+- * @chip: NAND chip structure
+- *
+- * Wait for command done. This applies to erase and program only.
+- */
+-static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
+-{
+-
+-	int status;
+-	unsigned long timeo = 400;
+-
+-	/*
+-	 * Apply this short delay always to ensure that we do wait tWB in any
+-	 * case on any machine.
+-	 */
+-	ndelay(100);
+-
+-	chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
+-
+-	if (in_interrupt() || oops_in_progress)
+-		panic_nand_wait(mtd, chip, timeo);
+-	else {
+-		timeo = jiffies + msecs_to_jiffies(timeo);
+-		do {
+-			if (chip->dev_ready) {
+-				if (chip->dev_ready(mtd))
+-					break;
+-			} else {
+-				if (chip->read_byte(mtd) & NAND_STATUS_READY)
+-					break;
+-			}
+-			cond_resched();
+-		} while (time_before(jiffies, timeo));
+-	}
+-
+-	status = (int)chip->read_byte(mtd);
+-	/* This can happen if in case of timeout or buggy dev_ready */
+-	WARN_ON(!(status & NAND_STATUS_READY));
+-	return status;
+-}
+-
+-/**
+- * nand_reset_data_interface - Reset data interface and timings
+- * @chip: The NAND chip
+- * @chipnr: Internal die id
+- *
+- * Reset the Data interface and timings to ONFI mode 0.
+- *
+- * Returns 0 for success or negative error code otherwise.
+- */
+-static int nand_reset_data_interface(struct nand_chip *chip, int chipnr)
+-{
+-	struct mtd_info *mtd = nand_to_mtd(chip);
+-	const struct nand_data_interface *conf;
+-	int ret;
+-
+-	if (!chip->setup_data_interface)
+-		return 0;
+-
+-	/*
+-	 * The ONFI specification says:
+-	 * "
+-	 * To transition from NV-DDR or NV-DDR2 to the SDR data
+-	 * interface, the host shall use the Reset (FFh) command
+-	 * using SDR timing mode 0. A device in any timing mode is
+-	 * required to recognize Reset (FFh) command issued in SDR
+-	 * timing mode 0.
+-	 * "
+-	 *
+-	 * Configure the data interface in SDR mode and set the
+-	 * timings to timing mode 0.
+-	 */
+-
+-	conf = nand_get_default_data_interface();
+-	ret = chip->setup_data_interface(mtd, chipnr, conf);
+-	if (ret)
+-		pr_err("Failed to configure data interface to SDR timing mode 0\n");
+-
+-	return ret;
+-}
+-
+-/**
+- * nand_setup_data_interface - Setup the best data interface and timings
+- * @chip: The NAND chip
+- * @chipnr: Internal die id
+- *
+- * Find and configure the best data interface and NAND timings supported by
+- * the chip and the driver.
+- * First tries to retrieve supported timing modes from ONFI information,
+- * and if the NAND chip does not support ONFI, relies on the
+- * ->onfi_timing_mode_default specified in the nand_ids table.
+- *
+- * Returns 0 for success or negative error code otherwise.
+- */
+-static int nand_setup_data_interface(struct nand_chip *chip, int chipnr)
+-{
+-	struct mtd_info *mtd = nand_to_mtd(chip);
+-	int ret;
+-
+-	if (!chip->setup_data_interface || !chip->data_interface)
+-		return 0;
+-
+-	/*
+-	 * Ensure the timing mode has been changed on the chip side
+-	 * before changing timings on the controller side.
+-	 */
+-	if (chip->onfi_version &&
+-	    (le16_to_cpu(chip->onfi_params.opt_cmd) &
+-	     ONFI_OPT_CMD_SET_GET_FEATURES)) {
+-		u8 tmode_param[ONFI_SUBFEATURE_PARAM_LEN] = {
+-			chip->onfi_timing_mode_default,
+-		};
+-
+-		ret = chip->onfi_set_features(mtd, chip,
+-				ONFI_FEATURE_ADDR_TIMING_MODE,
+-				tmode_param);
+-		if (ret)
+-			goto err;
+-	}
+-
+-	ret = chip->setup_data_interface(mtd, chipnr, chip->data_interface);
+-err:
+-	return ret;
+-}
+-
+-/**
+- * nand_init_data_interface - find the best data interface and timings
+- * @chip: The NAND chip
+- *
+- * Find the best data interface and NAND timings supported by the chip
+- * and the driver.
+- * First tries to retrieve supported timing modes from ONFI information,
+- * and if the NAND chip does not support ONFI, relies on the
+- * ->onfi_timing_mode_default specified in the nand_ids table. After this
+- * function nand_chip->data_interface is initialized with the best timing mode
+- * available.
+- *
+- * Returns 0 for success or negative error code otherwise.
+- */
+-static int nand_init_data_interface(struct nand_chip *chip)
+-{
+-	struct mtd_info *mtd = nand_to_mtd(chip);
+-	int modes, mode, ret;
+-
+-	if (!chip->setup_data_interface)
+-		return 0;
+-
+-	/*
+-	 * First try to identify the best timings from ONFI parameters and
+-	 * if the NAND does not support ONFI, fallback to the default ONFI
+-	 * timing mode.
+-	 */
+-	modes = onfi_get_async_timing_mode(chip);
+-	if (modes == ONFI_TIMING_MODE_UNKNOWN) {
+-		if (!chip->onfi_timing_mode_default)
+-			return 0;
+-
+-		modes = GENMASK(chip->onfi_timing_mode_default, 0);
+-	}
+-
+-	chip->data_interface = kzalloc(sizeof(*chip->data_interface),
+-				       GFP_KERNEL);
+-	if (!chip->data_interface)
+-		return -ENOMEM;
+-
+-	for (mode = fls(modes) - 1; mode >= 0; mode--) {
+-		ret = onfi_init_data_interface(chip, chip->data_interface,
+-					       NAND_SDR_IFACE, mode);
+-		if (ret)
+-			continue;
+-
+-		/* Pass -1 to only */
+-		ret = chip->setup_data_interface(mtd,
+-						 NAND_DATA_IFACE_CHECK_ONLY,
+-						 chip->data_interface);
+-		if (!ret) {
+-			chip->onfi_timing_mode_default = mode;
+-			break;
+-		}
+-	}
+-
+-	return 0;
+-}
+-
+-static void nand_release_data_interface(struct nand_chip *chip)
+-{
+-	kfree(chip->data_interface);
+-}
+-
+-/**
+- * 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 chipnr)
+-{
+-	struct mtd_info *mtd = nand_to_mtd(chip);
+-	int ret;
+-
+-	ret = nand_reset_data_interface(chip, chipnr);
+-	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, chipnr);
+-	chip->select_chip(mtd, -1);
+-	if (ret)
+-		return ret;
+-
+-	return 0;
+-}
+-EXPORT_SYMBOL_GPL(nand_reset);
+-
+-/**
+- * nand_check_erased_buf - check if a buffer contains (almost) only 0xff data
+- * @buf: buffer to test
+- * @len: buffer length
+- * @bitflips_threshold: maximum number of bitflips
+- *
+- * Check if a buffer contains only 0xff, which means the underlying region
+- * has been erased and is ready to be programmed.
+- * The bitflips_threshold specify the maximum number of bitflips before
+- * considering the region is not erased.
+- * Note: The logic of this function has been extracted from the memweight
+- * implementation, except that nand_check_erased_buf function exit before
+- * testing the whole buffer if the number of bitflips exceed the
+- * bitflips_threshold value.
+- *
+- * Returns a positive number of bitflips less than or equal to
+- * bitflips_threshold, or -ERROR_CODE for bitflips in excess of the
+- * threshold.
+- */
+-static int nand_check_erased_buf(void *buf, int len, int bitflips_threshold)
+-{
+-	const unsigned char *bitmap = buf;
+-	int bitflips = 0;
+-	int weight;
+-
+-	for (; len && ((uintptr_t)bitmap) % sizeof(long);
+-	     len--, bitmap++) {
+-		weight = hweight8(*bitmap);
+-		bitflips += BITS_PER_BYTE - weight;
+-		if (unlikely(bitflips > bitflips_threshold))
+-			return -EBADMSG;
+-	}
+-
+-	for (; len >= sizeof(long);
+-	     len -= sizeof(long), bitmap += sizeof(long)) {
+-		unsigned long d = *((unsigned long *)bitmap);
+-		if (d == ~0UL)
+-			continue;
+-		weight = hweight_long(d);
+-		bitflips += BITS_PER_LONG - weight;
+-		if (unlikely(bitflips > bitflips_threshold))
+-			return -EBADMSG;
+-	}
+-
+-	for (; len > 0; len--, bitmap++) {
+-		weight = hweight8(*bitmap);
+-		bitflips += BITS_PER_BYTE - weight;
+-		if (unlikely(bitflips > bitflips_threshold))
+-			return -EBADMSG;
+-	}
+-
+-	return bitflips;
+-}
+-
+-/**
+- * nand_check_erased_ecc_chunk - check if an ECC chunk contains (almost) only
+- *				 0xff data
+- * @data: data buffer to test
+- * @datalen: data length
+- * @ecc: ECC buffer
+- * @ecclen: ECC length
+- * @extraoob: extra OOB buffer
+- * @extraooblen: extra OOB length
+- * @bitflips_threshold: maximum number of bitflips
+- *
+- * Check if a data buffer and its associated ECC and OOB data contains only
+- * 0xff pattern, which means the underlying region has been erased and is
+- * ready to be programmed.
+- * The bitflips_threshold specify the maximum number of bitflips before
+- * considering the region as not erased.
+- *
+- * Note:
+- * 1/ ECC algorithms are working on pre-defined block sizes which are usually
+- *    different from the NAND page size. When fixing bitflips, ECC engines will
+- *    report the number of errors per chunk, and the NAND core infrastructure
+- *    expect you to return the maximum number of bitflips for the whole page.
+- *    This is why you should always use this function on a single chunk and
+- *    not on the whole page. After checking each chunk you should update your
+- *    max_bitflips value accordingly.
+- * 2/ When checking for bitflips in erased pages you should not only check
+- *    the payload data but also their associated ECC data, because a user might
+- *    have programmed almost all bits to 1 but a few. In this case, we
+- *    shouldn't consider the chunk as erased, and checking ECC bytes prevent
+- *    this case.
+- * 3/ The extraoob argument is optional, and should be used if some of your OOB
+- *    data are protected by the ECC engine.
+- *    It could also be used if you support subpages and want to attach some
+- *    extra OOB data to an ECC chunk.
+- *
+- * Returns a positive number of bitflips less than or equal to
+- * bitflips_threshold, or -ERROR_CODE for bitflips in excess of the
+- * threshold. In case of success, the passed buffers are filled with 0xff.
+- */
+-int nand_check_erased_ecc_chunk(void *data, int datalen,
+-				void *ecc, int ecclen,
+-				void *extraoob, int extraooblen,
+-				int bitflips_threshold)
+-{
+-	int data_bitflips = 0, ecc_bitflips = 0, extraoob_bitflips = 0;
+-
+-	data_bitflips = nand_check_erased_buf(data, datalen,
+-					      bitflips_threshold);
+-	if (data_bitflips < 0)
+-		return data_bitflips;
+-
+-	bitflips_threshold -= data_bitflips;
+-
+-	ecc_bitflips = nand_check_erased_buf(ecc, ecclen, bitflips_threshold);
+-	if (ecc_bitflips < 0)
+-		return ecc_bitflips;
+-
+-	bitflips_threshold -= ecc_bitflips;
+-
+-	extraoob_bitflips = nand_check_erased_buf(extraoob, extraooblen,
+-						  bitflips_threshold);
+-	if (extraoob_bitflips < 0)
+-		return extraoob_bitflips;
+-
+-	if (data_bitflips)
+-		memset(data, 0xff, datalen);
+-
+-	if (ecc_bitflips)
+-		memset(ecc, 0xff, ecclen);
+-
+-	if (extraoob_bitflips)
+-		memset(extraoob, 0xff, extraooblen);
+-
+-	return data_bitflips + ecc_bitflips + extraoob_bitflips;
+-}
+-EXPORT_SYMBOL(nand_check_erased_ecc_chunk);
+-
+-/**
+- * nand_read_page_raw - [INTERN] read raw page data without ecc
+- * @mtd: mtd info structure
+- * @chip: nand chip info structure
+- * @buf: buffer to store read data
+- * @oob_required: caller requires OOB data read to chip->oob_poi
+- * @page: page number to read
+- *
+- * Not for syndrome calculating ECC controllers, which use a special oob layout.
+- */
+-int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+-		       uint8_t *buf, int oob_required, int page)
+-{
+-	chip->read_buf(mtd, buf, mtd->writesize);
+-	if (oob_required)
+-		chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+-	return 0;
+-}
+-EXPORT_SYMBOL(nand_read_page_raw);
+-
+-/**
+- * nand_read_page_raw_syndrome - [INTERN] read raw page data without ecc
+- * @mtd: mtd info structure
+- * @chip: nand chip info structure
+- * @buf: buffer to store read data
+- * @oob_required: caller requires OOB data read to chip->oob_poi
+- * @page: page number to read
+- *
+- * We need a special oob layout and handling even when OOB isn't used.
+- */
+-static int nand_read_page_raw_syndrome(struct mtd_info *mtd,
+-				       struct nand_chip *chip, uint8_t *buf,
+-				       int oob_required, int page)
+-{
+-	int eccsize = chip->ecc.size;
+-	int eccbytes = chip->ecc.bytes;
+-	uint8_t *oob = chip->oob_poi;
+-	int steps, size;
+-
+-	for (steps = chip->ecc.steps; steps > 0; steps--) {
+-		chip->read_buf(mtd, buf, eccsize);
+-		buf += eccsize;
+-
+-		if (chip->ecc.prepad) {
+-			chip->read_buf(mtd, oob, chip->ecc.prepad);
+-			oob += chip->ecc.prepad;
+-		}
+-
+-		chip->read_buf(mtd, oob, eccbytes);
+-		oob += eccbytes;
+-
+-		if (chip->ecc.postpad) {
+-			chip->read_buf(mtd, oob, chip->ecc.postpad);
+-			oob += chip->ecc.postpad;
+-		}
+-	}
+-
+-	size = mtd->oobsize - (oob - chip->oob_poi);
+-	if (size)
+-		chip->read_buf(mtd, oob, size);
+-
+-	return 0;
+-}
+-
+-/**
+- * nand_read_page_swecc - [REPLACEABLE] software ECC based page read function
+- * @mtd: mtd info structure
+- * @chip: nand chip info structure
+- * @buf: buffer to store read data
+- * @oob_required: caller requires OOB data read to chip->oob_poi
+- * @page: page number to read
+- */
+-static int 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, ret;
+-	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;
+-	unsigned int max_bitflips = 0;
+-
+-	chip->ecc.read_page_raw(mtd, chip, buf, 1, page);
+-
+-	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
+-		chip->ecc.calculate(mtd, p, &ecc_calc[i]);
+-
+-	ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, chip->oob_poi, 0,
+-					 chip->ecc.total);
+-	if (ret)
+-		return ret;
+-
+-	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;
+-			max_bitflips = max_t(unsigned int, max_bitflips, stat);
+-		}
+-	}
+-	return max_bitflips;
+-}
+-
+-/**
+- * nand_read_subpage - [REPLACEABLE] ECC based sub-page read function
+- * @mtd: mtd info structure
+- * @chip: nand chip info structure
+- * @data_offs: offset of requested data within the page
+- * @readlen: data length
+- * @bufpoi: buffer to store read data
+- * @page: page number to read
+- */
+-static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
+-			uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi,
+-			int page)
+-{
+-	int start_step, end_step, num_steps, ret;
+-	uint8_t *p;
+-	int data_col_addr, i, gaps = 0;
+-	int datafrag_len, eccfrag_len, aligned_len, aligned_pos;
+-	int busw = (chip->options & NAND_BUSWIDTH_16) ? 2 : 1;
+-	int index, section = 0;
+-	unsigned int max_bitflips = 0;
+-	struct mtd_oob_region oobregion = { };
+-
+-	/* Column address within the page aligned to ECC size (256bytes) */
+-	start_step = data_offs / chip->ecc.size;
+-	end_step = (data_offs + readlen - 1) / chip->ecc.size;
+-	num_steps = end_step - start_step + 1;
+-	index = start_step * chip->ecc.bytes;
+-
+-	/* Data size aligned to ECC ecc.size */
+-	datafrag_len = num_steps * chip->ecc.size;
+-	eccfrag_len = num_steps * chip->ecc.bytes;
+-
+-	data_col_addr = start_step * chip->ecc.size;
+-	/* If we read not a page aligned data */
+-	if (data_col_addr != 0)
+-		chip->cmdfunc(mtd, NAND_CMD_RNDOUT, data_col_addr, -1);
+-
+-	p = bufpoi + data_col_addr;
+-	chip->read_buf(mtd, p, datafrag_len);
+-
+-	/* Calculate ECC */
+-	for (i = 0; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size)
+-		chip->ecc.calculate(mtd, p, &chip->buffers->ecccalc[i]);
+-
+-	/*
+-	 * The performance is faster if we position offsets according to
+-	 * ecc.pos. Let's make sure that there are no gaps in ECC positions.
+-	 */
+-	ret = mtd_ooblayout_find_eccregion(mtd, index, &section, &oobregion);
+-	if (ret)
+-		return ret;
+-
+-	if (oobregion.length < eccfrag_len)
+-		gaps = 1;
+-
+-	if (gaps) {
+-		chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize, -1);
+-		chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+-	} else {
+-		/*
+-		 * Send the command to read the particular ECC bytes take care
+-		 * about buswidth alignment in read_buf.
+-		 */
+-		aligned_pos = oobregion.offset & ~(busw - 1);
+-		aligned_len = eccfrag_len;
+-		if (oobregion.offset & (busw - 1))
+-			aligned_len++;
+-		if ((oobregion.offset + (num_steps * chip->ecc.bytes)) &
+-		    (busw - 1))
+-			aligned_len++;
+-
+-		chip->cmdfunc(mtd, NAND_CMD_RNDOUT,
+-			      mtd->writesize + aligned_pos, -1);
+-		chip->read_buf(mtd, &chip->oob_poi[aligned_pos], aligned_len);
+-	}
+-
+-	ret = mtd_ooblayout_get_eccbytes(mtd, chip->buffers->ecccode,
+-					 chip->oob_poi, index, eccfrag_len);
+-	if (ret)
+-		return ret;
+-
+-	p = bufpoi + data_col_addr;
+-	for (i = 0; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size) {
+-		int stat;
+-
+-		stat = chip->ecc.correct(mtd, p,
+-			&chip->buffers->ecccode[i], &chip->buffers->ecccalc[i]);
+-		if (stat == -EBADMSG &&
+-		    (chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) {
+-			/* check for empty pages with bitflips */
+-			stat = nand_check_erased_ecc_chunk(p, chip->ecc.size,
+-						&chip->buffers->ecccode[i],
+-						chip->ecc.bytes,
+-						NULL, 0,
+-						chip->ecc.strength);
+-		}
+-
+-		if (stat < 0) {
+-			mtd->ecc_stats.failed++;
+-		} else {
+-			mtd->ecc_stats.corrected += stat;
+-			max_bitflips = max_t(unsigned int, max_bitflips, stat);
+-		}
+-	}
+-	return max_bitflips;
+-}
+-
+-/**
+- * nand_read_page_hwecc - [REPLACEABLE] hardware ECC based page read function
+- * @mtd: mtd info structure
+- * @chip: nand chip info structure
+- * @buf: buffer to store read data
+- * @oob_required: caller requires OOB data read to chip->oob_poi
+- * @page: page number to read
+- *
+- * Not for syndrome calculating ECC controllers which need a special oob layout.
+- */
+-static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
+-				uint8_t *buf, int oob_required, int page)
+-{
+-	int i, eccsize = chip->ecc.size, ret;
+-	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;
+-	unsigned int max_bitflips = 0;
+-
+-	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
+-		chip->ecc.hwctl(mtd, NAND_ECC_READ);
+-		chip->read_buf(mtd, p, eccsize);
+-		chip->ecc.calculate(mtd, p, &ecc_calc[i]);
+-	}
+-	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+-
+-	ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, chip->oob_poi, 0,
+-					 chip->ecc.total);
+-	if (ret)
+-		return ret;
+-
+-	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 == -EBADMSG &&
+-		    (chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) {
+-			/* check for empty pages with bitflips */
+-			stat = nand_check_erased_ecc_chunk(p, eccsize,
+-						&ecc_code[i], eccbytes,
+-						NULL, 0,
+-						chip->ecc.strength);
+-		}
+-
+-		if (stat < 0) {
+-			mtd->ecc_stats.failed++;
+-		} else {
+-			mtd->ecc_stats.corrected += stat;
+-			max_bitflips = max_t(unsigned int, max_bitflips, stat);
+-		}
+-	}
+-	return max_bitflips;
+-}
+-
+-/**
+- * nand_read_page_hwecc_oob_first - [REPLACEABLE] hw ecc, read oob first
+- * @mtd: mtd info structure
+- * @chip: nand chip info structure
+- * @buf: buffer to store read data
+- * @oob_required: caller requires OOB data read to chip->oob_poi
+- * @page: page number to read
+- *
+- * Hardware ECC for large page chips, require OOB to be read first. For this
+- * ECC mode, the write_page method is re-used from ECC_HW. These methods
+- * read/write ECC from the OOB area, unlike the ECC_HW_SYNDROME support with
+- * multiple ECC steps, follows the "infix ECC" scheme and reads/writes ECC from
+- * the data area, by overwriting the NAND manufacturer bad block markings.
+- */
+-static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd,
+-	struct nand_chip *chip, uint8_t *buf, int oob_required, int page)
+-{
+-	int i, eccsize = chip->ecc.size, ret;
+-	int eccbytes = chip->ecc.bytes;
+-	int eccsteps = chip->ecc.steps;
+-	uint8_t *p = buf;
+-	uint8_t *ecc_code = chip->buffers->ecccode;
+-	uint8_t *ecc_calc = chip->buffers->ecccalc;
+-	unsigned int max_bitflips = 0;
+-
+-	/* Read the OOB area first */
+-	chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
+-	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+-	chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
+-
+-	ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, chip->oob_poi, 0,
+-					 chip->ecc.total);
+-	if (ret)
+-		return ret;
+-
+-	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
+-		int stat;
+-
+-		chip->ecc.hwctl(mtd, NAND_ECC_READ);
+-		chip->read_buf(mtd, p, eccsize);
+-		chip->ecc.calculate(mtd, p, &ecc_calc[i]);
+-
+-		stat = chip->ecc.correct(mtd, p, &ecc_code[i], NULL);
+-		if (stat == -EBADMSG &&
+-		    (chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) {
+-			/* check for empty pages with bitflips */
+-			stat = nand_check_erased_ecc_chunk(p, eccsize,
+-						&ecc_code[i], eccbytes,
+-						NULL, 0,
+-						chip->ecc.strength);
+-		}
+-
+-		if (stat < 0) {
+-			mtd->ecc_stats.failed++;
+-		} else {
+-			mtd->ecc_stats.corrected += stat;
+-			max_bitflips = max_t(unsigned int, max_bitflips, stat);
+-		}
+-	}
+-	return max_bitflips;
+-}
+-
+-/**
+- * nand_read_page_syndrome - [REPLACEABLE] hardware ECC syndrome based page read
+- * @mtd: mtd info structure
+- * @chip: nand chip info structure
+- * @buf: buffer to store read data
+- * @oob_required: caller requires OOB data read to chip->oob_poi
+- * @page: page number to read
+- *
+- * The hw generator calculates the error syndrome automatically. Therefore we
+- * need a special oob layout and handling.
+- */
+-static int nand_read_page_syndrome(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;
+-	int eccpadbytes = eccbytes + chip->ecc.prepad + chip->ecc.postpad;
+-	uint8_t *p = buf;
+-	uint8_t *oob = chip->oob_poi;
+-	unsigned int max_bitflips = 0;
+-
+-	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
+-		int stat;
+-
+-		chip->ecc.hwctl(mtd, NAND_ECC_READ);
+-		chip->read_buf(mtd, p, eccsize);
+-
+-		if (chip->ecc.prepad) {
+-			chip->read_buf(mtd, oob, chip->ecc.prepad);
+-			oob += chip->ecc.prepad;
+-		}
+-
+-		chip->ecc.hwctl(mtd, NAND_ECC_READSYN);
+-		chip->read_buf(mtd, oob, eccbytes);
+-		stat = chip->ecc.correct(mtd, p, oob, NULL);
+-
+-		oob += eccbytes;
+-
+-		if (chip->ecc.postpad) {
+-			chip->read_buf(mtd, oob, chip->ecc.postpad);
+-			oob += chip->ecc.postpad;
+-		}
+-
+-		if (stat == -EBADMSG &&
+-		    (chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) {
+-			/* check for empty pages with bitflips */
+-			stat = nand_check_erased_ecc_chunk(p, chip->ecc.size,
+-							   oob - eccpadbytes,
+-							   eccpadbytes,
+-							   NULL, 0,
+-							   chip->ecc.strength);
+-		}
+-
+-		if (stat < 0) {
+-			mtd->ecc_stats.failed++;
+-		} else {
+-			mtd->ecc_stats.corrected += stat;
+-			max_bitflips = max_t(unsigned int, max_bitflips, stat);
+-		}
+-	}
+-
+-	/* Calculate remaining oob bytes */
+-	i = mtd->oobsize - (oob - chip->oob_poi);
+-	if (i)
+-		chip->read_buf(mtd, oob, i);
+-
+-	return max_bitflips;
+-}
+-
+-/**
+- * nand_transfer_oob - [INTERN] Transfer oob to client buffer
+- * @mtd: mtd info structure
+- * @oob: oob destination address
+- * @ops: oob ops structure
+- * @len: size of oob to transfer
+- */
+-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);
+-	int ret;
+-
+-	switch (ops->mode) {
+-
+-	case MTD_OPS_PLACE_OOB:
+-	case MTD_OPS_RAW:
+-		memcpy(oob, chip->oob_poi + ops->ooboffs, len);
+-		return oob + len;
+-
+-	case MTD_OPS_AUTO_OOB:
+-		ret = mtd_ooblayout_get_databytes(mtd, oob, chip->oob_poi,
+-						  ops->ooboffs, len);
+-		BUG_ON(ret);
+-		return oob + len;
+-
+-	default:
+-		BUG();
+-	}
+-	return NULL;
+-}
+-
+-/**
+- * nand_setup_read_retry - [INTERN] Set the READ RETRY mode
+- * @mtd: MTD device structure
+- * @retry_mode: the retry mode to use
+- *
+- * Some vendors supply a special command to shift the Vt threshold, to be used
+- * when there are too many bitflips in a page (i.e., ECC error). After setting
+- * a new threshold, the host should retry reading the page.
+- */
+-static int nand_setup_read_retry(struct mtd_info *mtd, int retry_mode)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-
+-	pr_debug("setting READ RETRY mode %d\n", retry_mode);
+-
+-	if (retry_mode >= chip->read_retries)
+-		return -EINVAL;
+-
+-	if (!chip->setup_read_retry)
+-		return -EOPNOTSUPP;
+-
+-	return chip->setup_read_retry(mtd, retry_mode);
+-}
+-
+-/**
+- * nand_do_read_ops - [INTERN] Read data with ECC
+- * @mtd: MTD device structure
+- * @from: offset to read from
+- * @ops: oob ops structure
+- *
+- * Internal function. Called with chip held.
+- */
+-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);
+-	int ret = 0;
+-	uint32_t readlen = ops->len;
+-	uint32_t oobreadlen = ops->ooblen;
+-	uint32_t max_oobsize = mtd_oobavail(mtd, ops);
+-
+-	uint8_t *bufpoi, *oob, *buf;
+-	int use_bufpoi;
+-	unsigned int max_bitflips = 0;
+-	int retry_mode = 0;
+-	bool ecc_fail = false;
+-
+-	chipnr = (int)(from >> chip->chip_shift);
+-	chip->select_chip(mtd, chipnr);
+-
+-	realpage = (int)(from >> chip->page_shift);
+-	page = realpage & chip->pagemask;
+-
+-	col = (int)(from & (mtd->writesize - 1));
+-
+-	buf = ops->datbuf;
+-	oob = ops->oobbuf;
+-	oob_required = oob ? 1 : 0;
+-
+-	while (1) {
+-		unsigned int ecc_failures = mtd->ecc_stats.failed;
+-
+-		bytes = min(mtd->writesize - col, readlen);
+-		aligned = (bytes == mtd->writesize);
+-
+-		if (!aligned)
+-			use_bufpoi = 1;
+-		else if (chip->options & NAND_USE_BOUNCE_BUFFER)
+-			use_bufpoi = !virt_addr_valid(buf) ||
+-				     !IS_ALIGNED((unsigned long)buf,
+-						 chip->buf_align);
+-		else
+-			use_bufpoi = 0;
+-
+-		/* Is the current page in the buffer? */
+-		if (realpage != chip->pagebuf || oob) {
+-			bufpoi = use_bufpoi ? chip->buffers->databuf : buf;
+-
+-			if (use_bufpoi && aligned)
+-				pr_debug("%s: using read bounce buffer for buf@%p\n",
+-						 __func__, buf);
+-
+-read_retry:
+-			if (nand_standard_page_accessors(&chip->ecc))
+-				chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
+-
+-			/*
+-			 * Now read the page into the buffer.  Absent an error,
+-			 * the read methods return max bitflips per ecc step.
+-			 */
+-			if (unlikely(ops->mode == MTD_OPS_RAW))
+-				ret = chip->ecc.read_page_raw(mtd, chip, bufpoi,
+-							      oob_required,
+-							      page);
+-			else if (!aligned && NAND_HAS_SUBPAGE_READ(chip) &&
+-				 !oob)
+-				ret = chip->ecc.read_subpage(mtd, chip,
+-							col, bytes, bufpoi,
+-							page);
+-			else
+-				ret = chip->ecc.read_page(mtd, chip, bufpoi,
+-							  oob_required, page);
+-			if (ret < 0) {
+-				if (use_bufpoi)
+-					/* Invalidate page cache */
+-					chip->pagebuf = -1;
+-				break;
+-			}
+-
+-			/* Transfer not aligned data */
+-			if (use_bufpoi) {
+-				if (!NAND_HAS_SUBPAGE_READ(chip) && !oob &&
+-				    !(mtd->ecc_stats.failed - ecc_failures) &&
+-				    (ops->mode != MTD_OPS_RAW)) {
+-					chip->pagebuf = realpage;
+-					chip->pagebuf_bitflips = ret;
+-				} else {
+-					/* Invalidate page cache */
+-					chip->pagebuf = -1;
+-				}
+-				memcpy(buf, chip->buffers->databuf + col, bytes);
+-			}
+-
+-			if (unlikely(oob)) {
+-				int toread = min(oobreadlen, max_oobsize);
+-
+-				if (toread) {
+-					oob = nand_transfer_oob(mtd,
+-						oob, ops, toread);
+-					oobreadlen -= toread;
+-				}
+-			}
+-
+-			if (chip->options & NAND_NEED_READRDY) {
+-				/* Apply delay or wait for ready/busy pin */
+-				if (!chip->dev_ready)
+-					udelay(chip->chip_delay);
+-				else
+-					nand_wait_ready(mtd);
+-			}
+-
+-			if (mtd->ecc_stats.failed - ecc_failures) {
+-				if (retry_mode + 1 < chip->read_retries) {
+-					retry_mode++;
+-					ret = nand_setup_read_retry(mtd,
+-							retry_mode);
+-					if (ret < 0)
+-						break;
+-
+-					/* Reset failures; retry */
+-					mtd->ecc_stats.failed = ecc_failures;
+-					goto read_retry;
+-				} else {
+-					/* No more retry modes; real failure */
+-					ecc_fail = true;
+-				}
+-			}
+-
+-			buf += bytes;
+-			max_bitflips = max_t(unsigned int, max_bitflips, ret);
+-		} else {
+-			memcpy(buf, chip->buffers->databuf + col, bytes);
+-			buf += bytes;
+-			max_bitflips = max_t(unsigned int, max_bitflips,
+-					     chip->pagebuf_bitflips);
+-		}
+-
+-		readlen -= bytes;
+-
+-		/* Reset to retry mode 0 */
+-		if (retry_mode) {
+-			ret = nand_setup_read_retry(mtd, 0);
+-			if (ret < 0)
+-				break;
+-			retry_mode = 0;
+-		}
+-
+-		if (!readlen)
+-			break;
+-
+-		/* For subsequent reads align to page boundary */
+-		col = 0;
+-		/* Increment page address */
+-		realpage++;
+-
+-		page = realpage & chip->pagemask;
+-		/* Check, if we cross a chip boundary */
+-		if (!page) {
+-			chipnr++;
+-			chip->select_chip(mtd, -1);
+-			chip->select_chip(mtd, chipnr);
+-		}
+-	}
+-	chip->select_chip(mtd, -1);
+-
+-	ops->retlen = ops->len - (size_t) readlen;
+-	if (oob)
+-		ops->oobretlen = ops->ooblen - oobreadlen;
+-
+-	if (ret < 0)
+-		return ret;
+-
+-	if (ecc_fail)
+-		return -EBADMSG;
+-
+-	return max_bitflips;
+-}
+-
+-/**
+- * nand_read_oob_std - [REPLACEABLE] the most common OOB data read function
+- * @mtd: mtd info structure
+- * @chip: nand chip info structure
+- * @page: page number to read
+- */
+-int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip, int page)
+-{
+-	chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
+-	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+-	return 0;
+-}
+-EXPORT_SYMBOL(nand_read_oob_std);
+-
+-/**
+- * nand_read_oob_syndrome - [REPLACEABLE] OOB data read function for HW ECC
+- *			    with syndromes
+- * @mtd: mtd info structure
+- * @chip: nand chip info structure
+- * @page: page number to read
+- */
+-int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
+-			   int page)
+-{
+-	int length = mtd->oobsize;
+-	int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad;
+-	int eccsize = chip->ecc.size;
+-	uint8_t *bufpoi = chip->oob_poi;
+-	int i, toread, sndrnd = 0, pos;
+-
+-	chip->cmdfunc(mtd, NAND_CMD_READ0, chip->ecc.size, page);
+-	for (i = 0; i < chip->ecc.steps; i++) {
+-		if (sndrnd) {
+-			pos = eccsize + i * (eccsize + chunk);
+-			if (mtd->writesize > 512)
+-				chip->cmdfunc(mtd, NAND_CMD_RNDOUT, pos, -1);
+-			else
+-				chip->cmdfunc(mtd, NAND_CMD_READ0, pos, page);
+-		} else
+-			sndrnd = 1;
+-		toread = min_t(int, length, chunk);
+-		chip->read_buf(mtd, bufpoi, toread);
+-		bufpoi += toread;
+-		length -= toread;
+-	}
+-	if (length > 0)
+-		chip->read_buf(mtd, bufpoi, length);
+-
+-	return 0;
+-}
+-EXPORT_SYMBOL(nand_read_oob_syndrome);
+-
+-/**
+- * nand_write_oob_std - [REPLACEABLE] the most common OOB data write function
+- * @mtd: mtd info structure
+- * @chip: nand chip info structure
+- * @page: page number to write
+- */
+-int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip, int page)
+-{
+-	int status = 0;
+-	const uint8_t *buf = chip->oob_poi;
+-	int length = mtd->oobsize;
+-
+-	chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page);
+-	chip->write_buf(mtd, buf, length);
+-	/* Send command to program the OOB data */
+-	chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+-
+-	status = chip->waitfunc(mtd, chip);
+-
+-	return status & NAND_STATUS_FAIL ? -EIO : 0;
+-}
+-EXPORT_SYMBOL(nand_write_oob_std);
+-
+-/**
+- * nand_write_oob_syndrome - [REPLACEABLE] OOB data write function for HW ECC
+- *			     with syndrome - only for large page flash
+- * @mtd: mtd info structure
+- * @chip: nand chip info structure
+- * @page: page number to write
+- */
+-int nand_write_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
+-			    int page)
+-{
+-	int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad;
+-	int eccsize = chip->ecc.size, length = mtd->oobsize;
+-	int i, len, pos, status = 0, sndcmd = 0, steps = chip->ecc.steps;
+-	const uint8_t *bufpoi = chip->oob_poi;
+-
+-	/*
+-	 * data-ecc-data-ecc ... ecc-oob
+-	 * or
+-	 * data-pad-ecc-pad-data-pad .... ecc-pad-oob
+-	 */
+-	if (!chip->ecc.prepad && !chip->ecc.postpad) {
+-		pos = steps * (eccsize + chunk);
+-		steps = 0;
+-	} else
+-		pos = eccsize;
+-
+-	chip->cmdfunc(mtd, NAND_CMD_SEQIN, pos, page);
+-	for (i = 0; i < steps; i++) {
+-		if (sndcmd) {
+-			if (mtd->writesize <= 512) {
+-				uint32_t fill = 0xFFFFFFFF;
+-
+-				len = eccsize;
+-				while (len > 0) {
+-					int num = min_t(int, len, 4);
+-					chip->write_buf(mtd, (uint8_t *)&fill,
+-							num);
+-					len -= num;
+-				}
+-			} else {
+-				pos = eccsize + i * (eccsize + chunk);
+-				chip->cmdfunc(mtd, NAND_CMD_RNDIN, pos, -1);
+-			}
+-		} else
+-			sndcmd = 1;
+-		len = min_t(int, length, chunk);
+-		chip->write_buf(mtd, bufpoi, len);
+-		bufpoi += len;
+-		length -= len;
+-	}
+-	if (length > 0)
+-		chip->write_buf(mtd, bufpoi, length);
+-
+-	chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+-	status = chip->waitfunc(mtd, chip);
+-
+-	return status & NAND_STATUS_FAIL ? -EIO : 0;
+-}
+-EXPORT_SYMBOL(nand_write_oob_syndrome);
+-
+-/**
+- * nand_do_read_oob - [INTERN] NAND read out-of-band
+- * @mtd: MTD device structure
+- * @from: offset to read from
+- * @ops: oob operations description structure
+- *
+- * NAND read out-of-band data from the spare area.
+- */
+-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 mtd_ecc_stats stats;
+-	int readlen = ops->ooblen;
+-	int len;
+-	uint8_t *buf = ops->oobbuf;
+-	int ret = 0;
+-
+-	pr_debug("%s: from = 0x%08Lx, len = %i\n",
+-			__func__, (unsigned long long)from, readlen);
+-
+-	stats = mtd->ecc_stats;
+-
+-	len = mtd_oobavail(mtd, ops);
+-
+-	if (unlikely(ops->ooboffs >= len)) {
+-		pr_debug("%s: attempt to start read outside oob\n",
+-				__func__);
+-		return -EINVAL;
+-	}
+-
+-	/* Do not allow reads past end of device */
+-	if (unlikely(from >= mtd->size ||
+-		     ops->ooboffs + readlen > ((mtd->size >> chip->page_shift) -
+-					(from >> chip->page_shift)) * len)) {
+-		pr_debug("%s: attempt to read beyond end of device\n",
+-				__func__);
+-		return -EINVAL;
+-	}
+-
+-	chipnr = (int)(from >> chip->chip_shift);
+-	chip->select_chip(mtd, chipnr);
+-
+-	/* Shift to get page */
+-	realpage = (int)(from >> chip->page_shift);
+-	page = realpage & chip->pagemask;
+-
+-	while (1) {
+-		if (ops->mode == MTD_OPS_RAW)
+-			ret = chip->ecc.read_oob_raw(mtd, chip, page);
+-		else
+-			ret = chip->ecc.read_oob(mtd, chip, page);
+-
+-		if (ret < 0)
+-			break;
+-
+-		len = min(len, readlen);
+-		buf = nand_transfer_oob(mtd, buf, ops, len);
+-
+-		if (chip->options & NAND_NEED_READRDY) {
+-			/* Apply delay or wait for ready/busy pin */
+-			if (!chip->dev_ready)
+-				udelay(chip->chip_delay);
+-			else
+-				nand_wait_ready(mtd);
+-		}
+-
+-		readlen -= len;
+-		if (!readlen)
+-			break;
+-
+-		/* Increment page address */
+-		realpage++;
+-
+-		page = realpage & chip->pagemask;
+-		/* Check, if we cross a chip boundary */
+-		if (!page) {
+-			chipnr++;
+-			chip->select_chip(mtd, -1);
+-			chip->select_chip(mtd, chipnr);
+-		}
+-	}
+-	chip->select_chip(mtd, -1);
+-
+-	ops->oobretlen = ops->ooblen - readlen;
+-
+-	if (ret < 0)
+-		return ret;
+-
+-	if (mtd->ecc_stats.failed - stats.failed)
+-		return -EBADMSG;
+-
+-	return  mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0;
+-}
+-
+-/**
+- * nand_read_oob - [MTD Interface] NAND read data and/or out-of-band
+- * @mtd: MTD device structure
+- * @from: offset to read from
+- * @ops: oob operation description structure
+- *
+- * NAND read data and/or out-of-band data.
+- */
+-static int nand_read_oob(struct mtd_info *mtd, loff_t from,
+-			 struct mtd_oob_ops *ops)
+-{
+-	int ret;
+-
+-	ops->retlen = 0;
+-
+-	/* Do not allow reads past end of device */
+-	if (ops->datbuf && (from + ops->len) > mtd->size) {
+-		pr_debug("%s: attempt to read beyond end of device\n",
+-				__func__);
+-		return -EINVAL;
+-	}
+-
+-	if (ops->mode != MTD_OPS_PLACE_OOB &&
+-	    ops->mode != MTD_OPS_AUTO_OOB &&
+-	    ops->mode != MTD_OPS_RAW)
+-		return -ENOTSUPP;
+-
+-	nand_get_device(mtd, FL_READING);
+-
+-	if (!ops->datbuf)
+-		ret = nand_do_read_oob(mtd, from, ops);
+-	else
+-		ret = nand_do_read_ops(mtd, from, ops);
+-
+-	nand_release_device(mtd);
+-	return ret;
+-}
+-
+-
+-/**
+- * nand_write_page_raw - [INTERN] raw page write function
+- * @mtd: mtd info structure
+- * @chip: nand chip info structure
+- * @buf: data buffer
+- * @oob_required: must write chip->oob_poi to OOB
+- * @page: page number to write
+- *
+- * Not for syndrome calculating ECC controllers, which use a special oob layout.
+- */
+-int nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+-			const uint8_t *buf, int oob_required, int page)
+-{
+-	chip->write_buf(mtd, buf, mtd->writesize);
+-	if (oob_required)
+-		chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+-
+-	return 0;
+-}
+-EXPORT_SYMBOL(nand_write_page_raw);
+-
+-/**
+- * nand_write_page_raw_syndrome - [INTERN] raw page write function
+- * @mtd: mtd info structure
+- * @chip: nand chip info structure
+- * @buf: data buffer
+- * @oob_required: must write chip->oob_poi to OOB
+- * @page: page number to write
+- *
+- * We need a special oob layout and handling even when ECC isn't checked.
+- */
+-static int nand_write_page_raw_syndrome(struct mtd_info *mtd,
+-					struct nand_chip *chip,
+-					const uint8_t *buf, int oob_required,
+-					int page)
+-{
+-	int eccsize = chip->ecc.size;
+-	int eccbytes = chip->ecc.bytes;
+-	uint8_t *oob = chip->oob_poi;
+-	int steps, size;
+-
+-	for (steps = chip->ecc.steps; steps > 0; steps--) {
+-		chip->write_buf(mtd, buf, eccsize);
+-		buf += eccsize;
+-
+-		if (chip->ecc.prepad) {
+-			chip->write_buf(mtd, oob, chip->ecc.prepad);
+-			oob += chip->ecc.prepad;
+-		}
+-
+-		chip->write_buf(mtd, oob, eccbytes);
+-		oob += eccbytes;
+-
+-		if (chip->ecc.postpad) {
+-			chip->write_buf(mtd, oob, chip->ecc.postpad);
+-			oob += chip->ecc.postpad;
+-		}
+-	}
+-
+-	size = mtd->oobsize - (oob - chip->oob_poi);
+-	if (size)
+-		chip->write_buf(mtd, oob, size);
+-
+-	return 0;
+-}
+-/**
+- * nand_write_page_swecc - [REPLACEABLE] software ECC based page write function
+- * @mtd: mtd info structure
+- * @chip: nand chip info structure
+- * @buf: data buffer
+- * @oob_required: must write chip->oob_poi to OOB
+- * @page: page number to write
+- */
+-static int nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
+-				 const uint8_t *buf, int oob_required,
+-				 int page)
+-{
+-	int i, eccsize = chip->ecc.size, ret;
+-	int eccbytes = chip->ecc.bytes;
+-	int eccsteps = chip->ecc.steps;
+-	uint8_t *ecc_calc = chip->buffers->ecccalc;
+-	const uint8_t *p = buf;
+-
+-	/* Software ECC calculation */
+-	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
+-		chip->ecc.calculate(mtd, p, &ecc_calc[i]);
+-
+-	ret = mtd_ooblayout_set_eccbytes(mtd, ecc_calc, chip->oob_poi, 0,
+-					 chip->ecc.total);
+-	if (ret)
+-		return ret;
+-
+-	return chip->ecc.write_page_raw(mtd, chip, buf, 1, page);
+-}
+-
+-/**
+- * nand_write_page_hwecc - [REPLACEABLE] hardware ECC based page write function
+- * @mtd: mtd info structure
+- * @chip: nand chip info structure
+- * @buf: data buffer
+- * @oob_required: must write chip->oob_poi to OOB
+- * @page: page number to write
+- */
+-static int nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
+-				  const uint8_t *buf, int oob_required,
+-				  int page)
+-{
+-	int i, eccsize = chip->ecc.size, ret;
+-	int eccbytes = chip->ecc.bytes;
+-	int eccsteps = chip->ecc.steps;
+-	uint8_t *ecc_calc = chip->buffers->ecccalc;
+-	const uint8_t *p = buf;
+-
+-	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
+-		chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
+-		chip->write_buf(mtd, p, eccsize);
+-		chip->ecc.calculate(mtd, p, &ecc_calc[i]);
+-	}
+-
+-	ret = mtd_ooblayout_set_eccbytes(mtd, ecc_calc, chip->oob_poi, 0,
+-					 chip->ecc.total);
+-	if (ret)
+-		return ret;
+-
+-	chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+-
+-	return 0;
+-}
+-
+-
+-/**
+- * nand_write_subpage_hwecc - [REPLACEABLE] hardware ECC based subpage write
+- * @mtd:	mtd info structure
+- * @chip:	nand chip info structure
+- * @offset:	column address of subpage within the page
+- * @data_len:	data length
+- * @buf:	data buffer
+- * @oob_required: must write chip->oob_poi to OOB
+- * @page: page number to write
+- */
+-static int nand_write_subpage_hwecc(struct mtd_info *mtd,
+-				struct nand_chip *chip, uint32_t offset,
+-				uint32_t data_len, const uint8_t *buf,
+-				int oob_required, int page)
+-{
+-	uint8_t *oob_buf  = chip->oob_poi;
+-	uint8_t *ecc_calc = chip->buffers->ecccalc;
+-	int ecc_size      = chip->ecc.size;
+-	int ecc_bytes     = chip->ecc.bytes;
+-	int ecc_steps     = chip->ecc.steps;
+-	uint32_t start_step = offset / ecc_size;
+-	uint32_t end_step   = (offset + data_len - 1) / ecc_size;
+-	int oob_bytes       = mtd->oobsize / ecc_steps;
+-	int step, ret;
+-
+-	for (step = 0; step < ecc_steps; step++) {
+-		/* configure controller for WRITE access */
+-		chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
+-
+-		/* write data (untouched subpages already masked by 0xFF) */
+-		chip->write_buf(mtd, buf, ecc_size);
+-
+-		/* mask ECC of un-touched subpages by padding 0xFF */
+-		if ((step < start_step) || (step > end_step))
+-			memset(ecc_calc, 0xff, ecc_bytes);
+-		else
+-			chip->ecc.calculate(mtd, buf, ecc_calc);
+-
+-		/* mask OOB of un-touched subpages by padding 0xFF */
+-		/* if oob_required, preserve OOB metadata of written subpage */
+-		if (!oob_required || (step < start_step) || (step > end_step))
+-			memset(oob_buf, 0xff, oob_bytes);
+-
+-		buf += ecc_size;
+-		ecc_calc += ecc_bytes;
+-		oob_buf  += oob_bytes;
+-	}
+-
+-	/* copy calculated ECC for whole page to chip->buffer->oob */
+-	/* this include masked-value(0xFF) for unwritten subpages */
+-	ecc_calc = chip->buffers->ecccalc;
+-	ret = mtd_ooblayout_set_eccbytes(mtd, ecc_calc, chip->oob_poi, 0,
+-					 chip->ecc.total);
+-	if (ret)
+-		return ret;
+-
+-	/* write OOB buffer to NAND device */
+-	chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+-
+-	return 0;
+-}
+-
+-
+-/**
+- * nand_write_page_syndrome - [REPLACEABLE] hardware ECC syndrome based page write
+- * @mtd: mtd info structure
+- * @chip: nand chip info structure
+- * @buf: data buffer
+- * @oob_required: must write chip->oob_poi to OOB
+- * @page: page number to write
+- *
+- * The hw generator calculates the error syndrome automatically. Therefore we
+- * need a special oob layout and handling.
+- */
+-static int nand_write_page_syndrome(struct mtd_info *mtd,
+-				    struct nand_chip *chip,
+-				    const uint8_t *buf, int oob_required,
+-				    int page)
+-{
+-	int i, eccsize = chip->ecc.size;
+-	int eccbytes = chip->ecc.bytes;
+-	int eccsteps = chip->ecc.steps;
+-	const uint8_t *p = buf;
+-	uint8_t *oob = chip->oob_poi;
+-
+-	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
+-
+-		chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
+-		chip->write_buf(mtd, p, eccsize);
+-
+-		if (chip->ecc.prepad) {
+-			chip->write_buf(mtd, oob, chip->ecc.prepad);
+-			oob += chip->ecc.prepad;
+-		}
+-
+-		chip->ecc.calculate(mtd, p, oob);
+-		chip->write_buf(mtd, oob, eccbytes);
+-		oob += eccbytes;
+-
+-		if (chip->ecc.postpad) {
+-			chip->write_buf(mtd, oob, chip->ecc.postpad);
+-			oob += chip->ecc.postpad;
+-		}
+-	}
+-
+-	/* Calculate remaining oob bytes */
+-	i = mtd->oobsize - (oob - chip->oob_poi);
+-	if (i)
+-		chip->write_buf(mtd, oob, i);
+-
+-	return 0;
+-}
+-
+-/**
+- * nand_write_page - write one page
+- * @mtd: MTD device structure
+- * @chip: NAND chip descriptor
+- * @offset: address offset within the page
+- * @data_len: length of actual data to be written
+- * @buf: the data to write
+- * @oob_required: must write chip->oob_poi to OOB
+- * @page: page number to write
+- * @raw: use _raw version of write_page
+- */
+-static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
+-		uint32_t offset, int data_len, const uint8_t *buf,
+-		int oob_required, int page, int raw)
+-{
+-	int status, subpage;
+-
+-	if (!(chip->options & NAND_NO_SUBPAGE_WRITE) &&
+-		chip->ecc.write_subpage)
+-		subpage = offset || (data_len < mtd->writesize);
+-	else
+-		subpage = 0;
+-
+-	if (nand_standard_page_accessors(&chip->ecc))
+-		chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
+-
+-	if (unlikely(raw))
+-		status = chip->ecc.write_page_raw(mtd, chip, buf,
+-						  oob_required, page);
+-	else if (subpage)
+-		status = chip->ecc.write_subpage(mtd, chip, offset, data_len,
+-						 buf, oob_required, page);
+-	else
+-		status = chip->ecc.write_page(mtd, chip, buf, oob_required,
+-					      page);
+-
+-	if (status < 0)
+-		return status;
+-
+-	if (nand_standard_page_accessors(&chip->ecc)) {
+-		chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+-
+-		status = chip->waitfunc(mtd, chip);
+-		if (status & NAND_STATUS_FAIL)
+-			return -EIO;
+-	}
+-
+-	return 0;
+-}
+-
+-/**
+- * nand_fill_oob - [INTERN] Transfer client buffer to oob
+- * @mtd: MTD device structure
+- * @oob: oob data buffer
+- * @len: oob data write length
+- * @ops: oob ops structure
+- */
+-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);
+-	int ret;
+-
+-	/*
+-	 * Initialise to all 0xFF, to avoid the possibility of left over OOB
+-	 * data from a previous OOB read.
+-	 */
+-	memset(chip->oob_poi, 0xff, mtd->oobsize);
+-
+-	switch (ops->mode) {
+-
+-	case MTD_OPS_PLACE_OOB:
+-	case MTD_OPS_RAW:
+-		memcpy(chip->oob_poi + ops->ooboffs, oob, len);
+-		return oob + len;
+-
+-	case MTD_OPS_AUTO_OOB:
+-		ret = mtd_ooblayout_set_databytes(mtd, oob, chip->oob_poi,
+-						  ops->ooboffs, len);
+-		BUG_ON(ret);
+-		return oob + len;
+-
+-	default:
+-		BUG();
+-	}
+-	return NULL;
+-}
+-
+-#define NOTALIGNED(x)	((x & (chip->subpagesize - 1)) != 0)
+-
+-/**
+- * nand_do_write_ops - [INTERN] NAND write with ECC
+- * @mtd: MTD device structure
+- * @to: offset to write to
+- * @ops: oob operations description structure
+- *
+- * NAND write with ECC.
+- */
+-static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
+-			     struct mtd_oob_ops *ops)
+-{
+-	int chipnr, realpage, page, column;
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	uint32_t writelen = ops->len;
+-
+-	uint32_t oobwritelen = ops->ooblen;
+-	uint32_t oobmaxlen = mtd_oobavail(mtd, ops);
+-
+-	uint8_t *oob = ops->oobbuf;
+-	uint8_t *buf = ops->datbuf;
+-	int ret;
+-	int oob_required = oob ? 1 : 0;
+-
+-	ops->retlen = 0;
+-	if (!writelen)
+-		return 0;
+-
+-	/* Reject writes, which are not page aligned */
+-	if (NOTALIGNED(to) || NOTALIGNED(ops->len)) {
+-		pr_notice("%s: attempt to write non page aligned data\n",
+-			   __func__);
+-		return -EINVAL;
+-	}
+-
+-	column = to & (mtd->writesize - 1);
+-
+-	chipnr = (int)(to >> chip->chip_shift);
+-	chip->select_chip(mtd, chipnr);
+-
+-	/* Check, if it is write protected */
+-	if (nand_check_wp(mtd)) {
+-		ret = -EIO;
+-		goto err_out;
+-	}
+-
+-	realpage = (int)(to >> chip->page_shift);
+-	page = realpage & chip->pagemask;
+-
+-	/* Invalidate the page cache, when we write to the cached page */
+-	if (to <= ((loff_t)chip->pagebuf << chip->page_shift) &&
+-	    ((loff_t)chip->pagebuf << chip->page_shift) < (to + ops->len))
+-		chip->pagebuf = -1;
+-
+-	/* Don't allow multipage oob writes with offset */
+-	if (oob && ops->ooboffs && (ops->ooboffs + ops->ooblen > oobmaxlen)) {
+-		ret = -EINVAL;
+-		goto err_out;
+-	}
+-
+-	while (1) {
+-		int bytes = mtd->writesize;
+-		uint8_t *wbuf = buf;
+-		int use_bufpoi;
+-		int part_pagewr = (column || writelen < mtd->writesize);
+-
+-		if (part_pagewr)
+-			use_bufpoi = 1;
+-		else if (chip->options & NAND_USE_BOUNCE_BUFFER)
+-			use_bufpoi = !virt_addr_valid(buf) ||
+-				     !IS_ALIGNED((unsigned long)buf,
+-						 chip->buf_align);
+-		else
+-			use_bufpoi = 0;
+-
+-		/* Partial page write?, or need to use bounce buffer */
+-		if (use_bufpoi) {
+-			pr_debug("%s: using write bounce buffer for buf@%p\n",
+-					 __func__, buf);
+-			if (part_pagewr)
+-				bytes = min_t(int, bytes - column, writelen);
+-			chip->pagebuf = -1;
+-			memset(chip->buffers->databuf, 0xff, mtd->writesize);
+-			memcpy(&chip->buffers->databuf[column], buf, bytes);
+-			wbuf = chip->buffers->databuf;
+-		}
+-
+-		if (unlikely(oob)) {
+-			size_t len = min(oobwritelen, oobmaxlen);
+-			oob = nand_fill_oob(mtd, oob, len, ops);
+-			oobwritelen -= len;
+-		} else {
+-			/* We still need to erase leftover OOB data */
+-			memset(chip->oob_poi, 0xff, mtd->oobsize);
+-		}
+-
+-		ret = nand_write_page(mtd, chip, column, bytes, wbuf,
+-				      oob_required, page,
+-				      (ops->mode == MTD_OPS_RAW));
+-		if (ret)
+-			break;
+-
+-		writelen -= bytes;
+-		if (!writelen)
+-			break;
+-
+-		column = 0;
+-		buf += bytes;
+-		realpage++;
+-
+-		page = realpage & chip->pagemask;
+-		/* Check, if we cross a chip boundary */
+-		if (!page) {
+-			chipnr++;
+-			chip->select_chip(mtd, -1);
+-			chip->select_chip(mtd, chipnr);
+-		}
+-	}
+-
+-	ops->retlen = ops->len - writelen;
+-	if (unlikely(oob))
+-		ops->oobretlen = ops->ooblen;
+-
+-err_out:
+-	chip->select_chip(mtd, -1);
+-	return ret;
+-}
+-
+-/**
+- * panic_nand_write - [MTD Interface] NAND write with ECC
+- * @mtd: MTD device structure
+- * @to: offset to write to
+- * @len: number of bytes to write
+- * @retlen: pointer to variable to store the number of written bytes
+- * @buf: the data to write
+- *
+- * NAND write with ECC. Used when performing writes in interrupt context, this
+- * may for example be called by mtdoops when writing an oops while in panic.
+- */
+-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);
+-	int chipnr = (int)(to >> chip->chip_shift);
+-	struct mtd_oob_ops ops;
+-	int ret;
+-
+-	/* Grab the device */
+-	panic_nand_get_device(chip, mtd, FL_WRITING);
+-
+-	chip->select_chip(mtd, chipnr);
+-
+-	/* Wait for the device to get ready */
+-	panic_nand_wait(mtd, chip, 400);
+-
+-	memset(&ops, 0, sizeof(ops));
+-	ops.len = len;
+-	ops.datbuf = (uint8_t *)buf;
+-	ops.mode = MTD_OPS_PLACE_OOB;
+-
+-	ret = nand_do_write_ops(mtd, to, &ops);
+-
+-	*retlen = ops.retlen;
+-	return ret;
+-}
+-
+-/**
+- * nand_do_write_oob - [MTD Interface] NAND write out-of-band
+- * @mtd: MTD device structure
+- * @to: offset to write to
+- * @ops: oob operation description structure
+- *
+- * NAND write out-of-band.
+- */
+-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);
+-
+-	pr_debug("%s: to = 0x%08x, len = %i\n",
+-			 __func__, (unsigned int)to, (int)ops->ooblen);
+-
+-	len = mtd_oobavail(mtd, ops);
+-
+-	/* Do not allow write past end of page */
+-	if ((ops->ooboffs + ops->ooblen) > len) {
+-		pr_debug("%s: attempt to write past end of page\n",
+-				__func__);
+-		return -EINVAL;
+-	}
+-
+-	if (unlikely(ops->ooboffs >= len)) {
+-		pr_debug("%s: attempt to start write outside oob\n",
+-				__func__);
+-		return -EINVAL;
+-	}
+-
+-	/* Do not allow write past end of device */
+-	if (unlikely(to >= mtd->size ||
+-		     ops->ooboffs + ops->ooblen >
+-			((mtd->size >> chip->page_shift) -
+-			 (to >> chip->page_shift)) * len)) {
+-		pr_debug("%s: attempt to write beyond end of device\n",
+-				__func__);
+-		return -EINVAL;
+-	}
+-
+-	chipnr = (int)(to >> chip->chip_shift);
+-
+-	/*
+-	 * Reset the chip. Some chips (like the Toshiba TC5832DC found in one
+-	 * of my DiskOnChip 2000 test units) will clear the whole data page too
+-	 * 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, 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)) {
+-		chip->select_chip(mtd, -1);
+-		return -EROFS;
+-	}
+-
+-	/* Invalidate the page cache, if we write to the cached page */
+-	if (page == chip->pagebuf)
+-		chip->pagebuf = -1;
+-
+-	nand_fill_oob(mtd, ops->oobbuf, ops->ooblen, ops);
+-
+-	if (ops->mode == MTD_OPS_RAW)
+-		status = chip->ecc.write_oob_raw(mtd, chip, page & chip->pagemask);
+-	else
+-		status = chip->ecc.write_oob(mtd, chip, page & chip->pagemask);
+-
+-	chip->select_chip(mtd, -1);
+-
+-	if (status)
+-		return status;
+-
+-	ops->oobretlen = ops->ooblen;
+-
+-	return 0;
+-}
+-
+-/**
+- * nand_write_oob - [MTD Interface] NAND write data and/or out-of-band
+- * @mtd: MTD device structure
+- * @to: offset to write to
+- * @ops: oob operation description structure
+- */
+-static int nand_write_oob(struct mtd_info *mtd, loff_t to,
+-			  struct mtd_oob_ops *ops)
+-{
+-	int ret = -ENOTSUPP;
+-
+-	ops->retlen = 0;
+-
+-	/* Do not allow writes past end of device */
+-	if (ops->datbuf && (to + ops->len) > mtd->size) {
+-		pr_debug("%s: attempt to write beyond end of device\n",
+-				__func__);
+-		return -EINVAL;
+-	}
+-
+-	nand_get_device(mtd, FL_WRITING);
+-
+-	switch (ops->mode) {
+-	case MTD_OPS_PLACE_OOB:
+-	case MTD_OPS_AUTO_OOB:
+-	case MTD_OPS_RAW:
+-		break;
+-
+-	default:
+-		goto out;
+-	}
+-
+-	if (!ops->datbuf)
+-		ret = nand_do_write_oob(mtd, to, ops);
+-	else
+-		ret = nand_do_write_ops(mtd, to, ops);
+-
+-out:
+-	nand_release_device(mtd);
+-	return ret;
+-}
+-
+-/**
+- * single_erase - [GENERIC] NAND standard block erase command function
+- * @mtd: MTD device structure
+- * @page: the page address of the block which will be erased
+- *
+- * Standard erase command for NAND chips. Returns NAND status.
+- */
+-static int single_erase(struct mtd_info *mtd, int page)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	/* Send commands to erase a block */
+-	chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page);
+-	chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1);
+-
+-	return chip->waitfunc(mtd, chip);
+-}
+-
+-/**
+- * nand_erase - [MTD Interface] erase block(s)
+- * @mtd: MTD device structure
+- * @instr: erase instruction
+- *
+- * Erase one ore more blocks.
+- */
+-static int nand_erase(struct mtd_info *mtd, struct erase_info *instr)
+-{
+-	return nand_erase_nand(mtd, instr, 0);
+-}
+-
+-/**
+- * nand_erase_nand - [INTERN] erase block(s)
+- * @mtd: MTD device structure
+- * @instr: erase instruction
+- * @allowbbt: allow erasing the bbt area
+- *
+- * Erase one ore more blocks.
+- */
+-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);
+-	loff_t len;
+-
+-	pr_debug("%s: start = 0x%012llx, len = %llu\n",
+-			__func__, (unsigned long long)instr->addr,
+-			(unsigned long long)instr->len);
+-
+-	if (check_offs_len(mtd, instr->addr, instr->len))
+-		return -EINVAL;
+-
+-	/* Grab the lock and see if the device is available */
+-	nand_get_device(mtd, FL_ERASING);
+-
+-	/* Shift to get first page */
+-	page = (int)(instr->addr >> chip->page_shift);
+-	chipnr = (int)(instr->addr >> chip->chip_shift);
+-
+-	/* Calculate pages in each block */
+-	pages_per_block = 1 << (chip->phys_erase_shift - chip->page_shift);
+-
+-	/* Select the NAND device */
+-	chip->select_chip(mtd, chipnr);
+-
+-	/* Check, if it is write protected */
+-	if (nand_check_wp(mtd)) {
+-		pr_debug("%s: device is write protected!\n",
+-				__func__);
+-		instr->state = MTD_ERASE_FAILED;
+-		goto erase_exit;
+-	}
+-
+-	/* Loop through the pages */
+-	len = instr->len;
+-
+-	instr->state = MTD_ERASING;
+-
+-	while (len) {
+-		/* Check if we have a bad block, we do not erase bad blocks! */
+-		if (nand_block_checkbad(mtd, ((loff_t) page) <<
+-					chip->page_shift, allowbbt)) {
+-			pr_warn("%s: attempt to erase a bad block at page 0x%08x\n",
+-				    __func__, page);
+-			instr->state = MTD_ERASE_FAILED;
+-			goto erase_exit;
+-		}
+-
+-		/*
+-		 * Invalidate the page cache, if we erase the block which
+-		 * contains the current cached page.
+-		 */
+-		if (page <= chip->pagebuf && chip->pagebuf <
+-		    (page + pages_per_block))
+-			chip->pagebuf = -1;
+-
+-		status = chip->erase(mtd, page & chip->pagemask);
+-
+-		/* See if block erase succeeded */
+-		if (status & NAND_STATUS_FAIL) {
+-			pr_debug("%s: failed erase, page 0x%08x\n",
+-					__func__, page);
+-			instr->state = MTD_ERASE_FAILED;
+-			instr->fail_addr =
+-				((loff_t)page << chip->page_shift);
+-			goto erase_exit;
+-		}
+-
+-		/* Increment page address and decrement length */
+-		len -= (1ULL << chip->phys_erase_shift);
+-		page += pages_per_block;
+-
+-		/* Check, if we cross a chip boundary */
+-		if (len && !(page & chip->pagemask)) {
+-			chipnr++;
+-			chip->select_chip(mtd, -1);
+-			chip->select_chip(mtd, chipnr);
+-		}
+-	}
+-	instr->state = MTD_ERASE_DONE;
+-
+-erase_exit:
+-
+-	ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO;
+-
+-	/* Deselect and wake up anyone waiting on the device */
+-	chip->select_chip(mtd, -1);
+-	nand_release_device(mtd);
+-
+-	/* Do call back function */
+-	if (!ret)
+-		mtd_erase_callback(instr);
+-
+-	/* Return more or less happy */
+-	return ret;
+-}
+-
+-/**
+- * nand_sync - [MTD Interface] sync
+- * @mtd: MTD device structure
+- *
+- * Sync is actually a wait for chip ready function.
+- */
+-static void nand_sync(struct mtd_info *mtd)
+-{
+-	pr_debug("%s: called\n", __func__);
+-
+-	/* Grab the lock and see if the device is available */
+-	nand_get_device(mtd, FL_SYNCING);
+-	/* Release it and go back */
+-	nand_release_device(mtd);
+-}
+-
+-/**
+- * nand_block_isbad - [MTD Interface] Check if block at offset is bad
+- * @mtd: MTD device structure
+- * @offs: offset relative to mtd start
+- */
+-static int nand_block_isbad(struct mtd_info *mtd, loff_t offs)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	int chipnr = (int)(offs >> chip->chip_shift);
+-	int ret;
+-
+-	/* Select the NAND device */
+-	nand_get_device(mtd, FL_READING);
+-	chip->select_chip(mtd, chipnr);
+-
+-	ret = nand_block_checkbad(mtd, offs, 0);
+-
+-	chip->select_chip(mtd, -1);
+-	nand_release_device(mtd);
+-
+-	return ret;
+-}
+-
+-/**
+- * nand_block_markbad - [MTD Interface] Mark block at the given offset as bad
+- * @mtd: MTD device structure
+- * @ofs: offset relative to mtd start
+- */
+-static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs)
+-{
+-	int ret;
+-
+-	ret = nand_block_isbad(mtd, ofs);
+-	if (ret) {
+-		/* If it was bad already, return success and do nothing */
+-		if (ret > 0)
+-			return 0;
+-		return ret;
+-	}
+-
+-	return nand_block_markbad_lowlevel(mtd, 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);
+-	u32 part_start_block;
+-	u32 part_end_block;
+-	u32 part_start_die;
+-	u32 part_end_die;
+-
+-	/*
+-	 * max_bb_per_die and blocks_per_die used to determine
+-	 * the maximum bad block count.
+-	 */
+-	if (!chip->max_bb_per_die || !chip->blocks_per_die)
+-		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_die = part_start_block / chip->blocks_per_die;
+-	part_end_die = part_end_block / chip->blocks_per_die;
+-
+-	/*
+-	 * Look up the bad blocks per unit and multiply by the number of units
+-	 * that the partition spans.
+-	 */
+-	return chip->max_bb_per_die * (part_end_die - part_start_die + 1);
+-}
+-
+-/**
+- * nand_onfi_set_features- [REPLACEABLE] set features for ONFI nand
+- * @mtd: MTD device structure
+- * @chip: nand chip info structure
+- * @addr: feature address.
+- * @subfeature_param: the subfeature parameters, a four bytes array.
+- */
+-static int nand_onfi_set_features(struct mtd_info *mtd, struct nand_chip *chip,
+-			int addr, uint8_t *subfeature_param)
+-{
+-	int status;
+-	int i;
+-
+-	if (!chip->onfi_version ||
+-	    !(le16_to_cpu(chip->onfi_params.opt_cmd)
+-	      & ONFI_OPT_CMD_SET_GET_FEATURES))
+-		return -EINVAL;
+-
+-	chip->cmdfunc(mtd, NAND_CMD_SET_FEATURES, addr, -1);
+-	for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
+-		chip->write_byte(mtd, subfeature_param[i]);
+-
+-	status = chip->waitfunc(mtd, chip);
+-	if (status & NAND_STATUS_FAIL)
+-		return -EIO;
+-	return 0;
+-}
+-
+-/**
+- * nand_onfi_get_features- [REPLACEABLE] get features for ONFI nand
+- * @mtd: MTD device structure
+- * @chip: nand chip info structure
+- * @addr: feature address.
+- * @subfeature_param: the subfeature parameters, a four bytes array.
+- */
+-static int nand_onfi_get_features(struct mtd_info *mtd, struct nand_chip *chip,
+-			int addr, uint8_t *subfeature_param)
+-{
+-	int i;
+-
+-	if (!chip->onfi_version ||
+-	    !(le16_to_cpu(chip->onfi_params.opt_cmd)
+-	      & ONFI_OPT_CMD_SET_GET_FEATURES))
+-		return -EINVAL;
+-
+-	chip->cmdfunc(mtd, NAND_CMD_GET_FEATURES, addr, -1);
+-	for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
+-		*subfeature_param++ = chip->read_byte(mtd);
+-	return 0;
+-}
+-
+-/**
+- * nand_onfi_get_set_features_notsupp - set/get features stub returning
+- *					-ENOTSUPP
+- * @mtd: MTD device structure
+- * @chip: nand chip info structure
+- * @addr: feature address.
+- * @subfeature_param: the subfeature parameters, a four bytes array.
+- *
+- * Should be used by NAND controller drivers that do not support the SET/GET
+- * FEATURES operations.
+- */
+-int nand_onfi_get_set_features_notsupp(struct mtd_info *mtd,
+-				       struct nand_chip *chip, int addr,
+-				       u8 *subfeature_param)
+-{
+-	return -ENOTSUPP;
+-}
+-EXPORT_SYMBOL(nand_onfi_get_set_features_notsupp);
+-
+-/**
+- * nand_suspend - [MTD Interface] Suspend the NAND flash
+- * @mtd: MTD device structure
+- */
+-static int nand_suspend(struct mtd_info *mtd)
+-{
+-	return nand_get_device(mtd, FL_PM_SUSPENDED);
+-}
+-
+-/**
+- * nand_resume - [MTD Interface] Resume the NAND flash
+- * @mtd: MTD device structure
+- */
+-static void nand_resume(struct mtd_info *mtd)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-
+-	if (chip->state == FL_PM_SUSPENDED)
+-		nand_release_device(mtd);
+-	else
+-		pr_err("%s called for a chip which is not in suspended state\n",
+-			__func__);
+-}
+-
+-/**
+- * nand_shutdown - [MTD Interface] Finish the current NAND operation and
+- *                 prevent further operations
+- * @mtd: MTD device structure
+- */
+-static void nand_shutdown(struct mtd_info *mtd)
+-{
+-	nand_get_device(mtd, FL_PM_SUSPENDED);
+-}
+-
+-/* Set default functions */
+-static void nand_set_defaults(struct nand_chip *chip)
+-{
+-	unsigned int busw = chip->options & NAND_BUSWIDTH_16;
+-
+-	/* check for proper chip_delay setup, set 20us if not */
+-	if (!chip->chip_delay)
+-		chip->chip_delay = 20;
+-
+-	/* check, if a user supplied command function given */
+-	if (chip->cmdfunc == NULL)
+-		chip->cmdfunc = nand_command;
+-
+-	/* check, if a user supplied wait function given */
+-	if (chip->waitfunc == NULL)
+-		chip->waitfunc = nand_wait;
+-
+-	if (!chip->select_chip)
+-		chip->select_chip = nand_select_chip;
+-
+-	/* set for ONFI nand */
+-	if (!chip->onfi_set_features)
+-		chip->onfi_set_features = nand_onfi_set_features;
+-	if (!chip->onfi_get_features)
+-		chip->onfi_get_features = nand_onfi_get_features;
+-
+-	/* If called twice, pointers that depend on busw may need to be reset */
+-	if (!chip->read_byte || chip->read_byte == nand_read_byte)
+-		chip->read_byte = busw ? nand_read_byte16 : nand_read_byte;
+-	if (!chip->read_word)
+-		chip->read_word = nand_read_word;
+-	if (!chip->block_bad)
+-		chip->block_bad = nand_block_bad;
+-	if (!chip->block_markbad)
+-		chip->block_markbad = nand_default_block_markbad;
+-	if (!chip->write_buf || chip->write_buf == nand_write_buf)
+-		chip->write_buf = busw ? nand_write_buf16 : nand_write_buf;
+-	if (!chip->write_byte || chip->write_byte == nand_write_byte)
+-		chip->write_byte = busw ? nand_write_byte16 : nand_write_byte;
+-	if (!chip->read_buf || chip->read_buf == nand_read_buf)
+-		chip->read_buf = busw ? nand_read_buf16 : nand_read_buf;
+-	if (!chip->scan_bbt)
+-		chip->scan_bbt = nand_default_bbt;
+-
+-	if (!chip->controller) {
+-		chip->controller = &chip->hwcontrol;
+-		nand_hw_control_init(chip->controller);
+-	}
+-
+-	if (!chip->buf_align)
+-		chip->buf_align = 1;
+-}
+-
+-/* Sanitize ONFI strings so we can safely print them */
+-static void sanitize_string(uint8_t *s, size_t len)
+-{
+-	ssize_t i;
+-
+-	/* Null terminate */
+-	s[len - 1] = 0;
+-
+-	/* Remove non printable chars */
+-	for (i = 0; i < len - 1; i++) {
+-		if (s[i] < ' ' || s[i] > 127)
+-			s[i] = '?';
+-	}
+-
+-	/* Remove trailing spaces */
+-	strim(s);
+-}
+-
+-static u16 onfi_crc16(u16 crc, u8 const *p, size_t len)
+-{
+-	int i;
+-	while (len--) {
+-		crc ^= *p++ << 8;
+-		for (i = 0; i < 8; i++)
+-			crc = (crc << 1) ^ ((crc & 0x8000) ? 0x8005 : 0);
+-	}
+-
+-	return crc;
+-}
+-
+-/* Parse the Extended Parameter Page. */
+-static int nand_flash_detect_ext_param_page(struct nand_chip *chip,
+-					    struct nand_onfi_params *p)
+-{
+-	struct mtd_info *mtd = nand_to_mtd(chip);
+-	struct onfi_ext_param_page *ep;
+-	struct onfi_ext_section *s;
+-	struct onfi_ext_ecc_info *ecc;
+-	uint8_t *cursor;
+-	int ret = -EINVAL;
+-	int len;
+-	int i;
+-
+-	len = le16_to_cpu(p->ext_param_page_length) * 16;
+-	ep = kmalloc(len, GFP_KERNEL);
+-	if (!ep)
+-		return -ENOMEM;
+-
+-	/* Send our own NAND_CMD_PARAM. */
+-	chip->cmdfunc(mtd, NAND_CMD_PARAM, 0, -1);
+-
+-	/* Use the Change Read Column command to skip the ONFI param pages. */
+-	chip->cmdfunc(mtd, NAND_CMD_RNDOUT,
+-			sizeof(*p) * p->num_of_param_pages , -1);
+-
+-	/* Read out the Extended Parameter Page. */
+-	chip->read_buf(mtd, (uint8_t *)ep, len);
+-	if ((onfi_crc16(ONFI_CRC_BASE, ((uint8_t *)ep) + 2, len - 2)
+-		!= le16_to_cpu(ep->crc))) {
+-		pr_debug("fail in the CRC.\n");
+-		goto ext_out;
+-	}
+-
+-	/*
+-	 * Check the signature.
+-	 * Do not strictly follow the ONFI spec, maybe changed in future.
+-	 */
+-	if (strncmp(ep->sig, "EPPS", 4)) {
+-		pr_debug("The signature is invalid.\n");
+-		goto ext_out;
+-	}
+-
+-	/* find the ECC section. */
+-	cursor = (uint8_t *)(ep + 1);
+-	for (i = 0; i < ONFI_EXT_SECTION_MAX; i++) {
+-		s = ep->sections + i;
+-		if (s->type == ONFI_SECTION_TYPE_2)
+-			break;
+-		cursor += s->length * 16;
+-	}
+-	if (i == ONFI_EXT_SECTION_MAX) {
+-		pr_debug("We can not find the ECC section.\n");
+-		goto ext_out;
+-	}
+-
+-	/* get the info we want. */
+-	ecc = (struct onfi_ext_ecc_info *)cursor;
+-
+-	if (!ecc->codeword_size) {
+-		pr_debug("Invalid codeword size\n");
+-		goto ext_out;
+-	}
+-
+-	chip->ecc_strength_ds = ecc->ecc_bits;
+-	chip->ecc_step_ds = 1 << ecc->codeword_size;
+-	ret = 0;
+-
+-ext_out:
+-	kfree(ep);
+-	return ret;
+-}
+-
+-/*
+- * Check if the NAND chip is ONFI compliant, returns 1 if it is, 0 otherwise.
+- */
+-static int nand_flash_detect_onfi(struct nand_chip *chip)
+-{
+-	struct mtd_info *mtd = nand_to_mtd(chip);
+-	struct nand_onfi_params *p = &chip->onfi_params;
+-	int i, j;
+-	int val;
+-
+-	/* Try ONFI for unknown chip or LP */
+-	chip->cmdfunc(mtd, NAND_CMD_READID, 0x20, -1);
+-	if (chip->read_byte(mtd) != 'O' || chip->read_byte(mtd) != 'N' ||
+-		chip->read_byte(mtd) != 'F' || chip->read_byte(mtd) != 'I')
+-		return 0;
+-
+-	chip->cmdfunc(mtd, NAND_CMD_PARAM, 0, -1);
+-	for (i = 0; i < 3; i++) {
+-		for (j = 0; j < sizeof(*p); j++)
+-			((uint8_t *)p)[j] = chip->read_byte(mtd);
+-		if (onfi_crc16(ONFI_CRC_BASE, (uint8_t *)p, 254) ==
+-				le16_to_cpu(p->crc)) {
+-			break;
+-		}
+-	}
+-
+-	if (i == 3) {
+-		pr_err("Could not find valid ONFI parameter page; aborting\n");
+-		return 0;
+-	}
+-
+-	/* Check version */
+-	val = le16_to_cpu(p->revision);
+-	if (val & (1 << 5))
+-		chip->onfi_version = 23;
+-	else if (val & (1 << 4))
+-		chip->onfi_version = 22;
+-	else if (val & (1 << 3))
+-		chip->onfi_version = 21;
+-	else if (val & (1 << 2))
+-		chip->onfi_version = 20;
+-	else if (val & (1 << 1))
+-		chip->onfi_version = 10;
+-
+-	if (!chip->onfi_version) {
+-		pr_info("unsupported ONFI version: %d\n", val);
+-		return 0;
+-	}
+-
+-	sanitize_string(p->manufacturer, sizeof(p->manufacturer));
+-	sanitize_string(p->model, sizeof(p->model));
+-	if (!mtd->name)
+-		mtd->name = p->model;
+-
+-	mtd->writesize = le32_to_cpu(p->byte_per_page);
+-
+-	/*
+-	 * pages_per_block and blocks_per_lun may not be a power-of-2 size
+-	 * (don't ask me who thought of this...). MTD assumes that these
+-	 * dimensions will be power-of-2, so just truncate the remaining area.
+-	 */
+-	mtd->erasesize = 1 << (fls(le32_to_cpu(p->pages_per_block)) - 1);
+-	mtd->erasesize *= mtd->writesize;
+-
+-	mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page);
+-
+-	/* See erasesize comment */
+-	chip->chipsize = 1 << (fls(le32_to_cpu(p->blocks_per_lun)) - 1);
+-	chip->chipsize *= (uint64_t)mtd->erasesize * p->lun_count;
+-	chip->bits_per_cell = p->bits_per_cell;
+-
+-	chip->max_bb_per_die = le16_to_cpu(p->bb_per_lun);
+-	chip->blocks_per_die = le32_to_cpu(p->blocks_per_lun);
+-
+-	if (onfi_feature(chip) & ONFI_FEATURE_16_BIT_BUS)
+-		chip->options |= NAND_BUSWIDTH_16;
+-
+-	if (p->ecc_bits != 0xff) {
+-		chip->ecc_strength_ds = p->ecc_bits;
+-		chip->ecc_step_ds = 512;
+-	} else if (chip->onfi_version >= 21 &&
+-		(onfi_feature(chip) & ONFI_FEATURE_EXT_PARAM_PAGE)) {
+-
+-		/*
+-		 * The nand_flash_detect_ext_param_page() uses the
+-		 * Change Read Column command which maybe not supported
+-		 * by the chip->cmdfunc. So try to update the chip->cmdfunc
+-		 * now. We do not replace user supplied command function.
+-		 */
+-		if (mtd->writesize > 512 && chip->cmdfunc == nand_command)
+-			chip->cmdfunc = nand_command_lp;
+-
+-		/* The Extended Parameter Page is supported since ONFI 2.1. */
+-		if (nand_flash_detect_ext_param_page(chip, p))
+-			pr_warn("Failed to detect ONFI extended param page\n");
+-	} else {
+-		pr_warn("Could not retrieve ONFI ECC requirements\n");
+-	}
+-
+-	return 1;
+-}
+-
+-/*
+- * Check if the NAND chip is JEDEC compliant, returns 1 if it is, 0 otherwise.
+- */
+-static int nand_flash_detect_jedec(struct nand_chip *chip)
+-{
+-	struct mtd_info *mtd = nand_to_mtd(chip);
+-	struct nand_jedec_params *p = &chip->jedec_params;
+-	struct jedec_ecc_info *ecc;
+-	int val;
+-	int i, j;
+-
+-	/* Try JEDEC for unknown chip or LP */
+-	chip->cmdfunc(mtd, NAND_CMD_READID, 0x40, -1);
+-	if (chip->read_byte(mtd) != 'J' || chip->read_byte(mtd) != 'E' ||
+-		chip->read_byte(mtd) != 'D' || chip->read_byte(mtd) != 'E' ||
+-		chip->read_byte(mtd) != 'C')
+-		return 0;
+-
+-	chip->cmdfunc(mtd, NAND_CMD_PARAM, 0x40, -1);
+-	for (i = 0; i < 3; i++) {
+-		for (j = 0; j < sizeof(*p); j++)
+-			((uint8_t *)p)[j] = chip->read_byte(mtd);
+-
+-		if (onfi_crc16(ONFI_CRC_BASE, (uint8_t *)p, 510) ==
+-				le16_to_cpu(p->crc))
+-			break;
+-	}
+-
+-	if (i == 3) {
+-		pr_err("Could not find valid JEDEC parameter page; aborting\n");
+-		return 0;
+-	}
+-
+-	/* Check version */
+-	val = le16_to_cpu(p->revision);
+-	if (val & (1 << 2))
+-		chip->jedec_version = 10;
+-	else if (val & (1 << 1))
+-		chip->jedec_version = 1; /* vendor specific version */
+-
+-	if (!chip->jedec_version) {
+-		pr_info("unsupported JEDEC version: %d\n", val);
+-		return 0;
+-	}
+-
+-	sanitize_string(p->manufacturer, sizeof(p->manufacturer));
+-	sanitize_string(p->model, sizeof(p->model));
+-	if (!mtd->name)
+-		mtd->name = p->model;
+-
+-	mtd->writesize = le32_to_cpu(p->byte_per_page);
+-
+-	/* Please reference to the comment for nand_flash_detect_onfi. */
+-	mtd->erasesize = 1 << (fls(le32_to_cpu(p->pages_per_block)) - 1);
+-	mtd->erasesize *= mtd->writesize;
+-
+-	mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page);
+-
+-	/* Please reference to the comment for nand_flash_detect_onfi. */
+-	chip->chipsize = 1 << (fls(le32_to_cpu(p->blocks_per_lun)) - 1);
+-	chip->chipsize *= (uint64_t)mtd->erasesize * p->lun_count;
+-	chip->bits_per_cell = p->bits_per_cell;
+-
+-	if (jedec_feature(chip) & JEDEC_FEATURE_16_BIT_BUS)
+-		chip->options |= NAND_BUSWIDTH_16;
+-
+-	/* ECC info */
+-	ecc = &p->ecc_info[0];
+-
+-	if (ecc->codeword_size >= 9) {
+-		chip->ecc_strength_ds = ecc->ecc_bits;
+-		chip->ecc_step_ds = 1 << ecc->codeword_size;
+-	} else {
+-		pr_warn("Invalid codeword size\n");
+-	}
+-
+-	return 1;
+-}
+-
+-/*
+- * nand_id_has_period - Check if an ID string has a given wraparound period
+- * @id_data: the ID string
+- * @arrlen: the length of the @id_data array
+- * @period: the period of repitition
+- *
+- * Check if an ID string is repeated within a given sequence of bytes at
+- * specific repetition interval period (e.g., {0x20,0x01,0x7F,0x20} has a
+- * period of 3). This is a helper function for nand_id_len(). Returns non-zero
+- * if the repetition has a period of @period; otherwise, returns zero.
+- */
+-static int nand_id_has_period(u8 *id_data, int arrlen, int period)
+-{
+-	int i, j;
+-	for (i = 0; i < period; i++)
+-		for (j = i + period; j < arrlen; j += period)
+-			if (id_data[i] != id_data[j])
+-				return 0;
+-	return 1;
+-}
+-
+-/*
+- * nand_id_len - Get the length of an ID string returned by CMD_READID
+- * @id_data: the ID string
+- * @arrlen: the length of the @id_data array
+-
+- * Returns the length of the ID string, according to known wraparound/trailing
+- * zero patterns. If no pattern exists, returns the length of the array.
+- */
+-static int nand_id_len(u8 *id_data, int arrlen)
+-{
+-	int last_nonzero, period;
+-
+-	/* Find last non-zero byte */
+-	for (last_nonzero = arrlen - 1; last_nonzero >= 0; last_nonzero--)
+-		if (id_data[last_nonzero])
+-			break;
+-
+-	/* All zeros */
+-	if (last_nonzero < 0)
+-		return 0;
+-
+-	/* Calculate wraparound period */
+-	for (period = 1; period < arrlen; period++)
+-		if (nand_id_has_period(id_data, arrlen, period))
+-			break;
+-
+-	/* There's a repeated pattern */
+-	if (period < arrlen)
+-		return period;
+-
+-	/* There are trailing zeros */
+-	if (last_nonzero < arrlen - 1)
+-		return last_nonzero + 1;
+-
+-	/* No pattern detected */
+-	return arrlen;
+-}
+-
+-/* Extract the bits of per cell from the 3rd byte of the extended ID */
+-static int nand_get_bits_per_cell(u8 cellinfo)
+-{
+-	int bits;
+-
+-	bits = cellinfo & NAND_CI_CELLTYPE_MSK;
+-	bits >>= NAND_CI_CELLTYPE_SHIFT;
+-	return bits + 1;
+-}
+-
+-/*
+- * Many new NAND share similar device ID codes, which represent the size of the
+- * chip. The rest of the parameters must be decoded according to generic or
+- * manufacturer-specific "extended ID" decoding patterns.
+- */
+-void nand_decode_ext_id(struct nand_chip *chip)
+-{
+-	struct mtd_info *mtd = nand_to_mtd(chip);
+-	int extid;
+-	u8 *id_data = chip->id.data;
+-	/* The 3rd id byte holds MLC / multichip data */
+-	chip->bits_per_cell = nand_get_bits_per_cell(id_data[2]);
+-	/* The 4th id byte is the important one */
+-	extid = id_data[3];
+-
+-	/* Calc pagesize */
+-	mtd->writesize = 1024 << (extid & 0x03);
+-	extid >>= 2;
+-	/* Calc oobsize */
+-	mtd->oobsize = (8 << (extid & 0x01)) * (mtd->writesize >> 9);
+-	extid >>= 2;
+-	/* Calc blocksize. Blocksize is multiples of 64KiB */
+-	mtd->erasesize = (64 * 1024) << (extid & 0x03);
+-	extid >>= 2;
+-	/* Get buswidth information */
+-	if (extid & 0x1)
+-		chip->options |= NAND_BUSWIDTH_16;
+-}
+-EXPORT_SYMBOL_GPL(nand_decode_ext_id);
+-
+-/*
+- * Old devices have chip data hardcoded in the device ID table. nand_decode_id
+- * decodes a matching ID table entry and assigns the MTD size parameters for
+- * the chip.
+- */
+-static void nand_decode_id(struct nand_chip *chip, struct nand_flash_dev *type)
+-{
+-	struct mtd_info *mtd = nand_to_mtd(chip);
+-
+-	mtd->erasesize = type->erasesize;
+-	mtd->writesize = type->pagesize;
+-	mtd->oobsize = mtd->writesize / 32;
+-
+-	/* All legacy ID NAND are small-page, SLC */
+-	chip->bits_per_cell = 1;
+-}
+-
+-/*
+- * Set the bad block marker/indicator (BBM/BBI) patterns according to some
+- * heuristic patterns using various detected parameters (e.g., manufacturer,
+- * page size, cell-type information).
+- */
+-static void nand_decode_bbm_options(struct nand_chip *chip)
+-{
+-	struct mtd_info *mtd = nand_to_mtd(chip);
+-
+-	/* Set the bad block position */
+-	if (mtd->writesize > 512 || (chip->options & NAND_BUSWIDTH_16))
+-		chip->badblockpos = NAND_LARGE_BADBLOCK_POS;
+-	else
+-		chip->badblockpos = NAND_SMALL_BADBLOCK_POS;
+-}
+-
+-static inline bool is_full_id_nand(struct nand_flash_dev *type)
+-{
+-	return type->id_len;
+-}
+-
+-static bool find_full_id_nand(struct nand_chip *chip,
+-			      struct nand_flash_dev *type)
+-{
+-	struct mtd_info *mtd = nand_to_mtd(chip);
+-	u8 *id_data = chip->id.data;
+-
+-	if (!strncmp(type->id, id_data, type->id_len)) {
+-		mtd->writesize = type->pagesize;
+-		mtd->erasesize = type->erasesize;
+-		mtd->oobsize = type->oobsize;
+-
+-		chip->bits_per_cell = nand_get_bits_per_cell(id_data[2]);
+-		chip->chipsize = (uint64_t)type->chipsize << 20;
+-		chip->options |= type->options;
+-		chip->ecc_strength_ds = NAND_ECC_STRENGTH(type);
+-		chip->ecc_step_ds = NAND_ECC_STEP(type);
+-		chip->onfi_timing_mode_default =
+-					type->onfi_timing_mode_default;
+-
+-		if (!mtd->name)
+-			mtd->name = type->name;
+-
+-		return true;
+-	}
+-	return false;
+-}
+-
+-/*
+- * Manufacturer detection. Only used when the NAND is not ONFI or JEDEC
+- * compliant and does not have a full-id or legacy-id entry in the nand_ids
+- * table.
+- */
+-static void nand_manufacturer_detect(struct nand_chip *chip)
+-{
+-	/*
+-	 * Try manufacturer detection if available and use
+-	 * nand_decode_ext_id() otherwise.
+-	 */
+-	if (chip->manufacturer.desc && chip->manufacturer.desc->ops &&
+-	    chip->manufacturer.desc->ops->detect) {
+-		/* The 3rd id byte holds MLC / multichip data */
+-		chip->bits_per_cell = nand_get_bits_per_cell(chip->id.data[2]);
+-		chip->manufacturer.desc->ops->detect(chip);
+-	} else {
+-		nand_decode_ext_id(chip);
+-	}
+-}
+-
+-/*
+- * Manufacturer initialization. This function is called for all NANDs including
+- * ONFI and JEDEC compliant ones.
+- * Manufacturer drivers should put all their specific initialization code in
+- * their ->init() hook.
+- */
+-static int nand_manufacturer_init(struct nand_chip *chip)
+-{
+-	if (!chip->manufacturer.desc || !chip->manufacturer.desc->ops ||
+-	    !chip->manufacturer.desc->ops->init)
+-		return 0;
+-
+-	return chip->manufacturer.desc->ops->init(chip);
+-}
+-
+-/*
+- * Manufacturer cleanup. This function is called for all NANDs including
+- * ONFI and JEDEC compliant ones.
+- * Manufacturer drivers should put all their specific cleanup code in their
+- * ->cleanup() hook.
+- */
+-static void nand_manufacturer_cleanup(struct nand_chip *chip)
+-{
+-	/* Release manufacturer private data */
+-	if (chip->manufacturer.desc && chip->manufacturer.desc->ops &&
+-	    chip->manufacturer.desc->ops->cleanup)
+-		chip->manufacturer.desc->ops->cleanup(chip);
+-}
+-
+-/*
+- * Get the flash and manufacturer id and lookup if the type is supported.
+- */
+-static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type)
+-{
+-	const struct nand_manufacturer *manufacturer;
+-	struct mtd_info *mtd = nand_to_mtd(chip);
+-	int busw;
+-	int i;
+-	u8 *id_data = chip->id.data;
+-	u8 maf_id, dev_id;
+-
+-	/*
+-	 * Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx)
+-	 * after power-up.
+-	 */
+-	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);
+-
+-	/* Read manufacturer and device IDs */
+-	maf_id = chip->read_byte(mtd);
+-	dev_id = chip->read_byte(mtd);
+-
+-	/*
+-	 * Try again to make sure, as some systems the bus-hold or other
+-	 * interface concerns can cause random data which looks like a
+-	 * possibly credible NAND flash to appear. If the two results do
+-	 * not match, ignore the device completely.
+-	 */
+-
+-	chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
+-
+-	/* Read entire ID string */
+-	for (i = 0; i < ARRAY_SIZE(chip->id.data); i++)
+-		id_data[i] = chip->read_byte(mtd);
+-
+-	if (id_data[0] != maf_id || id_data[1] != dev_id) {
+-		pr_info("second ID read did not match %02x,%02x against %02x,%02x\n",
+-			maf_id, dev_id, id_data[0], id_data[1]);
+-		return -ENODEV;
+-	}
+-
+-	chip->id.len = nand_id_len(id_data, ARRAY_SIZE(chip->id.data));
+-
+-	/* Try to identify manufacturer */
+-	manufacturer = nand_get_manufacturer(maf_id);
+-	chip->manufacturer.desc = manufacturer;
+-
+-	if (!type)
+-		type = nand_flash_ids;
+-
+-	/*
+-	 * Save the NAND_BUSWIDTH_16 flag before letting auto-detection logic
+-	 * override it.
+-	 * This is required to make sure initial NAND bus width set by the
+-	 * NAND controller driver is coherent with the real NAND bus width
+-	 * (extracted by auto-detection code).
+-	 */
+-	busw = chip->options & NAND_BUSWIDTH_16;
+-
+-	/*
+-	 * The flag is only set (never cleared), reset it to its default value
+-	 * before starting auto-detection.
+-	 */
+-	chip->options &= ~NAND_BUSWIDTH_16;
+-
+-	for (; type->name != NULL; type++) {
+-		if (is_full_id_nand(type)) {
+-			if (find_full_id_nand(chip, type))
+-				goto ident_done;
+-		} else if (dev_id == type->dev_id) {
+-			break;
+-		}
+-	}
+-
+-	chip->onfi_version = 0;
+-	if (!type->name || !type->pagesize) {
+-		/* Check if the chip is ONFI compliant */
+-		if (nand_flash_detect_onfi(chip))
+-			goto ident_done;
+-
+-		/* Check if the chip is JEDEC compliant */
+-		if (nand_flash_detect_jedec(chip))
+-			goto ident_done;
+-	}
+-
+-	if (!type->name)
+-		return -ENODEV;
+-
+-	if (!mtd->name)
+-		mtd->name = type->name;
+-
+-	chip->chipsize = (uint64_t)type->chipsize << 20;
+-
+-	if (!type->pagesize)
+-		nand_manufacturer_detect(chip);
+-	else
+-		nand_decode_id(chip, type);
+-
+-	/* Get chip options */
+-	chip->options |= type->options;
+-
+-ident_done:
+-
+-	if (chip->options & NAND_BUSWIDTH_AUTO) {
+-		WARN_ON(busw & NAND_BUSWIDTH_16);
+-		nand_set_defaults(chip);
+-	} else if (busw != (chip->options & NAND_BUSWIDTH_16)) {
+-		/*
+-		 * Check, if buswidth is correct. Hardware drivers should set
+-		 * chip correct!
+-		 */
+-		pr_info("device found, Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n",
+-			maf_id, dev_id);
+-		pr_info("%s %s\n", nand_manufacturer_name(manufacturer),
+-			mtd->name);
+-		pr_warn("bus width %d instead of %d bits\n", busw ? 16 : 8,
+-			(chip->options & NAND_BUSWIDTH_16) ? 16 : 8);
+-		return -EINVAL;
+-	}
+-
+-	nand_decode_bbm_options(chip);
+-
+-	/* Calculate the address shift from the page size */
+-	chip->page_shift = ffs(mtd->writesize) - 1;
+-	/* Convert chipsize to number of pages per chip -1 */
+-	chip->pagemask = (chip->chipsize >> chip->page_shift) - 1;
+-
+-	chip->bbt_erase_shift = chip->phys_erase_shift =
+-		ffs(mtd->erasesize) - 1;
+-	if (chip->chipsize & 0xffffffff)
+-		chip->chip_shift = ffs((unsigned)chip->chipsize) - 1;
+-	else {
+-		chip->chip_shift = ffs((unsigned)(chip->chipsize >> 32));
+-		chip->chip_shift += 32 - 1;
+-	}
+-
+-	chip->badblockbits = 8;
+-	chip->erase = single_erase;
+-
+-	/* Do not replace user supplied command function! */
+-	if (mtd->writesize > 512 && chip->cmdfunc == nand_command)
+-		chip->cmdfunc = nand_command_lp;
+-
+-	pr_info("device found, Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n",
+-		maf_id, dev_id);
+-
+-	if (chip->onfi_version)
+-		pr_info("%s %s\n", nand_manufacturer_name(manufacturer),
+-			chip->onfi_params.model);
+-	else if (chip->jedec_version)
+-		pr_info("%s %s\n", nand_manufacturer_name(manufacturer),
+-			chip->jedec_params.model);
+-	else
+-		pr_info("%s %s\n", nand_manufacturer_name(manufacturer),
+-			type->name);
+-
+-	pr_info("%d MiB, %s, erase size: %d KiB, page size: %d, OOB size: %d\n",
+-		(int)(chip->chipsize >> 20), nand_is_slc(chip) ? "SLC" : "MLC",
+-		mtd->erasesize >> 10, mtd->writesize, mtd->oobsize);
+-	return 0;
+-}
+-
+-static const char * const nand_ecc_modes[] = {
+-	[NAND_ECC_NONE]		= "none",
+-	[NAND_ECC_SOFT]		= "soft",
+-	[NAND_ECC_HW]		= "hw",
+-	[NAND_ECC_HW_SYNDROME]	= "hw_syndrome",
+-	[NAND_ECC_HW_OOB_FIRST]	= "hw_oob_first",
+-	[NAND_ECC_ON_DIE]	= "on-die",
+-};
+-
+-static int of_get_nand_ecc_mode(struct device_node *np)
+-{
+-	const char *pm;
+-	int err, i;
+-
+-	err = of_property_read_string(np, "nand-ecc-mode", &pm);
+-	if (err < 0)
+-		return err;
+-
+-	for (i = 0; i < ARRAY_SIZE(nand_ecc_modes); i++)
+-		if (!strcasecmp(pm, nand_ecc_modes[i]))
+-			return i;
+-
+-	/*
+-	 * For backward compatibility we support few obsoleted values that don't
+-	 * have their mappings into nand_ecc_modes_t anymore (they were merged
+-	 * with other enums).
+-	 */
+-	if (!strcasecmp(pm, "soft_bch"))
+-		return NAND_ECC_SOFT;
+-
+-	return -ENODEV;
+-}
+-
+-static const char * const nand_ecc_algos[] = {
+-	[NAND_ECC_HAMMING]	= "hamming",
+-	[NAND_ECC_BCH]		= "bch",
+-};
+-
+-static int of_get_nand_ecc_algo(struct device_node *np)
+-{
+-	const char *pm;
+-	int err, i;
+-
+-	err = of_property_read_string(np, "nand-ecc-algo", &pm);
+-	if (!err) {
+-		for (i = NAND_ECC_HAMMING; i < ARRAY_SIZE(nand_ecc_algos); i++)
+-			if (!strcasecmp(pm, nand_ecc_algos[i]))
+-				return i;
+-		return -ENODEV;
+-	}
+-
+-	/*
+-	 * For backward compatibility we also read "nand-ecc-mode" checking
+-	 * for some obsoleted values that were specifying ECC algorithm.
+-	 */
+-	err = of_property_read_string(np, "nand-ecc-mode", &pm);
+-	if (err < 0)
+-		return err;
+-
+-	if (!strcasecmp(pm, "soft"))
+-		return NAND_ECC_HAMMING;
+-	else if (!strcasecmp(pm, "soft_bch"))
+-		return NAND_ECC_BCH;
+-
+-	return -ENODEV;
+-}
+-
+-static int of_get_nand_ecc_step_size(struct device_node *np)
+-{
+-	int ret;
+-	u32 val;
+-
+-	ret = of_property_read_u32(np, "nand-ecc-step-size", &val);
+-	return ret ? ret : val;
+-}
+-
+-static int of_get_nand_ecc_strength(struct device_node *np)
+-{
+-	int ret;
+-	u32 val;
+-
+-	ret = of_property_read_u32(np, "nand-ecc-strength", &val);
+-	return ret ? ret : val;
+-}
+-
+-static int of_get_nand_bus_width(struct device_node *np)
+-{
+-	u32 val;
+-
+-	if (of_property_read_u32(np, "nand-bus-width", &val))
+-		return 8;
+-
+-	switch (val) {
+-	case 8:
+-	case 16:
+-		return val;
+-	default:
+-		return -EIO;
+-	}
+-}
+-
+-static bool of_get_nand_on_flash_bbt(struct device_node *np)
+-{
+-	return of_property_read_bool(np, "nand-on-flash-bbt");
+-}
+-
+-static int nand_dt_init(struct nand_chip *chip)
+-{
+-	struct device_node *dn = nand_get_flash_node(chip);
+-	int ecc_mode, ecc_algo, ecc_strength, ecc_step;
+-
+-	if (!dn)
+-		return 0;
+-
+-	if (of_get_nand_bus_width(dn) == 16)
+-		chip->options |= NAND_BUSWIDTH_16;
+-
+-	if (of_get_nand_on_flash_bbt(dn))
+-		chip->bbt_options |= NAND_BBT_USE_FLASH;
+-
+-	ecc_mode = of_get_nand_ecc_mode(dn);
+-	ecc_algo = of_get_nand_ecc_algo(dn);
+-	ecc_strength = of_get_nand_ecc_strength(dn);
+-	ecc_step = of_get_nand_ecc_step_size(dn);
+-
+-	if (ecc_mode >= 0)
+-		chip->ecc.mode = ecc_mode;
+-
+-	if (ecc_algo >= 0)
+-		chip->ecc.algo = ecc_algo;
+-
+-	if (ecc_strength >= 0)
+-		chip->ecc.strength = ecc_strength;
+-
+-	if (ecc_step > 0)
+-		chip->ecc.size = ecc_step;
+-
+-	if (of_property_read_bool(dn, "nand-ecc-maximize"))
+-		chip->ecc.options |= NAND_ECC_MAXIMIZE;
+-
+-	return 0;
+-}
+-
+-/**
+- * nand_scan_ident - [NAND Interface] Scan for the NAND device
+- * @mtd: MTD device structure
+- * @maxchips: number of chips to scan for
+- * @table: alternative NAND ID table
+- *
+- * This is the first phase of the normal nand_scan() function. It reads the
+- * flash ID and sets up MTD fields accordingly.
+- *
+- */
+-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);
+-	int ret;
+-
+-	ret = nand_dt_init(chip);
+-	if (ret)
+-		return ret;
+-
+-	if (!mtd->name && mtd->dev.parent)
+-		mtd->name = dev_name(mtd->dev.parent);
+-
+-	if ((!chip->cmdfunc || !chip->select_chip) && !chip->cmd_ctrl) {
+-		/*
+-		 * Default functions assigned for chip_select() and
+-		 * cmdfunc() both expect cmd_ctrl() to be populated,
+-		 * so we need to check that that's the case
+-		 */
+-		pr_err("chip.cmd_ctrl() callback is not provided");
+-		return -EINVAL;
+-	}
+-	/* Set the default functions */
+-	nand_set_defaults(chip);
+-
+-	/* Read the flash type */
+-	ret = nand_detect(chip, table);
+-	if (ret) {
+-		if (!(chip->options & NAND_SCAN_SILENT_NODEV))
+-			pr_warn("No NAND device found\n");
+-		chip->select_chip(mtd, -1);
+-		return ret;
+-	}
+-
+-	nand_maf_id = chip->id.data[0];
+-	nand_dev_id = chip->id.data[1];
+-
+-	chip->select_chip(mtd, -1);
+-
+-	/* Check for a chip array */
+-	for (i = 1; i < maxchips; i++) {
+-		/* See comment in nand_get_flash_type for reset */
+-		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 */
+-		if (nand_maf_id != chip->read_byte(mtd) ||
+-		    nand_dev_id != chip->read_byte(mtd)) {
+-			chip->select_chip(mtd, -1);
+-			break;
+-		}
+-		chip->select_chip(mtd, -1);
+-	}
+-	if (i > 1)
+-		pr_info("%d chips detected\n", i);
+-
+-	/* Store the number of chips and calc total size for mtd */
+-	chip->numchips = i;
+-	mtd->size = i * chip->chipsize;
+-
+-	return 0;
+-}
+-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_ecc_ctrl *ecc = &chip->ecc;
+-
+-	if (WARN_ON(ecc->mode != NAND_ECC_SOFT))
+-		return -EINVAL;
+-
+-	switch (ecc->algo) {
+-	case NAND_ECC_HAMMING:
+-		ecc->calculate = nand_calculate_ecc;
+-		ecc->correct = nand_correct_data;
+-		ecc->read_page = nand_read_page_swecc;
+-		ecc->read_subpage = nand_read_subpage;
+-		ecc->write_page = nand_write_page_swecc;
+-		ecc->read_page_raw = nand_read_page_raw;
+-		ecc->write_page_raw = nand_write_page_raw;
+-		ecc->read_oob = nand_read_oob_std;
+-		ecc->write_oob = nand_write_oob_std;
+-		if (!ecc->size)
+-			ecc->size = 256;
+-		ecc->bytes = 3;
+-		ecc->strength = 1;
+-		return 0;
+-	case NAND_ECC_BCH:
+-		if (!mtd_nand_has_bch()) {
+-			WARN(1, "CONFIG_MTD_NAND_ECC_BCH not enabled\n");
+-			return -EINVAL;
+-		}
+-		ecc->calculate = nand_bch_calculate_ecc;
+-		ecc->correct = nand_bch_correct_data;
+-		ecc->read_page = nand_read_page_swecc;
+-		ecc->read_subpage = nand_read_subpage;
+-		ecc->write_page = nand_write_page_swecc;
+-		ecc->read_page_raw = nand_read_page_raw;
+-		ecc->write_page_raw = nand_write_page_raw;
+-		ecc->read_oob = nand_read_oob_std;
+-		ecc->write_oob = nand_write_oob_std;
+-
+-		/*
+-		* Board driver should supply ecc.size and ecc.strength
+-		* values to select how many bits are correctable.
+-		* Otherwise, default to 4 bits for large page devices.
+-		*/
+-		if (!ecc->size && (mtd->oobsize >= 64)) {
+-			ecc->size = 512;
+-			ecc->strength = 4;
+-		}
+-
+-		/*
+-		 * if no ecc placement scheme was provided pickup the default
+-		 * large page one.
+-		 */
+-		if (!mtd->ooblayout) {
+-			/* handle large page devices only */
+-			if (mtd->oobsize < 64) {
+-				WARN(1, "OOB layout is required when using software BCH on small pages\n");
+-				return -EINVAL;
+-			}
+-
+-			mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
+-
+-		}
+-
+-		/*
+-		 * We can only maximize ECC config when the default layout is
+-		 * used, otherwise we don't know how many bytes can really be
+-		 * used.
+-		 */
+-		if (mtd->ooblayout == &nand_ooblayout_lp_ops &&
+-		    ecc->options & NAND_ECC_MAXIMIZE) {
+-			int steps, bytes;
+-
+-			/* Always prefer 1k blocks over 512bytes ones */
+-			ecc->size = 1024;
+-			steps = mtd->writesize / ecc->size;
+-
+-			/* Reserve 2 bytes for the BBM */
+-			bytes = (mtd->oobsize - 2) / steps;
+-			ecc->strength = bytes * 8 / fls(8 * ecc->size);
+-		}
+-
+-		/* See nand_bch_init() for details. */
+-		ecc->bytes = 0;
+-		ecc->priv = nand_bch_init(mtd);
+-		if (!ecc->priv) {
+-			WARN(1, "BCH ECC initialization failed!\n");
+-			return -EINVAL;
+-		}
+-		return 0;
+-	default:
+-		WARN(1, "Unsupported ECC algorithm!\n");
+-		return -EINVAL;
+-	}
+-}
+-
+-/**
+- * nand_check_ecc_caps - check the sanity of preset ECC settings
+- * @chip: nand chip info structure
+- * @caps: ECC caps info structure
+- * @oobavail: OOB size that the ECC engine can use
+- *
+- * When ECC step size and strength are already set, check if they are supported
+- * by the controller and the calculated ECC bytes fit within the chip's OOB.
+- * On success, the calculated ECC bytes is set.
+- */
+-int nand_check_ecc_caps(struct nand_chip *chip,
+-			const struct nand_ecc_caps *caps, int oobavail)
+-{
+-	struct mtd_info *mtd = nand_to_mtd(chip);
+-	const struct nand_ecc_step_info *stepinfo;
+-	int preset_step = chip->ecc.size;
+-	int preset_strength = chip->ecc.strength;
+-	int nsteps, ecc_bytes;
+-	int i, j;
+-
+-	if (WARN_ON(oobavail < 0))
+-		return -EINVAL;
+-
+-	if (!preset_step || !preset_strength)
+-		return -ENODATA;
+-
+-	nsteps = mtd->writesize / preset_step;
+-
+-	for (i = 0; i < caps->nstepinfos; i++) {
+-		stepinfo = &caps->stepinfos[i];
+-
+-		if (stepinfo->stepsize != preset_step)
+-			continue;
+-
+-		for (j = 0; j < stepinfo->nstrengths; j++) {
+-			if (stepinfo->strengths[j] != preset_strength)
+-				continue;
+-
+-			ecc_bytes = caps->calc_ecc_bytes(preset_step,
+-							 preset_strength);
+-			if (WARN_ON_ONCE(ecc_bytes < 0))
+-				return ecc_bytes;
+-
+-			if (ecc_bytes * nsteps > oobavail) {
+-				pr_err("ECC (step, strength) = (%d, %d) does not fit in OOB",
+-				       preset_step, preset_strength);
+-				return -ENOSPC;
+-			}
+-
+-			chip->ecc.bytes = ecc_bytes;
+-
+-			return 0;
+-		}
+-	}
+-
+-	pr_err("ECC (step, strength) = (%d, %d) not supported on this controller",
+-	       preset_step, preset_strength);
+-
+-	return -ENOTSUPP;
+-}
+-EXPORT_SYMBOL_GPL(nand_check_ecc_caps);
+-
+-/**
+- * nand_match_ecc_req - meet the chip's requirement with least ECC bytes
+- * @chip: nand chip info structure
+- * @caps: ECC engine caps info structure
+- * @oobavail: OOB size that the ECC engine can use
+- *
+- * If a chip's ECC requirement is provided, try to meet it with the least
+- * number of ECC bytes (i.e. with the largest number of OOB-free bytes).
+- * On success, the chosen ECC settings are set.
+- */
+-int nand_match_ecc_req(struct nand_chip *chip,
+-		       const struct nand_ecc_caps *caps, int oobavail)
+-{
+-	struct mtd_info *mtd = nand_to_mtd(chip);
+-	const struct nand_ecc_step_info *stepinfo;
+-	int req_step = chip->ecc_step_ds;
+-	int req_strength = chip->ecc_strength_ds;
+-	int req_corr, step_size, strength, nsteps, ecc_bytes, ecc_bytes_total;
+-	int best_step, best_strength, best_ecc_bytes;
+-	int best_ecc_bytes_total = INT_MAX;
+-	int i, j;
+-
+-	if (WARN_ON(oobavail < 0))
+-		return -EINVAL;
+-
+-	/* No information provided by the NAND chip */
+-	if (!req_step || !req_strength)
+-		return -ENOTSUPP;
+-
+-	/* number of correctable bits the chip requires in a page */
+-	req_corr = mtd->writesize / req_step * req_strength;
+-
+-	for (i = 0; i < caps->nstepinfos; i++) {
+-		stepinfo = &caps->stepinfos[i];
+-		step_size = stepinfo->stepsize;
+-
+-		for (j = 0; j < stepinfo->nstrengths; j++) {
+-			strength = stepinfo->strengths[j];
+-
+-			/*
+-			 * If both step size and strength are smaller than the
+-			 * chip's requirement, it is not easy to compare the
+-			 * resulted reliability.
+-			 */
+-			if (step_size < req_step && strength < req_strength)
+-				continue;
+-
+-			if (mtd->writesize % step_size)
+-				continue;
+-
+-			nsteps = mtd->writesize / step_size;
+-
+-			ecc_bytes = caps->calc_ecc_bytes(step_size, strength);
+-			if (WARN_ON_ONCE(ecc_bytes < 0))
+-				continue;
+-			ecc_bytes_total = ecc_bytes * nsteps;
+-
+-			if (ecc_bytes_total > oobavail ||
+-			    strength * nsteps < req_corr)
+-				continue;
+-
+-			/*
+-			 * We assume the best is to meet the chip's requrement
+-			 * with the least number of ECC bytes.
+-			 */
+-			if (ecc_bytes_total < best_ecc_bytes_total) {
+-				best_ecc_bytes_total = ecc_bytes_total;
+-				best_step = step_size;
+-				best_strength = strength;
+-				best_ecc_bytes = ecc_bytes;
+-			}
+-		}
+-	}
+-
+-	if (best_ecc_bytes_total == INT_MAX)
+-		return -ENOTSUPP;
+-
+-	chip->ecc.size = best_step;
+-	chip->ecc.strength = best_strength;
+-	chip->ecc.bytes = best_ecc_bytes;
+-
+-	return 0;
+-}
+-EXPORT_SYMBOL_GPL(nand_match_ecc_req);
+-
+-/**
+- * nand_maximize_ecc - choose the max ECC strength available
+- * @chip: nand chip info structure
+- * @caps: ECC engine caps info structure
+- * @oobavail: OOB size that the ECC engine can use
+- *
+- * Choose the max ECC strength that is supported on the controller, and can fit
+- * within the chip's OOB.  On success, the chosen ECC settings are set.
+- */
+-int nand_maximize_ecc(struct nand_chip *chip,
+-		      const struct nand_ecc_caps *caps, int oobavail)
+-{
+-	struct mtd_info *mtd = nand_to_mtd(chip);
+-	const struct nand_ecc_step_info *stepinfo;
+-	int step_size, strength, nsteps, ecc_bytes, corr;
+-	int best_corr = 0;
+-	int best_step = 0;
+-	int best_strength, best_ecc_bytes;
+-	int i, j;
+-
+-	if (WARN_ON(oobavail < 0))
+-		return -EINVAL;
+-
+-	for (i = 0; i < caps->nstepinfos; i++) {
+-		stepinfo = &caps->stepinfos[i];
+-		step_size = stepinfo->stepsize;
+-
+-		/* If chip->ecc.size is already set, respect it */
+-		if (chip->ecc.size && step_size != chip->ecc.size)
+-			continue;
+-
+-		for (j = 0; j < stepinfo->nstrengths; j++) {
+-			strength = stepinfo->strengths[j];
+-
+-			if (mtd->writesize % step_size)
+-				continue;
+-
+-			nsteps = mtd->writesize / step_size;
+-
+-			ecc_bytes = caps->calc_ecc_bytes(step_size, strength);
+-			if (WARN_ON_ONCE(ecc_bytes < 0))
+-				continue;
+-
+-			if (ecc_bytes * nsteps > oobavail)
+-				continue;
+-
+-			corr = strength * nsteps;
+-
+-			/*
+-			 * If the number of correctable bits is the same,
+-			 * bigger step_size has more reliability.
+-			 */
+-			if (corr > best_corr ||
+-			    (corr == best_corr && step_size > best_step)) {
+-				best_corr = corr;
+-				best_step = step_size;
+-				best_strength = strength;
+-				best_ecc_bytes = ecc_bytes;
+-			}
+-		}
+-	}
+-
+-	if (!best_corr)
+-		return -ENOTSUPP;
+-
+-	chip->ecc.size = best_step;
+-	chip->ecc.strength = best_strength;
+-	chip->ecc.bytes = best_ecc_bytes;
+-
+-	return 0;
+-}
+-EXPORT_SYMBOL_GPL(nand_maximize_ecc);
+-
+-/*
+- * Check if the chip configuration meet the datasheet requirements.
+-
+- * If our configuration corrects A bits per B bytes and the minimum
+- * required correction level is X bits per Y bytes, then we must ensure
+- * both of the following are true:
+- *
+- * (1) A / B >= X / Y
+- * (2) A >= X
+- *
+- * Requirement (1) ensures we can correct for the required bitflip density.
+- * Requirement (2) ensures we can correct even when all bitflips are clumped
+- * in the same sector.
+- */
+-static bool nand_ecc_strength_good(struct mtd_info *mtd)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct nand_ecc_ctrl *ecc = &chip->ecc;
+-	int corr, ds_corr;
+-
+-	if (ecc->size == 0 || chip->ecc_step_ds == 0)
+-		/* Not enough information */
+-		return true;
+-
+-	/*
+-	 * We get the number of corrected bits per page to compare
+-	 * the correction density.
+-	 */
+-	corr = (mtd->writesize * ecc->strength) / ecc->size;
+-	ds_corr = (mtd->writesize * chip->ecc_strength_ds) / chip->ecc_step_ds;
+-
+-	return corr >= ds_corr && ecc->strength >= chip->ecc_strength_ds;
+-}
+-
+-static bool invalid_ecc_page_accessors(struct nand_chip *chip)
+-{
+-	struct nand_ecc_ctrl *ecc = &chip->ecc;
+-
+-	if (nand_standard_page_accessors(ecc))
+-		return false;
+-
+-	/*
+-	 * NAND_ECC_CUSTOM_PAGE_ACCESS flag is set, make sure the NAND
+-	 * controller driver implements all the page accessors because
+-	 * default helpers are not suitable when the core does not
+-	 * send the READ0/PAGEPROG commands.
+-	 */
+-	return (!ecc->read_page || !ecc->write_page ||
+-		!ecc->read_page_raw || !ecc->write_page_raw ||
+-		(NAND_HAS_SUBPAGE_READ(chip) && !ecc->read_subpage) ||
+-		(NAND_HAS_SUBPAGE_WRITE(chip) && !ecc->write_subpage &&
+-		 ecc->hwctl && ecc->calculate));
+-}
+-
+-/**
+- * nand_scan_tail - [NAND Interface] Scan for the NAND device
+- * @mtd: MTD device structure
+- *
+- * This is the second phase of the normal nand_scan() function. It fills out
+- * all the uninitialized function pointers with the defaults and scans for a
+- * bad block table if appropriate.
+- */
+-int nand_scan_tail(struct mtd_info *mtd)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct nand_ecc_ctrl *ecc = &chip->ecc;
+-	struct nand_buffers *nbuf = NULL;
+-	int ret, i;
+-
+-	/* New bad blocks should be marked in OOB, flash-based BBT, or both */
+-	if (WARN_ON((chip->bbt_options & NAND_BBT_NO_OOB_BBM) &&
+-		   !(chip->bbt_options & NAND_BBT_USE_FLASH))) {
+-		return -EINVAL;
+-	}
+-
+-	if (invalid_ecc_page_accessors(chip)) {
+-		pr_err("Invalid ECC page accessors setup\n");
+-		return -EINVAL;
+-	}
+-
+-	if (!(chip->options & NAND_OWN_BUFFERS)) {
+-		nbuf = kzalloc(sizeof(*nbuf), GFP_KERNEL);
+-		if (!nbuf)
+-			return -ENOMEM;
+-
+-		nbuf->ecccalc = kmalloc(mtd->oobsize, GFP_KERNEL);
+-		if (!nbuf->ecccalc) {
+-			ret = -ENOMEM;
+-			goto err_free_nbuf;
+-		}
+-
+-		nbuf->ecccode = kmalloc(mtd->oobsize, GFP_KERNEL);
+-		if (!nbuf->ecccode) {
+-			ret = -ENOMEM;
+-			goto err_free_nbuf;
+-		}
+-
+-		nbuf->databuf = kmalloc(mtd->writesize + mtd->oobsize,
+-					GFP_KERNEL);
+-		if (!nbuf->databuf) {
+-			ret = -ENOMEM;
+-			goto err_free_nbuf;
+-		}
+-
+-		chip->buffers = nbuf;
+-	} else if (!chip->buffers) {
+-		return -ENOMEM;
+-	}
+-
+-	/*
+-	 * FIXME: some NAND manufacturer drivers expect the first die to be
+-	 * selected when manufacturer->init() is called. They should be fixed
+-	 * to explictly select the relevant die when interacting with the NAND
+-	 * chip.
+-	 */
+-	chip->select_chip(mtd, 0);
+-	ret = nand_manufacturer_init(chip);
+-	chip->select_chip(mtd, -1);
+-	if (ret)
+-		goto err_free_nbuf;
+-
+-	/* Set the internal oob buffer location, just after the page data */
+-	chip->oob_poi = chip->buffers->databuf + mtd->writesize;
+-
+-	/*
+-	 * If no default placement scheme is given, select an appropriate one.
+-	 */
+-	if (!mtd->ooblayout &&
+-	    !(ecc->mode == NAND_ECC_SOFT && ecc->algo == NAND_ECC_BCH)) {
+-		switch (mtd->oobsize) {
+-		case 8:
+-		case 16:
+-			mtd_set_ooblayout(mtd, &nand_ooblayout_sp_ops);
+-			break;
+-		case 64:
+-		case 128:
+-			mtd_set_ooblayout(mtd, &nand_ooblayout_lp_hamming_ops);
+-			break;
+-		default:
+-			WARN(1, "No oob scheme defined for oobsize %d\n",
+-				mtd->oobsize);
+-			ret = -EINVAL;
+-			goto err_nand_manuf_cleanup;
+-		}
+-	}
+-
+-	/*
+-	 * Check ECC mode, default to software if 3byte/512byte hardware ECC is
+-	 * selected and we have 256 byte pagesize fallback to software ECC
+-	 */
+-
+-	switch (ecc->mode) {
+-	case NAND_ECC_HW_OOB_FIRST:
+-		/* Similar to NAND_ECC_HW, but a separate read_page handle */
+-		if (!ecc->calculate || !ecc->correct || !ecc->hwctl) {
+-			WARN(1, "No ECC functions supplied; hardware ECC not possible\n");
+-			ret = -EINVAL;
+-			goto err_nand_manuf_cleanup;
+-		}
+-		if (!ecc->read_page)
+-			ecc->read_page = nand_read_page_hwecc_oob_first;
+-
+-	case NAND_ECC_HW:
+-		/* Use standard hwecc read page function? */
+-		if (!ecc->read_page)
+-			ecc->read_page = nand_read_page_hwecc;
+-		if (!ecc->write_page)
+-			ecc->write_page = nand_write_page_hwecc;
+-		if (!ecc->read_page_raw)
+-			ecc->read_page_raw = nand_read_page_raw;
+-		if (!ecc->write_page_raw)
+-			ecc->write_page_raw = nand_write_page_raw;
+-		if (!ecc->read_oob)
+-			ecc->read_oob = nand_read_oob_std;
+-		if (!ecc->write_oob)
+-			ecc->write_oob = nand_write_oob_std;
+-		if (!ecc->read_subpage)
+-			ecc->read_subpage = nand_read_subpage;
+-		if (!ecc->write_subpage && ecc->hwctl && ecc->calculate)
+-			ecc->write_subpage = nand_write_subpage_hwecc;
+-
+-	case NAND_ECC_HW_SYNDROME:
+-		if ((!ecc->calculate || !ecc->correct || !ecc->hwctl) &&
+-		    (!ecc->read_page ||
+-		     ecc->read_page == nand_read_page_hwecc ||
+-		     !ecc->write_page ||
+-		     ecc->write_page == nand_write_page_hwecc)) {
+-			WARN(1, "No ECC functions supplied; hardware ECC not possible\n");
+-			ret = -EINVAL;
+-			goto err_nand_manuf_cleanup;
+-		}
+-		/* Use standard syndrome read/write page function? */
+-		if (!ecc->read_page)
+-			ecc->read_page = nand_read_page_syndrome;
+-		if (!ecc->write_page)
+-			ecc->write_page = nand_write_page_syndrome;
+-		if (!ecc->read_page_raw)
+-			ecc->read_page_raw = nand_read_page_raw_syndrome;
+-		if (!ecc->write_page_raw)
+-			ecc->write_page_raw = nand_write_page_raw_syndrome;
+-		if (!ecc->read_oob)
+-			ecc->read_oob = nand_read_oob_syndrome;
+-		if (!ecc->write_oob)
+-			ecc->write_oob = nand_write_oob_syndrome;
+-
+-		if (mtd->writesize >= ecc->size) {
+-			if (!ecc->strength) {
+-				WARN(1, "Driver must set ecc.strength when using hardware ECC\n");
+-				ret = -EINVAL;
+-				goto err_nand_manuf_cleanup;
+-			}
+-			break;
+-		}
+-		pr_warn("%d byte HW ECC not possible on %d byte page size, fallback to SW ECC\n",
+-			ecc->size, mtd->writesize);
+-		ecc->mode = NAND_ECC_SOFT;
+-		ecc->algo = NAND_ECC_HAMMING;
+-
+-	case NAND_ECC_SOFT:
+-		ret = nand_set_ecc_soft_ops(mtd);
+-		if (ret) {
+-			ret = -EINVAL;
+-			goto err_nand_manuf_cleanup;
+-		}
+-		break;
+-
+-	case NAND_ECC_ON_DIE:
+-		if (!ecc->read_page || !ecc->write_page) {
+-			WARN(1, "No ECC functions supplied; on-die ECC not possible\n");
+-			ret = -EINVAL;
+-			goto err_nand_manuf_cleanup;
+-		}
+-		if (!ecc->read_oob)
+-			ecc->read_oob = nand_read_oob_std;
+-		if (!ecc->write_oob)
+-			ecc->write_oob = nand_write_oob_std;
+-		break;
+-
+-	case NAND_ECC_NONE:
+-		pr_warn("NAND_ECC_NONE selected by board driver. This is not recommended!\n");
+-		ecc->read_page = nand_read_page_raw;
+-		ecc->write_page = nand_write_page_raw;
+-		ecc->read_oob = nand_read_oob_std;
+-		ecc->read_page_raw = nand_read_page_raw;
+-		ecc->write_page_raw = nand_write_page_raw;
+-		ecc->write_oob = nand_write_oob_std;
+-		ecc->size = mtd->writesize;
+-		ecc->bytes = 0;
+-		ecc->strength = 0;
+-		break;
+-
+-	default:
+-		WARN(1, "Invalid NAND_ECC_MODE %d\n", ecc->mode);
+-		ret = -EINVAL;
+-		goto err_nand_manuf_cleanup;
+-	}
+-
+-	/* For many systems, the standard OOB write also works for raw */
+-	if (!ecc->read_oob_raw)
+-		ecc->read_oob_raw = ecc->read_oob;
+-	if (!ecc->write_oob_raw)
+-		ecc->write_oob_raw = ecc->write_oob;
+-
+-	/* propagate ecc info to mtd_info */
+-	mtd->ecc_strength = ecc->strength;
+-	mtd->ecc_step_size = ecc->size;
+-
+-	/*
+-	 * Set the number of read / write steps for one page depending on ECC
+-	 * mode.
+-	 */
+-	ecc->steps = mtd->writesize / ecc->size;
+-	if (ecc->steps * ecc->size != mtd->writesize) {
+-		WARN(1, "Invalid ECC parameters\n");
+-		ret = -EINVAL;
+-		goto err_nand_manuf_cleanup;
+-	}
+-	ecc->total = ecc->steps * ecc->bytes;
+-	if (ecc->total > mtd->oobsize) {
+-		WARN(1, "Total number of ECC bytes exceeded oobsize\n");
+-		ret = -EINVAL;
+-		goto err_nand_manuf_cleanup;
+-	}
+-
+-	/*
+-	 * The number of bytes available for a client to place data into
+-	 * the out of band area.
+-	 */
+-	ret = mtd_ooblayout_count_freebytes(mtd);
+-	if (ret < 0)
+-		ret = 0;
+-
+-	mtd->oobavail = ret;
+-
+-	/* ECC sanity check: warn if it's too weak */
+-	if (!nand_ecc_strength_good(mtd))
+-		pr_warn("WARNING: %s: the ECC used on your system is too weak compared to the one required by the NAND chip\n",
+-			mtd->name);
+-
+-	/* Allow subpage writes up to ecc.steps. Not possible for MLC flash */
+-	if (!(chip->options & NAND_NO_SUBPAGE_WRITE) && nand_is_slc(chip)) {
+-		switch (ecc->steps) {
+-		case 2:
+-			mtd->subpage_sft = 1;
+-			break;
+-		case 4:
+-		case 8:
+-		case 16:
+-			mtd->subpage_sft = 2;
+-			break;
+-		}
+-	}
+-	chip->subpagesize = mtd->writesize >> mtd->subpage_sft;
+-
+-	/* Initialize state */
+-	chip->state = FL_READY;
+-
+-	/* Invalidate the pagebuffer reference */
+-	chip->pagebuf = -1;
+-
+-	/* Large page NAND with SOFT_ECC should support subpage reads */
+-	switch (ecc->mode) {
+-	case NAND_ECC_SOFT:
+-		if (chip->page_shift > 9)
+-			chip->options |= NAND_SUBPAGE_READ;
+-		break;
+-
+-	default:
+-		break;
+-	}
+-
+-	/* Fill in remaining MTD driver data */
+-	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->_point = NULL;
+-	mtd->_unpoint = NULL;
+-	mtd->_panic_write = panic_nand_write;
+-	mtd->_read_oob = nand_read_oob;
+-	mtd->_write_oob = nand_write_oob;
+-	mtd->_sync = nand_sync;
+-	mtd->_lock = NULL;
+-	mtd->_unlock = NULL;
+-	mtd->_suspend = nand_suspend;
+-	mtd->_resume = nand_resume;
+-	mtd->_reboot = nand_shutdown;
+-	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;
+-
+-	/*
+-	 * Initialize bitflip_threshold to its default prior scan_bbt() call.
+-	 * scan_bbt() might invoke mtd_read(), thus bitflip_threshold must be
+-	 * properly set.
+-	 */
+-	if (!mtd->bitflip_threshold)
+-		mtd->bitflip_threshold = DIV_ROUND_UP(mtd->ecc_strength * 3, 4);
+-
+-	/* Initialize the ->data_interface field. */
+-	ret = nand_init_data_interface(chip);
+-	if (ret)
+-		goto err_nand_manuf_cleanup;
+-
+-	/* Enter fastest possible mode on all dies. */
+-	for (i = 0; i < chip->numchips; i++) {
+-		chip->select_chip(mtd, i);
+-		ret = nand_setup_data_interface(chip, i);
+-		chip->select_chip(mtd, -1);
+-
+-		if (ret)
+-			goto err_nand_data_iface_cleanup;
+-	}
+-
+-	/* Check, if we should skip the bad block table scan */
+-	if (chip->options & NAND_SKIP_BBTSCAN)
+-		return 0;
+-
+-	/* Build bad block table */
+-	ret = chip->scan_bbt(mtd);
+-	if (ret)
+-		goto err_nand_data_iface_cleanup;
+-
+-	return 0;
+-
+-err_nand_data_iface_cleanup:
+-	nand_release_data_interface(chip);
+-
+-err_nand_manuf_cleanup:
+-	nand_manufacturer_cleanup(chip);
+-
+-err_free_nbuf:
+-	if (nbuf) {
+-		kfree(nbuf->databuf);
+-		kfree(nbuf->ecccode);
+-		kfree(nbuf->ecccalc);
+-		kfree(nbuf);
+-	}
+-
+-	return ret;
+-}
+-EXPORT_SYMBOL(nand_scan_tail);
+-
+-/*
+- * is_module_text_address() isn't exported, and it's mostly a pointless
+- * test if this is a module _anyway_ -- they'd have to try _really_ hard
+- * to call us from in-kernel code if the core NAND support is modular.
+- */
+-#ifdef MODULE
+-#define caller_is_module() (1)
+-#else
+-#define caller_is_module() \
+-	is_module_text_address((unsigned long)__builtin_return_address(0))
+-#endif
+-
+-/**
+- * nand_scan - [NAND Interface] Scan for the NAND device
+- * @mtd: MTD device structure
+- * @maxchips: number of chips to scan for
+- *
+- * This fills out all the uninitialized function pointers with the defaults.
+- * The flash ID is read and the mtd/chip structures are filled with the
+- * appropriate values.
+- */
+-int nand_scan(struct mtd_info *mtd, int maxchips)
+-{
+-	int ret;
+-
+-	ret = nand_scan_ident(mtd, maxchips, NULL);
+-	if (!ret)
+-		ret = nand_scan_tail(mtd);
+-	return ret;
+-}
+-EXPORT_SYMBOL(nand_scan);
+-
+-/**
+- * nand_cleanup - [NAND Interface] Free resources held by the NAND device
+- * @chip: NAND chip object
+- */
+-void nand_cleanup(struct nand_chip *chip)
+-{
+-	if (chip->ecc.mode == NAND_ECC_SOFT &&
+-	    chip->ecc.algo == NAND_ECC_BCH)
+-		nand_bch_free((struct nand_bch_control *)chip->ecc.priv);
+-
+-	nand_release_data_interface(chip);
+-
+-	/* Free bad block table memory */
+-	kfree(chip->bbt);
+-	if (!(chip->options & NAND_OWN_BUFFERS) && chip->buffers) {
+-		kfree(chip->buffers->databuf);
+-		kfree(chip->buffers->ecccode);
+-		kfree(chip->buffers->ecccalc);
+-		kfree(chip->buffers);
+-	}
+-
+-	/* Free bad block descriptor memory */
+-	if (chip->badblock_pattern && chip->badblock_pattern->options
+-			& NAND_BBT_DYNAMICSTRUCT)
+-		kfree(chip->badblock_pattern);
+-
+-	/* Free manufacturer priv data. */
+-	nand_manufacturer_cleanup(chip);
+-}
+-EXPORT_SYMBOL_GPL(nand_cleanup);
+-
+-/**
+- * nand_release - [NAND Interface] Unregister the MTD device and free resources
+- *		  held by the NAND device
+- * @mtd: MTD device structure
+- */
+-void nand_release(struct mtd_info *mtd)
+-{
+-	mtd_device_unregister(mtd);
+-	nand_cleanup(mtd_to_nand(mtd));
+-}
+-EXPORT_SYMBOL_GPL(nand_release);
+-
+-MODULE_LICENSE("GPL");
+-MODULE_AUTHOR("Steven J. Hill <sjhill@realitydiluted.com>");
+-MODULE_AUTHOR("Thomas Gleixner <tglx@linutronix.de>");
+-MODULE_DESCRIPTION("Generic NAND flash driver code");
+diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c
+deleted file mode 100644
+index 2915b67..0000000
+--- a/drivers/mtd/nand/nand_bbt.c
++++ /dev/null
+@@ -1,1452 +0,0 @@
+-/*
+- *  Overview:
+- *   Bad block table support for the NAND driver
+- *
+- *  Copyright © 2004 Thomas Gleixner (tglx@linutronix.de)
+- *
+- * 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.
+- *
+- * Description:
+- *
+- * When nand_scan_bbt is called, then it tries to find the bad block table
+- * depending on the options in the BBT descriptor(s). If no flash based BBT
+- * (NAND_BBT_USE_FLASH) is specified then the device is scanned for factory
+- * marked good / bad blocks. This information is used to create a memory BBT.
+- * Once a new bad block is discovered then the "factory" information is updated
+- * on the device.
+- * If a flash based BBT is specified then the function first tries to find the
+- * BBT on flash. If a BBT is found then the contents are read and the memory
+- * based BBT is created. If a mirrored BBT is selected then the mirror is
+- * searched too and the versions are compared. If the mirror has a greater
+- * version number, then the mirror BBT is used to build the memory based BBT.
+- * If the tables are not versioned, then we "or" the bad block information.
+- * If one of the BBTs is out of date or does not exist it is (re)created.
+- * If no BBT exists at all then the device is scanned for factory marked
+- * good / bad blocks and the bad block tables are created.
+- *
+- * For manufacturer created BBTs like the one found on M-SYS DOC devices
+- * the BBT is searched and read but never created
+- *
+- * The auto generated bad block table is located in the last good blocks
+- * of the device. The table is mirrored, so it can be updated eventually.
+- * The table is marked in the OOB area with an ident pattern and a version
+- * number which indicates which of both tables is more up to date. If the NAND
+- * controller needs the complete OOB area for the ECC information then the
+- * option NAND_BBT_NO_OOB should be used (along with NAND_BBT_USE_FLASH, of
+- * course): it moves the ident pattern and the version byte into the data area
+- * and the OOB area will remain untouched.
+- *
+- * The table uses 2 bits per block
+- * 11b:		block is good
+- * 00b:		block is factory marked bad
+- * 01b, 10b:	block is marked bad due to wear
+- *
+- * The memory bad block table uses the following scheme:
+- * 00b:		block is good
+- * 01b:		block is marked bad due to wear
+- * 10b:		block is reserved (to protect the bbt area)
+- * 11b:		block is factory marked bad
+- *
+- * Multichip devices like DOC store the bad block info per floor.
+- *
+- * Following assumptions are made:
+- * - bbts start at a page boundary, if autolocated on a block boundary
+- * - the space necessary for a bbt in FLASH does not exceed a block boundary
+- *
+- */
+-
+-#include <linux/slab.h>
+-#include <linux/types.h>
+-#include <linux/mtd/mtd.h>
+-#include <linux/mtd/bbm.h>
+-#include <linux/mtd/rawnand.h>
+-#include <linux/bitops.h>
+-#include <linux/delay.h>
+-#include <linux/vmalloc.h>
+-#include <linux/export.h>
+-#include <linux/string.h>
+-
+-#define BBT_BLOCK_GOOD		0x00
+-#define BBT_BLOCK_WORN		0x01
+-#define BBT_BLOCK_RESERVED	0x02
+-#define BBT_BLOCK_FACTORY_BAD	0x03
+-
+-#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)
+-{
+-	uint8_t entry = chip->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,
+-		uint8_t mark)
+-{
+-	uint8_t msk = (mark & BBT_ENTRY_MASK) << ((block & BBT_ENTRY_MASK) * 2);
+-	chip->bbt[block >> BBT_ENTRY_SHIFT] |= msk;
+-}
+-
+-static int check_pattern_no_oob(uint8_t *buf, struct nand_bbt_descr *td)
+-{
+-	if (memcmp(buf, td->pattern, td->len))
+-		return -1;
+-	return 0;
+-}
+-
+-/**
+- * check_pattern - [GENERIC] check if a pattern is in the buffer
+- * @buf: the buffer to search
+- * @len: the length of buffer to search
+- * @paglen: the pagelength
+- * @td: search pattern descriptor
+- *
+- * Check for a pattern at the given place. Used to search bad block tables and
+- * good / bad block identifiers.
+- */
+-static int check_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_descr *td)
+-{
+-	if (td->options & NAND_BBT_NO_OOB)
+-		return check_pattern_no_oob(buf, td);
+-
+-	/* Compare the pattern */
+-	if (memcmp(buf + paglen + td->offs, td->pattern, td->len))
+-		return -1;
+-
+-	return 0;
+-}
+-
+-/**
+- * check_short_pattern - [GENERIC] check if a pattern is in the buffer
+- * @buf: the buffer to search
+- * @td:	search pattern descriptor
+- *
+- * Check for a pattern at the given place. Used to search bad block tables and
+- * good / bad block identifiers. Same as check_pattern, but no optional empty
+- * check.
+- */
+-static int check_short_pattern(uint8_t *buf, struct nand_bbt_descr *td)
+-{
+-	/* Compare the pattern */
+-	if (memcmp(buf + td->offs, td->pattern, td->len))
+-		return -1;
+-	return 0;
+-}
+-
+-/**
+- * add_marker_len - compute the length of the marker in data area
+- * @td: BBT descriptor used for computation
+- *
+- * The length will be 0 if the marker is located in OOB area.
+- */
+-static u32 add_marker_len(struct nand_bbt_descr *td)
+-{
+-	u32 len;
+-
+-	if (!(td->options & NAND_BBT_NO_OOB))
+-		return 0;
+-
+-	len = td->len;
+-	if (td->options & NAND_BBT_VERSION)
+-		len++;
+-	return len;
+-}
+-
+-/**
+- * read_bbt - [GENERIC] Read the bad block table starting from page
+- * @mtd: MTD device structure
+- * @buf: temporary buffer
+- * @page: the starting page
+- * @num: the number of bbt descriptors to read
+- * @td: the bbt describtion table
+- * @offs: block number offset in the table
+- *
+- * 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)
+-{
+-	int res, ret = 0, i, j, act = 0;
+-	struct nand_chip *this = mtd_to_nand(mtd);
+-	size_t retlen, len, totlen;
+-	loff_t from;
+-	int bits = td->options & NAND_BBT_NRBITS_MSK;
+-	uint8_t msk = (uint8_t)((1 << bits) - 1);
+-	u32 marker_len;
+-	int reserved_block_code = td->reserved_block_code;
+-
+-	totlen = (num * bits) >> 3;
+-	marker_len = add_marker_len(td);
+-	from = ((loff_t)page) << this->page_shift;
+-
+-	while (totlen) {
+-		len = min(totlen, (size_t)(1 << this->bbt_erase_shift));
+-		if (marker_len) {
+-			/*
+-			 * In case the BBT marker is not in the OOB area it
+-			 * will be just in the first page.
+-			 */
+-			len -= marker_len;
+-			from += marker_len;
+-			marker_len = 0;
+-		}
+-		res = mtd_read(mtd, from, len, &retlen, buf);
+-		if (res < 0) {
+-			if (mtd_is_eccerr(res)) {
+-				pr_info("nand_bbt: ECC error in BBT at 0x%012llx\n",
+-					from & ~mtd->writesize);
+-				return res;
+-			} else if (mtd_is_bitflip(res)) {
+-				pr_info("nand_bbt: corrected error in BBT at 0x%012llx\n",
+-					from & ~mtd->writesize);
+-				ret = res;
+-			} else {
+-				pr_info("nand_bbt: error reading BBT\n");
+-				return res;
+-			}
+-		}
+-
+-		/* Analyse data */
+-		for (i = 0; i < len; i++) {
+-			uint8_t dat = buf[i];
+-			for (j = 0; j < 8; j += bits, act++) {
+-				uint8_t tmp = (dat >> j) & msk;
+-				if (tmp == msk)
+-					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);
+-					bbt_mark_entry(this, offs + act,
+-							BBT_BLOCK_RESERVED);
+-					mtd->ecc_stats.bbtblocks++;
+-					continue;
+-				}
+-				/*
+-				 * Leave it for now, if it's matured we can
+-				 * 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);
+-				/* Factory marked bad or worn out? */
+-				if (tmp == 0)
+-					bbt_mark_entry(this, offs + act,
+-							BBT_BLOCK_FACTORY_BAD);
+-				else
+-					bbt_mark_entry(this, offs + act,
+-							BBT_BLOCK_WORN);
+-				mtd->ecc_stats.badblocks++;
+-			}
+-		}
+-		totlen -= len;
+-		from += len;
+-	}
+-	return ret;
+-}
+-
+-/**
+- * read_abs_bbt - [GENERIC] Read the bad block table starting at a given page
+- * @mtd: MTD device structure
+- * @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
+- *        NAND_BBT_PERCHIP option is set
+- *
+- * 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)
+-{
+-	struct nand_chip *this = mtd_to_nand(mtd);
+-	int res = 0, i;
+-
+-	if (td->options & NAND_BBT_PERCHIP) {
+-		int offs = 0;
+-		for (i = 0; i < this->numchips; i++) {
+-			if (chip == -1 || chip == i)
+-				res = read_bbt(mtd, buf, td->pages[i],
+-					this->chipsize >> this->bbt_erase_shift,
+-					td, offs);
+-			if (res)
+-				return res;
+-			offs += this->chipsize >> this->bbt_erase_shift;
+-		}
+-	} else {
+-		res = read_bbt(mtd, buf, td->pages[0],
+-				mtd->size >> this->bbt_erase_shift, td, 0);
+-		if (res)
+-			return res;
+-	}
+-	return 0;
+-}
+-
+-/* 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)
+-{
+-	size_t retlen;
+-	size_t len;
+-
+-	len = td->len;
+-	if (td->options & NAND_BBT_VERSION)
+-		len++;
+-
+-	return mtd_read(mtd, offs, len, &retlen, buf);
+-}
+-
+-/**
+- * scan_read_oob - [GENERIC] Scan data+OOB region to buffer
+- * @mtd: MTD device structure
+- * @buf: temporary buffer
+- * @offs: offset at which to scan
+- * @len: length of data region to read
+- *
+- * Scan read data from data+OOB. May traverse multiple pages, interleaving
+- * 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,
+-			 size_t len)
+-{
+-	struct mtd_oob_ops ops;
+-	int res, ret = 0;
+-
+-	ops.mode = MTD_OPS_PLACE_OOB;
+-	ops.ooboffs = 0;
+-	ops.ooblen = mtd->oobsize;
+-
+-	while (len > 0) {
+-		ops.datbuf = buf;
+-		ops.len = min(len, (size_t)mtd->writesize);
+-		ops.oobbuf = buf + ops.len;
+-
+-		res = mtd_read_oob(mtd, offs, &ops);
+-		if (res) {
+-			if (!mtd_is_bitflip_or_eccerr(res))
+-				return res;
+-			else if (mtd_is_eccerr(res) || !ret)
+-				ret = res;
+-		}
+-
+-		buf += mtd->oobsize + mtd->writesize;
+-		len -= mtd->writesize;
+-		offs += mtd->writesize;
+-	}
+-	return ret;
+-}
+-
+-static int scan_read(struct mtd_info *mtd, 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);
+-	else
+-		return scan_read_oob(mtd, 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,
+-			  uint8_t *buf, uint8_t *oob)
+-{
+-	struct mtd_oob_ops ops;
+-
+-	ops.mode = MTD_OPS_PLACE_OOB;
+-	ops.ooboffs = 0;
+-	ops.ooblen = mtd->oobsize;
+-	ops.datbuf = buf;
+-	ops.oobbuf = oob;
+-	ops.len = len;
+-
+-	return mtd_write_oob(mtd, offs, &ops);
+-}
+-
+-static u32 bbt_get_ver_offs(struct mtd_info *mtd, struct nand_bbt_descr *td)
+-{
+-	u32 ver_offs = td->veroffs;
+-
+-	if (!(td->options & NAND_BBT_NO_OOB))
+-		ver_offs += mtd->writesize;
+-	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
+- * @buf: temporary buffer
+- * @td: descriptor for the bad block table
+- * @md:	descriptor for the bad block table mirror
+- *
+- * 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,
+-			  struct nand_bbt_descr *td, struct nand_bbt_descr *md)
+-{
+-	struct nand_chip *this = mtd_to_nand(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)];
+-		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)];
+-		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,
+-			   loff_t offs, uint8_t *buf, int numpages)
+-{
+-	struct mtd_oob_ops ops;
+-	int j, ret;
+-
+-	ops.ooblen = mtd->oobsize;
+-	ops.oobbuf = buf;
+-	ops.ooboffs = 0;
+-	ops.datbuf = NULL;
+-	ops.mode = MTD_OPS_PLACE_OOB;
+-
+-	for (j = 0; j < numpages; j++) {
+-		/*
+-		 * Read the full oob until read_oob is fixed to handle single
+-		 * byte reads for 16 bit buswidth.
+-		 */
+-		ret = mtd_read_oob(mtd, offs, &ops);
+-		/* Ignore ECC errors when checking for BBM */
+-		if (ret && !mtd_is_bitflip_or_eccerr(ret))
+-			return ret;
+-
+-		if (check_short_pattern(buf, bd))
+-			return 1;
+-
+-		offs += mtd->writesize;
+-	}
+-	return 0;
+-}
+-
+-/**
+- * create_bbt - [GENERIC] Create a bad block table by scanning the device
+- * @mtd: MTD device structure
+- * @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
+- *        if NAND_BBT_PERCHIP option is set
+- *
+- * 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)
+-{
+-	struct nand_chip *this = mtd_to_nand(mtd);
+-	int i, numblocks, numpages;
+-	int startblock;
+-	loff_t from;
+-
+-	pr_info("Scanning device for bad blocks\n");
+-
+-	if (bd->options & NAND_BBT_SCAN2NDPAGE)
+-		numpages = 2;
+-	else
+-		numpages = 1;
+-
+-	if (chip == -1) {
+-		numblocks = mtd->size >> this->bbt_erase_shift;
+-		startblock = 0;
+-		from = 0;
+-	} else {
+-		if (chip >= this->numchips) {
+-			pr_warn("create_bbt(): chipnr (%d) > available chips (%d)\n",
+-			       chip + 1, this->numchips);
+-			return -EINVAL;
+-		}
+-		numblocks = this->chipsize >> this->bbt_erase_shift;
+-		startblock = chip * numblocks;
+-		numblocks += startblock;
+-		from = (loff_t)startblock << this->bbt_erase_shift;
+-	}
+-
+-	if (this->bbt_options & NAND_BBT_SCANLASTPAGE)
+-		from += mtd->erasesize - (mtd->writesize * 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);
+-		if (ret < 0)
+-			return ret;
+-
+-		if (ret) {
+-			bbt_mark_entry(this, i, BBT_BLOCK_FACTORY_BAD);
+-			pr_warn("Bad eraseblock %d at 0x%012llx\n",
+-				i, (unsigned long long)from);
+-			mtd->ecc_stats.badblocks++;
+-		}
+-
+-		from += (1 << this->bbt_erase_shift);
+-	}
+-	return 0;
+-}
+-
+-/**
+- * search_bbt - [GENERIC] scan the device for a specific bad block table
+- * @mtd: MTD device structure
+- * @buf: temporary buffer
+- * @td: descriptor for the bad block table
+- *
+- * Read the bad block table by searching for a given ident pattern. Search is
+- * preformed either from the beginning up or from the end of the device
+- * downwards. The search starts always at the start of a block. If the option
+- * NAND_BBT_PERCHIP is given, each chip is searched for a bbt, which contains
+- * the bad block information of this chip. This is necessary to provide support
+- * for certain DOC devices.
+- *
+- * 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)
+-{
+-	struct nand_chip *this = mtd_to_nand(mtd);
+-	int i, chips;
+-	int startblock, block, dir;
+-	int scanlen = mtd->writesize + mtd->oobsize;
+-	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;
+-		dir = -1;
+-	} else {
+-		startblock = 0;
+-		dir = 1;
+-	}
+-
+-	/* Do we have a bbt per chip? */
+-	if (td->options & NAND_BBT_PERCHIP) {
+-		chips = this->numchips;
+-		bbtblocks = this->chipsize >> this->bbt_erase_shift;
+-		startblock &= bbtblocks - 1;
+-	} else {
+-		chips = 1;
+-		bbtblocks = mtd->size >> this->bbt_erase_shift;
+-	}
+-
+-	for (i = 0; i < chips; i++) {
+-		/* Reset version information */
+-		td->version[i] = 0;
+-		td->pages[i] = -1;
+-		/* Scan the maximum number of blocks */
+-		for (block = 0; block < td->maxblocks; block++) {
+-
+-			int actblock = startblock + dir * block;
+-			loff_t offs = (loff_t)actblock << this->bbt_erase_shift;
+-
+-			/* Read first page */
+-			scan_read(mtd, buf, offs, mtd->writesize, td);
+-			if (!check_pattern(buf, scanlen, mtd->writesize, td)) {
+-				td->pages[i] = actblock << blocktopage;
+-				if (td->options & NAND_BBT_VERSION) {
+-					offs = bbt_get_ver_offs(mtd, td);
+-					td->version[i] = buf[offs];
+-				}
+-				break;
+-			}
+-		}
+-		startblock += this->chipsize >> this->bbt_erase_shift;
+-	}
+-	/* Check, if we found a bbt for each requested chip */
+-	for (i = 0; i < chips; i++) {
+-		if (td->pages[i] == -1)
+-			pr_warn("Bad block table not found for chip %d\n", i);
+-		else
+-			pr_info("Bad block table found at page %d, version 0x%02X\n",
+-				td->pages[i], td->version[i]);
+-	}
+-	return 0;
+-}
+-
+-/**
+- * search_read_bbts - [GENERIC] scan the device for bad block table(s)
+- * @mtd: MTD device structure
+- * @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,
+-			     struct nand_bbt_descr *td,
+-			     struct nand_bbt_descr *md)
+-{
+-	/* Search the primary table */
+-	search_bbt(mtd, buf, td);
+-
+-	/* Search the mirror table */
+-	if (md)
+-		search_bbt(mtd, buf, md);
+-}
+-
+-/**
+- * get_bbt_block - Get the first valid eraseblock suitable to store a BBT
+- * @this: the NAND device
+- * @td: the BBT description
+- * @md: the mirror BBT descriptor
+- * @chip: the CHIP selector
+- *
+- * This functions returns a positive block number pointing a valid eraseblock
+- * suitable to store a BBT (i.e. in the range reserved for BBT), or -ENOSPC if
+- * all blocks are already used of marked bad. If td->pages[chip] was already
+- * 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,
+-			 struct nand_bbt_descr *md, int chip)
+-{
+-	int startblock, dir, page, numblocks, i;
+-
+-	/*
+-	 * There was already a version of the table, reuse the page. This
+-	 * applies for absolute placement too, as we have the page number in
+-	 * td->pages.
+-	 */
+-	if (td->pages[chip] != -1)
+-		return td->pages[chip] >>
+-				(this->bbt_erase_shift - this->page_shift);
+-
+-	numblocks = (int)(this->chipsize >> this->bbt_erase_shift);
+-	if (!(td->options & NAND_BBT_PERCHIP))
+-		numblocks *= this->numchips;
+-
+-	/*
+-	 * Automatic placement of the bad block table. Search direction
+-	 * top -> down?
+-	 */
+-	if (td->options & NAND_BBT_LASTBLOCK) {
+-		startblock = numblocks * (chip + 1) - 1;
+-		dir = -1;
+-	} else {
+-		startblock = chip * numblocks;
+-		dir = 1;
+-	}
+-
+-	for (i = 0; i < td->maxblocks; i++) {
+-		int block = startblock + dir * i;
+-
+-		/* Check, if the block is bad */
+-		switch (bbt_get_entry(this, block)) {
+-		case BBT_BLOCK_WORN:
+-		case BBT_BLOCK_FACTORY_BAD:
+-			continue;
+-		}
+-
+-		page = block << (this->bbt_erase_shift - this->page_shift);
+-
+-		/* Check, if the block is used by the mirror table */
+-		if (!md || md->pages[chip] != page)
+-			return block;
+-	}
+-
+-	return -ENOSPC;
+-}
+-
+-/**
+- * mark_bbt_block_bad - Mark one of the block reserved for BBT bad
+- * @this: the NAND device
+- * @td: the BBT description
+- * @chip: the CHIP selector
+- * @block: the BBT block to mark
+- *
+- * Blocks reserved for BBT can become bad. This functions is an helper to mark
+- * such blocks as bad. It takes care of updating the in-memory BBT, marking the
+- * 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,
+-			       struct nand_bbt_descr *td,
+-			       int chip, int block)
+-{
+-	struct mtd_info *mtd = nand_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);
+-	if (res)
+-		pr_warn("nand_bbt: error %d while marking block %d bad\n",
+-			res, block);
+-
+-	td->pages[chip] = -1;
+-}
+-
+-/**
+- * write_bbt - [GENERIC] (Re)write the bad block table
+- * @mtd: MTD device structure
+- * @buf: temporary buffer
+- * @td: descriptor for the bad block table
+- * @md: descriptor for the bad block table mirror
+- * @chipsel: selector for a specific chip, -1 for all
+- *
+- * (Re)write the bad block table.
+- */
+-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 erase_info einfo;
+-	int i, res, chip = 0;
+-	int bits, page, offs, numblocks, sft, sftmsk;
+-	int nrchips, pageoffs, ooboffs;
+-	uint8_t msk[4];
+-	uint8_t rcode = td->reserved_block_code;
+-	size_t retlen, len = 0;
+-	loff_t to;
+-	struct mtd_oob_ops ops;
+-
+-	ops.ooblen = mtd->oobsize;
+-	ops.ooboffs = 0;
+-	ops.datbuf = NULL;
+-	ops.mode = MTD_OPS_PLACE_OOB;
+-
+-	if (!rcode)
+-		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);
+-		/* Full device write or specific chip? */
+-		if (chipsel == -1) {
+-			nrchips = this->numchips;
+-		} else {
+-			nrchips = chipsel + 1;
+-			chip = chipsel;
+-		}
+-	} else {
+-		numblocks = (int)(mtd->size >> this->bbt_erase_shift);
+-		nrchips = 1;
+-	}
+-
+-	/* Loop through the chips */
+-	while (chip < nrchips) {
+-		int block;
+-
+-		block = get_bbt_block(this, td, md, chip);
+-		if (block < 0) {
+-			pr_err("No space left to write bad block table\n");
+-			res = block;
+-			goto outerr;
+-		}
+-
+-		/*
+-		 * get_bbt_block() returns a block number, shift the value to
+-		 * get a page number.
+-		 */
+-		page = block << (this->bbt_erase_shift - this->page_shift);
+-
+-		/* Set up shift count and masks for the flash table */
+-		bits = td->options & NAND_BBT_NRBITS_MSK;
+-		msk[2] = ~rcode;
+-		switch (bits) {
+-		case 1: sft = 3; sftmsk = 0x07; msk[0] = 0x00; msk[1] = 0x01;
+-			msk[3] = 0x01;
+-			break;
+-		case 2: sft = 2; sftmsk = 0x06; msk[0] = 0x00; msk[1] = 0x01;
+-			msk[3] = 0x03;
+-			break;
+-		case 4: sft = 1; sftmsk = 0x04; msk[0] = 0x00; msk[1] = 0x0C;
+-			msk[3] = 0x0f;
+-			break;
+-		case 8: sft = 0; sftmsk = 0x00; msk[0] = 0x00; msk[1] = 0x0F;
+-			msk[3] = 0xff;
+-			break;
+-		default: return -EINVAL;
+-		}
+-
+-		to = ((loff_t)page) << this->page_shift;
+-
+-		/* 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;
+-			res = mtd_read(mtd, to, len, &retlen, buf);
+-			if (res < 0) {
+-				if (retlen != len) {
+-					pr_info("nand_bbt: error reading block for writing the bad block table\n");
+-					return res;
+-				}
+-				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.oobbuf = &buf[len];
+-			res = mtd_read_oob(mtd, to + mtd->writesize, &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;
+-			/* Preset the bbt area with 0xff */
+-			memset(&buf[offs], 0xff, (size_t)(numblocks >> sft));
+-			ooboffs = len + (pageoffs * mtd->oobsize);
+-
+-		} else if (td->options & NAND_BBT_NO_OOB) {
+-			ooboffs = 0;
+-			offs = td->len;
+-			/* The version byte */
+-			if (td->options & NAND_BBT_VERSION)
+-				offs++;
+-			/* Calc length */
+-			len = (size_t)(numblocks >> sft);
+-			len += offs;
+-			/* Make it page aligned! */
+-			len = ALIGN(len, mtd->writesize);
+-			/* Preset the buffer with 0xff */
+-			memset(buf, 0xff, len);
+-			/* Pattern is located at the begin of first page */
+-			memcpy(buf, td->pattern, td->len);
+-		} else {
+-			/* Calc length */
+-			len = (size_t)(numblocks >> sft);
+-			/* Make it page aligned! */
+-			len = ALIGN(len, mtd->writesize);
+-			/* Preset the buffer with 0xff */
+-			memset(buf, 0xff, len +
+-			       (len >> this->page_shift)* mtd->oobsize);
+-			offs = 0;
+-			ooboffs = len;
+-			/* Pattern is located in oob area of first page */
+-			memcpy(&buf[ooboffs + td->offs], td->pattern, td->len);
+-		}
+-
+-		if (td->options & NAND_BBT_VERSION)
+-			buf[ooboffs + td->veroffs] = td->version[chip];
+-
+-		/* Walk through the memory table */
+-		for (i = 0; i < numblocks; i++) {
+-			uint8_t dat;
+-			int sftcnt = (i << (3 - sft)) & sftmsk;
+-			dat = bbt_get_entry(this, chip * numblocks + i);
+-			/* Do not store the reserved bbt blocks! */
+-			buf[offs + (i >> sft)] &= ~(msk[dat] << sftcnt);
+-		}
+-
+-		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);
+-		if (res < 0) {
+-			pr_warn("nand_bbt: error while erasing BBT block %d\n",
+-				res);
+-			mark_bbt_block_bad(this, td, chip, block);
+-			continue;
+-		}
+-
+-		res = scan_write_bbt(mtd, 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);
+-			mark_bbt_block_bad(this, td, chip, block);
+-			continue;
+-		}
+-
+-		pr_info("Bad block table written to 0x%012llx, version 0x%02X\n",
+-			 (unsigned long long)to, td->version[chip]);
+-
+-		/* Mark it as used */
+-		td->pages[chip++] = page;
+-	}
+-	return 0;
+-
+- outerr:
+-	pr_warn("nand_bbt: error while writing bad block table %d\n", res);
+-	return res;
+-}
+-
+-/**
+- * nand_memory_bbt - [GENERIC] create a memory based bad block table
+- * @mtd: MTD device structure
+- * @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)
+-{
+-	struct nand_chip *this = mtd_to_nand(mtd);
+-
+-	return create_bbt(mtd, this->buffers->databuf, bd, -1);
+-}
+-
+-/**
+- * check_create - [GENERIC] create and write bbt(s) if necessary
+- * @mtd: MTD device structure
+- * @buf: temporary buffer
+- * @bd: descriptor for the good/bad block search pattern
+- *
+- * The function checks the results of the previous call to read_bbt and creates
+- * / updates the bbt(s) if necessary. Creation is necessary if no bbt was found
+- * 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)
+-{
+-	int i, chips, writeops, create, chipsel, res, res2;
+-	struct nand_chip *this = mtd_to_nand(mtd);
+-	struct nand_bbt_descr *td = this->bbt_td;
+-	struct nand_bbt_descr *md = this->bbt_md;
+-	struct nand_bbt_descr *rd, *rd2;
+-
+-	/* Do we have a bbt per chip? */
+-	if (td->options & NAND_BBT_PERCHIP)
+-		chips = this->numchips;
+-	else
+-		chips = 1;
+-
+-	for (i = 0; i < chips; i++) {
+-		writeops = 0;
+-		create = 0;
+-		rd = NULL;
+-		rd2 = NULL;
+-		res = res2 = 0;
+-		/* Per chip or per device? */
+-		chipsel = (td->options & NAND_BBT_PERCHIP) ? i : -1;
+-		/* Mirrored table available? */
+-		if (md) {
+-			if (td->pages[i] == -1 && md->pages[i] == -1) {
+-				create = 1;
+-				writeops = 0x03;
+-			} else if (td->pages[i] == -1) {
+-				rd = md;
+-				writeops = 0x01;
+-			} else if (md->pages[i] == -1) {
+-				rd = td;
+-				writeops = 0x02;
+-			} else if (td->version[i] == md->version[i]) {
+-				rd = td;
+-				if (!(td->options & NAND_BBT_VERSION))
+-					rd2 = md;
+-			} else if (((int8_t)(td->version[i] - md->version[i])) > 0) {
+-				rd = td;
+-				writeops = 0x02;
+-			} else {
+-				rd = md;
+-				writeops = 0x01;
+-			}
+-		} else {
+-			if (td->pages[i] == -1) {
+-				create = 1;
+-				writeops = 0x01;
+-			} else {
+-				rd = td;
+-			}
+-		}
+-
+-		if (create) {
+-			/* Create the bad block table by scanning the device? */
+-			if (!(td->options & NAND_BBT_CREATE))
+-				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);
+-
+-			td->version[i] = 1;
+-			if (md)
+-				md->version[i] = 1;
+-		}
+-
+-		/* Read back first? */
+-		if (rd) {
+-			res = read_abs_bbt(mtd, buf, rd, chipsel);
+-			if (mtd_is_eccerr(res)) {
+-				/* Mark table as invalid */
+-				rd->pages[i] = -1;
+-				rd->version[i] = 0;
+-				i--;
+-				continue;
+-			}
+-		}
+-		/* If they weren't versioned, read both */
+-		if (rd2) {
+-			res2 = read_abs_bbt(mtd, buf, rd2, chipsel);
+-			if (mtd_is_eccerr(res2)) {
+-				/* Mark table as invalid */
+-				rd2->pages[i] = -1;
+-				rd2->version[i] = 0;
+-				i--;
+-				continue;
+-			}
+-		}
+-
+-		/* Scrub the flash table(s)? */
+-		if (mtd_is_bitflip(res) || mtd_is_bitflip(res2))
+-			writeops = 0x03;
+-
+-		/* Update version numbers before writing */
+-		if (md) {
+-			td->version[i] = max(td->version[i], md->version[i]);
+-			md->version[i] = td->version[i];
+-		}
+-
+-		/* Write the bad block table to the device? */
+-		if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) {
+-			res = write_bbt(mtd, 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);
+-			if (res < 0)
+-				return res;
+-		}
+-	}
+-	return 0;
+-}
+-
+-/**
+- * mark_bbt_regions - [GENERIC] mark the bad block table regions
+- * @mtd: MTD device structure
+- * @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)
+-{
+-	struct nand_chip *this = mtd_to_nand(mtd);
+-	int i, j, chips, block, nrblocks, update;
+-	uint8_t oldval;
+-
+-	/* Do we have a bbt per chip? */
+-	if (td->options & NAND_BBT_PERCHIP) {
+-		chips = this->numchips;
+-		nrblocks = (int)(this->chipsize >> this->bbt_erase_shift);
+-	} else {
+-		chips = 1;
+-		nrblocks = (int)(mtd->size >> this->bbt_erase_shift);
+-	}
+-
+-	for (i = 0; i < chips; i++) {
+-		if ((td->options & NAND_BBT_ABSPAGE) ||
+-		    !(td->options & NAND_BBT_WRITE)) {
+-			if (td->pages[i] == -1)
+-				continue;
+-			block = td->pages[i] >> (this->bbt_erase_shift - this->page_shift);
+-			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);
+-			continue;
+-		}
+-		update = 0;
+-		if (td->options & NAND_BBT_LASTBLOCK)
+-			block = ((i + 1) * nrblocks) - td->maxblocks;
+-		else
+-			block = i * nrblocks;
+-		for (j = 0; j < td->maxblocks; j++) {
+-			oldval = bbt_get_entry(this, block);
+-			bbt_mark_entry(this, block, BBT_BLOCK_RESERVED);
+-			if (oldval != BBT_BLOCK_RESERVED)
+-				update = 1;
+-			block++;
+-		}
+-		/*
+-		 * If we want reserved blocks to be recorded to flash, and some
+-		 * 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);
+-	}
+-}
+-
+-/**
+- * verify_bbt_descr - verify the bad block description
+- * @mtd: MTD device structure
+- * @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)
+-{
+-	struct nand_chip *this = mtd_to_nand(mtd);
+-	u32 pattern_len;
+-	u32 bits;
+-	u32 table_size;
+-
+-	if (!bd)
+-		return;
+-
+-	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(!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(bd->offs);
+-		if (bd->options & NAND_BBT_VERSION)
+-			BUG_ON(bd->veroffs != bd->len);
+-		BUG_ON(bd->options & NAND_BBT_SAVECONTENT);
+-	}
+-
+-	if (bd->options & NAND_BBT_PERCHIP)
+-		table_size = this->chipsize >> this->bbt_erase_shift;
+-	else
+-		table_size = mtd->size >> this->bbt_erase_shift;
+-	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));
+-}
+-
+-/**
+- * nand_scan_bbt - [NAND Interface] scan, find, read and maybe create bad block table(s)
+- * @mtd: MTD device structure
+- * @bd: descriptor for the good/bad block search pattern
+- *
+- * The function checks, if a bad block table(s) is/are already available. If
+- * not it scans the device for manufacturer marked good / bad blocks and writes
+- * the bad block table(s) to the selected place.
+- *
+- * 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)
+-{
+-	struct nand_chip *this = mtd_to_nand(mtd);
+-	int len, res;
+-	uint8_t *buf;
+-	struct nand_bbt_descr *td = this->bbt_td;
+-	struct nand_bbt_descr *md = this->bbt_md;
+-
+-	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)
+-		return -ENOMEM;
+-
+-	/*
+-	 * If no primary table decriptor is given, scan the device to build a
+-	 * memory based bad block table.
+-	 */
+-	if (!td) {
+-		if ((res = nand_memory_bbt(mtd, 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);
+-
+-	/* Allocate a temporary buffer for one eraseblock incl. oob */
+-	len = (1 << this->bbt_erase_shift);
+-	len += (len >> this->page_shift) * mtd->oobsize;
+-	buf = vmalloc(len);
+-	if (!buf) {
+-		res = -ENOMEM;
+-		goto err;
+-	}
+-
+-	/* Is the bbt at a given page? */
+-	if (td->options & NAND_BBT_ABSPAGE) {
+-		read_abs_bbts(mtd, buf, td, md);
+-	} else {
+-		/* Search the bad block table using a pattern in oob */
+-		search_read_bbts(mtd, buf, td, md);
+-	}
+-
+-	res = check_create(mtd, buf, bd);
+-	if (res)
+-		goto err;
+-
+-	/* Prevent the bbt regions from erasing / writing */
+-	mark_bbt_region(mtd, td);
+-	if (md)
+-		mark_bbt_region(mtd, md);
+-
+-	vfree(buf);
+-	return 0;
+-
+-err:
+-	kfree(this->bbt);
+-	this->bbt = NULL;
+-	return res;
+-}
+-
+-/**
+- * nand_update_bbt - update bad block table(s)
+- * @mtd: MTD device structure
+- * @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)
+-{
+-	struct nand_chip *this = mtd_to_nand(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;
+-
+-	if (!this->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;
+-	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);
+-		chipsel = chip;
+-	} else {
+-		chip = 0;
+-		chipsel = -1;
+-	}
+-
+-	td->version[chip]++;
+-	if (md)
+-		md->version[chip]++;
+-
+-	/* Write the bad block table to the device? */
+-	if (td->options & NAND_BBT_WRITE) {
+-		res = write_bbt(mtd, 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);
+-	}
+-
+- out:
+-	kfree(buf);
+-	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_nand(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
+- * @offs: offset in the device
+- */
+-int nand_isreserved_bbt(struct mtd_info *mtd, loff_t offs)
+-{
+-	struct nand_chip *this = mtd_to_nand(mtd);
+-	int block;
+-
+-	block = (int)(offs >> this->bbt_erase_shift);
+-	return bbt_get_entry(this, block) == BBT_BLOCK_RESERVED;
+-}
+-
+-/**
+- * nand_isbad_bbt - [NAND Interface] Check if a block is bad
+- * @mtd: MTD device structure
+- * @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)
+-{
+-	struct nand_chip *this = mtd_to_nand(mtd);
+-	int block, res;
+-
+-	block = (int)(offs >> this->bbt_erase_shift);
+-	res = bbt_get_entry(this, block);
+-
+-	pr_debug("nand_isbad_bbt(): bbt info for offs 0x%08x: (block %d) 0x%02x\n",
+-		 (unsigned int)offs, block, res);
+-
+-	switch (res) {
+-	case BBT_BLOCK_GOOD:
+-		return 0;
+-	case BBT_BLOCK_WORN:
+-		return 1;
+-	case BBT_BLOCK_RESERVED:
+-		return allowbbt ? 0 : 1;
+-	}
+-	return 1;
+-}
+-
+-/**
+- * nand_markbad_bbt - [NAND Interface] Mark a block bad in the BBT
+- * @mtd: MTD device structure
+- * @offs: offset of the bad block
+- */
+-int nand_markbad_bbt(struct mtd_info *mtd, loff_t offs)
+-{
+-	struct nand_chip *this = mtd_to_nand(mtd);
+-	int block, ret = 0;
+-
+-	block = (int)(offs >> this->bbt_erase_shift);
+-
+-	/* 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);
+-
+-	return ret;
+-}
+diff --git a/drivers/mtd/nand/nand_bch.c b/drivers/mtd/nand/nand_bch.c
+deleted file mode 100644
+index 505441c..0000000
+--- a/drivers/mtd/nand/nand_bch.c
++++ /dev/null
+@@ -1,234 +0,0 @@
+-/*
+- * This file provides ECC correction for more than 1 bit per block of data,
+- * using binary BCH codes. It relies on the generic BCH library lib/bch.c.
+- *
+- * Copyright © 2011 Ivan Djelic <ivan.djelic@parrot.com>
+- *
+- * 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 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.
+- *
+- * You should have received a copy of the GNU General Public License along
+- * with this file; if not, write to the Free Software Foundation, Inc.,
+- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+- */
+-
+-#include <linux/types.h>
+-#include <linux/kernel.h>
+-#include <linux/module.h>
+-#include <linux/slab.h>
+-#include <linux/bitops.h>
+-#include <linux/mtd/mtd.h>
+-#include <linux/mtd/rawnand.h>
+-#include <linux/mtd/nand_bch.h>
+-#include <linux/bch.h>
+-
+-/**
+- * struct nand_bch_control - private NAND BCH control structure
+- * @bch:       BCH control structure
+- * @errloc:    error location array
+- * @eccmask:   XOR ecc mask, allows erased pages to be decoded as valid
+- */
+-struct nand_bch_control {
+-	struct bch_control   *bch;
+-	unsigned int         *errloc;
+-	unsigned char        *eccmask;
+-};
+-
+-/**
+- * nand_bch_calculate_ecc - [NAND Interface] Calculate ECC for data block
+- * @mtd:	MTD block structure
+- * @buf:	input buffer with raw data
+- * @code:	output buffer with ECC
+- */
+-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);
+-	struct nand_bch_control *nbc = chip->ecc.priv;
+-	unsigned int i;
+-
+-	memset(code, 0, chip->ecc.bytes);
+-	encode_bch(nbc->bch, buf, chip->ecc.size, code);
+-
+-	/* apply mask so that an erased page is a valid codeword */
+-	for (i = 0; i < chip->ecc.bytes; i++)
+-		code[i] ^= nbc->eccmask[i];
+-
+-	return 0;
+-}
+-EXPORT_SYMBOL(nand_bch_calculate_ecc);
+-
+-/**
+- * nand_bch_correct_data - [NAND Interface] Detect and correct bit error(s)
+- * @mtd:	MTD block structure
+- * @buf:	raw data read from the chip
+- * @read_ecc:	ECC from the chip
+- * @calc_ecc:	the ECC calculated from raw data
+- *
+- * Detect and correct bit errors for a data byte block
+- */
+-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);
+-	struct nand_bch_control *nbc = chip->ecc.priv;
+-	unsigned int *errloc = nbc->errloc;
+-	int i, count;
+-
+-	count = decode_bch(nbc->bch, NULL, chip->ecc.size, read_ecc, calc_ecc,
+-			   NULL, errloc);
+-	if (count > 0) {
+-		for (i = 0; i < count; i++) {
+-			if (errloc[i] < (chip->ecc.size*8))
+-				/* error is located in data, correct it */
+-				buf[errloc[i] >> 3] ^= (1 << (errloc[i] & 7));
+-			/* else error in ecc, no action needed */
+-
+-			pr_debug("%s: corrected bitflip %u\n", __func__,
+-					errloc[i]);
+-		}
+-	} else if (count < 0) {
+-		printk(KERN_ERR "ecc unrecoverable error\n");
+-		count = -EBADMSG;
+-	}
+-	return count;
+-}
+-EXPORT_SYMBOL(nand_bch_correct_data);
+-
+-/**
+- * nand_bch_init - [NAND Interface] Initialize NAND BCH error correction
+- * @mtd:	MTD block structure
+- *
+- * Returns:
+- *  a pointer to a new NAND BCH control structure, or NULL upon failure
+- *
+- * Initialize NAND BCH error correction. Parameters @eccsize and @eccbytes
+- * are used to compute BCH parameters m (Galois field order) and t (error
+- * correction capability). @eccbytes should be equal to the number of bytes
+- * required to store m*t bits, where m is such that 2^m-1 > @eccsize*8.
+- *
+- * Example: to configure 4 bit correction per 512 bytes, you should pass
+- * @eccsize = 512  (thus, m=13 is the smallest integer such that 2^m-1 > 512*8)
+- * @eccbytes = 7   (7 bytes are required to store m*t = 13*4 = 52 bits)
+- */
+-struct nand_bch_control *nand_bch_init(struct mtd_info *mtd)
+-{
+-	struct nand_chip *nand = mtd_to_nand(mtd);
+-	unsigned int m, t, eccsteps, i;
+-	struct nand_bch_control *nbc = NULL;
+-	unsigned char *erased_page;
+-	unsigned int eccsize = nand->ecc.size;
+-	unsigned int eccbytes = nand->ecc.bytes;
+-	unsigned int eccstrength = nand->ecc.strength;
+-
+-	if (!eccbytes && eccstrength) {
+-		eccbytes = DIV_ROUND_UP(eccstrength * fls(8 * eccsize), 8);
+-		nand->ecc.bytes = eccbytes;
+-	}
+-
+-	if (!eccsize || !eccbytes) {
+-		printk(KERN_WARNING "ecc parameters not supplied\n");
+-		goto fail;
+-	}
+-
+-	m = fls(1+8*eccsize);
+-	t = (eccbytes*8)/m;
+-
+-	nbc = kzalloc(sizeof(*nbc), GFP_KERNEL);
+-	if (!nbc)
+-		goto fail;
+-
+-	nbc->bch = init_bch(m, t, 0);
+-	if (!nbc->bch)
+-		goto fail;
+-
+-	/* verify that eccbytes has the expected value */
+-	if (nbc->bch->ecc_bytes != eccbytes) {
+-		printk(KERN_WARNING "invalid eccbytes %u, should be %u\n",
+-		       eccbytes, nbc->bch->ecc_bytes);
+-		goto fail;
+-	}
+-
+-	eccsteps = mtd->writesize/eccsize;
+-
+-	/* Check that we have an oob layout description. */
+-	if (!mtd->ooblayout) {
+-		pr_warn("missing oob scheme");
+-		goto fail;
+-	}
+-
+-	/* sanity checks */
+-	if (8*(eccsize+eccbytes) >= (1 << m)) {
+-		printk(KERN_WARNING "eccsize %u is too large\n", eccsize);
+-		goto fail;
+-	}
+-
+-	/*
+-	 * ecc->steps and ecc->total might be used by mtd->ooblayout->ecc(),
+-	 * which is called by mtd_ooblayout_count_eccbytes().
+-	 * Make sure they are properly initialized before calling
+-	 * mtd_ooblayout_count_eccbytes().
+-	 * FIXME: we should probably rework the sequencing in nand_scan_tail()
+-	 * to avoid setting those fields twice.
+-	 */
+-	nand->ecc.steps = eccsteps;
+-	nand->ecc.total = eccsteps * eccbytes;
+-	if (mtd_ooblayout_count_eccbytes(mtd) != (eccsteps*eccbytes)) {
+-		printk(KERN_WARNING "invalid ecc layout\n");
+-		goto fail;
+-	}
+-
+-	nbc->eccmask = kmalloc(eccbytes, GFP_KERNEL);
+-	nbc->errloc = kmalloc(t*sizeof(*nbc->errloc), GFP_KERNEL);
+-	if (!nbc->eccmask || !nbc->errloc)
+-		goto fail;
+-	/*
+-	 * compute and store the inverted ecc of an erased ecc block
+-	 */
+-	erased_page = kmalloc(eccsize, GFP_KERNEL);
+-	if (!erased_page)
+-		goto fail;
+-
+-	memset(erased_page, 0xff, eccsize);
+-	memset(nbc->eccmask, 0, eccbytes);
+-	encode_bch(nbc->bch, erased_page, eccsize, nbc->eccmask);
+-	kfree(erased_page);
+-
+-	for (i = 0; i < eccbytes; i++)
+-		nbc->eccmask[i] ^= 0xff;
+-
+-	if (!eccstrength)
+-		nand->ecc.strength = (eccbytes * 8) / fls(8 * eccsize);
+-
+-	return nbc;
+-fail:
+-	nand_bch_free(nbc);
+-	return NULL;
+-}
+-EXPORT_SYMBOL(nand_bch_init);
+-
+-/**
+- * nand_bch_free - [NAND Interface] Release NAND BCH ECC resources
+- * @nbc:	NAND BCH control structure
+- */
+-void nand_bch_free(struct nand_bch_control *nbc)
+-{
+-	if (nbc) {
+-		free_bch(nbc->bch);
+-		kfree(nbc->errloc);
+-		kfree(nbc->eccmask);
+-		kfree(nbc);
+-	}
+-}
+-EXPORT_SYMBOL(nand_bch_free);
+-
+-MODULE_LICENSE("GPL");
+-MODULE_AUTHOR("Ivan Djelic <ivan.djelic@parrot.com>");
+-MODULE_DESCRIPTION("NAND software BCH ECC support");
+diff --git a/drivers/mtd/nand/nand_ecc.c b/drivers/mtd/nand/nand_ecc.c
+deleted file mode 100644
+index 7613a03..0000000
+--- a/drivers/mtd/nand/nand_ecc.c
++++ /dev/null
+@@ -1,533 +0,0 @@
+-/*
+- * This file contains an ECC algorithm that detects and corrects 1 bit
+- * errors in a 256 byte block of data.
+- *
+- * drivers/mtd/nand/nand_ecc.c
+- *
+- * Copyright © 2008 Koninklijke Philips Electronics NV.
+- *                  Author: Frans Meulenbroeks
+- *
+- * Completely replaces the previous ECC implementation which was written by:
+- *   Steven J. Hill (sjhill@realitydiluted.com)
+- *   Thomas Gleixner (tglx@linutronix.de)
+- *
+- * Information on how this algorithm works and how it was developed
+- * can be found in Documentation/mtd/nand_ecc.txt
+- *
+- * 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 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.
+- *
+- * You should have received a copy of the GNU General Public License along
+- * with this file; if not, write to the Free Software Foundation, Inc.,
+- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+- *
+- */
+-
+-/*
+- * The STANDALONE macro is useful when running the code outside the kernel
+- * e.g. when running the code in a testbed or a benchmark program.
+- * When STANDALONE is used, the module related macros are commented out
+- * as well as the linux include files.
+- * Instead a private definition of mtd_info is given to satisfy the compiler
+- * (the code does not use mtd_info, so the code does not care)
+- */
+-#ifndef STANDALONE
+-#include <linux/types.h>
+-#include <linux/kernel.h>
+-#include <linux/module.h>
+-#include <linux/mtd/mtd.h>
+-#include <linux/mtd/rawnand.h>
+-#include <linux/mtd/nand_ecc.h>
+-#include <asm/byteorder.h>
+-#else
+-#include <stdint.h>
+-struct mtd_info;
+-#define EXPORT_SYMBOL(x)  /* x */
+-
+-#define MODULE_LICENSE(x)	/* x */
+-#define MODULE_AUTHOR(x)	/* x */
+-#define MODULE_DESCRIPTION(x)	/* x */
+-
+-#define pr_err printf
+-#endif
+-
+-/*
+- * invparity is a 256 byte table that contains the odd parity
+- * for each byte. So if the number of bits in a byte is even,
+- * the array element is 1, and when the number of bits is odd
+- * the array eleemnt is 0.
+- */
+-static const char invparity[256] = {
+-	1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
+-	0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
+-	0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
+-	1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
+-	0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
+-	1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
+-	1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
+-	0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
+-	0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
+-	1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
+-	1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
+-	0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
+-	1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
+-	0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
+-	0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
+-	1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1
+-};
+-
+-/*
+- * bitsperbyte contains the number of bits per byte
+- * this is only used for testing and repairing parity
+- * (a precalculated value slightly improves performance)
+- */
+-static const char bitsperbyte[256] = {
+-	0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
+-	1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+-	1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+-	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+-	1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+-	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+-	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+-	3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+-	1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+-	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+-	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+-	3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+-	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+-	3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+-	3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+-	4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8,
+-};
+-
+-/*
+- * addressbits is a lookup table to filter out the bits from the xor-ed
+- * ECC data that identify the faulty location.
+- * this is only used for repairing parity
+- * see the comments in nand_correct_data for more details
+- */
+-static const char addressbits[256] = {
+-	0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01,
+-	0x02, 0x02, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03,
+-	0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01,
+-	0x02, 0x02, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03,
+-	0x04, 0x04, 0x05, 0x05, 0x04, 0x04, 0x05, 0x05,
+-	0x06, 0x06, 0x07, 0x07, 0x06, 0x06, 0x07, 0x07,
+-	0x04, 0x04, 0x05, 0x05, 0x04, 0x04, 0x05, 0x05,
+-	0x06, 0x06, 0x07, 0x07, 0x06, 0x06, 0x07, 0x07,
+-	0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01,
+-	0x02, 0x02, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03,
+-	0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01,
+-	0x02, 0x02, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03,
+-	0x04, 0x04, 0x05, 0x05, 0x04, 0x04, 0x05, 0x05,
+-	0x06, 0x06, 0x07, 0x07, 0x06, 0x06, 0x07, 0x07,
+-	0x04, 0x04, 0x05, 0x05, 0x04, 0x04, 0x05, 0x05,
+-	0x06, 0x06, 0x07, 0x07, 0x06, 0x06, 0x07, 0x07,
+-	0x08, 0x08, 0x09, 0x09, 0x08, 0x08, 0x09, 0x09,
+-	0x0a, 0x0a, 0x0b, 0x0b, 0x0a, 0x0a, 0x0b, 0x0b,
+-	0x08, 0x08, 0x09, 0x09, 0x08, 0x08, 0x09, 0x09,
+-	0x0a, 0x0a, 0x0b, 0x0b, 0x0a, 0x0a, 0x0b, 0x0b,
+-	0x0c, 0x0c, 0x0d, 0x0d, 0x0c, 0x0c, 0x0d, 0x0d,
+-	0x0e, 0x0e, 0x0f, 0x0f, 0x0e, 0x0e, 0x0f, 0x0f,
+-	0x0c, 0x0c, 0x0d, 0x0d, 0x0c, 0x0c, 0x0d, 0x0d,
+-	0x0e, 0x0e, 0x0f, 0x0f, 0x0e, 0x0e, 0x0f, 0x0f,
+-	0x08, 0x08, 0x09, 0x09, 0x08, 0x08, 0x09, 0x09,
+-	0x0a, 0x0a, 0x0b, 0x0b, 0x0a, 0x0a, 0x0b, 0x0b,
+-	0x08, 0x08, 0x09, 0x09, 0x08, 0x08, 0x09, 0x09,
+-	0x0a, 0x0a, 0x0b, 0x0b, 0x0a, 0x0a, 0x0b, 0x0b,
+-	0x0c, 0x0c, 0x0d, 0x0d, 0x0c, 0x0c, 0x0d, 0x0d,
+-	0x0e, 0x0e, 0x0f, 0x0f, 0x0e, 0x0e, 0x0f, 0x0f,
+-	0x0c, 0x0c, 0x0d, 0x0d, 0x0c, 0x0c, 0x0d, 0x0d,
+-	0x0e, 0x0e, 0x0f, 0x0f, 0x0e, 0x0e, 0x0f, 0x0f
+-};
+-
+-/**
+- * __nand_calculate_ecc - [NAND Interface] Calculate 3-byte ECC for 256/512-byte
+- *			 block
+- * @buf:	input buffer with raw data
+- * @eccsize:	data bytes per ECC step (256 or 512)
+- * @code:	output buffer with ECC
+- */
+-void __nand_calculate_ecc(const unsigned char *buf, unsigned int eccsize,
+-		       unsigned char *code)
+-{
+-	int i;
+-	const uint32_t *bp = (uint32_t *)buf;
+-	/* 256 or 512 bytes/ecc  */
+-	const uint32_t eccsize_mult = eccsize >> 8;
+-	uint32_t cur;		/* current value in buffer */
+-	/* rp0..rp15..rp17 are the various accumulated parities (per byte) */
+-	uint32_t rp0, rp1, rp2, rp3, rp4, rp5, rp6, rp7;
+-	uint32_t rp8, rp9, rp10, rp11, rp12, rp13, rp14, rp15, rp16;
+-	uint32_t uninitialized_var(rp17);	/* to make compiler happy */
+-	uint32_t par;		/* the cumulative parity for all data */
+-	uint32_t tmppar;	/* the cumulative parity for this iteration;
+-				   for rp12, rp14 and rp16 at the end of the
+-				   loop */
+-
+-	par = 0;
+-	rp4 = 0;
+-	rp6 = 0;
+-	rp8 = 0;
+-	rp10 = 0;
+-	rp12 = 0;
+-	rp14 = 0;
+-	rp16 = 0;
+-
+-	/*
+-	 * The loop is unrolled a number of times;
+-	 * This avoids if statements to decide on which rp value to update
+-	 * Also we process the data by longwords.
+-	 * Note: passing unaligned data might give a performance penalty.
+-	 * It is assumed that the buffers are aligned.
+-	 * tmppar is the cumulative sum of this iteration.
+-	 * needed for calculating rp12, rp14, rp16 and par
+-	 * also used as a performance improvement for rp6, rp8 and rp10
+-	 */
+-	for (i = 0; i < eccsize_mult << 2; i++) {
+-		cur = *bp++;
+-		tmppar = cur;
+-		rp4 ^= cur;
+-		cur = *bp++;
+-		tmppar ^= cur;
+-		rp6 ^= tmppar;
+-		cur = *bp++;
+-		tmppar ^= cur;
+-		rp4 ^= cur;
+-		cur = *bp++;
+-		tmppar ^= cur;
+-		rp8 ^= tmppar;
+-
+-		cur = *bp++;
+-		tmppar ^= cur;
+-		rp4 ^= cur;
+-		rp6 ^= cur;
+-		cur = *bp++;
+-		tmppar ^= cur;
+-		rp6 ^= cur;
+-		cur = *bp++;
+-		tmppar ^= cur;
+-		rp4 ^= cur;
+-		cur = *bp++;
+-		tmppar ^= cur;
+-		rp10 ^= tmppar;
+-
+-		cur = *bp++;
+-		tmppar ^= cur;
+-		rp4 ^= cur;
+-		rp6 ^= cur;
+-		rp8 ^= cur;
+-		cur = *bp++;
+-		tmppar ^= cur;
+-		rp6 ^= cur;
+-		rp8 ^= cur;
+-		cur = *bp++;
+-		tmppar ^= cur;
+-		rp4 ^= cur;
+-		rp8 ^= cur;
+-		cur = *bp++;
+-		tmppar ^= cur;
+-		rp8 ^= cur;
+-
+-		cur = *bp++;
+-		tmppar ^= cur;
+-		rp4 ^= cur;
+-		rp6 ^= cur;
+-		cur = *bp++;
+-		tmppar ^= cur;
+-		rp6 ^= cur;
+-		cur = *bp++;
+-		tmppar ^= cur;
+-		rp4 ^= cur;
+-		cur = *bp++;
+-		tmppar ^= cur;
+-
+-		par ^= tmppar;
+-		if ((i & 0x1) == 0)
+-			rp12 ^= tmppar;
+-		if ((i & 0x2) == 0)
+-			rp14 ^= tmppar;
+-		if (eccsize_mult == 2 && (i & 0x4) == 0)
+-			rp16 ^= tmppar;
+-	}
+-
+-	/*
+-	 * handle the fact that we use longword operations
+-	 * we'll bring rp4..rp14..rp16 back to single byte entities by
+-	 * shifting and xoring first fold the upper and lower 16 bits,
+-	 * then the upper and lower 8 bits.
+-	 */
+-	rp4 ^= (rp4 >> 16);
+-	rp4 ^= (rp4 >> 8);
+-	rp4 &= 0xff;
+-	rp6 ^= (rp6 >> 16);
+-	rp6 ^= (rp6 >> 8);
+-	rp6 &= 0xff;
+-	rp8 ^= (rp8 >> 16);
+-	rp8 ^= (rp8 >> 8);
+-	rp8 &= 0xff;
+-	rp10 ^= (rp10 >> 16);
+-	rp10 ^= (rp10 >> 8);
+-	rp10 &= 0xff;
+-	rp12 ^= (rp12 >> 16);
+-	rp12 ^= (rp12 >> 8);
+-	rp12 &= 0xff;
+-	rp14 ^= (rp14 >> 16);
+-	rp14 ^= (rp14 >> 8);
+-	rp14 &= 0xff;
+-	if (eccsize_mult == 2) {
+-		rp16 ^= (rp16 >> 16);
+-		rp16 ^= (rp16 >> 8);
+-		rp16 &= 0xff;
+-	}
+-
+-	/*
+-	 * we also need to calculate the row parity for rp0..rp3
+-	 * This is present in par, because par is now
+-	 * rp3 rp3 rp2 rp2 in little endian and
+-	 * rp2 rp2 rp3 rp3 in big endian
+-	 * as well as
+-	 * rp1 rp0 rp1 rp0 in little endian and
+-	 * rp0 rp1 rp0 rp1 in big endian
+-	 * First calculate rp2 and rp3
+-	 */
+-#ifdef __BIG_ENDIAN
+-	rp2 = (par >> 16);
+-	rp2 ^= (rp2 >> 8);
+-	rp2 &= 0xff;
+-	rp3 = par & 0xffff;
+-	rp3 ^= (rp3 >> 8);
+-	rp3 &= 0xff;
+-#else
+-	rp3 = (par >> 16);
+-	rp3 ^= (rp3 >> 8);
+-	rp3 &= 0xff;
+-	rp2 = par & 0xffff;
+-	rp2 ^= (rp2 >> 8);
+-	rp2 &= 0xff;
+-#endif
+-
+-	/* reduce par to 16 bits then calculate rp1 and rp0 */
+-	par ^= (par >> 16);
+-#ifdef __BIG_ENDIAN
+-	rp0 = (par >> 8) & 0xff;
+-	rp1 = (par & 0xff);
+-#else
+-	rp1 = (par >> 8) & 0xff;
+-	rp0 = (par & 0xff);
+-#endif
+-
+-	/* finally reduce par to 8 bits */
+-	par ^= (par >> 8);
+-	par &= 0xff;
+-
+-	/*
+-	 * and calculate rp5..rp15..rp17
+-	 * note that par = rp4 ^ rp5 and due to the commutative property
+-	 * of the ^ operator we can say:
+-	 * rp5 = (par ^ rp4);
+-	 * The & 0xff seems superfluous, but benchmarking learned that
+-	 * leaving it out gives slightly worse results. No idea why, probably
+-	 * it has to do with the way the pipeline in pentium is organized.
+-	 */
+-	rp5 = (par ^ rp4) & 0xff;
+-	rp7 = (par ^ rp6) & 0xff;
+-	rp9 = (par ^ rp8) & 0xff;
+-	rp11 = (par ^ rp10) & 0xff;
+-	rp13 = (par ^ rp12) & 0xff;
+-	rp15 = (par ^ rp14) & 0xff;
+-	if (eccsize_mult == 2)
+-		rp17 = (par ^ rp16) & 0xff;
+-
+-	/*
+-	 * Finally calculate the ECC bits.
+-	 * Again here it might seem that there are performance optimisations
+-	 * possible, but benchmarks showed that on the system this is developed
+-	 * the code below is the fastest
+-	 */
+-#ifdef CONFIG_MTD_NAND_ECC_SMC
+-	code[0] =
+-	    (invparity[rp7] << 7) |
+-	    (invparity[rp6] << 6) |
+-	    (invparity[rp5] << 5) |
+-	    (invparity[rp4] << 4) |
+-	    (invparity[rp3] << 3) |
+-	    (invparity[rp2] << 2) |
+-	    (invparity[rp1] << 1) |
+-	    (invparity[rp0]);
+-	code[1] =
+-	    (invparity[rp15] << 7) |
+-	    (invparity[rp14] << 6) |
+-	    (invparity[rp13] << 5) |
+-	    (invparity[rp12] << 4) |
+-	    (invparity[rp11] << 3) |
+-	    (invparity[rp10] << 2) |
+-	    (invparity[rp9] << 1)  |
+-	    (invparity[rp8]);
+-#else
+-	code[1] =
+-	    (invparity[rp7] << 7) |
+-	    (invparity[rp6] << 6) |
+-	    (invparity[rp5] << 5) |
+-	    (invparity[rp4] << 4) |
+-	    (invparity[rp3] << 3) |
+-	    (invparity[rp2] << 2) |
+-	    (invparity[rp1] << 1) |
+-	    (invparity[rp0]);
+-	code[0] =
+-	    (invparity[rp15] << 7) |
+-	    (invparity[rp14] << 6) |
+-	    (invparity[rp13] << 5) |
+-	    (invparity[rp12] << 4) |
+-	    (invparity[rp11] << 3) |
+-	    (invparity[rp10] << 2) |
+-	    (invparity[rp9] << 1)  |
+-	    (invparity[rp8]);
+-#endif
+-	if (eccsize_mult == 1)
+-		code[2] =
+-		    (invparity[par & 0xf0] << 7) |
+-		    (invparity[par & 0x0f] << 6) |
+-		    (invparity[par & 0xcc] << 5) |
+-		    (invparity[par & 0x33] << 4) |
+-		    (invparity[par & 0xaa] << 3) |
+-		    (invparity[par & 0x55] << 2) |
+-		    3;
+-	else
+-		code[2] =
+-		    (invparity[par & 0xf0] << 7) |
+-		    (invparity[par & 0x0f] << 6) |
+-		    (invparity[par & 0xcc] << 5) |
+-		    (invparity[par & 0x33] << 4) |
+-		    (invparity[par & 0xaa] << 3) |
+-		    (invparity[par & 0x55] << 2) |
+-		    (invparity[rp17] << 1) |
+-		    (invparity[rp16] << 0);
+-}
+-EXPORT_SYMBOL(__nand_calculate_ecc);
+-
+-/**
+- * nand_calculate_ecc - [NAND Interface] Calculate 3-byte ECC for 256/512-byte
+- *			 block
+- * @mtd:	MTD block structure
+- * @buf:	input buffer with raw data
+- * @code:	output buffer with ECC
+- */
+-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);
+-
+-	return 0;
+-}
+-EXPORT_SYMBOL(nand_calculate_ecc);
+-
+-/**
+- * __nand_correct_data - [NAND Interface] Detect and correct bit error(s)
+- * @buf:	raw data read from the chip
+- * @read_ecc:	ECC from the chip
+- * @calc_ecc:	the ECC calculated from raw data
+- * @eccsize:	data bytes per ECC step (256 or 512)
+- *
+- * Detect and correct a 1 bit error for eccsize byte block
+- */
+-int __nand_correct_data(unsigned char *buf,
+-			unsigned char *read_ecc, unsigned char *calc_ecc,
+-			unsigned int eccsize)
+-{
+-	unsigned char b0, b1, b2, bit_addr;
+-	unsigned int byte_addr;
+-	/* 256 or 512 bytes/ecc  */
+-	const uint32_t eccsize_mult = eccsize >> 8;
+-
+-	/*
+-	 * b0 to b2 indicate which bit is faulty (if any)
+-	 * we might need the xor result  more than once,
+-	 * so keep them in a local var
+-	*/
+-#ifdef CONFIG_MTD_NAND_ECC_SMC
+-	b0 = read_ecc[0] ^ calc_ecc[0];
+-	b1 = read_ecc[1] ^ calc_ecc[1];
+-#else
+-	b0 = read_ecc[1] ^ calc_ecc[1];
+-	b1 = read_ecc[0] ^ calc_ecc[0];
+-#endif
+-	b2 = read_ecc[2] ^ calc_ecc[2];
+-
+-	/* check if there are any bitfaults */
+-
+-	/* repeated if statements are slightly more efficient than switch ... */
+-	/* ordered in order of likelihood */
+-
+-	if ((b0 | b1 | b2) == 0)
+-		return 0;	/* no error */
+-
+-	if ((((b0 ^ (b0 >> 1)) & 0x55) == 0x55) &&
+-	    (((b1 ^ (b1 >> 1)) & 0x55) == 0x55) &&
+-	    ((eccsize_mult == 1 && ((b2 ^ (b2 >> 1)) & 0x54) == 0x54) ||
+-	     (eccsize_mult == 2 && ((b2 ^ (b2 >> 1)) & 0x55) == 0x55))) {
+-	/* single bit error */
+-		/*
+-		 * rp17/rp15/13/11/9/7/5/3/1 indicate which byte is the faulty
+-		 * byte, cp 5/3/1 indicate the faulty bit.
+-		 * A lookup table (called addressbits) is used to filter
+-		 * the bits from the byte they are in.
+-		 * A marginal optimisation is possible by having three
+-		 * different lookup tables.
+-		 * One as we have now (for b0), one for b2
+-		 * (that would avoid the >> 1), and one for b1 (with all values
+-		 * << 4). However it was felt that introducing two more tables
+-		 * hardly justify the gain.
+-		 *
+-		 * The b2 shift is there to get rid of the lowest two bits.
+-		 * We could also do addressbits[b2] >> 1 but for the
+-		 * performance it does not make any difference
+-		 */
+-		if (eccsize_mult == 1)
+-			byte_addr = (addressbits[b1] << 4) + addressbits[b0];
+-		else
+-			byte_addr = (addressbits[b2 & 0x3] << 8) +
+-				    (addressbits[b1] << 4) + addressbits[b0];
+-		bit_addr = addressbits[b2 >> 2];
+-		/* flip the bit */
+-		buf[byte_addr] ^= (1 << bit_addr);
+-		return 1;
+-
+-	}
+-	/* count nr of bits; use table lookup, faster than calculating it */
+-	if ((bitsperbyte[b0] + bitsperbyte[b1] + bitsperbyte[b2]) == 1)
+-		return 1;	/* error in ECC data; no action needed */
+-
+-	pr_err("%s: uncorrectable ECC error\n", __func__);
+-	return -EBADMSG;
+-}
+-EXPORT_SYMBOL(__nand_correct_data);
+-
+-/**
+- * nand_correct_data - [NAND Interface] Detect and correct bit error(s)
+- * @mtd:	MTD block structure
+- * @buf:	raw data read from the chip
+- * @read_ecc:	ECC from the chip
+- * @calc_ecc:	the ECC calculated from raw data
+- *
+- * Detect and correct a 1 bit error for 256/512 byte block
+- */
+-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);
+-}
+-EXPORT_SYMBOL(nand_correct_data);
+-
+-MODULE_LICENSE("GPL");
+-MODULE_AUTHOR("Frans Meulenbroeks <fransmeulenbroeks@gmail.com>");
+-MODULE_DESCRIPTION("Generic NAND ECC support");
+diff --git a/drivers/mtd/nand/nand_hynix.c b/drivers/mtd/nand/nand_hynix.c
+deleted file mode 100644
+index 985751e..0000000
+--- a/drivers/mtd/nand/nand_hynix.c
++++ /dev/null
+@@ -1,631 +0,0 @@
+-/*
+- * Copyright (C) 2017 Free Electrons
+- * Copyright (C) 2017 NextThing Co
+- *
+- * Author: Boris Brezillon <boris.brezillon@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 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/mtd/rawnand.h>
+-#include <linux/sizes.h>
+-#include <linux/slab.h>
+-
+-#define NAND_HYNIX_CMD_SET_PARAMS	0x36
+-#define NAND_HYNIX_CMD_APPLY_PARAMS	0x16
+-
+-#define NAND_HYNIX_1XNM_RR_REPEAT	8
+-
+-/**
+- * struct hynix_read_retry - read-retry data
+- * @nregs: number of register to set when applying a new read-retry mode
+- * @regs: register offsets (NAND chip dependent)
+- * @values: array of values to set in registers. The array size is equal to
+- *	    (nregs * nmodes)
+- */
+-struct hynix_read_retry {
+-	int nregs;
+-	const u8 *regs;
+-	u8 values[0];
+-};
+-
+-/**
+- * struct hynix_nand - private Hynix NAND struct
+- * @nand_technology: manufacturing process expressed in picometer
+- * @read_retry: read-retry information
+- */
+-struct hynix_nand {
+-	const struct hynix_read_retry *read_retry;
+-};
+-
+-/**
+- * struct hynix_read_retry_otp - structure describing how the read-retry OTP
+- *				 area
+- * @nregs: number of hynix private registers to set before reading the reading
+- *	   the OTP area
+- * @regs: registers that should be configured
+- * @values: values that should be set in regs
+- * @page: the address to pass to the READ_PAGE command. Depends on the NAND
+- *	  chip
+- * @size: size of the read-retry OTP section
+- */
+-struct hynix_read_retry_otp {
+-	int nregs;
+-	const u8 *regs;
+-	const u8 *values;
+-	int page;
+-	int size;
+-};
+-
+-static bool hynix_nand_has_valid_jedecid(struct nand_chip *chip)
+-{
+-	struct mtd_info *mtd = nand_to_mtd(chip);
+-	u8 jedecid[6] = { };
+-	int i = 0;
+-
+-	chip->cmdfunc(mtd, NAND_CMD_READID, 0x40, -1);
+-	for (i = 0; i < 5; i++)
+-		jedecid[i] = chip->read_byte(mtd);
+-
+-	return !strcmp("JEDEC", jedecid);
+-}
+-
+-static int hynix_nand_setup_read_retry(struct mtd_info *mtd, int retry_mode)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct hynix_nand *hynix = nand_get_manufacturer_data(chip);
+-	const u8 *values;
+-	int status;
+-	int i;
+-
+-	values = hynix->read_retry->values +
+-		 (retry_mode * hynix->read_retry->nregs);
+-
+-	/* Enter 'Set Hynix Parameters' mode */
+-	chip->cmdfunc(mtd, NAND_HYNIX_CMD_SET_PARAMS, -1, -1);
+-
+-	/*
+-	 * Configure the NAND in the requested read-retry mode.
+-	 * This is done by setting pre-defined values in internal NAND
+-	 * registers.
+-	 *
+-	 * The set of registers is NAND specific, and the values are either
+-	 * predefined or extracted from an OTP area on the NAND (values are
+-	 * probably tweaked at production in this case).
+-	 */
+-	for (i = 0; i < hynix->read_retry->nregs; i++) {
+-		int column = hynix->read_retry->regs[i];
+-
+-		column |= column << 8;
+-		chip->cmdfunc(mtd, NAND_CMD_NONE, column, -1);
+-		chip->write_byte(mtd, values[i]);
+-	}
+-
+-	/* Apply the new settings. */
+-	chip->cmdfunc(mtd, NAND_HYNIX_CMD_APPLY_PARAMS, -1, -1);
+-
+-	status = chip->waitfunc(mtd, chip);
+-	if (status & NAND_STATUS_FAIL)
+-		return -EIO;
+-
+-	return 0;
+-}
+-
+-/**
+- * hynix_get_majority - get the value that is occurring the most in a given
+- *			set of values
+- * @in: the array of values to test
+- * @repeat: the size of the in array
+- * @out: pointer used to store the output value
+- *
+- * This function implements the 'majority check' logic that is supposed to
+- * overcome the unreliability of MLC NANDs when reading the OTP area storing
+- * the read-retry parameters.
+- *
+- * It's based on a pretty simple assumption: if we repeat the same value
+- * several times and then take the one that is occurring the most, we should
+- * find the correct value.
+- * Let's hope this dummy algorithm prevents us from losing the read-retry
+- * parameters.
+- */
+-static int hynix_get_majority(const u8 *in, int repeat, u8 *out)
+-{
+-	int i, j, half = repeat / 2;
+-
+-	/*
+-	 * We only test the first half of the in array because we must ensure
+-	 * that the value is at least occurring repeat / 2 times.
+-	 *
+-	 * This loop is suboptimal since we may count the occurrences of the
+-	 * same value several time, but we are doing that on small sets, which
+-	 * makes it acceptable.
+-	 */
+-	for (i = 0; i < half; i++) {
+-		int cnt = 0;
+-		u8 val = in[i];
+-
+-		/* Count all values that are matching the one at index i. */
+-		for (j = i + 1; j < repeat; j++) {
+-			if (in[j] == val)
+-				cnt++;
+-		}
+-
+-		/* We found a value occurring more than repeat / 2. */
+-		if (cnt > half) {
+-			*out = val;
+-			return 0;
+-		}
+-	}
+-
+-	return -EIO;
+-}
+-
+-static int hynix_read_rr_otp(struct nand_chip *chip,
+-			     const struct hynix_read_retry_otp *info,
+-			     void *buf)
+-{
+-	struct mtd_info *mtd = nand_to_mtd(chip);
+-	int i;
+-
+-	chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
+-
+-	chip->cmdfunc(mtd, NAND_HYNIX_CMD_SET_PARAMS, -1, -1);
+-
+-	for (i = 0; i < info->nregs; i++) {
+-		int column = info->regs[i];
+-
+-		column |= column << 8;
+-		chip->cmdfunc(mtd, NAND_CMD_NONE, column, -1);
+-		chip->write_byte(mtd, info->values[i]);
+-	}
+-
+-	chip->cmdfunc(mtd, NAND_HYNIX_CMD_APPLY_PARAMS, -1, -1);
+-
+-	/* Sequence to enter OTP mode? */
+-	chip->cmdfunc(mtd, 0x17, -1, -1);
+-	chip->cmdfunc(mtd, 0x04, -1, -1);
+-	chip->cmdfunc(mtd, 0x19, -1, -1);
+-
+-	/* Now read the page */
+-	chip->cmdfunc(mtd, NAND_CMD_READ0, 0x0, info->page);
+-	chip->read_buf(mtd, buf, info->size);
+-
+-	/* Put everything back to normal */
+-	chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
+-	chip->cmdfunc(mtd, NAND_HYNIX_CMD_SET_PARAMS, 0x38, -1);
+-	chip->write_byte(mtd, 0x0);
+-	chip->cmdfunc(mtd, NAND_HYNIX_CMD_APPLY_PARAMS, -1, -1);
+-	chip->cmdfunc(mtd, NAND_CMD_READ0, 0x0, -1);
+-
+-	return 0;
+-}
+-
+-#define NAND_HYNIX_1XNM_RR_COUNT_OFFS				0
+-#define NAND_HYNIX_1XNM_RR_REG_COUNT_OFFS			8
+-#define NAND_HYNIX_1XNM_RR_SET_OFFS(x, setsize, inv)		\
+-	(16 + ((((x) * 2) + ((inv) ? 1 : 0)) * (setsize)))
+-
+-static int hynix_mlc_1xnm_rr_value(const u8 *buf, int nmodes, int nregs,
+-				   int mode, int reg, bool inv, u8 *val)
+-{
+-	u8 tmp[NAND_HYNIX_1XNM_RR_REPEAT];
+-	int val_offs = (mode * nregs) + reg;
+-	int set_size = nmodes * nregs;
+-	int i, ret;
+-
+-	for (i = 0; i < NAND_HYNIX_1XNM_RR_REPEAT; i++) {
+-		int set_offs = NAND_HYNIX_1XNM_RR_SET_OFFS(i, set_size, inv);
+-
+-		tmp[i] = buf[val_offs + set_offs];
+-	}
+-
+-	ret = hynix_get_majority(tmp, NAND_HYNIX_1XNM_RR_REPEAT, val);
+-	if (ret)
+-		return ret;
+-
+-	if (inv)
+-		*val = ~*val;
+-
+-	return 0;
+-}
+-
+-static u8 hynix_1xnm_mlc_read_retry_regs[] = {
+-	0xcc, 0xbf, 0xaa, 0xab, 0xcd, 0xad, 0xae, 0xaf
+-};
+-
+-static int hynix_mlc_1xnm_rr_init(struct nand_chip *chip,
+-				  const struct hynix_read_retry_otp *info)
+-{
+-	struct hynix_nand *hynix = nand_get_manufacturer_data(chip);
+-	struct hynix_read_retry *rr = NULL;
+-	int ret, i, j;
+-	u8 nregs, nmodes;
+-	u8 *buf;
+-
+-	buf = kmalloc(info->size, GFP_KERNEL);
+-	if (!buf)
+-		return -ENOMEM;
+-
+-	ret = hynix_read_rr_otp(chip, info, buf);
+-	if (ret)
+-		goto out;
+-
+-	ret = hynix_get_majority(buf, NAND_HYNIX_1XNM_RR_REPEAT,
+-				 &nmodes);
+-	if (ret)
+-		goto out;
+-
+-	ret = hynix_get_majority(buf + NAND_HYNIX_1XNM_RR_REPEAT,
+-				 NAND_HYNIX_1XNM_RR_REPEAT,
+-				 &nregs);
+-	if (ret)
+-		goto out;
+-
+-	rr = kzalloc(sizeof(*rr) + (nregs * nmodes), GFP_KERNEL);
+-	if (!rr) {
+-		ret = -ENOMEM;
+-		goto out;
+-	}
+-
+-	for (i = 0; i < nmodes; i++) {
+-		for (j = 0; j < nregs; j++) {
+-			u8 *val = rr->values + (i * nregs);
+-
+-			ret = hynix_mlc_1xnm_rr_value(buf, nmodes, nregs, i, j,
+-						      false, val);
+-			if (!ret)
+-				continue;
+-
+-			ret = hynix_mlc_1xnm_rr_value(buf, nmodes, nregs, i, j,
+-						      true, val);
+-			if (ret)
+-				goto out;
+-		}
+-	}
+-
+-	rr->nregs = nregs;
+-	rr->regs = hynix_1xnm_mlc_read_retry_regs;
+-	hynix->read_retry = rr;
+-	chip->setup_read_retry = hynix_nand_setup_read_retry;
+-	chip->read_retries = nmodes;
+-
+-out:
+-	kfree(buf);
+-
+-	if (ret)
+-		kfree(rr);
+-
+-	return ret;
+-}
+-
+-static const u8 hynix_mlc_1xnm_rr_otp_regs[] = { 0x38 };
+-static const u8 hynix_mlc_1xnm_rr_otp_values[] = { 0x52 };
+-
+-static const struct hynix_read_retry_otp hynix_mlc_1xnm_rr_otps[] = {
+-	{
+-		.nregs = ARRAY_SIZE(hynix_mlc_1xnm_rr_otp_regs),
+-		.regs = hynix_mlc_1xnm_rr_otp_regs,
+-		.values = hynix_mlc_1xnm_rr_otp_values,
+-		.page = 0x21f,
+-		.size = 784
+-	},
+-	{
+-		.nregs = ARRAY_SIZE(hynix_mlc_1xnm_rr_otp_regs),
+-		.regs = hynix_mlc_1xnm_rr_otp_regs,
+-		.values = hynix_mlc_1xnm_rr_otp_values,
+-		.page = 0x200,
+-		.size = 528,
+-	},
+-};
+-
+-static int hynix_nand_rr_init(struct nand_chip *chip)
+-{
+-	int i, ret = 0;
+-	bool valid_jedecid;
+-
+-	valid_jedecid = hynix_nand_has_valid_jedecid(chip);
+-
+-	/*
+-	 * We only support read-retry for 1xnm NANDs, and those NANDs all
+-	 * expose a valid JEDEC ID.
+-	 */
+-	if (valid_jedecid) {
+-		u8 nand_tech = chip->id.data[5] >> 4;
+-
+-		/* 1xnm technology */
+-		if (nand_tech == 4) {
+-			for (i = 0; i < ARRAY_SIZE(hynix_mlc_1xnm_rr_otps);
+-			     i++) {
+-				/*
+-				 * FIXME: Hynix recommend to copy the
+-				 * read-retry OTP area into a normal page.
+-				 */
+-				ret = hynix_mlc_1xnm_rr_init(chip,
+-						hynix_mlc_1xnm_rr_otps);
+-				if (!ret)
+-					break;
+-			}
+-		}
+-	}
+-
+-	if (ret)
+-		pr_warn("failed to initialize read-retry infrastructure");
+-
+-	return 0;
+-}
+-
+-static void hynix_nand_extract_oobsize(struct nand_chip *chip,
+-				       bool valid_jedecid)
+-{
+-	struct mtd_info *mtd = nand_to_mtd(chip);
+-	u8 oobsize;
+-
+-	oobsize = ((chip->id.data[3] >> 2) & 0x3) |
+-		  ((chip->id.data[3] >> 4) & 0x4);
+-
+-	if (valid_jedecid) {
+-		switch (oobsize) {
+-		case 0:
+-			mtd->oobsize = 2048;
+-			break;
+-		case 1:
+-			mtd->oobsize = 1664;
+-			break;
+-		case 2:
+-			mtd->oobsize = 1024;
+-			break;
+-		case 3:
+-			mtd->oobsize = 640;
+-			break;
+-		default:
+-			/*
+-			 * We should never reach this case, but if that
+-			 * happens, this probably means Hynix decided to use
+-			 * a different extended ID format, and we should find
+-			 * a way to support it.
+-			 */
+-			WARN(1, "Invalid OOB size");
+-			break;
+-		}
+-	} else {
+-		switch (oobsize) {
+-		case 0:
+-			mtd->oobsize = 128;
+-			break;
+-		case 1:
+-			mtd->oobsize = 224;
+-			break;
+-		case 2:
+-			mtd->oobsize = 448;
+-			break;
+-		case 3:
+-			mtd->oobsize = 64;
+-			break;
+-		case 4:
+-			mtd->oobsize = 32;
+-			break;
+-		case 5:
+-			mtd->oobsize = 16;
+-			break;
+-		case 6:
+-			mtd->oobsize = 640;
+-			break;
+-		default:
+-			/*
+-			 * We should never reach this case, but if that
+-			 * happens, this probably means Hynix decided to use
+-			 * a different extended ID format, and we should find
+-			 * a way to support it.
+-			 */
+-			WARN(1, "Invalid OOB size");
+-			break;
+-		}
+-	}
+-}
+-
+-static void hynix_nand_extract_ecc_requirements(struct nand_chip *chip,
+-						bool valid_jedecid)
+-{
+-	u8 ecc_level = (chip->id.data[4] >> 4) & 0x7;
+-
+-	if (valid_jedecid) {
+-		/* Reference: H27UCG8T2E datasheet */
+-		chip->ecc_step_ds = 1024;
+-
+-		switch (ecc_level) {
+-		case 0:
+-			chip->ecc_step_ds = 0;
+-			chip->ecc_strength_ds = 0;
+-			break;
+-		case 1:
+-			chip->ecc_strength_ds = 4;
+-			break;
+-		case 2:
+-			chip->ecc_strength_ds = 24;
+-			break;
+-		case 3:
+-			chip->ecc_strength_ds = 32;
+-			break;
+-		case 4:
+-			chip->ecc_strength_ds = 40;
+-			break;
+-		case 5:
+-			chip->ecc_strength_ds = 50;
+-			break;
+-		case 6:
+-			chip->ecc_strength_ds = 60;
+-			break;
+-		default:
+-			/*
+-			 * We should never reach this case, but if that
+-			 * happens, this probably means Hynix decided to use
+-			 * a different extended ID format, and we should find
+-			 * a way to support it.
+-			 */
+-			WARN(1, "Invalid ECC requirements");
+-		}
+-	} else {
+-		/*
+-		 * The ECC requirements field meaning depends on the
+-		 * NAND technology.
+-		 */
+-		u8 nand_tech = chip->id.data[5] & 0x7;
+-
+-		if (nand_tech < 3) {
+-			/* > 26nm, reference: H27UBG8T2A datasheet */
+-			if (ecc_level < 5) {
+-				chip->ecc_step_ds = 512;
+-				chip->ecc_strength_ds = 1 << ecc_level;
+-			} else if (ecc_level < 7) {
+-				if (ecc_level == 5)
+-					chip->ecc_step_ds = 2048;
+-				else
+-					chip->ecc_step_ds = 1024;
+-				chip->ecc_strength_ds = 24;
+-			} else {
+-				/*
+-				 * We should never reach this case, but if that
+-				 * happens, this probably means Hynix decided
+-				 * to use a different extended ID format, and
+-				 * we should find a way to support it.
+-				 */
+-				WARN(1, "Invalid ECC requirements");
+-			}
+-		} else {
+-			/* <= 26nm, reference: H27UBG8T2B datasheet */
+-			if (!ecc_level) {
+-				chip->ecc_step_ds = 0;
+-				chip->ecc_strength_ds = 0;
+-			} else if (ecc_level < 5) {
+-				chip->ecc_step_ds = 512;
+-				chip->ecc_strength_ds = 1 << (ecc_level - 1);
+-			} else {
+-				chip->ecc_step_ds = 1024;
+-				chip->ecc_strength_ds = 24 +
+-							(8 * (ecc_level - 5));
+-			}
+-		}
+-	}
+-}
+-
+-static void hynix_nand_extract_scrambling_requirements(struct nand_chip *chip,
+-						       bool valid_jedecid)
+-{
+-	u8 nand_tech;
+-
+-	/* We need scrambling on all TLC NANDs*/
+-	if (chip->bits_per_cell > 2)
+-		chip->options |= NAND_NEED_SCRAMBLING;
+-
+-	/* And on MLC NANDs with sub-3xnm process */
+-	if (valid_jedecid) {
+-		nand_tech = chip->id.data[5] >> 4;
+-
+-		/* < 3xnm */
+-		if (nand_tech > 0)
+-			chip->options |= NAND_NEED_SCRAMBLING;
+-	} else {
+-		nand_tech = chip->id.data[5] & 0x7;
+-
+-		/* < 32nm */
+-		if (nand_tech > 2)
+-			chip->options |= NAND_NEED_SCRAMBLING;
+-	}
+-}
+-
+-static void hynix_nand_decode_id(struct nand_chip *chip)
+-{
+-	struct mtd_info *mtd = nand_to_mtd(chip);
+-	bool valid_jedecid;
+-	u8 tmp;
+-
+-	/*
+-	 * Exclude all SLC NANDs from this advanced detection scheme.
+-	 * According to the ranges defined in several datasheets, it might
+-	 * appear that even SLC NANDs could fall in this extended ID scheme.
+-	 * If that the case rework the test to let SLC NANDs go through the
+-	 * detection process.
+-	 */
+-	if (chip->id.len < 6 || nand_is_slc(chip)) {
+-		nand_decode_ext_id(chip);
+-		return;
+-	}
+-
+-	/* Extract pagesize */
+-	mtd->writesize = 2048 << (chip->id.data[3] & 0x03);
+-
+-	tmp = (chip->id.data[3] >> 4) & 0x3;
+-	/*
+-	 * When bit7 is set that means we start counting at 1MiB, otherwise
+-	 * we start counting at 128KiB and shift this value the content of
+-	 * ID[3][4:5].
+-	 * The only exception is when ID[3][4:5] == 3 and ID[3][7] == 0, in
+-	 * this case the erasesize is set to 768KiB.
+-	 */
+-	if (chip->id.data[3] & 0x80)
+-		mtd->erasesize = SZ_1M << tmp;
+-	else if (tmp == 3)
+-		mtd->erasesize = SZ_512K + SZ_256K;
+-	else
+-		mtd->erasesize = SZ_128K << tmp;
+-
+-	/*
+-	 * Modern Toggle DDR NANDs have a valid JEDECID even though they are
+-	 * not exposing a valid JEDEC parameter table.
+-	 * These NANDs use a different NAND ID scheme.
+-	 */
+-	valid_jedecid = hynix_nand_has_valid_jedecid(chip);
+-
+-	hynix_nand_extract_oobsize(chip, valid_jedecid);
+-	hynix_nand_extract_ecc_requirements(chip, valid_jedecid);
+-	hynix_nand_extract_scrambling_requirements(chip, valid_jedecid);
+-}
+-
+-static void hynix_nand_cleanup(struct nand_chip *chip)
+-{
+-	struct hynix_nand *hynix = nand_get_manufacturer_data(chip);
+-
+-	if (!hynix)
+-		return;
+-
+-	kfree(hynix->read_retry);
+-	kfree(hynix);
+-	nand_set_manufacturer_data(chip, NULL);
+-}
+-
+-static int hynix_nand_init(struct nand_chip *chip)
+-{
+-	struct hynix_nand *hynix;
+-	int ret;
+-
+-	if (!nand_is_slc(chip))
+-		chip->bbt_options |= NAND_BBT_SCANLASTPAGE;
+-	else
+-		chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
+-
+-	hynix = kzalloc(sizeof(*hynix), GFP_KERNEL);
+-	if (!hynix)
+-		return -ENOMEM;
+-
+-	nand_set_manufacturer_data(chip, hynix);
+-
+-	ret = hynix_nand_rr_init(chip);
+-	if (ret)
+-		hynix_nand_cleanup(chip);
+-
+-	return ret;
+-}
+-
+-const struct nand_manufacturer_ops hynix_nand_manuf_ops = {
+-	.detect = hynix_nand_decode_id,
+-	.init = hynix_nand_init,
+-	.cleanup = hynix_nand_cleanup,
+-};
+diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c
+deleted file mode 100644
+index 5423c3b..0000000
+--- a/drivers/mtd/nand/nand_ids.c
++++ /dev/null
+@@ -1,207 +0,0 @@
+-/*
+- *  Copyright (C) 2002 Thomas Gleixner (tglx@linutronix.de)
+- *
+- * 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/mtd/rawnand.h>
+-#include <linux/sizes.h>
+-
+-#define LP_OPTIONS 0
+-#define LP_OPTIONS16 (LP_OPTIONS | NAND_BUSWIDTH_16)
+-
+-#define SP_OPTIONS NAND_NEED_READRDY
+-#define SP_OPTIONS16 (SP_OPTIONS | NAND_BUSWIDTH_16)
+-
+-/*
+- * The chip ID list:
+- *    name, device ID, page size, chip size in MiB, eraseblock size, options
+- *
+- * If page size and eraseblock size are 0, the sizes are taken from the
+- * extended chip ID.
+- */
+-struct nand_flash_dev nand_flash_ids[] = {
+-	/*
+-	 * Some incompatible NAND chips share device ID's and so must be
+-	 * listed by full ID. We list them first so that we can easily identify
+-	 * the most specific match.
+-	 */
+-	{"TC58NVG0S3E 1G 3.3V 8-bit",
+-		{ .id = {0x98, 0xd1, 0x90, 0x15, 0x76, 0x14, 0x01, 0x00} },
+-		  SZ_2K, SZ_128, SZ_128K, 0, 8, 64, NAND_ECC_INFO(1, SZ_512),
+-		  2 },
+-	{"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) },
+-	{"TC58NVG5D2 32G 3.3V 8-bit",
+-		{ .id = {0x98, 0xd7, 0x94, 0x32, 0x76, 0x56, 0x09, 0x00} },
+-		  SZ_8K, SZ_4K, SZ_1M, 0, 8, 640, NAND_ECC_INFO(40, SZ_1K) },
+-	{"TC58NVG6D2 64G 3.3V 8-bit",
+-		{ .id = {0x98, 0xde, 0x94, 0x82, 0x76, 0x56, 0x04, 0x20} },
+-		  SZ_8K, SZ_8K, SZ_2M, 0, 8, 640, NAND_ECC_INFO(40, SZ_1K) },
+-	{"SDTNRGAMA 64G 3.3V 8-bit",
+-		{ .id = {0x45, 0xde, 0x94, 0x93, 0x76, 0x50} },
+-		  SZ_16K, SZ_8K, SZ_4M, 0, 6, 1280, NAND_ECC_INFO(40, SZ_1K) },
+-	{"H27UCG8T2ATR-BC 64G 3.3V 8-bit",
+-		{ .id = {0xad, 0xde, 0x94, 0xda, 0x74, 0xc4} },
+-		  SZ_8K, SZ_8K, SZ_2M, NAND_NEED_SCRAMBLING, 6, 640,
+-		  NAND_ECC_INFO(40, SZ_1K), 4 },
+-
+-	LEGACY_ID_NAND("NAND 4MiB 5V 8-bit",   0x6B, 4, SZ_8K, SP_OPTIONS),
+-	LEGACY_ID_NAND("NAND 4MiB 3,3V 8-bit", 0xE3, 4, SZ_8K, SP_OPTIONS),
+-	LEGACY_ID_NAND("NAND 4MiB 3,3V 8-bit", 0xE5, 4, SZ_8K, SP_OPTIONS),
+-	LEGACY_ID_NAND("NAND 8MiB 3,3V 8-bit", 0xD6, 8, SZ_8K, SP_OPTIONS),
+-	LEGACY_ID_NAND("NAND 8MiB 3,3V 8-bit", 0xE6, 8, SZ_8K, SP_OPTIONS),
+-
+-	LEGACY_ID_NAND("NAND 16MiB 1,8V 8-bit",  0x33, 16, SZ_16K, SP_OPTIONS),
+-	LEGACY_ID_NAND("NAND 16MiB 3,3V 8-bit",  0x73, 16, SZ_16K, SP_OPTIONS),
+-	LEGACY_ID_NAND("NAND 16MiB 1,8V 16-bit", 0x43, 16, SZ_16K, SP_OPTIONS16),
+-	LEGACY_ID_NAND("NAND 16MiB 3,3V 16-bit", 0x53, 16, SZ_16K, SP_OPTIONS16),
+-
+-	LEGACY_ID_NAND("NAND 32MiB 1,8V 8-bit",  0x35, 32, SZ_16K, SP_OPTIONS),
+-	LEGACY_ID_NAND("NAND 32MiB 3,3V 8-bit",  0x75, 32, SZ_16K, SP_OPTIONS),
+-	LEGACY_ID_NAND("NAND 32MiB 1,8V 16-bit", 0x45, 32, SZ_16K, SP_OPTIONS16),
+-	LEGACY_ID_NAND("NAND 32MiB 3,3V 16-bit", 0x55, 32, SZ_16K, SP_OPTIONS16),
+-
+-	LEGACY_ID_NAND("NAND 64MiB 1,8V 8-bit",  0x36, 64, SZ_16K, SP_OPTIONS),
+-	LEGACY_ID_NAND("NAND 64MiB 3,3V 8-bit",  0x76, 64, SZ_16K, SP_OPTIONS),
+-	LEGACY_ID_NAND("NAND 64MiB 1,8V 16-bit", 0x46, 64, SZ_16K, SP_OPTIONS16),
+-	LEGACY_ID_NAND("NAND 64MiB 3,3V 16-bit", 0x56, 64, SZ_16K, SP_OPTIONS16),
+-
+-	LEGACY_ID_NAND("NAND 128MiB 1,8V 8-bit",  0x78, 128, SZ_16K, SP_OPTIONS),
+-	LEGACY_ID_NAND("NAND 128MiB 1,8V 8-bit",  0x39, 128, SZ_16K, SP_OPTIONS),
+-	LEGACY_ID_NAND("NAND 128MiB 3,3V 8-bit",  0x79, 128, SZ_16K, SP_OPTIONS),
+-	LEGACY_ID_NAND("NAND 128MiB 1,8V 16-bit", 0x72, 128, SZ_16K, SP_OPTIONS16),
+-	LEGACY_ID_NAND("NAND 128MiB 1,8V 16-bit", 0x49, 128, SZ_16K, SP_OPTIONS16),
+-	LEGACY_ID_NAND("NAND 128MiB 3,3V 16-bit", 0x74, 128, SZ_16K, SP_OPTIONS16),
+-	LEGACY_ID_NAND("NAND 128MiB 3,3V 16-bit", 0x59, 128, SZ_16K, SP_OPTIONS16),
+-
+-	LEGACY_ID_NAND("NAND 256MiB 3,3V 8-bit", 0x71, 256, SZ_16K, SP_OPTIONS),
+-
+-	/*
+-	 * These are the new chips with large page size. Their page size and
+-	 * eraseblock size are determined from the extended ID bytes.
+-	 */
+-
+-	/* 512 Megabit */
+-	EXTENDED_ID_NAND("NAND 64MiB 1,8V 8-bit",  0xA2,  64, LP_OPTIONS),
+-	EXTENDED_ID_NAND("NAND 64MiB 1,8V 8-bit",  0xA0,  64, LP_OPTIONS),
+-	EXTENDED_ID_NAND("NAND 64MiB 3,3V 8-bit",  0xF2,  64, LP_OPTIONS),
+-	EXTENDED_ID_NAND("NAND 64MiB 3,3V 8-bit",  0xD0,  64, LP_OPTIONS),
+-	EXTENDED_ID_NAND("NAND 64MiB 3,3V 8-bit",  0xF0,  64, LP_OPTIONS),
+-	EXTENDED_ID_NAND("NAND 64MiB 1,8V 16-bit", 0xB2,  64, LP_OPTIONS16),
+-	EXTENDED_ID_NAND("NAND 64MiB 1,8V 16-bit", 0xB0,  64, LP_OPTIONS16),
+-	EXTENDED_ID_NAND("NAND 64MiB 3,3V 16-bit", 0xC2,  64, LP_OPTIONS16),
+-	EXTENDED_ID_NAND("NAND 64MiB 3,3V 16-bit", 0xC0,  64, LP_OPTIONS16),
+-
+-	/* 1 Gigabit */
+-	EXTENDED_ID_NAND("NAND 128MiB 1,8V 8-bit",  0xA1, 128, LP_OPTIONS),
+-	EXTENDED_ID_NAND("NAND 128MiB 3,3V 8-bit",  0xF1, 128, LP_OPTIONS),
+-	EXTENDED_ID_NAND("NAND 128MiB 3,3V 8-bit",  0xD1, 128, LP_OPTIONS),
+-	EXTENDED_ID_NAND("NAND 128MiB 1,8V 16-bit", 0xB1, 128, LP_OPTIONS16),
+-	EXTENDED_ID_NAND("NAND 128MiB 3,3V 16-bit", 0xC1, 128, LP_OPTIONS16),
+-	EXTENDED_ID_NAND("NAND 128MiB 1,8V 16-bit", 0xAD, 128, LP_OPTIONS16),
+-
+-	/* 2 Gigabit */
+-	EXTENDED_ID_NAND("NAND 256MiB 1,8V 8-bit",  0xAA, 256, LP_OPTIONS),
+-	EXTENDED_ID_NAND("NAND 256MiB 3,3V 8-bit",  0xDA, 256, LP_OPTIONS),
+-	EXTENDED_ID_NAND("NAND 256MiB 1,8V 16-bit", 0xBA, 256, LP_OPTIONS16),
+-	EXTENDED_ID_NAND("NAND 256MiB 3,3V 16-bit", 0xCA, 256, LP_OPTIONS16),
+-
+-	/* 4 Gigabit */
+-	EXTENDED_ID_NAND("NAND 512MiB 1,8V 8-bit",  0xAC, 512, LP_OPTIONS),
+-	EXTENDED_ID_NAND("NAND 512MiB 3,3V 8-bit",  0xDC, 512, LP_OPTIONS),
+-	EXTENDED_ID_NAND("NAND 512MiB 1,8V 16-bit", 0xBC, 512, LP_OPTIONS16),
+-	EXTENDED_ID_NAND("NAND 512MiB 3,3V 16-bit", 0xCC, 512, LP_OPTIONS16),
+-
+-	/* 8 Gigabit */
+-	EXTENDED_ID_NAND("NAND 1GiB 1,8V 8-bit",  0xA3, 1024, LP_OPTIONS),
+-	EXTENDED_ID_NAND("NAND 1GiB 3,3V 8-bit",  0xD3, 1024, LP_OPTIONS),
+-	EXTENDED_ID_NAND("NAND 1GiB 1,8V 16-bit", 0xB3, 1024, LP_OPTIONS16),
+-	EXTENDED_ID_NAND("NAND 1GiB 3,3V 16-bit", 0xC3, 1024, LP_OPTIONS16),
+-
+-	/* 16 Gigabit */
+-	EXTENDED_ID_NAND("NAND 2GiB 1,8V 8-bit",  0xA5, 2048, LP_OPTIONS),
+-	EXTENDED_ID_NAND("NAND 2GiB 3,3V 8-bit",  0xD5, 2048, LP_OPTIONS),
+-	EXTENDED_ID_NAND("NAND 2GiB 1,8V 16-bit", 0xB5, 2048, LP_OPTIONS16),
+-	EXTENDED_ID_NAND("NAND 2GiB 3,3V 16-bit", 0xC5, 2048, LP_OPTIONS16),
+-
+-	/* 32 Gigabit */
+-	EXTENDED_ID_NAND("NAND 4GiB 1,8V 8-bit",  0xA7, 4096, LP_OPTIONS),
+-	EXTENDED_ID_NAND("NAND 4GiB 3,3V 8-bit",  0xD7, 4096, LP_OPTIONS),
+-	EXTENDED_ID_NAND("NAND 4GiB 1,8V 16-bit", 0xB7, 4096, LP_OPTIONS16),
+-	EXTENDED_ID_NAND("NAND 4GiB 3,3V 16-bit", 0xC7, 4096, LP_OPTIONS16),
+-
+-	/* 64 Gigabit */
+-	EXTENDED_ID_NAND("NAND 8GiB 1,8V 8-bit",  0xAE, 8192, LP_OPTIONS),
+-	EXTENDED_ID_NAND("NAND 8GiB 3,3V 8-bit",  0xDE, 8192, LP_OPTIONS),
+-	EXTENDED_ID_NAND("NAND 8GiB 1,8V 16-bit", 0xBE, 8192, LP_OPTIONS16),
+-	EXTENDED_ID_NAND("NAND 8GiB 3,3V 16-bit", 0xCE, 8192, LP_OPTIONS16),
+-
+-	/* 128 Gigabit */
+-	EXTENDED_ID_NAND("NAND 16GiB 1,8V 8-bit",  0x1A, 16384, LP_OPTIONS),
+-	EXTENDED_ID_NAND("NAND 16GiB 3,3V 8-bit",  0x3A, 16384, LP_OPTIONS),
+-	EXTENDED_ID_NAND("NAND 16GiB 1,8V 16-bit", 0x2A, 16384, LP_OPTIONS16),
+-	EXTENDED_ID_NAND("NAND 16GiB 3,3V 16-bit", 0x4A, 16384, LP_OPTIONS16),
+-
+-	/* 256 Gigabit */
+-	EXTENDED_ID_NAND("NAND 32GiB 1,8V 8-bit",  0x1C, 32768, LP_OPTIONS),
+-	EXTENDED_ID_NAND("NAND 32GiB 3,3V 8-bit",  0x3C, 32768, LP_OPTIONS),
+-	EXTENDED_ID_NAND("NAND 32GiB 1,8V 16-bit", 0x2C, 32768, LP_OPTIONS16),
+-	EXTENDED_ID_NAND("NAND 32GiB 3,3V 16-bit", 0x4C, 32768, LP_OPTIONS16),
+-
+-	/* 512 Gigabit */
+-	EXTENDED_ID_NAND("NAND 64GiB 1,8V 8-bit",  0x1E, 65536, LP_OPTIONS),
+-	EXTENDED_ID_NAND("NAND 64GiB 3,3V 8-bit",  0x3E, 65536, LP_OPTIONS),
+-	EXTENDED_ID_NAND("NAND 64GiB 1,8V 16-bit", 0x2E, 65536, LP_OPTIONS16),
+-	EXTENDED_ID_NAND("NAND 64GiB 3,3V 16-bit", 0x4E, 65536, LP_OPTIONS16),
+-
+-	{NULL}
+-};
+-
+-/* Manufacturer IDs */
+-static const struct nand_manufacturer nand_manufacturers[] = {
+-	{NAND_MFR_TOSHIBA, "Toshiba", &toshiba_nand_manuf_ops},
+-	{NAND_MFR_ESMT, "ESMT"},
+-	{NAND_MFR_SAMSUNG, "Samsung", &samsung_nand_manuf_ops},
+-	{NAND_MFR_FUJITSU, "Fujitsu"},
+-	{NAND_MFR_NATIONAL, "National"},
+-	{NAND_MFR_RENESAS, "Renesas"},
+-	{NAND_MFR_STMICRO, "ST Micro"},
+-	{NAND_MFR_HYNIX, "Hynix", &hynix_nand_manuf_ops},
+-	{NAND_MFR_MICRON, "Micron", &micron_nand_manuf_ops},
+-	{NAND_MFR_AMD, "AMD/Spansion", &amd_nand_manuf_ops},
+-	{NAND_MFR_MACRONIX, "Macronix", &macronix_nand_manuf_ops},
+-	{NAND_MFR_EON, "Eon"},
+-	{NAND_MFR_SANDISK, "SanDisk"},
+-	{NAND_MFR_INTEL, "Intel"},
+-	{NAND_MFR_ATO, "ATO"},
+-	{NAND_MFR_WINBOND, "Winbond"},
+-};
+-
+-/**
+- * nand_get_manufacturer - Get manufacturer information from the manufacturer
+- *			   ID
+- * @id: manufacturer ID
+- *
+- * Returns a pointer a nand_manufacturer object if the manufacturer is defined
+- * in the NAND manufacturers database, NULL otherwise.
+- */
+-const struct nand_manufacturer *nand_get_manufacturer(u8 id)
+-{
+-	int i;
+-
+-	for (i = 0; i < ARRAY_SIZE(nand_manufacturers); i++)
+-		if (nand_manufacturers[i].id == id)
+-			return &nand_manufacturers[i];
+-
+-	return NULL;
+-}
+diff --git a/drivers/mtd/nand/nand_macronix.c b/drivers/mtd/nand/nand_macronix.c
+deleted file mode 100644
+index d290ff2..0000000
+--- a/drivers/mtd/nand/nand_macronix.c
++++ /dev/null
+@@ -1,30 +0,0 @@
+-/*
+- * Copyright (C) 2017 Free Electrons
+- * Copyright (C) 2017 NextThing Co
+- *
+- * Author: Boris Brezillon <boris.brezillon@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 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/mtd/rawnand.h>
+-
+-static int macronix_nand_init(struct nand_chip *chip)
+-{
+-	if (nand_is_slc(chip))
+-		chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
+-
+-	return 0;
+-}
+-
+-const struct nand_manufacturer_ops macronix_nand_manuf_ops = {
+-	.init = macronix_nand_init,
+-};
+diff --git a/drivers/mtd/nand/nand_micron.c b/drivers/mtd/nand/nand_micron.c
+deleted file mode 100644
+index abf6a3c..0000000
+--- a/drivers/mtd/nand/nand_micron.c
++++ /dev/null
+@@ -1,308 +0,0 @@
+-/*
+- * Copyright (C) 2017 Free Electrons
+- * Copyright (C) 2017 NextThing Co
+- *
+- * Author: Boris Brezillon <boris.brezillon@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 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/mtd/rawnand.h>
+-
+-/*
+- * Special Micron status bit that indicates when the block has been
+- * corrected by on-die ECC and should be rewritten
+- */
+-#define NAND_STATUS_WRITE_RECOMMENDED	BIT(3)
+-
+-struct nand_onfi_vendor_micron {
+-	u8 two_plane_read;
+-	u8 read_cache;
+-	u8 read_unique_id;
+-	u8 dq_imped;
+-	u8 dq_imped_num_settings;
+-	u8 dq_imped_feat_addr;
+-	u8 rb_pulldown_strength;
+-	u8 rb_pulldown_strength_feat_addr;
+-	u8 rb_pulldown_strength_num_settings;
+-	u8 otp_mode;
+-	u8 otp_page_start;
+-	u8 otp_data_prot_addr;
+-	u8 otp_num_pages;
+-	u8 otp_feat_addr;
+-	u8 read_retry_options;
+-	u8 reserved[72];
+-	u8 param_revision;
+-} __packed;
+-
+-static int micron_nand_setup_read_retry(struct mtd_info *mtd, int retry_mode)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	u8 feature[ONFI_SUBFEATURE_PARAM_LEN] = {retry_mode};
+-
+-	return chip->onfi_set_features(mtd, chip, ONFI_FEATURE_ADDR_READ_RETRY,
+-				       feature);
+-}
+-
+-/*
+- * Configure chip properties from Micron vendor-specific ONFI table
+- */
+-static int micron_nand_onfi_init(struct nand_chip *chip)
+-{
+-	struct nand_onfi_params *p = &chip->onfi_params;
+-	struct nand_onfi_vendor_micron *micron = (void *)p->vendor;
+-
+-	if (!chip->onfi_version)
+-		return 0;
+-
+-	if (le16_to_cpu(p->vendor_revision) < 1)
+-		return 0;
+-
+-	chip->read_retries = micron->read_retry_options;
+-	chip->setup_read_retry = micron_nand_setup_read_retry;
+-
+-	return 0;
+-}
+-
+-static int micron_nand_on_die_ooblayout_ecc(struct mtd_info *mtd, int section,
+-					    struct mtd_oob_region *oobregion)
+-{
+-	if (section >= 4)
+-		return -ERANGE;
+-
+-	oobregion->offset = (section * 16) + 8;
+-	oobregion->length = 8;
+-
+-	return 0;
+-}
+-
+-static int micron_nand_on_die_ooblayout_free(struct mtd_info *mtd, int section,
+-					     struct mtd_oob_region *oobregion)
+-{
+-	if (section >= 4)
+-		return -ERANGE;
+-
+-	oobregion->offset = (section * 16) + 2;
+-	oobregion->length = 6;
+-
+-	return 0;
+-}
+-
+-static const struct mtd_ooblayout_ops micron_nand_on_die_ooblayout_ops = {
+-	.ecc = micron_nand_on_die_ooblayout_ecc,
+-	.free = micron_nand_on_die_ooblayout_free,
+-};
+-
+-static int micron_nand_on_die_ecc_setup(struct nand_chip *chip, bool enable)
+-{
+-	u8 feature[ONFI_SUBFEATURE_PARAM_LEN] = { 0, };
+-
+-	if (enable)
+-		feature[0] |= ONFI_FEATURE_ON_DIE_ECC_EN;
+-
+-	return chip->onfi_set_features(nand_to_mtd(chip), chip,
+-				       ONFI_FEATURE_ON_DIE_ECC, feature);
+-}
+-
+-static int
+-micron_nand_read_page_on_die_ecc(struct mtd_info *mtd, struct nand_chip *chip,
+-				 uint8_t *buf, int oob_required,
+-				 int page)
+-{
+-	int status;
+-	int max_bitflips = 0;
+-
+-	micron_nand_on_die_ecc_setup(chip, true);
+-
+-	chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
+-	chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
+-	status = chip->read_byte(mtd);
+-	if (status & NAND_STATUS_FAIL)
+-		mtd->ecc_stats.failed++;
+-	/*
+-	 * The internal ECC doesn't tell us the number of bitflips
+-	 * that have been corrected, but tells us if it recommends to
+-	 * rewrite the block. If it's the case, then we pretend we had
+-	 * a number of bitflips equal to the ECC strength, which will
+-	 * hint the NAND core to rewrite the block.
+-	 */
+-	else if (status & NAND_STATUS_WRITE_RECOMMENDED)
+-		max_bitflips = chip->ecc.strength;
+-
+-	chip->cmdfunc(mtd, NAND_CMD_READ0, -1, -1);
+-
+-	nand_read_page_raw(mtd, chip, buf, oob_required, page);
+-
+-	micron_nand_on_die_ecc_setup(chip, false);
+-
+-	return max_bitflips;
+-}
+-
+-static int
+-micron_nand_write_page_on_die_ecc(struct mtd_info *mtd, struct nand_chip *chip,
+-				  const uint8_t *buf, int oob_required,
+-				  int page)
+-{
+-	int status;
+-
+-	micron_nand_on_die_ecc_setup(chip, true);
+-
+-	chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
+-	nand_write_page_raw(mtd, chip, buf, oob_required, page);
+-	chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+-	status = chip->waitfunc(mtd, chip);
+-
+-	micron_nand_on_die_ecc_setup(chip, false);
+-
+-	return status & NAND_STATUS_FAIL ? -EIO : 0;
+-}
+-
+-static int
+-micron_nand_read_page_raw_on_die_ecc(struct mtd_info *mtd,
+-				     struct nand_chip *chip,
+-				     uint8_t *buf, int oob_required,
+-				     int page)
+-{
+-	chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
+-	nand_read_page_raw(mtd, chip, buf, oob_required, page);
+-
+-	return 0;
+-}
+-
+-static int
+-micron_nand_write_page_raw_on_die_ecc(struct mtd_info *mtd,
+-				      struct nand_chip *chip,
+-				      const uint8_t *buf, int oob_required,
+-				      int page)
+-{
+-	int status;
+-
+-	chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
+-	nand_write_page_raw(mtd, chip, buf, oob_required, page);
+-	chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+-	status = chip->waitfunc(mtd, chip);
+-
+-	return status & NAND_STATUS_FAIL ? -EIO : 0;
+-}
+-
+-enum {
+-	/* The NAND flash doesn't support on-die ECC */
+-	MICRON_ON_DIE_UNSUPPORTED,
+-
+-	/*
+-	 * The NAND flash supports on-die ECC and it can be
+-	 * enabled/disabled by a set features command.
+-	 */
+-	MICRON_ON_DIE_SUPPORTED,
+-
+-	/*
+-	 * The NAND flash supports on-die ECC, and it cannot be
+-	 * disabled.
+-	 */
+-	MICRON_ON_DIE_MANDATORY,
+-};
+-
+-/*
+- * Try to detect if the NAND support on-die ECC. To do this, we enable
+- * the feature, and read back if it has been enabled as expected. We
+- * also check if it can be disabled, because some Micron NANDs do not
+- * allow disabling the on-die ECC and we don't support such NANDs for
+- * now.
+- *
+- * This function also has the side effect of disabling on-die ECC if
+- * it had been left enabled by the firmware/bootloader.
+- */
+-static int micron_supports_on_die_ecc(struct nand_chip *chip)
+-{
+-	u8 feature[ONFI_SUBFEATURE_PARAM_LEN] = { 0, };
+-	int ret;
+-
+-	if (chip->onfi_version == 0)
+-		return MICRON_ON_DIE_UNSUPPORTED;
+-
+-	if (chip->bits_per_cell != 1)
+-		return MICRON_ON_DIE_UNSUPPORTED;
+-
+-	ret = micron_nand_on_die_ecc_setup(chip, true);
+-	if (ret)
+-		return MICRON_ON_DIE_UNSUPPORTED;
+-
+-	chip->onfi_get_features(nand_to_mtd(chip), chip,
+-				ONFI_FEATURE_ON_DIE_ECC, feature);
+-	if ((feature[0] & ONFI_FEATURE_ON_DIE_ECC_EN) == 0)
+-		return MICRON_ON_DIE_UNSUPPORTED;
+-
+-	ret = micron_nand_on_die_ecc_setup(chip, false);
+-	if (ret)
+-		return MICRON_ON_DIE_UNSUPPORTED;
+-
+-	chip->onfi_get_features(nand_to_mtd(chip), chip,
+-				ONFI_FEATURE_ON_DIE_ECC, feature);
+-	if (feature[0] & ONFI_FEATURE_ON_DIE_ECC_EN)
+-		return MICRON_ON_DIE_MANDATORY;
+-
+-	/*
+-	 * Some Micron NANDs have an on-die ECC of 4/512, some other
+-	 * 8/512. We only support the former.
+-	 */
+-	if (chip->onfi_params.ecc_bits != 4)
+-		return MICRON_ON_DIE_UNSUPPORTED;
+-
+-	return MICRON_ON_DIE_SUPPORTED;
+-}
+-
+-static int micron_nand_init(struct nand_chip *chip)
+-{
+-	struct mtd_info *mtd = nand_to_mtd(chip);
+-	int ondie;
+-	int ret;
+-
+-	ret = micron_nand_onfi_init(chip);
+-	if (ret)
+-		return ret;
+-
+-	if (mtd->writesize == 2048)
+-		chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
+-
+-	ondie = micron_supports_on_die_ecc(chip);
+-
+-	if (ondie == MICRON_ON_DIE_MANDATORY) {
+-		pr_err("On-die ECC forcefully enabled, not supported\n");
+-		return -EINVAL;
+-	}
+-
+-	if (chip->ecc.mode == NAND_ECC_ON_DIE) {
+-		if (ondie == MICRON_ON_DIE_UNSUPPORTED) {
+-			pr_err("On-die ECC selected but not supported\n");
+-			return -EINVAL;
+-		}
+-
+-		chip->ecc.options = NAND_ECC_CUSTOM_PAGE_ACCESS;
+-		chip->ecc.bytes = 8;
+-		chip->ecc.size = 512;
+-		chip->ecc.strength = 4;
+-		chip->ecc.algo = NAND_ECC_BCH;
+-		chip->ecc.read_page = micron_nand_read_page_on_die_ecc;
+-		chip->ecc.write_page = micron_nand_write_page_on_die_ecc;
+-		chip->ecc.read_page_raw =
+-			micron_nand_read_page_raw_on_die_ecc;
+-		chip->ecc.write_page_raw =
+-			micron_nand_write_page_raw_on_die_ecc;
+-
+-		mtd_set_ooblayout(mtd, &micron_nand_on_die_ooblayout_ops);
+-	}
+-
+-	return 0;
+-}
+-
+-const struct nand_manufacturer_ops micron_nand_manuf_ops = {
+-	.init = micron_nand_init,
+-};
+diff --git a/drivers/mtd/nand/nand_samsung.c b/drivers/mtd/nand/nand_samsung.c
+deleted file mode 100644
+index d348f01..0000000
+--- a/drivers/mtd/nand/nand_samsung.c
++++ /dev/null
+@@ -1,115 +0,0 @@
+-/*
+- * Copyright (C) 2017 Free Electrons
+- * Copyright (C) 2017 NextThing Co
+- *
+- * Author: Boris Brezillon <boris.brezillon@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 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/mtd/rawnand.h>
+-
+-static void samsung_nand_decode_id(struct nand_chip *chip)
+-{
+-	struct mtd_info *mtd = nand_to_mtd(chip);
+-
+-	/* New Samsung (6 byte ID): Samsung K9GAG08U0F (p.44) */
+-	if (chip->id.len == 6 && !nand_is_slc(chip) &&
+-	    chip->id.data[5] != 0x00) {
+-		u8 extid = chip->id.data[3];
+-
+-		/* Get pagesize */
+-		mtd->writesize = 2048 << (extid & 0x03);
+-
+-		extid >>= 2;
+-
+-		/* Get oobsize */
+-		switch (((extid >> 2) & 0x4) | (extid & 0x3)) {
+-		case 1:
+-			mtd->oobsize = 128;
+-			break;
+-		case 2:
+-			mtd->oobsize = 218;
+-			break;
+-		case 3:
+-			mtd->oobsize = 400;
+-			break;
+-		case 4:
+-			mtd->oobsize = 436;
+-			break;
+-		case 5:
+-			mtd->oobsize = 512;
+-			break;
+-		case 6:
+-			mtd->oobsize = 640;
+-			break;
+-		default:
+-			/*
+-			 * We should never reach this case, but if that
+-			 * happens, this probably means Samsung decided to use
+-			 * a different extended ID format, and we should find
+-			 * a way to support it.
+-			 */
+-			WARN(1, "Invalid OOB size value");
+-			break;
+-		}
+-
+-		/* Get blocksize */
+-		extid >>= 2;
+-		mtd->erasesize = (128 * 1024) <<
+-				 (((extid >> 1) & 0x04) | (extid & 0x03));
+-
+-		/* Extract ECC requirements from 5th id byte*/
+-		extid = (chip->id.data[4] >> 4) & 0x07;
+-		if (extid < 5) {
+-			chip->ecc_step_ds = 512;
+-			chip->ecc_strength_ds = 1 << extid;
+-		} else {
+-			chip->ecc_step_ds = 1024;
+-			switch (extid) {
+-			case 5:
+-				chip->ecc_strength_ds = 24;
+-				break;
+-			case 6:
+-				chip->ecc_strength_ds = 40;
+-				break;
+-			case 7:
+-				chip->ecc_strength_ds = 60;
+-				break;
+-			default:
+-				WARN(1, "Could not decode ECC info");
+-				chip->ecc_step_ds = 0;
+-			}
+-		}
+-	} else {
+-		nand_decode_ext_id(chip);
+-	}
+-}
+-
+-static int samsung_nand_init(struct nand_chip *chip)
+-{
+-	struct mtd_info *mtd = nand_to_mtd(chip);
+-
+-	if (mtd->writesize > 512)
+-		chip->options |= NAND_SAMSUNG_LP_OPTIONS;
+-
+-	if (!nand_is_slc(chip))
+-		chip->bbt_options |= NAND_BBT_SCANLASTPAGE;
+-	else
+-		chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
+-
+-	return 0;
+-}
+-
+-const struct nand_manufacturer_ops samsung_nand_manuf_ops = {
+-	.detect = samsung_nand_decode_id,
+-	.init = samsung_nand_init,
+-};
+diff --git a/drivers/mtd/nand/nand_timings.c b/drivers/mtd/nand/nand_timings.c
+deleted file mode 100644
+index 5d1533b..0000000
+--- a/drivers/mtd/nand/nand_timings.c
++++ /dev/null
+@@ -1,335 +0,0 @@
+-/*
+- *  Copyright (C) 2014 Free Electrons
+- *
+- *  Author: Boris BREZILLON <boris.brezillon@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.
+- *
+- */
+-#include <linux/kernel.h>
+-#include <linux/err.h>
+-#include <linux/export.h>
+-#include <linux/mtd/rawnand.h>
+-
+-static const struct nand_data_interface onfi_sdr_timings[] = {
+-	/* Mode 0 */
+-	{
+-		.type = NAND_SDR_IFACE,
+-		.timings.sdr = {
+-			.tCCS_min = 500000,
+-			.tR_max = 200000000,
+-			.tADL_min = 400000,
+-			.tALH_min = 20000,
+-			.tALS_min = 50000,
+-			.tAR_min = 25000,
+-			.tCEA_max = 100000,
+-			.tCEH_min = 20000,
+-			.tCH_min = 20000,
+-			.tCHZ_max = 100000,
+-			.tCLH_min = 20000,
+-			.tCLR_min = 20000,
+-			.tCLS_min = 50000,
+-			.tCOH_min = 0,
+-			.tCS_min = 70000,
+-			.tDH_min = 20000,
+-			.tDS_min = 40000,
+-			.tFEAT_max = 1000000,
+-			.tIR_min = 10000,
+-			.tITC_max = 1000000,
+-			.tRC_min = 100000,
+-			.tREA_max = 40000,
+-			.tREH_min = 30000,
+-			.tRHOH_min = 0,
+-			.tRHW_min = 200000,
+-			.tRHZ_max = 200000,
+-			.tRLOH_min = 0,
+-			.tRP_min = 50000,
+-			.tRR_min = 40000,
+-			.tRST_max = 250000000000ULL,
+-			.tWB_max = 200000,
+-			.tWC_min = 100000,
+-			.tWH_min = 30000,
+-			.tWHR_min = 120000,
+-			.tWP_min = 50000,
+-			.tWW_min = 100000,
+-		},
+-	},
+-	/* Mode 1 */
+-	{
+-		.type = NAND_SDR_IFACE,
+-		.timings.sdr = {
+-			.tCCS_min = 500000,
+-			.tR_max = 200000000,
+-			.tADL_min = 400000,
+-			.tALH_min = 10000,
+-			.tALS_min = 25000,
+-			.tAR_min = 10000,
+-			.tCEA_max = 45000,
+-			.tCEH_min = 20000,
+-			.tCH_min = 10000,
+-			.tCHZ_max = 50000,
+-			.tCLH_min = 10000,
+-			.tCLR_min = 10000,
+-			.tCLS_min = 25000,
+-			.tCOH_min = 15000,
+-			.tCS_min = 35000,
+-			.tDH_min = 10000,
+-			.tDS_min = 20000,
+-			.tFEAT_max = 1000000,
+-			.tIR_min = 0,
+-			.tITC_max = 1000000,
+-			.tRC_min = 50000,
+-			.tREA_max = 30000,
+-			.tREH_min = 15000,
+-			.tRHOH_min = 15000,
+-			.tRHW_min = 100000,
+-			.tRHZ_max = 100000,
+-			.tRLOH_min = 0,
+-			.tRP_min = 25000,
+-			.tRR_min = 20000,
+-			.tRST_max = 500000000,
+-			.tWB_max = 100000,
+-			.tWC_min = 45000,
+-			.tWH_min = 15000,
+-			.tWHR_min = 80000,
+-			.tWP_min = 25000,
+-			.tWW_min = 100000,
+-		},
+-	},
+-	/* Mode 2 */
+-	{
+-		.type = NAND_SDR_IFACE,
+-		.timings.sdr = {
+-			.tCCS_min = 500000,
+-			.tR_max = 200000000,
+-			.tADL_min = 400000,
+-			.tALH_min = 10000,
+-			.tALS_min = 15000,
+-			.tAR_min = 10000,
+-			.tCEA_max = 30000,
+-			.tCEH_min = 20000,
+-			.tCH_min = 10000,
+-			.tCHZ_max = 50000,
+-			.tCLH_min = 10000,
+-			.tCLR_min = 10000,
+-			.tCLS_min = 15000,
+-			.tCOH_min = 15000,
+-			.tCS_min = 25000,
+-			.tDH_min = 5000,
+-			.tDS_min = 15000,
+-			.tFEAT_max = 1000000,
+-			.tIR_min = 0,
+-			.tITC_max = 1000000,
+-			.tRC_min = 35000,
+-			.tREA_max = 25000,
+-			.tREH_min = 15000,
+-			.tRHOH_min = 15000,
+-			.tRHW_min = 100000,
+-			.tRHZ_max = 100000,
+-			.tRLOH_min = 0,
+-			.tRR_min = 20000,
+-			.tRST_max = 500000000,
+-			.tWB_max = 100000,
+-			.tRP_min = 17000,
+-			.tWC_min = 35000,
+-			.tWH_min = 15000,
+-			.tWHR_min = 80000,
+-			.tWP_min = 17000,
+-			.tWW_min = 100000,
+-		},
+-	},
+-	/* Mode 3 */
+-	{
+-		.type = NAND_SDR_IFACE,
+-		.timings.sdr = {
+-			.tCCS_min = 500000,
+-			.tR_max = 200000000,
+-			.tADL_min = 400000,
+-			.tALH_min = 5000,
+-			.tALS_min = 10000,
+-			.tAR_min = 10000,
+-			.tCEA_max = 25000,
+-			.tCEH_min = 20000,
+-			.tCH_min = 5000,
+-			.tCHZ_max = 50000,
+-			.tCLH_min = 5000,
+-			.tCLR_min = 10000,
+-			.tCLS_min = 10000,
+-			.tCOH_min = 15000,
+-			.tCS_min = 25000,
+-			.tDH_min = 5000,
+-			.tDS_min = 10000,
+-			.tFEAT_max = 1000000,
+-			.tIR_min = 0,
+-			.tITC_max = 1000000,
+-			.tRC_min = 30000,
+-			.tREA_max = 20000,
+-			.tREH_min = 10000,
+-			.tRHOH_min = 15000,
+-			.tRHW_min = 100000,
+-			.tRHZ_max = 100000,
+-			.tRLOH_min = 0,
+-			.tRP_min = 15000,
+-			.tRR_min = 20000,
+-			.tRST_max = 500000000,
+-			.tWB_max = 100000,
+-			.tWC_min = 30000,
+-			.tWH_min = 10000,
+-			.tWHR_min = 80000,
+-			.tWP_min = 15000,
+-			.tWW_min = 100000,
+-		},
+-	},
+-	/* Mode 4 */
+-	{
+-		.type = NAND_SDR_IFACE,
+-		.timings.sdr = {
+-			.tCCS_min = 500000,
+-			.tR_max = 200000000,
+-			.tADL_min = 400000,
+-			.tALH_min = 5000,
+-			.tALS_min = 10000,
+-			.tAR_min = 10000,
+-			.tCEA_max = 25000,
+-			.tCEH_min = 20000,
+-			.tCH_min = 5000,
+-			.tCHZ_max = 30000,
+-			.tCLH_min = 5000,
+-			.tCLR_min = 10000,
+-			.tCLS_min = 10000,
+-			.tCOH_min = 15000,
+-			.tCS_min = 20000,
+-			.tDH_min = 5000,
+-			.tDS_min = 10000,
+-			.tFEAT_max = 1000000,
+-			.tIR_min = 0,
+-			.tITC_max = 1000000,
+-			.tRC_min = 25000,
+-			.tREA_max = 20000,
+-			.tREH_min = 10000,
+-			.tRHOH_min = 15000,
+-			.tRHW_min = 100000,
+-			.tRHZ_max = 100000,
+-			.tRLOH_min = 5000,
+-			.tRP_min = 12000,
+-			.tRR_min = 20000,
+-			.tRST_max = 500000000,
+-			.tWB_max = 100000,
+-			.tWC_min = 25000,
+-			.tWH_min = 10000,
+-			.tWHR_min = 80000,
+-			.tWP_min = 12000,
+-			.tWW_min = 100000,
+-		},
+-	},
+-	/* Mode 5 */
+-	{
+-		.type = NAND_SDR_IFACE,
+-		.timings.sdr = {
+-			.tCCS_min = 500000,
+-			.tR_max = 200000000,
+-			.tADL_min = 400000,
+-			.tALH_min = 5000,
+-			.tALS_min = 10000,
+-			.tAR_min = 10000,
+-			.tCEA_max = 25000,
+-			.tCEH_min = 20000,
+-			.tCH_min = 5000,
+-			.tCHZ_max = 30000,
+-			.tCLH_min = 5000,
+-			.tCLR_min = 10000,
+-			.tCLS_min = 10000,
+-			.tCOH_min = 15000,
+-			.tCS_min = 15000,
+-			.tDH_min = 5000,
+-			.tDS_min = 7000,
+-			.tFEAT_max = 1000000,
+-			.tIR_min = 0,
+-			.tITC_max = 1000000,
+-			.tRC_min = 20000,
+-			.tREA_max = 16000,
+-			.tREH_min = 7000,
+-			.tRHOH_min = 15000,
+-			.tRHW_min = 100000,
+-			.tRHZ_max = 100000,
+-			.tRLOH_min = 5000,
+-			.tRP_min = 10000,
+-			.tRR_min = 20000,
+-			.tRST_max = 500000000,
+-			.tWB_max = 100000,
+-			.tWC_min = 20000,
+-			.tWH_min = 7000,
+-			.tWHR_min = 80000,
+-			.tWP_min = 10000,
+-			.tWW_min = 100000,
+-		},
+-	},
+-};
+-
+-/**
+- * onfi_async_timing_mode_to_sdr_timings - [NAND Interface] Retrieve NAND
+- * timings according to the given ONFI timing mode
+- * @mode: ONFI timing mode
+- */
+-const struct nand_sdr_timings *onfi_async_timing_mode_to_sdr_timings(int mode)
+-{
+-	if (mode < 0 || mode >= ARRAY_SIZE(onfi_sdr_timings))
+-		return ERR_PTR(-EINVAL);
+-
+-	return &onfi_sdr_timings[mode].timings.sdr;
+-}
+-EXPORT_SYMBOL(onfi_async_timing_mode_to_sdr_timings);
+-
+-/**
+- * onfi_init_data_interface - [NAND Interface] Initialize a data interface from
+- * given ONFI mode
+- * @iface: The data interface to be initialized
+- * @mode: The ONFI timing mode
+- */
+-int onfi_init_data_interface(struct nand_chip *chip,
+-			     struct nand_data_interface *iface,
+-			     enum nand_data_interface_type type,
+-			     int timing_mode)
+-{
+-	if (type != NAND_SDR_IFACE)
+-		return -EINVAL;
+-
+-	if (timing_mode < 0 || timing_mode >= ARRAY_SIZE(onfi_sdr_timings))
+-		return -EINVAL;
+-
+-	*iface = onfi_sdr_timings[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 = 1000000ULL * le16_to_cpu(params->t_prog);
+-		timings->tBERS_max = 1000000ULL * le16_to_cpu(params->t_bers);
+-		timings->tR_max = 1000000ULL * le16_to_cpu(params->t_r);
+-
+-		/* nanoseconds -> picoseconds */
+-		timings->tCCS_min = 1000UL * le16_to_cpu(params->t_ccs);
+-	}
+-
+-	return 0;
+-}
+-EXPORT_SYMBOL(onfi_init_data_interface);
+-
+-/**
+- * 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);
+diff --git a/drivers/mtd/nand/nand_toshiba.c b/drivers/mtd/nand/nand_toshiba.c
+deleted file mode 100644
+index 57df857..0000000
+--- a/drivers/mtd/nand/nand_toshiba.c
++++ /dev/null
+@@ -1,51 +0,0 @@
+-/*
+- * Copyright (C) 2017 Free Electrons
+- * Copyright (C) 2017 NextThing Co
+- *
+- * Author: Boris Brezillon <boris.brezillon@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 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/mtd/rawnand.h>
+-
+-static void toshiba_nand_decode_id(struct nand_chip *chip)
+-{
+-	struct mtd_info *mtd = nand_to_mtd(chip);
+-
+-	nand_decode_ext_id(chip);
+-
+-	/*
+-	 * Toshiba 24nm raw SLC (i.e., not BENAND) have 32B OOB per
+-	 * 512B page. For Toshiba SLC, we decode the 5th/6th byte as
+-	 * follows:
+-	 * - ID byte 6, bits[2:0]: 100b -> 43nm, 101b -> 32nm,
+-	 *                         110b -> 24nm
+-	 * - ID byte 5, bit[7]:    1 -> BENAND, 0 -> raw SLC
+-	 */
+-	if (chip->id.len >= 6 && nand_is_slc(chip) &&
+-	    (chip->id.data[5] & 0x7) == 0x6 /* 24nm */ &&
+-	    !(chip->id.data[4] & 0x80) /* !BENAND */)
+-		mtd->oobsize = 32 * mtd->writesize >> 9;
+-}
+-
+-static int toshiba_nand_init(struct nand_chip *chip)
+-{
+-	if (nand_is_slc(chip))
+-		chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
+-
+-	return 0;
+-}
+-
+-const struct nand_manufacturer_ops toshiba_nand_manuf_ops = {
+-	.detect = toshiba_nand_decode_id,
+-	.init = toshiba_nand_init,
+-};
+diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
+deleted file mode 100644
+index 44322a3..0000000
+--- a/drivers/mtd/nand/nandsim.c
++++ /dev/null
+@@ -1,2392 +0,0 @@
+-/*
+- * NAND flash simulator.
+- *
+- * Author: Artem B. Bityuckiy <dedekind@oktetlabs.ru>, <dedekind@infradead.org>
+- *
+- * Copyright (C) 2004 Nokia Corporation
+- *
+- * Note: NS means "NAND Simulator".
+- * Note: Input means input TO flash chip, output means output FROM chip.
+- *
+- * 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, 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.
+- *
+- * You should have received a copy of the GNU General Public License
+- * along with this program; if not, write to the Free Software
+- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
+- */
+-
+-#include <linux/init.h>
+-#include <linux/types.h>
+-#include <linux/module.h>
+-#include <linux/moduleparam.h>
+-#include <linux/vmalloc.h>
+-#include <linux/math64.h>
+-#include <linux/slab.h>
+-#include <linux/errno.h>
+-#include <linux/string.h>
+-#include <linux/mtd/mtd.h>
+-#include <linux/mtd/rawnand.h>
+-#include <linux/mtd/nand_bch.h>
+-#include <linux/mtd/partitions.h>
+-#include <linux/delay.h>
+-#include <linux/list.h>
+-#include <linux/random.h>
+-#include <linux/sched.h>
+-#include <linux/sched/mm.h>
+-#include <linux/fs.h>
+-#include <linux/pagemap.h>
+-#include <linux/seq_file.h>
+-#include <linux/debugfs.h>
+-
+-/* Default simulator parameters values */
+-#if !defined(CONFIG_NANDSIM_FIRST_ID_BYTE)  || \
+-    !defined(CONFIG_NANDSIM_SECOND_ID_BYTE) || \
+-    !defined(CONFIG_NANDSIM_THIRD_ID_BYTE)  || \
+-    !defined(CONFIG_NANDSIM_FOURTH_ID_BYTE)
+-#define CONFIG_NANDSIM_FIRST_ID_BYTE  0x98
+-#define CONFIG_NANDSIM_SECOND_ID_BYTE 0x39
+-#define CONFIG_NANDSIM_THIRD_ID_BYTE  0xFF /* No byte */
+-#define CONFIG_NANDSIM_FOURTH_ID_BYTE 0xFF /* No byte */
+-#endif
+-
+-#ifndef CONFIG_NANDSIM_ACCESS_DELAY
+-#define CONFIG_NANDSIM_ACCESS_DELAY 25
+-#endif
+-#ifndef CONFIG_NANDSIM_PROGRAMM_DELAY
+-#define CONFIG_NANDSIM_PROGRAMM_DELAY 200
+-#endif
+-#ifndef CONFIG_NANDSIM_ERASE_DELAY
+-#define CONFIG_NANDSIM_ERASE_DELAY 2
+-#endif
+-#ifndef CONFIG_NANDSIM_OUTPUT_CYCLE
+-#define CONFIG_NANDSIM_OUTPUT_CYCLE 40
+-#endif
+-#ifndef CONFIG_NANDSIM_INPUT_CYCLE
+-#define CONFIG_NANDSIM_INPUT_CYCLE  50
+-#endif
+-#ifndef CONFIG_NANDSIM_BUS_WIDTH
+-#define CONFIG_NANDSIM_BUS_WIDTH  8
+-#endif
+-#ifndef CONFIG_NANDSIM_DO_DELAYS
+-#define CONFIG_NANDSIM_DO_DELAYS  0
+-#endif
+-#ifndef CONFIG_NANDSIM_LOG
+-#define CONFIG_NANDSIM_LOG        0
+-#endif
+-#ifndef CONFIG_NANDSIM_DBG
+-#define CONFIG_NANDSIM_DBG        0
+-#endif
+-#ifndef CONFIG_NANDSIM_MAX_PARTS
+-#define CONFIG_NANDSIM_MAX_PARTS  32
+-#endif
+-
+-static uint access_delay   = CONFIG_NANDSIM_ACCESS_DELAY;
+-static uint programm_delay = CONFIG_NANDSIM_PROGRAMM_DELAY;
+-static uint erase_delay    = CONFIG_NANDSIM_ERASE_DELAY;
+-static uint output_cycle   = CONFIG_NANDSIM_OUTPUT_CYCLE;
+-static uint input_cycle    = CONFIG_NANDSIM_INPUT_CYCLE;
+-static uint bus_width      = CONFIG_NANDSIM_BUS_WIDTH;
+-static uint do_delays      = CONFIG_NANDSIM_DO_DELAYS;
+-static uint log            = CONFIG_NANDSIM_LOG;
+-static uint dbg            = CONFIG_NANDSIM_DBG;
+-static unsigned long parts[CONFIG_NANDSIM_MAX_PARTS];
+-static unsigned int parts_num;
+-static char *badblocks = NULL;
+-static char *weakblocks = NULL;
+-static char *weakpages = NULL;
+-static unsigned int bitflips = 0;
+-static char *gravepages = NULL;
+-static unsigned int overridesize = 0;
+-static char *cache_file = NULL;
+-static unsigned int bbt;
+-static unsigned int bch;
+-static u_char id_bytes[8] = {
+-	[0] = CONFIG_NANDSIM_FIRST_ID_BYTE,
+-	[1] = CONFIG_NANDSIM_SECOND_ID_BYTE,
+-	[2] = CONFIG_NANDSIM_THIRD_ID_BYTE,
+-	[3] = CONFIG_NANDSIM_FOURTH_ID_BYTE,
+-	[4 ... 7] = 0xFF,
+-};
+-
+-module_param_array(id_bytes, byte, NULL, 0400);
+-module_param_named(first_id_byte, id_bytes[0], byte, 0400);
+-module_param_named(second_id_byte, id_bytes[1], byte, 0400);
+-module_param_named(third_id_byte, id_bytes[2], byte, 0400);
+-module_param_named(fourth_id_byte, id_bytes[3], byte, 0400);
+-module_param(access_delay,   uint, 0400);
+-module_param(programm_delay, uint, 0400);
+-module_param(erase_delay,    uint, 0400);
+-module_param(output_cycle,   uint, 0400);
+-module_param(input_cycle,    uint, 0400);
+-module_param(bus_width,      uint, 0400);
+-module_param(do_delays,      uint, 0400);
+-module_param(log,            uint, 0400);
+-module_param(dbg,            uint, 0400);
+-module_param_array(parts, ulong, &parts_num, 0400);
+-module_param(badblocks,      charp, 0400);
+-module_param(weakblocks,     charp, 0400);
+-module_param(weakpages,      charp, 0400);
+-module_param(bitflips,       uint, 0400);
+-module_param(gravepages,     charp, 0400);
+-module_param(overridesize,   uint, 0400);
+-module_param(cache_file,     charp, 0400);
+-module_param(bbt,	     uint, 0400);
+-module_param(bch,	     uint, 0400);
+-
+-MODULE_PARM_DESC(id_bytes,       "The ID bytes returned by NAND Flash 'read ID' command");
+-MODULE_PARM_DESC(first_id_byte,  "The first byte returned by NAND Flash 'read ID' command (manufacturer ID) (obsolete)");
+-MODULE_PARM_DESC(second_id_byte, "The second byte returned by NAND Flash 'read ID' command (chip ID) (obsolete)");
+-MODULE_PARM_DESC(third_id_byte,  "The third byte returned by NAND Flash 'read ID' command (obsolete)");
+-MODULE_PARM_DESC(fourth_id_byte, "The fourth byte returned by NAND Flash 'read ID' command (obsolete)");
+-MODULE_PARM_DESC(access_delay,   "Initial page access delay (microseconds)");
+-MODULE_PARM_DESC(programm_delay, "Page programm delay (microseconds");
+-MODULE_PARM_DESC(erase_delay,    "Sector erase delay (milliseconds)");
+-MODULE_PARM_DESC(output_cycle,   "Word output (from flash) time (nanoseconds)");
+-MODULE_PARM_DESC(input_cycle,    "Word input (to flash) time (nanoseconds)");
+-MODULE_PARM_DESC(bus_width,      "Chip's bus width (8- or 16-bit)");
+-MODULE_PARM_DESC(do_delays,      "Simulate NAND delays using busy-waits if not zero");
+-MODULE_PARM_DESC(log,            "Perform logging if not zero");
+-MODULE_PARM_DESC(dbg,            "Output debug information if not zero");
+-MODULE_PARM_DESC(parts,          "Partition sizes (in erase blocks) separated by commas");
+-/* Page and erase block positions for the following parameters are independent of any partitions */
+-MODULE_PARM_DESC(badblocks,      "Erase blocks that are initially marked bad, separated by commas");
+-MODULE_PARM_DESC(weakblocks,     "Weak erase blocks [: remaining erase cycles (defaults to 3)]"
+-				 " separated by commas e.g. 113:2 means eb 113"
+-				 " can be erased only twice before failing");
+-MODULE_PARM_DESC(weakpages,      "Weak pages [: maximum writes (defaults to 3)]"
+-				 " separated by commas e.g. 1401:2 means page 1401"
+-				 " can be written only twice before failing");
+-MODULE_PARM_DESC(bitflips,       "Maximum number of random bit flips per page (zero by default)");
+-MODULE_PARM_DESC(gravepages,     "Pages that lose data [: maximum reads (defaults to 3)]"
+-				 " separated by commas e.g. 1401:2 means page 1401"
+-				 " can be read only twice before failing");
+-MODULE_PARM_DESC(overridesize,   "Specifies the NAND Flash size overriding the ID bytes. "
+-				 "The size is specified in erase blocks and as the exponent of a power of two"
+-				 " e.g. 5 means a size of 32 erase blocks");
+-MODULE_PARM_DESC(cache_file,     "File to use to cache nand pages instead of memory");
+-MODULE_PARM_DESC(bbt,		 "0 OOB, 1 BBT with marker in OOB, 2 BBT with marker in data area");
+-MODULE_PARM_DESC(bch,		 "Enable BCH ecc and set how many bits should "
+-				 "be correctable in 512-byte blocks");
+-
+-/* The largest possible page size */
+-#define NS_LARGEST_PAGE_SIZE	4096
+-
+-/* The prefix for simulator output */
+-#define NS_OUTPUT_PREFIX "[nandsim]"
+-
+-/* Simulator's output macros (logging, debugging, warning, error) */
+-#define NS_LOG(args...) \
+-	do { if (log) printk(KERN_DEBUG NS_OUTPUT_PREFIX " log: " args); } while(0)
+-#define NS_DBG(args...) \
+-	do { if (dbg) printk(KERN_DEBUG NS_OUTPUT_PREFIX " debug: " args); } while(0)
+-#define NS_WARN(args...) \
+-	do { printk(KERN_WARNING NS_OUTPUT_PREFIX " warning: " args); } while(0)
+-#define NS_ERR(args...) \
+-	do { printk(KERN_ERR NS_OUTPUT_PREFIX " error: " args); } while(0)
+-#define NS_INFO(args...) \
+-	do { printk(KERN_INFO NS_OUTPUT_PREFIX " " args); } while(0)
+-
+-/* Busy-wait delay macros (microseconds, milliseconds) */
+-#define NS_UDELAY(us) \
+-        do { if (do_delays) udelay(us); } while(0)
+-#define NS_MDELAY(us) \
+-        do { if (do_delays) mdelay(us); } while(0)
+-
+-/* Is the nandsim structure initialized ? */
+-#define NS_IS_INITIALIZED(ns) ((ns)->geom.totsz != 0)
+-
+-/* Good operation completion status */
+-#define NS_STATUS_OK(ns) (NAND_STATUS_READY | (NAND_STATUS_WP * ((ns)->lines.wp == 0)))
+-
+-/* Operation failed completion status */
+-#define NS_STATUS_FAILED(ns) (NAND_STATUS_FAIL | NS_STATUS_OK(ns))
+-
+-/* Calculate the page offset in flash RAM image by (row, column) address */
+-#define NS_RAW_OFFSET(ns) \
+-	(((ns)->regs.row * (ns)->geom.pgszoob) + (ns)->regs.column)
+-
+-/* Calculate the OOB offset in flash RAM image by (row, column) address */
+-#define NS_RAW_OFFSET_OOB(ns) (NS_RAW_OFFSET(ns) + ns->geom.pgsz)
+-
+-/* After a command is input, the simulator goes to one of the following states */
+-#define STATE_CMD_READ0        0x00000001 /* read data from the beginning of page */
+-#define STATE_CMD_READ1        0x00000002 /* read data from the second half of page */
+-#define STATE_CMD_READSTART    0x00000003 /* read data second command (large page devices) */
+-#define STATE_CMD_PAGEPROG     0x00000004 /* start page program */
+-#define STATE_CMD_READOOB      0x00000005 /* read OOB area */
+-#define STATE_CMD_ERASE1       0x00000006 /* sector erase first command */
+-#define STATE_CMD_STATUS       0x00000007 /* read status */
+-#define STATE_CMD_SEQIN        0x00000009 /* sequential data input */
+-#define STATE_CMD_READID       0x0000000A /* read ID */
+-#define STATE_CMD_ERASE2       0x0000000B /* sector erase second command */
+-#define STATE_CMD_RESET        0x0000000C /* reset */
+-#define STATE_CMD_RNDOUT       0x0000000D /* random output command */
+-#define STATE_CMD_RNDOUTSTART  0x0000000E /* random output start command */
+-#define STATE_CMD_MASK         0x0000000F /* command states mask */
+-
+-/* After an address is input, the simulator goes to one of these states */
+-#define STATE_ADDR_PAGE        0x00000010 /* full (row, column) address is accepted */
+-#define STATE_ADDR_SEC         0x00000020 /* sector address was accepted */
+-#define STATE_ADDR_COLUMN      0x00000030 /* column address was accepted */
+-#define STATE_ADDR_ZERO        0x00000040 /* one byte zero address was accepted */
+-#define STATE_ADDR_MASK        0x00000070 /* address states mask */
+-
+-/* During data input/output the simulator is in these states */
+-#define STATE_DATAIN           0x00000100 /* waiting for data input */
+-#define STATE_DATAIN_MASK      0x00000100 /* data input states mask */
+-
+-#define STATE_DATAOUT          0x00001000 /* waiting for page data output */
+-#define STATE_DATAOUT_ID       0x00002000 /* waiting for ID bytes output */
+-#define STATE_DATAOUT_STATUS   0x00003000 /* waiting for status output */
+-#define STATE_DATAOUT_MASK     0x00007000 /* data output states mask */
+-
+-/* Previous operation is done, ready to accept new requests */
+-#define STATE_READY            0x00000000
+-
+-/* This state is used to mark that the next state isn't known yet */
+-#define STATE_UNKNOWN          0x10000000
+-
+-/* Simulator's actions bit masks */
+-#define ACTION_CPY       0x00100000 /* copy page/OOB to the internal buffer */
+-#define ACTION_PRGPAGE   0x00200000 /* program the internal buffer to flash */
+-#define ACTION_SECERASE  0x00300000 /* erase sector */
+-#define ACTION_ZEROOFF   0x00400000 /* don't add any offset to address */
+-#define ACTION_HALFOFF   0x00500000 /* add to address half of page */
+-#define ACTION_OOBOFF    0x00600000 /* add to address OOB offset */
+-#define ACTION_MASK      0x00700000 /* action mask */
+-
+-#define NS_OPER_NUM      13 /* Number of operations supported by the simulator */
+-#define NS_OPER_STATES   6  /* Maximum number of states in operation */
+-
+-#define OPT_ANY          0xFFFFFFFF /* any chip supports this operation */
+-#define OPT_PAGE512      0x00000002 /* 512-byte  page chips */
+-#define OPT_PAGE2048     0x00000008 /* 2048-byte page chips */
+-#define OPT_PAGE512_8BIT 0x00000040 /* 512-byte page chips with 8-bit bus width */
+-#define OPT_PAGE4096     0x00000080 /* 4096-byte page chips */
+-#define OPT_LARGEPAGE    (OPT_PAGE2048 | OPT_PAGE4096) /* 2048 & 4096-byte page chips */
+-#define OPT_SMALLPAGE    (OPT_PAGE512) /* 512-byte page chips */
+-
+-/* Remove action bits from state */
+-#define NS_STATE(x) ((x) & ~ACTION_MASK)
+-
+-/*
+- * Maximum previous states which need to be saved. Currently saving is
+- * only needed for page program operation with preceded read command
+- * (which is only valid for 512-byte pages).
+- */
+-#define NS_MAX_PREVSTATES 1
+-
+-/* Maximum page cache pages needed to read or write a NAND page to the cache_file */
+-#define NS_MAX_HELD_PAGES 16
+-
+-/*
+- * A union to represent flash memory contents and flash buffer.
+- */
+-union ns_mem {
+-	u_char *byte;    /* for byte access */
+-	uint16_t *word;  /* for 16-bit word access */
+-};
+-
+-/*
+- * The structure which describes all the internal simulator data.
+- */
+-struct nandsim {
+-	struct mtd_partition partitions[CONFIG_NANDSIM_MAX_PARTS];
+-	unsigned int nbparts;
+-
+-	uint busw;              /* flash chip bus width (8 or 16) */
+-	u_char ids[8];          /* chip's ID bytes */
+-	uint32_t options;       /* chip's characteristic bits */
+-	uint32_t state;         /* current chip state */
+-	uint32_t nxstate;       /* next expected state */
+-
+-	uint32_t *op;           /* current operation, NULL operations isn't known yet  */
+-	uint32_t pstates[NS_MAX_PREVSTATES]; /* previous states */
+-	uint16_t npstates;      /* number of previous states saved */
+-	uint16_t stateidx;      /* current state index */
+-
+-	/* The simulated NAND flash pages array */
+-	union ns_mem *pages;
+-
+-	/* Slab allocator for nand pages */
+-	struct kmem_cache *nand_pages_slab;
+-
+-	/* Internal buffer of page + OOB size bytes */
+-	union ns_mem buf;
+-
+-	/* NAND flash "geometry" */
+-	struct {
+-		uint64_t totsz;     /* total flash size, bytes */
+-		uint32_t secsz;     /* flash sector (erase block) size, bytes */
+-		uint pgsz;          /* NAND flash page size, bytes */
+-		uint oobsz;         /* page OOB area size, bytes */
+-		uint64_t totszoob;  /* total flash size including OOB, bytes */
+-		uint pgszoob;       /* page size including OOB , bytes*/
+-		uint secszoob;      /* sector size including OOB, bytes */
+-		uint pgnum;         /* total number of pages */
+-		uint pgsec;         /* number of pages per sector */
+-		uint secshift;      /* bits number in sector size */
+-		uint pgshift;       /* bits number in page size */
+-		uint pgaddrbytes;   /* bytes per page address */
+-		uint secaddrbytes;  /* bytes per sector address */
+-		uint idbytes;       /* the number ID bytes that this chip outputs */
+-	} geom;
+-
+-	/* NAND flash internal registers */
+-	struct {
+-		unsigned command; /* the command register */
+-		u_char   status;  /* the status register */
+-		uint     row;     /* the page number */
+-		uint     column;  /* the offset within page */
+-		uint     count;   /* internal counter */
+-		uint     num;     /* number of bytes which must be processed */
+-		uint     off;     /* fixed page offset */
+-	} regs;
+-
+-	/* NAND flash lines state */
+-        struct {
+-                int ce;  /* chip Enable */
+-                int cle; /* command Latch Enable */
+-                int ale; /* address Latch Enable */
+-                int wp;  /* write Protect */
+-        } lines;
+-
+-	/* Fields needed when using a cache file */
+-	struct file *cfile; /* Open file */
+-	unsigned long *pages_written; /* Which pages have been written */
+-	void *file_buf;
+-	struct page *held_pages[NS_MAX_HELD_PAGES];
+-	int held_cnt;
+-};
+-
+-/*
+- * Operations array. To perform any operation the simulator must pass
+- * through the correspondent states chain.
+- */
+-static struct nandsim_operations {
+-	uint32_t reqopts;  /* options which are required to perform the operation */
+-	uint32_t states[NS_OPER_STATES]; /* operation's states */
+-} ops[NS_OPER_NUM] = {
+-	/* Read page + OOB from the beginning */
+-	{OPT_SMALLPAGE, {STATE_CMD_READ0 | ACTION_ZEROOFF, STATE_ADDR_PAGE | ACTION_CPY,
+-			STATE_DATAOUT, STATE_READY}},
+-	/* Read page + OOB from the second half */
+-	{OPT_PAGE512_8BIT, {STATE_CMD_READ1 | ACTION_HALFOFF, STATE_ADDR_PAGE | ACTION_CPY,
+-			STATE_DATAOUT, STATE_READY}},
+-	/* Read OOB */
+-	{OPT_SMALLPAGE, {STATE_CMD_READOOB | ACTION_OOBOFF, STATE_ADDR_PAGE | ACTION_CPY,
+-			STATE_DATAOUT, STATE_READY}},
+-	/* Program page starting from the beginning */
+-	{OPT_ANY, {STATE_CMD_SEQIN, STATE_ADDR_PAGE, STATE_DATAIN,
+-			STATE_CMD_PAGEPROG | ACTION_PRGPAGE, STATE_READY}},
+-	/* Program page starting from the beginning */
+-	{OPT_SMALLPAGE, {STATE_CMD_READ0, STATE_CMD_SEQIN | ACTION_ZEROOFF, STATE_ADDR_PAGE,
+-			      STATE_DATAIN, STATE_CMD_PAGEPROG | ACTION_PRGPAGE, STATE_READY}},
+-	/* Program page starting from the second half */
+-	{OPT_PAGE512, {STATE_CMD_READ1, STATE_CMD_SEQIN | ACTION_HALFOFF, STATE_ADDR_PAGE,
+-			      STATE_DATAIN, STATE_CMD_PAGEPROG | ACTION_PRGPAGE, STATE_READY}},
+-	/* Program OOB */
+-	{OPT_SMALLPAGE, {STATE_CMD_READOOB, STATE_CMD_SEQIN | ACTION_OOBOFF, STATE_ADDR_PAGE,
+-			      STATE_DATAIN, STATE_CMD_PAGEPROG | ACTION_PRGPAGE, STATE_READY}},
+-	/* Erase sector */
+-	{OPT_ANY, {STATE_CMD_ERASE1, STATE_ADDR_SEC, STATE_CMD_ERASE2 | ACTION_SECERASE, STATE_READY}},
+-	/* Read status */
+-	{OPT_ANY, {STATE_CMD_STATUS, STATE_DATAOUT_STATUS, STATE_READY}},
+-	/* Read ID */
+-	{OPT_ANY, {STATE_CMD_READID, STATE_ADDR_ZERO, STATE_DATAOUT_ID, STATE_READY}},
+-	/* Large page devices read page */
+-	{OPT_LARGEPAGE, {STATE_CMD_READ0, STATE_ADDR_PAGE, STATE_CMD_READSTART | ACTION_CPY,
+-			       STATE_DATAOUT, STATE_READY}},
+-	/* Large page devices random page read */
+-	{OPT_LARGEPAGE, {STATE_CMD_RNDOUT, STATE_ADDR_COLUMN, STATE_CMD_RNDOUTSTART | ACTION_CPY,
+-			       STATE_DATAOUT, STATE_READY}},
+-};
+-
+-struct weak_block {
+-	struct list_head list;
+-	unsigned int erase_block_no;
+-	unsigned int max_erases;
+-	unsigned int erases_done;
+-};
+-
+-static LIST_HEAD(weak_blocks);
+-
+-struct weak_page {
+-	struct list_head list;
+-	unsigned int page_no;
+-	unsigned int max_writes;
+-	unsigned int writes_done;
+-};
+-
+-static LIST_HEAD(weak_pages);
+-
+-struct grave_page {
+-	struct list_head list;
+-	unsigned int page_no;
+-	unsigned int max_reads;
+-	unsigned int reads_done;
+-};
+-
+-static LIST_HEAD(grave_pages);
+-
+-static unsigned long *erase_block_wear = NULL;
+-static unsigned int wear_eb_count = 0;
+-static unsigned long total_wear = 0;
+-
+-/* MTD structure for NAND controller */
+-static struct mtd_info *nsmtd;
+-
+-static int nandsim_debugfs_show(struct seq_file *m, void *private)
+-{
+-	unsigned long wmin = -1, wmax = 0, avg;
+-	unsigned long deciles[10], decile_max[10], tot = 0;
+-	unsigned int i;
+-
+-	/* Calc wear stats */
+-	for (i = 0; i < wear_eb_count; ++i) {
+-		unsigned long wear = erase_block_wear[i];
+-		if (wear < wmin)
+-			wmin = wear;
+-		if (wear > wmax)
+-			wmax = wear;
+-		tot += wear;
+-	}
+-
+-	for (i = 0; i < 9; ++i) {
+-		deciles[i] = 0;
+-		decile_max[i] = (wmax * (i + 1) + 5) / 10;
+-	}
+-	deciles[9] = 0;
+-	decile_max[9] = wmax;
+-	for (i = 0; i < wear_eb_count; ++i) {
+-		int d;
+-		unsigned long wear = erase_block_wear[i];
+-		for (d = 0; d < 10; ++d)
+-			if (wear <= decile_max[d]) {
+-				deciles[d] += 1;
+-				break;
+-			}
+-	}
+-	avg = tot / wear_eb_count;
+-
+-	/* Output wear report */
+-	seq_printf(m, "Total numbers of erases:  %lu\n", tot);
+-	seq_printf(m, "Number of erase blocks:   %u\n", wear_eb_count);
+-	seq_printf(m, "Average number of erases: %lu\n", avg);
+-	seq_printf(m, "Maximum number of erases: %lu\n", wmax);
+-	seq_printf(m, "Minimum number of erases: %lu\n", wmin);
+-	for (i = 0; i < 10; ++i) {
+-		unsigned long from = (i ? decile_max[i - 1] + 1 : 0);
+-		if (from > decile_max[i])
+-			continue;
+-		seq_printf(m, "Number of ebs with erase counts from %lu to %lu : %lu\n",
+-			from,
+-			decile_max[i],
+-			deciles[i]);
+-	}
+-
+-	return 0;
+-}
+-
+-static int nandsim_debugfs_open(struct inode *inode, struct file *file)
+-{
+-	return single_open(file, nandsim_debugfs_show, inode->i_private);
+-}
+-
+-static const struct file_operations dfs_fops = {
+-	.open		= nandsim_debugfs_open,
+-	.read		= seq_read,
+-	.llseek		= seq_lseek,
+-	.release	= single_release,
+-};
+-
+-/**
+- * nandsim_debugfs_create - initialize debugfs
+- * @dev: nandsim device description object
+- *
+- * This function creates all debugfs files for UBI device @ubi. Returns zero in
+- * case of success and a negative error code in case of failure.
+- */
+-static int nandsim_debugfs_create(struct nandsim *dev)
+-{
+-	struct dentry *root = nsmtd->dbg.dfs_dir;
+-	struct dentry *dent;
+-
+-	/*
+-	 * Just skip debugfs initialization when the debugfs directory is
+-	 * missing.
+-	 */
+-	if (IS_ERR_OR_NULL(root)) {
+-		if (IS_ENABLED(CONFIG_DEBUG_FS) &&
+-		    !IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER))
+-			NS_WARN("CONFIG_MTD_PARTITIONED_MASTER must be enabled to expose debugfs stuff\n");
+-		return 0;
+-	}
+-
+-	dent = debugfs_create_file("nandsim_wear_report", S_IRUSR,
+-				   root, dev, &dfs_fops);
+-	if (IS_ERR_OR_NULL(dent)) {
+-		NS_ERR("cannot create \"nandsim_wear_report\" debugfs entry\n");
+-		return -1;
+-	}
+-
+-	return 0;
+-}
+-
+-/*
+- * Allocate array of page pointers, create slab allocation for an array
+- * and initialize the array by NULL pointers.
+- *
+- * RETURNS: 0 if success, -ENOMEM if memory alloc fails.
+- */
+-static int __init alloc_device(struct nandsim *ns)
+-{
+-	struct file *cfile;
+-	int i, err;
+-
+-	if (cache_file) {
+-		cfile = filp_open(cache_file, O_CREAT | O_RDWR | O_LARGEFILE, 0600);
+-		if (IS_ERR(cfile))
+-			return PTR_ERR(cfile);
+-		if (!(cfile->f_mode & FMODE_CAN_READ)) {
+-			NS_ERR("alloc_device: cache file not readable\n");
+-			err = -EINVAL;
+-			goto err_close;
+-		}
+-		if (!(cfile->f_mode & FMODE_CAN_WRITE)) {
+-			NS_ERR("alloc_device: cache file not writeable\n");
+-			err = -EINVAL;
+-			goto err_close;
+-		}
+-		ns->pages_written = vzalloc(BITS_TO_LONGS(ns->geom.pgnum) *
+-					    sizeof(unsigned long));
+-		if (!ns->pages_written) {
+-			NS_ERR("alloc_device: unable to allocate pages written array\n");
+-			err = -ENOMEM;
+-			goto err_close;
+-		}
+-		ns->file_buf = kmalloc(ns->geom.pgszoob, GFP_KERNEL);
+-		if (!ns->file_buf) {
+-			NS_ERR("alloc_device: unable to allocate file buf\n");
+-			err = -ENOMEM;
+-			goto err_free;
+-		}
+-		ns->cfile = cfile;
+-		return 0;
+-	}
+-
+-	ns->pages = vmalloc(ns->geom.pgnum * sizeof(union ns_mem));
+-	if (!ns->pages) {
+-		NS_ERR("alloc_device: unable to allocate page array\n");
+-		return -ENOMEM;
+-	}
+-	for (i = 0; i < ns->geom.pgnum; i++) {
+-		ns->pages[i].byte = NULL;
+-	}
+-	ns->nand_pages_slab = kmem_cache_create("nandsim",
+-						ns->geom.pgszoob, 0, 0, NULL);
+-	if (!ns->nand_pages_slab) {
+-		NS_ERR("cache_create: unable to create kmem_cache\n");
+-		return -ENOMEM;
+-	}
+-
+-	return 0;
+-
+-err_free:
+-	vfree(ns->pages_written);
+-err_close:
+-	filp_close(cfile, NULL);
+-	return err;
+-}
+-
+-/*
+- * Free any allocated pages, and free the array of page pointers.
+- */
+-static void free_device(struct nandsim *ns)
+-{
+-	int i;
+-
+-	if (ns->cfile) {
+-		kfree(ns->file_buf);
+-		vfree(ns->pages_written);
+-		filp_close(ns->cfile, NULL);
+-		return;
+-	}
+-
+-	if (ns->pages) {
+-		for (i = 0; i < ns->geom.pgnum; i++) {
+-			if (ns->pages[i].byte)
+-				kmem_cache_free(ns->nand_pages_slab,
+-						ns->pages[i].byte);
+-		}
+-		kmem_cache_destroy(ns->nand_pages_slab);
+-		vfree(ns->pages);
+-	}
+-}
+-
+-static char __init *get_partition_name(int i)
+-{
+-	return kasprintf(GFP_KERNEL, "NAND simulator partition %d", i);
+-}
+-
+-/*
+- * Initialize the nandsim structure.
+- *
+- * RETURNS: 0 if success, -ERRNO if failure.
+- */
+-static int __init init_nandsim(struct mtd_info *mtd)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct nandsim   *ns   = nand_get_controller_data(chip);
+-	int i, ret = 0;
+-	uint64_t remains;
+-	uint64_t next_offset;
+-
+-	if (NS_IS_INITIALIZED(ns)) {
+-		NS_ERR("init_nandsim: nandsim is already initialized\n");
+-		return -EIO;
+-	}
+-
+-	/* Force mtd to not do delays */
+-	chip->chip_delay = 0;
+-
+-	/* Initialize the NAND flash parameters */
+-	ns->busw = chip->options & NAND_BUSWIDTH_16 ? 16 : 8;
+-	ns->geom.totsz    = mtd->size;
+-	ns->geom.pgsz     = mtd->writesize;
+-	ns->geom.oobsz    = mtd->oobsize;
+-	ns->geom.secsz    = mtd->erasesize;
+-	ns->geom.pgszoob  = ns->geom.pgsz + ns->geom.oobsz;
+-	ns->geom.pgnum    = div_u64(ns->geom.totsz, ns->geom.pgsz);
+-	ns->geom.totszoob = ns->geom.totsz + (uint64_t)ns->geom.pgnum * ns->geom.oobsz;
+-	ns->geom.secshift = ffs(ns->geom.secsz) - 1;
+-	ns->geom.pgshift  = chip->page_shift;
+-	ns->geom.pgsec    = ns->geom.secsz / ns->geom.pgsz;
+-	ns->geom.secszoob = ns->geom.secsz + ns->geom.oobsz * ns->geom.pgsec;
+-	ns->options = 0;
+-
+-	if (ns->geom.pgsz == 512) {
+-		ns->options |= OPT_PAGE512;
+-		if (ns->busw == 8)
+-			ns->options |= OPT_PAGE512_8BIT;
+-	} else if (ns->geom.pgsz == 2048) {
+-		ns->options |= OPT_PAGE2048;
+-	} else if (ns->geom.pgsz == 4096) {
+-		ns->options |= OPT_PAGE4096;
+-	} else {
+-		NS_ERR("init_nandsim: unknown page size %u\n", ns->geom.pgsz);
+-		return -EIO;
+-	}
+-
+-	if (ns->options & OPT_SMALLPAGE) {
+-		if (ns->geom.totsz <= (32 << 20)) {
+-			ns->geom.pgaddrbytes  = 3;
+-			ns->geom.secaddrbytes = 2;
+-		} else {
+-			ns->geom.pgaddrbytes  = 4;
+-			ns->geom.secaddrbytes = 3;
+-		}
+-	} else {
+-		if (ns->geom.totsz <= (128 << 20)) {
+-			ns->geom.pgaddrbytes  = 4;
+-			ns->geom.secaddrbytes = 2;
+-		} else {
+-			ns->geom.pgaddrbytes  = 5;
+-			ns->geom.secaddrbytes = 3;
+-		}
+-	}
+-
+-	/* Fill the partition_info structure */
+-	if (parts_num > ARRAY_SIZE(ns->partitions)) {
+-		NS_ERR("too many partitions.\n");
+-		return -EINVAL;
+-	}
+-	remains = ns->geom.totsz;
+-	next_offset = 0;
+-	for (i = 0; i < parts_num; ++i) {
+-		uint64_t part_sz = (uint64_t)parts[i] * ns->geom.secsz;
+-
+-		if (!part_sz || part_sz > remains) {
+-			NS_ERR("bad partition size.\n");
+-			return -EINVAL;
+-		}
+-		ns->partitions[i].name   = get_partition_name(i);
+-		if (!ns->partitions[i].name) {
+-			NS_ERR("unable to allocate memory.\n");
+-			return -ENOMEM;
+-		}
+-		ns->partitions[i].offset = next_offset;
+-		ns->partitions[i].size   = part_sz;
+-		next_offset += ns->partitions[i].size;
+-		remains -= ns->partitions[i].size;
+-	}
+-	ns->nbparts = parts_num;
+-	if (remains) {
+-		if (parts_num + 1 > ARRAY_SIZE(ns->partitions)) {
+-			NS_ERR("too many partitions.\n");
+-			return -EINVAL;
+-		}
+-		ns->partitions[i].name   = get_partition_name(i);
+-		if (!ns->partitions[i].name) {
+-			NS_ERR("unable to allocate memory.\n");
+-			return -ENOMEM;
+-		}
+-		ns->partitions[i].offset = next_offset;
+-		ns->partitions[i].size   = remains;
+-		ns->nbparts += 1;
+-	}
+-
+-	if (ns->busw == 16)
+-		NS_WARN("16-bit flashes support wasn't tested\n");
+-
+-	printk("flash size: %llu MiB\n",
+-			(unsigned long long)ns->geom.totsz >> 20);
+-	printk("page size: %u bytes\n",         ns->geom.pgsz);
+-	printk("OOB area size: %u bytes\n",     ns->geom.oobsz);
+-	printk("sector size: %u KiB\n",         ns->geom.secsz >> 10);
+-	printk("pages number: %u\n",            ns->geom.pgnum);
+-	printk("pages per sector: %u\n",        ns->geom.pgsec);
+-	printk("bus width: %u\n",               ns->busw);
+-	printk("bits in sector size: %u\n",     ns->geom.secshift);
+-	printk("bits in page size: %u\n",       ns->geom.pgshift);
+-	printk("bits in OOB size: %u\n",	ffs(ns->geom.oobsz) - 1);
+-	printk("flash size with OOB: %llu KiB\n",
+-			(unsigned long long)ns->geom.totszoob >> 10);
+-	printk("page address bytes: %u\n",      ns->geom.pgaddrbytes);
+-	printk("sector address bytes: %u\n",    ns->geom.secaddrbytes);
+-	printk("options: %#x\n",                ns->options);
+-
+-	if ((ret = alloc_device(ns)) != 0)
+-		return ret;
+-
+-	/* Allocate / initialize the internal buffer */
+-	ns->buf.byte = kmalloc(ns->geom.pgszoob, GFP_KERNEL);
+-	if (!ns->buf.byte) {
+-		NS_ERR("init_nandsim: unable to allocate %u bytes for the internal buffer\n",
+-			ns->geom.pgszoob);
+-		return -ENOMEM;
+-	}
+-	memset(ns->buf.byte, 0xFF, ns->geom.pgszoob);
+-
+-	return 0;
+-}
+-
+-/*
+- * Free the nandsim structure.
+- */
+-static void free_nandsim(struct nandsim *ns)
+-{
+-	kfree(ns->buf.byte);
+-	free_device(ns);
+-
+-	return;
+-}
+-
+-static int parse_badblocks(struct nandsim *ns, struct mtd_info *mtd)
+-{
+-	char *w;
+-	int zero_ok;
+-	unsigned int erase_block_no;
+-	loff_t offset;
+-
+-	if (!badblocks)
+-		return 0;
+-	w = badblocks;
+-	do {
+-		zero_ok = (*w == '0' ? 1 : 0);
+-		erase_block_no = simple_strtoul(w, &w, 0);
+-		if (!zero_ok && !erase_block_no) {
+-			NS_ERR("invalid badblocks.\n");
+-			return -EINVAL;
+-		}
+-		offset = (loff_t)erase_block_no * ns->geom.secsz;
+-		if (mtd_block_markbad(mtd, offset)) {
+-			NS_ERR("invalid badblocks.\n");
+-			return -EINVAL;
+-		}
+-		if (*w == ',')
+-			w += 1;
+-	} while (*w);
+-	return 0;
+-}
+-
+-static int parse_weakblocks(void)
+-{
+-	char *w;
+-	int zero_ok;
+-	unsigned int erase_block_no;
+-	unsigned int max_erases;
+-	struct weak_block *wb;
+-
+-	if (!weakblocks)
+-		return 0;
+-	w = weakblocks;
+-	do {
+-		zero_ok = (*w == '0' ? 1 : 0);
+-		erase_block_no = simple_strtoul(w, &w, 0);
+-		if (!zero_ok && !erase_block_no) {
+-			NS_ERR("invalid weakblocks.\n");
+-			return -EINVAL;
+-		}
+-		max_erases = 3;
+-		if (*w == ':') {
+-			w += 1;
+-			max_erases = simple_strtoul(w, &w, 0);
+-		}
+-		if (*w == ',')
+-			w += 1;
+-		wb = kzalloc(sizeof(*wb), GFP_KERNEL);
+-		if (!wb) {
+-			NS_ERR("unable to allocate memory.\n");
+-			return -ENOMEM;
+-		}
+-		wb->erase_block_no = erase_block_no;
+-		wb->max_erases = max_erases;
+-		list_add(&wb->list, &weak_blocks);
+-	} while (*w);
+-	return 0;
+-}
+-
+-static int erase_error(unsigned int erase_block_no)
+-{
+-	struct weak_block *wb;
+-
+-	list_for_each_entry(wb, &weak_blocks, list)
+-		if (wb->erase_block_no == erase_block_no) {
+-			if (wb->erases_done >= wb->max_erases)
+-				return 1;
+-			wb->erases_done += 1;
+-			return 0;
+-		}
+-	return 0;
+-}
+-
+-static int parse_weakpages(void)
+-{
+-	char *w;
+-	int zero_ok;
+-	unsigned int page_no;
+-	unsigned int max_writes;
+-	struct weak_page *wp;
+-
+-	if (!weakpages)
+-		return 0;
+-	w = weakpages;
+-	do {
+-		zero_ok = (*w == '0' ? 1 : 0);
+-		page_no = simple_strtoul(w, &w, 0);
+-		if (!zero_ok && !page_no) {
+-			NS_ERR("invalid weakpages.\n");
+-			return -EINVAL;
+-		}
+-		max_writes = 3;
+-		if (*w == ':') {
+-			w += 1;
+-			max_writes = simple_strtoul(w, &w, 0);
+-		}
+-		if (*w == ',')
+-			w += 1;
+-		wp = kzalloc(sizeof(*wp), GFP_KERNEL);
+-		if (!wp) {
+-			NS_ERR("unable to allocate memory.\n");
+-			return -ENOMEM;
+-		}
+-		wp->page_no = page_no;
+-		wp->max_writes = max_writes;
+-		list_add(&wp->list, &weak_pages);
+-	} while (*w);
+-	return 0;
+-}
+-
+-static int write_error(unsigned int page_no)
+-{
+-	struct weak_page *wp;
+-
+-	list_for_each_entry(wp, &weak_pages, list)
+-		if (wp->page_no == page_no) {
+-			if (wp->writes_done >= wp->max_writes)
+-				return 1;
+-			wp->writes_done += 1;
+-			return 0;
+-		}
+-	return 0;
+-}
+-
+-static int parse_gravepages(void)
+-{
+-	char *g;
+-	int zero_ok;
+-	unsigned int page_no;
+-	unsigned int max_reads;
+-	struct grave_page *gp;
+-
+-	if (!gravepages)
+-		return 0;
+-	g = gravepages;
+-	do {
+-		zero_ok = (*g == '0' ? 1 : 0);
+-		page_no = simple_strtoul(g, &g, 0);
+-		if (!zero_ok && !page_no) {
+-			NS_ERR("invalid gravepagess.\n");
+-			return -EINVAL;
+-		}
+-		max_reads = 3;
+-		if (*g == ':') {
+-			g += 1;
+-			max_reads = simple_strtoul(g, &g, 0);
+-		}
+-		if (*g == ',')
+-			g += 1;
+-		gp = kzalloc(sizeof(*gp), GFP_KERNEL);
+-		if (!gp) {
+-			NS_ERR("unable to allocate memory.\n");
+-			return -ENOMEM;
+-		}
+-		gp->page_no = page_no;
+-		gp->max_reads = max_reads;
+-		list_add(&gp->list, &grave_pages);
+-	} while (*g);
+-	return 0;
+-}
+-
+-static int read_error(unsigned int page_no)
+-{
+-	struct grave_page *gp;
+-
+-	list_for_each_entry(gp, &grave_pages, list)
+-		if (gp->page_no == page_no) {
+-			if (gp->reads_done >= gp->max_reads)
+-				return 1;
+-			gp->reads_done += 1;
+-			return 0;
+-		}
+-	return 0;
+-}
+-
+-static void free_lists(void)
+-{
+-	struct list_head *pos, *n;
+-	list_for_each_safe(pos, n, &weak_blocks) {
+-		list_del(pos);
+-		kfree(list_entry(pos, struct weak_block, list));
+-	}
+-	list_for_each_safe(pos, n, &weak_pages) {
+-		list_del(pos);
+-		kfree(list_entry(pos, struct weak_page, list));
+-	}
+-	list_for_each_safe(pos, n, &grave_pages) {
+-		list_del(pos);
+-		kfree(list_entry(pos, struct grave_page, list));
+-	}
+-	kfree(erase_block_wear);
+-}
+-
+-static int setup_wear_reporting(struct mtd_info *mtd)
+-{
+-	size_t mem;
+-
+-	wear_eb_count = div_u64(mtd->size, mtd->erasesize);
+-	mem = wear_eb_count * sizeof(unsigned long);
+-	if (mem / sizeof(unsigned long) != wear_eb_count) {
+-		NS_ERR("Too many erase blocks for wear reporting\n");
+-		return -ENOMEM;
+-	}
+-	erase_block_wear = kzalloc(mem, GFP_KERNEL);
+-	if (!erase_block_wear) {
+-		NS_ERR("Too many erase blocks for wear reporting\n");
+-		return -ENOMEM;
+-	}
+-	return 0;
+-}
+-
+-static void update_wear(unsigned int erase_block_no)
+-{
+-	if (!erase_block_wear)
+-		return;
+-	total_wear += 1;
+-	/*
+-	 * TODO: Notify this through a debugfs entry,
+-	 * instead of showing an error message.
+-	 */
+-	if (total_wear == 0)
+-		NS_ERR("Erase counter total overflow\n");
+-	erase_block_wear[erase_block_no] += 1;
+-	if (erase_block_wear[erase_block_no] == 0)
+-		NS_ERR("Erase counter overflow for erase block %u\n", erase_block_no);
+-}
+-
+-/*
+- * Returns the string representation of 'state' state.
+- */
+-static char *get_state_name(uint32_t state)
+-{
+-	switch (NS_STATE(state)) {
+-		case STATE_CMD_READ0:
+-			return "STATE_CMD_READ0";
+-		case STATE_CMD_READ1:
+-			return "STATE_CMD_READ1";
+-		case STATE_CMD_PAGEPROG:
+-			return "STATE_CMD_PAGEPROG";
+-		case STATE_CMD_READOOB:
+-			return "STATE_CMD_READOOB";
+-		case STATE_CMD_READSTART:
+-			return "STATE_CMD_READSTART";
+-		case STATE_CMD_ERASE1:
+-			return "STATE_CMD_ERASE1";
+-		case STATE_CMD_STATUS:
+-			return "STATE_CMD_STATUS";
+-		case STATE_CMD_SEQIN:
+-			return "STATE_CMD_SEQIN";
+-		case STATE_CMD_READID:
+-			return "STATE_CMD_READID";
+-		case STATE_CMD_ERASE2:
+-			return "STATE_CMD_ERASE2";
+-		case STATE_CMD_RESET:
+-			return "STATE_CMD_RESET";
+-		case STATE_CMD_RNDOUT:
+-			return "STATE_CMD_RNDOUT";
+-		case STATE_CMD_RNDOUTSTART:
+-			return "STATE_CMD_RNDOUTSTART";
+-		case STATE_ADDR_PAGE:
+-			return "STATE_ADDR_PAGE";
+-		case STATE_ADDR_SEC:
+-			return "STATE_ADDR_SEC";
+-		case STATE_ADDR_ZERO:
+-			return "STATE_ADDR_ZERO";
+-		case STATE_ADDR_COLUMN:
+-			return "STATE_ADDR_COLUMN";
+-		case STATE_DATAIN:
+-			return "STATE_DATAIN";
+-		case STATE_DATAOUT:
+-			return "STATE_DATAOUT";
+-		case STATE_DATAOUT_ID:
+-			return "STATE_DATAOUT_ID";
+-		case STATE_DATAOUT_STATUS:
+-			return "STATE_DATAOUT_STATUS";
+-		case STATE_READY:
+-			return "STATE_READY";
+-		case STATE_UNKNOWN:
+-			return "STATE_UNKNOWN";
+-	}
+-
+-	NS_ERR("get_state_name: unknown state, BUG\n");
+-	return NULL;
+-}
+-
+-/*
+- * Check if command is valid.
+- *
+- * RETURNS: 1 if wrong command, 0 if right.
+- */
+-static int check_command(int cmd)
+-{
+-	switch (cmd) {
+-
+-	case NAND_CMD_READ0:
+-	case NAND_CMD_READ1:
+-	case NAND_CMD_READSTART:
+-	case NAND_CMD_PAGEPROG:
+-	case NAND_CMD_READOOB:
+-	case NAND_CMD_ERASE1:
+-	case NAND_CMD_STATUS:
+-	case NAND_CMD_SEQIN:
+-	case NAND_CMD_READID:
+-	case NAND_CMD_ERASE2:
+-	case NAND_CMD_RESET:
+-	case NAND_CMD_RNDOUT:
+-	case NAND_CMD_RNDOUTSTART:
+-		return 0;
+-
+-	default:
+-		return 1;
+-	}
+-}
+-
+-/*
+- * Returns state after command is accepted by command number.
+- */
+-static uint32_t get_state_by_command(unsigned command)
+-{
+-	switch (command) {
+-		case NAND_CMD_READ0:
+-			return STATE_CMD_READ0;
+-		case NAND_CMD_READ1:
+-			return STATE_CMD_READ1;
+-		case NAND_CMD_PAGEPROG:
+-			return STATE_CMD_PAGEPROG;
+-		case NAND_CMD_READSTART:
+-			return STATE_CMD_READSTART;
+-		case NAND_CMD_READOOB:
+-			return STATE_CMD_READOOB;
+-		case NAND_CMD_ERASE1:
+-			return STATE_CMD_ERASE1;
+-		case NAND_CMD_STATUS:
+-			return STATE_CMD_STATUS;
+-		case NAND_CMD_SEQIN:
+-			return STATE_CMD_SEQIN;
+-		case NAND_CMD_READID:
+-			return STATE_CMD_READID;
+-		case NAND_CMD_ERASE2:
+-			return STATE_CMD_ERASE2;
+-		case NAND_CMD_RESET:
+-			return STATE_CMD_RESET;
+-		case NAND_CMD_RNDOUT:
+-			return STATE_CMD_RNDOUT;
+-		case NAND_CMD_RNDOUTSTART:
+-			return STATE_CMD_RNDOUTSTART;
+-	}
+-
+-	NS_ERR("get_state_by_command: unknown command, BUG\n");
+-	return 0;
+-}
+-
+-/*
+- * Move an address byte to the correspondent internal register.
+- */
+-static inline void accept_addr_byte(struct nandsim *ns, u_char bt)
+-{
+-	uint byte = (uint)bt;
+-
+-	if (ns->regs.count < (ns->geom.pgaddrbytes - ns->geom.secaddrbytes))
+-		ns->regs.column |= (byte << 8 * ns->regs.count);
+-	else {
+-		ns->regs.row |= (byte << 8 * (ns->regs.count -
+-						ns->geom.pgaddrbytes +
+-						ns->geom.secaddrbytes));
+-	}
+-
+-	return;
+-}
+-
+-/*
+- * Switch to STATE_READY state.
+- */
+-static inline void switch_to_ready_state(struct nandsim *ns, u_char status)
+-{
+-	NS_DBG("switch_to_ready_state: switch to %s state\n", get_state_name(STATE_READY));
+-
+-	ns->state       = STATE_READY;
+-	ns->nxstate     = STATE_UNKNOWN;
+-	ns->op          = NULL;
+-	ns->npstates    = 0;
+-	ns->stateidx    = 0;
+-	ns->regs.num    = 0;
+-	ns->regs.count  = 0;
+-	ns->regs.off    = 0;
+-	ns->regs.row    = 0;
+-	ns->regs.column = 0;
+-	ns->regs.status = status;
+-}
+-
+-/*
+- * If the operation isn't known yet, try to find it in the global array
+- * of supported operations.
+- *
+- * Operation can be unknown because of the following.
+- *   1. New command was accepted and this is the first call to find the
+- *      correspondent states chain. In this case ns->npstates = 0;
+- *   2. There are several operations which begin with the same command(s)
+- *      (for example program from the second half and read from the
+- *      second half operations both begin with the READ1 command). In this
+- *      case the ns->pstates[] array contains previous states.
+- *
+- * Thus, the function tries to find operation containing the following
+- * states (if the 'flag' parameter is 0):
+- *    ns->pstates[0], ... ns->pstates[ns->npstates], ns->state
+- *
+- * If (one and only one) matching operation is found, it is accepted (
+- * ns->ops, ns->state, ns->nxstate are initialized, ns->npstate is
+- * zeroed).
+- *
+- * If there are several matches, the current state is pushed to the
+- * ns->pstates.
+- *
+- * The operation can be unknown only while commands are input to the chip.
+- * As soon as address command is accepted, the operation must be known.
+- * In such situation the function is called with 'flag' != 0, and the
+- * operation is searched using the following pattern:
+- *     ns->pstates[0], ... ns->pstates[ns->npstates], <address input>
+- *
+- * It is supposed that this pattern must either match one operation or
+- * none. There can't be ambiguity in that case.
+- *
+- * If no matches found, the function does the following:
+- *   1. if there are saved states present, try to ignore them and search
+- *      again only using the last command. If nothing was found, switch
+- *      to the STATE_READY state.
+- *   2. if there are no saved states, switch to the STATE_READY state.
+- *
+- * RETURNS: -2 - no matched operations found.
+- *          -1 - several matches.
+- *           0 - operation is found.
+- */
+-static int find_operation(struct nandsim *ns, uint32_t flag)
+-{
+-	int opsfound = 0;
+-	int i, j, idx = 0;
+-
+-	for (i = 0; i < NS_OPER_NUM; i++) {
+-
+-		int found = 1;
+-
+-		if (!(ns->options & ops[i].reqopts))
+-			/* Ignore operations we can't perform */
+-			continue;
+-
+-		if (flag) {
+-			if (!(ops[i].states[ns->npstates] & STATE_ADDR_MASK))
+-				continue;
+-		} else {
+-			if (NS_STATE(ns->state) != NS_STATE(ops[i].states[ns->npstates]))
+-				continue;
+-		}
+-
+-		for (j = 0; j < ns->npstates; j++)
+-			if (NS_STATE(ops[i].states[j]) != NS_STATE(ns->pstates[j])
+-				&& (ns->options & ops[idx].reqopts)) {
+-				found = 0;
+-				break;
+-			}
+-
+-		if (found) {
+-			idx = i;
+-			opsfound += 1;
+-		}
+-	}
+-
+-	if (opsfound == 1) {
+-		/* Exact match */
+-		ns->op = &ops[idx].states[0];
+-		if (flag) {
+-			/*
+-			 * In this case the find_operation function was
+-			 * called when address has just began input. But it isn't
+-			 * yet fully input and the current state must
+-			 * not be one of STATE_ADDR_*, but the STATE_ADDR_*
+-			 * state must be the next state (ns->nxstate).
+-			 */
+-			ns->stateidx = ns->npstates - 1;
+-		} else {
+-			ns->stateidx = ns->npstates;
+-		}
+-		ns->npstates = 0;
+-		ns->state = ns->op[ns->stateidx];
+-		ns->nxstate = ns->op[ns->stateidx + 1];
+-		NS_DBG("find_operation: operation found, index: %d, state: %s, nxstate %s\n",
+-				idx, get_state_name(ns->state), get_state_name(ns->nxstate));
+-		return 0;
+-	}
+-
+-	if (opsfound == 0) {
+-		/* Nothing was found. Try to ignore previous commands (if any) and search again */
+-		if (ns->npstates != 0) {
+-			NS_DBG("find_operation: no operation found, try again with state %s\n",
+-					get_state_name(ns->state));
+-			ns->npstates = 0;
+-			return find_operation(ns, 0);
+-
+-		}
+-		NS_DBG("find_operation: no operations found\n");
+-		switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
+-		return -2;
+-	}
+-
+-	if (flag) {
+-		/* This shouldn't happen */
+-		NS_DBG("find_operation: BUG, operation must be known if address is input\n");
+-		return -2;
+-	}
+-
+-	NS_DBG("find_operation: there is still ambiguity\n");
+-
+-	ns->pstates[ns->npstates++] = ns->state;
+-
+-	return -1;
+-}
+-
+-static void put_pages(struct nandsim *ns)
+-{
+-	int i;
+-
+-	for (i = 0; i < ns->held_cnt; i++)
+-		put_page(ns->held_pages[i]);
+-}
+-
+-/* Get page cache pages in advance to provide NOFS memory allocation */
+-static int get_pages(struct nandsim *ns, struct file *file, size_t count, loff_t pos)
+-{
+-	pgoff_t index, start_index, end_index;
+-	struct page *page;
+-	struct address_space *mapping = file->f_mapping;
+-
+-	start_index = pos >> PAGE_SHIFT;
+-	end_index = (pos + count - 1) >> PAGE_SHIFT;
+-	if (end_index - start_index + 1 > NS_MAX_HELD_PAGES)
+-		return -EINVAL;
+-	ns->held_cnt = 0;
+-	for (index = start_index; index <= end_index; index++) {
+-		page = find_get_page(mapping, index);
+-		if (page == NULL) {
+-			page = find_or_create_page(mapping, index, GFP_NOFS);
+-			if (page == NULL) {
+-				write_inode_now(mapping->host, 1);
+-				page = find_or_create_page(mapping, index, GFP_NOFS);
+-			}
+-			if (page == NULL) {
+-				put_pages(ns);
+-				return -ENOMEM;
+-			}
+-			unlock_page(page);
+-		}
+-		ns->held_pages[ns->held_cnt++] = page;
+-	}
+-	return 0;
+-}
+-
+-static ssize_t read_file(struct nandsim *ns, struct file *file, void *buf, size_t count, loff_t pos)
+-{
+-	ssize_t tx;
+-	int err;
+-	unsigned int noreclaim_flag;
+-
+-	err = get_pages(ns, file, count, pos);
+-	if (err)
+-		return err;
+-	noreclaim_flag = memalloc_noreclaim_save();
+-	tx = kernel_read(file, buf, count, &pos);
+-	memalloc_noreclaim_restore(noreclaim_flag);
+-	put_pages(ns);
+-	return tx;
+-}
+-
+-static ssize_t write_file(struct nandsim *ns, struct file *file, void *buf, size_t count, loff_t pos)
+-{
+-	ssize_t tx;
+-	int err;
+-	unsigned int noreclaim_flag;
+-
+-	err = get_pages(ns, file, count, pos);
+-	if (err)
+-		return err;
+-	noreclaim_flag = memalloc_noreclaim_save();
+-	tx = kernel_write(file, buf, count, &pos);
+-	memalloc_noreclaim_restore(noreclaim_flag);
+-	put_pages(ns);
+-	return tx;
+-}
+-
+-/*
+- * Returns a pointer to the current page.
+- */
+-static inline union ns_mem *NS_GET_PAGE(struct nandsim *ns)
+-{
+-	return &(ns->pages[ns->regs.row]);
+-}
+-
+-/*
+- * Retuns a pointer to the current byte, within the current page.
+- */
+-static inline u_char *NS_PAGE_BYTE_OFF(struct nandsim *ns)
+-{
+-	return NS_GET_PAGE(ns)->byte + ns->regs.column + ns->regs.off;
+-}
+-
+-static int do_read_error(struct nandsim *ns, int num)
+-{
+-	unsigned int page_no = ns->regs.row;
+-
+-	if (read_error(page_no)) {
+-		prandom_bytes(ns->buf.byte, num);
+-		NS_WARN("simulating read error in page %u\n", page_no);
+-		return 1;
+-	}
+-	return 0;
+-}
+-
+-static void do_bit_flips(struct nandsim *ns, int num)
+-{
+-	if (bitflips && prandom_u32() < (1 << 22)) {
+-		int flips = 1;
+-		if (bitflips > 1)
+-			flips = (prandom_u32() % (int) bitflips) + 1;
+-		while (flips--) {
+-			int pos = prandom_u32() % (num * 8);
+-			ns->buf.byte[pos / 8] ^= (1 << (pos % 8));
+-			NS_WARN("read_page: flipping bit %d in page %d "
+-				"reading from %d ecc: corrected=%u failed=%u\n",
+-				pos, ns->regs.row, ns->regs.column + ns->regs.off,
+-				nsmtd->ecc_stats.corrected, nsmtd->ecc_stats.failed);
+-		}
+-	}
+-}
+-
+-/*
+- * Fill the NAND buffer with data read from the specified page.
+- */
+-static void read_page(struct nandsim *ns, int num)
+-{
+-	union ns_mem *mypage;
+-
+-	if (ns->cfile) {
+-		if (!test_bit(ns->regs.row, ns->pages_written)) {
+-			NS_DBG("read_page: page %d not written\n", ns->regs.row);
+-			memset(ns->buf.byte, 0xFF, num);
+-		} else {
+-			loff_t pos;
+-			ssize_t tx;
+-
+-			NS_DBG("read_page: page %d written, reading from %d\n",
+-				ns->regs.row, ns->regs.column + ns->regs.off);
+-			if (do_read_error(ns, num))
+-				return;
+-			pos = (loff_t)NS_RAW_OFFSET(ns) + ns->regs.off;
+-			tx = read_file(ns, ns->cfile, ns->buf.byte, num, pos);
+-			if (tx != num) {
+-				NS_ERR("read_page: read error for page %d ret %ld\n", ns->regs.row, (long)tx);
+-				return;
+-			}
+-			do_bit_flips(ns, num);
+-		}
+-		return;
+-	}
+-
+-	mypage = NS_GET_PAGE(ns);
+-	if (mypage->byte == NULL) {
+-		NS_DBG("read_page: page %d not allocated\n", ns->regs.row);
+-		memset(ns->buf.byte, 0xFF, num);
+-	} else {
+-		NS_DBG("read_page: page %d allocated, reading from %d\n",
+-			ns->regs.row, ns->regs.column + ns->regs.off);
+-		if (do_read_error(ns, num))
+-			return;
+-		memcpy(ns->buf.byte, NS_PAGE_BYTE_OFF(ns), num);
+-		do_bit_flips(ns, num);
+-	}
+-}
+-
+-/*
+- * Erase all pages in the specified sector.
+- */
+-static void erase_sector(struct nandsim *ns)
+-{
+-	union ns_mem *mypage;
+-	int i;
+-
+-	if (ns->cfile) {
+-		for (i = 0; i < ns->geom.pgsec; i++)
+-			if (__test_and_clear_bit(ns->regs.row + i,
+-						 ns->pages_written)) {
+-				NS_DBG("erase_sector: freeing page %d\n", ns->regs.row + i);
+-			}
+-		return;
+-	}
+-
+-	mypage = NS_GET_PAGE(ns);
+-	for (i = 0; i < ns->geom.pgsec; i++) {
+-		if (mypage->byte != NULL) {
+-			NS_DBG("erase_sector: freeing page %d\n", ns->regs.row+i);
+-			kmem_cache_free(ns->nand_pages_slab, mypage->byte);
+-			mypage->byte = NULL;
+-		}
+-		mypage++;
+-	}
+-}
+-
+-/*
+- * Program the specified page with the contents from the NAND buffer.
+- */
+-static int prog_page(struct nandsim *ns, int num)
+-{
+-	int i;
+-	union ns_mem *mypage;
+-	u_char *pg_off;
+-
+-	if (ns->cfile) {
+-		loff_t off;
+-		ssize_t tx;
+-		int all;
+-
+-		NS_DBG("prog_page: writing page %d\n", ns->regs.row);
+-		pg_off = ns->file_buf + ns->regs.column + ns->regs.off;
+-		off = (loff_t)NS_RAW_OFFSET(ns) + ns->regs.off;
+-		if (!test_bit(ns->regs.row, ns->pages_written)) {
+-			all = 1;
+-			memset(ns->file_buf, 0xff, ns->geom.pgszoob);
+-		} else {
+-			all = 0;
+-			tx = read_file(ns, ns->cfile, pg_off, num, off);
+-			if (tx != num) {
+-				NS_ERR("prog_page: read error for page %d ret %ld\n", ns->regs.row, (long)tx);
+-				return -1;
+-			}
+-		}
+-		for (i = 0; i < num; i++)
+-			pg_off[i] &= ns->buf.byte[i];
+-		if (all) {
+-			loff_t pos = (loff_t)ns->regs.row * ns->geom.pgszoob;
+-			tx = write_file(ns, ns->cfile, ns->file_buf, ns->geom.pgszoob, pos);
+-			if (tx != ns->geom.pgszoob) {
+-				NS_ERR("prog_page: write error for page %d ret %ld\n", ns->regs.row, (long)tx);
+-				return -1;
+-			}
+-			__set_bit(ns->regs.row, ns->pages_written);
+-		} else {
+-			tx = write_file(ns, ns->cfile, pg_off, num, off);
+-			if (tx != num) {
+-				NS_ERR("prog_page: write error for page %d ret %ld\n", ns->regs.row, (long)tx);
+-				return -1;
+-			}
+-		}
+-		return 0;
+-	}
+-
+-	mypage = NS_GET_PAGE(ns);
+-	if (mypage->byte == NULL) {
+-		NS_DBG("prog_page: allocating page %d\n", ns->regs.row);
+-		/*
+-		 * We allocate memory with GFP_NOFS because a flash FS may
+-		 * utilize this. If it is holding an FS lock, then gets here,
+-		 * then kernel memory alloc runs writeback which goes to the FS
+-		 * again and deadlocks. This was seen in practice.
+-		 */
+-		mypage->byte = kmem_cache_alloc(ns->nand_pages_slab, GFP_NOFS);
+-		if (mypage->byte == NULL) {
+-			NS_ERR("prog_page: error allocating memory for page %d\n", ns->regs.row);
+-			return -1;
+-		}
+-		memset(mypage->byte, 0xFF, ns->geom.pgszoob);
+-	}
+-
+-	pg_off = NS_PAGE_BYTE_OFF(ns);
+-	for (i = 0; i < num; i++)
+-		pg_off[i] &= ns->buf.byte[i];
+-
+-	return 0;
+-}
+-
+-/*
+- * If state has any action bit, perform this action.
+- *
+- * RETURNS: 0 if success, -1 if error.
+- */
+-static int do_state_action(struct nandsim *ns, uint32_t action)
+-{
+-	int num;
+-	int busdiv = ns->busw == 8 ? 1 : 2;
+-	unsigned int erase_block_no, page_no;
+-
+-	action &= ACTION_MASK;
+-
+-	/* Check that page address input is correct */
+-	if (action != ACTION_SECERASE && ns->regs.row >= ns->geom.pgnum) {
+-		NS_WARN("do_state_action: wrong page number (%#x)\n", ns->regs.row);
+-		return -1;
+-	}
+-
+-	switch (action) {
+-
+-	case ACTION_CPY:
+-		/*
+-		 * Copy page data to the internal buffer.
+-		 */
+-
+-		/* Column shouldn't be very large */
+-		if (ns->regs.column >= (ns->geom.pgszoob - ns->regs.off)) {
+-			NS_ERR("do_state_action: column number is too large\n");
+-			break;
+-		}
+-		num = ns->geom.pgszoob - ns->regs.off - ns->regs.column;
+-		read_page(ns, num);
+-
+-		NS_DBG("do_state_action: (ACTION_CPY:) copy %d bytes to int buf, raw offset %d\n",
+-			num, NS_RAW_OFFSET(ns) + ns->regs.off);
+-
+-		if (ns->regs.off == 0)
+-			NS_LOG("read page %d\n", ns->regs.row);
+-		else if (ns->regs.off < ns->geom.pgsz)
+-			NS_LOG("read page %d (second half)\n", ns->regs.row);
+-		else
+-			NS_LOG("read OOB of page %d\n", ns->regs.row);
+-
+-		NS_UDELAY(access_delay);
+-		NS_UDELAY(input_cycle * ns->geom.pgsz / 1000 / busdiv);
+-
+-		break;
+-
+-	case ACTION_SECERASE:
+-		/*
+-		 * Erase sector.
+-		 */
+-
+-		if (ns->lines.wp) {
+-			NS_ERR("do_state_action: device is write-protected, ignore sector erase\n");
+-			return -1;
+-		}
+-
+-		if (ns->regs.row >= ns->geom.pgnum - ns->geom.pgsec
+-			|| (ns->regs.row & ~(ns->geom.secsz - 1))) {
+-			NS_ERR("do_state_action: wrong sector address (%#x)\n", ns->regs.row);
+-			return -1;
+-		}
+-
+-		ns->regs.row = (ns->regs.row <<
+-				8 * (ns->geom.pgaddrbytes - ns->geom.secaddrbytes)) | ns->regs.column;
+-		ns->regs.column = 0;
+-
+-		erase_block_no = ns->regs.row >> (ns->geom.secshift - ns->geom.pgshift);
+-
+-		NS_DBG("do_state_action: erase sector at address %#x, off = %d\n",
+-				ns->regs.row, NS_RAW_OFFSET(ns));
+-		NS_LOG("erase sector %u\n", erase_block_no);
+-
+-		erase_sector(ns);
+-
+-		NS_MDELAY(erase_delay);
+-
+-		if (erase_block_wear)
+-			update_wear(erase_block_no);
+-
+-		if (erase_error(erase_block_no)) {
+-			NS_WARN("simulating erase failure in erase block %u\n", erase_block_no);
+-			return -1;
+-		}
+-
+-		break;
+-
+-	case ACTION_PRGPAGE:
+-		/*
+-		 * Program page - move internal buffer data to the page.
+-		 */
+-
+-		if (ns->lines.wp) {
+-			NS_WARN("do_state_action: device is write-protected, programm\n");
+-			return -1;
+-		}
+-
+-		num = ns->geom.pgszoob - ns->regs.off - ns->regs.column;
+-		if (num != ns->regs.count) {
+-			NS_ERR("do_state_action: too few bytes were input (%d instead of %d)\n",
+-					ns->regs.count, num);
+-			return -1;
+-		}
+-
+-		if (prog_page(ns, num) == -1)
+-			return -1;
+-
+-		page_no = ns->regs.row;
+-
+-		NS_DBG("do_state_action: copy %d bytes from int buf to (%#x, %#x), raw off = %d\n",
+-			num, ns->regs.row, ns->regs.column, NS_RAW_OFFSET(ns) + ns->regs.off);
+-		NS_LOG("programm page %d\n", ns->regs.row);
+-
+-		NS_UDELAY(programm_delay);
+-		NS_UDELAY(output_cycle * ns->geom.pgsz / 1000 / busdiv);
+-
+-		if (write_error(page_no)) {
+-			NS_WARN("simulating write failure in page %u\n", page_no);
+-			return -1;
+-		}
+-
+-		break;
+-
+-	case ACTION_ZEROOFF:
+-		NS_DBG("do_state_action: set internal offset to 0\n");
+-		ns->regs.off = 0;
+-		break;
+-
+-	case ACTION_HALFOFF:
+-		if (!(ns->options & OPT_PAGE512_8BIT)) {
+-			NS_ERR("do_state_action: BUG! can't skip half of page for non-512"
+-				"byte page size 8x chips\n");
+-			return -1;
+-		}
+-		NS_DBG("do_state_action: set internal offset to %d\n", ns->geom.pgsz/2);
+-		ns->regs.off = ns->geom.pgsz/2;
+-		break;
+-
+-	case ACTION_OOBOFF:
+-		NS_DBG("do_state_action: set internal offset to %d\n", ns->geom.pgsz);
+-		ns->regs.off = ns->geom.pgsz;
+-		break;
+-
+-	default:
+-		NS_DBG("do_state_action: BUG! unknown action\n");
+-	}
+-
+-	return 0;
+-}
+-
+-/*
+- * Switch simulator's state.
+- */
+-static void switch_state(struct nandsim *ns)
+-{
+-	if (ns->op) {
+-		/*
+-		 * The current operation have already been identified.
+-		 * Just follow the states chain.
+-		 */
+-
+-		ns->stateidx += 1;
+-		ns->state = ns->nxstate;
+-		ns->nxstate = ns->op[ns->stateidx + 1];
+-
+-		NS_DBG("switch_state: operation is known, switch to the next state, "
+-			"state: %s, nxstate: %s\n",
+-			get_state_name(ns->state), get_state_name(ns->nxstate));
+-
+-		/* See, whether we need to do some action */
+-		if ((ns->state & ACTION_MASK) && do_state_action(ns, ns->state) < 0) {
+-			switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
+-			return;
+-		}
+-
+-	} else {
+-		/*
+-		 * We don't yet know which operation we perform.
+-		 * Try to identify it.
+-		 */
+-
+-		/*
+-		 *  The only event causing the switch_state function to
+-		 *  be called with yet unknown operation is new command.
+-		 */
+-		ns->state = get_state_by_command(ns->regs.command);
+-
+-		NS_DBG("switch_state: operation is unknown, try to find it\n");
+-
+-		if (find_operation(ns, 0) != 0)
+-			return;
+-
+-		if ((ns->state & ACTION_MASK) && do_state_action(ns, ns->state) < 0) {
+-			switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
+-			return;
+-		}
+-	}
+-
+-	/* For 16x devices column means the page offset in words */
+-	if ((ns->nxstate & STATE_ADDR_MASK) && ns->busw == 16) {
+-		NS_DBG("switch_state: double the column number for 16x device\n");
+-		ns->regs.column <<= 1;
+-	}
+-
+-	if (NS_STATE(ns->nxstate) == STATE_READY) {
+-		/*
+-		 * The current state is the last. Return to STATE_READY
+-		 */
+-
+-		u_char status = NS_STATUS_OK(ns);
+-
+-		/* In case of data states, see if all bytes were input/output */
+-		if ((ns->state & (STATE_DATAIN_MASK | STATE_DATAOUT_MASK))
+-			&& ns->regs.count != ns->regs.num) {
+-			NS_WARN("switch_state: not all bytes were processed, %d left\n",
+-					ns->regs.num - ns->regs.count);
+-			status = NS_STATUS_FAILED(ns);
+-		}
+-
+-		NS_DBG("switch_state: operation complete, switch to STATE_READY state\n");
+-
+-		switch_to_ready_state(ns, status);
+-
+-		return;
+-	} else if (ns->nxstate & (STATE_DATAIN_MASK | STATE_DATAOUT_MASK)) {
+-		/*
+-		 * If the next state is data input/output, switch to it now
+-		 */
+-
+-		ns->state      = ns->nxstate;
+-		ns->nxstate    = ns->op[++ns->stateidx + 1];
+-		ns->regs.num   = ns->regs.count = 0;
+-
+-		NS_DBG("switch_state: the next state is data I/O, switch, "
+-			"state: %s, nxstate: %s\n",
+-			get_state_name(ns->state), get_state_name(ns->nxstate));
+-
+-		/*
+-		 * Set the internal register to the count of bytes which
+-		 * are expected to be input or output
+-		 */
+-		switch (NS_STATE(ns->state)) {
+-			case STATE_DATAIN:
+-			case STATE_DATAOUT:
+-				ns->regs.num = ns->geom.pgszoob - ns->regs.off - ns->regs.column;
+-				break;
+-
+-			case STATE_DATAOUT_ID:
+-				ns->regs.num = ns->geom.idbytes;
+-				break;
+-
+-			case STATE_DATAOUT_STATUS:
+-				ns->regs.count = ns->regs.num = 0;
+-				break;
+-
+-			default:
+-				NS_ERR("switch_state: BUG! unknown data state\n");
+-		}
+-
+-	} else if (ns->nxstate & STATE_ADDR_MASK) {
+-		/*
+-		 * If the next state is address input, set the internal
+-		 * register to the number of expected address bytes
+-		 */
+-
+-		ns->regs.count = 0;
+-
+-		switch (NS_STATE(ns->nxstate)) {
+-			case STATE_ADDR_PAGE:
+-				ns->regs.num = ns->geom.pgaddrbytes;
+-
+-				break;
+-			case STATE_ADDR_SEC:
+-				ns->regs.num = ns->geom.secaddrbytes;
+-				break;
+-
+-			case STATE_ADDR_ZERO:
+-				ns->regs.num = 1;
+-				break;
+-
+-			case STATE_ADDR_COLUMN:
+-				/* Column address is always 2 bytes */
+-				ns->regs.num = ns->geom.pgaddrbytes - ns->geom.secaddrbytes;
+-				break;
+-
+-			default:
+-				NS_ERR("switch_state: BUG! unknown address state\n");
+-		}
+-	} else {
+-		/*
+-		 * Just reset internal counters.
+-		 */
+-
+-		ns->regs.num = 0;
+-		ns->regs.count = 0;
+-	}
+-}
+-
+-static u_char ns_nand_read_byte(struct mtd_info *mtd)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct nandsim *ns = nand_get_controller_data(chip);
+-	u_char outb = 0x00;
+-
+-	/* Sanity and correctness checks */
+-	if (!ns->lines.ce) {
+-		NS_ERR("read_byte: chip is disabled, return %#x\n", (uint)outb);
+-		return outb;
+-	}
+-	if (ns->lines.ale || ns->lines.cle) {
+-		NS_ERR("read_byte: ALE or CLE pin is high, return %#x\n", (uint)outb);
+-		return outb;
+-	}
+-	if (!(ns->state & STATE_DATAOUT_MASK)) {
+-		NS_WARN("read_byte: unexpected data output cycle, state is %s "
+-			"return %#x\n", get_state_name(ns->state), (uint)outb);
+-		return outb;
+-	}
+-
+-	/* Status register may be read as many times as it is wanted */
+-	if (NS_STATE(ns->state) == STATE_DATAOUT_STATUS) {
+-		NS_DBG("read_byte: return %#x status\n", ns->regs.status);
+-		return ns->regs.status;
+-	}
+-
+-	/* Check if there is any data in the internal buffer which may be read */
+-	if (ns->regs.count == ns->regs.num) {
+-		NS_WARN("read_byte: no more data to output, return %#x\n", (uint)outb);
+-		return outb;
+-	}
+-
+-	switch (NS_STATE(ns->state)) {
+-		case STATE_DATAOUT:
+-			if (ns->busw == 8) {
+-				outb = ns->buf.byte[ns->regs.count];
+-				ns->regs.count += 1;
+-			} else {
+-				outb = (u_char)cpu_to_le16(ns->buf.word[ns->regs.count >> 1]);
+-				ns->regs.count += 2;
+-			}
+-			break;
+-		case STATE_DATAOUT_ID:
+-			NS_DBG("read_byte: read ID byte %d, total = %d\n", ns->regs.count, ns->regs.num);
+-			outb = ns->ids[ns->regs.count];
+-			ns->regs.count += 1;
+-			break;
+-		default:
+-			BUG();
+-	}
+-
+-	if (ns->regs.count == ns->regs.num) {
+-		NS_DBG("read_byte: all bytes were read\n");
+-
+-		if (NS_STATE(ns->nxstate) == STATE_READY)
+-			switch_state(ns);
+-	}
+-
+-	return outb;
+-}
+-
+-static void ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct nandsim *ns = nand_get_controller_data(chip);
+-
+-	/* Sanity and correctness checks */
+-	if (!ns->lines.ce) {
+-		NS_ERR("write_byte: chip is disabled, ignore write\n");
+-		return;
+-	}
+-	if (ns->lines.ale && ns->lines.cle) {
+-		NS_ERR("write_byte: ALE and CLE pins are high simultaneously, ignore write\n");
+-		return;
+-	}
+-
+-	if (ns->lines.cle == 1) {
+-		/*
+-		 * The byte written is a command.
+-		 */
+-
+-		if (byte == NAND_CMD_RESET) {
+-			NS_LOG("reset chip\n");
+-			switch_to_ready_state(ns, NS_STATUS_OK(ns));
+-			return;
+-		}
+-
+-		/* Check that the command byte is correct */
+-		if (check_command(byte)) {
+-			NS_ERR("write_byte: unknown command %#x\n", (uint)byte);
+-			return;
+-		}
+-
+-		if (NS_STATE(ns->state) == STATE_DATAOUT_STATUS
+-			|| NS_STATE(ns->state) == STATE_DATAOUT) {
+-			int row = ns->regs.row;
+-
+-			switch_state(ns);
+-			if (byte == NAND_CMD_RNDOUT)
+-				ns->regs.row = row;
+-		}
+-
+-		/* Check if chip is expecting command */
+-		if (NS_STATE(ns->nxstate) != STATE_UNKNOWN && !(ns->nxstate & STATE_CMD_MASK)) {
+-			/* Do not warn if only 2 id bytes are read */
+-			if (!(ns->regs.command == NAND_CMD_READID &&
+-			    NS_STATE(ns->state) == STATE_DATAOUT_ID && ns->regs.count == 2)) {
+-				/*
+-				 * We are in situation when something else (not command)
+-				 * was expected but command was input. In this case ignore
+-				 * previous command(s)/state(s) and accept the last one.
+-				 */
+-				NS_WARN("write_byte: command (%#x) wasn't expected, expected state is %s, "
+-					"ignore previous states\n", (uint)byte, get_state_name(ns->nxstate));
+-			}
+-			switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
+-		}
+-
+-		NS_DBG("command byte corresponding to %s state accepted\n",
+-			get_state_name(get_state_by_command(byte)));
+-		ns->regs.command = byte;
+-		switch_state(ns);
+-
+-	} else if (ns->lines.ale == 1) {
+-		/*
+-		 * The byte written is an address.
+-		 */
+-
+-		if (NS_STATE(ns->nxstate) == STATE_UNKNOWN) {
+-
+-			NS_DBG("write_byte: operation isn't known yet, identify it\n");
+-
+-			if (find_operation(ns, 1) < 0)
+-				return;
+-
+-			if ((ns->state & ACTION_MASK) && do_state_action(ns, ns->state) < 0) {
+-				switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
+-				return;
+-			}
+-
+-			ns->regs.count = 0;
+-			switch (NS_STATE(ns->nxstate)) {
+-				case STATE_ADDR_PAGE:
+-					ns->regs.num = ns->geom.pgaddrbytes;
+-					break;
+-				case STATE_ADDR_SEC:
+-					ns->regs.num = ns->geom.secaddrbytes;
+-					break;
+-				case STATE_ADDR_ZERO:
+-					ns->regs.num = 1;
+-					break;
+-				default:
+-					BUG();
+-			}
+-		}
+-
+-		/* Check that chip is expecting address */
+-		if (!(ns->nxstate & STATE_ADDR_MASK)) {
+-			NS_ERR("write_byte: address (%#x) isn't expected, expected state is %s, "
+-				"switch to STATE_READY\n", (uint)byte, get_state_name(ns->nxstate));
+-			switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
+-			return;
+-		}
+-
+-		/* Check if this is expected byte */
+-		if (ns->regs.count == ns->regs.num) {
+-			NS_ERR("write_byte: no more address bytes expected\n");
+-			switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
+-			return;
+-		}
+-
+-		accept_addr_byte(ns, byte);
+-
+-		ns->regs.count += 1;
+-
+-		NS_DBG("write_byte: address byte %#x was accepted (%d bytes input, %d expected)\n",
+-				(uint)byte, ns->regs.count, ns->regs.num);
+-
+-		if (ns->regs.count == ns->regs.num) {
+-			NS_DBG("address (%#x, %#x) is accepted\n", ns->regs.row, ns->regs.column);
+-			switch_state(ns);
+-		}
+-
+-	} else {
+-		/*
+-		 * The byte written is an input data.
+-		 */
+-
+-		/* Check that chip is expecting data input */
+-		if (!(ns->state & STATE_DATAIN_MASK)) {
+-			NS_ERR("write_byte: data input (%#x) isn't expected, state is %s, "
+-				"switch to %s\n", (uint)byte,
+-				get_state_name(ns->state), get_state_name(STATE_READY));
+-			switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
+-			return;
+-		}
+-
+-		/* Check if this is expected byte */
+-		if (ns->regs.count == ns->regs.num) {
+-			NS_WARN("write_byte: %u input bytes has already been accepted, ignore write\n",
+-					ns->regs.num);
+-			return;
+-		}
+-
+-		if (ns->busw == 8) {
+-			ns->buf.byte[ns->regs.count] = byte;
+-			ns->regs.count += 1;
+-		} else {
+-			ns->buf.word[ns->regs.count >> 1] = cpu_to_le16((uint16_t)byte);
+-			ns->regs.count += 2;
+-		}
+-	}
+-
+-	return;
+-}
+-
+-static void ns_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int bitmask)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct nandsim *ns = nand_get_controller_data(chip);
+-
+-	ns->lines.cle = bitmask & NAND_CLE ? 1 : 0;
+-	ns->lines.ale = bitmask & NAND_ALE ? 1 : 0;
+-	ns->lines.ce = bitmask & NAND_NCE ? 1 : 0;
+-
+-	if (cmd != NAND_CMD_NONE)
+-		ns_nand_write_byte(mtd, cmd);
+-}
+-
+-static int ns_device_ready(struct mtd_info *mtd)
+-{
+-	NS_DBG("device_ready\n");
+-	return 1;
+-}
+-
+-static uint16_t ns_nand_read_word(struct mtd_info *mtd)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-
+-	NS_DBG("read_word\n");
+-
+-	return chip->read_byte(mtd) | (chip->read_byte(mtd) << 8);
+-}
+-
+-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 nandsim *ns = nand_get_controller_data(chip);
+-
+-	/* Check that chip is expecting data input */
+-	if (!(ns->state & STATE_DATAIN_MASK)) {
+-		NS_ERR("write_buf: data input isn't expected, state is %s, "
+-			"switch to STATE_READY\n", get_state_name(ns->state));
+-		switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
+-		return;
+-	}
+-
+-	/* Check if these are expected bytes */
+-	if (ns->regs.count + len > ns->regs.num) {
+-		NS_ERR("write_buf: too many input bytes\n");
+-		switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
+-		return;
+-	}
+-
+-	memcpy(ns->buf.byte + ns->regs.count, buf, len);
+-	ns->regs.count += len;
+-
+-	if (ns->regs.count == ns->regs.num) {
+-		NS_DBG("write_buf: %d bytes were written\n", ns->regs.count);
+-	}
+-}
+-
+-static void ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct nandsim *ns = nand_get_controller_data(chip);
+-
+-	/* Sanity and correctness checks */
+-	if (!ns->lines.ce) {
+-		NS_ERR("read_buf: chip is disabled\n");
+-		return;
+-	}
+-	if (ns->lines.ale || ns->lines.cle) {
+-		NS_ERR("read_buf: ALE or CLE pin is high\n");
+-		return;
+-	}
+-	if (!(ns->state & STATE_DATAOUT_MASK)) {
+-		NS_WARN("read_buf: unexpected data output cycle, current state is %s\n",
+-			get_state_name(ns->state));
+-		return;
+-	}
+-
+-	if (NS_STATE(ns->state) != STATE_DATAOUT) {
+-		int i;
+-
+-		for (i = 0; i < len; i++)
+-			buf[i] = mtd_to_nand(mtd)->read_byte(mtd);
+-
+-		return;
+-	}
+-
+-	/* Check if these are expected bytes */
+-	if (ns->regs.count + len > ns->regs.num) {
+-		NS_ERR("read_buf: too many bytes to read\n");
+-		switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
+-		return;
+-	}
+-
+-	memcpy(buf, ns->buf.byte + ns->regs.count, len);
+-	ns->regs.count += len;
+-
+-	if (ns->regs.count == ns->regs.num) {
+-		if (NS_STATE(ns->nxstate) == STATE_READY)
+-			switch_state(ns);
+-	}
+-
+-	return;
+-}
+-
+-/*
+- * Module initialization function
+- */
+-static int __init ns_init_module(void)
+-{
+-	struct nand_chip *chip;
+-	struct nandsim *nand;
+-	int retval = -ENOMEM, i;
+-
+-	if (bus_width != 8 && bus_width != 16) {
+-		NS_ERR("wrong bus width (%d), use only 8 or 16\n", bus_width);
+-		return -EINVAL;
+-	}
+-
+-	/* Allocate and initialize mtd_info, nand_chip and nandsim structures */
+-	chip = kzalloc(sizeof(struct nand_chip) + sizeof(struct nandsim),
+-		       GFP_KERNEL);
+-	if (!chip) {
+-		NS_ERR("unable to allocate core structures.\n");
+-		return -ENOMEM;
+-	}
+-	nsmtd       = nand_to_mtd(chip);
+-	nand        = (struct nandsim *)(chip + 1);
+-	nand_set_controller_data(chip, (void *)nand);
+-
+-	/*
+-	 * Register simulator's callbacks.
+-	 */
+-	chip->cmd_ctrl	 = ns_hwcontrol;
+-	chip->read_byte  = ns_nand_read_byte;
+-	chip->dev_ready  = ns_device_ready;
+-	chip->write_buf  = ns_nand_write_buf;
+-	chip->read_buf   = ns_nand_read_buf;
+-	chip->read_word  = ns_nand_read_word;
+-	chip->ecc.mode   = NAND_ECC_SOFT;
+-	chip->ecc.algo   = NAND_ECC_HAMMING;
+-	/* The NAND_SKIP_BBTSCAN option is necessary for 'overridesize' */
+-	/* and 'badblocks' parameters to work */
+-	chip->options   |= NAND_SKIP_BBTSCAN;
+-
+-	switch (bbt) {
+-	case 2:
+-		 chip->bbt_options |= NAND_BBT_NO_OOB;
+-	case 1:
+-		 chip->bbt_options |= NAND_BBT_USE_FLASH;
+-	case 0:
+-		break;
+-	default:
+-		NS_ERR("bbt has to be 0..2\n");
+-		retval = -EINVAL;
+-		goto error;
+-	}
+-	/*
+-	 * Perform minimum nandsim structure initialization to handle
+-	 * the initial ID read command correctly
+-	 */
+-	if (id_bytes[6] != 0xFF || id_bytes[7] != 0xFF)
+-		nand->geom.idbytes = 8;
+-	else if (id_bytes[4] != 0xFF || id_bytes[5] != 0xFF)
+-		nand->geom.idbytes = 6;
+-	else if (id_bytes[2] != 0xFF || id_bytes[3] != 0xFF)
+-		nand->geom.idbytes = 4;
+-	else
+-		nand->geom.idbytes = 2;
+-	nand->regs.status = NS_STATUS_OK(nand);
+-	nand->nxstate = STATE_UNKNOWN;
+-	nand->options |= OPT_PAGE512; /* temporary value */
+-	memcpy(nand->ids, id_bytes, sizeof(nand->ids));
+-	if (bus_width == 16) {
+-		nand->busw = 16;
+-		chip->options |= NAND_BUSWIDTH_16;
+-	}
+-
+-	nsmtd->owner = THIS_MODULE;
+-
+-	if ((retval = parse_weakblocks()) != 0)
+-		goto error;
+-
+-	if ((retval = parse_weakpages()) != 0)
+-		goto error;
+-
+-	if ((retval = parse_gravepages()) != 0)
+-		goto error;
+-
+-	retval = nand_scan_ident(nsmtd, 1, NULL);
+-	if (retval) {
+-		NS_ERR("cannot scan NAND Simulator device\n");
+-		goto error;
+-	}
+-
+-	if (bch) {
+-		unsigned int eccsteps, eccbytes;
+-		if (!mtd_nand_has_bch()) {
+-			NS_ERR("BCH ECC support is disabled\n");
+-			retval = -EINVAL;
+-			goto error;
+-		}
+-		/* use 512-byte ecc blocks */
+-		eccsteps = nsmtd->writesize/512;
+-		eccbytes = (bch*13+7)/8;
+-		/* do not bother supporting small page devices */
+-		if ((nsmtd->oobsize < 64) || !eccsteps) {
+-			NS_ERR("bch not available on small page devices\n");
+-			retval = -EINVAL;
+-			goto error;
+-		}
+-		if ((eccbytes*eccsteps+2) > nsmtd->oobsize) {
+-			NS_ERR("invalid bch value %u\n", bch);
+-			retval = -EINVAL;
+-			goto error;
+-		}
+-		chip->ecc.mode = NAND_ECC_SOFT;
+-		chip->ecc.algo = NAND_ECC_BCH;
+-		chip->ecc.size = 512;
+-		chip->ecc.strength = bch;
+-		chip->ecc.bytes = eccbytes;
+-		NS_INFO("using %u-bit/%u bytes BCH ECC\n", bch, chip->ecc.size);
+-	}
+-
+-	retval = nand_scan_tail(nsmtd);
+-	if (retval) {
+-		NS_ERR("can't register NAND Simulator\n");
+-		goto error;
+-	}
+-
+-	if (overridesize) {
+-		uint64_t new_size = (uint64_t)nsmtd->erasesize << overridesize;
+-		if (new_size >> overridesize != nsmtd->erasesize) {
+-			NS_ERR("overridesize is too big\n");
+-			retval = -EINVAL;
+-			goto err_exit;
+-		}
+-		/* N.B. This relies on nand_scan not doing anything with the size before we change it */
+-		nsmtd->size = new_size;
+-		chip->chipsize = new_size;
+-		chip->chip_shift = ffs(nsmtd->erasesize) + overridesize - 1;
+-		chip->pagemask = (chip->chipsize >> chip->page_shift) - 1;
+-	}
+-
+-	if ((retval = setup_wear_reporting(nsmtd)) != 0)
+-		goto err_exit;
+-
+-	if ((retval = init_nandsim(nsmtd)) != 0)
+-		goto err_exit;
+-
+-	if ((retval = chip->scan_bbt(nsmtd)) != 0)
+-		goto err_exit;
+-
+-	if ((retval = parse_badblocks(nand, nsmtd)) != 0)
+-		goto err_exit;
+-
+-	/* Register NAND partitions */
+-	retval = mtd_device_register(nsmtd, &nand->partitions[0],
+-				     nand->nbparts);
+-	if (retval != 0)
+-		goto err_exit;
+-
+-	if ((retval = nandsim_debugfs_create(nand)) != 0)
+-		goto err_exit;
+-
+-        return 0;
+-
+-err_exit:
+-	free_nandsim(nand);
+-	nand_release(nsmtd);
+-	for (i = 0;i < ARRAY_SIZE(nand->partitions); ++i)
+-		kfree(nand->partitions[i].name);
+-error:
+-	kfree(chip);
+-	free_lists();
+-
+-	return retval;
+-}
+-
+-module_init(ns_init_module);
+-
+-/*
+- * Module clean-up function
+- */
+-static void __exit ns_cleanup_module(void)
+-{
+-	struct nand_chip *chip = mtd_to_nand(nsmtd);
+-	struct nandsim *ns = nand_get_controller_data(chip);
+-	int i;
+-
+-	free_nandsim(ns);    /* Free nandsim private resources */
+-	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 */
+-	free_lists();
+-}
+-
+-module_exit(ns_cleanup_module);
+-
+-MODULE_LICENSE ("GPL");
+-MODULE_AUTHOR ("Artem B. Bityuckiy");
+-MODULE_DESCRIPTION ("The NAND flash simulator");
+diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c
+deleted file mode 100644
+index d8a8068..0000000
+--- a/drivers/mtd/nand/ndfc.c
++++ /dev/null
+@@ -1,286 +0,0 @@
+-/*
+- *  Overview:
+- *   Platform independent driver for NDFC (NanD Flash Controller)
+- *   integrated into EP440 cores
+- *
+- *   Ported to an OF platform driver by Sean MacLennan
+- *
+- *   The NDFC supports multiple chips, but this driver only supports a
+- *   single chip since I do not have access to any boards with
+- *   multiple chips.
+- *
+- *  Author: Thomas Gleixner
+- *
+- *  Copyright 2006 IBM
+- *  Copyright 2008 PIKA Technologies
+- *    Sean MacLennan <smaclennan@pikatech.com>
+- *
+- *  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/mtd/rawnand.h>
+-#include <linux/mtd/nand_ecc.h>
+-#include <linux/mtd/partitions.h>
+-#include <linux/mtd/ndfc.h>
+-#include <linux/slab.h>
+-#include <linux/mtd/mtd.h>
+-#include <linux/of_address.h>
+-#include <linux/of_platform.h>
+-#include <asm/io.h>
+-
+-#define NDFC_MAX_CS    4
+-
+-struct ndfc_controller {
+-	struct platform_device *ofdev;
+-	void __iomem *ndfcbase;
+-	struct nand_chip chip;
+-	int chip_select;
+-	struct nand_hw_control ndfc_control;
+-};
+-
+-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 ndfc_controller *ndfc = nand_get_controller_data(nchip);
+-
+-	ccr = in_be32(ndfc->ndfcbase + NDFC_CCR);
+-	if (chip >= 0) {
+-		ccr &= ~NDFC_CCR_BS_MASK;
+-		ccr |= NDFC_CCR_BS(chip + ndfc->chip_select);
+-	} else
+-		ccr |= NDFC_CCR_RESET_CE;
+-	out_be32(ndfc->ndfcbase + NDFC_CCR, ccr);
+-}
+-
+-static void ndfc_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct ndfc_controller *ndfc = nand_get_controller_data(chip);
+-
+-	if (cmd == NAND_CMD_NONE)
+-		return;
+-
+-	if (ctrl & NAND_CLE)
+-		writel(cmd & 0xFF, ndfc->ndfcbase + NDFC_CMD);
+-	else
+-		writel(cmd & 0xFF, ndfc->ndfcbase + NDFC_ALE);
+-}
+-
+-static int ndfc_ready(struct mtd_info *mtd)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct ndfc_controller *ndfc = nand_get_controller_data(chip);
+-
+-	return in_be32(ndfc->ndfcbase + NDFC_STAT) & NDFC_STAT_IS_READY;
+-}
+-
+-static void ndfc_enable_hwecc(struct mtd_info *mtd, int mode)
+-{
+-	uint32_t ccr;
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct ndfc_controller *ndfc = nand_get_controller_data(chip);
+-
+-	ccr = in_be32(ndfc->ndfcbase + NDFC_CCR);
+-	ccr |= NDFC_CCR_RESET_ECC;
+-	out_be32(ndfc->ndfcbase + NDFC_CCR, ccr);
+-	wmb();
+-}
+-
+-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 ndfc_controller *ndfc = nand_get_controller_data(chip);
+-	uint32_t ecc;
+-	uint8_t *p = (uint8_t *)&ecc;
+-
+-	wmb();
+-	ecc = in_be32(ndfc->ndfcbase + NDFC_ECC);
+-	/* The NDFC uses Smart Media (SMC) bytes order */
+-	ecc_code[0] = p[1];
+-	ecc_code[1] = p[2];
+-	ecc_code[2] = p[3];
+-
+-	return 0;
+-}
+-
+-/*
+- * Speedups for buffer read/write/verify
+- *
+- * NDFC allows 32bit read/write of data. So we can speed up the buffer
+- * functions. No further checking, as nand_base will always read/write
+- * page aligned.
+- */
+-static void ndfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct ndfc_controller *ndfc = nand_get_controller_data(chip);
+-	uint32_t *p = (uint32_t *) buf;
+-
+-	for(;len > 0; len -= 4)
+-		*p++ = in_be32(ndfc->ndfcbase + NDFC_DATA);
+-}
+-
+-static void ndfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct ndfc_controller *ndfc = nand_get_controller_data(chip);
+-	uint32_t *p = (uint32_t *) buf;
+-
+-	for(;len > 0; len -= 4)
+-		out_be32(ndfc->ndfcbase + NDFC_DATA, *p++);
+-}
+-
+-/*
+- * Initialize chip structure
+- */
+-static int ndfc_chip_init(struct ndfc_controller *ndfc,
+-			  struct device_node *node)
+-{
+-	struct device_node *flash_np;
+-	struct nand_chip *chip = &ndfc->chip;
+-	struct mtd_info *mtd = nand_to_mtd(chip);
+-	int ret;
+-
+-	chip->IO_ADDR_R = ndfc->ndfcbase + NDFC_DATA;
+-	chip->IO_ADDR_W = ndfc->ndfcbase + NDFC_DATA;
+-	chip->cmd_ctrl = ndfc_hwcontrol;
+-	chip->dev_ready = ndfc_ready;
+-	chip->select_chip = ndfc_select_chip;
+-	chip->chip_delay = 50;
+-	chip->controller = &ndfc->ndfc_control;
+-	chip->read_buf = ndfc_read_buf;
+-	chip->write_buf = ndfc_write_buf;
+-	chip->ecc.correct = nand_correct_data;
+-	chip->ecc.hwctl = ndfc_enable_hwecc;
+-	chip->ecc.calculate = ndfc_calculate_ecc;
+-	chip->ecc.mode = NAND_ECC_HW;
+-	chip->ecc.size = 256;
+-	chip->ecc.bytes = 3;
+-	chip->ecc.strength = 1;
+-	nand_set_controller_data(chip, ndfc);
+-
+-	mtd->dev.parent = &ndfc->ofdev->dev;
+-
+-	flash_np = of_get_next_child(node, NULL);
+-	if (!flash_np)
+-		return -ENODEV;
+-	nand_set_flash_node(chip, flash_np);
+-
+-	mtd->name = kasprintf(GFP_KERNEL, "%s.%s", dev_name(&ndfc->ofdev->dev),
+-			      flash_np->name);
+-	if (!mtd->name) {
+-		ret = -ENOMEM;
+-		goto err;
+-	}
+-
+-	ret = nand_scan(mtd, 1);
+-	if (ret)
+-		goto err;
+-
+-	ret = mtd_device_register(mtd, NULL, 0);
+-
+-err:
+-	of_node_put(flash_np);
+-	if (ret)
+-		kfree(mtd->name);
+-	return ret;
+-}
+-
+-static int ndfc_probe(struct platform_device *ofdev)
+-{
+-	struct ndfc_controller *ndfc;
+-	const __be32 *reg;
+-	u32 ccr;
+-	u32 cs;
+-	int err, len;
+-
+-	/* Read the reg property to get the chip select */
+-	reg = of_get_property(ofdev->dev.of_node, "reg", &len);
+-	if (reg == NULL || len != 12) {
+-		dev_err(&ofdev->dev, "unable read reg property (%d)\n", len);
+-		return -ENOENT;
+-	}
+-
+-	cs = be32_to_cpu(reg[0]);
+-	if (cs >= NDFC_MAX_CS) {
+-		dev_err(&ofdev->dev, "invalid CS number (%d)\n", cs);
+-		return -EINVAL;
+-	}
+-
+-	ndfc = &ndfc_ctrl[cs];
+-	ndfc->chip_select = cs;
+-
+-	nand_hw_control_init(&ndfc->ndfc_control);
+-	ndfc->ofdev = ofdev;
+-	dev_set_drvdata(&ofdev->dev, ndfc);
+-
+-	ndfc->ndfcbase = of_iomap(ofdev->dev.of_node, 0);
+-	if (!ndfc->ndfcbase) {
+-		dev_err(&ofdev->dev, "failed to get memory\n");
+-		return -EIO;
+-	}
+-
+-	ccr = NDFC_CCR_BS(ndfc->chip_select);
+-
+-	/* It is ok if ccr does not exist - just default to 0 */
+-	reg = of_get_property(ofdev->dev.of_node, "ccr", NULL);
+-	if (reg)
+-		ccr |= be32_to_cpup(reg);
+-
+-	out_be32(ndfc->ndfcbase + NDFC_CCR, ccr);
+-
+-	/* Set the bank settings if given */
+-	reg = of_get_property(ofdev->dev.of_node, "bank-settings", NULL);
+-	if (reg) {
+-		int offset = NDFC_BCFG0 + (ndfc->chip_select << 2);
+-		out_be32(ndfc->ndfcbase + offset, be32_to_cpup(reg));
+-	}
+-
+-	err = ndfc_chip_init(ndfc, ofdev->dev.of_node);
+-	if (err) {
+-		iounmap(ndfc->ndfcbase);
+-		return err;
+-	}
+-
+-	return 0;
+-}
+-
+-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);
+-
+-	nand_release(mtd);
+-	kfree(mtd->name);
+-
+-	return 0;
+-}
+-
+-static const struct of_device_id ndfc_match[] = {
+-	{ .compatible = "ibm,ndfc", },
+-	{}
+-};
+-MODULE_DEVICE_TABLE(of, ndfc_match);
+-
+-static struct platform_driver ndfc_driver = {
+-	.driver = {
+-		.name = "ndfc",
+-		.of_match_table = ndfc_match,
+-	},
+-	.probe = ndfc_probe,
+-	.remove = ndfc_remove,
+-};
+-
+-module_platform_driver(ndfc_driver);
+-
+-MODULE_LICENSE("GPL");
+-MODULE_AUTHOR("Thomas Gleixner <tglx@linutronix.de>");
+-MODULE_DESCRIPTION("OF Platform driver for NDFC");
+diff --git a/drivers/mtd/nand/nuc900_nand.c b/drivers/mtd/nand/nuc900_nand.c
+deleted file mode 100644
+index 7bb4d2e..0000000
+--- a/drivers/mtd/nand/nuc900_nand.c
++++ /dev/null
+@@ -1,306 +0,0 @@
+-/*
+- * Copyright © 2009 Nuvoton technology corporation.
+- *
+- * Wan ZongShun <mcuos.com@gmail.com>
+- *
+- * 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.
+- *
+- */
+-
+-#include <linux/slab.h>
+-#include <linux/module.h>
+-#include <linux/interrupt.h>
+-#include <linux/io.h>
+-#include <linux/platform_device.h>
+-#include <linux/delay.h>
+-#include <linux/clk.h>
+-#include <linux/err.h>
+-
+-#include <linux/mtd/mtd.h>
+-#include <linux/mtd/rawnand.h>
+-#include <linux/mtd/partitions.h>
+-
+-#define REG_FMICSR   	0x00
+-#define REG_SMCSR    	0xa0
+-#define REG_SMISR    	0xac
+-#define REG_SMCMD    	0xb0
+-#define REG_SMADDR   	0xb4
+-#define REG_SMDATA   	0xb8
+-
+-#define RESET_FMI	0x01
+-#define NAND_EN		0x08
+-#define READYBUSY	(0x01 << 18)
+-
+-#define SWRST		0x01
+-#define PSIZE		(0x01 << 3)
+-#define DMARWEN		(0x03 << 1)
+-#define BUSWID		(0x01 << 4)
+-#define ECC4EN		(0x01 << 5)
+-#define WP		(0x01 << 24)
+-#define NANDCS		(0x01 << 25)
+-#define ENDADDR		(0x01 << 31)
+-
+-#define read_data_reg(dev)		\
+-	__raw_readl((dev)->reg + REG_SMDATA)
+-
+-#define write_data_reg(dev, val)	\
+-	__raw_writel((val), (dev)->reg + REG_SMDATA)
+-
+-#define write_cmd_reg(dev, val)		\
+-	__raw_writel((val), (dev)->reg + REG_SMCMD)
+-
+-#define write_addr_reg(dev, val)	\
+-	__raw_writel((val), (dev)->reg + REG_SMADDR)
+-
+-struct nuc900_nand {
+-	struct nand_chip chip;
+-	void __iomem *reg;
+-	struct clk *clk;
+-	spinlock_t lock;
+-};
+-
+-static inline struct nuc900_nand *mtd_to_nuc900(struct mtd_info *mtd)
+-{
+-	return container_of(mtd_to_nand(mtd), struct nuc900_nand, chip);
+-}
+-
+-static const struct mtd_partition partitions[] = {
+-	{
+-	 .name = "NAND FS 0",
+-	 .offset = 0,
+-	 .size = 8 * 1024 * 1024
+-	},
+-	{
+-	 .name = "NAND FS 1",
+-	 .offset = MTDPART_OFS_APPEND,
+-	 .size = MTDPART_SIZ_FULL
+-	}
+-};
+-
+-static unsigned char nuc900_nand_read_byte(struct mtd_info *mtd)
+-{
+-	unsigned char ret;
+-	struct nuc900_nand *nand = mtd_to_nuc900(mtd);
+-
+-	ret = (unsigned char)read_data_reg(nand);
+-
+-	return ret;
+-}
+-
+-static void nuc900_nand_read_buf(struct mtd_info *mtd,
+-				 unsigned char *buf, int len)
+-{
+-	int i;
+-	struct nuc900_nand *nand = mtd_to_nuc900(mtd);
+-
+-	for (i = 0; i < len; i++)
+-		buf[i] = (unsigned char)read_data_reg(nand);
+-}
+-
+-static void nuc900_nand_write_buf(struct mtd_info *mtd,
+-				  const unsigned char *buf, int len)
+-{
+-	int i;
+-	struct nuc900_nand *nand = mtd_to_nuc900(mtd);
+-
+-	for (i = 0; i < len; i++)
+-		write_data_reg(nand, buf[i]);
+-}
+-
+-static int nuc900_check_rb(struct nuc900_nand *nand)
+-{
+-	unsigned int val;
+-	spin_lock(&nand->lock);
+-	val = __raw_readl(nand->reg + REG_SMISR);
+-	val &= READYBUSY;
+-	spin_unlock(&nand->lock);
+-
+-	return val;
+-}
+-
+-static int nuc900_nand_devready(struct mtd_info *mtd)
+-{
+-	struct nuc900_nand *nand = mtd_to_nuc900(mtd);
+-	int ready;
+-
+-	ready = (nuc900_check_rb(nand)) ? 1 : 0;
+-	return ready;
+-}
+-
+-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);
+-	struct nuc900_nand *nand = mtd_to_nuc900(mtd);
+-
+-	if (command == NAND_CMD_READOOB) {
+-		column += mtd->writesize;
+-		command = NAND_CMD_READ0;
+-	}
+-
+-	write_cmd_reg(nand, command & 0xff);
+-
+-	if (column != -1 || page_addr != -1) {
+-
+-		if (column != -1) {
+-			if (chip->options & NAND_BUSWIDTH_16 &&
+-					!nand_opcode_8bits(command))
+-				column >>= 1;
+-			write_addr_reg(nand, column);
+-			write_addr_reg(nand, column >> 8 | ENDADDR);
+-		}
+-		if (page_addr != -1) {
+-			write_addr_reg(nand, page_addr);
+-
+-			if (chip->chipsize > (128 << 20)) {
+-				write_addr_reg(nand, page_addr >> 8);
+-				write_addr_reg(nand, page_addr >> 16 | ENDADDR);
+-			} else {
+-				write_addr_reg(nand, page_addr >> 8 | ENDADDR);
+-			}
+-		}
+-	}
+-
+-	switch (command) {
+-	case NAND_CMD_CACHEDPROG:
+-	case NAND_CMD_PAGEPROG:
+-	case NAND_CMD_ERASE1:
+-	case NAND_CMD_ERASE2:
+-	case NAND_CMD_SEQIN:
+-	case NAND_CMD_RNDIN:
+-	case NAND_CMD_STATUS:
+-		return;
+-
+-	case NAND_CMD_RESET:
+-		if (chip->dev_ready)
+-			break;
+-		udelay(chip->chip_delay);
+-
+-		write_cmd_reg(nand, NAND_CMD_STATUS);
+-		write_cmd_reg(nand, command);
+-
+-		while (!nuc900_check_rb(nand))
+-			;
+-
+-		return;
+-
+-	case NAND_CMD_RNDOUT:
+-		write_cmd_reg(nand, NAND_CMD_RNDOUTSTART);
+-		return;
+-
+-	case NAND_CMD_READ0:
+-
+-		write_cmd_reg(nand, NAND_CMD_READSTART);
+-	default:
+-
+-		if (!chip->dev_ready) {
+-			udelay(chip->chip_delay);
+-			return;
+-		}
+-	}
+-
+-	/* Apply this short delay always to ensure that we do wait tWB in
+-	 * any case on any machine. */
+-	ndelay(100);
+-
+-	while (!chip->dev_ready(mtd))
+-		;
+-}
+-
+-
+-static void nuc900_nand_enable(struct nuc900_nand *nand)
+-{
+-	unsigned int val;
+-	spin_lock(&nand->lock);
+-	__raw_writel(RESET_FMI, (nand->reg + REG_FMICSR));
+-
+-	val = __raw_readl(nand->reg + REG_FMICSR);
+-
+-	if (!(val & NAND_EN))
+-		__raw_writel(val | NAND_EN, nand->reg + REG_FMICSR);
+-
+-	val = __raw_readl(nand->reg + REG_SMCSR);
+-
+-	val &= ~(SWRST|PSIZE|DMARWEN|BUSWID|ECC4EN|NANDCS);
+-	val |= WP;
+-
+-	__raw_writel(val, nand->reg + REG_SMCSR);
+-
+-	spin_unlock(&nand->lock);
+-}
+-
+-static int nuc900_nand_probe(struct platform_device *pdev)
+-{
+-	struct nuc900_nand *nuc900_nand;
+-	struct nand_chip *chip;
+-	struct mtd_info *mtd;
+-	struct resource *res;
+-
+-	nuc900_nand = devm_kzalloc(&pdev->dev, sizeof(struct nuc900_nand),
+-				   GFP_KERNEL);
+-	if (!nuc900_nand)
+-		return -ENOMEM;
+-	chip = &(nuc900_nand->chip);
+-	mtd = nand_to_mtd(chip);
+-
+-	mtd->dev.parent		= &pdev->dev;
+-	spin_lock_init(&nuc900_nand->lock);
+-
+-	nuc900_nand->clk = devm_clk_get(&pdev->dev, NULL);
+-	if (IS_ERR(nuc900_nand->clk))
+-		return -ENOENT;
+-	clk_enable(nuc900_nand->clk);
+-
+-	chip->cmdfunc		= nuc900_nand_command_lp;
+-	chip->dev_ready		= nuc900_nand_devready;
+-	chip->read_byte		= nuc900_nand_read_byte;
+-	chip->write_buf		= nuc900_nand_write_buf;
+-	chip->read_buf		= nuc900_nand_read_buf;
+-	chip->chip_delay	= 50;
+-	chip->options		= 0;
+-	chip->ecc.mode		= NAND_ECC_SOFT;
+-	chip->ecc.algo		= NAND_ECC_HAMMING;
+-
+-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+-	nuc900_nand->reg = devm_ioremap_resource(&pdev->dev, res);
+-	if (IS_ERR(nuc900_nand->reg))
+-		return PTR_ERR(nuc900_nand->reg);
+-
+-	nuc900_nand_enable(nuc900_nand);
+-
+-	if (nand_scan(mtd, 1))
+-		return -ENXIO;
+-
+-	mtd_device_register(mtd, partitions, ARRAY_SIZE(partitions));
+-
+-	platform_set_drvdata(pdev, nuc900_nand);
+-
+-	return 0;
+-}
+-
+-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));
+-	clk_disable(nuc900_nand->clk);
+-
+-	return 0;
+-}
+-
+-static struct platform_driver nuc900_nand_driver = {
+-	.probe		= nuc900_nand_probe,
+-	.remove		= nuc900_nand_remove,
+-	.driver		= {
+-		.name	= "nuc900-fmi",
+-	},
+-};
+-
+-module_platform_driver(nuc900_nand_driver);
+-
+-MODULE_AUTHOR("Wan ZongShun <mcuos.com@gmail.com>");
+-MODULE_DESCRIPTION("w90p910/NUC9xx nand driver!");
+-MODULE_LICENSE("GPL");
+-MODULE_ALIAS("platform:nuc900-fmi");
+diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
+deleted file mode 100644
+index 9f98f74..0000000
+--- a/drivers/mtd/nand/omap2.c
++++ /dev/null
+@@ -1,2332 +0,0 @@
+-/*
+- * Copyright © 2004 Texas Instruments, Jian Zhang <jzhang@ti.com>
+- * Copyright © 2004 Micron Technology Inc.
+- * Copyright © 2004 David Brownell
+- *
+- * 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/platform_device.h>
+-#include <linux/dmaengine.h>
+-#include <linux/dma-mapping.h>
+-#include <linux/delay.h>
+-#include <linux/gpio/consumer.h>
+-#include <linux/module.h>
+-#include <linux/interrupt.h>
+-#include <linux/jiffies.h>
+-#include <linux/sched.h>
+-#include <linux/mtd/mtd.h>
+-#include <linux/mtd/rawnand.h>
+-#include <linux/mtd/partitions.h>
+-#include <linux/omap-dma.h>
+-#include <linux/io.h>
+-#include <linux/slab.h>
+-#include <linux/of.h>
+-#include <linux/of_device.h>
+-
+-#include <linux/mtd/nand_bch.h>
+-#include <linux/platform_data/elm.h>
+-
+-#include <linux/omap-gpmc.h>
+-#include <linux/platform_data/mtd-nand-omap2.h>
+-
+-#define	DRIVER_NAME	"omap2-nand"
+-#define	OMAP_NAND_TIMEOUT_MS	5000
+-
+-#define NAND_Ecc_P1e		(1 << 0)
+-#define NAND_Ecc_P2e		(1 << 1)
+-#define NAND_Ecc_P4e		(1 << 2)
+-#define NAND_Ecc_P8e		(1 << 3)
+-#define NAND_Ecc_P16e		(1 << 4)
+-#define NAND_Ecc_P32e		(1 << 5)
+-#define NAND_Ecc_P64e		(1 << 6)
+-#define NAND_Ecc_P128e		(1 << 7)
+-#define NAND_Ecc_P256e		(1 << 8)
+-#define NAND_Ecc_P512e		(1 << 9)
+-#define NAND_Ecc_P1024e		(1 << 10)
+-#define NAND_Ecc_P2048e		(1 << 11)
+-
+-#define NAND_Ecc_P1o		(1 << 16)
+-#define NAND_Ecc_P2o		(1 << 17)
+-#define NAND_Ecc_P4o		(1 << 18)
+-#define NAND_Ecc_P8o		(1 << 19)
+-#define NAND_Ecc_P16o		(1 << 20)
+-#define NAND_Ecc_P32o		(1 << 21)
+-#define NAND_Ecc_P64o		(1 << 22)
+-#define NAND_Ecc_P128o		(1 << 23)
+-#define NAND_Ecc_P256o		(1 << 24)
+-#define NAND_Ecc_P512o		(1 << 25)
+-#define NAND_Ecc_P1024o		(1 << 26)
+-#define NAND_Ecc_P2048o		(1 << 27)
+-
+-#define TF(value)	(value ? 1 : 0)
+-
+-#define P2048e(a)	(TF(a & NAND_Ecc_P2048e)	<< 0)
+-#define P2048o(a)	(TF(a & NAND_Ecc_P2048o)	<< 1)
+-#define P1e(a)		(TF(a & NAND_Ecc_P1e)		<< 2)
+-#define P1o(a)		(TF(a & NAND_Ecc_P1o)		<< 3)
+-#define P2e(a)		(TF(a & NAND_Ecc_P2e)		<< 4)
+-#define P2o(a)		(TF(a & NAND_Ecc_P2o)		<< 5)
+-#define P4e(a)		(TF(a & NAND_Ecc_P4e)		<< 6)
+-#define P4o(a)		(TF(a & NAND_Ecc_P4o)		<< 7)
+-
+-#define P8e(a)		(TF(a & NAND_Ecc_P8e)		<< 0)
+-#define P8o(a)		(TF(a & NAND_Ecc_P8o)		<< 1)
+-#define P16e(a)		(TF(a & NAND_Ecc_P16e)		<< 2)
+-#define P16o(a)		(TF(a & NAND_Ecc_P16o)		<< 3)
+-#define P32e(a)		(TF(a & NAND_Ecc_P32e)		<< 4)
+-#define P32o(a)		(TF(a & NAND_Ecc_P32o)		<< 5)
+-#define P64e(a)		(TF(a & NAND_Ecc_P64e)		<< 6)
+-#define P64o(a)		(TF(a & NAND_Ecc_P64o)		<< 7)
+-
+-#define P128e(a)	(TF(a & NAND_Ecc_P128e)		<< 0)
+-#define P128o(a)	(TF(a & NAND_Ecc_P128o)		<< 1)
+-#define P256e(a)	(TF(a & NAND_Ecc_P256e)		<< 2)
+-#define P256o(a)	(TF(a & NAND_Ecc_P256o)		<< 3)
+-#define P512e(a)	(TF(a & NAND_Ecc_P512e)		<< 4)
+-#define P512o(a)	(TF(a & NAND_Ecc_P512o)		<< 5)
+-#define P1024e(a)	(TF(a & NAND_Ecc_P1024e)	<< 6)
+-#define P1024o(a)	(TF(a & NAND_Ecc_P1024o)	<< 7)
+-
+-#define P8e_s(a)	(TF(a & NAND_Ecc_P8e)		<< 0)
+-#define P8o_s(a)	(TF(a & NAND_Ecc_P8o)		<< 1)
+-#define P16e_s(a)	(TF(a & NAND_Ecc_P16e)		<< 2)
+-#define P16o_s(a)	(TF(a & NAND_Ecc_P16o)		<< 3)
+-#define P1e_s(a)	(TF(a & NAND_Ecc_P1e)		<< 4)
+-#define P1o_s(a)	(TF(a & NAND_Ecc_P1o)		<< 5)
+-#define P2e_s(a)	(TF(a & NAND_Ecc_P2e)		<< 6)
+-#define P2o_s(a)	(TF(a & NAND_Ecc_P2o)		<< 7)
+-
+-#define P4e_s(a)	(TF(a & NAND_Ecc_P4e)		<< 0)
+-#define P4o_s(a)	(TF(a & NAND_Ecc_P4o)		<< 1)
+-
+-#define	PREFETCH_CONFIG1_CS_SHIFT	24
+-#define	ECC_CONFIG_CS_SHIFT		1
+-#define	CS_MASK				0x7
+-#define	ENABLE_PREFETCH			(0x1 << 7)
+-#define	DMA_MPU_MODE_SHIFT		2
+-#define	ECCSIZE0_SHIFT			12
+-#define	ECCSIZE1_SHIFT			22
+-#define	ECC1RESULTSIZE			0x1
+-#define	ECCCLEAR			0x100
+-#define	ECC1				0x1
+-#define	PREFETCH_FIFOTHRESHOLD_MAX	0x40
+-#define	PREFETCH_FIFOTHRESHOLD(val)	((val) << 8)
+-#define	PREFETCH_STATUS_COUNT(val)	(val & 0x00003fff)
+-#define	PREFETCH_STATUS_FIFO_CNT(val)	((val >> 24) & 0x7F)
+-#define	STATUS_BUFF_EMPTY		0x00000001
+-
+-#define SECTOR_BYTES		512
+-/* 4 bit padding to make byte aligned, 56 = 52 + 4 */
+-#define BCH4_BIT_PAD		4
+-
+-/* GPMC ecc engine settings for read */
+-#define BCH_WRAPMODE_1		1	/* BCH wrap mode 1 */
+-#define BCH8R_ECC_SIZE0		0x1a	/* ecc_size0 = 26 */
+-#define BCH8R_ECC_SIZE1		0x2	/* ecc_size1 = 2 */
+-#define BCH4R_ECC_SIZE0		0xd	/* ecc_size0 = 13 */
+-#define BCH4R_ECC_SIZE1		0x3	/* ecc_size1 = 3 */
+-
+-/* GPMC ecc engine settings for write */
+-#define BCH_WRAPMODE_6		6	/* BCH wrap mode 6 */
+-#define BCH_ECC_SIZE0		0x0	/* ecc_size0 = 0, no oob protection */
+-#define BCH_ECC_SIZE1		0x20	/* ecc_size1 = 32 */
+-
+-#define BADBLOCK_MARKER_LENGTH		2
+-
+-static u_char bch16_vector[] = {0xf5, 0x24, 0x1c, 0xd0, 0x61, 0xb3, 0xf1, 0x55,
+-				0x2e, 0x2c, 0x86, 0xa3, 0xed, 0x36, 0x1b, 0x78,
+-				0x48, 0x76, 0xa9, 0x3b, 0x97, 0xd1, 0x7a, 0x93,
+-				0x07, 0x0e};
+-static u_char bch8_vector[] = {0xf3, 0xdb, 0x14, 0x16, 0x8b, 0xd2, 0xbe, 0xcc,
+-	0xac, 0x6b, 0xff, 0x99, 0x7b};
+-static u_char bch4_vector[] = {0x00, 0x6b, 0x31, 0xdd, 0x41, 0xbc, 0x10};
+-
+-/* Shared among all NAND instances to synchronize access to the ECC Engine */
+-static struct nand_hw_control omap_gpmc_controller = {
+-	.lock = __SPIN_LOCK_UNLOCKED(omap_gpmc_controller.lock),
+-	.wq = __WAIT_QUEUE_HEAD_INITIALIZER(omap_gpmc_controller.wq),
+-};
+-
+-struct omap_nand_info {
+-	struct nand_chip		nand;
+-	struct platform_device		*pdev;
+-
+-	int				gpmc_cs;
+-	bool				dev_ready;
+-	enum nand_io			xfer_type;
+-	int				devsize;
+-	enum omap_ecc			ecc_opt;
+-	struct device_node		*elm_of_node;
+-
+-	unsigned long			phys_base;
+-	struct completion		comp;
+-	struct dma_chan			*dma;
+-	int				gpmc_irq_fifo;
+-	int				gpmc_irq_count;
+-	enum {
+-		OMAP_NAND_IO_READ = 0,	/* read */
+-		OMAP_NAND_IO_WRITE,	/* write */
+-	} iomode;
+-	u_char				*buf;
+-	int					buf_len;
+-	/* Interface to GPMC */
+-	struct gpmc_nand_regs		reg;
+-	struct gpmc_nand_ops		*ops;
+-	bool				flash_bbt;
+-	/* fields specific for BCHx_HW ECC scheme */
+-	struct device			*elm_dev;
+-	/* NAND ready gpio */
+-	struct gpio_desc		*ready_gpiod;
+-};
+-
+-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);
+-}
+-
+-/**
+- * omap_prefetch_enable - configures and starts prefetch transfer
+- * @cs: cs (chip select) number
+- * @fifo_th: fifo threshold to be used for read/ write
+- * @dma_mode: dma mode enable (1) or disable (0)
+- * @u32_count: number of bytes to be transferred
+- * @is_write: prefetch read(0) or write post(1) mode
+- */
+-static int omap_prefetch_enable(int cs, int fifo_th, int dma_mode,
+-	unsigned int u32_count, int is_write, struct omap_nand_info *info)
+-{
+-	u32 val;
+-
+-	if (fifo_th > PREFETCH_FIFOTHRESHOLD_MAX)
+-		return -1;
+-
+-	if (readl(info->reg.gpmc_prefetch_control))
+-		return -EBUSY;
+-
+-	/* Set the amount of bytes to be prefetched */
+-	writel(u32_count, info->reg.gpmc_prefetch_config2);
+-
+-	/* Set dma/mpu mode, the prefetch read / post write and
+-	 * enable the engine. Set which cs is has requested for.
+-	 */
+-	val = ((cs << PREFETCH_CONFIG1_CS_SHIFT) |
+-		PREFETCH_FIFOTHRESHOLD(fifo_th) | ENABLE_PREFETCH |
+-		(dma_mode << DMA_MPU_MODE_SHIFT) | (is_write & 0x1));
+-	writel(val, info->reg.gpmc_prefetch_config1);
+-
+-	/*  Start the prefetch engine */
+-	writel(0x1, info->reg.gpmc_prefetch_control);
+-
+-	return 0;
+-}
+-
+-/**
+- * omap_prefetch_reset - disables and stops the prefetch engine
+- */
+-static int omap_prefetch_reset(int cs, struct omap_nand_info *info)
+-{
+-	u32 config1;
+-
+-	/* check if the same module/cs is trying to reset */
+-	config1 = readl(info->reg.gpmc_prefetch_config1);
+-	if (((config1 >> PREFETCH_CONFIG1_CS_SHIFT) & CS_MASK) != cs)
+-		return -EINVAL;
+-
+-	/* Stop the PFPW engine */
+-	writel(0x0, info->reg.gpmc_prefetch_control);
+-
+-	/* Reset/disable the PFPW engine */
+-	writel(0x0, info->reg.gpmc_prefetch_config1);
+-
+-	return 0;
+-}
+-
+-/**
+- * omap_hwcontrol - hardware specific access to control-lines
+- * @mtd: MTD device structure
+- * @cmd: command to device
+- * @ctrl:
+- * NAND_NCE: bit 0 -> don't care
+- * NAND_CLE: bit 1 -> Command Latch
+- * NAND_ALE: bit 2 -> Address Latch
+- *
+- * NOTE: boards may use different bits for these!!
+- */
+-static void omap_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+-{
+-	struct omap_nand_info *info = mtd_to_omap(mtd);
+-
+-	if (cmd != NAND_CMD_NONE) {
+-		if (ctrl & NAND_CLE)
+-			writeb(cmd, info->reg.gpmc_nand_command);
+-
+-		else if (ctrl & NAND_ALE)
+-			writeb(cmd, info->reg.gpmc_nand_address);
+-
+-		else /* NAND_NCE */
+-			writeb(cmd, info->reg.gpmc_nand_data);
+-	}
+-}
+-
+-/**
+- * omap_read_buf8 - read data from NAND controller into buffer
+- * @mtd: MTD device structure
+- * @buf: buffer to store date
+- * @len: number of bytes to read
+- */
+-static void omap_read_buf8(struct mtd_info *mtd, u_char *buf, int len)
+-{
+-	struct nand_chip *nand = mtd_to_nand(mtd);
+-
+-	ioread8_rep(nand->IO_ADDR_R, buf, len);
+-}
+-
+-/**
+- * omap_write_buf8 - write buffer to NAND controller
+- * @mtd: MTD device structure
+- * @buf: data buffer
+- * @len: number of bytes to write
+- */
+-static void omap_write_buf8(struct mtd_info *mtd, const u_char *buf, int len)
+-{
+-	struct omap_nand_info *info = mtd_to_omap(mtd);
+-	u_char *p = (u_char *)buf;
+-	bool status;
+-
+-	while (len--) {
+-		iowrite8(*p++, info->nand.IO_ADDR_W);
+-		/* wait until buffer is available for write */
+-		do {
+-			status = info->ops->nand_writebuffer_empty();
+-		} while (!status);
+-	}
+-}
+-
+-/**
+- * omap_read_buf16 - read data from NAND controller into buffer
+- * @mtd: MTD device structure
+- * @buf: buffer to store date
+- * @len: number of bytes to read
+- */
+-static void omap_read_buf16(struct mtd_info *mtd, u_char *buf, int len)
+-{
+-	struct nand_chip *nand = mtd_to_nand(mtd);
+-
+-	ioread16_rep(nand->IO_ADDR_R, buf, len / 2);
+-}
+-
+-/**
+- * omap_write_buf16 - write buffer to NAND controller
+- * @mtd: MTD device structure
+- * @buf: data buffer
+- * @len: number of bytes to write
+- */
+-static void omap_write_buf16(struct mtd_info *mtd, const u_char * buf, int len)
+-{
+-	struct omap_nand_info *info = mtd_to_omap(mtd);
+-	u16 *p = (u16 *) buf;
+-	bool status;
+-	/* FIXME try bursts of writesw() or DMA ... */
+-	len >>= 1;
+-
+-	while (len--) {
+-		iowrite16(*p++, info->nand.IO_ADDR_W);
+-		/* wait until buffer is available for write */
+-		do {
+-			status = info->ops->nand_writebuffer_empty();
+-		} while (!status);
+-	}
+-}
+-
+-/**
+- * omap_read_buf_pref - read data from NAND controller into buffer
+- * @mtd: MTD device structure
+- * @buf: buffer to store date
+- * @len: number of bytes to read
+- */
+-static void omap_read_buf_pref(struct mtd_info *mtd, u_char *buf, int len)
+-{
+-	struct omap_nand_info *info = mtd_to_omap(mtd);
+-	uint32_t r_count = 0;
+-	int ret = 0;
+-	u32 *p = (u32 *)buf;
+-
+-	/* take care of subpage reads */
+-	if (len % 4) {
+-		if (info->nand.options & NAND_BUSWIDTH_16)
+-			omap_read_buf16(mtd, buf, len % 4);
+-		else
+-			omap_read_buf8(mtd, buf, len % 4);
+-		p = (u32 *) (buf + len % 4);
+-		len -= len % 4;
+-	}
+-
+-	/* configure and start prefetch transfer */
+-	ret = omap_prefetch_enable(info->gpmc_cs,
+-			PREFETCH_FIFOTHRESHOLD_MAX, 0x0, len, 0x0, info);
+-	if (ret) {
+-		/* PFPW engine is busy, use cpu copy method */
+-		if (info->nand.options & NAND_BUSWIDTH_16)
+-			omap_read_buf16(mtd, (u_char *)p, len);
+-		else
+-			omap_read_buf8(mtd, (u_char *)p, len);
+-	} else {
+-		do {
+-			r_count = readl(info->reg.gpmc_prefetch_status);
+-			r_count = PREFETCH_STATUS_FIFO_CNT(r_count);
+-			r_count = r_count >> 2;
+-			ioread32_rep(info->nand.IO_ADDR_R, p, r_count);
+-			p += r_count;
+-			len -= r_count << 2;
+-		} while (len);
+-		/* disable and stop the PFPW engine */
+-		omap_prefetch_reset(info->gpmc_cs, info);
+-	}
+-}
+-
+-/**
+- * omap_write_buf_pref - write buffer to NAND controller
+- * @mtd: MTD device structure
+- * @buf: data buffer
+- * @len: number of bytes to write
+- */
+-static void omap_write_buf_pref(struct mtd_info *mtd,
+-					const u_char *buf, int len)
+-{
+-	struct omap_nand_info *info = mtd_to_omap(mtd);
+-	uint32_t w_count = 0;
+-	int i = 0, ret = 0;
+-	u16 *p = (u16 *)buf;
+-	unsigned long tim, limit;
+-	u32 val;
+-
+-	/* take care of subpage writes */
+-	if (len % 2 != 0) {
+-		writeb(*buf, info->nand.IO_ADDR_W);
+-		p = (u16 *)(buf + 1);
+-		len--;
+-	}
+-
+-	/*  configure and start prefetch transfer */
+-	ret = omap_prefetch_enable(info->gpmc_cs,
+-			PREFETCH_FIFOTHRESHOLD_MAX, 0x0, len, 0x1, info);
+-	if (ret) {
+-		/* PFPW engine is busy, use cpu copy method */
+-		if (info->nand.options & NAND_BUSWIDTH_16)
+-			omap_write_buf16(mtd, (u_char *)p, len);
+-		else
+-			omap_write_buf8(mtd, (u_char *)p, len);
+-	} else {
+-		while (len) {
+-			w_count = readl(info->reg.gpmc_prefetch_status);
+-			w_count = PREFETCH_STATUS_FIFO_CNT(w_count);
+-			w_count = w_count >> 1;
+-			for (i = 0; (i < w_count) && len; i++, len -= 2)
+-				iowrite16(*p++, info->nand.IO_ADDR_W);
+-		}
+-		/* wait for data to flushed-out before reset the prefetch */
+-		tim = 0;
+-		limit = (loops_per_jiffy *
+-					msecs_to_jiffies(OMAP_NAND_TIMEOUT_MS));
+-		do {
+-			cpu_relax();
+-			val = readl(info->reg.gpmc_prefetch_status);
+-			val = PREFETCH_STATUS_COUNT(val);
+-		} while (val && (tim++ < limit));
+-
+-		/* disable and stop the PFPW engine */
+-		omap_prefetch_reset(info->gpmc_cs, info);
+-	}
+-}
+-
+-/*
+- * omap_nand_dma_callback: callback on the completion of dma transfer
+- * @data: pointer to completion data structure
+- */
+-static void omap_nand_dma_callback(void *data)
+-{
+-	complete((struct completion *) data);
+-}
+-
+-/*
+- * omap_nand_dma_transfer: configure and start dma transfer
+- * @mtd: MTD device structure
+- * @addr: virtual address in RAM of source/destination
+- * @len: number of data bytes to be transferred
+- * @is_write: flag for read/write operation
+- */
+-static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr,
+-					unsigned int len, int is_write)
+-{
+-	struct omap_nand_info *info = mtd_to_omap(mtd);
+-	struct dma_async_tx_descriptor *tx;
+-	enum dma_data_direction dir = is_write ? DMA_TO_DEVICE :
+-							DMA_FROM_DEVICE;
+-	struct scatterlist sg;
+-	unsigned long tim, limit;
+-	unsigned n;
+-	int ret;
+-	u32 val;
+-
+-	if (!virt_addr_valid(addr))
+-		goto out_copy;
+-
+-	sg_init_one(&sg, addr, len);
+-	n = dma_map_sg(info->dma->device->dev, &sg, 1, dir);
+-	if (n == 0) {
+-		dev_err(&info->pdev->dev,
+-			"Couldn't DMA map a %d byte buffer\n", len);
+-		goto out_copy;
+-	}
+-
+-	tx = dmaengine_prep_slave_sg(info->dma, &sg, n,
+-		is_write ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM,
+-		DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+-	if (!tx)
+-		goto out_copy_unmap;
+-
+-	tx->callback = omap_nand_dma_callback;
+-	tx->callback_param = &info->comp;
+-	dmaengine_submit(tx);
+-
+-	init_completion(&info->comp);
+-
+-	/* setup and start DMA using dma_addr */
+-	dma_async_issue_pending(info->dma);
+-
+-	/*  configure and start prefetch transfer */
+-	ret = omap_prefetch_enable(info->gpmc_cs,
+-		PREFETCH_FIFOTHRESHOLD_MAX, 0x1, len, is_write, info);
+-	if (ret)
+-		/* PFPW engine is busy, use cpu copy method */
+-		goto out_copy_unmap;
+-
+-	wait_for_completion(&info->comp);
+-	tim = 0;
+-	limit = (loops_per_jiffy * msecs_to_jiffies(OMAP_NAND_TIMEOUT_MS));
+-
+-	do {
+-		cpu_relax();
+-		val = readl(info->reg.gpmc_prefetch_status);
+-		val = PREFETCH_STATUS_COUNT(val);
+-	} while (val && (tim++ < limit));
+-
+-	/* disable and stop the PFPW engine */
+-	omap_prefetch_reset(info->gpmc_cs, info);
+-
+-	dma_unmap_sg(info->dma->device->dev, &sg, 1, dir);
+-	return 0;
+-
+-out_copy_unmap:
+-	dma_unmap_sg(info->dma->device->dev, &sg, 1, dir);
+-out_copy:
+-	if (info->nand.options & NAND_BUSWIDTH_16)
+-		is_write == 0 ? omap_read_buf16(mtd, (u_char *) addr, len)
+-			: omap_write_buf16(mtd, (u_char *) addr, len);
+-	else
+-		is_write == 0 ? omap_read_buf8(mtd, (u_char *) addr, len)
+-			: omap_write_buf8(mtd, (u_char *) addr, len);
+-	return 0;
+-}
+-
+-/**
+- * omap_read_buf_dma_pref - read data from NAND controller into buffer
+- * @mtd: MTD device structure
+- * @buf: buffer to store date
+- * @len: number of bytes to read
+- */
+-static void omap_read_buf_dma_pref(struct mtd_info *mtd, u_char *buf, int len)
+-{
+-	if (len <= mtd->oobsize)
+-		omap_read_buf_pref(mtd, buf, len);
+-	else
+-		/* start transfer in DMA mode */
+-		omap_nand_dma_transfer(mtd, buf, len, 0x0);
+-}
+-
+-/**
+- * omap_write_buf_dma_pref - write buffer to NAND controller
+- * @mtd: MTD device structure
+- * @buf: data buffer
+- * @len: number of bytes to write
+- */
+-static void omap_write_buf_dma_pref(struct mtd_info *mtd,
+-					const u_char *buf, int len)
+-{
+-	if (len <= mtd->oobsize)
+-		omap_write_buf_pref(mtd, buf, len);
+-	else
+-		/* start transfer in DMA mode */
+-		omap_nand_dma_transfer(mtd, (u_char *) buf, len, 0x1);
+-}
+-
+-/*
+- * omap_nand_irq - GPMC irq handler
+- * @this_irq: gpmc irq number
+- * @dev: omap_nand_info structure pointer is passed here
+- */
+-static irqreturn_t omap_nand_irq(int this_irq, void *dev)
+-{
+-	struct omap_nand_info *info = (struct omap_nand_info *) dev;
+-	u32 bytes;
+-
+-	bytes = readl(info->reg.gpmc_prefetch_status);
+-	bytes = PREFETCH_STATUS_FIFO_CNT(bytes);
+-	bytes = bytes  & 0xFFFC; /* io in multiple of 4 bytes */
+-	if (info->iomode == OMAP_NAND_IO_WRITE) { /* checks for write io */
+-		if (this_irq == info->gpmc_irq_count)
+-			goto done;
+-
+-		if (info->buf_len && (info->buf_len < bytes))
+-			bytes = info->buf_len;
+-		else if (!info->buf_len)
+-			bytes = 0;
+-		iowrite32_rep(info->nand.IO_ADDR_W,
+-						(u32 *)info->buf, bytes >> 2);
+-		info->buf = info->buf + bytes;
+-		info->buf_len -= bytes;
+-
+-	} else {
+-		ioread32_rep(info->nand.IO_ADDR_R,
+-						(u32 *)info->buf, bytes >> 2);
+-		info->buf = info->buf + bytes;
+-
+-		if (this_irq == info->gpmc_irq_count)
+-			goto done;
+-	}
+-
+-	return IRQ_HANDLED;
+-
+-done:
+-	complete(&info->comp);
+-
+-	disable_irq_nosync(info->gpmc_irq_fifo);
+-	disable_irq_nosync(info->gpmc_irq_count);
+-
+-	return IRQ_HANDLED;
+-}
+-
+-/*
+- * omap_read_buf_irq_pref - read data from NAND controller into buffer
+- * @mtd: MTD device structure
+- * @buf: buffer to store date
+- * @len: number of bytes to read
+- */
+-static void omap_read_buf_irq_pref(struct mtd_info *mtd, u_char *buf, int len)
+-{
+-	struct omap_nand_info *info = mtd_to_omap(mtd);
+-	int ret = 0;
+-
+-	if (len <= mtd->oobsize) {
+-		omap_read_buf_pref(mtd, buf, len);
+-		return;
+-	}
+-
+-	info->iomode = OMAP_NAND_IO_READ;
+-	info->buf = buf;
+-	init_completion(&info->comp);
+-
+-	/*  configure and start prefetch transfer */
+-	ret = omap_prefetch_enable(info->gpmc_cs,
+-			PREFETCH_FIFOTHRESHOLD_MAX/2, 0x0, len, 0x0, info);
+-	if (ret)
+-		/* PFPW engine is busy, use cpu copy method */
+-		goto out_copy;
+-
+-	info->buf_len = len;
+-
+-	enable_irq(info->gpmc_irq_count);
+-	enable_irq(info->gpmc_irq_fifo);
+-
+-	/* waiting for read to complete */
+-	wait_for_completion(&info->comp);
+-
+-	/* disable and stop the PFPW engine */
+-	omap_prefetch_reset(info->gpmc_cs, info);
+-	return;
+-
+-out_copy:
+-	if (info->nand.options & NAND_BUSWIDTH_16)
+-		omap_read_buf16(mtd, buf, len);
+-	else
+-		omap_read_buf8(mtd, buf, len);
+-}
+-
+-/*
+- * omap_write_buf_irq_pref - write buffer to NAND controller
+- * @mtd: MTD device structure
+- * @buf: data buffer
+- * @len: number of bytes to write
+- */
+-static void omap_write_buf_irq_pref(struct mtd_info *mtd,
+-					const u_char *buf, int len)
+-{
+-	struct omap_nand_info *info = mtd_to_omap(mtd);
+-	int ret = 0;
+-	unsigned long tim, limit;
+-	u32 val;
+-
+-	if (len <= mtd->oobsize) {
+-		omap_write_buf_pref(mtd, buf, len);
+-		return;
+-	}
+-
+-	info->iomode = OMAP_NAND_IO_WRITE;
+-	info->buf = (u_char *) buf;
+-	init_completion(&info->comp);
+-
+-	/* configure and start prefetch transfer : size=24 */
+-	ret = omap_prefetch_enable(info->gpmc_cs,
+-		(PREFETCH_FIFOTHRESHOLD_MAX * 3) / 8, 0x0, len, 0x1, info);
+-	if (ret)
+-		/* PFPW engine is busy, use cpu copy method */
+-		goto out_copy;
+-
+-	info->buf_len = len;
+-
+-	enable_irq(info->gpmc_irq_count);
+-	enable_irq(info->gpmc_irq_fifo);
+-
+-	/* waiting for write to complete */
+-	wait_for_completion(&info->comp);
+-
+-	/* wait for data to flushed-out before reset the prefetch */
+-	tim = 0;
+-	limit = (loops_per_jiffy *  msecs_to_jiffies(OMAP_NAND_TIMEOUT_MS));
+-	do {
+-		val = readl(info->reg.gpmc_prefetch_status);
+-		val = PREFETCH_STATUS_COUNT(val);
+-		cpu_relax();
+-	} while (val && (tim++ < limit));
+-
+-	/* disable and stop the PFPW engine */
+-	omap_prefetch_reset(info->gpmc_cs, info);
+-	return;
+-
+-out_copy:
+-	if (info->nand.options & NAND_BUSWIDTH_16)
+-		omap_write_buf16(mtd, buf, len);
+-	else
+-		omap_write_buf8(mtd, buf, len);
+-}
+-
+-/**
+- * gen_true_ecc - This function will generate true ECC value
+- * @ecc_buf: buffer to store ecc code
+- *
+- * This generated true ECC value can be used when correcting
+- * data read from NAND flash memory core
+- */
+-static void gen_true_ecc(u8 *ecc_buf)
+-{
+-	u32 tmp = ecc_buf[0] | (ecc_buf[1] << 16) |
+-		((ecc_buf[2] & 0xF0) << 20) | ((ecc_buf[2] & 0x0F) << 8);
+-
+-	ecc_buf[0] = ~(P64o(tmp) | P64e(tmp) | P32o(tmp) | P32e(tmp) |
+-			P16o(tmp) | P16e(tmp) | P8o(tmp) | P8e(tmp));
+-	ecc_buf[1] = ~(P1024o(tmp) | P1024e(tmp) | P512o(tmp) | P512e(tmp) |
+-			P256o(tmp) | P256e(tmp) | P128o(tmp) | P128e(tmp));
+-	ecc_buf[2] = ~(P4o(tmp) | P4e(tmp) | P2o(tmp) | P2e(tmp) | P1o(tmp) |
+-			P1e(tmp) | P2048o(tmp) | P2048e(tmp));
+-}
+-
+-/**
+- * omap_compare_ecc - Detect (2 bits) and correct (1 bit) error in data
+- * @ecc_data1:  ecc code from nand spare area
+- * @ecc_data2:  ecc code from hardware register obtained from hardware ecc
+- * @page_data:  page data
+- *
+- * This function compares two ECC's and indicates if there is an error.
+- * If the error can be corrected it will be corrected to the buffer.
+- * If there is no error, %0 is returned. If there is an error but it
+- * was corrected, %1 is returned. Otherwise, %-1 is returned.
+- */
+-static int omap_compare_ecc(u8 *ecc_data1,	/* read from NAND memory */
+-			    u8 *ecc_data2,	/* read from register */
+-			    u8 *page_data)
+-{
+-	uint	i;
+-	u8	tmp0_bit[8], tmp1_bit[8], tmp2_bit[8];
+-	u8	comp0_bit[8], comp1_bit[8], comp2_bit[8];
+-	u8	ecc_bit[24];
+-	u8	ecc_sum = 0;
+-	u8	find_bit = 0;
+-	uint	find_byte = 0;
+-	int	isEccFF;
+-
+-	isEccFF = ((*(u32 *)ecc_data1 & 0xFFFFFF) == 0xFFFFFF);
+-
+-	gen_true_ecc(ecc_data1);
+-	gen_true_ecc(ecc_data2);
+-
+-	for (i = 0; i <= 2; i++) {
+-		*(ecc_data1 + i) = ~(*(ecc_data1 + i));
+-		*(ecc_data2 + i) = ~(*(ecc_data2 + i));
+-	}
+-
+-	for (i = 0; i < 8; i++) {
+-		tmp0_bit[i]     = *ecc_data1 % 2;
+-		*ecc_data1	= *ecc_data1 / 2;
+-	}
+-
+-	for (i = 0; i < 8; i++) {
+-		tmp1_bit[i]	 = *(ecc_data1 + 1) % 2;
+-		*(ecc_data1 + 1) = *(ecc_data1 + 1) / 2;
+-	}
+-
+-	for (i = 0; i < 8; i++) {
+-		tmp2_bit[i]	 = *(ecc_data1 + 2) % 2;
+-		*(ecc_data1 + 2) = *(ecc_data1 + 2) / 2;
+-	}
+-
+-	for (i = 0; i < 8; i++) {
+-		comp0_bit[i]     = *ecc_data2 % 2;
+-		*ecc_data2       = *ecc_data2 / 2;
+-	}
+-
+-	for (i = 0; i < 8; i++) {
+-		comp1_bit[i]     = *(ecc_data2 + 1) % 2;
+-		*(ecc_data2 + 1) = *(ecc_data2 + 1) / 2;
+-	}
+-
+-	for (i = 0; i < 8; i++) {
+-		comp2_bit[i]     = *(ecc_data2 + 2) % 2;
+-		*(ecc_data2 + 2) = *(ecc_data2 + 2) / 2;
+-	}
+-
+-	for (i = 0; i < 6; i++)
+-		ecc_bit[i] = tmp2_bit[i + 2] ^ comp2_bit[i + 2];
+-
+-	for (i = 0; i < 8; i++)
+-		ecc_bit[i + 6] = tmp0_bit[i] ^ comp0_bit[i];
+-
+-	for (i = 0; i < 8; i++)
+-		ecc_bit[i + 14] = tmp1_bit[i] ^ comp1_bit[i];
+-
+-	ecc_bit[22] = tmp2_bit[0] ^ comp2_bit[0];
+-	ecc_bit[23] = tmp2_bit[1] ^ comp2_bit[1];
+-
+-	for (i = 0; i < 24; i++)
+-		ecc_sum += ecc_bit[i];
+-
+-	switch (ecc_sum) {
+-	case 0:
+-		/* Not reached because this function is not called if
+-		 *  ECC values are equal
+-		 */
+-		return 0;
+-
+-	case 1:
+-		/* Uncorrectable error */
+-		pr_debug("ECC UNCORRECTED_ERROR 1\n");
+-		return -EBADMSG;
+-
+-	case 11:
+-		/* UN-Correctable error */
+-		pr_debug("ECC UNCORRECTED_ERROR B\n");
+-		return -EBADMSG;
+-
+-	case 12:
+-		/* Correctable error */
+-		find_byte = (ecc_bit[23] << 8) +
+-			    (ecc_bit[21] << 7) +
+-			    (ecc_bit[19] << 6) +
+-			    (ecc_bit[17] << 5) +
+-			    (ecc_bit[15] << 4) +
+-			    (ecc_bit[13] << 3) +
+-			    (ecc_bit[11] << 2) +
+-			    (ecc_bit[9]  << 1) +
+-			    ecc_bit[7];
+-
+-		find_bit = (ecc_bit[5] << 2) + (ecc_bit[3] << 1) + ecc_bit[1];
+-
+-		pr_debug("Correcting single bit ECC error at offset: "
+-				"%d, bit: %d\n", find_byte, find_bit);
+-
+-		page_data[find_byte] ^= (1 << find_bit);
+-
+-		return 1;
+-	default:
+-		if (isEccFF) {
+-			if (ecc_data2[0] == 0 &&
+-			    ecc_data2[1] == 0 &&
+-			    ecc_data2[2] == 0)
+-				return 0;
+-		}
+-		pr_debug("UNCORRECTED_ERROR default\n");
+-		return -EBADMSG;
+-	}
+-}
+-
+-/**
+- * omap_correct_data - Compares the ECC read with HW generated ECC
+- * @mtd: MTD device structure
+- * @dat: page data
+- * @read_ecc: ecc read from nand flash
+- * @calc_ecc: ecc read from HW ECC registers
+- *
+- * Compares the ecc read from nand spare area with ECC registers values
+- * and if ECC's mismatched, it will call 'omap_compare_ecc' for error
+- * detection and correction. If there are no errors, %0 is returned. If
+- * there were errors and all of the errors were corrected, the number of
+- * corrected errors is returned. If uncorrectable errors exist, %-1 is
+- * returned.
+- */
+-static int omap_correct_data(struct mtd_info *mtd, u_char *dat,
+-				u_char *read_ecc, u_char *calc_ecc)
+-{
+-	struct omap_nand_info *info = mtd_to_omap(mtd);
+-	int blockCnt = 0, i = 0, ret = 0;
+-	int stat = 0;
+-
+-	/* Ex NAND_ECC_HW12_2048 */
+-	if ((info->nand.ecc.mode == NAND_ECC_HW) &&
+-			(info->nand.ecc.size  == 2048))
+-		blockCnt = 4;
+-	else
+-		blockCnt = 1;
+-
+-	for (i = 0; i < blockCnt; i++) {
+-		if (memcmp(read_ecc, calc_ecc, 3) != 0) {
+-			ret = omap_compare_ecc(read_ecc, calc_ecc, dat);
+-			if (ret < 0)
+-				return ret;
+-			/* keep track of the number of corrected errors */
+-			stat += ret;
+-		}
+-		read_ecc += 3;
+-		calc_ecc += 3;
+-		dat      += 512;
+-	}
+-	return stat;
+-}
+-
+-/**
+- * omap_calcuate_ecc - Generate non-inverted ECC bytes.
+- * @mtd: MTD device structure
+- * @dat: The pointer to data on which ecc is computed
+- * @ecc_code: The ecc_code buffer
+- *
+- * Using noninverted ECC can be considered ugly since writing a blank
+- * page ie. padding will clear the ECC bytes. This is no problem as long
+- * nobody is trying to write data on the seemingly unused page. Reading
+- * an erased page will produce an ECC mismatch between generated and read
+- * ECC bytes that has to be dealt with separately.
+- */
+-static int omap_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
+-				u_char *ecc_code)
+-{
+-	struct omap_nand_info *info = mtd_to_omap(mtd);
+-	u32 val;
+-
+-	val = readl(info->reg.gpmc_ecc_config);
+-	if (((val >> ECC_CONFIG_CS_SHIFT) & CS_MASK) != info->gpmc_cs)
+-		return -EINVAL;
+-
+-	/* read ecc result */
+-	val = readl(info->reg.gpmc_ecc1_result);
+-	*ecc_code++ = val;          /* P128e, ..., P1e */
+-	*ecc_code++ = val >> 16;    /* P128o, ..., P1o */
+-	/* P2048o, P1024o, P512o, P256o, P2048e, P1024e, P512e, P256e */
+-	*ecc_code++ = ((val >> 8) & 0x0f) | ((val >> 20) & 0xf0);
+-
+-	return 0;
+-}
+-
+-/**
+- * omap_enable_hwecc - This function enables the hardware ecc functionality
+- * @mtd: MTD device structure
+- * @mode: Read/Write mode
+- */
+-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);
+-	unsigned int dev_width = (chip->options & NAND_BUSWIDTH_16) ? 1 : 0;
+-	u32 val;
+-
+-	/* clear ecc and enable bits */
+-	val = ECCCLEAR | ECC1;
+-	writel(val, info->reg.gpmc_ecc_control);
+-
+-	/* program ecc and result sizes */
+-	val = ((((info->nand.ecc.size >> 1) - 1) << ECCSIZE1_SHIFT) |
+-			 ECC1RESULTSIZE);
+-	writel(val, info->reg.gpmc_ecc_size_config);
+-
+-	switch (mode) {
+-	case NAND_ECC_READ:
+-	case NAND_ECC_WRITE:
+-		writel(ECCCLEAR | ECC1, info->reg.gpmc_ecc_control);
+-		break;
+-	case NAND_ECC_READSYN:
+-		writel(ECCCLEAR, info->reg.gpmc_ecc_control);
+-		break;
+-	default:
+-		dev_info(&info->pdev->dev,
+-			"error: unrecognized Mode[%d]!\n", mode);
+-		break;
+-	}
+-
+-	/* (ECC 16 or 8 bit col) | ( CS  )  | ECC Enable */
+-	val = (dev_width << 7) | (info->gpmc_cs << 1) | (0x1);
+-	writel(val, info->reg.gpmc_ecc_config);
+-}
+-
+-/**
+- * omap_wait - wait until the command is done
+- * @mtd: MTD device structure
+- * @chip: NAND Chip structure
+- *
+- * Wait function is called during Program and erase operations and
+- * the way it is called from MTD layer, we should wait till the NAND
+- * chip is ready after the programming/erase operation has completed.
+- *
+- * Erase can take up to 400ms and program up to 20ms according to
+- * general NAND and SmartMedia specs
+- */
+-static int omap_wait(struct mtd_info *mtd, struct nand_chip *chip)
+-{
+-	struct nand_chip *this = mtd_to_nand(mtd);
+-	struct omap_nand_info *info = mtd_to_omap(mtd);
+-	unsigned long timeo = jiffies;
+-	int status, state = this->state;
+-
+-	if (state == FL_ERASING)
+-		timeo += msecs_to_jiffies(400);
+-	else
+-		timeo += msecs_to_jiffies(20);
+-
+-	writeb(NAND_CMD_STATUS & 0xFF, info->reg.gpmc_nand_command);
+-	while (time_before(jiffies, timeo)) {
+-		status = readb(info->reg.gpmc_nand_data);
+-		if (status & NAND_STATUS_READY)
+-			break;
+-		cond_resched();
+-	}
+-
+-	status = readb(info->reg.gpmc_nand_data);
+-	return status;
+-}
+-
+-/**
+- * omap_dev_ready - checks the NAND Ready GPIO line
+- * @mtd: MTD device structure
+- *
+- * Returns true if ready and false if busy.
+- */
+-static int omap_dev_ready(struct mtd_info *mtd)
+-{
+-	struct omap_nand_info *info = mtd_to_omap(mtd);
+-
+-	return gpiod_get_value(info->ready_gpiod);
+-}
+-
+-/**
+- * omap_enable_hwecc_bch - Program GPMC to perform BCH ECC calculation
+- * @mtd: MTD device structure
+- * @mode: Read/Write mode
+- *
+- * When using BCH with SW correction (i.e. no ELM), sector size is set
+- * to 512 bytes and we use BCH_WRAPMODE_6 wrapping mode
+- * for both reading and writing with:
+- * eccsize0 = 0  (no additional protected byte in spare area)
+- * eccsize1 = 32 (skip 32 nibbles = 16 bytes per sector in spare area)
+- */
+-static void __maybe_unused omap_enable_hwecc_bch(struct mtd_info *mtd, int mode)
+-{
+-	unsigned int bch_type;
+-	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);
+-	u32 val, wr_mode;
+-	unsigned int ecc_size1, ecc_size0;
+-
+-	/* GPMC configurations for calculating ECC */
+-	switch (ecc_opt) {
+-	case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW:
+-		bch_type = 0;
+-		nsectors = 1;
+-		wr_mode	  = BCH_WRAPMODE_6;
+-		ecc_size0 = BCH_ECC_SIZE0;
+-		ecc_size1 = BCH_ECC_SIZE1;
+-		break;
+-	case OMAP_ECC_BCH4_CODE_HW:
+-		bch_type = 0;
+-		nsectors = chip->ecc.steps;
+-		if (mode == NAND_ECC_READ) {
+-			wr_mode	  = BCH_WRAPMODE_1;
+-			ecc_size0 = BCH4R_ECC_SIZE0;
+-			ecc_size1 = BCH4R_ECC_SIZE1;
+-		} else {
+-			wr_mode   = BCH_WRAPMODE_6;
+-			ecc_size0 = BCH_ECC_SIZE0;
+-			ecc_size1 = BCH_ECC_SIZE1;
+-		}
+-		break;
+-	case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
+-		bch_type = 1;
+-		nsectors = 1;
+-		wr_mode	  = BCH_WRAPMODE_6;
+-		ecc_size0 = BCH_ECC_SIZE0;
+-		ecc_size1 = BCH_ECC_SIZE1;
+-		break;
+-	case OMAP_ECC_BCH8_CODE_HW:
+-		bch_type = 1;
+-		nsectors = chip->ecc.steps;
+-		if (mode == NAND_ECC_READ) {
+-			wr_mode	  = BCH_WRAPMODE_1;
+-			ecc_size0 = BCH8R_ECC_SIZE0;
+-			ecc_size1 = BCH8R_ECC_SIZE1;
+-		} else {
+-			wr_mode   = BCH_WRAPMODE_6;
+-			ecc_size0 = BCH_ECC_SIZE0;
+-			ecc_size1 = BCH_ECC_SIZE1;
+-		}
+-		break;
+-	case OMAP_ECC_BCH16_CODE_HW:
+-		bch_type = 0x2;
+-		nsectors = chip->ecc.steps;
+-		if (mode == NAND_ECC_READ) {
+-			wr_mode	  = 0x01;
+-			ecc_size0 = 52; /* ECC bits in nibbles per sector */
+-			ecc_size1 = 0;  /* non-ECC bits in nibbles per sector */
+-		} else {
+-			wr_mode	  = 0x01;
+-			ecc_size0 = 0;  /* extra bits in nibbles per sector */
+-			ecc_size1 = 52; /* OOB bits in nibbles per sector */
+-		}
+-		break;
+-	default:
+-		return;
+-	}
+-
+-	writel(ECC1, info->reg.gpmc_ecc_control);
+-
+-	/* Configure ecc size for BCH */
+-	val = (ecc_size1 << ECCSIZE1_SHIFT) | (ecc_size0 << ECCSIZE0_SHIFT);
+-	writel(val, info->reg.gpmc_ecc_size_config);
+-
+-	dev_width = (chip->options & NAND_BUSWIDTH_16) ? 1 : 0;
+-
+-	/* BCH configuration */
+-	val = ((1                        << 16) | /* enable BCH */
+-	       (bch_type		 << 12) | /* BCH4/BCH8/BCH16 */
+-	       (wr_mode                  <<  8) | /* wrap mode */
+-	       (dev_width                <<  7) | /* bus width */
+-	       (((nsectors-1) & 0x7)     <<  4) | /* number of sectors */
+-	       (info->gpmc_cs            <<  1) | /* ECC CS */
+-	       (0x1));                            /* enable ECC */
+-
+-	writel(val, info->reg.gpmc_ecc_config);
+-
+-	/* Clear ecc and enable bits */
+-	writel(ECCCLEAR | ECC1, info->reg.gpmc_ecc_control);
+-}
+-
+-static u8  bch4_polynomial[] = {0x28, 0x13, 0xcc, 0x39, 0x96, 0xac, 0x7f};
+-static u8  bch8_polynomial[] = {0xef, 0x51, 0x2e, 0x09, 0xed, 0x93, 0x9a, 0xc2,
+-				0x97, 0x79, 0xe5, 0x24, 0xb5};
+-
+-/**
+- * _omap_calculate_ecc_bch - Generate ECC bytes for one sector
+- * @mtd:	MTD device structure
+- * @dat:	The pointer to data on which ecc is computed
+- * @ecc_code:	The ecc_code buffer
+- * @i:		The sector number (for a multi sector page)
+- *
+- * Support calculating of BCH4/8/16 ECC vectors for one sector
+- * within a page. Sector number is in @i.
+- */
+-static int _omap_calculate_ecc_bch(struct mtd_info *mtd,
+-				   const u_char *dat, u_char *ecc_calc, int i)
+-{
+-	struct omap_nand_info *info = mtd_to_omap(mtd);
+-	int eccbytes	= info->nand.ecc.bytes;
+-	struct gpmc_nand_regs	*gpmc_regs = &info->reg;
+-	u8 *ecc_code;
+-	unsigned long bch_val1, bch_val2, bch_val3, bch_val4;
+-	u32 val;
+-	int j;
+-
+-	ecc_code = ecc_calc;
+-	switch (info->ecc_opt) {
+-	case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
+-	case OMAP_ECC_BCH8_CODE_HW:
+-		bch_val1 = readl(gpmc_regs->gpmc_bch_result0[i]);
+-		bch_val2 = readl(gpmc_regs->gpmc_bch_result1[i]);
+-		bch_val3 = readl(gpmc_regs->gpmc_bch_result2[i]);
+-		bch_val4 = readl(gpmc_regs->gpmc_bch_result3[i]);
+-		*ecc_code++ = (bch_val4 & 0xFF);
+-		*ecc_code++ = ((bch_val3 >> 24) & 0xFF);
+-		*ecc_code++ = ((bch_val3 >> 16) & 0xFF);
+-		*ecc_code++ = ((bch_val3 >> 8) & 0xFF);
+-		*ecc_code++ = (bch_val3 & 0xFF);
+-		*ecc_code++ = ((bch_val2 >> 24) & 0xFF);
+-		*ecc_code++ = ((bch_val2 >> 16) & 0xFF);
+-		*ecc_code++ = ((bch_val2 >> 8) & 0xFF);
+-		*ecc_code++ = (bch_val2 & 0xFF);
+-		*ecc_code++ = ((bch_val1 >> 24) & 0xFF);
+-		*ecc_code++ = ((bch_val1 >> 16) & 0xFF);
+-		*ecc_code++ = ((bch_val1 >> 8) & 0xFF);
+-		*ecc_code++ = (bch_val1 & 0xFF);
+-		break;
+-	case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW:
+-	case OMAP_ECC_BCH4_CODE_HW:
+-		bch_val1 = readl(gpmc_regs->gpmc_bch_result0[i]);
+-		bch_val2 = readl(gpmc_regs->gpmc_bch_result1[i]);
+-		*ecc_code++ = ((bch_val2 >> 12) & 0xFF);
+-		*ecc_code++ = ((bch_val2 >> 4) & 0xFF);
+-		*ecc_code++ = ((bch_val2 & 0xF) << 4) |
+-			((bch_val1 >> 28) & 0xF);
+-		*ecc_code++ = ((bch_val1 >> 20) & 0xFF);
+-		*ecc_code++ = ((bch_val1 >> 12) & 0xFF);
+-		*ecc_code++ = ((bch_val1 >> 4) & 0xFF);
+-		*ecc_code++ = ((bch_val1 & 0xF) << 4);
+-		break;
+-	case OMAP_ECC_BCH16_CODE_HW:
+-		val = readl(gpmc_regs->gpmc_bch_result6[i]);
+-		ecc_code[0]  = ((val >>  8) & 0xFF);
+-		ecc_code[1]  = ((val >>  0) & 0xFF);
+-		val = readl(gpmc_regs->gpmc_bch_result5[i]);
+-		ecc_code[2]  = ((val >> 24) & 0xFF);
+-		ecc_code[3]  = ((val >> 16) & 0xFF);
+-		ecc_code[4]  = ((val >>  8) & 0xFF);
+-		ecc_code[5]  = ((val >>  0) & 0xFF);
+-		val = readl(gpmc_regs->gpmc_bch_result4[i]);
+-		ecc_code[6]  = ((val >> 24) & 0xFF);
+-		ecc_code[7]  = ((val >> 16) & 0xFF);
+-		ecc_code[8]  = ((val >>  8) & 0xFF);
+-		ecc_code[9]  = ((val >>  0) & 0xFF);
+-		val = readl(gpmc_regs->gpmc_bch_result3[i]);
+-		ecc_code[10] = ((val >> 24) & 0xFF);
+-		ecc_code[11] = ((val >> 16) & 0xFF);
+-		ecc_code[12] = ((val >>  8) & 0xFF);
+-		ecc_code[13] = ((val >>  0) & 0xFF);
+-		val = readl(gpmc_regs->gpmc_bch_result2[i]);
+-		ecc_code[14] = ((val >> 24) & 0xFF);
+-		ecc_code[15] = ((val >> 16) & 0xFF);
+-		ecc_code[16] = ((val >>  8) & 0xFF);
+-		ecc_code[17] = ((val >>  0) & 0xFF);
+-		val = readl(gpmc_regs->gpmc_bch_result1[i]);
+-		ecc_code[18] = ((val >> 24) & 0xFF);
+-		ecc_code[19] = ((val >> 16) & 0xFF);
+-		ecc_code[20] = ((val >>  8) & 0xFF);
+-		ecc_code[21] = ((val >>  0) & 0xFF);
+-		val = readl(gpmc_regs->gpmc_bch_result0[i]);
+-		ecc_code[22] = ((val >> 24) & 0xFF);
+-		ecc_code[23] = ((val >> 16) & 0xFF);
+-		ecc_code[24] = ((val >>  8) & 0xFF);
+-		ecc_code[25] = ((val >>  0) & 0xFF);
+-		break;
+-	default:
+-		return -EINVAL;
+-	}
+-
+-	/* ECC scheme specific syndrome customizations */
+-	switch (info->ecc_opt) {
+-	case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW:
+-		/* Add constant polynomial to remainder, so that
+-		 * ECC of blank pages results in 0x0 on reading back
+-		 */
+-		for (j = 0; j < eccbytes; j++)
+-			ecc_calc[j] ^= bch4_polynomial[j];
+-		break;
+-	case OMAP_ECC_BCH4_CODE_HW:
+-		/* Set  8th ECC byte as 0x0 for ROM compatibility */
+-		ecc_calc[eccbytes - 1] = 0x0;
+-		break;
+-	case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
+-		/* Add constant polynomial to remainder, so that
+-		 * ECC of blank pages results in 0x0 on reading back
+-		 */
+-		for (j = 0; j < eccbytes; j++)
+-			ecc_calc[j] ^= bch8_polynomial[j];
+-		break;
+-	case OMAP_ECC_BCH8_CODE_HW:
+-		/* Set 14th ECC byte as 0x0 for ROM compatibility */
+-		ecc_calc[eccbytes - 1] = 0x0;
+-		break;
+-	case OMAP_ECC_BCH16_CODE_HW:
+-		break;
+-	default:
+-		return -EINVAL;
+-	}
+-
+-	return 0;
+-}
+-
+-/**
+- * omap_calculate_ecc_bch_sw - ECC generator for sector for SW based correction
+- * @mtd:	MTD device structure
+- * @dat:	The pointer to data on which ecc is computed
+- * @ecc_code:	The ecc_code buffer
+- *
+- * Support calculating of BCH4/8/16 ECC vectors for one sector. This is used
+- * when SW based correction is required as ECC is required for one sector
+- * at a time.
+- */
+-static int omap_calculate_ecc_bch_sw(struct mtd_info *mtd,
+-				     const u_char *dat, u_char *ecc_calc)
+-{
+-	return _omap_calculate_ecc_bch(mtd, dat, ecc_calc, 0);
+-}
+-
+-/**
+- * omap_calculate_ecc_bch_multi - Generate ECC for multiple sectors
+- * @mtd:	MTD device structure
+- * @dat:	The pointer to data on which ecc is computed
+- * @ecc_code:	The ecc_code buffer
+- *
+- * Support calculating of BCH4/8/16 ecc vectors for the entire page in one go.
+- */
+-static int omap_calculate_ecc_bch_multi(struct mtd_info *mtd,
+-					const u_char *dat, u_char *ecc_calc)
+-{
+-	struct omap_nand_info *info = mtd_to_omap(mtd);
+-	int eccbytes = info->nand.ecc.bytes;
+-	unsigned long nsectors;
+-	int i, ret;
+-
+-	nsectors = ((readl(info->reg.gpmc_ecc_config) >> 4) & 0x7) + 1;
+-	for (i = 0; i < nsectors; i++) {
+-		ret = _omap_calculate_ecc_bch(mtd, dat, ecc_calc, i);
+-		if (ret)
+-			return ret;
+-
+-		ecc_calc += eccbytes;
+-	}
+-
+-	return 0;
+-}
+-
+-/**
+- * erased_sector_bitflips - count bit flips
+- * @data:	data sector buffer
+- * @oob:	oob buffer
+- * @info:	omap_nand_info
+- *
+- * Check the bit flips in erased page falls below correctable level.
+- * If falls below, report the page as erased with correctable bit
+- * flip, else report as uncorrectable page.
+- */
+-static int erased_sector_bitflips(u_char *data, u_char *oob,
+-		struct omap_nand_info *info)
+-{
+-	int flip_bits = 0, i;
+-
+-	for (i = 0; i < info->nand.ecc.size; i++) {
+-		flip_bits += hweight8(~data[i]);
+-		if (flip_bits > info->nand.ecc.strength)
+-			return 0;
+-	}
+-
+-	for (i = 0; i < info->nand.ecc.bytes - 1; i++) {
+-		flip_bits += hweight8(~oob[i]);
+-		if (flip_bits > info->nand.ecc.strength)
+-			return 0;
+-	}
+-
+-	/*
+-	 * Bit flips falls in correctable level.
+-	 * Fill data area with 0xFF
+-	 */
+-	if (flip_bits) {
+-		memset(data, 0xFF, info->nand.ecc.size);
+-		memset(oob, 0xFF, info->nand.ecc.bytes);
+-	}
+-
+-	return flip_bits;
+-}
+-
+-/**
+- * omap_elm_correct_data - corrects page data area in case error reported
+- * @mtd:	MTD device structure
+- * @data:	page data
+- * @read_ecc:	ecc read from nand flash
+- * @calc_ecc:	ecc read from HW ECC registers
+- *
+- * Calculated ecc vector reported as zero in case of non-error pages.
+- * In case of non-zero ecc vector, first filter out erased-pages, and
+- * then process data via ELM to detect bit-flips.
+- */
+-static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data,
+-				u_char *read_ecc, u_char *calc_ecc)
+-{
+-	struct omap_nand_info *info = mtd_to_omap(mtd);
+-	struct nand_ecc_ctrl *ecc = &info->nand.ecc;
+-	int eccsteps = info->nand.ecc.steps;
+-	int i , j, stat = 0;
+-	int eccflag, actual_eccbytes;
+-	struct elm_errorvec err_vec[ERROR_VECTOR_MAX];
+-	u_char *ecc_vec = calc_ecc;
+-	u_char *spare_ecc = read_ecc;
+-	u_char *erased_ecc_vec;
+-	u_char *buf;
+-	int bitflip_count;
+-	bool is_error_reported = false;
+-	u32 bit_pos, byte_pos, error_max, pos;
+-	int err;
+-
+-	switch (info->ecc_opt) {
+-	case OMAP_ECC_BCH4_CODE_HW:
+-		/* omit  7th ECC byte reserved for ROM code compatibility */
+-		actual_eccbytes = ecc->bytes - 1;
+-		erased_ecc_vec = bch4_vector;
+-		break;
+-	case OMAP_ECC_BCH8_CODE_HW:
+-		/* omit 14th ECC byte reserved for ROM code compatibility */
+-		actual_eccbytes = ecc->bytes - 1;
+-		erased_ecc_vec = bch8_vector;
+-		break;
+-	case OMAP_ECC_BCH16_CODE_HW:
+-		actual_eccbytes = ecc->bytes;
+-		erased_ecc_vec = bch16_vector;
+-		break;
+-	default:
+-		dev_err(&info->pdev->dev, "invalid driver configuration\n");
+-		return -EINVAL;
+-	}
+-
+-	/* Initialize elm error vector to zero */
+-	memset(err_vec, 0, sizeof(err_vec));
+-
+-	for (i = 0; i < eccsteps ; i++) {
+-		eccflag = 0;	/* initialize eccflag */
+-
+-		/*
+-		 * Check any error reported,
+-		 * In case of error, non zero ecc reported.
+-		 */
+-		for (j = 0; j < actual_eccbytes; j++) {
+-			if (calc_ecc[j] != 0) {
+-				eccflag = 1; /* non zero ecc, error present */
+-				break;
+-			}
+-		}
+-
+-		if (eccflag == 1) {
+-			if (memcmp(calc_ecc, erased_ecc_vec,
+-						actual_eccbytes) == 0) {
+-				/*
+-				 * calc_ecc[] matches pattern for ECC(all 0xff)
+-				 * so this is definitely an erased-page
+-				 */
+-			} else {
+-				buf = &data[info->nand.ecc.size * i];
+-				/*
+-				 * count number of 0-bits in read_buf.
+-				 * This check can be removed once a similar
+-				 * check is introduced in generic NAND driver
+-				 */
+-				bitflip_count = erased_sector_bitflips(
+-						buf, read_ecc, info);
+-				if (bitflip_count) {
+-					/*
+-					 * number of 0-bits within ECC limits
+-					 * So this may be an erased-page
+-					 */
+-					stat += bitflip_count;
+-				} else {
+-					/*
+-					 * Too many 0-bits. It may be a
+-					 * - programmed-page, OR
+-					 * - erased-page with many bit-flips
+-					 * So this page requires check by ELM
+-					 */
+-					err_vec[i].error_reported = true;
+-					is_error_reported = true;
+-				}
+-			}
+-		}
+-
+-		/* Update the ecc vector */
+-		calc_ecc += ecc->bytes;
+-		read_ecc += ecc->bytes;
+-	}
+-
+-	/* Check if any error reported */
+-	if (!is_error_reported)
+-		return stat;
+-
+-	/* Decode BCH error using ELM module */
+-	elm_decode_bch_error_page(info->elm_dev, ecc_vec, err_vec);
+-
+-	err = 0;
+-	for (i = 0; i < eccsteps; i++) {
+-		if (err_vec[i].error_uncorrectable) {
+-			dev_err(&info->pdev->dev,
+-				"uncorrectable bit-flips found\n");
+-			err = -EBADMSG;
+-		} else if (err_vec[i].error_reported) {
+-			for (j = 0; j < err_vec[i].error_count; j++) {
+-				switch (info->ecc_opt) {
+-				case OMAP_ECC_BCH4_CODE_HW:
+-					/* Add 4 bits to take care of padding */
+-					pos = err_vec[i].error_loc[j] +
+-						BCH4_BIT_PAD;
+-					break;
+-				case OMAP_ECC_BCH8_CODE_HW:
+-				case OMAP_ECC_BCH16_CODE_HW:
+-					pos = err_vec[i].error_loc[j];
+-					break;
+-				default:
+-					return -EINVAL;
+-				}
+-				error_max = (ecc->size + actual_eccbytes) * 8;
+-				/* Calculate bit position of error */
+-				bit_pos = pos % 8;
+-
+-				/* Calculate byte position of error */
+-				byte_pos = (error_max - pos - 1) / 8;
+-
+-				if (pos < error_max) {
+-					if (byte_pos < 512) {
+-						pr_debug("bitflip@dat[%d]=%x\n",
+-						     byte_pos, data[byte_pos]);
+-						data[byte_pos] ^= 1 << bit_pos;
+-					} else {
+-						pr_debug("bitflip@oob[%d]=%x\n",
+-							(byte_pos - 512),
+-						     spare_ecc[byte_pos - 512]);
+-						spare_ecc[byte_pos - 512] ^=
+-							1 << bit_pos;
+-					}
+-				} else {
+-					dev_err(&info->pdev->dev,
+-						"invalid bit-flip @ %d:%d\n",
+-						byte_pos, bit_pos);
+-					err = -EBADMSG;
+-				}
+-			}
+-		}
+-
+-		/* Update number of correctable errors */
+-		stat += err_vec[i].error_count;
+-
+-		/* Update page data with sector size */
+-		data += ecc->size;
+-		spare_ecc += ecc->bytes;
+-	}
+-
+-	return (err) ? err : stat;
+-}
+-
+-/**
+- * omap_write_page_bch - BCH ecc based write page function for entire page
+- * @mtd:		mtd info structure
+- * @chip:		nand chip info structure
+- * @buf:		data buffer
+- * @oob_required:	must write chip->oob_poi to OOB
+- * @page:		page
+- *
+- * Custom write page method evolved to support multi sector writing in one shot
+- */
+-static int omap_write_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
+-			       const uint8_t *buf, int oob_required, int page)
+-{
+-	int ret;
+-	uint8_t *ecc_calc = chip->buffers->ecccalc;
+-
+-	/* Enable GPMC ecc engine */
+-	chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
+-
+-	/* Write data */
+-	chip->write_buf(mtd, buf, mtd->writesize);
+-
+-	/* Update ecc vector from GPMC result registers */
+-	omap_calculate_ecc_bch_multi(mtd, buf, &ecc_calc[0]);
+-
+-	ret = mtd_ooblayout_set_eccbytes(mtd, ecc_calc, chip->oob_poi, 0,
+-					 chip->ecc.total);
+-	if (ret)
+-		return ret;
+-
+-	/* Write ecc vector to OOB area */
+-	chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+-	return 0;
+-}
+-
+-/**
+- * omap_write_subpage_bch - BCH hardware ECC based subpage write
+- * @mtd:	mtd info structure
+- * @chip:	nand chip info structure
+- * @offset:	column address of subpage within the page
+- * @data_len:	data length
+- * @buf:	data buffer
+- * @oob_required: must write chip->oob_poi to OOB
+- * @page: page number to write
+- *
+- * OMAP optimized subpage write method.
+- */
+-static int omap_write_subpage_bch(struct mtd_info *mtd,
+-				  struct nand_chip *chip, u32 offset,
+-				  u32 data_len, const u8 *buf,
+-				  int oob_required, int page)
+-{
+-	u8 *ecc_calc = chip->buffers->ecccalc;
+-	int ecc_size      = chip->ecc.size;
+-	int ecc_bytes     = chip->ecc.bytes;
+-	int ecc_steps     = chip->ecc.steps;
+-	u32 start_step = offset / ecc_size;
+-	u32 end_step   = (offset + data_len - 1) / ecc_size;
+-	int step, ret = 0;
+-
+-	/*
+-	 * Write entire page at one go as it would be optimal
+-	 * as ECC is calculated by hardware.
+-	 * ECC is calculated for all subpages but we choose
+-	 * only what we want.
+-	 */
+-
+-	/* Enable GPMC ECC engine */
+-	chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
+-
+-	/* Write data */
+-	chip->write_buf(mtd, buf, mtd->writesize);
+-
+-	for (step = 0; step < ecc_steps; step++) {
+-		/* mask ECC of un-touched subpages by padding 0xFF */
+-		if (step < start_step || step > end_step)
+-			memset(ecc_calc, 0xff, ecc_bytes);
+-		else
+-			ret = _omap_calculate_ecc_bch(mtd, buf, ecc_calc, step);
+-
+-		if (ret)
+-			return ret;
+-
+-		buf += ecc_size;
+-		ecc_calc += ecc_bytes;
+-	}
+-
+-	/* copy calculated ECC for whole page to chip->buffer->oob */
+-	/* this include masked-value(0xFF) for unwritten subpages */
+-	ecc_calc = chip->buffers->ecccalc;
+-	ret = mtd_ooblayout_set_eccbytes(mtd, ecc_calc, chip->oob_poi, 0,
+-					 chip->ecc.total);
+-	if (ret)
+-		return ret;
+-
+-	/* write OOB buffer to NAND device */
+-	chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+-
+-	return 0;
+-}
+-
+-/**
+- * omap_read_page_bch - BCH ecc based page read function for entire page
+- * @mtd:		mtd info structure
+- * @chip:		nand chip info structure
+- * @buf:		buffer to store read data
+- * @oob_required:	caller requires OOB data read to chip->oob_poi
+- * @page:		page number to read
+- *
+- * For BCH ecc scheme, GPMC used for syndrome calculation and ELM module
+- * used for error correction.
+- * Custom method evolved to support ELM error correction & multi sector
+- * reading. On reading page data area is read along with OOB data with
+- * ecc engine enabled. ecc vector updated after read of OOB data.
+- * For non error pages ecc vector reported as zero.
+- */
+-static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
+-				uint8_t *buf, int oob_required, int page)
+-{
+-	uint8_t *ecc_calc = chip->buffers->ecccalc;
+-	uint8_t *ecc_code = chip->buffers->ecccode;
+-	int stat, ret;
+-	unsigned int max_bitflips = 0;
+-
+-	/* Enable GPMC ecc engine */
+-	chip->ecc.hwctl(mtd, NAND_ECC_READ);
+-
+-	/* Read data */
+-	chip->read_buf(mtd, buf, mtd->writesize);
+-
+-	/* Read oob bytes */
+-	chip->cmdfunc(mtd, NAND_CMD_RNDOUT,
+-		      mtd->writesize + BADBLOCK_MARKER_LENGTH, -1);
+-	chip->read_buf(mtd, chip->oob_poi + BADBLOCK_MARKER_LENGTH,
+-		       chip->ecc.total);
+-
+-	/* Calculate ecc bytes */
+-	omap_calculate_ecc_bch_multi(mtd, buf, ecc_calc);
+-
+-	ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, chip->oob_poi, 0,
+-					 chip->ecc.total);
+-	if (ret)
+-		return ret;
+-
+-	stat = chip->ecc.correct(mtd, buf, ecc_code, ecc_calc);
+-
+-	if (stat < 0) {
+-		mtd->ecc_stats.failed++;
+-	} else {
+-		mtd->ecc_stats.corrected += stat;
+-		max_bitflips = max_t(unsigned int, max_bitflips, stat);
+-	}
+-
+-	return max_bitflips;
+-}
+-
+-/**
+- * is_elm_present - checks for presence of ELM module by scanning DT nodes
+- * @omap_nand_info: NAND device structure containing platform data
+- */
+-static bool is_elm_present(struct omap_nand_info *info,
+-			   struct device_node *elm_node)
+-{
+-	struct platform_device *pdev;
+-
+-	/* check whether elm-id is passed via DT */
+-	if (!elm_node) {
+-		dev_err(&info->pdev->dev, "ELM devicetree node not found\n");
+-		return false;
+-	}
+-	pdev = of_find_device_by_node(elm_node);
+-	/* check whether ELM device is registered */
+-	if (!pdev) {
+-		dev_err(&info->pdev->dev, "ELM device not found\n");
+-		return false;
+-	}
+-	/* ELM module available, now configure it */
+-	info->elm_dev = &pdev->dev;
+-	return true;
+-}
+-
+-static bool omap2_nand_ecc_check(struct omap_nand_info *info,
+-				 struct omap_nand_platform_data	*pdata)
+-{
+-	bool ecc_needs_bch, ecc_needs_omap_bch, ecc_needs_elm;
+-
+-	switch (info->ecc_opt) {
+-	case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW:
+-	case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
+-		ecc_needs_omap_bch = false;
+-		ecc_needs_bch = true;
+-		ecc_needs_elm = false;
+-		break;
+-	case OMAP_ECC_BCH4_CODE_HW:
+-	case OMAP_ECC_BCH8_CODE_HW:
+-	case OMAP_ECC_BCH16_CODE_HW:
+-		ecc_needs_omap_bch = true;
+-		ecc_needs_bch = false;
+-		ecc_needs_elm = true;
+-		break;
+-	default:
+-		ecc_needs_omap_bch = false;
+-		ecc_needs_bch = false;
+-		ecc_needs_elm = false;
+-		break;
+-	}
+-
+-	if (ecc_needs_bch && !IS_ENABLED(CONFIG_MTD_NAND_ECC_BCH)) {
+-		dev_err(&info->pdev->dev,
+-			"CONFIG_MTD_NAND_ECC_BCH not enabled\n");
+-		return false;
+-	}
+-	if (ecc_needs_omap_bch && !IS_ENABLED(CONFIG_MTD_NAND_OMAP_BCH)) {
+-		dev_err(&info->pdev->dev,
+-			"CONFIG_MTD_NAND_OMAP_BCH not enabled\n");
+-		return false;
+-	}
+-	if (ecc_needs_elm && !is_elm_present(info, info->elm_of_node)) {
+-		dev_err(&info->pdev->dev, "ELM not available\n");
+-		return false;
+-	}
+-
+-	return true;
+-}
+-
+-static const char * const nand_xfer_types[] = {
+-	[NAND_OMAP_PREFETCH_POLLED] = "prefetch-polled",
+-	[NAND_OMAP_POLLED] = "polled",
+-	[NAND_OMAP_PREFETCH_DMA] = "prefetch-dma",
+-	[NAND_OMAP_PREFETCH_IRQ] = "prefetch-irq",
+-};
+-
+-static int omap_get_dt_info(struct device *dev, struct omap_nand_info *info)
+-{
+-	struct device_node *child = dev->of_node;
+-	int i;
+-	const char *s;
+-	u32 cs;
+-
+-	if (of_property_read_u32(child, "reg", &cs) < 0) {
+-		dev_err(dev, "reg not found in DT\n");
+-		return -EINVAL;
+-	}
+-
+-	info->gpmc_cs = cs;
+-
+-	/* detect availability of ELM module. Won't be present pre-OMAP4 */
+-	info->elm_of_node = of_parse_phandle(child, "ti,elm-id", 0);
+-	if (!info->elm_of_node) {
+-		info->elm_of_node = of_parse_phandle(child, "elm_id", 0);
+-		if (!info->elm_of_node)
+-			dev_dbg(dev, "ti,elm-id not in DT\n");
+-	}
+-
+-	/* select ecc-scheme for NAND */
+-	if (of_property_read_string(child, "ti,nand-ecc-opt", &s)) {
+-		dev_err(dev, "ti,nand-ecc-opt not found\n");
+-		return -EINVAL;
+-	}
+-
+-	if (!strcmp(s, "sw")) {
+-		info->ecc_opt = OMAP_ECC_HAM1_CODE_SW;
+-	} else if (!strcmp(s, "ham1") ||
+-		   !strcmp(s, "hw") || !strcmp(s, "hw-romcode")) {
+-		info->ecc_opt =	OMAP_ECC_HAM1_CODE_HW;
+-	} else if (!strcmp(s, "bch4")) {
+-		if (info->elm_of_node)
+-			info->ecc_opt = OMAP_ECC_BCH4_CODE_HW;
+-		else
+-			info->ecc_opt = OMAP_ECC_BCH4_CODE_HW_DETECTION_SW;
+-	} else if (!strcmp(s, "bch8")) {
+-		if (info->elm_of_node)
+-			info->ecc_opt = OMAP_ECC_BCH8_CODE_HW;
+-		else
+-			info->ecc_opt = OMAP_ECC_BCH8_CODE_HW_DETECTION_SW;
+-	} else if (!strcmp(s, "bch16")) {
+-		info->ecc_opt =	OMAP_ECC_BCH16_CODE_HW;
+-	} else {
+-		dev_err(dev, "unrecognized value for ti,nand-ecc-opt\n");
+-		return -EINVAL;
+-	}
+-
+-	/* select data transfer mode */
+-	if (!of_property_read_string(child, "ti,nand-xfer-type", &s)) {
+-		for (i = 0; i < ARRAY_SIZE(nand_xfer_types); i++) {
+-			if (!strcasecmp(s, nand_xfer_types[i])) {
+-				info->xfer_type = i;
+-				return 0;
+-			}
+-		}
+-
+-		dev_err(dev, "unrecognized value for ti,nand-xfer-type\n");
+-		return -EINVAL;
+-	}
+-
+-	return 0;
+-}
+-
+-static int omap_ooblayout_ecc(struct mtd_info *mtd, int section,
+-			      struct mtd_oob_region *oobregion)
+-{
+-	struct omap_nand_info *info = mtd_to_omap(mtd);
+-	struct nand_chip *chip = &info->nand;
+-	int off = BADBLOCK_MARKER_LENGTH;
+-
+-	if (info->ecc_opt == OMAP_ECC_HAM1_CODE_HW &&
+-	    !(chip->options & NAND_BUSWIDTH_16))
+-		off = 1;
+-
+-	if (section)
+-		return -ERANGE;
+-
+-	oobregion->offset = off;
+-	oobregion->length = chip->ecc.total;
+-
+-	return 0;
+-}
+-
+-static int omap_ooblayout_free(struct mtd_info *mtd, int section,
+-			       struct mtd_oob_region *oobregion)
+-{
+-	struct omap_nand_info *info = mtd_to_omap(mtd);
+-	struct nand_chip *chip = &info->nand;
+-	int off = BADBLOCK_MARKER_LENGTH;
+-
+-	if (info->ecc_opt == OMAP_ECC_HAM1_CODE_HW &&
+-	    !(chip->options & NAND_BUSWIDTH_16))
+-		off = 1;
+-
+-	if (section)
+-		return -ERANGE;
+-
+-	off += chip->ecc.total;
+-	if (off >= mtd->oobsize)
+-		return -ERANGE;
+-
+-	oobregion->offset = off;
+-	oobregion->length = mtd->oobsize - off;
+-
+-	return 0;
+-}
+-
+-static const struct mtd_ooblayout_ops omap_ooblayout_ops = {
+-	.ecc = omap_ooblayout_ecc,
+-	.free = omap_ooblayout_free,
+-};
+-
+-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);
+-	int off = BADBLOCK_MARKER_LENGTH;
+-
+-	if (section >= chip->ecc.steps)
+-		return -ERANGE;
+-
+-	/*
+-	 * When SW correction is employed, one OMAP specific marker byte is
+-	 * reserved after each ECC step.
+-	 */
+-	oobregion->offset = off + (section * (chip->ecc.bytes + 1));
+-	oobregion->length = chip->ecc.bytes;
+-
+-	return 0;
+-}
+-
+-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);
+-	int off = BADBLOCK_MARKER_LENGTH;
+-
+-	if (section)
+-		return -ERANGE;
+-
+-	/*
+-	 * When SW correction is employed, one OMAP specific marker byte is
+-	 * reserved after each ECC step.
+-	 */
+-	off += ((chip->ecc.bytes + 1) * chip->ecc.steps);
+-	if (off >= mtd->oobsize)
+-		return -ERANGE;
+-
+-	oobregion->offset = off;
+-	oobregion->length = mtd->oobsize - off;
+-
+-	return 0;
+-}
+-
+-static const struct mtd_ooblayout_ops omap_sw_ooblayout_ops = {
+-	.ecc = omap_sw_ooblayout_ecc,
+-	.free = omap_sw_ooblayout_free,
+-};
+-
+-static int omap_nand_probe(struct platform_device *pdev)
+-{
+-	struct omap_nand_info		*info;
+-	struct omap_nand_platform_data	*pdata = NULL;
+-	struct mtd_info			*mtd;
+-	struct nand_chip		*nand_chip;
+-	int				err;
+-	dma_cap_mask_t			mask;
+-	struct resource			*res;
+-	struct device			*dev = &pdev->dev;
+-	int				min_oobbytes = BADBLOCK_MARKER_LENGTH;
+-	int				oobbytes_per_step;
+-
+-	info = devm_kzalloc(&pdev->dev, sizeof(struct omap_nand_info),
+-				GFP_KERNEL);
+-	if (!info)
+-		return -ENOMEM;
+-
+-	info->pdev = pdev;
+-
+-	if (dev->of_node) {
+-		if (omap_get_dt_info(dev, info))
+-			return -EINVAL;
+-	} else {
+-		pdata = dev_get_platdata(&pdev->dev);
+-		if (!pdata) {
+-			dev_err(&pdev->dev, "platform data missing\n");
+-			return -EINVAL;
+-		}
+-
+-		info->gpmc_cs = pdata->cs;
+-		info->reg = pdata->reg;
+-		info->ecc_opt = pdata->ecc_opt;
+-		if (pdata->dev_ready)
+-			dev_info(&pdev->dev, "pdata->dev_ready is deprecated\n");
+-
+-		info->xfer_type = pdata->xfer_type;
+-		info->devsize = pdata->devsize;
+-		info->elm_of_node = pdata->elm_of_node;
+-		info->flash_bbt = pdata->flash_bbt;
+-	}
+-
+-	platform_set_drvdata(pdev, info);
+-	info->ops = gpmc_omap_get_nand_ops(&info->reg, info->gpmc_cs);
+-	if (!info->ops) {
+-		dev_err(&pdev->dev, "Failed to get GPMC->NAND interface\n");
+-		return -ENODEV;
+-	}
+-
+-	nand_chip		= &info->nand;
+-	mtd			= nand_to_mtd(nand_chip);
+-	mtd->dev.parent		= &pdev->dev;
+-	nand_chip->ecc.priv	= NULL;
+-	nand_set_flash_node(nand_chip, dev->of_node);
+-
+-	if (!mtd->name) {
+-		mtd->name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
+-					   "omap2-nand.%d", info->gpmc_cs);
+-		if (!mtd->name) {
+-			dev_err(&pdev->dev, "Failed to set MTD name\n");
+-			return -ENOMEM;
+-		}
+-	}
+-
+-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+-	nand_chip->IO_ADDR_R = devm_ioremap_resource(&pdev->dev, res);
+-	if (IS_ERR(nand_chip->IO_ADDR_R))
+-		return PTR_ERR(nand_chip->IO_ADDR_R);
+-
+-	info->phys_base = res->start;
+-
+-	nand_chip->controller = &omap_gpmc_controller;
+-
+-	nand_chip->IO_ADDR_W = nand_chip->IO_ADDR_R;
+-	nand_chip->cmd_ctrl  = omap_hwcontrol;
+-
+-	info->ready_gpiod = devm_gpiod_get_optional(&pdev->dev, "rb",
+-						    GPIOD_IN);
+-	if (IS_ERR(info->ready_gpiod)) {
+-		dev_err(dev, "failed to get ready gpio\n");
+-		return PTR_ERR(info->ready_gpiod);
+-	}
+-
+-	/*
+-	 * If RDY/BSY line is connected to OMAP then use the omap ready
+-	 * function and the generic nand_wait function which reads the status
+-	 * register after monitoring the RDY/BSY line. Otherwise use a standard
+-	 * chip delay which is slightly more than tR (AC Timing) of the NAND
+-	 * device and read status register until you get a failure or success
+-	 */
+-	if (info->ready_gpiod) {
+-		nand_chip->dev_ready = omap_dev_ready;
+-		nand_chip->chip_delay = 0;
+-	} else {
+-		nand_chip->waitfunc = omap_wait;
+-		nand_chip->chip_delay = 50;
+-	}
+-
+-	if (info->flash_bbt)
+-		nand_chip->bbt_options |= NAND_BBT_USE_FLASH;
+-
+-	/* scan NAND device connected to chip controller */
+-	nand_chip->options |= info->devsize & NAND_BUSWIDTH_16;
+-	err = nand_scan_ident(mtd, 1, NULL);
+-	if (err) {
+-		dev_err(&info->pdev->dev,
+-			"scan failed, may be bus-width mismatch\n");
+-		goto return_error;
+-	}
+-
+-	if (nand_chip->bbt_options & NAND_BBT_USE_FLASH)
+-		nand_chip->bbt_options |= NAND_BBT_NO_OOB;
+-	else
+-		nand_chip->options |= NAND_SKIP_BBTSCAN;
+-
+-	/* re-populate low-level callbacks based on xfer modes */
+-	switch (info->xfer_type) {
+-	case NAND_OMAP_PREFETCH_POLLED:
+-		nand_chip->read_buf   = omap_read_buf_pref;
+-		nand_chip->write_buf  = omap_write_buf_pref;
+-		break;
+-
+-	case NAND_OMAP_POLLED:
+-		/* Use nand_base defaults for {read,write}_buf */
+-		break;
+-
+-	case NAND_OMAP_PREFETCH_DMA:
+-		dma_cap_zero(mask);
+-		dma_cap_set(DMA_SLAVE, mask);
+-		info->dma = dma_request_chan(pdev->dev.parent, "rxtx");
+-
+-		if (IS_ERR(info->dma)) {
+-			dev_err(&pdev->dev, "DMA engine request failed\n");
+-			err = PTR_ERR(info->dma);
+-			goto return_error;
+-		} else {
+-			struct dma_slave_config cfg;
+-
+-			memset(&cfg, 0, sizeof(cfg));
+-			cfg.src_addr = info->phys_base;
+-			cfg.dst_addr = info->phys_base;
+-			cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+-			cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+-			cfg.src_maxburst = 16;
+-			cfg.dst_maxburst = 16;
+-			err = dmaengine_slave_config(info->dma, &cfg);
+-			if (err) {
+-				dev_err(&pdev->dev, "DMA engine slave config failed: %d\n",
+-					err);
+-				goto return_error;
+-			}
+-			nand_chip->read_buf   = omap_read_buf_dma_pref;
+-			nand_chip->write_buf  = omap_write_buf_dma_pref;
+-		}
+-		break;
+-
+-	case NAND_OMAP_PREFETCH_IRQ:
+-		info->gpmc_irq_fifo = platform_get_irq(pdev, 0);
+-		if (info->gpmc_irq_fifo <= 0) {
+-			dev_err(&pdev->dev, "error getting fifo irq\n");
+-			err = -ENODEV;
+-			goto return_error;
+-		}
+-		err = devm_request_irq(&pdev->dev, info->gpmc_irq_fifo,
+-					omap_nand_irq, IRQF_SHARED,
+-					"gpmc-nand-fifo", info);
+-		if (err) {
+-			dev_err(&pdev->dev, "requesting irq(%d) error:%d",
+-						info->gpmc_irq_fifo, err);
+-			info->gpmc_irq_fifo = 0;
+-			goto return_error;
+-		}
+-
+-		info->gpmc_irq_count = platform_get_irq(pdev, 1);
+-		if (info->gpmc_irq_count <= 0) {
+-			dev_err(&pdev->dev, "error getting count irq\n");
+-			err = -ENODEV;
+-			goto return_error;
+-		}
+-		err = devm_request_irq(&pdev->dev, info->gpmc_irq_count,
+-					omap_nand_irq, IRQF_SHARED,
+-					"gpmc-nand-count", info);
+-		if (err) {
+-			dev_err(&pdev->dev, "requesting irq(%d) error:%d",
+-						info->gpmc_irq_count, err);
+-			info->gpmc_irq_count = 0;
+-			goto return_error;
+-		}
+-
+-		nand_chip->read_buf  = omap_read_buf_irq_pref;
+-		nand_chip->write_buf = omap_write_buf_irq_pref;
+-
+-		break;
+-
+-	default:
+-		dev_err(&pdev->dev,
+-			"xfer_type(%d) not supported!\n", info->xfer_type);
+-		err = -EINVAL;
+-		goto return_error;
+-	}
+-
+-	if (!omap2_nand_ecc_check(info, pdata)) {
+-		err = -EINVAL;
+-		goto return_error;
+-	}
+-
+-	/*
+-	 * Bail out earlier to let NAND_ECC_SOFT code create its own
+-	 * ooblayout instead of using ours.
+-	 */
+-	if (info->ecc_opt == OMAP_ECC_HAM1_CODE_SW) {
+-		nand_chip->ecc.mode = NAND_ECC_SOFT;
+-		nand_chip->ecc.algo = NAND_ECC_HAMMING;
+-		goto scan_tail;
+-	}
+-
+-	/* populate MTD interface based on ECC scheme */
+-	switch (info->ecc_opt) {
+-	case OMAP_ECC_HAM1_CODE_HW:
+-		pr_info("nand: using OMAP_ECC_HAM1_CODE_HW\n");
+-		nand_chip->ecc.mode             = NAND_ECC_HW;
+-		nand_chip->ecc.bytes            = 3;
+-		nand_chip->ecc.size             = 512;
+-		nand_chip->ecc.strength         = 1;
+-		nand_chip->ecc.calculate        = omap_calculate_ecc;
+-		nand_chip->ecc.hwctl            = omap_enable_hwecc;
+-		nand_chip->ecc.correct          = omap_correct_data;
+-		mtd_set_ooblayout(mtd, &omap_ooblayout_ops);
+-		oobbytes_per_step		= nand_chip->ecc.bytes;
+-
+-		if (!(nand_chip->options & NAND_BUSWIDTH_16))
+-			min_oobbytes		= 1;
+-
+-		break;
+-
+-	case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW:
+-		pr_info("nand: using OMAP_ECC_BCH4_CODE_HW_DETECTION_SW\n");
+-		nand_chip->ecc.mode		= NAND_ECC_HW;
+-		nand_chip->ecc.size		= 512;
+-		nand_chip->ecc.bytes		= 7;
+-		nand_chip->ecc.strength		= 4;
+-		nand_chip->ecc.hwctl		= omap_enable_hwecc_bch;
+-		nand_chip->ecc.correct		= nand_bch_correct_data;
+-		nand_chip->ecc.calculate	= omap_calculate_ecc_bch_sw;
+-		mtd_set_ooblayout(mtd, &omap_sw_ooblayout_ops);
+-		/* Reserve one byte for the OMAP marker */
+-		oobbytes_per_step		= nand_chip->ecc.bytes + 1;
+-		/* software bch library is used for locating errors */
+-		nand_chip->ecc.priv		= nand_bch_init(mtd);
+-		if (!nand_chip->ecc.priv) {
+-			dev_err(&info->pdev->dev, "unable to use BCH library\n");
+-			err = -EINVAL;
+-			goto return_error;
+-		}
+-		break;
+-
+-	case OMAP_ECC_BCH4_CODE_HW:
+-		pr_info("nand: using OMAP_ECC_BCH4_CODE_HW ECC scheme\n");
+-		nand_chip->ecc.mode		= NAND_ECC_HW;
+-		nand_chip->ecc.size		= 512;
+-		/* 14th bit is kept reserved for ROM-code compatibility */
+-		nand_chip->ecc.bytes		= 7 + 1;
+-		nand_chip->ecc.strength		= 4;
+-		nand_chip->ecc.hwctl		= omap_enable_hwecc_bch;
+-		nand_chip->ecc.correct		= omap_elm_correct_data;
+-		nand_chip->ecc.read_page	= omap_read_page_bch;
+-		nand_chip->ecc.write_page	= omap_write_page_bch;
+-		nand_chip->ecc.write_subpage	= omap_write_subpage_bch;
+-		mtd_set_ooblayout(mtd, &omap_ooblayout_ops);
+-		oobbytes_per_step		= nand_chip->ecc.bytes;
+-
+-		err = elm_config(info->elm_dev, BCH4_ECC,
+-				 mtd->writesize / nand_chip->ecc.size,
+-				 nand_chip->ecc.size, nand_chip->ecc.bytes);
+-		if (err < 0)
+-			goto return_error;
+-		break;
+-
+-	case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
+-		pr_info("nand: using OMAP_ECC_BCH8_CODE_HW_DETECTION_SW\n");
+-		nand_chip->ecc.mode		= NAND_ECC_HW;
+-		nand_chip->ecc.size		= 512;
+-		nand_chip->ecc.bytes		= 13;
+-		nand_chip->ecc.strength		= 8;
+-		nand_chip->ecc.hwctl		= omap_enable_hwecc_bch;
+-		nand_chip->ecc.correct		= nand_bch_correct_data;
+-		nand_chip->ecc.calculate	= omap_calculate_ecc_bch_sw;
+-		mtd_set_ooblayout(mtd, &omap_sw_ooblayout_ops);
+-		/* Reserve one byte for the OMAP marker */
+-		oobbytes_per_step		= nand_chip->ecc.bytes + 1;
+-		/* software bch library is used for locating errors */
+-		nand_chip->ecc.priv		= nand_bch_init(mtd);
+-		if (!nand_chip->ecc.priv) {
+-			dev_err(&info->pdev->dev, "unable to use BCH library\n");
+-			err = -EINVAL;
+-			goto return_error;
+-		}
+-		break;
+-
+-	case OMAP_ECC_BCH8_CODE_HW:
+-		pr_info("nand: using OMAP_ECC_BCH8_CODE_HW ECC scheme\n");
+-		nand_chip->ecc.mode		= NAND_ECC_HW;
+-		nand_chip->ecc.size		= 512;
+-		/* 14th bit is kept reserved for ROM-code compatibility */
+-		nand_chip->ecc.bytes		= 13 + 1;
+-		nand_chip->ecc.strength		= 8;
+-		nand_chip->ecc.hwctl		= omap_enable_hwecc_bch;
+-		nand_chip->ecc.correct		= omap_elm_correct_data;
+-		nand_chip->ecc.read_page	= omap_read_page_bch;
+-		nand_chip->ecc.write_page	= omap_write_page_bch;
+-		nand_chip->ecc.write_subpage	= omap_write_subpage_bch;
+-		mtd_set_ooblayout(mtd, &omap_ooblayout_ops);
+-		oobbytes_per_step		= nand_chip->ecc.bytes;
+-
+-		err = elm_config(info->elm_dev, BCH8_ECC,
+-				 mtd->writesize / nand_chip->ecc.size,
+-				 nand_chip->ecc.size, nand_chip->ecc.bytes);
+-		if (err < 0)
+-			goto return_error;
+-
+-		break;
+-
+-	case OMAP_ECC_BCH16_CODE_HW:
+-		pr_info("using OMAP_ECC_BCH16_CODE_HW ECC scheme\n");
+-		nand_chip->ecc.mode		= NAND_ECC_HW;
+-		nand_chip->ecc.size		= 512;
+-		nand_chip->ecc.bytes		= 26;
+-		nand_chip->ecc.strength		= 16;
+-		nand_chip->ecc.hwctl		= omap_enable_hwecc_bch;
+-		nand_chip->ecc.correct		= omap_elm_correct_data;
+-		nand_chip->ecc.read_page	= omap_read_page_bch;
+-		nand_chip->ecc.write_page	= omap_write_page_bch;
+-		nand_chip->ecc.write_subpage	= omap_write_subpage_bch;
+-		mtd_set_ooblayout(mtd, &omap_ooblayout_ops);
+-		oobbytes_per_step		= nand_chip->ecc.bytes;
+-
+-		err = elm_config(info->elm_dev, BCH16_ECC,
+-				 mtd->writesize / nand_chip->ecc.size,
+-				 nand_chip->ecc.size, nand_chip->ecc.bytes);
+-		if (err < 0)
+-			goto return_error;
+-
+-		break;
+-	default:
+-		dev_err(&info->pdev->dev, "invalid or unsupported ECC scheme\n");
+-		err = -EINVAL;
+-		goto return_error;
+-	}
+-
+-	/* check if NAND device's OOB is enough to store ECC signatures */
+-	min_oobbytes += (oobbytes_per_step *
+-			 (mtd->writesize / nand_chip->ecc.size));
+-	if (mtd->oobsize < min_oobbytes) {
+-		dev_err(&info->pdev->dev,
+-			"not enough OOB bytes required = %d, available=%d\n",
+-			min_oobbytes, mtd->oobsize);
+-		err = -EINVAL;
+-		goto return_error;
+-	}
+-
+-scan_tail:
+-	/* second phase scan */
+-	err = nand_scan_tail(mtd);
+-	if (err)
+-		goto return_error;
+-
+-	if (dev->of_node)
+-		mtd_device_register(mtd, NULL, 0);
+-	else
+-		mtd_device_register(mtd, pdata->parts, pdata->nr_parts);
+-
+-	platform_set_drvdata(pdev, mtd);
+-
+-	return 0;
+-
+-return_error:
+-	if (!IS_ERR_OR_NULL(info->dma))
+-		dma_release_channel(info->dma);
+-	if (nand_chip->ecc.priv) {
+-		nand_bch_free(nand_chip->ecc.priv);
+-		nand_chip->ecc.priv = NULL;
+-	}
+-	return err;
+-}
+-
+-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 omap_nand_info *info = mtd_to_omap(mtd);
+-	if (nand_chip->ecc.priv) {
+-		nand_bch_free(nand_chip->ecc.priv);
+-		nand_chip->ecc.priv = NULL;
+-	}
+-	if (info->dma)
+-		dma_release_channel(info->dma);
+-	nand_release(mtd);
+-	return 0;
+-}
+-
+-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,
+-	.remove		= omap_nand_remove,
+-	.driver		= {
+-		.name	= DRIVER_NAME,
+-		.of_match_table = of_match_ptr(omap_nand_ids),
+-	},
+-};
+-
+-module_platform_driver(omap_nand_driver);
+-
+-MODULE_ALIAS("platform:" DRIVER_NAME);
+-MODULE_LICENSE("GPL");
+-MODULE_DESCRIPTION("Glue layer for NAND flash on TI OMAP boards");
+diff --git a/drivers/mtd/nand/omap_elm.c b/drivers/mtd/nand/omap_elm.c
+deleted file mode 100644
+index a3f32f9..0000000
+--- a/drivers/mtd/nand/omap_elm.c
++++ /dev/null
+@@ -1,578 +0,0 @@
+-/*
+- * Error Location Module
+- *
+- * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+- *
+- * 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.
+- *
+- */
+-
+-#define DRIVER_NAME	"omap-elm"
+-
+-#include <linux/platform_device.h>
+-#include <linux/module.h>
+-#include <linux/interrupt.h>
+-#include <linux/io.h>
+-#include <linux/of.h>
+-#include <linux/sched.h>
+-#include <linux/pm_runtime.h>
+-#include <linux/platform_data/elm.h>
+-
+-#define ELM_SYSCONFIG			0x010
+-#define ELM_IRQSTATUS			0x018
+-#define ELM_IRQENABLE			0x01c
+-#define ELM_LOCATION_CONFIG		0x020
+-#define ELM_PAGE_CTRL			0x080
+-#define ELM_SYNDROME_FRAGMENT_0		0x400
+-#define ELM_SYNDROME_FRAGMENT_1		0x404
+-#define ELM_SYNDROME_FRAGMENT_2		0x408
+-#define ELM_SYNDROME_FRAGMENT_3		0x40c
+-#define ELM_SYNDROME_FRAGMENT_4		0x410
+-#define ELM_SYNDROME_FRAGMENT_5		0x414
+-#define ELM_SYNDROME_FRAGMENT_6		0x418
+-#define ELM_LOCATION_STATUS		0x800
+-#define ELM_ERROR_LOCATION_0		0x880
+-
+-/* ELM Interrupt Status Register */
+-#define INTR_STATUS_PAGE_VALID		BIT(8)
+-
+-/* ELM Interrupt Enable Register */
+-#define INTR_EN_PAGE_MASK		BIT(8)
+-
+-/* ELM Location Configuration Register */
+-#define ECC_BCH_LEVEL_MASK		0x3
+-
+-/* ELM syndrome */
+-#define ELM_SYNDROME_VALID		BIT(16)
+-
+-/* ELM_LOCATION_STATUS Register */
+-#define ECC_CORRECTABLE_MASK		BIT(8)
+-#define ECC_NB_ERRORS_MASK		0x1f
+-
+-/* ELM_ERROR_LOCATION_0-15 Registers */
+-#define ECC_ERROR_LOCATION_MASK		0x1fff
+-
+-#define ELM_ECC_SIZE			0x7ff
+-
+-#define SYNDROME_FRAGMENT_REG_SIZE	0x40
+-#define ERROR_LOCATION_SIZE		0x100
+-
+-struct elm_registers {
+-	u32 elm_irqenable;
+-	u32 elm_sysconfig;
+-	u32 elm_location_config;
+-	u32 elm_page_ctrl;
+-	u32 elm_syndrome_fragment_6[ERROR_VECTOR_MAX];
+-	u32 elm_syndrome_fragment_5[ERROR_VECTOR_MAX];
+-	u32 elm_syndrome_fragment_4[ERROR_VECTOR_MAX];
+-	u32 elm_syndrome_fragment_3[ERROR_VECTOR_MAX];
+-	u32 elm_syndrome_fragment_2[ERROR_VECTOR_MAX];
+-	u32 elm_syndrome_fragment_1[ERROR_VECTOR_MAX];
+-	u32 elm_syndrome_fragment_0[ERROR_VECTOR_MAX];
+-};
+-
+-struct elm_info {
+-	struct device *dev;
+-	void __iomem *elm_base;
+-	struct completion elm_completion;
+-	struct list_head list;
+-	enum bch_ecc bch_type;
+-	struct elm_registers elm_regs;
+-	int ecc_steps;
+-	int ecc_syndrome_size;
+-};
+-
+-static LIST_HEAD(elm_devices);
+-
+-static void elm_write_reg(struct elm_info *info, int offset, u32 val)
+-{
+-	writel(val, info->elm_base + offset);
+-}
+-
+-static u32 elm_read_reg(struct elm_info *info, int offset)
+-{
+-	return readl(info->elm_base + offset);
+-}
+-
+-/**
+- * elm_config - Configure ELM module
+- * @dev:	ELM device
+- * @bch_type:	Type of BCH ecc
+- */
+-int elm_config(struct device *dev, enum bch_ecc bch_type,
+-	int ecc_steps, int ecc_step_size, int ecc_syndrome_size)
+-{
+-	u32 reg_val;
+-	struct elm_info *info = dev_get_drvdata(dev);
+-
+-	if (!info) {
+-		dev_err(dev, "Unable to configure elm - device not probed?\n");
+-		return -EPROBE_DEFER;
+-	}
+-	/* ELM cannot detect ECC errors for chunks > 1KB */
+-	if (ecc_step_size > ((ELM_ECC_SIZE + 1) / 2)) {
+-		dev_err(dev, "unsupported config ecc-size=%d\n", ecc_step_size);
+-		return -EINVAL;
+-	}
+-	/* ELM support 8 error syndrome process */
+-	if (ecc_steps > ERROR_VECTOR_MAX) {
+-		dev_err(dev, "unsupported config ecc-step=%d\n", ecc_steps);
+-		return -EINVAL;
+-	}
+-
+-	reg_val = (bch_type & ECC_BCH_LEVEL_MASK) | (ELM_ECC_SIZE << 16);
+-	elm_write_reg(info, ELM_LOCATION_CONFIG, reg_val);
+-	info->bch_type		= bch_type;
+-	info->ecc_steps		= ecc_steps;
+-	info->ecc_syndrome_size	= ecc_syndrome_size;
+-
+-	return 0;
+-}
+-EXPORT_SYMBOL(elm_config);
+-
+-/**
+- * elm_configure_page_mode - Enable/Disable page mode
+- * @info:	elm info
+- * @index:	index number of syndrome fragment vector
+- * @enable:	enable/disable flag for page mode
+- *
+- * Enable page mode for syndrome fragment index
+- */
+-static void elm_configure_page_mode(struct elm_info *info, int index,
+-		bool enable)
+-{
+-	u32 reg_val;
+-
+-	reg_val = elm_read_reg(info, ELM_PAGE_CTRL);
+-	if (enable)
+-		reg_val |= BIT(index);	/* enable page mode */
+-	else
+-		reg_val &= ~BIT(index);	/* disable page mode */
+-
+-	elm_write_reg(info, ELM_PAGE_CTRL, reg_val);
+-}
+-
+-/**
+- * elm_load_syndrome - Load ELM syndrome reg
+- * @info:	elm info
+- * @err_vec:	elm error vectors
+- * @ecc:	buffer with calculated ecc
+- *
+- * Load syndrome fragment registers with calculated ecc in reverse order.
+- */
+-static void elm_load_syndrome(struct elm_info *info,
+-		struct elm_errorvec *err_vec, u8 *ecc)
+-{
+-	int i, offset;
+-	u32 val;
+-
+-	for (i = 0; i < info->ecc_steps; i++) {
+-
+-		/* Check error reported */
+-		if (err_vec[i].error_reported) {
+-			elm_configure_page_mode(info, i, true);
+-			offset = ELM_SYNDROME_FRAGMENT_0 +
+-				SYNDROME_FRAGMENT_REG_SIZE * i;
+-			switch (info->bch_type) {
+-			case BCH8_ECC:
+-				/* syndrome fragment 0 = ecc[9-12B] */
+-				val = cpu_to_be32(*(u32 *) &ecc[9]);
+-				elm_write_reg(info, offset, val);
+-
+-				/* syndrome fragment 1 = ecc[5-8B] */
+-				offset += 4;
+-				val = cpu_to_be32(*(u32 *) &ecc[5]);
+-				elm_write_reg(info, offset, val);
+-
+-				/* syndrome fragment 2 = ecc[1-4B] */
+-				offset += 4;
+-				val = cpu_to_be32(*(u32 *) &ecc[1]);
+-				elm_write_reg(info, offset, val);
+-
+-				/* syndrome fragment 3 = ecc[0B] */
+-				offset += 4;
+-				val = ecc[0];
+-				elm_write_reg(info, offset, val);
+-				break;
+-			case BCH4_ECC:
+-				/* syndrome fragment 0 = ecc[20-52b] bits */
+-				val = (cpu_to_be32(*(u32 *) &ecc[3]) >> 4) |
+-					((ecc[2] & 0xf) << 28);
+-				elm_write_reg(info, offset, val);
+-
+-				/* syndrome fragment 1 = ecc[0-20b] bits */
+-				offset += 4;
+-				val = cpu_to_be32(*(u32 *) &ecc[0]) >> 12;
+-				elm_write_reg(info, offset, val);
+-				break;
+-			case BCH16_ECC:
+-				val = cpu_to_be32(*(u32 *) &ecc[22]);
+-				elm_write_reg(info, offset, val);
+-				offset += 4;
+-				val = cpu_to_be32(*(u32 *) &ecc[18]);
+-				elm_write_reg(info, offset, val);
+-				offset += 4;
+-				val = cpu_to_be32(*(u32 *) &ecc[14]);
+-				elm_write_reg(info, offset, val);
+-				offset += 4;
+-				val = cpu_to_be32(*(u32 *) &ecc[10]);
+-				elm_write_reg(info, offset, val);
+-				offset += 4;
+-				val = cpu_to_be32(*(u32 *) &ecc[6]);
+-				elm_write_reg(info, offset, val);
+-				offset += 4;
+-				val = cpu_to_be32(*(u32 *) &ecc[2]);
+-				elm_write_reg(info, offset, val);
+-				offset += 4;
+-				val = cpu_to_be32(*(u32 *) &ecc[0]) >> 16;
+-				elm_write_reg(info, offset, val);
+-				break;
+-			default:
+-				pr_err("invalid config bch_type\n");
+-			}
+-		}
+-
+-		/* Update ecc pointer with ecc byte size */
+-		ecc += info->ecc_syndrome_size;
+-	}
+-}
+-
+-/**
+- * elm_start_processing - start elm syndrome processing
+- * @info:	elm info
+- * @err_vec:	elm error vectors
+- *
+- * Set syndrome valid bit for syndrome fragment registers for which
+- * elm syndrome fragment registers are loaded. This enables elm module
+- * to start processing syndrome vectors.
+- */
+-static void elm_start_processing(struct elm_info *info,
+-		struct elm_errorvec *err_vec)
+-{
+-	int i, offset;
+-	u32 reg_val;
+-
+-	/*
+-	 * Set syndrome vector valid, so that ELM module
+-	 * will process it for vectors error is reported
+-	 */
+-	for (i = 0; i < info->ecc_steps; i++) {
+-		if (err_vec[i].error_reported) {
+-			offset = ELM_SYNDROME_FRAGMENT_6 +
+-				SYNDROME_FRAGMENT_REG_SIZE * i;
+-			reg_val = elm_read_reg(info, offset);
+-			reg_val |= ELM_SYNDROME_VALID;
+-			elm_write_reg(info, offset, reg_val);
+-		}
+-	}
+-}
+-
+-/**
+- * elm_error_correction - locate correctable error position
+- * @info:	elm info
+- * @err_vec:	elm error vectors
+- *
+- * On completion of processing by elm module, error location status
+- * register updated with correctable/uncorrectable error information.
+- * In case of correctable errors, number of errors located from
+- * elm location status register & read the positions from
+- * elm error location register.
+- */
+-static void elm_error_correction(struct elm_info *info,
+-		struct elm_errorvec *err_vec)
+-{
+-	int i, j, errors = 0;
+-	int offset;
+-	u32 reg_val;
+-
+-	for (i = 0; i < info->ecc_steps; i++) {
+-
+-		/* Check error reported */
+-		if (err_vec[i].error_reported) {
+-			offset = ELM_LOCATION_STATUS + ERROR_LOCATION_SIZE * i;
+-			reg_val = elm_read_reg(info, offset);
+-
+-			/* Check correctable error or not */
+-			if (reg_val & ECC_CORRECTABLE_MASK) {
+-				offset = ELM_ERROR_LOCATION_0 +
+-					ERROR_LOCATION_SIZE * i;
+-
+-				/* Read count of correctable errors */
+-				err_vec[i].error_count = reg_val &
+-					ECC_NB_ERRORS_MASK;
+-
+-				/* Update the error locations in error vector */
+-				for (j = 0; j < err_vec[i].error_count; j++) {
+-
+-					reg_val = elm_read_reg(info, offset);
+-					err_vec[i].error_loc[j] = reg_val &
+-						ECC_ERROR_LOCATION_MASK;
+-
+-					/* Update error location register */
+-					offset += 4;
+-				}
+-
+-				errors += err_vec[i].error_count;
+-			} else {
+-				err_vec[i].error_uncorrectable = true;
+-			}
+-
+-			/* Clearing interrupts for processed error vectors */
+-			elm_write_reg(info, ELM_IRQSTATUS, BIT(i));
+-
+-			/* Disable page mode */
+-			elm_configure_page_mode(info, i, false);
+-		}
+-	}
+-}
+-
+-/**
+- * elm_decode_bch_error_page - Locate error position
+- * @dev:	device pointer
+- * @ecc_calc:	calculated ECC bytes from GPMC
+- * @err_vec:	elm error vectors
+- *
+- * Called with one or more error reported vectors & vectors with
+- * error reported is updated in err_vec[].error_reported
+- */
+-void elm_decode_bch_error_page(struct device *dev, u8 *ecc_calc,
+-		struct elm_errorvec *err_vec)
+-{
+-	struct elm_info *info = dev_get_drvdata(dev);
+-	u32 reg_val;
+-
+-	/* Enable page mode interrupt */
+-	reg_val = elm_read_reg(info, ELM_IRQSTATUS);
+-	elm_write_reg(info, ELM_IRQSTATUS, reg_val & INTR_STATUS_PAGE_VALID);
+-	elm_write_reg(info, ELM_IRQENABLE, INTR_EN_PAGE_MASK);
+-
+-	/* Load valid ecc byte to syndrome fragment register */
+-	elm_load_syndrome(info, err_vec, ecc_calc);
+-
+-	/* Enable syndrome processing for which syndrome fragment is updated */
+-	elm_start_processing(info, err_vec);
+-
+-	/* Wait for ELM module to finish locating error correction */
+-	wait_for_completion(&info->elm_completion);
+-
+-	/* Disable page mode interrupt */
+-	reg_val = elm_read_reg(info, ELM_IRQENABLE);
+-	elm_write_reg(info, ELM_IRQENABLE, reg_val & ~INTR_EN_PAGE_MASK);
+-	elm_error_correction(info, err_vec);
+-}
+-EXPORT_SYMBOL(elm_decode_bch_error_page);
+-
+-static irqreturn_t elm_isr(int this_irq, void *dev_id)
+-{
+-	u32 reg_val;
+-	struct elm_info *info = dev_id;
+-
+-	reg_val = elm_read_reg(info, ELM_IRQSTATUS);
+-
+-	/* All error vectors processed */
+-	if (reg_val & INTR_STATUS_PAGE_VALID) {
+-		elm_write_reg(info, ELM_IRQSTATUS,
+-				reg_val & INTR_STATUS_PAGE_VALID);
+-		complete(&info->elm_completion);
+-		return IRQ_HANDLED;
+-	}
+-
+-	return IRQ_NONE;
+-}
+-
+-static int elm_probe(struct platform_device *pdev)
+-{
+-	int ret = 0;
+-	struct resource *res, *irq;
+-	struct elm_info *info;
+-
+-	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
+-	if (!info)
+-		return -ENOMEM;
+-
+-	info->dev = &pdev->dev;
+-
+-	irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+-	if (!irq) {
+-		dev_err(&pdev->dev, "no irq resource defined\n");
+-		return -ENODEV;
+-	}
+-
+-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+-	info->elm_base = devm_ioremap_resource(&pdev->dev, res);
+-	if (IS_ERR(info->elm_base))
+-		return PTR_ERR(info->elm_base);
+-
+-	ret = devm_request_irq(&pdev->dev, irq->start, elm_isr, 0,
+-			pdev->name, info);
+-	if (ret) {
+-		dev_err(&pdev->dev, "failure requesting %pr\n", irq);
+-		return ret;
+-	}
+-
+-	pm_runtime_enable(&pdev->dev);
+-	if (pm_runtime_get_sync(&pdev->dev) < 0) {
+-		ret = -EINVAL;
+-		pm_runtime_disable(&pdev->dev);
+-		dev_err(&pdev->dev, "can't enable clock\n");
+-		return ret;
+-	}
+-
+-	init_completion(&info->elm_completion);
+-	INIT_LIST_HEAD(&info->list);
+-	list_add(&info->list, &elm_devices);
+-	platform_set_drvdata(pdev, info);
+-	return ret;
+-}
+-
+-static int elm_remove(struct platform_device *pdev)
+-{
+-	pm_runtime_put_sync(&pdev->dev);
+-	pm_runtime_disable(&pdev->dev);
+-	return 0;
+-}
+-
+-#ifdef CONFIG_PM_SLEEP
+-/**
+- * elm_context_save
+- * saves ELM configurations to preserve them across Hardware powered-down
+- */
+-static int elm_context_save(struct elm_info *info)
+-{
+-	struct elm_registers *regs = &info->elm_regs;
+-	enum bch_ecc bch_type = info->bch_type;
+-	u32 offset = 0, i;
+-
+-	regs->elm_irqenable       = elm_read_reg(info, ELM_IRQENABLE);
+-	regs->elm_sysconfig       = elm_read_reg(info, ELM_SYSCONFIG);
+-	regs->elm_location_config = elm_read_reg(info, ELM_LOCATION_CONFIG);
+-	regs->elm_page_ctrl       = elm_read_reg(info, ELM_PAGE_CTRL);
+-	for (i = 0; i < ERROR_VECTOR_MAX; i++) {
+-		offset = i * SYNDROME_FRAGMENT_REG_SIZE;
+-		switch (bch_type) {
+-		case BCH16_ECC:
+-			regs->elm_syndrome_fragment_6[i] = elm_read_reg(info,
+-					ELM_SYNDROME_FRAGMENT_6 + offset);
+-			regs->elm_syndrome_fragment_5[i] = elm_read_reg(info,
+-					ELM_SYNDROME_FRAGMENT_5 + offset);
+-			regs->elm_syndrome_fragment_4[i] = elm_read_reg(info,
+-					ELM_SYNDROME_FRAGMENT_4 + offset);
+-		case BCH8_ECC:
+-			regs->elm_syndrome_fragment_3[i] = elm_read_reg(info,
+-					ELM_SYNDROME_FRAGMENT_3 + offset);
+-			regs->elm_syndrome_fragment_2[i] = elm_read_reg(info,
+-					ELM_SYNDROME_FRAGMENT_2 + offset);
+-		case BCH4_ECC:
+-			regs->elm_syndrome_fragment_1[i] = elm_read_reg(info,
+-					ELM_SYNDROME_FRAGMENT_1 + offset);
+-			regs->elm_syndrome_fragment_0[i] = elm_read_reg(info,
+-					ELM_SYNDROME_FRAGMENT_0 + offset);
+-			break;
+-		default:
+-			return -EINVAL;
+-		}
+-		/* ELM SYNDROME_VALID bit in SYNDROME_FRAGMENT_6[] needs
+-		 * to be saved for all BCH schemes*/
+-		regs->elm_syndrome_fragment_6[i] = elm_read_reg(info,
+-					ELM_SYNDROME_FRAGMENT_6 + offset);
+-	}
+-	return 0;
+-}
+-
+-/**
+- * elm_context_restore
+- * writes configurations saved duing power-down back into ELM registers
+- */
+-static int elm_context_restore(struct elm_info *info)
+-{
+-	struct elm_registers *regs = &info->elm_regs;
+-	enum bch_ecc bch_type = info->bch_type;
+-	u32 offset = 0, i;
+-
+-	elm_write_reg(info, ELM_IRQENABLE,	 regs->elm_irqenable);
+-	elm_write_reg(info, ELM_SYSCONFIG,	 regs->elm_sysconfig);
+-	elm_write_reg(info, ELM_LOCATION_CONFIG, regs->elm_location_config);
+-	elm_write_reg(info, ELM_PAGE_CTRL,	 regs->elm_page_ctrl);
+-	for (i = 0; i < ERROR_VECTOR_MAX; i++) {
+-		offset = i * SYNDROME_FRAGMENT_REG_SIZE;
+-		switch (bch_type) {
+-		case BCH16_ECC:
+-			elm_write_reg(info, ELM_SYNDROME_FRAGMENT_6 + offset,
+-					regs->elm_syndrome_fragment_6[i]);
+-			elm_write_reg(info, ELM_SYNDROME_FRAGMENT_5 + offset,
+-					regs->elm_syndrome_fragment_5[i]);
+-			elm_write_reg(info, ELM_SYNDROME_FRAGMENT_4 + offset,
+-					regs->elm_syndrome_fragment_4[i]);
+-		case BCH8_ECC:
+-			elm_write_reg(info, ELM_SYNDROME_FRAGMENT_3 + offset,
+-					regs->elm_syndrome_fragment_3[i]);
+-			elm_write_reg(info, ELM_SYNDROME_FRAGMENT_2 + offset,
+-					regs->elm_syndrome_fragment_2[i]);
+-		case BCH4_ECC:
+-			elm_write_reg(info, ELM_SYNDROME_FRAGMENT_1 + offset,
+-					regs->elm_syndrome_fragment_1[i]);
+-			elm_write_reg(info, ELM_SYNDROME_FRAGMENT_0 + offset,
+-					regs->elm_syndrome_fragment_0[i]);
+-			break;
+-		default:
+-			return -EINVAL;
+-		}
+-		/* ELM_SYNDROME_VALID bit to be set in last to trigger FSM */
+-		elm_write_reg(info, ELM_SYNDROME_FRAGMENT_6 + offset,
+-					regs->elm_syndrome_fragment_6[i] &
+-							 ELM_SYNDROME_VALID);
+-	}
+-	return 0;
+-}
+-
+-static int elm_suspend(struct device *dev)
+-{
+-	struct elm_info *info = dev_get_drvdata(dev);
+-	elm_context_save(info);
+-	pm_runtime_put_sync(dev);
+-	return 0;
+-}
+-
+-static int elm_resume(struct device *dev)
+-{
+-	struct elm_info *info = dev_get_drvdata(dev);
+-	pm_runtime_get_sync(dev);
+-	elm_context_restore(info);
+-	return 0;
+-}
+-#endif
+-
+-static SIMPLE_DEV_PM_OPS(elm_pm_ops, elm_suspend, elm_resume);
+-
+-#ifdef CONFIG_OF
+-static const struct of_device_id elm_of_match[] = {
+-	{ .compatible = "ti,am3352-elm" },
+-	{},
+-};
+-MODULE_DEVICE_TABLE(of, elm_of_match);
+-#endif
+-
+-static struct platform_driver elm_driver = {
+-	.driver	= {
+-		.name	= DRIVER_NAME,
+-		.of_match_table = of_match_ptr(elm_of_match),
+-		.pm	= &elm_pm_ops,
+-	},
+-	.probe	= elm_probe,
+-	.remove	= elm_remove,
+-};
+-
+-module_platform_driver(elm_driver);
+-
+-MODULE_DESCRIPTION("ELM driver for BCH error correction");
+-MODULE_AUTHOR("Texas Instruments");
+-MODULE_ALIAS("platform:" DRIVER_NAME);
+-MODULE_LICENSE("GPL v2");
+diff --git a/drivers/mtd/nand/orion_nand.c b/drivers/mtd/nand/orion_nand.c
+deleted file mode 100644
+index 5a5aa1f..0000000
+--- a/drivers/mtd/nand/orion_nand.c
++++ /dev/null
+@@ -1,234 +0,0 @@
+-/*
+- * drivers/mtd/nand/orion_nand.c
+- *
+- * NAND support for Marvell Orion SoC platforms
+- *
+- * Tzachi Perelstein <tzachi@marvell.com>
+- *
+- * This file is licensed under  the terms of the GNU General Public
+- * License version 2. This program is licensed "as is" without any
+- * warranty of any kind, whether express or implied.
+- */
+-
+-#include <linux/slab.h>
+-#include <linux/module.h>
+-#include <linux/platform_device.h>
+-#include <linux/of.h>
+-#include <linux/mtd/mtd.h>
+-#include <linux/mtd/rawnand.h>
+-#include <linux/mtd/partitions.h>
+-#include <linux/clk.h>
+-#include <linux/err.h>
+-#include <linux/io.h>
+-#include <asm/sizes.h>
+-#include <linux/platform_data/mtd-orion_nand.h>
+-
+-struct orion_nand_info {
+-	struct nand_chip chip;
+-	struct clk *clk;
+-};
+-
+-static void orion_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+-{
+-	struct nand_chip *nc = mtd_to_nand(mtd);
+-	struct orion_nand_data *board = nand_get_controller_data(nc);
+-	u32 offs;
+-
+-	if (cmd == NAND_CMD_NONE)
+-		return;
+-
+-	if (ctrl & NAND_CLE)
+-		offs = (1 << board->cle);
+-	else if (ctrl & NAND_ALE)
+-		offs = (1 << board->ale);
+-	else
+-		return;
+-
+-	if (nc->options & NAND_BUSWIDTH_16)
+-		offs <<= 1;
+-
+-	writeb(cmd, nc->IO_ADDR_W + offs);
+-}
+-
+-static void orion_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	void __iomem *io_base = chip->IO_ADDR_R;
+-#if __LINUX_ARM_ARCH__ >= 5
+-	uint64_t *buf64;
+-#endif
+-	int i = 0;
+-
+-	while (len && (unsigned long)buf & 7) {
+-		*buf++ = readb(io_base);
+-		len--;
+-	}
+-#if __LINUX_ARM_ARCH__ >= 5
+-	buf64 = (uint64_t *)buf;
+-	while (i < len/8) {
+-		/*
+-		 * Since GCC has no proper constraint (PR 43518)
+-		 * force x variable to r2/r3 registers as ldrd instruction
+-		 * requires first register to be even.
+-		 */
+-		register uint64_t x asm ("r2");
+-
+-		asm volatile ("ldrd\t%0, [%1]" : "=&r" (x) : "r" (io_base));
+-		buf64[i++] = x;
+-	}
+-	i *= 8;
+-#else
+-	readsl(io_base, buf, len/4);
+-	i = len / 4 * 4;
+-#endif
+-	while (i < len)
+-		buf[i++] = readb(io_base);
+-}
+-
+-static int __init orion_nand_probe(struct platform_device *pdev)
+-{
+-	struct orion_nand_info *info;
+-	struct mtd_info *mtd;
+-	struct nand_chip *nc;
+-	struct orion_nand_data *board;
+-	struct resource *res;
+-	void __iomem *io_base;
+-	int ret = 0;
+-	u32 val = 0;
+-
+-	info = devm_kzalloc(&pdev->dev,
+-			sizeof(struct orion_nand_info),
+-			GFP_KERNEL);
+-	if (!info)
+-		return -ENOMEM;
+-	nc = &info->chip;
+-	mtd = nand_to_mtd(nc);
+-
+-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+-	io_base = devm_ioremap_resource(&pdev->dev, res);
+-
+-	if (IS_ERR(io_base))
+-		return PTR_ERR(io_base);
+-
+-	if (pdev->dev.of_node) {
+-		board = devm_kzalloc(&pdev->dev, sizeof(struct orion_nand_data),
+-					GFP_KERNEL);
+-		if (!board)
+-			return -ENOMEM;
+-		if (!of_property_read_u32(pdev->dev.of_node, "cle", &val))
+-			board->cle = (u8)val;
+-		else
+-			board->cle = 0;
+-		if (!of_property_read_u32(pdev->dev.of_node, "ale", &val))
+-			board->ale = (u8)val;
+-		else
+-			board->ale = 1;
+-		if (!of_property_read_u32(pdev->dev.of_node,
+-						"bank-width", &val))
+-			board->width = (u8)val * 8;
+-		else
+-			board->width = 8;
+-		if (!of_property_read_u32(pdev->dev.of_node,
+-						"chip-delay", &val))
+-			board->chip_delay = (u8)val;
+-	} else {
+-		board = dev_get_platdata(&pdev->dev);
+-	}
+-
+-	mtd->dev.parent = &pdev->dev;
+-
+-	nand_set_controller_data(nc, board);
+-	nand_set_flash_node(nc, pdev->dev.of_node);
+-	nc->IO_ADDR_R = nc->IO_ADDR_W = io_base;
+-	nc->cmd_ctrl = orion_nand_cmd_ctrl;
+-	nc->read_buf = orion_nand_read_buf;
+-	nc->ecc.mode = NAND_ECC_SOFT;
+-	nc->ecc.algo = NAND_ECC_HAMMING;
+-
+-	if (board->chip_delay)
+-		nc->chip_delay = board->chip_delay;
+-
+-	WARN(board->width > 16,
+-		"%d bit bus width out of range",
+-		board->width);
+-
+-	if (board->width == 16)
+-		nc->options |= NAND_BUSWIDTH_16;
+-
+-	if (board->dev_ready)
+-		nc->dev_ready = board->dev_ready;
+-
+-	platform_set_drvdata(pdev, info);
+-
+-	/* Not all platforms can gate the clock, so it is not
+-	   an error if the clock does not exists. */
+-	info->clk = devm_clk_get(&pdev->dev, NULL);
+-	if (IS_ERR(info->clk)) {
+-		ret = PTR_ERR(info->clk);
+-		if (ret == -ENOENT) {
+-			info->clk = NULL;
+-		} else {
+-			dev_err(&pdev->dev, "failed to get clock!\n");
+-			return ret;
+-		}
+-	}
+-
+-	ret = clk_prepare_enable(info->clk);
+-	if (ret) {
+-		dev_err(&pdev->dev, "failed to prepare clock!\n");
+-		return ret;
+-	}
+-
+-	ret = nand_scan(mtd, 1);
+-	if (ret)
+-		goto no_dev;
+-
+-	mtd->name = "orion_nand";
+-	ret = mtd_device_register(mtd, board->parts, board->nr_parts);
+-	if (ret) {
+-		nand_release(mtd);
+-		goto no_dev;
+-	}
+-
+-	return 0;
+-
+-no_dev:
+-	clk_disable_unprepare(info->clk);
+-	return ret;
+-}
+-
+-static int orion_nand_remove(struct platform_device *pdev)
+-{
+-	struct orion_nand_info *info = platform_get_drvdata(pdev);
+-	struct nand_chip *chip = &info->chip;
+-	struct mtd_info *mtd = nand_to_mtd(chip);
+-
+-	nand_release(mtd);
+-
+-	clk_disable_unprepare(info->clk);
+-
+-	return 0;
+-}
+-
+-#ifdef CONFIG_OF
+-static const struct of_device_id orion_nand_of_match_table[] = {
+-	{ .compatible = "marvell,orion-nand", },
+-	{},
+-};
+-MODULE_DEVICE_TABLE(of, orion_nand_of_match_table);
+-#endif
+-
+-static struct platform_driver orion_nand_driver = {
+-	.remove		= orion_nand_remove,
+-	.driver		= {
+-		.name	= "orion_nand",
+-		.of_match_table = of_match_ptr(orion_nand_of_match_table),
+-	},
+-};
+-
+-module_platform_driver_probe(orion_nand_driver, orion_nand_probe);
+-
+-MODULE_LICENSE("GPL");
+-MODULE_AUTHOR("Tzachi Perelstein");
+-MODULE_DESCRIPTION("NAND glue for Orion platforms");
+-MODULE_ALIAS("platform:orion_nand");
+diff --git a/drivers/mtd/nand/oxnas_nand.c b/drivers/mtd/nand/oxnas_nand.c
+deleted file mode 100644
+index d649d59..0000000
+--- a/drivers/mtd/nand/oxnas_nand.c
++++ /dev/null
+@@ -1,206 +0,0 @@
+-/*
+- * Oxford Semiconductor OXNAS NAND driver
+-
+- * Copyright (C) 2016 Neil Armstrong <narmstrong@baylibre.com>
+- * Heavily based on plat_nand.c :
+- * Author: Vitaly Wool <vitalywool@gmail.com>
+- * Copyright (C) 2013 Ma Haijun <mahaijuns@gmail.com>
+- * Copyright (C) 2012 John Crispin <blogic@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/rawnand.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, u8 *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 u8 *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(*oxnas),
+-			     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;
+-
+-	err = clk_prepare_enable(oxnas->clk);
+-	if (err)
+-		return err;
+-
+-	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) {
+-			err = -ENOMEM;
+-			goto err_clk_unprepare;
+-		}
+-
+-		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)
+-			goto err_clk_unprepare;
+-
+-		err = mtd_device_register(mtd, NULL, 0);
+-		if (err) {
+-			nand_release(mtd);
+-			goto err_clk_unprepare;
+-		}
+-
+-		oxnas->chips[nchips] = chip;
+-		++nchips;
+-	}
+-
+-	/* Exit if no chips found */
+-	if (!nchips) {
+-		err = -ENODEV;
+-		goto err_clk_unprepare;
+-	}
+-
+-	platform_set_drvdata(pdev, oxnas);
+-
+-	return 0;
+-
+-err_clk_unprepare:
+-	clk_disable_unprepare(oxnas->clk);
+-	return err;
+-}
+-
+-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@baylibre.com>");
+-MODULE_DESCRIPTION("Oxnas NAND driver");
+-MODULE_ALIAS("platform:oxnas_nand");
+diff --git a/drivers/mtd/nand/pasemi_nand.c b/drivers/mtd/nand/pasemi_nand.c
+deleted file mode 100644
+index a47a7e4..0000000
+--- a/drivers/mtd/nand/pasemi_nand.c
++++ /dev/null
+@@ -1,232 +0,0 @@
+-/*
+- * Copyright (C) 2006-2007 PA Semi, Inc
+- *
+- * Author: Egor Martovetsky <egor@pasemi.com>
+- * Maintained by: Olof Johansson <olof@lixom.net>
+- *
+- * Driver for the PWRficient onchip NAND flash interface
+- *
+- * 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.
+- *
+- * You should have received a copy of the GNU General Public License
+- * along with this program; if not, write to the Free Software
+- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+- */
+-
+-#undef DEBUG
+-
+-#include <linux/slab.h>
+-#include <linux/module.h>
+-#include <linux/mtd/mtd.h>
+-#include <linux/mtd/rawnand.h>
+-#include <linux/mtd/nand_ecc.h>
+-#include <linux/of_address.h>
+-#include <linux/of_irq.h>
+-#include <linux/of_platform.h>
+-#include <linux/platform_device.h>
+-#include <linux/pci.h>
+-
+-#include <asm/io.h>
+-
+-#define LBICTRL_LPCCTL_NR		0x00004000
+-#define CLE_PIN_CTL			15
+-#define ALE_PIN_CTL			14
+-
+-static unsigned int lpcctl;
+-static struct mtd_info *pasemi_nand_mtd;
+-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);
+-
+-	while (len > 0x800) {
+-		memcpy_fromio(buf, chip->IO_ADDR_R, 0x800);
+-		buf += 0x800;
+-		len -= 0x800;
+-	}
+-	memcpy_fromio(buf, chip->IO_ADDR_R, len);
+-}
+-
+-static void pasemi_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-
+-	while (len > 0x800) {
+-		memcpy_toio(chip->IO_ADDR_R, buf, 0x800);
+-		buf += 0x800;
+-		len -= 0x800;
+-	}
+-	memcpy_toio(chip->IO_ADDR_R, buf, len);
+-}
+-
+-static void pasemi_hwcontrol(struct mtd_info *mtd, int cmd,
+-			     unsigned int ctrl)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-
+-	if (cmd == NAND_CMD_NONE)
+-		return;
+-
+-	if (ctrl & NAND_CLE)
+-		out_8(chip->IO_ADDR_W + (1 << CLE_PIN_CTL), cmd);
+-	else
+-		out_8(chip->IO_ADDR_W + (1 << ALE_PIN_CTL), cmd);
+-
+-	/* Push out posted writes */
+-	eieio();
+-	inl(lpcctl);
+-}
+-
+-int pasemi_device_ready(struct mtd_info *mtd)
+-{
+-	return !!(inl(lpcctl) & LBICTRL_LPCCTL_NR);
+-}
+-
+-static int pasemi_nand_probe(struct platform_device *ofdev)
+-{
+-	struct device *dev = &ofdev->dev;
+-	struct pci_dev *pdev;
+-	struct device_node *np = dev->of_node;
+-	struct resource res;
+-	struct nand_chip *chip;
+-	int err = 0;
+-
+-	err = of_address_to_resource(np, 0, &res);
+-
+-	if (err)
+-		return -EINVAL;
+-
+-	/* We only support one device at the moment */
+-	if (pasemi_nand_mtd)
+-		return -ENODEV;
+-
+-	dev_dbg(dev, "pasemi_nand at %pR\n", &res);
+-
+-	/* Allocate memory for MTD device structure and private data */
+-	chip = kzalloc(sizeof(struct nand_chip), GFP_KERNEL);
+-	if (!chip) {
+-		err = -ENOMEM;
+-		goto out;
+-	}
+-
+-	pasemi_nand_mtd = nand_to_mtd(chip);
+-
+-	/* Link the private data with the MTD structure */
+-	pasemi_nand_mtd->dev.parent = dev;
+-
+-	chip->IO_ADDR_R = of_iomap(np, 0);
+-	chip->IO_ADDR_W = chip->IO_ADDR_R;
+-
+-	if (!chip->IO_ADDR_R) {
+-		err = -EIO;
+-		goto out_mtd;
+-	}
+-
+-	pdev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa008, NULL);
+-	if (!pdev) {
+-		err = -ENODEV;
+-		goto out_ior;
+-	}
+-
+-	lpcctl = pci_resource_start(pdev, 0);
+-	pci_dev_put(pdev);
+-
+-	if (!request_region(lpcctl, 4, driver_name)) {
+-		err = -EBUSY;
+-		goto out_ior;
+-	}
+-
+-	chip->cmd_ctrl = pasemi_hwcontrol;
+-	chip->dev_ready = pasemi_device_ready;
+-	chip->read_buf = pasemi_read_buf;
+-	chip->write_buf = pasemi_write_buf;
+-	chip->chip_delay = 0;
+-	chip->ecc.mode = NAND_ECC_SOFT;
+-	chip->ecc.algo = NAND_ECC_HAMMING;
+-
+-	/* Enable the following for a flash based bad block table */
+-	chip->bbt_options = NAND_BBT_USE_FLASH;
+-
+-	/* Scan to find existence of the device */
+-	err = nand_scan(pasemi_nand_mtd, 1);
+-	if (err)
+-		goto out_lpc;
+-
+-	if (mtd_device_register(pasemi_nand_mtd, NULL, 0)) {
+-		dev_err(dev, "Unable to register MTD device\n");
+-		err = -ENODEV;
+-		goto out_lpc;
+-	}
+-
+-	dev_info(dev, "PA Semi NAND flash at %pR, control at I/O %x\n", &res,
+-		 lpcctl);
+-
+-	return 0;
+-
+- out_lpc:
+-	release_region(lpcctl, 4);
+- out_ior:
+-	iounmap(chip->IO_ADDR_R);
+- out_mtd:
+-	kfree(chip);
+- out:
+-	return err;
+-}
+-
+-static int pasemi_nand_remove(struct platform_device *ofdev)
+-{
+-	struct nand_chip *chip;
+-
+-	if (!pasemi_nand_mtd)
+-		return 0;
+-
+-	chip = mtd_to_nand(pasemi_nand_mtd);
+-
+-	/* Release resources, unregister device */
+-	nand_release(pasemi_nand_mtd);
+-
+-	release_region(lpcctl, 4);
+-
+-	iounmap(chip->IO_ADDR_R);
+-
+-	/* Free the MTD device structure */
+-	kfree(chip);
+-
+-	pasemi_nand_mtd = NULL;
+-
+-	return 0;
+-}
+-
+-static const struct of_device_id pasemi_nand_match[] =
+-{
+-	{
+-		.compatible   = "pasemi,localbus-nand",
+-	},
+-	{},
+-};
+-
+-MODULE_DEVICE_TABLE(of, pasemi_nand_match);
+-
+-static struct platform_driver pasemi_nand_driver =
+-{
+-	.driver = {
+-		.name = driver_name,
+-		.of_match_table = pasemi_nand_match,
+-	},
+-	.probe		= pasemi_nand_probe,
+-	.remove		= pasemi_nand_remove,
+-};
+-
+-module_platform_driver(pasemi_nand_driver);
+-
+-MODULE_LICENSE("GPL");
+-MODULE_AUTHOR("Egor Martovetsky <egor@pasemi.com>");
+-MODULE_DESCRIPTION("NAND flash interface driver for PA Semi PWRficient");
+diff --git a/drivers/mtd/nand/plat_nand.c b/drivers/mtd/nand/plat_nand.c
+deleted file mode 100644
+index 925a132..0000000
+--- a/drivers/mtd/nand/plat_nand.c
++++ /dev/null
+@@ -1,144 +0,0 @@
+-/*
+- * Generic NAND driver
+- *
+- * Author: Vitaly Wool <vitalywool@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/mtd/mtd.h>
+-#include <linux/mtd/rawnand.h>
+-#include <linux/mtd/partitions.h>
+-
+-struct plat_nand_data {
+-	struct nand_chip	chip;
+-	void __iomem		*io_base;
+-};
+-
+-/*
+- * Probe for the NAND device.
+- */
+-static int plat_nand_probe(struct platform_device *pdev)
+-{
+-	struct platform_nand_data *pdata = dev_get_platdata(&pdev->dev);
+-	struct plat_nand_data *data;
+-	struct mtd_info *mtd;
+-	struct resource *res;
+-	const char **part_types;
+-	int err = 0;
+-
+-	if (!pdata) {
+-		dev_err(&pdev->dev, "platform_nand_data is missing\n");
+-		return -EINVAL;
+-	}
+-
+-	if (pdata->chip.nr_chips < 1) {
+-		dev_err(&pdev->dev, "invalid number of chips specified\n");
+-		return -EINVAL;
+-	}
+-
+-	/* Allocate memory for the device structure (and zero it) */
+-	data = devm_kzalloc(&pdev->dev, sizeof(struct plat_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);
+-
+-	nand_set_flash_node(&data->chip, pdev->dev.of_node);
+-	mtd = nand_to_mtd(&data->chip);
+-	mtd->dev.parent = &pdev->dev;
+-
+-	data->chip.IO_ADDR_R = data->io_base;
+-	data->chip.IO_ADDR_W = data->io_base;
+-	data->chip.cmd_ctrl = pdata->ctrl.cmd_ctrl;
+-	data->chip.dev_ready = pdata->ctrl.dev_ready;
+-	data->chip.select_chip = pdata->ctrl.select_chip;
+-	data->chip.write_buf = pdata->ctrl.write_buf;
+-	data->chip.read_buf = pdata->ctrl.read_buf;
+-	data->chip.read_byte = pdata->ctrl.read_byte;
+-	data->chip.chip_delay = pdata->chip.chip_delay;
+-	data->chip.options |= pdata->chip.options;
+-	data->chip.bbt_options |= pdata->chip.bbt_options;
+-
+-	data->chip.ecc.hwctl = pdata->ctrl.hwcontrol;
+-	data->chip.ecc.mode = NAND_ECC_SOFT;
+-	data->chip.ecc.algo = NAND_ECC_HAMMING;
+-
+-	platform_set_drvdata(pdev, data);
+-
+-	/* Handle any platform specific setup */
+-	if (pdata->ctrl.probe) {
+-		err = pdata->ctrl.probe(pdev);
+-		if (err)
+-			goto out;
+-	}
+-
+-	/* Scan to find existence of the device */
+-	err = nand_scan(mtd, pdata->chip.nr_chips);
+-	if (err)
+-		goto out;
+-
+-	part_types = pdata->chip.part_probe_types;
+-
+-	err = mtd_device_parse_register(mtd, part_types, NULL,
+-					pdata->chip.partitions,
+-					pdata->chip.nr_partitions);
+-
+-	if (!err)
+-		return err;
+-
+-	nand_release(mtd);
+-out:
+-	if (pdata->ctrl.remove)
+-		pdata->ctrl.remove(pdev);
+-	return err;
+-}
+-
+-/*
+- * Remove a NAND device.
+- */
+-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));
+-	if (pdata->ctrl.remove)
+-		pdata->ctrl.remove(pdev);
+-
+-	return 0;
+-}
+-
+-static const struct of_device_id plat_nand_match[] = {
+-	{ .compatible = "gen_nand" },
+-	{},
+-};
+-MODULE_DEVICE_TABLE(of, plat_nand_match);
+-
+-static struct platform_driver plat_nand_driver = {
+-	.probe	= plat_nand_probe,
+-	.remove	= plat_nand_remove,
+-	.driver	= {
+-		.name		= "gen_nand",
+-		.of_match_table = plat_nand_match,
+-	},
+-};
+-
+-module_platform_driver(plat_nand_driver);
+-
+-MODULE_LICENSE("GPL");
+-MODULE_AUTHOR("Vitaly Wool");
+-MODULE_DESCRIPTION("Simple generic NAND driver");
+-MODULE_ALIAS("platform:gen_nand");
+diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
+deleted file mode 100644
+index 125b744..0000000
+--- a/drivers/mtd/nand/pxa3xx_nand.c
++++ /dev/null
+@@ -1,2074 +0,0 @@
+-/*
+- * drivers/mtd/nand/pxa3xx_nand.c
+- *
+- * Copyright © 2005 Intel Corporation
+- * Copyright © 2006 Marvell International Ltd.
+- *
+- * 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.
+- *
+- * See Documentation/mtd/nand/pxa3xx-nand.txt for more details.
+- */
+-
+-#include <linux/kernel.h>
+-#include <linux/module.h>
+-#include <linux/interrupt.h>
+-#include <linux/platform_device.h>
+-#include <linux/dmaengine.h>
+-#include <linux/dma-mapping.h>
+-#include <linux/dma/pxa-dma.h>
+-#include <linux/delay.h>
+-#include <linux/clk.h>
+-#include <linux/mtd/mtd.h>
+-#include <linux/mtd/rawnand.h>
+-#include <linux/mtd/partitions.h>
+-#include <linux/io.h>
+-#include <linux/iopoll.h>
+-#include <linux/irq.h>
+-#include <linux/slab.h>
+-#include <linux/of.h>
+-#include <linux/of_device.h>
+-#include <linux/platform_data/mtd-nand-pxa3xx.h>
+-
+-#define	CHIP_DELAY_TIMEOUT	msecs_to_jiffies(200)
+-#define NAND_STOP_DELAY		msecs_to_jiffies(40)
+-#define PAGE_CHUNK_SIZE		(2048)
+-
+-/*
+- * Define a buffer size for the initial command that detects the flash device:
+- * STATUS, READID and PARAM.
+- * ONFI param page is 256 bytes, and there are three redundant copies
+- * to be read. JEDEC param page is 512 bytes, and there are also three
+- * redundant copies to be read.
+- * Hence this buffer should be at least 512 x 3. Let's pick 2048.
+- */
+-#define INIT_BUFFER_SIZE	2048
+-
+-/* registers and bit definitions */
+-#define NDCR		(0x00) /* Control register */
+-#define NDTR0CS0	(0x04) /* Timing Parameter 0 for CS0 */
+-#define NDTR1CS0	(0x0C) /* Timing Parameter 1 for CS0 */
+-#define NDSR		(0x14) /* Status Register */
+-#define NDPCR		(0x18) /* Page Count Register */
+-#define NDBDR0		(0x1C) /* Bad Block Register 0 */
+-#define NDBDR1		(0x20) /* Bad Block Register 1 */
+-#define NDECCCTRL	(0x28) /* ECC control */
+-#define NDDB		(0x40) /* Data Buffer */
+-#define NDCB0		(0x48) /* Command Buffer0 */
+-#define NDCB1		(0x4C) /* Command Buffer1 */
+-#define NDCB2		(0x50) /* Command Buffer2 */
+-
+-#define NDCR_SPARE_EN		(0x1 << 31)
+-#define NDCR_ECC_EN		(0x1 << 30)
+-#define NDCR_DMA_EN		(0x1 << 29)
+-#define NDCR_ND_RUN		(0x1 << 28)
+-#define NDCR_DWIDTH_C		(0x1 << 27)
+-#define NDCR_DWIDTH_M		(0x1 << 26)
+-#define NDCR_PAGE_SZ		(0x1 << 24)
+-#define NDCR_NCSX		(0x1 << 23)
+-#define NDCR_ND_MODE		(0x3 << 21)
+-#define NDCR_NAND_MODE   	(0x0)
+-#define NDCR_CLR_PG_CNT		(0x1 << 20)
+-#define NFCV1_NDCR_ARB_CNTL	(0x1 << 19)
+-#define NFCV2_NDCR_STOP_ON_UNCOR	(0x1 << 19)
+-#define NDCR_RD_ID_CNT_MASK	(0x7 << 16)
+-#define NDCR_RD_ID_CNT(x)	(((x) << 16) & NDCR_RD_ID_CNT_MASK)
+-
+-#define NDCR_RA_START		(0x1 << 15)
+-#define NDCR_PG_PER_BLK		(0x1 << 14)
+-#define NDCR_ND_ARB_EN		(0x1 << 12)
+-#define NDCR_INT_MASK           (0xFFF)
+-
+-#define NDSR_MASK		(0xfff)
+-#define NDSR_ERR_CNT_OFF	(16)
+-#define NDSR_ERR_CNT_MASK       (0x1f)
+-#define NDSR_ERR_CNT(sr)	((sr >> NDSR_ERR_CNT_OFF) & NDSR_ERR_CNT_MASK)
+-#define NDSR_RDY                (0x1 << 12)
+-#define NDSR_FLASH_RDY          (0x1 << 11)
+-#define NDSR_CS0_PAGED		(0x1 << 10)
+-#define NDSR_CS1_PAGED		(0x1 << 9)
+-#define NDSR_CS0_CMDD		(0x1 << 8)
+-#define NDSR_CS1_CMDD		(0x1 << 7)
+-#define NDSR_CS0_BBD		(0x1 << 6)
+-#define NDSR_CS1_BBD		(0x1 << 5)
+-#define NDSR_UNCORERR		(0x1 << 4)
+-#define NDSR_CORERR		(0x1 << 3)
+-#define NDSR_WRDREQ		(0x1 << 2)
+-#define NDSR_RDDREQ		(0x1 << 1)
+-#define NDSR_WRCMDREQ		(0x1)
+-
+-#define NDCB0_LEN_OVRD		(0x1 << 28)
+-#define NDCB0_ST_ROW_EN         (0x1 << 26)
+-#define NDCB0_AUTO_RS		(0x1 << 25)
+-#define NDCB0_CSEL		(0x1 << 24)
+-#define NDCB0_EXT_CMD_TYPE_MASK	(0x7 << 29)
+-#define NDCB0_EXT_CMD_TYPE(x)	(((x) << 29) & NDCB0_EXT_CMD_TYPE_MASK)
+-#define NDCB0_CMD_TYPE_MASK	(0x7 << 21)
+-#define NDCB0_CMD_TYPE(x)	(((x) << 21) & NDCB0_CMD_TYPE_MASK)
+-#define NDCB0_NC		(0x1 << 20)
+-#define NDCB0_DBC		(0x1 << 19)
+-#define NDCB0_ADDR_CYC_MASK	(0x7 << 16)
+-#define NDCB0_ADDR_CYC(x)	(((x) << 16) & NDCB0_ADDR_CYC_MASK)
+-#define NDCB0_CMD2_MASK		(0xff << 8)
+-#define NDCB0_CMD1_MASK		(0xff)
+-#define NDCB0_ADDR_CYC_SHIFT	(16)
+-
+-#define EXT_CMD_TYPE_DISPATCH	6 /* Command dispatch */
+-#define EXT_CMD_TYPE_NAKED_RW	5 /* Naked read or Naked write */
+-#define EXT_CMD_TYPE_READ	4 /* Read */
+-#define EXT_CMD_TYPE_DISP_WR	4 /* Command dispatch with write */
+-#define EXT_CMD_TYPE_FINAL	3 /* Final command */
+-#define EXT_CMD_TYPE_LAST_RW	1 /* Last naked read/write */
+-#define EXT_CMD_TYPE_MONO	0 /* Monolithic read/write */
+-
+-/*
+- * This should be large enough to read 'ONFI' and 'JEDEC'.
+- * Let's use 7 bytes, which is the maximum ID count supported
+- * by the controller (see NDCR_RD_ID_CNT_MASK).
+- */
+-#define READ_ID_BYTES		7
+-
+-/* macros for registers read/write */
+-#define nand_writel(info, off, val)					\
+-	do {								\
+-		dev_vdbg(&info->pdev->dev,				\
+-			 "%s():%d nand_writel(0x%x, 0x%04x)\n",		\
+-			 __func__, __LINE__, (val), (off));		\
+-		writel_relaxed((val), (info)->mmio_base + (off));	\
+-	} while (0)
+-
+-#define nand_readl(info, off)						\
+-	({								\
+-		unsigned int _v;					\
+-		_v = readl_relaxed((info)->mmio_base + (off));		\
+-		dev_vdbg(&info->pdev->dev,				\
+-			 "%s():%d nand_readl(0x%04x) = 0x%x\n",		\
+-			 __func__, __LINE__, (off), _v);		\
+-		_v;							\
+-	})
+-
+-/* error code and state */
+-enum {
+-	ERR_NONE	= 0,
+-	ERR_DMABUSERR	= -1,
+-	ERR_SENDCMD	= -2,
+-	ERR_UNCORERR	= -3,
+-	ERR_BBERR	= -4,
+-	ERR_CORERR	= -5,
+-};
+-
+-enum {
+-	STATE_IDLE = 0,
+-	STATE_PREPARED,
+-	STATE_CMD_HANDLE,
+-	STATE_DMA_READING,
+-	STATE_DMA_WRITING,
+-	STATE_DMA_DONE,
+-	STATE_PIO_READING,
+-	STATE_PIO_WRITING,
+-	STATE_CMD_DONE,
+-	STATE_READY,
+-};
+-
+-enum pxa3xx_nand_variant {
+-	PXA3XX_NAND_VARIANT_PXA,
+-	PXA3XX_NAND_VARIANT_ARMADA370,
+-};
+-
+-struct pxa3xx_nand_host {
+-	struct nand_chip	chip;
+-	void			*info_data;
+-
+-	/* page size of attached chip */
+-	int			use_ecc;
+-	int			cs;
+-
+-	/* calculated from pxa3xx_nand_flash data */
+-	unsigned int		col_addr_cycles;
+-	unsigned int		row_addr_cycles;
+-};
+-
+-struct pxa3xx_nand_info {
+-	struct nand_hw_control	controller;
+-	struct platform_device	 *pdev;
+-
+-	struct clk		*clk;
+-	void __iomem		*mmio_base;
+-	unsigned long		mmio_phys;
+-	struct completion	cmd_complete, dev_ready;
+-
+-	unsigned int 		buf_start;
+-	unsigned int		buf_count;
+-	unsigned int		buf_size;
+-	unsigned int		data_buff_pos;
+-	unsigned int		oob_buff_pos;
+-
+-	/* DMA information */
+-	struct scatterlist	sg;
+-	enum dma_data_direction	dma_dir;
+-	struct dma_chan		*dma_chan;
+-	dma_cookie_t		dma_cookie;
+-	int			drcmr_dat;
+-
+-	unsigned char		*data_buff;
+-	unsigned char		*oob_buff;
+-	dma_addr_t 		data_buff_phys;
+-	int 			data_dma_ch;
+-
+-	struct pxa3xx_nand_host *host[NUM_CHIP_SELECT];
+-	unsigned int		state;
+-
+-	/*
+-	 * This driver supports NFCv1 (as found in PXA SoC)
+-	 * and NFCv2 (as found in Armada 370/XP SoC).
+-	 */
+-	enum pxa3xx_nand_variant variant;
+-
+-	int			cs;
+-	int			use_ecc;	/* use HW ECC ? */
+-	int			ecc_bch;	/* using BCH ECC? */
+-	int			use_dma;	/* use DMA ? */
+-	int			use_spare;	/* use spare ? */
+-	int			need_wait;
+-
+-	/* Amount of real data per full chunk */
+-	unsigned int		chunk_size;
+-
+-	/* Amount of spare data per full chunk */
+-	unsigned int		spare_size;
+-
+-	/* Number of full chunks (i.e chunk_size + spare_size) */
+-	unsigned int            nfullchunks;
+-
+-	/*
+-	 * Total number of chunks. If equal to nfullchunks, then there
+-	 * are only full chunks. Otherwise, there is one last chunk of
+-	 * size (last_chunk_size + last_spare_size)
+-	 */
+-	unsigned int            ntotalchunks;
+-
+-	/* Amount of real data in the last chunk */
+-	unsigned int		last_chunk_size;
+-
+-	/* Amount of spare data in the last chunk */
+-	unsigned int		last_spare_size;
+-
+-	unsigned int		ecc_size;
+-	unsigned int		ecc_err_cnt;
+-	unsigned int		max_bitflips;
+-	int 			retcode;
+-
+-	/*
+-	 * Variables only valid during command
+-	 * execution. step_chunk_size and step_spare_size is the
+-	 * amount of real data and spare data in the current
+-	 * chunk. cur_chunk is the current chunk being
+-	 * read/programmed.
+-	 */
+-	unsigned int		step_chunk_size;
+-	unsigned int		step_spare_size;
+-	unsigned int            cur_chunk;
+-
+-	/* cached register value */
+-	uint32_t		reg_ndcr;
+-	uint32_t		ndtr0cs0;
+-	uint32_t		ndtr1cs0;
+-
+-	/* generated NDCBx register values */
+-	uint32_t		ndcb0;
+-	uint32_t		ndcb1;
+-	uint32_t		ndcb2;
+-	uint32_t		ndcb3;
+-};
+-
+-static bool use_dma = 1;
+-module_param(use_dma, bool, 0444);
+-MODULE_PARM_DESC(use_dma, "enable DMA for data transferring to/from NAND HW");
+-
+-struct pxa3xx_nand_timing {
+-	unsigned int	tCH;  /* Enable signal hold time */
+-	unsigned int	tCS;  /* Enable signal setup time */
+-	unsigned int	tWH;  /* ND_nWE high duration */
+-	unsigned int	tWP;  /* ND_nWE pulse time */
+-	unsigned int	tRH;  /* ND_nRE high duration */
+-	unsigned int	tRP;  /* ND_nRE pulse width */
+-	unsigned int	tR;   /* ND_nWE high to ND_nRE low for read */
+-	unsigned int	tWHR; /* ND_nWE high to ND_nRE low for status read */
+-	unsigned int	tAR;  /* ND_ALE low to ND_nRE low delay */
+-};
+-
+-struct pxa3xx_nand_flash {
+-	uint32_t	chip_id;
+-	unsigned int	flash_width;	/* Width of Flash memory (DWIDTH_M) */
+-	unsigned int	dfc_width;	/* Width of flash controller(DWIDTH_C) */
+-	struct pxa3xx_nand_timing *timing;	/* NAND Flash timing */
+-};
+-
+-static struct pxa3xx_nand_timing timing[] = {
+-	{ 40, 80, 60, 100, 80, 100, 90000, 400, 40, },
+-	{ 10,  0, 20,  40, 30,  40, 11123, 110, 10, },
+-	{ 10, 25, 15,  25, 15,  30, 25000,  60, 10, },
+-	{ 10, 35, 15,  25, 15,  25, 25000,  60, 10, },
+-};
+-
+-static struct pxa3xx_nand_flash builtin_flash_types[] = {
+-	{ 0x46ec, 16, 16, &timing[1] },
+-	{ 0xdaec,  8,  8, &timing[1] },
+-	{ 0xd7ec,  8,  8, &timing[1] },
+-	{ 0xa12c,  8,  8, &timing[2] },
+-	{ 0xb12c, 16, 16, &timing[2] },
+-	{ 0xdc2c,  8,  8, &timing[2] },
+-	{ 0xcc2c, 16, 16, &timing[2] },
+-	{ 0xba20, 16, 16, &timing[3] },
+-};
+-
+-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 pxa3xx_nand_host *host = nand_get_controller_data(chip);
+-	struct pxa3xx_nand_info *info = host->info_data;
+-	int nchunks = mtd->writesize / info->chunk_size;
+-
+-	if (section >= nchunks)
+-		return -ERANGE;
+-
+-	oobregion->offset = ((info->ecc_size + info->spare_size) * section) +
+-			    info->spare_size;
+-	oobregion->length = info->ecc_size;
+-
+-	return 0;
+-}
+-
+-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 pxa3xx_nand_host *host = nand_get_controller_data(chip);
+-	struct pxa3xx_nand_info *info = host->info_data;
+-	int nchunks = mtd->writesize / info->chunk_size;
+-
+-	if (section >= nchunks)
+-		return -ERANGE;
+-
+-	if (!info->spare_size)
+-		return 0;
+-
+-	oobregion->offset = section * (info->ecc_size + info->spare_size);
+-	oobregion->length = info->spare_size;
+-	if (!section) {
+-		/*
+-		 * Bootrom looks in bytes 0 & 5 for bad blocks for the
+-		 * 4KB page / 4bit BCH combination.
+-		 */
+-		if (mtd->writesize == 4096 && info->chunk_size == 2048) {
+-			oobregion->offset += 6;
+-			oobregion->length -= 6;
+-		} else {
+-			oobregion->offset += 2;
+-			oobregion->length -= 2;
+-		}
+-	}
+-
+-	return 0;
+-}
+-
+-static const struct mtd_ooblayout_ops pxa3xx_ooblayout_ops = {
+-	.ecc = pxa3xx_ooblayout_ecc,
+-	.free = pxa3xx_ooblayout_free,
+-};
+-
+-static u8 bbt_pattern[] = {'M', 'V', 'B', 'b', 't', '0' };
+-static u8 bbt_mirror_pattern[] = {'1', 't', 'b', 'B', 'V', 'M' };
+-
+-static struct nand_bbt_descr bbt_main_descr = {
+-	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
+-		| NAND_BBT_2BIT | NAND_BBT_VERSION,
+-	.offs =	8,
+-	.len = 6,
+-	.veroffs = 14,
+-	.maxblocks = 8,		/* Last 8 blocks in each chip */
+-	.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,
+-	.offs =	8,
+-	.len = 6,
+-	.veroffs = 14,
+-	.maxblocks = 8,		/* Last 8 blocks in each chip */
+-	.pattern = bbt_mirror_pattern
+-};
+-
+-#define NDTR0_tCH(c)	(min((c), 7) << 19)
+-#define NDTR0_tCS(c)	(min((c), 7) << 16)
+-#define NDTR0_tWH(c)	(min((c), 7) << 11)
+-#define NDTR0_tWP(c)	(min((c), 7) << 8)
+-#define NDTR0_tRH(c)	(min((c), 7) << 3)
+-#define NDTR0_tRP(c)	(min((c), 7) << 0)
+-
+-#define NDTR1_tR(c)	(min((c), 65535) << 16)
+-#define NDTR1_tWHR(c)	(min((c), 15) << 4)
+-#define NDTR1_tAR(c)	(min((c), 15) << 0)
+-
+-/* convert nano-seconds to nand flash controller clock cycles */
+-#define ns2cycle(ns, clk)	(int)((ns) * (clk / 1000000) / 1000)
+-
+-static const struct of_device_id pxa3xx_nand_dt_ids[] = {
+-	{
+-		.compatible = "marvell,pxa3xx-nand",
+-		.data       = (void *)PXA3XX_NAND_VARIANT_PXA,
+-	},
+-	{
+-		.compatible = "marvell,armada370-nand",
+-		.data       = (void *)PXA3XX_NAND_VARIANT_ARMADA370,
+-	},
+-	{}
+-};
+-MODULE_DEVICE_TABLE(of, pxa3xx_nand_dt_ids);
+-
+-static enum pxa3xx_nand_variant
+-pxa3xx_nand_get_variant(struct platform_device *pdev)
+-{
+-	const struct of_device_id *of_id =
+-			of_match_device(pxa3xx_nand_dt_ids, &pdev->dev);
+-	if (!of_id)
+-		return PXA3XX_NAND_VARIANT_PXA;
+-	return (enum pxa3xx_nand_variant)of_id->data;
+-}
+-
+-static void pxa3xx_nand_set_timing(struct pxa3xx_nand_host *host,
+-				   const struct pxa3xx_nand_timing *t)
+-{
+-	struct pxa3xx_nand_info *info = host->info_data;
+-	unsigned long nand_clk = clk_get_rate(info->clk);
+-	uint32_t ndtr0, ndtr1;
+-
+-	ndtr0 = NDTR0_tCH(ns2cycle(t->tCH, nand_clk)) |
+-		NDTR0_tCS(ns2cycle(t->tCS, nand_clk)) |
+-		NDTR0_tWH(ns2cycle(t->tWH, nand_clk)) |
+-		NDTR0_tWP(ns2cycle(t->tWP, nand_clk)) |
+-		NDTR0_tRH(ns2cycle(t->tRH, nand_clk)) |
+-		NDTR0_tRP(ns2cycle(t->tRP, nand_clk));
+-
+-	ndtr1 = NDTR1_tR(ns2cycle(t->tR, nand_clk)) |
+-		NDTR1_tWHR(ns2cycle(t->tWHR, nand_clk)) |
+-		NDTR1_tAR(ns2cycle(t->tAR, nand_clk));
+-
+-	info->ndtr0cs0 = ndtr0;
+-	info->ndtr1cs0 = ndtr1;
+-	nand_writel(info, NDTR0CS0, ndtr0);
+-	nand_writel(info, NDTR1CS0, ndtr1);
+-}
+-
+-static void pxa3xx_nand_set_sdr_timing(struct pxa3xx_nand_host *host,
+-				       const struct nand_sdr_timings *t)
+-{
+-	struct pxa3xx_nand_info *info = host->info_data;
+-	struct nand_chip *chip = &host->chip;
+-	unsigned long nand_clk = clk_get_rate(info->clk);
+-	uint32_t ndtr0, ndtr1;
+-
+-	u32 tCH_min = DIV_ROUND_UP(t->tCH_min, 1000);
+-	u32 tCS_min = DIV_ROUND_UP(t->tCS_min, 1000);
+-	u32 tWH_min = DIV_ROUND_UP(t->tWH_min, 1000);
+-	u32 tWP_min = DIV_ROUND_UP(t->tWC_min - t->tWH_min, 1000);
+-	u32 tREH_min = DIV_ROUND_UP(t->tREH_min, 1000);
+-	u32 tRP_min = DIV_ROUND_UP(t->tRC_min - t->tREH_min, 1000);
+-	u32 tR = chip->chip_delay * 1000;
+-	u32 tWHR_min = DIV_ROUND_UP(t->tWHR_min, 1000);
+-	u32 tAR_min = DIV_ROUND_UP(t->tAR_min, 1000);
+-
+-	/* fallback to a default value if tR = 0 */
+-	if (!tR)
+-		tR = 20000;
+-
+-	ndtr0 = NDTR0_tCH(ns2cycle(tCH_min, nand_clk)) |
+-		NDTR0_tCS(ns2cycle(tCS_min, nand_clk)) |
+-		NDTR0_tWH(ns2cycle(tWH_min, nand_clk)) |
+-		NDTR0_tWP(ns2cycle(tWP_min, nand_clk)) |
+-		NDTR0_tRH(ns2cycle(tREH_min, nand_clk)) |
+-		NDTR0_tRP(ns2cycle(tRP_min, nand_clk));
+-
+-	ndtr1 = NDTR1_tR(ns2cycle(tR, nand_clk)) |
+-		NDTR1_tWHR(ns2cycle(tWHR_min, nand_clk)) |
+-		NDTR1_tAR(ns2cycle(tAR_min, nand_clk));
+-
+-	info->ndtr0cs0 = ndtr0;
+-	info->ndtr1cs0 = ndtr1;
+-	nand_writel(info, NDTR0CS0, ndtr0);
+-	nand_writel(info, NDTR1CS0, ndtr1);
+-}
+-
+-static int pxa3xx_nand_init_timings_compat(struct pxa3xx_nand_host *host,
+-					   unsigned int *flash_width,
+-					   unsigned int *dfc_width)
+-{
+-	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);
+-	int i, id, ntypes;
+-
+-	ntypes = ARRAY_SIZE(builtin_flash_types);
+-
+-	chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
+-
+-	id = chip->read_byte(mtd);
+-	id |= chip->read_byte(mtd) << 0x8;
+-
+-	for (i = 0; i < ntypes; i++) {
+-		f = &builtin_flash_types[i];
+-
+-		if (f->chip_id == id)
+-			break;
+-	}
+-
+-	if (i == ntypes) {
+-		dev_err(&info->pdev->dev, "Error: timings not found\n");
+-		return -EINVAL;
+-	}
+-
+-	pxa3xx_nand_set_timing(host, f->timing);
+-
+-	*flash_width = f->flash_width;
+-	*dfc_width = f->dfc_width;
+-
+-	return 0;
+-}
+-
+-static int pxa3xx_nand_init_timings_onfi(struct pxa3xx_nand_host *host,
+-					 int mode)
+-{
+-	const struct nand_sdr_timings *timings;
+-
+-	mode = fls(mode) - 1;
+-	if (mode < 0)
+-		mode = 0;
+-
+-	timings = onfi_async_timing_mode_to_sdr_timings(mode);
+-	if (IS_ERR(timings))
+-		return PTR_ERR(timings);
+-
+-	pxa3xx_nand_set_sdr_timing(host, timings);
+-
+-	return 0;
+-}
+-
+-static int pxa3xx_nand_init(struct pxa3xx_nand_host *host)
+-{
+-	struct nand_chip *chip = &host->chip;
+-	struct pxa3xx_nand_info *info = host->info_data;
+-	unsigned int flash_width = 0, dfc_width = 0;
+-	int mode, err;
+-
+-	mode = onfi_get_async_timing_mode(chip);
+-	if (mode == ONFI_TIMING_MODE_UNKNOWN) {
+-		err = pxa3xx_nand_init_timings_compat(host, &flash_width,
+-						      &dfc_width);
+-		if (err)
+-			return err;
+-
+-		if (flash_width == 16) {
+-			info->reg_ndcr |= NDCR_DWIDTH_M;
+-			chip->options |= NAND_BUSWIDTH_16;
+-		}
+-
+-		info->reg_ndcr |= (dfc_width == 16) ? NDCR_DWIDTH_C : 0;
+-	} else {
+-		err = pxa3xx_nand_init_timings_onfi(host, mode);
+-		if (err)
+-			return err;
+-	}
+-
+-	return 0;
+-}
+-
+-/**
+- * NOTE: it is a must to set ND_RUN firstly, then write
+- * command buffer, otherwise, it does not work.
+- * We enable all the interrupt at the same time, and
+- * let pxa3xx_nand_irq to handle all logic.
+- */
+-static void pxa3xx_nand_start(struct pxa3xx_nand_info *info)
+-{
+-	uint32_t ndcr;
+-
+-	ndcr = info->reg_ndcr;
+-
+-	if (info->use_ecc) {
+-		ndcr |= NDCR_ECC_EN;
+-		if (info->ecc_bch)
+-			nand_writel(info, NDECCCTRL, 0x1);
+-	} else {
+-		ndcr &= ~NDCR_ECC_EN;
+-		if (info->ecc_bch)
+-			nand_writel(info, NDECCCTRL, 0x0);
+-	}
+-
+-	if (info->use_dma)
+-		ndcr |= NDCR_DMA_EN;
+-	else
+-		ndcr &= ~NDCR_DMA_EN;
+-
+-	if (info->use_spare)
+-		ndcr |= NDCR_SPARE_EN;
+-	else
+-		ndcr &= ~NDCR_SPARE_EN;
+-
+-	ndcr |= NDCR_ND_RUN;
+-
+-	/* clear status bits and run */
+-	nand_writel(info, NDSR, NDSR_MASK);
+-	nand_writel(info, NDCR, 0);
+-	nand_writel(info, NDCR, ndcr);
+-}
+-
+-static void pxa3xx_nand_stop(struct pxa3xx_nand_info *info)
+-{
+-	uint32_t ndcr;
+-	int timeout = NAND_STOP_DELAY;
+-
+-	/* wait RUN bit in NDCR become 0 */
+-	ndcr = nand_readl(info, NDCR);
+-	while ((ndcr & NDCR_ND_RUN) && (timeout-- > 0)) {
+-		ndcr = nand_readl(info, NDCR);
+-		udelay(1);
+-	}
+-
+-	if (timeout <= 0) {
+-		ndcr &= ~NDCR_ND_RUN;
+-		nand_writel(info, NDCR, ndcr);
+-	}
+-	if (info->dma_chan)
+-		dmaengine_terminate_all(info->dma_chan);
+-
+-	/* clear status bits */
+-	nand_writel(info, NDSR, NDSR_MASK);
+-}
+-
+-static void __maybe_unused
+-enable_int(struct pxa3xx_nand_info *info, uint32_t int_mask)
+-{
+-	uint32_t ndcr;
+-
+-	ndcr = nand_readl(info, NDCR);
+-	nand_writel(info, NDCR, ndcr & ~int_mask);
+-}
+-
+-static void disable_int(struct pxa3xx_nand_info *info, uint32_t int_mask)
+-{
+-	uint32_t ndcr;
+-
+-	ndcr = nand_readl(info, NDCR);
+-	nand_writel(info, NDCR, ndcr | int_mask);
+-}
+-
+-static void drain_fifo(struct pxa3xx_nand_info *info, void *data, int len)
+-{
+-	if (info->ecc_bch) {
+-		u32 val;
+-		int ret;
+-
+-		/*
+-		 * According to the datasheet, when reading from NDDB
+-		 * with BCH enabled, after each 32 bytes reads, we
+-		 * have to make sure that the NDSR.RDDREQ bit is set.
+-		 *
+-		 * Drain the FIFO 8 32 bits reads at a time, and skip
+-		 * the polling on the last read.
+-		 */
+-		while (len > 8) {
+-			ioread32_rep(info->mmio_base + NDDB, data, 8);
+-
+-			ret = readl_relaxed_poll_timeout(info->mmio_base + NDSR, val,
+-							 val & NDSR_RDDREQ, 1000, 5000);
+-			if (ret) {
+-				dev_err(&info->pdev->dev,
+-					"Timeout on RDDREQ while draining the FIFO\n");
+-				return;
+-			}
+-
+-			data += 32;
+-			len -= 8;
+-		}
+-	}
+-
+-	ioread32_rep(info->mmio_base + NDDB, data, len);
+-}
+-
+-static void handle_data_pio(struct pxa3xx_nand_info *info)
+-{
+-	switch (info->state) {
+-	case STATE_PIO_WRITING:
+-		if (info->step_chunk_size)
+-			writesl(info->mmio_base + NDDB,
+-				info->data_buff + info->data_buff_pos,
+-				DIV_ROUND_UP(info->step_chunk_size, 4));
+-
+-		if (info->step_spare_size)
+-			writesl(info->mmio_base + NDDB,
+-				info->oob_buff + info->oob_buff_pos,
+-				DIV_ROUND_UP(info->step_spare_size, 4));
+-		break;
+-	case STATE_PIO_READING:
+-		if (info->step_chunk_size)
+-			drain_fifo(info,
+-				   info->data_buff + info->data_buff_pos,
+-				   DIV_ROUND_UP(info->step_chunk_size, 4));
+-
+-		if (info->step_spare_size)
+-			drain_fifo(info,
+-				   info->oob_buff + info->oob_buff_pos,
+-				   DIV_ROUND_UP(info->step_spare_size, 4));
+-		break;
+-	default:
+-		dev_err(&info->pdev->dev, "%s: invalid state %d\n", __func__,
+-				info->state);
+-		BUG();
+-	}
+-
+-	/* Update buffer pointers for multi-page read/write */
+-	info->data_buff_pos += info->step_chunk_size;
+-	info->oob_buff_pos += info->step_spare_size;
+-}
+-
+-static void pxa3xx_nand_data_dma_irq(void *data)
+-{
+-	struct pxa3xx_nand_info *info = data;
+-	struct dma_tx_state state;
+-	enum dma_status status;
+-
+-	status = dmaengine_tx_status(info->dma_chan, info->dma_cookie, &state);
+-	if (likely(status == DMA_COMPLETE)) {
+-		info->state = STATE_DMA_DONE;
+-	} else {
+-		dev_err(&info->pdev->dev, "DMA error on data channel\n");
+-		info->retcode = ERR_DMABUSERR;
+-	}
+-	dma_unmap_sg(info->dma_chan->device->dev, &info->sg, 1, info->dma_dir);
+-
+-	nand_writel(info, NDSR, NDSR_WRDREQ | NDSR_RDDREQ);
+-	enable_int(info, NDCR_INT_MASK);
+-}
+-
+-static void start_data_dma(struct pxa3xx_nand_info *info)
+-{
+-	enum dma_transfer_direction direction;
+-	struct dma_async_tx_descriptor *tx;
+-
+-	switch (info->state) {
+-	case STATE_DMA_WRITING:
+-		info->dma_dir = DMA_TO_DEVICE;
+-		direction = DMA_MEM_TO_DEV;
+-		break;
+-	case STATE_DMA_READING:
+-		info->dma_dir = DMA_FROM_DEVICE;
+-		direction = DMA_DEV_TO_MEM;
+-		break;
+-	default:
+-		dev_err(&info->pdev->dev, "%s: invalid state %d\n", __func__,
+-				info->state);
+-		BUG();
+-	}
+-	info->sg.length = info->chunk_size;
+-	if (info->use_spare)
+-		info->sg.length += info->spare_size + info->ecc_size;
+-	dma_map_sg(info->dma_chan->device->dev, &info->sg, 1, info->dma_dir);
+-
+-	tx = dmaengine_prep_slave_sg(info->dma_chan, &info->sg, 1, direction,
+-				     DMA_PREP_INTERRUPT);
+-	if (!tx) {
+-		dev_err(&info->pdev->dev, "prep_slave_sg() failed\n");
+-		return;
+-	}
+-	tx->callback = pxa3xx_nand_data_dma_irq;
+-	tx->callback_param = info;
+-	info->dma_cookie = dmaengine_submit(tx);
+-	dma_async_issue_pending(info->dma_chan);
+-	dev_dbg(&info->pdev->dev, "%s(dir=%d cookie=%x size=%u)\n",
+-		__func__, direction, info->dma_cookie, info->sg.length);
+-}
+-
+-static irqreturn_t pxa3xx_nand_irq_thread(int irq, void *data)
+-{
+-	struct pxa3xx_nand_info *info = data;
+-
+-	handle_data_pio(info);
+-
+-	info->state = STATE_CMD_DONE;
+-	nand_writel(info, NDSR, NDSR_WRDREQ | NDSR_RDDREQ);
+-
+-	return IRQ_HANDLED;
+-}
+-
+-static irqreturn_t pxa3xx_nand_irq(int irq, void *devid)
+-{
+-	struct pxa3xx_nand_info *info = devid;
+-	unsigned int status, is_completed = 0, is_ready = 0;
+-	unsigned int ready, cmd_done;
+-	irqreturn_t ret = IRQ_HANDLED;
+-
+-	if (info->cs == 0) {
+-		ready           = NDSR_FLASH_RDY;
+-		cmd_done        = NDSR_CS0_CMDD;
+-	} else {
+-		ready           = NDSR_RDY;
+-		cmd_done        = NDSR_CS1_CMDD;
+-	}
+-
+-	status = nand_readl(info, NDSR);
+-
+-	if (status & NDSR_UNCORERR)
+-		info->retcode = ERR_UNCORERR;
+-	if (status & NDSR_CORERR) {
+-		info->retcode = ERR_CORERR;
+-		if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370 &&
+-		    info->ecc_bch)
+-			info->ecc_err_cnt = NDSR_ERR_CNT(status);
+-		else
+-			info->ecc_err_cnt = 1;
+-
+-		/*
+-		 * Each chunk composing a page is corrected independently,
+-		 * and we need to store maximum number of corrected bitflips
+-		 * to return it to the MTD layer in ecc.read_page().
+-		 */
+-		info->max_bitflips = max_t(unsigned int,
+-					   info->max_bitflips,
+-					   info->ecc_err_cnt);
+-	}
+-	if (status & (NDSR_RDDREQ | NDSR_WRDREQ)) {
+-		/* whether use dma to transfer data */
+-		if (info->use_dma) {
+-			disable_int(info, NDCR_INT_MASK);
+-			info->state = (status & NDSR_RDDREQ) ?
+-				      STATE_DMA_READING : STATE_DMA_WRITING;
+-			start_data_dma(info);
+-			goto NORMAL_IRQ_EXIT;
+-		} else {
+-			info->state = (status & NDSR_RDDREQ) ?
+-				      STATE_PIO_READING : STATE_PIO_WRITING;
+-			ret = IRQ_WAKE_THREAD;
+-			goto NORMAL_IRQ_EXIT;
+-		}
+-	}
+-	if (status & cmd_done) {
+-		info->state = STATE_CMD_DONE;
+-		is_completed = 1;
+-	}
+-	if (status & ready) {
+-		info->state = STATE_READY;
+-		is_ready = 1;
+-	}
+-
+-	/*
+-	 * Clear all status bit before issuing the next command, which
+-	 * can and will alter the status bits and will deserve a new
+-	 * interrupt on its own. This lets the controller exit the IRQ
+-	 */
+-	nand_writel(info, NDSR, status);
+-
+-	if (status & NDSR_WRCMDREQ) {
+-		status &= ~NDSR_WRCMDREQ;
+-		info->state = STATE_CMD_HANDLE;
+-
+-		/*
+-		 * Command buffer registers NDCB{0-2} (and optionally NDCB3)
+-		 * must be loaded by writing directly either 12 or 16
+-		 * bytes directly to NDCB0, four bytes at a time.
+-		 *
+-		 * Direct write access to NDCB1, NDCB2 and NDCB3 is ignored
+-		 * but each NDCBx register can be read.
+-		 */
+-		nand_writel(info, NDCB0, info->ndcb0);
+-		nand_writel(info, NDCB0, info->ndcb1);
+-		nand_writel(info, NDCB0, info->ndcb2);
+-
+-		/* NDCB3 register is available in NFCv2 (Armada 370/XP SoC) */
+-		if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370)
+-			nand_writel(info, NDCB0, info->ndcb3);
+-	}
+-
+-	if (is_completed)
+-		complete(&info->cmd_complete);
+-	if (is_ready)
+-		complete(&info->dev_ready);
+-NORMAL_IRQ_EXIT:
+-	return ret;
+-}
+-
+-static inline int is_buf_blank(uint8_t *buf, size_t len)
+-{
+-	for (; len > 0; len--)
+-		if (*buf++ != 0xff)
+-			return 0;
+-	return 1;
+-}
+-
+-static void set_command_address(struct pxa3xx_nand_info *info,
+-		unsigned int page_size, uint16_t column, int page_addr)
+-{
+-	/* small page addr setting */
+-	if (page_size < PAGE_CHUNK_SIZE) {
+-		info->ndcb1 = ((page_addr & 0xFFFFFF) << 8)
+-				| (column & 0xFF);
+-
+-		info->ndcb2 = 0;
+-	} else {
+-		info->ndcb1 = ((page_addr & 0xFFFF) << 16)
+-				| (column & 0xFFFF);
+-
+-		if (page_addr & 0xFF0000)
+-			info->ndcb2 = (page_addr & 0xFF0000) >> 16;
+-		else
+-			info->ndcb2 = 0;
+-	}
+-}
+-
+-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);
+-
+-	/* reset data and oob column point to handle data */
+-	info->buf_start		= 0;
+-	info->buf_count		= 0;
+-	info->data_buff_pos	= 0;
+-	info->oob_buff_pos	= 0;
+-	info->step_chunk_size   = 0;
+-	info->step_spare_size   = 0;
+-	info->cur_chunk         = 0;
+-	info->use_ecc		= 0;
+-	info->use_spare		= 1;
+-	info->retcode		= ERR_NONE;
+-	info->ecc_err_cnt	= 0;
+-	info->ndcb3		= 0;
+-	info->need_wait		= 0;
+-
+-	switch (command) {
+-	case NAND_CMD_READ0:
+-	case NAND_CMD_READOOB:
+-	case NAND_CMD_PAGEPROG:
+-		info->use_ecc = 1;
+-		break;
+-	case NAND_CMD_PARAM:
+-		info->use_spare = 0;
+-		break;
+-	default:
+-		info->ndcb1 = 0;
+-		info->ndcb2 = 0;
+-		break;
+-	}
+-
+-	/*
+-	 * If we are about to issue a read command, or about to set
+-	 * the write address, then clean the data buffer.
+-	 */
+-	if (command == NAND_CMD_READ0 ||
+-	    command == NAND_CMD_READOOB ||
+-	    command == NAND_CMD_SEQIN) {
+-
+-		info->buf_count = mtd->writesize + mtd->oobsize;
+-		memset(info->data_buff, 0xFF, info->buf_count);
+-	}
+-
+-}
+-
+-static int prepare_set_command(struct pxa3xx_nand_info *info, int command,
+-		int ext_cmd_type, uint16_t column, int page_addr)
+-{
+-	int addr_cycle, exec_cmd;
+-	struct pxa3xx_nand_host *host;
+-	struct mtd_info *mtd;
+-
+-	host = info->host[info->cs];
+-	mtd = nand_to_mtd(&host->chip);
+-	addr_cycle = 0;
+-	exec_cmd = 1;
+-
+-	if (info->cs != 0)
+-		info->ndcb0 = NDCB0_CSEL;
+-	else
+-		info->ndcb0 = 0;
+-
+-	if (command == NAND_CMD_SEQIN)
+-		exec_cmd = 0;
+-
+-	addr_cycle = NDCB0_ADDR_CYC(host->row_addr_cycles
+-				    + host->col_addr_cycles);
+-
+-	switch (command) {
+-	case NAND_CMD_READOOB:
+-	case NAND_CMD_READ0:
+-		info->buf_start = column;
+-		info->ndcb0 |= NDCB0_CMD_TYPE(0)
+-				| addr_cycle
+-				| NAND_CMD_READ0;
+-
+-		if (command == NAND_CMD_READOOB)
+-			info->buf_start += mtd->writesize;
+-
+-		if (info->cur_chunk < info->nfullchunks) {
+-			info->step_chunk_size = info->chunk_size;
+-			info->step_spare_size = info->spare_size;
+-		} else {
+-			info->step_chunk_size = info->last_chunk_size;
+-			info->step_spare_size = info->last_spare_size;
+-		}
+-
+-		/*
+-		 * Multiple page read needs an 'extended command type' field,
+-		 * which is either naked-read or last-read according to the
+-		 * state.
+-		 */
+-		if (mtd->writesize == PAGE_CHUNK_SIZE) {
+-			info->ndcb0 |= NDCB0_DBC | (NAND_CMD_READSTART << 8);
+-		} else if (mtd->writesize > PAGE_CHUNK_SIZE) {
+-			info->ndcb0 |= NDCB0_DBC | (NAND_CMD_READSTART << 8)
+-					| NDCB0_LEN_OVRD
+-					| NDCB0_EXT_CMD_TYPE(ext_cmd_type);
+-			info->ndcb3 = info->step_chunk_size +
+-				info->step_spare_size;
+-		}
+-
+-		set_command_address(info, mtd->writesize, column, page_addr);
+-		break;
+-
+-	case NAND_CMD_SEQIN:
+-
+-		info->buf_start = column;
+-		set_command_address(info, mtd->writesize, 0, page_addr);
+-
+-		/*
+-		 * Multiple page programming needs to execute the initial
+-		 * SEQIN command that sets the page address.
+-		 */
+-		if (mtd->writesize > PAGE_CHUNK_SIZE) {
+-			info->ndcb0 |= NDCB0_CMD_TYPE(0x1)
+-				| NDCB0_EXT_CMD_TYPE(ext_cmd_type)
+-				| addr_cycle
+-				| command;
+-			exec_cmd = 1;
+-		}
+-		break;
+-
+-	case NAND_CMD_PAGEPROG:
+-		if (is_buf_blank(info->data_buff,
+-					(mtd->writesize + mtd->oobsize))) {
+-			exec_cmd = 0;
+-			break;
+-		}
+-
+-		if (info->cur_chunk < info->nfullchunks) {
+-			info->step_chunk_size = info->chunk_size;
+-			info->step_spare_size = info->spare_size;
+-		} else {
+-			info->step_chunk_size = info->last_chunk_size;
+-			info->step_spare_size = info->last_spare_size;
+-		}
+-
+-		/* Second command setting for large pages */
+-		if (mtd->writesize > PAGE_CHUNK_SIZE) {
+-			/*
+-			 * Multiple page write uses the 'extended command'
+-			 * field. This can be used to issue a command dispatch
+-			 * or a naked-write depending on the current stage.
+-			 */
+-			info->ndcb0 |= NDCB0_CMD_TYPE(0x1)
+-					| NDCB0_LEN_OVRD
+-					| NDCB0_EXT_CMD_TYPE(ext_cmd_type);
+-			info->ndcb3 = info->step_chunk_size +
+-				      info->step_spare_size;
+-
+-			/*
+-			 * This is the command dispatch that completes a chunked
+-			 * page program operation.
+-			 */
+-			if (info->cur_chunk == info->ntotalchunks) {
+-				info->ndcb0 = NDCB0_CMD_TYPE(0x1)
+-					| NDCB0_EXT_CMD_TYPE(ext_cmd_type)
+-					| command;
+-				info->ndcb1 = 0;
+-				info->ndcb2 = 0;
+-				info->ndcb3 = 0;
+-			}
+-		} else {
+-			info->ndcb0 |= NDCB0_CMD_TYPE(0x1)
+-					| NDCB0_AUTO_RS
+-					| NDCB0_ST_ROW_EN
+-					| NDCB0_DBC
+-					| (NAND_CMD_PAGEPROG << 8)
+-					| NAND_CMD_SEQIN
+-					| addr_cycle;
+-		}
+-		break;
+-
+-	case NAND_CMD_PARAM:
+-		info->buf_count = INIT_BUFFER_SIZE;
+-		info->ndcb0 |= NDCB0_CMD_TYPE(0)
+-				| NDCB0_ADDR_CYC(1)
+-				| NDCB0_LEN_OVRD
+-				| command;
+-		info->ndcb1 = (column & 0xFF);
+-		info->ndcb3 = INIT_BUFFER_SIZE;
+-		info->step_chunk_size = INIT_BUFFER_SIZE;
+-		break;
+-
+-	case NAND_CMD_READID:
+-		info->buf_count = READ_ID_BYTES;
+-		info->ndcb0 |= NDCB0_CMD_TYPE(3)
+-				| NDCB0_ADDR_CYC(1)
+-				| command;
+-		info->ndcb1 = (column & 0xFF);
+-
+-		info->step_chunk_size = 8;
+-		break;
+-	case NAND_CMD_STATUS:
+-		info->buf_count = 1;
+-		info->ndcb0 |= NDCB0_CMD_TYPE(4)
+-				| NDCB0_ADDR_CYC(1)
+-				| command;
+-
+-		info->step_chunk_size = 8;
+-		break;
+-
+-	case NAND_CMD_ERASE1:
+-		info->ndcb0 |= NDCB0_CMD_TYPE(2)
+-				| NDCB0_AUTO_RS
+-				| NDCB0_ADDR_CYC(3)
+-				| NDCB0_DBC
+-				| (NAND_CMD_ERASE2 << 8)
+-				| NAND_CMD_ERASE1;
+-		info->ndcb1 = page_addr;
+-		info->ndcb2 = 0;
+-
+-		break;
+-	case NAND_CMD_RESET:
+-		info->ndcb0 |= NDCB0_CMD_TYPE(5)
+-				| command;
+-
+-		break;
+-
+-	case NAND_CMD_ERASE2:
+-		exec_cmd = 0;
+-		break;
+-
+-	default:
+-		exec_cmd = 0;
+-		dev_err(&info->pdev->dev, "non-supported command %x\n",
+-				command);
+-		break;
+-	}
+-
+-	return exec_cmd;
+-}
+-
+-static void nand_cmdfunc(struct mtd_info *mtd, unsigned command,
+-			 int column, int page_addr)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct pxa3xx_nand_host *host = nand_get_controller_data(chip);
+-	struct pxa3xx_nand_info *info = host->info_data;
+-	int exec_cmd;
+-
+-	/*
+-	 * if this is a x16 device ,then convert the input
+-	 * "byte" address into a "word" address appropriate
+-	 * for indexing a word-oriented device
+-	 */
+-	if (info->reg_ndcr & NDCR_DWIDTH_M)
+-		column /= 2;
+-
+-	/*
+-	 * There may be different NAND chip hooked to
+-	 * different chip select, so check whether
+-	 * chip select has been changed, if yes, reset the timing
+-	 */
+-	if (info->cs != host->cs) {
+-		info->cs = host->cs;
+-		nand_writel(info, NDTR0CS0, info->ndtr0cs0);
+-		nand_writel(info, NDTR1CS0, info->ndtr1cs0);
+-	}
+-
+-	prepare_start_command(info, command);
+-
+-	info->state = STATE_PREPARED;
+-	exec_cmd = prepare_set_command(info, command, 0, column, page_addr);
+-
+-	if (exec_cmd) {
+-		init_completion(&info->cmd_complete);
+-		init_completion(&info->dev_ready);
+-		info->need_wait = 1;
+-		pxa3xx_nand_start(info);
+-
+-		if (!wait_for_completion_timeout(&info->cmd_complete,
+-		    CHIP_DELAY_TIMEOUT)) {
+-			dev_err(&info->pdev->dev, "Wait time out!!!\n");
+-			/* Stop State Machine for next command cycle */
+-			pxa3xx_nand_stop(info);
+-		}
+-	}
+-	info->state = STATE_IDLE;
+-}
+-
+-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 pxa3xx_nand_host *host = nand_get_controller_data(chip);
+-	struct pxa3xx_nand_info *info = host->info_data;
+-	int exec_cmd, ext_cmd_type;
+-
+-	/*
+-	 * if this is a x16 device then convert the input
+-	 * "byte" address into a "word" address appropriate
+-	 * for indexing a word-oriented device
+-	 */
+-	if (info->reg_ndcr & NDCR_DWIDTH_M)
+-		column /= 2;
+-
+-	/*
+-	 * There may be different NAND chip hooked to
+-	 * different chip select, so check whether
+-	 * chip select has been changed, if yes, reset the timing
+-	 */
+-	if (info->cs != host->cs) {
+-		info->cs = host->cs;
+-		nand_writel(info, NDTR0CS0, info->ndtr0cs0);
+-		nand_writel(info, NDTR1CS0, info->ndtr1cs0);
+-	}
+-
+-	/* Select the extended command for the first command */
+-	switch (command) {
+-	case NAND_CMD_READ0:
+-	case NAND_CMD_READOOB:
+-		ext_cmd_type = EXT_CMD_TYPE_MONO;
+-		break;
+-	case NAND_CMD_SEQIN:
+-		ext_cmd_type = EXT_CMD_TYPE_DISPATCH;
+-		break;
+-	case NAND_CMD_PAGEPROG:
+-		ext_cmd_type = EXT_CMD_TYPE_NAKED_RW;
+-		break;
+-	default:
+-		ext_cmd_type = 0;
+-		break;
+-	}
+-
+-	prepare_start_command(info, command);
+-
+-	/*
+-	 * Prepare the "is ready" completion before starting a command
+-	 * transaction sequence. If the command is not executed the
+-	 * completion will be completed, see below.
+-	 *
+-	 * We can do that inside the loop because the command variable
+-	 * is invariant and thus so is the exec_cmd.
+-	 */
+-	info->need_wait = 1;
+-	init_completion(&info->dev_ready);
+-	do {
+-		info->state = STATE_PREPARED;
+-
+-		exec_cmd = prepare_set_command(info, command, ext_cmd_type,
+-					       column, page_addr);
+-		if (!exec_cmd) {
+-			info->need_wait = 0;
+-			complete(&info->dev_ready);
+-			break;
+-		}
+-
+-		init_completion(&info->cmd_complete);
+-		pxa3xx_nand_start(info);
+-
+-		if (!wait_for_completion_timeout(&info->cmd_complete,
+-		    CHIP_DELAY_TIMEOUT)) {
+-			dev_err(&info->pdev->dev, "Wait time out!!!\n");
+-			/* Stop State Machine for next command cycle */
+-			pxa3xx_nand_stop(info);
+-			break;
+-		}
+-
+-		/* Only a few commands need several steps */
+-		if (command != NAND_CMD_PAGEPROG &&
+-		    command != NAND_CMD_READ0    &&
+-		    command != NAND_CMD_READOOB)
+-			break;
+-
+-		info->cur_chunk++;
+-
+-		/* Check if the sequence is complete */
+-		if (info->cur_chunk == info->ntotalchunks && command != NAND_CMD_PAGEPROG)
+-			break;
+-
+-		/*
+-		 * After a splitted program command sequence has issued
+-		 * the command dispatch, the command sequence is complete.
+-		 */
+-		if (info->cur_chunk == (info->ntotalchunks + 1) &&
+-		    command == NAND_CMD_PAGEPROG &&
+-		    ext_cmd_type == EXT_CMD_TYPE_DISPATCH)
+-			break;
+-
+-		if (command == NAND_CMD_READ0 || command == NAND_CMD_READOOB) {
+-			/* Last read: issue a 'last naked read' */
+-			if (info->cur_chunk == info->ntotalchunks - 1)
+-				ext_cmd_type = EXT_CMD_TYPE_LAST_RW;
+-			else
+-				ext_cmd_type = EXT_CMD_TYPE_NAKED_RW;
+-
+-		/*
+-		 * If a splitted program command has no more data to transfer,
+-		 * the command dispatch must be issued to complete.
+-		 */
+-		} else if (command == NAND_CMD_PAGEPROG &&
+-			   info->cur_chunk == info->ntotalchunks) {
+-				ext_cmd_type = EXT_CMD_TYPE_DISPATCH;
+-		}
+-	} while (1);
+-
+-	info->state = STATE_IDLE;
+-}
+-
+-static int pxa3xx_nand_write_page_hwecc(struct mtd_info *mtd,
+-		struct nand_chip *chip, const uint8_t *buf, int oob_required,
+-		int page)
+-{
+-	chip->write_buf(mtd, buf, mtd->writesize);
+-	chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+-
+-	return 0;
+-}
+-
+-static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd,
+-		struct nand_chip *chip, uint8_t *buf, int oob_required,
+-		int page)
+-{
+-	struct pxa3xx_nand_host *host = nand_get_controller_data(chip);
+-	struct pxa3xx_nand_info *info = host->info_data;
+-
+-	chip->read_buf(mtd, buf, mtd->writesize);
+-	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+-
+-	if (info->retcode == ERR_CORERR && info->use_ecc) {
+-		mtd->ecc_stats.corrected += info->ecc_err_cnt;
+-
+-	} else if (info->retcode == ERR_UNCORERR) {
+-		/*
+-		 * for blank page (all 0xff), HW will calculate its ECC as
+-		 * 0, which is different from the ECC information within
+-		 * OOB, ignore such uncorrectable errors
+-		 */
+-		if (is_buf_blank(buf, mtd->writesize))
+-			info->retcode = ERR_NONE;
+-		else
+-			mtd->ecc_stats.failed++;
+-	}
+-
+-	return info->max_bitflips;
+-}
+-
+-static uint8_t pxa3xx_nand_read_byte(struct mtd_info *mtd)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct pxa3xx_nand_host *host = nand_get_controller_data(chip);
+-	struct pxa3xx_nand_info *info = host->info_data;
+-	char retval = 0xFF;
+-
+-	if (info->buf_start < info->buf_count)
+-		/* Has just send a new command? */
+-		retval = info->data_buff[info->buf_start++];
+-
+-	return retval;
+-}
+-
+-static u16 pxa3xx_nand_read_word(struct mtd_info *mtd)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct pxa3xx_nand_host *host = nand_get_controller_data(chip);
+-	struct pxa3xx_nand_info *info = host->info_data;
+-	u16 retval = 0xFFFF;
+-
+-	if (!(info->buf_start & 0x01) && info->buf_start < info->buf_count) {
+-		retval = *((u16 *)(info->data_buff+info->buf_start));
+-		info->buf_start += 2;
+-	}
+-	return retval;
+-}
+-
+-static void pxa3xx_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+-{
+-	struct nand_chip *chip = mtd_to_nand(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);
+-
+-	memcpy(buf, info->data_buff + info->buf_start, real_len);
+-	info->buf_start += real_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 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);
+-
+-	memcpy(info->data_buff + info->buf_start, buf, real_len);
+-	info->buf_start += real_len;
+-}
+-
+-static void pxa3xx_nand_select_chip(struct mtd_info *mtd, int chip)
+-{
+-	return;
+-}
+-
+-static int pxa3xx_nand_waitfunc(struct mtd_info *mtd, struct nand_chip *this)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct pxa3xx_nand_host *host = nand_get_controller_data(chip);
+-	struct pxa3xx_nand_info *info = host->info_data;
+-
+-	if (info->need_wait) {
+-		info->need_wait = 0;
+-		if (!wait_for_completion_timeout(&info->dev_ready,
+-		    CHIP_DELAY_TIMEOUT)) {
+-			dev_err(&info->pdev->dev, "Ready time out!!!\n");
+-			return NAND_STATUS_FAIL;
+-		}
+-	}
+-
+-	/* pxa3xx_nand_send_command has waited for command complete */
+-	if (this->state == FL_WRITING || this->state == FL_ERASING) {
+-		if (info->retcode == ERR_NONE)
+-			return 0;
+-		else
+-			return NAND_STATUS_FAIL;
+-	}
+-
+-	return NAND_STATUS_READY;
+-}
+-
+-static int pxa3xx_nand_config_ident(struct pxa3xx_nand_info *info)
+-{
+-	struct pxa3xx_nand_host *host = info->host[info->cs];
+-	struct platform_device *pdev = info->pdev;
+-	struct pxa3xx_nand_platform_data *pdata = dev_get_platdata(&pdev->dev);
+-	const struct nand_sdr_timings *timings;
+-
+-	/* Configure default flash values */
+-	info->chunk_size = PAGE_CHUNK_SIZE;
+-	info->reg_ndcr = 0x0; /* enable all interrupts */
+-	info->reg_ndcr |= (pdata->enable_arbiter) ? NDCR_ND_ARB_EN : 0;
+-	info->reg_ndcr |= NDCR_RD_ID_CNT(READ_ID_BYTES);
+-	info->reg_ndcr |= NDCR_SPARE_EN;
+-
+-	/* use the common timing to make a try */
+-	timings = onfi_async_timing_mode_to_sdr_timings(0);
+-	if (IS_ERR(timings))
+-		return PTR_ERR(timings);
+-
+-	pxa3xx_nand_set_sdr_timing(host, timings);
+-	return 0;
+-}
+-
+-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);
+-
+-	info->reg_ndcr |= (host->col_addr_cycles == 2) ? NDCR_RA_START : 0;
+-	info->reg_ndcr |= (chip->page_shift == 6) ? NDCR_PG_PER_BLK : 0;
+-	info->reg_ndcr |= (mtd->writesize == 2048) ? NDCR_PAGE_SZ : 0;
+-}
+-
+-static void pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info)
+-{
+-	struct platform_device *pdev = info->pdev;
+-	struct pxa3xx_nand_platform_data *pdata = dev_get_platdata(&pdev->dev);
+-	uint32_t ndcr = nand_readl(info, NDCR);
+-
+-	/* Set an initial chunk size */
+-	info->chunk_size = ndcr & NDCR_PAGE_SZ ? 2048 : 512;
+-	info->reg_ndcr = ndcr &
+-		~(NDCR_INT_MASK | NDCR_ND_ARB_EN | NFCV1_NDCR_ARB_CNTL);
+-	info->reg_ndcr |= (pdata->enable_arbiter) ? NDCR_ND_ARB_EN : 0;
+-	info->ndtr0cs0 = nand_readl(info, NDTR0CS0);
+-	info->ndtr1cs0 = nand_readl(info, NDTR1CS0);
+-}
+-
+-static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info)
+-{
+-	struct platform_device *pdev = info->pdev;
+-	struct dma_slave_config	config;
+-	dma_cap_mask_t mask;
+-	struct pxad_param param;
+-	int ret;
+-
+-	info->data_buff = kmalloc(info->buf_size, GFP_KERNEL);
+-	if (info->data_buff == NULL)
+-		return -ENOMEM;
+-	if (use_dma == 0)
+-		return 0;
+-
+-	ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
+-	if (ret)
+-		return ret;
+-
+-	sg_init_one(&info->sg, info->data_buff, info->buf_size);
+-	dma_cap_zero(mask);
+-	dma_cap_set(DMA_SLAVE, mask);
+-	param.prio = PXAD_PRIO_LOWEST;
+-	param.drcmr = info->drcmr_dat;
+-	info->dma_chan = dma_request_slave_channel_compat(mask, pxad_filter_fn,
+-							  &param, &pdev->dev,
+-							  "data");
+-	if (!info->dma_chan) {
+-		dev_err(&pdev->dev, "unable to request data dma channel\n");
+-		return -ENODEV;
+-	}
+-
+-	memset(&config, 0, sizeof(config));
+-	config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+-	config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+-	config.src_addr = info->mmio_phys + NDDB;
+-	config.dst_addr = info->mmio_phys + NDDB;
+-	config.src_maxburst = 32;
+-	config.dst_maxburst = 32;
+-	ret = dmaengine_slave_config(info->dma_chan, &config);
+-	if (ret < 0) {
+-		dev_err(&info->pdev->dev,
+-			"dma channel configuration failed: %d\n",
+-			ret);
+-		return ret;
+-	}
+-
+-	/*
+-	 * Now that DMA buffers are allocated we turn on
+-	 * DMA proper for I/O operations.
+-	 */
+-	info->use_dma = 1;
+-	return 0;
+-}
+-
+-static void pxa3xx_nand_free_buff(struct pxa3xx_nand_info *info)
+-{
+-	if (info->use_dma) {
+-		dmaengine_terminate_all(info->dma_chan);
+-		dma_release_channel(info->dma_chan);
+-	}
+-	kfree(info->data_buff);
+-}
+-
+-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_ecc_ctrl *ecc = &chip->ecc;
+-
+-	if (strength == 1 && ecc_stepsize == 512 && page_size == 2048) {
+-		info->nfullchunks = 1;
+-		info->ntotalchunks = 1;
+-		info->chunk_size = 2048;
+-		info->spare_size = 40;
+-		info->ecc_size = 24;
+-		ecc->mode = NAND_ECC_HW;
+-		ecc->size = 512;
+-		ecc->strength = 1;
+-
+-	} else if (strength == 1 && ecc_stepsize == 512 && page_size == 512) {
+-		info->nfullchunks = 1;
+-		info->ntotalchunks = 1;
+-		info->chunk_size = 512;
+-		info->spare_size = 8;
+-		info->ecc_size = 8;
+-		ecc->mode = NAND_ECC_HW;
+-		ecc->size = 512;
+-		ecc->strength = 1;
+-
+-	/*
+-	 * Required ECC: 4-bit correction per 512 bytes
+-	 * Select: 16-bit correction per 2048 bytes
+-	 */
+-	} else if (strength == 4 && ecc_stepsize == 512 && page_size == 2048) {
+-		info->ecc_bch = 1;
+-		info->nfullchunks = 1;
+-		info->ntotalchunks = 1;
+-		info->chunk_size = 2048;
+-		info->spare_size = 32;
+-		info->ecc_size = 32;
+-		ecc->mode = NAND_ECC_HW;
+-		ecc->size = info->chunk_size;
+-		mtd_set_ooblayout(mtd, &pxa3xx_ooblayout_ops);
+-		ecc->strength = 16;
+-
+-	} else if (strength == 4 && ecc_stepsize == 512 && page_size == 4096) {
+-		info->ecc_bch = 1;
+-		info->nfullchunks = 2;
+-		info->ntotalchunks = 2;
+-		info->chunk_size = 2048;
+-		info->spare_size = 32;
+-		info->ecc_size = 32;
+-		ecc->mode = NAND_ECC_HW;
+-		ecc->size = info->chunk_size;
+-		mtd_set_ooblayout(mtd, &pxa3xx_ooblayout_ops);
+-		ecc->strength = 16;
+-
+-	/*
+-	 * Required ECC: 8-bit correction per 512 bytes
+-	 * Select: 16-bit correction per 1024 bytes
+-	 */
+-	} else if (strength == 8 && ecc_stepsize == 512 && page_size == 4096) {
+-		info->ecc_bch = 1;
+-		info->nfullchunks = 4;
+-		info->ntotalchunks = 5;
+-		info->chunk_size = 1024;
+-		info->spare_size = 0;
+-		info->last_chunk_size = 0;
+-		info->last_spare_size = 64;
+-		info->ecc_size = 32;
+-		ecc->mode = NAND_ECC_HW;
+-		ecc->size = info->chunk_size;
+-		mtd_set_ooblayout(mtd, &pxa3xx_ooblayout_ops);
+-		ecc->strength = 16;
+-	} else {
+-		dev_err(&info->pdev->dev,
+-			"ECC strength %d at page size %d is not supported\n",
+-			strength, page_size);
+-		return -ENODEV;
+-	}
+-
+-	dev_info(&info->pdev->dev, "ECC strength %d, ECC step size %d\n",
+-		 ecc->strength, ecc->size);
+-	return 0;
+-}
+-
+-static int pxa3xx_nand_scan(struct mtd_info *mtd)
+-{
+-	struct nand_chip *chip = mtd_to_nand(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;
+-	struct pxa3xx_nand_platform_data *pdata = dev_get_platdata(&pdev->dev);
+-	int ret;
+-	uint16_t ecc_strength, ecc_step;
+-
+-	if (pdata->keep_config) {
+-		pxa3xx_nand_detect_config(info);
+-	} else {
+-		ret = pxa3xx_nand_config_ident(info);
+-		if (ret)
+-			return ret;
+-	}
+-
+-	if (info->reg_ndcr & NDCR_DWIDTH_M)
+-		chip->options |= NAND_BUSWIDTH_16;
+-
+-	/* Device detection must be done with ECC disabled */
+-	if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370)
+-		nand_writel(info, NDECCCTRL, 0x0);
+-
+-	if (pdata->flash_bbt)
+-		chip->bbt_options |= NAND_BBT_USE_FLASH;
+-
+-	chip->ecc.strength = pdata->ecc_strength;
+-	chip->ecc.size = pdata->ecc_step_size;
+-
+-	ret = nand_scan_ident(mtd, 1, NULL);
+-	if (ret)
+-		return ret;
+-
+-	if (!pdata->keep_config) {
+-		ret = pxa3xx_nand_init(host);
+-		if (ret) {
+-			dev_err(&info->pdev->dev, "Failed to init nand: %d\n",
+-				ret);
+-			return ret;
+-		}
+-	}
+-
+-	if (chip->bbt_options & NAND_BBT_USE_FLASH) {
+-		/*
+-		 * We'll use a bad block table stored in-flash and don't
+-		 * allow writing the bad block marker to the flash.
+-		 */
+-		chip->bbt_options |= NAND_BBT_NO_OOB_BBM;
+-		chip->bbt_td = &bbt_main_descr;
+-		chip->bbt_md = &bbt_mirror_descr;
+-	}
+-
+-	/*
+-	 * If the page size is bigger than the FIFO size, let's check
+-	 * we are given the right variant and then switch to the extended
+-	 * (aka splitted) command handling,
+-	 */
+-	if (mtd->writesize > PAGE_CHUNK_SIZE) {
+-		if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370) {
+-			chip->cmdfunc = nand_cmdfunc_extended;
+-		} else {
+-			dev_err(&info->pdev->dev,
+-				"unsupported page size on this variant\n");
+-			return -ENODEV;
+-		}
+-	}
+-
+-	ecc_strength = chip->ecc.strength;
+-	ecc_step = chip->ecc.size;
+-	if (!ecc_strength || !ecc_step) {
+-		ecc_strength = chip->ecc_strength_ds;
+-		ecc_step = chip->ecc_step_ds;
+-	}
+-
+-	/* Set default ECC strength requirements on non-ONFI devices */
+-	if (ecc_strength < 1 && ecc_step < 1) {
+-		ecc_strength = 1;
+-		ecc_step = 512;
+-	}
+-
+-	ret = pxa_ecc_init(info, mtd, ecc_strength,
+-			   ecc_step, mtd->writesize);
+-	if (ret)
+-		return ret;
+-
+-	/* calculate addressing information */
+-	if (mtd->writesize >= 2048)
+-		host->col_addr_cycles = 2;
+-	else
+-		host->col_addr_cycles = 1;
+-
+-	/* release the initial buffer */
+-	kfree(info->data_buff);
+-
+-	/* allocate the real data + oob buffer */
+-	info->buf_size = mtd->writesize + mtd->oobsize;
+-	ret = pxa3xx_nand_init_buff(info);
+-	if (ret)
+-		return ret;
+-	info->oob_buff = info->data_buff + mtd->writesize;
+-
+-	if ((mtd->size >> chip->page_shift) > 65536)
+-		host->row_addr_cycles = 3;
+-	else
+-		host->row_addr_cycles = 2;
+-
+-	if (!pdata->keep_config)
+-		pxa3xx_nand_config_tail(info);
+-
+-	return nand_scan_tail(mtd);
+-}
+-
+-static int alloc_nand_resource(struct platform_device *pdev)
+-{
+-	struct device_node *np = pdev->dev.of_node;
+-	struct pxa3xx_nand_platform_data *pdata;
+-	struct pxa3xx_nand_info *info;
+-	struct pxa3xx_nand_host *host;
+-	struct nand_chip *chip = NULL;
+-	struct mtd_info *mtd;
+-	struct resource *r;
+-	int ret, irq, cs;
+-
+-	pdata = dev_get_platdata(&pdev->dev);
+-	if (pdata->num_cs <= 0) {
+-		dev_err(&pdev->dev, "invalid number of chip selects\n");
+-		return -ENODEV;
+-	}
+-
+-	info = devm_kzalloc(&pdev->dev,
+-			    sizeof(*info) + sizeof(*host) * pdata->num_cs,
+-			    GFP_KERNEL);
+-	if (!info)
+-		return -ENOMEM;
+-
+-	info->pdev = pdev;
+-	info->variant = pxa3xx_nand_get_variant(pdev);
+-	for (cs = 0; cs < pdata->num_cs; cs++) {
+-		host = (void *)&info[1] + sizeof(*host) * cs;
+-		chip = &host->chip;
+-		nand_set_controller_data(chip, host);
+-		mtd = nand_to_mtd(chip);
+-		info->host[cs] = host;
+-		host->cs = cs;
+-		host->info_data = info;
+-		mtd->dev.parent = &pdev->dev;
+-		/* FIXME: all chips use the same device tree partitions */
+-		nand_set_flash_node(chip, np);
+-
+-		nand_set_controller_data(chip, host);
+-		chip->ecc.read_page	= pxa3xx_nand_read_page_hwecc;
+-		chip->ecc.write_page	= pxa3xx_nand_write_page_hwecc;
+-		chip->controller        = &info->controller;
+-		chip->waitfunc		= pxa3xx_nand_waitfunc;
+-		chip->select_chip	= pxa3xx_nand_select_chip;
+-		chip->read_word		= pxa3xx_nand_read_word;
+-		chip->read_byte		= pxa3xx_nand_read_byte;
+-		chip->read_buf		= pxa3xx_nand_read_buf;
+-		chip->write_buf		= pxa3xx_nand_write_buf;
+-		chip->options		|= NAND_NO_SUBPAGE_WRITE;
+-		chip->cmdfunc		= nand_cmdfunc;
+-		chip->onfi_set_features	= nand_onfi_get_set_features_notsupp;
+-		chip->onfi_get_features	= nand_onfi_get_set_features_notsupp;
+-	}
+-
+-	nand_hw_control_init(chip->controller);
+-	info->clk = devm_clk_get(&pdev->dev, NULL);
+-	if (IS_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)
+-		return ret;
+-
+-	if (!np && use_dma) {
+-		r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+-		if (r == NULL) {
+-			dev_err(&pdev->dev,
+-				"no resource defined for data DMA\n");
+-			ret = -ENXIO;
+-			goto fail_disable_clk;
+-		}
+-		info->drcmr_dat = r->start;
+-	}
+-
+-	irq = platform_get_irq(pdev, 0);
+-	if (irq < 0) {
+-		dev_err(&pdev->dev, "no IRQ resource defined\n");
+-		ret = -ENXIO;
+-		goto fail_disable_clk;
+-	}
+-
+-	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+-	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;
+-
+-	/* Allocate a buffer to allow flash detection */
+-	info->buf_size = INIT_BUFFER_SIZE;
+-	info->data_buff = kmalloc(info->buf_size, GFP_KERNEL);
+-	if (info->data_buff == NULL) {
+-		ret = -ENOMEM;
+-		goto fail_disable_clk;
+-	}
+-
+-	/* initialize all interrupts to be disabled */
+-	disable_int(info, NDSR_MASK);
+-
+-	ret = request_threaded_irq(irq, pxa3xx_nand_irq,
+-				   pxa3xx_nand_irq_thread, IRQF_ONESHOT,
+-				   pdev->name, info);
+-	if (ret < 0) {
+-		dev_err(&pdev->dev, "failed to request IRQ: %d\n", ret);
+-		goto fail_free_buf;
+-	}
+-
+-	platform_set_drvdata(pdev, info);
+-
+-	return 0;
+-
+-fail_free_buf:
+-	free_irq(irq, info);
+-	kfree(info->data_buff);
+-fail_disable_clk:
+-	clk_disable_unprepare(info->clk);
+-	return ret;
+-}
+-
+-static int pxa3xx_nand_remove(struct platform_device *pdev)
+-{
+-	struct pxa3xx_nand_info *info = platform_get_drvdata(pdev);
+-	struct pxa3xx_nand_platform_data *pdata;
+-	int irq, cs;
+-
+-	if (!info)
+-		return 0;
+-
+-	pdata = dev_get_platdata(&pdev->dev);
+-
+-	irq = platform_get_irq(pdev, 0);
+-	if (irq >= 0)
+-		free_irq(irq, info);
+-	pxa3xx_nand_free_buff(info);
+-
+-	/*
+-	 * In the pxa3xx case, the DFI bus is shared between the SMC and NFC.
+-	 * In order to prevent a lockup of the system bus, the DFI bus
+-	 * arbitration is granted to SMC upon driver removal. This is done by
+-	 * setting the x_ARB_CNTL bit, which also prevents the NAND to have
+-	 * access to the bus anymore.
+-	 */
+-	nand_writel(info, NDCR,
+-		    (nand_readl(info, NDCR) & ~NDCR_ND_ARB_EN) |
+-		    NFCV1_NDCR_ARB_CNTL);
+-	clk_disable_unprepare(info->clk);
+-
+-	for (cs = 0; cs < pdata->num_cs; cs++)
+-		nand_release(nand_to_mtd(&info->host[cs]->chip));
+-	return 0;
+-}
+-
+-static int pxa3xx_nand_probe_dt(struct platform_device *pdev)
+-{
+-	struct pxa3xx_nand_platform_data *pdata;
+-	struct device_node *np = pdev->dev.of_node;
+-	const struct of_device_id *of_id =
+-			of_match_device(pxa3xx_nand_dt_ids, &pdev->dev);
+-
+-	if (!of_id)
+-		return 0;
+-
+-	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+-	if (!pdata)
+-		return -ENOMEM;
+-
+-	if (of_get_property(np, "marvell,nand-enable-arbiter", NULL))
+-		pdata->enable_arbiter = 1;
+-	if (of_get_property(np, "marvell,nand-keep-config", NULL))
+-		pdata->keep_config = 1;
+-	of_property_read_u32(np, "num-cs", &pdata->num_cs);
+-
+-	pdev->dev.platform_data = pdata;
+-
+-	return 0;
+-}
+-
+-static int pxa3xx_nand_probe(struct platform_device *pdev)
+-{
+-	struct pxa3xx_nand_platform_data *pdata;
+-	struct pxa3xx_nand_info *info;
+-	int ret, cs, probe_success, dma_available;
+-
+-	dma_available = IS_ENABLED(CONFIG_ARM) &&
+-		(IS_ENABLED(CONFIG_ARCH_PXA) || IS_ENABLED(CONFIG_ARCH_MMP));
+-	if (use_dma && !dma_available) {
+-		use_dma = 0;
+-		dev_warn(&pdev->dev,
+-			 "This platform can't do DMA on this device\n");
+-	}
+-
+-	ret = pxa3xx_nand_probe_dt(pdev);
+-	if (ret)
+-		return ret;
+-
+-	pdata = dev_get_platdata(&pdev->dev);
+-	if (!pdata) {
+-		dev_err(&pdev->dev, "no platform data defined\n");
+-		return -ENODEV;
+-	}
+-
+-	ret = alloc_nand_resource(pdev);
+-	if (ret)
+-		return ret;
+-
+-	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);
+-
+-		/*
+-		 * The mtd name matches the one used in 'mtdparts' kernel
+-		 * parameter. This name cannot be changed or otherwise
+-		 * user's mtd partitions configuration would get broken.
+-		 */
+-		mtd->name = "pxa3xx_nand-0";
+-		info->cs = cs;
+-		ret = pxa3xx_nand_scan(mtd);
+-		if (ret) {
+-			dev_warn(&pdev->dev, "failed to scan nand at cs %d\n",
+-				cs);
+-			continue;
+-		}
+-
+-		ret = mtd_device_register(mtd, pdata->parts[cs],
+-					  pdata->nr_parts[cs]);
+-		if (!ret)
+-			probe_success = 1;
+-	}
+-
+-	if (!probe_success) {
+-		pxa3xx_nand_remove(pdev);
+-		return -ENODEV;
+-	}
+-
+-	return 0;
+-}
+-
+-#ifdef CONFIG_PM
+-static int pxa3xx_nand_suspend(struct device *dev)
+-{
+-	struct pxa3xx_nand_info *info = dev_get_drvdata(dev);
+-
+-	if (info->state) {
+-		dev_err(dev, "driver busy, state = %d\n", info->state);
+-		return -EAGAIN;
+-	}
+-
+-	clk_disable(info->clk);
+-	return 0;
+-}
+-
+-static int pxa3xx_nand_resume(struct device *dev)
+-{
+-	struct pxa3xx_nand_info *info = dev_get_drvdata(dev);
+-	int ret;
+-
+-	ret = clk_enable(info->clk);
+-	if (ret < 0)
+-		return ret;
+-
+-	/* We don't want to handle interrupt without calling mtd routine */
+-	disable_int(info, NDCR_INT_MASK);
+-
+-	/*
+-	 * Directly set the chip select to a invalid value,
+-	 * then the driver would reset the timing according
+-	 * to current chip select at the beginning of cmdfunc
+-	 */
+-	info->cs = 0xff;
+-
+-	/*
+-	 * As the spec says, the NDSR would be updated to 0x1800 when
+-	 * doing the nand_clk disable/enable.
+-	 * To prevent it damaging state machine of the driver, clear
+-	 * all status before resume
+-	 */
+-	nand_writel(info, NDSR, NDSR_MASK);
+-
+-	return 0;
+-}
+-#else
+-#define pxa3xx_nand_suspend	NULL
+-#define pxa3xx_nand_resume	NULL
+-#endif
+-
+-static const struct dev_pm_ops pxa3xx_nand_pm_ops = {
+-	.suspend	= pxa3xx_nand_suspend,
+-	.resume		= pxa3xx_nand_resume,
+-};
+-
+-static struct platform_driver pxa3xx_nand_driver = {
+-	.driver = {
+-		.name	= "pxa3xx-nand",
+-		.of_match_table = pxa3xx_nand_dt_ids,
+-		.pm	= &pxa3xx_nand_pm_ops,
+-	},
+-	.probe		= pxa3xx_nand_probe,
+-	.remove		= pxa3xx_nand_remove,
+-};
+-
+-module_platform_driver(pxa3xx_nand_driver);
+-
+-MODULE_LICENSE("GPL");
+-MODULE_DESCRIPTION("PXA3xx NAND controller driver");
+diff --git a/drivers/mtd/nand/qcom_nandc.c b/drivers/mtd/nand/qcom_nandc.c
+deleted file mode 100644
+index 3baddfc..0000000
+--- a/drivers/mtd/nand/qcom_nandc.c
++++ /dev/null
+@@ -1,2821 +0,0 @@
+-/*
+- * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+- *
+- * This software is licensed under the terms of the GNU General Public
+- * License version 2, as published by the Free Software Foundation, and
+- * may be copied, distributed, and modified under those terms.
+- *
+- * 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/clk.h>
+-#include <linux/slab.h>
+-#include <linux/bitops.h>
+-#include <linux/dma-mapping.h>
+-#include <linux/dmaengine.h>
+-#include <linux/module.h>
+-#include <linux/mtd/rawnand.h>
+-#include <linux/mtd/partitions.h>
+-#include <linux/of.h>
+-#include <linux/of_device.h>
+-#include <linux/delay.h>
+-
+-/* NANDc reg offsets */
+-#define	NAND_FLASH_CMD			0x00
+-#define	NAND_ADDR0			0x04
+-#define	NAND_ADDR1			0x08
+-#define	NAND_FLASH_CHIP_SELECT		0x0c
+-#define	NAND_EXEC_CMD			0x10
+-#define	NAND_FLASH_STATUS		0x14
+-#define	NAND_BUFFER_STATUS		0x18
+-#define	NAND_DEV0_CFG0			0x20
+-#define	NAND_DEV0_CFG1			0x24
+-#define	NAND_DEV0_ECC_CFG		0x28
+-#define	NAND_DEV1_ECC_CFG		0x2c
+-#define	NAND_DEV1_CFG0			0x30
+-#define	NAND_DEV1_CFG1			0x34
+-#define	NAND_READ_ID			0x40
+-#define	NAND_READ_STATUS		0x44
+-#define	NAND_DEV_CMD0			0xa0
+-#define	NAND_DEV_CMD1			0xa4
+-#define	NAND_DEV_CMD2			0xa8
+-#define	NAND_DEV_CMD_VLD		0xac
+-#define	SFLASHC_BURST_CFG		0xe0
+-#define	NAND_ERASED_CW_DETECT_CFG	0xe8
+-#define	NAND_ERASED_CW_DETECT_STATUS	0xec
+-#define	NAND_EBI2_ECC_BUF_CFG		0xf0
+-#define	FLASH_BUF_ACC			0x100
+-
+-#define	NAND_CTRL			0xf00
+-#define	NAND_VERSION			0xf08
+-#define	NAND_READ_LOCATION_0		0xf20
+-#define	NAND_READ_LOCATION_1		0xf24
+-#define	NAND_READ_LOCATION_2		0xf28
+-#define	NAND_READ_LOCATION_3		0xf2c
+-
+-/* dummy register offsets, used by write_reg_dma */
+-#define	NAND_DEV_CMD1_RESTORE		0xdead
+-#define	NAND_DEV_CMD_VLD_RESTORE	0xbeef
+-
+-/* NAND_FLASH_CMD bits */
+-#define	PAGE_ACC			BIT(4)
+-#define	LAST_PAGE			BIT(5)
+-
+-/* NAND_FLASH_CHIP_SELECT bits */
+-#define	NAND_DEV_SEL			0
+-#define	DM_EN				BIT(2)
+-
+-/* NAND_FLASH_STATUS bits */
+-#define	FS_OP_ERR			BIT(4)
+-#define	FS_READY_BSY_N			BIT(5)
+-#define	FS_MPU_ERR			BIT(8)
+-#define	FS_DEVICE_STS_ERR		BIT(16)
+-#define	FS_DEVICE_WP			BIT(23)
+-
+-/* NAND_BUFFER_STATUS bits */
+-#define	BS_UNCORRECTABLE_BIT		BIT(8)
+-#define	BS_CORRECTABLE_ERR_MSK		0x1f
+-
+-/* NAND_DEVn_CFG0 bits */
+-#define	DISABLE_STATUS_AFTER_WRITE	4
+-#define	CW_PER_PAGE			6
+-#define	UD_SIZE_BYTES			9
+-#define	ECC_PARITY_SIZE_BYTES_RS	19
+-#define	SPARE_SIZE_BYTES		23
+-#define	NUM_ADDR_CYCLES			27
+-#define	STATUS_BFR_READ			30
+-#define	SET_RD_MODE_AFTER_STATUS	31
+-
+-/* NAND_DEVn_CFG0 bits */
+-#define	DEV0_CFG1_ECC_DISABLE		0
+-#define	WIDE_FLASH			1
+-#define	NAND_RECOVERY_CYCLES		2
+-#define	CS_ACTIVE_BSY			5
+-#define	BAD_BLOCK_BYTE_NUM		6
+-#define	BAD_BLOCK_IN_SPARE_AREA		16
+-#define	WR_RD_BSY_GAP			17
+-#define	ENABLE_BCH_ECC			27
+-
+-/* NAND_DEV0_ECC_CFG bits */
+-#define	ECC_CFG_ECC_DISABLE		0
+-#define	ECC_SW_RESET			1
+-#define	ECC_MODE			4
+-#define	ECC_PARITY_SIZE_BYTES_BCH	8
+-#define	ECC_NUM_DATA_BYTES		16
+-#define	ECC_FORCE_CLK_OPEN		30
+-
+-/* NAND_DEV_CMD1 bits */
+-#define	READ_ADDR			0
+-
+-/* NAND_DEV_CMD_VLD bits */
+-#define	READ_START_VLD			BIT(0)
+-#define	READ_STOP_VLD			BIT(1)
+-#define	WRITE_START_VLD			BIT(2)
+-#define	ERASE_START_VLD			BIT(3)
+-#define	SEQ_READ_START_VLD		BIT(4)
+-
+-/* NAND_EBI2_ECC_BUF_CFG bits */
+-#define	NUM_STEPS			0
+-
+-/* NAND_ERASED_CW_DETECT_CFG bits */
+-#define	ERASED_CW_ECC_MASK		1
+-#define	AUTO_DETECT_RES			0
+-#define	MASK_ECC			(1 << ERASED_CW_ECC_MASK)
+-#define	RESET_ERASED_DET		(1 << AUTO_DETECT_RES)
+-#define	ACTIVE_ERASED_DET		(0 << AUTO_DETECT_RES)
+-#define	CLR_ERASED_PAGE_DET		(RESET_ERASED_DET | MASK_ECC)
+-#define	SET_ERASED_PAGE_DET		(ACTIVE_ERASED_DET | MASK_ECC)
+-
+-/* NAND_ERASED_CW_DETECT_STATUS bits */
+-#define	PAGE_ALL_ERASED			BIT(7)
+-#define	CODEWORD_ALL_ERASED		BIT(6)
+-#define	PAGE_ERASED			BIT(5)
+-#define	CODEWORD_ERASED			BIT(4)
+-#define	ERASED_PAGE			(PAGE_ALL_ERASED | PAGE_ERASED)
+-#define	ERASED_CW			(CODEWORD_ALL_ERASED | CODEWORD_ERASED)
+-
+-/* NAND_READ_LOCATION_n bits */
+-#define READ_LOCATION_OFFSET		0
+-#define READ_LOCATION_SIZE		16
+-#define READ_LOCATION_LAST		31
+-
+-/* Version Mask */
+-#define	NAND_VERSION_MAJOR_MASK		0xf0000000
+-#define	NAND_VERSION_MAJOR_SHIFT	28
+-#define	NAND_VERSION_MINOR_MASK		0x0fff0000
+-#define	NAND_VERSION_MINOR_SHIFT	16
+-
+-/* NAND OP_CMDs */
+-#define	PAGE_READ			0x2
+-#define	PAGE_READ_WITH_ECC		0x3
+-#define	PAGE_READ_WITH_ECC_SPARE	0x4
+-#define	PROGRAM_PAGE			0x6
+-#define	PAGE_PROGRAM_WITH_ECC		0x7
+-#define	PROGRAM_PAGE_SPARE		0x9
+-#define	BLOCK_ERASE			0xa
+-#define	FETCH_ID			0xb
+-#define	RESET_DEVICE			0xd
+-
+-/* Default Value for NAND_DEV_CMD_VLD */
+-#define NAND_DEV_CMD_VLD_VAL		(READ_START_VLD | WRITE_START_VLD | \
+-					 ERASE_START_VLD | SEQ_READ_START_VLD)
+-
+-/* NAND_CTRL bits */
+-#define	BAM_MODE_EN			BIT(0)
+-
+-/*
+- * the NAND controller performs reads/writes with ECC in 516 byte chunks.
+- * the driver calls the chunks 'step' or 'codeword' interchangeably
+- */
+-#define	NANDC_STEP_SIZE			512
+-
+-/*
+- * the largest page size we support is 8K, this will have 16 steps/codewords
+- * of 512 bytes each
+- */
+-#define	MAX_NUM_STEPS			(SZ_8K / NANDC_STEP_SIZE)
+-
+-/* we read at most 3 registers per codeword scan */
+-#define	MAX_REG_RD			(3 * MAX_NUM_STEPS)
+-
+-/* ECC modes supported by the controller */
+-#define	ECC_NONE	BIT(0)
+-#define	ECC_RS_4BIT	BIT(1)
+-#define	ECC_BCH_4BIT	BIT(2)
+-#define	ECC_BCH_8BIT	BIT(3)
+-
+-#define nandc_set_read_loc(nandc, reg, offset, size, is_last)	\
+-nandc_set_reg(nandc, NAND_READ_LOCATION_##reg,			\
+-	      ((offset) << READ_LOCATION_OFFSET) |		\
+-	      ((size) << READ_LOCATION_SIZE) |			\
+-	      ((is_last) << READ_LOCATION_LAST))
+-
+-/*
+- * Returns the actual register address for all NAND_DEV_ registers
+- * (i.e. NAND_DEV_CMD0, NAND_DEV_CMD1, NAND_DEV_CMD2 and NAND_DEV_CMD_VLD)
+- */
+-#define dev_cmd_reg_addr(nandc, reg) ((nandc)->props->dev_cmd_reg_start + (reg))
+-
+-#define QPIC_PER_CW_CMD_SGL		32
+-#define QPIC_PER_CW_DATA_SGL		8
+-
+-/*
+- * Flags used in DMA descriptor preparation helper functions
+- * (i.e. read_reg_dma/write_reg_dma/read_data_dma/write_data_dma)
+- */
+-/* Don't set the EOT in current tx BAM sgl */
+-#define NAND_BAM_NO_EOT			BIT(0)
+-/* Set the NWD flag in current BAM sgl */
+-#define NAND_BAM_NWD			BIT(1)
+-/* Finish writing in the current BAM sgl and start writing in another BAM sgl */
+-#define NAND_BAM_NEXT_SGL		BIT(2)
+-/*
+- * Erased codeword status is being used two times in single transfer so this
+- * flag will determine the current value of erased codeword status register
+- */
+-#define NAND_ERASED_CW_SET		BIT(4)
+-
+-/*
+- * This data type corresponds to the BAM transaction which will be used for all
+- * NAND transfers.
+- * @cmd_sgl - sgl for NAND BAM command pipe
+- * @data_sgl - sgl for NAND BAM consumer/producer pipe
+- * @cmd_sgl_pos - current index in command sgl.
+- * @cmd_sgl_start - start index in command sgl.
+- * @tx_sgl_pos - current index in data sgl for tx.
+- * @tx_sgl_start - start index in data sgl for tx.
+- * @rx_sgl_pos - current index in data sgl for rx.
+- * @rx_sgl_start - start index in data sgl for rx.
+- */
+-struct bam_transaction {
+-	struct scatterlist *cmd_sgl;
+-	struct scatterlist *data_sgl;
+-	u32 cmd_sgl_pos;
+-	u32 cmd_sgl_start;
+-	u32 tx_sgl_pos;
+-	u32 tx_sgl_start;
+-	u32 rx_sgl_pos;
+-	u32 rx_sgl_start;
+-};
+-
+-/*
+- * This data type corresponds to the nand dma descriptor
+- * @list - list for desc_info
+- * @dir - DMA transfer direction
+- * @adm_sgl - sgl which will be used for single sgl dma descriptor. Only used by
+- *	      ADM
+- * @bam_sgl - sgl which will be used for dma descriptor. Only used by BAM
+- * @sgl_cnt - number of SGL in bam_sgl. Only used by BAM
+- * @dma_desc - low level DMA engine descriptor
+- */
+-struct desc_info {
+-	struct list_head node;
+-
+-	enum dma_data_direction dir;
+-	union {
+-		struct scatterlist adm_sgl;
+-		struct {
+-			struct scatterlist *bam_sgl;
+-			int sgl_cnt;
+-		};
+-	};
+-	struct dma_async_tx_descriptor *dma_desc;
+-};
+-
+-/*
+- * holds the current register values that we want to write. acts as a contiguous
+- * chunk of memory which we use to write the controller registers through DMA.
+- */
+-struct nandc_regs {
+-	__le32 cmd;
+-	__le32 addr0;
+-	__le32 addr1;
+-	__le32 chip_sel;
+-	__le32 exec;
+-
+-	__le32 cfg0;
+-	__le32 cfg1;
+-	__le32 ecc_bch_cfg;
+-
+-	__le32 clrflashstatus;
+-	__le32 clrreadstatus;
+-
+-	__le32 cmd1;
+-	__le32 vld;
+-
+-	__le32 orig_cmd1;
+-	__le32 orig_vld;
+-
+-	__le32 ecc_buf_cfg;
+-	__le32 read_location0;
+-	__le32 read_location1;
+-	__le32 read_location2;
+-	__le32 read_location3;
+-
+-	__le32 erased_cw_detect_cfg_clr;
+-	__le32 erased_cw_detect_cfg_set;
+-};
+-
+-/*
+- * NAND controller data struct
+- *
+- * @controller:			base controller structure
+- * @host_list:			list containing all the chips attached to the
+- *				controller
+- * @dev:			parent device
+- * @base:			MMIO base
+- * @base_dma:			physical base address of controller registers
+- * @core_clk:			controller clock
+- * @aon_clk:			another controller clock
+- *
+- * @chan:			dma channel
+- * @cmd_crci:			ADM DMA CRCI for command flow control
+- * @data_crci:			ADM DMA CRCI for data flow control
+- * @desc_list:			DMA descriptor list (list of desc_infos)
+- *
+- * @data_buffer:		our local DMA buffer for page read/writes,
+- *				used when we can't use the buffer provided
+- *				by upper layers directly
+- * @buf_size/count/start:	markers for chip->read_buf/write_buf functions
+- * @reg_read_buf:		local buffer for reading back registers via DMA
+- * @reg_read_dma:		contains dma address for register read buffer
+- * @reg_read_pos:		marker for data read in reg_read_buf
+- *
+- * @regs:			a contiguous chunk of memory for DMA register
+- *				writes. contains the register values to be
+- *				written to controller
+- * @cmd1/vld:			some fixed controller register values
+- * @props:			properties of current NAND controller,
+- *				initialized via DT match data
+- * @max_cwperpage:		maximum QPIC codewords required. calculated
+- *				from all connected NAND devices pagesize
+- */
+-struct qcom_nand_controller {
+-	struct nand_hw_control controller;
+-	struct list_head host_list;
+-
+-	struct device *dev;
+-
+-	void __iomem *base;
+-	dma_addr_t base_dma;
+-
+-	struct clk *core_clk;
+-	struct clk *aon_clk;
+-
+-	union {
+-		/* will be used only by QPIC for BAM DMA */
+-		struct {
+-			struct dma_chan *tx_chan;
+-			struct dma_chan *rx_chan;
+-			struct dma_chan *cmd_chan;
+-		};
+-
+-		/* will be used only by EBI2 for ADM DMA */
+-		struct {
+-			struct dma_chan *chan;
+-			unsigned int cmd_crci;
+-			unsigned int data_crci;
+-		};
+-	};
+-
+-	struct list_head desc_list;
+-	struct bam_transaction *bam_txn;
+-
+-	u8		*data_buffer;
+-	int		buf_size;
+-	int		buf_count;
+-	int		buf_start;
+-	unsigned int	max_cwperpage;
+-
+-	__le32 *reg_read_buf;
+-	dma_addr_t reg_read_dma;
+-	int reg_read_pos;
+-
+-	struct nandc_regs *regs;
+-
+-	u32 cmd1, vld;
+-	const struct qcom_nandc_props *props;
+-};
+-
+-/*
+- * NAND chip structure
+- *
+- * @chip:			base NAND chip structure
+- * @node:			list node to add itself to host_list in
+- *				qcom_nand_controller
+- *
+- * @cs:				chip select value for this chip
+- * @cw_size:			the number of bytes in a single step/codeword
+- *				of a page, consisting of all data, ecc, spare
+- *				and reserved bytes
+- * @cw_data:			the number of bytes within a codeword protected
+- *				by ECC
+- * @use_ecc:			request the controller to use ECC for the
+- *				upcoming read/write
+- * @bch_enabled:		flag to tell whether BCH ECC mode is used
+- * @ecc_bytes_hw:		ECC bytes used by controller hardware for this
+- *				chip
+- * @status:			value to be returned if NAND_CMD_STATUS command
+- *				is executed
+- * @last_command:		keeps track of last command on this chip. used
+- *				for reading correct status
+- *
+- * @cfg0, cfg1, cfg0_raw..:	NANDc register configurations needed for
+- *				ecc/non-ecc mode for the current nand flash
+- *				device
+- */
+-struct qcom_nand_host {
+-	struct nand_chip chip;
+-	struct list_head node;
+-
+-	int cs;
+-	int cw_size;
+-	int cw_data;
+-	bool use_ecc;
+-	bool bch_enabled;
+-	int ecc_bytes_hw;
+-	int spare_bytes;
+-	int bbm_size;
+-	u8 status;
+-	int last_command;
+-
+-	u32 cfg0, cfg1;
+-	u32 cfg0_raw, cfg1_raw;
+-	u32 ecc_buf_cfg;
+-	u32 ecc_bch_cfg;
+-	u32 clrflashstatus;
+-	u32 clrreadstatus;
+-};
+-
+-/*
+- * This data type corresponds to the NAND controller properties which varies
+- * among different NAND controllers.
+- * @ecc_modes - ecc mode for NAND
+- * @is_bam - whether NAND controller is using BAM
+- * @dev_cmd_reg_start - NAND_DEV_CMD_* registers starting offset
+- */
+-struct qcom_nandc_props {
+-	u32 ecc_modes;
+-	bool is_bam;
+-	u32 dev_cmd_reg_start;
+-};
+-
+-/* Frees the BAM transaction memory */
+-static void free_bam_transaction(struct qcom_nand_controller *nandc)
+-{
+-	struct bam_transaction *bam_txn = nandc->bam_txn;
+-
+-	devm_kfree(nandc->dev, bam_txn);
+-}
+-
+-/* Allocates and Initializes the BAM transaction */
+-static struct bam_transaction *
+-alloc_bam_transaction(struct qcom_nand_controller *nandc)
+-{
+-	struct bam_transaction *bam_txn;
+-	size_t bam_txn_size;
+-	unsigned int num_cw = nandc->max_cwperpage;
+-	void *bam_txn_buf;
+-
+-	bam_txn_size =
+-		sizeof(*bam_txn) + num_cw *
+-		((sizeof(*bam_txn->cmd_sgl) * QPIC_PER_CW_CMD_SGL) +
+-		(sizeof(*bam_txn->data_sgl) * QPIC_PER_CW_DATA_SGL));
+-
+-	bam_txn_buf = devm_kzalloc(nandc->dev, bam_txn_size, GFP_KERNEL);
+-	if (!bam_txn_buf)
+-		return NULL;
+-
+-	bam_txn = bam_txn_buf;
+-	bam_txn_buf += sizeof(*bam_txn);
+-
+-	bam_txn->cmd_sgl = bam_txn_buf;
+-	bam_txn_buf +=
+-		sizeof(*bam_txn->cmd_sgl) * QPIC_PER_CW_CMD_SGL * num_cw;
+-
+-	bam_txn->data_sgl = bam_txn_buf;
+-
+-	return bam_txn;
+-}
+-
+-/* Clears the BAM transaction indexes */
+-static void clear_bam_transaction(struct qcom_nand_controller *nandc)
+-{
+-	struct bam_transaction *bam_txn = nandc->bam_txn;
+-
+-	if (!nandc->props->is_bam)
+-		return;
+-
+-	bam_txn->cmd_sgl_pos = 0;
+-	bam_txn->cmd_sgl_start = 0;
+-	bam_txn->tx_sgl_pos = 0;
+-	bam_txn->tx_sgl_start = 0;
+-	bam_txn->rx_sgl_pos = 0;
+-	bam_txn->rx_sgl_start = 0;
+-
+-	sg_init_table(bam_txn->cmd_sgl, nandc->max_cwperpage *
+-		      QPIC_PER_CW_CMD_SGL);
+-	sg_init_table(bam_txn->data_sgl, nandc->max_cwperpage *
+-		      QPIC_PER_CW_DATA_SGL);
+-}
+-
+-static inline struct qcom_nand_host *to_qcom_nand_host(struct nand_chip *chip)
+-{
+-	return container_of(chip, struct qcom_nand_host, chip);
+-}
+-
+-static inline struct qcom_nand_controller *
+-get_qcom_nand_controller(struct nand_chip *chip)
+-{
+-	return container_of(chip->controller, struct qcom_nand_controller,
+-			    controller);
+-}
+-
+-static inline u32 nandc_read(struct qcom_nand_controller *nandc, int offset)
+-{
+-	return ioread32(nandc->base + offset);
+-}
+-
+-static inline void nandc_write(struct qcom_nand_controller *nandc, int offset,
+-			       u32 val)
+-{
+-	iowrite32(val, nandc->base + offset);
+-}
+-
+-static inline void nandc_read_buffer_sync(struct qcom_nand_controller *nandc,
+-					  bool is_cpu)
+-{
+-	if (!nandc->props->is_bam)
+-		return;
+-
+-	if (is_cpu)
+-		dma_sync_single_for_cpu(nandc->dev, nandc->reg_read_dma,
+-					MAX_REG_RD *
+-					sizeof(*nandc->reg_read_buf),
+-					DMA_FROM_DEVICE);
+-	else
+-		dma_sync_single_for_device(nandc->dev, nandc->reg_read_dma,
+-					   MAX_REG_RD *
+-					   sizeof(*nandc->reg_read_buf),
+-					   DMA_FROM_DEVICE);
+-}
+-
+-static __le32 *offset_to_nandc_reg(struct nandc_regs *regs, int offset)
+-{
+-	switch (offset) {
+-	case NAND_FLASH_CMD:
+-		return &regs->cmd;
+-	case NAND_ADDR0:
+-		return &regs->addr0;
+-	case NAND_ADDR1:
+-		return &regs->addr1;
+-	case NAND_FLASH_CHIP_SELECT:
+-		return &regs->chip_sel;
+-	case NAND_EXEC_CMD:
+-		return &regs->exec;
+-	case NAND_FLASH_STATUS:
+-		return &regs->clrflashstatus;
+-	case NAND_DEV0_CFG0:
+-		return &regs->cfg0;
+-	case NAND_DEV0_CFG1:
+-		return &regs->cfg1;
+-	case NAND_DEV0_ECC_CFG:
+-		return &regs->ecc_bch_cfg;
+-	case NAND_READ_STATUS:
+-		return &regs->clrreadstatus;
+-	case NAND_DEV_CMD1:
+-		return &regs->cmd1;
+-	case NAND_DEV_CMD1_RESTORE:
+-		return &regs->orig_cmd1;
+-	case NAND_DEV_CMD_VLD:
+-		return &regs->vld;
+-	case NAND_DEV_CMD_VLD_RESTORE:
+-		return &regs->orig_vld;
+-	case NAND_EBI2_ECC_BUF_CFG:
+-		return &regs->ecc_buf_cfg;
+-	case NAND_READ_LOCATION_0:
+-		return &regs->read_location0;
+-	case NAND_READ_LOCATION_1:
+-		return &regs->read_location1;
+-	case NAND_READ_LOCATION_2:
+-		return &regs->read_location2;
+-	case NAND_READ_LOCATION_3:
+-		return &regs->read_location3;
+-	default:
+-		return NULL;
+-	}
+-}
+-
+-static void nandc_set_reg(struct qcom_nand_controller *nandc, int offset,
+-			  u32 val)
+-{
+-	struct nandc_regs *regs = nandc->regs;
+-	__le32 *reg;
+-
+-	reg = offset_to_nandc_reg(regs, offset);
+-
+-	if (reg)
+-		*reg = cpu_to_le32(val);
+-}
+-
+-/* helper to configure address register values */
+-static void set_address(struct qcom_nand_host *host, u16 column, int page)
+-{
+-	struct nand_chip *chip = &host->chip;
+-	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+-
+-	if (chip->options & NAND_BUSWIDTH_16)
+-		column >>= 1;
+-
+-	nandc_set_reg(nandc, NAND_ADDR0, page << 16 | column);
+-	nandc_set_reg(nandc, NAND_ADDR1, page >> 16 & 0xff);
+-}
+-
+-/*
+- * update_rw_regs:	set up read/write register values, these will be
+- *			written to the NAND controller registers via DMA
+- *
+- * @num_cw:		number of steps for the read/write operation
+- * @read:		read or write operation
+- */
+-static void update_rw_regs(struct qcom_nand_host *host, int num_cw, bool read)
+-{
+-	struct nand_chip *chip = &host->chip;
+-	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+-	u32 cmd, cfg0, cfg1, ecc_bch_cfg;
+-
+-	if (read) {
+-		if (host->use_ecc)
+-			cmd = PAGE_READ_WITH_ECC | PAGE_ACC | LAST_PAGE;
+-		else
+-			cmd = PAGE_READ | PAGE_ACC | LAST_PAGE;
+-	} else {
+-			cmd = PROGRAM_PAGE | PAGE_ACC | LAST_PAGE;
+-	}
+-
+-	if (host->use_ecc) {
+-		cfg0 = (host->cfg0 & ~(7U << CW_PER_PAGE)) |
+-				(num_cw - 1) << CW_PER_PAGE;
+-
+-		cfg1 = host->cfg1;
+-		ecc_bch_cfg = host->ecc_bch_cfg;
+-	} else {
+-		cfg0 = (host->cfg0_raw & ~(7U << CW_PER_PAGE)) |
+-				(num_cw - 1) << CW_PER_PAGE;
+-
+-		cfg1 = host->cfg1_raw;
+-		ecc_bch_cfg = 1 << ECC_CFG_ECC_DISABLE;
+-	}
+-
+-	nandc_set_reg(nandc, NAND_FLASH_CMD, cmd);
+-	nandc_set_reg(nandc, NAND_DEV0_CFG0, cfg0);
+-	nandc_set_reg(nandc, NAND_DEV0_CFG1, cfg1);
+-	nandc_set_reg(nandc, NAND_DEV0_ECC_CFG, ecc_bch_cfg);
+-	nandc_set_reg(nandc, NAND_EBI2_ECC_BUF_CFG, host->ecc_buf_cfg);
+-	nandc_set_reg(nandc, NAND_FLASH_STATUS, host->clrflashstatus);
+-	nandc_set_reg(nandc, NAND_READ_STATUS, host->clrreadstatus);
+-	nandc_set_reg(nandc, NAND_EXEC_CMD, 1);
+-
+-	if (read)
+-		nandc_set_read_loc(nandc, 0, 0, host->use_ecc ?
+-				   host->cw_data : host->cw_size, 1);
+-}
+-
+-/*
+- * Maps the scatter gather list for DMA transfer and forms the DMA descriptor
+- * for BAM. This descriptor will be added in the NAND DMA descriptor queue
+- * which will be submitted to DMA engine.
+- */
+-static int prepare_bam_async_desc(struct qcom_nand_controller *nandc,
+-				  struct dma_chan *chan,
+-				  unsigned long flags)
+-{
+-	struct desc_info *desc;
+-	struct scatterlist *sgl;
+-	unsigned int sgl_cnt;
+-	int ret;
+-	struct bam_transaction *bam_txn = nandc->bam_txn;
+-	enum dma_transfer_direction dir_eng;
+-	struct dma_async_tx_descriptor *dma_desc;
+-
+-	desc = kzalloc(sizeof(*desc), GFP_KERNEL);
+-	if (!desc)
+-		return -ENOMEM;
+-
+-	if (chan == nandc->cmd_chan) {
+-		sgl = &bam_txn->cmd_sgl[bam_txn->cmd_sgl_start];
+-		sgl_cnt = bam_txn->cmd_sgl_pos - bam_txn->cmd_sgl_start;
+-		bam_txn->cmd_sgl_start = bam_txn->cmd_sgl_pos;
+-		dir_eng = DMA_MEM_TO_DEV;
+-		desc->dir = DMA_TO_DEVICE;
+-	} else if (chan == nandc->tx_chan) {
+-		sgl = &bam_txn->data_sgl[bam_txn->tx_sgl_start];
+-		sgl_cnt = bam_txn->tx_sgl_pos - bam_txn->tx_sgl_start;
+-		bam_txn->tx_sgl_start = bam_txn->tx_sgl_pos;
+-		dir_eng = DMA_MEM_TO_DEV;
+-		desc->dir = DMA_TO_DEVICE;
+-	} else {
+-		sgl = &bam_txn->data_sgl[bam_txn->rx_sgl_start];
+-		sgl_cnt = bam_txn->rx_sgl_pos - bam_txn->rx_sgl_start;
+-		bam_txn->rx_sgl_start = bam_txn->rx_sgl_pos;
+-		dir_eng = DMA_DEV_TO_MEM;
+-		desc->dir = DMA_FROM_DEVICE;
+-	}
+-
+-	sg_mark_end(sgl + sgl_cnt - 1);
+-	ret = dma_map_sg(nandc->dev, sgl, sgl_cnt, desc->dir);
+-	if (ret == 0) {
+-		dev_err(nandc->dev, "failure in mapping desc\n");
+-		kfree(desc);
+-		return -ENOMEM;
+-	}
+-
+-	desc->sgl_cnt = sgl_cnt;
+-	desc->bam_sgl = sgl;
+-
+-	dma_desc = dmaengine_prep_slave_sg(chan, sgl, sgl_cnt, dir_eng,
+-					   flags);
+-
+-	if (!dma_desc) {
+-		dev_err(nandc->dev, "failure in prep desc\n");
+-		dma_unmap_sg(nandc->dev, sgl, sgl_cnt, desc->dir);
+-		kfree(desc);
+-		return -EINVAL;
+-	}
+-
+-	desc->dma_desc = dma_desc;
+-
+-	list_add_tail(&desc->node, &nandc->desc_list);
+-
+-	return 0;
+-}
+-
+-/*
+- * Prepares the data descriptor for BAM DMA which will be used for NAND
+- * data reads and writes.
+- */
+-static int prep_bam_dma_desc_data(struct qcom_nand_controller *nandc, bool read,
+-				  const void *vaddr,
+-				  int size, unsigned int flags)
+-{
+-	int ret;
+-	struct bam_transaction *bam_txn = nandc->bam_txn;
+-
+-	if (read) {
+-		sg_set_buf(&bam_txn->data_sgl[bam_txn->rx_sgl_pos],
+-			   vaddr, size);
+-		bam_txn->rx_sgl_pos++;
+-	} else {
+-		sg_set_buf(&bam_txn->data_sgl[bam_txn->tx_sgl_pos],
+-			   vaddr, size);
+-		bam_txn->tx_sgl_pos++;
+-
+-		/*
+-		 * BAM will only set EOT for DMA_PREP_INTERRUPT so if this flag
+-		 * is not set, form the DMA descriptor
+-		 */
+-		if (!(flags & NAND_BAM_NO_EOT)) {
+-			ret = prepare_bam_async_desc(nandc, nandc->tx_chan,
+-						     DMA_PREP_INTERRUPT);
+-			if (ret)
+-				return ret;
+-		}
+-	}
+-
+-	return 0;
+-}
+-
+-static int prep_adm_dma_desc(struct qcom_nand_controller *nandc, bool read,
+-			     int reg_off, const void *vaddr, int size,
+-			     bool flow_control)
+-{
+-	struct desc_info *desc;
+-	struct dma_async_tx_descriptor *dma_desc;
+-	struct scatterlist *sgl;
+-	struct dma_slave_config slave_conf;
+-	enum dma_transfer_direction dir_eng;
+-	int ret;
+-
+-	desc = kzalloc(sizeof(*desc), GFP_KERNEL);
+-	if (!desc)
+-		return -ENOMEM;
+-
+-	sgl = &desc->adm_sgl;
+-
+-	sg_init_one(sgl, vaddr, size);
+-
+-	if (read) {
+-		dir_eng = DMA_DEV_TO_MEM;
+-		desc->dir = DMA_FROM_DEVICE;
+-	} else {
+-		dir_eng = DMA_MEM_TO_DEV;
+-		desc->dir = DMA_TO_DEVICE;
+-	}
+-
+-	ret = dma_map_sg(nandc->dev, sgl, 1, desc->dir);
+-	if (ret == 0) {
+-		ret = -ENOMEM;
+-		goto err;
+-	}
+-
+-	memset(&slave_conf, 0x00, sizeof(slave_conf));
+-
+-	slave_conf.device_fc = flow_control;
+-	if (read) {
+-		slave_conf.src_maxburst = 16;
+-		slave_conf.src_addr = nandc->base_dma + reg_off;
+-		slave_conf.slave_id = nandc->data_crci;
+-	} else {
+-		slave_conf.dst_maxburst = 16;
+-		slave_conf.dst_addr = nandc->base_dma + reg_off;
+-		slave_conf.slave_id = nandc->cmd_crci;
+-	}
+-
+-	ret = dmaengine_slave_config(nandc->chan, &slave_conf);
+-	if (ret) {
+-		dev_err(nandc->dev, "failed to configure dma channel\n");
+-		goto err;
+-	}
+-
+-	dma_desc = dmaengine_prep_slave_sg(nandc->chan, sgl, 1, dir_eng, 0);
+-	if (!dma_desc) {
+-		dev_err(nandc->dev, "failed to prepare desc\n");
+-		ret = -EINVAL;
+-		goto err;
+-	}
+-
+-	desc->dma_desc = dma_desc;
+-
+-	list_add_tail(&desc->node, &nandc->desc_list);
+-
+-	return 0;
+-err:
+-	kfree(desc);
+-
+-	return ret;
+-}
+-
+-/*
+- * read_reg_dma:	prepares a descriptor to read a given number of
+- *			contiguous registers to the reg_read_buf pointer
+- *
+- * @first:		offset of the first register in the contiguous block
+- * @num_regs:		number of registers to read
+- * @flags:		flags to control DMA descriptor preparation
+- */
+-static int read_reg_dma(struct qcom_nand_controller *nandc, int first,
+-			int num_regs, unsigned int flags)
+-{
+-	bool flow_control = false;
+-	void *vaddr;
+-	int size;
+-
+-	if (first == NAND_READ_ID || first == NAND_FLASH_STATUS)
+-		flow_control = true;
+-
+-	if (first == NAND_DEV_CMD_VLD || first == NAND_DEV_CMD1)
+-		first = dev_cmd_reg_addr(nandc, first);
+-
+-	size = num_regs * sizeof(u32);
+-	vaddr = nandc->reg_read_buf + nandc->reg_read_pos;
+-	nandc->reg_read_pos += num_regs;
+-
+-	return prep_adm_dma_desc(nandc, true, first, vaddr, size, flow_control);
+-}
+-
+-/*
+- * write_reg_dma:	prepares a descriptor to write a given number of
+- *			contiguous registers
+- *
+- * @first:		offset of the first register in the contiguous block
+- * @num_regs:		number of registers to write
+- * @flags:		flags to control DMA descriptor preparation
+- */
+-static int write_reg_dma(struct qcom_nand_controller *nandc, int first,
+-			 int num_regs, unsigned int flags)
+-{
+-	bool flow_control = false;
+-	struct nandc_regs *regs = nandc->regs;
+-	void *vaddr;
+-	int size;
+-
+-	vaddr = offset_to_nandc_reg(regs, first);
+-
+-	if (first == NAND_FLASH_CMD)
+-		flow_control = true;
+-
+-	if (first == NAND_ERASED_CW_DETECT_CFG) {
+-		if (flags & NAND_ERASED_CW_SET)
+-			vaddr = &regs->erased_cw_detect_cfg_set;
+-		else
+-			vaddr = &regs->erased_cw_detect_cfg_clr;
+-	}
+-
+-	if (first == NAND_EXEC_CMD)
+-		flags |= NAND_BAM_NWD;
+-
+-	if (first == NAND_DEV_CMD1_RESTORE || first == NAND_DEV_CMD1)
+-		first = dev_cmd_reg_addr(nandc, NAND_DEV_CMD1);
+-
+-	if (first == NAND_DEV_CMD_VLD_RESTORE || first == NAND_DEV_CMD_VLD)
+-		first = dev_cmd_reg_addr(nandc, NAND_DEV_CMD_VLD);
+-
+-	size = num_regs * sizeof(u32);
+-
+-	return prep_adm_dma_desc(nandc, false, first, vaddr, size,
+-				 flow_control);
+-}
+-
+-/*
+- * read_data_dma:	prepares a DMA descriptor to transfer data from the
+- *			controller's internal buffer to the buffer 'vaddr'
+- *
+- * @reg_off:		offset within the controller's data buffer
+- * @vaddr:		virtual address of the buffer we want to write to
+- * @size:		DMA transaction size in bytes
+- * @flags:		flags to control DMA descriptor preparation
+- */
+-static int read_data_dma(struct qcom_nand_controller *nandc, int reg_off,
+-			 const u8 *vaddr, int size, unsigned int flags)
+-{
+-	if (nandc->props->is_bam)
+-		return prep_bam_dma_desc_data(nandc, true, vaddr, size, flags);
+-
+-	return prep_adm_dma_desc(nandc, true, reg_off, vaddr, size, false);
+-}
+-
+-/*
+- * write_data_dma:	prepares a DMA descriptor to transfer data from
+- *			'vaddr' to the controller's internal buffer
+- *
+- * @reg_off:		offset within the controller's data buffer
+- * @vaddr:		virtual address of the buffer we want to read from
+- * @size:		DMA transaction size in bytes
+- * @flags:		flags to control DMA descriptor preparation
+- */
+-static int write_data_dma(struct qcom_nand_controller *nandc, int reg_off,
+-			  const u8 *vaddr, int size, unsigned int flags)
+-{
+-	if (nandc->props->is_bam)
+-		return prep_bam_dma_desc_data(nandc, false, vaddr, size, flags);
+-
+-	return prep_adm_dma_desc(nandc, false, reg_off, vaddr, size, false);
+-}
+-
+-/*
+- * Helper to prepare DMA descriptors for configuring registers
+- * before reading a NAND page.
+- */
+-static void config_nand_page_read(struct qcom_nand_controller *nandc)
+-{
+-	write_reg_dma(nandc, NAND_ADDR0, 2, 0);
+-	write_reg_dma(nandc, NAND_DEV0_CFG0, 3, 0);
+-	write_reg_dma(nandc, NAND_EBI2_ECC_BUF_CFG, 1, 0);
+-	write_reg_dma(nandc, NAND_ERASED_CW_DETECT_CFG, 1, 0);
+-	write_reg_dma(nandc, NAND_ERASED_CW_DETECT_CFG, 1,
+-		      NAND_ERASED_CW_SET | NAND_BAM_NEXT_SGL);
+-}
+-
+-/*
+- * Helper to prepare DMA descriptors for configuring registers
+- * before reading each codeword in NAND page.
+- */
+-static void config_nand_cw_read(struct qcom_nand_controller *nandc)
+-{
+-	if (nandc->props->is_bam)
+-		write_reg_dma(nandc, NAND_READ_LOCATION_0, 4,
+-			      NAND_BAM_NEXT_SGL);
+-
+-	write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
+-	write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
+-
+-	read_reg_dma(nandc, NAND_FLASH_STATUS, 2, 0);
+-	read_reg_dma(nandc, NAND_ERASED_CW_DETECT_STATUS, 1,
+-		     NAND_BAM_NEXT_SGL);
+-}
+-
+-/*
+- * Helper to prepare dma descriptors to configure registers needed for reading a
+- * single codeword in page
+- */
+-static void config_nand_single_cw_page_read(struct qcom_nand_controller *nandc)
+-{
+-	config_nand_page_read(nandc);
+-	config_nand_cw_read(nandc);
+-}
+-
+-/*
+- * Helper to prepare DMA descriptors used to configure registers needed for
+- * before writing a NAND page.
+- */
+-static void config_nand_page_write(struct qcom_nand_controller *nandc)
+-{
+-	write_reg_dma(nandc, NAND_ADDR0, 2, 0);
+-	write_reg_dma(nandc, NAND_DEV0_CFG0, 3, 0);
+-	write_reg_dma(nandc, NAND_EBI2_ECC_BUF_CFG, 1,
+-		      NAND_BAM_NEXT_SGL);
+-}
+-
+-/*
+- * Helper to prepare DMA descriptors for configuring registers
+- * before writing each codeword in NAND page.
+- */
+-static void config_nand_cw_write(struct qcom_nand_controller *nandc)
+-{
+-	write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
+-	write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
+-
+-	read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
+-
+-	write_reg_dma(nandc, NAND_FLASH_STATUS, 1, 0);
+-	write_reg_dma(nandc, NAND_READ_STATUS, 1, NAND_BAM_NEXT_SGL);
+-}
+-
+-/*
+- * the following functions are used within chip->cmdfunc() to perform different
+- * NAND_CMD_* commands
+- */
+-
+-/* sets up descriptors for NAND_CMD_PARAM */
+-static int nandc_param(struct qcom_nand_host *host)
+-{
+-	struct nand_chip *chip = &host->chip;
+-	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+-
+-	/*
+-	 * NAND_CMD_PARAM is called before we know much about the FLASH chip
+-	 * in use. we configure the controller to perform a raw read of 512
+-	 * bytes to read onfi params
+-	 */
+-	nandc_set_reg(nandc, NAND_FLASH_CMD, PAGE_READ | PAGE_ACC | LAST_PAGE);
+-	nandc_set_reg(nandc, NAND_ADDR0, 0);
+-	nandc_set_reg(nandc, NAND_ADDR1, 0);
+-	nandc_set_reg(nandc, NAND_DEV0_CFG0, 0 << CW_PER_PAGE
+-					| 512 << UD_SIZE_BYTES
+-					| 5 << NUM_ADDR_CYCLES
+-					| 0 << SPARE_SIZE_BYTES);
+-	nandc_set_reg(nandc, NAND_DEV0_CFG1, 7 << NAND_RECOVERY_CYCLES
+-					| 0 << CS_ACTIVE_BSY
+-					| 17 << BAD_BLOCK_BYTE_NUM
+-					| 1 << BAD_BLOCK_IN_SPARE_AREA
+-					| 2 << WR_RD_BSY_GAP
+-					| 0 << WIDE_FLASH
+-					| 1 << DEV0_CFG1_ECC_DISABLE);
+-	nandc_set_reg(nandc, NAND_EBI2_ECC_BUF_CFG, 1 << ECC_CFG_ECC_DISABLE);
+-
+-	/* configure CMD1 and VLD for ONFI param probing */
+-	nandc_set_reg(nandc, NAND_DEV_CMD_VLD,
+-		      (nandc->vld & ~READ_START_VLD));
+-	nandc_set_reg(nandc, NAND_DEV_CMD1,
+-		      (nandc->cmd1 & ~(0xFF << READ_ADDR))
+-		      | NAND_CMD_PARAM << READ_ADDR);
+-
+-	nandc_set_reg(nandc, NAND_EXEC_CMD, 1);
+-
+-	nandc_set_reg(nandc, NAND_DEV_CMD1_RESTORE, nandc->cmd1);
+-	nandc_set_reg(nandc, NAND_DEV_CMD_VLD_RESTORE, nandc->vld);
+-	nandc_set_read_loc(nandc, 0, 0, 512, 1);
+-
+-	write_reg_dma(nandc, NAND_DEV_CMD_VLD, 1, 0);
+-	write_reg_dma(nandc, NAND_DEV_CMD1, 1, NAND_BAM_NEXT_SGL);
+-
+-	nandc->buf_count = 512;
+-	memset(nandc->data_buffer, 0xff, nandc->buf_count);
+-
+-	config_nand_single_cw_page_read(nandc);
+-
+-	read_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer,
+-		      nandc->buf_count, 0);
+-
+-	/* restore CMD1 and VLD regs */
+-	write_reg_dma(nandc, NAND_DEV_CMD1_RESTORE, 1, 0);
+-	write_reg_dma(nandc, NAND_DEV_CMD_VLD_RESTORE, 1, NAND_BAM_NEXT_SGL);
+-
+-	return 0;
+-}
+-
+-/* sets up descriptors for NAND_CMD_ERASE1 */
+-static int erase_block(struct qcom_nand_host *host, int page_addr)
+-{
+-	struct nand_chip *chip = &host->chip;
+-	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+-
+-	nandc_set_reg(nandc, NAND_FLASH_CMD,
+-		      BLOCK_ERASE | PAGE_ACC | LAST_PAGE);
+-	nandc_set_reg(nandc, NAND_ADDR0, page_addr);
+-	nandc_set_reg(nandc, NAND_ADDR1, 0);
+-	nandc_set_reg(nandc, NAND_DEV0_CFG0,
+-		      host->cfg0_raw & ~(7 << CW_PER_PAGE));
+-	nandc_set_reg(nandc, NAND_DEV0_CFG1, host->cfg1_raw);
+-	nandc_set_reg(nandc, NAND_EXEC_CMD, 1);
+-	nandc_set_reg(nandc, NAND_FLASH_STATUS, host->clrflashstatus);
+-	nandc_set_reg(nandc, NAND_READ_STATUS, host->clrreadstatus);
+-
+-	write_reg_dma(nandc, NAND_FLASH_CMD, 3, NAND_BAM_NEXT_SGL);
+-	write_reg_dma(nandc, NAND_DEV0_CFG0, 2, NAND_BAM_NEXT_SGL);
+-	write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
+-
+-	read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
+-
+-	write_reg_dma(nandc, NAND_FLASH_STATUS, 1, 0);
+-	write_reg_dma(nandc, NAND_READ_STATUS, 1, NAND_BAM_NEXT_SGL);
+-
+-	return 0;
+-}
+-
+-/* sets up descriptors for NAND_CMD_READID */
+-static int read_id(struct qcom_nand_host *host, int column)
+-{
+-	struct nand_chip *chip = &host->chip;
+-	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+-
+-	if (column == -1)
+-		return 0;
+-
+-	nandc_set_reg(nandc, NAND_FLASH_CMD, FETCH_ID);
+-	nandc_set_reg(nandc, NAND_ADDR0, column);
+-	nandc_set_reg(nandc, NAND_ADDR1, 0);
+-	nandc_set_reg(nandc, NAND_FLASH_CHIP_SELECT,
+-		      nandc->props->is_bam ? 0 : DM_EN);
+-	nandc_set_reg(nandc, NAND_EXEC_CMD, 1);
+-
+-	write_reg_dma(nandc, NAND_FLASH_CMD, 4, NAND_BAM_NEXT_SGL);
+-	write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
+-
+-	read_reg_dma(nandc, NAND_READ_ID, 1, NAND_BAM_NEXT_SGL);
+-
+-	return 0;
+-}
+-
+-/* sets up descriptors for NAND_CMD_RESET */
+-static int reset(struct qcom_nand_host *host)
+-{
+-	struct nand_chip *chip = &host->chip;
+-	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+-
+-	nandc_set_reg(nandc, NAND_FLASH_CMD, RESET_DEVICE);
+-	nandc_set_reg(nandc, NAND_EXEC_CMD, 1);
+-
+-	write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
+-	write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
+-
+-	read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
+-
+-	return 0;
+-}
+-
+-/* helpers to submit/free our list of dma descriptors */
+-static int submit_descs(struct qcom_nand_controller *nandc)
+-{
+-	struct desc_info *desc;
+-	dma_cookie_t cookie = 0;
+-	struct bam_transaction *bam_txn = nandc->bam_txn;
+-	int r;
+-
+-	if (nandc->props->is_bam) {
+-		if (bam_txn->rx_sgl_pos > bam_txn->rx_sgl_start) {
+-			r = prepare_bam_async_desc(nandc, nandc->rx_chan, 0);
+-			if (r)
+-				return r;
+-		}
+-
+-		if (bam_txn->tx_sgl_pos > bam_txn->tx_sgl_start) {
+-			r = prepare_bam_async_desc(nandc, nandc->tx_chan,
+-						   DMA_PREP_INTERRUPT);
+-			if (r)
+-				return r;
+-		}
+-
+-		if (bam_txn->cmd_sgl_pos > bam_txn->cmd_sgl_start) {
+-			r = prepare_bam_async_desc(nandc, nandc->cmd_chan, 0);
+-			if (r)
+-				return r;
+-		}
+-	}
+-
+-	list_for_each_entry(desc, &nandc->desc_list, node)
+-		cookie = dmaengine_submit(desc->dma_desc);
+-
+-	if (nandc->props->is_bam) {
+-		dma_async_issue_pending(nandc->tx_chan);
+-		dma_async_issue_pending(nandc->rx_chan);
+-
+-		if (dma_sync_wait(nandc->cmd_chan, cookie) != DMA_COMPLETE)
+-			return -ETIMEDOUT;
+-	} else {
+-		if (dma_sync_wait(nandc->chan, cookie) != DMA_COMPLETE)
+-			return -ETIMEDOUT;
+-	}
+-
+-	return 0;
+-}
+-
+-static void free_descs(struct qcom_nand_controller *nandc)
+-{
+-	struct desc_info *desc, *n;
+-
+-	list_for_each_entry_safe(desc, n, &nandc->desc_list, node) {
+-		list_del(&desc->node);
+-
+-		if (nandc->props->is_bam)
+-			dma_unmap_sg(nandc->dev, desc->bam_sgl,
+-				     desc->sgl_cnt, desc->dir);
+-		else
+-			dma_unmap_sg(nandc->dev, &desc->adm_sgl, 1,
+-				     desc->dir);
+-
+-		kfree(desc);
+-	}
+-}
+-
+-/* reset the register read buffer for next NAND operation */
+-static void clear_read_regs(struct qcom_nand_controller *nandc)
+-{
+-	nandc->reg_read_pos = 0;
+-	nandc_read_buffer_sync(nandc, false);
+-}
+-
+-static void pre_command(struct qcom_nand_host *host, int command)
+-{
+-	struct nand_chip *chip = &host->chip;
+-	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+-
+-	nandc->buf_count = 0;
+-	nandc->buf_start = 0;
+-	host->use_ecc = false;
+-	host->last_command = command;
+-
+-	clear_read_regs(nandc);
+-
+-	if (command == NAND_CMD_RESET || command == NAND_CMD_READID ||
+-	    command == NAND_CMD_PARAM || command == NAND_CMD_ERASE1)
+-		clear_bam_transaction(nandc);
+-}
+-
+-/*
+- * this is called after NAND_CMD_PAGEPROG and NAND_CMD_ERASE1 to set our
+- * privately maintained status byte, this status byte can be read after
+- * NAND_CMD_STATUS is called
+- */
+-static void parse_erase_write_errors(struct qcom_nand_host *host, int command)
+-{
+-	struct nand_chip *chip = &host->chip;
+-	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+-	struct nand_ecc_ctrl *ecc = &chip->ecc;
+-	int num_cw;
+-	int i;
+-
+-	num_cw = command == NAND_CMD_PAGEPROG ? ecc->steps : 1;
+-	nandc_read_buffer_sync(nandc, true);
+-
+-	for (i = 0; i < num_cw; i++) {
+-		u32 flash_status = le32_to_cpu(nandc->reg_read_buf[i]);
+-
+-		if (flash_status & FS_MPU_ERR)
+-			host->status &= ~NAND_STATUS_WP;
+-
+-		if (flash_status & FS_OP_ERR || (i == (num_cw - 1) &&
+-						 (flash_status &
+-						  FS_DEVICE_STS_ERR)))
+-			host->status |= NAND_STATUS_FAIL;
+-	}
+-}
+-
+-static void post_command(struct qcom_nand_host *host, int command)
+-{
+-	struct nand_chip *chip = &host->chip;
+-	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+-
+-	switch (command) {
+-	case NAND_CMD_READID:
+-		nandc_read_buffer_sync(nandc, true);
+-		memcpy(nandc->data_buffer, nandc->reg_read_buf,
+-		       nandc->buf_count);
+-		break;
+-	case NAND_CMD_PAGEPROG:
+-	case NAND_CMD_ERASE1:
+-		parse_erase_write_errors(host, command);
+-		break;
+-	default:
+-		break;
+-	}
+-}
+-
+-/*
+- * Implements chip->cmdfunc. It's  only used for a limited set of commands.
+- * The rest of the commands wouldn't be called by upper layers. For example,
+- * NAND_CMD_READOOB would never be called because we have our own versions
+- * of read_oob ops for nand_ecc_ctrl.
+- */
+-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 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);
+-	bool wait = false;
+-	int ret = 0;
+-
+-	pre_command(host, command);
+-
+-	switch (command) {
+-	case NAND_CMD_RESET:
+-		ret = reset(host);
+-		wait = true;
+-		break;
+-
+-	case NAND_CMD_READID:
+-		nandc->buf_count = 4;
+-		ret = read_id(host, column);
+-		wait = true;
+-		break;
+-
+-	case NAND_CMD_PARAM:
+-		ret = nandc_param(host);
+-		wait = true;
+-		break;
+-
+-	case NAND_CMD_ERASE1:
+-		ret = erase_block(host, page_addr);
+-		wait = true;
+-		break;
+-
+-	case NAND_CMD_READ0:
+-		/* we read the entire page for now */
+-		WARN_ON(column != 0);
+-
+-		host->use_ecc = true;
+-		set_address(host, 0, page_addr);
+-		update_rw_regs(host, ecc->steps, true);
+-		break;
+-
+-	case NAND_CMD_SEQIN:
+-		WARN_ON(column != 0);
+-		set_address(host, 0, page_addr);
+-		break;
+-
+-	case NAND_CMD_PAGEPROG:
+-	case NAND_CMD_STATUS:
+-	case NAND_CMD_NONE:
+-	default:
+-		break;
+-	}
+-
+-	if (ret) {
+-		dev_err(nandc->dev, "failure executing command %d\n",
+-			command);
+-		free_descs(nandc);
+-		return;
+-	}
+-
+-	if (wait) {
+-		ret = submit_descs(nandc);
+-		if (ret)
+-			dev_err(nandc->dev,
+-				"failure submitting descs for command %d\n",
+-				command);
+-	}
+-
+-	free_descs(nandc);
+-
+-	post_command(host, command);
+-}
+-
+-/*
+- * when using BCH ECC, the HW flags an error in NAND_FLASH_STATUS if it read
+- * an erased CW, and reports an erased CW in NAND_ERASED_CW_DETECT_STATUS.
+- *
+- * when using RS ECC, the HW reports the same erros when reading an erased CW,
+- * but it notifies that it is an erased CW by placing special characters at
+- * certain offsets in the buffer.
+- *
+- * verify if the page is erased or not, and fix up the page for RS ECC by
+- * replacing the special characters with 0xff.
+- */
+-static bool erased_chunk_check_and_fixup(u8 *data_buf, int data_len)
+-{
+-	u8 empty1, empty2;
+-
+-	/*
+-	 * an erased page flags an error in NAND_FLASH_STATUS, check if the page
+-	 * is erased by looking for 0x54s at offsets 3 and 175 from the
+-	 * beginning of each codeword
+-	 */
+-
+-	empty1 = data_buf[3];
+-	empty2 = data_buf[175];
+-
+-	/*
+-	 * if the erased codework markers, if they exist override them with
+-	 * 0xffs
+-	 */
+-	if ((empty1 == 0x54 && empty2 == 0xff) ||
+-	    (empty1 == 0xff && empty2 == 0x54)) {
+-		data_buf[3] = 0xff;
+-		data_buf[175] = 0xff;
+-	}
+-
+-	/*
+-	 * check if the entire chunk contains 0xffs or not. if it doesn't, then
+-	 * restore the original values at the special offsets
+-	 */
+-	if (memchr_inv(data_buf, 0xff, data_len)) {
+-		data_buf[3] = empty1;
+-		data_buf[175] = empty2;
+-
+-		return false;
+-	}
+-
+-	return true;
+-}
+-
+-struct read_stats {
+-	__le32 flash;
+-	__le32 buffer;
+-	__le32 erased_cw;
+-};
+-
+-/*
+- * reads back status registers set by the controller to notify page read
+- * errors. this is equivalent to what 'ecc->correct()' would do.
+- */
+-static int parse_read_errors(struct qcom_nand_host *host, u8 *data_buf,
+-			     u8 *oob_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 nand_ecc_ctrl *ecc = &chip->ecc;
+-	unsigned int max_bitflips = 0;
+-	struct read_stats *buf;
+-	int i;
+-
+-	buf = (struct read_stats *)nandc->reg_read_buf;
+-	nandc_read_buffer_sync(nandc, true);
+-
+-	for (i = 0; i < ecc->steps; i++, buf++) {
+-		u32 flash, buffer, erased_cw;
+-		int data_len, oob_len;
+-
+-		if (i == (ecc->steps - 1)) {
+-			data_len = ecc->size - ((ecc->steps - 1) << 2);
+-			oob_len = ecc->steps << 2;
+-		} else {
+-			data_len = host->cw_data;
+-			oob_len = 0;
+-		}
+-
+-		flash = le32_to_cpu(buf->flash);
+-		buffer = le32_to_cpu(buf->buffer);
+-		erased_cw = le32_to_cpu(buf->erased_cw);
+-
+-		if (flash & (FS_OP_ERR | FS_MPU_ERR)) {
+-			bool erased;
+-
+-			/* ignore erased codeword errors */
+-			if (host->bch_enabled) {
+-				erased = (erased_cw & ERASED_CW) == ERASED_CW ?
+-					 true : false;
+-			} else {
+-				erased = erased_chunk_check_and_fixup(data_buf,
+-								      data_len);
+-			}
+-
+-			if (erased) {
+-				data_buf += data_len;
+-				if (oob_buf)
+-					oob_buf += oob_len + ecc->bytes;
+-				continue;
+-			}
+-
+-			if (buffer & BS_UNCORRECTABLE_BIT) {
+-				int ret, ecclen, extraooblen;
+-				void *eccbuf;
+-
+-				eccbuf = oob_buf ? oob_buf + oob_len : NULL;
+-				ecclen = oob_buf ? host->ecc_bytes_hw : 0;
+-				extraooblen = oob_buf ? oob_len : 0;
+-
+-				/*
+-				 * make sure it isn't an erased page reported
+-				 * as not-erased by HW because of a few bitflips
+-				 */
+-				ret = nand_check_erased_ecc_chunk(data_buf,
+-					data_len, eccbuf, ecclen, oob_buf,
+-					extraooblen, ecc->strength);
+-				if (ret < 0) {
+-					mtd->ecc_stats.failed++;
+-				} else {
+-					mtd->ecc_stats.corrected += ret;
+-					max_bitflips =
+-						max_t(unsigned int, max_bitflips, ret);
+-				}
+-			}
+-		} else {
+-			unsigned int stat;
+-
+-			stat = buffer & BS_CORRECTABLE_ERR_MSK;
+-			mtd->ecc_stats.corrected += stat;
+-			max_bitflips = max(max_bitflips, stat);
+-		}
+-
+-		data_buf += data_len;
+-		if (oob_buf)
+-			oob_buf += oob_len + ecc->bytes;
+-	}
+-
+-	return max_bitflips;
+-}
+-
+-/*
+- * helper to perform the actual page read operation, used by ecc->read_page(),
+- * ecc->read_oob()
+- */
+-static int read_page_ecc(struct qcom_nand_host *host, u8 *data_buf,
+-			 u8 *oob_buf)
+-{
+-	struct nand_chip *chip = &host->chip;
+-	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+-	struct nand_ecc_ctrl *ecc = &chip->ecc;
+-	int i, ret;
+-
+-	config_nand_page_read(nandc);
+-
+-	/* queue cmd descs for each codeword */
+-	for (i = 0; i < ecc->steps; i++) {
+-		int data_size, oob_size;
+-
+-		if (i == (ecc->steps - 1)) {
+-			data_size = ecc->size - ((ecc->steps - 1) << 2);
+-			oob_size = (ecc->steps << 2) + host->ecc_bytes_hw +
+-				   host->spare_bytes;
+-		} else {
+-			data_size = host->cw_data;
+-			oob_size = host->ecc_bytes_hw + host->spare_bytes;
+-		}
+-
+-		if (nandc->props->is_bam) {
+-			if (data_buf && oob_buf) {
+-				nandc_set_read_loc(nandc, 0, 0, data_size, 0);
+-				nandc_set_read_loc(nandc, 1, data_size,
+-						   oob_size, 1);
+-			} else if (data_buf) {
+-				nandc_set_read_loc(nandc, 0, 0, data_size, 1);
+-			} else {
+-				nandc_set_read_loc(nandc, 0, data_size,
+-						   oob_size, 1);
+-			}
+-		}
+-
+-		config_nand_cw_read(nandc);
+-
+-		if (data_buf)
+-			read_data_dma(nandc, FLASH_BUF_ACC, data_buf,
+-				      data_size, 0);
+-
+-		/*
+-		 * when ecc is enabled, the controller doesn't read the real
+-		 * or dummy bad block markers in each chunk. To maintain a
+-		 * consistent layout across RAW and ECC reads, we just
+-		 * leave the real/dummy BBM offsets empty (i.e, filled with
+-		 * 0xffs)
+-		 */
+-		if (oob_buf) {
+-			int j;
+-
+-			for (j = 0; j < host->bbm_size; j++)
+-				*oob_buf++ = 0xff;
+-
+-			read_data_dma(nandc, FLASH_BUF_ACC + data_size,
+-				      oob_buf, oob_size, 0);
+-		}
+-
+-		if (data_buf)
+-			data_buf += data_size;
+-		if (oob_buf)
+-			oob_buf += oob_size;
+-	}
+-
+-	ret = submit_descs(nandc);
+-	if (ret)
+-		dev_err(nandc->dev, "failure to read page/oob\n");
+-
+-	free_descs(nandc);
+-
+-	return ret;
+-}
+-
+-/*
+- * a helper that copies the last step/codeword of a page (containing free oob)
+- * into our local buffer
+- */
+-static int copy_last_cw(struct qcom_nand_host *host, int page)
+-{
+-	struct nand_chip *chip = &host->chip;
+-	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+-	struct nand_ecc_ctrl *ecc = &chip->ecc;
+-	int size;
+-	int ret;
+-
+-	clear_read_regs(nandc);
+-
+-	size = host->use_ecc ? host->cw_data : host->cw_size;
+-
+-	/* prepare a clean read buffer */
+-	memset(nandc->data_buffer, 0xff, size);
+-
+-	set_address(host, host->cw_size * (ecc->steps - 1), page);
+-	update_rw_regs(host, 1, true);
+-
+-	config_nand_single_cw_page_read(nandc);
+-
+-	read_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer, size, 0);
+-
+-	ret = submit_descs(nandc);
+-	if (ret)
+-		dev_err(nandc->dev, "failed to copy last codeword\n");
+-
+-	free_descs(nandc);
+-
+-	return ret;
+-}
+-
+-/* implements ecc->read_page() */
+-static int qcom_nandc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
+-				uint8_t *buf, int oob_required, int page)
+-{
+-	struct qcom_nand_host *host = to_qcom_nand_host(chip);
+-	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+-	u8 *data_buf, *oob_buf = NULL;
+-	int ret;
+-
+-	data_buf = buf;
+-	oob_buf = oob_required ? chip->oob_poi : NULL;
+-
+-	clear_bam_transaction(nandc);
+-	ret = read_page_ecc(host, data_buf, oob_buf);
+-	if (ret) {
+-		dev_err(nandc->dev, "failure to read page\n");
+-		return ret;
+-	}
+-
+-	return parse_read_errors(host, data_buf, oob_buf);
+-}
+-
+-/* implements ecc->read_page_raw() */
+-static int qcom_nandc_read_page_raw(struct mtd_info *mtd,
+-				    struct nand_chip *chip, uint8_t *buf,
+-				    int oob_required, int page)
+-{
+-	struct qcom_nand_host *host = to_qcom_nand_host(chip);
+-	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+-	u8 *data_buf, *oob_buf;
+-	struct nand_ecc_ctrl *ecc = &chip->ecc;
+-	int i, ret;
+-	int read_loc;
+-
+-	data_buf = buf;
+-	oob_buf = chip->oob_poi;
+-
+-	host->use_ecc = false;
+-
+-	clear_bam_transaction(nandc);
+-	update_rw_regs(host, ecc->steps, true);
+-	config_nand_page_read(nandc);
+-
+-	for (i = 0; i < ecc->steps; i++) {
+-		int data_size1, data_size2, oob_size1, oob_size2;
+-		int reg_off = FLASH_BUF_ACC;
+-
+-		data_size1 = mtd->writesize - host->cw_size * (ecc->steps - 1);
+-		oob_size1 = host->bbm_size;
+-
+-		if (i == (ecc->steps - 1)) {
+-			data_size2 = ecc->size - data_size1 -
+-				     ((ecc->steps - 1) << 2);
+-			oob_size2 = (ecc->steps << 2) + host->ecc_bytes_hw +
+-				    host->spare_bytes;
+-		} else {
+-			data_size2 = host->cw_data - data_size1;
+-			oob_size2 = host->ecc_bytes_hw + host->spare_bytes;
+-		}
+-
+-		if (nandc->props->is_bam) {
+-			read_loc = 0;
+-			nandc_set_read_loc(nandc, 0, read_loc, data_size1, 0);
+-			read_loc += data_size1;
+-
+-			nandc_set_read_loc(nandc, 1, read_loc, oob_size1, 0);
+-			read_loc += oob_size1;
+-
+-			nandc_set_read_loc(nandc, 2, read_loc, data_size2, 0);
+-			read_loc += data_size2;
+-
+-			nandc_set_read_loc(nandc, 3, read_loc, oob_size2, 1);
+-		}
+-
+-		config_nand_cw_read(nandc);
+-
+-		read_data_dma(nandc, reg_off, data_buf, data_size1, 0);
+-		reg_off += data_size1;
+-		data_buf += data_size1;
+-
+-		read_data_dma(nandc, reg_off, oob_buf, oob_size1, 0);
+-		reg_off += oob_size1;
+-		oob_buf += oob_size1;
+-
+-		read_data_dma(nandc, reg_off, data_buf, data_size2, 0);
+-		reg_off += data_size2;
+-		data_buf += data_size2;
+-
+-		read_data_dma(nandc, reg_off, oob_buf, oob_size2, 0);
+-		oob_buf += oob_size2;
+-	}
+-
+-	ret = submit_descs(nandc);
+-	if (ret)
+-		dev_err(nandc->dev, "failure to read raw page\n");
+-
+-	free_descs(nandc);
+-
+-	return 0;
+-}
+-
+-/* implements ecc->read_oob() */
+-static int qcom_nandc_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
+-			       int page)
+-{
+-	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;
+-	int ret;
+-
+-	clear_read_regs(nandc);
+-	clear_bam_transaction(nandc);
+-
+-	host->use_ecc = true;
+-	set_address(host, 0, page);
+-	update_rw_regs(host, ecc->steps, true);
+-
+-	ret = read_page_ecc(host, NULL, chip->oob_poi);
+-	if (ret)
+-		dev_err(nandc->dev, "failure to read oob\n");
+-
+-	return ret;
+-}
+-
+-/* implements ecc->write_page() */
+-static int qcom_nandc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
+-				 const uint8_t *buf, int oob_required, int page)
+-{
+-	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;
+-	u8 *data_buf, *oob_buf;
+-	int i, ret;
+-
+-	clear_read_regs(nandc);
+-	clear_bam_transaction(nandc);
+-
+-	data_buf = (u8 *)buf;
+-	oob_buf = chip->oob_poi;
+-
+-	host->use_ecc = true;
+-	update_rw_regs(host, ecc->steps, false);
+-	config_nand_page_write(nandc);
+-
+-	for (i = 0; i < ecc->steps; i++) {
+-		int data_size, oob_size;
+-
+-		if (i == (ecc->steps - 1)) {
+-			data_size = ecc->size - ((ecc->steps - 1) << 2);
+-			oob_size = (ecc->steps << 2) + host->ecc_bytes_hw +
+-				   host->spare_bytes;
+-		} else {
+-			data_size = host->cw_data;
+-			oob_size = ecc->bytes;
+-		}
+-
+-
+-		write_data_dma(nandc, FLASH_BUF_ACC, data_buf, data_size,
+-			       i == (ecc->steps - 1) ? NAND_BAM_NO_EOT : 0);
+-
+-		/*
+-		 * when ECC is enabled, we don't really need to write anything
+-		 * to oob for the first n - 1 codewords since these oob regions
+-		 * just contain ECC bytes that's written by the controller
+-		 * itself. For the last codeword, we skip the bbm positions and
+-		 * write to the free oob area.
+-		 */
+-		if (i == (ecc->steps - 1)) {
+-			oob_buf += host->bbm_size;
+-
+-			write_data_dma(nandc, FLASH_BUF_ACC + data_size,
+-				       oob_buf, oob_size, 0);
+-		}
+-
+-		config_nand_cw_write(nandc);
+-
+-		data_buf += data_size;
+-		oob_buf += oob_size;
+-	}
+-
+-	ret = submit_descs(nandc);
+-	if (ret)
+-		dev_err(nandc->dev, "failure to write page\n");
+-
+-	free_descs(nandc);
+-
+-	return ret;
+-}
+-
+-/* implements ecc->write_page_raw() */
+-static int qcom_nandc_write_page_raw(struct mtd_info *mtd,
+-				     struct nand_chip *chip, const uint8_t *buf,
+-				     int oob_required, int page)
+-{
+-	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;
+-	u8 *data_buf, *oob_buf;
+-	int i, ret;
+-
+-	clear_read_regs(nandc);
+-	clear_bam_transaction(nandc);
+-
+-	data_buf = (u8 *)buf;
+-	oob_buf = chip->oob_poi;
+-
+-	host->use_ecc = false;
+-	update_rw_regs(host, ecc->steps, false);
+-	config_nand_page_write(nandc);
+-
+-	for (i = 0; i < ecc->steps; i++) {
+-		int data_size1, data_size2, oob_size1, oob_size2;
+-		int reg_off = FLASH_BUF_ACC;
+-
+-		data_size1 = mtd->writesize - host->cw_size * (ecc->steps - 1);
+-		oob_size1 = host->bbm_size;
+-
+-		if (i == (ecc->steps - 1)) {
+-			data_size2 = ecc->size - data_size1 -
+-				     ((ecc->steps - 1) << 2);
+-			oob_size2 = (ecc->steps << 2) + host->ecc_bytes_hw +
+-				    host->spare_bytes;
+-		} else {
+-			data_size2 = host->cw_data - data_size1;
+-			oob_size2 = host->ecc_bytes_hw + host->spare_bytes;
+-		}
+-
+-		write_data_dma(nandc, reg_off, data_buf, data_size1,
+-			       NAND_BAM_NO_EOT);
+-		reg_off += data_size1;
+-		data_buf += data_size1;
+-
+-		write_data_dma(nandc, reg_off, oob_buf, oob_size1,
+-			       NAND_BAM_NO_EOT);
+-		reg_off += oob_size1;
+-		oob_buf += oob_size1;
+-
+-		write_data_dma(nandc, reg_off, data_buf, data_size2,
+-			       NAND_BAM_NO_EOT);
+-		reg_off += data_size2;
+-		data_buf += data_size2;
+-
+-		write_data_dma(nandc, reg_off, oob_buf, oob_size2, 0);
+-		oob_buf += oob_size2;
+-
+-		config_nand_cw_write(nandc);
+-	}
+-
+-	ret = submit_descs(nandc);
+-	if (ret)
+-		dev_err(nandc->dev, "failure to write raw page\n");
+-
+-	free_descs(nandc);
+-
+-	return ret;
+-}
+-
+-/*
+- * implements ecc->write_oob()
+- *
+- * the NAND controller cannot write only data or only oob within a codeword,
+- * since ecc is calculated for the combined codeword. we first copy the
+- * entire contents for the last codeword(data + oob), replace the old oob
+- * with the new one in chip->oob_poi, and then write the entire codeword.
+- * this read-copy-write operation results in a slight performance loss.
+- */
+-static int qcom_nandc_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
+-				int page)
+-{
+-	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;
+-	u8 *oob = chip->oob_poi;
+-	int data_size, oob_size;
+-	int ret, status = 0;
+-
+-	host->use_ecc = true;
+-
+-	clear_bam_transaction(nandc);
+-	ret = copy_last_cw(host, page);
+-	if (ret)
+-		return ret;
+-
+-	clear_read_regs(nandc);
+-	clear_bam_transaction(nandc);
+-
+-	/* calculate the data and oob size for the last codeword/step */
+-	data_size = ecc->size - ((ecc->steps - 1) << 2);
+-	oob_size = mtd->oobavail;
+-
+-	/* override new oob content to last codeword */
+-	mtd_ooblayout_get_databytes(mtd, nandc->data_buffer + data_size, oob,
+-				    0, mtd->oobavail);
+-
+-	set_address(host, host->cw_size * (ecc->steps - 1), page);
+-	update_rw_regs(host, 1, false);
+-
+-	config_nand_page_write(nandc);
+-	write_data_dma(nandc, FLASH_BUF_ACC,
+-		       nandc->data_buffer, data_size + oob_size, 0);
+-	config_nand_cw_write(nandc);
+-
+-	ret = submit_descs(nandc);
+-
+-	free_descs(nandc);
+-
+-	if (ret) {
+-		dev_err(nandc->dev, "failure to write oob\n");
+-		return -EIO;
+-	}
+-
+-	chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+-
+-	status = chip->waitfunc(mtd, chip);
+-
+-	return status & NAND_STATUS_FAIL ? -EIO : 0;
+-}
+-
+-static int qcom_nandc_block_bad(struct mtd_info *mtd, loff_t ofs)
+-{
+-	struct nand_chip *chip = mtd_to_nand(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;
+-	int page, ret, bbpos, bad = 0;
+-	u32 flash_status;
+-
+-	page = (int)(ofs >> chip->page_shift) & chip->pagemask;
+-
+-	/*
+-	 * configure registers for a raw sub page read, the address is set to
+-	 * the beginning of the last codeword, we don't care about reading ecc
+-	 * portion of oob. we just want the first few bytes from this codeword
+-	 * that contains the BBM
+-	 */
+-	host->use_ecc = false;
+-
+-	clear_bam_transaction(nandc);
+-	ret = copy_last_cw(host, page);
+-	if (ret)
+-		goto err;
+-
+-	flash_status = le32_to_cpu(nandc->reg_read_buf[0]);
+-
+-	if (flash_status & (FS_OP_ERR | FS_MPU_ERR)) {
+-		dev_warn(nandc->dev, "error when trying to read BBM\n");
+-		goto err;
+-	}
+-
+-	bbpos = mtd->writesize - host->cw_size * (ecc->steps - 1);
+-
+-	bad = nandc->data_buffer[bbpos] != 0xff;
+-
+-	if (chip->options & NAND_BUSWIDTH_16)
+-		bad = bad || (nandc->data_buffer[bbpos + 1] != 0xff);
+-err:
+-	return bad;
+-}
+-
+-static int qcom_nandc_block_markbad(struct mtd_info *mtd, loff_t ofs)
+-{
+-	struct nand_chip *chip = mtd_to_nand(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;
+-	int page, ret, status = 0;
+-
+-	clear_read_regs(nandc);
+-	clear_bam_transaction(nandc);
+-
+-	/*
+-	 * to mark the BBM as bad, we flash the entire last codeword with 0s.
+-	 * we don't care about the rest of the content in the codeword since
+-	 * we aren't going to use this block again
+-	 */
+-	memset(nandc->data_buffer, 0x00, host->cw_size);
+-
+-	page = (int)(ofs >> chip->page_shift) & chip->pagemask;
+-
+-	/* prepare write */
+-	host->use_ecc = false;
+-	set_address(host, host->cw_size * (ecc->steps - 1), page);
+-	update_rw_regs(host, 1, false);
+-
+-	config_nand_page_write(nandc);
+-	write_data_dma(nandc, FLASH_BUF_ACC,
+-		       nandc->data_buffer, host->cw_size, 0);
+-	config_nand_cw_write(nandc);
+-
+-	ret = submit_descs(nandc);
+-
+-	free_descs(nandc);
+-
+-	if (ret) {
+-		dev_err(nandc->dev, "failure to update BBM\n");
+-		return -EIO;
+-	}
+-
+-	chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+-
+-	status = chip->waitfunc(mtd, chip);
+-
+-	return status & NAND_STATUS_FAIL ? -EIO : 0;
+-}
+-
+-/*
+- * the three functions below implement chip->read_byte(), chip->read_buf()
+- * and chip->write_buf() respectively. these aren't used for
+- * reading/writing page data, they are used for smaller data like reading
+- * id, status etc
+- */
+-static uint8_t qcom_nandc_read_byte(struct mtd_info *mtd)
+-{
+-	struct nand_chip *chip = mtd_to_nand(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;
+-	u8 ret = 0x0;
+-
+-	if (host->last_command == NAND_CMD_STATUS) {
+-		ret = host->status;
+-
+-		host->status = NAND_STATUS_READY | NAND_STATUS_WP;
+-
+-		return ret;
+-	}
+-
+-	if (nandc->buf_start < nandc->buf_count)
+-		ret = buf[nandc->buf_start++];
+-
+-	return ret;
+-}
+-
+-static void qcom_nandc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+-{
+-	struct nand_chip *chip = mtd_to_nand(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);
+-
+-	memcpy(buf, nandc->data_buffer + nandc->buf_start, real_len);
+-	nandc->buf_start += real_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 qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+-	int real_len = min_t(size_t, len, nandc->buf_count - nandc->buf_start);
+-
+-	memcpy(nandc->data_buffer + nandc->buf_start, buf, real_len);
+-
+-	nandc->buf_start += real_len;
+-}
+-
+-/* 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 qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+-
+-	if (chipnr <= 0)
+-		return;
+-
+-	dev_warn(nandc->dev, "invalid chip select\n");
+-}
+-
+-/*
+- * NAND controller page layout info
+- *
+- * Layout with ECC enabled:
+- *
+- * |----------------------|  |---------------------------------|
+- * |           xx.......yy|  |             *********xx.......yy|
+- * |    DATA   xx..ECC..yy|  |    DATA     **SPARE**xx..ECC..yy|
+- * |   (516)   xx.......yy|  |  (516-n*4)  **(n*4)**xx.......yy|
+- * |           xx.......yy|  |             *********xx.......yy|
+- * |----------------------|  |---------------------------------|
+- *     codeword 1,2..n-1                  codeword n
+- *  <---(528/532 Bytes)-->    <-------(528/532 Bytes)--------->
+- *
+- * n = Number of codewords in the page
+- * . = ECC bytes
+- * * = Spare/free bytes
+- * x = Unused byte(s)
+- * y = Reserved byte(s)
+- *
+- * 2K page: n = 4, spare = 16 bytes
+- * 4K page: n = 8, spare = 32 bytes
+- * 8K page: n = 16, spare = 64 bytes
+- *
+- * the qcom nand controller operates at a sub page/codeword level. each
+- * codeword is 528 and 532 bytes for 4 bit and 8 bit ECC modes respectively.
+- * the number of ECC bytes vary based on the ECC strength and the bus width.
+- *
+- * the first n - 1 codewords contains 516 bytes of user data, the remaining
+- * 12/16 bytes consist of ECC and reserved data. The nth codeword contains
+- * both user data and spare(oobavail) bytes that sum up to 516 bytes.
+- *
+- * When we access a page with ECC enabled, the reserved bytes(s) are not
+- * accessible at all. When reading, we fill up these unreadable positions
+- * with 0xffs. When writing, the controller skips writing the inaccessible
+- * bytes.
+- *
+- * Layout with ECC disabled:
+- *
+- * |------------------------------|  |---------------------------------------|
+- * |         yy          xx.......|  |         bb          *********xx.......|
+- * |  DATA1  yy  DATA2   xx..ECC..|  |  DATA1  bb  DATA2   **SPARE**xx..ECC..|
+- * | (size1) yy (size2)  xx.......|  | (size1) bb (size2)  **(n*4)**xx.......|
+- * |         yy          xx.......|  |         bb          *********xx.......|
+- * |------------------------------|  |---------------------------------------|
+- *         codeword 1,2..n-1                        codeword n
+- *  <-------(528/532 Bytes)------>    <-----------(528/532 Bytes)----------->
+- *
+- * n = Number of codewords in the page
+- * . = ECC bytes
+- * * = Spare/free bytes
+- * x = Unused byte(s)
+- * y = Dummy Bad Bock byte(s)
+- * b = Real Bad Block byte(s)
+- * size1/size2 = function of codeword size and 'n'
+- *
+- * when the ECC block is disabled, one reserved byte (or two for 16 bit bus
+- * width) is now accessible. For the first n - 1 codewords, these are dummy Bad
+- * Block Markers. In the last codeword, this position contains the real BBM
+- *
+- * In order to have a consistent layout between RAW and ECC modes, we assume
+- * the following OOB layout arrangement:
+- *
+- * |-----------|  |--------------------|
+- * |yyxx.......|  |bb*********xx.......|
+- * |yyxx..ECC..|  |bb*FREEOOB*xx..ECC..|
+- * |yyxx.......|  |bb*********xx.......|
+- * |yyxx.......|  |bb*********xx.......|
+- * |-----------|  |--------------------|
+- *  first n - 1       nth OOB region
+- *  OOB regions
+- *
+- * n = Number of codewords in the page
+- * . = ECC bytes
+- * * = FREE OOB bytes
+- * y = Dummy bad block byte(s) (inaccessible when ECC enabled)
+- * x = Unused byte(s)
+- * b = Real bad block byte(s) (inaccessible when ECC enabled)
+- *
+- * This layout is read as is when ECC is disabled. When ECC is enabled, the
+- * inaccessible Bad Block byte(s) are ignored when we write to a page/oob,
+- * and assumed as 0xffs when we read a page/oob. The ECC, unused and
+- * dummy/real bad block bytes are grouped as ecc bytes (i.e, ecc->bytes is
+- * the sum of the three).
+- */
+-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 qcom_nand_host *host = to_qcom_nand_host(chip);
+-	struct nand_ecc_ctrl *ecc = &chip->ecc;
+-
+-	if (section > 1)
+-		return -ERANGE;
+-
+-	if (!section) {
+-		oobregion->length = (ecc->bytes * (ecc->steps - 1)) +
+-				    host->bbm_size;
+-		oobregion->offset = 0;
+-	} else {
+-		oobregion->length = host->ecc_bytes_hw + host->spare_bytes;
+-		oobregion->offset = mtd->oobsize - oobregion->length;
+-	}
+-
+-	return 0;
+-}
+-
+-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 qcom_nand_host *host = to_qcom_nand_host(chip);
+-	struct nand_ecc_ctrl *ecc = &chip->ecc;
+-
+-	if (section)
+-		return -ERANGE;
+-
+-	oobregion->length = ecc->steps * 4;
+-	oobregion->offset = ((ecc->steps - 1) * ecc->bytes) + host->bbm_size;
+-
+-	return 0;
+-}
+-
+-static const struct mtd_ooblayout_ops qcom_nand_ooblayout_ops = {
+-	.ecc = qcom_nand_ooblayout_ecc,
+-	.free = qcom_nand_ooblayout_free,
+-};
+-
+-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 nand_ecc_ctrl *ecc = &chip->ecc;
+-	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+-	int cwperpage, bad_block_byte;
+-	bool wide_bus;
+-	int ecc_mode = 1;
+-
+-	/*
+-	 * the controller requires each step consists of 512 bytes of data.
+-	 * bail out if DT has populated a wrong step size.
+-	 */
+-	if (ecc->size != NANDC_STEP_SIZE) {
+-		dev_err(nandc->dev, "invalid ecc size\n");
+-		return -EINVAL;
+-	}
+-
+-	wide_bus = chip->options & NAND_BUSWIDTH_16 ? true : false;
+-
+-	if (ecc->strength >= 8) {
+-		/* 8 bit ECC defaults to BCH ECC on all platforms */
+-		host->bch_enabled = true;
+-		ecc_mode = 1;
+-
+-		if (wide_bus) {
+-			host->ecc_bytes_hw = 14;
+-			host->spare_bytes = 0;
+-			host->bbm_size = 2;
+-		} else {
+-			host->ecc_bytes_hw = 13;
+-			host->spare_bytes = 2;
+-			host->bbm_size = 1;
+-		}
+-	} else {
+-		/*
+-		 * if the controller supports BCH for 4 bit ECC, the controller
+-		 * uses lesser bytes for ECC. If RS is used, the ECC bytes is
+-		 * always 10 bytes
+-		 */
+-		if (nandc->props->ecc_modes & ECC_BCH_4BIT) {
+-			/* BCH */
+-			host->bch_enabled = true;
+-			ecc_mode = 0;
+-
+-			if (wide_bus) {
+-				host->ecc_bytes_hw = 8;
+-				host->spare_bytes = 2;
+-				host->bbm_size = 2;
+-			} else {
+-				host->ecc_bytes_hw = 7;
+-				host->spare_bytes = 4;
+-				host->bbm_size = 1;
+-			}
+-		} else {
+-			/* RS */
+-			host->ecc_bytes_hw = 10;
+-
+-			if (wide_bus) {
+-				host->spare_bytes = 0;
+-				host->bbm_size = 2;
+-			} else {
+-				host->spare_bytes = 1;
+-				host->bbm_size = 1;
+-			}
+-		}
+-	}
+-
+-	/*
+-	 * we consider ecc->bytes as the sum of all the non-data content in a
+-	 * step. It gives us a clean representation of the oob area (even if
+-	 * all the bytes aren't used for ECC).It is always 16 bytes for 8 bit
+-	 * ECC and 12 bytes for 4 bit ECC
+-	 */
+-	ecc->bytes = host->ecc_bytes_hw + host->spare_bytes + host->bbm_size;
+-
+-	ecc->read_page		= qcom_nandc_read_page;
+-	ecc->read_page_raw	= qcom_nandc_read_page_raw;
+-	ecc->read_oob		= qcom_nandc_read_oob;
+-	ecc->write_page		= qcom_nandc_write_page;
+-	ecc->write_page_raw	= qcom_nandc_write_page_raw;
+-	ecc->write_oob		= qcom_nandc_write_oob;
+-
+-	ecc->mode = NAND_ECC_HW;
+-
+-	mtd_set_ooblayout(mtd, &qcom_nand_ooblayout_ops);
+-
+-	cwperpage = mtd->writesize / ecc->size;
+-	nandc->max_cwperpage = max_t(unsigned int, nandc->max_cwperpage,
+-				     cwperpage);
+-
+-	/*
+-	 * DATA_UD_BYTES varies based on whether the read/write command protects
+-	 * spare data with ECC too. We protect spare data by default, so we set
+-	 * it to main + spare data, which are 512 and 4 bytes respectively.
+-	 */
+-	host->cw_data = 516;
+-
+-	/*
+-	 * total bytes in a step, either 528 bytes for 4 bit ECC, or 532 bytes
+-	 * for 8 bit ECC
+-	 */
+-	host->cw_size = host->cw_data + ecc->bytes;
+-
+-	if (ecc->bytes * (mtd->writesize / ecc->size) > mtd->oobsize) {
+-		dev_err(nandc->dev, "ecc data doesn't fit in OOB area\n");
+-		return -EINVAL;
+-	}
+-
+-	bad_block_byte = mtd->writesize - host->cw_size * (cwperpage - 1) + 1;
+-
+-	host->cfg0 = (cwperpage - 1) << CW_PER_PAGE
+-				| host->cw_data << UD_SIZE_BYTES
+-				| 0 << DISABLE_STATUS_AFTER_WRITE
+-				| 5 << NUM_ADDR_CYCLES
+-				| host->ecc_bytes_hw << ECC_PARITY_SIZE_BYTES_RS
+-				| 0 << STATUS_BFR_READ
+-				| 1 << SET_RD_MODE_AFTER_STATUS
+-				| host->spare_bytes << SPARE_SIZE_BYTES;
+-
+-	host->cfg1 = 7 << NAND_RECOVERY_CYCLES
+-				| 0 <<  CS_ACTIVE_BSY
+-				| bad_block_byte << BAD_BLOCK_BYTE_NUM
+-				| 0 << BAD_BLOCK_IN_SPARE_AREA
+-				| 2 << WR_RD_BSY_GAP
+-				| wide_bus << WIDE_FLASH
+-				| host->bch_enabled << ENABLE_BCH_ECC;
+-
+-	host->cfg0_raw = (cwperpage - 1) << CW_PER_PAGE
+-				| host->cw_size << UD_SIZE_BYTES
+-				| 5 << NUM_ADDR_CYCLES
+-				| 0 << SPARE_SIZE_BYTES;
+-
+-	host->cfg1_raw = 7 << NAND_RECOVERY_CYCLES
+-				| 0 << CS_ACTIVE_BSY
+-				| 17 << BAD_BLOCK_BYTE_NUM
+-				| 1 << BAD_BLOCK_IN_SPARE_AREA
+-				| 2 << WR_RD_BSY_GAP
+-				| wide_bus << WIDE_FLASH
+-				| 1 << DEV0_CFG1_ECC_DISABLE;
+-
+-	host->ecc_bch_cfg = !host->bch_enabled << ECC_CFG_ECC_DISABLE
+-				| 0 << ECC_SW_RESET
+-				| host->cw_data << ECC_NUM_DATA_BYTES
+-				| 1 << ECC_FORCE_CLK_OPEN
+-				| ecc_mode << ECC_MODE
+-				| host->ecc_bytes_hw << ECC_PARITY_SIZE_BYTES_BCH;
+-
+-	host->ecc_buf_cfg = 0x203 << NUM_STEPS;
+-
+-	host->clrflashstatus = FS_READY_BSY_N;
+-	host->clrreadstatus = 0xc0;
+-	nandc->regs->erased_cw_detect_cfg_clr =
+-		cpu_to_le32(CLR_ERASED_PAGE_DET);
+-	nandc->regs->erased_cw_detect_cfg_set =
+-		cpu_to_le32(SET_ERASED_PAGE_DET);
+-
+-	dev_dbg(nandc->dev,
+-		"cfg0 %x cfg1 %x ecc_buf_cfg %x ecc_bch cfg %x cw_size %d cw_data %d strength %d parity_bytes %d steps %d\n",
+-		host->cfg0, host->cfg1, host->ecc_buf_cfg, host->ecc_bch_cfg,
+-		host->cw_size, host->cw_data, ecc->strength, ecc->bytes,
+-		cwperpage);
+-
+-	return 0;
+-}
+-
+-static int qcom_nandc_alloc(struct qcom_nand_controller *nandc)
+-{
+-	int ret;
+-
+-	ret = dma_set_coherent_mask(nandc->dev, DMA_BIT_MASK(32));
+-	if (ret) {
+-		dev_err(nandc->dev, "failed to set DMA mask\n");
+-		return ret;
+-	}
+-
+-	/*
+-	 * we use the internal buffer for reading ONFI params, reading small
+-	 * data like ID and status, and preforming read-copy-write operations
+-	 * when writing to a codeword partially. 532 is the maximum possible
+-	 * size of a codeword for our nand controller
+-	 */
+-	nandc->buf_size = 532;
+-
+-	nandc->data_buffer = devm_kzalloc(nandc->dev, nandc->buf_size,
+-					GFP_KERNEL);
+-	if (!nandc->data_buffer)
+-		return -ENOMEM;
+-
+-	nandc->regs = devm_kzalloc(nandc->dev, sizeof(*nandc->regs),
+-					GFP_KERNEL);
+-	if (!nandc->regs)
+-		return -ENOMEM;
+-
+-	nandc->reg_read_buf = devm_kzalloc(nandc->dev,
+-				MAX_REG_RD * sizeof(*nandc->reg_read_buf),
+-				GFP_KERNEL);
+-	if (!nandc->reg_read_buf)
+-		return -ENOMEM;
+-
+-	if (nandc->props->is_bam) {
+-		nandc->reg_read_dma =
+-			dma_map_single(nandc->dev, nandc->reg_read_buf,
+-				       MAX_REG_RD *
+-				       sizeof(*nandc->reg_read_buf),
+-				       DMA_FROM_DEVICE);
+-		if (dma_mapping_error(nandc->dev, nandc->reg_read_dma)) {
+-			dev_err(nandc->dev, "failed to DMA MAP reg buffer\n");
+-			return -EIO;
+-		}
+-
+-		nandc->tx_chan = dma_request_slave_channel(nandc->dev, "tx");
+-		if (!nandc->tx_chan) {
+-			dev_err(nandc->dev, "failed to request tx channel\n");
+-			return -ENODEV;
+-		}
+-
+-		nandc->rx_chan = dma_request_slave_channel(nandc->dev, "rx");
+-		if (!nandc->rx_chan) {
+-			dev_err(nandc->dev, "failed to request rx channel\n");
+-			return -ENODEV;
+-		}
+-
+-		nandc->cmd_chan = dma_request_slave_channel(nandc->dev, "cmd");
+-		if (!nandc->cmd_chan) {
+-			dev_err(nandc->dev, "failed to request cmd channel\n");
+-			return -ENODEV;
+-		}
+-
+-		/*
+-		 * Initially allocate BAM transaction to read ONFI param page.
+-		 * After detecting all the devices, this BAM transaction will
+-		 * be freed and the next BAM tranasction will be allocated with
+-		 * maximum codeword size
+-		 */
+-		nandc->max_cwperpage = 1;
+-		nandc->bam_txn = alloc_bam_transaction(nandc);
+-		if (!nandc->bam_txn) {
+-			dev_err(nandc->dev,
+-				"failed to allocate bam transaction\n");
+-			return -ENOMEM;
+-		}
+-	} else {
+-		nandc->chan = dma_request_slave_channel(nandc->dev, "rxtx");
+-		if (!nandc->chan) {
+-			dev_err(nandc->dev,
+-				"failed to request slave channel\n");
+-			return -ENODEV;
+-		}
+-	}
+-
+-	INIT_LIST_HEAD(&nandc->desc_list);
+-	INIT_LIST_HEAD(&nandc->host_list);
+-
+-	nand_hw_control_init(&nandc->controller);
+-
+-	return 0;
+-}
+-
+-static void qcom_nandc_unalloc(struct qcom_nand_controller *nandc)
+-{
+-	if (nandc->props->is_bam) {
+-		if (!dma_mapping_error(nandc->dev, nandc->reg_read_dma))
+-			dma_unmap_single(nandc->dev, nandc->reg_read_dma,
+-					 MAX_REG_RD *
+-					 sizeof(*nandc->reg_read_buf),
+-					 DMA_FROM_DEVICE);
+-
+-		if (nandc->tx_chan)
+-			dma_release_channel(nandc->tx_chan);
+-
+-		if (nandc->rx_chan)
+-			dma_release_channel(nandc->rx_chan);
+-
+-		if (nandc->cmd_chan)
+-			dma_release_channel(nandc->cmd_chan);
+-	} else {
+-		if (nandc->chan)
+-			dma_release_channel(nandc->chan);
+-	}
+-}
+-
+-/* one time setup of a few nand controller registers */
+-static int qcom_nandc_setup(struct qcom_nand_controller *nandc)
+-{
+-	u32 nand_ctrl;
+-
+-	/* kill onenand */
+-	nandc_write(nandc, SFLASHC_BURST_CFG, 0);
+-	nandc_write(nandc, dev_cmd_reg_addr(nandc, NAND_DEV_CMD_VLD),
+-		    NAND_DEV_CMD_VLD_VAL);
+-
+-	/* enable ADM or BAM DMA */
+-	if (nandc->props->is_bam) {
+-		nand_ctrl = nandc_read(nandc, NAND_CTRL);
+-		nandc_write(nandc, NAND_CTRL, nand_ctrl | BAM_MODE_EN);
+-	} else {
+-		nandc_write(nandc, NAND_FLASH_CHIP_SELECT, DM_EN);
+-	}
+-
+-	/* save the original values of these registers */
+-	nandc->cmd1 = nandc_read(nandc, dev_cmd_reg_addr(nandc, NAND_DEV_CMD1));
+-	nandc->vld = NAND_DEV_CMD_VLD_VAL;
+-
+-	return 0;
+-}
+-
+-static int qcom_nand_host_init(struct qcom_nand_controller *nandc,
+-			       struct qcom_nand_host *host,
+-			       struct device_node *dn)
+-{
+-	struct nand_chip *chip = &host->chip;
+-	struct mtd_info *mtd = nand_to_mtd(chip);
+-	struct device *dev = nandc->dev;
+-	int ret;
+-
+-	ret = of_property_read_u32(dn, "reg", &host->cs);
+-	if (ret) {
+-		dev_err(dev, "can't get chip-select\n");
+-		return -ENXIO;
+-	}
+-
+-	nand_set_flash_node(chip, dn);
+-	mtd->name = devm_kasprintf(dev, GFP_KERNEL, "qcom_nand.%d", host->cs);
+-	mtd->owner = THIS_MODULE;
+-	mtd->dev.parent = dev;
+-
+-	chip->cmdfunc		= qcom_nandc_command;
+-	chip->select_chip	= qcom_nandc_select_chip;
+-	chip->read_byte		= qcom_nandc_read_byte;
+-	chip->read_buf		= qcom_nandc_read_buf;
+-	chip->write_buf		= qcom_nandc_write_buf;
+-	chip->onfi_set_features	= nand_onfi_get_set_features_notsupp;
+-	chip->onfi_get_features	= nand_onfi_get_set_features_notsupp;
+-
+-	/*
+-	 * the bad block marker is readable only when we read the last codeword
+-	 * of a page with ECC disabled. currently, the nand_base and nand_bbt
+-	 * helpers don't allow us to read BB from a nand chip with ECC
+-	 * disabled (MTD_OPS_PLACE_OOB is set by default). use the block_bad
+-	 * and block_markbad helpers until we permanently switch to using
+-	 * MTD_OPS_RAW for all drivers (with the help of badblockbits)
+-	 */
+-	chip->block_bad		= qcom_nandc_block_bad;
+-	chip->block_markbad	= qcom_nandc_block_markbad;
+-
+-	chip->controller = &nandc->controller;
+-	chip->options |= NAND_NO_SUBPAGE_WRITE | NAND_USE_BOUNCE_BUFFER |
+-			 NAND_SKIP_BBTSCAN;
+-
+-	/* set up initial status value */
+-	host->status = NAND_STATUS_READY | NAND_STATUS_WP;
+-
+-	ret = nand_scan_ident(mtd, 1, NULL);
+-	if (ret)
+-		return ret;
+-
+-	ret = qcom_nand_host_setup(host);
+-
+-	return ret;
+-}
+-
+-static int qcom_nand_mtd_register(struct qcom_nand_controller *nandc,
+-				  struct qcom_nand_host *host,
+-				  struct device_node *dn)
+-{
+-	struct nand_chip *chip = &host->chip;
+-	struct mtd_info *mtd = nand_to_mtd(chip);
+-	int ret;
+-
+-	ret = nand_scan_tail(mtd);
+-	if (ret)
+-		return ret;
+-
+-	ret = mtd_device_register(mtd, NULL, 0);
+-	if (ret)
+-		nand_cleanup(mtd_to_nand(mtd));
+-
+-	return ret;
+-}
+-
+-static int qcom_probe_nand_devices(struct qcom_nand_controller *nandc)
+-{
+-	struct device *dev = nandc->dev;
+-	struct device_node *dn = dev->of_node, *child;
+-	struct qcom_nand_host *host, *tmp;
+-	int ret;
+-
+-	for_each_available_child_of_node(dn, child) {
+-		host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL);
+-		if (!host) {
+-			of_node_put(child);
+-			return -ENOMEM;
+-		}
+-
+-		ret = qcom_nand_host_init(nandc, host, child);
+-		if (ret) {
+-			devm_kfree(dev, host);
+-			continue;
+-		}
+-
+-		list_add_tail(&host->node, &nandc->host_list);
+-	}
+-
+-	if (list_empty(&nandc->host_list))
+-		return -ENODEV;
+-
+-	if (nandc->props->is_bam) {
+-		free_bam_transaction(nandc);
+-		nandc->bam_txn = alloc_bam_transaction(nandc);
+-		if (!nandc->bam_txn) {
+-			dev_err(nandc->dev,
+-				"failed to allocate bam transaction\n");
+-			return -ENOMEM;
+-		}
+-	}
+-
+-	list_for_each_entry_safe(host, tmp, &nandc->host_list, node) {
+-		ret = qcom_nand_mtd_register(nandc, host, child);
+-		if (ret) {
+-			list_del(&host->node);
+-			devm_kfree(dev, host);
+-		}
+-	}
+-
+-	if (list_empty(&nandc->host_list))
+-		return -ENODEV;
+-
+-	return 0;
+-}
+-
+-/* parse custom DT properties here */
+-static int qcom_nandc_parse_dt(struct platform_device *pdev)
+-{
+-	struct qcom_nand_controller *nandc = platform_get_drvdata(pdev);
+-	struct device_node *np = nandc->dev->of_node;
+-	int ret;
+-
+-	if (!nandc->props->is_bam) {
+-		ret = of_property_read_u32(np, "qcom,cmd-crci",
+-					   &nandc->cmd_crci);
+-		if (ret) {
+-			dev_err(nandc->dev, "command CRCI unspecified\n");
+-			return ret;
+-		}
+-
+-		ret = of_property_read_u32(np, "qcom,data-crci",
+-					   &nandc->data_crci);
+-		if (ret) {
+-			dev_err(nandc->dev, "data CRCI unspecified\n");
+-			return ret;
+-		}
+-	}
+-
+-	return 0;
+-}
+-
+-static int qcom_nandc_probe(struct platform_device *pdev)
+-{
+-	struct qcom_nand_controller *nandc;
+-	const void *dev_data;
+-	struct device *dev = &pdev->dev;
+-	struct resource *res;
+-	int ret;
+-
+-	nandc = devm_kzalloc(&pdev->dev, sizeof(*nandc), GFP_KERNEL);
+-	if (!nandc)
+-		return -ENOMEM;
+-
+-	platform_set_drvdata(pdev, nandc);
+-	nandc->dev = dev;
+-
+-	dev_data = of_device_get_match_data(dev);
+-	if (!dev_data) {
+-		dev_err(&pdev->dev, "failed to get device data\n");
+-		return -ENODEV;
+-	}
+-
+-	nandc->props = dev_data;
+-
+-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+-	nandc->base = devm_ioremap_resource(dev, res);
+-	if (IS_ERR(nandc->base))
+-		return PTR_ERR(nandc->base);
+-
+-	nandc->base_dma = phys_to_dma(dev, (phys_addr_t)res->start);
+-
+-	nandc->core_clk = devm_clk_get(dev, "core");
+-	if (IS_ERR(nandc->core_clk))
+-		return PTR_ERR(nandc->core_clk);
+-
+-	nandc->aon_clk = devm_clk_get(dev, "aon");
+-	if (IS_ERR(nandc->aon_clk))
+-		return PTR_ERR(nandc->aon_clk);
+-
+-	ret = qcom_nandc_parse_dt(pdev);
+-	if (ret)
+-		return ret;
+-
+-	ret = qcom_nandc_alloc(nandc);
+-	if (ret)
+-		goto err_core_clk;
+-
+-	ret = clk_prepare_enable(nandc->core_clk);
+-	if (ret)
+-		goto err_core_clk;
+-
+-	ret = clk_prepare_enable(nandc->aon_clk);
+-	if (ret)
+-		goto err_aon_clk;
+-
+-	ret = qcom_nandc_setup(nandc);
+-	if (ret)
+-		goto err_setup;
+-
+-	ret = qcom_probe_nand_devices(nandc);
+-	if (ret)
+-		goto err_setup;
+-
+-	return 0;
+-
+-err_setup:
+-	clk_disable_unprepare(nandc->aon_clk);
+-err_aon_clk:
+-	clk_disable_unprepare(nandc->core_clk);
+-err_core_clk:
+-	qcom_nandc_unalloc(nandc);
+-
+-	return ret;
+-}
+-
+-static int qcom_nandc_remove(struct platform_device *pdev)
+-{
+-	struct qcom_nand_controller *nandc = platform_get_drvdata(pdev);
+-	struct qcom_nand_host *host;
+-
+-	list_for_each_entry(host, &nandc->host_list, node)
+-		nand_release(nand_to_mtd(&host->chip));
+-
+-	qcom_nandc_unalloc(nandc);
+-
+-	clk_disable_unprepare(nandc->aon_clk);
+-	clk_disable_unprepare(nandc->core_clk);
+-
+-	return 0;
+-}
+-
+-static const struct qcom_nandc_props ipq806x_nandc_props = {
+-	.ecc_modes = (ECC_RS_4BIT | ECC_BCH_8BIT),
+-	.is_bam = false,
+-	.dev_cmd_reg_start = 0x0,
+-};
+-
+-static const struct qcom_nandc_props ipq4019_nandc_props = {
+-	.ecc_modes = (ECC_BCH_4BIT | ECC_BCH_8BIT),
+-	.is_bam = true,
+-	.dev_cmd_reg_start = 0x0,
+-};
+-
+-static const struct qcom_nandc_props ipq8074_nandc_props = {
+-	.ecc_modes = (ECC_BCH_4BIT | ECC_BCH_8BIT),
+-	.is_bam = true,
+-	.dev_cmd_reg_start = 0x7000,
+-};
+-
+-/*
+- * data will hold a struct pointer containing more differences once we support
+- * more controller variants
+- */
+-static const struct of_device_id qcom_nandc_of_match[] = {
+-	{
+-		.compatible = "qcom,ipq806x-nand",
+-		.data = &ipq806x_nandc_props,
+-	},
+-	{
+-		.compatible = "qcom,ipq4019-nand",
+-		.data = &ipq4019_nandc_props,
+-	},
+-	{
+-		.compatible = "qcom,ipq8074-nand",
+-		.data = &ipq8074_nandc_props,
+-	},
+-	{}
+-};
+-MODULE_DEVICE_TABLE(of, qcom_nandc_of_match);
+-
+-static struct platform_driver qcom_nandc_driver = {
+-	.driver = {
+-		.name = "qcom-nandc",
+-		.of_match_table = qcom_nandc_of_match,
+-	},
+-	.probe   = qcom_nandc_probe,
+-	.remove  = qcom_nandc_remove,
+-};
+-module_platform_driver(qcom_nandc_driver);
+-
+-MODULE_AUTHOR("Archit Taneja <architt@codeaurora.org>");
+-MODULE_DESCRIPTION("Qualcomm NAND Controller driver");
+-MODULE_LICENSE("GPL v2");
+diff --git a/drivers/mtd/nand/r852.c b/drivers/mtd/nand/r852.c
+deleted file mode 100644
+index fc9287a..0000000
+--- a/drivers/mtd/nand/r852.c
++++ /dev/null
+@@ -1,1082 +0,0 @@
+-/*
+- * Copyright © 2009 - Maxim Levitsky
+- * driver for Ricoh xD readers
+- *
+- * 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/kernel.h>
+-#include <linux/module.h>
+-#include <linux/jiffies.h>
+-#include <linux/workqueue.h>
+-#include <linux/interrupt.h>
+-#include <linux/pci.h>
+-#include <linux/pci_ids.h>
+-#include <linux/delay.h>
+-#include <linux/slab.h>
+-#include <asm/byteorder.h>
+-#include <linux/sched.h>
+-#include "sm_common.h"
+-#include "r852.h"
+-
+-
+-static bool r852_enable_dma = 1;
+-module_param(r852_enable_dma, bool, S_IRUGO);
+-MODULE_PARM_DESC(r852_enable_dma, "Enable usage of the DMA (default)");
+-
+-static int debug;
+-module_param(debug, int, S_IRUGO | S_IWUSR);
+-MODULE_PARM_DESC(debug, "Debug level (0-2)");
+-
+-/* read register */
+-static inline uint8_t r852_read_reg(struct r852_device *dev, int address)
+-{
+-	uint8_t reg = readb(dev->mmio + address);
+-	return reg;
+-}
+-
+-/* write register */
+-static inline void r852_write_reg(struct r852_device *dev,
+-						int address, uint8_t value)
+-{
+-	writeb(value, dev->mmio + address);
+-	mmiowb();
+-}
+-
+-
+-/* read dword sized register */
+-static inline uint32_t r852_read_reg_dword(struct r852_device *dev, int address)
+-{
+-	uint32_t reg = le32_to_cpu(readl(dev->mmio + address));
+-	return reg;
+-}
+-
+-/* write dword sized register */
+-static inline void r852_write_reg_dword(struct r852_device *dev,
+-							int address, uint32_t value)
+-{
+-	writel(cpu_to_le32(value), dev->mmio + address);
+-	mmiowb();
+-}
+-
+-/* 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);
+-	return nand_get_controller_data(chip);
+-}
+-
+-
+-/* check if controller supports dma */
+-static void r852_dma_test(struct r852_device *dev)
+-{
+-	dev->dma_usable = (r852_read_reg(dev, R852_DMA_CAP) &
+-		(R852_DMA1 | R852_DMA2)) == (R852_DMA1 | R852_DMA2);
+-
+-	if (!dev->dma_usable)
+-		message("Non dma capable device detected, dma disabled");
+-
+-	if (!r852_enable_dma) {
+-		message("disabling dma on user request");
+-		dev->dma_usable = 0;
+-	}
+-}
+-
+-/*
+- * Enable dma. Enables ether first or second stage of the DMA,
+- * Expects dev->dma_dir and dev->dma_state be set
+- */
+-static void r852_dma_enable(struct r852_device *dev)
+-{
+-	uint8_t dma_reg, dma_irq_reg;
+-
+-	/* Set up dma settings */
+-	dma_reg = r852_read_reg_dword(dev, R852_DMA_SETTINGS);
+-	dma_reg &= ~(R852_DMA_READ | R852_DMA_INTERNAL | R852_DMA_MEMORY);
+-
+-	if (dev->dma_dir)
+-		dma_reg |= R852_DMA_READ;
+-
+-	if (dev->dma_state == DMA_INTERNAL) {
+-		dma_reg |= R852_DMA_INTERNAL;
+-		/* Precaution to make sure HW doesn't write */
+-			/* to random kernel memory */
+-		r852_write_reg_dword(dev, R852_DMA_ADDR,
+-			cpu_to_le32(dev->phys_bounce_buffer));
+-	} else {
+-		dma_reg |= R852_DMA_MEMORY;
+-		r852_write_reg_dword(dev, R852_DMA_ADDR,
+-			cpu_to_le32(dev->phys_dma_addr));
+-	}
+-
+-	/* Precaution: make sure write reached the device */
+-	r852_read_reg_dword(dev, R852_DMA_ADDR);
+-
+-	r852_write_reg_dword(dev, R852_DMA_SETTINGS, dma_reg);
+-
+-	/* Set dma irq */
+-	dma_irq_reg = r852_read_reg_dword(dev, R852_DMA_IRQ_ENABLE);
+-	r852_write_reg_dword(dev, R852_DMA_IRQ_ENABLE,
+-		dma_irq_reg |
+-		R852_DMA_IRQ_INTERNAL |
+-		R852_DMA_IRQ_ERROR |
+-		R852_DMA_IRQ_MEMORY);
+-}
+-
+-/*
+- * Disable dma, called from the interrupt handler, which specifies
+- * success of the operation via 'error' argument
+- */
+-static void r852_dma_done(struct r852_device *dev, int error)
+-{
+-	WARN_ON(dev->dma_stage == 0);
+-
+-	r852_write_reg_dword(dev, R852_DMA_IRQ_STA,
+-			r852_read_reg_dword(dev, R852_DMA_IRQ_STA));
+-
+-	r852_write_reg_dword(dev, R852_DMA_SETTINGS, 0);
+-	r852_write_reg_dword(dev, R852_DMA_IRQ_ENABLE, 0);
+-
+-	/* Precaution to make sure HW doesn't write to random kernel memory */
+-	r852_write_reg_dword(dev, R852_DMA_ADDR,
+-		cpu_to_le32(dev->phys_bounce_buffer));
+-	r852_read_reg_dword(dev, R852_DMA_ADDR);
+-
+-	dev->dma_error = error;
+-	dev->dma_stage = 0;
+-
+-	if (dev->phys_dma_addr && dev->phys_dma_addr != dev->phys_bounce_buffer)
+-		pci_unmap_single(dev->pci_dev, dev->phys_dma_addr, R852_DMA_LEN,
+-			dev->dma_dir ? PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE);
+-}
+-
+-/*
+- * Wait, till dma is done, which includes both phases of it
+- */
+-static int r852_dma_wait(struct r852_device *dev)
+-{
+-	long timeout = wait_for_completion_timeout(&dev->dma_done,
+-				msecs_to_jiffies(1000));
+-	if (!timeout) {
+-		dbg("timeout waiting for DMA interrupt");
+-		return -ETIMEDOUT;
+-	}
+-
+-	return 0;
+-}
+-
+-/*
+- * Read/Write one page using dma. Only pages can be read (512 bytes)
+-*/
+-static void r852_do_dma(struct r852_device *dev, uint8_t *buf, int do_read)
+-{
+-	int bounce = 0;
+-	unsigned long flags;
+-	int error;
+-
+-	dev->dma_error = 0;
+-
+-	/* Set dma direction */
+-	dev->dma_dir = do_read;
+-	dev->dma_stage = 1;
+-	reinit_completion(&dev->dma_done);
+-
+-	dbg_verbose("doing dma %s ", do_read ? "read" : "write");
+-
+-	/* Set initial dma state: for reading first fill on board buffer,
+-	  from device, for writes first fill the buffer  from memory*/
+-	dev->dma_state = do_read ? DMA_INTERNAL : DMA_MEMORY;
+-
+-	/* if incoming buffer is not page aligned, we should do bounce */
+-	if ((unsigned long)buf & (R852_DMA_LEN-1))
+-		bounce = 1;
+-
+-	if (!bounce) {
+-		dev->phys_dma_addr = pci_map_single(dev->pci_dev, (void *)buf,
+-			R852_DMA_LEN,
+-			(do_read ? PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE));
+-
+-		if (pci_dma_mapping_error(dev->pci_dev, dev->phys_dma_addr))
+-			bounce = 1;
+-	}
+-
+-	if (bounce) {
+-		dbg_verbose("dma: using bounce buffer");
+-		dev->phys_dma_addr = dev->phys_bounce_buffer;
+-		if (!do_read)
+-			memcpy(dev->bounce_buffer, buf, R852_DMA_LEN);
+-	}
+-
+-	/* Enable DMA */
+-	spin_lock_irqsave(&dev->irqlock, flags);
+-	r852_dma_enable(dev);
+-	spin_unlock_irqrestore(&dev->irqlock, flags);
+-
+-	/* Wait till complete */
+-	error = r852_dma_wait(dev);
+-
+-	if (error) {
+-		r852_dma_done(dev, error);
+-		return;
+-	}
+-
+-	if (do_read && bounce)
+-		memcpy((void *)buf, dev->bounce_buffer, R852_DMA_LEN);
+-}
+-
+-/*
+- * Program data lines of the nand chip to send data to it
+- */
+-static void r852_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+-{
+-	struct r852_device *dev = r852_get_dev(mtd);
+-	uint32_t reg;
+-
+-	/* Don't allow any access to hardware if we suspect card removal */
+-	if (dev->card_unstable)
+-		return;
+-
+-	/* Special case for whole sector read */
+-	if (len == R852_DMA_LEN && dev->dma_usable) {
+-		r852_do_dma(dev, (uint8_t *)buf, 0);
+-		return;
+-	}
+-
+-	/* write DWORD chinks - faster */
+-	while (len >= 4) {
+-		reg = buf[0] | buf[1] << 8 | buf[2] << 16 | buf[3] << 24;
+-		r852_write_reg_dword(dev, R852_DATALINE, reg);
+-		buf += 4;
+-		len -= 4;
+-
+-	}
+-
+-	/* write rest */
+-	while (len > 0) {
+-		r852_write_reg(dev, R852_DATALINE, *buf++);
+-		len--;
+-	}
+-}
+-
+-/*
+- * Read data lines of the nand chip to retrieve data
+- */
+-static void r852_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+-{
+-	struct r852_device *dev = r852_get_dev(mtd);
+-	uint32_t reg;
+-
+-	if (dev->card_unstable) {
+-		/* since we can't signal error here, at least, return
+-			predictable buffer */
+-		memset(buf, 0, len);
+-		return;
+-	}
+-
+-	/* special case for whole sector read */
+-	if (len == R852_DMA_LEN && dev->dma_usable) {
+-		r852_do_dma(dev, buf, 1);
+-		return;
+-	}
+-
+-	/* read in dword sized chunks */
+-	while (len >= 4) {
+-
+-		reg = r852_read_reg_dword(dev, R852_DATALINE);
+-		*buf++ = reg & 0xFF;
+-		*buf++ = (reg >> 8) & 0xFF;
+-		*buf++ = (reg >> 16) & 0xFF;
+-		*buf++ = (reg >> 24) & 0xFF;
+-		len -= 4;
+-	}
+-
+-	/* read the reset by bytes */
+-	while (len--)
+-		*buf++ = r852_read_reg(dev, R852_DATALINE);
+-}
+-
+-/*
+- * Read one byte from nand chip
+- */
+-static uint8_t r852_read_byte(struct mtd_info *mtd)
+-{
+-	struct r852_device *dev = r852_get_dev(mtd);
+-
+-	/* Same problem as in r852_read_buf.... */
+-	if (dev->card_unstable)
+-		return 0;
+-
+-	return r852_read_reg(dev, R852_DATALINE);
+-}
+-
+-/*
+- * Control several chip lines & send commands
+- */
+-static void r852_cmdctl(struct mtd_info *mtd, int dat, unsigned int ctrl)
+-{
+-	struct r852_device *dev = r852_get_dev(mtd);
+-
+-	if (dev->card_unstable)
+-		return;
+-
+-	if (ctrl & NAND_CTRL_CHANGE) {
+-
+-		dev->ctlreg &= ~(R852_CTL_DATA | R852_CTL_COMMAND |
+-				 R852_CTL_ON | R852_CTL_CARDENABLE);
+-
+-		if (ctrl & NAND_ALE)
+-			dev->ctlreg |= R852_CTL_DATA;
+-
+-		if (ctrl & NAND_CLE)
+-			dev->ctlreg |= R852_CTL_COMMAND;
+-
+-		if (ctrl & NAND_NCE)
+-			dev->ctlreg |= (R852_CTL_CARDENABLE | R852_CTL_ON);
+-		else
+-			dev->ctlreg &= ~R852_CTL_WRITE;
+-
+-		/* when write is stareted, enable write access */
+-		if (dat == NAND_CMD_ERASE1)
+-			dev->ctlreg |= R852_CTL_WRITE;
+-
+-		r852_write_reg(dev, R852_CTL, dev->ctlreg);
+-	}
+-
+-	 /* HACK: NAND_CMD_SEQIN is called without NAND_CTRL_CHANGE, but we need
+-		to set write mode */
+-	if (dat == NAND_CMD_SEQIN && (dev->ctlreg & R852_CTL_COMMAND)) {
+-		dev->ctlreg |= R852_CTL_WRITE;
+-		r852_write_reg(dev, R852_CTL, dev->ctlreg);
+-	}
+-
+-	if (dat != NAND_CMD_NONE)
+-		r852_write_reg(dev, R852_DATALINE, dat);
+-}
+-
+-/*
+- * Wait till card is ready.
+- * based on nand_wait, but returns errors on DMA error
+- */
+-static int r852_wait(struct mtd_info *mtd, struct nand_chip *chip)
+-{
+-	struct r852_device *dev = nand_get_controller_data(chip);
+-
+-	unsigned long timeout;
+-	int status;
+-
+-	timeout = jiffies + (chip->state == FL_ERASING ?
+-		msecs_to_jiffies(400) : msecs_to_jiffies(20));
+-
+-	while (time_before(jiffies, timeout))
+-		if (chip->dev_ready(mtd))
+-			break;
+-
+-	chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
+-	status = (int)chip->read_byte(mtd);
+-
+-	/* Unfortunelly, no way to send detailed error status... */
+-	if (dev->dma_error) {
+-		status |= NAND_STATUS_FAIL;
+-		dev->dma_error = 0;
+-	}
+-	return status;
+-}
+-
+-/*
+- * Check if card is ready
+- */
+-
+-static int r852_ready(struct mtd_info *mtd)
+-{
+-	struct r852_device *dev = r852_get_dev(mtd);
+-	return !(r852_read_reg(dev, R852_CARD_STA) & R852_CARD_STA_BUSY);
+-}
+-
+-
+-/*
+- * Set ECC engine mode
+-*/
+-
+-static void r852_ecc_hwctl(struct mtd_info *mtd, int mode)
+-{
+-	struct r852_device *dev = r852_get_dev(mtd);
+-
+-	if (dev->card_unstable)
+-		return;
+-
+-	switch (mode) {
+-	case NAND_ECC_READ:
+-	case NAND_ECC_WRITE:
+-		/* enable ecc generation/check*/
+-		dev->ctlreg |= R852_CTL_ECC_ENABLE;
+-
+-		/* flush ecc buffer */
+-		r852_write_reg(dev, R852_CTL,
+-			dev->ctlreg | R852_CTL_ECC_ACCESS);
+-
+-		r852_read_reg_dword(dev, R852_DATALINE);
+-		r852_write_reg(dev, R852_CTL, dev->ctlreg);
+-		return;
+-
+-	case NAND_ECC_READSYN:
+-		/* disable ecc generation */
+-		dev->ctlreg &= ~R852_CTL_ECC_ENABLE;
+-		r852_write_reg(dev, R852_CTL, dev->ctlreg);
+-	}
+-}
+-
+-/*
+- * Calculate ECC, only used for writes
+- */
+-
+-static int r852_ecc_calculate(struct mtd_info *mtd, const uint8_t *dat,
+-							uint8_t *ecc_code)
+-{
+-	struct r852_device *dev = r852_get_dev(mtd);
+-	struct sm_oob *oob = (struct sm_oob *)ecc_code;
+-	uint32_t ecc1, ecc2;
+-
+-	if (dev->card_unstable)
+-		return 0;
+-
+-	dev->ctlreg &= ~R852_CTL_ECC_ENABLE;
+-	r852_write_reg(dev, R852_CTL, dev->ctlreg | R852_CTL_ECC_ACCESS);
+-
+-	ecc1 = r852_read_reg_dword(dev, R852_DATALINE);
+-	ecc2 = r852_read_reg_dword(dev, R852_DATALINE);
+-
+-	oob->ecc1[0] = (ecc1) & 0xFF;
+-	oob->ecc1[1] = (ecc1 >> 8) & 0xFF;
+-	oob->ecc1[2] = (ecc1 >> 16) & 0xFF;
+-
+-	oob->ecc2[0] = (ecc2) & 0xFF;
+-	oob->ecc2[1] = (ecc2 >> 8) & 0xFF;
+-	oob->ecc2[2] = (ecc2 >> 16) & 0xFF;
+-
+-	r852_write_reg(dev, R852_CTL, dev->ctlreg);
+-	return 0;
+-}
+-
+-/*
+- * Correct the data using ECC, hw did almost everything for us
+- */
+-
+-static int r852_ecc_correct(struct mtd_info *mtd, uint8_t *dat,
+-				uint8_t *read_ecc, uint8_t *calc_ecc)
+-{
+-	uint32_t ecc_reg;
+-	uint8_t ecc_status, err_byte;
+-	int i, error = 0;
+-
+-	struct r852_device *dev = r852_get_dev(mtd);
+-
+-	if (dev->card_unstable)
+-		return 0;
+-
+-	if (dev->dma_error) {
+-		dev->dma_error = 0;
+-		return -EIO;
+-	}
+-
+-	r852_write_reg(dev, R852_CTL, dev->ctlreg | R852_CTL_ECC_ACCESS);
+-	ecc_reg = r852_read_reg_dword(dev, R852_DATALINE);
+-	r852_write_reg(dev, R852_CTL, dev->ctlreg);
+-
+-	for (i = 0 ; i <= 1 ; i++) {
+-
+-		ecc_status = (ecc_reg >> 8) & 0xFF;
+-
+-		/* ecc uncorrectable error */
+-		if (ecc_status & R852_ECC_FAIL) {
+-			dbg("ecc: unrecoverable error, in half %d", i);
+-			error = -EBADMSG;
+-			goto exit;
+-		}
+-
+-		/* correctable error */
+-		if (ecc_status & R852_ECC_CORRECTABLE) {
+-
+-			err_byte = ecc_reg & 0xFF;
+-			dbg("ecc: recoverable error, "
+-				"in half %d, byte %d, bit %d", i,
+-				err_byte, ecc_status & R852_ECC_ERR_BIT_MSK);
+-
+-			dat[err_byte] ^=
+-				1 << (ecc_status & R852_ECC_ERR_BIT_MSK);
+-			error++;
+-		}
+-
+-		dat += 256;
+-		ecc_reg >>= 16;
+-	}
+-exit:
+-	return error;
+-}
+-
+-/*
+- * This is copy of nand_read_oob_std
+- * nand_read_oob_syndrome assumes we can send column address - we can't
+- */
+-static int r852_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
+-			     int page)
+-{
+-	chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
+-	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+-	return 0;
+-}
+-
+-/*
+- * Start the nand engine
+- */
+-
+-static void r852_engine_enable(struct r852_device *dev)
+-{
+-	if (r852_read_reg_dword(dev, R852_HW) & R852_HW_UNKNOWN) {
+-		r852_write_reg(dev, R852_CTL, R852_CTL_RESET | R852_CTL_ON);
+-		r852_write_reg_dword(dev, R852_HW, R852_HW_ENABLED);
+-	} else {
+-		r852_write_reg_dword(dev, R852_HW, R852_HW_ENABLED);
+-		r852_write_reg(dev, R852_CTL, R852_CTL_RESET | R852_CTL_ON);
+-	}
+-	msleep(300);
+-	r852_write_reg(dev, R852_CTL, 0);
+-}
+-
+-
+-/*
+- * Stop the nand engine
+- */
+-
+-static void r852_engine_disable(struct r852_device *dev)
+-{
+-	r852_write_reg_dword(dev, R852_HW, 0);
+-	r852_write_reg(dev, R852_CTL, R852_CTL_RESET);
+-}
+-
+-/*
+- * Test if card is present
+- */
+-
+-static void r852_card_update_present(struct r852_device *dev)
+-{
+-	unsigned long flags;
+-	uint8_t reg;
+-
+-	spin_lock_irqsave(&dev->irqlock, flags);
+-	reg = r852_read_reg(dev, R852_CARD_STA);
+-	dev->card_detected = !!(reg & R852_CARD_STA_PRESENT);
+-	spin_unlock_irqrestore(&dev->irqlock, flags);
+-}
+-
+-/*
+- * Update card detection IRQ state according to current card state
+- * which is read in r852_card_update_present
+- */
+-static void r852_update_card_detect(struct r852_device *dev)
+-{
+-	int card_detect_reg = r852_read_reg(dev, R852_CARD_IRQ_ENABLE);
+-	dev->card_unstable = 0;
+-
+-	card_detect_reg &= ~(R852_CARD_IRQ_REMOVE | R852_CARD_IRQ_INSERT);
+-	card_detect_reg |= R852_CARD_IRQ_GENABLE;
+-
+-	card_detect_reg |= dev->card_detected ?
+-		R852_CARD_IRQ_REMOVE : R852_CARD_IRQ_INSERT;
+-
+-	r852_write_reg(dev, R852_CARD_IRQ_ENABLE, card_detect_reg);
+-}
+-
+-static ssize_t r852_media_type_show(struct device *sys_dev,
+-			struct device_attribute *attr, char *buf)
+-{
+-	struct mtd_info *mtd = container_of(sys_dev, struct mtd_info, dev);
+-	struct r852_device *dev = r852_get_dev(mtd);
+-	char *data = dev->sm ? "smartmedia" : "xd";
+-
+-	strcpy(buf, data);
+-	return strlen(data);
+-}
+-
+-static DEVICE_ATTR(media_type, S_IRUGO, r852_media_type_show, NULL);
+-
+-
+-/* Detect properties of card in slot */
+-static void r852_update_media_status(struct r852_device *dev)
+-{
+-	uint8_t reg;
+-	unsigned long flags;
+-	int readonly;
+-
+-	spin_lock_irqsave(&dev->irqlock, flags);
+-	if (!dev->card_detected) {
+-		message("card removed");
+-		spin_unlock_irqrestore(&dev->irqlock, flags);
+-		return ;
+-	}
+-
+-	readonly  = r852_read_reg(dev, R852_CARD_STA) & R852_CARD_STA_RO;
+-	reg = r852_read_reg(dev, R852_DMA_CAP);
+-	dev->sm = (reg & (R852_DMA1 | R852_DMA2)) && (reg & R852_SMBIT);
+-
+-	message("detected %s %s card in slot",
+-		dev->sm ? "SmartMedia" : "xD",
+-		readonly ? "readonly" : "writeable");
+-
+-	dev->readonly = readonly;
+-	spin_unlock_irqrestore(&dev->irqlock, flags);
+-}
+-
+-/*
+- * Register the nand device
+- * Called when the card is detected
+- */
+-static int r852_register_nand_device(struct r852_device *dev)
+-{
+-	struct mtd_info *mtd = nand_to_mtd(dev->chip);
+-
+-	WARN_ON(dev->card_registred);
+-
+-	mtd->dev.parent = &dev->pci_dev->dev;
+-
+-	if (dev->readonly)
+-		dev->chip->options |= NAND_ROM;
+-
+-	r852_engine_enable(dev);
+-
+-	if (sm_register_device(mtd, dev->sm))
+-		goto error1;
+-
+-	if (device_create_file(&mtd->dev, &dev_attr_media_type)) {
+-		message("can't create media type sysfs attribute");
+-		goto error3;
+-	}
+-
+-	dev->card_registred = 1;
+-	return 0;
+-error3:
+-	nand_release(mtd);
+-error1:
+-	/* Force card redetect */
+-	dev->card_detected = 0;
+-	return -1;
+-}
+-
+-/*
+- * Unregister the card
+- */
+-
+-static void r852_unregister_nand_device(struct r852_device *dev)
+-{
+-	struct mtd_info *mtd = nand_to_mtd(dev->chip);
+-
+-	if (!dev->card_registred)
+-		return;
+-
+-	device_remove_file(&mtd->dev, &dev_attr_media_type);
+-	nand_release(mtd);
+-	r852_engine_disable(dev);
+-	dev->card_registred = 0;
+-}
+-
+-/* Card state updater */
+-static void r852_card_detect_work(struct work_struct *work)
+-{
+-	struct r852_device *dev =
+-		container_of(work, struct r852_device, card_detect_work.work);
+-
+-	r852_card_update_present(dev);
+-	r852_update_card_detect(dev);
+-	dev->card_unstable = 0;
+-
+-	/* False alarm */
+-	if (dev->card_detected == dev->card_registred)
+-		goto exit;
+-
+-	/* Read media properties */
+-	r852_update_media_status(dev);
+-
+-	/* Register the card */
+-	if (dev->card_detected)
+-		r852_register_nand_device(dev);
+-	else
+-		r852_unregister_nand_device(dev);
+-exit:
+-	r852_update_card_detect(dev);
+-}
+-
+-/* Ack + disable IRQ generation */
+-static void r852_disable_irqs(struct r852_device *dev)
+-{
+-	uint8_t reg;
+-	reg = r852_read_reg(dev, R852_CARD_IRQ_ENABLE);
+-	r852_write_reg(dev, R852_CARD_IRQ_ENABLE, reg & ~R852_CARD_IRQ_MASK);
+-
+-	reg = r852_read_reg_dword(dev, R852_DMA_IRQ_ENABLE);
+-	r852_write_reg_dword(dev, R852_DMA_IRQ_ENABLE,
+-					reg & ~R852_DMA_IRQ_MASK);
+-
+-	r852_write_reg(dev, R852_CARD_IRQ_STA, R852_CARD_IRQ_MASK);
+-	r852_write_reg_dword(dev, R852_DMA_IRQ_STA, R852_DMA_IRQ_MASK);
+-}
+-
+-/* Interrupt handler */
+-static irqreturn_t r852_irq(int irq, void *data)
+-{
+-	struct r852_device *dev = (struct r852_device *)data;
+-
+-	uint8_t card_status, dma_status;
+-	unsigned long flags;
+-	irqreturn_t ret = IRQ_NONE;
+-
+-	spin_lock_irqsave(&dev->irqlock, flags);
+-
+-	/* handle card detection interrupts first */
+-	card_status = r852_read_reg(dev, R852_CARD_IRQ_STA);
+-	r852_write_reg(dev, R852_CARD_IRQ_STA, card_status);
+-
+-	if (card_status & (R852_CARD_IRQ_INSERT|R852_CARD_IRQ_REMOVE)) {
+-
+-		ret = IRQ_HANDLED;
+-		dev->card_detected = !!(card_status & R852_CARD_IRQ_INSERT);
+-
+-		/* we shouldn't receive any interrupts if we wait for card
+-			to settle */
+-		WARN_ON(dev->card_unstable);
+-
+-		/* disable irqs while card is unstable */
+-		/* this will timeout DMA if active, but better that garbage */
+-		r852_disable_irqs(dev);
+-
+-		if (dev->card_unstable)
+-			goto out;
+-
+-		/* let, card state to settle a bit, and then do the work */
+-		dev->card_unstable = 1;
+-		queue_delayed_work(dev->card_workqueue,
+-			&dev->card_detect_work, msecs_to_jiffies(100));
+-		goto out;
+-	}
+-
+-
+-	/* Handle dma interrupts */
+-	dma_status = r852_read_reg_dword(dev, R852_DMA_IRQ_STA);
+-	r852_write_reg_dword(dev, R852_DMA_IRQ_STA, dma_status);
+-
+-	if (dma_status & R852_DMA_IRQ_MASK) {
+-
+-		ret = IRQ_HANDLED;
+-
+-		if (dma_status & R852_DMA_IRQ_ERROR) {
+-			dbg("received dma error IRQ");
+-			r852_dma_done(dev, -EIO);
+-			complete(&dev->dma_done);
+-			goto out;
+-		}
+-
+-		/* received DMA interrupt out of nowhere? */
+-		WARN_ON_ONCE(dev->dma_stage == 0);
+-
+-		if (dev->dma_stage == 0)
+-			goto out;
+-
+-		/* done device access */
+-		if (dev->dma_state == DMA_INTERNAL &&
+-				(dma_status & R852_DMA_IRQ_INTERNAL)) {
+-
+-			dev->dma_state = DMA_MEMORY;
+-			dev->dma_stage++;
+-		}
+-
+-		/* done memory DMA */
+-		if (dev->dma_state == DMA_MEMORY &&
+-				(dma_status & R852_DMA_IRQ_MEMORY)) {
+-			dev->dma_state = DMA_INTERNAL;
+-			dev->dma_stage++;
+-		}
+-
+-		/* Enable 2nd half of dma dance */
+-		if (dev->dma_stage == 2)
+-			r852_dma_enable(dev);
+-
+-		/* Operation done */
+-		if (dev->dma_stage == 3) {
+-			r852_dma_done(dev, 0);
+-			complete(&dev->dma_done);
+-		}
+-		goto out;
+-	}
+-
+-	/* Handle unknown interrupts */
+-	if (dma_status)
+-		dbg("bad dma IRQ status = %x", dma_status);
+-
+-	if (card_status & ~R852_CARD_STA_CD)
+-		dbg("strange card status = %x", card_status);
+-
+-out:
+-	spin_unlock_irqrestore(&dev->irqlock, flags);
+-	return ret;
+-}
+-
+-static int  r852_probe(struct pci_dev *pci_dev, const struct pci_device_id *id)
+-{
+-	int error;
+-	struct nand_chip *chip;
+-	struct r852_device *dev;
+-
+-	/* pci initialization */
+-	error = pci_enable_device(pci_dev);
+-
+-	if (error)
+-		goto error1;
+-
+-	pci_set_master(pci_dev);
+-
+-	error = pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32));
+-	if (error)
+-		goto error2;
+-
+-	error = pci_request_regions(pci_dev, DRV_NAME);
+-
+-	if (error)
+-		goto error3;
+-
+-	error = -ENOMEM;
+-
+-	/* init nand chip, but register it only on card insert */
+-	chip = kzalloc(sizeof(struct nand_chip), GFP_KERNEL);
+-
+-	if (!chip)
+-		goto error4;
+-
+-	/* commands */
+-	chip->cmd_ctrl = r852_cmdctl;
+-	chip->waitfunc = r852_wait;
+-	chip->dev_ready = r852_ready;
+-
+-	/* I/O */
+-	chip->read_byte = r852_read_byte;
+-	chip->read_buf = r852_read_buf;
+-	chip->write_buf = r852_write_buf;
+-
+-	/* ecc */
+-	chip->ecc.mode = NAND_ECC_HW_SYNDROME;
+-	chip->ecc.size = R852_DMA_LEN;
+-	chip->ecc.bytes = SM_OOB_SIZE;
+-	chip->ecc.strength = 2;
+-	chip->ecc.hwctl = r852_ecc_hwctl;
+-	chip->ecc.calculate = r852_ecc_calculate;
+-	chip->ecc.correct = r852_ecc_correct;
+-
+-	/* TODO: hack */
+-	chip->ecc.read_oob = r852_read_oob;
+-
+-	/* init our device structure */
+-	dev = kzalloc(sizeof(struct r852_device), GFP_KERNEL);
+-
+-	if (!dev)
+-		goto error5;
+-
+-	nand_set_controller_data(chip, dev);
+-	dev->chip = chip;
+-	dev->pci_dev = pci_dev;
+-	pci_set_drvdata(pci_dev, dev);
+-
+-	dev->bounce_buffer = pci_alloc_consistent(pci_dev, R852_DMA_LEN,
+-		&dev->phys_bounce_buffer);
+-
+-	if (!dev->bounce_buffer)
+-		goto error6;
+-
+-
+-	error = -ENODEV;
+-	dev->mmio = pci_ioremap_bar(pci_dev, 0);
+-
+-	if (!dev->mmio)
+-		goto error7;
+-
+-	error = -ENOMEM;
+-	dev->tmp_buffer = kzalloc(SM_SECTOR_SIZE, GFP_KERNEL);
+-
+-	if (!dev->tmp_buffer)
+-		goto error8;
+-
+-	init_completion(&dev->dma_done);
+-
+-	dev->card_workqueue = create_freezable_workqueue(DRV_NAME);
+-
+-	if (!dev->card_workqueue)
+-		goto error9;
+-
+-	INIT_DELAYED_WORK(&dev->card_detect_work, r852_card_detect_work);
+-
+-	/* shutdown everything - precation */
+-	r852_engine_disable(dev);
+-	r852_disable_irqs(dev);
+-
+-	r852_dma_test(dev);
+-
+-	dev->irq = pci_dev->irq;
+-	spin_lock_init(&dev->irqlock);
+-
+-	dev->card_detected = 0;
+-	r852_card_update_present(dev);
+-
+-	/*register irq handler*/
+-	error = -ENODEV;
+-	if (request_irq(pci_dev->irq, &r852_irq, IRQF_SHARED,
+-			  DRV_NAME, dev))
+-		goto error10;
+-
+-	/* kick initial present test */
+-	queue_delayed_work(dev->card_workqueue,
+-		&dev->card_detect_work, 0);
+-
+-
+-	printk(KERN_NOTICE DRV_NAME ": driver loaded successfully\n");
+-	return 0;
+-
+-error10:
+-	destroy_workqueue(dev->card_workqueue);
+-error9:
+-	kfree(dev->tmp_buffer);
+-error8:
+-	pci_iounmap(pci_dev, dev->mmio);
+-error7:
+-	pci_free_consistent(pci_dev, R852_DMA_LEN,
+-		dev->bounce_buffer, dev->phys_bounce_buffer);
+-error6:
+-	kfree(dev);
+-error5:
+-	kfree(chip);
+-error4:
+-	pci_release_regions(pci_dev);
+-error3:
+-error2:
+-	pci_disable_device(pci_dev);
+-error1:
+-	return error;
+-}
+-
+-static void r852_remove(struct pci_dev *pci_dev)
+-{
+-	struct r852_device *dev = pci_get_drvdata(pci_dev);
+-
+-	/* Stop detect workqueue -
+-		we are going to unregister the device anyway*/
+-	cancel_delayed_work_sync(&dev->card_detect_work);
+-	destroy_workqueue(dev->card_workqueue);
+-
+-	/* Unregister the device, this might make more IO */
+-	r852_unregister_nand_device(dev);
+-
+-	/* Stop interrupts */
+-	r852_disable_irqs(dev);
+-	free_irq(dev->irq, dev);
+-
+-	/* Cleanup */
+-	kfree(dev->tmp_buffer);
+-	pci_iounmap(pci_dev, dev->mmio);
+-	pci_free_consistent(pci_dev, R852_DMA_LEN,
+-		dev->bounce_buffer, dev->phys_bounce_buffer);
+-
+-	kfree(dev->chip);
+-	kfree(dev);
+-
+-	/* Shutdown the PCI device */
+-	pci_release_regions(pci_dev);
+-	pci_disable_device(pci_dev);
+-}
+-
+-static void r852_shutdown(struct pci_dev *pci_dev)
+-{
+-	struct r852_device *dev = pci_get_drvdata(pci_dev);
+-
+-	cancel_delayed_work_sync(&dev->card_detect_work);
+-	r852_disable_irqs(dev);
+-	synchronize_irq(dev->irq);
+-	pci_disable_device(pci_dev);
+-}
+-
+-#ifdef CONFIG_PM_SLEEP
+-static int r852_suspend(struct device *device)
+-{
+-	struct r852_device *dev = pci_get_drvdata(to_pci_dev(device));
+-
+-	if (dev->ctlreg & R852_CTL_CARDENABLE)
+-		return -EBUSY;
+-
+-	/* First make sure the detect work is gone */
+-	cancel_delayed_work_sync(&dev->card_detect_work);
+-
+-	/* Turn off the interrupts and stop the device */
+-	r852_disable_irqs(dev);
+-	r852_engine_disable(dev);
+-
+-	/* If card was pulled off just during the suspend, which is very
+-		unlikely, we will remove it on resume, it too late now
+-		anyway... */
+-	dev->card_unstable = 0;
+-	return 0;
+-}
+-
+-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);
+-
+-	r852_disable_irqs(dev);
+-	r852_card_update_present(dev);
+-	r852_engine_disable(dev);
+-
+-
+-	/* If card status changed, just do the work */
+-	if (dev->card_detected != dev->card_registred) {
+-		dbg("card was %s during low power state",
+-			dev->card_detected ? "added" : "removed");
+-
+-		queue_delayed_work(dev->card_workqueue,
+-		&dev->card_detect_work, msecs_to_jiffies(1000));
+-		return 0;
+-	}
+-
+-	/* Otherwise, initialize the card */
+-	if (dev->card_registred) {
+-		r852_engine_enable(dev);
+-		dev->chip->select_chip(mtd, 0);
+-		dev->chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
+-		dev->chip->select_chip(mtd, -1);
+-	}
+-
+-	/* Program card detection IRQ */
+-	r852_update_card_detect(dev);
+-	return 0;
+-}
+-#endif
+-
+-static const struct pci_device_id r852_pci_id_tbl[] = {
+-
+-	{ PCI_VDEVICE(RICOH, 0x0852), },
+-	{ },
+-};
+-
+-MODULE_DEVICE_TABLE(pci, r852_pci_id_tbl);
+-
+-static SIMPLE_DEV_PM_OPS(r852_pm_ops, r852_suspend, r852_resume);
+-
+-static struct pci_driver r852_pci_driver = {
+-	.name		= DRV_NAME,
+-	.id_table	= r852_pci_id_tbl,
+-	.probe		= r852_probe,
+-	.remove		= r852_remove,
+-	.shutdown	= r852_shutdown,
+-	.driver.pm	= &r852_pm_ops,
+-};
+-
+-module_pci_driver(r852_pci_driver);
+-
+-MODULE_LICENSE("GPL");
+-MODULE_AUTHOR("Maxim Levitsky <maximlevitsky@gmail.com>");
+-MODULE_DESCRIPTION("Ricoh 85xx xD/smartmedia card reader driver");
+diff --git a/drivers/mtd/nand/r852.h b/drivers/mtd/nand/r852.h
+deleted file mode 100644
+index 8713c57..0000000
+--- a/drivers/mtd/nand/r852.h
++++ /dev/null
+@@ -1,160 +0,0 @@
+-/*
+- * Copyright © 2009 - Maxim Levitsky
+- * driver for Ricoh xD readers
+- *
+- * 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/pci.h>
+-#include <linux/completion.h>
+-#include <linux/workqueue.h>
+-#include <linux/mtd/rawnand.h>
+-#include <linux/spinlock.h>
+-
+-
+-/* nand interface + ecc
+-   byte write/read does one cycle on nand data lines.
+-   dword write/read does 4 cycles
+-   if R852_CTL_ECC_ACCESS is set in R852_CTL, then dword read reads
+-   results of ecc correction, if DMA read was done before.
+-   If write was done two dword reads read generated ecc checksums
+-*/
+-#define	R852_DATALINE		0x00
+-
+-/* control register */
+-#define R852_CTL		0x04
+-#define R852_CTL_COMMAND 	0x01	/* send command (#CLE)*/
+-#define R852_CTL_DATA		0x02	/* read/write data (#ALE)*/
+-#define R852_CTL_ON		0x04	/* only seem to controls the hd led, */
+-					/* but has to be set on start...*/
+-#define R852_CTL_RESET		0x08	/* unknown, set only on start once*/
+-#define R852_CTL_CARDENABLE	0x10	/* probably (#CE) - always set*/
+-#define R852_CTL_ECC_ENABLE	0x20	/* enable ecc engine */
+-#define R852_CTL_ECC_ACCESS	0x40	/* read/write ecc via reg #0*/
+-#define R852_CTL_WRITE		0x80	/* set when performing writes (#WP) */
+-
+-/* card detection status */
+-#define R852_CARD_STA		0x05
+-
+-#define R852_CARD_STA_CD	0x01	/* state of #CD line, same as 0x04 */
+-#define R852_CARD_STA_RO	0x02	/* card is readonly */
+-#define R852_CARD_STA_PRESENT	0x04	/* card is present (#CD) */
+-#define R852_CARD_STA_ABSENT	0x08	/* card is absent */
+-#define R852_CARD_STA_BUSY	0x80	/* card is busy - (#R/B) */
+-
+-/* card detection irq status & enable*/
+-#define R852_CARD_IRQ_STA	0x06	/* IRQ status */
+-#define R852_CARD_IRQ_ENABLE	0x07	/* IRQ enable */
+-
+-#define R852_CARD_IRQ_CD	0x01	/* fire when #CD lights, same as 0x04*/
+-#define R852_CARD_IRQ_REMOVE	0x04	/* detect card removal */
+-#define R852_CARD_IRQ_INSERT	0x08	/* detect card insert */
+-#define R852_CARD_IRQ_UNK1	0x10	/* unknown */
+-#define R852_CARD_IRQ_GENABLE	0x80	/* general enable */
+-#define R852_CARD_IRQ_MASK	0x1D
+-
+-
+-
+-/* hardware enable */
+-#define R852_HW			0x08
+-#define R852_HW_ENABLED		0x01	/* hw enabled */
+-#define R852_HW_UNKNOWN		0x80
+-
+-
+-/* dma capabilities */
+-#define R852_DMA_CAP		0x09
+-#define R852_SMBIT		0x20	/* if set with bit #6 or bit #7, then */
+-					/* hw is smartmedia */
+-#define R852_DMA1		0x40	/* if set w/bit #7, dma is supported */
+-#define R852_DMA2		0x80	/* if set w/bit #6, dma is supported */
+-
+-
+-/* physical DMA address - 32 bit value*/
+-#define R852_DMA_ADDR		0x0C
+-
+-
+-/* dma settings */
+-#define R852_DMA_SETTINGS	0x10
+-#define R852_DMA_MEMORY		0x01	/* (memory <-> internal hw buffer) */
+-#define R852_DMA_READ		0x02	/* 0 = write, 1 = read */
+-#define R852_DMA_INTERNAL	0x04	/* (internal hw buffer <-> card) */
+-
+-/* dma IRQ status */
+-#define R852_DMA_IRQ_STA		0x14
+-
+-/* dma IRQ enable */
+-#define R852_DMA_IRQ_ENABLE	0x18
+-
+-#define R852_DMA_IRQ_MEMORY	0x01	/* (memory <-> internal hw buffer) */
+-#define R852_DMA_IRQ_ERROR	0x02	/* error did happen */
+-#define R852_DMA_IRQ_INTERNAL	0x04	/* (internal hw buffer <-> card) */
+-#define R852_DMA_IRQ_MASK	0x07	/* mask of all IRQ bits */
+-
+-
+-/* ECC syndrome format - read from reg #0 will return two copies of these for
+-   each half of the page.
+-   first byte is error byte location, and second, bit location + flags */
+-#define R852_ECC_ERR_BIT_MSK	0x07	/* error bit location */
+-#define R852_ECC_CORRECT		0x10	/* no errors - (guessed) */
+-#define R852_ECC_CORRECTABLE	0x20	/* correctable error exist */
+-#define R852_ECC_FAIL		0x40	/* non correctable error detected */
+-
+-#define R852_DMA_LEN		512
+-
+-#define DMA_INTERNAL	0
+-#define DMA_MEMORY	1
+-
+-struct r852_device {
+-	void __iomem *mmio;		/* mmio */
+-	struct nand_chip *chip;		/* nand chip backpointer */
+-	struct pci_dev *pci_dev;	/* pci backpointer */
+-
+-	/* dma area */
+-	dma_addr_t phys_dma_addr;	/* bus address of buffer*/
+-	struct completion dma_done;	/* data transfer done */
+-
+-	dma_addr_t phys_bounce_buffer;	/* bus address of bounce buffer */
+-	uint8_t *bounce_buffer;		/* virtual address of bounce buffer */
+-
+-	int dma_dir;			/* 1 = read, 0 = write */
+-	int dma_stage;			/* 0 - idle, 1 - first step,
+-					   2 - second step */
+-
+-	int dma_state;			/* 0 = internal, 1 = memory */
+-	int dma_error;			/* dma errors */
+-	int dma_usable;			/* is it possible to use dma */
+-
+-	/* card status area */
+-	struct delayed_work card_detect_work;
+-	struct workqueue_struct *card_workqueue;
+-	int card_registred;		/* card registered with mtd */
+-	int card_detected;		/* card detected in slot */
+-	int card_unstable;		/* whenever the card is inserted,
+-					   is not known yet */
+-	int readonly;			/* card is readonly */
+-	int sm;				/* Is card smartmedia */
+-
+-	/* interrupt handling */
+-	spinlock_t irqlock;		/* IRQ protecting lock */
+-	int irq;			/* irq num */
+-	/* misc */
+-	void *tmp_buffer;		/* temporary buffer */
+-	uint8_t ctlreg;			/* cached contents of control reg */
+-};
+-
+-#define DRV_NAME "r852"
+-
+-
+-#define dbg(format, ...) \
+-	if (debug) \
+-		printk(KERN_DEBUG DRV_NAME ": " format "\n", ## __VA_ARGS__)
+-
+-#define dbg_verbose(format, ...) \
+-	if (debug > 1) \
+-		printk(KERN_DEBUG DRV_NAME ": " format "\n", ## __VA_ARGS__)
+-
+-
+-#define message(format, ...) \
+-	printk(KERN_INFO DRV_NAME ": " format "\n", ## __VA_ARGS__)
+diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig
+new file mode 100644
+index 0000000..0c179e6
+--- /dev/null
++++ b/drivers/mtd/nand/raw/Kconfig
+@@ -0,0 +1,573 @@
++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_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_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_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_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_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
++	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"
++	depends on ARCH_AT91
++	select MFD_ATMEL_SMC
++	help
++	  Enables support for NAND Flash / Smart Media Card interface
++	  on Atmel AT91 processors.
++
++config MTD_NAND_PXA3xx
++	tristate "NAND support on PXA3xx and Armada 370/XP"
++	depends on PXA3xx || ARCH_MMP || PLAT_ORION || ARCH_MVEBU
++	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_OXNAS
++	tristate "NAND Flash support for Oxford Semiconductor SoC"
++	depends on ARCH_OXNAS || COMPILE_TEST
++	depends on HAS_IOMEM
++	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
++	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 || SOC_LS1021A
++	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 OF
++	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
++	bool "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 ARCH_HISI || COMPILE_TEST
++	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 ARCH_MEDIATEK || COMPILE_TEST
++	depends on HAS_DMA
++	help
++	  Enables support for NAND controller on MTK SoCs.
++	  This controller is found on mt27xx, mt81xx, mt65xx SoCs.
++
++config MTD_NAND_STM32_FMC
++	tristate "Support for NAND controller on STM32"
++	depends on ARCH_STM32
++	help
++	  Enables support for NAND Flash chips on the ST Microelectronics
++	  Flexible Memory Controller (FMC)
++
++endif # MTD_NAND
+diff --git a/drivers/mtd/nand/raw/Makefile b/drivers/mtd/nand/raw/Makefile
+new file mode 100644
+index 0000000..7c2606f
+--- /dev/null
++++ b/drivers/mtd/nand/raw/Makefile
+@@ -0,0 +1,71 @@
++# SPDX-License-Identifier: GPL-2.0
++#
++# linux/drivers/nand/raw/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_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_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
++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/
++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_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
++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
++obj-$(CONFIG_MTD_NAND_STM32_FMC)	+= stm32_fmc.o
++
++nand-objs := nand_base.o nand_bbt.o nand_timings.o nand_ids.o
++nand-objs += nand_amd.o
++nand-objs += nand_hynix.o
++nand-objs += nand_macronix.o
++nand-objs += nand_micron.o
++nand-objs += nand_samsung.o
++nand-objs += nand_toshiba.o
+diff --git a/drivers/mtd/nand/raw/ams-delta.c b/drivers/mtd/nand/raw/ams-delta.c
+new file mode 100644
+index 0000000..dcec9cf
+--- /dev/null
++++ b/drivers/mtd/nand/raw/ams-delta.c
+@@ -0,0 +1,290 @@
++/*
++ *  drivers/mtd/nand/ams-delta.c
++ *
++ *  Copyright (C) 2006 Jonathan McDowell <noodles@earth.li>
++ *
++ *  Derived from drivers/mtd/toto.c
++ *  Converted to platform driver by Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>
++ *  Partially stolen from drivers/mtd/nand/plat_nand.c
++ *
++ * 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.
++ *
++ *  Overview:
++ *   This is a device driver for the NAND flash device found on the
++ *   Amstrad E3 (Delta).
++ */
++
++#include <linux/slab.h>
++#include <linux/module.h>
++#include <linux/delay.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/rawnand.h>
++#include <linux/mtd/partitions.h>
++#include <linux/gpio.h>
++#include <linux/platform_data/gpio-omap.h>
++
++#include <asm/io.h>
++#include <asm/sizes.h>
++
++#include <mach/board-ams-delta.h>
++
++#include <mach/hardware.h>
++
++/*
++ * MTD structure for E3 (Delta)
++ */
++static struct mtd_info *ams_delta_mtd = NULL;
++
++/*
++ * Define partitions for flash devices
++ */
++
++static struct mtd_partition partition_info[] = {
++	{ .name		= "Kernel",
++	  .offset	= 0,
++	  .size		= 3 * SZ_1M + SZ_512K },
++	{ .name		= "u-boot",
++	  .offset	= 3 * SZ_1M + SZ_512K,
++	  .size		= SZ_256K },
++	{ .name		= "u-boot params",
++	  .offset	= 3 * SZ_1M + SZ_512K + SZ_256K,
++	  .size		= SZ_256K },
++	{ .name		= "Amstrad LDR",
++	  .offset	= 4 * SZ_1M,
++	  .size		= SZ_256K },
++	{ .name		= "File system",
++	  .offset	= 4 * SZ_1M + 1 * SZ_256K,
++	  .size		= 27 * SZ_1M },
++	{ .name		= "PBL reserved",
++	  .offset	= 32 * SZ_1M - 3 * SZ_256K,
++	  .size		=  3 * SZ_256K },
++};
++
++static void ams_delta_write_byte(struct mtd_info *mtd, u_char byte)
++{
++	struct nand_chip *this = mtd_to_nand(mtd);
++	void __iomem *io_base = (void __iomem *)nand_get_controller_data(this);
++
++	writew(0, io_base + OMAP_MPUIO_IO_CNTL);
++	writew(byte, this->IO_ADDR_W);
++	gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_NWE, 0);
++	ndelay(40);
++	gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_NWE, 1);
++}
++
++static u_char ams_delta_read_byte(struct mtd_info *mtd)
++{
++	u_char res;
++	struct nand_chip *this = mtd_to_nand(mtd);
++	void __iomem *io_base = (void __iomem *)nand_get_controller_data(this);
++
++	gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_NRE, 0);
++	ndelay(40);
++	writew(~0, io_base + OMAP_MPUIO_IO_CNTL);
++	res = readw(this->IO_ADDR_R);
++	gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_NRE, 1);
++
++	return res;
++}
++
++static void ams_delta_write_buf(struct mtd_info *mtd, const u_char *buf,
++				int len)
++{
++	int i;
++
++	for (i=0; i<len; i++)
++		ams_delta_write_byte(mtd, buf[i]);
++}
++
++static void ams_delta_read_buf(struct mtd_info *mtd, u_char *buf, int len)
++{
++	int i;
++
++	for (i=0; i<len; i++)
++		buf[i] = ams_delta_read_byte(mtd);
++}
++
++/*
++ * Command control function
++ *
++ * ctrl:
++ * NAND_NCE: bit 0 -> bit 2
++ * NAND_CLE: bit 1 -> bit 7
++ * NAND_ALE: bit 2 -> bit 6
++ */
++static void ams_delta_hwcontrol(struct mtd_info *mtd, int cmd,
++				unsigned int ctrl)
++{
++
++	if (ctrl & NAND_CTRL_CHANGE) {
++		gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_NCE,
++				(ctrl & NAND_NCE) == 0);
++		gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_CLE,
++				(ctrl & NAND_CLE) != 0);
++		gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_ALE,
++				(ctrl & NAND_ALE) != 0);
++	}
++
++	if (cmd != NAND_CMD_NONE)
++		ams_delta_write_byte(mtd, cmd);
++}
++
++static int ams_delta_nand_ready(struct mtd_info *mtd)
++{
++	return gpio_get_value(AMS_DELTA_GPIO_PIN_NAND_RB);
++}
++
++static const struct gpio _mandatory_gpio[] = {
++	{
++		.gpio	= AMS_DELTA_GPIO_PIN_NAND_NCE,
++		.flags	= GPIOF_OUT_INIT_HIGH,
++		.label	= "nand_nce",
++	},
++	{
++		.gpio	= AMS_DELTA_GPIO_PIN_NAND_NRE,
++		.flags	= GPIOF_OUT_INIT_HIGH,
++		.label	= "nand_nre",
++	},
++	{
++		.gpio	= AMS_DELTA_GPIO_PIN_NAND_NWP,
++		.flags	= GPIOF_OUT_INIT_HIGH,
++		.label	= "nand_nwp",
++	},
++	{
++		.gpio	= AMS_DELTA_GPIO_PIN_NAND_NWE,
++		.flags	= GPIOF_OUT_INIT_HIGH,
++		.label	= "nand_nwe",
++	},
++	{
++		.gpio	= AMS_DELTA_GPIO_PIN_NAND_ALE,
++		.flags	= GPIOF_OUT_INIT_LOW,
++		.label	= "nand_ale",
++	},
++	{
++		.gpio	= AMS_DELTA_GPIO_PIN_NAND_CLE,
++		.flags	= GPIOF_OUT_INIT_LOW,
++		.label	= "nand_cle",
++	},
++};
++
++/*
++ * Main initialization routine
++ */
++static int ams_delta_init(struct platform_device *pdev)
++{
++	struct nand_chip *this;
++	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	void __iomem *io_base;
++	int err = 0;
++
++	if (!res)
++		return -ENXIO;
++
++	/* Allocate memory for MTD device structure and private data */
++	this = kzalloc(sizeof(struct nand_chip), GFP_KERNEL);
++	if (!this) {
++		printk (KERN_WARNING "Unable to allocate E3 NAND MTD device structure.\n");
++		err = -ENOMEM;
++		goto out;
++	}
++
++	ams_delta_mtd = nand_to_mtd(this);
++	ams_delta_mtd->owner = THIS_MODULE;
++
++	/*
++	 * Don't try to request the memory region from here,
++	 * it should have been already requested from the
++	 * gpio-omap driver and requesting it again would fail.
++	 */
++
++	io_base = ioremap(res->start, resource_size(res));
++	if (io_base == NULL) {
++		dev_err(&pdev->dev, "ioremap failed\n");
++		err = -EIO;
++		goto out_free;
++	}
++
++	nand_set_controller_data(this, (void *)io_base);
++
++	/* Set address of NAND IO lines */
++	this->IO_ADDR_R = io_base + OMAP_MPUIO_INPUT_LATCH;
++	this->IO_ADDR_W = io_base + OMAP_MPUIO_OUTPUT;
++	this->read_byte = ams_delta_read_byte;
++	this->write_buf = ams_delta_write_buf;
++	this->read_buf = ams_delta_read_buf;
++	this->cmd_ctrl = ams_delta_hwcontrol;
++	if (gpio_request(AMS_DELTA_GPIO_PIN_NAND_RB, "nand_rdy") == 0) {
++		this->dev_ready = ams_delta_nand_ready;
++	} else {
++		this->dev_ready = NULL;
++		printk(KERN_NOTICE "Couldn't request gpio for Delta NAND ready.\n");
++	}
++	/* 25 us command delay time */
++	this->chip_delay = 30;
++	this->ecc.mode = NAND_ECC_SOFT;
++	this->ecc.algo = NAND_ECC_HAMMING;
++
++	platform_set_drvdata(pdev, io_base);
++
++	/* Set chip enabled, but  */
++	err = gpio_request_array(_mandatory_gpio, ARRAY_SIZE(_mandatory_gpio));
++	if (err)
++		goto out_gpio;
++
++	/* Scan to find existence of the device */
++	err = nand_scan(ams_delta_mtd, 1);
++	if (err)
++		goto out_mtd;
++
++	/* Register the partitions */
++	mtd_device_register(ams_delta_mtd, partition_info,
++			    ARRAY_SIZE(partition_info));
++
++	goto out;
++
++ out_mtd:
++	gpio_free_array(_mandatory_gpio, ARRAY_SIZE(_mandatory_gpio));
++out_gpio:
++	gpio_free(AMS_DELTA_GPIO_PIN_NAND_RB);
++	iounmap(io_base);
++out_free:
++	kfree(this);
++ out:
++	return err;
++}
++
++/*
++ * Clean up routine
++ */
++static int ams_delta_cleanup(struct platform_device *pdev)
++{
++	void __iomem *io_base = platform_get_drvdata(pdev);
++
++	/* Release resources, unregister device */
++	nand_release(ams_delta_mtd);
++
++	gpio_free_array(_mandatory_gpio, ARRAY_SIZE(_mandatory_gpio));
++	gpio_free(AMS_DELTA_GPIO_PIN_NAND_RB);
++	iounmap(io_base);
++
++	/* Free the MTD device structure */
++	kfree(mtd_to_nand(ams_delta_mtd));
++
++	return 0;
++}
++
++static struct platform_driver ams_delta_nand_driver = {
++	.probe		= ams_delta_init,
++	.remove		= ams_delta_cleanup,
++	.driver		= {
++		.name	= "ams-delta-nand",
++	},
++};
++
++module_platform_driver(ams_delta_nand_driver);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Jonathan McDowell <noodles@earth.li>");
++MODULE_DESCRIPTION("Glue layer for NAND flash on Amstrad E3 (Delta)");
+diff --git a/drivers/mtd/nand/raw/atmel/Makefile b/drivers/mtd/nand/raw/atmel/Makefile
+new file mode 100644
+index 0000000..288db4f
+--- /dev/null
++++ b/drivers/mtd/nand/raw/atmel/Makefile
+@@ -0,0 +1,4 @@
++obj-$(CONFIG_MTD_NAND_ATMEL)	+= atmel-nand-controller.o atmel-pmecc.o
++
++atmel-nand-controller-objs	:= nand-controller.o
++atmel-pmecc-objs		:= pmecc.o
+diff --git a/drivers/mtd/nand/raw/atmel/nand-controller.c b/drivers/mtd/nand/raw/atmel/nand-controller.c
+new file mode 100644
+index 0000000..68c9d98
+--- /dev/null
++++ b/drivers/mtd/nand/raw/atmel/nand-controller.c
+@@ -0,0 +1,2560 @@
++/*
++ * Copyright 2017 ATMEL
++ * Copyright 2017 Free Electrons
++ *
++ * Author: Boris Brezillon <boris.brezillon@free-electrons.com>
++ *
++ * Derived from the atmel_nand.c driver which contained the following
++ * copyrights:
++ *
++ *   Copyright 2003 Rick Bronson
++ *
++ *   Derived from drivers/mtd/nand/autcpu12.c
++ *	Copyright 2001 Thomas Gleixner (gleixner@autronix.de)
++ *
++ *   Derived from drivers/mtd/spia.c
++ *	Copyright 2000 Steven J. Hill (sjhill@cotw.com)
++ *
++ *
++ *   Add Hardware ECC support for AT91SAM9260 / AT91SAM9263
++ *	Richard Genoud (richard.genoud@gmail.com), Adeneo Copyright 2007
++ *
++ *   Derived from Das U-Boot source code
++ *	(u-boot-1.1.5/board/atmel/at91sam9263ek/nand.c)
++ *	Copyright 2006 ATMEL Rousset, Lacressonniere Nicolas
++ *
++ *   Add Programmable Multibit ECC support for various AT91 SoC
++ *	Copyright 2012 ATMEL, Hong Xu
++ *
++ *   Add Nand Flash Controller support for SAMA5 SoC
++ *	Copyright 2013 ATMEL, Josh Wu (josh.wu@atmel.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.
++ *
++ * A few words about the naming convention in this file. This convention
++ * applies to structure and function names.
++ *
++ * Prefixes:
++ *
++ * - atmel_nand_: all generic structures/functions
++ * - atmel_smc_nand_: all structures/functions specific to the SMC interface
++ *		      (at91sam9 and avr32 SoCs)
++ * - atmel_hsmc_nand_: all structures/functions specific to the HSMC interface
++ *		       (sama5 SoCs and later)
++ * - atmel_nfc_: all structures/functions used to manipulate the NFC sub-block
++ *		 that is available in the HSMC block
++ * - <soc>_nand_: all SoC specific structures/functions
++ */
++
++#include <linux/clk.h>
++#include <linux/dma-mapping.h>
++#include <linux/dmaengine.h>
++#include <linux/genalloc.h>
++#include <linux/gpio.h>
++#include <linux/gpio/consumer.h>
++#include <linux/interrupt.h>
++#include <linux/mfd/syscon.h>
++#include <linux/mfd/syscon/atmel-matrix.h>
++#include <linux/mfd/syscon/atmel-smc.h>
++#include <linux/module.h>
++#include <linux/mtd/rawnand.h>
++#include <linux/of_address.h>
++#include <linux/of_irq.h>
++#include <linux/of_platform.h>
++#include <linux/iopoll.h>
++#include <linux/platform_device.h>
++#include <linux/regmap.h>
++
++#include "pmecc.h"
++
++#define ATMEL_HSMC_NFC_CFG			0x0
++#define ATMEL_HSMC_NFC_CFG_SPARESIZE(x)		(((x) / 4) << 24)
++#define ATMEL_HSMC_NFC_CFG_SPARESIZE_MASK	GENMASK(30, 24)
++#define ATMEL_HSMC_NFC_CFG_DTO(cyc, mul)	(((cyc) << 16) | ((mul) << 20))
++#define ATMEL_HSMC_NFC_CFG_DTO_MAX		GENMASK(22, 16)
++#define ATMEL_HSMC_NFC_CFG_RBEDGE		BIT(13)
++#define ATMEL_HSMC_NFC_CFG_FALLING_EDGE		BIT(12)
++#define ATMEL_HSMC_NFC_CFG_RSPARE		BIT(9)
++#define ATMEL_HSMC_NFC_CFG_WSPARE		BIT(8)
++#define ATMEL_HSMC_NFC_CFG_PAGESIZE_MASK	GENMASK(2, 0)
++#define ATMEL_HSMC_NFC_CFG_PAGESIZE(x)		(fls((x) / 512) - 1)
++
++#define ATMEL_HSMC_NFC_CTRL			0x4
++#define ATMEL_HSMC_NFC_CTRL_EN			BIT(0)
++#define ATMEL_HSMC_NFC_CTRL_DIS			BIT(1)
++
++#define ATMEL_HSMC_NFC_SR			0x8
++#define ATMEL_HSMC_NFC_IER			0xc
++#define ATMEL_HSMC_NFC_IDR			0x10
++#define ATMEL_HSMC_NFC_IMR			0x14
++#define ATMEL_HSMC_NFC_SR_ENABLED		BIT(1)
++#define ATMEL_HSMC_NFC_SR_RB_RISE		BIT(4)
++#define ATMEL_HSMC_NFC_SR_RB_FALL		BIT(5)
++#define ATMEL_HSMC_NFC_SR_BUSY			BIT(8)
++#define ATMEL_HSMC_NFC_SR_WR			BIT(11)
++#define ATMEL_HSMC_NFC_SR_CSID			GENMASK(14, 12)
++#define ATMEL_HSMC_NFC_SR_XFRDONE		BIT(16)
++#define ATMEL_HSMC_NFC_SR_CMDDONE		BIT(17)
++#define ATMEL_HSMC_NFC_SR_DTOE			BIT(20)
++#define ATMEL_HSMC_NFC_SR_UNDEF			BIT(21)
++#define ATMEL_HSMC_NFC_SR_AWB			BIT(22)
++#define ATMEL_HSMC_NFC_SR_NFCASE		BIT(23)
++#define ATMEL_HSMC_NFC_SR_ERRORS		(ATMEL_HSMC_NFC_SR_DTOE | \
++						 ATMEL_HSMC_NFC_SR_UNDEF | \
++						 ATMEL_HSMC_NFC_SR_AWB | \
++						 ATMEL_HSMC_NFC_SR_NFCASE)
++#define ATMEL_HSMC_NFC_SR_RBEDGE(x)		BIT((x) + 24)
++
++#define ATMEL_HSMC_NFC_ADDR			0x18
++#define ATMEL_HSMC_NFC_BANK			0x1c
++
++#define ATMEL_NFC_MAX_RB_ID			7
++
++#define ATMEL_NFC_SRAM_SIZE			0x2400
++
++#define ATMEL_NFC_CMD(pos, cmd)			((cmd) << (((pos) * 8) + 2))
++#define ATMEL_NFC_VCMD2				BIT(18)
++#define ATMEL_NFC_ACYCLE(naddrs)		((naddrs) << 19)
++#define ATMEL_NFC_CSID(cs)			((cs) << 22)
++#define ATMEL_NFC_DATAEN			BIT(25)
++#define ATMEL_NFC_NFCWR				BIT(26)
++
++#define ATMEL_NFC_MAX_ADDR_CYCLES		5
++
++#define ATMEL_NAND_ALE_OFFSET			BIT(21)
++#define ATMEL_NAND_CLE_OFFSET			BIT(22)
++
++#define DEFAULT_TIMEOUT_MS			1000
++#define MIN_DMA_LEN				128
++
++enum atmel_nand_rb_type {
++	ATMEL_NAND_NO_RB,
++	ATMEL_NAND_NATIVE_RB,
++	ATMEL_NAND_GPIO_RB,
++};
++
++struct atmel_nand_rb {
++	enum atmel_nand_rb_type type;
++	union {
++		struct gpio_desc *gpio;
++		int id;
++	};
++};
++
++struct atmel_nand_cs {
++	int id;
++	struct atmel_nand_rb rb;
++	struct gpio_desc *csgpio;
++	struct {
++		void __iomem *virt;
++		dma_addr_t dma;
++	} io;
++
++	struct atmel_smc_cs_conf smcconf;
++};
++
++struct atmel_nand {
++	struct list_head node;
++	struct device *dev;
++	struct nand_chip base;
++	struct atmel_nand_cs *activecs;
++	struct atmel_pmecc_user *pmecc;
++	struct gpio_desc *cdgpio;
++	int numcs;
++	struct atmel_nand_cs cs[];
++};
++
++static inline struct atmel_nand *to_atmel_nand(struct nand_chip *chip)
++{
++	return container_of(chip, struct atmel_nand, base);
++}
++
++enum atmel_nfc_data_xfer {
++	ATMEL_NFC_NO_DATA,
++	ATMEL_NFC_READ_DATA,
++	ATMEL_NFC_WRITE_DATA,
++};
++
++struct atmel_nfc_op {
++	u8 cs;
++	u8 ncmds;
++	u8 cmds[2];
++	u8 naddrs;
++	u8 addrs[5];
++	enum atmel_nfc_data_xfer data;
++	u32 wait;
++	u32 errors;
++};
++
++struct atmel_nand_controller;
++struct atmel_nand_controller_caps;
++
++struct atmel_nand_controller_ops {
++	int (*probe)(struct platform_device *pdev,
++		     const struct atmel_nand_controller_caps *caps);
++	int (*remove)(struct atmel_nand_controller *nc);
++	void (*nand_init)(struct atmel_nand_controller *nc,
++			  struct atmel_nand *nand);
++	int (*ecc_init)(struct atmel_nand *nand);
++	int (*setup_data_interface)(struct atmel_nand *nand, int csline,
++				    const struct nand_data_interface *conf);
++};
++
++struct atmel_nand_controller_caps {
++	bool has_dma;
++	bool legacy_of_bindings;
++	u32 ale_offs;
++	u32 cle_offs;
++	const struct atmel_nand_controller_ops *ops;
++};
++
++struct atmel_nand_controller {
++	struct nand_hw_control base;
++	const struct atmel_nand_controller_caps *caps;
++	struct device *dev;
++	struct regmap *smc;
++	struct dma_chan *dmac;
++	struct atmel_pmecc *pmecc;
++	struct list_head chips;
++	struct clk *mck;
++};
++
++static inline struct atmel_nand_controller *
++to_nand_controller(struct nand_hw_control *ctl)
++{
++	return container_of(ctl, struct atmel_nand_controller, base);
++}
++
++struct atmel_smc_nand_controller {
++	struct atmel_nand_controller base;
++	struct regmap *matrix;
++	unsigned int ebi_csa_offs;
++};
++
++static inline struct atmel_smc_nand_controller *
++to_smc_nand_controller(struct nand_hw_control *ctl)
++{
++	return container_of(to_nand_controller(ctl),
++			    struct atmel_smc_nand_controller, base);
++}
++
++struct atmel_hsmc_nand_controller {
++	struct atmel_nand_controller base;
++	struct {
++		struct gen_pool *pool;
++		void __iomem *virt;
++		dma_addr_t dma;
++	} sram;
++	const struct atmel_hsmc_reg_layout *hsmc_layout;
++	struct regmap *io;
++	struct atmel_nfc_op op;
++	struct completion complete;
++	int irq;
++
++	/* Only used when instantiating from legacy DT bindings. */
++	struct clk *clk;
++};
++
++static inline struct atmel_hsmc_nand_controller *
++to_hsmc_nand_controller(struct nand_hw_control *ctl)
++{
++	return container_of(to_nand_controller(ctl),
++			    struct atmel_hsmc_nand_controller, base);
++}
++
++static bool atmel_nfc_op_done(struct atmel_nfc_op *op, u32 status)
++{
++	op->errors |= status & ATMEL_HSMC_NFC_SR_ERRORS;
++	op->wait ^= status & op->wait;
++
++	return !op->wait || op->errors;
++}
++
++static irqreturn_t atmel_nfc_interrupt(int irq, void *data)
++{
++	struct atmel_hsmc_nand_controller *nc = data;
++	u32 sr, rcvd;
++	bool done;
++
++	regmap_read(nc->base.smc, ATMEL_HSMC_NFC_SR, &sr);
++
++	rcvd = sr & (nc->op.wait | ATMEL_HSMC_NFC_SR_ERRORS);
++	done = atmel_nfc_op_done(&nc->op, sr);
++
++	if (rcvd)
++		regmap_write(nc->base.smc, ATMEL_HSMC_NFC_IDR, rcvd);
++
++	if (done)
++		complete(&nc->complete);
++
++	return rcvd ? IRQ_HANDLED : IRQ_NONE;
++}
++
++static int atmel_nfc_wait(struct atmel_hsmc_nand_controller *nc, bool poll,
++			  unsigned int timeout_ms)
++{
++	int ret;
++
++	if (!timeout_ms)
++		timeout_ms = DEFAULT_TIMEOUT_MS;
++
++	if (poll) {
++		u32 status;
++
++		ret = regmap_read_poll_timeout(nc->base.smc,
++					       ATMEL_HSMC_NFC_SR, status,
++					       atmel_nfc_op_done(&nc->op,
++								 status),
++					       0, timeout_ms * 1000);
++	} else {
++		init_completion(&nc->complete);
++		regmap_write(nc->base.smc, ATMEL_HSMC_NFC_IER,
++			     nc->op.wait | ATMEL_HSMC_NFC_SR_ERRORS);
++		ret = wait_for_completion_timeout(&nc->complete,
++						msecs_to_jiffies(timeout_ms));
++		if (!ret)
++			ret = -ETIMEDOUT;
++		else
++			ret = 0;
++
++		regmap_write(nc->base.smc, ATMEL_HSMC_NFC_IDR, 0xffffffff);
++	}
++
++	if (nc->op.errors & ATMEL_HSMC_NFC_SR_DTOE) {
++		dev_err(nc->base.dev, "Waiting NAND R/B Timeout\n");
++		ret = -ETIMEDOUT;
++	}
++
++	if (nc->op.errors & ATMEL_HSMC_NFC_SR_UNDEF) {
++		dev_err(nc->base.dev, "Access to an undefined area\n");
++		ret = -EIO;
++	}
++
++	if (nc->op.errors & ATMEL_HSMC_NFC_SR_AWB) {
++		dev_err(nc->base.dev, "Access while busy\n");
++		ret = -EIO;
++	}
++
++	if (nc->op.errors & ATMEL_HSMC_NFC_SR_NFCASE) {
++		dev_err(nc->base.dev, "Wrong access size\n");
++		ret = -EIO;
++	}
++
++	return ret;
++}
++
++static void atmel_nand_dma_transfer_finished(void *data)
++{
++	struct completion *finished = data;
++
++	complete(finished);
++}
++
++static int atmel_nand_dma_transfer(struct atmel_nand_controller *nc,
++				   void *buf, dma_addr_t dev_dma, size_t len,
++				   enum dma_data_direction dir)
++{
++	DECLARE_COMPLETION_ONSTACK(finished);
++	dma_addr_t src_dma, dst_dma, buf_dma;
++	struct dma_async_tx_descriptor *tx;
++	dma_cookie_t cookie;
++
++	buf_dma = dma_map_single(nc->dev, buf, len, dir);
++	if (dma_mapping_error(nc->dev, dev_dma)) {
++		dev_err(nc->dev,
++			"Failed to prepare a buffer for DMA access\n");
++		goto err;
++	}
++
++	if (dir == DMA_FROM_DEVICE) {
++		src_dma = dev_dma;
++		dst_dma = buf_dma;
++	} else {
++		src_dma = buf_dma;
++		dst_dma = dev_dma;
++	}
++
++	tx = dmaengine_prep_dma_memcpy(nc->dmac, dst_dma, src_dma, len,
++				       DMA_CTRL_ACK | DMA_PREP_INTERRUPT);
++	if (!tx) {
++		dev_err(nc->dev, "Failed to prepare DMA memcpy\n");
++		goto err_unmap;
++	}
++
++	tx->callback = atmel_nand_dma_transfer_finished;
++	tx->callback_param = &finished;
++
++	cookie = dmaengine_submit(tx);
++	if (dma_submit_error(cookie)) {
++		dev_err(nc->dev, "Failed to do DMA tx_submit\n");
++		goto err_unmap;
++	}
++
++	dma_async_issue_pending(nc->dmac);
++	wait_for_completion(&finished);
++
++	return 0;
++
++err_unmap:
++	dma_unmap_single(nc->dev, buf_dma, len, dir);
++
++err:
++	dev_dbg(nc->dev, "Fall back to CPU I/O\n");
++
++	return -EIO;
++}
++
++static u8 atmel_nand_read_byte(struct mtd_info *mtd)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct atmel_nand *nand = to_atmel_nand(chip);
++
++	return ioread8(nand->activecs->io.virt);
++}
++
++static u16 atmel_nand_read_word(struct mtd_info *mtd)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct atmel_nand *nand = to_atmel_nand(chip);
++
++	return ioread16(nand->activecs->io.virt);
++}
++
++static void atmel_nand_write_byte(struct mtd_info *mtd, u8 byte)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct atmel_nand *nand = to_atmel_nand(chip);
++
++	if (chip->options & NAND_BUSWIDTH_16)
++		iowrite16(byte | (byte << 8), nand->activecs->io.virt);
++	else
++		iowrite8(byte, nand->activecs->io.virt);
++}
++
++static void atmel_nand_read_buf(struct mtd_info *mtd, u8 *buf, int len)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct atmel_nand *nand = to_atmel_nand(chip);
++	struct atmel_nand_controller *nc;
++
++	nc = to_nand_controller(chip->controller);
++
++	/*
++	 * If the controller supports DMA, the buffer address is DMA-able and
++	 * len is long enough to make DMA transfers profitable, let's trigger
++	 * a DMA transfer. If it fails, fallback to PIO mode.
++	 */
++	if (nc->dmac && virt_addr_valid(buf) &&
++	    len >= MIN_DMA_LEN &&
++	    !atmel_nand_dma_transfer(nc, buf, nand->activecs->io.dma, len,
++				     DMA_FROM_DEVICE))
++		return;
++
++	if (chip->options & NAND_BUSWIDTH_16)
++		ioread16_rep(nand->activecs->io.virt, buf, len / 2);
++	else
++		ioread8_rep(nand->activecs->io.virt, buf, len);
++}
++
++static void atmel_nand_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct atmel_nand *nand = to_atmel_nand(chip);
++	struct atmel_nand_controller *nc;
++
++	nc = to_nand_controller(chip->controller);
++
++	/*
++	 * If the controller supports DMA, the buffer address is DMA-able and
++	 * len is long enough to make DMA transfers profitable, let's trigger
++	 * a DMA transfer. If it fails, fallback to PIO mode.
++	 */
++	if (nc->dmac && virt_addr_valid(buf) &&
++	    len >= MIN_DMA_LEN &&
++	    !atmel_nand_dma_transfer(nc, (void *)buf, nand->activecs->io.dma,
++				     len, DMA_TO_DEVICE))
++		return;
++
++	if (chip->options & NAND_BUSWIDTH_16)
++		iowrite16_rep(nand->activecs->io.virt, buf, len / 2);
++	else
++		iowrite8_rep(nand->activecs->io.virt, buf, len);
++}
++
++static int atmel_nand_dev_ready(struct mtd_info *mtd)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct atmel_nand *nand = to_atmel_nand(chip);
++
++	return gpiod_get_value(nand->activecs->rb.gpio);
++}
++
++static void atmel_nand_select_chip(struct mtd_info *mtd, int cs)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct atmel_nand *nand = to_atmel_nand(chip);
++
++	if (cs < 0 || cs >= nand->numcs) {
++		nand->activecs = NULL;
++		chip->dev_ready = NULL;
++		return;
++	}
++
++	nand->activecs = &nand->cs[cs];
++
++	if (nand->activecs->rb.type == ATMEL_NAND_GPIO_RB)
++		chip->dev_ready = atmel_nand_dev_ready;
++}
++
++static int atmel_hsmc_nand_dev_ready(struct mtd_info *mtd)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct atmel_nand *nand = to_atmel_nand(chip);
++	struct atmel_hsmc_nand_controller *nc;
++	u32 status;
++
++	nc = to_hsmc_nand_controller(chip->controller);
++
++	regmap_read(nc->base.smc, ATMEL_HSMC_NFC_SR, &status);
++
++	return status & ATMEL_HSMC_NFC_SR_RBEDGE(nand->activecs->rb.id);
++}
++
++static void atmel_hsmc_nand_select_chip(struct mtd_info *mtd, int cs)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct atmel_nand *nand = to_atmel_nand(chip);
++	struct atmel_hsmc_nand_controller *nc;
++
++	nc = to_hsmc_nand_controller(chip->controller);
++
++	atmel_nand_select_chip(mtd, cs);
++
++	if (!nand->activecs) {
++		regmap_write(nc->base.smc, ATMEL_HSMC_NFC_CTRL,
++			     ATMEL_HSMC_NFC_CTRL_DIS);
++		return;
++	}
++
++	if (nand->activecs->rb.type == ATMEL_NAND_NATIVE_RB)
++		chip->dev_ready = atmel_hsmc_nand_dev_ready;
++
++	regmap_update_bits(nc->base.smc, ATMEL_HSMC_NFC_CFG,
++			   ATMEL_HSMC_NFC_CFG_PAGESIZE_MASK |
++			   ATMEL_HSMC_NFC_CFG_SPARESIZE_MASK |
++			   ATMEL_HSMC_NFC_CFG_RSPARE |
++			   ATMEL_HSMC_NFC_CFG_WSPARE,
++			   ATMEL_HSMC_NFC_CFG_PAGESIZE(mtd->writesize) |
++			   ATMEL_HSMC_NFC_CFG_SPARESIZE(mtd->oobsize) |
++			   ATMEL_HSMC_NFC_CFG_RSPARE);
++	regmap_write(nc->base.smc, ATMEL_HSMC_NFC_CTRL,
++		     ATMEL_HSMC_NFC_CTRL_EN);
++}
++
++static int atmel_nfc_exec_op(struct atmel_hsmc_nand_controller *nc, bool poll)
++{
++	u8 *addrs = nc->op.addrs;
++	unsigned int op = 0;
++	u32 addr, val;
++	int i, ret;
++
++	nc->op.wait = ATMEL_HSMC_NFC_SR_CMDDONE;
++
++	for (i = 0; i < nc->op.ncmds; i++)
++		op |= ATMEL_NFC_CMD(i, nc->op.cmds[i]);
++
++	if (nc->op.naddrs == ATMEL_NFC_MAX_ADDR_CYCLES)
++		regmap_write(nc->base.smc, ATMEL_HSMC_NFC_ADDR, *addrs++);
++
++	op |= ATMEL_NFC_CSID(nc->op.cs) |
++	      ATMEL_NFC_ACYCLE(nc->op.naddrs);
++
++	if (nc->op.ncmds > 1)
++		op |= ATMEL_NFC_VCMD2;
++
++	addr = addrs[0] | (addrs[1] << 8) | (addrs[2] << 16) |
++	       (addrs[3] << 24);
++
++	if (nc->op.data != ATMEL_NFC_NO_DATA) {
++		op |= ATMEL_NFC_DATAEN;
++		nc->op.wait |= ATMEL_HSMC_NFC_SR_XFRDONE;
++
++		if (nc->op.data == ATMEL_NFC_WRITE_DATA)
++			op |= ATMEL_NFC_NFCWR;
++	}
++
++	/* Clear all flags. */
++	regmap_read(nc->base.smc, ATMEL_HSMC_NFC_SR, &val);
++
++	/* Send the command. */
++	regmap_write(nc->io, op, addr);
++
++	ret = atmel_nfc_wait(nc, poll, 0);
++	if (ret)
++		dev_err(nc->base.dev,
++			"Failed to send NAND command (err = %d)!",
++			ret);
++
++	/* Reset the op state. */
++	memset(&nc->op, 0, sizeof(nc->op));
++
++	return ret;
++}
++
++static void atmel_hsmc_nand_cmd_ctrl(struct mtd_info *mtd, int dat,
++				     unsigned int ctrl)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct atmel_nand *nand = to_atmel_nand(chip);
++	struct atmel_hsmc_nand_controller *nc;
++
++	nc = to_hsmc_nand_controller(chip->controller);
++
++	if (ctrl & NAND_ALE) {
++		if (nc->op.naddrs == ATMEL_NFC_MAX_ADDR_CYCLES)
++			return;
++
++		nc->op.addrs[nc->op.naddrs++] = dat;
++	} else if (ctrl & NAND_CLE) {
++		if (nc->op.ncmds > 1)
++			return;
++
++		nc->op.cmds[nc->op.ncmds++] = dat;
++	}
++
++	if (dat == NAND_CMD_NONE) {
++		nc->op.cs = nand->activecs->id;
++		atmel_nfc_exec_op(nc, true);
++	}
++}
++
++static void atmel_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
++				unsigned int ctrl)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct atmel_nand *nand = to_atmel_nand(chip);
++	struct atmel_nand_controller *nc;
++
++	nc = to_nand_controller(chip->controller);
++
++	if ((ctrl & NAND_CTRL_CHANGE) && nand->activecs->csgpio) {
++		if (ctrl & NAND_NCE)
++			gpiod_set_value(nand->activecs->csgpio, 0);
++		else
++			gpiod_set_value(nand->activecs->csgpio, 1);
++	}
++
++	if (ctrl & NAND_ALE)
++		writeb(cmd, nand->activecs->io.virt + nc->caps->ale_offs);
++	else if (ctrl & NAND_CLE)
++		writeb(cmd, nand->activecs->io.virt + nc->caps->cle_offs);
++}
++
++static void atmel_nfc_copy_to_sram(struct nand_chip *chip, const u8 *buf,
++				   bool oob_required)
++{
++	struct mtd_info *mtd = nand_to_mtd(chip);
++	struct atmel_hsmc_nand_controller *nc;
++	int ret = -EIO;
++
++	nc = to_hsmc_nand_controller(chip->controller);
++
++	if (nc->base.dmac)
++		ret = atmel_nand_dma_transfer(&nc->base, (void *)buf,
++					      nc->sram.dma, mtd->writesize,
++					      DMA_TO_DEVICE);
++
++	/* Falling back to CPU copy. */
++	if (ret)
++		memcpy_toio(nc->sram.virt, buf, mtd->writesize);
++
++	if (oob_required)
++		memcpy_toio(nc->sram.virt + mtd->writesize, chip->oob_poi,
++			    mtd->oobsize);
++}
++
++static void atmel_nfc_copy_from_sram(struct nand_chip *chip, u8 *buf,
++				     bool oob_required)
++{
++	struct mtd_info *mtd = nand_to_mtd(chip);
++	struct atmel_hsmc_nand_controller *nc;
++	int ret = -EIO;
++
++	nc = to_hsmc_nand_controller(chip->controller);
++
++	if (nc->base.dmac)
++		ret = atmel_nand_dma_transfer(&nc->base, buf, nc->sram.dma,
++					      mtd->writesize, DMA_FROM_DEVICE);
++
++	/* Falling back to CPU copy. */
++	if (ret)
++		memcpy_fromio(buf, nc->sram.virt, mtd->writesize);
++
++	if (oob_required)
++		memcpy_fromio(chip->oob_poi, nc->sram.virt + mtd->writesize,
++			      mtd->oobsize);
++}
++
++static void atmel_nfc_set_op_addr(struct nand_chip *chip, int page, int column)
++{
++	struct mtd_info *mtd = nand_to_mtd(chip);
++	struct atmel_hsmc_nand_controller *nc;
++
++	nc = to_hsmc_nand_controller(chip->controller);
++
++	if (column >= 0) {
++		nc->op.addrs[nc->op.naddrs++] = column;
++
++		/*
++		 * 2 address cycles for the column offset on large page NANDs.
++		 */
++		if (mtd->writesize > 512)
++			nc->op.addrs[nc->op.naddrs++] = column >> 8;
++	}
++
++	if (page >= 0) {
++		nc->op.addrs[nc->op.naddrs++] = page;
++		nc->op.addrs[nc->op.naddrs++] = page >> 8;
++
++		if ((mtd->writesize > 512 && chip->chipsize > SZ_128M) ||
++		    (mtd->writesize <= 512 && chip->chipsize > SZ_32M))
++			nc->op.addrs[nc->op.naddrs++] = page >> 16;
++	}
++}
++
++static int atmel_nand_pmecc_enable(struct nand_chip *chip, int op, bool raw)
++{
++	struct atmel_nand *nand = to_atmel_nand(chip);
++	struct atmel_nand_controller *nc;
++	int ret;
++
++	nc = to_nand_controller(chip->controller);
++
++	if (raw)
++		return 0;
++
++	ret = atmel_pmecc_enable(nand->pmecc, op);
++	if (ret)
++		dev_err(nc->dev,
++			"Failed to enable ECC engine (err = %d)\n", ret);
++
++	return ret;
++}
++
++static void atmel_nand_pmecc_disable(struct nand_chip *chip, bool raw)
++{
++	struct atmel_nand *nand = to_atmel_nand(chip);
++
++	if (!raw)
++		atmel_pmecc_disable(nand->pmecc);
++}
++
++static int atmel_nand_pmecc_generate_eccbytes(struct nand_chip *chip, bool raw)
++{
++	struct atmel_nand *nand = to_atmel_nand(chip);
++	struct mtd_info *mtd = nand_to_mtd(chip);
++	struct atmel_nand_controller *nc;
++	struct mtd_oob_region oobregion;
++	void *eccbuf;
++	int ret, i;
++
++	nc = to_nand_controller(chip->controller);
++
++	if (raw)
++		return 0;
++
++	ret = atmel_pmecc_wait_rdy(nand->pmecc);
++	if (ret) {
++		dev_err(nc->dev,
++			"Failed to transfer NAND page data (err = %d)\n",
++			ret);
++		return ret;
++	}
++
++	mtd_ooblayout_ecc(mtd, 0, &oobregion);
++	eccbuf = chip->oob_poi + oobregion.offset;
++
++	for (i = 0; i < chip->ecc.steps; i++) {
++		atmel_pmecc_get_generated_eccbytes(nand->pmecc, i,
++						   eccbuf);
++		eccbuf += chip->ecc.bytes;
++	}
++
++	return 0;
++}
++
++static int atmel_nand_pmecc_correct_data(struct nand_chip *chip, void *buf,
++					 bool raw)
++{
++	struct atmel_nand *nand = to_atmel_nand(chip);
++	struct mtd_info *mtd = nand_to_mtd(chip);
++	struct atmel_nand_controller *nc;
++	struct mtd_oob_region oobregion;
++	int ret, i, max_bitflips = 0;
++	void *databuf, *eccbuf;
++
++	nc = to_nand_controller(chip->controller);
++
++	if (raw)
++		return 0;
++
++	ret = atmel_pmecc_wait_rdy(nand->pmecc);
++	if (ret) {
++		dev_err(nc->dev,
++			"Failed to read NAND page data (err = %d)\n",
++			ret);
++		return ret;
++	}
++
++	mtd_ooblayout_ecc(mtd, 0, &oobregion);
++	eccbuf = chip->oob_poi + oobregion.offset;
++	databuf = buf;
++
++	for (i = 0; i < chip->ecc.steps; i++) {
++		ret = atmel_pmecc_correct_sector(nand->pmecc, i, databuf,
++						 eccbuf);
++		if (ret < 0 && !atmel_pmecc_correct_erased_chunks(nand->pmecc))
++			ret = nand_check_erased_ecc_chunk(databuf,
++							  chip->ecc.size,
++							  eccbuf,
++							  chip->ecc.bytes,
++							  NULL, 0,
++							  chip->ecc.strength);
++
++		if (ret >= 0)
++			max_bitflips = max(ret, max_bitflips);
++		else
++			mtd->ecc_stats.failed++;
++
++		databuf += chip->ecc.size;
++		eccbuf += chip->ecc.bytes;
++	}
++
++	return max_bitflips;
++}
++
++static int atmel_nand_pmecc_write_pg(struct nand_chip *chip, const u8 *buf,
++				     bool oob_required, int page, bool raw)
++{
++	struct mtd_info *mtd = nand_to_mtd(chip);
++	struct atmel_nand *nand = to_atmel_nand(chip);
++	int ret;
++
++	ret = atmel_nand_pmecc_enable(chip, NAND_ECC_WRITE, raw);
++	if (ret)
++		return ret;
++
++	atmel_nand_write_buf(mtd, buf, mtd->writesize);
++
++	ret = atmel_nand_pmecc_generate_eccbytes(chip, raw);
++	if (ret) {
++		atmel_pmecc_disable(nand->pmecc);
++		return ret;
++	}
++
++	atmel_nand_pmecc_disable(chip, raw);
++
++	atmel_nand_write_buf(mtd, chip->oob_poi, mtd->oobsize);
++
++	return 0;
++}
++
++static int atmel_nand_pmecc_write_page(struct mtd_info *mtd,
++				       struct nand_chip *chip, const u8 *buf,
++				       int oob_required, int page)
++{
++	return atmel_nand_pmecc_write_pg(chip, buf, oob_required, page, false);
++}
++
++static int atmel_nand_pmecc_write_page_raw(struct mtd_info *mtd,
++					   struct nand_chip *chip,
++					   const u8 *buf, int oob_required,
++					   int page)
++{
++	return atmel_nand_pmecc_write_pg(chip, buf, oob_required, page, true);
++}
++
++static int atmel_nand_pmecc_read_pg(struct nand_chip *chip, u8 *buf,
++				    bool oob_required, int page, bool raw)
++{
++	struct mtd_info *mtd = nand_to_mtd(chip);
++	int ret;
++
++	ret = atmel_nand_pmecc_enable(chip, NAND_ECC_READ, raw);
++	if (ret)
++		return ret;
++
++	atmel_nand_read_buf(mtd, buf, mtd->writesize);
++	atmel_nand_read_buf(mtd, chip->oob_poi, mtd->oobsize);
++
++	ret = atmel_nand_pmecc_correct_data(chip, buf, raw);
++
++	atmel_nand_pmecc_disable(chip, raw);
++
++	return ret;
++}
++
++static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,
++				      struct nand_chip *chip, u8 *buf,
++				      int oob_required, int page)
++{
++	return atmel_nand_pmecc_read_pg(chip, buf, oob_required, page, false);
++}
++
++static int atmel_nand_pmecc_read_page_raw(struct mtd_info *mtd,
++					  struct nand_chip *chip, u8 *buf,
++					  int oob_required, int page)
++{
++	return atmel_nand_pmecc_read_pg(chip, buf, oob_required, page, true);
++}
++
++static int atmel_hsmc_nand_pmecc_write_pg(struct nand_chip *chip,
++					  const u8 *buf, bool oob_required,
++					  int page, bool raw)
++{
++	struct mtd_info *mtd = nand_to_mtd(chip);
++	struct atmel_nand *nand = to_atmel_nand(chip);
++	struct atmel_hsmc_nand_controller *nc;
++	int ret, status;
++
++	nc = to_hsmc_nand_controller(chip->controller);
++
++	atmel_nfc_copy_to_sram(chip, buf, false);
++
++	nc->op.cmds[0] = NAND_CMD_SEQIN;
++	nc->op.ncmds = 1;
++	atmel_nfc_set_op_addr(chip, page, 0x0);
++	nc->op.cs = nand->activecs->id;
++	nc->op.data = ATMEL_NFC_WRITE_DATA;
++
++	ret = atmel_nand_pmecc_enable(chip, NAND_ECC_WRITE, raw);
++	if (ret)
++		return ret;
++
++	ret = atmel_nfc_exec_op(nc, false);
++	if (ret) {
++		atmel_nand_pmecc_disable(chip, raw);
++		dev_err(nc->base.dev,
++			"Failed to transfer NAND page data (err = %d)\n",
++			ret);
++		return ret;
++	}
++
++	ret = atmel_nand_pmecc_generate_eccbytes(chip, raw);
++
++	atmel_nand_pmecc_disable(chip, raw);
++
++	if (ret)
++		return ret;
++
++	atmel_nand_write_buf(mtd, chip->oob_poi, mtd->oobsize);
++
++	nc->op.cmds[0] = NAND_CMD_PAGEPROG;
++	nc->op.ncmds = 1;
++	nc->op.cs = nand->activecs->id;
++	ret = atmel_nfc_exec_op(nc, false);
++	if (ret)
++		dev_err(nc->base.dev, "Failed to program NAND page (err = %d)\n",
++			ret);
++
++	status = chip->waitfunc(mtd, chip);
++	if (status & NAND_STATUS_FAIL)
++		return -EIO;
++
++	return ret;
++}
++
++static int atmel_hsmc_nand_pmecc_write_page(struct mtd_info *mtd,
++					    struct nand_chip *chip,
++					    const u8 *buf, int oob_required,
++					    int page)
++{
++	return atmel_hsmc_nand_pmecc_write_pg(chip, buf, oob_required, page,
++					      false);
++}
++
++static int atmel_hsmc_nand_pmecc_write_page_raw(struct mtd_info *mtd,
++						struct nand_chip *chip,
++						const u8 *buf,
++						int oob_required, int page)
++{
++	return atmel_hsmc_nand_pmecc_write_pg(chip, buf, oob_required, page,
++					      true);
++}
++
++static int atmel_hsmc_nand_pmecc_read_pg(struct nand_chip *chip, u8 *buf,
++					 bool oob_required, int page,
++					 bool raw)
++{
++	struct mtd_info *mtd = nand_to_mtd(chip);
++	struct atmel_nand *nand = to_atmel_nand(chip);
++	struct atmel_hsmc_nand_controller *nc;
++	int ret;
++
++	nc = to_hsmc_nand_controller(chip->controller);
++
++	/*
++	 * Optimized read page accessors only work when the NAND R/B pin is
++	 * connected to a native SoC R/B pin. If that's not the case, fallback
++	 * to the non-optimized one.
++	 */
++	if (nand->activecs->rb.type != ATMEL_NAND_NATIVE_RB) {
++		chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
++
++		return atmel_nand_pmecc_read_pg(chip, buf, oob_required, page,
++						raw);
++	}
++
++	nc->op.cmds[nc->op.ncmds++] = NAND_CMD_READ0;
++
++	if (mtd->writesize > 512)
++		nc->op.cmds[nc->op.ncmds++] = NAND_CMD_READSTART;
++
++	atmel_nfc_set_op_addr(chip, page, 0x0);
++	nc->op.cs = nand->activecs->id;
++	nc->op.data = ATMEL_NFC_READ_DATA;
++
++	ret = atmel_nand_pmecc_enable(chip, NAND_ECC_READ, raw);
++	if (ret)
++		return ret;
++
++	ret = atmel_nfc_exec_op(nc, false);
++	if (ret) {
++		atmel_nand_pmecc_disable(chip, raw);
++		dev_err(nc->base.dev,
++			"Failed to load NAND page data (err = %d)\n",
++			ret);
++		return ret;
++	}
++
++	atmel_nfc_copy_from_sram(chip, buf, true);
++
++	ret = atmel_nand_pmecc_correct_data(chip, buf, raw);
++
++	atmel_nand_pmecc_disable(chip, raw);
++
++	return ret;
++}
++
++static int atmel_hsmc_nand_pmecc_read_page(struct mtd_info *mtd,
++					   struct nand_chip *chip, u8 *buf,
++					   int oob_required, int page)
++{
++	return atmel_hsmc_nand_pmecc_read_pg(chip, buf, oob_required, page,
++					     false);
++}
++
++static int atmel_hsmc_nand_pmecc_read_page_raw(struct mtd_info *mtd,
++					       struct nand_chip *chip,
++					       u8 *buf, int oob_required,
++					       int page)
++{
++	return atmel_hsmc_nand_pmecc_read_pg(chip, buf, oob_required, page,
++					     true);
++}
++
++static int atmel_nand_pmecc_init(struct nand_chip *chip)
++{
++	struct mtd_info *mtd = nand_to_mtd(chip);
++	struct atmel_nand *nand = to_atmel_nand(chip);
++	struct atmel_nand_controller *nc;
++	struct atmel_pmecc_user_req req;
++
++	nc = to_nand_controller(chip->controller);
++
++	if (!nc->pmecc) {
++		dev_err(nc->dev, "HW ECC not supported\n");
++		return -ENOTSUPP;
++	}
++
++	if (nc->caps->legacy_of_bindings) {
++		u32 val;
++
++		if (!of_property_read_u32(nc->dev->of_node, "atmel,pmecc-cap",
++					  &val))
++			chip->ecc.strength = val;
++
++		if (!of_property_read_u32(nc->dev->of_node,
++					  "atmel,pmecc-sector-size",
++					  &val))
++			chip->ecc.size = val;
++	}
++
++	if (chip->ecc.options & NAND_ECC_MAXIMIZE)
++		req.ecc.strength = ATMEL_PMECC_MAXIMIZE_ECC_STRENGTH;
++	else if (chip->ecc.strength)
++		req.ecc.strength = chip->ecc.strength;
++	else if (chip->ecc_strength_ds)
++		req.ecc.strength = chip->ecc_strength_ds;
++	else
++		req.ecc.strength = ATMEL_PMECC_MAXIMIZE_ECC_STRENGTH;
++
++	if (chip->ecc.size)
++		req.ecc.sectorsize = chip->ecc.size;
++	else if (chip->ecc_step_ds)
++		req.ecc.sectorsize = chip->ecc_step_ds;
++	else
++		req.ecc.sectorsize = ATMEL_PMECC_SECTOR_SIZE_AUTO;
++
++	req.pagesize = mtd->writesize;
++	req.oobsize = mtd->oobsize;
++
++	if (mtd->writesize <= 512) {
++		req.ecc.bytes = 4;
++		req.ecc.ooboffset = 0;
++	} else {
++		req.ecc.bytes = mtd->oobsize - 2;
++		req.ecc.ooboffset = ATMEL_PMECC_OOBOFFSET_AUTO;
++	}
++
++	nand->pmecc = atmel_pmecc_create_user(nc->pmecc, &req);
++	if (IS_ERR(nand->pmecc))
++		return PTR_ERR(nand->pmecc);
++
++	chip->ecc.algo = NAND_ECC_BCH;
++	chip->ecc.size = req.ecc.sectorsize;
++	chip->ecc.bytes = req.ecc.bytes / req.ecc.nsectors;
++	chip->ecc.strength = req.ecc.strength;
++
++	chip->options |= NAND_NO_SUBPAGE_WRITE;
++
++	mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
++
++	return 0;
++}
++
++static int atmel_nand_ecc_init(struct atmel_nand *nand)
++{
++	struct nand_chip *chip = &nand->base;
++	struct atmel_nand_controller *nc;
++	int ret;
++
++	nc = to_nand_controller(chip->controller);
++
++	switch (chip->ecc.mode) {
++	case NAND_ECC_NONE:
++	case NAND_ECC_SOFT:
++		/*
++		 * Nothing to do, the core will initialize everything for us.
++		 */
++		break;
++
++	case NAND_ECC_HW:
++		ret = atmel_nand_pmecc_init(chip);
++		if (ret)
++			return ret;
++
++		chip->ecc.read_page = atmel_nand_pmecc_read_page;
++		chip->ecc.write_page = atmel_nand_pmecc_write_page;
++		chip->ecc.read_page_raw = atmel_nand_pmecc_read_page_raw;
++		chip->ecc.write_page_raw = atmel_nand_pmecc_write_page_raw;
++		break;
++
++	default:
++		/* Other modes are not supported. */
++		dev_err(nc->dev, "Unsupported ECC mode: %d\n",
++			chip->ecc.mode);
++		return -ENOTSUPP;
++	}
++
++	return 0;
++}
++
++static int atmel_hsmc_nand_ecc_init(struct atmel_nand *nand)
++{
++	struct nand_chip *chip = &nand->base;
++	int ret;
++
++	ret = atmel_nand_ecc_init(nand);
++	if (ret)
++		return ret;
++
++	if (chip->ecc.mode != NAND_ECC_HW)
++		return 0;
++
++	/* Adjust the ECC operations for the HSMC IP. */
++	chip->ecc.read_page = atmel_hsmc_nand_pmecc_read_page;
++	chip->ecc.write_page = atmel_hsmc_nand_pmecc_write_page;
++	chip->ecc.read_page_raw = atmel_hsmc_nand_pmecc_read_page_raw;
++	chip->ecc.write_page_raw = atmel_hsmc_nand_pmecc_write_page_raw;
++	chip->ecc.options |= NAND_ECC_CUSTOM_PAGE_ACCESS;
++
++	return 0;
++}
++
++static int atmel_smc_nand_prepare_smcconf(struct atmel_nand *nand,
++					const struct nand_data_interface *conf,
++					struct atmel_smc_cs_conf *smcconf)
++{
++	u32 ncycles, totalcycles, timeps, mckperiodps;
++	struct atmel_nand_controller *nc;
++	int ret;
++
++	nc = to_nand_controller(nand->base.controller);
++
++	/* DDR interface not supported. */
++	if (conf->type != NAND_SDR_IFACE)
++		return -ENOTSUPP;
++
++	/*
++	 * tRC < 30ns implies EDO mode. This controller does not support this
++	 * mode.
++	 */
++	if (conf->timings.sdr.tRC_min < 30000)
++		return -ENOTSUPP;
++
++	atmel_smc_cs_conf_init(smcconf);
++
++	mckperiodps = NSEC_PER_SEC / clk_get_rate(nc->mck);
++	mckperiodps *= 1000;
++
++	/*
++	 * Set write pulse timing. This one is easy to extract:
++	 *
++	 * NWE_PULSE = tWP
++	 */
++	ncycles = DIV_ROUND_UP(conf->timings.sdr.tWP_min, mckperiodps);
++	totalcycles = ncycles;
++	ret = atmel_smc_cs_conf_set_pulse(smcconf, ATMEL_SMC_NWE_SHIFT,
++					  ncycles);
++	if (ret)
++		return ret;
++
++	/*
++	 * The write setup timing depends on the operation done on the NAND.
++	 * All operations goes through the same data bus, but the operation
++	 * type depends on the address we are writing to (ALE/CLE address
++	 * lines).
++	 * Since we have no way to differentiate the different operations at
++	 * the SMC level, we must consider the worst case (the biggest setup
++	 * time among all operation types):
++	 *
++	 * NWE_SETUP = max(tCLS, tCS, tALS, tDS) - NWE_PULSE
++	 */
++	timeps = max3(conf->timings.sdr.tCLS_min, conf->timings.sdr.tCS_min,
++		      conf->timings.sdr.tALS_min);
++	timeps = max(timeps, conf->timings.sdr.tDS_min);
++	ncycles = DIV_ROUND_UP(timeps, mckperiodps);
++	ncycles = ncycles > totalcycles ? ncycles - totalcycles : 0;
++	totalcycles += ncycles;
++	ret = atmel_smc_cs_conf_set_setup(smcconf, ATMEL_SMC_NWE_SHIFT,
++					  ncycles);
++	if (ret)
++		return ret;
++
++	/*
++	 * As for the write setup timing, the write hold timing depends on the
++	 * operation done on the NAND:
++	 *
++	 * NWE_HOLD = max(tCLH, tCH, tALH, tDH, tWH)
++	 */
++	timeps = max3(conf->timings.sdr.tCLH_min, conf->timings.sdr.tCH_min,
++		      conf->timings.sdr.tALH_min);
++	timeps = max3(timeps, conf->timings.sdr.tDH_min,
++		      conf->timings.sdr.tWH_min);
++	ncycles = DIV_ROUND_UP(timeps, mckperiodps);
++	totalcycles += ncycles;
++
++	/*
++	 * The write cycle timing is directly matching tWC, but is also
++	 * dependent on the other timings on the setup and hold timings we
++	 * calculated earlier, which gives:
++	 *
++	 * NWE_CYCLE = max(tWC, NWE_SETUP + NWE_PULSE + NWE_HOLD)
++	 */
++	ncycles = DIV_ROUND_UP(conf->timings.sdr.tWC_min, mckperiodps);
++	ncycles = max(totalcycles, ncycles);
++	ret = atmel_smc_cs_conf_set_cycle(smcconf, ATMEL_SMC_NWE_SHIFT,
++					  ncycles);
++	if (ret)
++		return ret;
++
++	/*
++	 * We don't want the CS line to be toggled between each byte/word
++	 * transfer to the NAND. The only way to guarantee that is to have the
++	 * NCS_{WR,RD}_{SETUP,HOLD} timings set to 0, which in turn means:
++	 *
++	 * NCS_WR_PULSE = NWE_CYCLE
++	 */
++	ret = atmel_smc_cs_conf_set_pulse(smcconf, ATMEL_SMC_NCS_WR_SHIFT,
++					  ncycles);
++	if (ret)
++		return ret;
++
++	/*
++	 * As for the write setup timing, the read hold timing depends on the
++	 * operation done on the NAND:
++	 *
++	 * NRD_HOLD = max(tREH, tRHOH)
++	 */
++	timeps = max(conf->timings.sdr.tREH_min, conf->timings.sdr.tRHOH_min);
++	ncycles = DIV_ROUND_UP(timeps, mckperiodps);
++	totalcycles = ncycles;
++
++	/*
++	 * TDF = tRHZ - NRD_HOLD
++	 */
++	ncycles = DIV_ROUND_UP(conf->timings.sdr.tRHZ_max, mckperiodps);
++	ncycles -= totalcycles;
++
++	/*
++	 * In ONFI 4.0 specs, tRHZ has been increased to support EDO NANDs and
++	 * we might end up with a config that does not fit in the TDF field.
++	 * Just take the max value in this case and hope that the NAND is more
++	 * tolerant than advertised.
++	 */
++	if (ncycles > ATMEL_SMC_MODE_TDF_MAX)
++		ncycles = ATMEL_SMC_MODE_TDF_MAX;
++	else if (ncycles < ATMEL_SMC_MODE_TDF_MIN)
++		ncycles = ATMEL_SMC_MODE_TDF_MIN;
++
++	smcconf->mode |= ATMEL_SMC_MODE_TDF(ncycles) |
++			 ATMEL_SMC_MODE_TDFMODE_OPTIMIZED;
++
++	/*
++	 * Read pulse timing directly matches tRP:
++	 *
++	 * NRD_PULSE = tRP
++	 */
++	ncycles = DIV_ROUND_UP(conf->timings.sdr.tRP_min, mckperiodps);
++	totalcycles += ncycles;
++	ret = atmel_smc_cs_conf_set_pulse(smcconf, ATMEL_SMC_NRD_SHIFT,
++					  ncycles);
++	if (ret)
++		return ret;
++
++	/*
++	 * The write cycle timing is directly matching tWC, but is also
++	 * dependent on the setup and hold timings we calculated earlier,
++	 * which gives:
++	 *
++	 * NRD_CYCLE = max(tRC, NRD_PULSE + NRD_HOLD)
++	 *
++	 * NRD_SETUP is always 0.
++	 */
++	ncycles = DIV_ROUND_UP(conf->timings.sdr.tRC_min, mckperiodps);
++	ncycles = max(totalcycles, ncycles);
++	ret = atmel_smc_cs_conf_set_cycle(smcconf, ATMEL_SMC_NRD_SHIFT,
++					  ncycles);
++	if (ret)
++		return ret;
++
++	/*
++	 * We don't want the CS line to be toggled between each byte/word
++	 * transfer from the NAND. The only way to guarantee that is to have
++	 * the NCS_{WR,RD}_{SETUP,HOLD} timings set to 0, which in turn means:
++	 *
++	 * NCS_RD_PULSE = NRD_CYCLE
++	 */
++	ret = atmel_smc_cs_conf_set_pulse(smcconf, ATMEL_SMC_NCS_RD_SHIFT,
++					  ncycles);
++	if (ret)
++		return ret;
++
++	/* Txxx timings are directly matching tXXX ones. */
++	ncycles = DIV_ROUND_UP(conf->timings.sdr.tCLR_min, mckperiodps);
++	ret = atmel_smc_cs_conf_set_timing(smcconf,
++					   ATMEL_HSMC_TIMINGS_TCLR_SHIFT,
++					   ncycles);
++	if (ret)
++		return ret;
++
++	ncycles = DIV_ROUND_UP(conf->timings.sdr.tADL_min, mckperiodps);
++	ret = atmel_smc_cs_conf_set_timing(smcconf,
++					   ATMEL_HSMC_TIMINGS_TADL_SHIFT,
++					   ncycles);
++	/*
++	 * Version 4 of the ONFI spec mandates that tADL be at least 400
++	 * nanoseconds, but, depending on the master clock rate, 400 ns may not
++	 * fit in the tADL field of the SMC reg. We need to relax the check and
++	 * accept the -ERANGE return code.
++	 *
++	 * Note that previous versions of the ONFI spec had a lower tADL_min
++	 * (100 or 200 ns). It's not clear why this timing constraint got
++	 * increased but it seems most NANDs are fine with values lower than
++	 * 400ns, so we should be safe.
++	 */
++	if (ret && ret != -ERANGE)
++		return ret;
++
++	ncycles = DIV_ROUND_UP(conf->timings.sdr.tAR_min, mckperiodps);
++	ret = atmel_smc_cs_conf_set_timing(smcconf,
++					   ATMEL_HSMC_TIMINGS_TAR_SHIFT,
++					   ncycles);
++	if (ret)
++		return ret;
++
++	ncycles = DIV_ROUND_UP(conf->timings.sdr.tRR_min, mckperiodps);
++	ret = atmel_smc_cs_conf_set_timing(smcconf,
++					   ATMEL_HSMC_TIMINGS_TRR_SHIFT,
++					   ncycles);
++	if (ret)
++		return ret;
++
++	ncycles = DIV_ROUND_UP(conf->timings.sdr.tWB_max, mckperiodps);
++	ret = atmel_smc_cs_conf_set_timing(smcconf,
++					   ATMEL_HSMC_TIMINGS_TWB_SHIFT,
++					   ncycles);
++	if (ret)
++		return ret;
++
++	/* Attach the CS line to the NFC logic. */
++	smcconf->timings |= ATMEL_HSMC_TIMINGS_NFSEL;
++
++	/* Set the appropriate data bus width. */
++	if (nand->base.options & NAND_BUSWIDTH_16)
++		smcconf->mode |= ATMEL_SMC_MODE_DBW_16;
++
++	/* Operate in NRD/NWE READ/WRITEMODE. */
++	smcconf->mode |= ATMEL_SMC_MODE_READMODE_NRD |
++			 ATMEL_SMC_MODE_WRITEMODE_NWE;
++
++	return 0;
++}
++
++static int atmel_smc_nand_setup_data_interface(struct atmel_nand *nand,
++					int csline,
++					const struct nand_data_interface *conf)
++{
++	struct atmel_nand_controller *nc;
++	struct atmel_smc_cs_conf smcconf;
++	struct atmel_nand_cs *cs;
++	int ret;
++
++	nc = to_nand_controller(nand->base.controller);
++
++	ret = atmel_smc_nand_prepare_smcconf(nand, conf, &smcconf);
++	if (ret)
++		return ret;
++
++	if (csline == NAND_DATA_IFACE_CHECK_ONLY)
++		return 0;
++
++	cs = &nand->cs[csline];
++	cs->smcconf = smcconf;
++	atmel_smc_cs_conf_apply(nc->smc, cs->id, &cs->smcconf);
++
++	return 0;
++}
++
++static int atmel_hsmc_nand_setup_data_interface(struct atmel_nand *nand,
++					int csline,
++					const struct nand_data_interface *conf)
++{
++	struct atmel_hsmc_nand_controller *nc;
++	struct atmel_smc_cs_conf smcconf;
++	struct atmel_nand_cs *cs;
++	int ret;
++
++	nc = to_hsmc_nand_controller(nand->base.controller);
++
++	ret = atmel_smc_nand_prepare_smcconf(nand, conf, &smcconf);
++	if (ret)
++		return ret;
++
++	if (csline == NAND_DATA_IFACE_CHECK_ONLY)
++		return 0;
++
++	cs = &nand->cs[csline];
++	cs->smcconf = smcconf;
++
++	if (cs->rb.type == ATMEL_NAND_NATIVE_RB)
++		cs->smcconf.timings |= ATMEL_HSMC_TIMINGS_RBNSEL(cs->rb.id);
++
++	atmel_hsmc_cs_conf_apply(nc->base.smc, nc->hsmc_layout, cs->id,
++				 &cs->smcconf);
++
++	return 0;
++}
++
++static int atmel_nand_setup_data_interface(struct mtd_info *mtd, int csline,
++					const struct nand_data_interface *conf)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct atmel_nand *nand = to_atmel_nand(chip);
++	struct atmel_nand_controller *nc;
++
++	nc = to_nand_controller(nand->base.controller);
++
++	if (csline >= nand->numcs ||
++	    (csline < 0 && csline != NAND_DATA_IFACE_CHECK_ONLY))
++		return -EINVAL;
++
++	return nc->caps->ops->setup_data_interface(nand, csline, conf);
++}
++
++static void atmel_nand_init(struct atmel_nand_controller *nc,
++			    struct atmel_nand *nand)
++{
++	struct nand_chip *chip = &nand->base;
++	struct mtd_info *mtd = nand_to_mtd(chip);
++
++	mtd->dev.parent = nc->dev;
++	nand->base.controller = &nc->base;
++
++	chip->cmd_ctrl = atmel_nand_cmd_ctrl;
++	chip->read_byte = atmel_nand_read_byte;
++	chip->read_word = atmel_nand_read_word;
++	chip->write_byte = atmel_nand_write_byte;
++	chip->read_buf = atmel_nand_read_buf;
++	chip->write_buf = atmel_nand_write_buf;
++	chip->select_chip = atmel_nand_select_chip;
++
++	if (nc->mck && nc->caps->ops->setup_data_interface)
++		chip->setup_data_interface = atmel_nand_setup_data_interface;
++
++	/* Some NANDs require a longer delay than the default one (20us). */
++	chip->chip_delay = 40;
++
++	/*
++	 * Use a bounce buffer when the buffer passed by the MTD user is not
++	 * suitable for DMA.
++	 */
++	if (nc->dmac)
++		chip->options |= NAND_USE_BOUNCE_BUFFER;
++
++	/* Default to HW ECC if pmecc is available. */
++	if (nc->pmecc)
++		chip->ecc.mode = NAND_ECC_HW;
++}
++
++static void atmel_smc_nand_init(struct atmel_nand_controller *nc,
++				struct atmel_nand *nand)
++{
++	struct nand_chip *chip = &nand->base;
++	struct atmel_smc_nand_controller *smc_nc;
++	int i;
++
++	atmel_nand_init(nc, nand);
++
++	smc_nc = to_smc_nand_controller(chip->controller);
++	if (!smc_nc->matrix)
++		return;
++
++	/* Attach the CS to the NAND Flash logic. */
++	for (i = 0; i < nand->numcs; i++)
++		regmap_update_bits(smc_nc->matrix, smc_nc->ebi_csa_offs,
++				   BIT(nand->cs[i].id), BIT(nand->cs[i].id));
++}
++
++static void atmel_hsmc_nand_init(struct atmel_nand_controller *nc,
++				 struct atmel_nand *nand)
++{
++	struct nand_chip *chip = &nand->base;
++
++	atmel_nand_init(nc, nand);
++
++	/* Overload some methods for the HSMC controller. */
++	chip->cmd_ctrl = atmel_hsmc_nand_cmd_ctrl;
++	chip->select_chip = atmel_hsmc_nand_select_chip;
++}
++
++static int atmel_nand_detect(struct atmel_nand *nand)
++{
++	struct nand_chip *chip = &nand->base;
++	struct mtd_info *mtd = nand_to_mtd(chip);
++	struct atmel_nand_controller *nc;
++	int ret;
++
++	nc = to_nand_controller(chip->controller);
++
++	ret = nand_scan_ident(mtd, nand->numcs, NULL);
++	if (ret)
++		dev_err(nc->dev, "nand_scan_ident() failed: %d\n", ret);
++
++	return ret;
++}
++
++static int atmel_nand_unregister(struct atmel_nand *nand)
++{
++	struct nand_chip *chip = &nand->base;
++	struct mtd_info *mtd = nand_to_mtd(chip);
++	int ret;
++
++	ret = mtd_device_unregister(mtd);
++	if (ret)
++		return ret;
++
++	nand_cleanup(chip);
++	list_del(&nand->node);
++
++	return 0;
++}
++
++static int atmel_nand_register(struct atmel_nand *nand)
++{
++	struct nand_chip *chip = &nand->base;
++	struct mtd_info *mtd = nand_to_mtd(chip);
++	struct atmel_nand_controller *nc;
++	int ret;
++
++	nc = to_nand_controller(chip->controller);
++
++	if (nc->caps->legacy_of_bindings || !nc->dev->of_node) {
++		/*
++		 * We keep the MTD name unchanged to avoid breaking platforms
++		 * where the MTD cmdline parser is used and the bootloader
++		 * has not been updated to use the new naming scheme.
++		 */
++		mtd->name = "atmel_nand";
++	} else if (!mtd->name) {
++		/*
++		 * If the new bindings are used and the bootloader has not been
++		 * updated to pass a new mtdparts parameter on the cmdline, you
++		 * should define the following property in your nand node:
++		 *
++		 *	label = "atmel_nand";
++		 *
++		 * This way, mtd->name will be set by the core when
++		 * nand_set_flash_node() is called.
++		 */
++		mtd->name = devm_kasprintf(nc->dev, GFP_KERNEL,
++					   "%s:nand.%d", dev_name(nc->dev),
++					   nand->cs[0].id);
++		if (!mtd->name) {
++			dev_err(nc->dev, "Failed to allocate mtd->name\n");
++			return -ENOMEM;
++		}
++	}
++
++	ret = nand_scan_tail(mtd);
++	if (ret) {
++		dev_err(nc->dev, "nand_scan_tail() failed: %d\n", ret);
++		return ret;
++	}
++
++	ret = mtd_device_register(mtd, NULL, 0);
++	if (ret) {
++		dev_err(nc->dev, "Failed to register mtd device: %d\n", ret);
++		nand_cleanup(chip);
++		return ret;
++	}
++
++	list_add_tail(&nand->node, &nc->chips);
++
++	return 0;
++}
++
++static struct atmel_nand *atmel_nand_create(struct atmel_nand_controller *nc,
++					    struct device_node *np,
++					    int reg_cells)
++{
++	struct atmel_nand *nand;
++	struct gpio_desc *gpio;
++	int numcs, ret, i;
++
++	numcs = of_property_count_elems_of_size(np, "reg",
++						reg_cells * sizeof(u32));
++	if (numcs < 1) {
++		dev_err(nc->dev, "Missing or invalid reg property\n");
++		return ERR_PTR(-EINVAL);
++	}
++
++	nand = devm_kzalloc(nc->dev,
++			    sizeof(*nand) + (numcs * sizeof(*nand->cs)),
++			    GFP_KERNEL);
++	if (!nand) {
++		dev_err(nc->dev, "Failed to allocate NAND object\n");
++		return ERR_PTR(-ENOMEM);
++	}
++
++	nand->numcs = numcs;
++
++	gpio = devm_fwnode_get_index_gpiod_from_child(nc->dev, "det", 0,
++						      &np->fwnode, GPIOD_IN,
++						      "nand-det");
++	if (IS_ERR(gpio) && PTR_ERR(gpio) != -ENOENT) {
++		dev_err(nc->dev,
++			"Failed to get detect gpio (err = %ld)\n",
++			PTR_ERR(gpio));
++		return ERR_CAST(gpio);
++	}
++
++	if (!IS_ERR(gpio))
++		nand->cdgpio = gpio;
++
++	for (i = 0; i < numcs; i++) {
++		struct resource res;
++		u32 val;
++
++		ret = of_address_to_resource(np, 0, &res);
++		if (ret) {
++			dev_err(nc->dev, "Invalid reg property (err = %d)\n",
++				ret);
++			return ERR_PTR(ret);
++		}
++
++		ret = of_property_read_u32_index(np, "reg", i * reg_cells,
++						 &val);
++		if (ret) {
++			dev_err(nc->dev, "Invalid reg property (err = %d)\n",
++				ret);
++			return ERR_PTR(ret);
++		}
++
++		nand->cs[i].id = val;
++
++		nand->cs[i].io.dma = res.start;
++		nand->cs[i].io.virt = devm_ioremap_resource(nc->dev, &res);
++		if (IS_ERR(nand->cs[i].io.virt))
++			return ERR_CAST(nand->cs[i].io.virt);
++
++		if (!of_property_read_u32(np, "atmel,rb", &val)) {
++			if (val > ATMEL_NFC_MAX_RB_ID)
++				return ERR_PTR(-EINVAL);
++
++			nand->cs[i].rb.type = ATMEL_NAND_NATIVE_RB;
++			nand->cs[i].rb.id = val;
++		} else {
++			gpio = devm_fwnode_get_index_gpiod_from_child(nc->dev,
++							"rb", i, &np->fwnode,
++							GPIOD_IN, "nand-rb");
++			if (IS_ERR(gpio) && PTR_ERR(gpio) != -ENOENT) {
++				dev_err(nc->dev,
++					"Failed to get R/B gpio (err = %ld)\n",
++					PTR_ERR(gpio));
++				return ERR_CAST(gpio);
++			}
++
++			if (!IS_ERR(gpio)) {
++				nand->cs[i].rb.type = ATMEL_NAND_GPIO_RB;
++				nand->cs[i].rb.gpio = gpio;
++			}
++		}
++
++		gpio = devm_fwnode_get_index_gpiod_from_child(nc->dev, "cs",
++							      i, &np->fwnode,
++							      GPIOD_OUT_HIGH,
++							      "nand-cs");
++		if (IS_ERR(gpio) && PTR_ERR(gpio) != -ENOENT) {
++			dev_err(nc->dev,
++				"Failed to get CS gpio (err = %ld)\n",
++				PTR_ERR(gpio));
++			return ERR_CAST(gpio);
++		}
++
++		if (!IS_ERR(gpio))
++			nand->cs[i].csgpio = gpio;
++	}
++
++	nand_set_flash_node(&nand->base, np);
++
++	return nand;
++}
++
++static int
++atmel_nand_controller_add_nand(struct atmel_nand_controller *nc,
++			       struct atmel_nand *nand)
++{
++	int ret;
++
++	/* No card inserted, skip this NAND. */
++	if (nand->cdgpio && gpiod_get_value(nand->cdgpio)) {
++		dev_info(nc->dev, "No SmartMedia card inserted.\n");
++		return 0;
++	}
++
++	nc->caps->ops->nand_init(nc, nand);
++
++	ret = atmel_nand_detect(nand);
++	if (ret)
++		return ret;
++
++	ret = nc->caps->ops->ecc_init(nand);
++	if (ret)
++		return ret;
++
++	return atmel_nand_register(nand);
++}
++
++static int
++atmel_nand_controller_remove_nands(struct atmel_nand_controller *nc)
++{
++	struct atmel_nand *nand, *tmp;
++	int ret;
++
++	list_for_each_entry_safe(nand, tmp, &nc->chips, node) {
++		ret = atmel_nand_unregister(nand);
++		if (ret)
++			return ret;
++	}
++
++	return 0;
++}
++
++static int
++atmel_nand_controller_legacy_add_nands(struct atmel_nand_controller *nc)
++{
++	struct device *dev = nc->dev;
++	struct platform_device *pdev = to_platform_device(dev);
++	struct atmel_nand *nand;
++	struct gpio_desc *gpio;
++	struct resource *res;
++
++	/*
++	 * Legacy bindings only allow connecting a single NAND with a unique CS
++	 * line to the controller.
++	 */
++	nand = devm_kzalloc(nc->dev, sizeof(*nand) + sizeof(*nand->cs),
++			    GFP_KERNEL);
++	if (!nand)
++		return -ENOMEM;
++
++	nand->numcs = 1;
++
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	nand->cs[0].io.virt = devm_ioremap_resource(dev, res);
++	if (IS_ERR(nand->cs[0].io.virt))
++		return PTR_ERR(nand->cs[0].io.virt);
++
++	nand->cs[0].io.dma = res->start;
++
++	/*
++	 * The old driver was hardcoding the CS id to 3 for all sama5
++	 * controllers. Since this id is only meaningful for the sama5
++	 * controller we can safely assign this id to 3 no matter the
++	 * controller.
++	 * If one wants to connect a NAND to a different CS line, he will
++	 * have to use the new bindings.
++	 */
++	nand->cs[0].id = 3;
++
++	/* R/B GPIO. */
++	gpio = devm_gpiod_get_index_optional(dev, NULL, 0,  GPIOD_IN);
++	if (IS_ERR(gpio)) {
++		dev_err(dev, "Failed to get R/B gpio (err = %ld)\n",
++			PTR_ERR(gpio));
++		return PTR_ERR(gpio);
++	}
++
++	if (gpio) {
++		nand->cs[0].rb.type = ATMEL_NAND_GPIO_RB;
++		nand->cs[0].rb.gpio = gpio;
++	}
++
++	/* CS GPIO. */
++	gpio = devm_gpiod_get_index_optional(dev, NULL, 1, GPIOD_OUT_HIGH);
++	if (IS_ERR(gpio)) {
++		dev_err(dev, "Failed to get CS gpio (err = %ld)\n",
++			PTR_ERR(gpio));
++		return PTR_ERR(gpio);
++	}
++
++	nand->cs[0].csgpio = gpio;
++
++	/* Card detect GPIO. */
++	gpio = devm_gpiod_get_index_optional(nc->dev, NULL, 2, GPIOD_IN);
++	if (IS_ERR(gpio)) {
++		dev_err(dev,
++			"Failed to get detect gpio (err = %ld)\n",
++			PTR_ERR(gpio));
++		return PTR_ERR(gpio);
++	}
++
++	nand->cdgpio = gpio;
++
++	nand_set_flash_node(&nand->base, nc->dev->of_node);
++
++	return atmel_nand_controller_add_nand(nc, nand);
++}
++
++static int atmel_nand_controller_add_nands(struct atmel_nand_controller *nc)
++{
++	struct device_node *np, *nand_np;
++	struct device *dev = nc->dev;
++	int ret, reg_cells;
++	u32 val;
++
++	/* We do not retrieve the SMC syscon when parsing old DTs. */
++	if (nc->caps->legacy_of_bindings)
++		return atmel_nand_controller_legacy_add_nands(nc);
++
++	np = dev->of_node;
++
++	ret = of_property_read_u32(np, "#address-cells", &val);
++	if (ret) {
++		dev_err(dev, "missing #address-cells property\n");
++		return ret;
++	}
++
++	reg_cells = val;
++
++	ret = of_property_read_u32(np, "#size-cells", &val);
++	if (ret) {
++		dev_err(dev, "missing #address-cells property\n");
++		return ret;
++	}
++
++	reg_cells += val;
++
++	for_each_child_of_node(np, nand_np) {
++		struct atmel_nand *nand;
++
++		nand = atmel_nand_create(nc, nand_np, reg_cells);
++		if (IS_ERR(nand)) {
++			ret = PTR_ERR(nand);
++			goto err;
++		}
++
++		ret = atmel_nand_controller_add_nand(nc, nand);
++		if (ret)
++			goto err;
++	}
++
++	return 0;
++
++err:
++	atmel_nand_controller_remove_nands(nc);
++
++	return ret;
++}
++
++static void atmel_nand_controller_cleanup(struct atmel_nand_controller *nc)
++{
++	if (nc->dmac)
++		dma_release_channel(nc->dmac);
++
++	clk_put(nc->mck);
++}
++
++static const struct of_device_id atmel_matrix_of_ids[] = {
++	{
++		.compatible = "atmel,at91sam9260-matrix",
++		.data = (void *)AT91SAM9260_MATRIX_EBICSA,
++	},
++	{
++		.compatible = "atmel,at91sam9261-matrix",
++		.data = (void *)AT91SAM9261_MATRIX_EBICSA,
++	},
++	{
++		.compatible = "atmel,at91sam9263-matrix",
++		.data = (void *)AT91SAM9263_MATRIX_EBI0CSA,
++	},
++	{
++		.compatible = "atmel,at91sam9rl-matrix",
++		.data = (void *)AT91SAM9RL_MATRIX_EBICSA,
++	},
++	{
++		.compatible = "atmel,at91sam9g45-matrix",
++		.data = (void *)AT91SAM9G45_MATRIX_EBICSA,
++	},
++	{
++		.compatible = "atmel,at91sam9n12-matrix",
++		.data = (void *)AT91SAM9N12_MATRIX_EBICSA,
++	},
++	{
++		.compatible = "atmel,at91sam9x5-matrix",
++		.data = (void *)AT91SAM9X5_MATRIX_EBICSA,
++	},
++	{ /* sentinel */ },
++};
++
++static int atmel_nand_controller_init(struct atmel_nand_controller *nc,
++				struct platform_device *pdev,
++				const struct atmel_nand_controller_caps *caps)
++{
++	struct device *dev = &pdev->dev;
++	struct device_node *np = dev->of_node;
++	int ret;
++
++	nand_hw_control_init(&nc->base);
++	INIT_LIST_HEAD(&nc->chips);
++	nc->dev = dev;
++	nc->caps = caps;
++
++	platform_set_drvdata(pdev, nc);
++
++	nc->pmecc = devm_atmel_pmecc_get(dev);
++	if (IS_ERR(nc->pmecc)) {
++		ret = PTR_ERR(nc->pmecc);
++		if (ret != -EPROBE_DEFER)
++			dev_err(dev, "Could not get PMECC object (err = %d)\n",
++				ret);
++		return ret;
++	}
++
++	if (nc->caps->has_dma) {
++		dma_cap_mask_t mask;
++
++		dma_cap_zero(mask);
++		dma_cap_set(DMA_MEMCPY, mask);
++
++		nc->dmac = dma_request_channel(mask, NULL, NULL);
++		if (!nc->dmac)
++			dev_err(nc->dev, "Failed to request DMA channel\n");
++	}
++
++	/* We do not retrieve the SMC syscon when parsing old DTs. */
++	if (nc->caps->legacy_of_bindings)
++		return 0;
++
++	nc->mck = of_clk_get(dev->parent->of_node, 0);
++	if (IS_ERR(nc->mck)) {
++		dev_err(dev, "Failed to retrieve MCK clk\n");
++		return PTR_ERR(nc->mck);
++	}
++
++	np = of_parse_phandle(dev->parent->of_node, "atmel,smc", 0);
++	if (!np) {
++		dev_err(dev, "Missing or invalid atmel,smc property\n");
++		return -EINVAL;
++	}
++
++	nc->smc = syscon_node_to_regmap(np);
++	of_node_put(np);
++	if (IS_ERR(nc->smc)) {
++		ret = PTR_ERR(nc->smc);
++		dev_err(dev, "Could not get SMC regmap (err = %d)\n", ret);
++		return ret;
++	}
++
++	return 0;
++}
++
++static int
++atmel_smc_nand_controller_init(struct atmel_smc_nand_controller *nc)
++{
++	struct device *dev = nc->base.dev;
++	const struct of_device_id *match;
++	struct device_node *np;
++	int ret;
++
++	/* We do not retrieve the matrix syscon when parsing old DTs. */
++	if (nc->base.caps->legacy_of_bindings)
++		return 0;
++
++	np = of_parse_phandle(dev->parent->of_node, "atmel,matrix", 0);
++	if (!np)
++		return 0;
++
++	match = of_match_node(atmel_matrix_of_ids, np);
++	if (!match) {
++		of_node_put(np);
++		return 0;
++	}
++
++	nc->matrix = syscon_node_to_regmap(np);
++	of_node_put(np);
++	if (IS_ERR(nc->matrix)) {
++		ret = PTR_ERR(nc->matrix);
++		dev_err(dev, "Could not get Matrix regmap (err = %d)\n", ret);
++		return ret;
++	}
++
++	nc->ebi_csa_offs = (unsigned int)match->data;
++
++	/*
++	 * The at91sam9263 has 2 EBIs, if the NAND controller is under EBI1
++	 * add 4 to ->ebi_csa_offs.
++	 */
++	if (of_device_is_compatible(dev->parent->of_node,
++				    "atmel,at91sam9263-ebi1"))
++		nc->ebi_csa_offs += 4;
++
++	return 0;
++}
++
++static int
++atmel_hsmc_nand_controller_legacy_init(struct atmel_hsmc_nand_controller *nc)
++{
++	struct regmap_config regmap_conf = {
++		.reg_bits = 32,
++		.val_bits = 32,
++		.reg_stride = 4,
++	};
++
++	struct device *dev = nc->base.dev;
++	struct device_node *nand_np, *nfc_np;
++	void __iomem *iomem;
++	struct resource res;
++	int ret;
++
++	nand_np = dev->of_node;
++	nfc_np = of_find_compatible_node(dev->of_node, NULL,
++					 "atmel,sama5d3-nfc");
++
++	nc->clk = of_clk_get(nfc_np, 0);
++	if (IS_ERR(nc->clk)) {
++		ret = PTR_ERR(nc->clk);
++		dev_err(dev, "Failed to retrieve HSMC clock (err = %d)\n",
++			ret);
++		goto out;
++	}
++
++	ret = clk_prepare_enable(nc->clk);
++	if (ret) {
++		dev_err(dev, "Failed to enable the HSMC clock (err = %d)\n",
++			ret);
++		goto out;
++	}
++
++	nc->irq = of_irq_get(nand_np, 0);
++	if (nc->irq <= 0) {
++		ret = nc->irq ?: -ENXIO;
++		if (ret != -EPROBE_DEFER)
++			dev_err(dev, "Failed to get IRQ number (err = %d)\n",
++				ret);
++		goto out;
++	}
++
++	ret = of_address_to_resource(nfc_np, 0, &res);
++	if (ret) {
++		dev_err(dev, "Invalid or missing NFC IO resource (err = %d)\n",
++			ret);
++		goto out;
++	}
++
++	iomem = devm_ioremap_resource(dev, &res);
++	if (IS_ERR(iomem)) {
++		ret = PTR_ERR(iomem);
++		goto out;
++	}
++
++	regmap_conf.name = "nfc-io";
++	regmap_conf.max_register = resource_size(&res) - 4;
++	nc->io = devm_regmap_init_mmio(dev, iomem, &regmap_conf);
++	if (IS_ERR(nc->io)) {
++		ret = PTR_ERR(nc->io);
++		dev_err(dev, "Could not create NFC IO regmap (err = %d)\n",
++			ret);
++		goto out;
++	}
++
++	ret = of_address_to_resource(nfc_np, 1, &res);
++	if (ret) {
++		dev_err(dev, "Invalid or missing HSMC resource (err = %d)\n",
++			ret);
++		goto out;
++	}
++
++	iomem = devm_ioremap_resource(dev, &res);
++	if (IS_ERR(iomem)) {
++		ret = PTR_ERR(iomem);
++		goto out;
++	}
++
++	regmap_conf.name = "smc";
++	regmap_conf.max_register = resource_size(&res) - 4;
++	nc->base.smc = devm_regmap_init_mmio(dev, iomem, &regmap_conf);
++	if (IS_ERR(nc->base.smc)) {
++		ret = PTR_ERR(nc->base.smc);
++		dev_err(dev, "Could not create NFC IO regmap (err = %d)\n",
++			ret);
++		goto out;
++	}
++
++	ret = of_address_to_resource(nfc_np, 2, &res);
++	if (ret) {
++		dev_err(dev, "Invalid or missing SRAM resource (err = %d)\n",
++			ret);
++		goto out;
++	}
++
++	nc->sram.virt = devm_ioremap_resource(dev, &res);
++	if (IS_ERR(nc->sram.virt)) {
++		ret = PTR_ERR(nc->sram.virt);
++		goto out;
++	}
++
++	nc->sram.dma = res.start;
++
++out:
++	of_node_put(nfc_np);
++
++	return ret;
++}
++
++static int
++atmel_hsmc_nand_controller_init(struct atmel_hsmc_nand_controller *nc)
++{
++	struct device *dev = nc->base.dev;
++	struct device_node *np;
++	int ret;
++
++	np = of_parse_phandle(dev->parent->of_node, "atmel,smc", 0);
++	if (!np) {
++		dev_err(dev, "Missing or invalid atmel,smc property\n");
++		return -EINVAL;
++	}
++
++	nc->hsmc_layout = atmel_hsmc_get_reg_layout(np);
++
++	nc->irq = of_irq_get(np, 0);
++	of_node_put(np);
++	if (nc->irq <= 0) {
++		ret = nc->irq ?: -ENXIO;
++		if (ret != -EPROBE_DEFER)
++			dev_err(dev, "Failed to get IRQ number (err = %d)\n",
++				ret);
++		return ret;
++	}
++
++	np = of_parse_phandle(dev->of_node, "atmel,nfc-io", 0);
++	if (!np) {
++		dev_err(dev, "Missing or invalid atmel,nfc-io property\n");
++		return -EINVAL;
++	}
++
++	nc->io = syscon_node_to_regmap(np);
++	of_node_put(np);
++	if (IS_ERR(nc->io)) {
++		ret = PTR_ERR(nc->io);
++		dev_err(dev, "Could not get NFC IO regmap (err = %d)\n", ret);
++		return ret;
++	}
++
++	nc->sram.pool = of_gen_pool_get(nc->base.dev->of_node,
++					 "atmel,nfc-sram", 0);
++	if (!nc->sram.pool) {
++		dev_err(nc->base.dev, "Missing SRAM\n");
++		return -ENOMEM;
++	}
++
++	nc->sram.virt = gen_pool_dma_alloc(nc->sram.pool,
++					    ATMEL_NFC_SRAM_SIZE,
++					    &nc->sram.dma);
++	if (!nc->sram.virt) {
++		dev_err(nc->base.dev,
++			"Could not allocate memory from the NFC SRAM pool\n");
++		return -ENOMEM;
++	}
++
++	return 0;
++}
++
++static int
++atmel_hsmc_nand_controller_remove(struct atmel_nand_controller *nc)
++{
++	struct atmel_hsmc_nand_controller *hsmc_nc;
++	int ret;
++
++	ret = atmel_nand_controller_remove_nands(nc);
++	if (ret)
++		return ret;
++
++	hsmc_nc = container_of(nc, struct atmel_hsmc_nand_controller, base);
++	if (hsmc_nc->sram.pool)
++		gen_pool_free(hsmc_nc->sram.pool,
++			      (unsigned long)hsmc_nc->sram.virt,
++			      ATMEL_NFC_SRAM_SIZE);
++
++	if (hsmc_nc->clk) {
++		clk_disable_unprepare(hsmc_nc->clk);
++		clk_put(hsmc_nc->clk);
++	}
++
++	atmel_nand_controller_cleanup(nc);
++
++	return 0;
++}
++
++static int atmel_hsmc_nand_controller_probe(struct platform_device *pdev,
++				const struct atmel_nand_controller_caps *caps)
++{
++	struct device *dev = &pdev->dev;
++	struct atmel_hsmc_nand_controller *nc;
++	int ret;
++
++	nc = devm_kzalloc(dev, sizeof(*nc), GFP_KERNEL);
++	if (!nc)
++		return -ENOMEM;
++
++	ret = atmel_nand_controller_init(&nc->base, pdev, caps);
++	if (ret)
++		return ret;
++
++	if (caps->legacy_of_bindings)
++		ret = atmel_hsmc_nand_controller_legacy_init(nc);
++	else
++		ret = atmel_hsmc_nand_controller_init(nc);
++
++	if (ret)
++		return ret;
++
++	/* Make sure all irqs are masked before registering our IRQ handler. */
++	regmap_write(nc->base.smc, ATMEL_HSMC_NFC_IDR, 0xffffffff);
++	ret = devm_request_irq(dev, nc->irq, atmel_nfc_interrupt,
++			       IRQF_SHARED, "nfc", nc);
++	if (ret) {
++		dev_err(dev,
++			"Could not get register NFC interrupt handler (err = %d)\n",
++			ret);
++		goto err;
++	}
++
++	/* Initial NFC configuration. */
++	regmap_write(nc->base.smc, ATMEL_HSMC_NFC_CFG,
++		     ATMEL_HSMC_NFC_CFG_DTO_MAX);
++
++	ret = atmel_nand_controller_add_nands(&nc->base);
++	if (ret)
++		goto err;
++
++	return 0;
++
++err:
++	atmel_hsmc_nand_controller_remove(&nc->base);
++
++	return ret;
++}
++
++static const struct atmel_nand_controller_ops atmel_hsmc_nc_ops = {
++	.probe = atmel_hsmc_nand_controller_probe,
++	.remove = atmel_hsmc_nand_controller_remove,
++	.ecc_init = atmel_hsmc_nand_ecc_init,
++	.nand_init = atmel_hsmc_nand_init,
++	.setup_data_interface = atmel_hsmc_nand_setup_data_interface,
++};
++
++static const struct atmel_nand_controller_caps atmel_sama5_nc_caps = {
++	.has_dma = true,
++	.ale_offs = BIT(21),
++	.cle_offs = BIT(22),
++	.ops = &atmel_hsmc_nc_ops,
++};
++
++/* Only used to parse old bindings. */
++static const struct atmel_nand_controller_caps atmel_sama5_nand_caps = {
++	.has_dma = true,
++	.ale_offs = BIT(21),
++	.cle_offs = BIT(22),
++	.ops = &atmel_hsmc_nc_ops,
++	.legacy_of_bindings = true,
++};
++
++static int atmel_smc_nand_controller_probe(struct platform_device *pdev,
++				const struct atmel_nand_controller_caps *caps)
++{
++	struct device *dev = &pdev->dev;
++	struct atmel_smc_nand_controller *nc;
++	int ret;
++
++	nc = devm_kzalloc(dev, sizeof(*nc), GFP_KERNEL);
++	if (!nc)
++		return -ENOMEM;
++
++	ret = atmel_nand_controller_init(&nc->base, pdev, caps);
++	if (ret)
++		return ret;
++
++	ret = atmel_smc_nand_controller_init(nc);
++	if (ret)
++		return ret;
++
++	return atmel_nand_controller_add_nands(&nc->base);
++}
++
++static int
++atmel_smc_nand_controller_remove(struct atmel_nand_controller *nc)
++{
++	int ret;
++
++	ret = atmel_nand_controller_remove_nands(nc);
++	if (ret)
++		return ret;
++
++	atmel_nand_controller_cleanup(nc);
++
++	return 0;
++}
++
++/*
++ * The SMC reg layout of at91rm9200 is completely different which prevents us
++ * from re-using atmel_smc_nand_setup_data_interface() for the
++ * ->setup_data_interface() hook.
++ * At this point, there's no support for the at91rm9200 SMC IP, so we leave
++ * ->setup_data_interface() unassigned.
++ */
++static const struct atmel_nand_controller_ops at91rm9200_nc_ops = {
++	.probe = atmel_smc_nand_controller_probe,
++	.remove = atmel_smc_nand_controller_remove,
++	.ecc_init = atmel_nand_ecc_init,
++	.nand_init = atmel_smc_nand_init,
++};
++
++static const struct atmel_nand_controller_caps atmel_rm9200_nc_caps = {
++	.ale_offs = BIT(21),
++	.cle_offs = BIT(22),
++	.ops = &at91rm9200_nc_ops,
++};
++
++static const struct atmel_nand_controller_ops atmel_smc_nc_ops = {
++	.probe = atmel_smc_nand_controller_probe,
++	.remove = atmel_smc_nand_controller_remove,
++	.ecc_init = atmel_nand_ecc_init,
++	.nand_init = atmel_smc_nand_init,
++	.setup_data_interface = atmel_smc_nand_setup_data_interface,
++};
++
++static const struct atmel_nand_controller_caps atmel_sam9260_nc_caps = {
++	.ale_offs = BIT(21),
++	.cle_offs = BIT(22),
++	.ops = &atmel_smc_nc_ops,
++};
++
++static const struct atmel_nand_controller_caps atmel_sam9261_nc_caps = {
++	.ale_offs = BIT(22),
++	.cle_offs = BIT(21),
++	.ops = &atmel_smc_nc_ops,
++};
++
++static const struct atmel_nand_controller_caps atmel_sam9g45_nc_caps = {
++	.has_dma = true,
++	.ale_offs = BIT(21),
++	.cle_offs = BIT(22),
++	.ops = &atmel_smc_nc_ops,
++};
++
++/* Only used to parse old bindings. */
++static const struct atmel_nand_controller_caps atmel_rm9200_nand_caps = {
++	.ale_offs = BIT(21),
++	.cle_offs = BIT(22),
++	.ops = &atmel_smc_nc_ops,
++	.legacy_of_bindings = true,
++};
++
++static const struct atmel_nand_controller_caps atmel_sam9261_nand_caps = {
++	.ale_offs = BIT(22),
++	.cle_offs = BIT(21),
++	.ops = &atmel_smc_nc_ops,
++	.legacy_of_bindings = true,
++};
++
++static const struct atmel_nand_controller_caps atmel_sam9g45_nand_caps = {
++	.has_dma = true,
++	.ale_offs = BIT(21),
++	.cle_offs = BIT(22),
++	.ops = &atmel_smc_nc_ops,
++	.legacy_of_bindings = true,
++};
++
++static const struct of_device_id atmel_nand_controller_of_ids[] = {
++	{
++		.compatible = "atmel,at91rm9200-nand-controller",
++		.data = &atmel_rm9200_nc_caps,
++	},
++	{
++		.compatible = "atmel,at91sam9260-nand-controller",
++		.data = &atmel_sam9260_nc_caps,
++	},
++	{
++		.compatible = "atmel,at91sam9261-nand-controller",
++		.data = &atmel_sam9261_nc_caps,
++	},
++	{
++		.compatible = "atmel,at91sam9g45-nand-controller",
++		.data = &atmel_sam9g45_nc_caps,
++	},
++	{
++		.compatible = "atmel,sama5d3-nand-controller",
++		.data = &atmel_sama5_nc_caps,
++	},
++	/* Support for old/deprecated bindings: */
++	{
++		.compatible = "atmel,at91rm9200-nand",
++		.data = &atmel_rm9200_nand_caps,
++	},
++	{
++		.compatible = "atmel,sama5d4-nand",
++		.data = &atmel_rm9200_nand_caps,
++	},
++	{
++		.compatible = "atmel,sama5d2-nand",
++		.data = &atmel_rm9200_nand_caps,
++	},
++	{ /* sentinel */ },
++};
++MODULE_DEVICE_TABLE(of, atmel_nand_controller_of_ids);
++
++static int atmel_nand_controller_probe(struct platform_device *pdev)
++{
++	const struct atmel_nand_controller_caps *caps;
++
++	if (pdev->id_entry)
++		caps = (void *)pdev->id_entry->driver_data;
++	else
++		caps = of_device_get_match_data(&pdev->dev);
++
++	if (!caps) {
++		dev_err(&pdev->dev, "Could not retrieve NFC caps\n");
++		return -EINVAL;
++	}
++
++	if (caps->legacy_of_bindings) {
++		u32 ale_offs = 21;
++
++		/*
++		 * If we are parsing legacy DT props and the DT contains a
++		 * valid NFC node, forward the request to the sama5 logic.
++		 */
++		if (of_find_compatible_node(pdev->dev.of_node, NULL,
++					    "atmel,sama5d3-nfc"))
++			caps = &atmel_sama5_nand_caps;
++
++		/*
++		 * Even if the compatible says we are dealing with an
++		 * at91rm9200 controller, the atmel,nand-has-dma specify that
++		 * this controller supports DMA, which means we are in fact
++		 * dealing with an at91sam9g45+ controller.
++		 */
++		if (!caps->has_dma &&
++		    of_property_read_bool(pdev->dev.of_node,
++					  "atmel,nand-has-dma"))
++			caps = &atmel_sam9g45_nand_caps;
++
++		/*
++		 * All SoCs except the at91sam9261 are assigning ALE to A21 and
++		 * CLE to A22. If atmel,nand-addr-offset != 21 this means we're
++		 * actually dealing with an at91sam9261 controller.
++		 */
++		of_property_read_u32(pdev->dev.of_node,
++				     "atmel,nand-addr-offset", &ale_offs);
++		if (ale_offs != 21)
++			caps = &atmel_sam9261_nand_caps;
++	}
++
++	return caps->ops->probe(pdev, caps);
++}
++
++static int atmel_nand_controller_remove(struct platform_device *pdev)
++{
++	struct atmel_nand_controller *nc = platform_get_drvdata(pdev);
++
++	return nc->caps->ops->remove(nc);
++}
++
++static __maybe_unused int atmel_nand_controller_resume(struct device *dev)
++{
++	struct atmel_nand_controller *nc = dev_get_drvdata(dev);
++	struct atmel_nand *nand;
++
++	list_for_each_entry(nand, &nc->chips, node) {
++		int i;
++
++		for (i = 0; i < nand->numcs; i++)
++			nand_reset(&nand->base, i);
++	}
++
++	return 0;
++}
++
++static SIMPLE_DEV_PM_OPS(atmel_nand_controller_pm_ops, NULL,
++			 atmel_nand_controller_resume);
++
++static struct platform_driver atmel_nand_controller_driver = {
++	.driver = {
++		.name = "atmel-nand-controller",
++		.of_match_table = of_match_ptr(atmel_nand_controller_of_ids),
++		.pm = &atmel_nand_controller_pm_ops,
++	},
++	.probe = atmel_nand_controller_probe,
++	.remove = atmel_nand_controller_remove,
++};
++module_platform_driver(atmel_nand_controller_driver);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Boris Brezillon <boris.brezillon@free-electrons.com>");
++MODULE_DESCRIPTION("NAND Flash Controller driver for Atmel SoCs");
++MODULE_ALIAS("platform:atmel-nand-controller");
+diff --git a/drivers/mtd/nand/raw/atmel/pmecc.c b/drivers/mtd/nand/raw/atmel/pmecc.c
+new file mode 100644
+index 0000000..8268636
+--- /dev/null
++++ b/drivers/mtd/nand/raw/atmel/pmecc.c
+@@ -0,0 +1,1011 @@
++/*
++ * Copyright 2017 ATMEL
++ * Copyright 2017 Free Electrons
++ *
++ * Author: Boris Brezillon <boris.brezillon@free-electrons.com>
++ *
++ * Derived from the atmel_nand.c driver which contained the following
++ * copyrights:
++ *
++ *   Copyright 2003 Rick Bronson
++ *
++ *   Derived from drivers/mtd/nand/autcpu12.c
++ *	Copyright 2001 Thomas Gleixner (gleixner@autronix.de)
++ *
++ *   Derived from drivers/mtd/spia.c
++ *	Copyright 2000 Steven J. Hill (sjhill@cotw.com)
++ *
++ *   Add Hardware ECC support for AT91SAM9260 / AT91SAM9263
++ *	Richard Genoud (richard.genoud@gmail.com), Adeneo Copyright 2007
++ *
++ *   Derived from Das U-Boot source code
++ *	(u-boot-1.1.5/board/atmel/at91sam9263ek/nand.c)
++ *      Copyright 2006 ATMEL Rousset, Lacressonniere Nicolas
++ *
++ *   Add Programmable Multibit ECC support for various AT91 SoC
++ *	Copyright 2012 ATMEL, Hong Xu
++ *
++ *   Add Nand Flash Controller support for SAMA5 SoC
++ *	Copyright 2013 ATMEL, Josh Wu (josh.wu@atmel.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.
++ *
++ * The PMECC is an hardware assisted BCH engine, which means part of the
++ * ECC algorithm is left to the software. The hardware/software repartition
++ * is explained in the "PMECC Controller Functional Description" chapter in
++ * Atmel datasheets, and some of the functions in this file are directly
++ * implementing the algorithms described in the "Software Implementation"
++ * sub-section.
++ *
++ * TODO: it seems that the software BCH implementation in lib/bch.c is already
++ * providing some of the logic we are implementing here. It would be smart
++ * to expose the needed lib/bch.c helpers/functions and re-use them here.
++ */
++
++#include <linux/genalloc.h>
++#include <linux/iopoll.h>
++#include <linux/module.h>
++#include <linux/mtd/rawnand.h>
++#include <linux/of_irq.h>
++#include <linux/of_platform.h>
++#include <linux/platform_device.h>
++#include <linux/slab.h>
++
++#include "pmecc.h"
++
++/* Galois field dimension */
++#define PMECC_GF_DIMENSION_13			13
++#define PMECC_GF_DIMENSION_14			14
++
++/* Primitive Polynomial used by PMECC */
++#define PMECC_GF_13_PRIMITIVE_POLY		0x201b
++#define PMECC_GF_14_PRIMITIVE_POLY		0x4443
++
++#define PMECC_LOOKUP_TABLE_SIZE_512		0x2000
++#define PMECC_LOOKUP_TABLE_SIZE_1024		0x4000
++
++/* Time out value for reading PMECC status register */
++#define PMECC_MAX_TIMEOUT_MS			100
++
++/* PMECC Register Definitions */
++#define ATMEL_PMECC_CFG				0x0
++#define PMECC_CFG_BCH_STRENGTH(x)		(x)
++#define PMECC_CFG_BCH_STRENGTH_MASK		GENMASK(2, 0)
++#define PMECC_CFG_SECTOR512			(0 << 4)
++#define PMECC_CFG_SECTOR1024			(1 << 4)
++#define PMECC_CFG_NSECTORS(x)			((fls(x) - 1) << 8)
++#define PMECC_CFG_READ_OP			(0 << 12)
++#define PMECC_CFG_WRITE_OP			(1 << 12)
++#define PMECC_CFG_SPARE_ENABLE			BIT(16)
++#define PMECC_CFG_AUTO_ENABLE			BIT(20)
++
++#define ATMEL_PMECC_SAREA			0x4
++#define ATMEL_PMECC_SADDR			0x8
++#define ATMEL_PMECC_EADDR			0xc
++
++#define ATMEL_PMECC_CLK				0x10
++#define PMECC_CLK_133MHZ			(2 << 0)
++
++#define ATMEL_PMECC_CTRL			0x14
++#define PMECC_CTRL_RST				BIT(0)
++#define PMECC_CTRL_DATA				BIT(1)
++#define PMECC_CTRL_USER				BIT(2)
++#define PMECC_CTRL_ENABLE			BIT(4)
++#define PMECC_CTRL_DISABLE			BIT(5)
++
++#define ATMEL_PMECC_SR				0x18
++#define PMECC_SR_BUSY				BIT(0)
++#define PMECC_SR_ENABLE				BIT(4)
++
++#define ATMEL_PMECC_IER				0x1c
++#define ATMEL_PMECC_IDR				0x20
++#define ATMEL_PMECC_IMR				0x24
++#define ATMEL_PMECC_ISR				0x28
++#define PMECC_ERROR_INT				BIT(0)
++
++#define ATMEL_PMECC_ECC(sector, n)		\
++	((((sector) + 1) * 0x40) + (n))
++
++#define ATMEL_PMECC_REM(sector, n)		\
++	((((sector) + 1) * 0x40) + ((n) * 4) + 0x200)
++
++/* PMERRLOC Register Definitions */
++#define ATMEL_PMERRLOC_ELCFG			0x0
++#define PMERRLOC_ELCFG_SECTOR_512		(0 << 0)
++#define PMERRLOC_ELCFG_SECTOR_1024		(1 << 0)
++#define PMERRLOC_ELCFG_NUM_ERRORS(n)		((n) << 16)
++
++#define ATMEL_PMERRLOC_ELPRIM			0x4
++#define ATMEL_PMERRLOC_ELEN			0x8
++#define ATMEL_PMERRLOC_ELDIS			0xc
++#define PMERRLOC_DISABLE			BIT(0)
++
++#define ATMEL_PMERRLOC_ELSR			0x10
++#define PMERRLOC_ELSR_BUSY			BIT(0)
++
++#define ATMEL_PMERRLOC_ELIER			0x14
++#define ATMEL_PMERRLOC_ELIDR			0x18
++#define ATMEL_PMERRLOC_ELIMR			0x1c
++#define ATMEL_PMERRLOC_ELISR			0x20
++#define PMERRLOC_ERR_NUM_MASK			GENMASK(12, 8)
++#define PMERRLOC_CALC_DONE			BIT(0)
++
++#define ATMEL_PMERRLOC_SIGMA(x)			(((x) * 0x4) + 0x28)
++
++#define ATMEL_PMERRLOC_EL(offs, x)		(((x) * 0x4) + (offs))
++
++struct atmel_pmecc_gf_tables {
++	u16 *alpha_to;
++	u16 *index_of;
++};
++
++struct atmel_pmecc_caps {
++	const int *strengths;
++	int nstrengths;
++	int el_offset;
++	bool correct_erased_chunks;
++};
++
++struct atmel_pmecc {
++	struct device *dev;
++	const struct atmel_pmecc_caps *caps;
++
++	struct {
++		void __iomem *base;
++		void __iomem *errloc;
++	} regs;
++
++	struct mutex lock;
++};
++
++struct atmel_pmecc_user_conf_cache {
++	u32 cfg;
++	u32 sarea;
++	u32 saddr;
++	u32 eaddr;
++};
++
++struct atmel_pmecc_user {
++	struct atmel_pmecc_user_conf_cache cache;
++	struct atmel_pmecc *pmecc;
++	const struct atmel_pmecc_gf_tables *gf_tables;
++	int eccbytes;
++	s16 *partial_syn;
++	s16 *si;
++	s16 *lmu;
++	s16 *smu;
++	s32 *mu;
++	s32 *dmu;
++	s32 *delta;
++	u32 isr;
++};
++
++static DEFINE_MUTEX(pmecc_gf_tables_lock);
++static const struct atmel_pmecc_gf_tables *pmecc_gf_tables_512;
++static const struct atmel_pmecc_gf_tables *pmecc_gf_tables_1024;
++
++static inline int deg(unsigned int poly)
++{
++	/* polynomial degree is the most-significant bit index */
++	return fls(poly) - 1;
++}
++
++static int atmel_pmecc_build_gf_tables(int mm, unsigned int poly,
++				       struct atmel_pmecc_gf_tables *gf_tables)
++{
++	unsigned int i, x = 1;
++	const unsigned int k = BIT(deg(poly));
++	unsigned int nn = BIT(mm) - 1;
++
++	/* primitive polynomial must be of degree m */
++	if (k != (1u << mm))
++		return -EINVAL;
++
++	for (i = 0; i < nn; i++) {
++		gf_tables->alpha_to[i] = x;
++		gf_tables->index_of[x] = i;
++		if (i && (x == 1))
++			/* polynomial is not primitive (a^i=1 with 0<i<2^m-1) */
++			return -EINVAL;
++		x <<= 1;
++		if (x & k)
++			x ^= poly;
++	}
++	gf_tables->alpha_to[nn] = 1;
++	gf_tables->index_of[0] = 0;
++
++	return 0;
++}
++
++static const struct atmel_pmecc_gf_tables *
++atmel_pmecc_create_gf_tables(const struct atmel_pmecc_user_req *req)
++{
++	struct atmel_pmecc_gf_tables *gf_tables;
++	unsigned int poly, degree, table_size;
++	int ret;
++
++	if (req->ecc.sectorsize == 512) {
++		degree = PMECC_GF_DIMENSION_13;
++		poly = PMECC_GF_13_PRIMITIVE_POLY;
++		table_size = PMECC_LOOKUP_TABLE_SIZE_512;
++	} else {
++		degree = PMECC_GF_DIMENSION_14;
++		poly = PMECC_GF_14_PRIMITIVE_POLY;
++		table_size = PMECC_LOOKUP_TABLE_SIZE_1024;
++	}
++
++	gf_tables = kzalloc(sizeof(*gf_tables) +
++			    (2 * table_size * sizeof(u16)),
++			    GFP_KERNEL);
++	if (!gf_tables)
++		return ERR_PTR(-ENOMEM);
++
++	gf_tables->alpha_to = (void *)(gf_tables + 1);
++	gf_tables->index_of = gf_tables->alpha_to + table_size;
++
++	ret = atmel_pmecc_build_gf_tables(degree, poly, gf_tables);
++	if (ret) {
++		kfree(gf_tables);
++		return ERR_PTR(ret);
++	}
++
++	return gf_tables;
++}
++
++static const struct atmel_pmecc_gf_tables *
++atmel_pmecc_get_gf_tables(const struct atmel_pmecc_user_req *req)
++{
++	const struct atmel_pmecc_gf_tables **gf_tables, *ret;
++
++	mutex_lock(&pmecc_gf_tables_lock);
++	if (req->ecc.sectorsize == 512)
++		gf_tables = &pmecc_gf_tables_512;
++	else
++		gf_tables = &pmecc_gf_tables_1024;
++
++	ret = *gf_tables;
++
++	if (!ret) {
++		ret = atmel_pmecc_create_gf_tables(req);
++		if (!IS_ERR(ret))
++			*gf_tables = ret;
++	}
++	mutex_unlock(&pmecc_gf_tables_lock);
++
++	return ret;
++}
++
++static int atmel_pmecc_prepare_user_req(struct atmel_pmecc *pmecc,
++					struct atmel_pmecc_user_req *req)
++{
++	int i, max_eccbytes, eccbytes = 0, eccstrength = 0;
++
++	if (req->pagesize <= 0 || req->oobsize <= 0 || req->ecc.bytes <= 0)
++		return -EINVAL;
++
++	if (req->ecc.ooboffset >= 0 &&
++	    req->ecc.ooboffset + req->ecc.bytes > req->oobsize)
++		return -EINVAL;
++
++	if (req->ecc.sectorsize == ATMEL_PMECC_SECTOR_SIZE_AUTO) {
++		if (req->ecc.strength != ATMEL_PMECC_MAXIMIZE_ECC_STRENGTH)
++			return -EINVAL;
++
++		if (req->pagesize > 512)
++			req->ecc.sectorsize = 1024;
++		else
++			req->ecc.sectorsize = 512;
++	}
++
++	if (req->ecc.sectorsize != 512 && req->ecc.sectorsize != 1024)
++		return -EINVAL;
++
++	if (req->pagesize % req->ecc.sectorsize)
++		return -EINVAL;
++
++	req->ecc.nsectors = req->pagesize / req->ecc.sectorsize;
++
++	max_eccbytes = req->ecc.bytes;
++
++	for (i = 0; i < pmecc->caps->nstrengths; i++) {
++		int nbytes, strength = pmecc->caps->strengths[i];
++
++		if (req->ecc.strength != ATMEL_PMECC_MAXIMIZE_ECC_STRENGTH &&
++		    strength < req->ecc.strength)
++			continue;
++
++		nbytes = DIV_ROUND_UP(strength * fls(8 * req->ecc.sectorsize),
++				      8);
++		nbytes *= req->ecc.nsectors;
++
++		if (nbytes > max_eccbytes)
++			break;
++
++		eccstrength = strength;
++		eccbytes = nbytes;
++
++		if (req->ecc.strength != ATMEL_PMECC_MAXIMIZE_ECC_STRENGTH)
++			break;
++	}
++
++	if (!eccstrength)
++		return -EINVAL;
++
++	req->ecc.bytes = eccbytes;
++	req->ecc.strength = eccstrength;
++
++	if (req->ecc.ooboffset < 0)
++		req->ecc.ooboffset = req->oobsize - eccbytes;
++
++	return 0;
++}
++
++struct atmel_pmecc_user *
++atmel_pmecc_create_user(struct atmel_pmecc *pmecc,
++			struct atmel_pmecc_user_req *req)
++{
++	struct atmel_pmecc_user *user;
++	const struct atmel_pmecc_gf_tables *gf_tables;
++	int strength, size, ret;
++
++	ret = atmel_pmecc_prepare_user_req(pmecc, req);
++	if (ret)
++		return ERR_PTR(ret);
++
++	size = sizeof(*user);
++	size = ALIGN(size, sizeof(u16));
++	/* Reserve space for partial_syn, si and smu */
++	size += ((2 * req->ecc.strength) + 1) * sizeof(u16) *
++		(2 + req->ecc.strength + 2);
++	/* Reserve space for lmu. */
++	size += (req->ecc.strength + 1) * sizeof(u16);
++	/* Reserve space for mu, dmu and delta. */
++	size = ALIGN(size, sizeof(s32));
++	size += (req->ecc.strength + 1) * sizeof(s32) * 3;
++
++	user = kzalloc(size, GFP_KERNEL);
++	if (!user)
++		return ERR_PTR(-ENOMEM);
++
++	user->pmecc = pmecc;
++
++	user->partial_syn = (s16 *)PTR_ALIGN(user + 1, sizeof(u16));
++	user->si = user->partial_syn + ((2 * req->ecc.strength) + 1);
++	user->lmu = user->si + ((2 * req->ecc.strength) + 1);
++	user->smu = user->lmu + (req->ecc.strength + 1);
++	user->mu = (s32 *)PTR_ALIGN(user->smu +
++				    (((2 * req->ecc.strength) + 1) *
++				     (req->ecc.strength + 2)),
++				    sizeof(s32));
++	user->dmu = user->mu + req->ecc.strength + 1;
++	user->delta = user->dmu + req->ecc.strength + 1;
++
++	gf_tables = atmel_pmecc_get_gf_tables(req);
++	if (IS_ERR(gf_tables)) {
++		kfree(user);
++		return ERR_CAST(gf_tables);
++	}
++
++	user->gf_tables = gf_tables;
++
++	user->eccbytes = req->ecc.bytes / req->ecc.nsectors;
++
++	for (strength = 0; strength < pmecc->caps->nstrengths; strength++) {
++		if (pmecc->caps->strengths[strength] == req->ecc.strength)
++			break;
++	}
++
++	user->cache.cfg = PMECC_CFG_BCH_STRENGTH(strength) |
++			  PMECC_CFG_NSECTORS(req->ecc.nsectors);
++
++	if (req->ecc.sectorsize == 1024)
++		user->cache.cfg |= PMECC_CFG_SECTOR1024;
++
++	user->cache.sarea = req->oobsize - 1;
++	user->cache.saddr = req->ecc.ooboffset;
++	user->cache.eaddr = req->ecc.ooboffset + req->ecc.bytes - 1;
++
++	return user;
++}
++EXPORT_SYMBOL_GPL(atmel_pmecc_create_user);
++
++void atmel_pmecc_destroy_user(struct atmel_pmecc_user *user)
++{
++	kfree(user);
++}
++EXPORT_SYMBOL_GPL(atmel_pmecc_destroy_user);
++
++static int get_strength(struct atmel_pmecc_user *user)
++{
++	const int *strengths = user->pmecc->caps->strengths;
++
++	return strengths[user->cache.cfg & PMECC_CFG_BCH_STRENGTH_MASK];
++}
++
++static int get_sectorsize(struct atmel_pmecc_user *user)
++{
++	return user->cache.cfg & PMECC_LOOKUP_TABLE_SIZE_1024 ? 1024 : 512;
++}
++
++static void atmel_pmecc_gen_syndrome(struct atmel_pmecc_user *user, int sector)
++{
++	int strength = get_strength(user);
++	u32 value;
++	int i;
++
++	/* Fill odd syndromes */
++	for (i = 0; i < strength; i++) {
++		value = readl_relaxed(user->pmecc->regs.base +
++				      ATMEL_PMECC_REM(sector, i / 2));
++		if (i & 1)
++			value >>= 16;
++
++		user->partial_syn[(2 * i) + 1] = value;
++	}
++}
++
++static void atmel_pmecc_substitute(struct atmel_pmecc_user *user)
++{
++	int degree = get_sectorsize(user) == 512 ? 13 : 14;
++	int cw_len = BIT(degree) - 1;
++	int strength = get_strength(user);
++	s16 *alpha_to = user->gf_tables->alpha_to;
++	s16 *index_of = user->gf_tables->index_of;
++	s16 *partial_syn = user->partial_syn;
++	s16 *si;
++	int i, j;
++
++	/*
++	 * si[] is a table that holds the current syndrome value,
++	 * an element of that table belongs to the field
++	 */
++	si = user->si;
++
++	memset(&si[1], 0, sizeof(s16) * ((2 * strength) - 1));
++
++	/* Computation 2t syndromes based on S(x) */
++	/* Odd syndromes */
++	for (i = 1; i < 2 * strength; i += 2) {
++		for (j = 0; j < degree; j++) {
++			if (partial_syn[i] & BIT(j))
++				si[i] = alpha_to[i * j] ^ si[i];
++		}
++	}
++	/* Even syndrome = (Odd syndrome) ** 2 */
++	for (i = 2, j = 1; j <= strength; i = ++j << 1) {
++		if (si[j] == 0) {
++			si[i] = 0;
++		} else {
++			s16 tmp;
++
++			tmp = index_of[si[j]];
++			tmp = (tmp * 2) % cw_len;
++			si[i] = alpha_to[tmp];
++		}
++	}
++}
++
++static void atmel_pmecc_get_sigma(struct atmel_pmecc_user *user)
++{
++	s16 *lmu = user->lmu;
++	s16 *si = user->si;
++	s32 *mu = user->mu;
++	s32 *dmu = user->dmu;
++	s32 *delta = user->delta;
++	int degree = get_sectorsize(user) == 512 ? 13 : 14;
++	int cw_len = BIT(degree) - 1;
++	int strength = get_strength(user);
++	int num = 2 * strength + 1;
++	s16 *index_of = user->gf_tables->index_of;
++	s16 *alpha_to = user->gf_tables->alpha_to;
++	int i, j, k;
++	u32 dmu_0_count, tmp;
++	s16 *smu = user->smu;
++
++	/* index of largest delta */
++	int ro;
++	int largest;
++	int diff;
++
++	dmu_0_count = 0;
++
++	/* First Row */
++
++	/* Mu */
++	mu[0] = -1;
++
++	memset(smu, 0, sizeof(s16) * num);
++	smu[0] = 1;
++
++	/* discrepancy set to 1 */
++	dmu[0] = 1;
++	/* polynom order set to 0 */
++	lmu[0] = 0;
++	delta[0] = (mu[0] * 2 - lmu[0]) >> 1;
++
++	/* Second Row */
++
++	/* Mu */
++	mu[1] = 0;
++	/* Sigma(x) set to 1 */
++	memset(&smu[num], 0, sizeof(s16) * num);
++	smu[num] = 1;
++
++	/* discrepancy set to S1 */
++	dmu[1] = si[1];
++
++	/* polynom order set to 0 */
++	lmu[1] = 0;
++
++	delta[1] = (mu[1] * 2 - lmu[1]) >> 1;
++
++	/* Init the Sigma(x) last row */
++	memset(&smu[(strength + 1) * num], 0, sizeof(s16) * num);
++
++	for (i = 1; i <= strength; i++) {
++		mu[i + 1] = i << 1;
++		/* Begin Computing Sigma (Mu+1) and L(mu) */
++		/* check if discrepancy is set to 0 */
++		if (dmu[i] == 0) {
++			dmu_0_count++;
++
++			tmp = ((strength - (lmu[i] >> 1) - 1) / 2);
++			if ((strength - (lmu[i] >> 1) - 1) & 0x1)
++				tmp += 2;
++			else
++				tmp += 1;
++
++			if (dmu_0_count == tmp) {
++				for (j = 0; j <= (lmu[i] >> 1) + 1; j++)
++					smu[(strength + 1) * num + j] =
++							smu[i * num + j];
++
++				lmu[strength + 1] = lmu[i];
++				return;
++			}
++
++			/* copy polynom */
++			for (j = 0; j <= lmu[i] >> 1; j++)
++				smu[(i + 1) * num + j] = smu[i * num + j];
++
++			/* copy previous polynom order to the next */
++			lmu[i + 1] = lmu[i];
++		} else {
++			ro = 0;
++			largest = -1;
++			/* find largest delta with dmu != 0 */
++			for (j = 0; j < i; j++) {
++				if ((dmu[j]) && (delta[j] > largest)) {
++					largest = delta[j];
++					ro = j;
++				}
++			}
++
++			/* compute difference */
++			diff = (mu[i] - mu[ro]);
++
++			/* Compute degree of the new smu polynomial */
++			if ((lmu[i] >> 1) > ((lmu[ro] >> 1) + diff))
++				lmu[i + 1] = lmu[i];
++			else
++				lmu[i + 1] = ((lmu[ro] >> 1) + diff) * 2;
++
++			/* Init smu[i+1] with 0 */
++			for (k = 0; k < num; k++)
++				smu[(i + 1) * num + k] = 0;
++
++			/* Compute smu[i+1] */
++			for (k = 0; k <= lmu[ro] >> 1; k++) {
++				s16 a, b, c;
++
++				if (!(smu[ro * num + k] && dmu[i]))
++					continue;
++
++				a = index_of[dmu[i]];
++				b = index_of[dmu[ro]];
++				c = index_of[smu[ro * num + k]];
++				tmp = a + (cw_len - b) + c;
++				a = alpha_to[tmp % cw_len];
++				smu[(i + 1) * num + (k + diff)] = a;
++			}
++
++			for (k = 0; k <= lmu[i] >> 1; k++)
++				smu[(i + 1) * num + k] ^= smu[i * num + k];
++		}
++
++		/* End Computing Sigma (Mu+1) and L(mu) */
++		/* In either case compute delta */
++		delta[i + 1] = (mu[i + 1] * 2 - lmu[i + 1]) >> 1;
++
++		/* Do not compute discrepancy for the last iteration */
++		if (i >= strength)
++			continue;
++
++		for (k = 0; k <= (lmu[i + 1] >> 1); k++) {
++			tmp = 2 * (i - 1);
++			if (k == 0) {
++				dmu[i + 1] = si[tmp + 3];
++			} else if (smu[(i + 1) * num + k] && si[tmp + 3 - k]) {
++				s16 a, b, c;
++
++				a = index_of[smu[(i + 1) * num + k]];
++				b = si[2 * (i - 1) + 3 - k];
++				c = index_of[b];
++				tmp = a + c;
++				tmp %= cw_len;
++				dmu[i + 1] = alpha_to[tmp] ^ dmu[i + 1];
++			}
++		}
++	}
++}
++
++static int atmel_pmecc_err_location(struct atmel_pmecc_user *user)
++{
++	int sector_size = get_sectorsize(user);
++	int degree = sector_size == 512 ? 13 : 14;
++	struct atmel_pmecc *pmecc = user->pmecc;
++	int strength = get_strength(user);
++	int ret, roots_nbr, i, err_nbr = 0;
++	int num = (2 * strength) + 1;
++	s16 *smu = user->smu;
++	u32 val;
++
++	writel(PMERRLOC_DISABLE, pmecc->regs.errloc + ATMEL_PMERRLOC_ELDIS);
++
++	for (i = 0; i <= user->lmu[strength + 1] >> 1; i++) {
++		writel_relaxed(smu[(strength + 1) * num + i],
++			       pmecc->regs.errloc + ATMEL_PMERRLOC_SIGMA(i));
++		err_nbr++;
++	}
++
++	val = (err_nbr - 1) << 16;
++	if (sector_size == 1024)
++		val |= 1;
++
++	writel(val, pmecc->regs.errloc + ATMEL_PMERRLOC_ELCFG);
++	writel((sector_size * 8) + (degree * strength),
++	       pmecc->regs.errloc + ATMEL_PMERRLOC_ELEN);
++
++	ret = readl_relaxed_poll_timeout(pmecc->regs.errloc +
++					 ATMEL_PMERRLOC_ELISR,
++					 val, val & PMERRLOC_CALC_DONE, 0,
++					 PMECC_MAX_TIMEOUT_MS * 1000);
++	if (ret) {
++		dev_err(pmecc->dev,
++			"PMECC: Timeout to calculate error location.\n");
++		return ret;
++	}
++
++	roots_nbr = (val & PMERRLOC_ERR_NUM_MASK) >> 8;
++	/* Number of roots == degree of smu hence <= cap */
++	if (roots_nbr == user->lmu[strength + 1] >> 1)
++		return err_nbr - 1;
++
++	/*
++	 * Number of roots does not match the degree of smu
++	 * unable to correct error.
++	 */
++	return -EBADMSG;
++}
++
++int atmel_pmecc_correct_sector(struct atmel_pmecc_user *user, int sector,
++			       void *data, void *ecc)
++{
++	struct atmel_pmecc *pmecc = user->pmecc;
++	int sectorsize = get_sectorsize(user);
++	int eccbytes = user->eccbytes;
++	int i, nerrors;
++
++	if (!(user->isr & BIT(sector)))
++		return 0;
++
++	atmel_pmecc_gen_syndrome(user, sector);
++	atmel_pmecc_substitute(user);
++	atmel_pmecc_get_sigma(user);
++
++	nerrors = atmel_pmecc_err_location(user);
++	if (nerrors < 0)
++		return nerrors;
++
++	for (i = 0; i < nerrors; i++) {
++		const char *area;
++		int byte, bit;
++		u32 errpos;
++		u8 *ptr;
++
++		errpos = readl_relaxed(pmecc->regs.errloc +
++				ATMEL_PMERRLOC_EL(pmecc->caps->el_offset, i));
++		errpos--;
++
++		byte = errpos / 8;
++		bit = errpos % 8;
++
++		if (byte < sectorsize) {
++			ptr = data + byte;
++			area = "data";
++		} else if (byte < sectorsize + eccbytes) {
++			ptr = ecc + byte - sectorsize;
++			area = "ECC";
++		} else {
++			dev_dbg(pmecc->dev,
++				"Invalid errpos value (%d, max is %d)\n",
++				errpos, (sectorsize + eccbytes) * 8);
++			return -EINVAL;
++		}
++
++		dev_dbg(pmecc->dev,
++			"Bit flip in %s area, byte %d: 0x%02x -> 0x%02x\n",
++			area, byte, *ptr, (unsigned int)(*ptr ^ BIT(bit)));
++
++		*ptr ^= BIT(bit);
++	}
++
++	return nerrors;
++}
++EXPORT_SYMBOL_GPL(atmel_pmecc_correct_sector);
++
++bool atmel_pmecc_correct_erased_chunks(struct atmel_pmecc_user *user)
++{
++	return user->pmecc->caps->correct_erased_chunks;
++}
++EXPORT_SYMBOL_GPL(atmel_pmecc_correct_erased_chunks);
++
++void atmel_pmecc_get_generated_eccbytes(struct atmel_pmecc_user *user,
++					int sector, void *ecc)
++{
++	struct atmel_pmecc *pmecc = user->pmecc;
++	u8 *ptr = ecc;
++	int i;
++
++	for (i = 0; i < user->eccbytes; i++)
++		ptr[i] = readb_relaxed(pmecc->regs.base +
++				       ATMEL_PMECC_ECC(sector, i));
++}
++EXPORT_SYMBOL_GPL(atmel_pmecc_get_generated_eccbytes);
++
++int atmel_pmecc_enable(struct atmel_pmecc_user *user, int op)
++{
++	struct atmel_pmecc *pmecc = user->pmecc;
++	u32 cfg;
++
++	if (op != NAND_ECC_READ && op != NAND_ECC_WRITE) {
++		dev_err(pmecc->dev, "Bad ECC operation!");
++		return -EINVAL;
++	}
++
++	mutex_lock(&user->pmecc->lock);
++
++	cfg = user->cache.cfg;
++	if (op == NAND_ECC_WRITE)
++		cfg |= PMECC_CFG_WRITE_OP;
++	else
++		cfg |= PMECC_CFG_AUTO_ENABLE;
++
++	writel(cfg, pmecc->regs.base + ATMEL_PMECC_CFG);
++	writel(user->cache.sarea, pmecc->regs.base + ATMEL_PMECC_SAREA);
++	writel(user->cache.saddr, pmecc->regs.base + ATMEL_PMECC_SADDR);
++	writel(user->cache.eaddr, pmecc->regs.base + ATMEL_PMECC_EADDR);
++
++	writel(PMECC_CTRL_ENABLE, pmecc->regs.base + ATMEL_PMECC_CTRL);
++	writel(PMECC_CTRL_DATA, pmecc->regs.base + ATMEL_PMECC_CTRL);
++
++	return 0;
++}
++EXPORT_SYMBOL_GPL(atmel_pmecc_enable);
++
++void atmel_pmecc_disable(struct atmel_pmecc_user *user)
++{
++	struct atmel_pmecc *pmecc = user->pmecc;
++
++	writel(PMECC_CTRL_RST, pmecc->regs.base + ATMEL_PMECC_CTRL);
++	writel(PMECC_CTRL_DISABLE, pmecc->regs.base + ATMEL_PMECC_CTRL);
++	mutex_unlock(&user->pmecc->lock);
++}
++EXPORT_SYMBOL_GPL(atmel_pmecc_disable);
++
++int atmel_pmecc_wait_rdy(struct atmel_pmecc_user *user)
++{
++	struct atmel_pmecc *pmecc = user->pmecc;
++	u32 status;
++	int ret;
++
++	ret = readl_relaxed_poll_timeout(pmecc->regs.base +
++					 ATMEL_PMECC_SR,
++					 status, !(status & PMECC_SR_BUSY), 0,
++					 PMECC_MAX_TIMEOUT_MS * 1000);
++	if (ret) {
++		dev_err(pmecc->dev,
++			"Timeout while waiting for PMECC ready.\n");
++		return ret;
++	}
++
++	user->isr = readl_relaxed(pmecc->regs.base + ATMEL_PMECC_ISR);
++
++	return 0;
++}
++EXPORT_SYMBOL_GPL(atmel_pmecc_wait_rdy);
++
++static struct atmel_pmecc *atmel_pmecc_create(struct platform_device *pdev,
++					const struct atmel_pmecc_caps *caps,
++					int pmecc_res_idx, int errloc_res_idx)
++{
++	struct device *dev = &pdev->dev;
++	struct atmel_pmecc *pmecc;
++	struct resource *res;
++
++	pmecc = devm_kzalloc(dev, sizeof(*pmecc), GFP_KERNEL);
++	if (!pmecc)
++		return ERR_PTR(-ENOMEM);
++
++	pmecc->caps = caps;
++	pmecc->dev = dev;
++	mutex_init(&pmecc->lock);
++
++	res = platform_get_resource(pdev, IORESOURCE_MEM, pmecc_res_idx);
++	pmecc->regs.base = devm_ioremap_resource(dev, res);
++	if (IS_ERR(pmecc->regs.base))
++		return ERR_CAST(pmecc->regs.base);
++
++	res = platform_get_resource(pdev, IORESOURCE_MEM, errloc_res_idx);
++	pmecc->regs.errloc = devm_ioremap_resource(dev, res);
++	if (IS_ERR(pmecc->regs.errloc))
++		return ERR_CAST(pmecc->regs.errloc);
++
++	/* Disable all interrupts before registering the PMECC handler. */
++	writel(0xffffffff, pmecc->regs.base + ATMEL_PMECC_IDR);
++
++	/* Reset the ECC engine */
++	writel(PMECC_CTRL_RST, pmecc->regs.base + ATMEL_PMECC_CTRL);
++	writel(PMECC_CTRL_DISABLE, pmecc->regs.base + ATMEL_PMECC_CTRL);
++
++	return pmecc;
++}
++
++static void devm_atmel_pmecc_put(struct device *dev, void *res)
++{
++	struct atmel_pmecc **pmecc = res;
++
++	put_device((*pmecc)->dev);
++}
++
++static struct atmel_pmecc *atmel_pmecc_get_by_node(struct device *userdev,
++						   struct device_node *np)
++{
++	struct platform_device *pdev;
++	struct atmel_pmecc *pmecc, **ptr;
++
++	pdev = of_find_device_by_node(np);
++	if (!pdev || !platform_get_drvdata(pdev))
++		return ERR_PTR(-EPROBE_DEFER);
++
++	ptr = devres_alloc(devm_atmel_pmecc_put, sizeof(*ptr), GFP_KERNEL);
++	if (!ptr)
++		return ERR_PTR(-ENOMEM);
++
++	get_device(&pdev->dev);
++	pmecc = platform_get_drvdata(pdev);
++
++	*ptr = pmecc;
++
++	devres_add(userdev, ptr);
++
++	return pmecc;
++}
++
++static const int atmel_pmecc_strengths[] = { 2, 4, 8, 12, 24, 32 };
++
++static struct atmel_pmecc_caps at91sam9g45_caps = {
++	.strengths = atmel_pmecc_strengths,
++	.nstrengths = 5,
++	.el_offset = 0x8c,
++};
++
++static struct atmel_pmecc_caps sama5d4_caps = {
++	.strengths = atmel_pmecc_strengths,
++	.nstrengths = 5,
++	.el_offset = 0x8c,
++	.correct_erased_chunks = true,
++};
++
++static struct atmel_pmecc_caps sama5d2_caps = {
++	.strengths = atmel_pmecc_strengths,
++	.nstrengths = 6,
++	.el_offset = 0xac,
++	.correct_erased_chunks = true,
++};
++
++static const struct of_device_id atmel_pmecc_legacy_match[] = {
++	{ .compatible = "atmel,sama5d4-nand", &sama5d4_caps },
++	{ .compatible = "atmel,sama5d2-nand", &sama5d2_caps },
++	{ /* sentinel */ }
++};
++
++struct atmel_pmecc *devm_atmel_pmecc_get(struct device *userdev)
++{
++	struct atmel_pmecc *pmecc;
++	struct device_node *np;
++
++	if (!userdev)
++		return ERR_PTR(-EINVAL);
++
++	if (!userdev->of_node)
++		return NULL;
++
++	np = of_parse_phandle(userdev->of_node, "ecc-engine", 0);
++	if (np) {
++		pmecc = atmel_pmecc_get_by_node(userdev, np);
++		of_node_put(np);
++	} else {
++		/*
++		 * Support old DT bindings: in this case the PMECC iomem
++		 * resources are directly defined in the user pdev at position
++		 * 1 and 2. Extract all relevant information from there.
++		 */
++		struct platform_device *pdev = to_platform_device(userdev);
++		const struct atmel_pmecc_caps *caps;
++		const struct of_device_id *match;
++
++		/* No PMECC engine available. */
++		if (!of_property_read_bool(userdev->of_node,
++					   "atmel,has-pmecc"))
++			return NULL;
++
++		caps = &at91sam9g45_caps;
++
++		/* Find the caps associated to the NAND dev node. */
++		match = of_match_node(atmel_pmecc_legacy_match,
++				      userdev->of_node);
++		if (match && match->data)
++			caps = match->data;
++
++		pmecc = atmel_pmecc_create(pdev, caps, 1, 2);
++	}
++
++	return pmecc;
++}
++EXPORT_SYMBOL(devm_atmel_pmecc_get);
++
++static const struct of_device_id atmel_pmecc_match[] = {
++	{ .compatible = "atmel,at91sam9g45-pmecc", &at91sam9g45_caps },
++	{ .compatible = "atmel,sama5d4-pmecc", &sama5d4_caps },
++	{ .compatible = "atmel,sama5d2-pmecc", &sama5d2_caps },
++	{ /* sentinel */ }
++};
++MODULE_DEVICE_TABLE(of, atmel_pmecc_match);
++
++static int atmel_pmecc_probe(struct platform_device *pdev)
++{
++	struct device *dev = &pdev->dev;
++	const struct atmel_pmecc_caps *caps;
++	struct atmel_pmecc *pmecc;
++
++	caps = of_device_get_match_data(&pdev->dev);
++	if (!caps) {
++		dev_err(dev, "Invalid caps\n");
++		return -EINVAL;
++	}
++
++	pmecc = atmel_pmecc_create(pdev, caps, 0, 1);
++	if (IS_ERR(pmecc))
++		return PTR_ERR(pmecc);
++
++	platform_set_drvdata(pdev, pmecc);
++
++	return 0;
++}
++
++static struct platform_driver atmel_pmecc_driver = {
++	.driver = {
++		.name = "atmel-pmecc",
++		.of_match_table = of_match_ptr(atmel_pmecc_match),
++	},
++	.probe = atmel_pmecc_probe,
++};
++module_platform_driver(atmel_pmecc_driver);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Boris Brezillon <boris.brezillon@free-electrons.com>");
++MODULE_DESCRIPTION("PMECC engine driver");
++MODULE_ALIAS("platform:atmel_pmecc");
+diff --git a/drivers/mtd/nand/raw/atmel/pmecc.h b/drivers/mtd/nand/raw/atmel/pmecc.h
+new file mode 100644
+index 0000000..a8ddbfc
+--- /dev/null
++++ b/drivers/mtd/nand/raw/atmel/pmecc.h
+@@ -0,0 +1,73 @@
++/*
++ * © Copyright 2016 ATMEL
++ * © Copyright 2016 Free Electrons
++ *
++ * Author: Boris Brezillon <boris.brezillon@free-electrons.com>
++ *
++ * Derived from the atmel_nand.c driver which contained the following
++ * copyrights:
++ *
++ *    Copyright © 2003 Rick Bronson
++ *
++ *    Derived from drivers/mtd/nand/autcpu12.c
++ *        Copyright © 2001 Thomas Gleixner (gleixner@autronix.de)
++ *
++ *    Derived from drivers/mtd/spia.c
++ *        Copyright © 2000 Steven J. Hill (sjhill@cotw.com)
++ *
++ *
++ *    Add Hardware ECC support for AT91SAM9260 / AT91SAM9263
++ *        Richard Genoud (richard.genoud@gmail.com), Adeneo Copyright © 2007
++ *
++ *        Derived from Das U-Boot source code
++ *              (u-boot-1.1.5/board/atmel/at91sam9263ek/nand.c)
++ *        © Copyright 2006 ATMEL Rousset, Lacressonniere Nicolas
++ *
++ *    Add Programmable Multibit ECC support for various AT91 SoC
++ *        © Copyright 2012 ATMEL, Hong Xu
++ *
++ *    Add Nand Flash Controller support for SAMA5 SoC
++ *        © Copyright 2013 ATMEL, Josh Wu (josh.wu@atmel.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 ATMEL_PMECC_H
++#define ATMEL_PMECC_H
++
++#define ATMEL_PMECC_MAXIMIZE_ECC_STRENGTH	0
++#define ATMEL_PMECC_SECTOR_SIZE_AUTO		0
++#define ATMEL_PMECC_OOBOFFSET_AUTO		-1
++
++struct atmel_pmecc_user_req {
++	int pagesize;
++	int oobsize;
++	struct {
++		int strength;
++		int bytes;
++		int sectorsize;
++		int nsectors;
++		int ooboffset;
++	} ecc;
++};
++
++struct atmel_pmecc *devm_atmel_pmecc_get(struct device *dev);
++
++struct atmel_pmecc_user *
++atmel_pmecc_create_user(struct atmel_pmecc *pmecc,
++			struct atmel_pmecc_user_req *req);
++void atmel_pmecc_destroy_user(struct atmel_pmecc_user *user);
++
++int atmel_pmecc_enable(struct atmel_pmecc_user *user, int op);
++void atmel_pmecc_disable(struct atmel_pmecc_user *user);
++int atmel_pmecc_wait_rdy(struct atmel_pmecc_user *user);
++int atmel_pmecc_correct_sector(struct atmel_pmecc_user *user, int sector,
++			       void *data, void *ecc);
++bool atmel_pmecc_correct_erased_chunks(struct atmel_pmecc_user *user);
++void atmel_pmecc_get_generated_eccbytes(struct atmel_pmecc_user *user,
++					int sector, void *ecc);
++
++#endif /* ATMEL_PMECC_H */
+diff --git a/drivers/mtd/nand/raw/au1550nd.c b/drivers/mtd/nand/raw/au1550nd.c
+new file mode 100644
+index 0000000..9d4a28f
+--- /dev/null
++++ b/drivers/mtd/nand/raw/au1550nd.c
+@@ -0,0 +1,518 @@
++/*
++ *  drivers/mtd/nand/au1550nd.c
++ *
++ *  Copyright (C) 2004 Embedded Edge, LLC
++ *
++ * 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/slab.h>
++#include <linux/gpio.h>
++#include <linux/module.h>
++#include <linux/interrupt.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/rawnand.h>
++#include <linux/mtd/partitions.h>
++#include <linux/platform_device.h>
++#include <asm/io.h>
++#include <asm/mach-au1x00/au1000.h>
++#include <asm/mach-au1x00/au1550nd.h>
++
++
++struct au1550nd_ctx {
++	struct nand_chip chip;
++
++	int cs;
++	void __iomem *base;
++	void (*write_byte)(struct mtd_info *, u_char);
++};
++
++/**
++ * au_read_byte -  read one byte from the chip
++ * @mtd:	MTD device structure
++ *
++ * read function for 8bit buswidth
++ */
++static u_char au_read_byte(struct mtd_info *mtd)
++{
++	struct nand_chip *this = mtd_to_nand(mtd);
++	u_char ret = readb(this->IO_ADDR_R);
++	wmb(); /* drain writebuffer */
++	return ret;
++}
++
++/**
++ * au_write_byte -  write one byte to the chip
++ * @mtd:	MTD device structure
++ * @byte:	pointer to data byte to write
++ *
++ * write function for 8it buswidth
++ */
++static void au_write_byte(struct mtd_info *mtd, u_char byte)
++{
++	struct nand_chip *this = mtd_to_nand(mtd);
++	writeb(byte, this->IO_ADDR_W);
++	wmb(); /* drain writebuffer */
++}
++
++/**
++ * au_read_byte16 -  read one byte endianness aware from the chip
++ * @mtd:	MTD device structure
++ *
++ * read function for 16bit buswidth with endianness conversion
++ */
++static u_char au_read_byte16(struct mtd_info *mtd)
++{
++	struct nand_chip *this = mtd_to_nand(mtd);
++	u_char ret = (u_char) cpu_to_le16(readw(this->IO_ADDR_R));
++	wmb(); /* drain writebuffer */
++	return ret;
++}
++
++/**
++ * au_write_byte16 -  write one byte endianness aware to the chip
++ * @mtd:	MTD device structure
++ * @byte:	pointer to data byte to write
++ *
++ * write function for 16bit buswidth with endianness conversion
++ */
++static void au_write_byte16(struct mtd_info *mtd, u_char byte)
++{
++	struct nand_chip *this = mtd_to_nand(mtd);
++	writew(le16_to_cpu((u16) byte), this->IO_ADDR_W);
++	wmb(); /* drain writebuffer */
++}
++
++/**
++ * au_read_word -  read one word from the chip
++ * @mtd:	MTD device structure
++ *
++ * read function for 16bit buswidth without endianness conversion
++ */
++static u16 au_read_word(struct mtd_info *mtd)
++{
++	struct nand_chip *this = mtd_to_nand(mtd);
++	u16 ret = readw(this->IO_ADDR_R);
++	wmb(); /* drain writebuffer */
++	return ret;
++}
++
++/**
++ * au_write_buf -  write buffer to chip
++ * @mtd:	MTD device structure
++ * @buf:	data buffer
++ * @len:	number of bytes to write
++ *
++ * write function for 8bit buswidth
++ */
++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);
++
++	for (i = 0; i < len; i++) {
++		writeb(buf[i], this->IO_ADDR_W);
++		wmb(); /* drain writebuffer */
++	}
++}
++
++/**
++ * au_read_buf -  read chip data into buffer
++ * @mtd:	MTD device structure
++ * @buf:	buffer to store date
++ * @len:	number of bytes to read
++ *
++ * read function for 8bit buswidth
++ */
++static void au_read_buf(struct mtd_info *mtd, u_char *buf, int len)
++{
++	int i;
++	struct nand_chip *this = mtd_to_nand(mtd);
++
++	for (i = 0; i < len; i++) {
++		buf[i] = readb(this->IO_ADDR_R);
++		wmb(); /* drain writebuffer */
++	}
++}
++
++/**
++ * au_write_buf16 -  write buffer to chip
++ * @mtd:	MTD device structure
++ * @buf:	data buffer
++ * @len:	number of bytes to write
++ *
++ * write function for 16bit buswidth
++ */
++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);
++	u16 *p = (u16 *) buf;
++	len >>= 1;
++
++	for (i = 0; i < len; i++) {
++		writew(p[i], this->IO_ADDR_W);
++		wmb(); /* drain writebuffer */
++	}
++
++}
++
++/**
++ * au_read_buf16 -  read chip data into buffer
++ * @mtd:	MTD device structure
++ * @buf:	buffer to store date
++ * @len:	number of bytes to read
++ *
++ * read function for 16bit buswidth
++ */
++static void au_read_buf16(struct mtd_info *mtd, u_char *buf, int len)
++{
++	int i;
++	struct nand_chip *this = mtd_to_nand(mtd);
++	u16 *p = (u16 *) buf;
++	len >>= 1;
++
++	for (i = 0; i < len; i++) {
++		p[i] = readw(this->IO_ADDR_R);
++		wmb(); /* drain writebuffer */
++	}
++}
++
++/* Select the chip by setting nCE to low */
++#define NAND_CTL_SETNCE		1
++/* Deselect the chip by setting nCE to high */
++#define NAND_CTL_CLRNCE		2
++/* Select the command latch by setting CLE to high */
++#define NAND_CTL_SETCLE		3
++/* Deselect the command latch by setting CLE to low */
++#define NAND_CTL_CLRCLE		4
++/* Select the address latch by setting ALE to high */
++#define NAND_CTL_SETALE		5
++/* Deselect the address latch by setting ALE to low */
++#define NAND_CTL_CLRALE		6
++
++static void au1550_hwcontrol(struct mtd_info *mtd, int cmd)
++{
++	struct nand_chip *this = mtd_to_nand(mtd);
++	struct au1550nd_ctx *ctx = container_of(this, struct au1550nd_ctx,
++						chip);
++
++	switch (cmd) {
++
++	case NAND_CTL_SETCLE:
++		this->IO_ADDR_W = ctx->base + MEM_STNAND_CMD;
++		break;
++
++	case NAND_CTL_CLRCLE:
++		this->IO_ADDR_W = ctx->base + MEM_STNAND_DATA;
++		break;
++
++	case NAND_CTL_SETALE:
++		this->IO_ADDR_W = ctx->base + MEM_STNAND_ADDR;
++		break;
++
++	case NAND_CTL_CLRALE:
++		this->IO_ADDR_W = ctx->base + MEM_STNAND_DATA;
++		/* FIXME: Nobody knows why this is necessary,
++		 * but it works only that way */
++		udelay(1);
++		break;
++
++	case NAND_CTL_SETNCE:
++		/* assert (force assert) chip enable */
++		alchemy_wrsmem((1 << (4 + ctx->cs)), AU1000_MEM_STNDCTL);
++		break;
++
++	case NAND_CTL_CLRNCE:
++		/* deassert chip enable */
++		alchemy_wrsmem(0, AU1000_MEM_STNDCTL);
++		break;
++	}
++
++	this->IO_ADDR_R = this->IO_ADDR_W;
++
++	wmb(); /* Drain the writebuffer */
++}
++
++int au1550_device_ready(struct mtd_info *mtd)
++{
++	return (alchemy_rdsmem(AU1000_MEM_STSTAT) & 0x1) ? 1 : 0;
++}
++
++/**
++ * au1550_select_chip - control -CE line
++ *	Forbid driving -CE manually permitting the NAND controller to do this.
++ *	Keeping -CE asserted during the whole sector reads interferes with the
++ *	NOR flash and PCMCIA drivers as it causes contention on the static bus.
++ *	We only have to hold -CE low for the NAND read commands since the flash
++ *	chip needs it to be asserted during chip not ready time but the NAND
++ *	controller keeps it released.
++ *
++ * @mtd:	MTD device structure
++ * @chip:	chipnumber to select, -1 for deselect
++ */
++static void au1550_select_chip(struct mtd_info *mtd, int chip)
++{
++}
++
++/**
++ * au1550_command - Send command to NAND device
++ * @mtd:	MTD device structure
++ * @command:	the command to be sent
++ * @column:	the column address for this command, -1 if none
++ * @page_addr:	the page address for this command, -1 if none
++ */
++static void au1550_command(struct mtd_info *mtd, unsigned command, int column, int page_addr)
++{
++	struct nand_chip *this = mtd_to_nand(mtd);
++	struct au1550nd_ctx *ctx = container_of(this, struct au1550nd_ctx,
++						chip);
++	int ce_override = 0, i;
++	unsigned long flags = 0;
++
++	/* Begin command latch cycle */
++	au1550_hwcontrol(mtd, NAND_CTL_SETCLE);
++	/*
++	 * Write out the command to the device.
++	 */
++	if (command == NAND_CMD_SEQIN) {
++		int readcmd;
++
++		if (column >= mtd->writesize) {
++			/* OOB area */
++			column -= mtd->writesize;
++			readcmd = NAND_CMD_READOOB;
++		} else if (column < 256) {
++			/* First 256 bytes --> READ0 */
++			readcmd = NAND_CMD_READ0;
++		} else {
++			column -= 256;
++			readcmd = NAND_CMD_READ1;
++		}
++		ctx->write_byte(mtd, readcmd);
++	}
++	ctx->write_byte(mtd, command);
++
++	/* Set ALE and clear CLE to start address cycle */
++	au1550_hwcontrol(mtd, NAND_CTL_CLRCLE);
++
++	if (column != -1 || page_addr != -1) {
++		au1550_hwcontrol(mtd, NAND_CTL_SETALE);
++
++		/* Serially input address */
++		if (column != -1) {
++			/* Adjust columns for 16 bit buswidth */
++			if (this->options & NAND_BUSWIDTH_16 &&
++					!nand_opcode_8bits(command))
++				column >>= 1;
++			ctx->write_byte(mtd, column);
++		}
++		if (page_addr != -1) {
++			ctx->write_byte(mtd, (u8)(page_addr & 0xff));
++
++			if (command == NAND_CMD_READ0 ||
++			    command == NAND_CMD_READ1 ||
++			    command == NAND_CMD_READOOB) {
++				/*
++				 * NAND controller will release -CE after
++				 * the last address byte is written, so we'll
++				 * have to forcibly assert it. No interrupts
++				 * are allowed while we do this as we don't
++				 * want the NOR flash or PCMCIA drivers to
++				 * steal our precious bytes of data...
++				 */
++				ce_override = 1;
++				local_irq_save(flags);
++				au1550_hwcontrol(mtd, NAND_CTL_SETNCE);
++			}
++
++			ctx->write_byte(mtd, (u8)(page_addr >> 8));
++
++			/* One more address cycle for devices > 32MiB */
++			if (this->chipsize > (32 << 20))
++				ctx->write_byte(mtd,
++						((page_addr >> 16) & 0x0f));
++		}
++		/* Latch in address */
++		au1550_hwcontrol(mtd, NAND_CTL_CLRALE);
++	}
++
++	/*
++	 * Program and erase have their own busy handlers.
++	 * Status and sequential in need no delay.
++	 */
++	switch (command) {
++
++	case NAND_CMD_PAGEPROG:
++	case NAND_CMD_ERASE1:
++	case NAND_CMD_ERASE2:
++	case NAND_CMD_SEQIN:
++	case NAND_CMD_STATUS:
++		return;
++
++	case NAND_CMD_RESET:
++		break;
++
++	case NAND_CMD_READ0:
++	case NAND_CMD_READ1:
++	case NAND_CMD_READOOB:
++		/* Check if we're really driving -CE low (just in case) */
++		if (unlikely(!ce_override))
++			break;
++
++		/* Apply a short delay always to ensure that we do wait tWB. */
++		ndelay(100);
++		/* Wait for a chip to become ready... */
++		for (i = this->chip_delay; !this->dev_ready(mtd) && i > 0; --i)
++			udelay(1);
++
++		/* Release -CE and re-enable interrupts. */
++		au1550_hwcontrol(mtd, NAND_CTL_CLRNCE);
++		local_irq_restore(flags);
++		return;
++	}
++	/* Apply this short delay always to ensure that we do wait tWB. */
++	ndelay(100);
++
++	while(!this->dev_ready(mtd));
++}
++
++static int find_nand_cs(unsigned long nand_base)
++{
++	void __iomem *base =
++			(void __iomem *)KSEG1ADDR(AU1000_STATIC_MEM_PHYS_ADDR);
++	unsigned long addr, staddr, start, mask, end;
++	int i;
++
++	for (i = 0; i < 4; i++) {
++		addr = 0x1000 + (i * 0x10);			/* CSx */
++		staddr = __raw_readl(base + addr + 0x08);	/* STADDRx */
++		/* figure out the decoded range of this CS */
++		start = (staddr << 4) & 0xfffc0000;
++		mask = (staddr << 18) & 0xfffc0000;
++		end = (start | (start - 1)) & ~(start ^ mask);
++		if ((nand_base >= start) && (nand_base < end))
++			return i;
++	}
++
++	return -ENODEV;
++}
++
++static int au1550nd_probe(struct platform_device *pdev)
++{
++	struct au1550nd_platdata *pd;
++	struct au1550nd_ctx *ctx;
++	struct nand_chip *this;
++	struct mtd_info *mtd;
++	struct resource *r;
++	int ret, cs;
++
++	pd = dev_get_platdata(&pdev->dev);
++	if (!pd) {
++		dev_err(&pdev->dev, "missing platform data\n");
++		return -ENODEV;
++	}
++
++	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
++	if (!ctx)
++		return -ENOMEM;
++
++	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	if (!r) {
++		dev_err(&pdev->dev, "no NAND memory resource\n");
++		ret = -ENODEV;
++		goto out1;
++	}
++	if (request_mem_region(r->start, resource_size(r), "au1550-nand")) {
++		dev_err(&pdev->dev, "cannot claim NAND memory area\n");
++		ret = -ENOMEM;
++		goto out1;
++	}
++
++	ctx->base = ioremap_nocache(r->start, 0x1000);
++	if (!ctx->base) {
++		dev_err(&pdev->dev, "cannot remap NAND memory area\n");
++		ret = -ENODEV;
++		goto out2;
++	}
++
++	this = &ctx->chip;
++	mtd = nand_to_mtd(this);
++	mtd->dev.parent = &pdev->dev;
++
++	/* figure out which CS# r->start belongs to */
++	cs = find_nand_cs(r->start);
++	if (cs < 0) {
++		dev_err(&pdev->dev, "cannot detect NAND chipselect\n");
++		ret = -ENODEV;
++		goto out3;
++	}
++	ctx->cs = cs;
++
++	this->dev_ready = au1550_device_ready;
++	this->select_chip = au1550_select_chip;
++	this->cmdfunc = au1550_command;
++
++	/* 30 us command delay time */
++	this->chip_delay = 30;
++	this->ecc.mode = NAND_ECC_SOFT;
++	this->ecc.algo = NAND_ECC_HAMMING;
++
++	if (pd->devwidth)
++		this->options |= NAND_BUSWIDTH_16;
++
++	this->read_byte = (pd->devwidth) ? au_read_byte16 : au_read_byte;
++	ctx->write_byte = (pd->devwidth) ? au_write_byte16 : au_write_byte;
++	this->read_word = au_read_word;
++	this->write_buf = (pd->devwidth) ? au_write_buf16 : au_write_buf;
++	this->read_buf = (pd->devwidth) ? au_read_buf16 : au_read_buf;
++
++	ret = nand_scan(mtd, 1);
++	if (ret) {
++		dev_err(&pdev->dev, "NAND scan failed with %d\n", ret);
++		goto out3;
++	}
++
++	mtd_device_register(mtd, pd->parts, pd->num_parts);
++
++	platform_set_drvdata(pdev, ctx);
++
++	return 0;
++
++out3:
++	iounmap(ctx->base);
++out2:
++	release_mem_region(r->start, resource_size(r));
++out1:
++	kfree(ctx);
++	return ret;
++}
++
++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));
++	iounmap(ctx->base);
++	release_mem_region(r->start, 0x1000);
++	kfree(ctx);
++	return 0;
++}
++
++static struct platform_driver au1550nd_driver = {
++	.driver = {
++		.name	= "au1550-nand",
++	},
++	.probe		= au1550nd_probe,
++	.remove		= au1550nd_remove,
++};
++
++module_platform_driver(au1550nd_driver);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Embedded Edge, LLC");
++MODULE_DESCRIPTION("Board-specific glue layer for NAND flash on Pb1550 board");
+diff --git a/drivers/mtd/nand/raw/bcm47xxnflash/Makefile b/drivers/mtd/nand/raw/bcm47xxnflash/Makefile
+new file mode 100644
+index 0000000..f05b119
+--- /dev/null
++++ b/drivers/mtd/nand/raw/bcm47xxnflash/Makefile
+@@ -0,0 +1,4 @@
++bcm47xxnflash-y				+= main.o
++bcm47xxnflash-y				+= ops_bcm4706.o
++
++obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH)	+= bcm47xxnflash.o
+diff --git a/drivers/mtd/nand/raw/bcm47xxnflash/bcm47xxnflash.h b/drivers/mtd/nand/raw/bcm47xxnflash/bcm47xxnflash.h
+new file mode 100644
+index 0000000..201b9baa
+--- /dev/null
++++ b/drivers/mtd/nand/raw/bcm47xxnflash/bcm47xxnflash.h
+@@ -0,0 +1,26 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++#ifndef __BCM47XXNFLASH_H
++#define __BCM47XXNFLASH_H
++
++#ifndef pr_fmt
++#define pr_fmt(fmt)		KBUILD_MODNAME ": " fmt
++#endif
++
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/rawnand.h>
++
++struct bcm47xxnflash {
++	struct bcma_drv_cc *cc;
++
++	struct nand_chip nand_chip;
++
++	unsigned curr_command;
++	int curr_page_addr;
++	int curr_column;
++
++	u8 id_data[8];
++};
++
++int bcm47xxnflash_ops_bcm4706_init(struct bcm47xxnflash *b47n);
++
++#endif /* BCM47XXNFLASH */
+diff --git a/drivers/mtd/nand/raw/bcm47xxnflash/main.c b/drivers/mtd/nand/raw/bcm47xxnflash/main.c
+new file mode 100644
+index 0000000..fb31429
+--- /dev/null
++++ b/drivers/mtd/nand/raw/bcm47xxnflash/main.c
+@@ -0,0 +1,81 @@
++/*
++ * BCM47XX NAND flash driver
++ *
++ * Copyright (C) 2012 Rafał Miłecki <zajec5@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 "bcm47xxnflash.h"
++
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/platform_device.h>
++#include <linux/bcma/bcma.h>
++
++MODULE_DESCRIPTION("NAND flash driver for BCMA bus");
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Rafał Miłecki");
++
++static const char *probes[] = { "bcm47xxpart", NULL };
++
++static int bcm47xxnflash_probe(struct platform_device *pdev)
++{
++	struct bcma_nflash *nflash = dev_get_platdata(&pdev->dev);
++	struct bcm47xxnflash *b47n;
++	struct mtd_info *mtd;
++	int err = 0;
++
++	b47n = devm_kzalloc(&pdev->dev, sizeof(*b47n), GFP_KERNEL);
++	if (!b47n)
++		return -ENOMEM;
++
++	nand_set_controller_data(&b47n->nand_chip, b47n);
++	mtd = nand_to_mtd(&b47n->nand_chip);
++	mtd->dev.parent = &pdev->dev;
++	b47n->cc = container_of(nflash, struct bcma_drv_cc, nflash);
++
++	if (b47n->cc->core->bus->chipinfo.id == BCMA_CHIP_ID_BCM4706) {
++		err = bcm47xxnflash_ops_bcm4706_init(b47n);
++	} else {
++		pr_err("Device not supported\n");
++		err = -ENOTSUPP;
++	}
++	if (err) {
++		pr_err("Initialization failed: %d\n", err);
++		return err;
++	}
++
++	platform_set_drvdata(pdev, b47n);
++
++	err = mtd_device_parse_register(mtd, probes, NULL, NULL, 0);
++	if (err) {
++		pr_err("Failed to register MTD device: %d\n", err);
++		return err;
++	}
++
++	return 0;
++}
++
++static int bcm47xxnflash_remove(struct platform_device *pdev)
++{
++	struct bcm47xxnflash *nflash = platform_get_drvdata(pdev);
++
++	nand_release(nand_to_mtd(&nflash->nand_chip));
++
++	return 0;
++}
++
++static struct platform_driver bcm47xxnflash_driver = {
++	.probe	= bcm47xxnflash_probe,
++	.remove = bcm47xxnflash_remove,
++	.driver = {
++		.name = "bcma_nflash",
++	},
++};
++
++module_platform_driver(bcm47xxnflash_driver);
+diff --git a/drivers/mtd/nand/raw/bcm47xxnflash/ops_bcm4706.c b/drivers/mtd/nand/raw/bcm47xxnflash/ops_bcm4706.c
+new file mode 100644
+index 0000000..54bac5b
+--- /dev/null
++++ b/drivers/mtd/nand/raw/bcm47xxnflash/ops_bcm4706.c
+@@ -0,0 +1,456 @@
++/*
++ * BCM47XX NAND flash driver
++ *
++ * Copyright (C) 2012 Rafał Miłecki <zajec5@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 "bcm47xxnflash.h"
++
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/delay.h>
++#include <linux/bcma/bcma.h>
++
++/* Broadcom uses 1'000'000 but it seems to be too many. Tests on WNDR4500 has
++ * shown ~1000 retries as maxiumum. */
++#define NFLASH_READY_RETRIES		10000
++
++#define NFLASH_SECTOR_SIZE		512
++
++#define NCTL_CMD0			0x00010000
++#define NCTL_COL			0x00020000	/* Update column with value from BCMA_CC_NFLASH_COL_ADDR */
++#define NCTL_ROW			0x00040000	/* Update row (page) with value from BCMA_CC_NFLASH_ROW_ADDR */
++#define NCTL_CMD1W			0x00080000
++#define NCTL_READ			0x00100000
++#define NCTL_WRITE			0x00200000
++#define NCTL_SPECADDR			0x01000000
++#define NCTL_READY			0x04000000
++#define NCTL_ERR			0x08000000
++#define NCTL_CSA			0x40000000
++#define NCTL_START			0x80000000
++
++/**************************************************
++ * Various helpers
++ **************************************************/
++
++static inline u8 bcm47xxnflash_ops_bcm4706_ns_to_cycle(u16 ns, u16 clock)
++{
++	return ((ns * 1000 * clock) / 1000000) + 1;
++}
++
++static int bcm47xxnflash_ops_bcm4706_ctl_cmd(struct bcma_drv_cc *cc, u32 code)
++{
++	int i = 0;
++
++	bcma_cc_write32(cc, BCMA_CC_NFLASH_CTL, NCTL_START | code);
++	for (i = 0; i < NFLASH_READY_RETRIES; i++) {
++		if (!(bcma_cc_read32(cc, BCMA_CC_NFLASH_CTL) & NCTL_START)) {
++			i = 0;
++			break;
++		}
++	}
++	if (i) {
++		pr_err("NFLASH control command not ready!\n");
++		return -EBUSY;
++	}
++	return 0;
++}
++
++static int bcm47xxnflash_ops_bcm4706_poll(struct bcma_drv_cc *cc)
++{
++	int i;
++
++	for (i = 0; i < NFLASH_READY_RETRIES; i++) {
++		if (bcma_cc_read32(cc, BCMA_CC_NFLASH_CTL) & NCTL_READY) {
++			if (bcma_cc_read32(cc, BCMA_CC_NFLASH_CTL) &
++			    BCMA_CC_NFLASH_CTL_ERR) {
++				pr_err("Error on polling\n");
++				return -EBUSY;
++			} else {
++				return 0;
++			}
++		}
++	}
++
++	pr_err("Polling timeout!\n");
++	return -EBUSY;
++}
++
++/**************************************************
++ * R/W
++ **************************************************/
++
++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 bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
++
++	u32 ctlcode;
++	u32 *dest = (u32 *)buf;
++	int i;
++	int toread;
++
++	BUG_ON(b47n->curr_page_addr & ~nand_chip->pagemask);
++	/* Don't validate column using nand_chip->page_shift, it may be bigger
++	 * when accessing OOB */
++
++	while (len) {
++		/* We can read maximum of 0x200 bytes at once */
++		toread = min(len, 0x200);
++
++		/* Set page and column */
++		bcma_cc_write32(b47n->cc, BCMA_CC_NFLASH_COL_ADDR,
++				b47n->curr_column);
++		bcma_cc_write32(b47n->cc, BCMA_CC_NFLASH_ROW_ADDR,
++				b47n->curr_page_addr);
++
++		/* Prepare to read */
++		ctlcode = NCTL_CSA | NCTL_CMD1W | NCTL_ROW | NCTL_COL |
++			  NCTL_CMD0;
++		ctlcode |= NAND_CMD_READSTART << 8;
++		if (bcm47xxnflash_ops_bcm4706_ctl_cmd(b47n->cc, ctlcode))
++			return;
++		if (bcm47xxnflash_ops_bcm4706_poll(b47n->cc))
++			return;
++
++		/* Eventually read some data :) */
++		for (i = 0; i < toread; i += 4, dest++) {
++			ctlcode = NCTL_CSA | 0x30000000 | NCTL_READ;
++			if (i == toread - 4) /* Last read goes without that */
++				ctlcode &= ~NCTL_CSA;
++			if (bcm47xxnflash_ops_bcm4706_ctl_cmd(b47n->cc,
++							      ctlcode))
++				return;
++			*dest = bcma_cc_read32(b47n->cc, BCMA_CC_NFLASH_DATA);
++		}
++
++		b47n->curr_column += toread;
++		len -= toread;
++	}
++}
++
++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 bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
++	struct bcma_drv_cc *cc = b47n->cc;
++
++	u32 ctlcode;
++	const u32 *data = (u32 *)buf;
++	int i;
++
++	BUG_ON(b47n->curr_page_addr & ~nand_chip->pagemask);
++	/* Don't validate column using nand_chip->page_shift, it may be bigger
++	 * when accessing OOB */
++
++	for (i = 0; i < len; i += 4, data++) {
++		bcma_cc_write32(cc, BCMA_CC_NFLASH_DATA, *data);
++
++		ctlcode = NCTL_CSA | 0x30000000 | NCTL_WRITE;
++		if (i == len - 4) /* Last read goes without that */
++			ctlcode &= ~NCTL_CSA;
++		if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, ctlcode)) {
++			pr_err("%s ctl_cmd didn't work!\n", __func__);
++			return;
++		}
++	}
++
++	b47n->curr_column += len;
++}
++
++/**************************************************
++ * NAND chip ops
++ **************************************************/
++
++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 bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
++	u32 code = 0;
++
++	if (cmd == NAND_CMD_NONE)
++		return;
++
++	if (cmd & NAND_CTRL_CLE)
++		code = cmd | NCTL_CMD0;
++
++	/* nCS is not needed for reset command */
++	if (cmd != NAND_CMD_RESET)
++		code |= NCTL_CSA;
++
++	bcm47xxnflash_ops_bcm4706_ctl_cmd(b47n->cc, code);
++}
++
++/* Default nand_select_chip calls cmd_ctrl, which is not used in BCM4706 */
++static void bcm47xxnflash_ops_bcm4706_select_chip(struct mtd_info *mtd,
++						  int chip)
++{
++	return;
++}
++
++static int bcm47xxnflash_ops_bcm4706_dev_ready(struct mtd_info *mtd)
++{
++	struct nand_chip *nand_chip = mtd_to_nand(mtd);
++	struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
++
++	return !!(bcma_cc_read32(b47n->cc, BCMA_CC_NFLASH_CTL) & NCTL_READY);
++}
++
++/*
++ * Default nand_command and nand_command_lp don't match BCM4706 hardware layout.
++ * For example, reading chip id is performed in a non-standard way.
++ * Setting column and page is also handled differently, we use a special
++ * registers of ChipCommon core. Hacking cmd_ctrl to understand and convert
++ * standard commands would be much more complicated.
++ */
++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 bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
++	struct bcma_drv_cc *cc = b47n->cc;
++	u32 ctlcode;
++	int i;
++
++	if (column != -1)
++		b47n->curr_column = column;
++	if (page_addr != -1)
++		b47n->curr_page_addr = page_addr;
++
++	switch (command) {
++	case NAND_CMD_RESET:
++		nand_chip->cmd_ctrl(mtd, command, NAND_CTRL_CLE);
++
++		ndelay(100);
++		nand_wait_ready(mtd);
++		break;
++	case NAND_CMD_READID:
++		ctlcode = NCTL_CSA | 0x01000000 | NCTL_CMD1W | NCTL_CMD0;
++		ctlcode |= NAND_CMD_READID;
++		if (bcm47xxnflash_ops_bcm4706_ctl_cmd(b47n->cc, ctlcode)) {
++			pr_err("READID error\n");
++			break;
++		}
++
++		/*
++		 * Reading is specific, last one has to go without NCTL_CSA
++		 * bit. We don't know how many reads NAND subsystem is going
++		 * to perform, so cache everything.
++		 */
++		for (i = 0; i < ARRAY_SIZE(b47n->id_data); i++) {
++			ctlcode = NCTL_CSA | NCTL_READ;
++			if (i == ARRAY_SIZE(b47n->id_data) - 1)
++				ctlcode &= ~NCTL_CSA;
++			if (bcm47xxnflash_ops_bcm4706_ctl_cmd(b47n->cc,
++							      ctlcode)) {
++				pr_err("READID error\n");
++				break;
++			}
++			b47n->id_data[i] =
++				bcma_cc_read32(b47n->cc, BCMA_CC_NFLASH_DATA)
++				& 0xFF;
++		}
++
++		break;
++	case NAND_CMD_STATUS:
++		ctlcode = NCTL_CSA | NCTL_CMD0 | NAND_CMD_STATUS;
++		if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, ctlcode))
++			pr_err("STATUS command error\n");
++		break;
++	case NAND_CMD_READ0:
++		break;
++	case NAND_CMD_READOOB:
++		if (page_addr != -1)
++			b47n->curr_column += mtd->writesize;
++		break;
++	case NAND_CMD_ERASE1:
++		bcma_cc_write32(cc, BCMA_CC_NFLASH_ROW_ADDR,
++				b47n->curr_page_addr);
++		ctlcode = NCTL_ROW | NCTL_CMD1W | NCTL_CMD0 |
++			  NAND_CMD_ERASE1 | (NAND_CMD_ERASE2 << 8);
++		if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, ctlcode))
++			pr_err("ERASE1 failed\n");
++		break;
++	case NAND_CMD_ERASE2:
++		break;
++	case NAND_CMD_SEQIN:
++		/* Set page and column */
++		bcma_cc_write32(cc, BCMA_CC_NFLASH_COL_ADDR,
++				b47n->curr_column);
++		bcma_cc_write32(cc, BCMA_CC_NFLASH_ROW_ADDR,
++				b47n->curr_page_addr);
++
++		/* Prepare to write */
++		ctlcode = 0x40000000 | NCTL_ROW | NCTL_COL | NCTL_CMD0;
++		ctlcode |= NAND_CMD_SEQIN;
++		if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, ctlcode))
++			pr_err("SEQIN failed\n");
++		break;
++	case NAND_CMD_PAGEPROG:
++		if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, NCTL_CMD0 |
++							  NAND_CMD_PAGEPROG))
++			pr_err("PAGEPROG failed\n");
++		if (bcm47xxnflash_ops_bcm4706_poll(cc))
++			pr_err("PAGEPROG not ready\n");
++		break;
++	default:
++		pr_err("Command 0x%X unsupported\n", command);
++		break;
++	}
++	b47n->curr_command = command;
++}
++
++static u8 bcm47xxnflash_ops_bcm4706_read_byte(struct mtd_info *mtd)
++{
++	struct nand_chip *nand_chip = mtd_to_nand(mtd);
++	struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
++	struct bcma_drv_cc *cc = b47n->cc;
++	u32 tmp = 0;
++
++	switch (b47n->curr_command) {
++	case NAND_CMD_READID:
++		if (b47n->curr_column >= ARRAY_SIZE(b47n->id_data)) {
++			pr_err("Requested invalid id_data: %d\n",
++			       b47n->curr_column);
++			return 0;
++		}
++		return b47n->id_data[b47n->curr_column++];
++	case NAND_CMD_STATUS:
++		if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, NCTL_READ))
++			return 0;
++		return bcma_cc_read32(cc, BCMA_CC_NFLASH_DATA) & 0xff;
++	case NAND_CMD_READOOB:
++		bcm47xxnflash_ops_bcm4706_read(mtd, (u8 *)&tmp, 4);
++		return tmp & 0xFF;
++	}
++
++	pr_err("Invalid command for byte read: 0x%X\n", b47n->curr_command);
++	return 0;
++}
++
++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 bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
++
++	switch (b47n->curr_command) {
++	case NAND_CMD_READ0:
++	case NAND_CMD_READOOB:
++		bcm47xxnflash_ops_bcm4706_read(mtd, buf, len);
++		return;
++	}
++
++	pr_err("Invalid command for buf read: 0x%X\n", b47n->curr_command);
++}
++
++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 bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
++
++	switch (b47n->curr_command) {
++	case NAND_CMD_SEQIN:
++		bcm47xxnflash_ops_bcm4706_write(mtd, buf, len);
++		return;
++	}
++
++	pr_err("Invalid command for buf write: 0x%X\n", b47n->curr_command);
++}
++
++/**************************************************
++ * Init
++ **************************************************/
++
++int bcm47xxnflash_ops_bcm4706_init(struct bcm47xxnflash *b47n)
++{
++	struct nand_chip *nand_chip = (struct nand_chip *)&b47n->nand_chip;
++	int err;
++	u32 freq;
++	u16 clock;
++	u8 w0, w1, w2, w3, w4;
++
++	unsigned long chipsize; /* MiB */
++	u8 tbits, col_bits, col_size, row_bits, row_bsize;
++	u32 val;
++
++	b47n->nand_chip.select_chip = bcm47xxnflash_ops_bcm4706_select_chip;
++	nand_chip->cmd_ctrl = bcm47xxnflash_ops_bcm4706_cmd_ctrl;
++	nand_chip->dev_ready = bcm47xxnflash_ops_bcm4706_dev_ready;
++	b47n->nand_chip.cmdfunc = bcm47xxnflash_ops_bcm4706_cmdfunc;
++	b47n->nand_chip.read_byte = bcm47xxnflash_ops_bcm4706_read_byte;
++	b47n->nand_chip.read_buf = bcm47xxnflash_ops_bcm4706_read_buf;
++	b47n->nand_chip.write_buf = bcm47xxnflash_ops_bcm4706_write_buf;
++	b47n->nand_chip.onfi_set_features = nand_onfi_get_set_features_notsupp;
++	b47n->nand_chip.onfi_get_features = nand_onfi_get_set_features_notsupp;
++
++	nand_chip->chip_delay = 50;
++	b47n->nand_chip.bbt_options = NAND_BBT_USE_FLASH;
++	b47n->nand_chip.ecc.mode = NAND_ECC_NONE; /* TODO: implement ECC */
++
++	/* Enable NAND flash access */
++	bcma_cc_set32(b47n->cc, BCMA_CC_4706_FLASHSCFG,
++		      BCMA_CC_4706_FLASHSCFG_NF1);
++
++	/* Configure wait counters */
++	if (b47n->cc->status & BCMA_CC_CHIPST_4706_PKG_OPTION) {
++		/* 400 MHz */
++		freq = 400000000 / 4;
++	} else {
++		freq = bcma_chipco_pll_read(b47n->cc, 4);
++		freq = (freq & 0xFFF) >> 3;
++		/* Fixed reference clock 25 MHz and m = 2 */
++		freq = (freq * 25000000 / 2) / 4;
++	}
++	clock = freq / 1000000;
++	w0 = bcm47xxnflash_ops_bcm4706_ns_to_cycle(15, clock);
++	w1 = bcm47xxnflash_ops_bcm4706_ns_to_cycle(20, clock);
++	w2 = bcm47xxnflash_ops_bcm4706_ns_to_cycle(10, clock);
++	w3 = bcm47xxnflash_ops_bcm4706_ns_to_cycle(10, clock);
++	w4 = bcm47xxnflash_ops_bcm4706_ns_to_cycle(100, clock);
++	bcma_cc_write32(b47n->cc, BCMA_CC_NFLASH_WAITCNT0,
++			(w4 << 24 | w3 << 18 | w2 << 12 | w1 << 6 | w0));
++
++	/* Scan NAND */
++	err = nand_scan(nand_to_mtd(&b47n->nand_chip), 1);
++	if (err) {
++		pr_err("Could not scan NAND flash: %d\n", err);
++		goto exit;
++	}
++
++	/* Configure FLASH */
++	chipsize = b47n->nand_chip.chipsize >> 20;
++	tbits = ffs(chipsize); /* find first bit set */
++	if (!tbits || tbits != fls(chipsize)) {
++		pr_err("Invalid flash size: 0x%lX\n", chipsize);
++		err = -ENOTSUPP;
++		goto exit;
++	}
++	tbits += 19; /* Broadcom increases *index* by 20, we increase *pos* */
++
++	col_bits = b47n->nand_chip.page_shift + 1;
++	col_size = (col_bits + 7) / 8;
++
++	row_bits = tbits - col_bits + 1;
++	row_bsize = (row_bits + 7) / 8;
++
++	val = ((row_bsize - 1) << 6) | ((col_size - 1) << 4) | 2;
++	bcma_cc_write32(b47n->cc, BCMA_CC_NFLASH_CONF, val);
++
++exit:
++	if (err)
++		bcma_cc_mask32(b47n->cc, BCMA_CC_4706_FLASHSCFG,
++			       ~BCMA_CC_4706_FLASHSCFG_NF1);
++	return err;
++}
+diff --git a/drivers/mtd/nand/raw/bf5xx_nand.c b/drivers/mtd/nand/raw/bf5xx_nand.c
+new file mode 100644
+index 0000000..5655dca
+--- /dev/null
++++ b/drivers/mtd/nand/raw/bf5xx_nand.c
+@@ -0,0 +1,860 @@
++/* linux/drivers/mtd/nand/bf5xx_nand.c
++ *
++ * Copyright 2006-2008 Analog Devices Inc.
++ *	http://blackfin.uclinux.org/
++ *	Bryan Wu <bryan.wu@analog.com>
++ *
++ * Blackfin BF5xx on-chip NAND flash controller driver
++ *
++ * Derived from drivers/mtd/nand/s3c2410.c
++ * Copyright (c) 2007 Ben Dooks <ben@simtec.co.uk>
++ *
++ * Derived from drivers/mtd/nand/cafe.c
++ * Copyright © 2006 Red Hat, Inc.
++ * Copyright © 2006 David Woodhouse <dwmw2@infradead.org>
++ *
++ * Changelog:
++ *	12-Jun-2007  Bryan Wu:  Initial version
++ *	18-Jul-2007  Bryan Wu:
++ *		- ECC_HW and ECC_SW supported
++ *		- DMA supported in ECC_HW
++ *		- YAFFS tested as rootfs in both ECC_HW and ECC_SW
++ *
++ * 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.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <linux/string.h>
++#include <linux/ioport.h>
++#include <linux/platform_device.h>
++#include <linux/delay.h>
++#include <linux/dma-mapping.h>
++#include <linux/err.h>
++#include <linux/slab.h>
++#include <linux/io.h>
++#include <linux/bitops.h>
++
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/rawnand.h>
++#include <linux/mtd/nand_ecc.h>
++#include <linux/mtd/partitions.h>
++
++#include <asm/blackfin.h>
++#include <asm/dma.h>
++#include <asm/cacheflush.h>
++#include <asm/nand.h>
++#include <asm/portmux.h>
++
++#define DRV_NAME	"bf5xx-nand"
++#define DRV_VERSION	"1.2"
++#define DRV_AUTHOR	"Bryan Wu <bryan.wu@analog.com>"
++#define DRV_DESC	"BF5xx on-chip NAND FLash Controller Driver"
++
++/* NFC_STAT Masks */
++#define NBUSY       0x01  /* Not Busy */
++#define WB_FULL     0x02  /* Write Buffer Full */
++#define PG_WR_STAT  0x04  /* Page Write Pending */
++#define PG_RD_STAT  0x08  /* Page Read Pending */
++#define WB_EMPTY    0x10  /* Write Buffer Empty */
++
++/* NFC_IRQSTAT Masks */
++#define NBUSYIRQ    0x01  /* Not Busy IRQ */
++#define WB_OVF      0x02  /* Write Buffer Overflow */
++#define WB_EDGE     0x04  /* Write Buffer Edge Detect */
++#define RD_RDY      0x08  /* Read Data Ready */
++#define WR_DONE     0x10  /* Page Write Done */
++
++/* NFC_RST Masks */
++#define ECC_RST     0x01  /* ECC (and NFC counters) Reset */
++
++/* NFC_PGCTL Masks */
++#define PG_RD_START 0x01  /* Page Read Start */
++#define PG_WR_START 0x02  /* Page Write Start */
++
++#ifdef CONFIG_MTD_NAND_BF5XX_HWECC
++static int hardware_ecc = 1;
++#else
++static int hardware_ecc;
++#endif
++
++static const unsigned short bfin_nfc_pin_req[] =
++	{P_NAND_CE,
++	 P_NAND_RB,
++	 P_NAND_D0,
++	 P_NAND_D1,
++	 P_NAND_D2,
++	 P_NAND_D3,
++	 P_NAND_D4,
++	 P_NAND_D5,
++	 P_NAND_D6,
++	 P_NAND_D7,
++	 P_NAND_WE,
++	 P_NAND_RE,
++	 P_NAND_CLE,
++	 P_NAND_ALE,
++	 0};
++
++#ifdef CONFIG_MTD_NAND_BF5XX_BOOTROM_ECC
++static int bootrom_ooblayout_ecc(struct mtd_info *mtd, int section,
++				 struct mtd_oob_region *oobregion)
++{
++	if (section > 7)
++		return -ERANGE;
++
++	oobregion->offset = section * 8;
++	oobregion->length = 3;
++
++	return 0;
++}
++
++static int bootrom_ooblayout_free(struct mtd_info *mtd, int section,
++				  struct mtd_oob_region *oobregion)
++{
++	if (section > 7)
++		return -ERANGE;
++
++	oobregion->offset = (section * 8) + 3;
++	oobregion->length = 5;
++
++	return 0;
++}
++
++static const struct mtd_ooblayout_ops bootrom_ooblayout_ops = {
++	.ecc = bootrom_ooblayout_ecc,
++	.free = bootrom_ooblayout_free,
++};
++#endif
++
++/*
++ * Data structures for bf5xx nand flash controller driver
++ */
++
++/* bf5xx nand info */
++struct bf5xx_nand_info {
++	/* mtd info */
++	struct nand_hw_control		controller;
++	struct nand_chip		chip;
++
++	/* platform info */
++	struct bf5xx_nand_platform	*platform;
++
++	/* device info */
++	struct device			*device;
++
++	/* DMA stuff */
++	struct completion		dma_completion;
++};
++
++/*
++ * Conversion functions
++ */
++static struct bf5xx_nand_info *mtd_to_nand_info(struct mtd_info *mtd)
++{
++	return container_of(mtd_to_nand(mtd), struct bf5xx_nand_info,
++			    chip);
++}
++
++static struct bf5xx_nand_info *to_nand_info(struct platform_device *pdev)
++{
++	return platform_get_drvdata(pdev);
++}
++
++static struct bf5xx_nand_platform *to_nand_plat(struct platform_device *pdev)
++{
++	return dev_get_platdata(&pdev->dev);
++}
++
++/*
++ * struct nand_chip interface function pointers
++ */
++
++/*
++ * bf5xx_nand_hwcontrol
++ *
++ * Issue command and address cycles to the chip
++ */
++static void bf5xx_nand_hwcontrol(struct mtd_info *mtd, int cmd,
++				   unsigned int ctrl)
++{
++	if (cmd == NAND_CMD_NONE)
++		return;
++
++	while (bfin_read_NFC_STAT() & WB_FULL)
++		cpu_relax();
++
++	if (ctrl & NAND_CLE)
++		bfin_write_NFC_CMD(cmd);
++	else if (ctrl & NAND_ALE)
++		bfin_write_NFC_ADDR(cmd);
++	SSYNC();
++}
++
++/*
++ * bf5xx_nand_devready()
++ *
++ * returns 0 if the nand is busy, 1 if it is ready
++ */
++static int bf5xx_nand_devready(struct mtd_info *mtd)
++{
++	unsigned short val = bfin_read_NFC_STAT();
++
++	if ((val & NBUSY) == NBUSY)
++		return 1;
++	else
++		return 0;
++}
++
++/*
++ * ECC functions
++ * These allow the bf5xx to use the controller's ECC
++ * generator block to ECC the data as it passes through
++ */
++
++/*
++ * ECC error correction function
++ */
++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);
++	u32 syndrome[5];
++	u32 calced, stored;
++	int i;
++	unsigned short failing_bit, failing_byte;
++	u_char data;
++
++	calced = calc_ecc[0] | (calc_ecc[1] << 8) | (calc_ecc[2] << 16);
++	stored = read_ecc[0] | (read_ecc[1] << 8) | (read_ecc[2] << 16);
++
++	syndrome[0] = (calced ^ stored);
++
++	/*
++	 * syndrome 0: all zero
++	 * No error in data
++	 * No action
++	 */
++	if (!syndrome[0] || !calced || !stored)
++		return 0;
++
++	/*
++	 * sysdrome 0: only one bit is one
++	 * ECC data was incorrect
++	 * No action
++	 */
++	if (hweight32(syndrome[0]) == 1) {
++		dev_err(info->device, "ECC data was incorrect!\n");
++		return -EBADMSG;
++	}
++
++	syndrome[1] = (calced & 0x7FF) ^ (stored & 0x7FF);
++	syndrome[2] = (calced & 0x7FF) ^ ((calced >> 11) & 0x7FF);
++	syndrome[3] = (stored & 0x7FF) ^ ((stored >> 11) & 0x7FF);
++	syndrome[4] = syndrome[2] ^ syndrome[3];
++
++	for (i = 0; i < 5; i++)
++		dev_info(info->device, "syndrome[%d] 0x%08x\n", i, syndrome[i]);
++
++	dev_info(info->device,
++		"calced[0x%08x], stored[0x%08x]\n",
++		calced, stored);
++
++	/*
++	 * sysdrome 0: exactly 11 bits are one, each parity
++	 * and parity' pair is 1 & 0 or 0 & 1.
++	 * 1-bit correctable error
++	 * Correct the error
++	 */
++	if (hweight32(syndrome[0]) == 11 && syndrome[4] == 0x7FF) {
++		dev_info(info->device,
++			"1-bit correctable error, correct it.\n");
++		dev_info(info->device,
++			"syndrome[1] 0x%08x\n", syndrome[1]);
++
++		failing_bit = syndrome[1] & 0x7;
++		failing_byte = syndrome[1] >> 0x3;
++		data = *(dat + failing_byte);
++		data = data ^ (0x1 << failing_bit);
++		*(dat + failing_byte) = data;
++
++		return 1;
++	}
++
++	/*
++	 * sysdrome 0: random data
++	 * More than 1-bit error, non-correctable error
++	 * Discard data, mark bad block
++	 */
++	dev_err(info->device,
++		"More than 1-bit error, non-correctable error.\n");
++	dev_err(info->device,
++		"Please discard data, mark bad block\n");
++
++	return -EBADMSG;
++}
++
++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);
++	int ret, bitflips = 0;
++
++	ret = bf5xx_nand_correct_data_256(mtd, dat, read_ecc, calc_ecc);
++	if (ret < 0)
++		return ret;
++
++	bitflips = ret;
++
++	/* If ecc size is 512, correct second 256 bytes */
++	if (chip->ecc.size == 512) {
++		dat += 256;
++		read_ecc += 3;
++		calc_ecc += 3;
++		ret = bf5xx_nand_correct_data_256(mtd, dat, read_ecc, calc_ecc);
++		if (ret < 0)
++			return ret;
++
++		bitflips += ret;
++	}
++
++	return bitflips;
++}
++
++static void bf5xx_nand_enable_hwecc(struct mtd_info *mtd, int mode)
++{
++	return;
++}
++
++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);
++	u16 ecc0, ecc1;
++	u32 code[2];
++	u8 *p;
++
++	/* first 3 bytes ECC code for 256 page size */
++	ecc0 = bfin_read_NFC_ECC0();
++	ecc1 = bfin_read_NFC_ECC1();
++
++	code[0] = (ecc0 & 0x7ff) | ((ecc1 & 0x7ff) << 11);
++
++	dev_dbg(info->device, "returning ecc 0x%08x\n", code[0]);
++
++	p = (u8 *) code;
++	memcpy(ecc_code, p, 3);
++
++	/* second 3 bytes ECC code for 512 ecc size */
++	if (chip->ecc.size == 512) {
++		ecc0 = bfin_read_NFC_ECC2();
++		ecc1 = bfin_read_NFC_ECC3();
++		code[1] = (ecc0 & 0x7ff) | ((ecc1 & 0x7ff) << 11);
++
++		/* second 3 bytes in ecc_code for second 256
++		 * bytes of 512 page size
++		 */
++		p = (u8 *) (code + 1);
++		memcpy((ecc_code + 3), p, 3);
++		dev_dbg(info->device, "returning ecc 0x%08x\n", code[1]);
++	}
++
++	return 0;
++}
++
++/*
++ * PIO mode for buffer writing and reading
++ */
++static void bf5xx_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
++{
++	int i;
++	unsigned short val;
++
++	/*
++	 * Data reads are requested by first writing to NFC_DATA_RD
++	 * and then reading back from NFC_READ.
++	 */
++	for (i = 0; i < len; i++) {
++		while (bfin_read_NFC_STAT() & WB_FULL)
++			cpu_relax();
++
++		/* Contents do not matter */
++		bfin_write_NFC_DATA_RD(0x0000);
++		SSYNC();
++
++		while ((bfin_read_NFC_IRQSTAT() & RD_RDY) != RD_RDY)
++			cpu_relax();
++
++		buf[i] = bfin_read_NFC_READ();
++
++		val = bfin_read_NFC_IRQSTAT();
++		val |= RD_RDY;
++		bfin_write_NFC_IRQSTAT(val);
++		SSYNC();
++	}
++}
++
++static uint8_t bf5xx_nand_read_byte(struct mtd_info *mtd)
++{
++	uint8_t val;
++
++	bf5xx_nand_read_buf(mtd, &val, 1);
++
++	return val;
++}
++
++static void bf5xx_nand_write_buf(struct mtd_info *mtd,
++				const uint8_t *buf, int len)
++{
++	int i;
++
++	for (i = 0; i < len; i++) {
++		while (bfin_read_NFC_STAT() & WB_FULL)
++			cpu_relax();
++
++		bfin_write_NFC_DATA_WR(buf[i]);
++		SSYNC();
++	}
++}
++
++static void bf5xx_nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
++{
++	int i;
++	u16 *p = (u16 *) buf;
++	len >>= 1;
++
++	/*
++	 * Data reads are requested by first writing to NFC_DATA_RD
++	 * and then reading back from NFC_READ.
++	 */
++	bfin_write_NFC_DATA_RD(0x5555);
++
++	SSYNC();
++
++	for (i = 0; i < len; i++)
++		p[i] = bfin_read_NFC_READ();
++}
++
++static void bf5xx_nand_write_buf16(struct mtd_info *mtd,
++				const uint8_t *buf, int len)
++{
++	int i;
++	u16 *p = (u16 *) buf;
++	len >>= 1;
++
++	for (i = 0; i < len; i++)
++		bfin_write_NFC_DATA_WR(p[i]);
++
++	SSYNC();
++}
++
++/*
++ * DMA functions for buffer writing and reading
++ */
++static irqreturn_t bf5xx_nand_dma_irq(int irq, void *dev_id)
++{
++	struct bf5xx_nand_info *info = dev_id;
++
++	clear_dma_irqstat(CH_NFC);
++	disable_dma(CH_NFC);
++	complete(&info->dma_completion);
++
++	return IRQ_HANDLED;
++}
++
++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);
++	unsigned short val;
++
++	dev_dbg(info->device, " mtd->%p, buf->%p, is_read %d\n",
++			mtd, buf, is_read);
++
++	/*
++	 * Before starting a dma transfer, be sure to invalidate/flush
++	 * the cache over the address range of your DMA buffer to
++	 * prevent cache coherency problems. Otherwise very subtle bugs
++	 * can be introduced to your driver.
++	 */
++	if (is_read)
++		invalidate_dcache_range((unsigned int)buf,
++				(unsigned int)(buf + chip->ecc.size));
++	else
++		flush_dcache_range((unsigned int)buf,
++				(unsigned int)(buf + chip->ecc.size));
++
++	/*
++	 * This register must be written before each page is
++	 * transferred to generate the correct ECC register
++	 * values.
++	 */
++	bfin_write_NFC_RST(ECC_RST);
++	SSYNC();
++	while (bfin_read_NFC_RST() & ECC_RST)
++		cpu_relax();
++
++	disable_dma(CH_NFC);
++	clear_dma_irqstat(CH_NFC);
++
++	/* setup DMA register with Blackfin DMA API */
++	set_dma_config(CH_NFC, 0x0);
++	set_dma_start_addr(CH_NFC, (unsigned long) buf);
++
++	/* The DMAs have different size on BF52x and BF54x */
++#ifdef CONFIG_BF52x
++	set_dma_x_count(CH_NFC, (chip->ecc.size >> 1));
++	set_dma_x_modify(CH_NFC, 2);
++	val = DI_EN | WDSIZE_16;
++#endif
++
++#ifdef CONFIG_BF54x
++	set_dma_x_count(CH_NFC, (chip->ecc.size >> 2));
++	set_dma_x_modify(CH_NFC, 4);
++	val = DI_EN | WDSIZE_32;
++#endif
++	/* setup write or read operation */
++	if (is_read)
++		val |= WNR;
++	set_dma_config(CH_NFC, val);
++	enable_dma(CH_NFC);
++
++	/* Start PAGE read/write operation */
++	if (is_read)
++		bfin_write_NFC_PGCTL(PG_RD_START);
++	else
++		bfin_write_NFC_PGCTL(PG_WR_START);
++	wait_for_completion(&info->dma_completion);
++}
++
++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);
++
++	dev_dbg(info->device, "mtd->%p, buf->%p, int %d\n", mtd, buf, len);
++
++	if (len == chip->ecc.size)
++		bf5xx_nand_dma_rw(mtd, buf, 1);
++	else
++		bf5xx_nand_read_buf(mtd, buf, len);
++}
++
++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);
++
++	dev_dbg(info->device, "mtd->%p, buf->%p, len %d\n", mtd, buf, len);
++
++	if (len == chip->ecc.size)
++		bf5xx_nand_dma_rw(mtd, (uint8_t *)buf, 0);
++	else
++		bf5xx_nand_write_buf(mtd, buf, len);
++}
++
++static int bf5xx_nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
++		uint8_t *buf, int oob_required, int page)
++{
++	bf5xx_nand_read_buf(mtd, buf, mtd->writesize);
++	bf5xx_nand_read_buf(mtd, chip->oob_poi, mtd->oobsize);
++
++	return 0;
++}
++
++static int bf5xx_nand_write_page_raw(struct mtd_info *mtd,
++		struct nand_chip *chip,	const uint8_t *buf, int oob_required,
++		int page)
++{
++	bf5xx_nand_write_buf(mtd, buf, mtd->writesize);
++	bf5xx_nand_write_buf(mtd, chip->oob_poi, mtd->oobsize);
++
++	return 0;
++}
++
++/*
++ * System initialization functions
++ */
++static int bf5xx_nand_dma_init(struct bf5xx_nand_info *info)
++{
++	int ret;
++
++	/* Do not use dma */
++	if (!hardware_ecc)
++		return 0;
++
++	init_completion(&info->dma_completion);
++
++	/* Request NFC DMA channel */
++	ret = request_dma(CH_NFC, "BF5XX NFC driver");
++	if (ret < 0) {
++		dev_err(info->device, " unable to get DMA channel\n");
++		return ret;
++	}
++
++#ifdef CONFIG_BF54x
++	/* Setup DMAC1 channel mux for NFC which shared with SDH */
++	bfin_write_DMAC1_PERIMUX(bfin_read_DMAC1_PERIMUX() & ~1);
++	SSYNC();
++#endif
++
++	set_dma_callback(CH_NFC, bf5xx_nand_dma_irq, info);
++
++	/* Turn off the DMA channel first */
++	disable_dma(CH_NFC);
++	return 0;
++}
++
++static void bf5xx_nand_dma_remove(struct bf5xx_nand_info *info)
++{
++	/* Free NFC DMA channel */
++	if (hardware_ecc)
++		free_dma(CH_NFC);
++}
++
++/*
++ * BF5XX NFC hardware initialization
++ *  - pin mux setup
++ *  - clear interrupt status
++ */
++static int bf5xx_nand_hw_init(struct bf5xx_nand_info *info)
++{
++	int err = 0;
++	unsigned short val;
++	struct bf5xx_nand_platform *plat = info->platform;
++
++	/* setup NFC_CTL register */
++	dev_info(info->device,
++		"data_width=%d, wr_dly=%d, rd_dly=%d\n",
++		(plat->data_width ? 16 : 8),
++		plat->wr_dly, plat->rd_dly);
++
++	val = (1 << NFC_PG_SIZE_OFFSET) |
++		(plat->data_width << NFC_NWIDTH_OFFSET) |
++		(plat->rd_dly << NFC_RDDLY_OFFSET) |
++		(plat->wr_dly << NFC_WRDLY_OFFSET);
++	dev_dbg(info->device, "NFC_CTL is 0x%04x\n", val);
++
++	bfin_write_NFC_CTL(val);
++	SSYNC();
++
++	/* clear interrupt status */
++	bfin_write_NFC_IRQMASK(0x0);
++	SSYNC();
++	val = bfin_read_NFC_IRQSTAT();
++	bfin_write_NFC_IRQSTAT(val);
++	SSYNC();
++
++	/* DMA initialization  */
++	if (bf5xx_nand_dma_init(info))
++		err = -ENXIO;
++
++	return err;
++}
++
++/*
++ * Device management interface
++ */
++static int bf5xx_nand_add_partition(struct bf5xx_nand_info *info)
++{
++	struct mtd_info *mtd = nand_to_mtd(&info->chip);
++	struct mtd_partition *parts = info->platform->partitions;
++	int nr = info->platform->nr_partitions;
++
++	return mtd_device_register(mtd, parts, nr);
++}
++
++static int bf5xx_nand_remove(struct platform_device *pdev)
++{
++	struct bf5xx_nand_info *info = to_nand_info(pdev);
++
++	/* first thing we need to do is release all our mtds
++	 * and their partitions, then go through freeing the
++	 * resources used
++	 */
++	nand_release(nand_to_mtd(&info->chip));
++
++	peripheral_free_list(bfin_nfc_pin_req);
++	bf5xx_nand_dma_remove(info);
++
++	return 0;
++}
++
++static int bf5xx_nand_scan(struct mtd_info *mtd)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	int ret;
++
++	ret = nand_scan_ident(mtd, 1, NULL);
++	if (ret)
++		return ret;
++
++	if (hardware_ecc) {
++		/*
++		 * for nand with page size > 512B, think it as several sections with 512B
++		 */
++		if (likely(mtd->writesize >= 512)) {
++			chip->ecc.size = 512;
++			chip->ecc.bytes = 6;
++			chip->ecc.strength = 2;
++		} else {
++			chip->ecc.size = 256;
++			chip->ecc.bytes = 3;
++			chip->ecc.strength = 1;
++			bfin_write_NFC_CTL(bfin_read_NFC_CTL() & ~(1 << NFC_PG_SIZE_OFFSET));
++			SSYNC();
++		}
++	}
++
++	return	nand_scan_tail(mtd);
++}
++
++/*
++ * bf5xx_nand_probe
++ *
++ * called by device layer when it finds a device matching
++ * one our driver can handled. This code checks to see if
++ * it can allocate all necessary resources then calls the
++ * nand layer to look for devices
++ */
++static int bf5xx_nand_probe(struct platform_device *pdev)
++{
++	struct bf5xx_nand_platform *plat = to_nand_plat(pdev);
++	struct bf5xx_nand_info *info = NULL;
++	struct nand_chip *chip = NULL;
++	struct mtd_info *mtd = NULL;
++	int err = 0;
++
++	dev_dbg(&pdev->dev, "(%p)\n", pdev);
++
++	if (!plat) {
++		dev_err(&pdev->dev, "no platform specific information\n");
++		return -EINVAL;
++	}
++
++	if (peripheral_request_list(bfin_nfc_pin_req, DRV_NAME)) {
++		dev_err(&pdev->dev, "requesting Peripherals failed\n");
++		return -EFAULT;
++	}
++
++	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
++	if (info == NULL) {
++		err = -ENOMEM;
++		goto out_err;
++	}
++
++	platform_set_drvdata(pdev, info);
++
++	nand_hw_control_init(&info->controller);
++
++	info->device     = &pdev->dev;
++	info->platform   = plat;
++
++	/* initialise chip data struct */
++	chip = &info->chip;
++	mtd = nand_to_mtd(&info->chip);
++
++	if (plat->data_width)
++		chip->options |= NAND_BUSWIDTH_16;
++
++	chip->options |= NAND_CACHEPRG | NAND_SKIP_BBTSCAN;
++
++	chip->read_buf = (plat->data_width) ?
++		bf5xx_nand_read_buf16 : bf5xx_nand_read_buf;
++	chip->write_buf = (plat->data_width) ?
++		bf5xx_nand_write_buf16 : bf5xx_nand_write_buf;
++
++	chip->read_byte    = bf5xx_nand_read_byte;
++
++	chip->cmd_ctrl     = bf5xx_nand_hwcontrol;
++	chip->dev_ready    = bf5xx_nand_devready;
++
++	nand_set_controller_data(chip, mtd);
++	chip->controller   = &info->controller;
++
++	chip->IO_ADDR_R    = (void __iomem *) NFC_READ;
++	chip->IO_ADDR_W    = (void __iomem *) NFC_DATA_WR;
++
++	chip->chip_delay   = 0;
++
++	/* initialise mtd info data struct */
++	mtd->dev.parent = &pdev->dev;
++
++	/* initialise the hardware */
++	err = bf5xx_nand_hw_init(info);
++	if (err)
++		goto out_err;
++
++	/* setup hardware ECC data struct */
++	if (hardware_ecc) {
++#ifdef CONFIG_MTD_NAND_BF5XX_BOOTROM_ECC
++		mtd_set_ooblayout(mtd, &bootrom_ooblayout_ops);
++#endif
++		chip->read_buf      = bf5xx_nand_dma_read_buf;
++		chip->write_buf     = bf5xx_nand_dma_write_buf;
++		chip->ecc.calculate = bf5xx_nand_calculate_ecc;
++		chip->ecc.correct   = bf5xx_nand_correct_data;
++		chip->ecc.mode	    = NAND_ECC_HW;
++		chip->ecc.hwctl	    = bf5xx_nand_enable_hwecc;
++		chip->ecc.read_page_raw = bf5xx_nand_read_page_raw;
++		chip->ecc.write_page_raw = bf5xx_nand_write_page_raw;
++	} else {
++		chip->ecc.mode	    = NAND_ECC_SOFT;
++		chip->ecc.algo	= NAND_ECC_HAMMING;
++	}
++
++	/* scan hardware nand chip and setup mtd info data struct */
++	if (bf5xx_nand_scan(mtd)) {
++		err = -ENXIO;
++		goto out_err_nand_scan;
++	}
++
++#ifdef CONFIG_MTD_NAND_BF5XX_BOOTROM_ECC
++	chip->badblockpos = 63;
++#endif
++
++	/* add NAND partition */
++	bf5xx_nand_add_partition(info);
++
++	dev_dbg(&pdev->dev, "initialised ok\n");
++	return 0;
++
++out_err_nand_scan:
++	bf5xx_nand_dma_remove(info);
++out_err:
++	peripheral_free_list(bfin_nfc_pin_req);
++
++	return err;
++}
++
++/* driver device registration */
++static struct platform_driver bf5xx_nand_driver = {
++	.probe		= bf5xx_nand_probe,
++	.remove		= bf5xx_nand_remove,
++	.driver		= {
++		.name	= DRV_NAME,
++	},
++};
++
++module_platform_driver(bf5xx_nand_driver);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR(DRV_AUTHOR);
++MODULE_DESCRIPTION(DRV_DESC);
++MODULE_ALIAS("platform:" DRV_NAME);
+diff --git a/drivers/mtd/nand/raw/brcmnand/Makefile b/drivers/mtd/nand/raw/brcmnand/Makefile
+new file mode 100644
+index 0000000..195b845
+--- /dev/null
++++ b/drivers/mtd/nand/raw/brcmnand/Makefile
+@@ -0,0 +1,8 @@
++# SPDX-License-Identifier: GPL-2.0
++# link order matters; don't link the more generic brcmstb_nand.o before the
++# more specific iproc_nand.o, for instance
++obj-$(CONFIG_MTD_NAND_BRCMNAND)		+= iproc_nand.o
++obj-$(CONFIG_MTD_NAND_BRCMNAND)		+= bcm63138_nand.o
++obj-$(CONFIG_MTD_NAND_BRCMNAND)		+= bcm6368_nand.o
++obj-$(CONFIG_MTD_NAND_BRCMNAND)		+= brcmstb_nand.o
++obj-$(CONFIG_MTD_NAND_BRCMNAND)		+= brcmnand.o
+diff --git a/drivers/mtd/nand/raw/brcmnand/bcm63138_nand.c b/drivers/mtd/nand/raw/brcmnand/bcm63138_nand.c
+new file mode 100644
+index 0000000..59444b3
+--- /dev/null
++++ b/drivers/mtd/nand/raw/brcmnand/bcm63138_nand.c
+@@ -0,0 +1,109 @@
++/*
++ * Copyright © 2015 Broadcom Corporation
++ *
++ * 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/device.h>
++#include <linux/io.h>
++#include <linux/ioport.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/of_address.h>
++#include <linux/platform_device.h>
++#include <linux/slab.h>
++
++#include "brcmnand.h"
++
++struct bcm63138_nand_soc {
++	struct brcmnand_soc soc;
++	void __iomem *base;
++};
++
++#define BCM63138_NAND_INT_STATUS		0x00
++#define BCM63138_NAND_INT_EN			0x04
++
++enum {
++	BCM63138_CTLRDY		= BIT(4),
++};
++
++static bool bcm63138_nand_intc_ack(struct brcmnand_soc *soc)
++{
++	struct bcm63138_nand_soc *priv =
++			container_of(soc, struct bcm63138_nand_soc, soc);
++	void __iomem *mmio = priv->base + BCM63138_NAND_INT_STATUS;
++	u32 val = brcmnand_readl(mmio);
++
++	if (val & BCM63138_CTLRDY) {
++		brcmnand_writel(val & ~BCM63138_CTLRDY, mmio);
++		return true;
++	}
++
++	return false;
++}
++
++static void bcm63138_nand_intc_set(struct brcmnand_soc *soc, bool en)
++{
++	struct bcm63138_nand_soc *priv =
++			container_of(soc, struct bcm63138_nand_soc, soc);
++	void __iomem *mmio = priv->base + BCM63138_NAND_INT_EN;
++	u32 val = brcmnand_readl(mmio);
++
++	if (en)
++		val |= BCM63138_CTLRDY;
++	else
++		val &= ~BCM63138_CTLRDY;
++
++	brcmnand_writel(val, mmio);
++}
++
++static int bcm63138_nand_probe(struct platform_device *pdev)
++{
++	struct device *dev = &pdev->dev;
++	struct bcm63138_nand_soc *priv;
++	struct brcmnand_soc *soc;
++	struct resource *res;
++
++	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
++	if (!priv)
++		return -ENOMEM;
++	soc = &priv->soc;
++
++	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand-int-base");
++	priv->base = devm_ioremap_resource(dev, res);
++	if (IS_ERR(priv->base))
++		return PTR_ERR(priv->base);
++
++	soc->ctlrdy_ack = bcm63138_nand_intc_ack;
++	soc->ctlrdy_set_enabled = bcm63138_nand_intc_set;
++
++	return brcmnand_probe(pdev, soc);
++}
++
++static const struct of_device_id bcm63138_nand_of_match[] = {
++	{ .compatible = "brcm,nand-bcm63138" },
++	{},
++};
++MODULE_DEVICE_TABLE(of, bcm63138_nand_of_match);
++
++static struct platform_driver bcm63138_nand_driver = {
++	.probe			= bcm63138_nand_probe,
++	.remove			= brcmnand_remove,
++	.driver = {
++		.name		= "bcm63138_nand",
++		.pm		= &brcmnand_pm_ops,
++		.of_match_table	= bcm63138_nand_of_match,
++	}
++};
++module_platform_driver(bcm63138_nand_driver);
++
++MODULE_LICENSE("GPL v2");
++MODULE_AUTHOR("Brian Norris");
++MODULE_DESCRIPTION("NAND driver for BCM63138");
+diff --git a/drivers/mtd/nand/raw/brcmnand/bcm6368_nand.c b/drivers/mtd/nand/raw/brcmnand/bcm6368_nand.c
+new file mode 100644
+index 0000000..34c91b0
+--- /dev/null
++++ b/drivers/mtd/nand/raw/brcmnand/bcm6368_nand.c
+@@ -0,0 +1,142 @@
++/*
++ * Copyright 2015 Simon Arlott
++ *
++ * 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.
++ *
++ * Derived from bcm63138_nand.c:
++ * Copyright © 2015 Broadcom Corporation
++ *
++ * Derived from bcm963xx_4.12L.06B_consumer/shared/opensource/include/bcm963xx/63268_map_part.h:
++ * Copyright 2000-2010 Broadcom Corporation
++ *
++ * Derived from bcm963xx_4.12L.06B_consumer/shared/opensource/flash/nandflash.c:
++ * Copyright 2000-2010 Broadcom Corporation
++ */
++
++#include <linux/device.h>
++#include <linux/io.h>
++#include <linux/ioport.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/of_address.h>
++#include <linux/platform_device.h>
++#include <linux/slab.h>
++
++#include "brcmnand.h"
++
++struct bcm6368_nand_soc {
++	struct brcmnand_soc soc;
++	void __iomem *base;
++};
++
++#define BCM6368_NAND_INT		0x00
++#define  BCM6368_NAND_STATUS_SHIFT	0
++#define  BCM6368_NAND_STATUS_MASK	(0xfff << BCM6368_NAND_STATUS_SHIFT)
++#define  BCM6368_NAND_ENABLE_SHIFT	16
++#define  BCM6368_NAND_ENABLE_MASK	(0xffff << BCM6368_NAND_ENABLE_SHIFT)
++#define BCM6368_NAND_BASE_ADDR0	0x04
++#define BCM6368_NAND_BASE_ADDR1	0x0c
++
++enum {
++	BCM6368_NP_READ		= BIT(0),
++	BCM6368_BLOCK_ERASE	= BIT(1),
++	BCM6368_COPY_BACK	= BIT(2),
++	BCM6368_PAGE_PGM	= BIT(3),
++	BCM6368_CTRL_READY	= BIT(4),
++	BCM6368_DEV_RBPIN	= BIT(5),
++	BCM6368_ECC_ERR_UNC	= BIT(6),
++	BCM6368_ECC_ERR_CORR	= BIT(7),
++};
++
++static bool bcm6368_nand_intc_ack(struct brcmnand_soc *soc)
++{
++	struct bcm6368_nand_soc *priv =
++			container_of(soc, struct bcm6368_nand_soc, soc);
++	void __iomem *mmio = priv->base + BCM6368_NAND_INT;
++	u32 val = brcmnand_readl(mmio);
++
++	if (val & (BCM6368_CTRL_READY << BCM6368_NAND_STATUS_SHIFT)) {
++		/* Ack interrupt */
++		val &= ~BCM6368_NAND_STATUS_MASK;
++		val |= BCM6368_CTRL_READY << BCM6368_NAND_STATUS_SHIFT;
++		brcmnand_writel(val, mmio);
++		return true;
++	}
++
++	return false;
++}
++
++static void bcm6368_nand_intc_set(struct brcmnand_soc *soc, bool en)
++{
++	struct bcm6368_nand_soc *priv =
++			container_of(soc, struct bcm6368_nand_soc, soc);
++	void __iomem *mmio = priv->base + BCM6368_NAND_INT;
++	u32 val = brcmnand_readl(mmio);
++
++	/* Don't ack any interrupts */
++	val &= ~BCM6368_NAND_STATUS_MASK;
++
++	if (en)
++		val |= BCM6368_CTRL_READY << BCM6368_NAND_ENABLE_SHIFT;
++	else
++		val &= ~(BCM6368_CTRL_READY << BCM6368_NAND_ENABLE_SHIFT);
++
++	brcmnand_writel(val, mmio);
++}
++
++static int bcm6368_nand_probe(struct platform_device *pdev)
++{
++	struct device *dev = &pdev->dev;
++	struct bcm6368_nand_soc *priv;
++	struct brcmnand_soc *soc;
++	struct resource *res;
++
++	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
++	if (!priv)
++		return -ENOMEM;
++	soc = &priv->soc;
++
++	res = platform_get_resource_byname(pdev,
++		IORESOURCE_MEM, "nand-int-base");
++	priv->base = devm_ioremap_resource(dev, res);
++	if (IS_ERR(priv->base))
++		return PTR_ERR(priv->base);
++
++	soc->ctlrdy_ack = bcm6368_nand_intc_ack;
++	soc->ctlrdy_set_enabled = bcm6368_nand_intc_set;
++
++	/* Disable and ack all interrupts  */
++	brcmnand_writel(0, priv->base + BCM6368_NAND_INT);
++	brcmnand_writel(BCM6368_NAND_STATUS_MASK,
++			priv->base + BCM6368_NAND_INT);
++
++	return brcmnand_probe(pdev, soc);
++}
++
++static const struct of_device_id bcm6368_nand_of_match[] = {
++	{ .compatible = "brcm,nand-bcm6368" },
++	{},
++};
++MODULE_DEVICE_TABLE(of, bcm6368_nand_of_match);
++
++static struct platform_driver bcm6368_nand_driver = {
++	.probe			= bcm6368_nand_probe,
++	.remove			= brcmnand_remove,
++	.driver = {
++		.name		= "bcm6368_nand",
++		.pm		= &brcmnand_pm_ops,
++		.of_match_table	= bcm6368_nand_of_match,
++	}
++};
++module_platform_driver(bcm6368_nand_driver);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Simon Arlott");
++MODULE_DESCRIPTION("NAND driver for BCM6368");
+diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand.c b/drivers/mtd/nand/raw/brcmnand/brcmnand.c
+new file mode 100644
+index 0000000..e0eb51d
+--- /dev/null
++++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.c
+@@ -0,0 +1,2618 @@
++/*
++ * Copyright © 2010-2015 Broadcom Corporation
++ *
++ * 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/clk.h>
++#include <linux/version.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++#include <linux/device.h>
++#include <linux/platform_device.h>
++#include <linux/err.h>
++#include <linux/completion.h>
++#include <linux/interrupt.h>
++#include <linux/spinlock.h>
++#include <linux/dma-mapping.h>
++#include <linux/ioport.h>
++#include <linux/bug.h>
++#include <linux/kernel.h>
++#include <linux/bitops.h>
++#include <linux/mm.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/rawnand.h>
++#include <linux/mtd/partitions.h>
++#include <linux/of.h>
++#include <linux/of_platform.h>
++#include <linux/slab.h>
++#include <linux/list.h>
++#include <linux/log2.h>
++
++#include "brcmnand.h"
++
++/*
++ * This flag controls if WP stays on between erase/write commands to mitigate
++ * flash corruption due to power glitches. Values:
++ * 0: NAND_WP is not used or not available
++ * 1: NAND_WP is set by default, cleared for erase/write operations
++ * 2: NAND_WP is always cleared
++ */
++static int wp_on = 1;
++module_param(wp_on, int, 0444);
++
++/***********************************************************************
++ * Definitions
++ ***********************************************************************/
++
++#define DRV_NAME			"brcmnand"
++
++#define CMD_NULL			0x00
++#define CMD_PAGE_READ			0x01
++#define CMD_SPARE_AREA_READ		0x02
++#define CMD_STATUS_READ			0x03
++#define CMD_PROGRAM_PAGE		0x04
++#define CMD_PROGRAM_SPARE_AREA		0x05
++#define CMD_COPY_BACK			0x06
++#define CMD_DEVICE_ID_READ		0x07
++#define CMD_BLOCK_ERASE			0x08
++#define CMD_FLASH_RESET			0x09
++#define CMD_BLOCKS_LOCK			0x0a
++#define CMD_BLOCKS_LOCK_DOWN		0x0b
++#define CMD_BLOCKS_UNLOCK		0x0c
++#define CMD_READ_BLOCKS_LOCK_STATUS	0x0d
++#define CMD_PARAMETER_READ		0x0e
++#define CMD_PARAMETER_CHANGE_COL	0x0f
++#define CMD_LOW_LEVEL_OP		0x10
++
++struct brcm_nand_dma_desc {
++	u32 next_desc;
++	u32 next_desc_ext;
++	u32 cmd_irq;
++	u32 dram_addr;
++	u32 dram_addr_ext;
++	u32 tfr_len;
++	u32 total_len;
++	u32 flash_addr;
++	u32 flash_addr_ext;
++	u32 cs;
++	u32 pad2[5];
++	u32 status_valid;
++} __packed;
++
++/* Bitfields for brcm_nand_dma_desc::status_valid */
++#define FLASH_DMA_ECC_ERROR	(1 << 8)
++#define FLASH_DMA_CORR_ERROR	(1 << 9)
++
++/* 512B flash cache in the NAND controller HW */
++#define FC_SHIFT		9U
++#define FC_BYTES		512U
++#define FC_WORDS		(FC_BYTES >> 2)
++
++#define BRCMNAND_MIN_PAGESIZE	512
++#define BRCMNAND_MIN_BLOCKSIZE	(8 * 1024)
++#define BRCMNAND_MIN_DEVSIZE	(4ULL * 1024 * 1024)
++
++#define NAND_CTRL_RDY			(INTFC_CTLR_READY | INTFC_FLASH_READY)
++#define NAND_POLL_STATUS_TIMEOUT_MS	100
++
++/* Controller feature flags */
++enum {
++	BRCMNAND_HAS_1K_SECTORS			= BIT(0),
++	BRCMNAND_HAS_PREFETCH			= BIT(1),
++	BRCMNAND_HAS_CACHE_MODE			= BIT(2),
++	BRCMNAND_HAS_WP				= BIT(3),
++};
++
++struct brcmnand_controller {
++	struct device		*dev;
++	struct nand_hw_control	controller;
++	void __iomem		*nand_base;
++	void __iomem		*nand_fc; /* flash cache */
++	void __iomem		*flash_dma_base;
++	unsigned int		irq;
++	unsigned int		dma_irq;
++	int			nand_version;
++
++	/* Some SoCs provide custom interrupt status register(s) */
++	struct brcmnand_soc	*soc;
++
++	/* Some SoCs have a gateable clock for the controller */
++	struct clk		*clk;
++
++	int			cmd_pending;
++	bool			dma_pending;
++	struct completion	done;
++	struct completion	dma_done;
++
++	/* List of NAND hosts (one for each chip-select) */
++	struct list_head host_list;
++
++	struct brcm_nand_dma_desc *dma_desc;
++	dma_addr_t		dma_pa;
++
++	/* in-memory cache of the FLASH_CACHE, used only for some commands */
++	u8			flash_cache[FC_BYTES];
++
++	/* Controller revision details */
++	const u16		*reg_offsets;
++	unsigned int		reg_spacing; /* between CS1, CS2, ... regs */
++	const u8		*cs_offsets; /* within each chip-select */
++	const u8		*cs0_offsets; /* within CS0, if different */
++	unsigned int		max_block_size;
++	const unsigned int	*block_sizes;
++	unsigned int		max_page_size;
++	const unsigned int	*page_sizes;
++	unsigned int		max_oob;
++	u32			features;
++
++	/* for low-power standby/resume only */
++	u32			nand_cs_nand_select;
++	u32			nand_cs_nand_xor;
++	u32			corr_stat_threshold;
++	u32			flash_dma_mode;
++};
++
++struct brcmnand_cfg {
++	u64			device_size;
++	unsigned int		block_size;
++	unsigned int		page_size;
++	unsigned int		spare_area_size;
++	unsigned int		device_width;
++	unsigned int		col_adr_bytes;
++	unsigned int		blk_adr_bytes;
++	unsigned int		ful_adr_bytes;
++	unsigned int		sector_size_1k;
++	unsigned int		ecc_level;
++	/* use for low-power standby/resume only */
++	u32			acc_control;
++	u32			config;
++	u32			config_ext;
++	u32			timing_1;
++	u32			timing_2;
++};
++
++struct brcmnand_host {
++	struct list_head	node;
++
++	struct nand_chip	chip;
++	struct platform_device	*pdev;
++	int			cs;
++
++	unsigned int		last_cmd;
++	unsigned int		last_byte;
++	u64			last_addr;
++	struct brcmnand_cfg	hwcfg;
++	struct brcmnand_controller *ctrl;
++};
++
++enum brcmnand_reg {
++	BRCMNAND_CMD_START = 0,
++	BRCMNAND_CMD_EXT_ADDRESS,
++	BRCMNAND_CMD_ADDRESS,
++	BRCMNAND_INTFC_STATUS,
++	BRCMNAND_CS_SELECT,
++	BRCMNAND_CS_XOR,
++	BRCMNAND_LL_OP,
++	BRCMNAND_CS0_BASE,
++	BRCMNAND_CS1_BASE,		/* CS1 regs, if non-contiguous */
++	BRCMNAND_CORR_THRESHOLD,
++	BRCMNAND_CORR_THRESHOLD_EXT,
++	BRCMNAND_UNCORR_COUNT,
++	BRCMNAND_CORR_COUNT,
++	BRCMNAND_CORR_EXT_ADDR,
++	BRCMNAND_CORR_ADDR,
++	BRCMNAND_UNCORR_EXT_ADDR,
++	BRCMNAND_UNCORR_ADDR,
++	BRCMNAND_SEMAPHORE,
++	BRCMNAND_ID,
++	BRCMNAND_ID_EXT,
++	BRCMNAND_LL_RDATA,
++	BRCMNAND_OOB_READ_BASE,
++	BRCMNAND_OOB_READ_10_BASE,	/* offset 0x10, if non-contiguous */
++	BRCMNAND_OOB_WRITE_BASE,
++	BRCMNAND_OOB_WRITE_10_BASE,	/* offset 0x10, if non-contiguous */
++	BRCMNAND_FC_BASE,
++};
++
++/* BRCMNAND v4.0 */
++static const u16 brcmnand_regs_v40[] = {
++	[BRCMNAND_CMD_START]		=  0x04,
++	[BRCMNAND_CMD_EXT_ADDRESS]	=  0x08,
++	[BRCMNAND_CMD_ADDRESS]		=  0x0c,
++	[BRCMNAND_INTFC_STATUS]		=  0x6c,
++	[BRCMNAND_CS_SELECT]		=  0x14,
++	[BRCMNAND_CS_XOR]		=  0x18,
++	[BRCMNAND_LL_OP]		= 0x178,
++	[BRCMNAND_CS0_BASE]		=  0x40,
++	[BRCMNAND_CS1_BASE]		=  0xd0,
++	[BRCMNAND_CORR_THRESHOLD]	=  0x84,
++	[BRCMNAND_CORR_THRESHOLD_EXT]	=     0,
++	[BRCMNAND_UNCORR_COUNT]		=     0,
++	[BRCMNAND_CORR_COUNT]		=     0,
++	[BRCMNAND_CORR_EXT_ADDR]	=  0x70,
++	[BRCMNAND_CORR_ADDR]		=  0x74,
++	[BRCMNAND_UNCORR_EXT_ADDR]	=  0x78,
++	[BRCMNAND_UNCORR_ADDR]		=  0x7c,
++	[BRCMNAND_SEMAPHORE]		=  0x58,
++	[BRCMNAND_ID]			=  0x60,
++	[BRCMNAND_ID_EXT]		=  0x64,
++	[BRCMNAND_LL_RDATA]		= 0x17c,
++	[BRCMNAND_OOB_READ_BASE]	=  0x20,
++	[BRCMNAND_OOB_READ_10_BASE]	= 0x130,
++	[BRCMNAND_OOB_WRITE_BASE]	=  0x30,
++	[BRCMNAND_OOB_WRITE_10_BASE]	=     0,
++	[BRCMNAND_FC_BASE]		= 0x200,
++};
++
++/* BRCMNAND v5.0 */
++static const u16 brcmnand_regs_v50[] = {
++	[BRCMNAND_CMD_START]		=  0x04,
++	[BRCMNAND_CMD_EXT_ADDRESS]	=  0x08,
++	[BRCMNAND_CMD_ADDRESS]		=  0x0c,
++	[BRCMNAND_INTFC_STATUS]		=  0x6c,
++	[BRCMNAND_CS_SELECT]		=  0x14,
++	[BRCMNAND_CS_XOR]		=  0x18,
++	[BRCMNAND_LL_OP]		= 0x178,
++	[BRCMNAND_CS0_BASE]		=  0x40,
++	[BRCMNAND_CS1_BASE]		=  0xd0,
++	[BRCMNAND_CORR_THRESHOLD]	=  0x84,
++	[BRCMNAND_CORR_THRESHOLD_EXT]	=     0,
++	[BRCMNAND_UNCORR_COUNT]		=     0,
++	[BRCMNAND_CORR_COUNT]		=     0,
++	[BRCMNAND_CORR_EXT_ADDR]	=  0x70,
++	[BRCMNAND_CORR_ADDR]		=  0x74,
++	[BRCMNAND_UNCORR_EXT_ADDR]	=  0x78,
++	[BRCMNAND_UNCORR_ADDR]		=  0x7c,
++	[BRCMNAND_SEMAPHORE]		=  0x58,
++	[BRCMNAND_ID]			=  0x60,
++	[BRCMNAND_ID_EXT]		=  0x64,
++	[BRCMNAND_LL_RDATA]		= 0x17c,
++	[BRCMNAND_OOB_READ_BASE]	=  0x20,
++	[BRCMNAND_OOB_READ_10_BASE]	= 0x130,
++	[BRCMNAND_OOB_WRITE_BASE]	=  0x30,
++	[BRCMNAND_OOB_WRITE_10_BASE]	= 0x140,
++	[BRCMNAND_FC_BASE]		= 0x200,
++};
++
++/* BRCMNAND v6.0 - v7.1 */
++static const u16 brcmnand_regs_v60[] = {
++	[BRCMNAND_CMD_START]		=  0x04,
++	[BRCMNAND_CMD_EXT_ADDRESS]	=  0x08,
++	[BRCMNAND_CMD_ADDRESS]		=  0x0c,
++	[BRCMNAND_INTFC_STATUS]		=  0x14,
++	[BRCMNAND_CS_SELECT]		=  0x18,
++	[BRCMNAND_CS_XOR]		=  0x1c,
++	[BRCMNAND_LL_OP]		=  0x20,
++	[BRCMNAND_CS0_BASE]		=  0x50,
++	[BRCMNAND_CS1_BASE]		=     0,
++	[BRCMNAND_CORR_THRESHOLD]	=  0xc0,
++	[BRCMNAND_CORR_THRESHOLD_EXT]	=  0xc4,
++	[BRCMNAND_UNCORR_COUNT]		=  0xfc,
++	[BRCMNAND_CORR_COUNT]		= 0x100,
++	[BRCMNAND_CORR_EXT_ADDR]	= 0x10c,
++	[BRCMNAND_CORR_ADDR]		= 0x110,
++	[BRCMNAND_UNCORR_EXT_ADDR]	= 0x114,
++	[BRCMNAND_UNCORR_ADDR]		= 0x118,
++	[BRCMNAND_SEMAPHORE]		= 0x150,
++	[BRCMNAND_ID]			= 0x194,
++	[BRCMNAND_ID_EXT]		= 0x198,
++	[BRCMNAND_LL_RDATA]		= 0x19c,
++	[BRCMNAND_OOB_READ_BASE]	= 0x200,
++	[BRCMNAND_OOB_READ_10_BASE]	=     0,
++	[BRCMNAND_OOB_WRITE_BASE]	= 0x280,
++	[BRCMNAND_OOB_WRITE_10_BASE]	=     0,
++	[BRCMNAND_FC_BASE]		= 0x400,
++};
++
++/* BRCMNAND v7.1 */
++static const u16 brcmnand_regs_v71[] = {
++	[BRCMNAND_CMD_START]		=  0x04,
++	[BRCMNAND_CMD_EXT_ADDRESS]	=  0x08,
++	[BRCMNAND_CMD_ADDRESS]		=  0x0c,
++	[BRCMNAND_INTFC_STATUS]		=  0x14,
++	[BRCMNAND_CS_SELECT]		=  0x18,
++	[BRCMNAND_CS_XOR]		=  0x1c,
++	[BRCMNAND_LL_OP]		=  0x20,
++	[BRCMNAND_CS0_BASE]		=  0x50,
++	[BRCMNAND_CS1_BASE]		=     0,
++	[BRCMNAND_CORR_THRESHOLD]	=  0xdc,
++	[BRCMNAND_CORR_THRESHOLD_EXT]	=  0xe0,
++	[BRCMNAND_UNCORR_COUNT]		=  0xfc,
++	[BRCMNAND_CORR_COUNT]		= 0x100,
++	[BRCMNAND_CORR_EXT_ADDR]	= 0x10c,
++	[BRCMNAND_CORR_ADDR]		= 0x110,
++	[BRCMNAND_UNCORR_EXT_ADDR]	= 0x114,
++	[BRCMNAND_UNCORR_ADDR]		= 0x118,
++	[BRCMNAND_SEMAPHORE]		= 0x150,
++	[BRCMNAND_ID]			= 0x194,
++	[BRCMNAND_ID_EXT]		= 0x198,
++	[BRCMNAND_LL_RDATA]		= 0x19c,
++	[BRCMNAND_OOB_READ_BASE]	= 0x200,
++	[BRCMNAND_OOB_READ_10_BASE]	=     0,
++	[BRCMNAND_OOB_WRITE_BASE]	= 0x280,
++	[BRCMNAND_OOB_WRITE_10_BASE]	=     0,
++	[BRCMNAND_FC_BASE]		= 0x400,
++};
++
++/* BRCMNAND v7.2 */
++static const u16 brcmnand_regs_v72[] = {
++	[BRCMNAND_CMD_START]		=  0x04,
++	[BRCMNAND_CMD_EXT_ADDRESS]	=  0x08,
++	[BRCMNAND_CMD_ADDRESS]		=  0x0c,
++	[BRCMNAND_INTFC_STATUS]		=  0x14,
++	[BRCMNAND_CS_SELECT]		=  0x18,
++	[BRCMNAND_CS_XOR]		=  0x1c,
++	[BRCMNAND_LL_OP]		=  0x20,
++	[BRCMNAND_CS0_BASE]		=  0x50,
++	[BRCMNAND_CS1_BASE]		=     0,
++	[BRCMNAND_CORR_THRESHOLD]	=  0xdc,
++	[BRCMNAND_CORR_THRESHOLD_EXT]	=  0xe0,
++	[BRCMNAND_UNCORR_COUNT]		=  0xfc,
++	[BRCMNAND_CORR_COUNT]		= 0x100,
++	[BRCMNAND_CORR_EXT_ADDR]	= 0x10c,
++	[BRCMNAND_CORR_ADDR]		= 0x110,
++	[BRCMNAND_UNCORR_EXT_ADDR]	= 0x114,
++	[BRCMNAND_UNCORR_ADDR]		= 0x118,
++	[BRCMNAND_SEMAPHORE]		= 0x150,
++	[BRCMNAND_ID]			= 0x194,
++	[BRCMNAND_ID_EXT]		= 0x198,
++	[BRCMNAND_LL_RDATA]		= 0x19c,
++	[BRCMNAND_OOB_READ_BASE]	= 0x200,
++	[BRCMNAND_OOB_READ_10_BASE]	=     0,
++	[BRCMNAND_OOB_WRITE_BASE]	= 0x400,
++	[BRCMNAND_OOB_WRITE_10_BASE]	=     0,
++	[BRCMNAND_FC_BASE]		= 0x600,
++};
++
++enum brcmnand_cs_reg {
++	BRCMNAND_CS_CFG_EXT = 0,
++	BRCMNAND_CS_CFG,
++	BRCMNAND_CS_ACC_CONTROL,
++	BRCMNAND_CS_TIMING1,
++	BRCMNAND_CS_TIMING2,
++};
++
++/* Per chip-select offsets for v7.1 */
++static const u8 brcmnand_cs_offsets_v71[] = {
++	[BRCMNAND_CS_ACC_CONTROL]	= 0x00,
++	[BRCMNAND_CS_CFG_EXT]		= 0x04,
++	[BRCMNAND_CS_CFG]		= 0x08,
++	[BRCMNAND_CS_TIMING1]		= 0x0c,
++	[BRCMNAND_CS_TIMING2]		= 0x10,
++};
++
++/* Per chip-select offsets for pre v7.1, except CS0 on <= v5.0 */
++static const u8 brcmnand_cs_offsets[] = {
++	[BRCMNAND_CS_ACC_CONTROL]	= 0x00,
++	[BRCMNAND_CS_CFG_EXT]		= 0x04,
++	[BRCMNAND_CS_CFG]		= 0x04,
++	[BRCMNAND_CS_TIMING1]		= 0x08,
++	[BRCMNAND_CS_TIMING2]		= 0x0c,
++};
++
++/* Per chip-select offset for <= v5.0 on CS0 only */
++static const u8 brcmnand_cs_offsets_cs0[] = {
++	[BRCMNAND_CS_ACC_CONTROL]	= 0x00,
++	[BRCMNAND_CS_CFG_EXT]		= 0x08,
++	[BRCMNAND_CS_CFG]		= 0x08,
++	[BRCMNAND_CS_TIMING1]		= 0x10,
++	[BRCMNAND_CS_TIMING2]		= 0x14,
++};
++
++/*
++ * Bitfields for the CFG and CFG_EXT registers. Pre-v7.1 controllers only had
++ * one config register, but once the bitfields overflowed, newer controllers
++ * (v7.1 and newer) added a CFG_EXT register and shuffled a few fields around.
++ */
++enum {
++	CFG_BLK_ADR_BYTES_SHIFT		= 8,
++	CFG_COL_ADR_BYTES_SHIFT		= 12,
++	CFG_FUL_ADR_BYTES_SHIFT		= 16,
++	CFG_BUS_WIDTH_SHIFT		= 23,
++	CFG_BUS_WIDTH			= BIT(CFG_BUS_WIDTH_SHIFT),
++	CFG_DEVICE_SIZE_SHIFT		= 24,
++
++	/* Only for pre-v7.1 (with no CFG_EXT register) */
++	CFG_PAGE_SIZE_SHIFT		= 20,
++	CFG_BLK_SIZE_SHIFT		= 28,
++
++	/* Only for v7.1+ (with CFG_EXT register) */
++	CFG_EXT_PAGE_SIZE_SHIFT		= 0,
++	CFG_EXT_BLK_SIZE_SHIFT		= 4,
++};
++
++/* BRCMNAND_INTFC_STATUS */
++enum {
++	INTFC_FLASH_STATUS		= GENMASK(7, 0),
++
++	INTFC_ERASED			= BIT(27),
++	INTFC_OOB_VALID			= BIT(28),
++	INTFC_CACHE_VALID		= BIT(29),
++	INTFC_FLASH_READY		= BIT(30),
++	INTFC_CTLR_READY		= BIT(31),
++};
++
++static inline u32 nand_readreg(struct brcmnand_controller *ctrl, u32 offs)
++{
++	return brcmnand_readl(ctrl->nand_base + offs);
++}
++
++static inline void nand_writereg(struct brcmnand_controller *ctrl, u32 offs,
++				 u32 val)
++{
++	brcmnand_writel(val, ctrl->nand_base + offs);
++}
++
++static int brcmnand_revision_init(struct brcmnand_controller *ctrl)
++{
++	static const unsigned int block_sizes_v6[] = { 8, 16, 128, 256, 512, 1024, 2048, 0 };
++	static const unsigned int block_sizes_v4[] = { 16, 128, 8, 512, 256, 1024, 2048, 0 };
++	static const unsigned int page_sizes[] = { 512, 2048, 4096, 8192, 0 };
++
++	ctrl->nand_version = nand_readreg(ctrl, 0) & 0xffff;
++
++	/* Only support v4.0+? */
++	if (ctrl->nand_version < 0x0400) {
++		dev_err(ctrl->dev, "version %#x not supported\n",
++			ctrl->nand_version);
++		return -ENODEV;
++	}
++
++	/* Register offsets */
++	if (ctrl->nand_version >= 0x0702)
++		ctrl->reg_offsets = brcmnand_regs_v72;
++	else if (ctrl->nand_version >= 0x0701)
++		ctrl->reg_offsets = brcmnand_regs_v71;
++	else if (ctrl->nand_version >= 0x0600)
++		ctrl->reg_offsets = brcmnand_regs_v60;
++	else if (ctrl->nand_version >= 0x0500)
++		ctrl->reg_offsets = brcmnand_regs_v50;
++	else if (ctrl->nand_version >= 0x0400)
++		ctrl->reg_offsets = brcmnand_regs_v40;
++
++	/* Chip-select stride */
++	if (ctrl->nand_version >= 0x0701)
++		ctrl->reg_spacing = 0x14;
++	else
++		ctrl->reg_spacing = 0x10;
++
++	/* Per chip-select registers */
++	if (ctrl->nand_version >= 0x0701) {
++		ctrl->cs_offsets = brcmnand_cs_offsets_v71;
++	} else {
++		ctrl->cs_offsets = brcmnand_cs_offsets;
++
++		/* v5.0 and earlier has a different CS0 offset layout */
++		if (ctrl->nand_version <= 0x0500)
++			ctrl->cs0_offsets = brcmnand_cs_offsets_cs0;
++	}
++
++	/* Page / block sizes */
++	if (ctrl->nand_version >= 0x0701) {
++		/* >= v7.1 use nice power-of-2 values! */
++		ctrl->max_page_size = 16 * 1024;
++		ctrl->max_block_size = 2 * 1024 * 1024;
++	} else {
++		ctrl->page_sizes = page_sizes;
++		if (ctrl->nand_version >= 0x0600)
++			ctrl->block_sizes = block_sizes_v6;
++		else
++			ctrl->block_sizes = block_sizes_v4;
++
++		if (ctrl->nand_version < 0x0400) {
++			ctrl->max_page_size = 4096;
++			ctrl->max_block_size = 512 * 1024;
++		}
++	}
++
++	/* Maximum spare area sector size (per 512B) */
++	if (ctrl->nand_version >= 0x0702)
++		ctrl->max_oob = 128;
++	else if (ctrl->nand_version >= 0x0600)
++		ctrl->max_oob = 64;
++	else if (ctrl->nand_version >= 0x0500)
++		ctrl->max_oob = 32;
++	else
++		ctrl->max_oob = 16;
++
++	/* v6.0 and newer (except v6.1) have prefetch support */
++	if (ctrl->nand_version >= 0x0600 && ctrl->nand_version != 0x0601)
++		ctrl->features |= BRCMNAND_HAS_PREFETCH;
++
++	/*
++	 * v6.x has cache mode, but it's implemented differently. Ignore it for
++	 * now.
++	 */
++	if (ctrl->nand_version >= 0x0700)
++		ctrl->features |= BRCMNAND_HAS_CACHE_MODE;
++
++	if (ctrl->nand_version >= 0x0500)
++		ctrl->features |= BRCMNAND_HAS_1K_SECTORS;
++
++	if (ctrl->nand_version >= 0x0700)
++		ctrl->features |= BRCMNAND_HAS_WP;
++	else if (of_property_read_bool(ctrl->dev->of_node, "brcm,nand-has-wp"))
++		ctrl->features |= BRCMNAND_HAS_WP;
++
++	return 0;
++}
++
++static inline u32 brcmnand_read_reg(struct brcmnand_controller *ctrl,
++		enum brcmnand_reg reg)
++{
++	u16 offs = ctrl->reg_offsets[reg];
++
++	if (offs)
++		return nand_readreg(ctrl, offs);
++	else
++		return 0;
++}
++
++static inline void brcmnand_write_reg(struct brcmnand_controller *ctrl,
++				      enum brcmnand_reg reg, u32 val)
++{
++	u16 offs = ctrl->reg_offsets[reg];
++
++	if (offs)
++		nand_writereg(ctrl, offs, val);
++}
++
++static inline void brcmnand_rmw_reg(struct brcmnand_controller *ctrl,
++				    enum brcmnand_reg reg, u32 mask, unsigned
++				    int shift, u32 val)
++{
++	u32 tmp = brcmnand_read_reg(ctrl, reg);
++
++	tmp &= ~mask;
++	tmp |= val << shift;
++	brcmnand_write_reg(ctrl, reg, tmp);
++}
++
++static inline u32 brcmnand_read_fc(struct brcmnand_controller *ctrl, int word)
++{
++	return __raw_readl(ctrl->nand_fc + word * 4);
++}
++
++static inline void brcmnand_write_fc(struct brcmnand_controller *ctrl,
++				     int word, u32 val)
++{
++	__raw_writel(val, ctrl->nand_fc + word * 4);
++}
++
++static inline u16 brcmnand_cs_offset(struct brcmnand_controller *ctrl, int cs,
++				     enum brcmnand_cs_reg reg)
++{
++	u16 offs_cs0 = ctrl->reg_offsets[BRCMNAND_CS0_BASE];
++	u16 offs_cs1 = ctrl->reg_offsets[BRCMNAND_CS1_BASE];
++	u8 cs_offs;
++
++	if (cs == 0 && ctrl->cs0_offsets)
++		cs_offs = ctrl->cs0_offsets[reg];
++	else
++		cs_offs = ctrl->cs_offsets[reg];
++
++	if (cs && offs_cs1)
++		return offs_cs1 + (cs - 1) * ctrl->reg_spacing + cs_offs;
++
++	return offs_cs0 + cs * ctrl->reg_spacing + cs_offs;
++}
++
++static inline u32 brcmnand_count_corrected(struct brcmnand_controller *ctrl)
++{
++	if (ctrl->nand_version < 0x0600)
++		return 1;
++	return brcmnand_read_reg(ctrl, BRCMNAND_CORR_COUNT);
++}
++
++static void brcmnand_wr_corr_thresh(struct brcmnand_host *host, u8 val)
++{
++	struct brcmnand_controller *ctrl = host->ctrl;
++	unsigned int shift = 0, bits;
++	enum brcmnand_reg reg = BRCMNAND_CORR_THRESHOLD;
++	int cs = host->cs;
++
++	if (ctrl->nand_version >= 0x0702)
++		bits = 7;
++	else if (ctrl->nand_version >= 0x0600)
++		bits = 6;
++	else if (ctrl->nand_version >= 0x0500)
++		bits = 5;
++	else
++		bits = 4;
++
++	if (ctrl->nand_version >= 0x0702) {
++		if (cs >= 4)
++			reg = BRCMNAND_CORR_THRESHOLD_EXT;
++		shift = (cs % 4) * bits;
++	} else if (ctrl->nand_version >= 0x0600) {
++		if (cs >= 5)
++			reg = BRCMNAND_CORR_THRESHOLD_EXT;
++		shift = (cs % 5) * bits;
++	}
++	brcmnand_rmw_reg(ctrl, reg, (bits - 1) << shift, shift, val);
++}
++
++static inline int brcmnand_cmd_shift(struct brcmnand_controller *ctrl)
++{
++	if (ctrl->nand_version < 0x0602)
++		return 24;
++	return 0;
++}
++
++/***********************************************************************
++ * NAND ACC CONTROL bitfield
++ *
++ * Some bits have remained constant throughout hardware revision, while
++ * others have shifted around.
++ ***********************************************************************/
++
++/* Constant for all versions (where supported) */
++enum {
++	/* See BRCMNAND_HAS_CACHE_MODE */
++	ACC_CONTROL_CACHE_MODE				= BIT(22),
++
++	/* See BRCMNAND_HAS_PREFETCH */
++	ACC_CONTROL_PREFETCH				= BIT(23),
++
++	ACC_CONTROL_PAGE_HIT				= BIT(24),
++	ACC_CONTROL_WR_PREEMPT				= BIT(25),
++	ACC_CONTROL_PARTIAL_PAGE			= BIT(26),
++	ACC_CONTROL_RD_ERASED				= BIT(27),
++	ACC_CONTROL_FAST_PGM_RDIN			= BIT(28),
++	ACC_CONTROL_WR_ECC				= BIT(30),
++	ACC_CONTROL_RD_ECC				= BIT(31),
++};
++
++static inline u32 brcmnand_spare_area_mask(struct brcmnand_controller *ctrl)
++{
++	if (ctrl->nand_version >= 0x0702)
++		return GENMASK(7, 0);
++	else if (ctrl->nand_version >= 0x0600)
++		return GENMASK(6, 0);
++	else
++		return GENMASK(5, 0);
++}
++
++#define NAND_ACC_CONTROL_ECC_SHIFT	16
++#define NAND_ACC_CONTROL_ECC_EXT_SHIFT	13
++
++static inline u32 brcmnand_ecc_level_mask(struct brcmnand_controller *ctrl)
++{
++	u32 mask = (ctrl->nand_version >= 0x0600) ? 0x1f : 0x0f;
++
++	mask <<= NAND_ACC_CONTROL_ECC_SHIFT;
++
++	/* v7.2 includes additional ECC levels */
++	if (ctrl->nand_version >= 0x0702)
++		mask |= 0x7 << NAND_ACC_CONTROL_ECC_EXT_SHIFT;
++
++	return mask;
++}
++
++static void brcmnand_set_ecc_enabled(struct brcmnand_host *host, int en)
++{
++	struct brcmnand_controller *ctrl = host->ctrl;
++	u16 offs = brcmnand_cs_offset(ctrl, host->cs, BRCMNAND_CS_ACC_CONTROL);
++	u32 acc_control = nand_readreg(ctrl, offs);
++	u32 ecc_flags = ACC_CONTROL_WR_ECC | ACC_CONTROL_RD_ECC;
++
++	if (en) {
++		acc_control |= ecc_flags; /* enable RD/WR ECC */
++		acc_control |= host->hwcfg.ecc_level
++			       << NAND_ACC_CONTROL_ECC_SHIFT;
++	} else {
++		acc_control &= ~ecc_flags; /* disable RD/WR ECC */
++		acc_control &= ~brcmnand_ecc_level_mask(ctrl);
++	}
++
++	nand_writereg(ctrl, offs, acc_control);
++}
++
++static inline int brcmnand_sector_1k_shift(struct brcmnand_controller *ctrl)
++{
++	if (ctrl->nand_version >= 0x0702)
++		return 9;
++	else if (ctrl->nand_version >= 0x0600)
++		return 7;
++	else if (ctrl->nand_version >= 0x0500)
++		return 6;
++	else
++		return -1;
++}
++
++static int brcmnand_get_sector_size_1k(struct brcmnand_host *host)
++{
++	struct brcmnand_controller *ctrl = host->ctrl;
++	int shift = brcmnand_sector_1k_shift(ctrl);
++	u16 acc_control_offs = brcmnand_cs_offset(ctrl, host->cs,
++						  BRCMNAND_CS_ACC_CONTROL);
++
++	if (shift < 0)
++		return 0;
++
++	return (nand_readreg(ctrl, acc_control_offs) >> shift) & 0x1;
++}
++
++static void brcmnand_set_sector_size_1k(struct brcmnand_host *host, int val)
++{
++	struct brcmnand_controller *ctrl = host->ctrl;
++	int shift = brcmnand_sector_1k_shift(ctrl);
++	u16 acc_control_offs = brcmnand_cs_offset(ctrl, host->cs,
++						  BRCMNAND_CS_ACC_CONTROL);
++	u32 tmp;
++
++	if (shift < 0)
++		return;
++
++	tmp = nand_readreg(ctrl, acc_control_offs);
++	tmp &= ~(1 << shift);
++	tmp |= (!!val) << shift;
++	nand_writereg(ctrl, acc_control_offs, tmp);
++}
++
++/***********************************************************************
++ * CS_NAND_SELECT
++ ***********************************************************************/
++
++enum {
++	CS_SELECT_NAND_WP			= BIT(29),
++	CS_SELECT_AUTO_DEVICE_ID_CFG		= BIT(30),
++};
++
++static int bcmnand_ctrl_poll_status(struct brcmnand_controller *ctrl,
++				    u32 mask, u32 expected_val,
++				    unsigned long timeout_ms)
++{
++	unsigned long limit;
++	u32 val;
++
++	if (!timeout_ms)
++		timeout_ms = NAND_POLL_STATUS_TIMEOUT_MS;
++
++	limit = jiffies + msecs_to_jiffies(timeout_ms);
++	do {
++		val = brcmnand_read_reg(ctrl, BRCMNAND_INTFC_STATUS);
++		if ((val & mask) == expected_val)
++			return 0;
++
++		cpu_relax();
++	} while (time_after(limit, jiffies));
++
++	dev_warn(ctrl->dev, "timeout on status poll (expected %x got %x)\n",
++		 expected_val, val & mask);
++
++	return -ETIMEDOUT;
++}
++
++static inline void brcmnand_set_wp(struct brcmnand_controller *ctrl, bool en)
++{
++	u32 val = en ? CS_SELECT_NAND_WP : 0;
++
++	brcmnand_rmw_reg(ctrl, BRCMNAND_CS_SELECT, CS_SELECT_NAND_WP, 0, val);
++}
++
++/***********************************************************************
++ * Flash DMA
++ ***********************************************************************/
++
++enum flash_dma_reg {
++	FLASH_DMA_REVISION		= 0x00,
++	FLASH_DMA_FIRST_DESC		= 0x04,
++	FLASH_DMA_FIRST_DESC_EXT	= 0x08,
++	FLASH_DMA_CTRL			= 0x0c,
++	FLASH_DMA_MODE			= 0x10,
++	FLASH_DMA_STATUS		= 0x14,
++	FLASH_DMA_INTERRUPT_DESC	= 0x18,
++	FLASH_DMA_INTERRUPT_DESC_EXT	= 0x1c,
++	FLASH_DMA_ERROR_STATUS		= 0x20,
++	FLASH_DMA_CURRENT_DESC		= 0x24,
++	FLASH_DMA_CURRENT_DESC_EXT	= 0x28,
++};
++
++static inline bool has_flash_dma(struct brcmnand_controller *ctrl)
++{
++	return ctrl->flash_dma_base;
++}
++
++static inline bool flash_dma_buf_ok(const void *buf)
++{
++	return buf && !is_vmalloc_addr(buf) &&
++		likely(IS_ALIGNED((uintptr_t)buf, 4));
++}
++
++static inline void flash_dma_writel(struct brcmnand_controller *ctrl, u8 offs,
++				    u32 val)
++{
++	brcmnand_writel(val, ctrl->flash_dma_base + offs);
++}
++
++static inline u32 flash_dma_readl(struct brcmnand_controller *ctrl, u8 offs)
++{
++	return brcmnand_readl(ctrl->flash_dma_base + offs);
++}
++
++/* Low-level operation types: command, address, write, or read */
++enum brcmnand_llop_type {
++	LL_OP_CMD,
++	LL_OP_ADDR,
++	LL_OP_WR,
++	LL_OP_RD,
++};
++
++/***********************************************************************
++ * Internal support functions
++ ***********************************************************************/
++
++static inline bool is_hamming_ecc(struct brcmnand_controller *ctrl,
++				  struct brcmnand_cfg *cfg)
++{
++	if (ctrl->nand_version <= 0x0701)
++		return cfg->sector_size_1k == 0 && cfg->spare_area_size == 16 &&
++			cfg->ecc_level == 15;
++	else
++		return cfg->sector_size_1k == 0 && ((cfg->spare_area_size == 16 &&
++			cfg->ecc_level == 15) ||
++			(cfg->spare_area_size == 28 && cfg->ecc_level == 16));
++}
++
++/*
++ * Set mtd->ooblayout to the appropriate mtd_ooblayout_ops given
++ * the layout/configuration.
++ * Returns -ERRCODE on failure.
++ */
++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 brcmnand_host *host = nand_get_controller_data(chip);
++	struct brcmnand_cfg *cfg = &host->hwcfg;
++	int sas = cfg->spare_area_size << cfg->sector_size_1k;
++	int sectors = cfg->page_size / (512 << cfg->sector_size_1k);
++
++	if (section >= sectors)
++		return -ERANGE;
++
++	oobregion->offset = (section * sas) + 6;
++	oobregion->length = 3;
++
++	return 0;
++}
++
++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 brcmnand_host *host = nand_get_controller_data(chip);
++	struct brcmnand_cfg *cfg = &host->hwcfg;
++	int sas = cfg->spare_area_size << cfg->sector_size_1k;
++	int sectors = cfg->page_size / (512 << cfg->sector_size_1k);
++
++	if (section >= sectors * 2)
++		return -ERANGE;
++
++	oobregion->offset = (section / 2) * sas;
++
++	if (section & 1) {
++		oobregion->offset += 9;
++		oobregion->length = 7;
++	} else {
++		oobregion->length = 6;
++
++		/* First sector of each page may have BBI */
++		if (!section) {
++			/*
++			 * Small-page NAND use byte 6 for BBI while large-page
++			 * NAND use byte 0.
++			 */
++			if (cfg->page_size > 512)
++				oobregion->offset++;
++			oobregion->length--;
++		}
++	}
++
++	return 0;
++}
++
++static const struct mtd_ooblayout_ops brcmnand_hamming_ooblayout_ops = {
++	.ecc = brcmnand_hamming_ooblayout_ecc,
++	.free = brcmnand_hamming_ooblayout_free,
++};
++
++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 brcmnand_host *host = nand_get_controller_data(chip);
++	struct brcmnand_cfg *cfg = &host->hwcfg;
++	int sas = cfg->spare_area_size << cfg->sector_size_1k;
++	int sectors = cfg->page_size / (512 << cfg->sector_size_1k);
++
++	if (section >= sectors)
++		return -ERANGE;
++
++	oobregion->offset = (section * (sas + 1)) - chip->ecc.bytes;
++	oobregion->length = chip->ecc.bytes;
++
++	return 0;
++}
++
++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 brcmnand_host *host = nand_get_controller_data(chip);
++	struct brcmnand_cfg *cfg = &host->hwcfg;
++	int sas = cfg->spare_area_size << cfg->sector_size_1k;
++	int sectors = cfg->page_size / (512 << cfg->sector_size_1k);
++
++	if (section >= sectors)
++		return -ERANGE;
++
++	if (sas <= chip->ecc.bytes)
++		return 0;
++
++	oobregion->offset = section * sas;
++	oobregion->length = sas - chip->ecc.bytes;
++
++	if (!section) {
++		oobregion->offset++;
++		oobregion->length--;
++	}
++
++	return 0;
++}
++
++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 brcmnand_host *host = nand_get_controller_data(chip);
++	struct brcmnand_cfg *cfg = &host->hwcfg;
++	int sas = cfg->spare_area_size << cfg->sector_size_1k;
++
++	if (section > 1 || sas - chip->ecc.bytes < 6 ||
++	    (section && sas - chip->ecc.bytes == 6))
++		return -ERANGE;
++
++	if (!section) {
++		oobregion->offset = 0;
++		oobregion->length = 5;
++	} else {
++		oobregion->offset = 6;
++		oobregion->length = sas - chip->ecc.bytes - 6;
++	}
++
++	return 0;
++}
++
++static const struct mtd_ooblayout_ops brcmnand_bch_lp_ooblayout_ops = {
++	.ecc = brcmnand_bch_ooblayout_ecc,
++	.free = brcmnand_bch_ooblayout_free_lp,
++};
++
++static const struct mtd_ooblayout_ops brcmnand_bch_sp_ooblayout_ops = {
++	.ecc = brcmnand_bch_ooblayout_ecc,
++	.free = brcmnand_bch_ooblayout_free_sp,
++};
++
++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 nand_ecc_ctrl *ecc = &host->chip.ecc;
++	unsigned int ecc_level = p->ecc_level;
++	int sas = p->spare_area_size << p->sector_size_1k;
++	int sectors = p->page_size / (512 << p->sector_size_1k);
++
++	if (p->sector_size_1k)
++		ecc_level <<= 1;
++
++	if (is_hamming_ecc(host->ctrl, p)) {
++		ecc->bytes = 3 * sectors;
++		mtd_set_ooblayout(mtd, &brcmnand_hamming_ooblayout_ops);
++		return 0;
++	}
++
++	/*
++	 * CONTROLLER_VERSION:
++	 *   < v5.0: ECC_REQ = ceil(BCH_T * 13/8)
++	 *  >= v5.0: ECC_REQ = ceil(BCH_T * 14/8)
++	 * But we will just be conservative.
++	 */
++	ecc->bytes = DIV_ROUND_UP(ecc_level * 14, 8);
++	if (p->page_size == 512)
++		mtd_set_ooblayout(mtd, &brcmnand_bch_sp_ooblayout_ops);
++	else
++		mtd_set_ooblayout(mtd, &brcmnand_bch_lp_ooblayout_ops);
++
++	if (ecc->bytes >= sas) {
++		dev_err(&host->pdev->dev,
++			"error: ECC too large for OOB (ECC bytes %d, spare sector %d)\n",
++			ecc->bytes, sas);
++		return -EINVAL;
++	}
++
++	return 0;
++}
++
++static void brcmnand_wp(struct mtd_info *mtd, int wp)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct brcmnand_host *host = nand_get_controller_data(chip);
++	struct brcmnand_controller *ctrl = host->ctrl;
++
++	if ((ctrl->features & BRCMNAND_HAS_WP) && wp_on == 1) {
++		static int old_wp = -1;
++		int ret;
++
++		if (old_wp != wp) {
++			dev_dbg(ctrl->dev, "WP %s\n", wp ? "on" : "off");
++			old_wp = wp;
++		}
++
++		/*
++		 * make sure ctrl/flash ready before and after
++		 * changing state of #WP pin
++		 */
++		ret = bcmnand_ctrl_poll_status(ctrl, NAND_CTRL_RDY |
++					       NAND_STATUS_READY,
++					       NAND_CTRL_RDY |
++					       NAND_STATUS_READY, 0);
++		if (ret)
++			return;
++
++		brcmnand_set_wp(ctrl, wp);
++		chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
++		/* NAND_STATUS_WP 0x00 = protected, 0x80 = not protected */
++		ret = bcmnand_ctrl_poll_status(ctrl,
++					       NAND_CTRL_RDY |
++					       NAND_STATUS_READY |
++					       NAND_STATUS_WP,
++					       NAND_CTRL_RDY |
++					       NAND_STATUS_READY |
++					       (wp ? 0 : NAND_STATUS_WP), 0);
++
++		if (ret)
++			dev_err_ratelimited(&host->pdev->dev,
++					    "nand #WP expected %s\n",
++					    wp ? "on" : "off");
++	}
++}
++
++/* Helper functions for reading and writing OOB registers */
++static inline u8 oob_reg_read(struct brcmnand_controller *ctrl, u32 offs)
++{
++	u16 offset0, offset10, reg_offs;
++
++	offset0 = ctrl->reg_offsets[BRCMNAND_OOB_READ_BASE];
++	offset10 = ctrl->reg_offsets[BRCMNAND_OOB_READ_10_BASE];
++
++	if (offs >= ctrl->max_oob)
++		return 0x77;
++
++	if (offs >= 16 && offset10)
++		reg_offs = offset10 + ((offs - 0x10) & ~0x03);
++	else
++		reg_offs = offset0 + (offs & ~0x03);
++
++	return nand_readreg(ctrl, reg_offs) >> (24 - ((offs & 0x03) << 3));
++}
++
++static inline void oob_reg_write(struct brcmnand_controller *ctrl, u32 offs,
++				 u32 data)
++{
++	u16 offset0, offset10, reg_offs;
++
++	offset0 = ctrl->reg_offsets[BRCMNAND_OOB_WRITE_BASE];
++	offset10 = ctrl->reg_offsets[BRCMNAND_OOB_WRITE_10_BASE];
++
++	if (offs >= ctrl->max_oob)
++		return;
++
++	if (offs >= 16 && offset10)
++		reg_offs = offset10 + ((offs - 0x10) & ~0x03);
++	else
++		reg_offs = offset0 + (offs & ~0x03);
++
++	nand_writereg(ctrl, reg_offs, data);
++}
++
++/*
++ * read_oob_from_regs - read data from OOB registers
++ * @ctrl: NAND controller
++ * @i: sub-page sector index
++ * @oob: buffer to read to
++ * @sas: spare area sector size (i.e., OOB size per FLASH_CACHE)
++ * @sector_1k: 1 for 1KiB sectors, 0 for 512B, other values are illegal
++ */
++static int read_oob_from_regs(struct brcmnand_controller *ctrl, int i, u8 *oob,
++			      int sas, int sector_1k)
++{
++	int tbytes = sas << sector_1k;
++	int j;
++
++	/* Adjust OOB values for 1K sector size */
++	if (sector_1k && (i & 0x01))
++		tbytes = max(0, tbytes - (int)ctrl->max_oob);
++	tbytes = min_t(int, tbytes, ctrl->max_oob);
++
++	for (j = 0; j < tbytes; j++)
++		oob[j] = oob_reg_read(ctrl, j);
++	return tbytes;
++}
++
++/*
++ * write_oob_to_regs - write data to OOB registers
++ * @i: sub-page sector index
++ * @oob: buffer to write from
++ * @sas: spare area sector size (i.e., OOB size per FLASH_CACHE)
++ * @sector_1k: 1 for 1KiB sectors, 0 for 512B, other values are illegal
++ */
++static int write_oob_to_regs(struct brcmnand_controller *ctrl, int i,
++			     const u8 *oob, int sas, int sector_1k)
++{
++	int tbytes = sas << sector_1k;
++	int j;
++
++	/* Adjust OOB values for 1K sector size */
++	if (sector_1k && (i & 0x01))
++		tbytes = max(0, tbytes - (int)ctrl->max_oob);
++	tbytes = min_t(int, tbytes, ctrl->max_oob);
++
++	for (j = 0; j < tbytes; j += 4)
++		oob_reg_write(ctrl, j,
++				(oob[j + 0] << 24) |
++				(oob[j + 1] << 16) |
++				(oob[j + 2] <<  8) |
++				(oob[j + 3] <<  0));
++	return tbytes;
++}
++
++static irqreturn_t brcmnand_ctlrdy_irq(int irq, void *data)
++{
++	struct brcmnand_controller *ctrl = data;
++
++	/* Discard all NAND_CTLRDY interrupts during DMA */
++	if (ctrl->dma_pending)
++		return IRQ_HANDLED;
++
++	complete(&ctrl->done);
++	return IRQ_HANDLED;
++}
++
++/* Handle SoC-specific interrupt hardware */
++static irqreturn_t brcmnand_irq(int irq, void *data)
++{
++	struct brcmnand_controller *ctrl = data;
++
++	if (ctrl->soc->ctlrdy_ack(ctrl->soc))
++		return brcmnand_ctlrdy_irq(irq, data);
++
++	return IRQ_NONE;
++}
++
++static irqreturn_t brcmnand_dma_irq(int irq, void *data)
++{
++	struct brcmnand_controller *ctrl = data;
++
++	complete(&ctrl->dma_done);
++
++	return IRQ_HANDLED;
++}
++
++static void brcmnand_send_cmd(struct brcmnand_host *host, int cmd)
++{
++	struct brcmnand_controller *ctrl = host->ctrl;
++	int ret;
++
++	dev_dbg(ctrl->dev, "send native cmd %d addr_lo 0x%x\n", cmd,
++		brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS));
++	BUG_ON(ctrl->cmd_pending != 0);
++	ctrl->cmd_pending = cmd;
++
++	ret = bcmnand_ctrl_poll_status(ctrl, NAND_CTRL_RDY, NAND_CTRL_RDY, 0);
++	WARN_ON(ret);
++
++	mb(); /* flush previous writes */
++	brcmnand_write_reg(ctrl, BRCMNAND_CMD_START,
++			   cmd << brcmnand_cmd_shift(ctrl));
++}
++
++/***********************************************************************
++ * NAND MTD API: read/program/erase
++ ***********************************************************************/
++
++static void brcmnand_cmd_ctrl(struct mtd_info *mtd, int dat,
++	unsigned int ctrl)
++{
++	/* intentionally left blank */
++}
++
++static int brcmnand_waitfunc(struct mtd_info *mtd, struct nand_chip *this)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct brcmnand_host *host = nand_get_controller_data(chip);
++	struct brcmnand_controller *ctrl = host->ctrl;
++	unsigned long timeo = msecs_to_jiffies(100);
++
++	dev_dbg(ctrl->dev, "wait on native cmd %d\n", ctrl->cmd_pending);
++	if (ctrl->cmd_pending &&
++			wait_for_completion_timeout(&ctrl->done, timeo) <= 0) {
++		u32 cmd = brcmnand_read_reg(ctrl, BRCMNAND_CMD_START)
++					>> brcmnand_cmd_shift(ctrl);
++
++		dev_err_ratelimited(ctrl->dev,
++			"timeout waiting for command %#02x\n", cmd);
++		dev_err_ratelimited(ctrl->dev, "intfc status %08x\n",
++			brcmnand_read_reg(ctrl, BRCMNAND_INTFC_STATUS));
++	}
++	ctrl->cmd_pending = 0;
++	return brcmnand_read_reg(ctrl, BRCMNAND_INTFC_STATUS) &
++				 INTFC_FLASH_STATUS;
++}
++
++enum {
++	LLOP_RE				= BIT(16),
++	LLOP_WE				= BIT(17),
++	LLOP_ALE			= BIT(18),
++	LLOP_CLE			= BIT(19),
++	LLOP_RETURN_IDLE		= BIT(31),
++
++	LLOP_DATA_MASK			= GENMASK(15, 0),
++};
++
++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 nand_chip *chip = &host->chip;
++	struct brcmnand_controller *ctrl = host->ctrl;
++	u32 tmp;
++
++	tmp = data & LLOP_DATA_MASK;
++	switch (type) {
++	case LL_OP_CMD:
++		tmp |= LLOP_WE | LLOP_CLE;
++		break;
++	case LL_OP_ADDR:
++		/* WE | ALE */
++		tmp |= LLOP_WE | LLOP_ALE;
++		break;
++	case LL_OP_WR:
++		/* WE */
++		tmp |= LLOP_WE;
++		break;
++	case LL_OP_RD:
++		/* RE */
++		tmp |= LLOP_RE;
++		break;
++	}
++	if (last_op)
++		/* RETURN_IDLE */
++		tmp |= LLOP_RETURN_IDLE;
++
++	dev_dbg(ctrl->dev, "ll_op cmd %#x\n", tmp);
++
++	brcmnand_write_reg(ctrl, BRCMNAND_LL_OP, tmp);
++	(void)brcmnand_read_reg(ctrl, BRCMNAND_LL_OP);
++
++	brcmnand_send_cmd(host, CMD_LOW_LEVEL_OP);
++	return brcmnand_waitfunc(mtd, chip);
++}
++
++static void brcmnand_cmdfunc(struct mtd_info *mtd, unsigned command,
++			     int column, int page_addr)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct brcmnand_host *host = nand_get_controller_data(chip);
++	struct brcmnand_controller *ctrl = host->ctrl;
++	u64 addr = (u64)page_addr << chip->page_shift;
++	int native_cmd = 0;
++
++	if (command == NAND_CMD_READID || command == NAND_CMD_PARAM ||
++			command == NAND_CMD_RNDOUT)
++		addr = (u64)column;
++	/* Avoid propagating a negative, don't-care address */
++	else if (page_addr < 0)
++		addr = 0;
++
++	dev_dbg(ctrl->dev, "cmd 0x%x addr 0x%llx\n", command,
++		(unsigned long long)addr);
++
++	host->last_cmd = command;
++	host->last_byte = 0;
++	host->last_addr = addr;
++
++	switch (command) {
++	case NAND_CMD_RESET:
++		native_cmd = CMD_FLASH_RESET;
++		break;
++	case NAND_CMD_STATUS:
++		native_cmd = CMD_STATUS_READ;
++		break;
++	case NAND_CMD_READID:
++		native_cmd = CMD_DEVICE_ID_READ;
++		break;
++	case NAND_CMD_READOOB:
++		native_cmd = CMD_SPARE_AREA_READ;
++		break;
++	case NAND_CMD_ERASE1:
++		native_cmd = CMD_BLOCK_ERASE;
++		brcmnand_wp(mtd, 0);
++		break;
++	case NAND_CMD_PARAM:
++		native_cmd = CMD_PARAMETER_READ;
++		break;
++	case NAND_CMD_SET_FEATURES:
++	case NAND_CMD_GET_FEATURES:
++		brcmnand_low_level_op(host, LL_OP_CMD, command, false);
++		brcmnand_low_level_op(host, LL_OP_ADDR, column, false);
++		break;
++	case NAND_CMD_RNDOUT:
++		native_cmd = CMD_PARAMETER_CHANGE_COL;
++		addr &= ~((u64)(FC_BYTES - 1));
++		/*
++		 * HW quirk: PARAMETER_CHANGE_COL requires SECTOR_SIZE_1K=0
++		 * NB: hwcfg.sector_size_1k may not be initialized yet
++		 */
++		if (brcmnand_get_sector_size_1k(host)) {
++			host->hwcfg.sector_size_1k =
++				brcmnand_get_sector_size_1k(host);
++			brcmnand_set_sector_size_1k(host, 0);
++		}
++		break;
++	}
++
++	if (!native_cmd)
++		return;
++
++	brcmnand_write_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS,
++		(host->cs << 16) | ((addr >> 32) & 0xffff));
++	(void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS);
++	brcmnand_write_reg(ctrl, BRCMNAND_CMD_ADDRESS, lower_32_bits(addr));
++	(void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS);
++
++	brcmnand_send_cmd(host, native_cmd);
++	brcmnand_waitfunc(mtd, chip);
++
++	if (native_cmd == CMD_PARAMETER_READ ||
++			native_cmd == CMD_PARAMETER_CHANGE_COL) {
++		/* Copy flash cache word-wise */
++		u32 *flash_cache = (u32 *)ctrl->flash_cache;
++		int i;
++
++		brcmnand_soc_data_bus_prepare(ctrl->soc, true);
++
++		/*
++		 * Must cache the FLASH_CACHE now, since changes in
++		 * SECTOR_SIZE_1K may invalidate it
++		 */
++		for (i = 0; i < FC_WORDS; i++)
++			/*
++			 * Flash cache is big endian for parameter pages, at
++			 * least on STB SoCs
++			 */
++			flash_cache[i] = be32_to_cpu(brcmnand_read_fc(ctrl, i));
++
++		brcmnand_soc_data_bus_unprepare(ctrl->soc, true);
++
++		/* Cleanup from HW quirk: restore SECTOR_SIZE_1K */
++		if (host->hwcfg.sector_size_1k)
++			brcmnand_set_sector_size_1k(host,
++						    host->hwcfg.sector_size_1k);
++	}
++
++	/* Re-enable protection is necessary only after erase */
++	if (command == NAND_CMD_ERASE1)
++		brcmnand_wp(mtd, 1);
++}
++
++static uint8_t brcmnand_read_byte(struct mtd_info *mtd)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct brcmnand_host *host = nand_get_controller_data(chip);
++	struct brcmnand_controller *ctrl = host->ctrl;
++	uint8_t ret = 0;
++	int addr, offs;
++
++	switch (host->last_cmd) {
++	case NAND_CMD_READID:
++		if (host->last_byte < 4)
++			ret = brcmnand_read_reg(ctrl, BRCMNAND_ID) >>
++				(24 - (host->last_byte << 3));
++		else if (host->last_byte < 8)
++			ret = brcmnand_read_reg(ctrl, BRCMNAND_ID_EXT) >>
++				(56 - (host->last_byte << 3));
++		break;
++
++	case NAND_CMD_READOOB:
++		ret = oob_reg_read(ctrl, host->last_byte);
++		break;
++
++	case NAND_CMD_STATUS:
++		ret = brcmnand_read_reg(ctrl, BRCMNAND_INTFC_STATUS) &
++					INTFC_FLASH_STATUS;
++		if (wp_on) /* hide WP status */
++			ret |= NAND_STATUS_WP;
++		break;
++
++	case NAND_CMD_PARAM:
++	case NAND_CMD_RNDOUT:
++		addr = host->last_addr + host->last_byte;
++		offs = addr & (FC_BYTES - 1);
++
++		/* At FC_BYTES boundary, switch to next column */
++		if (host->last_byte > 0 && offs == 0)
++			chip->cmdfunc(mtd, NAND_CMD_RNDOUT, addr, -1);
++
++		ret = ctrl->flash_cache[offs];
++		break;
++	case NAND_CMD_GET_FEATURES:
++		if (host->last_byte >= ONFI_SUBFEATURE_PARAM_LEN) {
++			ret = 0;
++		} else {
++			bool last = host->last_byte ==
++				ONFI_SUBFEATURE_PARAM_LEN - 1;
++			brcmnand_low_level_op(host, LL_OP_RD, 0, last);
++			ret = brcmnand_read_reg(ctrl, BRCMNAND_LL_RDATA) & 0xff;
++		}
++	}
++
++	dev_dbg(ctrl->dev, "read byte = 0x%02x\n", ret);
++	host->last_byte++;
++
++	return ret;
++}
++
++static void brcmnand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
++{
++	int i;
++
++	for (i = 0; i < len; i++, buf++)
++		*buf = brcmnand_read_byte(mtd);
++}
++
++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 brcmnand_host *host = nand_get_controller_data(chip);
++
++	switch (host->last_cmd) {
++	case NAND_CMD_SET_FEATURES:
++		for (i = 0; i < len; i++)
++			brcmnand_low_level_op(host, LL_OP_WR, buf[i],
++						  (i + 1) == len);
++		break;
++	default:
++		BUG();
++		break;
++	}
++}
++
++/**
++ * Construct a FLASH_DMA descriptor as part of a linked list. You must know the
++ * following ahead of time:
++ *  - Is this descriptor the beginning or end of a linked list?
++ *  - What is the (DMA) address of the next descriptor in the linked list?
++ */
++static int brcmnand_fill_dma_desc(struct brcmnand_host *host,
++				  struct brcm_nand_dma_desc *desc, u64 addr,
++				  dma_addr_t buf, u32 len, u8 dma_cmd,
++				  bool begin, bool end,
++				  dma_addr_t next_desc)
++{
++	memset(desc, 0, sizeof(*desc));
++	/* Descriptors are written in native byte order (wordwise) */
++	desc->next_desc = lower_32_bits(next_desc);
++	desc->next_desc_ext = upper_32_bits(next_desc);
++	desc->cmd_irq = (dma_cmd << 24) |
++		(end ? (0x03 << 8) : 0) | /* IRQ | STOP */
++		(!!begin) | ((!!end) << 1); /* head, tail */
++#ifdef CONFIG_CPU_BIG_ENDIAN
++	desc->cmd_irq |= 0x01 << 12;
++#endif
++	desc->dram_addr = lower_32_bits(buf);
++	desc->dram_addr_ext = upper_32_bits(buf);
++	desc->tfr_len = len;
++	desc->total_len = len;
++	desc->flash_addr = lower_32_bits(addr);
++	desc->flash_addr_ext = upper_32_bits(addr);
++	desc->cs = host->cs;
++	desc->status_valid = 0x01;
++	return 0;
++}
++
++/**
++ * Kick the FLASH_DMA engine, with a given DMA descriptor
++ */
++static void brcmnand_dma_run(struct brcmnand_host *host, dma_addr_t desc)
++{
++	struct brcmnand_controller *ctrl = host->ctrl;
++	unsigned long timeo = msecs_to_jiffies(100);
++
++	flash_dma_writel(ctrl, FLASH_DMA_FIRST_DESC, lower_32_bits(desc));
++	(void)flash_dma_readl(ctrl, FLASH_DMA_FIRST_DESC);
++	flash_dma_writel(ctrl, FLASH_DMA_FIRST_DESC_EXT, upper_32_bits(desc));
++	(void)flash_dma_readl(ctrl, FLASH_DMA_FIRST_DESC_EXT);
++
++	/* Start FLASH_DMA engine */
++	ctrl->dma_pending = true;
++	mb(); /* flush previous writes */
++	flash_dma_writel(ctrl, FLASH_DMA_CTRL, 0x03); /* wake | run */
++
++	if (wait_for_completion_timeout(&ctrl->dma_done, timeo) <= 0) {
++		dev_err(ctrl->dev,
++				"timeout waiting for DMA; status %#x, error status %#x\n",
++				flash_dma_readl(ctrl, FLASH_DMA_STATUS),
++				flash_dma_readl(ctrl, FLASH_DMA_ERROR_STATUS));
++	}
++	ctrl->dma_pending = false;
++	flash_dma_writel(ctrl, FLASH_DMA_CTRL, 0); /* force stop */
++}
++
++static int brcmnand_dma_trans(struct brcmnand_host *host, u64 addr, u32 *buf,
++			      u32 len, u8 dma_cmd)
++{
++	struct brcmnand_controller *ctrl = host->ctrl;
++	dma_addr_t buf_pa;
++	int dir = dma_cmd == CMD_PAGE_READ ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
++
++	buf_pa = dma_map_single(ctrl->dev, buf, len, dir);
++	if (dma_mapping_error(ctrl->dev, buf_pa)) {
++		dev_err(ctrl->dev, "unable to map buffer for DMA\n");
++		return -ENOMEM;
++	}
++
++	brcmnand_fill_dma_desc(host, ctrl->dma_desc, addr, buf_pa, len,
++				   dma_cmd, true, true, 0);
++
++	brcmnand_dma_run(host, ctrl->dma_pa);
++
++	dma_unmap_single(ctrl->dev, buf_pa, len, dir);
++
++	if (ctrl->dma_desc->status_valid & FLASH_DMA_ECC_ERROR)
++		return -EBADMSG;
++	else if (ctrl->dma_desc->status_valid & FLASH_DMA_CORR_ERROR)
++		return -EUCLEAN;
++
++	return 0;
++}
++
++/*
++ * Assumes proper CS is already set
++ */
++static int brcmnand_read_by_pio(struct mtd_info *mtd, struct nand_chip *chip,
++				u64 addr, unsigned int trans, u32 *buf,
++				u8 *oob, u64 *err_addr)
++{
++	struct brcmnand_host *host = nand_get_controller_data(chip);
++	struct brcmnand_controller *ctrl = host->ctrl;
++	int i, j, ret = 0;
++
++	/* Clear error addresses */
++	brcmnand_write_reg(ctrl, BRCMNAND_UNCORR_ADDR, 0);
++	brcmnand_write_reg(ctrl, BRCMNAND_CORR_ADDR, 0);
++	brcmnand_write_reg(ctrl, BRCMNAND_UNCORR_EXT_ADDR, 0);
++	brcmnand_write_reg(ctrl, BRCMNAND_CORR_EXT_ADDR, 0);
++
++	brcmnand_write_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS,
++			(host->cs << 16) | ((addr >> 32) & 0xffff));
++	(void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS);
++
++	for (i = 0; i < trans; i++, addr += FC_BYTES) {
++		brcmnand_write_reg(ctrl, BRCMNAND_CMD_ADDRESS,
++				   lower_32_bits(addr));
++		(void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS);
++		/* SPARE_AREA_READ does not use ECC, so just use PAGE_READ */
++		brcmnand_send_cmd(host, CMD_PAGE_READ);
++		brcmnand_waitfunc(mtd, chip);
++
++		if (likely(buf)) {
++			brcmnand_soc_data_bus_prepare(ctrl->soc, false);
++
++			for (j = 0; j < FC_WORDS; j++, buf++)
++				*buf = brcmnand_read_fc(ctrl, j);
++
++			brcmnand_soc_data_bus_unprepare(ctrl->soc, false);
++		}
++
++		if (oob)
++			oob += read_oob_from_regs(ctrl, i, oob,
++					mtd->oobsize / trans,
++					host->hwcfg.sector_size_1k);
++
++		if (!ret) {
++			*err_addr = brcmnand_read_reg(ctrl,
++					BRCMNAND_UNCORR_ADDR) |
++				((u64)(brcmnand_read_reg(ctrl,
++						BRCMNAND_UNCORR_EXT_ADDR)
++					& 0xffff) << 32);
++			if (*err_addr)
++				ret = -EBADMSG;
++		}
++
++		if (!ret) {
++			*err_addr = brcmnand_read_reg(ctrl,
++					BRCMNAND_CORR_ADDR) |
++				((u64)(brcmnand_read_reg(ctrl,
++						BRCMNAND_CORR_EXT_ADDR)
++					& 0xffff) << 32);
++			if (*err_addr)
++				ret = -EUCLEAN;
++		}
++	}
++
++	return ret;
++}
++
++/*
++ * Check a page to see if it is erased (w/ bitflips) after an uncorrectable ECC
++ * error
++ *
++ * Because the HW ECC signals an ECC error if an erase paged has even a single
++ * bitflip, we must check each ECC error to see if it is actually an erased
++ * page with bitflips, not a truly corrupted page.
++ *
++ * On a real error, return a negative error code (-EBADMSG for ECC error), and
++ * buf will contain raw data.
++ * Otherwise, buf gets filled with 0xffs and return the maximum number of
++ * bitflips-per-ECC-sector to the caller.
++ *
++ */
++static int brcmstb_nand_verify_erased_page(struct mtd_info *mtd,
++		  struct nand_chip *chip, void *buf, u64 addr)
++{
++	int i, sas;
++	void *oob = chip->oob_poi;
++	int bitflips = 0;
++	int page = addr >> chip->page_shift;
++	int ret;
++
++	if (!buf) {
++		buf = chip->buffers->databuf;
++		/* Invalidate page cache */
++		chip->pagebuf = -1;
++	}
++
++	sas = mtd->oobsize / chip->ecc.steps;
++
++	/* read without ecc for verification */
++	chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
++	ret = chip->ecc.read_page_raw(mtd, chip, buf, true, page);
++	if (ret)
++		return ret;
++
++	for (i = 0; i < chip->ecc.steps; i++, oob += sas) {
++		ret = nand_check_erased_ecc_chunk(buf, chip->ecc.size,
++						  oob, sas, NULL, 0,
++						  chip->ecc.strength);
++		if (ret < 0)
++			return ret;
++
++		bitflips = max(bitflips, ret);
++	}
++
++	return bitflips;
++}
++
++static int brcmnand_read(struct mtd_info *mtd, struct nand_chip *chip,
++			 u64 addr, unsigned int trans, u32 *buf, u8 *oob)
++{
++	struct brcmnand_host *host = nand_get_controller_data(chip);
++	struct brcmnand_controller *ctrl = host->ctrl;
++	u64 err_addr = 0;
++	int err;
++	bool retry = true;
++
++	dev_dbg(ctrl->dev, "read %llx -> %p\n", (unsigned long long)addr, buf);
++
++try_dmaread:
++	brcmnand_write_reg(ctrl, BRCMNAND_UNCORR_COUNT, 0);
++
++	if (has_flash_dma(ctrl) && !oob && flash_dma_buf_ok(buf)) {
++		err = brcmnand_dma_trans(host, addr, buf, trans * FC_BYTES,
++					     CMD_PAGE_READ);
++		if (err) {
++			if (mtd_is_bitflip_or_eccerr(err))
++				err_addr = addr;
++			else
++				return -EIO;
++		}
++	} else {
++		if (oob)
++			memset(oob, 0x99, mtd->oobsize);
++
++		err = brcmnand_read_by_pio(mtd, chip, addr, trans, buf,
++					       oob, &err_addr);
++	}
++
++	if (mtd_is_eccerr(err)) {
++		/*
++		 * On controller version and 7.0, 7.1 , DMA read after a
++		 * prior PIO read that reported uncorrectable error,
++		 * the DMA engine captures this error following DMA read
++		 * cleared only on subsequent DMA read, so just retry once
++		 * to clear a possible false error reported for current DMA
++		 * read
++		 */
++		if ((ctrl->nand_version == 0x0700) ||
++		    (ctrl->nand_version == 0x0701)) {
++			if (retry) {
++				retry = false;
++				goto try_dmaread;
++			}
++		}
++
++		/*
++		 * Controller version 7.2 has hw encoder to detect erased page
++		 * bitflips, apply sw verification for older controllers only
++		 */
++		if (ctrl->nand_version < 0x0702) {
++			err = brcmstb_nand_verify_erased_page(mtd, chip, buf,
++							      addr);
++			/* erased page bitflips corrected */
++			if (err > 0)
++				return err;
++		}
++
++		dev_dbg(ctrl->dev, "uncorrectable error at 0x%llx\n",
++			(unsigned long long)err_addr);
++		mtd->ecc_stats.failed++;
++		/* NAND layer expects zero on ECC errors */
++		return 0;
++	}
++
++	if (mtd_is_bitflip(err)) {
++		unsigned int corrected = brcmnand_count_corrected(ctrl);
++
++		dev_dbg(ctrl->dev, "corrected error at 0x%llx\n",
++			(unsigned long long)err_addr);
++		mtd->ecc_stats.corrected += corrected;
++		/* Always exceed the software-imposed threshold */
++		return max(mtd->bitflip_threshold, corrected);
++	}
++
++	return 0;
++}
++
++static int brcmnand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
++			      uint8_t *buf, int oob_required, int page)
++{
++	struct brcmnand_host *host = nand_get_controller_data(chip);
++	u8 *oob = oob_required ? (u8 *)chip->oob_poi : NULL;
++
++	return brcmnand_read(mtd, chip, host->last_addr,
++			mtd->writesize >> FC_SHIFT, (u32 *)buf, oob);
++}
++
++static int brcmnand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
++				  uint8_t *buf, int oob_required, int page)
++{
++	struct brcmnand_host *host = nand_get_controller_data(chip);
++	u8 *oob = oob_required ? (u8 *)chip->oob_poi : NULL;
++	int ret;
++
++	brcmnand_set_ecc_enabled(host, 0);
++	ret = brcmnand_read(mtd, chip, host->last_addr,
++			mtd->writesize >> FC_SHIFT, (u32 *)buf, oob);
++	brcmnand_set_ecc_enabled(host, 1);
++	return ret;
++}
++
++static int brcmnand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
++			     int page)
++{
++	return brcmnand_read(mtd, chip, (u64)page << chip->page_shift,
++			mtd->writesize >> FC_SHIFT,
++			NULL, (u8 *)chip->oob_poi);
++}
++
++static int brcmnand_read_oob_raw(struct mtd_info *mtd, struct nand_chip *chip,
++				 int page)
++{
++	struct brcmnand_host *host = nand_get_controller_data(chip);
++
++	brcmnand_set_ecc_enabled(host, 0);
++	brcmnand_read(mtd, chip, (u64)page << chip->page_shift,
++		mtd->writesize >> FC_SHIFT,
++		NULL, (u8 *)chip->oob_poi);
++	brcmnand_set_ecc_enabled(host, 1);
++	return 0;
++}
++
++static int brcmnand_write(struct mtd_info *mtd, struct nand_chip *chip,
++			  u64 addr, const u32 *buf, u8 *oob)
++{
++	struct brcmnand_host *host = nand_get_controller_data(chip);
++	struct brcmnand_controller *ctrl = host->ctrl;
++	unsigned int i, j, trans = mtd->writesize >> FC_SHIFT;
++	int status, ret = 0;
++
++	dev_dbg(ctrl->dev, "write %llx <- %p\n", (unsigned long long)addr, buf);
++
++	if (unlikely((unsigned long)buf & 0x03)) {
++		dev_warn(ctrl->dev, "unaligned buffer: %p\n", buf);
++		buf = (u32 *)((unsigned long)buf & ~0x03);
++	}
++
++	brcmnand_wp(mtd, 0);
++
++	for (i = 0; i < ctrl->max_oob; i += 4)
++		oob_reg_write(ctrl, i, 0xffffffff);
++
++	if (has_flash_dma(ctrl) && !oob && flash_dma_buf_ok(buf)) {
++		if (brcmnand_dma_trans(host, addr, (u32 *)buf,
++					mtd->writesize, CMD_PROGRAM_PAGE))
++			ret = -EIO;
++		goto out;
++	}
++
++	brcmnand_write_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS,
++			(host->cs << 16) | ((addr >> 32) & 0xffff));
++	(void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS);
++
++	for (i = 0; i < trans; i++, addr += FC_BYTES) {
++		/* full address MUST be set before populating FC */
++		brcmnand_write_reg(ctrl, BRCMNAND_CMD_ADDRESS,
++				   lower_32_bits(addr));
++		(void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS);
++
++		if (buf) {
++			brcmnand_soc_data_bus_prepare(ctrl->soc, false);
++
++			for (j = 0; j < FC_WORDS; j++, buf++)
++				brcmnand_write_fc(ctrl, j, *buf);
++
++			brcmnand_soc_data_bus_unprepare(ctrl->soc, false);
++		} else if (oob) {
++			for (j = 0; j < FC_WORDS; j++)
++				brcmnand_write_fc(ctrl, j, 0xffffffff);
++		}
++
++		if (oob) {
++			oob += write_oob_to_regs(ctrl, i, oob,
++					mtd->oobsize / trans,
++					host->hwcfg.sector_size_1k);
++		}
++
++		/* we cannot use SPARE_AREA_PROGRAM when PARTIAL_PAGE_EN=0 */
++		brcmnand_send_cmd(host, CMD_PROGRAM_PAGE);
++		status = brcmnand_waitfunc(mtd, chip);
++
++		if (status & NAND_STATUS_FAIL) {
++			dev_info(ctrl->dev, "program failed at %llx\n",
++				(unsigned long long)addr);
++			ret = -EIO;
++			goto out;
++		}
++	}
++out:
++	brcmnand_wp(mtd, 1);
++	return ret;
++}
++
++static int brcmnand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
++			       const uint8_t *buf, int oob_required, int page)
++{
++	struct brcmnand_host *host = nand_get_controller_data(chip);
++	void *oob = oob_required ? chip->oob_poi : NULL;
++
++	brcmnand_write(mtd, chip, host->last_addr, (const u32 *)buf, oob);
++	return 0;
++}
++
++static int brcmnand_write_page_raw(struct mtd_info *mtd,
++				   struct nand_chip *chip, const uint8_t *buf,
++				   int oob_required, int page)
++{
++	struct brcmnand_host *host = nand_get_controller_data(chip);
++	void *oob = oob_required ? chip->oob_poi : NULL;
++
++	brcmnand_set_ecc_enabled(host, 0);
++	brcmnand_write(mtd, chip, host->last_addr, (const u32 *)buf, oob);
++	brcmnand_set_ecc_enabled(host, 1);
++	return 0;
++}
++
++static int brcmnand_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
++				  int page)
++{
++	return brcmnand_write(mtd, chip, (u64)page << chip->page_shift,
++				  NULL, chip->oob_poi);
++}
++
++static int brcmnand_write_oob_raw(struct mtd_info *mtd, struct nand_chip *chip,
++				  int page)
++{
++	struct brcmnand_host *host = nand_get_controller_data(chip);
++	int ret;
++
++	brcmnand_set_ecc_enabled(host, 0);
++	ret = brcmnand_write(mtd, chip, (u64)page << chip->page_shift, NULL,
++				 (u8 *)chip->oob_poi);
++	brcmnand_set_ecc_enabled(host, 1);
++
++	return ret;
++}
++
++/***********************************************************************
++ * Per-CS setup (1 NAND device)
++ ***********************************************************************/
++
++static int brcmnand_set_cfg(struct brcmnand_host *host,
++			    struct brcmnand_cfg *cfg)
++{
++	struct brcmnand_controller *ctrl = host->ctrl;
++	struct nand_chip *chip = &host->chip;
++	u16 cfg_offs = brcmnand_cs_offset(ctrl, host->cs, BRCMNAND_CS_CFG);
++	u16 cfg_ext_offs = brcmnand_cs_offset(ctrl, host->cs,
++			BRCMNAND_CS_CFG_EXT);
++	u16 acc_control_offs = brcmnand_cs_offset(ctrl, host->cs,
++			BRCMNAND_CS_ACC_CONTROL);
++	u8 block_size = 0, page_size = 0, device_size = 0;
++	u32 tmp;
++
++	if (ctrl->block_sizes) {
++		int i, found;
++
++		for (i = 0, found = 0; ctrl->block_sizes[i]; i++)
++			if (ctrl->block_sizes[i] * 1024 == cfg->block_size) {
++				block_size = i;
++				found = 1;
++			}
++		if (!found) {
++			dev_warn(ctrl->dev, "invalid block size %u\n",
++					cfg->block_size);
++			return -EINVAL;
++		}
++	} else {
++		block_size = ffs(cfg->block_size) - ffs(BRCMNAND_MIN_BLOCKSIZE);
++	}
++
++	if (cfg->block_size < BRCMNAND_MIN_BLOCKSIZE || (ctrl->max_block_size &&
++				cfg->block_size > ctrl->max_block_size)) {
++		dev_warn(ctrl->dev, "invalid block size %u\n",
++				cfg->block_size);
++		block_size = 0;
++	}
++
++	if (ctrl->page_sizes) {
++		int i, found;
++
++		for (i = 0, found = 0; ctrl->page_sizes[i]; i++)
++			if (ctrl->page_sizes[i] == cfg->page_size) {
++				page_size = i;
++				found = 1;
++			}
++		if (!found) {
++			dev_warn(ctrl->dev, "invalid page size %u\n",
++					cfg->page_size);
++			return -EINVAL;
++		}
++	} else {
++		page_size = ffs(cfg->page_size) - ffs(BRCMNAND_MIN_PAGESIZE);
++	}
++
++	if (cfg->page_size < BRCMNAND_MIN_PAGESIZE || (ctrl->max_page_size &&
++				cfg->page_size > ctrl->max_page_size)) {
++		dev_warn(ctrl->dev, "invalid page size %u\n", cfg->page_size);
++		return -EINVAL;
++	}
++
++	if (fls64(cfg->device_size) < fls64(BRCMNAND_MIN_DEVSIZE)) {
++		dev_warn(ctrl->dev, "invalid device size 0x%llx\n",
++			(unsigned long long)cfg->device_size);
++		return -EINVAL;
++	}
++	device_size = fls64(cfg->device_size) - fls64(BRCMNAND_MIN_DEVSIZE);
++
++	tmp = (cfg->blk_adr_bytes << CFG_BLK_ADR_BYTES_SHIFT) |
++		(cfg->col_adr_bytes << CFG_COL_ADR_BYTES_SHIFT) |
++		(cfg->ful_adr_bytes << CFG_FUL_ADR_BYTES_SHIFT) |
++		(!!(cfg->device_width == 16) << CFG_BUS_WIDTH_SHIFT) |
++		(device_size << CFG_DEVICE_SIZE_SHIFT);
++	if (cfg_offs == cfg_ext_offs) {
++		tmp |= (page_size << CFG_PAGE_SIZE_SHIFT) |
++		       (block_size << CFG_BLK_SIZE_SHIFT);
++		nand_writereg(ctrl, cfg_offs, tmp);
++	} else {
++		nand_writereg(ctrl, cfg_offs, tmp);
++		tmp = (page_size << CFG_EXT_PAGE_SIZE_SHIFT) |
++		      (block_size << CFG_EXT_BLK_SIZE_SHIFT);
++		nand_writereg(ctrl, cfg_ext_offs, tmp);
++	}
++
++	tmp = nand_readreg(ctrl, acc_control_offs);
++	tmp &= ~brcmnand_ecc_level_mask(ctrl);
++	tmp |= cfg->ecc_level << NAND_ACC_CONTROL_ECC_SHIFT;
++	tmp &= ~brcmnand_spare_area_mask(ctrl);
++	tmp |= cfg->spare_area_size;
++	nand_writereg(ctrl, acc_control_offs, tmp);
++
++	brcmnand_set_sector_size_1k(host, cfg->sector_size_1k);
++
++	/* threshold = ceil(BCH-level * 0.75) */
++	brcmnand_wr_corr_thresh(host, DIV_ROUND_UP(chip->ecc.strength * 3, 4));
++
++	return 0;
++}
++
++static void brcmnand_print_cfg(struct brcmnand_host *host,
++			       char *buf, struct brcmnand_cfg *cfg)
++{
++	buf += sprintf(buf,
++		"%lluMiB total, %uKiB blocks, %u%s pages, %uB OOB, %u-bit",
++		(unsigned long long)cfg->device_size >> 20,
++		cfg->block_size >> 10,
++		cfg->page_size >= 1024 ? cfg->page_size >> 10 : cfg->page_size,
++		cfg->page_size >= 1024 ? "KiB" : "B",
++		cfg->spare_area_size, cfg->device_width);
++
++	/* Account for Hamming ECC and for BCH 512B vs 1KiB sectors */
++	if (is_hamming_ecc(host->ctrl, cfg))
++		sprintf(buf, ", Hamming ECC");
++	else if (cfg->sector_size_1k)
++		sprintf(buf, ", BCH-%u (1KiB sector)", cfg->ecc_level << 1);
++	else
++		sprintf(buf, ", BCH-%u", cfg->ecc_level);
++}
++
++/*
++ * Minimum number of bytes to address a page. Calculated as:
++ *     roundup(log2(size / page-size) / 8)
++ *
++ * NB: the following does not "round up" for non-power-of-2 'size'; but this is
++ *     OK because many other things will break if 'size' is irregular...
++ */
++static inline int get_blk_adr_bytes(u64 size, u32 writesize)
++{
++	return ALIGN(ilog2(size) - ilog2(writesize), 8) >> 3;
++}
++
++static int brcmnand_setup_dev(struct brcmnand_host *host)
++{
++	struct mtd_info *mtd = nand_to_mtd(&host->chip);
++	struct nand_chip *chip = &host->chip;
++	struct brcmnand_controller *ctrl = host->ctrl;
++	struct brcmnand_cfg *cfg = &host->hwcfg;
++	char msg[128];
++	u32 offs, tmp, oob_sector;
++	int ret;
++
++	memset(cfg, 0, sizeof(*cfg));
++
++	ret = of_property_read_u32(nand_get_flash_node(chip),
++				   "brcm,nand-oob-sector-size",
++				   &oob_sector);
++	if (ret) {
++		/* Use detected size */
++		cfg->spare_area_size = mtd->oobsize /
++					(mtd->writesize >> FC_SHIFT);
++	} else {
++		cfg->spare_area_size = oob_sector;
++	}
++	if (cfg->spare_area_size > ctrl->max_oob)
++		cfg->spare_area_size = ctrl->max_oob;
++	/*
++	 * Set oobsize to be consistent with controller's spare_area_size, as
++	 * the rest is inaccessible.
++	 */
++	mtd->oobsize = cfg->spare_area_size * (mtd->writesize >> FC_SHIFT);
++
++	cfg->device_size = mtd->size;
++	cfg->block_size = mtd->erasesize;
++	cfg->page_size = mtd->writesize;
++	cfg->device_width = (chip->options & NAND_BUSWIDTH_16) ? 16 : 8;
++	cfg->col_adr_bytes = 2;
++	cfg->blk_adr_bytes = get_blk_adr_bytes(mtd->size, mtd->writesize);
++
++	if (chip->ecc.mode != NAND_ECC_HW) {
++		dev_err(ctrl->dev, "only HW ECC supported; selected: %d\n",
++			chip->ecc.mode);
++		return -EINVAL;
++	}
++
++	if (chip->ecc.algo == NAND_ECC_UNKNOWN) {
++		if (chip->ecc.strength == 1 && chip->ecc.size == 512)
++			/* Default to Hamming for 1-bit ECC, if unspecified */
++			chip->ecc.algo = NAND_ECC_HAMMING;
++		else
++			/* Otherwise, BCH */
++			chip->ecc.algo = NAND_ECC_BCH;
++	}
++
++	if (chip->ecc.algo == NAND_ECC_HAMMING && (chip->ecc.strength != 1 ||
++						   chip->ecc.size != 512)) {
++		dev_err(ctrl->dev, "invalid Hamming params: %d bits per %d bytes\n",
++			chip->ecc.strength, chip->ecc.size);
++		return -EINVAL;
++	}
++
++	switch (chip->ecc.size) {
++	case 512:
++		if (chip->ecc.algo == NAND_ECC_HAMMING)
++			cfg->ecc_level = 15;
++		else
++			cfg->ecc_level = chip->ecc.strength;
++		cfg->sector_size_1k = 0;
++		break;
++	case 1024:
++		if (!(ctrl->features & BRCMNAND_HAS_1K_SECTORS)) {
++			dev_err(ctrl->dev, "1KB sectors not supported\n");
++			return -EINVAL;
++		}
++		if (chip->ecc.strength & 0x1) {
++			dev_err(ctrl->dev,
++				"odd ECC not supported with 1KB sectors\n");
++			return -EINVAL;
++		}
++
++		cfg->ecc_level = chip->ecc.strength >> 1;
++		cfg->sector_size_1k = 1;
++		break;
++	default:
++		dev_err(ctrl->dev, "unsupported ECC size: %d\n",
++			chip->ecc.size);
++		return -EINVAL;
++	}
++
++	cfg->ful_adr_bytes = cfg->blk_adr_bytes;
++	if (mtd->writesize > 512)
++		cfg->ful_adr_bytes += cfg->col_adr_bytes;
++	else
++		cfg->ful_adr_bytes += 1;
++
++	ret = brcmnand_set_cfg(host, cfg);
++	if (ret)
++		return ret;
++
++	brcmnand_set_ecc_enabled(host, 1);
++
++	brcmnand_print_cfg(host, msg, cfg);
++	dev_info(ctrl->dev, "detected %s\n", msg);
++
++	/* Configure ACC_CONTROL */
++	offs = brcmnand_cs_offset(ctrl, host->cs, BRCMNAND_CS_ACC_CONTROL);
++	tmp = nand_readreg(ctrl, offs);
++	tmp &= ~ACC_CONTROL_PARTIAL_PAGE;
++	tmp &= ~ACC_CONTROL_RD_ERASED;
++
++	/* We need to turn on Read from erased paged protected by ECC */
++	if (ctrl->nand_version >= 0x0702)
++		tmp |= ACC_CONTROL_RD_ERASED;
++	tmp &= ~ACC_CONTROL_FAST_PGM_RDIN;
++	if (ctrl->features & BRCMNAND_HAS_PREFETCH) {
++		/*
++		 * FIXME: Flash DMA + prefetch may see spurious erased-page ECC
++		 * errors
++		 */
++		if (has_flash_dma(ctrl))
++			tmp &= ~ACC_CONTROL_PREFETCH;
++		else
++			tmp |= ACC_CONTROL_PREFETCH;
++	}
++	nand_writereg(ctrl, offs, tmp);
++
++	return 0;
++}
++
++static int brcmnand_init_cs(struct brcmnand_host *host, struct device_node *dn)
++{
++	struct brcmnand_controller *ctrl = host->ctrl;
++	struct platform_device *pdev = host->pdev;
++	struct mtd_info *mtd;
++	struct nand_chip *chip;
++	int ret;
++	u16 cfg_offs;
++
++	ret = of_property_read_u32(dn, "reg", &host->cs);
++	if (ret) {
++		dev_err(&pdev->dev, "can't get chip-select\n");
++		return -ENXIO;
++	}
++
++	mtd = nand_to_mtd(&host->chip);
++	chip = &host->chip;
++
++	nand_set_flash_node(chip, dn);
++	nand_set_controller_data(chip, host);
++	mtd->name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "brcmnand.%d",
++				   host->cs);
++	mtd->owner = THIS_MODULE;
++	mtd->dev.parent = &pdev->dev;
++
++	chip->IO_ADDR_R = (void __iomem *)0xdeadbeef;
++	chip->IO_ADDR_W = (void __iomem *)0xdeadbeef;
++
++	chip->cmd_ctrl = brcmnand_cmd_ctrl;
++	chip->cmdfunc = brcmnand_cmdfunc;
++	chip->waitfunc = brcmnand_waitfunc;
++	chip->read_byte = brcmnand_read_byte;
++	chip->read_buf = brcmnand_read_buf;
++	chip->write_buf = brcmnand_write_buf;
++
++	chip->ecc.mode = NAND_ECC_HW;
++	chip->ecc.read_page = brcmnand_read_page;
++	chip->ecc.write_page = brcmnand_write_page;
++	chip->ecc.read_page_raw = brcmnand_read_page_raw;
++	chip->ecc.write_page_raw = brcmnand_write_page_raw;
++	chip->ecc.write_oob_raw = brcmnand_write_oob_raw;
++	chip->ecc.read_oob_raw = brcmnand_read_oob_raw;
++	chip->ecc.read_oob = brcmnand_read_oob;
++	chip->ecc.write_oob = brcmnand_write_oob;
++
++	chip->controller = &ctrl->controller;
++
++	/*
++	 * The bootloader might have configured 16bit mode but
++	 * NAND READID command only works in 8bit mode. We force
++	 * 8bit mode here to ensure that NAND READID commands works.
++	 */
++	cfg_offs = brcmnand_cs_offset(ctrl, host->cs, BRCMNAND_CS_CFG);
++	nand_writereg(ctrl, cfg_offs,
++		      nand_readreg(ctrl, cfg_offs) & ~CFG_BUS_WIDTH);
++
++	ret = nand_scan_ident(mtd, 1, NULL);
++	if (ret)
++		return ret;
++
++	chip->options |= NAND_NO_SUBPAGE_WRITE;
++	/*
++	 * Avoid (for instance) kmap()'d buffers from JFFS2, which we can't DMA
++	 * to/from, and have nand_base pass us a bounce buffer instead, as
++	 * needed.
++	 */
++	chip->options |= NAND_USE_BOUNCE_BUFFER;
++
++	if (chip->bbt_options & NAND_BBT_USE_FLASH)
++		chip->bbt_options |= NAND_BBT_NO_OOB;
++
++	if (brcmnand_setup_dev(host))
++		return -ENXIO;
++
++	chip->ecc.size = host->hwcfg.sector_size_1k ? 1024 : 512;
++	/* only use our internal HW threshold */
++	mtd->bitflip_threshold = 1;
++
++	ret = brcmstb_choose_ecc_layout(host);
++	if (ret)
++		return ret;
++
++	ret = nand_scan_tail(mtd);
++	if (ret)
++		return ret;
++
++	return mtd_device_register(mtd, NULL, 0);
++}
++
++static void brcmnand_save_restore_cs_config(struct brcmnand_host *host,
++					    int restore)
++{
++	struct brcmnand_controller *ctrl = host->ctrl;
++	u16 cfg_offs = brcmnand_cs_offset(ctrl, host->cs, BRCMNAND_CS_CFG);
++	u16 cfg_ext_offs = brcmnand_cs_offset(ctrl, host->cs,
++			BRCMNAND_CS_CFG_EXT);
++	u16 acc_control_offs = brcmnand_cs_offset(ctrl, host->cs,
++			BRCMNAND_CS_ACC_CONTROL);
++	u16 t1_offs = brcmnand_cs_offset(ctrl, host->cs, BRCMNAND_CS_TIMING1);
++	u16 t2_offs = brcmnand_cs_offset(ctrl, host->cs, BRCMNAND_CS_TIMING2);
++
++	if (restore) {
++		nand_writereg(ctrl, cfg_offs, host->hwcfg.config);
++		if (cfg_offs != cfg_ext_offs)
++			nand_writereg(ctrl, cfg_ext_offs,
++				      host->hwcfg.config_ext);
++		nand_writereg(ctrl, acc_control_offs, host->hwcfg.acc_control);
++		nand_writereg(ctrl, t1_offs, host->hwcfg.timing_1);
++		nand_writereg(ctrl, t2_offs, host->hwcfg.timing_2);
++	} else {
++		host->hwcfg.config = nand_readreg(ctrl, cfg_offs);
++		if (cfg_offs != cfg_ext_offs)
++			host->hwcfg.config_ext =
++				nand_readreg(ctrl, cfg_ext_offs);
++		host->hwcfg.acc_control = nand_readreg(ctrl, acc_control_offs);
++		host->hwcfg.timing_1 = nand_readreg(ctrl, t1_offs);
++		host->hwcfg.timing_2 = nand_readreg(ctrl, t2_offs);
++	}
++}
++
++static int brcmnand_suspend(struct device *dev)
++{
++	struct brcmnand_controller *ctrl = dev_get_drvdata(dev);
++	struct brcmnand_host *host;
++
++	list_for_each_entry(host, &ctrl->host_list, node)
++		brcmnand_save_restore_cs_config(host, 0);
++
++	ctrl->nand_cs_nand_select = brcmnand_read_reg(ctrl, BRCMNAND_CS_SELECT);
++	ctrl->nand_cs_nand_xor = brcmnand_read_reg(ctrl, BRCMNAND_CS_XOR);
++	ctrl->corr_stat_threshold =
++		brcmnand_read_reg(ctrl, BRCMNAND_CORR_THRESHOLD);
++
++	if (has_flash_dma(ctrl))
++		ctrl->flash_dma_mode = flash_dma_readl(ctrl, FLASH_DMA_MODE);
++
++	return 0;
++}
++
++static int brcmnand_resume(struct device *dev)
++{
++	struct brcmnand_controller *ctrl = dev_get_drvdata(dev);
++	struct brcmnand_host *host;
++
++	if (has_flash_dma(ctrl)) {
++		flash_dma_writel(ctrl, FLASH_DMA_MODE, ctrl->flash_dma_mode);
++		flash_dma_writel(ctrl, FLASH_DMA_ERROR_STATUS, 0);
++	}
++
++	brcmnand_write_reg(ctrl, BRCMNAND_CS_SELECT, ctrl->nand_cs_nand_select);
++	brcmnand_write_reg(ctrl, BRCMNAND_CS_XOR, ctrl->nand_cs_nand_xor);
++	brcmnand_write_reg(ctrl, BRCMNAND_CORR_THRESHOLD,
++			ctrl->corr_stat_threshold);
++	if (ctrl->soc) {
++		/* Clear/re-enable interrupt */
++		ctrl->soc->ctlrdy_ack(ctrl->soc);
++		ctrl->soc->ctlrdy_set_enabled(ctrl->soc, true);
++	}
++
++	list_for_each_entry(host, &ctrl->host_list, node) {
++		struct nand_chip *chip = &host->chip;
++		struct mtd_info *mtd = nand_to_mtd(chip);
++
++		brcmnand_save_restore_cs_config(host, 1);
++
++		/* Reset the chip, required by some chips after power-up */
++		chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
++	}
++
++	return 0;
++}
++
++const struct dev_pm_ops brcmnand_pm_ops = {
++	.suspend		= brcmnand_suspend,
++	.resume			= brcmnand_resume,
++};
++EXPORT_SYMBOL_GPL(brcmnand_pm_ops);
++
++static const struct of_device_id brcmnand_of_match[] = {
++	{ .compatible = "brcm,brcmnand-v4.0" },
++	{ .compatible = "brcm,brcmnand-v5.0" },
++	{ .compatible = "brcm,brcmnand-v6.0" },
++	{ .compatible = "brcm,brcmnand-v6.1" },
++	{ .compatible = "brcm,brcmnand-v6.2" },
++	{ .compatible = "brcm,brcmnand-v7.0" },
++	{ .compatible = "brcm,brcmnand-v7.1" },
++	{ .compatible = "brcm,brcmnand-v7.2" },
++	{},
++};
++MODULE_DEVICE_TABLE(of, brcmnand_of_match);
++
++/***********************************************************************
++ * Platform driver setup (per controller)
++ ***********************************************************************/
++
++int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc)
++{
++	struct device *dev = &pdev->dev;
++	struct device_node *dn = dev->of_node, *child;
++	struct brcmnand_controller *ctrl;
++	struct resource *res;
++	int ret;
++
++	/* We only support device-tree instantiation */
++	if (!dn)
++		return -ENODEV;
++
++	if (!of_match_node(brcmnand_of_match, dn))
++		return -ENODEV;
++
++	ctrl = devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL);
++	if (!ctrl)
++		return -ENOMEM;
++
++	dev_set_drvdata(dev, ctrl);
++	ctrl->dev = dev;
++
++	init_completion(&ctrl->done);
++	init_completion(&ctrl->dma_done);
++	nand_hw_control_init(&ctrl->controller);
++	INIT_LIST_HEAD(&ctrl->host_list);
++
++	/* NAND register range */
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	ctrl->nand_base = devm_ioremap_resource(dev, res);
++	if (IS_ERR(ctrl->nand_base))
++		return PTR_ERR(ctrl->nand_base);
++
++	/* Enable clock before using NAND registers */
++	ctrl->clk = devm_clk_get(dev, "nand");
++	if (!IS_ERR(ctrl->clk)) {
++		ret = clk_prepare_enable(ctrl->clk);
++		if (ret)
++			return ret;
++	} else {
++		ret = PTR_ERR(ctrl->clk);
++		if (ret == -EPROBE_DEFER)
++			return ret;
++
++		ctrl->clk = NULL;
++	}
++
++	/* Initialize NAND revision */
++	ret = brcmnand_revision_init(ctrl);
++	if (ret)
++		goto err;
++
++	/*
++	 * Most chips have this cache at a fixed offset within 'nand' block.
++	 * Some must specify this region separately.
++	 */
++	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand-cache");
++	if (res) {
++		ctrl->nand_fc = devm_ioremap_resource(dev, res);
++		if (IS_ERR(ctrl->nand_fc)) {
++			ret = PTR_ERR(ctrl->nand_fc);
++			goto err;
++		}
++	} else {
++		ctrl->nand_fc = ctrl->nand_base +
++				ctrl->reg_offsets[BRCMNAND_FC_BASE];
++	}
++
++	/* FLASH_DMA */
++	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "flash-dma");
++	if (res) {
++		ctrl->flash_dma_base = devm_ioremap_resource(dev, res);
++		if (IS_ERR(ctrl->flash_dma_base)) {
++			ret = PTR_ERR(ctrl->flash_dma_base);
++			goto err;
++		}
++
++		flash_dma_writel(ctrl, FLASH_DMA_MODE, 1); /* linked-list */
++		flash_dma_writel(ctrl, FLASH_DMA_ERROR_STATUS, 0);
++
++		/* Allocate descriptor(s) */
++		ctrl->dma_desc = dmam_alloc_coherent(dev,
++						     sizeof(*ctrl->dma_desc),
++						     &ctrl->dma_pa, GFP_KERNEL);
++		if (!ctrl->dma_desc) {
++			ret = -ENOMEM;
++			goto err;
++		}
++
++		ctrl->dma_irq = platform_get_irq(pdev, 1);
++		if ((int)ctrl->dma_irq < 0) {
++			dev_err(dev, "missing FLASH_DMA IRQ\n");
++			ret = -ENODEV;
++			goto err;
++		}
++
++		ret = devm_request_irq(dev, ctrl->dma_irq,
++				brcmnand_dma_irq, 0, DRV_NAME,
++				ctrl);
++		if (ret < 0) {
++			dev_err(dev, "can't allocate IRQ %d: error %d\n",
++					ctrl->dma_irq, ret);
++			goto err;
++		}
++
++		dev_info(dev, "enabling FLASH_DMA\n");
++	}
++
++	/* Disable automatic device ID config, direct addressing */
++	brcmnand_rmw_reg(ctrl, BRCMNAND_CS_SELECT,
++			 CS_SELECT_AUTO_DEVICE_ID_CFG | 0xff, 0, 0);
++	/* Disable XOR addressing */
++	brcmnand_rmw_reg(ctrl, BRCMNAND_CS_XOR, 0xff, 0, 0);
++
++	if (ctrl->features & BRCMNAND_HAS_WP) {
++		/* Permanently disable write protection */
++		if (wp_on == 2)
++			brcmnand_set_wp(ctrl, false);
++	} else {
++		wp_on = 0;
++	}
++
++	/* IRQ */
++	ctrl->irq = platform_get_irq(pdev, 0);
++	if ((int)ctrl->irq < 0) {
++		dev_err(dev, "no IRQ defined\n");
++		ret = -ENODEV;
++		goto err;
++	}
++
++	/*
++	 * Some SoCs integrate this controller (e.g., its interrupt bits) in
++	 * interesting ways
++	 */
++	if (soc) {
++		ctrl->soc = soc;
++
++		ret = devm_request_irq(dev, ctrl->irq, brcmnand_irq, 0,
++				       DRV_NAME, ctrl);
++
++		/* Enable interrupt */
++		ctrl->soc->ctlrdy_ack(ctrl->soc);
++		ctrl->soc->ctlrdy_set_enabled(ctrl->soc, true);
++	} else {
++		/* Use standard interrupt infrastructure */
++		ret = devm_request_irq(dev, ctrl->irq, brcmnand_ctlrdy_irq, 0,
++				       DRV_NAME, ctrl);
++	}
++	if (ret < 0) {
++		dev_err(dev, "can't allocate IRQ %d: error %d\n",
++			ctrl->irq, ret);
++		goto err;
++	}
++
++	for_each_available_child_of_node(dn, child) {
++		if (of_device_is_compatible(child, "brcm,nandcs")) {
++			struct brcmnand_host *host;
++
++			host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL);
++			if (!host) {
++				of_node_put(child);
++				ret = -ENOMEM;
++				goto err;
++			}
++			host->pdev = pdev;
++			host->ctrl = ctrl;
++
++			ret = brcmnand_init_cs(host, child);
++			if (ret) {
++				devm_kfree(dev, host);
++				continue; /* Try all chip-selects */
++			}
++
++			list_add_tail(&host->node, &ctrl->host_list);
++		}
++	}
++
++	/* No chip-selects could initialize properly */
++	if (list_empty(&ctrl->host_list)) {
++		ret = -ENODEV;
++		goto err;
++	}
++
++	return 0;
++
++err:
++	clk_disable_unprepare(ctrl->clk);
++	return ret;
++
++}
++EXPORT_SYMBOL_GPL(brcmnand_probe);
++
++int brcmnand_remove(struct platform_device *pdev)
++{
++	struct brcmnand_controller *ctrl = dev_get_drvdata(&pdev->dev);
++	struct brcmnand_host *host;
++
++	list_for_each_entry(host, &ctrl->host_list, node)
++		nand_release(nand_to_mtd(&host->chip));
++
++	clk_disable_unprepare(ctrl->clk);
++
++	dev_set_drvdata(&pdev->dev, NULL);
++
++	return 0;
++}
++EXPORT_SYMBOL_GPL(brcmnand_remove);
++
++MODULE_LICENSE("GPL v2");
++MODULE_AUTHOR("Kevin Cernekee");
++MODULE_AUTHOR("Brian Norris");
++MODULE_DESCRIPTION("NAND driver for Broadcom chips");
++MODULE_ALIAS("platform:brcmnand");
+diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand.h b/drivers/mtd/nand/raw/brcmnand/brcmnand.h
+new file mode 100644
+index 0000000..5c44cd4
+--- /dev/null
++++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.h
+@@ -0,0 +1,74 @@
++/*
++ * Copyright © 2015 Broadcom Corporation
++ *
++ * 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.
++ */
++
++#ifndef __BRCMNAND_H__
++#define __BRCMNAND_H__
++
++#include <linux/types.h>
++#include <linux/io.h>
++
++struct platform_device;
++struct dev_pm_ops;
++
++struct brcmnand_soc {
++	bool (*ctlrdy_ack)(struct brcmnand_soc *soc);
++	void (*ctlrdy_set_enabled)(struct brcmnand_soc *soc, bool en);
++	void (*prepare_data_bus)(struct brcmnand_soc *soc, bool prepare,
++				 bool is_param);
++};
++
++static inline void brcmnand_soc_data_bus_prepare(struct brcmnand_soc *soc,
++						 bool is_param)
++{
++	if (soc && soc->prepare_data_bus)
++		soc->prepare_data_bus(soc, true, is_param);
++}
++
++static inline void brcmnand_soc_data_bus_unprepare(struct brcmnand_soc *soc,
++						   bool is_param)
++{
++	if (soc && soc->prepare_data_bus)
++		soc->prepare_data_bus(soc, false, is_param);
++}
++
++static inline u32 brcmnand_readl(void __iomem *addr)
++{
++	/*
++	 * MIPS endianness is configured by boot strap, which also reverses all
++	 * bus endianness (i.e., big-endian CPU + big endian bus ==> native
++	 * endian I/O).
++	 *
++	 * Other architectures (e.g., ARM) either do not support big endian, or
++	 * else leave I/O in little endian mode.
++	 */
++	if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
++		return __raw_readl(addr);
++	else
++		return readl_relaxed(addr);
++}
++
++static inline void brcmnand_writel(u32 val, void __iomem *addr)
++{
++	/* See brcmnand_readl() comments */
++	if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
++		__raw_writel(val, addr);
++	else
++		writel_relaxed(val, addr);
++}
++
++int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc);
++int brcmnand_remove(struct platform_device *pdev);
++
++extern const struct dev_pm_ops brcmnand_pm_ops;
++
++#endif /* __BRCMNAND_H__ */
+diff --git a/drivers/mtd/nand/raw/brcmnand/brcmstb_nand.c b/drivers/mtd/nand/raw/brcmnand/brcmstb_nand.c
+new file mode 100644
+index 0000000..5c271077
+--- /dev/null
++++ b/drivers/mtd/nand/raw/brcmnand/brcmstb_nand.c
+@@ -0,0 +1,44 @@
++/*
++ * Copyright © 2015 Broadcom Corporation
++ *
++ * 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/device.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++
++#include "brcmnand.h"
++
++static const struct of_device_id brcmstb_nand_of_match[] = {
++	{ .compatible = "brcm,brcmnand" },
++	{},
++};
++MODULE_DEVICE_TABLE(of, brcmstb_nand_of_match);
++
++static int brcmstb_nand_probe(struct platform_device *pdev)
++{
++	return brcmnand_probe(pdev, NULL);
++}
++
++static struct platform_driver brcmstb_nand_driver = {
++	.probe			= brcmstb_nand_probe,
++	.remove			= brcmnand_remove,
++	.driver = {
++		.name		= "brcmstb_nand",
++		.pm		= &brcmnand_pm_ops,
++		.of_match_table = brcmstb_nand_of_match,
++	}
++};
++module_platform_driver(brcmstb_nand_driver);
++
++MODULE_LICENSE("GPL v2");
++MODULE_AUTHOR("Brian Norris");
++MODULE_DESCRIPTION("NAND driver for Broadcom STB chips");
+diff --git a/drivers/mtd/nand/raw/brcmnand/iproc_nand.c b/drivers/mtd/nand/raw/brcmnand/iproc_nand.c
+new file mode 100644
+index 0000000..4c6ae11
+--- /dev/null
++++ b/drivers/mtd/nand/raw/brcmnand/iproc_nand.c
+@@ -0,0 +1,160 @@
++/*
++ * Copyright © 2015 Broadcom Corporation
++ *
++ * 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/device.h>
++#include <linux/io.h>
++#include <linux/ioport.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/of_address.h>
++#include <linux/platform_device.h>
++#include <linux/slab.h>
++
++#include "brcmnand.h"
++
++struct iproc_nand_soc {
++	struct brcmnand_soc soc;
++
++	void __iomem *idm_base;
++	void __iomem *ext_base;
++	spinlock_t idm_lock;
++};
++
++#define IPROC_NAND_CTLR_READY_OFFSET       0x10
++#define IPROC_NAND_CTLR_READY              BIT(0)
++
++#define IPROC_NAND_IO_CTRL_OFFSET          0x00
++#define IPROC_NAND_APB_LE_MODE             BIT(24)
++#define IPROC_NAND_INT_CTRL_READ_ENABLE    BIT(6)
++
++static bool iproc_nand_intc_ack(struct brcmnand_soc *soc)
++{
++	struct iproc_nand_soc *priv =
++			container_of(soc, struct iproc_nand_soc, soc);
++	void __iomem *mmio = priv->ext_base + IPROC_NAND_CTLR_READY_OFFSET;
++	u32 val = brcmnand_readl(mmio);
++
++	if (val & IPROC_NAND_CTLR_READY) {
++		brcmnand_writel(IPROC_NAND_CTLR_READY, mmio);
++		return true;
++	}
++
++	return false;
++}
++
++static void iproc_nand_intc_set(struct brcmnand_soc *soc, bool en)
++{
++	struct iproc_nand_soc *priv =
++			container_of(soc, struct iproc_nand_soc, soc);
++	void __iomem *mmio = priv->idm_base + IPROC_NAND_IO_CTRL_OFFSET;
++	u32 val;
++	unsigned long flags;
++
++	spin_lock_irqsave(&priv->idm_lock, flags);
++
++	val = brcmnand_readl(mmio);
++
++	if (en)
++		val |= IPROC_NAND_INT_CTRL_READ_ENABLE;
++	else
++		val &= ~IPROC_NAND_INT_CTRL_READ_ENABLE;
++
++	brcmnand_writel(val, mmio);
++
++	spin_unlock_irqrestore(&priv->idm_lock, flags);
++}
++
++static void iproc_nand_apb_access(struct brcmnand_soc *soc, bool prepare,
++				  bool is_param)
++{
++	struct iproc_nand_soc *priv =
++			container_of(soc, struct iproc_nand_soc, soc);
++	void __iomem *mmio = priv->idm_base + IPROC_NAND_IO_CTRL_OFFSET;
++	u32 val;
++	unsigned long flags;
++
++	spin_lock_irqsave(&priv->idm_lock, flags);
++
++	val = brcmnand_readl(mmio);
++
++	/*
++	 * In the case of BE or when dealing with NAND data, alway configure
++	 * the APB bus to LE mode before accessing the FIFO and back to BE mode
++	 * after the access is done
++	 */
++	if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) || !is_param) {
++		if (prepare)
++			val |= IPROC_NAND_APB_LE_MODE;
++		else
++			val &= ~IPROC_NAND_APB_LE_MODE;
++	} else { /* when in LE accessing the parameter page, keep APB in BE */
++		val &= ~IPROC_NAND_APB_LE_MODE;
++	}
++
++	brcmnand_writel(val, mmio);
++
++	spin_unlock_irqrestore(&priv->idm_lock, flags);
++}
++
++static int iproc_nand_probe(struct platform_device *pdev)
++{
++	struct device *dev = &pdev->dev;
++	struct iproc_nand_soc *priv;
++	struct brcmnand_soc *soc;
++	struct resource *res;
++
++	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
++	if (!priv)
++		return -ENOMEM;
++	soc = &priv->soc;
++
++	spin_lock_init(&priv->idm_lock);
++
++	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "iproc-idm");
++	priv->idm_base = devm_ioremap_resource(dev, res);
++	if (IS_ERR(priv->idm_base))
++		return PTR_ERR(priv->idm_base);
++
++	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "iproc-ext");
++	priv->ext_base = devm_ioremap_resource(dev, res);
++	if (IS_ERR(priv->ext_base))
++		return PTR_ERR(priv->ext_base);
++
++	soc->ctlrdy_ack = iproc_nand_intc_ack;
++	soc->ctlrdy_set_enabled = iproc_nand_intc_set;
++	soc->prepare_data_bus = iproc_nand_apb_access;
++
++	return brcmnand_probe(pdev, soc);
++}
++
++static const struct of_device_id iproc_nand_of_match[] = {
++	{ .compatible = "brcm,nand-iproc" },
++	{},
++};
++MODULE_DEVICE_TABLE(of, iproc_nand_of_match);
++
++static struct platform_driver iproc_nand_driver = {
++	.probe			= iproc_nand_probe,
++	.remove			= brcmnand_remove,
++	.driver = {
++		.name		= "iproc_nand",
++		.pm		= &brcmnand_pm_ops,
++		.of_match_table	= iproc_nand_of_match,
++	}
++};
++module_platform_driver(iproc_nand_driver);
++
++MODULE_LICENSE("GPL v2");
++MODULE_AUTHOR("Brian Norris");
++MODULE_AUTHOR("Ray Jui");
++MODULE_DESCRIPTION("NAND driver for Broadcom IPROC-based SoCs");
+diff --git a/drivers/mtd/nand/raw/cafe_nand.c b/drivers/mtd/nand/raw/cafe_nand.c
+new file mode 100644
+index 0000000..bc558c4
+--- /dev/null
++++ b/drivers/mtd/nand/raw/cafe_nand.c
+@@ -0,0 +1,899 @@
++/*
++ * Driver for One Laptop Per Child ‘CAFÉ’ controller, aka Marvell 88ALP01
++ *
++ * The data sheet for this device can be found at:
++ *    http://wiki.laptop.org/go/Datasheets 
++ *
++ * Copyright © 2006 Red Hat, Inc.
++ * Copyright © 2006 David Woodhouse <dwmw2@infradead.org>
++ */
++
++#define DEBUG
++
++#include <linux/device.h>
++#undef DEBUG
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/rawnand.h>
++#include <linux/mtd/partitions.h>
++#include <linux/rslib.h>
++#include <linux/pci.h>
++#include <linux/delay.h>
++#include <linux/interrupt.h>
++#include <linux/dma-mapping.h>
++#include <linux/slab.h>
++#include <linux/module.h>
++#include <asm/io.h>
++
++#define CAFE_NAND_CTRL1		0x00
++#define CAFE_NAND_CTRL2		0x04
++#define CAFE_NAND_CTRL3		0x08
++#define CAFE_NAND_STATUS	0x0c
++#define CAFE_NAND_IRQ		0x10
++#define CAFE_NAND_IRQ_MASK	0x14
++#define CAFE_NAND_DATA_LEN	0x18
++#define CAFE_NAND_ADDR1		0x1c
++#define CAFE_NAND_ADDR2		0x20
++#define CAFE_NAND_TIMING1	0x24
++#define CAFE_NAND_TIMING2	0x28
++#define CAFE_NAND_TIMING3	0x2c
++#define CAFE_NAND_NONMEM	0x30
++#define CAFE_NAND_ECC_RESULT	0x3C
++#define CAFE_NAND_DMA_CTRL	0x40
++#define CAFE_NAND_DMA_ADDR0	0x44
++#define CAFE_NAND_DMA_ADDR1	0x48
++#define CAFE_NAND_ECC_SYN01	0x50
++#define CAFE_NAND_ECC_SYN23	0x54
++#define CAFE_NAND_ECC_SYN45	0x58
++#define CAFE_NAND_ECC_SYN67	0x5c
++#define CAFE_NAND_READ_DATA	0x1000
++#define CAFE_NAND_WRITE_DATA	0x2000
++
++#define CAFE_GLOBAL_CTRL	0x3004
++#define CAFE_GLOBAL_IRQ		0x3008
++#define CAFE_GLOBAL_IRQ_MASK	0x300c
++#define CAFE_NAND_RESET		0x3034
++
++/* Missing from the datasheet: bit 19 of CTRL1 sets CE0 vs. CE1 */
++#define CTRL1_CHIPSELECT	(1<<19)
++
++struct cafe_priv {
++	struct nand_chip nand;
++	struct pci_dev *pdev;
++	void __iomem *mmio;
++	struct rs_control *rs;
++	uint32_t ctl1;
++	uint32_t ctl2;
++	int datalen;
++	int nr_data;
++	int data_pos;
++	int page_addr;
++	dma_addr_t dmaaddr;
++	unsigned char *dmabuf;
++};
++
++static int usedma = 1;
++module_param(usedma, int, 0644);
++
++static int skipbbt = 0;
++module_param(skipbbt, int, 0644);
++
++static int debug = 0;
++module_param(debug, int, 0644);
++
++static int regdebug = 0;
++module_param(regdebug, int, 0644);
++
++static int checkecc = 1;
++module_param(checkecc, int, 0644);
++
++static unsigned int numtimings;
++static int timing[3];
++module_param_array(timing, int, &numtimings, 0644);
++
++static const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL };
++
++/* Hrm. Why isn't this already conditional on something in the struct device? */
++#define cafe_dev_dbg(dev, args...) do { if (debug) dev_dbg(dev, ##args); } while(0)
++
++/* Make it easier to switch to PIO if we need to */
++#define cafe_readl(cafe, addr)			readl((cafe)->mmio + CAFE_##addr)
++#define cafe_writel(cafe, datum, addr)		writel(datum, (cafe)->mmio + CAFE_##addr)
++
++static int cafe_device_ready(struct mtd_info *mtd)
++{
++	struct nand_chip *chip = mtd_to_nand(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);
++
++	cafe_writel(cafe, irqs, NAND_IRQ);
++
++	cafe_dev_dbg(&cafe->pdev->dev, "NAND device is%s ready, IRQ %x (%x) (%x,%x)\n",
++		result?"":" not", irqs, cafe_readl(cafe, NAND_IRQ),
++		cafe_readl(cafe, GLOBAL_IRQ), cafe_readl(cafe, GLOBAL_IRQ_MASK));
++
++	return result;
++}
++
++
++static void cafe_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct cafe_priv *cafe = nand_get_controller_data(chip);
++
++	if (usedma)
++		memcpy(cafe->dmabuf + cafe->datalen, buf, len);
++	else
++		memcpy_toio(cafe->mmio + CAFE_NAND_WRITE_DATA + cafe->datalen, buf, len);
++
++	cafe->datalen += len;
++
++	cafe_dev_dbg(&cafe->pdev->dev, "Copy 0x%x bytes to write buffer. datalen 0x%x\n",
++		len, cafe->datalen);
++}
++
++static void cafe_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct cafe_priv *cafe = nand_get_controller_data(chip);
++
++	if (usedma)
++		memcpy(buf, cafe->dmabuf + cafe->datalen, len);
++	else
++		memcpy_fromio(buf, cafe->mmio + CAFE_NAND_READ_DATA + cafe->datalen, len);
++
++	cafe_dev_dbg(&cafe->pdev->dev, "Copy 0x%x bytes from position 0x%x in read buffer.\n",
++		  len, cafe->datalen);
++	cafe->datalen += len;
++}
++
++static uint8_t cafe_read_byte(struct mtd_info *mtd)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct cafe_priv *cafe = nand_get_controller_data(chip);
++	uint8_t d;
++
++	cafe_read_buf(mtd, &d, 1);
++	cafe_dev_dbg(&cafe->pdev->dev, "Read %02x\n", d);
++
++	return d;
++}
++
++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 cafe_priv *cafe = nand_get_controller_data(chip);
++	int adrbytes = 0;
++	uint32_t ctl1;
++	uint32_t doneint = 0x80000000;
++
++	cafe_dev_dbg(&cafe->pdev->dev, "cmdfunc %02x, 0x%x, 0x%x\n",
++		command, column, page_addr);
++
++	if (command == NAND_CMD_ERASE2 || command == NAND_CMD_PAGEPROG) {
++		/* Second half of a command we already calculated */
++		cafe_writel(cafe, cafe->ctl2 | 0x100 | command, NAND_CTRL2);
++		ctl1 = cafe->ctl1;
++		cafe->ctl2 &= ~(1<<30);
++		cafe_dev_dbg(&cafe->pdev->dev, "Continue command, ctl1 %08x, #data %d\n",
++			  cafe->ctl1, cafe->nr_data);
++		goto do_command;
++	}
++	/* Reset ECC engine */
++	cafe_writel(cafe, 0, NAND_CTRL2);
++
++	/* Emulate NAND_CMD_READOOB on large-page chips */
++	if (mtd->writesize > 512 &&
++	    command == NAND_CMD_READOOB) {
++		column += mtd->writesize;
++		command = NAND_CMD_READ0;
++	}
++
++	/* FIXME: Do we need to send read command before sending data
++	   for small-page chips, to position the buffer correctly? */
++
++	if (column != -1) {
++		cafe_writel(cafe, column, NAND_ADDR1);
++		adrbytes = 2;
++		if (page_addr != -1)
++			goto write_adr2;
++	} else if (page_addr != -1) {
++		cafe_writel(cafe, page_addr & 0xffff, NAND_ADDR1);
++		page_addr >>= 16;
++	write_adr2:
++		cafe_writel(cafe, page_addr, NAND_ADDR2);
++		adrbytes += 2;
++		if (mtd->size > mtd->writesize << 16)
++			adrbytes++;
++	}
++
++	cafe->data_pos = cafe->datalen = 0;
++
++	/* Set command valid bit, mask in the chip select bit  */
++	ctl1 = 0x80000000 | command | (cafe->ctl1 & CTRL1_CHIPSELECT);
++
++	/* Set RD or WR bits as appropriate */
++	if (command == NAND_CMD_READID || command == NAND_CMD_STATUS) {
++		ctl1 |= (1<<26); /* rd */
++		/* Always 5 bytes, for now */
++		cafe->datalen = 4;
++		/* And one address cycle -- even for STATUS, since the controller doesn't work without */
++		adrbytes = 1;
++	} else if (command == NAND_CMD_READ0 || command == NAND_CMD_READ1 ||
++		   command == NAND_CMD_READOOB || command == NAND_CMD_RNDOUT) {
++		ctl1 |= 1<<26; /* rd */
++		/* For now, assume just read to end of page */
++		cafe->datalen = mtd->writesize + mtd->oobsize - column;
++	} else if (command == NAND_CMD_SEQIN)
++		ctl1 |= 1<<25; /* wr */
++
++	/* Set number of address bytes */
++	if (adrbytes)
++		ctl1 |= ((adrbytes-1)|8) << 27;
++
++	if (command == NAND_CMD_SEQIN || command == NAND_CMD_ERASE1) {
++		/* Ignore the first command of a pair; the hardware
++		   deals with them both at once, later */
++		cafe->ctl1 = ctl1;
++		cafe_dev_dbg(&cafe->pdev->dev, "Setup for delayed command, ctl1 %08x, dlen %x\n",
++			  cafe->ctl1, cafe->datalen);
++		return;
++	}
++	/* RNDOUT and READ0 commands need a following byte */
++	if (command == NAND_CMD_RNDOUT)
++		cafe_writel(cafe, cafe->ctl2 | 0x100 | NAND_CMD_RNDOUTSTART, NAND_CTRL2);
++	else if (command == NAND_CMD_READ0 && mtd->writesize > 512)
++		cafe_writel(cafe, cafe->ctl2 | 0x100 | NAND_CMD_READSTART, NAND_CTRL2);
++
++ do_command:
++	cafe_dev_dbg(&cafe->pdev->dev, "dlen %x, ctl1 %x, ctl2 %x\n",
++		cafe->datalen, ctl1, cafe_readl(cafe, NAND_CTRL2));
++
++	/* NB: The datasheet lies -- we really should be subtracting 1 here */
++	cafe_writel(cafe, cafe->datalen, NAND_DATA_LEN);
++	cafe_writel(cafe, 0x90000000, NAND_IRQ);
++	if (usedma && (ctl1 & (3<<25))) {
++		uint32_t dmactl = 0xc0000000 + cafe->datalen;
++		/* If WR or RD bits set, set up DMA */
++		if (ctl1 & (1<<26)) {
++			/* It's a read */
++			dmactl |= (1<<29);
++			/* ... so it's done when the DMA is done, not just
++			   the command. */
++			doneint = 0x10000000;
++		}
++		cafe_writel(cafe, dmactl, NAND_DMA_CTRL);
++	}
++	cafe->datalen = 0;
++
++	if (unlikely(regdebug)) {
++		int i;
++		printk("About to write command %08x to register 0\n", ctl1);
++		for (i=4; i< 0x5c; i+=4)
++			printk("Register %x: %08x\n", i, readl(cafe->mmio + i));
++	}
++
++	cafe_writel(cafe, ctl1, NAND_CTRL1);
++	/* Apply this short delay always to ensure that we do wait tWB in
++	 * any case on any machine. */
++	ndelay(100);
++
++	if (1) {
++		int c;
++		uint32_t irqs;
++
++		for (c = 500000; c != 0; c--) {
++			irqs = cafe_readl(cafe, NAND_IRQ);
++			if (irqs & doneint)
++				break;
++			udelay(1);
++			if (!(c % 100000))
++				cafe_dev_dbg(&cafe->pdev->dev, "Wait for ready, IRQ %x\n", irqs);
++			cpu_relax();
++		}
++		cafe_writel(cafe, doneint, NAND_IRQ);
++		cafe_dev_dbg(&cafe->pdev->dev, "Command %x completed after %d usec, irqs %x (%x)\n",
++			     command, 500000-c, irqs, cafe_readl(cafe, NAND_IRQ));
++	}
++
++	WARN_ON(cafe->ctl2 & (1<<30));
++
++	switch (command) {
++
++	case NAND_CMD_CACHEDPROG:
++	case NAND_CMD_PAGEPROG:
++	case NAND_CMD_ERASE1:
++	case NAND_CMD_ERASE2:
++	case NAND_CMD_SEQIN:
++	case NAND_CMD_RNDIN:
++	case NAND_CMD_STATUS:
++	case NAND_CMD_RNDOUT:
++		cafe_writel(cafe, cafe->ctl2, NAND_CTRL2);
++		return;
++	}
++	nand_wait_ready(mtd);
++	cafe_writel(cafe, cafe->ctl2, NAND_CTRL2);
++}
++
++static void cafe_select_chip(struct mtd_info *mtd, int chipnr)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct cafe_priv *cafe = nand_get_controller_data(chip);
++
++	cafe_dev_dbg(&cafe->pdev->dev, "select_chip %d\n", chipnr);
++
++	/* Mask the appropriate bit into the stored value of ctl1
++	   which will be used by cafe_nand_cmdfunc() */
++	if (chipnr)
++		cafe->ctl1 |= CTRL1_CHIPSELECT;
++	else
++		cafe->ctl1 &= ~CTRL1_CHIPSELECT;
++}
++
++static irqreturn_t cafe_nand_interrupt(int irq, void *id)
++{
++	struct mtd_info *mtd = id;
++	struct nand_chip *chip = mtd_to_nand(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);
++	if (!irqs)
++		return IRQ_NONE;
++
++	cafe_dev_dbg(&cafe->pdev->dev, "irq, bits %x (%x)\n", irqs, cafe_readl(cafe, NAND_IRQ));
++	return IRQ_HANDLED;
++}
++
++static void cafe_nand_bug(struct mtd_info *mtd)
++{
++	BUG();
++}
++
++static int cafe_nand_write_oob(struct mtd_info *mtd,
++			       struct nand_chip *chip, int page)
++{
++	int status = 0;
++
++	chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page);
++	chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
++	chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
++	status = chip->waitfunc(mtd, chip);
++
++	return status & NAND_STATUS_FAIL ? -EIO : 0;
++}
++
++/* Don't use -- use nand_read_oob_std for now */
++static int cafe_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
++			      int page)
++{
++	chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
++	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
++	return 0;
++}
++/**
++ * cafe_nand_read_page_syndrome - [REPLACEABLE] hardware ecc syndrome based page read
++ * @mtd:	mtd info structure
++ * @chip:	nand chip info structure
++ * @buf:	buffer to store read data
++ * @oob_required:	caller expects OOB data read to chip->oob_poi
++ *
++ * The hw generator calculates the error syndrome automatically. Therefore
++ * we need a special oob layout and handling.
++ */
++static int cafe_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
++			       uint8_t *buf, int oob_required, int page)
++{
++	struct cafe_priv *cafe = nand_get_controller_data(chip);
++	unsigned int max_bitflips = 0;
++
++	cafe_dev_dbg(&cafe->pdev->dev, "ECC result %08x SYN1,2 %08x\n",
++		     cafe_readl(cafe, NAND_ECC_RESULT),
++		     cafe_readl(cafe, NAND_ECC_SYN01));
++
++	chip->read_buf(mtd, buf, mtd->writesize);
++	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
++
++	if (checkecc && cafe_readl(cafe, NAND_ECC_RESULT) & (1<<18)) {
++		unsigned short syn[8], pat[4];
++		int pos[4];
++		u8 *oob = chip->oob_poi;
++		int i, n;
++
++		for (i=0; i<8; i+=2) {
++			uint32_t tmp = cafe_readl(cafe, NAND_ECC_SYN01 + (i*2));
++			syn[i] = cafe->rs->index_of[tmp & 0xfff];
++			syn[i+1] = cafe->rs->index_of[(tmp >> 16) & 0xfff];
++		}
++
++		n = decode_rs16(cafe->rs, NULL, NULL, 1367, syn, 0, pos, 0,
++		                pat);
++
++		for (i = 0; i < n; i++) {
++			int p = pos[i];
++
++			/* The 12-bit symbols are mapped to bytes here */
++
++			if (p > 1374) {
++				/* out of range */
++				n = -1374;
++			} else if (p == 0) {
++				/* high four bits do not correspond to data */
++				if (pat[i] > 0xff)
++					n = -2048;
++				else
++					buf[0] ^= pat[i];
++			} else if (p == 1365) {
++				buf[2047] ^= pat[i] >> 4;
++				oob[0] ^= pat[i] << 4;
++			} else if (p > 1365) {
++				if ((p & 1) == 1) {
++					oob[3*p/2 - 2048] ^= pat[i] >> 4;
++					oob[3*p/2 - 2047] ^= pat[i] << 4;
++				} else {
++					oob[3*p/2 - 2049] ^= pat[i] >> 8;
++					oob[3*p/2 - 2048] ^= pat[i];
++				}
++			} else if ((p & 1) == 1) {
++				buf[3*p/2] ^= pat[i] >> 4;
++				buf[3*p/2 + 1] ^= pat[i] << 4;
++			} else {
++				buf[3*p/2 - 1] ^= pat[i] >> 8;
++				buf[3*p/2] ^= pat[i];
++			}
++		}
++
++		if (n < 0) {
++			dev_dbg(&cafe->pdev->dev, "Failed to correct ECC at %08x\n",
++				cafe_readl(cafe, NAND_ADDR2) * 2048);
++			for (i = 0; i < 0x5c; i += 4)
++				printk("Register %x: %08x\n", i, readl(cafe->mmio + i));
++			mtd->ecc_stats.failed++;
++		} else {
++			dev_dbg(&cafe->pdev->dev, "Corrected %d symbol errors\n", n);
++			mtd->ecc_stats.corrected += n;
++			max_bitflips = max_t(unsigned int, max_bitflips, n);
++		}
++	}
++
++	return max_bitflips;
++}
++
++static int cafe_ooblayout_ecc(struct mtd_info *mtd, int section,
++			      struct mtd_oob_region *oobregion)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++
++	if (section)
++		return -ERANGE;
++
++	oobregion->offset = 0;
++	oobregion->length = chip->ecc.total;
++
++	return 0;
++}
++
++static int cafe_ooblayout_free(struct mtd_info *mtd, int section,
++			       struct mtd_oob_region *oobregion)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++
++	if (section)
++		return -ERANGE;
++
++	oobregion->offset = chip->ecc.total;
++	oobregion->length = mtd->oobsize - chip->ecc.total;
++
++	return 0;
++}
++
++static const struct mtd_ooblayout_ops cafe_ooblayout_ops = {
++	.ecc = cafe_ooblayout_ecc,
++	.free = cafe_ooblayout_free,
++};
++
++/* Ick. The BBT code really ought to be able to work this bit out
++   for itself from the above, at least for the 2KiB case */
++static uint8_t cafe_bbt_pattern_2048[] = { 'B', 'b', 't', '0' };
++static uint8_t cafe_mirror_pattern_2048[] = { '1', 't', 'b', 'B' };
++
++static uint8_t cafe_bbt_pattern_512[] = { 0xBB };
++static uint8_t cafe_mirror_pattern_512[] = { 0xBC };
++
++
++static struct nand_bbt_descr cafe_bbt_main_descr_2048 = {
++	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
++		| NAND_BBT_2BIT | NAND_BBT_VERSION,
++	.offs =	14,
++	.len = 4,
++	.veroffs = 18,
++	.maxblocks = 4,
++	.pattern = cafe_bbt_pattern_2048
++};
++
++static struct nand_bbt_descr cafe_bbt_mirror_descr_2048 = {
++	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
++		| NAND_BBT_2BIT | NAND_BBT_VERSION,
++	.offs =	14,
++	.len = 4,
++	.veroffs = 18,
++	.maxblocks = 4,
++	.pattern = cafe_mirror_pattern_2048
++};
++
++static struct nand_bbt_descr cafe_bbt_main_descr_512 = {
++	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
++		| NAND_BBT_2BIT | NAND_BBT_VERSION,
++	.offs =	14,
++	.len = 1,
++	.veroffs = 15,
++	.maxblocks = 4,
++	.pattern = cafe_bbt_pattern_512
++};
++
++static struct nand_bbt_descr cafe_bbt_mirror_descr_512 = {
++	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
++		| NAND_BBT_2BIT | NAND_BBT_VERSION,
++	.offs =	14,
++	.len = 1,
++	.veroffs = 15,
++	.maxblocks = 4,
++	.pattern = cafe_mirror_pattern_512
++};
++
++
++static int cafe_nand_write_page_lowlevel(struct mtd_info *mtd,
++					  struct nand_chip *chip,
++					  const uint8_t *buf, int oob_required,
++					  int page)
++{
++	struct cafe_priv *cafe = nand_get_controller_data(chip);
++
++	chip->write_buf(mtd, buf, mtd->writesize);
++	chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
++
++	/* Set up ECC autogeneration */
++	cafe->ctl2 |= (1<<30);
++
++	return 0;
++}
++
++static int cafe_nand_block_bad(struct mtd_info *mtd, loff_t ofs)
++{
++	return 0;
++}
++
++/* F_2[X]/(X**6+X+1)  */
++static unsigned short gf64_mul(u8 a, u8 b)
++{
++	u8 c;
++	unsigned int i;
++
++	c = 0;
++	for (i = 0; i < 6; i++) {
++		if (a & 1)
++			c ^= b;
++		a >>= 1;
++		b <<= 1;
++		if ((b & 0x40) != 0)
++			b ^= 0x43;
++	}
++
++	return c;
++}
++
++/* F_64[X]/(X**2+X+A**-1) with A the generator of F_64[X]  */
++static u16 gf4096_mul(u16 a, u16 b)
++{
++	u8 ah, al, bh, bl, ch, cl;
++
++	ah = a >> 6;
++	al = a & 0x3f;
++	bh = b >> 6;
++	bl = b & 0x3f;
++
++	ch = gf64_mul(ah ^ al, bh ^ bl) ^ gf64_mul(al, bl);
++	cl = gf64_mul(gf64_mul(ah, bh), 0x21) ^ gf64_mul(al, bl);
++
++	return (ch << 6) ^ cl;
++}
++
++static int cafe_mul(int x)
++{
++	if (x == 0)
++		return 1;
++	return gf4096_mul(x, 0xe01);
++}
++
++static int cafe_nand_probe(struct pci_dev *pdev,
++				     const struct pci_device_id *ent)
++{
++	struct mtd_info *mtd;
++	struct cafe_priv *cafe;
++	uint32_t ctrl;
++	int err = 0;
++	int old_dma;
++	struct nand_buffers *nbuf;
++
++	/* Very old versions shared the same PCI ident for all three
++	   functions on the chip. Verify the class too... */
++	if ((pdev->class >> 8) != PCI_CLASS_MEMORY_FLASH)
++		return -ENODEV;
++
++	err = pci_enable_device(pdev);
++	if (err)
++		return err;
++
++	pci_set_master(pdev);
++
++	cafe = kzalloc(sizeof(*cafe), GFP_KERNEL);
++	if (!cafe)
++		return  -ENOMEM;
++
++	mtd = nand_to_mtd(&cafe->nand);
++	mtd->dev.parent = &pdev->dev;
++	nand_set_controller_data(&cafe->nand, cafe);
++
++	cafe->pdev = pdev;
++	cafe->mmio = pci_iomap(pdev, 0, 0);
++	if (!cafe->mmio) {
++		dev_warn(&pdev->dev, "failed to iomap\n");
++		err = -ENOMEM;
++		goto out_free_mtd;
++	}
++
++	cafe->rs = init_rs_non_canonical(12, &cafe_mul, 0, 1, 8);
++	if (!cafe->rs) {
++		err = -ENOMEM;
++		goto out_ior;
++	}
++
++	cafe->nand.cmdfunc = cafe_nand_cmdfunc;
++	cafe->nand.dev_ready = cafe_device_ready;
++	cafe->nand.read_byte = cafe_read_byte;
++	cafe->nand.read_buf = cafe_read_buf;
++	cafe->nand.write_buf = cafe_write_buf;
++	cafe->nand.select_chip = cafe_select_chip;
++	cafe->nand.onfi_set_features = nand_onfi_get_set_features_notsupp;
++	cafe->nand.onfi_get_features = nand_onfi_get_set_features_notsupp;
++
++	cafe->nand.chip_delay = 0;
++
++	/* Enable the following for a flash based bad block table */
++	cafe->nand.bbt_options = NAND_BBT_USE_FLASH;
++	cafe->nand.options = NAND_OWN_BUFFERS;
++
++	if (skipbbt) {
++		cafe->nand.options |= NAND_SKIP_BBTSCAN;
++		cafe->nand.block_bad = cafe_nand_block_bad;
++	}
++
++	if (numtimings && numtimings != 3) {
++		dev_warn(&cafe->pdev->dev, "%d timing register values ignored; precisely three are required\n", numtimings);
++	}
++
++	if (numtimings == 3) {
++		cafe_dev_dbg(&cafe->pdev->dev, "Using provided timings (%08x %08x %08x)\n",
++			     timing[0], timing[1], timing[2]);
++	} else {
++		timing[0] = cafe_readl(cafe, NAND_TIMING1);
++		timing[1] = cafe_readl(cafe, NAND_TIMING2);
++		timing[2] = cafe_readl(cafe, NAND_TIMING3);
++
++		if (timing[0] | timing[1] | timing[2]) {
++			cafe_dev_dbg(&cafe->pdev->dev, "Timing registers already set (%08x %08x %08x)\n",
++				     timing[0], timing[1], timing[2]);
++		} else {
++			dev_warn(&cafe->pdev->dev, "Timing registers unset; using most conservative defaults\n");
++			timing[0] = timing[1] = timing[2] = 0xffffffff;
++		}
++	}
++
++	/* Start off by resetting the NAND controller completely */
++	cafe_writel(cafe, 1, NAND_RESET);
++	cafe_writel(cafe, 0, NAND_RESET);
++
++	cafe_writel(cafe, timing[0], NAND_TIMING1);
++	cafe_writel(cafe, timing[1], NAND_TIMING2);
++	cafe_writel(cafe, timing[2], NAND_TIMING3);
++
++	cafe_writel(cafe, 0xffffffff, NAND_IRQ_MASK);
++	err = request_irq(pdev->irq, &cafe_nand_interrupt, IRQF_SHARED,
++			  "CAFE NAND", mtd);
++	if (err) {
++		dev_warn(&pdev->dev, "Could not register IRQ %d\n", pdev->irq);
++		goto out_ior;
++	}
++
++	/* Disable master reset, enable NAND clock */
++	ctrl = cafe_readl(cafe, GLOBAL_CTRL);
++	ctrl &= 0xffffeff0;
++	ctrl |= 0x00007000;
++	cafe_writel(cafe, ctrl | 0x05, GLOBAL_CTRL);
++	cafe_writel(cafe, ctrl | 0x0a, GLOBAL_CTRL);
++	cafe_writel(cafe, 0, NAND_DMA_CTRL);
++
++	cafe_writel(cafe, 0x7006, GLOBAL_CTRL);
++	cafe_writel(cafe, 0x700a, GLOBAL_CTRL);
++
++	/* Enable NAND IRQ in global IRQ mask register */
++	cafe_writel(cafe, 0x80000007, GLOBAL_IRQ_MASK);
++	cafe_dev_dbg(&cafe->pdev->dev, "Control %x, IRQ mask %x\n",
++		cafe_readl(cafe, GLOBAL_CTRL),
++		cafe_readl(cafe, GLOBAL_IRQ_MASK));
++
++	/* Do not use the DMA for the nand_scan_ident() */
++	old_dma = usedma;
++	usedma = 0;
++
++	/* Scan to find existence of the device */
++	err = nand_scan_ident(mtd, 2, NULL);
++	if (err)
++		goto out_irq;
++
++	cafe->dmabuf = dma_alloc_coherent(&cafe->pdev->dev,
++				2112 + sizeof(struct nand_buffers) +
++				mtd->writesize + mtd->oobsize,
++				&cafe->dmaaddr, GFP_KERNEL);
++	if (!cafe->dmabuf) {
++		err = -ENOMEM;
++		goto out_irq;
++	}
++	cafe->nand.buffers = nbuf = (void *)cafe->dmabuf + 2112;
++
++	/* Set up DMA address */
++	cafe_writel(cafe, cafe->dmaaddr & 0xffffffff, NAND_DMA_ADDR0);
++	if (sizeof(cafe->dmaaddr) > 4)
++		/* Shift in two parts to shut the compiler up */
++		cafe_writel(cafe, (cafe->dmaaddr >> 16) >> 16, NAND_DMA_ADDR1);
++	else
++		cafe_writel(cafe, 0, NAND_DMA_ADDR1);
++
++	cafe_dev_dbg(&cafe->pdev->dev, "Set DMA address to %x (virt %p)\n",
++		cafe_readl(cafe, NAND_DMA_ADDR0), cafe->dmabuf);
++
++	/* this driver does not need the @ecccalc and @ecccode */
++	nbuf->ecccalc = NULL;
++	nbuf->ecccode = NULL;
++	nbuf->databuf = (uint8_t *)(nbuf + 1);
++
++	/* Restore the DMA flag */
++	usedma = old_dma;
++
++	cafe->ctl2 = 1<<27; /* Reed-Solomon ECC */
++	if (mtd->writesize == 2048)
++		cafe->ctl2 |= 1<<29; /* 2KiB page size */
++
++	/* Set up ECC according to the type of chip we found */
++	mtd_set_ooblayout(mtd, &cafe_ooblayout_ops);
++	if (mtd->writesize == 2048) {
++		cafe->nand.bbt_td = &cafe_bbt_main_descr_2048;
++		cafe->nand.bbt_md = &cafe_bbt_mirror_descr_2048;
++	} else if (mtd->writesize == 512) {
++		cafe->nand.bbt_td = &cafe_bbt_main_descr_512;
++		cafe->nand.bbt_md = &cafe_bbt_mirror_descr_512;
++	} else {
++		printk(KERN_WARNING "Unexpected NAND flash writesize %d. Aborting\n",
++		       mtd->writesize);
++		goto out_free_dma;
++	}
++	cafe->nand.ecc.mode = NAND_ECC_HW_SYNDROME;
++	cafe->nand.ecc.size = mtd->writesize;
++	cafe->nand.ecc.bytes = 14;
++	cafe->nand.ecc.strength = 4;
++	cafe->nand.ecc.hwctl  = (void *)cafe_nand_bug;
++	cafe->nand.ecc.calculate = (void *)cafe_nand_bug;
++	cafe->nand.ecc.correct  = (void *)cafe_nand_bug;
++	cafe->nand.ecc.write_page = cafe_nand_write_page_lowlevel;
++	cafe->nand.ecc.write_oob = cafe_nand_write_oob;
++	cafe->nand.ecc.read_page = cafe_nand_read_page;
++	cafe->nand.ecc.read_oob = cafe_nand_read_oob;
++
++	err = nand_scan_tail(mtd);
++	if (err)
++		goto out_free_dma;
++
++	pci_set_drvdata(pdev, mtd);
++
++	mtd->name = "cafe_nand";
++	mtd_device_parse_register(mtd, part_probes, NULL, NULL, 0);
++
++	goto out;
++
++ out_free_dma:
++	dma_free_coherent(&cafe->pdev->dev,
++			2112 + sizeof(struct nand_buffers) +
++			mtd->writesize + mtd->oobsize,
++			cafe->dmabuf, cafe->dmaaddr);
++ out_irq:
++	/* Disable NAND IRQ in global IRQ mask register */
++	cafe_writel(cafe, ~1 & cafe_readl(cafe, GLOBAL_IRQ_MASK), GLOBAL_IRQ_MASK);
++	free_irq(pdev->irq, mtd);
++ out_ior:
++	pci_iounmap(pdev, cafe->mmio);
++ out_free_mtd:
++	kfree(cafe);
++ out:
++	return err;
++}
++
++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 cafe_priv *cafe = nand_get_controller_data(chip);
++
++	/* Disable NAND IRQ in global IRQ mask register */
++	cafe_writel(cafe, ~1 & cafe_readl(cafe, GLOBAL_IRQ_MASK), GLOBAL_IRQ_MASK);
++	free_irq(pdev->irq, mtd);
++	nand_release(mtd);
++	free_rs(cafe->rs);
++	pci_iounmap(pdev, cafe->mmio);
++	dma_free_coherent(&cafe->pdev->dev,
++			2112 + sizeof(struct nand_buffers) +
++			mtd->writesize + mtd->oobsize,
++			cafe->dmabuf, cafe->dmaaddr);
++	kfree(cafe);
++}
++
++static const struct pci_device_id cafe_nand_tbl[] = {
++	{ PCI_VENDOR_ID_MARVELL, PCI_DEVICE_ID_MARVELL_88ALP01_NAND,
++	  PCI_ANY_ID, PCI_ANY_ID },
++	{ }
++};
++
++MODULE_DEVICE_TABLE(pci, cafe_nand_tbl);
++
++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 cafe_priv *cafe = nand_get_controller_data(chip);
++
++       /* Start off by resetting the NAND controller completely */
++	cafe_writel(cafe, 1, NAND_RESET);
++	cafe_writel(cafe, 0, NAND_RESET);
++	cafe_writel(cafe, 0xffffffff, NAND_IRQ_MASK);
++
++	/* Restore timing configuration */
++	cafe_writel(cafe, timing[0], NAND_TIMING1);
++	cafe_writel(cafe, timing[1], NAND_TIMING2);
++	cafe_writel(cafe, timing[2], NAND_TIMING3);
++
++        /* Disable master reset, enable NAND clock */
++	ctrl = cafe_readl(cafe, GLOBAL_CTRL);
++	ctrl &= 0xffffeff0;
++	ctrl |= 0x00007000;
++	cafe_writel(cafe, ctrl | 0x05, GLOBAL_CTRL);
++	cafe_writel(cafe, ctrl | 0x0a, GLOBAL_CTRL);
++	cafe_writel(cafe, 0, NAND_DMA_CTRL);
++	cafe_writel(cafe, 0x7006, GLOBAL_CTRL);
++	cafe_writel(cafe, 0x700a, GLOBAL_CTRL);
++
++	/* Set up DMA address */
++	cafe_writel(cafe, cafe->dmaaddr & 0xffffffff, NAND_DMA_ADDR0);
++	if (sizeof(cafe->dmaaddr) > 4)
++	/* Shift in two parts to shut the compiler up */
++		cafe_writel(cafe, (cafe->dmaaddr >> 16) >> 16, NAND_DMA_ADDR1);
++	else
++		cafe_writel(cafe, 0, NAND_DMA_ADDR1);
++
++	/* Enable NAND IRQ in global IRQ mask register */
++	cafe_writel(cafe, 0x80000007, GLOBAL_IRQ_MASK);
++	return 0;
++}
++
++static struct pci_driver cafe_nand_pci_driver = {
++	.name = "CAFÉ NAND",
++	.id_table = cafe_nand_tbl,
++	.probe = cafe_nand_probe,
++	.remove = cafe_nand_remove,
++	.resume = cafe_nand_resume,
++};
++
++module_pci_driver(cafe_nand_pci_driver);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
++MODULE_DESCRIPTION("NAND flash driver for OLPC CAFÉ chip");
+diff --git a/drivers/mtd/nand/raw/cmx270_nand.c b/drivers/mtd/nand/raw/cmx270_nand.c
+new file mode 100644
+index 0000000..1fc435f
+--- /dev/null
++++ b/drivers/mtd/nand/raw/cmx270_nand.c
+@@ -0,0 +1,246 @@
++/*
++ *  linux/drivers/mtd/nand/cmx270-nand.c
++ *
++ *  Copyright (C) 2006 Compulab, Ltd.
++ *  Mike Rapoport <mike@compulab.co.il>
++ *
++ *  Derived from drivers/mtd/nand/h1910.c
++ *       Copyright (C) 2002 Marius Gröger (mag@sysgo.de)
++ *       Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de)
++ *
++ *
++ * 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.
++ *
++ *  Overview:
++ *   This is a device driver for the NAND flash device found on the
++ *   CM-X270 board.
++ */
++
++#include <linux/mtd/rawnand.h>
++#include <linux/mtd/partitions.h>
++#include <linux/slab.h>
++#include <linux/gpio.h>
++#include <linux/module.h>
++
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/mach-types.h>
++
++#include <mach/pxa2xx-regs.h>
++
++#define GPIO_NAND_CS	(11)
++#define GPIO_NAND_RB	(89)
++
++/* MTD structure for CM-X270 board */
++static struct mtd_info *cmx270_nand_mtd;
++
++/* remaped IO address of the device */
++static void __iomem *cmx270_nand_io;
++
++/*
++ * Define static partitions for flash device
++ */
++static struct mtd_partition partition_info[] = {
++	[0] = {
++		.name	= "cmx270-0",
++		.offset	= 0,
++		.size	= MTDPART_SIZ_FULL
++	}
++};
++#define NUM_PARTITIONS (ARRAY_SIZE(partition_info))
++
++static u_char cmx270_read_byte(struct mtd_info *mtd)
++{
++	struct nand_chip *this = mtd_to_nand(mtd);
++
++	return (readl(this->IO_ADDR_R) >> 16);
++}
++
++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);
++
++	for (i=0; i<len; i++)
++		writel((*buf++ << 16), this->IO_ADDR_W);
++}
++
++static void cmx270_read_buf(struct mtd_info *mtd, u_char *buf, int len)
++{
++	int i;
++	struct nand_chip *this = mtd_to_nand(mtd);
++
++	for (i=0; i<len; i++)
++		*buf++ = readl(this->IO_ADDR_R) >> 16;
++}
++
++static inline void nand_cs_on(void)
++{
++	gpio_set_value(GPIO_NAND_CS, 0);
++}
++
++static void nand_cs_off(void)
++{
++	dsb();
++
++	gpio_set_value(GPIO_NAND_CS, 1);
++}
++
++/*
++ *	hardware specific access to control-lines
++ */
++static void cmx270_hwcontrol(struct mtd_info *mtd, int dat,
++			     unsigned int ctrl)
++{
++	struct nand_chip *this = mtd_to_nand(mtd);
++	unsigned int nandaddr = (unsigned int)this->IO_ADDR_W;
++
++	dsb();
++
++	if (ctrl & NAND_CTRL_CHANGE) {
++		if ( ctrl & NAND_ALE )
++			nandaddr |=  (1 << 3);
++		else
++			nandaddr &= ~(1 << 3);
++		if ( ctrl & NAND_CLE )
++			nandaddr |=  (1 << 2);
++		else
++			nandaddr &= ~(1 << 2);
++		if ( ctrl & NAND_NCE )
++			nand_cs_on();
++		else
++			nand_cs_off();
++	}
++
++	dsb();
++	this->IO_ADDR_W = (void __iomem*)nandaddr;
++	if (dat != NAND_CMD_NONE)
++		writel((dat << 16), this->IO_ADDR_W);
++
++	dsb();
++}
++
++/*
++ *	read device ready pin
++ */
++static int cmx270_device_ready(struct mtd_info *mtd)
++{
++	dsb();
++
++	return (gpio_get_value(GPIO_NAND_RB));
++}
++
++/*
++ * Main initialization routine
++ */
++static int __init cmx270_init(void)
++{
++	struct nand_chip *this;
++	int ret;
++
++	if (!(machine_is_armcore() && cpu_is_pxa27x()))
++		return -ENODEV;
++
++	ret = gpio_request(GPIO_NAND_CS, "NAND CS");
++	if (ret) {
++		pr_warn("CM-X270: failed to request NAND CS gpio\n");
++		return ret;
++	}
++
++	gpio_direction_output(GPIO_NAND_CS, 1);
++
++	ret = gpio_request(GPIO_NAND_RB, "NAND R/B");
++	if (ret) {
++		pr_warn("CM-X270: failed to request NAND R/B gpio\n");
++		goto err_gpio_request;
++	}
++
++	gpio_direction_input(GPIO_NAND_RB);
++
++	/* Allocate memory for MTD device structure and private data */
++	this = kzalloc(sizeof(struct nand_chip), GFP_KERNEL);
++	if (!this) {
++		ret = -ENOMEM;
++		goto err_kzalloc;
++	}
++
++	cmx270_nand_io = ioremap(PXA_CS1_PHYS, 12);
++	if (!cmx270_nand_io) {
++		pr_debug("Unable to ioremap NAND device\n");
++		ret = -EINVAL;
++		goto err_ioremap;
++	}
++
++	cmx270_nand_mtd = nand_to_mtd(this);
++
++	/* Link the private data with the MTD structure */
++	cmx270_nand_mtd->owner = THIS_MODULE;
++
++	/* insert callbacks */
++	this->IO_ADDR_R = cmx270_nand_io;
++	this->IO_ADDR_W = cmx270_nand_io;
++	this->cmd_ctrl = cmx270_hwcontrol;
++	this->dev_ready = cmx270_device_ready;
++
++	/* 15 us command delay time */
++	this->chip_delay = 20;
++	this->ecc.mode = NAND_ECC_SOFT;
++	this->ecc.algo = NAND_ECC_HAMMING;
++
++	/* read/write functions */
++	this->read_byte = cmx270_read_byte;
++	this->read_buf = cmx270_read_buf;
++	this->write_buf = cmx270_write_buf;
++
++	/* Scan to find existence of the device */
++	ret = nand_scan(cmx270_nand_mtd, 1);
++	if (ret) {
++		pr_notice("No NAND device\n");
++		goto err_scan;
++	}
++
++	/* Register the partitions */
++	ret = mtd_device_parse_register(cmx270_nand_mtd, NULL, NULL,
++					partition_info, NUM_PARTITIONS);
++	if (ret)
++		goto err_scan;
++
++	/* Return happy */
++	return 0;
++
++err_scan:
++	iounmap(cmx270_nand_io);
++err_ioremap:
++	kfree(this);
++err_kzalloc:
++	gpio_free(GPIO_NAND_RB);
++err_gpio_request:
++	gpio_free(GPIO_NAND_CS);
++
++	return ret;
++
++}
++module_init(cmx270_init);
++
++/*
++ * Clean up routine
++ */
++static void __exit cmx270_cleanup(void)
++{
++	/* Release resources, unregister device */
++	nand_release(cmx270_nand_mtd);
++
++	gpio_free(GPIO_NAND_RB);
++	gpio_free(GPIO_NAND_CS);
++
++	iounmap(cmx270_nand_io);
++
++	kfree(mtd_to_nand(cmx270_nand_mtd));
++}
++module_exit(cmx270_cleanup);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>");
++MODULE_DESCRIPTION("NAND flash driver for Compulab CM-X270 Module");
+diff --git a/drivers/mtd/nand/raw/cs553x_nand.c b/drivers/mtd/nand/raw/cs553x_nand.c
+new file mode 100644
+index 0000000..d488775
+--- /dev/null
++++ b/drivers/mtd/nand/raw/cs553x_nand.c
+@@ -0,0 +1,357 @@
++/*
++ * drivers/mtd/nand/cs553x_nand.c
++ *
++ * (C) 2005, 2006 Red Hat Inc.
++ *
++ * Author: David Woodhouse <dwmw2@infradead.org>
++ *	   Tom Sylla <tom.sylla@amd.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.
++ *
++ *  Overview:
++ *   This is a device driver for the NAND flash controller found on
++ *   the AMD CS5535/CS5536 companion chipsets for the Geode processor.
++ *   mtd-id for command line partitioning is cs553x_nand_cs[0-3]
++ *   where 0-3 reflects the chip select for NAND.
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/delay.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/rawnand.h>
++#include <linux/mtd/nand_ecc.h>
++#include <linux/mtd/partitions.h>
++
++#include <asm/msr.h>
++#include <asm/io.h>
++
++#define NR_CS553X_CONTROLLERS	4
++
++#define MSR_DIVIL_GLD_CAP	0x51400000	/* DIVIL capabilitiies */
++#define CAP_CS5535		0x2df000ULL
++#define CAP_CS5536		0x5df500ULL
++
++/* NAND Timing MSRs */
++#define MSR_NANDF_DATA		0x5140001b	/* NAND Flash Data Timing MSR */
++#define MSR_NANDF_CTL		0x5140001c	/* NAND Flash Control Timing */
++#define MSR_NANDF_RSVD		0x5140001d	/* Reserved */
++
++/* NAND BAR MSRs */
++#define MSR_DIVIL_LBAR_FLSH0	0x51400010	/* Flash Chip Select 0 */
++#define MSR_DIVIL_LBAR_FLSH1	0x51400011	/* Flash Chip Select 1 */
++#define MSR_DIVIL_LBAR_FLSH2	0x51400012	/* Flash Chip Select 2 */
++#define MSR_DIVIL_LBAR_FLSH3	0x51400013	/* Flash Chip Select 3 */
++	/* Each made up of... */
++#define FLSH_LBAR_EN		(1ULL<<32)
++#define FLSH_NOR_NAND		(1ULL<<33)	/* 1 for NAND */
++#define FLSH_MEM_IO		(1ULL<<34)	/* 1 for MMIO */
++	/* I/O BARs have BASE_ADDR in bits 15:4, IO_MASK in 47:36 */
++	/* MMIO BARs have BASE_ADDR in bits 31:12, MEM_MASK in 63:44 */
++
++/* Pin function selection MSR (IDE vs. flash on the IDE pins) */
++#define MSR_DIVIL_BALL_OPTS	0x51400015
++#define PIN_OPT_IDE		(1<<0)	/* 0 for flash, 1 for IDE */
++
++/* Registers within the NAND flash controller BAR -- memory mapped */
++#define MM_NAND_DATA		0x00	/* 0 to 0x7ff, in fact */
++#define MM_NAND_CTL		0x800	/* Any even address 0x800-0x80e */
++#define MM_NAND_IO		0x801	/* Any odd address 0x801-0x80f */
++#define MM_NAND_STS		0x810
++#define MM_NAND_ECC_LSB		0x811
++#define MM_NAND_ECC_MSB		0x812
++#define MM_NAND_ECC_COL		0x813
++#define MM_NAND_LAC		0x814
++#define MM_NAND_ECC_CTL		0x815
++
++/* Registers within the NAND flash controller BAR -- I/O mapped */
++#define IO_NAND_DATA		0x00	/* 0 to 3, in fact */
++#define IO_NAND_CTL		0x04
++#define IO_NAND_IO		0x05
++#define IO_NAND_STS		0x06
++#define IO_NAND_ECC_CTL		0x08
++#define IO_NAND_ECC_LSB		0x09
++#define IO_NAND_ECC_MSB		0x0a
++#define IO_NAND_ECC_COL		0x0b
++#define IO_NAND_LAC		0x0c
++
++#define CS_NAND_CTL_DIST_EN	(1<<4)	/* Enable NAND Distract interrupt */
++#define CS_NAND_CTL_RDY_INT_MASK	(1<<3)	/* Enable RDY/BUSY# interrupt */
++#define CS_NAND_CTL_ALE		(1<<2)
++#define CS_NAND_CTL_CLE		(1<<1)
++#define CS_NAND_CTL_CE		(1<<0)	/* Keep low; 1 to reset */
++
++#define CS_NAND_STS_FLASH_RDY	(1<<3)
++#define CS_NAND_CTLR_BUSY	(1<<2)
++#define CS_NAND_CMD_COMP	(1<<1)
++#define CS_NAND_DIST_ST		(1<<0)
++
++#define CS_NAND_ECC_PARITY	(1<<2)
++#define CS_NAND_ECC_CLRECC	(1<<1)
++#define CS_NAND_ECC_ENECC	(1<<0)
++
++static void cs553x_read_buf(struct mtd_info *mtd, u_char *buf, int len)
++{
++	struct nand_chip *this = mtd_to_nand(mtd);
++
++	while (unlikely(len > 0x800)) {
++		memcpy_fromio(buf, this->IO_ADDR_R, 0x800);
++		buf += 0x800;
++		len -= 0x800;
++	}
++	memcpy_fromio(buf, this->IO_ADDR_R, len);
++}
++
++static void cs553x_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
++{
++	struct nand_chip *this = mtd_to_nand(mtd);
++
++	while (unlikely(len > 0x800)) {
++		memcpy_toio(this->IO_ADDR_R, buf, 0x800);
++		buf += 0x800;
++		len -= 0x800;
++	}
++	memcpy_toio(this->IO_ADDR_R, buf, len);
++}
++
++static unsigned char cs553x_read_byte(struct mtd_info *mtd)
++{
++	struct nand_chip *this = mtd_to_nand(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);
++	int i = 100000;
++
++	while (i && readb(this->IO_ADDR_R + MM_NAND_STS) & CS_NAND_CTLR_BUSY) {
++		udelay(1);
++		i--;
++	}
++	writeb(byte, this->IO_ADDR_W + 0x801);
++}
++
++static void cs553x_hwcontrol(struct mtd_info *mtd, int cmd,
++			     unsigned int ctrl)
++{
++	struct nand_chip *this = mtd_to_nand(mtd);
++	void __iomem *mmio_base = this->IO_ADDR_R;
++	if (ctrl & NAND_CTRL_CHANGE) {
++		unsigned char ctl = (ctrl & ~NAND_CTRL_CHANGE ) ^ 0x01;
++		writeb(ctl, mmio_base + MM_NAND_CTL);
++	}
++	if (cmd != NAND_CMD_NONE)
++		cs553x_write_byte(mtd, cmd);
++}
++
++static int cs553x_device_ready(struct mtd_info *mtd)
++{
++	struct nand_chip *this = mtd_to_nand(mtd);
++	void __iomem *mmio_base = this->IO_ADDR_R;
++	unsigned char foo = readb(mmio_base + MM_NAND_STS);
++
++	return (foo & CS_NAND_STS_FLASH_RDY) && !(foo & CS_NAND_CTLR_BUSY);
++}
++
++static void cs_enable_hwecc(struct mtd_info *mtd, int mode)
++{
++	struct nand_chip *this = mtd_to_nand(mtd);
++	void __iomem *mmio_base = this->IO_ADDR_R;
++
++	writeb(0x07, mmio_base + MM_NAND_ECC_CTL);
++}
++
++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);
++	void __iomem *mmio_base = this->IO_ADDR_R;
++
++	ecc = readl(mmio_base + MM_NAND_STS);
++
++	ecc_code[1] = ecc >> 8;
++	ecc_code[0] = ecc >> 16;
++	ecc_code[2] = ecc >> 24;
++	return 0;
++}
++
++static struct mtd_info *cs553x_mtd[4];
++
++static int __init cs553x_init_one(int cs, int mmio, unsigned long adr)
++{
++	int err = 0;
++	struct nand_chip *this;
++	struct mtd_info *new_mtd;
++
++	printk(KERN_NOTICE "Probing CS553x NAND controller CS#%d at %sIO 0x%08lx\n", cs, mmio?"MM":"P", adr);
++
++	if (!mmio) {
++		printk(KERN_NOTICE "PIO mode not yet implemented for CS553X NAND controller\n");
++		return -ENXIO;
++	}
++
++	/* Allocate memory for MTD device structure and private data */
++	this = kzalloc(sizeof(struct nand_chip), GFP_KERNEL);
++	if (!this) {
++		err = -ENOMEM;
++		goto out;
++	}
++
++	new_mtd = nand_to_mtd(this);
++
++	/* Link the private data with the MTD structure */
++	new_mtd->owner = THIS_MODULE;
++
++	/* map physical address */
++	this->IO_ADDR_R = this->IO_ADDR_W = ioremap(adr, 4096);
++	if (!this->IO_ADDR_R) {
++		printk(KERN_WARNING "ioremap cs553x NAND @0x%08lx failed\n", adr);
++		err = -EIO;
++		goto out_mtd;
++	}
++
++	this->cmd_ctrl = cs553x_hwcontrol;
++	this->dev_ready = cs553x_device_ready;
++	this->read_byte = cs553x_read_byte;
++	this->read_buf = cs553x_read_buf;
++	this->write_buf = cs553x_write_buf;
++
++	this->chip_delay = 0;
++
++	this->ecc.mode = NAND_ECC_HW;
++	this->ecc.size = 256;
++	this->ecc.bytes = 3;
++	this->ecc.hwctl  = cs_enable_hwecc;
++	this->ecc.calculate = cs_calculate_ecc;
++	this->ecc.correct  = nand_correct_data;
++	this->ecc.strength = 1;
++
++	/* Enable the following for a flash based bad block table */
++	this->bbt_options = NAND_BBT_USE_FLASH;
++
++	new_mtd->name = kasprintf(GFP_KERNEL, "cs553x_nand_cs%d", cs);
++	if (!new_mtd->name) {
++		err = -ENOMEM;
++		goto out_ior;
++	}
++
++	/* Scan to find existence of the device */
++	err = nand_scan(new_mtd, 1);
++	if (err)
++		goto out_free;
++
++	cs553x_mtd[cs] = new_mtd;
++	goto out;
++
++out_free:
++	kfree(new_mtd->name);
++out_ior:
++	iounmap(this->IO_ADDR_R);
++out_mtd:
++	kfree(this);
++out:
++	return err;
++}
++
++static int is_geode(void)
++{
++	/* These are the CPUs which will have a CS553[56] companion chip */
++	if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD &&
++	    boot_cpu_data.x86 == 5 &&
++	    boot_cpu_data.x86_model == 10)
++		return 1; /* Geode LX */
++
++	if ((boot_cpu_data.x86_vendor == X86_VENDOR_NSC ||
++	     boot_cpu_data.x86_vendor == X86_VENDOR_CYRIX) &&
++	    boot_cpu_data.x86 == 5 &&
++	    boot_cpu_data.x86_model == 5)
++		return 1; /* Geode GX (née GX2) */
++
++	return 0;
++}
++
++static int __init cs553x_init(void)
++{
++	int err = -ENXIO;
++	int i;
++	uint64_t val;
++
++	/* If the CPU isn't a Geode GX or LX, abort */
++	if (!is_geode())
++		return -ENXIO;
++
++	/* If it doesn't have the CS553[56], abort */
++	rdmsrl(MSR_DIVIL_GLD_CAP, val);
++	val &= ~0xFFULL;
++	if (val != CAP_CS5535 && val != CAP_CS5536)
++		return -ENXIO;
++
++	/* If it doesn't have the NAND controller enabled, abort */
++	rdmsrl(MSR_DIVIL_BALL_OPTS, val);
++	if (val & PIN_OPT_IDE) {
++		printk(KERN_INFO "CS553x NAND controller: Flash I/O not enabled in MSR_DIVIL_BALL_OPTS.\n");
++		return -ENXIO;
++	}
++
++	for (i = 0; i < NR_CS553X_CONTROLLERS; i++) {
++		rdmsrl(MSR_DIVIL_LBAR_FLSH0 + i, val);
++
++		if ((val & (FLSH_LBAR_EN|FLSH_NOR_NAND)) == (FLSH_LBAR_EN|FLSH_NOR_NAND))
++			err = cs553x_init_one(i, !!(val & FLSH_MEM_IO), val & 0xFFFFFFFF);
++	}
++
++	/* Register all devices together here. This means we can easily hack it to
++	   do mtdconcat etc. if we want to. */
++	for (i = 0; i < NR_CS553X_CONTROLLERS; i++) {
++		if (cs553x_mtd[i]) {
++			/* If any devices registered, return success. Else the last error. */
++			mtd_device_parse_register(cs553x_mtd[i], NULL, NULL,
++						  NULL, 0);
++			err = 0;
++		}
++	}
++
++	return err;
++}
++
++module_init(cs553x_init);
++
++static void __exit cs553x_cleanup(void)
++{
++	int i;
++
++	for (i = 0; i < NR_CS553X_CONTROLLERS; i++) {
++		struct mtd_info *mtd = cs553x_mtd[i];
++		struct nand_chip *this;
++		void __iomem *mmio_base;
++
++		if (!mtd)
++			continue;
++
++		this = mtd_to_nand(mtd);
++		mmio_base = this->IO_ADDR_R;
++
++		/* Release resources, unregister device */
++		nand_release(mtd);
++		kfree(mtd->name);
++		cs553x_mtd[i] = NULL;
++
++		/* unmap physical address */
++		iounmap(mmio_base);
++
++		/* Free the MTD device structure */
++		kfree(this);
++	}
++}
++
++module_exit(cs553x_cleanup);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
++MODULE_DESCRIPTION("NAND controller driver for AMD CS5535/CS5536 companion chip");
+diff --git a/drivers/mtd/nand/raw/davinci_nand.c b/drivers/mtd/nand/raw/davinci_nand.c
+new file mode 100644
+index 0000000..ccc8c43
+--- /dev/null
++++ b/drivers/mtd/nand/raw/davinci_nand.c
+@@ -0,0 +1,879 @@
++/*
++ * davinci_nand.c - NAND Flash Driver for DaVinci family chips
++ *
++ * Copyright © 2006 Texas Instruments.
++ *
++ * Port to 2.6.23 Copyright © 2008 by:
++ *   Sander Huijsen <Shuijsen@optelecom-nkf.com>
++ *   Troy Kisky <troy.kisky@boundarydevices.com>
++ *   Dirk Behme <Dirk.Behme@gmail.com>
++ *
++ * 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.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/err.h>
++#include <linux/clk.h>
++#include <linux/io.h>
++#include <linux/mtd/rawnand.h>
++#include <linux/mtd/partitions.h>
++#include <linux/slab.h>
++#include <linux/of_device.h>
++#include <linux/of.h>
++
++#include <linux/platform_data/mtd-davinci.h>
++#include <linux/platform_data/mtd-davinci-aemif.h>
++
++/*
++ * This is a device driver for the NAND flash controller found on the
++ * various DaVinci family chips.  It handles up to four SoC chipselects,
++ * and some flavors of secondary chipselect (e.g. based on A12) as used
++ * with multichip packages.
++ *
++ * The 1-bit ECC hardware is supported, as well as the newer 4-bit ECC
++ * available on chips like the DM355 and OMAP-L137 and needed with the
++ * more error-prone MLC NAND chips.
++ *
++ * This driver assumes EM_WAIT connects all the NAND devices' RDY/nBUSY
++ * outputs in a "wire-AND" configuration, with no per-chip signals.
++ */
++struct davinci_nand_info {
++	struct nand_chip	chip;
++
++	struct device		*dev;
++	struct clk		*clk;
++
++	bool			is_readmode;
++
++	void __iomem		*base;
++	void __iomem		*vaddr;
++
++	uint32_t		ioaddr;
++	uint32_t		current_cs;
++
++	uint32_t		mask_chipsel;
++	uint32_t		mask_ale;
++	uint32_t		mask_cle;
++
++	uint32_t		core_chipsel;
++
++	struct davinci_aemif_timing	*timing;
++};
++
++static DEFINE_SPINLOCK(davinci_nand_lock);
++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);
++}
++
++static inline unsigned int davinci_nand_readl(struct davinci_nand_info *info,
++		int offset)
++{
++	return __raw_readl(info->base + offset);
++}
++
++static inline void davinci_nand_writel(struct davinci_nand_info *info,
++		int offset, unsigned long value)
++{
++	__raw_writel(value, info->base + offset);
++}
++
++/*----------------------------------------------------------------------*/
++
++/*
++ * Access to hardware control lines:  ALE, CLE, secondary chipselect.
++ */
++
++static void nand_davinci_hwcontrol(struct mtd_info *mtd, int cmd,
++				   unsigned int ctrl)
++{
++	struct davinci_nand_info	*info = to_davinci_nand(mtd);
++	uint32_t			addr = info->current_cs;
++	struct nand_chip		*nand = mtd_to_nand(mtd);
++
++	/* Did the control lines change? */
++	if (ctrl & NAND_CTRL_CHANGE) {
++		if ((ctrl & NAND_CTRL_CLE) == NAND_CTRL_CLE)
++			addr |= info->mask_cle;
++		else if ((ctrl & NAND_CTRL_ALE) == NAND_CTRL_ALE)
++			addr |= info->mask_ale;
++
++		nand->IO_ADDR_W = (void __iomem __force *)addr;
++	}
++
++	if (cmd != NAND_CMD_NONE)
++		iowrite8(cmd, nand->IO_ADDR_W);
++}
++
++static void nand_davinci_select_chip(struct mtd_info *mtd, int chip)
++{
++	struct davinci_nand_info	*info = to_davinci_nand(mtd);
++	uint32_t			addr = info->ioaddr;
++
++	/* maybe kick in a second chipselect */
++	if (chip > 0)
++		addr |= info->mask_chipsel;
++	info->current_cs = addr;
++
++	info->chip.IO_ADDR_W = (void __iomem __force *)addr;
++	info->chip.IO_ADDR_R = info->chip.IO_ADDR_W;
++}
++
++/*----------------------------------------------------------------------*/
++
++/*
++ * 1-bit hardware ECC ... context maintained for each core chipselect
++ */
++
++static inline uint32_t nand_davinci_readecc_1bit(struct mtd_info *mtd)
++{
++	struct davinci_nand_info *info = to_davinci_nand(mtd);
++
++	return davinci_nand_readl(info, NANDF1ECC_OFFSET
++			+ 4 * info->core_chipsel);
++}
++
++static void nand_davinci_hwctl_1bit(struct mtd_info *mtd, int mode)
++{
++	struct davinci_nand_info *info;
++	uint32_t nandcfr;
++	unsigned long flags;
++
++	info = to_davinci_nand(mtd);
++
++	/* Reset ECC hardware */
++	nand_davinci_readecc_1bit(mtd);
++
++	spin_lock_irqsave(&davinci_nand_lock, flags);
++
++	/* Restart ECC hardware */
++	nandcfr = davinci_nand_readl(info, NANDFCR_OFFSET);
++	nandcfr |= BIT(8 + info->core_chipsel);
++	davinci_nand_writel(info, NANDFCR_OFFSET, nandcfr);
++
++	spin_unlock_irqrestore(&davinci_nand_lock, flags);
++}
++
++/*
++ * Read hardware ECC value and pack into three bytes
++ */
++static int nand_davinci_calculate_1bit(struct mtd_info *mtd,
++				      const u_char *dat, u_char *ecc_code)
++{
++	unsigned int ecc_val = nand_davinci_readecc_1bit(mtd);
++	unsigned int ecc24 = (ecc_val & 0x0fff) | ((ecc_val & 0x0fff0000) >> 4);
++
++	/* invert so that erased block ecc is correct */
++	ecc24 = ~ecc24;
++	ecc_code[0] = (u_char)(ecc24);
++	ecc_code[1] = (u_char)(ecc24 >> 8);
++	ecc_code[2] = (u_char)(ecc24 >> 16);
++
++	return 0;
++}
++
++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);
++	uint32_t eccNand = read_ecc[0] | (read_ecc[1] << 8) |
++					  (read_ecc[2] << 16);
++	uint32_t eccCalc = calc_ecc[0] | (calc_ecc[1] << 8) |
++					  (calc_ecc[2] << 16);
++	uint32_t diff = eccCalc ^ eccNand;
++
++	if (diff) {
++		if ((((diff >> 12) ^ diff) & 0xfff) == 0xfff) {
++			/* Correctable error */
++			if ((diff >> (12 + 3)) < chip->ecc.size) {
++				dat[diff >> (12 + 3)] ^= BIT((diff >> 12) & 7);
++				return 1;
++			} else {
++				return -EBADMSG;
++			}
++		} else if (!(diff & (diff - 1))) {
++			/* Single bit ECC error in the ECC itself,
++			 * nothing to fix */
++			return 1;
++		} else {
++			/* Uncorrectable error */
++			return -EBADMSG;
++		}
++
++	}
++	return 0;
++}
++
++/*----------------------------------------------------------------------*/
++
++/*
++ * 4-bit hardware ECC ... context maintained over entire AEMIF
++ *
++ * This is a syndrome engine, but we avoid NAND_ECC_HW_SYNDROME
++ * since that forces use of a problematic "infix OOB" layout.
++ * Among other things, it trashes manufacturer bad block markers.
++ * Also, and specific to this hardware, it ECC-protects the "prepad"
++ * in the OOB ... while having ECC protection for parts of OOB would
++ * seem useful, the current MTD stack sometimes wants to update the
++ * OOB without recomputing ECC.
++ */
++
++static void nand_davinci_hwctl_4bit(struct mtd_info *mtd, int mode)
++{
++	struct davinci_nand_info *info = to_davinci_nand(mtd);
++	unsigned long flags;
++	u32 val;
++
++	/* Reset ECC hardware */
++	davinci_nand_readl(info, NAND_4BIT_ECC1_OFFSET);
++
++	spin_lock_irqsave(&davinci_nand_lock, flags);
++
++	/* Start 4-bit ECC calculation for read/write */
++	val = davinci_nand_readl(info, NANDFCR_OFFSET);
++	val &= ~(0x03 << 4);
++	val |= (info->core_chipsel << 4) | BIT(12);
++	davinci_nand_writel(info, NANDFCR_OFFSET, val);
++
++	info->is_readmode = (mode == NAND_ECC_READ);
++
++	spin_unlock_irqrestore(&davinci_nand_lock, flags);
++}
++
++/* Read raw ECC code after writing to NAND. */
++static void
++nand_davinci_readecc_4bit(struct davinci_nand_info *info, u32 code[4])
++{
++	const u32 mask = 0x03ff03ff;
++
++	code[0] = davinci_nand_readl(info, NAND_4BIT_ECC1_OFFSET) & mask;
++	code[1] = davinci_nand_readl(info, NAND_4BIT_ECC2_OFFSET) & mask;
++	code[2] = davinci_nand_readl(info, NAND_4BIT_ECC3_OFFSET) & mask;
++	code[3] = davinci_nand_readl(info, NAND_4BIT_ECC4_OFFSET) & mask;
++}
++
++/* Terminate read ECC; or return ECC (as bytes) of data written to NAND. */
++static int nand_davinci_calculate_4bit(struct mtd_info *mtd,
++		const u_char *dat, u_char *ecc_code)
++{
++	struct davinci_nand_info *info = to_davinci_nand(mtd);
++	u32 raw_ecc[4], *p;
++	unsigned i;
++
++	/* After a read, terminate ECC calculation by a dummy read
++	 * of some 4-bit ECC register.  ECC covers everything that
++	 * was read; correct() just uses the hardware state, so
++	 * ecc_code is not needed.
++	 */
++	if (info->is_readmode) {
++		davinci_nand_readl(info, NAND_4BIT_ECC1_OFFSET);
++		return 0;
++	}
++
++	/* Pack eight raw 10-bit ecc values into ten bytes, making
++	 * two passes which each convert four values (in upper and
++	 * lower halves of two 32-bit words) into five bytes.  The
++	 * ROM boot loader uses this same packing scheme.
++	 */
++	nand_davinci_readecc_4bit(info, raw_ecc);
++	for (i = 0, p = raw_ecc; i < 2; i++, p += 2) {
++		*ecc_code++ =   p[0]        & 0xff;
++		*ecc_code++ = ((p[0] >>  8) & 0x03) | ((p[0] >> 14) & 0xfc);
++		*ecc_code++ = ((p[0] >> 22) & 0x0f) | ((p[1] <<  4) & 0xf0);
++		*ecc_code++ = ((p[1] >>  4) & 0x3f) | ((p[1] >> 10) & 0xc0);
++		*ecc_code++ =  (p[1] >> 18) & 0xff;
++	}
++
++	return 0;
++}
++
++/* Correct up to 4 bits in data we just read, using state left in the
++ * hardware plus the ecc_code computed when it was first written.
++ */
++static int nand_davinci_correct_4bit(struct mtd_info *mtd,
++		u_char *data, u_char *ecc_code, u_char *null)
++{
++	int i;
++	struct davinci_nand_info *info = to_davinci_nand(mtd);
++	unsigned short ecc10[8];
++	unsigned short *ecc16;
++	u32 syndrome[4];
++	u32 ecc_state;
++	unsigned num_errors, corrected;
++	unsigned long timeo;
++
++	/* Unpack ten bytes into eight 10 bit values.  We know we're
++	 * little-endian, and use type punning for less shifting/masking.
++	 */
++	if (WARN_ON(0x01 & (unsigned) ecc_code))
++		return -EINVAL;
++	ecc16 = (unsigned short *)ecc_code;
++
++	ecc10[0] =  (ecc16[0] >>  0) & 0x3ff;
++	ecc10[1] = ((ecc16[0] >> 10) & 0x3f) | ((ecc16[1] << 6) & 0x3c0);
++	ecc10[2] =  (ecc16[1] >>  4) & 0x3ff;
++	ecc10[3] = ((ecc16[1] >> 14) & 0x3)  | ((ecc16[2] << 2) & 0x3fc);
++	ecc10[4] =  (ecc16[2] >>  8)         | ((ecc16[3] << 8) & 0x300);
++	ecc10[5] =  (ecc16[3] >>  2) & 0x3ff;
++	ecc10[6] = ((ecc16[3] >> 12) & 0xf)  | ((ecc16[4] << 4) & 0x3f0);
++	ecc10[7] =  (ecc16[4] >>  6) & 0x3ff;
++
++	/* Tell ECC controller about the expected ECC codes. */
++	for (i = 7; i >= 0; i--)
++		davinci_nand_writel(info, NAND_4BIT_ECC_LOAD_OFFSET, ecc10[i]);
++
++	/* Allow time for syndrome calculation ... then read it.
++	 * A syndrome of all zeroes 0 means no detected errors.
++	 */
++	davinci_nand_readl(info, NANDFSR_OFFSET);
++	nand_davinci_readecc_4bit(info, syndrome);
++	if (!(syndrome[0] | syndrome[1] | syndrome[2] | syndrome[3]))
++		return 0;
++
++	/*
++	 * Clear any previous address calculation by doing a dummy read of an
++	 * error address register.
++	 */
++	davinci_nand_readl(info, NAND_ERR_ADD1_OFFSET);
++
++	/* Start address calculation, and wait for it to complete.
++	 * We _could_ start reading more data while this is working,
++	 * to speed up the overall page read.
++	 */
++	davinci_nand_writel(info, NANDFCR_OFFSET,
++			davinci_nand_readl(info, NANDFCR_OFFSET) | BIT(13));
++
++	/*
++	 * ECC_STATE field reads 0x3 (Error correction complete) immediately
++	 * after setting the 4BITECC_ADD_CALC_START bit. So if you immediately
++	 * begin trying to poll for the state, you may fall right out of your
++	 * loop without any of the correction calculations having taken place.
++	 * The recommendation from the hardware team is to initially delay as
++	 * long as ECC_STATE reads less than 4. After that, ECC HW has entered
++	 * correction state.
++	 */
++	timeo = jiffies + usecs_to_jiffies(100);
++	do {
++		ecc_state = (davinci_nand_readl(info,
++				NANDFSR_OFFSET) >> 8) & 0x0f;
++		cpu_relax();
++	} while ((ecc_state < 4) && time_before(jiffies, timeo));
++
++	for (;;) {
++		u32	fsr = davinci_nand_readl(info, NANDFSR_OFFSET);
++
++		switch ((fsr >> 8) & 0x0f) {
++		case 0:		/* no error, should not happen */
++			davinci_nand_readl(info, NAND_ERR_ERRVAL1_OFFSET);
++			return 0;
++		case 1:		/* five or more errors detected */
++			davinci_nand_readl(info, NAND_ERR_ERRVAL1_OFFSET);
++			return -EBADMSG;
++		case 2:		/* error addresses computed */
++		case 3:
++			num_errors = 1 + ((fsr >> 16) & 0x03);
++			goto correct;
++		default:	/* still working on it */
++			cpu_relax();
++			continue;
++		}
++	}
++
++correct:
++	/* correct each error */
++	for (i = 0, corrected = 0; i < num_errors; i++) {
++		int error_address, error_value;
++
++		if (i > 1) {
++			error_address = davinci_nand_readl(info,
++						NAND_ERR_ADD2_OFFSET);
++			error_value = davinci_nand_readl(info,
++						NAND_ERR_ERRVAL2_OFFSET);
++		} else {
++			error_address = davinci_nand_readl(info,
++						NAND_ERR_ADD1_OFFSET);
++			error_value = davinci_nand_readl(info,
++						NAND_ERR_ERRVAL1_OFFSET);
++		}
++
++		if (i & 1) {
++			error_address >>= 16;
++			error_value >>= 16;
++		}
++		error_address &= 0x3ff;
++		error_address = (512 + 7) - error_address;
++
++		if (error_address < 512) {
++			data[error_address] ^= error_value;
++			corrected++;
++		}
++	}
++
++	return corrected;
++}
++
++/*----------------------------------------------------------------------*/
++
++/*
++ * NOTE:  NAND boot requires ALE == EM_A[1], CLE == EM_A[2], so that's
++ * how these chips are normally wired.  This translates to both 8 and 16
++ * bit busses using ALE == BIT(3) in byte addresses, and CLE == BIT(4).
++ *
++ * For now we assume that configuration, or any other one which ignores
++ * the two LSBs for NAND access ... so we can issue 32-bit reads/writes
++ * and have that transparently morphed into multiple NAND operations.
++ */
++static void nand_davinci_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++
++	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
++		ioread8_rep(chip->IO_ADDR_R, buf, 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);
++
++	if ((0x03 & ((unsigned)buf)) == 0 && (0x03 & len) == 0)
++		iowrite32_rep(chip->IO_ADDR_R, buf, len >> 2);
++	else if ((0x01 & ((unsigned)buf)) == 0 && (0x01 & len) == 0)
++		iowrite16_rep(chip->IO_ADDR_R, buf, len >> 1);
++	else
++		iowrite8_rep(chip->IO_ADDR_R, buf, len);
++}
++
++/*
++ * Check hardware register for wait status. Returns 1 if device is ready,
++ * 0 if it is still busy.
++ */
++static int nand_davinci_dev_ready(struct mtd_info *mtd)
++{
++	struct davinci_nand_info *info = to_davinci_nand(mtd);
++
++	return davinci_nand_readl(info, NANDFSR_OFFSET) & BIT(0);
++}
++
++/*----------------------------------------------------------------------*/
++
++/* An ECC layout for using 4-bit ECC with small-page flash, storing
++ * ten ECC bytes plus the manufacturer's bad block marker byte, and
++ * and not overlapping the default BBT markers.
++ */
++static int hwecc4_ooblayout_small_ecc(struct mtd_info *mtd, int section,
++				      struct mtd_oob_region *oobregion)
++{
++	if (section > 2)
++		return -ERANGE;
++
++	if (!section) {
++		oobregion->offset = 0;
++		oobregion->length = 5;
++	} else if (section == 1) {
++		oobregion->offset = 6;
++		oobregion->length = 2;
++	} else {
++		oobregion->offset = 13;
++		oobregion->length = 3;
++	}
++
++	return 0;
++}
++
++static int hwecc4_ooblayout_small_free(struct mtd_info *mtd, int section,
++				       struct mtd_oob_region *oobregion)
++{
++	if (section > 1)
++		return -ERANGE;
++
++	if (!section) {
++		oobregion->offset = 8;
++		oobregion->length = 5;
++	} else {
++		oobregion->offset = 16;
++		oobregion->length = mtd->oobsize - 16;
++	}
++
++	return 0;
++}
++
++static const struct mtd_ooblayout_ops hwecc4_small_ooblayout_ops = {
++	.ecc = hwecc4_ooblayout_small_ecc,
++	.free = hwecc4_ooblayout_small_free,
++};
++
++#if defined(CONFIG_OF)
++static const struct of_device_id davinci_nand_of_match[] = {
++	{.compatible = "ti,davinci-nand", },
++	{.compatible = "ti,keystone-nand", },
++	{},
++};
++MODULE_DEVICE_TABLE(of, davinci_nand_of_match);
++
++static struct davinci_nand_pdata
++	*nand_davinci_get_pdata(struct platform_device *pdev)
++{
++	if (!dev_get_platdata(&pdev->dev) && pdev->dev.of_node) {
++		struct davinci_nand_pdata *pdata;
++		const char *mode;
++		u32 prop;
++
++		pdata =  devm_kzalloc(&pdev->dev,
++				sizeof(struct davinci_nand_pdata),
++				GFP_KERNEL);
++		pdev->dev.platform_data = pdata;
++		if (!pdata)
++			return ERR_PTR(-ENOMEM);
++		if (!of_property_read_u32(pdev->dev.of_node,
++			"ti,davinci-chipselect", &prop))
++			pdev->id = prop;
++		else
++			return ERR_PTR(-EINVAL);
++
++		if (!of_property_read_u32(pdev->dev.of_node,
++			"ti,davinci-mask-ale", &prop))
++			pdata->mask_ale = prop;
++		if (!of_property_read_u32(pdev->dev.of_node,
++			"ti,davinci-mask-cle", &prop))
++			pdata->mask_cle = prop;
++		if (!of_property_read_u32(pdev->dev.of_node,
++			"ti,davinci-mask-chipsel", &prop))
++			pdata->mask_chipsel = prop;
++		if (!of_property_read_string(pdev->dev.of_node,
++			"ti,davinci-ecc-mode", &mode)) {
++			if (!strncmp("none", mode, 4))
++				pdata->ecc_mode = NAND_ECC_NONE;
++			if (!strncmp("soft", mode, 4))
++				pdata->ecc_mode = NAND_ECC_SOFT;
++			if (!strncmp("hw", mode, 2))
++				pdata->ecc_mode = NAND_ECC_HW;
++		}
++		if (!of_property_read_u32(pdev->dev.of_node,
++			"ti,davinci-ecc-bits", &prop))
++			pdata->ecc_bits = prop;
++
++		if (!of_property_read_u32(pdev->dev.of_node,
++			"ti,davinci-nand-buswidth", &prop) && prop == 16)
++			pdata->options |= NAND_BUSWIDTH_16;
++
++		if (of_property_read_bool(pdev->dev.of_node,
++			"ti,davinci-nand-use-bbt"))
++			pdata->bbt_options = NAND_BBT_USE_FLASH;
++
++		/*
++		 * Since kernel v4.8, this driver has been fixed to enable
++		 * use of 4-bit hardware ECC with subpages and verified on
++		 * TI's keystone EVMs (K2L, K2HK and K2E).
++		 * However, in the interest of not breaking systems using
++		 * existing UBI partitions, sub-page writes are not being
++		 * (re)enabled. If you want to use subpage writes on Keystone
++		 * platforms (i.e. do not have any existing UBI partitions),
++		 * then use "ti,davinci-nand" as the compatible in your
++		 * device-tree file.
++		 */
++		if (of_device_is_compatible(pdev->dev.of_node,
++					    "ti,keystone-nand")) {
++			pdata->options |= NAND_NO_SUBPAGE_WRITE;
++		}
++	}
++
++	return dev_get_platdata(&pdev->dev);
++}
++#else
++static struct davinci_nand_pdata
++	*nand_davinci_get_pdata(struct platform_device *pdev)
++{
++	return dev_get_platdata(&pdev->dev);
++}
++#endif
++
++static int nand_davinci_probe(struct platform_device *pdev)
++{
++	struct davinci_nand_pdata	*pdata;
++	struct davinci_nand_info	*info;
++	struct resource			*res1;
++	struct resource			*res2;
++	void __iomem			*vaddr;
++	void __iomem			*base;
++	int				ret;
++	uint32_t			val;
++	struct mtd_info			*mtd;
++
++	pdata = nand_davinci_get_pdata(pdev);
++	if (IS_ERR(pdata))
++		return PTR_ERR(pdata);
++
++	/* insist on board-specific configuration */
++	if (!pdata)
++		return -ENODEV;
++
++	/* which external chipselect will we be managing? */
++	if (pdev->id < 0 || pdev->id > 3)
++		return -ENODEV;
++
++	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
++	if (!info)
++		return -ENOMEM;
++
++	platform_set_drvdata(pdev, info);
++
++	res1 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	res2 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
++	if (!res1 || !res2) {
++		dev_err(&pdev->dev, "resource missing\n");
++		return -EINVAL;
++	}
++
++	vaddr = devm_ioremap_resource(&pdev->dev, res1);
++	if (IS_ERR(vaddr))
++		return PTR_ERR(vaddr);
++
++	/*
++	 * This registers range is used to setup NAND settings. In case with
++	 * TI AEMIF driver, the same memory address range is requested already
++	 * by AEMIF, so we cannot request it twice, just ioremap.
++	 * The AEMIF and NAND drivers not use the same registers in this range.
++	 */
++	base = devm_ioremap(&pdev->dev, res2->start, resource_size(res2));
++	if (!base) {
++		dev_err(&pdev->dev, "ioremap failed for resource %pR\n", res2);
++		return -EADDRNOTAVAIL;
++	}
++
++	info->dev		= &pdev->dev;
++	info->base		= base;
++	info->vaddr		= vaddr;
++
++	mtd			= nand_to_mtd(&info->chip);
++	mtd->dev.parent		= &pdev->dev;
++	nand_set_flash_node(&info->chip, pdev->dev.of_node);
++
++	info->chip.IO_ADDR_R	= vaddr;
++	info->chip.IO_ADDR_W	= vaddr;
++	info->chip.chip_delay	= 0;
++	info->chip.select_chip	= nand_davinci_select_chip;
++
++	/* options such as NAND_BBT_USE_FLASH */
++	info->chip.bbt_options	= pdata->bbt_options;
++	/* options such as 16-bit widths */
++	info->chip.options	= pdata->options;
++	info->chip.bbt_td	= pdata->bbt_td;
++	info->chip.bbt_md	= pdata->bbt_md;
++	info->timing		= pdata->timing;
++
++	info->ioaddr		= (uint32_t __force) vaddr;
++
++	info->current_cs	= info->ioaddr;
++	info->core_chipsel	= pdev->id;
++	info->mask_chipsel	= pdata->mask_chipsel;
++
++	/* use nandboot-capable ALE/CLE masks by default */
++	info->mask_ale		= pdata->mask_ale ? : MASK_ALE;
++	info->mask_cle		= pdata->mask_cle ? : MASK_CLE;
++
++	/* Set address of hardware control function */
++	info->chip.cmd_ctrl	= nand_davinci_hwcontrol;
++	info->chip.dev_ready	= nand_davinci_dev_ready;
++
++	/* Speed up buffer I/O */
++	info->chip.read_buf     = nand_davinci_read_buf;
++	info->chip.write_buf    = nand_davinci_write_buf;
++
++	/* Use board-specific ECC config */
++	info->chip.ecc.mode	= pdata->ecc_mode;
++
++	ret = -EINVAL;
++
++	info->clk = devm_clk_get(&pdev->dev, "aemif");
++	if (IS_ERR(info->clk)) {
++		ret = PTR_ERR(info->clk);
++		dev_dbg(&pdev->dev, "unable to get AEMIF clock, err %d\n", ret);
++		return ret;
++	}
++
++	ret = clk_prepare_enable(info->clk);
++	if (ret < 0) {
++		dev_dbg(&pdev->dev, "unable to enable AEMIF clock, err %d\n",
++			ret);
++		goto err_clk_enable;
++	}
++
++	spin_lock_irq(&davinci_nand_lock);
++
++	/* put CSxNAND into NAND mode */
++	val = davinci_nand_readl(info, NANDFCR_OFFSET);
++	val |= BIT(info->core_chipsel);
++	davinci_nand_writel(info, NANDFCR_OFFSET, val);
++
++	spin_unlock_irq(&davinci_nand_lock);
++
++	/* Scan to find existence of the device(s) */
++	ret = nand_scan_ident(mtd, pdata->mask_chipsel ? 2 : 1, NULL);
++	if (ret < 0) {
++		dev_dbg(&pdev->dev, "no NAND chip(s) found\n");
++		goto err;
++	}
++
++	switch (info->chip.ecc.mode) {
++	case NAND_ECC_NONE:
++		pdata->ecc_bits = 0;
++		break;
++	case NAND_ECC_SOFT:
++		pdata->ecc_bits = 0;
++		/*
++		 * 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
++		 * davinci_nand_pdata.
++		 */
++		info->chip.ecc.algo = NAND_ECC_HAMMING;
++		break;
++	case NAND_ECC_HW:
++		if (pdata->ecc_bits == 4) {
++			/* No sanity checks:  CPUs must support this,
++			 * and the chips may not use NAND_BUSWIDTH_16.
++			 */
++
++			/* No sharing 4-bit hardware between chipselects yet */
++			spin_lock_irq(&davinci_nand_lock);
++			if (ecc4_busy)
++				ret = -EBUSY;
++			else
++				ecc4_busy = true;
++			spin_unlock_irq(&davinci_nand_lock);
++
++			if (ret == -EBUSY)
++				return ret;
++
++			info->chip.ecc.calculate = nand_davinci_calculate_4bit;
++			info->chip.ecc.correct = nand_davinci_correct_4bit;
++			info->chip.ecc.hwctl = nand_davinci_hwctl_4bit;
++			info->chip.ecc.bytes = 10;
++			info->chip.ecc.options = NAND_ECC_GENERIC_ERASED_CHECK;
++			info->chip.ecc.algo = NAND_ECC_BCH;
++		} else {
++			/* 1bit ecc hamming */
++			info->chip.ecc.calculate = nand_davinci_calculate_1bit;
++			info->chip.ecc.correct = nand_davinci_correct_1bit;
++			info->chip.ecc.hwctl = nand_davinci_hwctl_1bit;
++			info->chip.ecc.bytes = 3;
++			info->chip.ecc.algo = NAND_ECC_HAMMING;
++		}
++		info->chip.ecc.size = 512;
++		info->chip.ecc.strength = pdata->ecc_bits;
++		break;
++	default:
++		return -EINVAL;
++	}
++
++	/* Update ECC layout if needed ... for 1-bit HW ECC, the default
++	 * is OK, but it allocates 6 bytes when only 3 are needed (for
++	 * each 512 bytes).  For the 4-bit HW ECC, that default is not
++	 * usable:  10 bytes are needed, not 6.
++	 */
++	if (pdata->ecc_bits == 4) {
++		int	chunks = mtd->writesize / 512;
++
++		if (!chunks || mtd->oobsize < 16) {
++			dev_dbg(&pdev->dev, "too small\n");
++			ret = -EINVAL;
++			goto err;
++		}
++
++		/* For small page chips, preserve the manufacturer's
++		 * badblock marking data ... and make sure a flash BBT
++		 * table marker fits in the free bytes.
++		 */
++		if (chunks == 1) {
++			mtd_set_ooblayout(mtd, &hwecc4_small_ooblayout_ops);
++		} else if (chunks == 4 || chunks == 8) {
++			mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
++			info->chip.ecc.mode = NAND_ECC_HW_OOB_FIRST;
++		} else {
++			ret = -EIO;
++			goto err;
++		}
++	}
++
++	ret = nand_scan_tail(mtd);
++	if (ret < 0)
++		goto err;
++
++	if (pdata->parts)
++		ret = mtd_device_parse_register(mtd, NULL, NULL,
++					pdata->parts, pdata->nr_parts);
++	else
++		ret = mtd_device_register(mtd, NULL, 0);
++	if (ret < 0)
++		goto err;
++
++	val = davinci_nand_readl(info, NRCSR_OFFSET);
++	dev_info(&pdev->dev, "controller rev. %d.%d\n",
++	       (val >> 8) & 0xff, val & 0xff);
++
++	return 0;
++
++err:
++	clk_disable_unprepare(info->clk);
++
++err_clk_enable:
++	spin_lock_irq(&davinci_nand_lock);
++	if (info->chip.ecc.mode == NAND_ECC_HW_SYNDROME)
++		ecc4_busy = false;
++	spin_unlock_irq(&davinci_nand_lock);
++	return ret;
++}
++
++static int nand_davinci_remove(struct platform_device *pdev)
++{
++	struct davinci_nand_info *info = platform_get_drvdata(pdev);
++
++	spin_lock_irq(&davinci_nand_lock);
++	if (info->chip.ecc.mode == NAND_ECC_HW_SYNDROME)
++		ecc4_busy = false;
++	spin_unlock_irq(&davinci_nand_lock);
++
++	nand_release(nand_to_mtd(&info->chip));
++
++	clk_disable_unprepare(info->clk);
++
++	return 0;
++}
++
++static struct platform_driver nand_davinci_driver = {
++	.probe		= nand_davinci_probe,
++	.remove		= nand_davinci_remove,
++	.driver		= {
++		.name	= "davinci_nand",
++		.of_match_table = of_match_ptr(davinci_nand_of_match),
++	},
++};
++MODULE_ALIAS("platform:davinci_nand");
++
++module_platform_driver(nand_davinci_driver);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Texas Instruments");
++MODULE_DESCRIPTION("Davinci NAND flash driver");
++
+diff --git a/drivers/mtd/nand/raw/denali.c b/drivers/mtd/nand/raw/denali.c
+new file mode 100644
+index 0000000..3087b0b
+--- /dev/null
++++ b/drivers/mtd/nand/raw/denali.c
+@@ -0,0 +1,1453 @@
++/*
++ * NAND Flash Controller Device Driver
++ * Copyright © 2009-2010, Intel Corporation and its suppliers.
++ *
++ * 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, write to the Free Software Foundation, Inc.,
++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ */
++#include <linux/interrupt.h>
++#include <linux/delay.h>
++#include <linux/dma-mapping.h>
++#include <linux/wait.h>
++#include <linux/mutex.h>
++#include <linux/mtd/mtd.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++
++#include "denali.h"
++
++MODULE_LICENSE("GPL");
++
++#define DENALI_NAND_NAME    "denali-nand"
++
++/* Host Data/Command Interface */
++#define DENALI_HOST_ADDR	0x00
++#define DENALI_HOST_DATA	0x10
++
++#define DENALI_MAP00		(0 << 26)	/* direct access to buffer */
++#define DENALI_MAP01		(1 << 26)	/* read/write pages in PIO */
++#define DENALI_MAP10		(2 << 26)	/* high-level control plane */
++#define DENALI_MAP11		(3 << 26)	/* direct controller access */
++
++/* MAP11 access cycle type */
++#define DENALI_MAP11_CMD	((DENALI_MAP11) | 0)	/* command cycle */
++#define DENALI_MAP11_ADDR	((DENALI_MAP11) | 1)	/* address cycle */
++#define DENALI_MAP11_DATA	((DENALI_MAP11) | 2)	/* data cycle */
++
++/* MAP10 commands */
++#define DENALI_ERASE		0x01
++
++#define DENALI_BANK(denali)	((denali)->active_bank << 24)
++
++#define DENALI_INVALID_BANK	-1
++#define DENALI_NR_BANKS		4
++
++/*
++ * The bus interface clock, clk_x, is phase aligned with the core clock.  The
++ * clk_x is an integral multiple N of the core clk.  The value N is configured
++ * at IP delivery time, and its available value is 4, 5, or 6.  We need to align
++ * to the largest value to make it work with any possible configuration.
++ */
++#define DENALI_CLK_X_MULT	6
++
++/*
++ * this macro allows us to convert from an MTD structure to our own
++ * device context (denali) structure.
++ */
++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);
++}
++
++static void denali_host_write(struct denali_nand_info *denali,
++			      uint32_t addr, uint32_t data)
++{
++	iowrite32(addr, denali->host + DENALI_HOST_ADDR);
++	iowrite32(data, denali->host + DENALI_HOST_DATA);
++}
++
++/*
++ * Use the configuration feature register to determine the maximum number of
++ * banks that the hardware supports.
++ */
++static void detect_max_banks(struct denali_nand_info *denali)
++{
++	uint32_t features = ioread32(denali->reg + FEATURES);
++
++	denali->max_banks = 1 << (features & FEATURES__N_BANKS);
++
++	/* the encoding changed from rev 5.0 to 5.1 */
++	if (denali->revision < 0x0501)
++		denali->max_banks <<= 1;
++}
++
++static void denali_enable_irq(struct denali_nand_info *denali)
++{
++	int i;
++
++	for (i = 0; i < DENALI_NR_BANKS; i++)
++		iowrite32(U32_MAX, denali->reg + INTR_EN(i));
++	iowrite32(GLOBAL_INT_EN_FLAG, denali->reg + GLOBAL_INT_ENABLE);
++}
++
++static void denali_disable_irq(struct denali_nand_info *denali)
++{
++	int i;
++
++	for (i = 0; i < DENALI_NR_BANKS; i++)
++		iowrite32(0, denali->reg + INTR_EN(i));
++	iowrite32(0, denali->reg + GLOBAL_INT_ENABLE);
++}
++
++static void denali_clear_irq(struct denali_nand_info *denali,
++			     int bank, uint32_t irq_status)
++{
++	/* write one to clear bits */
++	iowrite32(irq_status, denali->reg + INTR_STATUS(bank));
++}
++
++static void denali_clear_irq_all(struct denali_nand_info *denali)
++{
++	int i;
++
++	for (i = 0; i < DENALI_NR_BANKS; i++)
++		denali_clear_irq(denali, i, U32_MAX);
++}
++
++static irqreturn_t denali_isr(int irq, void *dev_id)
++{
++	struct denali_nand_info *denali = dev_id;
++	irqreturn_t ret = IRQ_NONE;
++	uint32_t irq_status;
++	int i;
++
++	spin_lock(&denali->irq_lock);
++
++	for (i = 0; i < DENALI_NR_BANKS; i++) {
++		irq_status = ioread32(denali->reg + INTR_STATUS(i));
++		if (irq_status)
++			ret = IRQ_HANDLED;
++
++		denali_clear_irq(denali, i, irq_status);
++
++		if (i != denali->active_bank)
++			continue;
++
++		denali->irq_status |= irq_status;
++
++		if (denali->irq_status & denali->irq_mask)
++			complete(&denali->complete);
++	}
++
++	spin_unlock(&denali->irq_lock);
++
++	return ret;
++}
++
++static void denali_reset_irq(struct denali_nand_info *denali)
++{
++	unsigned long flags;
++
++	spin_lock_irqsave(&denali->irq_lock, flags);
++	denali->irq_status = 0;
++	denali->irq_mask = 0;
++	spin_unlock_irqrestore(&denali->irq_lock, flags);
++}
++
++static uint32_t denali_wait_for_irq(struct denali_nand_info *denali,
++				    uint32_t irq_mask)
++{
++	unsigned long time_left, flags;
++	uint32_t irq_status;
++
++	spin_lock_irqsave(&denali->irq_lock, flags);
++
++	irq_status = denali->irq_status;
++
++	if (irq_mask & irq_status) {
++		/* return immediately if the IRQ has already happened. */
++		spin_unlock_irqrestore(&denali->irq_lock, flags);
++		return irq_status;
++	}
++
++	denali->irq_mask = irq_mask;
++	reinit_completion(&denali->complete);
++	spin_unlock_irqrestore(&denali->irq_lock, flags);
++
++	time_left = wait_for_completion_timeout(&denali->complete,
++						msecs_to_jiffies(1000));
++	if (!time_left) {
++		dev_err(denali->dev, "timeout while waiting for irq 0x%x\n",
++			denali->irq_mask);
++		return 0;
++	}
++
++	return denali->irq_status;
++}
++
++static uint32_t denali_check_irq(struct denali_nand_info *denali)
++{
++	unsigned long flags;
++	uint32_t irq_status;
++
++	spin_lock_irqsave(&denali->irq_lock, flags);
++	irq_status = denali->irq_status;
++	spin_unlock_irqrestore(&denali->irq_lock, flags);
++
++	return irq_status;
++}
++
++/*
++ * This helper function setups the registers for ECC and whether or not
++ * the spare area will be transferred.
++ */
++static void setup_ecc_for_xfer(struct denali_nand_info *denali, bool ecc_en,
++				bool transfer_spare)
++{
++	int ecc_en_flag, transfer_spare_flag;
++
++	/* set ECC, transfer spare bits if needed */
++	ecc_en_flag = ecc_en ? ECC_ENABLE__FLAG : 0;
++	transfer_spare_flag = transfer_spare ? TRANSFER_SPARE_REG__FLAG : 0;
++
++	/* Enable spare area/ECC per user's request. */
++	iowrite32(ecc_en_flag, denali->reg + ECC_ENABLE);
++	iowrite32(transfer_spare_flag, denali->reg + TRANSFER_SPARE_REG);
++}
++
++static void denali_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
++{
++	struct denali_nand_info *denali = mtd_to_denali(mtd);
++	int i;
++
++	iowrite32(DENALI_MAP11_DATA | DENALI_BANK(denali),
++		  denali->host + DENALI_HOST_ADDR);
++
++	for (i = 0; i < len; i++)
++		buf[i] = ioread32(denali->host + DENALI_HOST_DATA);
++}
++
++static void denali_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
++{
++	struct denali_nand_info *denali = mtd_to_denali(mtd);
++	int i;
++
++	iowrite32(DENALI_MAP11_DATA | DENALI_BANK(denali),
++		  denali->host + DENALI_HOST_ADDR);
++
++	for (i = 0; i < len; i++)
++		iowrite32(buf[i], denali->host + DENALI_HOST_DATA);
++}
++
++static void denali_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
++{
++	struct denali_nand_info *denali = mtd_to_denali(mtd);
++	uint16_t *buf16 = (uint16_t *)buf;
++	int i;
++
++	iowrite32(DENALI_MAP11_DATA | DENALI_BANK(denali),
++		  denali->host + DENALI_HOST_ADDR);
++
++	for (i = 0; i < len / 2; i++)
++		buf16[i] = ioread32(denali->host + DENALI_HOST_DATA);
++}
++
++static void denali_write_buf16(struct mtd_info *mtd, const uint8_t *buf,
++			       int len)
++{
++	struct denali_nand_info *denali = mtd_to_denali(mtd);
++	const uint16_t *buf16 = (const uint16_t *)buf;
++	int i;
++
++	iowrite32(DENALI_MAP11_DATA | DENALI_BANK(denali),
++		  denali->host + DENALI_HOST_ADDR);
++
++	for (i = 0; i < len / 2; i++)
++		iowrite32(buf16[i], denali->host + DENALI_HOST_DATA);
++}
++
++static uint8_t denali_read_byte(struct mtd_info *mtd)
++{
++	uint8_t byte;
++
++	denali_read_buf(mtd, &byte, 1);
++
++	return byte;
++}
++
++static void denali_write_byte(struct mtd_info *mtd, uint8_t byte)
++{
++	denali_write_buf(mtd, &byte, 1);
++}
++
++static uint16_t denali_read_word(struct mtd_info *mtd)
++{
++	uint16_t word;
++
++	denali_read_buf16(mtd, (uint8_t *)&word, 2);
++
++	return word;
++}
++
++static void denali_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
++{
++	struct denali_nand_info *denali = mtd_to_denali(mtd);
++	uint32_t type;
++
++	if (ctrl & NAND_CLE)
++		type = DENALI_MAP11_CMD;
++	else if (ctrl & NAND_ALE)
++		type = DENALI_MAP11_ADDR;
++	else
++		return;
++
++	/*
++	 * Some commands are followed by chip->dev_ready or chip->waitfunc.
++	 * irq_status must be cleared here to catch the R/B# interrupt later.
++	 */
++	if (ctrl & NAND_CTRL_CHANGE)
++		denali_reset_irq(denali);
++
++	denali_host_write(denali, DENALI_BANK(denali) | type, dat);
++}
++
++static int denali_dev_ready(struct mtd_info *mtd)
++{
++	struct denali_nand_info *denali = mtd_to_denali(mtd);
++
++	return !!(denali_check_irq(denali) & INTR__INT_ACT);
++}
++
++static int denali_check_erased_page(struct mtd_info *mtd,
++				    struct nand_chip *chip, uint8_t *buf,
++				    unsigned long uncor_ecc_flags,
++				    unsigned int max_bitflips)
++{
++	uint8_t *ecc_code = chip->buffers->ecccode;
++	int ecc_steps = chip->ecc.steps;
++	int ecc_size = chip->ecc.size;
++	int ecc_bytes = chip->ecc.bytes;
++	int i, ret, stat;
++
++	ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, chip->oob_poi, 0,
++					 chip->ecc.total);
++	if (ret)
++		return ret;
++
++	for (i = 0; i < ecc_steps; i++) {
++		if (!(uncor_ecc_flags & BIT(i)))
++			continue;
++
++		stat = nand_check_erased_ecc_chunk(buf, ecc_size,
++						  ecc_code, ecc_bytes,
++						  NULL, 0,
++						  chip->ecc.strength);
++		if (stat < 0) {
++			mtd->ecc_stats.failed++;
++		} else {
++			mtd->ecc_stats.corrected += stat;
++			max_bitflips = max_t(unsigned int, max_bitflips, stat);
++		}
++
++		buf += ecc_size;
++		ecc_code += ecc_bytes;
++	}
++
++	return max_bitflips;
++}
++
++static int denali_hw_ecc_fixup(struct mtd_info *mtd,
++			       struct denali_nand_info *denali,
++			       unsigned long *uncor_ecc_flags)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	int bank = denali->active_bank;
++	uint32_t ecc_cor;
++	unsigned int max_bitflips;
++
++	ecc_cor = ioread32(denali->reg + ECC_COR_INFO(bank));
++	ecc_cor >>= ECC_COR_INFO__SHIFT(bank);
++
++	if (ecc_cor & ECC_COR_INFO__UNCOR_ERR) {
++		/*
++		 * This flag is set when uncorrectable error occurs at least in
++		 * one ECC sector.  We can not know "how many sectors", or
++		 * "which sector(s)".  We need erase-page check for all sectors.
++		 */
++		*uncor_ecc_flags = GENMASK(chip->ecc.steps - 1, 0);
++		return 0;
++	}
++
++	max_bitflips = ecc_cor & ECC_COR_INFO__MAX_ERRORS;
++
++	/*
++	 * The register holds the maximum of per-sector corrected bitflips.
++	 * This is suitable for the return value of the ->read_page() callback.
++	 * Unfortunately, we can not know the total number of corrected bits in
++	 * the page.  Increase the stats by max_bitflips. (compromised solution)
++	 */
++	mtd->ecc_stats.corrected += max_bitflips;
++
++	return max_bitflips;
++}
++
++#define ECC_SECTOR(x)	(((x) & ECC_ERROR_ADDRESS__SECTOR_NR) >> 12)
++#define ECC_BYTE(x)	(((x) & ECC_ERROR_ADDRESS__OFFSET))
++#define ECC_CORRECTION_VALUE(x) ((x) & ERR_CORRECTION_INFO__BYTEMASK)
++#define ECC_ERROR_UNCORRECTABLE(x) ((x) & ERR_CORRECTION_INFO__ERROR_TYPE)
++#define ECC_ERR_DEVICE(x)	(((x) & ERR_CORRECTION_INFO__DEVICE_NR) >> 8)
++#define ECC_LAST_ERR(x)		((x) & ERR_CORRECTION_INFO__LAST_ERR_INFO)
++
++static int denali_sw_ecc_fixup(struct mtd_info *mtd,
++			       struct denali_nand_info *denali,
++			       unsigned long *uncor_ecc_flags, uint8_t *buf)
++{
++	unsigned int ecc_size = denali->nand.ecc.size;
++	unsigned int bitflips = 0;
++	unsigned int max_bitflips = 0;
++	uint32_t err_addr, err_cor_info;
++	unsigned int err_byte, err_sector, err_device;
++	uint8_t err_cor_value;
++	unsigned int prev_sector = 0;
++	uint32_t irq_status;
++
++	denali_reset_irq(denali);
++
++	do {
++		err_addr = ioread32(denali->reg + ECC_ERROR_ADDRESS);
++		err_sector = ECC_SECTOR(err_addr);
++		err_byte = ECC_BYTE(err_addr);
++
++		err_cor_info = ioread32(denali->reg + ERR_CORRECTION_INFO);
++		err_cor_value = ECC_CORRECTION_VALUE(err_cor_info);
++		err_device = ECC_ERR_DEVICE(err_cor_info);
++
++		/* reset the bitflip counter when crossing ECC sector */
++		if (err_sector != prev_sector)
++			bitflips = 0;
++
++		if (ECC_ERROR_UNCORRECTABLE(err_cor_info)) {
++			/*
++			 * Check later if this is a real ECC error, or
++			 * an erased sector.
++			 */
++			*uncor_ecc_flags |= BIT(err_sector);
++		} else if (err_byte < ecc_size) {
++			/*
++			 * If err_byte is larger than ecc_size, means error
++			 * happened in OOB, so we ignore it. It's no need for
++			 * us to correct it err_device is represented the NAND
++			 * error bits are happened in if there are more than
++			 * one NAND connected.
++			 */
++			int offset;
++			unsigned int flips_in_byte;
++
++			offset = (err_sector * ecc_size + err_byte) *
++					denali->devs_per_cs + err_device;
++
++			/* correct the ECC error */
++			flips_in_byte = hweight8(buf[offset] ^ err_cor_value);
++			buf[offset] ^= err_cor_value;
++			mtd->ecc_stats.corrected += flips_in_byte;
++			bitflips += flips_in_byte;
++
++			max_bitflips = max(max_bitflips, bitflips);
++		}
++
++		prev_sector = err_sector;
++	} while (!ECC_LAST_ERR(err_cor_info));
++
++	/*
++	 * Once handle all ecc errors, controller will trigger a
++	 * ECC_TRANSACTION_DONE interrupt, so here just wait for
++	 * a while for this interrupt
++	 */
++	irq_status = denali_wait_for_irq(denali, INTR__ECC_TRANSACTION_DONE);
++	if (!(irq_status & INTR__ECC_TRANSACTION_DONE))
++		return -EIO;
++
++	return max_bitflips;
++}
++
++/* programs the controller to either enable/disable DMA transfers */
++static void denali_enable_dma(struct denali_nand_info *denali, bool en)
++{
++	iowrite32(en ? DMA_ENABLE__FLAG : 0, denali->reg + DMA_ENABLE);
++	ioread32(denali->reg + DMA_ENABLE);
++}
++
++static void denali_setup_dma64(struct denali_nand_info *denali,
++			       dma_addr_t dma_addr, int page, int write)
++{
++	uint32_t mode;
++	const int page_count = 1;
++
++	mode = DENALI_MAP10 | DENALI_BANK(denali) | page;
++
++	/* DMA is a three step process */
++
++	/*
++	 * 1. setup transfer type, interrupt when complete,
++	 *    burst len = 64 bytes, the number of pages
++	 */
++	denali_host_write(denali, mode,
++			  0x01002000 | (64 << 16) | (write << 8) | page_count);
++
++	/* 2. set memory low address */
++	denali_host_write(denali, mode, dma_addr);
++
++	/* 3. set memory high address */
++	denali_host_write(denali, mode, (uint64_t)dma_addr >> 32);
++}
++
++static void denali_setup_dma32(struct denali_nand_info *denali,
++			       dma_addr_t dma_addr, int page, int write)
++{
++	uint32_t mode;
++	const int page_count = 1;
++
++	mode = DENALI_MAP10 | DENALI_BANK(denali);
++
++	/* DMA is a four step process */
++
++	/* 1. setup transfer type and # of pages */
++	denali_host_write(denali, mode | page,
++			  0x2000 | (write << 8) | page_count);
++
++	/* 2. set memory high address bits 23:8 */
++	denali_host_write(denali, mode | ((dma_addr >> 16) << 8), 0x2200);
++
++	/* 3. set memory low address bits 23:8 */
++	denali_host_write(denali, mode | ((dma_addr & 0xffff) << 8), 0x2300);
++
++	/* 4. interrupt when complete, burst len = 64 bytes */
++	denali_host_write(denali, mode | 0x14000, 0x2400);
++}
++
++static void denali_setup_dma(struct denali_nand_info *denali,
++			     dma_addr_t dma_addr, int page, int write)
++{
++	if (denali->caps & DENALI_CAP_DMA_64BIT)
++		denali_setup_dma64(denali, dma_addr, page, write);
++	else
++		denali_setup_dma32(denali, dma_addr, page, write);
++}
++
++static int denali_pio_read(struct denali_nand_info *denali, void *buf,
++			   size_t size, int page, int raw)
++{
++	uint32_t addr = DENALI_BANK(denali) | page;
++	uint32_t *buf32 = (uint32_t *)buf;
++	uint32_t irq_status, ecc_err_mask;
++	int i;
++
++	if (denali->caps & DENALI_CAP_HW_ECC_FIXUP)
++		ecc_err_mask = INTR__ECC_UNCOR_ERR;
++	else
++		ecc_err_mask = INTR__ECC_ERR;
++
++	denali_reset_irq(denali);
++
++	iowrite32(DENALI_MAP01 | addr, denali->host + DENALI_HOST_ADDR);
++	for (i = 0; i < size / 4; i++)
++		*buf32++ = ioread32(denali->host + DENALI_HOST_DATA);
++
++	irq_status = denali_wait_for_irq(denali, INTR__PAGE_XFER_INC);
++	if (!(irq_status & INTR__PAGE_XFER_INC))
++		return -EIO;
++
++	if (irq_status & INTR__ERASED_PAGE)
++		memset(buf, 0xff, size);
++
++	return irq_status & ecc_err_mask ? -EBADMSG : 0;
++}
++
++static int denali_pio_write(struct denali_nand_info *denali,
++			    const void *buf, size_t size, int page, int raw)
++{
++	uint32_t addr = DENALI_BANK(denali) | page;
++	const uint32_t *buf32 = (uint32_t *)buf;
++	uint32_t irq_status;
++	int i;
++
++	denali_reset_irq(denali);
++
++	iowrite32(DENALI_MAP01 | addr, denali->host + DENALI_HOST_ADDR);
++	for (i = 0; i < size / 4; i++)
++		iowrite32(*buf32++, denali->host + DENALI_HOST_DATA);
++
++	irq_status = denali_wait_for_irq(denali,
++				INTR__PROGRAM_COMP | INTR__PROGRAM_FAIL);
++	if (!(irq_status & INTR__PROGRAM_COMP))
++		return -EIO;
++
++	return 0;
++}
++
++static int denali_pio_xfer(struct denali_nand_info *denali, void *buf,
++			   size_t size, int page, int raw, int write)
++{
++	if (write)
++		return denali_pio_write(denali, buf, size, page, raw);
++	else
++		return denali_pio_read(denali, buf, size, page, raw);
++}
++
++static int denali_dma_xfer(struct denali_nand_info *denali, void *buf,
++			   size_t size, int page, int raw, int write)
++{
++	dma_addr_t dma_addr;
++	uint32_t irq_mask, irq_status, ecc_err_mask;
++	enum dma_data_direction dir = write ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
++	int ret = 0;
++
++	dma_addr = dma_map_single(denali->dev, buf, size, dir);
++	if (dma_mapping_error(denali->dev, dma_addr)) {
++		dev_dbg(denali->dev, "Failed to DMA-map buffer. Trying PIO.\n");
++		return denali_pio_xfer(denali, buf, size, page, raw, write);
++	}
++
++	if (write) {
++		/*
++		 * INTR__PROGRAM_COMP is never asserted for the DMA transfer.
++		 * We can use INTR__DMA_CMD_COMP instead.  This flag is asserted
++		 * when the page program is completed.
++		 */
++		irq_mask = INTR__DMA_CMD_COMP | INTR__PROGRAM_FAIL;
++		ecc_err_mask = 0;
++	} else if (denali->caps & DENALI_CAP_HW_ECC_FIXUP) {
++		irq_mask = INTR__DMA_CMD_COMP;
++		ecc_err_mask = INTR__ECC_UNCOR_ERR;
++	} else {
++		irq_mask = INTR__DMA_CMD_COMP;
++		ecc_err_mask = INTR__ECC_ERR;
++	}
++
++	denali_enable_dma(denali, true);
++
++	denali_reset_irq(denali);
++	denali_setup_dma(denali, dma_addr, page, write);
++
++	/* wait for operation to complete */
++	irq_status = denali_wait_for_irq(denali, irq_mask);
++	if (!(irq_status & INTR__DMA_CMD_COMP))
++		ret = -EIO;
++	else if (irq_status & ecc_err_mask)
++		ret = -EBADMSG;
++
++	denali_enable_dma(denali, false);
++	dma_unmap_single(denali->dev, dma_addr, size, dir);
++
++	if (irq_status & INTR__ERASED_PAGE)
++		memset(buf, 0xff, size);
++
++	return ret;
++}
++
++static int denali_data_xfer(struct denali_nand_info *denali, void *buf,
++			    size_t size, int page, int raw, int write)
++{
++	setup_ecc_for_xfer(denali, !raw, raw);
++
++	if (denali->dma_avail)
++		return denali_dma_xfer(denali, buf, size, page, raw, write);
++	else
++		return denali_pio_xfer(denali, buf, size, page, raw, write);
++}
++
++static void denali_oob_xfer(struct mtd_info *mtd, struct nand_chip *chip,
++			    int page, int write)
++{
++	struct denali_nand_info *denali = mtd_to_denali(mtd);
++	unsigned int start_cmd = write ? NAND_CMD_SEQIN : NAND_CMD_READ0;
++	unsigned int rnd_cmd = write ? NAND_CMD_RNDIN : NAND_CMD_RNDOUT;
++	int writesize = mtd->writesize;
++	int oobsize = mtd->oobsize;
++	uint8_t *bufpoi = chip->oob_poi;
++	int ecc_steps = chip->ecc.steps;
++	int ecc_size = chip->ecc.size;
++	int ecc_bytes = chip->ecc.bytes;
++	int oob_skip = denali->oob_skip_bytes;
++	size_t size = writesize + oobsize;
++	int i, pos, len;
++
++	/* BBM at the beginning of the OOB area */
++	chip->cmdfunc(mtd, start_cmd, writesize, page);
++	if (write)
++		chip->write_buf(mtd, bufpoi, oob_skip);
++	else
++		chip->read_buf(mtd, bufpoi, oob_skip);
++	bufpoi += oob_skip;
++
++	/* OOB ECC */
++	for (i = 0; i < ecc_steps; i++) {
++		pos = ecc_size + i * (ecc_size + ecc_bytes);
++		len = ecc_bytes;
++
++		if (pos >= writesize)
++			pos += oob_skip;
++		else if (pos + len > writesize)
++			len = writesize - pos;
++
++		chip->cmdfunc(mtd, rnd_cmd, pos, -1);
++		if (write)
++			chip->write_buf(mtd, bufpoi, len);
++		else
++			chip->read_buf(mtd, bufpoi, len);
++		bufpoi += len;
++		if (len < ecc_bytes) {
++			len = ecc_bytes - len;
++			chip->cmdfunc(mtd, rnd_cmd, writesize + oob_skip, -1);
++			if (write)
++				chip->write_buf(mtd, bufpoi, len);
++			else
++				chip->read_buf(mtd, bufpoi, len);
++			bufpoi += len;
++		}
++	}
++
++	/* OOB free */
++	len = oobsize - (bufpoi - chip->oob_poi);
++	chip->cmdfunc(mtd, rnd_cmd, size - len, -1);
++	if (write)
++		chip->write_buf(mtd, bufpoi, len);
++	else
++		chip->read_buf(mtd, bufpoi, len);
++}
++
++static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
++				uint8_t *buf, int oob_required, int page)
++{
++	struct denali_nand_info *denali = mtd_to_denali(mtd);
++	int writesize = mtd->writesize;
++	int oobsize = mtd->oobsize;
++	int ecc_steps = chip->ecc.steps;
++	int ecc_size = chip->ecc.size;
++	int ecc_bytes = chip->ecc.bytes;
++	void *dma_buf = denali->buf;
++	int oob_skip = denali->oob_skip_bytes;
++	size_t size = writesize + oobsize;
++	int ret, i, pos, len;
++
++	ret = denali_data_xfer(denali, dma_buf, size, page, 1, 0);
++	if (ret)
++		return ret;
++
++	/* Arrange the buffer for syndrome payload/ecc layout */
++	if (buf) {
++		for (i = 0; i < ecc_steps; i++) {
++			pos = i * (ecc_size + ecc_bytes);
++			len = ecc_size;
++
++			if (pos >= writesize)
++				pos += oob_skip;
++			else if (pos + len > writesize)
++				len = writesize - pos;
++
++			memcpy(buf, dma_buf + pos, len);
++			buf += len;
++			if (len < ecc_size) {
++				len = ecc_size - len;
++				memcpy(buf, dma_buf + writesize + oob_skip,
++				       len);
++				buf += len;
++			}
++		}
++	}
++
++	if (oob_required) {
++		uint8_t *oob = chip->oob_poi;
++
++		/* BBM at the beginning of the OOB area */
++		memcpy(oob, dma_buf + writesize, oob_skip);
++		oob += oob_skip;
++
++		/* OOB ECC */
++		for (i = 0; i < ecc_steps; i++) {
++			pos = ecc_size + i * (ecc_size + ecc_bytes);
++			len = ecc_bytes;
++
++			if (pos >= writesize)
++				pos += oob_skip;
++			else if (pos + len > writesize)
++				len = writesize - pos;
++
++			memcpy(oob, dma_buf + pos, len);
++			oob += len;
++			if (len < ecc_bytes) {
++				len = ecc_bytes - len;
++				memcpy(oob, dma_buf + writesize + oob_skip,
++				       len);
++				oob += len;
++			}
++		}
++
++		/* OOB free */
++		len = oobsize - (oob - chip->oob_poi);
++		memcpy(oob, dma_buf + size - len, len);
++	}
++
++	return 0;
++}
++
++static int denali_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
++			   int page)
++{
++	denali_oob_xfer(mtd, chip, page, 0);
++
++	return 0;
++}
++
++static int denali_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
++			    int page)
++{
++	struct denali_nand_info *denali = mtd_to_denali(mtd);
++	int status;
++
++	denali_reset_irq(denali);
++
++	denali_oob_xfer(mtd, chip, page, 1);
++
++	chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
++	status = chip->waitfunc(mtd, chip);
++
++	return status & NAND_STATUS_FAIL ? -EIO : 0;
++}
++
++static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
++			    uint8_t *buf, int oob_required, int page)
++{
++	struct denali_nand_info *denali = mtd_to_denali(mtd);
++	unsigned long uncor_ecc_flags = 0;
++	int stat = 0;
++	int ret;
++
++	ret = denali_data_xfer(denali, buf, mtd->writesize, page, 0, 0);
++	if (ret && ret != -EBADMSG)
++		return ret;
++
++	if (denali->caps & DENALI_CAP_HW_ECC_FIXUP)
++		stat = denali_hw_ecc_fixup(mtd, denali, &uncor_ecc_flags);
++	else if (ret == -EBADMSG)
++		stat = denali_sw_ecc_fixup(mtd, denali, &uncor_ecc_flags, buf);
++
++	if (stat < 0)
++		return stat;
++
++	if (uncor_ecc_flags) {
++		ret = denali_read_oob(mtd, chip, page);
++		if (ret)
++			return ret;
++
++		stat = denali_check_erased_page(mtd, chip, buf,
++						uncor_ecc_flags, stat);
++	}
++
++	return stat;
++}
++
++static int denali_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
++				 const uint8_t *buf, int oob_required, int page)
++{
++	struct denali_nand_info *denali = mtd_to_denali(mtd);
++	int writesize = mtd->writesize;
++	int oobsize = mtd->oobsize;
++	int ecc_steps = chip->ecc.steps;
++	int ecc_size = chip->ecc.size;
++	int ecc_bytes = chip->ecc.bytes;
++	void *dma_buf = denali->buf;
++	int oob_skip = denali->oob_skip_bytes;
++	size_t size = writesize + oobsize;
++	int i, pos, len;
++
++	/*
++	 * Fill the buffer with 0xff first except the full page transfer.
++	 * This simplifies the logic.
++	 */
++	if (!buf || !oob_required)
++		memset(dma_buf, 0xff, size);
++
++	/* Arrange the buffer for syndrome payload/ecc layout */
++	if (buf) {
++		for (i = 0; i < ecc_steps; i++) {
++			pos = i * (ecc_size + ecc_bytes);
++			len = ecc_size;
++
++			if (pos >= writesize)
++				pos += oob_skip;
++			else if (pos + len > writesize)
++				len = writesize - pos;
++
++			memcpy(dma_buf + pos, buf, len);
++			buf += len;
++			if (len < ecc_size) {
++				len = ecc_size - len;
++				memcpy(dma_buf + writesize + oob_skip, buf,
++				       len);
++				buf += len;
++			}
++		}
++	}
++
++	if (oob_required) {
++		const uint8_t *oob = chip->oob_poi;
++
++		/* BBM at the beginning of the OOB area */
++		memcpy(dma_buf + writesize, oob, oob_skip);
++		oob += oob_skip;
++
++		/* OOB ECC */
++		for (i = 0; i < ecc_steps; i++) {
++			pos = ecc_size + i * (ecc_size + ecc_bytes);
++			len = ecc_bytes;
++
++			if (pos >= writesize)
++				pos += oob_skip;
++			else if (pos + len > writesize)
++				len = writesize - pos;
++
++			memcpy(dma_buf + pos, oob, len);
++			oob += len;
++			if (len < ecc_bytes) {
++				len = ecc_bytes - len;
++				memcpy(dma_buf + writesize + oob_skip, oob,
++				       len);
++				oob += len;
++			}
++		}
++
++		/* OOB free */
++		len = oobsize - (oob - chip->oob_poi);
++		memcpy(dma_buf + size - len, oob, len);
++	}
++
++	return denali_data_xfer(denali, dma_buf, size, page, 1, 1);
++}
++
++static int denali_write_page(struct mtd_info *mtd, struct nand_chip *chip,
++			     const uint8_t *buf, int oob_required, int page)
++{
++	struct denali_nand_info *denali = mtd_to_denali(mtd);
++
++	return denali_data_xfer(denali, (void *)buf, mtd->writesize,
++				page, 0, 1);
++}
++
++static void denali_select_chip(struct mtd_info *mtd, int chip)
++{
++	struct denali_nand_info *denali = mtd_to_denali(mtd);
++
++	denali->active_bank = chip;
++}
++
++static int denali_waitfunc(struct mtd_info *mtd, struct nand_chip *chip)
++{
++	struct denali_nand_info *denali = mtd_to_denali(mtd);
++	uint32_t irq_status;
++
++	/* R/B# pin transitioned from low to high? */
++	irq_status = denali_wait_for_irq(denali, INTR__INT_ACT);
++
++	return irq_status & INTR__INT_ACT ? 0 : NAND_STATUS_FAIL;
++}
++
++static int denali_erase(struct mtd_info *mtd, int page)
++{
++	struct denali_nand_info *denali = mtd_to_denali(mtd);
++	uint32_t irq_status;
++
++	denali_reset_irq(denali);
++
++	denali_host_write(denali, DENALI_MAP10 | DENALI_BANK(denali) | page,
++			  DENALI_ERASE);
++
++	/* wait for erase to complete or failure to occur */
++	irq_status = denali_wait_for_irq(denali,
++					 INTR__ERASE_COMP | INTR__ERASE_FAIL);
++
++	return irq_status & INTR__ERASE_COMP ? 0 : NAND_STATUS_FAIL;
++}
++
++static int denali_setup_data_interface(struct mtd_info *mtd, int chipnr,
++				       const struct nand_data_interface *conf)
++{
++	struct denali_nand_info *denali = mtd_to_denali(mtd);
++	const struct nand_sdr_timings *timings;
++	unsigned long t_clk;
++	int acc_clks, re_2_we, re_2_re, we_2_re, addr_2_data;
++	int rdwr_en_lo, rdwr_en_hi, rdwr_en_lo_hi, cs_setup;
++	int addr_2_data_mask;
++	uint32_t tmp;
++
++	timings = nand_get_sdr_timings(conf);
++	if (IS_ERR(timings))
++		return PTR_ERR(timings);
++
++	/* clk_x period in picoseconds */
++	t_clk = DIV_ROUND_DOWN_ULL(1000000000000ULL, denali->clk_x_rate);
++	if (!t_clk)
++		return -EINVAL;
++
++	if (chipnr == NAND_DATA_IFACE_CHECK_ONLY)
++		return 0;
++
++	/* tREA -> ACC_CLKS */
++	acc_clks = DIV_ROUND_UP(timings->tREA_max, t_clk);
++	acc_clks = min_t(int, acc_clks, ACC_CLKS__VALUE);
++
++	tmp = ioread32(denali->reg + ACC_CLKS);
++	tmp &= ~ACC_CLKS__VALUE;
++	tmp |= acc_clks;
++	iowrite32(tmp, denali->reg + ACC_CLKS);
++
++	/* tRWH -> RE_2_WE */
++	re_2_we = DIV_ROUND_UP(timings->tRHW_min, t_clk);
++	re_2_we = min_t(int, re_2_we, RE_2_WE__VALUE);
++
++	tmp = ioread32(denali->reg + RE_2_WE);
++	tmp &= ~RE_2_WE__VALUE;
++	tmp |= re_2_we;
++	iowrite32(tmp, denali->reg + RE_2_WE);
++
++	/* tRHZ -> RE_2_RE */
++	re_2_re = DIV_ROUND_UP(timings->tRHZ_max, t_clk);
++	re_2_re = min_t(int, re_2_re, RE_2_RE__VALUE);
++
++	tmp = ioread32(denali->reg + RE_2_RE);
++	tmp &= ~RE_2_RE__VALUE;
++	tmp |= re_2_re;
++	iowrite32(tmp, denali->reg + RE_2_RE);
++
++	/* tWHR -> WE_2_RE */
++	we_2_re = DIV_ROUND_UP(timings->tWHR_min, t_clk);
++	we_2_re = min_t(int, we_2_re, TWHR2_AND_WE_2_RE__WE_2_RE);
++
++	tmp = ioread32(denali->reg + TWHR2_AND_WE_2_RE);
++	tmp &= ~TWHR2_AND_WE_2_RE__WE_2_RE;
++	tmp |= we_2_re;
++	iowrite32(tmp, denali->reg + TWHR2_AND_WE_2_RE);
++
++	/* tADL -> ADDR_2_DATA */
++
++	/* for older versions, ADDR_2_DATA is only 6 bit wide */
++	addr_2_data_mask = TCWAW_AND_ADDR_2_DATA__ADDR_2_DATA;
++	if (denali->revision < 0x0501)
++		addr_2_data_mask >>= 1;
++
++	addr_2_data = DIV_ROUND_UP(timings->tADL_min, t_clk);
++	addr_2_data = min_t(int, addr_2_data, addr_2_data_mask);
++
++	tmp = ioread32(denali->reg + TCWAW_AND_ADDR_2_DATA);
++	tmp &= ~addr_2_data_mask;
++	tmp |= addr_2_data;
++	iowrite32(tmp, denali->reg + TCWAW_AND_ADDR_2_DATA);
++
++	/* tREH, tWH -> RDWR_EN_HI_CNT */
++	rdwr_en_hi = DIV_ROUND_UP(max(timings->tREH_min, timings->tWH_min),
++				  t_clk);
++	rdwr_en_hi = min_t(int, rdwr_en_hi, RDWR_EN_HI_CNT__VALUE);
++
++	tmp = ioread32(denali->reg + RDWR_EN_HI_CNT);
++	tmp &= ~RDWR_EN_HI_CNT__VALUE;
++	tmp |= rdwr_en_hi;
++	iowrite32(tmp, denali->reg + RDWR_EN_HI_CNT);
++
++	/* tRP, tWP -> RDWR_EN_LO_CNT */
++	rdwr_en_lo = DIV_ROUND_UP(max(timings->tRP_min, timings->tWP_min),
++				  t_clk);
++	rdwr_en_lo_hi = DIV_ROUND_UP(max(timings->tRC_min, timings->tWC_min),
++				     t_clk);
++	rdwr_en_lo_hi = max(rdwr_en_lo_hi, DENALI_CLK_X_MULT);
++	rdwr_en_lo = max(rdwr_en_lo, rdwr_en_lo_hi - rdwr_en_hi);
++	rdwr_en_lo = min_t(int, rdwr_en_lo, RDWR_EN_LO_CNT__VALUE);
++
++	tmp = ioread32(denali->reg + RDWR_EN_LO_CNT);
++	tmp &= ~RDWR_EN_LO_CNT__VALUE;
++	tmp |= rdwr_en_lo;
++	iowrite32(tmp, denali->reg + RDWR_EN_LO_CNT);
++
++	/* tCS, tCEA -> CS_SETUP_CNT */
++	cs_setup = max3((int)DIV_ROUND_UP(timings->tCS_min, t_clk) - rdwr_en_lo,
++			(int)DIV_ROUND_UP(timings->tCEA_max, t_clk) - acc_clks,
++			0);
++	cs_setup = min_t(int, cs_setup, CS_SETUP_CNT__VALUE);
++
++	tmp = ioread32(denali->reg + CS_SETUP_CNT);
++	tmp &= ~CS_SETUP_CNT__VALUE;
++	tmp |= cs_setup;
++	iowrite32(tmp, denali->reg + CS_SETUP_CNT);
++
++	return 0;
++}
++
++static void denali_reset_banks(struct denali_nand_info *denali)
++{
++	u32 irq_status;
++	int i;
++
++	for (i = 0; i < denali->max_banks; i++) {
++		denali->active_bank = i;
++
++		denali_reset_irq(denali);
++
++		iowrite32(DEVICE_RESET__BANK(i),
++			  denali->reg + DEVICE_RESET);
++
++		irq_status = denali_wait_for_irq(denali,
++			INTR__RST_COMP | INTR__INT_ACT | INTR__TIME_OUT);
++		if (!(irq_status & INTR__INT_ACT))
++			break;
++	}
++
++	dev_dbg(denali->dev, "%d chips connected\n", i);
++	denali->max_banks = i;
++}
++
++static void denali_hw_init(struct denali_nand_info *denali)
++{
++	/*
++	 * The REVISION register may not be reliable.  Platforms are allowed to
++	 * override it.
++	 */
++	if (!denali->revision)
++		denali->revision = swab16(ioread32(denali->reg + REVISION));
++
++	/*
++	 * tell driver how many bit controller will skip before
++	 * writing ECC code in OOB, this register may be already
++	 * set by firmware. So we read this value out.
++	 * if this value is 0, just let it be.
++	 */
++	denali->oob_skip_bytes = ioread32(denali->reg + SPARE_AREA_SKIP_BYTES);
++	detect_max_banks(denali);
++	iowrite32(0x0F, denali->reg + RB_PIN_ENABLED);
++	iowrite32(CHIP_EN_DONT_CARE__FLAG, denali->reg + CHIP_ENABLE_DONT_CARE);
++
++	iowrite32(0xffff, denali->reg + SPARE_AREA_MARKER);
++
++	/* Should set value for these registers when init */
++	iowrite32(0, denali->reg + TWO_ROW_ADDR_CYCLES);
++	iowrite32(1, denali->reg + ECC_ENABLE);
++}
++
++int denali_calc_ecc_bytes(int step_size, int strength)
++{
++	/* BCH code.  Denali requires ecc.bytes to be multiple of 2 */
++	return DIV_ROUND_UP(strength * fls(step_size * 8), 16) * 2;
++}
++EXPORT_SYMBOL(denali_calc_ecc_bytes);
++
++static int denali_ecc_setup(struct mtd_info *mtd, struct nand_chip *chip,
++			    struct denali_nand_info *denali)
++{
++	int oobavail = mtd->oobsize - denali->oob_skip_bytes;
++	int ret;
++
++	/*
++	 * If .size and .strength are already set (usually by DT),
++	 * check if they are supported by this controller.
++	 */
++	if (chip->ecc.size && chip->ecc.strength)
++		return nand_check_ecc_caps(chip, denali->ecc_caps, oobavail);
++
++	/*
++	 * We want .size and .strength closest to the chip's requirement
++	 * unless NAND_ECC_MAXIMIZE is requested.
++	 */
++	if (!(chip->ecc.options & NAND_ECC_MAXIMIZE)) {
++		ret = nand_match_ecc_req(chip, denali->ecc_caps, oobavail);
++		if (!ret)
++			return 0;
++	}
++
++	/* Max ECC strength is the last thing we can do */
++	return nand_maximize_ecc(chip, denali->ecc_caps, oobavail);
++}
++
++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);
++
++	if (section)
++		return -ERANGE;
++
++	oobregion->offset = denali->oob_skip_bytes;
++	oobregion->length = chip->ecc.total;
++
++	return 0;
++}
++
++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);
++
++	if (section)
++		return -ERANGE;
++
++	oobregion->offset = chip->ecc.total + denali->oob_skip_bytes;
++	oobregion->length = mtd->oobsize - oobregion->offset;
++
++	return 0;
++}
++
++static const struct mtd_ooblayout_ops denali_ooblayout_ops = {
++	.ecc = denali_ooblayout_ecc,
++	.free = denali_ooblayout_free,
++};
++
++/* initialize driver data structures */
++static void denali_drv_init(struct denali_nand_info *denali)
++{
++	/*
++	 * the completion object will be used to notify
++	 * the callee that the interrupt is done
++	 */
++	init_completion(&denali->complete);
++
++	/*
++	 * the spinlock will be used to synchronize the ISR with any
++	 * element that might be access shared data (interrupt status)
++	 */
++	spin_lock_init(&denali->irq_lock);
++}
++
++static int denali_multidev_fixup(struct denali_nand_info *denali)
++{
++	struct nand_chip *chip = &denali->nand;
++	struct mtd_info *mtd = nand_to_mtd(chip);
++
++	/*
++	 * Support for multi device:
++	 * When the IP configuration is x16 capable and two x8 chips are
++	 * connected in parallel, DEVICES_CONNECTED should be set to 2.
++	 * In this case, the core framework knows nothing about this fact,
++	 * so we should tell it the _logical_ pagesize and anything necessary.
++	 */
++	denali->devs_per_cs = ioread32(denali->reg + DEVICES_CONNECTED);
++
++	/*
++	 * On some SoCs, DEVICES_CONNECTED is not auto-detected.
++	 * For those, DEVICES_CONNECTED is left to 0.  Set 1 if it is the case.
++	 */
++	if (denali->devs_per_cs == 0) {
++		denali->devs_per_cs = 1;
++		iowrite32(1, denali->reg + DEVICES_CONNECTED);
++	}
++
++	if (denali->devs_per_cs == 1)
++		return 0;
++
++	if (denali->devs_per_cs != 2) {
++		dev_err(denali->dev, "unsupported number of devices %d\n",
++			denali->devs_per_cs);
++		return -EINVAL;
++	}
++
++	/* 2 chips in parallel */
++	mtd->size <<= 1;
++	mtd->erasesize <<= 1;
++	mtd->writesize <<= 1;
++	mtd->oobsize <<= 1;
++	chip->chipsize <<= 1;
++	chip->page_shift += 1;
++	chip->phys_erase_shift += 1;
++	chip->bbt_erase_shift += 1;
++	chip->chip_shift += 1;
++	chip->pagemask <<= 1;
++	chip->ecc.size <<= 1;
++	chip->ecc.bytes <<= 1;
++	chip->ecc.strength <<= 1;
++	denali->oob_skip_bytes <<= 1;
++
++	return 0;
++}
++
++int denali_init(struct denali_nand_info *denali)
++{
++	struct nand_chip *chip = &denali->nand;
++	struct mtd_info *mtd = nand_to_mtd(chip);
++	int ret;
++
++	mtd->dev.parent = denali->dev;
++	denali_hw_init(denali);
++	denali_drv_init(denali);
++
++	denali_clear_irq_all(denali);
++
++	/* Request IRQ after all the hardware initialization is finished */
++	ret = devm_request_irq(denali->dev, denali->irq, denali_isr,
++			       IRQF_SHARED, DENALI_NAND_NAME, denali);
++	if (ret) {
++		dev_err(denali->dev, "Unable to request IRQ\n");
++		return ret;
++	}
++
++	denali_enable_irq(denali);
++	denali_reset_banks(denali);
++
++	denali->active_bank = DENALI_INVALID_BANK;
++
++	nand_set_flash_node(chip, denali->dev->of_node);
++	/* Fallback to the default name if DT did not give "label" property */
++	if (!mtd->name)
++		mtd->name = "denali-nand";
++
++	/* register the driver with the NAND core subsystem */
++	chip->select_chip = denali_select_chip;
++	chip->read_byte = denali_read_byte;
++	chip->write_byte = denali_write_byte;
++	chip->read_word = denali_read_word;
++	chip->cmd_ctrl = denali_cmd_ctrl;
++	chip->dev_ready = denali_dev_ready;
++	chip->waitfunc = denali_waitfunc;
++
++	/* clk rate info is needed for setup_data_interface */
++	if (denali->clk_x_rate)
++		chip->setup_data_interface = denali_setup_data_interface;
++
++	/*
++	 * scan for NAND devices attached to the controller
++	 * this is the first stage in a two step process to register
++	 * with the nand subsystem
++	 */
++	ret = nand_scan_ident(mtd, denali->max_banks, NULL);
++	if (ret)
++		goto disable_irq;
++
++	if (ioread32(denali->reg + FEATURES) & FEATURES__DMA)
++		denali->dma_avail = 1;
++
++	if (denali->dma_avail) {
++		int dma_bit = denali->caps & DENALI_CAP_DMA_64BIT ? 64 : 32;
++
++		ret = dma_set_mask(denali->dev, DMA_BIT_MASK(dma_bit));
++		if (ret) {
++			dev_info(denali->dev,
++				 "Failed to set DMA mask. Disabling DMA.\n");
++			denali->dma_avail = 0;
++		}
++	}
++
++	if (denali->dma_avail) {
++		chip->options |= NAND_USE_BOUNCE_BUFFER;
++		chip->buf_align = 16;
++	}
++
++	/*
++	 * second stage of the NAND scan
++	 * this stage requires information regarding ECC and
++	 * bad block management.
++	 */
++
++	chip->bbt_options |= NAND_BBT_USE_FLASH;
++	chip->bbt_options |= NAND_BBT_NO_OOB;
++
++	chip->ecc.mode = NAND_ECC_HW_SYNDROME;
++
++	/* no subpage writes on denali */
++	chip->options |= NAND_NO_SUBPAGE_WRITE;
++
++	ret = denali_ecc_setup(mtd, chip, denali);
++	if (ret) {
++		dev_err(denali->dev, "Failed to setup ECC settings.\n");
++		goto disable_irq;
++	}
++
++	dev_dbg(denali->dev,
++		"chosen ECC settings: step=%d, strength=%d, bytes=%d\n",
++		chip->ecc.size, chip->ecc.strength, chip->ecc.bytes);
++
++	iowrite32(MAKE_ECC_CORRECTION(chip->ecc.strength, 1),
++		  denali->reg + ECC_CORRECTION);
++	iowrite32(mtd->erasesize / mtd->writesize,
++		  denali->reg + PAGES_PER_BLOCK);
++	iowrite32(chip->options & NAND_BUSWIDTH_16 ? 1 : 0,
++		  denali->reg + DEVICE_WIDTH);
++	iowrite32(mtd->writesize, denali->reg + DEVICE_MAIN_AREA_SIZE);
++	iowrite32(mtd->oobsize, denali->reg + DEVICE_SPARE_AREA_SIZE);
++
++	iowrite32(chip->ecc.size, denali->reg + CFG_DATA_BLOCK_SIZE);
++	iowrite32(chip->ecc.size, denali->reg + CFG_LAST_DATA_BLOCK_SIZE);
++	/* chip->ecc.steps is set by nand_scan_tail(); not available here */
++	iowrite32(mtd->writesize / chip->ecc.size,
++		  denali->reg + CFG_NUM_DATA_BLOCKS);
++
++	mtd_set_ooblayout(mtd, &denali_ooblayout_ops);
++
++	if (chip->options & NAND_BUSWIDTH_16) {
++		chip->read_buf = denali_read_buf16;
++		chip->write_buf = denali_write_buf16;
++	} else {
++		chip->read_buf = denali_read_buf;
++		chip->write_buf = denali_write_buf;
++	}
++	chip->ecc.options |= NAND_ECC_CUSTOM_PAGE_ACCESS;
++	chip->ecc.read_page = denali_read_page;
++	chip->ecc.read_page_raw = denali_read_page_raw;
++	chip->ecc.write_page = denali_write_page;
++	chip->ecc.write_page_raw = denali_write_page_raw;
++	chip->ecc.read_oob = denali_read_oob;
++	chip->ecc.write_oob = denali_write_oob;
++	chip->erase = denali_erase;
++
++	ret = denali_multidev_fixup(denali);
++	if (ret)
++		goto disable_irq;
++
++	/*
++	 * This buffer is DMA-mapped by denali_{read,write}_page_raw.  Do not
++	 * use devm_kmalloc() because the memory allocated by devm_ does not
++	 * guarantee DMA-safe alignment.
++	 */
++	denali->buf = kmalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL);
++	if (!denali->buf) {
++		ret = -ENOMEM;
++		goto disable_irq;
++	}
++
++	ret = nand_scan_tail(mtd);
++	if (ret)
++		goto free_buf;
++
++	ret = mtd_device_register(mtd, NULL, 0);
++	if (ret) {
++		dev_err(denali->dev, "Failed to register MTD: %d\n", ret);
++		goto free_buf;
++	}
++	return 0;
++
++free_buf:
++	kfree(denali->buf);
++disable_irq:
++	denali_disable_irq(denali);
++
++	return ret;
++}
++EXPORT_SYMBOL(denali_init);
++
++/* driver exit point */
++void denali_remove(struct denali_nand_info *denali)
++{
++	struct mtd_info *mtd = nand_to_mtd(&denali->nand);
++
++	nand_release(mtd);
++	kfree(denali->buf);
++	denali_disable_irq(denali);
++}
++EXPORT_SYMBOL(denali_remove);
+diff --git a/drivers/mtd/nand/raw/denali.h b/drivers/mtd/nand/raw/denali.h
+new file mode 100644
+index 0000000..9239e67
+--- /dev/null
++++ b/drivers/mtd/nand/raw/denali.h
+@@ -0,0 +1,339 @@
++/*
++ * NAND Flash Controller Device Driver
++ * Copyright (c) 2009 - 2010, Intel Corporation and its suppliers.
++ *
++ * 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, write to the Free Software Foundation, Inc.,
++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ */
++
++#ifndef __DENALI_H__
++#define __DENALI_H__
++
++#include <linux/bitops.h>
++#include <linux/mtd/rawnand.h>
++
++#define DEVICE_RESET				0x0
++#define     DEVICE_RESET__BANK(bank)			BIT(bank)
++
++#define TRANSFER_SPARE_REG			0x10
++#define     TRANSFER_SPARE_REG__FLAG			BIT(0)
++
++#define LOAD_WAIT_CNT				0x20
++#define     LOAD_WAIT_CNT__VALUE			GENMASK(15, 0)
++
++#define PROGRAM_WAIT_CNT			0x30
++#define     PROGRAM_WAIT_CNT__VALUE			GENMASK(15, 0)
++
++#define ERASE_WAIT_CNT				0x40
++#define     ERASE_WAIT_CNT__VALUE			GENMASK(15, 0)
++
++#define INT_MON_CYCCNT				0x50
++#define     INT_MON_CYCCNT__VALUE			GENMASK(15, 0)
++
++#define RB_PIN_ENABLED				0x60
++#define     RB_PIN_ENABLED__BANK(bank)			BIT(bank)
++
++#define MULTIPLANE_OPERATION			0x70
++#define     MULTIPLANE_OPERATION__FLAG			BIT(0)
++
++#define MULTIPLANE_READ_ENABLE			0x80
++#define     MULTIPLANE_READ_ENABLE__FLAG		BIT(0)
++
++#define COPYBACK_DISABLE			0x90
++#define     COPYBACK_DISABLE__FLAG			BIT(0)
++
++#define CACHE_WRITE_ENABLE			0xa0
++#define     CACHE_WRITE_ENABLE__FLAG			BIT(0)
++
++#define CACHE_READ_ENABLE			0xb0
++#define     CACHE_READ_ENABLE__FLAG			BIT(0)
++
++#define PREFETCH_MODE				0xc0
++#define     PREFETCH_MODE__PREFETCH_EN			BIT(0)
++#define     PREFETCH_MODE__PREFETCH_BURST_LENGTH	GENMASK(15, 4)
++
++#define CHIP_ENABLE_DONT_CARE			0xd0
++#define     CHIP_EN_DONT_CARE__FLAG			BIT(0)
++
++#define ECC_ENABLE				0xe0
++#define     ECC_ENABLE__FLAG				BIT(0)
++
++#define GLOBAL_INT_ENABLE			0xf0
++#define     GLOBAL_INT_EN_FLAG				BIT(0)
++
++#define TWHR2_AND_WE_2_RE			0x100
++#define     TWHR2_AND_WE_2_RE__WE_2_RE			GENMASK(5, 0)
++#define     TWHR2_AND_WE_2_RE__TWHR2			GENMASK(13, 8)
++
++#define TCWAW_AND_ADDR_2_DATA			0x110
++/* The width of ADDR_2_DATA is 6 bit for old IP, 7 bit for new IP */
++#define     TCWAW_AND_ADDR_2_DATA__ADDR_2_DATA		GENMASK(6, 0)
++#define     TCWAW_AND_ADDR_2_DATA__TCWAW		GENMASK(13, 8)
++
++#define RE_2_WE					0x120
++#define     RE_2_WE__VALUE				GENMASK(5, 0)
++
++#define ACC_CLKS				0x130
++#define     ACC_CLKS__VALUE				GENMASK(3, 0)
++
++#define NUMBER_OF_PLANES			0x140
++#define     NUMBER_OF_PLANES__VALUE			GENMASK(2, 0)
++
++#define PAGES_PER_BLOCK				0x150
++#define     PAGES_PER_BLOCK__VALUE			GENMASK(15, 0)
++
++#define DEVICE_WIDTH				0x160
++#define     DEVICE_WIDTH__VALUE				GENMASK(1, 0)
++
++#define DEVICE_MAIN_AREA_SIZE			0x170
++#define     DEVICE_MAIN_AREA_SIZE__VALUE		GENMASK(15, 0)
++
++#define DEVICE_SPARE_AREA_SIZE			0x180
++#define     DEVICE_SPARE_AREA_SIZE__VALUE		GENMASK(15, 0)
++
++#define TWO_ROW_ADDR_CYCLES			0x190
++#define     TWO_ROW_ADDR_CYCLES__FLAG			BIT(0)
++
++#define MULTIPLANE_ADDR_RESTRICT		0x1a0
++#define     MULTIPLANE_ADDR_RESTRICT__FLAG		BIT(0)
++
++#define ECC_CORRECTION				0x1b0
++#define     ECC_CORRECTION__VALUE			GENMASK(4, 0)
++#define     ECC_CORRECTION__ERASE_THRESHOLD		GENMASK(31, 16)
++#define     MAKE_ECC_CORRECTION(val, thresh)		\
++			(((val) & (ECC_CORRECTION__VALUE)) | \
++			(((thresh) << 16) & (ECC_CORRECTION__ERASE_THRESHOLD)))
++
++#define READ_MODE				0x1c0
++#define     READ_MODE__VALUE				GENMASK(3, 0)
++
++#define WRITE_MODE				0x1d0
++#define     WRITE_MODE__VALUE				GENMASK(3, 0)
++
++#define COPYBACK_MODE				0x1e0
++#define     COPYBACK_MODE__VALUE			GENMASK(3, 0)
++
++#define RDWR_EN_LO_CNT				0x1f0
++#define     RDWR_EN_LO_CNT__VALUE			GENMASK(4, 0)
++
++#define RDWR_EN_HI_CNT				0x200
++#define     RDWR_EN_HI_CNT__VALUE			GENMASK(4, 0)
++
++#define MAX_RD_DELAY				0x210
++#define     MAX_RD_DELAY__VALUE				GENMASK(3, 0)
++
++#define CS_SETUP_CNT				0x220
++#define     CS_SETUP_CNT__VALUE				GENMASK(4, 0)
++#define     CS_SETUP_CNT__TWB				GENMASK(17, 12)
++
++#define SPARE_AREA_SKIP_BYTES			0x230
++#define     SPARE_AREA_SKIP_BYTES__VALUE		GENMASK(5, 0)
++
++#define SPARE_AREA_MARKER			0x240
++#define     SPARE_AREA_MARKER__VALUE			GENMASK(15, 0)
++
++#define DEVICES_CONNECTED			0x250
++#define     DEVICES_CONNECTED__VALUE			GENMASK(2, 0)
++
++#define DIE_MASK				0x260
++#define     DIE_MASK__VALUE				GENMASK(7, 0)
++
++#define FIRST_BLOCK_OF_NEXT_PLANE		0x270
++#define     FIRST_BLOCK_OF_NEXT_PLANE__VALUE		GENMASK(15, 0)
++
++#define WRITE_PROTECT				0x280
++#define     WRITE_PROTECT__FLAG				BIT(0)
++
++#define RE_2_RE					0x290
++#define     RE_2_RE__VALUE				GENMASK(5, 0)
++
++#define MANUFACTURER_ID				0x300
++#define     MANUFACTURER_ID__VALUE			GENMASK(7, 0)
++
++#define DEVICE_ID				0x310
++#define     DEVICE_ID__VALUE				GENMASK(7, 0)
++
++#define DEVICE_PARAM_0				0x320
++#define     DEVICE_PARAM_0__VALUE			GENMASK(7, 0)
++
++#define DEVICE_PARAM_1				0x330
++#define     DEVICE_PARAM_1__VALUE			GENMASK(7, 0)
++
++#define DEVICE_PARAM_2				0x340
++#define     DEVICE_PARAM_2__VALUE			GENMASK(7, 0)
++
++#define LOGICAL_PAGE_DATA_SIZE			0x350
++#define     LOGICAL_PAGE_DATA_SIZE__VALUE		GENMASK(15, 0)
++
++#define LOGICAL_PAGE_SPARE_SIZE			0x360
++#define     LOGICAL_PAGE_SPARE_SIZE__VALUE		GENMASK(15, 0)
++
++#define REVISION				0x370
++#define     REVISION__VALUE				GENMASK(15, 0)
++
++#define ONFI_DEVICE_FEATURES			0x380
++#define     ONFI_DEVICE_FEATURES__VALUE			GENMASK(5, 0)
++
++#define ONFI_OPTIONAL_COMMANDS			0x390
++#define     ONFI_OPTIONAL_COMMANDS__VALUE		GENMASK(5, 0)
++
++#define ONFI_TIMING_MODE			0x3a0
++#define     ONFI_TIMING_MODE__VALUE			GENMASK(5, 0)
++
++#define ONFI_PGM_CACHE_TIMING_MODE		0x3b0
++#define     ONFI_PGM_CACHE_TIMING_MODE__VALUE		GENMASK(5, 0)
++
++#define ONFI_DEVICE_NO_OF_LUNS			0x3c0
++#define     ONFI_DEVICE_NO_OF_LUNS__NO_OF_LUNS		GENMASK(7, 0)
++#define     ONFI_DEVICE_NO_OF_LUNS__ONFI_DEVICE		BIT(8)
++
++#define ONFI_DEVICE_NO_OF_BLOCKS_PER_LUN_L	0x3d0
++#define     ONFI_DEVICE_NO_OF_BLOCKS_PER_LUN_L__VALUE	GENMASK(15, 0)
++
++#define ONFI_DEVICE_NO_OF_BLOCKS_PER_LUN_U	0x3e0
++#define     ONFI_DEVICE_NO_OF_BLOCKS_PER_LUN_U__VALUE	GENMASK(15, 0)
++
++#define FEATURES				0x3f0
++#define     FEATURES__N_BANKS				GENMASK(1, 0)
++#define     FEATURES__ECC_MAX_ERR			GENMASK(5, 2)
++#define     FEATURES__DMA				BIT(6)
++#define     FEATURES__CMD_DMA				BIT(7)
++#define     FEATURES__PARTITION				BIT(8)
++#define     FEATURES__XDMA_SIDEBAND			BIT(9)
++#define     FEATURES__GPREG				BIT(10)
++#define     FEATURES__INDEX_ADDR			BIT(11)
++
++#define TRANSFER_MODE				0x400
++#define     TRANSFER_MODE__VALUE			GENMASK(1, 0)
++
++#define INTR_STATUS(bank)			(0x410 + (bank) * 0x50)
++#define INTR_EN(bank)				(0x420 + (bank) * 0x50)
++/* bit[1:0] is used differently depending on IP version */
++#define     INTR__ECC_UNCOR_ERR				BIT(0)	/* new IP */
++#define     INTR__ECC_TRANSACTION_DONE			BIT(0)	/* old IP */
++#define     INTR__ECC_ERR				BIT(1)	/* old IP */
++#define     INTR__DMA_CMD_COMP				BIT(2)
++#define     INTR__TIME_OUT				BIT(3)
++#define     INTR__PROGRAM_FAIL				BIT(4)
++#define     INTR__ERASE_FAIL				BIT(5)
++#define     INTR__LOAD_COMP				BIT(6)
++#define     INTR__PROGRAM_COMP				BIT(7)
++#define     INTR__ERASE_COMP				BIT(8)
++#define     INTR__PIPE_CPYBCK_CMD_COMP			BIT(9)
++#define     INTR__LOCKED_BLK				BIT(10)
++#define     INTR__UNSUP_CMD				BIT(11)
++#define     INTR__INT_ACT				BIT(12)
++#define     INTR__RST_COMP				BIT(13)
++#define     INTR__PIPE_CMD_ERR				BIT(14)
++#define     INTR__PAGE_XFER_INC				BIT(15)
++#define     INTR__ERASED_PAGE				BIT(16)
++
++#define PAGE_CNT(bank)				(0x430 + (bank) * 0x50)
++#define ERR_PAGE_ADDR(bank)			(0x440 + (bank) * 0x50)
++#define ERR_BLOCK_ADDR(bank)			(0x450 + (bank) * 0x50)
++
++#define ECC_THRESHOLD				0x600
++#define     ECC_THRESHOLD__VALUE			GENMASK(9, 0)
++
++#define ECC_ERROR_BLOCK_ADDRESS			0x610
++#define     ECC_ERROR_BLOCK_ADDRESS__VALUE		GENMASK(15, 0)
++
++#define ECC_ERROR_PAGE_ADDRESS			0x620
++#define     ECC_ERROR_PAGE_ADDRESS__VALUE		GENMASK(11, 0)
++#define     ECC_ERROR_PAGE_ADDRESS__BANK		GENMASK(15, 12)
++
++#define ECC_ERROR_ADDRESS			0x630
++#define     ECC_ERROR_ADDRESS__OFFSET			GENMASK(11, 0)
++#define     ECC_ERROR_ADDRESS__SECTOR_NR		GENMASK(15, 12)
++
++#define ERR_CORRECTION_INFO			0x640
++#define     ERR_CORRECTION_INFO__BYTEMASK		GENMASK(7, 0)
++#define     ERR_CORRECTION_INFO__DEVICE_NR		GENMASK(11, 8)
++#define     ERR_CORRECTION_INFO__ERROR_TYPE		BIT(14)
++#define     ERR_CORRECTION_INFO__LAST_ERR_INFO		BIT(15)
++
++#define ECC_COR_INFO(bank)			(0x650 + (bank) / 2 * 0x10)
++#define     ECC_COR_INFO__SHIFT(bank)			((bank) % 2 * 8)
++#define     ECC_COR_INFO__MAX_ERRORS			GENMASK(6, 0)
++#define     ECC_COR_INFO__UNCOR_ERR			BIT(7)
++
++#define CFG_DATA_BLOCK_SIZE			0x6b0
++
++#define CFG_LAST_DATA_BLOCK_SIZE		0x6c0
++
++#define CFG_NUM_DATA_BLOCKS			0x6d0
++
++#define CFG_META_DATA_SIZE			0x6e0
++
++#define DMA_ENABLE				0x700
++#define     DMA_ENABLE__FLAG				BIT(0)
++
++#define IGNORE_ECC_DONE				0x710
++#define     IGNORE_ECC_DONE__FLAG			BIT(0)
++
++#define DMA_INTR				0x720
++#define DMA_INTR_EN				0x730
++#define     DMA_INTR__TARGET_ERROR			BIT(0)
++#define     DMA_INTR__DESC_COMP_CHANNEL0		BIT(1)
++#define     DMA_INTR__DESC_COMP_CHANNEL1		BIT(2)
++#define     DMA_INTR__DESC_COMP_CHANNEL2		BIT(3)
++#define     DMA_INTR__DESC_COMP_CHANNEL3		BIT(4)
++#define     DMA_INTR__MEMCOPY_DESC_COMP			BIT(5)
++
++#define TARGET_ERR_ADDR_LO			0x740
++#define     TARGET_ERR_ADDR_LO__VALUE			GENMASK(15, 0)
++
++#define TARGET_ERR_ADDR_HI			0x750
++#define     TARGET_ERR_ADDR_HI__VALUE			GENMASK(15, 0)
++
++#define CHNL_ACTIVE				0x760
++#define     CHNL_ACTIVE__CHANNEL0			BIT(0)
++#define     CHNL_ACTIVE__CHANNEL1			BIT(1)
++#define     CHNL_ACTIVE__CHANNEL2			BIT(2)
++#define     CHNL_ACTIVE__CHANNEL3			BIT(3)
++
++struct denali_nand_info {
++	struct nand_chip nand;
++	unsigned long clk_x_rate;	/* bus interface clock rate */
++	int active_bank;		/* currently selected bank */
++	struct device *dev;
++	void __iomem *reg;		/* Register Interface */
++	void __iomem *host;		/* Host Data/Command Interface */
++
++	/* elements used by ISR */
++	struct completion complete;
++	spinlock_t irq_lock;
++	uint32_t irq_mask;
++	uint32_t irq_status;
++	int irq;
++
++	void *buf;
++	dma_addr_t dma_addr;
++	int dma_avail;
++	int devs_per_cs;		/* devices connected in parallel */
++	int oob_skip_bytes;
++	int max_banks;
++	unsigned int revision;
++	unsigned int caps;
++	const struct nand_ecc_caps *ecc_caps;
++};
++
++#define DENALI_CAP_HW_ECC_FIXUP			BIT(0)
++#define DENALI_CAP_DMA_64BIT			BIT(1)
++
++int denali_calc_ecc_bytes(int step_size, int strength);
++extern int denali_init(struct denali_nand_info *denali);
++extern void denali_remove(struct denali_nand_info *denali);
++
++#endif /* __DENALI_H__ */
+diff --git a/drivers/mtd/nand/raw/denali_dt.c b/drivers/mtd/nand/raw/denali_dt.c
+new file mode 100644
+index 0000000..56e2e17
+--- /dev/null
++++ b/drivers/mtd/nand/raw/denali_dt.c
+@@ -0,0 +1,163 @@
++/*
++ * NAND Flash Controller Device Driver for DT
++ *
++ * Copyright © 2011, Picochip.
++ *
++ * 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.
++ */
++#include <linux/clk.h>
++#include <linux/err.h>
++#include <linux/io.h>
++#include <linux/ioport.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/of.h>
++#include <linux/of_device.h>
++
++#include "denali.h"
++
++struct denali_dt {
++	struct denali_nand_info	denali;
++	struct clk		*clk;
++};
++
++struct denali_dt_data {
++	unsigned int revision;
++	unsigned int caps;
++	const struct nand_ecc_caps *ecc_caps;
++};
++
++NAND_ECC_CAPS_SINGLE(denali_socfpga_ecc_caps, denali_calc_ecc_bytes,
++		     512, 8, 15);
++static const struct denali_dt_data denali_socfpga_data = {
++	.caps = DENALI_CAP_HW_ECC_FIXUP,
++	.ecc_caps = &denali_socfpga_ecc_caps,
++};
++
++NAND_ECC_CAPS_SINGLE(denali_uniphier_v5a_ecc_caps, denali_calc_ecc_bytes,
++		     1024, 8, 16, 24);
++static const struct denali_dt_data denali_uniphier_v5a_data = {
++	.caps = DENALI_CAP_HW_ECC_FIXUP |
++		DENALI_CAP_DMA_64BIT,
++	.ecc_caps = &denali_uniphier_v5a_ecc_caps,
++};
++
++NAND_ECC_CAPS_SINGLE(denali_uniphier_v5b_ecc_caps, denali_calc_ecc_bytes,
++		     1024, 8, 16);
++static const struct denali_dt_data denali_uniphier_v5b_data = {
++	.revision = 0x0501,
++	.caps = DENALI_CAP_HW_ECC_FIXUP |
++		DENALI_CAP_DMA_64BIT,
++	.ecc_caps = &denali_uniphier_v5b_ecc_caps,
++};
++
++static const struct of_device_id denali_nand_dt_ids[] = {
++	{
++		.compatible = "altr,socfpga-denali-nand",
++		.data = &denali_socfpga_data,
++	},
++	{
++		.compatible = "socionext,uniphier-denali-nand-v5a",
++		.data = &denali_uniphier_v5a_data,
++	},
++	{
++		.compatible = "socionext,uniphier-denali-nand-v5b",
++		.data = &denali_uniphier_v5b_data,
++	},
++	{ /* sentinel */ }
++};
++MODULE_DEVICE_TABLE(of, denali_nand_dt_ids);
++
++static int denali_dt_probe(struct platform_device *pdev)
++{
++	struct resource *res;
++	struct denali_dt *dt;
++	const struct denali_dt_data *data;
++	struct denali_nand_info *denali;
++	int ret;
++
++	dt = devm_kzalloc(&pdev->dev, sizeof(*dt), GFP_KERNEL);
++	if (!dt)
++		return -ENOMEM;
++	denali = &dt->denali;
++
++	data = of_device_get_match_data(&pdev->dev);
++	if (data) {
++		denali->revision = data->revision;
++		denali->caps = data->caps;
++		denali->ecc_caps = data->ecc_caps;
++	}
++
++	denali->dev = &pdev->dev;
++	denali->irq = platform_get_irq(pdev, 0);
++	if (denali->irq < 0) {
++		dev_err(&pdev->dev, "no irq defined\n");
++		return denali->irq;
++	}
++
++	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "denali_reg");
++	denali->reg = devm_ioremap_resource(&pdev->dev, res);
++	if (IS_ERR(denali->reg))
++		return PTR_ERR(denali->reg);
++
++	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_data");
++	denali->host = devm_ioremap_resource(&pdev->dev, res);
++	if (IS_ERR(denali->host))
++		return PTR_ERR(denali->host);
++
++	dt->clk = devm_clk_get(&pdev->dev, NULL);
++	if (IS_ERR(dt->clk)) {
++		dev_err(&pdev->dev, "no clk available\n");
++		return PTR_ERR(dt->clk);
++	}
++	ret = clk_prepare_enable(dt->clk);
++	if (ret)
++		return ret;
++
++	denali->clk_x_rate = clk_get_rate(dt->clk);
++
++	ret = denali_init(denali);
++	if (ret)
++		goto out_disable_clk;
++
++	platform_set_drvdata(pdev, dt);
++	return 0;
++
++out_disable_clk:
++	clk_disable_unprepare(dt->clk);
++
++	return ret;
++}
++
++static int denali_dt_remove(struct platform_device *pdev)
++{
++	struct denali_dt *dt = platform_get_drvdata(pdev);
++
++	denali_remove(&dt->denali);
++	clk_disable_unprepare(dt->clk);
++
++	return 0;
++}
++
++static struct platform_driver denali_dt_driver = {
++	.probe		= denali_dt_probe,
++	.remove		= denali_dt_remove,
++	.driver		= {
++		.name	= "denali-nand-dt",
++		.of_match_table	= denali_nand_dt_ids,
++	},
++};
++
++module_platform_driver(denali_dt_driver);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Jamie Iles");
++MODULE_DESCRIPTION("DT driver for Denali NAND controller");
+diff --git a/drivers/mtd/nand/raw/denali_pci.c b/drivers/mtd/nand/raw/denali_pci.c
+new file mode 100644
+index 0000000..81370c7
+--- /dev/null
++++ b/drivers/mtd/nand/raw/denali_pci.c
+@@ -0,0 +1,126 @@
++/*
++ * NAND Flash Controller Device Driver
++ * Copyright © 2009-2010, Intel Corporation and its suppliers.
++ *
++ * 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.
++ */
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++
++#include "denali.h"
++
++#define DENALI_NAND_NAME    "denali-nand-pci"
++
++#define INTEL_CE4100	1
++#define INTEL_MRST	2
++
++/* List of platforms this NAND controller has be integrated into */
++static const struct pci_device_id denali_pci_ids[] = {
++	{ PCI_VDEVICE(INTEL, 0x0701), INTEL_CE4100 },
++	{ PCI_VDEVICE(INTEL, 0x0809), INTEL_MRST },
++	{ /* end: all zeroes */ }
++};
++MODULE_DEVICE_TABLE(pci, denali_pci_ids);
++
++NAND_ECC_CAPS_SINGLE(denali_pci_ecc_caps, denali_calc_ecc_bytes, 512, 8, 15);
++
++static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
++{
++	int ret;
++	resource_size_t csr_base, mem_base;
++	unsigned long csr_len, mem_len;
++	struct denali_nand_info *denali;
++
++	denali = devm_kzalloc(&dev->dev, sizeof(*denali), GFP_KERNEL);
++	if (!denali)
++		return -ENOMEM;
++
++	ret = pcim_enable_device(dev);
++	if (ret) {
++		dev_err(&dev->dev, "Spectra: pci_enable_device failed.\n");
++		return ret;
++	}
++
++	if (id->driver_data == INTEL_CE4100) {
++		mem_base = pci_resource_start(dev, 0);
++		mem_len = pci_resource_len(dev, 1);
++		csr_base = pci_resource_start(dev, 1);
++		csr_len = pci_resource_len(dev, 1);
++	} else {
++		csr_base = pci_resource_start(dev, 0);
++		csr_len = pci_resource_len(dev, 0);
++		mem_base = pci_resource_start(dev, 1);
++		mem_len = pci_resource_len(dev, 1);
++		if (!mem_len) {
++			mem_base = csr_base + csr_len;
++			mem_len = csr_len;
++		}
++	}
++
++	pci_set_master(dev);
++	denali->dev = &dev->dev;
++	denali->irq = dev->irq;
++	denali->ecc_caps = &denali_pci_ecc_caps;
++	denali->nand.ecc.options |= NAND_ECC_MAXIMIZE;
++	denali->clk_x_rate = 200000000;		/* 200 MHz */
++
++	ret = pci_request_regions(dev, DENALI_NAND_NAME);
++	if (ret) {
++		dev_err(&dev->dev, "Spectra: Unable to request memory regions\n");
++		return ret;
++	}
++
++	denali->reg = ioremap_nocache(csr_base, csr_len);
++	if (!denali->reg) {
++		dev_err(&dev->dev, "Spectra: Unable to remap memory region\n");
++		return -ENOMEM;
++	}
++
++	denali->host = ioremap_nocache(mem_base, mem_len);
++	if (!denali->host) {
++		dev_err(&dev->dev, "Spectra: ioremap_nocache failed!");
++		ret = -ENOMEM;
++		goto failed_remap_reg;
++	}
++
++	ret = denali_init(denali);
++	if (ret)
++		goto failed_remap_mem;
++
++	pci_set_drvdata(dev, denali);
++
++	return 0;
++
++failed_remap_mem:
++	iounmap(denali->host);
++failed_remap_reg:
++	iounmap(denali->reg);
++	return ret;
++}
++
++/* driver exit point */
++static void denali_pci_remove(struct pci_dev *dev)
++{
++	struct denali_nand_info *denali = pci_get_drvdata(dev);
++
++	denali_remove(denali);
++	iounmap(denali->reg);
++	iounmap(denali->host);
++}
++
++static struct pci_driver denali_pci_driver = {
++	.name = DENALI_NAND_NAME,
++	.id_table = denali_pci_ids,
++	.probe = denali_pci_probe,
++	.remove = denali_pci_remove,
++};
++
++module_pci_driver(denali_pci_driver);
+diff --git a/drivers/mtd/nand/raw/diskonchip.c b/drivers/mtd/nand/raw/diskonchip.c
+new file mode 100644
+index 0000000..c3aa53c
+--- /dev/null
++++ b/drivers/mtd/nand/raw/diskonchip.c
+@@ -0,0 +1,1712 @@
++/*
++ * drivers/mtd/nand/diskonchip.c
++ *
++ * (C) 2003 Red Hat, Inc.
++ * (C) 2004 Dan Brown <dan_brown@ieee.org>
++ * (C) 2004 Kalev Lember <kalev@smartlink.ee>
++ *
++ * Author: David Woodhouse <dwmw2@infradead.org>
++ * Additional Diskonchip 2000 and Millennium support by Dan Brown <dan_brown@ieee.org>
++ * Diskonchip Millennium Plus support by Kalev Lember <kalev@smartlink.ee>
++ *
++ * Error correction code lifted from the old docecc code
++ * Author: Fabrice Bellard (fabrice.bellard@netgem.com)
++ * Copyright (C) 2000 Netgem S.A.
++ * converted to the generic Reed-Solomon library by Thomas Gleixner <tglx@linutronix.de>
++ *
++ * Interface to generic NAND code for M-Systems DiskOnChip devices
++ */
++
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/sched.h>
++#include <linux/delay.h>
++#include <linux/rslib.h>
++#include <linux/moduleparam.h>
++#include <linux/slab.h>
++#include <linux/io.h>
++
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/rawnand.h>
++#include <linux/mtd/doc2000.h>
++#include <linux/mtd/partitions.h>
++#include <linux/mtd/inftl.h>
++#include <linux/module.h>
++
++/* Where to look for the devices? */
++#ifndef CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS
++#define CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS 0
++#endif
++
++static unsigned long doc_locations[] __initdata = {
++#if defined (__alpha__) || defined(__i386__) || defined(__x86_64__)
++#ifdef CONFIG_MTD_NAND_DISKONCHIP_PROBE_HIGH
++	0xfffc8000, 0xfffca000, 0xfffcc000, 0xfffce000,
++	0xfffd0000, 0xfffd2000, 0xfffd4000, 0xfffd6000,
++	0xfffd8000, 0xfffda000, 0xfffdc000, 0xfffde000,
++	0xfffe0000, 0xfffe2000, 0xfffe4000, 0xfffe6000,
++	0xfffe8000, 0xfffea000, 0xfffec000, 0xfffee000,
++#else
++	0xc8000, 0xca000, 0xcc000, 0xce000,
++	0xd0000, 0xd2000, 0xd4000, 0xd6000,
++	0xd8000, 0xda000, 0xdc000, 0xde000,
++	0xe0000, 0xe2000, 0xe4000, 0xe6000,
++	0xe8000, 0xea000, 0xec000, 0xee000,
++#endif
++#endif
++	0xffffffff };
++
++static struct mtd_info *doclist = NULL;
++
++struct doc_priv {
++	void __iomem *virtadr;
++	unsigned long physadr;
++	u_char ChipID;
++	u_char CDSNControl;
++	int chips_per_floor;	/* The number of chips detected on each floor */
++	int curfloor;
++	int curchip;
++	int mh0_page;
++	int mh1_page;
++	struct mtd_info *nextdoc;
++
++	/* Handle the last stage of initialization (BBT scan, partitioning) */
++	int (*late_init)(struct mtd_info *mtd);
++};
++
++/* This is the ecc value computed by the HW ecc generator upon writing an empty
++   page, one with all 0xff for data. */
++static u_char empty_write_ecc[6] = { 0x4b, 0x00, 0xe2, 0x0e, 0x93, 0xf7 };
++
++#define INFTL_BBT_RESERVED_BLOCKS 4
++
++#define DoC_is_MillenniumPlus(doc) ((doc)->ChipID == DOC_ChipID_DocMilPlus16 || (doc)->ChipID == DOC_ChipID_DocMilPlus32)
++#define DoC_is_Millennium(doc) ((doc)->ChipID == DOC_ChipID_DocMil)
++#define DoC_is_2000(doc) ((doc)->ChipID == DOC_ChipID_Doc2k)
++
++static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd,
++			      unsigned int bitmask);
++static void doc200x_select_chip(struct mtd_info *mtd, int chip);
++
++static int debug = 0;
++module_param(debug, int, 0);
++
++static int try_dword = 1;
++module_param(try_dword, int, 0);
++
++static int no_ecc_failures = 0;
++module_param(no_ecc_failures, int, 0);
++
++static int no_autopart = 0;
++module_param(no_autopart, int, 0);
++
++static int show_firmware_partition = 0;
++module_param(show_firmware_partition, int, 0);
++
++#ifdef CONFIG_MTD_NAND_DISKONCHIP_BBTWRITE
++static int inftl_bbt_write = 1;
++#else
++static int inftl_bbt_write = 0;
++#endif
++module_param(inftl_bbt_write, int, 0);
++
++static unsigned long doc_config_location = CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS;
++module_param(doc_config_location, ulong, 0);
++MODULE_PARM_DESC(doc_config_location, "Physical memory address at which to probe for DiskOnChip");
++
++/* Sector size for HW ECC */
++#define SECTOR_SIZE 512
++/* The sector bytes are packed into NB_DATA 10 bit words */
++#define NB_DATA (((SECTOR_SIZE + 1) * 8 + 6) / 10)
++/* Number of roots */
++#define NROOTS 4
++/* First consective root */
++#define FCR 510
++/* Number of symbols */
++#define NN 1023
++
++/* the Reed Solomon control structure */
++static struct rs_control *rs_decoder;
++
++/*
++ * The HW decoder in the DoC ASIC's provides us a error syndrome,
++ * which we must convert to a standard syndrome usable by the generic
++ * Reed-Solomon library code.
++ *
++ * Fabrice Bellard figured this out in the old docecc code. I added
++ * some comments, improved a minor bit and converted it to make use
++ * of the generic Reed-Solomon library. tglx
++ */
++static int doc_ecc_decode(struct rs_control *rs, uint8_t *data, uint8_t *ecc)
++{
++	int i, j, nerr, errpos[8];
++	uint8_t parity;
++	uint16_t ds[4], s[5], tmp, errval[8], syn[4];
++
++	memset(syn, 0, sizeof(syn));
++	/* Convert the ecc bytes into words */
++	ds[0] = ((ecc[4] & 0xff) >> 0) | ((ecc[5] & 0x03) << 8);
++	ds[1] = ((ecc[5] & 0xfc) >> 2) | ((ecc[2] & 0x0f) << 6);
++	ds[2] = ((ecc[2] & 0xf0) >> 4) | ((ecc[3] & 0x3f) << 4);
++	ds[3] = ((ecc[3] & 0xc0) >> 6) | ((ecc[0] & 0xff) << 2);
++	parity = ecc[1];
++
++	/* Initialize the syndrome buffer */
++	for (i = 0; i < NROOTS; i++)
++		s[i] = ds[0];
++	/*
++	 *  Evaluate
++	 *  s[i] = ds[3]x^3 + ds[2]x^2 + ds[1]x^1 + ds[0]
++	 *  where x = alpha^(FCR + i)
++	 */
++	for (j = 1; j < NROOTS; j++) {
++		if (ds[j] == 0)
++			continue;
++		tmp = rs->index_of[ds[j]];
++		for (i = 0; i < NROOTS; i++)
++			s[i] ^= rs->alpha_to[rs_modnn(rs, tmp + (FCR + i) * j)];
++	}
++
++	/* Calc syn[i] = s[i] / alpha^(v + i) */
++	for (i = 0; i < NROOTS; i++) {
++		if (s[i])
++			syn[i] = rs_modnn(rs, rs->index_of[s[i]] + (NN - FCR - i));
++	}
++	/* Call the decoder library */
++	nerr = decode_rs16(rs, NULL, NULL, 1019, syn, 0, errpos, 0, errval);
++
++	/* Incorrectable errors ? */
++	if (nerr < 0)
++		return nerr;
++
++	/*
++	 * Correct the errors. The bitpositions are a bit of magic,
++	 * but they are given by the design of the de/encoder circuit
++	 * in the DoC ASIC's.
++	 */
++	for (i = 0; i < nerr; i++) {
++		int index, bitpos, pos = 1015 - errpos[i];
++		uint8_t val;
++		if (pos >= NB_DATA && pos < 1019)
++			continue;
++		if (pos < NB_DATA) {
++			/* extract bit position (MSB first) */
++			pos = 10 * (NB_DATA - 1 - pos) - 6;
++			/* now correct the following 10 bits. At most two bytes
++			   can be modified since pos is even */
++			index = (pos >> 3) ^ 1;
++			bitpos = pos & 7;
++			if ((index >= 0 && index < SECTOR_SIZE) || index == (SECTOR_SIZE + 1)) {
++				val = (uint8_t) (errval[i] >> (2 + bitpos));
++				parity ^= val;
++				if (index < SECTOR_SIZE)
++					data[index] ^= val;
++			}
++			index = ((pos >> 3) + 1) ^ 1;
++			bitpos = (bitpos + 10) & 7;
++			if (bitpos == 0)
++				bitpos = 8;
++			if ((index >= 0 && index < SECTOR_SIZE) || index == (SECTOR_SIZE + 1)) {
++				val = (uint8_t) (errval[i] << (8 - bitpos));
++				parity ^= val;
++				if (index < SECTOR_SIZE)
++					data[index] ^= val;
++			}
++		}
++	}
++	/* If the parity is wrong, no rescue possible */
++	return parity ? -EBADMSG : nerr;
++}
++
++static void DoC_Delay(struct doc_priv *doc, unsigned short cycles)
++{
++	volatile char dummy;
++	int i;
++
++	for (i = 0; i < cycles; i++) {
++		if (DoC_is_Millennium(doc))
++			dummy = ReadDOC(doc->virtadr, NOP);
++		else if (DoC_is_MillenniumPlus(doc))
++			dummy = ReadDOC(doc->virtadr, Mplus_NOP);
++		else
++			dummy = ReadDOC(doc->virtadr, DOCStatus);
++	}
++
++}
++
++#define CDSN_CTRL_FR_B_MASK	(CDSN_CTRL_FR_B0 | CDSN_CTRL_FR_B1)
++
++/* DOC_WaitReady: Wait for RDY line to be asserted by the flash chip */
++static int _DoC_WaitReady(struct doc_priv *doc)
++{
++	void __iomem *docptr = doc->virtadr;
++	unsigned long timeo = jiffies + (HZ * 10);
++
++	if (debug)
++		printk("_DoC_WaitReady...\n");
++	/* Out-of-line routine to wait for chip response */
++	if (DoC_is_MillenniumPlus(doc)) {
++		while ((ReadDOC(docptr, Mplus_FlashControl) & CDSN_CTRL_FR_B_MASK) != CDSN_CTRL_FR_B_MASK) {
++			if (time_after(jiffies, timeo)) {
++				printk("_DoC_WaitReady timed out.\n");
++				return -EIO;
++			}
++			udelay(1);
++			cond_resched();
++		}
++	} else {
++		while (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B)) {
++			if (time_after(jiffies, timeo)) {
++				printk("_DoC_WaitReady timed out.\n");
++				return -EIO;
++			}
++			udelay(1);
++			cond_resched();
++		}
++	}
++
++	return 0;
++}
++
++static inline int DoC_WaitReady(struct doc_priv *doc)
++{
++	void __iomem *docptr = doc->virtadr;
++	int ret = 0;
++
++	if (DoC_is_MillenniumPlus(doc)) {
++		DoC_Delay(doc, 4);
++
++		if ((ReadDOC(docptr, Mplus_FlashControl) & CDSN_CTRL_FR_B_MASK) != CDSN_CTRL_FR_B_MASK)
++			/* Call the out-of-line routine to wait */
++			ret = _DoC_WaitReady(doc);
++	} else {
++		DoC_Delay(doc, 4);
++
++		if (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B))
++			/* Call the out-of-line routine to wait */
++			ret = _DoC_WaitReady(doc);
++		DoC_Delay(doc, 2);
++	}
++
++	if (debug)
++		printk("DoC_WaitReady OK\n");
++	return ret;
++}
++
++static void doc2000_write_byte(struct mtd_info *mtd, u_char datum)
++{
++	struct nand_chip *this = mtd_to_nand(mtd);
++	struct doc_priv *doc = nand_get_controller_data(this);
++	void __iomem *docptr = doc->virtadr;
++
++	if (debug)
++		printk("write_byte %02x\n", datum);
++	WriteDOC(datum, docptr, CDSNSlowIO);
++	WriteDOC(datum, docptr, 2k_CDSN_IO);
++}
++
++static u_char doc2000_read_byte(struct mtd_info *mtd)
++{
++	struct nand_chip *this = mtd_to_nand(mtd);
++	struct doc_priv *doc = nand_get_controller_data(this);
++	void __iomem *docptr = doc->virtadr;
++	u_char ret;
++
++	ReadDOC(docptr, CDSNSlowIO);
++	DoC_Delay(doc, 2);
++	ret = ReadDOC(docptr, 2k_CDSN_IO);
++	if (debug)
++		printk("read_byte returns %02x\n", ret);
++	return ret;
++}
++
++static void doc2000_writebuf(struct mtd_info *mtd, const u_char *buf, int len)
++{
++	struct nand_chip *this = mtd_to_nand(mtd);
++	struct doc_priv *doc = nand_get_controller_data(this);
++	void __iomem *docptr = doc->virtadr;
++	int i;
++	if (debug)
++		printk("writebuf of %d bytes: ", len);
++	for (i = 0; i < len; i++) {
++		WriteDOC_(buf[i], docptr, DoC_2k_CDSN_IO + i);
++		if (debug && i < 16)
++			printk("%02x ", buf[i]);
++	}
++	if (debug)
++		printk("\n");
++}
++
++static void doc2000_readbuf(struct mtd_info *mtd, u_char *buf, int len)
++{
++	struct nand_chip *this = mtd_to_nand(mtd);
++	struct doc_priv *doc = nand_get_controller_data(this);
++	void __iomem *docptr = doc->virtadr;
++	int i;
++
++	if (debug)
++		printk("readbuf of %d bytes: ", len);
++
++	for (i = 0; i < len; i++) {
++		buf[i] = ReadDOC(docptr, 2k_CDSN_IO + i);
++	}
++}
++
++static void doc2000_readbuf_dword(struct mtd_info *mtd, u_char *buf, int len)
++{
++	struct nand_chip *this = mtd_to_nand(mtd);
++	struct doc_priv *doc = nand_get_controller_data(this);
++	void __iomem *docptr = doc->virtadr;
++	int i;
++
++	if (debug)
++		printk("readbuf_dword of %d bytes: ", len);
++
++	if (unlikely((((unsigned long)buf) | len) & 3)) {
++		for (i = 0; i < len; i++) {
++			*(uint8_t *) (&buf[i]) = ReadDOC(docptr, 2k_CDSN_IO + i);
++		}
++	} else {
++		for (i = 0; i < len; i += 4) {
++			*(uint32_t *) (&buf[i]) = readl(docptr + DoC_2k_CDSN_IO + i);
++		}
++	}
++}
++
++static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr)
++{
++	struct nand_chip *this = mtd_to_nand(mtd);
++	struct doc_priv *doc = nand_get_controller_data(this);
++	uint16_t ret;
++
++	doc200x_select_chip(mtd, nr);
++	doc200x_hwcontrol(mtd, NAND_CMD_READID,
++			  NAND_CTRL_CLE | NAND_CTRL_CHANGE);
++	doc200x_hwcontrol(mtd, 0, NAND_CTRL_ALE | NAND_CTRL_CHANGE);
++	doc200x_hwcontrol(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
++
++	/* We can't use dev_ready here, but at least we wait for the
++	 * command to complete
++	 */
++	udelay(50);
++
++	ret = this->read_byte(mtd) << 8;
++	ret |= this->read_byte(mtd);
++
++	if (doc->ChipID == DOC_ChipID_Doc2k && try_dword && !nr) {
++		/* First chip probe. See if we get same results by 32-bit access */
++		union {
++			uint32_t dword;
++			uint8_t byte[4];
++		} ident;
++		void __iomem *docptr = doc->virtadr;
++
++		doc200x_hwcontrol(mtd, NAND_CMD_READID,
++				  NAND_CTRL_CLE | NAND_CTRL_CHANGE);
++		doc200x_hwcontrol(mtd, 0, NAND_CTRL_ALE | NAND_CTRL_CHANGE);
++		doc200x_hwcontrol(mtd, NAND_CMD_NONE,
++				  NAND_NCE | NAND_CTRL_CHANGE);
++
++		udelay(50);
++
++		ident.dword = readl(docptr + DoC_2k_CDSN_IO);
++		if (((ident.byte[0] << 8) | ident.byte[1]) == ret) {
++			printk(KERN_INFO "DiskOnChip 2000 responds to DWORD access\n");
++			this->read_buf = &doc2000_readbuf_dword;
++		}
++	}
++
++	return ret;
++}
++
++static void __init doc2000_count_chips(struct mtd_info *mtd)
++{
++	struct nand_chip *this = mtd_to_nand(mtd);
++	struct doc_priv *doc = nand_get_controller_data(this);
++	uint16_t mfrid;
++	int i;
++
++	/* Max 4 chips per floor on DiskOnChip 2000 */
++	doc->chips_per_floor = 4;
++
++	/* Find out what the first chip is */
++	mfrid = doc200x_ident_chip(mtd, 0);
++
++	/* Find how many chips in each floor. */
++	for (i = 1; i < 4; i++) {
++		if (doc200x_ident_chip(mtd, i) != mfrid)
++			break;
++	}
++	doc->chips_per_floor = i;
++	printk(KERN_DEBUG "Detected %d chips per floor.\n", i);
++}
++
++static int doc200x_wait(struct mtd_info *mtd, struct nand_chip *this)
++{
++	struct doc_priv *doc = nand_get_controller_data(this);
++
++	int status;
++
++	DoC_WaitReady(doc);
++	this->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
++	DoC_WaitReady(doc);
++	status = (int)this->read_byte(mtd);
++
++	return status;
++}
++
++static void doc2001_write_byte(struct mtd_info *mtd, u_char datum)
++{
++	struct nand_chip *this = mtd_to_nand(mtd);
++	struct doc_priv *doc = nand_get_controller_data(this);
++	void __iomem *docptr = doc->virtadr;
++
++	WriteDOC(datum, docptr, CDSNSlowIO);
++	WriteDOC(datum, docptr, Mil_CDSN_IO);
++	WriteDOC(datum, docptr, WritePipeTerm);
++}
++
++static u_char doc2001_read_byte(struct mtd_info *mtd)
++{
++	struct nand_chip *this = mtd_to_nand(mtd);
++	struct doc_priv *doc = nand_get_controller_data(this);
++	void __iomem *docptr = doc->virtadr;
++
++	//ReadDOC(docptr, CDSNSlowIO);
++	/* 11.4.5 -- delay twice to allow extended length cycle */
++	DoC_Delay(doc, 2);
++	ReadDOC(docptr, ReadPipeInit);
++	//return ReadDOC(docptr, Mil_CDSN_IO);
++	return ReadDOC(docptr, LastDataRead);
++}
++
++static void doc2001_writebuf(struct mtd_info *mtd, const u_char *buf, int len)
++{
++	struct nand_chip *this = mtd_to_nand(mtd);
++	struct doc_priv *doc = nand_get_controller_data(this);
++	void __iomem *docptr = doc->virtadr;
++	int i;
++
++	for (i = 0; i < len; i++)
++		WriteDOC_(buf[i], docptr, DoC_Mil_CDSN_IO + i);
++	/* Terminate write pipeline */
++	WriteDOC(0x00, docptr, WritePipeTerm);
++}
++
++static void doc2001_readbuf(struct mtd_info *mtd, u_char *buf, int len)
++{
++	struct nand_chip *this = mtd_to_nand(mtd);
++	struct doc_priv *doc = nand_get_controller_data(this);
++	void __iomem *docptr = doc->virtadr;
++	int i;
++
++	/* Start read pipeline */
++	ReadDOC(docptr, ReadPipeInit);
++
++	for (i = 0; i < len - 1; i++)
++		buf[i] = ReadDOC(docptr, Mil_CDSN_IO + (i & 0xff));
++
++	/* Terminate read pipeline */
++	buf[i] = ReadDOC(docptr, LastDataRead);
++}
++
++static u_char doc2001plus_read_byte(struct mtd_info *mtd)
++{
++	struct nand_chip *this = mtd_to_nand(mtd);
++	struct doc_priv *doc = nand_get_controller_data(this);
++	void __iomem *docptr = doc->virtadr;
++	u_char ret;
++
++	ReadDOC(docptr, Mplus_ReadPipeInit);
++	ReadDOC(docptr, Mplus_ReadPipeInit);
++	ret = ReadDOC(docptr, Mplus_LastDataRead);
++	if (debug)
++		printk("read_byte returns %02x\n", ret);
++	return ret;
++}
++
++static void doc2001plus_writebuf(struct mtd_info *mtd, const u_char *buf, int len)
++{
++	struct nand_chip *this = mtd_to_nand(mtd);
++	struct doc_priv *doc = nand_get_controller_data(this);
++	void __iomem *docptr = doc->virtadr;
++	int i;
++
++	if (debug)
++		printk("writebuf of %d bytes: ", len);
++	for (i = 0; i < len; i++) {
++		WriteDOC_(buf[i], docptr, DoC_Mil_CDSN_IO + i);
++		if (debug && i < 16)
++			printk("%02x ", buf[i]);
++	}
++	if (debug)
++		printk("\n");
++}
++
++static void doc2001plus_readbuf(struct mtd_info *mtd, u_char *buf, int len)
++{
++	struct nand_chip *this = mtd_to_nand(mtd);
++	struct doc_priv *doc = nand_get_controller_data(this);
++	void __iomem *docptr = doc->virtadr;
++	int i;
++
++	if (debug)
++		printk("readbuf of %d bytes: ", len);
++
++	/* Start read pipeline */
++	ReadDOC(docptr, Mplus_ReadPipeInit);
++	ReadDOC(docptr, Mplus_ReadPipeInit);
++
++	for (i = 0; i < len - 2; i++) {
++		buf[i] = ReadDOC(docptr, Mil_CDSN_IO);
++		if (debug && i < 16)
++			printk("%02x ", buf[i]);
++	}
++
++	/* Terminate read pipeline */
++	buf[len - 2] = ReadDOC(docptr, Mplus_LastDataRead);
++	if (debug && i < 16)
++		printk("%02x ", buf[len - 2]);
++	buf[len - 1] = ReadDOC(docptr, Mplus_LastDataRead);
++	if (debug && i < 16)
++		printk("%02x ", buf[len - 1]);
++	if (debug)
++		printk("\n");
++}
++
++static void doc2001plus_select_chip(struct mtd_info *mtd, int chip)
++{
++	struct nand_chip *this = mtd_to_nand(mtd);
++	struct doc_priv *doc = nand_get_controller_data(this);
++	void __iomem *docptr = doc->virtadr;
++	int floor = 0;
++
++	if (debug)
++		printk("select chip (%d)\n", chip);
++
++	if (chip == -1) {
++		/* Disable flash internally */
++		WriteDOC(0, docptr, Mplus_FlashSelect);
++		return;
++	}
++
++	floor = chip / doc->chips_per_floor;
++	chip -= (floor * doc->chips_per_floor);
++
++	/* Assert ChipEnable and deassert WriteProtect */
++	WriteDOC((DOC_FLASH_CE), docptr, Mplus_FlashSelect);
++	this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
++
++	doc->curchip = chip;
++	doc->curfloor = floor;
++}
++
++static void doc200x_select_chip(struct mtd_info *mtd, int chip)
++{
++	struct nand_chip *this = mtd_to_nand(mtd);
++	struct doc_priv *doc = nand_get_controller_data(this);
++	void __iomem *docptr = doc->virtadr;
++	int floor = 0;
++
++	if (debug)
++		printk("select chip (%d)\n", chip);
++
++	if (chip == -1)
++		return;
++
++	floor = chip / doc->chips_per_floor;
++	chip -= (floor * doc->chips_per_floor);
++
++	/* 11.4.4 -- deassert CE before changing chip */
++	doc200x_hwcontrol(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE);
++
++	WriteDOC(floor, docptr, FloorSelect);
++	WriteDOC(chip, docptr, CDSNDeviceSelect);
++
++	doc200x_hwcontrol(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
++
++	doc->curchip = chip;
++	doc->curfloor = floor;
++}
++
++#define CDSN_CTRL_MSK (CDSN_CTRL_CE | CDSN_CTRL_CLE | CDSN_CTRL_ALE)
++
++static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd,
++			      unsigned int ctrl)
++{
++	struct nand_chip *this = mtd_to_nand(mtd);
++	struct doc_priv *doc = nand_get_controller_data(this);
++	void __iomem *docptr = doc->virtadr;
++
++	if (ctrl & NAND_CTRL_CHANGE) {
++		doc->CDSNControl &= ~CDSN_CTRL_MSK;
++		doc->CDSNControl |= ctrl & CDSN_CTRL_MSK;
++		if (debug)
++			printk("hwcontrol(%d): %02x\n", cmd, doc->CDSNControl);
++		WriteDOC(doc->CDSNControl, docptr, CDSNControl);
++		/* 11.4.3 -- 4 NOPs after CSDNControl write */
++		DoC_Delay(doc, 4);
++	}
++	if (cmd != NAND_CMD_NONE) {
++		if (DoC_is_2000(doc))
++			doc2000_write_byte(mtd, cmd);
++		else
++			doc2001_write_byte(mtd, 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 doc_priv *doc = nand_get_controller_data(this);
++	void __iomem *docptr = doc->virtadr;
++
++	/*
++	 * Must terminate write pipeline before sending any commands
++	 * to the device.
++	 */
++	if (command == NAND_CMD_PAGEPROG) {
++		WriteDOC(0x00, docptr, Mplus_WritePipeTerm);
++		WriteDOC(0x00, docptr, Mplus_WritePipeTerm);
++	}
++
++	/*
++	 * Write out the command to the device.
++	 */
++	if (command == NAND_CMD_SEQIN) {
++		int readcmd;
++
++		if (column >= mtd->writesize) {
++			/* OOB area */
++			column -= mtd->writesize;
++			readcmd = NAND_CMD_READOOB;
++		} else if (column < 256) {
++			/* First 256 bytes --> READ0 */
++			readcmd = NAND_CMD_READ0;
++		} else {
++			column -= 256;
++			readcmd = NAND_CMD_READ1;
++		}
++		WriteDOC(readcmd, docptr, Mplus_FlashCmd);
++	}
++	WriteDOC(command, docptr, Mplus_FlashCmd);
++	WriteDOC(0, docptr, Mplus_WritePipeTerm);
++	WriteDOC(0, docptr, Mplus_WritePipeTerm);
++
++	if (column != -1 || page_addr != -1) {
++		/* Serially input address */
++		if (column != -1) {
++			/* Adjust columns for 16 bit buswidth */
++			if (this->options & NAND_BUSWIDTH_16 &&
++					!nand_opcode_8bits(command))
++				column >>= 1;
++			WriteDOC(column, docptr, Mplus_FlashAddress);
++		}
++		if (page_addr != -1) {
++			WriteDOC((unsigned char)(page_addr & 0xff), docptr, Mplus_FlashAddress);
++			WriteDOC((unsigned char)((page_addr >> 8) & 0xff), docptr, Mplus_FlashAddress);
++			/* One more address cycle for higher density devices */
++			if (this->chipsize & 0x0c000000) {
++				WriteDOC((unsigned char)((page_addr >> 16) & 0x0f), docptr, Mplus_FlashAddress);
++				printk("high density\n");
++			}
++		}
++		WriteDOC(0, docptr, Mplus_WritePipeTerm);
++		WriteDOC(0, docptr, Mplus_WritePipeTerm);
++		/* deassert ALE */
++		if (command == NAND_CMD_READ0 || command == NAND_CMD_READ1 ||
++		    command == NAND_CMD_READOOB || command == NAND_CMD_READID)
++			WriteDOC(0, docptr, Mplus_FlashControl);
++	}
++
++	/*
++	 * program and erase have their own busy handlers
++	 * status and sequential in needs no delay
++	 */
++	switch (command) {
++
++	case NAND_CMD_PAGEPROG:
++	case NAND_CMD_ERASE1:
++	case NAND_CMD_ERASE2:
++	case NAND_CMD_SEQIN:
++	case NAND_CMD_STATUS:
++		return;
++
++	case NAND_CMD_RESET:
++		if (this->dev_ready)
++			break;
++		udelay(this->chip_delay);
++		WriteDOC(NAND_CMD_STATUS, docptr, Mplus_FlashCmd);
++		WriteDOC(0, docptr, Mplus_WritePipeTerm);
++		WriteDOC(0, docptr, Mplus_WritePipeTerm);
++		while (!(this->read_byte(mtd) & 0x40)) ;
++		return;
++
++		/* This applies to read commands */
++	default:
++		/*
++		 * If we don't have access to the busy pin, we apply the given
++		 * command delay
++		 */
++		if (!this->dev_ready) {
++			udelay(this->chip_delay);
++			return;
++		}
++	}
++
++	/* Apply this short delay always to ensure that we do wait tWB in
++	 * any case on any machine. */
++	ndelay(100);
++	/* wait until command is processed */
++	while (!this->dev_ready(mtd)) ;
++}
++
++static int doc200x_dev_ready(struct mtd_info *mtd)
++{
++	struct nand_chip *this = mtd_to_nand(mtd);
++	struct doc_priv *doc = nand_get_controller_data(this);
++	void __iomem *docptr = doc->virtadr;
++
++	if (DoC_is_MillenniumPlus(doc)) {
++		/* 11.4.2 -- must NOP four times before checking FR/B# */
++		DoC_Delay(doc, 4);
++		if ((ReadDOC(docptr, Mplus_FlashControl) & CDSN_CTRL_FR_B_MASK) != CDSN_CTRL_FR_B_MASK) {
++			if (debug)
++				printk("not ready\n");
++			return 0;
++		}
++		if (debug)
++			printk("was ready\n");
++		return 1;
++	} else {
++		/* 11.4.2 -- must NOP four times before checking FR/B# */
++		DoC_Delay(doc, 4);
++		if (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B)) {
++			if (debug)
++				printk("not ready\n");
++			return 0;
++		}
++		/* 11.4.2 -- Must NOP twice if it's ready */
++		DoC_Delay(doc, 2);
++		if (debug)
++			printk("was ready\n");
++		return 1;
++	}
++}
++
++static int doc200x_block_bad(struct mtd_info *mtd, loff_t ofs)
++{
++	/* This is our last resort if we couldn't find or create a BBT.  Just
++	   pretend all blocks are good. */
++	return 0;
++}
++
++static void doc200x_enable_hwecc(struct mtd_info *mtd, int mode)
++{
++	struct nand_chip *this = mtd_to_nand(mtd);
++	struct doc_priv *doc = nand_get_controller_data(this);
++	void __iomem *docptr = doc->virtadr;
++
++	/* Prime the ECC engine */
++	switch (mode) {
++	case NAND_ECC_READ:
++		WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
++		WriteDOC(DOC_ECC_EN, docptr, ECCConf);
++		break;
++	case NAND_ECC_WRITE:
++		WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
++		WriteDOC(DOC_ECC_EN | DOC_ECC_RW, docptr, ECCConf);
++		break;
++	}
++}
++
++static void doc2001plus_enable_hwecc(struct mtd_info *mtd, int mode)
++{
++	struct nand_chip *this = mtd_to_nand(mtd);
++	struct doc_priv *doc = nand_get_controller_data(this);
++	void __iomem *docptr = doc->virtadr;
++
++	/* Prime the ECC engine */
++	switch (mode) {
++	case NAND_ECC_READ:
++		WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf);
++		WriteDOC(DOC_ECC_EN, docptr, Mplus_ECCConf);
++		break;
++	case NAND_ECC_WRITE:
++		WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf);
++		WriteDOC(DOC_ECC_EN | DOC_ECC_RW, docptr, Mplus_ECCConf);
++		break;
++	}
++}
++
++/* 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 doc_priv *doc = nand_get_controller_data(this);
++	void __iomem *docptr = doc->virtadr;
++	int i;
++	int emptymatch = 1;
++
++	/* flush the pipeline */
++	if (DoC_is_2000(doc)) {
++		WriteDOC(doc->CDSNControl & ~CDSN_CTRL_FLASH_IO, docptr, CDSNControl);
++		WriteDOC(0, docptr, 2k_CDSN_IO);
++		WriteDOC(0, docptr, 2k_CDSN_IO);
++		WriteDOC(0, docptr, 2k_CDSN_IO);
++		WriteDOC(doc->CDSNControl, docptr, CDSNControl);
++	} else if (DoC_is_MillenniumPlus(doc)) {
++		WriteDOC(0, docptr, Mplus_NOP);
++		WriteDOC(0, docptr, Mplus_NOP);
++		WriteDOC(0, docptr, Mplus_NOP);
++	} else {
++		WriteDOC(0, docptr, NOP);
++		WriteDOC(0, docptr, NOP);
++		WriteDOC(0, docptr, NOP);
++	}
++
++	for (i = 0; i < 6; i++) {
++		if (DoC_is_MillenniumPlus(doc))
++			ecc_code[i] = ReadDOC_(docptr, DoC_Mplus_ECCSyndrome0 + i);
++		else
++			ecc_code[i] = ReadDOC_(docptr, DoC_ECCSyndrome0 + i);
++		if (ecc_code[i] != empty_write_ecc[i])
++			emptymatch = 0;
++	}
++	if (DoC_is_MillenniumPlus(doc))
++		WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf);
++	else
++		WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
++#if 0
++	/* If emptymatch=1, we might have an all-0xff data buffer.  Check. */
++	if (emptymatch) {
++		/* Note: this somewhat expensive test should not be triggered
++		   often.  It could be optimized away by examining the data in
++		   the writebuf routine, and remembering the result. */
++		for (i = 0; i < 512; i++) {
++			if (dat[i] == 0xff)
++				continue;
++			emptymatch = 0;
++			break;
++		}
++	}
++	/* If emptymatch still =1, we do have an all-0xff data buffer.
++	   Return all-0xff ecc value instead of the computed one, so
++	   it'll look just like a freshly-erased page. */
++	if (emptymatch)
++		memset(ecc_code, 0xff, 6);
++#endif
++	return 0;
++}
++
++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 doc_priv *doc = nand_get_controller_data(this);
++	void __iomem *docptr = doc->virtadr;
++	uint8_t calc_ecc[6];
++	volatile u_char dummy;
++
++	/* flush the pipeline */
++	if (DoC_is_2000(doc)) {
++		dummy = ReadDOC(docptr, 2k_ECCStatus);
++		dummy = ReadDOC(docptr, 2k_ECCStatus);
++		dummy = ReadDOC(docptr, 2k_ECCStatus);
++	} else if (DoC_is_MillenniumPlus(doc)) {
++		dummy = ReadDOC(docptr, Mplus_ECCConf);
++		dummy = ReadDOC(docptr, Mplus_ECCConf);
++		dummy = ReadDOC(docptr, Mplus_ECCConf);
++	} else {
++		dummy = ReadDOC(docptr, ECCConf);
++		dummy = ReadDOC(docptr, ECCConf);
++		dummy = ReadDOC(docptr, ECCConf);
++	}
++
++	/* Error occurred ? */
++	if (dummy & 0x80) {
++		for (i = 0; i < 6; i++) {
++			if (DoC_is_MillenniumPlus(doc))
++				calc_ecc[i] = ReadDOC_(docptr, DoC_Mplus_ECCSyndrome0 + i);
++			else
++				calc_ecc[i] = ReadDOC_(docptr, DoC_ECCSyndrome0 + i);
++		}
++
++		ret = doc_ecc_decode(rs_decoder, dat, calc_ecc);
++		if (ret > 0)
++			printk(KERN_ERR "doc200x_correct_data corrected %d errors\n", ret);
++	}
++	if (DoC_is_MillenniumPlus(doc))
++		WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf);
++	else
++		WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
++	if (no_ecc_failures && mtd_is_eccerr(ret)) {
++		printk(KERN_ERR "suppressing ECC failure\n");
++		ret = 0;
++	}
++	return ret;
++}
++
++//u_char mydatabuf[528];
++
++static int doc200x_ooblayout_ecc(struct mtd_info *mtd, int section,
++				 struct mtd_oob_region *oobregion)
++{
++	if (section)
++		return -ERANGE;
++
++	oobregion->offset = 0;
++	oobregion->length = 6;
++
++	return 0;
++}
++
++static int doc200x_ooblayout_free(struct mtd_info *mtd, int section,
++				  struct mtd_oob_region *oobregion)
++{
++	if (section > 1)
++		return -ERANGE;
++
++	/*
++	 * The strange out-of-order free bytes definition is a (possibly
++	 * unneeded) attempt to retain compatibility.  It used to read:
++	 *	.oobfree = { {8, 8} }
++	 * Since that leaves two bytes unusable, it was changed.  But the
++	 * following scheme might affect existing jffs2 installs by moving the
++	 * cleanmarker:
++	 *	.oobfree = { {6, 10} }
++	 * jffs2 seems to handle the above gracefully, but the current scheme
++	 * seems safer. The only problem with it is that any code retrieving
++	 * free bytes position must be able to handle out-of-order segments.
++	 */
++	if (!section) {
++		oobregion->offset = 8;
++		oobregion->length = 8;
++	} else {
++		oobregion->offset = 6;
++		oobregion->length = 2;
++	}
++
++	return 0;
++}
++
++static const struct mtd_ooblayout_ops doc200x_ooblayout_ops = {
++	.ecc = doc200x_ooblayout_ecc,
++	.free = doc200x_ooblayout_free,
++};
++
++/* Find the (I)NFTL Media Header, and optionally also the mirror media header.
++   On successful return, buf will contain a copy of the media header for
++   further processing.  id is the string to scan for, and will presumably be
++   either "ANAND" or "BNAND".  If findmirror=1, also look for the mirror media
++   header.  The page #s of the found media headers are placed in mh0_page and
++   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 doc_priv *doc = nand_get_controller_data(this);
++	unsigned offs;
++	int ret;
++	size_t retlen;
++
++	for (offs = 0; offs < mtd->size; offs += mtd->erasesize) {
++		ret = mtd_read(mtd, offs, mtd->writesize, &retlen, buf);
++		if (retlen != mtd->writesize)
++			continue;
++		if (ret) {
++			printk(KERN_WARNING "ECC error scanning DOC at 0x%x\n", offs);
++		}
++		if (memcmp(buf, id, 6))
++			continue;
++		printk(KERN_INFO "Found DiskOnChip %s Media Header at 0x%x\n", id, offs);
++		if (doc->mh0_page == -1) {
++			doc->mh0_page = offs >> this->page_shift;
++			if (!findmirror)
++				return 1;
++			continue;
++		}
++		doc->mh1_page = offs >> this->page_shift;
++		return 2;
++	}
++	if (doc->mh0_page == -1) {
++		printk(KERN_WARNING "DiskOnChip %s Media Header not found.\n", id);
++		return 0;
++	}
++	/* Only one mediaheader was found.  We want buf to contain a
++	   mediaheader on return, so we'll have to re-read the one we found. */
++	offs = doc->mh0_page << this->page_shift;
++	ret = mtd_read(mtd, offs, mtd->writesize, &retlen, buf);
++	if (retlen != mtd->writesize) {
++		/* Insanity.  Give up. */
++		printk(KERN_ERR "Read DiskOnChip Media Header once, but can't reread it???\n");
++		return 0;
++	}
++	return 1;
++}
++
++static inline int __init nftl_partscan(struct mtd_info *mtd, struct mtd_partition *parts)
++{
++	struct nand_chip *this = mtd_to_nand(mtd);
++	struct doc_priv *doc = nand_get_controller_data(this);
++	int ret = 0;
++	u_char *buf;
++	struct NFTLMediaHeader *mh;
++	const unsigned psize = 1 << this->page_shift;
++	int numparts = 0;
++	unsigned blocks, maxblocks;
++	int offs, numheaders;
++
++	buf = kmalloc(mtd->writesize, GFP_KERNEL);
++	if (!buf) {
++		return 0;
++	}
++	if (!(numheaders = find_media_headers(mtd, buf, "ANAND", 1)))
++		goto out;
++	mh = (struct NFTLMediaHeader *)buf;
++
++	le16_to_cpus(&mh->NumEraseUnits);
++	le16_to_cpus(&mh->FirstPhysicalEUN);
++	le32_to_cpus(&mh->FormattedSize);
++
++	printk(KERN_INFO "    DataOrgID        = %s\n"
++			 "    NumEraseUnits    = %d\n"
++			 "    FirstPhysicalEUN = %d\n"
++			 "    FormattedSize    = %d\n"
++			 "    UnitSizeFactor   = %d\n",
++		mh->DataOrgID, mh->NumEraseUnits,
++		mh->FirstPhysicalEUN, mh->FormattedSize,
++		mh->UnitSizeFactor);
++
++	blocks = mtd->size >> this->phys_erase_shift;
++	maxblocks = min(32768U, mtd->erasesize - psize);
++
++	if (mh->UnitSizeFactor == 0x00) {
++		/* Auto-determine UnitSizeFactor.  The constraints are:
++		   - There can be at most 32768 virtual blocks.
++		   - There can be at most (virtual block size - page size)
++		   virtual blocks (because MediaHeader+BBT must fit in 1).
++		 */
++		mh->UnitSizeFactor = 0xff;
++		while (blocks > maxblocks) {
++			blocks >>= 1;
++			maxblocks = min(32768U, (maxblocks << 1) + psize);
++			mh->UnitSizeFactor--;
++		}
++		printk(KERN_WARNING "UnitSizeFactor=0x00 detected.  Correct value is assumed to be 0x%02x.\n", mh->UnitSizeFactor);
++	}
++
++	/* NOTE: The lines below modify internal variables of the NAND and MTD
++	   layers; variables with have already been configured by nand_scan.
++	   Unfortunately, we didn't know before this point what these values
++	   should be.  Thus, this code is somewhat dependent on the exact
++	   implementation of the NAND layer.  */
++	if (mh->UnitSizeFactor != 0xff) {
++		this->bbt_erase_shift += (0xff - mh->UnitSizeFactor);
++		mtd->erasesize <<= (0xff - mh->UnitSizeFactor);
++		printk(KERN_INFO "Setting virtual erase size to %d\n", mtd->erasesize);
++		blocks = mtd->size >> this->bbt_erase_shift;
++		maxblocks = min(32768U, mtd->erasesize - psize);
++	}
++
++	if (blocks > maxblocks) {
++		printk(KERN_ERR "UnitSizeFactor of 0x%02x is inconsistent with device size.  Aborting.\n", mh->UnitSizeFactor);
++		goto out;
++	}
++
++	/* Skip past the media headers. */
++	offs = max(doc->mh0_page, doc->mh1_page);
++	offs <<= this->page_shift;
++	offs += mtd->erasesize;
++
++	if (show_firmware_partition == 1) {
++		parts[0].name = " DiskOnChip Firmware / Media Header partition";
++		parts[0].offset = 0;
++		parts[0].size = offs;
++		numparts = 1;
++	}
++
++	parts[numparts].name = " DiskOnChip BDTL partition";
++	parts[numparts].offset = offs;
++	parts[numparts].size = (mh->NumEraseUnits - numheaders) << this->bbt_erase_shift;
++
++	offs += parts[numparts].size;
++	numparts++;
++
++	if (offs < mtd->size) {
++		parts[numparts].name = " DiskOnChip Remainder partition";
++		parts[numparts].offset = offs;
++		parts[numparts].size = mtd->size - offs;
++		numparts++;
++	}
++
++	ret = numparts;
++ out:
++	kfree(buf);
++	return ret;
++}
++
++/* 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 doc_priv *doc = nand_get_controller_data(this);
++	int ret = 0;
++	u_char *buf;
++	struct INFTLMediaHeader *mh;
++	struct INFTLPartition *ip;
++	int numparts = 0;
++	int blocks;
++	int vshift, lastvunit = 0;
++	int i;
++	int end = mtd->size;
++
++	if (inftl_bbt_write)
++		end -= (INFTL_BBT_RESERVED_BLOCKS << this->phys_erase_shift);
++
++	buf = kmalloc(mtd->writesize, GFP_KERNEL);
++	if (!buf) {
++		return 0;
++	}
++
++	if (!find_media_headers(mtd, buf, "BNAND", 0))
++		goto out;
++	doc->mh1_page = doc->mh0_page + (4096 >> this->page_shift);
++	mh = (struct INFTLMediaHeader *)buf;
++
++	le32_to_cpus(&mh->NoOfBootImageBlocks);
++	le32_to_cpus(&mh->NoOfBinaryPartitions);
++	le32_to_cpus(&mh->NoOfBDTLPartitions);
++	le32_to_cpus(&mh->BlockMultiplierBits);
++	le32_to_cpus(&mh->FormatFlags);
++	le32_to_cpus(&mh->PercentUsed);
++
++	printk(KERN_INFO "    bootRecordID          = %s\n"
++			 "    NoOfBootImageBlocks   = %d\n"
++			 "    NoOfBinaryPartitions  = %d\n"
++			 "    NoOfBDTLPartitions    = %d\n"
++			 "    BlockMultiplerBits    = %d\n"
++			 "    FormatFlgs            = %d\n"
++			 "    OsakVersion           = %d.%d.%d.%d\n"
++			 "    PercentUsed           = %d\n",
++		mh->bootRecordID, mh->NoOfBootImageBlocks,
++		mh->NoOfBinaryPartitions,
++		mh->NoOfBDTLPartitions,
++		mh->BlockMultiplierBits, mh->FormatFlags,
++		((unsigned char *) &mh->OsakVersion)[0] & 0xf,
++		((unsigned char *) &mh->OsakVersion)[1] & 0xf,
++		((unsigned char *) &mh->OsakVersion)[2] & 0xf,
++		((unsigned char *) &mh->OsakVersion)[3] & 0xf,
++		mh->PercentUsed);
++
++	vshift = this->phys_erase_shift + mh->BlockMultiplierBits;
++
++	blocks = mtd->size >> vshift;
++	if (blocks > 32768) {
++		printk(KERN_ERR "BlockMultiplierBits=%d is inconsistent with device size.  Aborting.\n", mh->BlockMultiplierBits);
++		goto out;
++	}
++
++	blocks = doc->chips_per_floor << (this->chip_shift - this->phys_erase_shift);
++	if (inftl_bbt_write && (blocks > mtd->erasesize)) {
++		printk(KERN_ERR "Writeable BBTs spanning more than one erase block are not yet supported.  FIX ME!\n");
++		goto out;
++	}
++
++	/* Scan the partitions */
++	for (i = 0; (i < 4); i++) {
++		ip = &(mh->Partitions[i]);
++		le32_to_cpus(&ip->virtualUnits);
++		le32_to_cpus(&ip->firstUnit);
++		le32_to_cpus(&ip->lastUnit);
++		le32_to_cpus(&ip->flags);
++		le32_to_cpus(&ip->spareUnits);
++		le32_to_cpus(&ip->Reserved0);
++
++		printk(KERN_INFO	"    PARTITION[%d] ->\n"
++			"        virtualUnits    = %d\n"
++			"        firstUnit       = %d\n"
++			"        lastUnit        = %d\n"
++			"        flags           = 0x%x\n"
++			"        spareUnits      = %d\n",
++			i, ip->virtualUnits, ip->firstUnit,
++			ip->lastUnit, ip->flags,
++			ip->spareUnits);
++
++		if ((show_firmware_partition == 1) &&
++		    (i == 0) && (ip->firstUnit > 0)) {
++			parts[0].name = " DiskOnChip IPL / Media Header partition";
++			parts[0].offset = 0;
++			parts[0].size = mtd->erasesize * ip->firstUnit;
++			numparts = 1;
++		}
++
++		if (ip->flags & INFTL_BINARY)
++			parts[numparts].name = " DiskOnChip BDK partition";
++		else
++			parts[numparts].name = " DiskOnChip BDTL partition";
++		parts[numparts].offset = ip->firstUnit << vshift;
++		parts[numparts].size = (1 + ip->lastUnit - ip->firstUnit) << vshift;
++		numparts++;
++		if (ip->lastUnit > lastvunit)
++			lastvunit = ip->lastUnit;
++		if (ip->flags & INFTL_LAST)
++			break;
++	}
++	lastvunit++;
++	if ((lastvunit << vshift) < end) {
++		parts[numparts].name = " DiskOnChip Remainder partition";
++		parts[numparts].offset = lastvunit << vshift;
++		parts[numparts].size = end - parts[numparts].offset;
++		numparts++;
++	}
++	ret = numparts;
++ out:
++	kfree(buf);
++	return ret;
++}
++
++static int __init nftl_scan_bbt(struct mtd_info *mtd)
++{
++	int ret, numparts;
++	struct nand_chip *this = mtd_to_nand(mtd);
++	struct doc_priv *doc = nand_get_controller_data(this);
++	struct mtd_partition parts[2];
++
++	memset((char *)parts, 0, sizeof(parts));
++	/* On NFTL, we have to find the media headers before we can read the
++	   BBTs, since they're stored in the media header eraseblocks. */
++	numparts = nftl_partscan(mtd, parts);
++	if (!numparts)
++		return -EIO;
++	this->bbt_td->options = NAND_BBT_ABSPAGE | NAND_BBT_8BIT |
++				NAND_BBT_SAVECONTENT | NAND_BBT_WRITE |
++				NAND_BBT_VERSION;
++	this->bbt_td->veroffs = 7;
++	this->bbt_td->pages[0] = doc->mh0_page + 1;
++	if (doc->mh1_page != -1) {
++		this->bbt_md->options = NAND_BBT_ABSPAGE | NAND_BBT_8BIT |
++					NAND_BBT_SAVECONTENT | NAND_BBT_WRITE |
++					NAND_BBT_VERSION;
++		this->bbt_md->veroffs = 7;
++		this->bbt_md->pages[0] = doc->mh1_page + 1;
++	} else {
++		this->bbt_md = NULL;
++	}
++
++	ret = this->scan_bbt(mtd);
++	if (ret)
++		return ret;
++
++	return mtd_device_register(mtd, parts, no_autopart ? 0 : numparts);
++}
++
++static int __init inftl_scan_bbt(struct mtd_info *mtd)
++{
++	int ret, numparts;
++	struct nand_chip *this = mtd_to_nand(mtd);
++	struct doc_priv *doc = nand_get_controller_data(this);
++	struct mtd_partition parts[5];
++
++	if (this->numchips > doc->chips_per_floor) {
++		printk(KERN_ERR "Multi-floor INFTL devices not yet supported.\n");
++		return -EIO;
++	}
++
++	if (DoC_is_MillenniumPlus(doc)) {
++		this->bbt_td->options = NAND_BBT_2BIT | NAND_BBT_ABSPAGE;
++		if (inftl_bbt_write)
++			this->bbt_td->options |= NAND_BBT_WRITE;
++		this->bbt_td->pages[0] = 2;
++		this->bbt_md = NULL;
++	} else {
++		this->bbt_td->options = NAND_BBT_LASTBLOCK | NAND_BBT_8BIT | NAND_BBT_VERSION;
++		if (inftl_bbt_write)
++			this->bbt_td->options |= NAND_BBT_WRITE;
++		this->bbt_td->offs = 8;
++		this->bbt_td->len = 8;
++		this->bbt_td->veroffs = 7;
++		this->bbt_td->maxblocks = INFTL_BBT_RESERVED_BLOCKS;
++		this->bbt_td->reserved_block_code = 0x01;
++		this->bbt_td->pattern = "MSYS_BBT";
++
++		this->bbt_md->options = NAND_BBT_LASTBLOCK | NAND_BBT_8BIT | NAND_BBT_VERSION;
++		if (inftl_bbt_write)
++			this->bbt_md->options |= NAND_BBT_WRITE;
++		this->bbt_md->offs = 8;
++		this->bbt_md->len = 8;
++		this->bbt_md->veroffs = 7;
++		this->bbt_md->maxblocks = INFTL_BBT_RESERVED_BLOCKS;
++		this->bbt_md->reserved_block_code = 0x01;
++		this->bbt_md->pattern = "TBB_SYSM";
++	}
++
++	ret = this->scan_bbt(mtd);
++	if (ret)
++		return ret;
++
++	memset((char *)parts, 0, sizeof(parts));
++	numparts = inftl_partscan(mtd, parts);
++	/* At least for now, require the INFTL Media Header.  We could probably
++	   do without it for non-INFTL use, since all it gives us is
++	   autopartitioning, but I want to give it more thought. */
++	if (!numparts)
++		return -EIO;
++	return mtd_device_register(mtd, parts, no_autopart ? 0 : numparts);
++}
++
++static inline int __init doc2000_init(struct mtd_info *mtd)
++{
++	struct nand_chip *this = mtd_to_nand(mtd);
++	struct doc_priv *doc = nand_get_controller_data(this);
++
++	this->read_byte = doc2000_read_byte;
++	this->write_buf = doc2000_writebuf;
++	this->read_buf = doc2000_readbuf;
++	doc->late_init = nftl_scan_bbt;
++
++	doc->CDSNControl = CDSN_CTRL_FLASH_IO | CDSN_CTRL_ECC_IO;
++	doc2000_count_chips(mtd);
++	mtd->name = "DiskOnChip 2000 (NFTL Model)";
++	return (4 * doc->chips_per_floor);
++}
++
++static inline int __init doc2001_init(struct mtd_info *mtd)
++{
++	struct nand_chip *this = mtd_to_nand(mtd);
++	struct doc_priv *doc = nand_get_controller_data(this);
++
++	this->read_byte = doc2001_read_byte;
++	this->write_buf = doc2001_writebuf;
++	this->read_buf = doc2001_readbuf;
++
++	ReadDOC(doc->virtadr, ChipID);
++	ReadDOC(doc->virtadr, ChipID);
++	ReadDOC(doc->virtadr, ChipID);
++	if (ReadDOC(doc->virtadr, ChipID) != DOC_ChipID_DocMil) {
++		/* It's not a Millennium; it's one of the newer
++		   DiskOnChip 2000 units with a similar ASIC.
++		   Treat it like a Millennium, except that it
++		   can have multiple chips. */
++		doc2000_count_chips(mtd);
++		mtd->name = "DiskOnChip 2000 (INFTL Model)";
++		doc->late_init = inftl_scan_bbt;
++		return (4 * doc->chips_per_floor);
++	} else {
++		/* Bog-standard Millennium */
++		doc->chips_per_floor = 1;
++		mtd->name = "DiskOnChip Millennium";
++		doc->late_init = nftl_scan_bbt;
++		return 1;
++	}
++}
++
++static inline int __init doc2001plus_init(struct mtd_info *mtd)
++{
++	struct nand_chip *this = mtd_to_nand(mtd);
++	struct doc_priv *doc = nand_get_controller_data(this);
++
++	this->read_byte = doc2001plus_read_byte;
++	this->write_buf = doc2001plus_writebuf;
++	this->read_buf = doc2001plus_readbuf;
++	doc->late_init = inftl_scan_bbt;
++	this->cmd_ctrl = NULL;
++	this->select_chip = doc2001plus_select_chip;
++	this->cmdfunc = doc2001plus_command;
++	this->ecc.hwctl = doc2001plus_enable_hwecc;
++
++	doc->chips_per_floor = 1;
++	mtd->name = "DiskOnChip Millennium Plus";
++
++	return 1;
++}
++
++static int __init doc_probe(unsigned long physadr)
++{
++	unsigned char ChipID;
++	struct mtd_info *mtd;
++	struct nand_chip *nand;
++	struct doc_priv *doc;
++	void __iomem *virtadr;
++	unsigned char save_control;
++	unsigned char tmp, tmpb, tmpc;
++	int reg, len, numchips;
++	int ret = 0;
++
++	if (!request_mem_region(physadr, DOC_IOREMAP_LEN, "DiskOnChip"))
++		return -EBUSY;
++	virtadr = ioremap(physadr, DOC_IOREMAP_LEN);
++	if (!virtadr) {
++		printk(KERN_ERR "Diskonchip ioremap failed: 0x%x bytes at 0x%lx\n", DOC_IOREMAP_LEN, physadr);
++		ret = -EIO;
++		goto error_ioremap;
++	}
++
++	/* It's not possible to cleanly detect the DiskOnChip - the
++	 * bootup procedure will put the device into reset mode, and
++	 * it's not possible to talk to it without actually writing
++	 * to the DOCControl register. So we store the current contents
++	 * of the DOCControl register's location, in case we later decide
++	 * that it's not a DiskOnChip, and want to put it back how we
++	 * found it.
++	 */
++	save_control = ReadDOC(virtadr, DOCControl);
++
++	/* Reset the DiskOnChip ASIC */
++	WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, virtadr, DOCControl);
++	WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, virtadr, DOCControl);
++
++	/* Enable the DiskOnChip ASIC */
++	WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, virtadr, DOCControl);
++	WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, virtadr, DOCControl);
++
++	ChipID = ReadDOC(virtadr, ChipID);
++
++	switch (ChipID) {
++	case DOC_ChipID_Doc2k:
++		reg = DoC_2k_ECCStatus;
++		break;
++	case DOC_ChipID_DocMil:
++		reg = DoC_ECCConf;
++		break;
++	case DOC_ChipID_DocMilPlus16:
++	case DOC_ChipID_DocMilPlus32:
++	case 0:
++		/* Possible Millennium Plus, need to do more checks */
++		/* Possibly release from power down mode */
++		for (tmp = 0; (tmp < 4); tmp++)
++			ReadDOC(virtadr, Mplus_Power);
++
++		/* Reset the Millennium Plus ASIC */
++		tmp = DOC_MODE_RESET | DOC_MODE_MDWREN | DOC_MODE_RST_LAT | DOC_MODE_BDECT;
++		WriteDOC(tmp, virtadr, Mplus_DOCControl);
++		WriteDOC(~tmp, virtadr, Mplus_CtrlConfirm);
++
++		mdelay(1);
++		/* Enable the Millennium Plus ASIC */
++		tmp = DOC_MODE_NORMAL | DOC_MODE_MDWREN | DOC_MODE_RST_LAT | DOC_MODE_BDECT;
++		WriteDOC(tmp, virtadr, Mplus_DOCControl);
++		WriteDOC(~tmp, virtadr, Mplus_CtrlConfirm);
++		mdelay(1);
++
++		ChipID = ReadDOC(virtadr, ChipID);
++
++		switch (ChipID) {
++		case DOC_ChipID_DocMilPlus16:
++			reg = DoC_Mplus_Toggle;
++			break;
++		case DOC_ChipID_DocMilPlus32:
++			printk(KERN_ERR "DiskOnChip Millennium Plus 32MB is not supported, ignoring.\n");
++		default:
++			ret = -ENODEV;
++			goto notfound;
++		}
++		break;
++
++	default:
++		ret = -ENODEV;
++		goto notfound;
++	}
++	/* Check the TOGGLE bit in the ECC register */
++	tmp = ReadDOC_(virtadr, reg) & DOC_TOGGLE_BIT;
++	tmpb = ReadDOC_(virtadr, reg) & DOC_TOGGLE_BIT;
++	tmpc = ReadDOC_(virtadr, reg) & DOC_TOGGLE_BIT;
++	if ((tmp == tmpb) || (tmp != tmpc)) {
++		printk(KERN_WARNING "Possible DiskOnChip at 0x%lx failed TOGGLE test, dropping.\n", physadr);
++		ret = -ENODEV;
++		goto notfound;
++	}
++
++	for (mtd = doclist; mtd; mtd = doc->nextdoc) {
++		unsigned char oldval;
++		unsigned char newval;
++		nand = mtd_to_nand(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
++		   to one chip's alias resolution register change the value on
++		   the other chip, they're the same chip. */
++		if (ChipID == DOC_ChipID_DocMilPlus16) {
++			oldval = ReadDOC(doc->virtadr, Mplus_AliasResolution);
++			newval = ReadDOC(virtadr, Mplus_AliasResolution);
++		} else {
++			oldval = ReadDOC(doc->virtadr, AliasResolution);
++			newval = ReadDOC(virtadr, AliasResolution);
++		}
++		if (oldval != newval)
++			continue;
++		if (ChipID == DOC_ChipID_DocMilPlus16) {
++			WriteDOC(~newval, virtadr, Mplus_AliasResolution);
++			oldval = ReadDOC(doc->virtadr, Mplus_AliasResolution);
++			WriteDOC(newval, virtadr, Mplus_AliasResolution);	// restore it
++		} else {
++			WriteDOC(~newval, virtadr, AliasResolution);
++			oldval = ReadDOC(doc->virtadr, AliasResolution);
++			WriteDOC(newval, virtadr, AliasResolution);	// restore it
++		}
++		newval = ~newval;
++		if (oldval == newval) {
++			printk(KERN_DEBUG "Found alias of DOC at 0x%lx to 0x%lx\n", doc->physadr, physadr);
++			goto notfound;
++		}
++	}
++
++	printk(KERN_NOTICE "DiskOnChip found at 0x%lx\n", physadr);
++
++	len = sizeof(struct nand_chip) + sizeof(struct doc_priv) +
++	      (2 * sizeof(struct nand_bbt_descr));
++	nand = kzalloc(len, GFP_KERNEL);
++	if (!nand) {
++		ret = -ENOMEM;
++		goto fail;
++	}
++
++	mtd			= nand_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;
++
++	mtd->owner		= THIS_MODULE;
++	mtd_set_ooblayout(mtd, &doc200x_ooblayout_ops);
++
++	nand_set_controller_data(nand, doc);
++	nand->select_chip	= doc200x_select_chip;
++	nand->cmd_ctrl		= doc200x_hwcontrol;
++	nand->dev_ready		= doc200x_dev_ready;
++	nand->waitfunc		= doc200x_wait;
++	nand->block_bad		= doc200x_block_bad;
++	nand->ecc.hwctl		= doc200x_enable_hwecc;
++	nand->ecc.calculate	= doc200x_calculate_ecc;
++	nand->ecc.correct	= doc200x_correct_data;
++
++	nand->ecc.mode		= NAND_ECC_HW_SYNDROME;
++	nand->ecc.size		= 512;
++	nand->ecc.bytes		= 6;
++	nand->ecc.strength	= 2;
++	nand->ecc.options	= NAND_ECC_GENERIC_ERASED_CHECK;
++	nand->bbt_options	= NAND_BBT_USE_FLASH;
++	/* Skip the automatic BBT scan so we can run it manually */
++	nand->options		|= NAND_SKIP_BBTSCAN;
++
++	doc->physadr		= physadr;
++	doc->virtadr		= virtadr;
++	doc->ChipID		= ChipID;
++	doc->curfloor		= -1;
++	doc->curchip		= -1;
++	doc->mh0_page		= -1;
++	doc->mh1_page		= -1;
++	doc->nextdoc		= doclist;
++
++	if (ChipID == DOC_ChipID_Doc2k)
++		numchips = doc2000_init(mtd);
++	else if (ChipID == DOC_ChipID_DocMilPlus16)
++		numchips = doc2001plus_init(mtd);
++	else
++		numchips = doc2001_init(mtd);
++
++	if ((ret = nand_scan(mtd, numchips)) || (ret = doc->late_init(mtd))) {
++		/* DBB note: i believe nand_release is necessary here, as
++		   buffers may have been allocated in nand_base.  Check with
++		   Thomas. FIX ME! */
++		/* nand_release will call mtd_device_unregister, but we
++		   haven't yet added it.  This is handled without incident by
++		   mtd_device_unregister, as far as I can tell. */
++		nand_release(mtd);
++		kfree(nand);
++		goto fail;
++	}
++
++	/* Success! */
++	doclist = mtd;
++	return 0;
++
++ notfound:
++	/* Put back the contents of the DOCControl register, in case it's not
++	   actually a DiskOnChip.  */
++	WriteDOC(save_control, virtadr, DOCControl);
++ fail:
++	iounmap(virtadr);
++
++error_ioremap:
++	release_mem_region(physadr, DOC_IOREMAP_LEN);
++
++	return ret;
++}
++
++static void release_nanddoc(void)
++{
++	struct mtd_info *mtd, *nextmtd;
++	struct nand_chip *nand;
++	struct doc_priv *doc;
++
++	for (mtd = doclist; mtd; mtd = nextmtd) {
++		nand = mtd_to_nand(mtd);
++		doc = nand_get_controller_data(nand);
++
++		nextmtd = doc->nextdoc;
++		nand_release(mtd);
++		iounmap(doc->virtadr);
++		release_mem_region(doc->physadr, DOC_IOREMAP_LEN);
++		kfree(nand);
++	}
++}
++
++static int __init init_nanddoc(void)
++{
++	int i, ret = 0;
++
++	/* We could create the decoder on demand, if memory is a concern.
++	 * This way we have it handy, if an error happens
++	 *
++	 * Symbolsize is 10 (bits)
++	 * Primitve polynomial is x^10+x^3+1
++	 * first consecutive root is 510
++	 * primitve element to generate roots = 1
++	 * generator polinomial degree = 4
++	 */
++	rs_decoder = init_rs(10, 0x409, FCR, 1, NROOTS);
++	if (!rs_decoder) {
++		printk(KERN_ERR "DiskOnChip: Could not create a RS decoder\n");
++		return -ENOMEM;
++	}
++
++	if (doc_config_location) {
++		printk(KERN_INFO "Using configured DiskOnChip probe address 0x%lx\n", doc_config_location);
++		ret = doc_probe(doc_config_location);
++		if (ret < 0)
++			goto outerr;
++	} else {
++		for (i = 0; (doc_locations[i] != 0xffffffff); i++) {
++			doc_probe(doc_locations[i]);
++		}
++	}
++	/* No banner message any more. Print a message if no DiskOnChip
++	   found, so the user knows we at least tried. */
++	if (!doclist) {
++		printk(KERN_INFO "No valid DiskOnChip devices found\n");
++		ret = -ENODEV;
++		goto outerr;
++	}
++	return 0;
++ outerr:
++	free_rs(rs_decoder);
++	return ret;
++}
++
++static void __exit cleanup_nanddoc(void)
++{
++	/* Cleanup the nand/DoC resources */
++	release_nanddoc();
++
++	/* Free the reed solomon resources */
++	if (rs_decoder) {
++		free_rs(rs_decoder);
++	}
++}
++
++module_init(init_nanddoc);
++module_exit(cleanup_nanddoc);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
++MODULE_DESCRIPTION("M-Systems DiskOnChip 2000, Millennium and Millennium Plus device driver");
+diff --git a/drivers/mtd/nand/raw/docg4.c b/drivers/mtd/nand/raw/docg4.c
+new file mode 100644
+index 0000000..2436cbc
+--- /dev/null
++++ b/drivers/mtd/nand/raw/docg4.c
+@@ -0,0 +1,1412 @@
++/*
++ *  Copyright © 2012 Mike Dunn <mikedunn@newsguy.com>
++ *
++ * mtd nand driver for M-Systems DiskOnChip G4
++ *
++ * 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.
++ *
++ * Tested on the Palm Treo 680.  The G4 is also present on Toshiba Portege, Asus
++ * P526, some HTC smartphones (Wizard, Prophet, ...), O2 XDA Zinc, maybe others.
++ * Should work on these as well.  Let me know!
++ *
++ * TODO:
++ *
++ *  Mechanism for management of password-protected areas
++ *
++ *  Hamming ecc when reading oob only
++ *
++ *  According to the M-Sys documentation, this device is also available in a
++ *  "dual-die" configuration having a 256MB capacity, but no mechanism for
++ *  detecting this variant is documented.  Currently this driver assumes 128MB
++ *  capacity.
++ *
++ *  Support for multiple cascaded devices ("floors").  Not sure which gadgets
++ *  contain multiple G4s in a cascaded configuration, if any.
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/init.h>
++#include <linux/string.h>
++#include <linux/sched.h>
++#include <linux/delay.h>
++#include <linux/module.h>
++#include <linux/export.h>
++#include <linux/platform_device.h>
++#include <linux/io.h>
++#include <linux/bitops.h>
++#include <linux/mtd/partitions.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/rawnand.h>
++#include <linux/bch.h>
++#include <linux/bitrev.h>
++#include <linux/jiffies.h>
++
++/*
++ * In "reliable mode" consecutive 2k pages are used in parallel (in some
++ * fashion) to store the same data.  The data can be read back from the
++ * even-numbered pages in the normal manner; odd-numbered pages will appear to
++ * contain junk.  Systems that boot from the docg4 typically write the secondary
++ * program loader (SPL) code in this mode.  The SPL is loaded by the initial
++ * program loader (IPL, stored in the docg4's 2k NOR-like region that is mapped
++ * to the reset vector address).  This module parameter enables you to use this
++ * driver to write the SPL.  When in this mode, no more than 2k of data can be
++ * written at a time, because the addresses do not increment in the normal
++ * manner, and the starting offset must be within an even-numbered 2k region;
++ * i.e., invalid starting offsets are 0x800, 0xa00, 0xc00, 0xe00, 0x1800,
++ * 0x1a00, ...  Reliable mode is a special case and should not be used unless
++ * you know what you're doing.
++ */
++static bool reliable_mode;
++module_param(reliable_mode, bool, 0);
++MODULE_PARM_DESC(reliable_mode, "pages are programmed in reliable mode");
++
++/*
++ * You'll want to ignore badblocks if you're reading a partition that contains
++ * data written by the TrueFFS library (i.e., by PalmOS, Windows, etc), since
++ * it does not use mtd nand's method for marking bad blocks (using oob area).
++ * This will also skip the check of the "page written" flag.
++ */
++static bool ignore_badblocks;
++module_param(ignore_badblocks, bool, 0);
++MODULE_PARM_DESC(ignore_badblocks, "no badblock checking performed");
++
++struct docg4_priv {
++	struct mtd_info	*mtd;
++	struct device *dev;
++	void __iomem *virtadr;
++	int status;
++	struct {
++		unsigned int command;
++		int column;
++		int page;
++	} last_command;
++	uint8_t oob_buf[16];
++	uint8_t ecc_buf[7];
++	int oob_page;
++	struct bch_control *bch;
++};
++
++/*
++ * Defines prefixed with DOCG4 are unique to the diskonchip G4.  All others are
++ * shared with other diskonchip devices (P3, G3 at least).
++ *
++ * Functions with names prefixed with docg4_ are mtd / nand interface functions
++ * (though they may also be called internally).  All others are internal.
++ */
++
++#define DOC_IOSPACE_DATA		0x0800
++
++/* register offsets */
++#define DOC_CHIPID			0x1000
++#define DOC_DEVICESELECT		0x100a
++#define DOC_ASICMODE			0x100c
++#define DOC_DATAEND			0x101e
++#define DOC_NOP				0x103e
++
++#define DOC_FLASHSEQUENCE		0x1032
++#define DOC_FLASHCOMMAND		0x1034
++#define DOC_FLASHADDRESS		0x1036
++#define DOC_FLASHCONTROL		0x1038
++#define DOC_ECCCONF0			0x1040
++#define DOC_ECCCONF1			0x1042
++#define DOC_HAMMINGPARITY		0x1046
++#define DOC_BCH_SYNDROM(idx)		(0x1048 + idx)
++
++#define DOC_ASICMODECONFIRM		0x1072
++#define DOC_CHIPID_INV			0x1074
++#define DOC_POWERMODE			0x107c
++
++#define DOCG4_MYSTERY_REG		0x1050
++
++/* apparently used only to write oob bytes 6 and 7 */
++#define DOCG4_OOB_6_7			0x1052
++
++/* DOC_FLASHSEQUENCE register commands */
++#define DOC_SEQ_RESET			0x00
++#define DOCG4_SEQ_PAGE_READ		0x03
++#define DOCG4_SEQ_FLUSH			0x29
++#define DOCG4_SEQ_PAGEWRITE		0x16
++#define DOCG4_SEQ_PAGEPROG		0x1e
++#define DOCG4_SEQ_BLOCKERASE		0x24
++#define DOCG4_SEQ_SETMODE		0x45
++
++/* DOC_FLASHCOMMAND register commands */
++#define DOCG4_CMD_PAGE_READ             0x00
++#define DOC_CMD_ERASECYCLE2		0xd0
++#define DOCG4_CMD_FLUSH                 0x70
++#define DOCG4_CMD_READ2                 0x30
++#define DOC_CMD_PROG_BLOCK_ADDR		0x60
++#define DOCG4_CMD_PAGEWRITE		0x80
++#define DOC_CMD_PROG_CYCLE2		0x10
++#define DOCG4_CMD_FAST_MODE		0xa3 /* functionality guessed */
++#define DOC_CMD_RELIABLE_MODE		0x22
++#define DOC_CMD_RESET			0xff
++
++/* DOC_POWERMODE register bits */
++#define DOC_POWERDOWN_READY		0x80
++
++/* DOC_FLASHCONTROL register bits */
++#define DOC_CTRL_CE			0x10
++#define DOC_CTRL_UNKNOWN		0x40
++#define DOC_CTRL_FLASHREADY		0x01
++
++/* DOC_ECCCONF0 register bits */
++#define DOC_ECCCONF0_READ_MODE		0x8000
++#define DOC_ECCCONF0_UNKNOWN		0x2000
++#define DOC_ECCCONF0_ECC_ENABLE	        0x1000
++#define DOC_ECCCONF0_DATA_BYTES_MASK	0x07ff
++
++/* DOC_ECCCONF1 register bits */
++#define DOC_ECCCONF1_BCH_SYNDROM_ERR	0x80
++#define DOC_ECCCONF1_ECC_ENABLE         0x07
++#define DOC_ECCCONF1_PAGE_IS_WRITTEN	0x20
++
++/* DOC_ASICMODE register bits */
++#define DOC_ASICMODE_RESET		0x00
++#define DOC_ASICMODE_NORMAL		0x01
++#define DOC_ASICMODE_POWERDOWN		0x02
++#define DOC_ASICMODE_MDWREN		0x04
++#define DOC_ASICMODE_BDETCT_RESET	0x08
++#define DOC_ASICMODE_RSTIN_RESET	0x10
++#define DOC_ASICMODE_RAM_WE		0x20
++
++/* good status values read after read/write/erase operations */
++#define DOCG4_PROGSTATUS_GOOD          0x51
++#define DOCG4_PROGSTATUS_GOOD_2        0xe0
++
++/*
++ * On read operations (page and oob-only), the first byte read from I/O reg is a
++ * status.  On error, it reads 0x73; otherwise, it reads either 0x71 (first read
++ * after reset only) or 0x51, so bit 1 is presumed to be an error indicator.
++ */
++#define DOCG4_READ_ERROR           0x02 /* bit 1 indicates read error */
++
++/* anatomy of the device */
++#define DOCG4_CHIP_SIZE        0x8000000
++#define DOCG4_PAGE_SIZE        0x200
++#define DOCG4_PAGES_PER_BLOCK  0x200
++#define DOCG4_BLOCK_SIZE       (DOCG4_PAGES_PER_BLOCK * DOCG4_PAGE_SIZE)
++#define DOCG4_NUMBLOCKS        (DOCG4_CHIP_SIZE / DOCG4_BLOCK_SIZE)
++#define DOCG4_OOB_SIZE         0x10
++#define DOCG4_CHIP_SHIFT       27    /* log_2(DOCG4_CHIP_SIZE) */
++#define DOCG4_PAGE_SHIFT       9     /* log_2(DOCG4_PAGE_SIZE) */
++#define DOCG4_ERASE_SHIFT      18    /* log_2(DOCG4_BLOCK_SIZE) */
++
++/* all but the last byte is included in ecc calculation */
++#define DOCG4_BCH_SIZE         (DOCG4_PAGE_SIZE + DOCG4_OOB_SIZE - 1)
++
++#define DOCG4_USERDATA_LEN     520 /* 512 byte page plus 8 oob avail to user */
++
++/* expected values from the ID registers */
++#define DOCG4_IDREG1_VALUE     0x0400
++#define DOCG4_IDREG2_VALUE     0xfbff
++
++/* primitive polynomial used to build the Galois field used by hw ecc gen */
++#define DOCG4_PRIMITIVE_POLY   0x4443
++
++#define DOCG4_M                14  /* Galois field is of order 2^14 */
++#define DOCG4_T                4   /* BCH alg corrects up to 4 bit errors */
++
++#define DOCG4_FACTORY_BBT_PAGE 16 /* page where read-only factory bbt lives */
++#define DOCG4_REDUNDANT_BBT_PAGE 24 /* page where redundant factory bbt lives */
++
++/*
++ * Bytes 0, 1 are used as badblock marker.
++ * Bytes 2 - 6 are available to the user.
++ * Byte 7 is hamming ecc for first 7 oob bytes only.
++ * Bytes 8 - 14 are hw-generated ecc covering entire page + oob bytes 0 - 14.
++ * Byte 15 (the last) is used by the driver as a "page written" flag.
++ */
++static int docg4_ooblayout_ecc(struct mtd_info *mtd, int section,
++			       struct mtd_oob_region *oobregion)
++{
++	if (section)
++		return -ERANGE;
++
++	oobregion->offset = 7;
++	oobregion->length = 9;
++
++	return 0;
++}
++
++static int docg4_ooblayout_free(struct mtd_info *mtd, int section,
++				struct mtd_oob_region *oobregion)
++{
++	if (section)
++		return -ERANGE;
++
++	oobregion->offset = 2;
++	oobregion->length = 5;
++
++	return 0;
++}
++
++static const struct mtd_ooblayout_ops docg4_ooblayout_ops = {
++	.ecc = docg4_ooblayout_ecc,
++	.free = docg4_ooblayout_free,
++};
++
++/*
++ * The device has a nop register which M-Sys claims is for the purpose of
++ * inserting precise delays.  But beware; at least some operations fail if the
++ * nop writes are replaced with a generic delay!
++ */
++static inline void write_nop(void __iomem *docptr)
++{
++	writew(0, docptr + DOC_NOP);
++}
++
++static void docg4_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
++{
++	int i;
++	struct nand_chip *nand = mtd_to_nand(mtd);
++	uint16_t *p = (uint16_t *) buf;
++	len >>= 1;
++
++	for (i = 0; i < len; i++)
++		p[i] = readw(nand->IO_ADDR_R);
++}
++
++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);
++	uint16_t *p = (uint16_t *) buf;
++	len >>= 1;
++
++	for (i = 0; i < len; i++)
++		writew(p[i], nand->IO_ADDR_W);
++}
++
++static int poll_status(struct docg4_priv *doc)
++{
++	/*
++	 * Busy-wait for the FLASHREADY bit to be set in the FLASHCONTROL
++	 * register.  Operations known to take a long time (e.g., block erase)
++	 * should sleep for a while before calling this.
++	 */
++
++	uint16_t flash_status;
++	unsigned long timeo;
++	void __iomem *docptr = doc->virtadr;
++
++	dev_dbg(doc->dev, "%s...\n", __func__);
++
++	/* hardware quirk requires reading twice initially */
++	flash_status = readw(docptr + DOC_FLASHCONTROL);
++
++	timeo = jiffies + msecs_to_jiffies(200); /* generous timeout */
++	do {
++		cpu_relax();
++		flash_status = readb(docptr + DOC_FLASHCONTROL);
++	} while (!(flash_status & DOC_CTRL_FLASHREADY) &&
++		 time_before(jiffies, timeo));
++
++	if (unlikely(!(flash_status & DOC_CTRL_FLASHREADY))) {
++		dev_err(doc->dev, "%s: timed out!\n", __func__);
++		return NAND_STATUS_FAIL;
++	}
++
++	return 0;
++}
++
++
++static int docg4_wait(struct mtd_info *mtd, struct nand_chip *nand)
++{
++
++	struct docg4_priv *doc = nand_get_controller_data(nand);
++	int status = NAND_STATUS_WP;       /* inverse logic?? */
++	dev_dbg(doc->dev, "%s...\n", __func__);
++
++	/* report any previously unreported error */
++	if (doc->status) {
++		status |= doc->status;
++		doc->status = 0;
++		return status;
++	}
++
++	status |= poll_status(doc);
++	return status;
++}
++
++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 docg4_priv *doc = nand_get_controller_data(nand);
++	void __iomem *docptr = doc->virtadr;
++
++	dev_dbg(doc->dev, "%s: chip %d\n", __func__, chip);
++
++	if (chip < 0)
++		return;		/* deselected */
++
++	if (chip > 0)
++		dev_warn(doc->dev, "multiple floors currently unsupported\n");
++
++	writew(0, docptr + DOC_DEVICESELECT);
++}
++
++static void reset(struct mtd_info *mtd)
++{
++	/* full device reset */
++
++	struct nand_chip *nand = mtd_to_nand(mtd);
++	struct docg4_priv *doc = nand_get_controller_data(nand);
++	void __iomem *docptr = doc->virtadr;
++
++	writew(DOC_ASICMODE_RESET | DOC_ASICMODE_MDWREN,
++	       docptr + DOC_ASICMODE);
++	writew(~(DOC_ASICMODE_RESET | DOC_ASICMODE_MDWREN),
++	       docptr + DOC_ASICMODECONFIRM);
++	write_nop(docptr);
++
++	writew(DOC_ASICMODE_NORMAL | DOC_ASICMODE_MDWREN,
++	       docptr + DOC_ASICMODE);
++	writew(~(DOC_ASICMODE_NORMAL | DOC_ASICMODE_MDWREN),
++	       docptr + DOC_ASICMODECONFIRM);
++
++	writew(DOC_ECCCONF1_ECC_ENABLE, docptr + DOC_ECCCONF1);
++
++	poll_status(doc);
++}
++
++static void read_hw_ecc(void __iomem *docptr, uint8_t *ecc_buf)
++{
++	/* read the 7 hw-generated ecc bytes */
++
++	int i;
++	for (i = 0; i < 7; i++) { /* hw quirk; read twice */
++		ecc_buf[i] = readb(docptr + DOC_BCH_SYNDROM(i));
++		ecc_buf[i] = readb(docptr + DOC_BCH_SYNDROM(i));
++	}
++}
++
++static int correct_data(struct mtd_info *mtd, uint8_t *buf, int page)
++{
++	/*
++	 * Called after a page read when hardware reports bitflips.
++	 * Up to four bitflips can be corrected.
++	 */
++
++	struct nand_chip *nand = mtd_to_nand(mtd);
++	struct docg4_priv *doc = nand_get_controller_data(nand);
++	void __iomem *docptr = doc->virtadr;
++	int i, numerrs, errpos[4];
++	const uint8_t blank_read_hwecc[8] = {
++		0xcf, 0x72, 0xfc, 0x1b, 0xa9, 0xc7, 0xb9, 0 };
++
++	read_hw_ecc(docptr, doc->ecc_buf); /* read 7 hw-generated ecc bytes */
++
++	/* check if read error is due to a blank page */
++	if (!memcmp(doc->ecc_buf, blank_read_hwecc, 7))
++		return 0;	/* yes */
++
++	/* skip additional check of "written flag" if ignore_badblocks */
++	if (ignore_badblocks == false) {
++
++		/*
++		 * If the hw ecc bytes are not those of a blank page, there's
++		 * still a chance that the page is blank, but was read with
++		 * errors.  Check the "written flag" in last oob byte, which
++		 * is set to zero when a page is written.  If more than half
++		 * the bits are set, assume a blank page.  Unfortunately, the
++		 * bit flips(s) are not reported in stats.
++		 */
++
++		if (nand->oob_poi[15]) {
++			int bit, numsetbits = 0;
++			unsigned long written_flag = nand->oob_poi[15];
++			for_each_set_bit(bit, &written_flag, 8)
++				numsetbits++;
++			if (numsetbits > 4) { /* assume blank */
++				dev_warn(doc->dev,
++					 "error(s) in blank page "
++					 "at offset %08x\n",
++					 page * DOCG4_PAGE_SIZE);
++				return 0;
++			}
++		}
++	}
++
++	/*
++	 * The hardware ecc unit produces oob_ecc ^ calc_ecc.  The kernel's bch
++	 * algorithm is used to decode this.  However the hw operates on page
++	 * data in a bit order that is the reverse of that of the bch alg,
++	 * requiring that the bits be reversed on the result.  Thanks to Ivan
++	 * Djelic for his analysis!
++	 */
++	for (i = 0; i < 7; i++)
++		doc->ecc_buf[i] = bitrev8(doc->ecc_buf[i]);
++
++	numerrs = decode_bch(doc->bch, NULL, DOCG4_USERDATA_LEN, NULL,
++			     doc->ecc_buf, NULL, errpos);
++
++	if (numerrs == -EBADMSG) {
++		dev_warn(doc->dev, "uncorrectable errors at offset %08x\n",
++			 page * DOCG4_PAGE_SIZE);
++		return -EBADMSG;
++	}
++
++	BUG_ON(numerrs < 0);	/* -EINVAL, or anything other than -EBADMSG */
++
++	/* undo last step in BCH alg (modulo mirroring not needed) */
++	for (i = 0; i < numerrs; i++)
++		errpos[i] = (errpos[i] & ~7)|(7-(errpos[i] & 7));
++
++	/* fix the errors */
++	for (i = 0; i < numerrs; i++) {
++
++		/* ignore if error within oob ecc bytes */
++		if (errpos[i] > DOCG4_USERDATA_LEN * 8)
++			continue;
++
++		/* if error within oob area preceeding ecc bytes... */
++		if (errpos[i] > DOCG4_PAGE_SIZE * 8)
++			change_bit(errpos[i] - DOCG4_PAGE_SIZE * 8,
++				   (unsigned long *)nand->oob_poi);
++
++		else    /* error in page data */
++			change_bit(errpos[i], (unsigned long *)buf);
++	}
++
++	dev_notice(doc->dev, "%d error(s) corrected at offset %08x\n",
++		   numerrs, page * DOCG4_PAGE_SIZE);
++
++	return numerrs;
++}
++
++static uint8_t docg4_read_byte(struct mtd_info *mtd)
++{
++	struct nand_chip *nand = mtd_to_nand(mtd);
++	struct docg4_priv *doc = nand_get_controller_data(nand);
++
++	dev_dbg(doc->dev, "%s\n", __func__);
++
++	if (doc->last_command.command == NAND_CMD_STATUS) {
++		int status;
++
++		/*
++		 * Previous nand command was status request, so nand
++		 * infrastructure code expects to read the status here.  If an
++		 * error occurred in a previous operation, report it.
++		 */
++		doc->last_command.command = 0;
++
++		if (doc->status) {
++			status = doc->status;
++			doc->status = 0;
++		}
++
++		/* why is NAND_STATUS_WP inverse logic?? */
++		else
++			status = NAND_STATUS_WP | NAND_STATUS_READY;
++
++		return status;
++	}
++
++	dev_warn(doc->dev, "unexpected call to read_byte()\n");
++
++	return 0;
++}
++
++static void write_addr(struct docg4_priv *doc, uint32_t docg4_addr)
++{
++	/* write the four address bytes packed in docg4_addr to the device */
++
++	void __iomem *docptr = doc->virtadr;
++	writeb(docg4_addr & 0xff, docptr + DOC_FLASHADDRESS);
++	docg4_addr >>= 8;
++	writeb(docg4_addr & 0xff, docptr + DOC_FLASHADDRESS);
++	docg4_addr >>= 8;
++	writeb(docg4_addr & 0xff, docptr + DOC_FLASHADDRESS);
++	docg4_addr >>= 8;
++	writeb(docg4_addr & 0xff, docptr + DOC_FLASHADDRESS);
++}
++
++static int read_progstatus(struct docg4_priv *doc)
++{
++	/*
++	 * This apparently checks the status of programming.  Done after an
++	 * erasure, and after page data is written.  On error, the status is
++	 * saved, to be later retrieved by the nand infrastructure code.
++	 */
++	void __iomem *docptr = doc->virtadr;
++
++	/* status is read from the I/O reg */
++	uint16_t status1 = readw(docptr + DOC_IOSPACE_DATA);
++	uint16_t status2 = readw(docptr + DOC_IOSPACE_DATA);
++	uint16_t status3 = readw(docptr + DOCG4_MYSTERY_REG);
++
++	dev_dbg(doc->dev, "docg4: %s: %02x %02x %02x\n",
++	      __func__, status1, status2, status3);
++
++	if (status1 != DOCG4_PROGSTATUS_GOOD
++	    || status2 != DOCG4_PROGSTATUS_GOOD_2
++	    || status3 != DOCG4_PROGSTATUS_GOOD_2) {
++		doc->status = NAND_STATUS_FAIL;
++		dev_warn(doc->dev, "read_progstatus failed: "
++			 "%02x, %02x, %02x\n", status1, status2, status3);
++		return -EIO;
++	}
++	return 0;
++}
++
++static int pageprog(struct mtd_info *mtd)
++{
++	/*
++	 * Final step in writing a page.  Writes the contents of its
++	 * internal buffer out to the flash array, or some such.
++	 */
++
++	struct nand_chip *nand = mtd_to_nand(mtd);
++	struct docg4_priv *doc = nand_get_controller_data(nand);
++	void __iomem *docptr = doc->virtadr;
++	int retval = 0;
++
++	dev_dbg(doc->dev, "docg4: %s\n", __func__);
++
++	writew(DOCG4_SEQ_PAGEPROG, docptr + DOC_FLASHSEQUENCE);
++	writew(DOC_CMD_PROG_CYCLE2, docptr + DOC_FLASHCOMMAND);
++	write_nop(docptr);
++	write_nop(docptr);
++
++	/* Just busy-wait; usleep_range() slows things down noticeably. */
++	poll_status(doc);
++
++	writew(DOCG4_SEQ_FLUSH, docptr + DOC_FLASHSEQUENCE);
++	writew(DOCG4_CMD_FLUSH, docptr + DOC_FLASHCOMMAND);
++	writew(DOC_ECCCONF0_READ_MODE | 4, docptr + DOC_ECCCONF0);
++	write_nop(docptr);
++	write_nop(docptr);
++	write_nop(docptr);
++	write_nop(docptr);
++	write_nop(docptr);
++
++	retval = read_progstatus(doc);
++	writew(0, docptr + DOC_DATAEND);
++	write_nop(docptr);
++	poll_status(doc);
++	write_nop(docptr);
++
++	return retval;
++}
++
++static void sequence_reset(struct mtd_info *mtd)
++{
++	/* common starting sequence for all operations */
++
++	struct nand_chip *nand = mtd_to_nand(mtd);
++	struct docg4_priv *doc = nand_get_controller_data(nand);
++	void __iomem *docptr = doc->virtadr;
++
++	writew(DOC_CTRL_UNKNOWN | DOC_CTRL_CE, docptr + DOC_FLASHCONTROL);
++	writew(DOC_SEQ_RESET, docptr + DOC_FLASHSEQUENCE);
++	writew(DOC_CMD_RESET, docptr + DOC_FLASHCOMMAND);
++	write_nop(docptr);
++	write_nop(docptr);
++	poll_status(doc);
++	write_nop(docptr);
++}
++
++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 docg4_priv *doc = nand_get_controller_data(nand);
++	void __iomem *docptr = doc->virtadr;
++
++	dev_dbg(doc->dev,
++	      "docg4: %s: g4 page %08x\n", __func__, docg4_addr);
++
++	sequence_reset(mtd);
++
++	writew(DOCG4_SEQ_PAGE_READ, docptr + DOC_FLASHSEQUENCE);
++	writew(DOCG4_CMD_PAGE_READ, docptr + DOC_FLASHCOMMAND);
++	write_nop(docptr);
++
++	write_addr(doc, docg4_addr);
++
++	write_nop(docptr);
++	writew(DOCG4_CMD_READ2, docptr + DOC_FLASHCOMMAND);
++	write_nop(docptr);
++	write_nop(docptr);
++
++	poll_status(doc);
++}
++
++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 docg4_priv *doc = nand_get_controller_data(nand);
++	void __iomem *docptr = doc->virtadr;
++
++	dev_dbg(doc->dev,
++	      "docg4: %s: g4 addr: %x\n", __func__, docg4_addr);
++	sequence_reset(mtd);
++
++	if (unlikely(reliable_mode)) {
++		writew(DOCG4_SEQ_SETMODE, docptr + DOC_FLASHSEQUENCE);
++		writew(DOCG4_CMD_FAST_MODE, docptr + DOC_FLASHCOMMAND);
++		writew(DOC_CMD_RELIABLE_MODE, docptr + DOC_FLASHCOMMAND);
++		write_nop(docptr);
++	}
++
++	writew(DOCG4_SEQ_PAGEWRITE, docptr + DOC_FLASHSEQUENCE);
++	writew(DOCG4_CMD_PAGEWRITE, docptr + DOC_FLASHCOMMAND);
++	write_nop(docptr);
++	write_addr(doc, docg4_addr);
++	write_nop(docptr);
++	write_nop(docptr);
++	poll_status(doc);
++}
++
++static uint32_t mtd_to_docg4_address(int page, int column)
++{
++	/*
++	 * Convert mtd address to format used by the device, 32 bit packed.
++	 *
++	 * Some notes on G4 addressing... The M-Sys documentation on this device
++	 * claims that pages are 2K in length, and indeed, the format of the
++	 * address used by the device reflects that.  But within each page are
++	 * four 512 byte "sub-pages", each with its own oob data that is
++	 * read/written immediately after the 512 bytes of page data.  This oob
++	 * data contains the ecc bytes for the preceeding 512 bytes.
++	 *
++	 * Rather than tell the mtd nand infrastructure that page size is 2k,
++	 * with four sub-pages each, we engage in a little subterfuge and tell
++	 * the infrastructure code that pages are 512 bytes in size.  This is
++	 * done because during the course of reverse-engineering the device, I
++	 * never observed an instance where an entire 2K "page" was read or
++	 * written as a unit.  Each "sub-page" is always addressed individually,
++	 * its data read/written, and ecc handled before the next "sub-page" is
++	 * addressed.
++	 *
++	 * This requires us to convert addresses passed by the mtd nand
++	 * infrastructure code to those used by the device.
++	 *
++	 * The address that is written to the device consists of four bytes: the
++	 * first two are the 2k page number, and the second is the index into
++	 * the page.  The index is in terms of 16-bit half-words and includes
++	 * the preceeding oob data, so e.g., the index into the second
++	 * "sub-page" is 0x108, and the full device address of the start of mtd
++	 * page 0x201 is 0x00800108.
++	 */
++	int g4_page = page / 4;	                      /* device's 2K page */
++	int g4_index = (page % 4) * 0x108 + column/2; /* offset into page */
++	return (g4_page << 16) | g4_index;	      /* pack */
++}
++
++static void docg4_command(struct mtd_info *mtd, unsigned command, int column,
++			  int page_addr)
++{
++	/* handle standard nand commands */
++
++	struct nand_chip *nand = mtd_to_nand(mtd);
++	struct docg4_priv *doc = nand_get_controller_data(nand);
++	uint32_t g4_addr = mtd_to_docg4_address(page_addr, column);
++
++	dev_dbg(doc->dev, "%s %x, page_addr=%x, column=%x\n",
++	      __func__, command, page_addr, column);
++
++	/*
++	 * Save the command and its arguments.  This enables emulation of
++	 * standard flash devices, and also some optimizations.
++	 */
++	doc->last_command.command = command;
++	doc->last_command.column = column;
++	doc->last_command.page = page_addr;
++
++	switch (command) {
++
++	case NAND_CMD_RESET:
++		reset(mtd);
++		break;
++
++	case NAND_CMD_READ0:
++		read_page_prologue(mtd, g4_addr);
++		break;
++
++	case NAND_CMD_STATUS:
++		/* next call to read_byte() will expect a status */
++		break;
++
++	case NAND_CMD_SEQIN:
++		if (unlikely(reliable_mode)) {
++			uint16_t g4_page = g4_addr >> 16;
++
++			/* writes to odd-numbered 2k pages are invalid */
++			if (g4_page & 0x01)
++				dev_warn(doc->dev,
++					 "invalid reliable mode address\n");
++		}
++
++		write_page_prologue(mtd, g4_addr);
++
++		/* hack for deferred write of oob bytes */
++		if (doc->oob_page == page_addr)
++			memcpy(nand->oob_poi, doc->oob_buf, 16);
++		break;
++
++	case NAND_CMD_PAGEPROG:
++		pageprog(mtd);
++		break;
++
++	/* we don't expect these, based on review of nand_base.c */
++	case NAND_CMD_READOOB:
++	case NAND_CMD_READID:
++	case NAND_CMD_ERASE1:
++	case NAND_CMD_ERASE2:
++		dev_warn(doc->dev, "docg4_command: "
++			 "unexpected nand command 0x%x\n", command);
++		break;
++
++	}
++}
++
++static int read_page(struct mtd_info *mtd, struct nand_chip *nand,
++		     uint8_t *buf, int page, bool use_ecc)
++{
++	struct docg4_priv *doc = nand_get_controller_data(nand);
++	void __iomem *docptr = doc->virtadr;
++	uint16_t status, edc_err, *buf16;
++	int bits_corrected = 0;
++
++	dev_dbg(doc->dev, "%s: page %08x\n", __func__, page);
++
++	writew(DOC_ECCCONF0_READ_MODE |
++	       DOC_ECCCONF0_ECC_ENABLE |
++	       DOC_ECCCONF0_UNKNOWN |
++	       DOCG4_BCH_SIZE,
++	       docptr + DOC_ECCCONF0);
++	write_nop(docptr);
++	write_nop(docptr);
++	write_nop(docptr);
++	write_nop(docptr);
++	write_nop(docptr);
++
++	/* the 1st byte from the I/O reg is a status; the rest is page data */
++	status = readw(docptr + DOC_IOSPACE_DATA);
++	if (status & DOCG4_READ_ERROR) {
++		dev_err(doc->dev,
++			"docg4_read_page: bad status: 0x%02x\n", status);
++		writew(0, docptr + DOC_DATAEND);
++		return -EIO;
++	}
++
++	dev_dbg(doc->dev, "%s: status = 0x%x\n", __func__, status);
++
++	docg4_read_buf(mtd, buf, DOCG4_PAGE_SIZE); /* read the page data */
++
++	/* this device always reads oob after page data */
++	/* first 14 oob bytes read from I/O reg */
++	docg4_read_buf(mtd, nand->oob_poi, 14);
++
++	/* last 2 read from another reg */
++	buf16 = (uint16_t *)(nand->oob_poi + 14);
++	*buf16 = readw(docptr + DOCG4_MYSTERY_REG);
++
++	write_nop(docptr);
++
++	if (likely(use_ecc == true)) {
++
++		/* read the register that tells us if bitflip(s) detected  */
++		edc_err = readw(docptr + DOC_ECCCONF1);
++		edc_err = readw(docptr + DOC_ECCCONF1);
++		dev_dbg(doc->dev, "%s: edc_err = 0x%02x\n", __func__, edc_err);
++
++		/* If bitflips are reported, attempt to correct with ecc */
++		if (edc_err & DOC_ECCCONF1_BCH_SYNDROM_ERR) {
++			bits_corrected = correct_data(mtd, buf, page);
++			if (bits_corrected == -EBADMSG)
++				mtd->ecc_stats.failed++;
++			else
++				mtd->ecc_stats.corrected += bits_corrected;
++		}
++	}
++
++	writew(0, docptr + DOC_DATAEND);
++	if (bits_corrected == -EBADMSG)	  /* uncorrectable errors */
++		return 0;
++	return bits_corrected;
++}
++
++
++static int docg4_read_page_raw(struct mtd_info *mtd, struct nand_chip *nand,
++			       uint8_t *buf, int oob_required, int page)
++{
++	return read_page(mtd, nand, buf, page, false);
++}
++
++static int docg4_read_page(struct mtd_info *mtd, struct nand_chip *nand,
++			   uint8_t *buf, int oob_required, int page)
++{
++	return read_page(mtd, nand, buf, page, true);
++}
++
++static int docg4_read_oob(struct mtd_info *mtd, struct nand_chip *nand,
++			  int page)
++{
++	struct docg4_priv *doc = nand_get_controller_data(nand);
++	void __iomem *docptr = doc->virtadr;
++	uint16_t status;
++
++	dev_dbg(doc->dev, "%s: page %x\n", __func__, page);
++
++	docg4_command(mtd, NAND_CMD_READ0, nand->ecc.size, page);
++
++	writew(DOC_ECCCONF0_READ_MODE | DOCG4_OOB_SIZE, docptr + DOC_ECCCONF0);
++	write_nop(docptr);
++	write_nop(docptr);
++	write_nop(docptr);
++	write_nop(docptr);
++	write_nop(docptr);
++
++	/* the 1st byte from the I/O reg is a status; the rest is oob data */
++	status = readw(docptr + DOC_IOSPACE_DATA);
++	if (status & DOCG4_READ_ERROR) {
++		dev_warn(doc->dev,
++			 "docg4_read_oob failed: status = 0x%02x\n", status);
++		return -EIO;
++	}
++
++	dev_dbg(doc->dev, "%s: status = 0x%x\n", __func__, status);
++
++	docg4_read_buf(mtd, nand->oob_poi, 16);
++
++	write_nop(docptr);
++	write_nop(docptr);
++	write_nop(docptr);
++	writew(0, docptr + DOC_DATAEND);
++	write_nop(docptr);
++
++	return 0;
++}
++
++static int docg4_erase_block(struct mtd_info *mtd, int page)
++{
++	struct nand_chip *nand = mtd_to_nand(mtd);
++	struct docg4_priv *doc = nand_get_controller_data(nand);
++	void __iomem *docptr = doc->virtadr;
++	uint16_t g4_page;
++
++	dev_dbg(doc->dev, "%s: page %04x\n", __func__, page);
++
++	sequence_reset(mtd);
++
++	writew(DOCG4_SEQ_BLOCKERASE, docptr + DOC_FLASHSEQUENCE);
++	writew(DOC_CMD_PROG_BLOCK_ADDR, docptr + DOC_FLASHCOMMAND);
++	write_nop(docptr);
++
++	/* only 2 bytes of address are written to specify erase block */
++	g4_page = (uint16_t)(page / 4);  /* to g4's 2k page addressing */
++	writeb(g4_page & 0xff, docptr + DOC_FLASHADDRESS);
++	g4_page >>= 8;
++	writeb(g4_page & 0xff, docptr + DOC_FLASHADDRESS);
++	write_nop(docptr);
++
++	/* start the erasure */
++	writew(DOC_CMD_ERASECYCLE2, docptr + DOC_FLASHCOMMAND);
++	write_nop(docptr);
++	write_nop(docptr);
++
++	usleep_range(500, 1000); /* erasure is long; take a snooze */
++	poll_status(doc);
++	writew(DOCG4_SEQ_FLUSH, docptr + DOC_FLASHSEQUENCE);
++	writew(DOCG4_CMD_FLUSH, docptr + DOC_FLASHCOMMAND);
++	writew(DOC_ECCCONF0_READ_MODE | 4, docptr + DOC_ECCCONF0);
++	write_nop(docptr);
++	write_nop(docptr);
++	write_nop(docptr);
++	write_nop(docptr);
++	write_nop(docptr);
++
++	read_progstatus(doc);
++
++	writew(0, docptr + DOC_DATAEND);
++	write_nop(docptr);
++	poll_status(doc);
++	write_nop(docptr);
++
++	return nand->waitfunc(mtd, nand);
++}
++
++static int write_page(struct mtd_info *mtd, struct nand_chip *nand,
++		       const uint8_t *buf, bool use_ecc)
++{
++	struct docg4_priv *doc = nand_get_controller_data(nand);
++	void __iomem *docptr = doc->virtadr;
++	uint8_t ecc_buf[8];
++
++	dev_dbg(doc->dev, "%s...\n", __func__);
++
++	writew(DOC_ECCCONF0_ECC_ENABLE |
++	       DOC_ECCCONF0_UNKNOWN |
++	       DOCG4_BCH_SIZE,
++	       docptr + DOC_ECCCONF0);
++	write_nop(docptr);
++
++	/* write the page data */
++	docg4_write_buf16(mtd, buf, DOCG4_PAGE_SIZE);
++
++	/* oob bytes 0 through 5 are written to I/O reg */
++	docg4_write_buf16(mtd, nand->oob_poi, 6);
++
++	/* oob byte 6 written to a separate reg */
++	writew(nand->oob_poi[6], docptr + DOCG4_OOB_6_7);
++
++	write_nop(docptr);
++	write_nop(docptr);
++
++	/* write hw-generated ecc bytes to oob */
++	if (likely(use_ecc == true)) {
++		/* oob byte 7 is hamming code */
++		uint8_t hamming = readb(docptr + DOC_HAMMINGPARITY);
++		hamming = readb(docptr + DOC_HAMMINGPARITY); /* 2nd read */
++		writew(hamming, docptr + DOCG4_OOB_6_7);
++		write_nop(docptr);
++
++		/* read the 7 bch bytes from ecc regs */
++		read_hw_ecc(docptr, ecc_buf);
++		ecc_buf[7] = 0;         /* clear the "page written" flag */
++	}
++
++	/* write user-supplied bytes to oob */
++	else {
++		writew(nand->oob_poi[7], docptr + DOCG4_OOB_6_7);
++		write_nop(docptr);
++		memcpy(ecc_buf, &nand->oob_poi[8], 8);
++	}
++
++	docg4_write_buf16(mtd, ecc_buf, 8);
++	write_nop(docptr);
++	write_nop(docptr);
++	writew(0, docptr + DOC_DATAEND);
++	write_nop(docptr);
++
++	return 0;
++}
++
++static int docg4_write_page_raw(struct mtd_info *mtd, struct nand_chip *nand,
++				const uint8_t *buf, int oob_required, int page)
++{
++	return write_page(mtd, nand, buf, false);
++}
++
++static int docg4_write_page(struct mtd_info *mtd, struct nand_chip *nand,
++			     const uint8_t *buf, int oob_required, int page)
++{
++	return write_page(mtd, nand, buf, true);
++}
++
++static int docg4_write_oob(struct mtd_info *mtd, struct nand_chip *nand,
++			   int page)
++{
++	/*
++	 * Writing oob-only is not really supported, because MLC nand must write
++	 * oob bytes at the same time as page data.  Nonetheless, we save the
++	 * oob buffer contents here, and then write it along with the page data
++	 * if the same page is subsequently written.  This allows user space
++	 * utilities that write the oob data prior to the page data to work
++	 * (e.g., nandwrite).  The disdvantage is that, if the intention was to
++	 * write oob only, the operation is quietly ignored.  Also, oob can get
++	 * corrupted if two concurrent processes are running nandwrite.
++	 */
++
++	/* note that bytes 7..14 are hw generated hamming/ecc and overwritten */
++	struct docg4_priv *doc = nand_get_controller_data(nand);
++	doc->oob_page = page;
++	memcpy(doc->oob_buf, nand->oob_poi, 16);
++	return 0;
++}
++
++static int __init read_factory_bbt(struct mtd_info *mtd)
++{
++	/*
++	 * The device contains a read-only factory bad block table.  Read it and
++	 * update the memory-based bbt accordingly.
++	 */
++
++	struct nand_chip *nand = mtd_to_nand(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;
++	int i, block;
++	__u32 eccfailed_stats = mtd->ecc_stats.failed;
++
++	buf = kzalloc(DOCG4_PAGE_SIZE, GFP_KERNEL);
++	if (buf == NULL)
++		return -ENOMEM;
++
++	read_page_prologue(mtd, g4_addr);
++	docg4_read_page(mtd, nand, buf, 0, DOCG4_FACTORY_BBT_PAGE);
++
++	/*
++	 * If no memory-based bbt was created, exit.  This will happen if module
++	 * parameter ignore_badblocks is set.  Then why even call this function?
++	 * For an unknown reason, block erase always fails if it's the first
++	 * operation after device power-up.  The above read ensures it never is.
++	 * Ugly, I know.
++	 */
++	if (nand->bbt == NULL)  /* no memory-based bbt */
++		goto exit;
++
++	if (mtd->ecc_stats.failed > eccfailed_stats) {
++		/*
++		 * Whoops, an ecc failure ocurred reading the factory bbt.
++		 * It is stored redundantly, so we get another chance.
++		 */
++		eccfailed_stats = mtd->ecc_stats.failed;
++		docg4_read_page(mtd, nand, buf, 0, DOCG4_REDUNDANT_BBT_PAGE);
++		if (mtd->ecc_stats.failed > eccfailed_stats) {
++			dev_warn(doc->dev,
++				 "The factory bbt could not be read!\n");
++			goto exit;
++		}
++	}
++
++	/*
++	 * Parse factory bbt and update memory-based bbt.  Factory bbt format is
++	 * simple: one bit per block, block numbers increase left to right (msb
++	 * to lsb).  Bit clear means bad block.
++	 */
++	for (i = block = 0; block < DOCG4_NUMBLOCKS; block += 8, i++) {
++		int bitnum;
++		unsigned long bits = ~buf[i];
++		for_each_set_bit(bitnum, &bits, 8) {
++			int badblock = block + 7 - bitnum;
++			nand->bbt[badblock / 4] |=
++				0x03 << ((badblock % 4) * 2);
++			mtd->ecc_stats.badblocks++;
++			dev_notice(doc->dev, "factory-marked bad block: %d\n",
++				   badblock);
++		}
++	}
++ exit:
++	kfree(buf);
++	return 0;
++}
++
++static int docg4_block_markbad(struct mtd_info *mtd, loff_t ofs)
++{
++	/*
++	 * Mark a block as bad.  Bad blocks are marked in the oob area of the
++	 * first page of the block.  The default scan_bbt() in the nand
++	 * infrastructure code works fine for building the memory-based bbt
++	 * during initialization, as does the nand infrastructure function that
++	 * checks if a block is bad by reading the bbt.  This function replaces
++	 * the nand default because writes to oob-only are not supported.
++	 */
++
++	int ret, i;
++	uint8_t *buf;
++	struct nand_chip *nand = mtd_to_nand(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);
++	uint32_t g4_addr = mtd_to_docg4_address(page, 0);
++
++	dev_dbg(doc->dev, "%s: %08llx\n", __func__, ofs);
++
++	if (unlikely(ofs & (DOCG4_BLOCK_SIZE - 1)))
++		dev_warn(doc->dev, "%s: ofs %llx not start of block!\n",
++			 __func__, ofs);
++
++	/* allocate blank buffer for page data */
++	buf = kzalloc(DOCG4_PAGE_SIZE, GFP_KERNEL);
++	if (buf == NULL)
++		return -ENOMEM;
++
++	/* write bit-wise negation of pattern to oob buffer */
++	memset(nand->oob_poi, 0xff, mtd->oobsize);
++	for (i = 0; i < bbtd->len; i++)
++		nand->oob_poi[bbtd->offs + i] = ~bbtd->pattern[i];
++
++	/* write first page of block */
++	write_page_prologue(mtd, g4_addr);
++	docg4_write_page(mtd, nand, buf, 1, page);
++	ret = pageprog(mtd);
++
++	kfree(buf);
++
++	return ret;
++}
++
++static int docg4_block_neverbad(struct mtd_info *mtd, loff_t ofs)
++{
++	/* only called when module_param ignore_badblocks is set */
++	return 0;
++}
++
++static int docg4_suspend(struct platform_device *pdev, pm_message_t state)
++{
++	/*
++	 * Put the device into "deep power-down" mode.  Note that CE# must be
++	 * deasserted for this to take effect.  The xscale, e.g., can be
++	 * configured to float this signal when the processor enters power-down,
++	 * and a suitable pull-up ensures its deassertion.
++	 */
++
++	int i;
++	uint8_t pwr_down;
++	struct docg4_priv *doc = platform_get_drvdata(pdev);
++	void __iomem *docptr = doc->virtadr;
++
++	dev_dbg(doc->dev, "%s...\n", __func__);
++
++	/* poll the register that tells us we're ready to go to sleep */
++	for (i = 0; i < 10; i++) {
++		pwr_down = readb(docptr + DOC_POWERMODE);
++		if (pwr_down & DOC_POWERDOWN_READY)
++			break;
++		usleep_range(1000, 4000);
++	}
++
++	if (pwr_down & DOC_POWERDOWN_READY) {
++		dev_err(doc->dev, "suspend failed; "
++			"timeout polling DOC_POWERDOWN_READY\n");
++		return -EIO;
++	}
++
++	writew(DOC_ASICMODE_POWERDOWN | DOC_ASICMODE_MDWREN,
++	       docptr + DOC_ASICMODE);
++	writew(~(DOC_ASICMODE_POWERDOWN | DOC_ASICMODE_MDWREN),
++	       docptr + DOC_ASICMODECONFIRM);
++
++	write_nop(docptr);
++
++	return 0;
++}
++
++static int docg4_resume(struct platform_device *pdev)
++{
++
++	/*
++	 * Exit power-down.  Twelve consecutive reads of the address below
++	 * accomplishes this, assuming CE# has been asserted.
++	 */
++
++	struct docg4_priv *doc = platform_get_drvdata(pdev);
++	void __iomem *docptr = doc->virtadr;
++	int i;
++
++	dev_dbg(doc->dev, "%s...\n", __func__);
++
++	for (i = 0; i < 12; i++)
++		readb(docptr + 0x1fff);
++
++	return 0;
++}
++
++static void __init init_mtd_structs(struct mtd_info *mtd)
++{
++	/* initialize mtd and nand data structures */
++
++	/*
++	 * Note that some of the following initializations are not usually
++	 * required within a nand driver because they are performed by the nand
++	 * infrastructure code as part of nand_scan().  In this case they need
++	 * to be initialized here because we skip call to nand_scan_ident() (the
++	 * first half of nand_scan()).  The call to nand_scan_ident() is skipped
++	 * because for this device the chip id is not read in the manner of a
++	 * standard nand device.  Unfortunately, nand_scan_ident() does other
++	 * things as well, such as call nand_set_defaults().
++	 */
++
++	struct nand_chip *nand = mtd_to_nand(mtd);
++	struct docg4_priv *doc = nand_get_controller_data(nand);
++
++	mtd->size = DOCG4_CHIP_SIZE;
++	mtd->name = "Msys_Diskonchip_G4";
++	mtd->writesize = DOCG4_PAGE_SIZE;
++	mtd->erasesize = DOCG4_BLOCK_SIZE;
++	mtd->oobsize = DOCG4_OOB_SIZE;
++	mtd_set_ooblayout(mtd, &docg4_ooblayout_ops);
++	nand->chipsize = DOCG4_CHIP_SIZE;
++	nand->chip_shift = DOCG4_CHIP_SHIFT;
++	nand->bbt_erase_shift = nand->phys_erase_shift = DOCG4_ERASE_SHIFT;
++	nand->chip_delay = 20;
++	nand->page_shift = DOCG4_PAGE_SHIFT;
++	nand->pagemask = 0x3ffff;
++	nand->badblockpos = NAND_LARGE_BADBLOCK_POS;
++	nand->badblockbits = 8;
++	nand->ecc.mode = NAND_ECC_HW_SYNDROME;
++	nand->ecc.size = DOCG4_PAGE_SIZE;
++	nand->ecc.prepad = 8;
++	nand->ecc.bytes	= 8;
++	nand->ecc.strength = DOCG4_T;
++	nand->options = NAND_BUSWIDTH_16 | NAND_NO_SUBPAGE_WRITE;
++	nand->IO_ADDR_R = nand->IO_ADDR_W = doc->virtadr + DOC_IOSPACE_DATA;
++	nand->controller = &nand->hwcontrol;
++	nand_hw_control_init(nand->controller);
++
++	/* methods */
++	nand->cmdfunc = docg4_command;
++	nand->waitfunc = docg4_wait;
++	nand->select_chip = docg4_select_chip;
++	nand->read_byte = docg4_read_byte;
++	nand->block_markbad = docg4_block_markbad;
++	nand->read_buf = docg4_read_buf;
++	nand->write_buf = docg4_write_buf16;
++	nand->erase = docg4_erase_block;
++	nand->onfi_set_features = nand_onfi_get_set_features_notsupp;
++	nand->onfi_get_features = nand_onfi_get_set_features_notsupp;
++	nand->ecc.read_page = docg4_read_page;
++	nand->ecc.write_page = docg4_write_page;
++	nand->ecc.read_page_raw = docg4_read_page_raw;
++	nand->ecc.write_page_raw = docg4_write_page_raw;
++	nand->ecc.read_oob = docg4_read_oob;
++	nand->ecc.write_oob = docg4_write_oob;
++
++	/*
++	 * The way the nand infrastructure code is written, a memory-based bbt
++	 * is not created if NAND_SKIP_BBTSCAN is set.  With no memory bbt,
++	 * nand->block_bad() is used.  So when ignoring bad blocks, we skip the
++	 * scan and define a dummy block_bad() which always returns 0.
++	 */
++	if (ignore_badblocks) {
++		nand->options |= NAND_SKIP_BBTSCAN;
++		nand->block_bad	= docg4_block_neverbad;
++	}
++
++}
++
++static int __init read_id_reg(struct mtd_info *mtd)
++{
++	struct nand_chip *nand = mtd_to_nand(mtd);
++	struct docg4_priv *doc = nand_get_controller_data(nand);
++	void __iomem *docptr = doc->virtadr;
++	uint16_t id1, id2;
++
++	/* check for presence of g4 chip by reading id registers */
++	id1 = readw(docptr + DOC_CHIPID);
++	id1 = readw(docptr + DOCG4_MYSTERY_REG);
++	id2 = readw(docptr + DOC_CHIPID_INV);
++	id2 = readw(docptr + DOCG4_MYSTERY_REG);
++
++	if (id1 == DOCG4_IDREG1_VALUE && id2 == DOCG4_IDREG2_VALUE) {
++		dev_info(doc->dev,
++			 "NAND device: 128MiB Diskonchip G4 detected\n");
++		return 0;
++	}
++
++	return -ENODEV;
++}
++
++static char const *part_probes[] = { "cmdlinepart", "saftlpart", NULL };
++
++static int __init probe_docg4(struct platform_device *pdev)
++{
++	struct mtd_info *mtd;
++	struct nand_chip *nand;
++	void __iomem *virtadr;
++	struct docg4_priv *doc;
++	int len, retval;
++	struct resource *r;
++	struct device *dev = &pdev->dev;
++
++	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	if (r == NULL) {
++		dev_err(dev, "no io memory resource defined!\n");
++		return -ENODEV;
++	}
++
++	virtadr = ioremap(r->start, resource_size(r));
++	if (!virtadr) {
++		dev_err(dev, "Diskonchip ioremap failed: %pR\n", r);
++		return -EIO;
++	}
++
++	len = sizeof(struct nand_chip) + sizeof(struct docg4_priv);
++	nand = kzalloc(len, GFP_KERNEL);
++	if (nand == NULL) {
++		retval = -ENOMEM;
++		goto fail_unmap;
++	}
++
++	mtd = nand_to_mtd(nand);
++	doc = (struct docg4_priv *) (nand + 1);
++	nand_set_controller_data(nand, doc);
++	mtd->dev.parent = &pdev->dev;
++	doc->virtadr = virtadr;
++	doc->dev = dev;
++
++	init_mtd_structs(mtd);
++
++	/* initialize kernel bch algorithm */
++	doc->bch = init_bch(DOCG4_M, DOCG4_T, DOCG4_PRIMITIVE_POLY);
++	if (doc->bch == NULL) {
++		retval = -EINVAL;
++		goto fail;
++	}
++
++	platform_set_drvdata(pdev, doc);
++
++	reset(mtd);
++	retval = read_id_reg(mtd);
++	if (retval == -ENODEV) {
++		dev_warn(dev, "No diskonchip G4 device found.\n");
++		goto fail;
++	}
++
++	retval = nand_scan_tail(mtd);
++	if (retval)
++		goto fail;
++
++	retval = read_factory_bbt(mtd);
++	if (retval)
++		goto fail;
++
++	retval = mtd_device_parse_register(mtd, part_probes, NULL, NULL, 0);
++	if (retval)
++		goto fail;
++
++	doc->mtd = mtd;
++	return 0;
++
++fail:
++	nand_release(mtd); /* deletes partitions and mtd devices */
++	free_bch(doc->bch);
++	kfree(nand);
++
++fail_unmap:
++	iounmap(virtadr);
++
++	return retval;
++}
++
++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));
++	iounmap(doc->virtadr);
++	return 0;
++}
++
++static struct platform_driver docg4_driver = {
++	.driver		= {
++		.name	= "docg4",
++	},
++	.suspend	= docg4_suspend,
++	.resume		= docg4_resume,
++	.remove		= __exit_p(cleanup_docg4),
++};
++
++module_platform_driver_probe(docg4_driver, probe_docg4);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Mike Dunn");
++MODULE_DESCRIPTION("M-Systems DiskOnChip G4 device driver");
+diff --git a/drivers/mtd/nand/raw/fsl_elbc_nand.c b/drivers/mtd/nand/raw/fsl_elbc_nand.c
+new file mode 100644
+index 0000000..17db2f9
+--- /dev/null
++++ b/drivers/mtd/nand/raw/fsl_elbc_nand.c
+@@ -0,0 +1,979 @@
++/* Freescale Enhanced Local Bus Controller NAND driver
++ *
++ * Copyright © 2006-2007, 2010 Freescale Semiconductor
++ *
++ * Authors: Nick Spence <nick.spence@freescale.com>,
++ *          Scott Wood <scottwood@freescale.com>
++ *          Jack Lan <jack.lan@freescale.com>
++ *          Roy Zang <tie-fei.zang@freescale.com>
++ *
++ * 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.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <linux/string.h>
++#include <linux/ioport.h>
++#include <linux/of_address.h>
++#include <linux/of_platform.h>
++#include <linux/platform_device.h>
++#include <linux/slab.h>
++#include <linux/interrupt.h>
++
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/rawnand.h>
++#include <linux/mtd/nand_ecc.h>
++#include <linux/mtd/partitions.h>
++
++#include <asm/io.h>
++#include <asm/fsl_lbc.h>
++
++#define MAX_BANKS 8
++#define ERR_BYTE 0xFF /* Value returned for read bytes when read failed */
++#define FCM_TIMEOUT_MSECS 500 /* Maximum number of mSecs to wait for FCM */
++
++/* mtd information per set */
++
++struct fsl_elbc_mtd {
++	struct nand_chip chip;
++	struct fsl_lbc_ctrl *ctrl;
++
++	struct device *dev;
++	int bank;               /* Chip select bank number           */
++	u8 __iomem *vbase;      /* Chip select base virtual address  */
++	int page_size;          /* NAND page size (0=512, 1=2048)    */
++	unsigned int fmr;       /* FCM Flash Mode Register value     */
++};
++
++/* Freescale eLBC FCM controller information */
++
++struct fsl_elbc_fcm_ctrl {
++	struct nand_hw_control controller;
++	struct fsl_elbc_mtd *chips[MAX_BANKS];
++
++	u8 __iomem *addr;        /* Address of assigned FCM buffer        */
++	unsigned int page;       /* Last page written to / read from      */
++	unsigned int read_bytes; /* Number of bytes read during command   */
++	unsigned int column;     /* Saved column from SEQIN               */
++	unsigned int index;      /* Pointer to next byte to 'read'        */
++	unsigned int status;     /* status read from LTESR after last op  */
++	unsigned int mdr;        /* UPM/FCM Data Register value           */
++	unsigned int use_mdr;    /* Non zero if the MDR is to be set      */
++	unsigned int oob;        /* Non zero if operating on OOB data     */
++	unsigned int counter;	 /* counter for the initializations	  */
++	unsigned int max_bitflips;  /* Saved during READ0 cmd		  */
++};
++
++/* These map to the positions used by the FCM hardware ECC generator */
++
++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 fsl_elbc_mtd *priv = nand_get_controller_data(chip);
++
++	if (section >= chip->ecc.steps)
++		return -ERANGE;
++
++	oobregion->offset = (16 * section) + 6;
++	if (priv->fmr & FMR_ECCM)
++		oobregion->offset += 2;
++
++	oobregion->length = chip->ecc.bytes;
++
++	return 0;
++}
++
++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 fsl_elbc_mtd *priv = nand_get_controller_data(chip);
++
++	if (section > chip->ecc.steps)
++		return -ERANGE;
++
++	if (!section) {
++		oobregion->offset = 0;
++		if (mtd->writesize > 512)
++			oobregion->offset++;
++		oobregion->length = (priv->fmr & FMR_ECCM) ? 7 : 5;
++	} else {
++		oobregion->offset = (16 * section) -
++				    ((priv->fmr & FMR_ECCM) ? 5 : 7);
++		if (section < chip->ecc.steps)
++			oobregion->length = 13;
++		else
++			oobregion->length = mtd->oobsize - oobregion->offset;
++	}
++
++	return 0;
++}
++
++static const struct mtd_ooblayout_ops fsl_elbc_ooblayout_ops = {
++	.ecc = fsl_elbc_ooblayout_ecc,
++	.free = fsl_elbc_ooblayout_free,
++};
++
++/*
++ * ELBC may use HW ECC, so that OOB offsets, that NAND core uses for bbt,
++ * interfere with ECC positions, that's why we implement our own descriptors.
++ * OOB {11, 5}, works for both SP and LP chips, with ECCM = 1 and ECCM = 0.
++ */
++static u8 bbt_pattern[] = {'B', 'b', 't', '0' };
++static u8 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,
++	.offs =	11,
++	.len = 4,
++	.veroffs = 15,
++	.maxblocks = 4,
++	.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,
++	.offs =	11,
++	.len = 4,
++	.veroffs = 15,
++	.maxblocks = 4,
++	.pattern = mirror_pattern,
++};
++
++/*=================================*/
++
++/*
++ * Set up the FCM hardware block and page address fields, and the fcm
++ * structure addr field to point to the correct FCM buffer in memory
++ */
++static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob)
++{
++	struct nand_chip *chip = mtd_to_nand(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;
++	struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand;
++	int buf_num;
++
++	elbc_fcm_ctrl->page = page_addr;
++
++	if (priv->page_size) {
++		/*
++		 * large page size chip : FPAR[PI] save the lowest 6 bits,
++		 *                        FBAR[BLK] save the other bits.
++		 */
++		out_be32(&lbc->fbar, page_addr >> 6);
++		out_be32(&lbc->fpar,
++		         ((page_addr << FPAR_LP_PI_SHIFT) & FPAR_LP_PI) |
++		         (oob ? FPAR_LP_MS : 0) | column);
++		buf_num = (page_addr & 1) << 2;
++	} else {
++		/*
++		 * small page size chip : FPAR[PI] save the lowest 5 bits,
++		 *                        FBAR[BLK] save the other bits.
++		 */
++		out_be32(&lbc->fbar, page_addr >> 5);
++		out_be32(&lbc->fpar,
++		         ((page_addr << FPAR_SP_PI_SHIFT) & FPAR_SP_PI) |
++		         (oob ? FPAR_SP_MS : 0) | column);
++		buf_num = page_addr & 7;
++	}
++
++	elbc_fcm_ctrl->addr = priv->vbase + buf_num * 1024;
++	elbc_fcm_ctrl->index = column;
++
++	/* for OOB data point to the second half of the buffer */
++	if (oob)
++		elbc_fcm_ctrl->index += priv->page_size ? 2048 : 512;
++
++	dev_vdbg(priv->dev, "set_addr: bank=%d, "
++			    "elbc_fcm_ctrl->addr=0x%p (0x%p), "
++	                    "index %x, pes %d ps %d\n",
++		 buf_num, elbc_fcm_ctrl->addr, priv->vbase,
++		 elbc_fcm_ctrl->index,
++	         chip->phys_erase_shift, chip->page_shift);
++}
++
++/*
++ * execute FCM command and wait for it to complete
++ */
++static int fsl_elbc_run_command(struct mtd_info *mtd)
++{
++	struct nand_chip *chip = mtd_to_nand(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;
++	struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
++
++	/* Setup the FMR[OP] to execute without write protection */
++	out_be32(&lbc->fmr, priv->fmr | 3);
++	if (elbc_fcm_ctrl->use_mdr)
++		out_be32(&lbc->mdr, elbc_fcm_ctrl->mdr);
++
++	dev_vdbg(priv->dev,
++	         "fsl_elbc_run_command: fmr=%08x fir=%08x fcr=%08x\n",
++	         in_be32(&lbc->fmr), in_be32(&lbc->fir), in_be32(&lbc->fcr));
++	dev_vdbg(priv->dev,
++	         "fsl_elbc_run_command: fbar=%08x fpar=%08x "
++	         "fbcr=%08x bank=%d\n",
++	         in_be32(&lbc->fbar), in_be32(&lbc->fpar),
++	         in_be32(&lbc->fbcr), priv->bank);
++
++	ctrl->irq_status = 0;
++	/* execute special operation */
++	out_be32(&lbc->lsor, priv->bank);
++
++	/* wait for FCM complete flag or timeout */
++	wait_event_timeout(ctrl->irq_wait, ctrl->irq_status,
++	                   FCM_TIMEOUT_MSECS * HZ/1000);
++	elbc_fcm_ctrl->status = ctrl->irq_status;
++	/* store mdr value in case it was needed */
++	if (elbc_fcm_ctrl->use_mdr)
++		elbc_fcm_ctrl->mdr = in_be32(&lbc->mdr);
++
++	elbc_fcm_ctrl->use_mdr = 0;
++
++	if (elbc_fcm_ctrl->status != LTESR_CC) {
++		dev_info(priv->dev,
++		         "command failed: fir %x fcr %x status %x mdr %x\n",
++		         in_be32(&lbc->fir), in_be32(&lbc->fcr),
++			 elbc_fcm_ctrl->status, elbc_fcm_ctrl->mdr);
++		return -EIO;
++	}
++
++	if (chip->ecc.mode != NAND_ECC_HW)
++		return 0;
++
++	elbc_fcm_ctrl->max_bitflips = 0;
++
++	if (elbc_fcm_ctrl->read_bytes == mtd->writesize + mtd->oobsize) {
++		uint32_t lteccr = in_be32(&lbc->lteccr);
++		/*
++		 * if command was a full page read and the ELBC
++		 * has the LTECCR register, then bits 12-15 (ppc order) of
++		 * LTECCR indicates which 512 byte sub-pages had fixed errors.
++		 * bits 28-31 are uncorrectable errors, marked elsewhere.
++		 * for small page nand only 1 bit is used.
++		 * if the ELBC doesn't have the lteccr register it reads 0
++		 * FIXME: 4 bits can be corrected on NANDs with 2k pages, so
++		 * count the number of sub-pages with bitflips and update
++		 * ecc_stats.corrected accordingly.
++		 */
++		if (lteccr & 0x000F000F)
++			out_be32(&lbc->lteccr, 0x000F000F); /* clear lteccr */
++		if (lteccr & 0x000F0000) {
++			mtd->ecc_stats.corrected++;
++			elbc_fcm_ctrl->max_bitflips = 1;
++		}
++	}
++
++	return 0;
++}
++
++static void fsl_elbc_do_read(struct nand_chip *chip, int oob)
++{
++	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;
++
++	if (priv->page_size) {
++		out_be32(&lbc->fir,
++		         (FIR_OP_CM0 << FIR_OP0_SHIFT) |
++		         (FIR_OP_CA  << FIR_OP1_SHIFT) |
++		         (FIR_OP_PA  << FIR_OP2_SHIFT) |
++		         (FIR_OP_CM1 << FIR_OP3_SHIFT) |
++		         (FIR_OP_RBW << FIR_OP4_SHIFT));
++
++		out_be32(&lbc->fcr, (NAND_CMD_READ0 << FCR_CMD0_SHIFT) |
++		                    (NAND_CMD_READSTART << FCR_CMD1_SHIFT));
++	} else {
++		out_be32(&lbc->fir,
++		         (FIR_OP_CM0 << FIR_OP0_SHIFT) |
++		         (FIR_OP_CA  << FIR_OP1_SHIFT) |
++		         (FIR_OP_PA  << FIR_OP2_SHIFT) |
++		         (FIR_OP_RBW << FIR_OP3_SHIFT));
++
++		if (oob)
++			out_be32(&lbc->fcr, NAND_CMD_READOOB << FCR_CMD0_SHIFT);
++		else
++			out_be32(&lbc->fcr, NAND_CMD_READ0 << FCR_CMD0_SHIFT);
++	}
++}
++
++/* cmdfunc send commands to the FCM */
++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 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;
++	struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
++
++	elbc_fcm_ctrl->use_mdr = 0;
++
++	/* clear the read buffer */
++	elbc_fcm_ctrl->read_bytes = 0;
++	if (command != NAND_CMD_PAGEPROG)
++		elbc_fcm_ctrl->index = 0;
++
++	switch (command) {
++	/* READ0 and READ1 read the entire buffer to use hardware ECC. */
++	case NAND_CMD_READ1:
++		column += 256;
++
++	/* fall-through */
++	case NAND_CMD_READ0:
++		dev_dbg(priv->dev,
++		        "fsl_elbc_cmdfunc: NAND_CMD_READ0, page_addr:"
++		        " 0x%x, column: 0x%x.\n", page_addr, column);
++
++
++		out_be32(&lbc->fbcr, 0); /* read entire page to enable ECC */
++		set_addr(mtd, 0, page_addr, 0);
++
++		elbc_fcm_ctrl->read_bytes = mtd->writesize + mtd->oobsize;
++		elbc_fcm_ctrl->index += column;
++
++		fsl_elbc_do_read(chip, 0);
++		fsl_elbc_run_command(mtd);
++		return;
++
++	/* READOOB reads only the OOB because no ECC is performed. */
++	case NAND_CMD_READOOB:
++		dev_vdbg(priv->dev,
++		         "fsl_elbc_cmdfunc: NAND_CMD_READOOB, page_addr:"
++			 " 0x%x, column: 0x%x.\n", page_addr, column);
++
++		out_be32(&lbc->fbcr, mtd->oobsize - column);
++		set_addr(mtd, column, page_addr, 1);
++
++		elbc_fcm_ctrl->read_bytes = mtd->writesize + mtd->oobsize;
++
++		fsl_elbc_do_read(chip, 1);
++		fsl_elbc_run_command(mtd);
++		return;
++
++	case NAND_CMD_READID:
++	case NAND_CMD_PARAM:
++		dev_vdbg(priv->dev, "fsl_elbc_cmdfunc: NAND_CMD %x\n", command);
++
++		out_be32(&lbc->fir, (FIR_OP_CM0 << FIR_OP0_SHIFT) |
++		                    (FIR_OP_UA  << FIR_OP1_SHIFT) |
++		                    (FIR_OP_RBW << FIR_OP2_SHIFT));
++		out_be32(&lbc->fcr, command << FCR_CMD0_SHIFT);
++		/*
++		 * although currently it's 8 bytes for READID, we always read
++		 * the maximum 256 bytes(for PARAM)
++		 */
++		out_be32(&lbc->fbcr, 256);
++		elbc_fcm_ctrl->read_bytes = 256;
++		elbc_fcm_ctrl->use_mdr = 1;
++		elbc_fcm_ctrl->mdr = column;
++		set_addr(mtd, 0, 0, 0);
++		fsl_elbc_run_command(mtd);
++		return;
++
++	/* ERASE1 stores the block and page address */
++	case NAND_CMD_ERASE1:
++		dev_vdbg(priv->dev,
++		         "fsl_elbc_cmdfunc: NAND_CMD_ERASE1, "
++		         "page_addr: 0x%x.\n", page_addr);
++		set_addr(mtd, 0, page_addr, 0);
++		return;
++
++	/* ERASE2 uses the block and page address from ERASE1 */
++	case NAND_CMD_ERASE2:
++		dev_vdbg(priv->dev, "fsl_elbc_cmdfunc: NAND_CMD_ERASE2.\n");
++
++		out_be32(&lbc->fir,
++		         (FIR_OP_CM0 << FIR_OP0_SHIFT) |
++		         (FIR_OP_PA  << FIR_OP1_SHIFT) |
++		         (FIR_OP_CM2 << FIR_OP2_SHIFT) |
++		         (FIR_OP_CW1 << FIR_OP3_SHIFT) |
++		         (FIR_OP_RS  << FIR_OP4_SHIFT));
++
++		out_be32(&lbc->fcr,
++		         (NAND_CMD_ERASE1 << FCR_CMD0_SHIFT) |
++		         (NAND_CMD_STATUS << FCR_CMD1_SHIFT) |
++		         (NAND_CMD_ERASE2 << FCR_CMD2_SHIFT));
++
++		out_be32(&lbc->fbcr, 0);
++		elbc_fcm_ctrl->read_bytes = 0;
++		elbc_fcm_ctrl->use_mdr = 1;
++
++		fsl_elbc_run_command(mtd);
++		return;
++
++	/* SEQIN sets up the addr buffer and all registers except the length */
++	case NAND_CMD_SEQIN: {
++		__be32 fcr;
++		dev_vdbg(priv->dev,
++			 "fsl_elbc_cmdfunc: NAND_CMD_SEQIN/PAGE_PROG, "
++		         "page_addr: 0x%x, column: 0x%x.\n",
++		         page_addr, column);
++
++		elbc_fcm_ctrl->column = column;
++		elbc_fcm_ctrl->use_mdr = 1;
++
++		if (column >= mtd->writesize) {
++			/* OOB area */
++			column -= mtd->writesize;
++			elbc_fcm_ctrl->oob = 1;
++		} else {
++			WARN_ON(column != 0);
++			elbc_fcm_ctrl->oob = 0;
++		}
++
++		fcr = (NAND_CMD_STATUS   << FCR_CMD1_SHIFT) |
++		      (NAND_CMD_SEQIN    << FCR_CMD2_SHIFT) |
++		      (NAND_CMD_PAGEPROG << FCR_CMD3_SHIFT);
++
++		if (priv->page_size) {
++			out_be32(&lbc->fir,
++			         (FIR_OP_CM2 << FIR_OP0_SHIFT) |
++			         (FIR_OP_CA  << FIR_OP1_SHIFT) |
++			         (FIR_OP_PA  << FIR_OP2_SHIFT) |
++			         (FIR_OP_WB  << FIR_OP3_SHIFT) |
++			         (FIR_OP_CM3 << FIR_OP4_SHIFT) |
++			         (FIR_OP_CW1 << FIR_OP5_SHIFT) |
++			         (FIR_OP_RS  << FIR_OP6_SHIFT));
++		} else {
++			out_be32(&lbc->fir,
++			         (FIR_OP_CM0 << FIR_OP0_SHIFT) |
++			         (FIR_OP_CM2 << FIR_OP1_SHIFT) |
++			         (FIR_OP_CA  << FIR_OP2_SHIFT) |
++			         (FIR_OP_PA  << FIR_OP3_SHIFT) |
++			         (FIR_OP_WB  << FIR_OP4_SHIFT) |
++			         (FIR_OP_CM3 << FIR_OP5_SHIFT) |
++			         (FIR_OP_CW1 << FIR_OP6_SHIFT) |
++			         (FIR_OP_RS  << FIR_OP7_SHIFT));
++
++			if (elbc_fcm_ctrl->oob)
++				/* OOB area --> READOOB */
++				fcr |= NAND_CMD_READOOB << FCR_CMD0_SHIFT;
++			else
++				/* First 256 bytes --> READ0 */
++				fcr |= NAND_CMD_READ0 << FCR_CMD0_SHIFT;
++		}
++
++		out_be32(&lbc->fcr, fcr);
++		set_addr(mtd, column, page_addr, elbc_fcm_ctrl->oob);
++		return;
++	}
++
++	/* PAGEPROG reuses all of the setup from SEQIN and adds the length */
++	case NAND_CMD_PAGEPROG: {
++		dev_vdbg(priv->dev,
++		         "fsl_elbc_cmdfunc: NAND_CMD_PAGEPROG "
++			 "writing %d bytes.\n", elbc_fcm_ctrl->index);
++
++		/* if the write did not start at 0 or is not a full page
++		 * then set the exact length, otherwise use a full page
++		 * write so the HW generates the ECC.
++		 */
++		if (elbc_fcm_ctrl->oob || elbc_fcm_ctrl->column != 0 ||
++		    elbc_fcm_ctrl->index != mtd->writesize + mtd->oobsize)
++			out_be32(&lbc->fbcr,
++				elbc_fcm_ctrl->index - elbc_fcm_ctrl->column);
++		else
++			out_be32(&lbc->fbcr, 0);
++
++		fsl_elbc_run_command(mtd);
++		return;
++	}
++
++	/* CMD_STATUS must read the status byte while CEB is active */
++	/* Note - it does not wait for the ready line */
++	case NAND_CMD_STATUS:
++		out_be32(&lbc->fir,
++		         (FIR_OP_CM0 << FIR_OP0_SHIFT) |
++		         (FIR_OP_RBW << FIR_OP1_SHIFT));
++		out_be32(&lbc->fcr, NAND_CMD_STATUS << FCR_CMD0_SHIFT);
++		out_be32(&lbc->fbcr, 1);
++		set_addr(mtd, 0, 0, 0);
++		elbc_fcm_ctrl->read_bytes = 1;
++
++		fsl_elbc_run_command(mtd);
++
++		/* The chip always seems to report that it is
++		 * write-protected, even when it is not.
++		 */
++		setbits8(elbc_fcm_ctrl->addr, NAND_STATUS_WP);
++		return;
++
++	/* RESET without waiting for the ready line */
++	case NAND_CMD_RESET:
++		dev_dbg(priv->dev, "fsl_elbc_cmdfunc: NAND_CMD_RESET.\n");
++		out_be32(&lbc->fir, FIR_OP_CM0 << FIR_OP0_SHIFT);
++		out_be32(&lbc->fcr, NAND_CMD_RESET << FCR_CMD0_SHIFT);
++		fsl_elbc_run_command(mtd);
++		return;
++
++	default:
++		dev_err(priv->dev,
++		        "fsl_elbc_cmdfunc: error, unsupported command 0x%x.\n",
++		        command);
++	}
++}
++
++static void fsl_elbc_select_chip(struct mtd_info *mtd, int chip)
++{
++	/* The hardware does not seem to support multiple
++	 * chips per bank.
++	 */
++}
++
++/*
++ * Write buf to the FCM Controller Data Buffer
++ */
++static void fsl_elbc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
++{
++	struct nand_chip *chip = mtd_to_nand(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;
++
++	if (len <= 0) {
++		dev_err(priv->dev, "write_buf of %d bytes", len);
++		elbc_fcm_ctrl->status = 0;
++		return;
++	}
++
++	if ((unsigned int)len > bufsize - elbc_fcm_ctrl->index) {
++		dev_err(priv->dev,
++		        "write_buf beyond end of buffer "
++		        "(%d requested, %u available)\n",
++			len, bufsize - elbc_fcm_ctrl->index);
++		len = bufsize - elbc_fcm_ctrl->index;
++	}
++
++	memcpy_toio(&elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index], buf, len);
++	/*
++	 * This is workaround for the weird elbc hangs during nand write,
++	 * Scott Wood says: "...perhaps difference in how long it takes a
++	 * write to make it through the localbus compared to a write to IMMR
++	 * is causing problems, and sync isn't helping for some reason."
++	 * Reading back the last byte helps though.
++	 */
++	in_8(&elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index] + len - 1);
++
++	elbc_fcm_ctrl->index += len;
++}
++
++/*
++ * read a byte from either the FCM hardware buffer if it has any data left
++ * otherwise issue a command to read a single byte.
++ */
++static u8 fsl_elbc_read_byte(struct mtd_info *mtd)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
++	struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
++
++	/* If there are still bytes in the FCM, then use the next byte. */
++	if (elbc_fcm_ctrl->index < elbc_fcm_ctrl->read_bytes)
++		return in_8(&elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index++]);
++
++	dev_err(priv->dev, "read_byte beyond end of buffer\n");
++	return ERR_BYTE;
++}
++
++/*
++ * Read from the FCM Controller Data Buffer
++ */
++static void fsl_elbc_read_buf(struct mtd_info *mtd, u8 *buf, int len)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
++	struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
++	int avail;
++
++	if (len < 0)
++		return;
++
++	avail = min((unsigned int)len,
++			elbc_fcm_ctrl->read_bytes - elbc_fcm_ctrl->index);
++	memcpy_fromio(buf, &elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index], avail);
++	elbc_fcm_ctrl->index += avail;
++
++	if (len > avail)
++		dev_err(priv->dev,
++		        "read_buf beyond end of buffer "
++		        "(%d requested, %d available)\n",
++		        len, avail);
++}
++
++/* This function is called after Program and Erase Operations to
++ * check for success or failure.
++ */
++static int fsl_elbc_wait(struct mtd_info *mtd, struct nand_chip *chip)
++{
++	struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
++	struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
++
++	if (elbc_fcm_ctrl->status != LTESR_CC)
++		return NAND_STATUS_FAIL;
++
++	/* The chip always seems to report that it is
++	 * write-protected, even when it is not.
++	 */
++	return (elbc_fcm_ctrl->mdr & 0xff) | NAND_STATUS_WP;
++}
++
++static int fsl_elbc_chip_init_tail(struct mtd_info *mtd)
++{
++	struct nand_chip *chip = mtd_to_nand(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;
++	unsigned int al;
++
++	/* calculate FMR Address Length field */
++	al = 0;
++	if (chip->pagemask & 0xffff0000)
++		al++;
++	if (chip->pagemask & 0xff000000)
++		al++;
++
++	priv->fmr |= al << FMR_AL_SHIFT;
++
++	dev_dbg(priv->dev, "fsl_elbc_init: nand->numchips = %d\n",
++	        chip->numchips);
++	dev_dbg(priv->dev, "fsl_elbc_init: nand->chipsize = %lld\n",
++	        chip->chipsize);
++	dev_dbg(priv->dev, "fsl_elbc_init: nand->pagemask = %8x\n",
++	        chip->pagemask);
++	dev_dbg(priv->dev, "fsl_elbc_init: nand->chip_delay = %d\n",
++	        chip->chip_delay);
++	dev_dbg(priv->dev, "fsl_elbc_init: nand->badblockpos = %d\n",
++	        chip->badblockpos);
++	dev_dbg(priv->dev, "fsl_elbc_init: nand->chip_shift = %d\n",
++	        chip->chip_shift);
++	dev_dbg(priv->dev, "fsl_elbc_init: nand->page_shift = %d\n",
++	        chip->page_shift);
++	dev_dbg(priv->dev, "fsl_elbc_init: nand->phys_erase_shift = %d\n",
++	        chip->phys_erase_shift);
++	dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.mode = %d\n",
++	        chip->ecc.mode);
++	dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.steps = %d\n",
++	        chip->ecc.steps);
++	dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.bytes = %d\n",
++	        chip->ecc.bytes);
++	dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.total = %d\n",
++	        chip->ecc.total);
++	dev_dbg(priv->dev, "fsl_elbc_init: mtd->ooblayout = %p\n",
++		mtd->ooblayout);
++	dev_dbg(priv->dev, "fsl_elbc_init: mtd->flags = %08x\n", mtd->flags);
++	dev_dbg(priv->dev, "fsl_elbc_init: mtd->size = %lld\n", mtd->size);
++	dev_dbg(priv->dev, "fsl_elbc_init: mtd->erasesize = %d\n",
++	        mtd->erasesize);
++	dev_dbg(priv->dev, "fsl_elbc_init: mtd->writesize = %d\n",
++	        mtd->writesize);
++	dev_dbg(priv->dev, "fsl_elbc_init: mtd->oobsize = %d\n",
++	        mtd->oobsize);
++
++	/* adjust Option Register and ECC to match Flash page size */
++	if (mtd->writesize == 512) {
++		priv->page_size = 0;
++		clrbits32(&lbc->bank[priv->bank].or, OR_FCM_PGS);
++	} else if (mtd->writesize == 2048) {
++		priv->page_size = 1;
++		setbits32(&lbc->bank[priv->bank].or, OR_FCM_PGS);
++	} else {
++		dev_err(priv->dev,
++		        "fsl_elbc_init: page size %d is not supported\n",
++		        mtd->writesize);
++		return -1;
++	}
++
++	return 0;
++}
++
++static int fsl_elbc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
++			      uint8_t *buf, int oob_required, int page)
++{
++	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;
++
++	fsl_elbc_read_buf(mtd, buf, mtd->writesize);
++	if (oob_required)
++		fsl_elbc_read_buf(mtd, chip->oob_poi, mtd->oobsize);
++
++	if (fsl_elbc_wait(mtd, chip) & NAND_STATUS_FAIL)
++		mtd->ecc_stats.failed++;
++
++	return elbc_fcm_ctrl->max_bitflips;
++}
++
++/* ECC will be calculated automatically, and errors will be detected in
++ * waitfunc.
++ */
++static int fsl_elbc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
++				const uint8_t *buf, int oob_required, int page)
++{
++	fsl_elbc_write_buf(mtd, buf, mtd->writesize);
++	fsl_elbc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
++
++	return 0;
++}
++
++/* ECC will be calculated automatically, and errors will be detected in
++ * waitfunc.
++ */
++static int fsl_elbc_write_subpage(struct mtd_info *mtd, struct nand_chip *chip,
++				uint32_t offset, uint32_t data_len,
++				const uint8_t *buf, int oob_required, int page)
++{
++	fsl_elbc_write_buf(mtd, buf, mtd->writesize);
++	fsl_elbc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
++
++	return 0;
++}
++
++static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv)
++{
++	struct fsl_lbc_ctrl *ctrl = priv->ctrl;
++	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);
++
++	dev_dbg(priv->dev, "eLBC Set Information for bank %d\n", priv->bank);
++
++	/* Fill in fsl_elbc_mtd structure */
++	mtd->dev.parent = priv->dev;
++	nand_set_flash_node(chip, priv->dev->of_node);
++
++	/* set timeout to maximum */
++	priv->fmr = 15 << FMR_CWTO_SHIFT;
++	if (in_be32(&lbc->bank[priv->bank].or) & OR_FCM_PGS)
++		priv->fmr |= FMR_ECCM;
++
++	/* fill in nand_chip structure */
++	/* set up function call table */
++	chip->read_byte = fsl_elbc_read_byte;
++	chip->write_buf = fsl_elbc_write_buf;
++	chip->read_buf = fsl_elbc_read_buf;
++	chip->select_chip = fsl_elbc_select_chip;
++	chip->cmdfunc = fsl_elbc_cmdfunc;
++	chip->waitfunc = fsl_elbc_wait;
++	chip->onfi_set_features = nand_onfi_get_set_features_notsupp;
++	chip->onfi_get_features = nand_onfi_get_set_features_notsupp;
++
++	chip->bbt_td = &bbt_main_descr;
++	chip->bbt_md = &bbt_mirror_descr;
++
++	/* set up nand options */
++	chip->bbt_options = NAND_BBT_USE_FLASH;
++
++	chip->controller = &elbc_fcm_ctrl->controller;
++	nand_set_controller_data(chip, priv);
++
++	chip->ecc.read_page = fsl_elbc_read_page;
++	chip->ecc.write_page = fsl_elbc_write_page;
++	chip->ecc.write_subpage = fsl_elbc_write_subpage;
++
++	/* If CS Base Register selects full hardware ECC then use it */
++	if ((in_be32(&lbc->bank[priv->bank].br) & BR_DECC) ==
++	    BR_DECC_CHK_GEN) {
++		chip->ecc.mode = NAND_ECC_HW;
++		mtd_set_ooblayout(mtd, &fsl_elbc_ooblayout_ops);
++		chip->ecc.size = 512;
++		chip->ecc.bytes = 3;
++		chip->ecc.strength = 1;
++	} else {
++		/* otherwise fall back to default software ECC */
++		chip->ecc.mode = NAND_ECC_SOFT;
++		chip->ecc.algo = NAND_ECC_HAMMING;
++	}
++
++	return 0;
++}
++
++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);
++
++	nand_release(mtd);
++
++	kfree(mtd->name);
++
++	if (priv->vbase)
++		iounmap(priv->vbase);
++
++	elbc_fcm_ctrl->chips[priv->bank] = NULL;
++	kfree(priv);
++	return 0;
++}
++
++static DEFINE_MUTEX(fsl_elbc_nand_mutex);
++
++static int fsl_elbc_nand_probe(struct platform_device *pdev)
++{
++	struct fsl_lbc_regs __iomem *lbc;
++	struct fsl_elbc_mtd *priv;
++	struct resource res;
++	struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl;
++	static const char *part_probe_types[]
++		= { "cmdlinepart", "RedBoot", "ofpart", NULL };
++	int ret;
++	int bank;
++	struct device *dev;
++	struct device_node *node = pdev->dev.of_node;
++	struct mtd_info *mtd;
++
++	if (!fsl_lbc_ctrl_dev || !fsl_lbc_ctrl_dev->regs)
++		return -ENODEV;
++	lbc = fsl_lbc_ctrl_dev->regs;
++	dev = fsl_lbc_ctrl_dev->dev;
++
++	/* get, allocate and map the memory resource */
++	ret = of_address_to_resource(node, 0, &res);
++	if (ret) {
++		dev_err(dev, "failed to get resource\n");
++		return ret;
++	}
++
++	/* find which chip select it is connected to */
++	for (bank = 0; bank < MAX_BANKS; bank++)
++		if ((in_be32(&lbc->bank[bank].br) & BR_V) &&
++		    (in_be32(&lbc->bank[bank].br) & BR_MSEL) == BR_MS_FCM &&
++		    (in_be32(&lbc->bank[bank].br) &
++		     in_be32(&lbc->bank[bank].or) & BR_BA)
++		     == fsl_lbc_addr(res.start))
++			break;
++
++	if (bank >= MAX_BANKS) {
++		dev_err(dev, "address did not match any chip selects\n");
++		return -ENODEV;
++	}
++
++	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
++	if (!priv)
++		return -ENOMEM;
++
++	mutex_lock(&fsl_elbc_nand_mutex);
++	if (!fsl_lbc_ctrl_dev->nand) {
++		elbc_fcm_ctrl = kzalloc(sizeof(*elbc_fcm_ctrl), GFP_KERNEL);
++		if (!elbc_fcm_ctrl) {
++			mutex_unlock(&fsl_elbc_nand_mutex);
++			ret = -ENOMEM;
++			goto err;
++		}
++		elbc_fcm_ctrl->counter++;
++
++		nand_hw_control_init(&elbc_fcm_ctrl->controller);
++		fsl_lbc_ctrl_dev->nand = elbc_fcm_ctrl;
++	} else {
++		elbc_fcm_ctrl = fsl_lbc_ctrl_dev->nand;
++	}
++	mutex_unlock(&fsl_elbc_nand_mutex);
++
++	elbc_fcm_ctrl->chips[bank] = priv;
++	priv->bank = bank;
++	priv->ctrl = fsl_lbc_ctrl_dev;
++	priv->dev = &pdev->dev;
++	dev_set_drvdata(priv->dev, priv);
++
++	priv->vbase = ioremap(res.start, resource_size(&res));
++	if (!priv->vbase) {
++		dev_err(dev, "failed to map chip region\n");
++		ret = -ENOMEM;
++		goto err;
++	}
++
++	mtd = nand_to_mtd(&priv->chip);
++	mtd->name = kasprintf(GFP_KERNEL, "%llx.flash", (u64)res.start);
++	if (!nand_to_mtd(&priv->chip)->name) {
++		ret = -ENOMEM;
++		goto err;
++	}
++
++	ret = fsl_elbc_chip_init(priv);
++	if (ret)
++		goto err;
++
++	ret = nand_scan_ident(mtd, 1, NULL);
++	if (ret)
++		goto err;
++
++	ret = fsl_elbc_chip_init_tail(mtd);
++	if (ret)
++		goto err;
++
++	ret = nand_scan_tail(mtd);
++	if (ret)
++		goto err;
++
++	/* First look for RedBoot table or partitions on the command
++	 * line, these take precedence over device tree information */
++	mtd_device_parse_register(mtd, part_probe_types, NULL,
++				  NULL, 0);
++
++	printk(KERN_INFO "eLBC NAND device at 0x%llx, bank %d\n",
++	       (unsigned long long)res.start, priv->bank);
++	return 0;
++
++err:
++	fsl_elbc_chip_remove(priv);
++	return ret;
++}
++
++static int fsl_elbc_nand_remove(struct platform_device *pdev)
++{
++	struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = fsl_lbc_ctrl_dev->nand;
++	struct fsl_elbc_mtd *priv = dev_get_drvdata(&pdev->dev);
++
++	fsl_elbc_chip_remove(priv);
++
++	mutex_lock(&fsl_elbc_nand_mutex);
++	elbc_fcm_ctrl->counter--;
++	if (!elbc_fcm_ctrl->counter) {
++		fsl_lbc_ctrl_dev->nand = NULL;
++		kfree(elbc_fcm_ctrl);
++	}
++	mutex_unlock(&fsl_elbc_nand_mutex);
++
++	return 0;
++
++}
++
++static const struct of_device_id fsl_elbc_nand_match[] = {
++	{ .compatible = "fsl,elbc-fcm-nand", },
++	{}
++};
++MODULE_DEVICE_TABLE(of, fsl_elbc_nand_match);
++
++static struct platform_driver fsl_elbc_nand_driver = {
++	.driver = {
++		.name = "fsl,elbc-fcm-nand",
++		.of_match_table = fsl_elbc_nand_match,
++	},
++	.probe = fsl_elbc_nand_probe,
++	.remove = fsl_elbc_nand_remove,
++};
++
++module_platform_driver(fsl_elbc_nand_driver);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Freescale");
++MODULE_DESCRIPTION("Freescale Enhanced Local Bus Controller MTD NAND driver");
+diff --git a/drivers/mtd/nand/raw/fsl_ifc_nand.c b/drivers/mtd/nand/raw/fsl_ifc_nand.c
+new file mode 100644
+index 0000000..9e03bac
+--- /dev/null
++++ b/drivers/mtd/nand/raw/fsl_ifc_nand.c
+@@ -0,0 +1,1110 @@
++/*
++ * Freescale Integrated Flash Controller NAND driver
++ *
++ * Copyright 2011-2012 Freescale Semiconductor, Inc
++ *
++ * Author: Dipen Dudhat <Dipen.Dudhat@freescale.com>
++ *
++ * 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.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <linux/of_address.h>
++#include <linux/slab.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/rawnand.h>
++#include <linux/mtd/partitions.h>
++#include <linux/mtd/nand_ecc.h>
++#include <linux/fsl_ifc.h>
++
++#define ERR_BYTE		0xFF /* Value returned for read
++					bytes when read failed	*/
++#define IFC_TIMEOUT_MSECS	500  /* Maximum number of mSecs to wait
++					for IFC NAND Machine	*/
++
++struct fsl_ifc_ctrl;
++
++/* mtd information per set */
++struct fsl_ifc_mtd {
++	struct nand_chip chip;
++	struct fsl_ifc_ctrl *ctrl;
++
++	struct device *dev;
++	int bank;		/* Chip select bank number		*/
++	unsigned int bufnum_mask; /* bufnum = page & bufnum_mask */
++	u8 __iomem *vbase;      /* Chip select base virtual address	*/
++};
++
++/* overview of the fsl ifc controller */
++struct fsl_ifc_nand_ctrl {
++	struct nand_hw_control controller;
++	struct fsl_ifc_mtd *chips[FSL_IFC_BANK_COUNT];
++
++	void __iomem *addr;	/* Address of assigned IFC buffer	*/
++	unsigned int page;	/* Last page written to / read from	*/
++	unsigned int read_bytes;/* Number of bytes read during command	*/
++	unsigned int column;	/* Saved column from SEQIN		*/
++	unsigned int index;	/* Pointer to next byte to 'read'	*/
++	unsigned int oob;	/* Non zero if operating on OOB data	*/
++	unsigned int eccread;	/* Non zero for a full-page ECC read	*/
++	unsigned int counter;	/* counter for the initializations	*/
++	unsigned int max_bitflips;  /* Saved during READ0 cmd		*/
++};
++
++static struct fsl_ifc_nand_ctrl *ifc_nand_ctrl;
++
++/*
++ * Generic flash bbt descriptors
++ */
++static u8 bbt_pattern[] = {'B', 'b', 't', '0' };
++static u8 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,
++	.offs =	2, /* 0 on 8-bit small page */
++	.len = 4,
++	.veroffs = 6,
++	.maxblocks = 4,
++	.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,
++	.offs =	2, /* 0 on 8-bit small page */
++	.len = 4,
++	.veroffs = 6,
++	.maxblocks = 4,
++	.pattern = mirror_pattern,
++};
++
++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);
++
++	if (section)
++		return -ERANGE;
++
++	oobregion->offset = 8;
++	oobregion->length = chip->ecc.total;
++
++	return 0;
++}
++
++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);
++
++	if (section > 1)
++		return -ERANGE;
++
++	if (mtd->writesize == 512 &&
++	    !(chip->options & NAND_BUSWIDTH_16)) {
++		if (!section) {
++			oobregion->offset = 0;
++			oobregion->length = 5;
++		} else {
++			oobregion->offset = 6;
++			oobregion->length = 2;
++		}
++
++		return 0;
++	}
++
++	if (!section) {
++		oobregion->offset = 2;
++		oobregion->length = 6;
++	} else {
++		oobregion->offset = chip->ecc.total + 8;
++		oobregion->length = mtd->oobsize - oobregion->offset;
++	}
++
++	return 0;
++}
++
++static const struct mtd_ooblayout_ops fsl_ifc_ooblayout_ops = {
++	.ecc = fsl_ifc_ooblayout_ecc,
++	.free = fsl_ifc_ooblayout_free,
++};
++
++/*
++ * Set up the IFC hardware block and page address fields, and the ifc nand
++ * structure addr field to point to the correct IFC buffer in memory
++ */
++static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob)
++{
++	struct nand_chip *chip = mtd_to_nand(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;
++	int buf_num;
++
++	ifc_nand_ctrl->page = page_addr;
++	/* Program ROW0/COL0 */
++	ifc_out32(page_addr, &ifc->ifc_nand.row0);
++	ifc_out32((oob ? IFC_NAND_COL_MS : 0) | column, &ifc->ifc_nand.col0);
++
++	buf_num = page_addr & priv->bufnum_mask;
++
++	ifc_nand_ctrl->addr = priv->vbase + buf_num * (mtd->writesize * 2);
++	ifc_nand_ctrl->index = column;
++
++	/* for OOB data point to the second half of the buffer */
++	if (oob)
++		ifc_nand_ctrl->index += mtd->writesize;
++}
++
++/* returns nonzero if entire page is blank */
++static int check_read_ecc(struct mtd_info *mtd, struct fsl_ifc_ctrl *ctrl,
++			  u32 *eccstat, unsigned int bufnum)
++{
++	u32 reg = eccstat[bufnum / 4];
++	int errors;
++
++	errors = (reg >> ((3 - bufnum % 4) * 8)) & 15;
++
++	return errors;
++}
++
++/*
++ * execute IFC NAND command and wait for it to complete
++ */
++static void fsl_ifc_run_command(struct mtd_info *mtd)
++{
++	struct nand_chip *chip = mtd_to_nand(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;
++	struct fsl_ifc_runtime __iomem *ifc = ctrl->rregs;
++	u32 eccstat[4];
++	int i;
++
++	/* set the chip select for NAND Transaction */
++	ifc_out32(priv->bank << IFC_NAND_CSEL_SHIFT,
++		  &ifc->ifc_nand.nand_csel);
++
++	dev_vdbg(priv->dev,
++			"%s: fir0=%08x fcr0=%08x\n",
++			__func__,
++			ifc_in32(&ifc->ifc_nand.nand_fir0),
++			ifc_in32(&ifc->ifc_nand.nand_fcr0));
++
++	ctrl->nand_stat = 0;
++
++	/* start read/write seq */
++	ifc_out32(IFC_NAND_SEQ_STRT_FIR_STRT, &ifc->ifc_nand.nandseq_strt);
++
++	/* wait for command complete flag or timeout */
++	wait_event_timeout(ctrl->nand_wait, ctrl->nand_stat,
++			   msecs_to_jiffies(IFC_TIMEOUT_MSECS));
++
++	/* ctrl->nand_stat will be updated from IRQ context */
++	if (!ctrl->nand_stat)
++		dev_err(priv->dev, "Controller is not responding\n");
++	if (ctrl->nand_stat & IFC_NAND_EVTER_STAT_FTOER)
++		dev_err(priv->dev, "NAND Flash Timeout Error\n");
++	if (ctrl->nand_stat & IFC_NAND_EVTER_STAT_WPER)
++		dev_err(priv->dev, "NAND Flash Write Protect Error\n");
++
++	nctrl->max_bitflips = 0;
++
++	if (nctrl->eccread) {
++		int errors;
++		int bufnum = nctrl->page & priv->bufnum_mask;
++		int sector = bufnum * chip->ecc.steps;
++		int sector_end = sector + chip->ecc.steps - 1;
++		__be32 *eccstat_regs;
++
++		if (ctrl->version >= FSL_IFC_VERSION_2_0_0)
++			eccstat_regs = ifc->ifc_nand.v2_nand_eccstat;
++		else
++			eccstat_regs = ifc->ifc_nand.v1_nand_eccstat;
++
++		for (i = sector / 4; i <= sector_end / 4; i++)
++			eccstat[i] = ifc_in32(&eccstat_regs[i]);
++
++		for (i = sector; i <= sector_end; i++) {
++			errors = check_read_ecc(mtd, ctrl, eccstat, i);
++
++			if (errors == 15) {
++				/*
++				 * Uncorrectable error.
++				 * We'll check for blank pages later.
++				 *
++				 * We disable ECCER reporting due to...
++				 * erratum IFC-A002770 -- so report it now if we
++				 * see an uncorrectable error in ECCSTAT.
++				 */
++				ctrl->nand_stat |= IFC_NAND_EVTER_STAT_ECCER;
++				continue;
++			}
++
++			mtd->ecc_stats.corrected += errors;
++			nctrl->max_bitflips = max_t(unsigned int,
++						    nctrl->max_bitflips,
++						    errors);
++		}
++
++		nctrl->eccread = 0;
++	}
++}
++
++static void fsl_ifc_do_read(struct nand_chip *chip,
++			    int oob,
++			    struct mtd_info *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;
++
++	/* Program FIR/IFC_NAND_FCR0 for Small/Large page */
++	if (mtd->writesize > 512) {
++		ifc_out32((IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
++			  (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) |
++			  (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP2_SHIFT) |
++			  (IFC_FIR_OP_CMD1 << IFC_NAND_FIR0_OP3_SHIFT) |
++			  (IFC_FIR_OP_RBCD << IFC_NAND_FIR0_OP4_SHIFT),
++			  &ifc->ifc_nand.nand_fir0);
++		ifc_out32(0x0, &ifc->ifc_nand.nand_fir1);
++
++		ifc_out32((NAND_CMD_READ0 << IFC_NAND_FCR0_CMD0_SHIFT) |
++			  (NAND_CMD_READSTART << IFC_NAND_FCR0_CMD1_SHIFT),
++			  &ifc->ifc_nand.nand_fcr0);
++	} else {
++		ifc_out32((IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
++			  (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) |
++			  (IFC_FIR_OP_RA0  << IFC_NAND_FIR0_OP2_SHIFT) |
++			  (IFC_FIR_OP_RBCD << IFC_NAND_FIR0_OP3_SHIFT),
++			  &ifc->ifc_nand.nand_fir0);
++		ifc_out32(0x0, &ifc->ifc_nand.nand_fir1);
++
++		if (oob)
++			ifc_out32(NAND_CMD_READOOB <<
++				  IFC_NAND_FCR0_CMD0_SHIFT,
++				  &ifc->ifc_nand.nand_fcr0);
++		else
++			ifc_out32(NAND_CMD_READ0 <<
++				  IFC_NAND_FCR0_CMD0_SHIFT,
++				  &ifc->ifc_nand.nand_fcr0);
++	}
++}
++
++/* 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 fsl_ifc_mtd *priv = nand_get_controller_data(chip);
++	struct fsl_ifc_ctrl *ctrl = priv->ctrl;
++	struct fsl_ifc_runtime __iomem *ifc = ctrl->rregs;
++
++	/* clear the read buffer */
++	ifc_nand_ctrl->read_bytes = 0;
++	if (command != NAND_CMD_PAGEPROG)
++		ifc_nand_ctrl->index = 0;
++
++	switch (command) {
++	/* READ0 read the entire buffer to use hardware ECC. */
++	case NAND_CMD_READ0:
++		ifc_out32(0, &ifc->ifc_nand.nand_fbcr);
++		set_addr(mtd, 0, page_addr, 0);
++
++		ifc_nand_ctrl->read_bytes = mtd->writesize + mtd->oobsize;
++		ifc_nand_ctrl->index += column;
++
++		if (chip->ecc.mode == NAND_ECC_HW)
++			ifc_nand_ctrl->eccread = 1;
++
++		fsl_ifc_do_read(chip, 0, mtd);
++		fsl_ifc_run_command(mtd);
++		return;
++
++	/* READOOB reads only the OOB because no ECC is performed. */
++	case NAND_CMD_READOOB:
++		ifc_out32(mtd->oobsize - column, &ifc->ifc_nand.nand_fbcr);
++		set_addr(mtd, column, page_addr, 1);
++
++		ifc_nand_ctrl->read_bytes = mtd->writesize + mtd->oobsize;
++
++		fsl_ifc_do_read(chip, 1, mtd);
++		fsl_ifc_run_command(mtd);
++
++		return;
++
++	case NAND_CMD_READID:
++	case NAND_CMD_PARAM: {
++		int timing = IFC_FIR_OP_RB;
++		if (command == NAND_CMD_PARAM)
++			timing = IFC_FIR_OP_RBCD;
++
++		ifc_out32((IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
++			  (IFC_FIR_OP_UA  << IFC_NAND_FIR0_OP1_SHIFT) |
++			  (timing << IFC_NAND_FIR0_OP2_SHIFT),
++			  &ifc->ifc_nand.nand_fir0);
++		ifc_out32(command << IFC_NAND_FCR0_CMD0_SHIFT,
++			  &ifc->ifc_nand.nand_fcr0);
++		ifc_out32(column, &ifc->ifc_nand.row3);
++
++		/*
++		 * although currently it's 8 bytes for READID, we always read
++		 * the maximum 256 bytes(for PARAM)
++		 */
++		ifc_out32(256, &ifc->ifc_nand.nand_fbcr);
++		ifc_nand_ctrl->read_bytes = 256;
++
++		set_addr(mtd, 0, 0, 0);
++		fsl_ifc_run_command(mtd);
++		return;
++	}
++
++	/* ERASE1 stores the block and page address */
++	case NAND_CMD_ERASE1:
++		set_addr(mtd, 0, page_addr, 0);
++		return;
++
++	/* ERASE2 uses the block and page address from ERASE1 */
++	case NAND_CMD_ERASE2:
++		ifc_out32((IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
++			  (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP1_SHIFT) |
++			  (IFC_FIR_OP_CMD1 << IFC_NAND_FIR0_OP2_SHIFT),
++			  &ifc->ifc_nand.nand_fir0);
++
++		ifc_out32((NAND_CMD_ERASE1 << IFC_NAND_FCR0_CMD0_SHIFT) |
++			  (NAND_CMD_ERASE2 << IFC_NAND_FCR0_CMD1_SHIFT),
++			  &ifc->ifc_nand.nand_fcr0);
++
++		ifc_out32(0, &ifc->ifc_nand.nand_fbcr);
++		ifc_nand_ctrl->read_bytes = 0;
++		fsl_ifc_run_command(mtd);
++		return;
++
++	/* SEQIN sets up the addr buffer and all registers except the length */
++	case NAND_CMD_SEQIN: {
++		u32 nand_fcr0;
++		ifc_nand_ctrl->column = column;
++		ifc_nand_ctrl->oob = 0;
++
++		if (mtd->writesize > 512) {
++			nand_fcr0 =
++				(NAND_CMD_SEQIN << IFC_NAND_FCR0_CMD0_SHIFT) |
++				(NAND_CMD_STATUS << IFC_NAND_FCR0_CMD1_SHIFT) |
++				(NAND_CMD_PAGEPROG << IFC_NAND_FCR0_CMD2_SHIFT);
++
++			ifc_out32(
++				(IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
++				(IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) |
++				(IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP2_SHIFT) |
++				(IFC_FIR_OP_WBCD << IFC_NAND_FIR0_OP3_SHIFT) |
++				(IFC_FIR_OP_CMD2 << IFC_NAND_FIR0_OP4_SHIFT),
++				&ifc->ifc_nand.nand_fir0);
++			ifc_out32(
++				(IFC_FIR_OP_CW1 << IFC_NAND_FIR1_OP5_SHIFT) |
++				(IFC_FIR_OP_RDSTAT << IFC_NAND_FIR1_OP6_SHIFT) |
++				(IFC_FIR_OP_NOP << IFC_NAND_FIR1_OP7_SHIFT),
++				&ifc->ifc_nand.nand_fir1);
++		} else {
++			nand_fcr0 = ((NAND_CMD_PAGEPROG <<
++					IFC_NAND_FCR0_CMD1_SHIFT) |
++				    (NAND_CMD_SEQIN <<
++					IFC_NAND_FCR0_CMD2_SHIFT) |
++				    (NAND_CMD_STATUS <<
++					IFC_NAND_FCR0_CMD3_SHIFT));
++
++			ifc_out32(
++				(IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
++				(IFC_FIR_OP_CMD2 << IFC_NAND_FIR0_OP1_SHIFT) |
++				(IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP2_SHIFT) |
++				(IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP3_SHIFT) |
++				(IFC_FIR_OP_WBCD << IFC_NAND_FIR0_OP4_SHIFT),
++				&ifc->ifc_nand.nand_fir0);
++			ifc_out32(
++				(IFC_FIR_OP_CMD1 << IFC_NAND_FIR1_OP5_SHIFT) |
++				(IFC_FIR_OP_CW3 << IFC_NAND_FIR1_OP6_SHIFT) |
++				(IFC_FIR_OP_RDSTAT << IFC_NAND_FIR1_OP7_SHIFT) |
++				(IFC_FIR_OP_NOP << IFC_NAND_FIR1_OP8_SHIFT),
++				&ifc->ifc_nand.nand_fir1);
++
++			if (column >= mtd->writesize)
++				nand_fcr0 |=
++				NAND_CMD_READOOB << IFC_NAND_FCR0_CMD0_SHIFT;
++			else
++				nand_fcr0 |=
++				NAND_CMD_READ0 << IFC_NAND_FCR0_CMD0_SHIFT;
++		}
++
++		if (column >= mtd->writesize) {
++			/* OOB area --> READOOB */
++			column -= mtd->writesize;
++			ifc_nand_ctrl->oob = 1;
++		}
++		ifc_out32(nand_fcr0, &ifc->ifc_nand.nand_fcr0);
++		set_addr(mtd, column, page_addr, ifc_nand_ctrl->oob);
++		return;
++	}
++
++	/* PAGEPROG reuses all of the setup from SEQIN and adds the length */
++	case NAND_CMD_PAGEPROG: {
++		if (ifc_nand_ctrl->oob) {
++			ifc_out32(ifc_nand_ctrl->index -
++				  ifc_nand_ctrl->column,
++				  &ifc->ifc_nand.nand_fbcr);
++		} else {
++			ifc_out32(0, &ifc->ifc_nand.nand_fbcr);
++		}
++
++		fsl_ifc_run_command(mtd);
++		return;
++	}
++
++	case NAND_CMD_STATUS: {
++		void __iomem *addr;
++
++		ifc_out32((IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
++			  (IFC_FIR_OP_RB << IFC_NAND_FIR0_OP1_SHIFT),
++			  &ifc->ifc_nand.nand_fir0);
++		ifc_out32(NAND_CMD_STATUS << IFC_NAND_FCR0_CMD0_SHIFT,
++			  &ifc->ifc_nand.nand_fcr0);
++		ifc_out32(1, &ifc->ifc_nand.nand_fbcr);
++		set_addr(mtd, 0, 0, 0);
++		ifc_nand_ctrl->read_bytes = 1;
++
++		fsl_ifc_run_command(mtd);
++
++		/*
++		 * The chip always seems to report that it is
++		 * write-protected, even when it is not.
++		 */
++		addr = ifc_nand_ctrl->addr;
++		if (chip->options & NAND_BUSWIDTH_16)
++			ifc_out16(ifc_in16(addr) | (NAND_STATUS_WP), addr);
++		else
++			ifc_out8(ifc_in8(addr) | (NAND_STATUS_WP), addr);
++		return;
++	}
++
++	case NAND_CMD_RESET:
++		ifc_out32(IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT,
++			  &ifc->ifc_nand.nand_fir0);
++		ifc_out32(NAND_CMD_RESET << IFC_NAND_FCR0_CMD0_SHIFT,
++			  &ifc->ifc_nand.nand_fcr0);
++		fsl_ifc_run_command(mtd);
++		return;
++
++	default:
++		dev_err(priv->dev, "%s: error, unsupported command 0x%x.\n",
++					__func__, command);
++	}
++}
++
++static void fsl_ifc_select_chip(struct mtd_info *mtd, int chip)
++{
++	/* The hardware does not seem to support multiple
++	 * chips per bank.
++	 */
++}
++
++/*
++ * Write buf to the IFC NAND Controller Data Buffer
++ */
++static void fsl_ifc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
++	unsigned int bufsize = mtd->writesize + mtd->oobsize;
++
++	if (len <= 0) {
++		dev_err(priv->dev, "%s: len %d bytes", __func__, len);
++		return;
++	}
++
++	if ((unsigned int)len > bufsize - ifc_nand_ctrl->index) {
++		dev_err(priv->dev,
++			"%s: beyond end of buffer (%d requested, %u available)\n",
++			__func__, len, bufsize - ifc_nand_ctrl->index);
++		len = bufsize - ifc_nand_ctrl->index;
++	}
++
++	memcpy_toio(ifc_nand_ctrl->addr + ifc_nand_ctrl->index, buf, len);
++	ifc_nand_ctrl->index += len;
++}
++
++/*
++ * Read a byte from either the IFC hardware buffer
++ * read function for 8-bit buswidth
++ */
++static uint8_t fsl_ifc_read_byte(struct mtd_info *mtd)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
++	unsigned int offset;
++
++	/*
++	 * If there are still bytes in the IFC buffer, then use the
++	 * next byte.
++	 */
++	if (ifc_nand_ctrl->index < ifc_nand_ctrl->read_bytes) {
++		offset = ifc_nand_ctrl->index++;
++		return ifc_in8(ifc_nand_ctrl->addr + offset);
++	}
++
++	dev_err(priv->dev, "%s: beyond end of buffer\n", __func__);
++	return ERR_BYTE;
++}
++
++/*
++ * Read two bytes from the IFC hardware buffer
++ * read function for 16-bit buswith
++ */
++static uint8_t fsl_ifc_read_byte16(struct mtd_info *mtd)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
++	uint16_t data;
++
++	/*
++	 * If there are still bytes in the IFC buffer, then use the
++	 * next byte.
++	 */
++	if (ifc_nand_ctrl->index < ifc_nand_ctrl->read_bytes) {
++		data = ifc_in16(ifc_nand_ctrl->addr + ifc_nand_ctrl->index);
++		ifc_nand_ctrl->index += 2;
++		return (uint8_t) data;
++	}
++
++	dev_err(priv->dev, "%s: beyond end of buffer\n", __func__);
++	return ERR_BYTE;
++}
++
++/*
++ * Read from the IFC Controller Data Buffer
++ */
++static void fsl_ifc_read_buf(struct mtd_info *mtd, u8 *buf, int len)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
++	int avail;
++
++	if (len < 0) {
++		dev_err(priv->dev, "%s: len %d bytes", __func__, len);
++		return;
++	}
++
++	avail = min((unsigned int)len,
++			ifc_nand_ctrl->read_bytes - ifc_nand_ctrl->index);
++	memcpy_fromio(buf, ifc_nand_ctrl->addr + ifc_nand_ctrl->index, avail);
++	ifc_nand_ctrl->index += avail;
++
++	if (len > avail)
++		dev_err(priv->dev,
++			"%s: beyond end of buffer (%d requested, %d available)\n",
++			__func__, len, avail);
++}
++
++/*
++ * This function is called after Program and Erase Operations to
++ * check for success or failure.
++ */
++static int fsl_ifc_wait(struct mtd_info *mtd, struct nand_chip *chip)
++{
++	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;
++	u32 nand_fsr;
++
++	/* Use READ_STATUS command, but wait for the device to be ready */
++	ifc_out32((IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
++		  (IFC_FIR_OP_RDSTAT << IFC_NAND_FIR0_OP1_SHIFT),
++		  &ifc->ifc_nand.nand_fir0);
++	ifc_out32(NAND_CMD_STATUS << IFC_NAND_FCR0_CMD0_SHIFT,
++		  &ifc->ifc_nand.nand_fcr0);
++	ifc_out32(1, &ifc->ifc_nand.nand_fbcr);
++	set_addr(mtd, 0, 0, 0);
++	ifc_nand_ctrl->read_bytes = 1;
++
++	fsl_ifc_run_command(mtd);
++
++	nand_fsr = ifc_in32(&ifc->ifc_nand.nand_fsr);
++
++	/*
++	 * The chip always seems to report that it is
++	 * write-protected, even when it is not.
++	 */
++	return nand_fsr | NAND_STATUS_WP;
++}
++
++/*
++ * 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)
++{
++	struct mtd_info *mtd = nand_to_mtd(chip);
++	u8 *ecc = chip->oob_poi;
++	const int ecc_size = chip->ecc.bytes;
++	const int pkt_size = chip->ecc.size;
++	int i, res, bitflips = 0;
++	struct mtd_oob_region oobregion = { };
++
++	mtd_ooblayout_ecc(mtd, 0, &oobregion);
++	ecc += oobregion.offset;
++
++	for (i = 0; i < chip->ecc.steps; ++i) {
++		res = nand_check_erased_ecc_chunk(buf, pkt_size, ecc, ecc_size,
++						  NULL, 0,
++						  chip->ecc.strength);
++		if (res < 0)
++			mtd->ecc_stats.failed++;
++		else
++			mtd->ecc_stats.corrected += res;
++
++		bitflips = max(res, bitflips);
++		buf += pkt_size;
++		ecc += ecc_size;
++	}
++
++	return bitflips;
++}
++
++static int fsl_ifc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
++			     uint8_t *buf, int oob_required, int page)
++{
++	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;
++
++	fsl_ifc_read_buf(mtd, buf, mtd->writesize);
++	if (oob_required)
++		fsl_ifc_read_buf(mtd, chip->oob_poi, mtd->oobsize);
++
++	if (ctrl->nand_stat & IFC_NAND_EVTER_STAT_ECCER) {
++		if (!oob_required)
++			fsl_ifc_read_buf(mtd, chip->oob_poi, mtd->oobsize);
++
++		return check_erased_page(chip, buf);
++	}
++
++	if (ctrl->nand_stat != IFC_NAND_EVTER_STAT_OPC)
++		mtd->ecc_stats.failed++;
++
++	return nctrl->max_bitflips;
++}
++
++/* ECC will be calculated automatically, and errors will be detected in
++ * waitfunc.
++ */
++static int fsl_ifc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
++			       const uint8_t *buf, int oob_required, int page)
++{
++	fsl_ifc_write_buf(mtd, buf, mtd->writesize);
++	fsl_ifc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
++
++	return 0;
++}
++
++static int fsl_ifc_chip_init_tail(struct mtd_info *mtd)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
++
++	dev_dbg(priv->dev, "%s: nand->numchips = %d\n", __func__,
++							chip->numchips);
++	dev_dbg(priv->dev, "%s: nand->chipsize = %lld\n", __func__,
++							chip->chipsize);
++	dev_dbg(priv->dev, "%s: nand->pagemask = %8x\n", __func__,
++							chip->pagemask);
++	dev_dbg(priv->dev, "%s: nand->chip_delay = %d\n", __func__,
++							chip->chip_delay);
++	dev_dbg(priv->dev, "%s: nand->badblockpos = %d\n", __func__,
++							chip->badblockpos);
++	dev_dbg(priv->dev, "%s: nand->chip_shift = %d\n", __func__,
++							chip->chip_shift);
++	dev_dbg(priv->dev, "%s: nand->page_shift = %d\n", __func__,
++							chip->page_shift);
++	dev_dbg(priv->dev, "%s: nand->phys_erase_shift = %d\n", __func__,
++							chip->phys_erase_shift);
++	dev_dbg(priv->dev, "%s: nand->ecc.mode = %d\n", __func__,
++							chip->ecc.mode);
++	dev_dbg(priv->dev, "%s: nand->ecc.steps = %d\n", __func__,
++							chip->ecc.steps);
++	dev_dbg(priv->dev, "%s: nand->ecc.bytes = %d\n", __func__,
++							chip->ecc.bytes);
++	dev_dbg(priv->dev, "%s: nand->ecc.total = %d\n", __func__,
++							chip->ecc.total);
++	dev_dbg(priv->dev, "%s: mtd->ooblayout = %p\n", __func__,
++							mtd->ooblayout);
++	dev_dbg(priv->dev, "%s: mtd->flags = %08x\n", __func__, mtd->flags);
++	dev_dbg(priv->dev, "%s: mtd->size = %lld\n", __func__, mtd->size);
++	dev_dbg(priv->dev, "%s: mtd->erasesize = %d\n", __func__,
++							mtd->erasesize);
++	dev_dbg(priv->dev, "%s: mtd->writesize = %d\n", __func__,
++							mtd->writesize);
++	dev_dbg(priv->dev, "%s: mtd->oobsize = %d\n", __func__,
++							mtd->oobsize);
++
++	return 0;
++}
++
++static void fsl_ifc_sram_init(struct fsl_ifc_mtd *priv)
++{
++	struct fsl_ifc_ctrl *ctrl = priv->ctrl;
++	struct fsl_ifc_runtime __iomem *ifc_runtime = ctrl->rregs;
++	struct fsl_ifc_global __iomem *ifc_global = ctrl->gregs;
++	uint32_t csor = 0, csor_8k = 0, csor_ext = 0;
++	uint32_t cs = priv->bank;
++
++	/* Save CSOR and CSOR_ext */
++	csor = ifc_in32(&ifc_global->csor_cs[cs].csor);
++	csor_ext = ifc_in32(&ifc_global->csor_cs[cs].csor_ext);
++
++	/* chage PageSize 8K and SpareSize 1K*/
++	csor_8k = (csor & ~(CSOR_NAND_PGS_MASK)) | 0x0018C000;
++	ifc_out32(csor_8k, &ifc_global->csor_cs[cs].csor);
++	ifc_out32(0x0000400, &ifc_global->csor_cs[cs].csor_ext);
++
++	/* READID */
++	ifc_out32((IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
++		    (IFC_FIR_OP_UA  << IFC_NAND_FIR0_OP1_SHIFT) |
++		    (IFC_FIR_OP_RB << IFC_NAND_FIR0_OP2_SHIFT),
++		    &ifc_runtime->ifc_nand.nand_fir0);
++	ifc_out32(NAND_CMD_READID << IFC_NAND_FCR0_CMD0_SHIFT,
++		    &ifc_runtime->ifc_nand.nand_fcr0);
++	ifc_out32(0x0, &ifc_runtime->ifc_nand.row3);
++
++	ifc_out32(0x0, &ifc_runtime->ifc_nand.nand_fbcr);
++
++	/* Program ROW0/COL0 */
++	ifc_out32(0x0, &ifc_runtime->ifc_nand.row0);
++	ifc_out32(0x0, &ifc_runtime->ifc_nand.col0);
++
++	/* set the chip select for NAND Transaction */
++	ifc_out32(cs << IFC_NAND_CSEL_SHIFT,
++		&ifc_runtime->ifc_nand.nand_csel);
++
++	/* start read seq */
++	ifc_out32(IFC_NAND_SEQ_STRT_FIR_STRT,
++		&ifc_runtime->ifc_nand.nandseq_strt);
++
++	/* wait for command complete flag or timeout */
++	wait_event_timeout(ctrl->nand_wait, ctrl->nand_stat,
++			   msecs_to_jiffies(IFC_TIMEOUT_MSECS));
++
++	if (ctrl->nand_stat != IFC_NAND_EVTER_STAT_OPC)
++		printk(KERN_ERR "fsl-ifc: Failed to Initialise SRAM\n");
++
++	/* Restore CSOR and CSOR_ext */
++	ifc_out32(csor, &ifc_global->csor_cs[cs].csor);
++	ifc_out32(csor_ext, &ifc_global->csor_cs[cs].csor_ext);
++}
++
++static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
++{
++	struct fsl_ifc_ctrl *ctrl = priv->ctrl;
++	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);
++	u32 csor;
++
++	/* Fill in fsl_ifc_mtd structure */
++	mtd->dev.parent = priv->dev;
++	nand_set_flash_node(chip, priv->dev->of_node);
++
++	/* fill in nand_chip structure */
++	/* set up function call table */
++	if ((ifc_in32(&ifc_global->cspr_cs[priv->bank].cspr))
++		& CSPR_PORT_SIZE_16)
++		chip->read_byte = fsl_ifc_read_byte16;
++	else
++		chip->read_byte = fsl_ifc_read_byte;
++
++	chip->write_buf = fsl_ifc_write_buf;
++	chip->read_buf = fsl_ifc_read_buf;
++	chip->select_chip = fsl_ifc_select_chip;
++	chip->cmdfunc = fsl_ifc_cmdfunc;
++	chip->waitfunc = fsl_ifc_wait;
++	chip->onfi_set_features = nand_onfi_get_set_features_notsupp;
++	chip->onfi_get_features = nand_onfi_get_set_features_notsupp;
++
++	chip->bbt_td = &bbt_main_descr;
++	chip->bbt_md = &bbt_mirror_descr;
++
++	ifc_out32(0x0, &ifc_runtime->ifc_nand.ncfgr);
++
++	/* set up nand options */
++	chip->bbt_options = NAND_BBT_USE_FLASH;
++	chip->options = NAND_NO_SUBPAGE_WRITE;
++
++	if (ifc_in32(&ifc_global->cspr_cs[priv->bank].cspr)
++		& CSPR_PORT_SIZE_16) {
++		chip->read_byte = fsl_ifc_read_byte16;
++		chip->options |= NAND_BUSWIDTH_16;
++	} else {
++		chip->read_byte = fsl_ifc_read_byte;
++	}
++
++	chip->controller = &ifc_nand_ctrl->controller;
++	nand_set_controller_data(chip, priv);
++
++	chip->ecc.read_page = fsl_ifc_read_page;
++	chip->ecc.write_page = fsl_ifc_write_page;
++
++	csor = ifc_in32(&ifc_global->csor_cs[priv->bank].csor);
++
++	switch (csor & CSOR_NAND_PGS_MASK) {
++	case CSOR_NAND_PGS_512:
++		if (!(chip->options & NAND_BUSWIDTH_16)) {
++			/* Avoid conflict with bad block marker */
++			bbt_main_descr.offs = 0;
++			bbt_mirror_descr.offs = 0;
++		}
++
++		priv->bufnum_mask = 15;
++		break;
++
++	case CSOR_NAND_PGS_2K:
++		priv->bufnum_mask = 3;
++		break;
++
++	case CSOR_NAND_PGS_4K:
++		priv->bufnum_mask = 1;
++		break;
++
++	case CSOR_NAND_PGS_8K:
++		priv->bufnum_mask = 0;
++		break;
++
++	default:
++		dev_err(priv->dev, "bad csor %#x: bad page size\n", csor);
++		return -ENODEV;
++	}
++
++	/* Must also set CSOR_NAND_ECC_ENC_EN if DEC_EN set */
++	if (csor & CSOR_NAND_ECC_DEC_EN) {
++		chip->ecc.mode = NAND_ECC_HW;
++		mtd_set_ooblayout(mtd, &fsl_ifc_ooblayout_ops);
++
++		/* Hardware generates ECC per 512 Bytes */
++		chip->ecc.size = 512;
++		if ((csor & CSOR_NAND_ECC_MODE_MASK) == CSOR_NAND_ECC_MODE_4) {
++			chip->ecc.bytes = 8;
++			chip->ecc.strength = 4;
++		} else {
++			chip->ecc.bytes = 16;
++			chip->ecc.strength = 8;
++		}
++	} else {
++		chip->ecc.mode = NAND_ECC_SOFT;
++		chip->ecc.algo = NAND_ECC_HAMMING;
++	}
++
++	if (ctrl->version >= FSL_IFC_VERSION_1_1_0)
++		fsl_ifc_sram_init(priv);
++
++	return 0;
++}
++
++static int fsl_ifc_chip_remove(struct fsl_ifc_mtd *priv)
++{
++	struct mtd_info *mtd = nand_to_mtd(&priv->chip);
++
++	nand_release(mtd);
++
++	kfree(mtd->name);
++
++	if (priv->vbase)
++		iounmap(priv->vbase);
++
++	ifc_nand_ctrl->chips[priv->bank] = NULL;
++
++	return 0;
++}
++
++static int match_bank(struct fsl_ifc_global __iomem *ifc_global, int bank,
++		      phys_addr_t addr)
++{
++	u32 cspr = ifc_in32(&ifc_global->cspr_cs[bank].cspr);
++
++	if (!(cspr & CSPR_V))
++		return 0;
++	if ((cspr & CSPR_MSEL) != CSPR_MSEL_NAND)
++		return 0;
++
++	return (cspr & CSPR_BA) == convert_ifc_address(addr);
++}
++
++static DEFINE_MUTEX(fsl_ifc_nand_mutex);
++
++static int fsl_ifc_nand_probe(struct platform_device *dev)
++{
++	struct fsl_ifc_runtime __iomem *ifc;
++	struct fsl_ifc_mtd *priv;
++	struct resource res;
++	static const char *part_probe_types[]
++		= { "cmdlinepart", "RedBoot", "ofpart", NULL };
++	int ret;
++	int bank;
++	struct device_node *node = dev->dev.of_node;
++	struct mtd_info *mtd;
++
++	if (!fsl_ifc_ctrl_dev || !fsl_ifc_ctrl_dev->rregs)
++		return -ENODEV;
++	ifc = fsl_ifc_ctrl_dev->rregs;
++
++	/* get, allocate and map the memory resource */
++	ret = of_address_to_resource(node, 0, &res);
++	if (ret) {
++		dev_err(&dev->dev, "%s: failed to get resource\n", __func__);
++		return ret;
++	}
++
++	/* find which chip select it is connected to */
++	for (bank = 0; bank < fsl_ifc_ctrl_dev->banks; bank++) {
++		if (match_bank(fsl_ifc_ctrl_dev->gregs, bank, res.start))
++			break;
++	}
++
++	if (bank >= fsl_ifc_ctrl_dev->banks) {
++		dev_err(&dev->dev, "%s: address did not match any chip selects\n",
++			__func__);
++		return -ENODEV;
++	}
++
++	priv = devm_kzalloc(&dev->dev, sizeof(*priv), GFP_KERNEL);
++	if (!priv)
++		return -ENOMEM;
++
++	mutex_lock(&fsl_ifc_nand_mutex);
++	if (!fsl_ifc_ctrl_dev->nand) {
++		ifc_nand_ctrl = kzalloc(sizeof(*ifc_nand_ctrl), GFP_KERNEL);
++		if (!ifc_nand_ctrl) {
++			mutex_unlock(&fsl_ifc_nand_mutex);
++			return -ENOMEM;
++		}
++
++		ifc_nand_ctrl->read_bytes = 0;
++		ifc_nand_ctrl->index = 0;
++		ifc_nand_ctrl->addr = NULL;
++		fsl_ifc_ctrl_dev->nand = ifc_nand_ctrl;
++
++		nand_hw_control_init(&ifc_nand_ctrl->controller);
++	} else {
++		ifc_nand_ctrl = fsl_ifc_ctrl_dev->nand;
++	}
++	mutex_unlock(&fsl_ifc_nand_mutex);
++
++	ifc_nand_ctrl->chips[bank] = priv;
++	priv->bank = bank;
++	priv->ctrl = fsl_ifc_ctrl_dev;
++	priv->dev = &dev->dev;
++
++	priv->vbase = ioremap(res.start, resource_size(&res));
++	if (!priv->vbase) {
++		dev_err(priv->dev, "%s: failed to map chip region\n", __func__);
++		ret = -ENOMEM;
++		goto err;
++	}
++
++	dev_set_drvdata(priv->dev, priv);
++
++	ifc_out32(IFC_NAND_EVTER_EN_OPC_EN |
++		  IFC_NAND_EVTER_EN_FTOER_EN |
++		  IFC_NAND_EVTER_EN_WPER_EN,
++		  &ifc->ifc_nand.nand_evter_en);
++
++	/* enable NAND Machine Interrupts */
++	ifc_out32(IFC_NAND_EVTER_INTR_OPCIR_EN |
++		  IFC_NAND_EVTER_INTR_FTOERIR_EN |
++		  IFC_NAND_EVTER_INTR_WPERIR_EN,
++		  &ifc->ifc_nand.nand_evter_intr_en);
++
++	mtd = nand_to_mtd(&priv->chip);
++	mtd->name = kasprintf(GFP_KERNEL, "%llx.flash", (u64)res.start);
++	if (!mtd->name) {
++		ret = -ENOMEM;
++		goto err;
++	}
++
++	ret = fsl_ifc_chip_init(priv);
++	if (ret)
++		goto err;
++
++	ret = nand_scan_ident(mtd, 1, NULL);
++	if (ret)
++		goto err;
++
++	ret = fsl_ifc_chip_init_tail(mtd);
++	if (ret)
++		goto err;
++
++	ret = nand_scan_tail(mtd);
++	if (ret)
++		goto err;
++
++	/* First look for RedBoot table or partitions on the command
++	 * line, these take precedence over device tree information */
++	mtd_device_parse_register(mtd, part_probe_types, NULL, NULL, 0);
++
++	dev_info(priv->dev, "IFC NAND device at 0x%llx, bank %d\n",
++		 (unsigned long long)res.start, priv->bank);
++	return 0;
++
++err:
++	fsl_ifc_chip_remove(priv);
++	return ret;
++}
++
++static int fsl_ifc_nand_remove(struct platform_device *dev)
++{
++	struct fsl_ifc_mtd *priv = dev_get_drvdata(&dev->dev);
++
++	fsl_ifc_chip_remove(priv);
++
++	mutex_lock(&fsl_ifc_nand_mutex);
++	ifc_nand_ctrl->counter--;
++	if (!ifc_nand_ctrl->counter) {
++		fsl_ifc_ctrl_dev->nand = NULL;
++		kfree(ifc_nand_ctrl);
++	}
++	mutex_unlock(&fsl_ifc_nand_mutex);
++
++	return 0;
++}
++
++static const struct of_device_id fsl_ifc_nand_match[] = {
++	{
++		.compatible = "fsl,ifc-nand",
++	},
++	{}
++};
++MODULE_DEVICE_TABLE(of, fsl_ifc_nand_match);
++
++static struct platform_driver fsl_ifc_nand_driver = {
++	.driver = {
++		.name	= "fsl,ifc-nand",
++		.of_match_table = fsl_ifc_nand_match,
++	},
++	.probe       = fsl_ifc_nand_probe,
++	.remove      = fsl_ifc_nand_remove,
++};
++
++module_platform_driver(fsl_ifc_nand_driver);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Freescale");
++MODULE_DESCRIPTION("Freescale Integrated Flash Controller MTD NAND driver");
+diff --git a/drivers/mtd/nand/raw/fsl_upm.c b/drivers/mtd/nand/raw/fsl_upm.c
+new file mode 100644
+index 0000000..a88e2cf
+--- /dev/null
++++ b/drivers/mtd/nand/raw/fsl_upm.c
+@@ -0,0 +1,363 @@
++/*
++ * Freescale UPM NAND driver.
++ *
++ * Copyright © 2007-2008  MontaVista Software, Inc.
++ *
++ * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
++ *
++ * 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/kernel.h>
++#include <linux/module.h>
++#include <linux/delay.h>
++#include <linux/mtd/rawnand.h>
++#include <linux/mtd/nand_ecc.h>
++#include <linux/mtd/partitions.h>
++#include <linux/mtd/mtd.h>
++#include <linux/of_address.h>
++#include <linux/of_platform.h>
++#include <linux/of_gpio.h>
++#include <linux/io.h>
++#include <linux/slab.h>
++#include <asm/fsl_lbc.h>
++
++#define FSL_UPM_WAIT_RUN_PATTERN  0x1
++#define FSL_UPM_WAIT_WRITE_BYTE   0x2
++#define FSL_UPM_WAIT_WRITE_BUFFER 0x4
++
++struct fsl_upm_nand {
++	struct device *dev;
++	struct nand_chip chip;
++	int last_ctrl;
++	struct mtd_partition *parts;
++	struct fsl_upm upm;
++	uint8_t upm_addr_offset;
++	uint8_t upm_cmd_offset;
++	void __iomem *io_base;
++	int rnb_gpio[NAND_MAX_CHIPS];
++	uint32_t mchip_offsets[NAND_MAX_CHIPS];
++	uint32_t mchip_count;
++	uint32_t mchip_number;
++	int chip_delay;
++	uint32_t wait_flags;
++};
++
++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,
++			    chip);
++}
++
++static int fun_chip_ready(struct mtd_info *mtd)
++{
++	struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd);
++
++	if (gpio_get_value(fun->rnb_gpio[fun->mchip_number]))
++		return 1;
++
++	dev_vdbg(fun->dev, "busy\n");
++	return 0;
++}
++
++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);
++		int cnt = 1000000;
++
++		while (--cnt && !fun_chip_ready(mtd))
++			cpu_relax();
++		if (!cnt)
++			dev_err(fun->dev, "tired waiting for RNB\n");
++	} else {
++		ndelay(100);
++	}
++}
++
++static void fun_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd);
++	u32 mar;
++
++	if (!(ctrl & fun->last_ctrl)) {
++		fsl_upm_end_pattern(&fun->upm);
++
++		if (cmd == NAND_CMD_NONE)
++			return;
++
++		fun->last_ctrl = ctrl & (NAND_ALE | NAND_CLE);
++	}
++
++	if (ctrl & NAND_CTRL_CHANGE) {
++		if (ctrl & NAND_ALE)
++			fsl_upm_start_pattern(&fun->upm, fun->upm_addr_offset);
++		else if (ctrl & NAND_CLE)
++			fsl_upm_start_pattern(&fun->upm, fun->upm_cmd_offset);
++	}
++
++	mar = (cmd << (32 - fun->upm.width)) |
++		fun->mchip_offsets[fun->mchip_number];
++	fsl_upm_run_pattern(&fun->upm, chip->IO_ADDR_R, mar);
++
++	if (fun->wait_flags & FSL_UPM_WAIT_RUN_PATTERN)
++		fun_wait_rnb(fun);
++}
++
++static void fun_select_chip(struct mtd_info *mtd, int mchip_nr)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd);
++
++	if (mchip_nr == -1) {
++		chip->cmd_ctrl(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE);
++	} else if (mchip_nr >= 0 && mchip_nr < NAND_MAX_CHIPS) {
++		fun->mchip_number = mchip_nr;
++		chip->IO_ADDR_R = fun->io_base + fun->mchip_offsets[mchip_nr];
++		chip->IO_ADDR_W = chip->IO_ADDR_R;
++	} else {
++		BUG();
++	}
++}
++
++static uint8_t fun_read_byte(struct mtd_info *mtd)
++{
++	struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd);
++
++	return in_8(fun->chip.IO_ADDR_R);
++}
++
++static void fun_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
++{
++	struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd);
++	int i;
++
++	for (i = 0; i < len; i++)
++		buf[i] = in_8(fun->chip.IO_ADDR_R);
++}
++
++static void fun_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
++{
++	struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd);
++	int i;
++
++	for (i = 0; i < len; i++) {
++		out_8(fun->chip.IO_ADDR_W, buf[i]);
++		if (fun->wait_flags & FSL_UPM_WAIT_WRITE_BYTE)
++			fun_wait_rnb(fun);
++	}
++	if (fun->wait_flags & FSL_UPM_WAIT_WRITE_BUFFER)
++		fun_wait_rnb(fun);
++}
++
++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);
++	int ret;
++	struct device_node *flash_np;
++
++	fun->chip.IO_ADDR_R = fun->io_base;
++	fun->chip.IO_ADDR_W = fun->io_base;
++	fun->chip.cmd_ctrl = fun_cmd_ctrl;
++	fun->chip.chip_delay = fun->chip_delay;
++	fun->chip.read_byte = fun_read_byte;
++	fun->chip.read_buf = fun_read_buf;
++	fun->chip.write_buf = fun_write_buf;
++	fun->chip.ecc.mode = NAND_ECC_SOFT;
++	fun->chip.ecc.algo = NAND_ECC_HAMMING;
++	if (fun->mchip_count > 1)
++		fun->chip.select_chip = fun_select_chip;
++
++	if (fun->rnb_gpio[0] >= 0)
++		fun->chip.dev_ready = fun_chip_ready;
++
++	mtd->dev.parent = fun->dev;
++
++	flash_np = of_get_next_child(upm_np, NULL);
++	if (!flash_np)
++		return -ENODEV;
++
++	nand_set_flash_node(&fun->chip, flash_np);
++	mtd->name = kasprintf(GFP_KERNEL, "0x%llx.%s", (u64)io_res->start,
++			      flash_np->name);
++	if (!mtd->name) {
++		ret = -ENOMEM;
++		goto err;
++	}
++
++	ret = nand_scan(mtd, fun->mchip_count);
++	if (ret)
++		goto err;
++
++	ret = mtd_device_register(mtd, NULL, 0);
++err:
++	of_node_put(flash_np);
++	if (ret)
++		kfree(mtd->name);
++	return ret;
++}
++
++static int fun_probe(struct platform_device *ofdev)
++{
++	struct fsl_upm_nand *fun;
++	struct resource io_res;
++	const __be32 *prop;
++	int rnb_gpio;
++	int ret;
++	int size;
++	int i;
++
++	fun = kzalloc(sizeof(*fun), GFP_KERNEL);
++	if (!fun)
++		return -ENOMEM;
++
++	ret = of_address_to_resource(ofdev->dev.of_node, 0, &io_res);
++	if (ret) {
++		dev_err(&ofdev->dev, "can't get IO base\n");
++		goto err1;
++	}
++
++	ret = fsl_upm_find(io_res.start, &fun->upm);
++	if (ret) {
++		dev_err(&ofdev->dev, "can't find UPM\n");
++		goto err1;
++	}
++
++	prop = of_get_property(ofdev->dev.of_node, "fsl,upm-addr-offset",
++			       &size);
++	if (!prop || size != sizeof(uint32_t)) {
++		dev_err(&ofdev->dev, "can't get UPM address offset\n");
++		ret = -EINVAL;
++		goto err1;
++	}
++	fun->upm_addr_offset = *prop;
++
++	prop = of_get_property(ofdev->dev.of_node, "fsl,upm-cmd-offset", &size);
++	if (!prop || size != sizeof(uint32_t)) {
++		dev_err(&ofdev->dev, "can't get UPM command offset\n");
++		ret = -EINVAL;
++		goto err1;
++	}
++	fun->upm_cmd_offset = *prop;
++
++	prop = of_get_property(ofdev->dev.of_node,
++			       "fsl,upm-addr-line-cs-offsets", &size);
++	if (prop && (size / sizeof(uint32_t)) > 0) {
++		fun->mchip_count = size / sizeof(uint32_t);
++		if (fun->mchip_count >= NAND_MAX_CHIPS) {
++			dev_err(&ofdev->dev, "too much multiple chips\n");
++			goto err1;
++		}
++		for (i = 0; i < fun->mchip_count; i++)
++			fun->mchip_offsets[i] = be32_to_cpu(prop[i]);
++	} else {
++		fun->mchip_count = 1;
++	}
++
++	for (i = 0; i < fun->mchip_count; i++) {
++		fun->rnb_gpio[i] = -1;
++		rnb_gpio = of_get_gpio(ofdev->dev.of_node, i);
++		if (rnb_gpio >= 0) {
++			ret = gpio_request(rnb_gpio, dev_name(&ofdev->dev));
++			if (ret) {
++				dev_err(&ofdev->dev,
++					"can't request RNB gpio #%d\n", i);
++				goto err2;
++			}
++			gpio_direction_input(rnb_gpio);
++			fun->rnb_gpio[i] = rnb_gpio;
++		} else if (rnb_gpio == -EINVAL) {
++			dev_err(&ofdev->dev, "RNB gpio #%d is invalid\n", i);
++			goto err2;
++		}
++	}
++
++	prop = of_get_property(ofdev->dev.of_node, "chip-delay", NULL);
++	if (prop)
++		fun->chip_delay = be32_to_cpup(prop);
++	else
++		fun->chip_delay = 50;
++
++	prop = of_get_property(ofdev->dev.of_node, "fsl,upm-wait-flags", &size);
++	if (prop && size == sizeof(uint32_t))
++		fun->wait_flags = be32_to_cpup(prop);
++	else
++		fun->wait_flags = FSL_UPM_WAIT_RUN_PATTERN |
++				  FSL_UPM_WAIT_WRITE_BYTE;
++
++	fun->io_base = devm_ioremap_nocache(&ofdev->dev, io_res.start,
++					    resource_size(&io_res));
++	if (!fun->io_base) {
++		ret = -ENOMEM;
++		goto err2;
++	}
++
++	fun->dev = &ofdev->dev;
++	fun->last_ctrl = NAND_CLE;
++
++	ret = fun_chip_init(fun, ofdev->dev.of_node, &io_res);
++	if (ret)
++		goto err2;
++
++	dev_set_drvdata(&ofdev->dev, fun);
++
++	return 0;
++err2:
++	for (i = 0; i < fun->mchip_count; i++) {
++		if (fun->rnb_gpio[i] < 0)
++			break;
++		gpio_free(fun->rnb_gpio[i]);
++	}
++err1:
++	kfree(fun);
++
++	return ret;
++}
++
++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);
++	int i;
++
++	nand_release(mtd);
++	kfree(mtd->name);
++
++	for (i = 0; i < fun->mchip_count; i++) {
++		if (fun->rnb_gpio[i] < 0)
++			break;
++		gpio_free(fun->rnb_gpio[i]);
++	}
++
++	kfree(fun);
++
++	return 0;
++}
++
++static const struct of_device_id of_fun_match[] = {
++	{ .compatible = "fsl,upm-nand" },
++	{},
++};
++MODULE_DEVICE_TABLE(of, of_fun_match);
++
++static struct platform_driver of_fun_driver = {
++	.driver = {
++		.name = "fsl,upm-nand",
++		.of_match_table = of_fun_match,
++	},
++	.probe		= fun_probe,
++	.remove		= fun_remove,
++};
++
++module_platform_driver(of_fun_driver);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Anton Vorontsov <avorontsov@ru.mvista.com>");
++MODULE_DESCRIPTION("Driver for NAND chips working through Freescale "
++		   "LocalBus User-Programmable Machine");
+diff --git a/drivers/mtd/nand/raw/fsmc_nand.c b/drivers/mtd/nand/raw/fsmc_nand.c
+new file mode 100644
+index 0000000..eac15d9
+--- /dev/null
++++ b/drivers/mtd/nand/raw/fsmc_nand.c
+@@ -0,0 +1,1176 @@
++/*
++ * drivers/mtd/nand/fsmc_nand.c
++ *
++ * ST Microelectronics
++ * Flexible Static Memory Controller (FSMC)
++ * Driver for NAND portions
++ *
++ * Copyright © 2010 ST Microelectronics
++ * Vipin Kumar <vipin.kumar@st.com>
++ * Ashish Priyadarshi
++ *
++ * Based on drivers/mtd/nand/nomadik_nand.c
++ *
++ * This file is licensed under the terms of the GNU General Public
++ * License version 2. This program is licensed "as is" without any
++ * warranty of any kind, whether express or implied.
++ */
++
++#include <linux/clk.h>
++#include <linux/completion.h>
++#include <linux/dmaengine.h>
++#include <linux/dma-direction.h>
++#include <linux/dma-mapping.h>
++#include <linux/err.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/resource.h>
++#include <linux/sched.h>
++#include <linux/types.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/rawnand.h>
++#include <linux/mtd/nand_ecc.h>
++#include <linux/platform_device.h>
++#include <linux/of.h>
++#include <linux/mtd/partitions.h>
++#include <linux/io.h>
++#include <linux/slab.h>
++#include <linux/amba/bus.h>
++#include <mtd/mtd-abi.h>
++
++/* fsmc controller registers for NOR flash */
++#define CTRL			0x0
++	/* ctrl register definitions */
++	#define BANK_ENABLE		(1 << 0)
++	#define MUXED			(1 << 1)
++	#define NOR_DEV			(2 << 2)
++	#define WIDTH_8			(0 << 4)
++	#define WIDTH_16		(1 << 4)
++	#define RSTPWRDWN		(1 << 6)
++	#define WPROT			(1 << 7)
++	#define WRT_ENABLE		(1 << 12)
++	#define WAIT_ENB		(1 << 13)
++
++#define CTRL_TIM		0x4
++	/* ctrl_tim register definitions */
++
++#define FSMC_NOR_BANK_SZ	0x8
++#define FSMC_NOR_REG_SIZE	0x40
++
++#define FSMC_NOR_REG(base, bank, reg)		(base + \
++						FSMC_NOR_BANK_SZ * (bank) + \
++						reg)
++
++/* fsmc controller registers for NAND flash */
++#define PC			0x00
++	/* pc register definitions */
++	#define FSMC_RESET		(1 << 0)
++	#define FSMC_WAITON		(1 << 1)
++	#define FSMC_ENABLE		(1 << 2)
++	#define FSMC_DEVTYPE_NAND	(1 << 3)
++	#define FSMC_DEVWID_8		(0 << 4)
++	#define FSMC_DEVWID_16		(1 << 4)
++	#define FSMC_ECCEN		(1 << 6)
++	#define FSMC_ECCPLEN_512	(0 << 7)
++	#define FSMC_ECCPLEN_256	(1 << 7)
++	#define FSMC_TCLR_1		(1)
++	#define FSMC_TCLR_SHIFT		(9)
++	#define FSMC_TCLR_MASK		(0xF)
++	#define FSMC_TAR_1		(1)
++	#define FSMC_TAR_SHIFT		(13)
++	#define FSMC_TAR_MASK		(0xF)
++#define STS			0x04
++	/* sts register definitions */
++	#define FSMC_CODE_RDY		(1 << 15)
++#define COMM			0x08
++	/* comm register definitions */
++	#define FSMC_TSET_0		0
++	#define FSMC_TSET_SHIFT		0
++	#define FSMC_TSET_MASK		0xFF
++	#define FSMC_TWAIT_6		6
++	#define FSMC_TWAIT_SHIFT	8
++	#define FSMC_TWAIT_MASK		0xFF
++	#define FSMC_THOLD_4		4
++	#define FSMC_THOLD_SHIFT	16
++	#define FSMC_THOLD_MASK		0xFF
++	#define FSMC_THIZ_1		1
++	#define FSMC_THIZ_SHIFT		24
++	#define FSMC_THIZ_MASK		0xFF
++#define ATTRIB			0x0C
++#define IOATA			0x10
++#define ECC1			0x14
++#define ECC2			0x18
++#define ECC3			0x1C
++#define FSMC_NAND_BANK_SZ	0x20
++
++#define FSMC_NAND_REG(base, bank, reg)		(base + FSMC_NOR_REG_SIZE + \
++						(FSMC_NAND_BANK_SZ * (bank)) + \
++						reg)
++
++#define FSMC_BUSY_WAIT_TIMEOUT	(1 * HZ)
++
++struct fsmc_nand_timings {
++	uint8_t tclr;
++	uint8_t tar;
++	uint8_t thiz;
++	uint8_t thold;
++	uint8_t twait;
++	uint8_t tset;
++};
++
++enum access_mode {
++	USE_DMA_ACCESS = 1,
++	USE_WORD_ACCESS,
++};
++
++/**
++ * struct fsmc_nand_data - structure for FSMC NAND device state
++ *
++ * @pid:		Part ID on the AMBA PrimeCell format
++ * @mtd:		MTD info for a NAND flash.
++ * @nand:		Chip related info for a NAND flash.
++ * @partitions:		Partition info for a NAND Flash.
++ * @nr_partitions:	Total number of partition of a NAND flash.
++ *
++ * @bank:		Bank number for probed device.
++ * @clk:		Clock structure for FSMC.
++ *
++ * @read_dma_chan:	DMA channel for read access
++ * @write_dma_chan:	DMA channel for write access to NAND
++ * @dma_access_complete: Completion structure
++ *
++ * @data_pa:		NAND Physical port for Data.
++ * @data_va:		NAND port for Data.
++ * @cmd_va:		NAND port for Command.
++ * @addr_va:		NAND port for Address.
++ * @regs_va:		FSMC regs base address.
++ */
++struct fsmc_nand_data {
++	u32			pid;
++	struct nand_chip	nand;
++
++	unsigned int		bank;
++	struct device		*dev;
++	enum access_mode	mode;
++	struct clk		*clk;
++
++	/* DMA related objects */
++	struct dma_chan		*read_dma_chan;
++	struct dma_chan		*write_dma_chan;
++	struct completion	dma_access_complete;
++
++	struct fsmc_nand_timings *dev_timings;
++
++	dma_addr_t		data_pa;
++	void __iomem		*data_va;
++	void __iomem		*cmd_va;
++	void __iomem		*addr_va;
++	void __iomem		*regs_va;
++};
++
++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);
++
++	if (section >= chip->ecc.steps)
++		return -ERANGE;
++
++	oobregion->offset = (section * 16) + 2;
++	oobregion->length = 3;
++
++	return 0;
++}
++
++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);
++
++	if (section >= chip->ecc.steps)
++		return -ERANGE;
++
++	oobregion->offset = (section * 16) + 8;
++
++	if (section < chip->ecc.steps - 1)
++		oobregion->length = 8;
++	else
++		oobregion->length = mtd->oobsize - oobregion->offset;
++
++	return 0;
++}
++
++static const struct mtd_ooblayout_ops fsmc_ecc1_ooblayout_ops = {
++	.ecc = fsmc_ecc1_ooblayout_ecc,
++	.free = fsmc_ecc1_ooblayout_free,
++};
++
++/*
++ * ECC placement definitions in oobfree type format.
++ * There are 13 bytes of ecc for every 512 byte block and it has to be read
++ * consecutively and immediately after the 512 byte data block for hardware to
++ * generate the error bit offsets in 512 byte data.
++ */
++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);
++
++	if (section >= chip->ecc.steps)
++		return -ERANGE;
++
++	oobregion->length = chip->ecc.bytes;
++
++	if (!section && mtd->writesize <= 512)
++		oobregion->offset = 0;
++	else
++		oobregion->offset = (section * 16) + 2;
++
++	return 0;
++}
++
++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);
++
++	if (section >= chip->ecc.steps)
++		return -ERANGE;
++
++	oobregion->offset = (section * 16) + 15;
++
++	if (section < chip->ecc.steps - 1)
++		oobregion->length = 3;
++	else
++		oobregion->length = mtd->oobsize - oobregion->offset;
++
++	return 0;
++}
++
++static const struct mtd_ooblayout_ops fsmc_ecc4_ooblayout_ops = {
++	.ecc = fsmc_ecc4_ooblayout_ecc,
++	.free = fsmc_ecc4_ooblayout_free,
++};
++
++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);
++}
++
++/*
++ * fsmc_cmd_ctrl - For facilitaing Hardware access
++ * This routine allows hardware specific access to control-lines(ALE,CLE)
++ */
++static void fsmc_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
++{
++	struct nand_chip *this = mtd_to_nand(mtd);
++	struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
++	void __iomem *regs = host->regs_va;
++	unsigned int bank = host->bank;
++
++	if (ctrl & NAND_CTRL_CHANGE) {
++		u32 pc;
++
++		if (ctrl & NAND_CLE) {
++			this->IO_ADDR_R = host->cmd_va;
++			this->IO_ADDR_W = host->cmd_va;
++		} else if (ctrl & NAND_ALE) {
++			this->IO_ADDR_R = host->addr_va;
++			this->IO_ADDR_W = host->addr_va;
++		} else {
++			this->IO_ADDR_R = host->data_va;
++			this->IO_ADDR_W = host->data_va;
++		}
++
++		pc = readl(FSMC_NAND_REG(regs, bank, PC));
++		if (ctrl & NAND_NCE)
++			pc |= FSMC_ENABLE;
++		else
++			pc &= ~FSMC_ENABLE;
++		writel_relaxed(pc, FSMC_NAND_REG(regs, bank, PC));
++	}
++
++	mb();
++
++	if (cmd != NAND_CMD_NONE)
++		writeb_relaxed(cmd, this->IO_ADDR_W);
++}
++
++/*
++ * fsmc_nand_setup - FSMC (Flexible Static Memory Controller) init routine
++ *
++ * This routine initializes timing parameters related to NAND memory access in
++ * FSMC registers
++ */
++static void fsmc_nand_setup(struct fsmc_nand_data *host,
++			    struct fsmc_nand_timings *tims)
++{
++	uint32_t value = FSMC_DEVTYPE_NAND | FSMC_ENABLE | FSMC_WAITON;
++	uint32_t tclr, tar, thiz, thold, twait, tset;
++	unsigned int bank = host->bank;
++	void __iomem *regs = host->regs_va;
++
++	tclr = (tims->tclr & FSMC_TCLR_MASK) << FSMC_TCLR_SHIFT;
++	tar = (tims->tar & FSMC_TAR_MASK) << FSMC_TAR_SHIFT;
++	thiz = (tims->thiz & FSMC_THIZ_MASK) << FSMC_THIZ_SHIFT;
++	thold = (tims->thold & FSMC_THOLD_MASK) << FSMC_THOLD_SHIFT;
++	twait = (tims->twait & FSMC_TWAIT_MASK) << FSMC_TWAIT_SHIFT;
++	tset = (tims->tset & FSMC_TSET_MASK) << FSMC_TSET_SHIFT;
++
++	if (host->nand.options & NAND_BUSWIDTH_16)
++		writel_relaxed(value | FSMC_DEVWID_16,
++				FSMC_NAND_REG(regs, bank, PC));
++	else
++		writel_relaxed(value | FSMC_DEVWID_8,
++				FSMC_NAND_REG(regs, bank, PC));
++
++	writel_relaxed(readl(FSMC_NAND_REG(regs, bank, PC)) | tclr | tar,
++			FSMC_NAND_REG(regs, bank, PC));
++	writel_relaxed(thiz | thold | twait | tset,
++			FSMC_NAND_REG(regs, bank, COMM));
++	writel_relaxed(thiz | thold | twait | tset,
++			FSMC_NAND_REG(regs, bank, ATTRIB));
++}
++
++static int fsmc_calc_timings(struct fsmc_nand_data *host,
++			     const struct nand_sdr_timings *sdrt,
++			     struct fsmc_nand_timings *tims)
++{
++	unsigned long hclk = clk_get_rate(host->clk);
++	unsigned long hclkn = NSEC_PER_SEC / hclk;
++	uint32_t thiz, thold, twait, tset;
++
++	if (sdrt->tRC_min < 30000)
++		return -EOPNOTSUPP;
++
++	tims->tar = DIV_ROUND_UP(sdrt->tAR_min / 1000, hclkn) - 1;
++	if (tims->tar > FSMC_TAR_MASK)
++		tims->tar = FSMC_TAR_MASK;
++	tims->tclr = DIV_ROUND_UP(sdrt->tCLR_min / 1000, hclkn) - 1;
++	if (tims->tclr > FSMC_TCLR_MASK)
++		tims->tclr = FSMC_TCLR_MASK;
++
++	thiz = sdrt->tCS_min - sdrt->tWP_min;
++	tims->thiz = DIV_ROUND_UP(thiz / 1000, hclkn);
++
++	thold = sdrt->tDH_min;
++	if (thold < sdrt->tCH_min)
++		thold = sdrt->tCH_min;
++	if (thold < sdrt->tCLH_min)
++		thold = sdrt->tCLH_min;
++	if (thold < sdrt->tWH_min)
++		thold = sdrt->tWH_min;
++	if (thold < sdrt->tALH_min)
++		thold = sdrt->tALH_min;
++	if (thold < sdrt->tREH_min)
++		thold = sdrt->tREH_min;
++	tims->thold = DIV_ROUND_UP(thold / 1000, hclkn);
++	if (tims->thold == 0)
++		tims->thold = 1;
++	else if (tims->thold > FSMC_THOLD_MASK)
++		tims->thold = FSMC_THOLD_MASK;
++
++	twait = max(sdrt->tRP_min, sdrt->tWP_min);
++	tims->twait = DIV_ROUND_UP(twait / 1000, hclkn) - 1;
++	if (tims->twait == 0)
++		tims->twait = 1;
++	else if (tims->twait > FSMC_TWAIT_MASK)
++		tims->twait = FSMC_TWAIT_MASK;
++
++	tset = max(sdrt->tCS_min - sdrt->tWP_min,
++		   sdrt->tCEA_max - sdrt->tREA_max);
++	tims->tset = DIV_ROUND_UP(tset / 1000, hclkn) - 1;
++	if (tims->tset == 0)
++		tims->tset = 1;
++	else if (tims->tset > FSMC_TSET_MASK)
++		tims->tset = FSMC_TSET_MASK;
++
++	return 0;
++}
++
++static int fsmc_setup_data_interface(struct mtd_info *mtd, int csline,
++				     const struct nand_data_interface *conf)
++{
++	struct nand_chip *nand = mtd_to_nand(mtd);
++	struct fsmc_nand_data *host = nand_get_controller_data(nand);
++	struct fsmc_nand_timings tims;
++	const struct nand_sdr_timings *sdrt;
++	int ret;
++
++	sdrt = nand_get_sdr_timings(conf);
++	if (IS_ERR(sdrt))
++		return PTR_ERR(sdrt);
++
++	ret = fsmc_calc_timings(host, sdrt, &tims);
++	if (ret)
++		return ret;
++
++	if (csline == NAND_DATA_IFACE_CHECK_ONLY)
++		return 0;
++
++	fsmc_nand_setup(host, &tims);
++
++	return 0;
++}
++
++/*
++ * fsmc_enable_hwecc - Enables Hardware ECC through FSMC registers
++ */
++static void fsmc_enable_hwecc(struct mtd_info *mtd, int mode)
++{
++	struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
++	void __iomem *regs = host->regs_va;
++	uint32_t bank = host->bank;
++
++	writel_relaxed(readl(FSMC_NAND_REG(regs, bank, PC)) & ~FSMC_ECCPLEN_256,
++			FSMC_NAND_REG(regs, bank, PC));
++	writel_relaxed(readl(FSMC_NAND_REG(regs, bank, PC)) & ~FSMC_ECCEN,
++			FSMC_NAND_REG(regs, bank, PC));
++	writel_relaxed(readl(FSMC_NAND_REG(regs, bank, PC)) | FSMC_ECCEN,
++			FSMC_NAND_REG(regs, bank, PC));
++}
++
++/*
++ * fsmc_read_hwecc_ecc4 - Hardware ECC calculator for ecc4 option supported by
++ * FSMC. ECC is 13 bytes for 512 bytes of data (supports error correction up to
++ * max of 8-bits)
++ */
++static int fsmc_read_hwecc_ecc4(struct mtd_info *mtd, const uint8_t *data,
++				uint8_t *ecc)
++{
++	struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
++	void __iomem *regs = host->regs_va;
++	uint32_t bank = host->bank;
++	uint32_t ecc_tmp;
++	unsigned long deadline = jiffies + FSMC_BUSY_WAIT_TIMEOUT;
++
++	do {
++		if (readl_relaxed(FSMC_NAND_REG(regs, bank, STS)) & FSMC_CODE_RDY)
++			break;
++		else
++			cond_resched();
++	} while (!time_after_eq(jiffies, deadline));
++
++	if (time_after_eq(jiffies, deadline)) {
++		dev_err(host->dev, "calculate ecc timed out\n");
++		return -ETIMEDOUT;
++	}
++
++	ecc_tmp = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC1));
++	ecc[0] = (uint8_t) (ecc_tmp >> 0);
++	ecc[1] = (uint8_t) (ecc_tmp >> 8);
++	ecc[2] = (uint8_t) (ecc_tmp >> 16);
++	ecc[3] = (uint8_t) (ecc_tmp >> 24);
++
++	ecc_tmp = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC2));
++	ecc[4] = (uint8_t) (ecc_tmp >> 0);
++	ecc[5] = (uint8_t) (ecc_tmp >> 8);
++	ecc[6] = (uint8_t) (ecc_tmp >> 16);
++	ecc[7] = (uint8_t) (ecc_tmp >> 24);
++
++	ecc_tmp = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC3));
++	ecc[8] = (uint8_t) (ecc_tmp >> 0);
++	ecc[9] = (uint8_t) (ecc_tmp >> 8);
++	ecc[10] = (uint8_t) (ecc_tmp >> 16);
++	ecc[11] = (uint8_t) (ecc_tmp >> 24);
++
++	ecc_tmp = readl_relaxed(FSMC_NAND_REG(regs, bank, STS));
++	ecc[12] = (uint8_t) (ecc_tmp >> 16);
++
++	return 0;
++}
++
++/*
++ * fsmc_read_hwecc_ecc1 - Hardware ECC calculator for ecc1 option supported by
++ * FSMC. ECC is 3 bytes for 512 bytes of data (supports error correction up to
++ * max of 1-bit)
++ */
++static int fsmc_read_hwecc_ecc1(struct mtd_info *mtd, const uint8_t *data,
++				uint8_t *ecc)
++{
++	struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
++	void __iomem *regs = host->regs_va;
++	uint32_t bank = host->bank;
++	uint32_t ecc_tmp;
++
++	ecc_tmp = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC1));
++	ecc[0] = (uint8_t) (ecc_tmp >> 0);
++	ecc[1] = (uint8_t) (ecc_tmp >> 8);
++	ecc[2] = (uint8_t) (ecc_tmp >> 16);
++
++	return 0;
++}
++
++/* Count the number of 0's in buff upto a max of max_bits */
++static int count_written_bits(uint8_t *buff, int size, int max_bits)
++{
++	int k, written_bits = 0;
++
++	for (k = 0; k < size; k++) {
++		written_bits += hweight8(~buff[k]);
++		if (written_bits > max_bits)
++			break;
++	}
++
++	return written_bits;
++}
++
++static void dma_complete(void *param)
++{
++	struct fsmc_nand_data *host = param;
++
++	complete(&host->dma_access_complete);
++}
++
++static int dma_xfer(struct fsmc_nand_data *host, void *buffer, int len,
++		enum dma_data_direction direction)
++{
++	struct dma_chan *chan;
++	struct dma_device *dma_dev;
++	struct dma_async_tx_descriptor *tx;
++	dma_addr_t dma_dst, dma_src, dma_addr;
++	dma_cookie_t cookie;
++	unsigned long flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
++	int ret;
++	unsigned long time_left;
++
++	if (direction == DMA_TO_DEVICE)
++		chan = host->write_dma_chan;
++	else if (direction == DMA_FROM_DEVICE)
++		chan = host->read_dma_chan;
++	else
++		return -EINVAL;
++
++	dma_dev = chan->device;
++	dma_addr = dma_map_single(dma_dev->dev, buffer, len, direction);
++
++	if (direction == DMA_TO_DEVICE) {
++		dma_src = dma_addr;
++		dma_dst = host->data_pa;
++	} else {
++		dma_src = host->data_pa;
++		dma_dst = dma_addr;
++	}
++
++	tx = dma_dev->device_prep_dma_memcpy(chan, dma_dst, dma_src,
++			len, flags);
++	if (!tx) {
++		dev_err(host->dev, "device_prep_dma_memcpy error\n");
++		ret = -EIO;
++		goto unmap_dma;
++	}
++
++	tx->callback = dma_complete;
++	tx->callback_param = host;
++	cookie = tx->tx_submit(tx);
++
++	ret = dma_submit_error(cookie);
++	if (ret) {
++		dev_err(host->dev, "dma_submit_error %d\n", cookie);
++		goto unmap_dma;
++	}
++
++	dma_async_issue_pending(chan);
++
++	time_left =
++	wait_for_completion_timeout(&host->dma_access_complete,
++				msecs_to_jiffies(3000));
++	if (time_left == 0) {
++		dmaengine_terminate_all(chan);
++		dev_err(host->dev, "wait_for_completion_timeout\n");
++		ret = -ETIMEDOUT;
++		goto unmap_dma;
++	}
++
++	ret = 0;
++
++unmap_dma:
++	dma_unmap_single(dma_dev->dev, dma_addr, len, direction);
++
++	return ret;
++}
++
++/*
++ * fsmc_write_buf - write buffer to chip
++ * @mtd:	MTD device structure
++ * @buf:	data buffer
++ * @len:	number of bytes to write
++ */
++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);
++
++	if (IS_ALIGNED((uint32_t)buf, sizeof(uint32_t)) &&
++			IS_ALIGNED(len, sizeof(uint32_t))) {
++		uint32_t *p = (uint32_t *)buf;
++		len = len >> 2;
++		for (i = 0; i < len; i++)
++			writel_relaxed(p[i], chip->IO_ADDR_W);
++	} else {
++		for (i = 0; i < len; i++)
++			writeb_relaxed(buf[i], chip->IO_ADDR_W);
++	}
++}
++
++/*
++ * fsmc_read_buf - read chip data into buffer
++ * @mtd:	MTD device structure
++ * @buf:	buffer to store date
++ * @len:	number of bytes to read
++ */
++static void fsmc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
++{
++	int i;
++	struct nand_chip *chip = mtd_to_nand(mtd);
++
++	if (IS_ALIGNED((uint32_t)buf, sizeof(uint32_t)) &&
++			IS_ALIGNED(len, sizeof(uint32_t))) {
++		uint32_t *p = (uint32_t *)buf;
++		len = len >> 2;
++		for (i = 0; i < len; i++)
++			p[i] = readl_relaxed(chip->IO_ADDR_R);
++	} else {
++		for (i = 0; i < len; i++)
++			buf[i] = readb_relaxed(chip->IO_ADDR_R);
++	}
++}
++
++/*
++ * fsmc_read_buf_dma - read chip data into buffer
++ * @mtd:	MTD device structure
++ * @buf:	buffer to store date
++ * @len:	number of bytes to read
++ */
++static void fsmc_read_buf_dma(struct mtd_info *mtd, uint8_t *buf, int len)
++{
++	struct fsmc_nand_data *host  = mtd_to_fsmc(mtd);
++
++	dma_xfer(host, buf, len, DMA_FROM_DEVICE);
++}
++
++/*
++ * fsmc_write_buf_dma - write buffer to chip
++ * @mtd:	MTD device structure
++ * @buf:	data buffer
++ * @len:	number of bytes to write
++ */
++static void fsmc_write_buf_dma(struct mtd_info *mtd, const uint8_t *buf,
++		int len)
++{
++	struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
++
++	dma_xfer(host, (void *)buf, len, DMA_TO_DEVICE);
++}
++
++/*
++ * fsmc_read_page_hwecc
++ * @mtd:	mtd info structure
++ * @chip:	nand chip info structure
++ * @buf:	buffer to store read data
++ * @oob_required:	caller expects OOB data read to chip->oob_poi
++ * @page:	page number to read
++ *
++ * This routine is needed for fsmc version 8 as reading from NAND chip has to be
++ * performed in a strict sequence as follows:
++ * data(512 byte) -> ecc(13 byte)
++ * After this read, fsmc hardware generates and reports error data bits(up to a
++ * max of 8 bits)
++ */
++static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
++				 uint8_t *buf, int oob_required, int page)
++{
++	int i, j, s, stat, 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;
++	int off, len, group = 0;
++	/*
++	 * ecc_oob is intentionally taken as uint16_t. In 16bit devices, we
++	 * end up reading 14 bytes (7 words) from oob. The local array is
++	 * to maintain word alignment
++	 */
++	uint16_t ecc_oob[7];
++	uint8_t *oob = (uint8_t *)&ecc_oob[0];
++	unsigned int max_bitflips = 0;
++
++	for (i = 0, s = 0; s < eccsteps; s++, i += eccbytes, p += eccsize) {
++		chip->cmdfunc(mtd, NAND_CMD_READ0, s * eccsize, page);
++		chip->ecc.hwctl(mtd, NAND_ECC_READ);
++		chip->read_buf(mtd, p, eccsize);
++
++		for (j = 0; j < eccbytes;) {
++			struct mtd_oob_region oobregion;
++			int ret;
++
++			ret = mtd_ooblayout_ecc(mtd, group++, &oobregion);
++			if (ret)
++				return ret;
++
++			off = oobregion.offset;
++			len = oobregion.length;
++
++			/*
++			 * length is intentionally kept a higher multiple of 2
++			 * to read at least 13 bytes even in case of 16 bit NAND
++			 * devices
++			 */
++			if (chip->options & NAND_BUSWIDTH_16)
++				len = roundup(len, 2);
++
++			chip->cmdfunc(mtd, NAND_CMD_READOOB, off, page);
++			chip->read_buf(mtd, oob + j, len);
++			j += len;
++		}
++
++		memcpy(&ecc_code[i], oob, chip->ecc.bytes);
++		chip->ecc.calculate(mtd, p, &ecc_calc[i]);
++
++		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;
++			max_bitflips = max_t(unsigned int, max_bitflips, stat);
++		}
++	}
++
++	return max_bitflips;
++}
++
++/*
++ * fsmc_bch8_correct_data
++ * @mtd:	mtd info structure
++ * @dat:	buffer of read data
++ * @read_ecc:	ecc read from device spare area
++ * @calc_ecc:	ecc calculated from read data
++ *
++ * calc_ecc is a 104 bit information containing maximum of 8 error
++ * offset informations of 13 bits each in 512 bytes of read data.
++ */
++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 fsmc_nand_data *host = mtd_to_fsmc(mtd);
++	void __iomem *regs = host->regs_va;
++	unsigned int bank = host->bank;
++	uint32_t err_idx[8];
++	uint32_t num_err, i;
++	uint32_t ecc1, ecc2, ecc3, ecc4;
++
++	num_err = (readl_relaxed(FSMC_NAND_REG(regs, bank, STS)) >> 10) & 0xF;
++
++	/* no bit flipping */
++	if (likely(num_err == 0))
++		return 0;
++
++	/* too many errors */
++	if (unlikely(num_err > 8)) {
++		/*
++		 * This is a temporary erase check. A newly erased page read
++		 * would result in an ecc error because the oob data is also
++		 * erased to FF and the calculated ecc for an FF data is not
++		 * FF..FF.
++		 * This is a workaround to skip performing correction in case
++		 * data is FF..FF
++		 *
++		 * Logic:
++		 * For every page, each bit written as 0 is counted until these
++		 * number of bits are greater than 8 (the maximum correction
++		 * capability of FSMC for each 512 + 13 bytes)
++		 */
++
++		int bits_ecc = count_written_bits(read_ecc, chip->ecc.bytes, 8);
++		int bits_data = count_written_bits(dat, chip->ecc.size, 8);
++
++		if ((bits_ecc + bits_data) <= 8) {
++			if (bits_data)
++				memset(dat, 0xff, chip->ecc.size);
++			return bits_data;
++		}
++
++		return -EBADMSG;
++	}
++
++	/*
++	 * ------------------- calc_ecc[] bit wise -----------|--13 bits--|
++	 * |---idx[7]--|--.....-----|---idx[2]--||---idx[1]--||---idx[0]--|
++	 *
++	 * calc_ecc is a 104 bit information containing maximum of 8 error
++	 * offset informations of 13 bits each. calc_ecc is copied into a
++	 * uint64_t array and error offset indexes are populated in err_idx
++	 * array
++	 */
++	ecc1 = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC1));
++	ecc2 = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC2));
++	ecc3 = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC3));
++	ecc4 = readl_relaxed(FSMC_NAND_REG(regs, bank, STS));
++
++	err_idx[0] = (ecc1 >> 0) & 0x1FFF;
++	err_idx[1] = (ecc1 >> 13) & 0x1FFF;
++	err_idx[2] = (((ecc2 >> 0) & 0x7F) << 6) | ((ecc1 >> 26) & 0x3F);
++	err_idx[3] = (ecc2 >> 7) & 0x1FFF;
++	err_idx[4] = (((ecc3 >> 0) & 0x1) << 12) | ((ecc2 >> 20) & 0xFFF);
++	err_idx[5] = (ecc3 >> 1) & 0x1FFF;
++	err_idx[6] = (ecc3 >> 14) & 0x1FFF;
++	err_idx[7] = (((ecc4 >> 16) & 0xFF) << 5) | ((ecc3 >> 27) & 0x1F);
++
++	i = 0;
++	while (num_err--) {
++		change_bit(0, (unsigned long *)&err_idx[i]);
++		change_bit(1, (unsigned long *)&err_idx[i]);
++
++		if (err_idx[i] < chip->ecc.size * 8) {
++			change_bit(err_idx[i], (unsigned long *)dat);
++			i++;
++		}
++	}
++	return i;
++}
++
++static bool filter(struct dma_chan *chan, void *slave)
++{
++	chan->private = slave;
++	return true;
++}
++
++static int fsmc_nand_probe_config_dt(struct platform_device *pdev,
++				     struct fsmc_nand_data *host,
++				     struct nand_chip *nand)
++{
++	struct device_node *np = pdev->dev.of_node;
++	u32 val;
++	int ret;
++
++	nand->options = 0;
++
++	if (!of_property_read_u32(np, "bank-width", &val)) {
++		if (val == 2) {
++			nand->options |= NAND_BUSWIDTH_16;
++		} else if (val != 1) {
++			dev_err(&pdev->dev, "invalid bank-width %u\n", val);
++			return -EINVAL;
++		}
++	}
++
++	if (of_get_property(np, "nand-skip-bbtscan", NULL))
++		nand->options |= NAND_SKIP_BBTSCAN;
++
++	host->dev_timings = devm_kzalloc(&pdev->dev,
++				sizeof(*host->dev_timings), GFP_KERNEL);
++	if (!host->dev_timings)
++		return -ENOMEM;
++	ret = of_property_read_u8_array(np, "timings", (u8 *)host->dev_timings,
++						sizeof(*host->dev_timings));
++	if (ret)
++		host->dev_timings = NULL;
++
++	/* Set default NAND bank to 0 */
++	host->bank = 0;
++	if (!of_property_read_u32(np, "bank", &val)) {
++		if (val > 3) {
++			dev_err(&pdev->dev, "invalid bank %u\n", val);
++			return -EINVAL;
++		}
++		host->bank = val;
++	}
++	return 0;
++}
++
++/*
++ * fsmc_nand_probe - Probe function
++ * @pdev:       platform device structure
++ */
++static int __init fsmc_nand_probe(struct platform_device *pdev)
++{
++	struct fsmc_nand_data *host;
++	struct mtd_info *mtd;
++	struct nand_chip *nand;
++	struct resource *res;
++	dma_cap_mask_t mask;
++	int ret = 0;
++	u32 pid;
++	int i;
++
++	/* Allocate memory for the device structure (and zero it) */
++	host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
++	if (!host)
++		return -ENOMEM;
++
++	nand = &host->nand;
++
++	ret = fsmc_nand_probe_config_dt(pdev, host, nand);
++	if (ret)
++		return ret;
++
++	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_data");
++	host->data_va = devm_ioremap_resource(&pdev->dev, res);
++	if (IS_ERR(host->data_va))
++		return PTR_ERR(host->data_va);
++
++	host->data_pa = (dma_addr_t)res->start;
++
++	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_addr");
++	host->addr_va = devm_ioremap_resource(&pdev->dev, res);
++	if (IS_ERR(host->addr_va))
++		return PTR_ERR(host->addr_va);
++
++	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_cmd");
++	host->cmd_va = devm_ioremap_resource(&pdev->dev, res);
++	if (IS_ERR(host->cmd_va))
++		return PTR_ERR(host->cmd_va);
++
++	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fsmc_regs");
++	host->regs_va = devm_ioremap_resource(&pdev->dev, res);
++	if (IS_ERR(host->regs_va))
++		return PTR_ERR(host->regs_va);
++
++	host->clk = devm_clk_get(&pdev->dev, NULL);
++	if (IS_ERR(host->clk)) {
++		dev_err(&pdev->dev, "failed to fetch block clock\n");
++		return PTR_ERR(host->clk);
++	}
++
++	ret = clk_prepare_enable(host->clk);
++	if (ret)
++		return ret;
++
++	/*
++	 * This device ID is actually a common AMBA ID as used on the
++	 * AMBA PrimeCell bus. However it is not a PrimeCell.
++	 */
++	for (pid = 0, i = 0; i < 4; i++)
++		pid |= (readl(host->regs_va + resource_size(res) - 0x20 + 4 * i) & 255) << (i * 8);
++	host->pid = pid;
++	dev_info(&pdev->dev, "FSMC device partno %03x, manufacturer %02x, "
++		 "revision %02x, config %02x\n",
++		 AMBA_PART_BITS(pid), AMBA_MANF_BITS(pid),
++		 AMBA_REV_BITS(pid), AMBA_CONFIG_BITS(pid));
++
++	host->dev = &pdev->dev;
++
++	if (host->mode == USE_DMA_ACCESS)
++		init_completion(&host->dma_access_complete);
++
++	/* Link all private pointers */
++	mtd = nand_to_mtd(&host->nand);
++	nand_set_controller_data(nand, host);
++	nand_set_flash_node(nand, pdev->dev.of_node);
++
++	mtd->dev.parent = &pdev->dev;
++	nand->IO_ADDR_R = host->data_va;
++	nand->IO_ADDR_W = host->data_va;
++	nand->cmd_ctrl = fsmc_cmd_ctrl;
++	nand->chip_delay = 30;
++
++	/*
++	 * Setup default ECC mode. nand_dt_init() called from nand_scan_ident()
++	 * can overwrite this value if the DT provides a different value.
++	 */
++	nand->ecc.mode = NAND_ECC_HW;
++	nand->ecc.hwctl = fsmc_enable_hwecc;
++	nand->ecc.size = 512;
++	nand->badblockbits = 7;
++
++	switch (host->mode) {
++	case USE_DMA_ACCESS:
++		dma_cap_zero(mask);
++		dma_cap_set(DMA_MEMCPY, mask);
++		host->read_dma_chan = dma_request_channel(mask, filter, NULL);
++		if (!host->read_dma_chan) {
++			dev_err(&pdev->dev, "Unable to get read dma channel\n");
++			goto err_req_read_chnl;
++		}
++		host->write_dma_chan = dma_request_channel(mask, filter, NULL);
++		if (!host->write_dma_chan) {
++			dev_err(&pdev->dev, "Unable to get write dma channel\n");
++			goto err_req_write_chnl;
++		}
++		nand->read_buf = fsmc_read_buf_dma;
++		nand->write_buf = fsmc_write_buf_dma;
++		break;
++
++	default:
++	case USE_WORD_ACCESS:
++		nand->read_buf = fsmc_read_buf;
++		nand->write_buf = fsmc_write_buf;
++		break;
++	}
++
++	if (host->dev_timings)
++		fsmc_nand_setup(host, host->dev_timings);
++	else
++		nand->setup_data_interface = fsmc_setup_data_interface;
++
++	if (AMBA_REV_BITS(host->pid) >= 8) {
++		nand->ecc.read_page = fsmc_read_page_hwecc;
++		nand->ecc.calculate = fsmc_read_hwecc_ecc4;
++		nand->ecc.correct = fsmc_bch8_correct_data;
++		nand->ecc.bytes = 13;
++		nand->ecc.strength = 8;
++	}
++
++	/*
++	 * Scan to find existence of the device
++	 */
++	ret = nand_scan_ident(mtd, 1, NULL);
++	if (ret) {
++		dev_err(&pdev->dev, "No NAND Device found!\n");
++		goto err_scan_ident;
++	}
++
++	if (AMBA_REV_BITS(host->pid) >= 8) {
++		switch (mtd->oobsize) {
++		case 16:
++		case 64:
++		case 128:
++		case 224:
++		case 256:
++			break;
++		default:
++			dev_warn(&pdev->dev, "No oob scheme defined for oobsize %d\n",
++				 mtd->oobsize);
++			ret = -EINVAL;
++			goto err_probe;
++		}
++
++		mtd_set_ooblayout(mtd, &fsmc_ecc4_ooblayout_ops);
++	} else {
++		switch (nand->ecc.mode) {
++		case NAND_ECC_HW:
++			dev_info(&pdev->dev, "Using 1-bit HW ECC scheme\n");
++			nand->ecc.calculate = fsmc_read_hwecc_ecc1;
++			nand->ecc.correct = nand_correct_data;
++			nand->ecc.bytes = 3;
++			nand->ecc.strength = 1;
++			break;
++
++		case NAND_ECC_SOFT:
++			if (nand->ecc.algo == NAND_ECC_BCH) {
++				dev_info(&pdev->dev, "Using 4-bit SW BCH ECC scheme\n");
++				break;
++			}
++
++		case NAND_ECC_ON_DIE:
++			break;
++
++		default:
++			dev_err(&pdev->dev, "Unsupported ECC mode!\n");
++			goto err_probe;
++		}
++
++		/*
++		 * Don't set layout for BCH4 SW ECC. This will be
++		 * generated later in nand_bch_init() later.
++		 */
++		if (nand->ecc.mode == NAND_ECC_HW) {
++			switch (mtd->oobsize) {
++			case 16:
++			case 64:
++			case 128:
++				mtd_set_ooblayout(mtd,
++						  &fsmc_ecc1_ooblayout_ops);
++				break;
++			default:
++				dev_warn(&pdev->dev,
++					 "No oob scheme defined for oobsize %d\n",
++					 mtd->oobsize);
++				ret = -EINVAL;
++				goto err_probe;
++			}
++		}
++	}
++
++	/* Second stage of scan to fill MTD data-structures */
++	ret = nand_scan_tail(mtd);
++	if (ret)
++		goto err_probe;
++
++	mtd->name = "nand";
++	ret = mtd_device_register(mtd, NULL, 0);
++	if (ret)
++		goto err_probe;
++
++	platform_set_drvdata(pdev, host);
++	dev_info(&pdev->dev, "FSMC NAND driver registration successful\n");
++	return 0;
++
++err_probe:
++err_scan_ident:
++	if (host->mode == USE_DMA_ACCESS)
++		dma_release_channel(host->write_dma_chan);
++err_req_write_chnl:
++	if (host->mode == USE_DMA_ACCESS)
++		dma_release_channel(host->read_dma_chan);
++err_req_read_chnl:
++	clk_disable_unprepare(host->clk);
++	return ret;
++}
++
++/*
++ * Clean up routine
++ */
++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));
++
++		if (host->mode == USE_DMA_ACCESS) {
++			dma_release_channel(host->write_dma_chan);
++			dma_release_channel(host->read_dma_chan);
++		}
++		clk_disable_unprepare(host->clk);
++	}
++
++	return 0;
++}
++
++#ifdef CONFIG_PM_SLEEP
++static int fsmc_nand_suspend(struct device *dev)
++{
++	struct fsmc_nand_data *host = dev_get_drvdata(dev);
++	if (host)
++		clk_disable_unprepare(host->clk);
++	return 0;
++}
++
++static int fsmc_nand_resume(struct device *dev)
++{
++	struct fsmc_nand_data *host = dev_get_drvdata(dev);
++	if (host) {
++		clk_prepare_enable(host->clk);
++		if (host->dev_timings)
++			fsmc_nand_setup(host, host->dev_timings);
++	}
++	return 0;
++}
++#endif
++
++static SIMPLE_DEV_PM_OPS(fsmc_nand_pm_ops, fsmc_nand_suspend, fsmc_nand_resume);
++
++static const struct of_device_id fsmc_nand_id_table[] = {
++	{ .compatible = "st,spear600-fsmc-nand" },
++	{ .compatible = "stericsson,fsmc-nand" },
++	{}
++};
++MODULE_DEVICE_TABLE(of, fsmc_nand_id_table);
++
++static struct platform_driver fsmc_nand_driver = {
++	.remove = fsmc_nand_remove,
++	.driver = {
++		.name = "fsmc-nand",
++		.of_match_table = fsmc_nand_id_table,
++		.pm = &fsmc_nand_pm_ops,
++	},
++};
++
++module_platform_driver_probe(fsmc_nand_driver, fsmc_nand_probe);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Vipin Kumar <vipin.kumar@st.com>, Ashish Priyadarshi");
++MODULE_DESCRIPTION("NAND driver for SPEAr Platforms");
+diff --git a/drivers/mtd/nand/raw/gpio.c b/drivers/mtd/nand/raw/gpio.c
+new file mode 100644
+index 0000000..fd36489
+--- /dev/null
++++ b/drivers/mtd/nand/raw/gpio.c
+@@ -0,0 +1,327 @@
++/*
++ * drivers/mtd/nand/gpio.c
++ *
++ * Updated, and converted to generic GPIO based driver by Russell King.
++ *
++ * Written by Ben Dooks <ben@simtec.co.uk>
++ *   Based on 2.4 version by Mark Whittaker
++ *
++ * © 2004 Simtec Electronics
++ *
++ * Device driver for NAND flash that uses a memory mapped interface to
++ * read/write the NAND commands and data, and GPIO pins for control signals
++ * (the DT binding refers to this as "GPIO assisted NAND flash")
++ *
++ * 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/kernel.h>
++#include <linux/err.h>
++#include <linux/slab.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/gpio.h>
++#include <linux/io.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/rawnand.h>
++#include <linux/mtd/partitions.h>
++#include <linux/mtd/nand-gpio.h>
++#include <linux/of.h>
++#include <linux/of_address.h>
++#include <linux/of_gpio.h>
++
++struct gpiomtd {
++	void __iomem		*io_sync;
++	struct nand_chip	nand_chip;
++	struct gpio_nand_platdata plat;
++};
++
++static inline struct gpiomtd *gpio_nand_getpriv(struct mtd_info *mtd)
++{
++	return container_of(mtd_to_nand(mtd), struct gpiomtd, nand_chip);
++}
++
++
++#ifdef CONFIG_ARM
++/* gpio_nand_dosync()
++ *
++ * Make sure the GPIO state changes occur in-order with writes to NAND
++ * memory region.
++ * Needed on PXA due to bus-reordering within the SoC itself (see section on
++ * I/O ordering in PXA manual (section 2.3, p35)
++ */
++static void gpio_nand_dosync(struct gpiomtd *gpiomtd)
++{
++	unsigned long tmp;
++
++	if (gpiomtd->io_sync) {
++		/*
++		 * Linux memory barriers don't cater for what's required here.
++		 * What's required is what's here - a read from a separate
++		 * region with a dependency on that read.
++		 */
++		tmp = readl(gpiomtd->io_sync);
++		asm volatile("mov %1, %0\n" : "=r" (tmp) : "r" (tmp));
++	}
++}
++#else
++static inline void gpio_nand_dosync(struct gpiomtd *gpiomtd) {}
++#endif
++
++static void gpio_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
++{
++	struct gpiomtd *gpiomtd = gpio_nand_getpriv(mtd);
++
++	gpio_nand_dosync(gpiomtd);
++
++	if (ctrl & NAND_CTRL_CHANGE) {
++		if (gpio_is_valid(gpiomtd->plat.gpio_nce))
++			gpio_set_value(gpiomtd->plat.gpio_nce,
++				       !(ctrl & NAND_NCE));
++		gpio_set_value(gpiomtd->plat.gpio_cle, !!(ctrl & NAND_CLE));
++		gpio_set_value(gpiomtd->plat.gpio_ale, !!(ctrl & NAND_ALE));
++		gpio_nand_dosync(gpiomtd);
++	}
++	if (cmd == NAND_CMD_NONE)
++		return;
++
++	writeb(cmd, gpiomtd->nand_chip.IO_ADDR_W);
++	gpio_nand_dosync(gpiomtd);
++}
++
++static int gpio_nand_devready(struct mtd_info *mtd)
++{
++	struct gpiomtd *gpiomtd = gpio_nand_getpriv(mtd);
++
++	return gpio_get_value(gpiomtd->plat.gpio_rdy);
++}
++
++#ifdef CONFIG_OF
++static const struct of_device_id gpio_nand_id_table[] = {
++	{ .compatible = "gpio-control-nand" },
++	{}
++};
++MODULE_DEVICE_TABLE(of, gpio_nand_id_table);
++
++static int gpio_nand_get_config_of(const struct device *dev,
++				   struct gpio_nand_platdata *plat)
++{
++	u32 val;
++
++	if (!dev->of_node)
++		return -ENODEV;
++
++	if (!of_property_read_u32(dev->of_node, "bank-width", &val)) {
++		if (val == 2) {
++			plat->options |= NAND_BUSWIDTH_16;
++		} else if (val != 1) {
++			dev_err(dev, "invalid bank-width %u\n", val);
++			return -EINVAL;
++		}
++	}
++
++	plat->gpio_rdy = of_get_gpio(dev->of_node, 0);
++	plat->gpio_nce = of_get_gpio(dev->of_node, 1);
++	plat->gpio_ale = of_get_gpio(dev->of_node, 2);
++	plat->gpio_cle = of_get_gpio(dev->of_node, 3);
++	plat->gpio_nwp = of_get_gpio(dev->of_node, 4);
++
++	if (!of_property_read_u32(dev->of_node, "chip-delay", &val))
++		plat->chip_delay = val;
++
++	return 0;
++}
++
++static struct resource *gpio_nand_get_io_sync_of(struct platform_device *pdev)
++{
++	struct resource *r;
++	u64 addr;
++
++	if (of_property_read_u64(pdev->dev.of_node,
++				       "gpio-control-nand,io-sync-reg", &addr))
++		return NULL;
++
++	r = devm_kzalloc(&pdev->dev, sizeof(*r), GFP_KERNEL);
++	if (!r)
++		return NULL;
++
++	r->start = addr;
++	r->end = r->start + 0x3;
++	r->flags = IORESOURCE_MEM;
++
++	return r;
++}
++#else /* CONFIG_OF */
++static inline int gpio_nand_get_config_of(const struct device *dev,
++					  struct gpio_nand_platdata *plat)
++{
++	return -ENOSYS;
++}
++
++static inline struct resource *
++gpio_nand_get_io_sync_of(struct platform_device *pdev)
++{
++	return NULL;
++}
++#endif /* CONFIG_OF */
++
++static inline int gpio_nand_get_config(const struct device *dev,
++				       struct gpio_nand_platdata *plat)
++{
++	int ret = gpio_nand_get_config_of(dev, plat);
++
++	if (!ret)
++		return ret;
++
++	if (dev_get_platdata(dev)) {
++		memcpy(plat, dev_get_platdata(dev), sizeof(*plat));
++		return 0;
++	}
++
++	return -EINVAL;
++}
++
++static inline struct resource *
++gpio_nand_get_io_sync(struct platform_device *pdev)
++{
++	struct resource *r = gpio_nand_get_io_sync_of(pdev);
++
++	if (r)
++		return r;
++
++	return platform_get_resource(pdev, IORESOURCE_MEM, 1);
++}
++
++static int gpio_nand_remove(struct platform_device *pdev)
++{
++	struct gpiomtd *gpiomtd = platform_get_drvdata(pdev);
++
++	nand_release(nand_to_mtd(&gpiomtd->nand_chip));
++
++	if (gpio_is_valid(gpiomtd->plat.gpio_nwp))
++		gpio_set_value(gpiomtd->plat.gpio_nwp, 0);
++	if (gpio_is_valid(gpiomtd->plat.gpio_nce))
++		gpio_set_value(gpiomtd->plat.gpio_nce, 1);
++
++	return 0;
++}
++
++static int gpio_nand_probe(struct platform_device *pdev)
++{
++	struct gpiomtd *gpiomtd;
++	struct nand_chip *chip;
++	struct mtd_info *mtd;
++	struct resource *res;
++	int ret = 0;
++
++	if (!pdev->dev.of_node && !dev_get_platdata(&pdev->dev))
++		return -EINVAL;
++
++	gpiomtd = devm_kzalloc(&pdev->dev, sizeof(*gpiomtd), GFP_KERNEL);
++	if (!gpiomtd)
++		return -ENOMEM;
++
++	chip = &gpiomtd->nand_chip;
++
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	chip->IO_ADDR_R = devm_ioremap_resource(&pdev->dev, res);
++	if (IS_ERR(chip->IO_ADDR_R))
++		return PTR_ERR(chip->IO_ADDR_R);
++
++	res = gpio_nand_get_io_sync(pdev);
++	if (res) {
++		gpiomtd->io_sync = devm_ioremap_resource(&pdev->dev, res);
++		if (IS_ERR(gpiomtd->io_sync))
++			return PTR_ERR(gpiomtd->io_sync);
++	}
++
++	ret = gpio_nand_get_config(&pdev->dev, &gpiomtd->plat);
++	if (ret)
++		return ret;
++
++	if (gpio_is_valid(gpiomtd->plat.gpio_nce)) {
++		ret = devm_gpio_request(&pdev->dev, gpiomtd->plat.gpio_nce,
++					"NAND NCE");
++		if (ret)
++			return ret;
++		gpio_direction_output(gpiomtd->plat.gpio_nce, 1);
++	}
++
++	if (gpio_is_valid(gpiomtd->plat.gpio_nwp)) {
++		ret = devm_gpio_request(&pdev->dev, gpiomtd->plat.gpio_nwp,
++					"NAND NWP");
++		if (ret)
++			return ret;
++	}
++
++	ret = devm_gpio_request(&pdev->dev, gpiomtd->plat.gpio_ale, "NAND ALE");
++	if (ret)
++		return ret;
++	gpio_direction_output(gpiomtd->plat.gpio_ale, 0);
++
++	ret = devm_gpio_request(&pdev->dev, gpiomtd->plat.gpio_cle, "NAND CLE");
++	if (ret)
++		return ret;
++	gpio_direction_output(gpiomtd->plat.gpio_cle, 0);
++
++	if (gpio_is_valid(gpiomtd->plat.gpio_rdy)) {
++		ret = devm_gpio_request(&pdev->dev, gpiomtd->plat.gpio_rdy,
++					"NAND RDY");
++		if (ret)
++			return ret;
++		gpio_direction_input(gpiomtd->plat.gpio_rdy);
++		chip->dev_ready = gpio_nand_devready;
++	}
++
++	nand_set_flash_node(chip, pdev->dev.of_node);
++	chip->IO_ADDR_W		= chip->IO_ADDR_R;
++	chip->ecc.mode		= NAND_ECC_SOFT;
++	chip->ecc.algo		= NAND_ECC_HAMMING;
++	chip->options		= gpiomtd->plat.options;
++	chip->chip_delay	= gpiomtd->plat.chip_delay;
++	chip->cmd_ctrl		= gpio_nand_cmd_ctrl;
++
++	mtd			= nand_to_mtd(chip);
++	mtd->dev.parent		= &pdev->dev;
++
++	platform_set_drvdata(pdev, gpiomtd);
++
++	if (gpio_is_valid(gpiomtd->plat.gpio_nwp))
++		gpio_direction_output(gpiomtd->plat.gpio_nwp, 1);
++
++	ret = nand_scan(mtd, 1);
++	if (ret)
++		goto err_wp;
++
++	if (gpiomtd->plat.adjust_parts)
++		gpiomtd->plat.adjust_parts(&gpiomtd->plat, mtd->size);
++
++	ret = mtd_device_register(mtd, gpiomtd->plat.parts,
++				  gpiomtd->plat.num_parts);
++	if (!ret)
++		return 0;
++
++err_wp:
++	if (gpio_is_valid(gpiomtd->plat.gpio_nwp))
++		gpio_set_value(gpiomtd->plat.gpio_nwp, 0);
++
++	return ret;
++}
++
++static struct platform_driver gpio_nand_driver = {
++	.probe		= gpio_nand_probe,
++	.remove		= gpio_nand_remove,
++	.driver		= {
++		.name	= "gpio-nand",
++		.of_match_table = of_match_ptr(gpio_nand_id_table),
++	},
++};
++
++module_platform_driver(gpio_nand_driver);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
++MODULE_DESCRIPTION("GPIO NAND Driver");
+diff --git a/drivers/mtd/nand/raw/gpmi-nand/Makefile b/drivers/mtd/nand/raw/gpmi-nand/Makefile
+new file mode 100644
+index 0000000..3a46248
+--- /dev/null
++++ b/drivers/mtd/nand/raw/gpmi-nand/Makefile
+@@ -0,0 +1,3 @@
++obj-$(CONFIG_MTD_NAND_GPMI_NAND) += gpmi_nand.o
++gpmi_nand-objs += gpmi-nand.o
++gpmi_nand-objs += gpmi-lib.o
+diff --git a/drivers/mtd/nand/raw/gpmi-nand/bch-regs.h b/drivers/mtd/nand/raw/gpmi-nand/bch-regs.h
+new file mode 100644
+index 0000000..05bb91f
+--- /dev/null
++++ b/drivers/mtd/nand/raw/gpmi-nand/bch-regs.h
+@@ -0,0 +1,128 @@
++/*
++ * Freescale GPMI NAND Flash Driver
++ *
++ * Copyright 2008-2011 Freescale Semiconductor, Inc.
++ * Copyright 2008 Embedded Alley Solutions, Inc.
++ *
++ * 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.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++ */
++#ifndef __GPMI_NAND_BCH_REGS_H
++#define __GPMI_NAND_BCH_REGS_H
++
++#define HW_BCH_CTRL				0x00000000
++#define HW_BCH_CTRL_SET				0x00000004
++#define HW_BCH_CTRL_CLR				0x00000008
++#define HW_BCH_CTRL_TOG				0x0000000c
++
++#define BM_BCH_CTRL_COMPLETE_IRQ_EN		(1 << 8)
++#define BM_BCH_CTRL_COMPLETE_IRQ		(1 << 0)
++
++#define HW_BCH_STATUS0				0x00000010
++#define HW_BCH_MODE				0x00000020
++#define HW_BCH_ENCODEPTR			0x00000030
++#define HW_BCH_DATAPTR				0x00000040
++#define HW_BCH_METAPTR				0x00000050
++#define HW_BCH_LAYOUTSELECT			0x00000070
++
++#define HW_BCH_FLASH0LAYOUT0			0x00000080
++
++#define BP_BCH_FLASH0LAYOUT0_NBLOCKS		24
++#define BM_BCH_FLASH0LAYOUT0_NBLOCKS	(0xff << BP_BCH_FLASH0LAYOUT0_NBLOCKS)
++#define BF_BCH_FLASH0LAYOUT0_NBLOCKS(v)		\
++	(((v) << BP_BCH_FLASH0LAYOUT0_NBLOCKS) & BM_BCH_FLASH0LAYOUT0_NBLOCKS)
++
++#define BP_BCH_FLASH0LAYOUT0_META_SIZE		16
++#define BM_BCH_FLASH0LAYOUT0_META_SIZE	(0xff << BP_BCH_FLASH0LAYOUT0_META_SIZE)
++#define BF_BCH_FLASH0LAYOUT0_META_SIZE(v)	\
++	(((v) << BP_BCH_FLASH0LAYOUT0_META_SIZE)\
++					 & BM_BCH_FLASH0LAYOUT0_META_SIZE)
++
++#define BP_BCH_FLASH0LAYOUT0_ECC0		12
++#define BM_BCH_FLASH0LAYOUT0_ECC0	(0xf << BP_BCH_FLASH0LAYOUT0_ECC0)
++#define MX6Q_BP_BCH_FLASH0LAYOUT0_ECC0		11
++#define MX6Q_BM_BCH_FLASH0LAYOUT0_ECC0	(0x1f << MX6Q_BP_BCH_FLASH0LAYOUT0_ECC0)
++#define BF_BCH_FLASH0LAYOUT0_ECC0(v, x)				\
++	(GPMI_IS_MX6(x)					\
++		? (((v) << MX6Q_BP_BCH_FLASH0LAYOUT0_ECC0)	\
++			& MX6Q_BM_BCH_FLASH0LAYOUT0_ECC0)	\
++		: (((v) << BP_BCH_FLASH0LAYOUT0_ECC0)		\
++			& BM_BCH_FLASH0LAYOUT0_ECC0)		\
++	)
++
++#define MX6Q_BP_BCH_FLASH0LAYOUT0_GF_13_14	10
++#define MX6Q_BM_BCH_FLASH0LAYOUT0_GF_13_14			\
++				(0x1 << MX6Q_BP_BCH_FLASH0LAYOUT0_GF_13_14)
++#define BF_BCH_FLASH0LAYOUT0_GF(v, x)				\
++	((GPMI_IS_MX6(x) && ((v) == 14))			\
++		? (((1) << MX6Q_BP_BCH_FLASH0LAYOUT0_GF_13_14)	\
++			& MX6Q_BM_BCH_FLASH0LAYOUT0_GF_13_14)	\
++		: 0						\
++	)
++
++#define BP_BCH_FLASH0LAYOUT0_DATA0_SIZE		0
++#define BM_BCH_FLASH0LAYOUT0_DATA0_SIZE		\
++			(0xfff << BP_BCH_FLASH0LAYOUT0_DATA0_SIZE)
++#define MX6Q_BM_BCH_FLASH0LAYOUT0_DATA0_SIZE	\
++			(0x3ff << BP_BCH_FLASH0LAYOUT0_DATA0_SIZE)
++#define BF_BCH_FLASH0LAYOUT0_DATA0_SIZE(v, x)				\
++	(GPMI_IS_MX6(x)						\
++		? (((v) >> 2) & MX6Q_BM_BCH_FLASH0LAYOUT0_DATA0_SIZE)	\
++		: ((v) & BM_BCH_FLASH0LAYOUT0_DATA0_SIZE)		\
++	)
++
++#define HW_BCH_FLASH0LAYOUT1			0x00000090
++
++#define BP_BCH_FLASH0LAYOUT1_PAGE_SIZE		16
++#define BM_BCH_FLASH0LAYOUT1_PAGE_SIZE		\
++			(0xffff << BP_BCH_FLASH0LAYOUT1_PAGE_SIZE)
++#define BF_BCH_FLASH0LAYOUT1_PAGE_SIZE(v)	\
++	(((v) << BP_BCH_FLASH0LAYOUT1_PAGE_SIZE) \
++					 & BM_BCH_FLASH0LAYOUT1_PAGE_SIZE)
++
++#define BP_BCH_FLASH0LAYOUT1_ECCN		12
++#define BM_BCH_FLASH0LAYOUT1_ECCN	(0xf << BP_BCH_FLASH0LAYOUT1_ECCN)
++#define MX6Q_BP_BCH_FLASH0LAYOUT1_ECCN		11
++#define MX6Q_BM_BCH_FLASH0LAYOUT1_ECCN	(0x1f << MX6Q_BP_BCH_FLASH0LAYOUT1_ECCN)
++#define BF_BCH_FLASH0LAYOUT1_ECCN(v, x)				\
++	(GPMI_IS_MX6(x)					\
++		? (((v) << MX6Q_BP_BCH_FLASH0LAYOUT1_ECCN)	\
++			& MX6Q_BM_BCH_FLASH0LAYOUT1_ECCN)	\
++		: (((v) << BP_BCH_FLASH0LAYOUT1_ECCN)		\
++			& BM_BCH_FLASH0LAYOUT1_ECCN)		\
++	)
++
++#define MX6Q_BP_BCH_FLASH0LAYOUT1_GF_13_14	10
++#define MX6Q_BM_BCH_FLASH0LAYOUT1_GF_13_14			\
++				(0x1 << MX6Q_BP_BCH_FLASH0LAYOUT1_GF_13_14)
++#define BF_BCH_FLASH0LAYOUT1_GF(v, x)				\
++	((GPMI_IS_MX6(x) && ((v) == 14))			\
++		? (((1) << MX6Q_BP_BCH_FLASH0LAYOUT1_GF_13_14)	\
++			& MX6Q_BM_BCH_FLASH0LAYOUT1_GF_13_14)	\
++		: 0						\
++	)
++
++#define BP_BCH_FLASH0LAYOUT1_DATAN_SIZE		0
++#define BM_BCH_FLASH0LAYOUT1_DATAN_SIZE		\
++			(0xfff << BP_BCH_FLASH0LAYOUT1_DATAN_SIZE)
++#define MX6Q_BM_BCH_FLASH0LAYOUT1_DATAN_SIZE	\
++			(0x3ff << BP_BCH_FLASH0LAYOUT1_DATAN_SIZE)
++#define BF_BCH_FLASH0LAYOUT1_DATAN_SIZE(v, x)				\
++	(GPMI_IS_MX6(x)						\
++		? (((v) >> 2) & MX6Q_BM_BCH_FLASH0LAYOUT1_DATAN_SIZE)	\
++		: ((v) & BM_BCH_FLASH0LAYOUT1_DATAN_SIZE)		\
++	)
++
++#define HW_BCH_VERSION				0x00000160
++#endif
+diff --git a/drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c b/drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c
+new file mode 100644
+index 0000000..9778724
+--- /dev/null
++++ b/drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c
+@@ -0,0 +1,1510 @@
++/*
++ * Freescale GPMI NAND Flash Driver
++ *
++ * Copyright (C) 2008-2011 Freescale Semiconductor, Inc.
++ * Copyright (C) 2008 Embedded Alley Solutions, Inc.
++ *
++ * 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.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++ */
++#include <linux/delay.h>
++#include <linux/clk.h>
++#include <linux/slab.h>
++
++#include "gpmi-nand.h"
++#include "gpmi-regs.h"
++#include "bch-regs.h"
++
++static struct timing_threshold timing_default_threshold = {
++	.max_data_setup_cycles       = (BM_GPMI_TIMING0_DATA_SETUP >>
++						BP_GPMI_TIMING0_DATA_SETUP),
++	.internal_data_setup_in_ns   = 0,
++	.max_sample_delay_factor     = (BM_GPMI_CTRL1_RDN_DELAY >>
++						BP_GPMI_CTRL1_RDN_DELAY),
++	.max_dll_clock_period_in_ns  = 32,
++	.max_dll_delay_in_ns         = 16,
++};
++
++#define MXS_SET_ADDR		0x4
++#define MXS_CLR_ADDR		0x8
++/*
++ * Clear the bit and poll it cleared.  This is usually called with
++ * a reset address and mask being either SFTRST(bit 31) or CLKGATE
++ * (bit 30).
++ */
++static int clear_poll_bit(void __iomem *addr, u32 mask)
++{
++	int timeout = 0x400;
++
++	/* clear the bit */
++	writel(mask, addr + MXS_CLR_ADDR);
++
++	/*
++	 * SFTRST needs 3 GPMI clocks to settle, the reference manual
++	 * recommends to wait 1us.
++	 */
++	udelay(1);
++
++	/* poll the bit becoming clear */
++	while ((readl(addr) & mask) && --timeout)
++		/* nothing */;
++
++	return !timeout;
++}
++
++#define MODULE_CLKGATE		(1 << 30)
++#define MODULE_SFTRST		(1 << 31)
++/*
++ * The current mxs_reset_block() will do two things:
++ *  [1] enable the module.
++ *  [2] reset the module.
++ *
++ * In most of the cases, it's ok.
++ * But in MX23, there is a hardware bug in the BCH block (see erratum #2847).
++ * If you try to soft reset the BCH block, it becomes unusable until
++ * the next hard reset. This case occurs in the NAND boot mode. When the board
++ * boots by NAND, the ROM of the chip will initialize the BCH blocks itself.
++ * So If the driver tries to reset the BCH again, the BCH will not work anymore.
++ * You will see a DMA timeout in this case. The bug has been fixed
++ * in the following chips, such as MX28.
++ *
++ * To avoid this bug, just add a new parameter `just_enable` for
++ * the mxs_reset_block(), and rewrite it here.
++ */
++static int gpmi_reset_block(void __iomem *reset_addr, bool just_enable)
++{
++	int ret;
++	int timeout = 0x400;
++
++	/* clear and poll SFTRST */
++	ret = clear_poll_bit(reset_addr, MODULE_SFTRST);
++	if (unlikely(ret))
++		goto error;
++
++	/* clear CLKGATE */
++	writel(MODULE_CLKGATE, reset_addr + MXS_CLR_ADDR);
++
++	if (!just_enable) {
++		/* set SFTRST to reset the block */
++		writel(MODULE_SFTRST, reset_addr + MXS_SET_ADDR);
++		udelay(1);
++
++		/* poll CLKGATE becoming set */
++		while ((!(readl(reset_addr) & MODULE_CLKGATE)) && --timeout)
++			/* nothing */;
++		if (unlikely(!timeout))
++			goto error;
++	}
++
++	/* clear and poll SFTRST */
++	ret = clear_poll_bit(reset_addr, MODULE_SFTRST);
++	if (unlikely(ret))
++		goto error;
++
++	/* clear and poll CLKGATE */
++	ret = clear_poll_bit(reset_addr, MODULE_CLKGATE);
++	if (unlikely(ret))
++		goto error;
++
++	return 0;
++
++error:
++	pr_err("%s(%p): module reset timeout\n", __func__, reset_addr);
++	return -ETIMEDOUT;
++}
++
++static int __gpmi_enable_clk(struct gpmi_nand_data *this, bool v)
++{
++	struct clk *clk;
++	int ret;
++	int i;
++
++	for (i = 0; i < GPMI_CLK_MAX; i++) {
++		clk = this->resources.clock[i];
++		if (!clk)
++			break;
++
++		if (v) {
++			ret = clk_prepare_enable(clk);
++			if (ret)
++				goto err_clk;
++		} else {
++			clk_disable_unprepare(clk);
++		}
++	}
++	return 0;
++
++err_clk:
++	for (; i > 0; i--)
++		clk_disable_unprepare(this->resources.clock[i - 1]);
++	return ret;
++}
++
++#define gpmi_enable_clk(x) __gpmi_enable_clk(x, true)
++#define gpmi_disable_clk(x) __gpmi_enable_clk(x, false)
++
++int gpmi_init(struct gpmi_nand_data *this)
++{
++	struct resources *r = &this->resources;
++	int ret;
++
++	ret = gpmi_enable_clk(this);
++	if (ret)
++		return ret;
++	ret = gpmi_reset_block(r->gpmi_regs, false);
++	if (ret)
++		goto err_out;
++
++	/*
++	 * Reset BCH here, too. We got failures otherwise :(
++	 * See later BCH reset for explanation of MX23 handling
++	 */
++	ret = gpmi_reset_block(r->bch_regs, GPMI_IS_MX23(this));
++	if (ret)
++		goto err_out;
++
++
++	/* Choose NAND mode. */
++	writel(BM_GPMI_CTRL1_GPMI_MODE, r->gpmi_regs + HW_GPMI_CTRL1_CLR);
++
++	/* Set the IRQ polarity. */
++	writel(BM_GPMI_CTRL1_ATA_IRQRDY_POLARITY,
++				r->gpmi_regs + HW_GPMI_CTRL1_SET);
++
++	/* Disable Write-Protection. */
++	writel(BM_GPMI_CTRL1_DEV_RESET, r->gpmi_regs + HW_GPMI_CTRL1_SET);
++
++	/* Select BCH ECC. */
++	writel(BM_GPMI_CTRL1_BCH_MODE, r->gpmi_regs + HW_GPMI_CTRL1_SET);
++
++	/*
++	 * Decouple the chip select from dma channel. We use dma0 for all
++	 * the chips.
++	 */
++	writel(BM_GPMI_CTRL1_DECOUPLE_CS, r->gpmi_regs + HW_GPMI_CTRL1_SET);
++
++	gpmi_disable_clk(this);
++	return 0;
++err_out:
++	gpmi_disable_clk(this);
++	return ret;
++}
++
++/* This function is very useful. It is called only when the bug occur. */
++void gpmi_dump_info(struct gpmi_nand_data *this)
++{
++	struct resources *r = &this->resources;
++	struct bch_geometry *geo = &this->bch_geometry;
++	u32 reg;
++	int i;
++
++	dev_err(this->dev, "Show GPMI registers :\n");
++	for (i = 0; i <= HW_GPMI_DEBUG / 0x10 + 1; i++) {
++		reg = readl(r->gpmi_regs + i * 0x10);
++		dev_err(this->dev, "offset 0x%.3x : 0x%.8x\n", i * 0x10, reg);
++	}
++
++	/* start to print out the BCH info */
++	dev_err(this->dev, "Show BCH registers :\n");
++	for (i = 0; i <= HW_BCH_VERSION / 0x10 + 1; i++) {
++		reg = readl(r->bch_regs + i * 0x10);
++		dev_err(this->dev, "offset 0x%.3x : 0x%.8x\n", i * 0x10, reg);
++	}
++	dev_err(this->dev, "BCH Geometry :\n"
++		"GF length              : %u\n"
++		"ECC Strength           : %u\n"
++		"Page Size in Bytes     : %u\n"
++		"Metadata Size in Bytes : %u\n"
++		"ECC Chunk Size in Bytes: %u\n"
++		"ECC Chunk Count        : %u\n"
++		"Payload Size in Bytes  : %u\n"
++		"Auxiliary Size in Bytes: %u\n"
++		"Auxiliary Status Offset: %u\n"
++		"Block Mark Byte Offset : %u\n"
++		"Block Mark Bit Offset  : %u\n",
++		geo->gf_len,
++		geo->ecc_strength,
++		geo->page_size,
++		geo->metadata_size,
++		geo->ecc_chunk_size,
++		geo->ecc_chunk_count,
++		geo->payload_size,
++		geo->auxiliary_size,
++		geo->auxiliary_status_offset,
++		geo->block_mark_byte_offset,
++		geo->block_mark_bit_offset);
++}
++
++/* Configures the geometry for BCH.  */
++int bch_set_geometry(struct gpmi_nand_data *this)
++{
++	struct resources *r = &this->resources;
++	struct bch_geometry *bch_geo = &this->bch_geometry;
++	unsigned int block_count;
++	unsigned int block_size;
++	unsigned int metadata_size;
++	unsigned int ecc_strength;
++	unsigned int page_size;
++	unsigned int gf_len;
++	int ret;
++
++	if (common_nfc_set_geometry(this))
++		return !0;
++
++	block_count   = bch_geo->ecc_chunk_count - 1;
++	block_size    = bch_geo->ecc_chunk_size;
++	metadata_size = bch_geo->metadata_size;
++	ecc_strength  = bch_geo->ecc_strength >> 1;
++	page_size     = bch_geo->page_size;
++	gf_len        = bch_geo->gf_len;
++
++	ret = gpmi_enable_clk(this);
++	if (ret)
++		return ret;
++
++	/*
++	* Due to erratum #2847 of the MX23, the BCH cannot be soft reset on this
++	* chip, otherwise it will lock up. So we skip resetting BCH on the MX23.
++	* On the other hand, the MX28 needs the reset, because one case has been
++	* seen where the BCH produced ECC errors constantly after 10000
++	* consecutive reboots. The latter case has not been seen on the MX23
++	* yet, still we don't know if it could happen there as well.
++	*/
++	ret = gpmi_reset_block(r->bch_regs, GPMI_IS_MX23(this));
++	if (ret)
++		goto err_out;
++
++	/* Configure layout 0. */
++	writel(BF_BCH_FLASH0LAYOUT0_NBLOCKS(block_count)
++			| BF_BCH_FLASH0LAYOUT0_META_SIZE(metadata_size)
++			| BF_BCH_FLASH0LAYOUT0_ECC0(ecc_strength, this)
++			| BF_BCH_FLASH0LAYOUT0_GF(gf_len, this)
++			| BF_BCH_FLASH0LAYOUT0_DATA0_SIZE(block_size, this),
++			r->bch_regs + HW_BCH_FLASH0LAYOUT0);
++
++	writel(BF_BCH_FLASH0LAYOUT1_PAGE_SIZE(page_size)
++			| BF_BCH_FLASH0LAYOUT1_ECCN(ecc_strength, this)
++			| BF_BCH_FLASH0LAYOUT1_GF(gf_len, this)
++			| BF_BCH_FLASH0LAYOUT1_DATAN_SIZE(block_size, this),
++			r->bch_regs + HW_BCH_FLASH0LAYOUT1);
++
++	/* Set *all* chip selects to use layout 0. */
++	writel(0, r->bch_regs + HW_BCH_LAYOUTSELECT);
++
++	/* Enable interrupts. */
++	writel(BM_BCH_CTRL_COMPLETE_IRQ_EN,
++				r->bch_regs + HW_BCH_CTRL_SET);
++
++	gpmi_disable_clk(this);
++	return 0;
++err_out:
++	gpmi_disable_clk(this);
++	return ret;
++}
++
++/* Converts time in nanoseconds to cycles. */
++static unsigned int ns_to_cycles(unsigned int time,
++			unsigned int period, unsigned int min)
++{
++	unsigned int k;
++
++	k = (time + period - 1) / period;
++	return max(k, min);
++}
++
++#define DEF_MIN_PROP_DELAY	5
++#define DEF_MAX_PROP_DELAY	9
++/* Apply timing to current hardware conditions. */
++static int gpmi_nfc_compute_hardware_timing(struct gpmi_nand_data *this,
++					struct gpmi_nfc_hardware_timing *hw)
++{
++	struct timing_threshold *nfc = &timing_default_threshold;
++	struct resources *r = &this->resources;
++	struct nand_chip *nand = &this->nand;
++	struct nand_timing target = this->timing;
++	bool improved_timing_is_available;
++	unsigned long clock_frequency_in_hz;
++	unsigned int clock_period_in_ns;
++	bool dll_use_half_periods;
++	unsigned int dll_delay_shift;
++	unsigned int max_sample_delay_in_ns;
++	unsigned int address_setup_in_cycles;
++	unsigned int data_setup_in_ns;
++	unsigned int data_setup_in_cycles;
++	unsigned int data_hold_in_cycles;
++	int ideal_sample_delay_in_ns;
++	unsigned int sample_delay_factor;
++	int tEYE;
++	unsigned int min_prop_delay_in_ns = DEF_MIN_PROP_DELAY;
++	unsigned int max_prop_delay_in_ns = DEF_MAX_PROP_DELAY;
++
++	/*
++	 * If there are multiple chips, we need to relax the timings to allow
++	 * for signal distortion due to higher capacitance.
++	 */
++	if (nand->numchips > 2) {
++		target.data_setup_in_ns    += 10;
++		target.data_hold_in_ns     += 10;
++		target.address_setup_in_ns += 10;
++	} else if (nand->numchips > 1) {
++		target.data_setup_in_ns    += 5;
++		target.data_hold_in_ns     += 5;
++		target.address_setup_in_ns += 5;
++	}
++
++	/* Check if improved timing information is available. */
++	improved_timing_is_available =
++		(target.tREA_in_ns  >= 0) &&
++		(target.tRLOH_in_ns >= 0) &&
++		(target.tRHOH_in_ns >= 0);
++
++	/* Inspect the clock. */
++	nfc->clock_frequency_in_hz = clk_get_rate(r->clock[0]);
++	clock_frequency_in_hz = nfc->clock_frequency_in_hz;
++	clock_period_in_ns    = NSEC_PER_SEC / clock_frequency_in_hz;
++
++	/*
++	 * The NFC quantizes setup and hold parameters in terms of clock cycles.
++	 * Here, we quantize the setup and hold timing parameters to the
++	 * next-highest clock period to make sure we apply at least the
++	 * specified times.
++	 *
++	 * For data setup and data hold, the hardware interprets a value of zero
++	 * as the largest possible delay. This is not what's intended by a zero
++	 * in the input parameter, so we impose a minimum of one cycle.
++	 */
++	data_setup_in_cycles    = ns_to_cycles(target.data_setup_in_ns,
++							clock_period_in_ns, 1);
++	data_hold_in_cycles     = ns_to_cycles(target.data_hold_in_ns,
++							clock_period_in_ns, 1);
++	address_setup_in_cycles = ns_to_cycles(target.address_setup_in_ns,
++							clock_period_in_ns, 0);
++
++	/*
++	 * The clock's period affects the sample delay in a number of ways:
++	 *
++	 * (1) The NFC HAL tells us the maximum clock period the sample delay
++	 *     DLL can tolerate. If the clock period is greater than half that
++	 *     maximum, we must configure the DLL to be driven by half periods.
++	 *
++	 * (2) We need to convert from an ideal sample delay, in ns, to a
++	 *     "sample delay factor," which the NFC uses. This factor depends on
++	 *     whether we're driving the DLL with full or half periods.
++	 *     Paraphrasing the reference manual:
++	 *
++	 *         AD = SDF x 0.125 x RP
++	 *
++	 * where:
++	 *
++	 *     AD   is the applied delay, in ns.
++	 *     SDF  is the sample delay factor, which is dimensionless.
++	 *     RP   is the reference period, in ns, which is a full clock period
++	 *          if the DLL is being driven by full periods, or half that if
++	 *          the DLL is being driven by half periods.
++	 *
++	 * Let's re-arrange this in a way that's more useful to us:
++	 *
++	 *                        8
++	 *         SDF  =  AD x ----
++	 *                       RP
++	 *
++	 * The reference period is either the clock period or half that, so this
++	 * is:
++	 *
++	 *                        8       AD x DDF
++	 *         SDF  =  AD x -----  =  --------
++	 *                      f x P        P
++	 *
++	 * where:
++	 *
++	 *       f  is 1 or 1/2, depending on how we're driving the DLL.
++	 *       P  is the clock period.
++	 *     DDF  is the DLL Delay Factor, a dimensionless value that
++	 *          incorporates all the constants in the conversion.
++	 *
++	 * DDF will be either 8 or 16, both of which are powers of two. We can
++	 * reduce the cost of this conversion by using bit shifts instead of
++	 * multiplication or division. Thus:
++	 *
++	 *                 AD << DDS
++	 *         SDF  =  ---------
++	 *                     P
++	 *
++	 *     or
++	 *
++	 *         AD  =  (SDF >> DDS) x P
++	 *
++	 * where:
++	 *
++	 *     DDS  is the DLL Delay Shift, the logarithm to base 2 of the DDF.
++	 */
++	if (clock_period_in_ns > (nfc->max_dll_clock_period_in_ns >> 1)) {
++		dll_use_half_periods = true;
++		dll_delay_shift      = 3 + 1;
++	} else {
++		dll_use_half_periods = false;
++		dll_delay_shift      = 3;
++	}
++
++	/*
++	 * Compute the maximum sample delay the NFC allows, under current
++	 * conditions. If the clock is running too slowly, no sample delay is
++	 * possible.
++	 */
++	if (clock_period_in_ns > nfc->max_dll_clock_period_in_ns)
++		max_sample_delay_in_ns = 0;
++	else {
++		/*
++		 * Compute the delay implied by the largest sample delay factor
++		 * the NFC allows.
++		 */
++		max_sample_delay_in_ns =
++			(nfc->max_sample_delay_factor * clock_period_in_ns) >>
++								dll_delay_shift;
++
++		/*
++		 * Check if the implied sample delay larger than the NFC
++		 * actually allows.
++		 */
++		if (max_sample_delay_in_ns > nfc->max_dll_delay_in_ns)
++			max_sample_delay_in_ns = nfc->max_dll_delay_in_ns;
++	}
++
++	/*
++	 * Check if improved timing information is available. If not, we have to
++	 * use a less-sophisticated algorithm.
++	 */
++	if (!improved_timing_is_available) {
++		/*
++		 * Fold the read setup time required by the NFC into the ideal
++		 * sample delay.
++		 */
++		ideal_sample_delay_in_ns = target.gpmi_sample_delay_in_ns +
++						nfc->internal_data_setup_in_ns;
++
++		/*
++		 * The ideal sample delay may be greater than the maximum
++		 * allowed by the NFC. If so, we can trade off sample delay time
++		 * for more data setup time.
++		 *
++		 * In each iteration of the following loop, we add a cycle to
++		 * the data setup time and subtract a corresponding amount from
++		 * the sample delay until we've satisified the constraints or
++		 * can't do any better.
++		 */
++		while ((ideal_sample_delay_in_ns > max_sample_delay_in_ns) &&
++			(data_setup_in_cycles < nfc->max_data_setup_cycles)) {
++
++			data_setup_in_cycles++;
++			ideal_sample_delay_in_ns -= clock_period_in_ns;
++
++			if (ideal_sample_delay_in_ns < 0)
++				ideal_sample_delay_in_ns = 0;
++
++		}
++
++		/*
++		 * Compute the sample delay factor that corresponds most closely
++		 * to the ideal sample delay. If the result is too large for the
++		 * NFC, use the maximum value.
++		 *
++		 * Notice that we use the ns_to_cycles function to compute the
++		 * sample delay factor. We do this because the form of the
++		 * computation is the same as that for calculating cycles.
++		 */
++		sample_delay_factor =
++			ns_to_cycles(
++				ideal_sample_delay_in_ns << dll_delay_shift,
++							clock_period_in_ns, 0);
++
++		if (sample_delay_factor > nfc->max_sample_delay_factor)
++			sample_delay_factor = nfc->max_sample_delay_factor;
++
++		/* Skip to the part where we return our results. */
++		goto return_results;
++	}
++
++	/*
++	 * If control arrives here, we have more detailed timing information,
++	 * so we can use a better algorithm.
++	 */
++
++	/*
++	 * Fold the read setup time required by the NFC into the maximum
++	 * propagation delay.
++	 */
++	max_prop_delay_in_ns += nfc->internal_data_setup_in_ns;
++
++	/*
++	 * Earlier, we computed the number of clock cycles required to satisfy
++	 * the data setup time. Now, we need to know the actual nanoseconds.
++	 */
++	data_setup_in_ns = clock_period_in_ns * data_setup_in_cycles;
++
++	/*
++	 * Compute tEYE, the width of the data eye when reading from the NAND
++	 * Flash. The eye width is fundamentally determined by the data setup
++	 * time, perturbed by propagation delays and some characteristics of the
++	 * NAND Flash device.
++	 *
++	 * start of the eye = max_prop_delay + tREA
++	 * end of the eye   = min_prop_delay + tRHOH + data_setup
++	 */
++	tEYE = (int)min_prop_delay_in_ns + (int)target.tRHOH_in_ns +
++							(int)data_setup_in_ns;
++
++	tEYE -= (int)max_prop_delay_in_ns + (int)target.tREA_in_ns;
++
++	/*
++	 * The eye must be open. If it's not, we can try to open it by
++	 * increasing its main forcer, the data setup time.
++	 *
++	 * In each iteration of the following loop, we increase the data setup
++	 * time by a single clock cycle. We do this until either the eye is
++	 * open or we run into NFC limits.
++	 */
++	while ((tEYE <= 0) &&
++			(data_setup_in_cycles < nfc->max_data_setup_cycles)) {
++		/* Give a cycle to data setup. */
++		data_setup_in_cycles++;
++		/* Synchronize the data setup time with the cycles. */
++		data_setup_in_ns += clock_period_in_ns;
++		/* Adjust tEYE accordingly. */
++		tEYE += clock_period_in_ns;
++	}
++
++	/*
++	 * When control arrives here, the eye is open. The ideal time to sample
++	 * the data is in the center of the eye:
++	 *
++	 *     end of the eye + start of the eye
++	 *     ---------------------------------  -  data_setup
++	 *                    2
++	 *
++	 * After some algebra, this simplifies to the code immediately below.
++	 */
++	ideal_sample_delay_in_ns =
++		((int)max_prop_delay_in_ns +
++			(int)target.tREA_in_ns +
++				(int)min_prop_delay_in_ns +
++					(int)target.tRHOH_in_ns -
++						(int)data_setup_in_ns) >> 1;
++
++	/*
++	 * The following figure illustrates some aspects of a NAND Flash read:
++	 *
++	 *
++	 *           __                   _____________________________________
++	 * RDN         \_________________/
++	 *
++	 *                                         <---- tEYE ----->
++	 *                                        /-----------------\
++	 * Read Data ----------------------------<                   >---------
++	 *                                        \-----------------/
++	 *             ^                 ^                 ^              ^
++	 *             |                 |                 |              |
++	 *             |<--Data Setup -->|<--Delay Time -->|              |
++	 *             |                 |                 |              |
++	 *             |                 |                                |
++	 *             |                 |<--   Quantized Delay Time   -->|
++	 *             |                 |                                |
++	 *
++	 *
++	 * We have some issues we must now address:
++	 *
++	 * (1) The *ideal* sample delay time must not be negative. If it is, we
++	 *     jam it to zero.
++	 *
++	 * (2) The *ideal* sample delay time must not be greater than that
++	 *     allowed by the NFC. If it is, we can increase the data setup
++	 *     time, which will reduce the delay between the end of the data
++	 *     setup and the center of the eye. It will also make the eye
++	 *     larger, which might help with the next issue...
++	 *
++	 * (3) The *quantized* sample delay time must not fall either before the
++	 *     eye opens or after it closes (the latter is the problem
++	 *     illustrated in the above figure).
++	 */
++
++	/* Jam a negative ideal sample delay to zero. */
++	if (ideal_sample_delay_in_ns < 0)
++		ideal_sample_delay_in_ns = 0;
++
++	/*
++	 * Extend the data setup as needed to reduce the ideal sample delay
++	 * below the maximum permitted by the NFC.
++	 */
++	while ((ideal_sample_delay_in_ns > max_sample_delay_in_ns) &&
++			(data_setup_in_cycles < nfc->max_data_setup_cycles)) {
++
++		/* Give a cycle to data setup. */
++		data_setup_in_cycles++;
++		/* Synchronize the data setup time with the cycles. */
++		data_setup_in_ns += clock_period_in_ns;
++		/* Adjust tEYE accordingly. */
++		tEYE += clock_period_in_ns;
++
++		/*
++		 * Decrease the ideal sample delay by one half cycle, to keep it
++		 * in the middle of the eye.
++		 */
++		ideal_sample_delay_in_ns -= (clock_period_in_ns >> 1);
++
++		/* Jam a negative ideal sample delay to zero. */
++		if (ideal_sample_delay_in_ns < 0)
++			ideal_sample_delay_in_ns = 0;
++	}
++
++	/*
++	 * Compute the sample delay factor that corresponds to the ideal sample
++	 * delay. If the result is too large, then use the maximum allowed
++	 * value.
++	 *
++	 * Notice that we use the ns_to_cycles function to compute the sample
++	 * delay factor. We do this because the form of the computation is the
++	 * same as that for calculating cycles.
++	 */
++	sample_delay_factor =
++		ns_to_cycles(ideal_sample_delay_in_ns << dll_delay_shift,
++							clock_period_in_ns, 0);
++
++	if (sample_delay_factor > nfc->max_sample_delay_factor)
++		sample_delay_factor = nfc->max_sample_delay_factor;
++
++	/*
++	 * These macros conveniently encapsulate a computation we'll use to
++	 * continuously evaluate whether or not the data sample delay is inside
++	 * the eye.
++	 */
++	#define IDEAL_DELAY  ((int) ideal_sample_delay_in_ns)
++
++	#define QUANTIZED_DELAY  \
++		((int) ((sample_delay_factor * clock_period_in_ns) >> \
++							dll_delay_shift))
++
++	#define DELAY_ERROR  (abs(QUANTIZED_DELAY - IDEAL_DELAY))
++
++	#define SAMPLE_IS_NOT_WITHIN_THE_EYE  (DELAY_ERROR > (tEYE >> 1))
++
++	/*
++	 * While the quantized sample time falls outside the eye, reduce the
++	 * sample delay or extend the data setup to move the sampling point back
++	 * toward the eye. Do not allow the number of data setup cycles to
++	 * exceed the maximum allowed by the NFC.
++	 */
++	while (SAMPLE_IS_NOT_WITHIN_THE_EYE &&
++			(data_setup_in_cycles < nfc->max_data_setup_cycles)) {
++		/*
++		 * If control arrives here, the quantized sample delay falls
++		 * outside the eye. Check if it's before the eye opens, or after
++		 * the eye closes.
++		 */
++		if (QUANTIZED_DELAY > IDEAL_DELAY) {
++			/*
++			 * If control arrives here, the quantized sample delay
++			 * falls after the eye closes. Decrease the quantized
++			 * delay time and then go back to re-evaluate.
++			 */
++			if (sample_delay_factor != 0)
++				sample_delay_factor--;
++			continue;
++		}
++
++		/*
++		 * If control arrives here, the quantized sample delay falls
++		 * before the eye opens. Shift the sample point by increasing
++		 * data setup time. This will also make the eye larger.
++		 */
++
++		/* Give a cycle to data setup. */
++		data_setup_in_cycles++;
++		/* Synchronize the data setup time with the cycles. */
++		data_setup_in_ns += clock_period_in_ns;
++		/* Adjust tEYE accordingly. */
++		tEYE += clock_period_in_ns;
++
++		/*
++		 * Decrease the ideal sample delay by one half cycle, to keep it
++		 * in the middle of the eye.
++		 */
++		ideal_sample_delay_in_ns -= (clock_period_in_ns >> 1);
++
++		/* ...and one less period for the delay time. */
++		ideal_sample_delay_in_ns -= clock_period_in_ns;
++
++		/* Jam a negative ideal sample delay to zero. */
++		if (ideal_sample_delay_in_ns < 0)
++			ideal_sample_delay_in_ns = 0;
++
++		/*
++		 * We have a new ideal sample delay, so re-compute the quantized
++		 * delay.
++		 */
++		sample_delay_factor =
++			ns_to_cycles(
++				ideal_sample_delay_in_ns << dll_delay_shift,
++							clock_period_in_ns, 0);
++
++		if (sample_delay_factor > nfc->max_sample_delay_factor)
++			sample_delay_factor = nfc->max_sample_delay_factor;
++	}
++
++	/* Control arrives here when we're ready to return our results. */
++return_results:
++	hw->data_setup_in_cycles    = data_setup_in_cycles;
++	hw->data_hold_in_cycles     = data_hold_in_cycles;
++	hw->address_setup_in_cycles = address_setup_in_cycles;
++	hw->use_half_periods        = dll_use_half_periods;
++	hw->sample_delay_factor     = sample_delay_factor;
++	hw->device_busy_timeout     = GPMI_DEFAULT_BUSY_TIMEOUT;
++	hw->wrn_dly_sel             = BV_GPMI_CTRL1_WRN_DLY_SEL_4_TO_8NS;
++
++	/* Return success. */
++	return 0;
++}
++
++/*
++ * <1> Firstly, we should know what's the GPMI-clock means.
++ *     The GPMI-clock is the internal clock in the gpmi nand controller.
++ *     If you set 100MHz to gpmi nand controller, the GPMI-clock's period
++ *     is 10ns. Mark the GPMI-clock's period as GPMI-clock-period.
++ *
++ * <2> Secondly, we should know what's the frequency on the nand chip pins.
++ *     The frequency on the nand chip pins is derived from the GPMI-clock.
++ *     We can get it from the following equation:
++ *
++ *         F = G / (DS + DH)
++ *
++ *         F  : the frequency on the nand chip pins.
++ *         G  : the GPMI clock, such as 100MHz.
++ *         DS : GPMI_HW_GPMI_TIMING0:DATA_SETUP
++ *         DH : GPMI_HW_GPMI_TIMING0:DATA_HOLD
++ *
++ * <3> Thirdly, when the frequency on the nand chip pins is above 33MHz,
++ *     the nand EDO(extended Data Out) timing could be applied.
++ *     The GPMI implements a feedback read strobe to sample the read data.
++ *     The feedback read strobe can be delayed to support the nand EDO timing
++ *     where the read strobe may deasserts before the read data is valid, and
++ *     read data is valid for some time after read strobe.
++ *
++ *     The following figure illustrates some aspects of a NAND Flash read:
++ *
++ *                   |<---tREA---->|
++ *                   |             |
++ *                   |         |   |
++ *                   |<--tRP-->|   |
++ *                   |         |   |
++ *                  __          ___|__________________________________
++ *     RDN            \________/   |
++ *                                 |
++ *                                 /---------\
++ *     Read Data    --------------<           >---------
++ *                                 \---------/
++ *                                |     |
++ *                                |<-D->|
++ *     FeedbackRDN  ________             ____________
++ *                          \___________/
++ *
++ *          D stands for delay, set in the HW_GPMI_CTRL1:RDN_DELAY.
++ *
++ *
++ * <4> Now, we begin to describe how to compute the right RDN_DELAY.
++ *
++ *  4.1) From the aspect of the nand chip pins:
++ *        Delay = (tREA + C - tRP)               {1}
++ *
++ *        tREA : the maximum read access time. From the ONFI nand standards,
++ *               we know that tREA is 16ns in mode 5, tREA is 20ns is mode 4.
++ *               Please check it in : www.onfi.org
++ *        C    : a constant for adjust the delay. default is 4.
++ *        tRP  : the read pulse width.
++ *               Specified by the HW_GPMI_TIMING0:DATA_SETUP:
++ *                    tRP = (GPMI-clock-period) * DATA_SETUP
++ *
++ *  4.2) From the aspect of the GPMI nand controller:
++ *         Delay = RDN_DELAY * 0.125 * RP        {2}
++ *
++ *         RP   : the DLL reference period.
++ *            if (GPMI-clock-period > DLL_THRETHOLD)
++ *                   RP = GPMI-clock-period / 2;
++ *            else
++ *                   RP = GPMI-clock-period;
++ *
++ *            Set the HW_GPMI_CTRL1:HALF_PERIOD if GPMI-clock-period
++ *            is greater DLL_THRETHOLD. In other SOCs, the DLL_THRETHOLD
++ *            is 16ns, but in mx6q, we use 12ns.
++ *
++ *  4.3) since {1} equals {2}, we get:
++ *
++ *                    (tREA + 4 - tRP) * 8
++ *         RDN_DELAY = ---------------------     {3}
++ *                           RP
++ *
++ *  4.4) We only support the fastest asynchronous mode of ONFI nand.
++ *       For some ONFI nand, the mode 4 is the fastest mode;
++ *       while for some ONFI nand, the mode 5 is the fastest mode.
++ *       So we only support the mode 4 and mode 5. It is no need to
++ *       support other modes.
++ */
++static void gpmi_compute_edo_timing(struct gpmi_nand_data *this,
++			struct gpmi_nfc_hardware_timing *hw)
++{
++	struct resources *r = &this->resources;
++	unsigned long rate = clk_get_rate(r->clock[0]);
++	int mode = this->timing_mode;
++	int dll_threshold = this->devdata->max_chain_delay;
++	unsigned long delay;
++	unsigned long clk_period;
++	int t_rea;
++	int c = 4;
++	int t_rp;
++	int rp;
++
++	/*
++	 * [1] for GPMI_HW_GPMI_TIMING0:
++	 *     The async mode requires 40MHz for mode 4, 50MHz for mode 5.
++	 *     The GPMI can support 100MHz at most. So if we want to
++	 *     get the 40MHz or 50MHz, we have to set DS=1, DH=1.
++	 *     Set the ADDRESS_SETUP to 0 in mode 4.
++	 */
++	hw->data_setup_in_cycles = 1;
++	hw->data_hold_in_cycles = 1;
++	hw->address_setup_in_cycles = ((mode == 5) ? 1 : 0);
++
++	/* [2] for GPMI_HW_GPMI_TIMING1 */
++	hw->device_busy_timeout = 0x9000;
++
++	/* [3] for GPMI_HW_GPMI_CTRL1 */
++	hw->wrn_dly_sel = BV_GPMI_CTRL1_WRN_DLY_SEL_NO_DELAY;
++
++	/*
++	 * Enlarge 10 times for the numerator and denominator in {3}.
++	 * This make us to get more accurate result.
++	 */
++	clk_period = NSEC_PER_SEC / (rate / 10);
++	dll_threshold *= 10;
++	t_rea = ((mode == 5) ? 16 : 20) * 10;
++	c *= 10;
++
++	t_rp = clk_period * 1; /* DATA_SETUP is 1 */
++
++	if (clk_period > dll_threshold) {
++		hw->use_half_periods = 1;
++		rp = clk_period / 2;
++	} else {
++		hw->use_half_periods = 0;
++		rp = clk_period;
++	}
++
++	/*
++	 * Multiply the numerator with 10, we could do a round off:
++	 *      7.8 round up to 8; 7.4 round down to 7.
++	 */
++	delay  = (((t_rea + c - t_rp) * 8) * 10) / rp;
++	delay = (delay + 5) / 10;
++
++	hw->sample_delay_factor = delay;
++}
++
++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);
++	uint8_t *feature;
++	unsigned long rate;
++	int ret;
++
++	feature = kzalloc(ONFI_SUBFEATURE_PARAM_LEN, GFP_KERNEL);
++	if (!feature)
++		return -ENOMEM;
++
++	nand->select_chip(mtd, 0);
++
++	/* [1] send SET FEATURE command to NAND */
++	feature[0] = mode;
++	ret = nand->onfi_set_features(mtd, nand,
++				ONFI_FEATURE_ADDR_TIMING_MODE, feature);
++	if (ret)
++		goto err_out;
++
++	/* [2] send GET FEATURE command to double-check the timing mode */
++	memset(feature, 0, ONFI_SUBFEATURE_PARAM_LEN);
++	ret = nand->onfi_get_features(mtd, nand,
++				ONFI_FEATURE_ADDR_TIMING_MODE, feature);
++	if (ret || feature[0] != mode)
++		goto err_out;
++
++	nand->select_chip(mtd, -1);
++
++	/* [3] set the main IO clock, 100MHz for mode 5, 80MHz for mode 4. */
++	rate = (mode == 5) ? 100000000 : 80000000;
++	clk_set_rate(r->clock[0], rate);
++
++	/* Let the gpmi_begin() re-compute the timing again. */
++	this->flags &= ~GPMI_TIMING_INIT_OK;
++
++	this->flags |= GPMI_ASYNC_EDO_ENABLED;
++	this->timing_mode = mode;
++	kfree(feature);
++	dev_info(this->dev, "enable the asynchronous EDO mode %d\n", mode);
++	return 0;
++
++err_out:
++	nand->select_chip(mtd, -1);
++	kfree(feature);
++	dev_err(this->dev, "mode:%d ,failed in set feature.\n", mode);
++	return -EINVAL;
++}
++
++int gpmi_extra_init(struct gpmi_nand_data *this)
++{
++	struct nand_chip *chip = &this->nand;
++
++	/* Enable the asynchronous EDO feature. */
++	if (GPMI_IS_MX6(this) && chip->onfi_version) {
++		int mode = onfi_get_async_timing_mode(chip);
++
++		/* We only support the timing mode 4 and mode 5. */
++		if (mode & ONFI_TIMING_MODE_5)
++			mode = 5;
++		else if (mode & ONFI_TIMING_MODE_4)
++			mode = 4;
++		else
++			return 0;
++
++		return enable_edo_mode(this, mode);
++	}
++	return 0;
++}
++
++/* Begin the I/O */
++void gpmi_begin(struct gpmi_nand_data *this)
++{
++	struct resources *r = &this->resources;
++	void __iomem *gpmi_regs = r->gpmi_regs;
++	unsigned int   clock_period_in_ns;
++	uint32_t       reg;
++	unsigned int   dll_wait_time_in_us;
++	struct gpmi_nfc_hardware_timing  hw;
++	int ret;
++
++	/* Enable the clock. */
++	ret = gpmi_enable_clk(this);
++	if (ret) {
++		dev_err(this->dev, "We failed in enable the clk\n");
++		goto err_out;
++	}
++
++	/* Only initialize the timing once */
++	if (this->flags & GPMI_TIMING_INIT_OK)
++		return;
++	this->flags |= GPMI_TIMING_INIT_OK;
++
++	if (this->flags & GPMI_ASYNC_EDO_ENABLED)
++		gpmi_compute_edo_timing(this, &hw);
++	else
++		gpmi_nfc_compute_hardware_timing(this, &hw);
++
++	/* [1] Set HW_GPMI_TIMING0 */
++	reg = BF_GPMI_TIMING0_ADDRESS_SETUP(hw.address_setup_in_cycles) |
++		BF_GPMI_TIMING0_DATA_HOLD(hw.data_hold_in_cycles)         |
++		BF_GPMI_TIMING0_DATA_SETUP(hw.data_setup_in_cycles);
++
++	writel(reg, gpmi_regs + HW_GPMI_TIMING0);
++
++	/* [2] Set HW_GPMI_TIMING1 */
++	writel(BF_GPMI_TIMING1_BUSY_TIMEOUT(hw.device_busy_timeout),
++		gpmi_regs + HW_GPMI_TIMING1);
++
++	/* [3] The following code is to set the HW_GPMI_CTRL1. */
++
++	/* Set the WRN_DLY_SEL */
++	writel(BM_GPMI_CTRL1_WRN_DLY_SEL, gpmi_regs + HW_GPMI_CTRL1_CLR);
++	writel(BF_GPMI_CTRL1_WRN_DLY_SEL(hw.wrn_dly_sel),
++					gpmi_regs + HW_GPMI_CTRL1_SET);
++
++	/* DLL_ENABLE must be set to 0 when setting RDN_DELAY or HALF_PERIOD. */
++	writel(BM_GPMI_CTRL1_DLL_ENABLE, gpmi_regs + HW_GPMI_CTRL1_CLR);
++
++	/* Clear out the DLL control fields. */
++	reg = BM_GPMI_CTRL1_RDN_DELAY | BM_GPMI_CTRL1_HALF_PERIOD;
++	writel(reg, gpmi_regs + HW_GPMI_CTRL1_CLR);
++
++	/* If no sample delay is called for, return immediately. */
++	if (!hw.sample_delay_factor)
++		return;
++
++	/* Set RDN_DELAY or HALF_PERIOD. */
++	reg = ((hw.use_half_periods) ? BM_GPMI_CTRL1_HALF_PERIOD : 0)
++		| BF_GPMI_CTRL1_RDN_DELAY(hw.sample_delay_factor);
++
++	writel(reg, gpmi_regs + HW_GPMI_CTRL1_SET);
++
++	/* At last, we enable the DLL. */
++	writel(BM_GPMI_CTRL1_DLL_ENABLE, gpmi_regs + HW_GPMI_CTRL1_SET);
++
++	/*
++	 * After we enable the GPMI DLL, we have to wait 64 clock cycles before
++	 * we can use the GPMI. Calculate the amount of time we need to wait,
++	 * in microseconds.
++	 */
++	clock_period_in_ns = NSEC_PER_SEC / clk_get_rate(r->clock[0]);
++	dll_wait_time_in_us = (clock_period_in_ns * 64) / 1000;
++
++	if (!dll_wait_time_in_us)
++		dll_wait_time_in_us = 1;
++
++	/* Wait for the DLL to settle. */
++	udelay(dll_wait_time_in_us);
++
++err_out:
++	return;
++}
++
++void gpmi_end(struct gpmi_nand_data *this)
++{
++	gpmi_disable_clk(this);
++}
++
++/* Clears a BCH interrupt. */
++void gpmi_clear_bch(struct gpmi_nand_data *this)
++{
++	struct resources *r = &this->resources;
++	writel(BM_BCH_CTRL_COMPLETE_IRQ, r->bch_regs + HW_BCH_CTRL_CLR);
++}
++
++/* Returns the Ready/Busy status of the given chip. */
++int gpmi_is_ready(struct gpmi_nand_data *this, unsigned chip)
++{
++	struct resources *r = &this->resources;
++	uint32_t mask = 0;
++	uint32_t reg = 0;
++
++	if (GPMI_IS_MX23(this)) {
++		mask = MX23_BM_GPMI_DEBUG_READY0 << chip;
++		reg = readl(r->gpmi_regs + HW_GPMI_DEBUG);
++	} else if (GPMI_IS_MX28(this) || GPMI_IS_MX6(this)) {
++		/*
++		 * In the imx6, all the ready/busy pins are bound
++		 * together. So we only need to check chip 0.
++		 */
++		if (GPMI_IS_MX6(this))
++			chip = 0;
++
++		/* MX28 shares the same R/B register as MX6Q. */
++		mask = MX28_BF_GPMI_STAT_READY_BUSY(1 << chip);
++		reg = readl(r->gpmi_regs + HW_GPMI_STAT);
++	} else
++		dev_err(this->dev, "unknown arch.\n");
++	return reg & mask;
++}
++
++static inline void set_dma_type(struct gpmi_nand_data *this,
++					enum dma_ops_type type)
++{
++	this->last_dma_type = this->dma_type;
++	this->dma_type = type;
++}
++
++int gpmi_send_command(struct gpmi_nand_data *this)
++{
++	struct dma_chan *channel = get_dma_chan(this);
++	struct dma_async_tx_descriptor *desc;
++	struct scatterlist *sgl;
++	int chip = this->current_chip;
++	u32 pio[3];
++
++	/* [1] send out the PIO words */
++	pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(BV_GPMI_CTRL0_COMMAND_MODE__WRITE)
++		| BM_GPMI_CTRL0_WORD_LENGTH
++		| BF_GPMI_CTRL0_CS(chip, this)
++		| BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this)
++		| BF_GPMI_CTRL0_ADDRESS(BV_GPMI_CTRL0_ADDRESS__NAND_CLE)
++		| BM_GPMI_CTRL0_ADDRESS_INCREMENT
++		| BF_GPMI_CTRL0_XFER_COUNT(this->command_length);
++	pio[1] = pio[2] = 0;
++	desc = dmaengine_prep_slave_sg(channel,
++					(struct scatterlist *)pio,
++					ARRAY_SIZE(pio), DMA_TRANS_NONE, 0);
++	if (!desc)
++		return -EINVAL;
++
++	/* [2] send out the COMMAND + ADDRESS string stored in @buffer */
++	sgl = &this->cmd_sgl;
++
++	sg_init_one(sgl, this->cmd_buffer, this->command_length);
++	dma_map_sg(this->dev, sgl, 1, DMA_TO_DEVICE);
++	desc = dmaengine_prep_slave_sg(channel,
++				sgl, 1, DMA_MEM_TO_DEV,
++				DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
++	if (!desc)
++		return -EINVAL;
++
++	/* [3] submit the DMA */
++	set_dma_type(this, DMA_FOR_COMMAND);
++	return start_dma_without_bch_irq(this, desc);
++}
++
++int gpmi_send_data(struct gpmi_nand_data *this)
++{
++	struct dma_async_tx_descriptor *desc;
++	struct dma_chan *channel = get_dma_chan(this);
++	int chip = this->current_chip;
++	uint32_t command_mode;
++	uint32_t address;
++	u32 pio[2];
++
++	/* [1] PIO */
++	command_mode = BV_GPMI_CTRL0_COMMAND_MODE__WRITE;
++	address      = BV_GPMI_CTRL0_ADDRESS__NAND_DATA;
++
++	pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(command_mode)
++		| BM_GPMI_CTRL0_WORD_LENGTH
++		| BF_GPMI_CTRL0_CS(chip, this)
++		| BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this)
++		| BF_GPMI_CTRL0_ADDRESS(address)
++		| BF_GPMI_CTRL0_XFER_COUNT(this->upper_len);
++	pio[1] = 0;
++	desc = dmaengine_prep_slave_sg(channel, (struct scatterlist *)pio,
++					ARRAY_SIZE(pio), DMA_TRANS_NONE, 0);
++	if (!desc)
++		return -EINVAL;
++
++	/* [2] send DMA request */
++	prepare_data_dma(this, DMA_TO_DEVICE);
++	desc = dmaengine_prep_slave_sg(channel, &this->data_sgl,
++					1, DMA_MEM_TO_DEV,
++					DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
++	if (!desc)
++		return -EINVAL;
++
++	/* [3] submit the DMA */
++	set_dma_type(this, DMA_FOR_WRITE_DATA);
++	return start_dma_without_bch_irq(this, desc);
++}
++
++int gpmi_read_data(struct gpmi_nand_data *this)
++{
++	struct dma_async_tx_descriptor *desc;
++	struct dma_chan *channel = get_dma_chan(this);
++	int chip = this->current_chip;
++	u32 pio[2];
++
++	/* [1] : send PIO */
++	pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(BV_GPMI_CTRL0_COMMAND_MODE__READ)
++		| BM_GPMI_CTRL0_WORD_LENGTH
++		| BF_GPMI_CTRL0_CS(chip, this)
++		| BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this)
++		| BF_GPMI_CTRL0_ADDRESS(BV_GPMI_CTRL0_ADDRESS__NAND_DATA)
++		| BF_GPMI_CTRL0_XFER_COUNT(this->upper_len);
++	pio[1] = 0;
++	desc = dmaengine_prep_slave_sg(channel,
++					(struct scatterlist *)pio,
++					ARRAY_SIZE(pio), DMA_TRANS_NONE, 0);
++	if (!desc)
++		return -EINVAL;
++
++	/* [2] : send DMA request */
++	prepare_data_dma(this, DMA_FROM_DEVICE);
++	desc = dmaengine_prep_slave_sg(channel, &this->data_sgl,
++					1, DMA_DEV_TO_MEM,
++					DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
++	if (!desc)
++		return -EINVAL;
++
++	/* [3] : submit the DMA */
++	set_dma_type(this, DMA_FOR_READ_DATA);
++	return start_dma_without_bch_irq(this, desc);
++}
++
++int gpmi_send_page(struct gpmi_nand_data *this,
++			dma_addr_t payload, dma_addr_t auxiliary)
++{
++	struct bch_geometry *geo = &this->bch_geometry;
++	uint32_t command_mode;
++	uint32_t address;
++	uint32_t ecc_command;
++	uint32_t buffer_mask;
++	struct dma_async_tx_descriptor *desc;
++	struct dma_chan *channel = get_dma_chan(this);
++	int chip = this->current_chip;
++	u32 pio[6];
++
++	/* A DMA descriptor that does an ECC page read. */
++	command_mode = BV_GPMI_CTRL0_COMMAND_MODE__WRITE;
++	address      = BV_GPMI_CTRL0_ADDRESS__NAND_DATA;
++	ecc_command  = BV_GPMI_ECCCTRL_ECC_CMD__BCH_ENCODE;
++	buffer_mask  = BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_PAGE |
++				BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_AUXONLY;
++
++	pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(command_mode)
++		| BM_GPMI_CTRL0_WORD_LENGTH
++		| BF_GPMI_CTRL0_CS(chip, this)
++		| BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this)
++		| BF_GPMI_CTRL0_ADDRESS(address)
++		| BF_GPMI_CTRL0_XFER_COUNT(0);
++	pio[1] = 0;
++	pio[2] = BM_GPMI_ECCCTRL_ENABLE_ECC
++		| BF_GPMI_ECCCTRL_ECC_CMD(ecc_command)
++		| BF_GPMI_ECCCTRL_BUFFER_MASK(buffer_mask);
++	pio[3] = geo->page_size;
++	pio[4] = payload;
++	pio[5] = auxiliary;
++
++	desc = dmaengine_prep_slave_sg(channel,
++					(struct scatterlist *)pio,
++					ARRAY_SIZE(pio), DMA_TRANS_NONE,
++					DMA_CTRL_ACK);
++	if (!desc)
++		return -EINVAL;
++
++	set_dma_type(this, DMA_FOR_WRITE_ECC_PAGE);
++	return start_dma_with_bch_irq(this, desc);
++}
++
++int gpmi_read_page(struct gpmi_nand_data *this,
++				dma_addr_t payload, dma_addr_t auxiliary)
++{
++	struct bch_geometry *geo = &this->bch_geometry;
++	uint32_t command_mode;
++	uint32_t address;
++	uint32_t ecc_command;
++	uint32_t buffer_mask;
++	struct dma_async_tx_descriptor *desc;
++	struct dma_chan *channel = get_dma_chan(this);
++	int chip = this->current_chip;
++	u32 pio[6];
++
++	/* [1] Wait for the chip to report ready. */
++	command_mode = BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY;
++	address      = BV_GPMI_CTRL0_ADDRESS__NAND_DATA;
++
++	pio[0] =  BF_GPMI_CTRL0_COMMAND_MODE(command_mode)
++		| BM_GPMI_CTRL0_WORD_LENGTH
++		| BF_GPMI_CTRL0_CS(chip, this)
++		| BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this)
++		| BF_GPMI_CTRL0_ADDRESS(address)
++		| BF_GPMI_CTRL0_XFER_COUNT(0);
++	pio[1] = 0;
++	desc = dmaengine_prep_slave_sg(channel,
++				(struct scatterlist *)pio, 2,
++				DMA_TRANS_NONE, 0);
++	if (!desc)
++		return -EINVAL;
++
++	/* [2] Enable the BCH block and read. */
++	command_mode = BV_GPMI_CTRL0_COMMAND_MODE__READ;
++	address      = BV_GPMI_CTRL0_ADDRESS__NAND_DATA;
++	ecc_command  = BV_GPMI_ECCCTRL_ECC_CMD__BCH_DECODE;
++	buffer_mask  = BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_PAGE
++			| BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_AUXONLY;
++
++	pio[0] =  BF_GPMI_CTRL0_COMMAND_MODE(command_mode)
++		| BM_GPMI_CTRL0_WORD_LENGTH
++		| BF_GPMI_CTRL0_CS(chip, this)
++		| BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this)
++		| BF_GPMI_CTRL0_ADDRESS(address)
++		| BF_GPMI_CTRL0_XFER_COUNT(geo->page_size);
++
++	pio[1] = 0;
++	pio[2] =  BM_GPMI_ECCCTRL_ENABLE_ECC
++		| BF_GPMI_ECCCTRL_ECC_CMD(ecc_command)
++		| BF_GPMI_ECCCTRL_BUFFER_MASK(buffer_mask);
++	pio[3] = geo->page_size;
++	pio[4] = payload;
++	pio[5] = auxiliary;
++	desc = dmaengine_prep_slave_sg(channel,
++					(struct scatterlist *)pio,
++					ARRAY_SIZE(pio), DMA_TRANS_NONE,
++					DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
++	if (!desc)
++		return -EINVAL;
++
++	/* [3] Disable the BCH block */
++	command_mode = BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY;
++	address      = BV_GPMI_CTRL0_ADDRESS__NAND_DATA;
++
++	pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(command_mode)
++		| BM_GPMI_CTRL0_WORD_LENGTH
++		| BF_GPMI_CTRL0_CS(chip, this)
++		| BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this)
++		| BF_GPMI_CTRL0_ADDRESS(address)
++		| BF_GPMI_CTRL0_XFER_COUNT(geo->page_size);
++	pio[1] = 0;
++	pio[2] = 0; /* clear GPMI_HW_GPMI_ECCCTRL, disable the BCH. */
++	desc = dmaengine_prep_slave_sg(channel,
++				(struct scatterlist *)pio, 3,
++				DMA_TRANS_NONE,
++				DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
++	if (!desc)
++		return -EINVAL;
++
++	/* [4] submit the DMA */
++	set_dma_type(this, DMA_FOR_READ_ECC_PAGE);
++	return start_dma_with_bch_irq(this, desc);
++}
++
++/**
++ * gpmi_copy_bits - copy bits from one memory region to another
++ * @dst: destination buffer
++ * @dst_bit_off: bit offset we're starting to write at
++ * @src: source buffer
++ * @src_bit_off: bit offset we're starting to read from
++ * @nbits: number of bits to copy
++ *
++ * This functions copies bits from one memory region to another, and is used by
++ * the GPMI driver to copy ECC sections which are not guaranteed to be byte
++ * aligned.
++ *
++ * src and dst should not overlap.
++ *
++ */
++void gpmi_copy_bits(u8 *dst, size_t dst_bit_off,
++		    const u8 *src, size_t src_bit_off,
++		    size_t nbits)
++{
++	size_t i;
++	size_t nbytes;
++	u32 src_buffer = 0;
++	size_t bits_in_src_buffer = 0;
++
++	if (!nbits)
++		return;
++
++	/*
++	 * Move src and dst pointers to the closest byte pointer and store bit
++	 * offsets within a byte.
++	 */
++	src += src_bit_off / 8;
++	src_bit_off %= 8;
++
++	dst += dst_bit_off / 8;
++	dst_bit_off %= 8;
++
++	/*
++	 * Initialize the src_buffer value with bits available in the first
++	 * byte of data so that we end up with a byte aligned src pointer.
++	 */
++	if (src_bit_off) {
++		src_buffer = src[0] >> src_bit_off;
++		if (nbits >= (8 - src_bit_off)) {
++			bits_in_src_buffer += 8 - src_bit_off;
++		} else {
++			src_buffer &= GENMASK(nbits - 1, 0);
++			bits_in_src_buffer += nbits;
++		}
++		nbits -= bits_in_src_buffer;
++		src++;
++	}
++
++	/* Calculate the number of bytes that can be copied from src to dst. */
++	nbytes = nbits / 8;
++
++	/* Try to align dst to a byte boundary. */
++	if (dst_bit_off) {
++		if (bits_in_src_buffer < (8 - dst_bit_off) && nbytes) {
++			src_buffer |= src[0] << bits_in_src_buffer;
++			bits_in_src_buffer += 8;
++			src++;
++			nbytes--;
++		}
++
++		if (bits_in_src_buffer >= (8 - dst_bit_off)) {
++			dst[0] &= GENMASK(dst_bit_off - 1, 0);
++			dst[0] |= src_buffer << dst_bit_off;
++			src_buffer >>= (8 - dst_bit_off);
++			bits_in_src_buffer -= (8 - dst_bit_off);
++			dst_bit_off = 0;
++			dst++;
++			if (bits_in_src_buffer > 7) {
++				bits_in_src_buffer -= 8;
++				dst[0] = src_buffer;
++				dst++;
++				src_buffer >>= 8;
++			}
++		}
++	}
++
++	if (!bits_in_src_buffer && !dst_bit_off) {
++		/*
++		 * Both src and dst pointers are byte aligned, thus we can
++		 * just use the optimized memcpy function.
++		 */
++		if (nbytes)
++			memcpy(dst, src, nbytes);
++	} else {
++		/*
++		 * src buffer is not byte aligned, hence we have to copy each
++		 * src byte to the src_buffer variable before extracting a byte
++		 * to store in dst.
++		 */
++		for (i = 0; i < nbytes; i++) {
++			src_buffer |= src[i] << bits_in_src_buffer;
++			dst[i] = src_buffer;
++			src_buffer >>= 8;
++		}
++	}
++	/* Update dst and src pointers */
++	dst += nbytes;
++	src += nbytes;
++
++	/*
++	 * nbits is the number of remaining bits. It should not exceed 8 as
++	 * we've already copied as much bytes as possible.
++	 */
++	nbits %= 8;
++
++	/*
++	 * If there's no more bits to copy to the destination and src buffer
++	 * was already byte aligned, then we're done.
++	 */
++	if (!nbits && !bits_in_src_buffer)
++		return;
++
++	/* Copy the remaining bits to src_buffer */
++	if (nbits)
++		src_buffer |= (*src & GENMASK(nbits - 1, 0)) <<
++			      bits_in_src_buffer;
++	bits_in_src_buffer += nbits;
++
++	/*
++	 * In case there were not enough bits to get a byte aligned dst buffer
++	 * prepare the src_buffer variable to match the dst organization (shift
++	 * src_buffer by dst_bit_off and retrieve the least significant bits
++	 * from dst).
++	 */
++	if (dst_bit_off)
++		src_buffer = (src_buffer << dst_bit_off) |
++			     (*dst & GENMASK(dst_bit_off - 1, 0));
++	bits_in_src_buffer += dst_bit_off;
++
++	/*
++	 * Keep most significant bits from dst if we end up with an unaligned
++	 * number of bits.
++	 */
++	nbytes = bits_in_src_buffer / 8;
++	if (bits_in_src_buffer % 8) {
++		src_buffer |= (dst[nbytes] &
++			       GENMASK(7, bits_in_src_buffer % 8)) <<
++			      (nbytes * 8);
++		nbytes++;
++	}
++
++	/* Copy the remaining bytes to dst */
++	for (i = 0; i < nbytes; i++) {
++		dst[i] = src_buffer;
++		src_buffer >>= 8;
++	}
++}
+diff --git a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c
+new file mode 100644
+index 0000000..50f8d4a
+--- /dev/null
++++ b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c
+@@ -0,0 +1,2201 @@
++/*
++ * Freescale GPMI NAND Flash Driver
++ *
++ * Copyright (C) 2010-2015 Freescale Semiconductor, Inc.
++ * Copyright (C) 2008 Embedded Alley Solutions, Inc.
++ *
++ * 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.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++ */
++#include <linux/clk.h>
++#include <linux/slab.h>
++#include <linux/sched/task_stack.h>
++#include <linux/interrupt.h>
++#include <linux/module.h>
++#include <linux/mtd/partitions.h>
++#include <linux/of.h>
++#include <linux/of_device.h>
++#include "gpmi-nand.h"
++#include "bch-regs.h"
++
++/* Resource names for the GPMI NAND driver. */
++#define GPMI_NAND_GPMI_REGS_ADDR_RES_NAME  "gpmi-nand"
++#define GPMI_NAND_BCH_REGS_ADDR_RES_NAME   "bch"
++#define GPMI_NAND_BCH_INTERRUPT_RES_NAME   "bch"
++
++/* add our owner bbt descriptor */
++static uint8_t scan_ff_pattern[] = { 0xff };
++static struct nand_bbt_descr gpmi_bbt_descr = {
++	.options	= 0,
++	.offs		= 0,
++	.len		= 1,
++	.pattern	= scan_ff_pattern
++};
++
++/*
++ * We may change the layout if we can get the ECC info from the datasheet,
++ * else we will use all the (page + OOB).
++ */
++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 gpmi_nand_data *this = nand_get_controller_data(chip);
++	struct bch_geometry *geo = &this->bch_geometry;
++
++	if (section)
++		return -ERANGE;
++
++	oobregion->offset = 0;
++	oobregion->length = geo->page_size - mtd->writesize;
++
++	return 0;
++}
++
++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 gpmi_nand_data *this = nand_get_controller_data(chip);
++	struct bch_geometry *geo = &this->bch_geometry;
++
++	if (section)
++		return -ERANGE;
++
++	/* The available oob size we have. */
++	if (geo->page_size < mtd->writesize + mtd->oobsize) {
++		oobregion->offset = geo->page_size - mtd->writesize;
++		oobregion->length = mtd->oobsize - oobregion->offset;
++	}
++
++	return 0;
++}
++
++static const char * const gpmi_clks_for_mx2x[] = {
++	"gpmi_io",
++};
++
++static const struct mtd_ooblayout_ops gpmi_ooblayout_ops = {
++	.ecc = gpmi_ooblayout_ecc,
++	.free = gpmi_ooblayout_free,
++};
++
++static const struct gpmi_devdata gpmi_devdata_imx23 = {
++	.type = IS_MX23,
++	.bch_max_ecc_strength = 20,
++	.max_chain_delay = 16,
++	.clks = gpmi_clks_for_mx2x,
++	.clks_count = ARRAY_SIZE(gpmi_clks_for_mx2x),
++};
++
++static const struct gpmi_devdata gpmi_devdata_imx28 = {
++	.type = IS_MX28,
++	.bch_max_ecc_strength = 20,
++	.max_chain_delay = 16,
++	.clks = gpmi_clks_for_mx2x,
++	.clks_count = ARRAY_SIZE(gpmi_clks_for_mx2x),
++};
++
++static const char * const gpmi_clks_for_mx6[] = {
++	"gpmi_io", "gpmi_apb", "gpmi_bch", "gpmi_bch_apb", "per1_bch",
++};
++
++static const struct gpmi_devdata gpmi_devdata_imx6q = {
++	.type = IS_MX6Q,
++	.bch_max_ecc_strength = 40,
++	.max_chain_delay = 12,
++	.clks = gpmi_clks_for_mx6,
++	.clks_count = ARRAY_SIZE(gpmi_clks_for_mx6),
++};
++
++static const struct gpmi_devdata gpmi_devdata_imx6sx = {
++	.type = IS_MX6SX,
++	.bch_max_ecc_strength = 62,
++	.max_chain_delay = 12,
++	.clks = gpmi_clks_for_mx6,
++	.clks_count = ARRAY_SIZE(gpmi_clks_for_mx6),
++};
++
++static const char * const gpmi_clks_for_mx7d[] = {
++	"gpmi_io", "gpmi_bch_apb",
++};
++
++static const struct gpmi_devdata gpmi_devdata_imx7d = {
++	.type = IS_MX7D,
++	.bch_max_ecc_strength = 62,
++	.max_chain_delay = 12,
++	.clks = gpmi_clks_for_mx7d,
++	.clks_count = ARRAY_SIZE(gpmi_clks_for_mx7d),
++};
++
++static irqreturn_t bch_irq(int irq, void *cookie)
++{
++	struct gpmi_nand_data *this = cookie;
++
++	gpmi_clear_bch(this);
++	complete(&this->bch_done);
++	return IRQ_HANDLED;
++}
++
++/*
++ *  Calculate the ECC strength by hand:
++ *	E : The ECC strength.
++ *	G : the length of Galois Field.
++ *	N : The chunk count of per page.
++ *	O : the oobsize of the NAND chip.
++ *	M : the metasize of per page.
++ *
++ *	The formula is :
++ *		E * G * N
++ *	      ------------ <= (O - M)
++ *                  8
++ *
++ *      So, we get E by:
++ *                    (O - M) * 8
++ *              E <= -------------
++ *                       G * N
++ */
++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);
++	int ecc_strength;
++
++	ecc_strength = ((mtd->oobsize - geo->metadata_size) * 8)
++			/ (geo->gf_len * geo->ecc_chunk_count);
++
++	/* We need the minor even number. */
++	return round_down(ecc_strength, 2);
++}
++
++static inline bool gpmi_check_ecc(struct gpmi_nand_data *this)
++{
++	struct bch_geometry *geo = &this->bch_geometry;
++
++	/* Do the sanity check. */
++	if (GPMI_IS_MX23(this) || GPMI_IS_MX28(this)) {
++		/* The mx23/mx28 only support the GF13. */
++		if (geo->gf_len == 14)
++			return false;
++	}
++	return geo->ecc_strength <= this->devdata->bch_max_ecc_strength;
++}
++
++/*
++ * If we can get the ECC information from the nand chip, we do not
++ * need to calculate them ourselves.
++ *
++ * We may have available oob space in this case.
++ */
++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);
++	unsigned int block_mark_bit_offset;
++
++	if (!(chip->ecc_strength_ds > 0 && chip->ecc_step_ds > 0))
++		return -EINVAL;
++
++	switch (chip->ecc_step_ds) {
++	case SZ_512:
++		geo->gf_len = 13;
++		break;
++	case SZ_1K:
++		geo->gf_len = 14;
++		break;
++	default:
++		dev_err(this->dev,
++			"unsupported nand chip. ecc bits : %d, ecc size : %d\n",
++			chip->ecc_strength_ds, chip->ecc_step_ds);
++		return -EINVAL;
++	}
++	geo->ecc_chunk_size = chip->ecc_step_ds;
++	geo->ecc_strength = round_up(chip->ecc_strength_ds, 2);
++	if (!gpmi_check_ecc(this))
++		return -EINVAL;
++
++	/* Keep the C >= O */
++	if (geo->ecc_chunk_size < mtd->oobsize) {
++		dev_err(this->dev,
++			"unsupported nand chip. ecc size: %d, oob size : %d\n",
++			chip->ecc_step_ds, mtd->oobsize);
++		return -EINVAL;
++	}
++
++	/* The default value, see comment in the legacy_set_geometry(). */
++	geo->metadata_size = 10;
++
++	geo->ecc_chunk_count = mtd->writesize / geo->ecc_chunk_size;
++
++	/*
++	 * Now, the NAND chip with 2K page(data chunk is 512byte) shows below:
++	 *
++	 *    |                          P                            |
++	 *    |<----------------------------------------------------->|
++	 *    |                                                       |
++	 *    |                                        (Block Mark)   |
++	 *    |                      P'                      |      | |     |
++	 *    |<-------------------------------------------->|  D   | |  O' |
++	 *    |                                              |<---->| |<--->|
++	 *    V                                              V      V V     V
++	 *    +---+----------+-+----------+-+----------+-+----------+-+-----+
++	 *    | M |   data   |E|   data   |E|   data   |E|   data   |E|     |
++	 *    +---+----------+-+----------+-+----------+-+----------+-+-----+
++	 *                                                   ^              ^
++	 *                                                   |      O       |
++	 *                                                   |<------------>|
++	 *                                                   |              |
++	 *
++	 *	P : the page size for BCH module.
++	 *	E : The ECC strength.
++	 *	G : the length of Galois Field.
++	 *	N : The chunk count of per page.
++	 *	M : the metasize of per page.
++	 *	C : the ecc chunk size, aka the "data" above.
++	 *	P': the nand chip's page size.
++	 *	O : the nand chip's oob size.
++	 *	O': the free oob.
++	 *
++	 *	The formula for P is :
++	 *
++	 *	            E * G * N
++	 *	       P = ------------ + P' + M
++	 *                      8
++	 *
++	 * The position of block mark moves forward in the ECC-based view
++	 * of page, and the delta is:
++	 *
++	 *                   E * G * (N - 1)
++	 *             D = (---------------- + M)
++	 *                          8
++	 *
++	 * Please see the comment in legacy_set_geometry().
++	 * With the condition C >= O , we still can get same result.
++	 * So the bit position of the physical block mark within the ECC-based
++	 * view of the page is :
++	 *             (P' - D) * 8
++	 */
++	geo->page_size = mtd->writesize + geo->metadata_size +
++		(geo->gf_len * geo->ecc_strength * geo->ecc_chunk_count) / 8;
++
++	geo->payload_size = mtd->writesize;
++
++	geo->auxiliary_status_offset = ALIGN(geo->metadata_size, 4);
++	geo->auxiliary_size = ALIGN(geo->metadata_size, 4)
++				+ ALIGN(geo->ecc_chunk_count, 4);
++
++	if (!this->swap_block_mark)
++		return 0;
++
++	/* For bit swap. */
++	block_mark_bit_offset = mtd->writesize * 8 -
++		(geo->ecc_strength * geo->gf_len * (geo->ecc_chunk_count - 1)
++				+ geo->metadata_size * 8);
++
++	geo->block_mark_byte_offset = block_mark_bit_offset / 8;
++	geo->block_mark_bit_offset  = block_mark_bit_offset % 8;
++	return 0;
++}
++
++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);
++	unsigned int metadata_size;
++	unsigned int status_size;
++	unsigned int block_mark_bit_offset;
++
++	/*
++	 * The size of the metadata can be changed, though we set it to 10
++	 * bytes now. But it can't be too large, because we have to save
++	 * enough space for BCH.
++	 */
++	geo->metadata_size = 10;
++
++	/* The default for the length of Galois Field. */
++	geo->gf_len = 13;
++
++	/* The default for chunk size. */
++	geo->ecc_chunk_size = 512;
++	while (geo->ecc_chunk_size < mtd->oobsize) {
++		geo->ecc_chunk_size *= 2; /* keep C >= O */
++		geo->gf_len = 14;
++	}
++
++	geo->ecc_chunk_count = mtd->writesize / geo->ecc_chunk_size;
++
++	/* We use the same ECC strength for all chunks. */
++	geo->ecc_strength = get_ecc_strength(this);
++	if (!gpmi_check_ecc(this)) {
++		dev_err(this->dev,
++			"ecc strength: %d cannot be supported by the controller (%d)\n"
++			"try to use minimum ecc strength that NAND chip required\n",
++			geo->ecc_strength,
++			this->devdata->bch_max_ecc_strength);
++		return -EINVAL;
++	}
++
++	geo->page_size = mtd->writesize + geo->metadata_size +
++		(geo->gf_len * geo->ecc_strength * geo->ecc_chunk_count) / 8;
++	geo->payload_size = mtd->writesize;
++
++	/*
++	 * The auxiliary buffer contains the metadata and the ECC status. The
++	 * metadata is padded to the nearest 32-bit boundary. The ECC status
++	 * contains one byte for every ECC chunk, and is also padded to the
++	 * nearest 32-bit boundary.
++	 */
++	metadata_size = ALIGN(geo->metadata_size, 4);
++	status_size   = ALIGN(geo->ecc_chunk_count, 4);
++
++	geo->auxiliary_size = metadata_size + status_size;
++	geo->auxiliary_status_offset = metadata_size;
++
++	if (!this->swap_block_mark)
++		return 0;
++
++	/*
++	 * We need to compute the byte and bit offsets of
++	 * the physical block mark within the ECC-based view of the page.
++	 *
++	 * NAND chip with 2K page shows below:
++	 *                                             (Block Mark)
++	 *                                                   |      |
++	 *                                                   |  D   |
++	 *                                                   |<---->|
++	 *                                                   V      V
++	 *    +---+----------+-+----------+-+----------+-+----------+-+
++	 *    | M |   data   |E|   data   |E|   data   |E|   data   |E|
++	 *    +---+----------+-+----------+-+----------+-+----------+-+
++	 *
++	 * The position of block mark moves forward in the ECC-based view
++	 * of page, and the delta is:
++	 *
++	 *                   E * G * (N - 1)
++	 *             D = (---------------- + M)
++	 *                          8
++	 *
++	 * With the formula to compute the ECC strength, and the condition
++	 *       : C >= O         (C is the ecc chunk size)
++	 *
++	 * It's easy to deduce to the following result:
++	 *
++	 *         E * G       (O - M)      C - M         C - M
++	 *      ----------- <= ------- <=  --------  <  ---------
++	 *           8            N           N          (N - 1)
++	 *
++	 *  So, we get:
++	 *
++	 *                   E * G * (N - 1)
++	 *             D = (---------------- + M) < C
++	 *                          8
++	 *
++	 *  The above inequality means the position of block mark
++	 *  within the ECC-based view of the page is still in the data chunk,
++	 *  and it's NOT in the ECC bits of the chunk.
++	 *
++	 *  Use the following to compute the bit position of the
++	 *  physical block mark within the ECC-based view of the page:
++	 *          (page_size - D) * 8
++	 *
++	 *  --Huang Shijie
++	 */
++	block_mark_bit_offset = mtd->writesize * 8 -
++		(geo->ecc_strength * geo->gf_len * (geo->ecc_chunk_count - 1)
++				+ geo->metadata_size * 8);
++
++	geo->block_mark_byte_offset = block_mark_bit_offset / 8;
++	geo->block_mark_bit_offset  = block_mark_bit_offset % 8;
++	return 0;
++}
++
++int common_nfc_set_geometry(struct gpmi_nand_data *this)
++{
++	if ((of_property_read_bool(this->dev->of_node, "fsl,use-minimum-ecc"))
++				|| legacy_set_geometry(this))
++		return set_geometry_by_ecc_info(this);
++
++	return 0;
++}
++
++struct dma_chan *get_dma_chan(struct gpmi_nand_data *this)
++{
++	/* We use the DMA channel 0 to access all the nand chips. */
++	return this->dma_chans[0];
++}
++
++/* Can we use the upper's buffer directly for DMA? */
++void prepare_data_dma(struct gpmi_nand_data *this, enum dma_data_direction dr)
++{
++	struct scatterlist *sgl = &this->data_sgl;
++	int ret;
++
++	/* first try to map the upper buffer directly */
++	if (virt_addr_valid(this->upper_buf) &&
++		!object_is_on_stack(this->upper_buf)) {
++		sg_init_one(sgl, this->upper_buf, this->upper_len);
++		ret = dma_map_sg(this->dev, sgl, 1, dr);
++		if (ret == 0)
++			goto map_fail;
++
++		this->direct_dma_map_ok = true;
++		return;
++	}
++
++map_fail:
++	/* We have to use our own DMA buffer. */
++	sg_init_one(sgl, this->data_buffer_dma, this->upper_len);
++
++	if (dr == DMA_TO_DEVICE)
++		memcpy(this->data_buffer_dma, this->upper_buf, this->upper_len);
++
++	dma_map_sg(this->dev, sgl, 1, dr);
++
++	this->direct_dma_map_ok = false;
++}
++
++/* This will be called after the DMA operation is finished. */
++static void dma_irq_callback(void *param)
++{
++	struct gpmi_nand_data *this = param;
++	struct completion *dma_c = &this->dma_done;
++
++	switch (this->dma_type) {
++	case DMA_FOR_COMMAND:
++		dma_unmap_sg(this->dev, &this->cmd_sgl, 1, DMA_TO_DEVICE);
++		break;
++
++	case DMA_FOR_READ_DATA:
++		dma_unmap_sg(this->dev, &this->data_sgl, 1, DMA_FROM_DEVICE);
++		if (this->direct_dma_map_ok == false)
++			memcpy(this->upper_buf, this->data_buffer_dma,
++				this->upper_len);
++		break;
++
++	case DMA_FOR_WRITE_DATA:
++		dma_unmap_sg(this->dev, &this->data_sgl, 1, DMA_TO_DEVICE);
++		break;
++
++	case DMA_FOR_READ_ECC_PAGE:
++	case DMA_FOR_WRITE_ECC_PAGE:
++		/* We have to wait the BCH interrupt to finish. */
++		break;
++
++	default:
++		dev_err(this->dev, "in wrong DMA operation.\n");
++	}
++
++	complete(dma_c);
++}
++
++int start_dma_without_bch_irq(struct gpmi_nand_data *this,
++				struct dma_async_tx_descriptor *desc)
++{
++	struct completion *dma_c = &this->dma_done;
++	unsigned long timeout;
++
++	init_completion(dma_c);
++
++	desc->callback		= dma_irq_callback;
++	desc->callback_param	= this;
++	dmaengine_submit(desc);
++	dma_async_issue_pending(get_dma_chan(this));
++
++	/* Wait for the interrupt from the DMA block. */
++	timeout = wait_for_completion_timeout(dma_c, msecs_to_jiffies(1000));
++	if (!timeout) {
++		dev_err(this->dev, "DMA timeout, last DMA :%d\n",
++			this->last_dma_type);
++		gpmi_dump_info(this);
++		return -ETIMEDOUT;
++	}
++	return 0;
++}
++
++/*
++ * This function is used in BCH reading or BCH writing pages.
++ * It will wait for the BCH interrupt as long as ONE second.
++ * Actually, we must wait for two interrupts :
++ *	[1] firstly the DMA interrupt and
++ *	[2] secondly the BCH interrupt.
++ */
++int start_dma_with_bch_irq(struct gpmi_nand_data *this,
++			struct dma_async_tx_descriptor *desc)
++{
++	struct completion *bch_c = &this->bch_done;
++	unsigned long timeout;
++
++	/* Prepare to receive an interrupt from the BCH block. */
++	init_completion(bch_c);
++
++	/* start the DMA */
++	start_dma_without_bch_irq(this, desc);
++
++	/* Wait for the interrupt from the BCH block. */
++	timeout = wait_for_completion_timeout(bch_c, msecs_to_jiffies(1000));
++	if (!timeout) {
++		dev_err(this->dev, "BCH timeout, last DMA :%d\n",
++			this->last_dma_type);
++		gpmi_dump_info(this);
++		return -ETIMEDOUT;
++	}
++	return 0;
++}
++
++static int acquire_register_block(struct gpmi_nand_data *this,
++				  const char *res_name)
++{
++	struct platform_device *pdev = this->pdev;
++	struct resources *res = &this->resources;
++	struct resource *r;
++	void __iomem *p;
++
++	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, res_name);
++	p = devm_ioremap_resource(&pdev->dev, r);
++	if (IS_ERR(p))
++		return PTR_ERR(p);
++
++	if (!strcmp(res_name, GPMI_NAND_GPMI_REGS_ADDR_RES_NAME))
++		res->gpmi_regs = p;
++	else if (!strcmp(res_name, GPMI_NAND_BCH_REGS_ADDR_RES_NAME))
++		res->bch_regs = p;
++	else
++		dev_err(this->dev, "unknown resource name : %s\n", res_name);
++
++	return 0;
++}
++
++static int acquire_bch_irq(struct gpmi_nand_data *this, irq_handler_t irq_h)
++{
++	struct platform_device *pdev = this->pdev;
++	const char *res_name = GPMI_NAND_BCH_INTERRUPT_RES_NAME;
++	struct resource *r;
++	int err;
++
++	r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, res_name);
++	if (!r) {
++		dev_err(this->dev, "Can't get resource for %s\n", res_name);
++		return -ENODEV;
++	}
++
++	err = devm_request_irq(this->dev, r->start, irq_h, 0, res_name, this);
++	if (err)
++		dev_err(this->dev, "error requesting BCH IRQ\n");
++
++	return err;
++}
++
++static void release_dma_channels(struct gpmi_nand_data *this)
++{
++	unsigned int i;
++	for (i = 0; i < DMA_CHANS; i++)
++		if (this->dma_chans[i]) {
++			dma_release_channel(this->dma_chans[i]);
++			this->dma_chans[i] = NULL;
++		}
++}
++
++static int acquire_dma_channels(struct gpmi_nand_data *this)
++{
++	struct platform_device *pdev = this->pdev;
++	struct dma_chan *dma_chan;
++
++	/* request dma channel */
++	dma_chan = dma_request_slave_channel(&pdev->dev, "rx-tx");
++	if (!dma_chan) {
++		dev_err(this->dev, "Failed to request DMA channel.\n");
++		goto acquire_err;
++	}
++
++	this->dma_chans[0] = dma_chan;
++	return 0;
++
++acquire_err:
++	release_dma_channels(this);
++	return -EINVAL;
++}
++
++static int gpmi_get_clks(struct gpmi_nand_data *this)
++{
++	struct resources *r = &this->resources;
++	struct clk *clk;
++	int err, i;
++
++	for (i = 0; i < this->devdata->clks_count; i++) {
++		clk = devm_clk_get(this->dev, this->devdata->clks[i]);
++		if (IS_ERR(clk)) {
++			err = PTR_ERR(clk);
++			goto err_clock;
++		}
++
++		r->clock[i] = clk;
++	}
++
++	if (GPMI_IS_MX6(this))
++		/*
++		 * Set the default value for the gpmi clock.
++		 *
++		 * If you want to use the ONFI nand which is in the
++		 * Synchronous Mode, you should change the clock as you need.
++		 */
++		clk_set_rate(r->clock[0], 22000000);
++
++	return 0;
++
++err_clock:
++	dev_dbg(this->dev, "failed in finding the clocks.\n");
++	return err;
++}
++
++static int acquire_resources(struct gpmi_nand_data *this)
++{
++	int ret;
++
++	ret = acquire_register_block(this, GPMI_NAND_GPMI_REGS_ADDR_RES_NAME);
++	if (ret)
++		goto exit_regs;
++
++	ret = acquire_register_block(this, GPMI_NAND_BCH_REGS_ADDR_RES_NAME);
++	if (ret)
++		goto exit_regs;
++
++	ret = acquire_bch_irq(this, bch_irq);
++	if (ret)
++		goto exit_regs;
++
++	ret = acquire_dma_channels(this);
++	if (ret)
++		goto exit_regs;
++
++	ret = gpmi_get_clks(this);
++	if (ret)
++		goto exit_clock;
++	return 0;
++
++exit_clock:
++	release_dma_channels(this);
++exit_regs:
++	return ret;
++}
++
++static void release_resources(struct gpmi_nand_data *this)
++{
++	release_dma_channels(this);
++}
++
++static int init_hardware(struct gpmi_nand_data *this)
++{
++	int ret;
++
++	/*
++	 * This structure contains the "safe" GPMI timing that should succeed
++	 * with any NAND Flash device
++	 * (although, with less-than-optimal performance).
++	 */
++	struct nand_timing  safe_timing = {
++		.data_setup_in_ns        = 80,
++		.data_hold_in_ns         = 60,
++		.address_setup_in_ns     = 25,
++		.gpmi_sample_delay_in_ns =  6,
++		.tREA_in_ns              = -1,
++		.tRLOH_in_ns             = -1,
++		.tRHOH_in_ns             = -1,
++	};
++
++	/* Initialize the hardwares. */
++	ret = gpmi_init(this);
++	if (ret)
++		return ret;
++
++	this->timing = safe_timing;
++	return 0;
++}
++
++static int read_page_prepare(struct gpmi_nand_data *this,
++			void *destination, unsigned length,
++			void *alt_virt, dma_addr_t alt_phys, unsigned alt_size,
++			void **use_virt, dma_addr_t *use_phys)
++{
++	struct device *dev = this->dev;
++
++	if (virt_addr_valid(destination)) {
++		dma_addr_t dest_phys;
++
++		dest_phys = dma_map_single(dev, destination,
++						length, DMA_FROM_DEVICE);
++		if (dma_mapping_error(dev, dest_phys)) {
++			if (alt_size < length) {
++				dev_err(dev, "Alternate buffer is too small\n");
++				return -ENOMEM;
++			}
++			goto map_failed;
++		}
++		*use_virt = destination;
++		*use_phys = dest_phys;
++		this->direct_dma_map_ok = true;
++		return 0;
++	}
++
++map_failed:
++	*use_virt = alt_virt;
++	*use_phys = alt_phys;
++	this->direct_dma_map_ok = false;
++	return 0;
++}
++
++static inline void read_page_end(struct gpmi_nand_data *this,
++			void *destination, unsigned length,
++			void *alt_virt, dma_addr_t alt_phys, unsigned alt_size,
++			void *used_virt, dma_addr_t used_phys)
++{
++	if (this->direct_dma_map_ok)
++		dma_unmap_single(this->dev, used_phys, length, DMA_FROM_DEVICE);
++}
++
++static inline void read_page_swap_end(struct gpmi_nand_data *this,
++			void *destination, unsigned length,
++			void *alt_virt, dma_addr_t alt_phys, unsigned alt_size,
++			void *used_virt, dma_addr_t used_phys)
++{
++	if (!this->direct_dma_map_ok)
++		memcpy(destination, alt_virt, length);
++}
++
++static int send_page_prepare(struct gpmi_nand_data *this,
++			const void *source, unsigned length,
++			void *alt_virt, dma_addr_t alt_phys, unsigned alt_size,
++			const void **use_virt, dma_addr_t *use_phys)
++{
++	struct device *dev = this->dev;
++
++	if (virt_addr_valid(source)) {
++		dma_addr_t source_phys;
++
++		source_phys = dma_map_single(dev, (void *)source, length,
++						DMA_TO_DEVICE);
++		if (dma_mapping_error(dev, source_phys)) {
++			if (alt_size < length) {
++				dev_err(dev, "Alternate buffer is too small\n");
++				return -ENOMEM;
++			}
++			goto map_failed;
++		}
++		*use_virt = source;
++		*use_phys = source_phys;
++		return 0;
++	}
++map_failed:
++	/*
++	 * Copy the content of the source buffer into the alternate
++	 * buffer and set up the return values accordingly.
++	 */
++	memcpy(alt_virt, source, length);
++
++	*use_virt = alt_virt;
++	*use_phys = alt_phys;
++	return 0;
++}
++
++static void send_page_end(struct gpmi_nand_data *this,
++			const void *source, unsigned length,
++			void *alt_virt, dma_addr_t alt_phys, unsigned alt_size,
++			const void *used_virt, dma_addr_t used_phys)
++{
++	struct device *dev = this->dev;
++	if (used_virt == source)
++		dma_unmap_single(dev, used_phys, length, DMA_TO_DEVICE);
++}
++
++static void gpmi_free_dma_buffer(struct gpmi_nand_data *this)
++{
++	struct device *dev = this->dev;
++
++	if (this->page_buffer_virt && virt_addr_valid(this->page_buffer_virt))
++		dma_free_coherent(dev, this->page_buffer_size,
++					this->page_buffer_virt,
++					this->page_buffer_phys);
++	kfree(this->cmd_buffer);
++	kfree(this->data_buffer_dma);
++	kfree(this->raw_buffer);
++
++	this->cmd_buffer	= NULL;
++	this->data_buffer_dma	= NULL;
++	this->raw_buffer	= NULL;
++	this->page_buffer_virt	= NULL;
++	this->page_buffer_size	=  0;
++}
++
++/* Allocate the DMA buffers */
++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);
++
++	/* [1] Allocate a command buffer. PAGE_SIZE is enough. */
++	this->cmd_buffer = kzalloc(PAGE_SIZE, GFP_DMA | GFP_KERNEL);
++	if (this->cmd_buffer == NULL)
++		goto error_alloc;
++
++	/*
++	 * [2] Allocate a read/write data buffer.
++	 *     The gpmi_alloc_dma_buffer can be called twice.
++	 *     We allocate a PAGE_SIZE length buffer if gpmi_alloc_dma_buffer
++	 *     is called before the nand_scan_ident; and we allocate a buffer
++	 *     of the real NAND page size when the gpmi_alloc_dma_buffer is
++	 *     called after the nand_scan_ident.
++	 */
++	this->data_buffer_dma = kzalloc(mtd->writesize ?: PAGE_SIZE,
++					GFP_DMA | GFP_KERNEL);
++	if (this->data_buffer_dma == NULL)
++		goto error_alloc;
++
++	/*
++	 * [3] Allocate the page buffer.
++	 *
++	 * Both the payload buffer and the auxiliary buffer must appear on
++	 * 32-bit boundaries. We presume the size of the payload buffer is a
++	 * power of two and is much larger than four, which guarantees the
++	 * auxiliary buffer will appear on a 32-bit boundary.
++	 */
++	this->page_buffer_size = geo->payload_size + geo->auxiliary_size;
++	this->page_buffer_virt = dma_alloc_coherent(dev, this->page_buffer_size,
++					&this->page_buffer_phys, GFP_DMA);
++	if (!this->page_buffer_virt)
++		goto error_alloc;
++
++	this->raw_buffer = kzalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL);
++	if (!this->raw_buffer)
++		goto error_alloc;
++
++	/* Slice up the page buffer. */
++	this->payload_virt = this->page_buffer_virt;
++	this->payload_phys = this->page_buffer_phys;
++	this->auxiliary_virt = this->payload_virt + geo->payload_size;
++	this->auxiliary_phys = this->payload_phys + geo->payload_size;
++	return 0;
++
++error_alloc:
++	gpmi_free_dma_buffer(this);
++	return -ENOMEM;
++}
++
++static void gpmi_cmd_ctrl(struct mtd_info *mtd, int data, unsigned int ctrl)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct gpmi_nand_data *this = nand_get_controller_data(chip);
++	int ret;
++
++	/*
++	 * Every operation begins with a command byte and a series of zero or
++	 * more address bytes. These are distinguished by either the Address
++	 * Latch Enable (ALE) or Command Latch Enable (CLE) signals being
++	 * asserted. When MTD is ready to execute the command, it will deassert
++	 * both latch enables.
++	 *
++	 * Rather than run a separate DMA operation for every single byte, we
++	 * queue them up and run a single DMA operation for the entire series
++	 * of command and data bytes. NAND_CMD_NONE means the END of the queue.
++	 */
++	if ((ctrl & (NAND_ALE | NAND_CLE))) {
++		if (data != NAND_CMD_NONE)
++			this->cmd_buffer[this->command_length++] = data;
++		return;
++	}
++
++	if (!this->command_length)
++		return;
++
++	ret = gpmi_send_command(this);
++	if (ret)
++		dev_err(this->dev, "Chip: %u, Error %d\n",
++			this->current_chip, ret);
++
++	this->command_length = 0;
++}
++
++static int gpmi_dev_ready(struct mtd_info *mtd)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct gpmi_nand_data *this = nand_get_controller_data(chip);
++
++	return gpmi_is_ready(this, this->current_chip);
++}
++
++static void gpmi_select_chip(struct mtd_info *mtd, int chipnr)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct gpmi_nand_data *this = nand_get_controller_data(chip);
++
++	if ((this->current_chip < 0) && (chipnr >= 0))
++		gpmi_begin(this);
++	else if ((this->current_chip >= 0) && (chipnr < 0))
++		gpmi_end(this);
++
++	this->current_chip = chipnr;
++}
++
++static void gpmi_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct gpmi_nand_data *this = nand_get_controller_data(chip);
++
++	dev_dbg(this->dev, "len is %d\n", len);
++	this->upper_buf	= buf;
++	this->upper_len	= len;
++
++	gpmi_read_data(this);
++}
++
++static void gpmi_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct gpmi_nand_data *this = nand_get_controller_data(chip);
++
++	dev_dbg(this->dev, "len is %d\n", len);
++	this->upper_buf	= (uint8_t *)buf;
++	this->upper_len	= len;
++
++	gpmi_send_data(this);
++}
++
++static uint8_t gpmi_read_byte(struct mtd_info *mtd)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct gpmi_nand_data *this = nand_get_controller_data(chip);
++	uint8_t *buf = this->data_buffer_dma;
++
++	gpmi_read_buf(mtd, buf, 1);
++	return buf[0];
++}
++
++/*
++ * Handles block mark swapping.
++ * It can be called in swapping the block mark, or swapping it back,
++ * because the the operations are the same.
++ */
++static void block_mark_swapping(struct gpmi_nand_data *this,
++				void *payload, void *auxiliary)
++{
++	struct bch_geometry *nfc_geo = &this->bch_geometry;
++	unsigned char *p;
++	unsigned char *a;
++	unsigned int  bit;
++	unsigned char mask;
++	unsigned char from_data;
++	unsigned char from_oob;
++
++	if (!this->swap_block_mark)
++		return;
++
++	/*
++	 * If control arrives here, we're swapping. Make some convenience
++	 * variables.
++	 */
++	bit = nfc_geo->block_mark_bit_offset;
++	p   = payload + nfc_geo->block_mark_byte_offset;
++	a   = auxiliary;
++
++	/*
++	 * Get the byte from the data area that overlays the block mark. Since
++	 * the ECC engine applies its own view to the bits in the page, the
++	 * physical block mark won't (in general) appear on a byte boundary in
++	 * the data.
++	 */
++	from_data = (p[0] >> bit) | (p[1] << (8 - bit));
++
++	/* Get the byte from the OOB. */
++	from_oob = a[0];
++
++	/* Swap them. */
++	a[0] = from_data;
++
++	mask = (0x1 << bit) - 1;
++	p[0] = (p[0] & mask) | (from_oob << bit);
++
++	mask = ~0 << bit;
++	p[1] = (p[1] & mask) | (from_oob >> (8 - bit));
++}
++
++static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
++				uint8_t *buf, int oob_required, int page)
++{
++	struct gpmi_nand_data *this = nand_get_controller_data(chip);
++	struct bch_geometry *nfc_geo = &this->bch_geometry;
++	void          *payload_virt;
++	dma_addr_t    payload_phys;
++	void          *auxiliary_virt;
++	dma_addr_t    auxiliary_phys;
++	unsigned int  i;
++	unsigned char *status;
++	unsigned int  max_bitflips = 0;
++	int           ret;
++
++	dev_dbg(this->dev, "page number is : %d\n", page);
++	ret = read_page_prepare(this, buf, nfc_geo->payload_size,
++					this->payload_virt, this->payload_phys,
++					nfc_geo->payload_size,
++					&payload_virt, &payload_phys);
++	if (ret) {
++		dev_err(this->dev, "Inadequate DMA buffer\n");
++		ret = -ENOMEM;
++		return ret;
++	}
++	auxiliary_virt = this->auxiliary_virt;
++	auxiliary_phys = this->auxiliary_phys;
++
++	/* go! */
++	ret = gpmi_read_page(this, payload_phys, auxiliary_phys);
++	read_page_end(this, buf, nfc_geo->payload_size,
++			this->payload_virt, this->payload_phys,
++			nfc_geo->payload_size,
++			payload_virt, payload_phys);
++	if (ret) {
++		dev_err(this->dev, "Error in ECC-based read: %d\n", ret);
++		return ret;
++	}
++
++	/* handle the block mark swapping */
++	block_mark_swapping(this, payload_virt, auxiliary_virt);
++
++	/* Loop over status bytes, accumulating ECC status. */
++	status = auxiliary_virt + nfc_geo->auxiliary_status_offset;
++
++	read_page_swap_end(this, buf, nfc_geo->payload_size,
++			   this->payload_virt, this->payload_phys,
++			   nfc_geo->payload_size,
++			   payload_virt, payload_phys);
++
++	for (i = 0; i < nfc_geo->ecc_chunk_count; i++, status++) {
++		if ((*status == STATUS_GOOD) || (*status == STATUS_ERASED))
++			continue;
++
++		if (*status == STATUS_UNCORRECTABLE) {
++			int eccbits = nfc_geo->ecc_strength * nfc_geo->gf_len;
++			u8 *eccbuf = this->raw_buffer;
++			int offset, bitoffset;
++			int eccbytes;
++			int flips;
++
++			/* Read ECC bytes into our internal raw_buffer */
++			offset = nfc_geo->metadata_size * 8;
++			offset += ((8 * nfc_geo->ecc_chunk_size) + eccbits) * (i + 1);
++			offset -= eccbits;
++			bitoffset = offset % 8;
++			eccbytes = DIV_ROUND_UP(offset + eccbits, 8);
++			offset /= 8;
++			eccbytes -= offset;
++			chip->cmdfunc(mtd, NAND_CMD_RNDOUT, offset, -1);
++			chip->read_buf(mtd, eccbuf, eccbytes);
++
++			/*
++			 * ECC data are not byte aligned and we may have
++			 * in-band data in the first and last byte of
++			 * eccbuf. Set non-eccbits to one so that
++			 * nand_check_erased_ecc_chunk() does not count them
++			 * as bitflips.
++			 */
++			if (bitoffset)
++				eccbuf[0] |= GENMASK(bitoffset - 1, 0);
++
++			bitoffset = (bitoffset + eccbits) % 8;
++			if (bitoffset)
++				eccbuf[eccbytes - 1] |= GENMASK(7, bitoffset);
++
++			/*
++			 * The ECC hardware has an uncorrectable ECC status
++			 * code in case we have bitflips in an erased page. As
++			 * nothing was written into this subpage the ECC is
++			 * obviously wrong and we can not trust it. We assume
++			 * at this point that we are reading an erased page and
++			 * try to correct the bitflips in buffer up to
++			 * ecc_strength bitflips. If this is a page with random
++			 * data, we exceed this number of bitflips and have a
++			 * ECC failure. Otherwise we use the corrected buffer.
++			 */
++			if (i == 0) {
++				/* The first block includes metadata */
++				flips = nand_check_erased_ecc_chunk(
++						buf + i * nfc_geo->ecc_chunk_size,
++						nfc_geo->ecc_chunk_size,
++						eccbuf, eccbytes,
++						auxiliary_virt,
++						nfc_geo->metadata_size,
++						nfc_geo->ecc_strength);
++			} else {
++				flips = nand_check_erased_ecc_chunk(
++						buf + i * nfc_geo->ecc_chunk_size,
++						nfc_geo->ecc_chunk_size,
++						eccbuf, eccbytes,
++						NULL, 0,
++						nfc_geo->ecc_strength);
++			}
++
++			if (flips > 0) {
++				max_bitflips = max_t(unsigned int, max_bitflips,
++						     flips);
++				mtd->ecc_stats.corrected += flips;
++				continue;
++			}
++
++			mtd->ecc_stats.failed++;
++			continue;
++		}
++
++		mtd->ecc_stats.corrected += *status;
++		max_bitflips = max_t(unsigned int, max_bitflips, *status);
++	}
++
++	if (oob_required) {
++		/*
++		 * It's time to deliver the OOB bytes. See gpmi_ecc_read_oob()
++		 * for details about our policy for delivering the OOB.
++		 *
++		 * We fill the caller's buffer with set bits, and then copy the
++		 * block mark to th caller's buffer. Note that, if block mark
++		 * swapping was necessary, it has already been done, so we can
++		 * rely on the first byte of the auxiliary buffer to contain
++		 * the block mark.
++		 */
++		memset(chip->oob_poi, ~0, mtd->oobsize);
++		chip->oob_poi[0] = ((uint8_t *) auxiliary_virt)[0];
++	}
++
++	return max_bitflips;
++}
++
++/* Fake a virtual small page for the subpage read */
++static int gpmi_ecc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
++			uint32_t offs, uint32_t len, uint8_t *buf, int page)
++{
++	struct gpmi_nand_data *this = nand_get_controller_data(chip);
++	void __iomem *bch_regs = this->resources.bch_regs;
++	struct bch_geometry old_geo = this->bch_geometry;
++	struct bch_geometry *geo = &this->bch_geometry;
++	int size = chip->ecc.size; /* ECC chunk size */
++	int meta, n, page_size;
++	u32 r1_old, r2_old, r1_new, r2_new;
++	unsigned int max_bitflips;
++	int first, last, marker_pos;
++	int ecc_parity_size;
++	int col = 0;
++	int old_swap_block_mark = this->swap_block_mark;
++
++	/* The size of ECC parity */
++	ecc_parity_size = geo->gf_len * geo->ecc_strength / 8;
++
++	/* Align it with the chunk size */
++	first = offs / size;
++	last = (offs + len - 1) / size;
++
++	if (this->swap_block_mark) {
++		/*
++		 * Find the chunk which contains the Block Marker.
++		 * If this chunk is in the range of [first, last],
++		 * we have to read out the whole page.
++		 * Why? since we had swapped the data at the position of Block
++		 * Marker to the metadata which is bound with the chunk 0.
++		 */
++		marker_pos = geo->block_mark_byte_offset / size;
++		if (last >= marker_pos && first <= marker_pos) {
++			dev_dbg(this->dev,
++				"page:%d, first:%d, last:%d, marker at:%d\n",
++				page, first, last, marker_pos);
++			return gpmi_ecc_read_page(mtd, chip, buf, 0, page);
++		}
++	}
++
++	meta = geo->metadata_size;
++	if (first) {
++		col = meta + (size + ecc_parity_size) * first;
++		chip->cmdfunc(mtd, NAND_CMD_RNDOUT, col, -1);
++
++		meta = 0;
++		buf = buf + first * size;
++	}
++
++	/* Save the old environment */
++	r1_old = r1_new = readl(bch_regs + HW_BCH_FLASH0LAYOUT0);
++	r2_old = r2_new = readl(bch_regs + HW_BCH_FLASH0LAYOUT1);
++
++	/* change the BCH registers and bch_geometry{} */
++	n = last - first + 1;
++	page_size = meta + (size + ecc_parity_size) * n;
++
++	r1_new &= ~(BM_BCH_FLASH0LAYOUT0_NBLOCKS |
++			BM_BCH_FLASH0LAYOUT0_META_SIZE);
++	r1_new |= BF_BCH_FLASH0LAYOUT0_NBLOCKS(n - 1)
++			| BF_BCH_FLASH0LAYOUT0_META_SIZE(meta);
++	writel(r1_new, bch_regs + HW_BCH_FLASH0LAYOUT0);
++
++	r2_new &= ~BM_BCH_FLASH0LAYOUT1_PAGE_SIZE;
++	r2_new |= BF_BCH_FLASH0LAYOUT1_PAGE_SIZE(page_size);
++	writel(r2_new, bch_regs + HW_BCH_FLASH0LAYOUT1);
++
++	geo->ecc_chunk_count = n;
++	geo->payload_size = n * size;
++	geo->page_size = page_size;
++	geo->auxiliary_status_offset = ALIGN(meta, 4);
++
++	dev_dbg(this->dev, "page:%d(%d:%d)%d, chunk:(%d:%d), BCH PG size:%d\n",
++		page, offs, len, col, first, n, page_size);
++
++	/* Read the subpage now */
++	this->swap_block_mark = false;
++	max_bitflips = gpmi_ecc_read_page(mtd, chip, buf, 0, page);
++
++	/* Restore */
++	writel(r1_old, bch_regs + HW_BCH_FLASH0LAYOUT0);
++	writel(r2_old, bch_regs + HW_BCH_FLASH0LAYOUT1);
++	this->bch_geometry = old_geo;
++	this->swap_block_mark = old_swap_block_mark;
++
++	return max_bitflips;
++}
++
++static int gpmi_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
++				const uint8_t *buf, int oob_required, int page)
++{
++	struct gpmi_nand_data *this = nand_get_controller_data(chip);
++	struct bch_geometry *nfc_geo = &this->bch_geometry;
++	const void *payload_virt;
++	dma_addr_t payload_phys;
++	const void *auxiliary_virt;
++	dma_addr_t auxiliary_phys;
++	int        ret;
++
++	dev_dbg(this->dev, "ecc write page.\n");
++	if (this->swap_block_mark) {
++		/*
++		 * If control arrives here, we're doing block mark swapping.
++		 * Since we can't modify the caller's buffers, we must copy them
++		 * into our own.
++		 */
++		memcpy(this->payload_virt, buf, mtd->writesize);
++		payload_virt = this->payload_virt;
++		payload_phys = this->payload_phys;
++
++		memcpy(this->auxiliary_virt, chip->oob_poi,
++				nfc_geo->auxiliary_size);
++		auxiliary_virt = this->auxiliary_virt;
++		auxiliary_phys = this->auxiliary_phys;
++
++		/* Handle block mark swapping. */
++		block_mark_swapping(this,
++				(void *)payload_virt, (void *)auxiliary_virt);
++	} else {
++		/*
++		 * If control arrives here, we're not doing block mark swapping,
++		 * so we can to try and use the caller's buffers.
++		 */
++		ret = send_page_prepare(this,
++				buf, mtd->writesize,
++				this->payload_virt, this->payload_phys,
++				nfc_geo->payload_size,
++				&payload_virt, &payload_phys);
++		if (ret) {
++			dev_err(this->dev, "Inadequate payload DMA buffer\n");
++			return 0;
++		}
++
++		ret = send_page_prepare(this,
++				chip->oob_poi, mtd->oobsize,
++				this->auxiliary_virt, this->auxiliary_phys,
++				nfc_geo->auxiliary_size,
++				&auxiliary_virt, &auxiliary_phys);
++		if (ret) {
++			dev_err(this->dev, "Inadequate auxiliary DMA buffer\n");
++			goto exit_auxiliary;
++		}
++	}
++
++	/* Ask the NFC. */
++	ret = gpmi_send_page(this, payload_phys, auxiliary_phys);
++	if (ret)
++		dev_err(this->dev, "Error in ECC-based write: %d\n", ret);
++
++	if (!this->swap_block_mark) {
++		send_page_end(this, chip->oob_poi, mtd->oobsize,
++				this->auxiliary_virt, this->auxiliary_phys,
++				nfc_geo->auxiliary_size,
++				auxiliary_virt, auxiliary_phys);
++exit_auxiliary:
++		send_page_end(this, buf, mtd->writesize,
++				this->payload_virt, this->payload_phys,
++				nfc_geo->payload_size,
++				payload_virt, payload_phys);
++	}
++
++	return 0;
++}
++
++/*
++ * There are several places in this driver where we have to handle the OOB and
++ * block marks. This is the function where things are the most complicated, so
++ * this is where we try to explain it all. All the other places refer back to
++ * here.
++ *
++ * These are the rules, in order of decreasing importance:
++ *
++ * 1) Nothing the caller does can be allowed to imperil the block mark.
++ *
++ * 2) In read operations, the first byte of the OOB we return must reflect the
++ *    true state of the block mark, no matter where that block mark appears in
++ *    the physical page.
++ *
++ * 3) ECC-based read operations return an OOB full of set bits (since we never
++ *    allow ECC-based writes to the OOB, it doesn't matter what ECC-based reads
++ *    return).
++ *
++ * 4) "Raw" read operations return a direct view of the physical bytes in the
++ *    page, using the conventional definition of which bytes are data and which
++ *    are OOB. This gives the caller a way to see the actual, physical bytes
++ *    in the page, without the distortions applied by our ECC engine.
++ *
++ *
++ * What we do for this specific read operation depends on two questions:
++ *
++ * 1) Are we doing a "raw" read, or an ECC-based read?
++ *
++ * 2) Are we using block mark swapping or transcription?
++ *
++ * There are four cases, illustrated by the following Karnaugh map:
++ *
++ *                    |           Raw           |         ECC-based       |
++ *       -------------+-------------------------+-------------------------+
++ *                    | Read the conventional   |                         |
++ *                    | OOB at the end of the   |                         |
++ *       Swapping     | page and return it. It  |                         |
++ *                    | contains exactly what   |                         |
++ *                    | we want.                | Read the block mark and |
++ *       -------------+-------------------------+ return it in a buffer   |
++ *                    | Read the conventional   | full of set bits.       |
++ *                    | OOB at the end of the   |                         |
++ *                    | page and also the block |                         |
++ *       Transcribing | mark in the metadata.   |                         |
++ *                    | Copy the block mark     |                         |
++ *                    | into the first byte of  |                         |
++ *                    | the OOB.                |                         |
++ *       -------------+-------------------------+-------------------------+
++ *
++ * Note that we break rule #4 in the Transcribing/Raw case because we're not
++ * giving an accurate view of the actual, physical bytes in the page (we're
++ * overwriting the block mark). That's OK because it's more important to follow
++ * rule #2.
++ *
++ * It turns out that knowing whether we want an "ECC-based" or "raw" read is not
++ * easy. When reading a page, for example, the NAND Flash MTD code calls our
++ * ecc.read_page or ecc.read_page_raw function. Thus, the fact that MTD wants an
++ * ECC-based or raw view of the page is implicit in which function it calls
++ * (there is a similar pair of ECC-based/raw functions for writing).
++ */
++static int gpmi_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
++				int page)
++{
++	struct gpmi_nand_data *this = nand_get_controller_data(chip);
++
++	dev_dbg(this->dev, "page number is %d\n", page);
++	/* clear the OOB buffer */
++	memset(chip->oob_poi, ~0, mtd->oobsize);
++
++	/* Read out the conventional OOB. */
++	chip->cmdfunc(mtd, NAND_CMD_READ0, mtd->writesize, page);
++	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
++
++	/*
++	 * Now, we want to make sure the block mark is correct. In the
++	 * non-transcribing case (!GPMI_IS_MX23()), we already have it.
++	 * Otherwise, we need to explicitly read it.
++	 */
++	if (GPMI_IS_MX23(this)) {
++		/* Read the block mark into the first byte of the OOB buffer. */
++		chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
++		chip->oob_poi[0] = chip->read_byte(mtd);
++	}
++
++	return 0;
++}
++
++static int
++gpmi_ecc_write_oob(struct mtd_info *mtd, struct nand_chip *chip, int page)
++{
++	struct mtd_oob_region of = { };
++	int status = 0;
++
++	/* Do we have available oob area? */
++	mtd_ooblayout_free(mtd, 0, &of);
++	if (!of.length)
++		return -EPERM;
++
++	if (!nand_is_slc(chip))
++		return -EPERM;
++
++	chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize + of.offset, page);
++	chip->write_buf(mtd, chip->oob_poi + of.offset, of.length);
++	chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
++
++	status = chip->waitfunc(mtd, chip);
++	return status & NAND_STATUS_FAIL ? -EIO : 0;
++}
++
++/*
++ * This function reads a NAND page without involving the ECC engine (no HW
++ * ECC correction).
++ * The tricky part in the GPMI/BCH controller is that it stores ECC bits
++ * inline (interleaved with payload DATA), and do not align data chunk on
++ * byte boundaries.
++ * We thus need to take care moving the payload data and ECC bits stored in the
++ * page into the provided buffers, which is why we're using gpmi_copy_bits.
++ *
++ * See set_geometry_by_ecc_info inline comments to have a full description
++ * of the layout used by the GPMI controller.
++ */
++static int gpmi_ecc_read_page_raw(struct mtd_info *mtd,
++				  struct nand_chip *chip, uint8_t *buf,
++				  int oob_required, int page)
++{
++	struct gpmi_nand_data *this = nand_get_controller_data(chip);
++	struct bch_geometry *nfc_geo = &this->bch_geometry;
++	int eccsize = nfc_geo->ecc_chunk_size;
++	int eccbits = nfc_geo->ecc_strength * nfc_geo->gf_len;
++	u8 *tmp_buf = this->raw_buffer;
++	size_t src_bit_off;
++	size_t oob_bit_off;
++	size_t oob_byte_off;
++	uint8_t *oob = chip->oob_poi;
++	int step;
++
++	chip->read_buf(mtd, tmp_buf,
++		       mtd->writesize + mtd->oobsize);
++
++	/*
++	 * If required, swap the bad block marker and the data stored in the
++	 * metadata section, so that we don't wrongly consider a block as bad.
++	 *
++	 * See the layout description for a detailed explanation on why this
++	 * is needed.
++	 */
++	if (this->swap_block_mark) {
++		u8 swap = tmp_buf[0];
++
++		tmp_buf[0] = tmp_buf[mtd->writesize];
++		tmp_buf[mtd->writesize] = swap;
++	}
++
++	/*
++	 * Copy the metadata section into the oob buffer (this section is
++	 * guaranteed to be aligned on a byte boundary).
++	 */
++	if (oob_required)
++		memcpy(oob, tmp_buf, nfc_geo->metadata_size);
++
++	oob_bit_off = nfc_geo->metadata_size * 8;
++	src_bit_off = oob_bit_off;
++
++	/* Extract interleaved payload data and ECC bits */
++	for (step = 0; step < nfc_geo->ecc_chunk_count; step++) {
++		if (buf)
++			gpmi_copy_bits(buf, step * eccsize * 8,
++				       tmp_buf, src_bit_off,
++				       eccsize * 8);
++		src_bit_off += eccsize * 8;
++
++		/* Align last ECC block to align a byte boundary */
++		if (step == nfc_geo->ecc_chunk_count - 1 &&
++		    (oob_bit_off + eccbits) % 8)
++			eccbits += 8 - ((oob_bit_off + eccbits) % 8);
++
++		if (oob_required)
++			gpmi_copy_bits(oob, oob_bit_off,
++				       tmp_buf, src_bit_off,
++				       eccbits);
++
++		src_bit_off += eccbits;
++		oob_bit_off += eccbits;
++	}
++
++	if (oob_required) {
++		oob_byte_off = oob_bit_off / 8;
++
++		if (oob_byte_off < mtd->oobsize)
++			memcpy(oob + oob_byte_off,
++			       tmp_buf + mtd->writesize + oob_byte_off,
++			       mtd->oobsize - oob_byte_off);
++	}
++
++	return 0;
++}
++
++/*
++ * This function writes a NAND page without involving the ECC engine (no HW
++ * ECC generation).
++ * The tricky part in the GPMI/BCH controller is that it stores ECC bits
++ * inline (interleaved with payload DATA), and do not align data chunk on
++ * byte boundaries.
++ * We thus need to take care moving the OOB area at the right place in the
++ * final page, which is why we're using gpmi_copy_bits.
++ *
++ * See set_geometry_by_ecc_info inline comments to have a full description
++ * of the layout used by the GPMI controller.
++ */
++static int gpmi_ecc_write_page_raw(struct mtd_info *mtd,
++				   struct nand_chip *chip,
++				   const uint8_t *buf,
++				   int oob_required, int page)
++{
++	struct gpmi_nand_data *this = nand_get_controller_data(chip);
++	struct bch_geometry *nfc_geo = &this->bch_geometry;
++	int eccsize = nfc_geo->ecc_chunk_size;
++	int eccbits = nfc_geo->ecc_strength * nfc_geo->gf_len;
++	u8 *tmp_buf = this->raw_buffer;
++	uint8_t *oob = chip->oob_poi;
++	size_t dst_bit_off;
++	size_t oob_bit_off;
++	size_t oob_byte_off;
++	int step;
++
++	/*
++	 * Initialize all bits to 1 in case we don't have a buffer for the
++	 * payload or oob data in order to leave unspecified bits of data
++	 * to their initial state.
++	 */
++	if (!buf || !oob_required)
++		memset(tmp_buf, 0xff, mtd->writesize + mtd->oobsize);
++
++	/*
++	 * First copy the metadata section (stored in oob buffer) at the
++	 * beginning of the page, as imposed by the GPMI layout.
++	 */
++	memcpy(tmp_buf, oob, nfc_geo->metadata_size);
++	oob_bit_off = nfc_geo->metadata_size * 8;
++	dst_bit_off = oob_bit_off;
++
++	/* Interleave payload data and ECC bits */
++	for (step = 0; step < nfc_geo->ecc_chunk_count; step++) {
++		if (buf)
++			gpmi_copy_bits(tmp_buf, dst_bit_off,
++				       buf, step * eccsize * 8, eccsize * 8);
++		dst_bit_off += eccsize * 8;
++
++		/* Align last ECC block to align a byte boundary */
++		if (step == nfc_geo->ecc_chunk_count - 1 &&
++		    (oob_bit_off + eccbits) % 8)
++			eccbits += 8 - ((oob_bit_off + eccbits) % 8);
++
++		if (oob_required)
++			gpmi_copy_bits(tmp_buf, dst_bit_off,
++				       oob, oob_bit_off, eccbits);
++
++		dst_bit_off += eccbits;
++		oob_bit_off += eccbits;
++	}
++
++	oob_byte_off = oob_bit_off / 8;
++
++	if (oob_required && oob_byte_off < mtd->oobsize)
++		memcpy(tmp_buf + mtd->writesize + oob_byte_off,
++		       oob + oob_byte_off, mtd->oobsize - oob_byte_off);
++
++	/*
++	 * If required, swap the bad block marker and the first byte of the
++	 * metadata section, so that we don't modify the bad block marker.
++	 *
++	 * See the layout description for a detailed explanation on why this
++	 * is needed.
++	 */
++	if (this->swap_block_mark) {
++		u8 swap = tmp_buf[0];
++
++		tmp_buf[0] = tmp_buf[mtd->writesize];
++		tmp_buf[mtd->writesize] = swap;
++	}
++
++	chip->write_buf(mtd, tmp_buf, mtd->writesize + mtd->oobsize);
++
++	return 0;
++}
++
++static int gpmi_ecc_read_oob_raw(struct mtd_info *mtd, struct nand_chip *chip,
++				 int page)
++{
++	chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
++
++	return gpmi_ecc_read_page_raw(mtd, chip, NULL, 1, page);
++}
++
++static int gpmi_ecc_write_oob_raw(struct mtd_info *mtd, struct nand_chip *chip,
++				 int page)
++{
++	chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0, page);
++
++	return gpmi_ecc_write_page_raw(mtd, chip, NULL, 1, page);
++}
++
++static int gpmi_block_markbad(struct mtd_info *mtd, loff_t ofs)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct gpmi_nand_data *this = nand_get_controller_data(chip);
++	int ret = 0;
++	uint8_t *block_mark;
++	int column, page, status, chipnr;
++
++	chipnr = (int)(ofs >> chip->chip_shift);
++	chip->select_chip(mtd, chipnr);
++
++	column = !GPMI_IS_MX23(this) ? mtd->writesize : 0;
++
++	/* Write the block mark. */
++	block_mark = this->data_buffer_dma;
++	block_mark[0] = 0; /* bad block marker */
++
++	/* Shift to get page */
++	page = (int)(ofs >> chip->page_shift);
++
++	chip->cmdfunc(mtd, NAND_CMD_SEQIN, column, page);
++	chip->write_buf(mtd, block_mark, 1);
++	chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
++
++	status = chip->waitfunc(mtd, chip);
++	if (status & NAND_STATUS_FAIL)
++		ret = -EIO;
++
++	chip->select_chip(mtd, -1);
++
++	return ret;
++}
++
++static int nand_boot_set_geometry(struct gpmi_nand_data *this)
++{
++	struct boot_rom_geometry *geometry = &this->rom_geometry;
++
++	/*
++	 * Set the boot block stride size.
++	 *
++	 * In principle, we should be reading this from the OTP bits, since
++	 * that's where the ROM is going to get it. In fact, we don't have any
++	 * way to read the OTP bits, so we go with the default and hope for the
++	 * best.
++	 */
++	geometry->stride_size_in_pages = 64;
++
++	/*
++	 * Set the search area stride exponent.
++	 *
++	 * In principle, we should be reading this from the OTP bits, since
++	 * that's where the ROM is going to get it. In fact, we don't have any
++	 * way to read the OTP bits, so we go with the default and hope for the
++	 * best.
++	 */
++	geometry->search_area_stride_exponent = 2;
++	return 0;
++}
++
++static const char  *fingerprint = "STMP";
++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);
++	unsigned int search_area_size_in_strides;
++	unsigned int stride;
++	unsigned int page;
++	uint8_t *buffer = chip->buffers->databuf;
++	int saved_chip_number;
++	int found_an_ncb_fingerprint = false;
++
++	/* Compute the number of strides in a search area. */
++	search_area_size_in_strides = 1 << rom_geo->search_area_stride_exponent;
++
++	saved_chip_number = this->current_chip;
++	chip->select_chip(mtd, 0);
++
++	/*
++	 * Loop through the first search area, looking for the NCB fingerprint.
++	 */
++	dev_dbg(dev, "Scanning for an NCB fingerprint...\n");
++
++	for (stride = 0; stride < search_area_size_in_strides; stride++) {
++		/* Compute the page addresses. */
++		page = stride * rom_geo->stride_size_in_pages;
++
++		dev_dbg(dev, "Looking for a fingerprint in page 0x%x\n", page);
++
++		/*
++		 * Read the NCB fingerprint. The fingerprint is four bytes long
++		 * and starts in the 12th byte of the page.
++		 */
++		chip->cmdfunc(mtd, NAND_CMD_READ0, 12, page);
++		chip->read_buf(mtd, buffer, strlen(fingerprint));
++
++		/* Look for the fingerprint. */
++		if (!memcmp(buffer, fingerprint, strlen(fingerprint))) {
++			found_an_ncb_fingerprint = true;
++			break;
++		}
++
++	}
++
++	chip->select_chip(mtd, saved_chip_number);
++
++	if (found_an_ncb_fingerprint)
++		dev_dbg(dev, "\tFound a fingerprint\n");
++	else
++		dev_dbg(dev, "\tNo fingerprint found\n");
++	return found_an_ncb_fingerprint;
++}
++
++/* Writes a transcription stamp. */
++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);
++	unsigned int block_size_in_pages;
++	unsigned int search_area_size_in_strides;
++	unsigned int search_area_size_in_pages;
++	unsigned int search_area_size_in_blocks;
++	unsigned int block;
++	unsigned int stride;
++	unsigned int page;
++	uint8_t      *buffer = chip->buffers->databuf;
++	int saved_chip_number;
++	int status;
++
++	/* Compute the search area geometry. */
++	block_size_in_pages = mtd->erasesize / mtd->writesize;
++	search_area_size_in_strides = 1 << rom_geo->search_area_stride_exponent;
++	search_area_size_in_pages = search_area_size_in_strides *
++					rom_geo->stride_size_in_pages;
++	search_area_size_in_blocks =
++		  (search_area_size_in_pages + (block_size_in_pages - 1)) /
++				    block_size_in_pages;
++
++	dev_dbg(dev, "Search Area Geometry :\n");
++	dev_dbg(dev, "\tin Blocks : %u\n", search_area_size_in_blocks);
++	dev_dbg(dev, "\tin Strides: %u\n", search_area_size_in_strides);
++	dev_dbg(dev, "\tin Pages  : %u\n", search_area_size_in_pages);
++
++	/* Select chip 0. */
++	saved_chip_number = this->current_chip;
++	chip->select_chip(mtd, 0);
++
++	/* Loop over blocks in the first search area, erasing them. */
++	dev_dbg(dev, "Erasing the search area...\n");
++
++	for (block = 0; block < search_area_size_in_blocks; block++) {
++		/* Compute the page address. */
++		page = block * block_size_in_pages;
++
++		/* Erase this block. */
++		dev_dbg(dev, "\tErasing block 0x%x\n", block);
++		chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page);
++		chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1);
++
++		/* Wait for the erase to finish. */
++		status = chip->waitfunc(mtd, chip);
++		if (status & NAND_STATUS_FAIL)
++			dev_err(dev, "[%s] Erase failed.\n", __func__);
++	}
++
++	/* Write the NCB fingerprint into the page buffer. */
++	memset(buffer, ~0, mtd->writesize);
++	memcpy(buffer + 12, fingerprint, strlen(fingerprint));
++
++	/* Loop through the first search area, writing NCB fingerprints. */
++	dev_dbg(dev, "Writing NCB fingerprints...\n");
++	for (stride = 0; stride < search_area_size_in_strides; stride++) {
++		/* Compute the page addresses. */
++		page = stride * rom_geo->stride_size_in_pages;
++
++		/* Write the first page of the current stride. */
++		dev_dbg(dev, "Writing an NCB fingerprint in page 0x%x\n", page);
++		chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
++		chip->ecc.write_page_raw(mtd, chip, buffer, 0, page);
++		chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
++
++		/* Wait for the write to finish. */
++		status = chip->waitfunc(mtd, chip);
++		if (status & NAND_STATUS_FAIL)
++			dev_err(dev, "[%s] Write failed.\n", __func__);
++	}
++
++	/* Deselect chip 0. */
++	chip->select_chip(mtd, saved_chip_number);
++	return 0;
++}
++
++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);
++	unsigned int block_count;
++	unsigned int block;
++	int     chipnr;
++	int     page;
++	loff_t  byte;
++	uint8_t block_mark;
++	int     ret = 0;
++
++	/*
++	 * If control arrives here, we can't use block mark swapping, which
++	 * means we're forced to use transcription. First, scan for the
++	 * transcription stamp. If we find it, then we don't have to do
++	 * anything -- the block marks are already transcribed.
++	 */
++	if (mx23_check_transcription_stamp(this))
++		return 0;
++
++	/*
++	 * If control arrives here, we couldn't find a transcription stamp, so
++	 * so we presume the block marks are in the conventional location.
++	 */
++	dev_dbg(dev, "Transcribing bad block marks...\n");
++
++	/* Compute the number of blocks in the entire medium. */
++	block_count = chip->chipsize >> chip->phys_erase_shift;
++
++	/*
++	 * Loop over all the blocks in the medium, transcribing block marks as
++	 * we go.
++	 */
++	for (block = 0; block < block_count; block++) {
++		/*
++		 * Compute the chip, page and byte addresses for this block's
++		 * conventional mark.
++		 */
++		chipnr = block >> (chip->chip_shift - chip->phys_erase_shift);
++		page = block << (chip->phys_erase_shift - chip->page_shift);
++		byte = block <<  chip->phys_erase_shift;
++
++		/* Send the command to read the conventional block mark. */
++		chip->select_chip(mtd, chipnr);
++		chip->cmdfunc(mtd, NAND_CMD_READ0, mtd->writesize, page);
++		block_mark = chip->read_byte(mtd);
++		chip->select_chip(mtd, -1);
++
++		/*
++		 * Check if the block is marked bad. If so, we need to mark it
++		 * again, but this time the result will be a mark in the
++		 * location where we transcribe block marks.
++		 */
++		if (block_mark != 0xff) {
++			dev_dbg(dev, "Transcribing mark in block %u\n", block);
++			ret = chip->block_markbad(mtd, byte);
++			if (ret)
++				dev_err(dev,
++					"Failed to mark block bad with ret %d\n",
++					ret);
++		}
++	}
++
++	/* Write the stamp that indicates we've transcribed the block marks. */
++	mx23_write_transcription_stamp(this);
++	return 0;
++}
++
++static int nand_boot_init(struct gpmi_nand_data  *this)
++{
++	nand_boot_set_geometry(this);
++
++	/* This is ROM arch-specific initilization before the BBT scanning. */
++	if (GPMI_IS_MX23(this))
++		return mx23_boot_init(this);
++	return 0;
++}
++
++static int gpmi_set_geometry(struct gpmi_nand_data *this)
++{
++	int ret;
++
++	/* Free the temporary DMA memory for reading ID. */
++	gpmi_free_dma_buffer(this);
++
++	/* Set up the NFC geometry which is used by BCH. */
++	ret = bch_set_geometry(this);
++	if (ret) {
++		dev_err(this->dev, "Error setting BCH geometry : %d\n", ret);
++		return ret;
++	}
++
++	/* Alloc the new DMA buffers according to the pagesize and oobsize */
++	return gpmi_alloc_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 nand_ecc_ctrl *ecc = &chip->ecc;
++	struct bch_geometry *bch_geo = &this->bch_geometry;
++	int ret;
++
++	/* Set up the medium geometry */
++	ret = gpmi_set_geometry(this);
++	if (ret)
++		return ret;
++
++	/* Init the nand_ecc_ctrl{} */
++	ecc->read_page	= gpmi_ecc_read_page;
++	ecc->write_page	= gpmi_ecc_write_page;
++	ecc->read_oob	= gpmi_ecc_read_oob;
++	ecc->write_oob	= gpmi_ecc_write_oob;
++	ecc->read_page_raw = gpmi_ecc_read_page_raw;
++	ecc->write_page_raw = gpmi_ecc_write_page_raw;
++	ecc->read_oob_raw = gpmi_ecc_read_oob_raw;
++	ecc->write_oob_raw = gpmi_ecc_write_oob_raw;
++	ecc->mode	= NAND_ECC_HW;
++	ecc->size	= bch_geo->ecc_chunk_size;
++	ecc->strength	= bch_geo->ecc_strength;
++	mtd_set_ooblayout(mtd, &gpmi_ooblayout_ops);
++
++	/*
++	 * We only enable the subpage read when:
++	 *  (1) the chip is imx6, and
++	 *  (2) the size of the ECC parity is byte aligned.
++	 */
++	if (GPMI_IS_MX6(this) &&
++		((bch_geo->gf_len * bch_geo->ecc_strength) % 8) == 0) {
++		ecc->read_subpage = gpmi_ecc_read_subpage;
++		chip->options |= NAND_SUBPAGE_READ;
++	}
++
++	/*
++	 * Can we enable the extra features? such as EDO or Sync mode.
++	 *
++	 * We do not check the return value now. That's means if we fail in
++	 * enable the extra features, we still can run in the normal way.
++	 */
++	gpmi_extra_init(this);
++
++	return 0;
++}
++
++static int gpmi_nand_init(struct gpmi_nand_data *this)
++{
++	struct nand_chip *chip = &this->nand;
++	struct mtd_info  *mtd = nand_to_mtd(chip);
++	int ret;
++
++	/* init current chip */
++	this->current_chip	= -1;
++
++	/* init the MTD data structures */
++	mtd->name		= "gpmi-nand";
++	mtd->dev.parent		= this->dev;
++
++	/* init the nand_chip{}, we don't support a 16-bit NAND Flash bus. */
++	nand_set_controller_data(chip, this);
++	nand_set_flash_node(chip, this->pdev->dev.of_node);
++	chip->select_chip	= gpmi_select_chip;
++	chip->cmd_ctrl		= gpmi_cmd_ctrl;
++	chip->dev_ready		= gpmi_dev_ready;
++	chip->read_byte		= gpmi_read_byte;
++	chip->read_buf		= gpmi_read_buf;
++	chip->write_buf		= gpmi_write_buf;
++	chip->badblock_pattern	= &gpmi_bbt_descr;
++	chip->block_markbad	= gpmi_block_markbad;
++	chip->options		|= NAND_NO_SUBPAGE_WRITE;
++
++	/* Set up swap_block_mark, must be set before the gpmi_set_geometry() */
++	this->swap_block_mark = !GPMI_IS_MX23(this);
++
++	/*
++	 * Allocate a temporary DMA buffer for reading ID in the
++	 * nand_scan_ident().
++	 */
++	this->bch_geometry.payload_size = 1024;
++	this->bch_geometry.auxiliary_size = 128;
++	ret = gpmi_alloc_dma_buffer(this);
++	if (ret)
++		goto err_out;
++
++	ret = nand_scan_ident(mtd, GPMI_IS_MX6(this) ? 2 : 1, NULL);
++	if (ret)
++		goto err_out;
++
++	if (chip->bbt_options & NAND_BBT_USE_FLASH) {
++		chip->bbt_options |= NAND_BBT_NO_OOB;
++
++		if (of_property_read_bool(this->dev->of_node,
++						"fsl,no-blockmark-swap"))
++			this->swap_block_mark = false;
++	}
++	dev_dbg(this->dev, "Blockmark swapping %sabled\n",
++		this->swap_block_mark ? "en" : "dis");
++
++	ret = gpmi_init_last(this);
++	if (ret)
++		goto err_out;
++
++	chip->options |= NAND_SKIP_BBTSCAN;
++	ret = nand_scan_tail(mtd);
++	if (ret)
++		goto err_out;
++
++	ret = nand_boot_init(this);
++	if (ret)
++		goto err_nand_cleanup;
++	ret = chip->scan_bbt(mtd);
++	if (ret)
++		goto err_nand_cleanup;
++
++	ret = mtd_device_register(mtd, NULL, 0);
++	if (ret)
++		goto err_nand_cleanup;
++	return 0;
++
++err_nand_cleanup:
++	nand_cleanup(chip);
++err_out:
++	gpmi_free_dma_buffer(this);
++	return ret;
++}
++
++static const struct of_device_id gpmi_nand_id_table[] = {
++	{
++		.compatible = "fsl,imx23-gpmi-nand",
++		.data = &gpmi_devdata_imx23,
++	}, {
++		.compatible = "fsl,imx28-gpmi-nand",
++		.data = &gpmi_devdata_imx28,
++	}, {
++		.compatible = "fsl,imx6q-gpmi-nand",
++		.data = &gpmi_devdata_imx6q,
++	}, {
++		.compatible = "fsl,imx6sx-gpmi-nand",
++		.data = &gpmi_devdata_imx6sx,
++	}, {
++		.compatible = "fsl,imx7d-gpmi-nand",
++		.data = &gpmi_devdata_imx7d,
++	}, {}
++};
++MODULE_DEVICE_TABLE(of, gpmi_nand_id_table);
++
++static int gpmi_nand_probe(struct platform_device *pdev)
++{
++	struct gpmi_nand_data *this;
++	const struct of_device_id *of_id;
++	int ret;
++
++	this = devm_kzalloc(&pdev->dev, sizeof(*this), GFP_KERNEL);
++	if (!this)
++		return -ENOMEM;
++
++	of_id = of_match_device(gpmi_nand_id_table, &pdev->dev);
++	if (of_id) {
++		this->devdata = of_id->data;
++	} else {
++		dev_err(&pdev->dev, "Failed to find the right device id.\n");
++		return -ENODEV;
++	}
++
++	platform_set_drvdata(pdev, this);
++	this->pdev  = pdev;
++	this->dev   = &pdev->dev;
++
++	ret = acquire_resources(this);
++	if (ret)
++		goto exit_acquire_resources;
++
++	ret = init_hardware(this);
++	if (ret)
++		goto exit_nfc_init;
++
++	ret = gpmi_nand_init(this);
++	if (ret)
++		goto exit_nfc_init;
++
++	dev_info(this->dev, "driver registered.\n");
++
++	return 0;
++
++exit_nfc_init:
++	release_resources(this);
++exit_acquire_resources:
++
++	return ret;
++}
++
++static int gpmi_nand_remove(struct platform_device *pdev)
++{
++	struct gpmi_nand_data *this = platform_get_drvdata(pdev);
++
++	nand_release(nand_to_mtd(&this->nand));
++	gpmi_free_dma_buffer(this);
++	release_resources(this);
++	return 0;
++}
++
++#ifdef CONFIG_PM_SLEEP
++static int gpmi_pm_suspend(struct device *dev)
++{
++	struct gpmi_nand_data *this = dev_get_drvdata(dev);
++
++	release_dma_channels(this);
++	return 0;
++}
++
++static int gpmi_pm_resume(struct device *dev)
++{
++	struct gpmi_nand_data *this = dev_get_drvdata(dev);
++	int ret;
++
++	ret = acquire_dma_channels(this);
++	if (ret < 0)
++		return ret;
++
++	/* re-init the GPMI registers */
++	this->flags &= ~GPMI_TIMING_INIT_OK;
++	ret = gpmi_init(this);
++	if (ret) {
++		dev_err(this->dev, "Error setting GPMI : %d\n", ret);
++		return ret;
++	}
++
++	/* re-init the BCH registers */
++	ret = bch_set_geometry(this);
++	if (ret) {
++		dev_err(this->dev, "Error setting BCH : %d\n", ret);
++		return ret;
++	}
++
++	/* re-init others */
++	gpmi_extra_init(this);
++
++	return 0;
++}
++#endif /* CONFIG_PM_SLEEP */
++
++static const struct dev_pm_ops gpmi_pm_ops = {
++	SET_SYSTEM_SLEEP_PM_OPS(gpmi_pm_suspend, gpmi_pm_resume)
++};
++
++static struct platform_driver gpmi_nand_driver = {
++	.driver = {
++		.name = "gpmi-nand",
++		.pm = &gpmi_pm_ops,
++		.of_match_table = gpmi_nand_id_table,
++	},
++	.probe   = gpmi_nand_probe,
++	.remove  = gpmi_nand_remove,
++};
++module_platform_driver(gpmi_nand_driver);
++
++MODULE_AUTHOR("Freescale Semiconductor, Inc.");
++MODULE_DESCRIPTION("i.MX GPMI NAND Flash Controller Driver");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.h b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.h
+new file mode 100644
+index 0000000..a45e4ce
+--- /dev/null
++++ b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.h
+@@ -0,0 +1,315 @@
++/*
++ * Freescale GPMI NAND Flash Driver
++ *
++ * Copyright (C) 2010-2011 Freescale Semiconductor, Inc.
++ * Copyright (C) 2008 Embedded Alley Solutions, Inc.
++ *
++ * 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.
++ */
++#ifndef __DRIVERS_MTD_NAND_GPMI_NAND_H
++#define __DRIVERS_MTD_NAND_GPMI_NAND_H
++
++#include <linux/mtd/rawnand.h>
++#include <linux/platform_device.h>
++#include <linux/dma-mapping.h>
++#include <linux/dmaengine.h>
++
++#define GPMI_CLK_MAX 5 /* MX6Q needs five clocks */
++struct resources {
++	void __iomem  *gpmi_regs;
++	void __iomem  *bch_regs;
++	unsigned int  dma_low_channel;
++	unsigned int  dma_high_channel;
++	struct clk    *clock[GPMI_CLK_MAX];
++};
++
++/**
++ * struct bch_geometry - BCH geometry description.
++ * @gf_len:                   The length of Galois Field. (e.g., 13 or 14)
++ * @ecc_strength:             A number that describes the strength of the ECC
++ *                            algorithm.
++ * @page_size:                The size, in bytes, of a physical page, including
++ *                            both data and OOB.
++ * @metadata_size:            The size, in bytes, of the metadata.
++ * @ecc_chunk_size:           The size, in bytes, of a single ECC chunk. Note
++ *                            the first chunk in the page includes both data and
++ *                            metadata, so it's a bit larger than this value.
++ * @ecc_chunk_count:          The number of ECC chunks in the page,
++ * @payload_size:             The size, in bytes, of the payload buffer.
++ * @auxiliary_size:           The size, in bytes, of the auxiliary buffer.
++ * @auxiliary_status_offset:  The offset into the auxiliary buffer at which
++ *                            the ECC status appears.
++ * @block_mark_byte_offset:   The byte offset in the ECC-based page view at
++ *                            which the underlying physical block mark appears.
++ * @block_mark_bit_offset:    The bit offset into the ECC-based page view at
++ *                            which the underlying physical block mark appears.
++ */
++struct bch_geometry {
++	unsigned int  gf_len;
++	unsigned int  ecc_strength;
++	unsigned int  page_size;
++	unsigned int  metadata_size;
++	unsigned int  ecc_chunk_size;
++	unsigned int  ecc_chunk_count;
++	unsigned int  payload_size;
++	unsigned int  auxiliary_size;
++	unsigned int  auxiliary_status_offset;
++	unsigned int  block_mark_byte_offset;
++	unsigned int  block_mark_bit_offset;
++};
++
++/**
++ * struct boot_rom_geometry - Boot ROM geometry description.
++ * @stride_size_in_pages:        The size of a boot block stride, in pages.
++ * @search_area_stride_exponent: The logarithm to base 2 of the size of a
++ *                               search area in boot block strides.
++ */
++struct boot_rom_geometry {
++	unsigned int  stride_size_in_pages;
++	unsigned int  search_area_stride_exponent;
++};
++
++/* DMA operations types */
++enum dma_ops_type {
++	DMA_FOR_COMMAND = 1,
++	DMA_FOR_READ_DATA,
++	DMA_FOR_WRITE_DATA,
++	DMA_FOR_READ_ECC_PAGE,
++	DMA_FOR_WRITE_ECC_PAGE
++};
++
++/**
++ * struct nand_timing - Fundamental timing attributes for NAND.
++ * @data_setup_in_ns:         The data setup time, in nanoseconds. Usually the
++ *                            maximum of tDS and tWP. A negative value
++ *                            indicates this characteristic isn't known.
++ * @data_hold_in_ns:          The data hold time, in nanoseconds. Usually the
++ *                            maximum of tDH, tWH and tREH. A negative value
++ *                            indicates this characteristic isn't known.
++ * @address_setup_in_ns:      The address setup time, in nanoseconds. Usually
++ *                            the maximum of tCLS, tCS and tALS. A negative
++ *                            value indicates this characteristic isn't known.
++ * @gpmi_sample_delay_in_ns:  A GPMI-specific timing parameter. A negative value
++ *                            indicates this characteristic isn't known.
++ * @tREA_in_ns:               tREA, in nanoseconds, from the data sheet. A
++ *                            negative value indicates this characteristic isn't
++ *                            known.
++ * @tRLOH_in_ns:              tRLOH, in nanoseconds, from the data sheet. A
++ *                            negative value indicates this characteristic isn't
++ *                            known.
++ * @tRHOH_in_ns:              tRHOH, in nanoseconds, from the data sheet. A
++ *                            negative value indicates this characteristic isn't
++ *                            known.
++ */
++struct nand_timing {
++	int8_t  data_setup_in_ns;
++	int8_t  data_hold_in_ns;
++	int8_t  address_setup_in_ns;
++	int8_t  gpmi_sample_delay_in_ns;
++	int8_t  tREA_in_ns;
++	int8_t  tRLOH_in_ns;
++	int8_t  tRHOH_in_ns;
++};
++
++enum gpmi_type {
++	IS_MX23,
++	IS_MX28,
++	IS_MX6Q,
++	IS_MX6SX,
++	IS_MX7D,
++};
++
++struct gpmi_devdata {
++	enum gpmi_type type;
++	int bch_max_ecc_strength;
++	int max_chain_delay; /* See the async EDO mode */
++	const char * const *clks;
++	const int clks_count;
++};
++
++struct gpmi_nand_data {
++	/* flags */
++#define GPMI_ASYNC_EDO_ENABLED	(1 << 0)
++#define GPMI_TIMING_INIT_OK	(1 << 1)
++	int			flags;
++	const struct gpmi_devdata *devdata;
++
++	/* System Interface */
++	struct device		*dev;
++	struct platform_device	*pdev;
++
++	/* Resources */
++	struct resources	resources;
++
++	/* Flash Hardware */
++	struct nand_timing	timing;
++	int			timing_mode;
++
++	/* BCH */
++	struct bch_geometry	bch_geometry;
++	struct completion	bch_done;
++
++	/* NAND Boot issue */
++	bool			swap_block_mark;
++	struct boot_rom_geometry rom_geometry;
++
++	/* MTD / NAND */
++	struct nand_chip	nand;
++
++	/* General-use Variables */
++	int			current_chip;
++	unsigned int		command_length;
++
++	/* passed from upper layer */
++	uint8_t			*upper_buf;
++	int			upper_len;
++
++	/* for DMA operations */
++	bool			direct_dma_map_ok;
++
++	struct scatterlist	cmd_sgl;
++	char			*cmd_buffer;
++
++	struct scatterlist	data_sgl;
++	char			*data_buffer_dma;
++
++	void			*page_buffer_virt;
++	dma_addr_t		page_buffer_phys;
++	unsigned int		page_buffer_size;
++
++	void			*payload_virt;
++	dma_addr_t		payload_phys;
++
++	void			*auxiliary_virt;
++	dma_addr_t		auxiliary_phys;
++
++	void			*raw_buffer;
++
++	/* DMA channels */
++#define DMA_CHANS		8
++	struct dma_chan		*dma_chans[DMA_CHANS];
++	enum dma_ops_type	last_dma_type;
++	enum dma_ops_type	dma_type;
++	struct completion	dma_done;
++
++	/* private */
++	void			*private;
++};
++
++/**
++ * struct gpmi_nfc_hardware_timing - GPMI hardware timing parameters.
++ * @data_setup_in_cycles:      The data setup time, in cycles.
++ * @data_hold_in_cycles:       The data hold time, in cycles.
++ * @address_setup_in_cycles:   The address setup time, in cycles.
++ * @device_busy_timeout:       The timeout waiting for NAND Ready/Busy,
++ *                             this value is the number of cycles multiplied
++ *                             by 4096.
++ * @use_half_periods:          Indicates the clock is running slowly, so the
++ *                             NFC DLL should use half-periods.
++ * @sample_delay_factor:       The sample delay factor.
++ * @wrn_dly_sel:               The delay on the GPMI write strobe.
++ */
++struct gpmi_nfc_hardware_timing {
++	/* for HW_GPMI_TIMING0 */
++	uint8_t  data_setup_in_cycles;
++	uint8_t  data_hold_in_cycles;
++	uint8_t  address_setup_in_cycles;
++
++	/* for HW_GPMI_TIMING1 */
++	uint16_t device_busy_timeout;
++#define GPMI_DEFAULT_BUSY_TIMEOUT	0x500 /* default busy timeout value.*/
++
++	/* for HW_GPMI_CTRL1 */
++	bool     use_half_periods;
++	uint8_t  sample_delay_factor;
++	uint8_t  wrn_dly_sel;
++};
++
++/**
++ * struct timing_threshold - Timing threshold
++ * @max_data_setup_cycles:       The maximum number of data setup cycles that
++ *                               can be expressed in the hardware.
++ * @internal_data_setup_in_ns:   The time, in ns, that the NFC hardware requires
++ *                               for data read internal setup. In the Reference
++ *                               Manual, see the chapter "High-Speed NAND
++ *                               Timing" for more details.
++ * @max_sample_delay_factor:     The maximum sample delay factor that can be
++ *                               expressed in the hardware.
++ * @max_dll_clock_period_in_ns:  The maximum period of the GPMI clock that the
++ *                               sample delay DLL hardware can possibly work
++ *                               with (the DLL is unusable with longer periods).
++ *                               If the full-cycle period is greater than HALF
++ *                               this value, the DLL must be configured to use
++ *                               half-periods.
++ * @max_dll_delay_in_ns:         The maximum amount of delay, in ns, that the
++ *                               DLL can implement.
++ * @clock_frequency_in_hz:       The clock frequency, in Hz, during the current
++ *                               I/O transaction. If no I/O transaction is in
++ *                               progress, this is the clock frequency during
++ *                               the most recent I/O transaction.
++ */
++struct timing_threshold {
++	const unsigned int      max_chip_count;
++	const unsigned int      max_data_setup_cycles;
++	const unsigned int      internal_data_setup_in_ns;
++	const unsigned int      max_sample_delay_factor;
++	const unsigned int      max_dll_clock_period_in_ns;
++	const unsigned int      max_dll_delay_in_ns;
++	unsigned long           clock_frequency_in_hz;
++
++};
++
++/* Common Services */
++extern int common_nfc_set_geometry(struct gpmi_nand_data *);
++extern struct dma_chan *get_dma_chan(struct gpmi_nand_data *);
++extern void prepare_data_dma(struct gpmi_nand_data *,
++				enum dma_data_direction dr);
++extern int start_dma_without_bch_irq(struct gpmi_nand_data *,
++				struct dma_async_tx_descriptor *);
++extern int start_dma_with_bch_irq(struct gpmi_nand_data *,
++				struct dma_async_tx_descriptor *);
++
++/* GPMI-NAND helper function library */
++extern int gpmi_init(struct gpmi_nand_data *);
++extern int gpmi_extra_init(struct gpmi_nand_data *);
++extern void gpmi_clear_bch(struct gpmi_nand_data *);
++extern void gpmi_dump_info(struct gpmi_nand_data *);
++extern int bch_set_geometry(struct gpmi_nand_data *);
++extern int gpmi_is_ready(struct gpmi_nand_data *, unsigned chip);
++extern int gpmi_send_command(struct gpmi_nand_data *);
++extern void gpmi_begin(struct gpmi_nand_data *);
++extern void gpmi_end(struct gpmi_nand_data *);
++extern int gpmi_read_data(struct gpmi_nand_data *);
++extern int gpmi_send_data(struct gpmi_nand_data *);
++extern int gpmi_send_page(struct gpmi_nand_data *,
++			dma_addr_t payload, dma_addr_t auxiliary);
++extern int gpmi_read_page(struct gpmi_nand_data *,
++			dma_addr_t payload, dma_addr_t auxiliary);
++
++void gpmi_copy_bits(u8 *dst, size_t dst_bit_off,
++		    const u8 *src, size_t src_bit_off,
++		    size_t nbits);
++
++/* BCH : Status Block Completion Codes */
++#define STATUS_GOOD		0x00
++#define STATUS_ERASED		0xff
++#define STATUS_UNCORRECTABLE	0xfe
++
++/* Use the devdata to distinguish different Archs. */
++#define GPMI_IS_MX23(x)		((x)->devdata->type == IS_MX23)
++#define GPMI_IS_MX28(x)		((x)->devdata->type == IS_MX28)
++#define GPMI_IS_MX6Q(x)		((x)->devdata->type == IS_MX6Q)
++#define GPMI_IS_MX6SX(x)	((x)->devdata->type == IS_MX6SX)
++#define GPMI_IS_MX7D(x)		((x)->devdata->type == IS_MX7D)
++
++#define GPMI_IS_MX6(x)		(GPMI_IS_MX6Q(x) || GPMI_IS_MX6SX(x) || \
++				 GPMI_IS_MX7D(x))
++#endif
+diff --git a/drivers/mtd/nand/raw/gpmi-nand/gpmi-regs.h b/drivers/mtd/nand/raw/gpmi-nand/gpmi-regs.h
+new file mode 100644
+index 0000000..82114cd
+--- /dev/null
++++ b/drivers/mtd/nand/raw/gpmi-nand/gpmi-regs.h
+@@ -0,0 +1,187 @@
++/*
++ * Freescale GPMI NAND Flash Driver
++ *
++ * Copyright 2008-2011 Freescale Semiconductor, Inc.
++ * Copyright 2008 Embedded Alley Solutions, Inc.
++ *
++ * 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.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++ */
++#ifndef __GPMI_NAND_GPMI_REGS_H
++#define __GPMI_NAND_GPMI_REGS_H
++
++#define HW_GPMI_CTRL0					0x00000000
++#define HW_GPMI_CTRL0_SET				0x00000004
++#define HW_GPMI_CTRL0_CLR				0x00000008
++#define HW_GPMI_CTRL0_TOG				0x0000000c
++
++#define BP_GPMI_CTRL0_COMMAND_MODE			24
++#define BM_GPMI_CTRL0_COMMAND_MODE	(3 << BP_GPMI_CTRL0_COMMAND_MODE)
++#define BF_GPMI_CTRL0_COMMAND_MODE(v)	\
++	(((v) << BP_GPMI_CTRL0_COMMAND_MODE) & BM_GPMI_CTRL0_COMMAND_MODE)
++#define BV_GPMI_CTRL0_COMMAND_MODE__WRITE		0x0
++#define BV_GPMI_CTRL0_COMMAND_MODE__READ		0x1
++#define BV_GPMI_CTRL0_COMMAND_MODE__READ_AND_COMPARE	0x2
++#define BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY	0x3
++
++#define BM_GPMI_CTRL0_WORD_LENGTH			(1 << 23)
++#define BV_GPMI_CTRL0_WORD_LENGTH__16_BIT		0x0
++#define BV_GPMI_CTRL0_WORD_LENGTH__8_BIT		0x1
++
++/*
++ *  Difference in LOCK_CS between imx23 and imx28 :
++ *  This bit may impact the _POWER_ consumption. So some chips
++ *  do not set it.
++ */
++#define MX23_BP_GPMI_CTRL0_LOCK_CS			22
++#define MX28_BP_GPMI_CTRL0_LOCK_CS			27
++#define LOCK_CS_ENABLE					0x1
++#define BF_GPMI_CTRL0_LOCK_CS(v, x)			0x0
++
++/* Difference in CS between imx23 and imx28 */
++#define BP_GPMI_CTRL0_CS				20
++#define MX23_BM_GPMI_CTRL0_CS		(3 << BP_GPMI_CTRL0_CS)
++#define MX28_BM_GPMI_CTRL0_CS		(7 << BP_GPMI_CTRL0_CS)
++#define BF_GPMI_CTRL0_CS(v, x)		(((v) << BP_GPMI_CTRL0_CS) & \
++						(GPMI_IS_MX23((x)) \
++						? MX23_BM_GPMI_CTRL0_CS	\
++						: MX28_BM_GPMI_CTRL0_CS))
++
++#define BP_GPMI_CTRL0_ADDRESS				17
++#define BM_GPMI_CTRL0_ADDRESS		(3 << BP_GPMI_CTRL0_ADDRESS)
++#define BF_GPMI_CTRL0_ADDRESS(v)	\
++		(((v) << BP_GPMI_CTRL0_ADDRESS) & BM_GPMI_CTRL0_ADDRESS)
++#define BV_GPMI_CTRL0_ADDRESS__NAND_DATA		0x0
++#define BV_GPMI_CTRL0_ADDRESS__NAND_CLE			0x1
++#define BV_GPMI_CTRL0_ADDRESS__NAND_ALE			0x2
++
++#define BM_GPMI_CTRL0_ADDRESS_INCREMENT			(1 << 16)
++#define BV_GPMI_CTRL0_ADDRESS_INCREMENT__DISABLED	0x0
++#define BV_GPMI_CTRL0_ADDRESS_INCREMENT__ENABLED	0x1
++
++#define BP_GPMI_CTRL0_XFER_COUNT			0
++#define BM_GPMI_CTRL0_XFER_COUNT	(0xffff << BP_GPMI_CTRL0_XFER_COUNT)
++#define BF_GPMI_CTRL0_XFER_COUNT(v)	\
++		(((v) << BP_GPMI_CTRL0_XFER_COUNT) & BM_GPMI_CTRL0_XFER_COUNT)
++
++#define HW_GPMI_COMPARE					0x00000010
++
++#define HW_GPMI_ECCCTRL					0x00000020
++#define HW_GPMI_ECCCTRL_SET				0x00000024
++#define HW_GPMI_ECCCTRL_CLR				0x00000028
++#define HW_GPMI_ECCCTRL_TOG				0x0000002c
++
++#define BP_GPMI_ECCCTRL_ECC_CMD				13
++#define BM_GPMI_ECCCTRL_ECC_CMD		(3 << BP_GPMI_ECCCTRL_ECC_CMD)
++#define BF_GPMI_ECCCTRL_ECC_CMD(v)	\
++		(((v) << BP_GPMI_ECCCTRL_ECC_CMD) & BM_GPMI_ECCCTRL_ECC_CMD)
++#define BV_GPMI_ECCCTRL_ECC_CMD__BCH_DECODE		0x0
++#define BV_GPMI_ECCCTRL_ECC_CMD__BCH_ENCODE		0x1
++
++#define BM_GPMI_ECCCTRL_ENABLE_ECC			(1 << 12)
++#define BV_GPMI_ECCCTRL_ENABLE_ECC__ENABLE		0x1
++#define BV_GPMI_ECCCTRL_ENABLE_ECC__DISABLE		0x0
++
++#define BP_GPMI_ECCCTRL_BUFFER_MASK			0
++#define BM_GPMI_ECCCTRL_BUFFER_MASK	(0x1ff << BP_GPMI_ECCCTRL_BUFFER_MASK)
++#define BF_GPMI_ECCCTRL_BUFFER_MASK(v)	\
++	(((v) << BP_GPMI_ECCCTRL_BUFFER_MASK) & BM_GPMI_ECCCTRL_BUFFER_MASK)
++#define BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_AUXONLY	0x100
++#define BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_PAGE		0x1FF
++
++#define HW_GPMI_ECCCOUNT				0x00000030
++#define HW_GPMI_PAYLOAD					0x00000040
++#define HW_GPMI_AUXILIARY				0x00000050
++#define HW_GPMI_CTRL1					0x00000060
++#define HW_GPMI_CTRL1_SET				0x00000064
++#define HW_GPMI_CTRL1_CLR				0x00000068
++#define HW_GPMI_CTRL1_TOG				0x0000006c
++
++#define BP_GPMI_CTRL1_DECOUPLE_CS			24
++#define BM_GPMI_CTRL1_DECOUPLE_CS	(1 << BP_GPMI_CTRL1_DECOUPLE_CS)
++
++#define BP_GPMI_CTRL1_WRN_DLY_SEL			22
++#define BM_GPMI_CTRL1_WRN_DLY_SEL	(0x3 << BP_GPMI_CTRL1_WRN_DLY_SEL)
++#define BF_GPMI_CTRL1_WRN_DLY_SEL(v)  \
++	(((v) << BP_GPMI_CTRL1_WRN_DLY_SEL) & BM_GPMI_CTRL1_WRN_DLY_SEL)
++#define BV_GPMI_CTRL1_WRN_DLY_SEL_4_TO_8NS		0x0
++#define BV_GPMI_CTRL1_WRN_DLY_SEL_6_TO_10NS		0x1
++#define BV_GPMI_CTRL1_WRN_DLY_SEL_7_TO_12NS		0x2
++#define BV_GPMI_CTRL1_WRN_DLY_SEL_NO_DELAY		0x3
++
++#define BM_GPMI_CTRL1_BCH_MODE				(1 << 18)
++
++#define BP_GPMI_CTRL1_DLL_ENABLE			17
++#define BM_GPMI_CTRL1_DLL_ENABLE	(1 << BP_GPMI_CTRL1_DLL_ENABLE)
++
++#define BP_GPMI_CTRL1_HALF_PERIOD			16
++#define BM_GPMI_CTRL1_HALF_PERIOD	(1 << BP_GPMI_CTRL1_HALF_PERIOD)
++
++#define BP_GPMI_CTRL1_RDN_DELAY				12
++#define BM_GPMI_CTRL1_RDN_DELAY		(0xf << BP_GPMI_CTRL1_RDN_DELAY)
++#define BF_GPMI_CTRL1_RDN_DELAY(v)	\
++		(((v) << BP_GPMI_CTRL1_RDN_DELAY) & BM_GPMI_CTRL1_RDN_DELAY)
++
++#define BM_GPMI_CTRL1_DEV_RESET				(1 << 3)
++#define BV_GPMI_CTRL1_DEV_RESET__ENABLED		0x0
++#define BV_GPMI_CTRL1_DEV_RESET__DISABLED		0x1
++
++#define BM_GPMI_CTRL1_ATA_IRQRDY_POLARITY		(1 << 2)
++#define BV_GPMI_CTRL1_ATA_IRQRDY_POLARITY__ACTIVELOW	0x0
++#define BV_GPMI_CTRL1_ATA_IRQRDY_POLARITY__ACTIVEHIGH	0x1
++
++#define BM_GPMI_CTRL1_CAMERA_MODE			(1 << 1)
++#define BV_GPMI_CTRL1_GPMI_MODE__NAND			0x0
++#define BV_GPMI_CTRL1_GPMI_MODE__ATA			0x1
++
++#define BM_GPMI_CTRL1_GPMI_MODE				(1 << 0)
++
++#define HW_GPMI_TIMING0					0x00000070
++
++#define BP_GPMI_TIMING0_ADDRESS_SETUP			16
++#define BM_GPMI_TIMING0_ADDRESS_SETUP	(0xff << BP_GPMI_TIMING0_ADDRESS_SETUP)
++#define BF_GPMI_TIMING0_ADDRESS_SETUP(v)	\
++	(((v) << BP_GPMI_TIMING0_ADDRESS_SETUP) & BM_GPMI_TIMING0_ADDRESS_SETUP)
++
++#define BP_GPMI_TIMING0_DATA_HOLD			8
++#define BM_GPMI_TIMING0_DATA_HOLD	(0xff << BP_GPMI_TIMING0_DATA_HOLD)
++#define BF_GPMI_TIMING0_DATA_HOLD(v)		\
++	(((v) << BP_GPMI_TIMING0_DATA_HOLD) & BM_GPMI_TIMING0_DATA_HOLD)
++
++#define BP_GPMI_TIMING0_DATA_SETUP			0
++#define BM_GPMI_TIMING0_DATA_SETUP	(0xff << BP_GPMI_TIMING0_DATA_SETUP)
++#define BF_GPMI_TIMING0_DATA_SETUP(v)		\
++	(((v) << BP_GPMI_TIMING0_DATA_SETUP) & BM_GPMI_TIMING0_DATA_SETUP)
++
++#define HW_GPMI_TIMING1					0x00000080
++#define BP_GPMI_TIMING1_BUSY_TIMEOUT			16
++#define BM_GPMI_TIMING1_BUSY_TIMEOUT	(0xffff << BP_GPMI_TIMING1_BUSY_TIMEOUT)
++#define BF_GPMI_TIMING1_BUSY_TIMEOUT(v)		\
++	(((v) << BP_GPMI_TIMING1_BUSY_TIMEOUT) & BM_GPMI_TIMING1_BUSY_TIMEOUT)
++
++#define HW_GPMI_TIMING2					0x00000090
++#define HW_GPMI_DATA					0x000000a0
++
++/* MX28 uses this to detect READY. */
++#define HW_GPMI_STAT					0x000000b0
++#define MX28_BP_GPMI_STAT_READY_BUSY			24
++#define MX28_BM_GPMI_STAT_READY_BUSY	(0xff << MX28_BP_GPMI_STAT_READY_BUSY)
++#define MX28_BF_GPMI_STAT_READY_BUSY(v)		\
++	(((v) << MX28_BP_GPMI_STAT_READY_BUSY) & MX28_BM_GPMI_STAT_READY_BUSY)
++
++/* MX23 uses this to detect READY. */
++#define HW_GPMI_DEBUG					0x000000c0
++#define MX23_BP_GPMI_DEBUG_READY0			28
++#define MX23_BM_GPMI_DEBUG_READY0	(1 << MX23_BP_GPMI_DEBUG_READY0)
++#endif
+diff --git a/drivers/mtd/nand/raw/hisi504_nand.c b/drivers/mtd/nand/raw/hisi504_nand.c
+new file mode 100644
+index 0000000..d9ee1a7
+--- /dev/null
++++ b/drivers/mtd/nand/raw/hisi504_nand.c
+@@ -0,0 +1,898 @@
++/*
++ * Hisilicon NAND Flash controller driver
++ *
++ * Copyright © 2012-2014 HiSilicon Technologies Co., Ltd.
++ *              http://www.hisilicon.com
++ *
++ * Author: Zhou Wang <wangzhou.bry@gmail.com>
++ * The initial developer of the original code is Zhiyong Cai
++ * <caizhiyong@huawei.com>
++ *
++ * 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/of.h>
++#include <linux/mtd/mtd.h>
++#include <linux/sizes.h>
++#include <linux/clk.h>
++#include <linux/slab.h>
++#include <linux/module.h>
++#include <linux/delay.h>
++#include <linux/interrupt.h>
++#include <linux/mtd/rawnand.h>
++#include <linux/dma-mapping.h>
++#include <linux/platform_device.h>
++#include <linux/mtd/partitions.h>
++
++#define HINFC504_MAX_CHIP                               (4)
++#define HINFC504_W_LATCH                                (5)
++#define HINFC504_R_LATCH                                (7)
++#define HINFC504_RW_LATCH                               (3)
++
++#define HINFC504_NFC_TIMEOUT				(2 * HZ)
++#define HINFC504_NFC_PM_TIMEOUT				(1 * HZ)
++#define HINFC504_NFC_DMA_TIMEOUT			(5 * HZ)
++#define HINFC504_CHIP_DELAY				(25)
++
++#define HINFC504_REG_BASE_ADDRESS_LEN			(0x100)
++#define HINFC504_BUFFER_BASE_ADDRESS_LEN		(2048 + 128)
++
++#define HINFC504_ADDR_CYCLE_MASK			0x4
++
++#define HINFC504_CON					0x00
++#define HINFC504_CON_OP_MODE_NORMAL			BIT(0)
++#define HINFC504_CON_PAGEISZE_SHIFT			(1)
++#define HINFC504_CON_PAGESIZE_MASK			(0x07)
++#define HINFC504_CON_BUS_WIDTH				BIT(4)
++#define HINFC504_CON_READY_BUSY_SEL			BIT(8)
++#define HINFC504_CON_ECCTYPE_SHIFT			(9)
++#define HINFC504_CON_ECCTYPE_MASK			(0x07)
++
++#define HINFC504_PWIDTH					0x04
++#define SET_HINFC504_PWIDTH(_w_lcnt, _r_lcnt, _rw_hcnt) \
++	((_w_lcnt) | (((_r_lcnt) & 0x0F) << 4) | (((_rw_hcnt) & 0x0F) << 8))
++
++#define HINFC504_CMD					0x0C
++#define HINFC504_ADDRL					0x10
++#define HINFC504_ADDRH					0x14
++#define HINFC504_DATA_NUM				0x18
++
++#define HINFC504_OP					0x1C
++#define HINFC504_OP_READ_DATA_EN			BIT(1)
++#define HINFC504_OP_WAIT_READY_EN			BIT(2)
++#define HINFC504_OP_CMD2_EN				BIT(3)
++#define HINFC504_OP_WRITE_DATA_EN			BIT(4)
++#define HINFC504_OP_ADDR_EN				BIT(5)
++#define HINFC504_OP_CMD1_EN				BIT(6)
++#define HINFC504_OP_NF_CS_SHIFT                         (7)
++#define HINFC504_OP_NF_CS_MASK				(3)
++#define HINFC504_OP_ADDR_CYCLE_SHIFT			(9)
++#define HINFC504_OP_ADDR_CYCLE_MASK			(7)
++
++#define HINFC504_STATUS                                 0x20
++#define HINFC504_READY					BIT(0)
++
++#define HINFC504_INTEN					0x24
++#define HINFC504_INTEN_DMA				BIT(9)
++#define HINFC504_INTEN_UE				BIT(6)
++#define HINFC504_INTEN_CE				BIT(5)
++
++#define HINFC504_INTS					0x28
++#define HINFC504_INTS_DMA				BIT(9)
++#define HINFC504_INTS_UE				BIT(6)
++#define HINFC504_INTS_CE				BIT(5)
++
++#define HINFC504_INTCLR                                 0x2C
++#define HINFC504_INTCLR_DMA				BIT(9)
++#define HINFC504_INTCLR_UE				BIT(6)
++#define HINFC504_INTCLR_CE				BIT(5)
++
++#define HINFC504_ECC_STATUS                             0x5C
++#define HINFC504_ECC_16_BIT_SHIFT                       12
++
++#define HINFC504_DMA_CTRL				0x60
++#define HINFC504_DMA_CTRL_DMA_START			BIT(0)
++#define HINFC504_DMA_CTRL_WE				BIT(1)
++#define HINFC504_DMA_CTRL_DATA_AREA_EN			BIT(2)
++#define HINFC504_DMA_CTRL_OOB_AREA_EN			BIT(3)
++#define HINFC504_DMA_CTRL_BURST4_EN			BIT(4)
++#define HINFC504_DMA_CTRL_BURST8_EN			BIT(5)
++#define HINFC504_DMA_CTRL_BURST16_EN			BIT(6)
++#define HINFC504_DMA_CTRL_ADDR_NUM_SHIFT		(7)
++#define HINFC504_DMA_CTRL_ADDR_NUM_MASK                 (1)
++#define HINFC504_DMA_CTRL_CS_SHIFT			(8)
++#define HINFC504_DMA_CTRL_CS_MASK			(0x03)
++
++#define HINFC504_DMA_ADDR_DATA				0x64
++#define HINFC504_DMA_ADDR_OOB				0x68
++
++#define HINFC504_DMA_LEN				0x6C
++#define HINFC504_DMA_LEN_OOB_SHIFT			(16)
++#define HINFC504_DMA_LEN_OOB_MASK			(0xFFF)
++
++#define HINFC504_DMA_PARA				0x70
++#define HINFC504_DMA_PARA_DATA_RW_EN			BIT(0)
++#define HINFC504_DMA_PARA_OOB_RW_EN			BIT(1)
++#define HINFC504_DMA_PARA_DATA_EDC_EN			BIT(2)
++#define HINFC504_DMA_PARA_OOB_EDC_EN			BIT(3)
++#define HINFC504_DMA_PARA_DATA_ECC_EN			BIT(4)
++#define HINFC504_DMA_PARA_OOB_ECC_EN			BIT(5)
++
++#define HINFC_VERSION                                   0x74
++#define HINFC504_LOG_READ_ADDR				0x7C
++#define HINFC504_LOG_READ_LEN				0x80
++
++#define HINFC504_NANDINFO_LEN				0x10
++
++struct hinfc_host {
++	struct nand_chip	chip;
++	struct device		*dev;
++	void __iomem		*iobase;
++	void __iomem		*mmio;
++	struct completion       cmd_complete;
++	unsigned int		offset;
++	unsigned int		command;
++	int			chipselect;
++	unsigned int		addr_cycle;
++	u32                     addr_value[2];
++	u32                     cache_addr_value[2];
++	char			*buffer;
++	dma_addr_t		dma_buffer;
++	dma_addr_t		dma_oob;
++	int			version;
++	unsigned int            irq_status; /* interrupt status */
++};
++
++static inline unsigned int hinfc_read(struct hinfc_host *host, unsigned int reg)
++{
++	return readl(host->iobase + reg);
++}
++
++static inline void hinfc_write(struct hinfc_host *host, unsigned int value,
++			       unsigned int reg)
++{
++	writel(value, host->iobase + reg);
++}
++
++static void wait_controller_finished(struct hinfc_host *host)
++{
++	unsigned long timeout = jiffies + HINFC504_NFC_TIMEOUT;
++	int val;
++
++	while (time_before(jiffies, timeout)) {
++		val = hinfc_read(host, HINFC504_STATUS);
++		if (host->command == NAND_CMD_ERASE2) {
++			/* nfc is ready */
++			while (!(val & HINFC504_READY))	{
++				usleep_range(500, 1000);
++				val = hinfc_read(host, HINFC504_STATUS);
++			}
++			return;
++		}
++
++		if (val & HINFC504_READY)
++			return;
++	}
++
++	/* wait cmd timeout */
++	dev_err(host->dev, "Wait NAND controller exec cmd timeout.\n");
++}
++
++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);
++	unsigned long val;
++	int ret;
++
++	hinfc_write(host, host->dma_buffer, HINFC504_DMA_ADDR_DATA);
++	hinfc_write(host, host->dma_oob, HINFC504_DMA_ADDR_OOB);
++
++	if (chip->ecc.mode == NAND_ECC_NONE) {
++		hinfc_write(host, ((mtd->oobsize & HINFC504_DMA_LEN_OOB_MASK)
++			<< HINFC504_DMA_LEN_OOB_SHIFT), HINFC504_DMA_LEN);
++
++		hinfc_write(host, HINFC504_DMA_PARA_DATA_RW_EN
++			| HINFC504_DMA_PARA_OOB_RW_EN, HINFC504_DMA_PARA);
++	} else {
++		if (host->command == NAND_CMD_READOOB)
++			hinfc_write(host, HINFC504_DMA_PARA_OOB_RW_EN
++			| HINFC504_DMA_PARA_OOB_EDC_EN
++			| HINFC504_DMA_PARA_OOB_ECC_EN, HINFC504_DMA_PARA);
++		else
++			hinfc_write(host, HINFC504_DMA_PARA_DATA_RW_EN
++			| HINFC504_DMA_PARA_OOB_RW_EN
++			| HINFC504_DMA_PARA_DATA_EDC_EN
++			| HINFC504_DMA_PARA_OOB_EDC_EN
++			| HINFC504_DMA_PARA_DATA_ECC_EN
++			| HINFC504_DMA_PARA_OOB_ECC_EN, HINFC504_DMA_PARA);
++
++	}
++
++	val = (HINFC504_DMA_CTRL_DMA_START | HINFC504_DMA_CTRL_BURST4_EN
++		| HINFC504_DMA_CTRL_BURST8_EN | HINFC504_DMA_CTRL_BURST16_EN
++		| HINFC504_DMA_CTRL_DATA_AREA_EN | HINFC504_DMA_CTRL_OOB_AREA_EN
++		| ((host->addr_cycle == 4 ? 1 : 0)
++			<< HINFC504_DMA_CTRL_ADDR_NUM_SHIFT)
++		| ((host->chipselect & HINFC504_DMA_CTRL_CS_MASK)
++			<< HINFC504_DMA_CTRL_CS_SHIFT));
++
++	if (todev)
++		val |= HINFC504_DMA_CTRL_WE;
++
++	init_completion(&host->cmd_complete);
++
++	hinfc_write(host, val, HINFC504_DMA_CTRL);
++	ret = wait_for_completion_timeout(&host->cmd_complete,
++			HINFC504_NFC_DMA_TIMEOUT);
++
++	if (!ret) {
++		dev_err(host->dev, "DMA operation(irq) timeout!\n");
++		/* sanity check */
++		val = hinfc_read(host, HINFC504_DMA_CTRL);
++		if (!(val & HINFC504_DMA_CTRL_DMA_START))
++			dev_err(host->dev, "DMA is already done but without irq ACK!\n");
++		else
++			dev_err(host->dev, "DMA is really timeout!\n");
++	}
++}
++
++static int hisi_nfc_send_cmd_pageprog(struct hinfc_host *host)
++{
++	host->addr_value[0] &= 0xffff0000;
++
++	hinfc_write(host, host->addr_value[0], HINFC504_ADDRL);
++	hinfc_write(host, host->addr_value[1], HINFC504_ADDRH);
++	hinfc_write(host, NAND_CMD_PAGEPROG << 8 | NAND_CMD_SEQIN,
++		    HINFC504_CMD);
++
++	hisi_nfc_dma_transfer(host, 1);
++
++	return 0;
++}
++
++static int hisi_nfc_send_cmd_readstart(struct hinfc_host *host)
++{
++	struct mtd_info	*mtd = nand_to_mtd(&host->chip);
++
++	if ((host->addr_value[0] == host->cache_addr_value[0]) &&
++	    (host->addr_value[1] == host->cache_addr_value[1]))
++		return 0;
++
++	host->addr_value[0] &= 0xffff0000;
++
++	hinfc_write(host, host->addr_value[0], HINFC504_ADDRL);
++	hinfc_write(host, host->addr_value[1], HINFC504_ADDRH);
++	hinfc_write(host, NAND_CMD_READSTART << 8 | NAND_CMD_READ0,
++		    HINFC504_CMD);
++
++	hinfc_write(host, 0, HINFC504_LOG_READ_ADDR);
++	hinfc_write(host, mtd->writesize + mtd->oobsize,
++		    HINFC504_LOG_READ_LEN);
++
++	hisi_nfc_dma_transfer(host, 0);
++
++	host->cache_addr_value[0] = host->addr_value[0];
++	host->cache_addr_value[1] = host->addr_value[1];
++
++	return 0;
++}
++
++static int hisi_nfc_send_cmd_erase(struct hinfc_host *host)
++{
++	hinfc_write(host, host->addr_value[0], HINFC504_ADDRL);
++	hinfc_write(host, (NAND_CMD_ERASE2 << 8) | NAND_CMD_ERASE1,
++		    HINFC504_CMD);
++
++	hinfc_write(host, HINFC504_OP_WAIT_READY_EN
++		| HINFC504_OP_CMD2_EN
++		| HINFC504_OP_CMD1_EN
++		| HINFC504_OP_ADDR_EN
++		| ((host->chipselect & HINFC504_OP_NF_CS_MASK)
++			<< HINFC504_OP_NF_CS_SHIFT)
++		| ((host->addr_cycle & HINFC504_OP_ADDR_CYCLE_MASK)
++			<< HINFC504_OP_ADDR_CYCLE_SHIFT),
++		HINFC504_OP);
++
++	wait_controller_finished(host);
++
++	return 0;
++}
++
++static int hisi_nfc_send_cmd_readid(struct hinfc_host *host)
++{
++	hinfc_write(host, HINFC504_NANDINFO_LEN, HINFC504_DATA_NUM);
++	hinfc_write(host, NAND_CMD_READID, HINFC504_CMD);
++	hinfc_write(host, 0, HINFC504_ADDRL);
++
++	hinfc_write(host, HINFC504_OP_CMD1_EN | HINFC504_OP_ADDR_EN
++		| HINFC504_OP_READ_DATA_EN
++		| ((host->chipselect & HINFC504_OP_NF_CS_MASK)
++			<< HINFC504_OP_NF_CS_SHIFT)
++		| 1 << HINFC504_OP_ADDR_CYCLE_SHIFT, HINFC504_OP);
++
++	wait_controller_finished(host);
++
++	return 0;
++}
++
++static int hisi_nfc_send_cmd_status(struct hinfc_host *host)
++{
++	hinfc_write(host, HINFC504_NANDINFO_LEN, HINFC504_DATA_NUM);
++	hinfc_write(host, NAND_CMD_STATUS, HINFC504_CMD);
++	hinfc_write(host, HINFC504_OP_CMD1_EN
++		| HINFC504_OP_READ_DATA_EN
++		| ((host->chipselect & HINFC504_OP_NF_CS_MASK)
++			<< HINFC504_OP_NF_CS_SHIFT),
++		HINFC504_OP);
++
++	wait_controller_finished(host);
++
++	return 0;
++}
++
++static int hisi_nfc_send_cmd_reset(struct hinfc_host *host, int chipselect)
++{
++	hinfc_write(host, NAND_CMD_RESET, HINFC504_CMD);
++
++	hinfc_write(host, HINFC504_OP_CMD1_EN
++		| ((chipselect & HINFC504_OP_NF_CS_MASK)
++			<< HINFC504_OP_NF_CS_SHIFT)
++		| HINFC504_OP_WAIT_READY_EN,
++		HINFC504_OP);
++
++	wait_controller_finished(host);
++
++	return 0;
++}
++
++static void hisi_nfc_select_chip(struct mtd_info *mtd, int chipselect)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct hinfc_host *host = nand_get_controller_data(chip);
++
++	if (chipselect < 0)
++		return;
++
++	host->chipselect = chipselect;
++}
++
++static uint8_t hisi_nfc_read_byte(struct mtd_info *mtd)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct hinfc_host *host = nand_get_controller_data(chip);
++
++	if (host->command == NAND_CMD_STATUS)
++		return *(uint8_t *)(host->mmio);
++
++	host->offset++;
++
++	if (host->command == NAND_CMD_READID)
++		return *(uint8_t *)(host->mmio + host->offset - 1);
++
++	return *(uint8_t *)(host->buffer + host->offset - 1);
++}
++
++static u16 hisi_nfc_read_word(struct mtd_info *mtd)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct hinfc_host *host = nand_get_controller_data(chip);
++
++	host->offset += 2;
++	return *(u16 *)(host->buffer + host->offset - 2);
++}
++
++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 hinfc_host *host = nand_get_controller_data(chip);
++
++	memcpy(host->buffer + host->offset, buf, len);
++	host->offset += 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 hinfc_host *host = nand_get_controller_data(chip);
++
++	memcpy(buf, host->buffer + host->offset, len);
++	host->offset += len;
++}
++
++static void set_addr(struct mtd_info *mtd, int column, int page_addr)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct hinfc_host *host = nand_get_controller_data(chip);
++	unsigned int command = host->command;
++
++	host->addr_cycle    = 0;
++	host->addr_value[0] = 0;
++	host->addr_value[1] = 0;
++
++	/* Serially input address */
++	if (column != -1) {
++		/* Adjust columns for 16 bit buswidth */
++		if (chip->options & NAND_BUSWIDTH_16 &&
++				!nand_opcode_8bits(command))
++			column >>= 1;
++
++		host->addr_value[0] = column & 0xffff;
++		host->addr_cycle    = 2;
++	}
++	if (page_addr != -1) {
++		host->addr_value[0] |= (page_addr & 0xffff)
++			<< (host->addr_cycle * 8);
++		host->addr_cycle    += 2;
++		/* One more address cycle for devices > 128MiB */
++		if (chip->chipsize > (128 << 20)) {
++			host->addr_cycle += 1;
++			if (host->command == NAND_CMD_ERASE1)
++				host->addr_value[0] |= ((page_addr >> 16) & 0xff) << 16;
++			else
++				host->addr_value[1] |= ((page_addr >> 16) & 0xff);
++		}
++	}
++}
++
++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 hinfc_host *host = nand_get_controller_data(chip);
++	int is_cache_invalid = 1;
++	unsigned int flag = 0;
++
++	host->command =  command;
++
++	switch (command) {
++	case NAND_CMD_READ0:
++	case NAND_CMD_READOOB:
++		if (command == NAND_CMD_READ0)
++			host->offset = column;
++		else
++			host->offset = column + mtd->writesize;
++
++		is_cache_invalid = 0;
++		set_addr(mtd, column, page_addr);
++		hisi_nfc_send_cmd_readstart(host);
++		break;
++
++	case NAND_CMD_SEQIN:
++		host->offset = column;
++		set_addr(mtd, column, page_addr);
++		break;
++
++	case NAND_CMD_ERASE1:
++		set_addr(mtd, column, page_addr);
++		break;
++
++	case NAND_CMD_PAGEPROG:
++		hisi_nfc_send_cmd_pageprog(host);
++		break;
++
++	case NAND_CMD_ERASE2:
++		hisi_nfc_send_cmd_erase(host);
++		break;
++
++	case NAND_CMD_READID:
++		host->offset = column;
++		memset(host->mmio, 0, 0x10);
++		hisi_nfc_send_cmd_readid(host);
++		break;
++
++	case NAND_CMD_STATUS:
++		flag = hinfc_read(host, HINFC504_CON);
++		if (chip->ecc.mode == NAND_ECC_HW)
++			hinfc_write(host,
++				    flag & ~(HINFC504_CON_ECCTYPE_MASK <<
++				    HINFC504_CON_ECCTYPE_SHIFT), HINFC504_CON);
++
++		host->offset = 0;
++		memset(host->mmio, 0, 0x10);
++		hisi_nfc_send_cmd_status(host);
++		hinfc_write(host, flag, HINFC504_CON);
++		break;
++
++	case NAND_CMD_RESET:
++		hisi_nfc_send_cmd_reset(host, host->chipselect);
++		break;
++
++	default:
++		dev_err(host->dev, "Error: unsupported cmd(cmd=%x, col=%x, page=%x)\n",
++			command, column, page_addr);
++	}
++
++	if (is_cache_invalid) {
++		host->cache_addr_value[0] = ~0;
++		host->cache_addr_value[1] = ~0;
++	}
++}
++
++static irqreturn_t hinfc_irq_handle(int irq, void *devid)
++{
++	struct hinfc_host *host = devid;
++	unsigned int flag;
++
++	flag = hinfc_read(host, HINFC504_INTS);
++	/* store interrupts state */
++	host->irq_status |= flag;
++
++	if (flag & HINFC504_INTS_DMA) {
++		hinfc_write(host, HINFC504_INTCLR_DMA, HINFC504_INTCLR);
++		complete(&host->cmd_complete);
++	} else if (flag & HINFC504_INTS_CE) {
++		hinfc_write(host, HINFC504_INTCLR_CE, HINFC504_INTCLR);
++	} else if (flag & HINFC504_INTS_UE) {
++		hinfc_write(host, HINFC504_INTCLR_UE, HINFC504_INTCLR);
++	}
++
++	return IRQ_HANDLED;
++}
++
++static int hisi_nand_read_page_hwecc(struct mtd_info *mtd,
++	struct nand_chip *chip, uint8_t *buf, int oob_required, int page)
++{
++	struct hinfc_host *host = nand_get_controller_data(chip);
++	int max_bitflips = 0, stat = 0, stat_max = 0, status_ecc;
++	int stat_1, stat_2;
++
++	chip->read_buf(mtd, buf, mtd->writesize);
++	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
++
++	/* errors which can not be corrected by ECC */
++	if (host->irq_status & HINFC504_INTS_UE) {
++		mtd->ecc_stats.failed++;
++	} else if (host->irq_status & HINFC504_INTS_CE) {
++		/* TODO: need add other ECC modes! */
++		switch (chip->ecc.strength) {
++		case 16:
++			status_ecc = hinfc_read(host, HINFC504_ECC_STATUS) >>
++					HINFC504_ECC_16_BIT_SHIFT & 0x0fff;
++			stat_2 = status_ecc & 0x3f;
++			stat_1 = status_ecc >> 6 & 0x3f;
++			stat = stat_1 + stat_2;
++			stat_max = max_t(int, stat_1, stat_2);
++		}
++		mtd->ecc_stats.corrected += stat;
++		max_bitflips = max_t(int, max_bitflips, stat_max);
++	}
++	host->irq_status = 0;
++
++	return max_bitflips;
++}
++
++static int hisi_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
++				int page)
++{
++	struct hinfc_host *host = nand_get_controller_data(chip);
++
++	chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
++	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
++
++	if (host->irq_status & HINFC504_INTS_UE) {
++		host->irq_status = 0;
++		return -EBADMSG;
++	}
++
++	host->irq_status = 0;
++	return 0;
++}
++
++static int hisi_nand_write_page_hwecc(struct mtd_info *mtd,
++		struct nand_chip *chip, const uint8_t *buf, int oob_required,
++		int page)
++{
++	chip->write_buf(mtd, buf, mtd->writesize);
++	if (oob_required)
++		chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
++
++	return 0;
++}
++
++static void hisi_nfc_host_init(struct hinfc_host *host)
++{
++	struct nand_chip *chip = &host->chip;
++	unsigned int flag = 0;
++
++	host->version = hinfc_read(host, HINFC_VERSION);
++	host->addr_cycle		= 0;
++	host->addr_value[0]		= 0;
++	host->addr_value[1]		= 0;
++	host->cache_addr_value[0]	= ~0;
++	host->cache_addr_value[1]	= ~0;
++	host->chipselect		= 0;
++
++	/* default page size: 2K, ecc_none. need modify */
++	flag = HINFC504_CON_OP_MODE_NORMAL | HINFC504_CON_READY_BUSY_SEL
++		| ((0x001 & HINFC504_CON_PAGESIZE_MASK)
++			<< HINFC504_CON_PAGEISZE_SHIFT)
++		| ((0x0 & HINFC504_CON_ECCTYPE_MASK)
++			<< HINFC504_CON_ECCTYPE_SHIFT)
++		| ((chip->options & NAND_BUSWIDTH_16) ?
++			HINFC504_CON_BUS_WIDTH : 0);
++	hinfc_write(host, flag, HINFC504_CON);
++
++	memset(host->mmio, 0xff, HINFC504_BUFFER_BASE_ADDRESS_LEN);
++
++	hinfc_write(host, SET_HINFC504_PWIDTH(HINFC504_W_LATCH,
++		    HINFC504_R_LATCH, HINFC504_RW_LATCH), HINFC504_PWIDTH);
++
++	/* enable DMA irq */
++	hinfc_write(host, HINFC504_INTEN_DMA, HINFC504_INTEN);
++}
++
++static int hisi_ooblayout_ecc(struct mtd_info *mtd, int section,
++			      struct mtd_oob_region *oobregion)
++{
++	/* FIXME: add ECC bytes position */
++	return -ENOTSUPP;
++}
++
++static int hisi_ooblayout_free(struct mtd_info *mtd, int section,
++			       struct mtd_oob_region *oobregion)
++{
++	if (section)
++		return -ERANGE;
++
++	oobregion->offset = 2;
++	oobregion->length = 6;
++
++	return 0;
++}
++
++static const struct mtd_ooblayout_ops hisi_ooblayout_ops = {
++	.ecc = hisi_ooblayout_ecc,
++	.free = hisi_ooblayout_free,
++};
++
++static int hisi_nfc_ecc_probe(struct hinfc_host *host)
++{
++	unsigned int flag;
++	int size, strength, ecc_bits;
++	struct device *dev = host->dev;
++	struct nand_chip *chip = &host->chip;
++	struct mtd_info *mtd = nand_to_mtd(chip);
++
++	size = chip->ecc.size;
++	strength = chip->ecc.strength;
++	if (size != 1024) {
++		dev_err(dev, "error ecc size: %d\n", size);
++		return -EINVAL;
++	}
++
++	if ((size == 1024) && ((strength != 8) && (strength != 16) &&
++				(strength != 24) && (strength != 40))) {
++		dev_err(dev, "ecc size and strength do not match\n");
++		return -EINVAL;
++	}
++
++	chip->ecc.size = size;
++	chip->ecc.strength = strength;
++
++	chip->ecc.read_page = hisi_nand_read_page_hwecc;
++	chip->ecc.read_oob = hisi_nand_read_oob;
++	chip->ecc.write_page = hisi_nand_write_page_hwecc;
++
++	switch (chip->ecc.strength) {
++	case 16:
++		ecc_bits = 6;
++		if (mtd->writesize == 2048)
++			mtd_set_ooblayout(mtd, &hisi_ooblayout_ops);
++
++		/* TODO: add more page size support */
++		break;
++
++	/* TODO: add more ecc strength support */
++	default:
++		dev_err(dev, "not support strength: %d\n", chip->ecc.strength);
++		return -EINVAL;
++	}
++
++	flag = hinfc_read(host, HINFC504_CON);
++	/* add ecc type configure */
++	flag |= ((ecc_bits & HINFC504_CON_ECCTYPE_MASK)
++						<< HINFC504_CON_ECCTYPE_SHIFT);
++	hinfc_write(host, flag, HINFC504_CON);
++
++	/* enable ecc irq */
++	flag = hinfc_read(host, HINFC504_INTEN) & 0xfff;
++	hinfc_write(host, flag | HINFC504_INTEN_UE | HINFC504_INTEN_CE,
++		    HINFC504_INTEN);
++
++	return 0;
++}
++
++static int hisi_nfc_probe(struct platform_device *pdev)
++{
++	int ret = 0, irq, flag, max_chips = HINFC504_MAX_CHIP;
++	struct device *dev = &pdev->dev;
++	struct hinfc_host *host;
++	struct nand_chip  *chip;
++	struct mtd_info   *mtd;
++	struct resource	  *res;
++	struct device_node *np = dev->of_node;
++
++	host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL);
++	if (!host)
++		return -ENOMEM;
++	host->dev = dev;
++
++	platform_set_drvdata(pdev, host);
++	chip = &host->chip;
++	mtd  = nand_to_mtd(chip);
++
++	irq = platform_get_irq(pdev, 0);
++	if (irq < 0) {
++		dev_err(dev, "no IRQ resource defined\n");
++		ret = -ENXIO;
++		goto err_res;
++	}
++
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	host->iobase = devm_ioremap_resource(dev, res);
++	if (IS_ERR(host->iobase)) {
++		ret = PTR_ERR(host->iobase);
++		goto err_res;
++	}
++
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
++	host->mmio = devm_ioremap_resource(dev, res);
++	if (IS_ERR(host->mmio)) {
++		ret = PTR_ERR(host->mmio);
++		dev_err(dev, "devm_ioremap_resource[1] fail\n");
++		goto err_res;
++	}
++
++	mtd->name		= "hisi_nand";
++	mtd->dev.parent         = &pdev->dev;
++
++	nand_set_controller_data(chip, host);
++	nand_set_flash_node(chip, np);
++	chip->cmdfunc		= hisi_nfc_cmdfunc;
++	chip->select_chip	= hisi_nfc_select_chip;
++	chip->read_byte		= hisi_nfc_read_byte;
++	chip->read_word		= hisi_nfc_read_word;
++	chip->write_buf		= hisi_nfc_write_buf;
++	chip->read_buf		= hisi_nfc_read_buf;
++	chip->chip_delay	= HINFC504_CHIP_DELAY;
++	chip->onfi_set_features	= nand_onfi_get_set_features_notsupp;
++	chip->onfi_get_features	= nand_onfi_get_set_features_notsupp;
++
++	hisi_nfc_host_init(host);
++
++	ret = devm_request_irq(dev, irq, hinfc_irq_handle, 0x0, "nandc", host);
++	if (ret) {
++		dev_err(dev, "failed to request IRQ\n");
++		goto err_res;
++	}
++
++	ret = nand_scan_ident(mtd, max_chips, NULL);
++	if (ret)
++		goto err_res;
++
++	host->buffer = dmam_alloc_coherent(dev, mtd->writesize + mtd->oobsize,
++		&host->dma_buffer, GFP_KERNEL);
++	if (!host->buffer) {
++		ret = -ENOMEM;
++		goto err_res;
++	}
++
++	host->dma_oob = host->dma_buffer + mtd->writesize;
++	memset(host->buffer, 0xff, mtd->writesize + mtd->oobsize);
++
++	flag = hinfc_read(host, HINFC504_CON);
++	flag &= ~(HINFC504_CON_PAGESIZE_MASK << HINFC504_CON_PAGEISZE_SHIFT);
++	switch (mtd->writesize) {
++	case 2048:
++		flag |= (0x001 << HINFC504_CON_PAGEISZE_SHIFT); break;
++	/*
++	 * TODO: add more pagesize support,
++	 * default pagesize has been set in hisi_nfc_host_init
++	 */
++	default:
++		dev_err(dev, "NON-2KB page size nand flash\n");
++		ret = -EINVAL;
++		goto err_res;
++	}
++	hinfc_write(host, flag, HINFC504_CON);
++
++	if (chip->ecc.mode == NAND_ECC_HW)
++		hisi_nfc_ecc_probe(host);
++
++	ret = nand_scan_tail(mtd);
++	if (ret) {
++		dev_err(dev, "nand_scan_tail failed: %d\n", ret);
++		goto err_res;
++	}
++
++	ret = mtd_device_register(mtd, NULL, 0);
++	if (ret) {
++		dev_err(dev, "Err MTD partition=%d\n", ret);
++		goto err_mtd;
++	}
++
++	return 0;
++
++err_mtd:
++	nand_release(mtd);
++err_res:
++	return ret;
++}
++
++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);
++
++	nand_release(mtd);
++
++	return 0;
++}
++
++#ifdef CONFIG_PM_SLEEP
++static int hisi_nfc_suspend(struct device *dev)
++{
++	struct hinfc_host *host = dev_get_drvdata(dev);
++	unsigned long timeout = jiffies + HINFC504_NFC_PM_TIMEOUT;
++
++	while (time_before(jiffies, timeout)) {
++		if (((hinfc_read(host, HINFC504_STATUS) & 0x1) == 0x0) &&
++		    (hinfc_read(host, HINFC504_DMA_CTRL) &
++		     HINFC504_DMA_CTRL_DMA_START)) {
++			cond_resched();
++			return 0;
++		}
++	}
++
++	dev_err(host->dev, "nand controller suspend timeout.\n");
++
++	return -EAGAIN;
++}
++
++static int hisi_nfc_resume(struct device *dev)
++{
++	int cs;
++	struct hinfc_host *host = dev_get_drvdata(dev);
++	struct nand_chip *chip = &host->chip;
++
++	for (cs = 0; cs < chip->numchips; cs++)
++		hisi_nfc_send_cmd_reset(host, cs);
++	hinfc_write(host, SET_HINFC504_PWIDTH(HINFC504_W_LATCH,
++		    HINFC504_R_LATCH, HINFC504_RW_LATCH), HINFC504_PWIDTH);
++
++	return 0;
++}
++#endif
++static SIMPLE_DEV_PM_OPS(hisi_nfc_pm_ops, hisi_nfc_suspend, hisi_nfc_resume);
++
++static const struct of_device_id nfc_id_table[] = {
++	{ .compatible = "hisilicon,504-nfc" },
++	{}
++};
++MODULE_DEVICE_TABLE(of, nfc_id_table);
++
++static struct platform_driver hisi_nfc_driver = {
++	.driver = {
++		.name  = "hisi_nand",
++		.of_match_table = nfc_id_table,
++		.pm = &hisi_nfc_pm_ops,
++	},
++	.probe		= hisi_nfc_probe,
++	.remove		= hisi_nfc_remove,
++};
++
++module_platform_driver(hisi_nfc_driver);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Zhou Wang");
++MODULE_AUTHOR("Zhiyong Cai");
++MODULE_DESCRIPTION("Hisilicon Nand Flash Controller Driver");
+diff --git a/drivers/mtd/nand/raw/jz4740_nand.c b/drivers/mtd/nand/raw/jz4740_nand.c
+new file mode 100644
+index 0000000..ad827d4
+--- /dev/null
++++ b/drivers/mtd/nand/raw/jz4740_nand.c
+@@ -0,0 +1,536 @@
++/*
++ *  Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
++ *  JZ4740 SoC NAND controller driver
++ *
++ *  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.
++ *
++ *  You should have received a copy of the GNU General Public License along
++ *  with this program; if not, write to the Free Software Foundation, Inc.,
++ *  675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++#include <linux/ioport.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/slab.h>
++
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/rawnand.h>
++#include <linux/mtd/partitions.h>
++
++#include <linux/gpio.h>
++
++#include <asm/mach-jz4740/jz4740_nand.h>
++
++#define JZ_REG_NAND_CTRL	0x50
++#define JZ_REG_NAND_ECC_CTRL	0x100
++#define JZ_REG_NAND_DATA	0x104
++#define JZ_REG_NAND_PAR0	0x108
++#define JZ_REG_NAND_PAR1	0x10C
++#define JZ_REG_NAND_PAR2	0x110
++#define JZ_REG_NAND_IRQ_STAT	0x114
++#define JZ_REG_NAND_IRQ_CTRL	0x118
++#define JZ_REG_NAND_ERR(x)	(0x11C + ((x) << 2))
++
++#define JZ_NAND_ECC_CTRL_PAR_READY	BIT(4)
++#define JZ_NAND_ECC_CTRL_ENCODING	BIT(3)
++#define JZ_NAND_ECC_CTRL_RS		BIT(2)
++#define JZ_NAND_ECC_CTRL_RESET		BIT(1)
++#define JZ_NAND_ECC_CTRL_ENABLE		BIT(0)
++
++#define JZ_NAND_STATUS_ERR_COUNT	(BIT(31) | BIT(30) | BIT(29))
++#define JZ_NAND_STATUS_PAD_FINISH	BIT(4)
++#define JZ_NAND_STATUS_DEC_FINISH	BIT(3)
++#define JZ_NAND_STATUS_ENC_FINISH	BIT(2)
++#define JZ_NAND_STATUS_UNCOR_ERROR	BIT(1)
++#define JZ_NAND_STATUS_ERROR		BIT(0)
++
++#define JZ_NAND_CTRL_ENABLE_CHIP(x) BIT((x) << 1)
++#define JZ_NAND_CTRL_ASSERT_CHIP(x) BIT(((x) << 1) + 1)
++#define JZ_NAND_CTRL_ASSERT_CHIP_MASK 0xaa
++
++#define JZ_NAND_MEM_CMD_OFFSET 0x08000
++#define JZ_NAND_MEM_ADDR_OFFSET 0x10000
++
++struct jz_nand {
++	struct nand_chip chip;
++	void __iomem *base;
++	struct resource *mem;
++
++	unsigned char banks[JZ_NAND_NUM_BANKS];
++	void __iomem *bank_base[JZ_NAND_NUM_BANKS];
++	struct resource *bank_mem[JZ_NAND_NUM_BANKS];
++
++	int selected_bank;
++
++	struct gpio_desc *busy_gpio;
++	bool is_reading;
++};
++
++static inline struct jz_nand *mtd_to_jz_nand(struct mtd_info *mtd)
++{
++	return container_of(mtd_to_nand(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);
++	uint32_t ctrl;
++	int banknr;
++
++	ctrl = readl(nand->base + JZ_REG_NAND_CTRL);
++	ctrl &= ~JZ_NAND_CTRL_ASSERT_CHIP_MASK;
++
++	if (chipnr == -1) {
++		banknr = -1;
++	} else {
++		banknr = nand->banks[chipnr] - 1;
++		chip->IO_ADDR_R = nand->bank_base[banknr];
++		chip->IO_ADDR_W = nand->bank_base[banknr];
++	}
++	writel(ctrl, nand->base + JZ_REG_NAND_CTRL);
++
++	nand->selected_bank = banknr;
++}
++
++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);
++	uint32_t reg;
++	void __iomem *bank_base = nand->bank_base[nand->selected_bank];
++
++	BUG_ON(nand->selected_bank < 0);
++
++	if (ctrl & NAND_CTRL_CHANGE) {
++		BUG_ON((ctrl & NAND_ALE) && (ctrl & NAND_CLE));
++		if (ctrl & NAND_ALE)
++			bank_base += JZ_NAND_MEM_ADDR_OFFSET;
++		else if (ctrl & NAND_CLE)
++			bank_base += JZ_NAND_MEM_CMD_OFFSET;
++		chip->IO_ADDR_W = bank_base;
++
++		reg = readl(nand->base + JZ_REG_NAND_CTRL);
++		if (ctrl & NAND_NCE)
++			reg |= JZ_NAND_CTRL_ASSERT_CHIP(nand->selected_bank);
++		else
++			reg &= ~JZ_NAND_CTRL_ASSERT_CHIP(nand->selected_bank);
++		writel(reg, nand->base + JZ_REG_NAND_CTRL);
++	}
++	if (dat != NAND_CMD_NONE)
++		writeb(dat, chip->IO_ADDR_W);
++}
++
++static int jz_nand_dev_ready(struct mtd_info *mtd)
++{
++	struct jz_nand *nand = mtd_to_jz_nand(mtd);
++	return gpiod_get_value_cansleep(nand->busy_gpio);
++}
++
++static void jz_nand_hwctl(struct mtd_info *mtd, int mode)
++{
++	struct jz_nand *nand = mtd_to_jz_nand(mtd);
++	uint32_t reg;
++
++	writel(0, nand->base + JZ_REG_NAND_IRQ_STAT);
++	reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL);
++
++	reg |= JZ_NAND_ECC_CTRL_RESET;
++	reg |= JZ_NAND_ECC_CTRL_ENABLE;
++	reg |= JZ_NAND_ECC_CTRL_RS;
++
++	switch (mode) {
++	case NAND_ECC_READ:
++		reg &= ~JZ_NAND_ECC_CTRL_ENCODING;
++		nand->is_reading = true;
++		break;
++	case NAND_ECC_WRITE:
++		reg |= JZ_NAND_ECC_CTRL_ENCODING;
++		nand->is_reading = false;
++		break;
++	default:
++		break;
++	}
++
++	writel(reg, nand->base + JZ_REG_NAND_ECC_CTRL);
++}
++
++static int jz_nand_calculate_ecc_rs(struct mtd_info *mtd, const uint8_t *dat,
++	uint8_t *ecc_code)
++{
++	struct jz_nand *nand = mtd_to_jz_nand(mtd);
++	uint32_t reg, status;
++	int i;
++	unsigned int timeout = 1000;
++	static uint8_t empty_block_ecc[] = {0xcd, 0x9d, 0x90, 0x58, 0xf4,
++						0x8b, 0xff, 0xb7, 0x6f};
++
++	if (nand->is_reading)
++		return 0;
++
++	do {
++		status = readl(nand->base + JZ_REG_NAND_IRQ_STAT);
++	} while (!(status & JZ_NAND_STATUS_ENC_FINISH) && --timeout);
++
++	if (timeout == 0)
++	    return -1;
++
++	reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL);
++	reg &= ~JZ_NAND_ECC_CTRL_ENABLE;
++	writel(reg, nand->base + JZ_REG_NAND_ECC_CTRL);
++
++	for (i = 0; i < 9; ++i)
++		ecc_code[i] = readb(nand->base + JZ_REG_NAND_PAR0 + i);
++
++	/* If the written data is completly 0xff, we also want to write 0xff as
++	 * ecc, otherwise we will get in trouble when doing subpage writes. */
++	if (memcmp(ecc_code, empty_block_ecc, 9) == 0)
++		memset(ecc_code, 0xff, 9);
++
++	return 0;
++}
++
++static void jz_nand_correct_data(uint8_t *dat, int index, int mask)
++{
++	int offset = index & 0x7;
++	uint16_t data;
++
++	index += (index >> 3);
++
++	data = dat[index];
++	data |= dat[index+1] << 8;
++
++	mask ^= (data >> offset) & 0x1ff;
++	data &= ~(0x1ff << offset);
++	data |= (mask << offset);
++
++	dat[index] = data & 0xff;
++	dat[index+1] = (data >> 8) & 0xff;
++}
++
++static int jz_nand_correct_ecc_rs(struct mtd_info *mtd, uint8_t *dat,
++	uint8_t *read_ecc, uint8_t *calc_ecc)
++{
++	struct jz_nand *nand = mtd_to_jz_nand(mtd);
++	int i, error_count, index;
++	uint32_t reg, status, error;
++	unsigned int timeout = 1000;
++
++	for (i = 0; i < 9; ++i)
++		writeb(read_ecc[i], nand->base + JZ_REG_NAND_PAR0 + i);
++
++	reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL);
++	reg |= JZ_NAND_ECC_CTRL_PAR_READY;
++	writel(reg, nand->base + JZ_REG_NAND_ECC_CTRL);
++
++	do {
++		status = readl(nand->base + JZ_REG_NAND_IRQ_STAT);
++	} while (!(status & JZ_NAND_STATUS_DEC_FINISH) && --timeout);
++
++	if (timeout == 0)
++		return -ETIMEDOUT;
++
++	reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL);
++	reg &= ~JZ_NAND_ECC_CTRL_ENABLE;
++	writel(reg, nand->base + JZ_REG_NAND_ECC_CTRL);
++
++	if (status & JZ_NAND_STATUS_ERROR) {
++		if (status & JZ_NAND_STATUS_UNCOR_ERROR)
++			return -EBADMSG;
++
++		error_count = (status & JZ_NAND_STATUS_ERR_COUNT) >> 29;
++
++		for (i = 0; i < error_count; ++i) {
++			error = readl(nand->base + JZ_REG_NAND_ERR(i));
++			index = ((error >> 16) & 0x1ff) - 1;
++			if (index >= 0 && index < 512)
++				jz_nand_correct_data(dat, index, error & 0x1ff);
++		}
++
++		return error_count;
++	}
++
++	return 0;
++}
++
++static int jz_nand_ioremap_resource(struct platform_device *pdev,
++	const char *name, struct resource **res, void *__iomem *base)
++{
++	int ret;
++
++	*res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
++	if (!*res) {
++		dev_err(&pdev->dev, "Failed to get platform %s memory\n", name);
++		ret = -ENXIO;
++		goto err;
++	}
++
++	*res = request_mem_region((*res)->start, resource_size(*res),
++				pdev->name);
++	if (!*res) {
++		dev_err(&pdev->dev, "Failed to request %s memory region\n", name);
++		ret = -EBUSY;
++		goto err;
++	}
++
++	*base = ioremap((*res)->start, resource_size(*res));
++	if (!*base) {
++		dev_err(&pdev->dev, "Failed to ioremap %s memory region\n", name);
++		ret = -EBUSY;
++		goto err_release_mem;
++	}
++
++	return 0;
++
++err_release_mem:
++	release_mem_region((*res)->start, resource_size(*res));
++err:
++	*res = NULL;
++	*base = NULL;
++	return ret;
++}
++
++static inline void jz_nand_iounmap_resource(struct resource *res,
++					    void __iomem *base)
++{
++	iounmap(base);
++	release_mem_region(res->start, resource_size(res));
++}
++
++static int jz_nand_detect_bank(struct platform_device *pdev,
++			       struct jz_nand *nand, unsigned char bank,
++			       size_t chipnr, uint8_t *nand_maf_id,
++			       uint8_t *nand_dev_id)
++{
++	int ret;
++	char res_name[6];
++	uint32_t ctrl;
++	struct nand_chip *chip = &nand->chip;
++	struct mtd_info *mtd = nand_to_mtd(chip);
++
++	/* Request I/O resource. */
++	sprintf(res_name, "bank%d", bank);
++	ret = jz_nand_ioremap_resource(pdev, res_name,
++					&nand->bank_mem[bank - 1],
++					&nand->bank_base[bank - 1]);
++	if (ret)
++		return ret;
++
++	/* Enable chip in bank. */
++	ctrl = readl(nand->base + JZ_REG_NAND_CTRL);
++	ctrl |= JZ_NAND_CTRL_ENABLE_CHIP(bank - 1);
++	writel(ctrl, nand->base + JZ_REG_NAND_CTRL);
++
++	if (chipnr == 0) {
++		/* Detect first chip. */
++		ret = nand_scan_ident(mtd, 1, NULL);
++		if (ret)
++			goto notfound_id;
++
++		/* Retrieve the IDs from the first chip. */
++		chip->select_chip(mtd, 0);
++		chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
++		chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
++		*nand_maf_id = chip->read_byte(mtd);
++		*nand_dev_id = chip->read_byte(mtd);
++	} else {
++		/* Detect additional chip. */
++		chip->select_chip(mtd, chipnr);
++		chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
++		chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
++		if (*nand_maf_id != chip->read_byte(mtd)
++		 || *nand_dev_id != chip->read_byte(mtd)) {
++			ret = -ENODEV;
++			goto notfound_id;
++		}
++
++		/* Update size of the MTD. */
++		chip->numchips++;
++		mtd->size += chip->chipsize;
++	}
++
++	dev_info(&pdev->dev, "Found chip %i on bank %i\n", chipnr, bank);
++	return 0;
++
++notfound_id:
++	dev_info(&pdev->dev, "No chip found on bank %i\n", bank);
++	ctrl &= ~(JZ_NAND_CTRL_ENABLE_CHIP(bank - 1));
++	writel(ctrl, nand->base + JZ_REG_NAND_CTRL);
++	jz_nand_iounmap_resource(nand->bank_mem[bank - 1],
++				 nand->bank_base[bank - 1]);
++	return ret;
++}
++
++static int jz_nand_probe(struct platform_device *pdev)
++{
++	int ret;
++	struct jz_nand *nand;
++	struct nand_chip *chip;
++	struct mtd_info *mtd;
++	struct jz_nand_platform_data *pdata = dev_get_platdata(&pdev->dev);
++	size_t chipnr, bank_idx;
++	uint8_t nand_maf_id = 0, nand_dev_id = 0;
++
++	nand = kzalloc(sizeof(*nand), GFP_KERNEL);
++	if (!nand)
++		return -ENOMEM;
++
++	ret = jz_nand_ioremap_resource(pdev, "mmio", &nand->mem, &nand->base);
++	if (ret)
++		goto err_free;
++
++	nand->busy_gpio = devm_gpiod_get_optional(&pdev->dev, "busy", GPIOD_IN);
++	if (IS_ERR(nand->busy_gpio)) {
++		ret = PTR_ERR(nand->busy_gpio);
++		dev_err(&pdev->dev, "Failed to request busy gpio %d\n",
++		    ret);
++		goto err_iounmap_mmio;
++	}
++
++	chip		= &nand->chip;
++	mtd		= nand_to_mtd(chip);
++	mtd->dev.parent = &pdev->dev;
++	mtd->name	= "jz4740-nand";
++
++	chip->ecc.hwctl		= jz_nand_hwctl;
++	chip->ecc.calculate	= jz_nand_calculate_ecc_rs;
++	chip->ecc.correct	= jz_nand_correct_ecc_rs;
++	chip->ecc.mode		= NAND_ECC_HW_OOB_FIRST;
++	chip->ecc.size		= 512;
++	chip->ecc.bytes		= 9;
++	chip->ecc.strength	= 4;
++	chip->ecc.options	= NAND_ECC_GENERIC_ERASED_CHECK;
++
++	chip->chip_delay = 50;
++	chip->cmd_ctrl = jz_nand_cmd_ctrl;
++	chip->select_chip = jz_nand_select_chip;
++
++	if (nand->busy_gpio)
++		chip->dev_ready = jz_nand_dev_ready;
++
++	platform_set_drvdata(pdev, nand);
++
++	/* We are going to autodetect NAND chips in the banks specified in the
++	 * platform data. Although nand_scan_ident() can detect multiple chips,
++	 * it requires those chips to be numbered consecuitively, which is not
++	 * always the case for external memory banks. And a fixed chip-to-bank
++	 * mapping is not practical either, since for example Dingoo units
++	 * produced at different times have NAND chips in different banks.
++	 */
++	chipnr = 0;
++	for (bank_idx = 0; bank_idx < JZ_NAND_NUM_BANKS; bank_idx++) {
++		unsigned char bank;
++
++		/* If there is no platform data, look for NAND in bank 1,
++		 * which is the most likely bank since it is the only one
++		 * that can be booted from.
++		 */
++		bank = pdata ? pdata->banks[bank_idx] : bank_idx ^ 1;
++		if (bank == 0)
++			break;
++		if (bank > JZ_NAND_NUM_BANKS) {
++			dev_warn(&pdev->dev,
++				"Skipping non-existing bank: %d\n", bank);
++			continue;
++		}
++		/* The detection routine will directly or indirectly call
++		 * jz_nand_select_chip(), so nand->banks has to contain the
++		 * bank we're checking.
++		 */
++		nand->banks[chipnr] = bank;
++		if (jz_nand_detect_bank(pdev, nand, bank, chipnr,
++					&nand_maf_id, &nand_dev_id) == 0)
++			chipnr++;
++		else
++			nand->banks[chipnr] = 0;
++	}
++	if (chipnr == 0) {
++		dev_err(&pdev->dev, "No NAND chips found\n");
++		goto err_iounmap_mmio;
++	}
++
++	if (pdata && pdata->ident_callback) {
++		pdata->ident_callback(pdev, mtd, &pdata->partitions,
++					&pdata->num_partitions);
++	}
++
++	ret = nand_scan_tail(mtd);
++	if (ret) {
++		dev_err(&pdev->dev,  "Failed to scan NAND\n");
++		goto err_unclaim_banks;
++	}
++
++	ret = mtd_device_parse_register(mtd, NULL, NULL,
++					pdata ? pdata->partitions : NULL,
++					pdata ? pdata->num_partitions : 0);
++
++	if (ret) {
++		dev_err(&pdev->dev, "Failed to add mtd device\n");
++		goto err_nand_release;
++	}
++
++	dev_info(&pdev->dev, "Successfully registered JZ4740 NAND driver\n");
++
++	return 0;
++
++err_nand_release:
++	nand_release(mtd);
++err_unclaim_banks:
++	while (chipnr--) {
++		unsigned char bank = nand->banks[chipnr];
++		jz_nand_iounmap_resource(nand->bank_mem[bank - 1],
++					 nand->bank_base[bank - 1]);
++	}
++	writel(0, nand->base + JZ_REG_NAND_CTRL);
++err_iounmap_mmio:
++	jz_nand_iounmap_resource(nand->mem, nand->base);
++err_free:
++	kfree(nand);
++	return ret;
++}
++
++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));
++
++	/* Deassert and disable all chips */
++	writel(0, nand->base + JZ_REG_NAND_CTRL);
++
++	for (i = 0; i < JZ_NAND_NUM_BANKS; ++i) {
++		unsigned char bank = nand->banks[i];
++		if (bank != 0) {
++			jz_nand_iounmap_resource(nand->bank_mem[bank - 1],
++						 nand->bank_base[bank - 1]);
++		}
++	}
++
++	jz_nand_iounmap_resource(nand->mem, nand->base);
++
++	kfree(nand);
++
++	return 0;
++}
++
++static struct platform_driver jz_nand_driver = {
++	.probe = jz_nand_probe,
++	.remove = jz_nand_remove,
++	.driver = {
++		.name = "jz4740-nand",
++	},
++};
++
++module_platform_driver(jz_nand_driver);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
++MODULE_DESCRIPTION("NAND controller driver for JZ4740 SoC");
++MODULE_ALIAS("platform:jz4740-nand");
+diff --git a/drivers/mtd/nand/raw/jz4780_bch.c b/drivers/mtd/nand/raw/jz4780_bch.c
+new file mode 100644
+index 0000000..731c605
+--- /dev/null
++++ b/drivers/mtd/nand/raw/jz4780_bch.c
+@@ -0,0 +1,380 @@
++/*
++ * JZ4780 BCH controller
++ *
++ * Copyright (c) 2015 Imagination Technologies
++ * Author: Alex Smith <alex.smith@imgtec.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/bitops.h>
++#include <linux/clk.h>
++#include <linux/delay.h>
++#include <linux/init.h>
++#include <linux/iopoll.h>
++#include <linux/module.h>
++#include <linux/mutex.h>
++#include <linux/of.h>
++#include <linux/of_platform.h>
++#include <linux/platform_device.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++
++#include "jz4780_bch.h"
++
++#define BCH_BHCR			0x0
++#define BCH_BHCCR			0x8
++#define BCH_BHCNT			0xc
++#define BCH_BHDR			0x10
++#define BCH_BHPAR0			0x14
++#define BCH_BHERR0			0x84
++#define BCH_BHINT			0x184
++#define BCH_BHINTES			0x188
++#define BCH_BHINTEC			0x18c
++#define BCH_BHINTE			0x190
++
++#define BCH_BHCR_BSEL_SHIFT		4
++#define BCH_BHCR_BSEL_MASK		(0x7f << BCH_BHCR_BSEL_SHIFT)
++#define BCH_BHCR_ENCE			BIT(2)
++#define BCH_BHCR_INIT			BIT(1)
++#define BCH_BHCR_BCHE			BIT(0)
++
++#define BCH_BHCNT_PARITYSIZE_SHIFT	16
++#define BCH_BHCNT_PARITYSIZE_MASK	(0x7f << BCH_BHCNT_PARITYSIZE_SHIFT)
++#define BCH_BHCNT_BLOCKSIZE_SHIFT	0
++#define BCH_BHCNT_BLOCKSIZE_MASK	(0x7ff << BCH_BHCNT_BLOCKSIZE_SHIFT)
++
++#define BCH_BHERR_MASK_SHIFT		16
++#define BCH_BHERR_MASK_MASK		(0xffff << BCH_BHERR_MASK_SHIFT)
++#define BCH_BHERR_INDEX_SHIFT		0
++#define BCH_BHERR_INDEX_MASK		(0x7ff << BCH_BHERR_INDEX_SHIFT)
++
++#define BCH_BHINT_ERRC_SHIFT		24
++#define BCH_BHINT_ERRC_MASK		(0x7f << BCH_BHINT_ERRC_SHIFT)
++#define BCH_BHINT_TERRC_SHIFT		16
++#define BCH_BHINT_TERRC_MASK		(0x7f << BCH_BHINT_TERRC_SHIFT)
++#define BCH_BHINT_DECF			BIT(3)
++#define BCH_BHINT_ENCF			BIT(2)
++#define BCH_BHINT_UNCOR			BIT(1)
++#define BCH_BHINT_ERR			BIT(0)
++
++#define BCH_CLK_RATE			(200 * 1000 * 1000)
++
++/* Timeout for BCH calculation/correction. */
++#define BCH_TIMEOUT_US			100000
++
++struct jz4780_bch {
++	struct device *dev;
++	void __iomem *base;
++	struct clk *clk;
++	struct mutex lock;
++};
++
++static void jz4780_bch_init(struct jz4780_bch *bch,
++			    struct jz4780_bch_params *params, bool encode)
++{
++	u32 reg;
++
++	/* Clear interrupt status. */
++	writel(readl(bch->base + BCH_BHINT), bch->base + BCH_BHINT);
++
++	/* Set up BCH count register. */
++	reg = params->size << BCH_BHCNT_BLOCKSIZE_SHIFT;
++	reg |= params->bytes << BCH_BHCNT_PARITYSIZE_SHIFT;
++	writel(reg, bch->base + BCH_BHCNT);
++
++	/* Initialise and enable BCH. */
++	reg = BCH_BHCR_BCHE | BCH_BHCR_INIT;
++	reg |= params->strength << BCH_BHCR_BSEL_SHIFT;
++	if (encode)
++		reg |= BCH_BHCR_ENCE;
++	writel(reg, bch->base + BCH_BHCR);
++}
++
++static void jz4780_bch_disable(struct jz4780_bch *bch)
++{
++	writel(readl(bch->base + BCH_BHINT), bch->base + BCH_BHINT);
++	writel(BCH_BHCR_BCHE, bch->base + BCH_BHCCR);
++}
++
++static void jz4780_bch_write_data(struct jz4780_bch *bch, const void *buf,
++				  size_t size)
++{
++	size_t size32 = size / sizeof(u32);
++	size_t size8 = size % sizeof(u32);
++	const u32 *src32;
++	const u8 *src8;
++
++	src32 = (const u32 *)buf;
++	while (size32--)
++		writel(*src32++, bch->base + BCH_BHDR);
++
++	src8 = (const u8 *)src32;
++	while (size8--)
++		writeb(*src8++, bch->base + BCH_BHDR);
++}
++
++static void jz4780_bch_read_parity(struct jz4780_bch *bch, void *buf,
++				   size_t size)
++{
++	size_t size32 = size / sizeof(u32);
++	size_t size8 = size % sizeof(u32);
++	u32 *dest32;
++	u8 *dest8;
++	u32 val, offset = 0;
++
++	dest32 = (u32 *)buf;
++	while (size32--) {
++		*dest32++ = readl(bch->base + BCH_BHPAR0 + offset);
++		offset += sizeof(u32);
++	}
++
++	dest8 = (u8 *)dest32;
++	val = readl(bch->base + BCH_BHPAR0 + offset);
++	switch (size8) {
++	case 3:
++		dest8[2] = (val >> 16) & 0xff;
++	case 2:
++		dest8[1] = (val >> 8) & 0xff;
++	case 1:
++		dest8[0] = val & 0xff;
++		break;
++	}
++}
++
++static bool jz4780_bch_wait_complete(struct jz4780_bch *bch, unsigned int irq,
++				     u32 *status)
++{
++	u32 reg;
++	int ret;
++
++	/*
++	 * While we could use interrupts here and sleep until the operation
++	 * completes, the controller works fairly quickly (usually a few
++	 * microseconds) and so the overhead of sleeping until we get an
++	 * interrupt quite noticeably decreases performance.
++	 */
++	ret = readl_poll_timeout(bch->base + BCH_BHINT, reg,
++				 (reg & irq) == irq, 0, BCH_TIMEOUT_US);
++	if (ret)
++		return false;
++
++	if (status)
++		*status = reg;
++
++	writel(reg, bch->base + BCH_BHINT);
++	return true;
++}
++
++/**
++ * jz4780_bch_calculate() - calculate ECC for a data buffer
++ * @bch: BCH device.
++ * @params: BCH parameters.
++ * @buf: input buffer with raw data.
++ * @ecc_code: output buffer with ECC.
++ *
++ * Return: 0 on success, -ETIMEDOUT if timed out while waiting for BCH
++ * controller.
++ */
++int jz4780_bch_calculate(struct jz4780_bch *bch, struct jz4780_bch_params *params,
++			 const u8 *buf, u8 *ecc_code)
++{
++	int ret = 0;
++
++	mutex_lock(&bch->lock);
++	jz4780_bch_init(bch, params, true);
++	jz4780_bch_write_data(bch, buf, params->size);
++
++	if (jz4780_bch_wait_complete(bch, BCH_BHINT_ENCF, NULL)) {
++		jz4780_bch_read_parity(bch, ecc_code, params->bytes);
++	} else {
++		dev_err(bch->dev, "timed out while calculating ECC\n");
++		ret = -ETIMEDOUT;
++	}
++
++	jz4780_bch_disable(bch);
++	mutex_unlock(&bch->lock);
++	return ret;
++}
++EXPORT_SYMBOL(jz4780_bch_calculate);
++
++/**
++ * jz4780_bch_correct() - detect and correct bit errors
++ * @bch: BCH device.
++ * @params: BCH parameters.
++ * @buf: raw data read from the chip.
++ * @ecc_code: ECC read from the chip.
++ *
++ * Given the raw data and the ECC read from the NAND device, detects and
++ * corrects errors in the data.
++ *
++ * Return: the number of bit errors corrected, -EBADMSG if there are too many
++ * errors to correct or -ETIMEDOUT if we timed out waiting for the controller.
++ */
++int jz4780_bch_correct(struct jz4780_bch *bch, struct jz4780_bch_params *params,
++		       u8 *buf, u8 *ecc_code)
++{
++	u32 reg, mask, index;
++	int i, ret, count;
++
++	mutex_lock(&bch->lock);
++
++	jz4780_bch_init(bch, params, false);
++	jz4780_bch_write_data(bch, buf, params->size);
++	jz4780_bch_write_data(bch, ecc_code, params->bytes);
++
++	if (!jz4780_bch_wait_complete(bch, BCH_BHINT_DECF, &reg)) {
++		dev_err(bch->dev, "timed out while correcting data\n");
++		ret = -ETIMEDOUT;
++		goto out;
++	}
++
++	if (reg & BCH_BHINT_UNCOR) {
++		dev_warn(bch->dev, "uncorrectable ECC error\n");
++		ret = -EBADMSG;
++		goto out;
++	}
++
++	/* Correct any detected errors. */
++	if (reg & BCH_BHINT_ERR) {
++		count = (reg & BCH_BHINT_ERRC_MASK) >> BCH_BHINT_ERRC_SHIFT;
++		ret = (reg & BCH_BHINT_TERRC_MASK) >> BCH_BHINT_TERRC_SHIFT;
++
++		for (i = 0; i < count; i++) {
++			reg = readl(bch->base + BCH_BHERR0 + (i * 4));
++			mask = (reg & BCH_BHERR_MASK_MASK) >>
++						BCH_BHERR_MASK_SHIFT;
++			index = (reg & BCH_BHERR_INDEX_MASK) >>
++						BCH_BHERR_INDEX_SHIFT;
++			buf[(index * 2) + 0] ^= mask;
++			buf[(index * 2) + 1] ^= mask >> 8;
++		}
++	} else {
++		ret = 0;
++	}
++
++out:
++	jz4780_bch_disable(bch);
++	mutex_unlock(&bch->lock);
++	return ret;
++}
++EXPORT_SYMBOL(jz4780_bch_correct);
++
++/**
++ * jz4780_bch_get() - get the BCH controller device
++ * @np: BCH device tree node.
++ *
++ * Gets the BCH controller device from the specified device tree node. The
++ * device must be released with jz4780_bch_release() when it is no longer being
++ * used.
++ *
++ * Return: a pointer to jz4780_bch, errors are encoded into the pointer.
++ * PTR_ERR(-EPROBE_DEFER) if the device hasn't been initialised yet.
++ */
++static struct jz4780_bch *jz4780_bch_get(struct device_node *np)
++{
++	struct platform_device *pdev;
++	struct jz4780_bch *bch;
++
++	pdev = of_find_device_by_node(np);
++	if (!pdev || !platform_get_drvdata(pdev))
++		return ERR_PTR(-EPROBE_DEFER);
++
++	get_device(&pdev->dev);
++
++	bch = platform_get_drvdata(pdev);
++	clk_prepare_enable(bch->clk);
++
++	return bch;
++}
++
++/**
++ * of_jz4780_bch_get() - get the BCH controller from a DT node
++ * @of_node: the node that contains a bch-controller property.
++ *
++ * Get the bch-controller property from the given device tree
++ * node and pass it to jz4780_bch_get to do the work.
++ *
++ * Return: a pointer to jz4780_bch, errors are encoded into the pointer.
++ * PTR_ERR(-EPROBE_DEFER) if the device hasn't been initialised yet.
++ */
++struct jz4780_bch *of_jz4780_bch_get(struct device_node *of_node)
++{
++	struct jz4780_bch *bch = NULL;
++	struct device_node *np;
++
++	np = of_parse_phandle(of_node, "ingenic,bch-controller", 0);
++
++	if (np) {
++		bch = jz4780_bch_get(np);
++		of_node_put(np);
++	}
++	return bch;
++}
++EXPORT_SYMBOL(of_jz4780_bch_get);
++
++/**
++ * jz4780_bch_release() - release the BCH controller device
++ * @bch: BCH device.
++ */
++void jz4780_bch_release(struct jz4780_bch *bch)
++{
++	clk_disable_unprepare(bch->clk);
++	put_device(bch->dev);
++}
++EXPORT_SYMBOL(jz4780_bch_release);
++
++static int jz4780_bch_probe(struct platform_device *pdev)
++{
++	struct device *dev = &pdev->dev;
++	struct jz4780_bch *bch;
++	struct resource *res;
++
++	bch = devm_kzalloc(dev, sizeof(*bch), GFP_KERNEL);
++	if (!bch)
++		return -ENOMEM;
++
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	bch->base = devm_ioremap_resource(dev, res);
++	if (IS_ERR(bch->base))
++		return PTR_ERR(bch->base);
++
++	jz4780_bch_disable(bch);
++
++	bch->clk = devm_clk_get(dev, NULL);
++	if (IS_ERR(bch->clk)) {
++		dev_err(dev, "failed to get clock: %ld\n", PTR_ERR(bch->clk));
++		return PTR_ERR(bch->clk);
++	}
++
++	clk_set_rate(bch->clk, BCH_CLK_RATE);
++
++	mutex_init(&bch->lock);
++
++	bch->dev = dev;
++	platform_set_drvdata(pdev, bch);
++
++	return 0;
++}
++
++static const struct of_device_id jz4780_bch_dt_match[] = {
++	{ .compatible = "ingenic,jz4780-bch" },
++	{},
++};
++MODULE_DEVICE_TABLE(of, jz4780_bch_dt_match);
++
++static struct platform_driver jz4780_bch_driver = {
++	.probe		= jz4780_bch_probe,
++	.driver	= {
++		.name	= "jz4780-bch",
++		.of_match_table = of_match_ptr(jz4780_bch_dt_match),
++	},
++};
++module_platform_driver(jz4780_bch_driver);
++
++MODULE_AUTHOR("Alex Smith <alex@alex-smith.me.uk>");
++MODULE_AUTHOR("Harvey Hunt <harveyhuntnexus@gmail.com>");
++MODULE_DESCRIPTION("Ingenic JZ4780 BCH error correction driver");
++MODULE_LICENSE("GPL v2");
+diff --git a/drivers/mtd/nand/raw/jz4780_bch.h b/drivers/mtd/nand/raw/jz4780_bch.h
+new file mode 100644
+index 0000000..bf471808
+--- /dev/null
++++ b/drivers/mtd/nand/raw/jz4780_bch.h
+@@ -0,0 +1,43 @@
++/*
++ * JZ4780 BCH controller
++ *
++ * Copyright (c) 2015 Imagination Technologies
++ * Author: Alex Smith <alex.smith@imgtec.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 __DRIVERS_MTD_NAND_JZ4780_BCH_H__
++#define __DRIVERS_MTD_NAND_JZ4780_BCH_H__
++
++#include <linux/types.h>
++
++struct device;
++struct device_node;
++struct jz4780_bch;
++
++/**
++ * struct jz4780_bch_params - BCH parameters
++ * @size: data bytes per ECC step.
++ * @bytes: ECC bytes per step.
++ * @strength: number of correctable bits per ECC step.
++ */
++struct jz4780_bch_params {
++	int size;
++	int bytes;
++	int strength;
++};
++
++int jz4780_bch_calculate(struct jz4780_bch *bch,
++				struct jz4780_bch_params *params,
++				const u8 *buf, u8 *ecc_code);
++int jz4780_bch_correct(struct jz4780_bch *bch,
++			      struct jz4780_bch_params *params, u8 *buf,
++			      u8 *ecc_code);
++
++void jz4780_bch_release(struct jz4780_bch *bch);
++struct jz4780_bch *of_jz4780_bch_get(struct device_node *np);
++
++#endif /* __DRIVERS_MTD_NAND_JZ4780_BCH_H__ */
+diff --git a/drivers/mtd/nand/raw/jz4780_nand.c b/drivers/mtd/nand/raw/jz4780_nand.c
+new file mode 100644
+index 0000000..e69f6ae
+--- /dev/null
++++ b/drivers/mtd/nand/raw/jz4780_nand.c
+@@ -0,0 +1,416 @@
++/*
++ * JZ4780 NAND driver
++ *
++ * Copyright (c) 2015 Imagination Technologies
++ * Author: Alex Smith <alex.smith@imgtec.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/delay.h>
++#include <linux/init.h>
++#include <linux/io.h>
++#include <linux/list.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/of_address.h>
++#include <linux/gpio/consumer.h>
++#include <linux/platform_device.h>
++#include <linux/slab.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/rawnand.h>
++#include <linux/mtd/partitions.h>
++
++#include <linux/jz4780-nemc.h>
++
++#include "jz4780_bch.h"
++
++#define DRV_NAME	"jz4780-nand"
++
++#define OFFSET_DATA	0x00000000
++#define OFFSET_CMD	0x00400000
++#define OFFSET_ADDR	0x00800000
++
++/* Command delay when there is no R/B pin. */
++#define RB_DELAY_US	100
++
++struct jz4780_nand_cs {
++	unsigned int bank;
++	void __iomem *base;
++};
++
++struct jz4780_nand_controller {
++	struct device *dev;
++	struct jz4780_bch *bch;
++	struct nand_hw_control controller;
++	unsigned int num_banks;
++	struct list_head chips;
++	int selected;
++	struct jz4780_nand_cs cs[];
++};
++
++struct jz4780_nand_chip {
++	struct nand_chip chip;
++	struct list_head chip_list;
++
++	struct gpio_desc *busy_gpio;
++	struct gpio_desc *wp_gpio;
++	unsigned int reading: 1;
++};
++
++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);
++}
++
++static inline struct jz4780_nand_controller *to_jz4780_nand_controller(struct nand_hw_control *ctrl)
++{
++	return container_of(ctrl, struct jz4780_nand_controller, controller);
++}
++
++static void jz4780_nand_select_chip(struct mtd_info *mtd, int chipnr)
++{
++	struct jz4780_nand_chip *nand = to_jz4780_nand_chip(mtd);
++	struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(nand->chip.controller);
++	struct jz4780_nand_cs *cs;
++
++	/* Ensure the currently selected chip is deasserted. */
++	if (chipnr == -1 && nfc->selected >= 0) {
++		cs = &nfc->cs[nfc->selected];
++		jz4780_nemc_assert(nfc->dev, cs->bank, false);
++	}
++
++	nfc->selected = chipnr;
++}
++
++static void jz4780_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
++				 unsigned int ctrl)
++{
++	struct jz4780_nand_chip *nand = to_jz4780_nand_chip(mtd);
++	struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(nand->chip.controller);
++	struct jz4780_nand_cs *cs;
++
++	if (WARN_ON(nfc->selected < 0))
++		return;
++
++	cs = &nfc->cs[nfc->selected];
++
++	jz4780_nemc_assert(nfc->dev, cs->bank, ctrl & NAND_NCE);
++
++	if (cmd == NAND_CMD_NONE)
++		return;
++
++	if (ctrl & NAND_ALE)
++		writeb(cmd, cs->base + OFFSET_ADDR);
++	else if (ctrl & NAND_CLE)
++		writeb(cmd, cs->base + OFFSET_CMD);
++}
++
++static int jz4780_nand_dev_ready(struct mtd_info *mtd)
++{
++	struct jz4780_nand_chip *nand = to_jz4780_nand_chip(mtd);
++
++	return !gpiod_get_value_cansleep(nand->busy_gpio);
++}
++
++static void jz4780_nand_ecc_hwctl(struct mtd_info *mtd, int mode)
++{
++	struct jz4780_nand_chip *nand = to_jz4780_nand_chip(mtd);
++
++	nand->reading = (mode == NAND_ECC_READ);
++}
++
++static int jz4780_nand_ecc_calculate(struct mtd_info *mtd, const u8 *dat,
++				     u8 *ecc_code)
++{
++	struct jz4780_nand_chip *nand = to_jz4780_nand_chip(mtd);
++	struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(nand->chip.controller);
++	struct jz4780_bch_params params;
++
++	/*
++	 * Don't need to generate the ECC when reading, BCH does it for us as
++	 * part of decoding/correction.
++	 */
++	if (nand->reading)
++		return 0;
++
++	params.size = nand->chip.ecc.size;
++	params.bytes = nand->chip.ecc.bytes;
++	params.strength = nand->chip.ecc.strength;
++
++	return jz4780_bch_calculate(nfc->bch, &params, dat, ecc_code);
++}
++
++static int jz4780_nand_ecc_correct(struct mtd_info *mtd, u8 *dat,
++				   u8 *read_ecc, u8 *calc_ecc)
++{
++	struct jz4780_nand_chip *nand = to_jz4780_nand_chip(mtd);
++	struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(nand->chip.controller);
++	struct jz4780_bch_params params;
++
++	params.size = nand->chip.ecc.size;
++	params.bytes = nand->chip.ecc.bytes;
++	params.strength = nand->chip.ecc.strength;
++
++	return jz4780_bch_correct(nfc->bch, &params, dat, read_ecc);
++}
++
++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 jz4780_nand_controller *nfc = to_jz4780_nand_controller(chip->controller);
++	int eccbytes;
++
++	chip->ecc.bytes = fls((1 + 8) * chip->ecc.size)	*
++				(chip->ecc.strength / 8);
++
++	switch (chip->ecc.mode) {
++	case NAND_ECC_HW:
++		if (!nfc->bch) {
++			dev_err(dev, "HW BCH selected, but BCH controller not found\n");
++			return -ENODEV;
++		}
++
++		chip->ecc.hwctl = jz4780_nand_ecc_hwctl;
++		chip->ecc.calculate = jz4780_nand_ecc_calculate;
++		chip->ecc.correct = jz4780_nand_ecc_correct;
++		/* fall through */
++	case NAND_ECC_SOFT:
++		dev_info(dev, "using %s (strength %d, size %d, bytes %d)\n",
++			(nfc->bch) ? "hardware BCH" : "software ECC",
++			chip->ecc.strength, chip->ecc.size, chip->ecc.bytes);
++		break;
++	case NAND_ECC_NONE:
++		dev_info(dev, "not using ECC\n");
++		break;
++	default:
++		dev_err(dev, "ECC mode %d not supported\n", chip->ecc.mode);
++		return -EINVAL;
++	}
++
++	/* The NAND core will generate the ECC layout for SW ECC */
++	if (chip->ecc.mode != NAND_ECC_HW)
++		return 0;
++
++	/* Generate ECC layout. ECC codes are right aligned in the OOB area. */
++	eccbytes = mtd->writesize / chip->ecc.size * chip->ecc.bytes;
++
++	if (eccbytes > mtd->oobsize - 2) {
++		dev_err(dev,
++			"invalid ECC config: required %d ECC bytes, but only %d are available",
++			eccbytes, mtd->oobsize - 2);
++		return -EINVAL;
++	}
++
++	mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
++
++	return 0;
++}
++
++static int jz4780_nand_init_chip(struct platform_device *pdev,
++				struct jz4780_nand_controller *nfc,
++				struct device_node *np,
++				unsigned int chipnr)
++{
++	struct device *dev = &pdev->dev;
++	struct jz4780_nand_chip *nand;
++	struct jz4780_nand_cs *cs;
++	struct resource *res;
++	struct nand_chip *chip;
++	struct mtd_info *mtd;
++	const __be32 *reg;
++	int ret = 0;
++
++	cs = &nfc->cs[chipnr];
++
++	reg = of_get_property(np, "reg", NULL);
++	if (!reg)
++		return -EINVAL;
++
++	cs->bank = be32_to_cpu(*reg);
++
++	jz4780_nemc_set_type(nfc->dev, cs->bank, JZ4780_NEMC_BANK_NAND);
++
++	res = platform_get_resource(pdev, IORESOURCE_MEM, chipnr);
++	cs->base = devm_ioremap_resource(dev, res);
++	if (IS_ERR(cs->base))
++		return PTR_ERR(cs->base);
++
++	nand = devm_kzalloc(dev, sizeof(*nand), GFP_KERNEL);
++	if (!nand)
++		return -ENOMEM;
++
++	nand->busy_gpio = devm_gpiod_get_optional(dev, "rb", GPIOD_IN);
++
++	if (IS_ERR(nand->busy_gpio)) {
++		ret = PTR_ERR(nand->busy_gpio);
++		dev_err(dev, "failed to request busy GPIO: %d\n", ret);
++		return ret;
++	} else if (nand->busy_gpio) {
++		nand->chip.dev_ready = jz4780_nand_dev_ready;
++	}
++
++	nand->wp_gpio = devm_gpiod_get_optional(dev, "wp", GPIOD_OUT_LOW);
++
++	if (IS_ERR(nand->wp_gpio)) {
++		ret = PTR_ERR(nand->wp_gpio);
++		dev_err(dev, "failed to request WP GPIO: %d\n", ret);
++		return ret;
++	}
++
++	chip = &nand->chip;
++	mtd = nand_to_mtd(chip);
++	mtd->name = devm_kasprintf(dev, GFP_KERNEL, "%s.%d", dev_name(dev),
++				   cs->bank);
++	if (!mtd->name)
++		return -ENOMEM;
++	mtd->dev.parent = dev;
++
++	chip->IO_ADDR_R = cs->base + OFFSET_DATA;
++	chip->IO_ADDR_W = cs->base + OFFSET_DATA;
++	chip->chip_delay = RB_DELAY_US;
++	chip->options = NAND_NO_SUBPAGE_WRITE;
++	chip->select_chip = jz4780_nand_select_chip;
++	chip->cmd_ctrl = jz4780_nand_cmd_ctrl;
++	chip->ecc.mode = NAND_ECC_HW;
++	chip->controller = &nfc->controller;
++	nand_set_flash_node(chip, np);
++
++	ret = nand_scan_ident(mtd, 1, NULL);
++	if (ret)
++		return ret;
++
++	ret = jz4780_nand_init_ecc(nand, dev);
++	if (ret)
++		return ret;
++
++	ret = nand_scan_tail(mtd);
++	if (ret)
++		return ret;
++
++	ret = mtd_device_register(mtd, NULL, 0);
++	if (ret) {
++		nand_release(mtd);
++		return ret;
++	}
++
++	list_add_tail(&nand->chip_list, &nfc->chips);
++
++	return 0;
++}
++
++static void jz4780_nand_cleanup_chips(struct jz4780_nand_controller *nfc)
++{
++	struct jz4780_nand_chip *chip;
++
++	while (!list_empty(&nfc->chips)) {
++		chip = list_first_entry(&nfc->chips, struct jz4780_nand_chip, chip_list);
++		nand_release(nand_to_mtd(&chip->chip));
++		list_del(&chip->chip_list);
++	}
++}
++
++static int jz4780_nand_init_chips(struct jz4780_nand_controller *nfc,
++				  struct platform_device *pdev)
++{
++	struct device *dev = &pdev->dev;
++	struct device_node *np;
++	int i = 0;
++	int ret;
++	int num_chips = of_get_child_count(dev->of_node);
++
++	if (num_chips > nfc->num_banks) {
++		dev_err(dev, "found %d chips but only %d banks\n", num_chips, nfc->num_banks);
++		return -EINVAL;
++	}
++
++	for_each_child_of_node(dev->of_node, np) {
++		ret = jz4780_nand_init_chip(pdev, nfc, np, i);
++		if (ret) {
++			jz4780_nand_cleanup_chips(nfc);
++			return ret;
++		}
++
++		i++;
++	}
++
++	return 0;
++}
++
++static int jz4780_nand_probe(struct platform_device *pdev)
++{
++	struct device *dev = &pdev->dev;
++	unsigned int num_banks;
++	struct jz4780_nand_controller *nfc;
++	int ret;
++
++	num_banks = jz4780_nemc_num_banks(dev);
++	if (num_banks == 0) {
++		dev_err(dev, "no banks found\n");
++		return -ENODEV;
++	}
++
++	nfc = devm_kzalloc(dev, sizeof(*nfc) + (sizeof(nfc->cs[0]) * num_banks), GFP_KERNEL);
++	if (!nfc)
++		return -ENOMEM;
++
++	/*
++	 * Check for BCH HW before we call nand_scan_ident, to prevent us from
++	 * having to call it again if the BCH driver returns -EPROBE_DEFER.
++	 */
++	nfc->bch = of_jz4780_bch_get(dev->of_node);
++	if (IS_ERR(nfc->bch))
++		return PTR_ERR(nfc->bch);
++
++	nfc->dev = dev;
++	nfc->num_banks = num_banks;
++
++	nand_hw_control_init(&nfc->controller);
++	INIT_LIST_HEAD(&nfc->chips);
++
++	ret = jz4780_nand_init_chips(nfc, pdev);
++	if (ret) {
++		if (nfc->bch)
++			jz4780_bch_release(nfc->bch);
++		return ret;
++	}
++
++	platform_set_drvdata(pdev, nfc);
++	return 0;
++}
++
++static int jz4780_nand_remove(struct platform_device *pdev)
++{
++	struct jz4780_nand_controller *nfc = platform_get_drvdata(pdev);
++
++	if (nfc->bch)
++		jz4780_bch_release(nfc->bch);
++
++	jz4780_nand_cleanup_chips(nfc);
++
++	return 0;
++}
++
++static const struct of_device_id jz4780_nand_dt_match[] = {
++	{ .compatible = "ingenic,jz4780-nand" },
++	{},
++};
++MODULE_DEVICE_TABLE(of, jz4780_nand_dt_match);
++
++static struct platform_driver jz4780_nand_driver = {
++	.probe		= jz4780_nand_probe,
++	.remove		= jz4780_nand_remove,
++	.driver	= {
++		.name	= DRV_NAME,
++		.of_match_table = of_match_ptr(jz4780_nand_dt_match),
++	},
++};
++module_platform_driver(jz4780_nand_driver);
++
++MODULE_AUTHOR("Alex Smith <alex@alex-smith.me.uk>");
++MODULE_AUTHOR("Harvey Hunt <harveyhuntnexus@gmail.com>");
++MODULE_DESCRIPTION("Ingenic JZ4780 NAND driver");
++MODULE_LICENSE("GPL v2");
+diff --git a/drivers/mtd/nand/raw/lpc32xx_mlc.c b/drivers/mtd/nand/raw/lpc32xx_mlc.c
+new file mode 100644
+index 0000000..5796468
+--- /dev/null
++++ b/drivers/mtd/nand/raw/lpc32xx_mlc.c
+@@ -0,0 +1,906 @@
++/*
++ * Driver for NAND MLC Controller in LPC32xx
++ *
++ * Author: Roland Stigge <stigge@antcom.de>
++ *
++ * Copyright © 2011 WORK Microwave GmbH
++ * Copyright © 2011, 2012 Roland Stigge
++ *
++ * 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.
++ *
++ *
++ * NAND Flash Controller Operation:
++ * - Read: Auto Decode
++ * - Write: Auto Encode
++ * - Tested Page Sizes: 2048, 4096
++ */
++
++#include <linux/slab.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/rawnand.h>
++#include <linux/mtd/partitions.h>
++#include <linux/clk.h>
++#include <linux/err.h>
++#include <linux/delay.h>
++#include <linux/completion.h>
++#include <linux/interrupt.h>
++#include <linux/of.h>
++#include <linux/of_gpio.h>
++#include <linux/mtd/lpc32xx_mlc.h>
++#include <linux/io.h>
++#include <linux/mm.h>
++#include <linux/dma-mapping.h>
++#include <linux/dmaengine.h>
++#include <linux/mtd/nand_ecc.h>
++
++#define DRV_NAME "lpc32xx_mlc"
++
++/**********************************************************************
++* MLC NAND controller register offsets
++**********************************************************************/
++
++#define MLC_BUFF(x)			(x + 0x00000)
++#define MLC_DATA(x)			(x + 0x08000)
++#define MLC_CMD(x)			(x + 0x10000)
++#define MLC_ADDR(x)			(x + 0x10004)
++#define MLC_ECC_ENC_REG(x)		(x + 0x10008)
++#define MLC_ECC_DEC_REG(x)		(x + 0x1000C)
++#define MLC_ECC_AUTO_ENC_REG(x)		(x + 0x10010)
++#define MLC_ECC_AUTO_DEC_REG(x)		(x + 0x10014)
++#define MLC_RPR(x)			(x + 0x10018)
++#define MLC_WPR(x)			(x + 0x1001C)
++#define MLC_RUBP(x)			(x + 0x10020)
++#define MLC_ROBP(x)			(x + 0x10024)
++#define MLC_SW_WP_ADD_LOW(x)		(x + 0x10028)
++#define MLC_SW_WP_ADD_HIG(x)		(x + 0x1002C)
++#define MLC_ICR(x)			(x + 0x10030)
++#define MLC_TIME_REG(x)			(x + 0x10034)
++#define MLC_IRQ_MR(x)			(x + 0x10038)
++#define MLC_IRQ_SR(x)			(x + 0x1003C)
++#define MLC_LOCK_PR(x)			(x + 0x10044)
++#define MLC_ISR(x)			(x + 0x10048)
++#define MLC_CEH(x)			(x + 0x1004C)
++
++/**********************************************************************
++* MLC_CMD bit definitions
++**********************************************************************/
++#define MLCCMD_RESET			0xFF
++
++/**********************************************************************
++* MLC_ICR bit definitions
++**********************************************************************/
++#define MLCICR_WPROT			(1 << 3)
++#define MLCICR_LARGEBLOCK		(1 << 2)
++#define MLCICR_LONGADDR			(1 << 1)
++#define MLCICR_16BIT			(1 << 0)  /* unsupported by LPC32x0! */
++
++/**********************************************************************
++* MLC_TIME_REG bit definitions
++**********************************************************************/
++#define MLCTIMEREG_TCEA_DELAY(n)	(((n) & 0x03) << 24)
++#define MLCTIMEREG_BUSY_DELAY(n)	(((n) & 0x1F) << 19)
++#define MLCTIMEREG_NAND_TA(n)		(((n) & 0x07) << 16)
++#define MLCTIMEREG_RD_HIGH(n)		(((n) & 0x0F) << 12)
++#define MLCTIMEREG_RD_LOW(n)		(((n) & 0x0F) << 8)
++#define MLCTIMEREG_WR_HIGH(n)		(((n) & 0x0F) << 4)
++#define MLCTIMEREG_WR_LOW(n)		(((n) & 0x0F) << 0)
++
++/**********************************************************************
++* MLC_IRQ_MR and MLC_IRQ_SR bit definitions
++**********************************************************************/
++#define MLCIRQ_NAND_READY		(1 << 5)
++#define MLCIRQ_CONTROLLER_READY		(1 << 4)
++#define MLCIRQ_DECODE_FAILURE		(1 << 3)
++#define MLCIRQ_DECODE_ERROR		(1 << 2)
++#define MLCIRQ_ECC_READY		(1 << 1)
++#define MLCIRQ_WRPROT_FAULT		(1 << 0)
++
++/**********************************************************************
++* MLC_LOCK_PR bit definitions
++**********************************************************************/
++#define MLCLOCKPR_MAGIC			0xA25E
++
++/**********************************************************************
++* MLC_ISR bit definitions
++**********************************************************************/
++#define MLCISR_DECODER_FAILURE		(1 << 6)
++#define MLCISR_ERRORS			((1 << 4) | (1 << 5))
++#define MLCISR_ERRORS_DETECTED		(1 << 3)
++#define MLCISR_ECC_READY		(1 << 2)
++#define MLCISR_CONTROLLER_READY		(1 << 1)
++#define MLCISR_NAND_READY		(1 << 0)
++
++/**********************************************************************
++* MLC_CEH bit definitions
++**********************************************************************/
++#define MLCCEH_NORMAL			(1 << 0)
++
++struct lpc32xx_nand_cfg_mlc {
++	uint32_t tcea_delay;
++	uint32_t busy_delay;
++	uint32_t nand_ta;
++	uint32_t rd_high;
++	uint32_t rd_low;
++	uint32_t wr_high;
++	uint32_t wr_low;
++	int wp_gpio;
++	struct mtd_partition *parts;
++	unsigned num_parts;
++};
++
++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);
++
++	if (section >= nand_chip->ecc.steps)
++		return -ERANGE;
++
++	oobregion->offset = ((section + 1) * 16) - nand_chip->ecc.bytes;
++	oobregion->length = nand_chip->ecc.bytes;
++
++	return 0;
++}
++
++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);
++
++	if (section >= nand_chip->ecc.steps)
++		return -ERANGE;
++
++	oobregion->offset = 16 * section;
++	oobregion->length = 16 - nand_chip->ecc.bytes;
++
++	return 0;
++}
++
++static const struct mtd_ooblayout_ops lpc32xx_ooblayout_ops = {
++	.ecc = lpc32xx_ooblayout_ecc,
++	.free = lpc32xx_ooblayout_free,
++};
++
++static struct nand_bbt_descr lpc32xx_nand_bbt = {
++	.options = NAND_BBT_ABSPAGE | NAND_BBT_2BIT | NAND_BBT_NO_OOB |
++		   NAND_BBT_WRITE,
++	.pages = { 524224, 0, 0, 0, 0, 0, 0, 0 },
++};
++
++static struct nand_bbt_descr lpc32xx_nand_bbt_mirror = {
++	.options = NAND_BBT_ABSPAGE | NAND_BBT_2BIT | NAND_BBT_NO_OOB |
++		   NAND_BBT_WRITE,
++	.pages = { 524160, 0, 0, 0, 0, 0, 0, 0 },
++};
++
++struct lpc32xx_nand_host {
++	struct nand_chip	nand_chip;
++	struct lpc32xx_mlc_platform_data *pdata;
++	struct clk		*clk;
++	void __iomem		*io_base;
++	int			irq;
++	struct lpc32xx_nand_cfg_mlc	*ncfg;
++	struct completion       comp_nand;
++	struct completion       comp_controller;
++	uint32_t llptr;
++	/*
++	 * Physical addresses of ECC buffer, DMA data buffers, OOB data buffer
++	 */
++	dma_addr_t		oob_buf_phy;
++	/*
++	 * Virtual addresses of ECC buffer, DMA data buffers, OOB data buffer
++	 */
++	uint8_t			*oob_buf;
++	/* Physical address of DMA base address */
++	dma_addr_t		io_base_phy;
++
++	struct completion	comp_dma;
++	struct dma_chan		*dma_chan;
++	struct dma_slave_config	dma_slave_config;
++	struct scatterlist	sgl;
++	uint8_t			*dma_buf;
++	uint8_t			*dummy_buf;
++	int			mlcsubpages; /* number of 512bytes-subpages */
++};
++
++/*
++ * Activate/Deactivate DMA Operation:
++ *
++ * Using the PL080 DMA Controller for transferring the 512 byte subpages
++ * instead of doing readl() / writel() in a loop slows it down significantly.
++ * Measurements via getnstimeofday() upon 512 byte subpage reads reveal:
++ *
++ * - readl() of 128 x 32 bits in a loop: ~20us
++ * - DMA read of 512 bytes (32 bit, 4...128 words bursts): ~60us
++ * - DMA read of 512 bytes (32 bit, no bursts): ~100us
++ *
++ * This applies to the transfer itself. In the DMA case: only the
++ * wait_for_completion() (DMA setup _not_ included).
++ *
++ * Note that the 512 bytes subpage transfer is done directly from/to a
++ * FIFO/buffer inside the NAND controller. Most of the time (~400-800us for a
++ * 2048 bytes page) is spent waiting for the NAND IRQ, anyway. (The NAND
++ * controller transferring data between its internal buffer to/from the NAND
++ * chip.)
++ *
++ * Therefore, using the PL080 DMA is disabled by default, for now.
++ *
++ */
++static int use_dma;
++
++static void lpc32xx_nand_setup(struct lpc32xx_nand_host *host)
++{
++	uint32_t clkrate, tmp;
++
++	/* Reset MLC controller */
++	writel(MLCCMD_RESET, MLC_CMD(host->io_base));
++	udelay(1000);
++
++	/* Get base clock for MLC block */
++	clkrate = clk_get_rate(host->clk);
++	if (clkrate == 0)
++		clkrate = 104000000;
++
++	/* Unlock MLC_ICR
++	 * (among others, will be locked again automatically) */
++	writew(MLCLOCKPR_MAGIC, MLC_LOCK_PR(host->io_base));
++
++	/* Configure MLC Controller: Large Block, 5 Byte Address */
++	tmp = MLCICR_LARGEBLOCK | MLCICR_LONGADDR;
++	writel(tmp, MLC_ICR(host->io_base));
++
++	/* Unlock MLC_TIME_REG
++	 * (among others, will be locked again automatically) */
++	writew(MLCLOCKPR_MAGIC, MLC_LOCK_PR(host->io_base));
++
++	/* Compute clock setup values, see LPC and NAND manual */
++	tmp = 0;
++	tmp |= MLCTIMEREG_TCEA_DELAY(clkrate / host->ncfg->tcea_delay + 1);
++	tmp |= MLCTIMEREG_BUSY_DELAY(clkrate / host->ncfg->busy_delay + 1);
++	tmp |= MLCTIMEREG_NAND_TA(clkrate / host->ncfg->nand_ta + 1);
++	tmp |= MLCTIMEREG_RD_HIGH(clkrate / host->ncfg->rd_high + 1);
++	tmp |= MLCTIMEREG_RD_LOW(clkrate / host->ncfg->rd_low);
++	tmp |= MLCTIMEREG_WR_HIGH(clkrate / host->ncfg->wr_high + 1);
++	tmp |= MLCTIMEREG_WR_LOW(clkrate / host->ncfg->wr_low);
++	writel(tmp, MLC_TIME_REG(host->io_base));
++
++	/* Enable IRQ for CONTROLLER_READY and NAND_READY */
++	writeb(MLCIRQ_CONTROLLER_READY | MLCIRQ_NAND_READY,
++			MLC_IRQ_MR(host->io_base));
++
++	/* Normal nCE operation: nCE controlled by controller */
++	writel(MLCCEH_NORMAL, MLC_CEH(host->io_base));
++}
++
++/*
++ * Hardware specific access to control lines
++ */
++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 lpc32xx_nand_host *host = nand_get_controller_data(nand_chip);
++
++	if (cmd != NAND_CMD_NONE) {
++		if (ctrl & NAND_CLE)
++			writel(cmd, MLC_CMD(host->io_base));
++		else
++			writel(cmd, MLC_ADDR(host->io_base));
++	}
++}
++
++/*
++ * Read Device Ready (NAND device _and_ controller ready)
++ */
++static int lpc32xx_nand_device_ready(struct mtd_info *mtd)
++{
++	struct nand_chip *nand_chip = mtd_to_nand(mtd);
++	struct lpc32xx_nand_host *host = nand_get_controller_data(nand_chip);
++
++	if ((readb(MLC_ISR(host->io_base)) &
++	     (MLCISR_CONTROLLER_READY | MLCISR_NAND_READY)) ==
++	    (MLCISR_CONTROLLER_READY | MLCISR_NAND_READY))
++		return  1;
++
++	return 0;
++}
++
++static irqreturn_t lpc3xxx_nand_irq(int irq, struct lpc32xx_nand_host *host)
++{
++	uint8_t sr;
++
++	/* Clear interrupt flag by reading status */
++	sr = readb(MLC_IRQ_SR(host->io_base));
++	if (sr & MLCIRQ_NAND_READY)
++		complete(&host->comp_nand);
++	if (sr & MLCIRQ_CONTROLLER_READY)
++		complete(&host->comp_controller);
++
++	return IRQ_HANDLED;
++}
++
++static int lpc32xx_waitfunc_nand(struct mtd_info *mtd, struct nand_chip *chip)
++{
++	struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
++
++	if (readb(MLC_ISR(host->io_base)) & MLCISR_NAND_READY)
++		goto exit;
++
++	wait_for_completion(&host->comp_nand);
++
++	while (!(readb(MLC_ISR(host->io_base)) & MLCISR_NAND_READY)) {
++		/* Seems to be delayed sometimes by controller */
++		dev_dbg(&mtd->dev, "Warning: NAND not ready.\n");
++		cpu_relax();
++	}
++
++exit:
++	return NAND_STATUS_READY;
++}
++
++static int lpc32xx_waitfunc_controller(struct mtd_info *mtd,
++				       struct nand_chip *chip)
++{
++	struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
++
++	if (readb(MLC_ISR(host->io_base)) & MLCISR_CONTROLLER_READY)
++		goto exit;
++
++	wait_for_completion(&host->comp_controller);
++
++	while (!(readb(MLC_ISR(host->io_base)) &
++		 MLCISR_CONTROLLER_READY)) {
++		dev_dbg(&mtd->dev, "Warning: Controller not ready.\n");
++		cpu_relax();
++	}
++
++exit:
++	return NAND_STATUS_READY;
++}
++
++static int lpc32xx_waitfunc(struct mtd_info *mtd, struct nand_chip *chip)
++{
++	lpc32xx_waitfunc_nand(mtd, chip);
++	lpc32xx_waitfunc_controller(mtd, chip);
++
++	return NAND_STATUS_READY;
++}
++
++/*
++ * Enable NAND write protect
++ */
++static void lpc32xx_wp_enable(struct lpc32xx_nand_host *host)
++{
++	if (gpio_is_valid(host->ncfg->wp_gpio))
++		gpio_set_value(host->ncfg->wp_gpio, 0);
++}
++
++/*
++ * Disable NAND write protect
++ */
++static void lpc32xx_wp_disable(struct lpc32xx_nand_host *host)
++{
++	if (gpio_is_valid(host->ncfg->wp_gpio))
++		gpio_set_value(host->ncfg->wp_gpio, 1);
++}
++
++static void lpc32xx_dma_complete_func(void *completion)
++{
++	complete(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 lpc32xx_nand_host *host = nand_get_controller_data(chip);
++	struct dma_async_tx_descriptor *desc;
++	int flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
++	int res;
++
++	sg_init_one(&host->sgl, mem, len);
++
++	res = dma_map_sg(host->dma_chan->device->dev, &host->sgl, 1,
++			 DMA_BIDIRECTIONAL);
++	if (res != 1) {
++		dev_err(mtd->dev.parent, "Failed to map sg list\n");
++		return -ENXIO;
++	}
++	desc = dmaengine_prep_slave_sg(host->dma_chan, &host->sgl, 1, dir,
++				       flags);
++	if (!desc) {
++		dev_err(mtd->dev.parent, "Failed to prepare slave sg\n");
++		goto out1;
++	}
++
++	init_completion(&host->comp_dma);
++	desc->callback = lpc32xx_dma_complete_func;
++	desc->callback_param = &host->comp_dma;
++
++	dmaengine_submit(desc);
++	dma_async_issue_pending(host->dma_chan);
++
++	wait_for_completion_timeout(&host->comp_dma, msecs_to_jiffies(1000));
++
++	dma_unmap_sg(host->dma_chan->device->dev, &host->sgl, 1,
++		     DMA_BIDIRECTIONAL);
++	return 0;
++out1:
++	dma_unmap_sg(host->dma_chan->device->dev, &host->sgl, 1,
++		     DMA_BIDIRECTIONAL);
++	return -ENXIO;
++}
++
++static int lpc32xx_read_page(struct mtd_info *mtd, struct nand_chip *chip,
++			     uint8_t *buf, int oob_required, int page)
++{
++	struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
++	int i, j;
++	uint8_t *oobbuf = chip->oob_poi;
++	uint32_t mlc_isr;
++	int res;
++	uint8_t *dma_buf;
++	bool dma_mapped;
++
++	if ((void *)buf <= high_memory) {
++		dma_buf = buf;
++		dma_mapped = true;
++	} else {
++		dma_buf = host->dma_buf;
++		dma_mapped = false;
++	}
++
++	/* Writing Command and Address */
++	chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
++
++	/* For all sub-pages */
++	for (i = 0; i < host->mlcsubpages; i++) {
++		/* Start Auto Decode Command */
++		writeb(0x00, MLC_ECC_AUTO_DEC_REG(host->io_base));
++
++		/* Wait for Controller Ready */
++		lpc32xx_waitfunc_controller(mtd, chip);
++
++		/* Check ECC Error status */
++		mlc_isr = readl(MLC_ISR(host->io_base));
++		if (mlc_isr & MLCISR_DECODER_FAILURE) {
++			mtd->ecc_stats.failed++;
++			dev_warn(&mtd->dev, "%s: DECODER_FAILURE\n", __func__);
++		} else if (mlc_isr & MLCISR_ERRORS_DETECTED) {
++			mtd->ecc_stats.corrected += ((mlc_isr >> 4) & 0x3) + 1;
++		}
++
++		/* Read 512 + 16 Bytes */
++		if (use_dma) {
++			res = lpc32xx_xmit_dma(mtd, dma_buf + i * 512, 512,
++					       DMA_DEV_TO_MEM);
++			if (res)
++				return res;
++		} else {
++			for (j = 0; j < (512 >> 2); j++) {
++				*((uint32_t *)(buf)) =
++					readl(MLC_BUFF(host->io_base));
++				buf += 4;
++			}
++		}
++		for (j = 0; j < (16 >> 2); j++) {
++			*((uint32_t *)(oobbuf)) =
++				readl(MLC_BUFF(host->io_base));
++			oobbuf += 4;
++		}
++	}
++
++	if (use_dma && !dma_mapped)
++		memcpy(buf, dma_buf, mtd->writesize);
++
++	return 0;
++}
++
++static int lpc32xx_write_page_lowlevel(struct mtd_info *mtd,
++				       struct nand_chip *chip,
++				       const uint8_t *buf, int oob_required,
++				       int page)
++{
++	struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
++	const uint8_t *oobbuf = chip->oob_poi;
++	uint8_t *dma_buf = (uint8_t *)buf;
++	int res;
++	int i, j;
++
++	if (use_dma && (void *)buf >= high_memory) {
++		dma_buf = host->dma_buf;
++		memcpy(dma_buf, buf, mtd->writesize);
++	}
++
++	for (i = 0; i < host->mlcsubpages; i++) {
++		/* Start Encode */
++		writeb(0x00, MLC_ECC_ENC_REG(host->io_base));
++
++		/* Write 512 + 6 Bytes to Buffer */
++		if (use_dma) {
++			res = lpc32xx_xmit_dma(mtd, dma_buf + i * 512, 512,
++					       DMA_MEM_TO_DEV);
++			if (res)
++				return res;
++		} else {
++			for (j = 0; j < (512 >> 2); j++) {
++				writel(*((uint32_t *)(buf)),
++				       MLC_BUFF(host->io_base));
++				buf += 4;
++			}
++		}
++		writel(*((uint32_t *)(oobbuf)), MLC_BUFF(host->io_base));
++		oobbuf += 4;
++		writew(*((uint16_t *)(oobbuf)), MLC_BUFF(host->io_base));
++		oobbuf += 12;
++
++		/* Auto Encode w/ Bit 8 = 0 (see LPC MLC Controller manual) */
++		writeb(0x00, MLC_ECC_AUTO_ENC_REG(host->io_base));
++
++		/* Wait for Controller Ready */
++		lpc32xx_waitfunc_controller(mtd, chip);
++	}
++	return 0;
++}
++
++static int lpc32xx_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
++			    int page)
++{
++	struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
++
++	/* Read whole page - necessary with MLC controller! */
++	lpc32xx_read_page(mtd, chip, host->dummy_buf, 1, page);
++
++	return 0;
++}
++
++static int lpc32xx_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
++			      int page)
++{
++	/* None, write_oob conflicts with the automatic LPC MLC ECC decoder! */
++	return 0;
++}
++
++/* Prepares MLC for transfers with H/W ECC enabled: always enabled anyway */
++static void lpc32xx_ecc_enable(struct mtd_info *mtd, int mode)
++{
++	/* Always enabled! */
++}
++
++static int lpc32xx_dma_setup(struct lpc32xx_nand_host *host)
++{
++	struct mtd_info *mtd = nand_to_mtd(&host->nand_chip);
++	dma_cap_mask_t mask;
++
++	if (!host->pdata || !host->pdata->dma_filter) {
++		dev_err(mtd->dev.parent, "no DMA platform data\n");
++		return -ENOENT;
++	}
++
++	dma_cap_zero(mask);
++	dma_cap_set(DMA_SLAVE, mask);
++	host->dma_chan = dma_request_channel(mask, host->pdata->dma_filter,
++					     "nand-mlc");
++	if (!host->dma_chan) {
++		dev_err(mtd->dev.parent, "Failed to request DMA channel\n");
++		return -EBUSY;
++	}
++
++	/*
++	 * Set direction to a sensible value even if the dmaengine driver
++	 * should ignore it. With the default (DMA_MEM_TO_MEM), the amba-pl08x
++	 * driver criticizes it as "alien transfer direction".
++	 */
++	host->dma_slave_config.direction = DMA_DEV_TO_MEM;
++	host->dma_slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
++	host->dma_slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
++	host->dma_slave_config.src_maxburst = 128;
++	host->dma_slave_config.dst_maxburst = 128;
++	/* DMA controller does flow control: */
++	host->dma_slave_config.device_fc = false;
++	host->dma_slave_config.src_addr = MLC_BUFF(host->io_base_phy);
++	host->dma_slave_config.dst_addr = MLC_BUFF(host->io_base_phy);
++	if (dmaengine_slave_config(host->dma_chan, &host->dma_slave_config)) {
++		dev_err(mtd->dev.parent, "Failed to setup DMA slave\n");
++		goto out1;
++	}
++
++	return 0;
++out1:
++	dma_release_channel(host->dma_chan);
++	return -ENXIO;
++}
++
++static struct lpc32xx_nand_cfg_mlc *lpc32xx_parse_dt(struct device *dev)
++{
++	struct lpc32xx_nand_cfg_mlc *ncfg;
++	struct device_node *np = dev->of_node;
++
++	ncfg = devm_kzalloc(dev, sizeof(*ncfg), GFP_KERNEL);
++	if (!ncfg)
++		return NULL;
++
++	of_property_read_u32(np, "nxp,tcea-delay", &ncfg->tcea_delay);
++	of_property_read_u32(np, "nxp,busy-delay", &ncfg->busy_delay);
++	of_property_read_u32(np, "nxp,nand-ta", &ncfg->nand_ta);
++	of_property_read_u32(np, "nxp,rd-high", &ncfg->rd_high);
++	of_property_read_u32(np, "nxp,rd-low", &ncfg->rd_low);
++	of_property_read_u32(np, "nxp,wr-high", &ncfg->wr_high);
++	of_property_read_u32(np, "nxp,wr-low", &ncfg->wr_low);
++
++	if (!ncfg->tcea_delay || !ncfg->busy_delay || !ncfg->nand_ta ||
++	    !ncfg->rd_high || !ncfg->rd_low || !ncfg->wr_high ||
++	    !ncfg->wr_low) {
++		dev_err(dev, "chip parameters not specified correctly\n");
++		return NULL;
++	}
++
++	ncfg->wp_gpio = of_get_named_gpio(np, "gpios", 0);
++
++	return ncfg;
++}
++
++/*
++ * Probe for NAND controller
++ */
++static int lpc32xx_nand_probe(struct platform_device *pdev)
++{
++	struct lpc32xx_nand_host *host;
++	struct mtd_info *mtd;
++	struct nand_chip *nand_chip;
++	struct resource *rc;
++	int res;
++
++	/* Allocate memory for the device structure (and zero it) */
++	host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
++	if (!host)
++		return -ENOMEM;
++
++	rc = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	host->io_base = devm_ioremap_resource(&pdev->dev, rc);
++	if (IS_ERR(host->io_base))
++		return PTR_ERR(host->io_base);
++	
++	host->io_base_phy = rc->start;
++
++	nand_chip = &host->nand_chip;
++	mtd = nand_to_mtd(nand_chip);
++	if (pdev->dev.of_node)
++		host->ncfg = lpc32xx_parse_dt(&pdev->dev);
++	if (!host->ncfg) {
++		dev_err(&pdev->dev,
++			"Missing or bad NAND config from device tree\n");
++		return -ENOENT;
++	}
++	if (host->ncfg->wp_gpio == -EPROBE_DEFER)
++		return -EPROBE_DEFER;
++	if (gpio_is_valid(host->ncfg->wp_gpio) &&
++			gpio_request(host->ncfg->wp_gpio, "NAND WP")) {
++		dev_err(&pdev->dev, "GPIO not available\n");
++		return -EBUSY;
++	}
++	lpc32xx_wp_disable(host);
++
++	host->pdata = dev_get_platdata(&pdev->dev);
++
++	/* link the private data structures */
++	nand_set_controller_data(nand_chip, host);
++	nand_set_flash_node(nand_chip, pdev->dev.of_node);
++	mtd->dev.parent = &pdev->dev;
++
++	/* Get NAND clock */
++	host->clk = clk_get(&pdev->dev, NULL);
++	if (IS_ERR(host->clk)) {
++		dev_err(&pdev->dev, "Clock initialization failure\n");
++		res = -ENOENT;
++		goto err_exit1;
++	}
++	res = clk_prepare_enable(host->clk);
++	if (res)
++		goto err_put_clk;
++
++	nand_chip->cmd_ctrl = lpc32xx_nand_cmd_ctrl;
++	nand_chip->dev_ready = lpc32xx_nand_device_ready;
++	nand_chip->chip_delay = 25; /* us */
++	nand_chip->IO_ADDR_R = MLC_DATA(host->io_base);
++	nand_chip->IO_ADDR_W = MLC_DATA(host->io_base);
++
++	/* Init NAND controller */
++	lpc32xx_nand_setup(host);
++
++	platform_set_drvdata(pdev, host);
++
++	/* Initialize function pointers */
++	nand_chip->ecc.hwctl = lpc32xx_ecc_enable;
++	nand_chip->ecc.read_page_raw = lpc32xx_read_page;
++	nand_chip->ecc.read_page = lpc32xx_read_page;
++	nand_chip->ecc.write_page_raw = lpc32xx_write_page_lowlevel;
++	nand_chip->ecc.write_page = lpc32xx_write_page_lowlevel;
++	nand_chip->ecc.write_oob = lpc32xx_write_oob;
++	nand_chip->ecc.read_oob = lpc32xx_read_oob;
++	nand_chip->ecc.strength = 4;
++	nand_chip->ecc.bytes = 10;
++	nand_chip->waitfunc = lpc32xx_waitfunc;
++
++	nand_chip->options = NAND_NO_SUBPAGE_WRITE;
++	nand_chip->bbt_options = NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB;
++	nand_chip->bbt_td = &lpc32xx_nand_bbt;
++	nand_chip->bbt_md = &lpc32xx_nand_bbt_mirror;
++
++	if (use_dma) {
++		res = lpc32xx_dma_setup(host);
++		if (res) {
++			res = -EIO;
++			goto err_exit2;
++		}
++	}
++
++	/*
++	 * Scan to find existance of the device and
++	 * Get the type of NAND device SMALL block or LARGE block
++	 */
++	res = nand_scan_ident(mtd, 1, NULL);
++	if (res)
++		goto err_exit3;
++
++	host->dma_buf = devm_kzalloc(&pdev->dev, mtd->writesize, GFP_KERNEL);
++	if (!host->dma_buf) {
++		res = -ENOMEM;
++		goto err_exit3;
++	}
++
++	host->dummy_buf = devm_kzalloc(&pdev->dev, mtd->writesize, GFP_KERNEL);
++	if (!host->dummy_buf) {
++		res = -ENOMEM;
++		goto err_exit3;
++	}
++
++	nand_chip->ecc.mode = NAND_ECC_HW;
++	nand_chip->ecc.size = 512;
++	mtd_set_ooblayout(mtd, &lpc32xx_ooblayout_ops);
++	host->mlcsubpages = mtd->writesize / 512;
++
++	/* initially clear interrupt status */
++	readb(MLC_IRQ_SR(host->io_base));
++
++	init_completion(&host->comp_nand);
++	init_completion(&host->comp_controller);
++
++	host->irq = platform_get_irq(pdev, 0);
++	if (host->irq < 0) {
++		dev_err(&pdev->dev, "failed to get platform irq\n");
++		res = -EINVAL;
++		goto err_exit3;
++	}
++
++	if (request_irq(host->irq, (irq_handler_t)&lpc3xxx_nand_irq,
++			IRQF_TRIGGER_HIGH, DRV_NAME, host)) {
++		dev_err(&pdev->dev, "Error requesting NAND IRQ\n");
++		res = -ENXIO;
++		goto err_exit3;
++	}
++
++	/*
++	 * Fills out all the uninitialized function pointers with the defaults
++	 * And scans for a bad block table if appropriate.
++	 */
++	res = nand_scan_tail(mtd);
++	if (res)
++		goto err_exit4;
++
++	mtd->name = DRV_NAME;
++
++	res = mtd_device_register(mtd, host->ncfg->parts,
++				  host->ncfg->num_parts);
++	if (!res)
++		return res;
++
++	nand_release(mtd);
++
++err_exit4:
++	free_irq(host->irq, host);
++err_exit3:
++	if (use_dma)
++		dma_release_channel(host->dma_chan);
++err_exit2:
++	clk_disable_unprepare(host->clk);
++err_put_clk:
++	clk_put(host->clk);
++err_exit1:
++	lpc32xx_wp_enable(host);
++	gpio_free(host->ncfg->wp_gpio);
++
++	return res;
++}
++
++/*
++ * Remove NAND device
++ */
++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);
++
++	nand_release(mtd);
++	free_irq(host->irq, host);
++	if (use_dma)
++		dma_release_channel(host->dma_chan);
++
++	clk_disable_unprepare(host->clk);
++	clk_put(host->clk);
++
++	lpc32xx_wp_enable(host);
++	gpio_free(host->ncfg->wp_gpio);
++
++	return 0;
++}
++
++#ifdef CONFIG_PM
++static int lpc32xx_nand_resume(struct platform_device *pdev)
++{
++	struct lpc32xx_nand_host *host = platform_get_drvdata(pdev);
++	int ret;
++
++	/* Re-enable NAND clock */
++	ret = clk_prepare_enable(host->clk);
++	if (ret)
++		return ret;
++
++	/* Fresh init of NAND controller */
++	lpc32xx_nand_setup(host);
++
++	/* Disable write protect */
++	lpc32xx_wp_disable(host);
++
++	return 0;
++}
++
++static int lpc32xx_nand_suspend(struct platform_device *pdev, pm_message_t pm)
++{
++	struct lpc32xx_nand_host *host = platform_get_drvdata(pdev);
++
++	/* Enable write protect for safety */
++	lpc32xx_wp_enable(host);
++
++	/* Disable clock */
++	clk_disable_unprepare(host->clk);
++	return 0;
++}
++
++#else
++#define lpc32xx_nand_resume NULL
++#define lpc32xx_nand_suspend NULL
++#endif
++
++static const struct of_device_id lpc32xx_nand_match[] = {
++	{ .compatible = "nxp,lpc3220-mlc" },
++	{ /* sentinel */ },
++};
++MODULE_DEVICE_TABLE(of, lpc32xx_nand_match);
++
++static struct platform_driver lpc32xx_nand_driver = {
++	.probe		= lpc32xx_nand_probe,
++	.remove		= lpc32xx_nand_remove,
++	.resume		= lpc32xx_nand_resume,
++	.suspend	= lpc32xx_nand_suspend,
++	.driver		= {
++		.name	= DRV_NAME,
++		.of_match_table = lpc32xx_nand_match,
++	},
++};
++
++module_platform_driver(lpc32xx_nand_driver);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>");
++MODULE_DESCRIPTION("NAND driver for the NXP LPC32XX MLC controller");
+diff --git a/drivers/mtd/nand/raw/lpc32xx_slc.c b/drivers/mtd/nand/raw/lpc32xx_slc.c
+new file mode 100644
+index 0000000..b61f28a
+--- /dev/null
++++ b/drivers/mtd/nand/raw/lpc32xx_slc.c
+@@ -0,0 +1,1039 @@
++/*
++ * NXP LPC32XX NAND SLC driver
++ *
++ * Authors:
++ *    Kevin Wells <kevin.wells@nxp.com>
++ *    Roland Stigge <stigge@antcom.de>
++ *
++ * Copyright © 2011 NXP Semiconductors
++ * Copyright © 2012 Roland Stigge
++ *
++ * 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/slab.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/rawnand.h>
++#include <linux/mtd/partitions.h>
++#include <linux/clk.h>
++#include <linux/err.h>
++#include <linux/delay.h>
++#include <linux/io.h>
++#include <linux/mm.h>
++#include <linux/dma-mapping.h>
++#include <linux/dmaengine.h>
++#include <linux/mtd/nand_ecc.h>
++#include <linux/gpio.h>
++#include <linux/of.h>
++#include <linux/of_gpio.h>
++#include <linux/mtd/lpc32xx_slc.h>
++
++#define LPC32XX_MODNAME		"lpc32xx-nand"
++
++/**********************************************************************
++* SLC NAND controller register offsets
++**********************************************************************/
++
++#define SLC_DATA(x)		(x + 0x000)
++#define SLC_ADDR(x)		(x + 0x004)
++#define SLC_CMD(x)		(x + 0x008)
++#define SLC_STOP(x)		(x + 0x00C)
++#define SLC_CTRL(x)		(x + 0x010)
++#define SLC_CFG(x)		(x + 0x014)
++#define SLC_STAT(x)		(x + 0x018)
++#define SLC_INT_STAT(x)		(x + 0x01C)
++#define SLC_IEN(x)		(x + 0x020)
++#define SLC_ISR(x)		(x + 0x024)
++#define SLC_ICR(x)		(x + 0x028)
++#define SLC_TAC(x)		(x + 0x02C)
++#define SLC_TC(x)		(x + 0x030)
++#define SLC_ECC(x)		(x + 0x034)
++#define SLC_DMA_DATA(x)		(x + 0x038)
++
++/**********************************************************************
++* slc_ctrl register definitions
++**********************************************************************/
++#define SLCCTRL_SW_RESET	(1 << 2) /* Reset the NAND controller bit */
++#define SLCCTRL_ECC_CLEAR	(1 << 1) /* Reset ECC bit */
++#define SLCCTRL_DMA_START	(1 << 0) /* Start DMA channel bit */
++
++/**********************************************************************
++* slc_cfg register definitions
++**********************************************************************/
++#define SLCCFG_CE_LOW		(1 << 5) /* Force CE low bit */
++#define SLCCFG_DMA_ECC		(1 << 4) /* Enable DMA ECC bit */
++#define SLCCFG_ECC_EN		(1 << 3) /* ECC enable bit */
++#define SLCCFG_DMA_BURST	(1 << 2) /* DMA burst bit */
++#define SLCCFG_DMA_DIR		(1 << 1) /* DMA write(0)/read(1) bit */
++#define SLCCFG_WIDTH		(1 << 0) /* External device width, 0=8bit */
++
++/**********************************************************************
++* slc_stat register definitions
++**********************************************************************/
++#define SLCSTAT_DMA_FIFO	(1 << 2) /* DMA FIFO has data bit */
++#define SLCSTAT_SLC_FIFO	(1 << 1) /* SLC FIFO has data bit */
++#define SLCSTAT_NAND_READY	(1 << 0) /* NAND device is ready bit */
++
++/**********************************************************************
++* slc_int_stat, slc_ien, slc_isr, and slc_icr register definitions
++**********************************************************************/
++#define SLCSTAT_INT_TC		(1 << 1) /* Transfer count bit */
++#define SLCSTAT_INT_RDY_EN	(1 << 0) /* Ready interrupt bit */
++
++/**********************************************************************
++* slc_tac register definitions
++**********************************************************************/
++/* Computation of clock cycles on basis of controller and device clock rates */
++#define SLCTAC_CLOCKS(c, n, s)	(min_t(u32, DIV_ROUND_UP(c, n) - 1, 0xF) << s)
++
++/* Clock setting for RDY write sample wait time in 2*n clocks */
++#define SLCTAC_WDR(n)		(((n) & 0xF) << 28)
++/* Write pulse width in clock cycles, 1 to 16 clocks */
++#define SLCTAC_WWIDTH(c, n)	(SLCTAC_CLOCKS(c, n, 24))
++/* Write hold time of control and data signals, 1 to 16 clocks */
++#define SLCTAC_WHOLD(c, n)	(SLCTAC_CLOCKS(c, n, 20))
++/* Write setup time of control and data signals, 1 to 16 clocks */
++#define SLCTAC_WSETUP(c, n)	(SLCTAC_CLOCKS(c, n, 16))
++/* Clock setting for RDY read sample wait time in 2*n clocks */
++#define SLCTAC_RDR(n)		(((n) & 0xF) << 12)
++/* Read pulse width in clock cycles, 1 to 16 clocks */
++#define SLCTAC_RWIDTH(c, n)	(SLCTAC_CLOCKS(c, n, 8))
++/* Read hold time of control and data signals, 1 to 16 clocks */
++#define SLCTAC_RHOLD(c, n)	(SLCTAC_CLOCKS(c, n, 4))
++/* Read setup time of control and data signals, 1 to 16 clocks */
++#define SLCTAC_RSETUP(c, n)	(SLCTAC_CLOCKS(c, n, 0))
++
++/**********************************************************************
++* slc_ecc register definitions
++**********************************************************************/
++/* ECC line party fetch macro */
++#define SLCECC_TO_LINEPAR(n)	(((n) >> 6) & 0x7FFF)
++#define SLCECC_TO_COLPAR(n)	((n) & 0x3F)
++
++/*
++ * DMA requires storage space for the DMA local buffer and the hardware ECC
++ * storage area. The DMA local buffer is only used if DMA mapping fails
++ * during runtime.
++ */
++#define LPC32XX_DMA_DATA_SIZE		4096
++#define LPC32XX_ECC_SAVE_SIZE		((4096 / 256) * 4)
++
++/* Number of bytes used for ECC stored in NAND per 256 bytes */
++#define LPC32XX_SLC_DEV_ECC_BYTES	3
++
++/*
++ * If the NAND base clock frequency can't be fetched, this frequency will be
++ * used instead as the base. This rate is used to setup the timing registers
++ * used for NAND accesses.
++ */
++#define LPC32XX_DEF_BUS_RATE		133250000
++
++/* Milliseconds for DMA FIFO timeout (unlikely anyway) */
++#define LPC32XX_DMA_TIMEOUT		100
++
++/*
++ * NAND ECC Layout for small page NAND devices
++ * Note: For large and huge page devices, the default layouts are used
++ */
++static int lpc32xx_ooblayout_ecc(struct mtd_info *mtd, int section,
++				 struct mtd_oob_region *oobregion)
++{
++	if (section)
++		return -ERANGE;
++
++	oobregion->length = 6;
++	oobregion->offset = 10;
++
++	return 0;
++}
++
++static int lpc32xx_ooblayout_free(struct mtd_info *mtd, int section,
++				  struct mtd_oob_region *oobregion)
++{
++	if (section > 1)
++		return -ERANGE;
++
++	if (!section) {
++		oobregion->offset = 0;
++		oobregion->length = 4;
++	} else {
++		oobregion->offset = 6;
++		oobregion->length = 4;
++	}
++
++	return 0;
++}
++
++static const struct mtd_ooblayout_ops lpc32xx_ooblayout_ops = {
++	.ecc = lpc32xx_ooblayout_ecc,
++	.free = lpc32xx_ooblayout_free,
++};
++
++static u8 bbt_pattern[] = {'B', 'b', 't', '0' };
++static u8 mirror_pattern[] = {'1', 't', 'b', 'B' };
++
++/*
++ * Small page FLASH BBT descriptors, marker at offset 0, version at offset 6
++ * Note: Large page devices used the default layout
++ */
++static struct nand_bbt_descr bbt_smallpage_main_descr = {
++	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
++		| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
++	.offs =	0,
++	.len = 4,
++	.veroffs = 6,
++	.maxblocks = 4,
++	.pattern = bbt_pattern
++};
++
++static struct nand_bbt_descr bbt_smallpage_mirror_descr = {
++	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
++		| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
++	.offs =	0,
++	.len = 4,
++	.veroffs = 6,
++	.maxblocks = 4,
++	.pattern = mirror_pattern
++};
++
++/*
++ * NAND platform configuration structure
++ */
++struct lpc32xx_nand_cfg_slc {
++	uint32_t wdr_clks;
++	uint32_t wwidth;
++	uint32_t whold;
++	uint32_t wsetup;
++	uint32_t rdr_clks;
++	uint32_t rwidth;
++	uint32_t rhold;
++	uint32_t rsetup;
++	int wp_gpio;
++	struct mtd_partition *parts;
++	unsigned num_parts;
++};
++
++struct lpc32xx_nand_host {
++	struct nand_chip	nand_chip;
++	struct lpc32xx_slc_platform_data *pdata;
++	struct clk		*clk;
++	void __iomem		*io_base;
++	struct lpc32xx_nand_cfg_slc *ncfg;
++
++	struct completion	comp;
++	struct dma_chan		*dma_chan;
++	uint32_t		dma_buf_len;
++	struct dma_slave_config	dma_slave_config;
++	struct scatterlist	sgl;
++
++	/*
++	 * DMA and CPU addresses of ECC work area and data buffer
++	 */
++	uint32_t		*ecc_buf;
++	uint8_t			*data_buf;
++	dma_addr_t		io_base_dma;
++};
++
++static void lpc32xx_nand_setup(struct lpc32xx_nand_host *host)
++{
++	uint32_t clkrate, tmp;
++
++	/* Reset SLC controller */
++	writel(SLCCTRL_SW_RESET, SLC_CTRL(host->io_base));
++	udelay(1000);
++
++	/* Basic setup */
++	writel(0, SLC_CFG(host->io_base));
++	writel(0, SLC_IEN(host->io_base));
++	writel((SLCSTAT_INT_TC | SLCSTAT_INT_RDY_EN),
++		SLC_ICR(host->io_base));
++
++	/* Get base clock for SLC block */
++	clkrate = clk_get_rate(host->clk);
++	if (clkrate == 0)
++		clkrate = LPC32XX_DEF_BUS_RATE;
++
++	/* Compute clock setup values */
++	tmp = SLCTAC_WDR(host->ncfg->wdr_clks) |
++		SLCTAC_WWIDTH(clkrate, host->ncfg->wwidth) |
++		SLCTAC_WHOLD(clkrate, host->ncfg->whold) |
++		SLCTAC_WSETUP(clkrate, host->ncfg->wsetup) |
++		SLCTAC_RDR(host->ncfg->rdr_clks) |
++		SLCTAC_RWIDTH(clkrate, host->ncfg->rwidth) |
++		SLCTAC_RHOLD(clkrate, host->ncfg->rhold) |
++		SLCTAC_RSETUP(clkrate, host->ncfg->rsetup);
++	writel(tmp, SLC_TAC(host->io_base));
++}
++
++/*
++ * Hardware specific access to control lines
++ */
++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 lpc32xx_nand_host *host = nand_get_controller_data(chip);
++
++	/* Does CE state need to be changed? */
++	tmp = readl(SLC_CFG(host->io_base));
++	if (ctrl & NAND_NCE)
++		tmp |= SLCCFG_CE_LOW;
++	else
++		tmp &= ~SLCCFG_CE_LOW;
++	writel(tmp, SLC_CFG(host->io_base));
++
++	if (cmd != NAND_CMD_NONE) {
++		if (ctrl & NAND_CLE)
++			writel(cmd, SLC_CMD(host->io_base));
++		else
++			writel(cmd, SLC_ADDR(host->io_base));
++	}
++}
++
++/*
++ * Read the Device Ready pin
++ */
++static int lpc32xx_nand_device_ready(struct mtd_info *mtd)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
++	int rdy = 0;
++
++	if ((readl(SLC_STAT(host->io_base)) & SLCSTAT_NAND_READY) != 0)
++		rdy = 1;
++
++	return rdy;
++}
++
++/*
++ * Enable NAND write protect
++ */
++static void lpc32xx_wp_enable(struct lpc32xx_nand_host *host)
++{
++	if (gpio_is_valid(host->ncfg->wp_gpio))
++		gpio_set_value(host->ncfg->wp_gpio, 0);
++}
++
++/*
++ * Disable NAND write protect
++ */
++static void lpc32xx_wp_disable(struct lpc32xx_nand_host *host)
++{
++	if (gpio_is_valid(host->ncfg->wp_gpio))
++		gpio_set_value(host->ncfg->wp_gpio, 1);
++}
++
++/*
++ * Prepares SLC for transfers with H/W ECC enabled
++ */
++static void lpc32xx_nand_ecc_enable(struct mtd_info *mtd, int mode)
++{
++	/* Hardware ECC is enabled automatically in hardware as needed */
++}
++
++/*
++ * Calculates the ECC for the data
++ */
++static int lpc32xx_nand_ecc_calculate(struct mtd_info *mtd,
++				      const unsigned char *buf,
++				      unsigned char *code)
++{
++	/*
++	 * ECC is calculated automatically in hardware during syndrome read
++	 * and write operations, so it doesn't need to be calculated here.
++	 */
++	return 0;
++}
++
++/*
++ * Read a single byte from NAND device
++ */
++static uint8_t lpc32xx_nand_read_byte(struct mtd_info *mtd)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
++
++	return (uint8_t)readl(SLC_DATA(host->io_base));
++}
++
++/*
++ * Simple device read without ECC
++ */
++static void lpc32xx_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
++
++	/* Direct device read with no ECC */
++	while (len-- > 0)
++		*buf++ = (uint8_t)readl(SLC_DATA(host->io_base));
++}
++
++/*
++ * Simple device write without ECC
++ */
++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 lpc32xx_nand_host *host = nand_get_controller_data(chip);
++
++	/* Direct device write with no ECC */
++	while (len-- > 0)
++		writel((uint32_t)*buf++, SLC_DATA(host->io_base));
++}
++
++/*
++ * Read the OOB data from the device without ECC using FIFO method
++ */
++static int lpc32xx_nand_read_oob_syndrome(struct mtd_info *mtd,
++					  struct nand_chip *chip, int page)
++{
++	chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
++	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
++
++	return 0;
++}
++
++/*
++ * Write the OOB data to the device without ECC using FIFO method
++ */
++static int lpc32xx_nand_write_oob_syndrome(struct mtd_info *mtd,
++	struct nand_chip *chip, int page)
++{
++	int status;
++
++	chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page);
++	chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
++
++	/* Send command to program the OOB data */
++	chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
++
++	status = chip->waitfunc(mtd, chip);
++
++	return status & NAND_STATUS_FAIL ? -EIO : 0;
++}
++
++/*
++ * Fills in the ECC fields in the OOB buffer with the hardware generated ECC
++ */
++static void lpc32xx_slc_ecc_copy(uint8_t *spare, const uint32_t *ecc, int count)
++{
++	int i;
++
++	for (i = 0; i < (count * 3); i += 3) {
++		uint32_t ce = ecc[i / 3];
++		ce = ~(ce << 2) & 0xFFFFFF;
++		spare[i + 2] = (uint8_t)(ce & 0xFF);
++		ce >>= 8;
++		spare[i + 1] = (uint8_t)(ce & 0xFF);
++		ce >>= 8;
++		spare[i] = (uint8_t)(ce & 0xFF);
++	}
++}
++
++static void lpc32xx_dma_complete_func(void *completion)
++{
++	complete(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 lpc32xx_nand_host *host = nand_get_controller_data(chip);
++	struct dma_async_tx_descriptor *desc;
++	int flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
++	int res;
++
++	host->dma_slave_config.direction = dir;
++	host->dma_slave_config.src_addr = dma;
++	host->dma_slave_config.dst_addr = dma;
++	host->dma_slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
++	host->dma_slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
++	host->dma_slave_config.src_maxburst = 4;
++	host->dma_slave_config.dst_maxburst = 4;
++	/* DMA controller does flow control: */
++	host->dma_slave_config.device_fc = false;
++	if (dmaengine_slave_config(host->dma_chan, &host->dma_slave_config)) {
++		dev_err(mtd->dev.parent, "Failed to setup DMA slave\n");
++		return -ENXIO;
++	}
++
++	sg_init_one(&host->sgl, mem, len);
++
++	res = dma_map_sg(host->dma_chan->device->dev, &host->sgl, 1,
++			 DMA_BIDIRECTIONAL);
++	if (res != 1) {
++		dev_err(mtd->dev.parent, "Failed to map sg list\n");
++		return -ENXIO;
++	}
++	desc = dmaengine_prep_slave_sg(host->dma_chan, &host->sgl, 1, dir,
++				       flags);
++	if (!desc) {
++		dev_err(mtd->dev.parent, "Failed to prepare slave sg\n");
++		goto out1;
++	}
++
++	init_completion(&host->comp);
++	desc->callback = lpc32xx_dma_complete_func;
++	desc->callback_param = &host->comp;
++
++	dmaengine_submit(desc);
++	dma_async_issue_pending(host->dma_chan);
++
++	wait_for_completion_timeout(&host->comp, msecs_to_jiffies(1000));
++
++	dma_unmap_sg(host->dma_chan->device->dev, &host->sgl, 1,
++		     DMA_BIDIRECTIONAL);
++
++	return 0;
++out1:
++	dma_unmap_sg(host->dma_chan->device->dev, &host->sgl, 1,
++		     DMA_BIDIRECTIONAL);
++	return -ENXIO;
++}
++
++/*
++ * DMA read/write transfers with ECC support
++ */
++static int lpc32xx_xfer(struct mtd_info *mtd, uint8_t *buf, int eccsubpages,
++			int read)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
++	int i, status = 0;
++	unsigned long timeout;
++	int res;
++	enum dma_transfer_direction dir =
++		read ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV;
++	uint8_t *dma_buf;
++	bool dma_mapped;
++
++	if ((void *)buf <= high_memory) {
++		dma_buf = buf;
++		dma_mapped = true;
++	} else {
++		dma_buf = host->data_buf;
++		dma_mapped = false;
++		if (!read)
++			memcpy(host->data_buf, buf, mtd->writesize);
++	}
++
++	if (read) {
++		writel(readl(SLC_CFG(host->io_base)) |
++		       SLCCFG_DMA_DIR | SLCCFG_ECC_EN | SLCCFG_DMA_ECC |
++		       SLCCFG_DMA_BURST, SLC_CFG(host->io_base));
++	} else {
++		writel((readl(SLC_CFG(host->io_base)) |
++			SLCCFG_ECC_EN | SLCCFG_DMA_ECC | SLCCFG_DMA_BURST) &
++		       ~SLCCFG_DMA_DIR,
++			SLC_CFG(host->io_base));
++	}
++
++	/* Clear initial ECC */
++	writel(SLCCTRL_ECC_CLEAR, SLC_CTRL(host->io_base));
++
++	/* Transfer size is data area only */
++	writel(mtd->writesize, SLC_TC(host->io_base));
++
++	/* Start transfer in the NAND controller */
++	writel(readl(SLC_CTRL(host->io_base)) | SLCCTRL_DMA_START,
++	       SLC_CTRL(host->io_base));
++
++	for (i = 0; i < chip->ecc.steps; i++) {
++		/* Data */
++		res = lpc32xx_xmit_dma(mtd, SLC_DMA_DATA(host->io_base_dma),
++				       dma_buf + i * chip->ecc.size,
++				       mtd->writesize / chip->ecc.steps, dir);
++		if (res)
++			return res;
++
++		/* Always _read_ ECC */
++		if (i == chip->ecc.steps - 1)
++			break;
++		if (!read) /* ECC availability delayed on write */
++			udelay(10);
++		res = lpc32xx_xmit_dma(mtd, SLC_ECC(host->io_base_dma),
++				       &host->ecc_buf[i], 4, DMA_DEV_TO_MEM);
++		if (res)
++			return res;
++	}
++
++	/*
++	 * According to NXP, the DMA can be finished here, but the NAND
++	 * controller may still have buffered data. After porting to using the
++	 * dmaengine DMA driver (amba-pl080), the condition (DMA_FIFO empty)
++	 * appears to be always true, according to tests. Keeping the check for
++	 * safety reasons for now.
++	 */
++	if (readl(SLC_STAT(host->io_base)) & SLCSTAT_DMA_FIFO) {
++		dev_warn(mtd->dev.parent, "FIFO not empty!\n");
++		timeout = jiffies + msecs_to_jiffies(LPC32XX_DMA_TIMEOUT);
++		while ((readl(SLC_STAT(host->io_base)) & SLCSTAT_DMA_FIFO) &&
++		       time_before(jiffies, timeout))
++			cpu_relax();
++		if (!time_before(jiffies, timeout)) {
++			dev_err(mtd->dev.parent, "FIFO held data too long\n");
++			status = -EIO;
++		}
++	}
++
++	/* Read last calculated ECC value */
++	if (!read)
++		udelay(10);
++	host->ecc_buf[chip->ecc.steps - 1] =
++		readl(SLC_ECC(host->io_base));
++
++	/* Flush DMA */
++	dmaengine_terminate_all(host->dma_chan);
++
++	if (readl(SLC_STAT(host->io_base)) & SLCSTAT_DMA_FIFO ||
++	    readl(SLC_TC(host->io_base))) {
++		/* Something is left in the FIFO, something is wrong */
++		dev_err(mtd->dev.parent, "DMA FIFO failure\n");
++		status = -EIO;
++	}
++
++	/* Stop DMA & HW ECC */
++	writel(readl(SLC_CTRL(host->io_base)) & ~SLCCTRL_DMA_START,
++	       SLC_CTRL(host->io_base));
++	writel(readl(SLC_CFG(host->io_base)) &
++	       ~(SLCCFG_DMA_DIR | SLCCFG_ECC_EN | SLCCFG_DMA_ECC |
++		 SLCCFG_DMA_BURST), SLC_CFG(host->io_base));
++
++	if (!dma_mapped && read)
++		memcpy(buf, host->data_buf, mtd->writesize);
++
++	return status;
++}
++
++/*
++ * Read the data and OOB data from the device, use ECC correction with the
++ * data, disable ECC for the OOB data
++ */
++static int lpc32xx_nand_read_page_syndrome(struct mtd_info *mtd,
++					   struct nand_chip *chip, uint8_t *buf,
++					   int oob_required, int page)
++{
++	struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
++	struct mtd_oob_region oobregion = { };
++	int stat, i, status, error;
++	uint8_t *oobecc, tmpecc[LPC32XX_ECC_SAVE_SIZE];
++
++	/* Issue read command */
++	chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
++
++	/* Read data and oob, calculate ECC */
++	status = lpc32xx_xfer(mtd, buf, chip->ecc.steps, 1);
++
++	/* Get OOB data */
++	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
++
++	/* Convert to stored ECC format */
++	lpc32xx_slc_ecc_copy(tmpecc, (uint32_t *) host->ecc_buf, chip->ecc.steps);
++
++	/* Pointer to ECC data retrieved from NAND spare area */
++	error = mtd_ooblayout_ecc(mtd, 0, &oobregion);
++	if (error)
++		return error;
++
++	oobecc = chip->oob_poi + oobregion.offset;
++
++	for (i = 0; i < chip->ecc.steps; i++) {
++		stat = chip->ecc.correct(mtd, buf, oobecc,
++					 &tmpecc[i * chip->ecc.bytes]);
++		if (stat < 0)
++			mtd->ecc_stats.failed++;
++		else
++			mtd->ecc_stats.corrected += stat;
++
++		buf += chip->ecc.size;
++		oobecc += chip->ecc.bytes;
++	}
++
++	return status;
++}
++
++/*
++ * Read the data and OOB data from the device, no ECC correction with the
++ * data or OOB data
++ */
++static int lpc32xx_nand_read_page_raw_syndrome(struct mtd_info *mtd,
++					       struct nand_chip *chip,
++					       uint8_t *buf, int oob_required,
++					       int page)
++{
++	/* Issue read command */
++	chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
++
++	/* Raw reads can just use the FIFO interface */
++	chip->read_buf(mtd, buf, chip->ecc.size * chip->ecc.steps);
++	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
++
++	return 0;
++}
++
++/*
++ * Write the data and OOB data to the device, use ECC with the data,
++ * disable ECC for the OOB data
++ */
++static int lpc32xx_nand_write_page_syndrome(struct mtd_info *mtd,
++					    struct nand_chip *chip,
++					    const uint8_t *buf,
++					    int oob_required, int page)
++{
++	struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
++	struct mtd_oob_region oobregion = { };
++	uint8_t *pb;
++	int error;
++
++	/* Write data, calculate ECC on outbound data */
++	error = lpc32xx_xfer(mtd, (uint8_t *)buf, chip->ecc.steps, 0);
++	if (error)
++		return error;
++
++	/*
++	 * The calculated ECC needs some manual work done to it before
++	 * committing it to NAND. Process the calculated ECC and place
++	 * the resultant values directly into the OOB buffer. */
++	error = mtd_ooblayout_ecc(mtd, 0, &oobregion);
++	if (error)
++		return error;
++
++	pb = chip->oob_poi + oobregion.offset;
++	lpc32xx_slc_ecc_copy(pb, (uint32_t *)host->ecc_buf, chip->ecc.steps);
++
++	/* Write ECC data to device */
++	chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
++	return 0;
++}
++
++/*
++ * Write the data and OOB data to the device, no ECC correction with the
++ * data or OOB data
++ */
++static int lpc32xx_nand_write_page_raw_syndrome(struct mtd_info *mtd,
++						struct nand_chip *chip,
++						const uint8_t *buf,
++						int oob_required, int page)
++{
++	/* Raw writes can just use the FIFO interface */
++	chip->write_buf(mtd, buf, chip->ecc.size * chip->ecc.steps);
++	chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
++	return 0;
++}
++
++static int lpc32xx_nand_dma_setup(struct lpc32xx_nand_host *host)
++{
++	struct mtd_info *mtd = nand_to_mtd(&host->nand_chip);
++	dma_cap_mask_t mask;
++
++	if (!host->pdata || !host->pdata->dma_filter) {
++		dev_err(mtd->dev.parent, "no DMA platform data\n");
++		return -ENOENT;
++	}
++
++	dma_cap_zero(mask);
++	dma_cap_set(DMA_SLAVE, mask);
++	host->dma_chan = dma_request_channel(mask, host->pdata->dma_filter,
++					     "nand-slc");
++	if (!host->dma_chan) {
++		dev_err(mtd->dev.parent, "Failed to request DMA channel\n");
++		return -EBUSY;
++	}
++
++	return 0;
++}
++
++static struct lpc32xx_nand_cfg_slc *lpc32xx_parse_dt(struct device *dev)
++{
++	struct lpc32xx_nand_cfg_slc *ncfg;
++	struct device_node *np = dev->of_node;
++
++	ncfg = devm_kzalloc(dev, sizeof(*ncfg), GFP_KERNEL);
++	if (!ncfg)
++		return NULL;
++
++	of_property_read_u32(np, "nxp,wdr-clks", &ncfg->wdr_clks);
++	of_property_read_u32(np, "nxp,wwidth", &ncfg->wwidth);
++	of_property_read_u32(np, "nxp,whold", &ncfg->whold);
++	of_property_read_u32(np, "nxp,wsetup", &ncfg->wsetup);
++	of_property_read_u32(np, "nxp,rdr-clks", &ncfg->rdr_clks);
++	of_property_read_u32(np, "nxp,rwidth", &ncfg->rwidth);
++	of_property_read_u32(np, "nxp,rhold", &ncfg->rhold);
++	of_property_read_u32(np, "nxp,rsetup", &ncfg->rsetup);
++
++	if (!ncfg->wdr_clks || !ncfg->wwidth || !ncfg->whold ||
++	    !ncfg->wsetup || !ncfg->rdr_clks || !ncfg->rwidth ||
++	    !ncfg->rhold || !ncfg->rsetup) {
++		dev_err(dev, "chip parameters not specified correctly\n");
++		return NULL;
++	}
++
++	ncfg->wp_gpio = of_get_named_gpio(np, "gpios", 0);
++
++	return ncfg;
++}
++
++/*
++ * Probe for NAND controller
++ */
++static int lpc32xx_nand_probe(struct platform_device *pdev)
++{
++	struct lpc32xx_nand_host *host;
++	struct mtd_info *mtd;
++	struct nand_chip *chip;
++	struct resource *rc;
++	int res;
++
++	/* Allocate memory for the device structure (and zero it) */
++	host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
++	if (!host)
++		return -ENOMEM;
++
++	rc = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	host->io_base = devm_ioremap_resource(&pdev->dev, rc);
++	if (IS_ERR(host->io_base))
++		return PTR_ERR(host->io_base);
++
++	host->io_base_dma = rc->start;
++	if (pdev->dev.of_node)
++		host->ncfg = lpc32xx_parse_dt(&pdev->dev);
++	if (!host->ncfg) {
++		dev_err(&pdev->dev,
++			"Missing or bad NAND config from device tree\n");
++		return -ENOENT;
++	}
++	if (host->ncfg->wp_gpio == -EPROBE_DEFER)
++		return -EPROBE_DEFER;
++	if (gpio_is_valid(host->ncfg->wp_gpio) && devm_gpio_request(&pdev->dev,
++			host->ncfg->wp_gpio, "NAND WP")) {
++		dev_err(&pdev->dev, "GPIO not available\n");
++		return -EBUSY;
++	}
++	lpc32xx_wp_disable(host);
++
++	host->pdata = dev_get_platdata(&pdev->dev);
++
++	chip = &host->nand_chip;
++	mtd = nand_to_mtd(chip);
++	nand_set_controller_data(chip, host);
++	nand_set_flash_node(chip, pdev->dev.of_node);
++	mtd->owner = THIS_MODULE;
++	mtd->dev.parent = &pdev->dev;
++
++	/* Get NAND clock */
++	host->clk = devm_clk_get(&pdev->dev, NULL);
++	if (IS_ERR(host->clk)) {
++		dev_err(&pdev->dev, "Clock failure\n");
++		res = -ENOENT;
++		goto err_exit1;
++	}
++	res = clk_prepare_enable(host->clk);
++	if (res)
++		goto err_exit1;
++
++	/* Set NAND IO addresses and command/ready functions */
++	chip->IO_ADDR_R = SLC_DATA(host->io_base);
++	chip->IO_ADDR_W = SLC_DATA(host->io_base);
++	chip->cmd_ctrl = lpc32xx_nand_cmd_ctrl;
++	chip->dev_ready = lpc32xx_nand_device_ready;
++	chip->chip_delay = 20; /* 20us command delay time */
++
++	/* Init NAND controller */
++	lpc32xx_nand_setup(host);
++
++	platform_set_drvdata(pdev, host);
++
++	/* NAND callbacks for LPC32xx SLC hardware */
++	chip->ecc.mode = NAND_ECC_HW_SYNDROME;
++	chip->read_byte = lpc32xx_nand_read_byte;
++	chip->read_buf = lpc32xx_nand_read_buf;
++	chip->write_buf = lpc32xx_nand_write_buf;
++	chip->ecc.read_page_raw = lpc32xx_nand_read_page_raw_syndrome;
++	chip->ecc.read_page = lpc32xx_nand_read_page_syndrome;
++	chip->ecc.write_page_raw = lpc32xx_nand_write_page_raw_syndrome;
++	chip->ecc.write_page = lpc32xx_nand_write_page_syndrome;
++	chip->ecc.write_oob = lpc32xx_nand_write_oob_syndrome;
++	chip->ecc.read_oob = lpc32xx_nand_read_oob_syndrome;
++	chip->ecc.calculate = lpc32xx_nand_ecc_calculate;
++	chip->ecc.correct = nand_correct_data;
++	chip->ecc.strength = 1;
++	chip->ecc.hwctl = lpc32xx_nand_ecc_enable;
++
++	/*
++	 * Allocate a large enough buffer for a single huge page plus
++	 * extra space for the spare area and ECC storage area
++	 */
++	host->dma_buf_len = LPC32XX_DMA_DATA_SIZE + LPC32XX_ECC_SAVE_SIZE;
++	host->data_buf = devm_kzalloc(&pdev->dev, host->dma_buf_len,
++				      GFP_KERNEL);
++	if (host->data_buf == NULL) {
++		res = -ENOMEM;
++		goto err_exit2;
++	}
++
++	res = lpc32xx_nand_dma_setup(host);
++	if (res) {
++		res = -EIO;
++		goto err_exit2;
++	}
++
++	/* Find NAND device */
++	res = nand_scan_ident(mtd, 1, NULL);
++	if (res)
++		goto err_exit3;
++
++	/* OOB and ECC CPU and DMA work areas */
++	host->ecc_buf = (uint32_t *)(host->data_buf + LPC32XX_DMA_DATA_SIZE);
++
++	/*
++	 * Small page FLASH has a unique OOB layout, but large and huge
++	 * page FLASH use the standard layout. Small page FLASH uses a
++	 * custom BBT marker layout.
++	 */
++	if (mtd->writesize <= 512)
++		mtd_set_ooblayout(mtd, &lpc32xx_ooblayout_ops);
++
++	/* These sizes remain the same regardless of page size */
++	chip->ecc.size = 256;
++	chip->ecc.bytes = LPC32XX_SLC_DEV_ECC_BYTES;
++	chip->ecc.prepad = chip->ecc.postpad = 0;
++
++	/*
++	 * Use a custom BBT marker setup for small page FLASH that
++	 * won't interfere with the ECC layout. Large and huge page
++	 * FLASH use the standard layout.
++	 */
++	if ((chip->bbt_options & NAND_BBT_USE_FLASH) &&
++	    mtd->writesize <= 512) {
++		chip->bbt_td = &bbt_smallpage_main_descr;
++		chip->bbt_md = &bbt_smallpage_mirror_descr;
++	}
++
++	/*
++	 * Fills out all the uninitialized function pointers with the defaults
++	 */
++	res = nand_scan_tail(mtd);
++	if (res)
++		goto err_exit3;
++
++	mtd->name = "nxp_lpc3220_slc";
++	res = mtd_device_register(mtd, host->ncfg->parts,
++				  host->ncfg->num_parts);
++	if (!res)
++		return res;
++
++	nand_release(mtd);
++
++err_exit3:
++	dma_release_channel(host->dma_chan);
++err_exit2:
++	clk_disable_unprepare(host->clk);
++err_exit1:
++	lpc32xx_wp_enable(host);
++
++	return res;
++}
++
++/*
++ * Remove NAND device.
++ */
++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);
++
++	nand_release(mtd);
++	dma_release_channel(host->dma_chan);
++
++	/* Force CE high */
++	tmp = readl(SLC_CTRL(host->io_base));
++	tmp &= ~SLCCFG_CE_LOW;
++	writel(tmp, SLC_CTRL(host->io_base));
++
++	clk_disable_unprepare(host->clk);
++	lpc32xx_wp_enable(host);
++
++	return 0;
++}
++
++#ifdef CONFIG_PM
++static int lpc32xx_nand_resume(struct platform_device *pdev)
++{
++	struct lpc32xx_nand_host *host = platform_get_drvdata(pdev);
++	int ret;
++
++	/* Re-enable NAND clock */
++	ret = clk_prepare_enable(host->clk);
++	if (ret)
++		return ret;
++
++	/* Fresh init of NAND controller */
++	lpc32xx_nand_setup(host);
++
++	/* Disable write protect */
++	lpc32xx_wp_disable(host);
++
++	return 0;
++}
++
++static int lpc32xx_nand_suspend(struct platform_device *pdev, pm_message_t pm)
++{
++	uint32_t tmp;
++	struct lpc32xx_nand_host *host = platform_get_drvdata(pdev);
++
++	/* Force CE high */
++	tmp = readl(SLC_CTRL(host->io_base));
++	tmp &= ~SLCCFG_CE_LOW;
++	writel(tmp, SLC_CTRL(host->io_base));
++
++	/* Enable write protect for safety */
++	lpc32xx_wp_enable(host);
++
++	/* Disable clock */
++	clk_disable_unprepare(host->clk);
++
++	return 0;
++}
++
++#else
++#define lpc32xx_nand_resume NULL
++#define lpc32xx_nand_suspend NULL
++#endif
++
++static const struct of_device_id lpc32xx_nand_match[] = {
++	{ .compatible = "nxp,lpc3220-slc" },
++	{ /* sentinel */ },
++};
++MODULE_DEVICE_TABLE(of, lpc32xx_nand_match);
++
++static struct platform_driver lpc32xx_nand_driver = {
++	.probe		= lpc32xx_nand_probe,
++	.remove		= lpc32xx_nand_remove,
++	.resume		= lpc32xx_nand_resume,
++	.suspend	= lpc32xx_nand_suspend,
++	.driver		= {
++		.name	= LPC32XX_MODNAME,
++		.of_match_table = lpc32xx_nand_match,
++	},
++};
++
++module_platform_driver(lpc32xx_nand_driver);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Kevin Wells <kevin.wells@nxp.com>");
++MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>");
++MODULE_DESCRIPTION("NAND driver for the NXP LPC32XX SLC controller");
+diff --git a/drivers/mtd/nand/raw/mpc5121_nfc.c b/drivers/mtd/nand/raw/mpc5121_nfc.c
+new file mode 100644
+index 0000000..b6b97cc9
+--- /dev/null
++++ b/drivers/mtd/nand/raw/mpc5121_nfc.c
+@@ -0,0 +1,857 @@
++/*
++ * Copyright 2004-2008 Freescale Semiconductor, Inc.
++ * Copyright 2009 Semihalf.
++ *
++ * Approved as OSADL project by a majority of OSADL members and funded
++ * by OSADL membership fees in 2009;  for details see www.osadl.org.
++ *
++ * Based on original driver from Freescale Semiconductor
++ * written by John Rigby <jrigby@freescale.com> on basis
++ * of drivers/mtd/nand/mxc_nand.c. Reworked and extended
++ * Piotr Ziecik <kosmo@semihalf.com>.
++ *
++ * 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.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
++ * MA 02110-1301, USA.
++ */
++
++#include <linux/module.h>
++#include <linux/clk.h>
++#include <linux/gfp.h>
++#include <linux/delay.h>
++#include <linux/err.h>
++#include <linux/interrupt.h>
++#include <linux/io.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/rawnand.h>
++#include <linux/mtd/partitions.h>
++#include <linux/of_address.h>
++#include <linux/of_device.h>
++#include <linux/of_irq.h>
++#include <linux/of_platform.h>
++
++#include <asm/mpc5121.h>
++
++/* Addresses for NFC MAIN RAM BUFFER areas */
++#define NFC_MAIN_AREA(n)	((n) *  0x200)
++
++/* Addresses for NFC SPARE BUFFER areas */
++#define NFC_SPARE_BUFFERS	8
++#define NFC_SPARE_LEN		0x40
++#define NFC_SPARE_AREA(n)	(0x1000 + ((n) * NFC_SPARE_LEN))
++
++/* MPC5121 NFC registers */
++#define NFC_BUF_ADDR		0x1E04
++#define NFC_FLASH_ADDR		0x1E06
++#define NFC_FLASH_CMD		0x1E08
++#define NFC_CONFIG		0x1E0A
++#define NFC_ECC_STATUS1		0x1E0C
++#define NFC_ECC_STATUS2		0x1E0E
++#define NFC_SPAS		0x1E10
++#define NFC_WRPROT		0x1E12
++#define NFC_NF_WRPRST		0x1E18
++#define NFC_CONFIG1		0x1E1A
++#define NFC_CONFIG2		0x1E1C
++#define NFC_UNLOCKSTART_BLK0	0x1E20
++#define NFC_UNLOCKEND_BLK0	0x1E22
++#define NFC_UNLOCKSTART_BLK1	0x1E24
++#define NFC_UNLOCKEND_BLK1	0x1E26
++#define NFC_UNLOCKSTART_BLK2	0x1E28
++#define NFC_UNLOCKEND_BLK2	0x1E2A
++#define NFC_UNLOCKSTART_BLK3	0x1E2C
++#define NFC_UNLOCKEND_BLK3	0x1E2E
++
++/* Bit Definitions: NFC_BUF_ADDR */
++#define NFC_RBA_MASK		(7 << 0)
++#define NFC_ACTIVE_CS_SHIFT	5
++#define NFC_ACTIVE_CS_MASK	(3 << NFC_ACTIVE_CS_SHIFT)
++
++/* Bit Definitions: NFC_CONFIG */
++#define NFC_BLS_UNLOCKED	(1 << 1)
++
++/* Bit Definitions: NFC_CONFIG1 */
++#define NFC_ECC_4BIT		(1 << 0)
++#define NFC_FULL_PAGE_DMA	(1 << 1)
++#define NFC_SPARE_ONLY		(1 << 2)
++#define NFC_ECC_ENABLE		(1 << 3)
++#define NFC_INT_MASK		(1 << 4)
++#define NFC_BIG_ENDIAN		(1 << 5)
++#define NFC_RESET		(1 << 6)
++#define NFC_CE			(1 << 7)
++#define NFC_ONE_CYCLE		(1 << 8)
++#define NFC_PPB_32		(0 << 9)
++#define NFC_PPB_64		(1 << 9)
++#define NFC_PPB_128		(2 << 9)
++#define NFC_PPB_256		(3 << 9)
++#define NFC_PPB_MASK		(3 << 9)
++#define NFC_FULL_PAGE_INT	(1 << 11)
++
++/* Bit Definitions: NFC_CONFIG2 */
++#define NFC_COMMAND		(1 << 0)
++#define NFC_ADDRESS		(1 << 1)
++#define NFC_INPUT		(1 << 2)
++#define NFC_OUTPUT		(1 << 3)
++#define NFC_ID			(1 << 4)
++#define NFC_STATUS		(1 << 5)
++#define NFC_CMD_FAIL		(1 << 15)
++#define NFC_INT			(1 << 15)
++
++/* Bit Definitions: NFC_WRPROT */
++#define NFC_WPC_LOCK_TIGHT	(1 << 0)
++#define NFC_WPC_LOCK		(1 << 1)
++#define NFC_WPC_UNLOCK		(1 << 2)
++
++#define	DRV_NAME		"mpc5121_nfc"
++
++/* Timeouts */
++#define NFC_RESET_TIMEOUT	1000		/* 1 ms */
++#define NFC_TIMEOUT		(HZ / 10)	/* 1/10 s */
++
++struct mpc5121_nfc_prv {
++	struct nand_chip	chip;
++	int			irq;
++	void __iomem		*regs;
++	struct clk		*clk;
++	wait_queue_head_t	irq_waitq;
++	uint			column;
++	int			spareonly;
++	void __iomem		*csreg;
++	struct device		*dev;
++};
++
++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 mpc5121_nfc_prv *prv = nand_get_controller_data(chip);
++
++	return in_be16(prv->regs + 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 mpc5121_nfc_prv *prv = nand_get_controller_data(chip);
++
++	out_be16(prv->regs + reg, val);
++}
++
++/* Set bits in NFC register */
++static inline void nfc_set(struct mtd_info *mtd, uint reg, u16 bits)
++{
++	nfc_write(mtd, reg, nfc_read(mtd, reg) | bits);
++}
++
++/* Clear bits in NFC register */
++static inline void nfc_clear(struct mtd_info *mtd, uint reg, u16 bits)
++{
++	nfc_write(mtd, reg, nfc_read(mtd, reg) & ~bits);
++}
++
++/* Invoke address cycle */
++static inline void mpc5121_nfc_send_addr(struct mtd_info *mtd, u16 addr)
++{
++	nfc_write(mtd, NFC_FLASH_ADDR, addr);
++	nfc_write(mtd, NFC_CONFIG2, NFC_ADDRESS);
++	mpc5121_nfc_done(mtd);
++}
++
++/* Invoke command cycle */
++static inline void mpc5121_nfc_send_cmd(struct mtd_info *mtd, u16 cmd)
++{
++	nfc_write(mtd, NFC_FLASH_CMD, cmd);
++	nfc_write(mtd, NFC_CONFIG2, NFC_COMMAND);
++	mpc5121_nfc_done(mtd);
++}
++
++/* Send data from NFC buffers to NAND flash */
++static inline void mpc5121_nfc_send_prog_page(struct mtd_info *mtd)
++{
++	nfc_clear(mtd, NFC_BUF_ADDR, NFC_RBA_MASK);
++	nfc_write(mtd, NFC_CONFIG2, NFC_INPUT);
++	mpc5121_nfc_done(mtd);
++}
++
++/* Receive data from NAND flash */
++static inline void mpc5121_nfc_send_read_page(struct mtd_info *mtd)
++{
++	nfc_clear(mtd, NFC_BUF_ADDR, NFC_RBA_MASK);
++	nfc_write(mtd, NFC_CONFIG2, NFC_OUTPUT);
++	mpc5121_nfc_done(mtd);
++}
++
++/* Receive ID from NAND flash */
++static inline void mpc5121_nfc_send_read_id(struct mtd_info *mtd)
++{
++	nfc_clear(mtd, NFC_BUF_ADDR, NFC_RBA_MASK);
++	nfc_write(mtd, NFC_CONFIG2, NFC_ID);
++	mpc5121_nfc_done(mtd);
++}
++
++/* Receive status from NAND flash */
++static inline void mpc5121_nfc_send_read_status(struct mtd_info *mtd)
++{
++	nfc_clear(mtd, NFC_BUF_ADDR, NFC_RBA_MASK);
++	nfc_write(mtd, NFC_CONFIG2, NFC_STATUS);
++	mpc5121_nfc_done(mtd);
++}
++
++/* NFC interrupt handler */
++static irqreturn_t mpc5121_nfc_irq(int irq, void *data)
++{
++	struct mtd_info *mtd = data;
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip);
++
++	nfc_set(mtd, NFC_CONFIG1, NFC_INT_MASK);
++	wake_up(&prv->irq_waitq);
++
++	return IRQ_HANDLED;
++}
++
++/* Wait for operation complete */
++static void mpc5121_nfc_done(struct mtd_info *mtd)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip);
++	int rv;
++
++	if ((nfc_read(mtd, NFC_CONFIG2) & NFC_INT) == 0) {
++		nfc_clear(mtd, NFC_CONFIG1, NFC_INT_MASK);
++		rv = wait_event_timeout(prv->irq_waitq,
++			(nfc_read(mtd, NFC_CONFIG2) & NFC_INT), NFC_TIMEOUT);
++
++		if (!rv)
++			dev_warn(prv->dev,
++				"Timeout while waiting for interrupt.\n");
++	}
++
++	nfc_clear(mtd, NFC_CONFIG2, NFC_INT);
++}
++
++/* 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);
++	u32 pagemask = chip->pagemask;
++
++	if (column != -1) {
++		mpc5121_nfc_send_addr(mtd, column);
++		if (mtd->writesize > 512)
++			mpc5121_nfc_send_addr(mtd, column >> 8);
++	}
++
++	if (page != -1) {
++		do {
++			mpc5121_nfc_send_addr(mtd, page & 0xFF);
++			page >>= 8;
++			pagemask >>= 8;
++		} while (pagemask);
++	}
++}
++
++/* Control chip select signals */
++static void mpc5121_nfc_select_chip(struct mtd_info *mtd, int chip)
++{
++	if (chip < 0) {
++		nfc_clear(mtd, NFC_CONFIG1, NFC_CE);
++		return;
++	}
++
++	nfc_clear(mtd, NFC_BUF_ADDR, NFC_ACTIVE_CS_MASK);
++	nfc_set(mtd, NFC_BUF_ADDR, (chip << NFC_ACTIVE_CS_SHIFT) &
++							NFC_ACTIVE_CS_MASK);
++	nfc_set(mtd, NFC_CONFIG1, NFC_CE);
++}
++
++/* 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 mpc5121_nfc_prv *prv = nand_get_controller_data(chip);
++	struct device_node *dn;
++
++	dn = of_find_compatible_node(NULL, NULL, "fsl,mpc5121ads-cpld");
++	if (dn) {
++		prv->csreg = of_iomap(dn, 0);
++		of_node_put(dn);
++		if (!prv->csreg)
++			return -ENOMEM;
++
++		/* CPLD Register 9 controls NAND /CE Lines */
++		prv->csreg += 9;
++		return 0;
++	}
++
++	return -EINVAL;
++}
++
++/* 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 mpc5121_nfc_prv *prv = nand_get_controller_data(nand);
++	u8 v;
++
++	v = in_8(prv->csreg);
++	v |= 0x0F;
++
++	if (chip >= 0) {
++		mpc5121_nfc_select_chip(mtd, 0);
++		v &= ~(1 << chip);
++	} else
++		mpc5121_nfc_select_chip(mtd, -1);
++
++	out_8(prv->csreg, v);
++}
++
++/* Read NAND Ready/Busy signal */
++static int mpc5121_nfc_dev_ready(struct mtd_info *mtd)
++{
++	/*
++	 * NFC handles ready/busy signal internally. Therefore, this function
++	 * always returns status as ready.
++	 */
++	return 1;
++}
++
++/* Write command to NAND flash */
++static void mpc5121_nfc_command(struct mtd_info *mtd, unsigned command,
++							int column, int page)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip);
++
++	prv->column = (column >= 0) ? column : 0;
++	prv->spareonly = 0;
++
++	switch (command) {
++	case NAND_CMD_PAGEPROG:
++		mpc5121_nfc_send_prog_page(mtd);
++		break;
++	/*
++	 * NFC does not support sub-page reads and writes,
++	 * so emulate them using full page transfers.
++	 */
++	case NAND_CMD_READ0:
++		column = 0;
++		break;
++
++	case NAND_CMD_READ1:
++		prv->column += 256;
++		command = NAND_CMD_READ0;
++		column = 0;
++		break;
++
++	case NAND_CMD_READOOB:
++		prv->spareonly = 1;
++		command = NAND_CMD_READ0;
++		column = 0;
++		break;
++
++	case NAND_CMD_SEQIN:
++		mpc5121_nfc_command(mtd, NAND_CMD_READ0, column, page);
++		column = 0;
++		break;
++
++	case NAND_CMD_ERASE1:
++	case NAND_CMD_ERASE2:
++	case NAND_CMD_READID:
++	case NAND_CMD_STATUS:
++		break;
++
++	default:
++		return;
++	}
++
++	mpc5121_nfc_send_cmd(mtd, command);
++	mpc5121_nfc_addr_cycle(mtd, column, page);
++
++	switch (command) {
++	case NAND_CMD_READ0:
++		if (mtd->writesize > 512)
++			mpc5121_nfc_send_cmd(mtd, NAND_CMD_READSTART);
++		mpc5121_nfc_send_read_page(mtd);
++		break;
++
++	case NAND_CMD_READID:
++		mpc5121_nfc_send_read_id(mtd);
++		break;
++
++	case NAND_CMD_STATUS:
++		mpc5121_nfc_send_read_status(mtd);
++		if (chip->options & NAND_BUSWIDTH_16)
++			prv->column = 1;
++		else
++			prv->column = 0;
++		break;
++	}
++}
++
++/* Copy data from/to NFC spare buffers. */
++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 mpc5121_nfc_prv *prv = nand_get_controller_data(nand);
++	uint o, s, sbsize, blksize;
++
++	/*
++	 * NAND spare area is available through NFC spare buffers.
++	 * The NFC divides spare area into (page_size / 512) chunks.
++	 * Each chunk is placed into separate spare memory area, using
++	 * first (spare_size / num_of_chunks) bytes of the buffer.
++	 *
++	 * For NAND device in which the spare area is not divided fully
++	 * by the number of chunks, number of used bytes in each spare
++	 * buffer is rounded down to the nearest even number of bytes,
++	 * and all remaining bytes are added to the last used spare area.
++	 *
++	 * For more information read section 26.6.10 of MPC5121e
++	 * Microcontroller Reference Manual, Rev. 3.
++	 */
++
++	/* Calculate number of valid bytes in each spare buffer */
++	sbsize = (mtd->oobsize / (mtd->writesize / 512)) & ~1;
++
++	while (size) {
++		/* Calculate spare buffer number */
++		s = offset / sbsize;
++		if (s > NFC_SPARE_BUFFERS - 1)
++			s = NFC_SPARE_BUFFERS - 1;
++
++		/*
++		 * Calculate offset to requested data block in selected spare
++		 * buffer and its size.
++		 */
++		o = offset - (s * sbsize);
++		blksize = min(sbsize - o, size);
++
++		if (wr)
++			memcpy_toio(prv->regs + NFC_SPARE_AREA(s) + o,
++							buffer, blksize);
++		else
++			memcpy_fromio(buffer,
++				prv->regs + NFC_SPARE_AREA(s) + o, blksize);
++
++		buffer += blksize;
++		offset += blksize;
++		size -= blksize;
++	};
++}
++
++/* Copy data from/to NFC main and spare buffers */
++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 mpc5121_nfc_prv *prv = nand_get_controller_data(chip);
++	uint c = prv->column;
++	uint l;
++
++	/* Handle spare area access */
++	if (prv->spareonly || c >= mtd->writesize) {
++		/* Calculate offset from beginning of spare area */
++		if (c >= mtd->writesize)
++			c -= mtd->writesize;
++
++		prv->column += len;
++		mpc5121_nfc_copy_spare(mtd, c, buf, len, wr);
++		return;
++	}
++
++	/*
++	 * Handle main area access - limit copy length to prevent
++	 * crossing main/spare boundary.
++	 */
++	l = min((uint)len, mtd->writesize - c);
++	prv->column += l;
++
++	if (wr)
++		memcpy_toio(prv->regs + NFC_MAIN_AREA(0) + c, buf, l);
++	else
++		memcpy_fromio(buf, prv->regs + NFC_MAIN_AREA(0) + c, l);
++
++	/* Handle crossing main/spare boundary */
++	if (l != len) {
++		buf += l;
++		len -= l;
++		mpc5121_nfc_buf_copy(mtd, buf, len, wr);
++	}
++}
++
++/* Read data from NFC buffers */
++static void mpc5121_nfc_read_buf(struct mtd_info *mtd, u_char *buf, int len)
++{
++	mpc5121_nfc_buf_copy(mtd, buf, len, 0);
++}
++
++/* Write data to NFC buffers */
++static void mpc5121_nfc_write_buf(struct mtd_info *mtd,
++						const u_char *buf, int len)
++{
++	mpc5121_nfc_buf_copy(mtd, (u_char *)buf, len, 1);
++}
++
++/* Read byte from NFC buffers */
++static u8 mpc5121_nfc_read_byte(struct mtd_info *mtd)
++{
++	u8 tmp;
++
++	mpc5121_nfc_read_buf(mtd, &tmp, sizeof(tmp));
++
++	return tmp;
++}
++
++/* Read word from NFC buffers */
++static u16 mpc5121_nfc_read_word(struct mtd_info *mtd)
++{
++	u16 tmp;
++
++	mpc5121_nfc_read_buf(mtd, (u_char *)&tmp, sizeof(tmp));
++
++	return tmp;
++}
++
++/*
++ * Read NFC configuration from Reset Config Word
++ *
++ * NFC is configured during reset in basis of information stored
++ * in Reset Config Word. There is no other way to set NAND block
++ * size, spare size and bus width.
++ */
++static int mpc5121_nfc_read_hw_config(struct mtd_info *mtd)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip);
++	struct mpc512x_reset_module *rm;
++	struct device_node *rmnode;
++	uint rcw_pagesize = 0;
++	uint rcw_sparesize = 0;
++	uint rcw_width;
++	uint rcwh;
++	uint romloc, ps;
++	int ret = 0;
++
++	rmnode = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-reset");
++	if (!rmnode) {
++		dev_err(prv->dev, "Missing 'fsl,mpc5121-reset' "
++					"node in device tree!\n");
++		return -ENODEV;
++	}
++
++	rm = of_iomap(rmnode, 0);
++	if (!rm) {
++		dev_err(prv->dev, "Error mapping reset module node!\n");
++		ret = -EBUSY;
++		goto out;
++	}
++
++	rcwh = in_be32(&rm->rcwhr);
++
++	/* Bit 6: NFC bus width */
++	rcw_width = ((rcwh >> 6) & 0x1) ? 2 : 1;
++
++	/* Bit 7: NFC Page/Spare size */
++	ps = (rcwh >> 7) & 0x1;
++
++	/* Bits [22:21]: ROM Location */
++	romloc = (rcwh >> 21) & 0x3;
++
++	/* Decode RCW bits */
++	switch ((ps << 2) | romloc) {
++	case 0x00:
++	case 0x01:
++		rcw_pagesize = 512;
++		rcw_sparesize = 16;
++		break;
++	case 0x02:
++	case 0x03:
++		rcw_pagesize = 4096;
++		rcw_sparesize = 128;
++		break;
++	case 0x04:
++	case 0x05:
++		rcw_pagesize = 2048;
++		rcw_sparesize = 64;
++		break;
++	case 0x06:
++	case 0x07:
++		rcw_pagesize = 4096;
++		rcw_sparesize = 218;
++		break;
++	}
++
++	mtd->writesize = rcw_pagesize;
++	mtd->oobsize = rcw_sparesize;
++	if (rcw_width == 2)
++		chip->options |= NAND_BUSWIDTH_16;
++
++	dev_notice(prv->dev, "Configured for "
++				"%u-bit NAND, page size %u "
++				"with %u spare.\n",
++				rcw_width * 8, rcw_pagesize,
++				rcw_sparesize);
++	iounmap(rm);
++out:
++	of_node_put(rmnode);
++	return ret;
++}
++
++/* Free driver resources */
++static void mpc5121_nfc_free(struct device *dev, struct mtd_info *mtd)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip);
++
++	if (prv->clk)
++		clk_disable_unprepare(prv->clk);
++
++	if (prv->csreg)
++		iounmap(prv->csreg);
++}
++
++static int mpc5121_nfc_probe(struct platform_device *op)
++{
++	struct device_node *dn = op->dev.of_node;
++	struct clk *clk;
++	struct device *dev = &op->dev;
++	struct mpc5121_nfc_prv *prv;
++	struct resource res;
++	struct mtd_info *mtd;
++	struct nand_chip *chip;
++	unsigned long regs_paddr, regs_size;
++	const __be32 *chips_no;
++	int resettime = 0;
++	int retval = 0;
++	int rev, len;
++
++	/*
++	 * Check SoC revision. This driver supports only NFC
++	 * in MPC5121 revision 2 and MPC5123 revision 3.
++	 */
++	rev = (mfspr(SPRN_SVR) >> 4) & 0xF;
++	if ((rev != 2) && (rev != 3)) {
++		dev_err(dev, "SoC revision %u is not supported!\n", rev);
++		return -ENXIO;
++	}
++
++	prv = devm_kzalloc(dev, sizeof(*prv), GFP_KERNEL);
++	if (!prv)
++		return -ENOMEM;
++
++	chip = &prv->chip;
++	mtd = nand_to_mtd(chip);
++
++	mtd->dev.parent = dev;
++	nand_set_controller_data(chip, prv);
++	nand_set_flash_node(chip, dn);
++	prv->dev = dev;
++
++	/* Read NFC configuration from Reset Config Word */
++	retval = mpc5121_nfc_read_hw_config(mtd);
++	if (retval) {
++		dev_err(dev, "Unable to read NFC config!\n");
++		return retval;
++	}
++
++	prv->irq = irq_of_parse_and_map(dn, 0);
++	if (prv->irq == NO_IRQ) {
++		dev_err(dev, "Error mapping IRQ!\n");
++		return -EINVAL;
++	}
++
++	retval = of_address_to_resource(dn, 0, &res);
++	if (retval) {
++		dev_err(dev, "Error parsing memory region!\n");
++		return retval;
++	}
++
++	chips_no = of_get_property(dn, "chips", &len);
++	if (!chips_no || len != sizeof(*chips_no)) {
++		dev_err(dev, "Invalid/missing 'chips' property!\n");
++		return -EINVAL;
++	}
++
++	regs_paddr = res.start;
++	regs_size = resource_size(&res);
++
++	if (!devm_request_mem_region(dev, regs_paddr, regs_size, DRV_NAME)) {
++		dev_err(dev, "Error requesting memory region!\n");
++		return -EBUSY;
++	}
++
++	prv->regs = devm_ioremap(dev, regs_paddr, regs_size);
++	if (!prv->regs) {
++		dev_err(dev, "Error mapping memory region!\n");
++		return -ENOMEM;
++	}
++
++	mtd->name = "MPC5121 NAND";
++	chip->dev_ready = mpc5121_nfc_dev_ready;
++	chip->cmdfunc = mpc5121_nfc_command;
++	chip->read_byte = mpc5121_nfc_read_byte;
++	chip->read_word = mpc5121_nfc_read_word;
++	chip->read_buf = mpc5121_nfc_read_buf;
++	chip->write_buf = mpc5121_nfc_write_buf;
++	chip->select_chip = mpc5121_nfc_select_chip;
++	chip->onfi_set_features	= nand_onfi_get_set_features_notsupp;
++	chip->onfi_get_features	= nand_onfi_get_set_features_notsupp;
++	chip->bbt_options = NAND_BBT_USE_FLASH;
++	chip->ecc.mode = NAND_ECC_SOFT;
++	chip->ecc.algo = NAND_ECC_HAMMING;
++
++	/* Support external chip-select logic on ADS5121 board */
++	if (of_machine_is_compatible("fsl,mpc5121ads")) {
++		retval = ads5121_chipselect_init(mtd);
++		if (retval) {
++			dev_err(dev, "Chipselect init error!\n");
++			return retval;
++		}
++
++		chip->select_chip = ads5121_select_chip;
++	}
++
++	/* Enable NFC clock */
++	clk = devm_clk_get(dev, "ipg");
++	if (IS_ERR(clk)) {
++		dev_err(dev, "Unable to acquire NFC clock!\n");
++		retval = PTR_ERR(clk);
++		goto error;
++	}
++	retval = clk_prepare_enable(clk);
++	if (retval) {
++		dev_err(dev, "Unable to enable NFC clock!\n");
++		goto error;
++	}
++	prv->clk = clk;
++
++	/* Reset NAND Flash controller */
++	nfc_set(mtd, NFC_CONFIG1, NFC_RESET);
++	while (nfc_read(mtd, NFC_CONFIG1) & NFC_RESET) {
++		if (resettime++ >= NFC_RESET_TIMEOUT) {
++			dev_err(dev, "Timeout while resetting NFC!\n");
++			retval = -EINVAL;
++			goto error;
++		}
++
++		udelay(1);
++	}
++
++	/* Enable write to NFC memory */
++	nfc_write(mtd, NFC_CONFIG, NFC_BLS_UNLOCKED);
++
++	/* Enable write to all NAND pages */
++	nfc_write(mtd, NFC_UNLOCKSTART_BLK0, 0x0000);
++	nfc_write(mtd, NFC_UNLOCKEND_BLK0, 0xFFFF);
++	nfc_write(mtd, NFC_WRPROT, NFC_WPC_UNLOCK);
++
++	/*
++	 * Setup NFC:
++	 *	- Big Endian transfers,
++	 *	- Interrupt after full page read/write.
++	 */
++	nfc_write(mtd, NFC_CONFIG1, NFC_BIG_ENDIAN | NFC_INT_MASK |
++							NFC_FULL_PAGE_INT);
++
++	/* Set spare area size */
++	nfc_write(mtd, NFC_SPAS, mtd->oobsize >> 1);
++
++	init_waitqueue_head(&prv->irq_waitq);
++	retval = devm_request_irq(dev, prv->irq, &mpc5121_nfc_irq, 0, DRV_NAME,
++									mtd);
++	if (retval) {
++		dev_err(dev, "Error requesting IRQ!\n");
++		goto error;
++	}
++
++	/* Detect NAND chips */
++	retval = nand_scan(mtd, be32_to_cpup(chips_no));
++	if (retval) {
++		dev_err(dev, "NAND Flash not found !\n");
++		goto error;
++	}
++
++	/* Set erase block size */
++	switch (mtd->erasesize / mtd->writesize) {
++	case 32:
++		nfc_set(mtd, NFC_CONFIG1, NFC_PPB_32);
++		break;
++
++	case 64:
++		nfc_set(mtd, NFC_CONFIG1, NFC_PPB_64);
++		break;
++
++	case 128:
++		nfc_set(mtd, NFC_CONFIG1, NFC_PPB_128);
++		break;
++
++	case 256:
++		nfc_set(mtd, NFC_CONFIG1, NFC_PPB_256);
++		break;
++
++	default:
++		dev_err(dev, "Unsupported NAND flash!\n");
++		retval = -ENXIO;
++		goto error;
++	}
++
++	dev_set_drvdata(dev, mtd);
++
++	/* Register device in MTD */
++	retval = mtd_device_register(mtd, NULL, 0);
++	if (retval) {
++		dev_err(dev, "Error adding MTD device!\n");
++		goto error;
++	}
++
++	return 0;
++error:
++	mpc5121_nfc_free(dev, mtd);
++	return retval;
++}
++
++static int mpc5121_nfc_remove(struct platform_device *op)
++{
++	struct device *dev = &op->dev;
++	struct mtd_info *mtd = dev_get_drvdata(dev);
++
++	nand_release(mtd);
++	mpc5121_nfc_free(dev, mtd);
++
++	return 0;
++}
++
++static const struct of_device_id mpc5121_nfc_match[] = {
++	{ .compatible = "fsl,mpc5121-nfc", },
++	{},
++};
++MODULE_DEVICE_TABLE(of, mpc5121_nfc_match);
++
++static struct platform_driver mpc5121_nfc_driver = {
++	.probe		= mpc5121_nfc_probe,
++	.remove		= mpc5121_nfc_remove,
++	.driver		= {
++		.name = DRV_NAME,
++		.of_match_table = mpc5121_nfc_match,
++	},
++};
++
++module_platform_driver(mpc5121_nfc_driver);
++
++MODULE_AUTHOR("Freescale Semiconductor, Inc.");
++MODULE_DESCRIPTION("MPC5121 NAND MTD driver");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/mtd/nand/raw/mtk_ecc.c b/drivers/mtd/nand/raw/mtk_ecc.c
+new file mode 100644
+index 0000000..c51d214
+--- /dev/null
++++ b/drivers/mtd/nand/raw/mtk_ecc.c
+@@ -0,0 +1,544 @@
++/*
++ * MTK ECC controller driver.
++ * Copyright (C) 2016  MediaTek Inc.
++ * Authors:	Xiaolei Li		<xiaolei.li@mediatek.com>
++ *		Jorge Ramirez-Ortiz	<jorge.ramirez-ortiz@linaro.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.
++ *
++ * 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/platform_device.h>
++#include <linux/dma-mapping.h>
++#include <linux/interrupt.h>
++#include <linux/clk.h>
++#include <linux/module.h>
++#include <linux/iopoll.h>
++#include <linux/of.h>
++#include <linux/of_platform.h>
++#include <linux/mutex.h>
++
++#include "mtk_ecc.h"
++
++#define ECC_IDLE_MASK		BIT(0)
++#define ECC_IRQ_EN		BIT(0)
++#define ECC_PG_IRQ_SEL		BIT(1)
++#define ECC_OP_ENABLE		(1)
++#define ECC_OP_DISABLE		(0)
++
++#define ECC_ENCCON		(0x00)
++#define ECC_ENCCNFG		(0x04)
++#define		ECC_MODE_SHIFT		(5)
++#define		ECC_MS_SHIFT		(16)
++#define ECC_ENCDIADDR		(0x08)
++#define ECC_ENCIDLE		(0x0C)
++#define ECC_ENCIRQ_EN		(0x80)
++#define ECC_ENCIRQ_STA		(0x84)
++#define ECC_DECCON		(0x100)
++#define ECC_DECCNFG		(0x104)
++#define		DEC_EMPTY_EN		BIT(31)
++#define		DEC_CNFG_CORRECT	(0x3 << 12)
++#define ECC_DECIDLE		(0x10C)
++#define ECC_DECENUM0		(0x114)
++#define ECC_DECDONE		(0x124)
++#define ECC_DECIRQ_EN		(0x200)
++#define ECC_DECIRQ_STA		(0x204)
++
++#define ECC_TIMEOUT		(500000)
++
++#define ECC_IDLE_REG(op)	((op) == ECC_ENCODE ? ECC_ENCIDLE : ECC_DECIDLE)
++#define ECC_CTL_REG(op)		((op) == ECC_ENCODE ? ECC_ENCCON : ECC_DECCON)
++#define ECC_IRQ_REG(op)		((op) == ECC_ENCODE ? \
++					ECC_ENCIRQ_EN : ECC_DECIRQ_EN)
++
++struct mtk_ecc_caps {
++	u32 err_mask;
++	const u8 *ecc_strength;
++	u8 num_ecc_strength;
++	u32 encode_parity_reg0;
++	int pg_irq_sel;
++};
++
++struct mtk_ecc {
++	struct device *dev;
++	const struct mtk_ecc_caps *caps;
++	void __iomem *regs;
++	struct clk *clk;
++
++	struct completion done;
++	struct mutex lock;
++	u32 sectors;
++
++	u8 *eccdata;
++};
++
++/* ecc strength that each IP supports */
++static const u8 ecc_strength_mt2701[] = {
++	4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 28, 32, 36,
++	40, 44, 48, 52, 56, 60
++};
++
++static const u8 ecc_strength_mt2712[] = {
++	4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 28, 32, 36,
++	40, 44, 48, 52, 56, 60, 68, 72, 80
++};
++
++static inline void mtk_ecc_wait_idle(struct mtk_ecc *ecc,
++				     enum mtk_ecc_operation op)
++{
++	struct device *dev = ecc->dev;
++	u32 val;
++	int ret;
++
++	ret = readl_poll_timeout_atomic(ecc->regs + ECC_IDLE_REG(op), val,
++					val & ECC_IDLE_MASK,
++					10, ECC_TIMEOUT);
++	if (ret)
++		dev_warn(dev, "%s NOT idle\n",
++			 op == ECC_ENCODE ? "encoder" : "decoder");
++}
++
++static irqreturn_t mtk_ecc_irq(int irq, void *id)
++{
++	struct mtk_ecc *ecc = id;
++	enum mtk_ecc_operation op;
++	u32 dec, enc;
++
++	dec = readw(ecc->regs + ECC_DECIRQ_STA) & ECC_IRQ_EN;
++	if (dec) {
++		op = ECC_DECODE;
++		dec = readw(ecc->regs + ECC_DECDONE);
++		if (dec & ecc->sectors) {
++			/*
++			 * Clear decode IRQ status once again to ensure that
++			 * there will be no extra IRQ.
++			 */
++			readw(ecc->regs + ECC_DECIRQ_STA);
++			ecc->sectors = 0;
++			complete(&ecc->done);
++		} else {
++			return IRQ_HANDLED;
++		}
++	} else {
++		enc = readl(ecc->regs + ECC_ENCIRQ_STA) & ECC_IRQ_EN;
++		if (enc) {
++			op = ECC_ENCODE;
++			complete(&ecc->done);
++		} else {
++			return IRQ_NONE;
++		}
++	}
++
++	return IRQ_HANDLED;
++}
++
++static int mtk_ecc_config(struct mtk_ecc *ecc, struct mtk_ecc_config *config)
++{
++	u32 ecc_bit, dec_sz, enc_sz;
++	u32 reg, i;
++
++	for (i = 0; i < ecc->caps->num_ecc_strength; i++) {
++		if (ecc->caps->ecc_strength[i] == config->strength)
++			break;
++	}
++
++	if (i == ecc->caps->num_ecc_strength) {
++		dev_err(ecc->dev, "invalid ecc strength %d\n",
++			config->strength);
++		return -EINVAL;
++	}
++
++	ecc_bit = i;
++
++	if (config->op == ECC_ENCODE) {
++		/* configure ECC encoder (in bits) */
++		enc_sz = config->len << 3;
++
++		reg = ecc_bit | (config->mode << ECC_MODE_SHIFT);
++		reg |= (enc_sz << ECC_MS_SHIFT);
++		writel(reg, ecc->regs + ECC_ENCCNFG);
++
++		if (config->mode != ECC_NFI_MODE)
++			writel(lower_32_bits(config->addr),
++			       ecc->regs + ECC_ENCDIADDR);
++
++	} else {
++		/* configure ECC decoder (in bits) */
++		dec_sz = (config->len << 3) +
++					config->strength * ECC_PARITY_BITS;
++
++		reg = ecc_bit | (config->mode << ECC_MODE_SHIFT);
++		reg |= (dec_sz << ECC_MS_SHIFT) | DEC_CNFG_CORRECT;
++		reg |= DEC_EMPTY_EN;
++		writel(reg, ecc->regs + ECC_DECCNFG);
++
++		if (config->sectors)
++			ecc->sectors = 1 << (config->sectors - 1);
++	}
++
++	return 0;
++}
++
++void mtk_ecc_get_stats(struct mtk_ecc *ecc, struct mtk_ecc_stats *stats,
++		       int sectors)
++{
++	u32 offset, i, err;
++	u32 bitflips = 0;
++
++	stats->corrected = 0;
++	stats->failed = 0;
++
++	for (i = 0; i < sectors; i++) {
++		offset = (i >> 2) << 2;
++		err = readl(ecc->regs + ECC_DECENUM0 + offset);
++		err = err >> ((i % 4) * 8);
++		err &= ecc->caps->err_mask;
++		if (err == ecc->caps->err_mask) {
++			/* uncorrectable errors */
++			stats->failed++;
++			continue;
++		}
++
++		stats->corrected += err;
++		bitflips = max_t(u32, bitflips, err);
++	}
++
++	stats->bitflips = bitflips;
++}
++EXPORT_SYMBOL(mtk_ecc_get_stats);
++
++void mtk_ecc_release(struct mtk_ecc *ecc)
++{
++	clk_disable_unprepare(ecc->clk);
++	put_device(ecc->dev);
++}
++EXPORT_SYMBOL(mtk_ecc_release);
++
++static void mtk_ecc_hw_init(struct mtk_ecc *ecc)
++{
++	mtk_ecc_wait_idle(ecc, ECC_ENCODE);
++	writew(ECC_OP_DISABLE, ecc->regs + ECC_ENCCON);
++
++	mtk_ecc_wait_idle(ecc, ECC_DECODE);
++	writel(ECC_OP_DISABLE, ecc->regs + ECC_DECCON);
++}
++
++static struct mtk_ecc *mtk_ecc_get(struct device_node *np)
++{
++	struct platform_device *pdev;
++	struct mtk_ecc *ecc;
++
++	pdev = of_find_device_by_node(np);
++	if (!pdev || !platform_get_drvdata(pdev))
++		return ERR_PTR(-EPROBE_DEFER);
++
++	get_device(&pdev->dev);
++	ecc = platform_get_drvdata(pdev);
++	clk_prepare_enable(ecc->clk);
++	mtk_ecc_hw_init(ecc);
++
++	return ecc;
++}
++
++struct mtk_ecc *of_mtk_ecc_get(struct device_node *of_node)
++{
++	struct mtk_ecc *ecc = NULL;
++	struct device_node *np;
++
++	np = of_parse_phandle(of_node, "ecc-engine", 0);
++	if (np) {
++		ecc = mtk_ecc_get(np);
++		of_node_put(np);
++	}
++
++	return ecc;
++}
++EXPORT_SYMBOL(of_mtk_ecc_get);
++
++int mtk_ecc_enable(struct mtk_ecc *ecc, struct mtk_ecc_config *config)
++{
++	enum mtk_ecc_operation op = config->op;
++	u16 reg_val;
++	int ret;
++
++	ret = mutex_lock_interruptible(&ecc->lock);
++	if (ret) {
++		dev_err(ecc->dev, "interrupted when attempting to lock\n");
++		return ret;
++	}
++
++	mtk_ecc_wait_idle(ecc, op);
++
++	ret = mtk_ecc_config(ecc, config);
++	if (ret) {
++		mutex_unlock(&ecc->lock);
++		return ret;
++	}
++
++	if (config->mode != ECC_NFI_MODE || op != ECC_ENCODE) {
++		init_completion(&ecc->done);
++		reg_val = ECC_IRQ_EN;
++		/*
++		 * For ECC_NFI_MODE, if ecc->caps->pg_irq_sel is 1, then it
++		 * means this chip can only generate one ecc irq during page
++		 * read / write. If is 0, generate one ecc irq each ecc step.
++		 */
++		if (ecc->caps->pg_irq_sel && config->mode == ECC_NFI_MODE)
++			reg_val |= ECC_PG_IRQ_SEL;
++		writew(reg_val, ecc->regs + ECC_IRQ_REG(op));
++	}
++
++	writew(ECC_OP_ENABLE, ecc->regs + ECC_CTL_REG(op));
++
++	return 0;
++}
++EXPORT_SYMBOL(mtk_ecc_enable);
++
++void mtk_ecc_disable(struct mtk_ecc *ecc)
++{
++	enum mtk_ecc_operation op = ECC_ENCODE;
++
++	/* find out the running operation */
++	if (readw(ecc->regs + ECC_CTL_REG(op)) != ECC_OP_ENABLE)
++		op = ECC_DECODE;
++
++	/* disable it */
++	mtk_ecc_wait_idle(ecc, op);
++	if (op == ECC_DECODE)
++		/*
++		 * Clear decode IRQ status in case there is a timeout to wait
++		 * decode IRQ.
++		 */
++		readw(ecc->regs + ECC_DECIRQ_STA);
++	writew(0, ecc->regs + ECC_IRQ_REG(op));
++	writew(ECC_OP_DISABLE, ecc->regs + ECC_CTL_REG(op));
++
++	mutex_unlock(&ecc->lock);
++}
++EXPORT_SYMBOL(mtk_ecc_disable);
++
++int mtk_ecc_wait_done(struct mtk_ecc *ecc, enum mtk_ecc_operation op)
++{
++	int ret;
++
++	ret = wait_for_completion_timeout(&ecc->done, msecs_to_jiffies(500));
++	if (!ret) {
++		dev_err(ecc->dev, "%s timeout - interrupt did not arrive)\n",
++			(op == ECC_ENCODE) ? "encoder" : "decoder");
++		return -ETIMEDOUT;
++	}
++
++	return 0;
++}
++EXPORT_SYMBOL(mtk_ecc_wait_done);
++
++int mtk_ecc_encode(struct mtk_ecc *ecc, struct mtk_ecc_config *config,
++		   u8 *data, u32 bytes)
++{
++	dma_addr_t addr;
++	u32 len;
++	int ret;
++
++	addr = dma_map_single(ecc->dev, data, bytes, DMA_TO_DEVICE);
++	ret = dma_mapping_error(ecc->dev, addr);
++	if (ret) {
++		dev_err(ecc->dev, "dma mapping error\n");
++		return -EINVAL;
++	}
++
++	config->op = ECC_ENCODE;
++	config->addr = addr;
++	ret = mtk_ecc_enable(ecc, config);
++	if (ret) {
++		dma_unmap_single(ecc->dev, addr, bytes, DMA_TO_DEVICE);
++		return ret;
++	}
++
++	ret = mtk_ecc_wait_done(ecc, ECC_ENCODE);
++	if (ret)
++		goto timeout;
++
++	mtk_ecc_wait_idle(ecc, ECC_ENCODE);
++
++	/* Program ECC bytes to OOB: per sector oob = FDM + ECC + SPARE */
++	len = (config->strength * ECC_PARITY_BITS + 7) >> 3;
++
++	/* write the parity bytes generated by the ECC back to temp buffer */
++	__ioread32_copy(ecc->eccdata,
++			ecc->regs + ecc->caps->encode_parity_reg0,
++			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);
++	mtk_ecc_disable(ecc);
++
++	return ret;
++}
++EXPORT_SYMBOL(mtk_ecc_encode);
++
++void mtk_ecc_adjust_strength(struct mtk_ecc *ecc, u32 *p)
++{
++	const u8 *ecc_strength = ecc->caps->ecc_strength;
++	int i;
++
++	for (i = 0; i < ecc->caps->num_ecc_strength; i++) {
++		if (*p <= ecc_strength[i]) {
++			if (!i)
++				*p = ecc_strength[i];
++			else if (*p != ecc_strength[i])
++				*p = ecc_strength[i - 1];
++			return;
++		}
++	}
++
++	*p = ecc_strength[ecc->caps->num_ecc_strength - 1];
++}
++EXPORT_SYMBOL(mtk_ecc_adjust_strength);
++
++static const struct mtk_ecc_caps mtk_ecc_caps_mt2701 = {
++	.err_mask = 0x3f,
++	.ecc_strength = ecc_strength_mt2701,
++	.num_ecc_strength = 20,
++	.encode_parity_reg0 = 0x10,
++	.pg_irq_sel = 0,
++};
++
++static const struct mtk_ecc_caps mtk_ecc_caps_mt2712 = {
++	.err_mask = 0x7f,
++	.ecc_strength = ecc_strength_mt2712,
++	.num_ecc_strength = 23,
++	.encode_parity_reg0 = 0x300,
++	.pg_irq_sel = 1,
++};
++
++static const struct of_device_id mtk_ecc_dt_match[] = {
++	{
++		.compatible = "mediatek,mt2701-ecc",
++		.data = &mtk_ecc_caps_mt2701,
++	}, {
++		.compatible = "mediatek,mt2712-ecc",
++		.data = &mtk_ecc_caps_mt2712,
++	},
++	{},
++};
++
++static int mtk_ecc_probe(struct platform_device *pdev)
++{
++	struct device *dev = &pdev->dev;
++	struct mtk_ecc *ecc;
++	struct resource *res;
++	const struct of_device_id *of_ecc_id = NULL;
++	u32 max_eccdata_size;
++	int irq, ret;
++
++	ecc = devm_kzalloc(dev, sizeof(*ecc), GFP_KERNEL);
++	if (!ecc)
++		return -ENOMEM;
++
++	of_ecc_id = of_match_device(mtk_ecc_dt_match, &pdev->dev);
++	if (!of_ecc_id)
++		return -ENODEV;
++
++	ecc->caps = of_ecc_id->data;
++
++	max_eccdata_size = ecc->caps->num_ecc_strength - 1;
++	max_eccdata_size = ecc->caps->ecc_strength[max_eccdata_size];
++	max_eccdata_size = (max_eccdata_size * ECC_PARITY_BITS + 7) >> 3;
++	max_eccdata_size = round_up(max_eccdata_size, 4);
++	ecc->eccdata = devm_kzalloc(dev, max_eccdata_size, GFP_KERNEL);
++	if (!ecc->eccdata)
++		return -ENOMEM;
++
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	ecc->regs = devm_ioremap_resource(dev, res);
++	if (IS_ERR(ecc->regs)) {
++		dev_err(dev, "failed to map regs: %ld\n", PTR_ERR(ecc->regs));
++		return PTR_ERR(ecc->regs);
++	}
++
++	ecc->clk = devm_clk_get(dev, NULL);
++	if (IS_ERR(ecc->clk)) {
++		dev_err(dev, "failed to get clock: %ld\n", PTR_ERR(ecc->clk));
++		return PTR_ERR(ecc->clk);
++	}
++
++	irq = platform_get_irq(pdev, 0);
++	if (irq < 0) {
++		dev_err(dev, "failed to get irq: %d\n", irq);
++		return irq;
++	}
++
++	ret = dma_set_mask(dev, DMA_BIT_MASK(32));
++	if (ret) {
++		dev_err(dev, "failed to set DMA mask\n");
++		return ret;
++	}
++
++	ret = devm_request_irq(dev, irq, mtk_ecc_irq, 0x0, "mtk-ecc", ecc);
++	if (ret) {
++		dev_err(dev, "failed to request irq\n");
++		return -EINVAL;
++	}
++
++	ecc->dev = dev;
++	mutex_init(&ecc->lock);
++	platform_set_drvdata(pdev, ecc);
++	dev_info(dev, "probed\n");
++
++	return 0;
++}
++
++#ifdef CONFIG_PM_SLEEP
++static int mtk_ecc_suspend(struct device *dev)
++{
++	struct mtk_ecc *ecc = dev_get_drvdata(dev);
++
++	clk_disable_unprepare(ecc->clk);
++
++	return 0;
++}
++
++static int mtk_ecc_resume(struct device *dev)
++{
++	struct mtk_ecc *ecc = dev_get_drvdata(dev);
++	int ret;
++
++	ret = clk_prepare_enable(ecc->clk);
++	if (ret) {
++		dev_err(dev, "failed to enable clk\n");
++		return ret;
++	}
++
++	return 0;
++}
++
++static SIMPLE_DEV_PM_OPS(mtk_ecc_pm_ops, mtk_ecc_suspend, mtk_ecc_resume);
++#endif
++
++MODULE_DEVICE_TABLE(of, mtk_ecc_dt_match);
++
++static struct platform_driver mtk_ecc_driver = {
++	.probe  = mtk_ecc_probe,
++	.driver = {
++		.name  = "mtk-ecc",
++		.of_match_table = of_match_ptr(mtk_ecc_dt_match),
++#ifdef CONFIG_PM_SLEEP
++		.pm = &mtk_ecc_pm_ops,
++#endif
++	},
++};
++
++module_platform_driver(mtk_ecc_driver);
++
++MODULE_AUTHOR("Xiaolei Li <xiaolei.li@mediatek.com>");
++MODULE_DESCRIPTION("MTK Nand ECC Driver");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/mtd/nand/raw/mtk_ecc.h b/drivers/mtd/nand/raw/mtk_ecc.h
+new file mode 100644
+index 0000000..d245c14
+--- /dev/null
++++ b/drivers/mtd/nand/raw/mtk_ecc.h
+@@ -0,0 +1,50 @@
++/*
++ * MTK SDG1 ECC controller
++ *
++ * Copyright (c) 2016 Mediatek
++ * Authors:	Xiaolei Li		<xiaolei.li@mediatek.com>
++ *		Jorge Ramirez-Ortiz	<jorge.ramirez-ortiz@linaro.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.
++ */
++
++#ifndef __DRIVERS_MTD_NAND_MTK_ECC_H__
++#define __DRIVERS_MTD_NAND_MTK_ECC_H__
++
++#include <linux/types.h>
++
++#define ECC_PARITY_BITS		(14)
++
++enum mtk_ecc_mode {ECC_DMA_MODE = 0, ECC_NFI_MODE = 1};
++enum mtk_ecc_operation {ECC_ENCODE, ECC_DECODE};
++
++struct device_node;
++struct mtk_ecc;
++
++struct mtk_ecc_stats {
++	u32 corrected;
++	u32 bitflips;
++	u32 failed;
++};
++
++struct mtk_ecc_config {
++	enum mtk_ecc_operation op;
++	enum mtk_ecc_mode mode;
++	dma_addr_t addr;
++	u32 strength;
++	u32 sectors;
++	u32 len;
++};
++
++int mtk_ecc_encode(struct mtk_ecc *, struct mtk_ecc_config *, u8 *, u32);
++void mtk_ecc_get_stats(struct mtk_ecc *, struct mtk_ecc_stats *, int);
++int mtk_ecc_wait_done(struct mtk_ecc *, enum mtk_ecc_operation);
++int mtk_ecc_enable(struct mtk_ecc *, struct mtk_ecc_config *);
++void mtk_ecc_disable(struct mtk_ecc *);
++void mtk_ecc_adjust_strength(struct mtk_ecc *ecc, u32 *p);
++
++struct mtk_ecc *of_mtk_ecc_get(struct device_node *);
++void mtk_ecc_release(struct mtk_ecc *);
++
++#endif
+diff --git a/drivers/mtd/nand/raw/mtk_nand.c b/drivers/mtd/nand/raw/mtk_nand.c
+new file mode 100644
+index 0000000..d86a7d1
+--- /dev/null
++++ b/drivers/mtd/nand/raw/mtk_nand.c
+@@ -0,0 +1,1585 @@
++/*
++ * MTK NAND Flash controller driver.
++ * Copyright (C) 2016 MediaTek Inc.
++ * Authors:	Xiaolei Li		<xiaolei.li@mediatek.com>
++ *		Jorge Ramirez-Ortiz	<jorge.ramirez-ortiz@linaro.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.
++ *
++ * 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/platform_device.h>
++#include <linux/dma-mapping.h>
++#include <linux/interrupt.h>
++#include <linux/delay.h>
++#include <linux/clk.h>
++#include <linux/mtd/rawnand.h>
++#include <linux/mtd/mtd.h>
++#include <linux/module.h>
++#include <linux/iopoll.h>
++#include <linux/of.h>
++#include <linux/of_device.h>
++#include "mtk_ecc.h"
++
++/* NAND controller register definition */
++#define NFI_CNFG		(0x00)
++#define		CNFG_AHB		BIT(0)
++#define		CNFG_READ_EN		BIT(1)
++#define		CNFG_DMA_BURST_EN	BIT(2)
++#define		CNFG_BYTE_RW		BIT(6)
++#define		CNFG_HW_ECC_EN		BIT(8)
++#define		CNFG_AUTO_FMT_EN	BIT(9)
++#define		CNFG_OP_CUST		(6 << 12)
++#define NFI_PAGEFMT		(0x04)
++#define		PAGEFMT_FDM_ECC_SHIFT	(12)
++#define		PAGEFMT_FDM_SHIFT	(8)
++#define		PAGEFMT_SEC_SEL_512	BIT(2)
++#define		PAGEFMT_512_2K		(0)
++#define		PAGEFMT_2K_4K		(1)
++#define		PAGEFMT_4K_8K		(2)
++#define		PAGEFMT_8K_16K		(3)
++/* NFI control */
++#define NFI_CON			(0x08)
++#define		CON_FIFO_FLUSH		BIT(0)
++#define		CON_NFI_RST		BIT(1)
++#define		CON_BRD			BIT(8)  /* burst  read */
++#define		CON_BWR			BIT(9)	/* burst  write */
++#define		CON_SEC_SHIFT		(12)
++/* Timming control register */
++#define NFI_ACCCON		(0x0C)
++#define NFI_INTR_EN		(0x10)
++#define		INTR_AHB_DONE_EN	BIT(6)
++#define NFI_INTR_STA		(0x14)
++#define NFI_CMD			(0x20)
++#define NFI_ADDRNOB		(0x30)
++#define NFI_COLADDR		(0x34)
++#define NFI_ROWADDR		(0x38)
++#define NFI_STRDATA		(0x40)
++#define		STAR_EN			(1)
++#define		STAR_DE			(0)
++#define NFI_CNRNB		(0x44)
++#define NFI_DATAW		(0x50)
++#define NFI_DATAR		(0x54)
++#define NFI_PIO_DIRDY		(0x58)
++#define		PIO_DI_RDY		(0x01)
++#define NFI_STA			(0x60)
++#define		STA_CMD			BIT(0)
++#define		STA_ADDR		BIT(1)
++#define		STA_BUSY		BIT(8)
++#define		STA_EMP_PAGE		BIT(12)
++#define		NFI_FSM_CUSTDATA	(0xe << 16)
++#define		NFI_FSM_MASK		(0xf << 16)
++#define NFI_ADDRCNTR		(0x70)
++#define		CNTR_MASK		GENMASK(16, 12)
++#define		ADDRCNTR_SEC_SHIFT	(12)
++#define		ADDRCNTR_SEC(val) \
++		(((val) & CNTR_MASK) >> ADDRCNTR_SEC_SHIFT)
++#define NFI_STRADDR		(0x80)
++#define NFI_BYTELEN		(0x84)
++#define NFI_CSEL		(0x90)
++#define NFI_FDML(x)		(0xA0 + (x) * sizeof(u32) * 2)
++#define NFI_FDMM(x)		(0xA4 + (x) * sizeof(u32) * 2)
++#define NFI_FDM_MAX_SIZE	(8)
++#define NFI_FDM_MIN_SIZE	(1)
++#define NFI_MASTER_STA		(0x224)
++#define		MASTER_STA_MASK		(0x0FFF)
++#define NFI_EMPTY_THRESH	(0x23C)
++
++#define MTK_NAME		"mtk-nand"
++#define KB(x)			((x) * 1024UL)
++#define MB(x)			(KB(x) * 1024UL)
++
++#define MTK_TIMEOUT		(500000)
++#define MTK_RESET_TIMEOUT	(1000000)
++#define MTK_MAX_SECTOR		(16)
++#define MTK_NAND_MAX_NSELS	(2)
++#define MTK_NFC_MIN_SPARE	(16)
++#define ACCTIMING(tpoecs, tprecs, tc2r, tw2r, twh, twst, trlt) \
++	((tpoecs) << 28 | (tprecs) << 22 | (tc2r) << 16 | \
++	(tw2r) << 12 | (twh) << 8 | (twst) << 4 | (trlt))
++
++struct mtk_nfc_caps {
++	const u8 *spare_size;
++	u8 num_spare_size;
++	u8 pageformat_spare_shift;
++	u8 nfi_clk_div;
++};
++
++struct mtk_nfc_bad_mark_ctl {
++	void (*bm_swap)(struct mtd_info *, u8 *buf, int raw);
++	u32 sec;
++	u32 pos;
++};
++
++/*
++ * FDM: region used to store free OOB data
++ */
++struct mtk_nfc_fdm {
++	u32 reg_size;
++	u32 ecc_size;
++};
++
++struct mtk_nfc_nand_chip {
++	struct list_head node;
++	struct nand_chip nand;
++
++	struct mtk_nfc_bad_mark_ctl bad_mark;
++	struct mtk_nfc_fdm fdm;
++	u32 spare_per_sector;
++
++	int nsels;
++	u8 sels[0];
++	/* nothing after this field */
++};
++
++struct mtk_nfc_clk {
++	struct clk *nfi_clk;
++	struct clk *pad_clk;
++};
++
++struct mtk_nfc {
++	struct nand_hw_control controller;
++	struct mtk_ecc_config ecc_cfg;
++	struct mtk_nfc_clk clk;
++	struct mtk_ecc *ecc;
++
++	struct device *dev;
++	const struct mtk_nfc_caps *caps;
++	void __iomem *regs;
++
++	struct completion done;
++	struct list_head chips;
++
++	u8 *buffer;
++};
++
++/*
++ * supported spare size of each IP.
++ * order should be the same with the spare size bitfiled defination of
++ * register NFI_PAGEFMT.
++ */
++static const u8 spare_size_mt2701[] = {
++	16, 26, 27, 28, 32, 36, 40, 44,	48, 49, 50, 51, 52, 62, 63, 64
++};
++
++static const u8 spare_size_mt2712[] = {
++	16, 26, 27, 28, 32, 36, 40, 44, 48, 49, 50, 51, 52, 62, 61, 63, 64, 67,
++	74
++};
++
++static inline struct mtk_nfc_nand_chip *to_mtk_nand(struct nand_chip *nand)
++{
++	return container_of(nand, struct mtk_nfc_nand_chip, nand);
++}
++
++static inline u8 *data_ptr(struct nand_chip *chip, const u8 *p, int i)
++{
++	return (u8 *)p + i * chip->ecc.size;
++}
++
++static inline u8 *oob_ptr(struct nand_chip *chip, int i)
++{
++	struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
++	u8 *poi;
++
++	/* map the sector's FDM data to free oob:
++	 * the beginning of the oob area stores the FDM data of bad mark sectors
++	 */
++
++	if (i < mtk_nand->bad_mark.sec)
++		poi = chip->oob_poi + (i + 1) * mtk_nand->fdm.reg_size;
++	else if (i == mtk_nand->bad_mark.sec)
++		poi = chip->oob_poi;
++	else
++		poi = chip->oob_poi + i * mtk_nand->fdm.reg_size;
++
++	return poi;
++}
++
++static inline int mtk_data_len(struct nand_chip *chip)
++{
++	struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
++
++	return chip->ecc.size + mtk_nand->spare_per_sector;
++}
++
++static inline u8 *mtk_data_ptr(struct nand_chip *chip,  int i)
++{
++	struct mtk_nfc *nfc = nand_get_controller_data(chip);
++
++	return nfc->buffer + i * mtk_data_len(chip);
++}
++
++static inline u8 *mtk_oob_ptr(struct nand_chip *chip, int i)
++{
++	struct mtk_nfc *nfc = nand_get_controller_data(chip);
++
++	return nfc->buffer + i * mtk_data_len(chip) + chip->ecc.size;
++}
++
++static inline void nfi_writel(struct mtk_nfc *nfc, u32 val, u32 reg)
++{
++	writel(val, nfc->regs + reg);
++}
++
++static inline void nfi_writew(struct mtk_nfc *nfc, u16 val, u32 reg)
++{
++	writew(val, nfc->regs + reg);
++}
++
++static inline void nfi_writeb(struct mtk_nfc *nfc, u8 val, u32 reg)
++{
++	writeb(val, nfc->regs + reg);
++}
++
++static inline u32 nfi_readl(struct mtk_nfc *nfc, u32 reg)
++{
++	return readl_relaxed(nfc->regs + reg);
++}
++
++static inline u16 nfi_readw(struct mtk_nfc *nfc, u32 reg)
++{
++	return readw_relaxed(nfc->regs + reg);
++}
++
++static inline u8 nfi_readb(struct mtk_nfc *nfc, u32 reg)
++{
++	return readb_relaxed(nfc->regs + reg);
++}
++
++static void mtk_nfc_hw_reset(struct mtk_nfc *nfc)
++{
++	struct device *dev = nfc->dev;
++	u32 val;
++	int ret;
++
++	/* reset all registers and force the NFI master to terminate */
++	nfi_writel(nfc, CON_FIFO_FLUSH | CON_NFI_RST, NFI_CON);
++
++	/* wait for the master to finish the last transaction */
++	ret = readl_poll_timeout(nfc->regs + NFI_MASTER_STA, val,
++				 !(val & MASTER_STA_MASK), 50,
++				 MTK_RESET_TIMEOUT);
++	if (ret)
++		dev_warn(dev, "master active in reset [0x%x] = 0x%x\n",
++			 NFI_MASTER_STA, val);
++
++	/* ensure any status register affected by the NFI master is reset */
++	nfi_writel(nfc, CON_FIFO_FLUSH | CON_NFI_RST, NFI_CON);
++	nfi_writew(nfc, STAR_DE, NFI_STRDATA);
++}
++
++static int mtk_nfc_send_command(struct mtk_nfc *nfc, u8 command)
++{
++	struct device *dev = nfc->dev;
++	u32 val;
++	int ret;
++
++	nfi_writel(nfc, command, NFI_CMD);
++
++	ret = readl_poll_timeout_atomic(nfc->regs + NFI_STA, val,
++					!(val & STA_CMD), 10,  MTK_TIMEOUT);
++	if (ret) {
++		dev_warn(dev, "nfi core timed out entering command mode\n");
++		return -EIO;
++	}
++
++	return 0;
++}
++
++static int mtk_nfc_send_address(struct mtk_nfc *nfc, int addr)
++{
++	struct device *dev = nfc->dev;
++	u32 val;
++	int ret;
++
++	nfi_writel(nfc, addr, NFI_COLADDR);
++	nfi_writel(nfc, 0, NFI_ROWADDR);
++	nfi_writew(nfc, 1, NFI_ADDRNOB);
++
++	ret = readl_poll_timeout_atomic(nfc->regs + NFI_STA, val,
++					!(val & STA_ADDR), 10, MTK_TIMEOUT);
++	if (ret) {
++		dev_warn(dev, "nfi core timed out entering address mode\n");
++		return -EIO;
++	}
++
++	return 0;
++}
++
++static int mtk_nfc_hw_runtime_config(struct mtd_info *mtd)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
++	struct mtk_nfc *nfc = nand_get_controller_data(chip);
++	u32 fmt, spare, i;
++
++	if (!mtd->writesize)
++		return 0;
++
++	spare = mtk_nand->spare_per_sector;
++
++	switch (mtd->writesize) {
++	case 512:
++		fmt = PAGEFMT_512_2K | PAGEFMT_SEC_SEL_512;
++		break;
++	case KB(2):
++		if (chip->ecc.size == 512)
++			fmt = PAGEFMT_2K_4K | PAGEFMT_SEC_SEL_512;
++		else
++			fmt = PAGEFMT_512_2K;
++		break;
++	case KB(4):
++		if (chip->ecc.size == 512)
++			fmt = PAGEFMT_4K_8K | PAGEFMT_SEC_SEL_512;
++		else
++			fmt = PAGEFMT_2K_4K;
++		break;
++	case KB(8):
++		if (chip->ecc.size == 512)
++			fmt = PAGEFMT_8K_16K | PAGEFMT_SEC_SEL_512;
++		else
++			fmt = PAGEFMT_4K_8K;
++		break;
++	case KB(16):
++		fmt = PAGEFMT_8K_16K;
++		break;
++	default:
++		dev_err(nfc->dev, "invalid page len: %d\n", mtd->writesize);
++		return -EINVAL;
++	}
++
++	/*
++	 * the hardware will double the value for this eccsize, so we need to
++	 * halve it
++	 */
++	if (chip->ecc.size == 1024)
++		spare >>= 1;
++
++	for (i = 0; i < nfc->caps->num_spare_size; i++) {
++		if (nfc->caps->spare_size[i] == spare)
++			break;
++	}
++
++	if (i == nfc->caps->num_spare_size) {
++		dev_err(nfc->dev, "invalid spare size %d\n", spare);
++		return -EINVAL;
++	}
++
++	fmt |= i << nfc->caps->pageformat_spare_shift;
++
++	fmt |= mtk_nand->fdm.reg_size << PAGEFMT_FDM_SHIFT;
++	fmt |= mtk_nand->fdm.ecc_size << PAGEFMT_FDM_ECC_SHIFT;
++	nfi_writel(nfc, fmt, NFI_PAGEFMT);
++
++	nfc->ecc_cfg.strength = chip->ecc.strength;
++	nfc->ecc_cfg.len = chip->ecc.size + mtk_nand->fdm.ecc_size;
++
++	return 0;
++}
++
++static void mtk_nfc_select_chip(struct mtd_info *mtd, int chip)
++{
++	struct nand_chip *nand = mtd_to_nand(mtd);
++	struct mtk_nfc *nfc = nand_get_controller_data(nand);
++	struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(nand);
++
++	if (chip < 0)
++		return;
++
++	mtk_nfc_hw_runtime_config(mtd);
++
++	nfi_writel(nfc, mtk_nand->sels[chip], NFI_CSEL);
++}
++
++static int mtk_nfc_dev_ready(struct mtd_info *mtd)
++{
++	struct mtk_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd));
++
++	if (nfi_readl(nfc, NFI_STA) & STA_BUSY)
++		return 0;
++
++	return 1;
++}
++
++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));
++
++	if (ctrl & NAND_ALE) {
++		mtk_nfc_send_address(nfc, dat);
++	} else if (ctrl & NAND_CLE) {
++		mtk_nfc_hw_reset(nfc);
++
++		nfi_writew(nfc, CNFG_OP_CUST, NFI_CNFG);
++		mtk_nfc_send_command(nfc, dat);
++	}
++}
++
++static inline void mtk_nfc_wait_ioready(struct mtk_nfc *nfc)
++{
++	int rc;
++	u8 val;
++
++	rc = readb_poll_timeout_atomic(nfc->regs + NFI_PIO_DIRDY, val,
++				       val & PIO_DI_RDY, 10, MTK_TIMEOUT);
++	if (rc < 0)
++		dev_err(nfc->dev, "data not ready\n");
++}
++
++static inline u8 mtk_nfc_read_byte(struct mtd_info *mtd)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct mtk_nfc *nfc = nand_get_controller_data(chip);
++	u32 reg;
++
++	/* after each byte read, the NFI_STA reg is reset by the hardware */
++	reg = nfi_readl(nfc, NFI_STA) & NFI_FSM_MASK;
++	if (reg != NFI_FSM_CUSTDATA) {
++		reg = nfi_readw(nfc, NFI_CNFG);
++		reg |= CNFG_BYTE_RW | CNFG_READ_EN;
++		nfi_writew(nfc, reg, NFI_CNFG);
++
++		/*
++		 * set to max sector to allow the HW to continue reading over
++		 * unaligned accesses
++		 */
++		reg = (MTK_MAX_SECTOR << CON_SEC_SHIFT) | CON_BRD;
++		nfi_writel(nfc, reg, NFI_CON);
++
++		/* trigger to fetch data */
++		nfi_writew(nfc, STAR_EN, NFI_STRDATA);
++	}
++
++	mtk_nfc_wait_ioready(nfc);
++
++	return nfi_readb(nfc, NFI_DATAR);
++}
++
++static void mtk_nfc_read_buf(struct mtd_info *mtd, u8 *buf, int len)
++{
++	int i;
++
++	for (i = 0; i < len; i++)
++		buf[i] = mtk_nfc_read_byte(mtd);
++}
++
++static void mtk_nfc_write_byte(struct mtd_info *mtd, u8 byte)
++{
++	struct mtk_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd));
++	u32 reg;
++
++	reg = nfi_readl(nfc, NFI_STA) & NFI_FSM_MASK;
++
++	if (reg != NFI_FSM_CUSTDATA) {
++		reg = nfi_readw(nfc, NFI_CNFG) | CNFG_BYTE_RW;
++		nfi_writew(nfc, reg, NFI_CNFG);
++
++		reg = MTK_MAX_SECTOR << CON_SEC_SHIFT | CON_BWR;
++		nfi_writel(nfc, reg, NFI_CON);
++
++		nfi_writew(nfc, STAR_EN, NFI_STRDATA);
++	}
++
++	mtk_nfc_wait_ioready(nfc);
++	nfi_writeb(nfc, byte, NFI_DATAW);
++}
++
++static void mtk_nfc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
++{
++	int i;
++
++	for (i = 0; i < len; i++)
++		mtk_nfc_write_byte(mtd, buf[i]);
++}
++
++static int mtk_nfc_setup_data_interface(struct mtd_info *mtd, int csline,
++					const struct nand_data_interface *conf)
++{
++	struct mtk_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd));
++	const struct nand_sdr_timings *timings;
++	u32 rate, tpoecs, tprecs, tc2r, tw2r, twh, twst, trlt;
++
++	timings = nand_get_sdr_timings(conf);
++	if (IS_ERR(timings))
++		return -ENOTSUPP;
++
++	if (csline == NAND_DATA_IFACE_CHECK_ONLY)
++		return 0;
++
++	rate = clk_get_rate(nfc->clk.nfi_clk);
++	/* There is a frequency divider in some IPs */
++	rate /= nfc->caps->nfi_clk_div;
++
++	/* turn clock rate into KHZ */
++	rate /= 1000;
++
++	tpoecs = max(timings->tALH_min, timings->tCLH_min) / 1000;
++	tpoecs = DIV_ROUND_UP(tpoecs * rate, 1000000);
++	tpoecs &= 0xf;
++
++	tprecs = max(timings->tCLS_min, timings->tALS_min) / 1000;
++	tprecs = DIV_ROUND_UP(tprecs * rate, 1000000);
++	tprecs &= 0x3f;
++
++	/* sdr interface has no tCR which means CE# low to RE# low */
++	tc2r = 0;
++
++	tw2r = timings->tWHR_min / 1000;
++	tw2r = DIV_ROUND_UP(tw2r * rate, 1000000);
++	tw2r = DIV_ROUND_UP(tw2r - 1, 2);
++	tw2r &= 0xf;
++
++	twh = max(timings->tREH_min, timings->tWH_min) / 1000;
++	twh = DIV_ROUND_UP(twh * rate, 1000000) - 1;
++	twh &= 0xf;
++
++	twst = timings->tWP_min / 1000;
++	twst = DIV_ROUND_UP(twst * rate, 1000000) - 1;
++	twst &= 0xf;
++
++	trlt = max(timings->tREA_max, timings->tRP_min) / 1000;
++	trlt = DIV_ROUND_UP(trlt * rate, 1000000) - 1;
++	trlt &= 0xf;
++
++	/*
++	 * ACCON: access timing control register
++	 * -------------------------------------
++	 * 31:28: tpoecs, minimum required time for CS post pulling down after
++	 *        accessing the device
++	 * 27:22: tprecs, minimum required time for CS pre pulling down before
++	 *        accessing the device
++	 * 21:16: tc2r, minimum required time from NCEB low to NREB low
++	 * 15:12: tw2r, minimum required time from NWEB high to NREB low.
++	 * 11:08: twh, write enable hold time
++	 * 07:04: twst, write wait states
++	 * 03:00: trlt, read wait states
++	 */
++	trlt = ACCTIMING(tpoecs, tprecs, tc2r, tw2r, twh, twst, trlt);
++	nfi_writel(nfc, trlt, NFI_ACCCON);
++
++	return 0;
++}
++
++static int mtk_nfc_sector_encode(struct nand_chip *chip, u8 *data)
++{
++	struct mtk_nfc *nfc = nand_get_controller_data(chip);
++	struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
++	int size = chip->ecc.size + mtk_nand->fdm.reg_size;
++
++	nfc->ecc_cfg.mode = ECC_DMA_MODE;
++	nfc->ecc_cfg.op = ECC_ENCODE;
++
++	return mtk_ecc_encode(nfc->ecc, &nfc->ecc_cfg, data, size);
++}
++
++static void mtk_nfc_no_bad_mark_swap(struct mtd_info *a, u8 *b, int c)
++{
++	/* nop */
++}
++
++static void mtk_nfc_bad_mark_swap(struct mtd_info *mtd, u8 *buf, int raw)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct mtk_nfc_nand_chip *nand = to_mtk_nand(chip);
++	u32 bad_pos = nand->bad_mark.pos;
++
++	if (raw)
++		bad_pos += nand->bad_mark.sec * mtk_data_len(chip);
++	else
++		bad_pos += nand->bad_mark.sec * chip->ecc.size;
++
++	swap(chip->oob_poi[0], buf[bad_pos]);
++}
++
++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 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;
++	u32 start, end;
++	int i, ret;
++
++	start = offset / chip->ecc.size;
++	end = DIV_ROUND_UP(offset + len, chip->ecc.size);
++
++	memset(nfc->buffer, 0xff, mtd->writesize + mtd->oobsize);
++	for (i = 0; i < chip->ecc.steps; i++) {
++		memcpy(mtk_data_ptr(chip, i), data_ptr(chip, buf, i),
++		       chip->ecc.size);
++
++		if (start > i || i >= end)
++			continue;
++
++		if (i == mtk_nand->bad_mark.sec)
++			mtk_nand->bad_mark.bm_swap(mtd, nfc->buffer, 1);
++
++		memcpy(mtk_oob_ptr(chip, i), oob_ptr(chip, i), fdm->reg_size);
++
++		/* program the CRC back to the OOB */
++		ret = mtk_nfc_sector_encode(chip, mtk_data_ptr(chip, i));
++		if (ret < 0)
++			return ret;
++	}
++
++	return 0;
++}
++
++static void mtk_nfc_format_page(struct mtd_info *mtd, const u8 *buf)
++{
++	struct nand_chip *chip = mtd_to_nand(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;
++	u32 i;
++
++	memset(nfc->buffer, 0xff, mtd->writesize + mtd->oobsize);
++	for (i = 0; i < chip->ecc.steps; i++) {
++		if (buf)
++			memcpy(mtk_data_ptr(chip, i), data_ptr(chip, buf, i),
++			       chip->ecc.size);
++
++		if (i == mtk_nand->bad_mark.sec)
++			mtk_nand->bad_mark.bm_swap(mtd, nfc->buffer, 1);
++
++		memcpy(mtk_oob_ptr(chip, i), oob_ptr(chip, i), fdm->reg_size);
++	}
++}
++
++static inline void mtk_nfc_read_fdm(struct nand_chip *chip, u32 start,
++				    u32 sectors)
++{
++	struct mtk_nfc *nfc = nand_get_controller_data(chip);
++	struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
++	struct mtk_nfc_fdm *fdm = &mtk_nand->fdm;
++	u32 vall, valm;
++	u8 *oobptr;
++	int i, j;
++
++	for (i = 0; i < sectors; i++) {
++		oobptr = oob_ptr(chip, start + i);
++		vall = nfi_readl(nfc, NFI_FDML(i));
++		valm = nfi_readl(nfc, NFI_FDMM(i));
++
++		for (j = 0; j < fdm->reg_size; j++)
++			oobptr[j] = (j >= 4 ? valm : vall) >> ((j % 4) * 8);
++	}
++}
++
++static inline void mtk_nfc_write_fdm(struct nand_chip *chip)
++{
++	struct mtk_nfc *nfc = nand_get_controller_data(chip);
++	struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
++	struct mtk_nfc_fdm *fdm = &mtk_nand->fdm;
++	u32 vall, valm;
++	u8 *oobptr;
++	int i, j;
++
++	for (i = 0; i < chip->ecc.steps; i++) {
++		oobptr = oob_ptr(chip, i);
++		vall = 0;
++		valm = 0;
++		for (j = 0; j < 8; j++) {
++			if (j < 4)
++				vall |= (j < fdm->reg_size ? oobptr[j] : 0xff)
++						<< (j * 8);
++			else
++				valm |= (j < fdm->reg_size ? oobptr[j] : 0xff)
++						<< ((j - 4) * 8);
++		}
++		nfi_writel(nfc, vall, NFI_FDML(i));
++		nfi_writel(nfc, valm, NFI_FDMM(i));
++	}
++}
++
++static int mtk_nfc_do_write_page(struct mtd_info *mtd, struct nand_chip *chip,
++				 const u8 *buf, int page, int len)
++{
++	struct mtk_nfc *nfc = nand_get_controller_data(chip);
++	struct device *dev = nfc->dev;
++	dma_addr_t addr;
++	u32 reg;
++	int ret;
++
++	addr = dma_map_single(dev, (void *)buf, len, DMA_TO_DEVICE);
++	ret = dma_mapping_error(nfc->dev, addr);
++	if (ret) {
++		dev_err(nfc->dev, "dma mapping error\n");
++		return -EINVAL;
++	}
++
++	reg = nfi_readw(nfc, NFI_CNFG) | CNFG_AHB | CNFG_DMA_BURST_EN;
++	nfi_writew(nfc, reg, NFI_CNFG);
++
++	nfi_writel(nfc, chip->ecc.steps << CON_SEC_SHIFT, NFI_CON);
++	nfi_writel(nfc, lower_32_bits(addr), NFI_STRADDR);
++	nfi_writew(nfc, INTR_AHB_DONE_EN, NFI_INTR_EN);
++
++	init_completion(&nfc->done);
++
++	reg = nfi_readl(nfc, NFI_CON) | CON_BWR;
++	nfi_writel(nfc, reg, NFI_CON);
++	nfi_writew(nfc, STAR_EN, NFI_STRDATA);
++
++	ret = wait_for_completion_timeout(&nfc->done, msecs_to_jiffies(500));
++	if (!ret) {
++		dev_err(dev, "program ahb done timeout\n");
++		nfi_writew(nfc, 0, NFI_INTR_EN);
++		ret = -ETIMEDOUT;
++		goto timeout;
++	}
++
++	ret = readl_poll_timeout_atomic(nfc->regs + NFI_ADDRCNTR, reg,
++					ADDRCNTR_SEC(reg) >= chip->ecc.steps,
++					10, MTK_TIMEOUT);
++	if (ret)
++		dev_err(dev, "hwecc write timeout\n");
++
++timeout:
++
++	dma_unmap_single(nfc->dev, addr, len, DMA_TO_DEVICE);
++	nfi_writel(nfc, 0, NFI_CON);
++
++	return ret;
++}
++
++static int mtk_nfc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
++			      const u8 *buf, int page, int raw)
++{
++	struct mtk_nfc *nfc = nand_get_controller_data(chip);
++	struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
++	size_t len;
++	const u8 *bufpoi;
++	u32 reg;
++	int ret;
++
++	if (!raw) {
++		/* OOB => FDM: from register,  ECC: from HW */
++		reg = nfi_readw(nfc, NFI_CNFG) | CNFG_AUTO_FMT_EN;
++		nfi_writew(nfc, reg | CNFG_HW_ECC_EN, NFI_CNFG);
++
++		nfc->ecc_cfg.op = ECC_ENCODE;
++		nfc->ecc_cfg.mode = ECC_NFI_MODE;
++		ret = mtk_ecc_enable(nfc->ecc, &nfc->ecc_cfg);
++		if (ret) {
++			/* clear NFI config */
++			reg = nfi_readw(nfc, NFI_CNFG);
++			reg &= ~(CNFG_AUTO_FMT_EN | CNFG_HW_ECC_EN);
++			nfi_writew(nfc, reg, NFI_CNFG);
++
++			return ret;
++		}
++
++		memcpy(nfc->buffer, buf, mtd->writesize);
++		mtk_nand->bad_mark.bm_swap(mtd, nfc->buffer, raw);
++		bufpoi = nfc->buffer;
++
++		/* write OOB into the FDM registers (OOB area in MTK NAND) */
++		mtk_nfc_write_fdm(chip);
++	} else {
++		bufpoi = buf;
++	}
++
++	len = mtd->writesize + (raw ? mtd->oobsize : 0);
++	ret = mtk_nfc_do_write_page(mtd, chip, bufpoi, page, len);
++
++	if (!raw)
++		mtk_ecc_disable(nfc->ecc);
++
++	return ret;
++}
++
++static int mtk_nfc_write_page_hwecc(struct mtd_info *mtd,
++				    struct nand_chip *chip, const u8 *buf,
++				    int oob_on, int page)
++{
++	return mtk_nfc_write_page(mtd, chip, buf, page, 0);
++}
++
++static int mtk_nfc_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
++				  const u8 *buf, int oob_on, int pg)
++{
++	struct mtk_nfc *nfc = nand_get_controller_data(chip);
++
++	mtk_nfc_format_page(mtd, buf);
++	return mtk_nfc_write_page(mtd, chip, nfc->buffer, pg, 1);
++}
++
++static int mtk_nfc_write_subpage_hwecc(struct mtd_info *mtd,
++				       struct nand_chip *chip, u32 offset,
++				       u32 data_len, const u8 *buf,
++				       int oob_on, int page)
++{
++	struct mtk_nfc *nfc = nand_get_controller_data(chip);
++	int ret;
++
++	ret = mtk_nfc_format_subpage(mtd, offset, data_len, buf);
++	if (ret < 0)
++		return ret;
++
++	/* use the data in the private buffer (now with FDM and CRC) */
++	return mtk_nfc_write_page(mtd, chip, nfc->buffer, page, 1);
++}
++
++static int mtk_nfc_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
++				 int page)
++{
++	int ret;
++
++	chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
++
++	ret = mtk_nfc_write_page_raw(mtd, chip, NULL, 1, page);
++	if (ret < 0)
++		return -EIO;
++
++	chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
++	ret = chip->waitfunc(mtd, chip);
++
++	return ret & NAND_STATUS_FAIL ? -EIO : 0;
++}
++
++static int mtk_nfc_update_ecc_stats(struct mtd_info *mtd, u8 *buf, u32 sectors)
++{
++	struct nand_chip *chip = mtd_to_nand(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;
++	int rc, i;
++
++	rc = nfi_readl(nfc, NFI_STA) & STA_EMP_PAGE;
++	if (rc) {
++		memset(buf, 0xff, sectors * chip->ecc.size);
++		for (i = 0; i < sectors; i++)
++			memset(oob_ptr(chip, i), 0xff, mtk_nand->fdm.reg_size);
++		return 0;
++	}
++
++	mtk_ecc_get_stats(nfc->ecc, &stats, sectors);
++	mtd->ecc_stats.corrected += stats.corrected;
++	mtd->ecc_stats.failed += stats.failed;
++
++	return stats.bitflips;
++}
++
++static int mtk_nfc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
++				u32 data_offs, u32 readlen,
++				u8 *bufpoi, int page, int raw)
++{
++	struct mtk_nfc *nfc = nand_get_controller_data(chip);
++	struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
++	u32 spare = mtk_nand->spare_per_sector;
++	u32 column, sectors, start, end, reg;
++	dma_addr_t addr;
++	int bitflips;
++	size_t len;
++	u8 *buf;
++	int rc;
++
++	start = data_offs / chip->ecc.size;
++	end = DIV_ROUND_UP(data_offs + readlen, chip->ecc.size);
++
++	sectors = end - start;
++	column = start * (chip->ecc.size + spare);
++
++	len = sectors * chip->ecc.size + (raw ? sectors * spare : 0);
++	buf = bufpoi + start * chip->ecc.size;
++
++	if (column != 0)
++		chip->cmdfunc(mtd, NAND_CMD_RNDOUT, column, -1);
++
++	addr = dma_map_single(nfc->dev, buf, len, DMA_FROM_DEVICE);
++	rc = dma_mapping_error(nfc->dev, addr);
++	if (rc) {
++		dev_err(nfc->dev, "dma mapping error\n");
++
++		return -EINVAL;
++	}
++
++	reg = nfi_readw(nfc, NFI_CNFG);
++	reg |= CNFG_READ_EN | CNFG_DMA_BURST_EN | CNFG_AHB;
++	if (!raw) {
++		reg |= CNFG_AUTO_FMT_EN | CNFG_HW_ECC_EN;
++		nfi_writew(nfc, reg, NFI_CNFG);
++
++		nfc->ecc_cfg.mode = ECC_NFI_MODE;
++		nfc->ecc_cfg.sectors = sectors;
++		nfc->ecc_cfg.op = ECC_DECODE;
++		rc = mtk_ecc_enable(nfc->ecc, &nfc->ecc_cfg);
++		if (rc) {
++			dev_err(nfc->dev, "ecc enable\n");
++			/* clear NFI_CNFG */
++			reg &= ~(CNFG_DMA_BURST_EN | CNFG_AHB | CNFG_READ_EN |
++				CNFG_AUTO_FMT_EN | CNFG_HW_ECC_EN);
++			nfi_writew(nfc, reg, NFI_CNFG);
++			dma_unmap_single(nfc->dev, addr, len, DMA_FROM_DEVICE);
++
++			return rc;
++		}
++	} else {
++		nfi_writew(nfc, reg, NFI_CNFG);
++	}
++
++	nfi_writel(nfc, sectors << CON_SEC_SHIFT, NFI_CON);
++	nfi_writew(nfc, INTR_AHB_DONE_EN, NFI_INTR_EN);
++	nfi_writel(nfc, lower_32_bits(addr), NFI_STRADDR);
++
++	init_completion(&nfc->done);
++	reg = nfi_readl(nfc, NFI_CON) | CON_BRD;
++	nfi_writel(nfc, reg, NFI_CON);
++	nfi_writew(nfc, STAR_EN, NFI_STRDATA);
++
++	rc = wait_for_completion_timeout(&nfc->done, msecs_to_jiffies(500));
++	if (!rc)
++		dev_warn(nfc->dev, "read ahb/dma done timeout\n");
++
++	rc = readl_poll_timeout_atomic(nfc->regs + NFI_BYTELEN, reg,
++				       ADDRCNTR_SEC(reg) >= sectors, 10,
++				       MTK_TIMEOUT);
++	if (rc < 0) {
++		dev_err(nfc->dev, "subpage done timeout\n");
++		bitflips = -EIO;
++	} else {
++		bitflips = 0;
++		if (!raw) {
++			rc = mtk_ecc_wait_done(nfc->ecc, ECC_DECODE);
++			bitflips = rc < 0 ? -ETIMEDOUT :
++				mtk_nfc_update_ecc_stats(mtd, buf, sectors);
++			mtk_nfc_read_fdm(chip, start, sectors);
++		}
++	}
++
++	dma_unmap_single(nfc->dev, addr, len, DMA_FROM_DEVICE);
++
++	if (raw)
++		goto done;
++
++	mtk_ecc_disable(nfc->ecc);
++
++	if (clamp(mtk_nand->bad_mark.sec, start, end) == mtk_nand->bad_mark.sec)
++		mtk_nand->bad_mark.bm_swap(mtd, bufpoi, raw);
++done:
++	nfi_writel(nfc, 0, NFI_CON);
++
++	return bitflips;
++}
++
++static int mtk_nfc_read_subpage_hwecc(struct mtd_info *mtd,
++				      struct nand_chip *chip, u32 off,
++				      u32 len, u8 *p, int pg)
++{
++	return mtk_nfc_read_subpage(mtd, chip, off, len, p, pg, 0);
++}
++
++static int mtk_nfc_read_page_hwecc(struct mtd_info *mtd,
++				   struct nand_chip *chip, u8 *p,
++				   int oob_on, int pg)
++{
++	return mtk_nfc_read_subpage(mtd, chip, 0, mtd->writesize, p, pg, 0);
++}
++
++static int mtk_nfc_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
++				 u8 *buf, int oob_on, int page)
++{
++	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;
++	int i, ret;
++
++	memset(nfc->buffer, 0xff, mtd->writesize + mtd->oobsize);
++	ret = mtk_nfc_read_subpage(mtd, chip, 0, mtd->writesize, nfc->buffer,
++				   page, 1);
++	if (ret < 0)
++		return ret;
++
++	for (i = 0; i < chip->ecc.steps; i++) {
++		memcpy(oob_ptr(chip, i), mtk_oob_ptr(chip, i), fdm->reg_size);
++
++		if (i == mtk_nand->bad_mark.sec)
++			mtk_nand->bad_mark.bm_swap(mtd, nfc->buffer, 1);
++
++		if (buf)
++			memcpy(data_ptr(chip, buf, i), mtk_data_ptr(chip, i),
++			       chip->ecc.size);
++	}
++
++	return ret;
++}
++
++static int mtk_nfc_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
++				int page)
++{
++	chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
++
++	return mtk_nfc_read_page_raw(mtd, chip, NULL, 1, page);
++}
++
++static inline void mtk_nfc_hw_init(struct mtk_nfc *nfc)
++{
++	/*
++	 * CNRNB: nand ready/busy register
++	 * -------------------------------
++	 * 7:4: timeout register for polling the NAND busy/ready signal
++	 * 0  : poll the status of the busy/ready signal after [7:4]*16 cycles.
++	 */
++	nfi_writew(nfc, 0xf1, NFI_CNRNB);
++	nfi_writel(nfc, PAGEFMT_8K_16K, NFI_PAGEFMT);
++
++	mtk_nfc_hw_reset(nfc);
++
++	nfi_readl(nfc, NFI_INTR_STA);
++	nfi_writel(nfc, 0, NFI_INTR_EN);
++}
++
++static irqreturn_t mtk_nfc_irq(int irq, void *id)
++{
++	struct mtk_nfc *nfc = id;
++	u16 sta, ien;
++
++	sta = nfi_readw(nfc, NFI_INTR_STA);
++	ien = nfi_readw(nfc, NFI_INTR_EN);
++
++	if (!(sta & ien))
++		return IRQ_NONE;
++
++	nfi_writew(nfc, ~sta & ien, NFI_INTR_EN);
++	complete(&nfc->done);
++
++	return IRQ_HANDLED;
++}
++
++static int mtk_nfc_enable_clk(struct device *dev, struct mtk_nfc_clk *clk)
++{
++	int ret;
++
++	ret = clk_prepare_enable(clk->nfi_clk);
++	if (ret) {
++		dev_err(dev, "failed to enable nfi clk\n");
++		return ret;
++	}
++
++	ret = clk_prepare_enable(clk->pad_clk);
++	if (ret) {
++		dev_err(dev, "failed to enable pad clk\n");
++		clk_disable_unprepare(clk->nfi_clk);
++		return ret;
++	}
++
++	return 0;
++}
++
++static void mtk_nfc_disable_clk(struct mtk_nfc_clk *clk)
++{
++	clk_disable_unprepare(clk->nfi_clk);
++	clk_disable_unprepare(clk->pad_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 mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
++	struct mtk_nfc_fdm *fdm = &mtk_nand->fdm;
++	u32 eccsteps;
++
++	eccsteps = mtd->writesize / chip->ecc.size;
++
++	if (section >= eccsteps)
++		return -ERANGE;
++
++	oob_region->length = fdm->reg_size - fdm->ecc_size;
++	oob_region->offset = section * fdm->reg_size + fdm->ecc_size;
++
++	return 0;
++}
++
++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 mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
++	u32 eccsteps;
++
++	if (section)
++		return -ERANGE;
++
++	eccsteps = mtd->writesize / chip->ecc.size;
++	oob_region->offset = mtk_nand->fdm.reg_size * eccsteps;
++	oob_region->length = mtd->oobsize - oob_region->offset;
++
++	return 0;
++}
++
++static const struct mtd_ooblayout_ops mtk_nfc_ooblayout_ops = {
++	.free = mtk_nfc_ooblayout_free,
++	.ecc = mtk_nfc_ooblayout_ecc,
++};
++
++static void mtk_nfc_set_fdm(struct mtk_nfc_fdm *fdm, struct mtd_info *mtd)
++{
++	struct nand_chip *nand = mtd_to_nand(mtd);
++	struct mtk_nfc_nand_chip *chip = to_mtk_nand(nand);
++	u32 ecc_bytes;
++
++	ecc_bytes = DIV_ROUND_UP(nand->ecc.strength * ECC_PARITY_BITS, 8);
++
++	fdm->reg_size = chip->spare_per_sector - ecc_bytes;
++	if (fdm->reg_size > NFI_FDM_MAX_SIZE)
++		fdm->reg_size = NFI_FDM_MAX_SIZE;
++
++	/* bad block mark storage */
++	fdm->ecc_size = 1;
++}
++
++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);
++
++	if (mtd->writesize == 512) {
++		bm_ctl->bm_swap = mtk_nfc_no_bad_mark_swap;
++	} else {
++		bm_ctl->bm_swap = mtk_nfc_bad_mark_swap;
++		bm_ctl->sec = mtd->writesize / mtk_data_len(nand);
++		bm_ctl->pos = mtd->writesize % mtk_data_len(nand);
++	}
++}
++
++static int mtk_nfc_set_spare_per_sector(u32 *sps, struct mtd_info *mtd)
++{
++	struct nand_chip *nand = mtd_to_nand(mtd);
++	struct mtk_nfc *nfc = nand_get_controller_data(nand);
++	const u8 *spare = nfc->caps->spare_size;
++	u32 eccsteps, i, closest_spare = 0;
++
++	eccsteps = mtd->writesize / nand->ecc.size;
++	*sps = mtd->oobsize / eccsteps;
++
++	if (nand->ecc.size == 1024)
++		*sps >>= 1;
++
++	if (*sps < MTK_NFC_MIN_SPARE)
++		return -EINVAL;
++
++	for (i = 0; i < nfc->caps->num_spare_size; i++) {
++		if (*sps >= spare[i] && spare[i] >= spare[closest_spare]) {
++			closest_spare = i;
++			if (*sps == spare[i])
++				break;
++		}
++	}
++
++	*sps = spare[closest_spare];
++
++	if (nand->ecc.size == 1024)
++		*sps <<= 1;
++
++	return 0;
++}
++
++static int mtk_nfc_ecc_init(struct device *dev, struct mtd_info *mtd)
++{
++	struct nand_chip *nand = mtd_to_nand(mtd);
++	struct mtk_nfc *nfc = nand_get_controller_data(nand);
++	u32 spare;
++	int free, ret;
++
++	/* support only ecc hw mode */
++	if (nand->ecc.mode != NAND_ECC_HW) {
++		dev_err(dev, "ecc.mode not supported\n");
++		return -EINVAL;
++	}
++
++	/* if optional dt settings not present */
++	if (!nand->ecc.size || !nand->ecc.strength) {
++		/* use datasheet requirements */
++		nand->ecc.strength = nand->ecc_strength_ds;
++		nand->ecc.size = nand->ecc_step_ds;
++
++		/*
++		 * align eccstrength and eccsize
++		 * this controller only supports 512 and 1024 sizes
++		 */
++		if (nand->ecc.size < 1024) {
++			if (mtd->writesize > 512) {
++				nand->ecc.size = 1024;
++				nand->ecc.strength <<= 1;
++			} else {
++				nand->ecc.size = 512;
++			}
++		} else {
++			nand->ecc.size = 1024;
++		}
++
++		ret = mtk_nfc_set_spare_per_sector(&spare, mtd);
++		if (ret)
++			return ret;
++
++		/* calculate oob bytes except ecc parity data */
++		free = ((nand->ecc.strength * ECC_PARITY_BITS) + 7) >> 3;
++		free = spare - free;
++
++		/*
++		 * enhance ecc strength if oob left is bigger than max FDM size
++		 * or reduce ecc strength if oob size is not enough for ecc
++		 * parity data.
++		 */
++		if (free > NFI_FDM_MAX_SIZE) {
++			spare -= NFI_FDM_MAX_SIZE;
++			nand->ecc.strength = (spare << 3) / ECC_PARITY_BITS;
++		} else if (free < 0) {
++			spare -= NFI_FDM_MIN_SIZE;
++			nand->ecc.strength = (spare << 3) / ECC_PARITY_BITS;
++		}
++	}
++
++	mtk_ecc_adjust_strength(nfc->ecc, &nand->ecc.strength);
++
++	dev_info(dev, "eccsize %d eccstrength %d\n",
++		 nand->ecc.size, nand->ecc.strength);
++
++	return 0;
++}
++
++static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc,
++				  struct device_node *np)
++{
++	struct mtk_nfc_nand_chip *chip;
++	struct nand_chip *nand;
++	struct mtd_info *mtd;
++	int nsels, len;
++	u32 tmp;
++	int ret;
++	int i;
++
++	if (!of_get_property(np, "reg", &nsels))
++		return -ENODEV;
++
++	nsels /= sizeof(u32);
++	if (!nsels || nsels > MTK_NAND_MAX_NSELS) {
++		dev_err(dev, "invalid reg property size %d\n", nsels);
++		return -EINVAL;
++	}
++
++	chip = devm_kzalloc(dev, sizeof(*chip) + nsels * sizeof(u8),
++			    GFP_KERNEL);
++	if (!chip)
++		return -ENOMEM;
++
++	chip->nsels = nsels;
++	for (i = 0; i < nsels; i++) {
++		ret = of_property_read_u32_index(np, "reg", i, &tmp);
++		if (ret) {
++			dev_err(dev, "reg property failure : %d\n", ret);
++			return ret;
++		}
++		chip->sels[i] = tmp;
++	}
++
++	nand = &chip->nand;
++	nand->controller = &nfc->controller;
++
++	nand_set_flash_node(nand, np);
++	nand_set_controller_data(nand, nfc);
++
++	nand->options |= NAND_USE_BOUNCE_BUFFER | NAND_SUBPAGE_READ;
++	nand->dev_ready = mtk_nfc_dev_ready;
++	nand->select_chip = mtk_nfc_select_chip;
++	nand->write_byte = mtk_nfc_write_byte;
++	nand->write_buf = mtk_nfc_write_buf;
++	nand->read_byte = mtk_nfc_read_byte;
++	nand->read_buf = mtk_nfc_read_buf;
++	nand->cmd_ctrl = mtk_nfc_cmd_ctrl;
++	nand->setup_data_interface = mtk_nfc_setup_data_interface;
++
++	/* set default mode in case dt entry is missing */
++	nand->ecc.mode = NAND_ECC_HW;
++
++	nand->ecc.write_subpage = mtk_nfc_write_subpage_hwecc;
++	nand->ecc.write_page_raw = mtk_nfc_write_page_raw;
++	nand->ecc.write_page = mtk_nfc_write_page_hwecc;
++	nand->ecc.write_oob_raw = mtk_nfc_write_oob_std;
++	nand->ecc.write_oob = mtk_nfc_write_oob_std;
++
++	nand->ecc.read_subpage = mtk_nfc_read_subpage_hwecc;
++	nand->ecc.read_page_raw = mtk_nfc_read_page_raw;
++	nand->ecc.read_page = mtk_nfc_read_page_hwecc;
++	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->owner = THIS_MODULE;
++	mtd->dev.parent = dev;
++	mtd->name = MTK_NAME;
++	mtd_set_ooblayout(mtd, &mtk_nfc_ooblayout_ops);
++
++	mtk_nfc_hw_init(nfc);
++
++	ret = nand_scan_ident(mtd, nsels, NULL);
++	if (ret)
++		return ret;
++
++	/* store bbt magic in page, cause OOB is not protected */
++	if (nand->bbt_options & NAND_BBT_USE_FLASH)
++		nand->bbt_options |= NAND_BBT_NO_OOB;
++
++	ret = mtk_nfc_ecc_init(dev, mtd);
++	if (ret)
++		return -EINVAL;
++
++	if (nand->options & NAND_BUSWIDTH_16) {
++		dev_err(dev, "16bits buswidth not supported");
++		return -EINVAL;
++	}
++
++	ret = mtk_nfc_set_spare_per_sector(&chip->spare_per_sector, mtd);
++	if (ret)
++		return ret;
++
++	mtk_nfc_set_fdm(&chip->fdm, mtd);
++	mtk_nfc_set_bad_mark_ctl(&chip->bad_mark, mtd);
++
++	len = mtd->writesize + mtd->oobsize;
++	nfc->buffer = devm_kzalloc(dev, len, GFP_KERNEL);
++	if (!nfc->buffer)
++		return  -ENOMEM;
++
++	ret = nand_scan_tail(mtd);
++	if (ret)
++		return ret;
++
++	ret = mtd_device_parse_register(mtd, NULL, NULL, NULL, 0);
++	if (ret) {
++		dev_err(dev, "mtd parse partition error\n");
++		nand_release(mtd);
++		return ret;
++	}
++
++	list_add_tail(&chip->node, &nfc->chips);
++
++	return 0;
++}
++
++static int mtk_nfc_nand_chips_init(struct device *dev, struct mtk_nfc *nfc)
++{
++	struct device_node *np = dev->of_node;
++	struct device_node *nand_np;
++	int ret;
++
++	for_each_child_of_node(np, nand_np) {
++		ret = mtk_nfc_nand_chip_init(dev, nfc, nand_np);
++		if (ret) {
++			of_node_put(nand_np);
++			return ret;
++		}
++	}
++
++	return 0;
++}
++
++static const struct mtk_nfc_caps mtk_nfc_caps_mt2701 = {
++	.spare_size = spare_size_mt2701,
++	.num_spare_size = 16,
++	.pageformat_spare_shift = 4,
++	.nfi_clk_div = 1,
++};
++
++static const struct mtk_nfc_caps mtk_nfc_caps_mt2712 = {
++	.spare_size = spare_size_mt2712,
++	.num_spare_size = 19,
++	.pageformat_spare_shift = 16,
++	.nfi_clk_div = 2,
++};
++
++static const struct of_device_id mtk_nfc_id_table[] = {
++	{
++		.compatible = "mediatek,mt2701-nfc",
++		.data = &mtk_nfc_caps_mt2701,
++	}, {
++		.compatible = "mediatek,mt2712-nfc",
++		.data = &mtk_nfc_caps_mt2712,
++	},
++	{}
++};
++MODULE_DEVICE_TABLE(of, mtk_nfc_id_table);
++
++static int mtk_nfc_probe(struct platform_device *pdev)
++{
++	struct device *dev = &pdev->dev;
++	struct device_node *np = dev->of_node;
++	struct mtk_nfc *nfc;
++	struct resource *res;
++	const struct of_device_id *of_nfc_id = NULL;
++	int ret, irq;
++
++	nfc = devm_kzalloc(dev, sizeof(*nfc), GFP_KERNEL);
++	if (!nfc)
++		return -ENOMEM;
++
++	spin_lock_init(&nfc->controller.lock);
++	init_waitqueue_head(&nfc->controller.wq);
++	INIT_LIST_HEAD(&nfc->chips);
++
++	/* probe defer if not ready */
++	nfc->ecc = of_mtk_ecc_get(np);
++	if (IS_ERR(nfc->ecc))
++		return PTR_ERR(nfc->ecc);
++	else if (!nfc->ecc)
++		return -ENODEV;
++
++	nfc->dev = dev;
++
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	nfc->regs = devm_ioremap_resource(dev, res);
++	if (IS_ERR(nfc->regs)) {
++		ret = PTR_ERR(nfc->regs);
++		goto release_ecc;
++	}
++
++	nfc->clk.nfi_clk = devm_clk_get(dev, "nfi_clk");
++	if (IS_ERR(nfc->clk.nfi_clk)) {
++		dev_err(dev, "no clk\n");
++		ret = PTR_ERR(nfc->clk.nfi_clk);
++		goto release_ecc;
++	}
++
++	nfc->clk.pad_clk = devm_clk_get(dev, "pad_clk");
++	if (IS_ERR(nfc->clk.pad_clk)) {
++		dev_err(dev, "no pad clk\n");
++		ret = PTR_ERR(nfc->clk.pad_clk);
++		goto release_ecc;
++	}
++
++	ret = mtk_nfc_enable_clk(dev, &nfc->clk);
++	if (ret)
++		goto release_ecc;
++
++	irq = platform_get_irq(pdev, 0);
++	if (irq < 0) {
++		dev_err(dev, "no nfi irq resource\n");
++		ret = -EINVAL;
++		goto clk_disable;
++	}
++
++	ret = devm_request_irq(dev, irq, mtk_nfc_irq, 0x0, "mtk-nand", nfc);
++	if (ret) {
++		dev_err(dev, "failed to request nfi irq\n");
++		goto clk_disable;
++	}
++
++	ret = dma_set_mask(dev, DMA_BIT_MASK(32));
++	if (ret) {
++		dev_err(dev, "failed to set dma mask\n");
++		goto clk_disable;
++	}
++
++	of_nfc_id = of_match_device(mtk_nfc_id_table, &pdev->dev);
++	if (!of_nfc_id) {
++		ret = -ENODEV;
++		goto clk_disable;
++	}
++
++	nfc->caps = of_nfc_id->data;
++
++	platform_set_drvdata(pdev, nfc);
++
++	ret = mtk_nfc_nand_chips_init(dev, nfc);
++	if (ret) {
++		dev_err(dev, "failed to init nand chips\n");
++		goto clk_disable;
++	}
++
++	return 0;
++
++clk_disable:
++	mtk_nfc_disable_clk(&nfc->clk);
++
++release_ecc:
++	mtk_ecc_release(nfc->ecc);
++
++	return ret;
++}
++
++static int mtk_nfc_remove(struct platform_device *pdev)
++{
++	struct mtk_nfc *nfc = platform_get_drvdata(pdev);
++	struct mtk_nfc_nand_chip *chip;
++
++	while (!list_empty(&nfc->chips)) {
++		chip = list_first_entry(&nfc->chips, struct mtk_nfc_nand_chip,
++					node);
++		nand_release(nand_to_mtd(&chip->nand));
++		list_del(&chip->node);
++	}
++
++	mtk_ecc_release(nfc->ecc);
++	mtk_nfc_disable_clk(&nfc->clk);
++
++	return 0;
++}
++
++#ifdef CONFIG_PM_SLEEP
++static int mtk_nfc_suspend(struct device *dev)
++{
++	struct mtk_nfc *nfc = dev_get_drvdata(dev);
++
++	mtk_nfc_disable_clk(&nfc->clk);
++
++	return 0;
++}
++
++static int mtk_nfc_resume(struct device *dev)
++{
++	struct mtk_nfc *nfc = dev_get_drvdata(dev);
++	struct mtk_nfc_nand_chip *chip;
++	struct nand_chip *nand;
++	struct mtd_info *mtd;
++	int ret;
++	u32 i;
++
++	udelay(200);
++
++	ret = mtk_nfc_enable_clk(dev, &nfc->clk);
++	if (ret)
++		return ret;
++
++	/* reset NAND chip if VCC was powered off */
++	list_for_each_entry(chip, &nfc->chips, node) {
++		nand = &chip->nand;
++		mtd = nand_to_mtd(nand);
++		for (i = 0; i < chip->nsels; i++) {
++			nand->select_chip(mtd, i);
++			nand->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
++		}
++	}
++
++	return 0;
++}
++
++static SIMPLE_DEV_PM_OPS(mtk_nfc_pm_ops, mtk_nfc_suspend, mtk_nfc_resume);
++#endif
++
++static struct platform_driver mtk_nfc_driver = {
++	.probe  = mtk_nfc_probe,
++	.remove = mtk_nfc_remove,
++	.driver = {
++		.name  = MTK_NAME,
++		.of_match_table = mtk_nfc_id_table,
++#ifdef CONFIG_PM_SLEEP
++		.pm = &mtk_nfc_pm_ops,
++#endif
++	},
++};
++
++module_platform_driver(mtk_nfc_driver);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Xiaolei Li <xiaolei.li@mediatek.com>");
++MODULE_DESCRIPTION("MTK Nand Flash Controller Driver");
+diff --git a/drivers/mtd/nand/raw/mxc_nand.c b/drivers/mtd/nand/raw/mxc_nand.c
+new file mode 100644
+index 0000000..53e5e03
+--- /dev/null
++++ b/drivers/mtd/nand/raw/mxc_nand.c
+@@ -0,0 +1,1854 @@
++/*
++ * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
++ * Copyright 2008 Sascha Hauer, kernel@pengutronix.de
++ *
++ * 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.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
++ * MA 02110-1301, USA.
++ */
++
++#include <linux/delay.h>
++#include <linux/slab.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/rawnand.h>
++#include <linux/mtd/partitions.h>
++#include <linux/interrupt.h>
++#include <linux/device.h>
++#include <linux/platform_device.h>
++#include <linux/clk.h>
++#include <linux/err.h>
++#include <linux/io.h>
++#include <linux/irq.h>
++#include <linux/completion.h>
++#include <linux/of.h>
++#include <linux/of_device.h>
++
++#include <asm/mach/flash.h>
++#include <linux/platform_data/mtd-mxc_nand.h>
++
++#define DRIVER_NAME "mxc_nand"
++
++/* Addresses for NFC registers */
++#define NFC_V1_V2_BUF_SIZE		(host->regs + 0x00)
++#define NFC_V1_V2_BUF_ADDR		(host->regs + 0x04)
++#define NFC_V1_V2_FLASH_ADDR		(host->regs + 0x06)
++#define NFC_V1_V2_FLASH_CMD		(host->regs + 0x08)
++#define NFC_V1_V2_CONFIG		(host->regs + 0x0a)
++#define NFC_V1_V2_ECC_STATUS_RESULT	(host->regs + 0x0c)
++#define NFC_V1_V2_RSLTMAIN_AREA		(host->regs + 0x0e)
++#define NFC_V1_V2_RSLTSPARE_AREA	(host->regs + 0x10)
++#define NFC_V1_V2_WRPROT		(host->regs + 0x12)
++#define NFC_V1_UNLOCKSTART_BLKADDR	(host->regs + 0x14)
++#define NFC_V1_UNLOCKEND_BLKADDR	(host->regs + 0x16)
++#define NFC_V21_UNLOCKSTART_BLKADDR0	(host->regs + 0x20)
++#define NFC_V21_UNLOCKSTART_BLKADDR1	(host->regs + 0x24)
++#define NFC_V21_UNLOCKSTART_BLKADDR2	(host->regs + 0x28)
++#define NFC_V21_UNLOCKSTART_BLKADDR3	(host->regs + 0x2c)
++#define NFC_V21_UNLOCKEND_BLKADDR0	(host->regs + 0x22)
++#define NFC_V21_UNLOCKEND_BLKADDR1	(host->regs + 0x26)
++#define NFC_V21_UNLOCKEND_BLKADDR2	(host->regs + 0x2a)
++#define NFC_V21_UNLOCKEND_BLKADDR3	(host->regs + 0x2e)
++#define NFC_V1_V2_NF_WRPRST		(host->regs + 0x18)
++#define NFC_V1_V2_CONFIG1		(host->regs + 0x1a)
++#define NFC_V1_V2_CONFIG2		(host->regs + 0x1c)
++
++#define NFC_V2_CONFIG1_ECC_MODE_4	(1 << 0)
++#define NFC_V1_V2_CONFIG1_SP_EN		(1 << 2)
++#define NFC_V1_V2_CONFIG1_ECC_EN	(1 << 3)
++#define NFC_V1_V2_CONFIG1_INT_MSK	(1 << 4)
++#define NFC_V1_V2_CONFIG1_BIG		(1 << 5)
++#define NFC_V1_V2_CONFIG1_RST		(1 << 6)
++#define NFC_V1_V2_CONFIG1_CE		(1 << 7)
++#define NFC_V2_CONFIG1_ONE_CYCLE	(1 << 8)
++#define NFC_V2_CONFIG1_PPB(x)		(((x) & 0x3) << 9)
++#define NFC_V2_CONFIG1_FP_INT		(1 << 11)
++
++#define NFC_V1_V2_CONFIG2_INT		(1 << 15)
++
++/*
++ * Operation modes for the NFC. Valid for v1, v2 and v3
++ * type controllers.
++ */
++#define NFC_CMD				(1 << 0)
++#define NFC_ADDR			(1 << 1)
++#define NFC_INPUT			(1 << 2)
++#define NFC_OUTPUT			(1 << 3)
++#define NFC_ID				(1 << 4)
++#define NFC_STATUS			(1 << 5)
++
++#define NFC_V3_FLASH_CMD		(host->regs_axi + 0x00)
++#define NFC_V3_FLASH_ADDR0		(host->regs_axi + 0x04)
++
++#define NFC_V3_CONFIG1			(host->regs_axi + 0x34)
++#define NFC_V3_CONFIG1_SP_EN		(1 << 0)
++#define NFC_V3_CONFIG1_RBA(x)		(((x) & 0x7 ) << 4)
++
++#define NFC_V3_ECC_STATUS_RESULT	(host->regs_axi + 0x38)
++
++#define NFC_V3_LAUNCH			(host->regs_axi + 0x40)
++
++#define NFC_V3_WRPROT			(host->regs_ip + 0x0)
++#define NFC_V3_WRPROT_LOCK_TIGHT	(1 << 0)
++#define NFC_V3_WRPROT_LOCK		(1 << 1)
++#define NFC_V3_WRPROT_UNLOCK		(1 << 2)
++#define NFC_V3_WRPROT_BLS_UNLOCK	(2 << 6)
++
++#define NFC_V3_WRPROT_UNLOCK_BLK_ADD0   (host->regs_ip + 0x04)
++
++#define NFC_V3_CONFIG2			(host->regs_ip + 0x24)
++#define NFC_V3_CONFIG2_PS_512			(0 << 0)
++#define NFC_V3_CONFIG2_PS_2048			(1 << 0)
++#define NFC_V3_CONFIG2_PS_4096			(2 << 0)
++#define NFC_V3_CONFIG2_ONE_CYCLE		(1 << 2)
++#define NFC_V3_CONFIG2_ECC_EN			(1 << 3)
++#define NFC_V3_CONFIG2_2CMD_PHASES		(1 << 4)
++#define NFC_V3_CONFIG2_NUM_ADDR_PHASE0		(1 << 5)
++#define NFC_V3_CONFIG2_ECC_MODE_8		(1 << 6)
++#define NFC_V3_CONFIG2_PPB(x, shift)		(((x) & 0x3) << shift)
++#define NFC_V3_CONFIG2_NUM_ADDR_PHASE1(x)	(((x) & 0x3) << 12)
++#define NFC_V3_CONFIG2_INT_MSK			(1 << 15)
++#define NFC_V3_CONFIG2_ST_CMD(x)		(((x) & 0xff) << 24)
++#define NFC_V3_CONFIG2_SPAS(x)			(((x) & 0xff) << 16)
++
++#define NFC_V3_CONFIG3				(host->regs_ip + 0x28)
++#define NFC_V3_CONFIG3_ADD_OP(x)		(((x) & 0x3) << 0)
++#define NFC_V3_CONFIG3_FW8			(1 << 3)
++#define NFC_V3_CONFIG3_SBB(x)			(((x) & 0x7) << 8)
++#define NFC_V3_CONFIG3_NUM_OF_DEVICES(x)	(((x) & 0x7) << 12)
++#define NFC_V3_CONFIG3_RBB_MODE			(1 << 15)
++#define NFC_V3_CONFIG3_NO_SDMA			(1 << 20)
++
++#define NFC_V3_IPC			(host->regs_ip + 0x2C)
++#define NFC_V3_IPC_CREQ			(1 << 0)
++#define NFC_V3_IPC_INT			(1 << 31)
++
++#define NFC_V3_DELAY_LINE		(host->regs_ip + 0x34)
++
++struct mxc_nand_host;
++
++struct mxc_nand_devtype_data {
++	void (*preset)(struct mtd_info *);
++	void (*send_cmd)(struct mxc_nand_host *, uint16_t, int);
++	void (*send_addr)(struct mxc_nand_host *, uint16_t, int);
++	void (*send_page)(struct mtd_info *, unsigned int);
++	void (*send_read_id)(struct mxc_nand_host *);
++	uint16_t (*get_dev_status)(struct mxc_nand_host *);
++	int (*check_int)(struct mxc_nand_host *);
++	void (*irq_control)(struct mxc_nand_host *, int);
++	u32 (*get_ecc_status)(struct mxc_nand_host *);
++	const struct mtd_ooblayout_ops *ooblayout;
++	void (*select_chip)(struct mtd_info *mtd, int chip);
++	int (*correct_data)(struct mtd_info *mtd, u_char *dat,
++			u_char *read_ecc, u_char *calc_ecc);
++	int (*setup_data_interface)(struct mtd_info *mtd, int csline,
++				    const struct nand_data_interface *conf);
++
++	/*
++	 * On i.MX21 the CONFIG2:INT bit cannot be read if interrupts are masked
++	 * (CONFIG1:INT_MSK is set). To handle this the driver uses
++	 * enable_irq/disable_irq_nosync instead of CONFIG1:INT_MSK
++	 */
++	int irqpending_quirk;
++	int needs_ip;
++
++	size_t regs_offset;
++	size_t spare0_offset;
++	size_t axi_offset;
++
++	int spare_len;
++	int eccbytes;
++	int eccsize;
++	int ppb_shift;
++};
++
++struct mxc_nand_host {
++	struct nand_chip	nand;
++	struct device		*dev;
++
++	void __iomem		*spare0;
++	void __iomem		*main_area0;
++
++	void __iomem		*base;
++	void __iomem		*regs;
++	void __iomem		*regs_axi;
++	void __iomem		*regs_ip;
++	int			status_request;
++	struct clk		*clk;
++	int			clk_act;
++	int			irq;
++	int			eccsize;
++	int			used_oobsize;
++	int			active_cs;
++
++	struct completion	op_completion;
++
++	uint8_t			*data_buf;
++	unsigned int		buf_start;
++
++	const struct mxc_nand_devtype_data *devtype_data;
++	struct mxc_nand_platform_data pdata;
++};
++
++static const char * const part_probes[] = {
++	"cmdlinepart", "RedBoot", "ofpart", NULL };
++
++static void memcpy32_fromio(void *trg, const void __iomem  *src, size_t size)
++{
++	int i;
++	u32 *t = trg;
++	const __iomem u32 *s = src;
++
++	for (i = 0; i < (size >> 2); i++)
++		*t++ = __raw_readl(s++);
++}
++
++static void memcpy16_fromio(void *trg, const void __iomem  *src, size_t size)
++{
++	int i;
++	u16 *t = trg;
++	const __iomem u16 *s = src;
++
++	/* We assume that src (IO) is always 32bit aligned */
++	if (PTR_ALIGN(trg, 4) == trg && IS_ALIGNED(size, 4)) {
++		memcpy32_fromio(trg, src, size);
++		return;
++	}
++
++	for (i = 0; i < (size >> 1); i++)
++		*t++ = __raw_readw(s++);
++}
++
++static inline void memcpy32_toio(void __iomem *trg, const void *src, int size)
++{
++	/* __iowrite32_copy use 32bit size values so divide by 4 */
++	__iowrite32_copy(trg, src, size / 4);
++}
++
++static void memcpy16_toio(void __iomem *trg, const void *src, int size)
++{
++	int i;
++	__iomem u16 *t = trg;
++	const u16 *s = src;
++
++	/* We assume that trg (IO) is always 32bit aligned */
++	if (PTR_ALIGN(src, 4) == src && IS_ALIGNED(size, 4)) {
++		memcpy32_toio(trg, src, size);
++		return;
++	}
++
++	for (i = 0; i < (size >> 1); i++)
++		__raw_writew(*s++, t++);
++}
++
++static int check_int_v3(struct mxc_nand_host *host)
++{
++	uint32_t tmp;
++
++	tmp = readl(NFC_V3_IPC);
++	if (!(tmp & NFC_V3_IPC_INT))
++		return 0;
++
++	tmp &= ~NFC_V3_IPC_INT;
++	writel(tmp, NFC_V3_IPC);
++
++	return 1;
++}
++
++static int check_int_v1_v2(struct mxc_nand_host *host)
++{
++	uint32_t tmp;
++
++	tmp = readw(NFC_V1_V2_CONFIG2);
++	if (!(tmp & NFC_V1_V2_CONFIG2_INT))
++		return 0;
++
++	if (!host->devtype_data->irqpending_quirk)
++		writew(tmp & ~NFC_V1_V2_CONFIG2_INT, NFC_V1_V2_CONFIG2);
++
++	return 1;
++}
++
++static void irq_control_v1_v2(struct mxc_nand_host *host, int activate)
++{
++	uint16_t tmp;
++
++	tmp = readw(NFC_V1_V2_CONFIG1);
++
++	if (activate)
++		tmp &= ~NFC_V1_V2_CONFIG1_INT_MSK;
++	else
++		tmp |= NFC_V1_V2_CONFIG1_INT_MSK;
++
++	writew(tmp, NFC_V1_V2_CONFIG1);
++}
++
++static void irq_control_v3(struct mxc_nand_host *host, int activate)
++{
++	uint32_t tmp;
++
++	tmp = readl(NFC_V3_CONFIG2);
++
++	if (activate)
++		tmp &= ~NFC_V3_CONFIG2_INT_MSK;
++	else
++		tmp |= NFC_V3_CONFIG2_INT_MSK;
++
++	writel(tmp, NFC_V3_CONFIG2);
++}
++
++static void irq_control(struct mxc_nand_host *host, int activate)
++{
++	if (host->devtype_data->irqpending_quirk) {
++		if (activate)
++			enable_irq(host->irq);
++		else
++			disable_irq_nosync(host->irq);
++	} else {
++		host->devtype_data->irq_control(host, activate);
++	}
++}
++
++static u32 get_ecc_status_v1(struct mxc_nand_host *host)
++{
++	return readw(NFC_V1_V2_ECC_STATUS_RESULT);
++}
++
++static u32 get_ecc_status_v2(struct mxc_nand_host *host)
++{
++	return readl(NFC_V1_V2_ECC_STATUS_RESULT);
++}
++
++static u32 get_ecc_status_v3(struct mxc_nand_host *host)
++{
++	return readl(NFC_V3_ECC_STATUS_RESULT);
++}
++
++static irqreturn_t mxc_nfc_irq(int irq, void *dev_id)
++{
++	struct mxc_nand_host *host = dev_id;
++
++	if (!host->devtype_data->check_int(host))
++		return IRQ_NONE;
++
++	irq_control(host, 0);
++
++	complete(&host->op_completion);
++
++	return IRQ_HANDLED;
++}
++
++/* This function polls the NANDFC to wait for the basic operation to
++ * complete by checking the INT bit of config2 register.
++ */
++static int wait_op_done(struct mxc_nand_host *host, int useirq)
++{
++	int ret = 0;
++
++	/*
++	 * If operation is already complete, don't bother to setup an irq or a
++	 * loop.
++	 */
++	if (host->devtype_data->check_int(host))
++		return 0;
++
++	if (useirq) {
++		unsigned long timeout;
++
++		reinit_completion(&host->op_completion);
++
++		irq_control(host, 1);
++
++		timeout = wait_for_completion_timeout(&host->op_completion, HZ);
++		if (!timeout && !host->devtype_data->check_int(host)) {
++			dev_dbg(host->dev, "timeout waiting for irq\n");
++			ret = -ETIMEDOUT;
++		}
++	} else {
++		int max_retries = 8000;
++		int done;
++
++		do {
++			udelay(1);
++
++			done = host->devtype_data->check_int(host);
++			if (done)
++				break;
++
++		} while (--max_retries);
++
++		if (!done) {
++			dev_dbg(host->dev, "timeout polling for completion\n");
++			ret = -ETIMEDOUT;
++		}
++	}
++
++	WARN_ONCE(ret < 0, "timeout! useirq=%d\n", useirq);
++
++	return ret;
++}
++
++static void send_cmd_v3(struct mxc_nand_host *host, uint16_t cmd, int useirq)
++{
++	/* fill command */
++	writel(cmd, NFC_V3_FLASH_CMD);
++
++	/* send out command */
++	writel(NFC_CMD, NFC_V3_LAUNCH);
++
++	/* Wait for operation to complete */
++	wait_op_done(host, useirq);
++}
++
++/* This function issues the specified command to the NAND device and
++ * waits for completion. */
++static void send_cmd_v1_v2(struct mxc_nand_host *host, uint16_t cmd, int useirq)
++{
++	pr_debug("send_cmd(host, 0x%x, %d)\n", cmd, useirq);
++
++	writew(cmd, NFC_V1_V2_FLASH_CMD);
++	writew(NFC_CMD, NFC_V1_V2_CONFIG2);
++
++	if (host->devtype_data->irqpending_quirk && (cmd == NAND_CMD_RESET)) {
++		int max_retries = 100;
++		/* Reset completion is indicated by NFC_CONFIG2 */
++		/* being set to 0 */
++		while (max_retries-- > 0) {
++			if (readw(NFC_V1_V2_CONFIG2) == 0) {
++				break;
++			}
++			udelay(1);
++		}
++		if (max_retries < 0)
++			pr_debug("%s: RESET failed\n", __func__);
++	} else {
++		/* Wait for operation to complete */
++		wait_op_done(host, useirq);
++	}
++}
++
++static void send_addr_v3(struct mxc_nand_host *host, uint16_t addr, int islast)
++{
++	/* fill address */
++	writel(addr, NFC_V3_FLASH_ADDR0);
++
++	/* send out address */
++	writel(NFC_ADDR, NFC_V3_LAUNCH);
++
++	wait_op_done(host, 0);
++}
++
++/* This function sends an address (or partial address) to the
++ * NAND device. The address is used to select the source/destination for
++ * a NAND command. */
++static void send_addr_v1_v2(struct mxc_nand_host *host, uint16_t addr, int islast)
++{
++	pr_debug("send_addr(host, 0x%x %d)\n", addr, islast);
++
++	writew(addr, NFC_V1_V2_FLASH_ADDR);
++	writew(NFC_ADDR, NFC_V1_V2_CONFIG2);
++
++	/* Wait for operation to complete */
++	wait_op_done(host, islast);
++}
++
++static void send_page_v3(struct mtd_info *mtd, unsigned int ops)
++{
++	struct nand_chip *nand_chip = mtd_to_nand(mtd);
++	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
++	uint32_t tmp;
++
++	tmp = readl(NFC_V3_CONFIG1);
++	tmp &= ~(7 << 4);
++	writel(tmp, NFC_V3_CONFIG1);
++
++	/* transfer data from NFC ram to nand */
++	writel(ops, NFC_V3_LAUNCH);
++
++	wait_op_done(host, false);
++}
++
++static void send_page_v2(struct mtd_info *mtd, unsigned int ops)
++{
++	struct nand_chip *nand_chip = mtd_to_nand(mtd);
++	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
++
++	/* NANDFC buffer 0 is used for page read/write */
++	writew(host->active_cs << 4, NFC_V1_V2_BUF_ADDR);
++
++	writew(ops, NFC_V1_V2_CONFIG2);
++
++	/* Wait for operation to complete */
++	wait_op_done(host, true);
++}
++
++static void send_page_v1(struct mtd_info *mtd, unsigned int ops)
++{
++	struct nand_chip *nand_chip = mtd_to_nand(mtd);
++	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
++	int bufs, i;
++
++	if (mtd->writesize > 512)
++		bufs = 4;
++	else
++		bufs = 1;
++
++	for (i = 0; i < bufs; i++) {
++
++		/* NANDFC buffer 0 is used for page read/write */
++		writew((host->active_cs << 4) | i, NFC_V1_V2_BUF_ADDR);
++
++		writew(ops, NFC_V1_V2_CONFIG2);
++
++		/* Wait for operation to complete */
++		wait_op_done(host, true);
++	}
++}
++
++static void send_read_id_v3(struct mxc_nand_host *host)
++{
++	/* Read ID into main buffer */
++	writel(NFC_ID, NFC_V3_LAUNCH);
++
++	wait_op_done(host, true);
++
++	memcpy32_fromio(host->data_buf, host->main_area0, 16);
++}
++
++/* Request the NANDFC to perform a read of the NAND device ID. */
++static void send_read_id_v1_v2(struct mxc_nand_host *host)
++{
++	/* NANDFC buffer 0 is used for device ID output */
++	writew(host->active_cs << 4, NFC_V1_V2_BUF_ADDR);
++
++	writew(NFC_ID, NFC_V1_V2_CONFIG2);
++
++	/* Wait for operation to complete */
++	wait_op_done(host, true);
++
++	memcpy32_fromio(host->data_buf, host->main_area0, 16);
++}
++
++static uint16_t get_dev_status_v3(struct mxc_nand_host *host)
++{
++	writew(NFC_STATUS, NFC_V3_LAUNCH);
++	wait_op_done(host, true);
++
++	return readl(NFC_V3_CONFIG1) >> 16;
++}
++
++/* This function requests the NANDFC to perform a read of the
++ * NAND device status and returns the current status. */
++static uint16_t get_dev_status_v1_v2(struct mxc_nand_host *host)
++{
++	void __iomem *main_buf = host->main_area0;
++	uint32_t store;
++	uint16_t ret;
++
++	writew(host->active_cs << 4, NFC_V1_V2_BUF_ADDR);
++
++	/*
++	 * The device status is stored in main_area0. To
++	 * prevent corruption of the buffer save the value
++	 * and restore it afterwards.
++	 */
++	store = readl(main_buf);
++
++	writew(NFC_STATUS, NFC_V1_V2_CONFIG2);
++	wait_op_done(host, true);
++
++	ret = readw(main_buf);
++
++	writel(store, main_buf);
++
++	return ret;
++}
++
++/* This functions is used by upper layer to checks if device is ready */
++static int mxc_nand_dev_ready(struct mtd_info *mtd)
++{
++	/*
++	 * NFC handles R/B internally. Therefore, this function
++	 * always returns status as ready.
++	 */
++	return 1;
++}
++
++static void mxc_nand_enable_hwecc(struct mtd_info *mtd, int mode)
++{
++	/*
++	 * If HW ECC is enabled, we turn it on during init. There is
++	 * no need to enable again here.
++	 */
++}
++
++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 mxc_nand_host *host = nand_get_controller_data(nand_chip);
++
++	/*
++	 * 1-Bit errors are automatically corrected in HW.  No need for
++	 * additional correction.  2-Bit errors cannot be corrected by
++	 * HW ECC, so we need to return failure
++	 */
++	uint16_t ecc_status = get_ecc_status_v1(host);
++
++	if (((ecc_status & 0x3) == 2) || ((ecc_status >> 2) == 2)) {
++		pr_debug("MXC_NAND: HWECC uncorrectable 2-bit ECC error\n");
++		return -EBADMSG;
++	}
++
++	return 0;
++}
++
++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 mxc_nand_host *host = nand_get_controller_data(nand_chip);
++	u32 ecc_stat, err;
++	int no_subpages = 1;
++	int ret = 0;
++	u8 ecc_bit_mask, err_limit;
++
++	ecc_bit_mask = (host->eccsize == 4) ? 0x7 : 0xf;
++	err_limit = (host->eccsize == 4) ? 0x4 : 0x8;
++
++	no_subpages = mtd->writesize >> 9;
++
++	ecc_stat = host->devtype_data->get_ecc_status(host);
++
++	do {
++		err = ecc_stat & ecc_bit_mask;
++		if (err > err_limit) {
++			printk(KERN_WARNING "UnCorrectable RS-ECC Error\n");
++			return -EBADMSG;
++		} else {
++			ret += err;
++		}
++		ecc_stat >>= 4;
++	} while (--no_subpages);
++
++	pr_debug("%d Symbol Correctable RS-ECC Error\n", ret);
++
++	return ret;
++}
++
++static int mxc_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
++				  u_char *ecc_code)
++{
++	return 0;
++}
++
++static u_char mxc_nand_read_byte(struct mtd_info *mtd)
++{
++	struct nand_chip *nand_chip = mtd_to_nand(mtd);
++	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
++	uint8_t ret;
++
++	/* Check for status request */
++	if (host->status_request)
++		return host->devtype_data->get_dev_status(host) & 0xFF;
++
++	if (nand_chip->options & NAND_BUSWIDTH_16) {
++		/* only take the lower byte of each word */
++		ret = *(uint16_t *)(host->data_buf + host->buf_start);
++
++		host->buf_start += 2;
++	} else {
++		ret = *(uint8_t *)(host->data_buf + host->buf_start);
++		host->buf_start++;
++	}
++
++	pr_debug("%s: ret=0x%hhx (start=%u)\n", __func__, ret, host->buf_start);
++	return ret;
++}
++
++static uint16_t mxc_nand_read_word(struct mtd_info *mtd)
++{
++	struct nand_chip *nand_chip = mtd_to_nand(mtd);
++	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
++	uint16_t ret;
++
++	ret = *(uint16_t *)(host->data_buf + host->buf_start);
++	host->buf_start += 2;
++
++	return ret;
++}
++
++/* Write data of length len to buffer buf. The data to be
++ * written on NAND Flash is first copied to RAMbuffer. After the Data Input
++ * Operation by the NFC, the data is written to NAND Flash */
++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 mxc_nand_host *host = nand_get_controller_data(nand_chip);
++	u16 col = host->buf_start;
++	int n = mtd->oobsize + mtd->writesize - col;
++
++	n = min(n, len);
++
++	memcpy(host->data_buf + col, buf, n);
++
++	host->buf_start += n;
++}
++
++/* Read the data buffer from the NAND Flash. To read the data from NAND
++ * Flash first the data output cycle is initiated by the NFC, which copies
++ * the data to RAMbuffer. This data of length len is then copied to buffer buf.
++ */
++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 mxc_nand_host *host = nand_get_controller_data(nand_chip);
++	u16 col = host->buf_start;
++	int n = mtd->oobsize + mtd->writesize - col;
++
++	n = min(n, len);
++
++	memcpy(buf, host->data_buf + col, n);
++
++	host->buf_start += n;
++}
++
++/* This function is used by upper layer for select and
++ * 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 mxc_nand_host *host = nand_get_controller_data(nand_chip);
++
++	if (chip == -1) {
++		/* Disable the NFC clock */
++		if (host->clk_act) {
++			clk_disable_unprepare(host->clk);
++			host->clk_act = 0;
++		}
++		return;
++	}
++
++	if (!host->clk_act) {
++		/* Enable the NFC clock */
++		clk_prepare_enable(host->clk);
++		host->clk_act = 1;
++	}
++}
++
++static void mxc_nand_select_chip_v2(struct mtd_info *mtd, int chip)
++{
++	struct nand_chip *nand_chip = mtd_to_nand(mtd);
++	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
++
++	if (chip == -1) {
++		/* Disable the NFC clock */
++		if (host->clk_act) {
++			clk_disable_unprepare(host->clk);
++			host->clk_act = 0;
++		}
++		return;
++	}
++
++	if (!host->clk_act) {
++		/* Enable the NFC clock */
++		clk_prepare_enable(host->clk);
++		host->clk_act = 1;
++	}
++
++	host->active_cs = chip;
++	writew(host->active_cs << 4, NFC_V1_V2_BUF_ADDR);
++}
++
++/*
++ * The controller splits a page into data chunks of 512 bytes + partial oob.
++ * There are writesize / 512 such chunks, the size of the partial oob parts is
++ * oobsize / #chunks rounded down to a multiple of 2. The last oob chunk then
++ * contains additionally the byte lost by rounding (if any).
++ * This function handles the needed shuffling between host->data_buf (which
++ * holds a page in natural order, i.e. writesize bytes data + oobsize bytes
++ * spare) and the NFC buffer.
++ */
++static void copy_spare(struct mtd_info *mtd, bool bfrom)
++{
++	struct nand_chip *this = mtd_to_nand(mtd);
++	struct mxc_nand_host *host = nand_get_controller_data(this);
++	u16 i, oob_chunk_size;
++	u16 num_chunks = mtd->writesize / 512;
++
++	u8 *d = host->data_buf + mtd->writesize;
++	u8 __iomem *s = host->spare0;
++	u16 sparebuf_size = host->devtype_data->spare_len;
++
++	/* size of oob chunk for all but possibly the last one */
++	oob_chunk_size = (host->used_oobsize / num_chunks) & ~1;
++
++	if (bfrom) {
++		for (i = 0; i < num_chunks - 1; i++)
++			memcpy16_fromio(d + i * oob_chunk_size,
++					s + i * sparebuf_size,
++					oob_chunk_size);
++
++		/* the last chunk */
++		memcpy16_fromio(d + i * oob_chunk_size,
++				s + i * sparebuf_size,
++				host->used_oobsize - i * oob_chunk_size);
++	} else {
++		for (i = 0; i < num_chunks - 1; i++)
++			memcpy16_toio(&s[i * sparebuf_size],
++				      &d[i * oob_chunk_size],
++				      oob_chunk_size);
++
++		/* the last chunk */
++		memcpy16_toio(&s[i * sparebuf_size],
++			      &d[i * oob_chunk_size],
++			      host->used_oobsize - i * oob_chunk_size);
++	}
++}
++
++/*
++ * MXC NANDFC can only perform full page+spare or spare-only read/write.  When
++ * the upper layers perform a read/write buf operation, the saved column address
++ * is used to index into the full page. So usually this function is called with
++ * column == 0 (unless no column cycle is needed indicated by column == -1)
++ */
++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 mxc_nand_host *host = nand_get_controller_data(nand_chip);
++
++	/* Write out column address, if necessary */
++	if (column != -1) {
++		host->devtype_data->send_addr(host, column & 0xff,
++					      page_addr == -1);
++		if (mtd->writesize > 512)
++			/* another col addr cycle for 2k page */
++			host->devtype_data->send_addr(host,
++						      (column >> 8) & 0xff,
++						      false);
++	}
++
++	/* Write out page address, if necessary */
++	if (page_addr != -1) {
++		/* paddr_0 - p_addr_7 */
++		host->devtype_data->send_addr(host, (page_addr & 0xff), false);
++
++		if (mtd->writesize > 512) {
++			if (mtd->size >= 0x10000000) {
++				/* paddr_8 - paddr_15 */
++				host->devtype_data->send_addr(host,
++						(page_addr >> 8) & 0xff,
++						false);
++				host->devtype_data->send_addr(host,
++						(page_addr >> 16) & 0xff,
++						true);
++			} else
++				/* paddr_8 - paddr_15 */
++				host->devtype_data->send_addr(host,
++						(page_addr >> 8) & 0xff, true);
++		} else {
++			/* One more address cycle for higher density devices */
++			if (mtd->size >= 0x4000000) {
++				/* paddr_8 - paddr_15 */
++				host->devtype_data->send_addr(host,
++						(page_addr >> 8) & 0xff,
++						false);
++				host->devtype_data->send_addr(host,
++						(page_addr >> 16) & 0xff,
++						true);
++			} else
++				/* paddr_8 - paddr_15 */
++				host->devtype_data->send_addr(host,
++						(page_addr >> 8) & 0xff, true);
++		}
++	}
++}
++
++#define MXC_V1_ECCBYTES		5
++
++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);
++
++	if (section >= nand_chip->ecc.steps)
++		return -ERANGE;
++
++	oobregion->offset = (section * 16) + 6;
++	oobregion->length = MXC_V1_ECCBYTES;
++
++	return 0;
++}
++
++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);
++
++	if (section > nand_chip->ecc.steps)
++		return -ERANGE;
++
++	if (!section) {
++		if (mtd->writesize <= 512) {
++			oobregion->offset = 0;
++			oobregion->length = 5;
++		} else {
++			oobregion->offset = 2;
++			oobregion->length = 4;
++		}
++	} else {
++		oobregion->offset = ((section - 1) * 16) + MXC_V1_ECCBYTES + 6;
++		if (section < nand_chip->ecc.steps)
++			oobregion->length = (section * 16) + 6 -
++					    oobregion->offset;
++		else
++			oobregion->length = mtd->oobsize - oobregion->offset;
++	}
++
++	return 0;
++}
++
++static const struct mtd_ooblayout_ops mxc_v1_ooblayout_ops = {
++	.ecc = mxc_v1_ooblayout_ecc,
++	.free = mxc_v1_ooblayout_free,
++};
++
++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);
++	int stepsize = nand_chip->ecc.bytes == 9 ? 16 : 26;
++
++	if (section >= nand_chip->ecc.steps)
++		return -ERANGE;
++
++	oobregion->offset = (section * stepsize) + 7;
++	oobregion->length = nand_chip->ecc.bytes;
++
++	return 0;
++}
++
++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);
++	int stepsize = nand_chip->ecc.bytes == 9 ? 16 : 26;
++
++	if (section >= nand_chip->ecc.steps)
++		return -ERANGE;
++
++	if (!section) {
++		if (mtd->writesize <= 512) {
++			oobregion->offset = 0;
++			oobregion->length = 5;
++		} else {
++			oobregion->offset = 2;
++			oobregion->length = 4;
++		}
++	} else {
++		oobregion->offset = section * stepsize;
++		oobregion->length = 7;
++	}
++
++	return 0;
++}
++
++static const struct mtd_ooblayout_ops mxc_v2_ooblayout_ops = {
++	.ecc = mxc_v2_ooblayout_ecc,
++	.free = mxc_v2_ooblayout_free,
++};
++
++/*
++ * v2 and v3 type controllers can do 4bit or 8bit ecc depending
++ * on how much oob the nand chip has. For 8bit ecc we need at least
++ * 26 bytes of oob data per 512 byte block.
++ */
++static int get_eccsize(struct mtd_info *mtd)
++{
++	int oobbytes_per_512 = 0;
++
++	oobbytes_per_512 = mtd->oobsize * 512 / mtd->writesize;
++
++	if (oobbytes_per_512 < 26)
++		return 4;
++	else
++		return 8;
++}
++
++static void preset_v1(struct mtd_info *mtd)
++{
++	struct nand_chip *nand_chip = mtd_to_nand(mtd);
++	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
++	uint16_t config1 = 0;
++
++	if (nand_chip->ecc.mode == NAND_ECC_HW && mtd->writesize)
++		config1 |= NFC_V1_V2_CONFIG1_ECC_EN;
++
++	if (!host->devtype_data->irqpending_quirk)
++		config1 |= NFC_V1_V2_CONFIG1_INT_MSK;
++
++	host->eccsize = 1;
++
++	writew(config1, NFC_V1_V2_CONFIG1);
++	/* preset operation */
++
++	/* Unlock the internal RAM Buffer */
++	writew(0x2, NFC_V1_V2_CONFIG);
++
++	/* Blocks to be unlocked */
++	writew(0x0, NFC_V1_UNLOCKSTART_BLKADDR);
++	writew(0xffff, NFC_V1_UNLOCKEND_BLKADDR);
++
++	/* Unlock Block Command for given address range */
++	writew(0x4, NFC_V1_V2_WRPROT);
++}
++
++static int mxc_nand_v2_setup_data_interface(struct mtd_info *mtd, int csline,
++					const struct nand_data_interface *conf)
++{
++	struct nand_chip *nand_chip = mtd_to_nand(mtd);
++	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
++	int tRC_min_ns, tRC_ps, ret;
++	unsigned long rate, rate_round;
++	const struct nand_sdr_timings *timings;
++	u16 config1;
++
++	timings = nand_get_sdr_timings(conf);
++	if (IS_ERR(timings))
++		return -ENOTSUPP;
++
++	config1 = readw(NFC_V1_V2_CONFIG1);
++
++	tRC_min_ns = timings->tRC_min / 1000;
++	rate = 1000000000 / tRC_min_ns;
++
++	/*
++	 * For tRC < 30ns we have to use EDO mode. In this case the controller
++	 * does one access per clock cycle. Otherwise the controller does one
++	 * access in two clock cycles, thus we have to double the rate to the
++	 * controller.
++	 */
++	if (tRC_min_ns < 30) {
++		rate_round = clk_round_rate(host->clk, rate);
++		config1 |= NFC_V2_CONFIG1_ONE_CYCLE;
++		tRC_ps = 1000000000 / (rate_round / 1000);
++	} else {
++		rate *= 2;
++		rate_round = clk_round_rate(host->clk, rate);
++		config1 &= ~NFC_V2_CONFIG1_ONE_CYCLE;
++		tRC_ps = 1000000000 / (rate_round / 1000 / 2);
++	}
++
++	/*
++	 * The timing values compared against are from the i.MX25 Automotive
++	 * datasheet, Table 50. NFC Timing Parameters
++	 */
++	if (timings->tCLS_min > tRC_ps - 1000 ||
++	    timings->tCLH_min > tRC_ps - 2000 ||
++	    timings->tCS_min > tRC_ps - 1000 ||
++	    timings->tCH_min > tRC_ps - 2000 ||
++	    timings->tWP_min > tRC_ps - 1500 ||
++	    timings->tALS_min > tRC_ps ||
++	    timings->tALH_min > tRC_ps - 3000 ||
++	    timings->tDS_min > tRC_ps ||
++	    timings->tDH_min > tRC_ps - 5000 ||
++	    timings->tWC_min > 2 * tRC_ps ||
++	    timings->tWH_min > tRC_ps - 2500 ||
++	    timings->tRR_min > 6 * tRC_ps ||
++	    timings->tRP_min > 3 * tRC_ps / 2 ||
++	    timings->tRC_min > 2 * tRC_ps ||
++	    timings->tREH_min > (tRC_ps / 2) - 2500) {
++		dev_dbg(host->dev, "Timing out of bounds\n");
++		return -EINVAL;
++	}
++
++	if (csline == NAND_DATA_IFACE_CHECK_ONLY)
++		return 0;
++
++	ret = clk_set_rate(host->clk, rate);
++	if (ret)
++		return ret;
++
++	writew(config1, NFC_V1_V2_CONFIG1);
++
++	dev_dbg(host->dev, "Setting rate to %ldHz, %s mode\n", rate_round,
++		config1 & NFC_V2_CONFIG1_ONE_CYCLE ? "One cycle (EDO)" :
++		"normal");
++
++	return 0;
++}
++
++static void preset_v2(struct mtd_info *mtd)
++{
++	struct nand_chip *nand_chip = mtd_to_nand(mtd);
++	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
++	uint16_t config1 = 0;
++
++	config1 |= NFC_V2_CONFIG1_FP_INT;
++
++	if (!host->devtype_data->irqpending_quirk)
++		config1 |= NFC_V1_V2_CONFIG1_INT_MSK;
++
++	if (mtd->writesize) {
++		uint16_t pages_per_block = mtd->erasesize / mtd->writesize;
++
++		if (nand_chip->ecc.mode == NAND_ECC_HW)
++			config1 |= NFC_V1_V2_CONFIG1_ECC_EN;
++
++		host->eccsize = get_eccsize(mtd);
++		if (host->eccsize == 4)
++			config1 |= NFC_V2_CONFIG1_ECC_MODE_4;
++
++		config1 |= NFC_V2_CONFIG1_PPB(ffs(pages_per_block) - 6);
++	} else {
++		host->eccsize = 1;
++	}
++
++	writew(config1, NFC_V1_V2_CONFIG1);
++	/* preset operation */
++
++	/* Unlock the internal RAM Buffer */
++	writew(0x2, NFC_V1_V2_CONFIG);
++
++	/* Blocks to be unlocked */
++	writew(0x0, NFC_V21_UNLOCKSTART_BLKADDR0);
++	writew(0x0, NFC_V21_UNLOCKSTART_BLKADDR1);
++	writew(0x0, NFC_V21_UNLOCKSTART_BLKADDR2);
++	writew(0x0, NFC_V21_UNLOCKSTART_BLKADDR3);
++	writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR0);
++	writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR1);
++	writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR2);
++	writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR3);
++
++	/* Unlock Block Command for given address range */
++	writew(0x4, NFC_V1_V2_WRPROT);
++}
++
++static void preset_v3(struct mtd_info *mtd)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct mxc_nand_host *host = nand_get_controller_data(chip);
++	uint32_t config2, config3;
++	int i, addr_phases;
++
++	writel(NFC_V3_CONFIG1_RBA(0), NFC_V3_CONFIG1);
++	writel(NFC_V3_IPC_CREQ, NFC_V3_IPC);
++
++	/* Unlock the internal RAM Buffer */
++	writel(NFC_V3_WRPROT_BLS_UNLOCK | NFC_V3_WRPROT_UNLOCK,
++			NFC_V3_WRPROT);
++
++	/* Blocks to be unlocked */
++	for (i = 0; i < NAND_MAX_CHIPS; i++)
++		writel(0xffff << 16, NFC_V3_WRPROT_UNLOCK_BLK_ADD0 + (i << 2));
++
++	writel(0, NFC_V3_IPC);
++
++	config2 = NFC_V3_CONFIG2_ONE_CYCLE |
++		NFC_V3_CONFIG2_2CMD_PHASES |
++		NFC_V3_CONFIG2_SPAS(mtd->oobsize >> 1) |
++		NFC_V3_CONFIG2_ST_CMD(0x70) |
++		NFC_V3_CONFIG2_INT_MSK |
++		NFC_V3_CONFIG2_NUM_ADDR_PHASE0;
++
++	addr_phases = fls(chip->pagemask) >> 3;
++
++	if (mtd->writesize == 2048) {
++		config2 |= NFC_V3_CONFIG2_PS_2048;
++		config2 |= NFC_V3_CONFIG2_NUM_ADDR_PHASE1(addr_phases);
++	} else if (mtd->writesize == 4096) {
++		config2 |= NFC_V3_CONFIG2_PS_4096;
++		config2 |= NFC_V3_CONFIG2_NUM_ADDR_PHASE1(addr_phases);
++	} else {
++		config2 |= NFC_V3_CONFIG2_PS_512;
++		config2 |= NFC_V3_CONFIG2_NUM_ADDR_PHASE1(addr_phases - 1);
++	}
++
++	if (mtd->writesize) {
++		if (chip->ecc.mode == NAND_ECC_HW)
++			config2 |= NFC_V3_CONFIG2_ECC_EN;
++
++		config2 |= NFC_V3_CONFIG2_PPB(
++				ffs(mtd->erasesize / mtd->writesize) - 6,
++				host->devtype_data->ppb_shift);
++		host->eccsize = get_eccsize(mtd);
++		if (host->eccsize == 8)
++			config2 |= NFC_V3_CONFIG2_ECC_MODE_8;
++	}
++
++	writel(config2, NFC_V3_CONFIG2);
++
++	config3 = NFC_V3_CONFIG3_NUM_OF_DEVICES(0) |
++			NFC_V3_CONFIG3_NO_SDMA |
++			NFC_V3_CONFIG3_RBB_MODE |
++			NFC_V3_CONFIG3_SBB(6) | /* Reset default */
++			NFC_V3_CONFIG3_ADD_OP(0);
++
++	if (!(chip->options & NAND_BUSWIDTH_16))
++		config3 |= NFC_V3_CONFIG3_FW8;
++
++	writel(config3, NFC_V3_CONFIG3);
++
++	writel(0, NFC_V3_DELAY_LINE);
++}
++
++/* Used by the upper layer to write command to NAND Flash for
++ * different operations to be carried out on NAND Flash */
++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 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",
++	      command, column, page_addr);
++
++	/* Reset command state information */
++	host->status_request = false;
++
++	/* Command pre-processing step */
++	switch (command) {
++	case NAND_CMD_RESET:
++		host->devtype_data->preset(mtd);
++		host->devtype_data->send_cmd(host, command, false);
++		break;
++
++	case NAND_CMD_STATUS:
++		host->buf_start = 0;
++		host->status_request = true;
++
++		host->devtype_data->send_cmd(host, command, true);
++		WARN_ONCE(column != -1 || page_addr != -1,
++			  "Unexpected column/row value (cmd=%u, col=%d, row=%d)\n",
++			  command, column, page_addr);
++		mxc_do_addr_cycle(mtd, column, page_addr);
++		break;
++
++	case NAND_CMD_READ0:
++	case NAND_CMD_READOOB:
++		if (command == NAND_CMD_READ0)
++			host->buf_start = column;
++		else
++			host->buf_start = column + mtd->writesize;
++
++		command = NAND_CMD_READ0; /* only READ0 is valid */
++
++		host->devtype_data->send_cmd(host, command, false);
++		WARN_ONCE(column < 0,
++			  "Unexpected column/row value (cmd=%u, col=%d, row=%d)\n",
++			  command, column, page_addr);
++		mxc_do_addr_cycle(mtd, 0, page_addr);
++
++		if (mtd->writesize > 512)
++			host->devtype_data->send_cmd(host,
++					NAND_CMD_READSTART, true);
++
++		host->devtype_data->send_page(mtd, NFC_OUTPUT);
++
++		memcpy32_fromio(host->data_buf, host->main_area0,
++				mtd->writesize);
++		copy_spare(mtd, true);
++		break;
++
++	case NAND_CMD_SEQIN:
++		if (column >= mtd->writesize)
++			/* call ourself to read a page */
++			mxc_nand_command(mtd, NAND_CMD_READ0, 0, page_addr);
++
++		host->buf_start = column;
++
++		host->devtype_data->send_cmd(host, command, false);
++		WARN_ONCE(column < -1,
++			  "Unexpected column/row value (cmd=%u, col=%d, row=%d)\n",
++			  command, column, page_addr);
++		mxc_do_addr_cycle(mtd, 0, page_addr);
++		break;
++
++	case NAND_CMD_PAGEPROG:
++		memcpy32_toio(host->main_area0, host->data_buf, mtd->writesize);
++		copy_spare(mtd, false);
++		host->devtype_data->send_page(mtd, NFC_INPUT);
++		host->devtype_data->send_cmd(host, command, true);
++		WARN_ONCE(column != -1 || page_addr != -1,
++			  "Unexpected column/row value (cmd=%u, col=%d, row=%d)\n",
++			  command, column, page_addr);
++		mxc_do_addr_cycle(mtd, column, page_addr);
++		break;
++
++	case NAND_CMD_READID:
++		host->devtype_data->send_cmd(host, command, true);
++		mxc_do_addr_cycle(mtd, column, page_addr);
++		host->devtype_data->send_read_id(host);
++		host->buf_start = 0;
++		break;
++
++	case NAND_CMD_ERASE1:
++	case NAND_CMD_ERASE2:
++		host->devtype_data->send_cmd(host, command, false);
++		WARN_ONCE(column != -1,
++			  "Unexpected column value (cmd=%u, col=%d)\n",
++			  command, column);
++		mxc_do_addr_cycle(mtd, column, page_addr);
++
++		break;
++	case NAND_CMD_PARAM:
++		host->devtype_data->send_cmd(host, command, false);
++		mxc_do_addr_cycle(mtd, column, page_addr);
++		host->devtype_data->send_page(mtd, NFC_OUTPUT);
++		memcpy32_fromio(host->data_buf, host->main_area0, 512);
++		host->buf_start = 0;
++		break;
++	default:
++		WARN_ONCE(1, "Unimplemented command (cmd=%u)\n",
++			  command);
++		break;
++	}
++}
++
++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 mxc_nand_host *host = nand_get_controller_data(nand_chip);
++	int i;
++
++	if (!chip->onfi_version ||
++	    !(le16_to_cpu(chip->onfi_params.opt_cmd)
++	      & ONFI_OPT_CMD_SET_GET_FEATURES))
++		return -EINVAL;
++
++	host->buf_start = 0;
++
++	for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
++		chip->write_byte(mtd, subfeature_param[i]);
++
++	memcpy32_toio(host->main_area0, host->data_buf, mtd->writesize);
++	host->devtype_data->send_cmd(host, NAND_CMD_SET_FEATURES, false);
++	mxc_do_addr_cycle(mtd, addr, -1);
++	host->devtype_data->send_page(mtd, NFC_INPUT);
++
++	return 0;
++}
++
++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 mxc_nand_host *host = nand_get_controller_data(nand_chip);
++	int i;
++
++	if (!chip->onfi_version ||
++	    !(le16_to_cpu(chip->onfi_params.opt_cmd)
++	      & ONFI_OPT_CMD_SET_GET_FEATURES))
++		return -EINVAL;
++
++	host->devtype_data->send_cmd(host, NAND_CMD_GET_FEATURES, false);
++	mxc_do_addr_cycle(mtd, addr, -1);
++	host->devtype_data->send_page(mtd, NFC_OUTPUT);
++	memcpy32_fromio(host->data_buf, host->main_area0, 512);
++	host->buf_start = 0;
++
++	for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
++		*subfeature_param++ = chip->read_byte(mtd);
++
++	return 0;
++}
++
++/*
++ * The generic flash bbt decriptors overlap with our ecc
++ * hardware, so define some i.MX specific ones.
++ */
++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 = 0,
++	.len = 4,
++	.veroffs = 4,
++	.maxblocks = 4,
++	.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 = 0,
++	.len = 4,
++	.veroffs = 4,
++	.maxblocks = 4,
++	.pattern = mirror_pattern,
++};
++
++/* v1 + irqpending_quirk: i.MX21 */
++static const struct mxc_nand_devtype_data imx21_nand_devtype_data = {
++	.preset = preset_v1,
++	.send_cmd = send_cmd_v1_v2,
++	.send_addr = send_addr_v1_v2,
++	.send_page = send_page_v1,
++	.send_read_id = send_read_id_v1_v2,
++	.get_dev_status = get_dev_status_v1_v2,
++	.check_int = check_int_v1_v2,
++	.irq_control = irq_control_v1_v2,
++	.get_ecc_status = get_ecc_status_v1,
++	.ooblayout = &mxc_v1_ooblayout_ops,
++	.select_chip = mxc_nand_select_chip_v1_v3,
++	.correct_data = mxc_nand_correct_data_v1,
++	.irqpending_quirk = 1,
++	.needs_ip = 0,
++	.regs_offset = 0xe00,
++	.spare0_offset = 0x800,
++	.spare_len = 16,
++	.eccbytes = 3,
++	.eccsize = 1,
++};
++
++/* v1 + !irqpending_quirk: i.MX27, i.MX31 */
++static const struct mxc_nand_devtype_data imx27_nand_devtype_data = {
++	.preset = preset_v1,
++	.send_cmd = send_cmd_v1_v2,
++	.send_addr = send_addr_v1_v2,
++	.send_page = send_page_v1,
++	.send_read_id = send_read_id_v1_v2,
++	.get_dev_status = get_dev_status_v1_v2,
++	.check_int = check_int_v1_v2,
++	.irq_control = irq_control_v1_v2,
++	.get_ecc_status = get_ecc_status_v1,
++	.ooblayout = &mxc_v1_ooblayout_ops,
++	.select_chip = mxc_nand_select_chip_v1_v3,
++	.correct_data = mxc_nand_correct_data_v1,
++	.irqpending_quirk = 0,
++	.needs_ip = 0,
++	.regs_offset = 0xe00,
++	.spare0_offset = 0x800,
++	.axi_offset = 0,
++	.spare_len = 16,
++	.eccbytes = 3,
++	.eccsize = 1,
++};
++
++/* v21: i.MX25, i.MX35 */
++static const struct mxc_nand_devtype_data imx25_nand_devtype_data = {
++	.preset = preset_v2,
++	.send_cmd = send_cmd_v1_v2,
++	.send_addr = send_addr_v1_v2,
++	.send_page = send_page_v2,
++	.send_read_id = send_read_id_v1_v2,
++	.get_dev_status = get_dev_status_v1_v2,
++	.check_int = check_int_v1_v2,
++	.irq_control = irq_control_v1_v2,
++	.get_ecc_status = get_ecc_status_v2,
++	.ooblayout = &mxc_v2_ooblayout_ops,
++	.select_chip = mxc_nand_select_chip_v2,
++	.correct_data = mxc_nand_correct_data_v2_v3,
++	.setup_data_interface = mxc_nand_v2_setup_data_interface,
++	.irqpending_quirk = 0,
++	.needs_ip = 0,
++	.regs_offset = 0x1e00,
++	.spare0_offset = 0x1000,
++	.axi_offset = 0,
++	.spare_len = 64,
++	.eccbytes = 9,
++	.eccsize = 0,
++};
++
++/* v3.2a: i.MX51 */
++static const struct mxc_nand_devtype_data imx51_nand_devtype_data = {
++	.preset = preset_v3,
++	.send_cmd = send_cmd_v3,
++	.send_addr = send_addr_v3,
++	.send_page = send_page_v3,
++	.send_read_id = send_read_id_v3,
++	.get_dev_status = get_dev_status_v3,
++	.check_int = check_int_v3,
++	.irq_control = irq_control_v3,
++	.get_ecc_status = get_ecc_status_v3,
++	.ooblayout = &mxc_v2_ooblayout_ops,
++	.select_chip = mxc_nand_select_chip_v1_v3,
++	.correct_data = mxc_nand_correct_data_v2_v3,
++	.irqpending_quirk = 0,
++	.needs_ip = 1,
++	.regs_offset = 0,
++	.spare0_offset = 0x1000,
++	.axi_offset = 0x1e00,
++	.spare_len = 64,
++	.eccbytes = 0,
++	.eccsize = 0,
++	.ppb_shift = 7,
++};
++
++/* v3.2b: i.MX53 */
++static const struct mxc_nand_devtype_data imx53_nand_devtype_data = {
++	.preset = preset_v3,
++	.send_cmd = send_cmd_v3,
++	.send_addr = send_addr_v3,
++	.send_page = send_page_v3,
++	.send_read_id = send_read_id_v3,
++	.get_dev_status = get_dev_status_v3,
++	.check_int = check_int_v3,
++	.irq_control = irq_control_v3,
++	.get_ecc_status = get_ecc_status_v3,
++	.ooblayout = &mxc_v2_ooblayout_ops,
++	.select_chip = mxc_nand_select_chip_v1_v3,
++	.correct_data = mxc_nand_correct_data_v2_v3,
++	.irqpending_quirk = 0,
++	.needs_ip = 1,
++	.regs_offset = 0,
++	.spare0_offset = 0x1000,
++	.axi_offset = 0x1e00,
++	.spare_len = 64,
++	.eccbytes = 0,
++	.eccsize = 0,
++	.ppb_shift = 8,
++};
++
++static inline int is_imx21_nfc(struct mxc_nand_host *host)
++{
++	return host->devtype_data == &imx21_nand_devtype_data;
++}
++
++static inline int is_imx27_nfc(struct mxc_nand_host *host)
++{
++	return host->devtype_data == &imx27_nand_devtype_data;
++}
++
++static inline int is_imx25_nfc(struct mxc_nand_host *host)
++{
++	return host->devtype_data == &imx25_nand_devtype_data;
++}
++
++static inline int is_imx51_nfc(struct mxc_nand_host *host)
++{
++	return host->devtype_data == &imx51_nand_devtype_data;
++}
++
++static inline int is_imx53_nfc(struct mxc_nand_host *host)
++{
++	return host->devtype_data == &imx53_nand_devtype_data;
++}
++
++static const struct platform_device_id mxcnd_devtype[] = {
++	{
++		.name = "imx21-nand",
++		.driver_data = (kernel_ulong_t) &imx21_nand_devtype_data,
++	}, {
++		.name = "imx27-nand",
++		.driver_data = (kernel_ulong_t) &imx27_nand_devtype_data,
++	}, {
++		.name = "imx25-nand",
++		.driver_data = (kernel_ulong_t) &imx25_nand_devtype_data,
++	}, {
++		.name = "imx51-nand",
++		.driver_data = (kernel_ulong_t) &imx51_nand_devtype_data,
++	}, {
++		.name = "imx53-nand",
++		.driver_data = (kernel_ulong_t) &imx53_nand_devtype_data,
++	}, {
++		/* sentinel */
++	}
++};
++MODULE_DEVICE_TABLE(platform, mxcnd_devtype);
++
++#ifdef CONFIG_OF
++static const struct of_device_id mxcnd_dt_ids[] = {
++	{
++		.compatible = "fsl,imx21-nand",
++		.data = &imx21_nand_devtype_data,
++	}, {
++		.compatible = "fsl,imx27-nand",
++		.data = &imx27_nand_devtype_data,
++	}, {
++		.compatible = "fsl,imx25-nand",
++		.data = &imx25_nand_devtype_data,
++	}, {
++		.compatible = "fsl,imx51-nand",
++		.data = &imx51_nand_devtype_data,
++	}, {
++		.compatible = "fsl,imx53-nand",
++		.data = &imx53_nand_devtype_data,
++	},
++	{ /* sentinel */ }
++};
++MODULE_DEVICE_TABLE(of, mxcnd_dt_ids);
++
++static int __init mxcnd_probe_dt(struct mxc_nand_host *host)
++{
++	struct device_node *np = host->dev->of_node;
++	const struct of_device_id *of_id =
++		of_match_device(mxcnd_dt_ids, host->dev);
++
++	if (!np)
++		return 1;
++
++	host->devtype_data = of_id->data;
++
++	return 0;
++}
++#else
++static int __init mxcnd_probe_dt(struct mxc_nand_host *host)
++{
++	return 1;
++}
++#endif
++
++static int mxcnd_probe(struct platform_device *pdev)
++{
++	struct nand_chip *this;
++	struct mtd_info *mtd;
++	struct mxc_nand_host *host;
++	struct resource *res;
++	int err = 0;
++
++	/* Allocate memory for MTD device structure and private data */
++	host = devm_kzalloc(&pdev->dev, sizeof(struct mxc_nand_host),
++			GFP_KERNEL);
++	if (!host)
++		return -ENOMEM;
++
++	/* allocate a temporary buffer for the nand_scan_ident() */
++	host->data_buf = devm_kzalloc(&pdev->dev, PAGE_SIZE, GFP_KERNEL);
++	if (!host->data_buf)
++		return -ENOMEM;
++
++	host->dev = &pdev->dev;
++	/* structures must be linked */
++	this = &host->nand;
++	mtd = nand_to_mtd(this);
++	mtd->dev.parent = &pdev->dev;
++	mtd->name = DRIVER_NAME;
++
++	/* 50 us command delay time */
++	this->chip_delay = 5;
++
++	nand_set_controller_data(this, host);
++	nand_set_flash_node(this, pdev->dev.of_node),
++	this->dev_ready = mxc_nand_dev_ready;
++	this->cmdfunc = mxc_nand_command;
++	this->read_byte = mxc_nand_read_byte;
++	this->read_word = mxc_nand_read_word;
++	this->write_buf = mxc_nand_write_buf;
++	this->read_buf = mxc_nand_read_buf;
++	this->onfi_set_features = mxc_nand_onfi_set_features;
++	this->onfi_get_features = mxc_nand_onfi_get_features;
++
++	host->clk = devm_clk_get(&pdev->dev, NULL);
++	if (IS_ERR(host->clk))
++		return PTR_ERR(host->clk);
++
++	err = mxcnd_probe_dt(host);
++	if (err > 0) {
++		struct mxc_nand_platform_data *pdata =
++					dev_get_platdata(&pdev->dev);
++		if (pdata) {
++			host->pdata = *pdata;
++			host->devtype_data = (struct mxc_nand_devtype_data *)
++						pdev->id_entry->driver_data;
++		} else {
++			err = -ENODEV;
++		}
++	}
++	if (err < 0)
++		return err;
++
++	this->setup_data_interface = host->devtype_data->setup_data_interface;
++
++	if (host->devtype_data->needs_ip) {
++		res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++		host->regs_ip = devm_ioremap_resource(&pdev->dev, res);
++		if (IS_ERR(host->regs_ip))
++			return PTR_ERR(host->regs_ip);
++
++		res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
++	} else {
++		res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	}
++
++	host->base = devm_ioremap_resource(&pdev->dev, res);
++	if (IS_ERR(host->base))
++		return PTR_ERR(host->base);
++
++	host->main_area0 = host->base;
++
++	if (host->devtype_data->regs_offset)
++		host->regs = host->base + host->devtype_data->regs_offset;
++	host->spare0 = host->base + host->devtype_data->spare0_offset;
++	if (host->devtype_data->axi_offset)
++		host->regs_axi = host->base + host->devtype_data->axi_offset;
++
++	this->ecc.bytes = host->devtype_data->eccbytes;
++	host->eccsize = host->devtype_data->eccsize;
++
++	this->select_chip = host->devtype_data->select_chip;
++	this->ecc.size = 512;
++	mtd_set_ooblayout(mtd, host->devtype_data->ooblayout);
++
++	if (host->pdata.hw_ecc) {
++		this->ecc.mode = NAND_ECC_HW;
++	} else {
++		this->ecc.mode = NAND_ECC_SOFT;
++		this->ecc.algo = NAND_ECC_HAMMING;
++	}
++
++	/* NAND bus width determines access functions used by upper layer */
++	if (host->pdata.width == 2)
++		this->options |= NAND_BUSWIDTH_16;
++
++	/* update flash based bbt */
++	if (host->pdata.flash_bbt)
++		this->bbt_options |= NAND_BBT_USE_FLASH;
++
++	init_completion(&host->op_completion);
++
++	host->irq = platform_get_irq(pdev, 0);
++	if (host->irq < 0)
++		return host->irq;
++
++	/*
++	 * Use host->devtype_data->irq_control() here instead of irq_control()
++	 * because we must not disable_irq_nosync without having requested the
++	 * irq.
++	 */
++	host->devtype_data->irq_control(host, 0);
++
++	err = devm_request_irq(&pdev->dev, host->irq, mxc_nfc_irq,
++			0, DRIVER_NAME, host);
++	if (err)
++		return err;
++
++	err = clk_prepare_enable(host->clk);
++	if (err)
++		return err;
++	host->clk_act = 1;
++
++	/*
++	 * Now that we "own" the interrupt make sure the interrupt mask bit is
++	 * cleared on i.MX21. Otherwise we can't read the interrupt status bit
++	 * on this machine.
++	 */
++	if (host->devtype_data->irqpending_quirk) {
++		disable_irq_nosync(host->irq);
++		host->devtype_data->irq_control(host, 1);
++	}
++
++	/* first scan to find the device and get the page size */
++	err = nand_scan_ident(mtd, is_imx25_nfc(host) ? 4 : 1, NULL);
++	if (err)
++		goto escan;
++
++	switch (this->ecc.mode) {
++	case NAND_ECC_HW:
++		this->ecc.calculate = mxc_nand_calculate_ecc;
++		this->ecc.hwctl = mxc_nand_enable_hwecc;
++		this->ecc.correct = host->devtype_data->correct_data;
++		break;
++
++	case NAND_ECC_SOFT:
++		break;
++
++	default:
++		err = -EINVAL;
++		goto escan;
++	}
++
++	if (this->bbt_options & NAND_BBT_USE_FLASH) {
++		this->bbt_td = &bbt_main_descr;
++		this->bbt_md = &bbt_mirror_descr;
++	}
++
++	/* allocate the right size buffer now */
++	devm_kfree(&pdev->dev, (void *)host->data_buf);
++	host->data_buf = devm_kzalloc(&pdev->dev, mtd->writesize + mtd->oobsize,
++					GFP_KERNEL);
++	if (!host->data_buf) {
++		err = -ENOMEM;
++		goto escan;
++	}
++
++	/* Call preset again, with correct writesize this time */
++	host->devtype_data->preset(mtd);
++
++	if (!this->ecc.bytes) {
++		if (host->eccsize == 8)
++			this->ecc.bytes = 18;
++		else if (host->eccsize == 4)
++			this->ecc.bytes = 9;
++	}
++
++	/*
++	 * Experimentation shows that i.MX NFC can only handle up to 218 oob
++	 * bytes. Limit used_oobsize to 218 so as to not confuse copy_spare()
++	 * into copying invalid data to/from the spare IO buffer, as this
++	 * might cause ECC data corruption when doing sub-page write to a
++	 * partially written page.
++	 */
++	host->used_oobsize = min(mtd->oobsize, 218U);
++
++	if (this->ecc.mode == NAND_ECC_HW) {
++		if (is_imx21_nfc(host) || is_imx27_nfc(host))
++			this->ecc.strength = 1;
++		else
++			this->ecc.strength = (host->eccsize == 4) ? 4 : 8;
++	}
++
++	/* second phase scan */
++	err = nand_scan_tail(mtd);
++	if (err)
++		goto escan;
++
++	/* Register the partitions */
++	mtd_device_parse_register(mtd, part_probes,
++			NULL,
++			host->pdata.parts,
++			host->pdata.nr_parts);
++
++	platform_set_drvdata(pdev, host);
++
++	return 0;
++
++escan:
++	if (host->clk_act)
++		clk_disable_unprepare(host->clk);
++
++	return err;
++}
++
++static int mxcnd_remove(struct platform_device *pdev)
++{
++	struct mxc_nand_host *host = platform_get_drvdata(pdev);
++
++	nand_release(nand_to_mtd(&host->nand));
++	if (host->clk_act)
++		clk_disable_unprepare(host->clk);
++
++	return 0;
++}
++
++static struct platform_driver mxcnd_driver = {
++	.driver = {
++		   .name = DRIVER_NAME,
++		   .of_match_table = of_match_ptr(mxcnd_dt_ids),
++	},
++	.id_table = mxcnd_devtype,
++	.probe = mxcnd_probe,
++	.remove = mxcnd_remove,
++};
++module_platform_driver(mxcnd_driver);
++
++MODULE_AUTHOR("Freescale Semiconductor, Inc.");
++MODULE_DESCRIPTION("MXC NAND MTD driver");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/mtd/nand/raw/nand_amd.c b/drivers/mtd/nand/raw/nand_amd.c
+new file mode 100644
+index 0000000..22f060f
+--- /dev/null
++++ b/drivers/mtd/nand/raw/nand_amd.c
+@@ -0,0 +1,51 @@
++/*
++ * Copyright (C) 2017 Free Electrons
++ * Copyright (C) 2017 NextThing Co
++ *
++ * Author: Boris Brezillon <boris.brezillon@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 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/mtd/rawnand.h>
++
++static void amd_nand_decode_id(struct nand_chip *chip)
++{
++	struct mtd_info *mtd = nand_to_mtd(chip);
++
++	nand_decode_ext_id(chip);
++
++	/*
++	 * Check for Spansion/AMD ID + repeating 5th, 6th byte since
++	 * some Spansion chips have erasesize that conflicts with size
++	 * listed in nand_ids table.
++	 * Data sheet (5 byte ID): Spansion S30ML-P ORNAND (p.39)
++	 */
++	if (chip->id.data[4] != 0x00 && chip->id.data[5] == 0x00 &&
++	    chip->id.data[6] == 0x00 && chip->id.data[7] == 0x00 &&
++	    mtd->writesize == 512) {
++		mtd->erasesize = 128 * 1024;
++		mtd->erasesize <<= ((chip->id.data[3] & 0x03) << 1);
++	}
++}
++
++static int amd_nand_init(struct nand_chip *chip)
++{
++	if (nand_is_slc(chip))
++		chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
++
++	return 0;
++}
++
++const struct nand_manufacturer_ops amd_nand_manuf_ops = {
++	.detect = amd_nand_decode_id,
++	.init = amd_nand_init,
++};
+diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
+new file mode 100644
+index 0000000..4495861
+--- /dev/null
++++ b/drivers/mtd/nand/raw/nand_base.c
+@@ -0,0 +1,4997 @@
++/*
++ *  Overview:
++ *   This is the generic MTD driver for NAND flash devices. It should be
++ *   capable of working with almost all NAND chips currently available.
++ *
++ *	Additional technical information is available on
++ *	http://www.linux-mtd.infradead.org/doc/nand.html
++ *
++ *  Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
++ *		  2002-2006 Thomas Gleixner (tglx@linutronix.de)
++ *
++ *  Credits:
++ *	David Woodhouse for adding multichip support
++ *
++ *	Aleph One Ltd. and Toby Churchill Ltd. for supporting the
++ *	rework for 2K page size chips
++ *
++ *  TODO:
++ *	Enable cached programming for 2k page size chips
++ *	Check, if mtd->ecctype should be set to MTD_ECC_HW
++ *	if we have HW ECC support.
++ *	BBT table is not serialized, has to be fixed
++ *
++ * 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.
++ *
++ */
++
++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
++
++#include <linux/module.h>
++#include <linux/delay.h>
++#include <linux/errno.h>
++#include <linux/err.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/mm.h>
++#include <linux/nmi.h>
++#include <linux/types.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/rawnand.h>
++#include <linux/mtd/nand_ecc.h>
++#include <linux/mtd/nand_bch.h>
++#include <linux/interrupt.h>
++#include <linux/bitops.h>
++#include <linux/io.h>
++#include <linux/mtd/partitions.h>
++#include <linux/of.h>
++
++static int nand_get_device(struct mtd_info *mtd, int new_state);
++
++static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
++			     struct mtd_oob_ops *ops);
++
++/* Define default oob placement schemes for large and small page devices */
++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_ecc_ctrl *ecc = &chip->ecc;
++
++	if (section > 1)
++		return -ERANGE;
++
++	if (!section) {
++		oobregion->offset = 0;
++		if (mtd->oobsize == 16)
++			oobregion->length = 4;
++		else
++			oobregion->length = 3;
++	} else {
++		if (mtd->oobsize == 8)
++			return -ERANGE;
++
++		oobregion->offset = 6;
++		oobregion->length = ecc->total - 4;
++	}
++
++	return 0;
++}
++
++static int nand_ooblayout_free_sp(struct mtd_info *mtd, int section,
++				  struct mtd_oob_region *oobregion)
++{
++	if (section > 1)
++		return -ERANGE;
++
++	if (mtd->oobsize == 16) {
++		if (section)
++			return -ERANGE;
++
++		oobregion->length = 8;
++		oobregion->offset = 8;
++	} else {
++		oobregion->length = 2;
++		if (!section)
++			oobregion->offset = 3;
++		else
++			oobregion->offset = 6;
++	}
++
++	return 0;
++}
++
++const struct mtd_ooblayout_ops nand_ooblayout_sp_ops = {
++	.ecc = nand_ooblayout_ecc_sp,
++	.free = nand_ooblayout_free_sp,
++};
++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_ecc_ctrl *ecc = &chip->ecc;
++
++	if (section)
++		return -ERANGE;
++
++	oobregion->length = ecc->total;
++	oobregion->offset = mtd->oobsize - oobregion->length;
++
++	return 0;
++}
++
++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_ecc_ctrl *ecc = &chip->ecc;
++
++	if (section)
++		return -ERANGE;
++
++	oobregion->length = mtd->oobsize - ecc->total - 2;
++	oobregion->offset = 2;
++
++	return 0;
++}
++
++const struct mtd_ooblayout_ops nand_ooblayout_lp_ops = {
++	.ecc = nand_ooblayout_ecc_lp,
++	.free = nand_ooblayout_free_lp,
++};
++EXPORT_SYMBOL_GPL(nand_ooblayout_lp_ops);
++
++/*
++ * Support the old "large page" layout used for 1-bit Hamming ECC where ECC
++ * are placed at a fixed offset.
++ */
++static int nand_ooblayout_ecc_lp_hamming(struct mtd_info *mtd, int section,
++					 struct mtd_oob_region *oobregion)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct nand_ecc_ctrl *ecc = &chip->ecc;
++
++	if (section)
++		return -ERANGE;
++
++	switch (mtd->oobsize) {
++	case 64:
++		oobregion->offset = 40;
++		break;
++	case 128:
++		oobregion->offset = 80;
++		break;
++	default:
++		return -EINVAL;
++	}
++
++	oobregion->length = ecc->total;
++	if (oobregion->offset + oobregion->length > mtd->oobsize)
++		return -ERANGE;
++
++	return 0;
++}
++
++static int nand_ooblayout_free_lp_hamming(struct mtd_info *mtd, int section,
++					  struct mtd_oob_region *oobregion)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct nand_ecc_ctrl *ecc = &chip->ecc;
++	int ecc_offset = 0;
++
++	if (section < 0 || section > 1)
++		return -ERANGE;
++
++	switch (mtd->oobsize) {
++	case 64:
++		ecc_offset = 40;
++		break;
++	case 128:
++		ecc_offset = 80;
++		break;
++	default:
++		return -EINVAL;
++	}
++
++	if (section == 0) {
++		oobregion->offset = 2;
++		oobregion->length = ecc_offset - 2;
++	} else {
++		oobregion->offset = ecc_offset + ecc->total;
++		oobregion->length = mtd->oobsize - oobregion->offset;
++	}
++
++	return 0;
++}
++
++static const struct mtd_ooblayout_ops nand_ooblayout_lp_hamming_ops = {
++	.ecc = nand_ooblayout_ecc_lp_hamming,
++	.free = nand_ooblayout_free_lp_hamming,
++};
++
++static int check_offs_len(struct mtd_info *mtd,
++					loff_t ofs, uint64_t len)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	int ret = 0;
++
++	/* Start address must align on block boundary */
++	if (ofs & ((1ULL << chip->phys_erase_shift) - 1)) {
++		pr_debug("%s: unaligned address\n", __func__);
++		ret = -EINVAL;
++	}
++
++	/* Length must align on block boundary */
++	if (len & ((1ULL << chip->phys_erase_shift) - 1)) {
++		pr_debug("%s: length not block aligned\n", __func__);
++		ret = -EINVAL;
++	}
++
++	return ret;
++}
++
++/**
++ * nand_release_device - [GENERIC] release chip
++ * @mtd: MTD device structure
++ *
++ * Release chip lock and wake up anyone waiting on the device.
++ */
++static void nand_release_device(struct mtd_info *mtd)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++
++	/* Release the controller and the chip */
++	spin_lock(&chip->controller->lock);
++	chip->controller->active = NULL;
++	chip->state = FL_READY;
++	wake_up(&chip->controller->wq);
++	spin_unlock(&chip->controller->lock);
++}
++
++/**
++ * nand_read_byte - [DEFAULT] read one byte from the chip
++ * @mtd: MTD device structure
++ *
++ * Default read function for 8bit buswidth
++ */
++static uint8_t nand_read_byte(struct mtd_info *mtd)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	return readb(chip->IO_ADDR_R);
++}
++
++/**
++ * nand_read_byte16 - [DEFAULT] read one byte endianness aware from the chip
++ * @mtd: MTD device structure
++ *
++ * Default read function for 16bit buswidth with endianness conversion.
++ *
++ */
++static uint8_t nand_read_byte16(struct mtd_info *mtd)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	return (uint8_t) cpu_to_le16(readw(chip->IO_ADDR_R));
++}
++
++/**
++ * nand_read_word - [DEFAULT] read one word from the chip
++ * @mtd: MTD device structure
++ *
++ * Default read function for 16bit buswidth without endianness conversion.
++ */
++static u16 nand_read_word(struct mtd_info *mtd)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	return readw(chip->IO_ADDR_R);
++}
++
++/**
++ * nand_select_chip - [DEFAULT] control CE line
++ * @mtd: MTD device structure
++ * @chipnr: chipnumber to select, -1 for deselect
++ *
++ * Default select function for 1 chip devices.
++ */
++static void nand_select_chip(struct mtd_info *mtd, int chipnr)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++
++	switch (chipnr) {
++	case -1:
++		chip->cmd_ctrl(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE);
++		break;
++	case 0:
++		break;
++
++	default:
++		BUG();
++	}
++}
++
++/**
++ * nand_write_byte - [DEFAULT] write single byte to chip
++ * @mtd: MTD device structure
++ * @byte: value to write
++ *
++ * Default function to write a byte to I/O[7:0]
++ */
++static void nand_write_byte(struct mtd_info *mtd, uint8_t byte)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++
++	chip->write_buf(mtd, &byte, 1);
++}
++
++/**
++ * nand_write_byte16 - [DEFAULT] write single byte to a chip with width 16
++ * @mtd: MTD device structure
++ * @byte: value to write
++ *
++ * Default function to write a byte to I/O[7:0] on a 16-bit wide chip.
++ */
++static void nand_write_byte16(struct mtd_info *mtd, uint8_t byte)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	uint16_t word = byte;
++
++	/*
++	 * It's not entirely clear what should happen to I/O[15:8] when writing
++	 * a byte. The ONFi spec (Revision 3.1; 2012-09-19, Section 2.16) reads:
++	 *
++	 *    When the host supports a 16-bit bus width, only data is
++	 *    transferred at the 16-bit width. All address and command line
++	 *    transfers shall use only the lower 8-bits of the data bus. During
++	 *    command transfers, the host may place any value on the upper
++	 *    8-bits of the data bus. During address transfers, the host shall
++	 *    set the upper 8-bits of the data bus to 00h.
++	 *
++	 * One user of the write_byte callback is nand_onfi_set_features. The
++	 * four parameters are specified to be written to I/O[7:0], but this is
++	 * neither an address nor a command transfer. Let's assume a 0 on the
++	 * upper I/O lines is OK.
++	 */
++	chip->write_buf(mtd, (uint8_t *)&word, 2);
++}
++
++/**
++ * nand_write_buf - [DEFAULT] write buffer to chip
++ * @mtd: MTD device structure
++ * @buf: data buffer
++ * @len: number of bytes to write
++ *
++ * Default write function for 8bit buswidth.
++ */
++static void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++
++	iowrite8_rep(chip->IO_ADDR_W, buf, len);
++}
++
++/**
++ * nand_read_buf - [DEFAULT] read chip data into buffer
++ * @mtd: MTD device structure
++ * @buf: buffer to store date
++ * @len: number of bytes to read
++ *
++ * Default read function for 8bit buswidth.
++ */
++static void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++
++	ioread8_rep(chip->IO_ADDR_R, buf, len);
++}
++
++/**
++ * nand_write_buf16 - [DEFAULT] write buffer to chip
++ * @mtd: MTD device structure
++ * @buf: data buffer
++ * @len: number of bytes to write
++ *
++ * Default write function for 16bit buswidth.
++ */
++static void nand_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	u16 *p = (u16 *) buf;
++
++	iowrite16_rep(chip->IO_ADDR_W, p, len >> 1);
++}
++
++/**
++ * nand_read_buf16 - [DEFAULT] read chip data into buffer
++ * @mtd: MTD device structure
++ * @buf: buffer to store date
++ * @len: number of bytes to read
++ *
++ * Default read function for 16bit buswidth.
++ */
++static void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	u16 *p = (u16 *) buf;
++
++	ioread16_rep(chip->IO_ADDR_R, p, len >> 1);
++}
++
++/**
++ * nand_block_bad - [DEFAULT] Read bad block marker from the chip
++ * @mtd: MTD device structure
++ * @ofs: offset from device start
++ *
++ * Check, if the block is bad.
++ */
++static int nand_block_bad(struct mtd_info *mtd, loff_t ofs)
++{
++	int page, page_end, res;
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	u8 bad;
++
++	if (chip->bbt_options & NAND_BBT_SCANLASTPAGE)
++		ofs += mtd->erasesize - mtd->writesize;
++
++	page = (int)(ofs >> chip->page_shift) & chip->pagemask;
++	page_end = page + (chip->bbt_options & NAND_BBT_SCAN2NDPAGE ? 2 : 1);
++
++	for (; page < page_end; page++) {
++		res = chip->ecc.read_oob(mtd, chip, page);
++		if (res)
++			return res;
++
++		bad = chip->oob_poi[chip->badblockpos];
++
++		if (likely(chip->badblockbits == 8))
++			res = bad != 0xFF;
++		else
++			res = hweight8(bad) < chip->badblockbits;
++		if (res)
++			return res;
++	}
++
++	return 0;
++}
++
++/**
++ * nand_default_block_markbad - [DEFAULT] mark a block bad via bad block marker
++ * @mtd: MTD device structure
++ * @ofs: offset from device start
++ *
++ * This is the default implementation, which can be overridden by a hardware
++ * specific driver. It provides the details for writing a bad block marker to a
++ * block.
++ */
++static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct mtd_oob_ops ops;
++	uint8_t buf[2] = { 0, 0 };
++	int ret = 0, res, i = 0;
++
++	memset(&ops, 0, sizeof(ops));
++	ops.oobbuf = buf;
++	ops.ooboffs = chip->badblockpos;
++	if (chip->options & NAND_BUSWIDTH_16) {
++		ops.ooboffs &= ~0x01;
++		ops.len = ops.ooblen = 2;
++	} else {
++		ops.len = ops.ooblen = 1;
++	}
++	ops.mode = MTD_OPS_PLACE_OOB;
++
++	/* Write to first/last page(s) if necessary */
++	if (chip->bbt_options & NAND_BBT_SCANLASTPAGE)
++		ofs += mtd->erasesize - mtd->writesize;
++	do {
++		res = nand_do_write_oob(mtd, ofs, &ops);
++		if (!ret)
++			ret = res;
++
++		i++;
++		ofs += mtd->writesize;
++	} while ((chip->bbt_options & NAND_BBT_SCAN2NDPAGE) && i < 2);
++
++	return ret;
++}
++
++/**
++ * nand_block_markbad_lowlevel - mark a block bad
++ * @mtd: MTD device structure
++ * @ofs: offset from device start
++ *
++ * This function performs the generic NAND bad block marking steps (i.e., bad
++ * block table(s) and/or marker(s)). We only allow the hardware driver to
++ * specify how to write bad block markers to OOB (chip->block_markbad).
++ *
++ * We try operations in the following order:
++ *
++ *  (1) erase the affected block, to allow OOB marker to be written cleanly
++ *  (2) write bad block marker to OOB area of affected block (unless flag
++ *      NAND_BBT_NO_OOB_BBM is present)
++ *  (3) update the BBT
++ *
++ * Note that we retain the first error encountered in (2) or (3), finish the
++ * procedures, and dump the error in the end.
++*/
++static int nand_block_markbad_lowlevel(struct mtd_info *mtd, loff_t ofs)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	int res, ret = 0;
++
++	if (!(chip->bbt_options & NAND_BBT_NO_OOB_BBM)) {
++		struct erase_info einfo;
++
++		/* Attempt erase before marking OOB */
++		memset(&einfo, 0, sizeof(einfo));
++		einfo.mtd = mtd;
++		einfo.addr = ofs;
++		einfo.len = 1ULL << chip->phys_erase_shift;
++		nand_erase_nand(mtd, &einfo, 0);
++
++		/* Write bad block marker to OOB */
++		nand_get_device(mtd, FL_WRITING);
++		ret = chip->block_markbad(mtd, ofs);
++		nand_release_device(mtd);
++	}
++
++	/* Mark block bad in BBT */
++	if (chip->bbt) {
++		res = nand_markbad_bbt(mtd, ofs);
++		if (!ret)
++			ret = res;
++	}
++
++	if (!ret)
++		mtd->ecc_stats.badblocks++;
++
++	return ret;
++}
++
++/**
++ * nand_check_wp - [GENERIC] check if the chip is write protected
++ * @mtd: MTD device structure
++ *
++ * Check, if the device is write protected. The function expects, that the
++ * device is already selected.
++ */
++static int nand_check_wp(struct mtd_info *mtd)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++
++	/* Broken xD cards report WP despite being writable */
++	if (chip->options & NAND_BROKEN_XD)
++		return 0;
++
++	/* Check the WP bit */
++	chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
++	return (chip->read_byte(mtd) & NAND_STATUS_WP) ? 0 : 1;
++}
++
++/**
++ * nand_block_isreserved - [GENERIC] Check if a block is marked reserved.
++ * @mtd: MTD device structure
++ * @ofs: offset from device start
++ *
++ * Check if the block is marked as reserved.
++ */
++static int nand_block_isreserved(struct mtd_info *mtd, loff_t ofs)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++
++	if (!chip->bbt)
++		return 0;
++	/* Return info from the table */
++	return nand_isreserved_bbt(mtd, ofs);
++}
++
++/**
++ * nand_block_checkbad - [GENERIC] Check if a block is marked bad
++ * @mtd: MTD device structure
++ * @ofs: offset from device start
++ * @allowbbt: 1, if its allowed to access the bbt area
++ *
++ * Check, if the block is bad. Either by reading the bad block table or
++ * calling of the scan function.
++ */
++static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int allowbbt)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++
++	if (!chip->bbt)
++		return chip->block_bad(mtd, ofs);
++
++	/* Return info from the table */
++	return nand_isbad_bbt(mtd, ofs, allowbbt);
++}
++
++/**
++ * panic_nand_wait_ready - [GENERIC] Wait for the ready pin after commands.
++ * @mtd: MTD device structure
++ * @timeo: Timeout
++ *
++ * Helper function for nand_wait_ready used when needing to wait in interrupt
++ * context.
++ */
++static void panic_nand_wait_ready(struct mtd_info *mtd, unsigned long timeo)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	int i;
++
++	/* Wait for the device to get ready */
++	for (i = 0; i < timeo; i++) {
++		if (chip->dev_ready(mtd))
++			break;
++		touch_softlockup_watchdog();
++		mdelay(1);
++	}
++}
++
++/**
++ * nand_wait_ready - [GENERIC] Wait for the ready pin after commands.
++ * @mtd: MTD device structure
++ *
++ * Wait for the ready pin after a command, and warn if a timeout occurs.
++ */
++void nand_wait_ready(struct mtd_info *mtd)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	unsigned long timeo = 400;
++
++	if (in_interrupt() || oops_in_progress)
++		return panic_nand_wait_ready(mtd, timeo);
++
++	/* Wait until command is processed or timeout occurs */
++	timeo = jiffies + msecs_to_jiffies(timeo);
++	do {
++		if (chip->dev_ready(mtd))
++			return;
++		cond_resched();
++	} while (time_before(jiffies, timeo));
++
++	if (!chip->dev_ready(mtd))
++		pr_warn_ratelimited("timeout while waiting for chip to become ready\n");
++}
++EXPORT_SYMBOL_GPL(nand_wait_ready);
++
++/**
++ * nand_wait_status_ready - [GENERIC] Wait for the ready status after commands.
++ * @mtd: MTD device structure
++ * @timeo: Timeout in ms
++ *
++ * Wait for status ready (i.e. command done) or timeout.
++ */
++static void nand_wait_status_ready(struct mtd_info *mtd, unsigned long timeo)
++{
++	register struct nand_chip *chip = mtd_to_nand(mtd);
++
++	timeo = jiffies + msecs_to_jiffies(timeo);
++	do {
++		if ((chip->read_byte(mtd) & NAND_STATUS_READY))
++			break;
++		touch_softlockup_watchdog();
++	} while (time_before(jiffies, timeo));
++};
++
++/**
++ * nand_command - [DEFAULT] Send command to NAND device
++ * @mtd: MTD device structure
++ * @command: the command to be sent
++ * @column: the column address for this command, -1 if none
++ * @page_addr: the page address for this command, -1 if none
++ *
++ * Send command to NAND device. This function is used for small page devices
++ * (512 Bytes per page).
++ */
++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);
++	int ctrl = NAND_CTRL_CLE | NAND_CTRL_CHANGE;
++
++	/* Write out the command to the device */
++	if (command == NAND_CMD_SEQIN) {
++		int readcmd;
++
++		if (column >= mtd->writesize) {
++			/* OOB area */
++			column -= mtd->writesize;
++			readcmd = NAND_CMD_READOOB;
++		} else if (column < 256) {
++			/* First 256 bytes --> READ0 */
++			readcmd = NAND_CMD_READ0;
++		} else {
++			column -= 256;
++			readcmd = NAND_CMD_READ1;
++		}
++		chip->cmd_ctrl(mtd, readcmd, ctrl);
++		ctrl &= ~NAND_CTRL_CHANGE;
++	}
++	chip->cmd_ctrl(mtd, command, ctrl);
++
++	/* Address cycle, when necessary */
++	ctrl = NAND_CTRL_ALE | NAND_CTRL_CHANGE;
++	/* Serially input address */
++	if (column != -1) {
++		/* Adjust columns for 16 bit buswidth */
++		if (chip->options & NAND_BUSWIDTH_16 &&
++				!nand_opcode_8bits(command))
++			column >>= 1;
++		chip->cmd_ctrl(mtd, column, ctrl);
++		ctrl &= ~NAND_CTRL_CHANGE;
++	}
++	if (page_addr != -1) {
++		chip->cmd_ctrl(mtd, page_addr, ctrl);
++		ctrl &= ~NAND_CTRL_CHANGE;
++		chip->cmd_ctrl(mtd, page_addr >> 8, ctrl);
++		/* One more address cycle for devices > 32MiB */
++		if (chip->chipsize > (32 << 20))
++			chip->cmd_ctrl(mtd, page_addr >> 16, ctrl);
++	}
++	chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
++
++	/*
++	 * Program and erase have their own busy handlers status and sequential
++	 * in needs no delay
++	 */
++	switch (command) {
++
++	case NAND_CMD_PAGEPROG:
++	case NAND_CMD_ERASE1:
++	case NAND_CMD_ERASE2:
++	case NAND_CMD_SEQIN:
++	case NAND_CMD_STATUS:
++	case NAND_CMD_READID:
++	case NAND_CMD_SET_FEATURES:
++		return;
++
++	case NAND_CMD_RESET:
++		if (chip->dev_ready)
++			break;
++		udelay(chip->chip_delay);
++		chip->cmd_ctrl(mtd, NAND_CMD_STATUS,
++			       NAND_CTRL_CLE | NAND_CTRL_CHANGE);
++		chip->cmd_ctrl(mtd,
++			       NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
++		/* EZ-NAND can take upto 250ms as per ONFi v4.0 */
++		nand_wait_status_ready(mtd, 250);
++		return;
++
++		/* This applies to read commands */
++	case NAND_CMD_READ0:
++		/*
++		 * READ0 is sometimes used to exit GET STATUS mode. When this
++		 * is the case no address cycles are requested, and we can use
++		 * this information to detect that we should not wait for the
++		 * device to be ready.
++		 */
++		if (column == -1 && page_addr == -1)
++			return;
++
++	default:
++		/*
++		 * If we don't have access to the busy pin, we apply the given
++		 * command delay
++		 */
++		if (!chip->dev_ready) {
++			udelay(chip->chip_delay);
++			return;
++		}
++	}
++	/*
++	 * Apply this short delay always to ensure that we do wait tWB in
++	 * any case on any machine.
++	 */
++	ndelay(100);
++
++	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
++ * @command: the command to be sent
++ * @column: the column address for this command, -1 if none
++ * @page_addr: the page address for this command, -1 if none
++ *
++ * Send command to NAND device. This is the version for the new large page
++ * devices. We don't have the separate regions as we have in the small page
++ * devices. We must emulate NAND_CMD_READOOB to keep the code compatible.
++ */
++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);
++
++	/* Emulate NAND_CMD_READOOB */
++	if (command == NAND_CMD_READOOB) {
++		column += mtd->writesize;
++		command = NAND_CMD_READ0;
++	}
++
++	/* Command latch cycle */
++	chip->cmd_ctrl(mtd, command, NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
++
++	if (column != -1 || page_addr != -1) {
++		int ctrl = NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE;
++
++		/* Serially input address */
++		if (column != -1) {
++			/* Adjust columns for 16 bit buswidth */
++			if (chip->options & NAND_BUSWIDTH_16 &&
++					!nand_opcode_8bits(command))
++				column >>= 1;
++			chip->cmd_ctrl(mtd, column, ctrl);
++			ctrl &= ~NAND_CTRL_CHANGE;
++
++			/* Only output a single addr cycle for 8bits opcodes. */
++			if (!nand_opcode_8bits(command))
++				chip->cmd_ctrl(mtd, column >> 8, ctrl);
++		}
++		if (page_addr != -1) {
++			chip->cmd_ctrl(mtd, page_addr, ctrl);
++			chip->cmd_ctrl(mtd, page_addr >> 8,
++				       NAND_NCE | NAND_ALE);
++			/* One more address cycle for devices > 128MiB */
++			if (chip->chipsize > (128 << 20))
++				chip->cmd_ctrl(mtd, page_addr >> 16,
++					       NAND_NCE | NAND_ALE);
++		}
++	}
++	chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
++
++	/*
++	 * Program and erase have their own busy handlers status, sequential
++	 * in and status need no delay.
++	 */
++	switch (command) {
++
++	case NAND_CMD_CACHEDPROG:
++	case NAND_CMD_PAGEPROG:
++	case NAND_CMD_ERASE1:
++	case NAND_CMD_ERASE2:
++	case NAND_CMD_SEQIN:
++	case NAND_CMD_STATUS:
++	case NAND_CMD_READID:
++	case NAND_CMD_SET_FEATURES:
++		return;
++
++	case NAND_CMD_RNDIN:
++		nand_ccs_delay(chip);
++		return;
++
++	case NAND_CMD_RESET:
++		if (chip->dev_ready)
++			break;
++		udelay(chip->chip_delay);
++		chip->cmd_ctrl(mtd, NAND_CMD_STATUS,
++			       NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
++		chip->cmd_ctrl(mtd, NAND_CMD_NONE,
++			       NAND_NCE | NAND_CTRL_CHANGE);
++		/* EZ-NAND can take upto 250ms as per ONFi v4.0 */
++		nand_wait_status_ready(mtd, 250);
++		return;
++
++	case NAND_CMD_RNDOUT:
++		/* No ready / busy check necessary */
++		chip->cmd_ctrl(mtd, NAND_CMD_RNDOUTSTART,
++			       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:
++		/*
++		 * READ0 is sometimes used to exit GET STATUS mode. When this
++		 * is the case no address cycles are requested, and we can use
++		 * this information to detect that READSTART should not be
++		 * issued.
++		 */
++		if (column == -1 && page_addr == -1)
++			return;
++
++		chip->cmd_ctrl(mtd, NAND_CMD_READSTART,
++			       NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
++		chip->cmd_ctrl(mtd, NAND_CMD_NONE,
++			       NAND_NCE | NAND_CTRL_CHANGE);
++
++		/* This applies to read commands */
++	default:
++		/*
++		 * If we don't have access to the busy pin, we apply the given
++		 * command delay.
++		 */
++		if (!chip->dev_ready) {
++			udelay(chip->chip_delay);
++			return;
++		}
++	}
++
++	/*
++	 * Apply this short delay always to ensure that we do wait tWB in
++	 * any case on any machine.
++	 */
++	ndelay(100);
++
++	nand_wait_ready(mtd);
++}
++
++/**
++ * panic_nand_get_device - [GENERIC] Get chip for selected access
++ * @chip: the nand chip descriptor
++ * @mtd: MTD device structure
++ * @new_state: the state which is requested
++ *
++ * Used when in panic, no locks are taken.
++ */
++static void panic_nand_get_device(struct nand_chip *chip,
++		      struct mtd_info *mtd, int new_state)
++{
++	/* Hardware controller shared among independent devices */
++	chip->controller->active = chip;
++	chip->state = new_state;
++}
++
++/**
++ * nand_get_device - [GENERIC] Get chip for selected access
++ * @mtd: MTD device structure
++ * @new_state: the state which is requested
++ *
++ * Get the device and lock it for exclusive access
++ */
++static int
++nand_get_device(struct mtd_info *mtd, int new_state)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	spinlock_t *lock = &chip->controller->lock;
++	wait_queue_head_t *wq = &chip->controller->wq;
++	DECLARE_WAITQUEUE(wait, current);
++retry:
++	spin_lock(lock);
++
++	/* Hardware controller shared among independent devices */
++	if (!chip->controller->active)
++		chip->controller->active = chip;
++
++	if (chip->controller->active == chip && chip->state == FL_READY) {
++		chip->state = new_state;
++		spin_unlock(lock);
++		return 0;
++	}
++	if (new_state == FL_PM_SUSPENDED) {
++		if (chip->controller->active->state == FL_PM_SUSPENDED) {
++			chip->state = FL_PM_SUSPENDED;
++			spin_unlock(lock);
++			return 0;
++		}
++	}
++	set_current_state(TASK_UNINTERRUPTIBLE);
++	add_wait_queue(wq, &wait);
++	spin_unlock(lock);
++	schedule();
++	remove_wait_queue(wq, &wait);
++	goto retry;
++}
++
++/**
++ * panic_nand_wait - [GENERIC] wait until the command is done
++ * @mtd: MTD device structure
++ * @chip: NAND chip structure
++ * @timeo: timeout
++ *
++ * Wait for command done. This is a helper function for nand_wait used when
++ * we are in interrupt context. May happen when in panic and trying to write
++ * an oops through mtdoops.
++ */
++static void panic_nand_wait(struct mtd_info *mtd, struct nand_chip *chip,
++			    unsigned long timeo)
++{
++	int i;
++	for (i = 0; i < timeo; i++) {
++		if (chip->dev_ready) {
++			if (chip->dev_ready(mtd))
++				break;
++		} else {
++			if (chip->read_byte(mtd) & NAND_STATUS_READY)
++				break;
++		}
++		mdelay(1);
++	}
++}
++
++/**
++ * nand_wait - [DEFAULT] wait until the command is done
++ * @mtd: MTD device structure
++ * @chip: NAND chip structure
++ *
++ * Wait for command done. This applies to erase and program only.
++ */
++static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
++{
++
++	int status;
++	unsigned long timeo = 400;
++
++	/*
++	 * Apply this short delay always to ensure that we do wait tWB in any
++	 * case on any machine.
++	 */
++	ndelay(100);
++
++	chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
++
++	if (in_interrupt() || oops_in_progress)
++		panic_nand_wait(mtd, chip, timeo);
++	else {
++		timeo = jiffies + msecs_to_jiffies(timeo);
++		do {
++			if (chip->dev_ready) {
++				if (chip->dev_ready(mtd))
++					break;
++			} else {
++				if (chip->read_byte(mtd) & NAND_STATUS_READY)
++					break;
++			}
++			cond_resched();
++		} while (time_before(jiffies, timeo));
++	}
++
++	status = (int)chip->read_byte(mtd);
++	/* This can happen if in case of timeout or buggy dev_ready */
++	WARN_ON(!(status & NAND_STATUS_READY));
++	return status;
++}
++
++/**
++ * nand_reset_data_interface - Reset data interface and timings
++ * @chip: The NAND chip
++ * @chipnr: Internal die id
++ *
++ * Reset the Data interface and timings to ONFI mode 0.
++ *
++ * Returns 0 for success or negative error code otherwise.
++ */
++static int nand_reset_data_interface(struct nand_chip *chip, int chipnr)
++{
++	struct mtd_info *mtd = nand_to_mtd(chip);
++	const struct nand_data_interface *conf;
++	int ret;
++
++	if (!chip->setup_data_interface)
++		return 0;
++
++	/*
++	 * The ONFI specification says:
++	 * "
++	 * To transition from NV-DDR or NV-DDR2 to the SDR data
++	 * interface, the host shall use the Reset (FFh) command
++	 * using SDR timing mode 0. A device in any timing mode is
++	 * required to recognize Reset (FFh) command issued in SDR
++	 * timing mode 0.
++	 * "
++	 *
++	 * Configure the data interface in SDR mode and set the
++	 * timings to timing mode 0.
++	 */
++
++	conf = nand_get_default_data_interface();
++	ret = chip->setup_data_interface(mtd, chipnr, conf);
++	if (ret)
++		pr_err("Failed to configure data interface to SDR timing mode 0\n");
++
++	return ret;
++}
++
++/**
++ * nand_setup_data_interface - Setup the best data interface and timings
++ * @chip: The NAND chip
++ * @chipnr: Internal die id
++ *
++ * Find and configure the best data interface and NAND timings supported by
++ * the chip and the driver.
++ * First tries to retrieve supported timing modes from ONFI information,
++ * and if the NAND chip does not support ONFI, relies on the
++ * ->onfi_timing_mode_default specified in the nand_ids table.
++ *
++ * Returns 0 for success or negative error code otherwise.
++ */
++static int nand_setup_data_interface(struct nand_chip *chip, int chipnr)
++{
++	struct mtd_info *mtd = nand_to_mtd(chip);
++	int ret;
++
++	if (!chip->setup_data_interface || !chip->data_interface)
++		return 0;
++
++	/*
++	 * Ensure the timing mode has been changed on the chip side
++	 * before changing timings on the controller side.
++	 */
++	if (chip->onfi_version &&
++	    (le16_to_cpu(chip->onfi_params.opt_cmd) &
++	     ONFI_OPT_CMD_SET_GET_FEATURES)) {
++		u8 tmode_param[ONFI_SUBFEATURE_PARAM_LEN] = {
++			chip->onfi_timing_mode_default,
++		};
++
++		ret = chip->onfi_set_features(mtd, chip,
++				ONFI_FEATURE_ADDR_TIMING_MODE,
++				tmode_param);
++		if (ret)
++			goto err;
++	}
++
++	ret = chip->setup_data_interface(mtd, chipnr, chip->data_interface);
++err:
++	return ret;
++}
++
++/**
++ * nand_init_data_interface - find the best data interface and timings
++ * @chip: The NAND chip
++ *
++ * Find the best data interface and NAND timings supported by the chip
++ * and the driver.
++ * First tries to retrieve supported timing modes from ONFI information,
++ * and if the NAND chip does not support ONFI, relies on the
++ * ->onfi_timing_mode_default specified in the nand_ids table. After this
++ * function nand_chip->data_interface is initialized with the best timing mode
++ * available.
++ *
++ * Returns 0 for success or negative error code otherwise.
++ */
++static int nand_init_data_interface(struct nand_chip *chip)
++{
++	struct mtd_info *mtd = nand_to_mtd(chip);
++	int modes, mode, ret;
++
++	if (!chip->setup_data_interface)
++		return 0;
++
++	/*
++	 * First try to identify the best timings from ONFI parameters and
++	 * if the NAND does not support ONFI, fallback to the default ONFI
++	 * timing mode.
++	 */
++	modes = onfi_get_async_timing_mode(chip);
++	if (modes == ONFI_TIMING_MODE_UNKNOWN) {
++		if (!chip->onfi_timing_mode_default)
++			return 0;
++
++		modes = GENMASK(chip->onfi_timing_mode_default, 0);
++	}
++
++	chip->data_interface = kzalloc(sizeof(*chip->data_interface),
++				       GFP_KERNEL);
++	if (!chip->data_interface)
++		return -ENOMEM;
++
++	for (mode = fls(modes) - 1; mode >= 0; mode--) {
++		ret = onfi_init_data_interface(chip, chip->data_interface,
++					       NAND_SDR_IFACE, mode);
++		if (ret)
++			continue;
++
++		/* Pass -1 to only */
++		ret = chip->setup_data_interface(mtd,
++						 NAND_DATA_IFACE_CHECK_ONLY,
++						 chip->data_interface);
++		if (!ret) {
++			chip->onfi_timing_mode_default = mode;
++			break;
++		}
++	}
++
++	return 0;
++}
++
++static void nand_release_data_interface(struct nand_chip *chip)
++{
++	kfree(chip->data_interface);
++}
++
++/**
++ * 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 chipnr)
++{
++	struct mtd_info *mtd = nand_to_mtd(chip);
++	int ret;
++
++	ret = nand_reset_data_interface(chip, chipnr);
++	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, chipnr);
++	chip->select_chip(mtd, -1);
++	if (ret)
++		return ret;
++
++	return 0;
++}
++EXPORT_SYMBOL_GPL(nand_reset);
++
++/**
++ * nand_check_erased_buf - check if a buffer contains (almost) only 0xff data
++ * @buf: buffer to test
++ * @len: buffer length
++ * @bitflips_threshold: maximum number of bitflips
++ *
++ * Check if a buffer contains only 0xff, which means the underlying region
++ * has been erased and is ready to be programmed.
++ * The bitflips_threshold specify the maximum number of bitflips before
++ * considering the region is not erased.
++ * Note: The logic of this function has been extracted from the memweight
++ * implementation, except that nand_check_erased_buf function exit before
++ * testing the whole buffer if the number of bitflips exceed the
++ * bitflips_threshold value.
++ *
++ * Returns a positive number of bitflips less than or equal to
++ * bitflips_threshold, or -ERROR_CODE for bitflips in excess of the
++ * threshold.
++ */
++static int nand_check_erased_buf(void *buf, int len, int bitflips_threshold)
++{
++	const unsigned char *bitmap = buf;
++	int bitflips = 0;
++	int weight;
++
++	for (; len && ((uintptr_t)bitmap) % sizeof(long);
++	     len--, bitmap++) {
++		weight = hweight8(*bitmap);
++		bitflips += BITS_PER_BYTE - weight;
++		if (unlikely(bitflips > bitflips_threshold))
++			return -EBADMSG;
++	}
++
++	for (; len >= sizeof(long);
++	     len -= sizeof(long), bitmap += sizeof(long)) {
++		unsigned long d = *((unsigned long *)bitmap);
++		if (d == ~0UL)
++			continue;
++		weight = hweight_long(d);
++		bitflips += BITS_PER_LONG - weight;
++		if (unlikely(bitflips > bitflips_threshold))
++			return -EBADMSG;
++	}
++
++	for (; len > 0; len--, bitmap++) {
++		weight = hweight8(*bitmap);
++		bitflips += BITS_PER_BYTE - weight;
++		if (unlikely(bitflips > bitflips_threshold))
++			return -EBADMSG;
++	}
++
++	return bitflips;
++}
++
++/**
++ * nand_check_erased_ecc_chunk - check if an ECC chunk contains (almost) only
++ *				 0xff data
++ * @data: data buffer to test
++ * @datalen: data length
++ * @ecc: ECC buffer
++ * @ecclen: ECC length
++ * @extraoob: extra OOB buffer
++ * @extraooblen: extra OOB length
++ * @bitflips_threshold: maximum number of bitflips
++ *
++ * Check if a data buffer and its associated ECC and OOB data contains only
++ * 0xff pattern, which means the underlying region has been erased and is
++ * ready to be programmed.
++ * The bitflips_threshold specify the maximum number of bitflips before
++ * considering the region as not erased.
++ *
++ * Note:
++ * 1/ ECC algorithms are working on pre-defined block sizes which are usually
++ *    different from the NAND page size. When fixing bitflips, ECC engines will
++ *    report the number of errors per chunk, and the NAND core infrastructure
++ *    expect you to return the maximum number of bitflips for the whole page.
++ *    This is why you should always use this function on a single chunk and
++ *    not on the whole page. After checking each chunk you should update your
++ *    max_bitflips value accordingly.
++ * 2/ When checking for bitflips in erased pages you should not only check
++ *    the payload data but also their associated ECC data, because a user might
++ *    have programmed almost all bits to 1 but a few. In this case, we
++ *    shouldn't consider the chunk as erased, and checking ECC bytes prevent
++ *    this case.
++ * 3/ The extraoob argument is optional, and should be used if some of your OOB
++ *    data are protected by the ECC engine.
++ *    It could also be used if you support subpages and want to attach some
++ *    extra OOB data to an ECC chunk.
++ *
++ * Returns a positive number of bitflips less than or equal to
++ * bitflips_threshold, or -ERROR_CODE for bitflips in excess of the
++ * threshold. In case of success, the passed buffers are filled with 0xff.
++ */
++int nand_check_erased_ecc_chunk(void *data, int datalen,
++				void *ecc, int ecclen,
++				void *extraoob, int extraooblen,
++				int bitflips_threshold)
++{
++	int data_bitflips = 0, ecc_bitflips = 0, extraoob_bitflips = 0;
++
++	data_bitflips = nand_check_erased_buf(data, datalen,
++					      bitflips_threshold);
++	if (data_bitflips < 0)
++		return data_bitflips;
++
++	bitflips_threshold -= data_bitflips;
++
++	ecc_bitflips = nand_check_erased_buf(ecc, ecclen, bitflips_threshold);
++	if (ecc_bitflips < 0)
++		return ecc_bitflips;
++
++	bitflips_threshold -= ecc_bitflips;
++
++	extraoob_bitflips = nand_check_erased_buf(extraoob, extraooblen,
++						  bitflips_threshold);
++	if (extraoob_bitflips < 0)
++		return extraoob_bitflips;
++
++	if (data_bitflips)
++		memset(data, 0xff, datalen);
++
++	if (ecc_bitflips)
++		memset(ecc, 0xff, ecclen);
++
++	if (extraoob_bitflips)
++		memset(extraoob, 0xff, extraooblen);
++
++	return data_bitflips + ecc_bitflips + extraoob_bitflips;
++}
++EXPORT_SYMBOL(nand_check_erased_ecc_chunk);
++
++/**
++ * nand_read_page_raw - [INTERN] read raw page data without ecc
++ * @mtd: mtd info structure
++ * @chip: nand chip info structure
++ * @buf: buffer to store read data
++ * @oob_required: caller requires OOB data read to chip->oob_poi
++ * @page: page number to read
++ *
++ * Not for syndrome calculating ECC controllers, which use a special oob layout.
++ */
++int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
++		       uint8_t *buf, int oob_required, int page)
++{
++	chip->read_buf(mtd, buf, mtd->writesize);
++	if (oob_required)
++		chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
++	return 0;
++}
++EXPORT_SYMBOL(nand_read_page_raw);
++
++/**
++ * nand_read_page_raw_syndrome - [INTERN] read raw page data without ecc
++ * @mtd: mtd info structure
++ * @chip: nand chip info structure
++ * @buf: buffer to store read data
++ * @oob_required: caller requires OOB data read to chip->oob_poi
++ * @page: page number to read
++ *
++ * We need a special oob layout and handling even when OOB isn't used.
++ */
++static int nand_read_page_raw_syndrome(struct mtd_info *mtd,
++				       struct nand_chip *chip, uint8_t *buf,
++				       int oob_required, int page)
++{
++	int eccsize = chip->ecc.size;
++	int eccbytes = chip->ecc.bytes;
++	uint8_t *oob = chip->oob_poi;
++	int steps, size;
++
++	for (steps = chip->ecc.steps; steps > 0; steps--) {
++		chip->read_buf(mtd, buf, eccsize);
++		buf += eccsize;
++
++		if (chip->ecc.prepad) {
++			chip->read_buf(mtd, oob, chip->ecc.prepad);
++			oob += chip->ecc.prepad;
++		}
++
++		chip->read_buf(mtd, oob, eccbytes);
++		oob += eccbytes;
++
++		if (chip->ecc.postpad) {
++			chip->read_buf(mtd, oob, chip->ecc.postpad);
++			oob += chip->ecc.postpad;
++		}
++	}
++
++	size = mtd->oobsize - (oob - chip->oob_poi);
++	if (size)
++		chip->read_buf(mtd, oob, size);
++
++	return 0;
++}
++
++/**
++ * nand_read_page_swecc - [REPLACEABLE] software ECC based page read function
++ * @mtd: mtd info structure
++ * @chip: nand chip info structure
++ * @buf: buffer to store read data
++ * @oob_required: caller requires OOB data read to chip->oob_poi
++ * @page: page number to read
++ */
++static int 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, ret;
++	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;
++	unsigned int max_bitflips = 0;
++
++	chip->ecc.read_page_raw(mtd, chip, buf, 1, page);
++
++	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
++		chip->ecc.calculate(mtd, p, &ecc_calc[i]);
++
++	ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, chip->oob_poi, 0,
++					 chip->ecc.total);
++	if (ret)
++		return ret;
++
++	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;
++			max_bitflips = max_t(unsigned int, max_bitflips, stat);
++		}
++	}
++	return max_bitflips;
++}
++
++/**
++ * nand_read_subpage - [REPLACEABLE] ECC based sub-page read function
++ * @mtd: mtd info structure
++ * @chip: nand chip info structure
++ * @data_offs: offset of requested data within the page
++ * @readlen: data length
++ * @bufpoi: buffer to store read data
++ * @page: page number to read
++ */
++static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
++			uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi,
++			int page)
++{
++	int start_step, end_step, num_steps, ret;
++	uint8_t *p;
++	int data_col_addr, i, gaps = 0;
++	int datafrag_len, eccfrag_len, aligned_len, aligned_pos;
++	int busw = (chip->options & NAND_BUSWIDTH_16) ? 2 : 1;
++	int index, section = 0;
++	unsigned int max_bitflips = 0;
++	struct mtd_oob_region oobregion = { };
++
++	/* Column address within the page aligned to ECC size (256bytes) */
++	start_step = data_offs / chip->ecc.size;
++	end_step = (data_offs + readlen - 1) / chip->ecc.size;
++	num_steps = end_step - start_step + 1;
++	index = start_step * chip->ecc.bytes;
++
++	/* Data size aligned to ECC ecc.size */
++	datafrag_len = num_steps * chip->ecc.size;
++	eccfrag_len = num_steps * chip->ecc.bytes;
++
++	data_col_addr = start_step * chip->ecc.size;
++	/* If we read not a page aligned data */
++	if (data_col_addr != 0)
++		chip->cmdfunc(mtd, NAND_CMD_RNDOUT, data_col_addr, -1);
++
++	p = bufpoi + data_col_addr;
++	chip->read_buf(mtd, p, datafrag_len);
++
++	/* Calculate ECC */
++	for (i = 0; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size)
++		chip->ecc.calculate(mtd, p, &chip->buffers->ecccalc[i]);
++
++	/*
++	 * The performance is faster if we position offsets according to
++	 * ecc.pos. Let's make sure that there are no gaps in ECC positions.
++	 */
++	ret = mtd_ooblayout_find_eccregion(mtd, index, &section, &oobregion);
++	if (ret)
++		return ret;
++
++	if (oobregion.length < eccfrag_len)
++		gaps = 1;
++
++	if (gaps) {
++		chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize, -1);
++		chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
++	} else {
++		/*
++		 * Send the command to read the particular ECC bytes take care
++		 * about buswidth alignment in read_buf.
++		 */
++		aligned_pos = oobregion.offset & ~(busw - 1);
++		aligned_len = eccfrag_len;
++		if (oobregion.offset & (busw - 1))
++			aligned_len++;
++		if ((oobregion.offset + (num_steps * chip->ecc.bytes)) &
++		    (busw - 1))
++			aligned_len++;
++
++		chip->cmdfunc(mtd, NAND_CMD_RNDOUT,
++			      mtd->writesize + aligned_pos, -1);
++		chip->read_buf(mtd, &chip->oob_poi[aligned_pos], aligned_len);
++	}
++
++	ret = mtd_ooblayout_get_eccbytes(mtd, chip->buffers->ecccode,
++					 chip->oob_poi, index, eccfrag_len);
++	if (ret)
++		return ret;
++
++	p = bufpoi + data_col_addr;
++	for (i = 0; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size) {
++		int stat;
++
++		stat = chip->ecc.correct(mtd, p,
++			&chip->buffers->ecccode[i], &chip->buffers->ecccalc[i]);
++		if (stat == -EBADMSG &&
++		    (chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) {
++			/* check for empty pages with bitflips */
++			stat = nand_check_erased_ecc_chunk(p, chip->ecc.size,
++						&chip->buffers->ecccode[i],
++						chip->ecc.bytes,
++						NULL, 0,
++						chip->ecc.strength);
++		}
++
++		if (stat < 0) {
++			mtd->ecc_stats.failed++;
++		} else {
++			mtd->ecc_stats.corrected += stat;
++			max_bitflips = max_t(unsigned int, max_bitflips, stat);
++		}
++	}
++	return max_bitflips;
++}
++
++/**
++ * nand_read_page_hwecc - [REPLACEABLE] hardware ECC based page read function
++ * @mtd: mtd info structure
++ * @chip: nand chip info structure
++ * @buf: buffer to store read data
++ * @oob_required: caller requires OOB data read to chip->oob_poi
++ * @page: page number to read
++ *
++ * Not for syndrome calculating ECC controllers which need a special oob layout.
++ */
++static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
++				uint8_t *buf, int oob_required, int page)
++{
++	int i, eccsize = chip->ecc.size, ret;
++	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;
++	unsigned int max_bitflips = 0;
++
++	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
++		chip->ecc.hwctl(mtd, NAND_ECC_READ);
++		chip->read_buf(mtd, p, eccsize);
++		chip->ecc.calculate(mtd, p, &ecc_calc[i]);
++	}
++	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
++
++	ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, chip->oob_poi, 0,
++					 chip->ecc.total);
++	if (ret)
++		return ret;
++
++	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 == -EBADMSG &&
++		    (chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) {
++			/* check for empty pages with bitflips */
++			stat = nand_check_erased_ecc_chunk(p, eccsize,
++						&ecc_code[i], eccbytes,
++						NULL, 0,
++						chip->ecc.strength);
++		}
++
++		if (stat < 0) {
++			mtd->ecc_stats.failed++;
++		} else {
++			mtd->ecc_stats.corrected += stat;
++			max_bitflips = max_t(unsigned int, max_bitflips, stat);
++		}
++	}
++	return max_bitflips;
++}
++
++/**
++ * nand_read_page_hwecc_oob_first - [REPLACEABLE] hw ecc, read oob first
++ * @mtd: mtd info structure
++ * @chip: nand chip info structure
++ * @buf: buffer to store read data
++ * @oob_required: caller requires OOB data read to chip->oob_poi
++ * @page: page number to read
++ *
++ * Hardware ECC for large page chips, require OOB to be read first. For this
++ * ECC mode, the write_page method is re-used from ECC_HW. These methods
++ * read/write ECC from the OOB area, unlike the ECC_HW_SYNDROME support with
++ * multiple ECC steps, follows the "infix ECC" scheme and reads/writes ECC from
++ * the data area, by overwriting the NAND manufacturer bad block markings.
++ */
++static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd,
++	struct nand_chip *chip, uint8_t *buf, int oob_required, int page)
++{
++	int i, eccsize = chip->ecc.size, ret;
++	int eccbytes = chip->ecc.bytes;
++	int eccsteps = chip->ecc.steps;
++	uint8_t *p = buf;
++	uint8_t *ecc_code = chip->buffers->ecccode;
++	uint8_t *ecc_calc = chip->buffers->ecccalc;
++	unsigned int max_bitflips = 0;
++
++	/* Read the OOB area first */
++	chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
++	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
++	chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
++
++	ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, chip->oob_poi, 0,
++					 chip->ecc.total);
++	if (ret)
++		return ret;
++
++	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
++		int stat;
++
++		chip->ecc.hwctl(mtd, NAND_ECC_READ);
++		chip->read_buf(mtd, p, eccsize);
++		chip->ecc.calculate(mtd, p, &ecc_calc[i]);
++
++		stat = chip->ecc.correct(mtd, p, &ecc_code[i], NULL);
++		if (stat == -EBADMSG &&
++		    (chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) {
++			/* check for empty pages with bitflips */
++			stat = nand_check_erased_ecc_chunk(p, eccsize,
++						&ecc_code[i], eccbytes,
++						NULL, 0,
++						chip->ecc.strength);
++		}
++
++		if (stat < 0) {
++			mtd->ecc_stats.failed++;
++		} else {
++			mtd->ecc_stats.corrected += stat;
++			max_bitflips = max_t(unsigned int, max_bitflips, stat);
++		}
++	}
++	return max_bitflips;
++}
++
++/**
++ * nand_read_page_syndrome - [REPLACEABLE] hardware ECC syndrome based page read
++ * @mtd: mtd info structure
++ * @chip: nand chip info structure
++ * @buf: buffer to store read data
++ * @oob_required: caller requires OOB data read to chip->oob_poi
++ * @page: page number to read
++ *
++ * The hw generator calculates the error syndrome automatically. Therefore we
++ * need a special oob layout and handling.
++ */
++static int nand_read_page_syndrome(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;
++	int eccpadbytes = eccbytes + chip->ecc.prepad + chip->ecc.postpad;
++	uint8_t *p = buf;
++	uint8_t *oob = chip->oob_poi;
++	unsigned int max_bitflips = 0;
++
++	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
++		int stat;
++
++		chip->ecc.hwctl(mtd, NAND_ECC_READ);
++		chip->read_buf(mtd, p, eccsize);
++
++		if (chip->ecc.prepad) {
++			chip->read_buf(mtd, oob, chip->ecc.prepad);
++			oob += chip->ecc.prepad;
++		}
++
++		chip->ecc.hwctl(mtd, NAND_ECC_READSYN);
++		chip->read_buf(mtd, oob, eccbytes);
++		stat = chip->ecc.correct(mtd, p, oob, NULL);
++
++		oob += eccbytes;
++
++		if (chip->ecc.postpad) {
++			chip->read_buf(mtd, oob, chip->ecc.postpad);
++			oob += chip->ecc.postpad;
++		}
++
++		if (stat == -EBADMSG &&
++		    (chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) {
++			/* check for empty pages with bitflips */
++			stat = nand_check_erased_ecc_chunk(p, chip->ecc.size,
++							   oob - eccpadbytes,
++							   eccpadbytes,
++							   NULL, 0,
++							   chip->ecc.strength);
++		}
++
++		if (stat < 0) {
++			mtd->ecc_stats.failed++;
++		} else {
++			mtd->ecc_stats.corrected += stat;
++			max_bitflips = max_t(unsigned int, max_bitflips, stat);
++		}
++	}
++
++	/* Calculate remaining oob bytes */
++	i = mtd->oobsize - (oob - chip->oob_poi);
++	if (i)
++		chip->read_buf(mtd, oob, i);
++
++	return max_bitflips;
++}
++
++/**
++ * nand_transfer_oob - [INTERN] Transfer oob to client buffer
++ * @mtd: mtd info structure
++ * @oob: oob destination address
++ * @ops: oob ops structure
++ * @len: size of oob to transfer
++ */
++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);
++	int ret;
++
++	switch (ops->mode) {
++
++	case MTD_OPS_PLACE_OOB:
++	case MTD_OPS_RAW:
++		memcpy(oob, chip->oob_poi + ops->ooboffs, len);
++		return oob + len;
++
++	case MTD_OPS_AUTO_OOB:
++		ret = mtd_ooblayout_get_databytes(mtd, oob, chip->oob_poi,
++						  ops->ooboffs, len);
++		BUG_ON(ret);
++		return oob + len;
++
++	default:
++		BUG();
++	}
++	return NULL;
++}
++
++/**
++ * nand_setup_read_retry - [INTERN] Set the READ RETRY mode
++ * @mtd: MTD device structure
++ * @retry_mode: the retry mode to use
++ *
++ * Some vendors supply a special command to shift the Vt threshold, to be used
++ * when there are too many bitflips in a page (i.e., ECC error). After setting
++ * a new threshold, the host should retry reading the page.
++ */
++static int nand_setup_read_retry(struct mtd_info *mtd, int retry_mode)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++
++	pr_debug("setting READ RETRY mode %d\n", retry_mode);
++
++	if (retry_mode >= chip->read_retries)
++		return -EINVAL;
++
++	if (!chip->setup_read_retry)
++		return -EOPNOTSUPP;
++
++	return chip->setup_read_retry(mtd, retry_mode);
++}
++
++/**
++ * nand_do_read_ops - [INTERN] Read data with ECC
++ * @mtd: MTD device structure
++ * @from: offset to read from
++ * @ops: oob ops structure
++ *
++ * Internal function. Called with chip held.
++ */
++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);
++	int ret = 0;
++	uint32_t readlen = ops->len;
++	uint32_t oobreadlen = ops->ooblen;
++	uint32_t max_oobsize = mtd_oobavail(mtd, ops);
++
++	uint8_t *bufpoi, *oob, *buf;
++	int use_bufpoi;
++	unsigned int max_bitflips = 0;
++	int retry_mode = 0;
++	bool ecc_fail = false;
++
++	chipnr = (int)(from >> chip->chip_shift);
++	chip->select_chip(mtd, chipnr);
++
++	realpage = (int)(from >> chip->page_shift);
++	page = realpage & chip->pagemask;
++
++	col = (int)(from & (mtd->writesize - 1));
++
++	buf = ops->datbuf;
++	oob = ops->oobbuf;
++	oob_required = oob ? 1 : 0;
++
++	while (1) {
++		unsigned int ecc_failures = mtd->ecc_stats.failed;
++
++		bytes = min(mtd->writesize - col, readlen);
++		aligned = (bytes == mtd->writesize);
++
++		if (!aligned)
++			use_bufpoi = 1;
++		else if (chip->options & NAND_USE_BOUNCE_BUFFER)
++			use_bufpoi = !virt_addr_valid(buf) ||
++				     !IS_ALIGNED((unsigned long)buf,
++						 chip->buf_align);
++		else
++			use_bufpoi = 0;
++
++		/* Is the current page in the buffer? */
++		if (realpage != chip->pagebuf || oob) {
++			bufpoi = use_bufpoi ? chip->buffers->databuf : buf;
++
++			if (use_bufpoi && aligned)
++				pr_debug("%s: using read bounce buffer for buf@%p\n",
++						 __func__, buf);
++
++read_retry:
++			if (nand_standard_page_accessors(&chip->ecc))
++				chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
++
++			/*
++			 * Now read the page into the buffer.  Absent an error,
++			 * the read methods return max bitflips per ecc step.
++			 */
++			if (unlikely(ops->mode == MTD_OPS_RAW))
++				ret = chip->ecc.read_page_raw(mtd, chip, bufpoi,
++							      oob_required,
++							      page);
++			else if (!aligned && NAND_HAS_SUBPAGE_READ(chip) &&
++				 !oob)
++				ret = chip->ecc.read_subpage(mtd, chip,
++							col, bytes, bufpoi,
++							page);
++			else
++				ret = chip->ecc.read_page(mtd, chip, bufpoi,
++							  oob_required, page);
++			if (ret < 0) {
++				if (use_bufpoi)
++					/* Invalidate page cache */
++					chip->pagebuf = -1;
++				break;
++			}
++
++			/* Transfer not aligned data */
++			if (use_bufpoi) {
++				if (!NAND_HAS_SUBPAGE_READ(chip) && !oob &&
++				    !(mtd->ecc_stats.failed - ecc_failures) &&
++				    (ops->mode != MTD_OPS_RAW)) {
++					chip->pagebuf = realpage;
++					chip->pagebuf_bitflips = ret;
++				} else {
++					/* Invalidate page cache */
++					chip->pagebuf = -1;
++				}
++				memcpy(buf, chip->buffers->databuf + col, bytes);
++			}
++
++			if (unlikely(oob)) {
++				int toread = min(oobreadlen, max_oobsize);
++
++				if (toread) {
++					oob = nand_transfer_oob(mtd,
++						oob, ops, toread);
++					oobreadlen -= toread;
++				}
++			}
++
++			if (chip->options & NAND_NEED_READRDY) {
++				/* Apply delay or wait for ready/busy pin */
++				if (!chip->dev_ready)
++					udelay(chip->chip_delay);
++				else
++					nand_wait_ready(mtd);
++			}
++
++			if (mtd->ecc_stats.failed - ecc_failures) {
++				if (retry_mode + 1 < chip->read_retries) {
++					retry_mode++;
++					ret = nand_setup_read_retry(mtd,
++							retry_mode);
++					if (ret < 0)
++						break;
++
++					/* Reset failures; retry */
++					mtd->ecc_stats.failed = ecc_failures;
++					goto read_retry;
++				} else {
++					/* No more retry modes; real failure */
++					ecc_fail = true;
++				}
++			}
++
++			buf += bytes;
++			max_bitflips = max_t(unsigned int, max_bitflips, ret);
++		} else {
++			memcpy(buf, chip->buffers->databuf + col, bytes);
++			buf += bytes;
++			max_bitflips = max_t(unsigned int, max_bitflips,
++					     chip->pagebuf_bitflips);
++		}
++
++		readlen -= bytes;
++
++		/* Reset to retry mode 0 */
++		if (retry_mode) {
++			ret = nand_setup_read_retry(mtd, 0);
++			if (ret < 0)
++				break;
++			retry_mode = 0;
++		}
++
++		if (!readlen)
++			break;
++
++		/* For subsequent reads align to page boundary */
++		col = 0;
++		/* Increment page address */
++		realpage++;
++
++		page = realpage & chip->pagemask;
++		/* Check, if we cross a chip boundary */
++		if (!page) {
++			chipnr++;
++			chip->select_chip(mtd, -1);
++			chip->select_chip(mtd, chipnr);
++		}
++	}
++	chip->select_chip(mtd, -1);
++
++	ops->retlen = ops->len - (size_t) readlen;
++	if (oob)
++		ops->oobretlen = ops->ooblen - oobreadlen;
++
++	if (ret < 0)
++		return ret;
++
++	if (ecc_fail)
++		return -EBADMSG;
++
++	return max_bitflips;
++}
++
++/**
++ * nand_read_oob_std - [REPLACEABLE] the most common OOB data read function
++ * @mtd: mtd info structure
++ * @chip: nand chip info structure
++ * @page: page number to read
++ */
++int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip, int page)
++{
++	chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
++	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
++	return 0;
++}
++EXPORT_SYMBOL(nand_read_oob_std);
++
++/**
++ * nand_read_oob_syndrome - [REPLACEABLE] OOB data read function for HW ECC
++ *			    with syndromes
++ * @mtd: mtd info structure
++ * @chip: nand chip info structure
++ * @page: page number to read
++ */
++int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
++			   int page)
++{
++	int length = mtd->oobsize;
++	int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad;
++	int eccsize = chip->ecc.size;
++	uint8_t *bufpoi = chip->oob_poi;
++	int i, toread, sndrnd = 0, pos;
++
++	chip->cmdfunc(mtd, NAND_CMD_READ0, chip->ecc.size, page);
++	for (i = 0; i < chip->ecc.steps; i++) {
++		if (sndrnd) {
++			pos = eccsize + i * (eccsize + chunk);
++			if (mtd->writesize > 512)
++				chip->cmdfunc(mtd, NAND_CMD_RNDOUT, pos, -1);
++			else
++				chip->cmdfunc(mtd, NAND_CMD_READ0, pos, page);
++		} else
++			sndrnd = 1;
++		toread = min_t(int, length, chunk);
++		chip->read_buf(mtd, bufpoi, toread);
++		bufpoi += toread;
++		length -= toread;
++	}
++	if (length > 0)
++		chip->read_buf(mtd, bufpoi, length);
++
++	return 0;
++}
++EXPORT_SYMBOL(nand_read_oob_syndrome);
++
++/**
++ * nand_write_oob_std - [REPLACEABLE] the most common OOB data write function
++ * @mtd: mtd info structure
++ * @chip: nand chip info structure
++ * @page: page number to write
++ */
++int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip, int page)
++{
++	int status = 0;
++	const uint8_t *buf = chip->oob_poi;
++	int length = mtd->oobsize;
++
++	chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page);
++	chip->write_buf(mtd, buf, length);
++	/* Send command to program the OOB data */
++	chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
++
++	status = chip->waitfunc(mtd, chip);
++
++	return status & NAND_STATUS_FAIL ? -EIO : 0;
++}
++EXPORT_SYMBOL(nand_write_oob_std);
++
++/**
++ * nand_write_oob_syndrome - [REPLACEABLE] OOB data write function for HW ECC
++ *			     with syndrome - only for large page flash
++ * @mtd: mtd info structure
++ * @chip: nand chip info structure
++ * @page: page number to write
++ */
++int nand_write_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
++			    int page)
++{
++	int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad;
++	int eccsize = chip->ecc.size, length = mtd->oobsize;
++	int i, len, pos, status = 0, sndcmd = 0, steps = chip->ecc.steps;
++	const uint8_t *bufpoi = chip->oob_poi;
++
++	/*
++	 * data-ecc-data-ecc ... ecc-oob
++	 * or
++	 * data-pad-ecc-pad-data-pad .... ecc-pad-oob
++	 */
++	if (!chip->ecc.prepad && !chip->ecc.postpad) {
++		pos = steps * (eccsize + chunk);
++		steps = 0;
++	} else
++		pos = eccsize;
++
++	chip->cmdfunc(mtd, NAND_CMD_SEQIN, pos, page);
++	for (i = 0; i < steps; i++) {
++		if (sndcmd) {
++			if (mtd->writesize <= 512) {
++				uint32_t fill = 0xFFFFFFFF;
++
++				len = eccsize;
++				while (len > 0) {
++					int num = min_t(int, len, 4);
++					chip->write_buf(mtd, (uint8_t *)&fill,
++							num);
++					len -= num;
++				}
++			} else {
++				pos = eccsize + i * (eccsize + chunk);
++				chip->cmdfunc(mtd, NAND_CMD_RNDIN, pos, -1);
++			}
++		} else
++			sndcmd = 1;
++		len = min_t(int, length, chunk);
++		chip->write_buf(mtd, bufpoi, len);
++		bufpoi += len;
++		length -= len;
++	}
++	if (length > 0)
++		chip->write_buf(mtd, bufpoi, length);
++
++	chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
++	status = chip->waitfunc(mtd, chip);
++
++	return status & NAND_STATUS_FAIL ? -EIO : 0;
++}
++EXPORT_SYMBOL(nand_write_oob_syndrome);
++
++/**
++ * nand_do_read_oob - [INTERN] NAND read out-of-band
++ * @mtd: MTD device structure
++ * @from: offset to read from
++ * @ops: oob operations description structure
++ *
++ * NAND read out-of-band data from the spare area.
++ */
++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 mtd_ecc_stats stats;
++	int readlen = ops->ooblen;
++	int len;
++	uint8_t *buf = ops->oobbuf;
++	int ret = 0;
++
++	pr_debug("%s: from = 0x%08Lx, len = %i\n",
++			__func__, (unsigned long long)from, readlen);
++
++	stats = mtd->ecc_stats;
++
++	len = mtd_oobavail(mtd, ops);
++
++	if (unlikely(ops->ooboffs >= len)) {
++		pr_debug("%s: attempt to start read outside oob\n",
++				__func__);
++		return -EINVAL;
++	}
++
++	/* Do not allow reads past end of device */
++	if (unlikely(from >= mtd->size ||
++		     ops->ooboffs + readlen > ((mtd->size >> chip->page_shift) -
++					(from >> chip->page_shift)) * len)) {
++		pr_debug("%s: attempt to read beyond end of device\n",
++				__func__);
++		return -EINVAL;
++	}
++
++	chipnr = (int)(from >> chip->chip_shift);
++	chip->select_chip(mtd, chipnr);
++
++	/* Shift to get page */
++	realpage = (int)(from >> chip->page_shift);
++	page = realpage & chip->pagemask;
++
++	while (1) {
++		if (ops->mode == MTD_OPS_RAW)
++			ret = chip->ecc.read_oob_raw(mtd, chip, page);
++		else
++			ret = chip->ecc.read_oob(mtd, chip, page);
++
++		if (ret < 0)
++			break;
++
++		len = min(len, readlen);
++		buf = nand_transfer_oob(mtd, buf, ops, len);
++
++		if (chip->options & NAND_NEED_READRDY) {
++			/* Apply delay or wait for ready/busy pin */
++			if (!chip->dev_ready)
++				udelay(chip->chip_delay);
++			else
++				nand_wait_ready(mtd);
++		}
++
++		readlen -= len;
++		if (!readlen)
++			break;
++
++		/* Increment page address */
++		realpage++;
++
++		page = realpage & chip->pagemask;
++		/* Check, if we cross a chip boundary */
++		if (!page) {
++			chipnr++;
++			chip->select_chip(mtd, -1);
++			chip->select_chip(mtd, chipnr);
++		}
++	}
++	chip->select_chip(mtd, -1);
++
++	ops->oobretlen = ops->ooblen - readlen;
++
++	if (ret < 0)
++		return ret;
++
++	if (mtd->ecc_stats.failed - stats.failed)
++		return -EBADMSG;
++
++	return  mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0;
++}
++
++/**
++ * nand_read_oob - [MTD Interface] NAND read data and/or out-of-band
++ * @mtd: MTD device structure
++ * @from: offset to read from
++ * @ops: oob operation description structure
++ *
++ * NAND read data and/or out-of-band data.
++ */
++static int nand_read_oob(struct mtd_info *mtd, loff_t from,
++			 struct mtd_oob_ops *ops)
++{
++	int ret;
++
++	ops->retlen = 0;
++
++	/* Do not allow reads past end of device */
++	if (ops->datbuf && (from + ops->len) > mtd->size) {
++		pr_debug("%s: attempt to read beyond end of device\n",
++				__func__);
++		return -EINVAL;
++	}
++
++	if (ops->mode != MTD_OPS_PLACE_OOB &&
++	    ops->mode != MTD_OPS_AUTO_OOB &&
++	    ops->mode != MTD_OPS_RAW)
++		return -ENOTSUPP;
++
++	nand_get_device(mtd, FL_READING);
++
++	if (!ops->datbuf)
++		ret = nand_do_read_oob(mtd, from, ops);
++	else
++		ret = nand_do_read_ops(mtd, from, ops);
++
++	nand_release_device(mtd);
++	return ret;
++}
++
++
++/**
++ * nand_write_page_raw - [INTERN] raw page write function
++ * @mtd: mtd info structure
++ * @chip: nand chip info structure
++ * @buf: data buffer
++ * @oob_required: must write chip->oob_poi to OOB
++ * @page: page number to write
++ *
++ * Not for syndrome calculating ECC controllers, which use a special oob layout.
++ */
++int nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
++			const uint8_t *buf, int oob_required, int page)
++{
++	chip->write_buf(mtd, buf, mtd->writesize);
++	if (oob_required)
++		chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
++
++	return 0;
++}
++EXPORT_SYMBOL(nand_write_page_raw);
++
++/**
++ * nand_write_page_raw_syndrome - [INTERN] raw page write function
++ * @mtd: mtd info structure
++ * @chip: nand chip info structure
++ * @buf: data buffer
++ * @oob_required: must write chip->oob_poi to OOB
++ * @page: page number to write
++ *
++ * We need a special oob layout and handling even when ECC isn't checked.
++ */
++static int nand_write_page_raw_syndrome(struct mtd_info *mtd,
++					struct nand_chip *chip,
++					const uint8_t *buf, int oob_required,
++					int page)
++{
++	int eccsize = chip->ecc.size;
++	int eccbytes = chip->ecc.bytes;
++	uint8_t *oob = chip->oob_poi;
++	int steps, size;
++
++	for (steps = chip->ecc.steps; steps > 0; steps--) {
++		chip->write_buf(mtd, buf, eccsize);
++		buf += eccsize;
++
++		if (chip->ecc.prepad) {
++			chip->write_buf(mtd, oob, chip->ecc.prepad);
++			oob += chip->ecc.prepad;
++		}
++
++		chip->write_buf(mtd, oob, eccbytes);
++		oob += eccbytes;
++
++		if (chip->ecc.postpad) {
++			chip->write_buf(mtd, oob, chip->ecc.postpad);
++			oob += chip->ecc.postpad;
++		}
++	}
++
++	size = mtd->oobsize - (oob - chip->oob_poi);
++	if (size)
++		chip->write_buf(mtd, oob, size);
++
++	return 0;
++}
++/**
++ * nand_write_page_swecc - [REPLACEABLE] software ECC based page write function
++ * @mtd: mtd info structure
++ * @chip: nand chip info structure
++ * @buf: data buffer
++ * @oob_required: must write chip->oob_poi to OOB
++ * @page: page number to write
++ */
++static int nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
++				 const uint8_t *buf, int oob_required,
++				 int page)
++{
++	int i, eccsize = chip->ecc.size, ret;
++	int eccbytes = chip->ecc.bytes;
++	int eccsteps = chip->ecc.steps;
++	uint8_t *ecc_calc = chip->buffers->ecccalc;
++	const uint8_t *p = buf;
++
++	/* Software ECC calculation */
++	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
++		chip->ecc.calculate(mtd, p, &ecc_calc[i]);
++
++	ret = mtd_ooblayout_set_eccbytes(mtd, ecc_calc, chip->oob_poi, 0,
++					 chip->ecc.total);
++	if (ret)
++		return ret;
++
++	return chip->ecc.write_page_raw(mtd, chip, buf, 1, page);
++}
++
++/**
++ * nand_write_page_hwecc - [REPLACEABLE] hardware ECC based page write function
++ * @mtd: mtd info structure
++ * @chip: nand chip info structure
++ * @buf: data buffer
++ * @oob_required: must write chip->oob_poi to OOB
++ * @page: page number to write
++ */
++static int nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
++				  const uint8_t *buf, int oob_required,
++				  int page)
++{
++	int i, eccsize = chip->ecc.size, ret;
++	int eccbytes = chip->ecc.bytes;
++	int eccsteps = chip->ecc.steps;
++	uint8_t *ecc_calc = chip->buffers->ecccalc;
++	const uint8_t *p = buf;
++
++	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
++		chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
++		chip->write_buf(mtd, p, eccsize);
++		chip->ecc.calculate(mtd, p, &ecc_calc[i]);
++	}
++
++	ret = mtd_ooblayout_set_eccbytes(mtd, ecc_calc, chip->oob_poi, 0,
++					 chip->ecc.total);
++	if (ret)
++		return ret;
++
++	chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
++
++	return 0;
++}
++
++
++/**
++ * nand_write_subpage_hwecc - [REPLACEABLE] hardware ECC based subpage write
++ * @mtd:	mtd info structure
++ * @chip:	nand chip info structure
++ * @offset:	column address of subpage within the page
++ * @data_len:	data length
++ * @buf:	data buffer
++ * @oob_required: must write chip->oob_poi to OOB
++ * @page: page number to write
++ */
++static int nand_write_subpage_hwecc(struct mtd_info *mtd,
++				struct nand_chip *chip, uint32_t offset,
++				uint32_t data_len, const uint8_t *buf,
++				int oob_required, int page)
++{
++	uint8_t *oob_buf  = chip->oob_poi;
++	uint8_t *ecc_calc = chip->buffers->ecccalc;
++	int ecc_size      = chip->ecc.size;
++	int ecc_bytes     = chip->ecc.bytes;
++	int ecc_steps     = chip->ecc.steps;
++	uint32_t start_step = offset / ecc_size;
++	uint32_t end_step   = (offset + data_len - 1) / ecc_size;
++	int oob_bytes       = mtd->oobsize / ecc_steps;
++	int step, ret;
++
++	for (step = 0; step < ecc_steps; step++) {
++		/* configure controller for WRITE access */
++		chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
++
++		/* write data (untouched subpages already masked by 0xFF) */
++		chip->write_buf(mtd, buf, ecc_size);
++
++		/* mask ECC of un-touched subpages by padding 0xFF */
++		if ((step < start_step) || (step > end_step))
++			memset(ecc_calc, 0xff, ecc_bytes);
++		else
++			chip->ecc.calculate(mtd, buf, ecc_calc);
++
++		/* mask OOB of un-touched subpages by padding 0xFF */
++		/* if oob_required, preserve OOB metadata of written subpage */
++		if (!oob_required || (step < start_step) || (step > end_step))
++			memset(oob_buf, 0xff, oob_bytes);
++
++		buf += ecc_size;
++		ecc_calc += ecc_bytes;
++		oob_buf  += oob_bytes;
++	}
++
++	/* copy calculated ECC for whole page to chip->buffer->oob */
++	/* this include masked-value(0xFF) for unwritten subpages */
++	ecc_calc = chip->buffers->ecccalc;
++	ret = mtd_ooblayout_set_eccbytes(mtd, ecc_calc, chip->oob_poi, 0,
++					 chip->ecc.total);
++	if (ret)
++		return ret;
++
++	/* write OOB buffer to NAND device */
++	chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
++
++	return 0;
++}
++
++
++/**
++ * nand_write_page_syndrome - [REPLACEABLE] hardware ECC syndrome based page write
++ * @mtd: mtd info structure
++ * @chip: nand chip info structure
++ * @buf: data buffer
++ * @oob_required: must write chip->oob_poi to OOB
++ * @page: page number to write
++ *
++ * The hw generator calculates the error syndrome automatically. Therefore we
++ * need a special oob layout and handling.
++ */
++static int nand_write_page_syndrome(struct mtd_info *mtd,
++				    struct nand_chip *chip,
++				    const uint8_t *buf, int oob_required,
++				    int page)
++{
++	int i, eccsize = chip->ecc.size;
++	int eccbytes = chip->ecc.bytes;
++	int eccsteps = chip->ecc.steps;
++	const uint8_t *p = buf;
++	uint8_t *oob = chip->oob_poi;
++
++	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
++
++		chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
++		chip->write_buf(mtd, p, eccsize);
++
++		if (chip->ecc.prepad) {
++			chip->write_buf(mtd, oob, chip->ecc.prepad);
++			oob += chip->ecc.prepad;
++		}
++
++		chip->ecc.calculate(mtd, p, oob);
++		chip->write_buf(mtd, oob, eccbytes);
++		oob += eccbytes;
++
++		if (chip->ecc.postpad) {
++			chip->write_buf(mtd, oob, chip->ecc.postpad);
++			oob += chip->ecc.postpad;
++		}
++	}
++
++	/* Calculate remaining oob bytes */
++	i = mtd->oobsize - (oob - chip->oob_poi);
++	if (i)
++		chip->write_buf(mtd, oob, i);
++
++	return 0;
++}
++
++/**
++ * nand_write_page - write one page
++ * @mtd: MTD device structure
++ * @chip: NAND chip descriptor
++ * @offset: address offset within the page
++ * @data_len: length of actual data to be written
++ * @buf: the data to write
++ * @oob_required: must write chip->oob_poi to OOB
++ * @page: page number to write
++ * @raw: use _raw version of write_page
++ */
++static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
++		uint32_t offset, int data_len, const uint8_t *buf,
++		int oob_required, int page, int raw)
++{
++	int status, subpage;
++
++	if (!(chip->options & NAND_NO_SUBPAGE_WRITE) &&
++		chip->ecc.write_subpage)
++		subpage = offset || (data_len < mtd->writesize);
++	else
++		subpage = 0;
++
++	if (nand_standard_page_accessors(&chip->ecc))
++		chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
++
++	if (unlikely(raw))
++		status = chip->ecc.write_page_raw(mtd, chip, buf,
++						  oob_required, page);
++	else if (subpage)
++		status = chip->ecc.write_subpage(mtd, chip, offset, data_len,
++						 buf, oob_required, page);
++	else
++		status = chip->ecc.write_page(mtd, chip, buf, oob_required,
++					      page);
++
++	if (status < 0)
++		return status;
++
++	if (nand_standard_page_accessors(&chip->ecc)) {
++		chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
++
++		status = chip->waitfunc(mtd, chip);
++		if (status & NAND_STATUS_FAIL)
++			return -EIO;
++	}
++
++	return 0;
++}
++
++/**
++ * nand_fill_oob - [INTERN] Transfer client buffer to oob
++ * @mtd: MTD device structure
++ * @oob: oob data buffer
++ * @len: oob data write length
++ * @ops: oob ops structure
++ */
++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);
++	int ret;
++
++	/*
++	 * Initialise to all 0xFF, to avoid the possibility of left over OOB
++	 * data from a previous OOB read.
++	 */
++	memset(chip->oob_poi, 0xff, mtd->oobsize);
++
++	switch (ops->mode) {
++
++	case MTD_OPS_PLACE_OOB:
++	case MTD_OPS_RAW:
++		memcpy(chip->oob_poi + ops->ooboffs, oob, len);
++		return oob + len;
++
++	case MTD_OPS_AUTO_OOB:
++		ret = mtd_ooblayout_set_databytes(mtd, oob, chip->oob_poi,
++						  ops->ooboffs, len);
++		BUG_ON(ret);
++		return oob + len;
++
++	default:
++		BUG();
++	}
++	return NULL;
++}
++
++#define NOTALIGNED(x)	((x & (chip->subpagesize - 1)) != 0)
++
++/**
++ * nand_do_write_ops - [INTERN] NAND write with ECC
++ * @mtd: MTD device structure
++ * @to: offset to write to
++ * @ops: oob operations description structure
++ *
++ * NAND write with ECC.
++ */
++static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
++			     struct mtd_oob_ops *ops)
++{
++	int chipnr, realpage, page, column;
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	uint32_t writelen = ops->len;
++
++	uint32_t oobwritelen = ops->ooblen;
++	uint32_t oobmaxlen = mtd_oobavail(mtd, ops);
++
++	uint8_t *oob = ops->oobbuf;
++	uint8_t *buf = ops->datbuf;
++	int ret;
++	int oob_required = oob ? 1 : 0;
++
++	ops->retlen = 0;
++	if (!writelen)
++		return 0;
++
++	/* Reject writes, which are not page aligned */
++	if (NOTALIGNED(to) || NOTALIGNED(ops->len)) {
++		pr_notice("%s: attempt to write non page aligned data\n",
++			   __func__);
++		return -EINVAL;
++	}
++
++	column = to & (mtd->writesize - 1);
++
++	chipnr = (int)(to >> chip->chip_shift);
++	chip->select_chip(mtd, chipnr);
++
++	/* Check, if it is write protected */
++	if (nand_check_wp(mtd)) {
++		ret = -EIO;
++		goto err_out;
++	}
++
++	realpage = (int)(to >> chip->page_shift);
++	page = realpage & chip->pagemask;
++
++	/* Invalidate the page cache, when we write to the cached page */
++	if (to <= ((loff_t)chip->pagebuf << chip->page_shift) &&
++	    ((loff_t)chip->pagebuf << chip->page_shift) < (to + ops->len))
++		chip->pagebuf = -1;
++
++	/* Don't allow multipage oob writes with offset */
++	if (oob && ops->ooboffs && (ops->ooboffs + ops->ooblen > oobmaxlen)) {
++		ret = -EINVAL;
++		goto err_out;
++	}
++
++	while (1) {
++		int bytes = mtd->writesize;
++		uint8_t *wbuf = buf;
++		int use_bufpoi;
++		int part_pagewr = (column || writelen < mtd->writesize);
++
++		if (part_pagewr)
++			use_bufpoi = 1;
++		else if (chip->options & NAND_USE_BOUNCE_BUFFER)
++			use_bufpoi = !virt_addr_valid(buf) ||
++				     !IS_ALIGNED((unsigned long)buf,
++						 chip->buf_align);
++		else
++			use_bufpoi = 0;
++
++		/* Partial page write?, or need to use bounce buffer */
++		if (use_bufpoi) {
++			pr_debug("%s: using write bounce buffer for buf@%p\n",
++					 __func__, buf);
++			if (part_pagewr)
++				bytes = min_t(int, bytes - column, writelen);
++			chip->pagebuf = -1;
++			memset(chip->buffers->databuf, 0xff, mtd->writesize);
++			memcpy(&chip->buffers->databuf[column], buf, bytes);
++			wbuf = chip->buffers->databuf;
++		}
++
++		if (unlikely(oob)) {
++			size_t len = min(oobwritelen, oobmaxlen);
++			oob = nand_fill_oob(mtd, oob, len, ops);
++			oobwritelen -= len;
++		} else {
++			/* We still need to erase leftover OOB data */
++			memset(chip->oob_poi, 0xff, mtd->oobsize);
++		}
++
++		ret = nand_write_page(mtd, chip, column, bytes, wbuf,
++				      oob_required, page,
++				      (ops->mode == MTD_OPS_RAW));
++		if (ret)
++			break;
++
++		writelen -= bytes;
++		if (!writelen)
++			break;
++
++		column = 0;
++		buf += bytes;
++		realpage++;
++
++		page = realpage & chip->pagemask;
++		/* Check, if we cross a chip boundary */
++		if (!page) {
++			chipnr++;
++			chip->select_chip(mtd, -1);
++			chip->select_chip(mtd, chipnr);
++		}
++	}
++
++	ops->retlen = ops->len - writelen;
++	if (unlikely(oob))
++		ops->oobretlen = ops->ooblen;
++
++err_out:
++	chip->select_chip(mtd, -1);
++	return ret;
++}
++
++/**
++ * panic_nand_write - [MTD Interface] NAND write with ECC
++ * @mtd: MTD device structure
++ * @to: offset to write to
++ * @len: number of bytes to write
++ * @retlen: pointer to variable to store the number of written bytes
++ * @buf: the data to write
++ *
++ * NAND write with ECC. Used when performing writes in interrupt context, this
++ * may for example be called by mtdoops when writing an oops while in panic.
++ */
++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);
++	int chipnr = (int)(to >> chip->chip_shift);
++	struct mtd_oob_ops ops;
++	int ret;
++
++	/* Grab the device */
++	panic_nand_get_device(chip, mtd, FL_WRITING);
++
++	chip->select_chip(mtd, chipnr);
++
++	/* Wait for the device to get ready */
++	panic_nand_wait(mtd, chip, 400);
++
++	memset(&ops, 0, sizeof(ops));
++	ops.len = len;
++	ops.datbuf = (uint8_t *)buf;
++	ops.mode = MTD_OPS_PLACE_OOB;
++
++	ret = nand_do_write_ops(mtd, to, &ops);
++
++	*retlen = ops.retlen;
++	return ret;
++}
++
++/**
++ * nand_do_write_oob - [MTD Interface] NAND write out-of-band
++ * @mtd: MTD device structure
++ * @to: offset to write to
++ * @ops: oob operation description structure
++ *
++ * NAND write out-of-band.
++ */
++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);
++
++	pr_debug("%s: to = 0x%08x, len = %i\n",
++			 __func__, (unsigned int)to, (int)ops->ooblen);
++
++	len = mtd_oobavail(mtd, ops);
++
++	/* Do not allow write past end of page */
++	if ((ops->ooboffs + ops->ooblen) > len) {
++		pr_debug("%s: attempt to write past end of page\n",
++				__func__);
++		return -EINVAL;
++	}
++
++	if (unlikely(ops->ooboffs >= len)) {
++		pr_debug("%s: attempt to start write outside oob\n",
++				__func__);
++		return -EINVAL;
++	}
++
++	/* Do not allow write past end of device */
++	if (unlikely(to >= mtd->size ||
++		     ops->ooboffs + ops->ooblen >
++			((mtd->size >> chip->page_shift) -
++			 (to >> chip->page_shift)) * len)) {
++		pr_debug("%s: attempt to write beyond end of device\n",
++				__func__);
++		return -EINVAL;
++	}
++
++	chipnr = (int)(to >> chip->chip_shift);
++
++	/*
++	 * Reset the chip. Some chips (like the Toshiba TC5832DC found in one
++	 * of my DiskOnChip 2000 test units) will clear the whole data page too
++	 * 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, 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)) {
++		chip->select_chip(mtd, -1);
++		return -EROFS;
++	}
++
++	/* Invalidate the page cache, if we write to the cached page */
++	if (page == chip->pagebuf)
++		chip->pagebuf = -1;
++
++	nand_fill_oob(mtd, ops->oobbuf, ops->ooblen, ops);
++
++	if (ops->mode == MTD_OPS_RAW)
++		status = chip->ecc.write_oob_raw(mtd, chip, page & chip->pagemask);
++	else
++		status = chip->ecc.write_oob(mtd, chip, page & chip->pagemask);
++
++	chip->select_chip(mtd, -1);
++
++	if (status)
++		return status;
++
++	ops->oobretlen = ops->ooblen;
++
++	return 0;
++}
++
++/**
++ * nand_write_oob - [MTD Interface] NAND write data and/or out-of-band
++ * @mtd: MTD device structure
++ * @to: offset to write to
++ * @ops: oob operation description structure
++ */
++static int nand_write_oob(struct mtd_info *mtd, loff_t to,
++			  struct mtd_oob_ops *ops)
++{
++	int ret = -ENOTSUPP;
++
++	ops->retlen = 0;
++
++	/* Do not allow writes past end of device */
++	if (ops->datbuf && (to + ops->len) > mtd->size) {
++		pr_debug("%s: attempt to write beyond end of device\n",
++				__func__);
++		return -EINVAL;
++	}
++
++	nand_get_device(mtd, FL_WRITING);
++
++	switch (ops->mode) {
++	case MTD_OPS_PLACE_OOB:
++	case MTD_OPS_AUTO_OOB:
++	case MTD_OPS_RAW:
++		break;
++
++	default:
++		goto out;
++	}
++
++	if (!ops->datbuf)
++		ret = nand_do_write_oob(mtd, to, ops);
++	else
++		ret = nand_do_write_ops(mtd, to, ops);
++
++out:
++	nand_release_device(mtd);
++	return ret;
++}
++
++/**
++ * single_erase - [GENERIC] NAND standard block erase command function
++ * @mtd: MTD device structure
++ * @page: the page address of the block which will be erased
++ *
++ * Standard erase command for NAND chips. Returns NAND status.
++ */
++static int single_erase(struct mtd_info *mtd, int page)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	/* Send commands to erase a block */
++	chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page);
++	chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1);
++
++	return chip->waitfunc(mtd, chip);
++}
++
++/**
++ * nand_erase - [MTD Interface] erase block(s)
++ * @mtd: MTD device structure
++ * @instr: erase instruction
++ *
++ * Erase one ore more blocks.
++ */
++static int nand_erase(struct mtd_info *mtd, struct erase_info *instr)
++{
++	return nand_erase_nand(mtd, instr, 0);
++}
++
++/**
++ * nand_erase_nand - [INTERN] erase block(s)
++ * @mtd: MTD device structure
++ * @instr: erase instruction
++ * @allowbbt: allow erasing the bbt area
++ *
++ * Erase one ore more blocks.
++ */
++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);
++	loff_t len;
++
++	pr_debug("%s: start = 0x%012llx, len = %llu\n",
++			__func__, (unsigned long long)instr->addr,
++			(unsigned long long)instr->len);
++
++	if (check_offs_len(mtd, instr->addr, instr->len))
++		return -EINVAL;
++
++	/* Grab the lock and see if the device is available */
++	nand_get_device(mtd, FL_ERASING);
++
++	/* Shift to get first page */
++	page = (int)(instr->addr >> chip->page_shift);
++	chipnr = (int)(instr->addr >> chip->chip_shift);
++
++	/* Calculate pages in each block */
++	pages_per_block = 1 << (chip->phys_erase_shift - chip->page_shift);
++
++	/* Select the NAND device */
++	chip->select_chip(mtd, chipnr);
++
++	/* Check, if it is write protected */
++	if (nand_check_wp(mtd)) {
++		pr_debug("%s: device is write protected!\n",
++				__func__);
++		instr->state = MTD_ERASE_FAILED;
++		goto erase_exit;
++	}
++
++	/* Loop through the pages */
++	len = instr->len;
++
++	instr->state = MTD_ERASING;
++
++	while (len) {
++		/* Check if we have a bad block, we do not erase bad blocks! */
++		if (nand_block_checkbad(mtd, ((loff_t) page) <<
++					chip->page_shift, allowbbt)) {
++			pr_warn("%s: attempt to erase a bad block at page 0x%08x\n",
++				    __func__, page);
++			instr->state = MTD_ERASE_FAILED;
++			goto erase_exit;
++		}
++
++		/*
++		 * Invalidate the page cache, if we erase the block which
++		 * contains the current cached page.
++		 */
++		if (page <= chip->pagebuf && chip->pagebuf <
++		    (page + pages_per_block))
++			chip->pagebuf = -1;
++
++		status = chip->erase(mtd, page & chip->pagemask);
++
++		/* See if block erase succeeded */
++		if (status & NAND_STATUS_FAIL) {
++			pr_debug("%s: failed erase, page 0x%08x\n",
++					__func__, page);
++			instr->state = MTD_ERASE_FAILED;
++			instr->fail_addr =
++				((loff_t)page << chip->page_shift);
++			goto erase_exit;
++		}
++
++		/* Increment page address and decrement length */
++		len -= (1ULL << chip->phys_erase_shift);
++		page += pages_per_block;
++
++		/* Check, if we cross a chip boundary */
++		if (len && !(page & chip->pagemask)) {
++			chipnr++;
++			chip->select_chip(mtd, -1);
++			chip->select_chip(mtd, chipnr);
++		}
++	}
++	instr->state = MTD_ERASE_DONE;
++
++erase_exit:
++
++	ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO;
++
++	/* Deselect and wake up anyone waiting on the device */
++	chip->select_chip(mtd, -1);
++	nand_release_device(mtd);
++
++	/* Do call back function */
++	if (!ret)
++		mtd_erase_callback(instr);
++
++	/* Return more or less happy */
++	return ret;
++}
++
++/**
++ * nand_sync - [MTD Interface] sync
++ * @mtd: MTD device structure
++ *
++ * Sync is actually a wait for chip ready function.
++ */
++static void nand_sync(struct mtd_info *mtd)
++{
++	pr_debug("%s: called\n", __func__);
++
++	/* Grab the lock and see if the device is available */
++	nand_get_device(mtd, FL_SYNCING);
++	/* Release it and go back */
++	nand_release_device(mtd);
++}
++
++/**
++ * nand_block_isbad - [MTD Interface] Check if block at offset is bad
++ * @mtd: MTD device structure
++ * @offs: offset relative to mtd start
++ */
++static int nand_block_isbad(struct mtd_info *mtd, loff_t offs)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	int chipnr = (int)(offs >> chip->chip_shift);
++	int ret;
++
++	/* Select the NAND device */
++	nand_get_device(mtd, FL_READING);
++	chip->select_chip(mtd, chipnr);
++
++	ret = nand_block_checkbad(mtd, offs, 0);
++
++	chip->select_chip(mtd, -1);
++	nand_release_device(mtd);
++
++	return ret;
++}
++
++/**
++ * nand_block_markbad - [MTD Interface] Mark block at the given offset as bad
++ * @mtd: MTD device structure
++ * @ofs: offset relative to mtd start
++ */
++static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs)
++{
++	int ret;
++
++	ret = nand_block_isbad(mtd, ofs);
++	if (ret) {
++		/* If it was bad already, return success and do nothing */
++		if (ret > 0)
++			return 0;
++		return ret;
++	}
++
++	return nand_block_markbad_lowlevel(mtd, 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);
++	u32 part_start_block;
++	u32 part_end_block;
++	u32 part_start_die;
++	u32 part_end_die;
++
++	/*
++	 * max_bb_per_die and blocks_per_die used to determine
++	 * the maximum bad block count.
++	 */
++	if (!chip->max_bb_per_die || !chip->blocks_per_die)
++		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_die = part_start_block / chip->blocks_per_die;
++	part_end_die = part_end_block / chip->blocks_per_die;
++
++	/*
++	 * Look up the bad blocks per unit and multiply by the number of units
++	 * that the partition spans.
++	 */
++	return chip->max_bb_per_die * (part_end_die - part_start_die + 1);
++}
++
++/**
++ * nand_onfi_set_features- [REPLACEABLE] set features for ONFI nand
++ * @mtd: MTD device structure
++ * @chip: nand chip info structure
++ * @addr: feature address.
++ * @subfeature_param: the subfeature parameters, a four bytes array.
++ */
++static int nand_onfi_set_features(struct mtd_info *mtd, struct nand_chip *chip,
++			int addr, uint8_t *subfeature_param)
++{
++	int status;
++	int i;
++
++	if (!chip->onfi_version ||
++	    !(le16_to_cpu(chip->onfi_params.opt_cmd)
++	      & ONFI_OPT_CMD_SET_GET_FEATURES))
++		return -EINVAL;
++
++	chip->cmdfunc(mtd, NAND_CMD_SET_FEATURES, addr, -1);
++	for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
++		chip->write_byte(mtd, subfeature_param[i]);
++
++	status = chip->waitfunc(mtd, chip);
++	if (status & NAND_STATUS_FAIL)
++		return -EIO;
++	return 0;
++}
++
++/**
++ * nand_onfi_get_features- [REPLACEABLE] get features for ONFI nand
++ * @mtd: MTD device structure
++ * @chip: nand chip info structure
++ * @addr: feature address.
++ * @subfeature_param: the subfeature parameters, a four bytes array.
++ */
++static int nand_onfi_get_features(struct mtd_info *mtd, struct nand_chip *chip,
++			int addr, uint8_t *subfeature_param)
++{
++	int i;
++
++	if (!chip->onfi_version ||
++	    !(le16_to_cpu(chip->onfi_params.opt_cmd)
++	      & ONFI_OPT_CMD_SET_GET_FEATURES))
++		return -EINVAL;
++
++	chip->cmdfunc(mtd, NAND_CMD_GET_FEATURES, addr, -1);
++	for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
++		*subfeature_param++ = chip->read_byte(mtd);
++	return 0;
++}
++
++/**
++ * nand_onfi_get_set_features_notsupp - set/get features stub returning
++ *					-ENOTSUPP
++ * @mtd: MTD device structure
++ * @chip: nand chip info structure
++ * @addr: feature address.
++ * @subfeature_param: the subfeature parameters, a four bytes array.
++ *
++ * Should be used by NAND controller drivers that do not support the SET/GET
++ * FEATURES operations.
++ */
++int nand_onfi_get_set_features_notsupp(struct mtd_info *mtd,
++				       struct nand_chip *chip, int addr,
++				       u8 *subfeature_param)
++{
++	return -ENOTSUPP;
++}
++EXPORT_SYMBOL(nand_onfi_get_set_features_notsupp);
++
++/**
++ * nand_suspend - [MTD Interface] Suspend the NAND flash
++ * @mtd: MTD device structure
++ */
++static int nand_suspend(struct mtd_info *mtd)
++{
++	return nand_get_device(mtd, FL_PM_SUSPENDED);
++}
++
++/**
++ * nand_resume - [MTD Interface] Resume the NAND flash
++ * @mtd: MTD device structure
++ */
++static void nand_resume(struct mtd_info *mtd)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++
++	if (chip->state == FL_PM_SUSPENDED)
++		nand_release_device(mtd);
++	else
++		pr_err("%s called for a chip which is not in suspended state\n",
++			__func__);
++}
++
++/**
++ * nand_shutdown - [MTD Interface] Finish the current NAND operation and
++ *                 prevent further operations
++ * @mtd: MTD device structure
++ */
++static void nand_shutdown(struct mtd_info *mtd)
++{
++	nand_get_device(mtd, FL_PM_SUSPENDED);
++}
++
++/* Set default functions */
++static void nand_set_defaults(struct nand_chip *chip)
++{
++	unsigned int busw = chip->options & NAND_BUSWIDTH_16;
++
++	/* check for proper chip_delay setup, set 20us if not */
++	if (!chip->chip_delay)
++		chip->chip_delay = 20;
++
++	/* check, if a user supplied command function given */
++	if (chip->cmdfunc == NULL)
++		chip->cmdfunc = nand_command;
++
++	/* check, if a user supplied wait function given */
++	if (chip->waitfunc == NULL)
++		chip->waitfunc = nand_wait;
++
++	if (!chip->select_chip)
++		chip->select_chip = nand_select_chip;
++
++	/* set for ONFI nand */
++	if (!chip->onfi_set_features)
++		chip->onfi_set_features = nand_onfi_set_features;
++	if (!chip->onfi_get_features)
++		chip->onfi_get_features = nand_onfi_get_features;
++
++	/* If called twice, pointers that depend on busw may need to be reset */
++	if (!chip->read_byte || chip->read_byte == nand_read_byte)
++		chip->read_byte = busw ? nand_read_byte16 : nand_read_byte;
++	if (!chip->read_word)
++		chip->read_word = nand_read_word;
++	if (!chip->block_bad)
++		chip->block_bad = nand_block_bad;
++	if (!chip->block_markbad)
++		chip->block_markbad = nand_default_block_markbad;
++	if (!chip->write_buf || chip->write_buf == nand_write_buf)
++		chip->write_buf = busw ? nand_write_buf16 : nand_write_buf;
++	if (!chip->write_byte || chip->write_byte == nand_write_byte)
++		chip->write_byte = busw ? nand_write_byte16 : nand_write_byte;
++	if (!chip->read_buf || chip->read_buf == nand_read_buf)
++		chip->read_buf = busw ? nand_read_buf16 : nand_read_buf;
++	if (!chip->scan_bbt)
++		chip->scan_bbt = nand_default_bbt;
++
++	if (!chip->controller) {
++		chip->controller = &chip->hwcontrol;
++		nand_hw_control_init(chip->controller);
++	}
++
++	if (!chip->buf_align)
++		chip->buf_align = 1;
++}
++
++/* Sanitize ONFI strings so we can safely print them */
++static void sanitize_string(uint8_t *s, size_t len)
++{
++	ssize_t i;
++
++	/* Null terminate */
++	s[len - 1] = 0;
++
++	/* Remove non printable chars */
++	for (i = 0; i < len - 1; i++) {
++		if (s[i] < ' ' || s[i] > 127)
++			s[i] = '?';
++	}
++
++	/* Remove trailing spaces */
++	strim(s);
++}
++
++static u16 onfi_crc16(u16 crc, u8 const *p, size_t len)
++{
++	int i;
++	while (len--) {
++		crc ^= *p++ << 8;
++		for (i = 0; i < 8; i++)
++			crc = (crc << 1) ^ ((crc & 0x8000) ? 0x8005 : 0);
++	}
++
++	return crc;
++}
++
++/* Parse the Extended Parameter Page. */
++static int nand_flash_detect_ext_param_page(struct nand_chip *chip,
++					    struct nand_onfi_params *p)
++{
++	struct mtd_info *mtd = nand_to_mtd(chip);
++	struct onfi_ext_param_page *ep;
++	struct onfi_ext_section *s;
++	struct onfi_ext_ecc_info *ecc;
++	uint8_t *cursor;
++	int ret = -EINVAL;
++	int len;
++	int i;
++
++	len = le16_to_cpu(p->ext_param_page_length) * 16;
++	ep = kmalloc(len, GFP_KERNEL);
++	if (!ep)
++		return -ENOMEM;
++
++	/* Send our own NAND_CMD_PARAM. */
++	chip->cmdfunc(mtd, NAND_CMD_PARAM, 0, -1);
++
++	/* Use the Change Read Column command to skip the ONFI param pages. */
++	chip->cmdfunc(mtd, NAND_CMD_RNDOUT,
++			sizeof(*p) * p->num_of_param_pages , -1);
++
++	/* Read out the Extended Parameter Page. */
++	chip->read_buf(mtd, (uint8_t *)ep, len);
++	if ((onfi_crc16(ONFI_CRC_BASE, ((uint8_t *)ep) + 2, len - 2)
++		!= le16_to_cpu(ep->crc))) {
++		pr_debug("fail in the CRC.\n");
++		goto ext_out;
++	}
++
++	/*
++	 * Check the signature.
++	 * Do not strictly follow the ONFI spec, maybe changed in future.
++	 */
++	if (strncmp(ep->sig, "EPPS", 4)) {
++		pr_debug("The signature is invalid.\n");
++		goto ext_out;
++	}
++
++	/* find the ECC section. */
++	cursor = (uint8_t *)(ep + 1);
++	for (i = 0; i < ONFI_EXT_SECTION_MAX; i++) {
++		s = ep->sections + i;
++		if (s->type == ONFI_SECTION_TYPE_2)
++			break;
++		cursor += s->length * 16;
++	}
++	if (i == ONFI_EXT_SECTION_MAX) {
++		pr_debug("We can not find the ECC section.\n");
++		goto ext_out;
++	}
++
++	/* get the info we want. */
++	ecc = (struct onfi_ext_ecc_info *)cursor;
++
++	if (!ecc->codeword_size) {
++		pr_debug("Invalid codeword size\n");
++		goto ext_out;
++	}
++
++	chip->ecc_strength_ds = ecc->ecc_bits;
++	chip->ecc_step_ds = 1 << ecc->codeword_size;
++	ret = 0;
++
++ext_out:
++	kfree(ep);
++	return ret;
++}
++
++/*
++ * Check if the NAND chip is ONFI compliant, returns 1 if it is, 0 otherwise.
++ */
++static int nand_flash_detect_onfi(struct nand_chip *chip)
++{
++	struct mtd_info *mtd = nand_to_mtd(chip);
++	struct nand_onfi_params *p = &chip->onfi_params;
++	int i, j;
++	int val;
++
++	/* Try ONFI for unknown chip or LP */
++	chip->cmdfunc(mtd, NAND_CMD_READID, 0x20, -1);
++	if (chip->read_byte(mtd) != 'O' || chip->read_byte(mtd) != 'N' ||
++		chip->read_byte(mtd) != 'F' || chip->read_byte(mtd) != 'I')
++		return 0;
++
++	chip->cmdfunc(mtd, NAND_CMD_PARAM, 0, -1);
++	for (i = 0; i < 3; i++) {
++		for (j = 0; j < sizeof(*p); j++)
++			((uint8_t *)p)[j] = chip->read_byte(mtd);
++		if (onfi_crc16(ONFI_CRC_BASE, (uint8_t *)p, 254) ==
++				le16_to_cpu(p->crc)) {
++			break;
++		}
++	}
++
++	if (i == 3) {
++		pr_err("Could not find valid ONFI parameter page; aborting\n");
++		return 0;
++	}
++
++	/* Check version */
++	val = le16_to_cpu(p->revision);
++	if (val & (1 << 5))
++		chip->onfi_version = 23;
++	else if (val & (1 << 4))
++		chip->onfi_version = 22;
++	else if (val & (1 << 3))
++		chip->onfi_version = 21;
++	else if (val & (1 << 2))
++		chip->onfi_version = 20;
++	else if (val & (1 << 1))
++		chip->onfi_version = 10;
++
++	if (!chip->onfi_version) {
++		pr_info("unsupported ONFI version: %d\n", val);
++		return 0;
++	}
++
++	sanitize_string(p->manufacturer, sizeof(p->manufacturer));
++	sanitize_string(p->model, sizeof(p->model));
++	if (!mtd->name)
++		mtd->name = p->model;
++
++	mtd->writesize = le32_to_cpu(p->byte_per_page);
++
++	/*
++	 * pages_per_block and blocks_per_lun may not be a power-of-2 size
++	 * (don't ask me who thought of this...). MTD assumes that these
++	 * dimensions will be power-of-2, so just truncate the remaining area.
++	 */
++	mtd->erasesize = 1 << (fls(le32_to_cpu(p->pages_per_block)) - 1);
++	mtd->erasesize *= mtd->writesize;
++
++	mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page);
++
++	/* See erasesize comment */
++	chip->chipsize = 1 << (fls(le32_to_cpu(p->blocks_per_lun)) - 1);
++	chip->chipsize *= (uint64_t)mtd->erasesize * p->lun_count;
++	chip->bits_per_cell = p->bits_per_cell;
++
++	chip->max_bb_per_die = le16_to_cpu(p->bb_per_lun);
++	chip->blocks_per_die = le32_to_cpu(p->blocks_per_lun);
++
++	if (onfi_feature(chip) & ONFI_FEATURE_16_BIT_BUS)
++		chip->options |= NAND_BUSWIDTH_16;
++
++	if (p->ecc_bits != 0xff) {
++		chip->ecc_strength_ds = p->ecc_bits;
++		chip->ecc_step_ds = 512;
++	} else if (chip->onfi_version >= 21 &&
++		(onfi_feature(chip) & ONFI_FEATURE_EXT_PARAM_PAGE)) {
++
++		/*
++		 * The nand_flash_detect_ext_param_page() uses the
++		 * Change Read Column command which maybe not supported
++		 * by the chip->cmdfunc. So try to update the chip->cmdfunc
++		 * now. We do not replace user supplied command function.
++		 */
++		if (mtd->writesize > 512 && chip->cmdfunc == nand_command)
++			chip->cmdfunc = nand_command_lp;
++
++		/* The Extended Parameter Page is supported since ONFI 2.1. */
++		if (nand_flash_detect_ext_param_page(chip, p))
++			pr_warn("Failed to detect ONFI extended param page\n");
++	} else {
++		pr_warn("Could not retrieve ONFI ECC requirements\n");
++	}
++
++	return 1;
++}
++
++/*
++ * Check if the NAND chip is JEDEC compliant, returns 1 if it is, 0 otherwise.
++ */
++static int nand_flash_detect_jedec(struct nand_chip *chip)
++{
++	struct mtd_info *mtd = nand_to_mtd(chip);
++	struct nand_jedec_params *p = &chip->jedec_params;
++	struct jedec_ecc_info *ecc;
++	int val;
++	int i, j;
++
++	/* Try JEDEC for unknown chip or LP */
++	chip->cmdfunc(mtd, NAND_CMD_READID, 0x40, -1);
++	if (chip->read_byte(mtd) != 'J' || chip->read_byte(mtd) != 'E' ||
++		chip->read_byte(mtd) != 'D' || chip->read_byte(mtd) != 'E' ||
++		chip->read_byte(mtd) != 'C')
++		return 0;
++
++	chip->cmdfunc(mtd, NAND_CMD_PARAM, 0x40, -1);
++	for (i = 0; i < 3; i++) {
++		for (j = 0; j < sizeof(*p); j++)
++			((uint8_t *)p)[j] = chip->read_byte(mtd);
++
++		if (onfi_crc16(ONFI_CRC_BASE, (uint8_t *)p, 510) ==
++				le16_to_cpu(p->crc))
++			break;
++	}
++
++	if (i == 3) {
++		pr_err("Could not find valid JEDEC parameter page; aborting\n");
++		return 0;
++	}
++
++	/* Check version */
++	val = le16_to_cpu(p->revision);
++	if (val & (1 << 2))
++		chip->jedec_version = 10;
++	else if (val & (1 << 1))
++		chip->jedec_version = 1; /* vendor specific version */
++
++	if (!chip->jedec_version) {
++		pr_info("unsupported JEDEC version: %d\n", val);
++		return 0;
++	}
++
++	sanitize_string(p->manufacturer, sizeof(p->manufacturer));
++	sanitize_string(p->model, sizeof(p->model));
++	if (!mtd->name)
++		mtd->name = p->model;
++
++	mtd->writesize = le32_to_cpu(p->byte_per_page);
++
++	/* Please reference to the comment for nand_flash_detect_onfi. */
++	mtd->erasesize = 1 << (fls(le32_to_cpu(p->pages_per_block)) - 1);
++	mtd->erasesize *= mtd->writesize;
++
++	mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page);
++
++	/* Please reference to the comment for nand_flash_detect_onfi. */
++	chip->chipsize = 1 << (fls(le32_to_cpu(p->blocks_per_lun)) - 1);
++	chip->chipsize *= (uint64_t)mtd->erasesize * p->lun_count;
++	chip->bits_per_cell = p->bits_per_cell;
++
++	if (jedec_feature(chip) & JEDEC_FEATURE_16_BIT_BUS)
++		chip->options |= NAND_BUSWIDTH_16;
++
++	/* ECC info */
++	ecc = &p->ecc_info[0];
++
++	if (ecc->codeword_size >= 9) {
++		chip->ecc_strength_ds = ecc->ecc_bits;
++		chip->ecc_step_ds = 1 << ecc->codeword_size;
++	} else {
++		pr_warn("Invalid codeword size\n");
++	}
++
++	return 1;
++}
++
++/*
++ * nand_id_has_period - Check if an ID string has a given wraparound period
++ * @id_data: the ID string
++ * @arrlen: the length of the @id_data array
++ * @period: the period of repitition
++ *
++ * Check if an ID string is repeated within a given sequence of bytes at
++ * specific repetition interval period (e.g., {0x20,0x01,0x7F,0x20} has a
++ * period of 3). This is a helper function for nand_id_len(). Returns non-zero
++ * if the repetition has a period of @period; otherwise, returns zero.
++ */
++static int nand_id_has_period(u8 *id_data, int arrlen, int period)
++{
++	int i, j;
++	for (i = 0; i < period; i++)
++		for (j = i + period; j < arrlen; j += period)
++			if (id_data[i] != id_data[j])
++				return 0;
++	return 1;
++}
++
++/*
++ * nand_id_len - Get the length of an ID string returned by CMD_READID
++ * @id_data: the ID string
++ * @arrlen: the length of the @id_data array
++
++ * Returns the length of the ID string, according to known wraparound/trailing
++ * zero patterns. If no pattern exists, returns the length of the array.
++ */
++static int nand_id_len(u8 *id_data, int arrlen)
++{
++	int last_nonzero, period;
++
++	/* Find last non-zero byte */
++	for (last_nonzero = arrlen - 1; last_nonzero >= 0; last_nonzero--)
++		if (id_data[last_nonzero])
++			break;
++
++	/* All zeros */
++	if (last_nonzero < 0)
++		return 0;
++
++	/* Calculate wraparound period */
++	for (period = 1; period < arrlen; period++)
++		if (nand_id_has_period(id_data, arrlen, period))
++			break;
++
++	/* There's a repeated pattern */
++	if (period < arrlen)
++		return period;
++
++	/* There are trailing zeros */
++	if (last_nonzero < arrlen - 1)
++		return last_nonzero + 1;
++
++	/* No pattern detected */
++	return arrlen;
++}
++
++/* Extract the bits of per cell from the 3rd byte of the extended ID */
++static int nand_get_bits_per_cell(u8 cellinfo)
++{
++	int bits;
++
++	bits = cellinfo & NAND_CI_CELLTYPE_MSK;
++	bits >>= NAND_CI_CELLTYPE_SHIFT;
++	return bits + 1;
++}
++
++/*
++ * Many new NAND share similar device ID codes, which represent the size of the
++ * chip. The rest of the parameters must be decoded according to generic or
++ * manufacturer-specific "extended ID" decoding patterns.
++ */
++void nand_decode_ext_id(struct nand_chip *chip)
++{
++	struct mtd_info *mtd = nand_to_mtd(chip);
++	int extid;
++	u8 *id_data = chip->id.data;
++	/* The 3rd id byte holds MLC / multichip data */
++	chip->bits_per_cell = nand_get_bits_per_cell(id_data[2]);
++	/* The 4th id byte is the important one */
++	extid = id_data[3];
++
++	/* Calc pagesize */
++	mtd->writesize = 1024 << (extid & 0x03);
++	extid >>= 2;
++	/* Calc oobsize */
++	mtd->oobsize = (8 << (extid & 0x01)) * (mtd->writesize >> 9);
++	extid >>= 2;
++	/* Calc blocksize. Blocksize is multiples of 64KiB */
++	mtd->erasesize = (64 * 1024) << (extid & 0x03);
++	extid >>= 2;
++	/* Get buswidth information */
++	if (extid & 0x1)
++		chip->options |= NAND_BUSWIDTH_16;
++}
++EXPORT_SYMBOL_GPL(nand_decode_ext_id);
++
++/*
++ * Old devices have chip data hardcoded in the device ID table. nand_decode_id
++ * decodes a matching ID table entry and assigns the MTD size parameters for
++ * the chip.
++ */
++static void nand_decode_id(struct nand_chip *chip, struct nand_flash_dev *type)
++{
++	struct mtd_info *mtd = nand_to_mtd(chip);
++
++	mtd->erasesize = type->erasesize;
++	mtd->writesize = type->pagesize;
++	mtd->oobsize = mtd->writesize / 32;
++
++	/* All legacy ID NAND are small-page, SLC */
++	chip->bits_per_cell = 1;
++}
++
++/*
++ * Set the bad block marker/indicator (BBM/BBI) patterns according to some
++ * heuristic patterns using various detected parameters (e.g., manufacturer,
++ * page size, cell-type information).
++ */
++static void nand_decode_bbm_options(struct nand_chip *chip)
++{
++	struct mtd_info *mtd = nand_to_mtd(chip);
++
++	/* Set the bad block position */
++	if (mtd->writesize > 512 || (chip->options & NAND_BUSWIDTH_16))
++		chip->badblockpos = NAND_LARGE_BADBLOCK_POS;
++	else
++		chip->badblockpos = NAND_SMALL_BADBLOCK_POS;
++}
++
++static inline bool is_full_id_nand(struct nand_flash_dev *type)
++{
++	return type->id_len;
++}
++
++static bool find_full_id_nand(struct nand_chip *chip,
++			      struct nand_flash_dev *type)
++{
++	struct mtd_info *mtd = nand_to_mtd(chip);
++	u8 *id_data = chip->id.data;
++
++	if (!strncmp(type->id, id_data, type->id_len)) {
++		mtd->writesize = type->pagesize;
++		mtd->erasesize = type->erasesize;
++		mtd->oobsize = type->oobsize;
++
++		chip->bits_per_cell = nand_get_bits_per_cell(id_data[2]);
++		chip->chipsize = (uint64_t)type->chipsize << 20;
++		chip->options |= type->options;
++		chip->ecc_strength_ds = NAND_ECC_STRENGTH(type);
++		chip->ecc_step_ds = NAND_ECC_STEP(type);
++		chip->onfi_timing_mode_default =
++					type->onfi_timing_mode_default;
++
++		if (!mtd->name)
++			mtd->name = type->name;
++
++		return true;
++	}
++	return false;
++}
++
++/*
++ * Manufacturer detection. Only used when the NAND is not ONFI or JEDEC
++ * compliant and does not have a full-id or legacy-id entry in the nand_ids
++ * table.
++ */
++static void nand_manufacturer_detect(struct nand_chip *chip)
++{
++	/*
++	 * Try manufacturer detection if available and use
++	 * nand_decode_ext_id() otherwise.
++	 */
++	if (chip->manufacturer.desc && chip->manufacturer.desc->ops &&
++	    chip->manufacturer.desc->ops->detect) {
++		/* The 3rd id byte holds MLC / multichip data */
++		chip->bits_per_cell = nand_get_bits_per_cell(chip->id.data[2]);
++		chip->manufacturer.desc->ops->detect(chip);
++	} else {
++		nand_decode_ext_id(chip);
++	}
++}
++
++/*
++ * Manufacturer initialization. This function is called for all NANDs including
++ * ONFI and JEDEC compliant ones.
++ * Manufacturer drivers should put all their specific initialization code in
++ * their ->init() hook.
++ */
++static int nand_manufacturer_init(struct nand_chip *chip)
++{
++	if (!chip->manufacturer.desc || !chip->manufacturer.desc->ops ||
++	    !chip->manufacturer.desc->ops->init)
++		return 0;
++
++	return chip->manufacturer.desc->ops->init(chip);
++}
++
++/*
++ * Manufacturer cleanup. This function is called for all NANDs including
++ * ONFI and JEDEC compliant ones.
++ * Manufacturer drivers should put all their specific cleanup code in their
++ * ->cleanup() hook.
++ */
++static void nand_manufacturer_cleanup(struct nand_chip *chip)
++{
++	/* Release manufacturer private data */
++	if (chip->manufacturer.desc && chip->manufacturer.desc->ops &&
++	    chip->manufacturer.desc->ops->cleanup)
++		chip->manufacturer.desc->ops->cleanup(chip);
++}
++
++/*
++ * Get the flash and manufacturer id and lookup if the type is supported.
++ */
++static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type)
++{
++	const struct nand_manufacturer *manufacturer;
++	struct mtd_info *mtd = nand_to_mtd(chip);
++	int busw;
++	int i;
++	u8 *id_data = chip->id.data;
++	u8 maf_id, dev_id;
++
++	/*
++	 * Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx)
++	 * after power-up.
++	 */
++	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);
++
++	/* Read manufacturer and device IDs */
++	maf_id = chip->read_byte(mtd);
++	dev_id = chip->read_byte(mtd);
++
++	/*
++	 * Try again to make sure, as some systems the bus-hold or other
++	 * interface concerns can cause random data which looks like a
++	 * possibly credible NAND flash to appear. If the two results do
++	 * not match, ignore the device completely.
++	 */
++
++	chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
++
++	/* Read entire ID string */
++	for (i = 0; i < ARRAY_SIZE(chip->id.data); i++)
++		id_data[i] = chip->read_byte(mtd);
++
++	if (id_data[0] != maf_id || id_data[1] != dev_id) {
++		pr_info("second ID read did not match %02x,%02x against %02x,%02x\n",
++			maf_id, dev_id, id_data[0], id_data[1]);
++		return -ENODEV;
++	}
++
++	chip->id.len = nand_id_len(id_data, ARRAY_SIZE(chip->id.data));
++
++	/* Try to identify manufacturer */
++	manufacturer = nand_get_manufacturer(maf_id);
++	chip->manufacturer.desc = manufacturer;
++
++	if (!type)
++		type = nand_flash_ids;
++
++	/*
++	 * Save the NAND_BUSWIDTH_16 flag before letting auto-detection logic
++	 * override it.
++	 * This is required to make sure initial NAND bus width set by the
++	 * NAND controller driver is coherent with the real NAND bus width
++	 * (extracted by auto-detection code).
++	 */
++	busw = chip->options & NAND_BUSWIDTH_16;
++
++	/*
++	 * The flag is only set (never cleared), reset it to its default value
++	 * before starting auto-detection.
++	 */
++	chip->options &= ~NAND_BUSWIDTH_16;
++
++	for (; type->name != NULL; type++) {
++		if (is_full_id_nand(type)) {
++			if (find_full_id_nand(chip, type))
++				goto ident_done;
++		} else if (dev_id == type->dev_id) {
++			break;
++		}
++	}
++
++	chip->onfi_version = 0;
++	if (!type->name || !type->pagesize) {
++		/* Check if the chip is ONFI compliant */
++		if (nand_flash_detect_onfi(chip))
++			goto ident_done;
++
++		/* Check if the chip is JEDEC compliant */
++		if (nand_flash_detect_jedec(chip))
++			goto ident_done;
++	}
++
++	if (!type->name)
++		return -ENODEV;
++
++	if (!mtd->name)
++		mtd->name = type->name;
++
++	chip->chipsize = (uint64_t)type->chipsize << 20;
++
++	if (!type->pagesize)
++		nand_manufacturer_detect(chip);
++	else
++		nand_decode_id(chip, type);
++
++	/* Get chip options */
++	chip->options |= type->options;
++
++ident_done:
++
++	if (chip->options & NAND_BUSWIDTH_AUTO) {
++		WARN_ON(busw & NAND_BUSWIDTH_16);
++		nand_set_defaults(chip);
++	} else if (busw != (chip->options & NAND_BUSWIDTH_16)) {
++		/*
++		 * Check, if buswidth is correct. Hardware drivers should set
++		 * chip correct!
++		 */
++		pr_info("device found, Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n",
++			maf_id, dev_id);
++		pr_info("%s %s\n", nand_manufacturer_name(manufacturer),
++			mtd->name);
++		pr_warn("bus width %d instead of %d bits\n", busw ? 16 : 8,
++			(chip->options & NAND_BUSWIDTH_16) ? 16 : 8);
++		return -EINVAL;
++	}
++
++	nand_decode_bbm_options(chip);
++
++	/* Calculate the address shift from the page size */
++	chip->page_shift = ffs(mtd->writesize) - 1;
++	/* Convert chipsize to number of pages per chip -1 */
++	chip->pagemask = (chip->chipsize >> chip->page_shift) - 1;
++
++	chip->bbt_erase_shift = chip->phys_erase_shift =
++		ffs(mtd->erasesize) - 1;
++	if (chip->chipsize & 0xffffffff)
++		chip->chip_shift = ffs((unsigned)chip->chipsize) - 1;
++	else {
++		chip->chip_shift = ffs((unsigned)(chip->chipsize >> 32));
++		chip->chip_shift += 32 - 1;
++	}
++
++	chip->badblockbits = 8;
++	chip->erase = single_erase;
++
++	/* Do not replace user supplied command function! */
++	if (mtd->writesize > 512 && chip->cmdfunc == nand_command)
++		chip->cmdfunc = nand_command_lp;
++
++	pr_info("device found, Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n",
++		maf_id, dev_id);
++
++	if (chip->onfi_version)
++		pr_info("%s %s\n", nand_manufacturer_name(manufacturer),
++			chip->onfi_params.model);
++	else if (chip->jedec_version)
++		pr_info("%s %s\n", nand_manufacturer_name(manufacturer),
++			chip->jedec_params.model);
++	else
++		pr_info("%s %s\n", nand_manufacturer_name(manufacturer),
++			type->name);
++
++	pr_info("%d MiB, %s, erase size: %d KiB, page size: %d, OOB size: %d\n",
++		(int)(chip->chipsize >> 20), nand_is_slc(chip) ? "SLC" : "MLC",
++		mtd->erasesize >> 10, mtd->writesize, mtd->oobsize);
++	return 0;
++}
++
++static const char * const nand_ecc_modes[] = {
++	[NAND_ECC_NONE]		= "none",
++	[NAND_ECC_SOFT]		= "soft",
++	[NAND_ECC_HW]		= "hw",
++	[NAND_ECC_HW_SYNDROME]	= "hw_syndrome",
++	[NAND_ECC_HW_OOB_FIRST]	= "hw_oob_first",
++	[NAND_ECC_ON_DIE]	= "on-die",
++};
++
++static int of_get_nand_ecc_mode(struct device_node *np)
++{
++	const char *pm;
++	int err, i;
++
++	err = of_property_read_string(np, "nand-ecc-mode", &pm);
++	if (err < 0)
++		return err;
++
++	for (i = 0; i < ARRAY_SIZE(nand_ecc_modes); i++)
++		if (!strcasecmp(pm, nand_ecc_modes[i]))
++			return i;
++
++	/*
++	 * For backward compatibility we support few obsoleted values that don't
++	 * have their mappings into nand_ecc_modes_t anymore (they were merged
++	 * with other enums).
++	 */
++	if (!strcasecmp(pm, "soft_bch"))
++		return NAND_ECC_SOFT;
++
++	return -ENODEV;
++}
++
++static const char * const nand_ecc_algos[] = {
++	[NAND_ECC_HAMMING]	= "hamming",
++	[NAND_ECC_BCH]		= "bch",
++};
++
++static int of_get_nand_ecc_algo(struct device_node *np)
++{
++	const char *pm;
++	int err, i;
++
++	err = of_property_read_string(np, "nand-ecc-algo", &pm);
++	if (!err) {
++		for (i = NAND_ECC_HAMMING; i < ARRAY_SIZE(nand_ecc_algos); i++)
++			if (!strcasecmp(pm, nand_ecc_algos[i]))
++				return i;
++		return -ENODEV;
++	}
++
++	/*
++	 * For backward compatibility we also read "nand-ecc-mode" checking
++	 * for some obsoleted values that were specifying ECC algorithm.
++	 */
++	err = of_property_read_string(np, "nand-ecc-mode", &pm);
++	if (err < 0)
++		return err;
++
++	if (!strcasecmp(pm, "soft"))
++		return NAND_ECC_HAMMING;
++	else if (!strcasecmp(pm, "soft_bch"))
++		return NAND_ECC_BCH;
++
++	return -ENODEV;
++}
++
++static int of_get_nand_ecc_step_size(struct device_node *np)
++{
++	int ret;
++	u32 val;
++
++	ret = of_property_read_u32(np, "nand-ecc-step-size", &val);
++	return ret ? ret : val;
++}
++
++static int of_get_nand_ecc_strength(struct device_node *np)
++{
++	int ret;
++	u32 val;
++
++	ret = of_property_read_u32(np, "nand-ecc-strength", &val);
++	return ret ? ret : val;
++}
++
++static int of_get_nand_bus_width(struct device_node *np)
++{
++	u32 val;
++
++	if (of_property_read_u32(np, "nand-bus-width", &val))
++		return 8;
++
++	switch (val) {
++	case 8:
++	case 16:
++		return val;
++	default:
++		return -EIO;
++	}
++}
++
++static bool of_get_nand_on_flash_bbt(struct device_node *np)
++{
++	return of_property_read_bool(np, "nand-on-flash-bbt");
++}
++
++static int nand_dt_init(struct nand_chip *chip)
++{
++	struct device_node *dn = nand_get_flash_node(chip);
++	int ecc_mode, ecc_algo, ecc_strength, ecc_step;
++
++	if (!dn)
++		return 0;
++
++	if (of_get_nand_bus_width(dn) == 16)
++		chip->options |= NAND_BUSWIDTH_16;
++
++	if (of_get_nand_on_flash_bbt(dn))
++		chip->bbt_options |= NAND_BBT_USE_FLASH;
++
++	ecc_mode = of_get_nand_ecc_mode(dn);
++	ecc_algo = of_get_nand_ecc_algo(dn);
++	ecc_strength = of_get_nand_ecc_strength(dn);
++	ecc_step = of_get_nand_ecc_step_size(dn);
++
++	if (ecc_mode >= 0)
++		chip->ecc.mode = ecc_mode;
++
++	if (ecc_algo >= 0)
++		chip->ecc.algo = ecc_algo;
++
++	if (ecc_strength >= 0)
++		chip->ecc.strength = ecc_strength;
++
++	if (ecc_step > 0)
++		chip->ecc.size = ecc_step;
++
++	if (of_property_read_bool(dn, "nand-ecc-maximize"))
++		chip->ecc.options |= NAND_ECC_MAXIMIZE;
++
++	return 0;
++}
++
++/**
++ * nand_scan_ident - [NAND Interface] Scan for the NAND device
++ * @mtd: MTD device structure
++ * @maxchips: number of chips to scan for
++ * @table: alternative NAND ID table
++ *
++ * This is the first phase of the normal nand_scan() function. It reads the
++ * flash ID and sets up MTD fields accordingly.
++ *
++ */
++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);
++	int ret;
++
++	ret = nand_dt_init(chip);
++	if (ret)
++		return ret;
++
++	if (!mtd->name && mtd->dev.parent)
++		mtd->name = dev_name(mtd->dev.parent);
++
++	if ((!chip->cmdfunc || !chip->select_chip) && !chip->cmd_ctrl) {
++		/*
++		 * Default functions assigned for chip_select() and
++		 * cmdfunc() both expect cmd_ctrl() to be populated,
++		 * so we need to check that that's the case
++		 */
++		pr_err("chip.cmd_ctrl() callback is not provided");
++		return -EINVAL;
++	}
++	/* Set the default functions */
++	nand_set_defaults(chip);
++
++	/* Read the flash type */
++	ret = nand_detect(chip, table);
++	if (ret) {
++		if (!(chip->options & NAND_SCAN_SILENT_NODEV))
++			pr_warn("No NAND device found\n");
++		chip->select_chip(mtd, -1);
++		return ret;
++	}
++
++	nand_maf_id = chip->id.data[0];
++	nand_dev_id = chip->id.data[1];
++
++	chip->select_chip(mtd, -1);
++
++	/* Check for a chip array */
++	for (i = 1; i < maxchips; i++) {
++		/* See comment in nand_get_flash_type for reset */
++		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 */
++		if (nand_maf_id != chip->read_byte(mtd) ||
++		    nand_dev_id != chip->read_byte(mtd)) {
++			chip->select_chip(mtd, -1);
++			break;
++		}
++		chip->select_chip(mtd, -1);
++	}
++	if (i > 1)
++		pr_info("%d chips detected\n", i);
++
++	/* Store the number of chips and calc total size for mtd */
++	chip->numchips = i;
++	mtd->size = i * chip->chipsize;
++
++	return 0;
++}
++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_ecc_ctrl *ecc = &chip->ecc;
++
++	if (WARN_ON(ecc->mode != NAND_ECC_SOFT))
++		return -EINVAL;
++
++	switch (ecc->algo) {
++	case NAND_ECC_HAMMING:
++		ecc->calculate = nand_calculate_ecc;
++		ecc->correct = nand_correct_data;
++		ecc->read_page = nand_read_page_swecc;
++		ecc->read_subpage = nand_read_subpage;
++		ecc->write_page = nand_write_page_swecc;
++		ecc->read_page_raw = nand_read_page_raw;
++		ecc->write_page_raw = nand_write_page_raw;
++		ecc->read_oob = nand_read_oob_std;
++		ecc->write_oob = nand_write_oob_std;
++		if (!ecc->size)
++			ecc->size = 256;
++		ecc->bytes = 3;
++		ecc->strength = 1;
++		return 0;
++	case NAND_ECC_BCH:
++		if (!mtd_nand_has_bch()) {
++			WARN(1, "CONFIG_MTD_NAND_ECC_BCH not enabled\n");
++			return -EINVAL;
++		}
++		ecc->calculate = nand_bch_calculate_ecc;
++		ecc->correct = nand_bch_correct_data;
++		ecc->read_page = nand_read_page_swecc;
++		ecc->read_subpage = nand_read_subpage;
++		ecc->write_page = nand_write_page_swecc;
++		ecc->read_page_raw = nand_read_page_raw;
++		ecc->write_page_raw = nand_write_page_raw;
++		ecc->read_oob = nand_read_oob_std;
++		ecc->write_oob = nand_write_oob_std;
++
++		/*
++		* Board driver should supply ecc.size and ecc.strength
++		* values to select how many bits are correctable.
++		* Otherwise, default to 4 bits for large page devices.
++		*/
++		if (!ecc->size && (mtd->oobsize >= 64)) {
++			ecc->size = 512;
++			ecc->strength = 4;
++		}
++
++		/*
++		 * if no ecc placement scheme was provided pickup the default
++		 * large page one.
++		 */
++		if (!mtd->ooblayout) {
++			/* handle large page devices only */
++			if (mtd->oobsize < 64) {
++				WARN(1, "OOB layout is required when using software BCH on small pages\n");
++				return -EINVAL;
++			}
++
++			mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
++
++		}
++
++		/*
++		 * We can only maximize ECC config when the default layout is
++		 * used, otherwise we don't know how many bytes can really be
++		 * used.
++		 */
++		if (mtd->ooblayout == &nand_ooblayout_lp_ops &&
++		    ecc->options & NAND_ECC_MAXIMIZE) {
++			int steps, bytes;
++
++			/* Always prefer 1k blocks over 512bytes ones */
++			ecc->size = 1024;
++			steps = mtd->writesize / ecc->size;
++
++			/* Reserve 2 bytes for the BBM */
++			bytes = (mtd->oobsize - 2) / steps;
++			ecc->strength = bytes * 8 / fls(8 * ecc->size);
++		}
++
++		/* See nand_bch_init() for details. */
++		ecc->bytes = 0;
++		ecc->priv = nand_bch_init(mtd);
++		if (!ecc->priv) {
++			WARN(1, "BCH ECC initialization failed!\n");
++			return -EINVAL;
++		}
++		return 0;
++	default:
++		WARN(1, "Unsupported ECC algorithm!\n");
++		return -EINVAL;
++	}
++}
++
++/**
++ * nand_check_ecc_caps - check the sanity of preset ECC settings
++ * @chip: nand chip info structure
++ * @caps: ECC caps info structure
++ * @oobavail: OOB size that the ECC engine can use
++ *
++ * When ECC step size and strength are already set, check if they are supported
++ * by the controller and the calculated ECC bytes fit within the chip's OOB.
++ * On success, the calculated ECC bytes is set.
++ */
++int nand_check_ecc_caps(struct nand_chip *chip,
++			const struct nand_ecc_caps *caps, int oobavail)
++{
++	struct mtd_info *mtd = nand_to_mtd(chip);
++	const struct nand_ecc_step_info *stepinfo;
++	int preset_step = chip->ecc.size;
++	int preset_strength = chip->ecc.strength;
++	int nsteps, ecc_bytes;
++	int i, j;
++
++	if (WARN_ON(oobavail < 0))
++		return -EINVAL;
++
++	if (!preset_step || !preset_strength)
++		return -ENODATA;
++
++	nsteps = mtd->writesize / preset_step;
++
++	for (i = 0; i < caps->nstepinfos; i++) {
++		stepinfo = &caps->stepinfos[i];
++
++		if (stepinfo->stepsize != preset_step)
++			continue;
++
++		for (j = 0; j < stepinfo->nstrengths; j++) {
++			if (stepinfo->strengths[j] != preset_strength)
++				continue;
++
++			ecc_bytes = caps->calc_ecc_bytes(preset_step,
++							 preset_strength);
++			if (WARN_ON_ONCE(ecc_bytes < 0))
++				return ecc_bytes;
++
++			if (ecc_bytes * nsteps > oobavail) {
++				pr_err("ECC (step, strength) = (%d, %d) does not fit in OOB",
++				       preset_step, preset_strength);
++				return -ENOSPC;
++			}
++
++			chip->ecc.bytes = ecc_bytes;
++
++			return 0;
++		}
++	}
++
++	pr_err("ECC (step, strength) = (%d, %d) not supported on this controller",
++	       preset_step, preset_strength);
++
++	return -ENOTSUPP;
++}
++EXPORT_SYMBOL_GPL(nand_check_ecc_caps);
++
++/**
++ * nand_match_ecc_req - meet the chip's requirement with least ECC bytes
++ * @chip: nand chip info structure
++ * @caps: ECC engine caps info structure
++ * @oobavail: OOB size that the ECC engine can use
++ *
++ * If a chip's ECC requirement is provided, try to meet it with the least
++ * number of ECC bytes (i.e. with the largest number of OOB-free bytes).
++ * On success, the chosen ECC settings are set.
++ */
++int nand_match_ecc_req(struct nand_chip *chip,
++		       const struct nand_ecc_caps *caps, int oobavail)
++{
++	struct mtd_info *mtd = nand_to_mtd(chip);
++	const struct nand_ecc_step_info *stepinfo;
++	int req_step = chip->ecc_step_ds;
++	int req_strength = chip->ecc_strength_ds;
++	int req_corr, step_size, strength, nsteps, ecc_bytes, ecc_bytes_total;
++	int best_step, best_strength, best_ecc_bytes;
++	int best_ecc_bytes_total = INT_MAX;
++	int i, j;
++
++	if (WARN_ON(oobavail < 0))
++		return -EINVAL;
++
++	/* No information provided by the NAND chip */
++	if (!req_step || !req_strength)
++		return -ENOTSUPP;
++
++	/* number of correctable bits the chip requires in a page */
++	req_corr = mtd->writesize / req_step * req_strength;
++
++	for (i = 0; i < caps->nstepinfos; i++) {
++		stepinfo = &caps->stepinfos[i];
++		step_size = stepinfo->stepsize;
++
++		for (j = 0; j < stepinfo->nstrengths; j++) {
++			strength = stepinfo->strengths[j];
++
++			/*
++			 * If both step size and strength are smaller than the
++			 * chip's requirement, it is not easy to compare the
++			 * resulted reliability.
++			 */
++			if (step_size < req_step && strength < req_strength)
++				continue;
++
++			if (mtd->writesize % step_size)
++				continue;
++
++			nsteps = mtd->writesize / step_size;
++
++			ecc_bytes = caps->calc_ecc_bytes(step_size, strength);
++			if (WARN_ON_ONCE(ecc_bytes < 0))
++				continue;
++			ecc_bytes_total = ecc_bytes * nsteps;
++
++			if (ecc_bytes_total > oobavail ||
++			    strength * nsteps < req_corr)
++				continue;
++
++			/*
++			 * We assume the best is to meet the chip's requrement
++			 * with the least number of ECC bytes.
++			 */
++			if (ecc_bytes_total < best_ecc_bytes_total) {
++				best_ecc_bytes_total = ecc_bytes_total;
++				best_step = step_size;
++				best_strength = strength;
++				best_ecc_bytes = ecc_bytes;
++			}
++		}
++	}
++
++	if (best_ecc_bytes_total == INT_MAX)
++		return -ENOTSUPP;
++
++	chip->ecc.size = best_step;
++	chip->ecc.strength = best_strength;
++	chip->ecc.bytes = best_ecc_bytes;
++
++	return 0;
++}
++EXPORT_SYMBOL_GPL(nand_match_ecc_req);
++
++/**
++ * nand_maximize_ecc - choose the max ECC strength available
++ * @chip: nand chip info structure
++ * @caps: ECC engine caps info structure
++ * @oobavail: OOB size that the ECC engine can use
++ *
++ * Choose the max ECC strength that is supported on the controller, and can fit
++ * within the chip's OOB.  On success, the chosen ECC settings are set.
++ */
++int nand_maximize_ecc(struct nand_chip *chip,
++		      const struct nand_ecc_caps *caps, int oobavail)
++{
++	struct mtd_info *mtd = nand_to_mtd(chip);
++	const struct nand_ecc_step_info *stepinfo;
++	int step_size, strength, nsteps, ecc_bytes, corr;
++	int best_corr = 0;
++	int best_step = 0;
++	int best_strength, best_ecc_bytes;
++	int i, j;
++
++	if (WARN_ON(oobavail < 0))
++		return -EINVAL;
++
++	for (i = 0; i < caps->nstepinfos; i++) {
++		stepinfo = &caps->stepinfos[i];
++		step_size = stepinfo->stepsize;
++
++		/* If chip->ecc.size is already set, respect it */
++		if (chip->ecc.size && step_size != chip->ecc.size)
++			continue;
++
++		for (j = 0; j < stepinfo->nstrengths; j++) {
++			strength = stepinfo->strengths[j];
++
++			if (mtd->writesize % step_size)
++				continue;
++
++			nsteps = mtd->writesize / step_size;
++
++			ecc_bytes = caps->calc_ecc_bytes(step_size, strength);
++			if (WARN_ON_ONCE(ecc_bytes < 0))
++				continue;
++
++			if (ecc_bytes * nsteps > oobavail)
++				continue;
++
++			corr = strength * nsteps;
++
++			/*
++			 * If the number of correctable bits is the same,
++			 * bigger step_size has more reliability.
++			 */
++			if (corr > best_corr ||
++			    (corr == best_corr && step_size > best_step)) {
++				best_corr = corr;
++				best_step = step_size;
++				best_strength = strength;
++				best_ecc_bytes = ecc_bytes;
++			}
++		}
++	}
++
++	if (!best_corr)
++		return -ENOTSUPP;
++
++	chip->ecc.size = best_step;
++	chip->ecc.strength = best_strength;
++	chip->ecc.bytes = best_ecc_bytes;
++
++	return 0;
++}
++EXPORT_SYMBOL_GPL(nand_maximize_ecc);
++
++/*
++ * Check if the chip configuration meet the datasheet requirements.
++
++ * If our configuration corrects A bits per B bytes and the minimum
++ * required correction level is X bits per Y bytes, then we must ensure
++ * both of the following are true:
++ *
++ * (1) A / B >= X / Y
++ * (2) A >= X
++ *
++ * Requirement (1) ensures we can correct for the required bitflip density.
++ * Requirement (2) ensures we can correct even when all bitflips are clumped
++ * in the same sector.
++ */
++static bool nand_ecc_strength_good(struct mtd_info *mtd)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct nand_ecc_ctrl *ecc = &chip->ecc;
++	int corr, ds_corr;
++
++	if (ecc->size == 0 || chip->ecc_step_ds == 0)
++		/* Not enough information */
++		return true;
++
++	/*
++	 * We get the number of corrected bits per page to compare
++	 * the correction density.
++	 */
++	corr = (mtd->writesize * ecc->strength) / ecc->size;
++	ds_corr = (mtd->writesize * chip->ecc_strength_ds) / chip->ecc_step_ds;
++
++	return corr >= ds_corr && ecc->strength >= chip->ecc_strength_ds;
++}
++
++static bool invalid_ecc_page_accessors(struct nand_chip *chip)
++{
++	struct nand_ecc_ctrl *ecc = &chip->ecc;
++
++	if (nand_standard_page_accessors(ecc))
++		return false;
++
++	/*
++	 * NAND_ECC_CUSTOM_PAGE_ACCESS flag is set, make sure the NAND
++	 * controller driver implements all the page accessors because
++	 * default helpers are not suitable when the core does not
++	 * send the READ0/PAGEPROG commands.
++	 */
++	return (!ecc->read_page || !ecc->write_page ||
++		!ecc->read_page_raw || !ecc->write_page_raw ||
++		(NAND_HAS_SUBPAGE_READ(chip) && !ecc->read_subpage) ||
++		(NAND_HAS_SUBPAGE_WRITE(chip) && !ecc->write_subpage &&
++		 ecc->hwctl && ecc->calculate));
++}
++
++/**
++ * nand_scan_tail - [NAND Interface] Scan for the NAND device
++ * @mtd: MTD device structure
++ *
++ * This is the second phase of the normal nand_scan() function. It fills out
++ * all the uninitialized function pointers with the defaults and scans for a
++ * bad block table if appropriate.
++ */
++int nand_scan_tail(struct mtd_info *mtd)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct nand_ecc_ctrl *ecc = &chip->ecc;
++	struct nand_buffers *nbuf = NULL;
++	int ret, i;
++
++	/* New bad blocks should be marked in OOB, flash-based BBT, or both */
++	if (WARN_ON((chip->bbt_options & NAND_BBT_NO_OOB_BBM) &&
++		   !(chip->bbt_options & NAND_BBT_USE_FLASH))) {
++		return -EINVAL;
++	}
++
++	if (invalid_ecc_page_accessors(chip)) {
++		pr_err("Invalid ECC page accessors setup\n");
++		return -EINVAL;
++	}
++
++	if (!(chip->options & NAND_OWN_BUFFERS)) {
++		nbuf = kzalloc(sizeof(*nbuf), GFP_KERNEL);
++		if (!nbuf)
++			return -ENOMEM;
++
++		nbuf->ecccalc = kmalloc(mtd->oobsize, GFP_KERNEL);
++		if (!nbuf->ecccalc) {
++			ret = -ENOMEM;
++			goto err_free_nbuf;
++		}
++
++		nbuf->ecccode = kmalloc(mtd->oobsize, GFP_KERNEL);
++		if (!nbuf->ecccode) {
++			ret = -ENOMEM;
++			goto err_free_nbuf;
++		}
++
++		nbuf->databuf = kmalloc(mtd->writesize + mtd->oobsize,
++					GFP_KERNEL);
++		if (!nbuf->databuf) {
++			ret = -ENOMEM;
++			goto err_free_nbuf;
++		}
++
++		chip->buffers = nbuf;
++	} else if (!chip->buffers) {
++		return -ENOMEM;
++	}
++
++	/*
++	 * FIXME: some NAND manufacturer drivers expect the first die to be
++	 * selected when manufacturer->init() is called. They should be fixed
++	 * to explictly select the relevant die when interacting with the NAND
++	 * chip.
++	 */
++	chip->select_chip(mtd, 0);
++	ret = nand_manufacturer_init(chip);
++	chip->select_chip(mtd, -1);
++	if (ret)
++		goto err_free_nbuf;
++
++	/* Set the internal oob buffer location, just after the page data */
++	chip->oob_poi = chip->buffers->databuf + mtd->writesize;
++
++	/*
++	 * If no default placement scheme is given, select an appropriate one.
++	 */
++	if (!mtd->ooblayout &&
++	    !(ecc->mode == NAND_ECC_SOFT && ecc->algo == NAND_ECC_BCH)) {
++		switch (mtd->oobsize) {
++		case 8:
++		case 16:
++			mtd_set_ooblayout(mtd, &nand_ooblayout_sp_ops);
++			break;
++		case 64:
++		case 128:
++			mtd_set_ooblayout(mtd, &nand_ooblayout_lp_hamming_ops);
++			break;
++		default:
++			WARN(1, "No oob scheme defined for oobsize %d\n",
++				mtd->oobsize);
++			ret = -EINVAL;
++			goto err_nand_manuf_cleanup;
++		}
++	}
++
++	/*
++	 * Check ECC mode, default to software if 3byte/512byte hardware ECC is
++	 * selected and we have 256 byte pagesize fallback to software ECC
++	 */
++
++	switch (ecc->mode) {
++	case NAND_ECC_HW_OOB_FIRST:
++		/* Similar to NAND_ECC_HW, but a separate read_page handle */
++		if (!ecc->calculate || !ecc->correct || !ecc->hwctl) {
++			WARN(1, "No ECC functions supplied; hardware ECC not possible\n");
++			ret = -EINVAL;
++			goto err_nand_manuf_cleanup;
++		}
++		if (!ecc->read_page)
++			ecc->read_page = nand_read_page_hwecc_oob_first;
++
++	case NAND_ECC_HW:
++		/* Use standard hwecc read page function? */
++		if (!ecc->read_page)
++			ecc->read_page = nand_read_page_hwecc;
++		if (!ecc->write_page)
++			ecc->write_page = nand_write_page_hwecc;
++		if (!ecc->read_page_raw)
++			ecc->read_page_raw = nand_read_page_raw;
++		if (!ecc->write_page_raw)
++			ecc->write_page_raw = nand_write_page_raw;
++		if (!ecc->read_oob)
++			ecc->read_oob = nand_read_oob_std;
++		if (!ecc->write_oob)
++			ecc->write_oob = nand_write_oob_std;
++		if (!ecc->read_subpage)
++			ecc->read_subpage = nand_read_subpage;
++		if (!ecc->write_subpage && ecc->hwctl && ecc->calculate)
++			ecc->write_subpage = nand_write_subpage_hwecc;
++
++	case NAND_ECC_HW_SYNDROME:
++		if ((!ecc->calculate || !ecc->correct || !ecc->hwctl) &&
++		    (!ecc->read_page ||
++		     ecc->read_page == nand_read_page_hwecc ||
++		     !ecc->write_page ||
++		     ecc->write_page == nand_write_page_hwecc)) {
++			WARN(1, "No ECC functions supplied; hardware ECC not possible\n");
++			ret = -EINVAL;
++			goto err_nand_manuf_cleanup;
++		}
++		/* Use standard syndrome read/write page function? */
++		if (!ecc->read_page)
++			ecc->read_page = nand_read_page_syndrome;
++		if (!ecc->write_page)
++			ecc->write_page = nand_write_page_syndrome;
++		if (!ecc->read_page_raw)
++			ecc->read_page_raw = nand_read_page_raw_syndrome;
++		if (!ecc->write_page_raw)
++			ecc->write_page_raw = nand_write_page_raw_syndrome;
++		if (!ecc->read_oob)
++			ecc->read_oob = nand_read_oob_syndrome;
++		if (!ecc->write_oob)
++			ecc->write_oob = nand_write_oob_syndrome;
++
++		if (mtd->writesize >= ecc->size) {
++			if (!ecc->strength) {
++				WARN(1, "Driver must set ecc.strength when using hardware ECC\n");
++				ret = -EINVAL;
++				goto err_nand_manuf_cleanup;
++			}
++			break;
++		}
++		pr_warn("%d byte HW ECC not possible on %d byte page size, fallback to SW ECC\n",
++			ecc->size, mtd->writesize);
++		ecc->mode = NAND_ECC_SOFT;
++		ecc->algo = NAND_ECC_HAMMING;
++
++	case NAND_ECC_SOFT:
++		ret = nand_set_ecc_soft_ops(mtd);
++		if (ret) {
++			ret = -EINVAL;
++			goto err_nand_manuf_cleanup;
++		}
++		break;
++
++	case NAND_ECC_ON_DIE:
++		if (!ecc->read_page || !ecc->write_page) {
++			WARN(1, "No ECC functions supplied; on-die ECC not possible\n");
++			ret = -EINVAL;
++			goto err_nand_manuf_cleanup;
++		}
++		if (!ecc->read_oob)
++			ecc->read_oob = nand_read_oob_std;
++		if (!ecc->write_oob)
++			ecc->write_oob = nand_write_oob_std;
++		break;
++
++	case NAND_ECC_NONE:
++		pr_warn("NAND_ECC_NONE selected by board driver. This is not recommended!\n");
++		ecc->read_page = nand_read_page_raw;
++		ecc->write_page = nand_write_page_raw;
++		ecc->read_oob = nand_read_oob_std;
++		ecc->read_page_raw = nand_read_page_raw;
++		ecc->write_page_raw = nand_write_page_raw;
++		ecc->write_oob = nand_write_oob_std;
++		ecc->size = mtd->writesize;
++		ecc->bytes = 0;
++		ecc->strength = 0;
++		break;
++
++	default:
++		WARN(1, "Invalid NAND_ECC_MODE %d\n", ecc->mode);
++		ret = -EINVAL;
++		goto err_nand_manuf_cleanup;
++	}
++
++	/* For many systems, the standard OOB write also works for raw */
++	if (!ecc->read_oob_raw)
++		ecc->read_oob_raw = ecc->read_oob;
++	if (!ecc->write_oob_raw)
++		ecc->write_oob_raw = ecc->write_oob;
++
++	/* propagate ecc info to mtd_info */
++	mtd->ecc_strength = ecc->strength;
++	mtd->ecc_step_size = ecc->size;
++
++	/*
++	 * Set the number of read / write steps for one page depending on ECC
++	 * mode.
++	 */
++	ecc->steps = mtd->writesize / ecc->size;
++	if (ecc->steps * ecc->size != mtd->writesize) {
++		WARN(1, "Invalid ECC parameters\n");
++		ret = -EINVAL;
++		goto err_nand_manuf_cleanup;
++	}
++	ecc->total = ecc->steps * ecc->bytes;
++	if (ecc->total > mtd->oobsize) {
++		WARN(1, "Total number of ECC bytes exceeded oobsize\n");
++		ret = -EINVAL;
++		goto err_nand_manuf_cleanup;
++	}
++
++	/*
++	 * The number of bytes available for a client to place data into
++	 * the out of band area.
++	 */
++	ret = mtd_ooblayout_count_freebytes(mtd);
++	if (ret < 0)
++		ret = 0;
++
++	mtd->oobavail = ret;
++
++	/* ECC sanity check: warn if it's too weak */
++	if (!nand_ecc_strength_good(mtd))
++		pr_warn("WARNING: %s: the ECC used on your system is too weak compared to the one required by the NAND chip\n",
++			mtd->name);
++
++	/* Allow subpage writes up to ecc.steps. Not possible for MLC flash */
++	if (!(chip->options & NAND_NO_SUBPAGE_WRITE) && nand_is_slc(chip)) {
++		switch (ecc->steps) {
++		case 2:
++			mtd->subpage_sft = 1;
++			break;
++		case 4:
++		case 8:
++		case 16:
++			mtd->subpage_sft = 2;
++			break;
++		}
++	}
++	chip->subpagesize = mtd->writesize >> mtd->subpage_sft;
++
++	/* Initialize state */
++	chip->state = FL_READY;
++
++	/* Invalidate the pagebuffer reference */
++	chip->pagebuf = -1;
++
++	/* Large page NAND with SOFT_ECC should support subpage reads */
++	switch (ecc->mode) {
++	case NAND_ECC_SOFT:
++		if (chip->page_shift > 9)
++			chip->options |= NAND_SUBPAGE_READ;
++		break;
++
++	default:
++		break;
++	}
++
++	/* Fill in remaining MTD driver data */
++	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->_point = NULL;
++	mtd->_unpoint = NULL;
++	mtd->_panic_write = panic_nand_write;
++	mtd->_read_oob = nand_read_oob;
++	mtd->_write_oob = nand_write_oob;
++	mtd->_sync = nand_sync;
++	mtd->_lock = NULL;
++	mtd->_unlock = NULL;
++	mtd->_suspend = nand_suspend;
++	mtd->_resume = nand_resume;
++	mtd->_reboot = nand_shutdown;
++	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;
++
++	/*
++	 * Initialize bitflip_threshold to its default prior scan_bbt() call.
++	 * scan_bbt() might invoke mtd_read(), thus bitflip_threshold must be
++	 * properly set.
++	 */
++	if (!mtd->bitflip_threshold)
++		mtd->bitflip_threshold = DIV_ROUND_UP(mtd->ecc_strength * 3, 4);
++
++	/* Initialize the ->data_interface field. */
++	ret = nand_init_data_interface(chip);
++	if (ret)
++		goto err_nand_manuf_cleanup;
++
++	/* Enter fastest possible mode on all dies. */
++	for (i = 0; i < chip->numchips; i++) {
++		chip->select_chip(mtd, i);
++		ret = nand_setup_data_interface(chip, i);
++		chip->select_chip(mtd, -1);
++
++		if (ret)
++			goto err_nand_data_iface_cleanup;
++	}
++
++	/* Check, if we should skip the bad block table scan */
++	if (chip->options & NAND_SKIP_BBTSCAN)
++		return 0;
++
++	/* Build bad block table */
++	ret = chip->scan_bbt(mtd);
++	if (ret)
++		goto err_nand_data_iface_cleanup;
++
++	return 0;
++
++err_nand_data_iface_cleanup:
++	nand_release_data_interface(chip);
++
++err_nand_manuf_cleanup:
++	nand_manufacturer_cleanup(chip);
++
++err_free_nbuf:
++	if (nbuf) {
++		kfree(nbuf->databuf);
++		kfree(nbuf->ecccode);
++		kfree(nbuf->ecccalc);
++		kfree(nbuf);
++	}
++
++	return ret;
++}
++EXPORT_SYMBOL(nand_scan_tail);
++
++/*
++ * is_module_text_address() isn't exported, and it's mostly a pointless
++ * test if this is a module _anyway_ -- they'd have to try _really_ hard
++ * to call us from in-kernel code if the core NAND support is modular.
++ */
++#ifdef MODULE
++#define caller_is_module() (1)
++#else
++#define caller_is_module() \
++	is_module_text_address((unsigned long)__builtin_return_address(0))
++#endif
++
++/**
++ * nand_scan - [NAND Interface] Scan for the NAND device
++ * @mtd: MTD device structure
++ * @maxchips: number of chips to scan for
++ *
++ * This fills out all the uninitialized function pointers with the defaults.
++ * The flash ID is read and the mtd/chip structures are filled with the
++ * appropriate values.
++ */
++int nand_scan(struct mtd_info *mtd, int maxchips)
++{
++	int ret;
++
++	ret = nand_scan_ident(mtd, maxchips, NULL);
++	if (!ret)
++		ret = nand_scan_tail(mtd);
++	return ret;
++}
++EXPORT_SYMBOL(nand_scan);
++
++/**
++ * nand_cleanup - [NAND Interface] Free resources held by the NAND device
++ * @chip: NAND chip object
++ */
++void nand_cleanup(struct nand_chip *chip)
++{
++	if (chip->ecc.mode == NAND_ECC_SOFT &&
++	    chip->ecc.algo == NAND_ECC_BCH)
++		nand_bch_free((struct nand_bch_control *)chip->ecc.priv);
++
++	nand_release_data_interface(chip);
++
++	/* Free bad block table memory */
++	kfree(chip->bbt);
++	if (!(chip->options & NAND_OWN_BUFFERS) && chip->buffers) {
++		kfree(chip->buffers->databuf);
++		kfree(chip->buffers->ecccode);
++		kfree(chip->buffers->ecccalc);
++		kfree(chip->buffers);
++	}
++
++	/* Free bad block descriptor memory */
++	if (chip->badblock_pattern && chip->badblock_pattern->options
++			& NAND_BBT_DYNAMICSTRUCT)
++		kfree(chip->badblock_pattern);
++
++	/* Free manufacturer priv data. */
++	nand_manufacturer_cleanup(chip);
++}
++EXPORT_SYMBOL_GPL(nand_cleanup);
++
++/**
++ * nand_release - [NAND Interface] Unregister the MTD device and free resources
++ *		  held by the NAND device
++ * @mtd: MTD device structure
++ */
++void nand_release(struct mtd_info *mtd)
++{
++	mtd_device_unregister(mtd);
++	nand_cleanup(mtd_to_nand(mtd));
++}
++EXPORT_SYMBOL_GPL(nand_release);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Steven J. Hill <sjhill@realitydiluted.com>");
++MODULE_AUTHOR("Thomas Gleixner <tglx@linutronix.de>");
++MODULE_DESCRIPTION("Generic NAND flash driver code");
+diff --git a/drivers/mtd/nand/raw/nand_bbt.c b/drivers/mtd/nand/raw/nand_bbt.c
+new file mode 100644
+index 0000000..2915b67
+--- /dev/null
++++ b/drivers/mtd/nand/raw/nand_bbt.c
+@@ -0,0 +1,1452 @@
++/*
++ *  Overview:
++ *   Bad block table support for the NAND driver
++ *
++ *  Copyright © 2004 Thomas Gleixner (tglx@linutronix.de)
++ *
++ * 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.
++ *
++ * Description:
++ *
++ * When nand_scan_bbt is called, then it tries to find the bad block table
++ * depending on the options in the BBT descriptor(s). If no flash based BBT
++ * (NAND_BBT_USE_FLASH) is specified then the device is scanned for factory
++ * marked good / bad blocks. This information is used to create a memory BBT.
++ * Once a new bad block is discovered then the "factory" information is updated
++ * on the device.
++ * If a flash based BBT is specified then the function first tries to find the
++ * BBT on flash. If a BBT is found then the contents are read and the memory
++ * based BBT is created. If a mirrored BBT is selected then the mirror is
++ * searched too and the versions are compared. If the mirror has a greater
++ * version number, then the mirror BBT is used to build the memory based BBT.
++ * If the tables are not versioned, then we "or" the bad block information.
++ * If one of the BBTs is out of date or does not exist it is (re)created.
++ * If no BBT exists at all then the device is scanned for factory marked
++ * good / bad blocks and the bad block tables are created.
++ *
++ * For manufacturer created BBTs like the one found on M-SYS DOC devices
++ * the BBT is searched and read but never created
++ *
++ * The auto generated bad block table is located in the last good blocks
++ * of the device. The table is mirrored, so it can be updated eventually.
++ * The table is marked in the OOB area with an ident pattern and a version
++ * number which indicates which of both tables is more up to date. If the NAND
++ * controller needs the complete OOB area for the ECC information then the
++ * option NAND_BBT_NO_OOB should be used (along with NAND_BBT_USE_FLASH, of
++ * course): it moves the ident pattern and the version byte into the data area
++ * and the OOB area will remain untouched.
++ *
++ * The table uses 2 bits per block
++ * 11b:		block is good
++ * 00b:		block is factory marked bad
++ * 01b, 10b:	block is marked bad due to wear
++ *
++ * The memory bad block table uses the following scheme:
++ * 00b:		block is good
++ * 01b:		block is marked bad due to wear
++ * 10b:		block is reserved (to protect the bbt area)
++ * 11b:		block is factory marked bad
++ *
++ * Multichip devices like DOC store the bad block info per floor.
++ *
++ * Following assumptions are made:
++ * - bbts start at a page boundary, if autolocated on a block boundary
++ * - the space necessary for a bbt in FLASH does not exceed a block boundary
++ *
++ */
++
++#include <linux/slab.h>
++#include <linux/types.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/bbm.h>
++#include <linux/mtd/rawnand.h>
++#include <linux/bitops.h>
++#include <linux/delay.h>
++#include <linux/vmalloc.h>
++#include <linux/export.h>
++#include <linux/string.h>
++
++#define BBT_BLOCK_GOOD		0x00
++#define BBT_BLOCK_WORN		0x01
++#define BBT_BLOCK_RESERVED	0x02
++#define BBT_BLOCK_FACTORY_BAD	0x03
++
++#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)
++{
++	uint8_t entry = chip->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,
++		uint8_t mark)
++{
++	uint8_t msk = (mark & BBT_ENTRY_MASK) << ((block & BBT_ENTRY_MASK) * 2);
++	chip->bbt[block >> BBT_ENTRY_SHIFT] |= msk;
++}
++
++static int check_pattern_no_oob(uint8_t *buf, struct nand_bbt_descr *td)
++{
++	if (memcmp(buf, td->pattern, td->len))
++		return -1;
++	return 0;
++}
++
++/**
++ * check_pattern - [GENERIC] check if a pattern is in the buffer
++ * @buf: the buffer to search
++ * @len: the length of buffer to search
++ * @paglen: the pagelength
++ * @td: search pattern descriptor
++ *
++ * Check for a pattern at the given place. Used to search bad block tables and
++ * good / bad block identifiers.
++ */
++static int check_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_descr *td)
++{
++	if (td->options & NAND_BBT_NO_OOB)
++		return check_pattern_no_oob(buf, td);
++
++	/* Compare the pattern */
++	if (memcmp(buf + paglen + td->offs, td->pattern, td->len))
++		return -1;
++
++	return 0;
++}
++
++/**
++ * check_short_pattern - [GENERIC] check if a pattern is in the buffer
++ * @buf: the buffer to search
++ * @td:	search pattern descriptor
++ *
++ * Check for a pattern at the given place. Used to search bad block tables and
++ * good / bad block identifiers. Same as check_pattern, but no optional empty
++ * check.
++ */
++static int check_short_pattern(uint8_t *buf, struct nand_bbt_descr *td)
++{
++	/* Compare the pattern */
++	if (memcmp(buf + td->offs, td->pattern, td->len))
++		return -1;
++	return 0;
++}
++
++/**
++ * add_marker_len - compute the length of the marker in data area
++ * @td: BBT descriptor used for computation
++ *
++ * The length will be 0 if the marker is located in OOB area.
++ */
++static u32 add_marker_len(struct nand_bbt_descr *td)
++{
++	u32 len;
++
++	if (!(td->options & NAND_BBT_NO_OOB))
++		return 0;
++
++	len = td->len;
++	if (td->options & NAND_BBT_VERSION)
++		len++;
++	return len;
++}
++
++/**
++ * read_bbt - [GENERIC] Read the bad block table starting from page
++ * @mtd: MTD device structure
++ * @buf: temporary buffer
++ * @page: the starting page
++ * @num: the number of bbt descriptors to read
++ * @td: the bbt describtion table
++ * @offs: block number offset in the table
++ *
++ * 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)
++{
++	int res, ret = 0, i, j, act = 0;
++	struct nand_chip *this = mtd_to_nand(mtd);
++	size_t retlen, len, totlen;
++	loff_t from;
++	int bits = td->options & NAND_BBT_NRBITS_MSK;
++	uint8_t msk = (uint8_t)((1 << bits) - 1);
++	u32 marker_len;
++	int reserved_block_code = td->reserved_block_code;
++
++	totlen = (num * bits) >> 3;
++	marker_len = add_marker_len(td);
++	from = ((loff_t)page) << this->page_shift;
++
++	while (totlen) {
++		len = min(totlen, (size_t)(1 << this->bbt_erase_shift));
++		if (marker_len) {
++			/*
++			 * In case the BBT marker is not in the OOB area it
++			 * will be just in the first page.
++			 */
++			len -= marker_len;
++			from += marker_len;
++			marker_len = 0;
++		}
++		res = mtd_read(mtd, from, len, &retlen, buf);
++		if (res < 0) {
++			if (mtd_is_eccerr(res)) {
++				pr_info("nand_bbt: ECC error in BBT at 0x%012llx\n",
++					from & ~mtd->writesize);
++				return res;
++			} else if (mtd_is_bitflip(res)) {
++				pr_info("nand_bbt: corrected error in BBT at 0x%012llx\n",
++					from & ~mtd->writesize);
++				ret = res;
++			} else {
++				pr_info("nand_bbt: error reading BBT\n");
++				return res;
++			}
++		}
++
++		/* Analyse data */
++		for (i = 0; i < len; i++) {
++			uint8_t dat = buf[i];
++			for (j = 0; j < 8; j += bits, act++) {
++				uint8_t tmp = (dat >> j) & msk;
++				if (tmp == msk)
++					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);
++					bbt_mark_entry(this, offs + act,
++							BBT_BLOCK_RESERVED);
++					mtd->ecc_stats.bbtblocks++;
++					continue;
++				}
++				/*
++				 * Leave it for now, if it's matured we can
++				 * 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);
++				/* Factory marked bad or worn out? */
++				if (tmp == 0)
++					bbt_mark_entry(this, offs + act,
++							BBT_BLOCK_FACTORY_BAD);
++				else
++					bbt_mark_entry(this, offs + act,
++							BBT_BLOCK_WORN);
++				mtd->ecc_stats.badblocks++;
++			}
++		}
++		totlen -= len;
++		from += len;
++	}
++	return ret;
++}
++
++/**
++ * read_abs_bbt - [GENERIC] Read the bad block table starting at a given page
++ * @mtd: MTD device structure
++ * @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
++ *        NAND_BBT_PERCHIP option is set
++ *
++ * 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)
++{
++	struct nand_chip *this = mtd_to_nand(mtd);
++	int res = 0, i;
++
++	if (td->options & NAND_BBT_PERCHIP) {
++		int offs = 0;
++		for (i = 0; i < this->numchips; i++) {
++			if (chip == -1 || chip == i)
++				res = read_bbt(mtd, buf, td->pages[i],
++					this->chipsize >> this->bbt_erase_shift,
++					td, offs);
++			if (res)
++				return res;
++			offs += this->chipsize >> this->bbt_erase_shift;
++		}
++	} else {
++		res = read_bbt(mtd, buf, td->pages[0],
++				mtd->size >> this->bbt_erase_shift, td, 0);
++		if (res)
++			return res;
++	}
++	return 0;
++}
++
++/* 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)
++{
++	size_t retlen;
++	size_t len;
++
++	len = td->len;
++	if (td->options & NAND_BBT_VERSION)
++		len++;
++
++	return mtd_read(mtd, offs, len, &retlen, buf);
++}
++
++/**
++ * scan_read_oob - [GENERIC] Scan data+OOB region to buffer
++ * @mtd: MTD device structure
++ * @buf: temporary buffer
++ * @offs: offset at which to scan
++ * @len: length of data region to read
++ *
++ * Scan read data from data+OOB. May traverse multiple pages, interleaving
++ * 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,
++			 size_t len)
++{
++	struct mtd_oob_ops ops;
++	int res, ret = 0;
++
++	ops.mode = MTD_OPS_PLACE_OOB;
++	ops.ooboffs = 0;
++	ops.ooblen = mtd->oobsize;
++
++	while (len > 0) {
++		ops.datbuf = buf;
++		ops.len = min(len, (size_t)mtd->writesize);
++		ops.oobbuf = buf + ops.len;
++
++		res = mtd_read_oob(mtd, offs, &ops);
++		if (res) {
++			if (!mtd_is_bitflip_or_eccerr(res))
++				return res;
++			else if (mtd_is_eccerr(res) || !ret)
++				ret = res;
++		}
++
++		buf += mtd->oobsize + mtd->writesize;
++		len -= mtd->writesize;
++		offs += mtd->writesize;
++	}
++	return ret;
++}
++
++static int scan_read(struct mtd_info *mtd, 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);
++	else
++		return scan_read_oob(mtd, 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,
++			  uint8_t *buf, uint8_t *oob)
++{
++	struct mtd_oob_ops ops;
++
++	ops.mode = MTD_OPS_PLACE_OOB;
++	ops.ooboffs = 0;
++	ops.ooblen = mtd->oobsize;
++	ops.datbuf = buf;
++	ops.oobbuf = oob;
++	ops.len = len;
++
++	return mtd_write_oob(mtd, offs, &ops);
++}
++
++static u32 bbt_get_ver_offs(struct mtd_info *mtd, struct nand_bbt_descr *td)
++{
++	u32 ver_offs = td->veroffs;
++
++	if (!(td->options & NAND_BBT_NO_OOB))
++		ver_offs += mtd->writesize;
++	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
++ * @buf: temporary buffer
++ * @td: descriptor for the bad block table
++ * @md:	descriptor for the bad block table mirror
++ *
++ * 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,
++			  struct nand_bbt_descr *td, struct nand_bbt_descr *md)
++{
++	struct nand_chip *this = mtd_to_nand(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)];
++		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)];
++		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,
++			   loff_t offs, uint8_t *buf, int numpages)
++{
++	struct mtd_oob_ops ops;
++	int j, ret;
++
++	ops.ooblen = mtd->oobsize;
++	ops.oobbuf = buf;
++	ops.ooboffs = 0;
++	ops.datbuf = NULL;
++	ops.mode = MTD_OPS_PLACE_OOB;
++
++	for (j = 0; j < numpages; j++) {
++		/*
++		 * Read the full oob until read_oob is fixed to handle single
++		 * byte reads for 16 bit buswidth.
++		 */
++		ret = mtd_read_oob(mtd, offs, &ops);
++		/* Ignore ECC errors when checking for BBM */
++		if (ret && !mtd_is_bitflip_or_eccerr(ret))
++			return ret;
++
++		if (check_short_pattern(buf, bd))
++			return 1;
++
++		offs += mtd->writesize;
++	}
++	return 0;
++}
++
++/**
++ * create_bbt - [GENERIC] Create a bad block table by scanning the device
++ * @mtd: MTD device structure
++ * @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
++ *        if NAND_BBT_PERCHIP option is set
++ *
++ * 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)
++{
++	struct nand_chip *this = mtd_to_nand(mtd);
++	int i, numblocks, numpages;
++	int startblock;
++	loff_t from;
++
++	pr_info("Scanning device for bad blocks\n");
++
++	if (bd->options & NAND_BBT_SCAN2NDPAGE)
++		numpages = 2;
++	else
++		numpages = 1;
++
++	if (chip == -1) {
++		numblocks = mtd->size >> this->bbt_erase_shift;
++		startblock = 0;
++		from = 0;
++	} else {
++		if (chip >= this->numchips) {
++			pr_warn("create_bbt(): chipnr (%d) > available chips (%d)\n",
++			       chip + 1, this->numchips);
++			return -EINVAL;
++		}
++		numblocks = this->chipsize >> this->bbt_erase_shift;
++		startblock = chip * numblocks;
++		numblocks += startblock;
++		from = (loff_t)startblock << this->bbt_erase_shift;
++	}
++
++	if (this->bbt_options & NAND_BBT_SCANLASTPAGE)
++		from += mtd->erasesize - (mtd->writesize * 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);
++		if (ret < 0)
++			return ret;
++
++		if (ret) {
++			bbt_mark_entry(this, i, BBT_BLOCK_FACTORY_BAD);
++			pr_warn("Bad eraseblock %d at 0x%012llx\n",
++				i, (unsigned long long)from);
++			mtd->ecc_stats.badblocks++;
++		}
++
++		from += (1 << this->bbt_erase_shift);
++	}
++	return 0;
++}
++
++/**
++ * search_bbt - [GENERIC] scan the device for a specific bad block table
++ * @mtd: MTD device structure
++ * @buf: temporary buffer
++ * @td: descriptor for the bad block table
++ *
++ * Read the bad block table by searching for a given ident pattern. Search is
++ * preformed either from the beginning up or from the end of the device
++ * downwards. The search starts always at the start of a block. If the option
++ * NAND_BBT_PERCHIP is given, each chip is searched for a bbt, which contains
++ * the bad block information of this chip. This is necessary to provide support
++ * for certain DOC devices.
++ *
++ * 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)
++{
++	struct nand_chip *this = mtd_to_nand(mtd);
++	int i, chips;
++	int startblock, block, dir;
++	int scanlen = mtd->writesize + mtd->oobsize;
++	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;
++		dir = -1;
++	} else {
++		startblock = 0;
++		dir = 1;
++	}
++
++	/* Do we have a bbt per chip? */
++	if (td->options & NAND_BBT_PERCHIP) {
++		chips = this->numchips;
++		bbtblocks = this->chipsize >> this->bbt_erase_shift;
++		startblock &= bbtblocks - 1;
++	} else {
++		chips = 1;
++		bbtblocks = mtd->size >> this->bbt_erase_shift;
++	}
++
++	for (i = 0; i < chips; i++) {
++		/* Reset version information */
++		td->version[i] = 0;
++		td->pages[i] = -1;
++		/* Scan the maximum number of blocks */
++		for (block = 0; block < td->maxblocks; block++) {
++
++			int actblock = startblock + dir * block;
++			loff_t offs = (loff_t)actblock << this->bbt_erase_shift;
++
++			/* Read first page */
++			scan_read(mtd, buf, offs, mtd->writesize, td);
++			if (!check_pattern(buf, scanlen, mtd->writesize, td)) {
++				td->pages[i] = actblock << blocktopage;
++				if (td->options & NAND_BBT_VERSION) {
++					offs = bbt_get_ver_offs(mtd, td);
++					td->version[i] = buf[offs];
++				}
++				break;
++			}
++		}
++		startblock += this->chipsize >> this->bbt_erase_shift;
++	}
++	/* Check, if we found a bbt for each requested chip */
++	for (i = 0; i < chips; i++) {
++		if (td->pages[i] == -1)
++			pr_warn("Bad block table not found for chip %d\n", i);
++		else
++			pr_info("Bad block table found at page %d, version 0x%02X\n",
++				td->pages[i], td->version[i]);
++	}
++	return 0;
++}
++
++/**
++ * search_read_bbts - [GENERIC] scan the device for bad block table(s)
++ * @mtd: MTD device structure
++ * @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,
++			     struct nand_bbt_descr *td,
++			     struct nand_bbt_descr *md)
++{
++	/* Search the primary table */
++	search_bbt(mtd, buf, td);
++
++	/* Search the mirror table */
++	if (md)
++		search_bbt(mtd, buf, md);
++}
++
++/**
++ * get_bbt_block - Get the first valid eraseblock suitable to store a BBT
++ * @this: the NAND device
++ * @td: the BBT description
++ * @md: the mirror BBT descriptor
++ * @chip: the CHIP selector
++ *
++ * This functions returns a positive block number pointing a valid eraseblock
++ * suitable to store a BBT (i.e. in the range reserved for BBT), or -ENOSPC if
++ * all blocks are already used of marked bad. If td->pages[chip] was already
++ * 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,
++			 struct nand_bbt_descr *md, int chip)
++{
++	int startblock, dir, page, numblocks, i;
++
++	/*
++	 * There was already a version of the table, reuse the page. This
++	 * applies for absolute placement too, as we have the page number in
++	 * td->pages.
++	 */
++	if (td->pages[chip] != -1)
++		return td->pages[chip] >>
++				(this->bbt_erase_shift - this->page_shift);
++
++	numblocks = (int)(this->chipsize >> this->bbt_erase_shift);
++	if (!(td->options & NAND_BBT_PERCHIP))
++		numblocks *= this->numchips;
++
++	/*
++	 * Automatic placement of the bad block table. Search direction
++	 * top -> down?
++	 */
++	if (td->options & NAND_BBT_LASTBLOCK) {
++		startblock = numblocks * (chip + 1) - 1;
++		dir = -1;
++	} else {
++		startblock = chip * numblocks;
++		dir = 1;
++	}
++
++	for (i = 0; i < td->maxblocks; i++) {
++		int block = startblock + dir * i;
++
++		/* Check, if the block is bad */
++		switch (bbt_get_entry(this, block)) {
++		case BBT_BLOCK_WORN:
++		case BBT_BLOCK_FACTORY_BAD:
++			continue;
++		}
++
++		page = block << (this->bbt_erase_shift - this->page_shift);
++
++		/* Check, if the block is used by the mirror table */
++		if (!md || md->pages[chip] != page)
++			return block;
++	}
++
++	return -ENOSPC;
++}
++
++/**
++ * mark_bbt_block_bad - Mark one of the block reserved for BBT bad
++ * @this: the NAND device
++ * @td: the BBT description
++ * @chip: the CHIP selector
++ * @block: the BBT block to mark
++ *
++ * Blocks reserved for BBT can become bad. This functions is an helper to mark
++ * such blocks as bad. It takes care of updating the in-memory BBT, marking the
++ * 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,
++			       struct nand_bbt_descr *td,
++			       int chip, int block)
++{
++	struct mtd_info *mtd = nand_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);
++	if (res)
++		pr_warn("nand_bbt: error %d while marking block %d bad\n",
++			res, block);
++
++	td->pages[chip] = -1;
++}
++
++/**
++ * write_bbt - [GENERIC] (Re)write the bad block table
++ * @mtd: MTD device structure
++ * @buf: temporary buffer
++ * @td: descriptor for the bad block table
++ * @md: descriptor for the bad block table mirror
++ * @chipsel: selector for a specific chip, -1 for all
++ *
++ * (Re)write the bad block table.
++ */
++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 erase_info einfo;
++	int i, res, chip = 0;
++	int bits, page, offs, numblocks, sft, sftmsk;
++	int nrchips, pageoffs, ooboffs;
++	uint8_t msk[4];
++	uint8_t rcode = td->reserved_block_code;
++	size_t retlen, len = 0;
++	loff_t to;
++	struct mtd_oob_ops ops;
++
++	ops.ooblen = mtd->oobsize;
++	ops.ooboffs = 0;
++	ops.datbuf = NULL;
++	ops.mode = MTD_OPS_PLACE_OOB;
++
++	if (!rcode)
++		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);
++		/* Full device write or specific chip? */
++		if (chipsel == -1) {
++			nrchips = this->numchips;
++		} else {
++			nrchips = chipsel + 1;
++			chip = chipsel;
++		}
++	} else {
++		numblocks = (int)(mtd->size >> this->bbt_erase_shift);
++		nrchips = 1;
++	}
++
++	/* Loop through the chips */
++	while (chip < nrchips) {
++		int block;
++
++		block = get_bbt_block(this, td, md, chip);
++		if (block < 0) {
++			pr_err("No space left to write bad block table\n");
++			res = block;
++			goto outerr;
++		}
++
++		/*
++		 * get_bbt_block() returns a block number, shift the value to
++		 * get a page number.
++		 */
++		page = block << (this->bbt_erase_shift - this->page_shift);
++
++		/* Set up shift count and masks for the flash table */
++		bits = td->options & NAND_BBT_NRBITS_MSK;
++		msk[2] = ~rcode;
++		switch (bits) {
++		case 1: sft = 3; sftmsk = 0x07; msk[0] = 0x00; msk[1] = 0x01;
++			msk[3] = 0x01;
++			break;
++		case 2: sft = 2; sftmsk = 0x06; msk[0] = 0x00; msk[1] = 0x01;
++			msk[3] = 0x03;
++			break;
++		case 4: sft = 1; sftmsk = 0x04; msk[0] = 0x00; msk[1] = 0x0C;
++			msk[3] = 0x0f;
++			break;
++		case 8: sft = 0; sftmsk = 0x00; msk[0] = 0x00; msk[1] = 0x0F;
++			msk[3] = 0xff;
++			break;
++		default: return -EINVAL;
++		}
++
++		to = ((loff_t)page) << this->page_shift;
++
++		/* 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;
++			res = mtd_read(mtd, to, len, &retlen, buf);
++			if (res < 0) {
++				if (retlen != len) {
++					pr_info("nand_bbt: error reading block for writing the bad block table\n");
++					return res;
++				}
++				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.oobbuf = &buf[len];
++			res = mtd_read_oob(mtd, to + mtd->writesize, &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;
++			/* Preset the bbt area with 0xff */
++			memset(&buf[offs], 0xff, (size_t)(numblocks >> sft));
++			ooboffs = len + (pageoffs * mtd->oobsize);
++
++		} else if (td->options & NAND_BBT_NO_OOB) {
++			ooboffs = 0;
++			offs = td->len;
++			/* The version byte */
++			if (td->options & NAND_BBT_VERSION)
++				offs++;
++			/* Calc length */
++			len = (size_t)(numblocks >> sft);
++			len += offs;
++			/* Make it page aligned! */
++			len = ALIGN(len, mtd->writesize);
++			/* Preset the buffer with 0xff */
++			memset(buf, 0xff, len);
++			/* Pattern is located at the begin of first page */
++			memcpy(buf, td->pattern, td->len);
++		} else {
++			/* Calc length */
++			len = (size_t)(numblocks >> sft);
++			/* Make it page aligned! */
++			len = ALIGN(len, mtd->writesize);
++			/* Preset the buffer with 0xff */
++			memset(buf, 0xff, len +
++			       (len >> this->page_shift)* mtd->oobsize);
++			offs = 0;
++			ooboffs = len;
++			/* Pattern is located in oob area of first page */
++			memcpy(&buf[ooboffs + td->offs], td->pattern, td->len);
++		}
++
++		if (td->options & NAND_BBT_VERSION)
++			buf[ooboffs + td->veroffs] = td->version[chip];
++
++		/* Walk through the memory table */
++		for (i = 0; i < numblocks; i++) {
++			uint8_t dat;
++			int sftcnt = (i << (3 - sft)) & sftmsk;
++			dat = bbt_get_entry(this, chip * numblocks + i);
++			/* Do not store the reserved bbt blocks! */
++			buf[offs + (i >> sft)] &= ~(msk[dat] << sftcnt);
++		}
++
++		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);
++		if (res < 0) {
++			pr_warn("nand_bbt: error while erasing BBT block %d\n",
++				res);
++			mark_bbt_block_bad(this, td, chip, block);
++			continue;
++		}
++
++		res = scan_write_bbt(mtd, 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);
++			mark_bbt_block_bad(this, td, chip, block);
++			continue;
++		}
++
++		pr_info("Bad block table written to 0x%012llx, version 0x%02X\n",
++			 (unsigned long long)to, td->version[chip]);
++
++		/* Mark it as used */
++		td->pages[chip++] = page;
++	}
++	return 0;
++
++ outerr:
++	pr_warn("nand_bbt: error while writing bad block table %d\n", res);
++	return res;
++}
++
++/**
++ * nand_memory_bbt - [GENERIC] create a memory based bad block table
++ * @mtd: MTD device structure
++ * @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)
++{
++	struct nand_chip *this = mtd_to_nand(mtd);
++
++	return create_bbt(mtd, this->buffers->databuf, bd, -1);
++}
++
++/**
++ * check_create - [GENERIC] create and write bbt(s) if necessary
++ * @mtd: MTD device structure
++ * @buf: temporary buffer
++ * @bd: descriptor for the good/bad block search pattern
++ *
++ * The function checks the results of the previous call to read_bbt and creates
++ * / updates the bbt(s) if necessary. Creation is necessary if no bbt was found
++ * 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)
++{
++	int i, chips, writeops, create, chipsel, res, res2;
++	struct nand_chip *this = mtd_to_nand(mtd);
++	struct nand_bbt_descr *td = this->bbt_td;
++	struct nand_bbt_descr *md = this->bbt_md;
++	struct nand_bbt_descr *rd, *rd2;
++
++	/* Do we have a bbt per chip? */
++	if (td->options & NAND_BBT_PERCHIP)
++		chips = this->numchips;
++	else
++		chips = 1;
++
++	for (i = 0; i < chips; i++) {
++		writeops = 0;
++		create = 0;
++		rd = NULL;
++		rd2 = NULL;
++		res = res2 = 0;
++		/* Per chip or per device? */
++		chipsel = (td->options & NAND_BBT_PERCHIP) ? i : -1;
++		/* Mirrored table available? */
++		if (md) {
++			if (td->pages[i] == -1 && md->pages[i] == -1) {
++				create = 1;
++				writeops = 0x03;
++			} else if (td->pages[i] == -1) {
++				rd = md;
++				writeops = 0x01;
++			} else if (md->pages[i] == -1) {
++				rd = td;
++				writeops = 0x02;
++			} else if (td->version[i] == md->version[i]) {
++				rd = td;
++				if (!(td->options & NAND_BBT_VERSION))
++					rd2 = md;
++			} else if (((int8_t)(td->version[i] - md->version[i])) > 0) {
++				rd = td;
++				writeops = 0x02;
++			} else {
++				rd = md;
++				writeops = 0x01;
++			}
++		} else {
++			if (td->pages[i] == -1) {
++				create = 1;
++				writeops = 0x01;
++			} else {
++				rd = td;
++			}
++		}
++
++		if (create) {
++			/* Create the bad block table by scanning the device? */
++			if (!(td->options & NAND_BBT_CREATE))
++				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);
++
++			td->version[i] = 1;
++			if (md)
++				md->version[i] = 1;
++		}
++
++		/* Read back first? */
++		if (rd) {
++			res = read_abs_bbt(mtd, buf, rd, chipsel);
++			if (mtd_is_eccerr(res)) {
++				/* Mark table as invalid */
++				rd->pages[i] = -1;
++				rd->version[i] = 0;
++				i--;
++				continue;
++			}
++		}
++		/* If they weren't versioned, read both */
++		if (rd2) {
++			res2 = read_abs_bbt(mtd, buf, rd2, chipsel);
++			if (mtd_is_eccerr(res2)) {
++				/* Mark table as invalid */
++				rd2->pages[i] = -1;
++				rd2->version[i] = 0;
++				i--;
++				continue;
++			}
++		}
++
++		/* Scrub the flash table(s)? */
++		if (mtd_is_bitflip(res) || mtd_is_bitflip(res2))
++			writeops = 0x03;
++
++		/* Update version numbers before writing */
++		if (md) {
++			td->version[i] = max(td->version[i], md->version[i]);
++			md->version[i] = td->version[i];
++		}
++
++		/* Write the bad block table to the device? */
++		if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) {
++			res = write_bbt(mtd, 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);
++			if (res < 0)
++				return res;
++		}
++	}
++	return 0;
++}
++
++/**
++ * mark_bbt_regions - [GENERIC] mark the bad block table regions
++ * @mtd: MTD device structure
++ * @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)
++{
++	struct nand_chip *this = mtd_to_nand(mtd);
++	int i, j, chips, block, nrblocks, update;
++	uint8_t oldval;
++
++	/* Do we have a bbt per chip? */
++	if (td->options & NAND_BBT_PERCHIP) {
++		chips = this->numchips;
++		nrblocks = (int)(this->chipsize >> this->bbt_erase_shift);
++	} else {
++		chips = 1;
++		nrblocks = (int)(mtd->size >> this->bbt_erase_shift);
++	}
++
++	for (i = 0; i < chips; i++) {
++		if ((td->options & NAND_BBT_ABSPAGE) ||
++		    !(td->options & NAND_BBT_WRITE)) {
++			if (td->pages[i] == -1)
++				continue;
++			block = td->pages[i] >> (this->bbt_erase_shift - this->page_shift);
++			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);
++			continue;
++		}
++		update = 0;
++		if (td->options & NAND_BBT_LASTBLOCK)
++			block = ((i + 1) * nrblocks) - td->maxblocks;
++		else
++			block = i * nrblocks;
++		for (j = 0; j < td->maxblocks; j++) {
++			oldval = bbt_get_entry(this, block);
++			bbt_mark_entry(this, block, BBT_BLOCK_RESERVED);
++			if (oldval != BBT_BLOCK_RESERVED)
++				update = 1;
++			block++;
++		}
++		/*
++		 * If we want reserved blocks to be recorded to flash, and some
++		 * 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);
++	}
++}
++
++/**
++ * verify_bbt_descr - verify the bad block description
++ * @mtd: MTD device structure
++ * @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)
++{
++	struct nand_chip *this = mtd_to_nand(mtd);
++	u32 pattern_len;
++	u32 bits;
++	u32 table_size;
++
++	if (!bd)
++		return;
++
++	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(!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(bd->offs);
++		if (bd->options & NAND_BBT_VERSION)
++			BUG_ON(bd->veroffs != bd->len);
++		BUG_ON(bd->options & NAND_BBT_SAVECONTENT);
++	}
++
++	if (bd->options & NAND_BBT_PERCHIP)
++		table_size = this->chipsize >> this->bbt_erase_shift;
++	else
++		table_size = mtd->size >> this->bbt_erase_shift;
++	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));
++}
++
++/**
++ * nand_scan_bbt - [NAND Interface] scan, find, read and maybe create bad block table(s)
++ * @mtd: MTD device structure
++ * @bd: descriptor for the good/bad block search pattern
++ *
++ * The function checks, if a bad block table(s) is/are already available. If
++ * not it scans the device for manufacturer marked good / bad blocks and writes
++ * the bad block table(s) to the selected place.
++ *
++ * 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)
++{
++	struct nand_chip *this = mtd_to_nand(mtd);
++	int len, res;
++	uint8_t *buf;
++	struct nand_bbt_descr *td = this->bbt_td;
++	struct nand_bbt_descr *md = this->bbt_md;
++
++	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)
++		return -ENOMEM;
++
++	/*
++	 * If no primary table decriptor is given, scan the device to build a
++	 * memory based bad block table.
++	 */
++	if (!td) {
++		if ((res = nand_memory_bbt(mtd, 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);
++
++	/* Allocate a temporary buffer for one eraseblock incl. oob */
++	len = (1 << this->bbt_erase_shift);
++	len += (len >> this->page_shift) * mtd->oobsize;
++	buf = vmalloc(len);
++	if (!buf) {
++		res = -ENOMEM;
++		goto err;
++	}
++
++	/* Is the bbt at a given page? */
++	if (td->options & NAND_BBT_ABSPAGE) {
++		read_abs_bbts(mtd, buf, td, md);
++	} else {
++		/* Search the bad block table using a pattern in oob */
++		search_read_bbts(mtd, buf, td, md);
++	}
++
++	res = check_create(mtd, buf, bd);
++	if (res)
++		goto err;
++
++	/* Prevent the bbt regions from erasing / writing */
++	mark_bbt_region(mtd, td);
++	if (md)
++		mark_bbt_region(mtd, md);
++
++	vfree(buf);
++	return 0;
++
++err:
++	kfree(this->bbt);
++	this->bbt = NULL;
++	return res;
++}
++
++/**
++ * nand_update_bbt - update bad block table(s)
++ * @mtd: MTD device structure
++ * @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)
++{
++	struct nand_chip *this = mtd_to_nand(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;
++
++	if (!this->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;
++	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);
++		chipsel = chip;
++	} else {
++		chip = 0;
++		chipsel = -1;
++	}
++
++	td->version[chip]++;
++	if (md)
++		md->version[chip]++;
++
++	/* Write the bad block table to the device? */
++	if (td->options & NAND_BBT_WRITE) {
++		res = write_bbt(mtd, 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);
++	}
++
++ out:
++	kfree(buf);
++	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_nand(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
++ * @offs: offset in the device
++ */
++int nand_isreserved_bbt(struct mtd_info *mtd, loff_t offs)
++{
++	struct nand_chip *this = mtd_to_nand(mtd);
++	int block;
++
++	block = (int)(offs >> this->bbt_erase_shift);
++	return bbt_get_entry(this, block) == BBT_BLOCK_RESERVED;
++}
++
++/**
++ * nand_isbad_bbt - [NAND Interface] Check if a block is bad
++ * @mtd: MTD device structure
++ * @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)
++{
++	struct nand_chip *this = mtd_to_nand(mtd);
++	int block, res;
++
++	block = (int)(offs >> this->bbt_erase_shift);
++	res = bbt_get_entry(this, block);
++
++	pr_debug("nand_isbad_bbt(): bbt info for offs 0x%08x: (block %d) 0x%02x\n",
++		 (unsigned int)offs, block, res);
++
++	switch (res) {
++	case BBT_BLOCK_GOOD:
++		return 0;
++	case BBT_BLOCK_WORN:
++		return 1;
++	case BBT_BLOCK_RESERVED:
++		return allowbbt ? 0 : 1;
++	}
++	return 1;
++}
++
++/**
++ * nand_markbad_bbt - [NAND Interface] Mark a block bad in the BBT
++ * @mtd: MTD device structure
++ * @offs: offset of the bad block
++ */
++int nand_markbad_bbt(struct mtd_info *mtd, loff_t offs)
++{
++	struct nand_chip *this = mtd_to_nand(mtd);
++	int block, ret = 0;
++
++	block = (int)(offs >> this->bbt_erase_shift);
++
++	/* 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);
++
++	return ret;
++}
+diff --git a/drivers/mtd/nand/raw/nand_bch.c b/drivers/mtd/nand/raw/nand_bch.c
+new file mode 100644
+index 0000000..505441c
+--- /dev/null
++++ b/drivers/mtd/nand/raw/nand_bch.c
+@@ -0,0 +1,234 @@
++/*
++ * This file provides ECC correction for more than 1 bit per block of data,
++ * using binary BCH codes. It relies on the generic BCH library lib/bch.c.
++ *
++ * Copyright © 2011 Ivan Djelic <ivan.djelic@parrot.com>
++ *
++ * 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 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.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this file; if not, write to the Free Software Foundation, Inc.,
++ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
++ */
++
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/bitops.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/rawnand.h>
++#include <linux/mtd/nand_bch.h>
++#include <linux/bch.h>
++
++/**
++ * struct nand_bch_control - private NAND BCH control structure
++ * @bch:       BCH control structure
++ * @errloc:    error location array
++ * @eccmask:   XOR ecc mask, allows erased pages to be decoded as valid
++ */
++struct nand_bch_control {
++	struct bch_control   *bch;
++	unsigned int         *errloc;
++	unsigned char        *eccmask;
++};
++
++/**
++ * nand_bch_calculate_ecc - [NAND Interface] Calculate ECC for data block
++ * @mtd:	MTD block structure
++ * @buf:	input buffer with raw data
++ * @code:	output buffer with ECC
++ */
++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);
++	struct nand_bch_control *nbc = chip->ecc.priv;
++	unsigned int i;
++
++	memset(code, 0, chip->ecc.bytes);
++	encode_bch(nbc->bch, buf, chip->ecc.size, code);
++
++	/* apply mask so that an erased page is a valid codeword */
++	for (i = 0; i < chip->ecc.bytes; i++)
++		code[i] ^= nbc->eccmask[i];
++
++	return 0;
++}
++EXPORT_SYMBOL(nand_bch_calculate_ecc);
++
++/**
++ * nand_bch_correct_data - [NAND Interface] Detect and correct bit error(s)
++ * @mtd:	MTD block structure
++ * @buf:	raw data read from the chip
++ * @read_ecc:	ECC from the chip
++ * @calc_ecc:	the ECC calculated from raw data
++ *
++ * Detect and correct bit errors for a data byte block
++ */
++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);
++	struct nand_bch_control *nbc = chip->ecc.priv;
++	unsigned int *errloc = nbc->errloc;
++	int i, count;
++
++	count = decode_bch(nbc->bch, NULL, chip->ecc.size, read_ecc, calc_ecc,
++			   NULL, errloc);
++	if (count > 0) {
++		for (i = 0; i < count; i++) {
++			if (errloc[i] < (chip->ecc.size*8))
++				/* error is located in data, correct it */
++				buf[errloc[i] >> 3] ^= (1 << (errloc[i] & 7));
++			/* else error in ecc, no action needed */
++
++			pr_debug("%s: corrected bitflip %u\n", __func__,
++					errloc[i]);
++		}
++	} else if (count < 0) {
++		printk(KERN_ERR "ecc unrecoverable error\n");
++		count = -EBADMSG;
++	}
++	return count;
++}
++EXPORT_SYMBOL(nand_bch_correct_data);
++
++/**
++ * nand_bch_init - [NAND Interface] Initialize NAND BCH error correction
++ * @mtd:	MTD block structure
++ *
++ * Returns:
++ *  a pointer to a new NAND BCH control structure, or NULL upon failure
++ *
++ * Initialize NAND BCH error correction. Parameters @eccsize and @eccbytes
++ * are used to compute BCH parameters m (Galois field order) and t (error
++ * correction capability). @eccbytes should be equal to the number of bytes
++ * required to store m*t bits, where m is such that 2^m-1 > @eccsize*8.
++ *
++ * Example: to configure 4 bit correction per 512 bytes, you should pass
++ * @eccsize = 512  (thus, m=13 is the smallest integer such that 2^m-1 > 512*8)
++ * @eccbytes = 7   (7 bytes are required to store m*t = 13*4 = 52 bits)
++ */
++struct nand_bch_control *nand_bch_init(struct mtd_info *mtd)
++{
++	struct nand_chip *nand = mtd_to_nand(mtd);
++	unsigned int m, t, eccsteps, i;
++	struct nand_bch_control *nbc = NULL;
++	unsigned char *erased_page;
++	unsigned int eccsize = nand->ecc.size;
++	unsigned int eccbytes = nand->ecc.bytes;
++	unsigned int eccstrength = nand->ecc.strength;
++
++	if (!eccbytes && eccstrength) {
++		eccbytes = DIV_ROUND_UP(eccstrength * fls(8 * eccsize), 8);
++		nand->ecc.bytes = eccbytes;
++	}
++
++	if (!eccsize || !eccbytes) {
++		printk(KERN_WARNING "ecc parameters not supplied\n");
++		goto fail;
++	}
++
++	m = fls(1+8*eccsize);
++	t = (eccbytes*8)/m;
++
++	nbc = kzalloc(sizeof(*nbc), GFP_KERNEL);
++	if (!nbc)
++		goto fail;
++
++	nbc->bch = init_bch(m, t, 0);
++	if (!nbc->bch)
++		goto fail;
++
++	/* verify that eccbytes has the expected value */
++	if (nbc->bch->ecc_bytes != eccbytes) {
++		printk(KERN_WARNING "invalid eccbytes %u, should be %u\n",
++		       eccbytes, nbc->bch->ecc_bytes);
++		goto fail;
++	}
++
++	eccsteps = mtd->writesize/eccsize;
++
++	/* Check that we have an oob layout description. */
++	if (!mtd->ooblayout) {
++		pr_warn("missing oob scheme");
++		goto fail;
++	}
++
++	/* sanity checks */
++	if (8*(eccsize+eccbytes) >= (1 << m)) {
++		printk(KERN_WARNING "eccsize %u is too large\n", eccsize);
++		goto fail;
++	}
++
++	/*
++	 * ecc->steps and ecc->total might be used by mtd->ooblayout->ecc(),
++	 * which is called by mtd_ooblayout_count_eccbytes().
++	 * Make sure they are properly initialized before calling
++	 * mtd_ooblayout_count_eccbytes().
++	 * FIXME: we should probably rework the sequencing in nand_scan_tail()
++	 * to avoid setting those fields twice.
++	 */
++	nand->ecc.steps = eccsteps;
++	nand->ecc.total = eccsteps * eccbytes;
++	if (mtd_ooblayout_count_eccbytes(mtd) != (eccsteps*eccbytes)) {
++		printk(KERN_WARNING "invalid ecc layout\n");
++		goto fail;
++	}
++
++	nbc->eccmask = kmalloc(eccbytes, GFP_KERNEL);
++	nbc->errloc = kmalloc(t*sizeof(*nbc->errloc), GFP_KERNEL);
++	if (!nbc->eccmask || !nbc->errloc)
++		goto fail;
++	/*
++	 * compute and store the inverted ecc of an erased ecc block
++	 */
++	erased_page = kmalloc(eccsize, GFP_KERNEL);
++	if (!erased_page)
++		goto fail;
++
++	memset(erased_page, 0xff, eccsize);
++	memset(nbc->eccmask, 0, eccbytes);
++	encode_bch(nbc->bch, erased_page, eccsize, nbc->eccmask);
++	kfree(erased_page);
++
++	for (i = 0; i < eccbytes; i++)
++		nbc->eccmask[i] ^= 0xff;
++
++	if (!eccstrength)
++		nand->ecc.strength = (eccbytes * 8) / fls(8 * eccsize);
++
++	return nbc;
++fail:
++	nand_bch_free(nbc);
++	return NULL;
++}
++EXPORT_SYMBOL(nand_bch_init);
++
++/**
++ * nand_bch_free - [NAND Interface] Release NAND BCH ECC resources
++ * @nbc:	NAND BCH control structure
++ */
++void nand_bch_free(struct nand_bch_control *nbc)
++{
++	if (nbc) {
++		free_bch(nbc->bch);
++		kfree(nbc->errloc);
++		kfree(nbc->eccmask);
++		kfree(nbc);
++	}
++}
++EXPORT_SYMBOL(nand_bch_free);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Ivan Djelic <ivan.djelic@parrot.com>");
++MODULE_DESCRIPTION("NAND software BCH ECC support");
+diff --git a/drivers/mtd/nand/raw/nand_ecc.c b/drivers/mtd/nand/raw/nand_ecc.c
+new file mode 100644
+index 0000000..7613a03
+--- /dev/null
++++ b/drivers/mtd/nand/raw/nand_ecc.c
+@@ -0,0 +1,533 @@
++/*
++ * This file contains an ECC algorithm that detects and corrects 1 bit
++ * errors in a 256 byte block of data.
++ *
++ * drivers/mtd/nand/nand_ecc.c
++ *
++ * Copyright © 2008 Koninklijke Philips Electronics NV.
++ *                  Author: Frans Meulenbroeks
++ *
++ * Completely replaces the previous ECC implementation which was written by:
++ *   Steven J. Hill (sjhill@realitydiluted.com)
++ *   Thomas Gleixner (tglx@linutronix.de)
++ *
++ * Information on how this algorithm works and how it was developed
++ * can be found in Documentation/mtd/nand_ecc.txt
++ *
++ * 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 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.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this file; if not, write to the Free Software Foundation, Inc.,
++ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
++ *
++ */
++
++/*
++ * The STANDALONE macro is useful when running the code outside the kernel
++ * e.g. when running the code in a testbed or a benchmark program.
++ * When STANDALONE is used, the module related macros are commented out
++ * as well as the linux include files.
++ * Instead a private definition of mtd_info is given to satisfy the compiler
++ * (the code does not use mtd_info, so the code does not care)
++ */
++#ifndef STANDALONE
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/rawnand.h>
++#include <linux/mtd/nand_ecc.h>
++#include <asm/byteorder.h>
++#else
++#include <stdint.h>
++struct mtd_info;
++#define EXPORT_SYMBOL(x)  /* x */
++
++#define MODULE_LICENSE(x)	/* x */
++#define MODULE_AUTHOR(x)	/* x */
++#define MODULE_DESCRIPTION(x)	/* x */
++
++#define pr_err printf
++#endif
++
++/*
++ * invparity is a 256 byte table that contains the odd parity
++ * for each byte. So if the number of bits in a byte is even,
++ * the array element is 1, and when the number of bits is odd
++ * the array eleemnt is 0.
++ */
++static const char invparity[256] = {
++	1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
++	0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
++	0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
++	1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
++	0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
++	1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
++	1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
++	0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
++	0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
++	1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
++	1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
++	0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
++	1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
++	0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
++	0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
++	1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1
++};
++
++/*
++ * bitsperbyte contains the number of bits per byte
++ * this is only used for testing and repairing parity
++ * (a precalculated value slightly improves performance)
++ */
++static const char bitsperbyte[256] = {
++	0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
++	1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
++	1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
++	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
++	1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
++	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
++	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
++	3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
++	1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
++	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
++	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
++	3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
++	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
++	3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
++	3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
++	4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8,
++};
++
++/*
++ * addressbits is a lookup table to filter out the bits from the xor-ed
++ * ECC data that identify the faulty location.
++ * this is only used for repairing parity
++ * see the comments in nand_correct_data for more details
++ */
++static const char addressbits[256] = {
++	0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01,
++	0x02, 0x02, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03,
++	0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01,
++	0x02, 0x02, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03,
++	0x04, 0x04, 0x05, 0x05, 0x04, 0x04, 0x05, 0x05,
++	0x06, 0x06, 0x07, 0x07, 0x06, 0x06, 0x07, 0x07,
++	0x04, 0x04, 0x05, 0x05, 0x04, 0x04, 0x05, 0x05,
++	0x06, 0x06, 0x07, 0x07, 0x06, 0x06, 0x07, 0x07,
++	0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01,
++	0x02, 0x02, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03,
++	0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01,
++	0x02, 0x02, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03,
++	0x04, 0x04, 0x05, 0x05, 0x04, 0x04, 0x05, 0x05,
++	0x06, 0x06, 0x07, 0x07, 0x06, 0x06, 0x07, 0x07,
++	0x04, 0x04, 0x05, 0x05, 0x04, 0x04, 0x05, 0x05,
++	0x06, 0x06, 0x07, 0x07, 0x06, 0x06, 0x07, 0x07,
++	0x08, 0x08, 0x09, 0x09, 0x08, 0x08, 0x09, 0x09,
++	0x0a, 0x0a, 0x0b, 0x0b, 0x0a, 0x0a, 0x0b, 0x0b,
++	0x08, 0x08, 0x09, 0x09, 0x08, 0x08, 0x09, 0x09,
++	0x0a, 0x0a, 0x0b, 0x0b, 0x0a, 0x0a, 0x0b, 0x0b,
++	0x0c, 0x0c, 0x0d, 0x0d, 0x0c, 0x0c, 0x0d, 0x0d,
++	0x0e, 0x0e, 0x0f, 0x0f, 0x0e, 0x0e, 0x0f, 0x0f,
++	0x0c, 0x0c, 0x0d, 0x0d, 0x0c, 0x0c, 0x0d, 0x0d,
++	0x0e, 0x0e, 0x0f, 0x0f, 0x0e, 0x0e, 0x0f, 0x0f,
++	0x08, 0x08, 0x09, 0x09, 0x08, 0x08, 0x09, 0x09,
++	0x0a, 0x0a, 0x0b, 0x0b, 0x0a, 0x0a, 0x0b, 0x0b,
++	0x08, 0x08, 0x09, 0x09, 0x08, 0x08, 0x09, 0x09,
++	0x0a, 0x0a, 0x0b, 0x0b, 0x0a, 0x0a, 0x0b, 0x0b,
++	0x0c, 0x0c, 0x0d, 0x0d, 0x0c, 0x0c, 0x0d, 0x0d,
++	0x0e, 0x0e, 0x0f, 0x0f, 0x0e, 0x0e, 0x0f, 0x0f,
++	0x0c, 0x0c, 0x0d, 0x0d, 0x0c, 0x0c, 0x0d, 0x0d,
++	0x0e, 0x0e, 0x0f, 0x0f, 0x0e, 0x0e, 0x0f, 0x0f
++};
++
++/**
++ * __nand_calculate_ecc - [NAND Interface] Calculate 3-byte ECC for 256/512-byte
++ *			 block
++ * @buf:	input buffer with raw data
++ * @eccsize:	data bytes per ECC step (256 or 512)
++ * @code:	output buffer with ECC
++ */
++void __nand_calculate_ecc(const unsigned char *buf, unsigned int eccsize,
++		       unsigned char *code)
++{
++	int i;
++	const uint32_t *bp = (uint32_t *)buf;
++	/* 256 or 512 bytes/ecc  */
++	const uint32_t eccsize_mult = eccsize >> 8;
++	uint32_t cur;		/* current value in buffer */
++	/* rp0..rp15..rp17 are the various accumulated parities (per byte) */
++	uint32_t rp0, rp1, rp2, rp3, rp4, rp5, rp6, rp7;
++	uint32_t rp8, rp9, rp10, rp11, rp12, rp13, rp14, rp15, rp16;
++	uint32_t uninitialized_var(rp17);	/* to make compiler happy */
++	uint32_t par;		/* the cumulative parity for all data */
++	uint32_t tmppar;	/* the cumulative parity for this iteration;
++				   for rp12, rp14 and rp16 at the end of the
++				   loop */
++
++	par = 0;
++	rp4 = 0;
++	rp6 = 0;
++	rp8 = 0;
++	rp10 = 0;
++	rp12 = 0;
++	rp14 = 0;
++	rp16 = 0;
++
++	/*
++	 * The loop is unrolled a number of times;
++	 * This avoids if statements to decide on which rp value to update
++	 * Also we process the data by longwords.
++	 * Note: passing unaligned data might give a performance penalty.
++	 * It is assumed that the buffers are aligned.
++	 * tmppar is the cumulative sum of this iteration.
++	 * needed for calculating rp12, rp14, rp16 and par
++	 * also used as a performance improvement for rp6, rp8 and rp10
++	 */
++	for (i = 0; i < eccsize_mult << 2; i++) {
++		cur = *bp++;
++		tmppar = cur;
++		rp4 ^= cur;
++		cur = *bp++;
++		tmppar ^= cur;
++		rp6 ^= tmppar;
++		cur = *bp++;
++		tmppar ^= cur;
++		rp4 ^= cur;
++		cur = *bp++;
++		tmppar ^= cur;
++		rp8 ^= tmppar;
++
++		cur = *bp++;
++		tmppar ^= cur;
++		rp4 ^= cur;
++		rp6 ^= cur;
++		cur = *bp++;
++		tmppar ^= cur;
++		rp6 ^= cur;
++		cur = *bp++;
++		tmppar ^= cur;
++		rp4 ^= cur;
++		cur = *bp++;
++		tmppar ^= cur;
++		rp10 ^= tmppar;
++
++		cur = *bp++;
++		tmppar ^= cur;
++		rp4 ^= cur;
++		rp6 ^= cur;
++		rp8 ^= cur;
++		cur = *bp++;
++		tmppar ^= cur;
++		rp6 ^= cur;
++		rp8 ^= cur;
++		cur = *bp++;
++		tmppar ^= cur;
++		rp4 ^= cur;
++		rp8 ^= cur;
++		cur = *bp++;
++		tmppar ^= cur;
++		rp8 ^= cur;
++
++		cur = *bp++;
++		tmppar ^= cur;
++		rp4 ^= cur;
++		rp6 ^= cur;
++		cur = *bp++;
++		tmppar ^= cur;
++		rp6 ^= cur;
++		cur = *bp++;
++		tmppar ^= cur;
++		rp4 ^= cur;
++		cur = *bp++;
++		tmppar ^= cur;
++
++		par ^= tmppar;
++		if ((i & 0x1) == 0)
++			rp12 ^= tmppar;
++		if ((i & 0x2) == 0)
++			rp14 ^= tmppar;
++		if (eccsize_mult == 2 && (i & 0x4) == 0)
++			rp16 ^= tmppar;
++	}
++
++	/*
++	 * handle the fact that we use longword operations
++	 * we'll bring rp4..rp14..rp16 back to single byte entities by
++	 * shifting and xoring first fold the upper and lower 16 bits,
++	 * then the upper and lower 8 bits.
++	 */
++	rp4 ^= (rp4 >> 16);
++	rp4 ^= (rp4 >> 8);
++	rp4 &= 0xff;
++	rp6 ^= (rp6 >> 16);
++	rp6 ^= (rp6 >> 8);
++	rp6 &= 0xff;
++	rp8 ^= (rp8 >> 16);
++	rp8 ^= (rp8 >> 8);
++	rp8 &= 0xff;
++	rp10 ^= (rp10 >> 16);
++	rp10 ^= (rp10 >> 8);
++	rp10 &= 0xff;
++	rp12 ^= (rp12 >> 16);
++	rp12 ^= (rp12 >> 8);
++	rp12 &= 0xff;
++	rp14 ^= (rp14 >> 16);
++	rp14 ^= (rp14 >> 8);
++	rp14 &= 0xff;
++	if (eccsize_mult == 2) {
++		rp16 ^= (rp16 >> 16);
++		rp16 ^= (rp16 >> 8);
++		rp16 &= 0xff;
++	}
++
++	/*
++	 * we also need to calculate the row parity for rp0..rp3
++	 * This is present in par, because par is now
++	 * rp3 rp3 rp2 rp2 in little endian and
++	 * rp2 rp2 rp3 rp3 in big endian
++	 * as well as
++	 * rp1 rp0 rp1 rp0 in little endian and
++	 * rp0 rp1 rp0 rp1 in big endian
++	 * First calculate rp2 and rp3
++	 */
++#ifdef __BIG_ENDIAN
++	rp2 = (par >> 16);
++	rp2 ^= (rp2 >> 8);
++	rp2 &= 0xff;
++	rp3 = par & 0xffff;
++	rp3 ^= (rp3 >> 8);
++	rp3 &= 0xff;
++#else
++	rp3 = (par >> 16);
++	rp3 ^= (rp3 >> 8);
++	rp3 &= 0xff;
++	rp2 = par & 0xffff;
++	rp2 ^= (rp2 >> 8);
++	rp2 &= 0xff;
++#endif
++
++	/* reduce par to 16 bits then calculate rp1 and rp0 */
++	par ^= (par >> 16);
++#ifdef __BIG_ENDIAN
++	rp0 = (par >> 8) & 0xff;
++	rp1 = (par & 0xff);
++#else
++	rp1 = (par >> 8) & 0xff;
++	rp0 = (par & 0xff);
++#endif
++
++	/* finally reduce par to 8 bits */
++	par ^= (par >> 8);
++	par &= 0xff;
++
++	/*
++	 * and calculate rp5..rp15..rp17
++	 * note that par = rp4 ^ rp5 and due to the commutative property
++	 * of the ^ operator we can say:
++	 * rp5 = (par ^ rp4);
++	 * The & 0xff seems superfluous, but benchmarking learned that
++	 * leaving it out gives slightly worse results. No idea why, probably
++	 * it has to do with the way the pipeline in pentium is organized.
++	 */
++	rp5 = (par ^ rp4) & 0xff;
++	rp7 = (par ^ rp6) & 0xff;
++	rp9 = (par ^ rp8) & 0xff;
++	rp11 = (par ^ rp10) & 0xff;
++	rp13 = (par ^ rp12) & 0xff;
++	rp15 = (par ^ rp14) & 0xff;
++	if (eccsize_mult == 2)
++		rp17 = (par ^ rp16) & 0xff;
++
++	/*
++	 * Finally calculate the ECC bits.
++	 * Again here it might seem that there are performance optimisations
++	 * possible, but benchmarks showed that on the system this is developed
++	 * the code below is the fastest
++	 */
++#ifdef CONFIG_MTD_NAND_ECC_SMC
++	code[0] =
++	    (invparity[rp7] << 7) |
++	    (invparity[rp6] << 6) |
++	    (invparity[rp5] << 5) |
++	    (invparity[rp4] << 4) |
++	    (invparity[rp3] << 3) |
++	    (invparity[rp2] << 2) |
++	    (invparity[rp1] << 1) |
++	    (invparity[rp0]);
++	code[1] =
++	    (invparity[rp15] << 7) |
++	    (invparity[rp14] << 6) |
++	    (invparity[rp13] << 5) |
++	    (invparity[rp12] << 4) |
++	    (invparity[rp11] << 3) |
++	    (invparity[rp10] << 2) |
++	    (invparity[rp9] << 1)  |
++	    (invparity[rp8]);
++#else
++	code[1] =
++	    (invparity[rp7] << 7) |
++	    (invparity[rp6] << 6) |
++	    (invparity[rp5] << 5) |
++	    (invparity[rp4] << 4) |
++	    (invparity[rp3] << 3) |
++	    (invparity[rp2] << 2) |
++	    (invparity[rp1] << 1) |
++	    (invparity[rp0]);
++	code[0] =
++	    (invparity[rp15] << 7) |
++	    (invparity[rp14] << 6) |
++	    (invparity[rp13] << 5) |
++	    (invparity[rp12] << 4) |
++	    (invparity[rp11] << 3) |
++	    (invparity[rp10] << 2) |
++	    (invparity[rp9] << 1)  |
++	    (invparity[rp8]);
++#endif
++	if (eccsize_mult == 1)
++		code[2] =
++		    (invparity[par & 0xf0] << 7) |
++		    (invparity[par & 0x0f] << 6) |
++		    (invparity[par & 0xcc] << 5) |
++		    (invparity[par & 0x33] << 4) |
++		    (invparity[par & 0xaa] << 3) |
++		    (invparity[par & 0x55] << 2) |
++		    3;
++	else
++		code[2] =
++		    (invparity[par & 0xf0] << 7) |
++		    (invparity[par & 0x0f] << 6) |
++		    (invparity[par & 0xcc] << 5) |
++		    (invparity[par & 0x33] << 4) |
++		    (invparity[par & 0xaa] << 3) |
++		    (invparity[par & 0x55] << 2) |
++		    (invparity[rp17] << 1) |
++		    (invparity[rp16] << 0);
++}
++EXPORT_SYMBOL(__nand_calculate_ecc);
++
++/**
++ * nand_calculate_ecc - [NAND Interface] Calculate 3-byte ECC for 256/512-byte
++ *			 block
++ * @mtd:	MTD block structure
++ * @buf:	input buffer with raw data
++ * @code:	output buffer with ECC
++ */
++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);
++
++	return 0;
++}
++EXPORT_SYMBOL(nand_calculate_ecc);
++
++/**
++ * __nand_correct_data - [NAND Interface] Detect and correct bit error(s)
++ * @buf:	raw data read from the chip
++ * @read_ecc:	ECC from the chip
++ * @calc_ecc:	the ECC calculated from raw data
++ * @eccsize:	data bytes per ECC step (256 or 512)
++ *
++ * Detect and correct a 1 bit error for eccsize byte block
++ */
++int __nand_correct_data(unsigned char *buf,
++			unsigned char *read_ecc, unsigned char *calc_ecc,
++			unsigned int eccsize)
++{
++	unsigned char b0, b1, b2, bit_addr;
++	unsigned int byte_addr;
++	/* 256 or 512 bytes/ecc  */
++	const uint32_t eccsize_mult = eccsize >> 8;
++
++	/*
++	 * b0 to b2 indicate which bit is faulty (if any)
++	 * we might need the xor result  more than once,
++	 * so keep them in a local var
++	*/
++#ifdef CONFIG_MTD_NAND_ECC_SMC
++	b0 = read_ecc[0] ^ calc_ecc[0];
++	b1 = read_ecc[1] ^ calc_ecc[1];
++#else
++	b0 = read_ecc[1] ^ calc_ecc[1];
++	b1 = read_ecc[0] ^ calc_ecc[0];
++#endif
++	b2 = read_ecc[2] ^ calc_ecc[2];
++
++	/* check if there are any bitfaults */
++
++	/* repeated if statements are slightly more efficient than switch ... */
++	/* ordered in order of likelihood */
++
++	if ((b0 | b1 | b2) == 0)
++		return 0;	/* no error */
++
++	if ((((b0 ^ (b0 >> 1)) & 0x55) == 0x55) &&
++	    (((b1 ^ (b1 >> 1)) & 0x55) == 0x55) &&
++	    ((eccsize_mult == 1 && ((b2 ^ (b2 >> 1)) & 0x54) == 0x54) ||
++	     (eccsize_mult == 2 && ((b2 ^ (b2 >> 1)) & 0x55) == 0x55))) {
++	/* single bit error */
++		/*
++		 * rp17/rp15/13/11/9/7/5/3/1 indicate which byte is the faulty
++		 * byte, cp 5/3/1 indicate the faulty bit.
++		 * A lookup table (called addressbits) is used to filter
++		 * the bits from the byte they are in.
++		 * A marginal optimisation is possible by having three
++		 * different lookup tables.
++		 * One as we have now (for b0), one for b2
++		 * (that would avoid the >> 1), and one for b1 (with all values
++		 * << 4). However it was felt that introducing two more tables
++		 * hardly justify the gain.
++		 *
++		 * The b2 shift is there to get rid of the lowest two bits.
++		 * We could also do addressbits[b2] >> 1 but for the
++		 * performance it does not make any difference
++		 */
++		if (eccsize_mult == 1)
++			byte_addr = (addressbits[b1] << 4) + addressbits[b0];
++		else
++			byte_addr = (addressbits[b2 & 0x3] << 8) +
++				    (addressbits[b1] << 4) + addressbits[b0];
++		bit_addr = addressbits[b2 >> 2];
++		/* flip the bit */
++		buf[byte_addr] ^= (1 << bit_addr);
++		return 1;
++
++	}
++	/* count nr of bits; use table lookup, faster than calculating it */
++	if ((bitsperbyte[b0] + bitsperbyte[b1] + bitsperbyte[b2]) == 1)
++		return 1;	/* error in ECC data; no action needed */
++
++	pr_err("%s: uncorrectable ECC error\n", __func__);
++	return -EBADMSG;
++}
++EXPORT_SYMBOL(__nand_correct_data);
++
++/**
++ * nand_correct_data - [NAND Interface] Detect and correct bit error(s)
++ * @mtd:	MTD block structure
++ * @buf:	raw data read from the chip
++ * @read_ecc:	ECC from the chip
++ * @calc_ecc:	the ECC calculated from raw data
++ *
++ * Detect and correct a 1 bit error for 256/512 byte block
++ */
++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);
++}
++EXPORT_SYMBOL(nand_correct_data);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Frans Meulenbroeks <fransmeulenbroeks@gmail.com>");
++MODULE_DESCRIPTION("Generic NAND ECC support");
+diff --git a/drivers/mtd/nand/raw/nand_hynix.c b/drivers/mtd/nand/raw/nand_hynix.c
+new file mode 100644
+index 0000000..985751e
+--- /dev/null
++++ b/drivers/mtd/nand/raw/nand_hynix.c
+@@ -0,0 +1,631 @@
++/*
++ * Copyright (C) 2017 Free Electrons
++ * Copyright (C) 2017 NextThing Co
++ *
++ * Author: Boris Brezillon <boris.brezillon@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 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/mtd/rawnand.h>
++#include <linux/sizes.h>
++#include <linux/slab.h>
++
++#define NAND_HYNIX_CMD_SET_PARAMS	0x36
++#define NAND_HYNIX_CMD_APPLY_PARAMS	0x16
++
++#define NAND_HYNIX_1XNM_RR_REPEAT	8
++
++/**
++ * struct hynix_read_retry - read-retry data
++ * @nregs: number of register to set when applying a new read-retry mode
++ * @regs: register offsets (NAND chip dependent)
++ * @values: array of values to set in registers. The array size is equal to
++ *	    (nregs * nmodes)
++ */
++struct hynix_read_retry {
++	int nregs;
++	const u8 *regs;
++	u8 values[0];
++};
++
++/**
++ * struct hynix_nand - private Hynix NAND struct
++ * @nand_technology: manufacturing process expressed in picometer
++ * @read_retry: read-retry information
++ */
++struct hynix_nand {
++	const struct hynix_read_retry *read_retry;
++};
++
++/**
++ * struct hynix_read_retry_otp - structure describing how the read-retry OTP
++ *				 area
++ * @nregs: number of hynix private registers to set before reading the reading
++ *	   the OTP area
++ * @regs: registers that should be configured
++ * @values: values that should be set in regs
++ * @page: the address to pass to the READ_PAGE command. Depends on the NAND
++ *	  chip
++ * @size: size of the read-retry OTP section
++ */
++struct hynix_read_retry_otp {
++	int nregs;
++	const u8 *regs;
++	const u8 *values;
++	int page;
++	int size;
++};
++
++static bool hynix_nand_has_valid_jedecid(struct nand_chip *chip)
++{
++	struct mtd_info *mtd = nand_to_mtd(chip);
++	u8 jedecid[6] = { };
++	int i = 0;
++
++	chip->cmdfunc(mtd, NAND_CMD_READID, 0x40, -1);
++	for (i = 0; i < 5; i++)
++		jedecid[i] = chip->read_byte(mtd);
++
++	return !strcmp("JEDEC", jedecid);
++}
++
++static int hynix_nand_setup_read_retry(struct mtd_info *mtd, int retry_mode)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct hynix_nand *hynix = nand_get_manufacturer_data(chip);
++	const u8 *values;
++	int status;
++	int i;
++
++	values = hynix->read_retry->values +
++		 (retry_mode * hynix->read_retry->nregs);
++
++	/* Enter 'Set Hynix Parameters' mode */
++	chip->cmdfunc(mtd, NAND_HYNIX_CMD_SET_PARAMS, -1, -1);
++
++	/*
++	 * Configure the NAND in the requested read-retry mode.
++	 * This is done by setting pre-defined values in internal NAND
++	 * registers.
++	 *
++	 * The set of registers is NAND specific, and the values are either
++	 * predefined or extracted from an OTP area on the NAND (values are
++	 * probably tweaked at production in this case).
++	 */
++	for (i = 0; i < hynix->read_retry->nregs; i++) {
++		int column = hynix->read_retry->regs[i];
++
++		column |= column << 8;
++		chip->cmdfunc(mtd, NAND_CMD_NONE, column, -1);
++		chip->write_byte(mtd, values[i]);
++	}
++
++	/* Apply the new settings. */
++	chip->cmdfunc(mtd, NAND_HYNIX_CMD_APPLY_PARAMS, -1, -1);
++
++	status = chip->waitfunc(mtd, chip);
++	if (status & NAND_STATUS_FAIL)
++		return -EIO;
++
++	return 0;
++}
++
++/**
++ * hynix_get_majority - get the value that is occurring the most in a given
++ *			set of values
++ * @in: the array of values to test
++ * @repeat: the size of the in array
++ * @out: pointer used to store the output value
++ *
++ * This function implements the 'majority check' logic that is supposed to
++ * overcome the unreliability of MLC NANDs when reading the OTP area storing
++ * the read-retry parameters.
++ *
++ * It's based on a pretty simple assumption: if we repeat the same value
++ * several times and then take the one that is occurring the most, we should
++ * find the correct value.
++ * Let's hope this dummy algorithm prevents us from losing the read-retry
++ * parameters.
++ */
++static int hynix_get_majority(const u8 *in, int repeat, u8 *out)
++{
++	int i, j, half = repeat / 2;
++
++	/*
++	 * We only test the first half of the in array because we must ensure
++	 * that the value is at least occurring repeat / 2 times.
++	 *
++	 * This loop is suboptimal since we may count the occurrences of the
++	 * same value several time, but we are doing that on small sets, which
++	 * makes it acceptable.
++	 */
++	for (i = 0; i < half; i++) {
++		int cnt = 0;
++		u8 val = in[i];
++
++		/* Count all values that are matching the one at index i. */
++		for (j = i + 1; j < repeat; j++) {
++			if (in[j] == val)
++				cnt++;
++		}
++
++		/* We found a value occurring more than repeat / 2. */
++		if (cnt > half) {
++			*out = val;
++			return 0;
++		}
++	}
++
++	return -EIO;
++}
++
++static int hynix_read_rr_otp(struct nand_chip *chip,
++			     const struct hynix_read_retry_otp *info,
++			     void *buf)
++{
++	struct mtd_info *mtd = nand_to_mtd(chip);
++	int i;
++
++	chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
++
++	chip->cmdfunc(mtd, NAND_HYNIX_CMD_SET_PARAMS, -1, -1);
++
++	for (i = 0; i < info->nregs; i++) {
++		int column = info->regs[i];
++
++		column |= column << 8;
++		chip->cmdfunc(mtd, NAND_CMD_NONE, column, -1);
++		chip->write_byte(mtd, info->values[i]);
++	}
++
++	chip->cmdfunc(mtd, NAND_HYNIX_CMD_APPLY_PARAMS, -1, -1);
++
++	/* Sequence to enter OTP mode? */
++	chip->cmdfunc(mtd, 0x17, -1, -1);
++	chip->cmdfunc(mtd, 0x04, -1, -1);
++	chip->cmdfunc(mtd, 0x19, -1, -1);
++
++	/* Now read the page */
++	chip->cmdfunc(mtd, NAND_CMD_READ0, 0x0, info->page);
++	chip->read_buf(mtd, buf, info->size);
++
++	/* Put everything back to normal */
++	chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
++	chip->cmdfunc(mtd, NAND_HYNIX_CMD_SET_PARAMS, 0x38, -1);
++	chip->write_byte(mtd, 0x0);
++	chip->cmdfunc(mtd, NAND_HYNIX_CMD_APPLY_PARAMS, -1, -1);
++	chip->cmdfunc(mtd, NAND_CMD_READ0, 0x0, -1);
++
++	return 0;
++}
++
++#define NAND_HYNIX_1XNM_RR_COUNT_OFFS				0
++#define NAND_HYNIX_1XNM_RR_REG_COUNT_OFFS			8
++#define NAND_HYNIX_1XNM_RR_SET_OFFS(x, setsize, inv)		\
++	(16 + ((((x) * 2) + ((inv) ? 1 : 0)) * (setsize)))
++
++static int hynix_mlc_1xnm_rr_value(const u8 *buf, int nmodes, int nregs,
++				   int mode, int reg, bool inv, u8 *val)
++{
++	u8 tmp[NAND_HYNIX_1XNM_RR_REPEAT];
++	int val_offs = (mode * nregs) + reg;
++	int set_size = nmodes * nregs;
++	int i, ret;
++
++	for (i = 0; i < NAND_HYNIX_1XNM_RR_REPEAT; i++) {
++		int set_offs = NAND_HYNIX_1XNM_RR_SET_OFFS(i, set_size, inv);
++
++		tmp[i] = buf[val_offs + set_offs];
++	}
++
++	ret = hynix_get_majority(tmp, NAND_HYNIX_1XNM_RR_REPEAT, val);
++	if (ret)
++		return ret;
++
++	if (inv)
++		*val = ~*val;
++
++	return 0;
++}
++
++static u8 hynix_1xnm_mlc_read_retry_regs[] = {
++	0xcc, 0xbf, 0xaa, 0xab, 0xcd, 0xad, 0xae, 0xaf
++};
++
++static int hynix_mlc_1xnm_rr_init(struct nand_chip *chip,
++				  const struct hynix_read_retry_otp *info)
++{
++	struct hynix_nand *hynix = nand_get_manufacturer_data(chip);
++	struct hynix_read_retry *rr = NULL;
++	int ret, i, j;
++	u8 nregs, nmodes;
++	u8 *buf;
++
++	buf = kmalloc(info->size, GFP_KERNEL);
++	if (!buf)
++		return -ENOMEM;
++
++	ret = hynix_read_rr_otp(chip, info, buf);
++	if (ret)
++		goto out;
++
++	ret = hynix_get_majority(buf, NAND_HYNIX_1XNM_RR_REPEAT,
++				 &nmodes);
++	if (ret)
++		goto out;
++
++	ret = hynix_get_majority(buf + NAND_HYNIX_1XNM_RR_REPEAT,
++				 NAND_HYNIX_1XNM_RR_REPEAT,
++				 &nregs);
++	if (ret)
++		goto out;
++
++	rr = kzalloc(sizeof(*rr) + (nregs * nmodes), GFP_KERNEL);
++	if (!rr) {
++		ret = -ENOMEM;
++		goto out;
++	}
++
++	for (i = 0; i < nmodes; i++) {
++		for (j = 0; j < nregs; j++) {
++			u8 *val = rr->values + (i * nregs);
++
++			ret = hynix_mlc_1xnm_rr_value(buf, nmodes, nregs, i, j,
++						      false, val);
++			if (!ret)
++				continue;
++
++			ret = hynix_mlc_1xnm_rr_value(buf, nmodes, nregs, i, j,
++						      true, val);
++			if (ret)
++				goto out;
++		}
++	}
++
++	rr->nregs = nregs;
++	rr->regs = hynix_1xnm_mlc_read_retry_regs;
++	hynix->read_retry = rr;
++	chip->setup_read_retry = hynix_nand_setup_read_retry;
++	chip->read_retries = nmodes;
++
++out:
++	kfree(buf);
++
++	if (ret)
++		kfree(rr);
++
++	return ret;
++}
++
++static const u8 hynix_mlc_1xnm_rr_otp_regs[] = { 0x38 };
++static const u8 hynix_mlc_1xnm_rr_otp_values[] = { 0x52 };
++
++static const struct hynix_read_retry_otp hynix_mlc_1xnm_rr_otps[] = {
++	{
++		.nregs = ARRAY_SIZE(hynix_mlc_1xnm_rr_otp_regs),
++		.regs = hynix_mlc_1xnm_rr_otp_regs,
++		.values = hynix_mlc_1xnm_rr_otp_values,
++		.page = 0x21f,
++		.size = 784
++	},
++	{
++		.nregs = ARRAY_SIZE(hynix_mlc_1xnm_rr_otp_regs),
++		.regs = hynix_mlc_1xnm_rr_otp_regs,
++		.values = hynix_mlc_1xnm_rr_otp_values,
++		.page = 0x200,
++		.size = 528,
++	},
++};
++
++static int hynix_nand_rr_init(struct nand_chip *chip)
++{
++	int i, ret = 0;
++	bool valid_jedecid;
++
++	valid_jedecid = hynix_nand_has_valid_jedecid(chip);
++
++	/*
++	 * We only support read-retry for 1xnm NANDs, and those NANDs all
++	 * expose a valid JEDEC ID.
++	 */
++	if (valid_jedecid) {
++		u8 nand_tech = chip->id.data[5] >> 4;
++
++		/* 1xnm technology */
++		if (nand_tech == 4) {
++			for (i = 0; i < ARRAY_SIZE(hynix_mlc_1xnm_rr_otps);
++			     i++) {
++				/*
++				 * FIXME: Hynix recommend to copy the
++				 * read-retry OTP area into a normal page.
++				 */
++				ret = hynix_mlc_1xnm_rr_init(chip,
++						hynix_mlc_1xnm_rr_otps);
++				if (!ret)
++					break;
++			}
++		}
++	}
++
++	if (ret)
++		pr_warn("failed to initialize read-retry infrastructure");
++
++	return 0;
++}
++
++static void hynix_nand_extract_oobsize(struct nand_chip *chip,
++				       bool valid_jedecid)
++{
++	struct mtd_info *mtd = nand_to_mtd(chip);
++	u8 oobsize;
++
++	oobsize = ((chip->id.data[3] >> 2) & 0x3) |
++		  ((chip->id.data[3] >> 4) & 0x4);
++
++	if (valid_jedecid) {
++		switch (oobsize) {
++		case 0:
++			mtd->oobsize = 2048;
++			break;
++		case 1:
++			mtd->oobsize = 1664;
++			break;
++		case 2:
++			mtd->oobsize = 1024;
++			break;
++		case 3:
++			mtd->oobsize = 640;
++			break;
++		default:
++			/*
++			 * We should never reach this case, but if that
++			 * happens, this probably means Hynix decided to use
++			 * a different extended ID format, and we should find
++			 * a way to support it.
++			 */
++			WARN(1, "Invalid OOB size");
++			break;
++		}
++	} else {
++		switch (oobsize) {
++		case 0:
++			mtd->oobsize = 128;
++			break;
++		case 1:
++			mtd->oobsize = 224;
++			break;
++		case 2:
++			mtd->oobsize = 448;
++			break;
++		case 3:
++			mtd->oobsize = 64;
++			break;
++		case 4:
++			mtd->oobsize = 32;
++			break;
++		case 5:
++			mtd->oobsize = 16;
++			break;
++		case 6:
++			mtd->oobsize = 640;
++			break;
++		default:
++			/*
++			 * We should never reach this case, but if that
++			 * happens, this probably means Hynix decided to use
++			 * a different extended ID format, and we should find
++			 * a way to support it.
++			 */
++			WARN(1, "Invalid OOB size");
++			break;
++		}
++	}
++}
++
++static void hynix_nand_extract_ecc_requirements(struct nand_chip *chip,
++						bool valid_jedecid)
++{
++	u8 ecc_level = (chip->id.data[4] >> 4) & 0x7;
++
++	if (valid_jedecid) {
++		/* Reference: H27UCG8T2E datasheet */
++		chip->ecc_step_ds = 1024;
++
++		switch (ecc_level) {
++		case 0:
++			chip->ecc_step_ds = 0;
++			chip->ecc_strength_ds = 0;
++			break;
++		case 1:
++			chip->ecc_strength_ds = 4;
++			break;
++		case 2:
++			chip->ecc_strength_ds = 24;
++			break;
++		case 3:
++			chip->ecc_strength_ds = 32;
++			break;
++		case 4:
++			chip->ecc_strength_ds = 40;
++			break;
++		case 5:
++			chip->ecc_strength_ds = 50;
++			break;
++		case 6:
++			chip->ecc_strength_ds = 60;
++			break;
++		default:
++			/*
++			 * We should never reach this case, but if that
++			 * happens, this probably means Hynix decided to use
++			 * a different extended ID format, and we should find
++			 * a way to support it.
++			 */
++			WARN(1, "Invalid ECC requirements");
++		}
++	} else {
++		/*
++		 * The ECC requirements field meaning depends on the
++		 * NAND technology.
++		 */
++		u8 nand_tech = chip->id.data[5] & 0x7;
++
++		if (nand_tech < 3) {
++			/* > 26nm, reference: H27UBG8T2A datasheet */
++			if (ecc_level < 5) {
++				chip->ecc_step_ds = 512;
++				chip->ecc_strength_ds = 1 << ecc_level;
++			} else if (ecc_level < 7) {
++				if (ecc_level == 5)
++					chip->ecc_step_ds = 2048;
++				else
++					chip->ecc_step_ds = 1024;
++				chip->ecc_strength_ds = 24;
++			} else {
++				/*
++				 * We should never reach this case, but if that
++				 * happens, this probably means Hynix decided
++				 * to use a different extended ID format, and
++				 * we should find a way to support it.
++				 */
++				WARN(1, "Invalid ECC requirements");
++			}
++		} else {
++			/* <= 26nm, reference: H27UBG8T2B datasheet */
++			if (!ecc_level) {
++				chip->ecc_step_ds = 0;
++				chip->ecc_strength_ds = 0;
++			} else if (ecc_level < 5) {
++				chip->ecc_step_ds = 512;
++				chip->ecc_strength_ds = 1 << (ecc_level - 1);
++			} else {
++				chip->ecc_step_ds = 1024;
++				chip->ecc_strength_ds = 24 +
++							(8 * (ecc_level - 5));
++			}
++		}
++	}
++}
++
++static void hynix_nand_extract_scrambling_requirements(struct nand_chip *chip,
++						       bool valid_jedecid)
++{
++	u8 nand_tech;
++
++	/* We need scrambling on all TLC NANDs*/
++	if (chip->bits_per_cell > 2)
++		chip->options |= NAND_NEED_SCRAMBLING;
++
++	/* And on MLC NANDs with sub-3xnm process */
++	if (valid_jedecid) {
++		nand_tech = chip->id.data[5] >> 4;
++
++		/* < 3xnm */
++		if (nand_tech > 0)
++			chip->options |= NAND_NEED_SCRAMBLING;
++	} else {
++		nand_tech = chip->id.data[5] & 0x7;
++
++		/* < 32nm */
++		if (nand_tech > 2)
++			chip->options |= NAND_NEED_SCRAMBLING;
++	}
++}
++
++static void hynix_nand_decode_id(struct nand_chip *chip)
++{
++	struct mtd_info *mtd = nand_to_mtd(chip);
++	bool valid_jedecid;
++	u8 tmp;
++
++	/*
++	 * Exclude all SLC NANDs from this advanced detection scheme.
++	 * According to the ranges defined in several datasheets, it might
++	 * appear that even SLC NANDs could fall in this extended ID scheme.
++	 * If that the case rework the test to let SLC NANDs go through the
++	 * detection process.
++	 */
++	if (chip->id.len < 6 || nand_is_slc(chip)) {
++		nand_decode_ext_id(chip);
++		return;
++	}
++
++	/* Extract pagesize */
++	mtd->writesize = 2048 << (chip->id.data[3] & 0x03);
++
++	tmp = (chip->id.data[3] >> 4) & 0x3;
++	/*
++	 * When bit7 is set that means we start counting at 1MiB, otherwise
++	 * we start counting at 128KiB and shift this value the content of
++	 * ID[3][4:5].
++	 * The only exception is when ID[3][4:5] == 3 and ID[3][7] == 0, in
++	 * this case the erasesize is set to 768KiB.
++	 */
++	if (chip->id.data[3] & 0x80)
++		mtd->erasesize = SZ_1M << tmp;
++	else if (tmp == 3)
++		mtd->erasesize = SZ_512K + SZ_256K;
++	else
++		mtd->erasesize = SZ_128K << tmp;
++
++	/*
++	 * Modern Toggle DDR NANDs have a valid JEDECID even though they are
++	 * not exposing a valid JEDEC parameter table.
++	 * These NANDs use a different NAND ID scheme.
++	 */
++	valid_jedecid = hynix_nand_has_valid_jedecid(chip);
++
++	hynix_nand_extract_oobsize(chip, valid_jedecid);
++	hynix_nand_extract_ecc_requirements(chip, valid_jedecid);
++	hynix_nand_extract_scrambling_requirements(chip, valid_jedecid);
++}
++
++static void hynix_nand_cleanup(struct nand_chip *chip)
++{
++	struct hynix_nand *hynix = nand_get_manufacturer_data(chip);
++
++	if (!hynix)
++		return;
++
++	kfree(hynix->read_retry);
++	kfree(hynix);
++	nand_set_manufacturer_data(chip, NULL);
++}
++
++static int hynix_nand_init(struct nand_chip *chip)
++{
++	struct hynix_nand *hynix;
++	int ret;
++
++	if (!nand_is_slc(chip))
++		chip->bbt_options |= NAND_BBT_SCANLASTPAGE;
++	else
++		chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
++
++	hynix = kzalloc(sizeof(*hynix), GFP_KERNEL);
++	if (!hynix)
++		return -ENOMEM;
++
++	nand_set_manufacturer_data(chip, hynix);
++
++	ret = hynix_nand_rr_init(chip);
++	if (ret)
++		hynix_nand_cleanup(chip);
++
++	return ret;
++}
++
++const struct nand_manufacturer_ops hynix_nand_manuf_ops = {
++	.detect = hynix_nand_decode_id,
++	.init = hynix_nand_init,
++	.cleanup = hynix_nand_cleanup,
++};
+diff --git a/drivers/mtd/nand/raw/nand_ids.c b/drivers/mtd/nand/raw/nand_ids.c
+new file mode 100644
+index 0000000..5423c3b
+--- /dev/null
++++ b/drivers/mtd/nand/raw/nand_ids.c
+@@ -0,0 +1,207 @@
++/*
++ *  Copyright (C) 2002 Thomas Gleixner (tglx@linutronix.de)
++ *
++ * 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/mtd/rawnand.h>
++#include <linux/sizes.h>
++
++#define LP_OPTIONS 0
++#define LP_OPTIONS16 (LP_OPTIONS | NAND_BUSWIDTH_16)
++
++#define SP_OPTIONS NAND_NEED_READRDY
++#define SP_OPTIONS16 (SP_OPTIONS | NAND_BUSWIDTH_16)
++
++/*
++ * The chip ID list:
++ *    name, device ID, page size, chip size in MiB, eraseblock size, options
++ *
++ * If page size and eraseblock size are 0, the sizes are taken from the
++ * extended chip ID.
++ */
++struct nand_flash_dev nand_flash_ids[] = {
++	/*
++	 * Some incompatible NAND chips share device ID's and so must be
++	 * listed by full ID. We list them first so that we can easily identify
++	 * the most specific match.
++	 */
++	{"TC58NVG0S3E 1G 3.3V 8-bit",
++		{ .id = {0x98, 0xd1, 0x90, 0x15, 0x76, 0x14, 0x01, 0x00} },
++		  SZ_2K, SZ_128, SZ_128K, 0, 8, 64, NAND_ECC_INFO(1, SZ_512),
++		  2 },
++	{"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) },
++	{"TC58NVG5D2 32G 3.3V 8-bit",
++		{ .id = {0x98, 0xd7, 0x94, 0x32, 0x76, 0x56, 0x09, 0x00} },
++		  SZ_8K, SZ_4K, SZ_1M, 0, 8, 640, NAND_ECC_INFO(40, SZ_1K) },
++	{"TC58NVG6D2 64G 3.3V 8-bit",
++		{ .id = {0x98, 0xde, 0x94, 0x82, 0x76, 0x56, 0x04, 0x20} },
++		  SZ_8K, SZ_8K, SZ_2M, 0, 8, 640, NAND_ECC_INFO(40, SZ_1K) },
++	{"SDTNRGAMA 64G 3.3V 8-bit",
++		{ .id = {0x45, 0xde, 0x94, 0x93, 0x76, 0x50} },
++		  SZ_16K, SZ_8K, SZ_4M, 0, 6, 1280, NAND_ECC_INFO(40, SZ_1K) },
++	{"H27UCG8T2ATR-BC 64G 3.3V 8-bit",
++		{ .id = {0xad, 0xde, 0x94, 0xda, 0x74, 0xc4} },
++		  SZ_8K, SZ_8K, SZ_2M, NAND_NEED_SCRAMBLING, 6, 640,
++		  NAND_ECC_INFO(40, SZ_1K), 4 },
++
++	LEGACY_ID_NAND("NAND 4MiB 5V 8-bit",   0x6B, 4, SZ_8K, SP_OPTIONS),
++	LEGACY_ID_NAND("NAND 4MiB 3,3V 8-bit", 0xE3, 4, SZ_8K, SP_OPTIONS),
++	LEGACY_ID_NAND("NAND 4MiB 3,3V 8-bit", 0xE5, 4, SZ_8K, SP_OPTIONS),
++	LEGACY_ID_NAND("NAND 8MiB 3,3V 8-bit", 0xD6, 8, SZ_8K, SP_OPTIONS),
++	LEGACY_ID_NAND("NAND 8MiB 3,3V 8-bit", 0xE6, 8, SZ_8K, SP_OPTIONS),
++
++	LEGACY_ID_NAND("NAND 16MiB 1,8V 8-bit",  0x33, 16, SZ_16K, SP_OPTIONS),
++	LEGACY_ID_NAND("NAND 16MiB 3,3V 8-bit",  0x73, 16, SZ_16K, SP_OPTIONS),
++	LEGACY_ID_NAND("NAND 16MiB 1,8V 16-bit", 0x43, 16, SZ_16K, SP_OPTIONS16),
++	LEGACY_ID_NAND("NAND 16MiB 3,3V 16-bit", 0x53, 16, SZ_16K, SP_OPTIONS16),
++
++	LEGACY_ID_NAND("NAND 32MiB 1,8V 8-bit",  0x35, 32, SZ_16K, SP_OPTIONS),
++	LEGACY_ID_NAND("NAND 32MiB 3,3V 8-bit",  0x75, 32, SZ_16K, SP_OPTIONS),
++	LEGACY_ID_NAND("NAND 32MiB 1,8V 16-bit", 0x45, 32, SZ_16K, SP_OPTIONS16),
++	LEGACY_ID_NAND("NAND 32MiB 3,3V 16-bit", 0x55, 32, SZ_16K, SP_OPTIONS16),
++
++	LEGACY_ID_NAND("NAND 64MiB 1,8V 8-bit",  0x36, 64, SZ_16K, SP_OPTIONS),
++	LEGACY_ID_NAND("NAND 64MiB 3,3V 8-bit",  0x76, 64, SZ_16K, SP_OPTIONS),
++	LEGACY_ID_NAND("NAND 64MiB 1,8V 16-bit", 0x46, 64, SZ_16K, SP_OPTIONS16),
++	LEGACY_ID_NAND("NAND 64MiB 3,3V 16-bit", 0x56, 64, SZ_16K, SP_OPTIONS16),
++
++	LEGACY_ID_NAND("NAND 128MiB 1,8V 8-bit",  0x78, 128, SZ_16K, SP_OPTIONS),
++	LEGACY_ID_NAND("NAND 128MiB 1,8V 8-bit",  0x39, 128, SZ_16K, SP_OPTIONS),
++	LEGACY_ID_NAND("NAND 128MiB 3,3V 8-bit",  0x79, 128, SZ_16K, SP_OPTIONS),
++	LEGACY_ID_NAND("NAND 128MiB 1,8V 16-bit", 0x72, 128, SZ_16K, SP_OPTIONS16),
++	LEGACY_ID_NAND("NAND 128MiB 1,8V 16-bit", 0x49, 128, SZ_16K, SP_OPTIONS16),
++	LEGACY_ID_NAND("NAND 128MiB 3,3V 16-bit", 0x74, 128, SZ_16K, SP_OPTIONS16),
++	LEGACY_ID_NAND("NAND 128MiB 3,3V 16-bit", 0x59, 128, SZ_16K, SP_OPTIONS16),
++
++	LEGACY_ID_NAND("NAND 256MiB 3,3V 8-bit", 0x71, 256, SZ_16K, SP_OPTIONS),
++
++	/*
++	 * These are the new chips with large page size. Their page size and
++	 * eraseblock size are determined from the extended ID bytes.
++	 */
++
++	/* 512 Megabit */
++	EXTENDED_ID_NAND("NAND 64MiB 1,8V 8-bit",  0xA2,  64, LP_OPTIONS),
++	EXTENDED_ID_NAND("NAND 64MiB 1,8V 8-bit",  0xA0,  64, LP_OPTIONS),
++	EXTENDED_ID_NAND("NAND 64MiB 3,3V 8-bit",  0xF2,  64, LP_OPTIONS),
++	EXTENDED_ID_NAND("NAND 64MiB 3,3V 8-bit",  0xD0,  64, LP_OPTIONS),
++	EXTENDED_ID_NAND("NAND 64MiB 3,3V 8-bit",  0xF0,  64, LP_OPTIONS),
++	EXTENDED_ID_NAND("NAND 64MiB 1,8V 16-bit", 0xB2,  64, LP_OPTIONS16),
++	EXTENDED_ID_NAND("NAND 64MiB 1,8V 16-bit", 0xB0,  64, LP_OPTIONS16),
++	EXTENDED_ID_NAND("NAND 64MiB 3,3V 16-bit", 0xC2,  64, LP_OPTIONS16),
++	EXTENDED_ID_NAND("NAND 64MiB 3,3V 16-bit", 0xC0,  64, LP_OPTIONS16),
++
++	/* 1 Gigabit */
++	EXTENDED_ID_NAND("NAND 128MiB 1,8V 8-bit",  0xA1, 128, LP_OPTIONS),
++	EXTENDED_ID_NAND("NAND 128MiB 3,3V 8-bit",  0xF1, 128, LP_OPTIONS),
++	EXTENDED_ID_NAND("NAND 128MiB 3,3V 8-bit",  0xD1, 128, LP_OPTIONS),
++	EXTENDED_ID_NAND("NAND 128MiB 1,8V 16-bit", 0xB1, 128, LP_OPTIONS16),
++	EXTENDED_ID_NAND("NAND 128MiB 3,3V 16-bit", 0xC1, 128, LP_OPTIONS16),
++	EXTENDED_ID_NAND("NAND 128MiB 1,8V 16-bit", 0xAD, 128, LP_OPTIONS16),
++
++	/* 2 Gigabit */
++	EXTENDED_ID_NAND("NAND 256MiB 1,8V 8-bit",  0xAA, 256, LP_OPTIONS),
++	EXTENDED_ID_NAND("NAND 256MiB 3,3V 8-bit",  0xDA, 256, LP_OPTIONS),
++	EXTENDED_ID_NAND("NAND 256MiB 1,8V 16-bit", 0xBA, 256, LP_OPTIONS16),
++	EXTENDED_ID_NAND("NAND 256MiB 3,3V 16-bit", 0xCA, 256, LP_OPTIONS16),
++
++	/* 4 Gigabit */
++	EXTENDED_ID_NAND("NAND 512MiB 1,8V 8-bit",  0xAC, 512, LP_OPTIONS),
++	EXTENDED_ID_NAND("NAND 512MiB 3,3V 8-bit",  0xDC, 512, LP_OPTIONS),
++	EXTENDED_ID_NAND("NAND 512MiB 1,8V 16-bit", 0xBC, 512, LP_OPTIONS16),
++	EXTENDED_ID_NAND("NAND 512MiB 3,3V 16-bit", 0xCC, 512, LP_OPTIONS16),
++
++	/* 8 Gigabit */
++	EXTENDED_ID_NAND("NAND 1GiB 1,8V 8-bit",  0xA3, 1024, LP_OPTIONS),
++	EXTENDED_ID_NAND("NAND 1GiB 3,3V 8-bit",  0xD3, 1024, LP_OPTIONS),
++	EXTENDED_ID_NAND("NAND 1GiB 1,8V 16-bit", 0xB3, 1024, LP_OPTIONS16),
++	EXTENDED_ID_NAND("NAND 1GiB 3,3V 16-bit", 0xC3, 1024, LP_OPTIONS16),
++
++	/* 16 Gigabit */
++	EXTENDED_ID_NAND("NAND 2GiB 1,8V 8-bit",  0xA5, 2048, LP_OPTIONS),
++	EXTENDED_ID_NAND("NAND 2GiB 3,3V 8-bit",  0xD5, 2048, LP_OPTIONS),
++	EXTENDED_ID_NAND("NAND 2GiB 1,8V 16-bit", 0xB5, 2048, LP_OPTIONS16),
++	EXTENDED_ID_NAND("NAND 2GiB 3,3V 16-bit", 0xC5, 2048, LP_OPTIONS16),
++
++	/* 32 Gigabit */
++	EXTENDED_ID_NAND("NAND 4GiB 1,8V 8-bit",  0xA7, 4096, LP_OPTIONS),
++	EXTENDED_ID_NAND("NAND 4GiB 3,3V 8-bit",  0xD7, 4096, LP_OPTIONS),
++	EXTENDED_ID_NAND("NAND 4GiB 1,8V 16-bit", 0xB7, 4096, LP_OPTIONS16),
++	EXTENDED_ID_NAND("NAND 4GiB 3,3V 16-bit", 0xC7, 4096, LP_OPTIONS16),
++
++	/* 64 Gigabit */
++	EXTENDED_ID_NAND("NAND 8GiB 1,8V 8-bit",  0xAE, 8192, LP_OPTIONS),
++	EXTENDED_ID_NAND("NAND 8GiB 3,3V 8-bit",  0xDE, 8192, LP_OPTIONS),
++	EXTENDED_ID_NAND("NAND 8GiB 1,8V 16-bit", 0xBE, 8192, LP_OPTIONS16),
++	EXTENDED_ID_NAND("NAND 8GiB 3,3V 16-bit", 0xCE, 8192, LP_OPTIONS16),
++
++	/* 128 Gigabit */
++	EXTENDED_ID_NAND("NAND 16GiB 1,8V 8-bit",  0x1A, 16384, LP_OPTIONS),
++	EXTENDED_ID_NAND("NAND 16GiB 3,3V 8-bit",  0x3A, 16384, LP_OPTIONS),
++	EXTENDED_ID_NAND("NAND 16GiB 1,8V 16-bit", 0x2A, 16384, LP_OPTIONS16),
++	EXTENDED_ID_NAND("NAND 16GiB 3,3V 16-bit", 0x4A, 16384, LP_OPTIONS16),
++
++	/* 256 Gigabit */
++	EXTENDED_ID_NAND("NAND 32GiB 1,8V 8-bit",  0x1C, 32768, LP_OPTIONS),
++	EXTENDED_ID_NAND("NAND 32GiB 3,3V 8-bit",  0x3C, 32768, LP_OPTIONS),
++	EXTENDED_ID_NAND("NAND 32GiB 1,8V 16-bit", 0x2C, 32768, LP_OPTIONS16),
++	EXTENDED_ID_NAND("NAND 32GiB 3,3V 16-bit", 0x4C, 32768, LP_OPTIONS16),
++
++	/* 512 Gigabit */
++	EXTENDED_ID_NAND("NAND 64GiB 1,8V 8-bit",  0x1E, 65536, LP_OPTIONS),
++	EXTENDED_ID_NAND("NAND 64GiB 3,3V 8-bit",  0x3E, 65536, LP_OPTIONS),
++	EXTENDED_ID_NAND("NAND 64GiB 1,8V 16-bit", 0x2E, 65536, LP_OPTIONS16),
++	EXTENDED_ID_NAND("NAND 64GiB 3,3V 16-bit", 0x4E, 65536, LP_OPTIONS16),
++
++	{NULL}
++};
++
++/* Manufacturer IDs */
++static const struct nand_manufacturer nand_manufacturers[] = {
++	{NAND_MFR_TOSHIBA, "Toshiba", &toshiba_nand_manuf_ops},
++	{NAND_MFR_ESMT, "ESMT"},
++	{NAND_MFR_SAMSUNG, "Samsung", &samsung_nand_manuf_ops},
++	{NAND_MFR_FUJITSU, "Fujitsu"},
++	{NAND_MFR_NATIONAL, "National"},
++	{NAND_MFR_RENESAS, "Renesas"},
++	{NAND_MFR_STMICRO, "ST Micro"},
++	{NAND_MFR_HYNIX, "Hynix", &hynix_nand_manuf_ops},
++	{NAND_MFR_MICRON, "Micron", &micron_nand_manuf_ops},
++	{NAND_MFR_AMD, "AMD/Spansion", &amd_nand_manuf_ops},
++	{NAND_MFR_MACRONIX, "Macronix", &macronix_nand_manuf_ops},
++	{NAND_MFR_EON, "Eon"},
++	{NAND_MFR_SANDISK, "SanDisk"},
++	{NAND_MFR_INTEL, "Intel"},
++	{NAND_MFR_ATO, "ATO"},
++	{NAND_MFR_WINBOND, "Winbond"},
++};
++
++/**
++ * nand_get_manufacturer - Get manufacturer information from the manufacturer
++ *			   ID
++ * @id: manufacturer ID
++ *
++ * Returns a pointer a nand_manufacturer object if the manufacturer is defined
++ * in the NAND manufacturers database, NULL otherwise.
++ */
++const struct nand_manufacturer *nand_get_manufacturer(u8 id)
++{
++	int i;
++
++	for (i = 0; i < ARRAY_SIZE(nand_manufacturers); i++)
++		if (nand_manufacturers[i].id == id)
++			return &nand_manufacturers[i];
++
++	return NULL;
++}
+diff --git a/drivers/mtd/nand/raw/nand_macronix.c b/drivers/mtd/nand/raw/nand_macronix.c
+new file mode 100644
+index 0000000..d290ff2
+--- /dev/null
++++ b/drivers/mtd/nand/raw/nand_macronix.c
+@@ -0,0 +1,30 @@
++/*
++ * Copyright (C) 2017 Free Electrons
++ * Copyright (C) 2017 NextThing Co
++ *
++ * Author: Boris Brezillon <boris.brezillon@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 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/mtd/rawnand.h>
++
++static int macronix_nand_init(struct nand_chip *chip)
++{
++	if (nand_is_slc(chip))
++		chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
++
++	return 0;
++}
++
++const struct nand_manufacturer_ops macronix_nand_manuf_ops = {
++	.init = macronix_nand_init,
++};
+diff --git a/drivers/mtd/nand/raw/nand_micron.c b/drivers/mtd/nand/raw/nand_micron.c
+new file mode 100644
+index 0000000..abf6a3c
+--- /dev/null
++++ b/drivers/mtd/nand/raw/nand_micron.c
+@@ -0,0 +1,308 @@
++/*
++ * Copyright (C) 2017 Free Electrons
++ * Copyright (C) 2017 NextThing Co
++ *
++ * Author: Boris Brezillon <boris.brezillon@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 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/mtd/rawnand.h>
++
++/*
++ * Special Micron status bit that indicates when the block has been
++ * corrected by on-die ECC and should be rewritten
++ */
++#define NAND_STATUS_WRITE_RECOMMENDED	BIT(3)
++
++struct nand_onfi_vendor_micron {
++	u8 two_plane_read;
++	u8 read_cache;
++	u8 read_unique_id;
++	u8 dq_imped;
++	u8 dq_imped_num_settings;
++	u8 dq_imped_feat_addr;
++	u8 rb_pulldown_strength;
++	u8 rb_pulldown_strength_feat_addr;
++	u8 rb_pulldown_strength_num_settings;
++	u8 otp_mode;
++	u8 otp_page_start;
++	u8 otp_data_prot_addr;
++	u8 otp_num_pages;
++	u8 otp_feat_addr;
++	u8 read_retry_options;
++	u8 reserved[72];
++	u8 param_revision;
++} __packed;
++
++static int micron_nand_setup_read_retry(struct mtd_info *mtd, int retry_mode)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	u8 feature[ONFI_SUBFEATURE_PARAM_LEN] = {retry_mode};
++
++	return chip->onfi_set_features(mtd, chip, ONFI_FEATURE_ADDR_READ_RETRY,
++				       feature);
++}
++
++/*
++ * Configure chip properties from Micron vendor-specific ONFI table
++ */
++static int micron_nand_onfi_init(struct nand_chip *chip)
++{
++	struct nand_onfi_params *p = &chip->onfi_params;
++	struct nand_onfi_vendor_micron *micron = (void *)p->vendor;
++
++	if (!chip->onfi_version)
++		return 0;
++
++	if (le16_to_cpu(p->vendor_revision) < 1)
++		return 0;
++
++	chip->read_retries = micron->read_retry_options;
++	chip->setup_read_retry = micron_nand_setup_read_retry;
++
++	return 0;
++}
++
++static int micron_nand_on_die_ooblayout_ecc(struct mtd_info *mtd, int section,
++					    struct mtd_oob_region *oobregion)
++{
++	if (section >= 4)
++		return -ERANGE;
++
++	oobregion->offset = (section * 16) + 8;
++	oobregion->length = 8;
++
++	return 0;
++}
++
++static int micron_nand_on_die_ooblayout_free(struct mtd_info *mtd, int section,
++					     struct mtd_oob_region *oobregion)
++{
++	if (section >= 4)
++		return -ERANGE;
++
++	oobregion->offset = (section * 16) + 2;
++	oobregion->length = 6;
++
++	return 0;
++}
++
++static const struct mtd_ooblayout_ops micron_nand_on_die_ooblayout_ops = {
++	.ecc = micron_nand_on_die_ooblayout_ecc,
++	.free = micron_nand_on_die_ooblayout_free,
++};
++
++static int micron_nand_on_die_ecc_setup(struct nand_chip *chip, bool enable)
++{
++	u8 feature[ONFI_SUBFEATURE_PARAM_LEN] = { 0, };
++
++	if (enable)
++		feature[0] |= ONFI_FEATURE_ON_DIE_ECC_EN;
++
++	return chip->onfi_set_features(nand_to_mtd(chip), chip,
++				       ONFI_FEATURE_ON_DIE_ECC, feature);
++}
++
++static int
++micron_nand_read_page_on_die_ecc(struct mtd_info *mtd, struct nand_chip *chip,
++				 uint8_t *buf, int oob_required,
++				 int page)
++{
++	int status;
++	int max_bitflips = 0;
++
++	micron_nand_on_die_ecc_setup(chip, true);
++
++	chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
++	chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
++	status = chip->read_byte(mtd);
++	if (status & NAND_STATUS_FAIL)
++		mtd->ecc_stats.failed++;
++	/*
++	 * The internal ECC doesn't tell us the number of bitflips
++	 * that have been corrected, but tells us if it recommends to
++	 * rewrite the block. If it's the case, then we pretend we had
++	 * a number of bitflips equal to the ECC strength, which will
++	 * hint the NAND core to rewrite the block.
++	 */
++	else if (status & NAND_STATUS_WRITE_RECOMMENDED)
++		max_bitflips = chip->ecc.strength;
++
++	chip->cmdfunc(mtd, NAND_CMD_READ0, -1, -1);
++
++	nand_read_page_raw(mtd, chip, buf, oob_required, page);
++
++	micron_nand_on_die_ecc_setup(chip, false);
++
++	return max_bitflips;
++}
++
++static int
++micron_nand_write_page_on_die_ecc(struct mtd_info *mtd, struct nand_chip *chip,
++				  const uint8_t *buf, int oob_required,
++				  int page)
++{
++	int status;
++
++	micron_nand_on_die_ecc_setup(chip, true);
++
++	chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
++	nand_write_page_raw(mtd, chip, buf, oob_required, page);
++	chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
++	status = chip->waitfunc(mtd, chip);
++
++	micron_nand_on_die_ecc_setup(chip, false);
++
++	return status & NAND_STATUS_FAIL ? -EIO : 0;
++}
++
++static int
++micron_nand_read_page_raw_on_die_ecc(struct mtd_info *mtd,
++				     struct nand_chip *chip,
++				     uint8_t *buf, int oob_required,
++				     int page)
++{
++	chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
++	nand_read_page_raw(mtd, chip, buf, oob_required, page);
++
++	return 0;
++}
++
++static int
++micron_nand_write_page_raw_on_die_ecc(struct mtd_info *mtd,
++				      struct nand_chip *chip,
++				      const uint8_t *buf, int oob_required,
++				      int page)
++{
++	int status;
++
++	chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
++	nand_write_page_raw(mtd, chip, buf, oob_required, page);
++	chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
++	status = chip->waitfunc(mtd, chip);
++
++	return status & NAND_STATUS_FAIL ? -EIO : 0;
++}
++
++enum {
++	/* The NAND flash doesn't support on-die ECC */
++	MICRON_ON_DIE_UNSUPPORTED,
++
++	/*
++	 * The NAND flash supports on-die ECC and it can be
++	 * enabled/disabled by a set features command.
++	 */
++	MICRON_ON_DIE_SUPPORTED,
++
++	/*
++	 * The NAND flash supports on-die ECC, and it cannot be
++	 * disabled.
++	 */
++	MICRON_ON_DIE_MANDATORY,
++};
++
++/*
++ * Try to detect if the NAND support on-die ECC. To do this, we enable
++ * the feature, and read back if it has been enabled as expected. We
++ * also check if it can be disabled, because some Micron NANDs do not
++ * allow disabling the on-die ECC and we don't support such NANDs for
++ * now.
++ *
++ * This function also has the side effect of disabling on-die ECC if
++ * it had been left enabled by the firmware/bootloader.
++ */
++static int micron_supports_on_die_ecc(struct nand_chip *chip)
++{
++	u8 feature[ONFI_SUBFEATURE_PARAM_LEN] = { 0, };
++	int ret;
++
++	if (chip->onfi_version == 0)
++		return MICRON_ON_DIE_UNSUPPORTED;
++
++	if (chip->bits_per_cell != 1)
++		return MICRON_ON_DIE_UNSUPPORTED;
++
++	ret = micron_nand_on_die_ecc_setup(chip, true);
++	if (ret)
++		return MICRON_ON_DIE_UNSUPPORTED;
++
++	chip->onfi_get_features(nand_to_mtd(chip), chip,
++				ONFI_FEATURE_ON_DIE_ECC, feature);
++	if ((feature[0] & ONFI_FEATURE_ON_DIE_ECC_EN) == 0)
++		return MICRON_ON_DIE_UNSUPPORTED;
++
++	ret = micron_nand_on_die_ecc_setup(chip, false);
++	if (ret)
++		return MICRON_ON_DIE_UNSUPPORTED;
++
++	chip->onfi_get_features(nand_to_mtd(chip), chip,
++				ONFI_FEATURE_ON_DIE_ECC, feature);
++	if (feature[0] & ONFI_FEATURE_ON_DIE_ECC_EN)
++		return MICRON_ON_DIE_MANDATORY;
++
++	/*
++	 * Some Micron NANDs have an on-die ECC of 4/512, some other
++	 * 8/512. We only support the former.
++	 */
++	if (chip->onfi_params.ecc_bits != 4)
++		return MICRON_ON_DIE_UNSUPPORTED;
++
++	return MICRON_ON_DIE_SUPPORTED;
++}
++
++static int micron_nand_init(struct nand_chip *chip)
++{
++	struct mtd_info *mtd = nand_to_mtd(chip);
++	int ondie;
++	int ret;
++
++	ret = micron_nand_onfi_init(chip);
++	if (ret)
++		return ret;
++
++	if (mtd->writesize == 2048)
++		chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
++
++	ondie = micron_supports_on_die_ecc(chip);
++
++	if (ondie == MICRON_ON_DIE_MANDATORY) {
++		pr_err("On-die ECC forcefully enabled, not supported\n");
++		return -EINVAL;
++	}
++
++	if (chip->ecc.mode == NAND_ECC_ON_DIE) {
++		if (ondie == MICRON_ON_DIE_UNSUPPORTED) {
++			pr_err("On-die ECC selected but not supported\n");
++			return -EINVAL;
++		}
++
++		chip->ecc.options = NAND_ECC_CUSTOM_PAGE_ACCESS;
++		chip->ecc.bytes = 8;
++		chip->ecc.size = 512;
++		chip->ecc.strength = 4;
++		chip->ecc.algo = NAND_ECC_BCH;
++		chip->ecc.read_page = micron_nand_read_page_on_die_ecc;
++		chip->ecc.write_page = micron_nand_write_page_on_die_ecc;
++		chip->ecc.read_page_raw =
++			micron_nand_read_page_raw_on_die_ecc;
++		chip->ecc.write_page_raw =
++			micron_nand_write_page_raw_on_die_ecc;
++
++		mtd_set_ooblayout(mtd, &micron_nand_on_die_ooblayout_ops);
++	}
++
++	return 0;
++}
++
++const struct nand_manufacturer_ops micron_nand_manuf_ops = {
++	.init = micron_nand_init,
++};
+diff --git a/drivers/mtd/nand/raw/nand_samsung.c b/drivers/mtd/nand/raw/nand_samsung.c
+new file mode 100644
+index 0000000..d348f01
+--- /dev/null
++++ b/drivers/mtd/nand/raw/nand_samsung.c
+@@ -0,0 +1,115 @@
++/*
++ * Copyright (C) 2017 Free Electrons
++ * Copyright (C) 2017 NextThing Co
++ *
++ * Author: Boris Brezillon <boris.brezillon@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 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/mtd/rawnand.h>
++
++static void samsung_nand_decode_id(struct nand_chip *chip)
++{
++	struct mtd_info *mtd = nand_to_mtd(chip);
++
++	/* New Samsung (6 byte ID): Samsung K9GAG08U0F (p.44) */
++	if (chip->id.len == 6 && !nand_is_slc(chip) &&
++	    chip->id.data[5] != 0x00) {
++		u8 extid = chip->id.data[3];
++
++		/* Get pagesize */
++		mtd->writesize = 2048 << (extid & 0x03);
++
++		extid >>= 2;
++
++		/* Get oobsize */
++		switch (((extid >> 2) & 0x4) | (extid & 0x3)) {
++		case 1:
++			mtd->oobsize = 128;
++			break;
++		case 2:
++			mtd->oobsize = 218;
++			break;
++		case 3:
++			mtd->oobsize = 400;
++			break;
++		case 4:
++			mtd->oobsize = 436;
++			break;
++		case 5:
++			mtd->oobsize = 512;
++			break;
++		case 6:
++			mtd->oobsize = 640;
++			break;
++		default:
++			/*
++			 * We should never reach this case, but if that
++			 * happens, this probably means Samsung decided to use
++			 * a different extended ID format, and we should find
++			 * a way to support it.
++			 */
++			WARN(1, "Invalid OOB size value");
++			break;
++		}
++
++		/* Get blocksize */
++		extid >>= 2;
++		mtd->erasesize = (128 * 1024) <<
++				 (((extid >> 1) & 0x04) | (extid & 0x03));
++
++		/* Extract ECC requirements from 5th id byte*/
++		extid = (chip->id.data[4] >> 4) & 0x07;
++		if (extid < 5) {
++			chip->ecc_step_ds = 512;
++			chip->ecc_strength_ds = 1 << extid;
++		} else {
++			chip->ecc_step_ds = 1024;
++			switch (extid) {
++			case 5:
++				chip->ecc_strength_ds = 24;
++				break;
++			case 6:
++				chip->ecc_strength_ds = 40;
++				break;
++			case 7:
++				chip->ecc_strength_ds = 60;
++				break;
++			default:
++				WARN(1, "Could not decode ECC info");
++				chip->ecc_step_ds = 0;
++			}
++		}
++	} else {
++		nand_decode_ext_id(chip);
++	}
++}
++
++static int samsung_nand_init(struct nand_chip *chip)
++{
++	struct mtd_info *mtd = nand_to_mtd(chip);
++
++	if (mtd->writesize > 512)
++		chip->options |= NAND_SAMSUNG_LP_OPTIONS;
++
++	if (!nand_is_slc(chip))
++		chip->bbt_options |= NAND_BBT_SCANLASTPAGE;
++	else
++		chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
++
++	return 0;
++}
++
++const struct nand_manufacturer_ops samsung_nand_manuf_ops = {
++	.detect = samsung_nand_decode_id,
++	.init = samsung_nand_init,
++};
+diff --git a/drivers/mtd/nand/raw/nand_timings.c b/drivers/mtd/nand/raw/nand_timings.c
+new file mode 100644
+index 0000000..5d1533b
+--- /dev/null
++++ b/drivers/mtd/nand/raw/nand_timings.c
+@@ -0,0 +1,335 @@
++/*
++ *  Copyright (C) 2014 Free Electrons
++ *
++ *  Author: Boris BREZILLON <boris.brezillon@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.
++ *
++ */
++#include <linux/kernel.h>
++#include <linux/err.h>
++#include <linux/export.h>
++#include <linux/mtd/rawnand.h>
++
++static const struct nand_data_interface onfi_sdr_timings[] = {
++	/* Mode 0 */
++	{
++		.type = NAND_SDR_IFACE,
++		.timings.sdr = {
++			.tCCS_min = 500000,
++			.tR_max = 200000000,
++			.tADL_min = 400000,
++			.tALH_min = 20000,
++			.tALS_min = 50000,
++			.tAR_min = 25000,
++			.tCEA_max = 100000,
++			.tCEH_min = 20000,
++			.tCH_min = 20000,
++			.tCHZ_max = 100000,
++			.tCLH_min = 20000,
++			.tCLR_min = 20000,
++			.tCLS_min = 50000,
++			.tCOH_min = 0,
++			.tCS_min = 70000,
++			.tDH_min = 20000,
++			.tDS_min = 40000,
++			.tFEAT_max = 1000000,
++			.tIR_min = 10000,
++			.tITC_max = 1000000,
++			.tRC_min = 100000,
++			.tREA_max = 40000,
++			.tREH_min = 30000,
++			.tRHOH_min = 0,
++			.tRHW_min = 200000,
++			.tRHZ_max = 200000,
++			.tRLOH_min = 0,
++			.tRP_min = 50000,
++			.tRR_min = 40000,
++			.tRST_max = 250000000000ULL,
++			.tWB_max = 200000,
++			.tWC_min = 100000,
++			.tWH_min = 30000,
++			.tWHR_min = 120000,
++			.tWP_min = 50000,
++			.tWW_min = 100000,
++		},
++	},
++	/* Mode 1 */
++	{
++		.type = NAND_SDR_IFACE,
++		.timings.sdr = {
++			.tCCS_min = 500000,
++			.tR_max = 200000000,
++			.tADL_min = 400000,
++			.tALH_min = 10000,
++			.tALS_min = 25000,
++			.tAR_min = 10000,
++			.tCEA_max = 45000,
++			.tCEH_min = 20000,
++			.tCH_min = 10000,
++			.tCHZ_max = 50000,
++			.tCLH_min = 10000,
++			.tCLR_min = 10000,
++			.tCLS_min = 25000,
++			.tCOH_min = 15000,
++			.tCS_min = 35000,
++			.tDH_min = 10000,
++			.tDS_min = 20000,
++			.tFEAT_max = 1000000,
++			.tIR_min = 0,
++			.tITC_max = 1000000,
++			.tRC_min = 50000,
++			.tREA_max = 30000,
++			.tREH_min = 15000,
++			.tRHOH_min = 15000,
++			.tRHW_min = 100000,
++			.tRHZ_max = 100000,
++			.tRLOH_min = 0,
++			.tRP_min = 25000,
++			.tRR_min = 20000,
++			.tRST_max = 500000000,
++			.tWB_max = 100000,
++			.tWC_min = 45000,
++			.tWH_min = 15000,
++			.tWHR_min = 80000,
++			.tWP_min = 25000,
++			.tWW_min = 100000,
++		},
++	},
++	/* Mode 2 */
++	{
++		.type = NAND_SDR_IFACE,
++		.timings.sdr = {
++			.tCCS_min = 500000,
++			.tR_max = 200000000,
++			.tADL_min = 400000,
++			.tALH_min = 10000,
++			.tALS_min = 15000,
++			.tAR_min = 10000,
++			.tCEA_max = 30000,
++			.tCEH_min = 20000,
++			.tCH_min = 10000,
++			.tCHZ_max = 50000,
++			.tCLH_min = 10000,
++			.tCLR_min = 10000,
++			.tCLS_min = 15000,
++			.tCOH_min = 15000,
++			.tCS_min = 25000,
++			.tDH_min = 5000,
++			.tDS_min = 15000,
++			.tFEAT_max = 1000000,
++			.tIR_min = 0,
++			.tITC_max = 1000000,
++			.tRC_min = 35000,
++			.tREA_max = 25000,
++			.tREH_min = 15000,
++			.tRHOH_min = 15000,
++			.tRHW_min = 100000,
++			.tRHZ_max = 100000,
++			.tRLOH_min = 0,
++			.tRR_min = 20000,
++			.tRST_max = 500000000,
++			.tWB_max = 100000,
++			.tRP_min = 17000,
++			.tWC_min = 35000,
++			.tWH_min = 15000,
++			.tWHR_min = 80000,
++			.tWP_min = 17000,
++			.tWW_min = 100000,
++		},
++	},
++	/* Mode 3 */
++	{
++		.type = NAND_SDR_IFACE,
++		.timings.sdr = {
++			.tCCS_min = 500000,
++			.tR_max = 200000000,
++			.tADL_min = 400000,
++			.tALH_min = 5000,
++			.tALS_min = 10000,
++			.tAR_min = 10000,
++			.tCEA_max = 25000,
++			.tCEH_min = 20000,
++			.tCH_min = 5000,
++			.tCHZ_max = 50000,
++			.tCLH_min = 5000,
++			.tCLR_min = 10000,
++			.tCLS_min = 10000,
++			.tCOH_min = 15000,
++			.tCS_min = 25000,
++			.tDH_min = 5000,
++			.tDS_min = 10000,
++			.tFEAT_max = 1000000,
++			.tIR_min = 0,
++			.tITC_max = 1000000,
++			.tRC_min = 30000,
++			.tREA_max = 20000,
++			.tREH_min = 10000,
++			.tRHOH_min = 15000,
++			.tRHW_min = 100000,
++			.tRHZ_max = 100000,
++			.tRLOH_min = 0,
++			.tRP_min = 15000,
++			.tRR_min = 20000,
++			.tRST_max = 500000000,
++			.tWB_max = 100000,
++			.tWC_min = 30000,
++			.tWH_min = 10000,
++			.tWHR_min = 80000,
++			.tWP_min = 15000,
++			.tWW_min = 100000,
++		},
++	},
++	/* Mode 4 */
++	{
++		.type = NAND_SDR_IFACE,
++		.timings.sdr = {
++			.tCCS_min = 500000,
++			.tR_max = 200000000,
++			.tADL_min = 400000,
++			.tALH_min = 5000,
++			.tALS_min = 10000,
++			.tAR_min = 10000,
++			.tCEA_max = 25000,
++			.tCEH_min = 20000,
++			.tCH_min = 5000,
++			.tCHZ_max = 30000,
++			.tCLH_min = 5000,
++			.tCLR_min = 10000,
++			.tCLS_min = 10000,
++			.tCOH_min = 15000,
++			.tCS_min = 20000,
++			.tDH_min = 5000,
++			.tDS_min = 10000,
++			.tFEAT_max = 1000000,
++			.tIR_min = 0,
++			.tITC_max = 1000000,
++			.tRC_min = 25000,
++			.tREA_max = 20000,
++			.tREH_min = 10000,
++			.tRHOH_min = 15000,
++			.tRHW_min = 100000,
++			.tRHZ_max = 100000,
++			.tRLOH_min = 5000,
++			.tRP_min = 12000,
++			.tRR_min = 20000,
++			.tRST_max = 500000000,
++			.tWB_max = 100000,
++			.tWC_min = 25000,
++			.tWH_min = 10000,
++			.tWHR_min = 80000,
++			.tWP_min = 12000,
++			.tWW_min = 100000,
++		},
++	},
++	/* Mode 5 */
++	{
++		.type = NAND_SDR_IFACE,
++		.timings.sdr = {
++			.tCCS_min = 500000,
++			.tR_max = 200000000,
++			.tADL_min = 400000,
++			.tALH_min = 5000,
++			.tALS_min = 10000,
++			.tAR_min = 10000,
++			.tCEA_max = 25000,
++			.tCEH_min = 20000,
++			.tCH_min = 5000,
++			.tCHZ_max = 30000,
++			.tCLH_min = 5000,
++			.tCLR_min = 10000,
++			.tCLS_min = 10000,
++			.tCOH_min = 15000,
++			.tCS_min = 15000,
++			.tDH_min = 5000,
++			.tDS_min = 7000,
++			.tFEAT_max = 1000000,
++			.tIR_min = 0,
++			.tITC_max = 1000000,
++			.tRC_min = 20000,
++			.tREA_max = 16000,
++			.tREH_min = 7000,
++			.tRHOH_min = 15000,
++			.tRHW_min = 100000,
++			.tRHZ_max = 100000,
++			.tRLOH_min = 5000,
++			.tRP_min = 10000,
++			.tRR_min = 20000,
++			.tRST_max = 500000000,
++			.tWB_max = 100000,
++			.tWC_min = 20000,
++			.tWH_min = 7000,
++			.tWHR_min = 80000,
++			.tWP_min = 10000,
++			.tWW_min = 100000,
++		},
++	},
++};
++
++/**
++ * onfi_async_timing_mode_to_sdr_timings - [NAND Interface] Retrieve NAND
++ * timings according to the given ONFI timing mode
++ * @mode: ONFI timing mode
++ */
++const struct nand_sdr_timings *onfi_async_timing_mode_to_sdr_timings(int mode)
++{
++	if (mode < 0 || mode >= ARRAY_SIZE(onfi_sdr_timings))
++		return ERR_PTR(-EINVAL);
++
++	return &onfi_sdr_timings[mode].timings.sdr;
++}
++EXPORT_SYMBOL(onfi_async_timing_mode_to_sdr_timings);
++
++/**
++ * onfi_init_data_interface - [NAND Interface] Initialize a data interface from
++ * given ONFI mode
++ * @iface: The data interface to be initialized
++ * @mode: The ONFI timing mode
++ */
++int onfi_init_data_interface(struct nand_chip *chip,
++			     struct nand_data_interface *iface,
++			     enum nand_data_interface_type type,
++			     int timing_mode)
++{
++	if (type != NAND_SDR_IFACE)
++		return -EINVAL;
++
++	if (timing_mode < 0 || timing_mode >= ARRAY_SIZE(onfi_sdr_timings))
++		return -EINVAL;
++
++	*iface = onfi_sdr_timings[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 = 1000000ULL * le16_to_cpu(params->t_prog);
++		timings->tBERS_max = 1000000ULL * le16_to_cpu(params->t_bers);
++		timings->tR_max = 1000000ULL * le16_to_cpu(params->t_r);
++
++		/* nanoseconds -> picoseconds */
++		timings->tCCS_min = 1000UL * le16_to_cpu(params->t_ccs);
++	}
++
++	return 0;
++}
++EXPORT_SYMBOL(onfi_init_data_interface);
++
++/**
++ * 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);
+diff --git a/drivers/mtd/nand/raw/nand_toshiba.c b/drivers/mtd/nand/raw/nand_toshiba.c
+new file mode 100644
+index 0000000..57df857
+--- /dev/null
++++ b/drivers/mtd/nand/raw/nand_toshiba.c
+@@ -0,0 +1,51 @@
++/*
++ * Copyright (C) 2017 Free Electrons
++ * Copyright (C) 2017 NextThing Co
++ *
++ * Author: Boris Brezillon <boris.brezillon@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 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/mtd/rawnand.h>
++
++static void toshiba_nand_decode_id(struct nand_chip *chip)
++{
++	struct mtd_info *mtd = nand_to_mtd(chip);
++
++	nand_decode_ext_id(chip);
++
++	/*
++	 * Toshiba 24nm raw SLC (i.e., not BENAND) have 32B OOB per
++	 * 512B page. For Toshiba SLC, we decode the 5th/6th byte as
++	 * follows:
++	 * - ID byte 6, bits[2:0]: 100b -> 43nm, 101b -> 32nm,
++	 *                         110b -> 24nm
++	 * - ID byte 5, bit[7]:    1 -> BENAND, 0 -> raw SLC
++	 */
++	if (chip->id.len >= 6 && nand_is_slc(chip) &&
++	    (chip->id.data[5] & 0x7) == 0x6 /* 24nm */ &&
++	    !(chip->id.data[4] & 0x80) /* !BENAND */)
++		mtd->oobsize = 32 * mtd->writesize >> 9;
++}
++
++static int toshiba_nand_init(struct nand_chip *chip)
++{
++	if (nand_is_slc(chip))
++		chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
++
++	return 0;
++}
++
++const struct nand_manufacturer_ops toshiba_nand_manuf_ops = {
++	.detect = toshiba_nand_decode_id,
++	.init = toshiba_nand_init,
++};
+diff --git a/drivers/mtd/nand/raw/nandsim.c b/drivers/mtd/nand/raw/nandsim.c
+new file mode 100644
+index 0000000..44322a3
+--- /dev/null
++++ b/drivers/mtd/nand/raw/nandsim.c
+@@ -0,0 +1,2392 @@
++/*
++ * NAND flash simulator.
++ *
++ * Author: Artem B. Bityuckiy <dedekind@oktetlabs.ru>, <dedekind@infradead.org>
++ *
++ * Copyright (C) 2004 Nokia Corporation
++ *
++ * Note: NS means "NAND Simulator".
++ * Note: Input means input TO flash chip, output means output FROM chip.
++ *
++ * 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, 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.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
++ */
++
++#include <linux/init.h>
++#include <linux/types.h>
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/vmalloc.h>
++#include <linux/math64.h>
++#include <linux/slab.h>
++#include <linux/errno.h>
++#include <linux/string.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/rawnand.h>
++#include <linux/mtd/nand_bch.h>
++#include <linux/mtd/partitions.h>
++#include <linux/delay.h>
++#include <linux/list.h>
++#include <linux/random.h>
++#include <linux/sched.h>
++#include <linux/sched/mm.h>
++#include <linux/fs.h>
++#include <linux/pagemap.h>
++#include <linux/seq_file.h>
++#include <linux/debugfs.h>
++
++/* Default simulator parameters values */
++#if !defined(CONFIG_NANDSIM_FIRST_ID_BYTE)  || \
++    !defined(CONFIG_NANDSIM_SECOND_ID_BYTE) || \
++    !defined(CONFIG_NANDSIM_THIRD_ID_BYTE)  || \
++    !defined(CONFIG_NANDSIM_FOURTH_ID_BYTE)
++#define CONFIG_NANDSIM_FIRST_ID_BYTE  0x98
++#define CONFIG_NANDSIM_SECOND_ID_BYTE 0x39
++#define CONFIG_NANDSIM_THIRD_ID_BYTE  0xFF /* No byte */
++#define CONFIG_NANDSIM_FOURTH_ID_BYTE 0xFF /* No byte */
++#endif
++
++#ifndef CONFIG_NANDSIM_ACCESS_DELAY
++#define CONFIG_NANDSIM_ACCESS_DELAY 25
++#endif
++#ifndef CONFIG_NANDSIM_PROGRAMM_DELAY
++#define CONFIG_NANDSIM_PROGRAMM_DELAY 200
++#endif
++#ifndef CONFIG_NANDSIM_ERASE_DELAY
++#define CONFIG_NANDSIM_ERASE_DELAY 2
++#endif
++#ifndef CONFIG_NANDSIM_OUTPUT_CYCLE
++#define CONFIG_NANDSIM_OUTPUT_CYCLE 40
++#endif
++#ifndef CONFIG_NANDSIM_INPUT_CYCLE
++#define CONFIG_NANDSIM_INPUT_CYCLE  50
++#endif
++#ifndef CONFIG_NANDSIM_BUS_WIDTH
++#define CONFIG_NANDSIM_BUS_WIDTH  8
++#endif
++#ifndef CONFIG_NANDSIM_DO_DELAYS
++#define CONFIG_NANDSIM_DO_DELAYS  0
++#endif
++#ifndef CONFIG_NANDSIM_LOG
++#define CONFIG_NANDSIM_LOG        0
++#endif
++#ifndef CONFIG_NANDSIM_DBG
++#define CONFIG_NANDSIM_DBG        0
++#endif
++#ifndef CONFIG_NANDSIM_MAX_PARTS
++#define CONFIG_NANDSIM_MAX_PARTS  32
++#endif
++
++static uint access_delay   = CONFIG_NANDSIM_ACCESS_DELAY;
++static uint programm_delay = CONFIG_NANDSIM_PROGRAMM_DELAY;
++static uint erase_delay    = CONFIG_NANDSIM_ERASE_DELAY;
++static uint output_cycle   = CONFIG_NANDSIM_OUTPUT_CYCLE;
++static uint input_cycle    = CONFIG_NANDSIM_INPUT_CYCLE;
++static uint bus_width      = CONFIG_NANDSIM_BUS_WIDTH;
++static uint do_delays      = CONFIG_NANDSIM_DO_DELAYS;
++static uint log            = CONFIG_NANDSIM_LOG;
++static uint dbg            = CONFIG_NANDSIM_DBG;
++static unsigned long parts[CONFIG_NANDSIM_MAX_PARTS];
++static unsigned int parts_num;
++static char *badblocks = NULL;
++static char *weakblocks = NULL;
++static char *weakpages = NULL;
++static unsigned int bitflips = 0;
++static char *gravepages = NULL;
++static unsigned int overridesize = 0;
++static char *cache_file = NULL;
++static unsigned int bbt;
++static unsigned int bch;
++static u_char id_bytes[8] = {
++	[0] = CONFIG_NANDSIM_FIRST_ID_BYTE,
++	[1] = CONFIG_NANDSIM_SECOND_ID_BYTE,
++	[2] = CONFIG_NANDSIM_THIRD_ID_BYTE,
++	[3] = CONFIG_NANDSIM_FOURTH_ID_BYTE,
++	[4 ... 7] = 0xFF,
++};
++
++module_param_array(id_bytes, byte, NULL, 0400);
++module_param_named(first_id_byte, id_bytes[0], byte, 0400);
++module_param_named(second_id_byte, id_bytes[1], byte, 0400);
++module_param_named(third_id_byte, id_bytes[2], byte, 0400);
++module_param_named(fourth_id_byte, id_bytes[3], byte, 0400);
++module_param(access_delay,   uint, 0400);
++module_param(programm_delay, uint, 0400);
++module_param(erase_delay,    uint, 0400);
++module_param(output_cycle,   uint, 0400);
++module_param(input_cycle,    uint, 0400);
++module_param(bus_width,      uint, 0400);
++module_param(do_delays,      uint, 0400);
++module_param(log,            uint, 0400);
++module_param(dbg,            uint, 0400);
++module_param_array(parts, ulong, &parts_num, 0400);
++module_param(badblocks,      charp, 0400);
++module_param(weakblocks,     charp, 0400);
++module_param(weakpages,      charp, 0400);
++module_param(bitflips,       uint, 0400);
++module_param(gravepages,     charp, 0400);
++module_param(overridesize,   uint, 0400);
++module_param(cache_file,     charp, 0400);
++module_param(bbt,	     uint, 0400);
++module_param(bch,	     uint, 0400);
++
++MODULE_PARM_DESC(id_bytes,       "The ID bytes returned by NAND Flash 'read ID' command");
++MODULE_PARM_DESC(first_id_byte,  "The first byte returned by NAND Flash 'read ID' command (manufacturer ID) (obsolete)");
++MODULE_PARM_DESC(second_id_byte, "The second byte returned by NAND Flash 'read ID' command (chip ID) (obsolete)");
++MODULE_PARM_DESC(third_id_byte,  "The third byte returned by NAND Flash 'read ID' command (obsolete)");
++MODULE_PARM_DESC(fourth_id_byte, "The fourth byte returned by NAND Flash 'read ID' command (obsolete)");
++MODULE_PARM_DESC(access_delay,   "Initial page access delay (microseconds)");
++MODULE_PARM_DESC(programm_delay, "Page programm delay (microseconds");
++MODULE_PARM_DESC(erase_delay,    "Sector erase delay (milliseconds)");
++MODULE_PARM_DESC(output_cycle,   "Word output (from flash) time (nanoseconds)");
++MODULE_PARM_DESC(input_cycle,    "Word input (to flash) time (nanoseconds)");
++MODULE_PARM_DESC(bus_width,      "Chip's bus width (8- or 16-bit)");
++MODULE_PARM_DESC(do_delays,      "Simulate NAND delays using busy-waits if not zero");
++MODULE_PARM_DESC(log,            "Perform logging if not zero");
++MODULE_PARM_DESC(dbg,            "Output debug information if not zero");
++MODULE_PARM_DESC(parts,          "Partition sizes (in erase blocks) separated by commas");
++/* Page and erase block positions for the following parameters are independent of any partitions */
++MODULE_PARM_DESC(badblocks,      "Erase blocks that are initially marked bad, separated by commas");
++MODULE_PARM_DESC(weakblocks,     "Weak erase blocks [: remaining erase cycles (defaults to 3)]"
++				 " separated by commas e.g. 113:2 means eb 113"
++				 " can be erased only twice before failing");
++MODULE_PARM_DESC(weakpages,      "Weak pages [: maximum writes (defaults to 3)]"
++				 " separated by commas e.g. 1401:2 means page 1401"
++				 " can be written only twice before failing");
++MODULE_PARM_DESC(bitflips,       "Maximum number of random bit flips per page (zero by default)");
++MODULE_PARM_DESC(gravepages,     "Pages that lose data [: maximum reads (defaults to 3)]"
++				 " separated by commas e.g. 1401:2 means page 1401"
++				 " can be read only twice before failing");
++MODULE_PARM_DESC(overridesize,   "Specifies the NAND Flash size overriding the ID bytes. "
++				 "The size is specified in erase blocks and as the exponent of a power of two"
++				 " e.g. 5 means a size of 32 erase blocks");
++MODULE_PARM_DESC(cache_file,     "File to use to cache nand pages instead of memory");
++MODULE_PARM_DESC(bbt,		 "0 OOB, 1 BBT with marker in OOB, 2 BBT with marker in data area");
++MODULE_PARM_DESC(bch,		 "Enable BCH ecc and set how many bits should "
++				 "be correctable in 512-byte blocks");
++
++/* The largest possible page size */
++#define NS_LARGEST_PAGE_SIZE	4096
++
++/* The prefix for simulator output */
++#define NS_OUTPUT_PREFIX "[nandsim]"
++
++/* Simulator's output macros (logging, debugging, warning, error) */
++#define NS_LOG(args...) \
++	do { if (log) printk(KERN_DEBUG NS_OUTPUT_PREFIX " log: " args); } while(0)
++#define NS_DBG(args...) \
++	do { if (dbg) printk(KERN_DEBUG NS_OUTPUT_PREFIX " debug: " args); } while(0)
++#define NS_WARN(args...) \
++	do { printk(KERN_WARNING NS_OUTPUT_PREFIX " warning: " args); } while(0)
++#define NS_ERR(args...) \
++	do { printk(KERN_ERR NS_OUTPUT_PREFIX " error: " args); } while(0)
++#define NS_INFO(args...) \
++	do { printk(KERN_INFO NS_OUTPUT_PREFIX " " args); } while(0)
++
++/* Busy-wait delay macros (microseconds, milliseconds) */
++#define NS_UDELAY(us) \
++        do { if (do_delays) udelay(us); } while(0)
++#define NS_MDELAY(us) \
++        do { if (do_delays) mdelay(us); } while(0)
++
++/* Is the nandsim structure initialized ? */
++#define NS_IS_INITIALIZED(ns) ((ns)->geom.totsz != 0)
++
++/* Good operation completion status */
++#define NS_STATUS_OK(ns) (NAND_STATUS_READY | (NAND_STATUS_WP * ((ns)->lines.wp == 0)))
++
++/* Operation failed completion status */
++#define NS_STATUS_FAILED(ns) (NAND_STATUS_FAIL | NS_STATUS_OK(ns))
++
++/* Calculate the page offset in flash RAM image by (row, column) address */
++#define NS_RAW_OFFSET(ns) \
++	(((ns)->regs.row * (ns)->geom.pgszoob) + (ns)->regs.column)
++
++/* Calculate the OOB offset in flash RAM image by (row, column) address */
++#define NS_RAW_OFFSET_OOB(ns) (NS_RAW_OFFSET(ns) + ns->geom.pgsz)
++
++/* After a command is input, the simulator goes to one of the following states */
++#define STATE_CMD_READ0        0x00000001 /* read data from the beginning of page */
++#define STATE_CMD_READ1        0x00000002 /* read data from the second half of page */
++#define STATE_CMD_READSTART    0x00000003 /* read data second command (large page devices) */
++#define STATE_CMD_PAGEPROG     0x00000004 /* start page program */
++#define STATE_CMD_READOOB      0x00000005 /* read OOB area */
++#define STATE_CMD_ERASE1       0x00000006 /* sector erase first command */
++#define STATE_CMD_STATUS       0x00000007 /* read status */
++#define STATE_CMD_SEQIN        0x00000009 /* sequential data input */
++#define STATE_CMD_READID       0x0000000A /* read ID */
++#define STATE_CMD_ERASE2       0x0000000B /* sector erase second command */
++#define STATE_CMD_RESET        0x0000000C /* reset */
++#define STATE_CMD_RNDOUT       0x0000000D /* random output command */
++#define STATE_CMD_RNDOUTSTART  0x0000000E /* random output start command */
++#define STATE_CMD_MASK         0x0000000F /* command states mask */
++
++/* After an address is input, the simulator goes to one of these states */
++#define STATE_ADDR_PAGE        0x00000010 /* full (row, column) address is accepted */
++#define STATE_ADDR_SEC         0x00000020 /* sector address was accepted */
++#define STATE_ADDR_COLUMN      0x00000030 /* column address was accepted */
++#define STATE_ADDR_ZERO        0x00000040 /* one byte zero address was accepted */
++#define STATE_ADDR_MASK        0x00000070 /* address states mask */
++
++/* During data input/output the simulator is in these states */
++#define STATE_DATAIN           0x00000100 /* waiting for data input */
++#define STATE_DATAIN_MASK      0x00000100 /* data input states mask */
++
++#define STATE_DATAOUT          0x00001000 /* waiting for page data output */
++#define STATE_DATAOUT_ID       0x00002000 /* waiting for ID bytes output */
++#define STATE_DATAOUT_STATUS   0x00003000 /* waiting for status output */
++#define STATE_DATAOUT_MASK     0x00007000 /* data output states mask */
++
++/* Previous operation is done, ready to accept new requests */
++#define STATE_READY            0x00000000
++
++/* This state is used to mark that the next state isn't known yet */
++#define STATE_UNKNOWN          0x10000000
++
++/* Simulator's actions bit masks */
++#define ACTION_CPY       0x00100000 /* copy page/OOB to the internal buffer */
++#define ACTION_PRGPAGE   0x00200000 /* program the internal buffer to flash */
++#define ACTION_SECERASE  0x00300000 /* erase sector */
++#define ACTION_ZEROOFF   0x00400000 /* don't add any offset to address */
++#define ACTION_HALFOFF   0x00500000 /* add to address half of page */
++#define ACTION_OOBOFF    0x00600000 /* add to address OOB offset */
++#define ACTION_MASK      0x00700000 /* action mask */
++
++#define NS_OPER_NUM      13 /* Number of operations supported by the simulator */
++#define NS_OPER_STATES   6  /* Maximum number of states in operation */
++
++#define OPT_ANY          0xFFFFFFFF /* any chip supports this operation */
++#define OPT_PAGE512      0x00000002 /* 512-byte  page chips */
++#define OPT_PAGE2048     0x00000008 /* 2048-byte page chips */
++#define OPT_PAGE512_8BIT 0x00000040 /* 512-byte page chips with 8-bit bus width */
++#define OPT_PAGE4096     0x00000080 /* 4096-byte page chips */
++#define OPT_LARGEPAGE    (OPT_PAGE2048 | OPT_PAGE4096) /* 2048 & 4096-byte page chips */
++#define OPT_SMALLPAGE    (OPT_PAGE512) /* 512-byte page chips */
++
++/* Remove action bits from state */
++#define NS_STATE(x) ((x) & ~ACTION_MASK)
++
++/*
++ * Maximum previous states which need to be saved. Currently saving is
++ * only needed for page program operation with preceded read command
++ * (which is only valid for 512-byte pages).
++ */
++#define NS_MAX_PREVSTATES 1
++
++/* Maximum page cache pages needed to read or write a NAND page to the cache_file */
++#define NS_MAX_HELD_PAGES 16
++
++/*
++ * A union to represent flash memory contents and flash buffer.
++ */
++union ns_mem {
++	u_char *byte;    /* for byte access */
++	uint16_t *word;  /* for 16-bit word access */
++};
++
++/*
++ * The structure which describes all the internal simulator data.
++ */
++struct nandsim {
++	struct mtd_partition partitions[CONFIG_NANDSIM_MAX_PARTS];
++	unsigned int nbparts;
++
++	uint busw;              /* flash chip bus width (8 or 16) */
++	u_char ids[8];          /* chip's ID bytes */
++	uint32_t options;       /* chip's characteristic bits */
++	uint32_t state;         /* current chip state */
++	uint32_t nxstate;       /* next expected state */
++
++	uint32_t *op;           /* current operation, NULL operations isn't known yet  */
++	uint32_t pstates[NS_MAX_PREVSTATES]; /* previous states */
++	uint16_t npstates;      /* number of previous states saved */
++	uint16_t stateidx;      /* current state index */
++
++	/* The simulated NAND flash pages array */
++	union ns_mem *pages;
++
++	/* Slab allocator for nand pages */
++	struct kmem_cache *nand_pages_slab;
++
++	/* Internal buffer of page + OOB size bytes */
++	union ns_mem buf;
++
++	/* NAND flash "geometry" */
++	struct {
++		uint64_t totsz;     /* total flash size, bytes */
++		uint32_t secsz;     /* flash sector (erase block) size, bytes */
++		uint pgsz;          /* NAND flash page size, bytes */
++		uint oobsz;         /* page OOB area size, bytes */
++		uint64_t totszoob;  /* total flash size including OOB, bytes */
++		uint pgszoob;       /* page size including OOB , bytes*/
++		uint secszoob;      /* sector size including OOB, bytes */
++		uint pgnum;         /* total number of pages */
++		uint pgsec;         /* number of pages per sector */
++		uint secshift;      /* bits number in sector size */
++		uint pgshift;       /* bits number in page size */
++		uint pgaddrbytes;   /* bytes per page address */
++		uint secaddrbytes;  /* bytes per sector address */
++		uint idbytes;       /* the number ID bytes that this chip outputs */
++	} geom;
++
++	/* NAND flash internal registers */
++	struct {
++		unsigned command; /* the command register */
++		u_char   status;  /* the status register */
++		uint     row;     /* the page number */
++		uint     column;  /* the offset within page */
++		uint     count;   /* internal counter */
++		uint     num;     /* number of bytes which must be processed */
++		uint     off;     /* fixed page offset */
++	} regs;
++
++	/* NAND flash lines state */
++        struct {
++                int ce;  /* chip Enable */
++                int cle; /* command Latch Enable */
++                int ale; /* address Latch Enable */
++                int wp;  /* write Protect */
++        } lines;
++
++	/* Fields needed when using a cache file */
++	struct file *cfile; /* Open file */
++	unsigned long *pages_written; /* Which pages have been written */
++	void *file_buf;
++	struct page *held_pages[NS_MAX_HELD_PAGES];
++	int held_cnt;
++};
++
++/*
++ * Operations array. To perform any operation the simulator must pass
++ * through the correspondent states chain.
++ */
++static struct nandsim_operations {
++	uint32_t reqopts;  /* options which are required to perform the operation */
++	uint32_t states[NS_OPER_STATES]; /* operation's states */
++} ops[NS_OPER_NUM] = {
++	/* Read page + OOB from the beginning */
++	{OPT_SMALLPAGE, {STATE_CMD_READ0 | ACTION_ZEROOFF, STATE_ADDR_PAGE | ACTION_CPY,
++			STATE_DATAOUT, STATE_READY}},
++	/* Read page + OOB from the second half */
++	{OPT_PAGE512_8BIT, {STATE_CMD_READ1 | ACTION_HALFOFF, STATE_ADDR_PAGE | ACTION_CPY,
++			STATE_DATAOUT, STATE_READY}},
++	/* Read OOB */
++	{OPT_SMALLPAGE, {STATE_CMD_READOOB | ACTION_OOBOFF, STATE_ADDR_PAGE | ACTION_CPY,
++			STATE_DATAOUT, STATE_READY}},
++	/* Program page starting from the beginning */
++	{OPT_ANY, {STATE_CMD_SEQIN, STATE_ADDR_PAGE, STATE_DATAIN,
++			STATE_CMD_PAGEPROG | ACTION_PRGPAGE, STATE_READY}},
++	/* Program page starting from the beginning */
++	{OPT_SMALLPAGE, {STATE_CMD_READ0, STATE_CMD_SEQIN | ACTION_ZEROOFF, STATE_ADDR_PAGE,
++			      STATE_DATAIN, STATE_CMD_PAGEPROG | ACTION_PRGPAGE, STATE_READY}},
++	/* Program page starting from the second half */
++	{OPT_PAGE512, {STATE_CMD_READ1, STATE_CMD_SEQIN | ACTION_HALFOFF, STATE_ADDR_PAGE,
++			      STATE_DATAIN, STATE_CMD_PAGEPROG | ACTION_PRGPAGE, STATE_READY}},
++	/* Program OOB */
++	{OPT_SMALLPAGE, {STATE_CMD_READOOB, STATE_CMD_SEQIN | ACTION_OOBOFF, STATE_ADDR_PAGE,
++			      STATE_DATAIN, STATE_CMD_PAGEPROG | ACTION_PRGPAGE, STATE_READY}},
++	/* Erase sector */
++	{OPT_ANY, {STATE_CMD_ERASE1, STATE_ADDR_SEC, STATE_CMD_ERASE2 | ACTION_SECERASE, STATE_READY}},
++	/* Read status */
++	{OPT_ANY, {STATE_CMD_STATUS, STATE_DATAOUT_STATUS, STATE_READY}},
++	/* Read ID */
++	{OPT_ANY, {STATE_CMD_READID, STATE_ADDR_ZERO, STATE_DATAOUT_ID, STATE_READY}},
++	/* Large page devices read page */
++	{OPT_LARGEPAGE, {STATE_CMD_READ0, STATE_ADDR_PAGE, STATE_CMD_READSTART | ACTION_CPY,
++			       STATE_DATAOUT, STATE_READY}},
++	/* Large page devices random page read */
++	{OPT_LARGEPAGE, {STATE_CMD_RNDOUT, STATE_ADDR_COLUMN, STATE_CMD_RNDOUTSTART | ACTION_CPY,
++			       STATE_DATAOUT, STATE_READY}},
++};
++
++struct weak_block {
++	struct list_head list;
++	unsigned int erase_block_no;
++	unsigned int max_erases;
++	unsigned int erases_done;
++};
++
++static LIST_HEAD(weak_blocks);
++
++struct weak_page {
++	struct list_head list;
++	unsigned int page_no;
++	unsigned int max_writes;
++	unsigned int writes_done;
++};
++
++static LIST_HEAD(weak_pages);
++
++struct grave_page {
++	struct list_head list;
++	unsigned int page_no;
++	unsigned int max_reads;
++	unsigned int reads_done;
++};
++
++static LIST_HEAD(grave_pages);
++
++static unsigned long *erase_block_wear = NULL;
++static unsigned int wear_eb_count = 0;
++static unsigned long total_wear = 0;
++
++/* MTD structure for NAND controller */
++static struct mtd_info *nsmtd;
++
++static int nandsim_debugfs_show(struct seq_file *m, void *private)
++{
++	unsigned long wmin = -1, wmax = 0, avg;
++	unsigned long deciles[10], decile_max[10], tot = 0;
++	unsigned int i;
++
++	/* Calc wear stats */
++	for (i = 0; i < wear_eb_count; ++i) {
++		unsigned long wear = erase_block_wear[i];
++		if (wear < wmin)
++			wmin = wear;
++		if (wear > wmax)
++			wmax = wear;
++		tot += wear;
++	}
++
++	for (i = 0; i < 9; ++i) {
++		deciles[i] = 0;
++		decile_max[i] = (wmax * (i + 1) + 5) / 10;
++	}
++	deciles[9] = 0;
++	decile_max[9] = wmax;
++	for (i = 0; i < wear_eb_count; ++i) {
++		int d;
++		unsigned long wear = erase_block_wear[i];
++		for (d = 0; d < 10; ++d)
++			if (wear <= decile_max[d]) {
++				deciles[d] += 1;
++				break;
++			}
++	}
++	avg = tot / wear_eb_count;
++
++	/* Output wear report */
++	seq_printf(m, "Total numbers of erases:  %lu\n", tot);
++	seq_printf(m, "Number of erase blocks:   %u\n", wear_eb_count);
++	seq_printf(m, "Average number of erases: %lu\n", avg);
++	seq_printf(m, "Maximum number of erases: %lu\n", wmax);
++	seq_printf(m, "Minimum number of erases: %lu\n", wmin);
++	for (i = 0; i < 10; ++i) {
++		unsigned long from = (i ? decile_max[i - 1] + 1 : 0);
++		if (from > decile_max[i])
++			continue;
++		seq_printf(m, "Number of ebs with erase counts from %lu to %lu : %lu\n",
++			from,
++			decile_max[i],
++			deciles[i]);
++	}
++
++	return 0;
++}
++
++static int nandsim_debugfs_open(struct inode *inode, struct file *file)
++{
++	return single_open(file, nandsim_debugfs_show, inode->i_private);
++}
++
++static const struct file_operations dfs_fops = {
++	.open		= nandsim_debugfs_open,
++	.read		= seq_read,
++	.llseek		= seq_lseek,
++	.release	= single_release,
++};
++
++/**
++ * nandsim_debugfs_create - initialize debugfs
++ * @dev: nandsim device description object
++ *
++ * This function creates all debugfs files for UBI device @ubi. Returns zero in
++ * case of success and a negative error code in case of failure.
++ */
++static int nandsim_debugfs_create(struct nandsim *dev)
++{
++	struct dentry *root = nsmtd->dbg.dfs_dir;
++	struct dentry *dent;
++
++	/*
++	 * Just skip debugfs initialization when the debugfs directory is
++	 * missing.
++	 */
++	if (IS_ERR_OR_NULL(root)) {
++		if (IS_ENABLED(CONFIG_DEBUG_FS) &&
++		    !IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER))
++			NS_WARN("CONFIG_MTD_PARTITIONED_MASTER must be enabled to expose debugfs stuff\n");
++		return 0;
++	}
++
++	dent = debugfs_create_file("nandsim_wear_report", S_IRUSR,
++				   root, dev, &dfs_fops);
++	if (IS_ERR_OR_NULL(dent)) {
++		NS_ERR("cannot create \"nandsim_wear_report\" debugfs entry\n");
++		return -1;
++	}
++
++	return 0;
++}
++
++/*
++ * Allocate array of page pointers, create slab allocation for an array
++ * and initialize the array by NULL pointers.
++ *
++ * RETURNS: 0 if success, -ENOMEM if memory alloc fails.
++ */
++static int __init alloc_device(struct nandsim *ns)
++{
++	struct file *cfile;
++	int i, err;
++
++	if (cache_file) {
++		cfile = filp_open(cache_file, O_CREAT | O_RDWR | O_LARGEFILE, 0600);
++		if (IS_ERR(cfile))
++			return PTR_ERR(cfile);
++		if (!(cfile->f_mode & FMODE_CAN_READ)) {
++			NS_ERR("alloc_device: cache file not readable\n");
++			err = -EINVAL;
++			goto err_close;
++		}
++		if (!(cfile->f_mode & FMODE_CAN_WRITE)) {
++			NS_ERR("alloc_device: cache file not writeable\n");
++			err = -EINVAL;
++			goto err_close;
++		}
++		ns->pages_written = vzalloc(BITS_TO_LONGS(ns->geom.pgnum) *
++					    sizeof(unsigned long));
++		if (!ns->pages_written) {
++			NS_ERR("alloc_device: unable to allocate pages written array\n");
++			err = -ENOMEM;
++			goto err_close;
++		}
++		ns->file_buf = kmalloc(ns->geom.pgszoob, GFP_KERNEL);
++		if (!ns->file_buf) {
++			NS_ERR("alloc_device: unable to allocate file buf\n");
++			err = -ENOMEM;
++			goto err_free;
++		}
++		ns->cfile = cfile;
++		return 0;
++	}
++
++	ns->pages = vmalloc(ns->geom.pgnum * sizeof(union ns_mem));
++	if (!ns->pages) {
++		NS_ERR("alloc_device: unable to allocate page array\n");
++		return -ENOMEM;
++	}
++	for (i = 0; i < ns->geom.pgnum; i++) {
++		ns->pages[i].byte = NULL;
++	}
++	ns->nand_pages_slab = kmem_cache_create("nandsim",
++						ns->geom.pgszoob, 0, 0, NULL);
++	if (!ns->nand_pages_slab) {
++		NS_ERR("cache_create: unable to create kmem_cache\n");
++		return -ENOMEM;
++	}
++
++	return 0;
++
++err_free:
++	vfree(ns->pages_written);
++err_close:
++	filp_close(cfile, NULL);
++	return err;
++}
++
++/*
++ * Free any allocated pages, and free the array of page pointers.
++ */
++static void free_device(struct nandsim *ns)
++{
++	int i;
++
++	if (ns->cfile) {
++		kfree(ns->file_buf);
++		vfree(ns->pages_written);
++		filp_close(ns->cfile, NULL);
++		return;
++	}
++
++	if (ns->pages) {
++		for (i = 0; i < ns->geom.pgnum; i++) {
++			if (ns->pages[i].byte)
++				kmem_cache_free(ns->nand_pages_slab,
++						ns->pages[i].byte);
++		}
++		kmem_cache_destroy(ns->nand_pages_slab);
++		vfree(ns->pages);
++	}
++}
++
++static char __init *get_partition_name(int i)
++{
++	return kasprintf(GFP_KERNEL, "NAND simulator partition %d", i);
++}
++
++/*
++ * Initialize the nandsim structure.
++ *
++ * RETURNS: 0 if success, -ERRNO if failure.
++ */
++static int __init init_nandsim(struct mtd_info *mtd)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct nandsim   *ns   = nand_get_controller_data(chip);
++	int i, ret = 0;
++	uint64_t remains;
++	uint64_t next_offset;
++
++	if (NS_IS_INITIALIZED(ns)) {
++		NS_ERR("init_nandsim: nandsim is already initialized\n");
++		return -EIO;
++	}
++
++	/* Force mtd to not do delays */
++	chip->chip_delay = 0;
++
++	/* Initialize the NAND flash parameters */
++	ns->busw = chip->options & NAND_BUSWIDTH_16 ? 16 : 8;
++	ns->geom.totsz    = mtd->size;
++	ns->geom.pgsz     = mtd->writesize;
++	ns->geom.oobsz    = mtd->oobsize;
++	ns->geom.secsz    = mtd->erasesize;
++	ns->geom.pgszoob  = ns->geom.pgsz + ns->geom.oobsz;
++	ns->geom.pgnum    = div_u64(ns->geom.totsz, ns->geom.pgsz);
++	ns->geom.totszoob = ns->geom.totsz + (uint64_t)ns->geom.pgnum * ns->geom.oobsz;
++	ns->geom.secshift = ffs(ns->geom.secsz) - 1;
++	ns->geom.pgshift  = chip->page_shift;
++	ns->geom.pgsec    = ns->geom.secsz / ns->geom.pgsz;
++	ns->geom.secszoob = ns->geom.secsz + ns->geom.oobsz * ns->geom.pgsec;
++	ns->options = 0;
++
++	if (ns->geom.pgsz == 512) {
++		ns->options |= OPT_PAGE512;
++		if (ns->busw == 8)
++			ns->options |= OPT_PAGE512_8BIT;
++	} else if (ns->geom.pgsz == 2048) {
++		ns->options |= OPT_PAGE2048;
++	} else if (ns->geom.pgsz == 4096) {
++		ns->options |= OPT_PAGE4096;
++	} else {
++		NS_ERR("init_nandsim: unknown page size %u\n", ns->geom.pgsz);
++		return -EIO;
++	}
++
++	if (ns->options & OPT_SMALLPAGE) {
++		if (ns->geom.totsz <= (32 << 20)) {
++			ns->geom.pgaddrbytes  = 3;
++			ns->geom.secaddrbytes = 2;
++		} else {
++			ns->geom.pgaddrbytes  = 4;
++			ns->geom.secaddrbytes = 3;
++		}
++	} else {
++		if (ns->geom.totsz <= (128 << 20)) {
++			ns->geom.pgaddrbytes  = 4;
++			ns->geom.secaddrbytes = 2;
++		} else {
++			ns->geom.pgaddrbytes  = 5;
++			ns->geom.secaddrbytes = 3;
++		}
++	}
++
++	/* Fill the partition_info structure */
++	if (parts_num > ARRAY_SIZE(ns->partitions)) {
++		NS_ERR("too many partitions.\n");
++		return -EINVAL;
++	}
++	remains = ns->geom.totsz;
++	next_offset = 0;
++	for (i = 0; i < parts_num; ++i) {
++		uint64_t part_sz = (uint64_t)parts[i] * ns->geom.secsz;
++
++		if (!part_sz || part_sz > remains) {
++			NS_ERR("bad partition size.\n");
++			return -EINVAL;
++		}
++		ns->partitions[i].name   = get_partition_name(i);
++		if (!ns->partitions[i].name) {
++			NS_ERR("unable to allocate memory.\n");
++			return -ENOMEM;
++		}
++		ns->partitions[i].offset = next_offset;
++		ns->partitions[i].size   = part_sz;
++		next_offset += ns->partitions[i].size;
++		remains -= ns->partitions[i].size;
++	}
++	ns->nbparts = parts_num;
++	if (remains) {
++		if (parts_num + 1 > ARRAY_SIZE(ns->partitions)) {
++			NS_ERR("too many partitions.\n");
++			return -EINVAL;
++		}
++		ns->partitions[i].name   = get_partition_name(i);
++		if (!ns->partitions[i].name) {
++			NS_ERR("unable to allocate memory.\n");
++			return -ENOMEM;
++		}
++		ns->partitions[i].offset = next_offset;
++		ns->partitions[i].size   = remains;
++		ns->nbparts += 1;
++	}
++
++	if (ns->busw == 16)
++		NS_WARN("16-bit flashes support wasn't tested\n");
++
++	printk("flash size: %llu MiB\n",
++			(unsigned long long)ns->geom.totsz >> 20);
++	printk("page size: %u bytes\n",         ns->geom.pgsz);
++	printk("OOB area size: %u bytes\n",     ns->geom.oobsz);
++	printk("sector size: %u KiB\n",         ns->geom.secsz >> 10);
++	printk("pages number: %u\n",            ns->geom.pgnum);
++	printk("pages per sector: %u\n",        ns->geom.pgsec);
++	printk("bus width: %u\n",               ns->busw);
++	printk("bits in sector size: %u\n",     ns->geom.secshift);
++	printk("bits in page size: %u\n",       ns->geom.pgshift);
++	printk("bits in OOB size: %u\n",	ffs(ns->geom.oobsz) - 1);
++	printk("flash size with OOB: %llu KiB\n",
++			(unsigned long long)ns->geom.totszoob >> 10);
++	printk("page address bytes: %u\n",      ns->geom.pgaddrbytes);
++	printk("sector address bytes: %u\n",    ns->geom.secaddrbytes);
++	printk("options: %#x\n",                ns->options);
++
++	if ((ret = alloc_device(ns)) != 0)
++		return ret;
++
++	/* Allocate / initialize the internal buffer */
++	ns->buf.byte = kmalloc(ns->geom.pgszoob, GFP_KERNEL);
++	if (!ns->buf.byte) {
++		NS_ERR("init_nandsim: unable to allocate %u bytes for the internal buffer\n",
++			ns->geom.pgszoob);
++		return -ENOMEM;
++	}
++	memset(ns->buf.byte, 0xFF, ns->geom.pgszoob);
++
++	return 0;
++}
++
++/*
++ * Free the nandsim structure.
++ */
++static void free_nandsim(struct nandsim *ns)
++{
++	kfree(ns->buf.byte);
++	free_device(ns);
++
++	return;
++}
++
++static int parse_badblocks(struct nandsim *ns, struct mtd_info *mtd)
++{
++	char *w;
++	int zero_ok;
++	unsigned int erase_block_no;
++	loff_t offset;
++
++	if (!badblocks)
++		return 0;
++	w = badblocks;
++	do {
++		zero_ok = (*w == '0' ? 1 : 0);
++		erase_block_no = simple_strtoul(w, &w, 0);
++		if (!zero_ok && !erase_block_no) {
++			NS_ERR("invalid badblocks.\n");
++			return -EINVAL;
++		}
++		offset = (loff_t)erase_block_no * ns->geom.secsz;
++		if (mtd_block_markbad(mtd, offset)) {
++			NS_ERR("invalid badblocks.\n");
++			return -EINVAL;
++		}
++		if (*w == ',')
++			w += 1;
++	} while (*w);
++	return 0;
++}
++
++static int parse_weakblocks(void)
++{
++	char *w;
++	int zero_ok;
++	unsigned int erase_block_no;
++	unsigned int max_erases;
++	struct weak_block *wb;
++
++	if (!weakblocks)
++		return 0;
++	w = weakblocks;
++	do {
++		zero_ok = (*w == '0' ? 1 : 0);
++		erase_block_no = simple_strtoul(w, &w, 0);
++		if (!zero_ok && !erase_block_no) {
++			NS_ERR("invalid weakblocks.\n");
++			return -EINVAL;
++		}
++		max_erases = 3;
++		if (*w == ':') {
++			w += 1;
++			max_erases = simple_strtoul(w, &w, 0);
++		}
++		if (*w == ',')
++			w += 1;
++		wb = kzalloc(sizeof(*wb), GFP_KERNEL);
++		if (!wb) {
++			NS_ERR("unable to allocate memory.\n");
++			return -ENOMEM;
++		}
++		wb->erase_block_no = erase_block_no;
++		wb->max_erases = max_erases;
++		list_add(&wb->list, &weak_blocks);
++	} while (*w);
++	return 0;
++}
++
++static int erase_error(unsigned int erase_block_no)
++{
++	struct weak_block *wb;
++
++	list_for_each_entry(wb, &weak_blocks, list)
++		if (wb->erase_block_no == erase_block_no) {
++			if (wb->erases_done >= wb->max_erases)
++				return 1;
++			wb->erases_done += 1;
++			return 0;
++		}
++	return 0;
++}
++
++static int parse_weakpages(void)
++{
++	char *w;
++	int zero_ok;
++	unsigned int page_no;
++	unsigned int max_writes;
++	struct weak_page *wp;
++
++	if (!weakpages)
++		return 0;
++	w = weakpages;
++	do {
++		zero_ok = (*w == '0' ? 1 : 0);
++		page_no = simple_strtoul(w, &w, 0);
++		if (!zero_ok && !page_no) {
++			NS_ERR("invalid weakpages.\n");
++			return -EINVAL;
++		}
++		max_writes = 3;
++		if (*w == ':') {
++			w += 1;
++			max_writes = simple_strtoul(w, &w, 0);
++		}
++		if (*w == ',')
++			w += 1;
++		wp = kzalloc(sizeof(*wp), GFP_KERNEL);
++		if (!wp) {
++			NS_ERR("unable to allocate memory.\n");
++			return -ENOMEM;
++		}
++		wp->page_no = page_no;
++		wp->max_writes = max_writes;
++		list_add(&wp->list, &weak_pages);
++	} while (*w);
++	return 0;
++}
++
++static int write_error(unsigned int page_no)
++{
++	struct weak_page *wp;
++
++	list_for_each_entry(wp, &weak_pages, list)
++		if (wp->page_no == page_no) {
++			if (wp->writes_done >= wp->max_writes)
++				return 1;
++			wp->writes_done += 1;
++			return 0;
++		}
++	return 0;
++}
++
++static int parse_gravepages(void)
++{
++	char *g;
++	int zero_ok;
++	unsigned int page_no;
++	unsigned int max_reads;
++	struct grave_page *gp;
++
++	if (!gravepages)
++		return 0;
++	g = gravepages;
++	do {
++		zero_ok = (*g == '0' ? 1 : 0);
++		page_no = simple_strtoul(g, &g, 0);
++		if (!zero_ok && !page_no) {
++			NS_ERR("invalid gravepagess.\n");
++			return -EINVAL;
++		}
++		max_reads = 3;
++		if (*g == ':') {
++			g += 1;
++			max_reads = simple_strtoul(g, &g, 0);
++		}
++		if (*g == ',')
++			g += 1;
++		gp = kzalloc(sizeof(*gp), GFP_KERNEL);
++		if (!gp) {
++			NS_ERR("unable to allocate memory.\n");
++			return -ENOMEM;
++		}
++		gp->page_no = page_no;
++		gp->max_reads = max_reads;
++		list_add(&gp->list, &grave_pages);
++	} while (*g);
++	return 0;
++}
++
++static int read_error(unsigned int page_no)
++{
++	struct grave_page *gp;
++
++	list_for_each_entry(gp, &grave_pages, list)
++		if (gp->page_no == page_no) {
++			if (gp->reads_done >= gp->max_reads)
++				return 1;
++			gp->reads_done += 1;
++			return 0;
++		}
++	return 0;
++}
++
++static void free_lists(void)
++{
++	struct list_head *pos, *n;
++	list_for_each_safe(pos, n, &weak_blocks) {
++		list_del(pos);
++		kfree(list_entry(pos, struct weak_block, list));
++	}
++	list_for_each_safe(pos, n, &weak_pages) {
++		list_del(pos);
++		kfree(list_entry(pos, struct weak_page, list));
++	}
++	list_for_each_safe(pos, n, &grave_pages) {
++		list_del(pos);
++		kfree(list_entry(pos, struct grave_page, list));
++	}
++	kfree(erase_block_wear);
++}
++
++static int setup_wear_reporting(struct mtd_info *mtd)
++{
++	size_t mem;
++
++	wear_eb_count = div_u64(mtd->size, mtd->erasesize);
++	mem = wear_eb_count * sizeof(unsigned long);
++	if (mem / sizeof(unsigned long) != wear_eb_count) {
++		NS_ERR("Too many erase blocks for wear reporting\n");
++		return -ENOMEM;
++	}
++	erase_block_wear = kzalloc(mem, GFP_KERNEL);
++	if (!erase_block_wear) {
++		NS_ERR("Too many erase blocks for wear reporting\n");
++		return -ENOMEM;
++	}
++	return 0;
++}
++
++static void update_wear(unsigned int erase_block_no)
++{
++	if (!erase_block_wear)
++		return;
++	total_wear += 1;
++	/*
++	 * TODO: Notify this through a debugfs entry,
++	 * instead of showing an error message.
++	 */
++	if (total_wear == 0)
++		NS_ERR("Erase counter total overflow\n");
++	erase_block_wear[erase_block_no] += 1;
++	if (erase_block_wear[erase_block_no] == 0)
++		NS_ERR("Erase counter overflow for erase block %u\n", erase_block_no);
++}
++
++/*
++ * Returns the string representation of 'state' state.
++ */
++static char *get_state_name(uint32_t state)
++{
++	switch (NS_STATE(state)) {
++		case STATE_CMD_READ0:
++			return "STATE_CMD_READ0";
++		case STATE_CMD_READ1:
++			return "STATE_CMD_READ1";
++		case STATE_CMD_PAGEPROG:
++			return "STATE_CMD_PAGEPROG";
++		case STATE_CMD_READOOB:
++			return "STATE_CMD_READOOB";
++		case STATE_CMD_READSTART:
++			return "STATE_CMD_READSTART";
++		case STATE_CMD_ERASE1:
++			return "STATE_CMD_ERASE1";
++		case STATE_CMD_STATUS:
++			return "STATE_CMD_STATUS";
++		case STATE_CMD_SEQIN:
++			return "STATE_CMD_SEQIN";
++		case STATE_CMD_READID:
++			return "STATE_CMD_READID";
++		case STATE_CMD_ERASE2:
++			return "STATE_CMD_ERASE2";
++		case STATE_CMD_RESET:
++			return "STATE_CMD_RESET";
++		case STATE_CMD_RNDOUT:
++			return "STATE_CMD_RNDOUT";
++		case STATE_CMD_RNDOUTSTART:
++			return "STATE_CMD_RNDOUTSTART";
++		case STATE_ADDR_PAGE:
++			return "STATE_ADDR_PAGE";
++		case STATE_ADDR_SEC:
++			return "STATE_ADDR_SEC";
++		case STATE_ADDR_ZERO:
++			return "STATE_ADDR_ZERO";
++		case STATE_ADDR_COLUMN:
++			return "STATE_ADDR_COLUMN";
++		case STATE_DATAIN:
++			return "STATE_DATAIN";
++		case STATE_DATAOUT:
++			return "STATE_DATAOUT";
++		case STATE_DATAOUT_ID:
++			return "STATE_DATAOUT_ID";
++		case STATE_DATAOUT_STATUS:
++			return "STATE_DATAOUT_STATUS";
++		case STATE_READY:
++			return "STATE_READY";
++		case STATE_UNKNOWN:
++			return "STATE_UNKNOWN";
++	}
++
++	NS_ERR("get_state_name: unknown state, BUG\n");
++	return NULL;
++}
++
++/*
++ * Check if command is valid.
++ *
++ * RETURNS: 1 if wrong command, 0 if right.
++ */
++static int check_command(int cmd)
++{
++	switch (cmd) {
++
++	case NAND_CMD_READ0:
++	case NAND_CMD_READ1:
++	case NAND_CMD_READSTART:
++	case NAND_CMD_PAGEPROG:
++	case NAND_CMD_READOOB:
++	case NAND_CMD_ERASE1:
++	case NAND_CMD_STATUS:
++	case NAND_CMD_SEQIN:
++	case NAND_CMD_READID:
++	case NAND_CMD_ERASE2:
++	case NAND_CMD_RESET:
++	case NAND_CMD_RNDOUT:
++	case NAND_CMD_RNDOUTSTART:
++		return 0;
++
++	default:
++		return 1;
++	}
++}
++
++/*
++ * Returns state after command is accepted by command number.
++ */
++static uint32_t get_state_by_command(unsigned command)
++{
++	switch (command) {
++		case NAND_CMD_READ0:
++			return STATE_CMD_READ0;
++		case NAND_CMD_READ1:
++			return STATE_CMD_READ1;
++		case NAND_CMD_PAGEPROG:
++			return STATE_CMD_PAGEPROG;
++		case NAND_CMD_READSTART:
++			return STATE_CMD_READSTART;
++		case NAND_CMD_READOOB:
++			return STATE_CMD_READOOB;
++		case NAND_CMD_ERASE1:
++			return STATE_CMD_ERASE1;
++		case NAND_CMD_STATUS:
++			return STATE_CMD_STATUS;
++		case NAND_CMD_SEQIN:
++			return STATE_CMD_SEQIN;
++		case NAND_CMD_READID:
++			return STATE_CMD_READID;
++		case NAND_CMD_ERASE2:
++			return STATE_CMD_ERASE2;
++		case NAND_CMD_RESET:
++			return STATE_CMD_RESET;
++		case NAND_CMD_RNDOUT:
++			return STATE_CMD_RNDOUT;
++		case NAND_CMD_RNDOUTSTART:
++			return STATE_CMD_RNDOUTSTART;
++	}
++
++	NS_ERR("get_state_by_command: unknown command, BUG\n");
++	return 0;
++}
++
++/*
++ * Move an address byte to the correspondent internal register.
++ */
++static inline void accept_addr_byte(struct nandsim *ns, u_char bt)
++{
++	uint byte = (uint)bt;
++
++	if (ns->regs.count < (ns->geom.pgaddrbytes - ns->geom.secaddrbytes))
++		ns->regs.column |= (byte << 8 * ns->regs.count);
++	else {
++		ns->regs.row |= (byte << 8 * (ns->regs.count -
++						ns->geom.pgaddrbytes +
++						ns->geom.secaddrbytes));
++	}
++
++	return;
++}
++
++/*
++ * Switch to STATE_READY state.
++ */
++static inline void switch_to_ready_state(struct nandsim *ns, u_char status)
++{
++	NS_DBG("switch_to_ready_state: switch to %s state\n", get_state_name(STATE_READY));
++
++	ns->state       = STATE_READY;
++	ns->nxstate     = STATE_UNKNOWN;
++	ns->op          = NULL;
++	ns->npstates    = 0;
++	ns->stateidx    = 0;
++	ns->regs.num    = 0;
++	ns->regs.count  = 0;
++	ns->regs.off    = 0;
++	ns->regs.row    = 0;
++	ns->regs.column = 0;
++	ns->regs.status = status;
++}
++
++/*
++ * If the operation isn't known yet, try to find it in the global array
++ * of supported operations.
++ *
++ * Operation can be unknown because of the following.
++ *   1. New command was accepted and this is the first call to find the
++ *      correspondent states chain. In this case ns->npstates = 0;
++ *   2. There are several operations which begin with the same command(s)
++ *      (for example program from the second half and read from the
++ *      second half operations both begin with the READ1 command). In this
++ *      case the ns->pstates[] array contains previous states.
++ *
++ * Thus, the function tries to find operation containing the following
++ * states (if the 'flag' parameter is 0):
++ *    ns->pstates[0], ... ns->pstates[ns->npstates], ns->state
++ *
++ * If (one and only one) matching operation is found, it is accepted (
++ * ns->ops, ns->state, ns->nxstate are initialized, ns->npstate is
++ * zeroed).
++ *
++ * If there are several matches, the current state is pushed to the
++ * ns->pstates.
++ *
++ * The operation can be unknown only while commands are input to the chip.
++ * As soon as address command is accepted, the operation must be known.
++ * In such situation the function is called with 'flag' != 0, and the
++ * operation is searched using the following pattern:
++ *     ns->pstates[0], ... ns->pstates[ns->npstates], <address input>
++ *
++ * It is supposed that this pattern must either match one operation or
++ * none. There can't be ambiguity in that case.
++ *
++ * If no matches found, the function does the following:
++ *   1. if there are saved states present, try to ignore them and search
++ *      again only using the last command. If nothing was found, switch
++ *      to the STATE_READY state.
++ *   2. if there are no saved states, switch to the STATE_READY state.
++ *
++ * RETURNS: -2 - no matched operations found.
++ *          -1 - several matches.
++ *           0 - operation is found.
++ */
++static int find_operation(struct nandsim *ns, uint32_t flag)
++{
++	int opsfound = 0;
++	int i, j, idx = 0;
++
++	for (i = 0; i < NS_OPER_NUM; i++) {
++
++		int found = 1;
++
++		if (!(ns->options & ops[i].reqopts))
++			/* Ignore operations we can't perform */
++			continue;
++
++		if (flag) {
++			if (!(ops[i].states[ns->npstates] & STATE_ADDR_MASK))
++				continue;
++		} else {
++			if (NS_STATE(ns->state) != NS_STATE(ops[i].states[ns->npstates]))
++				continue;
++		}
++
++		for (j = 0; j < ns->npstates; j++)
++			if (NS_STATE(ops[i].states[j]) != NS_STATE(ns->pstates[j])
++				&& (ns->options & ops[idx].reqopts)) {
++				found = 0;
++				break;
++			}
++
++		if (found) {
++			idx = i;
++			opsfound += 1;
++		}
++	}
++
++	if (opsfound == 1) {
++		/* Exact match */
++		ns->op = &ops[idx].states[0];
++		if (flag) {
++			/*
++			 * In this case the find_operation function was
++			 * called when address has just began input. But it isn't
++			 * yet fully input and the current state must
++			 * not be one of STATE_ADDR_*, but the STATE_ADDR_*
++			 * state must be the next state (ns->nxstate).
++			 */
++			ns->stateidx = ns->npstates - 1;
++		} else {
++			ns->stateidx = ns->npstates;
++		}
++		ns->npstates = 0;
++		ns->state = ns->op[ns->stateidx];
++		ns->nxstate = ns->op[ns->stateidx + 1];
++		NS_DBG("find_operation: operation found, index: %d, state: %s, nxstate %s\n",
++				idx, get_state_name(ns->state), get_state_name(ns->nxstate));
++		return 0;
++	}
++
++	if (opsfound == 0) {
++		/* Nothing was found. Try to ignore previous commands (if any) and search again */
++		if (ns->npstates != 0) {
++			NS_DBG("find_operation: no operation found, try again with state %s\n",
++					get_state_name(ns->state));
++			ns->npstates = 0;
++			return find_operation(ns, 0);
++
++		}
++		NS_DBG("find_operation: no operations found\n");
++		switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
++		return -2;
++	}
++
++	if (flag) {
++		/* This shouldn't happen */
++		NS_DBG("find_operation: BUG, operation must be known if address is input\n");
++		return -2;
++	}
++
++	NS_DBG("find_operation: there is still ambiguity\n");
++
++	ns->pstates[ns->npstates++] = ns->state;
++
++	return -1;
++}
++
++static void put_pages(struct nandsim *ns)
++{
++	int i;
++
++	for (i = 0; i < ns->held_cnt; i++)
++		put_page(ns->held_pages[i]);
++}
++
++/* Get page cache pages in advance to provide NOFS memory allocation */
++static int get_pages(struct nandsim *ns, struct file *file, size_t count, loff_t pos)
++{
++	pgoff_t index, start_index, end_index;
++	struct page *page;
++	struct address_space *mapping = file->f_mapping;
++
++	start_index = pos >> PAGE_SHIFT;
++	end_index = (pos + count - 1) >> PAGE_SHIFT;
++	if (end_index - start_index + 1 > NS_MAX_HELD_PAGES)
++		return -EINVAL;
++	ns->held_cnt = 0;
++	for (index = start_index; index <= end_index; index++) {
++		page = find_get_page(mapping, index);
++		if (page == NULL) {
++			page = find_or_create_page(mapping, index, GFP_NOFS);
++			if (page == NULL) {
++				write_inode_now(mapping->host, 1);
++				page = find_or_create_page(mapping, index, GFP_NOFS);
++			}
++			if (page == NULL) {
++				put_pages(ns);
++				return -ENOMEM;
++			}
++			unlock_page(page);
++		}
++		ns->held_pages[ns->held_cnt++] = page;
++	}
++	return 0;
++}
++
++static ssize_t read_file(struct nandsim *ns, struct file *file, void *buf, size_t count, loff_t pos)
++{
++	ssize_t tx;
++	int err;
++	unsigned int noreclaim_flag;
++
++	err = get_pages(ns, file, count, pos);
++	if (err)
++		return err;
++	noreclaim_flag = memalloc_noreclaim_save();
++	tx = kernel_read(file, buf, count, &pos);
++	memalloc_noreclaim_restore(noreclaim_flag);
++	put_pages(ns);
++	return tx;
++}
++
++static ssize_t write_file(struct nandsim *ns, struct file *file, void *buf, size_t count, loff_t pos)
++{
++	ssize_t tx;
++	int err;
++	unsigned int noreclaim_flag;
++
++	err = get_pages(ns, file, count, pos);
++	if (err)
++		return err;
++	noreclaim_flag = memalloc_noreclaim_save();
++	tx = kernel_write(file, buf, count, &pos);
++	memalloc_noreclaim_restore(noreclaim_flag);
++	put_pages(ns);
++	return tx;
++}
++
++/*
++ * Returns a pointer to the current page.
++ */
++static inline union ns_mem *NS_GET_PAGE(struct nandsim *ns)
++{
++	return &(ns->pages[ns->regs.row]);
++}
++
++/*
++ * Retuns a pointer to the current byte, within the current page.
++ */
++static inline u_char *NS_PAGE_BYTE_OFF(struct nandsim *ns)
++{
++	return NS_GET_PAGE(ns)->byte + ns->regs.column + ns->regs.off;
++}
++
++static int do_read_error(struct nandsim *ns, int num)
++{
++	unsigned int page_no = ns->regs.row;
++
++	if (read_error(page_no)) {
++		prandom_bytes(ns->buf.byte, num);
++		NS_WARN("simulating read error in page %u\n", page_no);
++		return 1;
++	}
++	return 0;
++}
++
++static void do_bit_flips(struct nandsim *ns, int num)
++{
++	if (bitflips && prandom_u32() < (1 << 22)) {
++		int flips = 1;
++		if (bitflips > 1)
++			flips = (prandom_u32() % (int) bitflips) + 1;
++		while (flips--) {
++			int pos = prandom_u32() % (num * 8);
++			ns->buf.byte[pos / 8] ^= (1 << (pos % 8));
++			NS_WARN("read_page: flipping bit %d in page %d "
++				"reading from %d ecc: corrected=%u failed=%u\n",
++				pos, ns->regs.row, ns->regs.column + ns->regs.off,
++				nsmtd->ecc_stats.corrected, nsmtd->ecc_stats.failed);
++		}
++	}
++}
++
++/*
++ * Fill the NAND buffer with data read from the specified page.
++ */
++static void read_page(struct nandsim *ns, int num)
++{
++	union ns_mem *mypage;
++
++	if (ns->cfile) {
++		if (!test_bit(ns->regs.row, ns->pages_written)) {
++			NS_DBG("read_page: page %d not written\n", ns->regs.row);
++			memset(ns->buf.byte, 0xFF, num);
++		} else {
++			loff_t pos;
++			ssize_t tx;
++
++			NS_DBG("read_page: page %d written, reading from %d\n",
++				ns->regs.row, ns->regs.column + ns->regs.off);
++			if (do_read_error(ns, num))
++				return;
++			pos = (loff_t)NS_RAW_OFFSET(ns) + ns->regs.off;
++			tx = read_file(ns, ns->cfile, ns->buf.byte, num, pos);
++			if (tx != num) {
++				NS_ERR("read_page: read error for page %d ret %ld\n", ns->regs.row, (long)tx);
++				return;
++			}
++			do_bit_flips(ns, num);
++		}
++		return;
++	}
++
++	mypage = NS_GET_PAGE(ns);
++	if (mypage->byte == NULL) {
++		NS_DBG("read_page: page %d not allocated\n", ns->regs.row);
++		memset(ns->buf.byte, 0xFF, num);
++	} else {
++		NS_DBG("read_page: page %d allocated, reading from %d\n",
++			ns->regs.row, ns->regs.column + ns->regs.off);
++		if (do_read_error(ns, num))
++			return;
++		memcpy(ns->buf.byte, NS_PAGE_BYTE_OFF(ns), num);
++		do_bit_flips(ns, num);
++	}
++}
++
++/*
++ * Erase all pages in the specified sector.
++ */
++static void erase_sector(struct nandsim *ns)
++{
++	union ns_mem *mypage;
++	int i;
++
++	if (ns->cfile) {
++		for (i = 0; i < ns->geom.pgsec; i++)
++			if (__test_and_clear_bit(ns->regs.row + i,
++						 ns->pages_written)) {
++				NS_DBG("erase_sector: freeing page %d\n", ns->regs.row + i);
++			}
++		return;
++	}
++
++	mypage = NS_GET_PAGE(ns);
++	for (i = 0; i < ns->geom.pgsec; i++) {
++		if (mypage->byte != NULL) {
++			NS_DBG("erase_sector: freeing page %d\n", ns->regs.row+i);
++			kmem_cache_free(ns->nand_pages_slab, mypage->byte);
++			mypage->byte = NULL;
++		}
++		mypage++;
++	}
++}
++
++/*
++ * Program the specified page with the contents from the NAND buffer.
++ */
++static int prog_page(struct nandsim *ns, int num)
++{
++	int i;
++	union ns_mem *mypage;
++	u_char *pg_off;
++
++	if (ns->cfile) {
++		loff_t off;
++		ssize_t tx;
++		int all;
++
++		NS_DBG("prog_page: writing page %d\n", ns->regs.row);
++		pg_off = ns->file_buf + ns->regs.column + ns->regs.off;
++		off = (loff_t)NS_RAW_OFFSET(ns) + ns->regs.off;
++		if (!test_bit(ns->regs.row, ns->pages_written)) {
++			all = 1;
++			memset(ns->file_buf, 0xff, ns->geom.pgszoob);
++		} else {
++			all = 0;
++			tx = read_file(ns, ns->cfile, pg_off, num, off);
++			if (tx != num) {
++				NS_ERR("prog_page: read error for page %d ret %ld\n", ns->regs.row, (long)tx);
++				return -1;
++			}
++		}
++		for (i = 0; i < num; i++)
++			pg_off[i] &= ns->buf.byte[i];
++		if (all) {
++			loff_t pos = (loff_t)ns->regs.row * ns->geom.pgszoob;
++			tx = write_file(ns, ns->cfile, ns->file_buf, ns->geom.pgszoob, pos);
++			if (tx != ns->geom.pgszoob) {
++				NS_ERR("prog_page: write error for page %d ret %ld\n", ns->regs.row, (long)tx);
++				return -1;
++			}
++			__set_bit(ns->regs.row, ns->pages_written);
++		} else {
++			tx = write_file(ns, ns->cfile, pg_off, num, off);
++			if (tx != num) {
++				NS_ERR("prog_page: write error for page %d ret %ld\n", ns->regs.row, (long)tx);
++				return -1;
++			}
++		}
++		return 0;
++	}
++
++	mypage = NS_GET_PAGE(ns);
++	if (mypage->byte == NULL) {
++		NS_DBG("prog_page: allocating page %d\n", ns->regs.row);
++		/*
++		 * We allocate memory with GFP_NOFS because a flash FS may
++		 * utilize this. If it is holding an FS lock, then gets here,
++		 * then kernel memory alloc runs writeback which goes to the FS
++		 * again and deadlocks. This was seen in practice.
++		 */
++		mypage->byte = kmem_cache_alloc(ns->nand_pages_slab, GFP_NOFS);
++		if (mypage->byte == NULL) {
++			NS_ERR("prog_page: error allocating memory for page %d\n", ns->regs.row);
++			return -1;
++		}
++		memset(mypage->byte, 0xFF, ns->geom.pgszoob);
++	}
++
++	pg_off = NS_PAGE_BYTE_OFF(ns);
++	for (i = 0; i < num; i++)
++		pg_off[i] &= ns->buf.byte[i];
++
++	return 0;
++}
++
++/*
++ * If state has any action bit, perform this action.
++ *
++ * RETURNS: 0 if success, -1 if error.
++ */
++static int do_state_action(struct nandsim *ns, uint32_t action)
++{
++	int num;
++	int busdiv = ns->busw == 8 ? 1 : 2;
++	unsigned int erase_block_no, page_no;
++
++	action &= ACTION_MASK;
++
++	/* Check that page address input is correct */
++	if (action != ACTION_SECERASE && ns->regs.row >= ns->geom.pgnum) {
++		NS_WARN("do_state_action: wrong page number (%#x)\n", ns->regs.row);
++		return -1;
++	}
++
++	switch (action) {
++
++	case ACTION_CPY:
++		/*
++		 * Copy page data to the internal buffer.
++		 */
++
++		/* Column shouldn't be very large */
++		if (ns->regs.column >= (ns->geom.pgszoob - ns->regs.off)) {
++			NS_ERR("do_state_action: column number is too large\n");
++			break;
++		}
++		num = ns->geom.pgszoob - ns->regs.off - ns->regs.column;
++		read_page(ns, num);
++
++		NS_DBG("do_state_action: (ACTION_CPY:) copy %d bytes to int buf, raw offset %d\n",
++			num, NS_RAW_OFFSET(ns) + ns->regs.off);
++
++		if (ns->regs.off == 0)
++			NS_LOG("read page %d\n", ns->regs.row);
++		else if (ns->regs.off < ns->geom.pgsz)
++			NS_LOG("read page %d (second half)\n", ns->regs.row);
++		else
++			NS_LOG("read OOB of page %d\n", ns->regs.row);
++
++		NS_UDELAY(access_delay);
++		NS_UDELAY(input_cycle * ns->geom.pgsz / 1000 / busdiv);
++
++		break;
++
++	case ACTION_SECERASE:
++		/*
++		 * Erase sector.
++		 */
++
++		if (ns->lines.wp) {
++			NS_ERR("do_state_action: device is write-protected, ignore sector erase\n");
++			return -1;
++		}
++
++		if (ns->regs.row >= ns->geom.pgnum - ns->geom.pgsec
++			|| (ns->regs.row & ~(ns->geom.secsz - 1))) {
++			NS_ERR("do_state_action: wrong sector address (%#x)\n", ns->regs.row);
++			return -1;
++		}
++
++		ns->regs.row = (ns->regs.row <<
++				8 * (ns->geom.pgaddrbytes - ns->geom.secaddrbytes)) | ns->regs.column;
++		ns->regs.column = 0;
++
++		erase_block_no = ns->regs.row >> (ns->geom.secshift - ns->geom.pgshift);
++
++		NS_DBG("do_state_action: erase sector at address %#x, off = %d\n",
++				ns->regs.row, NS_RAW_OFFSET(ns));
++		NS_LOG("erase sector %u\n", erase_block_no);
++
++		erase_sector(ns);
++
++		NS_MDELAY(erase_delay);
++
++		if (erase_block_wear)
++			update_wear(erase_block_no);
++
++		if (erase_error(erase_block_no)) {
++			NS_WARN("simulating erase failure in erase block %u\n", erase_block_no);
++			return -1;
++		}
++
++		break;
++
++	case ACTION_PRGPAGE:
++		/*
++		 * Program page - move internal buffer data to the page.
++		 */
++
++		if (ns->lines.wp) {
++			NS_WARN("do_state_action: device is write-protected, programm\n");
++			return -1;
++		}
++
++		num = ns->geom.pgszoob - ns->regs.off - ns->regs.column;
++		if (num != ns->regs.count) {
++			NS_ERR("do_state_action: too few bytes were input (%d instead of %d)\n",
++					ns->regs.count, num);
++			return -1;
++		}
++
++		if (prog_page(ns, num) == -1)
++			return -1;
++
++		page_no = ns->regs.row;
++
++		NS_DBG("do_state_action: copy %d bytes from int buf to (%#x, %#x), raw off = %d\n",
++			num, ns->regs.row, ns->regs.column, NS_RAW_OFFSET(ns) + ns->regs.off);
++		NS_LOG("programm page %d\n", ns->regs.row);
++
++		NS_UDELAY(programm_delay);
++		NS_UDELAY(output_cycle * ns->geom.pgsz / 1000 / busdiv);
++
++		if (write_error(page_no)) {
++			NS_WARN("simulating write failure in page %u\n", page_no);
++			return -1;
++		}
++
++		break;
++
++	case ACTION_ZEROOFF:
++		NS_DBG("do_state_action: set internal offset to 0\n");
++		ns->regs.off = 0;
++		break;
++
++	case ACTION_HALFOFF:
++		if (!(ns->options & OPT_PAGE512_8BIT)) {
++			NS_ERR("do_state_action: BUG! can't skip half of page for non-512"
++				"byte page size 8x chips\n");
++			return -1;
++		}
++		NS_DBG("do_state_action: set internal offset to %d\n", ns->geom.pgsz/2);
++		ns->regs.off = ns->geom.pgsz/2;
++		break;
++
++	case ACTION_OOBOFF:
++		NS_DBG("do_state_action: set internal offset to %d\n", ns->geom.pgsz);
++		ns->regs.off = ns->geom.pgsz;
++		break;
++
++	default:
++		NS_DBG("do_state_action: BUG! unknown action\n");
++	}
++
++	return 0;
++}
++
++/*
++ * Switch simulator's state.
++ */
++static void switch_state(struct nandsim *ns)
++{
++	if (ns->op) {
++		/*
++		 * The current operation have already been identified.
++		 * Just follow the states chain.
++		 */
++
++		ns->stateidx += 1;
++		ns->state = ns->nxstate;
++		ns->nxstate = ns->op[ns->stateidx + 1];
++
++		NS_DBG("switch_state: operation is known, switch to the next state, "
++			"state: %s, nxstate: %s\n",
++			get_state_name(ns->state), get_state_name(ns->nxstate));
++
++		/* See, whether we need to do some action */
++		if ((ns->state & ACTION_MASK) && do_state_action(ns, ns->state) < 0) {
++			switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
++			return;
++		}
++
++	} else {
++		/*
++		 * We don't yet know which operation we perform.
++		 * Try to identify it.
++		 */
++
++		/*
++		 *  The only event causing the switch_state function to
++		 *  be called with yet unknown operation is new command.
++		 */
++		ns->state = get_state_by_command(ns->regs.command);
++
++		NS_DBG("switch_state: operation is unknown, try to find it\n");
++
++		if (find_operation(ns, 0) != 0)
++			return;
++
++		if ((ns->state & ACTION_MASK) && do_state_action(ns, ns->state) < 0) {
++			switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
++			return;
++		}
++	}
++
++	/* For 16x devices column means the page offset in words */
++	if ((ns->nxstate & STATE_ADDR_MASK) && ns->busw == 16) {
++		NS_DBG("switch_state: double the column number for 16x device\n");
++		ns->regs.column <<= 1;
++	}
++
++	if (NS_STATE(ns->nxstate) == STATE_READY) {
++		/*
++		 * The current state is the last. Return to STATE_READY
++		 */
++
++		u_char status = NS_STATUS_OK(ns);
++
++		/* In case of data states, see if all bytes were input/output */
++		if ((ns->state & (STATE_DATAIN_MASK | STATE_DATAOUT_MASK))
++			&& ns->regs.count != ns->regs.num) {
++			NS_WARN("switch_state: not all bytes were processed, %d left\n",
++					ns->regs.num - ns->regs.count);
++			status = NS_STATUS_FAILED(ns);
++		}
++
++		NS_DBG("switch_state: operation complete, switch to STATE_READY state\n");
++
++		switch_to_ready_state(ns, status);
++
++		return;
++	} else if (ns->nxstate & (STATE_DATAIN_MASK | STATE_DATAOUT_MASK)) {
++		/*
++		 * If the next state is data input/output, switch to it now
++		 */
++
++		ns->state      = ns->nxstate;
++		ns->nxstate    = ns->op[++ns->stateidx + 1];
++		ns->regs.num   = ns->regs.count = 0;
++
++		NS_DBG("switch_state: the next state is data I/O, switch, "
++			"state: %s, nxstate: %s\n",
++			get_state_name(ns->state), get_state_name(ns->nxstate));
++
++		/*
++		 * Set the internal register to the count of bytes which
++		 * are expected to be input or output
++		 */
++		switch (NS_STATE(ns->state)) {
++			case STATE_DATAIN:
++			case STATE_DATAOUT:
++				ns->regs.num = ns->geom.pgszoob - ns->regs.off - ns->regs.column;
++				break;
++
++			case STATE_DATAOUT_ID:
++				ns->regs.num = ns->geom.idbytes;
++				break;
++
++			case STATE_DATAOUT_STATUS:
++				ns->regs.count = ns->regs.num = 0;
++				break;
++
++			default:
++				NS_ERR("switch_state: BUG! unknown data state\n");
++		}
++
++	} else if (ns->nxstate & STATE_ADDR_MASK) {
++		/*
++		 * If the next state is address input, set the internal
++		 * register to the number of expected address bytes
++		 */
++
++		ns->regs.count = 0;
++
++		switch (NS_STATE(ns->nxstate)) {
++			case STATE_ADDR_PAGE:
++				ns->regs.num = ns->geom.pgaddrbytes;
++
++				break;
++			case STATE_ADDR_SEC:
++				ns->regs.num = ns->geom.secaddrbytes;
++				break;
++
++			case STATE_ADDR_ZERO:
++				ns->regs.num = 1;
++				break;
++
++			case STATE_ADDR_COLUMN:
++				/* Column address is always 2 bytes */
++				ns->regs.num = ns->geom.pgaddrbytes - ns->geom.secaddrbytes;
++				break;
++
++			default:
++				NS_ERR("switch_state: BUG! unknown address state\n");
++		}
++	} else {
++		/*
++		 * Just reset internal counters.
++		 */
++
++		ns->regs.num = 0;
++		ns->regs.count = 0;
++	}
++}
++
++static u_char ns_nand_read_byte(struct mtd_info *mtd)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct nandsim *ns = nand_get_controller_data(chip);
++	u_char outb = 0x00;
++
++	/* Sanity and correctness checks */
++	if (!ns->lines.ce) {
++		NS_ERR("read_byte: chip is disabled, return %#x\n", (uint)outb);
++		return outb;
++	}
++	if (ns->lines.ale || ns->lines.cle) {
++		NS_ERR("read_byte: ALE or CLE pin is high, return %#x\n", (uint)outb);
++		return outb;
++	}
++	if (!(ns->state & STATE_DATAOUT_MASK)) {
++		NS_WARN("read_byte: unexpected data output cycle, state is %s "
++			"return %#x\n", get_state_name(ns->state), (uint)outb);
++		return outb;
++	}
++
++	/* Status register may be read as many times as it is wanted */
++	if (NS_STATE(ns->state) == STATE_DATAOUT_STATUS) {
++		NS_DBG("read_byte: return %#x status\n", ns->regs.status);
++		return ns->regs.status;
++	}
++
++	/* Check if there is any data in the internal buffer which may be read */
++	if (ns->regs.count == ns->regs.num) {
++		NS_WARN("read_byte: no more data to output, return %#x\n", (uint)outb);
++		return outb;
++	}
++
++	switch (NS_STATE(ns->state)) {
++		case STATE_DATAOUT:
++			if (ns->busw == 8) {
++				outb = ns->buf.byte[ns->regs.count];
++				ns->regs.count += 1;
++			} else {
++				outb = (u_char)cpu_to_le16(ns->buf.word[ns->regs.count >> 1]);
++				ns->regs.count += 2;
++			}
++			break;
++		case STATE_DATAOUT_ID:
++			NS_DBG("read_byte: read ID byte %d, total = %d\n", ns->regs.count, ns->regs.num);
++			outb = ns->ids[ns->regs.count];
++			ns->regs.count += 1;
++			break;
++		default:
++			BUG();
++	}
++
++	if (ns->regs.count == ns->regs.num) {
++		NS_DBG("read_byte: all bytes were read\n");
++
++		if (NS_STATE(ns->nxstate) == STATE_READY)
++			switch_state(ns);
++	}
++
++	return outb;
++}
++
++static void ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct nandsim *ns = nand_get_controller_data(chip);
++
++	/* Sanity and correctness checks */
++	if (!ns->lines.ce) {
++		NS_ERR("write_byte: chip is disabled, ignore write\n");
++		return;
++	}
++	if (ns->lines.ale && ns->lines.cle) {
++		NS_ERR("write_byte: ALE and CLE pins are high simultaneously, ignore write\n");
++		return;
++	}
++
++	if (ns->lines.cle == 1) {
++		/*
++		 * The byte written is a command.
++		 */
++
++		if (byte == NAND_CMD_RESET) {
++			NS_LOG("reset chip\n");
++			switch_to_ready_state(ns, NS_STATUS_OK(ns));
++			return;
++		}
++
++		/* Check that the command byte is correct */
++		if (check_command(byte)) {
++			NS_ERR("write_byte: unknown command %#x\n", (uint)byte);
++			return;
++		}
++
++		if (NS_STATE(ns->state) == STATE_DATAOUT_STATUS
++			|| NS_STATE(ns->state) == STATE_DATAOUT) {
++			int row = ns->regs.row;
++
++			switch_state(ns);
++			if (byte == NAND_CMD_RNDOUT)
++				ns->regs.row = row;
++		}
++
++		/* Check if chip is expecting command */
++		if (NS_STATE(ns->nxstate) != STATE_UNKNOWN && !(ns->nxstate & STATE_CMD_MASK)) {
++			/* Do not warn if only 2 id bytes are read */
++			if (!(ns->regs.command == NAND_CMD_READID &&
++			    NS_STATE(ns->state) == STATE_DATAOUT_ID && ns->regs.count == 2)) {
++				/*
++				 * We are in situation when something else (not command)
++				 * was expected but command was input. In this case ignore
++				 * previous command(s)/state(s) and accept the last one.
++				 */
++				NS_WARN("write_byte: command (%#x) wasn't expected, expected state is %s, "
++					"ignore previous states\n", (uint)byte, get_state_name(ns->nxstate));
++			}
++			switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
++		}
++
++		NS_DBG("command byte corresponding to %s state accepted\n",
++			get_state_name(get_state_by_command(byte)));
++		ns->regs.command = byte;
++		switch_state(ns);
++
++	} else if (ns->lines.ale == 1) {
++		/*
++		 * The byte written is an address.
++		 */
++
++		if (NS_STATE(ns->nxstate) == STATE_UNKNOWN) {
++
++			NS_DBG("write_byte: operation isn't known yet, identify it\n");
++
++			if (find_operation(ns, 1) < 0)
++				return;
++
++			if ((ns->state & ACTION_MASK) && do_state_action(ns, ns->state) < 0) {
++				switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
++				return;
++			}
++
++			ns->regs.count = 0;
++			switch (NS_STATE(ns->nxstate)) {
++				case STATE_ADDR_PAGE:
++					ns->regs.num = ns->geom.pgaddrbytes;
++					break;
++				case STATE_ADDR_SEC:
++					ns->regs.num = ns->geom.secaddrbytes;
++					break;
++				case STATE_ADDR_ZERO:
++					ns->regs.num = 1;
++					break;
++				default:
++					BUG();
++			}
++		}
++
++		/* Check that chip is expecting address */
++		if (!(ns->nxstate & STATE_ADDR_MASK)) {
++			NS_ERR("write_byte: address (%#x) isn't expected, expected state is %s, "
++				"switch to STATE_READY\n", (uint)byte, get_state_name(ns->nxstate));
++			switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
++			return;
++		}
++
++		/* Check if this is expected byte */
++		if (ns->regs.count == ns->regs.num) {
++			NS_ERR("write_byte: no more address bytes expected\n");
++			switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
++			return;
++		}
++
++		accept_addr_byte(ns, byte);
++
++		ns->regs.count += 1;
++
++		NS_DBG("write_byte: address byte %#x was accepted (%d bytes input, %d expected)\n",
++				(uint)byte, ns->regs.count, ns->regs.num);
++
++		if (ns->regs.count == ns->regs.num) {
++			NS_DBG("address (%#x, %#x) is accepted\n", ns->regs.row, ns->regs.column);
++			switch_state(ns);
++		}
++
++	} else {
++		/*
++		 * The byte written is an input data.
++		 */
++
++		/* Check that chip is expecting data input */
++		if (!(ns->state & STATE_DATAIN_MASK)) {
++			NS_ERR("write_byte: data input (%#x) isn't expected, state is %s, "
++				"switch to %s\n", (uint)byte,
++				get_state_name(ns->state), get_state_name(STATE_READY));
++			switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
++			return;
++		}
++
++		/* Check if this is expected byte */
++		if (ns->regs.count == ns->regs.num) {
++			NS_WARN("write_byte: %u input bytes has already been accepted, ignore write\n",
++					ns->regs.num);
++			return;
++		}
++
++		if (ns->busw == 8) {
++			ns->buf.byte[ns->regs.count] = byte;
++			ns->regs.count += 1;
++		} else {
++			ns->buf.word[ns->regs.count >> 1] = cpu_to_le16((uint16_t)byte);
++			ns->regs.count += 2;
++		}
++	}
++
++	return;
++}
++
++static void ns_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int bitmask)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct nandsim *ns = nand_get_controller_data(chip);
++
++	ns->lines.cle = bitmask & NAND_CLE ? 1 : 0;
++	ns->lines.ale = bitmask & NAND_ALE ? 1 : 0;
++	ns->lines.ce = bitmask & NAND_NCE ? 1 : 0;
++
++	if (cmd != NAND_CMD_NONE)
++		ns_nand_write_byte(mtd, cmd);
++}
++
++static int ns_device_ready(struct mtd_info *mtd)
++{
++	NS_DBG("device_ready\n");
++	return 1;
++}
++
++static uint16_t ns_nand_read_word(struct mtd_info *mtd)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++
++	NS_DBG("read_word\n");
++
++	return chip->read_byte(mtd) | (chip->read_byte(mtd) << 8);
++}
++
++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 nandsim *ns = nand_get_controller_data(chip);
++
++	/* Check that chip is expecting data input */
++	if (!(ns->state & STATE_DATAIN_MASK)) {
++		NS_ERR("write_buf: data input isn't expected, state is %s, "
++			"switch to STATE_READY\n", get_state_name(ns->state));
++		switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
++		return;
++	}
++
++	/* Check if these are expected bytes */
++	if (ns->regs.count + len > ns->regs.num) {
++		NS_ERR("write_buf: too many input bytes\n");
++		switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
++		return;
++	}
++
++	memcpy(ns->buf.byte + ns->regs.count, buf, len);
++	ns->regs.count += len;
++
++	if (ns->regs.count == ns->regs.num) {
++		NS_DBG("write_buf: %d bytes were written\n", ns->regs.count);
++	}
++}
++
++static void ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct nandsim *ns = nand_get_controller_data(chip);
++
++	/* Sanity and correctness checks */
++	if (!ns->lines.ce) {
++		NS_ERR("read_buf: chip is disabled\n");
++		return;
++	}
++	if (ns->lines.ale || ns->lines.cle) {
++		NS_ERR("read_buf: ALE or CLE pin is high\n");
++		return;
++	}
++	if (!(ns->state & STATE_DATAOUT_MASK)) {
++		NS_WARN("read_buf: unexpected data output cycle, current state is %s\n",
++			get_state_name(ns->state));
++		return;
++	}
++
++	if (NS_STATE(ns->state) != STATE_DATAOUT) {
++		int i;
++
++		for (i = 0; i < len; i++)
++			buf[i] = mtd_to_nand(mtd)->read_byte(mtd);
++
++		return;
++	}
++
++	/* Check if these are expected bytes */
++	if (ns->regs.count + len > ns->regs.num) {
++		NS_ERR("read_buf: too many bytes to read\n");
++		switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
++		return;
++	}
++
++	memcpy(buf, ns->buf.byte + ns->regs.count, len);
++	ns->regs.count += len;
++
++	if (ns->regs.count == ns->regs.num) {
++		if (NS_STATE(ns->nxstate) == STATE_READY)
++			switch_state(ns);
++	}
++
++	return;
++}
++
++/*
++ * Module initialization function
++ */
++static int __init ns_init_module(void)
++{
++	struct nand_chip *chip;
++	struct nandsim *nand;
++	int retval = -ENOMEM, i;
++
++	if (bus_width != 8 && bus_width != 16) {
++		NS_ERR("wrong bus width (%d), use only 8 or 16\n", bus_width);
++		return -EINVAL;
++	}
++
++	/* Allocate and initialize mtd_info, nand_chip and nandsim structures */
++	chip = kzalloc(sizeof(struct nand_chip) + sizeof(struct nandsim),
++		       GFP_KERNEL);
++	if (!chip) {
++		NS_ERR("unable to allocate core structures.\n");
++		return -ENOMEM;
++	}
++	nsmtd       = nand_to_mtd(chip);
++	nand        = (struct nandsim *)(chip + 1);
++	nand_set_controller_data(chip, (void *)nand);
++
++	/*
++	 * Register simulator's callbacks.
++	 */
++	chip->cmd_ctrl	 = ns_hwcontrol;
++	chip->read_byte  = ns_nand_read_byte;
++	chip->dev_ready  = ns_device_ready;
++	chip->write_buf  = ns_nand_write_buf;
++	chip->read_buf   = ns_nand_read_buf;
++	chip->read_word  = ns_nand_read_word;
++	chip->ecc.mode   = NAND_ECC_SOFT;
++	chip->ecc.algo   = NAND_ECC_HAMMING;
++	/* The NAND_SKIP_BBTSCAN option is necessary for 'overridesize' */
++	/* and 'badblocks' parameters to work */
++	chip->options   |= NAND_SKIP_BBTSCAN;
++
++	switch (bbt) {
++	case 2:
++		 chip->bbt_options |= NAND_BBT_NO_OOB;
++	case 1:
++		 chip->bbt_options |= NAND_BBT_USE_FLASH;
++	case 0:
++		break;
++	default:
++		NS_ERR("bbt has to be 0..2\n");
++		retval = -EINVAL;
++		goto error;
++	}
++	/*
++	 * Perform minimum nandsim structure initialization to handle
++	 * the initial ID read command correctly
++	 */
++	if (id_bytes[6] != 0xFF || id_bytes[7] != 0xFF)
++		nand->geom.idbytes = 8;
++	else if (id_bytes[4] != 0xFF || id_bytes[5] != 0xFF)
++		nand->geom.idbytes = 6;
++	else if (id_bytes[2] != 0xFF || id_bytes[3] != 0xFF)
++		nand->geom.idbytes = 4;
++	else
++		nand->geom.idbytes = 2;
++	nand->regs.status = NS_STATUS_OK(nand);
++	nand->nxstate = STATE_UNKNOWN;
++	nand->options |= OPT_PAGE512; /* temporary value */
++	memcpy(nand->ids, id_bytes, sizeof(nand->ids));
++	if (bus_width == 16) {
++		nand->busw = 16;
++		chip->options |= NAND_BUSWIDTH_16;
++	}
++
++	nsmtd->owner = THIS_MODULE;
++
++	if ((retval = parse_weakblocks()) != 0)
++		goto error;
++
++	if ((retval = parse_weakpages()) != 0)
++		goto error;
++
++	if ((retval = parse_gravepages()) != 0)
++		goto error;
++
++	retval = nand_scan_ident(nsmtd, 1, NULL);
++	if (retval) {
++		NS_ERR("cannot scan NAND Simulator device\n");
++		goto error;
++	}
++
++	if (bch) {
++		unsigned int eccsteps, eccbytes;
++		if (!mtd_nand_has_bch()) {
++			NS_ERR("BCH ECC support is disabled\n");
++			retval = -EINVAL;
++			goto error;
++		}
++		/* use 512-byte ecc blocks */
++		eccsteps = nsmtd->writesize/512;
++		eccbytes = (bch*13+7)/8;
++		/* do not bother supporting small page devices */
++		if ((nsmtd->oobsize < 64) || !eccsteps) {
++			NS_ERR("bch not available on small page devices\n");
++			retval = -EINVAL;
++			goto error;
++		}
++		if ((eccbytes*eccsteps+2) > nsmtd->oobsize) {
++			NS_ERR("invalid bch value %u\n", bch);
++			retval = -EINVAL;
++			goto error;
++		}
++		chip->ecc.mode = NAND_ECC_SOFT;
++		chip->ecc.algo = NAND_ECC_BCH;
++		chip->ecc.size = 512;
++		chip->ecc.strength = bch;
++		chip->ecc.bytes = eccbytes;
++		NS_INFO("using %u-bit/%u bytes BCH ECC\n", bch, chip->ecc.size);
++	}
++
++	retval = nand_scan_tail(nsmtd);
++	if (retval) {
++		NS_ERR("can't register NAND Simulator\n");
++		goto error;
++	}
++
++	if (overridesize) {
++		uint64_t new_size = (uint64_t)nsmtd->erasesize << overridesize;
++		if (new_size >> overridesize != nsmtd->erasesize) {
++			NS_ERR("overridesize is too big\n");
++			retval = -EINVAL;
++			goto err_exit;
++		}
++		/* N.B. This relies on nand_scan not doing anything with the size before we change it */
++		nsmtd->size = new_size;
++		chip->chipsize = new_size;
++		chip->chip_shift = ffs(nsmtd->erasesize) + overridesize - 1;
++		chip->pagemask = (chip->chipsize >> chip->page_shift) - 1;
++	}
++
++	if ((retval = setup_wear_reporting(nsmtd)) != 0)
++		goto err_exit;
++
++	if ((retval = init_nandsim(nsmtd)) != 0)
++		goto err_exit;
++
++	if ((retval = chip->scan_bbt(nsmtd)) != 0)
++		goto err_exit;
++
++	if ((retval = parse_badblocks(nand, nsmtd)) != 0)
++		goto err_exit;
++
++	/* Register NAND partitions */
++	retval = mtd_device_register(nsmtd, &nand->partitions[0],
++				     nand->nbparts);
++	if (retval != 0)
++		goto err_exit;
++
++	if ((retval = nandsim_debugfs_create(nand)) != 0)
++		goto err_exit;
++
++        return 0;
++
++err_exit:
++	free_nandsim(nand);
++	nand_release(nsmtd);
++	for (i = 0;i < ARRAY_SIZE(nand->partitions); ++i)
++		kfree(nand->partitions[i].name);
++error:
++	kfree(chip);
++	free_lists();
++
++	return retval;
++}
++
++module_init(ns_init_module);
++
++/*
++ * Module clean-up function
++ */
++static void __exit ns_cleanup_module(void)
++{
++	struct nand_chip *chip = mtd_to_nand(nsmtd);
++	struct nandsim *ns = nand_get_controller_data(chip);
++	int i;
++
++	free_nandsim(ns);    /* Free nandsim private resources */
++	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 */
++	free_lists();
++}
++
++module_exit(ns_cleanup_module);
++
++MODULE_LICENSE ("GPL");
++MODULE_AUTHOR ("Artem B. Bityuckiy");
++MODULE_DESCRIPTION ("The NAND flash simulator");
+diff --git a/drivers/mtd/nand/raw/ndfc.c b/drivers/mtd/nand/raw/ndfc.c
+new file mode 100644
+index 0000000..d8a8068
+--- /dev/null
++++ b/drivers/mtd/nand/raw/ndfc.c
+@@ -0,0 +1,286 @@
++/*
++ *  Overview:
++ *   Platform independent driver for NDFC (NanD Flash Controller)
++ *   integrated into EP440 cores
++ *
++ *   Ported to an OF platform driver by Sean MacLennan
++ *
++ *   The NDFC supports multiple chips, but this driver only supports a
++ *   single chip since I do not have access to any boards with
++ *   multiple chips.
++ *
++ *  Author: Thomas Gleixner
++ *
++ *  Copyright 2006 IBM
++ *  Copyright 2008 PIKA Technologies
++ *    Sean MacLennan <smaclennan@pikatech.com>
++ *
++ *  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/mtd/rawnand.h>
++#include <linux/mtd/nand_ecc.h>
++#include <linux/mtd/partitions.h>
++#include <linux/mtd/ndfc.h>
++#include <linux/slab.h>
++#include <linux/mtd/mtd.h>
++#include <linux/of_address.h>
++#include <linux/of_platform.h>
++#include <asm/io.h>
++
++#define NDFC_MAX_CS    4
++
++struct ndfc_controller {
++	struct platform_device *ofdev;
++	void __iomem *ndfcbase;
++	struct nand_chip chip;
++	int chip_select;
++	struct nand_hw_control ndfc_control;
++};
++
++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 ndfc_controller *ndfc = nand_get_controller_data(nchip);
++
++	ccr = in_be32(ndfc->ndfcbase + NDFC_CCR);
++	if (chip >= 0) {
++		ccr &= ~NDFC_CCR_BS_MASK;
++		ccr |= NDFC_CCR_BS(chip + ndfc->chip_select);
++	} else
++		ccr |= NDFC_CCR_RESET_CE;
++	out_be32(ndfc->ndfcbase + NDFC_CCR, ccr);
++}
++
++static void ndfc_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct ndfc_controller *ndfc = nand_get_controller_data(chip);
++
++	if (cmd == NAND_CMD_NONE)
++		return;
++
++	if (ctrl & NAND_CLE)
++		writel(cmd & 0xFF, ndfc->ndfcbase + NDFC_CMD);
++	else
++		writel(cmd & 0xFF, ndfc->ndfcbase + NDFC_ALE);
++}
++
++static int ndfc_ready(struct mtd_info *mtd)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct ndfc_controller *ndfc = nand_get_controller_data(chip);
++
++	return in_be32(ndfc->ndfcbase + NDFC_STAT) & NDFC_STAT_IS_READY;
++}
++
++static void ndfc_enable_hwecc(struct mtd_info *mtd, int mode)
++{
++	uint32_t ccr;
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct ndfc_controller *ndfc = nand_get_controller_data(chip);
++
++	ccr = in_be32(ndfc->ndfcbase + NDFC_CCR);
++	ccr |= NDFC_CCR_RESET_ECC;
++	out_be32(ndfc->ndfcbase + NDFC_CCR, ccr);
++	wmb();
++}
++
++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 ndfc_controller *ndfc = nand_get_controller_data(chip);
++	uint32_t ecc;
++	uint8_t *p = (uint8_t *)&ecc;
++
++	wmb();
++	ecc = in_be32(ndfc->ndfcbase + NDFC_ECC);
++	/* The NDFC uses Smart Media (SMC) bytes order */
++	ecc_code[0] = p[1];
++	ecc_code[1] = p[2];
++	ecc_code[2] = p[3];
++
++	return 0;
++}
++
++/*
++ * Speedups for buffer read/write/verify
++ *
++ * NDFC allows 32bit read/write of data. So we can speed up the buffer
++ * functions. No further checking, as nand_base will always read/write
++ * page aligned.
++ */
++static void ndfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct ndfc_controller *ndfc = nand_get_controller_data(chip);
++	uint32_t *p = (uint32_t *) buf;
++
++	for(;len > 0; len -= 4)
++		*p++ = in_be32(ndfc->ndfcbase + NDFC_DATA);
++}
++
++static void ndfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct ndfc_controller *ndfc = nand_get_controller_data(chip);
++	uint32_t *p = (uint32_t *) buf;
++
++	for(;len > 0; len -= 4)
++		out_be32(ndfc->ndfcbase + NDFC_DATA, *p++);
++}
++
++/*
++ * Initialize chip structure
++ */
++static int ndfc_chip_init(struct ndfc_controller *ndfc,
++			  struct device_node *node)
++{
++	struct device_node *flash_np;
++	struct nand_chip *chip = &ndfc->chip;
++	struct mtd_info *mtd = nand_to_mtd(chip);
++	int ret;
++
++	chip->IO_ADDR_R = ndfc->ndfcbase + NDFC_DATA;
++	chip->IO_ADDR_W = ndfc->ndfcbase + NDFC_DATA;
++	chip->cmd_ctrl = ndfc_hwcontrol;
++	chip->dev_ready = ndfc_ready;
++	chip->select_chip = ndfc_select_chip;
++	chip->chip_delay = 50;
++	chip->controller = &ndfc->ndfc_control;
++	chip->read_buf = ndfc_read_buf;
++	chip->write_buf = ndfc_write_buf;
++	chip->ecc.correct = nand_correct_data;
++	chip->ecc.hwctl = ndfc_enable_hwecc;
++	chip->ecc.calculate = ndfc_calculate_ecc;
++	chip->ecc.mode = NAND_ECC_HW;
++	chip->ecc.size = 256;
++	chip->ecc.bytes = 3;
++	chip->ecc.strength = 1;
++	nand_set_controller_data(chip, ndfc);
++
++	mtd->dev.parent = &ndfc->ofdev->dev;
++
++	flash_np = of_get_next_child(node, NULL);
++	if (!flash_np)
++		return -ENODEV;
++	nand_set_flash_node(chip, flash_np);
++
++	mtd->name = kasprintf(GFP_KERNEL, "%s.%s", dev_name(&ndfc->ofdev->dev),
++			      flash_np->name);
++	if (!mtd->name) {
++		ret = -ENOMEM;
++		goto err;
++	}
++
++	ret = nand_scan(mtd, 1);
++	if (ret)
++		goto err;
++
++	ret = mtd_device_register(mtd, NULL, 0);
++
++err:
++	of_node_put(flash_np);
++	if (ret)
++		kfree(mtd->name);
++	return ret;
++}
++
++static int ndfc_probe(struct platform_device *ofdev)
++{
++	struct ndfc_controller *ndfc;
++	const __be32 *reg;
++	u32 ccr;
++	u32 cs;
++	int err, len;
++
++	/* Read the reg property to get the chip select */
++	reg = of_get_property(ofdev->dev.of_node, "reg", &len);
++	if (reg == NULL || len != 12) {
++		dev_err(&ofdev->dev, "unable read reg property (%d)\n", len);
++		return -ENOENT;
++	}
++
++	cs = be32_to_cpu(reg[0]);
++	if (cs >= NDFC_MAX_CS) {
++		dev_err(&ofdev->dev, "invalid CS number (%d)\n", cs);
++		return -EINVAL;
++	}
++
++	ndfc = &ndfc_ctrl[cs];
++	ndfc->chip_select = cs;
++
++	nand_hw_control_init(&ndfc->ndfc_control);
++	ndfc->ofdev = ofdev;
++	dev_set_drvdata(&ofdev->dev, ndfc);
++
++	ndfc->ndfcbase = of_iomap(ofdev->dev.of_node, 0);
++	if (!ndfc->ndfcbase) {
++		dev_err(&ofdev->dev, "failed to get memory\n");
++		return -EIO;
++	}
++
++	ccr = NDFC_CCR_BS(ndfc->chip_select);
++
++	/* It is ok if ccr does not exist - just default to 0 */
++	reg = of_get_property(ofdev->dev.of_node, "ccr", NULL);
++	if (reg)
++		ccr |= be32_to_cpup(reg);
++
++	out_be32(ndfc->ndfcbase + NDFC_CCR, ccr);
++
++	/* Set the bank settings if given */
++	reg = of_get_property(ofdev->dev.of_node, "bank-settings", NULL);
++	if (reg) {
++		int offset = NDFC_BCFG0 + (ndfc->chip_select << 2);
++		out_be32(ndfc->ndfcbase + offset, be32_to_cpup(reg));
++	}
++
++	err = ndfc_chip_init(ndfc, ofdev->dev.of_node);
++	if (err) {
++		iounmap(ndfc->ndfcbase);
++		return err;
++	}
++
++	return 0;
++}
++
++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);
++
++	nand_release(mtd);
++	kfree(mtd->name);
++
++	return 0;
++}
++
++static const struct of_device_id ndfc_match[] = {
++	{ .compatible = "ibm,ndfc", },
++	{}
++};
++MODULE_DEVICE_TABLE(of, ndfc_match);
++
++static struct platform_driver ndfc_driver = {
++	.driver = {
++		.name = "ndfc",
++		.of_match_table = ndfc_match,
++	},
++	.probe = ndfc_probe,
++	.remove = ndfc_remove,
++};
++
++module_platform_driver(ndfc_driver);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Thomas Gleixner <tglx@linutronix.de>");
++MODULE_DESCRIPTION("OF Platform driver for NDFC");
+diff --git a/drivers/mtd/nand/raw/nuc900_nand.c b/drivers/mtd/nand/raw/nuc900_nand.c
+new file mode 100644
+index 0000000..7bb4d2e
+--- /dev/null
++++ b/drivers/mtd/nand/raw/nuc900_nand.c
+@@ -0,0 +1,306 @@
++/*
++ * Copyright © 2009 Nuvoton technology corporation.
++ *
++ * Wan ZongShun <mcuos.com@gmail.com>
++ *
++ * 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.
++ *
++ */
++
++#include <linux/slab.h>
++#include <linux/module.h>
++#include <linux/interrupt.h>
++#include <linux/io.h>
++#include <linux/platform_device.h>
++#include <linux/delay.h>
++#include <linux/clk.h>
++#include <linux/err.h>
++
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/rawnand.h>
++#include <linux/mtd/partitions.h>
++
++#define REG_FMICSR   	0x00
++#define REG_SMCSR    	0xa0
++#define REG_SMISR    	0xac
++#define REG_SMCMD    	0xb0
++#define REG_SMADDR   	0xb4
++#define REG_SMDATA   	0xb8
++
++#define RESET_FMI	0x01
++#define NAND_EN		0x08
++#define READYBUSY	(0x01 << 18)
++
++#define SWRST		0x01
++#define PSIZE		(0x01 << 3)
++#define DMARWEN		(0x03 << 1)
++#define BUSWID		(0x01 << 4)
++#define ECC4EN		(0x01 << 5)
++#define WP		(0x01 << 24)
++#define NANDCS		(0x01 << 25)
++#define ENDADDR		(0x01 << 31)
++
++#define read_data_reg(dev)		\
++	__raw_readl((dev)->reg + REG_SMDATA)
++
++#define write_data_reg(dev, val)	\
++	__raw_writel((val), (dev)->reg + REG_SMDATA)
++
++#define write_cmd_reg(dev, val)		\
++	__raw_writel((val), (dev)->reg + REG_SMCMD)
++
++#define write_addr_reg(dev, val)	\
++	__raw_writel((val), (dev)->reg + REG_SMADDR)
++
++struct nuc900_nand {
++	struct nand_chip chip;
++	void __iomem *reg;
++	struct clk *clk;
++	spinlock_t lock;
++};
++
++static inline struct nuc900_nand *mtd_to_nuc900(struct mtd_info *mtd)
++{
++	return container_of(mtd_to_nand(mtd), struct nuc900_nand, chip);
++}
++
++static const struct mtd_partition partitions[] = {
++	{
++	 .name = "NAND FS 0",
++	 .offset = 0,
++	 .size = 8 * 1024 * 1024
++	},
++	{
++	 .name = "NAND FS 1",
++	 .offset = MTDPART_OFS_APPEND,
++	 .size = MTDPART_SIZ_FULL
++	}
++};
++
++static unsigned char nuc900_nand_read_byte(struct mtd_info *mtd)
++{
++	unsigned char ret;
++	struct nuc900_nand *nand = mtd_to_nuc900(mtd);
++
++	ret = (unsigned char)read_data_reg(nand);
++
++	return ret;
++}
++
++static void nuc900_nand_read_buf(struct mtd_info *mtd,
++				 unsigned char *buf, int len)
++{
++	int i;
++	struct nuc900_nand *nand = mtd_to_nuc900(mtd);
++
++	for (i = 0; i < len; i++)
++		buf[i] = (unsigned char)read_data_reg(nand);
++}
++
++static void nuc900_nand_write_buf(struct mtd_info *mtd,
++				  const unsigned char *buf, int len)
++{
++	int i;
++	struct nuc900_nand *nand = mtd_to_nuc900(mtd);
++
++	for (i = 0; i < len; i++)
++		write_data_reg(nand, buf[i]);
++}
++
++static int nuc900_check_rb(struct nuc900_nand *nand)
++{
++	unsigned int val;
++	spin_lock(&nand->lock);
++	val = __raw_readl(nand->reg + REG_SMISR);
++	val &= READYBUSY;
++	spin_unlock(&nand->lock);
++
++	return val;
++}
++
++static int nuc900_nand_devready(struct mtd_info *mtd)
++{
++	struct nuc900_nand *nand = mtd_to_nuc900(mtd);
++	int ready;
++
++	ready = (nuc900_check_rb(nand)) ? 1 : 0;
++	return ready;
++}
++
++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);
++	struct nuc900_nand *nand = mtd_to_nuc900(mtd);
++
++	if (command == NAND_CMD_READOOB) {
++		column += mtd->writesize;
++		command = NAND_CMD_READ0;
++	}
++
++	write_cmd_reg(nand, command & 0xff);
++
++	if (column != -1 || page_addr != -1) {
++
++		if (column != -1) {
++			if (chip->options & NAND_BUSWIDTH_16 &&
++					!nand_opcode_8bits(command))
++				column >>= 1;
++			write_addr_reg(nand, column);
++			write_addr_reg(nand, column >> 8 | ENDADDR);
++		}
++		if (page_addr != -1) {
++			write_addr_reg(nand, page_addr);
++
++			if (chip->chipsize > (128 << 20)) {
++				write_addr_reg(nand, page_addr >> 8);
++				write_addr_reg(nand, page_addr >> 16 | ENDADDR);
++			} else {
++				write_addr_reg(nand, page_addr >> 8 | ENDADDR);
++			}
++		}
++	}
++
++	switch (command) {
++	case NAND_CMD_CACHEDPROG:
++	case NAND_CMD_PAGEPROG:
++	case NAND_CMD_ERASE1:
++	case NAND_CMD_ERASE2:
++	case NAND_CMD_SEQIN:
++	case NAND_CMD_RNDIN:
++	case NAND_CMD_STATUS:
++		return;
++
++	case NAND_CMD_RESET:
++		if (chip->dev_ready)
++			break;
++		udelay(chip->chip_delay);
++
++		write_cmd_reg(nand, NAND_CMD_STATUS);
++		write_cmd_reg(nand, command);
++
++		while (!nuc900_check_rb(nand))
++			;
++
++		return;
++
++	case NAND_CMD_RNDOUT:
++		write_cmd_reg(nand, NAND_CMD_RNDOUTSTART);
++		return;
++
++	case NAND_CMD_READ0:
++
++		write_cmd_reg(nand, NAND_CMD_READSTART);
++	default:
++
++		if (!chip->dev_ready) {
++			udelay(chip->chip_delay);
++			return;
++		}
++	}
++
++	/* Apply this short delay always to ensure that we do wait tWB in
++	 * any case on any machine. */
++	ndelay(100);
++
++	while (!chip->dev_ready(mtd))
++		;
++}
++
++
++static void nuc900_nand_enable(struct nuc900_nand *nand)
++{
++	unsigned int val;
++	spin_lock(&nand->lock);
++	__raw_writel(RESET_FMI, (nand->reg + REG_FMICSR));
++
++	val = __raw_readl(nand->reg + REG_FMICSR);
++
++	if (!(val & NAND_EN))
++		__raw_writel(val | NAND_EN, nand->reg + REG_FMICSR);
++
++	val = __raw_readl(nand->reg + REG_SMCSR);
++
++	val &= ~(SWRST|PSIZE|DMARWEN|BUSWID|ECC4EN|NANDCS);
++	val |= WP;
++
++	__raw_writel(val, nand->reg + REG_SMCSR);
++
++	spin_unlock(&nand->lock);
++}
++
++static int nuc900_nand_probe(struct platform_device *pdev)
++{
++	struct nuc900_nand *nuc900_nand;
++	struct nand_chip *chip;
++	struct mtd_info *mtd;
++	struct resource *res;
++
++	nuc900_nand = devm_kzalloc(&pdev->dev, sizeof(struct nuc900_nand),
++				   GFP_KERNEL);
++	if (!nuc900_nand)
++		return -ENOMEM;
++	chip = &(nuc900_nand->chip);
++	mtd = nand_to_mtd(chip);
++
++	mtd->dev.parent		= &pdev->dev;
++	spin_lock_init(&nuc900_nand->lock);
++
++	nuc900_nand->clk = devm_clk_get(&pdev->dev, NULL);
++	if (IS_ERR(nuc900_nand->clk))
++		return -ENOENT;
++	clk_enable(nuc900_nand->clk);
++
++	chip->cmdfunc		= nuc900_nand_command_lp;
++	chip->dev_ready		= nuc900_nand_devready;
++	chip->read_byte		= nuc900_nand_read_byte;
++	chip->write_buf		= nuc900_nand_write_buf;
++	chip->read_buf		= nuc900_nand_read_buf;
++	chip->chip_delay	= 50;
++	chip->options		= 0;
++	chip->ecc.mode		= NAND_ECC_SOFT;
++	chip->ecc.algo		= NAND_ECC_HAMMING;
++
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	nuc900_nand->reg = devm_ioremap_resource(&pdev->dev, res);
++	if (IS_ERR(nuc900_nand->reg))
++		return PTR_ERR(nuc900_nand->reg);
++
++	nuc900_nand_enable(nuc900_nand);
++
++	if (nand_scan(mtd, 1))
++		return -ENXIO;
++
++	mtd_device_register(mtd, partitions, ARRAY_SIZE(partitions));
++
++	platform_set_drvdata(pdev, nuc900_nand);
++
++	return 0;
++}
++
++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));
++	clk_disable(nuc900_nand->clk);
++
++	return 0;
++}
++
++static struct platform_driver nuc900_nand_driver = {
++	.probe		= nuc900_nand_probe,
++	.remove		= nuc900_nand_remove,
++	.driver		= {
++		.name	= "nuc900-fmi",
++	},
++};
++
++module_platform_driver(nuc900_nand_driver);
++
++MODULE_AUTHOR("Wan ZongShun <mcuos.com@gmail.com>");
++MODULE_DESCRIPTION("w90p910/NUC9xx nand driver!");
++MODULE_LICENSE("GPL");
++MODULE_ALIAS("platform:nuc900-fmi");
+diff --git a/drivers/mtd/nand/raw/omap2.c b/drivers/mtd/nand/raw/omap2.c
+new file mode 100644
+index 0000000..9f98f74
+--- /dev/null
++++ b/drivers/mtd/nand/raw/omap2.c
+@@ -0,0 +1,2332 @@
++/*
++ * Copyright © 2004 Texas Instruments, Jian Zhang <jzhang@ti.com>
++ * Copyright © 2004 Micron Technology Inc.
++ * Copyright © 2004 David Brownell
++ *
++ * 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/platform_device.h>
++#include <linux/dmaengine.h>
++#include <linux/dma-mapping.h>
++#include <linux/delay.h>
++#include <linux/gpio/consumer.h>
++#include <linux/module.h>
++#include <linux/interrupt.h>
++#include <linux/jiffies.h>
++#include <linux/sched.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/rawnand.h>
++#include <linux/mtd/partitions.h>
++#include <linux/omap-dma.h>
++#include <linux/io.h>
++#include <linux/slab.h>
++#include <linux/of.h>
++#include <linux/of_device.h>
++
++#include <linux/mtd/nand_bch.h>
++#include <linux/platform_data/elm.h>
++
++#include <linux/omap-gpmc.h>
++#include <linux/platform_data/mtd-nand-omap2.h>
++
++#define	DRIVER_NAME	"omap2-nand"
++#define	OMAP_NAND_TIMEOUT_MS	5000
++
++#define NAND_Ecc_P1e		(1 << 0)
++#define NAND_Ecc_P2e		(1 << 1)
++#define NAND_Ecc_P4e		(1 << 2)
++#define NAND_Ecc_P8e		(1 << 3)
++#define NAND_Ecc_P16e		(1 << 4)
++#define NAND_Ecc_P32e		(1 << 5)
++#define NAND_Ecc_P64e		(1 << 6)
++#define NAND_Ecc_P128e		(1 << 7)
++#define NAND_Ecc_P256e		(1 << 8)
++#define NAND_Ecc_P512e		(1 << 9)
++#define NAND_Ecc_P1024e		(1 << 10)
++#define NAND_Ecc_P2048e		(1 << 11)
++
++#define NAND_Ecc_P1o		(1 << 16)
++#define NAND_Ecc_P2o		(1 << 17)
++#define NAND_Ecc_P4o		(1 << 18)
++#define NAND_Ecc_P8o		(1 << 19)
++#define NAND_Ecc_P16o		(1 << 20)
++#define NAND_Ecc_P32o		(1 << 21)
++#define NAND_Ecc_P64o		(1 << 22)
++#define NAND_Ecc_P128o		(1 << 23)
++#define NAND_Ecc_P256o		(1 << 24)
++#define NAND_Ecc_P512o		(1 << 25)
++#define NAND_Ecc_P1024o		(1 << 26)
++#define NAND_Ecc_P2048o		(1 << 27)
++
++#define TF(value)	(value ? 1 : 0)
++
++#define P2048e(a)	(TF(a & NAND_Ecc_P2048e)	<< 0)
++#define P2048o(a)	(TF(a & NAND_Ecc_P2048o)	<< 1)
++#define P1e(a)		(TF(a & NAND_Ecc_P1e)		<< 2)
++#define P1o(a)		(TF(a & NAND_Ecc_P1o)		<< 3)
++#define P2e(a)		(TF(a & NAND_Ecc_P2e)		<< 4)
++#define P2o(a)		(TF(a & NAND_Ecc_P2o)		<< 5)
++#define P4e(a)		(TF(a & NAND_Ecc_P4e)		<< 6)
++#define P4o(a)		(TF(a & NAND_Ecc_P4o)		<< 7)
++
++#define P8e(a)		(TF(a & NAND_Ecc_P8e)		<< 0)
++#define P8o(a)		(TF(a & NAND_Ecc_P8o)		<< 1)
++#define P16e(a)		(TF(a & NAND_Ecc_P16e)		<< 2)
++#define P16o(a)		(TF(a & NAND_Ecc_P16o)		<< 3)
++#define P32e(a)		(TF(a & NAND_Ecc_P32e)		<< 4)
++#define P32o(a)		(TF(a & NAND_Ecc_P32o)		<< 5)
++#define P64e(a)		(TF(a & NAND_Ecc_P64e)		<< 6)
++#define P64o(a)		(TF(a & NAND_Ecc_P64o)		<< 7)
++
++#define P128e(a)	(TF(a & NAND_Ecc_P128e)		<< 0)
++#define P128o(a)	(TF(a & NAND_Ecc_P128o)		<< 1)
++#define P256e(a)	(TF(a & NAND_Ecc_P256e)		<< 2)
++#define P256o(a)	(TF(a & NAND_Ecc_P256o)		<< 3)
++#define P512e(a)	(TF(a & NAND_Ecc_P512e)		<< 4)
++#define P512o(a)	(TF(a & NAND_Ecc_P512o)		<< 5)
++#define P1024e(a)	(TF(a & NAND_Ecc_P1024e)	<< 6)
++#define P1024o(a)	(TF(a & NAND_Ecc_P1024o)	<< 7)
++
++#define P8e_s(a)	(TF(a & NAND_Ecc_P8e)		<< 0)
++#define P8o_s(a)	(TF(a & NAND_Ecc_P8o)		<< 1)
++#define P16e_s(a)	(TF(a & NAND_Ecc_P16e)		<< 2)
++#define P16o_s(a)	(TF(a & NAND_Ecc_P16o)		<< 3)
++#define P1e_s(a)	(TF(a & NAND_Ecc_P1e)		<< 4)
++#define P1o_s(a)	(TF(a & NAND_Ecc_P1o)		<< 5)
++#define P2e_s(a)	(TF(a & NAND_Ecc_P2e)		<< 6)
++#define P2o_s(a)	(TF(a & NAND_Ecc_P2o)		<< 7)
++
++#define P4e_s(a)	(TF(a & NAND_Ecc_P4e)		<< 0)
++#define P4o_s(a)	(TF(a & NAND_Ecc_P4o)		<< 1)
++
++#define	PREFETCH_CONFIG1_CS_SHIFT	24
++#define	ECC_CONFIG_CS_SHIFT		1
++#define	CS_MASK				0x7
++#define	ENABLE_PREFETCH			(0x1 << 7)
++#define	DMA_MPU_MODE_SHIFT		2
++#define	ECCSIZE0_SHIFT			12
++#define	ECCSIZE1_SHIFT			22
++#define	ECC1RESULTSIZE			0x1
++#define	ECCCLEAR			0x100
++#define	ECC1				0x1
++#define	PREFETCH_FIFOTHRESHOLD_MAX	0x40
++#define	PREFETCH_FIFOTHRESHOLD(val)	((val) << 8)
++#define	PREFETCH_STATUS_COUNT(val)	(val & 0x00003fff)
++#define	PREFETCH_STATUS_FIFO_CNT(val)	((val >> 24) & 0x7F)
++#define	STATUS_BUFF_EMPTY		0x00000001
++
++#define SECTOR_BYTES		512
++/* 4 bit padding to make byte aligned, 56 = 52 + 4 */
++#define BCH4_BIT_PAD		4
++
++/* GPMC ecc engine settings for read */
++#define BCH_WRAPMODE_1		1	/* BCH wrap mode 1 */
++#define BCH8R_ECC_SIZE0		0x1a	/* ecc_size0 = 26 */
++#define BCH8R_ECC_SIZE1		0x2	/* ecc_size1 = 2 */
++#define BCH4R_ECC_SIZE0		0xd	/* ecc_size0 = 13 */
++#define BCH4R_ECC_SIZE1		0x3	/* ecc_size1 = 3 */
++
++/* GPMC ecc engine settings for write */
++#define BCH_WRAPMODE_6		6	/* BCH wrap mode 6 */
++#define BCH_ECC_SIZE0		0x0	/* ecc_size0 = 0, no oob protection */
++#define BCH_ECC_SIZE1		0x20	/* ecc_size1 = 32 */
++
++#define BADBLOCK_MARKER_LENGTH		2
++
++static u_char bch16_vector[] = {0xf5, 0x24, 0x1c, 0xd0, 0x61, 0xb3, 0xf1, 0x55,
++				0x2e, 0x2c, 0x86, 0xa3, 0xed, 0x36, 0x1b, 0x78,
++				0x48, 0x76, 0xa9, 0x3b, 0x97, 0xd1, 0x7a, 0x93,
++				0x07, 0x0e};
++static u_char bch8_vector[] = {0xf3, 0xdb, 0x14, 0x16, 0x8b, 0xd2, 0xbe, 0xcc,
++	0xac, 0x6b, 0xff, 0x99, 0x7b};
++static u_char bch4_vector[] = {0x00, 0x6b, 0x31, 0xdd, 0x41, 0xbc, 0x10};
++
++/* Shared among all NAND instances to synchronize access to the ECC Engine */
++static struct nand_hw_control omap_gpmc_controller = {
++	.lock = __SPIN_LOCK_UNLOCKED(omap_gpmc_controller.lock),
++	.wq = __WAIT_QUEUE_HEAD_INITIALIZER(omap_gpmc_controller.wq),
++};
++
++struct omap_nand_info {
++	struct nand_chip		nand;
++	struct platform_device		*pdev;
++
++	int				gpmc_cs;
++	bool				dev_ready;
++	enum nand_io			xfer_type;
++	int				devsize;
++	enum omap_ecc			ecc_opt;
++	struct device_node		*elm_of_node;
++
++	unsigned long			phys_base;
++	struct completion		comp;
++	struct dma_chan			*dma;
++	int				gpmc_irq_fifo;
++	int				gpmc_irq_count;
++	enum {
++		OMAP_NAND_IO_READ = 0,	/* read */
++		OMAP_NAND_IO_WRITE,	/* write */
++	} iomode;
++	u_char				*buf;
++	int					buf_len;
++	/* Interface to GPMC */
++	struct gpmc_nand_regs		reg;
++	struct gpmc_nand_ops		*ops;
++	bool				flash_bbt;
++	/* fields specific for BCHx_HW ECC scheme */
++	struct device			*elm_dev;
++	/* NAND ready gpio */
++	struct gpio_desc		*ready_gpiod;
++};
++
++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);
++}
++
++/**
++ * omap_prefetch_enable - configures and starts prefetch transfer
++ * @cs: cs (chip select) number
++ * @fifo_th: fifo threshold to be used for read/ write
++ * @dma_mode: dma mode enable (1) or disable (0)
++ * @u32_count: number of bytes to be transferred
++ * @is_write: prefetch read(0) or write post(1) mode
++ */
++static int omap_prefetch_enable(int cs, int fifo_th, int dma_mode,
++	unsigned int u32_count, int is_write, struct omap_nand_info *info)
++{
++	u32 val;
++
++	if (fifo_th > PREFETCH_FIFOTHRESHOLD_MAX)
++		return -1;
++
++	if (readl(info->reg.gpmc_prefetch_control))
++		return -EBUSY;
++
++	/* Set the amount of bytes to be prefetched */
++	writel(u32_count, info->reg.gpmc_prefetch_config2);
++
++	/* Set dma/mpu mode, the prefetch read / post write and
++	 * enable the engine. Set which cs is has requested for.
++	 */
++	val = ((cs << PREFETCH_CONFIG1_CS_SHIFT) |
++		PREFETCH_FIFOTHRESHOLD(fifo_th) | ENABLE_PREFETCH |
++		(dma_mode << DMA_MPU_MODE_SHIFT) | (is_write & 0x1));
++	writel(val, info->reg.gpmc_prefetch_config1);
++
++	/*  Start the prefetch engine */
++	writel(0x1, info->reg.gpmc_prefetch_control);
++
++	return 0;
++}
++
++/**
++ * omap_prefetch_reset - disables and stops the prefetch engine
++ */
++static int omap_prefetch_reset(int cs, struct omap_nand_info *info)
++{
++	u32 config1;
++
++	/* check if the same module/cs is trying to reset */
++	config1 = readl(info->reg.gpmc_prefetch_config1);
++	if (((config1 >> PREFETCH_CONFIG1_CS_SHIFT) & CS_MASK) != cs)
++		return -EINVAL;
++
++	/* Stop the PFPW engine */
++	writel(0x0, info->reg.gpmc_prefetch_control);
++
++	/* Reset/disable the PFPW engine */
++	writel(0x0, info->reg.gpmc_prefetch_config1);
++
++	return 0;
++}
++
++/**
++ * omap_hwcontrol - hardware specific access to control-lines
++ * @mtd: MTD device structure
++ * @cmd: command to device
++ * @ctrl:
++ * NAND_NCE: bit 0 -> don't care
++ * NAND_CLE: bit 1 -> Command Latch
++ * NAND_ALE: bit 2 -> Address Latch
++ *
++ * NOTE: boards may use different bits for these!!
++ */
++static void omap_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
++{
++	struct omap_nand_info *info = mtd_to_omap(mtd);
++
++	if (cmd != NAND_CMD_NONE) {
++		if (ctrl & NAND_CLE)
++			writeb(cmd, info->reg.gpmc_nand_command);
++
++		else if (ctrl & NAND_ALE)
++			writeb(cmd, info->reg.gpmc_nand_address);
++
++		else /* NAND_NCE */
++			writeb(cmd, info->reg.gpmc_nand_data);
++	}
++}
++
++/**
++ * omap_read_buf8 - read data from NAND controller into buffer
++ * @mtd: MTD device structure
++ * @buf: buffer to store date
++ * @len: number of bytes to read
++ */
++static void omap_read_buf8(struct mtd_info *mtd, u_char *buf, int len)
++{
++	struct nand_chip *nand = mtd_to_nand(mtd);
++
++	ioread8_rep(nand->IO_ADDR_R, buf, len);
++}
++
++/**
++ * omap_write_buf8 - write buffer to NAND controller
++ * @mtd: MTD device structure
++ * @buf: data buffer
++ * @len: number of bytes to write
++ */
++static void omap_write_buf8(struct mtd_info *mtd, const u_char *buf, int len)
++{
++	struct omap_nand_info *info = mtd_to_omap(mtd);
++	u_char *p = (u_char *)buf;
++	bool status;
++
++	while (len--) {
++		iowrite8(*p++, info->nand.IO_ADDR_W);
++		/* wait until buffer is available for write */
++		do {
++			status = info->ops->nand_writebuffer_empty();
++		} while (!status);
++	}
++}
++
++/**
++ * omap_read_buf16 - read data from NAND controller into buffer
++ * @mtd: MTD device structure
++ * @buf: buffer to store date
++ * @len: number of bytes to read
++ */
++static void omap_read_buf16(struct mtd_info *mtd, u_char *buf, int len)
++{
++	struct nand_chip *nand = mtd_to_nand(mtd);
++
++	ioread16_rep(nand->IO_ADDR_R, buf, len / 2);
++}
++
++/**
++ * omap_write_buf16 - write buffer to NAND controller
++ * @mtd: MTD device structure
++ * @buf: data buffer
++ * @len: number of bytes to write
++ */
++static void omap_write_buf16(struct mtd_info *mtd, const u_char * buf, int len)
++{
++	struct omap_nand_info *info = mtd_to_omap(mtd);
++	u16 *p = (u16 *) buf;
++	bool status;
++	/* FIXME try bursts of writesw() or DMA ... */
++	len >>= 1;
++
++	while (len--) {
++		iowrite16(*p++, info->nand.IO_ADDR_W);
++		/* wait until buffer is available for write */
++		do {
++			status = info->ops->nand_writebuffer_empty();
++		} while (!status);
++	}
++}
++
++/**
++ * omap_read_buf_pref - read data from NAND controller into buffer
++ * @mtd: MTD device structure
++ * @buf: buffer to store date
++ * @len: number of bytes to read
++ */
++static void omap_read_buf_pref(struct mtd_info *mtd, u_char *buf, int len)
++{
++	struct omap_nand_info *info = mtd_to_omap(mtd);
++	uint32_t r_count = 0;
++	int ret = 0;
++	u32 *p = (u32 *)buf;
++
++	/* take care of subpage reads */
++	if (len % 4) {
++		if (info->nand.options & NAND_BUSWIDTH_16)
++			omap_read_buf16(mtd, buf, len % 4);
++		else
++			omap_read_buf8(mtd, buf, len % 4);
++		p = (u32 *) (buf + len % 4);
++		len -= len % 4;
++	}
++
++	/* configure and start prefetch transfer */
++	ret = omap_prefetch_enable(info->gpmc_cs,
++			PREFETCH_FIFOTHRESHOLD_MAX, 0x0, len, 0x0, info);
++	if (ret) {
++		/* PFPW engine is busy, use cpu copy method */
++		if (info->nand.options & NAND_BUSWIDTH_16)
++			omap_read_buf16(mtd, (u_char *)p, len);
++		else
++			omap_read_buf8(mtd, (u_char *)p, len);
++	} else {
++		do {
++			r_count = readl(info->reg.gpmc_prefetch_status);
++			r_count = PREFETCH_STATUS_FIFO_CNT(r_count);
++			r_count = r_count >> 2;
++			ioread32_rep(info->nand.IO_ADDR_R, p, r_count);
++			p += r_count;
++			len -= r_count << 2;
++		} while (len);
++		/* disable and stop the PFPW engine */
++		omap_prefetch_reset(info->gpmc_cs, info);
++	}
++}
++
++/**
++ * omap_write_buf_pref - write buffer to NAND controller
++ * @mtd: MTD device structure
++ * @buf: data buffer
++ * @len: number of bytes to write
++ */
++static void omap_write_buf_pref(struct mtd_info *mtd,
++					const u_char *buf, int len)
++{
++	struct omap_nand_info *info = mtd_to_omap(mtd);
++	uint32_t w_count = 0;
++	int i = 0, ret = 0;
++	u16 *p = (u16 *)buf;
++	unsigned long tim, limit;
++	u32 val;
++
++	/* take care of subpage writes */
++	if (len % 2 != 0) {
++		writeb(*buf, info->nand.IO_ADDR_W);
++		p = (u16 *)(buf + 1);
++		len--;
++	}
++
++	/*  configure and start prefetch transfer */
++	ret = omap_prefetch_enable(info->gpmc_cs,
++			PREFETCH_FIFOTHRESHOLD_MAX, 0x0, len, 0x1, info);
++	if (ret) {
++		/* PFPW engine is busy, use cpu copy method */
++		if (info->nand.options & NAND_BUSWIDTH_16)
++			omap_write_buf16(mtd, (u_char *)p, len);
++		else
++			omap_write_buf8(mtd, (u_char *)p, len);
++	} else {
++		while (len) {
++			w_count = readl(info->reg.gpmc_prefetch_status);
++			w_count = PREFETCH_STATUS_FIFO_CNT(w_count);
++			w_count = w_count >> 1;
++			for (i = 0; (i < w_count) && len; i++, len -= 2)
++				iowrite16(*p++, info->nand.IO_ADDR_W);
++		}
++		/* wait for data to flushed-out before reset the prefetch */
++		tim = 0;
++		limit = (loops_per_jiffy *
++					msecs_to_jiffies(OMAP_NAND_TIMEOUT_MS));
++		do {
++			cpu_relax();
++			val = readl(info->reg.gpmc_prefetch_status);
++			val = PREFETCH_STATUS_COUNT(val);
++		} while (val && (tim++ < limit));
++
++		/* disable and stop the PFPW engine */
++		omap_prefetch_reset(info->gpmc_cs, info);
++	}
++}
++
++/*
++ * omap_nand_dma_callback: callback on the completion of dma transfer
++ * @data: pointer to completion data structure
++ */
++static void omap_nand_dma_callback(void *data)
++{
++	complete((struct completion *) data);
++}
++
++/*
++ * omap_nand_dma_transfer: configure and start dma transfer
++ * @mtd: MTD device structure
++ * @addr: virtual address in RAM of source/destination
++ * @len: number of data bytes to be transferred
++ * @is_write: flag for read/write operation
++ */
++static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr,
++					unsigned int len, int is_write)
++{
++	struct omap_nand_info *info = mtd_to_omap(mtd);
++	struct dma_async_tx_descriptor *tx;
++	enum dma_data_direction dir = is_write ? DMA_TO_DEVICE :
++							DMA_FROM_DEVICE;
++	struct scatterlist sg;
++	unsigned long tim, limit;
++	unsigned n;
++	int ret;
++	u32 val;
++
++	if (!virt_addr_valid(addr))
++		goto out_copy;
++
++	sg_init_one(&sg, addr, len);
++	n = dma_map_sg(info->dma->device->dev, &sg, 1, dir);
++	if (n == 0) {
++		dev_err(&info->pdev->dev,
++			"Couldn't DMA map a %d byte buffer\n", len);
++		goto out_copy;
++	}
++
++	tx = dmaengine_prep_slave_sg(info->dma, &sg, n,
++		is_write ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM,
++		DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
++	if (!tx)
++		goto out_copy_unmap;
++
++	tx->callback = omap_nand_dma_callback;
++	tx->callback_param = &info->comp;
++	dmaengine_submit(tx);
++
++	init_completion(&info->comp);
++
++	/* setup and start DMA using dma_addr */
++	dma_async_issue_pending(info->dma);
++
++	/*  configure and start prefetch transfer */
++	ret = omap_prefetch_enable(info->gpmc_cs,
++		PREFETCH_FIFOTHRESHOLD_MAX, 0x1, len, is_write, info);
++	if (ret)
++		/* PFPW engine is busy, use cpu copy method */
++		goto out_copy_unmap;
++
++	wait_for_completion(&info->comp);
++	tim = 0;
++	limit = (loops_per_jiffy * msecs_to_jiffies(OMAP_NAND_TIMEOUT_MS));
++
++	do {
++		cpu_relax();
++		val = readl(info->reg.gpmc_prefetch_status);
++		val = PREFETCH_STATUS_COUNT(val);
++	} while (val && (tim++ < limit));
++
++	/* disable and stop the PFPW engine */
++	omap_prefetch_reset(info->gpmc_cs, info);
++
++	dma_unmap_sg(info->dma->device->dev, &sg, 1, dir);
++	return 0;
++
++out_copy_unmap:
++	dma_unmap_sg(info->dma->device->dev, &sg, 1, dir);
++out_copy:
++	if (info->nand.options & NAND_BUSWIDTH_16)
++		is_write == 0 ? omap_read_buf16(mtd, (u_char *) addr, len)
++			: omap_write_buf16(mtd, (u_char *) addr, len);
++	else
++		is_write == 0 ? omap_read_buf8(mtd, (u_char *) addr, len)
++			: omap_write_buf8(mtd, (u_char *) addr, len);
++	return 0;
++}
++
++/**
++ * omap_read_buf_dma_pref - read data from NAND controller into buffer
++ * @mtd: MTD device structure
++ * @buf: buffer to store date
++ * @len: number of bytes to read
++ */
++static void omap_read_buf_dma_pref(struct mtd_info *mtd, u_char *buf, int len)
++{
++	if (len <= mtd->oobsize)
++		omap_read_buf_pref(mtd, buf, len);
++	else
++		/* start transfer in DMA mode */
++		omap_nand_dma_transfer(mtd, buf, len, 0x0);
++}
++
++/**
++ * omap_write_buf_dma_pref - write buffer to NAND controller
++ * @mtd: MTD device structure
++ * @buf: data buffer
++ * @len: number of bytes to write
++ */
++static void omap_write_buf_dma_pref(struct mtd_info *mtd,
++					const u_char *buf, int len)
++{
++	if (len <= mtd->oobsize)
++		omap_write_buf_pref(mtd, buf, len);
++	else
++		/* start transfer in DMA mode */
++		omap_nand_dma_transfer(mtd, (u_char *) buf, len, 0x1);
++}
++
++/*
++ * omap_nand_irq - GPMC irq handler
++ * @this_irq: gpmc irq number
++ * @dev: omap_nand_info structure pointer is passed here
++ */
++static irqreturn_t omap_nand_irq(int this_irq, void *dev)
++{
++	struct omap_nand_info *info = (struct omap_nand_info *) dev;
++	u32 bytes;
++
++	bytes = readl(info->reg.gpmc_prefetch_status);
++	bytes = PREFETCH_STATUS_FIFO_CNT(bytes);
++	bytes = bytes  & 0xFFFC; /* io in multiple of 4 bytes */
++	if (info->iomode == OMAP_NAND_IO_WRITE) { /* checks for write io */
++		if (this_irq == info->gpmc_irq_count)
++			goto done;
++
++		if (info->buf_len && (info->buf_len < bytes))
++			bytes = info->buf_len;
++		else if (!info->buf_len)
++			bytes = 0;
++		iowrite32_rep(info->nand.IO_ADDR_W,
++						(u32 *)info->buf, bytes >> 2);
++		info->buf = info->buf + bytes;
++		info->buf_len -= bytes;
++
++	} else {
++		ioread32_rep(info->nand.IO_ADDR_R,
++						(u32 *)info->buf, bytes >> 2);
++		info->buf = info->buf + bytes;
++
++		if (this_irq == info->gpmc_irq_count)
++			goto done;
++	}
++
++	return IRQ_HANDLED;
++
++done:
++	complete(&info->comp);
++
++	disable_irq_nosync(info->gpmc_irq_fifo);
++	disable_irq_nosync(info->gpmc_irq_count);
++
++	return IRQ_HANDLED;
++}
++
++/*
++ * omap_read_buf_irq_pref - read data from NAND controller into buffer
++ * @mtd: MTD device structure
++ * @buf: buffer to store date
++ * @len: number of bytes to read
++ */
++static void omap_read_buf_irq_pref(struct mtd_info *mtd, u_char *buf, int len)
++{
++	struct omap_nand_info *info = mtd_to_omap(mtd);
++	int ret = 0;
++
++	if (len <= mtd->oobsize) {
++		omap_read_buf_pref(mtd, buf, len);
++		return;
++	}
++
++	info->iomode = OMAP_NAND_IO_READ;
++	info->buf = buf;
++	init_completion(&info->comp);
++
++	/*  configure and start prefetch transfer */
++	ret = omap_prefetch_enable(info->gpmc_cs,
++			PREFETCH_FIFOTHRESHOLD_MAX/2, 0x0, len, 0x0, info);
++	if (ret)
++		/* PFPW engine is busy, use cpu copy method */
++		goto out_copy;
++
++	info->buf_len = len;
++
++	enable_irq(info->gpmc_irq_count);
++	enable_irq(info->gpmc_irq_fifo);
++
++	/* waiting for read to complete */
++	wait_for_completion(&info->comp);
++
++	/* disable and stop the PFPW engine */
++	omap_prefetch_reset(info->gpmc_cs, info);
++	return;
++
++out_copy:
++	if (info->nand.options & NAND_BUSWIDTH_16)
++		omap_read_buf16(mtd, buf, len);
++	else
++		omap_read_buf8(mtd, buf, len);
++}
++
++/*
++ * omap_write_buf_irq_pref - write buffer to NAND controller
++ * @mtd: MTD device structure
++ * @buf: data buffer
++ * @len: number of bytes to write
++ */
++static void omap_write_buf_irq_pref(struct mtd_info *mtd,
++					const u_char *buf, int len)
++{
++	struct omap_nand_info *info = mtd_to_omap(mtd);
++	int ret = 0;
++	unsigned long tim, limit;
++	u32 val;
++
++	if (len <= mtd->oobsize) {
++		omap_write_buf_pref(mtd, buf, len);
++		return;
++	}
++
++	info->iomode = OMAP_NAND_IO_WRITE;
++	info->buf = (u_char *) buf;
++	init_completion(&info->comp);
++
++	/* configure and start prefetch transfer : size=24 */
++	ret = omap_prefetch_enable(info->gpmc_cs,
++		(PREFETCH_FIFOTHRESHOLD_MAX * 3) / 8, 0x0, len, 0x1, info);
++	if (ret)
++		/* PFPW engine is busy, use cpu copy method */
++		goto out_copy;
++
++	info->buf_len = len;
++
++	enable_irq(info->gpmc_irq_count);
++	enable_irq(info->gpmc_irq_fifo);
++
++	/* waiting for write to complete */
++	wait_for_completion(&info->comp);
++
++	/* wait for data to flushed-out before reset the prefetch */
++	tim = 0;
++	limit = (loops_per_jiffy *  msecs_to_jiffies(OMAP_NAND_TIMEOUT_MS));
++	do {
++		val = readl(info->reg.gpmc_prefetch_status);
++		val = PREFETCH_STATUS_COUNT(val);
++		cpu_relax();
++	} while (val && (tim++ < limit));
++
++	/* disable and stop the PFPW engine */
++	omap_prefetch_reset(info->gpmc_cs, info);
++	return;
++
++out_copy:
++	if (info->nand.options & NAND_BUSWIDTH_16)
++		omap_write_buf16(mtd, buf, len);
++	else
++		omap_write_buf8(mtd, buf, len);
++}
++
++/**
++ * gen_true_ecc - This function will generate true ECC value
++ * @ecc_buf: buffer to store ecc code
++ *
++ * This generated true ECC value can be used when correcting
++ * data read from NAND flash memory core
++ */
++static void gen_true_ecc(u8 *ecc_buf)
++{
++	u32 tmp = ecc_buf[0] | (ecc_buf[1] << 16) |
++		((ecc_buf[2] & 0xF0) << 20) | ((ecc_buf[2] & 0x0F) << 8);
++
++	ecc_buf[0] = ~(P64o(tmp) | P64e(tmp) | P32o(tmp) | P32e(tmp) |
++			P16o(tmp) | P16e(tmp) | P8o(tmp) | P8e(tmp));
++	ecc_buf[1] = ~(P1024o(tmp) | P1024e(tmp) | P512o(tmp) | P512e(tmp) |
++			P256o(tmp) | P256e(tmp) | P128o(tmp) | P128e(tmp));
++	ecc_buf[2] = ~(P4o(tmp) | P4e(tmp) | P2o(tmp) | P2e(tmp) | P1o(tmp) |
++			P1e(tmp) | P2048o(tmp) | P2048e(tmp));
++}
++
++/**
++ * omap_compare_ecc - Detect (2 bits) and correct (1 bit) error in data
++ * @ecc_data1:  ecc code from nand spare area
++ * @ecc_data2:  ecc code from hardware register obtained from hardware ecc
++ * @page_data:  page data
++ *
++ * This function compares two ECC's and indicates if there is an error.
++ * If the error can be corrected it will be corrected to the buffer.
++ * If there is no error, %0 is returned. If there is an error but it
++ * was corrected, %1 is returned. Otherwise, %-1 is returned.
++ */
++static int omap_compare_ecc(u8 *ecc_data1,	/* read from NAND memory */
++			    u8 *ecc_data2,	/* read from register */
++			    u8 *page_data)
++{
++	uint	i;
++	u8	tmp0_bit[8], tmp1_bit[8], tmp2_bit[8];
++	u8	comp0_bit[8], comp1_bit[8], comp2_bit[8];
++	u8	ecc_bit[24];
++	u8	ecc_sum = 0;
++	u8	find_bit = 0;
++	uint	find_byte = 0;
++	int	isEccFF;
++
++	isEccFF = ((*(u32 *)ecc_data1 & 0xFFFFFF) == 0xFFFFFF);
++
++	gen_true_ecc(ecc_data1);
++	gen_true_ecc(ecc_data2);
++
++	for (i = 0; i <= 2; i++) {
++		*(ecc_data1 + i) = ~(*(ecc_data1 + i));
++		*(ecc_data2 + i) = ~(*(ecc_data2 + i));
++	}
++
++	for (i = 0; i < 8; i++) {
++		tmp0_bit[i]     = *ecc_data1 % 2;
++		*ecc_data1	= *ecc_data1 / 2;
++	}
++
++	for (i = 0; i < 8; i++) {
++		tmp1_bit[i]	 = *(ecc_data1 + 1) % 2;
++		*(ecc_data1 + 1) = *(ecc_data1 + 1) / 2;
++	}
++
++	for (i = 0; i < 8; i++) {
++		tmp2_bit[i]	 = *(ecc_data1 + 2) % 2;
++		*(ecc_data1 + 2) = *(ecc_data1 + 2) / 2;
++	}
++
++	for (i = 0; i < 8; i++) {
++		comp0_bit[i]     = *ecc_data2 % 2;
++		*ecc_data2       = *ecc_data2 / 2;
++	}
++
++	for (i = 0; i < 8; i++) {
++		comp1_bit[i]     = *(ecc_data2 + 1) % 2;
++		*(ecc_data2 + 1) = *(ecc_data2 + 1) / 2;
++	}
++
++	for (i = 0; i < 8; i++) {
++		comp2_bit[i]     = *(ecc_data2 + 2) % 2;
++		*(ecc_data2 + 2) = *(ecc_data2 + 2) / 2;
++	}
++
++	for (i = 0; i < 6; i++)
++		ecc_bit[i] = tmp2_bit[i + 2] ^ comp2_bit[i + 2];
++
++	for (i = 0; i < 8; i++)
++		ecc_bit[i + 6] = tmp0_bit[i] ^ comp0_bit[i];
++
++	for (i = 0; i < 8; i++)
++		ecc_bit[i + 14] = tmp1_bit[i] ^ comp1_bit[i];
++
++	ecc_bit[22] = tmp2_bit[0] ^ comp2_bit[0];
++	ecc_bit[23] = tmp2_bit[1] ^ comp2_bit[1];
++
++	for (i = 0; i < 24; i++)
++		ecc_sum += ecc_bit[i];
++
++	switch (ecc_sum) {
++	case 0:
++		/* Not reached because this function is not called if
++		 *  ECC values are equal
++		 */
++		return 0;
++
++	case 1:
++		/* Uncorrectable error */
++		pr_debug("ECC UNCORRECTED_ERROR 1\n");
++		return -EBADMSG;
++
++	case 11:
++		/* UN-Correctable error */
++		pr_debug("ECC UNCORRECTED_ERROR B\n");
++		return -EBADMSG;
++
++	case 12:
++		/* Correctable error */
++		find_byte = (ecc_bit[23] << 8) +
++			    (ecc_bit[21] << 7) +
++			    (ecc_bit[19] << 6) +
++			    (ecc_bit[17] << 5) +
++			    (ecc_bit[15] << 4) +
++			    (ecc_bit[13] << 3) +
++			    (ecc_bit[11] << 2) +
++			    (ecc_bit[9]  << 1) +
++			    ecc_bit[7];
++
++		find_bit = (ecc_bit[5] << 2) + (ecc_bit[3] << 1) + ecc_bit[1];
++
++		pr_debug("Correcting single bit ECC error at offset: "
++				"%d, bit: %d\n", find_byte, find_bit);
++
++		page_data[find_byte] ^= (1 << find_bit);
++
++		return 1;
++	default:
++		if (isEccFF) {
++			if (ecc_data2[0] == 0 &&
++			    ecc_data2[1] == 0 &&
++			    ecc_data2[2] == 0)
++				return 0;
++		}
++		pr_debug("UNCORRECTED_ERROR default\n");
++		return -EBADMSG;
++	}
++}
++
++/**
++ * omap_correct_data - Compares the ECC read with HW generated ECC
++ * @mtd: MTD device structure
++ * @dat: page data
++ * @read_ecc: ecc read from nand flash
++ * @calc_ecc: ecc read from HW ECC registers
++ *
++ * Compares the ecc read from nand spare area with ECC registers values
++ * and if ECC's mismatched, it will call 'omap_compare_ecc' for error
++ * detection and correction. If there are no errors, %0 is returned. If
++ * there were errors and all of the errors were corrected, the number of
++ * corrected errors is returned. If uncorrectable errors exist, %-1 is
++ * returned.
++ */
++static int omap_correct_data(struct mtd_info *mtd, u_char *dat,
++				u_char *read_ecc, u_char *calc_ecc)
++{
++	struct omap_nand_info *info = mtd_to_omap(mtd);
++	int blockCnt = 0, i = 0, ret = 0;
++	int stat = 0;
++
++	/* Ex NAND_ECC_HW12_2048 */
++	if ((info->nand.ecc.mode == NAND_ECC_HW) &&
++			(info->nand.ecc.size  == 2048))
++		blockCnt = 4;
++	else
++		blockCnt = 1;
++
++	for (i = 0; i < blockCnt; i++) {
++		if (memcmp(read_ecc, calc_ecc, 3) != 0) {
++			ret = omap_compare_ecc(read_ecc, calc_ecc, dat);
++			if (ret < 0)
++				return ret;
++			/* keep track of the number of corrected errors */
++			stat += ret;
++		}
++		read_ecc += 3;
++		calc_ecc += 3;
++		dat      += 512;
++	}
++	return stat;
++}
++
++/**
++ * omap_calcuate_ecc - Generate non-inverted ECC bytes.
++ * @mtd: MTD device structure
++ * @dat: The pointer to data on which ecc is computed
++ * @ecc_code: The ecc_code buffer
++ *
++ * Using noninverted ECC can be considered ugly since writing a blank
++ * page ie. padding will clear the ECC bytes. This is no problem as long
++ * nobody is trying to write data on the seemingly unused page. Reading
++ * an erased page will produce an ECC mismatch between generated and read
++ * ECC bytes that has to be dealt with separately.
++ */
++static int omap_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
++				u_char *ecc_code)
++{
++	struct omap_nand_info *info = mtd_to_omap(mtd);
++	u32 val;
++
++	val = readl(info->reg.gpmc_ecc_config);
++	if (((val >> ECC_CONFIG_CS_SHIFT) & CS_MASK) != info->gpmc_cs)
++		return -EINVAL;
++
++	/* read ecc result */
++	val = readl(info->reg.gpmc_ecc1_result);
++	*ecc_code++ = val;          /* P128e, ..., P1e */
++	*ecc_code++ = val >> 16;    /* P128o, ..., P1o */
++	/* P2048o, P1024o, P512o, P256o, P2048e, P1024e, P512e, P256e */
++	*ecc_code++ = ((val >> 8) & 0x0f) | ((val >> 20) & 0xf0);
++
++	return 0;
++}
++
++/**
++ * omap_enable_hwecc - This function enables the hardware ecc functionality
++ * @mtd: MTD device structure
++ * @mode: Read/Write mode
++ */
++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);
++	unsigned int dev_width = (chip->options & NAND_BUSWIDTH_16) ? 1 : 0;
++	u32 val;
++
++	/* clear ecc and enable bits */
++	val = ECCCLEAR | ECC1;
++	writel(val, info->reg.gpmc_ecc_control);
++
++	/* program ecc and result sizes */
++	val = ((((info->nand.ecc.size >> 1) - 1) << ECCSIZE1_SHIFT) |
++			 ECC1RESULTSIZE);
++	writel(val, info->reg.gpmc_ecc_size_config);
++
++	switch (mode) {
++	case NAND_ECC_READ:
++	case NAND_ECC_WRITE:
++		writel(ECCCLEAR | ECC1, info->reg.gpmc_ecc_control);
++		break;
++	case NAND_ECC_READSYN:
++		writel(ECCCLEAR, info->reg.gpmc_ecc_control);
++		break;
++	default:
++		dev_info(&info->pdev->dev,
++			"error: unrecognized Mode[%d]!\n", mode);
++		break;
++	}
++
++	/* (ECC 16 or 8 bit col) | ( CS  )  | ECC Enable */
++	val = (dev_width << 7) | (info->gpmc_cs << 1) | (0x1);
++	writel(val, info->reg.gpmc_ecc_config);
++}
++
++/**
++ * omap_wait - wait until the command is done
++ * @mtd: MTD device structure
++ * @chip: NAND Chip structure
++ *
++ * Wait function is called during Program and erase operations and
++ * the way it is called from MTD layer, we should wait till the NAND
++ * chip is ready after the programming/erase operation has completed.
++ *
++ * Erase can take up to 400ms and program up to 20ms according to
++ * general NAND and SmartMedia specs
++ */
++static int omap_wait(struct mtd_info *mtd, struct nand_chip *chip)
++{
++	struct nand_chip *this = mtd_to_nand(mtd);
++	struct omap_nand_info *info = mtd_to_omap(mtd);
++	unsigned long timeo = jiffies;
++	int status, state = this->state;
++
++	if (state == FL_ERASING)
++		timeo += msecs_to_jiffies(400);
++	else
++		timeo += msecs_to_jiffies(20);
++
++	writeb(NAND_CMD_STATUS & 0xFF, info->reg.gpmc_nand_command);
++	while (time_before(jiffies, timeo)) {
++		status = readb(info->reg.gpmc_nand_data);
++		if (status & NAND_STATUS_READY)
++			break;
++		cond_resched();
++	}
++
++	status = readb(info->reg.gpmc_nand_data);
++	return status;
++}
++
++/**
++ * omap_dev_ready - checks the NAND Ready GPIO line
++ * @mtd: MTD device structure
++ *
++ * Returns true if ready and false if busy.
++ */
++static int omap_dev_ready(struct mtd_info *mtd)
++{
++	struct omap_nand_info *info = mtd_to_omap(mtd);
++
++	return gpiod_get_value(info->ready_gpiod);
++}
++
++/**
++ * omap_enable_hwecc_bch - Program GPMC to perform BCH ECC calculation
++ * @mtd: MTD device structure
++ * @mode: Read/Write mode
++ *
++ * When using BCH with SW correction (i.e. no ELM), sector size is set
++ * to 512 bytes and we use BCH_WRAPMODE_6 wrapping mode
++ * for both reading and writing with:
++ * eccsize0 = 0  (no additional protected byte in spare area)
++ * eccsize1 = 32 (skip 32 nibbles = 16 bytes per sector in spare area)
++ */
++static void __maybe_unused omap_enable_hwecc_bch(struct mtd_info *mtd, int mode)
++{
++	unsigned int bch_type;
++	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);
++	u32 val, wr_mode;
++	unsigned int ecc_size1, ecc_size0;
++
++	/* GPMC configurations for calculating ECC */
++	switch (ecc_opt) {
++	case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW:
++		bch_type = 0;
++		nsectors = 1;
++		wr_mode	  = BCH_WRAPMODE_6;
++		ecc_size0 = BCH_ECC_SIZE0;
++		ecc_size1 = BCH_ECC_SIZE1;
++		break;
++	case OMAP_ECC_BCH4_CODE_HW:
++		bch_type = 0;
++		nsectors = chip->ecc.steps;
++		if (mode == NAND_ECC_READ) {
++			wr_mode	  = BCH_WRAPMODE_1;
++			ecc_size0 = BCH4R_ECC_SIZE0;
++			ecc_size1 = BCH4R_ECC_SIZE1;
++		} else {
++			wr_mode   = BCH_WRAPMODE_6;
++			ecc_size0 = BCH_ECC_SIZE0;
++			ecc_size1 = BCH_ECC_SIZE1;
++		}
++		break;
++	case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
++		bch_type = 1;
++		nsectors = 1;
++		wr_mode	  = BCH_WRAPMODE_6;
++		ecc_size0 = BCH_ECC_SIZE0;
++		ecc_size1 = BCH_ECC_SIZE1;
++		break;
++	case OMAP_ECC_BCH8_CODE_HW:
++		bch_type = 1;
++		nsectors = chip->ecc.steps;
++		if (mode == NAND_ECC_READ) {
++			wr_mode	  = BCH_WRAPMODE_1;
++			ecc_size0 = BCH8R_ECC_SIZE0;
++			ecc_size1 = BCH8R_ECC_SIZE1;
++		} else {
++			wr_mode   = BCH_WRAPMODE_6;
++			ecc_size0 = BCH_ECC_SIZE0;
++			ecc_size1 = BCH_ECC_SIZE1;
++		}
++		break;
++	case OMAP_ECC_BCH16_CODE_HW:
++		bch_type = 0x2;
++		nsectors = chip->ecc.steps;
++		if (mode == NAND_ECC_READ) {
++			wr_mode	  = 0x01;
++			ecc_size0 = 52; /* ECC bits in nibbles per sector */
++			ecc_size1 = 0;  /* non-ECC bits in nibbles per sector */
++		} else {
++			wr_mode	  = 0x01;
++			ecc_size0 = 0;  /* extra bits in nibbles per sector */
++			ecc_size1 = 52; /* OOB bits in nibbles per sector */
++		}
++		break;
++	default:
++		return;
++	}
++
++	writel(ECC1, info->reg.gpmc_ecc_control);
++
++	/* Configure ecc size for BCH */
++	val = (ecc_size1 << ECCSIZE1_SHIFT) | (ecc_size0 << ECCSIZE0_SHIFT);
++	writel(val, info->reg.gpmc_ecc_size_config);
++
++	dev_width = (chip->options & NAND_BUSWIDTH_16) ? 1 : 0;
++
++	/* BCH configuration */
++	val = ((1                        << 16) | /* enable BCH */
++	       (bch_type		 << 12) | /* BCH4/BCH8/BCH16 */
++	       (wr_mode                  <<  8) | /* wrap mode */
++	       (dev_width                <<  7) | /* bus width */
++	       (((nsectors-1) & 0x7)     <<  4) | /* number of sectors */
++	       (info->gpmc_cs            <<  1) | /* ECC CS */
++	       (0x1));                            /* enable ECC */
++
++	writel(val, info->reg.gpmc_ecc_config);
++
++	/* Clear ecc and enable bits */
++	writel(ECCCLEAR | ECC1, info->reg.gpmc_ecc_control);
++}
++
++static u8  bch4_polynomial[] = {0x28, 0x13, 0xcc, 0x39, 0x96, 0xac, 0x7f};
++static u8  bch8_polynomial[] = {0xef, 0x51, 0x2e, 0x09, 0xed, 0x93, 0x9a, 0xc2,
++				0x97, 0x79, 0xe5, 0x24, 0xb5};
++
++/**
++ * _omap_calculate_ecc_bch - Generate ECC bytes for one sector
++ * @mtd:	MTD device structure
++ * @dat:	The pointer to data on which ecc is computed
++ * @ecc_code:	The ecc_code buffer
++ * @i:		The sector number (for a multi sector page)
++ *
++ * Support calculating of BCH4/8/16 ECC vectors for one sector
++ * within a page. Sector number is in @i.
++ */
++static int _omap_calculate_ecc_bch(struct mtd_info *mtd,
++				   const u_char *dat, u_char *ecc_calc, int i)
++{
++	struct omap_nand_info *info = mtd_to_omap(mtd);
++	int eccbytes	= info->nand.ecc.bytes;
++	struct gpmc_nand_regs	*gpmc_regs = &info->reg;
++	u8 *ecc_code;
++	unsigned long bch_val1, bch_val2, bch_val3, bch_val4;
++	u32 val;
++	int j;
++
++	ecc_code = ecc_calc;
++	switch (info->ecc_opt) {
++	case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
++	case OMAP_ECC_BCH8_CODE_HW:
++		bch_val1 = readl(gpmc_regs->gpmc_bch_result0[i]);
++		bch_val2 = readl(gpmc_regs->gpmc_bch_result1[i]);
++		bch_val3 = readl(gpmc_regs->gpmc_bch_result2[i]);
++		bch_val4 = readl(gpmc_regs->gpmc_bch_result3[i]);
++		*ecc_code++ = (bch_val4 & 0xFF);
++		*ecc_code++ = ((bch_val3 >> 24) & 0xFF);
++		*ecc_code++ = ((bch_val3 >> 16) & 0xFF);
++		*ecc_code++ = ((bch_val3 >> 8) & 0xFF);
++		*ecc_code++ = (bch_val3 & 0xFF);
++		*ecc_code++ = ((bch_val2 >> 24) & 0xFF);
++		*ecc_code++ = ((bch_val2 >> 16) & 0xFF);
++		*ecc_code++ = ((bch_val2 >> 8) & 0xFF);
++		*ecc_code++ = (bch_val2 & 0xFF);
++		*ecc_code++ = ((bch_val1 >> 24) & 0xFF);
++		*ecc_code++ = ((bch_val1 >> 16) & 0xFF);
++		*ecc_code++ = ((bch_val1 >> 8) & 0xFF);
++		*ecc_code++ = (bch_val1 & 0xFF);
++		break;
++	case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW:
++	case OMAP_ECC_BCH4_CODE_HW:
++		bch_val1 = readl(gpmc_regs->gpmc_bch_result0[i]);
++		bch_val2 = readl(gpmc_regs->gpmc_bch_result1[i]);
++		*ecc_code++ = ((bch_val2 >> 12) & 0xFF);
++		*ecc_code++ = ((bch_val2 >> 4) & 0xFF);
++		*ecc_code++ = ((bch_val2 & 0xF) << 4) |
++			((bch_val1 >> 28) & 0xF);
++		*ecc_code++ = ((bch_val1 >> 20) & 0xFF);
++		*ecc_code++ = ((bch_val1 >> 12) & 0xFF);
++		*ecc_code++ = ((bch_val1 >> 4) & 0xFF);
++		*ecc_code++ = ((bch_val1 & 0xF) << 4);
++		break;
++	case OMAP_ECC_BCH16_CODE_HW:
++		val = readl(gpmc_regs->gpmc_bch_result6[i]);
++		ecc_code[0]  = ((val >>  8) & 0xFF);
++		ecc_code[1]  = ((val >>  0) & 0xFF);
++		val = readl(gpmc_regs->gpmc_bch_result5[i]);
++		ecc_code[2]  = ((val >> 24) & 0xFF);
++		ecc_code[3]  = ((val >> 16) & 0xFF);
++		ecc_code[4]  = ((val >>  8) & 0xFF);
++		ecc_code[5]  = ((val >>  0) & 0xFF);
++		val = readl(gpmc_regs->gpmc_bch_result4[i]);
++		ecc_code[6]  = ((val >> 24) & 0xFF);
++		ecc_code[7]  = ((val >> 16) & 0xFF);
++		ecc_code[8]  = ((val >>  8) & 0xFF);
++		ecc_code[9]  = ((val >>  0) & 0xFF);
++		val = readl(gpmc_regs->gpmc_bch_result3[i]);
++		ecc_code[10] = ((val >> 24) & 0xFF);
++		ecc_code[11] = ((val >> 16) & 0xFF);
++		ecc_code[12] = ((val >>  8) & 0xFF);
++		ecc_code[13] = ((val >>  0) & 0xFF);
++		val = readl(gpmc_regs->gpmc_bch_result2[i]);
++		ecc_code[14] = ((val >> 24) & 0xFF);
++		ecc_code[15] = ((val >> 16) & 0xFF);
++		ecc_code[16] = ((val >>  8) & 0xFF);
++		ecc_code[17] = ((val >>  0) & 0xFF);
++		val = readl(gpmc_regs->gpmc_bch_result1[i]);
++		ecc_code[18] = ((val >> 24) & 0xFF);
++		ecc_code[19] = ((val >> 16) & 0xFF);
++		ecc_code[20] = ((val >>  8) & 0xFF);
++		ecc_code[21] = ((val >>  0) & 0xFF);
++		val = readl(gpmc_regs->gpmc_bch_result0[i]);
++		ecc_code[22] = ((val >> 24) & 0xFF);
++		ecc_code[23] = ((val >> 16) & 0xFF);
++		ecc_code[24] = ((val >>  8) & 0xFF);
++		ecc_code[25] = ((val >>  0) & 0xFF);
++		break;
++	default:
++		return -EINVAL;
++	}
++
++	/* ECC scheme specific syndrome customizations */
++	switch (info->ecc_opt) {
++	case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW:
++		/* Add constant polynomial to remainder, so that
++		 * ECC of blank pages results in 0x0 on reading back
++		 */
++		for (j = 0; j < eccbytes; j++)
++			ecc_calc[j] ^= bch4_polynomial[j];
++		break;
++	case OMAP_ECC_BCH4_CODE_HW:
++		/* Set  8th ECC byte as 0x0 for ROM compatibility */
++		ecc_calc[eccbytes - 1] = 0x0;
++		break;
++	case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
++		/* Add constant polynomial to remainder, so that
++		 * ECC of blank pages results in 0x0 on reading back
++		 */
++		for (j = 0; j < eccbytes; j++)
++			ecc_calc[j] ^= bch8_polynomial[j];
++		break;
++	case OMAP_ECC_BCH8_CODE_HW:
++		/* Set 14th ECC byte as 0x0 for ROM compatibility */
++		ecc_calc[eccbytes - 1] = 0x0;
++		break;
++	case OMAP_ECC_BCH16_CODE_HW:
++		break;
++	default:
++		return -EINVAL;
++	}
++
++	return 0;
++}
++
++/**
++ * omap_calculate_ecc_bch_sw - ECC generator for sector for SW based correction
++ * @mtd:	MTD device structure
++ * @dat:	The pointer to data on which ecc is computed
++ * @ecc_code:	The ecc_code buffer
++ *
++ * Support calculating of BCH4/8/16 ECC vectors for one sector. This is used
++ * when SW based correction is required as ECC is required for one sector
++ * at a time.
++ */
++static int omap_calculate_ecc_bch_sw(struct mtd_info *mtd,
++				     const u_char *dat, u_char *ecc_calc)
++{
++	return _omap_calculate_ecc_bch(mtd, dat, ecc_calc, 0);
++}
++
++/**
++ * omap_calculate_ecc_bch_multi - Generate ECC for multiple sectors
++ * @mtd:	MTD device structure
++ * @dat:	The pointer to data on which ecc is computed
++ * @ecc_code:	The ecc_code buffer
++ *
++ * Support calculating of BCH4/8/16 ecc vectors for the entire page in one go.
++ */
++static int omap_calculate_ecc_bch_multi(struct mtd_info *mtd,
++					const u_char *dat, u_char *ecc_calc)
++{
++	struct omap_nand_info *info = mtd_to_omap(mtd);
++	int eccbytes = info->nand.ecc.bytes;
++	unsigned long nsectors;
++	int i, ret;
++
++	nsectors = ((readl(info->reg.gpmc_ecc_config) >> 4) & 0x7) + 1;
++	for (i = 0; i < nsectors; i++) {
++		ret = _omap_calculate_ecc_bch(mtd, dat, ecc_calc, i);
++		if (ret)
++			return ret;
++
++		ecc_calc += eccbytes;
++	}
++
++	return 0;
++}
++
++/**
++ * erased_sector_bitflips - count bit flips
++ * @data:	data sector buffer
++ * @oob:	oob buffer
++ * @info:	omap_nand_info
++ *
++ * Check the bit flips in erased page falls below correctable level.
++ * If falls below, report the page as erased with correctable bit
++ * flip, else report as uncorrectable page.
++ */
++static int erased_sector_bitflips(u_char *data, u_char *oob,
++		struct omap_nand_info *info)
++{
++	int flip_bits = 0, i;
++
++	for (i = 0; i < info->nand.ecc.size; i++) {
++		flip_bits += hweight8(~data[i]);
++		if (flip_bits > info->nand.ecc.strength)
++			return 0;
++	}
++
++	for (i = 0; i < info->nand.ecc.bytes - 1; i++) {
++		flip_bits += hweight8(~oob[i]);
++		if (flip_bits > info->nand.ecc.strength)
++			return 0;
++	}
++
++	/*
++	 * Bit flips falls in correctable level.
++	 * Fill data area with 0xFF
++	 */
++	if (flip_bits) {
++		memset(data, 0xFF, info->nand.ecc.size);
++		memset(oob, 0xFF, info->nand.ecc.bytes);
++	}
++
++	return flip_bits;
++}
++
++/**
++ * omap_elm_correct_data - corrects page data area in case error reported
++ * @mtd:	MTD device structure
++ * @data:	page data
++ * @read_ecc:	ecc read from nand flash
++ * @calc_ecc:	ecc read from HW ECC registers
++ *
++ * Calculated ecc vector reported as zero in case of non-error pages.
++ * In case of non-zero ecc vector, first filter out erased-pages, and
++ * then process data via ELM to detect bit-flips.
++ */
++static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data,
++				u_char *read_ecc, u_char *calc_ecc)
++{
++	struct omap_nand_info *info = mtd_to_omap(mtd);
++	struct nand_ecc_ctrl *ecc = &info->nand.ecc;
++	int eccsteps = info->nand.ecc.steps;
++	int i , j, stat = 0;
++	int eccflag, actual_eccbytes;
++	struct elm_errorvec err_vec[ERROR_VECTOR_MAX];
++	u_char *ecc_vec = calc_ecc;
++	u_char *spare_ecc = read_ecc;
++	u_char *erased_ecc_vec;
++	u_char *buf;
++	int bitflip_count;
++	bool is_error_reported = false;
++	u32 bit_pos, byte_pos, error_max, pos;
++	int err;
++
++	switch (info->ecc_opt) {
++	case OMAP_ECC_BCH4_CODE_HW:
++		/* omit  7th ECC byte reserved for ROM code compatibility */
++		actual_eccbytes = ecc->bytes - 1;
++		erased_ecc_vec = bch4_vector;
++		break;
++	case OMAP_ECC_BCH8_CODE_HW:
++		/* omit 14th ECC byte reserved for ROM code compatibility */
++		actual_eccbytes = ecc->bytes - 1;
++		erased_ecc_vec = bch8_vector;
++		break;
++	case OMAP_ECC_BCH16_CODE_HW:
++		actual_eccbytes = ecc->bytes;
++		erased_ecc_vec = bch16_vector;
++		break;
++	default:
++		dev_err(&info->pdev->dev, "invalid driver configuration\n");
++		return -EINVAL;
++	}
++
++	/* Initialize elm error vector to zero */
++	memset(err_vec, 0, sizeof(err_vec));
++
++	for (i = 0; i < eccsteps ; i++) {
++		eccflag = 0;	/* initialize eccflag */
++
++		/*
++		 * Check any error reported,
++		 * In case of error, non zero ecc reported.
++		 */
++		for (j = 0; j < actual_eccbytes; j++) {
++			if (calc_ecc[j] != 0) {
++				eccflag = 1; /* non zero ecc, error present */
++				break;
++			}
++		}
++
++		if (eccflag == 1) {
++			if (memcmp(calc_ecc, erased_ecc_vec,
++						actual_eccbytes) == 0) {
++				/*
++				 * calc_ecc[] matches pattern for ECC(all 0xff)
++				 * so this is definitely an erased-page
++				 */
++			} else {
++				buf = &data[info->nand.ecc.size * i];
++				/*
++				 * count number of 0-bits in read_buf.
++				 * This check can be removed once a similar
++				 * check is introduced in generic NAND driver
++				 */
++				bitflip_count = erased_sector_bitflips(
++						buf, read_ecc, info);
++				if (bitflip_count) {
++					/*
++					 * number of 0-bits within ECC limits
++					 * So this may be an erased-page
++					 */
++					stat += bitflip_count;
++				} else {
++					/*
++					 * Too many 0-bits. It may be a
++					 * - programmed-page, OR
++					 * - erased-page with many bit-flips
++					 * So this page requires check by ELM
++					 */
++					err_vec[i].error_reported = true;
++					is_error_reported = true;
++				}
++			}
++		}
++
++		/* Update the ecc vector */
++		calc_ecc += ecc->bytes;
++		read_ecc += ecc->bytes;
++	}
++
++	/* Check if any error reported */
++	if (!is_error_reported)
++		return stat;
++
++	/* Decode BCH error using ELM module */
++	elm_decode_bch_error_page(info->elm_dev, ecc_vec, err_vec);
++
++	err = 0;
++	for (i = 0; i < eccsteps; i++) {
++		if (err_vec[i].error_uncorrectable) {
++			dev_err(&info->pdev->dev,
++				"uncorrectable bit-flips found\n");
++			err = -EBADMSG;
++		} else if (err_vec[i].error_reported) {
++			for (j = 0; j < err_vec[i].error_count; j++) {
++				switch (info->ecc_opt) {
++				case OMAP_ECC_BCH4_CODE_HW:
++					/* Add 4 bits to take care of padding */
++					pos = err_vec[i].error_loc[j] +
++						BCH4_BIT_PAD;
++					break;
++				case OMAP_ECC_BCH8_CODE_HW:
++				case OMAP_ECC_BCH16_CODE_HW:
++					pos = err_vec[i].error_loc[j];
++					break;
++				default:
++					return -EINVAL;
++				}
++				error_max = (ecc->size + actual_eccbytes) * 8;
++				/* Calculate bit position of error */
++				bit_pos = pos % 8;
++
++				/* Calculate byte position of error */
++				byte_pos = (error_max - pos - 1) / 8;
++
++				if (pos < error_max) {
++					if (byte_pos < 512) {
++						pr_debug("bitflip@dat[%d]=%x\n",
++						     byte_pos, data[byte_pos]);
++						data[byte_pos] ^= 1 << bit_pos;
++					} else {
++						pr_debug("bitflip@oob[%d]=%x\n",
++							(byte_pos - 512),
++						     spare_ecc[byte_pos - 512]);
++						spare_ecc[byte_pos - 512] ^=
++							1 << bit_pos;
++					}
++				} else {
++					dev_err(&info->pdev->dev,
++						"invalid bit-flip @ %d:%d\n",
++						byte_pos, bit_pos);
++					err = -EBADMSG;
++				}
++			}
++		}
++
++		/* Update number of correctable errors */
++		stat += err_vec[i].error_count;
++
++		/* Update page data with sector size */
++		data += ecc->size;
++		spare_ecc += ecc->bytes;
++	}
++
++	return (err) ? err : stat;
++}
++
++/**
++ * omap_write_page_bch - BCH ecc based write page function for entire page
++ * @mtd:		mtd info structure
++ * @chip:		nand chip info structure
++ * @buf:		data buffer
++ * @oob_required:	must write chip->oob_poi to OOB
++ * @page:		page
++ *
++ * Custom write page method evolved to support multi sector writing in one shot
++ */
++static int omap_write_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
++			       const uint8_t *buf, int oob_required, int page)
++{
++	int ret;
++	uint8_t *ecc_calc = chip->buffers->ecccalc;
++
++	/* Enable GPMC ecc engine */
++	chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
++
++	/* Write data */
++	chip->write_buf(mtd, buf, mtd->writesize);
++
++	/* Update ecc vector from GPMC result registers */
++	omap_calculate_ecc_bch_multi(mtd, buf, &ecc_calc[0]);
++
++	ret = mtd_ooblayout_set_eccbytes(mtd, ecc_calc, chip->oob_poi, 0,
++					 chip->ecc.total);
++	if (ret)
++		return ret;
++
++	/* Write ecc vector to OOB area */
++	chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
++	return 0;
++}
++
++/**
++ * omap_write_subpage_bch - BCH hardware ECC based subpage write
++ * @mtd:	mtd info structure
++ * @chip:	nand chip info structure
++ * @offset:	column address of subpage within the page
++ * @data_len:	data length
++ * @buf:	data buffer
++ * @oob_required: must write chip->oob_poi to OOB
++ * @page: page number to write
++ *
++ * OMAP optimized subpage write method.
++ */
++static int omap_write_subpage_bch(struct mtd_info *mtd,
++				  struct nand_chip *chip, u32 offset,
++				  u32 data_len, const u8 *buf,
++				  int oob_required, int page)
++{
++	u8 *ecc_calc = chip->buffers->ecccalc;
++	int ecc_size      = chip->ecc.size;
++	int ecc_bytes     = chip->ecc.bytes;
++	int ecc_steps     = chip->ecc.steps;
++	u32 start_step = offset / ecc_size;
++	u32 end_step   = (offset + data_len - 1) / ecc_size;
++	int step, ret = 0;
++
++	/*
++	 * Write entire page at one go as it would be optimal
++	 * as ECC is calculated by hardware.
++	 * ECC is calculated for all subpages but we choose
++	 * only what we want.
++	 */
++
++	/* Enable GPMC ECC engine */
++	chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
++
++	/* Write data */
++	chip->write_buf(mtd, buf, mtd->writesize);
++
++	for (step = 0; step < ecc_steps; step++) {
++		/* mask ECC of un-touched subpages by padding 0xFF */
++		if (step < start_step || step > end_step)
++			memset(ecc_calc, 0xff, ecc_bytes);
++		else
++			ret = _omap_calculate_ecc_bch(mtd, buf, ecc_calc, step);
++
++		if (ret)
++			return ret;
++
++		buf += ecc_size;
++		ecc_calc += ecc_bytes;
++	}
++
++	/* copy calculated ECC for whole page to chip->buffer->oob */
++	/* this include masked-value(0xFF) for unwritten subpages */
++	ecc_calc = chip->buffers->ecccalc;
++	ret = mtd_ooblayout_set_eccbytes(mtd, ecc_calc, chip->oob_poi, 0,
++					 chip->ecc.total);
++	if (ret)
++		return ret;
++
++	/* write OOB buffer to NAND device */
++	chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
++
++	return 0;
++}
++
++/**
++ * omap_read_page_bch - BCH ecc based page read function for entire page
++ * @mtd:		mtd info structure
++ * @chip:		nand chip info structure
++ * @buf:		buffer to store read data
++ * @oob_required:	caller requires OOB data read to chip->oob_poi
++ * @page:		page number to read
++ *
++ * For BCH ecc scheme, GPMC used for syndrome calculation and ELM module
++ * used for error correction.
++ * Custom method evolved to support ELM error correction & multi sector
++ * reading. On reading page data area is read along with OOB data with
++ * ecc engine enabled. ecc vector updated after read of OOB data.
++ * For non error pages ecc vector reported as zero.
++ */
++static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
++				uint8_t *buf, int oob_required, int page)
++{
++	uint8_t *ecc_calc = chip->buffers->ecccalc;
++	uint8_t *ecc_code = chip->buffers->ecccode;
++	int stat, ret;
++	unsigned int max_bitflips = 0;
++
++	/* Enable GPMC ecc engine */
++	chip->ecc.hwctl(mtd, NAND_ECC_READ);
++
++	/* Read data */
++	chip->read_buf(mtd, buf, mtd->writesize);
++
++	/* Read oob bytes */
++	chip->cmdfunc(mtd, NAND_CMD_RNDOUT,
++		      mtd->writesize + BADBLOCK_MARKER_LENGTH, -1);
++	chip->read_buf(mtd, chip->oob_poi + BADBLOCK_MARKER_LENGTH,
++		       chip->ecc.total);
++
++	/* Calculate ecc bytes */
++	omap_calculate_ecc_bch_multi(mtd, buf, ecc_calc);
++
++	ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, chip->oob_poi, 0,
++					 chip->ecc.total);
++	if (ret)
++		return ret;
++
++	stat = chip->ecc.correct(mtd, buf, ecc_code, ecc_calc);
++
++	if (stat < 0) {
++		mtd->ecc_stats.failed++;
++	} else {
++		mtd->ecc_stats.corrected += stat;
++		max_bitflips = max_t(unsigned int, max_bitflips, stat);
++	}
++
++	return max_bitflips;
++}
++
++/**
++ * is_elm_present - checks for presence of ELM module by scanning DT nodes
++ * @omap_nand_info: NAND device structure containing platform data
++ */
++static bool is_elm_present(struct omap_nand_info *info,
++			   struct device_node *elm_node)
++{
++	struct platform_device *pdev;
++
++	/* check whether elm-id is passed via DT */
++	if (!elm_node) {
++		dev_err(&info->pdev->dev, "ELM devicetree node not found\n");
++		return false;
++	}
++	pdev = of_find_device_by_node(elm_node);
++	/* check whether ELM device is registered */
++	if (!pdev) {
++		dev_err(&info->pdev->dev, "ELM device not found\n");
++		return false;
++	}
++	/* ELM module available, now configure it */
++	info->elm_dev = &pdev->dev;
++	return true;
++}
++
++static bool omap2_nand_ecc_check(struct omap_nand_info *info,
++				 struct omap_nand_platform_data	*pdata)
++{
++	bool ecc_needs_bch, ecc_needs_omap_bch, ecc_needs_elm;
++
++	switch (info->ecc_opt) {
++	case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW:
++	case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
++		ecc_needs_omap_bch = false;
++		ecc_needs_bch = true;
++		ecc_needs_elm = false;
++		break;
++	case OMAP_ECC_BCH4_CODE_HW:
++	case OMAP_ECC_BCH8_CODE_HW:
++	case OMAP_ECC_BCH16_CODE_HW:
++		ecc_needs_omap_bch = true;
++		ecc_needs_bch = false;
++		ecc_needs_elm = true;
++		break;
++	default:
++		ecc_needs_omap_bch = false;
++		ecc_needs_bch = false;
++		ecc_needs_elm = false;
++		break;
++	}
++
++	if (ecc_needs_bch && !IS_ENABLED(CONFIG_MTD_NAND_ECC_BCH)) {
++		dev_err(&info->pdev->dev,
++			"CONFIG_MTD_NAND_ECC_BCH not enabled\n");
++		return false;
++	}
++	if (ecc_needs_omap_bch && !IS_ENABLED(CONFIG_MTD_NAND_OMAP_BCH)) {
++		dev_err(&info->pdev->dev,
++			"CONFIG_MTD_NAND_OMAP_BCH not enabled\n");
++		return false;
++	}
++	if (ecc_needs_elm && !is_elm_present(info, info->elm_of_node)) {
++		dev_err(&info->pdev->dev, "ELM not available\n");
++		return false;
++	}
++
++	return true;
++}
++
++static const char * const nand_xfer_types[] = {
++	[NAND_OMAP_PREFETCH_POLLED] = "prefetch-polled",
++	[NAND_OMAP_POLLED] = "polled",
++	[NAND_OMAP_PREFETCH_DMA] = "prefetch-dma",
++	[NAND_OMAP_PREFETCH_IRQ] = "prefetch-irq",
++};
++
++static int omap_get_dt_info(struct device *dev, struct omap_nand_info *info)
++{
++	struct device_node *child = dev->of_node;
++	int i;
++	const char *s;
++	u32 cs;
++
++	if (of_property_read_u32(child, "reg", &cs) < 0) {
++		dev_err(dev, "reg not found in DT\n");
++		return -EINVAL;
++	}
++
++	info->gpmc_cs = cs;
++
++	/* detect availability of ELM module. Won't be present pre-OMAP4 */
++	info->elm_of_node = of_parse_phandle(child, "ti,elm-id", 0);
++	if (!info->elm_of_node) {
++		info->elm_of_node = of_parse_phandle(child, "elm_id", 0);
++		if (!info->elm_of_node)
++			dev_dbg(dev, "ti,elm-id not in DT\n");
++	}
++
++	/* select ecc-scheme for NAND */
++	if (of_property_read_string(child, "ti,nand-ecc-opt", &s)) {
++		dev_err(dev, "ti,nand-ecc-opt not found\n");
++		return -EINVAL;
++	}
++
++	if (!strcmp(s, "sw")) {
++		info->ecc_opt = OMAP_ECC_HAM1_CODE_SW;
++	} else if (!strcmp(s, "ham1") ||
++		   !strcmp(s, "hw") || !strcmp(s, "hw-romcode")) {
++		info->ecc_opt =	OMAP_ECC_HAM1_CODE_HW;
++	} else if (!strcmp(s, "bch4")) {
++		if (info->elm_of_node)
++			info->ecc_opt = OMAP_ECC_BCH4_CODE_HW;
++		else
++			info->ecc_opt = OMAP_ECC_BCH4_CODE_HW_DETECTION_SW;
++	} else if (!strcmp(s, "bch8")) {
++		if (info->elm_of_node)
++			info->ecc_opt = OMAP_ECC_BCH8_CODE_HW;
++		else
++			info->ecc_opt = OMAP_ECC_BCH8_CODE_HW_DETECTION_SW;
++	} else if (!strcmp(s, "bch16")) {
++		info->ecc_opt =	OMAP_ECC_BCH16_CODE_HW;
++	} else {
++		dev_err(dev, "unrecognized value for ti,nand-ecc-opt\n");
++		return -EINVAL;
++	}
++
++	/* select data transfer mode */
++	if (!of_property_read_string(child, "ti,nand-xfer-type", &s)) {
++		for (i = 0; i < ARRAY_SIZE(nand_xfer_types); i++) {
++			if (!strcasecmp(s, nand_xfer_types[i])) {
++				info->xfer_type = i;
++				return 0;
++			}
++		}
++
++		dev_err(dev, "unrecognized value for ti,nand-xfer-type\n");
++		return -EINVAL;
++	}
++
++	return 0;
++}
++
++static int omap_ooblayout_ecc(struct mtd_info *mtd, int section,
++			      struct mtd_oob_region *oobregion)
++{
++	struct omap_nand_info *info = mtd_to_omap(mtd);
++	struct nand_chip *chip = &info->nand;
++	int off = BADBLOCK_MARKER_LENGTH;
++
++	if (info->ecc_opt == OMAP_ECC_HAM1_CODE_HW &&
++	    !(chip->options & NAND_BUSWIDTH_16))
++		off = 1;
++
++	if (section)
++		return -ERANGE;
++
++	oobregion->offset = off;
++	oobregion->length = chip->ecc.total;
++
++	return 0;
++}
++
++static int omap_ooblayout_free(struct mtd_info *mtd, int section,
++			       struct mtd_oob_region *oobregion)
++{
++	struct omap_nand_info *info = mtd_to_omap(mtd);
++	struct nand_chip *chip = &info->nand;
++	int off = BADBLOCK_MARKER_LENGTH;
++
++	if (info->ecc_opt == OMAP_ECC_HAM1_CODE_HW &&
++	    !(chip->options & NAND_BUSWIDTH_16))
++		off = 1;
++
++	if (section)
++		return -ERANGE;
++
++	off += chip->ecc.total;
++	if (off >= mtd->oobsize)
++		return -ERANGE;
++
++	oobregion->offset = off;
++	oobregion->length = mtd->oobsize - off;
++
++	return 0;
++}
++
++static const struct mtd_ooblayout_ops omap_ooblayout_ops = {
++	.ecc = omap_ooblayout_ecc,
++	.free = omap_ooblayout_free,
++};
++
++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);
++	int off = BADBLOCK_MARKER_LENGTH;
++
++	if (section >= chip->ecc.steps)
++		return -ERANGE;
++
++	/*
++	 * When SW correction is employed, one OMAP specific marker byte is
++	 * reserved after each ECC step.
++	 */
++	oobregion->offset = off + (section * (chip->ecc.bytes + 1));
++	oobregion->length = chip->ecc.bytes;
++
++	return 0;
++}
++
++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);
++	int off = BADBLOCK_MARKER_LENGTH;
++
++	if (section)
++		return -ERANGE;
++
++	/*
++	 * When SW correction is employed, one OMAP specific marker byte is
++	 * reserved after each ECC step.
++	 */
++	off += ((chip->ecc.bytes + 1) * chip->ecc.steps);
++	if (off >= mtd->oobsize)
++		return -ERANGE;
++
++	oobregion->offset = off;
++	oobregion->length = mtd->oobsize - off;
++
++	return 0;
++}
++
++static const struct mtd_ooblayout_ops omap_sw_ooblayout_ops = {
++	.ecc = omap_sw_ooblayout_ecc,
++	.free = omap_sw_ooblayout_free,
++};
++
++static int omap_nand_probe(struct platform_device *pdev)
++{
++	struct omap_nand_info		*info;
++	struct omap_nand_platform_data	*pdata = NULL;
++	struct mtd_info			*mtd;
++	struct nand_chip		*nand_chip;
++	int				err;
++	dma_cap_mask_t			mask;
++	struct resource			*res;
++	struct device			*dev = &pdev->dev;
++	int				min_oobbytes = BADBLOCK_MARKER_LENGTH;
++	int				oobbytes_per_step;
++
++	info = devm_kzalloc(&pdev->dev, sizeof(struct omap_nand_info),
++				GFP_KERNEL);
++	if (!info)
++		return -ENOMEM;
++
++	info->pdev = pdev;
++
++	if (dev->of_node) {
++		if (omap_get_dt_info(dev, info))
++			return -EINVAL;
++	} else {
++		pdata = dev_get_platdata(&pdev->dev);
++		if (!pdata) {
++			dev_err(&pdev->dev, "platform data missing\n");
++			return -EINVAL;
++		}
++
++		info->gpmc_cs = pdata->cs;
++		info->reg = pdata->reg;
++		info->ecc_opt = pdata->ecc_opt;
++		if (pdata->dev_ready)
++			dev_info(&pdev->dev, "pdata->dev_ready is deprecated\n");
++
++		info->xfer_type = pdata->xfer_type;
++		info->devsize = pdata->devsize;
++		info->elm_of_node = pdata->elm_of_node;
++		info->flash_bbt = pdata->flash_bbt;
++	}
++
++	platform_set_drvdata(pdev, info);
++	info->ops = gpmc_omap_get_nand_ops(&info->reg, info->gpmc_cs);
++	if (!info->ops) {
++		dev_err(&pdev->dev, "Failed to get GPMC->NAND interface\n");
++		return -ENODEV;
++	}
++
++	nand_chip		= &info->nand;
++	mtd			= nand_to_mtd(nand_chip);
++	mtd->dev.parent		= &pdev->dev;
++	nand_chip->ecc.priv	= NULL;
++	nand_set_flash_node(nand_chip, dev->of_node);
++
++	if (!mtd->name) {
++		mtd->name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
++					   "omap2-nand.%d", info->gpmc_cs);
++		if (!mtd->name) {
++			dev_err(&pdev->dev, "Failed to set MTD name\n");
++			return -ENOMEM;
++		}
++	}
++
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	nand_chip->IO_ADDR_R = devm_ioremap_resource(&pdev->dev, res);
++	if (IS_ERR(nand_chip->IO_ADDR_R))
++		return PTR_ERR(nand_chip->IO_ADDR_R);
++
++	info->phys_base = res->start;
++
++	nand_chip->controller = &omap_gpmc_controller;
++
++	nand_chip->IO_ADDR_W = nand_chip->IO_ADDR_R;
++	nand_chip->cmd_ctrl  = omap_hwcontrol;
++
++	info->ready_gpiod = devm_gpiod_get_optional(&pdev->dev, "rb",
++						    GPIOD_IN);
++	if (IS_ERR(info->ready_gpiod)) {
++		dev_err(dev, "failed to get ready gpio\n");
++		return PTR_ERR(info->ready_gpiod);
++	}
++
++	/*
++	 * If RDY/BSY line is connected to OMAP then use the omap ready
++	 * function and the generic nand_wait function which reads the status
++	 * register after monitoring the RDY/BSY line. Otherwise use a standard
++	 * chip delay which is slightly more than tR (AC Timing) of the NAND
++	 * device and read status register until you get a failure or success
++	 */
++	if (info->ready_gpiod) {
++		nand_chip->dev_ready = omap_dev_ready;
++		nand_chip->chip_delay = 0;
++	} else {
++		nand_chip->waitfunc = omap_wait;
++		nand_chip->chip_delay = 50;
++	}
++
++	if (info->flash_bbt)
++		nand_chip->bbt_options |= NAND_BBT_USE_FLASH;
++
++	/* scan NAND device connected to chip controller */
++	nand_chip->options |= info->devsize & NAND_BUSWIDTH_16;
++	err = nand_scan_ident(mtd, 1, NULL);
++	if (err) {
++		dev_err(&info->pdev->dev,
++			"scan failed, may be bus-width mismatch\n");
++		goto return_error;
++	}
++
++	if (nand_chip->bbt_options & NAND_BBT_USE_FLASH)
++		nand_chip->bbt_options |= NAND_BBT_NO_OOB;
++	else
++		nand_chip->options |= NAND_SKIP_BBTSCAN;
++
++	/* re-populate low-level callbacks based on xfer modes */
++	switch (info->xfer_type) {
++	case NAND_OMAP_PREFETCH_POLLED:
++		nand_chip->read_buf   = omap_read_buf_pref;
++		nand_chip->write_buf  = omap_write_buf_pref;
++		break;
++
++	case NAND_OMAP_POLLED:
++		/* Use nand_base defaults for {read,write}_buf */
++		break;
++
++	case NAND_OMAP_PREFETCH_DMA:
++		dma_cap_zero(mask);
++		dma_cap_set(DMA_SLAVE, mask);
++		info->dma = dma_request_chan(pdev->dev.parent, "rxtx");
++
++		if (IS_ERR(info->dma)) {
++			dev_err(&pdev->dev, "DMA engine request failed\n");
++			err = PTR_ERR(info->dma);
++			goto return_error;
++		} else {
++			struct dma_slave_config cfg;
++
++			memset(&cfg, 0, sizeof(cfg));
++			cfg.src_addr = info->phys_base;
++			cfg.dst_addr = info->phys_base;
++			cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
++			cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
++			cfg.src_maxburst = 16;
++			cfg.dst_maxburst = 16;
++			err = dmaengine_slave_config(info->dma, &cfg);
++			if (err) {
++				dev_err(&pdev->dev, "DMA engine slave config failed: %d\n",
++					err);
++				goto return_error;
++			}
++			nand_chip->read_buf   = omap_read_buf_dma_pref;
++			nand_chip->write_buf  = omap_write_buf_dma_pref;
++		}
++		break;
++
++	case NAND_OMAP_PREFETCH_IRQ:
++		info->gpmc_irq_fifo = platform_get_irq(pdev, 0);
++		if (info->gpmc_irq_fifo <= 0) {
++			dev_err(&pdev->dev, "error getting fifo irq\n");
++			err = -ENODEV;
++			goto return_error;
++		}
++		err = devm_request_irq(&pdev->dev, info->gpmc_irq_fifo,
++					omap_nand_irq, IRQF_SHARED,
++					"gpmc-nand-fifo", info);
++		if (err) {
++			dev_err(&pdev->dev, "requesting irq(%d) error:%d",
++						info->gpmc_irq_fifo, err);
++			info->gpmc_irq_fifo = 0;
++			goto return_error;
++		}
++
++		info->gpmc_irq_count = platform_get_irq(pdev, 1);
++		if (info->gpmc_irq_count <= 0) {
++			dev_err(&pdev->dev, "error getting count irq\n");
++			err = -ENODEV;
++			goto return_error;
++		}
++		err = devm_request_irq(&pdev->dev, info->gpmc_irq_count,
++					omap_nand_irq, IRQF_SHARED,
++					"gpmc-nand-count", info);
++		if (err) {
++			dev_err(&pdev->dev, "requesting irq(%d) error:%d",
++						info->gpmc_irq_count, err);
++			info->gpmc_irq_count = 0;
++			goto return_error;
++		}
++
++		nand_chip->read_buf  = omap_read_buf_irq_pref;
++		nand_chip->write_buf = omap_write_buf_irq_pref;
++
++		break;
++
++	default:
++		dev_err(&pdev->dev,
++			"xfer_type(%d) not supported!\n", info->xfer_type);
++		err = -EINVAL;
++		goto return_error;
++	}
++
++	if (!omap2_nand_ecc_check(info, pdata)) {
++		err = -EINVAL;
++		goto return_error;
++	}
++
++	/*
++	 * Bail out earlier to let NAND_ECC_SOFT code create its own
++	 * ooblayout instead of using ours.
++	 */
++	if (info->ecc_opt == OMAP_ECC_HAM1_CODE_SW) {
++		nand_chip->ecc.mode = NAND_ECC_SOFT;
++		nand_chip->ecc.algo = NAND_ECC_HAMMING;
++		goto scan_tail;
++	}
++
++	/* populate MTD interface based on ECC scheme */
++	switch (info->ecc_opt) {
++	case OMAP_ECC_HAM1_CODE_HW:
++		pr_info("nand: using OMAP_ECC_HAM1_CODE_HW\n");
++		nand_chip->ecc.mode             = NAND_ECC_HW;
++		nand_chip->ecc.bytes            = 3;
++		nand_chip->ecc.size             = 512;
++		nand_chip->ecc.strength         = 1;
++		nand_chip->ecc.calculate        = omap_calculate_ecc;
++		nand_chip->ecc.hwctl            = omap_enable_hwecc;
++		nand_chip->ecc.correct          = omap_correct_data;
++		mtd_set_ooblayout(mtd, &omap_ooblayout_ops);
++		oobbytes_per_step		= nand_chip->ecc.bytes;
++
++		if (!(nand_chip->options & NAND_BUSWIDTH_16))
++			min_oobbytes		= 1;
++
++		break;
++
++	case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW:
++		pr_info("nand: using OMAP_ECC_BCH4_CODE_HW_DETECTION_SW\n");
++		nand_chip->ecc.mode		= NAND_ECC_HW;
++		nand_chip->ecc.size		= 512;
++		nand_chip->ecc.bytes		= 7;
++		nand_chip->ecc.strength		= 4;
++		nand_chip->ecc.hwctl		= omap_enable_hwecc_bch;
++		nand_chip->ecc.correct		= nand_bch_correct_data;
++		nand_chip->ecc.calculate	= omap_calculate_ecc_bch_sw;
++		mtd_set_ooblayout(mtd, &omap_sw_ooblayout_ops);
++		/* Reserve one byte for the OMAP marker */
++		oobbytes_per_step		= nand_chip->ecc.bytes + 1;
++		/* software bch library is used for locating errors */
++		nand_chip->ecc.priv		= nand_bch_init(mtd);
++		if (!nand_chip->ecc.priv) {
++			dev_err(&info->pdev->dev, "unable to use BCH library\n");
++			err = -EINVAL;
++			goto return_error;
++		}
++		break;
++
++	case OMAP_ECC_BCH4_CODE_HW:
++		pr_info("nand: using OMAP_ECC_BCH4_CODE_HW ECC scheme\n");
++		nand_chip->ecc.mode		= NAND_ECC_HW;
++		nand_chip->ecc.size		= 512;
++		/* 14th bit is kept reserved for ROM-code compatibility */
++		nand_chip->ecc.bytes		= 7 + 1;
++		nand_chip->ecc.strength		= 4;
++		nand_chip->ecc.hwctl		= omap_enable_hwecc_bch;
++		nand_chip->ecc.correct		= omap_elm_correct_data;
++		nand_chip->ecc.read_page	= omap_read_page_bch;
++		nand_chip->ecc.write_page	= omap_write_page_bch;
++		nand_chip->ecc.write_subpage	= omap_write_subpage_bch;
++		mtd_set_ooblayout(mtd, &omap_ooblayout_ops);
++		oobbytes_per_step		= nand_chip->ecc.bytes;
++
++		err = elm_config(info->elm_dev, BCH4_ECC,
++				 mtd->writesize / nand_chip->ecc.size,
++				 nand_chip->ecc.size, nand_chip->ecc.bytes);
++		if (err < 0)
++			goto return_error;
++		break;
++
++	case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
++		pr_info("nand: using OMAP_ECC_BCH8_CODE_HW_DETECTION_SW\n");
++		nand_chip->ecc.mode		= NAND_ECC_HW;
++		nand_chip->ecc.size		= 512;
++		nand_chip->ecc.bytes		= 13;
++		nand_chip->ecc.strength		= 8;
++		nand_chip->ecc.hwctl		= omap_enable_hwecc_bch;
++		nand_chip->ecc.correct		= nand_bch_correct_data;
++		nand_chip->ecc.calculate	= omap_calculate_ecc_bch_sw;
++		mtd_set_ooblayout(mtd, &omap_sw_ooblayout_ops);
++		/* Reserve one byte for the OMAP marker */
++		oobbytes_per_step		= nand_chip->ecc.bytes + 1;
++		/* software bch library is used for locating errors */
++		nand_chip->ecc.priv		= nand_bch_init(mtd);
++		if (!nand_chip->ecc.priv) {
++			dev_err(&info->pdev->dev, "unable to use BCH library\n");
++			err = -EINVAL;
++			goto return_error;
++		}
++		break;
++
++	case OMAP_ECC_BCH8_CODE_HW:
++		pr_info("nand: using OMAP_ECC_BCH8_CODE_HW ECC scheme\n");
++		nand_chip->ecc.mode		= NAND_ECC_HW;
++		nand_chip->ecc.size		= 512;
++		/* 14th bit is kept reserved for ROM-code compatibility */
++		nand_chip->ecc.bytes		= 13 + 1;
++		nand_chip->ecc.strength		= 8;
++		nand_chip->ecc.hwctl		= omap_enable_hwecc_bch;
++		nand_chip->ecc.correct		= omap_elm_correct_data;
++		nand_chip->ecc.read_page	= omap_read_page_bch;
++		nand_chip->ecc.write_page	= omap_write_page_bch;
++		nand_chip->ecc.write_subpage	= omap_write_subpage_bch;
++		mtd_set_ooblayout(mtd, &omap_ooblayout_ops);
++		oobbytes_per_step		= nand_chip->ecc.bytes;
++
++		err = elm_config(info->elm_dev, BCH8_ECC,
++				 mtd->writesize / nand_chip->ecc.size,
++				 nand_chip->ecc.size, nand_chip->ecc.bytes);
++		if (err < 0)
++			goto return_error;
++
++		break;
++
++	case OMAP_ECC_BCH16_CODE_HW:
++		pr_info("using OMAP_ECC_BCH16_CODE_HW ECC scheme\n");
++		nand_chip->ecc.mode		= NAND_ECC_HW;
++		nand_chip->ecc.size		= 512;
++		nand_chip->ecc.bytes		= 26;
++		nand_chip->ecc.strength		= 16;
++		nand_chip->ecc.hwctl		= omap_enable_hwecc_bch;
++		nand_chip->ecc.correct		= omap_elm_correct_data;
++		nand_chip->ecc.read_page	= omap_read_page_bch;
++		nand_chip->ecc.write_page	= omap_write_page_bch;
++		nand_chip->ecc.write_subpage	= omap_write_subpage_bch;
++		mtd_set_ooblayout(mtd, &omap_ooblayout_ops);
++		oobbytes_per_step		= nand_chip->ecc.bytes;
++
++		err = elm_config(info->elm_dev, BCH16_ECC,
++				 mtd->writesize / nand_chip->ecc.size,
++				 nand_chip->ecc.size, nand_chip->ecc.bytes);
++		if (err < 0)
++			goto return_error;
++
++		break;
++	default:
++		dev_err(&info->pdev->dev, "invalid or unsupported ECC scheme\n");
++		err = -EINVAL;
++		goto return_error;
++	}
++
++	/* check if NAND device's OOB is enough to store ECC signatures */
++	min_oobbytes += (oobbytes_per_step *
++			 (mtd->writesize / nand_chip->ecc.size));
++	if (mtd->oobsize < min_oobbytes) {
++		dev_err(&info->pdev->dev,
++			"not enough OOB bytes required = %d, available=%d\n",
++			min_oobbytes, mtd->oobsize);
++		err = -EINVAL;
++		goto return_error;
++	}
++
++scan_tail:
++	/* second phase scan */
++	err = nand_scan_tail(mtd);
++	if (err)
++		goto return_error;
++
++	if (dev->of_node)
++		mtd_device_register(mtd, NULL, 0);
++	else
++		mtd_device_register(mtd, pdata->parts, pdata->nr_parts);
++
++	platform_set_drvdata(pdev, mtd);
++
++	return 0;
++
++return_error:
++	if (!IS_ERR_OR_NULL(info->dma))
++		dma_release_channel(info->dma);
++	if (nand_chip->ecc.priv) {
++		nand_bch_free(nand_chip->ecc.priv);
++		nand_chip->ecc.priv = NULL;
++	}
++	return err;
++}
++
++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 omap_nand_info *info = mtd_to_omap(mtd);
++	if (nand_chip->ecc.priv) {
++		nand_bch_free(nand_chip->ecc.priv);
++		nand_chip->ecc.priv = NULL;
++	}
++	if (info->dma)
++		dma_release_channel(info->dma);
++	nand_release(mtd);
++	return 0;
++}
++
++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,
++	.remove		= omap_nand_remove,
++	.driver		= {
++		.name	= DRIVER_NAME,
++		.of_match_table = of_match_ptr(omap_nand_ids),
++	},
++};
++
++module_platform_driver(omap_nand_driver);
++
++MODULE_ALIAS("platform:" DRIVER_NAME);
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("Glue layer for NAND flash on TI OMAP boards");
+diff --git a/drivers/mtd/nand/raw/omap_elm.c b/drivers/mtd/nand/raw/omap_elm.c
+new file mode 100644
+index 0000000..a3f32f9
+--- /dev/null
++++ b/drivers/mtd/nand/raw/omap_elm.c
+@@ -0,0 +1,578 @@
++/*
++ * Error Location Module
++ *
++ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
++ *
++ * 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.
++ *
++ */
++
++#define DRIVER_NAME	"omap-elm"
++
++#include <linux/platform_device.h>
++#include <linux/module.h>
++#include <linux/interrupt.h>
++#include <linux/io.h>
++#include <linux/of.h>
++#include <linux/sched.h>
++#include <linux/pm_runtime.h>
++#include <linux/platform_data/elm.h>
++
++#define ELM_SYSCONFIG			0x010
++#define ELM_IRQSTATUS			0x018
++#define ELM_IRQENABLE			0x01c
++#define ELM_LOCATION_CONFIG		0x020
++#define ELM_PAGE_CTRL			0x080
++#define ELM_SYNDROME_FRAGMENT_0		0x400
++#define ELM_SYNDROME_FRAGMENT_1		0x404
++#define ELM_SYNDROME_FRAGMENT_2		0x408
++#define ELM_SYNDROME_FRAGMENT_3		0x40c
++#define ELM_SYNDROME_FRAGMENT_4		0x410
++#define ELM_SYNDROME_FRAGMENT_5		0x414
++#define ELM_SYNDROME_FRAGMENT_6		0x418
++#define ELM_LOCATION_STATUS		0x800
++#define ELM_ERROR_LOCATION_0		0x880
++
++/* ELM Interrupt Status Register */
++#define INTR_STATUS_PAGE_VALID		BIT(8)
++
++/* ELM Interrupt Enable Register */
++#define INTR_EN_PAGE_MASK		BIT(8)
++
++/* ELM Location Configuration Register */
++#define ECC_BCH_LEVEL_MASK		0x3
++
++/* ELM syndrome */
++#define ELM_SYNDROME_VALID		BIT(16)
++
++/* ELM_LOCATION_STATUS Register */
++#define ECC_CORRECTABLE_MASK		BIT(8)
++#define ECC_NB_ERRORS_MASK		0x1f
++
++/* ELM_ERROR_LOCATION_0-15 Registers */
++#define ECC_ERROR_LOCATION_MASK		0x1fff
++
++#define ELM_ECC_SIZE			0x7ff
++
++#define SYNDROME_FRAGMENT_REG_SIZE	0x40
++#define ERROR_LOCATION_SIZE		0x100
++
++struct elm_registers {
++	u32 elm_irqenable;
++	u32 elm_sysconfig;
++	u32 elm_location_config;
++	u32 elm_page_ctrl;
++	u32 elm_syndrome_fragment_6[ERROR_VECTOR_MAX];
++	u32 elm_syndrome_fragment_5[ERROR_VECTOR_MAX];
++	u32 elm_syndrome_fragment_4[ERROR_VECTOR_MAX];
++	u32 elm_syndrome_fragment_3[ERROR_VECTOR_MAX];
++	u32 elm_syndrome_fragment_2[ERROR_VECTOR_MAX];
++	u32 elm_syndrome_fragment_1[ERROR_VECTOR_MAX];
++	u32 elm_syndrome_fragment_0[ERROR_VECTOR_MAX];
++};
++
++struct elm_info {
++	struct device *dev;
++	void __iomem *elm_base;
++	struct completion elm_completion;
++	struct list_head list;
++	enum bch_ecc bch_type;
++	struct elm_registers elm_regs;
++	int ecc_steps;
++	int ecc_syndrome_size;
++};
++
++static LIST_HEAD(elm_devices);
++
++static void elm_write_reg(struct elm_info *info, int offset, u32 val)
++{
++	writel(val, info->elm_base + offset);
++}
++
++static u32 elm_read_reg(struct elm_info *info, int offset)
++{
++	return readl(info->elm_base + offset);
++}
++
++/**
++ * elm_config - Configure ELM module
++ * @dev:	ELM device
++ * @bch_type:	Type of BCH ecc
++ */
++int elm_config(struct device *dev, enum bch_ecc bch_type,
++	int ecc_steps, int ecc_step_size, int ecc_syndrome_size)
++{
++	u32 reg_val;
++	struct elm_info *info = dev_get_drvdata(dev);
++
++	if (!info) {
++		dev_err(dev, "Unable to configure elm - device not probed?\n");
++		return -EPROBE_DEFER;
++	}
++	/* ELM cannot detect ECC errors for chunks > 1KB */
++	if (ecc_step_size > ((ELM_ECC_SIZE + 1) / 2)) {
++		dev_err(dev, "unsupported config ecc-size=%d\n", ecc_step_size);
++		return -EINVAL;
++	}
++	/* ELM support 8 error syndrome process */
++	if (ecc_steps > ERROR_VECTOR_MAX) {
++		dev_err(dev, "unsupported config ecc-step=%d\n", ecc_steps);
++		return -EINVAL;
++	}
++
++	reg_val = (bch_type & ECC_BCH_LEVEL_MASK) | (ELM_ECC_SIZE << 16);
++	elm_write_reg(info, ELM_LOCATION_CONFIG, reg_val);
++	info->bch_type		= bch_type;
++	info->ecc_steps		= ecc_steps;
++	info->ecc_syndrome_size	= ecc_syndrome_size;
++
++	return 0;
++}
++EXPORT_SYMBOL(elm_config);
++
++/**
++ * elm_configure_page_mode - Enable/Disable page mode
++ * @info:	elm info
++ * @index:	index number of syndrome fragment vector
++ * @enable:	enable/disable flag for page mode
++ *
++ * Enable page mode for syndrome fragment index
++ */
++static void elm_configure_page_mode(struct elm_info *info, int index,
++		bool enable)
++{
++	u32 reg_val;
++
++	reg_val = elm_read_reg(info, ELM_PAGE_CTRL);
++	if (enable)
++		reg_val |= BIT(index);	/* enable page mode */
++	else
++		reg_val &= ~BIT(index);	/* disable page mode */
++
++	elm_write_reg(info, ELM_PAGE_CTRL, reg_val);
++}
++
++/**
++ * elm_load_syndrome - Load ELM syndrome reg
++ * @info:	elm info
++ * @err_vec:	elm error vectors
++ * @ecc:	buffer with calculated ecc
++ *
++ * Load syndrome fragment registers with calculated ecc in reverse order.
++ */
++static void elm_load_syndrome(struct elm_info *info,
++		struct elm_errorvec *err_vec, u8 *ecc)
++{
++	int i, offset;
++	u32 val;
++
++	for (i = 0; i < info->ecc_steps; i++) {
++
++		/* Check error reported */
++		if (err_vec[i].error_reported) {
++			elm_configure_page_mode(info, i, true);
++			offset = ELM_SYNDROME_FRAGMENT_0 +
++				SYNDROME_FRAGMENT_REG_SIZE * i;
++			switch (info->bch_type) {
++			case BCH8_ECC:
++				/* syndrome fragment 0 = ecc[9-12B] */
++				val = cpu_to_be32(*(u32 *) &ecc[9]);
++				elm_write_reg(info, offset, val);
++
++				/* syndrome fragment 1 = ecc[5-8B] */
++				offset += 4;
++				val = cpu_to_be32(*(u32 *) &ecc[5]);
++				elm_write_reg(info, offset, val);
++
++				/* syndrome fragment 2 = ecc[1-4B] */
++				offset += 4;
++				val = cpu_to_be32(*(u32 *) &ecc[1]);
++				elm_write_reg(info, offset, val);
++
++				/* syndrome fragment 3 = ecc[0B] */
++				offset += 4;
++				val = ecc[0];
++				elm_write_reg(info, offset, val);
++				break;
++			case BCH4_ECC:
++				/* syndrome fragment 0 = ecc[20-52b] bits */
++				val = (cpu_to_be32(*(u32 *) &ecc[3]) >> 4) |
++					((ecc[2] & 0xf) << 28);
++				elm_write_reg(info, offset, val);
++
++				/* syndrome fragment 1 = ecc[0-20b] bits */
++				offset += 4;
++				val = cpu_to_be32(*(u32 *) &ecc[0]) >> 12;
++				elm_write_reg(info, offset, val);
++				break;
++			case BCH16_ECC:
++				val = cpu_to_be32(*(u32 *) &ecc[22]);
++				elm_write_reg(info, offset, val);
++				offset += 4;
++				val = cpu_to_be32(*(u32 *) &ecc[18]);
++				elm_write_reg(info, offset, val);
++				offset += 4;
++				val = cpu_to_be32(*(u32 *) &ecc[14]);
++				elm_write_reg(info, offset, val);
++				offset += 4;
++				val = cpu_to_be32(*(u32 *) &ecc[10]);
++				elm_write_reg(info, offset, val);
++				offset += 4;
++				val = cpu_to_be32(*(u32 *) &ecc[6]);
++				elm_write_reg(info, offset, val);
++				offset += 4;
++				val = cpu_to_be32(*(u32 *) &ecc[2]);
++				elm_write_reg(info, offset, val);
++				offset += 4;
++				val = cpu_to_be32(*(u32 *) &ecc[0]) >> 16;
++				elm_write_reg(info, offset, val);
++				break;
++			default:
++				pr_err("invalid config bch_type\n");
++			}
++		}
++
++		/* Update ecc pointer with ecc byte size */
++		ecc += info->ecc_syndrome_size;
++	}
++}
++
++/**
++ * elm_start_processing - start elm syndrome processing
++ * @info:	elm info
++ * @err_vec:	elm error vectors
++ *
++ * Set syndrome valid bit for syndrome fragment registers for which
++ * elm syndrome fragment registers are loaded. This enables elm module
++ * to start processing syndrome vectors.
++ */
++static void elm_start_processing(struct elm_info *info,
++		struct elm_errorvec *err_vec)
++{
++	int i, offset;
++	u32 reg_val;
++
++	/*
++	 * Set syndrome vector valid, so that ELM module
++	 * will process it for vectors error is reported
++	 */
++	for (i = 0; i < info->ecc_steps; i++) {
++		if (err_vec[i].error_reported) {
++			offset = ELM_SYNDROME_FRAGMENT_6 +
++				SYNDROME_FRAGMENT_REG_SIZE * i;
++			reg_val = elm_read_reg(info, offset);
++			reg_val |= ELM_SYNDROME_VALID;
++			elm_write_reg(info, offset, reg_val);
++		}
++	}
++}
++
++/**
++ * elm_error_correction - locate correctable error position
++ * @info:	elm info
++ * @err_vec:	elm error vectors
++ *
++ * On completion of processing by elm module, error location status
++ * register updated with correctable/uncorrectable error information.
++ * In case of correctable errors, number of errors located from
++ * elm location status register & read the positions from
++ * elm error location register.
++ */
++static void elm_error_correction(struct elm_info *info,
++		struct elm_errorvec *err_vec)
++{
++	int i, j, errors = 0;
++	int offset;
++	u32 reg_val;
++
++	for (i = 0; i < info->ecc_steps; i++) {
++
++		/* Check error reported */
++		if (err_vec[i].error_reported) {
++			offset = ELM_LOCATION_STATUS + ERROR_LOCATION_SIZE * i;
++			reg_val = elm_read_reg(info, offset);
++
++			/* Check correctable error or not */
++			if (reg_val & ECC_CORRECTABLE_MASK) {
++				offset = ELM_ERROR_LOCATION_0 +
++					ERROR_LOCATION_SIZE * i;
++
++				/* Read count of correctable errors */
++				err_vec[i].error_count = reg_val &
++					ECC_NB_ERRORS_MASK;
++
++				/* Update the error locations in error vector */
++				for (j = 0; j < err_vec[i].error_count; j++) {
++
++					reg_val = elm_read_reg(info, offset);
++					err_vec[i].error_loc[j] = reg_val &
++						ECC_ERROR_LOCATION_MASK;
++
++					/* Update error location register */
++					offset += 4;
++				}
++
++				errors += err_vec[i].error_count;
++			} else {
++				err_vec[i].error_uncorrectable = true;
++			}
++
++			/* Clearing interrupts for processed error vectors */
++			elm_write_reg(info, ELM_IRQSTATUS, BIT(i));
++
++			/* Disable page mode */
++			elm_configure_page_mode(info, i, false);
++		}
++	}
++}
++
++/**
++ * elm_decode_bch_error_page - Locate error position
++ * @dev:	device pointer
++ * @ecc_calc:	calculated ECC bytes from GPMC
++ * @err_vec:	elm error vectors
++ *
++ * Called with one or more error reported vectors & vectors with
++ * error reported is updated in err_vec[].error_reported
++ */
++void elm_decode_bch_error_page(struct device *dev, u8 *ecc_calc,
++		struct elm_errorvec *err_vec)
++{
++	struct elm_info *info = dev_get_drvdata(dev);
++	u32 reg_val;
++
++	/* Enable page mode interrupt */
++	reg_val = elm_read_reg(info, ELM_IRQSTATUS);
++	elm_write_reg(info, ELM_IRQSTATUS, reg_val & INTR_STATUS_PAGE_VALID);
++	elm_write_reg(info, ELM_IRQENABLE, INTR_EN_PAGE_MASK);
++
++	/* Load valid ecc byte to syndrome fragment register */
++	elm_load_syndrome(info, err_vec, ecc_calc);
++
++	/* Enable syndrome processing for which syndrome fragment is updated */
++	elm_start_processing(info, err_vec);
++
++	/* Wait for ELM module to finish locating error correction */
++	wait_for_completion(&info->elm_completion);
++
++	/* Disable page mode interrupt */
++	reg_val = elm_read_reg(info, ELM_IRQENABLE);
++	elm_write_reg(info, ELM_IRQENABLE, reg_val & ~INTR_EN_PAGE_MASK);
++	elm_error_correction(info, err_vec);
++}
++EXPORT_SYMBOL(elm_decode_bch_error_page);
++
++static irqreturn_t elm_isr(int this_irq, void *dev_id)
++{
++	u32 reg_val;
++	struct elm_info *info = dev_id;
++
++	reg_val = elm_read_reg(info, ELM_IRQSTATUS);
++
++	/* All error vectors processed */
++	if (reg_val & INTR_STATUS_PAGE_VALID) {
++		elm_write_reg(info, ELM_IRQSTATUS,
++				reg_val & INTR_STATUS_PAGE_VALID);
++		complete(&info->elm_completion);
++		return IRQ_HANDLED;
++	}
++
++	return IRQ_NONE;
++}
++
++static int elm_probe(struct platform_device *pdev)
++{
++	int ret = 0;
++	struct resource *res, *irq;
++	struct elm_info *info;
++
++	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
++	if (!info)
++		return -ENOMEM;
++
++	info->dev = &pdev->dev;
++
++	irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
++	if (!irq) {
++		dev_err(&pdev->dev, "no irq resource defined\n");
++		return -ENODEV;
++	}
++
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	info->elm_base = devm_ioremap_resource(&pdev->dev, res);
++	if (IS_ERR(info->elm_base))
++		return PTR_ERR(info->elm_base);
++
++	ret = devm_request_irq(&pdev->dev, irq->start, elm_isr, 0,
++			pdev->name, info);
++	if (ret) {
++		dev_err(&pdev->dev, "failure requesting %pr\n", irq);
++		return ret;
++	}
++
++	pm_runtime_enable(&pdev->dev);
++	if (pm_runtime_get_sync(&pdev->dev) < 0) {
++		ret = -EINVAL;
++		pm_runtime_disable(&pdev->dev);
++		dev_err(&pdev->dev, "can't enable clock\n");
++		return ret;
++	}
++
++	init_completion(&info->elm_completion);
++	INIT_LIST_HEAD(&info->list);
++	list_add(&info->list, &elm_devices);
++	platform_set_drvdata(pdev, info);
++	return ret;
++}
++
++static int elm_remove(struct platform_device *pdev)
++{
++	pm_runtime_put_sync(&pdev->dev);
++	pm_runtime_disable(&pdev->dev);
++	return 0;
++}
++
++#ifdef CONFIG_PM_SLEEP
++/**
++ * elm_context_save
++ * saves ELM configurations to preserve them across Hardware powered-down
++ */
++static int elm_context_save(struct elm_info *info)
++{
++	struct elm_registers *regs = &info->elm_regs;
++	enum bch_ecc bch_type = info->bch_type;
++	u32 offset = 0, i;
++
++	regs->elm_irqenable       = elm_read_reg(info, ELM_IRQENABLE);
++	regs->elm_sysconfig       = elm_read_reg(info, ELM_SYSCONFIG);
++	regs->elm_location_config = elm_read_reg(info, ELM_LOCATION_CONFIG);
++	regs->elm_page_ctrl       = elm_read_reg(info, ELM_PAGE_CTRL);
++	for (i = 0; i < ERROR_VECTOR_MAX; i++) {
++		offset = i * SYNDROME_FRAGMENT_REG_SIZE;
++		switch (bch_type) {
++		case BCH16_ECC:
++			regs->elm_syndrome_fragment_6[i] = elm_read_reg(info,
++					ELM_SYNDROME_FRAGMENT_6 + offset);
++			regs->elm_syndrome_fragment_5[i] = elm_read_reg(info,
++					ELM_SYNDROME_FRAGMENT_5 + offset);
++			regs->elm_syndrome_fragment_4[i] = elm_read_reg(info,
++					ELM_SYNDROME_FRAGMENT_4 + offset);
++		case BCH8_ECC:
++			regs->elm_syndrome_fragment_3[i] = elm_read_reg(info,
++					ELM_SYNDROME_FRAGMENT_3 + offset);
++			regs->elm_syndrome_fragment_2[i] = elm_read_reg(info,
++					ELM_SYNDROME_FRAGMENT_2 + offset);
++		case BCH4_ECC:
++			regs->elm_syndrome_fragment_1[i] = elm_read_reg(info,
++					ELM_SYNDROME_FRAGMENT_1 + offset);
++			regs->elm_syndrome_fragment_0[i] = elm_read_reg(info,
++					ELM_SYNDROME_FRAGMENT_0 + offset);
++			break;
++		default:
++			return -EINVAL;
++		}
++		/* ELM SYNDROME_VALID bit in SYNDROME_FRAGMENT_6[] needs
++		 * to be saved for all BCH schemes*/
++		regs->elm_syndrome_fragment_6[i] = elm_read_reg(info,
++					ELM_SYNDROME_FRAGMENT_6 + offset);
++	}
++	return 0;
++}
++
++/**
++ * elm_context_restore
++ * writes configurations saved duing power-down back into ELM registers
++ */
++static int elm_context_restore(struct elm_info *info)
++{
++	struct elm_registers *regs = &info->elm_regs;
++	enum bch_ecc bch_type = info->bch_type;
++	u32 offset = 0, i;
++
++	elm_write_reg(info, ELM_IRQENABLE,	 regs->elm_irqenable);
++	elm_write_reg(info, ELM_SYSCONFIG,	 regs->elm_sysconfig);
++	elm_write_reg(info, ELM_LOCATION_CONFIG, regs->elm_location_config);
++	elm_write_reg(info, ELM_PAGE_CTRL,	 regs->elm_page_ctrl);
++	for (i = 0; i < ERROR_VECTOR_MAX; i++) {
++		offset = i * SYNDROME_FRAGMENT_REG_SIZE;
++		switch (bch_type) {
++		case BCH16_ECC:
++			elm_write_reg(info, ELM_SYNDROME_FRAGMENT_6 + offset,
++					regs->elm_syndrome_fragment_6[i]);
++			elm_write_reg(info, ELM_SYNDROME_FRAGMENT_5 + offset,
++					regs->elm_syndrome_fragment_5[i]);
++			elm_write_reg(info, ELM_SYNDROME_FRAGMENT_4 + offset,
++					regs->elm_syndrome_fragment_4[i]);
++		case BCH8_ECC:
++			elm_write_reg(info, ELM_SYNDROME_FRAGMENT_3 + offset,
++					regs->elm_syndrome_fragment_3[i]);
++			elm_write_reg(info, ELM_SYNDROME_FRAGMENT_2 + offset,
++					regs->elm_syndrome_fragment_2[i]);
++		case BCH4_ECC:
++			elm_write_reg(info, ELM_SYNDROME_FRAGMENT_1 + offset,
++					regs->elm_syndrome_fragment_1[i]);
++			elm_write_reg(info, ELM_SYNDROME_FRAGMENT_0 + offset,
++					regs->elm_syndrome_fragment_0[i]);
++			break;
++		default:
++			return -EINVAL;
++		}
++		/* ELM_SYNDROME_VALID bit to be set in last to trigger FSM */
++		elm_write_reg(info, ELM_SYNDROME_FRAGMENT_6 + offset,
++					regs->elm_syndrome_fragment_6[i] &
++							 ELM_SYNDROME_VALID);
++	}
++	return 0;
++}
++
++static int elm_suspend(struct device *dev)
++{
++	struct elm_info *info = dev_get_drvdata(dev);
++	elm_context_save(info);
++	pm_runtime_put_sync(dev);
++	return 0;
++}
++
++static int elm_resume(struct device *dev)
++{
++	struct elm_info *info = dev_get_drvdata(dev);
++	pm_runtime_get_sync(dev);
++	elm_context_restore(info);
++	return 0;
++}
++#endif
++
++static SIMPLE_DEV_PM_OPS(elm_pm_ops, elm_suspend, elm_resume);
++
++#ifdef CONFIG_OF
++static const struct of_device_id elm_of_match[] = {
++	{ .compatible = "ti,am3352-elm" },
++	{},
++};
++MODULE_DEVICE_TABLE(of, elm_of_match);
++#endif
++
++static struct platform_driver elm_driver = {
++	.driver	= {
++		.name	= DRIVER_NAME,
++		.of_match_table = of_match_ptr(elm_of_match),
++		.pm	= &elm_pm_ops,
++	},
++	.probe	= elm_probe,
++	.remove	= elm_remove,
++};
++
++module_platform_driver(elm_driver);
++
++MODULE_DESCRIPTION("ELM driver for BCH error correction");
++MODULE_AUTHOR("Texas Instruments");
++MODULE_ALIAS("platform:" DRIVER_NAME);
++MODULE_LICENSE("GPL v2");
+diff --git a/drivers/mtd/nand/raw/orion_nand.c b/drivers/mtd/nand/raw/orion_nand.c
+new file mode 100644
+index 0000000..5a5aa1f
+--- /dev/null
++++ b/drivers/mtd/nand/raw/orion_nand.c
+@@ -0,0 +1,234 @@
++/*
++ * drivers/mtd/nand/orion_nand.c
++ *
++ * NAND support for Marvell Orion SoC platforms
++ *
++ * Tzachi Perelstein <tzachi@marvell.com>
++ *
++ * This file is licensed under  the terms of the GNU General Public
++ * License version 2. This program is licensed "as is" without any
++ * warranty of any kind, whether express or implied.
++ */
++
++#include <linux/slab.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/of.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/rawnand.h>
++#include <linux/mtd/partitions.h>
++#include <linux/clk.h>
++#include <linux/err.h>
++#include <linux/io.h>
++#include <asm/sizes.h>
++#include <linux/platform_data/mtd-orion_nand.h>
++
++struct orion_nand_info {
++	struct nand_chip chip;
++	struct clk *clk;
++};
++
++static void orion_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
++{
++	struct nand_chip *nc = mtd_to_nand(mtd);
++	struct orion_nand_data *board = nand_get_controller_data(nc);
++	u32 offs;
++
++	if (cmd == NAND_CMD_NONE)
++		return;
++
++	if (ctrl & NAND_CLE)
++		offs = (1 << board->cle);
++	else if (ctrl & NAND_ALE)
++		offs = (1 << board->ale);
++	else
++		return;
++
++	if (nc->options & NAND_BUSWIDTH_16)
++		offs <<= 1;
++
++	writeb(cmd, nc->IO_ADDR_W + offs);
++}
++
++static void orion_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	void __iomem *io_base = chip->IO_ADDR_R;
++#if __LINUX_ARM_ARCH__ >= 5
++	uint64_t *buf64;
++#endif
++	int i = 0;
++
++	while (len && (unsigned long)buf & 7) {
++		*buf++ = readb(io_base);
++		len--;
++	}
++#if __LINUX_ARM_ARCH__ >= 5
++	buf64 = (uint64_t *)buf;
++	while (i < len/8) {
++		/*
++		 * Since GCC has no proper constraint (PR 43518)
++		 * force x variable to r2/r3 registers as ldrd instruction
++		 * requires first register to be even.
++		 */
++		register uint64_t x asm ("r2");
++
++		asm volatile ("ldrd\t%0, [%1]" : "=&r" (x) : "r" (io_base));
++		buf64[i++] = x;
++	}
++	i *= 8;
++#else
++	readsl(io_base, buf, len/4);
++	i = len / 4 * 4;
++#endif
++	while (i < len)
++		buf[i++] = readb(io_base);
++}
++
++static int __init orion_nand_probe(struct platform_device *pdev)
++{
++	struct orion_nand_info *info;
++	struct mtd_info *mtd;
++	struct nand_chip *nc;
++	struct orion_nand_data *board;
++	struct resource *res;
++	void __iomem *io_base;
++	int ret = 0;
++	u32 val = 0;
++
++	info = devm_kzalloc(&pdev->dev,
++			sizeof(struct orion_nand_info),
++			GFP_KERNEL);
++	if (!info)
++		return -ENOMEM;
++	nc = &info->chip;
++	mtd = nand_to_mtd(nc);
++
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	io_base = devm_ioremap_resource(&pdev->dev, res);
++
++	if (IS_ERR(io_base))
++		return PTR_ERR(io_base);
++
++	if (pdev->dev.of_node) {
++		board = devm_kzalloc(&pdev->dev, sizeof(struct orion_nand_data),
++					GFP_KERNEL);
++		if (!board)
++			return -ENOMEM;
++		if (!of_property_read_u32(pdev->dev.of_node, "cle", &val))
++			board->cle = (u8)val;
++		else
++			board->cle = 0;
++		if (!of_property_read_u32(pdev->dev.of_node, "ale", &val))
++			board->ale = (u8)val;
++		else
++			board->ale = 1;
++		if (!of_property_read_u32(pdev->dev.of_node,
++						"bank-width", &val))
++			board->width = (u8)val * 8;
++		else
++			board->width = 8;
++		if (!of_property_read_u32(pdev->dev.of_node,
++						"chip-delay", &val))
++			board->chip_delay = (u8)val;
++	} else {
++		board = dev_get_platdata(&pdev->dev);
++	}
++
++	mtd->dev.parent = &pdev->dev;
++
++	nand_set_controller_data(nc, board);
++	nand_set_flash_node(nc, pdev->dev.of_node);
++	nc->IO_ADDR_R = nc->IO_ADDR_W = io_base;
++	nc->cmd_ctrl = orion_nand_cmd_ctrl;
++	nc->read_buf = orion_nand_read_buf;
++	nc->ecc.mode = NAND_ECC_SOFT;
++	nc->ecc.algo = NAND_ECC_HAMMING;
++
++	if (board->chip_delay)
++		nc->chip_delay = board->chip_delay;
++
++	WARN(board->width > 16,
++		"%d bit bus width out of range",
++		board->width);
++
++	if (board->width == 16)
++		nc->options |= NAND_BUSWIDTH_16;
++
++	if (board->dev_ready)
++		nc->dev_ready = board->dev_ready;
++
++	platform_set_drvdata(pdev, info);
++
++	/* Not all platforms can gate the clock, so it is not
++	   an error if the clock does not exists. */
++	info->clk = devm_clk_get(&pdev->dev, NULL);
++	if (IS_ERR(info->clk)) {
++		ret = PTR_ERR(info->clk);
++		if (ret == -ENOENT) {
++			info->clk = NULL;
++		} else {
++			dev_err(&pdev->dev, "failed to get clock!\n");
++			return ret;
++		}
++	}
++
++	ret = clk_prepare_enable(info->clk);
++	if (ret) {
++		dev_err(&pdev->dev, "failed to prepare clock!\n");
++		return ret;
++	}
++
++	ret = nand_scan(mtd, 1);
++	if (ret)
++		goto no_dev;
++
++	mtd->name = "orion_nand";
++	ret = mtd_device_register(mtd, board->parts, board->nr_parts);
++	if (ret) {
++		nand_release(mtd);
++		goto no_dev;
++	}
++
++	return 0;
++
++no_dev:
++	clk_disable_unprepare(info->clk);
++	return ret;
++}
++
++static int orion_nand_remove(struct platform_device *pdev)
++{
++	struct orion_nand_info *info = platform_get_drvdata(pdev);
++	struct nand_chip *chip = &info->chip;
++	struct mtd_info *mtd = nand_to_mtd(chip);
++
++	nand_release(mtd);
++
++	clk_disable_unprepare(info->clk);
++
++	return 0;
++}
++
++#ifdef CONFIG_OF
++static const struct of_device_id orion_nand_of_match_table[] = {
++	{ .compatible = "marvell,orion-nand", },
++	{},
++};
++MODULE_DEVICE_TABLE(of, orion_nand_of_match_table);
++#endif
++
++static struct platform_driver orion_nand_driver = {
++	.remove		= orion_nand_remove,
++	.driver		= {
++		.name	= "orion_nand",
++		.of_match_table = of_match_ptr(orion_nand_of_match_table),
++	},
++};
++
++module_platform_driver_probe(orion_nand_driver, orion_nand_probe);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Tzachi Perelstein");
++MODULE_DESCRIPTION("NAND glue for Orion platforms");
++MODULE_ALIAS("platform:orion_nand");
+diff --git a/drivers/mtd/nand/raw/oxnas_nand.c b/drivers/mtd/nand/raw/oxnas_nand.c
+new file mode 100644
+index 0000000..d649d59
+--- /dev/null
++++ b/drivers/mtd/nand/raw/oxnas_nand.c
+@@ -0,0 +1,206 @@
++/*
++ * Oxford Semiconductor OXNAS NAND driver
++
++ * Copyright (C) 2016 Neil Armstrong <narmstrong@baylibre.com>
++ * Heavily based on plat_nand.c :
++ * Author: Vitaly Wool <vitalywool@gmail.com>
++ * Copyright (C) 2013 Ma Haijun <mahaijuns@gmail.com>
++ * Copyright (C) 2012 John Crispin <blogic@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/rawnand.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, u8 *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 u8 *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(*oxnas),
++			     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;
++
++	err = clk_prepare_enable(oxnas->clk);
++	if (err)
++		return err;
++
++	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) {
++			err = -ENOMEM;
++			goto err_clk_unprepare;
++		}
++
++		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)
++			goto err_clk_unprepare;
++
++		err = mtd_device_register(mtd, NULL, 0);
++		if (err) {
++			nand_release(mtd);
++			goto err_clk_unprepare;
++		}
++
++		oxnas->chips[nchips] = chip;
++		++nchips;
++	}
++
++	/* Exit if no chips found */
++	if (!nchips) {
++		err = -ENODEV;
++		goto err_clk_unprepare;
++	}
++
++	platform_set_drvdata(pdev, oxnas);
++
++	return 0;
++
++err_clk_unprepare:
++	clk_disable_unprepare(oxnas->clk);
++	return err;
++}
++
++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@baylibre.com>");
++MODULE_DESCRIPTION("Oxnas NAND driver");
++MODULE_ALIAS("platform:oxnas_nand");
+diff --git a/drivers/mtd/nand/raw/pasemi_nand.c b/drivers/mtd/nand/raw/pasemi_nand.c
+new file mode 100644
+index 0000000..a47a7e4
+--- /dev/null
++++ b/drivers/mtd/nand/raw/pasemi_nand.c
+@@ -0,0 +1,232 @@
++/*
++ * Copyright (C) 2006-2007 PA Semi, Inc
++ *
++ * Author: Egor Martovetsky <egor@pasemi.com>
++ * Maintained by: Olof Johansson <olof@lixom.net>
++ *
++ * Driver for the PWRficient onchip NAND flash interface
++ *
++ * 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.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
++ */
++
++#undef DEBUG
++
++#include <linux/slab.h>
++#include <linux/module.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/rawnand.h>
++#include <linux/mtd/nand_ecc.h>
++#include <linux/of_address.h>
++#include <linux/of_irq.h>
++#include <linux/of_platform.h>
++#include <linux/platform_device.h>
++#include <linux/pci.h>
++
++#include <asm/io.h>
++
++#define LBICTRL_LPCCTL_NR		0x00004000
++#define CLE_PIN_CTL			15
++#define ALE_PIN_CTL			14
++
++static unsigned int lpcctl;
++static struct mtd_info *pasemi_nand_mtd;
++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);
++
++	while (len > 0x800) {
++		memcpy_fromio(buf, chip->IO_ADDR_R, 0x800);
++		buf += 0x800;
++		len -= 0x800;
++	}
++	memcpy_fromio(buf, chip->IO_ADDR_R, len);
++}
++
++static void pasemi_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++
++	while (len > 0x800) {
++		memcpy_toio(chip->IO_ADDR_R, buf, 0x800);
++		buf += 0x800;
++		len -= 0x800;
++	}
++	memcpy_toio(chip->IO_ADDR_R, buf, len);
++}
++
++static void pasemi_hwcontrol(struct mtd_info *mtd, int cmd,
++			     unsigned int ctrl)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++
++	if (cmd == NAND_CMD_NONE)
++		return;
++
++	if (ctrl & NAND_CLE)
++		out_8(chip->IO_ADDR_W + (1 << CLE_PIN_CTL), cmd);
++	else
++		out_8(chip->IO_ADDR_W + (1 << ALE_PIN_CTL), cmd);
++
++	/* Push out posted writes */
++	eieio();
++	inl(lpcctl);
++}
++
++int pasemi_device_ready(struct mtd_info *mtd)
++{
++	return !!(inl(lpcctl) & LBICTRL_LPCCTL_NR);
++}
++
++static int pasemi_nand_probe(struct platform_device *ofdev)
++{
++	struct device *dev = &ofdev->dev;
++	struct pci_dev *pdev;
++	struct device_node *np = dev->of_node;
++	struct resource res;
++	struct nand_chip *chip;
++	int err = 0;
++
++	err = of_address_to_resource(np, 0, &res);
++
++	if (err)
++		return -EINVAL;
++
++	/* We only support one device at the moment */
++	if (pasemi_nand_mtd)
++		return -ENODEV;
++
++	dev_dbg(dev, "pasemi_nand at %pR\n", &res);
++
++	/* Allocate memory for MTD device structure and private data */
++	chip = kzalloc(sizeof(struct nand_chip), GFP_KERNEL);
++	if (!chip) {
++		err = -ENOMEM;
++		goto out;
++	}
++
++	pasemi_nand_mtd = nand_to_mtd(chip);
++
++	/* Link the private data with the MTD structure */
++	pasemi_nand_mtd->dev.parent = dev;
++
++	chip->IO_ADDR_R = of_iomap(np, 0);
++	chip->IO_ADDR_W = chip->IO_ADDR_R;
++
++	if (!chip->IO_ADDR_R) {
++		err = -EIO;
++		goto out_mtd;
++	}
++
++	pdev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa008, NULL);
++	if (!pdev) {
++		err = -ENODEV;
++		goto out_ior;
++	}
++
++	lpcctl = pci_resource_start(pdev, 0);
++	pci_dev_put(pdev);
++
++	if (!request_region(lpcctl, 4, driver_name)) {
++		err = -EBUSY;
++		goto out_ior;
++	}
++
++	chip->cmd_ctrl = pasemi_hwcontrol;
++	chip->dev_ready = pasemi_device_ready;
++	chip->read_buf = pasemi_read_buf;
++	chip->write_buf = pasemi_write_buf;
++	chip->chip_delay = 0;
++	chip->ecc.mode = NAND_ECC_SOFT;
++	chip->ecc.algo = NAND_ECC_HAMMING;
++
++	/* Enable the following for a flash based bad block table */
++	chip->bbt_options = NAND_BBT_USE_FLASH;
++
++	/* Scan to find existence of the device */
++	err = nand_scan(pasemi_nand_mtd, 1);
++	if (err)
++		goto out_lpc;
++
++	if (mtd_device_register(pasemi_nand_mtd, NULL, 0)) {
++		dev_err(dev, "Unable to register MTD device\n");
++		err = -ENODEV;
++		goto out_lpc;
++	}
++
++	dev_info(dev, "PA Semi NAND flash at %pR, control at I/O %x\n", &res,
++		 lpcctl);
++
++	return 0;
++
++ out_lpc:
++	release_region(lpcctl, 4);
++ out_ior:
++	iounmap(chip->IO_ADDR_R);
++ out_mtd:
++	kfree(chip);
++ out:
++	return err;
++}
++
++static int pasemi_nand_remove(struct platform_device *ofdev)
++{
++	struct nand_chip *chip;
++
++	if (!pasemi_nand_mtd)
++		return 0;
++
++	chip = mtd_to_nand(pasemi_nand_mtd);
++
++	/* Release resources, unregister device */
++	nand_release(pasemi_nand_mtd);
++
++	release_region(lpcctl, 4);
++
++	iounmap(chip->IO_ADDR_R);
++
++	/* Free the MTD device structure */
++	kfree(chip);
++
++	pasemi_nand_mtd = NULL;
++
++	return 0;
++}
++
++static const struct of_device_id pasemi_nand_match[] =
++{
++	{
++		.compatible   = "pasemi,localbus-nand",
++	},
++	{},
++};
++
++MODULE_DEVICE_TABLE(of, pasemi_nand_match);
++
++static struct platform_driver pasemi_nand_driver =
++{
++	.driver = {
++		.name = driver_name,
++		.of_match_table = pasemi_nand_match,
++	},
++	.probe		= pasemi_nand_probe,
++	.remove		= pasemi_nand_remove,
++};
++
++module_platform_driver(pasemi_nand_driver);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Egor Martovetsky <egor@pasemi.com>");
++MODULE_DESCRIPTION("NAND flash interface driver for PA Semi PWRficient");
+diff --git a/drivers/mtd/nand/raw/plat_nand.c b/drivers/mtd/nand/raw/plat_nand.c
+new file mode 100644
+index 0000000..925a132
+--- /dev/null
++++ b/drivers/mtd/nand/raw/plat_nand.c
+@@ -0,0 +1,144 @@
++/*
++ * Generic NAND driver
++ *
++ * Author: Vitaly Wool <vitalywool@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/mtd/mtd.h>
++#include <linux/mtd/rawnand.h>
++#include <linux/mtd/partitions.h>
++
++struct plat_nand_data {
++	struct nand_chip	chip;
++	void __iomem		*io_base;
++};
++
++/*
++ * Probe for the NAND device.
++ */
++static int plat_nand_probe(struct platform_device *pdev)
++{
++	struct platform_nand_data *pdata = dev_get_platdata(&pdev->dev);
++	struct plat_nand_data *data;
++	struct mtd_info *mtd;
++	struct resource *res;
++	const char **part_types;
++	int err = 0;
++
++	if (!pdata) {
++		dev_err(&pdev->dev, "platform_nand_data is missing\n");
++		return -EINVAL;
++	}
++
++	if (pdata->chip.nr_chips < 1) {
++		dev_err(&pdev->dev, "invalid number of chips specified\n");
++		return -EINVAL;
++	}
++
++	/* Allocate memory for the device structure (and zero it) */
++	data = devm_kzalloc(&pdev->dev, sizeof(struct plat_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);
++
++	nand_set_flash_node(&data->chip, pdev->dev.of_node);
++	mtd = nand_to_mtd(&data->chip);
++	mtd->dev.parent = &pdev->dev;
++
++	data->chip.IO_ADDR_R = data->io_base;
++	data->chip.IO_ADDR_W = data->io_base;
++	data->chip.cmd_ctrl = pdata->ctrl.cmd_ctrl;
++	data->chip.dev_ready = pdata->ctrl.dev_ready;
++	data->chip.select_chip = pdata->ctrl.select_chip;
++	data->chip.write_buf = pdata->ctrl.write_buf;
++	data->chip.read_buf = pdata->ctrl.read_buf;
++	data->chip.read_byte = pdata->ctrl.read_byte;
++	data->chip.chip_delay = pdata->chip.chip_delay;
++	data->chip.options |= pdata->chip.options;
++	data->chip.bbt_options |= pdata->chip.bbt_options;
++
++	data->chip.ecc.hwctl = pdata->ctrl.hwcontrol;
++	data->chip.ecc.mode = NAND_ECC_SOFT;
++	data->chip.ecc.algo = NAND_ECC_HAMMING;
++
++	platform_set_drvdata(pdev, data);
++
++	/* Handle any platform specific setup */
++	if (pdata->ctrl.probe) {
++		err = pdata->ctrl.probe(pdev);
++		if (err)
++			goto out;
++	}
++
++	/* Scan to find existence of the device */
++	err = nand_scan(mtd, pdata->chip.nr_chips);
++	if (err)
++		goto out;
++
++	part_types = pdata->chip.part_probe_types;
++
++	err = mtd_device_parse_register(mtd, part_types, NULL,
++					pdata->chip.partitions,
++					pdata->chip.nr_partitions);
++
++	if (!err)
++		return err;
++
++	nand_release(mtd);
++out:
++	if (pdata->ctrl.remove)
++		pdata->ctrl.remove(pdev);
++	return err;
++}
++
++/*
++ * Remove a NAND device.
++ */
++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));
++	if (pdata->ctrl.remove)
++		pdata->ctrl.remove(pdev);
++
++	return 0;
++}
++
++static const struct of_device_id plat_nand_match[] = {
++	{ .compatible = "gen_nand" },
++	{},
++};
++MODULE_DEVICE_TABLE(of, plat_nand_match);
++
++static struct platform_driver plat_nand_driver = {
++	.probe	= plat_nand_probe,
++	.remove	= plat_nand_remove,
++	.driver	= {
++		.name		= "gen_nand",
++		.of_match_table = plat_nand_match,
++	},
++};
++
++module_platform_driver(plat_nand_driver);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Vitaly Wool");
++MODULE_DESCRIPTION("Simple generic NAND driver");
++MODULE_ALIAS("platform:gen_nand");
+diff --git a/drivers/mtd/nand/raw/pxa3xx_nand.c b/drivers/mtd/nand/raw/pxa3xx_nand.c
+new file mode 100644
+index 0000000..125b744
+--- /dev/null
++++ b/drivers/mtd/nand/raw/pxa3xx_nand.c
+@@ -0,0 +1,2074 @@
++/*
++ * drivers/mtd/nand/pxa3xx_nand.c
++ *
++ * Copyright © 2005 Intel Corporation
++ * Copyright © 2006 Marvell International Ltd.
++ *
++ * 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.
++ *
++ * See Documentation/mtd/nand/pxa3xx-nand.txt for more details.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/interrupt.h>
++#include <linux/platform_device.h>
++#include <linux/dmaengine.h>
++#include <linux/dma-mapping.h>
++#include <linux/dma/pxa-dma.h>
++#include <linux/delay.h>
++#include <linux/clk.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/rawnand.h>
++#include <linux/mtd/partitions.h>
++#include <linux/io.h>
++#include <linux/iopoll.h>
++#include <linux/irq.h>
++#include <linux/slab.h>
++#include <linux/of.h>
++#include <linux/of_device.h>
++#include <linux/platform_data/mtd-nand-pxa3xx.h>
++
++#define	CHIP_DELAY_TIMEOUT	msecs_to_jiffies(200)
++#define NAND_STOP_DELAY		msecs_to_jiffies(40)
++#define PAGE_CHUNK_SIZE		(2048)
++
++/*
++ * Define a buffer size for the initial command that detects the flash device:
++ * STATUS, READID and PARAM.
++ * ONFI param page is 256 bytes, and there are three redundant copies
++ * to be read. JEDEC param page is 512 bytes, and there are also three
++ * redundant copies to be read.
++ * Hence this buffer should be at least 512 x 3. Let's pick 2048.
++ */
++#define INIT_BUFFER_SIZE	2048
++
++/* registers and bit definitions */
++#define NDCR		(0x00) /* Control register */
++#define NDTR0CS0	(0x04) /* Timing Parameter 0 for CS0 */
++#define NDTR1CS0	(0x0C) /* Timing Parameter 1 for CS0 */
++#define NDSR		(0x14) /* Status Register */
++#define NDPCR		(0x18) /* Page Count Register */
++#define NDBDR0		(0x1C) /* Bad Block Register 0 */
++#define NDBDR1		(0x20) /* Bad Block Register 1 */
++#define NDECCCTRL	(0x28) /* ECC control */
++#define NDDB		(0x40) /* Data Buffer */
++#define NDCB0		(0x48) /* Command Buffer0 */
++#define NDCB1		(0x4C) /* Command Buffer1 */
++#define NDCB2		(0x50) /* Command Buffer2 */
++
++#define NDCR_SPARE_EN		(0x1 << 31)
++#define NDCR_ECC_EN		(0x1 << 30)
++#define NDCR_DMA_EN		(0x1 << 29)
++#define NDCR_ND_RUN		(0x1 << 28)
++#define NDCR_DWIDTH_C		(0x1 << 27)
++#define NDCR_DWIDTH_M		(0x1 << 26)
++#define NDCR_PAGE_SZ		(0x1 << 24)
++#define NDCR_NCSX		(0x1 << 23)
++#define NDCR_ND_MODE		(0x3 << 21)
++#define NDCR_NAND_MODE   	(0x0)
++#define NDCR_CLR_PG_CNT		(0x1 << 20)
++#define NFCV1_NDCR_ARB_CNTL	(0x1 << 19)
++#define NFCV2_NDCR_STOP_ON_UNCOR	(0x1 << 19)
++#define NDCR_RD_ID_CNT_MASK	(0x7 << 16)
++#define NDCR_RD_ID_CNT(x)	(((x) << 16) & NDCR_RD_ID_CNT_MASK)
++
++#define NDCR_RA_START		(0x1 << 15)
++#define NDCR_PG_PER_BLK		(0x1 << 14)
++#define NDCR_ND_ARB_EN		(0x1 << 12)
++#define NDCR_INT_MASK           (0xFFF)
++
++#define NDSR_MASK		(0xfff)
++#define NDSR_ERR_CNT_OFF	(16)
++#define NDSR_ERR_CNT_MASK       (0x1f)
++#define NDSR_ERR_CNT(sr)	((sr >> NDSR_ERR_CNT_OFF) & NDSR_ERR_CNT_MASK)
++#define NDSR_RDY                (0x1 << 12)
++#define NDSR_FLASH_RDY          (0x1 << 11)
++#define NDSR_CS0_PAGED		(0x1 << 10)
++#define NDSR_CS1_PAGED		(0x1 << 9)
++#define NDSR_CS0_CMDD		(0x1 << 8)
++#define NDSR_CS1_CMDD		(0x1 << 7)
++#define NDSR_CS0_BBD		(0x1 << 6)
++#define NDSR_CS1_BBD		(0x1 << 5)
++#define NDSR_UNCORERR		(0x1 << 4)
++#define NDSR_CORERR		(0x1 << 3)
++#define NDSR_WRDREQ		(0x1 << 2)
++#define NDSR_RDDREQ		(0x1 << 1)
++#define NDSR_WRCMDREQ		(0x1)
++
++#define NDCB0_LEN_OVRD		(0x1 << 28)
++#define NDCB0_ST_ROW_EN         (0x1 << 26)
++#define NDCB0_AUTO_RS		(0x1 << 25)
++#define NDCB0_CSEL		(0x1 << 24)
++#define NDCB0_EXT_CMD_TYPE_MASK	(0x7 << 29)
++#define NDCB0_EXT_CMD_TYPE(x)	(((x) << 29) & NDCB0_EXT_CMD_TYPE_MASK)
++#define NDCB0_CMD_TYPE_MASK	(0x7 << 21)
++#define NDCB0_CMD_TYPE(x)	(((x) << 21) & NDCB0_CMD_TYPE_MASK)
++#define NDCB0_NC		(0x1 << 20)
++#define NDCB0_DBC		(0x1 << 19)
++#define NDCB0_ADDR_CYC_MASK	(0x7 << 16)
++#define NDCB0_ADDR_CYC(x)	(((x) << 16) & NDCB0_ADDR_CYC_MASK)
++#define NDCB0_CMD2_MASK		(0xff << 8)
++#define NDCB0_CMD1_MASK		(0xff)
++#define NDCB0_ADDR_CYC_SHIFT	(16)
++
++#define EXT_CMD_TYPE_DISPATCH	6 /* Command dispatch */
++#define EXT_CMD_TYPE_NAKED_RW	5 /* Naked read or Naked write */
++#define EXT_CMD_TYPE_READ	4 /* Read */
++#define EXT_CMD_TYPE_DISP_WR	4 /* Command dispatch with write */
++#define EXT_CMD_TYPE_FINAL	3 /* Final command */
++#define EXT_CMD_TYPE_LAST_RW	1 /* Last naked read/write */
++#define EXT_CMD_TYPE_MONO	0 /* Monolithic read/write */
++
++/*
++ * This should be large enough to read 'ONFI' and 'JEDEC'.
++ * Let's use 7 bytes, which is the maximum ID count supported
++ * by the controller (see NDCR_RD_ID_CNT_MASK).
++ */
++#define READ_ID_BYTES		7
++
++/* macros for registers read/write */
++#define nand_writel(info, off, val)					\
++	do {								\
++		dev_vdbg(&info->pdev->dev,				\
++			 "%s():%d nand_writel(0x%x, 0x%04x)\n",		\
++			 __func__, __LINE__, (val), (off));		\
++		writel_relaxed((val), (info)->mmio_base + (off));	\
++	} while (0)
++
++#define nand_readl(info, off)						\
++	({								\
++		unsigned int _v;					\
++		_v = readl_relaxed((info)->mmio_base + (off));		\
++		dev_vdbg(&info->pdev->dev,				\
++			 "%s():%d nand_readl(0x%04x) = 0x%x\n",		\
++			 __func__, __LINE__, (off), _v);		\
++		_v;							\
++	})
++
++/* error code and state */
++enum {
++	ERR_NONE	= 0,
++	ERR_DMABUSERR	= -1,
++	ERR_SENDCMD	= -2,
++	ERR_UNCORERR	= -3,
++	ERR_BBERR	= -4,
++	ERR_CORERR	= -5,
++};
++
++enum {
++	STATE_IDLE = 0,
++	STATE_PREPARED,
++	STATE_CMD_HANDLE,
++	STATE_DMA_READING,
++	STATE_DMA_WRITING,
++	STATE_DMA_DONE,
++	STATE_PIO_READING,
++	STATE_PIO_WRITING,
++	STATE_CMD_DONE,
++	STATE_READY,
++};
++
++enum pxa3xx_nand_variant {
++	PXA3XX_NAND_VARIANT_PXA,
++	PXA3XX_NAND_VARIANT_ARMADA370,
++};
++
++struct pxa3xx_nand_host {
++	struct nand_chip	chip;
++	void			*info_data;
++
++	/* page size of attached chip */
++	int			use_ecc;
++	int			cs;
++
++	/* calculated from pxa3xx_nand_flash data */
++	unsigned int		col_addr_cycles;
++	unsigned int		row_addr_cycles;
++};
++
++struct pxa3xx_nand_info {
++	struct nand_hw_control	controller;
++	struct platform_device	 *pdev;
++
++	struct clk		*clk;
++	void __iomem		*mmio_base;
++	unsigned long		mmio_phys;
++	struct completion	cmd_complete, dev_ready;
++
++	unsigned int 		buf_start;
++	unsigned int		buf_count;
++	unsigned int		buf_size;
++	unsigned int		data_buff_pos;
++	unsigned int		oob_buff_pos;
++
++	/* DMA information */
++	struct scatterlist	sg;
++	enum dma_data_direction	dma_dir;
++	struct dma_chan		*dma_chan;
++	dma_cookie_t		dma_cookie;
++	int			drcmr_dat;
++
++	unsigned char		*data_buff;
++	unsigned char		*oob_buff;
++	dma_addr_t 		data_buff_phys;
++	int 			data_dma_ch;
++
++	struct pxa3xx_nand_host *host[NUM_CHIP_SELECT];
++	unsigned int		state;
++
++	/*
++	 * This driver supports NFCv1 (as found in PXA SoC)
++	 * and NFCv2 (as found in Armada 370/XP SoC).
++	 */
++	enum pxa3xx_nand_variant variant;
++
++	int			cs;
++	int			use_ecc;	/* use HW ECC ? */
++	int			ecc_bch;	/* using BCH ECC? */
++	int			use_dma;	/* use DMA ? */
++	int			use_spare;	/* use spare ? */
++	int			need_wait;
++
++	/* Amount of real data per full chunk */
++	unsigned int		chunk_size;
++
++	/* Amount of spare data per full chunk */
++	unsigned int		spare_size;
++
++	/* Number of full chunks (i.e chunk_size + spare_size) */
++	unsigned int            nfullchunks;
++
++	/*
++	 * Total number of chunks. If equal to nfullchunks, then there
++	 * are only full chunks. Otherwise, there is one last chunk of
++	 * size (last_chunk_size + last_spare_size)
++	 */
++	unsigned int            ntotalchunks;
++
++	/* Amount of real data in the last chunk */
++	unsigned int		last_chunk_size;
++
++	/* Amount of spare data in the last chunk */
++	unsigned int		last_spare_size;
++
++	unsigned int		ecc_size;
++	unsigned int		ecc_err_cnt;
++	unsigned int		max_bitflips;
++	int 			retcode;
++
++	/*
++	 * Variables only valid during command
++	 * execution. step_chunk_size and step_spare_size is the
++	 * amount of real data and spare data in the current
++	 * chunk. cur_chunk is the current chunk being
++	 * read/programmed.
++	 */
++	unsigned int		step_chunk_size;
++	unsigned int		step_spare_size;
++	unsigned int            cur_chunk;
++
++	/* cached register value */
++	uint32_t		reg_ndcr;
++	uint32_t		ndtr0cs0;
++	uint32_t		ndtr1cs0;
++
++	/* generated NDCBx register values */
++	uint32_t		ndcb0;
++	uint32_t		ndcb1;
++	uint32_t		ndcb2;
++	uint32_t		ndcb3;
++};
++
++static bool use_dma = 1;
++module_param(use_dma, bool, 0444);
++MODULE_PARM_DESC(use_dma, "enable DMA for data transferring to/from NAND HW");
++
++struct pxa3xx_nand_timing {
++	unsigned int	tCH;  /* Enable signal hold time */
++	unsigned int	tCS;  /* Enable signal setup time */
++	unsigned int	tWH;  /* ND_nWE high duration */
++	unsigned int	tWP;  /* ND_nWE pulse time */
++	unsigned int	tRH;  /* ND_nRE high duration */
++	unsigned int	tRP;  /* ND_nRE pulse width */
++	unsigned int	tR;   /* ND_nWE high to ND_nRE low for read */
++	unsigned int	tWHR; /* ND_nWE high to ND_nRE low for status read */
++	unsigned int	tAR;  /* ND_ALE low to ND_nRE low delay */
++};
++
++struct pxa3xx_nand_flash {
++	uint32_t	chip_id;
++	unsigned int	flash_width;	/* Width of Flash memory (DWIDTH_M) */
++	unsigned int	dfc_width;	/* Width of flash controller(DWIDTH_C) */
++	struct pxa3xx_nand_timing *timing;	/* NAND Flash timing */
++};
++
++static struct pxa3xx_nand_timing timing[] = {
++	{ 40, 80, 60, 100, 80, 100, 90000, 400, 40, },
++	{ 10,  0, 20,  40, 30,  40, 11123, 110, 10, },
++	{ 10, 25, 15,  25, 15,  30, 25000,  60, 10, },
++	{ 10, 35, 15,  25, 15,  25, 25000,  60, 10, },
++};
++
++static struct pxa3xx_nand_flash builtin_flash_types[] = {
++	{ 0x46ec, 16, 16, &timing[1] },
++	{ 0xdaec,  8,  8, &timing[1] },
++	{ 0xd7ec,  8,  8, &timing[1] },
++	{ 0xa12c,  8,  8, &timing[2] },
++	{ 0xb12c, 16, 16, &timing[2] },
++	{ 0xdc2c,  8,  8, &timing[2] },
++	{ 0xcc2c, 16, 16, &timing[2] },
++	{ 0xba20, 16, 16, &timing[3] },
++};
++
++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 pxa3xx_nand_host *host = nand_get_controller_data(chip);
++	struct pxa3xx_nand_info *info = host->info_data;
++	int nchunks = mtd->writesize / info->chunk_size;
++
++	if (section >= nchunks)
++		return -ERANGE;
++
++	oobregion->offset = ((info->ecc_size + info->spare_size) * section) +
++			    info->spare_size;
++	oobregion->length = info->ecc_size;
++
++	return 0;
++}
++
++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 pxa3xx_nand_host *host = nand_get_controller_data(chip);
++	struct pxa3xx_nand_info *info = host->info_data;
++	int nchunks = mtd->writesize / info->chunk_size;
++
++	if (section >= nchunks)
++		return -ERANGE;
++
++	if (!info->spare_size)
++		return 0;
++
++	oobregion->offset = section * (info->ecc_size + info->spare_size);
++	oobregion->length = info->spare_size;
++	if (!section) {
++		/*
++		 * Bootrom looks in bytes 0 & 5 for bad blocks for the
++		 * 4KB page / 4bit BCH combination.
++		 */
++		if (mtd->writesize == 4096 && info->chunk_size == 2048) {
++			oobregion->offset += 6;
++			oobregion->length -= 6;
++		} else {
++			oobregion->offset += 2;
++			oobregion->length -= 2;
++		}
++	}
++
++	return 0;
++}
++
++static const struct mtd_ooblayout_ops pxa3xx_ooblayout_ops = {
++	.ecc = pxa3xx_ooblayout_ecc,
++	.free = pxa3xx_ooblayout_free,
++};
++
++static u8 bbt_pattern[] = {'M', 'V', 'B', 'b', 't', '0' };
++static u8 bbt_mirror_pattern[] = {'1', 't', 'b', 'B', 'V', 'M' };
++
++static struct nand_bbt_descr bbt_main_descr = {
++	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
++		| NAND_BBT_2BIT | NAND_BBT_VERSION,
++	.offs =	8,
++	.len = 6,
++	.veroffs = 14,
++	.maxblocks = 8,		/* Last 8 blocks in each chip */
++	.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,
++	.offs =	8,
++	.len = 6,
++	.veroffs = 14,
++	.maxblocks = 8,		/* Last 8 blocks in each chip */
++	.pattern = bbt_mirror_pattern
++};
++
++#define NDTR0_tCH(c)	(min((c), 7) << 19)
++#define NDTR0_tCS(c)	(min((c), 7) << 16)
++#define NDTR0_tWH(c)	(min((c), 7) << 11)
++#define NDTR0_tWP(c)	(min((c), 7) << 8)
++#define NDTR0_tRH(c)	(min((c), 7) << 3)
++#define NDTR0_tRP(c)	(min((c), 7) << 0)
++
++#define NDTR1_tR(c)	(min((c), 65535) << 16)
++#define NDTR1_tWHR(c)	(min((c), 15) << 4)
++#define NDTR1_tAR(c)	(min((c), 15) << 0)
++
++/* convert nano-seconds to nand flash controller clock cycles */
++#define ns2cycle(ns, clk)	(int)((ns) * (clk / 1000000) / 1000)
++
++static const struct of_device_id pxa3xx_nand_dt_ids[] = {
++	{
++		.compatible = "marvell,pxa3xx-nand",
++		.data       = (void *)PXA3XX_NAND_VARIANT_PXA,
++	},
++	{
++		.compatible = "marvell,armada370-nand",
++		.data       = (void *)PXA3XX_NAND_VARIANT_ARMADA370,
++	},
++	{}
++};
++MODULE_DEVICE_TABLE(of, pxa3xx_nand_dt_ids);
++
++static enum pxa3xx_nand_variant
++pxa3xx_nand_get_variant(struct platform_device *pdev)
++{
++	const struct of_device_id *of_id =
++			of_match_device(pxa3xx_nand_dt_ids, &pdev->dev);
++	if (!of_id)
++		return PXA3XX_NAND_VARIANT_PXA;
++	return (enum pxa3xx_nand_variant)of_id->data;
++}
++
++static void pxa3xx_nand_set_timing(struct pxa3xx_nand_host *host,
++				   const struct pxa3xx_nand_timing *t)
++{
++	struct pxa3xx_nand_info *info = host->info_data;
++	unsigned long nand_clk = clk_get_rate(info->clk);
++	uint32_t ndtr0, ndtr1;
++
++	ndtr0 = NDTR0_tCH(ns2cycle(t->tCH, nand_clk)) |
++		NDTR0_tCS(ns2cycle(t->tCS, nand_clk)) |
++		NDTR0_tWH(ns2cycle(t->tWH, nand_clk)) |
++		NDTR0_tWP(ns2cycle(t->tWP, nand_clk)) |
++		NDTR0_tRH(ns2cycle(t->tRH, nand_clk)) |
++		NDTR0_tRP(ns2cycle(t->tRP, nand_clk));
++
++	ndtr1 = NDTR1_tR(ns2cycle(t->tR, nand_clk)) |
++		NDTR1_tWHR(ns2cycle(t->tWHR, nand_clk)) |
++		NDTR1_tAR(ns2cycle(t->tAR, nand_clk));
++
++	info->ndtr0cs0 = ndtr0;
++	info->ndtr1cs0 = ndtr1;
++	nand_writel(info, NDTR0CS0, ndtr0);
++	nand_writel(info, NDTR1CS0, ndtr1);
++}
++
++static void pxa3xx_nand_set_sdr_timing(struct pxa3xx_nand_host *host,
++				       const struct nand_sdr_timings *t)
++{
++	struct pxa3xx_nand_info *info = host->info_data;
++	struct nand_chip *chip = &host->chip;
++	unsigned long nand_clk = clk_get_rate(info->clk);
++	uint32_t ndtr0, ndtr1;
++
++	u32 tCH_min = DIV_ROUND_UP(t->tCH_min, 1000);
++	u32 tCS_min = DIV_ROUND_UP(t->tCS_min, 1000);
++	u32 tWH_min = DIV_ROUND_UP(t->tWH_min, 1000);
++	u32 tWP_min = DIV_ROUND_UP(t->tWC_min - t->tWH_min, 1000);
++	u32 tREH_min = DIV_ROUND_UP(t->tREH_min, 1000);
++	u32 tRP_min = DIV_ROUND_UP(t->tRC_min - t->tREH_min, 1000);
++	u32 tR = chip->chip_delay * 1000;
++	u32 tWHR_min = DIV_ROUND_UP(t->tWHR_min, 1000);
++	u32 tAR_min = DIV_ROUND_UP(t->tAR_min, 1000);
++
++	/* fallback to a default value if tR = 0 */
++	if (!tR)
++		tR = 20000;
++
++	ndtr0 = NDTR0_tCH(ns2cycle(tCH_min, nand_clk)) |
++		NDTR0_tCS(ns2cycle(tCS_min, nand_clk)) |
++		NDTR0_tWH(ns2cycle(tWH_min, nand_clk)) |
++		NDTR0_tWP(ns2cycle(tWP_min, nand_clk)) |
++		NDTR0_tRH(ns2cycle(tREH_min, nand_clk)) |
++		NDTR0_tRP(ns2cycle(tRP_min, nand_clk));
++
++	ndtr1 = NDTR1_tR(ns2cycle(tR, nand_clk)) |
++		NDTR1_tWHR(ns2cycle(tWHR_min, nand_clk)) |
++		NDTR1_tAR(ns2cycle(tAR_min, nand_clk));
++
++	info->ndtr0cs0 = ndtr0;
++	info->ndtr1cs0 = ndtr1;
++	nand_writel(info, NDTR0CS0, ndtr0);
++	nand_writel(info, NDTR1CS0, ndtr1);
++}
++
++static int pxa3xx_nand_init_timings_compat(struct pxa3xx_nand_host *host,
++					   unsigned int *flash_width,
++					   unsigned int *dfc_width)
++{
++	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);
++	int i, id, ntypes;
++
++	ntypes = ARRAY_SIZE(builtin_flash_types);
++
++	chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
++
++	id = chip->read_byte(mtd);
++	id |= chip->read_byte(mtd) << 0x8;
++
++	for (i = 0; i < ntypes; i++) {
++		f = &builtin_flash_types[i];
++
++		if (f->chip_id == id)
++			break;
++	}
++
++	if (i == ntypes) {
++		dev_err(&info->pdev->dev, "Error: timings not found\n");
++		return -EINVAL;
++	}
++
++	pxa3xx_nand_set_timing(host, f->timing);
++
++	*flash_width = f->flash_width;
++	*dfc_width = f->dfc_width;
++
++	return 0;
++}
++
++static int pxa3xx_nand_init_timings_onfi(struct pxa3xx_nand_host *host,
++					 int mode)
++{
++	const struct nand_sdr_timings *timings;
++
++	mode = fls(mode) - 1;
++	if (mode < 0)
++		mode = 0;
++
++	timings = onfi_async_timing_mode_to_sdr_timings(mode);
++	if (IS_ERR(timings))
++		return PTR_ERR(timings);
++
++	pxa3xx_nand_set_sdr_timing(host, timings);
++
++	return 0;
++}
++
++static int pxa3xx_nand_init(struct pxa3xx_nand_host *host)
++{
++	struct nand_chip *chip = &host->chip;
++	struct pxa3xx_nand_info *info = host->info_data;
++	unsigned int flash_width = 0, dfc_width = 0;
++	int mode, err;
++
++	mode = onfi_get_async_timing_mode(chip);
++	if (mode == ONFI_TIMING_MODE_UNKNOWN) {
++		err = pxa3xx_nand_init_timings_compat(host, &flash_width,
++						      &dfc_width);
++		if (err)
++			return err;
++
++		if (flash_width == 16) {
++			info->reg_ndcr |= NDCR_DWIDTH_M;
++			chip->options |= NAND_BUSWIDTH_16;
++		}
++
++		info->reg_ndcr |= (dfc_width == 16) ? NDCR_DWIDTH_C : 0;
++	} else {
++		err = pxa3xx_nand_init_timings_onfi(host, mode);
++		if (err)
++			return err;
++	}
++
++	return 0;
++}
++
++/**
++ * NOTE: it is a must to set ND_RUN firstly, then write
++ * command buffer, otherwise, it does not work.
++ * We enable all the interrupt at the same time, and
++ * let pxa3xx_nand_irq to handle all logic.
++ */
++static void pxa3xx_nand_start(struct pxa3xx_nand_info *info)
++{
++	uint32_t ndcr;
++
++	ndcr = info->reg_ndcr;
++
++	if (info->use_ecc) {
++		ndcr |= NDCR_ECC_EN;
++		if (info->ecc_bch)
++			nand_writel(info, NDECCCTRL, 0x1);
++	} else {
++		ndcr &= ~NDCR_ECC_EN;
++		if (info->ecc_bch)
++			nand_writel(info, NDECCCTRL, 0x0);
++	}
++
++	if (info->use_dma)
++		ndcr |= NDCR_DMA_EN;
++	else
++		ndcr &= ~NDCR_DMA_EN;
++
++	if (info->use_spare)
++		ndcr |= NDCR_SPARE_EN;
++	else
++		ndcr &= ~NDCR_SPARE_EN;
++
++	ndcr |= NDCR_ND_RUN;
++
++	/* clear status bits and run */
++	nand_writel(info, NDSR, NDSR_MASK);
++	nand_writel(info, NDCR, 0);
++	nand_writel(info, NDCR, ndcr);
++}
++
++static void pxa3xx_nand_stop(struct pxa3xx_nand_info *info)
++{
++	uint32_t ndcr;
++	int timeout = NAND_STOP_DELAY;
++
++	/* wait RUN bit in NDCR become 0 */
++	ndcr = nand_readl(info, NDCR);
++	while ((ndcr & NDCR_ND_RUN) && (timeout-- > 0)) {
++		ndcr = nand_readl(info, NDCR);
++		udelay(1);
++	}
++
++	if (timeout <= 0) {
++		ndcr &= ~NDCR_ND_RUN;
++		nand_writel(info, NDCR, ndcr);
++	}
++	if (info->dma_chan)
++		dmaengine_terminate_all(info->dma_chan);
++
++	/* clear status bits */
++	nand_writel(info, NDSR, NDSR_MASK);
++}
++
++static void __maybe_unused
++enable_int(struct pxa3xx_nand_info *info, uint32_t int_mask)
++{
++	uint32_t ndcr;
++
++	ndcr = nand_readl(info, NDCR);
++	nand_writel(info, NDCR, ndcr & ~int_mask);
++}
++
++static void disable_int(struct pxa3xx_nand_info *info, uint32_t int_mask)
++{
++	uint32_t ndcr;
++
++	ndcr = nand_readl(info, NDCR);
++	nand_writel(info, NDCR, ndcr | int_mask);
++}
++
++static void drain_fifo(struct pxa3xx_nand_info *info, void *data, int len)
++{
++	if (info->ecc_bch) {
++		u32 val;
++		int ret;
++
++		/*
++		 * According to the datasheet, when reading from NDDB
++		 * with BCH enabled, after each 32 bytes reads, we
++		 * have to make sure that the NDSR.RDDREQ bit is set.
++		 *
++		 * Drain the FIFO 8 32 bits reads at a time, and skip
++		 * the polling on the last read.
++		 */
++		while (len > 8) {
++			ioread32_rep(info->mmio_base + NDDB, data, 8);
++
++			ret = readl_relaxed_poll_timeout(info->mmio_base + NDSR, val,
++							 val & NDSR_RDDREQ, 1000, 5000);
++			if (ret) {
++				dev_err(&info->pdev->dev,
++					"Timeout on RDDREQ while draining the FIFO\n");
++				return;
++			}
++
++			data += 32;
++			len -= 8;
++		}
++	}
++
++	ioread32_rep(info->mmio_base + NDDB, data, len);
++}
++
++static void handle_data_pio(struct pxa3xx_nand_info *info)
++{
++	switch (info->state) {
++	case STATE_PIO_WRITING:
++		if (info->step_chunk_size)
++			writesl(info->mmio_base + NDDB,
++				info->data_buff + info->data_buff_pos,
++				DIV_ROUND_UP(info->step_chunk_size, 4));
++
++		if (info->step_spare_size)
++			writesl(info->mmio_base + NDDB,
++				info->oob_buff + info->oob_buff_pos,
++				DIV_ROUND_UP(info->step_spare_size, 4));
++		break;
++	case STATE_PIO_READING:
++		if (info->step_chunk_size)
++			drain_fifo(info,
++				   info->data_buff + info->data_buff_pos,
++				   DIV_ROUND_UP(info->step_chunk_size, 4));
++
++		if (info->step_spare_size)
++			drain_fifo(info,
++				   info->oob_buff + info->oob_buff_pos,
++				   DIV_ROUND_UP(info->step_spare_size, 4));
++		break;
++	default:
++		dev_err(&info->pdev->dev, "%s: invalid state %d\n", __func__,
++				info->state);
++		BUG();
++	}
++
++	/* Update buffer pointers for multi-page read/write */
++	info->data_buff_pos += info->step_chunk_size;
++	info->oob_buff_pos += info->step_spare_size;
++}
++
++static void pxa3xx_nand_data_dma_irq(void *data)
++{
++	struct pxa3xx_nand_info *info = data;
++	struct dma_tx_state state;
++	enum dma_status status;
++
++	status = dmaengine_tx_status(info->dma_chan, info->dma_cookie, &state);
++	if (likely(status == DMA_COMPLETE)) {
++		info->state = STATE_DMA_DONE;
++	} else {
++		dev_err(&info->pdev->dev, "DMA error on data channel\n");
++		info->retcode = ERR_DMABUSERR;
++	}
++	dma_unmap_sg(info->dma_chan->device->dev, &info->sg, 1, info->dma_dir);
++
++	nand_writel(info, NDSR, NDSR_WRDREQ | NDSR_RDDREQ);
++	enable_int(info, NDCR_INT_MASK);
++}
++
++static void start_data_dma(struct pxa3xx_nand_info *info)
++{
++	enum dma_transfer_direction direction;
++	struct dma_async_tx_descriptor *tx;
++
++	switch (info->state) {
++	case STATE_DMA_WRITING:
++		info->dma_dir = DMA_TO_DEVICE;
++		direction = DMA_MEM_TO_DEV;
++		break;
++	case STATE_DMA_READING:
++		info->dma_dir = DMA_FROM_DEVICE;
++		direction = DMA_DEV_TO_MEM;
++		break;
++	default:
++		dev_err(&info->pdev->dev, "%s: invalid state %d\n", __func__,
++				info->state);
++		BUG();
++	}
++	info->sg.length = info->chunk_size;
++	if (info->use_spare)
++		info->sg.length += info->spare_size + info->ecc_size;
++	dma_map_sg(info->dma_chan->device->dev, &info->sg, 1, info->dma_dir);
++
++	tx = dmaengine_prep_slave_sg(info->dma_chan, &info->sg, 1, direction,
++				     DMA_PREP_INTERRUPT);
++	if (!tx) {
++		dev_err(&info->pdev->dev, "prep_slave_sg() failed\n");
++		return;
++	}
++	tx->callback = pxa3xx_nand_data_dma_irq;
++	tx->callback_param = info;
++	info->dma_cookie = dmaengine_submit(tx);
++	dma_async_issue_pending(info->dma_chan);
++	dev_dbg(&info->pdev->dev, "%s(dir=%d cookie=%x size=%u)\n",
++		__func__, direction, info->dma_cookie, info->sg.length);
++}
++
++static irqreturn_t pxa3xx_nand_irq_thread(int irq, void *data)
++{
++	struct pxa3xx_nand_info *info = data;
++
++	handle_data_pio(info);
++
++	info->state = STATE_CMD_DONE;
++	nand_writel(info, NDSR, NDSR_WRDREQ | NDSR_RDDREQ);
++
++	return IRQ_HANDLED;
++}
++
++static irqreturn_t pxa3xx_nand_irq(int irq, void *devid)
++{
++	struct pxa3xx_nand_info *info = devid;
++	unsigned int status, is_completed = 0, is_ready = 0;
++	unsigned int ready, cmd_done;
++	irqreturn_t ret = IRQ_HANDLED;
++
++	if (info->cs == 0) {
++		ready           = NDSR_FLASH_RDY;
++		cmd_done        = NDSR_CS0_CMDD;
++	} else {
++		ready           = NDSR_RDY;
++		cmd_done        = NDSR_CS1_CMDD;
++	}
++
++	status = nand_readl(info, NDSR);
++
++	if (status & NDSR_UNCORERR)
++		info->retcode = ERR_UNCORERR;
++	if (status & NDSR_CORERR) {
++		info->retcode = ERR_CORERR;
++		if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370 &&
++		    info->ecc_bch)
++			info->ecc_err_cnt = NDSR_ERR_CNT(status);
++		else
++			info->ecc_err_cnt = 1;
++
++		/*
++		 * Each chunk composing a page is corrected independently,
++		 * and we need to store maximum number of corrected bitflips
++		 * to return it to the MTD layer in ecc.read_page().
++		 */
++		info->max_bitflips = max_t(unsigned int,
++					   info->max_bitflips,
++					   info->ecc_err_cnt);
++	}
++	if (status & (NDSR_RDDREQ | NDSR_WRDREQ)) {
++		/* whether use dma to transfer data */
++		if (info->use_dma) {
++			disable_int(info, NDCR_INT_MASK);
++			info->state = (status & NDSR_RDDREQ) ?
++				      STATE_DMA_READING : STATE_DMA_WRITING;
++			start_data_dma(info);
++			goto NORMAL_IRQ_EXIT;
++		} else {
++			info->state = (status & NDSR_RDDREQ) ?
++				      STATE_PIO_READING : STATE_PIO_WRITING;
++			ret = IRQ_WAKE_THREAD;
++			goto NORMAL_IRQ_EXIT;
++		}
++	}
++	if (status & cmd_done) {
++		info->state = STATE_CMD_DONE;
++		is_completed = 1;
++	}
++	if (status & ready) {
++		info->state = STATE_READY;
++		is_ready = 1;
++	}
++
++	/*
++	 * Clear all status bit before issuing the next command, which
++	 * can and will alter the status bits and will deserve a new
++	 * interrupt on its own. This lets the controller exit the IRQ
++	 */
++	nand_writel(info, NDSR, status);
++
++	if (status & NDSR_WRCMDREQ) {
++		status &= ~NDSR_WRCMDREQ;
++		info->state = STATE_CMD_HANDLE;
++
++		/*
++		 * Command buffer registers NDCB{0-2} (and optionally NDCB3)
++		 * must be loaded by writing directly either 12 or 16
++		 * bytes directly to NDCB0, four bytes at a time.
++		 *
++		 * Direct write access to NDCB1, NDCB2 and NDCB3 is ignored
++		 * but each NDCBx register can be read.
++		 */
++		nand_writel(info, NDCB0, info->ndcb0);
++		nand_writel(info, NDCB0, info->ndcb1);
++		nand_writel(info, NDCB0, info->ndcb2);
++
++		/* NDCB3 register is available in NFCv2 (Armada 370/XP SoC) */
++		if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370)
++			nand_writel(info, NDCB0, info->ndcb3);
++	}
++
++	if (is_completed)
++		complete(&info->cmd_complete);
++	if (is_ready)
++		complete(&info->dev_ready);
++NORMAL_IRQ_EXIT:
++	return ret;
++}
++
++static inline int is_buf_blank(uint8_t *buf, size_t len)
++{
++	for (; len > 0; len--)
++		if (*buf++ != 0xff)
++			return 0;
++	return 1;
++}
++
++static void set_command_address(struct pxa3xx_nand_info *info,
++		unsigned int page_size, uint16_t column, int page_addr)
++{
++	/* small page addr setting */
++	if (page_size < PAGE_CHUNK_SIZE) {
++		info->ndcb1 = ((page_addr & 0xFFFFFF) << 8)
++				| (column & 0xFF);
++
++		info->ndcb2 = 0;
++	} else {
++		info->ndcb1 = ((page_addr & 0xFFFF) << 16)
++				| (column & 0xFFFF);
++
++		if (page_addr & 0xFF0000)
++			info->ndcb2 = (page_addr & 0xFF0000) >> 16;
++		else
++			info->ndcb2 = 0;
++	}
++}
++
++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);
++
++	/* reset data and oob column point to handle data */
++	info->buf_start		= 0;
++	info->buf_count		= 0;
++	info->data_buff_pos	= 0;
++	info->oob_buff_pos	= 0;
++	info->step_chunk_size   = 0;
++	info->step_spare_size   = 0;
++	info->cur_chunk         = 0;
++	info->use_ecc		= 0;
++	info->use_spare		= 1;
++	info->retcode		= ERR_NONE;
++	info->ecc_err_cnt	= 0;
++	info->ndcb3		= 0;
++	info->need_wait		= 0;
++
++	switch (command) {
++	case NAND_CMD_READ0:
++	case NAND_CMD_READOOB:
++	case NAND_CMD_PAGEPROG:
++		info->use_ecc = 1;
++		break;
++	case NAND_CMD_PARAM:
++		info->use_spare = 0;
++		break;
++	default:
++		info->ndcb1 = 0;
++		info->ndcb2 = 0;
++		break;
++	}
++
++	/*
++	 * If we are about to issue a read command, or about to set
++	 * the write address, then clean the data buffer.
++	 */
++	if (command == NAND_CMD_READ0 ||
++	    command == NAND_CMD_READOOB ||
++	    command == NAND_CMD_SEQIN) {
++
++		info->buf_count = mtd->writesize + mtd->oobsize;
++		memset(info->data_buff, 0xFF, info->buf_count);
++	}
++
++}
++
++static int prepare_set_command(struct pxa3xx_nand_info *info, int command,
++		int ext_cmd_type, uint16_t column, int page_addr)
++{
++	int addr_cycle, exec_cmd;
++	struct pxa3xx_nand_host *host;
++	struct mtd_info *mtd;
++
++	host = info->host[info->cs];
++	mtd = nand_to_mtd(&host->chip);
++	addr_cycle = 0;
++	exec_cmd = 1;
++
++	if (info->cs != 0)
++		info->ndcb0 = NDCB0_CSEL;
++	else
++		info->ndcb0 = 0;
++
++	if (command == NAND_CMD_SEQIN)
++		exec_cmd = 0;
++
++	addr_cycle = NDCB0_ADDR_CYC(host->row_addr_cycles
++				    + host->col_addr_cycles);
++
++	switch (command) {
++	case NAND_CMD_READOOB:
++	case NAND_CMD_READ0:
++		info->buf_start = column;
++		info->ndcb0 |= NDCB0_CMD_TYPE(0)
++				| addr_cycle
++				| NAND_CMD_READ0;
++
++		if (command == NAND_CMD_READOOB)
++			info->buf_start += mtd->writesize;
++
++		if (info->cur_chunk < info->nfullchunks) {
++			info->step_chunk_size = info->chunk_size;
++			info->step_spare_size = info->spare_size;
++		} else {
++			info->step_chunk_size = info->last_chunk_size;
++			info->step_spare_size = info->last_spare_size;
++		}
++
++		/*
++		 * Multiple page read needs an 'extended command type' field,
++		 * which is either naked-read or last-read according to the
++		 * state.
++		 */
++		if (mtd->writesize == PAGE_CHUNK_SIZE) {
++			info->ndcb0 |= NDCB0_DBC | (NAND_CMD_READSTART << 8);
++		} else if (mtd->writesize > PAGE_CHUNK_SIZE) {
++			info->ndcb0 |= NDCB0_DBC | (NAND_CMD_READSTART << 8)
++					| NDCB0_LEN_OVRD
++					| NDCB0_EXT_CMD_TYPE(ext_cmd_type);
++			info->ndcb3 = info->step_chunk_size +
++				info->step_spare_size;
++		}
++
++		set_command_address(info, mtd->writesize, column, page_addr);
++		break;
++
++	case NAND_CMD_SEQIN:
++
++		info->buf_start = column;
++		set_command_address(info, mtd->writesize, 0, page_addr);
++
++		/*
++		 * Multiple page programming needs to execute the initial
++		 * SEQIN command that sets the page address.
++		 */
++		if (mtd->writesize > PAGE_CHUNK_SIZE) {
++			info->ndcb0 |= NDCB0_CMD_TYPE(0x1)
++				| NDCB0_EXT_CMD_TYPE(ext_cmd_type)
++				| addr_cycle
++				| command;
++			exec_cmd = 1;
++		}
++		break;
++
++	case NAND_CMD_PAGEPROG:
++		if (is_buf_blank(info->data_buff,
++					(mtd->writesize + mtd->oobsize))) {
++			exec_cmd = 0;
++			break;
++		}
++
++		if (info->cur_chunk < info->nfullchunks) {
++			info->step_chunk_size = info->chunk_size;
++			info->step_spare_size = info->spare_size;
++		} else {
++			info->step_chunk_size = info->last_chunk_size;
++			info->step_spare_size = info->last_spare_size;
++		}
++
++		/* Second command setting for large pages */
++		if (mtd->writesize > PAGE_CHUNK_SIZE) {
++			/*
++			 * Multiple page write uses the 'extended command'
++			 * field. This can be used to issue a command dispatch
++			 * or a naked-write depending on the current stage.
++			 */
++			info->ndcb0 |= NDCB0_CMD_TYPE(0x1)
++					| NDCB0_LEN_OVRD
++					| NDCB0_EXT_CMD_TYPE(ext_cmd_type);
++			info->ndcb3 = info->step_chunk_size +
++				      info->step_spare_size;
++
++			/*
++			 * This is the command dispatch that completes a chunked
++			 * page program operation.
++			 */
++			if (info->cur_chunk == info->ntotalchunks) {
++				info->ndcb0 = NDCB0_CMD_TYPE(0x1)
++					| NDCB0_EXT_CMD_TYPE(ext_cmd_type)
++					| command;
++				info->ndcb1 = 0;
++				info->ndcb2 = 0;
++				info->ndcb3 = 0;
++			}
++		} else {
++			info->ndcb0 |= NDCB0_CMD_TYPE(0x1)
++					| NDCB0_AUTO_RS
++					| NDCB0_ST_ROW_EN
++					| NDCB0_DBC
++					| (NAND_CMD_PAGEPROG << 8)
++					| NAND_CMD_SEQIN
++					| addr_cycle;
++		}
++		break;
++
++	case NAND_CMD_PARAM:
++		info->buf_count = INIT_BUFFER_SIZE;
++		info->ndcb0 |= NDCB0_CMD_TYPE(0)
++				| NDCB0_ADDR_CYC(1)
++				| NDCB0_LEN_OVRD
++				| command;
++		info->ndcb1 = (column & 0xFF);
++		info->ndcb3 = INIT_BUFFER_SIZE;
++		info->step_chunk_size = INIT_BUFFER_SIZE;
++		break;
++
++	case NAND_CMD_READID:
++		info->buf_count = READ_ID_BYTES;
++		info->ndcb0 |= NDCB0_CMD_TYPE(3)
++				| NDCB0_ADDR_CYC(1)
++				| command;
++		info->ndcb1 = (column & 0xFF);
++
++		info->step_chunk_size = 8;
++		break;
++	case NAND_CMD_STATUS:
++		info->buf_count = 1;
++		info->ndcb0 |= NDCB0_CMD_TYPE(4)
++				| NDCB0_ADDR_CYC(1)
++				| command;
++
++		info->step_chunk_size = 8;
++		break;
++
++	case NAND_CMD_ERASE1:
++		info->ndcb0 |= NDCB0_CMD_TYPE(2)
++				| NDCB0_AUTO_RS
++				| NDCB0_ADDR_CYC(3)
++				| NDCB0_DBC
++				| (NAND_CMD_ERASE2 << 8)
++				| NAND_CMD_ERASE1;
++		info->ndcb1 = page_addr;
++		info->ndcb2 = 0;
++
++		break;
++	case NAND_CMD_RESET:
++		info->ndcb0 |= NDCB0_CMD_TYPE(5)
++				| command;
++
++		break;
++
++	case NAND_CMD_ERASE2:
++		exec_cmd = 0;
++		break;
++
++	default:
++		exec_cmd = 0;
++		dev_err(&info->pdev->dev, "non-supported command %x\n",
++				command);
++		break;
++	}
++
++	return exec_cmd;
++}
++
++static void nand_cmdfunc(struct mtd_info *mtd, unsigned command,
++			 int column, int page_addr)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct pxa3xx_nand_host *host = nand_get_controller_data(chip);
++	struct pxa3xx_nand_info *info = host->info_data;
++	int exec_cmd;
++
++	/*
++	 * if this is a x16 device ,then convert the input
++	 * "byte" address into a "word" address appropriate
++	 * for indexing a word-oriented device
++	 */
++	if (info->reg_ndcr & NDCR_DWIDTH_M)
++		column /= 2;
++
++	/*
++	 * There may be different NAND chip hooked to
++	 * different chip select, so check whether
++	 * chip select has been changed, if yes, reset the timing
++	 */
++	if (info->cs != host->cs) {
++		info->cs = host->cs;
++		nand_writel(info, NDTR0CS0, info->ndtr0cs0);
++		nand_writel(info, NDTR1CS0, info->ndtr1cs0);
++	}
++
++	prepare_start_command(info, command);
++
++	info->state = STATE_PREPARED;
++	exec_cmd = prepare_set_command(info, command, 0, column, page_addr);
++
++	if (exec_cmd) {
++		init_completion(&info->cmd_complete);
++		init_completion(&info->dev_ready);
++		info->need_wait = 1;
++		pxa3xx_nand_start(info);
++
++		if (!wait_for_completion_timeout(&info->cmd_complete,
++		    CHIP_DELAY_TIMEOUT)) {
++			dev_err(&info->pdev->dev, "Wait time out!!!\n");
++			/* Stop State Machine for next command cycle */
++			pxa3xx_nand_stop(info);
++		}
++	}
++	info->state = STATE_IDLE;
++}
++
++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 pxa3xx_nand_host *host = nand_get_controller_data(chip);
++	struct pxa3xx_nand_info *info = host->info_data;
++	int exec_cmd, ext_cmd_type;
++
++	/*
++	 * if this is a x16 device then convert the input
++	 * "byte" address into a "word" address appropriate
++	 * for indexing a word-oriented device
++	 */
++	if (info->reg_ndcr & NDCR_DWIDTH_M)
++		column /= 2;
++
++	/*
++	 * There may be different NAND chip hooked to
++	 * different chip select, so check whether
++	 * chip select has been changed, if yes, reset the timing
++	 */
++	if (info->cs != host->cs) {
++		info->cs = host->cs;
++		nand_writel(info, NDTR0CS0, info->ndtr0cs0);
++		nand_writel(info, NDTR1CS0, info->ndtr1cs0);
++	}
++
++	/* Select the extended command for the first command */
++	switch (command) {
++	case NAND_CMD_READ0:
++	case NAND_CMD_READOOB:
++		ext_cmd_type = EXT_CMD_TYPE_MONO;
++		break;
++	case NAND_CMD_SEQIN:
++		ext_cmd_type = EXT_CMD_TYPE_DISPATCH;
++		break;
++	case NAND_CMD_PAGEPROG:
++		ext_cmd_type = EXT_CMD_TYPE_NAKED_RW;
++		break;
++	default:
++		ext_cmd_type = 0;
++		break;
++	}
++
++	prepare_start_command(info, command);
++
++	/*
++	 * Prepare the "is ready" completion before starting a command
++	 * transaction sequence. If the command is not executed the
++	 * completion will be completed, see below.
++	 *
++	 * We can do that inside the loop because the command variable
++	 * is invariant and thus so is the exec_cmd.
++	 */
++	info->need_wait = 1;
++	init_completion(&info->dev_ready);
++	do {
++		info->state = STATE_PREPARED;
++
++		exec_cmd = prepare_set_command(info, command, ext_cmd_type,
++					       column, page_addr);
++		if (!exec_cmd) {
++			info->need_wait = 0;
++			complete(&info->dev_ready);
++			break;
++		}
++
++		init_completion(&info->cmd_complete);
++		pxa3xx_nand_start(info);
++
++		if (!wait_for_completion_timeout(&info->cmd_complete,
++		    CHIP_DELAY_TIMEOUT)) {
++			dev_err(&info->pdev->dev, "Wait time out!!!\n");
++			/* Stop State Machine for next command cycle */
++			pxa3xx_nand_stop(info);
++			break;
++		}
++
++		/* Only a few commands need several steps */
++		if (command != NAND_CMD_PAGEPROG &&
++		    command != NAND_CMD_READ0    &&
++		    command != NAND_CMD_READOOB)
++			break;
++
++		info->cur_chunk++;
++
++		/* Check if the sequence is complete */
++		if (info->cur_chunk == info->ntotalchunks && command != NAND_CMD_PAGEPROG)
++			break;
++
++		/*
++		 * After a splitted program command sequence has issued
++		 * the command dispatch, the command sequence is complete.
++		 */
++		if (info->cur_chunk == (info->ntotalchunks + 1) &&
++		    command == NAND_CMD_PAGEPROG &&
++		    ext_cmd_type == EXT_CMD_TYPE_DISPATCH)
++			break;
++
++		if (command == NAND_CMD_READ0 || command == NAND_CMD_READOOB) {
++			/* Last read: issue a 'last naked read' */
++			if (info->cur_chunk == info->ntotalchunks - 1)
++				ext_cmd_type = EXT_CMD_TYPE_LAST_RW;
++			else
++				ext_cmd_type = EXT_CMD_TYPE_NAKED_RW;
++
++		/*
++		 * If a splitted program command has no more data to transfer,
++		 * the command dispatch must be issued to complete.
++		 */
++		} else if (command == NAND_CMD_PAGEPROG &&
++			   info->cur_chunk == info->ntotalchunks) {
++				ext_cmd_type = EXT_CMD_TYPE_DISPATCH;
++		}
++	} while (1);
++
++	info->state = STATE_IDLE;
++}
++
++static int pxa3xx_nand_write_page_hwecc(struct mtd_info *mtd,
++		struct nand_chip *chip, const uint8_t *buf, int oob_required,
++		int page)
++{
++	chip->write_buf(mtd, buf, mtd->writesize);
++	chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
++
++	return 0;
++}
++
++static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd,
++		struct nand_chip *chip, uint8_t *buf, int oob_required,
++		int page)
++{
++	struct pxa3xx_nand_host *host = nand_get_controller_data(chip);
++	struct pxa3xx_nand_info *info = host->info_data;
++
++	chip->read_buf(mtd, buf, mtd->writesize);
++	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
++
++	if (info->retcode == ERR_CORERR && info->use_ecc) {
++		mtd->ecc_stats.corrected += info->ecc_err_cnt;
++
++	} else if (info->retcode == ERR_UNCORERR) {
++		/*
++		 * for blank page (all 0xff), HW will calculate its ECC as
++		 * 0, which is different from the ECC information within
++		 * OOB, ignore such uncorrectable errors
++		 */
++		if (is_buf_blank(buf, mtd->writesize))
++			info->retcode = ERR_NONE;
++		else
++			mtd->ecc_stats.failed++;
++	}
++
++	return info->max_bitflips;
++}
++
++static uint8_t pxa3xx_nand_read_byte(struct mtd_info *mtd)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct pxa3xx_nand_host *host = nand_get_controller_data(chip);
++	struct pxa3xx_nand_info *info = host->info_data;
++	char retval = 0xFF;
++
++	if (info->buf_start < info->buf_count)
++		/* Has just send a new command? */
++		retval = info->data_buff[info->buf_start++];
++
++	return retval;
++}
++
++static u16 pxa3xx_nand_read_word(struct mtd_info *mtd)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct pxa3xx_nand_host *host = nand_get_controller_data(chip);
++	struct pxa3xx_nand_info *info = host->info_data;
++	u16 retval = 0xFFFF;
++
++	if (!(info->buf_start & 0x01) && info->buf_start < info->buf_count) {
++		retval = *((u16 *)(info->data_buff+info->buf_start));
++		info->buf_start += 2;
++	}
++	return retval;
++}
++
++static void pxa3xx_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
++{
++	struct nand_chip *chip = mtd_to_nand(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);
++
++	memcpy(buf, info->data_buff + info->buf_start, real_len);
++	info->buf_start += real_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 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);
++
++	memcpy(info->data_buff + info->buf_start, buf, real_len);
++	info->buf_start += real_len;
++}
++
++static void pxa3xx_nand_select_chip(struct mtd_info *mtd, int chip)
++{
++	return;
++}
++
++static int pxa3xx_nand_waitfunc(struct mtd_info *mtd, struct nand_chip *this)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct pxa3xx_nand_host *host = nand_get_controller_data(chip);
++	struct pxa3xx_nand_info *info = host->info_data;
++
++	if (info->need_wait) {
++		info->need_wait = 0;
++		if (!wait_for_completion_timeout(&info->dev_ready,
++		    CHIP_DELAY_TIMEOUT)) {
++			dev_err(&info->pdev->dev, "Ready time out!!!\n");
++			return NAND_STATUS_FAIL;
++		}
++	}
++
++	/* pxa3xx_nand_send_command has waited for command complete */
++	if (this->state == FL_WRITING || this->state == FL_ERASING) {
++		if (info->retcode == ERR_NONE)
++			return 0;
++		else
++			return NAND_STATUS_FAIL;
++	}
++
++	return NAND_STATUS_READY;
++}
++
++static int pxa3xx_nand_config_ident(struct pxa3xx_nand_info *info)
++{
++	struct pxa3xx_nand_host *host = info->host[info->cs];
++	struct platform_device *pdev = info->pdev;
++	struct pxa3xx_nand_platform_data *pdata = dev_get_platdata(&pdev->dev);
++	const struct nand_sdr_timings *timings;
++
++	/* Configure default flash values */
++	info->chunk_size = PAGE_CHUNK_SIZE;
++	info->reg_ndcr = 0x0; /* enable all interrupts */
++	info->reg_ndcr |= (pdata->enable_arbiter) ? NDCR_ND_ARB_EN : 0;
++	info->reg_ndcr |= NDCR_RD_ID_CNT(READ_ID_BYTES);
++	info->reg_ndcr |= NDCR_SPARE_EN;
++
++	/* use the common timing to make a try */
++	timings = onfi_async_timing_mode_to_sdr_timings(0);
++	if (IS_ERR(timings))
++		return PTR_ERR(timings);
++
++	pxa3xx_nand_set_sdr_timing(host, timings);
++	return 0;
++}
++
++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);
++
++	info->reg_ndcr |= (host->col_addr_cycles == 2) ? NDCR_RA_START : 0;
++	info->reg_ndcr |= (chip->page_shift == 6) ? NDCR_PG_PER_BLK : 0;
++	info->reg_ndcr |= (mtd->writesize == 2048) ? NDCR_PAGE_SZ : 0;
++}
++
++static void pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info)
++{
++	struct platform_device *pdev = info->pdev;
++	struct pxa3xx_nand_platform_data *pdata = dev_get_platdata(&pdev->dev);
++	uint32_t ndcr = nand_readl(info, NDCR);
++
++	/* Set an initial chunk size */
++	info->chunk_size = ndcr & NDCR_PAGE_SZ ? 2048 : 512;
++	info->reg_ndcr = ndcr &
++		~(NDCR_INT_MASK | NDCR_ND_ARB_EN | NFCV1_NDCR_ARB_CNTL);
++	info->reg_ndcr |= (pdata->enable_arbiter) ? NDCR_ND_ARB_EN : 0;
++	info->ndtr0cs0 = nand_readl(info, NDTR0CS0);
++	info->ndtr1cs0 = nand_readl(info, NDTR1CS0);
++}
++
++static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info)
++{
++	struct platform_device *pdev = info->pdev;
++	struct dma_slave_config	config;
++	dma_cap_mask_t mask;
++	struct pxad_param param;
++	int ret;
++
++	info->data_buff = kmalloc(info->buf_size, GFP_KERNEL);
++	if (info->data_buff == NULL)
++		return -ENOMEM;
++	if (use_dma == 0)
++		return 0;
++
++	ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
++	if (ret)
++		return ret;
++
++	sg_init_one(&info->sg, info->data_buff, info->buf_size);
++	dma_cap_zero(mask);
++	dma_cap_set(DMA_SLAVE, mask);
++	param.prio = PXAD_PRIO_LOWEST;
++	param.drcmr = info->drcmr_dat;
++	info->dma_chan = dma_request_slave_channel_compat(mask, pxad_filter_fn,
++							  &param, &pdev->dev,
++							  "data");
++	if (!info->dma_chan) {
++		dev_err(&pdev->dev, "unable to request data dma channel\n");
++		return -ENODEV;
++	}
++
++	memset(&config, 0, sizeof(config));
++	config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
++	config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
++	config.src_addr = info->mmio_phys + NDDB;
++	config.dst_addr = info->mmio_phys + NDDB;
++	config.src_maxburst = 32;
++	config.dst_maxburst = 32;
++	ret = dmaengine_slave_config(info->dma_chan, &config);
++	if (ret < 0) {
++		dev_err(&info->pdev->dev,
++			"dma channel configuration failed: %d\n",
++			ret);
++		return ret;
++	}
++
++	/*
++	 * Now that DMA buffers are allocated we turn on
++	 * DMA proper for I/O operations.
++	 */
++	info->use_dma = 1;
++	return 0;
++}
++
++static void pxa3xx_nand_free_buff(struct pxa3xx_nand_info *info)
++{
++	if (info->use_dma) {
++		dmaengine_terminate_all(info->dma_chan);
++		dma_release_channel(info->dma_chan);
++	}
++	kfree(info->data_buff);
++}
++
++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_ecc_ctrl *ecc = &chip->ecc;
++
++	if (strength == 1 && ecc_stepsize == 512 && page_size == 2048) {
++		info->nfullchunks = 1;
++		info->ntotalchunks = 1;
++		info->chunk_size = 2048;
++		info->spare_size = 40;
++		info->ecc_size = 24;
++		ecc->mode = NAND_ECC_HW;
++		ecc->size = 512;
++		ecc->strength = 1;
++
++	} else if (strength == 1 && ecc_stepsize == 512 && page_size == 512) {
++		info->nfullchunks = 1;
++		info->ntotalchunks = 1;
++		info->chunk_size = 512;
++		info->spare_size = 8;
++		info->ecc_size = 8;
++		ecc->mode = NAND_ECC_HW;
++		ecc->size = 512;
++		ecc->strength = 1;
++
++	/*
++	 * Required ECC: 4-bit correction per 512 bytes
++	 * Select: 16-bit correction per 2048 bytes
++	 */
++	} else if (strength == 4 && ecc_stepsize == 512 && page_size == 2048) {
++		info->ecc_bch = 1;
++		info->nfullchunks = 1;
++		info->ntotalchunks = 1;
++		info->chunk_size = 2048;
++		info->spare_size = 32;
++		info->ecc_size = 32;
++		ecc->mode = NAND_ECC_HW;
++		ecc->size = info->chunk_size;
++		mtd_set_ooblayout(mtd, &pxa3xx_ooblayout_ops);
++		ecc->strength = 16;
++
++	} else if (strength == 4 && ecc_stepsize == 512 && page_size == 4096) {
++		info->ecc_bch = 1;
++		info->nfullchunks = 2;
++		info->ntotalchunks = 2;
++		info->chunk_size = 2048;
++		info->spare_size = 32;
++		info->ecc_size = 32;
++		ecc->mode = NAND_ECC_HW;
++		ecc->size = info->chunk_size;
++		mtd_set_ooblayout(mtd, &pxa3xx_ooblayout_ops);
++		ecc->strength = 16;
++
++	/*
++	 * Required ECC: 8-bit correction per 512 bytes
++	 * Select: 16-bit correction per 1024 bytes
++	 */
++	} else if (strength == 8 && ecc_stepsize == 512 && page_size == 4096) {
++		info->ecc_bch = 1;
++		info->nfullchunks = 4;
++		info->ntotalchunks = 5;
++		info->chunk_size = 1024;
++		info->spare_size = 0;
++		info->last_chunk_size = 0;
++		info->last_spare_size = 64;
++		info->ecc_size = 32;
++		ecc->mode = NAND_ECC_HW;
++		ecc->size = info->chunk_size;
++		mtd_set_ooblayout(mtd, &pxa3xx_ooblayout_ops);
++		ecc->strength = 16;
++	} else {
++		dev_err(&info->pdev->dev,
++			"ECC strength %d at page size %d is not supported\n",
++			strength, page_size);
++		return -ENODEV;
++	}
++
++	dev_info(&info->pdev->dev, "ECC strength %d, ECC step size %d\n",
++		 ecc->strength, ecc->size);
++	return 0;
++}
++
++static int pxa3xx_nand_scan(struct mtd_info *mtd)
++{
++	struct nand_chip *chip = mtd_to_nand(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;
++	struct pxa3xx_nand_platform_data *pdata = dev_get_platdata(&pdev->dev);
++	int ret;
++	uint16_t ecc_strength, ecc_step;
++
++	if (pdata->keep_config) {
++		pxa3xx_nand_detect_config(info);
++	} else {
++		ret = pxa3xx_nand_config_ident(info);
++		if (ret)
++			return ret;
++	}
++
++	if (info->reg_ndcr & NDCR_DWIDTH_M)
++		chip->options |= NAND_BUSWIDTH_16;
++
++	/* Device detection must be done with ECC disabled */
++	if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370)
++		nand_writel(info, NDECCCTRL, 0x0);
++
++	if (pdata->flash_bbt)
++		chip->bbt_options |= NAND_BBT_USE_FLASH;
++
++	chip->ecc.strength = pdata->ecc_strength;
++	chip->ecc.size = pdata->ecc_step_size;
++
++	ret = nand_scan_ident(mtd, 1, NULL);
++	if (ret)
++		return ret;
++
++	if (!pdata->keep_config) {
++		ret = pxa3xx_nand_init(host);
++		if (ret) {
++			dev_err(&info->pdev->dev, "Failed to init nand: %d\n",
++				ret);
++			return ret;
++		}
++	}
++
++	if (chip->bbt_options & NAND_BBT_USE_FLASH) {
++		/*
++		 * We'll use a bad block table stored in-flash and don't
++		 * allow writing the bad block marker to the flash.
++		 */
++		chip->bbt_options |= NAND_BBT_NO_OOB_BBM;
++		chip->bbt_td = &bbt_main_descr;
++		chip->bbt_md = &bbt_mirror_descr;
++	}
++
++	/*
++	 * If the page size is bigger than the FIFO size, let's check
++	 * we are given the right variant and then switch to the extended
++	 * (aka splitted) command handling,
++	 */
++	if (mtd->writesize > PAGE_CHUNK_SIZE) {
++		if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370) {
++			chip->cmdfunc = nand_cmdfunc_extended;
++		} else {
++			dev_err(&info->pdev->dev,
++				"unsupported page size on this variant\n");
++			return -ENODEV;
++		}
++	}
++
++	ecc_strength = chip->ecc.strength;
++	ecc_step = chip->ecc.size;
++	if (!ecc_strength || !ecc_step) {
++		ecc_strength = chip->ecc_strength_ds;
++		ecc_step = chip->ecc_step_ds;
++	}
++
++	/* Set default ECC strength requirements on non-ONFI devices */
++	if (ecc_strength < 1 && ecc_step < 1) {
++		ecc_strength = 1;
++		ecc_step = 512;
++	}
++
++	ret = pxa_ecc_init(info, mtd, ecc_strength,
++			   ecc_step, mtd->writesize);
++	if (ret)
++		return ret;
++
++	/* calculate addressing information */
++	if (mtd->writesize >= 2048)
++		host->col_addr_cycles = 2;
++	else
++		host->col_addr_cycles = 1;
++
++	/* release the initial buffer */
++	kfree(info->data_buff);
++
++	/* allocate the real data + oob buffer */
++	info->buf_size = mtd->writesize + mtd->oobsize;
++	ret = pxa3xx_nand_init_buff(info);
++	if (ret)
++		return ret;
++	info->oob_buff = info->data_buff + mtd->writesize;
++
++	if ((mtd->size >> chip->page_shift) > 65536)
++		host->row_addr_cycles = 3;
++	else
++		host->row_addr_cycles = 2;
++
++	if (!pdata->keep_config)
++		pxa3xx_nand_config_tail(info);
++
++	return nand_scan_tail(mtd);
++}
++
++static int alloc_nand_resource(struct platform_device *pdev)
++{
++	struct device_node *np = pdev->dev.of_node;
++	struct pxa3xx_nand_platform_data *pdata;
++	struct pxa3xx_nand_info *info;
++	struct pxa3xx_nand_host *host;
++	struct nand_chip *chip = NULL;
++	struct mtd_info *mtd;
++	struct resource *r;
++	int ret, irq, cs;
++
++	pdata = dev_get_platdata(&pdev->dev);
++	if (pdata->num_cs <= 0) {
++		dev_err(&pdev->dev, "invalid number of chip selects\n");
++		return -ENODEV;
++	}
++
++	info = devm_kzalloc(&pdev->dev,
++			    sizeof(*info) + sizeof(*host) * pdata->num_cs,
++			    GFP_KERNEL);
++	if (!info)
++		return -ENOMEM;
++
++	info->pdev = pdev;
++	info->variant = pxa3xx_nand_get_variant(pdev);
++	for (cs = 0; cs < pdata->num_cs; cs++) {
++		host = (void *)&info[1] + sizeof(*host) * cs;
++		chip = &host->chip;
++		nand_set_controller_data(chip, host);
++		mtd = nand_to_mtd(chip);
++		info->host[cs] = host;
++		host->cs = cs;
++		host->info_data = info;
++		mtd->dev.parent = &pdev->dev;
++		/* FIXME: all chips use the same device tree partitions */
++		nand_set_flash_node(chip, np);
++
++		nand_set_controller_data(chip, host);
++		chip->ecc.read_page	= pxa3xx_nand_read_page_hwecc;
++		chip->ecc.write_page	= pxa3xx_nand_write_page_hwecc;
++		chip->controller        = &info->controller;
++		chip->waitfunc		= pxa3xx_nand_waitfunc;
++		chip->select_chip	= pxa3xx_nand_select_chip;
++		chip->read_word		= pxa3xx_nand_read_word;
++		chip->read_byte		= pxa3xx_nand_read_byte;
++		chip->read_buf		= pxa3xx_nand_read_buf;
++		chip->write_buf		= pxa3xx_nand_write_buf;
++		chip->options		|= NAND_NO_SUBPAGE_WRITE;
++		chip->cmdfunc		= nand_cmdfunc;
++		chip->onfi_set_features	= nand_onfi_get_set_features_notsupp;
++		chip->onfi_get_features	= nand_onfi_get_set_features_notsupp;
++	}
++
++	nand_hw_control_init(chip->controller);
++	info->clk = devm_clk_get(&pdev->dev, NULL);
++	if (IS_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)
++		return ret;
++
++	if (!np && use_dma) {
++		r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
++		if (r == NULL) {
++			dev_err(&pdev->dev,
++				"no resource defined for data DMA\n");
++			ret = -ENXIO;
++			goto fail_disable_clk;
++		}
++		info->drcmr_dat = r->start;
++	}
++
++	irq = platform_get_irq(pdev, 0);
++	if (irq < 0) {
++		dev_err(&pdev->dev, "no IRQ resource defined\n");
++		ret = -ENXIO;
++		goto fail_disable_clk;
++	}
++
++	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	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;
++
++	/* Allocate a buffer to allow flash detection */
++	info->buf_size = INIT_BUFFER_SIZE;
++	info->data_buff = kmalloc(info->buf_size, GFP_KERNEL);
++	if (info->data_buff == NULL) {
++		ret = -ENOMEM;
++		goto fail_disable_clk;
++	}
++
++	/* initialize all interrupts to be disabled */
++	disable_int(info, NDSR_MASK);
++
++	ret = request_threaded_irq(irq, pxa3xx_nand_irq,
++				   pxa3xx_nand_irq_thread, IRQF_ONESHOT,
++				   pdev->name, info);
++	if (ret < 0) {
++		dev_err(&pdev->dev, "failed to request IRQ: %d\n", ret);
++		goto fail_free_buf;
++	}
++
++	platform_set_drvdata(pdev, info);
++
++	return 0;
++
++fail_free_buf:
++	free_irq(irq, info);
++	kfree(info->data_buff);
++fail_disable_clk:
++	clk_disable_unprepare(info->clk);
++	return ret;
++}
++
++static int pxa3xx_nand_remove(struct platform_device *pdev)
++{
++	struct pxa3xx_nand_info *info = platform_get_drvdata(pdev);
++	struct pxa3xx_nand_platform_data *pdata;
++	int irq, cs;
++
++	if (!info)
++		return 0;
++
++	pdata = dev_get_platdata(&pdev->dev);
++
++	irq = platform_get_irq(pdev, 0);
++	if (irq >= 0)
++		free_irq(irq, info);
++	pxa3xx_nand_free_buff(info);
++
++	/*
++	 * In the pxa3xx case, the DFI bus is shared between the SMC and NFC.
++	 * In order to prevent a lockup of the system bus, the DFI bus
++	 * arbitration is granted to SMC upon driver removal. This is done by
++	 * setting the x_ARB_CNTL bit, which also prevents the NAND to have
++	 * access to the bus anymore.
++	 */
++	nand_writel(info, NDCR,
++		    (nand_readl(info, NDCR) & ~NDCR_ND_ARB_EN) |
++		    NFCV1_NDCR_ARB_CNTL);
++	clk_disable_unprepare(info->clk);
++
++	for (cs = 0; cs < pdata->num_cs; cs++)
++		nand_release(nand_to_mtd(&info->host[cs]->chip));
++	return 0;
++}
++
++static int pxa3xx_nand_probe_dt(struct platform_device *pdev)
++{
++	struct pxa3xx_nand_platform_data *pdata;
++	struct device_node *np = pdev->dev.of_node;
++	const struct of_device_id *of_id =
++			of_match_device(pxa3xx_nand_dt_ids, &pdev->dev);
++
++	if (!of_id)
++		return 0;
++
++	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
++	if (!pdata)
++		return -ENOMEM;
++
++	if (of_get_property(np, "marvell,nand-enable-arbiter", NULL))
++		pdata->enable_arbiter = 1;
++	if (of_get_property(np, "marvell,nand-keep-config", NULL))
++		pdata->keep_config = 1;
++	of_property_read_u32(np, "num-cs", &pdata->num_cs);
++
++	pdev->dev.platform_data = pdata;
++
++	return 0;
++}
++
++static int pxa3xx_nand_probe(struct platform_device *pdev)
++{
++	struct pxa3xx_nand_platform_data *pdata;
++	struct pxa3xx_nand_info *info;
++	int ret, cs, probe_success, dma_available;
++
++	dma_available = IS_ENABLED(CONFIG_ARM) &&
++		(IS_ENABLED(CONFIG_ARCH_PXA) || IS_ENABLED(CONFIG_ARCH_MMP));
++	if (use_dma && !dma_available) {
++		use_dma = 0;
++		dev_warn(&pdev->dev,
++			 "This platform can't do DMA on this device\n");
++	}
++
++	ret = pxa3xx_nand_probe_dt(pdev);
++	if (ret)
++		return ret;
++
++	pdata = dev_get_platdata(&pdev->dev);
++	if (!pdata) {
++		dev_err(&pdev->dev, "no platform data defined\n");
++		return -ENODEV;
++	}
++
++	ret = alloc_nand_resource(pdev);
++	if (ret)
++		return ret;
++
++	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);
++
++		/*
++		 * The mtd name matches the one used in 'mtdparts' kernel
++		 * parameter. This name cannot be changed or otherwise
++		 * user's mtd partitions configuration would get broken.
++		 */
++		mtd->name = "pxa3xx_nand-0";
++		info->cs = cs;
++		ret = pxa3xx_nand_scan(mtd);
++		if (ret) {
++			dev_warn(&pdev->dev, "failed to scan nand at cs %d\n",
++				cs);
++			continue;
++		}
++
++		ret = mtd_device_register(mtd, pdata->parts[cs],
++					  pdata->nr_parts[cs]);
++		if (!ret)
++			probe_success = 1;
++	}
++
++	if (!probe_success) {
++		pxa3xx_nand_remove(pdev);
++		return -ENODEV;
++	}
++
++	return 0;
++}
++
++#ifdef CONFIG_PM
++static int pxa3xx_nand_suspend(struct device *dev)
++{
++	struct pxa3xx_nand_info *info = dev_get_drvdata(dev);
++
++	if (info->state) {
++		dev_err(dev, "driver busy, state = %d\n", info->state);
++		return -EAGAIN;
++	}
++
++	clk_disable(info->clk);
++	return 0;
++}
++
++static int pxa3xx_nand_resume(struct device *dev)
++{
++	struct pxa3xx_nand_info *info = dev_get_drvdata(dev);
++	int ret;
++
++	ret = clk_enable(info->clk);
++	if (ret < 0)
++		return ret;
++
++	/* We don't want to handle interrupt without calling mtd routine */
++	disable_int(info, NDCR_INT_MASK);
++
++	/*
++	 * Directly set the chip select to a invalid value,
++	 * then the driver would reset the timing according
++	 * to current chip select at the beginning of cmdfunc
++	 */
++	info->cs = 0xff;
++
++	/*
++	 * As the spec says, the NDSR would be updated to 0x1800 when
++	 * doing the nand_clk disable/enable.
++	 * To prevent it damaging state machine of the driver, clear
++	 * all status before resume
++	 */
++	nand_writel(info, NDSR, NDSR_MASK);
++
++	return 0;
++}
++#else
++#define pxa3xx_nand_suspend	NULL
++#define pxa3xx_nand_resume	NULL
++#endif
++
++static const struct dev_pm_ops pxa3xx_nand_pm_ops = {
++	.suspend	= pxa3xx_nand_suspend,
++	.resume		= pxa3xx_nand_resume,
++};
++
++static struct platform_driver pxa3xx_nand_driver = {
++	.driver = {
++		.name	= "pxa3xx-nand",
++		.of_match_table = pxa3xx_nand_dt_ids,
++		.pm	= &pxa3xx_nand_pm_ops,
++	},
++	.probe		= pxa3xx_nand_probe,
++	.remove		= pxa3xx_nand_remove,
++};
++
++module_platform_driver(pxa3xx_nand_driver);
++
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("PXA3xx NAND controller driver");
+diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c
+new file mode 100644
+index 0000000..3baddfc
+--- /dev/null
++++ b/drivers/mtd/nand/raw/qcom_nandc.c
+@@ -0,0 +1,2821 @@
++/*
++ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * 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/clk.h>
++#include <linux/slab.h>
++#include <linux/bitops.h>
++#include <linux/dma-mapping.h>
++#include <linux/dmaengine.h>
++#include <linux/module.h>
++#include <linux/mtd/rawnand.h>
++#include <linux/mtd/partitions.h>
++#include <linux/of.h>
++#include <linux/of_device.h>
++#include <linux/delay.h>
++
++/* NANDc reg offsets */
++#define	NAND_FLASH_CMD			0x00
++#define	NAND_ADDR0			0x04
++#define	NAND_ADDR1			0x08
++#define	NAND_FLASH_CHIP_SELECT		0x0c
++#define	NAND_EXEC_CMD			0x10
++#define	NAND_FLASH_STATUS		0x14
++#define	NAND_BUFFER_STATUS		0x18
++#define	NAND_DEV0_CFG0			0x20
++#define	NAND_DEV0_CFG1			0x24
++#define	NAND_DEV0_ECC_CFG		0x28
++#define	NAND_DEV1_ECC_CFG		0x2c
++#define	NAND_DEV1_CFG0			0x30
++#define	NAND_DEV1_CFG1			0x34
++#define	NAND_READ_ID			0x40
++#define	NAND_READ_STATUS		0x44
++#define	NAND_DEV_CMD0			0xa0
++#define	NAND_DEV_CMD1			0xa4
++#define	NAND_DEV_CMD2			0xa8
++#define	NAND_DEV_CMD_VLD		0xac
++#define	SFLASHC_BURST_CFG		0xe0
++#define	NAND_ERASED_CW_DETECT_CFG	0xe8
++#define	NAND_ERASED_CW_DETECT_STATUS	0xec
++#define	NAND_EBI2_ECC_BUF_CFG		0xf0
++#define	FLASH_BUF_ACC			0x100
++
++#define	NAND_CTRL			0xf00
++#define	NAND_VERSION			0xf08
++#define	NAND_READ_LOCATION_0		0xf20
++#define	NAND_READ_LOCATION_1		0xf24
++#define	NAND_READ_LOCATION_2		0xf28
++#define	NAND_READ_LOCATION_3		0xf2c
++
++/* dummy register offsets, used by write_reg_dma */
++#define	NAND_DEV_CMD1_RESTORE		0xdead
++#define	NAND_DEV_CMD_VLD_RESTORE	0xbeef
++
++/* NAND_FLASH_CMD bits */
++#define	PAGE_ACC			BIT(4)
++#define	LAST_PAGE			BIT(5)
++
++/* NAND_FLASH_CHIP_SELECT bits */
++#define	NAND_DEV_SEL			0
++#define	DM_EN				BIT(2)
++
++/* NAND_FLASH_STATUS bits */
++#define	FS_OP_ERR			BIT(4)
++#define	FS_READY_BSY_N			BIT(5)
++#define	FS_MPU_ERR			BIT(8)
++#define	FS_DEVICE_STS_ERR		BIT(16)
++#define	FS_DEVICE_WP			BIT(23)
++
++/* NAND_BUFFER_STATUS bits */
++#define	BS_UNCORRECTABLE_BIT		BIT(8)
++#define	BS_CORRECTABLE_ERR_MSK		0x1f
++
++/* NAND_DEVn_CFG0 bits */
++#define	DISABLE_STATUS_AFTER_WRITE	4
++#define	CW_PER_PAGE			6
++#define	UD_SIZE_BYTES			9
++#define	ECC_PARITY_SIZE_BYTES_RS	19
++#define	SPARE_SIZE_BYTES		23
++#define	NUM_ADDR_CYCLES			27
++#define	STATUS_BFR_READ			30
++#define	SET_RD_MODE_AFTER_STATUS	31
++
++/* NAND_DEVn_CFG0 bits */
++#define	DEV0_CFG1_ECC_DISABLE		0
++#define	WIDE_FLASH			1
++#define	NAND_RECOVERY_CYCLES		2
++#define	CS_ACTIVE_BSY			5
++#define	BAD_BLOCK_BYTE_NUM		6
++#define	BAD_BLOCK_IN_SPARE_AREA		16
++#define	WR_RD_BSY_GAP			17
++#define	ENABLE_BCH_ECC			27
++
++/* NAND_DEV0_ECC_CFG bits */
++#define	ECC_CFG_ECC_DISABLE		0
++#define	ECC_SW_RESET			1
++#define	ECC_MODE			4
++#define	ECC_PARITY_SIZE_BYTES_BCH	8
++#define	ECC_NUM_DATA_BYTES		16
++#define	ECC_FORCE_CLK_OPEN		30
++
++/* NAND_DEV_CMD1 bits */
++#define	READ_ADDR			0
++
++/* NAND_DEV_CMD_VLD bits */
++#define	READ_START_VLD			BIT(0)
++#define	READ_STOP_VLD			BIT(1)
++#define	WRITE_START_VLD			BIT(2)
++#define	ERASE_START_VLD			BIT(3)
++#define	SEQ_READ_START_VLD		BIT(4)
++
++/* NAND_EBI2_ECC_BUF_CFG bits */
++#define	NUM_STEPS			0
++
++/* NAND_ERASED_CW_DETECT_CFG bits */
++#define	ERASED_CW_ECC_MASK		1
++#define	AUTO_DETECT_RES			0
++#define	MASK_ECC			(1 << ERASED_CW_ECC_MASK)
++#define	RESET_ERASED_DET		(1 << AUTO_DETECT_RES)
++#define	ACTIVE_ERASED_DET		(0 << AUTO_DETECT_RES)
++#define	CLR_ERASED_PAGE_DET		(RESET_ERASED_DET | MASK_ECC)
++#define	SET_ERASED_PAGE_DET		(ACTIVE_ERASED_DET | MASK_ECC)
++
++/* NAND_ERASED_CW_DETECT_STATUS bits */
++#define	PAGE_ALL_ERASED			BIT(7)
++#define	CODEWORD_ALL_ERASED		BIT(6)
++#define	PAGE_ERASED			BIT(5)
++#define	CODEWORD_ERASED			BIT(4)
++#define	ERASED_PAGE			(PAGE_ALL_ERASED | PAGE_ERASED)
++#define	ERASED_CW			(CODEWORD_ALL_ERASED | CODEWORD_ERASED)
++
++/* NAND_READ_LOCATION_n bits */
++#define READ_LOCATION_OFFSET		0
++#define READ_LOCATION_SIZE		16
++#define READ_LOCATION_LAST		31
++
++/* Version Mask */
++#define	NAND_VERSION_MAJOR_MASK		0xf0000000
++#define	NAND_VERSION_MAJOR_SHIFT	28
++#define	NAND_VERSION_MINOR_MASK		0x0fff0000
++#define	NAND_VERSION_MINOR_SHIFT	16
++
++/* NAND OP_CMDs */
++#define	PAGE_READ			0x2
++#define	PAGE_READ_WITH_ECC		0x3
++#define	PAGE_READ_WITH_ECC_SPARE	0x4
++#define	PROGRAM_PAGE			0x6
++#define	PAGE_PROGRAM_WITH_ECC		0x7
++#define	PROGRAM_PAGE_SPARE		0x9
++#define	BLOCK_ERASE			0xa
++#define	FETCH_ID			0xb
++#define	RESET_DEVICE			0xd
++
++/* Default Value for NAND_DEV_CMD_VLD */
++#define NAND_DEV_CMD_VLD_VAL		(READ_START_VLD | WRITE_START_VLD | \
++					 ERASE_START_VLD | SEQ_READ_START_VLD)
++
++/* NAND_CTRL bits */
++#define	BAM_MODE_EN			BIT(0)
++
++/*
++ * the NAND controller performs reads/writes with ECC in 516 byte chunks.
++ * the driver calls the chunks 'step' or 'codeword' interchangeably
++ */
++#define	NANDC_STEP_SIZE			512
++
++/*
++ * the largest page size we support is 8K, this will have 16 steps/codewords
++ * of 512 bytes each
++ */
++#define	MAX_NUM_STEPS			(SZ_8K / NANDC_STEP_SIZE)
++
++/* we read at most 3 registers per codeword scan */
++#define	MAX_REG_RD			(3 * MAX_NUM_STEPS)
++
++/* ECC modes supported by the controller */
++#define	ECC_NONE	BIT(0)
++#define	ECC_RS_4BIT	BIT(1)
++#define	ECC_BCH_4BIT	BIT(2)
++#define	ECC_BCH_8BIT	BIT(3)
++
++#define nandc_set_read_loc(nandc, reg, offset, size, is_last)	\
++nandc_set_reg(nandc, NAND_READ_LOCATION_##reg,			\
++	      ((offset) << READ_LOCATION_OFFSET) |		\
++	      ((size) << READ_LOCATION_SIZE) |			\
++	      ((is_last) << READ_LOCATION_LAST))
++
++/*
++ * Returns the actual register address for all NAND_DEV_ registers
++ * (i.e. NAND_DEV_CMD0, NAND_DEV_CMD1, NAND_DEV_CMD2 and NAND_DEV_CMD_VLD)
++ */
++#define dev_cmd_reg_addr(nandc, reg) ((nandc)->props->dev_cmd_reg_start + (reg))
++
++#define QPIC_PER_CW_CMD_SGL		32
++#define QPIC_PER_CW_DATA_SGL		8
++
++/*
++ * Flags used in DMA descriptor preparation helper functions
++ * (i.e. read_reg_dma/write_reg_dma/read_data_dma/write_data_dma)
++ */
++/* Don't set the EOT in current tx BAM sgl */
++#define NAND_BAM_NO_EOT			BIT(0)
++/* Set the NWD flag in current BAM sgl */
++#define NAND_BAM_NWD			BIT(1)
++/* Finish writing in the current BAM sgl and start writing in another BAM sgl */
++#define NAND_BAM_NEXT_SGL		BIT(2)
++/*
++ * Erased codeword status is being used two times in single transfer so this
++ * flag will determine the current value of erased codeword status register
++ */
++#define NAND_ERASED_CW_SET		BIT(4)
++
++/*
++ * This data type corresponds to the BAM transaction which will be used for all
++ * NAND transfers.
++ * @cmd_sgl - sgl for NAND BAM command pipe
++ * @data_sgl - sgl for NAND BAM consumer/producer pipe
++ * @cmd_sgl_pos - current index in command sgl.
++ * @cmd_sgl_start - start index in command sgl.
++ * @tx_sgl_pos - current index in data sgl for tx.
++ * @tx_sgl_start - start index in data sgl for tx.
++ * @rx_sgl_pos - current index in data sgl for rx.
++ * @rx_sgl_start - start index in data sgl for rx.
++ */
++struct bam_transaction {
++	struct scatterlist *cmd_sgl;
++	struct scatterlist *data_sgl;
++	u32 cmd_sgl_pos;
++	u32 cmd_sgl_start;
++	u32 tx_sgl_pos;
++	u32 tx_sgl_start;
++	u32 rx_sgl_pos;
++	u32 rx_sgl_start;
++};
++
++/*
++ * This data type corresponds to the nand dma descriptor
++ * @list - list for desc_info
++ * @dir - DMA transfer direction
++ * @adm_sgl - sgl which will be used for single sgl dma descriptor. Only used by
++ *	      ADM
++ * @bam_sgl - sgl which will be used for dma descriptor. Only used by BAM
++ * @sgl_cnt - number of SGL in bam_sgl. Only used by BAM
++ * @dma_desc - low level DMA engine descriptor
++ */
++struct desc_info {
++	struct list_head node;
++
++	enum dma_data_direction dir;
++	union {
++		struct scatterlist adm_sgl;
++		struct {
++			struct scatterlist *bam_sgl;
++			int sgl_cnt;
++		};
++	};
++	struct dma_async_tx_descriptor *dma_desc;
++};
++
++/*
++ * holds the current register values that we want to write. acts as a contiguous
++ * chunk of memory which we use to write the controller registers through DMA.
++ */
++struct nandc_regs {
++	__le32 cmd;
++	__le32 addr0;
++	__le32 addr1;
++	__le32 chip_sel;
++	__le32 exec;
++
++	__le32 cfg0;
++	__le32 cfg1;
++	__le32 ecc_bch_cfg;
++
++	__le32 clrflashstatus;
++	__le32 clrreadstatus;
++
++	__le32 cmd1;
++	__le32 vld;
++
++	__le32 orig_cmd1;
++	__le32 orig_vld;
++
++	__le32 ecc_buf_cfg;
++	__le32 read_location0;
++	__le32 read_location1;
++	__le32 read_location2;
++	__le32 read_location3;
++
++	__le32 erased_cw_detect_cfg_clr;
++	__le32 erased_cw_detect_cfg_set;
++};
++
++/*
++ * NAND controller data struct
++ *
++ * @controller:			base controller structure
++ * @host_list:			list containing all the chips attached to the
++ *				controller
++ * @dev:			parent device
++ * @base:			MMIO base
++ * @base_dma:			physical base address of controller registers
++ * @core_clk:			controller clock
++ * @aon_clk:			another controller clock
++ *
++ * @chan:			dma channel
++ * @cmd_crci:			ADM DMA CRCI for command flow control
++ * @data_crci:			ADM DMA CRCI for data flow control
++ * @desc_list:			DMA descriptor list (list of desc_infos)
++ *
++ * @data_buffer:		our local DMA buffer for page read/writes,
++ *				used when we can't use the buffer provided
++ *				by upper layers directly
++ * @buf_size/count/start:	markers for chip->read_buf/write_buf functions
++ * @reg_read_buf:		local buffer for reading back registers via DMA
++ * @reg_read_dma:		contains dma address for register read buffer
++ * @reg_read_pos:		marker for data read in reg_read_buf
++ *
++ * @regs:			a contiguous chunk of memory for DMA register
++ *				writes. contains the register values to be
++ *				written to controller
++ * @cmd1/vld:			some fixed controller register values
++ * @props:			properties of current NAND controller,
++ *				initialized via DT match data
++ * @max_cwperpage:		maximum QPIC codewords required. calculated
++ *				from all connected NAND devices pagesize
++ */
++struct qcom_nand_controller {
++	struct nand_hw_control controller;
++	struct list_head host_list;
++
++	struct device *dev;
++
++	void __iomem *base;
++	dma_addr_t base_dma;
++
++	struct clk *core_clk;
++	struct clk *aon_clk;
++
++	union {
++		/* will be used only by QPIC for BAM DMA */
++		struct {
++			struct dma_chan *tx_chan;
++			struct dma_chan *rx_chan;
++			struct dma_chan *cmd_chan;
++		};
++
++		/* will be used only by EBI2 for ADM DMA */
++		struct {
++			struct dma_chan *chan;
++			unsigned int cmd_crci;
++			unsigned int data_crci;
++		};
++	};
++
++	struct list_head desc_list;
++	struct bam_transaction *bam_txn;
++
++	u8		*data_buffer;
++	int		buf_size;
++	int		buf_count;
++	int		buf_start;
++	unsigned int	max_cwperpage;
++
++	__le32 *reg_read_buf;
++	dma_addr_t reg_read_dma;
++	int reg_read_pos;
++
++	struct nandc_regs *regs;
++
++	u32 cmd1, vld;
++	const struct qcom_nandc_props *props;
++};
++
++/*
++ * NAND chip structure
++ *
++ * @chip:			base NAND chip structure
++ * @node:			list node to add itself to host_list in
++ *				qcom_nand_controller
++ *
++ * @cs:				chip select value for this chip
++ * @cw_size:			the number of bytes in a single step/codeword
++ *				of a page, consisting of all data, ecc, spare
++ *				and reserved bytes
++ * @cw_data:			the number of bytes within a codeword protected
++ *				by ECC
++ * @use_ecc:			request the controller to use ECC for the
++ *				upcoming read/write
++ * @bch_enabled:		flag to tell whether BCH ECC mode is used
++ * @ecc_bytes_hw:		ECC bytes used by controller hardware for this
++ *				chip
++ * @status:			value to be returned if NAND_CMD_STATUS command
++ *				is executed
++ * @last_command:		keeps track of last command on this chip. used
++ *				for reading correct status
++ *
++ * @cfg0, cfg1, cfg0_raw..:	NANDc register configurations needed for
++ *				ecc/non-ecc mode for the current nand flash
++ *				device
++ */
++struct qcom_nand_host {
++	struct nand_chip chip;
++	struct list_head node;
++
++	int cs;
++	int cw_size;
++	int cw_data;
++	bool use_ecc;
++	bool bch_enabled;
++	int ecc_bytes_hw;
++	int spare_bytes;
++	int bbm_size;
++	u8 status;
++	int last_command;
++
++	u32 cfg0, cfg1;
++	u32 cfg0_raw, cfg1_raw;
++	u32 ecc_buf_cfg;
++	u32 ecc_bch_cfg;
++	u32 clrflashstatus;
++	u32 clrreadstatus;
++};
++
++/*
++ * This data type corresponds to the NAND controller properties which varies
++ * among different NAND controllers.
++ * @ecc_modes - ecc mode for NAND
++ * @is_bam - whether NAND controller is using BAM
++ * @dev_cmd_reg_start - NAND_DEV_CMD_* registers starting offset
++ */
++struct qcom_nandc_props {
++	u32 ecc_modes;
++	bool is_bam;
++	u32 dev_cmd_reg_start;
++};
++
++/* Frees the BAM transaction memory */
++static void free_bam_transaction(struct qcom_nand_controller *nandc)
++{
++	struct bam_transaction *bam_txn = nandc->bam_txn;
++
++	devm_kfree(nandc->dev, bam_txn);
++}
++
++/* Allocates and Initializes the BAM transaction */
++static struct bam_transaction *
++alloc_bam_transaction(struct qcom_nand_controller *nandc)
++{
++	struct bam_transaction *bam_txn;
++	size_t bam_txn_size;
++	unsigned int num_cw = nandc->max_cwperpage;
++	void *bam_txn_buf;
++
++	bam_txn_size =
++		sizeof(*bam_txn) + num_cw *
++		((sizeof(*bam_txn->cmd_sgl) * QPIC_PER_CW_CMD_SGL) +
++		(sizeof(*bam_txn->data_sgl) * QPIC_PER_CW_DATA_SGL));
++
++	bam_txn_buf = devm_kzalloc(nandc->dev, bam_txn_size, GFP_KERNEL);
++	if (!bam_txn_buf)
++		return NULL;
++
++	bam_txn = bam_txn_buf;
++	bam_txn_buf += sizeof(*bam_txn);
++
++	bam_txn->cmd_sgl = bam_txn_buf;
++	bam_txn_buf +=
++		sizeof(*bam_txn->cmd_sgl) * QPIC_PER_CW_CMD_SGL * num_cw;
++
++	bam_txn->data_sgl = bam_txn_buf;
++
++	return bam_txn;
++}
++
++/* Clears the BAM transaction indexes */
++static void clear_bam_transaction(struct qcom_nand_controller *nandc)
++{
++	struct bam_transaction *bam_txn = nandc->bam_txn;
++
++	if (!nandc->props->is_bam)
++		return;
++
++	bam_txn->cmd_sgl_pos = 0;
++	bam_txn->cmd_sgl_start = 0;
++	bam_txn->tx_sgl_pos = 0;
++	bam_txn->tx_sgl_start = 0;
++	bam_txn->rx_sgl_pos = 0;
++	bam_txn->rx_sgl_start = 0;
++
++	sg_init_table(bam_txn->cmd_sgl, nandc->max_cwperpage *
++		      QPIC_PER_CW_CMD_SGL);
++	sg_init_table(bam_txn->data_sgl, nandc->max_cwperpage *
++		      QPIC_PER_CW_DATA_SGL);
++}
++
++static inline struct qcom_nand_host *to_qcom_nand_host(struct nand_chip *chip)
++{
++	return container_of(chip, struct qcom_nand_host, chip);
++}
++
++static inline struct qcom_nand_controller *
++get_qcom_nand_controller(struct nand_chip *chip)
++{
++	return container_of(chip->controller, struct qcom_nand_controller,
++			    controller);
++}
++
++static inline u32 nandc_read(struct qcom_nand_controller *nandc, int offset)
++{
++	return ioread32(nandc->base + offset);
++}
++
++static inline void nandc_write(struct qcom_nand_controller *nandc, int offset,
++			       u32 val)
++{
++	iowrite32(val, nandc->base + offset);
++}
++
++static inline void nandc_read_buffer_sync(struct qcom_nand_controller *nandc,
++					  bool is_cpu)
++{
++	if (!nandc->props->is_bam)
++		return;
++
++	if (is_cpu)
++		dma_sync_single_for_cpu(nandc->dev, nandc->reg_read_dma,
++					MAX_REG_RD *
++					sizeof(*nandc->reg_read_buf),
++					DMA_FROM_DEVICE);
++	else
++		dma_sync_single_for_device(nandc->dev, nandc->reg_read_dma,
++					   MAX_REG_RD *
++					   sizeof(*nandc->reg_read_buf),
++					   DMA_FROM_DEVICE);
++}
++
++static __le32 *offset_to_nandc_reg(struct nandc_regs *regs, int offset)
++{
++	switch (offset) {
++	case NAND_FLASH_CMD:
++		return &regs->cmd;
++	case NAND_ADDR0:
++		return &regs->addr0;
++	case NAND_ADDR1:
++		return &regs->addr1;
++	case NAND_FLASH_CHIP_SELECT:
++		return &regs->chip_sel;
++	case NAND_EXEC_CMD:
++		return &regs->exec;
++	case NAND_FLASH_STATUS:
++		return &regs->clrflashstatus;
++	case NAND_DEV0_CFG0:
++		return &regs->cfg0;
++	case NAND_DEV0_CFG1:
++		return &regs->cfg1;
++	case NAND_DEV0_ECC_CFG:
++		return &regs->ecc_bch_cfg;
++	case NAND_READ_STATUS:
++		return &regs->clrreadstatus;
++	case NAND_DEV_CMD1:
++		return &regs->cmd1;
++	case NAND_DEV_CMD1_RESTORE:
++		return &regs->orig_cmd1;
++	case NAND_DEV_CMD_VLD:
++		return &regs->vld;
++	case NAND_DEV_CMD_VLD_RESTORE:
++		return &regs->orig_vld;
++	case NAND_EBI2_ECC_BUF_CFG:
++		return &regs->ecc_buf_cfg;
++	case NAND_READ_LOCATION_0:
++		return &regs->read_location0;
++	case NAND_READ_LOCATION_1:
++		return &regs->read_location1;
++	case NAND_READ_LOCATION_2:
++		return &regs->read_location2;
++	case NAND_READ_LOCATION_3:
++		return &regs->read_location3;
++	default:
++		return NULL;
++	}
++}
++
++static void nandc_set_reg(struct qcom_nand_controller *nandc, int offset,
++			  u32 val)
++{
++	struct nandc_regs *regs = nandc->regs;
++	__le32 *reg;
++
++	reg = offset_to_nandc_reg(regs, offset);
++
++	if (reg)
++		*reg = cpu_to_le32(val);
++}
++
++/* helper to configure address register values */
++static void set_address(struct qcom_nand_host *host, u16 column, int page)
++{
++	struct nand_chip *chip = &host->chip;
++	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
++
++	if (chip->options & NAND_BUSWIDTH_16)
++		column >>= 1;
++
++	nandc_set_reg(nandc, NAND_ADDR0, page << 16 | column);
++	nandc_set_reg(nandc, NAND_ADDR1, page >> 16 & 0xff);
++}
++
++/*
++ * update_rw_regs:	set up read/write register values, these will be
++ *			written to the NAND controller registers via DMA
++ *
++ * @num_cw:		number of steps for the read/write operation
++ * @read:		read or write operation
++ */
++static void update_rw_regs(struct qcom_nand_host *host, int num_cw, bool read)
++{
++	struct nand_chip *chip = &host->chip;
++	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
++	u32 cmd, cfg0, cfg1, ecc_bch_cfg;
++
++	if (read) {
++		if (host->use_ecc)
++			cmd = PAGE_READ_WITH_ECC | PAGE_ACC | LAST_PAGE;
++		else
++			cmd = PAGE_READ | PAGE_ACC | LAST_PAGE;
++	} else {
++			cmd = PROGRAM_PAGE | PAGE_ACC | LAST_PAGE;
++	}
++
++	if (host->use_ecc) {
++		cfg0 = (host->cfg0 & ~(7U << CW_PER_PAGE)) |
++				(num_cw - 1) << CW_PER_PAGE;
++
++		cfg1 = host->cfg1;
++		ecc_bch_cfg = host->ecc_bch_cfg;
++	} else {
++		cfg0 = (host->cfg0_raw & ~(7U << CW_PER_PAGE)) |
++				(num_cw - 1) << CW_PER_PAGE;
++
++		cfg1 = host->cfg1_raw;
++		ecc_bch_cfg = 1 << ECC_CFG_ECC_DISABLE;
++	}
++
++	nandc_set_reg(nandc, NAND_FLASH_CMD, cmd);
++	nandc_set_reg(nandc, NAND_DEV0_CFG0, cfg0);
++	nandc_set_reg(nandc, NAND_DEV0_CFG1, cfg1);
++	nandc_set_reg(nandc, NAND_DEV0_ECC_CFG, ecc_bch_cfg);
++	nandc_set_reg(nandc, NAND_EBI2_ECC_BUF_CFG, host->ecc_buf_cfg);
++	nandc_set_reg(nandc, NAND_FLASH_STATUS, host->clrflashstatus);
++	nandc_set_reg(nandc, NAND_READ_STATUS, host->clrreadstatus);
++	nandc_set_reg(nandc, NAND_EXEC_CMD, 1);
++
++	if (read)
++		nandc_set_read_loc(nandc, 0, 0, host->use_ecc ?
++				   host->cw_data : host->cw_size, 1);
++}
++
++/*
++ * Maps the scatter gather list for DMA transfer and forms the DMA descriptor
++ * for BAM. This descriptor will be added in the NAND DMA descriptor queue
++ * which will be submitted to DMA engine.
++ */
++static int prepare_bam_async_desc(struct qcom_nand_controller *nandc,
++				  struct dma_chan *chan,
++				  unsigned long flags)
++{
++	struct desc_info *desc;
++	struct scatterlist *sgl;
++	unsigned int sgl_cnt;
++	int ret;
++	struct bam_transaction *bam_txn = nandc->bam_txn;
++	enum dma_transfer_direction dir_eng;
++	struct dma_async_tx_descriptor *dma_desc;
++
++	desc = kzalloc(sizeof(*desc), GFP_KERNEL);
++	if (!desc)
++		return -ENOMEM;
++
++	if (chan == nandc->cmd_chan) {
++		sgl = &bam_txn->cmd_sgl[bam_txn->cmd_sgl_start];
++		sgl_cnt = bam_txn->cmd_sgl_pos - bam_txn->cmd_sgl_start;
++		bam_txn->cmd_sgl_start = bam_txn->cmd_sgl_pos;
++		dir_eng = DMA_MEM_TO_DEV;
++		desc->dir = DMA_TO_DEVICE;
++	} else if (chan == nandc->tx_chan) {
++		sgl = &bam_txn->data_sgl[bam_txn->tx_sgl_start];
++		sgl_cnt = bam_txn->tx_sgl_pos - bam_txn->tx_sgl_start;
++		bam_txn->tx_sgl_start = bam_txn->tx_sgl_pos;
++		dir_eng = DMA_MEM_TO_DEV;
++		desc->dir = DMA_TO_DEVICE;
++	} else {
++		sgl = &bam_txn->data_sgl[bam_txn->rx_sgl_start];
++		sgl_cnt = bam_txn->rx_sgl_pos - bam_txn->rx_sgl_start;
++		bam_txn->rx_sgl_start = bam_txn->rx_sgl_pos;
++		dir_eng = DMA_DEV_TO_MEM;
++		desc->dir = DMA_FROM_DEVICE;
++	}
++
++	sg_mark_end(sgl + sgl_cnt - 1);
++	ret = dma_map_sg(nandc->dev, sgl, sgl_cnt, desc->dir);
++	if (ret == 0) {
++		dev_err(nandc->dev, "failure in mapping desc\n");
++		kfree(desc);
++		return -ENOMEM;
++	}
++
++	desc->sgl_cnt = sgl_cnt;
++	desc->bam_sgl = sgl;
++
++	dma_desc = dmaengine_prep_slave_sg(chan, sgl, sgl_cnt, dir_eng,
++					   flags);
++
++	if (!dma_desc) {
++		dev_err(nandc->dev, "failure in prep desc\n");
++		dma_unmap_sg(nandc->dev, sgl, sgl_cnt, desc->dir);
++		kfree(desc);
++		return -EINVAL;
++	}
++
++	desc->dma_desc = dma_desc;
++
++	list_add_tail(&desc->node, &nandc->desc_list);
++
++	return 0;
++}
++
++/*
++ * Prepares the data descriptor for BAM DMA which will be used for NAND
++ * data reads and writes.
++ */
++static int prep_bam_dma_desc_data(struct qcom_nand_controller *nandc, bool read,
++				  const void *vaddr,
++				  int size, unsigned int flags)
++{
++	int ret;
++	struct bam_transaction *bam_txn = nandc->bam_txn;
++
++	if (read) {
++		sg_set_buf(&bam_txn->data_sgl[bam_txn->rx_sgl_pos],
++			   vaddr, size);
++		bam_txn->rx_sgl_pos++;
++	} else {
++		sg_set_buf(&bam_txn->data_sgl[bam_txn->tx_sgl_pos],
++			   vaddr, size);
++		bam_txn->tx_sgl_pos++;
++
++		/*
++		 * BAM will only set EOT for DMA_PREP_INTERRUPT so if this flag
++		 * is not set, form the DMA descriptor
++		 */
++		if (!(flags & NAND_BAM_NO_EOT)) {
++			ret = prepare_bam_async_desc(nandc, nandc->tx_chan,
++						     DMA_PREP_INTERRUPT);
++			if (ret)
++				return ret;
++		}
++	}
++
++	return 0;
++}
++
++static int prep_adm_dma_desc(struct qcom_nand_controller *nandc, bool read,
++			     int reg_off, const void *vaddr, int size,
++			     bool flow_control)
++{
++	struct desc_info *desc;
++	struct dma_async_tx_descriptor *dma_desc;
++	struct scatterlist *sgl;
++	struct dma_slave_config slave_conf;
++	enum dma_transfer_direction dir_eng;
++	int ret;
++
++	desc = kzalloc(sizeof(*desc), GFP_KERNEL);
++	if (!desc)
++		return -ENOMEM;
++
++	sgl = &desc->adm_sgl;
++
++	sg_init_one(sgl, vaddr, size);
++
++	if (read) {
++		dir_eng = DMA_DEV_TO_MEM;
++		desc->dir = DMA_FROM_DEVICE;
++	} else {
++		dir_eng = DMA_MEM_TO_DEV;
++		desc->dir = DMA_TO_DEVICE;
++	}
++
++	ret = dma_map_sg(nandc->dev, sgl, 1, desc->dir);
++	if (ret == 0) {
++		ret = -ENOMEM;
++		goto err;
++	}
++
++	memset(&slave_conf, 0x00, sizeof(slave_conf));
++
++	slave_conf.device_fc = flow_control;
++	if (read) {
++		slave_conf.src_maxburst = 16;
++		slave_conf.src_addr = nandc->base_dma + reg_off;
++		slave_conf.slave_id = nandc->data_crci;
++	} else {
++		slave_conf.dst_maxburst = 16;
++		slave_conf.dst_addr = nandc->base_dma + reg_off;
++		slave_conf.slave_id = nandc->cmd_crci;
++	}
++
++	ret = dmaengine_slave_config(nandc->chan, &slave_conf);
++	if (ret) {
++		dev_err(nandc->dev, "failed to configure dma channel\n");
++		goto err;
++	}
++
++	dma_desc = dmaengine_prep_slave_sg(nandc->chan, sgl, 1, dir_eng, 0);
++	if (!dma_desc) {
++		dev_err(nandc->dev, "failed to prepare desc\n");
++		ret = -EINVAL;
++		goto err;
++	}
++
++	desc->dma_desc = dma_desc;
++
++	list_add_tail(&desc->node, &nandc->desc_list);
++
++	return 0;
++err:
++	kfree(desc);
++
++	return ret;
++}
++
++/*
++ * read_reg_dma:	prepares a descriptor to read a given number of
++ *			contiguous registers to the reg_read_buf pointer
++ *
++ * @first:		offset of the first register in the contiguous block
++ * @num_regs:		number of registers to read
++ * @flags:		flags to control DMA descriptor preparation
++ */
++static int read_reg_dma(struct qcom_nand_controller *nandc, int first,
++			int num_regs, unsigned int flags)
++{
++	bool flow_control = false;
++	void *vaddr;
++	int size;
++
++	if (first == NAND_READ_ID || first == NAND_FLASH_STATUS)
++		flow_control = true;
++
++	if (first == NAND_DEV_CMD_VLD || first == NAND_DEV_CMD1)
++		first = dev_cmd_reg_addr(nandc, first);
++
++	size = num_regs * sizeof(u32);
++	vaddr = nandc->reg_read_buf + nandc->reg_read_pos;
++	nandc->reg_read_pos += num_regs;
++
++	return prep_adm_dma_desc(nandc, true, first, vaddr, size, flow_control);
++}
++
++/*
++ * write_reg_dma:	prepares a descriptor to write a given number of
++ *			contiguous registers
++ *
++ * @first:		offset of the first register in the contiguous block
++ * @num_regs:		number of registers to write
++ * @flags:		flags to control DMA descriptor preparation
++ */
++static int write_reg_dma(struct qcom_nand_controller *nandc, int first,
++			 int num_regs, unsigned int flags)
++{
++	bool flow_control = false;
++	struct nandc_regs *regs = nandc->regs;
++	void *vaddr;
++	int size;
++
++	vaddr = offset_to_nandc_reg(regs, first);
++
++	if (first == NAND_FLASH_CMD)
++		flow_control = true;
++
++	if (first == NAND_ERASED_CW_DETECT_CFG) {
++		if (flags & NAND_ERASED_CW_SET)
++			vaddr = &regs->erased_cw_detect_cfg_set;
++		else
++			vaddr = &regs->erased_cw_detect_cfg_clr;
++	}
++
++	if (first == NAND_EXEC_CMD)
++		flags |= NAND_BAM_NWD;
++
++	if (first == NAND_DEV_CMD1_RESTORE || first == NAND_DEV_CMD1)
++		first = dev_cmd_reg_addr(nandc, NAND_DEV_CMD1);
++
++	if (first == NAND_DEV_CMD_VLD_RESTORE || first == NAND_DEV_CMD_VLD)
++		first = dev_cmd_reg_addr(nandc, NAND_DEV_CMD_VLD);
++
++	size = num_regs * sizeof(u32);
++
++	return prep_adm_dma_desc(nandc, false, first, vaddr, size,
++				 flow_control);
++}
++
++/*
++ * read_data_dma:	prepares a DMA descriptor to transfer data from the
++ *			controller's internal buffer to the buffer 'vaddr'
++ *
++ * @reg_off:		offset within the controller's data buffer
++ * @vaddr:		virtual address of the buffer we want to write to
++ * @size:		DMA transaction size in bytes
++ * @flags:		flags to control DMA descriptor preparation
++ */
++static int read_data_dma(struct qcom_nand_controller *nandc, int reg_off,
++			 const u8 *vaddr, int size, unsigned int flags)
++{
++	if (nandc->props->is_bam)
++		return prep_bam_dma_desc_data(nandc, true, vaddr, size, flags);
++
++	return prep_adm_dma_desc(nandc, true, reg_off, vaddr, size, false);
++}
++
++/*
++ * write_data_dma:	prepares a DMA descriptor to transfer data from
++ *			'vaddr' to the controller's internal buffer
++ *
++ * @reg_off:		offset within the controller's data buffer
++ * @vaddr:		virtual address of the buffer we want to read from
++ * @size:		DMA transaction size in bytes
++ * @flags:		flags to control DMA descriptor preparation
++ */
++static int write_data_dma(struct qcom_nand_controller *nandc, int reg_off,
++			  const u8 *vaddr, int size, unsigned int flags)
++{
++	if (nandc->props->is_bam)
++		return prep_bam_dma_desc_data(nandc, false, vaddr, size, flags);
++
++	return prep_adm_dma_desc(nandc, false, reg_off, vaddr, size, false);
++}
++
++/*
++ * Helper to prepare DMA descriptors for configuring registers
++ * before reading a NAND page.
++ */
++static void config_nand_page_read(struct qcom_nand_controller *nandc)
++{
++	write_reg_dma(nandc, NAND_ADDR0, 2, 0);
++	write_reg_dma(nandc, NAND_DEV0_CFG0, 3, 0);
++	write_reg_dma(nandc, NAND_EBI2_ECC_BUF_CFG, 1, 0);
++	write_reg_dma(nandc, NAND_ERASED_CW_DETECT_CFG, 1, 0);
++	write_reg_dma(nandc, NAND_ERASED_CW_DETECT_CFG, 1,
++		      NAND_ERASED_CW_SET | NAND_BAM_NEXT_SGL);
++}
++
++/*
++ * Helper to prepare DMA descriptors for configuring registers
++ * before reading each codeword in NAND page.
++ */
++static void config_nand_cw_read(struct qcom_nand_controller *nandc)
++{
++	if (nandc->props->is_bam)
++		write_reg_dma(nandc, NAND_READ_LOCATION_0, 4,
++			      NAND_BAM_NEXT_SGL);
++
++	write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
++	write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
++
++	read_reg_dma(nandc, NAND_FLASH_STATUS, 2, 0);
++	read_reg_dma(nandc, NAND_ERASED_CW_DETECT_STATUS, 1,
++		     NAND_BAM_NEXT_SGL);
++}
++
++/*
++ * Helper to prepare dma descriptors to configure registers needed for reading a
++ * single codeword in page
++ */
++static void config_nand_single_cw_page_read(struct qcom_nand_controller *nandc)
++{
++	config_nand_page_read(nandc);
++	config_nand_cw_read(nandc);
++}
++
++/*
++ * Helper to prepare DMA descriptors used to configure registers needed for
++ * before writing a NAND page.
++ */
++static void config_nand_page_write(struct qcom_nand_controller *nandc)
++{
++	write_reg_dma(nandc, NAND_ADDR0, 2, 0);
++	write_reg_dma(nandc, NAND_DEV0_CFG0, 3, 0);
++	write_reg_dma(nandc, NAND_EBI2_ECC_BUF_CFG, 1,
++		      NAND_BAM_NEXT_SGL);
++}
++
++/*
++ * Helper to prepare DMA descriptors for configuring registers
++ * before writing each codeword in NAND page.
++ */
++static void config_nand_cw_write(struct qcom_nand_controller *nandc)
++{
++	write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
++	write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
++
++	read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
++
++	write_reg_dma(nandc, NAND_FLASH_STATUS, 1, 0);
++	write_reg_dma(nandc, NAND_READ_STATUS, 1, NAND_BAM_NEXT_SGL);
++}
++
++/*
++ * the following functions are used within chip->cmdfunc() to perform different
++ * NAND_CMD_* commands
++ */
++
++/* sets up descriptors for NAND_CMD_PARAM */
++static int nandc_param(struct qcom_nand_host *host)
++{
++	struct nand_chip *chip = &host->chip;
++	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
++
++	/*
++	 * NAND_CMD_PARAM is called before we know much about the FLASH chip
++	 * in use. we configure the controller to perform a raw read of 512
++	 * bytes to read onfi params
++	 */
++	nandc_set_reg(nandc, NAND_FLASH_CMD, PAGE_READ | PAGE_ACC | LAST_PAGE);
++	nandc_set_reg(nandc, NAND_ADDR0, 0);
++	nandc_set_reg(nandc, NAND_ADDR1, 0);
++	nandc_set_reg(nandc, NAND_DEV0_CFG0, 0 << CW_PER_PAGE
++					| 512 << UD_SIZE_BYTES
++					| 5 << NUM_ADDR_CYCLES
++					| 0 << SPARE_SIZE_BYTES);
++	nandc_set_reg(nandc, NAND_DEV0_CFG1, 7 << NAND_RECOVERY_CYCLES
++					| 0 << CS_ACTIVE_BSY
++					| 17 << BAD_BLOCK_BYTE_NUM
++					| 1 << BAD_BLOCK_IN_SPARE_AREA
++					| 2 << WR_RD_BSY_GAP
++					| 0 << WIDE_FLASH
++					| 1 << DEV0_CFG1_ECC_DISABLE);
++	nandc_set_reg(nandc, NAND_EBI2_ECC_BUF_CFG, 1 << ECC_CFG_ECC_DISABLE);
++
++	/* configure CMD1 and VLD for ONFI param probing */
++	nandc_set_reg(nandc, NAND_DEV_CMD_VLD,
++		      (nandc->vld & ~READ_START_VLD));
++	nandc_set_reg(nandc, NAND_DEV_CMD1,
++		      (nandc->cmd1 & ~(0xFF << READ_ADDR))
++		      | NAND_CMD_PARAM << READ_ADDR);
++
++	nandc_set_reg(nandc, NAND_EXEC_CMD, 1);
++
++	nandc_set_reg(nandc, NAND_DEV_CMD1_RESTORE, nandc->cmd1);
++	nandc_set_reg(nandc, NAND_DEV_CMD_VLD_RESTORE, nandc->vld);
++	nandc_set_read_loc(nandc, 0, 0, 512, 1);
++
++	write_reg_dma(nandc, NAND_DEV_CMD_VLD, 1, 0);
++	write_reg_dma(nandc, NAND_DEV_CMD1, 1, NAND_BAM_NEXT_SGL);
++
++	nandc->buf_count = 512;
++	memset(nandc->data_buffer, 0xff, nandc->buf_count);
++
++	config_nand_single_cw_page_read(nandc);
++
++	read_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer,
++		      nandc->buf_count, 0);
++
++	/* restore CMD1 and VLD regs */
++	write_reg_dma(nandc, NAND_DEV_CMD1_RESTORE, 1, 0);
++	write_reg_dma(nandc, NAND_DEV_CMD_VLD_RESTORE, 1, NAND_BAM_NEXT_SGL);
++
++	return 0;
++}
++
++/* sets up descriptors for NAND_CMD_ERASE1 */
++static int erase_block(struct qcom_nand_host *host, int page_addr)
++{
++	struct nand_chip *chip = &host->chip;
++	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
++
++	nandc_set_reg(nandc, NAND_FLASH_CMD,
++		      BLOCK_ERASE | PAGE_ACC | LAST_PAGE);
++	nandc_set_reg(nandc, NAND_ADDR0, page_addr);
++	nandc_set_reg(nandc, NAND_ADDR1, 0);
++	nandc_set_reg(nandc, NAND_DEV0_CFG0,
++		      host->cfg0_raw & ~(7 << CW_PER_PAGE));
++	nandc_set_reg(nandc, NAND_DEV0_CFG1, host->cfg1_raw);
++	nandc_set_reg(nandc, NAND_EXEC_CMD, 1);
++	nandc_set_reg(nandc, NAND_FLASH_STATUS, host->clrflashstatus);
++	nandc_set_reg(nandc, NAND_READ_STATUS, host->clrreadstatus);
++
++	write_reg_dma(nandc, NAND_FLASH_CMD, 3, NAND_BAM_NEXT_SGL);
++	write_reg_dma(nandc, NAND_DEV0_CFG0, 2, NAND_BAM_NEXT_SGL);
++	write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
++
++	read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
++
++	write_reg_dma(nandc, NAND_FLASH_STATUS, 1, 0);
++	write_reg_dma(nandc, NAND_READ_STATUS, 1, NAND_BAM_NEXT_SGL);
++
++	return 0;
++}
++
++/* sets up descriptors for NAND_CMD_READID */
++static int read_id(struct qcom_nand_host *host, int column)
++{
++	struct nand_chip *chip = &host->chip;
++	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
++
++	if (column == -1)
++		return 0;
++
++	nandc_set_reg(nandc, NAND_FLASH_CMD, FETCH_ID);
++	nandc_set_reg(nandc, NAND_ADDR0, column);
++	nandc_set_reg(nandc, NAND_ADDR1, 0);
++	nandc_set_reg(nandc, NAND_FLASH_CHIP_SELECT,
++		      nandc->props->is_bam ? 0 : DM_EN);
++	nandc_set_reg(nandc, NAND_EXEC_CMD, 1);
++
++	write_reg_dma(nandc, NAND_FLASH_CMD, 4, NAND_BAM_NEXT_SGL);
++	write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
++
++	read_reg_dma(nandc, NAND_READ_ID, 1, NAND_BAM_NEXT_SGL);
++
++	return 0;
++}
++
++/* sets up descriptors for NAND_CMD_RESET */
++static int reset(struct qcom_nand_host *host)
++{
++	struct nand_chip *chip = &host->chip;
++	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
++
++	nandc_set_reg(nandc, NAND_FLASH_CMD, RESET_DEVICE);
++	nandc_set_reg(nandc, NAND_EXEC_CMD, 1);
++
++	write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
++	write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
++
++	read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
++
++	return 0;
++}
++
++/* helpers to submit/free our list of dma descriptors */
++static int submit_descs(struct qcom_nand_controller *nandc)
++{
++	struct desc_info *desc;
++	dma_cookie_t cookie = 0;
++	struct bam_transaction *bam_txn = nandc->bam_txn;
++	int r;
++
++	if (nandc->props->is_bam) {
++		if (bam_txn->rx_sgl_pos > bam_txn->rx_sgl_start) {
++			r = prepare_bam_async_desc(nandc, nandc->rx_chan, 0);
++			if (r)
++				return r;
++		}
++
++		if (bam_txn->tx_sgl_pos > bam_txn->tx_sgl_start) {
++			r = prepare_bam_async_desc(nandc, nandc->tx_chan,
++						   DMA_PREP_INTERRUPT);
++			if (r)
++				return r;
++		}
++
++		if (bam_txn->cmd_sgl_pos > bam_txn->cmd_sgl_start) {
++			r = prepare_bam_async_desc(nandc, nandc->cmd_chan, 0);
++			if (r)
++				return r;
++		}
++	}
++
++	list_for_each_entry(desc, &nandc->desc_list, node)
++		cookie = dmaengine_submit(desc->dma_desc);
++
++	if (nandc->props->is_bam) {
++		dma_async_issue_pending(nandc->tx_chan);
++		dma_async_issue_pending(nandc->rx_chan);
++
++		if (dma_sync_wait(nandc->cmd_chan, cookie) != DMA_COMPLETE)
++			return -ETIMEDOUT;
++	} else {
++		if (dma_sync_wait(nandc->chan, cookie) != DMA_COMPLETE)
++			return -ETIMEDOUT;
++	}
++
++	return 0;
++}
++
++static void free_descs(struct qcom_nand_controller *nandc)
++{
++	struct desc_info *desc, *n;
++
++	list_for_each_entry_safe(desc, n, &nandc->desc_list, node) {
++		list_del(&desc->node);
++
++		if (nandc->props->is_bam)
++			dma_unmap_sg(nandc->dev, desc->bam_sgl,
++				     desc->sgl_cnt, desc->dir);
++		else
++			dma_unmap_sg(nandc->dev, &desc->adm_sgl, 1,
++				     desc->dir);
++
++		kfree(desc);
++	}
++}
++
++/* reset the register read buffer for next NAND operation */
++static void clear_read_regs(struct qcom_nand_controller *nandc)
++{
++	nandc->reg_read_pos = 0;
++	nandc_read_buffer_sync(nandc, false);
++}
++
++static void pre_command(struct qcom_nand_host *host, int command)
++{
++	struct nand_chip *chip = &host->chip;
++	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
++
++	nandc->buf_count = 0;
++	nandc->buf_start = 0;
++	host->use_ecc = false;
++	host->last_command = command;
++
++	clear_read_regs(nandc);
++
++	if (command == NAND_CMD_RESET || command == NAND_CMD_READID ||
++	    command == NAND_CMD_PARAM || command == NAND_CMD_ERASE1)
++		clear_bam_transaction(nandc);
++}
++
++/*
++ * this is called after NAND_CMD_PAGEPROG and NAND_CMD_ERASE1 to set our
++ * privately maintained status byte, this status byte can be read after
++ * NAND_CMD_STATUS is called
++ */
++static void parse_erase_write_errors(struct qcom_nand_host *host, int command)
++{
++	struct nand_chip *chip = &host->chip;
++	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
++	struct nand_ecc_ctrl *ecc = &chip->ecc;
++	int num_cw;
++	int i;
++
++	num_cw = command == NAND_CMD_PAGEPROG ? ecc->steps : 1;
++	nandc_read_buffer_sync(nandc, true);
++
++	for (i = 0; i < num_cw; i++) {
++		u32 flash_status = le32_to_cpu(nandc->reg_read_buf[i]);
++
++		if (flash_status & FS_MPU_ERR)
++			host->status &= ~NAND_STATUS_WP;
++
++		if (flash_status & FS_OP_ERR || (i == (num_cw - 1) &&
++						 (flash_status &
++						  FS_DEVICE_STS_ERR)))
++			host->status |= NAND_STATUS_FAIL;
++	}
++}
++
++static void post_command(struct qcom_nand_host *host, int command)
++{
++	struct nand_chip *chip = &host->chip;
++	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
++
++	switch (command) {
++	case NAND_CMD_READID:
++		nandc_read_buffer_sync(nandc, true);
++		memcpy(nandc->data_buffer, nandc->reg_read_buf,
++		       nandc->buf_count);
++		break;
++	case NAND_CMD_PAGEPROG:
++	case NAND_CMD_ERASE1:
++		parse_erase_write_errors(host, command);
++		break;
++	default:
++		break;
++	}
++}
++
++/*
++ * Implements chip->cmdfunc. It's  only used for a limited set of commands.
++ * The rest of the commands wouldn't be called by upper layers. For example,
++ * NAND_CMD_READOOB would never be called because we have our own versions
++ * of read_oob ops for nand_ecc_ctrl.
++ */
++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 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);
++	bool wait = false;
++	int ret = 0;
++
++	pre_command(host, command);
++
++	switch (command) {
++	case NAND_CMD_RESET:
++		ret = reset(host);
++		wait = true;
++		break;
++
++	case NAND_CMD_READID:
++		nandc->buf_count = 4;
++		ret = read_id(host, column);
++		wait = true;
++		break;
++
++	case NAND_CMD_PARAM:
++		ret = nandc_param(host);
++		wait = true;
++		break;
++
++	case NAND_CMD_ERASE1:
++		ret = erase_block(host, page_addr);
++		wait = true;
++		break;
++
++	case NAND_CMD_READ0:
++		/* we read the entire page for now */
++		WARN_ON(column != 0);
++
++		host->use_ecc = true;
++		set_address(host, 0, page_addr);
++		update_rw_regs(host, ecc->steps, true);
++		break;
++
++	case NAND_CMD_SEQIN:
++		WARN_ON(column != 0);
++		set_address(host, 0, page_addr);
++		break;
++
++	case NAND_CMD_PAGEPROG:
++	case NAND_CMD_STATUS:
++	case NAND_CMD_NONE:
++	default:
++		break;
++	}
++
++	if (ret) {
++		dev_err(nandc->dev, "failure executing command %d\n",
++			command);
++		free_descs(nandc);
++		return;
++	}
++
++	if (wait) {
++		ret = submit_descs(nandc);
++		if (ret)
++			dev_err(nandc->dev,
++				"failure submitting descs for command %d\n",
++				command);
++	}
++
++	free_descs(nandc);
++
++	post_command(host, command);
++}
++
++/*
++ * when using BCH ECC, the HW flags an error in NAND_FLASH_STATUS if it read
++ * an erased CW, and reports an erased CW in NAND_ERASED_CW_DETECT_STATUS.
++ *
++ * when using RS ECC, the HW reports the same erros when reading an erased CW,
++ * but it notifies that it is an erased CW by placing special characters at
++ * certain offsets in the buffer.
++ *
++ * verify if the page is erased or not, and fix up the page for RS ECC by
++ * replacing the special characters with 0xff.
++ */
++static bool erased_chunk_check_and_fixup(u8 *data_buf, int data_len)
++{
++	u8 empty1, empty2;
++
++	/*
++	 * an erased page flags an error in NAND_FLASH_STATUS, check if the page
++	 * is erased by looking for 0x54s at offsets 3 and 175 from the
++	 * beginning of each codeword
++	 */
++
++	empty1 = data_buf[3];
++	empty2 = data_buf[175];
++
++	/*
++	 * if the erased codework markers, if they exist override them with
++	 * 0xffs
++	 */
++	if ((empty1 == 0x54 && empty2 == 0xff) ||
++	    (empty1 == 0xff && empty2 == 0x54)) {
++		data_buf[3] = 0xff;
++		data_buf[175] = 0xff;
++	}
++
++	/*
++	 * check if the entire chunk contains 0xffs or not. if it doesn't, then
++	 * restore the original values at the special offsets
++	 */
++	if (memchr_inv(data_buf, 0xff, data_len)) {
++		data_buf[3] = empty1;
++		data_buf[175] = empty2;
++
++		return false;
++	}
++
++	return true;
++}
++
++struct read_stats {
++	__le32 flash;
++	__le32 buffer;
++	__le32 erased_cw;
++};
++
++/*
++ * reads back status registers set by the controller to notify page read
++ * errors. this is equivalent to what 'ecc->correct()' would do.
++ */
++static int parse_read_errors(struct qcom_nand_host *host, u8 *data_buf,
++			     u8 *oob_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 nand_ecc_ctrl *ecc = &chip->ecc;
++	unsigned int max_bitflips = 0;
++	struct read_stats *buf;
++	int i;
++
++	buf = (struct read_stats *)nandc->reg_read_buf;
++	nandc_read_buffer_sync(nandc, true);
++
++	for (i = 0; i < ecc->steps; i++, buf++) {
++		u32 flash, buffer, erased_cw;
++		int data_len, oob_len;
++
++		if (i == (ecc->steps - 1)) {
++			data_len = ecc->size - ((ecc->steps - 1) << 2);
++			oob_len = ecc->steps << 2;
++		} else {
++			data_len = host->cw_data;
++			oob_len = 0;
++		}
++
++		flash = le32_to_cpu(buf->flash);
++		buffer = le32_to_cpu(buf->buffer);
++		erased_cw = le32_to_cpu(buf->erased_cw);
++
++		if (flash & (FS_OP_ERR | FS_MPU_ERR)) {
++			bool erased;
++
++			/* ignore erased codeword errors */
++			if (host->bch_enabled) {
++				erased = (erased_cw & ERASED_CW) == ERASED_CW ?
++					 true : false;
++			} else {
++				erased = erased_chunk_check_and_fixup(data_buf,
++								      data_len);
++			}
++
++			if (erased) {
++				data_buf += data_len;
++				if (oob_buf)
++					oob_buf += oob_len + ecc->bytes;
++				continue;
++			}
++
++			if (buffer & BS_UNCORRECTABLE_BIT) {
++				int ret, ecclen, extraooblen;
++				void *eccbuf;
++
++				eccbuf = oob_buf ? oob_buf + oob_len : NULL;
++				ecclen = oob_buf ? host->ecc_bytes_hw : 0;
++				extraooblen = oob_buf ? oob_len : 0;
++
++				/*
++				 * make sure it isn't an erased page reported
++				 * as not-erased by HW because of a few bitflips
++				 */
++				ret = nand_check_erased_ecc_chunk(data_buf,
++					data_len, eccbuf, ecclen, oob_buf,
++					extraooblen, ecc->strength);
++				if (ret < 0) {
++					mtd->ecc_stats.failed++;
++				} else {
++					mtd->ecc_stats.corrected += ret;
++					max_bitflips =
++						max_t(unsigned int, max_bitflips, ret);
++				}
++			}
++		} else {
++			unsigned int stat;
++
++			stat = buffer & BS_CORRECTABLE_ERR_MSK;
++			mtd->ecc_stats.corrected += stat;
++			max_bitflips = max(max_bitflips, stat);
++		}
++
++		data_buf += data_len;
++		if (oob_buf)
++			oob_buf += oob_len + ecc->bytes;
++	}
++
++	return max_bitflips;
++}
++
++/*
++ * helper to perform the actual page read operation, used by ecc->read_page(),
++ * ecc->read_oob()
++ */
++static int read_page_ecc(struct qcom_nand_host *host, u8 *data_buf,
++			 u8 *oob_buf)
++{
++	struct nand_chip *chip = &host->chip;
++	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
++	struct nand_ecc_ctrl *ecc = &chip->ecc;
++	int i, ret;
++
++	config_nand_page_read(nandc);
++
++	/* queue cmd descs for each codeword */
++	for (i = 0; i < ecc->steps; i++) {
++		int data_size, oob_size;
++
++		if (i == (ecc->steps - 1)) {
++			data_size = ecc->size - ((ecc->steps - 1) << 2);
++			oob_size = (ecc->steps << 2) + host->ecc_bytes_hw +
++				   host->spare_bytes;
++		} else {
++			data_size = host->cw_data;
++			oob_size = host->ecc_bytes_hw + host->spare_bytes;
++		}
++
++		if (nandc->props->is_bam) {
++			if (data_buf && oob_buf) {
++				nandc_set_read_loc(nandc, 0, 0, data_size, 0);
++				nandc_set_read_loc(nandc, 1, data_size,
++						   oob_size, 1);
++			} else if (data_buf) {
++				nandc_set_read_loc(nandc, 0, 0, data_size, 1);
++			} else {
++				nandc_set_read_loc(nandc, 0, data_size,
++						   oob_size, 1);
++			}
++		}
++
++		config_nand_cw_read(nandc);
++
++		if (data_buf)
++			read_data_dma(nandc, FLASH_BUF_ACC, data_buf,
++				      data_size, 0);
++
++		/*
++		 * when ecc is enabled, the controller doesn't read the real
++		 * or dummy bad block markers in each chunk. To maintain a
++		 * consistent layout across RAW and ECC reads, we just
++		 * leave the real/dummy BBM offsets empty (i.e, filled with
++		 * 0xffs)
++		 */
++		if (oob_buf) {
++			int j;
++
++			for (j = 0; j < host->bbm_size; j++)
++				*oob_buf++ = 0xff;
++
++			read_data_dma(nandc, FLASH_BUF_ACC + data_size,
++				      oob_buf, oob_size, 0);
++		}
++
++		if (data_buf)
++			data_buf += data_size;
++		if (oob_buf)
++			oob_buf += oob_size;
++	}
++
++	ret = submit_descs(nandc);
++	if (ret)
++		dev_err(nandc->dev, "failure to read page/oob\n");
++
++	free_descs(nandc);
++
++	return ret;
++}
++
++/*
++ * a helper that copies the last step/codeword of a page (containing free oob)
++ * into our local buffer
++ */
++static int copy_last_cw(struct qcom_nand_host *host, int page)
++{
++	struct nand_chip *chip = &host->chip;
++	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
++	struct nand_ecc_ctrl *ecc = &chip->ecc;
++	int size;
++	int ret;
++
++	clear_read_regs(nandc);
++
++	size = host->use_ecc ? host->cw_data : host->cw_size;
++
++	/* prepare a clean read buffer */
++	memset(nandc->data_buffer, 0xff, size);
++
++	set_address(host, host->cw_size * (ecc->steps - 1), page);
++	update_rw_regs(host, 1, true);
++
++	config_nand_single_cw_page_read(nandc);
++
++	read_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer, size, 0);
++
++	ret = submit_descs(nandc);
++	if (ret)
++		dev_err(nandc->dev, "failed to copy last codeword\n");
++
++	free_descs(nandc);
++
++	return ret;
++}
++
++/* implements ecc->read_page() */
++static int qcom_nandc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
++				uint8_t *buf, int oob_required, int page)
++{
++	struct qcom_nand_host *host = to_qcom_nand_host(chip);
++	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
++	u8 *data_buf, *oob_buf = NULL;
++	int ret;
++
++	data_buf = buf;
++	oob_buf = oob_required ? chip->oob_poi : NULL;
++
++	clear_bam_transaction(nandc);
++	ret = read_page_ecc(host, data_buf, oob_buf);
++	if (ret) {
++		dev_err(nandc->dev, "failure to read page\n");
++		return ret;
++	}
++
++	return parse_read_errors(host, data_buf, oob_buf);
++}
++
++/* implements ecc->read_page_raw() */
++static int qcom_nandc_read_page_raw(struct mtd_info *mtd,
++				    struct nand_chip *chip, uint8_t *buf,
++				    int oob_required, int page)
++{
++	struct qcom_nand_host *host = to_qcom_nand_host(chip);
++	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
++	u8 *data_buf, *oob_buf;
++	struct nand_ecc_ctrl *ecc = &chip->ecc;
++	int i, ret;
++	int read_loc;
++
++	data_buf = buf;
++	oob_buf = chip->oob_poi;
++
++	host->use_ecc = false;
++
++	clear_bam_transaction(nandc);
++	update_rw_regs(host, ecc->steps, true);
++	config_nand_page_read(nandc);
++
++	for (i = 0; i < ecc->steps; i++) {
++		int data_size1, data_size2, oob_size1, oob_size2;
++		int reg_off = FLASH_BUF_ACC;
++
++		data_size1 = mtd->writesize - host->cw_size * (ecc->steps - 1);
++		oob_size1 = host->bbm_size;
++
++		if (i == (ecc->steps - 1)) {
++			data_size2 = ecc->size - data_size1 -
++				     ((ecc->steps - 1) << 2);
++			oob_size2 = (ecc->steps << 2) + host->ecc_bytes_hw +
++				    host->spare_bytes;
++		} else {
++			data_size2 = host->cw_data - data_size1;
++			oob_size2 = host->ecc_bytes_hw + host->spare_bytes;
++		}
++
++		if (nandc->props->is_bam) {
++			read_loc = 0;
++			nandc_set_read_loc(nandc, 0, read_loc, data_size1, 0);
++			read_loc += data_size1;
++
++			nandc_set_read_loc(nandc, 1, read_loc, oob_size1, 0);
++			read_loc += oob_size1;
++
++			nandc_set_read_loc(nandc, 2, read_loc, data_size2, 0);
++			read_loc += data_size2;
++
++			nandc_set_read_loc(nandc, 3, read_loc, oob_size2, 1);
++		}
++
++		config_nand_cw_read(nandc);
++
++		read_data_dma(nandc, reg_off, data_buf, data_size1, 0);
++		reg_off += data_size1;
++		data_buf += data_size1;
++
++		read_data_dma(nandc, reg_off, oob_buf, oob_size1, 0);
++		reg_off += oob_size1;
++		oob_buf += oob_size1;
++
++		read_data_dma(nandc, reg_off, data_buf, data_size2, 0);
++		reg_off += data_size2;
++		data_buf += data_size2;
++
++		read_data_dma(nandc, reg_off, oob_buf, oob_size2, 0);
++		oob_buf += oob_size2;
++	}
++
++	ret = submit_descs(nandc);
++	if (ret)
++		dev_err(nandc->dev, "failure to read raw page\n");
++
++	free_descs(nandc);
++
++	return 0;
++}
++
++/* implements ecc->read_oob() */
++static int qcom_nandc_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
++			       int page)
++{
++	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;
++	int ret;
++
++	clear_read_regs(nandc);
++	clear_bam_transaction(nandc);
++
++	host->use_ecc = true;
++	set_address(host, 0, page);
++	update_rw_regs(host, ecc->steps, true);
++
++	ret = read_page_ecc(host, NULL, chip->oob_poi);
++	if (ret)
++		dev_err(nandc->dev, "failure to read oob\n");
++
++	return ret;
++}
++
++/* implements ecc->write_page() */
++static int qcom_nandc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
++				 const uint8_t *buf, int oob_required, int page)
++{
++	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;
++	u8 *data_buf, *oob_buf;
++	int i, ret;
++
++	clear_read_regs(nandc);
++	clear_bam_transaction(nandc);
++
++	data_buf = (u8 *)buf;
++	oob_buf = chip->oob_poi;
++
++	host->use_ecc = true;
++	update_rw_regs(host, ecc->steps, false);
++	config_nand_page_write(nandc);
++
++	for (i = 0; i < ecc->steps; i++) {
++		int data_size, oob_size;
++
++		if (i == (ecc->steps - 1)) {
++			data_size = ecc->size - ((ecc->steps - 1) << 2);
++			oob_size = (ecc->steps << 2) + host->ecc_bytes_hw +
++				   host->spare_bytes;
++		} else {
++			data_size = host->cw_data;
++			oob_size = ecc->bytes;
++		}
++
++
++		write_data_dma(nandc, FLASH_BUF_ACC, data_buf, data_size,
++			       i == (ecc->steps - 1) ? NAND_BAM_NO_EOT : 0);
++
++		/*
++		 * when ECC is enabled, we don't really need to write anything
++		 * to oob for the first n - 1 codewords since these oob regions
++		 * just contain ECC bytes that's written by the controller
++		 * itself. For the last codeword, we skip the bbm positions and
++		 * write to the free oob area.
++		 */
++		if (i == (ecc->steps - 1)) {
++			oob_buf += host->bbm_size;
++
++			write_data_dma(nandc, FLASH_BUF_ACC + data_size,
++				       oob_buf, oob_size, 0);
++		}
++
++		config_nand_cw_write(nandc);
++
++		data_buf += data_size;
++		oob_buf += oob_size;
++	}
++
++	ret = submit_descs(nandc);
++	if (ret)
++		dev_err(nandc->dev, "failure to write page\n");
++
++	free_descs(nandc);
++
++	return ret;
++}
++
++/* implements ecc->write_page_raw() */
++static int qcom_nandc_write_page_raw(struct mtd_info *mtd,
++				     struct nand_chip *chip, const uint8_t *buf,
++				     int oob_required, int page)
++{
++	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;
++	u8 *data_buf, *oob_buf;
++	int i, ret;
++
++	clear_read_regs(nandc);
++	clear_bam_transaction(nandc);
++
++	data_buf = (u8 *)buf;
++	oob_buf = chip->oob_poi;
++
++	host->use_ecc = false;
++	update_rw_regs(host, ecc->steps, false);
++	config_nand_page_write(nandc);
++
++	for (i = 0; i < ecc->steps; i++) {
++		int data_size1, data_size2, oob_size1, oob_size2;
++		int reg_off = FLASH_BUF_ACC;
++
++		data_size1 = mtd->writesize - host->cw_size * (ecc->steps - 1);
++		oob_size1 = host->bbm_size;
++
++		if (i == (ecc->steps - 1)) {
++			data_size2 = ecc->size - data_size1 -
++				     ((ecc->steps - 1) << 2);
++			oob_size2 = (ecc->steps << 2) + host->ecc_bytes_hw +
++				    host->spare_bytes;
++		} else {
++			data_size2 = host->cw_data - data_size1;
++			oob_size2 = host->ecc_bytes_hw + host->spare_bytes;
++		}
++
++		write_data_dma(nandc, reg_off, data_buf, data_size1,
++			       NAND_BAM_NO_EOT);
++		reg_off += data_size1;
++		data_buf += data_size1;
++
++		write_data_dma(nandc, reg_off, oob_buf, oob_size1,
++			       NAND_BAM_NO_EOT);
++		reg_off += oob_size1;
++		oob_buf += oob_size1;
++
++		write_data_dma(nandc, reg_off, data_buf, data_size2,
++			       NAND_BAM_NO_EOT);
++		reg_off += data_size2;
++		data_buf += data_size2;
++
++		write_data_dma(nandc, reg_off, oob_buf, oob_size2, 0);
++		oob_buf += oob_size2;
++
++		config_nand_cw_write(nandc);
++	}
++
++	ret = submit_descs(nandc);
++	if (ret)
++		dev_err(nandc->dev, "failure to write raw page\n");
++
++	free_descs(nandc);
++
++	return ret;
++}
++
++/*
++ * implements ecc->write_oob()
++ *
++ * the NAND controller cannot write only data or only oob within a codeword,
++ * since ecc is calculated for the combined codeword. we first copy the
++ * entire contents for the last codeword(data + oob), replace the old oob
++ * with the new one in chip->oob_poi, and then write the entire codeword.
++ * this read-copy-write operation results in a slight performance loss.
++ */
++static int qcom_nandc_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
++				int page)
++{
++	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;
++	u8 *oob = chip->oob_poi;
++	int data_size, oob_size;
++	int ret, status = 0;
++
++	host->use_ecc = true;
++
++	clear_bam_transaction(nandc);
++	ret = copy_last_cw(host, page);
++	if (ret)
++		return ret;
++
++	clear_read_regs(nandc);
++	clear_bam_transaction(nandc);
++
++	/* calculate the data and oob size for the last codeword/step */
++	data_size = ecc->size - ((ecc->steps - 1) << 2);
++	oob_size = mtd->oobavail;
++
++	/* override new oob content to last codeword */
++	mtd_ooblayout_get_databytes(mtd, nandc->data_buffer + data_size, oob,
++				    0, mtd->oobavail);
++
++	set_address(host, host->cw_size * (ecc->steps - 1), page);
++	update_rw_regs(host, 1, false);
++
++	config_nand_page_write(nandc);
++	write_data_dma(nandc, FLASH_BUF_ACC,
++		       nandc->data_buffer, data_size + oob_size, 0);
++	config_nand_cw_write(nandc);
++
++	ret = submit_descs(nandc);
++
++	free_descs(nandc);
++
++	if (ret) {
++		dev_err(nandc->dev, "failure to write oob\n");
++		return -EIO;
++	}
++
++	chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
++
++	status = chip->waitfunc(mtd, chip);
++
++	return status & NAND_STATUS_FAIL ? -EIO : 0;
++}
++
++static int qcom_nandc_block_bad(struct mtd_info *mtd, loff_t ofs)
++{
++	struct nand_chip *chip = mtd_to_nand(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;
++	int page, ret, bbpos, bad = 0;
++	u32 flash_status;
++
++	page = (int)(ofs >> chip->page_shift) & chip->pagemask;
++
++	/*
++	 * configure registers for a raw sub page read, the address is set to
++	 * the beginning of the last codeword, we don't care about reading ecc
++	 * portion of oob. we just want the first few bytes from this codeword
++	 * that contains the BBM
++	 */
++	host->use_ecc = false;
++
++	clear_bam_transaction(nandc);
++	ret = copy_last_cw(host, page);
++	if (ret)
++		goto err;
++
++	flash_status = le32_to_cpu(nandc->reg_read_buf[0]);
++
++	if (flash_status & (FS_OP_ERR | FS_MPU_ERR)) {
++		dev_warn(nandc->dev, "error when trying to read BBM\n");
++		goto err;
++	}
++
++	bbpos = mtd->writesize - host->cw_size * (ecc->steps - 1);
++
++	bad = nandc->data_buffer[bbpos] != 0xff;
++
++	if (chip->options & NAND_BUSWIDTH_16)
++		bad = bad || (nandc->data_buffer[bbpos + 1] != 0xff);
++err:
++	return bad;
++}
++
++static int qcom_nandc_block_markbad(struct mtd_info *mtd, loff_t ofs)
++{
++	struct nand_chip *chip = mtd_to_nand(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;
++	int page, ret, status = 0;
++
++	clear_read_regs(nandc);
++	clear_bam_transaction(nandc);
++
++	/*
++	 * to mark the BBM as bad, we flash the entire last codeword with 0s.
++	 * we don't care about the rest of the content in the codeword since
++	 * we aren't going to use this block again
++	 */
++	memset(nandc->data_buffer, 0x00, host->cw_size);
++
++	page = (int)(ofs >> chip->page_shift) & chip->pagemask;
++
++	/* prepare write */
++	host->use_ecc = false;
++	set_address(host, host->cw_size * (ecc->steps - 1), page);
++	update_rw_regs(host, 1, false);
++
++	config_nand_page_write(nandc);
++	write_data_dma(nandc, FLASH_BUF_ACC,
++		       nandc->data_buffer, host->cw_size, 0);
++	config_nand_cw_write(nandc);
++
++	ret = submit_descs(nandc);
++
++	free_descs(nandc);
++
++	if (ret) {
++		dev_err(nandc->dev, "failure to update BBM\n");
++		return -EIO;
++	}
++
++	chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
++
++	status = chip->waitfunc(mtd, chip);
++
++	return status & NAND_STATUS_FAIL ? -EIO : 0;
++}
++
++/*
++ * the three functions below implement chip->read_byte(), chip->read_buf()
++ * and chip->write_buf() respectively. these aren't used for
++ * reading/writing page data, they are used for smaller data like reading
++ * id, status etc
++ */
++static uint8_t qcom_nandc_read_byte(struct mtd_info *mtd)
++{
++	struct nand_chip *chip = mtd_to_nand(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;
++	u8 ret = 0x0;
++
++	if (host->last_command == NAND_CMD_STATUS) {
++		ret = host->status;
++
++		host->status = NAND_STATUS_READY | NAND_STATUS_WP;
++
++		return ret;
++	}
++
++	if (nandc->buf_start < nandc->buf_count)
++		ret = buf[nandc->buf_start++];
++
++	return ret;
++}
++
++static void qcom_nandc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
++{
++	struct nand_chip *chip = mtd_to_nand(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);
++
++	memcpy(buf, nandc->data_buffer + nandc->buf_start, real_len);
++	nandc->buf_start += real_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 qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
++	int real_len = min_t(size_t, len, nandc->buf_count - nandc->buf_start);
++
++	memcpy(nandc->data_buffer + nandc->buf_start, buf, real_len);
++
++	nandc->buf_start += real_len;
++}
++
++/* 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 qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
++
++	if (chipnr <= 0)
++		return;
++
++	dev_warn(nandc->dev, "invalid chip select\n");
++}
++
++/*
++ * NAND controller page layout info
++ *
++ * Layout with ECC enabled:
++ *
++ * |----------------------|  |---------------------------------|
++ * |           xx.......yy|  |             *********xx.......yy|
++ * |    DATA   xx..ECC..yy|  |    DATA     **SPARE**xx..ECC..yy|
++ * |   (516)   xx.......yy|  |  (516-n*4)  **(n*4)**xx.......yy|
++ * |           xx.......yy|  |             *********xx.......yy|
++ * |----------------------|  |---------------------------------|
++ *     codeword 1,2..n-1                  codeword n
++ *  <---(528/532 Bytes)-->    <-------(528/532 Bytes)--------->
++ *
++ * n = Number of codewords in the page
++ * . = ECC bytes
++ * * = Spare/free bytes
++ * x = Unused byte(s)
++ * y = Reserved byte(s)
++ *
++ * 2K page: n = 4, spare = 16 bytes
++ * 4K page: n = 8, spare = 32 bytes
++ * 8K page: n = 16, spare = 64 bytes
++ *
++ * the qcom nand controller operates at a sub page/codeword level. each
++ * codeword is 528 and 532 bytes for 4 bit and 8 bit ECC modes respectively.
++ * the number of ECC bytes vary based on the ECC strength and the bus width.
++ *
++ * the first n - 1 codewords contains 516 bytes of user data, the remaining
++ * 12/16 bytes consist of ECC and reserved data. The nth codeword contains
++ * both user data and spare(oobavail) bytes that sum up to 516 bytes.
++ *
++ * When we access a page with ECC enabled, the reserved bytes(s) are not
++ * accessible at all. When reading, we fill up these unreadable positions
++ * with 0xffs. When writing, the controller skips writing the inaccessible
++ * bytes.
++ *
++ * Layout with ECC disabled:
++ *
++ * |------------------------------|  |---------------------------------------|
++ * |         yy          xx.......|  |         bb          *********xx.......|
++ * |  DATA1  yy  DATA2   xx..ECC..|  |  DATA1  bb  DATA2   **SPARE**xx..ECC..|
++ * | (size1) yy (size2)  xx.......|  | (size1) bb (size2)  **(n*4)**xx.......|
++ * |         yy          xx.......|  |         bb          *********xx.......|
++ * |------------------------------|  |---------------------------------------|
++ *         codeword 1,2..n-1                        codeword n
++ *  <-------(528/532 Bytes)------>    <-----------(528/532 Bytes)----------->
++ *
++ * n = Number of codewords in the page
++ * . = ECC bytes
++ * * = Spare/free bytes
++ * x = Unused byte(s)
++ * y = Dummy Bad Bock byte(s)
++ * b = Real Bad Block byte(s)
++ * size1/size2 = function of codeword size and 'n'
++ *
++ * when the ECC block is disabled, one reserved byte (or two for 16 bit bus
++ * width) is now accessible. For the first n - 1 codewords, these are dummy Bad
++ * Block Markers. In the last codeword, this position contains the real BBM
++ *
++ * In order to have a consistent layout between RAW and ECC modes, we assume
++ * the following OOB layout arrangement:
++ *
++ * |-----------|  |--------------------|
++ * |yyxx.......|  |bb*********xx.......|
++ * |yyxx..ECC..|  |bb*FREEOOB*xx..ECC..|
++ * |yyxx.......|  |bb*********xx.......|
++ * |yyxx.......|  |bb*********xx.......|
++ * |-----------|  |--------------------|
++ *  first n - 1       nth OOB region
++ *  OOB regions
++ *
++ * n = Number of codewords in the page
++ * . = ECC bytes
++ * * = FREE OOB bytes
++ * y = Dummy bad block byte(s) (inaccessible when ECC enabled)
++ * x = Unused byte(s)
++ * b = Real bad block byte(s) (inaccessible when ECC enabled)
++ *
++ * This layout is read as is when ECC is disabled. When ECC is enabled, the
++ * inaccessible Bad Block byte(s) are ignored when we write to a page/oob,
++ * and assumed as 0xffs when we read a page/oob. The ECC, unused and
++ * dummy/real bad block bytes are grouped as ecc bytes (i.e, ecc->bytes is
++ * the sum of the three).
++ */
++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 qcom_nand_host *host = to_qcom_nand_host(chip);
++	struct nand_ecc_ctrl *ecc = &chip->ecc;
++
++	if (section > 1)
++		return -ERANGE;
++
++	if (!section) {
++		oobregion->length = (ecc->bytes * (ecc->steps - 1)) +
++				    host->bbm_size;
++		oobregion->offset = 0;
++	} else {
++		oobregion->length = host->ecc_bytes_hw + host->spare_bytes;
++		oobregion->offset = mtd->oobsize - oobregion->length;
++	}
++
++	return 0;
++}
++
++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 qcom_nand_host *host = to_qcom_nand_host(chip);
++	struct nand_ecc_ctrl *ecc = &chip->ecc;
++
++	if (section)
++		return -ERANGE;
++
++	oobregion->length = ecc->steps * 4;
++	oobregion->offset = ((ecc->steps - 1) * ecc->bytes) + host->bbm_size;
++
++	return 0;
++}
++
++static const struct mtd_ooblayout_ops qcom_nand_ooblayout_ops = {
++	.ecc = qcom_nand_ooblayout_ecc,
++	.free = qcom_nand_ooblayout_free,
++};
++
++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 nand_ecc_ctrl *ecc = &chip->ecc;
++	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
++	int cwperpage, bad_block_byte;
++	bool wide_bus;
++	int ecc_mode = 1;
++
++	/*
++	 * the controller requires each step consists of 512 bytes of data.
++	 * bail out if DT has populated a wrong step size.
++	 */
++	if (ecc->size != NANDC_STEP_SIZE) {
++		dev_err(nandc->dev, "invalid ecc size\n");
++		return -EINVAL;
++	}
++
++	wide_bus = chip->options & NAND_BUSWIDTH_16 ? true : false;
++
++	if (ecc->strength >= 8) {
++		/* 8 bit ECC defaults to BCH ECC on all platforms */
++		host->bch_enabled = true;
++		ecc_mode = 1;
++
++		if (wide_bus) {
++			host->ecc_bytes_hw = 14;
++			host->spare_bytes = 0;
++			host->bbm_size = 2;
++		} else {
++			host->ecc_bytes_hw = 13;
++			host->spare_bytes = 2;
++			host->bbm_size = 1;
++		}
++	} else {
++		/*
++		 * if the controller supports BCH for 4 bit ECC, the controller
++		 * uses lesser bytes for ECC. If RS is used, the ECC bytes is
++		 * always 10 bytes
++		 */
++		if (nandc->props->ecc_modes & ECC_BCH_4BIT) {
++			/* BCH */
++			host->bch_enabled = true;
++			ecc_mode = 0;
++
++			if (wide_bus) {
++				host->ecc_bytes_hw = 8;
++				host->spare_bytes = 2;
++				host->bbm_size = 2;
++			} else {
++				host->ecc_bytes_hw = 7;
++				host->spare_bytes = 4;
++				host->bbm_size = 1;
++			}
++		} else {
++			/* RS */
++			host->ecc_bytes_hw = 10;
++
++			if (wide_bus) {
++				host->spare_bytes = 0;
++				host->bbm_size = 2;
++			} else {
++				host->spare_bytes = 1;
++				host->bbm_size = 1;
++			}
++		}
++	}
++
++	/*
++	 * we consider ecc->bytes as the sum of all the non-data content in a
++	 * step. It gives us a clean representation of the oob area (even if
++	 * all the bytes aren't used for ECC).It is always 16 bytes for 8 bit
++	 * ECC and 12 bytes for 4 bit ECC
++	 */
++	ecc->bytes = host->ecc_bytes_hw + host->spare_bytes + host->bbm_size;
++
++	ecc->read_page		= qcom_nandc_read_page;
++	ecc->read_page_raw	= qcom_nandc_read_page_raw;
++	ecc->read_oob		= qcom_nandc_read_oob;
++	ecc->write_page		= qcom_nandc_write_page;
++	ecc->write_page_raw	= qcom_nandc_write_page_raw;
++	ecc->write_oob		= qcom_nandc_write_oob;
++
++	ecc->mode = NAND_ECC_HW;
++
++	mtd_set_ooblayout(mtd, &qcom_nand_ooblayout_ops);
++
++	cwperpage = mtd->writesize / ecc->size;
++	nandc->max_cwperpage = max_t(unsigned int, nandc->max_cwperpage,
++				     cwperpage);
++
++	/*
++	 * DATA_UD_BYTES varies based on whether the read/write command protects
++	 * spare data with ECC too. We protect spare data by default, so we set
++	 * it to main + spare data, which are 512 and 4 bytes respectively.
++	 */
++	host->cw_data = 516;
++
++	/*
++	 * total bytes in a step, either 528 bytes for 4 bit ECC, or 532 bytes
++	 * for 8 bit ECC
++	 */
++	host->cw_size = host->cw_data + ecc->bytes;
++
++	if (ecc->bytes * (mtd->writesize / ecc->size) > mtd->oobsize) {
++		dev_err(nandc->dev, "ecc data doesn't fit in OOB area\n");
++		return -EINVAL;
++	}
++
++	bad_block_byte = mtd->writesize - host->cw_size * (cwperpage - 1) + 1;
++
++	host->cfg0 = (cwperpage - 1) << CW_PER_PAGE
++				| host->cw_data << UD_SIZE_BYTES
++				| 0 << DISABLE_STATUS_AFTER_WRITE
++				| 5 << NUM_ADDR_CYCLES
++				| host->ecc_bytes_hw << ECC_PARITY_SIZE_BYTES_RS
++				| 0 << STATUS_BFR_READ
++				| 1 << SET_RD_MODE_AFTER_STATUS
++				| host->spare_bytes << SPARE_SIZE_BYTES;
++
++	host->cfg1 = 7 << NAND_RECOVERY_CYCLES
++				| 0 <<  CS_ACTIVE_BSY
++				| bad_block_byte << BAD_BLOCK_BYTE_NUM
++				| 0 << BAD_BLOCK_IN_SPARE_AREA
++				| 2 << WR_RD_BSY_GAP
++				| wide_bus << WIDE_FLASH
++				| host->bch_enabled << ENABLE_BCH_ECC;
++
++	host->cfg0_raw = (cwperpage - 1) << CW_PER_PAGE
++				| host->cw_size << UD_SIZE_BYTES
++				| 5 << NUM_ADDR_CYCLES
++				| 0 << SPARE_SIZE_BYTES;
++
++	host->cfg1_raw = 7 << NAND_RECOVERY_CYCLES
++				| 0 << CS_ACTIVE_BSY
++				| 17 << BAD_BLOCK_BYTE_NUM
++				| 1 << BAD_BLOCK_IN_SPARE_AREA
++				| 2 << WR_RD_BSY_GAP
++				| wide_bus << WIDE_FLASH
++				| 1 << DEV0_CFG1_ECC_DISABLE;
++
++	host->ecc_bch_cfg = !host->bch_enabled << ECC_CFG_ECC_DISABLE
++				| 0 << ECC_SW_RESET
++				| host->cw_data << ECC_NUM_DATA_BYTES
++				| 1 << ECC_FORCE_CLK_OPEN
++				| ecc_mode << ECC_MODE
++				| host->ecc_bytes_hw << ECC_PARITY_SIZE_BYTES_BCH;
++
++	host->ecc_buf_cfg = 0x203 << NUM_STEPS;
++
++	host->clrflashstatus = FS_READY_BSY_N;
++	host->clrreadstatus = 0xc0;
++	nandc->regs->erased_cw_detect_cfg_clr =
++		cpu_to_le32(CLR_ERASED_PAGE_DET);
++	nandc->regs->erased_cw_detect_cfg_set =
++		cpu_to_le32(SET_ERASED_PAGE_DET);
++
++	dev_dbg(nandc->dev,
++		"cfg0 %x cfg1 %x ecc_buf_cfg %x ecc_bch cfg %x cw_size %d cw_data %d strength %d parity_bytes %d steps %d\n",
++		host->cfg0, host->cfg1, host->ecc_buf_cfg, host->ecc_bch_cfg,
++		host->cw_size, host->cw_data, ecc->strength, ecc->bytes,
++		cwperpage);
++
++	return 0;
++}
++
++static int qcom_nandc_alloc(struct qcom_nand_controller *nandc)
++{
++	int ret;
++
++	ret = dma_set_coherent_mask(nandc->dev, DMA_BIT_MASK(32));
++	if (ret) {
++		dev_err(nandc->dev, "failed to set DMA mask\n");
++		return ret;
++	}
++
++	/*
++	 * we use the internal buffer for reading ONFI params, reading small
++	 * data like ID and status, and preforming read-copy-write operations
++	 * when writing to a codeword partially. 532 is the maximum possible
++	 * size of a codeword for our nand controller
++	 */
++	nandc->buf_size = 532;
++
++	nandc->data_buffer = devm_kzalloc(nandc->dev, nandc->buf_size,
++					GFP_KERNEL);
++	if (!nandc->data_buffer)
++		return -ENOMEM;
++
++	nandc->regs = devm_kzalloc(nandc->dev, sizeof(*nandc->regs),
++					GFP_KERNEL);
++	if (!nandc->regs)
++		return -ENOMEM;
++
++	nandc->reg_read_buf = devm_kzalloc(nandc->dev,
++				MAX_REG_RD * sizeof(*nandc->reg_read_buf),
++				GFP_KERNEL);
++	if (!nandc->reg_read_buf)
++		return -ENOMEM;
++
++	if (nandc->props->is_bam) {
++		nandc->reg_read_dma =
++			dma_map_single(nandc->dev, nandc->reg_read_buf,
++				       MAX_REG_RD *
++				       sizeof(*nandc->reg_read_buf),
++				       DMA_FROM_DEVICE);
++		if (dma_mapping_error(nandc->dev, nandc->reg_read_dma)) {
++			dev_err(nandc->dev, "failed to DMA MAP reg buffer\n");
++			return -EIO;
++		}
++
++		nandc->tx_chan = dma_request_slave_channel(nandc->dev, "tx");
++		if (!nandc->tx_chan) {
++			dev_err(nandc->dev, "failed to request tx channel\n");
++			return -ENODEV;
++		}
++
++		nandc->rx_chan = dma_request_slave_channel(nandc->dev, "rx");
++		if (!nandc->rx_chan) {
++			dev_err(nandc->dev, "failed to request rx channel\n");
++			return -ENODEV;
++		}
++
++		nandc->cmd_chan = dma_request_slave_channel(nandc->dev, "cmd");
++		if (!nandc->cmd_chan) {
++			dev_err(nandc->dev, "failed to request cmd channel\n");
++			return -ENODEV;
++		}
++
++		/*
++		 * Initially allocate BAM transaction to read ONFI param page.
++		 * After detecting all the devices, this BAM transaction will
++		 * be freed and the next BAM tranasction will be allocated with
++		 * maximum codeword size
++		 */
++		nandc->max_cwperpage = 1;
++		nandc->bam_txn = alloc_bam_transaction(nandc);
++		if (!nandc->bam_txn) {
++			dev_err(nandc->dev,
++				"failed to allocate bam transaction\n");
++			return -ENOMEM;
++		}
++	} else {
++		nandc->chan = dma_request_slave_channel(nandc->dev, "rxtx");
++		if (!nandc->chan) {
++			dev_err(nandc->dev,
++				"failed to request slave channel\n");
++			return -ENODEV;
++		}
++	}
++
++	INIT_LIST_HEAD(&nandc->desc_list);
++	INIT_LIST_HEAD(&nandc->host_list);
++
++	nand_hw_control_init(&nandc->controller);
++
++	return 0;
++}
++
++static void qcom_nandc_unalloc(struct qcom_nand_controller *nandc)
++{
++	if (nandc->props->is_bam) {
++		if (!dma_mapping_error(nandc->dev, nandc->reg_read_dma))
++			dma_unmap_single(nandc->dev, nandc->reg_read_dma,
++					 MAX_REG_RD *
++					 sizeof(*nandc->reg_read_buf),
++					 DMA_FROM_DEVICE);
++
++		if (nandc->tx_chan)
++			dma_release_channel(nandc->tx_chan);
++
++		if (nandc->rx_chan)
++			dma_release_channel(nandc->rx_chan);
++
++		if (nandc->cmd_chan)
++			dma_release_channel(nandc->cmd_chan);
++	} else {
++		if (nandc->chan)
++			dma_release_channel(nandc->chan);
++	}
++}
++
++/* one time setup of a few nand controller registers */
++static int qcom_nandc_setup(struct qcom_nand_controller *nandc)
++{
++	u32 nand_ctrl;
++
++	/* kill onenand */
++	nandc_write(nandc, SFLASHC_BURST_CFG, 0);
++	nandc_write(nandc, dev_cmd_reg_addr(nandc, NAND_DEV_CMD_VLD),
++		    NAND_DEV_CMD_VLD_VAL);
++
++	/* enable ADM or BAM DMA */
++	if (nandc->props->is_bam) {
++		nand_ctrl = nandc_read(nandc, NAND_CTRL);
++		nandc_write(nandc, NAND_CTRL, nand_ctrl | BAM_MODE_EN);
++	} else {
++		nandc_write(nandc, NAND_FLASH_CHIP_SELECT, DM_EN);
++	}
++
++	/* save the original values of these registers */
++	nandc->cmd1 = nandc_read(nandc, dev_cmd_reg_addr(nandc, NAND_DEV_CMD1));
++	nandc->vld = NAND_DEV_CMD_VLD_VAL;
++
++	return 0;
++}
++
++static int qcom_nand_host_init(struct qcom_nand_controller *nandc,
++			       struct qcom_nand_host *host,
++			       struct device_node *dn)
++{
++	struct nand_chip *chip = &host->chip;
++	struct mtd_info *mtd = nand_to_mtd(chip);
++	struct device *dev = nandc->dev;
++	int ret;
++
++	ret = of_property_read_u32(dn, "reg", &host->cs);
++	if (ret) {
++		dev_err(dev, "can't get chip-select\n");
++		return -ENXIO;
++	}
++
++	nand_set_flash_node(chip, dn);
++	mtd->name = devm_kasprintf(dev, GFP_KERNEL, "qcom_nand.%d", host->cs);
++	mtd->owner = THIS_MODULE;
++	mtd->dev.parent = dev;
++
++	chip->cmdfunc		= qcom_nandc_command;
++	chip->select_chip	= qcom_nandc_select_chip;
++	chip->read_byte		= qcom_nandc_read_byte;
++	chip->read_buf		= qcom_nandc_read_buf;
++	chip->write_buf		= qcom_nandc_write_buf;
++	chip->onfi_set_features	= nand_onfi_get_set_features_notsupp;
++	chip->onfi_get_features	= nand_onfi_get_set_features_notsupp;
++
++	/*
++	 * the bad block marker is readable only when we read the last codeword
++	 * of a page with ECC disabled. currently, the nand_base and nand_bbt
++	 * helpers don't allow us to read BB from a nand chip with ECC
++	 * disabled (MTD_OPS_PLACE_OOB is set by default). use the block_bad
++	 * and block_markbad helpers until we permanently switch to using
++	 * MTD_OPS_RAW for all drivers (with the help of badblockbits)
++	 */
++	chip->block_bad		= qcom_nandc_block_bad;
++	chip->block_markbad	= qcom_nandc_block_markbad;
++
++	chip->controller = &nandc->controller;
++	chip->options |= NAND_NO_SUBPAGE_WRITE | NAND_USE_BOUNCE_BUFFER |
++			 NAND_SKIP_BBTSCAN;
++
++	/* set up initial status value */
++	host->status = NAND_STATUS_READY | NAND_STATUS_WP;
++
++	ret = nand_scan_ident(mtd, 1, NULL);
++	if (ret)
++		return ret;
++
++	ret = qcom_nand_host_setup(host);
++
++	return ret;
++}
++
++static int qcom_nand_mtd_register(struct qcom_nand_controller *nandc,
++				  struct qcom_nand_host *host,
++				  struct device_node *dn)
++{
++	struct nand_chip *chip = &host->chip;
++	struct mtd_info *mtd = nand_to_mtd(chip);
++	int ret;
++
++	ret = nand_scan_tail(mtd);
++	if (ret)
++		return ret;
++
++	ret = mtd_device_register(mtd, NULL, 0);
++	if (ret)
++		nand_cleanup(mtd_to_nand(mtd));
++
++	return ret;
++}
++
++static int qcom_probe_nand_devices(struct qcom_nand_controller *nandc)
++{
++	struct device *dev = nandc->dev;
++	struct device_node *dn = dev->of_node, *child;
++	struct qcom_nand_host *host, *tmp;
++	int ret;
++
++	for_each_available_child_of_node(dn, child) {
++		host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL);
++		if (!host) {
++			of_node_put(child);
++			return -ENOMEM;
++		}
++
++		ret = qcom_nand_host_init(nandc, host, child);
++		if (ret) {
++			devm_kfree(dev, host);
++			continue;
++		}
++
++		list_add_tail(&host->node, &nandc->host_list);
++	}
++
++	if (list_empty(&nandc->host_list))
++		return -ENODEV;
++
++	if (nandc->props->is_bam) {
++		free_bam_transaction(nandc);
++		nandc->bam_txn = alloc_bam_transaction(nandc);
++		if (!nandc->bam_txn) {
++			dev_err(nandc->dev,
++				"failed to allocate bam transaction\n");
++			return -ENOMEM;
++		}
++	}
++
++	list_for_each_entry_safe(host, tmp, &nandc->host_list, node) {
++		ret = qcom_nand_mtd_register(nandc, host, child);
++		if (ret) {
++			list_del(&host->node);
++			devm_kfree(dev, host);
++		}
++	}
++
++	if (list_empty(&nandc->host_list))
++		return -ENODEV;
++
++	return 0;
++}
++
++/* parse custom DT properties here */
++static int qcom_nandc_parse_dt(struct platform_device *pdev)
++{
++	struct qcom_nand_controller *nandc = platform_get_drvdata(pdev);
++	struct device_node *np = nandc->dev->of_node;
++	int ret;
++
++	if (!nandc->props->is_bam) {
++		ret = of_property_read_u32(np, "qcom,cmd-crci",
++					   &nandc->cmd_crci);
++		if (ret) {
++			dev_err(nandc->dev, "command CRCI unspecified\n");
++			return ret;
++		}
++
++		ret = of_property_read_u32(np, "qcom,data-crci",
++					   &nandc->data_crci);
++		if (ret) {
++			dev_err(nandc->dev, "data CRCI unspecified\n");
++			return ret;
++		}
++	}
++
++	return 0;
++}
++
++static int qcom_nandc_probe(struct platform_device *pdev)
++{
++	struct qcom_nand_controller *nandc;
++	const void *dev_data;
++	struct device *dev = &pdev->dev;
++	struct resource *res;
++	int ret;
++
++	nandc = devm_kzalloc(&pdev->dev, sizeof(*nandc), GFP_KERNEL);
++	if (!nandc)
++		return -ENOMEM;
++
++	platform_set_drvdata(pdev, nandc);
++	nandc->dev = dev;
++
++	dev_data = of_device_get_match_data(dev);
++	if (!dev_data) {
++		dev_err(&pdev->dev, "failed to get device data\n");
++		return -ENODEV;
++	}
++
++	nandc->props = dev_data;
++
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	nandc->base = devm_ioremap_resource(dev, res);
++	if (IS_ERR(nandc->base))
++		return PTR_ERR(nandc->base);
++
++	nandc->base_dma = phys_to_dma(dev, (phys_addr_t)res->start);
++
++	nandc->core_clk = devm_clk_get(dev, "core");
++	if (IS_ERR(nandc->core_clk))
++		return PTR_ERR(nandc->core_clk);
++
++	nandc->aon_clk = devm_clk_get(dev, "aon");
++	if (IS_ERR(nandc->aon_clk))
++		return PTR_ERR(nandc->aon_clk);
++
++	ret = qcom_nandc_parse_dt(pdev);
++	if (ret)
++		return ret;
++
++	ret = qcom_nandc_alloc(nandc);
++	if (ret)
++		goto err_core_clk;
++
++	ret = clk_prepare_enable(nandc->core_clk);
++	if (ret)
++		goto err_core_clk;
++
++	ret = clk_prepare_enable(nandc->aon_clk);
++	if (ret)
++		goto err_aon_clk;
++
++	ret = qcom_nandc_setup(nandc);
++	if (ret)
++		goto err_setup;
++
++	ret = qcom_probe_nand_devices(nandc);
++	if (ret)
++		goto err_setup;
++
++	return 0;
++
++err_setup:
++	clk_disable_unprepare(nandc->aon_clk);
++err_aon_clk:
++	clk_disable_unprepare(nandc->core_clk);
++err_core_clk:
++	qcom_nandc_unalloc(nandc);
++
++	return ret;
++}
++
++static int qcom_nandc_remove(struct platform_device *pdev)
++{
++	struct qcom_nand_controller *nandc = platform_get_drvdata(pdev);
++	struct qcom_nand_host *host;
++
++	list_for_each_entry(host, &nandc->host_list, node)
++		nand_release(nand_to_mtd(&host->chip));
++
++	qcom_nandc_unalloc(nandc);
++
++	clk_disable_unprepare(nandc->aon_clk);
++	clk_disable_unprepare(nandc->core_clk);
++
++	return 0;
++}
++
++static const struct qcom_nandc_props ipq806x_nandc_props = {
++	.ecc_modes = (ECC_RS_4BIT | ECC_BCH_8BIT),
++	.is_bam = false,
++	.dev_cmd_reg_start = 0x0,
++};
++
++static const struct qcom_nandc_props ipq4019_nandc_props = {
++	.ecc_modes = (ECC_BCH_4BIT | ECC_BCH_8BIT),
++	.is_bam = true,
++	.dev_cmd_reg_start = 0x0,
++};
++
++static const struct qcom_nandc_props ipq8074_nandc_props = {
++	.ecc_modes = (ECC_BCH_4BIT | ECC_BCH_8BIT),
++	.is_bam = true,
++	.dev_cmd_reg_start = 0x7000,
++};
++
++/*
++ * data will hold a struct pointer containing more differences once we support
++ * more controller variants
++ */
++static const struct of_device_id qcom_nandc_of_match[] = {
++	{
++		.compatible = "qcom,ipq806x-nand",
++		.data = &ipq806x_nandc_props,
++	},
++	{
++		.compatible = "qcom,ipq4019-nand",
++		.data = &ipq4019_nandc_props,
++	},
++	{
++		.compatible = "qcom,ipq8074-nand",
++		.data = &ipq8074_nandc_props,
++	},
++	{}
++};
++MODULE_DEVICE_TABLE(of, qcom_nandc_of_match);
++
++static struct platform_driver qcom_nandc_driver = {
++	.driver = {
++		.name = "qcom-nandc",
++		.of_match_table = qcom_nandc_of_match,
++	},
++	.probe   = qcom_nandc_probe,
++	.remove  = qcom_nandc_remove,
++};
++module_platform_driver(qcom_nandc_driver);
++
++MODULE_AUTHOR("Archit Taneja <architt@codeaurora.org>");
++MODULE_DESCRIPTION("Qualcomm NAND Controller driver");
++MODULE_LICENSE("GPL v2");
+diff --git a/drivers/mtd/nand/raw/r852.c b/drivers/mtd/nand/raw/r852.c
+new file mode 100644
+index 0000000..fc9287a
+--- /dev/null
++++ b/drivers/mtd/nand/raw/r852.c
+@@ -0,0 +1,1082 @@
++/*
++ * Copyright © 2009 - Maxim Levitsky
++ * driver for Ricoh xD readers
++ *
++ * 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/kernel.h>
++#include <linux/module.h>
++#include <linux/jiffies.h>
++#include <linux/workqueue.h>
++#include <linux/interrupt.h>
++#include <linux/pci.h>
++#include <linux/pci_ids.h>
++#include <linux/delay.h>
++#include <linux/slab.h>
++#include <asm/byteorder.h>
++#include <linux/sched.h>
++#include "sm_common.h"
++#include "r852.h"
++
++
++static bool r852_enable_dma = 1;
++module_param(r852_enable_dma, bool, S_IRUGO);
++MODULE_PARM_DESC(r852_enable_dma, "Enable usage of the DMA (default)");
++
++static int debug;
++module_param(debug, int, S_IRUGO | S_IWUSR);
++MODULE_PARM_DESC(debug, "Debug level (0-2)");
++
++/* read register */
++static inline uint8_t r852_read_reg(struct r852_device *dev, int address)
++{
++	uint8_t reg = readb(dev->mmio + address);
++	return reg;
++}
++
++/* write register */
++static inline void r852_write_reg(struct r852_device *dev,
++						int address, uint8_t value)
++{
++	writeb(value, dev->mmio + address);
++	mmiowb();
++}
++
++
++/* read dword sized register */
++static inline uint32_t r852_read_reg_dword(struct r852_device *dev, int address)
++{
++	uint32_t reg = le32_to_cpu(readl(dev->mmio + address));
++	return reg;
++}
++
++/* write dword sized register */
++static inline void r852_write_reg_dword(struct r852_device *dev,
++							int address, uint32_t value)
++{
++	writel(cpu_to_le32(value), dev->mmio + address);
++	mmiowb();
++}
++
++/* 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);
++	return nand_get_controller_data(chip);
++}
++
++
++/* check if controller supports dma */
++static void r852_dma_test(struct r852_device *dev)
++{
++	dev->dma_usable = (r852_read_reg(dev, R852_DMA_CAP) &
++		(R852_DMA1 | R852_DMA2)) == (R852_DMA1 | R852_DMA2);
++
++	if (!dev->dma_usable)
++		message("Non dma capable device detected, dma disabled");
++
++	if (!r852_enable_dma) {
++		message("disabling dma on user request");
++		dev->dma_usable = 0;
++	}
++}
++
++/*
++ * Enable dma. Enables ether first or second stage of the DMA,
++ * Expects dev->dma_dir and dev->dma_state be set
++ */
++static void r852_dma_enable(struct r852_device *dev)
++{
++	uint8_t dma_reg, dma_irq_reg;
++
++	/* Set up dma settings */
++	dma_reg = r852_read_reg_dword(dev, R852_DMA_SETTINGS);
++	dma_reg &= ~(R852_DMA_READ | R852_DMA_INTERNAL | R852_DMA_MEMORY);
++
++	if (dev->dma_dir)
++		dma_reg |= R852_DMA_READ;
++
++	if (dev->dma_state == DMA_INTERNAL) {
++		dma_reg |= R852_DMA_INTERNAL;
++		/* Precaution to make sure HW doesn't write */
++			/* to random kernel memory */
++		r852_write_reg_dword(dev, R852_DMA_ADDR,
++			cpu_to_le32(dev->phys_bounce_buffer));
++	} else {
++		dma_reg |= R852_DMA_MEMORY;
++		r852_write_reg_dword(dev, R852_DMA_ADDR,
++			cpu_to_le32(dev->phys_dma_addr));
++	}
++
++	/* Precaution: make sure write reached the device */
++	r852_read_reg_dword(dev, R852_DMA_ADDR);
++
++	r852_write_reg_dword(dev, R852_DMA_SETTINGS, dma_reg);
++
++	/* Set dma irq */
++	dma_irq_reg = r852_read_reg_dword(dev, R852_DMA_IRQ_ENABLE);
++	r852_write_reg_dword(dev, R852_DMA_IRQ_ENABLE,
++		dma_irq_reg |
++		R852_DMA_IRQ_INTERNAL |
++		R852_DMA_IRQ_ERROR |
++		R852_DMA_IRQ_MEMORY);
++}
++
++/*
++ * Disable dma, called from the interrupt handler, which specifies
++ * success of the operation via 'error' argument
++ */
++static void r852_dma_done(struct r852_device *dev, int error)
++{
++	WARN_ON(dev->dma_stage == 0);
++
++	r852_write_reg_dword(dev, R852_DMA_IRQ_STA,
++			r852_read_reg_dword(dev, R852_DMA_IRQ_STA));
++
++	r852_write_reg_dword(dev, R852_DMA_SETTINGS, 0);
++	r852_write_reg_dword(dev, R852_DMA_IRQ_ENABLE, 0);
++
++	/* Precaution to make sure HW doesn't write to random kernel memory */
++	r852_write_reg_dword(dev, R852_DMA_ADDR,
++		cpu_to_le32(dev->phys_bounce_buffer));
++	r852_read_reg_dword(dev, R852_DMA_ADDR);
++
++	dev->dma_error = error;
++	dev->dma_stage = 0;
++
++	if (dev->phys_dma_addr && dev->phys_dma_addr != dev->phys_bounce_buffer)
++		pci_unmap_single(dev->pci_dev, dev->phys_dma_addr, R852_DMA_LEN,
++			dev->dma_dir ? PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE);
++}
++
++/*
++ * Wait, till dma is done, which includes both phases of it
++ */
++static int r852_dma_wait(struct r852_device *dev)
++{
++	long timeout = wait_for_completion_timeout(&dev->dma_done,
++				msecs_to_jiffies(1000));
++	if (!timeout) {
++		dbg("timeout waiting for DMA interrupt");
++		return -ETIMEDOUT;
++	}
++
++	return 0;
++}
++
++/*
++ * Read/Write one page using dma. Only pages can be read (512 bytes)
++*/
++static void r852_do_dma(struct r852_device *dev, uint8_t *buf, int do_read)
++{
++	int bounce = 0;
++	unsigned long flags;
++	int error;
++
++	dev->dma_error = 0;
++
++	/* Set dma direction */
++	dev->dma_dir = do_read;
++	dev->dma_stage = 1;
++	reinit_completion(&dev->dma_done);
++
++	dbg_verbose("doing dma %s ", do_read ? "read" : "write");
++
++	/* Set initial dma state: for reading first fill on board buffer,
++	  from device, for writes first fill the buffer  from memory*/
++	dev->dma_state = do_read ? DMA_INTERNAL : DMA_MEMORY;
++
++	/* if incoming buffer is not page aligned, we should do bounce */
++	if ((unsigned long)buf & (R852_DMA_LEN-1))
++		bounce = 1;
++
++	if (!bounce) {
++		dev->phys_dma_addr = pci_map_single(dev->pci_dev, (void *)buf,
++			R852_DMA_LEN,
++			(do_read ? PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE));
++
++		if (pci_dma_mapping_error(dev->pci_dev, dev->phys_dma_addr))
++			bounce = 1;
++	}
++
++	if (bounce) {
++		dbg_verbose("dma: using bounce buffer");
++		dev->phys_dma_addr = dev->phys_bounce_buffer;
++		if (!do_read)
++			memcpy(dev->bounce_buffer, buf, R852_DMA_LEN);
++	}
++
++	/* Enable DMA */
++	spin_lock_irqsave(&dev->irqlock, flags);
++	r852_dma_enable(dev);
++	spin_unlock_irqrestore(&dev->irqlock, flags);
++
++	/* Wait till complete */
++	error = r852_dma_wait(dev);
++
++	if (error) {
++		r852_dma_done(dev, error);
++		return;
++	}
++
++	if (do_read && bounce)
++		memcpy((void *)buf, dev->bounce_buffer, R852_DMA_LEN);
++}
++
++/*
++ * Program data lines of the nand chip to send data to it
++ */
++static void r852_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
++{
++	struct r852_device *dev = r852_get_dev(mtd);
++	uint32_t reg;
++
++	/* Don't allow any access to hardware if we suspect card removal */
++	if (dev->card_unstable)
++		return;
++
++	/* Special case for whole sector read */
++	if (len == R852_DMA_LEN && dev->dma_usable) {
++		r852_do_dma(dev, (uint8_t *)buf, 0);
++		return;
++	}
++
++	/* write DWORD chinks - faster */
++	while (len >= 4) {
++		reg = buf[0] | buf[1] << 8 | buf[2] << 16 | buf[3] << 24;
++		r852_write_reg_dword(dev, R852_DATALINE, reg);
++		buf += 4;
++		len -= 4;
++
++	}
++
++	/* write rest */
++	while (len > 0) {
++		r852_write_reg(dev, R852_DATALINE, *buf++);
++		len--;
++	}
++}
++
++/*
++ * Read data lines of the nand chip to retrieve data
++ */
++static void r852_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
++{
++	struct r852_device *dev = r852_get_dev(mtd);
++	uint32_t reg;
++
++	if (dev->card_unstable) {
++		/* since we can't signal error here, at least, return
++			predictable buffer */
++		memset(buf, 0, len);
++		return;
++	}
++
++	/* special case for whole sector read */
++	if (len == R852_DMA_LEN && dev->dma_usable) {
++		r852_do_dma(dev, buf, 1);
++		return;
++	}
++
++	/* read in dword sized chunks */
++	while (len >= 4) {
++
++		reg = r852_read_reg_dword(dev, R852_DATALINE);
++		*buf++ = reg & 0xFF;
++		*buf++ = (reg >> 8) & 0xFF;
++		*buf++ = (reg >> 16) & 0xFF;
++		*buf++ = (reg >> 24) & 0xFF;
++		len -= 4;
++	}
++
++	/* read the reset by bytes */
++	while (len--)
++		*buf++ = r852_read_reg(dev, R852_DATALINE);
++}
++
++/*
++ * Read one byte from nand chip
++ */
++static uint8_t r852_read_byte(struct mtd_info *mtd)
++{
++	struct r852_device *dev = r852_get_dev(mtd);
++
++	/* Same problem as in r852_read_buf.... */
++	if (dev->card_unstable)
++		return 0;
++
++	return r852_read_reg(dev, R852_DATALINE);
++}
++
++/*
++ * Control several chip lines & send commands
++ */
++static void r852_cmdctl(struct mtd_info *mtd, int dat, unsigned int ctrl)
++{
++	struct r852_device *dev = r852_get_dev(mtd);
++
++	if (dev->card_unstable)
++		return;
++
++	if (ctrl & NAND_CTRL_CHANGE) {
++
++		dev->ctlreg &= ~(R852_CTL_DATA | R852_CTL_COMMAND |
++				 R852_CTL_ON | R852_CTL_CARDENABLE);
++
++		if (ctrl & NAND_ALE)
++			dev->ctlreg |= R852_CTL_DATA;
++
++		if (ctrl & NAND_CLE)
++			dev->ctlreg |= R852_CTL_COMMAND;
++
++		if (ctrl & NAND_NCE)
++			dev->ctlreg |= (R852_CTL_CARDENABLE | R852_CTL_ON);
++		else
++			dev->ctlreg &= ~R852_CTL_WRITE;
++
++		/* when write is stareted, enable write access */
++		if (dat == NAND_CMD_ERASE1)
++			dev->ctlreg |= R852_CTL_WRITE;
++
++		r852_write_reg(dev, R852_CTL, dev->ctlreg);
++	}
++
++	 /* HACK: NAND_CMD_SEQIN is called without NAND_CTRL_CHANGE, but we need
++		to set write mode */
++	if (dat == NAND_CMD_SEQIN && (dev->ctlreg & R852_CTL_COMMAND)) {
++		dev->ctlreg |= R852_CTL_WRITE;
++		r852_write_reg(dev, R852_CTL, dev->ctlreg);
++	}
++
++	if (dat != NAND_CMD_NONE)
++		r852_write_reg(dev, R852_DATALINE, dat);
++}
++
++/*
++ * Wait till card is ready.
++ * based on nand_wait, but returns errors on DMA error
++ */
++static int r852_wait(struct mtd_info *mtd, struct nand_chip *chip)
++{
++	struct r852_device *dev = nand_get_controller_data(chip);
++
++	unsigned long timeout;
++	int status;
++
++	timeout = jiffies + (chip->state == FL_ERASING ?
++		msecs_to_jiffies(400) : msecs_to_jiffies(20));
++
++	while (time_before(jiffies, timeout))
++		if (chip->dev_ready(mtd))
++			break;
++
++	chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
++	status = (int)chip->read_byte(mtd);
++
++	/* Unfortunelly, no way to send detailed error status... */
++	if (dev->dma_error) {
++		status |= NAND_STATUS_FAIL;
++		dev->dma_error = 0;
++	}
++	return status;
++}
++
++/*
++ * Check if card is ready
++ */
++
++static int r852_ready(struct mtd_info *mtd)
++{
++	struct r852_device *dev = r852_get_dev(mtd);
++	return !(r852_read_reg(dev, R852_CARD_STA) & R852_CARD_STA_BUSY);
++}
++
++
++/*
++ * Set ECC engine mode
++*/
++
++static void r852_ecc_hwctl(struct mtd_info *mtd, int mode)
++{
++	struct r852_device *dev = r852_get_dev(mtd);
++
++	if (dev->card_unstable)
++		return;
++
++	switch (mode) {
++	case NAND_ECC_READ:
++	case NAND_ECC_WRITE:
++		/* enable ecc generation/check*/
++		dev->ctlreg |= R852_CTL_ECC_ENABLE;
++
++		/* flush ecc buffer */
++		r852_write_reg(dev, R852_CTL,
++			dev->ctlreg | R852_CTL_ECC_ACCESS);
++
++		r852_read_reg_dword(dev, R852_DATALINE);
++		r852_write_reg(dev, R852_CTL, dev->ctlreg);
++		return;
++
++	case NAND_ECC_READSYN:
++		/* disable ecc generation */
++		dev->ctlreg &= ~R852_CTL_ECC_ENABLE;
++		r852_write_reg(dev, R852_CTL, dev->ctlreg);
++	}
++}
++
++/*
++ * Calculate ECC, only used for writes
++ */
++
++static int r852_ecc_calculate(struct mtd_info *mtd, const uint8_t *dat,
++							uint8_t *ecc_code)
++{
++	struct r852_device *dev = r852_get_dev(mtd);
++	struct sm_oob *oob = (struct sm_oob *)ecc_code;
++	uint32_t ecc1, ecc2;
++
++	if (dev->card_unstable)
++		return 0;
++
++	dev->ctlreg &= ~R852_CTL_ECC_ENABLE;
++	r852_write_reg(dev, R852_CTL, dev->ctlreg | R852_CTL_ECC_ACCESS);
++
++	ecc1 = r852_read_reg_dword(dev, R852_DATALINE);
++	ecc2 = r852_read_reg_dword(dev, R852_DATALINE);
++
++	oob->ecc1[0] = (ecc1) & 0xFF;
++	oob->ecc1[1] = (ecc1 >> 8) & 0xFF;
++	oob->ecc1[2] = (ecc1 >> 16) & 0xFF;
++
++	oob->ecc2[0] = (ecc2) & 0xFF;
++	oob->ecc2[1] = (ecc2 >> 8) & 0xFF;
++	oob->ecc2[2] = (ecc2 >> 16) & 0xFF;
++
++	r852_write_reg(dev, R852_CTL, dev->ctlreg);
++	return 0;
++}
++
++/*
++ * Correct the data using ECC, hw did almost everything for us
++ */
++
++static int r852_ecc_correct(struct mtd_info *mtd, uint8_t *dat,
++				uint8_t *read_ecc, uint8_t *calc_ecc)
++{
++	uint32_t ecc_reg;
++	uint8_t ecc_status, err_byte;
++	int i, error = 0;
++
++	struct r852_device *dev = r852_get_dev(mtd);
++
++	if (dev->card_unstable)
++		return 0;
++
++	if (dev->dma_error) {
++		dev->dma_error = 0;
++		return -EIO;
++	}
++
++	r852_write_reg(dev, R852_CTL, dev->ctlreg | R852_CTL_ECC_ACCESS);
++	ecc_reg = r852_read_reg_dword(dev, R852_DATALINE);
++	r852_write_reg(dev, R852_CTL, dev->ctlreg);
++
++	for (i = 0 ; i <= 1 ; i++) {
++
++		ecc_status = (ecc_reg >> 8) & 0xFF;
++
++		/* ecc uncorrectable error */
++		if (ecc_status & R852_ECC_FAIL) {
++			dbg("ecc: unrecoverable error, in half %d", i);
++			error = -EBADMSG;
++			goto exit;
++		}
++
++		/* correctable error */
++		if (ecc_status & R852_ECC_CORRECTABLE) {
++
++			err_byte = ecc_reg & 0xFF;
++			dbg("ecc: recoverable error, "
++				"in half %d, byte %d, bit %d", i,
++				err_byte, ecc_status & R852_ECC_ERR_BIT_MSK);
++
++			dat[err_byte] ^=
++				1 << (ecc_status & R852_ECC_ERR_BIT_MSK);
++			error++;
++		}
++
++		dat += 256;
++		ecc_reg >>= 16;
++	}
++exit:
++	return error;
++}
++
++/*
++ * This is copy of nand_read_oob_std
++ * nand_read_oob_syndrome assumes we can send column address - we can't
++ */
++static int r852_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
++			     int page)
++{
++	chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
++	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
++	return 0;
++}
++
++/*
++ * Start the nand engine
++ */
++
++static void r852_engine_enable(struct r852_device *dev)
++{
++	if (r852_read_reg_dword(dev, R852_HW) & R852_HW_UNKNOWN) {
++		r852_write_reg(dev, R852_CTL, R852_CTL_RESET | R852_CTL_ON);
++		r852_write_reg_dword(dev, R852_HW, R852_HW_ENABLED);
++	} else {
++		r852_write_reg_dword(dev, R852_HW, R852_HW_ENABLED);
++		r852_write_reg(dev, R852_CTL, R852_CTL_RESET | R852_CTL_ON);
++	}
++	msleep(300);
++	r852_write_reg(dev, R852_CTL, 0);
++}
++
++
++/*
++ * Stop the nand engine
++ */
++
++static void r852_engine_disable(struct r852_device *dev)
++{
++	r852_write_reg_dword(dev, R852_HW, 0);
++	r852_write_reg(dev, R852_CTL, R852_CTL_RESET);
++}
++
++/*
++ * Test if card is present
++ */
++
++static void r852_card_update_present(struct r852_device *dev)
++{
++	unsigned long flags;
++	uint8_t reg;
++
++	spin_lock_irqsave(&dev->irqlock, flags);
++	reg = r852_read_reg(dev, R852_CARD_STA);
++	dev->card_detected = !!(reg & R852_CARD_STA_PRESENT);
++	spin_unlock_irqrestore(&dev->irqlock, flags);
++}
++
++/*
++ * Update card detection IRQ state according to current card state
++ * which is read in r852_card_update_present
++ */
++static void r852_update_card_detect(struct r852_device *dev)
++{
++	int card_detect_reg = r852_read_reg(dev, R852_CARD_IRQ_ENABLE);
++	dev->card_unstable = 0;
++
++	card_detect_reg &= ~(R852_CARD_IRQ_REMOVE | R852_CARD_IRQ_INSERT);
++	card_detect_reg |= R852_CARD_IRQ_GENABLE;
++
++	card_detect_reg |= dev->card_detected ?
++		R852_CARD_IRQ_REMOVE : R852_CARD_IRQ_INSERT;
++
++	r852_write_reg(dev, R852_CARD_IRQ_ENABLE, card_detect_reg);
++}
++
++static ssize_t r852_media_type_show(struct device *sys_dev,
++			struct device_attribute *attr, char *buf)
++{
++	struct mtd_info *mtd = container_of(sys_dev, struct mtd_info, dev);
++	struct r852_device *dev = r852_get_dev(mtd);
++	char *data = dev->sm ? "smartmedia" : "xd";
++
++	strcpy(buf, data);
++	return strlen(data);
++}
++
++static DEVICE_ATTR(media_type, S_IRUGO, r852_media_type_show, NULL);
++
++
++/* Detect properties of card in slot */
++static void r852_update_media_status(struct r852_device *dev)
++{
++	uint8_t reg;
++	unsigned long flags;
++	int readonly;
++
++	spin_lock_irqsave(&dev->irqlock, flags);
++	if (!dev->card_detected) {
++		message("card removed");
++		spin_unlock_irqrestore(&dev->irqlock, flags);
++		return ;
++	}
++
++	readonly  = r852_read_reg(dev, R852_CARD_STA) & R852_CARD_STA_RO;
++	reg = r852_read_reg(dev, R852_DMA_CAP);
++	dev->sm = (reg & (R852_DMA1 | R852_DMA2)) && (reg & R852_SMBIT);
++
++	message("detected %s %s card in slot",
++		dev->sm ? "SmartMedia" : "xD",
++		readonly ? "readonly" : "writeable");
++
++	dev->readonly = readonly;
++	spin_unlock_irqrestore(&dev->irqlock, flags);
++}
++
++/*
++ * Register the nand device
++ * Called when the card is detected
++ */
++static int r852_register_nand_device(struct r852_device *dev)
++{
++	struct mtd_info *mtd = nand_to_mtd(dev->chip);
++
++	WARN_ON(dev->card_registred);
++
++	mtd->dev.parent = &dev->pci_dev->dev;
++
++	if (dev->readonly)
++		dev->chip->options |= NAND_ROM;
++
++	r852_engine_enable(dev);
++
++	if (sm_register_device(mtd, dev->sm))
++		goto error1;
++
++	if (device_create_file(&mtd->dev, &dev_attr_media_type)) {
++		message("can't create media type sysfs attribute");
++		goto error3;
++	}
++
++	dev->card_registred = 1;
++	return 0;
++error3:
++	nand_release(mtd);
++error1:
++	/* Force card redetect */
++	dev->card_detected = 0;
++	return -1;
++}
++
++/*
++ * Unregister the card
++ */
++
++static void r852_unregister_nand_device(struct r852_device *dev)
++{
++	struct mtd_info *mtd = nand_to_mtd(dev->chip);
++
++	if (!dev->card_registred)
++		return;
++
++	device_remove_file(&mtd->dev, &dev_attr_media_type);
++	nand_release(mtd);
++	r852_engine_disable(dev);
++	dev->card_registred = 0;
++}
++
++/* Card state updater */
++static void r852_card_detect_work(struct work_struct *work)
++{
++	struct r852_device *dev =
++		container_of(work, struct r852_device, card_detect_work.work);
++
++	r852_card_update_present(dev);
++	r852_update_card_detect(dev);
++	dev->card_unstable = 0;
++
++	/* False alarm */
++	if (dev->card_detected == dev->card_registred)
++		goto exit;
++
++	/* Read media properties */
++	r852_update_media_status(dev);
++
++	/* Register the card */
++	if (dev->card_detected)
++		r852_register_nand_device(dev);
++	else
++		r852_unregister_nand_device(dev);
++exit:
++	r852_update_card_detect(dev);
++}
++
++/* Ack + disable IRQ generation */
++static void r852_disable_irqs(struct r852_device *dev)
++{
++	uint8_t reg;
++	reg = r852_read_reg(dev, R852_CARD_IRQ_ENABLE);
++	r852_write_reg(dev, R852_CARD_IRQ_ENABLE, reg & ~R852_CARD_IRQ_MASK);
++
++	reg = r852_read_reg_dword(dev, R852_DMA_IRQ_ENABLE);
++	r852_write_reg_dword(dev, R852_DMA_IRQ_ENABLE,
++					reg & ~R852_DMA_IRQ_MASK);
++
++	r852_write_reg(dev, R852_CARD_IRQ_STA, R852_CARD_IRQ_MASK);
++	r852_write_reg_dword(dev, R852_DMA_IRQ_STA, R852_DMA_IRQ_MASK);
++}
++
++/* Interrupt handler */
++static irqreturn_t r852_irq(int irq, void *data)
++{
++	struct r852_device *dev = (struct r852_device *)data;
++
++	uint8_t card_status, dma_status;
++	unsigned long flags;
++	irqreturn_t ret = IRQ_NONE;
++
++	spin_lock_irqsave(&dev->irqlock, flags);
++
++	/* handle card detection interrupts first */
++	card_status = r852_read_reg(dev, R852_CARD_IRQ_STA);
++	r852_write_reg(dev, R852_CARD_IRQ_STA, card_status);
++
++	if (card_status & (R852_CARD_IRQ_INSERT|R852_CARD_IRQ_REMOVE)) {
++
++		ret = IRQ_HANDLED;
++		dev->card_detected = !!(card_status & R852_CARD_IRQ_INSERT);
++
++		/* we shouldn't receive any interrupts if we wait for card
++			to settle */
++		WARN_ON(dev->card_unstable);
++
++		/* disable irqs while card is unstable */
++		/* this will timeout DMA if active, but better that garbage */
++		r852_disable_irqs(dev);
++
++		if (dev->card_unstable)
++			goto out;
++
++		/* let, card state to settle a bit, and then do the work */
++		dev->card_unstable = 1;
++		queue_delayed_work(dev->card_workqueue,
++			&dev->card_detect_work, msecs_to_jiffies(100));
++		goto out;
++	}
++
++
++	/* Handle dma interrupts */
++	dma_status = r852_read_reg_dword(dev, R852_DMA_IRQ_STA);
++	r852_write_reg_dword(dev, R852_DMA_IRQ_STA, dma_status);
++
++	if (dma_status & R852_DMA_IRQ_MASK) {
++
++		ret = IRQ_HANDLED;
++
++		if (dma_status & R852_DMA_IRQ_ERROR) {
++			dbg("received dma error IRQ");
++			r852_dma_done(dev, -EIO);
++			complete(&dev->dma_done);
++			goto out;
++		}
++
++		/* received DMA interrupt out of nowhere? */
++		WARN_ON_ONCE(dev->dma_stage == 0);
++
++		if (dev->dma_stage == 0)
++			goto out;
++
++		/* done device access */
++		if (dev->dma_state == DMA_INTERNAL &&
++				(dma_status & R852_DMA_IRQ_INTERNAL)) {
++
++			dev->dma_state = DMA_MEMORY;
++			dev->dma_stage++;
++		}
++
++		/* done memory DMA */
++		if (dev->dma_state == DMA_MEMORY &&
++				(dma_status & R852_DMA_IRQ_MEMORY)) {
++			dev->dma_state = DMA_INTERNAL;
++			dev->dma_stage++;
++		}
++
++		/* Enable 2nd half of dma dance */
++		if (dev->dma_stage == 2)
++			r852_dma_enable(dev);
++
++		/* Operation done */
++		if (dev->dma_stage == 3) {
++			r852_dma_done(dev, 0);
++			complete(&dev->dma_done);
++		}
++		goto out;
++	}
++
++	/* Handle unknown interrupts */
++	if (dma_status)
++		dbg("bad dma IRQ status = %x", dma_status);
++
++	if (card_status & ~R852_CARD_STA_CD)
++		dbg("strange card status = %x", card_status);
++
++out:
++	spin_unlock_irqrestore(&dev->irqlock, flags);
++	return ret;
++}
++
++static int  r852_probe(struct pci_dev *pci_dev, const struct pci_device_id *id)
++{
++	int error;
++	struct nand_chip *chip;
++	struct r852_device *dev;
++
++	/* pci initialization */
++	error = pci_enable_device(pci_dev);
++
++	if (error)
++		goto error1;
++
++	pci_set_master(pci_dev);
++
++	error = pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32));
++	if (error)
++		goto error2;
++
++	error = pci_request_regions(pci_dev, DRV_NAME);
++
++	if (error)
++		goto error3;
++
++	error = -ENOMEM;
++
++	/* init nand chip, but register it only on card insert */
++	chip = kzalloc(sizeof(struct nand_chip), GFP_KERNEL);
++
++	if (!chip)
++		goto error4;
++
++	/* commands */
++	chip->cmd_ctrl = r852_cmdctl;
++	chip->waitfunc = r852_wait;
++	chip->dev_ready = r852_ready;
++
++	/* I/O */
++	chip->read_byte = r852_read_byte;
++	chip->read_buf = r852_read_buf;
++	chip->write_buf = r852_write_buf;
++
++	/* ecc */
++	chip->ecc.mode = NAND_ECC_HW_SYNDROME;
++	chip->ecc.size = R852_DMA_LEN;
++	chip->ecc.bytes = SM_OOB_SIZE;
++	chip->ecc.strength = 2;
++	chip->ecc.hwctl = r852_ecc_hwctl;
++	chip->ecc.calculate = r852_ecc_calculate;
++	chip->ecc.correct = r852_ecc_correct;
++
++	/* TODO: hack */
++	chip->ecc.read_oob = r852_read_oob;
++
++	/* init our device structure */
++	dev = kzalloc(sizeof(struct r852_device), GFP_KERNEL);
++
++	if (!dev)
++		goto error5;
++
++	nand_set_controller_data(chip, dev);
++	dev->chip = chip;
++	dev->pci_dev = pci_dev;
++	pci_set_drvdata(pci_dev, dev);
++
++	dev->bounce_buffer = pci_alloc_consistent(pci_dev, R852_DMA_LEN,
++		&dev->phys_bounce_buffer);
++
++	if (!dev->bounce_buffer)
++		goto error6;
++
++
++	error = -ENODEV;
++	dev->mmio = pci_ioremap_bar(pci_dev, 0);
++
++	if (!dev->mmio)
++		goto error7;
++
++	error = -ENOMEM;
++	dev->tmp_buffer = kzalloc(SM_SECTOR_SIZE, GFP_KERNEL);
++
++	if (!dev->tmp_buffer)
++		goto error8;
++
++	init_completion(&dev->dma_done);
++
++	dev->card_workqueue = create_freezable_workqueue(DRV_NAME);
++
++	if (!dev->card_workqueue)
++		goto error9;
++
++	INIT_DELAYED_WORK(&dev->card_detect_work, r852_card_detect_work);
++
++	/* shutdown everything - precation */
++	r852_engine_disable(dev);
++	r852_disable_irqs(dev);
++
++	r852_dma_test(dev);
++
++	dev->irq = pci_dev->irq;
++	spin_lock_init(&dev->irqlock);
++
++	dev->card_detected = 0;
++	r852_card_update_present(dev);
++
++	/*register irq handler*/
++	error = -ENODEV;
++	if (request_irq(pci_dev->irq, &r852_irq, IRQF_SHARED,
++			  DRV_NAME, dev))
++		goto error10;
++
++	/* kick initial present test */
++	queue_delayed_work(dev->card_workqueue,
++		&dev->card_detect_work, 0);
++
++
++	printk(KERN_NOTICE DRV_NAME ": driver loaded successfully\n");
++	return 0;
++
++error10:
++	destroy_workqueue(dev->card_workqueue);
++error9:
++	kfree(dev->tmp_buffer);
++error8:
++	pci_iounmap(pci_dev, dev->mmio);
++error7:
++	pci_free_consistent(pci_dev, R852_DMA_LEN,
++		dev->bounce_buffer, dev->phys_bounce_buffer);
++error6:
++	kfree(dev);
++error5:
++	kfree(chip);
++error4:
++	pci_release_regions(pci_dev);
++error3:
++error2:
++	pci_disable_device(pci_dev);
++error1:
++	return error;
++}
++
++static void r852_remove(struct pci_dev *pci_dev)
++{
++	struct r852_device *dev = pci_get_drvdata(pci_dev);
++
++	/* Stop detect workqueue -
++		we are going to unregister the device anyway*/
++	cancel_delayed_work_sync(&dev->card_detect_work);
++	destroy_workqueue(dev->card_workqueue);
++
++	/* Unregister the device, this might make more IO */
++	r852_unregister_nand_device(dev);
++
++	/* Stop interrupts */
++	r852_disable_irqs(dev);
++	free_irq(dev->irq, dev);
++
++	/* Cleanup */
++	kfree(dev->tmp_buffer);
++	pci_iounmap(pci_dev, dev->mmio);
++	pci_free_consistent(pci_dev, R852_DMA_LEN,
++		dev->bounce_buffer, dev->phys_bounce_buffer);
++
++	kfree(dev->chip);
++	kfree(dev);
++
++	/* Shutdown the PCI device */
++	pci_release_regions(pci_dev);
++	pci_disable_device(pci_dev);
++}
++
++static void r852_shutdown(struct pci_dev *pci_dev)
++{
++	struct r852_device *dev = pci_get_drvdata(pci_dev);
++
++	cancel_delayed_work_sync(&dev->card_detect_work);
++	r852_disable_irqs(dev);
++	synchronize_irq(dev->irq);
++	pci_disable_device(pci_dev);
++}
++
++#ifdef CONFIG_PM_SLEEP
++static int r852_suspend(struct device *device)
++{
++	struct r852_device *dev = pci_get_drvdata(to_pci_dev(device));
++
++	if (dev->ctlreg & R852_CTL_CARDENABLE)
++		return -EBUSY;
++
++	/* First make sure the detect work is gone */
++	cancel_delayed_work_sync(&dev->card_detect_work);
++
++	/* Turn off the interrupts and stop the device */
++	r852_disable_irqs(dev);
++	r852_engine_disable(dev);
++
++	/* If card was pulled off just during the suspend, which is very
++		unlikely, we will remove it on resume, it too late now
++		anyway... */
++	dev->card_unstable = 0;
++	return 0;
++}
++
++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);
++
++	r852_disable_irqs(dev);
++	r852_card_update_present(dev);
++	r852_engine_disable(dev);
++
++
++	/* If card status changed, just do the work */
++	if (dev->card_detected != dev->card_registred) {
++		dbg("card was %s during low power state",
++			dev->card_detected ? "added" : "removed");
++
++		queue_delayed_work(dev->card_workqueue,
++		&dev->card_detect_work, msecs_to_jiffies(1000));
++		return 0;
++	}
++
++	/* Otherwise, initialize the card */
++	if (dev->card_registred) {
++		r852_engine_enable(dev);
++		dev->chip->select_chip(mtd, 0);
++		dev->chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
++		dev->chip->select_chip(mtd, -1);
++	}
++
++	/* Program card detection IRQ */
++	r852_update_card_detect(dev);
++	return 0;
++}
++#endif
++
++static const struct pci_device_id r852_pci_id_tbl[] = {
++
++	{ PCI_VDEVICE(RICOH, 0x0852), },
++	{ },
++};
++
++MODULE_DEVICE_TABLE(pci, r852_pci_id_tbl);
++
++static SIMPLE_DEV_PM_OPS(r852_pm_ops, r852_suspend, r852_resume);
++
++static struct pci_driver r852_pci_driver = {
++	.name		= DRV_NAME,
++	.id_table	= r852_pci_id_tbl,
++	.probe		= r852_probe,
++	.remove		= r852_remove,
++	.shutdown	= r852_shutdown,
++	.driver.pm	= &r852_pm_ops,
++};
++
++module_pci_driver(r852_pci_driver);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Maxim Levitsky <maximlevitsky@gmail.com>");
++MODULE_DESCRIPTION("Ricoh 85xx xD/smartmedia card reader driver");
+diff --git a/drivers/mtd/nand/raw/r852.h b/drivers/mtd/nand/raw/r852.h
+new file mode 100644
+index 0000000..8713c57
+--- /dev/null
++++ b/drivers/mtd/nand/raw/r852.h
+@@ -0,0 +1,160 @@
++/*
++ * Copyright © 2009 - Maxim Levitsky
++ * driver for Ricoh xD readers
++ *
++ * 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/pci.h>
++#include <linux/completion.h>
++#include <linux/workqueue.h>
++#include <linux/mtd/rawnand.h>
++#include <linux/spinlock.h>
++
++
++/* nand interface + ecc
++   byte write/read does one cycle on nand data lines.
++   dword write/read does 4 cycles
++   if R852_CTL_ECC_ACCESS is set in R852_CTL, then dword read reads
++   results of ecc correction, if DMA read was done before.
++   If write was done two dword reads read generated ecc checksums
++*/
++#define	R852_DATALINE		0x00
++
++/* control register */
++#define R852_CTL		0x04
++#define R852_CTL_COMMAND 	0x01	/* send command (#CLE)*/
++#define R852_CTL_DATA		0x02	/* read/write data (#ALE)*/
++#define R852_CTL_ON		0x04	/* only seem to controls the hd led, */
++					/* but has to be set on start...*/
++#define R852_CTL_RESET		0x08	/* unknown, set only on start once*/
++#define R852_CTL_CARDENABLE	0x10	/* probably (#CE) - always set*/
++#define R852_CTL_ECC_ENABLE	0x20	/* enable ecc engine */
++#define R852_CTL_ECC_ACCESS	0x40	/* read/write ecc via reg #0*/
++#define R852_CTL_WRITE		0x80	/* set when performing writes (#WP) */
++
++/* card detection status */
++#define R852_CARD_STA		0x05
++
++#define R852_CARD_STA_CD	0x01	/* state of #CD line, same as 0x04 */
++#define R852_CARD_STA_RO	0x02	/* card is readonly */
++#define R852_CARD_STA_PRESENT	0x04	/* card is present (#CD) */
++#define R852_CARD_STA_ABSENT	0x08	/* card is absent */
++#define R852_CARD_STA_BUSY	0x80	/* card is busy - (#R/B) */
++
++/* card detection irq status & enable*/
++#define R852_CARD_IRQ_STA	0x06	/* IRQ status */
++#define R852_CARD_IRQ_ENABLE	0x07	/* IRQ enable */
++
++#define R852_CARD_IRQ_CD	0x01	/* fire when #CD lights, same as 0x04*/
++#define R852_CARD_IRQ_REMOVE	0x04	/* detect card removal */
++#define R852_CARD_IRQ_INSERT	0x08	/* detect card insert */
++#define R852_CARD_IRQ_UNK1	0x10	/* unknown */
++#define R852_CARD_IRQ_GENABLE	0x80	/* general enable */
++#define R852_CARD_IRQ_MASK	0x1D
++
++
++
++/* hardware enable */
++#define R852_HW			0x08
++#define R852_HW_ENABLED		0x01	/* hw enabled */
++#define R852_HW_UNKNOWN		0x80
++
++
++/* dma capabilities */
++#define R852_DMA_CAP		0x09
++#define R852_SMBIT		0x20	/* if set with bit #6 or bit #7, then */
++					/* hw is smartmedia */
++#define R852_DMA1		0x40	/* if set w/bit #7, dma is supported */
++#define R852_DMA2		0x80	/* if set w/bit #6, dma is supported */
++
++
++/* physical DMA address - 32 bit value*/
++#define R852_DMA_ADDR		0x0C
++
++
++/* dma settings */
++#define R852_DMA_SETTINGS	0x10
++#define R852_DMA_MEMORY		0x01	/* (memory <-> internal hw buffer) */
++#define R852_DMA_READ		0x02	/* 0 = write, 1 = read */
++#define R852_DMA_INTERNAL	0x04	/* (internal hw buffer <-> card) */
++
++/* dma IRQ status */
++#define R852_DMA_IRQ_STA		0x14
++
++/* dma IRQ enable */
++#define R852_DMA_IRQ_ENABLE	0x18
++
++#define R852_DMA_IRQ_MEMORY	0x01	/* (memory <-> internal hw buffer) */
++#define R852_DMA_IRQ_ERROR	0x02	/* error did happen */
++#define R852_DMA_IRQ_INTERNAL	0x04	/* (internal hw buffer <-> card) */
++#define R852_DMA_IRQ_MASK	0x07	/* mask of all IRQ bits */
++
++
++/* ECC syndrome format - read from reg #0 will return two copies of these for
++   each half of the page.
++   first byte is error byte location, and second, bit location + flags */
++#define R852_ECC_ERR_BIT_MSK	0x07	/* error bit location */
++#define R852_ECC_CORRECT		0x10	/* no errors - (guessed) */
++#define R852_ECC_CORRECTABLE	0x20	/* correctable error exist */
++#define R852_ECC_FAIL		0x40	/* non correctable error detected */
++
++#define R852_DMA_LEN		512
++
++#define DMA_INTERNAL	0
++#define DMA_MEMORY	1
++
++struct r852_device {
++	void __iomem *mmio;		/* mmio */
++	struct nand_chip *chip;		/* nand chip backpointer */
++	struct pci_dev *pci_dev;	/* pci backpointer */
++
++	/* dma area */
++	dma_addr_t phys_dma_addr;	/* bus address of buffer*/
++	struct completion dma_done;	/* data transfer done */
++
++	dma_addr_t phys_bounce_buffer;	/* bus address of bounce buffer */
++	uint8_t *bounce_buffer;		/* virtual address of bounce buffer */
++
++	int dma_dir;			/* 1 = read, 0 = write */
++	int dma_stage;			/* 0 - idle, 1 - first step,
++					   2 - second step */
++
++	int dma_state;			/* 0 = internal, 1 = memory */
++	int dma_error;			/* dma errors */
++	int dma_usable;			/* is it possible to use dma */
++
++	/* card status area */
++	struct delayed_work card_detect_work;
++	struct workqueue_struct *card_workqueue;
++	int card_registred;		/* card registered with mtd */
++	int card_detected;		/* card detected in slot */
++	int card_unstable;		/* whenever the card is inserted,
++					   is not known yet */
++	int readonly;			/* card is readonly */
++	int sm;				/* Is card smartmedia */
++
++	/* interrupt handling */
++	spinlock_t irqlock;		/* IRQ protecting lock */
++	int irq;			/* irq num */
++	/* misc */
++	void *tmp_buffer;		/* temporary buffer */
++	uint8_t ctlreg;			/* cached contents of control reg */
++};
++
++#define DRV_NAME "r852"
++
++
++#define dbg(format, ...) \
++	if (debug) \
++		printk(KERN_DEBUG DRV_NAME ": " format "\n", ## __VA_ARGS__)
++
++#define dbg_verbose(format, ...) \
++	if (debug > 1) \
++		printk(KERN_DEBUG DRV_NAME ": " format "\n", ## __VA_ARGS__)
++
++
++#define message(format, ...) \
++	printk(KERN_INFO DRV_NAME ": " format "\n", ## __VA_ARGS__)
+diff --git a/drivers/mtd/nand/raw/s3c2410.c b/drivers/mtd/nand/raw/s3c2410.c
+new file mode 100644
+index 0000000..4c383ee
+--- /dev/null
++++ b/drivers/mtd/nand/raw/s3c2410.c
+@@ -0,0 +1,1296 @@
++/* linux/drivers/mtd/nand/s3c2410.c
++ *
++ * Copyright © 2004-2008 Simtec Electronics
++ *	http://armlinux.simtec.co.uk/
++ *	Ben Dooks <ben@simtec.co.uk>
++ *
++ * Samsung S3C2410/S3C2440/S3C2412 NAND driver
++ *
++ * 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.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++#define pr_fmt(fmt) "nand-s3c2410: " fmt
++
++#ifdef CONFIG_MTD_NAND_S3C2410_DEBUG
++#define DEBUG
++#endif
++
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <linux/string.h>
++#include <linux/io.h>
++#include <linux/ioport.h>
++#include <linux/platform_device.h>
++#include <linux/delay.h>
++#include <linux/err.h>
++#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/rawnand.h>
++#include <linux/mtd/nand_ecc.h>
++#include <linux/mtd/partitions.h>
++
++#include <linux/platform_data/mtd-nand-s3c2410.h>
++
++#define S3C2410_NFREG(x) (x)
++
++#define S3C2410_NFCONF		S3C2410_NFREG(0x00)
++#define S3C2410_NFCMD		S3C2410_NFREG(0x04)
++#define S3C2410_NFADDR		S3C2410_NFREG(0x08)
++#define S3C2410_NFDATA		S3C2410_NFREG(0x0C)
++#define S3C2410_NFSTAT		S3C2410_NFREG(0x10)
++#define S3C2410_NFECC		S3C2410_NFREG(0x14)
++#define S3C2440_NFCONT		S3C2410_NFREG(0x04)
++#define S3C2440_NFCMD		S3C2410_NFREG(0x08)
++#define S3C2440_NFADDR		S3C2410_NFREG(0x0C)
++#define S3C2440_NFDATA		S3C2410_NFREG(0x10)
++#define S3C2440_NFSTAT		S3C2410_NFREG(0x20)
++#define S3C2440_NFMECC0		S3C2410_NFREG(0x2C)
++#define S3C2412_NFSTAT		S3C2410_NFREG(0x28)
++#define S3C2412_NFMECC0		S3C2410_NFREG(0x34)
++#define S3C2410_NFCONF_EN		(1<<15)
++#define S3C2410_NFCONF_INITECC		(1<<12)
++#define S3C2410_NFCONF_nFCE		(1<<11)
++#define S3C2410_NFCONF_TACLS(x)		((x)<<8)
++#define S3C2410_NFCONF_TWRPH0(x)	((x)<<4)
++#define S3C2410_NFCONF_TWRPH1(x)	((x)<<0)
++#define S3C2410_NFSTAT_BUSY		(1<<0)
++#define S3C2440_NFCONF_TACLS(x)		((x)<<12)
++#define S3C2440_NFCONF_TWRPH0(x)	((x)<<8)
++#define S3C2440_NFCONF_TWRPH1(x)	((x)<<4)
++#define S3C2440_NFCONT_INITECC		(1<<4)
++#define S3C2440_NFCONT_nFCE		(1<<1)
++#define S3C2440_NFCONT_ENABLE		(1<<0)
++#define S3C2440_NFSTAT_READY		(1<<0)
++#define S3C2412_NFCONF_NANDBOOT		(1<<31)
++#define S3C2412_NFCONT_INIT_MAIN_ECC	(1<<5)
++#define S3C2412_NFCONT_nFCE0		(1<<1)
++#define S3C2412_NFSTAT_READY		(1<<0)
++
++/* new oob placement block for use with hardware ecc generation
++ */
++static int s3c2410_ooblayout_ecc(struct mtd_info *mtd, int section,
++				 struct mtd_oob_region *oobregion)
++{
++	if (section)
++		return -ERANGE;
++
++	oobregion->offset = 0;
++	oobregion->length = 3;
++
++	return 0;
++}
++
++static int s3c2410_ooblayout_free(struct mtd_info *mtd, int section,
++				  struct mtd_oob_region *oobregion)
++{
++	if (section)
++		return -ERANGE;
++
++	oobregion->offset = 8;
++	oobregion->length = 8;
++
++	return 0;
++}
++
++static const struct mtd_ooblayout_ops s3c2410_ooblayout_ops = {
++	.ecc = s3c2410_ooblayout_ecc,
++	.free = s3c2410_ooblayout_free,
++};
++
++/* controller and mtd information */
++
++struct s3c2410_nand_info;
++
++/**
++ * struct s3c2410_nand_mtd - driver MTD structure
++ * @mtd: The MTD instance to pass to the MTD layer.
++ * @chip: The NAND chip information.
++ * @set: The platform information supplied for this set of NAND chips.
++ * @info: Link back to the hardware information.
++ * @scan_res: The result from calling nand_scan_ident().
++*/
++struct s3c2410_nand_mtd {
++	struct nand_chip		chip;
++	struct s3c2410_nand_set		*set;
++	struct s3c2410_nand_info	*info;
++	int				scan_res;
++};
++
++enum s3c_cpu_type {
++	TYPE_S3C2410,
++	TYPE_S3C2412,
++	TYPE_S3C2440,
++};
++
++enum s3c_nand_clk_state {
++	CLOCK_DISABLE	= 0,
++	CLOCK_ENABLE,
++	CLOCK_SUSPEND,
++};
++
++/* overview of the s3c2410 nand state */
++
++/**
++ * struct s3c2410_nand_info - NAND controller state.
++ * @mtds: An array of MTD instances on this controoler.
++ * @platform: The platform data for this board.
++ * @device: The platform device we bound to.
++ * @clk: The clock resource for this controller.
++ * @regs: The area mapped for the hardware registers.
++ * @sel_reg: Pointer to the register controlling the NAND selection.
++ * @sel_bit: The bit in @sel_reg to select the NAND chip.
++ * @mtd_count: The number of MTDs created from this controller.
++ * @save_sel: The contents of @sel_reg to be saved over suspend.
++ * @clk_rate: The clock rate from @clk.
++ * @clk_state: The current clock state.
++ * @cpu_type: The exact type of this controller.
++ */
++struct s3c2410_nand_info {
++	/* mtd info */
++	struct nand_hw_control		controller;
++	struct s3c2410_nand_mtd		*mtds;
++	struct s3c2410_platform_nand	*platform;
++
++	/* device info */
++	struct device			*device;
++	struct clk			*clk;
++	void __iomem			*regs;
++	void __iomem			*sel_reg;
++	int				sel_bit;
++	int				mtd_count;
++	unsigned long			save_sel;
++	unsigned long			clk_rate;
++	enum s3c_nand_clk_state		clk_state;
++
++	enum s3c_cpu_type		cpu_type;
++
++#ifdef CONFIG_ARM_S3C24XX_CPUFREQ
++	struct notifier_block	freq_transition;
++#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)
++{
++	return container_of(mtd_to_nand(mtd), struct s3c2410_nand_mtd,
++			    chip);
++}
++
++static struct s3c2410_nand_info *s3c2410_nand_mtd_toinfo(struct mtd_info *mtd)
++{
++	return s3c2410_nand_mtd_toours(mtd)->info;
++}
++
++static struct s3c2410_nand_info *to_nand_info(struct platform_device *dev)
++{
++	return platform_get_drvdata(dev);
++}
++
++static struct s3c2410_platform_nand *to_nand_plat(struct platform_device *dev)
++{
++	return dev_get_platdata(&dev->dev);
++}
++
++static inline int allow_clk_suspend(struct s3c2410_nand_info *info)
++{
++#ifdef CONFIG_MTD_NAND_S3C2410_CLKSTOP
++	return 1;
++#else
++	return 0;
++#endif
++}
++
++/**
++ * s3c2410_nand_clk_set_state - Enable, disable or suspend NAND clock.
++ * @info: The controller instance.
++ * @new_state: State to which clock should be set.
++ */
++static void s3c2410_nand_clk_set_state(struct s3c2410_nand_info *info,
++		enum s3c_nand_clk_state new_state)
++{
++	if (!allow_clk_suspend(info) && new_state == CLOCK_SUSPEND)
++		return;
++
++	if (info->clk_state == CLOCK_ENABLE) {
++		if (new_state != CLOCK_ENABLE)
++			clk_disable_unprepare(info->clk);
++	} else {
++		if (new_state == CLOCK_ENABLE)
++			clk_prepare_enable(info->clk);
++	}
++
++	info->clk_state = new_state;
++}
++
++/* timing calculations */
++
++#define NS_IN_KHZ 1000000
++
++/**
++ * s3c_nand_calc_rate - calculate timing data.
++ * @wanted: The cycle time in nanoseconds.
++ * @clk: The clock rate in kHz.
++ * @max: The maximum divider value.
++ *
++ * Calculate the timing value from the given parameters.
++ */
++static int s3c_nand_calc_rate(int wanted, unsigned long clk, int max)
++{
++	int result;
++
++	result = DIV_ROUND_UP((wanted * clk), NS_IN_KHZ);
++
++	pr_debug("result %d from %ld, %d\n", result, clk, wanted);
++
++	if (result > max) {
++		pr_err("%d ns is too big for current clock rate %ld\n",
++			wanted, clk);
++		return -1;
++	}
++
++	if (result < 1)
++		result = 1;
++
++	return result;
++}
++
++#define to_ns(ticks, clk) (((ticks) * NS_IN_KHZ) / (unsigned int)(clk))
++
++/* controller setup */
++
++/**
++ * s3c2410_nand_setrate - setup controller timing information.
++ * @info: The controller instance.
++ *
++ * Given the information supplied by the platform, calculate and set
++ * the necessary timing registers in the hardware to generate the
++ * necessary timing cycles to the hardware.
++ */
++static int s3c2410_nand_setrate(struct s3c2410_nand_info *info)
++{
++	struct s3c2410_platform_nand *plat = info->platform;
++	int tacls_max = (info->cpu_type == TYPE_S3C2412) ? 8 : 4;
++	int tacls, twrph0, twrph1;
++	unsigned long clkrate = clk_get_rate(info->clk);
++	unsigned long uninitialized_var(set), cfg, uninitialized_var(mask);
++	unsigned long flags;
++
++	/* calculate the timing information for the controller */
++
++	info->clk_rate = clkrate;
++	clkrate /= 1000;	/* turn clock into kHz for ease of use */
++
++	if (plat != NULL) {
++		tacls = s3c_nand_calc_rate(plat->tacls, clkrate, tacls_max);
++		twrph0 = s3c_nand_calc_rate(plat->twrph0, clkrate, 8);
++		twrph1 = s3c_nand_calc_rate(plat->twrph1, clkrate, 8);
++	} else {
++		/* default timings */
++		tacls = tacls_max;
++		twrph0 = 8;
++		twrph1 = 8;
++	}
++
++	if (tacls < 0 || twrph0 < 0 || twrph1 < 0) {
++		dev_err(info->device, "cannot get suitable timings\n");
++		return -EINVAL;
++	}
++
++	dev_info(info->device, "Tacls=%d, %dns Twrph0=%d %dns, Twrph1=%d %dns\n",
++		tacls, to_ns(tacls, clkrate), twrph0, to_ns(twrph0, clkrate),
++						twrph1, to_ns(twrph1, clkrate));
++
++	switch (info->cpu_type) {
++	case TYPE_S3C2410:
++		mask = (S3C2410_NFCONF_TACLS(3) |
++			S3C2410_NFCONF_TWRPH0(7) |
++			S3C2410_NFCONF_TWRPH1(7));
++		set = S3C2410_NFCONF_EN;
++		set |= S3C2410_NFCONF_TACLS(tacls - 1);
++		set |= S3C2410_NFCONF_TWRPH0(twrph0 - 1);
++		set |= S3C2410_NFCONF_TWRPH1(twrph1 - 1);
++		break;
++
++	case TYPE_S3C2440:
++	case TYPE_S3C2412:
++		mask = (S3C2440_NFCONF_TACLS(tacls_max - 1) |
++			S3C2440_NFCONF_TWRPH0(7) |
++			S3C2440_NFCONF_TWRPH1(7));
++
++		set = S3C2440_NFCONF_TACLS(tacls - 1);
++		set |= S3C2440_NFCONF_TWRPH0(twrph0 - 1);
++		set |= S3C2440_NFCONF_TWRPH1(twrph1 - 1);
++		break;
++
++	default:
++		BUG();
++	}
++
++	local_irq_save(flags);
++
++	cfg = readl(info->regs + S3C2410_NFCONF);
++	cfg &= ~mask;
++	cfg |= set;
++	writel(cfg, info->regs + S3C2410_NFCONF);
++
++	local_irq_restore(flags);
++
++	dev_dbg(info->device, "NF_CONF is 0x%lx\n", cfg);
++
++	return 0;
++}
++
++/**
++ * s3c2410_nand_inithw - basic hardware initialisation
++ * @info: The hardware state.
++ *
++ * Do the basic initialisation of the hardware, using s3c2410_nand_setrate()
++ * to setup the hardware access speeds and set the controller to be enabled.
++*/
++static int s3c2410_nand_inithw(struct s3c2410_nand_info *info)
++{
++	int ret;
++
++	ret = s3c2410_nand_setrate(info);
++	if (ret < 0)
++		return ret;
++
++	switch (info->cpu_type) {
++	case TYPE_S3C2410:
++	default:
++		break;
++
++	case TYPE_S3C2440:
++	case TYPE_S3C2412:
++		/* enable the controller and de-assert nFCE */
++
++		writel(S3C2440_NFCONT_ENABLE, info->regs + S3C2440_NFCONT);
++	}
++
++	return 0;
++}
++
++/**
++ * s3c2410_nand_select_chip - select the given nand chip
++ * @mtd: The MTD instance for this chip.
++ * @chip: The chip number.
++ *
++ * This is called by the MTD layer to either select a given chip for the
++ * @mtd instance, or to indicate that the access has finished and the
++ * chip can be de-selected.
++ *
++ * The routine ensures that the nFCE line is correctly setup, and any
++ * platform specific selection code is called to route nFCE to the specific
++ * chip.
++ */
++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);
++	unsigned long cur;
++
++	nmtd = nand_get_controller_data(this);
++	info = nmtd->info;
++
++	if (chip != -1)
++		s3c2410_nand_clk_set_state(info, CLOCK_ENABLE);
++
++	cur = readl(info->sel_reg);
++
++	if (chip == -1) {
++		cur |= info->sel_bit;
++	} else {
++		if (nmtd->set != NULL && chip > nmtd->set->nr_chips) {
++			dev_err(info->device, "invalid chip %d\n", chip);
++			return;
++		}
++
++		if (info->platform != NULL) {
++			if (info->platform->select_chip != NULL)
++				(info->platform->select_chip) (nmtd->set, chip);
++		}
++
++		cur &= ~info->sel_bit;
++	}
++
++	writel(cur, info->sel_reg);
++
++	if (chip == -1)
++		s3c2410_nand_clk_set_state(info, CLOCK_SUSPEND);
++}
++
++/* s3c2410_nand_hwcontrol
++ *
++ * Issue command and address cycles to the chip
++*/
++
++static void s3c2410_nand_hwcontrol(struct mtd_info *mtd, int cmd,
++				   unsigned int ctrl)
++{
++	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
++
++	if (cmd == NAND_CMD_NONE)
++		return;
++
++	if (ctrl & NAND_CLE)
++		writeb(cmd, info->regs + S3C2410_NFCMD);
++	else
++		writeb(cmd, info->regs + S3C2410_NFADDR);
++}
++
++/* command and control functions */
++
++static void s3c2440_nand_hwcontrol(struct mtd_info *mtd, int cmd,
++				   unsigned int ctrl)
++{
++	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
++
++	if (cmd == NAND_CMD_NONE)
++		return;
++
++	if (ctrl & NAND_CLE)
++		writeb(cmd, info->regs + S3C2440_NFCMD);
++	else
++		writeb(cmd, info->regs + S3C2440_NFADDR);
++}
++
++/* s3c2410_nand_devready()
++ *
++ * returns 0 if the nand is busy, 1 if it is ready
++*/
++
++static int s3c2410_nand_devready(struct mtd_info *mtd)
++{
++	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
++	return readb(info->regs + S3C2410_NFSTAT) & S3C2410_NFSTAT_BUSY;
++}
++
++static int s3c2440_nand_devready(struct mtd_info *mtd)
++{
++	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
++	return readb(info->regs + S3C2440_NFSTAT) & S3C2440_NFSTAT_READY;
++}
++
++static int s3c2412_nand_devready(struct mtd_info *mtd)
++{
++	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
++	return readb(info->regs + S3C2412_NFSTAT) & S3C2412_NFSTAT_READY;
++}
++
++/* ECC handling functions */
++
++static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat,
++				     u_char *read_ecc, u_char *calc_ecc)
++{
++	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
++	unsigned int diff0, diff1, diff2;
++	unsigned int bit, byte;
++
++	pr_debug("%s(%p,%p,%p,%p)\n", __func__, mtd, dat, read_ecc, calc_ecc);
++
++	diff0 = read_ecc[0] ^ calc_ecc[0];
++	diff1 = read_ecc[1] ^ calc_ecc[1];
++	diff2 = read_ecc[2] ^ calc_ecc[2];
++
++	pr_debug("%s: rd %*phN calc %*phN diff %02x%02x%02x\n",
++		 __func__, 3, read_ecc, 3, calc_ecc,
++		 diff0, diff1, diff2);
++
++	if (diff0 == 0 && diff1 == 0 && diff2 == 0)
++		return 0;		/* ECC is ok */
++
++	/* sometimes people do not think about using the ECC, so check
++	 * to see if we have an 0xff,0xff,0xff read ECC and then ignore
++	 * the error, on the assumption that this is an un-eccd page.
++	 */
++	if (read_ecc[0] == 0xff && read_ecc[1] == 0xff && read_ecc[2] == 0xff
++	    && info->platform->ignore_unset_ecc)
++		return 0;
++
++	/* Can we correct this ECC (ie, one row and column change).
++	 * Note, this is similar to the 256 error code on smartmedia */
++
++	if (((diff0 ^ (diff0 >> 1)) & 0x55) == 0x55 &&
++	    ((diff1 ^ (diff1 >> 1)) & 0x55) == 0x55 &&
++	    ((diff2 ^ (diff2 >> 1)) & 0x55) == 0x55) {
++		/* calculate the bit position of the error */
++
++		bit  = ((diff2 >> 3) & 1) |
++		       ((diff2 >> 4) & 2) |
++		       ((diff2 >> 5) & 4);
++
++		/* calculate the byte position of the error */
++
++		byte = ((diff2 << 7) & 0x100) |
++		       ((diff1 << 0) & 0x80)  |
++		       ((diff1 << 1) & 0x40)  |
++		       ((diff1 << 2) & 0x20)  |
++		       ((diff1 << 3) & 0x10)  |
++		       ((diff0 >> 4) & 0x08)  |
++		       ((diff0 >> 3) & 0x04)  |
++		       ((diff0 >> 2) & 0x02)  |
++		       ((diff0 >> 1) & 0x01);
++
++		dev_dbg(info->device, "correcting error bit %d, byte %d\n",
++			bit, byte);
++
++		dat[byte] ^= (1 << bit);
++		return 1;
++	}
++
++	/* if there is only one bit difference in the ECC, then
++	 * one of only a row or column parity has changed, which
++	 * means the error is most probably in the ECC itself */
++
++	diff0 |= (diff1 << 8);
++	diff0 |= (diff2 << 16);
++
++	/* equal to "(diff0 & ~(1 << __ffs(diff0)))" */
++	if ((diff0 & (diff0 - 1)) == 0)
++		return 1;
++
++	return -1;
++}
++
++/* ECC functions
++ *
++ * These allow the s3c2410 and s3c2440 to use the controller's ECC
++ * generator block to ECC the data as it passes through]
++*/
++
++static void s3c2410_nand_enable_hwecc(struct mtd_info *mtd, int mode)
++{
++	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
++	unsigned long ctrl;
++
++	ctrl = readl(info->regs + S3C2410_NFCONF);
++	ctrl |= S3C2410_NFCONF_INITECC;
++	writel(ctrl, info->regs + S3C2410_NFCONF);
++}
++
++static void s3c2412_nand_enable_hwecc(struct mtd_info *mtd, int mode)
++{
++	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
++	unsigned long ctrl;
++
++	ctrl = readl(info->regs + S3C2440_NFCONT);
++	writel(ctrl | S3C2412_NFCONT_INIT_MAIN_ECC,
++	       info->regs + S3C2440_NFCONT);
++}
++
++static void s3c2440_nand_enable_hwecc(struct mtd_info *mtd, int mode)
++{
++	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
++	unsigned long ctrl;
++
++	ctrl = readl(info->regs + S3C2440_NFCONT);
++	writel(ctrl | S3C2440_NFCONT_INITECC, info->regs + S3C2440_NFCONT);
++}
++
++static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
++				      u_char *ecc_code)
++{
++	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
++
++	ecc_code[0] = readb(info->regs + S3C2410_NFECC + 0);
++	ecc_code[1] = readb(info->regs + S3C2410_NFECC + 1);
++	ecc_code[2] = readb(info->regs + S3C2410_NFECC + 2);
++
++	pr_debug("%s: returning ecc %*phN\n", __func__, 3, ecc_code);
++
++	return 0;
++}
++
++static int s3c2412_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
++				      u_char *ecc_code)
++{
++	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
++	unsigned long ecc = readl(info->regs + S3C2412_NFMECC0);
++
++	ecc_code[0] = ecc;
++	ecc_code[1] = ecc >> 8;
++	ecc_code[2] = ecc >> 16;
++
++	pr_debug("%s: returning ecc %*phN\n", __func__, 3, ecc_code);
++
++	return 0;
++}
++
++static int s3c2440_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
++				      u_char *ecc_code)
++{
++	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
++	unsigned long ecc = readl(info->regs + S3C2440_NFMECC0);
++
++	ecc_code[0] = ecc;
++	ecc_code[1] = ecc >> 8;
++	ecc_code[2] = ecc >> 16;
++
++	pr_debug("%s: returning ecc %06lx\n", __func__, ecc & 0xffffff);
++
++	return 0;
++}
++
++/* 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
++*/
++
++static void s3c2410_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
++{
++	struct nand_chip *this = mtd_to_nand(mtd);
++	readsb(this->IO_ADDR_R, buf, len);
++}
++
++static void s3c2440_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
++{
++	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
++
++	readsl(info->regs + S3C2440_NFDATA, buf, len >> 2);
++
++	/* cleanup if we've got less than a word to do */
++	if (len & 3) {
++		buf += len & ~3;
++
++		for (; len & 3; len--)
++			*buf++ = readb(info->regs + S3C2440_NFDATA);
++	}
++}
++
++static void s3c2410_nand_write_buf(struct mtd_info *mtd, const u_char *buf,
++				   int len)
++{
++	struct nand_chip *this = mtd_to_nand(mtd);
++	writesb(this->IO_ADDR_W, buf, len);
++}
++
++static void s3c2440_nand_write_buf(struct mtd_info *mtd, const u_char *buf,
++				   int len)
++{
++	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
++
++	writesl(info->regs + S3C2440_NFDATA, buf, len >> 2);
++
++	/* cleanup any fractional write */
++	if (len & 3) {
++		buf += len & ~3;
++
++		for (; len & 3; len--, buf++)
++			writeb(*buf, info->regs + S3C2440_NFDATA);
++	}
++}
++
++/* cpufreq driver support */
++
++#ifdef CONFIG_ARM_S3C24XX_CPUFREQ
++
++static int s3c2410_nand_cpufreq_transition(struct notifier_block *nb,
++					  unsigned long val, void *data)
++{
++	struct s3c2410_nand_info *info;
++	unsigned long newclk;
++
++	info = container_of(nb, struct s3c2410_nand_info, freq_transition);
++	newclk = clk_get_rate(info->clk);
++
++	if ((val == CPUFREQ_POSTCHANGE && newclk < info->clk_rate) ||
++	    (val == CPUFREQ_PRECHANGE && newclk > info->clk_rate)) {
++		s3c2410_nand_setrate(info);
++	}
++
++	return 0;
++}
++
++static inline int s3c2410_nand_cpufreq_register(struct s3c2410_nand_info *info)
++{
++	info->freq_transition.notifier_call = s3c2410_nand_cpufreq_transition;
++
++	return cpufreq_register_notifier(&info->freq_transition,
++					 CPUFREQ_TRANSITION_NOTIFIER);
++}
++
++static inline void
++s3c2410_nand_cpufreq_deregister(struct s3c2410_nand_info *info)
++{
++	cpufreq_unregister_notifier(&info->freq_transition,
++				    CPUFREQ_TRANSITION_NOTIFIER);
++}
++
++#else
++static inline int s3c2410_nand_cpufreq_register(struct s3c2410_nand_info *info)
++{
++	return 0;
++}
++
++static inline void
++s3c2410_nand_cpufreq_deregister(struct s3c2410_nand_info *info)
++{
++}
++#endif
++
++/* device management functions */
++
++static int s3c24xx_nand_remove(struct platform_device *pdev)
++{
++	struct s3c2410_nand_info *info = to_nand_info(pdev);
++
++	if (info == NULL)
++		return 0;
++
++	s3c2410_nand_cpufreq_deregister(info);
++
++	/* Release all our mtds  and their partitions, then go through
++	 * freeing the resources used
++	 */
++
++	if (info->mtds != NULL) {
++		struct s3c2410_nand_mtd *ptr = info->mtds;
++		int mtdno;
++
++		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));
++		}
++	}
++
++	/* free the common resources */
++
++	if (!IS_ERR(info->clk))
++		s3c2410_nand_clk_set_state(info, CLOCK_DISABLE);
++
++	return 0;
++}
++
++static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info,
++				      struct s3c2410_nand_mtd *mtd,
++				      struct s3c2410_nand_set *set)
++{
++	if (set) {
++		struct mtd_info *mtdinfo = nand_to_mtd(&mtd->chip);
++
++		mtdinfo->name = set->name;
++
++		return mtd_device_parse_register(mtdinfo, NULL, NULL,
++					 set->partitions, set->nr_partitions);
++	}
++
++	return -ENODEV;
++}
++
++static int s3c2410_nand_setup_data_interface(struct mtd_info *mtd, int csline,
++					const struct nand_data_interface *conf)
++{
++	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.
++ * @nmtd: The new controller MTD instance to fill in.
++ * @set: The information passed from the board specific platform data.
++ *
++ * Initialise the given @nmtd from the information in @info and @set. This
++ * readies the structure for use with the MTD layer functions by ensuring
++ * all pointers are setup and the necessary control routines selected.
++ */
++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;
++	chip->chip_delay   = 50;
++	nand_set_controller_data(chip, nmtd);
++	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;
++		info->sel_reg   = regs + S3C2410_NFCONF;
++		info->sel_bit	= S3C2410_NFCONF_nFCE;
++		chip->cmd_ctrl  = s3c2410_nand_hwcontrol;
++		chip->dev_ready = s3c2410_nand_devready;
++		break;
++
++	case TYPE_S3C2440:
++		chip->IO_ADDR_W = regs + S3C2440_NFDATA;
++		info->sel_reg   = regs + S3C2440_NFCONT;
++		info->sel_bit	= S3C2440_NFCONT_nFCE;
++		chip->cmd_ctrl  = s3c2440_nand_hwcontrol;
++		chip->dev_ready = s3c2440_nand_devready;
++		chip->read_buf  = s3c2440_nand_read_buf;
++		chip->write_buf	= s3c2440_nand_write_buf;
++		break;
++
++	case TYPE_S3C2412:
++		chip->IO_ADDR_W = regs + S3C2440_NFDATA;
++		info->sel_reg   = regs + S3C2440_NFCONT;
++		info->sel_bit	= S3C2412_NFCONT_nFCE0;
++		chip->cmd_ctrl  = s3c2440_nand_hwcontrol;
++		chip->dev_ready = s3c2412_nand_devready;
++
++		if (readl(regs + S3C2410_NFCONF) & S3C2412_NFCONF_NANDBOOT)
++			dev_info(info->device, "System booted from NAND\n");
++
++		break;
++	}
++
++	chip->IO_ADDR_R = chip->IO_ADDR_W;
++
++	nmtd->info	   = info;
++	nmtd->set	   = set;
++
++	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.
++	 */
++	if (set->flash_bbt)
++		chip->bbt_options |= NAND_BBT_USE_FLASH;
++}
++
++/**
++ * s3c2410_nand_update_chip - post probe update
++ * @info: The controller instance.
++ * @nmtd: The driver version of the MTD instance.
++ *
++ * This routine is called after the chip probe has successfully completed
++ * and the relevant per-chip information updated. This call ensure that
++ * we update the internal state accordingly.
++ *
++ * The internal state is currently limited to the ECC state information.
++*/
++static int s3c2410_nand_update_chip(struct s3c2410_nand_info *info,
++				    struct s3c2410_nand_mtd *nmtd)
++{
++	struct nand_chip *chip = &nmtd->chip;
++
++	switch (chip->ecc.mode) {
++
++	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);
++		}
++
++		dev_info(info->device, "hardware ECC\n");
++		break;
++
++	default:
++		dev_err(info->device, "invalid ECC mode!\n");
++		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,
++	}, {
++		/* also compatible with s3c6400 */
++		.compatible = "samsung,s3c2412-nand",
++		.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;
++}
++
++/* s3c24xx_nand_probe
++ *
++ * called by device layer when it finds a device matching
++ * one our driver can handled. This code checks to see if
++ * it can allocate all necessary resources then calls the
++ * nand layer to look for devices
++*/
++static int s3c24xx_nand_probe(struct platform_device *pdev)
++{
++	struct s3c2410_platform_nand *plat;
++	struct s3c2410_nand_info *info;
++	struct s3c2410_nand_mtd *nmtd;
++	struct s3c2410_nand_set *sets;
++	struct resource *res;
++	int err = 0;
++	int size;
++	int nr_sets;
++	int setno;
++
++	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
++	if (info == NULL) {
++		err = -ENOMEM;
++		goto exit_error;
++	}
++
++	platform_set_drvdata(pdev, info);
++
++	nand_hw_control_init(&info->controller);
++
++	/* get the clock source and enable it */
++
++	info->clk = devm_clk_get(&pdev->dev, "nand");
++	if (IS_ERR(info->clk)) {
++		dev_err(&pdev->dev, "failed to get clock\n");
++		err = -ENOENT;
++		goto exit_error;
++	}
++
++	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 */
++	res = pdev->resource;
++	size = resource_size(res);
++
++	info->device	= &pdev->dev;
++	info->platform	= plat;
++
++	info->regs = devm_ioremap_resource(&pdev->dev, res);
++	if (IS_ERR(info->regs)) {
++		err = PTR_ERR(info->regs);
++		goto exit_error;
++	}
++
++	dev_dbg(&pdev->dev, "mapped registers at %p\n", info->regs);
++
++	sets = (plat != NULL) ? plat->sets : NULL;
++	nr_sets = (plat != NULL) ? plat->nr_sets : 1;
++
++	info->mtd_count = nr_sets;
++
++	/* allocate our information */
++
++	size = nr_sets * sizeof(*info->mtds);
++	info->mtds = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
++	if (info->mtds == NULL) {
++		err = -ENOMEM;
++		goto exit_error;
++	}
++
++	/* initialise all possible chips */
++
++	nmtd = info->mtds;
++
++	for (setno = 0; setno < nr_sets; setno++, nmtd++) {
++		struct mtd_info *mtd = nand_to_mtd(&nmtd->chip);
++
++		pr_debug("initialising set %d (%p, info %p)\n",
++			 setno, nmtd, info);
++
++		mtd->dev.parent = &pdev->dev;
++		s3c2410_nand_init_chip(info, nmtd, sets);
++
++		nmtd->scan_res = nand_scan_ident(mtd,
++						 (sets) ? sets->nr_chips : 1,
++						 NULL);
++
++		if (nmtd->scan_res == 0) {
++			err = s3c2410_nand_update_chip(info, nmtd);
++			if (err < 0)
++				goto exit_error;
++			nand_scan_tail(mtd);
++			s3c2410_nand_add_partition(info, nmtd, sets);
++		}
++
++		if (sets != NULL)
++			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");
++		goto exit_error;
++	}
++
++	if (allow_clk_suspend(info)) {
++		dev_info(&pdev->dev, "clock idle support enabled\n");
++		s3c2410_nand_clk_set_state(info, CLOCK_SUSPEND);
++	}
++
++	return 0;
++
++ exit_error:
++	s3c24xx_nand_remove(pdev);
++
++	if (err == 0)
++		err = -EINVAL;
++	return err;
++}
++
++/* PM Support */
++#ifdef CONFIG_PM
++
++static int s3c24xx_nand_suspend(struct platform_device *dev, pm_message_t pm)
++{
++	struct s3c2410_nand_info *info = platform_get_drvdata(dev);
++
++	if (info) {
++		info->save_sel = readl(info->sel_reg);
++
++		/* For the moment, we must ensure nFCE is high during
++		 * the time we are suspended. This really should be
++		 * handled by suspending the MTDs we are using, but
++		 * that is currently not the case. */
++
++		writel(info->save_sel | info->sel_bit, info->sel_reg);
++
++		s3c2410_nand_clk_set_state(info, CLOCK_DISABLE);
++	}
++
++	return 0;
++}
++
++static int s3c24xx_nand_resume(struct platform_device *dev)
++{
++	struct s3c2410_nand_info *info = platform_get_drvdata(dev);
++	unsigned long sel;
++
++	if (info) {
++		s3c2410_nand_clk_set_state(info, CLOCK_ENABLE);
++		s3c2410_nand_inithw(info);
++
++		/* Restore the state of the nFCE line. */
++
++		sel = readl(info->sel_reg);
++		sel &= ~info->sel_bit;
++		sel |= info->save_sel & info->sel_bit;
++		writel(sel, info->sel_reg);
++
++		s3c2410_nand_clk_set_state(info, CLOCK_SUSPEND);
++	}
++
++	return 0;
++}
++
++#else
++#define s3c24xx_nand_suspend NULL
++#define s3c24xx_nand_resume NULL
++#endif
++
++/* driver device registration */
++
++static const struct platform_device_id s3c24xx_driver_ids[] = {
++	{
++		.name		= "s3c2410-nand",
++		.driver_data	= TYPE_S3C2410,
++	}, {
++		.name		= "s3c2440-nand",
++		.driver_data	= TYPE_S3C2440,
++	}, {
++		.name		= "s3c2412-nand",
++		.driver_data	= TYPE_S3C2412,
++	}, {
++		.name		= "s3c6400-nand",
++		.driver_data	= TYPE_S3C2412, /* compatible with 2412 */
++	},
++	{ }
++};
++
++MODULE_DEVICE_TABLE(platform, s3c24xx_driver_ids);
++
++static struct platform_driver s3c24xx_nand_driver = {
++	.probe		= s3c24xx_nand_probe,
++	.remove		= s3c24xx_nand_remove,
++	.suspend	= s3c24xx_nand_suspend,
++	.resume		= s3c24xx_nand_resume,
++	.id_table	= s3c24xx_driver_ids,
++	.driver		= {
++		.name	= "s3c24xx-nand",
++		.of_match_table = s3c24xx_nand_dt_ids,
++	},
++};
++
++module_platform_driver(s3c24xx_nand_driver);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
++MODULE_DESCRIPTION("S3C24XX MTD NAND driver");
+diff --git a/drivers/mtd/nand/raw/sh_flctl.c b/drivers/mtd/nand/raw/sh_flctl.c
+new file mode 100644
+index 0000000..e7f3c98
+--- /dev/null
++++ b/drivers/mtd/nand/raw/sh_flctl.c
+@@ -0,0 +1,1253 @@
++/*
++ * SuperH FLCTL nand controller
++ *
++ * Copyright (c) 2008 Renesas Solutions Corp.
++ * Copyright (c) 2008 Atom Create Engineering Co., Ltd.
++ *
++ * Based on fsl_elbc_nand.c, Copyright (c) 2006-2007 Freescale Semiconductor
++ *
++ * 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.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/completion.h>
++#include <linux/delay.h>
++#include <linux/dmaengine.h>
++#include <linux/dma-mapping.h>
++#include <linux/interrupt.h>
++#include <linux/io.h>
++#include <linux/of.h>
++#include <linux/of_device.h>
++#include <linux/platform_device.h>
++#include <linux/pm_runtime.h>
++#include <linux/sh_dma.h>
++#include <linux/slab.h>
++#include <linux/string.h>
++
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/rawnand.h>
++#include <linux/mtd/partitions.h>
++#include <linux/mtd/sh_flctl.h>
++
++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);
++
++	if (section)
++		return -ERANGE;
++
++	oobregion->offset = 0;
++	oobregion->length = chip->ecc.bytes;
++
++	return 0;
++}
++
++static int flctl_4secc_ooblayout_sp_free(struct mtd_info *mtd, int section,
++					 struct mtd_oob_region *oobregion)
++{
++	if (section)
++		return -ERANGE;
++
++	oobregion->offset = 12;
++	oobregion->length = 4;
++
++	return 0;
++}
++
++static const struct mtd_ooblayout_ops flctl_4secc_oob_smallpage_ops = {
++	.ecc = flctl_4secc_ooblayout_sp_ecc,
++	.free = flctl_4secc_ooblayout_sp_free,
++};
++
++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);
++
++	if (section >= chip->ecc.steps)
++		return -ERANGE;
++
++	oobregion->offset = (section * 16) + 6;
++	oobregion->length = chip->ecc.bytes;
++
++	return 0;
++}
++
++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);
++
++	if (section >= chip->ecc.steps)
++		return -ERANGE;
++
++	oobregion->offset = section * 16;
++	oobregion->length = 6;
++
++	if (!section) {
++		oobregion->offset += 2;
++		oobregion->length -= 2;
++	}
++
++	return 0;
++}
++
++static const struct mtd_ooblayout_ops flctl_4secc_oob_largepage_ops = {
++	.ecc = flctl_4secc_ooblayout_lp_ecc,
++	.free = flctl_4secc_ooblayout_lp_free,
++};
++
++static uint8_t scan_ff_pattern[] = { 0xff, 0xff };
++
++static struct nand_bbt_descr flctl_4secc_smallpage = {
++	.options = NAND_BBT_SCAN2NDPAGE,
++	.offs = 11,
++	.len = 1,
++	.pattern = scan_ff_pattern,
++};
++
++static struct nand_bbt_descr flctl_4secc_largepage = {
++	.options = NAND_BBT_SCAN2NDPAGE,
++	.offs = 0,
++	.len = 2,
++	.pattern = scan_ff_pattern,
++};
++
++static void empty_fifo(struct sh_flctl *flctl)
++{
++	writel(flctl->flintdmacr_base | AC1CLR | AC0CLR, FLINTDMACR(flctl));
++	writel(flctl->flintdmacr_base, FLINTDMACR(flctl));
++}
++
++static void start_translation(struct sh_flctl *flctl)
++{
++	writeb(TRSTRT, FLTRCR(flctl));
++}
++
++static void timeout_error(struct sh_flctl *flctl, const char *str)
++{
++	dev_err(&flctl->pdev->dev, "Timeout occurred in %s\n", str);
++}
++
++static void wait_completion(struct sh_flctl *flctl)
++{
++	uint32_t timeout = LOOP_TIMEOUT_MAX;
++
++	while (timeout--) {
++		if (readb(FLTRCR(flctl)) & TREND) {
++			writeb(0x0, FLTRCR(flctl));
++			return;
++		}
++		udelay(1);
++	}
++
++	timeout_error(flctl, __func__);
++	writeb(0x0, FLTRCR(flctl));
++}
++
++static void flctl_dma_complete(void *param)
++{
++	struct sh_flctl *flctl = param;
++
++	complete(&flctl->dma_complete);
++}
++
++static void flctl_release_dma(struct sh_flctl *flctl)
++{
++	if (flctl->chan_fifo0_rx) {
++		dma_release_channel(flctl->chan_fifo0_rx);
++		flctl->chan_fifo0_rx = NULL;
++	}
++	if (flctl->chan_fifo0_tx) {
++		dma_release_channel(flctl->chan_fifo0_tx);
++		flctl->chan_fifo0_tx = NULL;
++	}
++}
++
++static void flctl_setup_dma(struct sh_flctl *flctl)
++{
++	dma_cap_mask_t mask;
++	struct dma_slave_config cfg;
++	struct platform_device *pdev = flctl->pdev;
++	struct sh_flctl_platform_data *pdata = dev_get_platdata(&pdev->dev);
++	int ret;
++
++	if (!pdata)
++		return;
++
++	if (pdata->slave_id_fifo0_tx <= 0 || pdata->slave_id_fifo0_rx <= 0)
++		return;
++
++	/* We can only either use DMA for both Tx and Rx or not use it at all */
++	dma_cap_zero(mask);
++	dma_cap_set(DMA_SLAVE, mask);
++
++	flctl->chan_fifo0_tx = dma_request_channel(mask, shdma_chan_filter,
++				(void *)(uintptr_t)pdata->slave_id_fifo0_tx);
++	dev_dbg(&pdev->dev, "%s: TX: got channel %p\n", __func__,
++		flctl->chan_fifo0_tx);
++
++	if (!flctl->chan_fifo0_tx)
++		return;
++
++	memset(&cfg, 0, sizeof(cfg));
++	cfg.direction = DMA_MEM_TO_DEV;
++	cfg.dst_addr = flctl->fifo;
++	cfg.src_addr = 0;
++	ret = dmaengine_slave_config(flctl->chan_fifo0_tx, &cfg);
++	if (ret < 0)
++		goto err;
++
++	flctl->chan_fifo0_rx = dma_request_channel(mask, shdma_chan_filter,
++				(void *)(uintptr_t)pdata->slave_id_fifo0_rx);
++	dev_dbg(&pdev->dev, "%s: RX: got channel %p\n", __func__,
++		flctl->chan_fifo0_rx);
++
++	if (!flctl->chan_fifo0_rx)
++		goto err;
++
++	cfg.direction = DMA_DEV_TO_MEM;
++	cfg.dst_addr = 0;
++	cfg.src_addr = flctl->fifo;
++	ret = dmaengine_slave_config(flctl->chan_fifo0_rx, &cfg);
++	if (ret < 0)
++		goto err;
++
++	init_completion(&flctl->dma_complete);
++
++	return;
++
++err:
++	flctl_release_dma(flctl);
++}
++
++static void set_addr(struct mtd_info *mtd, int column, int page_addr)
++{
++	struct sh_flctl *flctl = mtd_to_flctl(mtd);
++	uint32_t addr = 0;
++
++	if (column == -1) {
++		addr = page_addr;	/* ERASE1 */
++	} else if (page_addr != -1) {
++		/* SEQIN, READ0, etc.. */
++		if (flctl->chip.options & NAND_BUSWIDTH_16)
++			column >>= 1;
++		if (flctl->page_size) {
++			addr = column & 0x0FFF;
++			addr |= (page_addr & 0xff) << 16;
++			addr |= ((page_addr >> 8) & 0xff) << 24;
++			/* big than 128MB */
++			if (flctl->rw_ADRCNT == ADRCNT2_E) {
++				uint32_t 	addr2;
++				addr2 = (page_addr >> 16) & 0xff;
++				writel(addr2, FLADR2(flctl));
++			}
++		} else {
++			addr = column;
++			addr |= (page_addr & 0xff) << 8;
++			addr |= ((page_addr >> 8) & 0xff) << 16;
++			addr |= ((page_addr >> 16) & 0xff) << 24;
++		}
++	}
++	writel(addr, FLADR(flctl));
++}
++
++static void wait_rfifo_ready(struct sh_flctl *flctl)
++{
++	uint32_t timeout = LOOP_TIMEOUT_MAX;
++
++	while (timeout--) {
++		uint32_t val;
++		/* check FIFO */
++		val = readl(FLDTCNTR(flctl)) >> 16;
++		if (val & 0xFF)
++			return;
++		udelay(1);
++	}
++	timeout_error(flctl, __func__);
++}
++
++static void wait_wfifo_ready(struct sh_flctl *flctl)
++{
++	uint32_t len, timeout = LOOP_TIMEOUT_MAX;
++
++	while (timeout--) {
++		/* check FIFO */
++		len = (readl(FLDTCNTR(flctl)) >> 16) & 0xFF;
++		if (len >= 4)
++			return;
++		udelay(1);
++	}
++	timeout_error(flctl, __func__);
++}
++
++static enum flctl_ecc_res_t wait_recfifo_ready
++		(struct sh_flctl *flctl, int sector_number)
++{
++	uint32_t timeout = LOOP_TIMEOUT_MAX;
++	void __iomem *ecc_reg[4];
++	int i;
++	int state = FL_SUCCESS;
++	uint32_t data, size;
++
++	/*
++	 * First this loops checks in FLDTCNTR if we are ready to read out the
++	 * oob data. This is the case if either all went fine without errors or
++	 * if the bottom part of the loop corrected the errors or marked them as
++	 * uncorrectable and the controller is given time to push the data into
++	 * the FIFO.
++	 */
++	while (timeout--) {
++		/* check if all is ok and we can read out the OOB */
++		size = readl(FLDTCNTR(flctl)) >> 24;
++		if ((size & 0xFF) == 4)
++			return state;
++
++		/* check if a correction code has been calculated */
++		if (!(readl(FL4ECCCR(flctl)) & _4ECCEND)) {
++			/*
++			 * either we wait for the fifo to be filled or a
++			 * correction pattern is being generated
++			 */
++			udelay(1);
++			continue;
++		}
++
++		/* check for an uncorrectable error */
++		if (readl(FL4ECCCR(flctl)) & _4ECCFA) {
++			/* check if we face a non-empty page */
++			for (i = 0; i < 512; i++) {
++				if (flctl->done_buff[i] != 0xff) {
++					state = FL_ERROR; /* can't correct */
++					break;
++				}
++			}
++
++			if (state == FL_SUCCESS)
++				dev_dbg(&flctl->pdev->dev,
++				"reading empty sector %d, ecc error ignored\n",
++				sector_number);
++
++			writel(0, FL4ECCCR(flctl));
++			continue;
++		}
++
++		/* start error correction */
++		ecc_reg[0] = FL4ECCRESULT0(flctl);
++		ecc_reg[1] = FL4ECCRESULT1(flctl);
++		ecc_reg[2] = FL4ECCRESULT2(flctl);
++		ecc_reg[3] = FL4ECCRESULT3(flctl);
++
++		for (i = 0; i < 3; i++) {
++			uint8_t org;
++			unsigned int index;
++
++			data = readl(ecc_reg[i]);
++
++			if (flctl->page_size)
++				index = (512 * sector_number) +
++					(data >> 16);
++			else
++				index = data >> 16;
++
++			org = flctl->done_buff[index];
++			flctl->done_buff[index] = org ^ (data & 0xFF);
++		}
++		state = FL_REPAIRABLE;
++		writel(0, FL4ECCCR(flctl));
++	}
++
++	timeout_error(flctl, __func__);
++	return FL_TIMEOUT;	/* timeout */
++}
++
++static void wait_wecfifo_ready(struct sh_flctl *flctl)
++{
++	uint32_t timeout = LOOP_TIMEOUT_MAX;
++	uint32_t len;
++
++	while (timeout--) {
++		/* check FLECFIFO */
++		len = (readl(FLDTCNTR(flctl)) >> 24) & 0xFF;
++		if (len >= 4)
++			return;
++		udelay(1);
++	}
++	timeout_error(flctl, __func__);
++}
++
++static int flctl_dma_fifo0_transfer(struct sh_flctl *flctl, unsigned long *buf,
++					int len, enum dma_data_direction dir)
++{
++	struct dma_async_tx_descriptor *desc = NULL;
++	struct dma_chan *chan;
++	enum dma_transfer_direction tr_dir;
++	dma_addr_t dma_addr;
++	dma_cookie_t cookie;
++	uint32_t reg;
++	int ret;
++
++	if (dir == DMA_FROM_DEVICE) {
++		chan = flctl->chan_fifo0_rx;
++		tr_dir = DMA_DEV_TO_MEM;
++	} else {
++		chan = flctl->chan_fifo0_tx;
++		tr_dir = DMA_MEM_TO_DEV;
++	}
++
++	dma_addr = dma_map_single(chan->device->dev, buf, len, dir);
++
++	if (!dma_mapping_error(chan->device->dev, dma_addr))
++		desc = dmaengine_prep_slave_single(chan, dma_addr, len,
++			tr_dir, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
++
++	if (desc) {
++		reg = readl(FLINTDMACR(flctl));
++		reg |= DREQ0EN;
++		writel(reg, FLINTDMACR(flctl));
++
++		desc->callback = flctl_dma_complete;
++		desc->callback_param = flctl;
++		cookie = dmaengine_submit(desc);
++		if (dma_submit_error(cookie)) {
++			ret = dma_submit_error(cookie);
++			dev_warn(&flctl->pdev->dev,
++				 "DMA submit failed, falling back to PIO\n");
++			goto out;
++		}
++
++		dma_async_issue_pending(chan);
++	} else {
++		/* DMA failed, fall back to PIO */
++		flctl_release_dma(flctl);
++		dev_warn(&flctl->pdev->dev,
++			 "DMA failed, falling back to PIO\n");
++		ret = -EIO;
++		goto out;
++	}
++
++	ret =
++	wait_for_completion_timeout(&flctl->dma_complete,
++				msecs_to_jiffies(3000));
++
++	if (ret <= 0) {
++		dmaengine_terminate_all(chan);
++		dev_err(&flctl->pdev->dev, "wait_for_completion_timeout\n");
++	}
++
++out:
++	reg = readl(FLINTDMACR(flctl));
++	reg &= ~DREQ0EN;
++	writel(reg, FLINTDMACR(flctl));
++
++	dma_unmap_single(chan->device->dev, dma_addr, len, dir);
++
++	/* ret > 0 is success */
++	return ret;
++}
++
++static void read_datareg(struct sh_flctl *flctl, int offset)
++{
++	unsigned long data;
++	unsigned long *buf = (unsigned long *)&flctl->done_buff[offset];
++
++	wait_completion(flctl);
++
++	data = readl(FLDATAR(flctl));
++	*buf = le32_to_cpu(data);
++}
++
++static void read_fiforeg(struct sh_flctl *flctl, int rlen, int offset)
++{
++	int i, len_4align;
++	unsigned long *buf = (unsigned long *)&flctl->done_buff[offset];
++
++	len_4align = (rlen + 3) / 4;
++
++	/* initiate DMA transfer */
++	if (flctl->chan_fifo0_rx && rlen >= 32 &&
++		flctl_dma_fifo0_transfer(flctl, buf, rlen, DMA_DEV_TO_MEM) > 0)
++			goto convert;	/* DMA success */
++
++	/* do polling transfer */
++	for (i = 0; i < len_4align; i++) {
++		wait_rfifo_ready(flctl);
++		buf[i] = readl(FLDTFIFO(flctl));
++	}
++
++convert:
++	for (i = 0; i < len_4align; i++)
++		buf[i] = be32_to_cpu(buf[i]);
++}
++
++static enum flctl_ecc_res_t read_ecfiforeg
++		(struct sh_flctl *flctl, uint8_t *buff, int sector)
++{
++	int i;
++	enum flctl_ecc_res_t res;
++	unsigned long *ecc_buf = (unsigned long *)buff;
++
++	res = wait_recfifo_ready(flctl , sector);
++
++	if (res != FL_ERROR) {
++		for (i = 0; i < 4; i++) {
++			ecc_buf[i] = readl(FLECFIFO(flctl));
++			ecc_buf[i] = be32_to_cpu(ecc_buf[i]);
++		}
++	}
++
++	return res;
++}
++
++static void write_fiforeg(struct sh_flctl *flctl, int rlen,
++						unsigned int offset)
++{
++	int i, len_4align;
++	unsigned long *buf = (unsigned long *)&flctl->done_buff[offset];
++
++	len_4align = (rlen + 3) / 4;
++	for (i = 0; i < len_4align; i++) {
++		wait_wfifo_ready(flctl);
++		writel(cpu_to_be32(buf[i]), FLDTFIFO(flctl));
++	}
++}
++
++static void write_ec_fiforeg(struct sh_flctl *flctl, int rlen,
++						unsigned int offset)
++{
++	int i, len_4align;
++	unsigned long *buf = (unsigned long *)&flctl->done_buff[offset];
++
++	len_4align = (rlen + 3) / 4;
++
++	for (i = 0; i < len_4align; i++)
++		buf[i] = cpu_to_be32(buf[i]);
++
++	/* initiate DMA transfer */
++	if (flctl->chan_fifo0_tx && rlen >= 32 &&
++		flctl_dma_fifo0_transfer(flctl, buf, rlen, DMA_MEM_TO_DEV) > 0)
++			return;	/* DMA success */
++
++	/* do polling transfer */
++	for (i = 0; i < len_4align; i++) {
++		wait_wecfifo_ready(flctl);
++		writel(buf[i], FLECFIFO(flctl));
++	}
++}
++
++static void set_cmd_regs(struct mtd_info *mtd, uint32_t cmd, uint32_t flcmcdr_val)
++{
++	struct sh_flctl *flctl = mtd_to_flctl(mtd);
++	uint32_t flcmncr_val = flctl->flcmncr_base & ~SEL_16BIT;
++	uint32_t flcmdcr_val, addr_len_bytes = 0;
++
++	/* Set SNAND bit if page size is 2048byte */
++	if (flctl->page_size)
++		flcmncr_val |= SNAND_E;
++	else
++		flcmncr_val &= ~SNAND_E;
++
++	/* default FLCMDCR val */
++	flcmdcr_val = DOCMD1_E | DOADR_E;
++
++	/* Set for FLCMDCR */
++	switch (cmd) {
++	case NAND_CMD_ERASE1:
++		addr_len_bytes = flctl->erase_ADRCNT;
++		flcmdcr_val |= DOCMD2_E;
++		break;
++	case NAND_CMD_READ0:
++	case NAND_CMD_READOOB:
++	case NAND_CMD_RNDOUT:
++		addr_len_bytes = flctl->rw_ADRCNT;
++		flcmdcr_val |= CDSRC_E;
++		if (flctl->chip.options & NAND_BUSWIDTH_16)
++			flcmncr_val |= SEL_16BIT;
++		break;
++	case NAND_CMD_SEQIN:
++		/* This case is that cmd is READ0 or READ1 or READ00 */
++		flcmdcr_val &= ~DOADR_E;	/* ONLY execute 1st cmd */
++		break;
++	case NAND_CMD_PAGEPROG:
++		addr_len_bytes = flctl->rw_ADRCNT;
++		flcmdcr_val |= DOCMD2_E | CDSRC_E | SELRW;
++		if (flctl->chip.options & NAND_BUSWIDTH_16)
++			flcmncr_val |= SEL_16BIT;
++		break;
++	case NAND_CMD_READID:
++		flcmncr_val &= ~SNAND_E;
++		flcmdcr_val |= CDSRC_E;
++		addr_len_bytes = ADRCNT_1;
++		break;
++	case NAND_CMD_STATUS:
++	case NAND_CMD_RESET:
++		flcmncr_val &= ~SNAND_E;
++		flcmdcr_val &= ~(DOADR_E | DOSR_E);
++		break;
++	default:
++		break;
++	}
++
++	/* Set address bytes parameter */
++	flcmdcr_val |= addr_len_bytes;
++
++	/* Now actually write */
++	writel(flcmncr_val, FLCMNCR(flctl));
++	writel(flcmdcr_val, FLCMDCR(flctl));
++	writel(flcmcdr_val, FLCMCDR(flctl));
++}
++
++static int flctl_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
++				uint8_t *buf, int oob_required, int page)
++{
++	chip->read_buf(mtd, buf, mtd->writesize);
++	if (oob_required)
++		chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
++	return 0;
++}
++
++static int flctl_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
++				  const uint8_t *buf, int oob_required,
++				  int page)
++{
++	chip->write_buf(mtd, buf, mtd->writesize);
++	chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
++	return 0;
++}
++
++static void execmd_read_page_sector(struct mtd_info *mtd, int page_addr)
++{
++	struct sh_flctl *flctl = mtd_to_flctl(mtd);
++	int sector, page_sectors;
++	enum flctl_ecc_res_t ecc_result;
++
++	page_sectors = flctl->page_size ? 4 : 1;
++
++	set_cmd_regs(mtd, NAND_CMD_READ0,
++		(NAND_CMD_READSTART << 8) | NAND_CMD_READ0);
++
++	writel(readl(FLCMNCR(flctl)) | ACM_SACCES_MODE | _4ECCCORRECT,
++		 FLCMNCR(flctl));
++	writel(readl(FLCMDCR(flctl)) | page_sectors, FLCMDCR(flctl));
++	writel(page_addr << 2, FLADR(flctl));
++
++	empty_fifo(flctl);
++	start_translation(flctl);
++
++	for (sector = 0; sector < page_sectors; sector++) {
++		read_fiforeg(flctl, 512, 512 * sector);
++
++		ecc_result = read_ecfiforeg(flctl,
++			&flctl->done_buff[mtd->writesize + 16 * sector],
++			sector);
++
++		switch (ecc_result) {
++		case FL_REPAIRABLE:
++			dev_info(&flctl->pdev->dev,
++				"applied ecc on page 0x%x", page_addr);
++			mtd->ecc_stats.corrected++;
++			break;
++		case FL_ERROR:
++			dev_warn(&flctl->pdev->dev,
++				"page 0x%x contains corrupted data\n",
++				page_addr);
++			mtd->ecc_stats.failed++;
++			break;
++		default:
++			;
++		}
++	}
++
++	wait_completion(flctl);
++
++	writel(readl(FLCMNCR(flctl)) & ~(ACM_SACCES_MODE | _4ECCCORRECT),
++			FLCMNCR(flctl));
++}
++
++static void execmd_read_oob(struct mtd_info *mtd, int page_addr)
++{
++	struct sh_flctl *flctl = mtd_to_flctl(mtd);
++	int page_sectors = flctl->page_size ? 4 : 1;
++	int i;
++
++	set_cmd_regs(mtd, NAND_CMD_READ0,
++		(NAND_CMD_READSTART << 8) | NAND_CMD_READ0);
++
++	empty_fifo(flctl);
++
++	for (i = 0; i < page_sectors; i++) {
++		set_addr(mtd, (512 + 16) * i + 512 , page_addr);
++		writel(16, FLDTCNTR(flctl));
++
++		start_translation(flctl);
++		read_fiforeg(flctl, 16, 16 * i);
++		wait_completion(flctl);
++	}
++}
++
++static void execmd_write_page_sector(struct mtd_info *mtd)
++{
++	struct sh_flctl *flctl = mtd_to_flctl(mtd);
++	int page_addr = flctl->seqin_page_addr;
++	int sector, page_sectors;
++
++	page_sectors = flctl->page_size ? 4 : 1;
++
++	set_cmd_regs(mtd, NAND_CMD_PAGEPROG,
++			(NAND_CMD_PAGEPROG << 8) | NAND_CMD_SEQIN);
++
++	empty_fifo(flctl);
++	writel(readl(FLCMNCR(flctl)) | ACM_SACCES_MODE, FLCMNCR(flctl));
++	writel(readl(FLCMDCR(flctl)) | page_sectors, FLCMDCR(flctl));
++	writel(page_addr << 2, FLADR(flctl));
++	start_translation(flctl);
++
++	for (sector = 0; sector < page_sectors; sector++) {
++		write_fiforeg(flctl, 512, 512 * sector);
++		write_ec_fiforeg(flctl, 16, mtd->writesize + 16 * sector);
++	}
++
++	wait_completion(flctl);
++	writel(readl(FLCMNCR(flctl)) & ~ACM_SACCES_MODE, FLCMNCR(flctl));
++}
++
++static void execmd_write_oob(struct mtd_info *mtd)
++{
++	struct sh_flctl *flctl = mtd_to_flctl(mtd);
++	int page_addr = flctl->seqin_page_addr;
++	int sector, page_sectors;
++
++	page_sectors = flctl->page_size ? 4 : 1;
++
++	set_cmd_regs(mtd, NAND_CMD_PAGEPROG,
++			(NAND_CMD_PAGEPROG << 8) | NAND_CMD_SEQIN);
++
++	for (sector = 0; sector < page_sectors; sector++) {
++		empty_fifo(flctl);
++		set_addr(mtd, sector * 528 + 512, page_addr);
++		writel(16, FLDTCNTR(flctl));	/* set read size */
++
++		start_translation(flctl);
++		write_fiforeg(flctl, 16, 16 * sector);
++		wait_completion(flctl);
++	}
++}
++
++static void flctl_cmdfunc(struct mtd_info *mtd, unsigned int command,
++			int column, int page_addr)
++{
++	struct sh_flctl *flctl = mtd_to_flctl(mtd);
++	uint32_t read_cmd = 0;
++
++	pm_runtime_get_sync(&flctl->pdev->dev);
++
++	flctl->read_bytes = 0;
++	if (command != NAND_CMD_PAGEPROG)
++		flctl->index = 0;
++
++	switch (command) {
++	case NAND_CMD_READ1:
++	case NAND_CMD_READ0:
++		if (flctl->hwecc) {
++			/* read page with hwecc */
++			execmd_read_page_sector(mtd, page_addr);
++			break;
++		}
++		if (flctl->page_size)
++			set_cmd_regs(mtd, command, (NAND_CMD_READSTART << 8)
++				| command);
++		else
++			set_cmd_regs(mtd, command, command);
++
++		set_addr(mtd, 0, page_addr);
++
++		flctl->read_bytes = mtd->writesize + mtd->oobsize;
++		if (flctl->chip.options & NAND_BUSWIDTH_16)
++			column >>= 1;
++		flctl->index += column;
++		goto read_normal_exit;
++
++	case NAND_CMD_READOOB:
++		if (flctl->hwecc) {
++			/* read page with hwecc */
++			execmd_read_oob(mtd, page_addr);
++			break;
++		}
++
++		if (flctl->page_size) {
++			set_cmd_regs(mtd, command, (NAND_CMD_READSTART << 8)
++				| NAND_CMD_READ0);
++			set_addr(mtd, mtd->writesize, page_addr);
++		} else {
++			set_cmd_regs(mtd, command, command);
++			set_addr(mtd, 0, page_addr);
++		}
++		flctl->read_bytes = mtd->oobsize;
++		goto read_normal_exit;
++
++	case NAND_CMD_RNDOUT:
++		if (flctl->hwecc)
++			break;
++
++		if (flctl->page_size)
++			set_cmd_regs(mtd, command, (NAND_CMD_RNDOUTSTART << 8)
++				| command);
++		else
++			set_cmd_regs(mtd, command, command);
++
++		set_addr(mtd, column, 0);
++
++		flctl->read_bytes = mtd->writesize + mtd->oobsize - column;
++		goto read_normal_exit;
++
++	case NAND_CMD_READID:
++		set_cmd_regs(mtd, command, command);
++
++		/* READID is always performed using an 8-bit bus */
++		if (flctl->chip.options & NAND_BUSWIDTH_16)
++			column <<= 1;
++		set_addr(mtd, column, 0);
++
++		flctl->read_bytes = 8;
++		writel(flctl->read_bytes, FLDTCNTR(flctl)); /* set read size */
++		empty_fifo(flctl);
++		start_translation(flctl);
++		read_fiforeg(flctl, flctl->read_bytes, 0);
++		wait_completion(flctl);
++		break;
++
++	case NAND_CMD_ERASE1:
++		flctl->erase1_page_addr = page_addr;
++		break;
++
++	case NAND_CMD_ERASE2:
++		set_cmd_regs(mtd, NAND_CMD_ERASE1,
++			(command << 8) | NAND_CMD_ERASE1);
++		set_addr(mtd, -1, flctl->erase1_page_addr);
++		start_translation(flctl);
++		wait_completion(flctl);
++		break;
++
++	case NAND_CMD_SEQIN:
++		if (!flctl->page_size) {
++			/* output read command */
++			if (column >= mtd->writesize) {
++				column -= mtd->writesize;
++				read_cmd = NAND_CMD_READOOB;
++			} else if (column < 256) {
++				read_cmd = NAND_CMD_READ0;
++			} else {
++				column -= 256;
++				read_cmd = NAND_CMD_READ1;
++			}
++		}
++		flctl->seqin_column = column;
++		flctl->seqin_page_addr = page_addr;
++		flctl->seqin_read_cmd = read_cmd;
++		break;
++
++	case NAND_CMD_PAGEPROG:
++		empty_fifo(flctl);
++		if (!flctl->page_size) {
++			set_cmd_regs(mtd, NAND_CMD_SEQIN,
++					flctl->seqin_read_cmd);
++			set_addr(mtd, -1, -1);
++			writel(0, FLDTCNTR(flctl));	/* set 0 size */
++			start_translation(flctl);
++			wait_completion(flctl);
++		}
++		if (flctl->hwecc) {
++			/* write page with hwecc */
++			if (flctl->seqin_column == mtd->writesize)
++				execmd_write_oob(mtd);
++			else if (!flctl->seqin_column)
++				execmd_write_page_sector(mtd);
++			else
++				printk(KERN_ERR "Invalid address !?\n");
++			break;
++		}
++		set_cmd_regs(mtd, command, (command << 8) | NAND_CMD_SEQIN);
++		set_addr(mtd, flctl->seqin_column, flctl->seqin_page_addr);
++		writel(flctl->index, FLDTCNTR(flctl));	/* set write size */
++		start_translation(flctl);
++		write_fiforeg(flctl, flctl->index, 0);
++		wait_completion(flctl);
++		break;
++
++	case NAND_CMD_STATUS:
++		set_cmd_regs(mtd, command, command);
++		set_addr(mtd, -1, -1);
++
++		flctl->read_bytes = 1;
++		writel(flctl->read_bytes, FLDTCNTR(flctl)); /* set read size */
++		start_translation(flctl);
++		read_datareg(flctl, 0); /* read and end */
++		break;
++
++	case NAND_CMD_RESET:
++		set_cmd_regs(mtd, command, command);
++		set_addr(mtd, -1, -1);
++
++		writel(0, FLDTCNTR(flctl));	/* set 0 size */
++		start_translation(flctl);
++		wait_completion(flctl);
++		break;
++
++	default:
++		break;
++	}
++	goto runtime_exit;
++
++read_normal_exit:
++	writel(flctl->read_bytes, FLDTCNTR(flctl));	/* set read size */
++	empty_fifo(flctl);
++	start_translation(flctl);
++	read_fiforeg(flctl, flctl->read_bytes, 0);
++	wait_completion(flctl);
++runtime_exit:
++	pm_runtime_put_sync(&flctl->pdev->dev);
++	return;
++}
++
++static void flctl_select_chip(struct mtd_info *mtd, int chipnr)
++{
++	struct sh_flctl *flctl = mtd_to_flctl(mtd);
++	int ret;
++
++	switch (chipnr) {
++	case -1:
++		flctl->flcmncr_base &= ~CE0_ENABLE;
++
++		pm_runtime_get_sync(&flctl->pdev->dev);
++		writel(flctl->flcmncr_base, FLCMNCR(flctl));
++
++		if (flctl->qos_request) {
++			dev_pm_qos_remove_request(&flctl->pm_qos);
++			flctl->qos_request = 0;
++		}
++
++		pm_runtime_put_sync(&flctl->pdev->dev);
++		break;
++	case 0:
++		flctl->flcmncr_base |= CE0_ENABLE;
++
++		if (!flctl->qos_request) {
++			ret = dev_pm_qos_add_request(&flctl->pdev->dev,
++							&flctl->pm_qos,
++							DEV_PM_QOS_RESUME_LATENCY,
++							100);
++			if (ret < 0)
++				dev_err(&flctl->pdev->dev,
++					"PM QoS request failed: %d\n", ret);
++			flctl->qos_request = 1;
++		}
++
++		if (flctl->holden) {
++			pm_runtime_get_sync(&flctl->pdev->dev);
++			writel(HOLDEN, FLHOLDCR(flctl));
++			pm_runtime_put_sync(&flctl->pdev->dev);
++		}
++		break;
++	default:
++		BUG();
++	}
++}
++
++static void flctl_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
++{
++	struct sh_flctl *flctl = mtd_to_flctl(mtd);
++
++	memcpy(&flctl->done_buff[flctl->index], buf, len);
++	flctl->index += len;
++}
++
++static uint8_t flctl_read_byte(struct mtd_info *mtd)
++{
++	struct sh_flctl *flctl = mtd_to_flctl(mtd);
++	uint8_t data;
++
++	data = flctl->done_buff[flctl->index];
++	flctl->index++;
++	return data;
++}
++
++static uint16_t flctl_read_word(struct mtd_info *mtd)
++{
++	struct sh_flctl *flctl = mtd_to_flctl(mtd);
++	uint16_t *buf = (uint16_t *)&flctl->done_buff[flctl->index];
++
++	flctl->index += 2;
++	return *buf;
++}
++
++static void flctl_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
++{
++	struct sh_flctl *flctl = mtd_to_flctl(mtd);
++
++	memcpy(buf, &flctl->done_buff[flctl->index], len);
++	flctl->index += len;
++}
++
++static int flctl_chip_init_tail(struct mtd_info *mtd)
++{
++	struct sh_flctl *flctl = mtd_to_flctl(mtd);
++	struct nand_chip *chip = &flctl->chip;
++
++	if (mtd->writesize == 512) {
++		flctl->page_size = 0;
++		if (chip->chipsize > (32 << 20)) {
++			/* big than 32MB */
++			flctl->rw_ADRCNT = ADRCNT_4;
++			flctl->erase_ADRCNT = ADRCNT_3;
++		} else if (chip->chipsize > (2 << 16)) {
++			/* big than 128KB */
++			flctl->rw_ADRCNT = ADRCNT_3;
++			flctl->erase_ADRCNT = ADRCNT_2;
++		} else {
++			flctl->rw_ADRCNT = ADRCNT_2;
++			flctl->erase_ADRCNT = ADRCNT_1;
++		}
++	} else {
++		flctl->page_size = 1;
++		if (chip->chipsize > (128 << 20)) {
++			/* big than 128MB */
++			flctl->rw_ADRCNT = ADRCNT2_E;
++			flctl->erase_ADRCNT = ADRCNT_3;
++		} else if (chip->chipsize > (8 << 16)) {
++			/* big than 512KB */
++			flctl->rw_ADRCNT = ADRCNT_4;
++			flctl->erase_ADRCNT = ADRCNT_2;
++		} else {
++			flctl->rw_ADRCNT = ADRCNT_3;
++			flctl->erase_ADRCNT = ADRCNT_1;
++		}
++	}
++
++	if (flctl->hwecc) {
++		if (mtd->writesize == 512) {
++			mtd_set_ooblayout(mtd, &flctl_4secc_oob_smallpage_ops);
++			chip->badblock_pattern = &flctl_4secc_smallpage;
++		} else {
++			mtd_set_ooblayout(mtd, &flctl_4secc_oob_largepage_ops);
++			chip->badblock_pattern = &flctl_4secc_largepage;
++		}
++
++		chip->ecc.size = 512;
++		chip->ecc.bytes = 10;
++		chip->ecc.strength = 4;
++		chip->ecc.read_page = flctl_read_page_hwecc;
++		chip->ecc.write_page = flctl_write_page_hwecc;
++		chip->ecc.mode = NAND_ECC_HW;
++
++		/* 4 symbols ECC enabled */
++		flctl->flcmncr_base |= _4ECCEN;
++	} else {
++		chip->ecc.mode = NAND_ECC_SOFT;
++		chip->ecc.algo = NAND_ECC_HAMMING;
++	}
++
++	return 0;
++}
++
++static irqreturn_t flctl_handle_flste(int irq, void *dev_id)
++{
++	struct sh_flctl *flctl = dev_id;
++
++	dev_err(&flctl->pdev->dev, "flste irq: %x\n", readl(FLINTDMACR(flctl)));
++	writel(flctl->flintdmacr_base, FLINTDMACR(flctl));
++
++	return IRQ_HANDLED;
++}
++
++struct flctl_soc_config {
++	unsigned long flcmncr_val;
++	unsigned has_hwecc:1;
++	unsigned use_holden:1;
++};
++
++static struct flctl_soc_config flctl_sh7372_config = {
++	.flcmncr_val = CLK_16B_12L_4H | TYPESEL_SET | SHBUSSEL,
++	.has_hwecc = 1,
++	.use_holden = 1,
++};
++
++static const struct of_device_id of_flctl_match[] = {
++	{ .compatible = "renesas,shmobile-flctl-sh7372",
++				.data = &flctl_sh7372_config },
++	{},
++};
++MODULE_DEVICE_TABLE(of, of_flctl_match);
++
++static struct sh_flctl_platform_data *flctl_parse_dt(struct device *dev)
++{
++	const struct of_device_id *match;
++	struct flctl_soc_config *config;
++	struct sh_flctl_platform_data *pdata;
++
++	match = of_match_device(of_flctl_match, dev);
++	if (match)
++		config = (struct flctl_soc_config *)match->data;
++	else {
++		dev_err(dev, "%s: no OF configuration attached\n", __func__);
++		return NULL;
++	}
++
++	pdata = devm_kzalloc(dev, sizeof(struct sh_flctl_platform_data),
++								GFP_KERNEL);
++	if (!pdata)
++		return NULL;
++
++	/* set SoC specific options */
++	pdata->flcmncr_val = config->flcmncr_val;
++	pdata->has_hwecc = config->has_hwecc;
++	pdata->use_holden = config->use_holden;
++
++	return pdata;
++}
++
++static int flctl_probe(struct platform_device *pdev)
++{
++	struct resource *res;
++	struct sh_flctl *flctl;
++	struct mtd_info *flctl_mtd;
++	struct nand_chip *nand;
++	struct sh_flctl_platform_data *pdata;
++	int ret;
++	int irq;
++
++	flctl = devm_kzalloc(&pdev->dev, sizeof(struct sh_flctl), GFP_KERNEL);
++	if (!flctl)
++		return -ENOMEM;
++
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	flctl->reg = devm_ioremap_resource(&pdev->dev, res);
++	if (IS_ERR(flctl->reg))
++		return PTR_ERR(flctl->reg);
++	flctl->fifo = res->start + 0x24; /* FLDTFIFO */
++
++	irq = platform_get_irq(pdev, 0);
++	if (irq < 0) {
++		dev_err(&pdev->dev, "failed to get flste irq data: %d\n", irq);
++		return irq;
++	}
++
++	ret = devm_request_irq(&pdev->dev, irq, flctl_handle_flste, IRQF_SHARED,
++			       "flste", flctl);
++	if (ret) {
++		dev_err(&pdev->dev, "request interrupt failed.\n");
++		return ret;
++	}
++
++	if (pdev->dev.of_node)
++		pdata = flctl_parse_dt(&pdev->dev);
++	else
++		pdata = dev_get_platdata(&pdev->dev);
++
++	if (!pdata) {
++		dev_err(&pdev->dev, "no setup data defined\n");
++		return -EINVAL;
++	}
++
++	platform_set_drvdata(pdev, flctl);
++	nand = &flctl->chip;
++	flctl_mtd = nand_to_mtd(nand);
++	nand_set_flash_node(nand, pdev->dev.of_node);
++	flctl_mtd->dev.parent = &pdev->dev;
++	flctl->pdev = pdev;
++	flctl->hwecc = pdata->has_hwecc;
++	flctl->holden = pdata->use_holden;
++	flctl->flcmncr_base = pdata->flcmncr_val;
++	flctl->flintdmacr_base = flctl->hwecc ? (STERINTE | ECERB) : STERINTE;
++
++	/* Set address of hardware control function */
++	/* 20 us command delay time */
++	nand->chip_delay = 20;
++
++	nand->read_byte = flctl_read_byte;
++	nand->read_word = flctl_read_word;
++	nand->write_buf = flctl_write_buf;
++	nand->read_buf = flctl_read_buf;
++	nand->select_chip = flctl_select_chip;
++	nand->cmdfunc = flctl_cmdfunc;
++	nand->onfi_set_features = nand_onfi_get_set_features_notsupp;
++	nand->onfi_get_features = nand_onfi_get_set_features_notsupp;
++
++	if (pdata->flcmncr_val & SEL_16BIT)
++		nand->options |= NAND_BUSWIDTH_16;
++
++	pm_runtime_enable(&pdev->dev);
++	pm_runtime_resume(&pdev->dev);
++
++	flctl_setup_dma(flctl);
++
++	ret = nand_scan_ident(flctl_mtd, 1, NULL);
++	if (ret)
++		goto err_chip;
++
++	if (nand->options & NAND_BUSWIDTH_16) {
++		/*
++		 * NAND_BUSWIDTH_16 may have been set by nand_scan_ident().
++		 * Add the SEL_16BIT flag in pdata->flcmncr_val and re-assign
++		 * flctl->flcmncr_base to pdata->flcmncr_val.
++		 */
++		pdata->flcmncr_val |= SEL_16BIT;
++		flctl->flcmncr_base = pdata->flcmncr_val;
++	}
++
++	ret = flctl_chip_init_tail(flctl_mtd);
++	if (ret)
++		goto err_chip;
++
++	ret = nand_scan_tail(flctl_mtd);
++	if (ret)
++		goto err_chip;
++
++	ret = mtd_device_register(flctl_mtd, pdata->parts, pdata->nr_parts);
++
++	return 0;
++
++err_chip:
++	flctl_release_dma(flctl);
++	pm_runtime_disable(&pdev->dev);
++	return ret;
++}
++
++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));
++	pm_runtime_disable(&pdev->dev);
++
++	return 0;
++}
++
++static struct platform_driver flctl_driver = {
++	.remove		= flctl_remove,
++	.driver = {
++		.name	= "sh_flctl",
++		.of_match_table = of_match_ptr(of_flctl_match),
++	},
++};
++
++module_platform_driver_probe(flctl_driver, flctl_probe);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Yoshihiro Shimoda");
++MODULE_DESCRIPTION("SuperH FLCTL driver");
++MODULE_ALIAS("platform:sh_flctl");
+diff --git a/drivers/mtd/nand/raw/sharpsl.c b/drivers/mtd/nand/raw/sharpsl.c
+new file mode 100644
+index 0000000..f59c455
+--- /dev/null
++++ b/drivers/mtd/nand/raw/sharpsl.c
+@@ -0,0 +1,235 @@
++/*
++ * drivers/mtd/nand/sharpsl.c
++ *
++ *  Copyright (C) 2004 Richard Purdie
++ *  Copyright (C) 2008 Dmitry Baryshkov
++ *
++ *  Based on Sharp's NAND driver sharp_sl.c
++ *
++ * 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/genhd.h>
++#include <linux/slab.h>
++#include <linux/module.h>
++#include <linux/delay.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/rawnand.h>
++#include <linux/mtd/nand_ecc.h>
++#include <linux/mtd/partitions.h>
++#include <linux/mtd/sharpsl.h>
++#include <linux/interrupt.h>
++#include <linux/platform_device.h>
++
++#include <asm/io.h>
++#include <mach/hardware.h>
++#include <asm/mach-types.h>
++
++struct sharpsl_nand {
++	struct nand_chip	chip;
++
++	void __iomem		*io;
++};
++
++static inline struct sharpsl_nand *mtd_to_sharpsl(struct mtd_info *mtd)
++{
++	return container_of(mtd_to_nand(mtd), struct sharpsl_nand, chip);
++}
++
++/* register offset */
++#define ECCLPLB		0x00	/* line parity 7 - 0 bit */
++#define ECCLPUB		0x04	/* line parity 15 - 8 bit */
++#define ECCCP		0x08	/* column parity 5 - 0 bit */
++#define ECCCNTR		0x0C	/* ECC byte counter */
++#define ECCCLRR		0x10	/* cleare ECC */
++#define FLASHIO		0x14	/* Flash I/O */
++#define FLASHCTL	0x18	/* Flash Control */
++
++/* Flash control bit */
++#define FLRYBY		(1 << 5)
++#define FLCE1		(1 << 4)
++#define FLWP		(1 << 3)
++#define FLALE		(1 << 2)
++#define FLCLE		(1 << 1)
++#define FLCE0		(1 << 0)
++
++/*
++ *	hardware specific access to control-lines
++ *	ctrl:
++ *	NAND_CNE: bit 0 -> ! bit 0 & 4
++ *	NAND_CLE: bit 1 -> bit 1
++ *	NAND_ALE: bit 2 -> bit 2
++ *
++ */
++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);
++
++	if (ctrl & NAND_CTRL_CHANGE) {
++		unsigned char bits = ctrl & 0x07;
++
++		bits |= (ctrl & 0x01) << 4;
++
++		bits ^= 0x11;
++
++		writeb((readb(sharpsl->io + FLASHCTL) & ~0x17) | bits, sharpsl->io + FLASHCTL);
++	}
++
++	if (cmd != NAND_CMD_NONE)
++		writeb(cmd, chip->IO_ADDR_W);
++}
++
++static int sharpsl_nand_dev_ready(struct mtd_info *mtd)
++{
++	struct sharpsl_nand *sharpsl = mtd_to_sharpsl(mtd);
++	return !((readb(sharpsl->io + FLASHCTL) & FLRYBY) == 0);
++}
++
++static void sharpsl_nand_enable_hwecc(struct mtd_info *mtd, int mode)
++{
++	struct sharpsl_nand *sharpsl = mtd_to_sharpsl(mtd);
++	writeb(0, sharpsl->io + ECCCLRR);
++}
++
++static int sharpsl_nand_calculate_ecc(struct mtd_info *mtd, const u_char * dat, u_char * ecc_code)
++{
++	struct sharpsl_nand *sharpsl = mtd_to_sharpsl(mtd);
++	ecc_code[0] = ~readb(sharpsl->io + ECCLPUB);
++	ecc_code[1] = ~readb(sharpsl->io + ECCLPLB);
++	ecc_code[2] = (~readb(sharpsl->io + ECCCP) << 2) | 0x03;
++	return readb(sharpsl->io + ECCCNTR) != 0;
++}
++
++/*
++ * Main initialization routine
++ */
++static int sharpsl_nand_probe(struct platform_device *pdev)
++{
++	struct nand_chip *this;
++	struct mtd_info *mtd;
++	struct resource *r;
++	int err = 0;
++	struct sharpsl_nand *sharpsl;
++	struct sharpsl_nand_platform_data *data = dev_get_platdata(&pdev->dev);
++
++	if (!data) {
++		dev_err(&pdev->dev, "no platform data!\n");
++		return -EINVAL;
++	}
++
++	/* Allocate memory for MTD device structure and private data */
++	sharpsl = kzalloc(sizeof(struct sharpsl_nand), GFP_KERNEL);
++	if (!sharpsl)
++		return -ENOMEM;
++
++	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	if (!r) {
++		dev_err(&pdev->dev, "no io memory resource defined!\n");
++		err = -ENODEV;
++		goto err_get_res;
++	}
++
++	/* map physical address */
++	sharpsl->io = ioremap(r->start, resource_size(r));
++	if (!sharpsl->io) {
++		dev_err(&pdev->dev, "ioremap to access Sharp SL NAND chip failed\n");
++		err = -EIO;
++		goto err_ioremap;
++	}
++
++	/* Get pointer to private data */
++	this = (struct nand_chip *)(&sharpsl->chip);
++
++	/* Link the private data with the MTD structure */
++	mtd = nand_to_mtd(this);
++	mtd->dev.parent = &pdev->dev;
++	mtd_set_ooblayout(mtd, data->ecc_layout);
++
++	platform_set_drvdata(pdev, sharpsl);
++
++	/*
++	 * PXA initialize
++	 */
++	writeb(readb(sharpsl->io + FLASHCTL) | FLWP, sharpsl->io + FLASHCTL);
++
++	/* Set address of NAND IO lines */
++	this->IO_ADDR_R = sharpsl->io + FLASHIO;
++	this->IO_ADDR_W = sharpsl->io + FLASHIO;
++	/* Set address of hardware control function */
++	this->cmd_ctrl = sharpsl_nand_hwcontrol;
++	this->dev_ready = sharpsl_nand_dev_ready;
++	/* 15 us command delay time */
++	this->chip_delay = 15;
++	/* set eccmode using hardware ECC */
++	this->ecc.mode = NAND_ECC_HW;
++	this->ecc.size = 256;
++	this->ecc.bytes = 3;
++	this->ecc.strength = 1;
++	this->badblock_pattern = data->badblock_pattern;
++	this->ecc.hwctl = sharpsl_nand_enable_hwecc;
++	this->ecc.calculate = sharpsl_nand_calculate_ecc;
++	this->ecc.correct = nand_correct_data;
++
++	/* Scan to find existence of the device */
++	err = nand_scan(mtd, 1);
++	if (err)
++		goto err_scan;
++
++	/* Register the partitions */
++	mtd->name = "sharpsl-nand";
++
++	err = mtd_device_parse_register(mtd, data->part_parsers, NULL,
++					data->partitions, data->nr_partitions);
++	if (err)
++		goto err_add;
++
++	/* Return happy */
++	return 0;
++
++err_add:
++	nand_release(mtd);
++
++err_scan:
++	iounmap(sharpsl->io);
++err_ioremap:
++err_get_res:
++	kfree(sharpsl);
++	return err;
++}
++
++/*
++ * Clean up routine
++ */
++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));
++
++	iounmap(sharpsl->io);
++
++	/* Free the MTD device structure */
++	kfree(sharpsl);
++
++	return 0;
++}
++
++static struct platform_driver sharpsl_nand_driver = {
++	.driver = {
++		.name	= "sharpsl-nand",
++	},
++	.probe		= sharpsl_nand_probe,
++	.remove		= sharpsl_nand_remove,
++};
++
++module_platform_driver(sharpsl_nand_driver);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Richard Purdie <rpurdie@rpsys.net>");
++MODULE_DESCRIPTION("Device specific logic for NAND flash on Sharp SL-C7xx Series");
+diff --git a/drivers/mtd/nand/raw/sm_common.c b/drivers/mtd/nand/raw/sm_common.c
+new file mode 100644
+index 0000000..c378705
+--- /dev/null
++++ b/drivers/mtd/nand/raw/sm_common.c
+@@ -0,0 +1,202 @@
++/*
++ * Copyright © 2009 - Maxim Levitsky
++ * Common routines & support for xD format
++ *
++ * 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/kernel.h>
++#include <linux/mtd/rawnand.h>
++#include <linux/module.h>
++#include <linux/sizes.h>
++#include "sm_common.h"
++
++static int oob_sm_ooblayout_ecc(struct mtd_info *mtd, int section,
++				struct mtd_oob_region *oobregion)
++{
++	if (section > 1)
++		return -ERANGE;
++
++	oobregion->length = 3;
++	oobregion->offset = ((section + 1) * 8) - 3;
++
++	return 0;
++}
++
++static int oob_sm_ooblayout_free(struct mtd_info *mtd, int section,
++				 struct mtd_oob_region *oobregion)
++{
++	switch (section) {
++	case 0:
++		/* reserved */
++		oobregion->offset = 0;
++		oobregion->length = 4;
++		break;
++	case 1:
++		/* LBA1 */
++		oobregion->offset = 6;
++		oobregion->length = 2;
++		break;
++	case 2:
++		/* LBA2 */
++		oobregion->offset = 11;
++		oobregion->length = 2;
++		break;
++	default:
++		return -ERANGE;
++	}
++
++	return 0;
++}
++
++static const struct mtd_ooblayout_ops oob_sm_ops = {
++	.ecc = oob_sm_ooblayout_ecc,
++	.free = oob_sm_ooblayout_free,
++};
++
++/* NOTE: This layout is is not compatabable with SmartMedia, */
++/* because the 256 byte devices have page depenent oob layout */
++/* However it does preserve the bad block markers */
++/* If you use smftl, it will bypass this and work correctly */
++/* If you not, then you break SmartMedia compliance anyway */
++
++static int oob_sm_small_ooblayout_ecc(struct mtd_info *mtd, int section,
++				      struct mtd_oob_region *oobregion)
++{
++	if (section)
++		return -ERANGE;
++
++	oobregion->length = 3;
++	oobregion->offset = 0;
++
++	return 0;
++}
++
++static int oob_sm_small_ooblayout_free(struct mtd_info *mtd, int section,
++				       struct mtd_oob_region *oobregion)
++{
++	switch (section) {
++	case 0:
++		/* reserved */
++		oobregion->offset = 3;
++		oobregion->length = 2;
++		break;
++	case 1:
++		/* LBA1 */
++		oobregion->offset = 6;
++		oobregion->length = 2;
++		break;
++	default:
++		return -ERANGE;
++	}
++
++	return 0;
++}
++
++static const struct mtd_ooblayout_ops oob_sm_small_ops = {
++	.ecc = oob_sm_small_ooblayout_ecc,
++	.free = oob_sm_small_ooblayout_free,
++};
++
++static int sm_block_markbad(struct mtd_info *mtd, loff_t ofs)
++{
++	struct mtd_oob_ops ops;
++	struct sm_oob oob;
++	int ret;
++
++	memset(&oob, -1, SM_OOB_SIZE);
++	oob.block_status = 0x0F;
++
++	/* As long as this function is called on erase block boundaries
++		it will work correctly for 256 byte nand */
++	ops.mode = MTD_OPS_PLACE_OOB;
++	ops.ooboffs = 0;
++	ops.ooblen = mtd->oobsize;
++	ops.oobbuf = (void *)&oob;
++	ops.datbuf = NULL;
++
++
++	ret = mtd_write_oob(mtd, ofs, &ops);
++	if (ret < 0 || ops.oobretlen != SM_OOB_SIZE) {
++		printk(KERN_NOTICE
++			"sm_common: can't mark sector at %i as bad\n",
++								(int)ofs);
++		return -EIO;
++	}
++
++	return 0;
++}
++
++static struct nand_flash_dev nand_smartmedia_flash_ids[] = {
++	LEGACY_ID_NAND("SmartMedia 2MiB 3,3V ROM",   0x5d, 2,   SZ_8K, NAND_ROM),
++	LEGACY_ID_NAND("SmartMedia 4MiB 3,3V",       0xe3, 4,   SZ_8K, 0),
++	LEGACY_ID_NAND("SmartMedia 4MiB 3,3/5V",     0xe5, 4,   SZ_8K, 0),
++	LEGACY_ID_NAND("SmartMedia 4MiB 5V",         0x6b, 4,   SZ_8K, 0),
++	LEGACY_ID_NAND("SmartMedia 4MiB 3,3V ROM",   0xd5, 4,   SZ_8K, NAND_ROM),
++	LEGACY_ID_NAND("SmartMedia 8MiB 3,3V",       0xe6, 8,   SZ_8K, 0),
++	LEGACY_ID_NAND("SmartMedia 8MiB 3,3V ROM",   0xd6, 8,   SZ_8K, NAND_ROM),
++	LEGACY_ID_NAND("SmartMedia 16MiB 3,3V",      0x73, 16,  SZ_16K, 0),
++	LEGACY_ID_NAND("SmartMedia 16MiB 3,3V ROM",  0x57, 16,  SZ_16K, NAND_ROM),
++	LEGACY_ID_NAND("SmartMedia 32MiB 3,3V",      0x75, 32,  SZ_16K, 0),
++	LEGACY_ID_NAND("SmartMedia 32MiB 3,3V ROM",  0x58, 32,  SZ_16K, NAND_ROM),
++	LEGACY_ID_NAND("SmartMedia 64MiB 3,3V",      0x76, 64,  SZ_16K, 0),
++	LEGACY_ID_NAND("SmartMedia 64MiB 3,3V ROM",  0xd9, 64,  SZ_16K, NAND_ROM),
++	LEGACY_ID_NAND("SmartMedia 128MiB 3,3V",     0x79, 128, SZ_16K, 0),
++	LEGACY_ID_NAND("SmartMedia 128MiB 3,3V ROM", 0xda, 128, SZ_16K, NAND_ROM),
++	LEGACY_ID_NAND("SmartMedia 256MiB 3, 3V",    0x71, 256, SZ_16K, 0),
++	LEGACY_ID_NAND("SmartMedia 256MiB 3,3V ROM", 0x5b, 256, SZ_16K, NAND_ROM),
++	{NULL}
++};
++
++static struct nand_flash_dev nand_xd_flash_ids[] = {
++	LEGACY_ID_NAND("xD 16MiB 3,3V",  0x73, 16,   SZ_16K, 0),
++	LEGACY_ID_NAND("xD 32MiB 3,3V",  0x75, 32,   SZ_16K, 0),
++	LEGACY_ID_NAND("xD 64MiB 3,3V",  0x76, 64,   SZ_16K, 0),
++	LEGACY_ID_NAND("xD 128MiB 3,3V", 0x79, 128,  SZ_16K, 0),
++	LEGACY_ID_NAND("xD 256MiB 3,3V", 0x71, 256,  SZ_16K, NAND_BROKEN_XD),
++	LEGACY_ID_NAND("xD 512MiB 3,3V", 0xdc, 512,  SZ_16K, NAND_BROKEN_XD),
++	LEGACY_ID_NAND("xD 1GiB 3,3V",   0xd3, 1024, SZ_16K, NAND_BROKEN_XD),
++	LEGACY_ID_NAND("xD 2GiB 3,3V",   0xd5, 2048, SZ_16K, NAND_BROKEN_XD),
++	{NULL}
++};
++
++int sm_register_device(struct mtd_info *mtd, int smartmedia)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	int ret;
++
++	chip->options |= NAND_SKIP_BBTSCAN;
++
++	/* Scan for card properties */
++	ret = nand_scan_ident(mtd, 1, smartmedia ?
++		nand_smartmedia_flash_ids : nand_xd_flash_ids);
++
++	if (ret)
++		return ret;
++
++	/* Bad block marker position */
++	chip->badblockpos = 0x05;
++	chip->badblockbits = 7;
++	chip->block_markbad = sm_block_markbad;
++
++	/* ECC layout */
++	if (mtd->writesize == SM_SECTOR_SIZE)
++		mtd_set_ooblayout(mtd, &oob_sm_ops);
++	else if (mtd->writesize == SM_SMALL_PAGE)
++		mtd_set_ooblayout(mtd, &oob_sm_small_ops);
++	else
++		return -ENODEV;
++
++	ret = nand_scan_tail(mtd);
++
++	if (ret)
++		return ret;
++
++	return mtd_device_register(mtd, NULL, 0);
++}
++EXPORT_SYMBOL_GPL(sm_register_device);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Maxim Levitsky <maximlevitsky@gmail.com>");
++MODULE_DESCRIPTION("Common SmartMedia/xD functions");
+diff --git a/drivers/mtd/nand/raw/sm_common.h b/drivers/mtd/nand/raw/sm_common.h
+new file mode 100644
+index 0000000..d3e028e
+--- /dev/null
++++ b/drivers/mtd/nand/raw/sm_common.h
+@@ -0,0 +1,61 @@
++/*
++ * Copyright © 2009 - Maxim Levitsky
++ * Common routines & support for SmartMedia/xD format
++ *
++ * 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/bitops.h>
++#include <linux/mtd/mtd.h>
++
++/* Full oob structure as written on the flash */
++struct sm_oob {
++	uint32_t reserved;
++	uint8_t data_status;
++	uint8_t block_status;
++	uint8_t lba_copy1[2];
++	uint8_t ecc2[3];
++	uint8_t lba_copy2[2];
++	uint8_t ecc1[3];
++} __packed;
++
++
++/* one sector is always 512 bytes, but it can consist of two nand pages */
++#define SM_SECTOR_SIZE		512
++
++/* oob area is also 16 bytes, but might be from two pages */
++#define SM_OOB_SIZE		16
++
++/* This is maximum zone size, and all devices that have more that one zone
++   have this size */
++#define SM_MAX_ZONE_SIZE 	1024
++
++/* support for small page nand */
++#define SM_SMALL_PAGE 		256
++#define SM_SMALL_OOB_SIZE	8
++
++
++extern int sm_register_device(struct mtd_info *mtd, int smartmedia);
++
++
++static inline int sm_sector_valid(struct sm_oob *oob)
++{
++	return hweight16(oob->data_status) >= 5;
++}
++
++static inline int sm_block_valid(struct sm_oob *oob)
++{
++	return hweight16(oob->block_status) >= 7;
++}
++
++static inline int sm_block_erased(struct sm_oob *oob)
++{
++	static const uint32_t erased_pattern[4] = {
++		0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
++
++	/* First test for erased block */
++	if (!memcmp(oob, erased_pattern, sizeof(*oob)))
++		return 1;
++	return 0;
++}
+diff --git a/drivers/mtd/nand/raw/socrates_nand.c b/drivers/mtd/nand/raw/socrates_nand.c
+new file mode 100644
+index 0000000..575997d
+--- /dev/null
++++ b/drivers/mtd/nand/raw/socrates_nand.c
+@@ -0,0 +1,243 @@
++/*
++ * drivers/mtd/nand/socrates_nand.c
++ *
++ *  Copyright © 2008 Ilya Yanok, Emcraft Systems
++ *
++ *
++ * 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/slab.h>
++#include <linux/module.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/rawnand.h>
++#include <linux/mtd/partitions.h>
++#include <linux/of_address.h>
++#include <linux/of_platform.h>
++#include <linux/io.h>
++
++#define FPGA_NAND_CMD_MASK		(0x7 << 28)
++#define FPGA_NAND_CMD_COMMAND		(0x0 << 28)
++#define FPGA_NAND_CMD_ADDR		(0x1 << 28)
++#define FPGA_NAND_CMD_READ		(0x2 << 28)
++#define FPGA_NAND_CMD_WRITE		(0x3 << 28)
++#define FPGA_NAND_BUSY			(0x1 << 15)
++#define FPGA_NAND_ENABLE		(0x1 << 31)
++#define FPGA_NAND_DATA_SHIFT		16
++
++struct socrates_nand_host {
++	struct nand_chip	nand_chip;
++	void __iomem		*io_base;
++	struct device		*dev;
++};
++
++/**
++ * socrates_nand_write_buf -  write buffer to chip
++ * @mtd:	MTD device structure
++ * @buf:	data buffer
++ * @len:	number of bytes to write
++ */
++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 socrates_nand_host *host = nand_get_controller_data(this);
++
++	for (i = 0; i < len; i++) {
++		out_be32(host->io_base, FPGA_NAND_ENABLE |
++				FPGA_NAND_CMD_WRITE |
++				(buf[i] << FPGA_NAND_DATA_SHIFT));
++	}
++}
++
++/**
++ * socrates_nand_read_buf -  read chip data into buffer
++ * @mtd:	MTD device structure
++ * @buf:	buffer to store date
++ * @len:	number of bytes to read
++ */
++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 socrates_nand_host *host = nand_get_controller_data(this);
++	uint32_t val;
++
++	val = FPGA_NAND_ENABLE | FPGA_NAND_CMD_READ;
++
++	out_be32(host->io_base, val);
++	for (i = 0; i < len; i++) {
++		buf[i] = (in_be32(host->io_base) >>
++				FPGA_NAND_DATA_SHIFT) & 0xff;
++	}
++}
++
++/**
++ * socrates_nand_read_byte -  read one byte from the chip
++ * @mtd:	MTD device structure
++ */
++static uint8_t socrates_nand_read_byte(struct mtd_info *mtd)
++{
++	uint8_t byte;
++	socrates_nand_read_buf(mtd, &byte, sizeof(byte));
++	return byte;
++}
++
++/**
++ * socrates_nand_read_word -  read one word from the chip
++ * @mtd:	MTD device structure
++ */
++static uint16_t socrates_nand_read_word(struct mtd_info *mtd)
++{
++	uint16_t word;
++	socrates_nand_read_buf(mtd, (uint8_t *)&word, sizeof(word));
++	return word;
++}
++
++/*
++ * Hardware specific access to control-lines
++ */
++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 socrates_nand_host *host = nand_get_controller_data(nand_chip);
++	uint32_t val;
++
++	if (cmd == NAND_CMD_NONE)
++		return;
++
++	if (ctrl & NAND_CLE)
++		val = FPGA_NAND_CMD_COMMAND;
++	else
++		val = FPGA_NAND_CMD_ADDR;
++
++	if (ctrl & NAND_NCE)
++		val |= FPGA_NAND_ENABLE;
++
++	val |= (cmd & 0xff) << FPGA_NAND_DATA_SHIFT;
++
++	out_be32(host->io_base, val);
++}
++
++/*
++ * Read the Device Ready pin.
++ */
++static int socrates_nand_device_ready(struct mtd_info *mtd)
++{
++	struct nand_chip *nand_chip = mtd_to_nand(mtd);
++	struct socrates_nand_host *host = nand_get_controller_data(nand_chip);
++
++	if (in_be32(host->io_base) & FPGA_NAND_BUSY)
++		return 0; /* busy */
++	return 1;
++}
++
++/*
++ * Probe for the NAND device.
++ */
++static int socrates_nand_probe(struct platform_device *ofdev)
++{
++	struct socrates_nand_host *host;
++	struct mtd_info *mtd;
++	struct nand_chip *nand_chip;
++	int res;
++
++	/* Allocate memory for the device structure (and zero it) */
++	host = devm_kzalloc(&ofdev->dev, sizeof(*host), GFP_KERNEL);
++	if (!host)
++		return -ENOMEM;
++
++	host->io_base = of_iomap(ofdev->dev.of_node, 0);
++	if (host->io_base == NULL) {
++		dev_err(&ofdev->dev, "ioremap failed\n");
++		return -EIO;
++	}
++
++	nand_chip = &host->nand_chip;
++	mtd = nand_to_mtd(nand_chip);
++	host->dev = &ofdev->dev;
++
++	/* link the private data structures */
++	nand_set_controller_data(nand_chip, host);
++	nand_set_flash_node(nand_chip, ofdev->dev.of_node);
++	mtd->name = "socrates_nand";
++	mtd->dev.parent = &ofdev->dev;
++
++	/*should never be accessed directly */
++	nand_chip->IO_ADDR_R = (void *)0xdeadbeef;
++	nand_chip->IO_ADDR_W = (void *)0xdeadbeef;
++
++	nand_chip->cmd_ctrl = socrates_nand_cmd_ctrl;
++	nand_chip->read_byte = socrates_nand_read_byte;
++	nand_chip->read_word = socrates_nand_read_word;
++	nand_chip->write_buf = socrates_nand_write_buf;
++	nand_chip->read_buf = socrates_nand_read_buf;
++	nand_chip->dev_ready = socrates_nand_device_ready;
++
++	nand_chip->ecc.mode = NAND_ECC_SOFT;	/* enable ECC */
++	nand_chip->ecc.algo = NAND_ECC_HAMMING;
++
++	/* TODO: I have no idea what real delay is. */
++	nand_chip->chip_delay = 20;		/* 20us command delay time */
++
++	dev_set_drvdata(&ofdev->dev, host);
++
++	res = nand_scan(mtd, 1);
++	if (res)
++		goto out;
++
++	res = mtd_device_register(mtd, NULL, 0);
++	if (!res)
++		return res;
++
++	nand_release(mtd);
++
++out:
++	iounmap(host->io_base);
++	return res;
++}
++
++/*
++ * Remove a NAND device.
++ */
++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);
++
++	nand_release(mtd);
++
++	iounmap(host->io_base);
++
++	return 0;
++}
++
++static const struct of_device_id socrates_nand_match[] =
++{
++	{
++		.compatible   = "abb,socrates-nand",
++	},
++	{},
++};
++
++MODULE_DEVICE_TABLE(of, socrates_nand_match);
++
++static struct platform_driver socrates_nand_driver = {
++	.driver = {
++		.name = "socrates_nand",
++		.of_match_table = socrates_nand_match,
++	},
++	.probe		= socrates_nand_probe,
++	.remove		= socrates_nand_remove,
++};
++
++module_platform_driver(socrates_nand_driver);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Ilya Yanok");
++MODULE_DESCRIPTION("NAND driver for Socrates board");
+diff --git a/drivers/mtd/nand/raw/stm32_fmc.c b/drivers/mtd/nand/raw/stm32_fmc.c
+new file mode 100644
+index 0000000..e3f5be7
+--- /dev/null
++++ b/drivers/mtd/nand/raw/stm32_fmc.c
+@@ -0,0 +1,1743 @@
++/*
++ * stm32_fmc.c
++ *
++ * Copyright (C) 2017, STMicroelectronics - All Rights Reserved
++ * Christophe Kerello <christophe.kerello@st.com>
++ *
++ * License terms: GPL V2.0.
++ */
++
++#include <linux/clk.h>
++#include <linux/dmaengine.h>
++#include <linux/dma-mapping.h>
++#include <linux/errno.h>
++#include <linux/io.h>
++#include <linux/iopoll.h>
++#include <linux/interrupt.h>
++#include <linux/module.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/rawnand.h>
++#include <linux/mtd/nand_ecc.h>
++#include <linux/mtd/partitions.h>
++#include <linux/of.h>
++#include <linux/of_device.h>
++#include <linux/platform_device.h>
++#include <linux/reset.h>
++
++/* Bad block marker length */
++#define FMC_BBM_LEN			2
++
++/* BCHDSRx registers length */
++#define FMC_BCHDSRS_LEN			20
++
++/* HECCR length */
++#define FMC_HECCR_LEN			4
++
++/* Max requests done for a 8k nand page size */
++#define FMC_MAX_SG_COUNT		16
++
++/* Command delay */
++#define FMC_RB_DELAY_US			30
++
++/* Bank offsets */
++#define FMC_DATA_SECTION		0x00000
++#define FMC_COMMAND_SECTION		0x10000
++#define FMC_ADDRESS_SECTION		0x20000
++
++/* Timings */
++#define FMC_THIZ			1
++#define FMC_TIO				8000
++#define FMC_TSYNC			3000
++#define FMC_PCR_TIMING_MASK		0xf
++#define FMC_PMEM_PATT_TIMING_MASK	0xff
++
++/* FMC Controller Registers */
++#define FMC_BCR1			0x0
++#define FMC_PCR(bank)			(0x0020 * ((bank) + 1))
++#define FMC_SR(bank)			((0x0020 * ((bank) + 1)) + 0x04)
++#define FMC_PMEM(bank)			((0x0020 * ((bank) + 1)) + 0x08)
++#define FMC_PATT(bank)			((0x0020 * ((bank) + 1)) + 0x0c)
++#define FMC_HECCR(bank)			((0x0020 * ((bank) + 1)) + 0x14)
++#define FMC_CSQCR			0x0200
++#define FMC_CSQCFGR1			0x0204
++#define FMC_CSQCFGR2			0x0208
++#define FMC_CSQCFGR3			0x020c
++#define FMC_CSQAR1			0x0210
++#define FMC_CSQAR2			0x0214
++#define FMC_CSQIER			0x0220
++#define FMC_CSQISR			0x0224
++#define FMC_CSQICR			0x0228
++#define FMC_CSQEMSR			0x0230
++#define FMC_BCHIER			0x0250
++#define FMC_BCHISR			0x0254
++#define FMC_BCHICR			0x0258
++#define FMC_BCHPBR1			0x0260
++#define FMC_BCHPBR2			0x0264
++#define FMC_BCHPBR3			0x0268
++#define FMC_BCHPBR4			0x026c
++#define FMC_BCHDSR0			0x027c
++#define FMC_BCHDSR1			0x0280
++#define FMC_BCHDSR2			0x0284
++#define FMC_BCHDSR3			0x0288
++#define FMC_BCHDSR4			0x028c
++
++/* Register: FMC_BCR1 */
++#define FMC_BCR1_FMCEN			BIT(31)
++
++/* Register: FMC_PCR */
++#define FMC_PCR_PWAITEN			BIT(1)
++#define FMC_PCR_PBKEN			BIT(2)
++#define FMC_PCR_PWID_MASK		GENMASK(5, 4)
++#define FMC_PCR_PWID(x)			(((x) & 0x3) << 4)
++#define FMC_PCR_PWID_BUSWIDTH_8		0
++#define FMC_PCR_PWID_BUSWIDTH_16	1
++#define FMC_PCR_ECCEN			BIT(6)
++#define FMC_PCR_ECCALG			BIT(8)
++#define FMC_PCR_TCLR_MASK		GENMASK(12, 9)
++#define FMC_PCR_TCLR(x)			(((x) & 0xf) << 9)
++#define FMC_PCR_TAR_MASK		GENMASK(16, 13)
++#define FMC_PCR_TAR(x)			(((x) & 0xf) << 13)
++#define FMC_PCR_ECCSS_MASK		GENMASK(19, 17)
++#define FMC_PCR_ECCSS(x)		(((x) & 0x7) << 17)
++#define FMC_PCR_ECCSS_512		1
++#define FMC_PCR_BCHECC			BIT(24)
++#define FMC_PCR_WEN			BIT(25)
++
++/* Register: FMC_SR */
++#define FMC_SR_NWRF			BIT(6)
++
++/* Register: FMC_PMEM */
++#define FMC_PMEM_MEMSET(x)		(((x) & 0xff) << 0)
++#define FMC_PMEM_MEMWAIT(x)		(((x) & 0xff) << 8)
++#define FMC_PMEM_MEMHOLD(x)		(((x) & 0xff) << 16)
++#define FMC_PMEM_MEMHIZ(x)		(((x) & 0xff) << 24)
++
++/* Register: FMC_PATT */
++#define FMC_PATT_ATTSET(x)		(((x) & 0xff) << 0)
++#define FMC_PATT_ATTWAIT(x)		(((x) & 0xff) << 8)
++#define FMC_PATT_ATTHOLD(x)		(((x) & 0xff) << 16)
++#define FMC_PATT_ATTHIZ(x)		(((x) & 0xff) << 24)
++
++/* Register: FMC_CSQCR */
++#define FMC_CSQCR_CSQSTART		BIT(0)
++
++/* Register: FMC_CSQCFGR1 */
++#define FMC_CSQCFGR1_CMD2EN		BIT(1)
++#define FMC_CSQCFGR1_DMADEN		BIT(2)
++#define FMC_CSQCFGR1_ACYNBR(x)		(((x) & 0x7) << 4)
++#define FMC_CSQCFGR1_CMD1(x)		(((x) & 0xff) << 8)
++#define FMC_CSQCFGR1_CMD2(x)		(((x) & 0xff) << 16)
++#define FMC_CSQCFGR1_CMD1T		BIT(24)
++#define FMC_CSQCFGR1_CMD2T		BIT(25)
++
++/* Register: FMC_CSQCFGR2 */
++#define FMC_CSQCFGR2_SQSDTEN		BIT(0)
++#define FMC_CSQCFGR2_RCMD2EN		BIT(1)
++#define FMC_CSQCFGR2_DMASEN		BIT(2)
++#define FMC_CSQCFGR2_RCMD1(x)		(((x) & 0xff) << 8)
++#define FMC_CSQCFGR2_RCMD2(x)		(((x) & 0xff) << 16)
++#define FMC_CSQCFGR2_RCMD1T		BIT(24)
++#define FMC_CSQCFGR2_RCMD2T		BIT(25)
++
++/* Register: FMC_CSQCFGR3 */
++#define FMC_CSQCFGR3_SNBR(x)		(((x) & 0x1f) << 8)
++#define FMC_CSQCFGR3_AC1T		BIT(16)
++#define FMC_CSQCFGR3_AC2T		BIT(17)
++#define FMC_CSQCFGR3_AC3T		BIT(18)
++#define FMC_CSQCFGR3_AC4T		BIT(19)
++#define FMC_CSQCFGR3_AC5T		BIT(20)
++#define FMC_CSQCFGR3_SDT		BIT(21)
++#define FMC_CSQCFGR3_RAC1T		BIT(22)
++#define FMC_CSQCFGR3_RAC2T		BIT(23)
++
++/* Register: FMC_CSQCAR1 */
++#define FMC_CSQCAR1_ADDC1(x)		(((x) & 0xff) << 0)
++#define FMC_CSQCAR1_ADDC2(x)		(((x) & 0xff) << 8)
++#define FMC_CSQCAR1_ADDC3(x)		(((x) & 0xff) << 16)
++#define FMC_CSQCAR1_ADDC4(x)		(((x) & 0xff) << 24)
++
++/* Register: FMC_CSQCAR2 */
++#define FMC_CSQCAR2_ADDC5(x)		(((x) & 0xff) << 0)
++#define FMC_CSQCAR2_SAO(x)		(((x) & 0xffff) << 16)
++
++/* Register: FMC_CSQIER */
++#define FMC_CSQIER_TCIE			BIT(0)
++
++/* Register: FMC_CSQICR */
++#define FMC_CSQICR_CTCF			BIT(0)
++#define FMC_CSQICR_CSCF			BIT(1)
++#define FMC_CSQICR_CSEF			BIT(2)
++#define FMC_CSQICR_CSUEF		BIT(3)
++#define FMC_CSQICR_CCMDTCF		BIT(4)
++
++/* Register: FMC_CSQEMSR */
++#define FMC_CSQEMSR_SEM			GENMASK(15, 0)
++
++/* Register: FMC_BCHIER */
++#define FMC_BCHIER_DERIE		BIT(1)
++#define FMC_BCHIER_EPBRIE		BIT(4)
++
++/* Register: FMC_BCHICR */
++#define FMC_BCHICR_CDUEF		BIT(0)
++#define FMC_BCHICR_CDERF		BIT(1)
++#define FMC_BCHICR_CDEFF		BIT(2)
++#define FMC_BCHICR_CDSRF		BIT(3)
++#define FMC_BCHICR_CEPBRF		BIT(4)
++
++/* Register: FMC_BCHDSR0 */
++#define FMC_BCHDSR0_DUE			BIT(0)
++#define FMC_BCHDSR0_DEF			BIT(1)
++#define FMC_BCHDSR0_DEN_MASK		GENMASK(7, 4)
++#define FMC_BCHDSR0_DEN_SHIFT		4
++
++/* Register: FMC_BCHDSR1 */
++#define FMC_BCHDSR1_EBP1_MASK		GENMASK(12, 0)
++#define FMC_BCHDSR1_EBP2_MASK		GENMASK(28, 16)
++#define FMC_BCHDSR1_EBP2_SHIFT		16
++
++/* Register: FMC_BCHDSR2 */
++#define FMC_BCHDSR2_EBP3_MASK		GENMASK(12, 0)
++#define FMC_BCHDSR2_EBP4_MASK		GENMASK(28, 16)
++#define FMC_BCHDSR2_EBP4_SHIFT		16
++
++/* Register: FMC_BCHDSR3 */
++#define FMC_BCHDSR3_EBP5_MASK		GENMASK(12, 0)
++#define FMC_BCHDSR3_EBP6_MASK		GENMASK(28, 16)
++#define FMC_BCHDSR3_EBP6_SHIFT		16
++
++/* Register: FMC_BCHDSR4 */
++#define FMC_BCHDSR4_EBP7_MASK		GENMASK(12, 0)
++#define FMC_BCHDSR4_EBP8_MASK		GENMASK(28, 16)
++#define FMC_BCHDSR4_EBP8_SHIFT		16
++
++enum stm32_ecc {
++	FMC_ECC_HAM = 1,
++	FMC_ECC_BCH4 = 4,
++	FMC_ECC_BCH8 = 8
++};
++
++enum stm32_irq_state {
++	FMC_IRQ_UNKNOWN = 0,
++	FMC_IRQ_BCH,
++	FMC_IRQ_SEQ
++};
++
++struct stm32_fmc_timings {
++	u8 tclr;
++	u8 tar;
++	u8 thiz;
++	u8 twait;
++	u8 thold_mem;
++	u8 tset_mem;
++	u8 thold_att;
++	u8 tset_att;
++};
++
++struct stm32_fmc {
++	struct nand_chip chip;
++	struct device *dev;
++	void __iomem *io_base;
++	void __iomem *common_base;
++	void __iomem *attrib_base;
++	struct clk *clk;
++
++	struct dma_chan *dma_data_ch;
++	struct dma_chan *dma_ecc_ch;
++	struct sg_table dma_data_sg;
++	struct sg_table dma_ecc_sg;
++	u8 *ecc_buf;
++	int dma_ecc_len;
++
++	struct completion complete;
++	struct completion dma_data_complete;
++	struct completion dma_ecc_complete;
++
++	struct stm32_fmc_timings timings;
++	u8 irq_state;
++	unsigned int bank;
++};
++
++/* Enable irq sources in case of the sequencer is used */
++static inline void stm32_fmc_enable_seq_irq(struct stm32_fmc *fmc)
++{
++	u32 csqier = readl_relaxed(fmc->io_base + FMC_CSQIER);
++
++	csqier |= FMC_CSQIER_TCIE;
++
++	fmc->irq_state = FMC_IRQ_SEQ;
++
++	writel_relaxed(csqier, fmc->io_base + FMC_CSQIER);
++}
++
++/* Disable irq sources in case of the sequencer is used */
++static inline void stm32_fmc_disable_seq_irq(struct stm32_fmc *fmc)
++{
++	u32 csqier = readl_relaxed(fmc->io_base + FMC_CSQIER);
++
++	csqier &= ~FMC_CSQIER_TCIE;
++
++	writel_relaxed(csqier, fmc->io_base + FMC_CSQIER);
++
++	fmc->irq_state = FMC_IRQ_UNKNOWN;
++}
++
++/* Clear irq sources in case of the sequencer is used */
++static inline void stm32_fmc_clear_seq_irq(struct stm32_fmc *fmc)
++{
++	u32 csqicr = FMC_CSQICR_CTCF;
++
++	csqicr |= FMC_CSQICR_CSCF;
++	csqicr |= FMC_CSQICR_CSEF;
++	csqicr |= FMC_CSQICR_CSUEF;
++	csqicr |= FMC_CSQICR_CCMDTCF;
++
++	writel_relaxed(csqicr, fmc->io_base + FMC_CSQICR);
++}
++
++/* Enable irq sources in case of bch is used */
++static inline void stm32_fmc_enable_bch_irq(struct stm32_fmc *fmc, int mode)
++{
++	u32 bchier = readl_relaxed(fmc->io_base + FMC_BCHIER);
++
++	if (mode == NAND_ECC_WRITE)
++		bchier |= FMC_BCHIER_EPBRIE;
++	else
++		bchier |= FMC_BCHIER_DERIE;
++
++	fmc->irq_state = FMC_IRQ_BCH;
++
++	writel_relaxed(bchier, fmc->io_base + FMC_BCHIER);
++}
++
++/* Disable irq sources in case of bch is used */
++static inline void stm32_fmc_disable_bch_irq(struct stm32_fmc *fmc)
++{
++	u32 bchier = readl_relaxed(fmc->io_base + FMC_BCHIER);
++
++	bchier &= ~FMC_BCHIER_DERIE;
++	bchier &= ~FMC_BCHIER_EPBRIE;
++
++	writel_relaxed(bchier, fmc->io_base + FMC_BCHIER);
++
++	fmc->irq_state = FMC_IRQ_UNKNOWN;
++}
++
++/* Clear irq sources in case of bch is used */
++static inline void stm32_fmc_clear_bch_irq(struct stm32_fmc *fmc)
++{
++	u32 bchicr = FMC_BCHICR_CDUEF;
++
++	bchicr |= FMC_BCHICR_CDERF;
++	bchicr |= FMC_BCHICR_CDEFF;
++	bchicr |= FMC_BCHICR_CDSRF;
++	bchicr |= FMC_BCHICR_CEPBRF;
++
++	writel_relaxed(bchicr, fmc->io_base + FMC_BCHICR);
++}
++
++/* Send command and address cycles */
++static void stm32_fmc_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct stm32_fmc *fmc = nand_get_controller_data(chip);
++	void __iomem *base = fmc->attrib_base;
++
++	if (cmd == NAND_CMD_NONE)
++		return;
++
++	if (ctrl & NAND_CLE) {
++		writeb_relaxed(cmd, base + FMC_COMMAND_SECTION);
++		return;
++	}
++
++	writeb_relaxed(cmd, base + FMC_ADDRESS_SECTION);
++}
++
++/*
++ * Enable ecc logic and reset syndrome/parity bits previously calculated
++ * Syndrome/parity bits is cleared by setting the ECCEN bit to 0
++ */
++static void stm32_fmc_hwctl(struct mtd_info *mtd, int mode)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct stm32_fmc *fmc = nand_get_controller_data(chip);
++	u32 pcr = readl_relaxed(fmc->io_base + FMC_PCR(fmc->bank));
++
++	pcr &= ~FMC_PCR_ECCEN;
++	writel_relaxed(pcr, fmc->io_base + FMC_PCR(fmc->bank));
++
++	if (chip->ecc.strength != FMC_ECC_HAM) {
++		if (mode == NAND_ECC_WRITE)
++			pcr |= FMC_PCR_WEN;
++		else
++			pcr &= ~FMC_PCR_WEN;
++		writel_relaxed(pcr, fmc->io_base + FMC_PCR(fmc->bank));
++
++		reinit_completion(&fmc->complete);
++		stm32_fmc_clear_bch_irq(fmc);
++		stm32_fmc_enable_bch_irq(fmc, mode);
++	}
++
++	pcr |= FMC_PCR_ECCEN;
++	writel_relaxed(pcr, fmc->io_base + FMC_PCR(fmc->bank));
++}
++
++/*
++ * ECC HAMMING calculation
++ * ECC is 3 bytes for 512 bytes of data (supports error correction up to
++ * max of 1-bit)
++ */
++static inline void stm32_fmc_ham_decode(const u32 ecc_sta, u8 *ecc)
++{
++	ecc[0] = ecc_sta;
++	ecc[1] = ecc_sta >> 8;
++	ecc[2] = ecc_sta >> 16;
++	ecc[3] = 0x0;
++}
++
++static int stm32_fmc_ham_calculate(struct mtd_info *mtd, const uint8_t *data,
++				   uint8_t *ecc)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct stm32_fmc *fmc = nand_get_controller_data(chip);
++	u32 sr, heccr;
++	int ret;
++
++	ret = readl_relaxed_poll_timeout(fmc->io_base + FMC_SR(fmc->bank),
++					 sr, sr & FMC_SR_NWRF, 10, 1000);
++	if (ret) {
++		dev_err(fmc->dev, "ham timeout\n");
++		return ret;
++	}
++
++	heccr = readl_relaxed(fmc->io_base + FMC_HECCR(fmc->bank));
++
++	stm32_fmc_ham_decode(heccr, ecc);
++
++	return 0;
++}
++
++static int stm32_fmc_ham_correct(struct mtd_info *mtd, uint8_t *dat,
++				 uint8_t *read_ecc, uint8_t *calc_ecc)
++{
++	u8 bit_position = 0, b0, b1, b2;
++	u32 byte_addr = 0, b;
++	u32 i, shifting = 1;
++
++	/* Indicate which bit and byte is faulty (if any) */
++	b0 = read_ecc[0] ^ calc_ecc[0];
++	b1 = read_ecc[1] ^ calc_ecc[1];
++	b2 = read_ecc[2] ^ calc_ecc[2];
++	b = b0 | (b1 << 8) | (b2 << 16);
++
++	/* No errors */
++	if (likely(!b))
++		return 0;
++
++	/* Calculate bit position */
++	for (i = 0; i < 3; i++) {
++		switch (b % 4) {
++		case 2:
++			bit_position += shifting;
++		case 1:
++			break;
++		default:
++			return -EBADMSG;
++		}
++		shifting <<= 1;
++		b >>= 2;
++	}
++
++	/* Calculate byte position */
++	shifting = 1;
++	for (i = 0; i < 9; i++) {
++		switch (b % 4) {
++		case 2:
++			byte_addr += shifting;
++		case 1:
++			break;
++		default:
++			return -EBADMSG;
++		}
++		shifting <<= 1;
++		b >>= 2;
++	}
++
++	/* Flip the bit */
++	dat[byte_addr] ^= (1 << bit_position);
++
++	return 1;
++}
++
++/*
++ * ECC BCH calculation and correction
++ * ECC is 7/13 bytes for 512 bytes of data (supports error correction up to
++ * max of 4-bit/8-bit)
++ */
++static int stm32_fmc_bch_calculate(struct mtd_info *mtd, const uint8_t *data,
++				   uint8_t *ecc)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct stm32_fmc *fmc = nand_get_controller_data(chip);
++	u32 bchpbr;
++
++	/* Wait that the BCH encoder parity is available */
++	if (!wait_for_completion_timeout(&fmc->complete,
++					 msecs_to_jiffies(1000))) {
++		dev_err(fmc->dev, "bch timeout\n");
++		stm32_fmc_disable_bch_irq(fmc);
++		return -ETIMEDOUT;
++	}
++
++	/* Read parity bits (write) or syndrome (read) */
++	bchpbr = readl_relaxed(fmc->io_base + FMC_BCHPBR1);
++	ecc[0] = bchpbr;
++	ecc[1] = bchpbr >> 8;
++	ecc[2] = bchpbr >> 16;
++	ecc[3] = bchpbr >> 24;
++
++	bchpbr = readl_relaxed(fmc->io_base + FMC_BCHPBR2);
++	ecc[4] = bchpbr;
++	ecc[5] = bchpbr >> 8;
++	ecc[6] = bchpbr >> 16;
++	ecc[7] = 0x0;
++
++	if (chip->ecc.strength == FMC_ECC_BCH8) {
++		ecc[7] = bchpbr >> 24;
++
++		bchpbr = readl_relaxed(fmc->io_base + FMC_BCHPBR3);
++		ecc[8] = bchpbr;
++		ecc[9] = bchpbr >> 8;
++		ecc[10] = bchpbr >> 16;
++		ecc[11] = bchpbr >> 24;
++
++		bchpbr = readl_relaxed(fmc->io_base + FMC_BCHPBR4);
++		ecc[12] = bchpbr;
++		ecc[13] = 0x0;
++	}
++
++	return 0;
++}
++
++/* BCH algorithm correction */
++static int stm32_fmc_bch_correct_data(struct nand_chip *chip, u8 *dat,
++				      u8 *read_ecc, u32 *ecc_sta)
++{
++	u32 bchdsr0 = ecc_sta[0];
++	u32 bchdsr1 = ecc_sta[1];
++	u32 bchdsr2 = ecc_sta[2];
++	u32 bchdsr3 = ecc_sta[3];
++	u32 bchdsr4 = ecc_sta[4];
++	u16 pos[8];
++	int i, den, eccsize = chip->ecc.size;
++
++	/* No errors found */
++	if (likely(!(bchdsr0 & FMC_BCHDSR0_DEF)))
++		return 0;
++
++	/* Too many errors detected */
++	if (unlikely(bchdsr0 & FMC_BCHDSR0_DUE))
++		return -EBADMSG;
++
++	pos[0] = bchdsr1 & FMC_BCHDSR1_EBP1_MASK;
++	pos[1] = (bchdsr1 & FMC_BCHDSR1_EBP2_MASK) >> FMC_BCHDSR1_EBP2_SHIFT;
++	pos[2] = bchdsr2 & FMC_BCHDSR2_EBP3_MASK;
++	pos[3] = (bchdsr2 & FMC_BCHDSR2_EBP4_MASK) >> FMC_BCHDSR2_EBP4_SHIFT;
++	pos[4] = bchdsr3 & FMC_BCHDSR3_EBP5_MASK;
++	pos[5] = (bchdsr3 & FMC_BCHDSR3_EBP6_MASK) >> FMC_BCHDSR3_EBP6_SHIFT;
++	pos[6] = bchdsr4 & FMC_BCHDSR4_EBP7_MASK;
++	pos[7] = (bchdsr4 & FMC_BCHDSR4_EBP8_MASK) >> FMC_BCHDSR4_EBP8_SHIFT;
++
++	den = (bchdsr0 & FMC_BCHDSR0_DEN_MASK) >> FMC_BCHDSR0_DEN_SHIFT;
++	for (i = 0; i < den; i++) {
++		if (pos[i] < eccsize * 8)
++			change_bit(pos[i], (unsigned long *)dat);
++	}
++
++	return den;
++}
++
++static int stm32_fmc_bch_correct(struct mtd_info *mtd, uint8_t *dat,
++				 uint8_t *read_ecc, uint8_t *calc_ecc)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct stm32_fmc *fmc = nand_get_controller_data(chip);
++	u32 ecc_sta[5];
++
++	/* Wait that the BCH syndrome is available */
++	if (!wait_for_completion_timeout(&fmc->complete,
++					 msecs_to_jiffies(1000))) {
++		dev_err(fmc->dev, "bch timeout\n");
++		stm32_fmc_disable_bch_irq(fmc);
++		return -ETIMEDOUT;
++	}
++
++	ecc_sta[0] = readl_relaxed(fmc->io_base + FMC_BCHDSR0);
++	ecc_sta[1] = readl_relaxed(fmc->io_base + FMC_BCHDSR1);
++	ecc_sta[2] = readl_relaxed(fmc->io_base + FMC_BCHDSR2);
++	ecc_sta[3] = readl_relaxed(fmc->io_base + FMC_BCHDSR3);
++	ecc_sta[4] = readl_relaxed(fmc->io_base + FMC_BCHDSR4);
++
++	return stm32_fmc_bch_correct_data(chip, dat, read_ecc, &ecc_sta[0]);
++}
++
++static int stm32_fmc_read_page(struct mtd_info *mtd,
++			       struct nand_chip *chip, uint8_t *buf,
++			       int oob_required, int page)
++{
++	int i, s, stat, eccsize = chip->ecc.size;
++	int eccbytes = chip->ecc.bytes;
++	int eccsteps = chip->ecc.steps;
++	int eccstrength = chip->ecc.strength;
++	u8 *p = buf;
++	u8 *ecc_calc = chip->buffers->ecccalc;
++	u8 *ecc_code = chip->buffers->ecccode;
++	unsigned int max_bitflips = 0;
++
++	for (i = mtd->writesize + FMC_BBM_LEN, s = 0; s < eccsteps;
++	     s++, i += eccbytes, p += eccsize) {
++		chip->ecc.hwctl(mtd, NAND_ECC_READ);
++
++		/* Read the nand page sector (512 bytes) */
++		chip->cmdfunc(mtd, NAND_CMD_RNDOUT, s * eccsize, -1);
++		chip->read_buf(mtd, p, eccsize);
++
++		/* Read the corresponding ecc bytes */
++		chip->cmdfunc(mtd, NAND_CMD_RNDOUT, i, -1);
++		chip->read_buf(mtd, ecc_code, eccbytes);
++
++		/* Correct the data */
++		stat = chip->ecc.correct(mtd, p, ecc_code, ecc_calc);
++		if (stat == -EBADMSG)
++			/* Check for empty pages with bitflips */
++			stat = nand_check_erased_ecc_chunk(p, eccsize,
++							   ecc_code, eccbytes,
++							   NULL, 0,
++							   eccstrength);
++
++		if (stat < 0) {
++			mtd->ecc_stats.failed++;
++		} else {
++			mtd->ecc_stats.corrected += stat;
++			max_bitflips = max_t(unsigned int, max_bitflips, stat);
++		}
++	}
++
++	/* Read oob */
++	if (oob_required) {
++		chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize, -1);
++		chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
++	}
++
++	return max_bitflips;
++}
++
++/* Sequencer read/write configuration */
++static void stm32_fmc_rw_page_init(struct stm32_fmc *fmc, int page,
++				   int raw, bool write_data)
++{
++	struct nand_chip *chip = &fmc->chip;
++	struct mtd_info *mtd = nand_to_mtd(chip);
++	u32 csqcfgr1, csqcfgr2, csqcfgr3;
++	u32 csqar1, csqar2;
++	u32 ecc_offset = mtd->writesize + FMC_BBM_LEN;
++	u32 pcr = readl_relaxed(fmc->io_base + FMC_PCR(fmc->bank));
++
++	if (write_data)
++		pcr |= FMC_PCR_WEN;
++	else
++		pcr &= ~FMC_PCR_WEN;
++	writel_relaxed(pcr, fmc->io_base + FMC_PCR(fmc->bank));
++
++	if (chip->ecc.strength != FMC_ECC_HAM)
++		stm32_fmc_clear_bch_irq(fmc);
++
++	/*
++	 * - Set Program Page/Page Read command
++	 * - Enable DMA request data
++	 * - Set timings
++	 */
++	csqcfgr1 = FMC_CSQCFGR1_DMADEN | FMC_CSQCFGR1_CMD1T;
++	if (write_data)
++		csqcfgr1 |= FMC_CSQCFGR1_CMD1(NAND_CMD_SEQIN);
++	else
++		csqcfgr1 |= FMC_CSQCFGR1_CMD1(NAND_CMD_READ0) |
++			    FMC_CSQCFGR1_CMD2EN |
++			    FMC_CSQCFGR1_CMD2(NAND_CMD_READSTART) |
++			    FMC_CSQCFGR1_CMD2T;
++
++	/*
++	 * - Set Random Data Input/Random Data Read command
++	 * - Enable the sequencer to access the Spare data area
++	 * - Enable  DMA request status decoding for read
++	 * - Set timings
++	 */
++	csqcfgr2 = FMC_CSQCFGR2_RCMD1T;
++	if (write_data)
++		csqcfgr2 |= FMC_CSQCFGR2_RCMD1(NAND_CMD_RNDIN);
++	else
++		csqcfgr2 |= FMC_CSQCFGR2_RCMD1(NAND_CMD_RNDOUT) |
++			    FMC_CSQCFGR2_RCMD2EN |
++			    FMC_CSQCFGR2_RCMD2(NAND_CMD_RNDOUTSTART) |
++			    FMC_CSQCFGR2_RCMD2T;
++	if (!raw) {
++		csqcfgr2 |= write_data ? 0 : FMC_CSQCFGR2_DMASEN;
++		csqcfgr2 |= FMC_CSQCFGR2_SQSDTEN;
++	}
++
++	/*
++	 * - Set the number of sectors to be written
++	 * - Set timings
++	 */
++	csqcfgr3 = FMC_CSQCFGR3_SNBR(chip->ecc.steps - 1);
++	if (write_data) {
++		csqcfgr3 |= FMC_CSQCFGR3_RAC2T;
++		if (chip->chipsize > SZ_128M)
++			csqcfgr3 |= FMC_CSQCFGR3_AC5T;
++		else
++			csqcfgr3 |= FMC_CSQCFGR3_AC4T;
++	}
++
++	/*
++	 * Set the fourth first address cycles
++	 * Byte 1 and byte 2 => column, we start at 0x0
++	 * Byte 3 and byte 4 => page
++	 */
++	csqar1 = FMC_CSQCAR1_ADDC3(page);
++	csqar1 |= FMC_CSQCAR1_ADDC4(page >> 8);
++
++	/*
++	 * - Set ecc byte offset in the spare area
++	 * - Calculate the number of address cycles to be issued
++	 * - Set byte 5 of address cycle if needed
++	 */
++	if (chip->options & NAND_BUSWIDTH_16)
++		csqar2 = FMC_CSQCAR2_SAO(ecc_offset >> 1);
++	else
++		csqar2 = FMC_CSQCAR2_SAO(ecc_offset);
++	if (chip->chipsize > SZ_128M) {
++		csqcfgr1 |= FMC_CSQCFGR1_ACYNBR(5);
++		csqar2 |= FMC_CSQCAR2_ADDC5(page >> 16);
++	} else {
++		csqcfgr1 |= FMC_CSQCFGR1_ACYNBR(4);
++	}
++
++	writel_relaxed(csqcfgr1, fmc->io_base + FMC_CSQCFGR1);
++	writel_relaxed(csqcfgr2, fmc->io_base + FMC_CSQCFGR2);
++	writel_relaxed(csqcfgr3, fmc->io_base + FMC_CSQCFGR3);
++	writel_relaxed(csqar1, fmc->io_base + FMC_CSQAR1);
++	writel_relaxed(csqar2, fmc->io_base + FMC_CSQAR2);
++}
++
++static void stm32_fmc_dma_callback(void *arg)
++{
++	struct completion *dma_completion = arg;
++
++	complete(dma_completion);
++}
++
++/* Read/write data from/to a page */
++static int stm32_fmc_xfer(struct stm32_fmc *fmc, const u8 *buf,
++			  int raw, bool write_data)
++{
++	struct nand_chip *chip = &fmc->chip;
++	struct dma_async_tx_descriptor *desc_data, *desc_ecc;
++	struct scatterlist *sg;
++	enum dma_data_direction dma_data_dir = DMA_FROM_DEVICE;
++	enum dma_transfer_direction dma_transfer_dir = DMA_DEV_TO_MEM;
++	u32 csqcr = readl_relaxed(fmc->io_base + FMC_CSQCR);
++	int eccsteps = chip->ecc.steps;
++	int eccsize = chip->ecc.size;
++	const u8 *p = buf;
++	int s, ret;
++
++	/* Configure DMA data */
++	if (write_data) {
++		dma_data_dir = DMA_TO_DEVICE;
++		dma_transfer_dir = DMA_MEM_TO_DEV;
++	}
++
++	for_each_sg(fmc->dma_data_sg.sgl, sg, eccsteps, s) {
++		sg_set_buf(sg, p, eccsize);
++		p += eccsize;
++	}
++
++	ret = dma_map_sg(fmc->dev, fmc->dma_data_sg.sgl,
++			 eccsteps, dma_data_dir);
++	if (ret < 0)
++		return ret;
++
++	desc_data = dmaengine_prep_slave_sg(fmc->dma_data_ch,
++					    fmc->dma_data_sg.sgl,
++					    eccsteps, dma_transfer_dir,
++					    DMA_PREP_INTERRUPT);
++	if (!desc_data) {
++		ret = -ENOMEM;
++		goto err_unmap_data;
++	}
++
++	reinit_completion(&fmc->dma_data_complete);
++	reinit_completion(&fmc->complete);
++	desc_data->callback = stm32_fmc_dma_callback;
++	desc_data->callback_param = &fmc->dma_data_complete;
++	ret = dma_submit_error(dmaengine_submit(desc_data));
++	if (ret)
++		goto err_unmap_data;
++
++	dma_async_issue_pending(fmc->dma_data_ch);
++
++	if (!write_data && !raw) {
++		/* Configure DMA ecc status */
++		p = fmc->ecc_buf;
++		for_each_sg(fmc->dma_ecc_sg.sgl, sg, eccsteps, s) {
++			sg_set_buf(sg, p, fmc->dma_ecc_len);
++			p += fmc->dma_ecc_len;
++		}
++
++		ret = dma_map_sg(fmc->dev, fmc->dma_ecc_sg.sgl,
++				 eccsteps, dma_data_dir);
++		if (ret < 0)
++			goto err_unmap_data;
++
++		desc_ecc = dmaengine_prep_slave_sg(fmc->dma_ecc_ch,
++						   fmc->dma_ecc_sg.sgl,
++						   eccsteps, dma_transfer_dir,
++						   DMA_PREP_INTERRUPT);
++		if (!desc_ecc) {
++			ret = -ENOMEM;
++			goto err_unmap_ecc;
++		}
++
++		reinit_completion(&fmc->dma_ecc_complete);
++		desc_ecc->callback = stm32_fmc_dma_callback;
++		desc_ecc->callback_param = &fmc->dma_ecc_complete;
++		ret = dma_submit_error(dmaengine_submit(desc_ecc));
++		if (ret)
++			goto err_unmap_ecc;
++
++		dma_async_issue_pending(fmc->dma_ecc_ch);
++	}
++
++	stm32_fmc_clear_seq_irq(fmc);
++	stm32_fmc_enable_seq_irq(fmc);
++
++	/* Start the transfer */
++	csqcr |= FMC_CSQCR_CSQSTART;
++	writel_relaxed(csqcr, fmc->io_base + FMC_CSQCR);
++
++	/* Wait end of sequencer transfer */
++	if (!wait_for_completion_timeout(&fmc->complete,
++					 msecs_to_jiffies(1000))) {
++		dev_err(fmc->dev, "seq timeout\n");
++		stm32_fmc_disable_seq_irq(fmc);
++		dmaengine_terminate_all(fmc->dma_data_ch);
++		if (!write_data && !raw)
++			dmaengine_terminate_all(fmc->dma_ecc_ch);
++		ret = -ETIMEDOUT;
++		goto err_unmap_ecc;
++	}
++
++	/* Wait DMA data transfer completion */
++	if (!wait_for_completion_timeout(&fmc->dma_data_complete,
++					 msecs_to_jiffies(100))) {
++		dev_err(fmc->dev, "data DMA timeout\n");
++		dmaengine_terminate_all(fmc->dma_data_ch);
++		ret = -ETIMEDOUT;
++	}
++
++	/* Wait DMA ecc transfer completion */
++	if (!write_data && !raw) {
++		if (!wait_for_completion_timeout(&fmc->dma_ecc_complete,
++						 msecs_to_jiffies(100))) {
++			dev_err(fmc->dev, "ecc DMA timeout\n");
++			dmaengine_terminate_all(fmc->dma_ecc_ch);
++			ret = -ETIMEDOUT;
++		}
++	}
++
++err_unmap_ecc:
++	if (!write_data && !raw)
++		dma_unmap_sg(fmc->dev, fmc->dma_ecc_sg.sgl,
++			     eccsteps, dma_data_dir);
++
++err_unmap_data:
++	dma_unmap_sg(fmc->dev, fmc->dma_data_sg.sgl, eccsteps, dma_data_dir);
++
++	return ret;
++}
++
++static int stm32_fmc_sequencer_write(struct mtd_info *mtd,
++				     struct nand_chip *chip,
++				     const u8 *buf, int oob_required,
++				     int page, int raw)
++{
++	struct stm32_fmc *fmc = nand_get_controller_data(chip);
++	int ret;
++
++	/* Configure the sequencer */
++	stm32_fmc_rw_page_init(fmc, page, raw, true);
++
++	/* Write the page */
++	ret = stm32_fmc_xfer(fmc, buf, raw, true);
++	if (ret)
++		return ret;
++
++	/* Write oob */
++	if (oob_required) {
++		chip->cmdfunc(mtd, NAND_CMD_RNDIN, mtd->writesize, -1);
++		chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
++	}
++
++	/* Send command to program the page */
++	chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
++
++	ret = chip->waitfunc(mtd, chip);
++
++	return ret & NAND_STATUS_FAIL ? -EIO : 0;
++}
++
++static int stm32_fmc_sequencer_write_page(struct mtd_info *mtd,
++					  struct nand_chip *chip,
++					  const uint8_t *buf,
++					  int oob_required,
++					  int page)
++{
++	return stm32_fmc_sequencer_write(mtd, chip, buf,
++					 oob_required, page, false);
++}
++
++static int stm32_fmc_sequencer_write_page_raw(struct mtd_info *mtd,
++					      struct nand_chip *chip,
++					      const uint8_t *buf,
++					      int oob_required,
++					      int page)
++{
++	return stm32_fmc_sequencer_write(mtd, chip, buf,
++					 oob_required, page, true);
++}
++
++/*
++ * Get a status indicating which sectors have errors
++ * Only available when the sequencer is used (BCH only)
++ */
++static inline u16 stm32_fmc_get_mapping_status(struct stm32_fmc *fmc)
++{
++	u32 csqemsr = readl_relaxed(fmc->io_base + FMC_CSQEMSR);
++
++	return csqemsr & FMC_CSQEMSR_SEM;
++}
++
++static int stm32_fmc_sequencer_read_page(struct mtd_info *mtd,
++					 struct nand_chip *chip,
++					 uint8_t *buf,
++					 int oob_required,
++					 int page)
++{
++	struct stm32_fmc *fmc = nand_get_controller_data(chip);
++	int i, s, ret, eccsize = chip->ecc.size;
++	int eccbytes = chip->ecc.bytes;
++	int eccsteps = chip->ecc.steps;
++	int eccstrength = chip->ecc.strength;
++	u8 *p = buf;
++	u8 *ecc_calc = chip->buffers->ecccalc;
++	u8 *ecc_code = chip->buffers->ecccode;
++	u32 *ecc_sta = (u32 *)fmc->ecc_buf;
++	u16 sta_map = 0xFFFF;
++	unsigned int max_bitflips = 0;
++
++	/* Configure the sequencer */
++	stm32_fmc_rw_page_init(fmc, page, 0, false);
++
++	/* Read the page */
++	ret = stm32_fmc_xfer(fmc, buf, 0, false);
++	if (ret)
++		return ret;
++
++	/* In case of BCH is used, get errors mapping */
++	if (eccstrength != FMC_ECC_HAM)
++		sta_map = stm32_fmc_get_mapping_status(fmc);
++
++	/* Read oob */
++	chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize, -1);
++	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
++
++	/* Check if errors happen for BCH algorithm */
++	if (likely(!sta_map))
++		return 0;
++
++	ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, chip->oob_poi, 0,
++					 chip->ecc.total);
++	if (ret)
++		return ret;
++
++	/* Correct data */
++	for (i = 0, s = 0; s < eccsteps; s++, i += eccbytes, p += eccsize) {
++		int stat = 0;
++
++		if (eccstrength == FMC_ECC_HAM) {
++			/* Ecc_sta = FMC_HECCR */
++			stm32_fmc_ham_decode(*ecc_sta, &ecc_calc[i]);
++			stat = stm32_fmc_ham_correct(mtd, p, &ecc_code[i],
++						     &ecc_calc[i]);
++			ecc_sta++;
++		} else {
++			/*
++			 * Ecc_sta[0] = FMC_BCHDSR0
++			 * Ecc_sta[1] = FMC_BCHDSR1
++			 * Ecc_sta[2] = FMC_BCHDSR2
++			 * Ecc_sta[3] = FMC_BCHDSR3
++			 * Ecc_sta[4] = FMC_BCHDSR4
++			 */
++			if (sta_map & BIT(s))
++				stat = stm32_fmc_bch_correct_data(chip, p,
++								  &ecc_code[i],
++								  ecc_sta);
++			ecc_sta += 5;
++		}
++
++		if (stat == -EBADMSG)
++			/* Check for empty pages with bitflips */
++			stat = nand_check_erased_ecc_chunk(p, eccsize,
++							   ecc_code, eccbytes,
++							   NULL, 0,
++							   eccstrength);
++
++		if (stat < 0) {
++			mtd->ecc_stats.failed++;
++		} else {
++			mtd->ecc_stats.corrected += stat;
++			max_bitflips = max_t(unsigned int, max_bitflips, stat);
++		}
++	}
++
++	return max_bitflips;
++}
++
++static int stm32_fmc_sequencer_read_page_raw(struct mtd_info *mtd,
++					     struct nand_chip *chip,
++					     uint8_t *buf,
++					     int oob_required,
++					     int page)
++{
++	struct stm32_fmc *fmc = nand_get_controller_data(chip);
++	int ret;
++
++	/* Configure the sequencer */
++	stm32_fmc_rw_page_init(fmc, page, 1, false);
++
++	/* Read the page */
++	ret = stm32_fmc_xfer(fmc, buf, 1, false);
++	if (ret)
++		return ret;
++
++	/* Read oob */
++	if (oob_required) {
++		chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize, -1);
++		chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
++	}
++
++	return 0;
++}
++
++static irqreturn_t stm32_fmc_irq(int irq, void *dev_id)
++{
++	struct stm32_fmc *fmc = (struct stm32_fmc *)dev_id;
++
++	if (fmc->irq_state == FMC_IRQ_SEQ)
++		/* Sequencer is used */
++		stm32_fmc_disable_seq_irq(fmc);
++	else if (fmc->irq_state == FMC_IRQ_BCH)
++		/* BCH is used */
++		stm32_fmc_disable_bch_irq(fmc);
++
++	complete(&fmc->complete);
++
++	return IRQ_HANDLED;
++}
++
++/* Timings configuration */
++static void stm32_fmc_timings_init(struct stm32_fmc *fmc)
++{
++	struct stm32_fmc_timings *timings = &fmc->timings;
++	u32 pcr = readl_relaxed(fmc->io_base + FMC_PCR(fmc->bank));
++	u32 pmem, patt;
++
++	/* Set tclr/tar timings */
++	pcr &= ~FMC_PCR_TCLR_MASK;
++	pcr |= FMC_PCR_TCLR(timings->tclr);
++	pcr &= ~FMC_PCR_TAR_MASK;
++	pcr |= FMC_PCR_TAR(timings->tar);
++
++	/* Set tset/twait/thold/thiz timings in common bank */
++	pmem = FMC_PMEM_MEMSET(timings->tset_mem);
++	pmem |= FMC_PMEM_MEMWAIT(timings->twait);
++	pmem |= FMC_PMEM_MEMHOLD(timings->thold_mem);
++	pmem |= FMC_PMEM_MEMHIZ(timings->thiz);
++
++	/* Set tset/twait/thold/thiz timings in attribut bank */
++	patt = FMC_PATT_ATTSET(timings->tset_att);
++	patt |= FMC_PATT_ATTWAIT(timings->twait);
++	patt |= FMC_PATT_ATTHOLD(timings->thold_att);
++	patt |= FMC_PATT_ATTHIZ(timings->thiz);
++
++	writel_relaxed(pcr, fmc->io_base + FMC_PCR(fmc->bank));
++	writel_relaxed(pmem, fmc->io_base + FMC_PMEM(fmc->bank));
++	writel_relaxed(patt, fmc->io_base + FMC_PATT(fmc->bank));
++}
++
++/* Controller initialization */
++static void stm32_fmc_init(struct stm32_fmc *fmc)
++{
++	u32 pcr = readl_relaxed(fmc->io_base + FMC_PCR(fmc->bank));
++	u32 bcr1 = readl_relaxed(fmc->io_base + FMC_BCR1);
++
++	/* Enable wait feature and nand flash memory bank */
++	pcr |= FMC_PCR_PWAITEN;
++	pcr |= FMC_PCR_PBKEN;
++
++	/* Set buswidth to 8 bits mode for identification */
++	pcr &= ~FMC_PCR_PWID_MASK;
++
++	/* Enable FMC controller */
++	bcr1 |= FMC_BCR1_FMCEN;
++
++	writel_relaxed(bcr1, fmc->io_base + FMC_BCR1);
++	writel_relaxed(pcr, fmc->io_base + FMC_PCR(fmc->bank));
++}
++
++/* Controller configuration */
++static void stm32_fmc_setup(struct stm32_fmc *fmc)
++{
++	struct nand_chip *chip = &fmc->chip;
++	u32 pcr = readl_relaxed(fmc->io_base + FMC_PCR(fmc->bank));
++
++	/* Configure in HAMMING by default */
++	if (chip->ecc.strength == FMC_ECC_BCH8) {
++		pcr |= FMC_PCR_ECCALG;
++		pcr |= FMC_PCR_BCHECC;
++	} else if (chip->ecc.strength == FMC_ECC_BCH4) {
++		pcr |= FMC_PCR_ECCALG;
++	}
++
++	/* Set buswidth */
++	if (chip->options & NAND_BUSWIDTH_16)
++		pcr |= FMC_PCR_PWID(FMC_PCR_PWID_BUSWIDTH_16);
++
++	/* Set ecc sector size */
++	pcr &= ~FMC_PCR_ECCSS_MASK;
++	pcr |= FMC_PCR_ECCSS(FMC_PCR_ECCSS_512);
++
++	writel_relaxed(pcr, fmc->io_base + FMC_PCR(fmc->bank));
++}
++
++/* Controller timings */
++static int stm32_fmc_calc_timings(struct stm32_fmc *fmc,
++				  const struct nand_sdr_timings *sdrt,
++				  struct stm32_fmc_timings *tims)
++{
++	unsigned long hclk = clk_get_rate(fmc->clk);
++	unsigned long hclkp = NSEC_PER_SEC / (hclk / 1000);
++	int tar, tclr, thiz, twait, tset_mem, tset_att, thold_mem, thold_att;
++
++	tar = hclkp;
++	if (tar < sdrt->tAR_min)
++		tar = sdrt->tAR_min;
++	tims->tar = DIV_ROUND_UP(tar, hclkp) - 1;
++	if (tims->tar > FMC_PCR_TIMING_MASK)
++		tims->tar = FMC_PCR_TIMING_MASK;
++
++	tclr = hclkp;
++	if (tclr < sdrt->tCLR_min)
++		tclr = sdrt->tCLR_min;
++	tims->tclr = DIV_ROUND_UP(tclr, hclkp) - 1;
++	if (tims->tclr > FMC_PCR_TIMING_MASK)
++		tims->tclr = FMC_PCR_TIMING_MASK;
++
++	tims->thiz = FMC_THIZ;
++	thiz = (tims->thiz + 1) * hclkp;
++
++	/*
++	 * tWAIT > tRP
++	 * tWAIT > tWP
++	 * tWAIT > tREA + tIO
++	 */
++	twait = hclkp;
++	if (twait < sdrt->tRP_min)
++		twait = sdrt->tRP_min;
++	if (twait < sdrt->tWP_min)
++		twait = sdrt->tWP_min;
++	if (twait < sdrt->tREA_max + FMC_TIO)
++		twait = sdrt->tREA_max + FMC_TIO;
++	tims->twait = DIV_ROUND_UP(twait, hclkp) - 1;
++	if (tims->twait > FMC_PMEM_PATT_TIMING_MASK)
++		tims->twait = FMC_PMEM_PATT_TIMING_MASK;
++
++	/*
++	 * tSETUP_MEM > tCS - tWAIT
++	 * tSETUP_MEM > tALS - tWAIT
++	 * tSETUP_MEM > tDS - (tWAIT - tHIZ)
++	 */
++	tset_mem = hclkp;
++	if ((sdrt->tCS_min > twait) && (tset_mem < sdrt->tCS_min - twait))
++		tset_mem = sdrt->tCS_min - twait;
++	if ((sdrt->tALS_min > twait) && (tset_mem < sdrt->tALS_min - twait))
++		tset_mem = sdrt->tALS_min - twait;
++	if ((twait > thiz) && (sdrt->tDS_min > twait - thiz) &&
++	    (tset_mem < sdrt->tDS_min - (twait - thiz)))
++		tset_mem = sdrt->tDS_min - (twait - thiz);
++	tims->tset_mem = DIV_ROUND_UP(tset_mem, hclkp) - 1;
++	if (tims->tset_mem > FMC_PMEM_PATT_TIMING_MASK)
++		tims->tset_mem = FMC_PMEM_PATT_TIMING_MASK;
++
++	/*
++	 * tHOLD_MEM > tCH
++	 * tHOLD_MEM > tREH - tSETUP_MEM
++	 * tHOLD_MEM > max(tRC, tWC) - (tSETUP_MEM + tWAIT)
++	 */
++	thold_mem = hclkp;
++	if (thold_mem < sdrt->tCH_min)
++		thold_mem = sdrt->tCH_min;
++	if ((sdrt->tREH_min > tset_mem) &&
++	    (thold_mem < sdrt->tREH_min - tset_mem))
++		thold_mem = sdrt->tREH_min - tset_mem;
++	if ((sdrt->tRC_min > tset_mem + twait) &&
++	    (thold_mem < sdrt->tRC_min - (tset_mem + twait)))
++		thold_mem = sdrt->tRC_min - (tset_mem + twait);
++	if ((sdrt->tWC_min > tset_mem + twait) &&
++	    (thold_mem < sdrt->tWC_min - (tset_mem + twait)))
++		thold_mem = sdrt->tWC_min - (tset_mem + twait);
++	tims->thold_mem = DIV_ROUND_UP(thold_mem, hclkp) - 1;
++	if (tims->thold_mem > FMC_PMEM_PATT_TIMING_MASK)
++		tims->thold_mem = FMC_PMEM_PATT_TIMING_MASK;
++
++	/*
++	 * tSETUP_ATT > tCS - tWAIT
++	 * tSETUP_ATT > tCLS - tWAIT
++	 * tSETUP_ATT > tALS - tWAIT
++	 * tSETUP_ATT > tRHW - tHOLD_MEM
++	 * tSETUP_ATT > tDS - (tWAIT - tHIZ)
++	 */
++	tset_att = hclkp;
++	if ((sdrt->tCS_min > twait) && (tset_att < sdrt->tCS_min - twait))
++		tset_att = sdrt->tCS_min - twait;
++	if ((sdrt->tCLS_min > twait) && (tset_att < sdrt->tCLS_min - twait))
++		tset_att = sdrt->tCLS_min - twait;
++	if ((sdrt->tALS_min > twait) && (tset_att < sdrt->tALS_min - twait))
++		tset_att = sdrt->tALS_min - twait;
++	if ((sdrt->tRHW_min > thold_mem) &&
++	    (tset_att < sdrt->tRHW_min - thold_mem))
++		tset_att = sdrt->tRHW_min - thold_mem;
++	if ((twait > thiz) && (sdrt->tDS_min > twait - thiz) &&
++	    (tset_att < sdrt->tDS_min - (twait - thiz)))
++		tset_att = sdrt->tDS_min - (twait - thiz);
++	tims->tset_att = DIV_ROUND_UP(tset_att, hclkp) - 1;
++	if (tims->tset_att > FMC_PMEM_PATT_TIMING_MASK)
++		tims->tset_att = FMC_PMEM_PATT_TIMING_MASK;
++
++	/*
++	 * tHOLD_ATT > tALH
++	 * tHOLD_ATT > tCH
++	 * tHOLD_ATT > tCLH
++	 * tHOLD_ATT > tCOH
++	 * tHOLD_ATT > tDH
++	 * tHOLD_ATT > tWB + tIO + tSYNC - tSETUP_MEM
++	 * tHOLD_ATT > tADL - tSETUP_MEM
++	 * tHOLD_ATT > tWH - tSETUP_MEM
++	 * tHOLD_ATT > tWHR - tSETUP_MEM
++	 * tHOLD_ATT > tRC - (tSETUP_ATT + tWAIT)
++	 * tHOLD_ATT > tWC - (tSETUP_ATT + tWAIT)
++	 */
++	thold_att = hclkp;
++	if (thold_att < sdrt->tALH_min)
++		thold_att = sdrt->tALH_min;
++	if (thold_att < sdrt->tCH_min)
++		thold_att = sdrt->tCH_min;
++	if (thold_att < sdrt->tCLH_min)
++		thold_att = sdrt->tCLH_min;
++	if (thold_att < sdrt->tCOH_min)
++		thold_att = sdrt->tCOH_min;
++	if (thold_att < sdrt->tDH_min)
++		thold_att = sdrt->tDH_min;
++	if ((sdrt->tWB_max + FMC_TIO + FMC_TSYNC > tset_mem) &&
++	    (thold_att < sdrt->tWB_max + FMC_TIO + FMC_TSYNC - tset_mem))
++		thold_att = sdrt->tWB_max + FMC_TIO + FMC_TSYNC - tset_mem;
++	if ((sdrt->tADL_min > tset_mem) &&
++	    (thold_att < sdrt->tADL_min - tset_mem))
++		thold_att = sdrt->tADL_min - tset_mem;
++	if ((sdrt->tWH_min > tset_mem) &&
++	    (thold_att < sdrt->tWH_min - tset_mem))
++		thold_att = sdrt->tWH_min - tset_mem;
++	if ((sdrt->tWHR_min > tset_mem) &&
++	    (thold_att < sdrt->tWHR_min - tset_mem))
++		thold_att = sdrt->tWHR_min - tset_mem;
++	if ((sdrt->tRC_min > tset_att + twait) &&
++	    (thold_att < sdrt->tRC_min - (tset_att + twait)))
++		thold_att = sdrt->tRC_min - (tset_att + twait);
++	if ((sdrt->tWC_min > tset_att + twait) &&
++	    (thold_att < sdrt->tWC_min - (tset_att + twait)))
++		thold_att = sdrt->tWC_min - (tset_att + twait);
++	tims->thold_att = DIV_ROUND_UP(thold_att, hclkp) - 1;
++	if (tims->thold_att > FMC_PMEM_PATT_TIMING_MASK)
++		tims->thold_att = FMC_PMEM_PATT_TIMING_MASK;
++
++	return 0;
++}
++
++static int stm32_fmc_setup_interface(struct mtd_info *mtd, int chipnr,
++				     const struct nand_data_interface *conf)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct stm32_fmc *fmc = nand_get_controller_data(chip);
++	struct stm32_fmc_timings tims;
++	const struct nand_sdr_timings *sdrt;
++	int ret;
++
++	sdrt = nand_get_sdr_timings(conf);
++	if (IS_ERR(sdrt))
++		return PTR_ERR(sdrt);
++
++	ret = stm32_fmc_calc_timings(fmc, sdrt, &tims);
++	if (ret)
++		return ret;
++
++	if (chipnr == NAND_DATA_IFACE_CHECK_ONLY)
++		return 0;
++
++	/* Save and apply timings */
++	memcpy(&fmc->timings, &tims, sizeof(tims));
++	stm32_fmc_timings_init(fmc);
++
++	return 0;
++}
++
++/* DMA configuration */
++static int stm32_fmc_nand_dma_setup(struct stm32_fmc *fmc, u8 nb_sect,
++				    phys_addr_t data_phys_base,
++				    phys_addr_t io_phys_base)
++{
++	struct nand_chip *chip = &fmc->chip;
++	struct dma_slave_config dma_cfg;
++	int ret;
++
++	/*
++	 * Data DMA is found => sequencer mode will be used
++	 * Else manual mode is used
++	 */
++	fmc->dma_data_ch = dma_request_slave_channel(fmc->dev, "rxtx");
++	if (fmc->dma_data_ch) {
++		memset(&dma_cfg, 0, sizeof(dma_cfg));
++		dma_cfg.src_addr = data_phys_base;
++		dma_cfg.dst_addr = data_phys_base;
++		dma_cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
++		dma_cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
++		dma_cfg.src_maxburst = 32;
++		dma_cfg.dst_maxburst = 32;
++
++		ret = dmaengine_slave_config(fmc->dma_data_ch, &dma_cfg);
++		if (ret) {
++			dev_err(fmc->dev, "data DMA engine slave config failed\n");
++			return ret;
++		}
++
++		ret = sg_alloc_table(&fmc->dma_data_sg, nb_sect, GFP_KERNEL);
++		if (ret)
++			return ret;
++
++		fmc->dma_ecc_ch = dma_request_slave_channel(fmc->dev, "ecc");
++		if (fmc->dma_ecc_ch) {
++			/*
++			 * HAMMING: we read HECCR register
++			 * BCH4/BCH8: we read BCHDSRSx registers
++			 */
++			memset(&dma_cfg, 0, sizeof(dma_cfg));
++			dma_cfg.src_addr = io_phys_base;
++			dma_cfg.src_addr += chip->ecc.strength == FMC_ECC_HAM ?
++					    FMC_HECCR(fmc->bank) : FMC_BCHDSR0;
++			dma_cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
++
++			ret = dmaengine_slave_config(fmc->dma_ecc_ch,
++						     &dma_cfg);
++			if (ret) {
++				dev_err(fmc->dev, "ecc DMA engine slave config failed\n");
++				return ret;
++			}
++
++			ret = sg_alloc_table(&fmc->dma_ecc_sg,
++					     nb_sect, GFP_KERNEL);
++			if (ret)
++				return ret;
++
++			/* Calculate ecc length needed for one sector */
++			fmc->dma_ecc_len = chip->ecc.strength == FMC_ECC_HAM ?
++					   FMC_HECCR_LEN : FMC_BCHDSRS_LEN;
++
++			/* Allocate a buffer to store ecc status registers */
++			fmc->ecc_buf = devm_kzalloc(fmc->dev,
++						    fmc->dma_ecc_len * nb_sect,
++						    GFP_KERNEL);
++			if (!fmc->ecc_buf)
++				return -ENOMEM;
++		} else {
++			dev_err(fmc->dev, "ecc DMA not defined in the device tree\n");
++			return -ENOENT;
++		}
++	}
++
++	return 0;
++}
++
++/* NAND callbacks setup */
++static void stm32_fmc_nand_callbacks_setup(struct stm32_fmc *fmc)
++{
++	struct nand_chip *chip = &fmc->chip;
++
++	/*
++	 * Specific callbacks to read/write a page depending on
++	 * the mode (manual/sequencer) and the algo used (HAMMING, BCH).
++	 */
++	if (fmc->dma_data_ch) {
++		/* DMA => use sequencer mode callbacks */
++		chip->ecc.write_page = stm32_fmc_sequencer_write_page;
++		chip->ecc.read_page = stm32_fmc_sequencer_read_page;
++		chip->ecc.write_page_raw = stm32_fmc_sequencer_write_page_raw;
++		chip->ecc.read_page_raw = stm32_fmc_sequencer_read_page_raw;
++		chip->options |= NAND_USE_BOUNCE_BUFFER;
++		chip->ecc.options |= NAND_ECC_CUSTOM_PAGE_ACCESS;
++	} else {
++		/* No DMA => use manual mode callbacks */
++		chip->ecc.hwctl = stm32_fmc_hwctl;
++		if (chip->ecc.strength == FMC_ECC_HAM) {
++			/* HAMMING is used */
++			chip->ecc.calculate = stm32_fmc_ham_calculate;
++			chip->ecc.correct = stm32_fmc_ham_correct;
++		} else {
++			/* BCH is used */
++			chip->ecc.read_page = stm32_fmc_read_page;
++			chip->ecc.calculate = stm32_fmc_bch_calculate;
++			chip->ecc.correct = stm32_fmc_bch_correct;
++		}
++	}
++
++	/* Specific configurations depending on the algo used (HAMMING, BCH) */
++	if (chip->ecc.strength == FMC_ECC_HAM) {
++		chip->ecc.bytes = chip->options & NAND_BUSWIDTH_16 ? 4 : 3;
++		chip->ecc.options |= NAND_ECC_GENERIC_ERASED_CHECK;
++	} else if (chip->ecc.strength == FMC_ECC_BCH8) {
++		chip->ecc.bytes = chip->options & NAND_BUSWIDTH_16 ? 14 : 13;
++	} else {
++		chip->ecc.bytes = chip->options & NAND_BUSWIDTH_16 ? 8 : 7;
++	}
++}
++
++/* FMC layout */
++static int stm32_fmc_nand_ooblayout_ecc(struct mtd_info *mtd, int section,
++					struct mtd_oob_region *oobregion)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct nand_ecc_ctrl *ecc = &chip->ecc;
++
++	if (section)
++		return -ERANGE;
++
++	oobregion->length = ecc->total;
++	oobregion->offset = FMC_BBM_LEN;
++
++	return 0;
++}
++
++static int stm32_fmc_nand_ooblayout_free(struct mtd_info *mtd, int section,
++					 struct mtd_oob_region *oobregion)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct nand_ecc_ctrl *ecc = &chip->ecc;
++
++	if (section)
++		return -ERANGE;
++
++	oobregion->length = mtd->oobsize - ecc->total - FMC_BBM_LEN;
++	oobregion->offset = ecc->total + FMC_BBM_LEN;
++
++	return 0;
++}
++
++const struct mtd_ooblayout_ops stm32_fmc_nand_ooblayout_ops = {
++	.ecc = stm32_fmc_nand_ooblayout_ecc,
++	.free = stm32_fmc_nand_ooblayout_free,
++};
++
++static bool stm32_fmc_parse_dt(struct platform_device *pdev)
++{
++	struct device *dev = &pdev->dev;
++	struct device_node *dn = dev->of_node;
++	struct stm32_fmc *fmc = platform_get_drvdata(pdev);
++	int ret;
++
++	/* Get the bank used, bank 3 is used by default */
++	if (of_property_read_u32(dn, "st,fmc_bank_used", &fmc->bank))
++		fmc->bank = 3;
++
++	/* Common bank timings */
++	ret = of_property_read_u8_array(dn, "st,fmc_timings",
++					(u8 *)&fmc->timings,
++					sizeof(fmc->timings));
++
++	return ret ? false : true;
++}
++
++static int stm32_fmc_probe(struct platform_device *pdev)
++{
++	struct device *dev = &pdev->dev;
++	struct reset_control *rstc;
++	struct stm32_fmc *fmc;
++	struct resource *res;
++	struct mtd_info *mtd;
++	struct nand_chip *chip;
++	phys_addr_t data_phys_base, io_phys_base;
++	u16 ecc_space_needed;
++	u8 nb_sect;
++	int ret, irq;
++	bool timings_def;
++
++	fmc = devm_kzalloc(dev, sizeof(*fmc), GFP_KERNEL);
++	if (!fmc)
++		return -ENOMEM;
++
++	fmc->dev = dev;
++	platform_set_drvdata(pdev, fmc);
++
++	timings_def = stm32_fmc_parse_dt(pdev);
++
++	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fmc_regs");
++	fmc->io_base = devm_ioremap_resource(dev, res);
++	if (IS_ERR(fmc->io_base))
++		return PTR_ERR(fmc->io_base);
++
++	io_phys_base = res->start;
++
++	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fmc_common");
++	fmc->common_base = devm_ioremap_resource(dev, res);
++	if (IS_ERR(fmc->common_base))
++		return PTR_ERR(fmc->common_base);
++
++	data_phys_base = res->start + FMC_DATA_SECTION;
++
++	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fmc_attrib");
++	fmc->attrib_base = devm_ioremap_resource(dev, res);
++	if (IS_ERR(fmc->attrib_base))
++		return PTR_ERR(fmc->attrib_base);
++
++	irq = platform_get_irq(pdev, 0);
++	ret = devm_request_irq(dev, irq, stm32_fmc_irq, 0,
++			       dev_name(dev), fmc);
++	if (ret) {
++		dev_err(dev, "failed to request irq\n");
++		return ret;
++	}
++
++	init_completion(&fmc->complete);
++	init_completion(&fmc->dma_data_complete);
++	init_completion(&fmc->dma_ecc_complete);
++
++	fmc->clk = devm_clk_get(dev, NULL);
++	if (IS_ERR(fmc->clk))
++		return PTR_ERR(fmc->clk);
++
++	ret = clk_prepare_enable(fmc->clk);
++	if (ret) {
++		dev_err(dev, "can not enable the clock\n");
++		return ret;
++	}
++
++	rstc = devm_reset_control_get(dev, NULL);
++	if (!IS_ERR(rstc)) {
++		reset_control_assert(rstc);
++		reset_control_deassert(rstc);
++	}
++
++	mtd = nand_to_mtd(&fmc->chip);
++	chip = &fmc->chip;
++	nand_set_controller_data(chip, fmc);
++	nand_set_flash_node(chip, dev->of_node);
++	mtd->dev.parent = dev;
++
++	/* Set NAND IO addresses and command/ready functions */
++	chip->IO_ADDR_R = fmc->common_base + FMC_DATA_SECTION;
++	chip->IO_ADDR_W = fmc->common_base + FMC_DATA_SECTION;
++	chip->cmd_ctrl = stm32_fmc_cmd_ctrl;
++	chip->chip_delay = FMC_RB_DELAY_US;
++	chip->options |= NAND_BUSWIDTH_AUTO | NAND_NO_SUBPAGE_WRITE;
++
++	/* FMC init routine */
++	stm32_fmc_init(fmc);
++	if (timings_def)
++		stm32_fmc_timings_init(fmc);
++	else
++		chip->setup_data_interface = stm32_fmc_setup_interface;
++
++	/*
++	 * Only NAND_ECC_HW mode is actually supported
++	 * HAMMING => ecc.strength = 1
++	 * BCH4 => ecc.strength = 4
++	 * BCH8 => ecc.strength = 8 (default)
++	 */
++	chip->ecc.mode = NAND_ECC_HW;
++	chip->ecc.size = 512;
++	chip->ecc.strength = FMC_ECC_BCH8;
++
++	/* Scan to find existence of the device */
++	ret = nand_scan_ident(mtd, 1, NULL);
++	if (ret)
++		goto err_scan_ident;
++
++	if (chip->ecc.size != 512) {
++		dev_err(dev, "ecc_step_size is not well defined in the DT\n");
++		ret = -EINVAL;
++		goto err_scan_ident;
++	}
++
++	if ((chip->ecc.strength != FMC_ECC_BCH8) &&
++	    (chip->ecc.strength != FMC_ECC_BCH4) &&
++	    (chip->ecc.strength != FMC_ECC_HAM)) {
++		dev_err(dev, "ecc_strength is not well defined in the DT\n");
++		ret = -EINVAL;
++		goto err_scan_ident;
++	}
++
++	nb_sect = mtd->writesize / chip->ecc.size;
++	if (nb_sect > FMC_MAX_SG_COUNT) {
++		dev_err(dev, "nand page size is not supported\n");
++		ret = -EINVAL;
++		goto err_scan_ident;
++	}
++
++	if (chip->bbt_options & NAND_BBT_USE_FLASH)
++		chip->bbt_options |= NAND_BBT_NO_OOB;
++
++	/* FMC setup routine */
++	stm32_fmc_setup(fmc);
++
++	/* DMA setup */
++	ret = stm32_fmc_nand_dma_setup(fmc, nb_sect, data_phys_base,
++				       io_phys_base);
++	if (ret)
++		goto err_dma_setup;
++
++	/* NAND callbacks setup */
++	stm32_fmc_nand_callbacks_setup(fmc);
++
++	/*
++	 * Check if parity bits can be stored in OOB
++	 * The first 2 bytes are skipped (BBM)
++	 */
++	ecc_space_needed = chip->ecc.bytes * nb_sect;
++	if (mtd->oobsize < (ecc_space_needed + FMC_BBM_LEN)) {
++		dev_err(dev, "not enough OOB bytes required = %d, available=%d\n",
++			ecc_space_needed, mtd->oobsize);
++		ret = -EINVAL;
++		goto err_dma_setup;
++	}
++
++	/* Define ECC layout */
++	mtd_set_ooblayout(mtd, &stm32_fmc_nand_ooblayout_ops);
++
++	/* Scan the device to fill MTD data-structures */
++	if (nand_scan_tail(mtd)) {
++		ret = -ENXIO;
++		goto err_dma_setup;
++	}
++
++	ret = mtd_device_register(mtd, NULL, 0);
++	if (ret)
++		goto err_dma_setup;
++
++	return 0;
++
++err_dma_setup:
++	if (fmc->dma_ecc_ch)
++		dma_release_channel(fmc->dma_ecc_ch);
++
++	if (fmc->dma_data_ch)
++		dma_release_channel(fmc->dma_data_ch);
++
++	sg_free_table(&fmc->dma_data_sg);
++	sg_free_table(&fmc->dma_ecc_sg);
++
++err_scan_ident:
++	clk_disable_unprepare(fmc->clk);
++
++	return ret;
++}
++
++static int stm32_fmc_remove(struct platform_device *pdev)
++{
++	struct stm32_fmc *fmc = platform_get_drvdata(pdev);
++	struct mtd_info *mtd = nand_to_mtd(&fmc->chip);
++
++	if (fmc->dma_ecc_ch)
++		dma_release_channel(fmc->dma_ecc_ch);
++
++	if (fmc->dma_data_ch)
++		dma_release_channel(fmc->dma_data_ch);
++
++	sg_free_table(&fmc->dma_data_sg);
++	sg_free_table(&fmc->dma_ecc_sg);
++
++	clk_disable_unprepare(fmc->clk);
++
++	nand_release(mtd);
++
++	return 0;
++}
++
++#ifdef CONFIG_PM_SLEEP
++static int stm32_fmc_suspend(struct device *dev)
++{
++	struct stm32_fmc *fmc = dev_get_drvdata(dev);
++
++	clk_disable_unprepare(fmc->clk);
++
++	return 0;
++}
++
++static int stm32_fmc_resume(struct device *dev)
++{
++	struct stm32_fmc *fmc = dev_get_drvdata(dev);
++	int ret;
++
++	ret = clk_prepare_enable(fmc->clk);
++	if (ret) {
++		dev_err(dev, "can not enable the clock\n");
++		return ret;
++	}
++
++	stm32_fmc_init(fmc);
++	stm32_fmc_timings_init(fmc);
++	stm32_fmc_setup(fmc);
++
++	return 0;
++}
++#endif
++
++static SIMPLE_DEV_PM_OPS(stm32_fmc_pm_ops, stm32_fmc_suspend, stm32_fmc_resume);
++
++static const struct of_device_id stm32_fmc_match[] = {
++	{.compatible = "st,stm32mp1-fmc"},
++	{}
++};
++MODULE_DEVICE_TABLE(of, stm32_fmc_match);
++
++static struct platform_driver stm32_fmc_driver = {
++	.probe	= stm32_fmc_probe,
++	.remove	= stm32_fmc_remove,
++	.driver	= {
++		.name = "stm32-fmc",
++		.of_match_table = stm32_fmc_match,
++		.pm = &stm32_fmc_pm_ops,
++	},
++};
++module_platform_driver(stm32_fmc_driver);
++
++MODULE_ALIAS("platform:" DRIVER_NAME);
++MODULE_AUTHOR("Christophe Kerello <christophe.kerello@st.com>");
++MODULE_DESCRIPTION("STMicroelectronics STM32 fmc nand driver");
++MODULE_LICENSE("GPL v2");
+diff --git a/drivers/mtd/nand/raw/sunxi_nand.c b/drivers/mtd/nand/raw/sunxi_nand.c
+new file mode 100644
+index 0000000..82244be
+--- /dev/null
++++ b/drivers/mtd/nand/raw/sunxi_nand.c
+@@ -0,0 +1,2310 @@
++/*
++ * Copyright (C) 2013 Boris BREZILLON <b.brezillon.dev@gmail.com>
++ *
++ * Derived from:
++ *	https://github.com/yuq/sunxi-nfc-mtd
++ *	Copyright (C) 2013 Qiang Yu <yuq825@gmail.com>
++ *
++ *	https://github.com/hno/Allwinner-Info
++ *	Copyright (C) 2013 Henrik Nordström <Henrik Nordström>
++ *
++ *	Copyright (C) 2013 Dmitriy B. <rzk333@gmail.com>
++ *	Copyright (C) 2013 Sergey Lapin <slapin@ossfans.org>
++ *
++ * 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/dma-mapping.h>
++#include <linux/slab.h>
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/platform_device.h>
++#include <linux/of.h>
++#include <linux/of_device.h>
++#include <linux/of_gpio.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/rawnand.h>
++#include <linux/mtd/partitions.h>
++#include <linux/clk.h>
++#include <linux/delay.h>
++#include <linux/dmaengine.h>
++#include <linux/gpio.h>
++#include <linux/interrupt.h>
++#include <linux/iopoll.h>
++#include <linux/reset.h>
++
++#define NFC_REG_CTL		0x0000
++#define NFC_REG_ST		0x0004
++#define NFC_REG_INT		0x0008
++#define NFC_REG_TIMING_CTL	0x000C
++#define NFC_REG_TIMING_CFG	0x0010
++#define NFC_REG_ADDR_LOW	0x0014
++#define NFC_REG_ADDR_HIGH	0x0018
++#define NFC_REG_SECTOR_NUM	0x001C
++#define NFC_REG_CNT		0x0020
++#define NFC_REG_CMD		0x0024
++#define NFC_REG_RCMD_SET	0x0028
++#define NFC_REG_WCMD_SET	0x002C
++#define NFC_REG_IO_DATA		0x0030
++#define NFC_REG_ECC_CTL		0x0034
++#define NFC_REG_ECC_ST		0x0038
++#define NFC_REG_DEBUG		0x003C
++#define NFC_REG_ECC_ERR_CNT(x)	((0x0040 + (x)) & ~0x3)
++#define NFC_REG_USER_DATA(x)	(0x0050 + ((x) * 4))
++#define NFC_REG_SPARE_AREA	0x00A0
++#define NFC_REG_PAT_ID		0x00A4
++#define NFC_RAM0_BASE		0x0400
++#define NFC_RAM1_BASE		0x0800
++
++/* define bit use in NFC_CTL */
++#define NFC_EN			BIT(0)
++#define NFC_RESET		BIT(1)
++#define NFC_BUS_WIDTH_MSK	BIT(2)
++#define NFC_BUS_WIDTH_8		(0 << 2)
++#define NFC_BUS_WIDTH_16	(1 << 2)
++#define NFC_RB_SEL_MSK		BIT(3)
++#define NFC_RB_SEL(x)		((x) << 3)
++#define NFC_CE_SEL_MSK		GENMASK(26, 24)
++#define NFC_CE_SEL(x)		((x) << 24)
++#define NFC_CE_CTL		BIT(6)
++#define NFC_PAGE_SHIFT_MSK	GENMASK(11, 8)
++#define NFC_PAGE_SHIFT(x)	(((x) < 10 ? 0 : (x) - 10) << 8)
++#define NFC_SAM			BIT(12)
++#define NFC_RAM_METHOD		BIT(14)
++#define NFC_DEBUG_CTL		BIT(31)
++
++/* define bit use in NFC_ST */
++#define NFC_RB_B2R		BIT(0)
++#define NFC_CMD_INT_FLAG	BIT(1)
++#define NFC_DMA_INT_FLAG	BIT(2)
++#define NFC_CMD_FIFO_STATUS	BIT(3)
++#define NFC_STA			BIT(4)
++#define NFC_NATCH_INT_FLAG	BIT(5)
++#define NFC_RB_STATE(x)		BIT(x + 8)
++
++/* define bit use in NFC_INT */
++#define NFC_B2R_INT_ENABLE	BIT(0)
++#define NFC_CMD_INT_ENABLE	BIT(1)
++#define NFC_DMA_INT_ENABLE	BIT(2)
++#define NFC_INT_MASK		(NFC_B2R_INT_ENABLE | \
++				 NFC_CMD_INT_ENABLE | \
++				 NFC_DMA_INT_ENABLE)
++
++/* define bit use in NFC_TIMING_CTL */
++#define NFC_TIMING_CTL_EDO	BIT(8)
++
++/* define NFC_TIMING_CFG register layout */
++#define NFC_TIMING_CFG(tWB, tADL, tWHR, tRHW, tCAD)		\
++	(((tWB) & 0x3) | (((tADL) & 0x3) << 2) |		\
++	(((tWHR) & 0x3) << 4) | (((tRHW) & 0x3) << 6) |		\
++	(((tCAD) & 0x7) << 8))
++
++/* define bit use in NFC_CMD */
++#define NFC_CMD_LOW_BYTE_MSK	GENMASK(7, 0)
++#define NFC_CMD_HIGH_BYTE_MSK	GENMASK(15, 8)
++#define NFC_CMD(x)		(x)
++#define NFC_ADR_NUM_MSK		GENMASK(18, 16)
++#define NFC_ADR_NUM(x)		(((x) - 1) << 16)
++#define NFC_SEND_ADR		BIT(19)
++#define NFC_ACCESS_DIR		BIT(20)
++#define NFC_DATA_TRANS		BIT(21)
++#define NFC_SEND_CMD1		BIT(22)
++#define NFC_WAIT_FLAG		BIT(23)
++#define NFC_SEND_CMD2		BIT(24)
++#define NFC_SEQ			BIT(25)
++#define NFC_DATA_SWAP_METHOD	BIT(26)
++#define NFC_ROW_AUTO_INC	BIT(27)
++#define NFC_SEND_CMD3		BIT(28)
++#define NFC_SEND_CMD4		BIT(29)
++#define NFC_CMD_TYPE_MSK	GENMASK(31, 30)
++#define NFC_NORMAL_OP		(0 << 30)
++#define NFC_ECC_OP		(1 << 30)
++#define NFC_PAGE_OP		(2 << 30)
++
++/* define bit use in NFC_RCMD_SET */
++#define NFC_READ_CMD_MSK	GENMASK(7, 0)
++#define NFC_RND_READ_CMD0_MSK	GENMASK(15, 8)
++#define NFC_RND_READ_CMD1_MSK	GENMASK(23, 16)
++
++/* define bit use in NFC_WCMD_SET */
++#define NFC_PROGRAM_CMD_MSK	GENMASK(7, 0)
++#define NFC_RND_WRITE_CMD_MSK	GENMASK(15, 8)
++#define NFC_READ_CMD0_MSK	GENMASK(23, 16)
++#define NFC_READ_CMD1_MSK	GENMASK(31, 24)
++
++/* define bit use in NFC_ECC_CTL */
++#define NFC_ECC_EN		BIT(0)
++#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)
++#define NFC_ECC_MODE(x)		((x) << 12)
++#define NFC_RANDOM_SEED_MSK	GENMASK(30, 16)
++#define NFC_RANDOM_SEED(x)	((x) << 16)
++
++/* define bit use in NFC_ECC_ST */
++#define NFC_ECC_ERR(x)		BIT(x)
++#define NFC_ECC_ERR_MSK		GENMASK(15, 0)
++#define NFC_ECC_PAT_FOUND(x)	BIT(x + 16)
++#define NFC_ECC_ERR_CNT(b, x)	(((x) >> (((b) % 4) * 8)) & 0xff)
++
++#define NFC_DEFAULT_TIMEOUT_MS	1000
++
++#define NFC_SRAM_SIZE		1024
++
++#define NFC_MAX_CS		7
++
++/*
++ * Ready/Busy detection type: describes the Ready/Busy detection modes
++ *
++ * @RB_NONE:	no external detection available, rely on STATUS command
++ *		and software timeouts
++ * @RB_NATIVE:	use sunxi NAND controller Ready/Busy support. The Ready/Busy
++ *		pin of the NAND flash chip must be connected to one of the
++ *		native NAND R/B pins (those which can be muxed to the NAND
++ *		Controller)
++ * @RB_GPIO:	use a simple GPIO to handle Ready/Busy status. The Ready/Busy
++ *		pin of the NAND flash chip must be connected to a GPIO capable
++ *		pin.
++ */
++enum sunxi_nand_rb_type {
++	RB_NONE,
++	RB_NATIVE,
++	RB_GPIO,
++};
++
++/*
++ * Ready/Busy structure: stores information related to Ready/Busy detection
++ *
++ * @type:	the Ready/Busy detection mode
++ * @info:	information related to the R/B detection mode. Either a gpio
++ *		id or a native R/B id (those supported by the NAND controller).
++ */
++struct sunxi_nand_rb {
++	enum sunxi_nand_rb_type type;
++	union {
++		int gpio;
++		int nativeid;
++	} info;
++};
++
++/*
++ * Chip Select structure: stores information related to NAND Chip Select
++ *
++ * @cs:		the NAND CS id used to communicate with a NAND Chip
++ * @rb:		the Ready/Busy description
++ */
++struct sunxi_nand_chip_sel {
++	u8 cs;
++	struct sunxi_nand_rb rb;
++};
++
++/*
++ * sunxi HW ECC infos: stores information related to HW ECC support
++ *
++ * @mode:	the sunxi ECC mode field deduced from ECC requirements
++ */
++struct sunxi_nand_hw_ecc {
++	int mode;
++};
++
++/*
++ * NAND chip structure: stores NAND chip device related information
++ *
++ * @node:		used to store NAND chips into a list
++ * @nand:		base NAND chip structure
++ * @mtd:		base MTD structure
++ * @clk_rate:		clk_rate required for this NAND chip
++ * @timing_cfg		TIMING_CFG register value for this NAND chip
++ * @selected:		current active CS
++ * @nsels:		number of CS lines required by the NAND chip
++ * @sels:		array of CS lines descriptions
++ */
++struct sunxi_nand_chip {
++	struct list_head node;
++	struct nand_chip nand;
++	unsigned long clk_rate;
++	u32 timing_cfg;
++	u32 timing_ctl;
++	int selected;
++	int addr_cycles;
++	u32 addr[2];
++	int cmd_cycles;
++	u8 cmd[2];
++	int nsels;
++	struct sunxi_nand_chip_sel sels[0];
++};
++
++static inline struct sunxi_nand_chip *to_sunxi_nand(struct nand_chip *nand)
++{
++	return container_of(nand, struct sunxi_nand_chip, nand);
++}
++
++/*
++ * NAND Controller structure: stores sunxi NAND controller information
++ *
++ * @controller:		base controller structure
++ * @dev:		parent device (used to print error messages)
++ * @regs:		NAND controller registers
++ * @ahb_clk:		NAND Controller AHB clock
++ * @mod_clk:		NAND Controller mod clock
++ * @assigned_cs:	bitmask describing already assigned CS lines
++ * @clk_rate:		NAND controller current clock rate
++ * @chips:		a list containing all the NAND chips attached to
++ *			this NAND controller
++ * @complete:		a completion object used to wait for NAND
++ *			controller events
++ */
++struct sunxi_nfc {
++	struct nand_hw_control controller;
++	struct device *dev;
++	void __iomem *regs;
++	struct clk *ahb_clk;
++	struct clk *mod_clk;
++	struct reset_control *reset;
++	unsigned long assigned_cs;
++	unsigned long clk_rate;
++	struct list_head chips;
++	struct completion complete;
++	struct dma_chan *dmac;
++};
++
++static inline struct sunxi_nfc *to_sunxi_nfc(struct nand_hw_control *ctrl)
++{
++	return container_of(ctrl, struct sunxi_nfc, controller);
++}
++
++static irqreturn_t sunxi_nfc_interrupt(int irq, void *dev_id)
++{
++	struct sunxi_nfc *nfc = dev_id;
++	u32 st = readl(nfc->regs + NFC_REG_ST);
++	u32 ien = readl(nfc->regs + NFC_REG_INT);
++
++	if (!(ien & st))
++		return IRQ_NONE;
++
++	if ((ien & st) == ien)
++		complete(&nfc->complete);
++
++	writel(st & NFC_INT_MASK, nfc->regs + NFC_REG_ST);
++	writel(~st & ien & NFC_INT_MASK, nfc->regs + NFC_REG_INT);
++
++	return IRQ_HANDLED;
++}
++
++static int sunxi_nfc_wait_events(struct sunxi_nfc *nfc, u32 events,
++				 bool use_polling, unsigned int timeout_ms)
++{
++	int ret;
++
++	if (events & ~NFC_INT_MASK)
++		return -EINVAL;
++
++	if (!timeout_ms)
++		timeout_ms = NFC_DEFAULT_TIMEOUT_MS;
++
++	if (!use_polling) {
++		init_completion(&nfc->complete);
++
++		writel(events, nfc->regs + NFC_REG_INT);
++
++		ret = wait_for_completion_timeout(&nfc->complete,
++						msecs_to_jiffies(timeout_ms));
++		if (!ret)
++			ret = -ETIMEDOUT;
++		else
++			ret = 0;
++
++		writel(0, nfc->regs + NFC_REG_INT);
++	} else {
++		u32 status;
++
++		ret = readl_poll_timeout(nfc->regs + NFC_REG_ST, status,
++					 (status & events) == events, 1,
++					 timeout_ms * 1000);
++	}
++
++	writel(events & NFC_INT_MASK, nfc->regs + NFC_REG_ST);
++
++	if (ret)
++		dev_err(nfc->dev, "wait interrupt timedout\n");
++
++	return ret;
++}
++
++static int sunxi_nfc_wait_cmd_fifo_empty(struct sunxi_nfc *nfc)
++{
++	u32 status;
++	int ret;
++
++	ret = readl_poll_timeout(nfc->regs + NFC_REG_ST, status,
++				 !(status & NFC_CMD_FIFO_STATUS), 1,
++				 NFC_DEFAULT_TIMEOUT_MS * 1000);
++	if (ret)
++		dev_err(nfc->dev, "wait for empty cmd FIFO timedout\n");
++
++	return ret;
++}
++
++static int sunxi_nfc_rst(struct sunxi_nfc *nfc)
++{
++	u32 ctl;
++	int ret;
++
++	writel(0, nfc->regs + NFC_REG_ECC_CTL);
++	writel(NFC_RESET, nfc->regs + NFC_REG_CTL);
++
++	ret = readl_poll_timeout(nfc->regs + NFC_REG_CTL, ctl,
++				 !(ctl & NFC_RESET), 1,
++				 NFC_DEFAULT_TIMEOUT_MS * 1000);
++	if (ret)
++		dev_err(nfc->dev, "wait for NAND controller reset timedout\n");
++
++	return ret;
++}
++
++static int sunxi_nfc_dma_op_prepare(struct mtd_info *mtd, const void *buf,
++				    int chunksize, int nchunks,
++				    enum dma_data_direction ddir,
++				    struct scatterlist *sg)
++{
++	struct nand_chip *nand = mtd_to_nand(mtd);
++	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
++	struct dma_async_tx_descriptor *dmad;
++	enum dma_transfer_direction tdir;
++	dma_cookie_t dmat;
++	int ret;
++
++	if (ddir == DMA_FROM_DEVICE)
++		tdir = DMA_DEV_TO_MEM;
++	else
++		tdir = DMA_MEM_TO_DEV;
++
++	sg_init_one(sg, buf, nchunks * chunksize);
++	ret = dma_map_sg(nfc->dev, sg, 1, ddir);
++	if (!ret)
++		return -ENOMEM;
++
++	dmad = dmaengine_prep_slave_sg(nfc->dmac, sg, 1, tdir, DMA_CTRL_ACK);
++	if (!dmad) {
++		ret = -EINVAL;
++		goto err_unmap_buf;
++	}
++
++	writel(readl(nfc->regs + NFC_REG_CTL) | NFC_RAM_METHOD,
++	       nfc->regs + NFC_REG_CTL);
++	writel(nchunks, nfc->regs + NFC_REG_SECTOR_NUM);
++	writel(chunksize, nfc->regs + NFC_REG_CNT);
++	dmat = dmaengine_submit(dmad);
++
++	ret = dma_submit_error(dmat);
++	if (ret)
++		goto err_clr_dma_flag;
++
++	return 0;
++
++err_clr_dma_flag:
++	writel(readl(nfc->regs + NFC_REG_CTL) & ~NFC_RAM_METHOD,
++	       nfc->regs + NFC_REG_CTL);
++
++err_unmap_buf:
++	dma_unmap_sg(nfc->dev, sg, 1, ddir);
++	return ret;
++}
++
++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 sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
++
++	dma_unmap_sg(nfc->dev, sg, 1, ddir);
++	writel(readl(nfc->regs + NFC_REG_CTL) & ~NFC_RAM_METHOD,
++	       nfc->regs + NFC_REG_CTL);
++}
++
++static int sunxi_nfc_dev_ready(struct mtd_info *mtd)
++{
++	struct nand_chip *nand = mtd_to_nand(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;
++	int ret;
++
++	if (sunxi_nand->selected < 0)
++		return 0;
++
++	rb = &sunxi_nand->sels[sunxi_nand->selected].rb;
++
++	switch (rb->type) {
++	case RB_NATIVE:
++		ret = !!(readl(nfc->regs + NFC_REG_ST) &
++			 NFC_RB_STATE(rb->info.nativeid));
++		break;
++	case RB_GPIO:
++		ret = gpio_get_value(rb->info.gpio);
++		break;
++	case RB_NONE:
++	default:
++		ret = 0;
++		dev_err(nfc->dev, "cannot check R/B NAND status!\n");
++		break;
++	}
++
++	return ret;
++}
++
++static void sunxi_nfc_select_chip(struct mtd_info *mtd, int chip)
++{
++	struct nand_chip *nand = mtd_to_nand(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;
++	u32 ctl;
++
++	if (chip > 0 && chip >= sunxi_nand->nsels)
++		return;
++
++	if (chip == sunxi_nand->selected)
++		return;
++
++	ctl = readl(nfc->regs + NFC_REG_CTL) &
++	      ~(NFC_PAGE_SHIFT_MSK | NFC_CE_SEL_MSK | NFC_RB_SEL_MSK | NFC_EN);
++
++	if (chip >= 0) {
++		sel = &sunxi_nand->sels[chip];
++
++		ctl |= NFC_CE_SEL(sel->cs) | NFC_EN |
++		       NFC_PAGE_SHIFT(nand->page_shift);
++		if (sel->rb.type == RB_NONE) {
++			nand->dev_ready = NULL;
++		} else {
++			nand->dev_ready = sunxi_nfc_dev_ready;
++			if (sel->rb.type == RB_NATIVE)
++				ctl |= NFC_RB_SEL(sel->rb.info.nativeid);
++		}
++
++		writel(mtd->writesize, nfc->regs + NFC_REG_SPARE_AREA);
++
++		if (nfc->clk_rate != sunxi_nand->clk_rate) {
++			clk_set_rate(nfc->mod_clk, sunxi_nand->clk_rate);
++			nfc->clk_rate = sunxi_nand->clk_rate;
++		}
++	}
++
++	writel(sunxi_nand->timing_ctl, nfc->regs + NFC_REG_TIMING_CTL);
++	writel(sunxi_nand->timing_cfg, nfc->regs + NFC_REG_TIMING_CFG);
++	writel(ctl, nfc->regs + NFC_REG_CTL);
++
++	sunxi_nand->selected = 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 sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
++	struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
++	int ret;
++	int cnt;
++	int offs = 0;
++	u32 tmp;
++
++	while (len > offs) {
++		bool poll = false;
++
++		cnt = min(len - offs, NFC_SRAM_SIZE);
++
++		ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
++		if (ret)
++			break;
++
++		writel(cnt, nfc->regs + NFC_REG_CNT);
++		tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD;
++		writel(tmp, nfc->regs + NFC_REG_CMD);
++
++		/* Arbitrary limit for polling mode */
++		if (cnt < 64)
++			poll = true;
++
++		ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, poll, 0);
++		if (ret)
++			break;
++
++		if (buf)
++			memcpy_fromio(buf + offs, nfc->regs + NFC_RAM0_BASE,
++				      cnt);
++		offs += cnt;
++	}
++}
++
++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 sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
++	struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
++	int ret;
++	int cnt;
++	int offs = 0;
++	u32 tmp;
++
++	while (len > offs) {
++		bool poll = false;
++
++		cnt = min(len - offs, NFC_SRAM_SIZE);
++
++		ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
++		if (ret)
++			break;
++
++		writel(cnt, nfc->regs + NFC_REG_CNT);
++		memcpy_toio(nfc->regs + NFC_RAM0_BASE, buf + offs, cnt);
++		tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD |
++		      NFC_ACCESS_DIR;
++		writel(tmp, nfc->regs + NFC_REG_CMD);
++
++		/* Arbitrary limit for polling mode */
++		if (cnt < 64)
++			poll = true;
++
++		ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, poll, 0);
++		if (ret)
++			break;
++
++		offs += cnt;
++	}
++}
++
++static uint8_t sunxi_nfc_read_byte(struct mtd_info *mtd)
++{
++	uint8_t ret;
++
++	sunxi_nfc_read_buf(mtd, &ret, 1);
++
++	return ret;
++}
++
++static void sunxi_nfc_cmd_ctrl(struct mtd_info *mtd, int dat,
++			       unsigned int ctrl)
++{
++	struct nand_chip *nand = mtd_to_nand(mtd);
++	struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
++	struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
++	int ret;
++
++	if (dat == NAND_CMD_NONE && (ctrl & NAND_NCE) &&
++	    !(ctrl & (NAND_CLE | NAND_ALE))) {
++		u32 cmd = 0;
++
++		if (!sunxi_nand->addr_cycles && !sunxi_nand->cmd_cycles)
++			return;
++
++		if (sunxi_nand->cmd_cycles--)
++			cmd |= NFC_SEND_CMD1 | sunxi_nand->cmd[0];
++
++		if (sunxi_nand->cmd_cycles--) {
++			cmd |= NFC_SEND_CMD2;
++			writel(sunxi_nand->cmd[1],
++			       nfc->regs + NFC_REG_RCMD_SET);
++		}
++
++		sunxi_nand->cmd_cycles = 0;
++
++		if (sunxi_nand->addr_cycles) {
++			cmd |= NFC_SEND_ADR |
++			       NFC_ADR_NUM(sunxi_nand->addr_cycles);
++			writel(sunxi_nand->addr[0],
++			       nfc->regs + NFC_REG_ADDR_LOW);
++		}
++
++		if (sunxi_nand->addr_cycles > 4)
++			writel(sunxi_nand->addr[1],
++			       nfc->regs + NFC_REG_ADDR_HIGH);
++
++		ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
++		if (ret)
++			return;
++
++		writel(cmd, nfc->regs + NFC_REG_CMD);
++		sunxi_nand->addr[0] = 0;
++		sunxi_nand->addr[1] = 0;
++		sunxi_nand->addr_cycles = 0;
++		sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, true, 0);
++	}
++
++	if (ctrl & NAND_CLE) {
++		sunxi_nand->cmd[sunxi_nand->cmd_cycles++] = dat;
++	} else if (ctrl & NAND_ALE) {
++		sunxi_nand->addr[sunxi_nand->addr_cycles / 4] |=
++				dat << ((sunxi_nand->addr_cycles % 4) * 8);
++		sunxi_nand->addr_cycles++;
++	}
++}
++
++/* These seed values have been extracted from Allwinner's BSP */
++static const u16 sunxi_nfc_randomizer_page_seeds[] = {
++	0x2b75, 0x0bd0, 0x5ca3, 0x62d1, 0x1c93, 0x07e9, 0x2162, 0x3a72,
++	0x0d67, 0x67f9, 0x1be7, 0x077d, 0x032f, 0x0dac, 0x2716, 0x2436,
++	0x7922, 0x1510, 0x3860, 0x5287, 0x480f, 0x4252, 0x1789, 0x5a2d,
++	0x2a49, 0x5e10, 0x437f, 0x4b4e, 0x2f45, 0x216e, 0x5cb7, 0x7130,
++	0x2a3f, 0x60e4, 0x4dc9, 0x0ef0, 0x0f52, 0x1bb9, 0x6211, 0x7a56,
++	0x226d, 0x4ea7, 0x6f36, 0x3692, 0x38bf, 0x0c62, 0x05eb, 0x4c55,
++	0x60f4, 0x728c, 0x3b6f, 0x2037, 0x7f69, 0x0936, 0x651a, 0x4ceb,
++	0x6218, 0x79f3, 0x383f, 0x18d9, 0x4f05, 0x5c82, 0x2912, 0x6f17,
++	0x6856, 0x5938, 0x1007, 0x61ab, 0x3e7f, 0x57c2, 0x542f, 0x4f62,
++	0x7454, 0x2eac, 0x7739, 0x42d4, 0x2f90, 0x435a, 0x2e52, 0x2064,
++	0x637c, 0x66ad, 0x2c90, 0x0bad, 0x759c, 0x0029, 0x0986, 0x7126,
++	0x1ca7, 0x1605, 0x386a, 0x27f5, 0x1380, 0x6d75, 0x24c3, 0x0f8e,
++	0x2b7a, 0x1418, 0x1fd1, 0x7dc1, 0x2d8e, 0x43af, 0x2267, 0x7da3,
++	0x4e3d, 0x1338, 0x50db, 0x454d, 0x764d, 0x40a3, 0x42e6, 0x262b,
++	0x2d2e, 0x1aea, 0x2e17, 0x173d, 0x3a6e, 0x71bf, 0x25f9, 0x0a5d,
++	0x7c57, 0x0fbe, 0x46ce, 0x4939, 0x6b17, 0x37bb, 0x3e91, 0x76db,
++};
++
++/*
++ * sunxi_nfc_randomizer_ecc512_seeds and sunxi_nfc_randomizer_ecc1024_seeds
++ * have been generated using
++ * sunxi_nfc_randomizer_step(seed, (step_size * 8) + 15), which is what
++ * the randomizer engine does internally before de/scrambling OOB data.
++ *
++ * Those tables are statically defined to avoid calculating randomizer state
++ * at runtime.
++ */
++static const u16 sunxi_nfc_randomizer_ecc512_seeds[] = {
++	0x3346, 0x367f, 0x1f18, 0x769a, 0x4f64, 0x068c, 0x2ef1, 0x6b64,
++	0x28a9, 0x15d7, 0x30f8, 0x3659, 0x53db, 0x7c5f, 0x71d4, 0x4409,
++	0x26eb, 0x03cc, 0x655d, 0x47d4, 0x4daa, 0x0877, 0x712d, 0x3617,
++	0x3264, 0x49aa, 0x7f9e, 0x588e, 0x4fbc, 0x7176, 0x7f91, 0x6c6d,
++	0x4b95, 0x5fb7, 0x3844, 0x4037, 0x0184, 0x081b, 0x0ee8, 0x5b91,
++	0x293d, 0x1f71, 0x0e6f, 0x402b, 0x5122, 0x1e52, 0x22be, 0x3d2d,
++	0x75bc, 0x7c60, 0x6291, 0x1a2f, 0x61d4, 0x74aa, 0x4140, 0x29ab,
++	0x472d, 0x2852, 0x017e, 0x15e8, 0x5ec2, 0x17cf, 0x7d0f, 0x06b8,
++	0x117a, 0x6b94, 0x789b, 0x3126, 0x6ac5, 0x5be7, 0x150f, 0x51f8,
++	0x7889, 0x0aa5, 0x663d, 0x77e8, 0x0b87, 0x3dcb, 0x360d, 0x218b,
++	0x512f, 0x7dc9, 0x6a4d, 0x630a, 0x3547, 0x1dd2, 0x5aea, 0x69a5,
++	0x7bfa, 0x5e4f, 0x1519, 0x6430, 0x3a0e, 0x5eb3, 0x5425, 0x0c7a,
++	0x5540, 0x3670, 0x63c1, 0x31e9, 0x5a39, 0x2de7, 0x5979, 0x2891,
++	0x1562, 0x014b, 0x5b05, 0x2756, 0x5a34, 0x13aa, 0x6cb5, 0x2c36,
++	0x5e72, 0x1306, 0x0861, 0x15ef, 0x1ee8, 0x5a37, 0x7ac4, 0x45dd,
++	0x44c4, 0x7266, 0x2f41, 0x3ccc, 0x045e, 0x7d40, 0x7c66, 0x0fa0,
++};
++
++static const u16 sunxi_nfc_randomizer_ecc1024_seeds[] = {
++	0x2cf5, 0x35f1, 0x63a4, 0x5274, 0x2bd2, 0x778b, 0x7285, 0x32b6,
++	0x6a5c, 0x70d6, 0x757d, 0x6769, 0x5375, 0x1e81, 0x0cf3, 0x3982,
++	0x6787, 0x042a, 0x6c49, 0x1925, 0x56a8, 0x40a9, 0x063e, 0x7bd9,
++	0x4dbf, 0x55ec, 0x672e, 0x7334, 0x5185, 0x4d00, 0x232a, 0x7e07,
++	0x445d, 0x6b92, 0x528f, 0x4255, 0x53ba, 0x7d82, 0x2a2e, 0x3a4e,
++	0x75eb, 0x450c, 0x6844, 0x1b5d, 0x581a, 0x4cc6, 0x0379, 0x37b2,
++	0x419f, 0x0e92, 0x6b27, 0x5624, 0x01e3, 0x07c1, 0x44a5, 0x130c,
++	0x13e8, 0x5910, 0x0876, 0x60c5, 0x54e3, 0x5b7f, 0x2269, 0x509f,
++	0x7665, 0x36fd, 0x3e9a, 0x0579, 0x6295, 0x14ef, 0x0a81, 0x1bcc,
++	0x4b16, 0x64db, 0x0514, 0x4f07, 0x0591, 0x3576, 0x6853, 0x0d9e,
++	0x259f, 0x38b7, 0x64fb, 0x3094, 0x4693, 0x6ddd, 0x29bb, 0x0bc8,
++	0x3f47, 0x490e, 0x0c0e, 0x7933, 0x3c9e, 0x5840, 0x398d, 0x3e68,
++	0x4af1, 0x71f5, 0x57cf, 0x1121, 0x64eb, 0x3579, 0x15ac, 0x584d,
++	0x5f2a, 0x47e2, 0x6528, 0x6eac, 0x196e, 0x6b96, 0x0450, 0x0179,
++	0x609c, 0x06e1, 0x4626, 0x42c7, 0x273e, 0x486f, 0x0705, 0x1601,
++	0x145b, 0x407e, 0x062b, 0x57a5, 0x53f9, 0x5659, 0x4410, 0x3ccd,
++};
++
++static u16 sunxi_nfc_randomizer_step(u16 state, int count)
++{
++	state &= 0x7fff;
++
++	/*
++	 * This loop is just a simple implementation of a Fibonacci LFSR using
++	 * the x16 + x15 + 1 polynomial.
++	 */
++	while (count--)
++		state = ((state >> 1) |
++			 (((state ^ (state >> 1)) & 1) << 14)) & 0x7fff;
++
++	return state;
++}
++
++static u16 sunxi_nfc_randomizer_state(struct mtd_info *mtd, int page, bool ecc)
++{
++	const u16 *seeds = sunxi_nfc_randomizer_page_seeds;
++	int mod = mtd_div_by_ws(mtd->erasesize, mtd);
++
++	if (mod > ARRAY_SIZE(sunxi_nfc_randomizer_page_seeds))
++		mod = ARRAY_SIZE(sunxi_nfc_randomizer_page_seeds);
++
++	if (ecc) {
++		if (mtd->ecc_step_size == 512)
++			seeds = sunxi_nfc_randomizer_ecc512_seeds;
++		else
++			seeds = sunxi_nfc_randomizer_ecc1024_seeds;
++	}
++
++	return seeds[page % mod];
++}
++
++static void sunxi_nfc_randomizer_config(struct mtd_info *mtd,
++					int page, bool ecc)
++{
++	struct nand_chip *nand = mtd_to_nand(mtd);
++	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
++	u32 ecc_ctl = readl(nfc->regs + NFC_REG_ECC_CTL);
++	u16 state;
++
++	if (!(nand->options & NAND_NEED_SCRAMBLING))
++		return;
++
++	ecc_ctl = readl(nfc->regs + NFC_REG_ECC_CTL);
++	state = sunxi_nfc_randomizer_state(mtd, page, ecc);
++	ecc_ctl = readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_RANDOM_SEED_MSK;
++	writel(ecc_ctl | NFC_RANDOM_SEED(state), nfc->regs + NFC_REG_ECC_CTL);
++}
++
++static void sunxi_nfc_randomizer_enable(struct mtd_info *mtd)
++{
++	struct nand_chip *nand = mtd_to_nand(mtd);
++	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
++
++	if (!(nand->options & NAND_NEED_SCRAMBLING))
++		return;
++
++	writel(readl(nfc->regs + NFC_REG_ECC_CTL) | NFC_RANDOM_EN,
++	       nfc->regs + NFC_REG_ECC_CTL);
++}
++
++static void sunxi_nfc_randomizer_disable(struct mtd_info *mtd)
++{
++	struct nand_chip *nand = mtd_to_nand(mtd);
++	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
++
++	if (!(nand->options & NAND_NEED_SCRAMBLING))
++		return;
++
++	writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_RANDOM_EN,
++	       nfc->regs + NFC_REG_ECC_CTL);
++}
++
++static void sunxi_nfc_randomize_bbm(struct mtd_info *mtd, int page, u8 *bbm)
++{
++	u16 state = sunxi_nfc_randomizer_state(mtd, page, true);
++
++	bbm[0] ^= state;
++	bbm[1] ^= sunxi_nfc_randomizer_step(state, 8);
++}
++
++static void sunxi_nfc_randomizer_write_buf(struct mtd_info *mtd,
++					   const uint8_t *buf, int len,
++					   bool ecc, int page)
++{
++	sunxi_nfc_randomizer_config(mtd, page, ecc);
++	sunxi_nfc_randomizer_enable(mtd);
++	sunxi_nfc_write_buf(mtd, buf, len);
++	sunxi_nfc_randomizer_disable(mtd);
++}
++
++static void sunxi_nfc_randomizer_read_buf(struct mtd_info *mtd, uint8_t *buf,
++					  int len, bool ecc, int page)
++{
++	sunxi_nfc_randomizer_config(mtd, page, ecc);
++	sunxi_nfc_randomizer_enable(mtd);
++	sunxi_nfc_read_buf(mtd, buf, len);
++	sunxi_nfc_randomizer_disable(mtd);
++}
++
++static void sunxi_nfc_hw_ecc_enable(struct mtd_info *mtd)
++{
++	struct nand_chip *nand = mtd_to_nand(mtd);
++	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
++	struct sunxi_nand_hw_ecc *data = nand->ecc.priv;
++	u32 ecc_ctl;
++
++	ecc_ctl = readl(nfc->regs + NFC_REG_ECC_CTL);
++	ecc_ctl &= ~(NFC_ECC_MODE_MSK | NFC_ECC_PIPELINE |
++		     NFC_ECC_BLOCK_SIZE_MSK);
++	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);
++}
++
++static void sunxi_nfc_hw_ecc_disable(struct mtd_info *mtd)
++{
++	struct nand_chip *nand = mtd_to_nand(mtd);
++	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
++
++	writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_ECC_EN,
++	       nfc->regs + NFC_REG_ECC_CTL);
++}
++
++static inline void sunxi_nfc_user_data_to_buf(u32 user_data, u8 *buf)
++{
++	buf[0] = user_data;
++	buf[1] = user_data >> 8;
++	buf[2] = user_data >> 16;
++	buf[3] = user_data >> 24;
++}
++
++static inline u32 sunxi_nfc_buf_to_user_data(const u8 *buf)
++{
++	return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
++}
++
++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 sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
++
++	sunxi_nfc_user_data_to_buf(readl(nfc->regs + NFC_REG_USER_DATA(step)),
++				   oob);
++
++	/* De-randomize the Bad Block Marker. */
++	if (bbm && (nand->options & NAND_NEED_SCRAMBLING))
++		sunxi_nfc_randomize_bbm(mtd, page, oob);
++}
++
++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 sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
++	u8 user_data[4];
++
++	/* Randomize the Bad Block Marker. */
++	if (bbm && (nand->options & NAND_NEED_SCRAMBLING)) {
++		memcpy(user_data, oob, sizeof(user_data));
++		sunxi_nfc_randomize_bbm(mtd, page, user_data);
++		oob = user_data;
++	}
++
++	writel(sunxi_nfc_buf_to_user_data(oob),
++	       nfc->regs + NFC_REG_USER_DATA(step));
++}
++
++static void sunxi_nfc_hw_ecc_update_stats(struct mtd_info *mtd,
++					  unsigned int *max_bitflips, int ret)
++{
++	if (ret < 0) {
++		mtd->ecc_stats.failed++;
++	} else {
++		mtd->ecc_stats.corrected += ret;
++		*max_bitflips = max_t(unsigned int, *max_bitflips, ret);
++	}
++}
++
++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 sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
++	struct nand_ecc_ctrl *ecc = &nand->ecc;
++	u32 tmp;
++
++	*erased = false;
++
++	if (status & NFC_ECC_ERR(step))
++		return -EBADMSG;
++
++	if (status & NFC_ECC_PAT_FOUND(step)) {
++		u8 pattern;
++
++		if (unlikely(!(readl(nfc->regs + NFC_REG_PAT_ID) & 0x1))) {
++			pattern = 0x0;
++		} else {
++			pattern = 0xff;
++			*erased = true;
++		}
++
++		if (data)
++			memset(data, pattern, ecc->size);
++
++		if (oob)
++			memset(oob, pattern, ecc->bytes + 4);
++
++		return 0;
++	}
++
++	tmp = readl(nfc->regs + NFC_REG_ECC_ERR_CNT(step));
++
++	return NFC_ECC_ERR_CNT(step, tmp);
++}
++
++static int sunxi_nfc_hw_ecc_read_chunk(struct mtd_info *mtd,
++				       u8 *data, int data_off,
++				       u8 *oob, int oob_off,
++				       int *cur_off,
++				       unsigned int *max_bitflips,
++				       bool bbm, bool oob_required, int page)
++{
++	struct nand_chip *nand = mtd_to_nand(mtd);
++	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
++	struct nand_ecc_ctrl *ecc = &nand->ecc;
++	int raw_mode = 0;
++	bool erased;
++	int ret;
++
++	if (*cur_off != data_off)
++		nand->cmdfunc(mtd, NAND_CMD_RNDOUT, data_off, -1);
++
++	sunxi_nfc_randomizer_read_buf(mtd, NULL, ecc->size, false, page);
++
++	if (data_off + ecc->size != oob_off)
++		nand->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_off, -1);
++
++	ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
++	if (ret)
++		return ret;
++
++	sunxi_nfc_randomizer_enable(mtd);
++	writel(NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | NFC_ECC_OP,
++	       nfc->regs + NFC_REG_CMD);
++
++	ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, false, 0);
++	sunxi_nfc_randomizer_disable(mtd);
++	if (ret)
++		return ret;
++
++	*cur_off = oob_off + ecc->bytes + 4;
++
++	ret = sunxi_nfc_hw_ecc_correct(mtd, data, oob_required ? oob : NULL, 0,
++				       readl(nfc->regs + NFC_REG_ECC_ST),
++				       &erased);
++	if (erased)
++		return 1;
++
++	if (ret < 0) {
++		/*
++		 * Re-read the data with the randomizer disabled to identify
++		 * bitflips in erased pages.
++		 */
++		if (nand->options & NAND_NEED_SCRAMBLING) {
++			nand->cmdfunc(mtd, NAND_CMD_RNDOUT, data_off, -1);
++			nand->read_buf(mtd, data, ecc->size);
++		} else {
++			memcpy_fromio(data, nfc->regs + NFC_RAM0_BASE,
++				      ecc->size);
++		}
++
++		nand->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_off, -1);
++		nand->read_buf(mtd, oob, ecc->bytes + 4);
++
++		ret = nand_check_erased_ecc_chunk(data,	ecc->size,
++						  oob, ecc->bytes + 4,
++						  NULL, 0, ecc->strength);
++		if (ret >= 0)
++			raw_mode = 1;
++	} else {
++		memcpy_fromio(data, nfc->regs + NFC_RAM0_BASE, ecc->size);
++
++		if (oob_required) {
++			nand->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_off, -1);
++			sunxi_nfc_randomizer_read_buf(mtd, oob, ecc->bytes + 4,
++						      true, page);
++
++			sunxi_nfc_hw_ecc_get_prot_oob_bytes(mtd, oob, 0,
++							    bbm, page);
++		}
++	}
++
++	sunxi_nfc_hw_ecc_update_stats(mtd, max_bitflips, ret);
++
++	return raw_mode;
++}
++
++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_ecc_ctrl *ecc = &nand->ecc;
++	int offset = ((ecc->bytes + 4) * ecc->steps);
++	int len = mtd->oobsize - offset;
++
++	if (len <= 0)
++		return;
++
++	if (!cur_off || *cur_off != offset)
++		nand->cmdfunc(mtd, NAND_CMD_RNDOUT,
++			      offset + mtd->writesize, -1);
++
++	if (!randomize)
++		sunxi_nfc_read_buf(mtd, oob + offset, len);
++	else
++		sunxi_nfc_randomizer_read_buf(mtd, oob + offset, len,
++					      false, page);
++
++	if (cur_off)
++		*cur_off = mtd->oobsize + mtd->writesize;
++}
++
++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);
++	bool randomized = nand->options & NAND_NEED_SCRAMBLING;
++	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
++	struct nand_ecc_ctrl *ecc = &nand->ecc;
++	unsigned int max_bitflips = 0;
++	int ret, i, raw_mode = 0;
++	struct scatterlist sg;
++	u32 status;
++
++	ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
++	if (ret)
++		return ret;
++
++	ret = sunxi_nfc_dma_op_prepare(mtd, buf, ecc->size, nchunks,
++				       DMA_FROM_DEVICE, &sg);
++	if (ret)
++		return ret;
++
++	sunxi_nfc_hw_ecc_enable(mtd);
++	sunxi_nfc_randomizer_config(mtd, page, false);
++	sunxi_nfc_randomizer_enable(mtd);
++
++	writel((NAND_CMD_RNDOUTSTART << 16) | (NAND_CMD_RNDOUT << 8) |
++	       NAND_CMD_READSTART, nfc->regs + NFC_REG_RCMD_SET);
++
++	dma_async_issue_pending(nfc->dmac);
++
++	writel(NFC_PAGE_OP | NFC_DATA_SWAP_METHOD | NFC_DATA_TRANS,
++	       nfc->regs + NFC_REG_CMD);
++
++	ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, false, 0);
++	if (ret)
++		dmaengine_terminate_all(nfc->dmac);
++
++	sunxi_nfc_randomizer_disable(mtd);
++	sunxi_nfc_hw_ecc_disable(mtd);
++
++	sunxi_nfc_dma_op_cleanup(mtd, DMA_FROM_DEVICE, &sg);
++
++	if (ret)
++		return ret;
++
++	status = readl(nfc->regs + NFC_REG_ECC_ST);
++
++	for (i = 0; i < nchunks; i++) {
++		int data_off = i * ecc->size;
++		int oob_off = i * (ecc->bytes + 4);
++		u8 *data = buf + data_off;
++		u8 *oob = nand->oob_poi + oob_off;
++		bool erased;
++
++		ret = sunxi_nfc_hw_ecc_correct(mtd, randomized ? data : NULL,
++					       oob_required ? oob : NULL,
++					       i, status, &erased);
++
++		/* ECC errors are handled in the second loop. */
++		if (ret < 0)
++			continue;
++
++		if (oob_required && !erased) {
++			/* TODO: use DMA to retrieve OOB */
++			nand->cmdfunc(mtd, NAND_CMD_RNDOUT,
++				      mtd->writesize + oob_off, -1);
++			nand->read_buf(mtd, oob, ecc->bytes + 4);
++
++			sunxi_nfc_hw_ecc_get_prot_oob_bytes(mtd, oob, i,
++							    !i, page);
++		}
++
++		if (erased)
++			raw_mode = 1;
++
++		sunxi_nfc_hw_ecc_update_stats(mtd, &max_bitflips, ret);
++	}
++
++	if (status & NFC_ECC_ERR_MSK) {
++		for (i = 0; i < nchunks; i++) {
++			int data_off = i * ecc->size;
++			int oob_off = i * (ecc->bytes + 4);
++			u8 *data = buf + data_off;
++			u8 *oob = nand->oob_poi + oob_off;
++
++			if (!(status & NFC_ECC_ERR(i)))
++				continue;
++
++			/*
++			 * Re-read the data with the randomizer disabled to
++			 * identify bitflips in erased pages.
++			 */
++			if (randomized) {
++				/* TODO: use DMA to read page in raw mode */
++				nand->cmdfunc(mtd, NAND_CMD_RNDOUT,
++					      data_off, -1);
++				nand->read_buf(mtd, data, ecc->size);
++			}
++
++			/* TODO: use DMA to retrieve OOB */
++			nand->cmdfunc(mtd, NAND_CMD_RNDOUT,
++				      mtd->writesize + oob_off, -1);
++			nand->read_buf(mtd, oob, ecc->bytes + 4);
++
++			ret = nand_check_erased_ecc_chunk(data,	ecc->size,
++							  oob, ecc->bytes + 4,
++							  NULL, 0,
++							  ecc->strength);
++			if (ret >= 0)
++				raw_mode = 1;
++
++			sunxi_nfc_hw_ecc_update_stats(mtd, &max_bitflips, ret);
++		}
++	}
++
++	if (oob_required)
++		sunxi_nfc_hw_ecc_read_extra_oob(mtd, nand->oob_poi,
++						NULL, !raw_mode,
++						page);
++
++	return max_bitflips;
++}
++
++static int sunxi_nfc_hw_ecc_write_chunk(struct mtd_info *mtd,
++					const u8 *data, int data_off,
++					const u8 *oob, int oob_off,
++					int *cur_off, bool bbm,
++					int page)
++{
++	struct nand_chip *nand = mtd_to_nand(mtd);
++	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
++	struct nand_ecc_ctrl *ecc = &nand->ecc;
++	int ret;
++
++	if (data_off != *cur_off)
++		nand->cmdfunc(mtd, NAND_CMD_RNDIN, data_off, -1);
++
++	sunxi_nfc_randomizer_write_buf(mtd, data, ecc->size, false, page);
++
++	if (data_off + ecc->size != oob_off)
++		nand->cmdfunc(mtd, NAND_CMD_RNDIN, oob_off, -1);
++
++	ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
++	if (ret)
++		return ret;
++
++	sunxi_nfc_randomizer_enable(mtd);
++	sunxi_nfc_hw_ecc_set_prot_oob_bytes(mtd, oob, 0, bbm, page);
++
++	writel(NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD |
++	       NFC_ACCESS_DIR | NFC_ECC_OP,
++	       nfc->regs + NFC_REG_CMD);
++
++	ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, false, 0);
++	sunxi_nfc_randomizer_disable(mtd);
++	if (ret)
++		return ret;
++
++	*cur_off = oob_off + ecc->bytes + 4;
++
++	return 0;
++}
++
++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_ecc_ctrl *ecc = &nand->ecc;
++	int offset = ((ecc->bytes + 4) * ecc->steps);
++	int len = mtd->oobsize - offset;
++
++	if (len <= 0)
++		return;
++
++	if (!cur_off || *cur_off != offset)
++		nand->cmdfunc(mtd, NAND_CMD_RNDIN,
++			      offset + mtd->writesize, -1);
++
++	sunxi_nfc_randomizer_write_buf(mtd, oob + offset, len, false, page);
++
++	if (cur_off)
++		*cur_off = mtd->oobsize + mtd->writesize;
++}
++
++static int sunxi_nfc_hw_ecc_read_page(struct mtd_info *mtd,
++				      struct nand_chip *chip, uint8_t *buf,
++				      int oob_required, int page)
++{
++	struct nand_ecc_ctrl *ecc = &chip->ecc;
++	unsigned int max_bitflips = 0;
++	int ret, i, cur_off = 0;
++	bool raw_mode = false;
++
++	sunxi_nfc_hw_ecc_enable(mtd);
++
++	for (i = 0; i < ecc->steps; i++) {
++		int data_off = i * ecc->size;
++		int oob_off = i * (ecc->bytes + 4);
++		u8 *data = buf + data_off;
++		u8 *oob = chip->oob_poi + oob_off;
++
++		ret = sunxi_nfc_hw_ecc_read_chunk(mtd, data, data_off, oob,
++						  oob_off + mtd->writesize,
++						  &cur_off, &max_bitflips,
++						  !i, oob_required, page);
++		if (ret < 0)
++			return ret;
++		else if (ret)
++			raw_mode = true;
++	}
++
++	if (oob_required)
++		sunxi_nfc_hw_ecc_read_extra_oob(mtd, chip->oob_poi, &cur_off,
++						!raw_mode, page);
++
++	sunxi_nfc_hw_ecc_disable(mtd);
++
++	return max_bitflips;
++}
++
++static int sunxi_nfc_hw_ecc_read_page_dma(struct mtd_info *mtd,
++					  struct nand_chip *chip, u8 *buf,
++					  int oob_required, int page)
++{
++	int ret;
++
++	ret = sunxi_nfc_hw_ecc_read_chunks_dma(mtd, buf, oob_required, page,
++					       chip->ecc.steps);
++	if (ret >= 0)
++		return ret;
++
++	/* Fallback to PIO mode */
++	chip->cmdfunc(mtd, NAND_CMD_RNDOUT, 0, -1);
++
++	return sunxi_nfc_hw_ecc_read_page(mtd, chip, buf, oob_required, page);
++}
++
++static int sunxi_nfc_hw_ecc_read_subpage(struct mtd_info *mtd,
++					 struct nand_chip *chip,
++					 u32 data_offs, u32 readlen,
++					 u8 *bufpoi, int page)
++{
++	struct nand_ecc_ctrl *ecc = &chip->ecc;
++	int ret, i, cur_off = 0;
++	unsigned int max_bitflips = 0;
++
++	sunxi_nfc_hw_ecc_enable(mtd);
++
++	for (i = data_offs / ecc->size;
++	     i < DIV_ROUND_UP(data_offs + readlen, ecc->size); i++) {
++		int data_off = i * ecc->size;
++		int oob_off = i * (ecc->bytes + 4);
++		u8 *data = bufpoi + data_off;
++		u8 *oob = chip->oob_poi + oob_off;
++
++		ret = sunxi_nfc_hw_ecc_read_chunk(mtd, data, data_off,
++						  oob,
++						  oob_off + mtd->writesize,
++						  &cur_off, &max_bitflips, !i,
++						  false, page);
++		if (ret < 0)
++			return ret;
++	}
++
++	sunxi_nfc_hw_ecc_disable(mtd);
++
++	return max_bitflips;
++}
++
++static int sunxi_nfc_hw_ecc_read_subpage_dma(struct mtd_info *mtd,
++					     struct nand_chip *chip,
++					     u32 data_offs, u32 readlen,
++					     u8 *buf, int page)
++{
++	int nchunks = DIV_ROUND_UP(data_offs + readlen, chip->ecc.size);
++	int ret;
++
++	ret = sunxi_nfc_hw_ecc_read_chunks_dma(mtd, buf, false, page, nchunks);
++	if (ret >= 0)
++		return ret;
++
++	/* Fallback to PIO mode */
++	chip->cmdfunc(mtd, NAND_CMD_RNDOUT, 0, -1);
++
++	return sunxi_nfc_hw_ecc_read_subpage(mtd, chip, data_offs, readlen,
++					     buf, page);
++}
++
++static int sunxi_nfc_hw_ecc_write_page(struct mtd_info *mtd,
++				       struct nand_chip *chip,
++				       const uint8_t *buf, int oob_required,
++				       int page)
++{
++	struct nand_ecc_ctrl *ecc = &chip->ecc;
++	int ret, i, cur_off = 0;
++
++	sunxi_nfc_hw_ecc_enable(mtd);
++
++	for (i = 0; i < ecc->steps; i++) {
++		int data_off = i * ecc->size;
++		int oob_off = i * (ecc->bytes + 4);
++		const u8 *data = buf + data_off;
++		const u8 *oob = chip->oob_poi + oob_off;
++
++		ret = sunxi_nfc_hw_ecc_write_chunk(mtd, data, data_off, oob,
++						   oob_off + mtd->writesize,
++						   &cur_off, !i, page);
++		if (ret)
++			return ret;
++	}
++
++	if (oob_required || (chip->options & NAND_NEED_SCRAMBLING))
++		sunxi_nfc_hw_ecc_write_extra_oob(mtd, chip->oob_poi,
++						 &cur_off, page);
++
++	sunxi_nfc_hw_ecc_disable(mtd);
++
++	return 0;
++}
++
++static int sunxi_nfc_hw_ecc_write_subpage(struct mtd_info *mtd,
++					  struct nand_chip *chip,
++					  u32 data_offs, u32 data_len,
++					  const u8 *buf, int oob_required,
++					  int page)
++{
++	struct nand_ecc_ctrl *ecc = &chip->ecc;
++	int ret, i, cur_off = 0;
++
++	sunxi_nfc_hw_ecc_enable(mtd);
++
++	for (i = data_offs / ecc->size;
++	     i < DIV_ROUND_UP(data_offs + data_len, ecc->size); i++) {
++		int data_off = i * ecc->size;
++		int oob_off = i * (ecc->bytes + 4);
++		const u8 *data = buf + data_off;
++		const u8 *oob = chip->oob_poi + oob_off;
++
++		ret = sunxi_nfc_hw_ecc_write_chunk(mtd, data, data_off, oob,
++						   oob_off + mtd->writesize,
++						   &cur_off, !i, page);
++		if (ret)
++			return ret;
++	}
++
++	sunxi_nfc_hw_ecc_disable(mtd);
++
++	return 0;
++}
++
++static int sunxi_nfc_hw_ecc_write_page_dma(struct mtd_info *mtd,
++					   struct nand_chip *chip,
++					   const u8 *buf,
++					   int oob_required,
++					   int page)
++{
++	struct nand_chip *nand = mtd_to_nand(mtd);
++	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
++	struct nand_ecc_ctrl *ecc = &nand->ecc;
++	struct scatterlist sg;
++	int ret, i;
++
++	ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
++	if (ret)
++		return ret;
++
++	ret = sunxi_nfc_dma_op_prepare(mtd, buf, ecc->size, ecc->steps,
++				       DMA_TO_DEVICE, &sg);
++	if (ret)
++		goto pio_fallback;
++
++	for (i = 0; i < ecc->steps; i++) {
++		const u8 *oob = nand->oob_poi + (i * (ecc->bytes + 4));
++
++		sunxi_nfc_hw_ecc_set_prot_oob_bytes(mtd, oob, i, !i, page);
++	}
++
++	sunxi_nfc_hw_ecc_enable(mtd);
++	sunxi_nfc_randomizer_config(mtd, page, false);
++	sunxi_nfc_randomizer_enable(mtd);
++
++	writel((NAND_CMD_RNDIN << 8) | NAND_CMD_PAGEPROG,
++	       nfc->regs + NFC_REG_RCMD_SET);
++
++	dma_async_issue_pending(nfc->dmac);
++
++	writel(NFC_PAGE_OP | NFC_DATA_SWAP_METHOD |
++	       NFC_DATA_TRANS | NFC_ACCESS_DIR,
++	       nfc->regs + NFC_REG_CMD);
++
++	ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, false, 0);
++	if (ret)
++		dmaengine_terminate_all(nfc->dmac);
++
++	sunxi_nfc_randomizer_disable(mtd);
++	sunxi_nfc_hw_ecc_disable(mtd);
++
++	sunxi_nfc_dma_op_cleanup(mtd, DMA_TO_DEVICE, &sg);
++
++	if (ret)
++		return ret;
++
++	if (oob_required || (chip->options & NAND_NEED_SCRAMBLING))
++		/* TODO: use DMA to transfer extra OOB bytes ? */
++		sunxi_nfc_hw_ecc_write_extra_oob(mtd, chip->oob_poi,
++						 NULL, page);
++
++	return 0;
++
++pio_fallback:
++	return sunxi_nfc_hw_ecc_write_page(mtd, chip, buf, oob_required, page);
++}
++
++static int sunxi_nfc_hw_syndrome_ecc_read_page(struct mtd_info *mtd,
++					       struct nand_chip *chip,
++					       uint8_t *buf, int oob_required,
++					       int page)
++{
++	struct nand_ecc_ctrl *ecc = &chip->ecc;
++	unsigned int max_bitflips = 0;
++	int ret, i, cur_off = 0;
++	bool raw_mode = false;
++
++	sunxi_nfc_hw_ecc_enable(mtd);
++
++	for (i = 0; i < ecc->steps; i++) {
++		int data_off = i * (ecc->size + ecc->bytes + 4);
++		int oob_off = data_off + ecc->size;
++		u8 *data = buf + (i * ecc->size);
++		u8 *oob = chip->oob_poi + (i * (ecc->bytes + 4));
++
++		ret = sunxi_nfc_hw_ecc_read_chunk(mtd, data, data_off, oob,
++						  oob_off, &cur_off,
++						  &max_bitflips, !i,
++						  oob_required,
++						  page);
++		if (ret < 0)
++			return ret;
++		else if (ret)
++			raw_mode = true;
++	}
++
++	if (oob_required)
++		sunxi_nfc_hw_ecc_read_extra_oob(mtd, chip->oob_poi, &cur_off,
++						!raw_mode, page);
++
++	sunxi_nfc_hw_ecc_disable(mtd);
++
++	return max_bitflips;
++}
++
++static int sunxi_nfc_hw_syndrome_ecc_write_page(struct mtd_info *mtd,
++						struct nand_chip *chip,
++						const uint8_t *buf,
++						int oob_required, int page)
++{
++	struct nand_ecc_ctrl *ecc = &chip->ecc;
++	int ret, i, cur_off = 0;
++
++	sunxi_nfc_hw_ecc_enable(mtd);
++
++	for (i = 0; i < ecc->steps; i++) {
++		int data_off = i * (ecc->size + ecc->bytes + 4);
++		int oob_off = data_off + ecc->size;
++		const u8 *data = buf + (i * ecc->size);
++		const u8 *oob = chip->oob_poi + (i * (ecc->bytes + 4));
++
++		ret = sunxi_nfc_hw_ecc_write_chunk(mtd, data, data_off,
++						   oob, oob_off, &cur_off,
++						   false, page);
++		if (ret)
++			return ret;
++	}
++
++	if (oob_required || (chip->options & NAND_NEED_SCRAMBLING))
++		sunxi_nfc_hw_ecc_write_extra_oob(mtd, chip->oob_poi,
++						 &cur_off, page);
++
++	sunxi_nfc_hw_ecc_disable(mtd);
++
++	return 0;
++}
++
++static int sunxi_nfc_hw_common_ecc_read_oob(struct mtd_info *mtd,
++					    struct nand_chip *chip,
++					    int page)
++{
++	chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
++
++	chip->pagebuf = -1;
++
++	return chip->ecc.read_page(mtd, chip, chip->buffers->databuf, 1, page);
++}
++
++static int sunxi_nfc_hw_common_ecc_write_oob(struct mtd_info *mtd,
++					     struct nand_chip *chip,
++					     int page)
++{
++	int ret, status;
++
++	chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0, page);
++
++	chip->pagebuf = -1;
++
++	memset(chip->buffers->databuf, 0xff, mtd->writesize);
++	ret = chip->ecc.write_page(mtd, chip, chip->buffers->databuf, 1, page);
++	if (ret)
++		return ret;
++
++	/* Send command to program the OOB data */
++	chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
++
++	status = chip->waitfunc(mtd, chip);
++
++	return status & NAND_STATUS_FAIL ? -EIO : 0;
++}
++
++static const s32 tWB_lut[] = {6, 12, 16, 20};
++static const s32 tRHW_lut[] = {4, 8, 12, 20};
++
++static int _sunxi_nand_lookup_timing(const s32 *lut, int lut_size, u32 duration,
++		u32 clk_period)
++{
++	u32 clk_cycles = DIV_ROUND_UP(duration, clk_period);
++	int i;
++
++	for (i = 0; i < lut_size; i++) {
++		if (clk_cycles <= lut[i])
++			return i;
++	}
++
++	/* Doesn't fit */
++	return -EINVAL;
++}
++
++#define sunxi_nand_lookup_timing(l, p, c) \
++			_sunxi_nand_lookup_timing(l, ARRAY_SIZE(l), p, c)
++
++static int sunxi_nfc_setup_data_interface(struct mtd_info *mtd, int csline,
++					const struct nand_data_interface *conf)
++{
++	struct nand_chip *nand = mtd_to_nand(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;
++	u32 min_clk_period = 0;
++	s32 tWB, tADL, tWHR, tRHW, tCAD;
++	long real_clk_rate;
++
++	timings = nand_get_sdr_timings(conf);
++	if (IS_ERR(timings))
++		return -ENOTSUPP;
++
++	/* T1 <=> tCLS */
++	if (timings->tCLS_min > min_clk_period)
++		min_clk_period = timings->tCLS_min;
++
++	/* T2 <=> tCLH */
++	if (timings->tCLH_min > min_clk_period)
++		min_clk_period = timings->tCLH_min;
++
++	/* T3 <=> tCS */
++	if (timings->tCS_min > min_clk_period)
++		min_clk_period = timings->tCS_min;
++
++	/* T4 <=> tCH */
++	if (timings->tCH_min > min_clk_period)
++		min_clk_period = timings->tCH_min;
++
++	/* T5 <=> tWP */
++	if (timings->tWP_min > min_clk_period)
++		min_clk_period = timings->tWP_min;
++
++	/* T6 <=> tWH */
++	if (timings->tWH_min > min_clk_period)
++		min_clk_period = timings->tWH_min;
++
++	/* T7 <=> tALS */
++	if (timings->tALS_min > min_clk_period)
++		min_clk_period = timings->tALS_min;
++
++	/* T8 <=> tDS */
++	if (timings->tDS_min > min_clk_period)
++		min_clk_period = timings->tDS_min;
++
++	/* T9 <=> tDH */
++	if (timings->tDH_min > min_clk_period)
++		min_clk_period = timings->tDH_min;
++
++	/* T10 <=> tRR */
++	if (timings->tRR_min > (min_clk_period * 3))
++		min_clk_period = DIV_ROUND_UP(timings->tRR_min, 3);
++
++	/* T11 <=> tALH */
++	if (timings->tALH_min > min_clk_period)
++		min_clk_period = timings->tALH_min;
++
++	/* T12 <=> tRP */
++	if (timings->tRP_min > min_clk_period)
++		min_clk_period = timings->tRP_min;
++
++	/* T13 <=> tREH */
++	if (timings->tREH_min > min_clk_period)
++		min_clk_period = timings->tREH_min;
++
++	/* T14 <=> tRC */
++	if (timings->tRC_min > (min_clk_period * 2))
++		min_clk_period = DIV_ROUND_UP(timings->tRC_min, 2);
++
++	/* T15 <=> tWC */
++	if (timings->tWC_min > (min_clk_period * 2))
++		min_clk_period = DIV_ROUND_UP(timings->tWC_min, 2);
++
++	/* T16 - T19 + tCAD */
++	if (timings->tWB_max > (min_clk_period * 20))
++		min_clk_period = DIV_ROUND_UP(timings->tWB_max, 20);
++
++	if (timings->tADL_min > (min_clk_period * 32))
++		min_clk_period = DIV_ROUND_UP(timings->tADL_min, 32);
++
++	if (timings->tWHR_min > (min_clk_period * 32))
++		min_clk_period = DIV_ROUND_UP(timings->tWHR_min, 32);
++
++	if (timings->tRHW_min > (min_clk_period * 20))
++		min_clk_period = DIV_ROUND_UP(timings->tRHW_min, 20);
++
++	tWB  = sunxi_nand_lookup_timing(tWB_lut, timings->tWB_max,
++					min_clk_period);
++	if (tWB < 0) {
++		dev_err(nfc->dev, "unsupported tWB\n");
++		return tWB;
++	}
++
++	tADL = DIV_ROUND_UP(timings->tADL_min, min_clk_period) >> 3;
++	if (tADL > 3) {
++		dev_err(nfc->dev, "unsupported tADL\n");
++		return -EINVAL;
++	}
++
++	tWHR = DIV_ROUND_UP(timings->tWHR_min, min_clk_period) >> 3;
++	if (tWHR > 3) {
++		dev_err(nfc->dev, "unsupported tWHR\n");
++		return -EINVAL;
++	}
++
++	tRHW = sunxi_nand_lookup_timing(tRHW_lut, timings->tRHW_min,
++					min_clk_period);
++	if (tRHW < 0) {
++		dev_err(nfc->dev, "unsupported tRHW\n");
++		return tRHW;
++	}
++
++	if (csline == NAND_DATA_IFACE_CHECK_ONLY)
++		return 0;
++
++	/*
++	 * TODO: according to ONFI specs this value only applies for DDR NAND,
++	 * but Allwinner seems to set this to 0x7. Mimic them for now.
++	 */
++	tCAD = 0x7;
++
++	/* TODO: A83 has some more bits for CDQSS, CS, CLHZ, CCS, WC */
++	chip->timing_cfg = NFC_TIMING_CFG(tWB, tADL, tWHR, tRHW, tCAD);
++
++	/* Convert min_clk_period from picoseconds to nanoseconds */
++	min_clk_period = DIV_ROUND_UP(min_clk_period, 1000);
++
++	/*
++	 * Unlike what is stated in Allwinner datasheet, the clk_rate should
++	 * be set to (1 / min_clk_period), and not (2 / min_clk_period).
++	 * This new formula was verified with a scope and validated by
++	 * Allwinner engineers.
++	 */
++	chip->clk_rate = NSEC_PER_SEC / min_clk_period;
++	real_clk_rate = clk_round_rate(nfc->mod_clk, chip->clk_rate);
++	if (real_clk_rate <= 0) {
++		dev_err(nfc->dev, "Unable to round clk %lu\n", chip->clk_rate);
++		return -EINVAL;
++	}
++
++	/*
++	 * ONFI specification 3.1, paragraph 4.15.2 dictates that EDO data
++	 * output cycle timings shall be used if the host drives tRC less than
++	 * 30 ns.
++	 */
++	min_clk_period = NSEC_PER_SEC / real_clk_rate;
++	chip->timing_ctl = ((min_clk_period * 2) < 30) ?
++			   NFC_TIMING_CTL_EDO : 0;
++
++	return 0;
++}
++
++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_ecc_ctrl *ecc = &nand->ecc;
++
++	if (section >= ecc->steps)
++		return -ERANGE;
++
++	oobregion->offset = section * (ecc->bytes + 4) + 4;
++	oobregion->length = ecc->bytes;
++
++	return 0;
++}
++
++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_ecc_ctrl *ecc = &nand->ecc;
++
++	if (section > ecc->steps)
++		return -ERANGE;
++
++	/*
++	 * The first 2 bytes are used for BB markers, hence we
++	 * only have 2 bytes available in the first user data
++	 * section.
++	 */
++	if (!section && ecc->mode == NAND_ECC_HW) {
++		oobregion->offset = 2;
++		oobregion->length = 2;
++
++		return 0;
++	}
++
++	oobregion->offset = section * (ecc->bytes + 4);
++
++	if (section < ecc->steps)
++		oobregion->length = 4;
++	else
++		oobregion->offset = mtd->oobsize - oobregion->offset;
++
++	return 0;
++}
++
++static const struct mtd_ooblayout_ops sunxi_nand_ooblayout_ops = {
++	.ecc = sunxi_nand_ooblayout_ecc,
++	.free = sunxi_nand_ooblayout_free,
++};
++
++static int sunxi_nand_hw_common_ecc_ctrl_init(struct mtd_info *mtd,
++					      struct nand_ecc_ctrl *ecc,
++					      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 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;
++	int nsectors;
++	int ret;
++	int i;
++
++	if (ecc->options & NAND_ECC_MAXIMIZE) {
++		int bytes;
++
++		ecc->size = 1024;
++		nsectors = mtd->writesize / ecc->size;
++
++		/* Reserve 2 bytes for the BBM */
++		bytes = (mtd->oobsize - 2) / nsectors;
++
++		/* 4 non-ECC bytes are added before each ECC bytes section */
++		bytes -= 4;
++
++		/* and bytes has to be even. */
++		if (bytes % 2)
++			bytes--;
++
++		ecc->strength = bytes * 8 / fls(8 * ecc->size);
++
++		for (i = 0; i < ARRAY_SIZE(strengths); i++) {
++			if (strengths[i] > ecc->strength)
++				break;
++		}
++
++		if (!i)
++			ecc->strength = 0;
++		else
++			ecc->strength = strengths[i - 1];
++	}
++
++	if (ecc->size != 512 && ecc->size != 1024)
++		return -EINVAL;
++
++	data = kzalloc(sizeof(*data), GFP_KERNEL);
++	if (!data)
++		return -ENOMEM;
++
++	/* Prefer 1k ECC chunk over 512 ones */
++	if (ecc->size == 512 && mtd->writesize > 512) {
++		ecc->size = 1024;
++		ecc->strength *= 2;
++	}
++
++	/* Add ECC info retrieval from DT */
++	for (i = 0; i < ARRAY_SIZE(strengths); i++) {
++		if (ecc->strength <= strengths[i])
++			break;
++	}
++
++	if (i >= ARRAY_SIZE(strengths)) {
++		dev_err(nfc->dev, "unsupported strength\n");
++		ret = -ENOTSUPP;
++		goto err;
++	}
++
++	data->mode = i;
++
++	/* HW ECC always request ECC bytes for 1024 bytes blocks */
++	ecc->bytes = DIV_ROUND_UP(ecc->strength * fls(8 * 1024), 8);
++
++	/* HW ECC always work with even numbers of ECC bytes */
++	ecc->bytes = ALIGN(ecc->bytes, 2);
++
++	nsectors = mtd->writesize / ecc->size;
++
++	if (mtd->oobsize < ((ecc->bytes + 4) * nsectors)) {
++		ret = -EINVAL;
++		goto err;
++	}
++
++	ecc->read_oob = sunxi_nfc_hw_common_ecc_read_oob;
++	ecc->write_oob = sunxi_nfc_hw_common_ecc_write_oob;
++	mtd_set_ooblayout(mtd, &sunxi_nand_ooblayout_ops);
++	ecc->priv = data;
++
++	return 0;
++
++err:
++	kfree(data);
++
++	return ret;
++}
++
++static void sunxi_nand_hw_common_ecc_ctrl_cleanup(struct nand_ecc_ctrl *ecc)
++{
++	kfree(ecc->priv);
++}
++
++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 sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
++	struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
++	int ret;
++
++	ret = sunxi_nand_hw_common_ecc_ctrl_init(mtd, ecc, np);
++	if (ret)
++		return ret;
++
++	if (nfc->dmac) {
++		ecc->read_page = sunxi_nfc_hw_ecc_read_page_dma;
++		ecc->read_subpage = sunxi_nfc_hw_ecc_read_subpage_dma;
++		ecc->write_page = sunxi_nfc_hw_ecc_write_page_dma;
++		nand->options |= NAND_USE_BOUNCE_BUFFER;
++	} else {
++		ecc->read_page = sunxi_nfc_hw_ecc_read_page;
++		ecc->read_subpage = sunxi_nfc_hw_ecc_read_subpage;
++		ecc->write_page = sunxi_nfc_hw_ecc_write_page;
++	}
++
++	/* TODO: support DMA for raw accesses and subpage write */
++	ecc->write_subpage = sunxi_nfc_hw_ecc_write_subpage;
++	ecc->read_oob_raw = nand_read_oob_std;
++	ecc->write_oob_raw = nand_write_oob_std;
++
++	return 0;
++}
++
++static int sunxi_nand_hw_syndrome_ecc_ctrl_init(struct mtd_info *mtd,
++						struct nand_ecc_ctrl *ecc,
++						struct device_node *np)
++{
++	int ret;
++
++	ret = sunxi_nand_hw_common_ecc_ctrl_init(mtd, ecc, np);
++	if (ret)
++		return ret;
++
++	ecc->prepad = 4;
++	ecc->read_page = sunxi_nfc_hw_syndrome_ecc_read_page;
++	ecc->write_page = sunxi_nfc_hw_syndrome_ecc_write_page;
++	ecc->read_oob_raw = nand_read_oob_syndrome;
++	ecc->write_oob_raw = nand_write_oob_syndrome;
++
++	return 0;
++}
++
++static void sunxi_nand_ecc_cleanup(struct nand_ecc_ctrl *ecc)
++{
++	switch (ecc->mode) {
++	case NAND_ECC_HW:
++	case NAND_ECC_HW_SYNDROME:
++		sunxi_nand_hw_common_ecc_ctrl_cleanup(ecc);
++		break;
++	case NAND_ECC_NONE:
++	default:
++		break;
++	}
++}
++
++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);
++	int ret;
++
++	if (!ecc->size) {
++		ecc->size = nand->ecc_step_ds;
++		ecc->strength = nand->ecc_strength_ds;
++	}
++
++	if (!ecc->size || !ecc->strength)
++		return -EINVAL;
++
++	switch (ecc->mode) {
++	case NAND_ECC_HW:
++		ret = sunxi_nand_hw_ecc_ctrl_init(mtd, ecc, np);
++		if (ret)
++			return ret;
++		break;
++	case NAND_ECC_HW_SYNDROME:
++		ret = sunxi_nand_hw_syndrome_ecc_ctrl_init(mtd, ecc, np);
++		if (ret)
++			return ret;
++		break;
++	case NAND_ECC_NONE:
++	case NAND_ECC_SOFT:
++		break;
++	default:
++		return -EINVAL;
++	}
++
++	return 0;
++}
++
++static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
++				struct device_node *np)
++{
++	struct sunxi_nand_chip *chip;
++	struct mtd_info *mtd;
++	struct nand_chip *nand;
++	int nsels;
++	int ret;
++	int i;
++	u32 tmp;
++
++	if (!of_get_property(np, "reg", &nsels))
++		return -EINVAL;
++
++	nsels /= sizeof(u32);
++	if (!nsels) {
++		dev_err(dev, "invalid reg property size\n");
++		return -EINVAL;
++	}
++
++	chip = devm_kzalloc(dev,
++			    sizeof(*chip) +
++			    (nsels * sizeof(struct sunxi_nand_chip_sel)),
++			    GFP_KERNEL);
++	if (!chip) {
++		dev_err(dev, "could not allocate chip\n");
++		return -ENOMEM;
++	}
++
++	chip->nsels = nsels;
++	chip->selected = -1;
++
++	for (i = 0; i < nsels; i++) {
++		ret = of_property_read_u32_index(np, "reg", i, &tmp);
++		if (ret) {
++			dev_err(dev, "could not retrieve reg property: %d\n",
++				ret);
++			return ret;
++		}
++
++		if (tmp > NFC_MAX_CS) {
++			dev_err(dev,
++				"invalid reg value: %u (max CS = 7)\n",
++				tmp);
++			return -EINVAL;
++		}
++
++		if (test_and_set_bit(tmp, &nfc->assigned_cs)) {
++			dev_err(dev, "CS %d already assigned\n", tmp);
++			return -EINVAL;
++		}
++
++		chip->sels[i].cs = tmp;
++
++		if (!of_property_read_u32_index(np, "allwinner,rb", i, &tmp) &&
++		    tmp < 2) {
++			chip->sels[i].rb.type = RB_NATIVE;
++			chip->sels[i].rb.info.nativeid = tmp;
++		} else {
++			ret = of_get_named_gpio(np, "rb-gpios", i);
++			if (ret >= 0) {
++				tmp = ret;
++				chip->sels[i].rb.type = RB_GPIO;
++				chip->sels[i].rb.info.gpio = tmp;
++				ret = devm_gpio_request(dev, tmp, "nand-rb");
++				if (ret)
++					return ret;
++
++				ret = gpio_direction_input(tmp);
++				if (ret)
++					return ret;
++			} else {
++				chip->sels[i].rb.type = RB_NONE;
++			}
++		}
++	}
++
++	nand = &chip->nand;
++	/* Default tR value specified in the ONFI spec (chapter 4.15.1) */
++	nand->chip_delay = 200;
++	nand->controller = &nfc->controller;
++	/*
++	 * Set the ECC mode to the default value in case nothing is specified
++	 * in the DT.
++	 */
++	nand->ecc.mode = NAND_ECC_HW;
++	nand_set_flash_node(nand, np);
++	nand->select_chip = sunxi_nfc_select_chip;
++	nand->cmd_ctrl = sunxi_nfc_cmd_ctrl;
++	nand->read_buf = sunxi_nfc_read_buf;
++	nand->write_buf = sunxi_nfc_write_buf;
++	nand->read_byte = sunxi_nfc_read_byte;
++	nand->setup_data_interface = sunxi_nfc_setup_data_interface;
++
++	mtd = nand_to_mtd(nand);
++	mtd->dev.parent = dev;
++
++	ret = nand_scan_ident(mtd, nsels, NULL);
++	if (ret)
++		return ret;
++
++	if (nand->bbt_options & NAND_BBT_USE_FLASH)
++		nand->bbt_options |= NAND_BBT_NO_OOB;
++
++	if (nand->options & NAND_NEED_SCRAMBLING)
++		nand->options |= NAND_NO_SUBPAGE_WRITE;
++
++	nand->options |= NAND_SUBPAGE_READ;
++
++	ret = sunxi_nand_ecc_init(mtd, &nand->ecc, np);
++	if (ret) {
++		dev_err(dev, "ECC init failed: %d\n", ret);
++		return ret;
++	}
++
++	ret = nand_scan_tail(mtd);
++	if (ret) {
++		dev_err(dev, "nand_scan_tail failed: %d\n", ret);
++		return ret;
++	}
++
++	ret = mtd_device_register(mtd, NULL, 0);
++	if (ret) {
++		dev_err(dev, "failed to register mtd device: %d\n", ret);
++		nand_release(mtd);
++		return ret;
++	}
++
++	list_add_tail(&chip->node, &nfc->chips);
++
++	return 0;
++}
++
++static int sunxi_nand_chips_init(struct device *dev, struct sunxi_nfc *nfc)
++{
++	struct device_node *np = dev->of_node;
++	struct device_node *nand_np;
++	int nchips = of_get_child_count(np);
++	int ret;
++
++	if (nchips > 8) {
++		dev_err(dev, "too many NAND chips: %d (max = 8)\n", nchips);
++		return -EINVAL;
++	}
++
++	for_each_child_of_node(np, nand_np) {
++		ret = sunxi_nand_chip_init(dev, nfc, nand_np);
++		if (ret) {
++			of_node_put(nand_np);
++			return ret;
++		}
++	}
++
++	return 0;
++}
++
++static void sunxi_nand_chips_cleanup(struct sunxi_nfc *nfc)
++{
++	struct sunxi_nand_chip *chip;
++
++	while (!list_empty(&nfc->chips)) {
++		chip = list_first_entry(&nfc->chips, struct sunxi_nand_chip,
++					node);
++		nand_release(nand_to_mtd(&chip->nand));
++		sunxi_nand_ecc_cleanup(&chip->nand.ecc);
++		list_del(&chip->node);
++	}
++}
++
++static int sunxi_nfc_probe(struct platform_device *pdev)
++{
++	struct device *dev = &pdev->dev;
++	struct resource *r;
++	struct sunxi_nfc *nfc;
++	int irq;
++	int ret;
++
++	nfc = devm_kzalloc(dev, sizeof(*nfc), GFP_KERNEL);
++	if (!nfc)
++		return -ENOMEM;
++
++	nfc->dev = dev;
++	nand_hw_control_init(&nfc->controller);
++	INIT_LIST_HEAD(&nfc->chips);
++
++	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	nfc->regs = devm_ioremap_resource(dev, r);
++	if (IS_ERR(nfc->regs))
++		return PTR_ERR(nfc->regs);
++
++	irq = platform_get_irq(pdev, 0);
++	if (irq < 0) {
++		dev_err(dev, "failed to retrieve irq\n");
++		return irq;
++	}
++
++	nfc->ahb_clk = devm_clk_get(dev, "ahb");
++	if (IS_ERR(nfc->ahb_clk)) {
++		dev_err(dev, "failed to retrieve ahb clk\n");
++		return PTR_ERR(nfc->ahb_clk);
++	}
++
++	ret = clk_prepare_enable(nfc->ahb_clk);
++	if (ret)
++		return ret;
++
++	nfc->mod_clk = devm_clk_get(dev, "mod");
++	if (IS_ERR(nfc->mod_clk)) {
++		dev_err(dev, "failed to retrieve mod clk\n");
++		ret = PTR_ERR(nfc->mod_clk);
++		goto out_ahb_clk_unprepare;
++	}
++
++	ret = clk_prepare_enable(nfc->mod_clk);
++	if (ret)
++		goto out_ahb_clk_unprepare;
++
++	nfc->reset = devm_reset_control_get_optional_exclusive(dev, "ahb");
++	if (IS_ERR(nfc->reset)) {
++		ret = PTR_ERR(nfc->reset);
++		goto out_mod_clk_unprepare;
++	}
++
++	ret = reset_control_deassert(nfc->reset);
++	if (ret) {
++		dev_err(dev, "reset err %d\n", ret);
++		goto out_mod_clk_unprepare;
++	}
++
++	ret = sunxi_nfc_rst(nfc);
++	if (ret)
++		goto out_ahb_reset_reassert;
++
++	writel(0, nfc->regs + NFC_REG_INT);
++	ret = devm_request_irq(dev, irq, sunxi_nfc_interrupt,
++			       0, "sunxi-nand", nfc);
++	if (ret)
++		goto out_ahb_reset_reassert;
++
++	nfc->dmac = dma_request_slave_channel(dev, "rxtx");
++	if (nfc->dmac) {
++		struct dma_slave_config dmac_cfg = { };
++
++		dmac_cfg.src_addr = r->start + NFC_REG_IO_DATA;
++		dmac_cfg.dst_addr = dmac_cfg.src_addr;
++		dmac_cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
++		dmac_cfg.dst_addr_width = dmac_cfg.src_addr_width;
++		dmac_cfg.src_maxburst = 4;
++		dmac_cfg.dst_maxburst = 4;
++		dmaengine_slave_config(nfc->dmac, &dmac_cfg);
++	} else {
++		dev_warn(dev, "failed to request rxtx DMA channel\n");
++	}
++
++	platform_set_drvdata(pdev, nfc);
++
++	ret = sunxi_nand_chips_init(dev, nfc);
++	if (ret) {
++		dev_err(dev, "failed to init nand chips\n");
++		goto out_release_dmac;
++	}
++
++	return 0;
++
++out_release_dmac:
++	if (nfc->dmac)
++		dma_release_channel(nfc->dmac);
++out_ahb_reset_reassert:
++	reset_control_assert(nfc->reset);
++out_mod_clk_unprepare:
++	clk_disable_unprepare(nfc->mod_clk);
++out_ahb_clk_unprepare:
++	clk_disable_unprepare(nfc->ahb_clk);
++
++	return ret;
++}
++
++static int sunxi_nfc_remove(struct platform_device *pdev)
++{
++	struct sunxi_nfc *nfc = platform_get_drvdata(pdev);
++
++	sunxi_nand_chips_cleanup(nfc);
++
++	reset_control_assert(nfc->reset);
++
++	if (nfc->dmac)
++		dma_release_channel(nfc->dmac);
++	clk_disable_unprepare(nfc->mod_clk);
++	clk_disable_unprepare(nfc->ahb_clk);
++
++	return 0;
++}
++
++static const struct of_device_id sunxi_nfc_ids[] = {
++	{ .compatible = "allwinner,sun4i-a10-nand" },
++	{ /* sentinel */ }
++};
++MODULE_DEVICE_TABLE(of, sunxi_nfc_ids);
++
++static struct platform_driver sunxi_nfc_driver = {
++	.driver = {
++		.name = "sunxi_nand",
++		.of_match_table = sunxi_nfc_ids,
++	},
++	.probe = sunxi_nfc_probe,
++	.remove = sunxi_nfc_remove,
++};
++module_platform_driver(sunxi_nfc_driver);
++
++MODULE_LICENSE("GPL v2");
++MODULE_AUTHOR("Boris BREZILLON");
++MODULE_DESCRIPTION("Allwinner NAND Flash Controller driver");
++MODULE_ALIAS("platform:sunxi_nand");
+diff --git a/drivers/mtd/nand/raw/tango_nand.c b/drivers/mtd/nand/raw/tango_nand.c
+new file mode 100644
+index 0000000..766906f
+--- /dev/null
++++ b/drivers/mtd/nand/raw/tango_nand.c
+@@ -0,0 +1,699 @@
++/*
++ * Copyright (C) 2016 Sigma Designs
++ *
++ * 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/io.h>
++#include <linux/of.h>
++#include <linux/clk.h>
++#include <linux/iopoll.h>
++#include <linux/module.h>
++#include <linux/mtd/rawnand.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 ERR_COUNT_PKT_0(v)	(((v) >> 0) & 0x3f)
++#define ERR_COUNT_PKT_N(v)	(((v) >> 8) & 0x3f)
++#define DECODE_FAIL_PKT_0(v)	(((v) & BIT(7)) == 0)
++#define DECODE_FAIL_PKT_N(v)	(((v) & BIT(15)) == 0)
++
++/* 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 u8 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, u8 *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 u8 *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)
++{
++	struct mtd_info *mtd = nand_to_mtd(chip);
++	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)
++			mtd->ecc_stats.failed++;
++		else
++			mtd->ecc_stats.corrected += res;
++
++		bitflips = max(res, bitflips);
++		buf += pkt_size;
++		ecc += ecc_size;
++	}
++
++	return bitflips;
++}
++
++static int decode_error_report(struct nand_chip *chip)
++{
++	u32 status, res;
++	struct mtd_info *mtd = nand_to_mtd(chip);
++	struct tango_nfc *nfc = to_tango_nfc(chip->controller);
++
++	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_FAIL_PKT_0(res) || DECODE_FAIL_PKT_N(res))
++		return -EBADMSG;
++
++	/* ERR_COUNT_PKT_N is max, not sum, but that's all we have */
++	mtd->ecc_stats.corrected +=
++		ERR_COUNT_PKT_0(res) + ERR_COUNT_PKT_N(res);
++
++	return max(ERR_COUNT_PKT_0(res), ERR_COUNT_PKT_N(res));
++}
++
++static void tango_dma_callback(void *arg)
++{
++	complete(arg);
++}
++
++static int do_dma(struct tango_nfc *nfc, enum dma_data_direction 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;
++	enum dma_transfer_direction tdir;
++	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;
++
++	tdir = dir == DMA_TO_DEVICE ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM;
++	desc = dmaengine_prep_slave_sg(chan, &sg, 1, tdir, 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,
++			   u8 *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(chip);
++	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 u8 *buf, int oob_required, int page)
++{
++	struct tango_nfc *nfc = to_tango_nfc(chip->controller);
++	int err, status, 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;
++
++	status = chip->waitfunc(mtd, chip);
++	if (status & NAND_STATUS_FAIL)
++		return -EIO;
++
++	return 0;
++}
++
++static void aux_read(struct nand_chip *chip, u8 **buf, int len, int *pos)
++{
++	struct mtd_info *mtd = nand_to_mtd(chip);
++
++	*pos += len;
++
++	if (!*buf) {
++		/* skip over "len" bytes */
++		chip->cmdfunc(mtd, NAND_CMD_RNDOUT, *pos, -1);
++	} else {
++		tango_read_buf(mtd, *buf, len);
++		*buf += len;
++	}
++}
++
++static void aux_write(struct nand_chip *chip, const u8 **buf, int len, int *pos)
++{
++	struct mtd_info *mtd = nand_to_mtd(chip);
++
++	*pos += len;
++
++	if (!*buf) {
++		/* skip over "len" bytes */
++		chip->cmdfunc(mtd, NAND_CMD_RNDIN, *pos, -1);
++	} else {
++		tango_write_buf(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 void raw_read(struct nand_chip *chip, u8 *buf, u8 *oob)
++{
++	struct mtd_info *mtd = nand_to_mtd(chip);
++	u8 *oob_orig = oob;
++	const int page_size = 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)
++		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);
++}
++
++static void raw_write(struct nand_chip *chip, const u8 *buf, const u8 *oob)
++{
++	struct mtd_info *mtd = nand_to_mtd(chip);
++	const u8 *oob_orig = oob;
++	const int page_size = 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)
++		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);
++}
++
++static int tango_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
++			       u8 *buf, int oob_required, int page)
++{
++	chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
++	raw_read(chip, buf, chip->oob_poi);
++	return 0;
++}
++
++static int tango_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
++				const u8 *buf, int oob_required, int page)
++{
++	int status;
++
++	chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0, page);
++	raw_write(chip, buf, chip->oob_poi);
++	chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
++
++	status = chip->waitfunc(mtd, chip);
++	if (status & NAND_STATUS_FAIL)
++		return -EIO;
++
++	return 0;
++}
++
++static int tango_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
++			  int page)
++{
++	chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
++	raw_read(chip, NULL, chip->oob_poi);
++	return 0;
++}
++
++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, int csline,
++			     const struct nand_data_interface *conf)
++{
++	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 (csline == NAND_DATA_IFACE_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 = nand_to_mtd(chip);
++
++	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;
++	ecc->options = NAND_ECC_CUSTOM_PAGE_ACCESS;
++
++	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])
++			nand_release(nand_to_mtd(&nfc->chips[cs]->nand_chip));
++	}
++
++	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);
++
++	writel_relaxed(MODE_RAW, nfc->pbus_base + PBUS_PAD_MODE);
++
++	clk = clk_get(&pdev->dev, NULL);
++	if (IS_ERR(clk))
++		return PTR_ERR(clk);
++
++	nfc->chan = dma_request_chan(&pdev->dev, "rxtx");
++	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 */ }
++};
++MODULE_DEVICE_TABLE(of, tango_nand_ids);
++
++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");
+diff --git a/drivers/mtd/nand/raw/tmio_nand.c b/drivers/mtd/nand/raw/tmio_nand.c
+new file mode 100644
+index 0000000..84dbf32
+--- /dev/null
++++ b/drivers/mtd/nand/raw/tmio_nand.c
+@@ -0,0 +1,512 @@
++/*
++ * Toshiba TMIO NAND flash controller driver
++ *
++ * Slightly murky pre-git history of the driver:
++ *
++ * Copyright (c) Ian Molton 2004, 2005, 2008
++ *    Original work, independent of sharps code. Included hardware ECC support.
++ *    Hard ECC did not work for writes in the early revisions.
++ * Copyright (c) Dirk Opfer 2005.
++ *    Modifications developed from sharps code but
++ *    NOT containing any, ported onto Ians base.
++ * Copyright (c) Chris Humbert 2005
++ * Copyright (c) Dmitry Baryshkov 2008
++ *    Minor fixes
++ *
++ * Parts copyright Sebastian Carlier
++ *
++ * This file is licensed under
++ * the terms of the GNU General Public License version 2. This program
++ * is licensed "as is" without any warranty of any kind, whether express
++ * or implied.
++ *
++ */
++
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/mfd/core.h>
++#include <linux/mfd/tmio.h>
++#include <linux/delay.h>
++#include <linux/io.h>
++#include <linux/irq.h>
++#include <linux/interrupt.h>
++#include <linux/ioport.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/rawnand.h>
++#include <linux/mtd/nand_ecc.h>
++#include <linux/mtd/partitions.h>
++#include <linux/slab.h>
++
++/*--------------------------------------------------------------------------*/
++
++/*
++ * NAND Flash Host Controller Configuration Register
++ */
++#define CCR_COMMAND	0x04	/* w Command				*/
++#define CCR_BASE	0x10	/* l NAND Flash Control Reg Base Addr	*/
++#define CCR_INTP	0x3d	/* b Interrupt Pin			*/
++#define CCR_INTE	0x48	/* b Interrupt Enable			*/
++#define CCR_EC		0x4a	/* b Event Control			*/
++#define CCR_ICC		0x4c	/* b Internal Clock Control		*/
++#define CCR_ECCC	0x5b	/* b ECC Control			*/
++#define CCR_NFTC	0x60	/* b NAND Flash Transaction Control	*/
++#define CCR_NFM		0x61	/* b NAND Flash Monitor			*/
++#define CCR_NFPSC	0x62	/* b NAND Flash Power Supply Control	*/
++#define CCR_NFDC	0x63	/* b NAND Flash Detect Control		*/
++
++/*
++ * NAND Flash Control Register
++ */
++#define FCR_DATA	0x00	/* bwl Data Register			*/
++#define FCR_MODE	0x04	/* b Mode Register			*/
++#define FCR_STATUS	0x05	/* b Status Register			*/
++#define FCR_ISR		0x06	/* b Interrupt Status Register		*/
++#define FCR_IMR		0x07	/* b Interrupt Mask Register		*/
++
++/* FCR_MODE Register Command List */
++#define FCR_MODE_DATA	0x94	/* Data Data_Mode */
++#define FCR_MODE_COMMAND 0x95	/* Data Command_Mode */
++#define FCR_MODE_ADDRESS 0x96	/* Data Address_Mode */
++
++#define FCR_MODE_HWECC_CALC	0xB4	/* HW-ECC Data */
++#define FCR_MODE_HWECC_RESULT	0xD4	/* HW-ECC Calc result Read_Mode */
++#define FCR_MODE_HWECC_RESET	0xF4	/* HW-ECC Reset */
++
++#define FCR_MODE_POWER_ON	0x0C	/* Power Supply ON  to SSFDC card */
++#define FCR_MODE_POWER_OFF	0x08	/* Power Supply OFF to SSFDC card */
++
++#define FCR_MODE_LED_OFF	0x00	/* LED OFF */
++#define FCR_MODE_LED_ON		0x04	/* LED ON */
++
++#define FCR_MODE_EJECT_ON	0x68	/* Ejection events active  */
++#define FCR_MODE_EJECT_OFF	0x08	/* Ejection events ignored */
++
++#define FCR_MODE_LOCK		0x6C	/* Lock_Mode. Eject Switch Invalid */
++#define FCR_MODE_UNLOCK		0x0C	/* UnLock_Mode. Eject Switch is valid */
++
++#define FCR_MODE_CONTROLLER_ID	0x40	/* Controller ID Read */
++#define FCR_MODE_STANDBY	0x00	/* SSFDC card Changes Standby State */
++
++#define FCR_MODE_WE		0x80
++#define FCR_MODE_ECC1		0x40
++#define FCR_MODE_ECC0		0x20
++#define FCR_MODE_CE		0x10
++#define FCR_MODE_PCNT1		0x08
++#define FCR_MODE_PCNT0		0x04
++#define FCR_MODE_ALE		0x02
++#define FCR_MODE_CLE		0x01
++
++#define FCR_STATUS_BUSY		0x80
++
++/*--------------------------------------------------------------------------*/
++
++struct tmio_nand {
++	struct nand_chip chip;
++
++	struct platform_device *dev;
++
++	void __iomem *ccr;
++	void __iomem *fcr;
++	unsigned long fcr_base;
++
++	unsigned int irq;
++
++	/* for tmio_nand_read_byte */
++	u8			read;
++	unsigned read_good:1;
++};
++
++static inline struct tmio_nand *mtd_to_tmio(struct mtd_info *mtd)
++{
++	return container_of(mtd_to_nand(mtd), struct tmio_nand, chip);
++}
++
++
++/*--------------------------------------------------------------------------*/
++
++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);
++
++	if (ctrl & NAND_CTRL_CHANGE) {
++		u8 mode;
++
++		if (ctrl & NAND_NCE) {
++			mode = FCR_MODE_DATA;
++
++			if (ctrl & NAND_CLE)
++				mode |=  FCR_MODE_CLE;
++			else
++				mode &= ~FCR_MODE_CLE;
++
++			if (ctrl & NAND_ALE)
++				mode |=  FCR_MODE_ALE;
++			else
++				mode &= ~FCR_MODE_ALE;
++		} else {
++			mode = FCR_MODE_STANDBY;
++		}
++
++		tmio_iowrite8(mode, tmio->fcr + FCR_MODE);
++		tmio->read_good = 0;
++	}
++
++	if (cmd != NAND_CMD_NONE)
++		tmio_iowrite8(cmd, chip->IO_ADDR_W);
++}
++
++static int tmio_nand_dev_ready(struct mtd_info *mtd)
++{
++	struct tmio_nand *tmio = mtd_to_tmio(mtd);
++
++	return !(tmio_ioread8(tmio->fcr + FCR_STATUS) & FCR_STATUS_BUSY);
++}
++
++static irqreturn_t tmio_irq(int irq, void *__tmio)
++{
++	struct tmio_nand *tmio = __tmio;
++	struct nand_chip *nand_chip = &tmio->chip;
++
++	/* disable RDYREQ interrupt */
++	tmio_iowrite8(0x00, tmio->fcr + FCR_IMR);
++
++	if (unlikely(!waitqueue_active(&nand_chip->controller->wq)))
++		dev_warn(&tmio->dev->dev, "spurious interrupt\n");
++
++	wake_up(&nand_chip->controller->wq);
++	return IRQ_HANDLED;
++}
++
++/*
++  *The TMIO core has a RDYREQ interrupt on the posedge of #SMRB.
++  *This interrupt is normally disabled, but for long operations like
++  *erase and write, we enable it to wake us up.  The irq handler
++  *disables the interrupt.
++ */
++static int
++tmio_nand_wait(struct mtd_info *mtd, struct nand_chip *nand_chip)
++{
++	struct tmio_nand *tmio = mtd_to_tmio(mtd);
++	long timeout;
++
++	/* enable RDYREQ interrupt */
++	tmio_iowrite8(0x0f, tmio->fcr + FCR_ISR);
++	tmio_iowrite8(0x81, tmio->fcr + FCR_IMR);
++
++	timeout = wait_event_timeout(nand_chip->controller->wq,
++		tmio_nand_dev_ready(mtd),
++		msecs_to_jiffies(nand_chip->state == FL_ERASING ? 400 : 20));
++
++	if (unlikely(!tmio_nand_dev_ready(mtd))) {
++		tmio_iowrite8(0x00, tmio->fcr + FCR_IMR);
++		dev_warn(&tmio->dev->dev, "still busy with %s after %d ms\n",
++			nand_chip->state == FL_ERASING ? "erase" : "program",
++			nand_chip->state == FL_ERASING ? 400 : 20);
++
++	} else if (unlikely(!timeout)) {
++		tmio_iowrite8(0x00, tmio->fcr + FCR_IMR);
++		dev_warn(&tmio->dev->dev, "timeout waiting for interrupt\n");
++	}
++
++	nand_chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
++	return nand_chip->read_byte(mtd);
++}
++
++/*
++  *The TMIO controller combines two 8-bit data bytes into one 16-bit
++  *word. This function separates them so nand_base.c works as expected,
++  *especially its NAND_CMD_READID routines.
++ *
++  *To prevent stale data from being read, tmio_nand_hwcontrol() clears
++  *tmio->read_good.
++ */
++static u_char tmio_nand_read_byte(struct mtd_info *mtd)
++{
++	struct tmio_nand *tmio = mtd_to_tmio(mtd);
++	unsigned int data;
++
++	if (tmio->read_good--)
++		return tmio->read;
++
++	data = tmio_ioread16(tmio->fcr + FCR_DATA);
++	tmio->read = data >> 8;
++	return data;
++}
++
++/*
++  *The TMIO controller converts an 8-bit NAND interface to a 16-bit
++  *bus interface, so all data reads and writes must be 16-bit wide.
++  *Thus, we implement 16-bit versions of the read, write, and verify
++  *buffer functions.
++ */
++static void
++tmio_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
++{
++	struct tmio_nand *tmio = mtd_to_tmio(mtd);
++
++	tmio_iowrite16_rep(tmio->fcr + FCR_DATA, buf, len >> 1);
++}
++
++static void tmio_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
++{
++	struct tmio_nand *tmio = mtd_to_tmio(mtd);
++
++	tmio_ioread16_rep(tmio->fcr + FCR_DATA, buf, len >> 1);
++}
++
++static void tmio_nand_enable_hwecc(struct mtd_info *mtd, int mode)
++{
++	struct tmio_nand *tmio = mtd_to_tmio(mtd);
++
++	tmio_iowrite8(FCR_MODE_HWECC_RESET, tmio->fcr + FCR_MODE);
++	tmio_ioread8(tmio->fcr + FCR_DATA);	/* dummy read */
++	tmio_iowrite8(FCR_MODE_HWECC_CALC, tmio->fcr + FCR_MODE);
++}
++
++static int tmio_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
++							u_char *ecc_code)
++{
++	struct tmio_nand *tmio = mtd_to_tmio(mtd);
++	unsigned int ecc;
++
++	tmio_iowrite8(FCR_MODE_HWECC_RESULT, tmio->fcr + FCR_MODE);
++
++	ecc = tmio_ioread16(tmio->fcr + FCR_DATA);
++	ecc_code[1] = ecc;	/* 000-255 LP7-0 */
++	ecc_code[0] = ecc >> 8;	/* 000-255 LP15-8 */
++	ecc = tmio_ioread16(tmio->fcr + FCR_DATA);
++	ecc_code[2] = ecc;	/* 000-255 CP5-0,11b */
++	ecc_code[4] = ecc >> 8;	/* 256-511 LP7-0 */
++	ecc = tmio_ioread16(tmio->fcr + FCR_DATA);
++	ecc_code[3] = ecc;	/* 256-511 LP15-8 */
++	ecc_code[5] = ecc >> 8;	/* 256-511 CP5-0,11b */
++
++	tmio_iowrite8(FCR_MODE_DATA, tmio->fcr + FCR_MODE);
++	return 0;
++}
++
++static int tmio_nand_correct_data(struct mtd_info *mtd, unsigned char *buf,
++		unsigned char *read_ecc, unsigned char *calc_ecc)
++{
++	int r0, r1;
++
++	/* assume ecc.size = 512 and ecc.bytes = 6 */
++	r0 = __nand_correct_data(buf, read_ecc, calc_ecc, 256);
++	if (r0 < 0)
++		return r0;
++	r1 = __nand_correct_data(buf + 256, read_ecc + 3, calc_ecc + 3, 256);
++	if (r1 < 0)
++		return r1;
++	return r0 + r1;
++}
++
++static int tmio_hw_init(struct platform_device *dev, struct tmio_nand *tmio)
++{
++	const struct mfd_cell *cell = mfd_get_cell(dev);
++	int ret;
++
++	if (cell->enable) {
++		ret = cell->enable(dev);
++		if (ret)
++			return ret;
++	}
++
++	/* (4Ch) CLKRUN Enable    1st spcrunc */
++	tmio_iowrite8(0x81, tmio->ccr + CCR_ICC);
++
++	/* (10h)BaseAddress    0x1000 spba.spba2 */
++	tmio_iowrite16(tmio->fcr_base, tmio->ccr + CCR_BASE);
++	tmio_iowrite16(tmio->fcr_base >> 16, tmio->ccr + CCR_BASE + 2);
++
++	/* (04h)Command Register I/O spcmd */
++	tmio_iowrite8(0x02, tmio->ccr + CCR_COMMAND);
++
++	/* (62h) Power Supply Control ssmpwc */
++	/* HardPowerOFF - SuspendOFF - PowerSupplyWait_4MS */
++	tmio_iowrite8(0x02, tmio->ccr + CCR_NFPSC);
++
++	/* (63h) Detect Control ssmdtc */
++	tmio_iowrite8(0x02, tmio->ccr + CCR_NFDC);
++
++	/* Interrupt status register clear sintst */
++	tmio_iowrite8(0x0f, tmio->fcr + FCR_ISR);
++
++	/* After power supply, Media are reset smode */
++	tmio_iowrite8(FCR_MODE_POWER_ON, tmio->fcr + FCR_MODE);
++	tmio_iowrite8(FCR_MODE_COMMAND, tmio->fcr + FCR_MODE);
++	tmio_iowrite8(NAND_CMD_RESET, tmio->fcr + FCR_DATA);
++
++	/* Standby Mode smode */
++	tmio_iowrite8(FCR_MODE_STANDBY, tmio->fcr + FCR_MODE);
++
++	mdelay(5);
++
++	return 0;
++}
++
++static void tmio_hw_stop(struct platform_device *dev, struct tmio_nand *tmio)
++{
++	const struct mfd_cell *cell = mfd_get_cell(dev);
++
++	tmio_iowrite8(FCR_MODE_POWER_OFF, tmio->fcr + FCR_MODE);
++	if (cell->disable)
++		cell->disable(dev);
++}
++
++static int tmio_probe(struct platform_device *dev)
++{
++	struct tmio_nand_data *data = dev_get_platdata(&dev->dev);
++	struct resource *fcr = platform_get_resource(dev,
++			IORESOURCE_MEM, 0);
++	struct resource *ccr = platform_get_resource(dev,
++			IORESOURCE_MEM, 1);
++	int irq = platform_get_irq(dev, 0);
++	struct tmio_nand *tmio;
++	struct mtd_info *mtd;
++	struct nand_chip *nand_chip;
++	int retval;
++
++	if (data == NULL)
++		dev_warn(&dev->dev, "NULL platform data!\n");
++
++	tmio = devm_kzalloc(&dev->dev, sizeof(*tmio), GFP_KERNEL);
++	if (!tmio)
++		return -ENOMEM;
++
++	tmio->dev = dev;
++
++	platform_set_drvdata(dev, tmio);
++	nand_chip = &tmio->chip;
++	mtd = nand_to_mtd(nand_chip);
++	mtd->name = "tmio-nand";
++	mtd->dev.parent = &dev->dev;
++
++	tmio->ccr = devm_ioremap(&dev->dev, ccr->start, resource_size(ccr));
++	if (!tmio->ccr)
++		return -EIO;
++
++	tmio->fcr_base = fcr->start & 0xfffff;
++	tmio->fcr = devm_ioremap(&dev->dev, fcr->start, resource_size(fcr));
++	if (!tmio->fcr)
++		return -EIO;
++
++	retval = tmio_hw_init(dev, tmio);
++	if (retval)
++		return retval;
++
++	/* Set address of NAND IO lines */
++	nand_chip->IO_ADDR_R = tmio->fcr;
++	nand_chip->IO_ADDR_W = tmio->fcr;
++
++	/* Set address of hardware control function */
++	nand_chip->cmd_ctrl = tmio_nand_hwcontrol;
++	nand_chip->dev_ready = tmio_nand_dev_ready;
++	nand_chip->read_byte = tmio_nand_read_byte;
++	nand_chip->write_buf = tmio_nand_write_buf;
++	nand_chip->read_buf = tmio_nand_read_buf;
++
++	/* set eccmode using hardware ECC */
++	nand_chip->ecc.mode = NAND_ECC_HW;
++	nand_chip->ecc.size = 512;
++	nand_chip->ecc.bytes = 6;
++	nand_chip->ecc.strength = 2;
++	nand_chip->ecc.hwctl = tmio_nand_enable_hwecc;
++	nand_chip->ecc.calculate = tmio_nand_calculate_ecc;
++	nand_chip->ecc.correct = tmio_nand_correct_data;
++
++	if (data)
++		nand_chip->badblock_pattern = data->badblock_pattern;
++
++	/* 15 us command delay time */
++	nand_chip->chip_delay = 15;
++
++	retval = devm_request_irq(&dev->dev, irq, &tmio_irq, 0,
++				  dev_name(&dev->dev), tmio);
++	if (retval) {
++		dev_err(&dev->dev, "request_irq error %d\n", retval);
++		goto err_irq;
++	}
++
++	tmio->irq = irq;
++	nand_chip->waitfunc = tmio_nand_wait;
++
++	/* Scan to find existence of the device */
++	retval = nand_scan(mtd, 1);
++	if (retval)
++		goto err_irq;
++
++	/* Register the partitions */
++	retval = mtd_device_parse_register(mtd,
++					   data ? data->part_parsers : NULL,
++					   NULL,
++					   data ? data->partition : NULL,
++					   data ? data->num_partitions : 0);
++	if (!retval)
++		return retval;
++
++	nand_release(mtd);
++
++err_irq:
++	tmio_hw_stop(dev, tmio);
++	return retval;
++}
++
++static int tmio_remove(struct platform_device *dev)
++{
++	struct tmio_nand *tmio = platform_get_drvdata(dev);
++
++	nand_release(nand_to_mtd(&tmio->chip));
++	tmio_hw_stop(dev, tmio);
++	return 0;
++}
++
++#ifdef CONFIG_PM
++static int tmio_suspend(struct platform_device *dev, pm_message_t state)
++{
++	const struct mfd_cell *cell = mfd_get_cell(dev);
++
++	if (cell->suspend)
++		cell->suspend(dev);
++
++	tmio_hw_stop(dev, platform_get_drvdata(dev));
++	return 0;
++}
++
++static int tmio_resume(struct platform_device *dev)
++{
++	const struct mfd_cell *cell = mfd_get_cell(dev);
++
++	/* FIXME - is this required or merely another attack of the broken
++	 * SHARP platform? Looks suspicious.
++	 */
++	tmio_hw_init(dev, platform_get_drvdata(dev));
++
++	if (cell->resume)
++		cell->resume(dev);
++
++	return 0;
++}
++#else
++#define tmio_suspend NULL
++#define tmio_resume NULL
++#endif
++
++static struct platform_driver tmio_driver = {
++	.driver.name	= "tmio-nand",
++	.driver.owner	= THIS_MODULE,
++	.probe		= tmio_probe,
++	.remove		= tmio_remove,
++	.suspend	= tmio_suspend,
++	.resume		= tmio_resume,
++};
++
++module_platform_driver(tmio_driver);
++
++MODULE_LICENSE("GPL v2");
++MODULE_AUTHOR("Ian Molton, Dirk Opfer, Chris Humbert, Dmitry Baryshkov");
++MODULE_DESCRIPTION("NAND flash driver on Toshiba Mobile IO controller");
++MODULE_ALIAS("platform:tmio-nand");
+diff --git a/drivers/mtd/nand/raw/txx9ndfmc.c b/drivers/mtd/nand/raw/txx9ndfmc.c
+new file mode 100644
+index 0000000..b567d21
+--- /dev/null
++++ b/drivers/mtd/nand/raw/txx9ndfmc.c
+@@ -0,0 +1,423 @@
++/*
++ * TXx9 NAND flash memory controller driver
++ * Based on RBTX49xx patch from CELF patch archive.
++ *
++ * 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.
++ *
++ * (C) Copyright TOSHIBA CORPORATION 2004-2007
++ * All Rights Reserved.
++ */
++#include <linux/err.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/delay.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/rawnand.h>
++#include <linux/mtd/nand_ecc.h>
++#include <linux/mtd/partitions.h>
++#include <linux/io.h>
++#include <asm/txx9/ndfmc.h>
++
++/* TXX9 NDFMC Registers */
++#define TXX9_NDFDTR	0x00
++#define TXX9_NDFMCR	0x04
++#define TXX9_NDFSR	0x08
++#define TXX9_NDFISR	0x0c
++#define TXX9_NDFIMR	0x10
++#define TXX9_NDFSPR	0x14
++#define TXX9_NDFRSTR	0x18	/* not TX4939 */
++
++/* NDFMCR : NDFMC Mode Control */
++#define TXX9_NDFMCR_WE	0x80
++#define TXX9_NDFMCR_ECC_ALL	0x60
++#define TXX9_NDFMCR_ECC_RESET	0x60
++#define TXX9_NDFMCR_ECC_READ	0x40
++#define TXX9_NDFMCR_ECC_ON	0x20
++#define TXX9_NDFMCR_ECC_OFF	0x00
++#define TXX9_NDFMCR_CE	0x10
++#define TXX9_NDFMCR_BSPRT	0x04	/* TX4925/TX4926 only */
++#define TXX9_NDFMCR_ALE	0x02
++#define TXX9_NDFMCR_CLE	0x01
++/* TX4939 only */
++#define TXX9_NDFMCR_X16	0x0400
++#define TXX9_NDFMCR_DMAREQ_MASK	0x0300
++#define TXX9_NDFMCR_DMAREQ_NODMA	0x0000
++#define TXX9_NDFMCR_DMAREQ_128	0x0100
++#define TXX9_NDFMCR_DMAREQ_256	0x0200
++#define TXX9_NDFMCR_DMAREQ_512	0x0300
++#define TXX9_NDFMCR_CS_MASK	0x0c
++#define TXX9_NDFMCR_CS(ch)	((ch) << 2)
++
++/* NDFMCR : NDFMC Status */
++#define TXX9_NDFSR_BUSY	0x80
++/* TX4939 only */
++#define TXX9_NDFSR_DMARUN	0x40
++
++/* NDFMCR : NDFMC Reset */
++#define TXX9_NDFRSTR_RST	0x01
++
++struct txx9ndfmc_priv {
++	struct platform_device *dev;
++	struct nand_chip chip;
++	int cs;
++	const char *mtdname;
++};
++
++#define MAX_TXX9NDFMC_DEV	4
++struct txx9ndfmc_drvdata {
++	struct mtd_info *mtds[MAX_TXX9NDFMC_DEV];
++	void __iomem *base;
++	unsigned char hold;	/* in gbusclock */
++	unsigned char spw;	/* in gbusclock */
++	struct nand_hw_control hw_control;
++};
++
++static struct platform_device *mtd_to_platdev(struct mtd_info *mtd)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct txx9ndfmc_priv *txx9_priv = nand_get_controller_data(chip);
++	return txx9_priv->dev;
++}
++
++static void __iomem *ndregaddr(struct platform_device *dev, unsigned int reg)
++{
++	struct txx9ndfmc_drvdata *drvdata = platform_get_drvdata(dev);
++	struct txx9ndfmc_platform_data *plat = dev_get_platdata(&dev->dev);
++
++	return drvdata->base + (reg << plat->shift);
++}
++
++static u32 txx9ndfmc_read(struct platform_device *dev, unsigned int reg)
++{
++	return __raw_readl(ndregaddr(dev, reg));
++}
++
++static void txx9ndfmc_write(struct platform_device *dev,
++			    u32 val, unsigned int reg)
++{
++	__raw_writel(val, ndregaddr(dev, reg));
++}
++
++static uint8_t txx9ndfmc_read_byte(struct mtd_info *mtd)
++{
++	struct platform_device *dev = mtd_to_platdev(mtd);
++
++	return txx9ndfmc_read(dev, TXX9_NDFDTR);
++}
++
++static void txx9ndfmc_write_buf(struct mtd_info *mtd, const uint8_t *buf,
++				int len)
++{
++	struct platform_device *dev = mtd_to_platdev(mtd);
++	void __iomem *ndfdtr = ndregaddr(dev, TXX9_NDFDTR);
++	u32 mcr = txx9ndfmc_read(dev, TXX9_NDFMCR);
++
++	txx9ndfmc_write(dev, mcr | TXX9_NDFMCR_WE, TXX9_NDFMCR);
++	while (len--)
++		__raw_writel(*buf++, ndfdtr);
++	txx9ndfmc_write(dev, mcr, TXX9_NDFMCR);
++}
++
++static void txx9ndfmc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
++{
++	struct platform_device *dev = mtd_to_platdev(mtd);
++	void __iomem *ndfdtr = ndregaddr(dev, TXX9_NDFDTR);
++
++	while (len--)
++		*buf++ = __raw_readl(ndfdtr);
++}
++
++static void txx9ndfmc_cmd_ctrl(struct mtd_info *mtd, int cmd,
++			       unsigned int ctrl)
++{
++	struct nand_chip *chip = mtd_to_nand(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);
++
++	if (ctrl & NAND_CTRL_CHANGE) {
++		u32 mcr = txx9ndfmc_read(dev, TXX9_NDFMCR);
++
++		mcr &= ~(TXX9_NDFMCR_CLE | TXX9_NDFMCR_ALE | TXX9_NDFMCR_CE);
++		mcr |= ctrl & NAND_CLE ? TXX9_NDFMCR_CLE : 0;
++		mcr |= ctrl & NAND_ALE ? TXX9_NDFMCR_ALE : 0;
++		/* TXX9_NDFMCR_CE bit is 0:high 1:low */
++		mcr |= ctrl & NAND_NCE ? TXX9_NDFMCR_CE : 0;
++		if (txx9_priv->cs >= 0 && (ctrl & NAND_NCE)) {
++			mcr &= ~TXX9_NDFMCR_CS_MASK;
++			mcr |= TXX9_NDFMCR_CS(txx9_priv->cs);
++		}
++		txx9ndfmc_write(dev, mcr, TXX9_NDFMCR);
++	}
++	if (cmd != NAND_CMD_NONE)
++		txx9ndfmc_write(dev, cmd & 0xff, TXX9_NDFDTR);
++	if (plat->flags & NDFMC_PLAT_FLAG_DUMMYWRITE) {
++		/* dummy write to update external latch */
++		if ((ctrl & NAND_CTRL_CHANGE) && cmd == NAND_CMD_NONE)
++			txx9ndfmc_write(dev, 0, TXX9_NDFDTR);
++	}
++	mmiowb();
++}
++
++static int txx9ndfmc_dev_ready(struct mtd_info *mtd)
++{
++	struct platform_device *dev = mtd_to_platdev(mtd);
++
++	return !(txx9ndfmc_read(dev, TXX9_NDFSR) & TXX9_NDFSR_BUSY);
++}
++
++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);
++	int eccbytes;
++	u32 mcr = txx9ndfmc_read(dev, TXX9_NDFMCR);
++
++	mcr &= ~TXX9_NDFMCR_ECC_ALL;
++	txx9ndfmc_write(dev, mcr | TXX9_NDFMCR_ECC_OFF, TXX9_NDFMCR);
++	txx9ndfmc_write(dev, mcr | TXX9_NDFMCR_ECC_READ, TXX9_NDFMCR);
++	for (eccbytes = chip->ecc.bytes; eccbytes > 0; eccbytes -= 3) {
++		ecc_code[1] = txx9ndfmc_read(dev, TXX9_NDFDTR);
++		ecc_code[0] = txx9ndfmc_read(dev, TXX9_NDFDTR);
++		ecc_code[2] = txx9ndfmc_read(dev, TXX9_NDFDTR);
++		ecc_code += 3;
++	}
++	txx9ndfmc_write(dev, mcr | TXX9_NDFMCR_ECC_OFF, TXX9_NDFMCR);
++	return 0;
++}
++
++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);
++	int eccsize;
++	int corrected = 0;
++	int stat;
++
++	for (eccsize = chip->ecc.size; eccsize > 0; eccsize -= 256) {
++		stat = __nand_correct_data(buf, read_ecc, calc_ecc, 256);
++		if (stat < 0)
++			return stat;
++		corrected += stat;
++		buf += 256;
++		read_ecc += 3;
++		calc_ecc += 3;
++	}
++	return corrected;
++}
++
++static void txx9ndfmc_enable_hwecc(struct mtd_info *mtd, int mode)
++{
++	struct platform_device *dev = mtd_to_platdev(mtd);
++	u32 mcr = txx9ndfmc_read(dev, TXX9_NDFMCR);
++
++	mcr &= ~TXX9_NDFMCR_ECC_ALL;
++	txx9ndfmc_write(dev, mcr | TXX9_NDFMCR_ECC_RESET, TXX9_NDFMCR);
++	txx9ndfmc_write(dev, mcr | TXX9_NDFMCR_ECC_OFF, TXX9_NDFMCR);
++	txx9ndfmc_write(dev, mcr | TXX9_NDFMCR_ECC_ON, TXX9_NDFMCR);
++}
++
++static void txx9ndfmc_initialize(struct platform_device *dev)
++{
++	struct txx9ndfmc_platform_data *plat = dev_get_platdata(&dev->dev);
++	struct txx9ndfmc_drvdata *drvdata = platform_get_drvdata(dev);
++	int tmout = 100;
++
++	if (plat->flags & NDFMC_PLAT_FLAG_NO_RSTR)
++		; /* no NDFRSTR.  Write to NDFSPR resets the NDFMC. */
++	else {
++		/* reset NDFMC */
++		txx9ndfmc_write(dev,
++				txx9ndfmc_read(dev, TXX9_NDFRSTR) |
++				TXX9_NDFRSTR_RST,
++				TXX9_NDFRSTR);
++		while (txx9ndfmc_read(dev, TXX9_NDFRSTR) & TXX9_NDFRSTR_RST) {
++			if (--tmout == 0) {
++				dev_err(&dev->dev, "reset failed.\n");
++				break;
++			}
++			udelay(1);
++		}
++	}
++	/* setup Hold Time, Strobe Pulse Width */
++	txx9ndfmc_write(dev, (drvdata->hold << 4) | drvdata->spw, TXX9_NDFSPR);
++	txx9ndfmc_write(dev,
++			(plat->flags & NDFMC_PLAT_FLAG_USE_BSPRT) ?
++			TXX9_NDFMCR_BSPRT : 0, TXX9_NDFMCR);
++}
++
++#define TXX9NDFMC_NS_TO_CYC(gbusclk, ns) \
++	DIV_ROUND_UP((ns) * DIV_ROUND_UP(gbusclk, 1000), 1000000)
++
++static int txx9ndfmc_nand_scan(struct mtd_info *mtd)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	int ret;
++
++	ret = nand_scan_ident(mtd, 1, NULL);
++	if (!ret) {
++		if (mtd->writesize >= 512) {
++			/* Hardware ECC 6 byte ECC per 512 Byte data */
++			chip->ecc.size = 512;
++			chip->ecc.bytes = 6;
++		}
++		ret = nand_scan_tail(mtd);
++	}
++	return ret;
++}
++
++static int __init txx9ndfmc_probe(struct platform_device *dev)
++{
++	struct txx9ndfmc_platform_data *plat = dev_get_platdata(&dev->dev);
++	int hold, spw;
++	int i;
++	struct txx9ndfmc_drvdata *drvdata;
++	unsigned long gbusclk = plat->gbus_clock;
++	struct resource *res;
++
++	drvdata = devm_kzalloc(&dev->dev, sizeof(*drvdata), GFP_KERNEL);
++	if (!drvdata)
++		return -ENOMEM;
++	res = platform_get_resource(dev, IORESOURCE_MEM, 0);
++	drvdata->base = devm_ioremap_resource(&dev->dev, res);
++	if (IS_ERR(drvdata->base))
++		return PTR_ERR(drvdata->base);
++
++	hold = plat->hold ?: 20; /* tDH */
++	spw = plat->spw ?: 90; /* max(tREADID, tWP, tRP) */
++
++	hold = TXX9NDFMC_NS_TO_CYC(gbusclk, hold);
++	spw = TXX9NDFMC_NS_TO_CYC(gbusclk, spw);
++	if (plat->flags & NDFMC_PLAT_FLAG_HOLDADD)
++		hold -= 2;	/* actual hold time : (HOLD + 2) BUSCLK */
++	spw -= 1;	/* actual wait time : (SPW + 1) BUSCLK */
++	hold = clamp(hold, 1, 15);
++	drvdata->hold = hold;
++	spw = clamp(spw, 1, 15);
++	drvdata->spw = spw;
++	dev_info(&dev->dev, "CLK:%ldMHz HOLD:%d SPW:%d\n",
++		 (gbusclk + 500000) / 1000000, hold, spw);
++
++	nand_hw_control_init(&drvdata->hw_control);
++
++	platform_set_drvdata(dev, drvdata);
++	txx9ndfmc_initialize(dev);
++
++	for (i = 0; i < MAX_TXX9NDFMC_DEV; i++) {
++		struct txx9ndfmc_priv *txx9_priv;
++		struct nand_chip *chip;
++		struct mtd_info *mtd;
++
++		if (!(plat->ch_mask & (1 << i)))
++			continue;
++		txx9_priv = kzalloc(sizeof(struct txx9ndfmc_priv),
++				    GFP_KERNEL);
++		if (!txx9_priv)
++			continue;
++		chip = &txx9_priv->chip;
++		mtd = nand_to_mtd(chip);
++		mtd->dev.parent = &dev->dev;
++
++		chip->read_byte = txx9ndfmc_read_byte;
++		chip->read_buf = txx9ndfmc_read_buf;
++		chip->write_buf = txx9ndfmc_write_buf;
++		chip->cmd_ctrl = txx9ndfmc_cmd_ctrl;
++		chip->dev_ready = txx9ndfmc_dev_ready;
++		chip->ecc.calculate = txx9ndfmc_calculate_ecc;
++		chip->ecc.correct = txx9ndfmc_correct_data;
++		chip->ecc.hwctl = txx9ndfmc_enable_hwecc;
++		chip->ecc.mode = NAND_ECC_HW;
++		/* txx9ndfmc_nand_scan will overwrite ecc.size and ecc.bytes */
++		chip->ecc.size = 256;
++		chip->ecc.bytes = 3;
++		chip->ecc.strength = 1;
++		chip->chip_delay = 100;
++		chip->controller = &drvdata->hw_control;
++
++		nand_set_controller_data(chip, txx9_priv);
++		txx9_priv->dev = dev;
++
++		if (plat->ch_mask != 1) {
++			txx9_priv->cs = i;
++			txx9_priv->mtdname = kasprintf(GFP_KERNEL, "%s.%u",
++						       dev_name(&dev->dev), i);
++		} else {
++			txx9_priv->cs = -1;
++			txx9_priv->mtdname = kstrdup(dev_name(&dev->dev),
++						     GFP_KERNEL);
++		}
++		if (!txx9_priv->mtdname) {
++			kfree(txx9_priv);
++			dev_err(&dev->dev, "Unable to allocate MTD name.\n");
++			continue;
++		}
++		if (plat->wide_mask & (1 << i))
++			chip->options |= NAND_BUSWIDTH_16;
++
++		if (txx9ndfmc_nand_scan(mtd)) {
++			kfree(txx9_priv->mtdname);
++			kfree(txx9_priv);
++			continue;
++		}
++		mtd->name = txx9_priv->mtdname;
++
++		mtd_device_parse_register(mtd, NULL, NULL, NULL, 0);
++		drvdata->mtds[i] = mtd;
++	}
++
++	return 0;
++}
++
++static int __exit txx9ndfmc_remove(struct platform_device *dev)
++{
++	struct txx9ndfmc_drvdata *drvdata = platform_get_drvdata(dev);
++	int i;
++
++	if (!drvdata)
++		return 0;
++	for (i = 0; i < MAX_TXX9NDFMC_DEV; i++) {
++		struct mtd_info *mtd = drvdata->mtds[i];
++		struct nand_chip *chip;
++		struct txx9ndfmc_priv *txx9_priv;
++
++		if (!mtd)
++			continue;
++		chip = mtd_to_nand(mtd);
++		txx9_priv = nand_get_controller_data(chip);
++
++		nand_release(mtd);
++		kfree(txx9_priv->mtdname);
++		kfree(txx9_priv);
++	}
++	return 0;
++}
++
++#ifdef CONFIG_PM
++static int txx9ndfmc_resume(struct platform_device *dev)
++{
++	if (platform_get_drvdata(dev))
++		txx9ndfmc_initialize(dev);
++	return 0;
++}
++#else
++#define txx9ndfmc_resume NULL
++#endif
++
++static struct platform_driver txx9ndfmc_driver = {
++	.remove		= __exit_p(txx9ndfmc_remove),
++	.resume		= txx9ndfmc_resume,
++	.driver		= {
++		.name	= "txx9ndfmc",
++	},
++};
++
++module_platform_driver_probe(txx9ndfmc_driver, txx9ndfmc_probe);
++
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("TXx9 SoC NAND flash controller driver");
++MODULE_ALIAS("platform:txx9ndfmc");
+diff --git a/drivers/mtd/nand/raw/vf610_nfc.c b/drivers/mtd/nand/raw/vf610_nfc.c
+new file mode 100644
+index 0000000..8037d4b
+--- /dev/null
++++ b/drivers/mtd/nand/raw/vf610_nfc.c
+@@ -0,0 +1,847 @@
++/*
++ * Copyright 2009-2015 Freescale Semiconductor, Inc. and others
++ *
++ * Description: MPC5125, VF610, MCF54418 and Kinetis K70 Nand driver.
++ * Jason ported to M54418TWR and MVFA5 (VF610).
++ * Authors: Stefan Agner <stefan.agner@toradex.com>
++ *          Bill Pringlemeir <bpringlemeir@nbsps.com>
++ *          Shaohui Xie <b21989@freescale.com>
++ *          Jason Jin <Jason.jin@freescale.com>
++ *
++ * Based on original driver mpc5121_nfc.c.
++ *
++ * This 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.
++ *
++ * Limitations:
++ * - Untested on MPC5125 and M54418.
++ * - DMA and pipelining not used.
++ * - 2K pages or less.
++ * - HW ECC: Only 2K page with 64+ OOB.
++ * - HW ECC: Only 24 and 32-bit error correction implemented.
++ */
++
++#include <linux/module.h>
++#include <linux/bitops.h>
++#include <linux/clk.h>
++#include <linux/delay.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/io.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/rawnand.h>
++#include <linux/mtd/partitions.h>
++#include <linux/of_device.h>
++#include <linux/platform_device.h>
++#include <linux/slab.h>
++
++#define	DRV_NAME		"vf610_nfc"
++
++/* Register Offsets */
++#define NFC_FLASH_CMD1			0x3F00
++#define NFC_FLASH_CMD2			0x3F04
++#define NFC_COL_ADDR			0x3F08
++#define NFC_ROW_ADDR			0x3F0c
++#define NFC_ROW_ADDR_INC		0x3F14
++#define NFC_FLASH_STATUS1		0x3F18
++#define NFC_FLASH_STATUS2		0x3F1c
++#define NFC_CACHE_SWAP			0x3F28
++#define NFC_SECTOR_SIZE			0x3F2c
++#define NFC_FLASH_CONFIG		0x3F30
++#define NFC_IRQ_STATUS			0x3F38
++
++/* Addresses for NFC MAIN RAM BUFFER areas */
++#define NFC_MAIN_AREA(n)		((n) *  0x1000)
++
++#define PAGE_2K				0x0800
++#define OOB_64				0x0040
++#define OOB_MAX				0x0100
++
++/*
++ * NFC_CMD2[CODE] values. See section:
++ *  - 31.4.7 Flash Command Code Description, Vybrid manual
++ *  - 23.8.6 Flash Command Sequencer, MPC5125 manual
++ *
++ * Briefly these are bitmasks of controller cycles.
++ */
++#define READ_PAGE_CMD_CODE		0x7EE0
++#define READ_ONFI_PARAM_CMD_CODE	0x4860
++#define PROGRAM_PAGE_CMD_CODE		0x7FC0
++#define ERASE_CMD_CODE			0x4EC0
++#define READ_ID_CMD_CODE		0x4804
++#define RESET_CMD_CODE			0x4040
++#define STATUS_READ_CMD_CODE		0x4068
++
++/* NFC ECC mode define */
++#define ECC_BYPASS			0
++#define ECC_45_BYTE			6
++#define ECC_60_BYTE			7
++
++/*** Register Mask and bit definitions */
++
++/* NFC_FLASH_CMD1 Field */
++#define CMD_BYTE2_MASK				0xFF000000
++#define CMD_BYTE2_SHIFT				24
++
++/* NFC_FLASH_CM2 Field */
++#define CMD_BYTE1_MASK				0xFF000000
++#define CMD_BYTE1_SHIFT				24
++#define CMD_CODE_MASK				0x00FFFF00
++#define CMD_CODE_SHIFT				8
++#define BUFNO_MASK				0x00000006
++#define BUFNO_SHIFT				1
++#define START_BIT				BIT(0)
++
++/* NFC_COL_ADDR Field */
++#define COL_ADDR_MASK				0x0000FFFF
++#define COL_ADDR_SHIFT				0
++
++/* NFC_ROW_ADDR Field */
++#define ROW_ADDR_MASK				0x00FFFFFF
++#define ROW_ADDR_SHIFT				0
++#define ROW_ADDR_CHIP_SEL_RB_MASK		0xF0000000
++#define ROW_ADDR_CHIP_SEL_RB_SHIFT		28
++#define ROW_ADDR_CHIP_SEL_MASK			0x0F000000
++#define ROW_ADDR_CHIP_SEL_SHIFT			24
++
++/* NFC_FLASH_STATUS2 Field */
++#define STATUS_BYTE1_MASK			0x000000FF
++
++/* NFC_FLASH_CONFIG Field */
++#define CONFIG_ECC_SRAM_ADDR_MASK		0x7FC00000
++#define CONFIG_ECC_SRAM_ADDR_SHIFT		22
++#define CONFIG_ECC_SRAM_REQ_BIT			BIT(21)
++#define CONFIG_DMA_REQ_BIT			BIT(20)
++#define CONFIG_ECC_MODE_MASK			0x000E0000
++#define CONFIG_ECC_MODE_SHIFT			17
++#define CONFIG_FAST_FLASH_BIT			BIT(16)
++#define CONFIG_16BIT				BIT(7)
++#define CONFIG_BOOT_MODE_BIT			BIT(6)
++#define CONFIG_ADDR_AUTO_INCR_BIT		BIT(5)
++#define CONFIG_BUFNO_AUTO_INCR_BIT		BIT(4)
++#define CONFIG_PAGE_CNT_MASK			0xF
++#define CONFIG_PAGE_CNT_SHIFT			0
++
++/* NFC_IRQ_STATUS Field */
++#define IDLE_IRQ_BIT				BIT(29)
++#define IDLE_EN_BIT				BIT(20)
++#define CMD_DONE_CLEAR_BIT			BIT(18)
++#define IDLE_CLEAR_BIT				BIT(17)
++
++/*
++ * ECC status - seems to consume 8 bytes (double word). The documented
++ * status byte is located in the lowest byte of the second word (which is
++ * the 4th or 7th byte depending on endianness).
++ * Calculate an offset to store the ECC status at the end of the buffer.
++ */
++#define ECC_SRAM_ADDR		(PAGE_2K + OOB_MAX - 8)
++
++#define ECC_STATUS		0x4
++#define ECC_STATUS_MASK		0x80
++#define ECC_STATUS_ERR_COUNT	0x3F
++
++enum vf610_nfc_alt_buf {
++	ALT_BUF_DATA = 0,
++	ALT_BUF_ID = 1,
++	ALT_BUF_STAT = 2,
++	ALT_BUF_ONFI = 3,
++};
++
++enum vf610_nfc_variant {
++	NFC_VFC610 = 1,
++};
++
++struct vf610_nfc {
++	struct nand_chip chip;
++	struct device *dev;
++	void __iomem *regs;
++	struct completion cmd_done;
++	uint buf_offset;
++	int write_sz;
++	/* Status and ID are in alternate locations. */
++	enum vf610_nfc_alt_buf alt_buf;
++	enum vf610_nfc_variant variant;
++	struct clk *clk;
++	bool use_hw_ecc;
++	u32 ecc_mode;
++};
++
++static inline struct vf610_nfc *mtd_to_nfc(struct mtd_info *mtd)
++{
++	return container_of(mtd_to_nand(mtd), struct vf610_nfc, chip);
++}
++
++static inline u32 vf610_nfc_read(struct vf610_nfc *nfc, uint reg)
++{
++	return readl(nfc->regs + reg);
++}
++
++static inline void vf610_nfc_write(struct vf610_nfc *nfc, uint reg, u32 val)
++{
++	writel(val, nfc->regs + reg);
++}
++
++static inline void vf610_nfc_set(struct vf610_nfc *nfc, uint reg, u32 bits)
++{
++	vf610_nfc_write(nfc, reg, vf610_nfc_read(nfc, reg) | bits);
++}
++
++static inline void vf610_nfc_clear(struct vf610_nfc *nfc, uint reg, u32 bits)
++{
++	vf610_nfc_write(nfc, reg, vf610_nfc_read(nfc, reg) & ~bits);
++}
++
++static inline void vf610_nfc_set_field(struct vf610_nfc *nfc, u32 reg,
++				       u32 mask, u32 shift, u32 val)
++{
++	vf610_nfc_write(nfc, reg,
++			(vf610_nfc_read(nfc, reg) & (~mask)) | val << shift);
++}
++
++static inline void vf610_nfc_memcpy(void *dst, const void __iomem *src,
++				    size_t n)
++{
++	/*
++	 * Use this accessor for the internal SRAM buffers. On the ARM
++	 * Freescale Vybrid SoC it's known that the driver can treat
++	 * the SRAM buffer as if it's memory. Other platform might need
++	 * to treat the buffers differently.
++	 *
++	 * For the time being, use memcpy
++	 */
++	memcpy(dst, src, n);
++}
++
++/* Clear flags for upcoming command */
++static inline void vf610_nfc_clear_status(struct vf610_nfc *nfc)
++{
++	u32 tmp = vf610_nfc_read(nfc, NFC_IRQ_STATUS);
++
++	tmp |= CMD_DONE_CLEAR_BIT | IDLE_CLEAR_BIT;
++	vf610_nfc_write(nfc, NFC_IRQ_STATUS, tmp);
++}
++
++static void vf610_nfc_done(struct vf610_nfc *nfc)
++{
++	unsigned long timeout = msecs_to_jiffies(100);
++
++	/*
++	 * Barrier is needed after this write. This write need
++	 * to be done before reading the next register the first
++	 * time.
++	 * vf610_nfc_set implicates such a barrier by using writel
++	 * to write to the register.
++	 */
++	vf610_nfc_set(nfc, NFC_IRQ_STATUS, IDLE_EN_BIT);
++	vf610_nfc_set(nfc, NFC_FLASH_CMD2, START_BIT);
++
++	if (!wait_for_completion_timeout(&nfc->cmd_done, timeout))
++		dev_warn(nfc->dev, "Timeout while waiting for BUSY.\n");
++
++	vf610_nfc_clear_status(nfc);
++}
++
++static u8 vf610_nfc_get_id(struct vf610_nfc *nfc, int col)
++{
++	u32 flash_id;
++
++	if (col < 4) {
++		flash_id = vf610_nfc_read(nfc, NFC_FLASH_STATUS1);
++		flash_id >>= (3 - col) * 8;
++	} else {
++		flash_id = vf610_nfc_read(nfc, NFC_FLASH_STATUS2);
++		flash_id >>= 24;
++	}
++
++	return flash_id & 0xff;
++}
++
++static u8 vf610_nfc_get_status(struct vf610_nfc *nfc)
++{
++	return vf610_nfc_read(nfc, NFC_FLASH_STATUS2) & STATUS_BYTE1_MASK;
++}
++
++static void vf610_nfc_send_command(struct vf610_nfc *nfc, u32 cmd_byte1,
++				   u32 cmd_code)
++{
++	u32 tmp;
++
++	vf610_nfc_clear_status(nfc);
++
++	tmp = vf610_nfc_read(nfc, NFC_FLASH_CMD2);
++	tmp &= ~(CMD_BYTE1_MASK | CMD_CODE_MASK | BUFNO_MASK);
++	tmp |= cmd_byte1 << CMD_BYTE1_SHIFT;
++	tmp |= cmd_code << CMD_CODE_SHIFT;
++	vf610_nfc_write(nfc, NFC_FLASH_CMD2, tmp);
++}
++
++static void vf610_nfc_send_commands(struct vf610_nfc *nfc, u32 cmd_byte1,
++				    u32 cmd_byte2, u32 cmd_code)
++{
++	u32 tmp;
++
++	vf610_nfc_send_command(nfc, cmd_byte1, cmd_code);
++
++	tmp = vf610_nfc_read(nfc, NFC_FLASH_CMD1);
++	tmp &= ~CMD_BYTE2_MASK;
++	tmp |= cmd_byte2 << CMD_BYTE2_SHIFT;
++	vf610_nfc_write(nfc, NFC_FLASH_CMD1, tmp);
++}
++
++static irqreturn_t vf610_nfc_irq(int irq, void *data)
++{
++	struct mtd_info *mtd = data;
++	struct vf610_nfc *nfc = mtd_to_nfc(mtd);
++
++	vf610_nfc_clear(nfc, NFC_IRQ_STATUS, IDLE_EN_BIT);
++	complete(&nfc->cmd_done);
++
++	return IRQ_HANDLED;
++}
++
++static void vf610_nfc_addr_cycle(struct vf610_nfc *nfc, int column, int page)
++{
++	if (column != -1) {
++		if (nfc->chip.options & NAND_BUSWIDTH_16)
++			column = column / 2;
++		vf610_nfc_set_field(nfc, NFC_COL_ADDR, COL_ADDR_MASK,
++				    COL_ADDR_SHIFT, column);
++	}
++	if (page != -1)
++		vf610_nfc_set_field(nfc, NFC_ROW_ADDR, ROW_ADDR_MASK,
++				    ROW_ADDR_SHIFT, page);
++}
++
++static inline void vf610_nfc_ecc_mode(struct vf610_nfc *nfc, int ecc_mode)
++{
++	vf610_nfc_set_field(nfc, NFC_FLASH_CONFIG,
++			    CONFIG_ECC_MODE_MASK,
++			    CONFIG_ECC_MODE_SHIFT, ecc_mode);
++}
++
++static inline void vf610_nfc_transfer_size(struct vf610_nfc *nfc, int size)
++{
++	vf610_nfc_write(nfc, NFC_SECTOR_SIZE, size);
++}
++
++static void vf610_nfc_command(struct mtd_info *mtd, unsigned command,
++			      int column, int page)
++{
++	struct vf610_nfc *nfc = mtd_to_nfc(mtd);
++	int trfr_sz = nfc->chip.options & NAND_BUSWIDTH_16 ? 1 : 0;
++
++	nfc->buf_offset = max(column, 0);
++	nfc->alt_buf = ALT_BUF_DATA;
++
++	switch (command) {
++	case NAND_CMD_SEQIN:
++		/* Use valid column/page from preread... */
++		vf610_nfc_addr_cycle(nfc, column, page);
++		nfc->buf_offset = 0;
++
++		/*
++		 * SEQIN => data => PAGEPROG sequence is done by the controller
++		 * hence we do not need to issue the command here...
++		 */
++		return;
++	case NAND_CMD_PAGEPROG:
++		trfr_sz += nfc->write_sz;
++		vf610_nfc_transfer_size(nfc, trfr_sz);
++		vf610_nfc_send_commands(nfc, NAND_CMD_SEQIN,
++					command, PROGRAM_PAGE_CMD_CODE);
++		if (nfc->use_hw_ecc)
++			vf610_nfc_ecc_mode(nfc, nfc->ecc_mode);
++		else
++			vf610_nfc_ecc_mode(nfc, ECC_BYPASS);
++		break;
++
++	case NAND_CMD_RESET:
++		vf610_nfc_transfer_size(nfc, 0);
++		vf610_nfc_send_command(nfc, command, RESET_CMD_CODE);
++		break;
++
++	case NAND_CMD_READOOB:
++		trfr_sz += mtd->oobsize;
++		column = mtd->writesize;
++		vf610_nfc_transfer_size(nfc, trfr_sz);
++		vf610_nfc_send_commands(nfc, NAND_CMD_READ0,
++					NAND_CMD_READSTART, READ_PAGE_CMD_CODE);
++		vf610_nfc_addr_cycle(nfc, column, page);
++		vf610_nfc_ecc_mode(nfc, ECC_BYPASS);
++		break;
++
++	case NAND_CMD_READ0:
++		trfr_sz += mtd->writesize + mtd->oobsize;
++		vf610_nfc_transfer_size(nfc, trfr_sz);
++		vf610_nfc_send_commands(nfc, NAND_CMD_READ0,
++					NAND_CMD_READSTART, READ_PAGE_CMD_CODE);
++		vf610_nfc_addr_cycle(nfc, column, page);
++		vf610_nfc_ecc_mode(nfc, nfc->ecc_mode);
++		break;
++
++	case NAND_CMD_PARAM:
++		nfc->alt_buf = ALT_BUF_ONFI;
++		trfr_sz = 3 * sizeof(struct nand_onfi_params);
++		vf610_nfc_transfer_size(nfc, trfr_sz);
++		vf610_nfc_send_command(nfc, command, READ_ONFI_PARAM_CMD_CODE);
++		vf610_nfc_addr_cycle(nfc, -1, column);
++		vf610_nfc_ecc_mode(nfc, ECC_BYPASS);
++		break;
++
++	case NAND_CMD_ERASE1:
++		vf610_nfc_transfer_size(nfc, 0);
++		vf610_nfc_send_commands(nfc, command,
++					NAND_CMD_ERASE2, ERASE_CMD_CODE);
++		vf610_nfc_addr_cycle(nfc, column, page);
++		break;
++
++	case NAND_CMD_READID:
++		nfc->alt_buf = ALT_BUF_ID;
++		nfc->buf_offset = 0;
++		vf610_nfc_transfer_size(nfc, 0);
++		vf610_nfc_send_command(nfc, command, READ_ID_CMD_CODE);
++		vf610_nfc_addr_cycle(nfc, -1, column);
++		break;
++
++	case NAND_CMD_STATUS:
++		nfc->alt_buf = ALT_BUF_STAT;
++		vf610_nfc_transfer_size(nfc, 0);
++		vf610_nfc_send_command(nfc, command, STATUS_READ_CMD_CODE);
++		break;
++	default:
++		return;
++	}
++
++	vf610_nfc_done(nfc);
++
++	nfc->use_hw_ecc = false;
++	nfc->write_sz = 0;
++}
++
++static void vf610_nfc_read_buf(struct mtd_info *mtd, u_char *buf, int len)
++{
++	struct vf610_nfc *nfc = mtd_to_nfc(mtd);
++	uint c = nfc->buf_offset;
++
++	/* Alternate buffers are only supported through read_byte */
++	WARN_ON(nfc->alt_buf);
++
++	vf610_nfc_memcpy(buf, nfc->regs + NFC_MAIN_AREA(0) + c, len);
++
++	nfc->buf_offset += len;
++}
++
++static void vf610_nfc_write_buf(struct mtd_info *mtd, const uint8_t *buf,
++				int len)
++{
++	struct vf610_nfc *nfc = mtd_to_nfc(mtd);
++	uint c = nfc->buf_offset;
++	uint l;
++
++	l = min_t(uint, len, mtd->writesize + mtd->oobsize - c);
++	vf610_nfc_memcpy(nfc->regs + NFC_MAIN_AREA(0) + c, buf, l);
++
++	nfc->write_sz += l;
++	nfc->buf_offset += l;
++}
++
++static uint8_t vf610_nfc_read_byte(struct mtd_info *mtd)
++{
++	struct vf610_nfc *nfc = mtd_to_nfc(mtd);
++	u8 tmp;
++	uint c = nfc->buf_offset;
++
++	switch (nfc->alt_buf) {
++	case ALT_BUF_ID:
++		tmp = vf610_nfc_get_id(nfc, c);
++		break;
++	case ALT_BUF_STAT:
++		tmp = vf610_nfc_get_status(nfc);
++		break;
++#ifdef __LITTLE_ENDIAN
++	case ALT_BUF_ONFI:
++		/* Reverse byte since the controller uses big endianness */
++		c = nfc->buf_offset ^ 0x3;
++		/* fall-through */
++#endif
++	default:
++		tmp = *((u8 *)(nfc->regs + NFC_MAIN_AREA(0) + c));
++		break;
++	}
++	nfc->buf_offset++;
++	return tmp;
++}
++
++static u16 vf610_nfc_read_word(struct mtd_info *mtd)
++{
++	u16 tmp;
++
++	vf610_nfc_read_buf(mtd, (u_char *)&tmp, sizeof(tmp));
++	return tmp;
++}
++
++/* If not provided, upper layers apply a fixed delay. */
++static int vf610_nfc_dev_ready(struct mtd_info *mtd)
++{
++	/* NFC handles R/B internally; always ready.  */
++	return 1;
++}
++
++/*
++ * This function supports Vybrid only (MPC5125 would have full RB and four CS)
++ */
++static void vf610_nfc_select_chip(struct mtd_info *mtd, int chip)
++{
++	struct vf610_nfc *nfc = mtd_to_nfc(mtd);
++	u32 tmp = vf610_nfc_read(nfc, NFC_ROW_ADDR);
++
++	/* Vybrid only (MPC5125 would have full RB and four CS) */
++	if (nfc->variant != NFC_VFC610)
++		return;
++
++	tmp &= ~(ROW_ADDR_CHIP_SEL_RB_MASK | ROW_ADDR_CHIP_SEL_MASK);
++
++	if (chip >= 0) {
++		tmp |= 1 << ROW_ADDR_CHIP_SEL_RB_SHIFT;
++		tmp |= BIT(chip) << ROW_ADDR_CHIP_SEL_SHIFT;
++	}
++
++	vf610_nfc_write(nfc, NFC_ROW_ADDR, tmp);
++}
++
++/* Count the number of 0's in buff up to max_bits */
++static inline int count_written_bits(uint8_t *buff, int size, int max_bits)
++{
++	uint32_t *buff32 = (uint32_t *)buff;
++	int k, written_bits = 0;
++
++	for (k = 0; k < (size / 4); k++) {
++		written_bits += hweight32(~buff32[k]);
++		if (unlikely(written_bits > max_bits))
++			break;
++	}
++
++	return written_bits;
++}
++
++static inline int vf610_nfc_correct_data(struct mtd_info *mtd, uint8_t *dat,
++					 uint8_t *oob, int page)
++{
++	struct vf610_nfc *nfc = mtd_to_nfc(mtd);
++	u32 ecc_status_off = NFC_MAIN_AREA(0) + ECC_SRAM_ADDR + ECC_STATUS;
++	u8 ecc_status;
++	u8 ecc_count;
++	int flips_threshold = nfc->chip.ecc.strength / 2;
++
++	ecc_status = vf610_nfc_read(nfc, ecc_status_off) & 0xff;
++	ecc_count = ecc_status & ECC_STATUS_ERR_COUNT;
++
++	if (!(ecc_status & ECC_STATUS_MASK))
++		return ecc_count;
++
++	/* Read OOB without ECC unit enabled */
++	vf610_nfc_command(mtd, NAND_CMD_READOOB, 0, page);
++	vf610_nfc_read_buf(mtd, oob, mtd->oobsize);
++
++	/*
++	 * On an erased page, bit count (including OOB) should be zero or
++	 * at least less then half of the ECC strength.
++	 */
++	return nand_check_erased_ecc_chunk(dat, nfc->chip.ecc.size, oob,
++					   mtd->oobsize, NULL, 0,
++					   flips_threshold);
++}
++
++static int vf610_nfc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
++				uint8_t *buf, int oob_required, int page)
++{
++	int eccsize = chip->ecc.size;
++	int stat;
++
++	vf610_nfc_read_buf(mtd, buf, eccsize);
++	if (oob_required)
++		vf610_nfc_read_buf(mtd, chip->oob_poi, mtd->oobsize);
++
++	stat = vf610_nfc_correct_data(mtd, buf, chip->oob_poi, page);
++
++	if (stat < 0) {
++		mtd->ecc_stats.failed++;
++		return 0;
++	} else {
++		mtd->ecc_stats.corrected += stat;
++		return stat;
++	}
++}
++
++static int vf610_nfc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
++				const uint8_t *buf, int oob_required, int page)
++{
++	struct vf610_nfc *nfc = mtd_to_nfc(mtd);
++
++	vf610_nfc_write_buf(mtd, buf, mtd->writesize);
++	if (oob_required)
++		vf610_nfc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
++
++	/* Always write whole page including OOB due to HW ECC */
++	nfc->use_hw_ecc = true;
++	nfc->write_sz = mtd->writesize + mtd->oobsize;
++
++	return 0;
++}
++
++static const struct of_device_id vf610_nfc_dt_ids[] = {
++	{ .compatible = "fsl,vf610-nfc", .data = (void *)NFC_VFC610 },
++	{ /* sentinel */ }
++};
++MODULE_DEVICE_TABLE(of, vf610_nfc_dt_ids);
++
++static void vf610_nfc_preinit_controller(struct vf610_nfc *nfc)
++{
++	vf610_nfc_clear(nfc, NFC_FLASH_CONFIG, CONFIG_16BIT);
++	vf610_nfc_clear(nfc, NFC_FLASH_CONFIG, CONFIG_ADDR_AUTO_INCR_BIT);
++	vf610_nfc_clear(nfc, NFC_FLASH_CONFIG, CONFIG_BUFNO_AUTO_INCR_BIT);
++	vf610_nfc_clear(nfc, NFC_FLASH_CONFIG, CONFIG_BOOT_MODE_BIT);
++	vf610_nfc_clear(nfc, NFC_FLASH_CONFIG, CONFIG_DMA_REQ_BIT);
++	vf610_nfc_set(nfc, NFC_FLASH_CONFIG, CONFIG_FAST_FLASH_BIT);
++
++	/* Disable virtual pages, only one elementary transfer unit */
++	vf610_nfc_set_field(nfc, NFC_FLASH_CONFIG, CONFIG_PAGE_CNT_MASK,
++			    CONFIG_PAGE_CNT_SHIFT, 1);
++}
++
++static void vf610_nfc_init_controller(struct vf610_nfc *nfc)
++{
++	if (nfc->chip.options & NAND_BUSWIDTH_16)
++		vf610_nfc_set(nfc, NFC_FLASH_CONFIG, CONFIG_16BIT);
++	else
++		vf610_nfc_clear(nfc, NFC_FLASH_CONFIG, CONFIG_16BIT);
++
++	if (nfc->chip.ecc.mode == NAND_ECC_HW) {
++		/* Set ECC status offset in SRAM */
++		vf610_nfc_set_field(nfc, NFC_FLASH_CONFIG,
++				    CONFIG_ECC_SRAM_ADDR_MASK,
++				    CONFIG_ECC_SRAM_ADDR_SHIFT,
++				    ECC_SRAM_ADDR >> 3);
++
++		/* Enable ECC status in SRAM */
++		vf610_nfc_set(nfc, NFC_FLASH_CONFIG, CONFIG_ECC_SRAM_REQ_BIT);
++	}
++}
++
++static int vf610_nfc_probe(struct platform_device *pdev)
++{
++	struct vf610_nfc *nfc;
++	struct resource *res;
++	struct mtd_info *mtd;
++	struct nand_chip *chip;
++	struct device_node *child;
++	const struct of_device_id *of_id;
++	int err;
++	int irq;
++
++	nfc = devm_kzalloc(&pdev->dev, sizeof(*nfc), GFP_KERNEL);
++	if (!nfc)
++		return -ENOMEM;
++
++	nfc->dev = &pdev->dev;
++	chip = &nfc->chip;
++	mtd = nand_to_mtd(chip);
++
++	mtd->owner = THIS_MODULE;
++	mtd->dev.parent = nfc->dev;
++	mtd->name = DRV_NAME;
++
++	irq = platform_get_irq(pdev, 0);
++	if (irq <= 0)
++		return -EINVAL;
++
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	nfc->regs = devm_ioremap_resource(nfc->dev, res);
++	if (IS_ERR(nfc->regs))
++		return PTR_ERR(nfc->regs);
++
++	nfc->clk = devm_clk_get(&pdev->dev, NULL);
++	if (IS_ERR(nfc->clk))
++		return PTR_ERR(nfc->clk);
++
++	err = clk_prepare_enable(nfc->clk);
++	if (err) {
++		dev_err(nfc->dev, "Unable to enable clock!\n");
++		return err;
++	}
++
++	of_id = of_match_device(vf610_nfc_dt_ids, &pdev->dev);
++	nfc->variant = (enum vf610_nfc_variant)of_id->data;
++
++	for_each_available_child_of_node(nfc->dev->of_node, child) {
++		if (of_device_is_compatible(child, "fsl,vf610-nfc-nandcs")) {
++
++			if (nand_get_flash_node(chip)) {
++				dev_err(nfc->dev,
++					"Only one NAND chip supported!\n");
++				err = -EINVAL;
++				goto error;
++			}
++
++			nand_set_flash_node(chip, child);
++		}
++	}
++
++	if (!nand_get_flash_node(chip)) {
++		dev_err(nfc->dev, "NAND chip sub-node missing!\n");
++		err = -ENODEV;
++		goto err_clk;
++	}
++
++	chip->dev_ready = vf610_nfc_dev_ready;
++	chip->cmdfunc = vf610_nfc_command;
++	chip->read_byte = vf610_nfc_read_byte;
++	chip->read_word = vf610_nfc_read_word;
++	chip->read_buf = vf610_nfc_read_buf;
++	chip->write_buf = vf610_nfc_write_buf;
++	chip->select_chip = vf610_nfc_select_chip;
++	chip->onfi_set_features = nand_onfi_get_set_features_notsupp;
++	chip->onfi_get_features = nand_onfi_get_set_features_notsupp;
++
++	chip->options |= NAND_NO_SUBPAGE_WRITE;
++
++	init_completion(&nfc->cmd_done);
++
++	err = devm_request_irq(nfc->dev, irq, vf610_nfc_irq, 0, DRV_NAME, mtd);
++	if (err) {
++		dev_err(nfc->dev, "Error requesting IRQ!\n");
++		goto error;
++	}
++
++	vf610_nfc_preinit_controller(nfc);
++
++	/* first scan to find the device and get the page size */
++	err = nand_scan_ident(mtd, 1, NULL);
++	if (err)
++		goto error;
++
++	vf610_nfc_init_controller(nfc);
++
++	/* Bad block options. */
++	if (chip->bbt_options & NAND_BBT_USE_FLASH)
++		chip->bbt_options |= NAND_BBT_NO_OOB;
++
++	/* Single buffer only, max 256 OOB minus ECC status */
++	if (mtd->writesize + mtd->oobsize > PAGE_2K + OOB_MAX - 8) {
++		dev_err(nfc->dev, "Unsupported flash page size\n");
++		err = -ENXIO;
++		goto error;
++	}
++
++	if (chip->ecc.mode == NAND_ECC_HW) {
++		if (mtd->writesize != PAGE_2K && mtd->oobsize < 64) {
++			dev_err(nfc->dev, "Unsupported flash with hwecc\n");
++			err = -ENXIO;
++			goto error;
++		}
++
++		if (chip->ecc.size != mtd->writesize) {
++			dev_err(nfc->dev, "Step size needs to be page size\n");
++			err = -ENXIO;
++			goto error;
++		}
++
++		/* Only 64 byte ECC layouts known */
++		if (mtd->oobsize > 64)
++			mtd->oobsize = 64;
++
++		/*
++		 * mtd->ecclayout is not specified here because we're using the
++		 * default large page ECC layout defined in NAND core.
++		 */
++		if (chip->ecc.strength == 32) {
++			nfc->ecc_mode = ECC_60_BYTE;
++			chip->ecc.bytes = 60;
++		} else if (chip->ecc.strength == 24) {
++			nfc->ecc_mode = ECC_45_BYTE;
++			chip->ecc.bytes = 45;
++		} else {
++			dev_err(nfc->dev, "Unsupported ECC strength\n");
++			err = -ENXIO;
++			goto error;
++		}
++
++		chip->ecc.read_page = vf610_nfc_read_page;
++		chip->ecc.write_page = vf610_nfc_write_page;
++
++		chip->ecc.size = PAGE_2K;
++	}
++
++	/* second phase scan */
++	err = nand_scan_tail(mtd);
++	if (err)
++		goto error;
++
++	platform_set_drvdata(pdev, mtd);
++
++	/* Register device in MTD */
++	return mtd_device_register(mtd, NULL, 0);
++
++error:
++	of_node_put(nand_get_flash_node(chip));
++err_clk:
++	clk_disable_unprepare(nfc->clk);
++	return err;
++}
++
++static int vf610_nfc_remove(struct platform_device *pdev)
++{
++	struct mtd_info *mtd = platform_get_drvdata(pdev);
++	struct vf610_nfc *nfc = mtd_to_nfc(mtd);
++
++	nand_release(mtd);
++	clk_disable_unprepare(nfc->clk);
++	return 0;
++}
++
++#ifdef CONFIG_PM_SLEEP
++static int vf610_nfc_suspend(struct device *dev)
++{
++	struct mtd_info *mtd = dev_get_drvdata(dev);
++	struct vf610_nfc *nfc = mtd_to_nfc(mtd);
++
++	clk_disable_unprepare(nfc->clk);
++	return 0;
++}
++
++static int vf610_nfc_resume(struct device *dev)
++{
++	int err;
++
++	struct mtd_info *mtd = dev_get_drvdata(dev);
++	struct vf610_nfc *nfc = mtd_to_nfc(mtd);
++
++	err = clk_prepare_enable(nfc->clk);
++	if (err)
++		return err;
++
++	vf610_nfc_preinit_controller(nfc);
++	vf610_nfc_init_controller(nfc);
++	return 0;
++}
++#endif
++
++static SIMPLE_DEV_PM_OPS(vf610_nfc_pm_ops, vf610_nfc_suspend, vf610_nfc_resume);
++
++static struct platform_driver vf610_nfc_driver = {
++	.driver		= {
++		.name	= DRV_NAME,
++		.of_match_table = vf610_nfc_dt_ids,
++		.pm	= &vf610_nfc_pm_ops,
++	},
++	.probe		= vf610_nfc_probe,
++	.remove		= vf610_nfc_remove,
++};
++
++module_platform_driver(vf610_nfc_driver);
++
++MODULE_AUTHOR("Stefan Agner <stefan.agner@toradex.com>");
++MODULE_DESCRIPTION("Freescale VF610/MPC5125 NFC MTD NAND driver");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/mtd/nand/raw/xway_nand.c b/drivers/mtd/nand/raw/xway_nand.c
+new file mode 100644
+index 0000000..9926b4e
+--- /dev/null
++++ b/drivers/mtd/nand/raw/xway_nand.c
+@@ -0,0 +1,245 @@
++/*
++ *  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.
++ *
++ *  Copyright © 2012 John Crispin <john@phrozen.org>
++ *  Copyright © 2016 Hauke Mehrtens <hauke@hauke-m.de>
++ */
++
++#include <linux/mtd/rawnand.h>
++#include <linux/of_gpio.h>
++#include <linux/of_platform.h>
++
++#include <lantiq_soc.h>
++
++/* nand registers */
++#define EBU_ADDSEL1		0x24
++#define EBU_NAND_CON		0xB0
++#define EBU_NAND_WAIT		0xB4
++#define  NAND_WAIT_RD		BIT(0) /* NAND flash status output */
++#define  NAND_WAIT_WR_C		BIT(3) /* NAND Write/Read complete */
++#define EBU_NAND_ECC0		0xB8
++#define EBU_NAND_ECC_AC		0xBC
++
++/*
++ * nand commands
++ * The pins of the NAND chip are selected based on the address bits of the
++ * "register" read and write. There are no special registers, but an
++ * address range and the lower address bits are used to activate the
++ * correct line. For example when the bit (1 << 2) is set in the address
++ * the ALE pin will be activated.
++ */
++#define NAND_CMD_ALE		BIT(2) /* address latch enable */
++#define NAND_CMD_CLE		BIT(3) /* command latch enable */
++#define NAND_CMD_CS		BIT(4) /* chip select */
++#define NAND_CMD_SE		BIT(5) /* spare area access latch */
++#define NAND_CMD_WP		BIT(6) /* write protect */
++#define NAND_WRITE_CMD		(NAND_CMD_CS | NAND_CMD_CLE)
++#define NAND_WRITE_ADDR		(NAND_CMD_CS | NAND_CMD_ALE)
++#define NAND_WRITE_DATA		(NAND_CMD_CS)
++#define NAND_READ_DATA		(NAND_CMD_CS)
++
++/* we need to tel the ebu which addr we mapped the nand to */
++#define ADDSEL1_MASK(x)		(x << 4)
++#define ADDSEL1_REGEN		1
++
++/* we need to tell the EBU that we have nand attached and set it up properly */
++#define BUSCON1_SETUP		(1 << 22)
++#define BUSCON1_BCGEN_RES	(0x3 << 12)
++#define BUSCON1_WAITWRC2	(2 << 8)
++#define BUSCON1_WAITRDC2	(2 << 6)
++#define BUSCON1_HOLDC1		(1 << 4)
++#define BUSCON1_RECOVC1		(1 << 2)
++#define BUSCON1_CMULT4		1
++
++#define NAND_CON_CE		(1 << 20)
++#define NAND_CON_OUT_CS1	(1 << 10)
++#define NAND_CON_IN_CS1		(1 << 8)
++#define NAND_CON_PRE_P		(1 << 7)
++#define NAND_CON_WP_P		(1 << 6)
++#define NAND_CON_SE_P		(1 << 5)
++#define NAND_CON_CS_P		(1 << 4)
++#define NAND_CON_CSMUX		(1 << 1)
++#define NAND_CON_NANDM		1
++
++struct xway_nand_data {
++	struct nand_chip	chip;
++	unsigned long		csflags;
++	void __iomem		*nandaddr;
++};
++
++static u8 xway_readb(struct mtd_info *mtd, int op)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct xway_nand_data *data = nand_get_controller_data(chip);
++
++	return readb(data->nandaddr + op);
++}
++
++static void xway_writeb(struct mtd_info *mtd, int op, u8 value)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct xway_nand_data *data = nand_get_controller_data(chip);
++
++	writeb(value, data->nandaddr + op);
++}
++
++static void xway_select_chip(struct mtd_info *mtd, int select)
++{
++	struct nand_chip *chip = mtd_to_nand(mtd);
++	struct xway_nand_data *data = nand_get_controller_data(chip);
++
++	switch (select) {
++	case -1:
++		ltq_ebu_w32_mask(NAND_CON_CE, 0, EBU_NAND_CON);
++		ltq_ebu_w32_mask(NAND_CON_NANDM, 0, EBU_NAND_CON);
++		spin_unlock_irqrestore(&ebu_lock, data->csflags);
++		break;
++	case 0:
++		spin_lock_irqsave(&ebu_lock, data->csflags);
++		ltq_ebu_w32_mask(0, NAND_CON_NANDM, EBU_NAND_CON);
++		ltq_ebu_w32_mask(0, NAND_CON_CE, EBU_NAND_CON);
++		break;
++	default:
++		BUG();
++	}
++}
++
++static void xway_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
++{
++	if (cmd == NAND_CMD_NONE)
++		return;
++
++	if (ctrl & NAND_CLE)
++		xway_writeb(mtd, NAND_WRITE_CMD, cmd);
++	else if (ctrl & NAND_ALE)
++		xway_writeb(mtd, NAND_WRITE_ADDR, cmd);
++
++	while ((ltq_ebu_r32(EBU_NAND_WAIT) & NAND_WAIT_WR_C) == 0)
++		;
++}
++
++static int xway_dev_ready(struct mtd_info *mtd)
++{
++	return ltq_ebu_r32(EBU_NAND_WAIT) & NAND_WAIT_RD;
++}
++
++static unsigned char xway_read_byte(struct mtd_info *mtd)
++{
++	return xway_readb(mtd, NAND_READ_DATA);
++}
++
++static void xway_read_buf(struct mtd_info *mtd, u_char *buf, int len)
++{
++	int i;
++
++	for (i = 0; i < len; i++)
++		buf[i] = xway_readb(mtd, NAND_WRITE_DATA);
++}
++
++static void xway_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
++{
++	int i;
++
++	for (i = 0; i < len; i++)
++		xway_writeb(mtd, NAND_WRITE_DATA, buf[i]);
++}
++
++/*
++ * Probe for the NAND device.
++ */
++static int xway_nand_probe(struct platform_device *pdev)
++{
++	struct xway_nand_data *data;
++	struct mtd_info *mtd;
++	struct resource *res;
++	int err;
++	u32 cs;
++	u32 cs_flag = 0;
++
++	/* Allocate memory for the device structure (and zero it) */
++	data = devm_kzalloc(&pdev->dev, sizeof(struct xway_nand_data),
++			    GFP_KERNEL);
++	if (!data)
++		return -ENOMEM;
++
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	data->nandaddr = devm_ioremap_resource(&pdev->dev, res);
++	if (IS_ERR(data->nandaddr))
++		return PTR_ERR(data->nandaddr);
++
++	nand_set_flash_node(&data->chip, pdev->dev.of_node);
++	mtd = nand_to_mtd(&data->chip);
++	mtd->dev.parent = &pdev->dev;
++
++	data->chip.cmd_ctrl = xway_cmd_ctrl;
++	data->chip.dev_ready = xway_dev_ready;
++	data->chip.select_chip = xway_select_chip;
++	data->chip.write_buf = xway_write_buf;
++	data->chip.read_buf = xway_read_buf;
++	data->chip.read_byte = xway_read_byte;
++	data->chip.chip_delay = 30;
++
++	data->chip.ecc.mode = NAND_ECC_SOFT;
++	data->chip.ecc.algo = NAND_ECC_HAMMING;
++
++	platform_set_drvdata(pdev, data);
++	nand_set_controller_data(&data->chip, data);
++
++	/* load our CS from the DT. Either we find a valid 1 or default to 0 */
++	err = of_property_read_u32(pdev->dev.of_node, "lantiq,cs", &cs);
++	if (!err && cs == 1)
++		cs_flag = NAND_CON_IN_CS1 | NAND_CON_OUT_CS1;
++
++	/* setup the EBU to run in NAND mode on our base addr */
++	ltq_ebu_w32(CPHYSADDR(data->nandaddr)
++		    | ADDSEL1_MASK(3) | ADDSEL1_REGEN, EBU_ADDSEL1);
++
++	ltq_ebu_w32(BUSCON1_SETUP | BUSCON1_BCGEN_RES | BUSCON1_WAITWRC2
++		    | BUSCON1_WAITRDC2 | BUSCON1_HOLDC1 | BUSCON1_RECOVC1
++		    | BUSCON1_CMULT4, LTQ_EBU_BUSCON1);
++
++	ltq_ebu_w32(NAND_CON_NANDM | NAND_CON_CSMUX | NAND_CON_CS_P
++		    | NAND_CON_SE_P | NAND_CON_WP_P | NAND_CON_PRE_P
++		    | cs_flag, EBU_NAND_CON);
++
++	/* 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;
++}
++
++/*
++ * Remove a NAND device.
++ */
++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));
++
++	return 0;
++}
++
++static const struct of_device_id xway_nand_match[] = {
++	{ .compatible = "lantiq,nand-xway" },
++	{},
++};
++
++static struct platform_driver xway_nand_driver = {
++	.probe	= xway_nand_probe,
++	.remove	= xway_nand_remove,
++	.driver	= {
++		.name		= "lantiq,nand-xway",
++		.of_match_table = xway_nand_match,
++	},
++};
++
++builtin_platform_driver(xway_nand_driver);
+diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c
+deleted file mode 100644
+index 4c383ee..0000000
+--- a/drivers/mtd/nand/s3c2410.c
++++ /dev/null
+@@ -1,1296 +0,0 @@
+-/* linux/drivers/mtd/nand/s3c2410.c
+- *
+- * Copyright © 2004-2008 Simtec Electronics
+- *	http://armlinux.simtec.co.uk/
+- *	Ben Dooks <ben@simtec.co.uk>
+- *
+- * Samsung S3C2410/S3C2440/S3C2412 NAND driver
+- *
+- * 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.
+- *
+- * You should have received a copy of the GNU General Public License
+- * along with this program; if not, write to the Free Software
+- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+-*/
+-
+-#define pr_fmt(fmt) "nand-s3c2410: " fmt
+-
+-#ifdef CONFIG_MTD_NAND_S3C2410_DEBUG
+-#define DEBUG
+-#endif
+-
+-#include <linux/module.h>
+-#include <linux/types.h>
+-#include <linux/kernel.h>
+-#include <linux/string.h>
+-#include <linux/io.h>
+-#include <linux/ioport.h>
+-#include <linux/platform_device.h>
+-#include <linux/delay.h>
+-#include <linux/err.h>
+-#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/rawnand.h>
+-#include <linux/mtd/nand_ecc.h>
+-#include <linux/mtd/partitions.h>
+-
+-#include <linux/platform_data/mtd-nand-s3c2410.h>
+-
+-#define S3C2410_NFREG(x) (x)
+-
+-#define S3C2410_NFCONF		S3C2410_NFREG(0x00)
+-#define S3C2410_NFCMD		S3C2410_NFREG(0x04)
+-#define S3C2410_NFADDR		S3C2410_NFREG(0x08)
+-#define S3C2410_NFDATA		S3C2410_NFREG(0x0C)
+-#define S3C2410_NFSTAT		S3C2410_NFREG(0x10)
+-#define S3C2410_NFECC		S3C2410_NFREG(0x14)
+-#define S3C2440_NFCONT		S3C2410_NFREG(0x04)
+-#define S3C2440_NFCMD		S3C2410_NFREG(0x08)
+-#define S3C2440_NFADDR		S3C2410_NFREG(0x0C)
+-#define S3C2440_NFDATA		S3C2410_NFREG(0x10)
+-#define S3C2440_NFSTAT		S3C2410_NFREG(0x20)
+-#define S3C2440_NFMECC0		S3C2410_NFREG(0x2C)
+-#define S3C2412_NFSTAT		S3C2410_NFREG(0x28)
+-#define S3C2412_NFMECC0		S3C2410_NFREG(0x34)
+-#define S3C2410_NFCONF_EN		(1<<15)
+-#define S3C2410_NFCONF_INITECC		(1<<12)
+-#define S3C2410_NFCONF_nFCE		(1<<11)
+-#define S3C2410_NFCONF_TACLS(x)		((x)<<8)
+-#define S3C2410_NFCONF_TWRPH0(x)	((x)<<4)
+-#define S3C2410_NFCONF_TWRPH1(x)	((x)<<0)
+-#define S3C2410_NFSTAT_BUSY		(1<<0)
+-#define S3C2440_NFCONF_TACLS(x)		((x)<<12)
+-#define S3C2440_NFCONF_TWRPH0(x)	((x)<<8)
+-#define S3C2440_NFCONF_TWRPH1(x)	((x)<<4)
+-#define S3C2440_NFCONT_INITECC		(1<<4)
+-#define S3C2440_NFCONT_nFCE		(1<<1)
+-#define S3C2440_NFCONT_ENABLE		(1<<0)
+-#define S3C2440_NFSTAT_READY		(1<<0)
+-#define S3C2412_NFCONF_NANDBOOT		(1<<31)
+-#define S3C2412_NFCONT_INIT_MAIN_ECC	(1<<5)
+-#define S3C2412_NFCONT_nFCE0		(1<<1)
+-#define S3C2412_NFSTAT_READY		(1<<0)
+-
+-/* new oob placement block for use with hardware ecc generation
+- */
+-static int s3c2410_ooblayout_ecc(struct mtd_info *mtd, int section,
+-				 struct mtd_oob_region *oobregion)
+-{
+-	if (section)
+-		return -ERANGE;
+-
+-	oobregion->offset = 0;
+-	oobregion->length = 3;
+-
+-	return 0;
+-}
+-
+-static int s3c2410_ooblayout_free(struct mtd_info *mtd, int section,
+-				  struct mtd_oob_region *oobregion)
+-{
+-	if (section)
+-		return -ERANGE;
+-
+-	oobregion->offset = 8;
+-	oobregion->length = 8;
+-
+-	return 0;
+-}
+-
+-static const struct mtd_ooblayout_ops s3c2410_ooblayout_ops = {
+-	.ecc = s3c2410_ooblayout_ecc,
+-	.free = s3c2410_ooblayout_free,
+-};
+-
+-/* controller and mtd information */
+-
+-struct s3c2410_nand_info;
+-
+-/**
+- * struct s3c2410_nand_mtd - driver MTD structure
+- * @mtd: The MTD instance to pass to the MTD layer.
+- * @chip: The NAND chip information.
+- * @set: The platform information supplied for this set of NAND chips.
+- * @info: Link back to the hardware information.
+- * @scan_res: The result from calling nand_scan_ident().
+-*/
+-struct s3c2410_nand_mtd {
+-	struct nand_chip		chip;
+-	struct s3c2410_nand_set		*set;
+-	struct s3c2410_nand_info	*info;
+-	int				scan_res;
+-};
+-
+-enum s3c_cpu_type {
+-	TYPE_S3C2410,
+-	TYPE_S3C2412,
+-	TYPE_S3C2440,
+-};
+-
+-enum s3c_nand_clk_state {
+-	CLOCK_DISABLE	= 0,
+-	CLOCK_ENABLE,
+-	CLOCK_SUSPEND,
+-};
+-
+-/* overview of the s3c2410 nand state */
+-
+-/**
+- * struct s3c2410_nand_info - NAND controller state.
+- * @mtds: An array of MTD instances on this controoler.
+- * @platform: The platform data for this board.
+- * @device: The platform device we bound to.
+- * @clk: The clock resource for this controller.
+- * @regs: The area mapped for the hardware registers.
+- * @sel_reg: Pointer to the register controlling the NAND selection.
+- * @sel_bit: The bit in @sel_reg to select the NAND chip.
+- * @mtd_count: The number of MTDs created from this controller.
+- * @save_sel: The contents of @sel_reg to be saved over suspend.
+- * @clk_rate: The clock rate from @clk.
+- * @clk_state: The current clock state.
+- * @cpu_type: The exact type of this controller.
+- */
+-struct s3c2410_nand_info {
+-	/* mtd info */
+-	struct nand_hw_control		controller;
+-	struct s3c2410_nand_mtd		*mtds;
+-	struct s3c2410_platform_nand	*platform;
+-
+-	/* device info */
+-	struct device			*device;
+-	struct clk			*clk;
+-	void __iomem			*regs;
+-	void __iomem			*sel_reg;
+-	int				sel_bit;
+-	int				mtd_count;
+-	unsigned long			save_sel;
+-	unsigned long			clk_rate;
+-	enum s3c_nand_clk_state		clk_state;
+-
+-	enum s3c_cpu_type		cpu_type;
+-
+-#ifdef CONFIG_ARM_S3C24XX_CPUFREQ
+-	struct notifier_block	freq_transition;
+-#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)
+-{
+-	return container_of(mtd_to_nand(mtd), struct s3c2410_nand_mtd,
+-			    chip);
+-}
+-
+-static struct s3c2410_nand_info *s3c2410_nand_mtd_toinfo(struct mtd_info *mtd)
+-{
+-	return s3c2410_nand_mtd_toours(mtd)->info;
+-}
+-
+-static struct s3c2410_nand_info *to_nand_info(struct platform_device *dev)
+-{
+-	return platform_get_drvdata(dev);
+-}
+-
+-static struct s3c2410_platform_nand *to_nand_plat(struct platform_device *dev)
+-{
+-	return dev_get_platdata(&dev->dev);
+-}
+-
+-static inline int allow_clk_suspend(struct s3c2410_nand_info *info)
+-{
+-#ifdef CONFIG_MTD_NAND_S3C2410_CLKSTOP
+-	return 1;
+-#else
+-	return 0;
+-#endif
+-}
+-
+-/**
+- * s3c2410_nand_clk_set_state - Enable, disable or suspend NAND clock.
+- * @info: The controller instance.
+- * @new_state: State to which clock should be set.
+- */
+-static void s3c2410_nand_clk_set_state(struct s3c2410_nand_info *info,
+-		enum s3c_nand_clk_state new_state)
+-{
+-	if (!allow_clk_suspend(info) && new_state == CLOCK_SUSPEND)
+-		return;
+-
+-	if (info->clk_state == CLOCK_ENABLE) {
+-		if (new_state != CLOCK_ENABLE)
+-			clk_disable_unprepare(info->clk);
+-	} else {
+-		if (new_state == CLOCK_ENABLE)
+-			clk_prepare_enable(info->clk);
+-	}
+-
+-	info->clk_state = new_state;
+-}
+-
+-/* timing calculations */
+-
+-#define NS_IN_KHZ 1000000
+-
+-/**
+- * s3c_nand_calc_rate - calculate timing data.
+- * @wanted: The cycle time in nanoseconds.
+- * @clk: The clock rate in kHz.
+- * @max: The maximum divider value.
+- *
+- * Calculate the timing value from the given parameters.
+- */
+-static int s3c_nand_calc_rate(int wanted, unsigned long clk, int max)
+-{
+-	int result;
+-
+-	result = DIV_ROUND_UP((wanted * clk), NS_IN_KHZ);
+-
+-	pr_debug("result %d from %ld, %d\n", result, clk, wanted);
+-
+-	if (result > max) {
+-		pr_err("%d ns is too big for current clock rate %ld\n",
+-			wanted, clk);
+-		return -1;
+-	}
+-
+-	if (result < 1)
+-		result = 1;
+-
+-	return result;
+-}
+-
+-#define to_ns(ticks, clk) (((ticks) * NS_IN_KHZ) / (unsigned int)(clk))
+-
+-/* controller setup */
+-
+-/**
+- * s3c2410_nand_setrate - setup controller timing information.
+- * @info: The controller instance.
+- *
+- * Given the information supplied by the platform, calculate and set
+- * the necessary timing registers in the hardware to generate the
+- * necessary timing cycles to the hardware.
+- */
+-static int s3c2410_nand_setrate(struct s3c2410_nand_info *info)
+-{
+-	struct s3c2410_platform_nand *plat = info->platform;
+-	int tacls_max = (info->cpu_type == TYPE_S3C2412) ? 8 : 4;
+-	int tacls, twrph0, twrph1;
+-	unsigned long clkrate = clk_get_rate(info->clk);
+-	unsigned long uninitialized_var(set), cfg, uninitialized_var(mask);
+-	unsigned long flags;
+-
+-	/* calculate the timing information for the controller */
+-
+-	info->clk_rate = clkrate;
+-	clkrate /= 1000;	/* turn clock into kHz for ease of use */
+-
+-	if (plat != NULL) {
+-		tacls = s3c_nand_calc_rate(plat->tacls, clkrate, tacls_max);
+-		twrph0 = s3c_nand_calc_rate(plat->twrph0, clkrate, 8);
+-		twrph1 = s3c_nand_calc_rate(plat->twrph1, clkrate, 8);
+-	} else {
+-		/* default timings */
+-		tacls = tacls_max;
+-		twrph0 = 8;
+-		twrph1 = 8;
+-	}
+-
+-	if (tacls < 0 || twrph0 < 0 || twrph1 < 0) {
+-		dev_err(info->device, "cannot get suitable timings\n");
+-		return -EINVAL;
+-	}
+-
+-	dev_info(info->device, "Tacls=%d, %dns Twrph0=%d %dns, Twrph1=%d %dns\n",
+-		tacls, to_ns(tacls, clkrate), twrph0, to_ns(twrph0, clkrate),
+-						twrph1, to_ns(twrph1, clkrate));
+-
+-	switch (info->cpu_type) {
+-	case TYPE_S3C2410:
+-		mask = (S3C2410_NFCONF_TACLS(3) |
+-			S3C2410_NFCONF_TWRPH0(7) |
+-			S3C2410_NFCONF_TWRPH1(7));
+-		set = S3C2410_NFCONF_EN;
+-		set |= S3C2410_NFCONF_TACLS(tacls - 1);
+-		set |= S3C2410_NFCONF_TWRPH0(twrph0 - 1);
+-		set |= S3C2410_NFCONF_TWRPH1(twrph1 - 1);
+-		break;
+-
+-	case TYPE_S3C2440:
+-	case TYPE_S3C2412:
+-		mask = (S3C2440_NFCONF_TACLS(tacls_max - 1) |
+-			S3C2440_NFCONF_TWRPH0(7) |
+-			S3C2440_NFCONF_TWRPH1(7));
+-
+-		set = S3C2440_NFCONF_TACLS(tacls - 1);
+-		set |= S3C2440_NFCONF_TWRPH0(twrph0 - 1);
+-		set |= S3C2440_NFCONF_TWRPH1(twrph1 - 1);
+-		break;
+-
+-	default:
+-		BUG();
+-	}
+-
+-	local_irq_save(flags);
+-
+-	cfg = readl(info->regs + S3C2410_NFCONF);
+-	cfg &= ~mask;
+-	cfg |= set;
+-	writel(cfg, info->regs + S3C2410_NFCONF);
+-
+-	local_irq_restore(flags);
+-
+-	dev_dbg(info->device, "NF_CONF is 0x%lx\n", cfg);
+-
+-	return 0;
+-}
+-
+-/**
+- * s3c2410_nand_inithw - basic hardware initialisation
+- * @info: The hardware state.
+- *
+- * Do the basic initialisation of the hardware, using s3c2410_nand_setrate()
+- * to setup the hardware access speeds and set the controller to be enabled.
+-*/
+-static int s3c2410_nand_inithw(struct s3c2410_nand_info *info)
+-{
+-	int ret;
+-
+-	ret = s3c2410_nand_setrate(info);
+-	if (ret < 0)
+-		return ret;
+-
+-	switch (info->cpu_type) {
+-	case TYPE_S3C2410:
+-	default:
+-		break;
+-
+-	case TYPE_S3C2440:
+-	case TYPE_S3C2412:
+-		/* enable the controller and de-assert nFCE */
+-
+-		writel(S3C2440_NFCONT_ENABLE, info->regs + S3C2440_NFCONT);
+-	}
+-
+-	return 0;
+-}
+-
+-/**
+- * s3c2410_nand_select_chip - select the given nand chip
+- * @mtd: The MTD instance for this chip.
+- * @chip: The chip number.
+- *
+- * This is called by the MTD layer to either select a given chip for the
+- * @mtd instance, or to indicate that the access has finished and the
+- * chip can be de-selected.
+- *
+- * The routine ensures that the nFCE line is correctly setup, and any
+- * platform specific selection code is called to route nFCE to the specific
+- * chip.
+- */
+-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);
+-	unsigned long cur;
+-
+-	nmtd = nand_get_controller_data(this);
+-	info = nmtd->info;
+-
+-	if (chip != -1)
+-		s3c2410_nand_clk_set_state(info, CLOCK_ENABLE);
+-
+-	cur = readl(info->sel_reg);
+-
+-	if (chip == -1) {
+-		cur |= info->sel_bit;
+-	} else {
+-		if (nmtd->set != NULL && chip > nmtd->set->nr_chips) {
+-			dev_err(info->device, "invalid chip %d\n", chip);
+-			return;
+-		}
+-
+-		if (info->platform != NULL) {
+-			if (info->platform->select_chip != NULL)
+-				(info->platform->select_chip) (nmtd->set, chip);
+-		}
+-
+-		cur &= ~info->sel_bit;
+-	}
+-
+-	writel(cur, info->sel_reg);
+-
+-	if (chip == -1)
+-		s3c2410_nand_clk_set_state(info, CLOCK_SUSPEND);
+-}
+-
+-/* s3c2410_nand_hwcontrol
+- *
+- * Issue command and address cycles to the chip
+-*/
+-
+-static void s3c2410_nand_hwcontrol(struct mtd_info *mtd, int cmd,
+-				   unsigned int ctrl)
+-{
+-	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+-
+-	if (cmd == NAND_CMD_NONE)
+-		return;
+-
+-	if (ctrl & NAND_CLE)
+-		writeb(cmd, info->regs + S3C2410_NFCMD);
+-	else
+-		writeb(cmd, info->regs + S3C2410_NFADDR);
+-}
+-
+-/* command and control functions */
+-
+-static void s3c2440_nand_hwcontrol(struct mtd_info *mtd, int cmd,
+-				   unsigned int ctrl)
+-{
+-	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+-
+-	if (cmd == NAND_CMD_NONE)
+-		return;
+-
+-	if (ctrl & NAND_CLE)
+-		writeb(cmd, info->regs + S3C2440_NFCMD);
+-	else
+-		writeb(cmd, info->regs + S3C2440_NFADDR);
+-}
+-
+-/* s3c2410_nand_devready()
+- *
+- * returns 0 if the nand is busy, 1 if it is ready
+-*/
+-
+-static int s3c2410_nand_devready(struct mtd_info *mtd)
+-{
+-	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+-	return readb(info->regs + S3C2410_NFSTAT) & S3C2410_NFSTAT_BUSY;
+-}
+-
+-static int s3c2440_nand_devready(struct mtd_info *mtd)
+-{
+-	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+-	return readb(info->regs + S3C2440_NFSTAT) & S3C2440_NFSTAT_READY;
+-}
+-
+-static int s3c2412_nand_devready(struct mtd_info *mtd)
+-{
+-	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+-	return readb(info->regs + S3C2412_NFSTAT) & S3C2412_NFSTAT_READY;
+-}
+-
+-/* ECC handling functions */
+-
+-static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat,
+-				     u_char *read_ecc, u_char *calc_ecc)
+-{
+-	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+-	unsigned int diff0, diff1, diff2;
+-	unsigned int bit, byte;
+-
+-	pr_debug("%s(%p,%p,%p,%p)\n", __func__, mtd, dat, read_ecc, calc_ecc);
+-
+-	diff0 = read_ecc[0] ^ calc_ecc[0];
+-	diff1 = read_ecc[1] ^ calc_ecc[1];
+-	diff2 = read_ecc[2] ^ calc_ecc[2];
+-
+-	pr_debug("%s: rd %*phN calc %*phN diff %02x%02x%02x\n",
+-		 __func__, 3, read_ecc, 3, calc_ecc,
+-		 diff0, diff1, diff2);
+-
+-	if (diff0 == 0 && diff1 == 0 && diff2 == 0)
+-		return 0;		/* ECC is ok */
+-
+-	/* sometimes people do not think about using the ECC, so check
+-	 * to see if we have an 0xff,0xff,0xff read ECC and then ignore
+-	 * the error, on the assumption that this is an un-eccd page.
+-	 */
+-	if (read_ecc[0] == 0xff && read_ecc[1] == 0xff && read_ecc[2] == 0xff
+-	    && info->platform->ignore_unset_ecc)
+-		return 0;
+-
+-	/* Can we correct this ECC (ie, one row and column change).
+-	 * Note, this is similar to the 256 error code on smartmedia */
+-
+-	if (((diff0 ^ (diff0 >> 1)) & 0x55) == 0x55 &&
+-	    ((diff1 ^ (diff1 >> 1)) & 0x55) == 0x55 &&
+-	    ((diff2 ^ (diff2 >> 1)) & 0x55) == 0x55) {
+-		/* calculate the bit position of the error */
+-
+-		bit  = ((diff2 >> 3) & 1) |
+-		       ((diff2 >> 4) & 2) |
+-		       ((diff2 >> 5) & 4);
+-
+-		/* calculate the byte position of the error */
+-
+-		byte = ((diff2 << 7) & 0x100) |
+-		       ((diff1 << 0) & 0x80)  |
+-		       ((diff1 << 1) & 0x40)  |
+-		       ((diff1 << 2) & 0x20)  |
+-		       ((diff1 << 3) & 0x10)  |
+-		       ((diff0 >> 4) & 0x08)  |
+-		       ((diff0 >> 3) & 0x04)  |
+-		       ((diff0 >> 2) & 0x02)  |
+-		       ((diff0 >> 1) & 0x01);
+-
+-		dev_dbg(info->device, "correcting error bit %d, byte %d\n",
+-			bit, byte);
+-
+-		dat[byte] ^= (1 << bit);
+-		return 1;
+-	}
+-
+-	/* if there is only one bit difference in the ECC, then
+-	 * one of only a row or column parity has changed, which
+-	 * means the error is most probably in the ECC itself */
+-
+-	diff0 |= (diff1 << 8);
+-	diff0 |= (diff2 << 16);
+-
+-	/* equal to "(diff0 & ~(1 << __ffs(diff0)))" */
+-	if ((diff0 & (diff0 - 1)) == 0)
+-		return 1;
+-
+-	return -1;
+-}
+-
+-/* ECC functions
+- *
+- * These allow the s3c2410 and s3c2440 to use the controller's ECC
+- * generator block to ECC the data as it passes through]
+-*/
+-
+-static void s3c2410_nand_enable_hwecc(struct mtd_info *mtd, int mode)
+-{
+-	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+-	unsigned long ctrl;
+-
+-	ctrl = readl(info->regs + S3C2410_NFCONF);
+-	ctrl |= S3C2410_NFCONF_INITECC;
+-	writel(ctrl, info->regs + S3C2410_NFCONF);
+-}
+-
+-static void s3c2412_nand_enable_hwecc(struct mtd_info *mtd, int mode)
+-{
+-	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+-	unsigned long ctrl;
+-
+-	ctrl = readl(info->regs + S3C2440_NFCONT);
+-	writel(ctrl | S3C2412_NFCONT_INIT_MAIN_ECC,
+-	       info->regs + S3C2440_NFCONT);
+-}
+-
+-static void s3c2440_nand_enable_hwecc(struct mtd_info *mtd, int mode)
+-{
+-	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+-	unsigned long ctrl;
+-
+-	ctrl = readl(info->regs + S3C2440_NFCONT);
+-	writel(ctrl | S3C2440_NFCONT_INITECC, info->regs + S3C2440_NFCONT);
+-}
+-
+-static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
+-				      u_char *ecc_code)
+-{
+-	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+-
+-	ecc_code[0] = readb(info->regs + S3C2410_NFECC + 0);
+-	ecc_code[1] = readb(info->regs + S3C2410_NFECC + 1);
+-	ecc_code[2] = readb(info->regs + S3C2410_NFECC + 2);
+-
+-	pr_debug("%s: returning ecc %*phN\n", __func__, 3, ecc_code);
+-
+-	return 0;
+-}
+-
+-static int s3c2412_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
+-				      u_char *ecc_code)
+-{
+-	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+-	unsigned long ecc = readl(info->regs + S3C2412_NFMECC0);
+-
+-	ecc_code[0] = ecc;
+-	ecc_code[1] = ecc >> 8;
+-	ecc_code[2] = ecc >> 16;
+-
+-	pr_debug("%s: returning ecc %*phN\n", __func__, 3, ecc_code);
+-
+-	return 0;
+-}
+-
+-static int s3c2440_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
+-				      u_char *ecc_code)
+-{
+-	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+-	unsigned long ecc = readl(info->regs + S3C2440_NFMECC0);
+-
+-	ecc_code[0] = ecc;
+-	ecc_code[1] = ecc >> 8;
+-	ecc_code[2] = ecc >> 16;
+-
+-	pr_debug("%s: returning ecc %06lx\n", __func__, ecc & 0xffffff);
+-
+-	return 0;
+-}
+-
+-/* 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
+-*/
+-
+-static void s3c2410_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+-{
+-	struct nand_chip *this = mtd_to_nand(mtd);
+-	readsb(this->IO_ADDR_R, buf, len);
+-}
+-
+-static void s3c2440_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+-{
+-	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+-
+-	readsl(info->regs + S3C2440_NFDATA, buf, len >> 2);
+-
+-	/* cleanup if we've got less than a word to do */
+-	if (len & 3) {
+-		buf += len & ~3;
+-
+-		for (; len & 3; len--)
+-			*buf++ = readb(info->regs + S3C2440_NFDATA);
+-	}
+-}
+-
+-static void s3c2410_nand_write_buf(struct mtd_info *mtd, const u_char *buf,
+-				   int len)
+-{
+-	struct nand_chip *this = mtd_to_nand(mtd);
+-	writesb(this->IO_ADDR_W, buf, len);
+-}
+-
+-static void s3c2440_nand_write_buf(struct mtd_info *mtd, const u_char *buf,
+-				   int len)
+-{
+-	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+-
+-	writesl(info->regs + S3C2440_NFDATA, buf, len >> 2);
+-
+-	/* cleanup any fractional write */
+-	if (len & 3) {
+-		buf += len & ~3;
+-
+-		for (; len & 3; len--, buf++)
+-			writeb(*buf, info->regs + S3C2440_NFDATA);
+-	}
+-}
+-
+-/* cpufreq driver support */
+-
+-#ifdef CONFIG_ARM_S3C24XX_CPUFREQ
+-
+-static int s3c2410_nand_cpufreq_transition(struct notifier_block *nb,
+-					  unsigned long val, void *data)
+-{
+-	struct s3c2410_nand_info *info;
+-	unsigned long newclk;
+-
+-	info = container_of(nb, struct s3c2410_nand_info, freq_transition);
+-	newclk = clk_get_rate(info->clk);
+-
+-	if ((val == CPUFREQ_POSTCHANGE && newclk < info->clk_rate) ||
+-	    (val == CPUFREQ_PRECHANGE && newclk > info->clk_rate)) {
+-		s3c2410_nand_setrate(info);
+-	}
+-
+-	return 0;
+-}
+-
+-static inline int s3c2410_nand_cpufreq_register(struct s3c2410_nand_info *info)
+-{
+-	info->freq_transition.notifier_call = s3c2410_nand_cpufreq_transition;
+-
+-	return cpufreq_register_notifier(&info->freq_transition,
+-					 CPUFREQ_TRANSITION_NOTIFIER);
+-}
+-
+-static inline void
+-s3c2410_nand_cpufreq_deregister(struct s3c2410_nand_info *info)
+-{
+-	cpufreq_unregister_notifier(&info->freq_transition,
+-				    CPUFREQ_TRANSITION_NOTIFIER);
+-}
+-
+-#else
+-static inline int s3c2410_nand_cpufreq_register(struct s3c2410_nand_info *info)
+-{
+-	return 0;
+-}
+-
+-static inline void
+-s3c2410_nand_cpufreq_deregister(struct s3c2410_nand_info *info)
+-{
+-}
+-#endif
+-
+-/* device management functions */
+-
+-static int s3c24xx_nand_remove(struct platform_device *pdev)
+-{
+-	struct s3c2410_nand_info *info = to_nand_info(pdev);
+-
+-	if (info == NULL)
+-		return 0;
+-
+-	s3c2410_nand_cpufreq_deregister(info);
+-
+-	/* Release all our mtds  and their partitions, then go through
+-	 * freeing the resources used
+-	 */
+-
+-	if (info->mtds != NULL) {
+-		struct s3c2410_nand_mtd *ptr = info->mtds;
+-		int mtdno;
+-
+-		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));
+-		}
+-	}
+-
+-	/* free the common resources */
+-
+-	if (!IS_ERR(info->clk))
+-		s3c2410_nand_clk_set_state(info, CLOCK_DISABLE);
+-
+-	return 0;
+-}
+-
+-static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info,
+-				      struct s3c2410_nand_mtd *mtd,
+-				      struct s3c2410_nand_set *set)
+-{
+-	if (set) {
+-		struct mtd_info *mtdinfo = nand_to_mtd(&mtd->chip);
+-
+-		mtdinfo->name = set->name;
+-
+-		return mtd_device_parse_register(mtdinfo, NULL, NULL,
+-					 set->partitions, set->nr_partitions);
+-	}
+-
+-	return -ENODEV;
+-}
+-
+-static int s3c2410_nand_setup_data_interface(struct mtd_info *mtd, int csline,
+-					const struct nand_data_interface *conf)
+-{
+-	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.
+- * @nmtd: The new controller MTD instance to fill in.
+- * @set: The information passed from the board specific platform data.
+- *
+- * Initialise the given @nmtd from the information in @info and @set. This
+- * readies the structure for use with the MTD layer functions by ensuring
+- * all pointers are setup and the necessary control routines selected.
+- */
+-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;
+-	chip->chip_delay   = 50;
+-	nand_set_controller_data(chip, nmtd);
+-	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;
+-		info->sel_reg   = regs + S3C2410_NFCONF;
+-		info->sel_bit	= S3C2410_NFCONF_nFCE;
+-		chip->cmd_ctrl  = s3c2410_nand_hwcontrol;
+-		chip->dev_ready = s3c2410_nand_devready;
+-		break;
+-
+-	case TYPE_S3C2440:
+-		chip->IO_ADDR_W = regs + S3C2440_NFDATA;
+-		info->sel_reg   = regs + S3C2440_NFCONT;
+-		info->sel_bit	= S3C2440_NFCONT_nFCE;
+-		chip->cmd_ctrl  = s3c2440_nand_hwcontrol;
+-		chip->dev_ready = s3c2440_nand_devready;
+-		chip->read_buf  = s3c2440_nand_read_buf;
+-		chip->write_buf	= s3c2440_nand_write_buf;
+-		break;
+-
+-	case TYPE_S3C2412:
+-		chip->IO_ADDR_W = regs + S3C2440_NFDATA;
+-		info->sel_reg   = regs + S3C2440_NFCONT;
+-		info->sel_bit	= S3C2412_NFCONT_nFCE0;
+-		chip->cmd_ctrl  = s3c2440_nand_hwcontrol;
+-		chip->dev_ready = s3c2412_nand_devready;
+-
+-		if (readl(regs + S3C2410_NFCONF) & S3C2412_NFCONF_NANDBOOT)
+-			dev_info(info->device, "System booted from NAND\n");
+-
+-		break;
+-	}
+-
+-	chip->IO_ADDR_R = chip->IO_ADDR_W;
+-
+-	nmtd->info	   = info;
+-	nmtd->set	   = set;
+-
+-	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.
+-	 */
+-	if (set->flash_bbt)
+-		chip->bbt_options |= NAND_BBT_USE_FLASH;
+-}
+-
+-/**
+- * s3c2410_nand_update_chip - post probe update
+- * @info: The controller instance.
+- * @nmtd: The driver version of the MTD instance.
+- *
+- * This routine is called after the chip probe has successfully completed
+- * and the relevant per-chip information updated. This call ensure that
+- * we update the internal state accordingly.
+- *
+- * The internal state is currently limited to the ECC state information.
+-*/
+-static int s3c2410_nand_update_chip(struct s3c2410_nand_info *info,
+-				    struct s3c2410_nand_mtd *nmtd)
+-{
+-	struct nand_chip *chip = &nmtd->chip;
+-
+-	switch (chip->ecc.mode) {
+-
+-	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);
+-		}
+-
+-		dev_info(info->device, "hardware ECC\n");
+-		break;
+-
+-	default:
+-		dev_err(info->device, "invalid ECC mode!\n");
+-		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,
+-	}, {
+-		/* also compatible with s3c6400 */
+-		.compatible = "samsung,s3c2412-nand",
+-		.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;
+-}
+-
+-/* s3c24xx_nand_probe
+- *
+- * called by device layer when it finds a device matching
+- * one our driver can handled. This code checks to see if
+- * it can allocate all necessary resources then calls the
+- * nand layer to look for devices
+-*/
+-static int s3c24xx_nand_probe(struct platform_device *pdev)
+-{
+-	struct s3c2410_platform_nand *plat;
+-	struct s3c2410_nand_info *info;
+-	struct s3c2410_nand_mtd *nmtd;
+-	struct s3c2410_nand_set *sets;
+-	struct resource *res;
+-	int err = 0;
+-	int size;
+-	int nr_sets;
+-	int setno;
+-
+-	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
+-	if (info == NULL) {
+-		err = -ENOMEM;
+-		goto exit_error;
+-	}
+-
+-	platform_set_drvdata(pdev, info);
+-
+-	nand_hw_control_init(&info->controller);
+-
+-	/* get the clock source and enable it */
+-
+-	info->clk = devm_clk_get(&pdev->dev, "nand");
+-	if (IS_ERR(info->clk)) {
+-		dev_err(&pdev->dev, "failed to get clock\n");
+-		err = -ENOENT;
+-		goto exit_error;
+-	}
+-
+-	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 */
+-	res = pdev->resource;
+-	size = resource_size(res);
+-
+-	info->device	= &pdev->dev;
+-	info->platform	= plat;
+-
+-	info->regs = devm_ioremap_resource(&pdev->dev, res);
+-	if (IS_ERR(info->regs)) {
+-		err = PTR_ERR(info->regs);
+-		goto exit_error;
+-	}
+-
+-	dev_dbg(&pdev->dev, "mapped registers at %p\n", info->regs);
+-
+-	sets = (plat != NULL) ? plat->sets : NULL;
+-	nr_sets = (plat != NULL) ? plat->nr_sets : 1;
+-
+-	info->mtd_count = nr_sets;
+-
+-	/* allocate our information */
+-
+-	size = nr_sets * sizeof(*info->mtds);
+-	info->mtds = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
+-	if (info->mtds == NULL) {
+-		err = -ENOMEM;
+-		goto exit_error;
+-	}
+-
+-	/* initialise all possible chips */
+-
+-	nmtd = info->mtds;
+-
+-	for (setno = 0; setno < nr_sets; setno++, nmtd++) {
+-		struct mtd_info *mtd = nand_to_mtd(&nmtd->chip);
+-
+-		pr_debug("initialising set %d (%p, info %p)\n",
+-			 setno, nmtd, info);
+-
+-		mtd->dev.parent = &pdev->dev;
+-		s3c2410_nand_init_chip(info, nmtd, sets);
+-
+-		nmtd->scan_res = nand_scan_ident(mtd,
+-						 (sets) ? sets->nr_chips : 1,
+-						 NULL);
+-
+-		if (nmtd->scan_res == 0) {
+-			err = s3c2410_nand_update_chip(info, nmtd);
+-			if (err < 0)
+-				goto exit_error;
+-			nand_scan_tail(mtd);
+-			s3c2410_nand_add_partition(info, nmtd, sets);
+-		}
+-
+-		if (sets != NULL)
+-			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");
+-		goto exit_error;
+-	}
+-
+-	if (allow_clk_suspend(info)) {
+-		dev_info(&pdev->dev, "clock idle support enabled\n");
+-		s3c2410_nand_clk_set_state(info, CLOCK_SUSPEND);
+-	}
+-
+-	return 0;
+-
+- exit_error:
+-	s3c24xx_nand_remove(pdev);
+-
+-	if (err == 0)
+-		err = -EINVAL;
+-	return err;
+-}
+-
+-/* PM Support */
+-#ifdef CONFIG_PM
+-
+-static int s3c24xx_nand_suspend(struct platform_device *dev, pm_message_t pm)
+-{
+-	struct s3c2410_nand_info *info = platform_get_drvdata(dev);
+-
+-	if (info) {
+-		info->save_sel = readl(info->sel_reg);
+-
+-		/* For the moment, we must ensure nFCE is high during
+-		 * the time we are suspended. This really should be
+-		 * handled by suspending the MTDs we are using, but
+-		 * that is currently not the case. */
+-
+-		writel(info->save_sel | info->sel_bit, info->sel_reg);
+-
+-		s3c2410_nand_clk_set_state(info, CLOCK_DISABLE);
+-	}
+-
+-	return 0;
+-}
+-
+-static int s3c24xx_nand_resume(struct platform_device *dev)
+-{
+-	struct s3c2410_nand_info *info = platform_get_drvdata(dev);
+-	unsigned long sel;
+-
+-	if (info) {
+-		s3c2410_nand_clk_set_state(info, CLOCK_ENABLE);
+-		s3c2410_nand_inithw(info);
+-
+-		/* Restore the state of the nFCE line. */
+-
+-		sel = readl(info->sel_reg);
+-		sel &= ~info->sel_bit;
+-		sel |= info->save_sel & info->sel_bit;
+-		writel(sel, info->sel_reg);
+-
+-		s3c2410_nand_clk_set_state(info, CLOCK_SUSPEND);
+-	}
+-
+-	return 0;
+-}
+-
+-#else
+-#define s3c24xx_nand_suspend NULL
+-#define s3c24xx_nand_resume NULL
+-#endif
+-
+-/* driver device registration */
+-
+-static const struct platform_device_id s3c24xx_driver_ids[] = {
+-	{
+-		.name		= "s3c2410-nand",
+-		.driver_data	= TYPE_S3C2410,
+-	}, {
+-		.name		= "s3c2440-nand",
+-		.driver_data	= TYPE_S3C2440,
+-	}, {
+-		.name		= "s3c2412-nand",
+-		.driver_data	= TYPE_S3C2412,
+-	}, {
+-		.name		= "s3c6400-nand",
+-		.driver_data	= TYPE_S3C2412, /* compatible with 2412 */
+-	},
+-	{ }
+-};
+-
+-MODULE_DEVICE_TABLE(platform, s3c24xx_driver_ids);
+-
+-static struct platform_driver s3c24xx_nand_driver = {
+-	.probe		= s3c24xx_nand_probe,
+-	.remove		= s3c24xx_nand_remove,
+-	.suspend	= s3c24xx_nand_suspend,
+-	.resume		= s3c24xx_nand_resume,
+-	.id_table	= s3c24xx_driver_ids,
+-	.driver		= {
+-		.name	= "s3c24xx-nand",
+-		.of_match_table = s3c24xx_nand_dt_ids,
+-	},
+-};
+-
+-module_platform_driver(s3c24xx_nand_driver);
+-
+-MODULE_LICENSE("GPL");
+-MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
+-MODULE_DESCRIPTION("S3C24XX MTD NAND driver");
+diff --git a/drivers/mtd/nand/sh_flctl.c b/drivers/mtd/nand/sh_flctl.c
+deleted file mode 100644
+index e7f3c98..0000000
+--- a/drivers/mtd/nand/sh_flctl.c
++++ /dev/null
+@@ -1,1253 +0,0 @@
+-/*
+- * SuperH FLCTL nand controller
+- *
+- * Copyright (c) 2008 Renesas Solutions Corp.
+- * Copyright (c) 2008 Atom Create Engineering Co., Ltd.
+- *
+- * Based on fsl_elbc_nand.c, Copyright (c) 2006-2007 Freescale Semiconductor
+- *
+- * 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.
+- *
+- * You should have received a copy of the GNU General Public License
+- * along with this program; if not, write to the Free Software
+- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+- *
+- */
+-
+-#include <linux/module.h>
+-#include <linux/kernel.h>
+-#include <linux/completion.h>
+-#include <linux/delay.h>
+-#include <linux/dmaengine.h>
+-#include <linux/dma-mapping.h>
+-#include <linux/interrupt.h>
+-#include <linux/io.h>
+-#include <linux/of.h>
+-#include <linux/of_device.h>
+-#include <linux/platform_device.h>
+-#include <linux/pm_runtime.h>
+-#include <linux/sh_dma.h>
+-#include <linux/slab.h>
+-#include <linux/string.h>
+-
+-#include <linux/mtd/mtd.h>
+-#include <linux/mtd/rawnand.h>
+-#include <linux/mtd/partitions.h>
+-#include <linux/mtd/sh_flctl.h>
+-
+-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);
+-
+-	if (section)
+-		return -ERANGE;
+-
+-	oobregion->offset = 0;
+-	oobregion->length = chip->ecc.bytes;
+-
+-	return 0;
+-}
+-
+-static int flctl_4secc_ooblayout_sp_free(struct mtd_info *mtd, int section,
+-					 struct mtd_oob_region *oobregion)
+-{
+-	if (section)
+-		return -ERANGE;
+-
+-	oobregion->offset = 12;
+-	oobregion->length = 4;
+-
+-	return 0;
+-}
+-
+-static const struct mtd_ooblayout_ops flctl_4secc_oob_smallpage_ops = {
+-	.ecc = flctl_4secc_ooblayout_sp_ecc,
+-	.free = flctl_4secc_ooblayout_sp_free,
+-};
+-
+-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);
+-
+-	if (section >= chip->ecc.steps)
+-		return -ERANGE;
+-
+-	oobregion->offset = (section * 16) + 6;
+-	oobregion->length = chip->ecc.bytes;
+-
+-	return 0;
+-}
+-
+-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);
+-
+-	if (section >= chip->ecc.steps)
+-		return -ERANGE;
+-
+-	oobregion->offset = section * 16;
+-	oobregion->length = 6;
+-
+-	if (!section) {
+-		oobregion->offset += 2;
+-		oobregion->length -= 2;
+-	}
+-
+-	return 0;
+-}
+-
+-static const struct mtd_ooblayout_ops flctl_4secc_oob_largepage_ops = {
+-	.ecc = flctl_4secc_ooblayout_lp_ecc,
+-	.free = flctl_4secc_ooblayout_lp_free,
+-};
+-
+-static uint8_t scan_ff_pattern[] = { 0xff, 0xff };
+-
+-static struct nand_bbt_descr flctl_4secc_smallpage = {
+-	.options = NAND_BBT_SCAN2NDPAGE,
+-	.offs = 11,
+-	.len = 1,
+-	.pattern = scan_ff_pattern,
+-};
+-
+-static struct nand_bbt_descr flctl_4secc_largepage = {
+-	.options = NAND_BBT_SCAN2NDPAGE,
+-	.offs = 0,
+-	.len = 2,
+-	.pattern = scan_ff_pattern,
+-};
+-
+-static void empty_fifo(struct sh_flctl *flctl)
+-{
+-	writel(flctl->flintdmacr_base | AC1CLR | AC0CLR, FLINTDMACR(flctl));
+-	writel(flctl->flintdmacr_base, FLINTDMACR(flctl));
+-}
+-
+-static void start_translation(struct sh_flctl *flctl)
+-{
+-	writeb(TRSTRT, FLTRCR(flctl));
+-}
+-
+-static void timeout_error(struct sh_flctl *flctl, const char *str)
+-{
+-	dev_err(&flctl->pdev->dev, "Timeout occurred in %s\n", str);
+-}
+-
+-static void wait_completion(struct sh_flctl *flctl)
+-{
+-	uint32_t timeout = LOOP_TIMEOUT_MAX;
+-
+-	while (timeout--) {
+-		if (readb(FLTRCR(flctl)) & TREND) {
+-			writeb(0x0, FLTRCR(flctl));
+-			return;
+-		}
+-		udelay(1);
+-	}
+-
+-	timeout_error(flctl, __func__);
+-	writeb(0x0, FLTRCR(flctl));
+-}
+-
+-static void flctl_dma_complete(void *param)
+-{
+-	struct sh_flctl *flctl = param;
+-
+-	complete(&flctl->dma_complete);
+-}
+-
+-static void flctl_release_dma(struct sh_flctl *flctl)
+-{
+-	if (flctl->chan_fifo0_rx) {
+-		dma_release_channel(flctl->chan_fifo0_rx);
+-		flctl->chan_fifo0_rx = NULL;
+-	}
+-	if (flctl->chan_fifo0_tx) {
+-		dma_release_channel(flctl->chan_fifo0_tx);
+-		flctl->chan_fifo0_tx = NULL;
+-	}
+-}
+-
+-static void flctl_setup_dma(struct sh_flctl *flctl)
+-{
+-	dma_cap_mask_t mask;
+-	struct dma_slave_config cfg;
+-	struct platform_device *pdev = flctl->pdev;
+-	struct sh_flctl_platform_data *pdata = dev_get_platdata(&pdev->dev);
+-	int ret;
+-
+-	if (!pdata)
+-		return;
+-
+-	if (pdata->slave_id_fifo0_tx <= 0 || pdata->slave_id_fifo0_rx <= 0)
+-		return;
+-
+-	/* We can only either use DMA for both Tx and Rx or not use it at all */
+-	dma_cap_zero(mask);
+-	dma_cap_set(DMA_SLAVE, mask);
+-
+-	flctl->chan_fifo0_tx = dma_request_channel(mask, shdma_chan_filter,
+-				(void *)(uintptr_t)pdata->slave_id_fifo0_tx);
+-	dev_dbg(&pdev->dev, "%s: TX: got channel %p\n", __func__,
+-		flctl->chan_fifo0_tx);
+-
+-	if (!flctl->chan_fifo0_tx)
+-		return;
+-
+-	memset(&cfg, 0, sizeof(cfg));
+-	cfg.direction = DMA_MEM_TO_DEV;
+-	cfg.dst_addr = flctl->fifo;
+-	cfg.src_addr = 0;
+-	ret = dmaengine_slave_config(flctl->chan_fifo0_tx, &cfg);
+-	if (ret < 0)
+-		goto err;
+-
+-	flctl->chan_fifo0_rx = dma_request_channel(mask, shdma_chan_filter,
+-				(void *)(uintptr_t)pdata->slave_id_fifo0_rx);
+-	dev_dbg(&pdev->dev, "%s: RX: got channel %p\n", __func__,
+-		flctl->chan_fifo0_rx);
+-
+-	if (!flctl->chan_fifo0_rx)
+-		goto err;
+-
+-	cfg.direction = DMA_DEV_TO_MEM;
+-	cfg.dst_addr = 0;
+-	cfg.src_addr = flctl->fifo;
+-	ret = dmaengine_slave_config(flctl->chan_fifo0_rx, &cfg);
+-	if (ret < 0)
+-		goto err;
+-
+-	init_completion(&flctl->dma_complete);
+-
+-	return;
+-
+-err:
+-	flctl_release_dma(flctl);
+-}
+-
+-static void set_addr(struct mtd_info *mtd, int column, int page_addr)
+-{
+-	struct sh_flctl *flctl = mtd_to_flctl(mtd);
+-	uint32_t addr = 0;
+-
+-	if (column == -1) {
+-		addr = page_addr;	/* ERASE1 */
+-	} else if (page_addr != -1) {
+-		/* SEQIN, READ0, etc.. */
+-		if (flctl->chip.options & NAND_BUSWIDTH_16)
+-			column >>= 1;
+-		if (flctl->page_size) {
+-			addr = column & 0x0FFF;
+-			addr |= (page_addr & 0xff) << 16;
+-			addr |= ((page_addr >> 8) & 0xff) << 24;
+-			/* big than 128MB */
+-			if (flctl->rw_ADRCNT == ADRCNT2_E) {
+-				uint32_t 	addr2;
+-				addr2 = (page_addr >> 16) & 0xff;
+-				writel(addr2, FLADR2(flctl));
+-			}
+-		} else {
+-			addr = column;
+-			addr |= (page_addr & 0xff) << 8;
+-			addr |= ((page_addr >> 8) & 0xff) << 16;
+-			addr |= ((page_addr >> 16) & 0xff) << 24;
+-		}
+-	}
+-	writel(addr, FLADR(flctl));
+-}
+-
+-static void wait_rfifo_ready(struct sh_flctl *flctl)
+-{
+-	uint32_t timeout = LOOP_TIMEOUT_MAX;
+-
+-	while (timeout--) {
+-		uint32_t val;
+-		/* check FIFO */
+-		val = readl(FLDTCNTR(flctl)) >> 16;
+-		if (val & 0xFF)
+-			return;
+-		udelay(1);
+-	}
+-	timeout_error(flctl, __func__);
+-}
+-
+-static void wait_wfifo_ready(struct sh_flctl *flctl)
+-{
+-	uint32_t len, timeout = LOOP_TIMEOUT_MAX;
+-
+-	while (timeout--) {
+-		/* check FIFO */
+-		len = (readl(FLDTCNTR(flctl)) >> 16) & 0xFF;
+-		if (len >= 4)
+-			return;
+-		udelay(1);
+-	}
+-	timeout_error(flctl, __func__);
+-}
+-
+-static enum flctl_ecc_res_t wait_recfifo_ready
+-		(struct sh_flctl *flctl, int sector_number)
+-{
+-	uint32_t timeout = LOOP_TIMEOUT_MAX;
+-	void __iomem *ecc_reg[4];
+-	int i;
+-	int state = FL_SUCCESS;
+-	uint32_t data, size;
+-
+-	/*
+-	 * First this loops checks in FLDTCNTR if we are ready to read out the
+-	 * oob data. This is the case if either all went fine without errors or
+-	 * if the bottom part of the loop corrected the errors or marked them as
+-	 * uncorrectable and the controller is given time to push the data into
+-	 * the FIFO.
+-	 */
+-	while (timeout--) {
+-		/* check if all is ok and we can read out the OOB */
+-		size = readl(FLDTCNTR(flctl)) >> 24;
+-		if ((size & 0xFF) == 4)
+-			return state;
+-
+-		/* check if a correction code has been calculated */
+-		if (!(readl(FL4ECCCR(flctl)) & _4ECCEND)) {
+-			/*
+-			 * either we wait for the fifo to be filled or a
+-			 * correction pattern is being generated
+-			 */
+-			udelay(1);
+-			continue;
+-		}
+-
+-		/* check for an uncorrectable error */
+-		if (readl(FL4ECCCR(flctl)) & _4ECCFA) {
+-			/* check if we face a non-empty page */
+-			for (i = 0; i < 512; i++) {
+-				if (flctl->done_buff[i] != 0xff) {
+-					state = FL_ERROR; /* can't correct */
+-					break;
+-				}
+-			}
+-
+-			if (state == FL_SUCCESS)
+-				dev_dbg(&flctl->pdev->dev,
+-				"reading empty sector %d, ecc error ignored\n",
+-				sector_number);
+-
+-			writel(0, FL4ECCCR(flctl));
+-			continue;
+-		}
+-
+-		/* start error correction */
+-		ecc_reg[0] = FL4ECCRESULT0(flctl);
+-		ecc_reg[1] = FL4ECCRESULT1(flctl);
+-		ecc_reg[2] = FL4ECCRESULT2(flctl);
+-		ecc_reg[3] = FL4ECCRESULT3(flctl);
+-
+-		for (i = 0; i < 3; i++) {
+-			uint8_t org;
+-			unsigned int index;
+-
+-			data = readl(ecc_reg[i]);
+-
+-			if (flctl->page_size)
+-				index = (512 * sector_number) +
+-					(data >> 16);
+-			else
+-				index = data >> 16;
+-
+-			org = flctl->done_buff[index];
+-			flctl->done_buff[index] = org ^ (data & 0xFF);
+-		}
+-		state = FL_REPAIRABLE;
+-		writel(0, FL4ECCCR(flctl));
+-	}
+-
+-	timeout_error(flctl, __func__);
+-	return FL_TIMEOUT;	/* timeout */
+-}
+-
+-static void wait_wecfifo_ready(struct sh_flctl *flctl)
+-{
+-	uint32_t timeout = LOOP_TIMEOUT_MAX;
+-	uint32_t len;
+-
+-	while (timeout--) {
+-		/* check FLECFIFO */
+-		len = (readl(FLDTCNTR(flctl)) >> 24) & 0xFF;
+-		if (len >= 4)
+-			return;
+-		udelay(1);
+-	}
+-	timeout_error(flctl, __func__);
+-}
+-
+-static int flctl_dma_fifo0_transfer(struct sh_flctl *flctl, unsigned long *buf,
+-					int len, enum dma_data_direction dir)
+-{
+-	struct dma_async_tx_descriptor *desc = NULL;
+-	struct dma_chan *chan;
+-	enum dma_transfer_direction tr_dir;
+-	dma_addr_t dma_addr;
+-	dma_cookie_t cookie;
+-	uint32_t reg;
+-	int ret;
+-
+-	if (dir == DMA_FROM_DEVICE) {
+-		chan = flctl->chan_fifo0_rx;
+-		tr_dir = DMA_DEV_TO_MEM;
+-	} else {
+-		chan = flctl->chan_fifo0_tx;
+-		tr_dir = DMA_MEM_TO_DEV;
+-	}
+-
+-	dma_addr = dma_map_single(chan->device->dev, buf, len, dir);
+-
+-	if (!dma_mapping_error(chan->device->dev, dma_addr))
+-		desc = dmaengine_prep_slave_single(chan, dma_addr, len,
+-			tr_dir, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+-
+-	if (desc) {
+-		reg = readl(FLINTDMACR(flctl));
+-		reg |= DREQ0EN;
+-		writel(reg, FLINTDMACR(flctl));
+-
+-		desc->callback = flctl_dma_complete;
+-		desc->callback_param = flctl;
+-		cookie = dmaengine_submit(desc);
+-		if (dma_submit_error(cookie)) {
+-			ret = dma_submit_error(cookie);
+-			dev_warn(&flctl->pdev->dev,
+-				 "DMA submit failed, falling back to PIO\n");
+-			goto out;
+-		}
+-
+-		dma_async_issue_pending(chan);
+-	} else {
+-		/* DMA failed, fall back to PIO */
+-		flctl_release_dma(flctl);
+-		dev_warn(&flctl->pdev->dev,
+-			 "DMA failed, falling back to PIO\n");
+-		ret = -EIO;
+-		goto out;
+-	}
+-
+-	ret =
+-	wait_for_completion_timeout(&flctl->dma_complete,
+-				msecs_to_jiffies(3000));
+-
+-	if (ret <= 0) {
+-		dmaengine_terminate_all(chan);
+-		dev_err(&flctl->pdev->dev, "wait_for_completion_timeout\n");
+-	}
+-
+-out:
+-	reg = readl(FLINTDMACR(flctl));
+-	reg &= ~DREQ0EN;
+-	writel(reg, FLINTDMACR(flctl));
+-
+-	dma_unmap_single(chan->device->dev, dma_addr, len, dir);
+-
+-	/* ret > 0 is success */
+-	return ret;
+-}
+-
+-static void read_datareg(struct sh_flctl *flctl, int offset)
+-{
+-	unsigned long data;
+-	unsigned long *buf = (unsigned long *)&flctl->done_buff[offset];
+-
+-	wait_completion(flctl);
+-
+-	data = readl(FLDATAR(flctl));
+-	*buf = le32_to_cpu(data);
+-}
+-
+-static void read_fiforeg(struct sh_flctl *flctl, int rlen, int offset)
+-{
+-	int i, len_4align;
+-	unsigned long *buf = (unsigned long *)&flctl->done_buff[offset];
+-
+-	len_4align = (rlen + 3) / 4;
+-
+-	/* initiate DMA transfer */
+-	if (flctl->chan_fifo0_rx && rlen >= 32 &&
+-		flctl_dma_fifo0_transfer(flctl, buf, rlen, DMA_DEV_TO_MEM) > 0)
+-			goto convert;	/* DMA success */
+-
+-	/* do polling transfer */
+-	for (i = 0; i < len_4align; i++) {
+-		wait_rfifo_ready(flctl);
+-		buf[i] = readl(FLDTFIFO(flctl));
+-	}
+-
+-convert:
+-	for (i = 0; i < len_4align; i++)
+-		buf[i] = be32_to_cpu(buf[i]);
+-}
+-
+-static enum flctl_ecc_res_t read_ecfiforeg
+-		(struct sh_flctl *flctl, uint8_t *buff, int sector)
+-{
+-	int i;
+-	enum flctl_ecc_res_t res;
+-	unsigned long *ecc_buf = (unsigned long *)buff;
+-
+-	res = wait_recfifo_ready(flctl , sector);
+-
+-	if (res != FL_ERROR) {
+-		for (i = 0; i < 4; i++) {
+-			ecc_buf[i] = readl(FLECFIFO(flctl));
+-			ecc_buf[i] = be32_to_cpu(ecc_buf[i]);
+-		}
+-	}
+-
+-	return res;
+-}
+-
+-static void write_fiforeg(struct sh_flctl *flctl, int rlen,
+-						unsigned int offset)
+-{
+-	int i, len_4align;
+-	unsigned long *buf = (unsigned long *)&flctl->done_buff[offset];
+-
+-	len_4align = (rlen + 3) / 4;
+-	for (i = 0; i < len_4align; i++) {
+-		wait_wfifo_ready(flctl);
+-		writel(cpu_to_be32(buf[i]), FLDTFIFO(flctl));
+-	}
+-}
+-
+-static void write_ec_fiforeg(struct sh_flctl *flctl, int rlen,
+-						unsigned int offset)
+-{
+-	int i, len_4align;
+-	unsigned long *buf = (unsigned long *)&flctl->done_buff[offset];
+-
+-	len_4align = (rlen + 3) / 4;
+-
+-	for (i = 0; i < len_4align; i++)
+-		buf[i] = cpu_to_be32(buf[i]);
+-
+-	/* initiate DMA transfer */
+-	if (flctl->chan_fifo0_tx && rlen >= 32 &&
+-		flctl_dma_fifo0_transfer(flctl, buf, rlen, DMA_MEM_TO_DEV) > 0)
+-			return;	/* DMA success */
+-
+-	/* do polling transfer */
+-	for (i = 0; i < len_4align; i++) {
+-		wait_wecfifo_ready(flctl);
+-		writel(buf[i], FLECFIFO(flctl));
+-	}
+-}
+-
+-static void set_cmd_regs(struct mtd_info *mtd, uint32_t cmd, uint32_t flcmcdr_val)
+-{
+-	struct sh_flctl *flctl = mtd_to_flctl(mtd);
+-	uint32_t flcmncr_val = flctl->flcmncr_base & ~SEL_16BIT;
+-	uint32_t flcmdcr_val, addr_len_bytes = 0;
+-
+-	/* Set SNAND bit if page size is 2048byte */
+-	if (flctl->page_size)
+-		flcmncr_val |= SNAND_E;
+-	else
+-		flcmncr_val &= ~SNAND_E;
+-
+-	/* default FLCMDCR val */
+-	flcmdcr_val = DOCMD1_E | DOADR_E;
+-
+-	/* Set for FLCMDCR */
+-	switch (cmd) {
+-	case NAND_CMD_ERASE1:
+-		addr_len_bytes = flctl->erase_ADRCNT;
+-		flcmdcr_val |= DOCMD2_E;
+-		break;
+-	case NAND_CMD_READ0:
+-	case NAND_CMD_READOOB:
+-	case NAND_CMD_RNDOUT:
+-		addr_len_bytes = flctl->rw_ADRCNT;
+-		flcmdcr_val |= CDSRC_E;
+-		if (flctl->chip.options & NAND_BUSWIDTH_16)
+-			flcmncr_val |= SEL_16BIT;
+-		break;
+-	case NAND_CMD_SEQIN:
+-		/* This case is that cmd is READ0 or READ1 or READ00 */
+-		flcmdcr_val &= ~DOADR_E;	/* ONLY execute 1st cmd */
+-		break;
+-	case NAND_CMD_PAGEPROG:
+-		addr_len_bytes = flctl->rw_ADRCNT;
+-		flcmdcr_val |= DOCMD2_E | CDSRC_E | SELRW;
+-		if (flctl->chip.options & NAND_BUSWIDTH_16)
+-			flcmncr_val |= SEL_16BIT;
+-		break;
+-	case NAND_CMD_READID:
+-		flcmncr_val &= ~SNAND_E;
+-		flcmdcr_val |= CDSRC_E;
+-		addr_len_bytes = ADRCNT_1;
+-		break;
+-	case NAND_CMD_STATUS:
+-	case NAND_CMD_RESET:
+-		flcmncr_val &= ~SNAND_E;
+-		flcmdcr_val &= ~(DOADR_E | DOSR_E);
+-		break;
+-	default:
+-		break;
+-	}
+-
+-	/* Set address bytes parameter */
+-	flcmdcr_val |= addr_len_bytes;
+-
+-	/* Now actually write */
+-	writel(flcmncr_val, FLCMNCR(flctl));
+-	writel(flcmdcr_val, FLCMDCR(flctl));
+-	writel(flcmcdr_val, FLCMCDR(flctl));
+-}
+-
+-static int flctl_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
+-				uint8_t *buf, int oob_required, int page)
+-{
+-	chip->read_buf(mtd, buf, mtd->writesize);
+-	if (oob_required)
+-		chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+-	return 0;
+-}
+-
+-static int flctl_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
+-				  const uint8_t *buf, int oob_required,
+-				  int page)
+-{
+-	chip->write_buf(mtd, buf, mtd->writesize);
+-	chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+-	return 0;
+-}
+-
+-static void execmd_read_page_sector(struct mtd_info *mtd, int page_addr)
+-{
+-	struct sh_flctl *flctl = mtd_to_flctl(mtd);
+-	int sector, page_sectors;
+-	enum flctl_ecc_res_t ecc_result;
+-
+-	page_sectors = flctl->page_size ? 4 : 1;
+-
+-	set_cmd_regs(mtd, NAND_CMD_READ0,
+-		(NAND_CMD_READSTART << 8) | NAND_CMD_READ0);
+-
+-	writel(readl(FLCMNCR(flctl)) | ACM_SACCES_MODE | _4ECCCORRECT,
+-		 FLCMNCR(flctl));
+-	writel(readl(FLCMDCR(flctl)) | page_sectors, FLCMDCR(flctl));
+-	writel(page_addr << 2, FLADR(flctl));
+-
+-	empty_fifo(flctl);
+-	start_translation(flctl);
+-
+-	for (sector = 0; sector < page_sectors; sector++) {
+-		read_fiforeg(flctl, 512, 512 * sector);
+-
+-		ecc_result = read_ecfiforeg(flctl,
+-			&flctl->done_buff[mtd->writesize + 16 * sector],
+-			sector);
+-
+-		switch (ecc_result) {
+-		case FL_REPAIRABLE:
+-			dev_info(&flctl->pdev->dev,
+-				"applied ecc on page 0x%x", page_addr);
+-			mtd->ecc_stats.corrected++;
+-			break;
+-		case FL_ERROR:
+-			dev_warn(&flctl->pdev->dev,
+-				"page 0x%x contains corrupted data\n",
+-				page_addr);
+-			mtd->ecc_stats.failed++;
+-			break;
+-		default:
+-			;
+-		}
+-	}
+-
+-	wait_completion(flctl);
+-
+-	writel(readl(FLCMNCR(flctl)) & ~(ACM_SACCES_MODE | _4ECCCORRECT),
+-			FLCMNCR(flctl));
+-}
+-
+-static void execmd_read_oob(struct mtd_info *mtd, int page_addr)
+-{
+-	struct sh_flctl *flctl = mtd_to_flctl(mtd);
+-	int page_sectors = flctl->page_size ? 4 : 1;
+-	int i;
+-
+-	set_cmd_regs(mtd, NAND_CMD_READ0,
+-		(NAND_CMD_READSTART << 8) | NAND_CMD_READ0);
+-
+-	empty_fifo(flctl);
+-
+-	for (i = 0; i < page_sectors; i++) {
+-		set_addr(mtd, (512 + 16) * i + 512 , page_addr);
+-		writel(16, FLDTCNTR(flctl));
+-
+-		start_translation(flctl);
+-		read_fiforeg(flctl, 16, 16 * i);
+-		wait_completion(flctl);
+-	}
+-}
+-
+-static void execmd_write_page_sector(struct mtd_info *mtd)
+-{
+-	struct sh_flctl *flctl = mtd_to_flctl(mtd);
+-	int page_addr = flctl->seqin_page_addr;
+-	int sector, page_sectors;
+-
+-	page_sectors = flctl->page_size ? 4 : 1;
+-
+-	set_cmd_regs(mtd, NAND_CMD_PAGEPROG,
+-			(NAND_CMD_PAGEPROG << 8) | NAND_CMD_SEQIN);
+-
+-	empty_fifo(flctl);
+-	writel(readl(FLCMNCR(flctl)) | ACM_SACCES_MODE, FLCMNCR(flctl));
+-	writel(readl(FLCMDCR(flctl)) | page_sectors, FLCMDCR(flctl));
+-	writel(page_addr << 2, FLADR(flctl));
+-	start_translation(flctl);
+-
+-	for (sector = 0; sector < page_sectors; sector++) {
+-		write_fiforeg(flctl, 512, 512 * sector);
+-		write_ec_fiforeg(flctl, 16, mtd->writesize + 16 * sector);
+-	}
+-
+-	wait_completion(flctl);
+-	writel(readl(FLCMNCR(flctl)) & ~ACM_SACCES_MODE, FLCMNCR(flctl));
+-}
+-
+-static void execmd_write_oob(struct mtd_info *mtd)
+-{
+-	struct sh_flctl *flctl = mtd_to_flctl(mtd);
+-	int page_addr = flctl->seqin_page_addr;
+-	int sector, page_sectors;
+-
+-	page_sectors = flctl->page_size ? 4 : 1;
+-
+-	set_cmd_regs(mtd, NAND_CMD_PAGEPROG,
+-			(NAND_CMD_PAGEPROG << 8) | NAND_CMD_SEQIN);
+-
+-	for (sector = 0; sector < page_sectors; sector++) {
+-		empty_fifo(flctl);
+-		set_addr(mtd, sector * 528 + 512, page_addr);
+-		writel(16, FLDTCNTR(flctl));	/* set read size */
+-
+-		start_translation(flctl);
+-		write_fiforeg(flctl, 16, 16 * sector);
+-		wait_completion(flctl);
+-	}
+-}
+-
+-static void flctl_cmdfunc(struct mtd_info *mtd, unsigned int command,
+-			int column, int page_addr)
+-{
+-	struct sh_flctl *flctl = mtd_to_flctl(mtd);
+-	uint32_t read_cmd = 0;
+-
+-	pm_runtime_get_sync(&flctl->pdev->dev);
+-
+-	flctl->read_bytes = 0;
+-	if (command != NAND_CMD_PAGEPROG)
+-		flctl->index = 0;
+-
+-	switch (command) {
+-	case NAND_CMD_READ1:
+-	case NAND_CMD_READ0:
+-		if (flctl->hwecc) {
+-			/* read page with hwecc */
+-			execmd_read_page_sector(mtd, page_addr);
+-			break;
+-		}
+-		if (flctl->page_size)
+-			set_cmd_regs(mtd, command, (NAND_CMD_READSTART << 8)
+-				| command);
+-		else
+-			set_cmd_regs(mtd, command, command);
+-
+-		set_addr(mtd, 0, page_addr);
+-
+-		flctl->read_bytes = mtd->writesize + mtd->oobsize;
+-		if (flctl->chip.options & NAND_BUSWIDTH_16)
+-			column >>= 1;
+-		flctl->index += column;
+-		goto read_normal_exit;
+-
+-	case NAND_CMD_READOOB:
+-		if (flctl->hwecc) {
+-			/* read page with hwecc */
+-			execmd_read_oob(mtd, page_addr);
+-			break;
+-		}
+-
+-		if (flctl->page_size) {
+-			set_cmd_regs(mtd, command, (NAND_CMD_READSTART << 8)
+-				| NAND_CMD_READ0);
+-			set_addr(mtd, mtd->writesize, page_addr);
+-		} else {
+-			set_cmd_regs(mtd, command, command);
+-			set_addr(mtd, 0, page_addr);
+-		}
+-		flctl->read_bytes = mtd->oobsize;
+-		goto read_normal_exit;
+-
+-	case NAND_CMD_RNDOUT:
+-		if (flctl->hwecc)
+-			break;
+-
+-		if (flctl->page_size)
+-			set_cmd_regs(mtd, command, (NAND_CMD_RNDOUTSTART << 8)
+-				| command);
+-		else
+-			set_cmd_regs(mtd, command, command);
+-
+-		set_addr(mtd, column, 0);
+-
+-		flctl->read_bytes = mtd->writesize + mtd->oobsize - column;
+-		goto read_normal_exit;
+-
+-	case NAND_CMD_READID:
+-		set_cmd_regs(mtd, command, command);
+-
+-		/* READID is always performed using an 8-bit bus */
+-		if (flctl->chip.options & NAND_BUSWIDTH_16)
+-			column <<= 1;
+-		set_addr(mtd, column, 0);
+-
+-		flctl->read_bytes = 8;
+-		writel(flctl->read_bytes, FLDTCNTR(flctl)); /* set read size */
+-		empty_fifo(flctl);
+-		start_translation(flctl);
+-		read_fiforeg(flctl, flctl->read_bytes, 0);
+-		wait_completion(flctl);
+-		break;
+-
+-	case NAND_CMD_ERASE1:
+-		flctl->erase1_page_addr = page_addr;
+-		break;
+-
+-	case NAND_CMD_ERASE2:
+-		set_cmd_regs(mtd, NAND_CMD_ERASE1,
+-			(command << 8) | NAND_CMD_ERASE1);
+-		set_addr(mtd, -1, flctl->erase1_page_addr);
+-		start_translation(flctl);
+-		wait_completion(flctl);
+-		break;
+-
+-	case NAND_CMD_SEQIN:
+-		if (!flctl->page_size) {
+-			/* output read command */
+-			if (column >= mtd->writesize) {
+-				column -= mtd->writesize;
+-				read_cmd = NAND_CMD_READOOB;
+-			} else if (column < 256) {
+-				read_cmd = NAND_CMD_READ0;
+-			} else {
+-				column -= 256;
+-				read_cmd = NAND_CMD_READ1;
+-			}
+-		}
+-		flctl->seqin_column = column;
+-		flctl->seqin_page_addr = page_addr;
+-		flctl->seqin_read_cmd = read_cmd;
+-		break;
+-
+-	case NAND_CMD_PAGEPROG:
+-		empty_fifo(flctl);
+-		if (!flctl->page_size) {
+-			set_cmd_regs(mtd, NAND_CMD_SEQIN,
+-					flctl->seqin_read_cmd);
+-			set_addr(mtd, -1, -1);
+-			writel(0, FLDTCNTR(flctl));	/* set 0 size */
+-			start_translation(flctl);
+-			wait_completion(flctl);
+-		}
+-		if (flctl->hwecc) {
+-			/* write page with hwecc */
+-			if (flctl->seqin_column == mtd->writesize)
+-				execmd_write_oob(mtd);
+-			else if (!flctl->seqin_column)
+-				execmd_write_page_sector(mtd);
+-			else
+-				printk(KERN_ERR "Invalid address !?\n");
+-			break;
+-		}
+-		set_cmd_regs(mtd, command, (command << 8) | NAND_CMD_SEQIN);
+-		set_addr(mtd, flctl->seqin_column, flctl->seqin_page_addr);
+-		writel(flctl->index, FLDTCNTR(flctl));	/* set write size */
+-		start_translation(flctl);
+-		write_fiforeg(flctl, flctl->index, 0);
+-		wait_completion(flctl);
+-		break;
+-
+-	case NAND_CMD_STATUS:
+-		set_cmd_regs(mtd, command, command);
+-		set_addr(mtd, -1, -1);
+-
+-		flctl->read_bytes = 1;
+-		writel(flctl->read_bytes, FLDTCNTR(flctl)); /* set read size */
+-		start_translation(flctl);
+-		read_datareg(flctl, 0); /* read and end */
+-		break;
+-
+-	case NAND_CMD_RESET:
+-		set_cmd_regs(mtd, command, command);
+-		set_addr(mtd, -1, -1);
+-
+-		writel(0, FLDTCNTR(flctl));	/* set 0 size */
+-		start_translation(flctl);
+-		wait_completion(flctl);
+-		break;
+-
+-	default:
+-		break;
+-	}
+-	goto runtime_exit;
+-
+-read_normal_exit:
+-	writel(flctl->read_bytes, FLDTCNTR(flctl));	/* set read size */
+-	empty_fifo(flctl);
+-	start_translation(flctl);
+-	read_fiforeg(flctl, flctl->read_bytes, 0);
+-	wait_completion(flctl);
+-runtime_exit:
+-	pm_runtime_put_sync(&flctl->pdev->dev);
+-	return;
+-}
+-
+-static void flctl_select_chip(struct mtd_info *mtd, int chipnr)
+-{
+-	struct sh_flctl *flctl = mtd_to_flctl(mtd);
+-	int ret;
+-
+-	switch (chipnr) {
+-	case -1:
+-		flctl->flcmncr_base &= ~CE0_ENABLE;
+-
+-		pm_runtime_get_sync(&flctl->pdev->dev);
+-		writel(flctl->flcmncr_base, FLCMNCR(flctl));
+-
+-		if (flctl->qos_request) {
+-			dev_pm_qos_remove_request(&flctl->pm_qos);
+-			flctl->qos_request = 0;
+-		}
+-
+-		pm_runtime_put_sync(&flctl->pdev->dev);
+-		break;
+-	case 0:
+-		flctl->flcmncr_base |= CE0_ENABLE;
+-
+-		if (!flctl->qos_request) {
+-			ret = dev_pm_qos_add_request(&flctl->pdev->dev,
+-							&flctl->pm_qos,
+-							DEV_PM_QOS_RESUME_LATENCY,
+-							100);
+-			if (ret < 0)
+-				dev_err(&flctl->pdev->dev,
+-					"PM QoS request failed: %d\n", ret);
+-			flctl->qos_request = 1;
+-		}
+-
+-		if (flctl->holden) {
+-			pm_runtime_get_sync(&flctl->pdev->dev);
+-			writel(HOLDEN, FLHOLDCR(flctl));
+-			pm_runtime_put_sync(&flctl->pdev->dev);
+-		}
+-		break;
+-	default:
+-		BUG();
+-	}
+-}
+-
+-static void flctl_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+-{
+-	struct sh_flctl *flctl = mtd_to_flctl(mtd);
+-
+-	memcpy(&flctl->done_buff[flctl->index], buf, len);
+-	flctl->index += len;
+-}
+-
+-static uint8_t flctl_read_byte(struct mtd_info *mtd)
+-{
+-	struct sh_flctl *flctl = mtd_to_flctl(mtd);
+-	uint8_t data;
+-
+-	data = flctl->done_buff[flctl->index];
+-	flctl->index++;
+-	return data;
+-}
+-
+-static uint16_t flctl_read_word(struct mtd_info *mtd)
+-{
+-	struct sh_flctl *flctl = mtd_to_flctl(mtd);
+-	uint16_t *buf = (uint16_t *)&flctl->done_buff[flctl->index];
+-
+-	flctl->index += 2;
+-	return *buf;
+-}
+-
+-static void flctl_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+-{
+-	struct sh_flctl *flctl = mtd_to_flctl(mtd);
+-
+-	memcpy(buf, &flctl->done_buff[flctl->index], len);
+-	flctl->index += len;
+-}
+-
+-static int flctl_chip_init_tail(struct mtd_info *mtd)
+-{
+-	struct sh_flctl *flctl = mtd_to_flctl(mtd);
+-	struct nand_chip *chip = &flctl->chip;
+-
+-	if (mtd->writesize == 512) {
+-		flctl->page_size = 0;
+-		if (chip->chipsize > (32 << 20)) {
+-			/* big than 32MB */
+-			flctl->rw_ADRCNT = ADRCNT_4;
+-			flctl->erase_ADRCNT = ADRCNT_3;
+-		} else if (chip->chipsize > (2 << 16)) {
+-			/* big than 128KB */
+-			flctl->rw_ADRCNT = ADRCNT_3;
+-			flctl->erase_ADRCNT = ADRCNT_2;
+-		} else {
+-			flctl->rw_ADRCNT = ADRCNT_2;
+-			flctl->erase_ADRCNT = ADRCNT_1;
+-		}
+-	} else {
+-		flctl->page_size = 1;
+-		if (chip->chipsize > (128 << 20)) {
+-			/* big than 128MB */
+-			flctl->rw_ADRCNT = ADRCNT2_E;
+-			flctl->erase_ADRCNT = ADRCNT_3;
+-		} else if (chip->chipsize > (8 << 16)) {
+-			/* big than 512KB */
+-			flctl->rw_ADRCNT = ADRCNT_4;
+-			flctl->erase_ADRCNT = ADRCNT_2;
+-		} else {
+-			flctl->rw_ADRCNT = ADRCNT_3;
+-			flctl->erase_ADRCNT = ADRCNT_1;
+-		}
+-	}
+-
+-	if (flctl->hwecc) {
+-		if (mtd->writesize == 512) {
+-			mtd_set_ooblayout(mtd, &flctl_4secc_oob_smallpage_ops);
+-			chip->badblock_pattern = &flctl_4secc_smallpage;
+-		} else {
+-			mtd_set_ooblayout(mtd, &flctl_4secc_oob_largepage_ops);
+-			chip->badblock_pattern = &flctl_4secc_largepage;
+-		}
+-
+-		chip->ecc.size = 512;
+-		chip->ecc.bytes = 10;
+-		chip->ecc.strength = 4;
+-		chip->ecc.read_page = flctl_read_page_hwecc;
+-		chip->ecc.write_page = flctl_write_page_hwecc;
+-		chip->ecc.mode = NAND_ECC_HW;
+-
+-		/* 4 symbols ECC enabled */
+-		flctl->flcmncr_base |= _4ECCEN;
+-	} else {
+-		chip->ecc.mode = NAND_ECC_SOFT;
+-		chip->ecc.algo = NAND_ECC_HAMMING;
+-	}
+-
+-	return 0;
+-}
+-
+-static irqreturn_t flctl_handle_flste(int irq, void *dev_id)
+-{
+-	struct sh_flctl *flctl = dev_id;
+-
+-	dev_err(&flctl->pdev->dev, "flste irq: %x\n", readl(FLINTDMACR(flctl)));
+-	writel(flctl->flintdmacr_base, FLINTDMACR(flctl));
+-
+-	return IRQ_HANDLED;
+-}
+-
+-struct flctl_soc_config {
+-	unsigned long flcmncr_val;
+-	unsigned has_hwecc:1;
+-	unsigned use_holden:1;
+-};
+-
+-static struct flctl_soc_config flctl_sh7372_config = {
+-	.flcmncr_val = CLK_16B_12L_4H | TYPESEL_SET | SHBUSSEL,
+-	.has_hwecc = 1,
+-	.use_holden = 1,
+-};
+-
+-static const struct of_device_id of_flctl_match[] = {
+-	{ .compatible = "renesas,shmobile-flctl-sh7372",
+-				.data = &flctl_sh7372_config },
+-	{},
+-};
+-MODULE_DEVICE_TABLE(of, of_flctl_match);
+-
+-static struct sh_flctl_platform_data *flctl_parse_dt(struct device *dev)
+-{
+-	const struct of_device_id *match;
+-	struct flctl_soc_config *config;
+-	struct sh_flctl_platform_data *pdata;
+-
+-	match = of_match_device(of_flctl_match, dev);
+-	if (match)
+-		config = (struct flctl_soc_config *)match->data;
+-	else {
+-		dev_err(dev, "%s: no OF configuration attached\n", __func__);
+-		return NULL;
+-	}
+-
+-	pdata = devm_kzalloc(dev, sizeof(struct sh_flctl_platform_data),
+-								GFP_KERNEL);
+-	if (!pdata)
+-		return NULL;
+-
+-	/* set SoC specific options */
+-	pdata->flcmncr_val = config->flcmncr_val;
+-	pdata->has_hwecc = config->has_hwecc;
+-	pdata->use_holden = config->use_holden;
+-
+-	return pdata;
+-}
+-
+-static int flctl_probe(struct platform_device *pdev)
+-{
+-	struct resource *res;
+-	struct sh_flctl *flctl;
+-	struct mtd_info *flctl_mtd;
+-	struct nand_chip *nand;
+-	struct sh_flctl_platform_data *pdata;
+-	int ret;
+-	int irq;
+-
+-	flctl = devm_kzalloc(&pdev->dev, sizeof(struct sh_flctl), GFP_KERNEL);
+-	if (!flctl)
+-		return -ENOMEM;
+-
+-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+-	flctl->reg = devm_ioremap_resource(&pdev->dev, res);
+-	if (IS_ERR(flctl->reg))
+-		return PTR_ERR(flctl->reg);
+-	flctl->fifo = res->start + 0x24; /* FLDTFIFO */
+-
+-	irq = platform_get_irq(pdev, 0);
+-	if (irq < 0) {
+-		dev_err(&pdev->dev, "failed to get flste irq data: %d\n", irq);
+-		return irq;
+-	}
+-
+-	ret = devm_request_irq(&pdev->dev, irq, flctl_handle_flste, IRQF_SHARED,
+-			       "flste", flctl);
+-	if (ret) {
+-		dev_err(&pdev->dev, "request interrupt failed.\n");
+-		return ret;
+-	}
+-
+-	if (pdev->dev.of_node)
+-		pdata = flctl_parse_dt(&pdev->dev);
+-	else
+-		pdata = dev_get_platdata(&pdev->dev);
+-
+-	if (!pdata) {
+-		dev_err(&pdev->dev, "no setup data defined\n");
+-		return -EINVAL;
+-	}
+-
+-	platform_set_drvdata(pdev, flctl);
+-	nand = &flctl->chip;
+-	flctl_mtd = nand_to_mtd(nand);
+-	nand_set_flash_node(nand, pdev->dev.of_node);
+-	flctl_mtd->dev.parent = &pdev->dev;
+-	flctl->pdev = pdev;
+-	flctl->hwecc = pdata->has_hwecc;
+-	flctl->holden = pdata->use_holden;
+-	flctl->flcmncr_base = pdata->flcmncr_val;
+-	flctl->flintdmacr_base = flctl->hwecc ? (STERINTE | ECERB) : STERINTE;
+-
+-	/* Set address of hardware control function */
+-	/* 20 us command delay time */
+-	nand->chip_delay = 20;
+-
+-	nand->read_byte = flctl_read_byte;
+-	nand->read_word = flctl_read_word;
+-	nand->write_buf = flctl_write_buf;
+-	nand->read_buf = flctl_read_buf;
+-	nand->select_chip = flctl_select_chip;
+-	nand->cmdfunc = flctl_cmdfunc;
+-	nand->onfi_set_features = nand_onfi_get_set_features_notsupp;
+-	nand->onfi_get_features = nand_onfi_get_set_features_notsupp;
+-
+-	if (pdata->flcmncr_val & SEL_16BIT)
+-		nand->options |= NAND_BUSWIDTH_16;
+-
+-	pm_runtime_enable(&pdev->dev);
+-	pm_runtime_resume(&pdev->dev);
+-
+-	flctl_setup_dma(flctl);
+-
+-	ret = nand_scan_ident(flctl_mtd, 1, NULL);
+-	if (ret)
+-		goto err_chip;
+-
+-	if (nand->options & NAND_BUSWIDTH_16) {
+-		/*
+-		 * NAND_BUSWIDTH_16 may have been set by nand_scan_ident().
+-		 * Add the SEL_16BIT flag in pdata->flcmncr_val and re-assign
+-		 * flctl->flcmncr_base to pdata->flcmncr_val.
+-		 */
+-		pdata->flcmncr_val |= SEL_16BIT;
+-		flctl->flcmncr_base = pdata->flcmncr_val;
+-	}
+-
+-	ret = flctl_chip_init_tail(flctl_mtd);
+-	if (ret)
+-		goto err_chip;
+-
+-	ret = nand_scan_tail(flctl_mtd);
+-	if (ret)
+-		goto err_chip;
+-
+-	ret = mtd_device_register(flctl_mtd, pdata->parts, pdata->nr_parts);
+-
+-	return 0;
+-
+-err_chip:
+-	flctl_release_dma(flctl);
+-	pm_runtime_disable(&pdev->dev);
+-	return ret;
+-}
+-
+-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));
+-	pm_runtime_disable(&pdev->dev);
+-
+-	return 0;
+-}
+-
+-static struct platform_driver flctl_driver = {
+-	.remove		= flctl_remove,
+-	.driver = {
+-		.name	= "sh_flctl",
+-		.of_match_table = of_match_ptr(of_flctl_match),
+-	},
+-};
+-
+-module_platform_driver_probe(flctl_driver, flctl_probe);
+-
+-MODULE_LICENSE("GPL");
+-MODULE_AUTHOR("Yoshihiro Shimoda");
+-MODULE_DESCRIPTION("SuperH FLCTL driver");
+-MODULE_ALIAS("platform:sh_flctl");
+diff --git a/drivers/mtd/nand/sharpsl.c b/drivers/mtd/nand/sharpsl.c
+deleted file mode 100644
+index f59c455..0000000
+--- a/drivers/mtd/nand/sharpsl.c
++++ /dev/null
+@@ -1,235 +0,0 @@
+-/*
+- * drivers/mtd/nand/sharpsl.c
+- *
+- *  Copyright (C) 2004 Richard Purdie
+- *  Copyright (C) 2008 Dmitry Baryshkov
+- *
+- *  Based on Sharp's NAND driver sharp_sl.c
+- *
+- * 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/genhd.h>
+-#include <linux/slab.h>
+-#include <linux/module.h>
+-#include <linux/delay.h>
+-#include <linux/mtd/mtd.h>
+-#include <linux/mtd/rawnand.h>
+-#include <linux/mtd/nand_ecc.h>
+-#include <linux/mtd/partitions.h>
+-#include <linux/mtd/sharpsl.h>
+-#include <linux/interrupt.h>
+-#include <linux/platform_device.h>
+-
+-#include <asm/io.h>
+-#include <mach/hardware.h>
+-#include <asm/mach-types.h>
+-
+-struct sharpsl_nand {
+-	struct nand_chip	chip;
+-
+-	void __iomem		*io;
+-};
+-
+-static inline struct sharpsl_nand *mtd_to_sharpsl(struct mtd_info *mtd)
+-{
+-	return container_of(mtd_to_nand(mtd), struct sharpsl_nand, chip);
+-}
+-
+-/* register offset */
+-#define ECCLPLB		0x00	/* line parity 7 - 0 bit */
+-#define ECCLPUB		0x04	/* line parity 15 - 8 bit */
+-#define ECCCP		0x08	/* column parity 5 - 0 bit */
+-#define ECCCNTR		0x0C	/* ECC byte counter */
+-#define ECCCLRR		0x10	/* cleare ECC */
+-#define FLASHIO		0x14	/* Flash I/O */
+-#define FLASHCTL	0x18	/* Flash Control */
+-
+-/* Flash control bit */
+-#define FLRYBY		(1 << 5)
+-#define FLCE1		(1 << 4)
+-#define FLWP		(1 << 3)
+-#define FLALE		(1 << 2)
+-#define FLCLE		(1 << 1)
+-#define FLCE0		(1 << 0)
+-
+-/*
+- *	hardware specific access to control-lines
+- *	ctrl:
+- *	NAND_CNE: bit 0 -> ! bit 0 & 4
+- *	NAND_CLE: bit 1 -> bit 1
+- *	NAND_ALE: bit 2 -> bit 2
+- *
+- */
+-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);
+-
+-	if (ctrl & NAND_CTRL_CHANGE) {
+-		unsigned char bits = ctrl & 0x07;
+-
+-		bits |= (ctrl & 0x01) << 4;
+-
+-		bits ^= 0x11;
+-
+-		writeb((readb(sharpsl->io + FLASHCTL) & ~0x17) | bits, sharpsl->io + FLASHCTL);
+-	}
+-
+-	if (cmd != NAND_CMD_NONE)
+-		writeb(cmd, chip->IO_ADDR_W);
+-}
+-
+-static int sharpsl_nand_dev_ready(struct mtd_info *mtd)
+-{
+-	struct sharpsl_nand *sharpsl = mtd_to_sharpsl(mtd);
+-	return !((readb(sharpsl->io + FLASHCTL) & FLRYBY) == 0);
+-}
+-
+-static void sharpsl_nand_enable_hwecc(struct mtd_info *mtd, int mode)
+-{
+-	struct sharpsl_nand *sharpsl = mtd_to_sharpsl(mtd);
+-	writeb(0, sharpsl->io + ECCCLRR);
+-}
+-
+-static int sharpsl_nand_calculate_ecc(struct mtd_info *mtd, const u_char * dat, u_char * ecc_code)
+-{
+-	struct sharpsl_nand *sharpsl = mtd_to_sharpsl(mtd);
+-	ecc_code[0] = ~readb(sharpsl->io + ECCLPUB);
+-	ecc_code[1] = ~readb(sharpsl->io + ECCLPLB);
+-	ecc_code[2] = (~readb(sharpsl->io + ECCCP) << 2) | 0x03;
+-	return readb(sharpsl->io + ECCCNTR) != 0;
+-}
+-
+-/*
+- * Main initialization routine
+- */
+-static int sharpsl_nand_probe(struct platform_device *pdev)
+-{
+-	struct nand_chip *this;
+-	struct mtd_info *mtd;
+-	struct resource *r;
+-	int err = 0;
+-	struct sharpsl_nand *sharpsl;
+-	struct sharpsl_nand_platform_data *data = dev_get_platdata(&pdev->dev);
+-
+-	if (!data) {
+-		dev_err(&pdev->dev, "no platform data!\n");
+-		return -EINVAL;
+-	}
+-
+-	/* Allocate memory for MTD device structure and private data */
+-	sharpsl = kzalloc(sizeof(struct sharpsl_nand), GFP_KERNEL);
+-	if (!sharpsl)
+-		return -ENOMEM;
+-
+-	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+-	if (!r) {
+-		dev_err(&pdev->dev, "no io memory resource defined!\n");
+-		err = -ENODEV;
+-		goto err_get_res;
+-	}
+-
+-	/* map physical address */
+-	sharpsl->io = ioremap(r->start, resource_size(r));
+-	if (!sharpsl->io) {
+-		dev_err(&pdev->dev, "ioremap to access Sharp SL NAND chip failed\n");
+-		err = -EIO;
+-		goto err_ioremap;
+-	}
+-
+-	/* Get pointer to private data */
+-	this = (struct nand_chip *)(&sharpsl->chip);
+-
+-	/* Link the private data with the MTD structure */
+-	mtd = nand_to_mtd(this);
+-	mtd->dev.parent = &pdev->dev;
+-	mtd_set_ooblayout(mtd, data->ecc_layout);
+-
+-	platform_set_drvdata(pdev, sharpsl);
+-
+-	/*
+-	 * PXA initialize
+-	 */
+-	writeb(readb(sharpsl->io + FLASHCTL) | FLWP, sharpsl->io + FLASHCTL);
+-
+-	/* Set address of NAND IO lines */
+-	this->IO_ADDR_R = sharpsl->io + FLASHIO;
+-	this->IO_ADDR_W = sharpsl->io + FLASHIO;
+-	/* Set address of hardware control function */
+-	this->cmd_ctrl = sharpsl_nand_hwcontrol;
+-	this->dev_ready = sharpsl_nand_dev_ready;
+-	/* 15 us command delay time */
+-	this->chip_delay = 15;
+-	/* set eccmode using hardware ECC */
+-	this->ecc.mode = NAND_ECC_HW;
+-	this->ecc.size = 256;
+-	this->ecc.bytes = 3;
+-	this->ecc.strength = 1;
+-	this->badblock_pattern = data->badblock_pattern;
+-	this->ecc.hwctl = sharpsl_nand_enable_hwecc;
+-	this->ecc.calculate = sharpsl_nand_calculate_ecc;
+-	this->ecc.correct = nand_correct_data;
+-
+-	/* Scan to find existence of the device */
+-	err = nand_scan(mtd, 1);
+-	if (err)
+-		goto err_scan;
+-
+-	/* Register the partitions */
+-	mtd->name = "sharpsl-nand";
+-
+-	err = mtd_device_parse_register(mtd, data->part_parsers, NULL,
+-					data->partitions, data->nr_partitions);
+-	if (err)
+-		goto err_add;
+-
+-	/* Return happy */
+-	return 0;
+-
+-err_add:
+-	nand_release(mtd);
+-
+-err_scan:
+-	iounmap(sharpsl->io);
+-err_ioremap:
+-err_get_res:
+-	kfree(sharpsl);
+-	return err;
+-}
+-
+-/*
+- * Clean up routine
+- */
+-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));
+-
+-	iounmap(sharpsl->io);
+-
+-	/* Free the MTD device structure */
+-	kfree(sharpsl);
+-
+-	return 0;
+-}
+-
+-static struct platform_driver sharpsl_nand_driver = {
+-	.driver = {
+-		.name	= "sharpsl-nand",
+-	},
+-	.probe		= sharpsl_nand_probe,
+-	.remove		= sharpsl_nand_remove,
+-};
+-
+-module_platform_driver(sharpsl_nand_driver);
+-
+-MODULE_LICENSE("GPL");
+-MODULE_AUTHOR("Richard Purdie <rpurdie@rpsys.net>");
+-MODULE_DESCRIPTION("Device specific logic for NAND flash on Sharp SL-C7xx Series");
+diff --git a/drivers/mtd/nand/sm_common.c b/drivers/mtd/nand/sm_common.c
+deleted file mode 100644
+index c378705..0000000
+--- a/drivers/mtd/nand/sm_common.c
++++ /dev/null
+@@ -1,202 +0,0 @@
+-/*
+- * Copyright © 2009 - Maxim Levitsky
+- * Common routines & support for xD format
+- *
+- * 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/kernel.h>
+-#include <linux/mtd/rawnand.h>
+-#include <linux/module.h>
+-#include <linux/sizes.h>
+-#include "sm_common.h"
+-
+-static int oob_sm_ooblayout_ecc(struct mtd_info *mtd, int section,
+-				struct mtd_oob_region *oobregion)
+-{
+-	if (section > 1)
+-		return -ERANGE;
+-
+-	oobregion->length = 3;
+-	oobregion->offset = ((section + 1) * 8) - 3;
+-
+-	return 0;
+-}
+-
+-static int oob_sm_ooblayout_free(struct mtd_info *mtd, int section,
+-				 struct mtd_oob_region *oobregion)
+-{
+-	switch (section) {
+-	case 0:
+-		/* reserved */
+-		oobregion->offset = 0;
+-		oobregion->length = 4;
+-		break;
+-	case 1:
+-		/* LBA1 */
+-		oobregion->offset = 6;
+-		oobregion->length = 2;
+-		break;
+-	case 2:
+-		/* LBA2 */
+-		oobregion->offset = 11;
+-		oobregion->length = 2;
+-		break;
+-	default:
+-		return -ERANGE;
+-	}
+-
+-	return 0;
+-}
+-
+-static const struct mtd_ooblayout_ops oob_sm_ops = {
+-	.ecc = oob_sm_ooblayout_ecc,
+-	.free = oob_sm_ooblayout_free,
+-};
+-
+-/* NOTE: This layout is is not compatabable with SmartMedia, */
+-/* because the 256 byte devices have page depenent oob layout */
+-/* However it does preserve the bad block markers */
+-/* If you use smftl, it will bypass this and work correctly */
+-/* If you not, then you break SmartMedia compliance anyway */
+-
+-static int oob_sm_small_ooblayout_ecc(struct mtd_info *mtd, int section,
+-				      struct mtd_oob_region *oobregion)
+-{
+-	if (section)
+-		return -ERANGE;
+-
+-	oobregion->length = 3;
+-	oobregion->offset = 0;
+-
+-	return 0;
+-}
+-
+-static int oob_sm_small_ooblayout_free(struct mtd_info *mtd, int section,
+-				       struct mtd_oob_region *oobregion)
+-{
+-	switch (section) {
+-	case 0:
+-		/* reserved */
+-		oobregion->offset = 3;
+-		oobregion->length = 2;
+-		break;
+-	case 1:
+-		/* LBA1 */
+-		oobregion->offset = 6;
+-		oobregion->length = 2;
+-		break;
+-	default:
+-		return -ERANGE;
+-	}
+-
+-	return 0;
+-}
+-
+-static const struct mtd_ooblayout_ops oob_sm_small_ops = {
+-	.ecc = oob_sm_small_ooblayout_ecc,
+-	.free = oob_sm_small_ooblayout_free,
+-};
+-
+-static int sm_block_markbad(struct mtd_info *mtd, loff_t ofs)
+-{
+-	struct mtd_oob_ops ops;
+-	struct sm_oob oob;
+-	int ret;
+-
+-	memset(&oob, -1, SM_OOB_SIZE);
+-	oob.block_status = 0x0F;
+-
+-	/* As long as this function is called on erase block boundaries
+-		it will work correctly for 256 byte nand */
+-	ops.mode = MTD_OPS_PLACE_OOB;
+-	ops.ooboffs = 0;
+-	ops.ooblen = mtd->oobsize;
+-	ops.oobbuf = (void *)&oob;
+-	ops.datbuf = NULL;
+-
+-
+-	ret = mtd_write_oob(mtd, ofs, &ops);
+-	if (ret < 0 || ops.oobretlen != SM_OOB_SIZE) {
+-		printk(KERN_NOTICE
+-			"sm_common: can't mark sector at %i as bad\n",
+-								(int)ofs);
+-		return -EIO;
+-	}
+-
+-	return 0;
+-}
+-
+-static struct nand_flash_dev nand_smartmedia_flash_ids[] = {
+-	LEGACY_ID_NAND("SmartMedia 2MiB 3,3V ROM",   0x5d, 2,   SZ_8K, NAND_ROM),
+-	LEGACY_ID_NAND("SmartMedia 4MiB 3,3V",       0xe3, 4,   SZ_8K, 0),
+-	LEGACY_ID_NAND("SmartMedia 4MiB 3,3/5V",     0xe5, 4,   SZ_8K, 0),
+-	LEGACY_ID_NAND("SmartMedia 4MiB 5V",         0x6b, 4,   SZ_8K, 0),
+-	LEGACY_ID_NAND("SmartMedia 4MiB 3,3V ROM",   0xd5, 4,   SZ_8K, NAND_ROM),
+-	LEGACY_ID_NAND("SmartMedia 8MiB 3,3V",       0xe6, 8,   SZ_8K, 0),
+-	LEGACY_ID_NAND("SmartMedia 8MiB 3,3V ROM",   0xd6, 8,   SZ_8K, NAND_ROM),
+-	LEGACY_ID_NAND("SmartMedia 16MiB 3,3V",      0x73, 16,  SZ_16K, 0),
+-	LEGACY_ID_NAND("SmartMedia 16MiB 3,3V ROM",  0x57, 16,  SZ_16K, NAND_ROM),
+-	LEGACY_ID_NAND("SmartMedia 32MiB 3,3V",      0x75, 32,  SZ_16K, 0),
+-	LEGACY_ID_NAND("SmartMedia 32MiB 3,3V ROM",  0x58, 32,  SZ_16K, NAND_ROM),
+-	LEGACY_ID_NAND("SmartMedia 64MiB 3,3V",      0x76, 64,  SZ_16K, 0),
+-	LEGACY_ID_NAND("SmartMedia 64MiB 3,3V ROM",  0xd9, 64,  SZ_16K, NAND_ROM),
+-	LEGACY_ID_NAND("SmartMedia 128MiB 3,3V",     0x79, 128, SZ_16K, 0),
+-	LEGACY_ID_NAND("SmartMedia 128MiB 3,3V ROM", 0xda, 128, SZ_16K, NAND_ROM),
+-	LEGACY_ID_NAND("SmartMedia 256MiB 3, 3V",    0x71, 256, SZ_16K, 0),
+-	LEGACY_ID_NAND("SmartMedia 256MiB 3,3V ROM", 0x5b, 256, SZ_16K, NAND_ROM),
+-	{NULL}
+-};
+-
+-static struct nand_flash_dev nand_xd_flash_ids[] = {
+-	LEGACY_ID_NAND("xD 16MiB 3,3V",  0x73, 16,   SZ_16K, 0),
+-	LEGACY_ID_NAND("xD 32MiB 3,3V",  0x75, 32,   SZ_16K, 0),
+-	LEGACY_ID_NAND("xD 64MiB 3,3V",  0x76, 64,   SZ_16K, 0),
+-	LEGACY_ID_NAND("xD 128MiB 3,3V", 0x79, 128,  SZ_16K, 0),
+-	LEGACY_ID_NAND("xD 256MiB 3,3V", 0x71, 256,  SZ_16K, NAND_BROKEN_XD),
+-	LEGACY_ID_NAND("xD 512MiB 3,3V", 0xdc, 512,  SZ_16K, NAND_BROKEN_XD),
+-	LEGACY_ID_NAND("xD 1GiB 3,3V",   0xd3, 1024, SZ_16K, NAND_BROKEN_XD),
+-	LEGACY_ID_NAND("xD 2GiB 3,3V",   0xd5, 2048, SZ_16K, NAND_BROKEN_XD),
+-	{NULL}
+-};
+-
+-int sm_register_device(struct mtd_info *mtd, int smartmedia)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	int ret;
+-
+-	chip->options |= NAND_SKIP_BBTSCAN;
+-
+-	/* Scan for card properties */
+-	ret = nand_scan_ident(mtd, 1, smartmedia ?
+-		nand_smartmedia_flash_ids : nand_xd_flash_ids);
+-
+-	if (ret)
+-		return ret;
+-
+-	/* Bad block marker position */
+-	chip->badblockpos = 0x05;
+-	chip->badblockbits = 7;
+-	chip->block_markbad = sm_block_markbad;
+-
+-	/* ECC layout */
+-	if (mtd->writesize == SM_SECTOR_SIZE)
+-		mtd_set_ooblayout(mtd, &oob_sm_ops);
+-	else if (mtd->writesize == SM_SMALL_PAGE)
+-		mtd_set_ooblayout(mtd, &oob_sm_small_ops);
+-	else
+-		return -ENODEV;
+-
+-	ret = nand_scan_tail(mtd);
+-
+-	if (ret)
+-		return ret;
+-
+-	return mtd_device_register(mtd, NULL, 0);
+-}
+-EXPORT_SYMBOL_GPL(sm_register_device);
+-
+-MODULE_LICENSE("GPL");
+-MODULE_AUTHOR("Maxim Levitsky <maximlevitsky@gmail.com>");
+-MODULE_DESCRIPTION("Common SmartMedia/xD functions");
+diff --git a/drivers/mtd/nand/sm_common.h b/drivers/mtd/nand/sm_common.h
+deleted file mode 100644
+index d3e028e..0000000
+--- a/drivers/mtd/nand/sm_common.h
++++ /dev/null
+@@ -1,61 +0,0 @@
+-/*
+- * Copyright © 2009 - Maxim Levitsky
+- * Common routines & support for SmartMedia/xD format
+- *
+- * 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/bitops.h>
+-#include <linux/mtd/mtd.h>
+-
+-/* Full oob structure as written on the flash */
+-struct sm_oob {
+-	uint32_t reserved;
+-	uint8_t data_status;
+-	uint8_t block_status;
+-	uint8_t lba_copy1[2];
+-	uint8_t ecc2[3];
+-	uint8_t lba_copy2[2];
+-	uint8_t ecc1[3];
+-} __packed;
+-
+-
+-/* one sector is always 512 bytes, but it can consist of two nand pages */
+-#define SM_SECTOR_SIZE		512
+-
+-/* oob area is also 16 bytes, but might be from two pages */
+-#define SM_OOB_SIZE		16
+-
+-/* This is maximum zone size, and all devices that have more that one zone
+-   have this size */
+-#define SM_MAX_ZONE_SIZE 	1024
+-
+-/* support for small page nand */
+-#define SM_SMALL_PAGE 		256
+-#define SM_SMALL_OOB_SIZE	8
+-
+-
+-extern int sm_register_device(struct mtd_info *mtd, int smartmedia);
+-
+-
+-static inline int sm_sector_valid(struct sm_oob *oob)
+-{
+-	return hweight16(oob->data_status) >= 5;
+-}
+-
+-static inline int sm_block_valid(struct sm_oob *oob)
+-{
+-	return hweight16(oob->block_status) >= 7;
+-}
+-
+-static inline int sm_block_erased(struct sm_oob *oob)
+-{
+-	static const uint32_t erased_pattern[4] = {
+-		0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+-
+-	/* First test for erased block */
+-	if (!memcmp(oob, erased_pattern, sizeof(*oob)))
+-		return 1;
+-	return 0;
+-}
+diff --git a/drivers/mtd/nand/socrates_nand.c b/drivers/mtd/nand/socrates_nand.c
+deleted file mode 100644
+index 575997d..0000000
+--- a/drivers/mtd/nand/socrates_nand.c
++++ /dev/null
+@@ -1,243 +0,0 @@
+-/*
+- * drivers/mtd/nand/socrates_nand.c
+- *
+- *  Copyright © 2008 Ilya Yanok, Emcraft Systems
+- *
+- *
+- * 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/slab.h>
+-#include <linux/module.h>
+-#include <linux/mtd/mtd.h>
+-#include <linux/mtd/rawnand.h>
+-#include <linux/mtd/partitions.h>
+-#include <linux/of_address.h>
+-#include <linux/of_platform.h>
+-#include <linux/io.h>
+-
+-#define FPGA_NAND_CMD_MASK		(0x7 << 28)
+-#define FPGA_NAND_CMD_COMMAND		(0x0 << 28)
+-#define FPGA_NAND_CMD_ADDR		(0x1 << 28)
+-#define FPGA_NAND_CMD_READ		(0x2 << 28)
+-#define FPGA_NAND_CMD_WRITE		(0x3 << 28)
+-#define FPGA_NAND_BUSY			(0x1 << 15)
+-#define FPGA_NAND_ENABLE		(0x1 << 31)
+-#define FPGA_NAND_DATA_SHIFT		16
+-
+-struct socrates_nand_host {
+-	struct nand_chip	nand_chip;
+-	void __iomem		*io_base;
+-	struct device		*dev;
+-};
+-
+-/**
+- * socrates_nand_write_buf -  write buffer to chip
+- * @mtd:	MTD device structure
+- * @buf:	data buffer
+- * @len:	number of bytes to write
+- */
+-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 socrates_nand_host *host = nand_get_controller_data(this);
+-
+-	for (i = 0; i < len; i++) {
+-		out_be32(host->io_base, FPGA_NAND_ENABLE |
+-				FPGA_NAND_CMD_WRITE |
+-				(buf[i] << FPGA_NAND_DATA_SHIFT));
+-	}
+-}
+-
+-/**
+- * socrates_nand_read_buf -  read chip data into buffer
+- * @mtd:	MTD device structure
+- * @buf:	buffer to store date
+- * @len:	number of bytes to read
+- */
+-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 socrates_nand_host *host = nand_get_controller_data(this);
+-	uint32_t val;
+-
+-	val = FPGA_NAND_ENABLE | FPGA_NAND_CMD_READ;
+-
+-	out_be32(host->io_base, val);
+-	for (i = 0; i < len; i++) {
+-		buf[i] = (in_be32(host->io_base) >>
+-				FPGA_NAND_DATA_SHIFT) & 0xff;
+-	}
+-}
+-
+-/**
+- * socrates_nand_read_byte -  read one byte from the chip
+- * @mtd:	MTD device structure
+- */
+-static uint8_t socrates_nand_read_byte(struct mtd_info *mtd)
+-{
+-	uint8_t byte;
+-	socrates_nand_read_buf(mtd, &byte, sizeof(byte));
+-	return byte;
+-}
+-
+-/**
+- * socrates_nand_read_word -  read one word from the chip
+- * @mtd:	MTD device structure
+- */
+-static uint16_t socrates_nand_read_word(struct mtd_info *mtd)
+-{
+-	uint16_t word;
+-	socrates_nand_read_buf(mtd, (uint8_t *)&word, sizeof(word));
+-	return word;
+-}
+-
+-/*
+- * Hardware specific access to control-lines
+- */
+-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 socrates_nand_host *host = nand_get_controller_data(nand_chip);
+-	uint32_t val;
+-
+-	if (cmd == NAND_CMD_NONE)
+-		return;
+-
+-	if (ctrl & NAND_CLE)
+-		val = FPGA_NAND_CMD_COMMAND;
+-	else
+-		val = FPGA_NAND_CMD_ADDR;
+-
+-	if (ctrl & NAND_NCE)
+-		val |= FPGA_NAND_ENABLE;
+-
+-	val |= (cmd & 0xff) << FPGA_NAND_DATA_SHIFT;
+-
+-	out_be32(host->io_base, val);
+-}
+-
+-/*
+- * Read the Device Ready pin.
+- */
+-static int socrates_nand_device_ready(struct mtd_info *mtd)
+-{
+-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+-	struct socrates_nand_host *host = nand_get_controller_data(nand_chip);
+-
+-	if (in_be32(host->io_base) & FPGA_NAND_BUSY)
+-		return 0; /* busy */
+-	return 1;
+-}
+-
+-/*
+- * Probe for the NAND device.
+- */
+-static int socrates_nand_probe(struct platform_device *ofdev)
+-{
+-	struct socrates_nand_host *host;
+-	struct mtd_info *mtd;
+-	struct nand_chip *nand_chip;
+-	int res;
+-
+-	/* Allocate memory for the device structure (and zero it) */
+-	host = devm_kzalloc(&ofdev->dev, sizeof(*host), GFP_KERNEL);
+-	if (!host)
+-		return -ENOMEM;
+-
+-	host->io_base = of_iomap(ofdev->dev.of_node, 0);
+-	if (host->io_base == NULL) {
+-		dev_err(&ofdev->dev, "ioremap failed\n");
+-		return -EIO;
+-	}
+-
+-	nand_chip = &host->nand_chip;
+-	mtd = nand_to_mtd(nand_chip);
+-	host->dev = &ofdev->dev;
+-
+-	/* link the private data structures */
+-	nand_set_controller_data(nand_chip, host);
+-	nand_set_flash_node(nand_chip, ofdev->dev.of_node);
+-	mtd->name = "socrates_nand";
+-	mtd->dev.parent = &ofdev->dev;
+-
+-	/*should never be accessed directly */
+-	nand_chip->IO_ADDR_R = (void *)0xdeadbeef;
+-	nand_chip->IO_ADDR_W = (void *)0xdeadbeef;
+-
+-	nand_chip->cmd_ctrl = socrates_nand_cmd_ctrl;
+-	nand_chip->read_byte = socrates_nand_read_byte;
+-	nand_chip->read_word = socrates_nand_read_word;
+-	nand_chip->write_buf = socrates_nand_write_buf;
+-	nand_chip->read_buf = socrates_nand_read_buf;
+-	nand_chip->dev_ready = socrates_nand_device_ready;
+-
+-	nand_chip->ecc.mode = NAND_ECC_SOFT;	/* enable ECC */
+-	nand_chip->ecc.algo = NAND_ECC_HAMMING;
+-
+-	/* TODO: I have no idea what real delay is. */
+-	nand_chip->chip_delay = 20;		/* 20us command delay time */
+-
+-	dev_set_drvdata(&ofdev->dev, host);
+-
+-	res = nand_scan(mtd, 1);
+-	if (res)
+-		goto out;
+-
+-	res = mtd_device_register(mtd, NULL, 0);
+-	if (!res)
+-		return res;
+-
+-	nand_release(mtd);
+-
+-out:
+-	iounmap(host->io_base);
+-	return res;
+-}
+-
+-/*
+- * Remove a NAND device.
+- */
+-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);
+-
+-	nand_release(mtd);
+-
+-	iounmap(host->io_base);
+-
+-	return 0;
+-}
+-
+-static const struct of_device_id socrates_nand_match[] =
+-{
+-	{
+-		.compatible   = "abb,socrates-nand",
+-	},
+-	{},
+-};
+-
+-MODULE_DEVICE_TABLE(of, socrates_nand_match);
+-
+-static struct platform_driver socrates_nand_driver = {
+-	.driver = {
+-		.name = "socrates_nand",
+-		.of_match_table = socrates_nand_match,
+-	},
+-	.probe		= socrates_nand_probe,
+-	.remove		= socrates_nand_remove,
+-};
+-
+-module_platform_driver(socrates_nand_driver);
+-
+-MODULE_LICENSE("GPL");
+-MODULE_AUTHOR("Ilya Yanok");
+-MODULE_DESCRIPTION("NAND driver for Socrates board");
+diff --git a/drivers/mtd/nand/stm32_fmc.c b/drivers/mtd/nand/stm32_fmc.c
+deleted file mode 100644
+index e3f5be7..0000000
+--- a/drivers/mtd/nand/stm32_fmc.c
++++ /dev/null
+@@ -1,1743 +0,0 @@
+-/*
+- * stm32_fmc.c
+- *
+- * Copyright (C) 2017, STMicroelectronics - All Rights Reserved
+- * Christophe Kerello <christophe.kerello@st.com>
+- *
+- * License terms: GPL V2.0.
+- */
+-
+-#include <linux/clk.h>
+-#include <linux/dmaengine.h>
+-#include <linux/dma-mapping.h>
+-#include <linux/errno.h>
+-#include <linux/io.h>
+-#include <linux/iopoll.h>
+-#include <linux/interrupt.h>
+-#include <linux/module.h>
+-#include <linux/mtd/mtd.h>
+-#include <linux/mtd/rawnand.h>
+-#include <linux/mtd/nand_ecc.h>
+-#include <linux/mtd/partitions.h>
+-#include <linux/of.h>
+-#include <linux/of_device.h>
+-#include <linux/platform_device.h>
+-#include <linux/reset.h>
+-
+-/* Bad block marker length */
+-#define FMC_BBM_LEN			2
+-
+-/* BCHDSRx registers length */
+-#define FMC_BCHDSRS_LEN			20
+-
+-/* HECCR length */
+-#define FMC_HECCR_LEN			4
+-
+-/* Max requests done for a 8k nand page size */
+-#define FMC_MAX_SG_COUNT		16
+-
+-/* Command delay */
+-#define FMC_RB_DELAY_US			30
+-
+-/* Bank offsets */
+-#define FMC_DATA_SECTION		0x00000
+-#define FMC_COMMAND_SECTION		0x10000
+-#define FMC_ADDRESS_SECTION		0x20000
+-
+-/* Timings */
+-#define FMC_THIZ			1
+-#define FMC_TIO				8000
+-#define FMC_TSYNC			3000
+-#define FMC_PCR_TIMING_MASK		0xf
+-#define FMC_PMEM_PATT_TIMING_MASK	0xff
+-
+-/* FMC Controller Registers */
+-#define FMC_BCR1			0x0
+-#define FMC_PCR(bank)			(0x0020 * ((bank) + 1))
+-#define FMC_SR(bank)			((0x0020 * ((bank) + 1)) + 0x04)
+-#define FMC_PMEM(bank)			((0x0020 * ((bank) + 1)) + 0x08)
+-#define FMC_PATT(bank)			((0x0020 * ((bank) + 1)) + 0x0c)
+-#define FMC_HECCR(bank)			((0x0020 * ((bank) + 1)) + 0x14)
+-#define FMC_CSQCR			0x0200
+-#define FMC_CSQCFGR1			0x0204
+-#define FMC_CSQCFGR2			0x0208
+-#define FMC_CSQCFGR3			0x020c
+-#define FMC_CSQAR1			0x0210
+-#define FMC_CSQAR2			0x0214
+-#define FMC_CSQIER			0x0220
+-#define FMC_CSQISR			0x0224
+-#define FMC_CSQICR			0x0228
+-#define FMC_CSQEMSR			0x0230
+-#define FMC_BCHIER			0x0250
+-#define FMC_BCHISR			0x0254
+-#define FMC_BCHICR			0x0258
+-#define FMC_BCHPBR1			0x0260
+-#define FMC_BCHPBR2			0x0264
+-#define FMC_BCHPBR3			0x0268
+-#define FMC_BCHPBR4			0x026c
+-#define FMC_BCHDSR0			0x027c
+-#define FMC_BCHDSR1			0x0280
+-#define FMC_BCHDSR2			0x0284
+-#define FMC_BCHDSR3			0x0288
+-#define FMC_BCHDSR4			0x028c
+-
+-/* Register: FMC_BCR1 */
+-#define FMC_BCR1_FMCEN			BIT(31)
+-
+-/* Register: FMC_PCR */
+-#define FMC_PCR_PWAITEN			BIT(1)
+-#define FMC_PCR_PBKEN			BIT(2)
+-#define FMC_PCR_PWID_MASK		GENMASK(5, 4)
+-#define FMC_PCR_PWID(x)			(((x) & 0x3) << 4)
+-#define FMC_PCR_PWID_BUSWIDTH_8		0
+-#define FMC_PCR_PWID_BUSWIDTH_16	1
+-#define FMC_PCR_ECCEN			BIT(6)
+-#define FMC_PCR_ECCALG			BIT(8)
+-#define FMC_PCR_TCLR_MASK		GENMASK(12, 9)
+-#define FMC_PCR_TCLR(x)			(((x) & 0xf) << 9)
+-#define FMC_PCR_TAR_MASK		GENMASK(16, 13)
+-#define FMC_PCR_TAR(x)			(((x) & 0xf) << 13)
+-#define FMC_PCR_ECCSS_MASK		GENMASK(19, 17)
+-#define FMC_PCR_ECCSS(x)		(((x) & 0x7) << 17)
+-#define FMC_PCR_ECCSS_512		1
+-#define FMC_PCR_BCHECC			BIT(24)
+-#define FMC_PCR_WEN			BIT(25)
+-
+-/* Register: FMC_SR */
+-#define FMC_SR_NWRF			BIT(6)
+-
+-/* Register: FMC_PMEM */
+-#define FMC_PMEM_MEMSET(x)		(((x) & 0xff) << 0)
+-#define FMC_PMEM_MEMWAIT(x)		(((x) & 0xff) << 8)
+-#define FMC_PMEM_MEMHOLD(x)		(((x) & 0xff) << 16)
+-#define FMC_PMEM_MEMHIZ(x)		(((x) & 0xff) << 24)
+-
+-/* Register: FMC_PATT */
+-#define FMC_PATT_ATTSET(x)		(((x) & 0xff) << 0)
+-#define FMC_PATT_ATTWAIT(x)		(((x) & 0xff) << 8)
+-#define FMC_PATT_ATTHOLD(x)		(((x) & 0xff) << 16)
+-#define FMC_PATT_ATTHIZ(x)		(((x) & 0xff) << 24)
+-
+-/* Register: FMC_CSQCR */
+-#define FMC_CSQCR_CSQSTART		BIT(0)
+-
+-/* Register: FMC_CSQCFGR1 */
+-#define FMC_CSQCFGR1_CMD2EN		BIT(1)
+-#define FMC_CSQCFGR1_DMADEN		BIT(2)
+-#define FMC_CSQCFGR1_ACYNBR(x)		(((x) & 0x7) << 4)
+-#define FMC_CSQCFGR1_CMD1(x)		(((x) & 0xff) << 8)
+-#define FMC_CSQCFGR1_CMD2(x)		(((x) & 0xff) << 16)
+-#define FMC_CSQCFGR1_CMD1T		BIT(24)
+-#define FMC_CSQCFGR1_CMD2T		BIT(25)
+-
+-/* Register: FMC_CSQCFGR2 */
+-#define FMC_CSQCFGR2_SQSDTEN		BIT(0)
+-#define FMC_CSQCFGR2_RCMD2EN		BIT(1)
+-#define FMC_CSQCFGR2_DMASEN		BIT(2)
+-#define FMC_CSQCFGR2_RCMD1(x)		(((x) & 0xff) << 8)
+-#define FMC_CSQCFGR2_RCMD2(x)		(((x) & 0xff) << 16)
+-#define FMC_CSQCFGR2_RCMD1T		BIT(24)
+-#define FMC_CSQCFGR2_RCMD2T		BIT(25)
+-
+-/* Register: FMC_CSQCFGR3 */
+-#define FMC_CSQCFGR3_SNBR(x)		(((x) & 0x1f) << 8)
+-#define FMC_CSQCFGR3_AC1T		BIT(16)
+-#define FMC_CSQCFGR3_AC2T		BIT(17)
+-#define FMC_CSQCFGR3_AC3T		BIT(18)
+-#define FMC_CSQCFGR3_AC4T		BIT(19)
+-#define FMC_CSQCFGR3_AC5T		BIT(20)
+-#define FMC_CSQCFGR3_SDT		BIT(21)
+-#define FMC_CSQCFGR3_RAC1T		BIT(22)
+-#define FMC_CSQCFGR3_RAC2T		BIT(23)
+-
+-/* Register: FMC_CSQCAR1 */
+-#define FMC_CSQCAR1_ADDC1(x)		(((x) & 0xff) << 0)
+-#define FMC_CSQCAR1_ADDC2(x)		(((x) & 0xff) << 8)
+-#define FMC_CSQCAR1_ADDC3(x)		(((x) & 0xff) << 16)
+-#define FMC_CSQCAR1_ADDC4(x)		(((x) & 0xff) << 24)
+-
+-/* Register: FMC_CSQCAR2 */
+-#define FMC_CSQCAR2_ADDC5(x)		(((x) & 0xff) << 0)
+-#define FMC_CSQCAR2_SAO(x)		(((x) & 0xffff) << 16)
+-
+-/* Register: FMC_CSQIER */
+-#define FMC_CSQIER_TCIE			BIT(0)
+-
+-/* Register: FMC_CSQICR */
+-#define FMC_CSQICR_CTCF			BIT(0)
+-#define FMC_CSQICR_CSCF			BIT(1)
+-#define FMC_CSQICR_CSEF			BIT(2)
+-#define FMC_CSQICR_CSUEF		BIT(3)
+-#define FMC_CSQICR_CCMDTCF		BIT(4)
+-
+-/* Register: FMC_CSQEMSR */
+-#define FMC_CSQEMSR_SEM			GENMASK(15, 0)
+-
+-/* Register: FMC_BCHIER */
+-#define FMC_BCHIER_DERIE		BIT(1)
+-#define FMC_BCHIER_EPBRIE		BIT(4)
+-
+-/* Register: FMC_BCHICR */
+-#define FMC_BCHICR_CDUEF		BIT(0)
+-#define FMC_BCHICR_CDERF		BIT(1)
+-#define FMC_BCHICR_CDEFF		BIT(2)
+-#define FMC_BCHICR_CDSRF		BIT(3)
+-#define FMC_BCHICR_CEPBRF		BIT(4)
+-
+-/* Register: FMC_BCHDSR0 */
+-#define FMC_BCHDSR0_DUE			BIT(0)
+-#define FMC_BCHDSR0_DEF			BIT(1)
+-#define FMC_BCHDSR0_DEN_MASK		GENMASK(7, 4)
+-#define FMC_BCHDSR0_DEN_SHIFT		4
+-
+-/* Register: FMC_BCHDSR1 */
+-#define FMC_BCHDSR1_EBP1_MASK		GENMASK(12, 0)
+-#define FMC_BCHDSR1_EBP2_MASK		GENMASK(28, 16)
+-#define FMC_BCHDSR1_EBP2_SHIFT		16
+-
+-/* Register: FMC_BCHDSR2 */
+-#define FMC_BCHDSR2_EBP3_MASK		GENMASK(12, 0)
+-#define FMC_BCHDSR2_EBP4_MASK		GENMASK(28, 16)
+-#define FMC_BCHDSR2_EBP4_SHIFT		16
+-
+-/* Register: FMC_BCHDSR3 */
+-#define FMC_BCHDSR3_EBP5_MASK		GENMASK(12, 0)
+-#define FMC_BCHDSR3_EBP6_MASK		GENMASK(28, 16)
+-#define FMC_BCHDSR3_EBP6_SHIFT		16
+-
+-/* Register: FMC_BCHDSR4 */
+-#define FMC_BCHDSR4_EBP7_MASK		GENMASK(12, 0)
+-#define FMC_BCHDSR4_EBP8_MASK		GENMASK(28, 16)
+-#define FMC_BCHDSR4_EBP8_SHIFT		16
+-
+-enum stm32_ecc {
+-	FMC_ECC_HAM = 1,
+-	FMC_ECC_BCH4 = 4,
+-	FMC_ECC_BCH8 = 8
+-};
+-
+-enum stm32_irq_state {
+-	FMC_IRQ_UNKNOWN = 0,
+-	FMC_IRQ_BCH,
+-	FMC_IRQ_SEQ
+-};
+-
+-struct stm32_fmc_timings {
+-	u8 tclr;
+-	u8 tar;
+-	u8 thiz;
+-	u8 twait;
+-	u8 thold_mem;
+-	u8 tset_mem;
+-	u8 thold_att;
+-	u8 tset_att;
+-};
+-
+-struct stm32_fmc {
+-	struct nand_chip chip;
+-	struct device *dev;
+-	void __iomem *io_base;
+-	void __iomem *common_base;
+-	void __iomem *attrib_base;
+-	struct clk *clk;
+-
+-	struct dma_chan *dma_data_ch;
+-	struct dma_chan *dma_ecc_ch;
+-	struct sg_table dma_data_sg;
+-	struct sg_table dma_ecc_sg;
+-	u8 *ecc_buf;
+-	int dma_ecc_len;
+-
+-	struct completion complete;
+-	struct completion dma_data_complete;
+-	struct completion dma_ecc_complete;
+-
+-	struct stm32_fmc_timings timings;
+-	u8 irq_state;
+-	unsigned int bank;
+-};
+-
+-/* Enable irq sources in case of the sequencer is used */
+-static inline void stm32_fmc_enable_seq_irq(struct stm32_fmc *fmc)
+-{
+-	u32 csqier = readl_relaxed(fmc->io_base + FMC_CSQIER);
+-
+-	csqier |= FMC_CSQIER_TCIE;
+-
+-	fmc->irq_state = FMC_IRQ_SEQ;
+-
+-	writel_relaxed(csqier, fmc->io_base + FMC_CSQIER);
+-}
+-
+-/* Disable irq sources in case of the sequencer is used */
+-static inline void stm32_fmc_disable_seq_irq(struct stm32_fmc *fmc)
+-{
+-	u32 csqier = readl_relaxed(fmc->io_base + FMC_CSQIER);
+-
+-	csqier &= ~FMC_CSQIER_TCIE;
+-
+-	writel_relaxed(csqier, fmc->io_base + FMC_CSQIER);
+-
+-	fmc->irq_state = FMC_IRQ_UNKNOWN;
+-}
+-
+-/* Clear irq sources in case of the sequencer is used */
+-static inline void stm32_fmc_clear_seq_irq(struct stm32_fmc *fmc)
+-{
+-	u32 csqicr = FMC_CSQICR_CTCF;
+-
+-	csqicr |= FMC_CSQICR_CSCF;
+-	csqicr |= FMC_CSQICR_CSEF;
+-	csqicr |= FMC_CSQICR_CSUEF;
+-	csqicr |= FMC_CSQICR_CCMDTCF;
+-
+-	writel_relaxed(csqicr, fmc->io_base + FMC_CSQICR);
+-}
+-
+-/* Enable irq sources in case of bch is used */
+-static inline void stm32_fmc_enable_bch_irq(struct stm32_fmc *fmc, int mode)
+-{
+-	u32 bchier = readl_relaxed(fmc->io_base + FMC_BCHIER);
+-
+-	if (mode == NAND_ECC_WRITE)
+-		bchier |= FMC_BCHIER_EPBRIE;
+-	else
+-		bchier |= FMC_BCHIER_DERIE;
+-
+-	fmc->irq_state = FMC_IRQ_BCH;
+-
+-	writel_relaxed(bchier, fmc->io_base + FMC_BCHIER);
+-}
+-
+-/* Disable irq sources in case of bch is used */
+-static inline void stm32_fmc_disable_bch_irq(struct stm32_fmc *fmc)
+-{
+-	u32 bchier = readl_relaxed(fmc->io_base + FMC_BCHIER);
+-
+-	bchier &= ~FMC_BCHIER_DERIE;
+-	bchier &= ~FMC_BCHIER_EPBRIE;
+-
+-	writel_relaxed(bchier, fmc->io_base + FMC_BCHIER);
+-
+-	fmc->irq_state = FMC_IRQ_UNKNOWN;
+-}
+-
+-/* Clear irq sources in case of bch is used */
+-static inline void stm32_fmc_clear_bch_irq(struct stm32_fmc *fmc)
+-{
+-	u32 bchicr = FMC_BCHICR_CDUEF;
+-
+-	bchicr |= FMC_BCHICR_CDERF;
+-	bchicr |= FMC_BCHICR_CDEFF;
+-	bchicr |= FMC_BCHICR_CDSRF;
+-	bchicr |= FMC_BCHICR_CEPBRF;
+-
+-	writel_relaxed(bchicr, fmc->io_base + FMC_BCHICR);
+-}
+-
+-/* Send command and address cycles */
+-static void stm32_fmc_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct stm32_fmc *fmc = nand_get_controller_data(chip);
+-	void __iomem *base = fmc->attrib_base;
+-
+-	if (cmd == NAND_CMD_NONE)
+-		return;
+-
+-	if (ctrl & NAND_CLE) {
+-		writeb_relaxed(cmd, base + FMC_COMMAND_SECTION);
+-		return;
+-	}
+-
+-	writeb_relaxed(cmd, base + FMC_ADDRESS_SECTION);
+-}
+-
+-/*
+- * Enable ecc logic and reset syndrome/parity bits previously calculated
+- * Syndrome/parity bits is cleared by setting the ECCEN bit to 0
+- */
+-static void stm32_fmc_hwctl(struct mtd_info *mtd, int mode)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct stm32_fmc *fmc = nand_get_controller_data(chip);
+-	u32 pcr = readl_relaxed(fmc->io_base + FMC_PCR(fmc->bank));
+-
+-	pcr &= ~FMC_PCR_ECCEN;
+-	writel_relaxed(pcr, fmc->io_base + FMC_PCR(fmc->bank));
+-
+-	if (chip->ecc.strength != FMC_ECC_HAM) {
+-		if (mode == NAND_ECC_WRITE)
+-			pcr |= FMC_PCR_WEN;
+-		else
+-			pcr &= ~FMC_PCR_WEN;
+-		writel_relaxed(pcr, fmc->io_base + FMC_PCR(fmc->bank));
+-
+-		reinit_completion(&fmc->complete);
+-		stm32_fmc_clear_bch_irq(fmc);
+-		stm32_fmc_enable_bch_irq(fmc, mode);
+-	}
+-
+-	pcr |= FMC_PCR_ECCEN;
+-	writel_relaxed(pcr, fmc->io_base + FMC_PCR(fmc->bank));
+-}
+-
+-/*
+- * ECC HAMMING calculation
+- * ECC is 3 bytes for 512 bytes of data (supports error correction up to
+- * max of 1-bit)
+- */
+-static inline void stm32_fmc_ham_decode(const u32 ecc_sta, u8 *ecc)
+-{
+-	ecc[0] = ecc_sta;
+-	ecc[1] = ecc_sta >> 8;
+-	ecc[2] = ecc_sta >> 16;
+-	ecc[3] = 0x0;
+-}
+-
+-static int stm32_fmc_ham_calculate(struct mtd_info *mtd, const uint8_t *data,
+-				   uint8_t *ecc)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct stm32_fmc *fmc = nand_get_controller_data(chip);
+-	u32 sr, heccr;
+-	int ret;
+-
+-	ret = readl_relaxed_poll_timeout(fmc->io_base + FMC_SR(fmc->bank),
+-					 sr, sr & FMC_SR_NWRF, 10, 1000);
+-	if (ret) {
+-		dev_err(fmc->dev, "ham timeout\n");
+-		return ret;
+-	}
+-
+-	heccr = readl_relaxed(fmc->io_base + FMC_HECCR(fmc->bank));
+-
+-	stm32_fmc_ham_decode(heccr, ecc);
+-
+-	return 0;
+-}
+-
+-static int stm32_fmc_ham_correct(struct mtd_info *mtd, uint8_t *dat,
+-				 uint8_t *read_ecc, uint8_t *calc_ecc)
+-{
+-	u8 bit_position = 0, b0, b1, b2;
+-	u32 byte_addr = 0, b;
+-	u32 i, shifting = 1;
+-
+-	/* Indicate which bit and byte is faulty (if any) */
+-	b0 = read_ecc[0] ^ calc_ecc[0];
+-	b1 = read_ecc[1] ^ calc_ecc[1];
+-	b2 = read_ecc[2] ^ calc_ecc[2];
+-	b = b0 | (b1 << 8) | (b2 << 16);
+-
+-	/* No errors */
+-	if (likely(!b))
+-		return 0;
+-
+-	/* Calculate bit position */
+-	for (i = 0; i < 3; i++) {
+-		switch (b % 4) {
+-		case 2:
+-			bit_position += shifting;
+-		case 1:
+-			break;
+-		default:
+-			return -EBADMSG;
+-		}
+-		shifting <<= 1;
+-		b >>= 2;
+-	}
+-
+-	/* Calculate byte position */
+-	shifting = 1;
+-	for (i = 0; i < 9; i++) {
+-		switch (b % 4) {
+-		case 2:
+-			byte_addr += shifting;
+-		case 1:
+-			break;
+-		default:
+-			return -EBADMSG;
+-		}
+-		shifting <<= 1;
+-		b >>= 2;
+-	}
+-
+-	/* Flip the bit */
+-	dat[byte_addr] ^= (1 << bit_position);
+-
+-	return 1;
+-}
+-
+-/*
+- * ECC BCH calculation and correction
+- * ECC is 7/13 bytes for 512 bytes of data (supports error correction up to
+- * max of 4-bit/8-bit)
+- */
+-static int stm32_fmc_bch_calculate(struct mtd_info *mtd, const uint8_t *data,
+-				   uint8_t *ecc)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct stm32_fmc *fmc = nand_get_controller_data(chip);
+-	u32 bchpbr;
+-
+-	/* Wait that the BCH encoder parity is available */
+-	if (!wait_for_completion_timeout(&fmc->complete,
+-					 msecs_to_jiffies(1000))) {
+-		dev_err(fmc->dev, "bch timeout\n");
+-		stm32_fmc_disable_bch_irq(fmc);
+-		return -ETIMEDOUT;
+-	}
+-
+-	/* Read parity bits (write) or syndrome (read) */
+-	bchpbr = readl_relaxed(fmc->io_base + FMC_BCHPBR1);
+-	ecc[0] = bchpbr;
+-	ecc[1] = bchpbr >> 8;
+-	ecc[2] = bchpbr >> 16;
+-	ecc[3] = bchpbr >> 24;
+-
+-	bchpbr = readl_relaxed(fmc->io_base + FMC_BCHPBR2);
+-	ecc[4] = bchpbr;
+-	ecc[5] = bchpbr >> 8;
+-	ecc[6] = bchpbr >> 16;
+-	ecc[7] = 0x0;
+-
+-	if (chip->ecc.strength == FMC_ECC_BCH8) {
+-		ecc[7] = bchpbr >> 24;
+-
+-		bchpbr = readl_relaxed(fmc->io_base + FMC_BCHPBR3);
+-		ecc[8] = bchpbr;
+-		ecc[9] = bchpbr >> 8;
+-		ecc[10] = bchpbr >> 16;
+-		ecc[11] = bchpbr >> 24;
+-
+-		bchpbr = readl_relaxed(fmc->io_base + FMC_BCHPBR4);
+-		ecc[12] = bchpbr;
+-		ecc[13] = 0x0;
+-	}
+-
+-	return 0;
+-}
+-
+-/* BCH algorithm correction */
+-static int stm32_fmc_bch_correct_data(struct nand_chip *chip, u8 *dat,
+-				      u8 *read_ecc, u32 *ecc_sta)
+-{
+-	u32 bchdsr0 = ecc_sta[0];
+-	u32 bchdsr1 = ecc_sta[1];
+-	u32 bchdsr2 = ecc_sta[2];
+-	u32 bchdsr3 = ecc_sta[3];
+-	u32 bchdsr4 = ecc_sta[4];
+-	u16 pos[8];
+-	int i, den, eccsize = chip->ecc.size;
+-
+-	/* No errors found */
+-	if (likely(!(bchdsr0 & FMC_BCHDSR0_DEF)))
+-		return 0;
+-
+-	/* Too many errors detected */
+-	if (unlikely(bchdsr0 & FMC_BCHDSR0_DUE))
+-		return -EBADMSG;
+-
+-	pos[0] = bchdsr1 & FMC_BCHDSR1_EBP1_MASK;
+-	pos[1] = (bchdsr1 & FMC_BCHDSR1_EBP2_MASK) >> FMC_BCHDSR1_EBP2_SHIFT;
+-	pos[2] = bchdsr2 & FMC_BCHDSR2_EBP3_MASK;
+-	pos[3] = (bchdsr2 & FMC_BCHDSR2_EBP4_MASK) >> FMC_BCHDSR2_EBP4_SHIFT;
+-	pos[4] = bchdsr3 & FMC_BCHDSR3_EBP5_MASK;
+-	pos[5] = (bchdsr3 & FMC_BCHDSR3_EBP6_MASK) >> FMC_BCHDSR3_EBP6_SHIFT;
+-	pos[6] = bchdsr4 & FMC_BCHDSR4_EBP7_MASK;
+-	pos[7] = (bchdsr4 & FMC_BCHDSR4_EBP8_MASK) >> FMC_BCHDSR4_EBP8_SHIFT;
+-
+-	den = (bchdsr0 & FMC_BCHDSR0_DEN_MASK) >> FMC_BCHDSR0_DEN_SHIFT;
+-	for (i = 0; i < den; i++) {
+-		if (pos[i] < eccsize * 8)
+-			change_bit(pos[i], (unsigned long *)dat);
+-	}
+-
+-	return den;
+-}
+-
+-static int stm32_fmc_bch_correct(struct mtd_info *mtd, uint8_t *dat,
+-				 uint8_t *read_ecc, uint8_t *calc_ecc)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct stm32_fmc *fmc = nand_get_controller_data(chip);
+-	u32 ecc_sta[5];
+-
+-	/* Wait that the BCH syndrome is available */
+-	if (!wait_for_completion_timeout(&fmc->complete,
+-					 msecs_to_jiffies(1000))) {
+-		dev_err(fmc->dev, "bch timeout\n");
+-		stm32_fmc_disable_bch_irq(fmc);
+-		return -ETIMEDOUT;
+-	}
+-
+-	ecc_sta[0] = readl_relaxed(fmc->io_base + FMC_BCHDSR0);
+-	ecc_sta[1] = readl_relaxed(fmc->io_base + FMC_BCHDSR1);
+-	ecc_sta[2] = readl_relaxed(fmc->io_base + FMC_BCHDSR2);
+-	ecc_sta[3] = readl_relaxed(fmc->io_base + FMC_BCHDSR3);
+-	ecc_sta[4] = readl_relaxed(fmc->io_base + FMC_BCHDSR4);
+-
+-	return stm32_fmc_bch_correct_data(chip, dat, read_ecc, &ecc_sta[0]);
+-}
+-
+-static int stm32_fmc_read_page(struct mtd_info *mtd,
+-			       struct nand_chip *chip, uint8_t *buf,
+-			       int oob_required, int page)
+-{
+-	int i, s, stat, eccsize = chip->ecc.size;
+-	int eccbytes = chip->ecc.bytes;
+-	int eccsteps = chip->ecc.steps;
+-	int eccstrength = chip->ecc.strength;
+-	u8 *p = buf;
+-	u8 *ecc_calc = chip->buffers->ecccalc;
+-	u8 *ecc_code = chip->buffers->ecccode;
+-	unsigned int max_bitflips = 0;
+-
+-	for (i = mtd->writesize + FMC_BBM_LEN, s = 0; s < eccsteps;
+-	     s++, i += eccbytes, p += eccsize) {
+-		chip->ecc.hwctl(mtd, NAND_ECC_READ);
+-
+-		/* Read the nand page sector (512 bytes) */
+-		chip->cmdfunc(mtd, NAND_CMD_RNDOUT, s * eccsize, -1);
+-		chip->read_buf(mtd, p, eccsize);
+-
+-		/* Read the corresponding ecc bytes */
+-		chip->cmdfunc(mtd, NAND_CMD_RNDOUT, i, -1);
+-		chip->read_buf(mtd, ecc_code, eccbytes);
+-
+-		/* Correct the data */
+-		stat = chip->ecc.correct(mtd, p, ecc_code, ecc_calc);
+-		if (stat == -EBADMSG)
+-			/* Check for empty pages with bitflips */
+-			stat = nand_check_erased_ecc_chunk(p, eccsize,
+-							   ecc_code, eccbytes,
+-							   NULL, 0,
+-							   eccstrength);
+-
+-		if (stat < 0) {
+-			mtd->ecc_stats.failed++;
+-		} else {
+-			mtd->ecc_stats.corrected += stat;
+-			max_bitflips = max_t(unsigned int, max_bitflips, stat);
+-		}
+-	}
+-
+-	/* Read oob */
+-	if (oob_required) {
+-		chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize, -1);
+-		chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+-	}
+-
+-	return max_bitflips;
+-}
+-
+-/* Sequencer read/write configuration */
+-static void stm32_fmc_rw_page_init(struct stm32_fmc *fmc, int page,
+-				   int raw, bool write_data)
+-{
+-	struct nand_chip *chip = &fmc->chip;
+-	struct mtd_info *mtd = nand_to_mtd(chip);
+-	u32 csqcfgr1, csqcfgr2, csqcfgr3;
+-	u32 csqar1, csqar2;
+-	u32 ecc_offset = mtd->writesize + FMC_BBM_LEN;
+-	u32 pcr = readl_relaxed(fmc->io_base + FMC_PCR(fmc->bank));
+-
+-	if (write_data)
+-		pcr |= FMC_PCR_WEN;
+-	else
+-		pcr &= ~FMC_PCR_WEN;
+-	writel_relaxed(pcr, fmc->io_base + FMC_PCR(fmc->bank));
+-
+-	if (chip->ecc.strength != FMC_ECC_HAM)
+-		stm32_fmc_clear_bch_irq(fmc);
+-
+-	/*
+-	 * - Set Program Page/Page Read command
+-	 * - Enable DMA request data
+-	 * - Set timings
+-	 */
+-	csqcfgr1 = FMC_CSQCFGR1_DMADEN | FMC_CSQCFGR1_CMD1T;
+-	if (write_data)
+-		csqcfgr1 |= FMC_CSQCFGR1_CMD1(NAND_CMD_SEQIN);
+-	else
+-		csqcfgr1 |= FMC_CSQCFGR1_CMD1(NAND_CMD_READ0) |
+-			    FMC_CSQCFGR1_CMD2EN |
+-			    FMC_CSQCFGR1_CMD2(NAND_CMD_READSTART) |
+-			    FMC_CSQCFGR1_CMD2T;
+-
+-	/*
+-	 * - Set Random Data Input/Random Data Read command
+-	 * - Enable the sequencer to access the Spare data area
+-	 * - Enable  DMA request status decoding for read
+-	 * - Set timings
+-	 */
+-	csqcfgr2 = FMC_CSQCFGR2_RCMD1T;
+-	if (write_data)
+-		csqcfgr2 |= FMC_CSQCFGR2_RCMD1(NAND_CMD_RNDIN);
+-	else
+-		csqcfgr2 |= FMC_CSQCFGR2_RCMD1(NAND_CMD_RNDOUT) |
+-			    FMC_CSQCFGR2_RCMD2EN |
+-			    FMC_CSQCFGR2_RCMD2(NAND_CMD_RNDOUTSTART) |
+-			    FMC_CSQCFGR2_RCMD2T;
+-	if (!raw) {
+-		csqcfgr2 |= write_data ? 0 : FMC_CSQCFGR2_DMASEN;
+-		csqcfgr2 |= FMC_CSQCFGR2_SQSDTEN;
+-	}
+-
+-	/*
+-	 * - Set the number of sectors to be written
+-	 * - Set timings
+-	 */
+-	csqcfgr3 = FMC_CSQCFGR3_SNBR(chip->ecc.steps - 1);
+-	if (write_data) {
+-		csqcfgr3 |= FMC_CSQCFGR3_RAC2T;
+-		if (chip->chipsize > SZ_128M)
+-			csqcfgr3 |= FMC_CSQCFGR3_AC5T;
+-		else
+-			csqcfgr3 |= FMC_CSQCFGR3_AC4T;
+-	}
+-
+-	/*
+-	 * Set the fourth first address cycles
+-	 * Byte 1 and byte 2 => column, we start at 0x0
+-	 * Byte 3 and byte 4 => page
+-	 */
+-	csqar1 = FMC_CSQCAR1_ADDC3(page);
+-	csqar1 |= FMC_CSQCAR1_ADDC4(page >> 8);
+-
+-	/*
+-	 * - Set ecc byte offset in the spare area
+-	 * - Calculate the number of address cycles to be issued
+-	 * - Set byte 5 of address cycle if needed
+-	 */
+-	if (chip->options & NAND_BUSWIDTH_16)
+-		csqar2 = FMC_CSQCAR2_SAO(ecc_offset >> 1);
+-	else
+-		csqar2 = FMC_CSQCAR2_SAO(ecc_offset);
+-	if (chip->chipsize > SZ_128M) {
+-		csqcfgr1 |= FMC_CSQCFGR1_ACYNBR(5);
+-		csqar2 |= FMC_CSQCAR2_ADDC5(page >> 16);
+-	} else {
+-		csqcfgr1 |= FMC_CSQCFGR1_ACYNBR(4);
+-	}
+-
+-	writel_relaxed(csqcfgr1, fmc->io_base + FMC_CSQCFGR1);
+-	writel_relaxed(csqcfgr2, fmc->io_base + FMC_CSQCFGR2);
+-	writel_relaxed(csqcfgr3, fmc->io_base + FMC_CSQCFGR3);
+-	writel_relaxed(csqar1, fmc->io_base + FMC_CSQAR1);
+-	writel_relaxed(csqar2, fmc->io_base + FMC_CSQAR2);
+-}
+-
+-static void stm32_fmc_dma_callback(void *arg)
+-{
+-	struct completion *dma_completion = arg;
+-
+-	complete(dma_completion);
+-}
+-
+-/* Read/write data from/to a page */
+-static int stm32_fmc_xfer(struct stm32_fmc *fmc, const u8 *buf,
+-			  int raw, bool write_data)
+-{
+-	struct nand_chip *chip = &fmc->chip;
+-	struct dma_async_tx_descriptor *desc_data, *desc_ecc;
+-	struct scatterlist *sg;
+-	enum dma_data_direction dma_data_dir = DMA_FROM_DEVICE;
+-	enum dma_transfer_direction dma_transfer_dir = DMA_DEV_TO_MEM;
+-	u32 csqcr = readl_relaxed(fmc->io_base + FMC_CSQCR);
+-	int eccsteps = chip->ecc.steps;
+-	int eccsize = chip->ecc.size;
+-	const u8 *p = buf;
+-	int s, ret;
+-
+-	/* Configure DMA data */
+-	if (write_data) {
+-		dma_data_dir = DMA_TO_DEVICE;
+-		dma_transfer_dir = DMA_MEM_TO_DEV;
+-	}
+-
+-	for_each_sg(fmc->dma_data_sg.sgl, sg, eccsteps, s) {
+-		sg_set_buf(sg, p, eccsize);
+-		p += eccsize;
+-	}
+-
+-	ret = dma_map_sg(fmc->dev, fmc->dma_data_sg.sgl,
+-			 eccsteps, dma_data_dir);
+-	if (ret < 0)
+-		return ret;
+-
+-	desc_data = dmaengine_prep_slave_sg(fmc->dma_data_ch,
+-					    fmc->dma_data_sg.sgl,
+-					    eccsteps, dma_transfer_dir,
+-					    DMA_PREP_INTERRUPT);
+-	if (!desc_data) {
+-		ret = -ENOMEM;
+-		goto err_unmap_data;
+-	}
+-
+-	reinit_completion(&fmc->dma_data_complete);
+-	reinit_completion(&fmc->complete);
+-	desc_data->callback = stm32_fmc_dma_callback;
+-	desc_data->callback_param = &fmc->dma_data_complete;
+-	ret = dma_submit_error(dmaengine_submit(desc_data));
+-	if (ret)
+-		goto err_unmap_data;
+-
+-	dma_async_issue_pending(fmc->dma_data_ch);
+-
+-	if (!write_data && !raw) {
+-		/* Configure DMA ecc status */
+-		p = fmc->ecc_buf;
+-		for_each_sg(fmc->dma_ecc_sg.sgl, sg, eccsteps, s) {
+-			sg_set_buf(sg, p, fmc->dma_ecc_len);
+-			p += fmc->dma_ecc_len;
+-		}
+-
+-		ret = dma_map_sg(fmc->dev, fmc->dma_ecc_sg.sgl,
+-				 eccsteps, dma_data_dir);
+-		if (ret < 0)
+-			goto err_unmap_data;
+-
+-		desc_ecc = dmaengine_prep_slave_sg(fmc->dma_ecc_ch,
+-						   fmc->dma_ecc_sg.sgl,
+-						   eccsteps, dma_transfer_dir,
+-						   DMA_PREP_INTERRUPT);
+-		if (!desc_ecc) {
+-			ret = -ENOMEM;
+-			goto err_unmap_ecc;
+-		}
+-
+-		reinit_completion(&fmc->dma_ecc_complete);
+-		desc_ecc->callback = stm32_fmc_dma_callback;
+-		desc_ecc->callback_param = &fmc->dma_ecc_complete;
+-		ret = dma_submit_error(dmaengine_submit(desc_ecc));
+-		if (ret)
+-			goto err_unmap_ecc;
+-
+-		dma_async_issue_pending(fmc->dma_ecc_ch);
+-	}
+-
+-	stm32_fmc_clear_seq_irq(fmc);
+-	stm32_fmc_enable_seq_irq(fmc);
+-
+-	/* Start the transfer */
+-	csqcr |= FMC_CSQCR_CSQSTART;
+-	writel_relaxed(csqcr, fmc->io_base + FMC_CSQCR);
+-
+-	/* Wait end of sequencer transfer */
+-	if (!wait_for_completion_timeout(&fmc->complete,
+-					 msecs_to_jiffies(1000))) {
+-		dev_err(fmc->dev, "seq timeout\n");
+-		stm32_fmc_disable_seq_irq(fmc);
+-		dmaengine_terminate_all(fmc->dma_data_ch);
+-		if (!write_data && !raw)
+-			dmaengine_terminate_all(fmc->dma_ecc_ch);
+-		ret = -ETIMEDOUT;
+-		goto err_unmap_ecc;
+-	}
+-
+-	/* Wait DMA data transfer completion */
+-	if (!wait_for_completion_timeout(&fmc->dma_data_complete,
+-					 msecs_to_jiffies(100))) {
+-		dev_err(fmc->dev, "data DMA timeout\n");
+-		dmaengine_terminate_all(fmc->dma_data_ch);
+-		ret = -ETIMEDOUT;
+-	}
+-
+-	/* Wait DMA ecc transfer completion */
+-	if (!write_data && !raw) {
+-		if (!wait_for_completion_timeout(&fmc->dma_ecc_complete,
+-						 msecs_to_jiffies(100))) {
+-			dev_err(fmc->dev, "ecc DMA timeout\n");
+-			dmaengine_terminate_all(fmc->dma_ecc_ch);
+-			ret = -ETIMEDOUT;
+-		}
+-	}
+-
+-err_unmap_ecc:
+-	if (!write_data && !raw)
+-		dma_unmap_sg(fmc->dev, fmc->dma_ecc_sg.sgl,
+-			     eccsteps, dma_data_dir);
+-
+-err_unmap_data:
+-	dma_unmap_sg(fmc->dev, fmc->dma_data_sg.sgl, eccsteps, dma_data_dir);
+-
+-	return ret;
+-}
+-
+-static int stm32_fmc_sequencer_write(struct mtd_info *mtd,
+-				     struct nand_chip *chip,
+-				     const u8 *buf, int oob_required,
+-				     int page, int raw)
+-{
+-	struct stm32_fmc *fmc = nand_get_controller_data(chip);
+-	int ret;
+-
+-	/* Configure the sequencer */
+-	stm32_fmc_rw_page_init(fmc, page, raw, true);
+-
+-	/* Write the page */
+-	ret = stm32_fmc_xfer(fmc, buf, raw, true);
+-	if (ret)
+-		return ret;
+-
+-	/* Write oob */
+-	if (oob_required) {
+-		chip->cmdfunc(mtd, NAND_CMD_RNDIN, mtd->writesize, -1);
+-		chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+-	}
+-
+-	/* Send command to program the page */
+-	chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+-
+-	ret = chip->waitfunc(mtd, chip);
+-
+-	return ret & NAND_STATUS_FAIL ? -EIO : 0;
+-}
+-
+-static int stm32_fmc_sequencer_write_page(struct mtd_info *mtd,
+-					  struct nand_chip *chip,
+-					  const uint8_t *buf,
+-					  int oob_required,
+-					  int page)
+-{
+-	return stm32_fmc_sequencer_write(mtd, chip, buf,
+-					 oob_required, page, false);
+-}
+-
+-static int stm32_fmc_sequencer_write_page_raw(struct mtd_info *mtd,
+-					      struct nand_chip *chip,
+-					      const uint8_t *buf,
+-					      int oob_required,
+-					      int page)
+-{
+-	return stm32_fmc_sequencer_write(mtd, chip, buf,
+-					 oob_required, page, true);
+-}
+-
+-/*
+- * Get a status indicating which sectors have errors
+- * Only available when the sequencer is used (BCH only)
+- */
+-static inline u16 stm32_fmc_get_mapping_status(struct stm32_fmc *fmc)
+-{
+-	u32 csqemsr = readl_relaxed(fmc->io_base + FMC_CSQEMSR);
+-
+-	return csqemsr & FMC_CSQEMSR_SEM;
+-}
+-
+-static int stm32_fmc_sequencer_read_page(struct mtd_info *mtd,
+-					 struct nand_chip *chip,
+-					 uint8_t *buf,
+-					 int oob_required,
+-					 int page)
+-{
+-	struct stm32_fmc *fmc = nand_get_controller_data(chip);
+-	int i, s, ret, eccsize = chip->ecc.size;
+-	int eccbytes = chip->ecc.bytes;
+-	int eccsteps = chip->ecc.steps;
+-	int eccstrength = chip->ecc.strength;
+-	u8 *p = buf;
+-	u8 *ecc_calc = chip->buffers->ecccalc;
+-	u8 *ecc_code = chip->buffers->ecccode;
+-	u32 *ecc_sta = (u32 *)fmc->ecc_buf;
+-	u16 sta_map = 0xFFFF;
+-	unsigned int max_bitflips = 0;
+-
+-	/* Configure the sequencer */
+-	stm32_fmc_rw_page_init(fmc, page, 0, false);
+-
+-	/* Read the page */
+-	ret = stm32_fmc_xfer(fmc, buf, 0, false);
+-	if (ret)
+-		return ret;
+-
+-	/* In case of BCH is used, get errors mapping */
+-	if (eccstrength != FMC_ECC_HAM)
+-		sta_map = stm32_fmc_get_mapping_status(fmc);
+-
+-	/* Read oob */
+-	chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize, -1);
+-	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+-
+-	/* Check if errors happen for BCH algorithm */
+-	if (likely(!sta_map))
+-		return 0;
+-
+-	ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, chip->oob_poi, 0,
+-					 chip->ecc.total);
+-	if (ret)
+-		return ret;
+-
+-	/* Correct data */
+-	for (i = 0, s = 0; s < eccsteps; s++, i += eccbytes, p += eccsize) {
+-		int stat = 0;
+-
+-		if (eccstrength == FMC_ECC_HAM) {
+-			/* Ecc_sta = FMC_HECCR */
+-			stm32_fmc_ham_decode(*ecc_sta, &ecc_calc[i]);
+-			stat = stm32_fmc_ham_correct(mtd, p, &ecc_code[i],
+-						     &ecc_calc[i]);
+-			ecc_sta++;
+-		} else {
+-			/*
+-			 * Ecc_sta[0] = FMC_BCHDSR0
+-			 * Ecc_sta[1] = FMC_BCHDSR1
+-			 * Ecc_sta[2] = FMC_BCHDSR2
+-			 * Ecc_sta[3] = FMC_BCHDSR3
+-			 * Ecc_sta[4] = FMC_BCHDSR4
+-			 */
+-			if (sta_map & BIT(s))
+-				stat = stm32_fmc_bch_correct_data(chip, p,
+-								  &ecc_code[i],
+-								  ecc_sta);
+-			ecc_sta += 5;
+-		}
+-
+-		if (stat == -EBADMSG)
+-			/* Check for empty pages with bitflips */
+-			stat = nand_check_erased_ecc_chunk(p, eccsize,
+-							   ecc_code, eccbytes,
+-							   NULL, 0,
+-							   eccstrength);
+-
+-		if (stat < 0) {
+-			mtd->ecc_stats.failed++;
+-		} else {
+-			mtd->ecc_stats.corrected += stat;
+-			max_bitflips = max_t(unsigned int, max_bitflips, stat);
+-		}
+-	}
+-
+-	return max_bitflips;
+-}
+-
+-static int stm32_fmc_sequencer_read_page_raw(struct mtd_info *mtd,
+-					     struct nand_chip *chip,
+-					     uint8_t *buf,
+-					     int oob_required,
+-					     int page)
+-{
+-	struct stm32_fmc *fmc = nand_get_controller_data(chip);
+-	int ret;
+-
+-	/* Configure the sequencer */
+-	stm32_fmc_rw_page_init(fmc, page, 1, false);
+-
+-	/* Read the page */
+-	ret = stm32_fmc_xfer(fmc, buf, 1, false);
+-	if (ret)
+-		return ret;
+-
+-	/* Read oob */
+-	if (oob_required) {
+-		chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize, -1);
+-		chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+-	}
+-
+-	return 0;
+-}
+-
+-static irqreturn_t stm32_fmc_irq(int irq, void *dev_id)
+-{
+-	struct stm32_fmc *fmc = (struct stm32_fmc *)dev_id;
+-
+-	if (fmc->irq_state == FMC_IRQ_SEQ)
+-		/* Sequencer is used */
+-		stm32_fmc_disable_seq_irq(fmc);
+-	else if (fmc->irq_state == FMC_IRQ_BCH)
+-		/* BCH is used */
+-		stm32_fmc_disable_bch_irq(fmc);
+-
+-	complete(&fmc->complete);
+-
+-	return IRQ_HANDLED;
+-}
+-
+-/* Timings configuration */
+-static void stm32_fmc_timings_init(struct stm32_fmc *fmc)
+-{
+-	struct stm32_fmc_timings *timings = &fmc->timings;
+-	u32 pcr = readl_relaxed(fmc->io_base + FMC_PCR(fmc->bank));
+-	u32 pmem, patt;
+-
+-	/* Set tclr/tar timings */
+-	pcr &= ~FMC_PCR_TCLR_MASK;
+-	pcr |= FMC_PCR_TCLR(timings->tclr);
+-	pcr &= ~FMC_PCR_TAR_MASK;
+-	pcr |= FMC_PCR_TAR(timings->tar);
+-
+-	/* Set tset/twait/thold/thiz timings in common bank */
+-	pmem = FMC_PMEM_MEMSET(timings->tset_mem);
+-	pmem |= FMC_PMEM_MEMWAIT(timings->twait);
+-	pmem |= FMC_PMEM_MEMHOLD(timings->thold_mem);
+-	pmem |= FMC_PMEM_MEMHIZ(timings->thiz);
+-
+-	/* Set tset/twait/thold/thiz timings in attribut bank */
+-	patt = FMC_PATT_ATTSET(timings->tset_att);
+-	patt |= FMC_PATT_ATTWAIT(timings->twait);
+-	patt |= FMC_PATT_ATTHOLD(timings->thold_att);
+-	patt |= FMC_PATT_ATTHIZ(timings->thiz);
+-
+-	writel_relaxed(pcr, fmc->io_base + FMC_PCR(fmc->bank));
+-	writel_relaxed(pmem, fmc->io_base + FMC_PMEM(fmc->bank));
+-	writel_relaxed(patt, fmc->io_base + FMC_PATT(fmc->bank));
+-}
+-
+-/* Controller initialization */
+-static void stm32_fmc_init(struct stm32_fmc *fmc)
+-{
+-	u32 pcr = readl_relaxed(fmc->io_base + FMC_PCR(fmc->bank));
+-	u32 bcr1 = readl_relaxed(fmc->io_base + FMC_BCR1);
+-
+-	/* Enable wait feature and nand flash memory bank */
+-	pcr |= FMC_PCR_PWAITEN;
+-	pcr |= FMC_PCR_PBKEN;
+-
+-	/* Set buswidth to 8 bits mode for identification */
+-	pcr &= ~FMC_PCR_PWID_MASK;
+-
+-	/* Enable FMC controller */
+-	bcr1 |= FMC_BCR1_FMCEN;
+-
+-	writel_relaxed(bcr1, fmc->io_base + FMC_BCR1);
+-	writel_relaxed(pcr, fmc->io_base + FMC_PCR(fmc->bank));
+-}
+-
+-/* Controller configuration */
+-static void stm32_fmc_setup(struct stm32_fmc *fmc)
+-{
+-	struct nand_chip *chip = &fmc->chip;
+-	u32 pcr = readl_relaxed(fmc->io_base + FMC_PCR(fmc->bank));
+-
+-	/* Configure in HAMMING by default */
+-	if (chip->ecc.strength == FMC_ECC_BCH8) {
+-		pcr |= FMC_PCR_ECCALG;
+-		pcr |= FMC_PCR_BCHECC;
+-	} else if (chip->ecc.strength == FMC_ECC_BCH4) {
+-		pcr |= FMC_PCR_ECCALG;
+-	}
+-
+-	/* Set buswidth */
+-	if (chip->options & NAND_BUSWIDTH_16)
+-		pcr |= FMC_PCR_PWID(FMC_PCR_PWID_BUSWIDTH_16);
+-
+-	/* Set ecc sector size */
+-	pcr &= ~FMC_PCR_ECCSS_MASK;
+-	pcr |= FMC_PCR_ECCSS(FMC_PCR_ECCSS_512);
+-
+-	writel_relaxed(pcr, fmc->io_base + FMC_PCR(fmc->bank));
+-}
+-
+-/* Controller timings */
+-static int stm32_fmc_calc_timings(struct stm32_fmc *fmc,
+-				  const struct nand_sdr_timings *sdrt,
+-				  struct stm32_fmc_timings *tims)
+-{
+-	unsigned long hclk = clk_get_rate(fmc->clk);
+-	unsigned long hclkp = NSEC_PER_SEC / (hclk / 1000);
+-	int tar, tclr, thiz, twait, tset_mem, tset_att, thold_mem, thold_att;
+-
+-	tar = hclkp;
+-	if (tar < sdrt->tAR_min)
+-		tar = sdrt->tAR_min;
+-	tims->tar = DIV_ROUND_UP(tar, hclkp) - 1;
+-	if (tims->tar > FMC_PCR_TIMING_MASK)
+-		tims->tar = FMC_PCR_TIMING_MASK;
+-
+-	tclr = hclkp;
+-	if (tclr < sdrt->tCLR_min)
+-		tclr = sdrt->tCLR_min;
+-	tims->tclr = DIV_ROUND_UP(tclr, hclkp) - 1;
+-	if (tims->tclr > FMC_PCR_TIMING_MASK)
+-		tims->tclr = FMC_PCR_TIMING_MASK;
+-
+-	tims->thiz = FMC_THIZ;
+-	thiz = (tims->thiz + 1) * hclkp;
+-
+-	/*
+-	 * tWAIT > tRP
+-	 * tWAIT > tWP
+-	 * tWAIT > tREA + tIO
+-	 */
+-	twait = hclkp;
+-	if (twait < sdrt->tRP_min)
+-		twait = sdrt->tRP_min;
+-	if (twait < sdrt->tWP_min)
+-		twait = sdrt->tWP_min;
+-	if (twait < sdrt->tREA_max + FMC_TIO)
+-		twait = sdrt->tREA_max + FMC_TIO;
+-	tims->twait = DIV_ROUND_UP(twait, hclkp) - 1;
+-	if (tims->twait > FMC_PMEM_PATT_TIMING_MASK)
+-		tims->twait = FMC_PMEM_PATT_TIMING_MASK;
+-
+-	/*
+-	 * tSETUP_MEM > tCS - tWAIT
+-	 * tSETUP_MEM > tALS - tWAIT
+-	 * tSETUP_MEM > tDS - (tWAIT - tHIZ)
+-	 */
+-	tset_mem = hclkp;
+-	if ((sdrt->tCS_min > twait) && (tset_mem < sdrt->tCS_min - twait))
+-		tset_mem = sdrt->tCS_min - twait;
+-	if ((sdrt->tALS_min > twait) && (tset_mem < sdrt->tALS_min - twait))
+-		tset_mem = sdrt->tALS_min - twait;
+-	if ((twait > thiz) && (sdrt->tDS_min > twait - thiz) &&
+-	    (tset_mem < sdrt->tDS_min - (twait - thiz)))
+-		tset_mem = sdrt->tDS_min - (twait - thiz);
+-	tims->tset_mem = DIV_ROUND_UP(tset_mem, hclkp) - 1;
+-	if (tims->tset_mem > FMC_PMEM_PATT_TIMING_MASK)
+-		tims->tset_mem = FMC_PMEM_PATT_TIMING_MASK;
+-
+-	/*
+-	 * tHOLD_MEM > tCH
+-	 * tHOLD_MEM > tREH - tSETUP_MEM
+-	 * tHOLD_MEM > max(tRC, tWC) - (tSETUP_MEM + tWAIT)
+-	 */
+-	thold_mem = hclkp;
+-	if (thold_mem < sdrt->tCH_min)
+-		thold_mem = sdrt->tCH_min;
+-	if ((sdrt->tREH_min > tset_mem) &&
+-	    (thold_mem < sdrt->tREH_min - tset_mem))
+-		thold_mem = sdrt->tREH_min - tset_mem;
+-	if ((sdrt->tRC_min > tset_mem + twait) &&
+-	    (thold_mem < sdrt->tRC_min - (tset_mem + twait)))
+-		thold_mem = sdrt->tRC_min - (tset_mem + twait);
+-	if ((sdrt->tWC_min > tset_mem + twait) &&
+-	    (thold_mem < sdrt->tWC_min - (tset_mem + twait)))
+-		thold_mem = sdrt->tWC_min - (tset_mem + twait);
+-	tims->thold_mem = DIV_ROUND_UP(thold_mem, hclkp) - 1;
+-	if (tims->thold_mem > FMC_PMEM_PATT_TIMING_MASK)
+-		tims->thold_mem = FMC_PMEM_PATT_TIMING_MASK;
+-
+-	/*
+-	 * tSETUP_ATT > tCS - tWAIT
+-	 * tSETUP_ATT > tCLS - tWAIT
+-	 * tSETUP_ATT > tALS - tWAIT
+-	 * tSETUP_ATT > tRHW - tHOLD_MEM
+-	 * tSETUP_ATT > tDS - (tWAIT - tHIZ)
+-	 */
+-	tset_att = hclkp;
+-	if ((sdrt->tCS_min > twait) && (tset_att < sdrt->tCS_min - twait))
+-		tset_att = sdrt->tCS_min - twait;
+-	if ((sdrt->tCLS_min > twait) && (tset_att < sdrt->tCLS_min - twait))
+-		tset_att = sdrt->tCLS_min - twait;
+-	if ((sdrt->tALS_min > twait) && (tset_att < sdrt->tALS_min - twait))
+-		tset_att = sdrt->tALS_min - twait;
+-	if ((sdrt->tRHW_min > thold_mem) &&
+-	    (tset_att < sdrt->tRHW_min - thold_mem))
+-		tset_att = sdrt->tRHW_min - thold_mem;
+-	if ((twait > thiz) && (sdrt->tDS_min > twait - thiz) &&
+-	    (tset_att < sdrt->tDS_min - (twait - thiz)))
+-		tset_att = sdrt->tDS_min - (twait - thiz);
+-	tims->tset_att = DIV_ROUND_UP(tset_att, hclkp) - 1;
+-	if (tims->tset_att > FMC_PMEM_PATT_TIMING_MASK)
+-		tims->tset_att = FMC_PMEM_PATT_TIMING_MASK;
+-
+-	/*
+-	 * tHOLD_ATT > tALH
+-	 * tHOLD_ATT > tCH
+-	 * tHOLD_ATT > tCLH
+-	 * tHOLD_ATT > tCOH
+-	 * tHOLD_ATT > tDH
+-	 * tHOLD_ATT > tWB + tIO + tSYNC - tSETUP_MEM
+-	 * tHOLD_ATT > tADL - tSETUP_MEM
+-	 * tHOLD_ATT > tWH - tSETUP_MEM
+-	 * tHOLD_ATT > tWHR - tSETUP_MEM
+-	 * tHOLD_ATT > tRC - (tSETUP_ATT + tWAIT)
+-	 * tHOLD_ATT > tWC - (tSETUP_ATT + tWAIT)
+-	 */
+-	thold_att = hclkp;
+-	if (thold_att < sdrt->tALH_min)
+-		thold_att = sdrt->tALH_min;
+-	if (thold_att < sdrt->tCH_min)
+-		thold_att = sdrt->tCH_min;
+-	if (thold_att < sdrt->tCLH_min)
+-		thold_att = sdrt->tCLH_min;
+-	if (thold_att < sdrt->tCOH_min)
+-		thold_att = sdrt->tCOH_min;
+-	if (thold_att < sdrt->tDH_min)
+-		thold_att = sdrt->tDH_min;
+-	if ((sdrt->tWB_max + FMC_TIO + FMC_TSYNC > tset_mem) &&
+-	    (thold_att < sdrt->tWB_max + FMC_TIO + FMC_TSYNC - tset_mem))
+-		thold_att = sdrt->tWB_max + FMC_TIO + FMC_TSYNC - tset_mem;
+-	if ((sdrt->tADL_min > tset_mem) &&
+-	    (thold_att < sdrt->tADL_min - tset_mem))
+-		thold_att = sdrt->tADL_min - tset_mem;
+-	if ((sdrt->tWH_min > tset_mem) &&
+-	    (thold_att < sdrt->tWH_min - tset_mem))
+-		thold_att = sdrt->tWH_min - tset_mem;
+-	if ((sdrt->tWHR_min > tset_mem) &&
+-	    (thold_att < sdrt->tWHR_min - tset_mem))
+-		thold_att = sdrt->tWHR_min - tset_mem;
+-	if ((sdrt->tRC_min > tset_att + twait) &&
+-	    (thold_att < sdrt->tRC_min - (tset_att + twait)))
+-		thold_att = sdrt->tRC_min - (tset_att + twait);
+-	if ((sdrt->tWC_min > tset_att + twait) &&
+-	    (thold_att < sdrt->tWC_min - (tset_att + twait)))
+-		thold_att = sdrt->tWC_min - (tset_att + twait);
+-	tims->thold_att = DIV_ROUND_UP(thold_att, hclkp) - 1;
+-	if (tims->thold_att > FMC_PMEM_PATT_TIMING_MASK)
+-		tims->thold_att = FMC_PMEM_PATT_TIMING_MASK;
+-
+-	return 0;
+-}
+-
+-static int stm32_fmc_setup_interface(struct mtd_info *mtd, int chipnr,
+-				     const struct nand_data_interface *conf)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct stm32_fmc *fmc = nand_get_controller_data(chip);
+-	struct stm32_fmc_timings tims;
+-	const struct nand_sdr_timings *sdrt;
+-	int ret;
+-
+-	sdrt = nand_get_sdr_timings(conf);
+-	if (IS_ERR(sdrt))
+-		return PTR_ERR(sdrt);
+-
+-	ret = stm32_fmc_calc_timings(fmc, sdrt, &tims);
+-	if (ret)
+-		return ret;
+-
+-	if (chipnr == NAND_DATA_IFACE_CHECK_ONLY)
+-		return 0;
+-
+-	/* Save and apply timings */
+-	memcpy(&fmc->timings, &tims, sizeof(tims));
+-	stm32_fmc_timings_init(fmc);
+-
+-	return 0;
+-}
+-
+-/* DMA configuration */
+-static int stm32_fmc_nand_dma_setup(struct stm32_fmc *fmc, u8 nb_sect,
+-				    phys_addr_t data_phys_base,
+-				    phys_addr_t io_phys_base)
+-{
+-	struct nand_chip *chip = &fmc->chip;
+-	struct dma_slave_config dma_cfg;
+-	int ret;
+-
+-	/*
+-	 * Data DMA is found => sequencer mode will be used
+-	 * Else manual mode is used
+-	 */
+-	fmc->dma_data_ch = dma_request_slave_channel(fmc->dev, "rxtx");
+-	if (fmc->dma_data_ch) {
+-		memset(&dma_cfg, 0, sizeof(dma_cfg));
+-		dma_cfg.src_addr = data_phys_base;
+-		dma_cfg.dst_addr = data_phys_base;
+-		dma_cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+-		dma_cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+-		dma_cfg.src_maxburst = 32;
+-		dma_cfg.dst_maxburst = 32;
+-
+-		ret = dmaengine_slave_config(fmc->dma_data_ch, &dma_cfg);
+-		if (ret) {
+-			dev_err(fmc->dev, "data DMA engine slave config failed\n");
+-			return ret;
+-		}
+-
+-		ret = sg_alloc_table(&fmc->dma_data_sg, nb_sect, GFP_KERNEL);
+-		if (ret)
+-			return ret;
+-
+-		fmc->dma_ecc_ch = dma_request_slave_channel(fmc->dev, "ecc");
+-		if (fmc->dma_ecc_ch) {
+-			/*
+-			 * HAMMING: we read HECCR register
+-			 * BCH4/BCH8: we read BCHDSRSx registers
+-			 */
+-			memset(&dma_cfg, 0, sizeof(dma_cfg));
+-			dma_cfg.src_addr = io_phys_base;
+-			dma_cfg.src_addr += chip->ecc.strength == FMC_ECC_HAM ?
+-					    FMC_HECCR(fmc->bank) : FMC_BCHDSR0;
+-			dma_cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+-
+-			ret = dmaengine_slave_config(fmc->dma_ecc_ch,
+-						     &dma_cfg);
+-			if (ret) {
+-				dev_err(fmc->dev, "ecc DMA engine slave config failed\n");
+-				return ret;
+-			}
+-
+-			ret = sg_alloc_table(&fmc->dma_ecc_sg,
+-					     nb_sect, GFP_KERNEL);
+-			if (ret)
+-				return ret;
+-
+-			/* Calculate ecc length needed for one sector */
+-			fmc->dma_ecc_len = chip->ecc.strength == FMC_ECC_HAM ?
+-					   FMC_HECCR_LEN : FMC_BCHDSRS_LEN;
+-
+-			/* Allocate a buffer to store ecc status registers */
+-			fmc->ecc_buf = devm_kzalloc(fmc->dev,
+-						    fmc->dma_ecc_len * nb_sect,
+-						    GFP_KERNEL);
+-			if (!fmc->ecc_buf)
+-				return -ENOMEM;
+-		} else {
+-			dev_err(fmc->dev, "ecc DMA not defined in the device tree\n");
+-			return -ENOENT;
+-		}
+-	}
+-
+-	return 0;
+-}
+-
+-/* NAND callbacks setup */
+-static void stm32_fmc_nand_callbacks_setup(struct stm32_fmc *fmc)
+-{
+-	struct nand_chip *chip = &fmc->chip;
+-
+-	/*
+-	 * Specific callbacks to read/write a page depending on
+-	 * the mode (manual/sequencer) and the algo used (HAMMING, BCH).
+-	 */
+-	if (fmc->dma_data_ch) {
+-		/* DMA => use sequencer mode callbacks */
+-		chip->ecc.write_page = stm32_fmc_sequencer_write_page;
+-		chip->ecc.read_page = stm32_fmc_sequencer_read_page;
+-		chip->ecc.write_page_raw = stm32_fmc_sequencer_write_page_raw;
+-		chip->ecc.read_page_raw = stm32_fmc_sequencer_read_page_raw;
+-		chip->options |= NAND_USE_BOUNCE_BUFFER;
+-		chip->ecc.options |= NAND_ECC_CUSTOM_PAGE_ACCESS;
+-	} else {
+-		/* No DMA => use manual mode callbacks */
+-		chip->ecc.hwctl = stm32_fmc_hwctl;
+-		if (chip->ecc.strength == FMC_ECC_HAM) {
+-			/* HAMMING is used */
+-			chip->ecc.calculate = stm32_fmc_ham_calculate;
+-			chip->ecc.correct = stm32_fmc_ham_correct;
+-		} else {
+-			/* BCH is used */
+-			chip->ecc.read_page = stm32_fmc_read_page;
+-			chip->ecc.calculate = stm32_fmc_bch_calculate;
+-			chip->ecc.correct = stm32_fmc_bch_correct;
+-		}
+-	}
+-
+-	/* Specific configurations depending on the algo used (HAMMING, BCH) */
+-	if (chip->ecc.strength == FMC_ECC_HAM) {
+-		chip->ecc.bytes = chip->options & NAND_BUSWIDTH_16 ? 4 : 3;
+-		chip->ecc.options |= NAND_ECC_GENERIC_ERASED_CHECK;
+-	} else if (chip->ecc.strength == FMC_ECC_BCH8) {
+-		chip->ecc.bytes = chip->options & NAND_BUSWIDTH_16 ? 14 : 13;
+-	} else {
+-		chip->ecc.bytes = chip->options & NAND_BUSWIDTH_16 ? 8 : 7;
+-	}
+-}
+-
+-/* FMC layout */
+-static int stm32_fmc_nand_ooblayout_ecc(struct mtd_info *mtd, int section,
+-					struct mtd_oob_region *oobregion)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct nand_ecc_ctrl *ecc = &chip->ecc;
+-
+-	if (section)
+-		return -ERANGE;
+-
+-	oobregion->length = ecc->total;
+-	oobregion->offset = FMC_BBM_LEN;
+-
+-	return 0;
+-}
+-
+-static int stm32_fmc_nand_ooblayout_free(struct mtd_info *mtd, int section,
+-					 struct mtd_oob_region *oobregion)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct nand_ecc_ctrl *ecc = &chip->ecc;
+-
+-	if (section)
+-		return -ERANGE;
+-
+-	oobregion->length = mtd->oobsize - ecc->total - FMC_BBM_LEN;
+-	oobregion->offset = ecc->total + FMC_BBM_LEN;
+-
+-	return 0;
+-}
+-
+-const struct mtd_ooblayout_ops stm32_fmc_nand_ooblayout_ops = {
+-	.ecc = stm32_fmc_nand_ooblayout_ecc,
+-	.free = stm32_fmc_nand_ooblayout_free,
+-};
+-
+-static bool stm32_fmc_parse_dt(struct platform_device *pdev)
+-{
+-	struct device *dev = &pdev->dev;
+-	struct device_node *dn = dev->of_node;
+-	struct stm32_fmc *fmc = platform_get_drvdata(pdev);
+-	int ret;
+-
+-	/* Get the bank used, bank 3 is used by default */
+-	if (of_property_read_u32(dn, "st,fmc_bank_used", &fmc->bank))
+-		fmc->bank = 3;
+-
+-	/* Common bank timings */
+-	ret = of_property_read_u8_array(dn, "st,fmc_timings",
+-					(u8 *)&fmc->timings,
+-					sizeof(fmc->timings));
+-
+-	return ret ? false : true;
+-}
+-
+-static int stm32_fmc_probe(struct platform_device *pdev)
+-{
+-	struct device *dev = &pdev->dev;
+-	struct reset_control *rstc;
+-	struct stm32_fmc *fmc;
+-	struct resource *res;
+-	struct mtd_info *mtd;
+-	struct nand_chip *chip;
+-	phys_addr_t data_phys_base, io_phys_base;
+-	u16 ecc_space_needed;
+-	u8 nb_sect;
+-	int ret, irq;
+-	bool timings_def;
+-
+-	fmc = devm_kzalloc(dev, sizeof(*fmc), GFP_KERNEL);
+-	if (!fmc)
+-		return -ENOMEM;
+-
+-	fmc->dev = dev;
+-	platform_set_drvdata(pdev, fmc);
+-
+-	timings_def = stm32_fmc_parse_dt(pdev);
+-
+-	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fmc_regs");
+-	fmc->io_base = devm_ioremap_resource(dev, res);
+-	if (IS_ERR(fmc->io_base))
+-		return PTR_ERR(fmc->io_base);
+-
+-	io_phys_base = res->start;
+-
+-	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fmc_common");
+-	fmc->common_base = devm_ioremap_resource(dev, res);
+-	if (IS_ERR(fmc->common_base))
+-		return PTR_ERR(fmc->common_base);
+-
+-	data_phys_base = res->start + FMC_DATA_SECTION;
+-
+-	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fmc_attrib");
+-	fmc->attrib_base = devm_ioremap_resource(dev, res);
+-	if (IS_ERR(fmc->attrib_base))
+-		return PTR_ERR(fmc->attrib_base);
+-
+-	irq = platform_get_irq(pdev, 0);
+-	ret = devm_request_irq(dev, irq, stm32_fmc_irq, 0,
+-			       dev_name(dev), fmc);
+-	if (ret) {
+-		dev_err(dev, "failed to request irq\n");
+-		return ret;
+-	}
+-
+-	init_completion(&fmc->complete);
+-	init_completion(&fmc->dma_data_complete);
+-	init_completion(&fmc->dma_ecc_complete);
+-
+-	fmc->clk = devm_clk_get(dev, NULL);
+-	if (IS_ERR(fmc->clk))
+-		return PTR_ERR(fmc->clk);
+-
+-	ret = clk_prepare_enable(fmc->clk);
+-	if (ret) {
+-		dev_err(dev, "can not enable the clock\n");
+-		return ret;
+-	}
+-
+-	rstc = devm_reset_control_get(dev, NULL);
+-	if (!IS_ERR(rstc)) {
+-		reset_control_assert(rstc);
+-		reset_control_deassert(rstc);
+-	}
+-
+-	mtd = nand_to_mtd(&fmc->chip);
+-	chip = &fmc->chip;
+-	nand_set_controller_data(chip, fmc);
+-	nand_set_flash_node(chip, dev->of_node);
+-	mtd->dev.parent = dev;
+-
+-	/* Set NAND IO addresses and command/ready functions */
+-	chip->IO_ADDR_R = fmc->common_base + FMC_DATA_SECTION;
+-	chip->IO_ADDR_W = fmc->common_base + FMC_DATA_SECTION;
+-	chip->cmd_ctrl = stm32_fmc_cmd_ctrl;
+-	chip->chip_delay = FMC_RB_DELAY_US;
+-	chip->options |= NAND_BUSWIDTH_AUTO | NAND_NO_SUBPAGE_WRITE;
+-
+-	/* FMC init routine */
+-	stm32_fmc_init(fmc);
+-	if (timings_def)
+-		stm32_fmc_timings_init(fmc);
+-	else
+-		chip->setup_data_interface = stm32_fmc_setup_interface;
+-
+-	/*
+-	 * Only NAND_ECC_HW mode is actually supported
+-	 * HAMMING => ecc.strength = 1
+-	 * BCH4 => ecc.strength = 4
+-	 * BCH8 => ecc.strength = 8 (default)
+-	 */
+-	chip->ecc.mode = NAND_ECC_HW;
+-	chip->ecc.size = 512;
+-	chip->ecc.strength = FMC_ECC_BCH8;
+-
+-	/* Scan to find existence of the device */
+-	ret = nand_scan_ident(mtd, 1, NULL);
+-	if (ret)
+-		goto err_scan_ident;
+-
+-	if (chip->ecc.size != 512) {
+-		dev_err(dev, "ecc_step_size is not well defined in the DT\n");
+-		ret = -EINVAL;
+-		goto err_scan_ident;
+-	}
+-
+-	if ((chip->ecc.strength != FMC_ECC_BCH8) &&
+-	    (chip->ecc.strength != FMC_ECC_BCH4) &&
+-	    (chip->ecc.strength != FMC_ECC_HAM)) {
+-		dev_err(dev, "ecc_strength is not well defined in the DT\n");
+-		ret = -EINVAL;
+-		goto err_scan_ident;
+-	}
+-
+-	nb_sect = mtd->writesize / chip->ecc.size;
+-	if (nb_sect > FMC_MAX_SG_COUNT) {
+-		dev_err(dev, "nand page size is not supported\n");
+-		ret = -EINVAL;
+-		goto err_scan_ident;
+-	}
+-
+-	if (chip->bbt_options & NAND_BBT_USE_FLASH)
+-		chip->bbt_options |= NAND_BBT_NO_OOB;
+-
+-	/* FMC setup routine */
+-	stm32_fmc_setup(fmc);
+-
+-	/* DMA setup */
+-	ret = stm32_fmc_nand_dma_setup(fmc, nb_sect, data_phys_base,
+-				       io_phys_base);
+-	if (ret)
+-		goto err_dma_setup;
+-
+-	/* NAND callbacks setup */
+-	stm32_fmc_nand_callbacks_setup(fmc);
+-
+-	/*
+-	 * Check if parity bits can be stored in OOB
+-	 * The first 2 bytes are skipped (BBM)
+-	 */
+-	ecc_space_needed = chip->ecc.bytes * nb_sect;
+-	if (mtd->oobsize < (ecc_space_needed + FMC_BBM_LEN)) {
+-		dev_err(dev, "not enough OOB bytes required = %d, available=%d\n",
+-			ecc_space_needed, mtd->oobsize);
+-		ret = -EINVAL;
+-		goto err_dma_setup;
+-	}
+-
+-	/* Define ECC layout */
+-	mtd_set_ooblayout(mtd, &stm32_fmc_nand_ooblayout_ops);
+-
+-	/* Scan the device to fill MTD data-structures */
+-	if (nand_scan_tail(mtd)) {
+-		ret = -ENXIO;
+-		goto err_dma_setup;
+-	}
+-
+-	ret = mtd_device_register(mtd, NULL, 0);
+-	if (ret)
+-		goto err_dma_setup;
+-
+-	return 0;
+-
+-err_dma_setup:
+-	if (fmc->dma_ecc_ch)
+-		dma_release_channel(fmc->dma_ecc_ch);
+-
+-	if (fmc->dma_data_ch)
+-		dma_release_channel(fmc->dma_data_ch);
+-
+-	sg_free_table(&fmc->dma_data_sg);
+-	sg_free_table(&fmc->dma_ecc_sg);
+-
+-err_scan_ident:
+-	clk_disable_unprepare(fmc->clk);
+-
+-	return ret;
+-}
+-
+-static int stm32_fmc_remove(struct platform_device *pdev)
+-{
+-	struct stm32_fmc *fmc = platform_get_drvdata(pdev);
+-	struct mtd_info *mtd = nand_to_mtd(&fmc->chip);
+-
+-	if (fmc->dma_ecc_ch)
+-		dma_release_channel(fmc->dma_ecc_ch);
+-
+-	if (fmc->dma_data_ch)
+-		dma_release_channel(fmc->dma_data_ch);
+-
+-	sg_free_table(&fmc->dma_data_sg);
+-	sg_free_table(&fmc->dma_ecc_sg);
+-
+-	clk_disable_unprepare(fmc->clk);
+-
+-	nand_release(mtd);
+-
+-	return 0;
+-}
+-
+-#ifdef CONFIG_PM_SLEEP
+-static int stm32_fmc_suspend(struct device *dev)
+-{
+-	struct stm32_fmc *fmc = dev_get_drvdata(dev);
+-
+-	clk_disable_unprepare(fmc->clk);
+-
+-	return 0;
+-}
+-
+-static int stm32_fmc_resume(struct device *dev)
+-{
+-	struct stm32_fmc *fmc = dev_get_drvdata(dev);
+-	int ret;
+-
+-	ret = clk_prepare_enable(fmc->clk);
+-	if (ret) {
+-		dev_err(dev, "can not enable the clock\n");
+-		return ret;
+-	}
+-
+-	stm32_fmc_init(fmc);
+-	stm32_fmc_timings_init(fmc);
+-	stm32_fmc_setup(fmc);
+-
+-	return 0;
+-}
+-#endif
+-
+-static SIMPLE_DEV_PM_OPS(stm32_fmc_pm_ops, stm32_fmc_suspend, stm32_fmc_resume);
+-
+-static const struct of_device_id stm32_fmc_match[] = {
+-	{.compatible = "st,stm32mp1-fmc"},
+-	{}
+-};
+-MODULE_DEVICE_TABLE(of, stm32_fmc_match);
+-
+-static struct platform_driver stm32_fmc_driver = {
+-	.probe	= stm32_fmc_probe,
+-	.remove	= stm32_fmc_remove,
+-	.driver	= {
+-		.name = "stm32-fmc",
+-		.of_match_table = stm32_fmc_match,
+-		.pm = &stm32_fmc_pm_ops,
+-	},
+-};
+-module_platform_driver(stm32_fmc_driver);
+-
+-MODULE_ALIAS("platform:" DRIVER_NAME);
+-MODULE_AUTHOR("Christophe Kerello <christophe.kerello@st.com>");
+-MODULE_DESCRIPTION("STMicroelectronics STM32 fmc nand driver");
+-MODULE_LICENSE("GPL v2");
+diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c
+deleted file mode 100644
+index 82244be..0000000
+--- a/drivers/mtd/nand/sunxi_nand.c
++++ /dev/null
+@@ -1,2310 +0,0 @@
+-/*
+- * Copyright (C) 2013 Boris BREZILLON <b.brezillon.dev@gmail.com>
+- *
+- * Derived from:
+- *	https://github.com/yuq/sunxi-nfc-mtd
+- *	Copyright (C) 2013 Qiang Yu <yuq825@gmail.com>
+- *
+- *	https://github.com/hno/Allwinner-Info
+- *	Copyright (C) 2013 Henrik Nordström <Henrik Nordström>
+- *
+- *	Copyright (C) 2013 Dmitriy B. <rzk333@gmail.com>
+- *	Copyright (C) 2013 Sergey Lapin <slapin@ossfans.org>
+- *
+- * 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/dma-mapping.h>
+-#include <linux/slab.h>
+-#include <linux/module.h>
+-#include <linux/moduleparam.h>
+-#include <linux/platform_device.h>
+-#include <linux/of.h>
+-#include <linux/of_device.h>
+-#include <linux/of_gpio.h>
+-#include <linux/mtd/mtd.h>
+-#include <linux/mtd/rawnand.h>
+-#include <linux/mtd/partitions.h>
+-#include <linux/clk.h>
+-#include <linux/delay.h>
+-#include <linux/dmaengine.h>
+-#include <linux/gpio.h>
+-#include <linux/interrupt.h>
+-#include <linux/iopoll.h>
+-#include <linux/reset.h>
+-
+-#define NFC_REG_CTL		0x0000
+-#define NFC_REG_ST		0x0004
+-#define NFC_REG_INT		0x0008
+-#define NFC_REG_TIMING_CTL	0x000C
+-#define NFC_REG_TIMING_CFG	0x0010
+-#define NFC_REG_ADDR_LOW	0x0014
+-#define NFC_REG_ADDR_HIGH	0x0018
+-#define NFC_REG_SECTOR_NUM	0x001C
+-#define NFC_REG_CNT		0x0020
+-#define NFC_REG_CMD		0x0024
+-#define NFC_REG_RCMD_SET	0x0028
+-#define NFC_REG_WCMD_SET	0x002C
+-#define NFC_REG_IO_DATA		0x0030
+-#define NFC_REG_ECC_CTL		0x0034
+-#define NFC_REG_ECC_ST		0x0038
+-#define NFC_REG_DEBUG		0x003C
+-#define NFC_REG_ECC_ERR_CNT(x)	((0x0040 + (x)) & ~0x3)
+-#define NFC_REG_USER_DATA(x)	(0x0050 + ((x) * 4))
+-#define NFC_REG_SPARE_AREA	0x00A0
+-#define NFC_REG_PAT_ID		0x00A4
+-#define NFC_RAM0_BASE		0x0400
+-#define NFC_RAM1_BASE		0x0800
+-
+-/* define bit use in NFC_CTL */
+-#define NFC_EN			BIT(0)
+-#define NFC_RESET		BIT(1)
+-#define NFC_BUS_WIDTH_MSK	BIT(2)
+-#define NFC_BUS_WIDTH_8		(0 << 2)
+-#define NFC_BUS_WIDTH_16	(1 << 2)
+-#define NFC_RB_SEL_MSK		BIT(3)
+-#define NFC_RB_SEL(x)		((x) << 3)
+-#define NFC_CE_SEL_MSK		GENMASK(26, 24)
+-#define NFC_CE_SEL(x)		((x) << 24)
+-#define NFC_CE_CTL		BIT(6)
+-#define NFC_PAGE_SHIFT_MSK	GENMASK(11, 8)
+-#define NFC_PAGE_SHIFT(x)	(((x) < 10 ? 0 : (x) - 10) << 8)
+-#define NFC_SAM			BIT(12)
+-#define NFC_RAM_METHOD		BIT(14)
+-#define NFC_DEBUG_CTL		BIT(31)
+-
+-/* define bit use in NFC_ST */
+-#define NFC_RB_B2R		BIT(0)
+-#define NFC_CMD_INT_FLAG	BIT(1)
+-#define NFC_DMA_INT_FLAG	BIT(2)
+-#define NFC_CMD_FIFO_STATUS	BIT(3)
+-#define NFC_STA			BIT(4)
+-#define NFC_NATCH_INT_FLAG	BIT(5)
+-#define NFC_RB_STATE(x)		BIT(x + 8)
+-
+-/* define bit use in NFC_INT */
+-#define NFC_B2R_INT_ENABLE	BIT(0)
+-#define NFC_CMD_INT_ENABLE	BIT(1)
+-#define NFC_DMA_INT_ENABLE	BIT(2)
+-#define NFC_INT_MASK		(NFC_B2R_INT_ENABLE | \
+-				 NFC_CMD_INT_ENABLE | \
+-				 NFC_DMA_INT_ENABLE)
+-
+-/* define bit use in NFC_TIMING_CTL */
+-#define NFC_TIMING_CTL_EDO	BIT(8)
+-
+-/* define NFC_TIMING_CFG register layout */
+-#define NFC_TIMING_CFG(tWB, tADL, tWHR, tRHW, tCAD)		\
+-	(((tWB) & 0x3) | (((tADL) & 0x3) << 2) |		\
+-	(((tWHR) & 0x3) << 4) | (((tRHW) & 0x3) << 6) |		\
+-	(((tCAD) & 0x7) << 8))
+-
+-/* define bit use in NFC_CMD */
+-#define NFC_CMD_LOW_BYTE_MSK	GENMASK(7, 0)
+-#define NFC_CMD_HIGH_BYTE_MSK	GENMASK(15, 8)
+-#define NFC_CMD(x)		(x)
+-#define NFC_ADR_NUM_MSK		GENMASK(18, 16)
+-#define NFC_ADR_NUM(x)		(((x) - 1) << 16)
+-#define NFC_SEND_ADR		BIT(19)
+-#define NFC_ACCESS_DIR		BIT(20)
+-#define NFC_DATA_TRANS		BIT(21)
+-#define NFC_SEND_CMD1		BIT(22)
+-#define NFC_WAIT_FLAG		BIT(23)
+-#define NFC_SEND_CMD2		BIT(24)
+-#define NFC_SEQ			BIT(25)
+-#define NFC_DATA_SWAP_METHOD	BIT(26)
+-#define NFC_ROW_AUTO_INC	BIT(27)
+-#define NFC_SEND_CMD3		BIT(28)
+-#define NFC_SEND_CMD4		BIT(29)
+-#define NFC_CMD_TYPE_MSK	GENMASK(31, 30)
+-#define NFC_NORMAL_OP		(0 << 30)
+-#define NFC_ECC_OP		(1 << 30)
+-#define NFC_PAGE_OP		(2 << 30)
+-
+-/* define bit use in NFC_RCMD_SET */
+-#define NFC_READ_CMD_MSK	GENMASK(7, 0)
+-#define NFC_RND_READ_CMD0_MSK	GENMASK(15, 8)
+-#define NFC_RND_READ_CMD1_MSK	GENMASK(23, 16)
+-
+-/* define bit use in NFC_WCMD_SET */
+-#define NFC_PROGRAM_CMD_MSK	GENMASK(7, 0)
+-#define NFC_RND_WRITE_CMD_MSK	GENMASK(15, 8)
+-#define NFC_READ_CMD0_MSK	GENMASK(23, 16)
+-#define NFC_READ_CMD1_MSK	GENMASK(31, 24)
+-
+-/* define bit use in NFC_ECC_CTL */
+-#define NFC_ECC_EN		BIT(0)
+-#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)
+-#define NFC_ECC_MODE(x)		((x) << 12)
+-#define NFC_RANDOM_SEED_MSK	GENMASK(30, 16)
+-#define NFC_RANDOM_SEED(x)	((x) << 16)
+-
+-/* define bit use in NFC_ECC_ST */
+-#define NFC_ECC_ERR(x)		BIT(x)
+-#define NFC_ECC_ERR_MSK		GENMASK(15, 0)
+-#define NFC_ECC_PAT_FOUND(x)	BIT(x + 16)
+-#define NFC_ECC_ERR_CNT(b, x)	(((x) >> (((b) % 4) * 8)) & 0xff)
+-
+-#define NFC_DEFAULT_TIMEOUT_MS	1000
+-
+-#define NFC_SRAM_SIZE		1024
+-
+-#define NFC_MAX_CS		7
+-
+-/*
+- * Ready/Busy detection type: describes the Ready/Busy detection modes
+- *
+- * @RB_NONE:	no external detection available, rely on STATUS command
+- *		and software timeouts
+- * @RB_NATIVE:	use sunxi NAND controller Ready/Busy support. The Ready/Busy
+- *		pin of the NAND flash chip must be connected to one of the
+- *		native NAND R/B pins (those which can be muxed to the NAND
+- *		Controller)
+- * @RB_GPIO:	use a simple GPIO to handle Ready/Busy status. The Ready/Busy
+- *		pin of the NAND flash chip must be connected to a GPIO capable
+- *		pin.
+- */
+-enum sunxi_nand_rb_type {
+-	RB_NONE,
+-	RB_NATIVE,
+-	RB_GPIO,
+-};
+-
+-/*
+- * Ready/Busy structure: stores information related to Ready/Busy detection
+- *
+- * @type:	the Ready/Busy detection mode
+- * @info:	information related to the R/B detection mode. Either a gpio
+- *		id or a native R/B id (those supported by the NAND controller).
+- */
+-struct sunxi_nand_rb {
+-	enum sunxi_nand_rb_type type;
+-	union {
+-		int gpio;
+-		int nativeid;
+-	} info;
+-};
+-
+-/*
+- * Chip Select structure: stores information related to NAND Chip Select
+- *
+- * @cs:		the NAND CS id used to communicate with a NAND Chip
+- * @rb:		the Ready/Busy description
+- */
+-struct sunxi_nand_chip_sel {
+-	u8 cs;
+-	struct sunxi_nand_rb rb;
+-};
+-
+-/*
+- * sunxi HW ECC infos: stores information related to HW ECC support
+- *
+- * @mode:	the sunxi ECC mode field deduced from ECC requirements
+- */
+-struct sunxi_nand_hw_ecc {
+-	int mode;
+-};
+-
+-/*
+- * NAND chip structure: stores NAND chip device related information
+- *
+- * @node:		used to store NAND chips into a list
+- * @nand:		base NAND chip structure
+- * @mtd:		base MTD structure
+- * @clk_rate:		clk_rate required for this NAND chip
+- * @timing_cfg		TIMING_CFG register value for this NAND chip
+- * @selected:		current active CS
+- * @nsels:		number of CS lines required by the NAND chip
+- * @sels:		array of CS lines descriptions
+- */
+-struct sunxi_nand_chip {
+-	struct list_head node;
+-	struct nand_chip nand;
+-	unsigned long clk_rate;
+-	u32 timing_cfg;
+-	u32 timing_ctl;
+-	int selected;
+-	int addr_cycles;
+-	u32 addr[2];
+-	int cmd_cycles;
+-	u8 cmd[2];
+-	int nsels;
+-	struct sunxi_nand_chip_sel sels[0];
+-};
+-
+-static inline struct sunxi_nand_chip *to_sunxi_nand(struct nand_chip *nand)
+-{
+-	return container_of(nand, struct sunxi_nand_chip, nand);
+-}
+-
+-/*
+- * NAND Controller structure: stores sunxi NAND controller information
+- *
+- * @controller:		base controller structure
+- * @dev:		parent device (used to print error messages)
+- * @regs:		NAND controller registers
+- * @ahb_clk:		NAND Controller AHB clock
+- * @mod_clk:		NAND Controller mod clock
+- * @assigned_cs:	bitmask describing already assigned CS lines
+- * @clk_rate:		NAND controller current clock rate
+- * @chips:		a list containing all the NAND chips attached to
+- *			this NAND controller
+- * @complete:		a completion object used to wait for NAND
+- *			controller events
+- */
+-struct sunxi_nfc {
+-	struct nand_hw_control controller;
+-	struct device *dev;
+-	void __iomem *regs;
+-	struct clk *ahb_clk;
+-	struct clk *mod_clk;
+-	struct reset_control *reset;
+-	unsigned long assigned_cs;
+-	unsigned long clk_rate;
+-	struct list_head chips;
+-	struct completion complete;
+-	struct dma_chan *dmac;
+-};
+-
+-static inline struct sunxi_nfc *to_sunxi_nfc(struct nand_hw_control *ctrl)
+-{
+-	return container_of(ctrl, struct sunxi_nfc, controller);
+-}
+-
+-static irqreturn_t sunxi_nfc_interrupt(int irq, void *dev_id)
+-{
+-	struct sunxi_nfc *nfc = dev_id;
+-	u32 st = readl(nfc->regs + NFC_REG_ST);
+-	u32 ien = readl(nfc->regs + NFC_REG_INT);
+-
+-	if (!(ien & st))
+-		return IRQ_NONE;
+-
+-	if ((ien & st) == ien)
+-		complete(&nfc->complete);
+-
+-	writel(st & NFC_INT_MASK, nfc->regs + NFC_REG_ST);
+-	writel(~st & ien & NFC_INT_MASK, nfc->regs + NFC_REG_INT);
+-
+-	return IRQ_HANDLED;
+-}
+-
+-static int sunxi_nfc_wait_events(struct sunxi_nfc *nfc, u32 events,
+-				 bool use_polling, unsigned int timeout_ms)
+-{
+-	int ret;
+-
+-	if (events & ~NFC_INT_MASK)
+-		return -EINVAL;
+-
+-	if (!timeout_ms)
+-		timeout_ms = NFC_DEFAULT_TIMEOUT_MS;
+-
+-	if (!use_polling) {
+-		init_completion(&nfc->complete);
+-
+-		writel(events, nfc->regs + NFC_REG_INT);
+-
+-		ret = wait_for_completion_timeout(&nfc->complete,
+-						msecs_to_jiffies(timeout_ms));
+-		if (!ret)
+-			ret = -ETIMEDOUT;
+-		else
+-			ret = 0;
+-
+-		writel(0, nfc->regs + NFC_REG_INT);
+-	} else {
+-		u32 status;
+-
+-		ret = readl_poll_timeout(nfc->regs + NFC_REG_ST, status,
+-					 (status & events) == events, 1,
+-					 timeout_ms * 1000);
+-	}
+-
+-	writel(events & NFC_INT_MASK, nfc->regs + NFC_REG_ST);
+-
+-	if (ret)
+-		dev_err(nfc->dev, "wait interrupt timedout\n");
+-
+-	return ret;
+-}
+-
+-static int sunxi_nfc_wait_cmd_fifo_empty(struct sunxi_nfc *nfc)
+-{
+-	u32 status;
+-	int ret;
+-
+-	ret = readl_poll_timeout(nfc->regs + NFC_REG_ST, status,
+-				 !(status & NFC_CMD_FIFO_STATUS), 1,
+-				 NFC_DEFAULT_TIMEOUT_MS * 1000);
+-	if (ret)
+-		dev_err(nfc->dev, "wait for empty cmd FIFO timedout\n");
+-
+-	return ret;
+-}
+-
+-static int sunxi_nfc_rst(struct sunxi_nfc *nfc)
+-{
+-	u32 ctl;
+-	int ret;
+-
+-	writel(0, nfc->regs + NFC_REG_ECC_CTL);
+-	writel(NFC_RESET, nfc->regs + NFC_REG_CTL);
+-
+-	ret = readl_poll_timeout(nfc->regs + NFC_REG_CTL, ctl,
+-				 !(ctl & NFC_RESET), 1,
+-				 NFC_DEFAULT_TIMEOUT_MS * 1000);
+-	if (ret)
+-		dev_err(nfc->dev, "wait for NAND controller reset timedout\n");
+-
+-	return ret;
+-}
+-
+-static int sunxi_nfc_dma_op_prepare(struct mtd_info *mtd, const void *buf,
+-				    int chunksize, int nchunks,
+-				    enum dma_data_direction ddir,
+-				    struct scatterlist *sg)
+-{
+-	struct nand_chip *nand = mtd_to_nand(mtd);
+-	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
+-	struct dma_async_tx_descriptor *dmad;
+-	enum dma_transfer_direction tdir;
+-	dma_cookie_t dmat;
+-	int ret;
+-
+-	if (ddir == DMA_FROM_DEVICE)
+-		tdir = DMA_DEV_TO_MEM;
+-	else
+-		tdir = DMA_MEM_TO_DEV;
+-
+-	sg_init_one(sg, buf, nchunks * chunksize);
+-	ret = dma_map_sg(nfc->dev, sg, 1, ddir);
+-	if (!ret)
+-		return -ENOMEM;
+-
+-	dmad = dmaengine_prep_slave_sg(nfc->dmac, sg, 1, tdir, DMA_CTRL_ACK);
+-	if (!dmad) {
+-		ret = -EINVAL;
+-		goto err_unmap_buf;
+-	}
+-
+-	writel(readl(nfc->regs + NFC_REG_CTL) | NFC_RAM_METHOD,
+-	       nfc->regs + NFC_REG_CTL);
+-	writel(nchunks, nfc->regs + NFC_REG_SECTOR_NUM);
+-	writel(chunksize, nfc->regs + NFC_REG_CNT);
+-	dmat = dmaengine_submit(dmad);
+-
+-	ret = dma_submit_error(dmat);
+-	if (ret)
+-		goto err_clr_dma_flag;
+-
+-	return 0;
+-
+-err_clr_dma_flag:
+-	writel(readl(nfc->regs + NFC_REG_CTL) & ~NFC_RAM_METHOD,
+-	       nfc->regs + NFC_REG_CTL);
+-
+-err_unmap_buf:
+-	dma_unmap_sg(nfc->dev, sg, 1, ddir);
+-	return ret;
+-}
+-
+-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 sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
+-
+-	dma_unmap_sg(nfc->dev, sg, 1, ddir);
+-	writel(readl(nfc->regs + NFC_REG_CTL) & ~NFC_RAM_METHOD,
+-	       nfc->regs + NFC_REG_CTL);
+-}
+-
+-static int sunxi_nfc_dev_ready(struct mtd_info *mtd)
+-{
+-	struct nand_chip *nand = mtd_to_nand(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;
+-	int ret;
+-
+-	if (sunxi_nand->selected < 0)
+-		return 0;
+-
+-	rb = &sunxi_nand->sels[sunxi_nand->selected].rb;
+-
+-	switch (rb->type) {
+-	case RB_NATIVE:
+-		ret = !!(readl(nfc->regs + NFC_REG_ST) &
+-			 NFC_RB_STATE(rb->info.nativeid));
+-		break;
+-	case RB_GPIO:
+-		ret = gpio_get_value(rb->info.gpio);
+-		break;
+-	case RB_NONE:
+-	default:
+-		ret = 0;
+-		dev_err(nfc->dev, "cannot check R/B NAND status!\n");
+-		break;
+-	}
+-
+-	return ret;
+-}
+-
+-static void sunxi_nfc_select_chip(struct mtd_info *mtd, int chip)
+-{
+-	struct nand_chip *nand = mtd_to_nand(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;
+-	u32 ctl;
+-
+-	if (chip > 0 && chip >= sunxi_nand->nsels)
+-		return;
+-
+-	if (chip == sunxi_nand->selected)
+-		return;
+-
+-	ctl = readl(nfc->regs + NFC_REG_CTL) &
+-	      ~(NFC_PAGE_SHIFT_MSK | NFC_CE_SEL_MSK | NFC_RB_SEL_MSK | NFC_EN);
+-
+-	if (chip >= 0) {
+-		sel = &sunxi_nand->sels[chip];
+-
+-		ctl |= NFC_CE_SEL(sel->cs) | NFC_EN |
+-		       NFC_PAGE_SHIFT(nand->page_shift);
+-		if (sel->rb.type == RB_NONE) {
+-			nand->dev_ready = NULL;
+-		} else {
+-			nand->dev_ready = sunxi_nfc_dev_ready;
+-			if (sel->rb.type == RB_NATIVE)
+-				ctl |= NFC_RB_SEL(sel->rb.info.nativeid);
+-		}
+-
+-		writel(mtd->writesize, nfc->regs + NFC_REG_SPARE_AREA);
+-
+-		if (nfc->clk_rate != sunxi_nand->clk_rate) {
+-			clk_set_rate(nfc->mod_clk, sunxi_nand->clk_rate);
+-			nfc->clk_rate = sunxi_nand->clk_rate;
+-		}
+-	}
+-
+-	writel(sunxi_nand->timing_ctl, nfc->regs + NFC_REG_TIMING_CTL);
+-	writel(sunxi_nand->timing_cfg, nfc->regs + NFC_REG_TIMING_CFG);
+-	writel(ctl, nfc->regs + NFC_REG_CTL);
+-
+-	sunxi_nand->selected = 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 sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
+-	struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
+-	int ret;
+-	int cnt;
+-	int offs = 0;
+-	u32 tmp;
+-
+-	while (len > offs) {
+-		bool poll = false;
+-
+-		cnt = min(len - offs, NFC_SRAM_SIZE);
+-
+-		ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
+-		if (ret)
+-			break;
+-
+-		writel(cnt, nfc->regs + NFC_REG_CNT);
+-		tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD;
+-		writel(tmp, nfc->regs + NFC_REG_CMD);
+-
+-		/* Arbitrary limit for polling mode */
+-		if (cnt < 64)
+-			poll = true;
+-
+-		ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, poll, 0);
+-		if (ret)
+-			break;
+-
+-		if (buf)
+-			memcpy_fromio(buf + offs, nfc->regs + NFC_RAM0_BASE,
+-				      cnt);
+-		offs += cnt;
+-	}
+-}
+-
+-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 sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
+-	struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
+-	int ret;
+-	int cnt;
+-	int offs = 0;
+-	u32 tmp;
+-
+-	while (len > offs) {
+-		bool poll = false;
+-
+-		cnt = min(len - offs, NFC_SRAM_SIZE);
+-
+-		ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
+-		if (ret)
+-			break;
+-
+-		writel(cnt, nfc->regs + NFC_REG_CNT);
+-		memcpy_toio(nfc->regs + NFC_RAM0_BASE, buf + offs, cnt);
+-		tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD |
+-		      NFC_ACCESS_DIR;
+-		writel(tmp, nfc->regs + NFC_REG_CMD);
+-
+-		/* Arbitrary limit for polling mode */
+-		if (cnt < 64)
+-			poll = true;
+-
+-		ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, poll, 0);
+-		if (ret)
+-			break;
+-
+-		offs += cnt;
+-	}
+-}
+-
+-static uint8_t sunxi_nfc_read_byte(struct mtd_info *mtd)
+-{
+-	uint8_t ret;
+-
+-	sunxi_nfc_read_buf(mtd, &ret, 1);
+-
+-	return ret;
+-}
+-
+-static void sunxi_nfc_cmd_ctrl(struct mtd_info *mtd, int dat,
+-			       unsigned int ctrl)
+-{
+-	struct nand_chip *nand = mtd_to_nand(mtd);
+-	struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
+-	struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
+-	int ret;
+-
+-	if (dat == NAND_CMD_NONE && (ctrl & NAND_NCE) &&
+-	    !(ctrl & (NAND_CLE | NAND_ALE))) {
+-		u32 cmd = 0;
+-
+-		if (!sunxi_nand->addr_cycles && !sunxi_nand->cmd_cycles)
+-			return;
+-
+-		if (sunxi_nand->cmd_cycles--)
+-			cmd |= NFC_SEND_CMD1 | sunxi_nand->cmd[0];
+-
+-		if (sunxi_nand->cmd_cycles--) {
+-			cmd |= NFC_SEND_CMD2;
+-			writel(sunxi_nand->cmd[1],
+-			       nfc->regs + NFC_REG_RCMD_SET);
+-		}
+-
+-		sunxi_nand->cmd_cycles = 0;
+-
+-		if (sunxi_nand->addr_cycles) {
+-			cmd |= NFC_SEND_ADR |
+-			       NFC_ADR_NUM(sunxi_nand->addr_cycles);
+-			writel(sunxi_nand->addr[0],
+-			       nfc->regs + NFC_REG_ADDR_LOW);
+-		}
+-
+-		if (sunxi_nand->addr_cycles > 4)
+-			writel(sunxi_nand->addr[1],
+-			       nfc->regs + NFC_REG_ADDR_HIGH);
+-
+-		ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
+-		if (ret)
+-			return;
+-
+-		writel(cmd, nfc->regs + NFC_REG_CMD);
+-		sunxi_nand->addr[0] = 0;
+-		sunxi_nand->addr[1] = 0;
+-		sunxi_nand->addr_cycles = 0;
+-		sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, true, 0);
+-	}
+-
+-	if (ctrl & NAND_CLE) {
+-		sunxi_nand->cmd[sunxi_nand->cmd_cycles++] = dat;
+-	} else if (ctrl & NAND_ALE) {
+-		sunxi_nand->addr[sunxi_nand->addr_cycles / 4] |=
+-				dat << ((sunxi_nand->addr_cycles % 4) * 8);
+-		sunxi_nand->addr_cycles++;
+-	}
+-}
+-
+-/* These seed values have been extracted from Allwinner's BSP */
+-static const u16 sunxi_nfc_randomizer_page_seeds[] = {
+-	0x2b75, 0x0bd0, 0x5ca3, 0x62d1, 0x1c93, 0x07e9, 0x2162, 0x3a72,
+-	0x0d67, 0x67f9, 0x1be7, 0x077d, 0x032f, 0x0dac, 0x2716, 0x2436,
+-	0x7922, 0x1510, 0x3860, 0x5287, 0x480f, 0x4252, 0x1789, 0x5a2d,
+-	0x2a49, 0x5e10, 0x437f, 0x4b4e, 0x2f45, 0x216e, 0x5cb7, 0x7130,
+-	0x2a3f, 0x60e4, 0x4dc9, 0x0ef0, 0x0f52, 0x1bb9, 0x6211, 0x7a56,
+-	0x226d, 0x4ea7, 0x6f36, 0x3692, 0x38bf, 0x0c62, 0x05eb, 0x4c55,
+-	0x60f4, 0x728c, 0x3b6f, 0x2037, 0x7f69, 0x0936, 0x651a, 0x4ceb,
+-	0x6218, 0x79f3, 0x383f, 0x18d9, 0x4f05, 0x5c82, 0x2912, 0x6f17,
+-	0x6856, 0x5938, 0x1007, 0x61ab, 0x3e7f, 0x57c2, 0x542f, 0x4f62,
+-	0x7454, 0x2eac, 0x7739, 0x42d4, 0x2f90, 0x435a, 0x2e52, 0x2064,
+-	0x637c, 0x66ad, 0x2c90, 0x0bad, 0x759c, 0x0029, 0x0986, 0x7126,
+-	0x1ca7, 0x1605, 0x386a, 0x27f5, 0x1380, 0x6d75, 0x24c3, 0x0f8e,
+-	0x2b7a, 0x1418, 0x1fd1, 0x7dc1, 0x2d8e, 0x43af, 0x2267, 0x7da3,
+-	0x4e3d, 0x1338, 0x50db, 0x454d, 0x764d, 0x40a3, 0x42e6, 0x262b,
+-	0x2d2e, 0x1aea, 0x2e17, 0x173d, 0x3a6e, 0x71bf, 0x25f9, 0x0a5d,
+-	0x7c57, 0x0fbe, 0x46ce, 0x4939, 0x6b17, 0x37bb, 0x3e91, 0x76db,
+-};
+-
+-/*
+- * sunxi_nfc_randomizer_ecc512_seeds and sunxi_nfc_randomizer_ecc1024_seeds
+- * have been generated using
+- * sunxi_nfc_randomizer_step(seed, (step_size * 8) + 15), which is what
+- * the randomizer engine does internally before de/scrambling OOB data.
+- *
+- * Those tables are statically defined to avoid calculating randomizer state
+- * at runtime.
+- */
+-static const u16 sunxi_nfc_randomizer_ecc512_seeds[] = {
+-	0x3346, 0x367f, 0x1f18, 0x769a, 0x4f64, 0x068c, 0x2ef1, 0x6b64,
+-	0x28a9, 0x15d7, 0x30f8, 0x3659, 0x53db, 0x7c5f, 0x71d4, 0x4409,
+-	0x26eb, 0x03cc, 0x655d, 0x47d4, 0x4daa, 0x0877, 0x712d, 0x3617,
+-	0x3264, 0x49aa, 0x7f9e, 0x588e, 0x4fbc, 0x7176, 0x7f91, 0x6c6d,
+-	0x4b95, 0x5fb7, 0x3844, 0x4037, 0x0184, 0x081b, 0x0ee8, 0x5b91,
+-	0x293d, 0x1f71, 0x0e6f, 0x402b, 0x5122, 0x1e52, 0x22be, 0x3d2d,
+-	0x75bc, 0x7c60, 0x6291, 0x1a2f, 0x61d4, 0x74aa, 0x4140, 0x29ab,
+-	0x472d, 0x2852, 0x017e, 0x15e8, 0x5ec2, 0x17cf, 0x7d0f, 0x06b8,
+-	0x117a, 0x6b94, 0x789b, 0x3126, 0x6ac5, 0x5be7, 0x150f, 0x51f8,
+-	0x7889, 0x0aa5, 0x663d, 0x77e8, 0x0b87, 0x3dcb, 0x360d, 0x218b,
+-	0x512f, 0x7dc9, 0x6a4d, 0x630a, 0x3547, 0x1dd2, 0x5aea, 0x69a5,
+-	0x7bfa, 0x5e4f, 0x1519, 0x6430, 0x3a0e, 0x5eb3, 0x5425, 0x0c7a,
+-	0x5540, 0x3670, 0x63c1, 0x31e9, 0x5a39, 0x2de7, 0x5979, 0x2891,
+-	0x1562, 0x014b, 0x5b05, 0x2756, 0x5a34, 0x13aa, 0x6cb5, 0x2c36,
+-	0x5e72, 0x1306, 0x0861, 0x15ef, 0x1ee8, 0x5a37, 0x7ac4, 0x45dd,
+-	0x44c4, 0x7266, 0x2f41, 0x3ccc, 0x045e, 0x7d40, 0x7c66, 0x0fa0,
+-};
+-
+-static const u16 sunxi_nfc_randomizer_ecc1024_seeds[] = {
+-	0x2cf5, 0x35f1, 0x63a4, 0x5274, 0x2bd2, 0x778b, 0x7285, 0x32b6,
+-	0x6a5c, 0x70d6, 0x757d, 0x6769, 0x5375, 0x1e81, 0x0cf3, 0x3982,
+-	0x6787, 0x042a, 0x6c49, 0x1925, 0x56a8, 0x40a9, 0x063e, 0x7bd9,
+-	0x4dbf, 0x55ec, 0x672e, 0x7334, 0x5185, 0x4d00, 0x232a, 0x7e07,
+-	0x445d, 0x6b92, 0x528f, 0x4255, 0x53ba, 0x7d82, 0x2a2e, 0x3a4e,
+-	0x75eb, 0x450c, 0x6844, 0x1b5d, 0x581a, 0x4cc6, 0x0379, 0x37b2,
+-	0x419f, 0x0e92, 0x6b27, 0x5624, 0x01e3, 0x07c1, 0x44a5, 0x130c,
+-	0x13e8, 0x5910, 0x0876, 0x60c5, 0x54e3, 0x5b7f, 0x2269, 0x509f,
+-	0x7665, 0x36fd, 0x3e9a, 0x0579, 0x6295, 0x14ef, 0x0a81, 0x1bcc,
+-	0x4b16, 0x64db, 0x0514, 0x4f07, 0x0591, 0x3576, 0x6853, 0x0d9e,
+-	0x259f, 0x38b7, 0x64fb, 0x3094, 0x4693, 0x6ddd, 0x29bb, 0x0bc8,
+-	0x3f47, 0x490e, 0x0c0e, 0x7933, 0x3c9e, 0x5840, 0x398d, 0x3e68,
+-	0x4af1, 0x71f5, 0x57cf, 0x1121, 0x64eb, 0x3579, 0x15ac, 0x584d,
+-	0x5f2a, 0x47e2, 0x6528, 0x6eac, 0x196e, 0x6b96, 0x0450, 0x0179,
+-	0x609c, 0x06e1, 0x4626, 0x42c7, 0x273e, 0x486f, 0x0705, 0x1601,
+-	0x145b, 0x407e, 0x062b, 0x57a5, 0x53f9, 0x5659, 0x4410, 0x3ccd,
+-};
+-
+-static u16 sunxi_nfc_randomizer_step(u16 state, int count)
+-{
+-	state &= 0x7fff;
+-
+-	/*
+-	 * This loop is just a simple implementation of a Fibonacci LFSR using
+-	 * the x16 + x15 + 1 polynomial.
+-	 */
+-	while (count--)
+-		state = ((state >> 1) |
+-			 (((state ^ (state >> 1)) & 1) << 14)) & 0x7fff;
+-
+-	return state;
+-}
+-
+-static u16 sunxi_nfc_randomizer_state(struct mtd_info *mtd, int page, bool ecc)
+-{
+-	const u16 *seeds = sunxi_nfc_randomizer_page_seeds;
+-	int mod = mtd_div_by_ws(mtd->erasesize, mtd);
+-
+-	if (mod > ARRAY_SIZE(sunxi_nfc_randomizer_page_seeds))
+-		mod = ARRAY_SIZE(sunxi_nfc_randomizer_page_seeds);
+-
+-	if (ecc) {
+-		if (mtd->ecc_step_size == 512)
+-			seeds = sunxi_nfc_randomizer_ecc512_seeds;
+-		else
+-			seeds = sunxi_nfc_randomizer_ecc1024_seeds;
+-	}
+-
+-	return seeds[page % mod];
+-}
+-
+-static void sunxi_nfc_randomizer_config(struct mtd_info *mtd,
+-					int page, bool ecc)
+-{
+-	struct nand_chip *nand = mtd_to_nand(mtd);
+-	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
+-	u32 ecc_ctl = readl(nfc->regs + NFC_REG_ECC_CTL);
+-	u16 state;
+-
+-	if (!(nand->options & NAND_NEED_SCRAMBLING))
+-		return;
+-
+-	ecc_ctl = readl(nfc->regs + NFC_REG_ECC_CTL);
+-	state = sunxi_nfc_randomizer_state(mtd, page, ecc);
+-	ecc_ctl = readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_RANDOM_SEED_MSK;
+-	writel(ecc_ctl | NFC_RANDOM_SEED(state), nfc->regs + NFC_REG_ECC_CTL);
+-}
+-
+-static void sunxi_nfc_randomizer_enable(struct mtd_info *mtd)
+-{
+-	struct nand_chip *nand = mtd_to_nand(mtd);
+-	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
+-
+-	if (!(nand->options & NAND_NEED_SCRAMBLING))
+-		return;
+-
+-	writel(readl(nfc->regs + NFC_REG_ECC_CTL) | NFC_RANDOM_EN,
+-	       nfc->regs + NFC_REG_ECC_CTL);
+-}
+-
+-static void sunxi_nfc_randomizer_disable(struct mtd_info *mtd)
+-{
+-	struct nand_chip *nand = mtd_to_nand(mtd);
+-	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
+-
+-	if (!(nand->options & NAND_NEED_SCRAMBLING))
+-		return;
+-
+-	writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_RANDOM_EN,
+-	       nfc->regs + NFC_REG_ECC_CTL);
+-}
+-
+-static void sunxi_nfc_randomize_bbm(struct mtd_info *mtd, int page, u8 *bbm)
+-{
+-	u16 state = sunxi_nfc_randomizer_state(mtd, page, true);
+-
+-	bbm[0] ^= state;
+-	bbm[1] ^= sunxi_nfc_randomizer_step(state, 8);
+-}
+-
+-static void sunxi_nfc_randomizer_write_buf(struct mtd_info *mtd,
+-					   const uint8_t *buf, int len,
+-					   bool ecc, int page)
+-{
+-	sunxi_nfc_randomizer_config(mtd, page, ecc);
+-	sunxi_nfc_randomizer_enable(mtd);
+-	sunxi_nfc_write_buf(mtd, buf, len);
+-	sunxi_nfc_randomizer_disable(mtd);
+-}
+-
+-static void sunxi_nfc_randomizer_read_buf(struct mtd_info *mtd, uint8_t *buf,
+-					  int len, bool ecc, int page)
+-{
+-	sunxi_nfc_randomizer_config(mtd, page, ecc);
+-	sunxi_nfc_randomizer_enable(mtd);
+-	sunxi_nfc_read_buf(mtd, buf, len);
+-	sunxi_nfc_randomizer_disable(mtd);
+-}
+-
+-static void sunxi_nfc_hw_ecc_enable(struct mtd_info *mtd)
+-{
+-	struct nand_chip *nand = mtd_to_nand(mtd);
+-	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
+-	struct sunxi_nand_hw_ecc *data = nand->ecc.priv;
+-	u32 ecc_ctl;
+-
+-	ecc_ctl = readl(nfc->regs + NFC_REG_ECC_CTL);
+-	ecc_ctl &= ~(NFC_ECC_MODE_MSK | NFC_ECC_PIPELINE |
+-		     NFC_ECC_BLOCK_SIZE_MSK);
+-	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);
+-}
+-
+-static void sunxi_nfc_hw_ecc_disable(struct mtd_info *mtd)
+-{
+-	struct nand_chip *nand = mtd_to_nand(mtd);
+-	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
+-
+-	writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_ECC_EN,
+-	       nfc->regs + NFC_REG_ECC_CTL);
+-}
+-
+-static inline void sunxi_nfc_user_data_to_buf(u32 user_data, u8 *buf)
+-{
+-	buf[0] = user_data;
+-	buf[1] = user_data >> 8;
+-	buf[2] = user_data >> 16;
+-	buf[3] = user_data >> 24;
+-}
+-
+-static inline u32 sunxi_nfc_buf_to_user_data(const u8 *buf)
+-{
+-	return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
+-}
+-
+-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 sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
+-
+-	sunxi_nfc_user_data_to_buf(readl(nfc->regs + NFC_REG_USER_DATA(step)),
+-				   oob);
+-
+-	/* De-randomize the Bad Block Marker. */
+-	if (bbm && (nand->options & NAND_NEED_SCRAMBLING))
+-		sunxi_nfc_randomize_bbm(mtd, page, oob);
+-}
+-
+-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 sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
+-	u8 user_data[4];
+-
+-	/* Randomize the Bad Block Marker. */
+-	if (bbm && (nand->options & NAND_NEED_SCRAMBLING)) {
+-		memcpy(user_data, oob, sizeof(user_data));
+-		sunxi_nfc_randomize_bbm(mtd, page, user_data);
+-		oob = user_data;
+-	}
+-
+-	writel(sunxi_nfc_buf_to_user_data(oob),
+-	       nfc->regs + NFC_REG_USER_DATA(step));
+-}
+-
+-static void sunxi_nfc_hw_ecc_update_stats(struct mtd_info *mtd,
+-					  unsigned int *max_bitflips, int ret)
+-{
+-	if (ret < 0) {
+-		mtd->ecc_stats.failed++;
+-	} else {
+-		mtd->ecc_stats.corrected += ret;
+-		*max_bitflips = max_t(unsigned int, *max_bitflips, ret);
+-	}
+-}
+-
+-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 sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
+-	struct nand_ecc_ctrl *ecc = &nand->ecc;
+-	u32 tmp;
+-
+-	*erased = false;
+-
+-	if (status & NFC_ECC_ERR(step))
+-		return -EBADMSG;
+-
+-	if (status & NFC_ECC_PAT_FOUND(step)) {
+-		u8 pattern;
+-
+-		if (unlikely(!(readl(nfc->regs + NFC_REG_PAT_ID) & 0x1))) {
+-			pattern = 0x0;
+-		} else {
+-			pattern = 0xff;
+-			*erased = true;
+-		}
+-
+-		if (data)
+-			memset(data, pattern, ecc->size);
+-
+-		if (oob)
+-			memset(oob, pattern, ecc->bytes + 4);
+-
+-		return 0;
+-	}
+-
+-	tmp = readl(nfc->regs + NFC_REG_ECC_ERR_CNT(step));
+-
+-	return NFC_ECC_ERR_CNT(step, tmp);
+-}
+-
+-static int sunxi_nfc_hw_ecc_read_chunk(struct mtd_info *mtd,
+-				       u8 *data, int data_off,
+-				       u8 *oob, int oob_off,
+-				       int *cur_off,
+-				       unsigned int *max_bitflips,
+-				       bool bbm, bool oob_required, int page)
+-{
+-	struct nand_chip *nand = mtd_to_nand(mtd);
+-	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
+-	struct nand_ecc_ctrl *ecc = &nand->ecc;
+-	int raw_mode = 0;
+-	bool erased;
+-	int ret;
+-
+-	if (*cur_off != data_off)
+-		nand->cmdfunc(mtd, NAND_CMD_RNDOUT, data_off, -1);
+-
+-	sunxi_nfc_randomizer_read_buf(mtd, NULL, ecc->size, false, page);
+-
+-	if (data_off + ecc->size != oob_off)
+-		nand->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_off, -1);
+-
+-	ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
+-	if (ret)
+-		return ret;
+-
+-	sunxi_nfc_randomizer_enable(mtd);
+-	writel(NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | NFC_ECC_OP,
+-	       nfc->regs + NFC_REG_CMD);
+-
+-	ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, false, 0);
+-	sunxi_nfc_randomizer_disable(mtd);
+-	if (ret)
+-		return ret;
+-
+-	*cur_off = oob_off + ecc->bytes + 4;
+-
+-	ret = sunxi_nfc_hw_ecc_correct(mtd, data, oob_required ? oob : NULL, 0,
+-				       readl(nfc->regs + NFC_REG_ECC_ST),
+-				       &erased);
+-	if (erased)
+-		return 1;
+-
+-	if (ret < 0) {
+-		/*
+-		 * Re-read the data with the randomizer disabled to identify
+-		 * bitflips in erased pages.
+-		 */
+-		if (nand->options & NAND_NEED_SCRAMBLING) {
+-			nand->cmdfunc(mtd, NAND_CMD_RNDOUT, data_off, -1);
+-			nand->read_buf(mtd, data, ecc->size);
+-		} else {
+-			memcpy_fromio(data, nfc->regs + NFC_RAM0_BASE,
+-				      ecc->size);
+-		}
+-
+-		nand->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_off, -1);
+-		nand->read_buf(mtd, oob, ecc->bytes + 4);
+-
+-		ret = nand_check_erased_ecc_chunk(data,	ecc->size,
+-						  oob, ecc->bytes + 4,
+-						  NULL, 0, ecc->strength);
+-		if (ret >= 0)
+-			raw_mode = 1;
+-	} else {
+-		memcpy_fromio(data, nfc->regs + NFC_RAM0_BASE, ecc->size);
+-
+-		if (oob_required) {
+-			nand->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_off, -1);
+-			sunxi_nfc_randomizer_read_buf(mtd, oob, ecc->bytes + 4,
+-						      true, page);
+-
+-			sunxi_nfc_hw_ecc_get_prot_oob_bytes(mtd, oob, 0,
+-							    bbm, page);
+-		}
+-	}
+-
+-	sunxi_nfc_hw_ecc_update_stats(mtd, max_bitflips, ret);
+-
+-	return raw_mode;
+-}
+-
+-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_ecc_ctrl *ecc = &nand->ecc;
+-	int offset = ((ecc->bytes + 4) * ecc->steps);
+-	int len = mtd->oobsize - offset;
+-
+-	if (len <= 0)
+-		return;
+-
+-	if (!cur_off || *cur_off != offset)
+-		nand->cmdfunc(mtd, NAND_CMD_RNDOUT,
+-			      offset + mtd->writesize, -1);
+-
+-	if (!randomize)
+-		sunxi_nfc_read_buf(mtd, oob + offset, len);
+-	else
+-		sunxi_nfc_randomizer_read_buf(mtd, oob + offset, len,
+-					      false, page);
+-
+-	if (cur_off)
+-		*cur_off = mtd->oobsize + mtd->writesize;
+-}
+-
+-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);
+-	bool randomized = nand->options & NAND_NEED_SCRAMBLING;
+-	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
+-	struct nand_ecc_ctrl *ecc = &nand->ecc;
+-	unsigned int max_bitflips = 0;
+-	int ret, i, raw_mode = 0;
+-	struct scatterlist sg;
+-	u32 status;
+-
+-	ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
+-	if (ret)
+-		return ret;
+-
+-	ret = sunxi_nfc_dma_op_prepare(mtd, buf, ecc->size, nchunks,
+-				       DMA_FROM_DEVICE, &sg);
+-	if (ret)
+-		return ret;
+-
+-	sunxi_nfc_hw_ecc_enable(mtd);
+-	sunxi_nfc_randomizer_config(mtd, page, false);
+-	sunxi_nfc_randomizer_enable(mtd);
+-
+-	writel((NAND_CMD_RNDOUTSTART << 16) | (NAND_CMD_RNDOUT << 8) |
+-	       NAND_CMD_READSTART, nfc->regs + NFC_REG_RCMD_SET);
+-
+-	dma_async_issue_pending(nfc->dmac);
+-
+-	writel(NFC_PAGE_OP | NFC_DATA_SWAP_METHOD | NFC_DATA_TRANS,
+-	       nfc->regs + NFC_REG_CMD);
+-
+-	ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, false, 0);
+-	if (ret)
+-		dmaengine_terminate_all(nfc->dmac);
+-
+-	sunxi_nfc_randomizer_disable(mtd);
+-	sunxi_nfc_hw_ecc_disable(mtd);
+-
+-	sunxi_nfc_dma_op_cleanup(mtd, DMA_FROM_DEVICE, &sg);
+-
+-	if (ret)
+-		return ret;
+-
+-	status = readl(nfc->regs + NFC_REG_ECC_ST);
+-
+-	for (i = 0; i < nchunks; i++) {
+-		int data_off = i * ecc->size;
+-		int oob_off = i * (ecc->bytes + 4);
+-		u8 *data = buf + data_off;
+-		u8 *oob = nand->oob_poi + oob_off;
+-		bool erased;
+-
+-		ret = sunxi_nfc_hw_ecc_correct(mtd, randomized ? data : NULL,
+-					       oob_required ? oob : NULL,
+-					       i, status, &erased);
+-
+-		/* ECC errors are handled in the second loop. */
+-		if (ret < 0)
+-			continue;
+-
+-		if (oob_required && !erased) {
+-			/* TODO: use DMA to retrieve OOB */
+-			nand->cmdfunc(mtd, NAND_CMD_RNDOUT,
+-				      mtd->writesize + oob_off, -1);
+-			nand->read_buf(mtd, oob, ecc->bytes + 4);
+-
+-			sunxi_nfc_hw_ecc_get_prot_oob_bytes(mtd, oob, i,
+-							    !i, page);
+-		}
+-
+-		if (erased)
+-			raw_mode = 1;
+-
+-		sunxi_nfc_hw_ecc_update_stats(mtd, &max_bitflips, ret);
+-	}
+-
+-	if (status & NFC_ECC_ERR_MSK) {
+-		for (i = 0; i < nchunks; i++) {
+-			int data_off = i * ecc->size;
+-			int oob_off = i * (ecc->bytes + 4);
+-			u8 *data = buf + data_off;
+-			u8 *oob = nand->oob_poi + oob_off;
+-
+-			if (!(status & NFC_ECC_ERR(i)))
+-				continue;
+-
+-			/*
+-			 * Re-read the data with the randomizer disabled to
+-			 * identify bitflips in erased pages.
+-			 */
+-			if (randomized) {
+-				/* TODO: use DMA to read page in raw mode */
+-				nand->cmdfunc(mtd, NAND_CMD_RNDOUT,
+-					      data_off, -1);
+-				nand->read_buf(mtd, data, ecc->size);
+-			}
+-
+-			/* TODO: use DMA to retrieve OOB */
+-			nand->cmdfunc(mtd, NAND_CMD_RNDOUT,
+-				      mtd->writesize + oob_off, -1);
+-			nand->read_buf(mtd, oob, ecc->bytes + 4);
+-
+-			ret = nand_check_erased_ecc_chunk(data,	ecc->size,
+-							  oob, ecc->bytes + 4,
+-							  NULL, 0,
+-							  ecc->strength);
+-			if (ret >= 0)
+-				raw_mode = 1;
+-
+-			sunxi_nfc_hw_ecc_update_stats(mtd, &max_bitflips, ret);
+-		}
+-	}
+-
+-	if (oob_required)
+-		sunxi_nfc_hw_ecc_read_extra_oob(mtd, nand->oob_poi,
+-						NULL, !raw_mode,
+-						page);
+-
+-	return max_bitflips;
+-}
+-
+-static int sunxi_nfc_hw_ecc_write_chunk(struct mtd_info *mtd,
+-					const u8 *data, int data_off,
+-					const u8 *oob, int oob_off,
+-					int *cur_off, bool bbm,
+-					int page)
+-{
+-	struct nand_chip *nand = mtd_to_nand(mtd);
+-	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
+-	struct nand_ecc_ctrl *ecc = &nand->ecc;
+-	int ret;
+-
+-	if (data_off != *cur_off)
+-		nand->cmdfunc(mtd, NAND_CMD_RNDIN, data_off, -1);
+-
+-	sunxi_nfc_randomizer_write_buf(mtd, data, ecc->size, false, page);
+-
+-	if (data_off + ecc->size != oob_off)
+-		nand->cmdfunc(mtd, NAND_CMD_RNDIN, oob_off, -1);
+-
+-	ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
+-	if (ret)
+-		return ret;
+-
+-	sunxi_nfc_randomizer_enable(mtd);
+-	sunxi_nfc_hw_ecc_set_prot_oob_bytes(mtd, oob, 0, bbm, page);
+-
+-	writel(NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD |
+-	       NFC_ACCESS_DIR | NFC_ECC_OP,
+-	       nfc->regs + NFC_REG_CMD);
+-
+-	ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, false, 0);
+-	sunxi_nfc_randomizer_disable(mtd);
+-	if (ret)
+-		return ret;
+-
+-	*cur_off = oob_off + ecc->bytes + 4;
+-
+-	return 0;
+-}
+-
+-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_ecc_ctrl *ecc = &nand->ecc;
+-	int offset = ((ecc->bytes + 4) * ecc->steps);
+-	int len = mtd->oobsize - offset;
+-
+-	if (len <= 0)
+-		return;
+-
+-	if (!cur_off || *cur_off != offset)
+-		nand->cmdfunc(mtd, NAND_CMD_RNDIN,
+-			      offset + mtd->writesize, -1);
+-
+-	sunxi_nfc_randomizer_write_buf(mtd, oob + offset, len, false, page);
+-
+-	if (cur_off)
+-		*cur_off = mtd->oobsize + mtd->writesize;
+-}
+-
+-static int sunxi_nfc_hw_ecc_read_page(struct mtd_info *mtd,
+-				      struct nand_chip *chip, uint8_t *buf,
+-				      int oob_required, int page)
+-{
+-	struct nand_ecc_ctrl *ecc = &chip->ecc;
+-	unsigned int max_bitflips = 0;
+-	int ret, i, cur_off = 0;
+-	bool raw_mode = false;
+-
+-	sunxi_nfc_hw_ecc_enable(mtd);
+-
+-	for (i = 0; i < ecc->steps; i++) {
+-		int data_off = i * ecc->size;
+-		int oob_off = i * (ecc->bytes + 4);
+-		u8 *data = buf + data_off;
+-		u8 *oob = chip->oob_poi + oob_off;
+-
+-		ret = sunxi_nfc_hw_ecc_read_chunk(mtd, data, data_off, oob,
+-						  oob_off + mtd->writesize,
+-						  &cur_off, &max_bitflips,
+-						  !i, oob_required, page);
+-		if (ret < 0)
+-			return ret;
+-		else if (ret)
+-			raw_mode = true;
+-	}
+-
+-	if (oob_required)
+-		sunxi_nfc_hw_ecc_read_extra_oob(mtd, chip->oob_poi, &cur_off,
+-						!raw_mode, page);
+-
+-	sunxi_nfc_hw_ecc_disable(mtd);
+-
+-	return max_bitflips;
+-}
+-
+-static int sunxi_nfc_hw_ecc_read_page_dma(struct mtd_info *mtd,
+-					  struct nand_chip *chip, u8 *buf,
+-					  int oob_required, int page)
+-{
+-	int ret;
+-
+-	ret = sunxi_nfc_hw_ecc_read_chunks_dma(mtd, buf, oob_required, page,
+-					       chip->ecc.steps);
+-	if (ret >= 0)
+-		return ret;
+-
+-	/* Fallback to PIO mode */
+-	chip->cmdfunc(mtd, NAND_CMD_RNDOUT, 0, -1);
+-
+-	return sunxi_nfc_hw_ecc_read_page(mtd, chip, buf, oob_required, page);
+-}
+-
+-static int sunxi_nfc_hw_ecc_read_subpage(struct mtd_info *mtd,
+-					 struct nand_chip *chip,
+-					 u32 data_offs, u32 readlen,
+-					 u8 *bufpoi, int page)
+-{
+-	struct nand_ecc_ctrl *ecc = &chip->ecc;
+-	int ret, i, cur_off = 0;
+-	unsigned int max_bitflips = 0;
+-
+-	sunxi_nfc_hw_ecc_enable(mtd);
+-
+-	for (i = data_offs / ecc->size;
+-	     i < DIV_ROUND_UP(data_offs + readlen, ecc->size); i++) {
+-		int data_off = i * ecc->size;
+-		int oob_off = i * (ecc->bytes + 4);
+-		u8 *data = bufpoi + data_off;
+-		u8 *oob = chip->oob_poi + oob_off;
+-
+-		ret = sunxi_nfc_hw_ecc_read_chunk(mtd, data, data_off,
+-						  oob,
+-						  oob_off + mtd->writesize,
+-						  &cur_off, &max_bitflips, !i,
+-						  false, page);
+-		if (ret < 0)
+-			return ret;
+-	}
+-
+-	sunxi_nfc_hw_ecc_disable(mtd);
+-
+-	return max_bitflips;
+-}
+-
+-static int sunxi_nfc_hw_ecc_read_subpage_dma(struct mtd_info *mtd,
+-					     struct nand_chip *chip,
+-					     u32 data_offs, u32 readlen,
+-					     u8 *buf, int page)
+-{
+-	int nchunks = DIV_ROUND_UP(data_offs + readlen, chip->ecc.size);
+-	int ret;
+-
+-	ret = sunxi_nfc_hw_ecc_read_chunks_dma(mtd, buf, false, page, nchunks);
+-	if (ret >= 0)
+-		return ret;
+-
+-	/* Fallback to PIO mode */
+-	chip->cmdfunc(mtd, NAND_CMD_RNDOUT, 0, -1);
+-
+-	return sunxi_nfc_hw_ecc_read_subpage(mtd, chip, data_offs, readlen,
+-					     buf, page);
+-}
+-
+-static int sunxi_nfc_hw_ecc_write_page(struct mtd_info *mtd,
+-				       struct nand_chip *chip,
+-				       const uint8_t *buf, int oob_required,
+-				       int page)
+-{
+-	struct nand_ecc_ctrl *ecc = &chip->ecc;
+-	int ret, i, cur_off = 0;
+-
+-	sunxi_nfc_hw_ecc_enable(mtd);
+-
+-	for (i = 0; i < ecc->steps; i++) {
+-		int data_off = i * ecc->size;
+-		int oob_off = i * (ecc->bytes + 4);
+-		const u8 *data = buf + data_off;
+-		const u8 *oob = chip->oob_poi + oob_off;
+-
+-		ret = sunxi_nfc_hw_ecc_write_chunk(mtd, data, data_off, oob,
+-						   oob_off + mtd->writesize,
+-						   &cur_off, !i, page);
+-		if (ret)
+-			return ret;
+-	}
+-
+-	if (oob_required || (chip->options & NAND_NEED_SCRAMBLING))
+-		sunxi_nfc_hw_ecc_write_extra_oob(mtd, chip->oob_poi,
+-						 &cur_off, page);
+-
+-	sunxi_nfc_hw_ecc_disable(mtd);
+-
+-	return 0;
+-}
+-
+-static int sunxi_nfc_hw_ecc_write_subpage(struct mtd_info *mtd,
+-					  struct nand_chip *chip,
+-					  u32 data_offs, u32 data_len,
+-					  const u8 *buf, int oob_required,
+-					  int page)
+-{
+-	struct nand_ecc_ctrl *ecc = &chip->ecc;
+-	int ret, i, cur_off = 0;
+-
+-	sunxi_nfc_hw_ecc_enable(mtd);
+-
+-	for (i = data_offs / ecc->size;
+-	     i < DIV_ROUND_UP(data_offs + data_len, ecc->size); i++) {
+-		int data_off = i * ecc->size;
+-		int oob_off = i * (ecc->bytes + 4);
+-		const u8 *data = buf + data_off;
+-		const u8 *oob = chip->oob_poi + oob_off;
+-
+-		ret = sunxi_nfc_hw_ecc_write_chunk(mtd, data, data_off, oob,
+-						   oob_off + mtd->writesize,
+-						   &cur_off, !i, page);
+-		if (ret)
+-			return ret;
+-	}
+-
+-	sunxi_nfc_hw_ecc_disable(mtd);
+-
+-	return 0;
+-}
+-
+-static int sunxi_nfc_hw_ecc_write_page_dma(struct mtd_info *mtd,
+-					   struct nand_chip *chip,
+-					   const u8 *buf,
+-					   int oob_required,
+-					   int page)
+-{
+-	struct nand_chip *nand = mtd_to_nand(mtd);
+-	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
+-	struct nand_ecc_ctrl *ecc = &nand->ecc;
+-	struct scatterlist sg;
+-	int ret, i;
+-
+-	ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
+-	if (ret)
+-		return ret;
+-
+-	ret = sunxi_nfc_dma_op_prepare(mtd, buf, ecc->size, ecc->steps,
+-				       DMA_TO_DEVICE, &sg);
+-	if (ret)
+-		goto pio_fallback;
+-
+-	for (i = 0; i < ecc->steps; i++) {
+-		const u8 *oob = nand->oob_poi + (i * (ecc->bytes + 4));
+-
+-		sunxi_nfc_hw_ecc_set_prot_oob_bytes(mtd, oob, i, !i, page);
+-	}
+-
+-	sunxi_nfc_hw_ecc_enable(mtd);
+-	sunxi_nfc_randomizer_config(mtd, page, false);
+-	sunxi_nfc_randomizer_enable(mtd);
+-
+-	writel((NAND_CMD_RNDIN << 8) | NAND_CMD_PAGEPROG,
+-	       nfc->regs + NFC_REG_RCMD_SET);
+-
+-	dma_async_issue_pending(nfc->dmac);
+-
+-	writel(NFC_PAGE_OP | NFC_DATA_SWAP_METHOD |
+-	       NFC_DATA_TRANS | NFC_ACCESS_DIR,
+-	       nfc->regs + NFC_REG_CMD);
+-
+-	ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, false, 0);
+-	if (ret)
+-		dmaengine_terminate_all(nfc->dmac);
+-
+-	sunxi_nfc_randomizer_disable(mtd);
+-	sunxi_nfc_hw_ecc_disable(mtd);
+-
+-	sunxi_nfc_dma_op_cleanup(mtd, DMA_TO_DEVICE, &sg);
+-
+-	if (ret)
+-		return ret;
+-
+-	if (oob_required || (chip->options & NAND_NEED_SCRAMBLING))
+-		/* TODO: use DMA to transfer extra OOB bytes ? */
+-		sunxi_nfc_hw_ecc_write_extra_oob(mtd, chip->oob_poi,
+-						 NULL, page);
+-
+-	return 0;
+-
+-pio_fallback:
+-	return sunxi_nfc_hw_ecc_write_page(mtd, chip, buf, oob_required, page);
+-}
+-
+-static int sunxi_nfc_hw_syndrome_ecc_read_page(struct mtd_info *mtd,
+-					       struct nand_chip *chip,
+-					       uint8_t *buf, int oob_required,
+-					       int page)
+-{
+-	struct nand_ecc_ctrl *ecc = &chip->ecc;
+-	unsigned int max_bitflips = 0;
+-	int ret, i, cur_off = 0;
+-	bool raw_mode = false;
+-
+-	sunxi_nfc_hw_ecc_enable(mtd);
+-
+-	for (i = 0; i < ecc->steps; i++) {
+-		int data_off = i * (ecc->size + ecc->bytes + 4);
+-		int oob_off = data_off + ecc->size;
+-		u8 *data = buf + (i * ecc->size);
+-		u8 *oob = chip->oob_poi + (i * (ecc->bytes + 4));
+-
+-		ret = sunxi_nfc_hw_ecc_read_chunk(mtd, data, data_off, oob,
+-						  oob_off, &cur_off,
+-						  &max_bitflips, !i,
+-						  oob_required,
+-						  page);
+-		if (ret < 0)
+-			return ret;
+-		else if (ret)
+-			raw_mode = true;
+-	}
+-
+-	if (oob_required)
+-		sunxi_nfc_hw_ecc_read_extra_oob(mtd, chip->oob_poi, &cur_off,
+-						!raw_mode, page);
+-
+-	sunxi_nfc_hw_ecc_disable(mtd);
+-
+-	return max_bitflips;
+-}
+-
+-static int sunxi_nfc_hw_syndrome_ecc_write_page(struct mtd_info *mtd,
+-						struct nand_chip *chip,
+-						const uint8_t *buf,
+-						int oob_required, int page)
+-{
+-	struct nand_ecc_ctrl *ecc = &chip->ecc;
+-	int ret, i, cur_off = 0;
+-
+-	sunxi_nfc_hw_ecc_enable(mtd);
+-
+-	for (i = 0; i < ecc->steps; i++) {
+-		int data_off = i * (ecc->size + ecc->bytes + 4);
+-		int oob_off = data_off + ecc->size;
+-		const u8 *data = buf + (i * ecc->size);
+-		const u8 *oob = chip->oob_poi + (i * (ecc->bytes + 4));
+-
+-		ret = sunxi_nfc_hw_ecc_write_chunk(mtd, data, data_off,
+-						   oob, oob_off, &cur_off,
+-						   false, page);
+-		if (ret)
+-			return ret;
+-	}
+-
+-	if (oob_required || (chip->options & NAND_NEED_SCRAMBLING))
+-		sunxi_nfc_hw_ecc_write_extra_oob(mtd, chip->oob_poi,
+-						 &cur_off, page);
+-
+-	sunxi_nfc_hw_ecc_disable(mtd);
+-
+-	return 0;
+-}
+-
+-static int sunxi_nfc_hw_common_ecc_read_oob(struct mtd_info *mtd,
+-					    struct nand_chip *chip,
+-					    int page)
+-{
+-	chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
+-
+-	chip->pagebuf = -1;
+-
+-	return chip->ecc.read_page(mtd, chip, chip->buffers->databuf, 1, page);
+-}
+-
+-static int sunxi_nfc_hw_common_ecc_write_oob(struct mtd_info *mtd,
+-					     struct nand_chip *chip,
+-					     int page)
+-{
+-	int ret, status;
+-
+-	chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0, page);
+-
+-	chip->pagebuf = -1;
+-
+-	memset(chip->buffers->databuf, 0xff, mtd->writesize);
+-	ret = chip->ecc.write_page(mtd, chip, chip->buffers->databuf, 1, page);
+-	if (ret)
+-		return ret;
+-
+-	/* Send command to program the OOB data */
+-	chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+-
+-	status = chip->waitfunc(mtd, chip);
+-
+-	return status & NAND_STATUS_FAIL ? -EIO : 0;
+-}
+-
+-static const s32 tWB_lut[] = {6, 12, 16, 20};
+-static const s32 tRHW_lut[] = {4, 8, 12, 20};
+-
+-static int _sunxi_nand_lookup_timing(const s32 *lut, int lut_size, u32 duration,
+-		u32 clk_period)
+-{
+-	u32 clk_cycles = DIV_ROUND_UP(duration, clk_period);
+-	int i;
+-
+-	for (i = 0; i < lut_size; i++) {
+-		if (clk_cycles <= lut[i])
+-			return i;
+-	}
+-
+-	/* Doesn't fit */
+-	return -EINVAL;
+-}
+-
+-#define sunxi_nand_lookup_timing(l, p, c) \
+-			_sunxi_nand_lookup_timing(l, ARRAY_SIZE(l), p, c)
+-
+-static int sunxi_nfc_setup_data_interface(struct mtd_info *mtd, int csline,
+-					const struct nand_data_interface *conf)
+-{
+-	struct nand_chip *nand = mtd_to_nand(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;
+-	u32 min_clk_period = 0;
+-	s32 tWB, tADL, tWHR, tRHW, tCAD;
+-	long real_clk_rate;
+-
+-	timings = nand_get_sdr_timings(conf);
+-	if (IS_ERR(timings))
+-		return -ENOTSUPP;
+-
+-	/* T1 <=> tCLS */
+-	if (timings->tCLS_min > min_clk_period)
+-		min_clk_period = timings->tCLS_min;
+-
+-	/* T2 <=> tCLH */
+-	if (timings->tCLH_min > min_clk_period)
+-		min_clk_period = timings->tCLH_min;
+-
+-	/* T3 <=> tCS */
+-	if (timings->tCS_min > min_clk_period)
+-		min_clk_period = timings->tCS_min;
+-
+-	/* T4 <=> tCH */
+-	if (timings->tCH_min > min_clk_period)
+-		min_clk_period = timings->tCH_min;
+-
+-	/* T5 <=> tWP */
+-	if (timings->tWP_min > min_clk_period)
+-		min_clk_period = timings->tWP_min;
+-
+-	/* T6 <=> tWH */
+-	if (timings->tWH_min > min_clk_period)
+-		min_clk_period = timings->tWH_min;
+-
+-	/* T7 <=> tALS */
+-	if (timings->tALS_min > min_clk_period)
+-		min_clk_period = timings->tALS_min;
+-
+-	/* T8 <=> tDS */
+-	if (timings->tDS_min > min_clk_period)
+-		min_clk_period = timings->tDS_min;
+-
+-	/* T9 <=> tDH */
+-	if (timings->tDH_min > min_clk_period)
+-		min_clk_period = timings->tDH_min;
+-
+-	/* T10 <=> tRR */
+-	if (timings->tRR_min > (min_clk_period * 3))
+-		min_clk_period = DIV_ROUND_UP(timings->tRR_min, 3);
+-
+-	/* T11 <=> tALH */
+-	if (timings->tALH_min > min_clk_period)
+-		min_clk_period = timings->tALH_min;
+-
+-	/* T12 <=> tRP */
+-	if (timings->tRP_min > min_clk_period)
+-		min_clk_period = timings->tRP_min;
+-
+-	/* T13 <=> tREH */
+-	if (timings->tREH_min > min_clk_period)
+-		min_clk_period = timings->tREH_min;
+-
+-	/* T14 <=> tRC */
+-	if (timings->tRC_min > (min_clk_period * 2))
+-		min_clk_period = DIV_ROUND_UP(timings->tRC_min, 2);
+-
+-	/* T15 <=> tWC */
+-	if (timings->tWC_min > (min_clk_period * 2))
+-		min_clk_period = DIV_ROUND_UP(timings->tWC_min, 2);
+-
+-	/* T16 - T19 + tCAD */
+-	if (timings->tWB_max > (min_clk_period * 20))
+-		min_clk_period = DIV_ROUND_UP(timings->tWB_max, 20);
+-
+-	if (timings->tADL_min > (min_clk_period * 32))
+-		min_clk_period = DIV_ROUND_UP(timings->tADL_min, 32);
+-
+-	if (timings->tWHR_min > (min_clk_period * 32))
+-		min_clk_period = DIV_ROUND_UP(timings->tWHR_min, 32);
+-
+-	if (timings->tRHW_min > (min_clk_period * 20))
+-		min_clk_period = DIV_ROUND_UP(timings->tRHW_min, 20);
+-
+-	tWB  = sunxi_nand_lookup_timing(tWB_lut, timings->tWB_max,
+-					min_clk_period);
+-	if (tWB < 0) {
+-		dev_err(nfc->dev, "unsupported tWB\n");
+-		return tWB;
+-	}
+-
+-	tADL = DIV_ROUND_UP(timings->tADL_min, min_clk_period) >> 3;
+-	if (tADL > 3) {
+-		dev_err(nfc->dev, "unsupported tADL\n");
+-		return -EINVAL;
+-	}
+-
+-	tWHR = DIV_ROUND_UP(timings->tWHR_min, min_clk_period) >> 3;
+-	if (tWHR > 3) {
+-		dev_err(nfc->dev, "unsupported tWHR\n");
+-		return -EINVAL;
+-	}
+-
+-	tRHW = sunxi_nand_lookup_timing(tRHW_lut, timings->tRHW_min,
+-					min_clk_period);
+-	if (tRHW < 0) {
+-		dev_err(nfc->dev, "unsupported tRHW\n");
+-		return tRHW;
+-	}
+-
+-	if (csline == NAND_DATA_IFACE_CHECK_ONLY)
+-		return 0;
+-
+-	/*
+-	 * TODO: according to ONFI specs this value only applies for DDR NAND,
+-	 * but Allwinner seems to set this to 0x7. Mimic them for now.
+-	 */
+-	tCAD = 0x7;
+-
+-	/* TODO: A83 has some more bits for CDQSS, CS, CLHZ, CCS, WC */
+-	chip->timing_cfg = NFC_TIMING_CFG(tWB, tADL, tWHR, tRHW, tCAD);
+-
+-	/* Convert min_clk_period from picoseconds to nanoseconds */
+-	min_clk_period = DIV_ROUND_UP(min_clk_period, 1000);
+-
+-	/*
+-	 * Unlike what is stated in Allwinner datasheet, the clk_rate should
+-	 * be set to (1 / min_clk_period), and not (2 / min_clk_period).
+-	 * This new formula was verified with a scope and validated by
+-	 * Allwinner engineers.
+-	 */
+-	chip->clk_rate = NSEC_PER_SEC / min_clk_period;
+-	real_clk_rate = clk_round_rate(nfc->mod_clk, chip->clk_rate);
+-	if (real_clk_rate <= 0) {
+-		dev_err(nfc->dev, "Unable to round clk %lu\n", chip->clk_rate);
+-		return -EINVAL;
+-	}
+-
+-	/*
+-	 * ONFI specification 3.1, paragraph 4.15.2 dictates that EDO data
+-	 * output cycle timings shall be used if the host drives tRC less than
+-	 * 30 ns.
+-	 */
+-	min_clk_period = NSEC_PER_SEC / real_clk_rate;
+-	chip->timing_ctl = ((min_clk_period * 2) < 30) ?
+-			   NFC_TIMING_CTL_EDO : 0;
+-
+-	return 0;
+-}
+-
+-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_ecc_ctrl *ecc = &nand->ecc;
+-
+-	if (section >= ecc->steps)
+-		return -ERANGE;
+-
+-	oobregion->offset = section * (ecc->bytes + 4) + 4;
+-	oobregion->length = ecc->bytes;
+-
+-	return 0;
+-}
+-
+-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_ecc_ctrl *ecc = &nand->ecc;
+-
+-	if (section > ecc->steps)
+-		return -ERANGE;
+-
+-	/*
+-	 * The first 2 bytes are used for BB markers, hence we
+-	 * only have 2 bytes available in the first user data
+-	 * section.
+-	 */
+-	if (!section && ecc->mode == NAND_ECC_HW) {
+-		oobregion->offset = 2;
+-		oobregion->length = 2;
+-
+-		return 0;
+-	}
+-
+-	oobregion->offset = section * (ecc->bytes + 4);
+-
+-	if (section < ecc->steps)
+-		oobregion->length = 4;
+-	else
+-		oobregion->offset = mtd->oobsize - oobregion->offset;
+-
+-	return 0;
+-}
+-
+-static const struct mtd_ooblayout_ops sunxi_nand_ooblayout_ops = {
+-	.ecc = sunxi_nand_ooblayout_ecc,
+-	.free = sunxi_nand_ooblayout_free,
+-};
+-
+-static int sunxi_nand_hw_common_ecc_ctrl_init(struct mtd_info *mtd,
+-					      struct nand_ecc_ctrl *ecc,
+-					      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 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;
+-	int nsectors;
+-	int ret;
+-	int i;
+-
+-	if (ecc->options & NAND_ECC_MAXIMIZE) {
+-		int bytes;
+-
+-		ecc->size = 1024;
+-		nsectors = mtd->writesize / ecc->size;
+-
+-		/* Reserve 2 bytes for the BBM */
+-		bytes = (mtd->oobsize - 2) / nsectors;
+-
+-		/* 4 non-ECC bytes are added before each ECC bytes section */
+-		bytes -= 4;
+-
+-		/* and bytes has to be even. */
+-		if (bytes % 2)
+-			bytes--;
+-
+-		ecc->strength = bytes * 8 / fls(8 * ecc->size);
+-
+-		for (i = 0; i < ARRAY_SIZE(strengths); i++) {
+-			if (strengths[i] > ecc->strength)
+-				break;
+-		}
+-
+-		if (!i)
+-			ecc->strength = 0;
+-		else
+-			ecc->strength = strengths[i - 1];
+-	}
+-
+-	if (ecc->size != 512 && ecc->size != 1024)
+-		return -EINVAL;
+-
+-	data = kzalloc(sizeof(*data), GFP_KERNEL);
+-	if (!data)
+-		return -ENOMEM;
+-
+-	/* Prefer 1k ECC chunk over 512 ones */
+-	if (ecc->size == 512 && mtd->writesize > 512) {
+-		ecc->size = 1024;
+-		ecc->strength *= 2;
+-	}
+-
+-	/* Add ECC info retrieval from DT */
+-	for (i = 0; i < ARRAY_SIZE(strengths); i++) {
+-		if (ecc->strength <= strengths[i])
+-			break;
+-	}
+-
+-	if (i >= ARRAY_SIZE(strengths)) {
+-		dev_err(nfc->dev, "unsupported strength\n");
+-		ret = -ENOTSUPP;
+-		goto err;
+-	}
+-
+-	data->mode = i;
+-
+-	/* HW ECC always request ECC bytes for 1024 bytes blocks */
+-	ecc->bytes = DIV_ROUND_UP(ecc->strength * fls(8 * 1024), 8);
+-
+-	/* HW ECC always work with even numbers of ECC bytes */
+-	ecc->bytes = ALIGN(ecc->bytes, 2);
+-
+-	nsectors = mtd->writesize / ecc->size;
+-
+-	if (mtd->oobsize < ((ecc->bytes + 4) * nsectors)) {
+-		ret = -EINVAL;
+-		goto err;
+-	}
+-
+-	ecc->read_oob = sunxi_nfc_hw_common_ecc_read_oob;
+-	ecc->write_oob = sunxi_nfc_hw_common_ecc_write_oob;
+-	mtd_set_ooblayout(mtd, &sunxi_nand_ooblayout_ops);
+-	ecc->priv = data;
+-
+-	return 0;
+-
+-err:
+-	kfree(data);
+-
+-	return ret;
+-}
+-
+-static void sunxi_nand_hw_common_ecc_ctrl_cleanup(struct nand_ecc_ctrl *ecc)
+-{
+-	kfree(ecc->priv);
+-}
+-
+-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 sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
+-	struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
+-	int ret;
+-
+-	ret = sunxi_nand_hw_common_ecc_ctrl_init(mtd, ecc, np);
+-	if (ret)
+-		return ret;
+-
+-	if (nfc->dmac) {
+-		ecc->read_page = sunxi_nfc_hw_ecc_read_page_dma;
+-		ecc->read_subpage = sunxi_nfc_hw_ecc_read_subpage_dma;
+-		ecc->write_page = sunxi_nfc_hw_ecc_write_page_dma;
+-		nand->options |= NAND_USE_BOUNCE_BUFFER;
+-	} else {
+-		ecc->read_page = sunxi_nfc_hw_ecc_read_page;
+-		ecc->read_subpage = sunxi_nfc_hw_ecc_read_subpage;
+-		ecc->write_page = sunxi_nfc_hw_ecc_write_page;
+-	}
+-
+-	/* TODO: support DMA for raw accesses and subpage write */
+-	ecc->write_subpage = sunxi_nfc_hw_ecc_write_subpage;
+-	ecc->read_oob_raw = nand_read_oob_std;
+-	ecc->write_oob_raw = nand_write_oob_std;
+-
+-	return 0;
+-}
+-
+-static int sunxi_nand_hw_syndrome_ecc_ctrl_init(struct mtd_info *mtd,
+-						struct nand_ecc_ctrl *ecc,
+-						struct device_node *np)
+-{
+-	int ret;
+-
+-	ret = sunxi_nand_hw_common_ecc_ctrl_init(mtd, ecc, np);
+-	if (ret)
+-		return ret;
+-
+-	ecc->prepad = 4;
+-	ecc->read_page = sunxi_nfc_hw_syndrome_ecc_read_page;
+-	ecc->write_page = sunxi_nfc_hw_syndrome_ecc_write_page;
+-	ecc->read_oob_raw = nand_read_oob_syndrome;
+-	ecc->write_oob_raw = nand_write_oob_syndrome;
+-
+-	return 0;
+-}
+-
+-static void sunxi_nand_ecc_cleanup(struct nand_ecc_ctrl *ecc)
+-{
+-	switch (ecc->mode) {
+-	case NAND_ECC_HW:
+-	case NAND_ECC_HW_SYNDROME:
+-		sunxi_nand_hw_common_ecc_ctrl_cleanup(ecc);
+-		break;
+-	case NAND_ECC_NONE:
+-	default:
+-		break;
+-	}
+-}
+-
+-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);
+-	int ret;
+-
+-	if (!ecc->size) {
+-		ecc->size = nand->ecc_step_ds;
+-		ecc->strength = nand->ecc_strength_ds;
+-	}
+-
+-	if (!ecc->size || !ecc->strength)
+-		return -EINVAL;
+-
+-	switch (ecc->mode) {
+-	case NAND_ECC_HW:
+-		ret = sunxi_nand_hw_ecc_ctrl_init(mtd, ecc, np);
+-		if (ret)
+-			return ret;
+-		break;
+-	case NAND_ECC_HW_SYNDROME:
+-		ret = sunxi_nand_hw_syndrome_ecc_ctrl_init(mtd, ecc, np);
+-		if (ret)
+-			return ret;
+-		break;
+-	case NAND_ECC_NONE:
+-	case NAND_ECC_SOFT:
+-		break;
+-	default:
+-		return -EINVAL;
+-	}
+-
+-	return 0;
+-}
+-
+-static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
+-				struct device_node *np)
+-{
+-	struct sunxi_nand_chip *chip;
+-	struct mtd_info *mtd;
+-	struct nand_chip *nand;
+-	int nsels;
+-	int ret;
+-	int i;
+-	u32 tmp;
+-
+-	if (!of_get_property(np, "reg", &nsels))
+-		return -EINVAL;
+-
+-	nsels /= sizeof(u32);
+-	if (!nsels) {
+-		dev_err(dev, "invalid reg property size\n");
+-		return -EINVAL;
+-	}
+-
+-	chip = devm_kzalloc(dev,
+-			    sizeof(*chip) +
+-			    (nsels * sizeof(struct sunxi_nand_chip_sel)),
+-			    GFP_KERNEL);
+-	if (!chip) {
+-		dev_err(dev, "could not allocate chip\n");
+-		return -ENOMEM;
+-	}
+-
+-	chip->nsels = nsels;
+-	chip->selected = -1;
+-
+-	for (i = 0; i < nsels; i++) {
+-		ret = of_property_read_u32_index(np, "reg", i, &tmp);
+-		if (ret) {
+-			dev_err(dev, "could not retrieve reg property: %d\n",
+-				ret);
+-			return ret;
+-		}
+-
+-		if (tmp > NFC_MAX_CS) {
+-			dev_err(dev,
+-				"invalid reg value: %u (max CS = 7)\n",
+-				tmp);
+-			return -EINVAL;
+-		}
+-
+-		if (test_and_set_bit(tmp, &nfc->assigned_cs)) {
+-			dev_err(dev, "CS %d already assigned\n", tmp);
+-			return -EINVAL;
+-		}
+-
+-		chip->sels[i].cs = tmp;
+-
+-		if (!of_property_read_u32_index(np, "allwinner,rb", i, &tmp) &&
+-		    tmp < 2) {
+-			chip->sels[i].rb.type = RB_NATIVE;
+-			chip->sels[i].rb.info.nativeid = tmp;
+-		} else {
+-			ret = of_get_named_gpio(np, "rb-gpios", i);
+-			if (ret >= 0) {
+-				tmp = ret;
+-				chip->sels[i].rb.type = RB_GPIO;
+-				chip->sels[i].rb.info.gpio = tmp;
+-				ret = devm_gpio_request(dev, tmp, "nand-rb");
+-				if (ret)
+-					return ret;
+-
+-				ret = gpio_direction_input(tmp);
+-				if (ret)
+-					return ret;
+-			} else {
+-				chip->sels[i].rb.type = RB_NONE;
+-			}
+-		}
+-	}
+-
+-	nand = &chip->nand;
+-	/* Default tR value specified in the ONFI spec (chapter 4.15.1) */
+-	nand->chip_delay = 200;
+-	nand->controller = &nfc->controller;
+-	/*
+-	 * Set the ECC mode to the default value in case nothing is specified
+-	 * in the DT.
+-	 */
+-	nand->ecc.mode = NAND_ECC_HW;
+-	nand_set_flash_node(nand, np);
+-	nand->select_chip = sunxi_nfc_select_chip;
+-	nand->cmd_ctrl = sunxi_nfc_cmd_ctrl;
+-	nand->read_buf = sunxi_nfc_read_buf;
+-	nand->write_buf = sunxi_nfc_write_buf;
+-	nand->read_byte = sunxi_nfc_read_byte;
+-	nand->setup_data_interface = sunxi_nfc_setup_data_interface;
+-
+-	mtd = nand_to_mtd(nand);
+-	mtd->dev.parent = dev;
+-
+-	ret = nand_scan_ident(mtd, nsels, NULL);
+-	if (ret)
+-		return ret;
+-
+-	if (nand->bbt_options & NAND_BBT_USE_FLASH)
+-		nand->bbt_options |= NAND_BBT_NO_OOB;
+-
+-	if (nand->options & NAND_NEED_SCRAMBLING)
+-		nand->options |= NAND_NO_SUBPAGE_WRITE;
+-
+-	nand->options |= NAND_SUBPAGE_READ;
+-
+-	ret = sunxi_nand_ecc_init(mtd, &nand->ecc, np);
+-	if (ret) {
+-		dev_err(dev, "ECC init failed: %d\n", ret);
+-		return ret;
+-	}
+-
+-	ret = nand_scan_tail(mtd);
+-	if (ret) {
+-		dev_err(dev, "nand_scan_tail failed: %d\n", ret);
+-		return ret;
+-	}
+-
+-	ret = mtd_device_register(mtd, NULL, 0);
+-	if (ret) {
+-		dev_err(dev, "failed to register mtd device: %d\n", ret);
+-		nand_release(mtd);
+-		return ret;
+-	}
+-
+-	list_add_tail(&chip->node, &nfc->chips);
+-
+-	return 0;
+-}
+-
+-static int sunxi_nand_chips_init(struct device *dev, struct sunxi_nfc *nfc)
+-{
+-	struct device_node *np = dev->of_node;
+-	struct device_node *nand_np;
+-	int nchips = of_get_child_count(np);
+-	int ret;
+-
+-	if (nchips > 8) {
+-		dev_err(dev, "too many NAND chips: %d (max = 8)\n", nchips);
+-		return -EINVAL;
+-	}
+-
+-	for_each_child_of_node(np, nand_np) {
+-		ret = sunxi_nand_chip_init(dev, nfc, nand_np);
+-		if (ret) {
+-			of_node_put(nand_np);
+-			return ret;
+-		}
+-	}
+-
+-	return 0;
+-}
+-
+-static void sunxi_nand_chips_cleanup(struct sunxi_nfc *nfc)
+-{
+-	struct sunxi_nand_chip *chip;
+-
+-	while (!list_empty(&nfc->chips)) {
+-		chip = list_first_entry(&nfc->chips, struct sunxi_nand_chip,
+-					node);
+-		nand_release(nand_to_mtd(&chip->nand));
+-		sunxi_nand_ecc_cleanup(&chip->nand.ecc);
+-		list_del(&chip->node);
+-	}
+-}
+-
+-static int sunxi_nfc_probe(struct platform_device *pdev)
+-{
+-	struct device *dev = &pdev->dev;
+-	struct resource *r;
+-	struct sunxi_nfc *nfc;
+-	int irq;
+-	int ret;
+-
+-	nfc = devm_kzalloc(dev, sizeof(*nfc), GFP_KERNEL);
+-	if (!nfc)
+-		return -ENOMEM;
+-
+-	nfc->dev = dev;
+-	nand_hw_control_init(&nfc->controller);
+-	INIT_LIST_HEAD(&nfc->chips);
+-
+-	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+-	nfc->regs = devm_ioremap_resource(dev, r);
+-	if (IS_ERR(nfc->regs))
+-		return PTR_ERR(nfc->regs);
+-
+-	irq = platform_get_irq(pdev, 0);
+-	if (irq < 0) {
+-		dev_err(dev, "failed to retrieve irq\n");
+-		return irq;
+-	}
+-
+-	nfc->ahb_clk = devm_clk_get(dev, "ahb");
+-	if (IS_ERR(nfc->ahb_clk)) {
+-		dev_err(dev, "failed to retrieve ahb clk\n");
+-		return PTR_ERR(nfc->ahb_clk);
+-	}
+-
+-	ret = clk_prepare_enable(nfc->ahb_clk);
+-	if (ret)
+-		return ret;
+-
+-	nfc->mod_clk = devm_clk_get(dev, "mod");
+-	if (IS_ERR(nfc->mod_clk)) {
+-		dev_err(dev, "failed to retrieve mod clk\n");
+-		ret = PTR_ERR(nfc->mod_clk);
+-		goto out_ahb_clk_unprepare;
+-	}
+-
+-	ret = clk_prepare_enable(nfc->mod_clk);
+-	if (ret)
+-		goto out_ahb_clk_unprepare;
+-
+-	nfc->reset = devm_reset_control_get_optional_exclusive(dev, "ahb");
+-	if (IS_ERR(nfc->reset)) {
+-		ret = PTR_ERR(nfc->reset);
+-		goto out_mod_clk_unprepare;
+-	}
+-
+-	ret = reset_control_deassert(nfc->reset);
+-	if (ret) {
+-		dev_err(dev, "reset err %d\n", ret);
+-		goto out_mod_clk_unprepare;
+-	}
+-
+-	ret = sunxi_nfc_rst(nfc);
+-	if (ret)
+-		goto out_ahb_reset_reassert;
+-
+-	writel(0, nfc->regs + NFC_REG_INT);
+-	ret = devm_request_irq(dev, irq, sunxi_nfc_interrupt,
+-			       0, "sunxi-nand", nfc);
+-	if (ret)
+-		goto out_ahb_reset_reassert;
+-
+-	nfc->dmac = dma_request_slave_channel(dev, "rxtx");
+-	if (nfc->dmac) {
+-		struct dma_slave_config dmac_cfg = { };
+-
+-		dmac_cfg.src_addr = r->start + NFC_REG_IO_DATA;
+-		dmac_cfg.dst_addr = dmac_cfg.src_addr;
+-		dmac_cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+-		dmac_cfg.dst_addr_width = dmac_cfg.src_addr_width;
+-		dmac_cfg.src_maxburst = 4;
+-		dmac_cfg.dst_maxburst = 4;
+-		dmaengine_slave_config(nfc->dmac, &dmac_cfg);
+-	} else {
+-		dev_warn(dev, "failed to request rxtx DMA channel\n");
+-	}
+-
+-	platform_set_drvdata(pdev, nfc);
+-
+-	ret = sunxi_nand_chips_init(dev, nfc);
+-	if (ret) {
+-		dev_err(dev, "failed to init nand chips\n");
+-		goto out_release_dmac;
+-	}
+-
+-	return 0;
+-
+-out_release_dmac:
+-	if (nfc->dmac)
+-		dma_release_channel(nfc->dmac);
+-out_ahb_reset_reassert:
+-	reset_control_assert(nfc->reset);
+-out_mod_clk_unprepare:
+-	clk_disable_unprepare(nfc->mod_clk);
+-out_ahb_clk_unprepare:
+-	clk_disable_unprepare(nfc->ahb_clk);
+-
+-	return ret;
+-}
+-
+-static int sunxi_nfc_remove(struct platform_device *pdev)
+-{
+-	struct sunxi_nfc *nfc = platform_get_drvdata(pdev);
+-
+-	sunxi_nand_chips_cleanup(nfc);
+-
+-	reset_control_assert(nfc->reset);
+-
+-	if (nfc->dmac)
+-		dma_release_channel(nfc->dmac);
+-	clk_disable_unprepare(nfc->mod_clk);
+-	clk_disable_unprepare(nfc->ahb_clk);
+-
+-	return 0;
+-}
+-
+-static const struct of_device_id sunxi_nfc_ids[] = {
+-	{ .compatible = "allwinner,sun4i-a10-nand" },
+-	{ /* sentinel */ }
+-};
+-MODULE_DEVICE_TABLE(of, sunxi_nfc_ids);
+-
+-static struct platform_driver sunxi_nfc_driver = {
+-	.driver = {
+-		.name = "sunxi_nand",
+-		.of_match_table = sunxi_nfc_ids,
+-	},
+-	.probe = sunxi_nfc_probe,
+-	.remove = sunxi_nfc_remove,
+-};
+-module_platform_driver(sunxi_nfc_driver);
+-
+-MODULE_LICENSE("GPL v2");
+-MODULE_AUTHOR("Boris BREZILLON");
+-MODULE_DESCRIPTION("Allwinner NAND Flash Controller driver");
+-MODULE_ALIAS("platform:sunxi_nand");
+diff --git a/drivers/mtd/nand/tango_nand.c b/drivers/mtd/nand/tango_nand.c
+deleted file mode 100644
+index 766906f..0000000
+--- a/drivers/mtd/nand/tango_nand.c
++++ /dev/null
+@@ -1,699 +0,0 @@
+-/*
+- * Copyright (C) 2016 Sigma Designs
+- *
+- * 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/io.h>
+-#include <linux/of.h>
+-#include <linux/clk.h>
+-#include <linux/iopoll.h>
+-#include <linux/module.h>
+-#include <linux/mtd/rawnand.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 ERR_COUNT_PKT_0(v)	(((v) >> 0) & 0x3f)
+-#define ERR_COUNT_PKT_N(v)	(((v) >> 8) & 0x3f)
+-#define DECODE_FAIL_PKT_0(v)	(((v) & BIT(7)) == 0)
+-#define DECODE_FAIL_PKT_N(v)	(((v) & BIT(15)) == 0)
+-
+-/* 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 u8 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, u8 *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 u8 *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)
+-{
+-	struct mtd_info *mtd = nand_to_mtd(chip);
+-	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)
+-			mtd->ecc_stats.failed++;
+-		else
+-			mtd->ecc_stats.corrected += res;
+-
+-		bitflips = max(res, bitflips);
+-		buf += pkt_size;
+-		ecc += ecc_size;
+-	}
+-
+-	return bitflips;
+-}
+-
+-static int decode_error_report(struct nand_chip *chip)
+-{
+-	u32 status, res;
+-	struct mtd_info *mtd = nand_to_mtd(chip);
+-	struct tango_nfc *nfc = to_tango_nfc(chip->controller);
+-
+-	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_FAIL_PKT_0(res) || DECODE_FAIL_PKT_N(res))
+-		return -EBADMSG;
+-
+-	/* ERR_COUNT_PKT_N is max, not sum, but that's all we have */
+-	mtd->ecc_stats.corrected +=
+-		ERR_COUNT_PKT_0(res) + ERR_COUNT_PKT_N(res);
+-
+-	return max(ERR_COUNT_PKT_0(res), ERR_COUNT_PKT_N(res));
+-}
+-
+-static void tango_dma_callback(void *arg)
+-{
+-	complete(arg);
+-}
+-
+-static int do_dma(struct tango_nfc *nfc, enum dma_data_direction 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;
+-	enum dma_transfer_direction tdir;
+-	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;
+-
+-	tdir = dir == DMA_TO_DEVICE ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM;
+-	desc = dmaengine_prep_slave_sg(chan, &sg, 1, tdir, 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,
+-			   u8 *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(chip);
+-	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 u8 *buf, int oob_required, int page)
+-{
+-	struct tango_nfc *nfc = to_tango_nfc(chip->controller);
+-	int err, status, 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;
+-
+-	status = chip->waitfunc(mtd, chip);
+-	if (status & NAND_STATUS_FAIL)
+-		return -EIO;
+-
+-	return 0;
+-}
+-
+-static void aux_read(struct nand_chip *chip, u8 **buf, int len, int *pos)
+-{
+-	struct mtd_info *mtd = nand_to_mtd(chip);
+-
+-	*pos += len;
+-
+-	if (!*buf) {
+-		/* skip over "len" bytes */
+-		chip->cmdfunc(mtd, NAND_CMD_RNDOUT, *pos, -1);
+-	} else {
+-		tango_read_buf(mtd, *buf, len);
+-		*buf += len;
+-	}
+-}
+-
+-static void aux_write(struct nand_chip *chip, const u8 **buf, int len, int *pos)
+-{
+-	struct mtd_info *mtd = nand_to_mtd(chip);
+-
+-	*pos += len;
+-
+-	if (!*buf) {
+-		/* skip over "len" bytes */
+-		chip->cmdfunc(mtd, NAND_CMD_RNDIN, *pos, -1);
+-	} else {
+-		tango_write_buf(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 void raw_read(struct nand_chip *chip, u8 *buf, u8 *oob)
+-{
+-	struct mtd_info *mtd = nand_to_mtd(chip);
+-	u8 *oob_orig = oob;
+-	const int page_size = 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)
+-		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);
+-}
+-
+-static void raw_write(struct nand_chip *chip, const u8 *buf, const u8 *oob)
+-{
+-	struct mtd_info *mtd = nand_to_mtd(chip);
+-	const u8 *oob_orig = oob;
+-	const int page_size = 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)
+-		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);
+-}
+-
+-static int tango_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+-			       u8 *buf, int oob_required, int page)
+-{
+-	chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
+-	raw_read(chip, buf, chip->oob_poi);
+-	return 0;
+-}
+-
+-static int tango_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+-				const u8 *buf, int oob_required, int page)
+-{
+-	int status;
+-
+-	chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0, page);
+-	raw_write(chip, buf, chip->oob_poi);
+-	chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+-
+-	status = chip->waitfunc(mtd, chip);
+-	if (status & NAND_STATUS_FAIL)
+-		return -EIO;
+-
+-	return 0;
+-}
+-
+-static int tango_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
+-			  int page)
+-{
+-	chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
+-	raw_read(chip, NULL, chip->oob_poi);
+-	return 0;
+-}
+-
+-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, int csline,
+-			     const struct nand_data_interface *conf)
+-{
+-	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 (csline == NAND_DATA_IFACE_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 = nand_to_mtd(chip);
+-
+-	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;
+-	ecc->options = NAND_ECC_CUSTOM_PAGE_ACCESS;
+-
+-	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])
+-			nand_release(nand_to_mtd(&nfc->chips[cs]->nand_chip));
+-	}
+-
+-	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);
+-
+-	writel_relaxed(MODE_RAW, nfc->pbus_base + PBUS_PAD_MODE);
+-
+-	clk = clk_get(&pdev->dev, NULL);
+-	if (IS_ERR(clk))
+-		return PTR_ERR(clk);
+-
+-	nfc->chan = dma_request_chan(&pdev->dev, "rxtx");
+-	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 */ }
+-};
+-MODULE_DEVICE_TABLE(of, tango_nand_ids);
+-
+-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");
+diff --git a/drivers/mtd/nand/tmio_nand.c b/drivers/mtd/nand/tmio_nand.c
+deleted file mode 100644
+index 84dbf32..0000000
+--- a/drivers/mtd/nand/tmio_nand.c
++++ /dev/null
+@@ -1,512 +0,0 @@
+-/*
+- * Toshiba TMIO NAND flash controller driver
+- *
+- * Slightly murky pre-git history of the driver:
+- *
+- * Copyright (c) Ian Molton 2004, 2005, 2008
+- *    Original work, independent of sharps code. Included hardware ECC support.
+- *    Hard ECC did not work for writes in the early revisions.
+- * Copyright (c) Dirk Opfer 2005.
+- *    Modifications developed from sharps code but
+- *    NOT containing any, ported onto Ians base.
+- * Copyright (c) Chris Humbert 2005
+- * Copyright (c) Dmitry Baryshkov 2008
+- *    Minor fixes
+- *
+- * Parts copyright Sebastian Carlier
+- *
+- * This file is licensed under
+- * the terms of the GNU General Public License version 2. This program
+- * is licensed "as is" without any warranty of any kind, whether express
+- * or implied.
+- *
+- */
+-
+-
+-#include <linux/kernel.h>
+-#include <linux/module.h>
+-#include <linux/platform_device.h>
+-#include <linux/mfd/core.h>
+-#include <linux/mfd/tmio.h>
+-#include <linux/delay.h>
+-#include <linux/io.h>
+-#include <linux/irq.h>
+-#include <linux/interrupt.h>
+-#include <linux/ioport.h>
+-#include <linux/mtd/mtd.h>
+-#include <linux/mtd/rawnand.h>
+-#include <linux/mtd/nand_ecc.h>
+-#include <linux/mtd/partitions.h>
+-#include <linux/slab.h>
+-
+-/*--------------------------------------------------------------------------*/
+-
+-/*
+- * NAND Flash Host Controller Configuration Register
+- */
+-#define CCR_COMMAND	0x04	/* w Command				*/
+-#define CCR_BASE	0x10	/* l NAND Flash Control Reg Base Addr	*/
+-#define CCR_INTP	0x3d	/* b Interrupt Pin			*/
+-#define CCR_INTE	0x48	/* b Interrupt Enable			*/
+-#define CCR_EC		0x4a	/* b Event Control			*/
+-#define CCR_ICC		0x4c	/* b Internal Clock Control		*/
+-#define CCR_ECCC	0x5b	/* b ECC Control			*/
+-#define CCR_NFTC	0x60	/* b NAND Flash Transaction Control	*/
+-#define CCR_NFM		0x61	/* b NAND Flash Monitor			*/
+-#define CCR_NFPSC	0x62	/* b NAND Flash Power Supply Control	*/
+-#define CCR_NFDC	0x63	/* b NAND Flash Detect Control		*/
+-
+-/*
+- * NAND Flash Control Register
+- */
+-#define FCR_DATA	0x00	/* bwl Data Register			*/
+-#define FCR_MODE	0x04	/* b Mode Register			*/
+-#define FCR_STATUS	0x05	/* b Status Register			*/
+-#define FCR_ISR		0x06	/* b Interrupt Status Register		*/
+-#define FCR_IMR		0x07	/* b Interrupt Mask Register		*/
+-
+-/* FCR_MODE Register Command List */
+-#define FCR_MODE_DATA	0x94	/* Data Data_Mode */
+-#define FCR_MODE_COMMAND 0x95	/* Data Command_Mode */
+-#define FCR_MODE_ADDRESS 0x96	/* Data Address_Mode */
+-
+-#define FCR_MODE_HWECC_CALC	0xB4	/* HW-ECC Data */
+-#define FCR_MODE_HWECC_RESULT	0xD4	/* HW-ECC Calc result Read_Mode */
+-#define FCR_MODE_HWECC_RESET	0xF4	/* HW-ECC Reset */
+-
+-#define FCR_MODE_POWER_ON	0x0C	/* Power Supply ON  to SSFDC card */
+-#define FCR_MODE_POWER_OFF	0x08	/* Power Supply OFF to SSFDC card */
+-
+-#define FCR_MODE_LED_OFF	0x00	/* LED OFF */
+-#define FCR_MODE_LED_ON		0x04	/* LED ON */
+-
+-#define FCR_MODE_EJECT_ON	0x68	/* Ejection events active  */
+-#define FCR_MODE_EJECT_OFF	0x08	/* Ejection events ignored */
+-
+-#define FCR_MODE_LOCK		0x6C	/* Lock_Mode. Eject Switch Invalid */
+-#define FCR_MODE_UNLOCK		0x0C	/* UnLock_Mode. Eject Switch is valid */
+-
+-#define FCR_MODE_CONTROLLER_ID	0x40	/* Controller ID Read */
+-#define FCR_MODE_STANDBY	0x00	/* SSFDC card Changes Standby State */
+-
+-#define FCR_MODE_WE		0x80
+-#define FCR_MODE_ECC1		0x40
+-#define FCR_MODE_ECC0		0x20
+-#define FCR_MODE_CE		0x10
+-#define FCR_MODE_PCNT1		0x08
+-#define FCR_MODE_PCNT0		0x04
+-#define FCR_MODE_ALE		0x02
+-#define FCR_MODE_CLE		0x01
+-
+-#define FCR_STATUS_BUSY		0x80
+-
+-/*--------------------------------------------------------------------------*/
+-
+-struct tmio_nand {
+-	struct nand_chip chip;
+-
+-	struct platform_device *dev;
+-
+-	void __iomem *ccr;
+-	void __iomem *fcr;
+-	unsigned long fcr_base;
+-
+-	unsigned int irq;
+-
+-	/* for tmio_nand_read_byte */
+-	u8			read;
+-	unsigned read_good:1;
+-};
+-
+-static inline struct tmio_nand *mtd_to_tmio(struct mtd_info *mtd)
+-{
+-	return container_of(mtd_to_nand(mtd), struct tmio_nand, chip);
+-}
+-
+-
+-/*--------------------------------------------------------------------------*/
+-
+-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);
+-
+-	if (ctrl & NAND_CTRL_CHANGE) {
+-		u8 mode;
+-
+-		if (ctrl & NAND_NCE) {
+-			mode = FCR_MODE_DATA;
+-
+-			if (ctrl & NAND_CLE)
+-				mode |=  FCR_MODE_CLE;
+-			else
+-				mode &= ~FCR_MODE_CLE;
+-
+-			if (ctrl & NAND_ALE)
+-				mode |=  FCR_MODE_ALE;
+-			else
+-				mode &= ~FCR_MODE_ALE;
+-		} else {
+-			mode = FCR_MODE_STANDBY;
+-		}
+-
+-		tmio_iowrite8(mode, tmio->fcr + FCR_MODE);
+-		tmio->read_good = 0;
+-	}
+-
+-	if (cmd != NAND_CMD_NONE)
+-		tmio_iowrite8(cmd, chip->IO_ADDR_W);
+-}
+-
+-static int tmio_nand_dev_ready(struct mtd_info *mtd)
+-{
+-	struct tmio_nand *tmio = mtd_to_tmio(mtd);
+-
+-	return !(tmio_ioread8(tmio->fcr + FCR_STATUS) & FCR_STATUS_BUSY);
+-}
+-
+-static irqreturn_t tmio_irq(int irq, void *__tmio)
+-{
+-	struct tmio_nand *tmio = __tmio;
+-	struct nand_chip *nand_chip = &tmio->chip;
+-
+-	/* disable RDYREQ interrupt */
+-	tmio_iowrite8(0x00, tmio->fcr + FCR_IMR);
+-
+-	if (unlikely(!waitqueue_active(&nand_chip->controller->wq)))
+-		dev_warn(&tmio->dev->dev, "spurious interrupt\n");
+-
+-	wake_up(&nand_chip->controller->wq);
+-	return IRQ_HANDLED;
+-}
+-
+-/*
+-  *The TMIO core has a RDYREQ interrupt on the posedge of #SMRB.
+-  *This interrupt is normally disabled, but for long operations like
+-  *erase and write, we enable it to wake us up.  The irq handler
+-  *disables the interrupt.
+- */
+-static int
+-tmio_nand_wait(struct mtd_info *mtd, struct nand_chip *nand_chip)
+-{
+-	struct tmio_nand *tmio = mtd_to_tmio(mtd);
+-	long timeout;
+-
+-	/* enable RDYREQ interrupt */
+-	tmio_iowrite8(0x0f, tmio->fcr + FCR_ISR);
+-	tmio_iowrite8(0x81, tmio->fcr + FCR_IMR);
+-
+-	timeout = wait_event_timeout(nand_chip->controller->wq,
+-		tmio_nand_dev_ready(mtd),
+-		msecs_to_jiffies(nand_chip->state == FL_ERASING ? 400 : 20));
+-
+-	if (unlikely(!tmio_nand_dev_ready(mtd))) {
+-		tmio_iowrite8(0x00, tmio->fcr + FCR_IMR);
+-		dev_warn(&tmio->dev->dev, "still busy with %s after %d ms\n",
+-			nand_chip->state == FL_ERASING ? "erase" : "program",
+-			nand_chip->state == FL_ERASING ? 400 : 20);
+-
+-	} else if (unlikely(!timeout)) {
+-		tmio_iowrite8(0x00, tmio->fcr + FCR_IMR);
+-		dev_warn(&tmio->dev->dev, "timeout waiting for interrupt\n");
+-	}
+-
+-	nand_chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
+-	return nand_chip->read_byte(mtd);
+-}
+-
+-/*
+-  *The TMIO controller combines two 8-bit data bytes into one 16-bit
+-  *word. This function separates them so nand_base.c works as expected,
+-  *especially its NAND_CMD_READID routines.
+- *
+-  *To prevent stale data from being read, tmio_nand_hwcontrol() clears
+-  *tmio->read_good.
+- */
+-static u_char tmio_nand_read_byte(struct mtd_info *mtd)
+-{
+-	struct tmio_nand *tmio = mtd_to_tmio(mtd);
+-	unsigned int data;
+-
+-	if (tmio->read_good--)
+-		return tmio->read;
+-
+-	data = tmio_ioread16(tmio->fcr + FCR_DATA);
+-	tmio->read = data >> 8;
+-	return data;
+-}
+-
+-/*
+-  *The TMIO controller converts an 8-bit NAND interface to a 16-bit
+-  *bus interface, so all data reads and writes must be 16-bit wide.
+-  *Thus, we implement 16-bit versions of the read, write, and verify
+-  *buffer functions.
+- */
+-static void
+-tmio_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
+-{
+-	struct tmio_nand *tmio = mtd_to_tmio(mtd);
+-
+-	tmio_iowrite16_rep(tmio->fcr + FCR_DATA, buf, len >> 1);
+-}
+-
+-static void tmio_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+-{
+-	struct tmio_nand *tmio = mtd_to_tmio(mtd);
+-
+-	tmio_ioread16_rep(tmio->fcr + FCR_DATA, buf, len >> 1);
+-}
+-
+-static void tmio_nand_enable_hwecc(struct mtd_info *mtd, int mode)
+-{
+-	struct tmio_nand *tmio = mtd_to_tmio(mtd);
+-
+-	tmio_iowrite8(FCR_MODE_HWECC_RESET, tmio->fcr + FCR_MODE);
+-	tmio_ioread8(tmio->fcr + FCR_DATA);	/* dummy read */
+-	tmio_iowrite8(FCR_MODE_HWECC_CALC, tmio->fcr + FCR_MODE);
+-}
+-
+-static int tmio_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
+-							u_char *ecc_code)
+-{
+-	struct tmio_nand *tmio = mtd_to_tmio(mtd);
+-	unsigned int ecc;
+-
+-	tmio_iowrite8(FCR_MODE_HWECC_RESULT, tmio->fcr + FCR_MODE);
+-
+-	ecc = tmio_ioread16(tmio->fcr + FCR_DATA);
+-	ecc_code[1] = ecc;	/* 000-255 LP7-0 */
+-	ecc_code[0] = ecc >> 8;	/* 000-255 LP15-8 */
+-	ecc = tmio_ioread16(tmio->fcr + FCR_DATA);
+-	ecc_code[2] = ecc;	/* 000-255 CP5-0,11b */
+-	ecc_code[4] = ecc >> 8;	/* 256-511 LP7-0 */
+-	ecc = tmio_ioread16(tmio->fcr + FCR_DATA);
+-	ecc_code[3] = ecc;	/* 256-511 LP15-8 */
+-	ecc_code[5] = ecc >> 8;	/* 256-511 CP5-0,11b */
+-
+-	tmio_iowrite8(FCR_MODE_DATA, tmio->fcr + FCR_MODE);
+-	return 0;
+-}
+-
+-static int tmio_nand_correct_data(struct mtd_info *mtd, unsigned char *buf,
+-		unsigned char *read_ecc, unsigned char *calc_ecc)
+-{
+-	int r0, r1;
+-
+-	/* assume ecc.size = 512 and ecc.bytes = 6 */
+-	r0 = __nand_correct_data(buf, read_ecc, calc_ecc, 256);
+-	if (r0 < 0)
+-		return r0;
+-	r1 = __nand_correct_data(buf + 256, read_ecc + 3, calc_ecc + 3, 256);
+-	if (r1 < 0)
+-		return r1;
+-	return r0 + r1;
+-}
+-
+-static int tmio_hw_init(struct platform_device *dev, struct tmio_nand *tmio)
+-{
+-	const struct mfd_cell *cell = mfd_get_cell(dev);
+-	int ret;
+-
+-	if (cell->enable) {
+-		ret = cell->enable(dev);
+-		if (ret)
+-			return ret;
+-	}
+-
+-	/* (4Ch) CLKRUN Enable    1st spcrunc */
+-	tmio_iowrite8(0x81, tmio->ccr + CCR_ICC);
+-
+-	/* (10h)BaseAddress    0x1000 spba.spba2 */
+-	tmio_iowrite16(tmio->fcr_base, tmio->ccr + CCR_BASE);
+-	tmio_iowrite16(tmio->fcr_base >> 16, tmio->ccr + CCR_BASE + 2);
+-
+-	/* (04h)Command Register I/O spcmd */
+-	tmio_iowrite8(0x02, tmio->ccr + CCR_COMMAND);
+-
+-	/* (62h) Power Supply Control ssmpwc */
+-	/* HardPowerOFF - SuspendOFF - PowerSupplyWait_4MS */
+-	tmio_iowrite8(0x02, tmio->ccr + CCR_NFPSC);
+-
+-	/* (63h) Detect Control ssmdtc */
+-	tmio_iowrite8(0x02, tmio->ccr + CCR_NFDC);
+-
+-	/* Interrupt status register clear sintst */
+-	tmio_iowrite8(0x0f, tmio->fcr + FCR_ISR);
+-
+-	/* After power supply, Media are reset smode */
+-	tmio_iowrite8(FCR_MODE_POWER_ON, tmio->fcr + FCR_MODE);
+-	tmio_iowrite8(FCR_MODE_COMMAND, tmio->fcr + FCR_MODE);
+-	tmio_iowrite8(NAND_CMD_RESET, tmio->fcr + FCR_DATA);
+-
+-	/* Standby Mode smode */
+-	tmio_iowrite8(FCR_MODE_STANDBY, tmio->fcr + FCR_MODE);
+-
+-	mdelay(5);
+-
+-	return 0;
+-}
+-
+-static void tmio_hw_stop(struct platform_device *dev, struct tmio_nand *tmio)
+-{
+-	const struct mfd_cell *cell = mfd_get_cell(dev);
+-
+-	tmio_iowrite8(FCR_MODE_POWER_OFF, tmio->fcr + FCR_MODE);
+-	if (cell->disable)
+-		cell->disable(dev);
+-}
+-
+-static int tmio_probe(struct platform_device *dev)
+-{
+-	struct tmio_nand_data *data = dev_get_platdata(&dev->dev);
+-	struct resource *fcr = platform_get_resource(dev,
+-			IORESOURCE_MEM, 0);
+-	struct resource *ccr = platform_get_resource(dev,
+-			IORESOURCE_MEM, 1);
+-	int irq = platform_get_irq(dev, 0);
+-	struct tmio_nand *tmio;
+-	struct mtd_info *mtd;
+-	struct nand_chip *nand_chip;
+-	int retval;
+-
+-	if (data == NULL)
+-		dev_warn(&dev->dev, "NULL platform data!\n");
+-
+-	tmio = devm_kzalloc(&dev->dev, sizeof(*tmio), GFP_KERNEL);
+-	if (!tmio)
+-		return -ENOMEM;
+-
+-	tmio->dev = dev;
+-
+-	platform_set_drvdata(dev, tmio);
+-	nand_chip = &tmio->chip;
+-	mtd = nand_to_mtd(nand_chip);
+-	mtd->name = "tmio-nand";
+-	mtd->dev.parent = &dev->dev;
+-
+-	tmio->ccr = devm_ioremap(&dev->dev, ccr->start, resource_size(ccr));
+-	if (!tmio->ccr)
+-		return -EIO;
+-
+-	tmio->fcr_base = fcr->start & 0xfffff;
+-	tmio->fcr = devm_ioremap(&dev->dev, fcr->start, resource_size(fcr));
+-	if (!tmio->fcr)
+-		return -EIO;
+-
+-	retval = tmio_hw_init(dev, tmio);
+-	if (retval)
+-		return retval;
+-
+-	/* Set address of NAND IO lines */
+-	nand_chip->IO_ADDR_R = tmio->fcr;
+-	nand_chip->IO_ADDR_W = tmio->fcr;
+-
+-	/* Set address of hardware control function */
+-	nand_chip->cmd_ctrl = tmio_nand_hwcontrol;
+-	nand_chip->dev_ready = tmio_nand_dev_ready;
+-	nand_chip->read_byte = tmio_nand_read_byte;
+-	nand_chip->write_buf = tmio_nand_write_buf;
+-	nand_chip->read_buf = tmio_nand_read_buf;
+-
+-	/* set eccmode using hardware ECC */
+-	nand_chip->ecc.mode = NAND_ECC_HW;
+-	nand_chip->ecc.size = 512;
+-	nand_chip->ecc.bytes = 6;
+-	nand_chip->ecc.strength = 2;
+-	nand_chip->ecc.hwctl = tmio_nand_enable_hwecc;
+-	nand_chip->ecc.calculate = tmio_nand_calculate_ecc;
+-	nand_chip->ecc.correct = tmio_nand_correct_data;
+-
+-	if (data)
+-		nand_chip->badblock_pattern = data->badblock_pattern;
+-
+-	/* 15 us command delay time */
+-	nand_chip->chip_delay = 15;
+-
+-	retval = devm_request_irq(&dev->dev, irq, &tmio_irq, 0,
+-				  dev_name(&dev->dev), tmio);
+-	if (retval) {
+-		dev_err(&dev->dev, "request_irq error %d\n", retval);
+-		goto err_irq;
+-	}
+-
+-	tmio->irq = irq;
+-	nand_chip->waitfunc = tmio_nand_wait;
+-
+-	/* Scan to find existence of the device */
+-	retval = nand_scan(mtd, 1);
+-	if (retval)
+-		goto err_irq;
+-
+-	/* Register the partitions */
+-	retval = mtd_device_parse_register(mtd,
+-					   data ? data->part_parsers : NULL,
+-					   NULL,
+-					   data ? data->partition : NULL,
+-					   data ? data->num_partitions : 0);
+-	if (!retval)
+-		return retval;
+-
+-	nand_release(mtd);
+-
+-err_irq:
+-	tmio_hw_stop(dev, tmio);
+-	return retval;
+-}
+-
+-static int tmio_remove(struct platform_device *dev)
+-{
+-	struct tmio_nand *tmio = platform_get_drvdata(dev);
+-
+-	nand_release(nand_to_mtd(&tmio->chip));
+-	tmio_hw_stop(dev, tmio);
+-	return 0;
+-}
+-
+-#ifdef CONFIG_PM
+-static int tmio_suspend(struct platform_device *dev, pm_message_t state)
+-{
+-	const struct mfd_cell *cell = mfd_get_cell(dev);
+-
+-	if (cell->suspend)
+-		cell->suspend(dev);
+-
+-	tmio_hw_stop(dev, platform_get_drvdata(dev));
+-	return 0;
+-}
+-
+-static int tmio_resume(struct platform_device *dev)
+-{
+-	const struct mfd_cell *cell = mfd_get_cell(dev);
+-
+-	/* FIXME - is this required or merely another attack of the broken
+-	 * SHARP platform? Looks suspicious.
+-	 */
+-	tmio_hw_init(dev, platform_get_drvdata(dev));
+-
+-	if (cell->resume)
+-		cell->resume(dev);
+-
+-	return 0;
+-}
+-#else
+-#define tmio_suspend NULL
+-#define tmio_resume NULL
+-#endif
+-
+-static struct platform_driver tmio_driver = {
+-	.driver.name	= "tmio-nand",
+-	.driver.owner	= THIS_MODULE,
+-	.probe		= tmio_probe,
+-	.remove		= tmio_remove,
+-	.suspend	= tmio_suspend,
+-	.resume		= tmio_resume,
+-};
+-
+-module_platform_driver(tmio_driver);
+-
+-MODULE_LICENSE("GPL v2");
+-MODULE_AUTHOR("Ian Molton, Dirk Opfer, Chris Humbert, Dmitry Baryshkov");
+-MODULE_DESCRIPTION("NAND flash driver on Toshiba Mobile IO controller");
+-MODULE_ALIAS("platform:tmio-nand");
+diff --git a/drivers/mtd/nand/txx9ndfmc.c b/drivers/mtd/nand/txx9ndfmc.c
+deleted file mode 100644
+index b567d21..0000000
+--- a/drivers/mtd/nand/txx9ndfmc.c
++++ /dev/null
+@@ -1,423 +0,0 @@
+-/*
+- * TXx9 NAND flash memory controller driver
+- * Based on RBTX49xx patch from CELF patch archive.
+- *
+- * 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.
+- *
+- * (C) Copyright TOSHIBA CORPORATION 2004-2007
+- * All Rights Reserved.
+- */
+-#include <linux/err.h>
+-#include <linux/init.h>
+-#include <linux/slab.h>
+-#include <linux/module.h>
+-#include <linux/platform_device.h>
+-#include <linux/delay.h>
+-#include <linux/mtd/mtd.h>
+-#include <linux/mtd/rawnand.h>
+-#include <linux/mtd/nand_ecc.h>
+-#include <linux/mtd/partitions.h>
+-#include <linux/io.h>
+-#include <asm/txx9/ndfmc.h>
+-
+-/* TXX9 NDFMC Registers */
+-#define TXX9_NDFDTR	0x00
+-#define TXX9_NDFMCR	0x04
+-#define TXX9_NDFSR	0x08
+-#define TXX9_NDFISR	0x0c
+-#define TXX9_NDFIMR	0x10
+-#define TXX9_NDFSPR	0x14
+-#define TXX9_NDFRSTR	0x18	/* not TX4939 */
+-
+-/* NDFMCR : NDFMC Mode Control */
+-#define TXX9_NDFMCR_WE	0x80
+-#define TXX9_NDFMCR_ECC_ALL	0x60
+-#define TXX9_NDFMCR_ECC_RESET	0x60
+-#define TXX9_NDFMCR_ECC_READ	0x40
+-#define TXX9_NDFMCR_ECC_ON	0x20
+-#define TXX9_NDFMCR_ECC_OFF	0x00
+-#define TXX9_NDFMCR_CE	0x10
+-#define TXX9_NDFMCR_BSPRT	0x04	/* TX4925/TX4926 only */
+-#define TXX9_NDFMCR_ALE	0x02
+-#define TXX9_NDFMCR_CLE	0x01
+-/* TX4939 only */
+-#define TXX9_NDFMCR_X16	0x0400
+-#define TXX9_NDFMCR_DMAREQ_MASK	0x0300
+-#define TXX9_NDFMCR_DMAREQ_NODMA	0x0000
+-#define TXX9_NDFMCR_DMAREQ_128	0x0100
+-#define TXX9_NDFMCR_DMAREQ_256	0x0200
+-#define TXX9_NDFMCR_DMAREQ_512	0x0300
+-#define TXX9_NDFMCR_CS_MASK	0x0c
+-#define TXX9_NDFMCR_CS(ch)	((ch) << 2)
+-
+-/* NDFMCR : NDFMC Status */
+-#define TXX9_NDFSR_BUSY	0x80
+-/* TX4939 only */
+-#define TXX9_NDFSR_DMARUN	0x40
+-
+-/* NDFMCR : NDFMC Reset */
+-#define TXX9_NDFRSTR_RST	0x01
+-
+-struct txx9ndfmc_priv {
+-	struct platform_device *dev;
+-	struct nand_chip chip;
+-	int cs;
+-	const char *mtdname;
+-};
+-
+-#define MAX_TXX9NDFMC_DEV	4
+-struct txx9ndfmc_drvdata {
+-	struct mtd_info *mtds[MAX_TXX9NDFMC_DEV];
+-	void __iomem *base;
+-	unsigned char hold;	/* in gbusclock */
+-	unsigned char spw;	/* in gbusclock */
+-	struct nand_hw_control hw_control;
+-};
+-
+-static struct platform_device *mtd_to_platdev(struct mtd_info *mtd)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct txx9ndfmc_priv *txx9_priv = nand_get_controller_data(chip);
+-	return txx9_priv->dev;
+-}
+-
+-static void __iomem *ndregaddr(struct platform_device *dev, unsigned int reg)
+-{
+-	struct txx9ndfmc_drvdata *drvdata = platform_get_drvdata(dev);
+-	struct txx9ndfmc_platform_data *plat = dev_get_platdata(&dev->dev);
+-
+-	return drvdata->base + (reg << plat->shift);
+-}
+-
+-static u32 txx9ndfmc_read(struct platform_device *dev, unsigned int reg)
+-{
+-	return __raw_readl(ndregaddr(dev, reg));
+-}
+-
+-static void txx9ndfmc_write(struct platform_device *dev,
+-			    u32 val, unsigned int reg)
+-{
+-	__raw_writel(val, ndregaddr(dev, reg));
+-}
+-
+-static uint8_t txx9ndfmc_read_byte(struct mtd_info *mtd)
+-{
+-	struct platform_device *dev = mtd_to_platdev(mtd);
+-
+-	return txx9ndfmc_read(dev, TXX9_NDFDTR);
+-}
+-
+-static void txx9ndfmc_write_buf(struct mtd_info *mtd, const uint8_t *buf,
+-				int len)
+-{
+-	struct platform_device *dev = mtd_to_platdev(mtd);
+-	void __iomem *ndfdtr = ndregaddr(dev, TXX9_NDFDTR);
+-	u32 mcr = txx9ndfmc_read(dev, TXX9_NDFMCR);
+-
+-	txx9ndfmc_write(dev, mcr | TXX9_NDFMCR_WE, TXX9_NDFMCR);
+-	while (len--)
+-		__raw_writel(*buf++, ndfdtr);
+-	txx9ndfmc_write(dev, mcr, TXX9_NDFMCR);
+-}
+-
+-static void txx9ndfmc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+-{
+-	struct platform_device *dev = mtd_to_platdev(mtd);
+-	void __iomem *ndfdtr = ndregaddr(dev, TXX9_NDFDTR);
+-
+-	while (len--)
+-		*buf++ = __raw_readl(ndfdtr);
+-}
+-
+-static void txx9ndfmc_cmd_ctrl(struct mtd_info *mtd, int cmd,
+-			       unsigned int ctrl)
+-{
+-	struct nand_chip *chip = mtd_to_nand(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);
+-
+-	if (ctrl & NAND_CTRL_CHANGE) {
+-		u32 mcr = txx9ndfmc_read(dev, TXX9_NDFMCR);
+-
+-		mcr &= ~(TXX9_NDFMCR_CLE | TXX9_NDFMCR_ALE | TXX9_NDFMCR_CE);
+-		mcr |= ctrl & NAND_CLE ? TXX9_NDFMCR_CLE : 0;
+-		mcr |= ctrl & NAND_ALE ? TXX9_NDFMCR_ALE : 0;
+-		/* TXX9_NDFMCR_CE bit is 0:high 1:low */
+-		mcr |= ctrl & NAND_NCE ? TXX9_NDFMCR_CE : 0;
+-		if (txx9_priv->cs >= 0 && (ctrl & NAND_NCE)) {
+-			mcr &= ~TXX9_NDFMCR_CS_MASK;
+-			mcr |= TXX9_NDFMCR_CS(txx9_priv->cs);
+-		}
+-		txx9ndfmc_write(dev, mcr, TXX9_NDFMCR);
+-	}
+-	if (cmd != NAND_CMD_NONE)
+-		txx9ndfmc_write(dev, cmd & 0xff, TXX9_NDFDTR);
+-	if (plat->flags & NDFMC_PLAT_FLAG_DUMMYWRITE) {
+-		/* dummy write to update external latch */
+-		if ((ctrl & NAND_CTRL_CHANGE) && cmd == NAND_CMD_NONE)
+-			txx9ndfmc_write(dev, 0, TXX9_NDFDTR);
+-	}
+-	mmiowb();
+-}
+-
+-static int txx9ndfmc_dev_ready(struct mtd_info *mtd)
+-{
+-	struct platform_device *dev = mtd_to_platdev(mtd);
+-
+-	return !(txx9ndfmc_read(dev, TXX9_NDFSR) & TXX9_NDFSR_BUSY);
+-}
+-
+-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);
+-	int eccbytes;
+-	u32 mcr = txx9ndfmc_read(dev, TXX9_NDFMCR);
+-
+-	mcr &= ~TXX9_NDFMCR_ECC_ALL;
+-	txx9ndfmc_write(dev, mcr | TXX9_NDFMCR_ECC_OFF, TXX9_NDFMCR);
+-	txx9ndfmc_write(dev, mcr | TXX9_NDFMCR_ECC_READ, TXX9_NDFMCR);
+-	for (eccbytes = chip->ecc.bytes; eccbytes > 0; eccbytes -= 3) {
+-		ecc_code[1] = txx9ndfmc_read(dev, TXX9_NDFDTR);
+-		ecc_code[0] = txx9ndfmc_read(dev, TXX9_NDFDTR);
+-		ecc_code[2] = txx9ndfmc_read(dev, TXX9_NDFDTR);
+-		ecc_code += 3;
+-	}
+-	txx9ndfmc_write(dev, mcr | TXX9_NDFMCR_ECC_OFF, TXX9_NDFMCR);
+-	return 0;
+-}
+-
+-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);
+-	int eccsize;
+-	int corrected = 0;
+-	int stat;
+-
+-	for (eccsize = chip->ecc.size; eccsize > 0; eccsize -= 256) {
+-		stat = __nand_correct_data(buf, read_ecc, calc_ecc, 256);
+-		if (stat < 0)
+-			return stat;
+-		corrected += stat;
+-		buf += 256;
+-		read_ecc += 3;
+-		calc_ecc += 3;
+-	}
+-	return corrected;
+-}
+-
+-static void txx9ndfmc_enable_hwecc(struct mtd_info *mtd, int mode)
+-{
+-	struct platform_device *dev = mtd_to_platdev(mtd);
+-	u32 mcr = txx9ndfmc_read(dev, TXX9_NDFMCR);
+-
+-	mcr &= ~TXX9_NDFMCR_ECC_ALL;
+-	txx9ndfmc_write(dev, mcr | TXX9_NDFMCR_ECC_RESET, TXX9_NDFMCR);
+-	txx9ndfmc_write(dev, mcr | TXX9_NDFMCR_ECC_OFF, TXX9_NDFMCR);
+-	txx9ndfmc_write(dev, mcr | TXX9_NDFMCR_ECC_ON, TXX9_NDFMCR);
+-}
+-
+-static void txx9ndfmc_initialize(struct platform_device *dev)
+-{
+-	struct txx9ndfmc_platform_data *plat = dev_get_platdata(&dev->dev);
+-	struct txx9ndfmc_drvdata *drvdata = platform_get_drvdata(dev);
+-	int tmout = 100;
+-
+-	if (plat->flags & NDFMC_PLAT_FLAG_NO_RSTR)
+-		; /* no NDFRSTR.  Write to NDFSPR resets the NDFMC. */
+-	else {
+-		/* reset NDFMC */
+-		txx9ndfmc_write(dev,
+-				txx9ndfmc_read(dev, TXX9_NDFRSTR) |
+-				TXX9_NDFRSTR_RST,
+-				TXX9_NDFRSTR);
+-		while (txx9ndfmc_read(dev, TXX9_NDFRSTR) & TXX9_NDFRSTR_RST) {
+-			if (--tmout == 0) {
+-				dev_err(&dev->dev, "reset failed.\n");
+-				break;
+-			}
+-			udelay(1);
+-		}
+-	}
+-	/* setup Hold Time, Strobe Pulse Width */
+-	txx9ndfmc_write(dev, (drvdata->hold << 4) | drvdata->spw, TXX9_NDFSPR);
+-	txx9ndfmc_write(dev,
+-			(plat->flags & NDFMC_PLAT_FLAG_USE_BSPRT) ?
+-			TXX9_NDFMCR_BSPRT : 0, TXX9_NDFMCR);
+-}
+-
+-#define TXX9NDFMC_NS_TO_CYC(gbusclk, ns) \
+-	DIV_ROUND_UP((ns) * DIV_ROUND_UP(gbusclk, 1000), 1000000)
+-
+-static int txx9ndfmc_nand_scan(struct mtd_info *mtd)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	int ret;
+-
+-	ret = nand_scan_ident(mtd, 1, NULL);
+-	if (!ret) {
+-		if (mtd->writesize >= 512) {
+-			/* Hardware ECC 6 byte ECC per 512 Byte data */
+-			chip->ecc.size = 512;
+-			chip->ecc.bytes = 6;
+-		}
+-		ret = nand_scan_tail(mtd);
+-	}
+-	return ret;
+-}
+-
+-static int __init txx9ndfmc_probe(struct platform_device *dev)
+-{
+-	struct txx9ndfmc_platform_data *plat = dev_get_platdata(&dev->dev);
+-	int hold, spw;
+-	int i;
+-	struct txx9ndfmc_drvdata *drvdata;
+-	unsigned long gbusclk = plat->gbus_clock;
+-	struct resource *res;
+-
+-	drvdata = devm_kzalloc(&dev->dev, sizeof(*drvdata), GFP_KERNEL);
+-	if (!drvdata)
+-		return -ENOMEM;
+-	res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+-	drvdata->base = devm_ioremap_resource(&dev->dev, res);
+-	if (IS_ERR(drvdata->base))
+-		return PTR_ERR(drvdata->base);
+-
+-	hold = plat->hold ?: 20; /* tDH */
+-	spw = plat->spw ?: 90; /* max(tREADID, tWP, tRP) */
+-
+-	hold = TXX9NDFMC_NS_TO_CYC(gbusclk, hold);
+-	spw = TXX9NDFMC_NS_TO_CYC(gbusclk, spw);
+-	if (plat->flags & NDFMC_PLAT_FLAG_HOLDADD)
+-		hold -= 2;	/* actual hold time : (HOLD + 2) BUSCLK */
+-	spw -= 1;	/* actual wait time : (SPW + 1) BUSCLK */
+-	hold = clamp(hold, 1, 15);
+-	drvdata->hold = hold;
+-	spw = clamp(spw, 1, 15);
+-	drvdata->spw = spw;
+-	dev_info(&dev->dev, "CLK:%ldMHz HOLD:%d SPW:%d\n",
+-		 (gbusclk + 500000) / 1000000, hold, spw);
+-
+-	nand_hw_control_init(&drvdata->hw_control);
+-
+-	platform_set_drvdata(dev, drvdata);
+-	txx9ndfmc_initialize(dev);
+-
+-	for (i = 0; i < MAX_TXX9NDFMC_DEV; i++) {
+-		struct txx9ndfmc_priv *txx9_priv;
+-		struct nand_chip *chip;
+-		struct mtd_info *mtd;
+-
+-		if (!(plat->ch_mask & (1 << i)))
+-			continue;
+-		txx9_priv = kzalloc(sizeof(struct txx9ndfmc_priv),
+-				    GFP_KERNEL);
+-		if (!txx9_priv)
+-			continue;
+-		chip = &txx9_priv->chip;
+-		mtd = nand_to_mtd(chip);
+-		mtd->dev.parent = &dev->dev;
+-
+-		chip->read_byte = txx9ndfmc_read_byte;
+-		chip->read_buf = txx9ndfmc_read_buf;
+-		chip->write_buf = txx9ndfmc_write_buf;
+-		chip->cmd_ctrl = txx9ndfmc_cmd_ctrl;
+-		chip->dev_ready = txx9ndfmc_dev_ready;
+-		chip->ecc.calculate = txx9ndfmc_calculate_ecc;
+-		chip->ecc.correct = txx9ndfmc_correct_data;
+-		chip->ecc.hwctl = txx9ndfmc_enable_hwecc;
+-		chip->ecc.mode = NAND_ECC_HW;
+-		/* txx9ndfmc_nand_scan will overwrite ecc.size and ecc.bytes */
+-		chip->ecc.size = 256;
+-		chip->ecc.bytes = 3;
+-		chip->ecc.strength = 1;
+-		chip->chip_delay = 100;
+-		chip->controller = &drvdata->hw_control;
+-
+-		nand_set_controller_data(chip, txx9_priv);
+-		txx9_priv->dev = dev;
+-
+-		if (plat->ch_mask != 1) {
+-			txx9_priv->cs = i;
+-			txx9_priv->mtdname = kasprintf(GFP_KERNEL, "%s.%u",
+-						       dev_name(&dev->dev), i);
+-		} else {
+-			txx9_priv->cs = -1;
+-			txx9_priv->mtdname = kstrdup(dev_name(&dev->dev),
+-						     GFP_KERNEL);
+-		}
+-		if (!txx9_priv->mtdname) {
+-			kfree(txx9_priv);
+-			dev_err(&dev->dev, "Unable to allocate MTD name.\n");
+-			continue;
+-		}
+-		if (plat->wide_mask & (1 << i))
+-			chip->options |= NAND_BUSWIDTH_16;
+-
+-		if (txx9ndfmc_nand_scan(mtd)) {
+-			kfree(txx9_priv->mtdname);
+-			kfree(txx9_priv);
+-			continue;
+-		}
+-		mtd->name = txx9_priv->mtdname;
+-
+-		mtd_device_parse_register(mtd, NULL, NULL, NULL, 0);
+-		drvdata->mtds[i] = mtd;
+-	}
+-
+-	return 0;
+-}
+-
+-static int __exit txx9ndfmc_remove(struct platform_device *dev)
+-{
+-	struct txx9ndfmc_drvdata *drvdata = platform_get_drvdata(dev);
+-	int i;
+-
+-	if (!drvdata)
+-		return 0;
+-	for (i = 0; i < MAX_TXX9NDFMC_DEV; i++) {
+-		struct mtd_info *mtd = drvdata->mtds[i];
+-		struct nand_chip *chip;
+-		struct txx9ndfmc_priv *txx9_priv;
+-
+-		if (!mtd)
+-			continue;
+-		chip = mtd_to_nand(mtd);
+-		txx9_priv = nand_get_controller_data(chip);
+-
+-		nand_release(mtd);
+-		kfree(txx9_priv->mtdname);
+-		kfree(txx9_priv);
+-	}
+-	return 0;
+-}
+-
+-#ifdef CONFIG_PM
+-static int txx9ndfmc_resume(struct platform_device *dev)
+-{
+-	if (platform_get_drvdata(dev))
+-		txx9ndfmc_initialize(dev);
+-	return 0;
+-}
+-#else
+-#define txx9ndfmc_resume NULL
+-#endif
+-
+-static struct platform_driver txx9ndfmc_driver = {
+-	.remove		= __exit_p(txx9ndfmc_remove),
+-	.resume		= txx9ndfmc_resume,
+-	.driver		= {
+-		.name	= "txx9ndfmc",
+-	},
+-};
+-
+-module_platform_driver_probe(txx9ndfmc_driver, txx9ndfmc_probe);
+-
+-MODULE_LICENSE("GPL");
+-MODULE_DESCRIPTION("TXx9 SoC NAND flash controller driver");
+-MODULE_ALIAS("platform:txx9ndfmc");
+diff --git a/drivers/mtd/nand/vf610_nfc.c b/drivers/mtd/nand/vf610_nfc.c
+deleted file mode 100644
+index 8037d4b..0000000
+--- a/drivers/mtd/nand/vf610_nfc.c
++++ /dev/null
+@@ -1,847 +0,0 @@
+-/*
+- * Copyright 2009-2015 Freescale Semiconductor, Inc. and others
+- *
+- * Description: MPC5125, VF610, MCF54418 and Kinetis K70 Nand driver.
+- * Jason ported to M54418TWR and MVFA5 (VF610).
+- * Authors: Stefan Agner <stefan.agner@toradex.com>
+- *          Bill Pringlemeir <bpringlemeir@nbsps.com>
+- *          Shaohui Xie <b21989@freescale.com>
+- *          Jason Jin <Jason.jin@freescale.com>
+- *
+- * Based on original driver mpc5121_nfc.c.
+- *
+- * This 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.
+- *
+- * Limitations:
+- * - Untested on MPC5125 and M54418.
+- * - DMA and pipelining not used.
+- * - 2K pages or less.
+- * - HW ECC: Only 2K page with 64+ OOB.
+- * - HW ECC: Only 24 and 32-bit error correction implemented.
+- */
+-
+-#include <linux/module.h>
+-#include <linux/bitops.h>
+-#include <linux/clk.h>
+-#include <linux/delay.h>
+-#include <linux/init.h>
+-#include <linux/interrupt.h>
+-#include <linux/io.h>
+-#include <linux/mtd/mtd.h>
+-#include <linux/mtd/rawnand.h>
+-#include <linux/mtd/partitions.h>
+-#include <linux/of_device.h>
+-#include <linux/platform_device.h>
+-#include <linux/slab.h>
+-
+-#define	DRV_NAME		"vf610_nfc"
+-
+-/* Register Offsets */
+-#define NFC_FLASH_CMD1			0x3F00
+-#define NFC_FLASH_CMD2			0x3F04
+-#define NFC_COL_ADDR			0x3F08
+-#define NFC_ROW_ADDR			0x3F0c
+-#define NFC_ROW_ADDR_INC		0x3F14
+-#define NFC_FLASH_STATUS1		0x3F18
+-#define NFC_FLASH_STATUS2		0x3F1c
+-#define NFC_CACHE_SWAP			0x3F28
+-#define NFC_SECTOR_SIZE			0x3F2c
+-#define NFC_FLASH_CONFIG		0x3F30
+-#define NFC_IRQ_STATUS			0x3F38
+-
+-/* Addresses for NFC MAIN RAM BUFFER areas */
+-#define NFC_MAIN_AREA(n)		((n) *  0x1000)
+-
+-#define PAGE_2K				0x0800
+-#define OOB_64				0x0040
+-#define OOB_MAX				0x0100
+-
+-/*
+- * NFC_CMD2[CODE] values. See section:
+- *  - 31.4.7 Flash Command Code Description, Vybrid manual
+- *  - 23.8.6 Flash Command Sequencer, MPC5125 manual
+- *
+- * Briefly these are bitmasks of controller cycles.
+- */
+-#define READ_PAGE_CMD_CODE		0x7EE0
+-#define READ_ONFI_PARAM_CMD_CODE	0x4860
+-#define PROGRAM_PAGE_CMD_CODE		0x7FC0
+-#define ERASE_CMD_CODE			0x4EC0
+-#define READ_ID_CMD_CODE		0x4804
+-#define RESET_CMD_CODE			0x4040
+-#define STATUS_READ_CMD_CODE		0x4068
+-
+-/* NFC ECC mode define */
+-#define ECC_BYPASS			0
+-#define ECC_45_BYTE			6
+-#define ECC_60_BYTE			7
+-
+-/*** Register Mask and bit definitions */
+-
+-/* NFC_FLASH_CMD1 Field */
+-#define CMD_BYTE2_MASK				0xFF000000
+-#define CMD_BYTE2_SHIFT				24
+-
+-/* NFC_FLASH_CM2 Field */
+-#define CMD_BYTE1_MASK				0xFF000000
+-#define CMD_BYTE1_SHIFT				24
+-#define CMD_CODE_MASK				0x00FFFF00
+-#define CMD_CODE_SHIFT				8
+-#define BUFNO_MASK				0x00000006
+-#define BUFNO_SHIFT				1
+-#define START_BIT				BIT(0)
+-
+-/* NFC_COL_ADDR Field */
+-#define COL_ADDR_MASK				0x0000FFFF
+-#define COL_ADDR_SHIFT				0
+-
+-/* NFC_ROW_ADDR Field */
+-#define ROW_ADDR_MASK				0x00FFFFFF
+-#define ROW_ADDR_SHIFT				0
+-#define ROW_ADDR_CHIP_SEL_RB_MASK		0xF0000000
+-#define ROW_ADDR_CHIP_SEL_RB_SHIFT		28
+-#define ROW_ADDR_CHIP_SEL_MASK			0x0F000000
+-#define ROW_ADDR_CHIP_SEL_SHIFT			24
+-
+-/* NFC_FLASH_STATUS2 Field */
+-#define STATUS_BYTE1_MASK			0x000000FF
+-
+-/* NFC_FLASH_CONFIG Field */
+-#define CONFIG_ECC_SRAM_ADDR_MASK		0x7FC00000
+-#define CONFIG_ECC_SRAM_ADDR_SHIFT		22
+-#define CONFIG_ECC_SRAM_REQ_BIT			BIT(21)
+-#define CONFIG_DMA_REQ_BIT			BIT(20)
+-#define CONFIG_ECC_MODE_MASK			0x000E0000
+-#define CONFIG_ECC_MODE_SHIFT			17
+-#define CONFIG_FAST_FLASH_BIT			BIT(16)
+-#define CONFIG_16BIT				BIT(7)
+-#define CONFIG_BOOT_MODE_BIT			BIT(6)
+-#define CONFIG_ADDR_AUTO_INCR_BIT		BIT(5)
+-#define CONFIG_BUFNO_AUTO_INCR_BIT		BIT(4)
+-#define CONFIG_PAGE_CNT_MASK			0xF
+-#define CONFIG_PAGE_CNT_SHIFT			0
+-
+-/* NFC_IRQ_STATUS Field */
+-#define IDLE_IRQ_BIT				BIT(29)
+-#define IDLE_EN_BIT				BIT(20)
+-#define CMD_DONE_CLEAR_BIT			BIT(18)
+-#define IDLE_CLEAR_BIT				BIT(17)
+-
+-/*
+- * ECC status - seems to consume 8 bytes (double word). The documented
+- * status byte is located in the lowest byte of the second word (which is
+- * the 4th or 7th byte depending on endianness).
+- * Calculate an offset to store the ECC status at the end of the buffer.
+- */
+-#define ECC_SRAM_ADDR		(PAGE_2K + OOB_MAX - 8)
+-
+-#define ECC_STATUS		0x4
+-#define ECC_STATUS_MASK		0x80
+-#define ECC_STATUS_ERR_COUNT	0x3F
+-
+-enum vf610_nfc_alt_buf {
+-	ALT_BUF_DATA = 0,
+-	ALT_BUF_ID = 1,
+-	ALT_BUF_STAT = 2,
+-	ALT_BUF_ONFI = 3,
+-};
+-
+-enum vf610_nfc_variant {
+-	NFC_VFC610 = 1,
+-};
+-
+-struct vf610_nfc {
+-	struct nand_chip chip;
+-	struct device *dev;
+-	void __iomem *regs;
+-	struct completion cmd_done;
+-	uint buf_offset;
+-	int write_sz;
+-	/* Status and ID are in alternate locations. */
+-	enum vf610_nfc_alt_buf alt_buf;
+-	enum vf610_nfc_variant variant;
+-	struct clk *clk;
+-	bool use_hw_ecc;
+-	u32 ecc_mode;
+-};
+-
+-static inline struct vf610_nfc *mtd_to_nfc(struct mtd_info *mtd)
+-{
+-	return container_of(mtd_to_nand(mtd), struct vf610_nfc, chip);
+-}
+-
+-static inline u32 vf610_nfc_read(struct vf610_nfc *nfc, uint reg)
+-{
+-	return readl(nfc->regs + reg);
+-}
+-
+-static inline void vf610_nfc_write(struct vf610_nfc *nfc, uint reg, u32 val)
+-{
+-	writel(val, nfc->regs + reg);
+-}
+-
+-static inline void vf610_nfc_set(struct vf610_nfc *nfc, uint reg, u32 bits)
+-{
+-	vf610_nfc_write(nfc, reg, vf610_nfc_read(nfc, reg) | bits);
+-}
+-
+-static inline void vf610_nfc_clear(struct vf610_nfc *nfc, uint reg, u32 bits)
+-{
+-	vf610_nfc_write(nfc, reg, vf610_nfc_read(nfc, reg) & ~bits);
+-}
+-
+-static inline void vf610_nfc_set_field(struct vf610_nfc *nfc, u32 reg,
+-				       u32 mask, u32 shift, u32 val)
+-{
+-	vf610_nfc_write(nfc, reg,
+-			(vf610_nfc_read(nfc, reg) & (~mask)) | val << shift);
+-}
+-
+-static inline void vf610_nfc_memcpy(void *dst, const void __iomem *src,
+-				    size_t n)
+-{
+-	/*
+-	 * Use this accessor for the internal SRAM buffers. On the ARM
+-	 * Freescale Vybrid SoC it's known that the driver can treat
+-	 * the SRAM buffer as if it's memory. Other platform might need
+-	 * to treat the buffers differently.
+-	 *
+-	 * For the time being, use memcpy
+-	 */
+-	memcpy(dst, src, n);
+-}
+-
+-/* Clear flags for upcoming command */
+-static inline void vf610_nfc_clear_status(struct vf610_nfc *nfc)
+-{
+-	u32 tmp = vf610_nfc_read(nfc, NFC_IRQ_STATUS);
+-
+-	tmp |= CMD_DONE_CLEAR_BIT | IDLE_CLEAR_BIT;
+-	vf610_nfc_write(nfc, NFC_IRQ_STATUS, tmp);
+-}
+-
+-static void vf610_nfc_done(struct vf610_nfc *nfc)
+-{
+-	unsigned long timeout = msecs_to_jiffies(100);
+-
+-	/*
+-	 * Barrier is needed after this write. This write need
+-	 * to be done before reading the next register the first
+-	 * time.
+-	 * vf610_nfc_set implicates such a barrier by using writel
+-	 * to write to the register.
+-	 */
+-	vf610_nfc_set(nfc, NFC_IRQ_STATUS, IDLE_EN_BIT);
+-	vf610_nfc_set(nfc, NFC_FLASH_CMD2, START_BIT);
+-
+-	if (!wait_for_completion_timeout(&nfc->cmd_done, timeout))
+-		dev_warn(nfc->dev, "Timeout while waiting for BUSY.\n");
+-
+-	vf610_nfc_clear_status(nfc);
+-}
+-
+-static u8 vf610_nfc_get_id(struct vf610_nfc *nfc, int col)
+-{
+-	u32 flash_id;
+-
+-	if (col < 4) {
+-		flash_id = vf610_nfc_read(nfc, NFC_FLASH_STATUS1);
+-		flash_id >>= (3 - col) * 8;
+-	} else {
+-		flash_id = vf610_nfc_read(nfc, NFC_FLASH_STATUS2);
+-		flash_id >>= 24;
+-	}
+-
+-	return flash_id & 0xff;
+-}
+-
+-static u8 vf610_nfc_get_status(struct vf610_nfc *nfc)
+-{
+-	return vf610_nfc_read(nfc, NFC_FLASH_STATUS2) & STATUS_BYTE1_MASK;
+-}
+-
+-static void vf610_nfc_send_command(struct vf610_nfc *nfc, u32 cmd_byte1,
+-				   u32 cmd_code)
+-{
+-	u32 tmp;
+-
+-	vf610_nfc_clear_status(nfc);
+-
+-	tmp = vf610_nfc_read(nfc, NFC_FLASH_CMD2);
+-	tmp &= ~(CMD_BYTE1_MASK | CMD_CODE_MASK | BUFNO_MASK);
+-	tmp |= cmd_byte1 << CMD_BYTE1_SHIFT;
+-	tmp |= cmd_code << CMD_CODE_SHIFT;
+-	vf610_nfc_write(nfc, NFC_FLASH_CMD2, tmp);
+-}
+-
+-static void vf610_nfc_send_commands(struct vf610_nfc *nfc, u32 cmd_byte1,
+-				    u32 cmd_byte2, u32 cmd_code)
+-{
+-	u32 tmp;
+-
+-	vf610_nfc_send_command(nfc, cmd_byte1, cmd_code);
+-
+-	tmp = vf610_nfc_read(nfc, NFC_FLASH_CMD1);
+-	tmp &= ~CMD_BYTE2_MASK;
+-	tmp |= cmd_byte2 << CMD_BYTE2_SHIFT;
+-	vf610_nfc_write(nfc, NFC_FLASH_CMD1, tmp);
+-}
+-
+-static irqreturn_t vf610_nfc_irq(int irq, void *data)
+-{
+-	struct mtd_info *mtd = data;
+-	struct vf610_nfc *nfc = mtd_to_nfc(mtd);
+-
+-	vf610_nfc_clear(nfc, NFC_IRQ_STATUS, IDLE_EN_BIT);
+-	complete(&nfc->cmd_done);
+-
+-	return IRQ_HANDLED;
+-}
+-
+-static void vf610_nfc_addr_cycle(struct vf610_nfc *nfc, int column, int page)
+-{
+-	if (column != -1) {
+-		if (nfc->chip.options & NAND_BUSWIDTH_16)
+-			column = column / 2;
+-		vf610_nfc_set_field(nfc, NFC_COL_ADDR, COL_ADDR_MASK,
+-				    COL_ADDR_SHIFT, column);
+-	}
+-	if (page != -1)
+-		vf610_nfc_set_field(nfc, NFC_ROW_ADDR, ROW_ADDR_MASK,
+-				    ROW_ADDR_SHIFT, page);
+-}
+-
+-static inline void vf610_nfc_ecc_mode(struct vf610_nfc *nfc, int ecc_mode)
+-{
+-	vf610_nfc_set_field(nfc, NFC_FLASH_CONFIG,
+-			    CONFIG_ECC_MODE_MASK,
+-			    CONFIG_ECC_MODE_SHIFT, ecc_mode);
+-}
+-
+-static inline void vf610_nfc_transfer_size(struct vf610_nfc *nfc, int size)
+-{
+-	vf610_nfc_write(nfc, NFC_SECTOR_SIZE, size);
+-}
+-
+-static void vf610_nfc_command(struct mtd_info *mtd, unsigned command,
+-			      int column, int page)
+-{
+-	struct vf610_nfc *nfc = mtd_to_nfc(mtd);
+-	int trfr_sz = nfc->chip.options & NAND_BUSWIDTH_16 ? 1 : 0;
+-
+-	nfc->buf_offset = max(column, 0);
+-	nfc->alt_buf = ALT_BUF_DATA;
+-
+-	switch (command) {
+-	case NAND_CMD_SEQIN:
+-		/* Use valid column/page from preread... */
+-		vf610_nfc_addr_cycle(nfc, column, page);
+-		nfc->buf_offset = 0;
+-
+-		/*
+-		 * SEQIN => data => PAGEPROG sequence is done by the controller
+-		 * hence we do not need to issue the command here...
+-		 */
+-		return;
+-	case NAND_CMD_PAGEPROG:
+-		trfr_sz += nfc->write_sz;
+-		vf610_nfc_transfer_size(nfc, trfr_sz);
+-		vf610_nfc_send_commands(nfc, NAND_CMD_SEQIN,
+-					command, PROGRAM_PAGE_CMD_CODE);
+-		if (nfc->use_hw_ecc)
+-			vf610_nfc_ecc_mode(nfc, nfc->ecc_mode);
+-		else
+-			vf610_nfc_ecc_mode(nfc, ECC_BYPASS);
+-		break;
+-
+-	case NAND_CMD_RESET:
+-		vf610_nfc_transfer_size(nfc, 0);
+-		vf610_nfc_send_command(nfc, command, RESET_CMD_CODE);
+-		break;
+-
+-	case NAND_CMD_READOOB:
+-		trfr_sz += mtd->oobsize;
+-		column = mtd->writesize;
+-		vf610_nfc_transfer_size(nfc, trfr_sz);
+-		vf610_nfc_send_commands(nfc, NAND_CMD_READ0,
+-					NAND_CMD_READSTART, READ_PAGE_CMD_CODE);
+-		vf610_nfc_addr_cycle(nfc, column, page);
+-		vf610_nfc_ecc_mode(nfc, ECC_BYPASS);
+-		break;
+-
+-	case NAND_CMD_READ0:
+-		trfr_sz += mtd->writesize + mtd->oobsize;
+-		vf610_nfc_transfer_size(nfc, trfr_sz);
+-		vf610_nfc_send_commands(nfc, NAND_CMD_READ0,
+-					NAND_CMD_READSTART, READ_PAGE_CMD_CODE);
+-		vf610_nfc_addr_cycle(nfc, column, page);
+-		vf610_nfc_ecc_mode(nfc, nfc->ecc_mode);
+-		break;
+-
+-	case NAND_CMD_PARAM:
+-		nfc->alt_buf = ALT_BUF_ONFI;
+-		trfr_sz = 3 * sizeof(struct nand_onfi_params);
+-		vf610_nfc_transfer_size(nfc, trfr_sz);
+-		vf610_nfc_send_command(nfc, command, READ_ONFI_PARAM_CMD_CODE);
+-		vf610_nfc_addr_cycle(nfc, -1, column);
+-		vf610_nfc_ecc_mode(nfc, ECC_BYPASS);
+-		break;
+-
+-	case NAND_CMD_ERASE1:
+-		vf610_nfc_transfer_size(nfc, 0);
+-		vf610_nfc_send_commands(nfc, command,
+-					NAND_CMD_ERASE2, ERASE_CMD_CODE);
+-		vf610_nfc_addr_cycle(nfc, column, page);
+-		break;
+-
+-	case NAND_CMD_READID:
+-		nfc->alt_buf = ALT_BUF_ID;
+-		nfc->buf_offset = 0;
+-		vf610_nfc_transfer_size(nfc, 0);
+-		vf610_nfc_send_command(nfc, command, READ_ID_CMD_CODE);
+-		vf610_nfc_addr_cycle(nfc, -1, column);
+-		break;
+-
+-	case NAND_CMD_STATUS:
+-		nfc->alt_buf = ALT_BUF_STAT;
+-		vf610_nfc_transfer_size(nfc, 0);
+-		vf610_nfc_send_command(nfc, command, STATUS_READ_CMD_CODE);
+-		break;
+-	default:
+-		return;
+-	}
+-
+-	vf610_nfc_done(nfc);
+-
+-	nfc->use_hw_ecc = false;
+-	nfc->write_sz = 0;
+-}
+-
+-static void vf610_nfc_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+-{
+-	struct vf610_nfc *nfc = mtd_to_nfc(mtd);
+-	uint c = nfc->buf_offset;
+-
+-	/* Alternate buffers are only supported through read_byte */
+-	WARN_ON(nfc->alt_buf);
+-
+-	vf610_nfc_memcpy(buf, nfc->regs + NFC_MAIN_AREA(0) + c, len);
+-
+-	nfc->buf_offset += len;
+-}
+-
+-static void vf610_nfc_write_buf(struct mtd_info *mtd, const uint8_t *buf,
+-				int len)
+-{
+-	struct vf610_nfc *nfc = mtd_to_nfc(mtd);
+-	uint c = nfc->buf_offset;
+-	uint l;
+-
+-	l = min_t(uint, len, mtd->writesize + mtd->oobsize - c);
+-	vf610_nfc_memcpy(nfc->regs + NFC_MAIN_AREA(0) + c, buf, l);
+-
+-	nfc->write_sz += l;
+-	nfc->buf_offset += l;
+-}
+-
+-static uint8_t vf610_nfc_read_byte(struct mtd_info *mtd)
+-{
+-	struct vf610_nfc *nfc = mtd_to_nfc(mtd);
+-	u8 tmp;
+-	uint c = nfc->buf_offset;
+-
+-	switch (nfc->alt_buf) {
+-	case ALT_BUF_ID:
+-		tmp = vf610_nfc_get_id(nfc, c);
+-		break;
+-	case ALT_BUF_STAT:
+-		tmp = vf610_nfc_get_status(nfc);
+-		break;
+-#ifdef __LITTLE_ENDIAN
+-	case ALT_BUF_ONFI:
+-		/* Reverse byte since the controller uses big endianness */
+-		c = nfc->buf_offset ^ 0x3;
+-		/* fall-through */
+-#endif
+-	default:
+-		tmp = *((u8 *)(nfc->regs + NFC_MAIN_AREA(0) + c));
+-		break;
+-	}
+-	nfc->buf_offset++;
+-	return tmp;
+-}
+-
+-static u16 vf610_nfc_read_word(struct mtd_info *mtd)
+-{
+-	u16 tmp;
+-
+-	vf610_nfc_read_buf(mtd, (u_char *)&tmp, sizeof(tmp));
+-	return tmp;
+-}
+-
+-/* If not provided, upper layers apply a fixed delay. */
+-static int vf610_nfc_dev_ready(struct mtd_info *mtd)
+-{
+-	/* NFC handles R/B internally; always ready.  */
+-	return 1;
+-}
+-
+-/*
+- * This function supports Vybrid only (MPC5125 would have full RB and four CS)
+- */
+-static void vf610_nfc_select_chip(struct mtd_info *mtd, int chip)
+-{
+-	struct vf610_nfc *nfc = mtd_to_nfc(mtd);
+-	u32 tmp = vf610_nfc_read(nfc, NFC_ROW_ADDR);
+-
+-	/* Vybrid only (MPC5125 would have full RB and four CS) */
+-	if (nfc->variant != NFC_VFC610)
+-		return;
+-
+-	tmp &= ~(ROW_ADDR_CHIP_SEL_RB_MASK | ROW_ADDR_CHIP_SEL_MASK);
+-
+-	if (chip >= 0) {
+-		tmp |= 1 << ROW_ADDR_CHIP_SEL_RB_SHIFT;
+-		tmp |= BIT(chip) << ROW_ADDR_CHIP_SEL_SHIFT;
+-	}
+-
+-	vf610_nfc_write(nfc, NFC_ROW_ADDR, tmp);
+-}
+-
+-/* Count the number of 0's in buff up to max_bits */
+-static inline int count_written_bits(uint8_t *buff, int size, int max_bits)
+-{
+-	uint32_t *buff32 = (uint32_t *)buff;
+-	int k, written_bits = 0;
+-
+-	for (k = 0; k < (size / 4); k++) {
+-		written_bits += hweight32(~buff32[k]);
+-		if (unlikely(written_bits > max_bits))
+-			break;
+-	}
+-
+-	return written_bits;
+-}
+-
+-static inline int vf610_nfc_correct_data(struct mtd_info *mtd, uint8_t *dat,
+-					 uint8_t *oob, int page)
+-{
+-	struct vf610_nfc *nfc = mtd_to_nfc(mtd);
+-	u32 ecc_status_off = NFC_MAIN_AREA(0) + ECC_SRAM_ADDR + ECC_STATUS;
+-	u8 ecc_status;
+-	u8 ecc_count;
+-	int flips_threshold = nfc->chip.ecc.strength / 2;
+-
+-	ecc_status = vf610_nfc_read(nfc, ecc_status_off) & 0xff;
+-	ecc_count = ecc_status & ECC_STATUS_ERR_COUNT;
+-
+-	if (!(ecc_status & ECC_STATUS_MASK))
+-		return ecc_count;
+-
+-	/* Read OOB without ECC unit enabled */
+-	vf610_nfc_command(mtd, NAND_CMD_READOOB, 0, page);
+-	vf610_nfc_read_buf(mtd, oob, mtd->oobsize);
+-
+-	/*
+-	 * On an erased page, bit count (including OOB) should be zero or
+-	 * at least less then half of the ECC strength.
+-	 */
+-	return nand_check_erased_ecc_chunk(dat, nfc->chip.ecc.size, oob,
+-					   mtd->oobsize, NULL, 0,
+-					   flips_threshold);
+-}
+-
+-static int vf610_nfc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
+-				uint8_t *buf, int oob_required, int page)
+-{
+-	int eccsize = chip->ecc.size;
+-	int stat;
+-
+-	vf610_nfc_read_buf(mtd, buf, eccsize);
+-	if (oob_required)
+-		vf610_nfc_read_buf(mtd, chip->oob_poi, mtd->oobsize);
+-
+-	stat = vf610_nfc_correct_data(mtd, buf, chip->oob_poi, page);
+-
+-	if (stat < 0) {
+-		mtd->ecc_stats.failed++;
+-		return 0;
+-	} else {
+-		mtd->ecc_stats.corrected += stat;
+-		return stat;
+-	}
+-}
+-
+-static int vf610_nfc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
+-				const uint8_t *buf, int oob_required, int page)
+-{
+-	struct vf610_nfc *nfc = mtd_to_nfc(mtd);
+-
+-	vf610_nfc_write_buf(mtd, buf, mtd->writesize);
+-	if (oob_required)
+-		vf610_nfc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
+-
+-	/* Always write whole page including OOB due to HW ECC */
+-	nfc->use_hw_ecc = true;
+-	nfc->write_sz = mtd->writesize + mtd->oobsize;
+-
+-	return 0;
+-}
+-
+-static const struct of_device_id vf610_nfc_dt_ids[] = {
+-	{ .compatible = "fsl,vf610-nfc", .data = (void *)NFC_VFC610 },
+-	{ /* sentinel */ }
+-};
+-MODULE_DEVICE_TABLE(of, vf610_nfc_dt_ids);
+-
+-static void vf610_nfc_preinit_controller(struct vf610_nfc *nfc)
+-{
+-	vf610_nfc_clear(nfc, NFC_FLASH_CONFIG, CONFIG_16BIT);
+-	vf610_nfc_clear(nfc, NFC_FLASH_CONFIG, CONFIG_ADDR_AUTO_INCR_BIT);
+-	vf610_nfc_clear(nfc, NFC_FLASH_CONFIG, CONFIG_BUFNO_AUTO_INCR_BIT);
+-	vf610_nfc_clear(nfc, NFC_FLASH_CONFIG, CONFIG_BOOT_MODE_BIT);
+-	vf610_nfc_clear(nfc, NFC_FLASH_CONFIG, CONFIG_DMA_REQ_BIT);
+-	vf610_nfc_set(nfc, NFC_FLASH_CONFIG, CONFIG_FAST_FLASH_BIT);
+-
+-	/* Disable virtual pages, only one elementary transfer unit */
+-	vf610_nfc_set_field(nfc, NFC_FLASH_CONFIG, CONFIG_PAGE_CNT_MASK,
+-			    CONFIG_PAGE_CNT_SHIFT, 1);
+-}
+-
+-static void vf610_nfc_init_controller(struct vf610_nfc *nfc)
+-{
+-	if (nfc->chip.options & NAND_BUSWIDTH_16)
+-		vf610_nfc_set(nfc, NFC_FLASH_CONFIG, CONFIG_16BIT);
+-	else
+-		vf610_nfc_clear(nfc, NFC_FLASH_CONFIG, CONFIG_16BIT);
+-
+-	if (nfc->chip.ecc.mode == NAND_ECC_HW) {
+-		/* Set ECC status offset in SRAM */
+-		vf610_nfc_set_field(nfc, NFC_FLASH_CONFIG,
+-				    CONFIG_ECC_SRAM_ADDR_MASK,
+-				    CONFIG_ECC_SRAM_ADDR_SHIFT,
+-				    ECC_SRAM_ADDR >> 3);
+-
+-		/* Enable ECC status in SRAM */
+-		vf610_nfc_set(nfc, NFC_FLASH_CONFIG, CONFIG_ECC_SRAM_REQ_BIT);
+-	}
+-}
+-
+-static int vf610_nfc_probe(struct platform_device *pdev)
+-{
+-	struct vf610_nfc *nfc;
+-	struct resource *res;
+-	struct mtd_info *mtd;
+-	struct nand_chip *chip;
+-	struct device_node *child;
+-	const struct of_device_id *of_id;
+-	int err;
+-	int irq;
+-
+-	nfc = devm_kzalloc(&pdev->dev, sizeof(*nfc), GFP_KERNEL);
+-	if (!nfc)
+-		return -ENOMEM;
+-
+-	nfc->dev = &pdev->dev;
+-	chip = &nfc->chip;
+-	mtd = nand_to_mtd(chip);
+-
+-	mtd->owner = THIS_MODULE;
+-	mtd->dev.parent = nfc->dev;
+-	mtd->name = DRV_NAME;
+-
+-	irq = platform_get_irq(pdev, 0);
+-	if (irq <= 0)
+-		return -EINVAL;
+-
+-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+-	nfc->regs = devm_ioremap_resource(nfc->dev, res);
+-	if (IS_ERR(nfc->regs))
+-		return PTR_ERR(nfc->regs);
+-
+-	nfc->clk = devm_clk_get(&pdev->dev, NULL);
+-	if (IS_ERR(nfc->clk))
+-		return PTR_ERR(nfc->clk);
+-
+-	err = clk_prepare_enable(nfc->clk);
+-	if (err) {
+-		dev_err(nfc->dev, "Unable to enable clock!\n");
+-		return err;
+-	}
+-
+-	of_id = of_match_device(vf610_nfc_dt_ids, &pdev->dev);
+-	nfc->variant = (enum vf610_nfc_variant)of_id->data;
+-
+-	for_each_available_child_of_node(nfc->dev->of_node, child) {
+-		if (of_device_is_compatible(child, "fsl,vf610-nfc-nandcs")) {
+-
+-			if (nand_get_flash_node(chip)) {
+-				dev_err(nfc->dev,
+-					"Only one NAND chip supported!\n");
+-				err = -EINVAL;
+-				goto error;
+-			}
+-
+-			nand_set_flash_node(chip, child);
+-		}
+-	}
+-
+-	if (!nand_get_flash_node(chip)) {
+-		dev_err(nfc->dev, "NAND chip sub-node missing!\n");
+-		err = -ENODEV;
+-		goto err_clk;
+-	}
+-
+-	chip->dev_ready = vf610_nfc_dev_ready;
+-	chip->cmdfunc = vf610_nfc_command;
+-	chip->read_byte = vf610_nfc_read_byte;
+-	chip->read_word = vf610_nfc_read_word;
+-	chip->read_buf = vf610_nfc_read_buf;
+-	chip->write_buf = vf610_nfc_write_buf;
+-	chip->select_chip = vf610_nfc_select_chip;
+-	chip->onfi_set_features = nand_onfi_get_set_features_notsupp;
+-	chip->onfi_get_features = nand_onfi_get_set_features_notsupp;
+-
+-	chip->options |= NAND_NO_SUBPAGE_WRITE;
+-
+-	init_completion(&nfc->cmd_done);
+-
+-	err = devm_request_irq(nfc->dev, irq, vf610_nfc_irq, 0, DRV_NAME, mtd);
+-	if (err) {
+-		dev_err(nfc->dev, "Error requesting IRQ!\n");
+-		goto error;
+-	}
+-
+-	vf610_nfc_preinit_controller(nfc);
+-
+-	/* first scan to find the device and get the page size */
+-	err = nand_scan_ident(mtd, 1, NULL);
+-	if (err)
+-		goto error;
+-
+-	vf610_nfc_init_controller(nfc);
+-
+-	/* Bad block options. */
+-	if (chip->bbt_options & NAND_BBT_USE_FLASH)
+-		chip->bbt_options |= NAND_BBT_NO_OOB;
+-
+-	/* Single buffer only, max 256 OOB minus ECC status */
+-	if (mtd->writesize + mtd->oobsize > PAGE_2K + OOB_MAX - 8) {
+-		dev_err(nfc->dev, "Unsupported flash page size\n");
+-		err = -ENXIO;
+-		goto error;
+-	}
+-
+-	if (chip->ecc.mode == NAND_ECC_HW) {
+-		if (mtd->writesize != PAGE_2K && mtd->oobsize < 64) {
+-			dev_err(nfc->dev, "Unsupported flash with hwecc\n");
+-			err = -ENXIO;
+-			goto error;
+-		}
+-
+-		if (chip->ecc.size != mtd->writesize) {
+-			dev_err(nfc->dev, "Step size needs to be page size\n");
+-			err = -ENXIO;
+-			goto error;
+-		}
+-
+-		/* Only 64 byte ECC layouts known */
+-		if (mtd->oobsize > 64)
+-			mtd->oobsize = 64;
+-
+-		/*
+-		 * mtd->ecclayout is not specified here because we're using the
+-		 * default large page ECC layout defined in NAND core.
+-		 */
+-		if (chip->ecc.strength == 32) {
+-			nfc->ecc_mode = ECC_60_BYTE;
+-			chip->ecc.bytes = 60;
+-		} else if (chip->ecc.strength == 24) {
+-			nfc->ecc_mode = ECC_45_BYTE;
+-			chip->ecc.bytes = 45;
+-		} else {
+-			dev_err(nfc->dev, "Unsupported ECC strength\n");
+-			err = -ENXIO;
+-			goto error;
+-		}
+-
+-		chip->ecc.read_page = vf610_nfc_read_page;
+-		chip->ecc.write_page = vf610_nfc_write_page;
+-
+-		chip->ecc.size = PAGE_2K;
+-	}
+-
+-	/* second phase scan */
+-	err = nand_scan_tail(mtd);
+-	if (err)
+-		goto error;
+-
+-	platform_set_drvdata(pdev, mtd);
+-
+-	/* Register device in MTD */
+-	return mtd_device_register(mtd, NULL, 0);
+-
+-error:
+-	of_node_put(nand_get_flash_node(chip));
+-err_clk:
+-	clk_disable_unprepare(nfc->clk);
+-	return err;
+-}
+-
+-static int vf610_nfc_remove(struct platform_device *pdev)
+-{
+-	struct mtd_info *mtd = platform_get_drvdata(pdev);
+-	struct vf610_nfc *nfc = mtd_to_nfc(mtd);
+-
+-	nand_release(mtd);
+-	clk_disable_unprepare(nfc->clk);
+-	return 0;
+-}
+-
+-#ifdef CONFIG_PM_SLEEP
+-static int vf610_nfc_suspend(struct device *dev)
+-{
+-	struct mtd_info *mtd = dev_get_drvdata(dev);
+-	struct vf610_nfc *nfc = mtd_to_nfc(mtd);
+-
+-	clk_disable_unprepare(nfc->clk);
+-	return 0;
+-}
+-
+-static int vf610_nfc_resume(struct device *dev)
+-{
+-	int err;
+-
+-	struct mtd_info *mtd = dev_get_drvdata(dev);
+-	struct vf610_nfc *nfc = mtd_to_nfc(mtd);
+-
+-	err = clk_prepare_enable(nfc->clk);
+-	if (err)
+-		return err;
+-
+-	vf610_nfc_preinit_controller(nfc);
+-	vf610_nfc_init_controller(nfc);
+-	return 0;
+-}
+-#endif
+-
+-static SIMPLE_DEV_PM_OPS(vf610_nfc_pm_ops, vf610_nfc_suspend, vf610_nfc_resume);
+-
+-static struct platform_driver vf610_nfc_driver = {
+-	.driver		= {
+-		.name	= DRV_NAME,
+-		.of_match_table = vf610_nfc_dt_ids,
+-		.pm	= &vf610_nfc_pm_ops,
+-	},
+-	.probe		= vf610_nfc_probe,
+-	.remove		= vf610_nfc_remove,
+-};
+-
+-module_platform_driver(vf610_nfc_driver);
+-
+-MODULE_AUTHOR("Stefan Agner <stefan.agner@toradex.com>");
+-MODULE_DESCRIPTION("Freescale VF610/MPC5125 NFC MTD NAND driver");
+-MODULE_LICENSE("GPL");
+diff --git a/drivers/mtd/nand/xway_nand.c b/drivers/mtd/nand/xway_nand.c
+deleted file mode 100644
+index 9926b4e..0000000
+--- a/drivers/mtd/nand/xway_nand.c
++++ /dev/null
+@@ -1,245 +0,0 @@
+-/*
+- *  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.
+- *
+- *  Copyright © 2012 John Crispin <john@phrozen.org>
+- *  Copyright © 2016 Hauke Mehrtens <hauke@hauke-m.de>
+- */
+-
+-#include <linux/mtd/rawnand.h>
+-#include <linux/of_gpio.h>
+-#include <linux/of_platform.h>
+-
+-#include <lantiq_soc.h>
+-
+-/* nand registers */
+-#define EBU_ADDSEL1		0x24
+-#define EBU_NAND_CON		0xB0
+-#define EBU_NAND_WAIT		0xB4
+-#define  NAND_WAIT_RD		BIT(0) /* NAND flash status output */
+-#define  NAND_WAIT_WR_C		BIT(3) /* NAND Write/Read complete */
+-#define EBU_NAND_ECC0		0xB8
+-#define EBU_NAND_ECC_AC		0xBC
+-
+-/*
+- * nand commands
+- * The pins of the NAND chip are selected based on the address bits of the
+- * "register" read and write. There are no special registers, but an
+- * address range and the lower address bits are used to activate the
+- * correct line. For example when the bit (1 << 2) is set in the address
+- * the ALE pin will be activated.
+- */
+-#define NAND_CMD_ALE		BIT(2) /* address latch enable */
+-#define NAND_CMD_CLE		BIT(3) /* command latch enable */
+-#define NAND_CMD_CS		BIT(4) /* chip select */
+-#define NAND_CMD_SE		BIT(5) /* spare area access latch */
+-#define NAND_CMD_WP		BIT(6) /* write protect */
+-#define NAND_WRITE_CMD		(NAND_CMD_CS | NAND_CMD_CLE)
+-#define NAND_WRITE_ADDR		(NAND_CMD_CS | NAND_CMD_ALE)
+-#define NAND_WRITE_DATA		(NAND_CMD_CS)
+-#define NAND_READ_DATA		(NAND_CMD_CS)
+-
+-/* we need to tel the ebu which addr we mapped the nand to */
+-#define ADDSEL1_MASK(x)		(x << 4)
+-#define ADDSEL1_REGEN		1
+-
+-/* we need to tell the EBU that we have nand attached and set it up properly */
+-#define BUSCON1_SETUP		(1 << 22)
+-#define BUSCON1_BCGEN_RES	(0x3 << 12)
+-#define BUSCON1_WAITWRC2	(2 << 8)
+-#define BUSCON1_WAITRDC2	(2 << 6)
+-#define BUSCON1_HOLDC1		(1 << 4)
+-#define BUSCON1_RECOVC1		(1 << 2)
+-#define BUSCON1_CMULT4		1
+-
+-#define NAND_CON_CE		(1 << 20)
+-#define NAND_CON_OUT_CS1	(1 << 10)
+-#define NAND_CON_IN_CS1		(1 << 8)
+-#define NAND_CON_PRE_P		(1 << 7)
+-#define NAND_CON_WP_P		(1 << 6)
+-#define NAND_CON_SE_P		(1 << 5)
+-#define NAND_CON_CS_P		(1 << 4)
+-#define NAND_CON_CSMUX		(1 << 1)
+-#define NAND_CON_NANDM		1
+-
+-struct xway_nand_data {
+-	struct nand_chip	chip;
+-	unsigned long		csflags;
+-	void __iomem		*nandaddr;
+-};
+-
+-static u8 xway_readb(struct mtd_info *mtd, int op)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct xway_nand_data *data = nand_get_controller_data(chip);
+-
+-	return readb(data->nandaddr + op);
+-}
+-
+-static void xway_writeb(struct mtd_info *mtd, int op, u8 value)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct xway_nand_data *data = nand_get_controller_data(chip);
+-
+-	writeb(value, data->nandaddr + op);
+-}
+-
+-static void xway_select_chip(struct mtd_info *mtd, int select)
+-{
+-	struct nand_chip *chip = mtd_to_nand(mtd);
+-	struct xway_nand_data *data = nand_get_controller_data(chip);
+-
+-	switch (select) {
+-	case -1:
+-		ltq_ebu_w32_mask(NAND_CON_CE, 0, EBU_NAND_CON);
+-		ltq_ebu_w32_mask(NAND_CON_NANDM, 0, EBU_NAND_CON);
+-		spin_unlock_irqrestore(&ebu_lock, data->csflags);
+-		break;
+-	case 0:
+-		spin_lock_irqsave(&ebu_lock, data->csflags);
+-		ltq_ebu_w32_mask(0, NAND_CON_NANDM, EBU_NAND_CON);
+-		ltq_ebu_w32_mask(0, NAND_CON_CE, EBU_NAND_CON);
+-		break;
+-	default:
+-		BUG();
+-	}
+-}
+-
+-static void xway_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+-{
+-	if (cmd == NAND_CMD_NONE)
+-		return;
+-
+-	if (ctrl & NAND_CLE)
+-		xway_writeb(mtd, NAND_WRITE_CMD, cmd);
+-	else if (ctrl & NAND_ALE)
+-		xway_writeb(mtd, NAND_WRITE_ADDR, cmd);
+-
+-	while ((ltq_ebu_r32(EBU_NAND_WAIT) & NAND_WAIT_WR_C) == 0)
+-		;
+-}
+-
+-static int xway_dev_ready(struct mtd_info *mtd)
+-{
+-	return ltq_ebu_r32(EBU_NAND_WAIT) & NAND_WAIT_RD;
+-}
+-
+-static unsigned char xway_read_byte(struct mtd_info *mtd)
+-{
+-	return xway_readb(mtd, NAND_READ_DATA);
+-}
+-
+-static void xway_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+-{
+-	int i;
+-
+-	for (i = 0; i < len; i++)
+-		buf[i] = xway_readb(mtd, NAND_WRITE_DATA);
+-}
+-
+-static void xway_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
+-{
+-	int i;
+-
+-	for (i = 0; i < len; i++)
+-		xway_writeb(mtd, NAND_WRITE_DATA, buf[i]);
+-}
+-
+-/*
+- * Probe for the NAND device.
+- */
+-static int xway_nand_probe(struct platform_device *pdev)
+-{
+-	struct xway_nand_data *data;
+-	struct mtd_info *mtd;
+-	struct resource *res;
+-	int err;
+-	u32 cs;
+-	u32 cs_flag = 0;
+-
+-	/* Allocate memory for the device structure (and zero it) */
+-	data = devm_kzalloc(&pdev->dev, sizeof(struct xway_nand_data),
+-			    GFP_KERNEL);
+-	if (!data)
+-		return -ENOMEM;
+-
+-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+-	data->nandaddr = devm_ioremap_resource(&pdev->dev, res);
+-	if (IS_ERR(data->nandaddr))
+-		return PTR_ERR(data->nandaddr);
+-
+-	nand_set_flash_node(&data->chip, pdev->dev.of_node);
+-	mtd = nand_to_mtd(&data->chip);
+-	mtd->dev.parent = &pdev->dev;
+-
+-	data->chip.cmd_ctrl = xway_cmd_ctrl;
+-	data->chip.dev_ready = xway_dev_ready;
+-	data->chip.select_chip = xway_select_chip;
+-	data->chip.write_buf = xway_write_buf;
+-	data->chip.read_buf = xway_read_buf;
+-	data->chip.read_byte = xway_read_byte;
+-	data->chip.chip_delay = 30;
+-
+-	data->chip.ecc.mode = NAND_ECC_SOFT;
+-	data->chip.ecc.algo = NAND_ECC_HAMMING;
+-
+-	platform_set_drvdata(pdev, data);
+-	nand_set_controller_data(&data->chip, data);
+-
+-	/* load our CS from the DT. Either we find a valid 1 or default to 0 */
+-	err = of_property_read_u32(pdev->dev.of_node, "lantiq,cs", &cs);
+-	if (!err && cs == 1)
+-		cs_flag = NAND_CON_IN_CS1 | NAND_CON_OUT_CS1;
+-
+-	/* setup the EBU to run in NAND mode on our base addr */
+-	ltq_ebu_w32(CPHYSADDR(data->nandaddr)
+-		    | ADDSEL1_MASK(3) | ADDSEL1_REGEN, EBU_ADDSEL1);
+-
+-	ltq_ebu_w32(BUSCON1_SETUP | BUSCON1_BCGEN_RES | BUSCON1_WAITWRC2
+-		    | BUSCON1_WAITRDC2 | BUSCON1_HOLDC1 | BUSCON1_RECOVC1
+-		    | BUSCON1_CMULT4, LTQ_EBU_BUSCON1);
+-
+-	ltq_ebu_w32(NAND_CON_NANDM | NAND_CON_CSMUX | NAND_CON_CS_P
+-		    | NAND_CON_SE_P | NAND_CON_WP_P | NAND_CON_PRE_P
+-		    | cs_flag, EBU_NAND_CON);
+-
+-	/* 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;
+-}
+-
+-/*
+- * Remove a NAND device.
+- */
+-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));
+-
+-	return 0;
+-}
+-
+-static const struct of_device_id xway_nand_match[] = {
+-	{ .compatible = "lantiq,nand-xway" },
+-	{},
+-};
+-
+-static struct platform_driver xway_nand_driver = {
+-	.probe	= xway_nand_probe,
+-	.remove	= xway_nand_remove,
+-	.driver	= {
+-		.name		= "lantiq,nand-xway",
+-		.of_match_table = xway_nand_match,
+-	},
+-};
+-
+-builtin_platform_driver(xway_nand_driver);
+-- 
+2.7.4
+
diff --git a/recipes-kernel/linux/linux-stm32mp/patches/0015-mtd-nand-Add-core-infrastructure-to-deal-with-NAND-d.patch b/recipes-kernel/linux/linux-stm32mp/patches/0015-mtd-nand-Add-core-infrastructure-to-deal-with-NAND-d.patch
new file mode 100644
index 0000000000000000000000000000000000000000..4a2e7e9066b8f44dfbc3fe553c7b8f239e8af54e
--- /dev/null
+++ b/recipes-kernel/linux/linux-stm32mp/patches/0015-mtd-nand-Add-core-infrastructure-to-deal-with-NAND-d.patch
@@ -0,0 +1,1169 @@
+From cfa4f3f955c311de3c3e9692f91e2ccabb054bcc Mon Sep 17 00:00:00 2001
+From: Boris Brezillon <boris.brezillon@bootlin.com>
+Date: Mon, 5 Feb 2018 23:02:05 +0100
+Subject: [PATCH 15/28] mtd: nand: Add core infrastructure to deal with NAND
+ devices
+
+Add an intermediate layer to abstract NAND device interface so that
+some logic can be shared between SPI NANDs, parallel/raw NANDs,
+OneNANDs, ...
+
+Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
+---
+ drivers/mtd/nand/Kconfig  |   3 +
+ drivers/mtd/nand/Makefile |   3 +
+ drivers/mtd/nand/bbt.c    | 130 +++++++++
+ drivers/mtd/nand/core.c   | 244 ++++++++++++++++
+ include/linux/mtd/nand.h  | 731 ++++++++++++++++++++++++++++++++++++++++++++++
+ 5 files changed, 1111 insertions(+)
+ create mode 100644 drivers/mtd/nand/bbt.c
+ create mode 100644 drivers/mtd/nand/core.c
+ create mode 100644 include/linux/mtd/nand.h
+
+diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
+index 6d53734..1c1a1f4 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 f168a5b..f749ec7 100644
+--- a/drivers/mtd/nand/Makefile
++++ b/drivers/mtd/nand/Makefile
+@@ -3,4 +3,7 @@
+ # linux/drivers/nand/Makefile
+ #
+ 
++nandcore-objs := core.o bbt.o
++obj-$(CONFIG_MTD_NAND_CORE) += nandcore.o
++
+ obj-y	+= raw/
+diff --git a/drivers/mtd/nand/bbt.c b/drivers/mtd/nand/bbt.c
+new file mode 100644
+index 0000000..56cde38
+--- /dev/null
++++ b/drivers/mtd/nand/bbt.c
+@@ -0,0 +1,130 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (c) 2017 Free Electrons
++ *
++ * Authors:
++ *	Boris Brezillon <boris.brezillon@free-electrons.com>
++ *	Peter Pan <peterpandong@micron.com>
++ */
++
++#define pr_fmt(fmt)	"nand-bbt: " fmt
++
++#include <linux/mtd/nand.h>
++#include <linux/slab.h>
++
++/**
++ * nanddev_bbt_init() - Initialize the BBT (Bad Block Table)
++ * @nand: NAND device
++ *
++ * Initialize the in-memory BBT.
++ *
++ * Return: 0 in case of success, a negative error code otherwise.
++ */
++int nanddev_bbt_init(struct nand_device *nand)
++{
++	unsigned int bits_per_block = fls(NAND_BBT_BLOCK_NUM_STATUS);
++	unsigned int nblocks = nanddev_neraseblocks(nand);
++	unsigned int nwords = DIV_ROUND_UP(nblocks * bits_per_block,
++					   BITS_PER_LONG);
++
++	nand->bbt.cache = kzalloc(nwords, GFP_KERNEL);
++	if (!nand->bbt.cache)
++		return -ENOMEM;
++
++	return 0;
++}
++EXPORT_SYMBOL_GPL(nanddev_bbt_init);
++
++/**
++ * nanddev_bbt_cleanup() - Cleanup the BBT (Bad Block Table)
++ * @nand: NAND device
++ *
++ * Undoes what has been done in nanddev_bbt_init()
++ */
++void nanddev_bbt_cleanup(struct nand_device *nand)
++{
++	kfree(nand->bbt.cache);
++}
++EXPORT_SYMBOL_GPL(nanddev_bbt_cleanup);
++
++/**
++ * nanddev_bbt_update() - Update a BBT
++ * @nand: nand device
++ *
++ * Update the BBT. Currently a NOP function since on-flash bbt is not yet
++ * supported.
++ *
++ * Return: 0 in case of success, a negative error code otherwise.
++ */
++int nanddev_bbt_update(struct nand_device *nand)
++{
++	return 0;
++}
++EXPORT_SYMBOL_GPL(nanddev_bbt_update);
++
++/**
++ * nanddev_bbt_get_block_status() - Return the status of an eraseblock
++ * @nand: nand device
++ * @entry: the BBT entry
++ *
++ * Return: a positive number nand_bbt_block_status status or -%ERANGE if @entry
++ *	   is bigger than the BBT size.
++ */
++int nanddev_bbt_get_block_status(const struct nand_device *nand,
++				 unsigned int entry)
++{
++	unsigned int bits_per_block = fls(NAND_BBT_BLOCK_NUM_STATUS);
++	unsigned long *pos = nand->bbt.cache +
++			     ((entry * bits_per_block) / BITS_PER_LONG);
++	unsigned int offs = (entry * bits_per_block) % BITS_PER_LONG;
++	unsigned long status;
++
++	if (entry >= nanddev_neraseblocks(nand))
++		return -ERANGE;
++
++	status = pos[0] >> offs;
++	if (bits_per_block + offs > BITS_PER_LONG)
++		status |= pos[1] << (BITS_PER_LONG - offs);
++
++	return status & GENMASK(bits_per_block - 1, 0);
++}
++EXPORT_SYMBOL_GPL(nanddev_bbt_get_block_status);
++
++/**
++ * nanddev_bbt_set_block_status() - Update the status of an eraseblock in the
++ *				    in-memory BBT
++ * @nand: nand device
++ * @entry: the BBT entry to update
++ * @status: the new status
++ *
++ * Update an entry of the in-memory BBT. If you want to push the updated BBT
++ * the NAND you should call nanddev_bbt_update().
++ *
++ * Return: 0 in case of success or -%ERANGE if @entry is bigger than the BBT
++ *	   size.
++ */
++int nanddev_bbt_set_block_status(struct nand_device *nand, unsigned int entry,
++				 enum nand_bbt_block_status status)
++{
++	unsigned int bits_per_block = fls(NAND_BBT_BLOCK_NUM_STATUS);
++	unsigned long *pos = nand->bbt.cache +
++			     ((entry * bits_per_block) / BITS_PER_LONG);
++	unsigned int offs = (entry * bits_per_block) % BITS_PER_LONG;
++	unsigned long val = status & GENMASK(bits_per_block - 1, 0);
++
++	if (entry >= nanddev_neraseblocks(nand))
++		return -ERANGE;
++
++	pos[0] &= ~GENMASK(offs + bits_per_block - 1, offs);
++	pos[0] |= val << offs;
++
++	if (bits_per_block + offs > BITS_PER_LONG) {
++		unsigned int rbits = bits_per_block + offs - BITS_PER_LONG;
++
++		pos[1] &= ~GENMASK(rbits - 1, 0);
++		pos[1] |= val >> rbits;
++	}
++
++	return 0;
++}
++EXPORT_SYMBOL_GPL(nanddev_bbt_set_block_status);
+diff --git a/drivers/mtd/nand/core.c b/drivers/mtd/nand/core.c
+new file mode 100644
+index 0000000..f237a68
+--- /dev/null
++++ b/drivers/mtd/nand/core.c
+@@ -0,0 +1,244 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (c) 2017 Free Electrons
++ *
++ * Authors:
++ *	Boris Brezillon <boris.brezillon@free-electrons.com>
++ *	Peter Pan <peterpandong@micron.com>
++ */
++
++#define pr_fmt(fmt)	"nand: " fmt
++
++#include <linux/module.h>
++#include <linux/mtd/nand.h>
++
++/**
++ * nanddev_isbad() - Check if a block is bad
++ * @nand: NAND device
++ * @pos: position pointing to the block we want to check
++ *
++ * Return: true if the block is bad, false otherwise.
++ */
++bool nanddev_isbad(struct nand_device *nand, const struct nand_pos *pos)
++{
++	if (nanddev_bbt_is_initialized(nand)) {
++		unsigned int entry;
++		int status;
++
++		entry = nanddev_bbt_pos_to_entry(nand, pos);
++		status = nanddev_bbt_get_block_status(nand, entry);
++		/* Lazy block status retrieval */
++		if (status == NAND_BBT_BLOCK_STATUS_UNKNOWN) {
++			if (nand->ops->isbad(nand, pos))
++				status = NAND_BBT_BLOCK_FACTORY_BAD;
++			else
++				status = NAND_BBT_BLOCK_GOOD;
++
++			nanddev_bbt_set_block_status(nand, entry, status);
++		}
++
++		if (status == NAND_BBT_BLOCK_WORN ||
++		    status == NAND_BBT_BLOCK_FACTORY_BAD)
++			return true;
++
++		return false;
++	}
++
++	return nand->ops->isbad(nand, pos);
++}
++EXPORT_SYMBOL_GPL(nanddev_isbad);
++
++/**
++ * nanddev_markbad() - Mark a block as bad
++ * @nand: NAND device
++ * @block: block to mark bad
++ *
++ * Mark a block bad. This function is updating the BBT if available and
++ * calls the low-level markbad hook (nand->ops->markbad()).
++ *
++ * Return: 0 in case of success, a negative error code otherwise.
++ */
++int nanddev_markbad(struct nand_device *nand, const struct nand_pos *pos)
++{
++	struct mtd_info *mtd = nanddev_to_mtd(nand);
++	unsigned int entry;
++	int ret = 0;
++
++	if (nanddev_isbad(nand, pos))
++		return 0;
++
++	ret = nand->ops->markbad(nand, pos);
++	if (ret)
++		pr_warn("failed to write BBM to block @%llx (err = %d)\n",
++			nanddev_pos_to_offs(nand, pos), ret);
++
++	if (!nanddev_bbt_is_initialized(nand))
++		goto out;
++
++	entry = nanddev_bbt_pos_to_entry(nand, pos);
++	ret = nanddev_bbt_set_block_status(nand, entry, NAND_BBT_BLOCK_WORN);
++	if (ret)
++		goto out;
++
++	ret = nanddev_bbt_update(nand);
++
++out:
++	if (!ret)
++		mtd->ecc_stats.badblocks++;
++
++	return ret;
++}
++EXPORT_SYMBOL_GPL(nanddev_markbad);
++
++/**
++ * nanddev_isreserved() - Check whether an eraseblock is reserved or not
++ * @nand: NAND device
++ * @pos: NAND position to test
++ *
++ * Checks whether the eraseblock pointed by @pos is reserved or not.
++ *
++ * Return: true if the eraseblock is reserved, false otherwise.
++ */
++bool nanddev_isreserved(struct nand_device *nand, const struct nand_pos *pos)
++{
++	unsigned int entry;
++	int status;
++
++	if (!nanddev_bbt_is_initialized(nand))
++		return false;
++
++	/* Return info from the table */
++	entry = nanddev_bbt_pos_to_entry(nand, pos);
++	status = nanddev_bbt_get_block_status(nand, entry);
++	return status == NAND_BBT_BLOCK_RESERVED;
++}
++EXPORT_SYMBOL_GPL(nanddev_isreserved);
++
++/**
++ * nanddev_erase() - Erase a NAND portion
++ * @nand: NAND device
++ * @block: eraseblock to erase
++ *
++ * Erases @block if it's not bad.
++ *
++ * Return: 0 in case of success, a negative error code otherwise.
++ */
++int nanddev_erase(struct nand_device *nand, const struct nand_pos *pos)
++{
++	if (nanddev_isbad(nand, pos) || nanddev_isreserved(nand, pos)) {
++		pr_warn("attempt to erase a bad/reserved block @%llx\n",
++			nanddev_pos_to_offs(nand, pos));
++		return -EIO;
++	}
++
++	return nand->ops->erase(nand, pos);
++}
++EXPORT_SYMBOL_GPL(nanddev_erase);
++
++/**
++ * nanddev_mtd_erase() - Generic mtd->_erase() implementation for NAND devices
++ * @mtd: MTD device
++ * @einfo: erase request
++ *
++ * This is a simple mtd->_erase() implementation iterating over all blocks
++ * concerned by @einfo and calling nand->ops->erase() on each of them.
++ *
++ * Note that mtd->_erase should not be directly assigned to this helper,
++ * because there's no locking here. NAND specialized layers should instead
++ * implement there own wrapper around nanddev_mtd_erase() taking the
++ * appropriate lock before calling nanddev_mtd_erase().
++ *
++ * Return: 0 in case of success, a negative error code otherwise.
++ */
++int nanddev_mtd_erase(struct mtd_info *mtd, struct erase_info *einfo)
++{
++	struct nand_device *nand = mtd_to_nanddev(mtd);
++	struct nand_pos pos, last;
++	int ret;
++
++	nanddev_offs_to_pos(nand, einfo->addr, &pos);
++	nanddev_offs_to_pos(nand, einfo->addr + einfo->len - 1, &last);
++	while (nanddev_pos_cmp(&pos, &last) <= 0) {
++		ret = nanddev_erase(nand, &pos);
++		if (ret) {
++			einfo->fail_addr = nanddev_pos_to_offs(nand, &pos);
++			einfo->state = MTD_ERASE_FAILED;
++
++			return ret;
++		}
++
++		nanddev_pos_next_eraseblock(nand, &pos);
++	}
++
++	einfo->state = MTD_ERASE_DONE;
++
++	return 0;
++}
++EXPORT_SYMBOL_GPL(nanddev_mtd_erase);
++
++/**
++ * nanddev_init() - Initialize a NAND device
++ * @nand: NAND device
++ * @memorg: NAND memory organization descriptor
++ * @ops: NAND device operations
++ *
++ * Initializes a NAND device object. Consistency checks are done on @memorg and
++ * @ops. Also takes care of initializing the BBT.
++ *
++ * Return: 0 in case of success, a negative error code otherwise.
++ */
++int nanddev_init(struct nand_device *nand, const struct nand_ops *ops,
++		 struct module *owner)
++{
++	struct mtd_info *mtd = nanddev_to_mtd(nand);
++	struct nand_memory_organization *memorg = nanddev_get_memorg(nand);
++
++	if (!nand || !ops)
++		return -EINVAL;
++
++	if (!ops->erase || !ops->markbad || !ops->isbad)
++		return -EINVAL;
++
++	if (!memorg->bits_per_cell || !memorg->pagesize ||
++	    !memorg->pages_per_eraseblock || !memorg->eraseblocks_per_lun ||
++	    !memorg->planes_per_lun || !memorg->luns_per_target ||
++	    !memorg->ntargets)
++		return -EINVAL;
++
++	nand->rowconv.eraseblock_addr_shift =
++					fls(memorg->pages_per_eraseblock - 1);
++	nand->rowconv.lun_addr_shift = fls(memorg->eraseblocks_per_lun - 1) +
++				       nand->rowconv.eraseblock_addr_shift;
++
++	nand->ops = ops;
++
++	mtd->type = memorg->bits_per_cell == 1 ?
++		    MTD_NANDFLASH : MTD_MLCNANDFLASH;
++	mtd->flags = MTD_CAP_NANDFLASH;
++	mtd->erasesize = memorg->pagesize * memorg->pages_per_eraseblock;
++	mtd->writesize = memorg->pagesize;
++	mtd->writebufsize = memorg->pagesize;
++	mtd->oobsize = memorg->oobsize;
++	mtd->size = nanddev_size(nand);
++	mtd->owner = owner;
++
++	return nanddev_bbt_init(nand);
++}
++EXPORT_SYMBOL_GPL(nanddev_init);
++
++/**
++ * nanddev_cleanup() - Release resources allocated in nanddev_init()
++ * @nand: NAND device
++ *
++ * Basically undoes what has been done in nanddev_init().
++ */
++void nanddev_cleanup(struct nand_device *nand)
++{
++	if (nanddev_bbt_is_initialized(nand))
++		nanddev_bbt_cleanup(nand);
++}
++EXPORT_SYMBOL_GPL(nanddev_cleanup);
++
++MODULE_DESCRIPTION("Generic NAND framework");
++MODULE_AUTHOR("Boris Brezillon <boris.brezillon@free-electrons.com>");
++MODULE_LICENSE("GPL v2");
+diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
+new file mode 100644
+index 0000000..792ea5c
+--- /dev/null
++++ b/include/linux/mtd/nand.h
+@@ -0,0 +1,731 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ *  Copyright 2017 - Free Electrons
++ *
++ *  Authors:
++ *	Boris Brezillon <boris.brezillon@free-electrons.com>
++ *	Peter Pan <peterpandong@micron.com>
++ */
++
++#ifndef __LINUX_MTD_NAND_H
++#define __LINUX_MTD_NAND_H
++
++#include <linux/mtd/mtd.h>
++
++/**
++ * struct nand_memory_organization - Memory organization structure
++ * @bits_per_cell: number of bits per NAND cell
++ * @pagesize: page size
++ * @oobsize: OOB area size
++ * @pages_per_eraseblock: number of pages per eraseblock
++ * @eraseblocks_per_lun: number of eraseblocks per LUN (Logical Unit Number)
++ * @planes_per_lun: number of planes per LUN
++ * @luns_per_target: number of LUN per target (target is a synonym for die)
++ * @ntargets: total number of targets exposed by the NAND device
++ */
++struct nand_memory_organization {
++	unsigned int bits_per_cell;
++	unsigned int pagesize;
++	unsigned int oobsize;
++	unsigned int pages_per_eraseblock;
++	unsigned int eraseblocks_per_lun;
++	unsigned int planes_per_lun;
++	unsigned int luns_per_target;
++	unsigned int ntargets;
++};
++
++#define NAND_MEMORG(bpc, ps, os, ppe, epl, ppl, lpt, nt)	\
++	{							\
++		.bits_per_cell = (bpc),				\
++		.pagesize = (ps),				\
++		.oobsize = (os),				\
++		.pages_per_eraseblock = (ppe),			\
++		.eraseblocks_per_lun = (epl),			\
++		.planes_per_lun = (ppl),			\
++		.luns_per_target = (lpt),			\
++		.ntargets = (nt),				\
++	}
++
++/**
++ * struct nand_row_converter - Information needed to convert an absolute offset
++ *			       into a row address
++ * @lun_addr_shift: position of the LUN identifier in the row address
++ * @eraseblock_addr_shift: position of the eraseblock identifier in the row
++ *			   address
++ */
++struct nand_row_converter {
++	unsigned int lun_addr_shift;
++	unsigned int eraseblock_addr_shift;
++};
++
++/**
++ * struct nand_pos - NAND position object
++ * @target: the NAND target/die
++ * @lun: the LUN identifier
++ * @plane: the plane within the LUN
++ * @eraseblock: the eraseblock within the LUN
++ * @page: the page within the LUN
++ *
++ * These information are usually used by specific sub-layers to select the
++ * appropriate target/die and generate a row address to pass to the device.
++ */
++struct nand_pos {
++	unsigned int target;
++	unsigned int lun;
++	unsigned int plane;
++	unsigned int eraseblock;
++	unsigned int page;
++};
++
++/**
++ * struct nand_page_io_req - NAND I/O request object
++ * @pos: the position this I/O request is targeting
++ * @dataoffs: the offset within the page
++ * @datalen: number of data bytes to read from/write to this page
++ * @databuf: buffer to store data in or get data from
++ * @ooboffs: the OOB offset within the page
++ * @ooblen: the number of OOB bytes to read from/write to this page
++ * @oobbuf: buffer to store OOB data in or get OOB data from
++ *
++ * This object is used to pass per-page I/O requests to NAND sub-layers. This
++ * way all useful information are already formatted in a useful way and
++ * specific NAND layers can focus on translating these information into
++ * specific commands/operations.
++ */
++struct nand_page_io_req {
++	struct nand_pos pos;
++	unsigned int dataoffs;
++	unsigned int datalen;
++	union {
++		const void *out;
++		void *in;
++	} databuf;
++	unsigned int ooboffs;
++	unsigned int ooblen;
++	union {
++		const void *out;
++		void *in;
++	} oobbuf;
++};
++
++/**
++ * struct nand_ecc_req - NAND ECC requirements
++ * @strength: ECC strength
++ * @step_size: ECC step/block size
++ */
++struct nand_ecc_req {
++	unsigned int strength;
++	unsigned int step_size;
++};
++
++#define NAND_ECCREQ(str, stp) { .strength = (str), .step_size = (stp) }
++
++/**
++ * struct nand_bbt - bad block table object
++ * @cache: in memory BBT cache
++ */
++struct nand_bbt {
++	unsigned long *cache;
++};
++
++struct nand_device;
++
++/**
++ * struct nand_ops - NAND operations
++ * @erase: erase a specific block. No need to check if the block is bad before
++ *	   erasing, this has been taken care of by the generic NAND layer
++ * @markbad: mark a specific block bad. No need to check if the block is
++ *	     already marked bad, this has been taken care of by the generic
++ *	     NAND layer. This method should just write the BBM (Bad Block
++ *	     Marker) so that future call to struct_nand_ops->isbad() return
++ *	     true
++ * @isbad: check whether a block is bad or not. This method should just read
++ *	   the BBM and return whether the block is bad or not based on what it
++ *	   reads
++ *
++ * These are all low level operations that should be implemented by specialized
++ * NAND layers (SPI NAND, raw NAND, ...).
++ */
++struct nand_ops {
++	int (*erase)(struct nand_device *nand, const struct nand_pos *pos);
++	int (*markbad)(struct nand_device *nand, const struct nand_pos *pos);
++	bool (*isbad)(struct nand_device *nand, const struct nand_pos *pos);
++};
++
++/**
++ * struct nand_device - NAND device
++ * @mtd: MTD instance attached to the NAND device
++ * @memorg: memory layout
++ * @eccreq: ECC requirements
++ * @rowconv: position to row address converter
++ * @bbt: bad block table info
++ * @ops: NAND operations attached to the NAND device
++ *
++ * Generic NAND object. Specialized NAND layers (raw NAND, SPI NAND, OneNAND)
++ * should declare their own NAND object embedding a nand_device struct (that's
++ * how inheritance is done).
++ * struct_nand_device->memorg and struct_nand_device->eccreq should be filled
++ * at device detection time to reflect the NAND device
++ * capabilities/requirements. Once this is done nanddev_init() can be called.
++ * It will take care of converting NAND information into MTD ones, which means
++ * the specialized NAND layers should never manually tweak
++ * struct_nand_device->mtd except for the ->_read/write() hooks.
++ */
++struct nand_device {
++	struct mtd_info mtd;
++	struct nand_memory_organization memorg;
++	struct nand_ecc_req eccreq;
++	struct nand_row_converter rowconv;
++	struct nand_bbt bbt;
++	const struct nand_ops *ops;
++};
++
++/**
++ * struct nand_io_iter - NAND I/O iterator
++ * @req: current I/O request
++ * @oobbytes_per_page: maximum number of OOB bytes per page
++ * @dataleft: remaining number of data bytes to read/write
++ * @oobleft: remaining number of OOB bytes to read/write
++ *
++ * Can be used by specialized NAND layers to iterate over all pages covered
++ * by an MTD I/O request, which should greatly simplifies the boiler-plate
++ * code needed to read/write data from/to a NAND device.
++ */
++struct nand_io_iter {
++	struct nand_page_io_req req;
++	unsigned int oobbytes_per_page;
++	unsigned int dataleft;
++	unsigned int oobleft;
++};
++
++/**
++ * mtd_to_nanddev() - Get the NAND device attached to the MTD instance
++ * @mtd: MTD instance
++ *
++ * Return: the NAND device embedding @mtd.
++ */
++static inline struct nand_device *mtd_to_nanddev(struct mtd_info *mtd)
++{
++	return container_of(mtd, struct nand_device, mtd);
++}
++
++/**
++ * nanddev_to_mtd() - Get the MTD device attached to a NAND device
++ * @nand: NAND device
++ *
++ * Return: the MTD device embedded in @nand.
++ */
++static inline struct mtd_info *nanddev_to_mtd(struct nand_device *nand)
++{
++	return &nand->mtd;
++}
++
++/*
++ * nanddev_bits_per_cell() - Get the number of bits per cell
++ * @nand: NAND device
++ *
++ * Return: the number of bits per cell.
++ */
++static inline unsigned int nanddev_bits_per_cell(const struct nand_device *nand)
++{
++	return nand->memorg.bits_per_cell;
++}
++
++/**
++ * nanddev_page_size() - Get NAND page size
++ * @nand: NAND device
++ *
++ * Return: the page size.
++ */
++static inline size_t nanddev_page_size(const struct nand_device *nand)
++{
++	return nand->memorg.pagesize;
++}
++
++/**
++ * nanddev_per_page_oobsize() - Get NAND OOB size
++ * @nand: NAND device
++ *
++ * Return: the OOB size.
++ */
++static inline unsigned int
++nanddev_per_page_oobsize(const struct nand_device *nand)
++{
++	return nand->memorg.oobsize;
++}
++
++/**
++ * nanddev_pages_per_eraseblock() - Get the number of pages per eraseblock
++ * @nand: NAND device
++ *
++ * Return: the number of pages per eraseblock.
++ */
++static inline unsigned int
++nanddev_pages_per_eraseblock(const struct nand_device *nand)
++{
++	return nand->memorg.pages_per_eraseblock;
++}
++
++/**
++ * nanddev_per_page_oobsize() - Get NAND erase block size
++ * @nand: NAND device
++ *
++ * Return: the eraseblock size.
++ */
++static inline size_t nanddev_eraseblock_size(const struct nand_device *nand)
++{
++	return nand->memorg.pagesize * nand->memorg.pages_per_eraseblock;
++}
++
++/**
++ * nanddev_eraseblocks_per_lun() - Get the number of eraseblocks per LUN
++ * @nand: NAND device
++ *
++ * Return: the number of eraseblocks per LUN.
++ */
++static inline unsigned int
++nanddev_eraseblocks_per_lun(const struct nand_device *nand)
++{
++	return nand->memorg.eraseblocks_per_lun;
++}
++
++/**
++ * nanddev_target_size() - Get the total size provided by a single target/die
++ * @nand: NAND device
++ *
++ * Return: the total size exposed by a single target/die in bytes.
++ */
++static inline u64 nanddev_target_size(const struct nand_device *nand)
++{
++	return (u64)nand->memorg.luns_per_target *
++	       nand->memorg.eraseblocks_per_lun *
++	       nand->memorg.pages_per_eraseblock *
++	       nand->memorg.pagesize;
++}
++
++/**
++ * nanddev_ntarget() - Get the total of targets
++ * @nand: NAND device
++ *
++ * Return: the number of targets/dies exposed by @nand.
++ */
++static inline unsigned int nanddev_ntargets(const struct nand_device *nand)
++{
++	return nand->memorg.ntargets;
++}
++
++/**
++ * nanddev_neraseblocks() - Get the total number of erasablocks
++ * @nand: NAND device
++ *
++ * Return: the total number of eraseblocks exposed by @nand.
++ */
++static inline unsigned int nanddev_neraseblocks(const struct nand_device *nand)
++{
++	return (u64)nand->memorg.luns_per_target *
++	       nand->memorg.eraseblocks_per_lun *
++	       nand->memorg.pages_per_eraseblock;
++}
++
++/**
++ * nanddev_size() - Get NAND size
++ * @nand: NAND device
++ *
++ * Return: the total size (in bytes) exposed by @nand.
++ */
++static inline u64 nanddev_size(const struct nand_device *nand)
++{
++	return nanddev_target_size(nand) * nanddev_ntargets(nand);
++}
++
++/**
++ * nanddev_get_memorg() - Extract memory organization info from a NAND device
++ * @nand: NAND device
++ *
++ * This can be used by the upper layer to fill the memorg info before calling
++ * nanddev_init().
++ *
++ * Return: the memorg object embedded in the NAND device.
++ */
++static inline struct nand_memory_organization *
++nanddev_get_memorg(struct nand_device *nand)
++{
++	return &nand->memorg;
++}
++
++int nanddev_init(struct nand_device *nand, const struct nand_ops *ops,
++		 struct module *owner);
++void nanddev_cleanup(struct nand_device *nand);
++
++/**
++ * nanddev_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 embedded in @nand.
++ *
++ * Return: 0 in case of success, a negative error code otherwise.
++ */
++static inline int nanddev_register(struct nand_device *nand)
++{
++	return mtd_device_register(&nand->mtd, NULL, 0);
++}
++
++/**
++ * nanddev_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 embedded in @nand.
++ *
++ * Return: 0 in case of success, a negative error code otherwise.
++ */
++static inline int nanddev_unregister(struct nand_device *nand)
++{
++	return mtd_device_unregister(&nand->mtd);
++}
++
++/**
++ * nanddev_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 nanddev_set_of_node(struct nand_device *nand,
++				       struct device_node *np)
++{
++	mtd_set_of_node(&nand->mtd, np);
++}
++
++/**
++ * nanddev_get_of_node() - Retrieve the DT node attached to a NAND device
++ * @nand: NAND device
++ *
++ * Return: the DT node attached to @nand.
++ */
++static inline struct device_node *nanddev_get_of_node(struct nand_device *nand)
++{
++	return mtd_get_of_node(&nand->mtd);
++}
++
++/**
++ * nanddev_offs_to_pos() - Convert an absolute NAND offset into a NAND position
++ * @nand: NAND device
++ * @offs: absolute NAND offset (usually passed by the MTD layer)
++ * @pos: a NAND position object to fill in
++ *
++ * Converts @offs into a nand_pos representation.
++ *
++ * Return: the offset within the NAND page pointed by @pos.
++ */
++static inline unsigned int nanddev_offs_to_pos(struct nand_device *nand,
++					       loff_t offs,
++					       struct nand_pos *pos)
++{
++	unsigned int pageoffs;
++	u64 tmp = offs;
++
++	pageoffs = do_div(tmp, nand->memorg.pagesize);
++	pos->page = do_div(tmp, nand->memorg.pages_per_eraseblock);
++	pos->eraseblock = do_div(tmp, nand->memorg.eraseblocks_per_lun);
++	pos->plane = pos->eraseblock % nand->memorg.planes_per_lun;
++	pos->lun = do_div(tmp, nand->memorg.luns_per_target);
++	pos->target = tmp;
++
++	return pageoffs;
++}
++
++/**
++ * nanddev_pos_cmp() - Compare two NAND positions
++ * @a: First NAND position
++ * @b: Second NAND position
++ *
++ * Compares two NAND positions.
++ *
++ * Return: -1 if @a < @b, 0 if @a == @b and 1 if @a > @b.
++ */
++static inline int nanddev_pos_cmp(const struct nand_pos *a,
++				  const struct nand_pos *b)
++{
++	if (a->target != b->target)
++		return a->target < b->target ? -1 : 1;
++
++	if (a->lun != b->lun)
++		return a->lun < b->lun ? -1 : 1;
++
++	if (a->eraseblock != b->eraseblock)
++		return a->eraseblock < b->eraseblock ? -1 : 1;
++
++	if (a->page != b->page)
++		return a->page < b->page ? -1 : 1;
++
++	return 0;
++}
++
++/**
++ * nanddev_pos_to_offs() - Convert a NAND position into an absolute offset
++ * @nand: NAND device
++ * @pos: the NAND position to convert
++ *
++ * Converts @pos NAND position into an absolute offset.
++ *
++ * Return: the absolute offset. Note that @pos points to the beginning of a
++ *	   page, if one wants to point to a specific offset within this page
++ *	   the returned offset has to be adjusted manually.
++ */
++static inline loff_t nanddev_pos_to_offs(struct nand_device *nand,
++					 const struct nand_pos *pos)
++{
++	unsigned int npages;
++
++	npages = pos->page +
++		 ((pos->eraseblock +
++		   (pos->lun +
++		    (pos->target * nand->memorg.luns_per_target)) *
++		   nand->memorg.eraseblocks_per_lun) *
++		  nand->memorg.pages_per_eraseblock);
++
++	return (loff_t)npages * nand->memorg.pagesize;
++}
++
++/**
++ * nanddev_pos_to_row() - Extract a row address from a NAND position
++ * @nand: NAND device
++ * @pos: the position to convert
++ *
++ * Converts a NAND position into a row address that can then be passed to the
++ * device.
++ *
++ * Return: the row address extracted from @pos.
++ */
++static inline unsigned int nanddev_pos_to_row(struct nand_device *nand,
++					      const struct nand_pos *pos)
++{
++	return (pos->lun << nand->rowconv.lun_addr_shift) |
++	       (pos->eraseblock << nand->rowconv.eraseblock_addr_shift) |
++	       pos->page;
++}
++
++/**
++ * nanddev_pos_next_target() - Move a position to the next target/die
++ * @nand: NAND device
++ * @pos: the position to update
++ *
++ * Updates @pos to point to the start of the next target/die. Useful when you
++ * want to iterate over all targets/dies of a NAND device.
++ */
++static inline void nanddev_pos_next_target(struct nand_device *nand,
++					   struct nand_pos *pos)
++{
++	pos->page = 0;
++	pos->plane = 0;
++	pos->eraseblock = 0;
++	pos->lun = 0;
++	pos->target++;
++}
++
++/**
++ * nanddev_pos_next_lun() - Move a position to the next LUN
++ * @nand: NAND device
++ * @pos: the position to update
++ *
++ * Updates @pos to point to the start of the next LUN. Useful when you want to
++ * iterate over all LUNs of a NAND device.
++ */
++static inline void nanddev_pos_next_lun(struct nand_device *nand,
++					struct nand_pos *pos)
++{
++	if (pos->lun >= nand->memorg.luns_per_target - 1)
++		return nanddev_pos_next_target(nand, pos);
++
++	pos->lun++;
++	pos->page = 0;
++	pos->plane = 0;
++	pos->eraseblock = 0;
++}
++
++/**
++ * nanddev_pos_next_eraseblock() - Move a position to the next eraseblock
++ * @nand: NAND device
++ * @pos: the position to update
++ *
++ * Updates @pos to point to the start of the next eraseblock. Useful when you
++ * want to iterate over all eraseblocks of a NAND device.
++ */
++static inline void nanddev_pos_next_eraseblock(struct nand_device *nand,
++					       struct nand_pos *pos)
++{
++	if (pos->eraseblock >= nand->memorg.eraseblocks_per_lun - 1)
++		return nanddev_pos_next_lun(nand, pos);
++
++	pos->eraseblock++;
++	pos->page = 0;
++	pos->plane = pos->eraseblock % nand->memorg.planes_per_lun;
++}
++
++/**
++ * nanddev_pos_next_eraseblock() - Move a position to the next page
++ * @nand: NAND device
++ * @pos: the position to update
++ *
++ * Updates @pos to point to the start of the next page. Useful when you want to
++ * iterate over all pages of a NAND device.
++ */
++static inline void nanddev_pos_next_page(struct nand_device *nand,
++					 struct nand_pos *pos)
++{
++	if (pos->page >= nand->memorg.pages_per_eraseblock - 1)
++		return nanddev_pos_next_eraseblock(nand, pos);
++
++	pos->page++;
++}
++
++/**
++ * nand_io_iter_init - Initialize a NAND I/O iterator
++ * @nand: NAND device
++ * @offs: absolute offset
++ * @req: MTD request
++ * @iter: NAND I/O iterator
++ *
++ * Initializes a NAND iterator based on the information passed by the MTD
++ * layer.
++ */
++static inline void nanddev_io_iter_init(struct nand_device *nand,
++					loff_t offs, struct mtd_oob_ops *req,
++					struct nand_io_iter *iter)
++{
++	struct mtd_info *mtd = nanddev_to_mtd(nand);
++
++	iter->req.dataoffs = nanddev_offs_to_pos(nand, offs, &iter->req.pos);
++	iter->req.ooboffs = req->ooboffs;
++	iter->oobbytes_per_page = mtd_oobavail(mtd, req);
++	iter->dataleft = req->len;
++	iter->oobleft = req->ooblen;
++	iter->req.databuf.in = req->datbuf;
++	iter->req.datalen = min_t(unsigned int,
++				  nand->memorg.pagesize - iter->req.dataoffs,
++				  iter->dataleft);
++	iter->req.oobbuf.in = req->oobbuf;
++	iter->req.ooblen = min_t(unsigned int,
++				 iter->oobbytes_per_page - iter->req.ooboffs,
++				 iter->oobleft);
++}
++
++/**
++ * nand_io_iter_next_page - Move to the next page
++ * @nand: NAND device
++ * @iter: NAND I/O iterator
++ *
++ * Updates the @iter to point to the next page.
++ */
++static inline void nanddev_io_iter_next_page(struct nand_device *nand,
++					     struct nand_io_iter *iter)
++{
++	nanddev_pos_next_page(nand, &iter->req.pos);
++	iter->dataleft -= iter->req.datalen;
++	iter->req.databuf.in += iter->req.datalen;
++	iter->oobleft -= iter->req.ooblen;
++	iter->req.oobbuf.in += iter->req.ooblen;
++	iter->req.dataoffs = 0;
++	iter->req.ooboffs = 0;
++	iter->req.datalen = min_t(unsigned int, nand->memorg.pagesize,
++				  iter->dataleft);
++	iter->req.ooblen = min_t(unsigned int, iter->oobbytes_per_page,
++				 iter->oobleft);
++}
++
++/**
++ * nand_io_iter_end - Should end iteration or not
++ * @nand: NAND device
++ * @iter: NAND I/O iterator
++ *
++ * Check whether @iter has reached the end of the NAND portion it was asked to
++ * iterate on or not.
++ *
++ * Return: true if @iter has reached the end of the iteration request, false
++ *	   otherwise.
++ */
++static inline bool nanddev_io_iter_end(struct nand_device *nand,
++				       const struct nand_io_iter *iter)
++{
++	if (iter->dataleft || iter->oobleft)
++		return false;
++
++	return true;
++}
++
++/**
++ * nand_io_for_each_page - Iterate over all NAND pages contained in an MTD I/O
++ *			   request
++ * @nand: NAND device
++ * @start: start address to read/write from
++ * @req: MTD I/O request
++ * @iter: NAND I/O iterator
++ *
++ * Should be used for iterate over pages that are contained in an MTD request.
++ */
++#define nanddev_io_for_each_page(nand, start, req, iter)		\
++	for (nanddev_io_iter_init(nand, start, req, iter);		\
++	     !nanddev_io_iter_end(nand, iter);				\
++	     nanddev_io_iter_next_page(nand, iter))
++
++bool nanddev_isbad(struct nand_device *nand, const struct nand_pos *pos);
++bool nanddev_isreserved(struct nand_device *nand, const struct nand_pos *pos);
++int nanddev_erase(struct nand_device *nand, const struct nand_pos *pos);
++int nanddev_markbad(struct nand_device *nand, const struct nand_pos *pos);
++
++/* BBT related functions */
++enum nand_bbt_block_status {
++	NAND_BBT_BLOCK_STATUS_UNKNOWN,
++	NAND_BBT_BLOCK_GOOD,
++	NAND_BBT_BLOCK_WORN,
++	NAND_BBT_BLOCK_RESERVED,
++	NAND_BBT_BLOCK_FACTORY_BAD,
++	NAND_BBT_BLOCK_NUM_STATUS,
++};
++
++int nanddev_bbt_init(struct nand_device *nand);
++void nanddev_bbt_cleanup(struct nand_device *nand);
++int nanddev_bbt_update(struct nand_device *nand);
++int nanddev_bbt_get_block_status(const struct nand_device *nand,
++				 unsigned int entry);
++int nanddev_bbt_set_block_status(struct nand_device *nand, unsigned int entry,
++				 enum nand_bbt_block_status status);
++int nanddev_bbt_markbad(struct nand_device *nand, unsigned int block);
++
++/**
++ * nanddev_bbt_pos_to_entry() - Convert a NAND position into a BBT entry
++ * @nand: NAND device
++ * @pos: the NAND position we want to get BBT entry for
++ *
++ * Return the BBT entry used to store information about the eraseblock pointed
++ * by @pos.
++ *
++ * Return: the BBT entry storing information about eraseblock pointed by @pos.
++ */
++static inline unsigned int nanddev_bbt_pos_to_entry(struct nand_device *nand,
++						    const struct nand_pos *pos)
++{
++	return pos->eraseblock +
++	       ((pos->lun + (pos->target * nand->memorg.luns_per_target)) *
++		nand->memorg.eraseblocks_per_lun);
++}
++
++/**
++ * nanddev_bbt_is_initialized() - Check if the BBT has been initialized
++ * @nand: NAND device
++ *
++ * Return: true if the BBT has been initialized, false otherwise.
++ */
++static inline bool nanddev_bbt_is_initialized(struct nand_device *nand)
++{
++	return !!nand->bbt.cache;
++}
++
++/* MTD -> NAND helper functions. */
++int nanddev_mtd_erase(struct mtd_info *mtd, struct erase_info *einfo);
++
++#endif /* __LINUX_MTD_NAND_H */
+-- 
+2.7.4
+
diff --git a/recipes-kernel/linux/linux-stm32mp/patches/0016-mtd-nand-Pass-mode-information-to-nand_page_io_req.patch b/recipes-kernel/linux/linux-stm32mp/patches/0016-mtd-nand-Pass-mode-information-to-nand_page_io_req.patch
new file mode 100644
index 0000000000000000000000000000000000000000..125b11cb0f6acbf9afd2cd04383a0ab2f926099b
--- /dev/null
+++ b/recipes-kernel/linux/linux-stm32mp/patches/0016-mtd-nand-Pass-mode-information-to-nand_page_io_req.patch
@@ -0,0 +1,47 @@
+From d11fcf6b16a9339900ffb3b354e92d74551dea98 Mon Sep 17 00:00:00 2001
+From: Boris Brezillon <boris.brezillon@bootlin.com>
+Date: Tue, 15 May 2018 17:08:21 +0200
+Subject: [PATCH 16/28] mtd: nand: Pass mode information to nand_page_io_req
+
+The NAND sub-layers are likely to need the MTD_OPS_XXX mode information
+in order to decide if they should enable/disable ECC or how they should
+place the OOB bytes in the provided OOB buffer.
+
+Add a field to nand_page_io_req to pass this information.
+
+Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
+---
+ include/linux/mtd/nand.h | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
+index 792ea5c..abe975c 100644
+--- a/include/linux/mtd/nand.h
++++ b/include/linux/mtd/nand.h
+@@ -86,6 +86,7 @@ struct nand_pos {
+  * @ooboffs: the OOB offset within the page
+  * @ooblen: the number of OOB bytes to read from/write to this page
+  * @oobbuf: buffer to store OOB data in or get OOB data from
++ * @mode: one of the %MTD_OPS_XXX mode
+  *
+  * This object is used to pass per-page I/O requests to NAND sub-layers. This
+  * way all useful information are already formatted in a useful way and
+@@ -106,6 +107,7 @@ struct nand_page_io_req {
+ 		const void *out;
+ 		void *in;
+ 	} oobbuf;
++	int mode;
+ };
+ 
+ /**
+@@ -599,6 +601,7 @@ static inline void nanddev_io_iter_init(struct nand_device *nand,
+ {
+ 	struct mtd_info *mtd = nanddev_to_mtd(nand);
+ 
++	iter->req.mode = req->mode;
+ 	iter->req.dataoffs = nanddev_offs_to_pos(nand, offs, &iter->req.pos);
+ 	iter->req.ooboffs = req->ooboffs;
+ 	iter->oobbytes_per_page = mtd_oobavail(mtd, req);
+-- 
+2.7.4
+
diff --git a/recipes-kernel/linux/linux-stm32mp/patches/0017-mtd-nand-Add-core-infrastructure-to-support-SPI-NAND.patch b/recipes-kernel/linux/linux-stm32mp/patches/0017-mtd-nand-Add-core-infrastructure-to-support-SPI-NAND.patch
new file mode 100644
index 0000000000000000000000000000000000000000..3fbdf5eeeb43586f8ddbb56f6903c4e017039e3c
--- /dev/null
+++ b/recipes-kernel/linux/linux-stm32mp/patches/0017-mtd-nand-Add-core-infrastructure-to-support-SPI-NAND.patch
@@ -0,0 +1,1635 @@
+From d7bf246a32ae677e5777a0f6311895afbc9be5d8 Mon Sep 17 00:00:00 2001
+From: Peter Pan <peterpandong@micron.com>
+Date: Tue, 15 May 2018 17:08:22 +0200
+Subject: [PATCH 17/28] mtd: nand: Add core infrastructure to support SPI NANDs
+
+Add a SPI NAND framework based on the generic NAND framework and the
+spi-mem infrastructure.
+
+In its current state, this framework supports the following features:
+
+- single/dual/quad IO modes
+- on-die ECC
+
+Signed-off-by: Peter Pan <peterpandong@micron.com>
+Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
+---
+ drivers/mtd/nand/Kconfig      |    1 +
+ drivers/mtd/nand/Makefile     |    1 +
+ drivers/mtd/nand/spi/Kconfig  |    7 +
+ drivers/mtd/nand/spi/Makefile |    2 +
+ drivers/mtd/nand/spi/core.c   | 1122 +++++++++++++++++++++++++++++++++++++++++
+ include/linux/mtd/spinand.h   |  415 +++++++++++++++
+ include/linux/spi/spi-mem.h   |    4 +-
+ 7 files changed, 1551 insertions(+), 1 deletion(-)
+ create mode 100644 drivers/mtd/nand/spi/Kconfig
+ create mode 100644 drivers/mtd/nand/spi/Makefile
+ create mode 100644 drivers/mtd/nand/spi/core.c
+ create mode 100644 include/linux/mtd/spinand.h
+
+diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
+index 1c1a1f4..7695fd8 100644
+--- a/drivers/mtd/nand/Kconfig
++++ b/drivers/mtd/nand/Kconfig
+@@ -2,3 +2,4 @@ config MTD_NAND_CORE
+ 	tristate
+ 
+ source "drivers/mtd/nand/raw/Kconfig"
++source "drivers/mtd/nand/spi/Kconfig"
+diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
+index f749ec7..7cf9e8f 100644
+--- a/drivers/mtd/nand/Makefile
++++ b/drivers/mtd/nand/Makefile
+@@ -7,3 +7,4 @@ nandcore-objs := core.o bbt.o
+ obj-$(CONFIG_MTD_NAND_CORE) += nandcore.o
+ 
+ obj-y	+= raw/
++obj-y	+= spi/
+diff --git a/drivers/mtd/nand/spi/Kconfig b/drivers/mtd/nand/spi/Kconfig
+new file mode 100644
+index 0000000..7c37d29
+--- /dev/null
++++ b/drivers/mtd/nand/spi/Kconfig
+@@ -0,0 +1,7 @@
++menuconfig MTD_SPI_NAND
++	tristate "SPI NAND device Support"
++	select MTD_NAND_CORE
++	depends on SPI_MASTER
++	select SPI_MEM
++	help
++	  This is the framework for the SPI NAND device drivers.
+diff --git a/drivers/mtd/nand/spi/Makefile b/drivers/mtd/nand/spi/Makefile
+new file mode 100644
+index 0000000..feb79a1
+--- /dev/null
++++ b/drivers/mtd/nand/spi/Makefile
+@@ -0,0 +1,2 @@
++spinand-objs := core.o
++obj-$(CONFIG_MTD_SPI_NAND) += spinand.o
+diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
+new file mode 100644
+index 0000000..faad9bc
+--- /dev/null
++++ b/drivers/mtd/nand/spi/core.c
+@@ -0,0 +1,1122 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (C) 2016-2017 Micron Technology, Inc.
++ *
++ * Authors:
++ *	Peter Pan <peterpandong@micron.com>
++ *	Boris Brezillon <boris.brezillon@bootlin.com>
++ */
++
++#define pr_fmt(fmt)	"spi-nand: " fmt
++
++#include <linux/device.h>
++#include <linux/jiffies.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/mtd/spinand.h>
++#include <linux/of.h>
++#include <linux/slab.h>
++#include <linux/spi/spi.h>
++#include <linux/spi/spi-mem.h>
++
++static void spinand_cache_op_adjust_colum(struct spinand_device *spinand,
++					  const struct nand_page_io_req *req,
++					  u16 *column)
++{
++	struct nand_device *nand = spinand_to_nand(spinand);
++	unsigned int shift;
++
++	if (nand->memorg.planes_per_lun < 2)
++		return;
++
++	/* The plane number is passed in MSB just above the column address */
++	shift = fls(nand->memorg.pagesize);
++	*column |= req->pos.plane << shift;
++}
++
++static int spinand_read_reg_op(struct spinand_device *spinand, u8 reg, u8 *val)
++{
++	struct spi_mem_op op = SPINAND_GET_FEATURE_OP(reg,
++						      spinand->scratchbuf);
++	int ret;
++
++	ret = spi_mem_exec_op(spinand->spimem, &op);
++	if (ret)
++		return ret;
++
++	*val = *spinand->scratchbuf;
++	return 0;
++}
++
++static int spinand_write_reg_op(struct spinand_device *spinand, u8 reg, u8 val)
++{
++	struct spi_mem_op op = SPINAND_SET_FEATURE_OP(reg,
++						      spinand->scratchbuf);
++
++	*spinand->scratchbuf = val;
++	return spi_mem_exec_op(spinand->spimem, &op);
++}
++
++static int spinand_read_status(struct spinand_device *spinand, u8 *status)
++{
++	return spinand_read_reg_op(spinand, REG_STATUS, status);
++}
++
++static int spinand_get_cfg(struct spinand_device *spinand, u8 *cfg)
++{
++	struct nand_device *nand = spinand_to_nand(spinand);
++
++	if (WARN_ON(spinand->cur_target < 0 ||
++		    spinand->cur_target >= nand->memorg.ntargets))
++		return -EINVAL;
++
++	*cfg = spinand->cfg_cache[spinand->cur_target];
++	return 0;
++}
++
++static int spinand_set_cfg(struct spinand_device *spinand, u8 cfg)
++{
++	struct nand_device *nand = spinand_to_nand(spinand);
++	int ret;
++
++	if (WARN_ON(spinand->cur_target < 0 ||
++		    spinand->cur_target >= nand->memorg.ntargets))
++		return -EINVAL;
++
++	if (spinand->cfg_cache[spinand->cur_target] == cfg)
++		return 0;
++
++	ret = spinand_write_reg_op(spinand, REG_CFG, cfg);
++	if (ret)
++		return ret;
++
++	spinand->cfg_cache[spinand->cur_target] = cfg;
++	return 0;
++}
++
++/**
++ * spinand_upd_cfg() - Update the configuration register
++ * @spinand: the spinand device
++ * @mask: the mask encoding the bits to update in the config reg
++ * @val: the new value to apply
++ *
++ * Update the configuration register.
++ *
++ * Return: 0 on success, a negative error code otherwise.
++ */
++int spinand_upd_cfg(struct spinand_device *spinand, u8 mask, u8 val)
++{
++	int ret;
++	u8 cfg;
++
++	ret = spinand_get_cfg(spinand, &cfg);
++	if (ret)
++		return ret;
++
++	cfg &= ~mask;
++	cfg |= val;
++
++	return spinand_set_cfg(spinand, cfg);
++}
++
++/**
++ * spinand_select_target() - Select a specific NAND target/die
++ * @spinand: the spinand device
++ * @target: the target/die to select
++ *
++ * Select a new target/die. If chip only has one die, this function is a NOOP.
++ *
++ * Return: 0 on success, a negative error code otherwise.
++ */
++int spinand_select_target(struct spinand_device *spinand, unsigned int target)
++{
++	struct nand_device *nand = spinand_to_nand(spinand);
++	int ret;
++
++	if (WARN_ON(target >= nand->memorg.ntargets))
++		return -EINVAL;
++
++	if (spinand->cur_target == target)
++		return 0;
++
++	if (nand->memorg.ntargets == 1) {
++		spinand->cur_target = target;
++		return 0;
++	}
++
++	ret = spinand->select_target(spinand, target);
++	if (ret)
++		return ret;
++
++	spinand->cur_target = target;
++	return 0;
++}
++
++static int spinand_init_cfg_cache(struct spinand_device *spinand)
++{
++	struct nand_device *nand = spinand_to_nand(spinand);
++	struct device *dev = &spinand->spimem->spi->dev;
++	unsigned int target;
++	int ret;
++
++	spinand->cfg_cache = devm_kzalloc(dev,
++					  sizeof(*spinand->cfg_cache) *
++					  nand->memorg.ntargets,
++					  GFP_KERNEL);
++	if (!spinand->cfg_cache)
++		return -ENOMEM;
++
++	for (target = 0; target < nand->memorg.ntargets; target++) {
++		ret = spinand_select_target(spinand, target);
++		if (ret)
++			return ret;
++
++		/*
++		 * We use spinand_read_reg_op() instead of spinand_get_cfg()
++		 * here to bypass the config cache.
++		 */
++		ret = spinand_read_reg_op(spinand, REG_CFG,
++					  &spinand->cfg_cache[target]);
++		if (ret)
++			return ret;
++	}
++
++	return 0;
++}
++
++static void spinand_init_quad_enable(struct spinand_device *spinand)
++{
++	bool enable = false;
++	u8 cfg = 0;
++
++	if (!(spinand->flags & SPINAND_HAS_QE_BIT))
++		return;
++
++	if (spinand->op_templates.read_cache->data.buswidth == 4 ||
++	    spinand->op_templates.write_cache->data.buswidth == 4 ||
++	    spinand->op_templates.update_cache->data.buswidth == 4)
++		enable = true;
++
++	WARN_ON(spinand_get_cfg(spinand, &cfg));
++
++	if (enable)
++		cfg |= CFG_QUAD_ENABLE;
++	else
++		cfg &= ~CFG_QUAD_ENABLE;
++
++	WARN_ON(spinand_set_cfg(spinand, cfg));
++}
++
++static void spinand_ecc_enable(struct spinand_device *spinand,
++			       bool enable)
++{
++	u8 cfg = 0;
++
++	WARN_ON(spinand_get_cfg(spinand, &cfg));
++
++	if (enable)
++		cfg |= CFG_ECC_ENABLE;
++	else
++		cfg &= ~CFG_ECC_ENABLE;
++
++	WARN_ON(spinand_set_cfg(spinand, cfg));
++}
++
++static int spinand_write_enable_op(struct spinand_device *spinand)
++{
++	struct spi_mem_op op = SPINAND_WR_EN_DIS_OP(true);
++
++	return spi_mem_exec_op(spinand->spimem, &op);
++}
++
++static int spinand_load_page_op(struct spinand_device *spinand,
++				const struct nand_page_io_req *req)
++{
++	struct nand_device *nand = spinand_to_nand(spinand);
++	unsigned int row = nanddev_pos_to_row(nand, &req->pos);
++	struct spi_mem_op op = SPINAND_PAGE_READ_OP(row);
++
++	return spi_mem_exec_op(spinand->spimem, &op);
++}
++
++static int spinand_read_from_cache_op(struct spinand_device *spinand,
++				      const struct nand_page_io_req *req)
++{
++	struct spi_mem_op op = *spinand->op_templates.read_cache;
++	struct nand_device *nand = spinand_to_nand(spinand);
++	struct mtd_info *mtd = nanddev_to_mtd(nand);
++	struct nand_page_io_req adjreq = *req;
++	unsigned int nbytes = 0;
++	void *buf = NULL;
++	u16 column = 0;
++	int ret;
++
++	if (req->datalen) {
++		adjreq.datalen = nanddev_page_size(nand);
++		adjreq.dataoffs = 0;
++		adjreq.databuf.in = spinand->databuf;
++		buf = spinand->databuf;
++		nbytes = adjreq.datalen;
++	}
++
++	if (req->ooblen) {
++		adjreq.ooblen = nanddev_per_page_oobsize(nand);
++		adjreq.ooboffs = 0;
++		adjreq.oobbuf.in = spinand->oobbuf;
++		nbytes += nanddev_per_page_oobsize(nand);
++		if (!buf) {
++			buf = spinand->oobbuf;
++			column = nanddev_page_size(nand);
++		}
++	}
++
++	spinand_cache_op_adjust_colum(spinand, &adjreq, &column);
++	op.addr.val = column;
++
++	/*
++	 * Some controllers are limited in term of max RX data size. In this
++	 * case, just repeat the READ_CACHE operation after updating the
++	 * column.
++	 */
++	while (nbytes) {
++		op.data.buf.in = buf;
++		op.data.nbytes = nbytes;
++		ret = spi_mem_adjust_op_size(spinand->spimem, &op);
++		if (ret)
++			return ret;
++
++		ret = spi_mem_exec_op(spinand->spimem, &op);
++		if (ret)
++			return ret;
++
++		buf += op.data.nbytes;
++		nbytes -= op.data.nbytes;
++		op.addr.val += op.data.nbytes;
++	}
++
++	if (req->datalen)
++		memcpy(req->databuf.in, spinand->databuf + req->dataoffs,
++		       req->datalen);
++
++	if (req->ooblen) {
++		if (req->mode == MTD_OPS_AUTO_OOB)
++			mtd_ooblayout_get_databytes(mtd, req->oobbuf.in,
++						    spinand->oobbuf,
++						    req->ooboffs,
++						    req->ooblen);
++		else
++			memcpy(req->oobbuf.in, spinand->oobbuf + req->ooboffs,
++			       req->ooblen);
++	}
++
++	return 0;
++}
++
++static int spinand_write_to_cache_op(struct spinand_device *spinand,
++				     const struct nand_page_io_req *req)
++{
++	struct spi_mem_op op = *spinand->op_templates.write_cache;
++	struct nand_device *nand = spinand_to_nand(spinand);
++	struct mtd_info *mtd = nanddev_to_mtd(nand);
++	struct nand_page_io_req adjreq = *req;
++	unsigned int nbytes = 0;
++	void *buf = NULL;
++	u16 column = 0;
++	int ret;
++
++	memset(spinand->databuf, 0xff,
++	       nanddev_page_size(nand) +
++	       nanddev_per_page_oobsize(nand));
++
++	if (req->datalen) {
++		memcpy(spinand->databuf + req->dataoffs, req->databuf.out,
++		       req->datalen);
++		adjreq.dataoffs = 0;
++		adjreq.datalen = nanddev_page_size(nand);
++		adjreq.databuf.out = spinand->databuf;
++		nbytes = adjreq.datalen;
++		buf = spinand->databuf;
++	}
++
++	if (req->ooblen) {
++		if (req->mode == MTD_OPS_AUTO_OOB)
++			mtd_ooblayout_set_databytes(mtd, req->oobbuf.out,
++						    spinand->oobbuf,
++						    req->ooboffs,
++						    req->ooblen);
++		else
++			memcpy(spinand->oobbuf + req->ooboffs, req->oobbuf.out,
++			       req->ooblen);
++
++		adjreq.ooblen = nanddev_per_page_oobsize(nand);
++		adjreq.ooboffs = 0;
++		nbytes += nanddev_per_page_oobsize(nand);
++		if (!buf) {
++			buf = spinand->oobbuf;
++			column = nanddev_page_size(nand);
++		}
++	}
++
++	spinand_cache_op_adjust_colum(spinand, &adjreq, &column);
++
++	op = *spinand->op_templates.write_cache;
++	op.addr.val = column;
++
++	/*
++	 * Some controllers are limited in term of max TX data size. In this
++	 * case, split the operation into one LOAD CACHE and one or more
++	 * LOAD RANDOM CACHE.
++	 */
++	while (nbytes) {
++		op.data.buf.out = buf;
++		op.data.nbytes = nbytes;
++
++		ret = spi_mem_adjust_op_size(spinand->spimem, &op);
++		if (ret)
++			return ret;
++
++		ret = spi_mem_exec_op(spinand->spimem, &op);
++		if (ret)
++			return ret;
++
++		buf += op.data.nbytes;
++		nbytes -= op.data.nbytes;
++		op.addr.val += op.data.nbytes;
++
++		/*
++		 * We need to use the RANDOM LOAD CACHE operation if there's
++		 * more than one iteration, because the LOAD operation resets
++		 * the cache to 0xff.
++		 */
++		if (nbytes) {
++			column = op.addr.val;
++			op = *spinand->op_templates.update_cache;
++			op.addr.val = column;
++		}
++	}
++
++	return 0;
++}
++
++static int spinand_program_op(struct spinand_device *spinand,
++			      const struct nand_page_io_req *req)
++{
++	struct nand_device *nand = spinand_to_nand(spinand);
++	unsigned int row = nanddev_pos_to_row(nand, &req->pos);
++	struct spi_mem_op op = SPINAND_PROG_EXEC_OP(row);
++
++	return spi_mem_exec_op(spinand->spimem, &op);
++}
++
++static int spinand_erase_op(struct spinand_device *spinand,
++			    const struct nand_pos *pos)
++{
++	struct nand_device *nand = &spinand->base;
++	unsigned int row = nanddev_pos_to_row(nand, pos);
++	struct spi_mem_op op = SPINAND_BLK_ERASE_OP(row);
++
++	return spi_mem_exec_op(spinand->spimem, &op);
++}
++
++static int spinand_wait(struct spinand_device *spinand, u8 *s)
++{
++	unsigned long timeo =  jiffies + msecs_to_jiffies(400);
++	u8 status;
++
++	do {
++		spinand_read_status(spinand, &status);
++		if (!(status & STATUS_BUSY))
++			goto out;
++	} while (time_before(jiffies, timeo));
++
++	/*
++	 * Extra read, just in case the STATUS_READY bit has changed
++	 * since our last check
++	 */
++	spinand_read_status(spinand, &status);
++
++out:
++	if (s)
++		*s = status;
++
++	return status & STATUS_BUSY ? -ETIMEDOUT : 0;
++}
++
++static int spinand_read_id_op(struct spinand_device *spinand, u8 *buf)
++{
++	struct spi_mem_op op = SPINAND_READID_OP(0, spinand->scratchbuf,
++						 SPINAND_MAX_ID_LEN);
++	int ret;
++
++	ret = spi_mem_exec_op(spinand->spimem, &op);
++	if (!ret)
++		memcpy(buf, spinand->scratchbuf, SPINAND_MAX_ID_LEN);
++
++	return 0;
++}
++
++static int spinand_reset_op(struct spinand_device *spinand)
++{
++	struct spi_mem_op op = SPINAND_RESET_OP;
++	int ret;
++
++	ret = spi_mem_exec_op(spinand->spimem, &op);
++	if (ret)
++		return ret;
++
++	return spinand_wait(spinand, NULL);
++}
++
++static int spinand_lock_block(struct spinand_device *spinand, u8 lock)
++{
++	return spinand_write_reg_op(spinand, REG_BLOCK_LOCK, lock);
++}
++
++static int spinand_check_ecc_status(struct spinand_device *spinand, u8 status)
++{
++	struct nand_device *nand = spinand_to_nand(spinand);
++
++	if (spinand->eccinfo.get_status)
++		return spinand->eccinfo.get_status(spinand, status);
++
++	switch (status & STATUS_ECC_MASK) {
++	case STATUS_ECC_NO_BITFLIPS:
++		return 0;
++
++	case STATUS_ECC_HAS_BITFLIPS:
++		/*
++		 * We have no way to know exactly how many bitflips have been
++		 * fixed, so let's return the maximum possible value so that
++		 * wear-leveling layers move the data immediately.
++		 */
++		return nand->eccreq.strength;
++
++	case STATUS_ECC_UNCOR_ERROR:
++		return -EBADMSG;
++
++	default:
++		break;
++	}
++
++	return -EINVAL;
++}
++
++static int spinand_read_page(struct spinand_device *spinand,
++			     const struct nand_page_io_req *req,
++			     bool ecc_enabled)
++{
++	struct nand_device *nand = spinand_to_nand(spinand);
++	struct device *dev = &spinand->spimem->spi->dev;
++	u8 status;
++	int ret;
++
++	spinand_load_page_op(spinand, req);
++
++	ret = spinand_wait(spinand, &status);
++	if (ret < 0) {
++		dev_err(dev, "failed to load page @%llx (err = %d)\n",
++			nanddev_pos_to_offs(nand, &req->pos), ret);
++		return ret;
++	}
++
++	spinand_read_from_cache_op(spinand, req);
++
++	if (!ecc_enabled)
++		return 0;
++
++	return spinand_check_ecc_status(spinand, status);
++}
++
++static int spinand_write_page(struct spinand_device *spinand,
++			      const struct nand_page_io_req *req)
++{
++	struct nand_device *nand = spinand_to_nand(spinand);
++	struct device *dev = &spinand->spimem->spi->dev;
++	u8 status;
++	int ret = 0;
++
++	spinand_write_enable_op(spinand);
++	spinand_write_to_cache_op(spinand, req);
++	spinand_program_op(spinand, req);
++
++	ret = spinand_wait(spinand, &status);
++	if (!ret && (status & STATUS_PROG_FAILED))
++		ret = -EIO;
++
++	if (ret < 0)
++		dev_err(dev, "failed to program page @%llx (err = %d)\n",
++			nanddev_pos_to_offs(nand, &req->pos), ret);
++
++	return ret;
++}
++
++static int spinand_mtd_read(struct mtd_info *mtd, loff_t from,
++			    struct mtd_oob_ops *ops)
++{
++	struct spinand_device *spinand = mtd_to_spinand(mtd);
++	struct nand_device *nand = mtd_to_nanddev(mtd);
++	unsigned int max_bitflips = 0;
++	struct nand_io_iter iter;
++	bool enable_ecc = false;
++	bool ecc_failed = false;
++	int ret = 0;
++
++	if (ops->mode != MTD_OPS_RAW && spinand->eccinfo.ooblayout)
++		enable_ecc = true;
++
++	mutex_lock(&spinand->lock);
++
++	nanddev_io_for_each_page(nand, from, ops, &iter) {
++		spinand_select_target(spinand, iter.req.pos.target);
++		spinand_ecc_enable(spinand, enable_ecc);
++		ret = spinand_read_page(spinand, &iter.req, enable_ecc);
++		if (ret < 0 && ret != -EBADMSG)
++			break;
++
++		if (ret == -EBADMSG) {
++			ecc_failed = true;
++			mtd->ecc_stats.failed++;
++			ret = 0;
++		} else {
++			mtd->ecc_stats.corrected += ret;
++			max_bitflips = max_t(unsigned int, max_bitflips, ret);
++		}
++
++		ops->retlen += iter.req.datalen;
++		ops->oobretlen += iter.req.ooblen;
++	}
++
++	mutex_unlock(&spinand->lock);
++
++	if (ecc_failed && !ret)
++		ret = -EBADMSG;
++
++	return ret ? ret : max_bitflips;
++}
++
++static int spinand_mtd_write(struct mtd_info *mtd, loff_t to,
++			     struct mtd_oob_ops *ops)
++{
++	struct spinand_device *spinand = mtd_to_spinand(mtd);
++	struct nand_device *nand = mtd_to_nanddev(mtd);
++	struct nand_io_iter iter;
++	bool enable_ecc = false;
++	int ret = 0;
++
++	if (ops->mode != MTD_OPS_RAW && mtd->ooblayout)
++		enable_ecc = true;
++
++	mutex_lock(&spinand->lock);
++
++	nanddev_io_for_each_page(nand, to, ops, &iter) {
++		spinand_select_target(spinand, iter.req.pos.target);
++		spinand_ecc_enable(spinand, enable_ecc);
++
++		ret = spinand_write_page(spinand, &iter.req);
++		if (ret)
++			break;
++
++		ops->retlen += iter.req.datalen;
++		ops->oobretlen += iter.req.ooblen;
++	}
++
++	mutex_unlock(&spinand->lock);
++
++	return ret;
++}
++
++static bool spinand_isbad(struct nand_device *nand, const struct nand_pos *pos)
++{
++	struct spinand_device *spinand = nand_to_spinand(nand);
++	struct nand_page_io_req req = {
++		.pos = *pos,
++		.ooblen = 2,
++		.ooboffs = 0,
++		.oobbuf.in = spinand->oobbuf,
++		.mode = MTD_OPS_RAW,
++	};
++	int ret;
++
++	memset(spinand->oobbuf, 0, 2);
++	spinand_select_target(spinand, pos->target);
++	ret = spinand_read_page(spinand, &req, false);
++	if (spinand->oobbuf[0] != 0xff || spinand->oobbuf[1] != 0xff)
++		return true;
++
++	return false;
++}
++
++static int spinand_mtd_block_isbad(struct mtd_info *mtd, loff_t offs)
++{
++	struct nand_device *nand = mtd_to_nanddev(mtd);
++	struct spinand_device *spinand = nand_to_spinand(nand);
++	struct nand_pos pos;
++	int ret;
++
++	nanddev_offs_to_pos(nand, offs, &pos);
++	mutex_lock(&spinand->lock);
++	ret = nanddev_isbad(nand, &pos);
++	mutex_unlock(&spinand->lock);
++
++	return ret;
++}
++
++static int spinand_markbad(struct nand_device *nand, const struct nand_pos *pos)
++{
++	struct spinand_device *spinand = nand_to_spinand(nand);
++	struct nand_page_io_req req = {
++		.pos = *pos,
++		.ooboffs = 0,
++		.ooblen = 2,
++		.oobbuf.out = spinand->oobbuf,
++	};
++
++	/* Erase block before marking it bad. */
++	spinand_select_target(spinand, pos->target);
++	spinand_write_enable_op(spinand);
++	spinand_erase_op(spinand, pos);
++
++	memset(spinand->oobbuf, 0, 2);
++	return spinand_write_page(spinand, &req);
++}
++
++static int spinand_mtd_block_markbad(struct mtd_info *mtd, loff_t offs)
++{
++	struct nand_device *nand = mtd_to_nanddev(mtd);
++	struct spinand_device *spinand = nand_to_spinand(nand);
++	struct nand_pos pos;
++	int ret;
++
++	nanddev_offs_to_pos(nand, offs, &pos);
++	mutex_lock(&spinand->lock);
++	ret = nanddev_markbad(nand, &pos);
++	mutex_unlock(&spinand->lock);
++
++	return ret;
++}
++
++static int spinand_erase(struct nand_device *nand, const struct nand_pos *pos)
++{
++	struct spinand_device *spinand = nand_to_spinand(nand);
++	struct device *dev = &spinand->spimem->spi->dev;
++	u8 status;
++	int ret;
++
++	spinand_select_target(spinand, pos->target);
++	spinand_write_enable_op(spinand);
++	spinand_erase_op(spinand, pos);
++
++	ret = spinand_wait(spinand, &status);
++
++	if (!ret && (status & STATUS_ERASE_FAILED))
++		ret = -EIO;
++
++	if (ret)
++		dev_err(dev, "failed to erase block %d (err = %d)\n",
++			pos->eraseblock, ret);
++
++	return ret;
++}
++
++static int spinand_mtd_erase(struct mtd_info *mtd,
++			     struct erase_info *einfo)
++{
++	struct spinand_device *spinand = mtd_to_spinand(mtd);
++	int ret;
++
++	mutex_lock(&spinand->lock);
++	ret = nanddev_mtd_erase(mtd, einfo);
++	mutex_unlock(&spinand->lock);
++
++	return ret;
++}
++
++static int spinand_mtd_block_isreserved(struct mtd_info *mtd, loff_t offs)
++{
++	struct spinand_device *spinand = mtd_to_spinand(mtd);
++	struct nand_device *nand = mtd_to_nanddev(mtd);
++	struct nand_pos pos;
++	int ret;
++
++	nanddev_offs_to_pos(nand, offs, &pos);
++	mutex_lock(&spinand->lock);
++	ret = nanddev_isreserved(nand, &pos);
++	mutex_unlock(&spinand->lock);
++
++	return ret;
++}
++
++const struct spi_mem_op *
++spinand_find_supported_op(struct spinand_device *spinand,
++			  const struct spi_mem_op *ops,
++			  unsigned int nops)
++{
++	unsigned int i;
++
++	for (i = 0; i < nops; i++) {
++		if (spi_mem_supports_op(spinand->spimem, &ops[i]))
++			return &ops[i];
++	}
++
++	return NULL;
++}
++
++static const struct nand_ops spinand_ops = {
++	.erase = spinand_erase,
++	.markbad = spinand_markbad,
++	.isbad = spinand_isbad,
++};
++
++static int spinand_manufacturer_detect(struct spinand_device *spinand)
++{
++	return -ENOTSUPP;
++}
++
++static int spinand_manufacturer_init(struct spinand_device *spinand)
++{
++	if (spinand->manufacturer->ops->init)
++		return spinand->manufacturer->ops->init(spinand);
++
++	return 0;
++}
++
++static void spinand_manufacturer_cleanup(struct spinand_device *spinand)
++{
++	/* Release manufacturer private data */
++	if (spinand->manufacturer->ops->cleanup)
++		return spinand->manufacturer->ops->cleanup(spinand);
++}
++
++static const struct spi_mem_op *
++spinand_select_op_variant(struct spinand_device *spinand,
++			  const struct spinand_op_variants *variants)
++{
++	struct nand_device *nand = spinand_to_nand(spinand);
++	unsigned int i;
++
++	for (i = 0; i < variants->nops; i++) {
++		struct spi_mem_op op = variants->ops[i];
++		unsigned int nbytes;
++		int ret;
++
++		nbytes = nanddev_per_page_oobsize(nand) +
++			 nanddev_page_size(nand);
++
++		while (nbytes) {
++			op.data.nbytes = nbytes;
++			ret = spi_mem_adjust_op_size(spinand->spimem, &op);
++			if (ret)
++				break;
++
++			if (!spi_mem_supports_op(spinand->spimem, &op))
++				break;
++
++			nbytes -= op.data.nbytes;
++		}
++
++		if (!nbytes)
++			return &variants->ops[i];
++	}
++
++	return NULL;
++}
++
++/**
++ * spinand_match_and_init() - Try to find a match between a device ID and an
++ *			      entry in a spinand_info table
++ * @spinand: SPI NAND object
++ * @table: SPI NAND device description table
++ * @table_size: size of the device description table
++ *
++ * Should be used by SPI NAND manufacturer drivers when they want to find a
++ * match between a device ID retrieved through the READ_ID command and an
++ * entry in the SPI NAND description table. If a match is found, the spinand
++ * object will be initialized with information provided by the matching
++ * spinand_info entry.
++ *
++ * Return: 0 on success, a negative error code otherwise.
++ */
++int spinand_match_and_init(struct spinand_device *spinand,
++			   const struct spinand_info *table,
++			   unsigned int table_size, u8 devid)
++{
++	struct nand_device *nand = spinand_to_nand(spinand);
++	unsigned int i;
++
++	for (i = 0; i < table_size; i++) {
++		const struct spinand_info *info = &table[i];
++		const struct spi_mem_op *op;
++
++		if (devid != info->devid)
++			continue;
++
++		nand->memorg = table[i].memorg;
++		nand->eccreq = table[i].eccreq;
++		spinand->eccinfo = table[i].eccinfo;
++		spinand->flags = table[i].flags;
++		spinand->select_target = table[i].select_target;
++
++		op = spinand_select_op_variant(spinand,
++					       info->op_variants.read_cache);
++		if (!op)
++			return -ENOTSUPP;
++
++		spinand->op_templates.read_cache = op;
++
++		op = spinand_select_op_variant(spinand,
++					       info->op_variants.write_cache);
++		if (!op)
++			return -ENOTSUPP;
++
++		spinand->op_templates.write_cache = op;
++
++		op = spinand_select_op_variant(spinand,
++					       info->op_variants.update_cache);
++		spinand->op_templates.update_cache = op;
++
++		spinand_init_quad_enable(spinand);
++
++		return 0;
++	}
++
++	return -ENOTSUPP;
++}
++
++static int spinand_detect(struct spinand_device *spinand)
++{
++	struct device *dev = &spinand->spimem->spi->dev;
++	struct nand_device *nand = &spinand->base;
++	int ret;
++
++	ret = spinand_reset_op(spinand);
++	if (ret)
++		return ret;
++
++	ret = spinand_read_id_op(spinand, spinand->id.data);
++	if (ret)
++		return ret;
++
++	spinand->id.len = SPINAND_MAX_ID_LEN;
++
++	ret = spinand_manufacturer_detect(spinand);
++	if (ret) {
++		dev_err(dev, "unknown raw ID %*phN\n", SPINAND_MAX_ID_LEN,
++			spinand->id.data);
++		return ret;
++	}
++
++	if (nand->memorg.ntargets > 1 && !spinand->select_target) {
++		dev_err(dev,
++			"SPI NANDs with more than one die must implement ->select_target()\n");
++		return -EINVAL;
++	}
++
++	dev_info(&spinand->spimem->spi->dev,
++		 "%s SPI NAND was found.\n", spinand->manufacturer->name);
++	dev_info(&spinand->spimem->spi->dev,
++		 "%llu MiB, block size: %zu KiB, page size: %zu, OOB size: %u\n",
++		 nanddev_size(nand) >> 20, nanddev_eraseblock_size(nand) >> 10,
++		 nanddev_page_size(nand), nanddev_per_page_oobsize(nand));
++
++	return 0;
++}
++
++static int spinand_noecc_ooblayout_ecc(struct mtd_info *mtd, int section,
++				       struct mtd_oob_region *region)
++{
++	return -ERANGE;
++}
++
++static int spinand_noecc_ooblayout_free(struct mtd_info *mtd, int section,
++					struct mtd_oob_region *region)
++{
++	if (section)
++		return -ERANGE;
++
++	/* Reserve 2 bytes for the BBM. */
++	region->offset = 2;
++	region->length = 62;
++
++	return 0;
++}
++
++static const struct mtd_ooblayout_ops spinand_noecc_ooblayout = {
++	.ecc = spinand_noecc_ooblayout_ecc,
++	.free = spinand_noecc_ooblayout_free,
++};
++
++static int spinand_init(struct spinand_device *spinand)
++{
++	struct device *dev = &spinand->spimem->spi->dev;
++	struct mtd_info *mtd = spinand_to_mtd(spinand);
++	struct nand_device *nand = mtd_to_nanddev(mtd);
++	int ret, i;
++
++	/*
++	 * We need a scratch buffer because the spi_mem interface requires that
++	 * buf passed in spi_mem_op->data.buf be DMA-able.
++	 */
++	spinand->scratchbuf = kzalloc(SPINAND_MAX_ID_LEN, GFP_KERNEL);
++	if (!spinand->scratchbuf)
++		return -ENOMEM;
++
++	ret = spinand_detect(spinand);
++	if (ret)
++		goto err_free_bufs;
++
++	/*
++	 * Use kzalloc() instead of devm_kzalloc() here, because some drivers
++	 * may use this buffer for DMA access.
++	 * Memory allocated by devm_ does not guarantee DMA-safe alignment.
++	 */
++	spinand->databuf = kzalloc(nanddev_page_size(nand) +
++			       nanddev_per_page_oobsize(nand),
++			       GFP_KERNEL);
++	if (!spinand->databuf)
++		goto err_free_bufs;
++
++	spinand->oobbuf = spinand->databuf + nanddev_page_size(nand);
++
++	ret = spinand_init_cfg_cache(spinand);
++	if (ret)
++		goto err_free_bufs;
++
++	ret = spinand_manufacturer_init(spinand);
++	if (ret) {
++		dev_err(dev,
++			"Failed to initialize the SPI NAND chip (err = %d)\n",
++			ret);
++		goto err_free_bufs;
++	}
++
++	/* After power up, all blocks are locked, so unlock it here. */
++	for (i = 0; i < nand->memorg.ntargets; i++) {
++		spinand_select_target(spinand, i);
++		spinand_lock_block(spinand, BL_ALL_UNLOCKED);
++	}
++
++	ret = nanddev_init(nand, &spinand_ops, THIS_MODULE);
++	if (ret)
++		goto err_free_bufs;
++
++	/*
++	 * Right now, we don't support ECC, so let the whole oob
++	 * area is available for user.
++	 */
++	mtd->_read_oob = spinand_mtd_read;
++	mtd->_write_oob = spinand_mtd_write;
++	mtd->_block_isbad = spinand_mtd_block_isbad;
++	mtd->_block_markbad = spinand_mtd_block_markbad;
++	mtd->_block_isreserved = spinand_mtd_block_isreserved;
++	mtd->_erase = spinand_mtd_erase;
++
++	if (spinand->eccinfo.ooblayout)
++		mtd_set_ooblayout(mtd, spinand->eccinfo.ooblayout);
++	else
++		mtd_set_ooblayout(mtd, &spinand_noecc_ooblayout);
++
++	ret = mtd_ooblayout_count_freebytes(mtd);
++	if (ret < 0)
++		goto err_cleanup_nanddev;
++
++	return 0;
++
++err_cleanup_nanddev:
++	nanddev_cleanup(nand);
++
++err_free_bufs:
++	kfree(spinand->databuf);
++	kfree(spinand->scratchbuf);
++	return ret;
++}
++
++static void spinand_cleanup(struct spinand_device *spinand)
++{
++	struct nand_device *nand = &spinand->base;
++
++	spinand_manufacturer_cleanup(spinand);
++	nanddev_cleanup(nand);
++	kfree(spinand->databuf);
++	kfree(spinand->scratchbuf);
++}
++
++static int spinand_probe(struct spi_mem *mem)
++{
++	struct spinand_device *spinand;
++	struct mtd_info *mtd;
++	int ret;
++
++	spinand = devm_kzalloc(&mem->spi->dev, sizeof(*spinand),
++			       GFP_KERNEL);
++	if (!spinand)
++		return -ENOMEM;
++
++	spinand->spimem = mem;
++	spi_mem_set_drvdata(mem, spinand);
++	spinand_set_of_node(spinand, mem->spi->dev.of_node);
++	mutex_init(&spinand->lock);
++	mtd = spinand_to_mtd(spinand);
++	mtd->dev.parent = &mem->spi->dev;
++
++	ret = spinand_init(spinand);
++	if (ret)
++		return ret;
++
++	ret = mtd_device_register(mtd, NULL, 0);
++	if (ret)
++		goto err_spinand_cleanup;
++
++	return 0;
++
++err_spinand_cleanup:
++	spinand_cleanup(spinand);
++
++	return ret;
++}
++
++static int spinand_remove(struct spi_mem *mem)
++{
++	struct spinand_device *spinand;
++	struct mtd_info *mtd;
++	int ret;
++
++	spinand = spi_mem_get_drvdata(mem);
++	mtd = spinand_to_mtd(spinand);
++
++	ret = mtd_device_unregister(mtd);
++	if (ret)
++		return ret;
++
++	spinand_cleanup(spinand);
++
++	return 0;
++}
++
++static const struct spi_device_id spinand_ids[] = {
++	{ .name = "spi-nand" },
++	{ /* sentinel */ },
++};
++
++#ifdef CONFIG_OF
++static const struct of_device_id spinand_of_ids[] = {
++	{ .compatible = "spi-nand" },
++	{ /* sentinel */ },
++};
++#endif
++
++static struct spi_mem_driver spinand_drv = {
++	.spidrv = {
++		.id_table = spinand_ids,
++		.driver = {
++			.name = "spi-nand",
++			.of_match_table = of_match_ptr(spinand_of_ids),
++		},
++	},
++	.probe = spinand_probe,
++	.remove = spinand_remove,
++};
++module_spi_mem_driver(spinand_drv);
++
++MODULE_DESCRIPTION("SPI NAND framework");
++MODULE_AUTHOR("Peter Pan<peterpandong@micron.com>");
++MODULE_LICENSE("GPL v2");
+diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
+new file mode 100644
+index 0000000..17a4584
+--- /dev/null
++++ b/include/linux/mtd/spinand.h
+@@ -0,0 +1,415 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * Copyright (c) 2016-2017 Micron Technology, Inc.
++ *
++ *  Authors:
++ *	Peter Pan <peterpandong@micron.com>
++ */
++#ifndef __LINUX_MTD_SPINAND_H
++#define __LINUX_MTD_SPINAND_H
++
++#include <linux/mutex.h>
++#include <linux/bitops.h>
++#include <linux/device.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/nand.h>
++#include <linux/spi/spi.h>
++#include <linux/spi/spi-mem.h>
++
++/**
++ * Standard SPI NAND flash operations
++ */
++
++#define SPINAND_RESET_OP						\
++	SPI_MEM_OP(SPI_MEM_OP_CMD(0xff, 1),				\
++		   SPI_MEM_OP_NO_ADDR,					\
++		   SPI_MEM_OP_NO_DUMMY,					\
++		   SPI_MEM_OP_NO_DATA)
++
++#define SPINAND_WR_EN_DIS_OP(enable)					\
++	SPI_MEM_OP(SPI_MEM_OP_CMD((enable) ? 0x06 : 0x04, 1),		\
++		   SPI_MEM_OP_NO_ADDR,					\
++		   SPI_MEM_OP_NO_DUMMY,					\
++		   SPI_MEM_OP_NO_DATA)
++
++#define SPINAND_READID_OP(ndummy, buf, len)				\
++	SPI_MEM_OP(SPI_MEM_OP_CMD(0x9f, 1),				\
++		   SPI_MEM_OP_NO_ADDR,					\
++		   SPI_MEM_OP_DUMMY(ndummy, 1),				\
++		   SPI_MEM_OP_DATA_IN(len, buf, 1))
++
++#define SPINAND_SET_FEATURE_OP(reg, valptr)				\
++	SPI_MEM_OP(SPI_MEM_OP_CMD(0x1f, 1),				\
++		   SPI_MEM_OP_ADDR(1, reg, 1),				\
++		   SPI_MEM_OP_NO_DUMMY,					\
++		   SPI_MEM_OP_DATA_OUT(1, valptr, 1))
++
++#define SPINAND_GET_FEATURE_OP(reg, valptr)				\
++	SPI_MEM_OP(SPI_MEM_OP_CMD(0x0f, 1),				\
++		   SPI_MEM_OP_ADDR(1, reg, 1),				\
++		   SPI_MEM_OP_NO_DUMMY,					\
++		   SPI_MEM_OP_DATA_IN(1, valptr, 1))
++
++#define SPINAND_BLK_ERASE_OP(addr)					\
++	SPI_MEM_OP(SPI_MEM_OP_CMD(0xd8, 1),				\
++		   SPI_MEM_OP_ADDR(3, addr, 1),				\
++		   SPI_MEM_OP_NO_DUMMY,					\
++		   SPI_MEM_OP_NO_DATA)
++
++#define SPINAND_PAGE_READ_OP(addr)					\
++	SPI_MEM_OP(SPI_MEM_OP_CMD(0x13, 1),				\
++		   SPI_MEM_OP_ADDR(3, addr, 1),				\
++		   SPI_MEM_OP_NO_DUMMY,					\
++		   SPI_MEM_OP_NO_DATA)
++
++#define SPINAND_PAGE_READ_FROM_CACHE_OP(fast, addr, ndummy, buf, len)	\
++	SPI_MEM_OP(SPI_MEM_OP_CMD(fast ? 0x0b : 0x03, 1),		\
++		   SPI_MEM_OP_ADDR(2, addr, 1),				\
++		   SPI_MEM_OP_DUMMY(ndummy, 1),				\
++		   SPI_MEM_OP_DATA_IN(len, buf, 1))
++
++#define SPINAND_PAGE_READ_FROM_CACHE_X2_OP(addr, ndummy, buf, len)	\
++	SPI_MEM_OP(SPI_MEM_OP_CMD(0x3b, 1),				\
++		   SPI_MEM_OP_ADDR(2, addr, 1),				\
++		   SPI_MEM_OP_DUMMY(ndummy, 1),				\
++		   SPI_MEM_OP_DATA_IN(len, buf, 2))
++
++#define SPINAND_PAGE_READ_FROM_CACHE_X4_OP(addr, ndummy, buf, len)	\
++	SPI_MEM_OP(SPI_MEM_OP_CMD(0x6b, 1),				\
++		   SPI_MEM_OP_ADDR(2, addr, 1),				\
++		   SPI_MEM_OP_DUMMY(ndummy, 1),				\
++		   SPI_MEM_OP_DATA_IN(len, buf, 4))
++
++#define SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(addr, ndummy, buf, len)	\
++	SPI_MEM_OP(SPI_MEM_OP_CMD(0xbb, 1),				\
++		   SPI_MEM_OP_ADDR(2, addr, 2),				\
++		   SPI_MEM_OP_DUMMY(ndummy, 2),				\
++		   SPI_MEM_OP_DATA_IN(len, buf, 2))
++
++#define SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(addr, ndummy, buf, len)	\
++	SPI_MEM_OP(SPI_MEM_OP_CMD(0xeb, 1),				\
++		   SPI_MEM_OP_ADDR(2, addr, 4),				\
++		   SPI_MEM_OP_DUMMY(ndummy, 4),				\
++		   SPI_MEM_OP_DATA_IN(len, buf, 4))
++
++#define SPINAND_PROG_EXEC_OP(addr)					\
++	SPI_MEM_OP(SPI_MEM_OP_CMD(0x10, 1),				\
++		   SPI_MEM_OP_ADDR(3, addr, 1),				\
++		   SPI_MEM_OP_NO_DUMMY,					\
++		   SPI_MEM_OP_NO_DATA)
++
++#define SPINAND_PROG_LOAD(reset, addr, buf, len)			\
++	SPI_MEM_OP(SPI_MEM_OP_CMD(reset ? 0x02 : 0x84, 1),		\
++		   SPI_MEM_OP_ADDR(2, addr, 1),				\
++		   SPI_MEM_OP_NO_DUMMY,					\
++		   SPI_MEM_OP_DATA_OUT(len, buf, 1))
++
++#define SPINAND_PROG_LOAD_X4(reset, addr, buf, len)			\
++	SPI_MEM_OP(SPI_MEM_OP_CMD(reset ? 0x32 : 0x34, 1),		\
++		   SPI_MEM_OP_ADDR(2, addr, 1),				\
++		   SPI_MEM_OP_NO_DUMMY,					\
++		   SPI_MEM_OP_DATA_OUT(len, buf, 4))
++
++/**
++ * Standard SPI NAND flash commands
++ */
++#define SPINAND_CMD_PROG_LOAD_X4		0x32
++#define SPINAND_CMD_PROG_LOAD_RDM_DATA_X4	0x34
++
++/* feature register */
++#define REG_BLOCK_LOCK		0xa0
++#define BL_ALL_UNLOCKED		0x00
++
++/* configuration register */
++#define REG_CFG			0xb0
++#define CFG_ECC_ENABLE		BIT(4)
++#define CFG_QUAD_ENABLE		BIT(0)
++
++/* status register */
++#define REG_STATUS		0xc0
++#define STATUS_BUSY		BIT(0)
++#define STATUS_ERASE_FAILED	BIT(2)
++#define STATUS_PROG_FAILED	BIT(3)
++#define STATUS_ECC_MASK		GENMASK(5, 4)
++#define STATUS_ECC_NO_BITFLIPS	(0 << 4)
++#define STATUS_ECC_HAS_BITFLIPS	(1 << 4)
++#define STATUS_ECC_UNCOR_ERROR	(2 << 4)
++
++struct spinand_op;
++struct spinand_device;
++
++#define SPINAND_MAX_ID_LEN	4
++
++/**
++ * struct spinand_id - SPI NAND id structure
++ * @data: buffer containing the id bytes. Currently 4 bytes large, but can
++ *	  be extended if required
++ * @len: ID length
++ *
++ * struct_spinand_id->data contains all bytes returned after a READ_ID command,
++ * including dummy bytes if the chip does not emit ID bytes right after the
++ * READ_ID command. The responsibility to extract real ID bytes is left to
++ * struct_manufacurer_ops->detect().
++ */
++struct spinand_id {
++	u8 data[SPINAND_MAX_ID_LEN];
++	int len;
++};
++
++/**
++ * struct manufacurer_ops - SPI NAND manufacturer specific operations
++ * @detect: detect a SPI NAND device. Every time a SPI NAND device is probed
++ *	    the core calls the struct_manufacurer_ops->detect() hook of each
++ *	    registered manufacturer until one of them return 1. Note that
++ *	    the first thing to check in this hook is that the manufacturer ID
++ *	    in struct_spinand_device->id matches the manufacturer whose
++ *	    ->detect() hook has been called. Should return 1 if there's a
++ *	    match, 0 if the manufacturer ID does not match and a negative
++ *	    error code otherwise. When true is returned, the core assumes
++ *	    that properties of the NAND chip (spinand->base.memorg and
++ *	    spinand->base.eccreq) have been filled
++ * @init: initialize a SPI NAND device
++ * @cleanup: cleanup a SPI NAND device
++ *
++ * Each SPI NAND manufacturer driver should implement this interface so that
++ * NAND chips coming from this vendor can be detected and initialized properly.
++ */
++struct spinand_manufacturer_ops {
++	int (*detect)(struct spinand_device *spinand);
++	int (*init)(struct spinand_device *spinand);
++	void (*cleanup)(struct spinand_device *spinand);
++};
++
++/**
++ * struct spinand_manufacturer - SPI NAND manufacturer instance
++ * @id: manufacturer ID
++ * @name: manufacturer name
++ * @ops: manufacturer operations
++ */
++struct spinand_manufacturer {
++	u8 id;
++	char *name;
++	const struct spinand_manufacturer_ops *ops;
++};
++
++/**
++ * struct spinand_op_variants - SPI NAND operation variants
++ * @ops: the list of variants for a given operation
++ * @nops: the number of variants
++ *
++ * Some operations like read-from-cache/write-to-cache have several variants
++ * depending on the number of IO lines you use to transfer data or address
++ * cycles. This structure is a way to describe the different variants supported
++ * by a chip and let the core pick the best one based on the SPI mem controller
++ * capabilities.
++ */
++struct spinand_op_variants {
++	const struct spi_mem_op *ops;
++	unsigned int nops;
++};
++
++#define SPINAND_OP_VARIANTS(name, ...)					\
++	const struct spinand_op_variants name = {			\
++		.ops = (struct spi_mem_op[]) { __VA_ARGS__ },		\
++		.nops = sizeof((struct spi_mem_op[]){ __VA_ARGS__ }) /	\
++			sizeof(struct spi_mem_op),			\
++	}
++
++/**
++ * spinand_ecc_info - description of the on-die ECC implemented by a SPI NAND
++ *		      chip
++ * @get_status: get the ECC status. Should return a positive number encoding
++ *		the number of corrected bitflips if correction was possible or
++ *		-EBADMSG if there are uncorrectable errors. I can also return
++ *		other negative error codes if the error is not caused by
++ *		uncorrectable bitflips
++ * @ooblayout: the OOB layout used by the on-die ECC implementation
++ */
++struct spinand_ecc_info {
++	int (*get_status)(struct spinand_device *spinand, u8 status);
++	const struct mtd_ooblayout_ops *ooblayout;
++};
++
++#define SPINAND_HAS_QE_BIT		BIT(0)
++
++/**
++ * struct spinand_info - Structure used to describe SPI NAND chips
++ * @model: model name
++ * @devid: device ID
++ * @flags: OR-ing of the SPINAND_XXX flags
++ * @memorg: memory organization
++ * @eccreq: ECC requirements
++ * @eccinfo: on-die ECC info
++ * @op_variants: operations variants
++ * @op_variants.read_cache: variants of the read-cache operation
++ * @op_variants.write_cache: variants of the write-cache operation
++ * @op_variants.update_cache: variants of the update-cache operation
++ * @select_target: function used to select a target/die. Required only for
++ *		   multi-die chips
++ *
++ * Each SPI NAND manufacturer driver should have a spinand_info table
++ * describing all the chips supported by the driver.
++ */
++struct spinand_info {
++	const char *model;
++	u8 devid;
++	u32 flags;
++	struct nand_memory_organization memorg;
++	struct nand_ecc_req eccreq;
++	struct spinand_ecc_info eccinfo;
++	struct {
++		const struct spinand_op_variants *read_cache;
++		const struct spinand_op_variants *write_cache;
++		const struct spinand_op_variants *update_cache;
++	} op_variants;
++	int (*select_target)(struct spinand_device *spinand,
++			     unsigned int target);
++};
++
++#define SPINAND_INFO_OP_VARIANTS(__read, __write, __update)		\
++	{								\
++		.read_cache = __read,					\
++		.write_cache = __write,					\
++		.update_cache = __update,				\
++	}
++
++#define SPINAND_ECCINFO(__ooblayout, __get_status)			\
++	.eccinfo = {							\
++		.ooblayout = __ooblayout,				\
++		.get_status = __get_status,				\
++	}
++
++#define SPINAND_SELECT_TARGET(__func)					\
++	.select_target = __func,
++
++#define SPINAND_INFO(__model, __id, __memorg, __eccreq, __op_variants,	\
++		     __flags, ...)					\
++	{								\
++		.model = __model,					\
++		.devid = __id,						\
++		.memorg = __memorg,					\
++		.eccreq = __eccreq,					\
++		.op_variants = __op_variants,				\
++		.flags = __flags,					\
++		__VA_ARGS__						\
++	}
++
++/**
++ * struct spinand_device - SPI NAND device instance
++ * @base: NAND device instance
++ * @spimem: pointer to the SPI mem object
++ * @lock: lock used to serialize accesses to the NAND
++ * @id: NAND ID as returned by READ_ID
++ * @flags: NAND flags
++ * @op_templates: various SPI mem op templates
++ * @op_templates.read_cache: read cache op template
++ * @op_templates.write_cache: write cache op template
++ * @op_templates.update_cache: update cache op template
++ * @select_target: select a specific target/die. Usually called before sending
++ *		   a command addressing a page or an eraseblock embedded in
++ *		   this die. Only required if your chip exposes several dies
++ * @cur_target: currently selected target/die
++ * @eccinfo: on-die ECC information
++ * @cfg_cache: config register cache. One entry per die
++ * @databuf: bounce buffer for data
++ * @oobbuf: bounce buffer for OOB data
++ * @scratchbuf: buffer used for everything but page accesses. This is needed
++ *		because the spi-mem interface explicitly requests that buffers
++ *		passed in spi_mem_op be DMA-able, so we can't based the bufs on
++ *		the stack
++ * @manufacturer: SPI NAND manufacturer information
++ * @priv: manufacturer private data
++ */
++struct spinand_device {
++	struct nand_device base;
++	struct spi_mem *spimem;
++	struct mutex lock;
++	struct spinand_id id;
++	u32 flags;
++
++	struct {
++		const struct spi_mem_op *read_cache;
++		const struct spi_mem_op *write_cache;
++		const struct spi_mem_op *update_cache;
++	} op_templates;
++
++	int (*select_target)(struct spinand_device *spinand,
++			     unsigned int target);
++	unsigned int cur_target;
++
++	struct spinand_ecc_info eccinfo;
++
++	u8 *cfg_cache;
++	u8 *databuf;
++	u8 *oobbuf;
++	u8 *scratchbuf;
++	const struct spinand_manufacturer *manufacturer;
++	void *priv;
++};
++
++/**
++ * mtd_to_spinand() - Get the SPI NAND device attached to an MTD instance
++ * @mtd: MTD instance
++ *
++ * Return: the SPI NAND device attached to @mtd.
++ */
++static inline struct spinand_device *mtd_to_spinand(struct mtd_info *mtd)
++{
++	return container_of(mtd_to_nanddev(mtd), struct spinand_device, base);
++}
++
++/**
++ * spinand_to_mtd() - Get the MTD device embedded in a SPI NAND device
++ * @spinand: SPI NAND device
++ *
++ * Return: the MTD device embedded in @spinand.
++ */
++static inline struct mtd_info *spinand_to_mtd(struct spinand_device *spinand)
++{
++	return nanddev_to_mtd(&spinand->base);
++}
++
++/**
++ * nand_to_spinand() - Get the SPI NAND device embedding an NAND object
++ * @nand: NAND object
++ *
++ * Return: the SPI NAND device embedding @nand.
++ */
++static inline struct spinand_device *nand_to_spinand(struct nand_device *nand)
++{
++	return container_of(nand, struct spinand_device, base);
++}
++
++/**
++ * spinand_to_nand() - Get the NAND device embedded in a SPI NAND object
++ * @spinand: SPI NAND device
++ *
++ * Return: the NAND device embedded in @spinand.
++ */
++static inline struct nand_device *
++spinand_to_nand(struct spinand_device *spinand)
++{
++	return &spinand->base;
++}
++
++/**
++ * spinand_set_of_node - Attach a DT node to a SPI NAND device
++ * @spinand: SPI NAND device
++ * @np: DT node
++ *
++ * Attach a DT node to a SPI NAND device.
++ */
++static inline void spinand_set_of_node(struct spinand_device *spinand,
++				       struct device_node *np)
++{
++	nanddev_set_of_node(&spinand->base, np);
++}
++
++int spinand_match_and_init(struct spinand_device *dev,
++			   const struct spinand_info *table,
++			   unsigned int table_size, u8 devid);
++
++int spinand_upd_cfg(struct spinand_device *spinand, u8 mask, u8 val);
++int spinand_select_target(struct spinand_device *spinand, unsigned int target);
++
++#endif /* __LINUX_MTD_SPINAND_H */
+diff --git a/include/linux/spi/spi-mem.h b/include/linux/spi/spi-mem.h
+index ac2e8d8..7726bad 100644
+--- a/include/linux/spi/spi-mem.h
++++ b/include/linux/spi/spi-mem.h
+@@ -3,7 +3,9 @@
+  * Copyright (C) 2018 Exceet Electronics GmbH
+  * Copyright (C) 2018 Bootlin
+  *
+- * Author: Boris Brezillon <boris.brezillon@bootlin.com>
++ * Author:
++ *	Peter Pan <peterpandong@micron.com>
++ *	Boris Brezillon <boris.brezillon@bootlin.com>
+  */
+ 
+ #ifndef __LINUX_SPI_MEM_H
+-- 
+2.7.4
+
diff --git a/recipes-kernel/linux/linux-stm32mp/patches/0018-dt-bindings-Add-bindings-for-SPI-NAND-devices.patch b/recipes-kernel/linux/linux-stm32mp/patches/0018-dt-bindings-Add-bindings-for-SPI-NAND-devices.patch
new file mode 100644
index 0000000000000000000000000000000000000000..cb6956f96b5ef674ab7b26b0a7e8ba444126a453
--- /dev/null
+++ b/recipes-kernel/linux/linux-stm32mp/patches/0018-dt-bindings-Add-bindings-for-SPI-NAND-devices.patch
@@ -0,0 +1,49 @@
+From bb01e3b0cb0c985e91205bcc28331827f7fa4597 Mon Sep 17 00:00:00 2001
+From: Boris Brezillon <boris.brezillon@bootlin.com>
+Date: Tue, 15 May 2018 17:08:23 +0200
+Subject: [PATCH 18/28] dt-bindings: Add bindings for SPI NAND devices
+
+Add bindigns for SPI NAND chips.
+
+Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
+---
+ Documentation/devicetree/bindings/mtd/spi-nand.txt | 27 ++++++++++++++++++++++
+ 1 file changed, 27 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/mtd/spi-nand.txt
+
+diff --git a/Documentation/devicetree/bindings/mtd/spi-nand.txt b/Documentation/devicetree/bindings/mtd/spi-nand.txt
+new file mode 100644
+index 0000000..d55f801
+--- /dev/null
++++ b/Documentation/devicetree/bindings/mtd/spi-nand.txt
+@@ -0,0 +1,27 @@
++SPI NAND flash
++
++Required properties:
++- compatible: should be "spi-nand"
++- reg: should encode the chip-select line used to access the NAND chip
++
++Optional properties
++- spi-max-frequency: maximum frequency of the SPI bus the chip can operate at.
++		     This should encode board limitations (i.e. max freq can't
++		     be achieved due to crosstalk on IO lines).
++		     When unspecified, the driver assumes the chip can run at
++		     the max frequency defined in the spec (information
++		     extracted chip detection time).
++- spi-tx-bus-width: The bus width (number of data wires) that is used for MOSI.
++		    Only encodes the board constraints (i.e. when not all IO
++		    signals are routed on the board). Device constraints are
++		    extracted when detecting the chip, and controller
++		    constraints are exposed by the SPI mem controller. If this
++		    property is missing that means no constraint at the board
++		    level.
++- spi-rx-bus-width: The bus width (number of data wires) that is used for MISO.
++		    Only encodes the board constraints (i.e. when not all IO
++		    signals are routed on the board). Device constraints are
++		    extracted when detecting the chip, and controller
++		    constraints are exposed by the SPI mem controller. If this
++		    property is missing that means no constraint at the board
++		    level.
+-- 
+2.7.4
+
diff --git a/recipes-kernel/linux/linux-stm32mp/patches/0019-mtd-nand-spi-Add-initial-support-for-Micron-MT29F2G0.patch b/recipes-kernel/linux/linux-stm32mp/patches/0019-mtd-nand-spi-Add-initial-support-for-Micron-MT29F2G0.patch
new file mode 100644
index 0000000000000000000000000000000000000000..248ecfc2a1b1022aef49fe752cb6dd44b187d021
--- /dev/null
+++ b/recipes-kernel/linux/linux-stm32mp/patches/0019-mtd-nand-spi-Add-initial-support-for-Micron-MT29F2G0.patch
@@ -0,0 +1,214 @@
+From 930655c128d16062822617589c3b31425203bc9e Mon Sep 17 00:00:00 2001
+From: Peter Pan <peterpandong@micron.com>
+Date: Tue, 15 May 2018 17:08:24 +0200
+Subject: [PATCH 19/28] mtd: nand: spi: Add initial support for Micron
+ MT29F2G01ABAGD
+
+Add a basic driver for Micron SPI NANDs. Only one device is supported
+right now, but the driver will be extended to support more devices
+afterwards.
+
+Signed-off-by: Peter Pan <peterpandong@micron.com>
+Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
+---
+ drivers/mtd/nand/spi/Makefile |   2 +-
+ drivers/mtd/nand/spi/core.c   |  17 ++++++
+ drivers/mtd/nand/spi/micron.c | 133 ++++++++++++++++++++++++++++++++++++++++++
+ include/linux/mtd/spinand.h   |   3 +
+ 4 files changed, 154 insertions(+), 1 deletion(-)
+ create mode 100644 drivers/mtd/nand/spi/micron.c
+
+diff --git a/drivers/mtd/nand/spi/Makefile b/drivers/mtd/nand/spi/Makefile
+index feb79a1..79a1f1e 100644
+--- a/drivers/mtd/nand/spi/Makefile
++++ b/drivers/mtd/nand/spi/Makefile
+@@ -1,2 +1,2 @@
+-spinand-objs := core.o
++spinand-objs := core.o micron.o
+ obj-$(CONFIG_MTD_SPI_NAND) += spinand.o
+diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
+index faad9bc..a4b8906 100644
+--- a/drivers/mtd/nand/spi/core.c
++++ b/drivers/mtd/nand/spi/core.c
+@@ -767,8 +767,25 @@ static const struct nand_ops spinand_ops = {
+ 	.isbad = spinand_isbad,
+ };
+ 
++static const struct spinand_manufacturer *spinand_manufacturers[] = {
++	&micron_spinand_manufacturer,
++};
++
+ static int spinand_manufacturer_detect(struct spinand_device *spinand)
+ {
++	unsigned int i;
++	int ret;
++
++	for (i = 0; i < ARRAY_SIZE(spinand_manufacturers); i++) {
++		ret = spinand_manufacturers[i]->ops->detect(spinand);
++		if (ret > 0) {
++			spinand->manufacturer = spinand_manufacturers[i];
++			return 0;
++		} else if (ret < 0) {
++			return ret;
++		}
++	}
++
+ 	return -ENOTSUPP;
+ }
+ 
+diff --git a/drivers/mtd/nand/spi/micron.c b/drivers/mtd/nand/spi/micron.c
+new file mode 100644
+index 0000000..9c4381d
+--- /dev/null
++++ b/drivers/mtd/nand/spi/micron.c
+@@ -0,0 +1,133 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (c) 2016-2017 Micron Technology, Inc.
++ *
++ * Authors:
++ *	Peter Pan <peterpandong@micron.com>
++ */
++
++#include <linux/device.h>
++#include <linux/kernel.h>
++#include <linux/mtd/spinand.h>
++
++#define SPINAND_MFR_MICRON		0x2c
++
++#define MICRON_STATUS_ECC_MASK		GENMASK(7, 4)
++#define MICRON_STATUS_ECC_NO_BITFLIPS	(0 << 4)
++#define MICRON_STATUS_ECC_1TO3_BITFLIPS	(1 << 4)
++#define MICRON_STATUS_ECC_4TO6_BITFLIPS	(3 << 4)
++#define MICRON_STATUS_ECC_7TO8_BITFLIPS	(5 << 4)
++
++static SPINAND_OP_VARIANTS(read_cache_variants,
++		SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
++		SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
++		SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
++		SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
++		SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
++		SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
++
++static SPINAND_OP_VARIANTS(write_cache_variants,
++		SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
++		SPINAND_PROG_LOAD(true, 0, NULL, 0));
++
++static SPINAND_OP_VARIANTS(update_cache_variants,
++		SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
++		SPINAND_PROG_LOAD(false, 0, NULL, 0));
++
++static int mt29f2g01abagd_ooblayout_ecc(struct mtd_info *mtd, int section,
++					struct mtd_oob_region *region)
++{
++	if (section)
++		return -ERANGE;
++
++	region->offset = 64;
++	region->length = 64;
++
++	return 0;
++}
++
++static int mt29f2g01abagd_ooblayout_free(struct mtd_info *mtd, int section,
++					 struct mtd_oob_region *region)
++{
++	if (section)
++		return -ERANGE;
++
++	/* Reserve 2 bytes for the BBM. */
++	region->offset = 2;
++	region->length = 62;
++
++	return 0;
++}
++
++static const struct mtd_ooblayout_ops mt29f2g01abagd_ooblayout = {
++	.ecc = mt29f2g01abagd_ooblayout_ecc,
++	.free = mt29f2g01abagd_ooblayout_free,
++};
++
++static int mt29f2g01abagd_ecc_get_status(struct spinand_device *spinand,
++					 u8 status)
++{
++	switch (status & MICRON_STATUS_ECC_MASK) {
++	case STATUS_ECC_NO_BITFLIPS:
++		return 0;
++
++	case STATUS_ECC_UNCOR_ERROR:
++		return -EBADMSG;
++
++	case MICRON_STATUS_ECC_1TO3_BITFLIPS:
++		return 3;
++
++	case MICRON_STATUS_ECC_4TO6_BITFLIPS:
++		return 6;
++
++	case MICRON_STATUS_ECC_7TO8_BITFLIPS:
++		return 8;
++
++	default:
++		break;
++	}
++
++	return -EINVAL;
++}
++
++static const struct spinand_info micron_spinand_table[] = {
++	SPINAND_INFO("MT29F2G01ABAGD", 0x24,
++		     NAND_MEMORG(1, 2048, 128, 64, 2048, 2, 1, 1),
++		     NAND_ECCREQ(8, 512),
++		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
++					      &write_cache_variants,
++					      &update_cache_variants),
++		     0,
++		     SPINAND_ECCINFO(&mt29f2g01abagd_ooblayout,
++				     mt29f2g01abagd_ecc_get_status)),
++};
++
++static int micron_spinand_detect(struct spinand_device *spinand)
++{
++	u8 *id = spinand->id.data;
++	int ret;
++
++	/*
++	 * Micron SPI NAND read ID need a dummy byte,
++	 * so the first byte in raw_id is dummy.
++	 */
++	if (id[1] != SPINAND_MFR_MICRON)
++		return 0;
++
++	ret = spinand_match_and_init(spinand, micron_spinand_table,
++				     ARRAY_SIZE(micron_spinand_table), id[2]);
++	if (ret)
++		return ret;
++
++	return 1;
++}
++
++static const struct spinand_manufacturer_ops micron_spinand_manuf_ops = {
++	.detect = micron_spinand_detect,
++};
++
++const struct spinand_manufacturer micron_spinand_manufacturer = {
++	.id = SPINAND_MFR_MICRON,
++	.name = "Micron",
++	.ops = &micron_spinand_manuf_ops,
++};
+diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
+index 17a4584..11a18c1 100644
+--- a/include/linux/mtd/spinand.h
++++ b/include/linux/mtd/spinand.h
+@@ -192,6 +192,9 @@ struct spinand_manufacturer {
+ 	const struct spinand_manufacturer_ops *ops;
+ };
+ 
++/* SPI NAND manufacturers */
++extern const struct spinand_manufacturer micron_spinand_manufacturer;
++
+ /**
+  * struct spinand_op_variants - SPI NAND operation variants
+  * @ops: the list of variants for a given operation
+-- 
+2.7.4
+
diff --git a/recipes-kernel/linux/linux-stm32mp/patches/0020-mtd-nand-spi-Add-initial-support-for-Winbond-W25M02G.patch b/recipes-kernel/linux/linux-stm32mp/patches/0020-mtd-nand-spi-Add-initial-support-for-Winbond-W25M02G.patch
new file mode 100644
index 0000000000000000000000000000000000000000..396905be4028eb701337f0432bfab77e0c1648cb
--- /dev/null
+++ b/recipes-kernel/linux/linux-stm32mp/patches/0020-mtd-nand-spi-Add-initial-support-for-Winbond-W25M02G.patch
@@ -0,0 +1,198 @@
+From 79d6d6da4e616c7010fe460dbb24a5ac4aed48e8 Mon Sep 17 00:00:00 2001
+From: Frieder Schrempf <frieder.schrempf@exceet.de>
+Date: Tue, 15 May 2018 17:08:25 +0200
+Subject: [PATCH 20/28] mtd: nand: spi: Add initial support for Winbond
+ W25M02GV
+
+Signed-off-by: Frieder Schrempf <frieder.schrempf@exceet.de>
+Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
+---
+ drivers/mtd/nand/spi/Makefile  |   2 +-
+ drivers/mtd/nand/spi/core.c    |   1 +
+ drivers/mtd/nand/spi/winbond.c | 141 +++++++++++++++++++++++++++++++++++++++++
+ include/linux/mtd/spinand.h    |   1 +
+ 4 files changed, 144 insertions(+), 1 deletion(-)
+ create mode 100644 drivers/mtd/nand/spi/winbond.c
+
+diff --git a/drivers/mtd/nand/spi/Makefile b/drivers/mtd/nand/spi/Makefile
+index 79a1f1e..983a94f 100644
+--- a/drivers/mtd/nand/spi/Makefile
++++ b/drivers/mtd/nand/spi/Makefile
+@@ -1,2 +1,2 @@
+-spinand-objs := core.o micron.o
++spinand-objs := core.o micron.o winbond.o
+ obj-$(CONFIG_MTD_SPI_NAND) += spinand.o
+diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
+index a4b8906..057adb5 100644
+--- a/drivers/mtd/nand/spi/core.c
++++ b/drivers/mtd/nand/spi/core.c
+@@ -769,6 +769,7 @@ static const struct nand_ops spinand_ops = {
+ 
+ static const struct spinand_manufacturer *spinand_manufacturers[] = {
+ 	&micron_spinand_manufacturer,
++	&winbond_spinand_manufacturer,
+ };
+ 
+ static int spinand_manufacturer_detect(struct spinand_device *spinand)
+diff --git a/drivers/mtd/nand/spi/winbond.c b/drivers/mtd/nand/spi/winbond.c
+new file mode 100644
+index 0000000..67baa1b
+--- /dev/null
++++ b/drivers/mtd/nand/spi/winbond.c
+@@ -0,0 +1,141 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (c) 2017 exceet electronics GmbH
++ *
++ * Authors:
++ *	Frieder Schrempf <frieder.schrempf@exceet.de>
++ *	Boris Brezillon <boris.brezillon@bootlin.com>
++ */
++
++#include <linux/device.h>
++#include <linux/kernel.h>
++#include <linux/mtd/spinand.h>
++
++#define SPINAND_MFR_WINBOND		0xEF
++
++#define WINBOND_CFG_BUF_READ		BIT(3)
++
++static SPINAND_OP_VARIANTS(read_cache_variants,
++		SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
++		SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
++		SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
++		SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
++		SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
++		SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
++
++static SPINAND_OP_VARIANTS(write_cache_variants,
++		SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
++		SPINAND_PROG_LOAD(true, 0, NULL, 0));
++
++static SPINAND_OP_VARIANTS(update_cache_variants,
++		SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
++		SPINAND_PROG_LOAD(false, 0, NULL, 0));
++
++static int w25m02gv_ooblayout_ecc(struct mtd_info *mtd, int section,
++				  struct mtd_oob_region *region)
++{
++	if (section > 3)
++		return -ERANGE;
++
++	region->offset = (16 * section) + 8;
++	region->length = 8;
++
++	return 0;
++}
++
++static int w25m02gv_ooblayout_free(struct mtd_info *mtd, int section,
++				   struct mtd_oob_region *region)
++{
++	if (section > 3)
++		return -ERANGE;
++
++	region->offset = (16 * section) + 2;
++	region->length = 6;
++
++	return 0;
++}
++
++static const struct mtd_ooblayout_ops w25m02gv_ooblayout = {
++	.ecc = w25m02gv_ooblayout_ecc,
++	.free = w25m02gv_ooblayout_free,
++};
++
++static int w25m02gv_select_target(struct spinand_device *spinand,
++				  unsigned int target)
++{
++	struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(0xc2, 1),
++					  SPI_MEM_OP_NO_ADDR,
++					  SPI_MEM_OP_NO_DUMMY,
++					  SPI_MEM_OP_DATA_OUT(1,
++							spinand->scratchbuf,
++							1));
++
++	*spinand->scratchbuf = target;
++	return spi_mem_exec_op(spinand->spimem, &op);
++}
++
++static const struct spinand_info winbond_spinand_table[] = {
++	SPINAND_INFO("W25M02GV", 0xAB,
++		     NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 2),
++		     NAND_ECCREQ(1, 512),
++		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
++					      &write_cache_variants,
++					      &update_cache_variants),
++		     0,
++		     SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL),
++		     SPINAND_SELECT_TARGET(w25m02gv_select_target)),
++};
++
++/**
++ * winbond_spinand_detect - initialize device related part in spinand_device
++ * struct if it is a Winbond device.
++ * @spinand: SPI NAND device structure
++ */
++static int winbond_spinand_detect(struct spinand_device *spinand)
++{
++	u8 *id = spinand->id.data;
++	int ret;
++
++	/*
++	 * Winbond SPI NAND read ID need a dummy byte,
++	 * so the first byte in raw_id is dummy.
++	 */
++	if (id[1] != SPINAND_MFR_WINBOND)
++		return 0;
++
++	ret = spinand_match_and_init(spinand, winbond_spinand_table,
++				     ARRAY_SIZE(winbond_spinand_table), id[2]);
++	if (ret)
++		return ret;
++
++	return 1;
++}
++
++static int winbond_spinand_init(struct spinand_device *spinand)
++{
++	struct nand_device *nand = spinand_to_nand(spinand);
++	unsigned int i;
++
++	/*
++	 * Make sure all dies are in buffer read mode and not continuous read
++	 * mode.
++	 */
++	for (i = 0; i < nand->memorg.ntargets; i++) {
++		spinand_select_target(spinand, i);
++		spinand_upd_cfg(spinand, WINBOND_CFG_BUF_READ,
++				WINBOND_CFG_BUF_READ);
++	}
++
++	return 0;
++}
++
++static const struct spinand_manufacturer_ops winbond_spinand_manuf_ops = {
++	.detect = winbond_spinand_detect,
++	.init = winbond_spinand_init,
++};
++
++const struct spinand_manufacturer winbond_spinand_manufacturer = {
++	.id = SPINAND_MFR_WINBOND,
++	.name = "Winbond",
++	.ops = &winbond_spinand_manuf_ops,
++};
+diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
+index 11a18c1..31d9936 100644
+--- a/include/linux/mtd/spinand.h
++++ b/include/linux/mtd/spinand.h
+@@ -194,6 +194,7 @@ struct spinand_manufacturer {
+ 
+ /* SPI NAND manufacturers */
+ extern const struct spinand_manufacturer micron_spinand_manufacturer;
++extern const struct spinand_manufacturer winbond_spinand_manufacturer;
+ 
+ /**
+  * struct spinand_op_variants - SPI NAND operation variants
+-- 
+2.7.4
+
diff --git a/recipes-kernel/linux/linux-stm32mp/patches/0021-spi-create-spi-mem-based-driver-for-stm32-QSPI.patch b/recipes-kernel/linux/linux-stm32mp/patches/0021-spi-create-spi-mem-based-driver-for-stm32-QSPI.patch
new file mode 100644
index 0000000000000000000000000000000000000000..66a25dd7a7c53d3f07e831e9168768624164847f
--- /dev/null
+++ b/recipes-kernel/linux/linux-stm32mp/patches/0021-spi-create-spi-mem-based-driver-for-stm32-QSPI.patch
@@ -0,0 +1,596 @@
+From 24d60da60c58f3b9769bc9a25d941dbedd7131df Mon Sep 17 00:00:00 2001
+From: Frieder Schrempf <frieder.schrempf@exceet.de>
+Date: Mon, 30 Apr 2018 10:13:15 +0200
+Subject: [PATCH 21/28] spi: create spi-mem based driver for stm32 QSPI
+
+TODO:
+* set correct fsize
+* use memory mapped mode
+* use DMA
+---
+ drivers/mtd/spi-nor/Kconfig  |   7 -
+ drivers/mtd/spi-nor/Makefile |   1 -
+ drivers/spi/Kconfig          |   8 +
+ drivers/spi/Makefile         |   1 +
+ drivers/spi/spi-stm32-qspi.c | 513 +++++++++++++++++++++++++++++++++++++++++++
+ 5 files changed, 522 insertions(+), 8 deletions(-)
+ create mode 100644 drivers/spi/spi-stm32-qspi.c
+
+diff --git a/drivers/mtd/spi-nor/Kconfig b/drivers/mtd/spi-nor/Kconfig
+index 69c638d..fa67256 100644
+--- a/drivers/mtd/spi-nor/Kconfig
++++ b/drivers/mtd/spi-nor/Kconfig
+@@ -122,11 +122,4 @@ config SPI_INTEL_SPI_PLATFORM
+ 	  To compile this driver as a module, choose M here: the module
+ 	  will be called intel-spi-platform.
+ 
+-config SPI_STM32_QUADSPI
+-	tristate "STM32 Quad SPI controller"
+-	depends on ARCH_STM32 || COMPILE_TEST
+-	help
+-	  This enables support for the STM32 Quad SPI controller.
+-	  We only connect the NOR to this controller.
+-
+ endif # MTD_SPI_NOR
+diff --git a/drivers/mtd/spi-nor/Makefile b/drivers/mtd/spi-nor/Makefile
+index f4c61d2..5d61422 100644
+--- a/drivers/mtd/spi-nor/Makefile
++++ b/drivers/mtd/spi-nor/Makefile
+@@ -10,4 +10,3 @@ obj-$(CONFIG_SPI_NXP_SPIFI)	+= nxp-spifi.o
+ obj-$(CONFIG_SPI_INTEL_SPI)	+= intel-spi.o
+ obj-$(CONFIG_SPI_INTEL_SPI_PCI)	+= intel-spi-pci.o
+ obj-$(CONFIG_SPI_INTEL_SPI_PLATFORM)	+= intel-spi-platform.o
+-obj-$(CONFIG_SPI_STM32_QUADSPI)	+= stm32-quadspi.o
+diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
+index 378e6a4..9d26ac4 100644
+--- a/drivers/spi/Kconfig
++++ b/drivers/spi/Kconfig
+@@ -643,6 +643,14 @@ config SPI_STM32
+ 	  is not available, the driver automatically falls back to
+ 	  PIO mode.
+ 
++config SPI_STM32_QUADSPI
++	tristate "STM32 Quad SPI controller"
++	depends on ARCH_STM32 || COMPILE_TEST
++	help
++	  This enables support for the STM32 Quad SPI controller.
++	  This controller does not support generic SPI. It only supports the
++	  high-level SPI memory interface.
++
+ config SPI_ST_SSC4
+ 	tristate "STMicroelectronics SPI SSC-based driver"
+ 	depends on ARCH_STI || COMPILE_TEST
+diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
+index d95bfe9..60ff432 100644
+--- a/drivers/spi/Makefile
++++ b/drivers/spi/Makefile
+@@ -93,6 +93,7 @@ obj-$(CONFIG_SPI_SH_MSIOF)		+= spi-sh-msiof.o
+ obj-$(CONFIG_SPI_SH_SCI)		+= spi-sh-sci.o
+ obj-$(CONFIG_SPI_SIRF)		+= spi-sirf.o
+ obj-$(CONFIG_SPI_STM32) 		+= spi-stm32.o
++obj-$(CONFIG_SPI_STM32_QUADSPI) 	+= spi-stm32-qspi.o
+ obj-$(CONFIG_SPI_ST_SSC4)		+= spi-st-ssc4.o
+ obj-$(CONFIG_SPI_SUN4I)			+= spi-sun4i.o
+ obj-$(CONFIG_SPI_SUN6I)			+= spi-sun6i.o
+diff --git a/drivers/spi/spi-stm32-qspi.c b/drivers/spi/spi-stm32-qspi.c
+new file mode 100644
+index 0000000..e3630c4
+--- /dev/null
++++ b/drivers/spi/spi-stm32-qspi.c
+@@ -0,0 +1,513 @@
++/*
++ * Driver for stm32 quadspi controller
++ *
++ * Copyright (C) 2017 STMicroelectronics
++ * Copyright (C) 2018 Exceet Electronics GmbH
++ *
++ * Authors: Ludovic Barre <ludovic.barre@st.com>
++ *          Frieder Schrempf <frieder.schrempf@exceet.de>
++ *
++ * License terms: GNU General Public License (GPL), version 2
++ */
++#include <linux/clk.h>
++#include <linux/errno.h>
++#include <linux/io.h>
++#include <linux/iopoll.h>
++#include <linux/interrupt.h>
++#include <linux/module.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mutex.h>
++#include <linux/of.h>
++#include <linux/of_device.h>
++#include <linux/platform_device.h>
++#include <linux/reset.h>
++#include <linux/sizes.h>
++#include <linux/spi/spi.h>
++#include <linux/spi/spi-mem.h>
++
++#define QUADSPI_CR		0x00
++#define CR_EN			BIT(0)
++#define CR_ABORT		BIT(1)
++#define CR_DMAEN		BIT(2)
++#define CR_TCEN			BIT(3)
++#define CR_SSHIFT		BIT(4)
++#define CR_DFM			BIT(6)
++#define CR_FSEL			BIT(7)
++#define CR_FTHRES_SHIFT		8
++#define CR_FTHRES_MASK		GENMASK(12, 8)
++#define CR_FTHRES(n)		(((n) << CR_FTHRES_SHIFT) & CR_FTHRES_MASK)
++#define CR_TEIE			BIT(16)
++#define CR_TCIE			BIT(17)
++#define CR_FTIE			BIT(18)
++#define CR_SMIE			BIT(19)
++#define CR_TOIE			BIT(20)
++#define CR_PRESC_SHIFT		24
++#define CR_PRESC_MASK		GENMASK(31, 24)
++#define CR_PRESC(n)		(((n) << CR_PRESC_SHIFT) & CR_PRESC_MASK)
++
++#define QUADSPI_DCR		0x04
++#define DCR_CSHT_SHIFT		8
++#define DCR_CSHT_MASK		GENMASK(10, 8)
++#define DCR_CSHT(n)		(((n) << DCR_CSHT_SHIFT) & DCR_CSHT_MASK)
++#define DCR_FSIZE_SHIFT		16
++#define DCR_FSIZE_MASK		GENMASK(20, 16)
++#define DCR_FSIZE(n)		(((n) << DCR_FSIZE_SHIFT) & DCR_FSIZE_MASK)
++
++#define QUADSPI_SR		0x08
++#define SR_TEF			BIT(0)
++#define SR_TCF			BIT(1)
++#define SR_FTF			BIT(2)
++#define SR_SMF			BIT(3)
++#define SR_TOF			BIT(4)
++#define SR_BUSY			BIT(5)
++#define SR_FLEVEL_SHIFT		8
++#define SR_FLEVEL_MASK		GENMASK(13, 8)
++
++#define QUADSPI_FCR		0x0c
++#define FCR_CTCF		BIT(1)
++
++#define QUADSPI_DLR		0x10
++
++#define CCR_BUSWIDTH(x)		fls(x)
++
++#define QUADSPI_CCR		0x14
++#define CCR_INST_SHIFT		0
++#define CCR_INST_MASK		GENMASK(7, 0)
++#define CCR_INST(n)		(((n) << CCR_INST_SHIFT) & CCR_INST_MASK)
++#define CCR_IMODE_SHIFT		8
++#define CCR_IMODE(x)		(CCR_BUSWIDTH(x) << CCR_IMODE_SHIFT)
++#define CCR_ADMODE_SHIFT	10
++#define CCR_ADMODE(x)		(CCR_BUSWIDTH(x) << CCR_ADMODE_SHIFT)
++#define CCR_ADSIZE_SHIFT	12
++#define CCR_ADSIZE_MASK		GENMASK(13, 12)
++#define CCR_ADSIZE(n)		(((n) << CCR_ADSIZE_SHIFT) & CCR_ADSIZE_MASK)
++#define CCR_ABMODE_SHIFT	14
++#define CCR_ABMODE(x)		(CCR_BUSWIDTH(x) << CCR_ABMODE_SHIFT)
++#define CCR_ABSIZE_8		(0U << 16)
++#define CCR_ABSIZE_16		(1U << 16)
++#define CCR_ABSIZE_24		(2U << 16)
++#define CCR_ABSIZE_32		(3U << 16)
++#define CCR_DCYC_SHIFT		18
++#define CCR_DCYC_MASK		GENMASK(22, 18)
++#define CCR_DCYC(n)		(((n) << CCR_DCYC_SHIFT) & CCR_DCYC_MASK)
++#define CCR_DMODE_SHIFT		24
++#define CCR_DMODE(x)		(CCR_BUSWIDTH(x) << CCR_DMODE_SHIFT)
++#define CCR_FMODE_INDW		(0U << 26)
++#define CCR_FMODE_INDR		(1U << 26)
++#define CCR_FMODE_APM		(2U << 26)
++#define CCR_FMODE_MM		(3U << 26)
++
++#define QUADSPI_AR		0x18
++#define QUADSPI_ABR		0x1c
++#define QUADSPI_DR		0x20
++#define QUADSPI_PSMKR		0x24
++#define QUADSPI_PSMAR		0x28
++#define QUADSPI_PIR		0x2c
++#define QUADSPI_LPTR		0x30
++#define LPTR_DFT_TIMEOUT	0x10
++
++#define FSIZE_VAL(size)		(__fls(size) - 1)
++
++#define STM32_MAX_MMAP_SZ	SZ_256M
++#define STM32_MAX_CHIP		2
++
++#define STM32_QSPI_FIFO_SZ	32
++#define STM32_QSPI_FIFO_TIMEOUT_US 30000
++#define STM32_QSPI_BUSY_TIMEOUT_US 100000
++
++struct stm32_qspi {
++	struct device *dev;
++	void __iomem *io_base;
++	void __iomem *mm_base;
++	resource_size_t mm_size;
++	struct clk *clk;
++	u32 clk_rate;
++	struct completion cmd_completion;
++
++	/*
++	 * to protect device configuration, could be different between
++	 * 2 flash access (bk1, bk2)
++	 */
++	struct mutex lock;
++};
++
++static int stm32_qspi_wait_cmd(struct stm32_qspi *qspi)
++{
++	u32 cr;
++	int err = 0;
++
++	if (readl_relaxed(qspi->io_base + QUADSPI_SR) & SR_TCF)
++		return 0;
++
++	reinit_completion(&qspi->cmd_completion);
++	cr = readl_relaxed(qspi->io_base + QUADSPI_CR);
++	writel_relaxed(cr | CR_TCIE, qspi->io_base + QUADSPI_CR);
++
++	if (!wait_for_completion_interruptible_timeout(&qspi->cmd_completion,
++						       msecs_to_jiffies(1000)))
++		err = -ETIMEDOUT;
++
++	writel_relaxed(cr, qspi->io_base + QUADSPI_CR);
++	return err;
++}
++
++static int stm32_qspi_wait_nobusy(struct stm32_qspi *qspi)
++{
++	u32 sr;
++
++	return readl_relaxed_poll_timeout(qspi->io_base + QUADSPI_SR, sr,
++					  !(sr & SR_BUSY), 10,
++					  STM32_QSPI_BUSY_TIMEOUT_US);
++}
++
++static int stm32_qspi_check_buswidth(struct stm32_qspi *qspi, u8 width)
++{
++	switch(width) {
++	case 1:
++	case 2:
++	case 4:
++		return 0;
++
++	default:
++		break;
++	}
++
++	return -ENOTSUPP;
++}
++
++static bool stm32_qspi_supports_op(struct spi_mem *mem,
++				   const struct spi_mem_op *op)
++{
++	struct stm32_qspi *qspi = spi_controller_get_devdata(mem->spi->master);
++	int ret;
++
++	ret = stm32_qspi_check_buswidth(qspi, op->cmd.buswidth);
++	
++	if (op->addr.nbytes)
++		ret |= stm32_qspi_check_buswidth(qspi, op->addr.buswidth);
++
++	if (op->dummy.nbytes)
++		ret |= stm32_qspi_check_buswidth(qspi, op->dummy.buswidth);
++
++	if (op->data.nbytes)
++		ret |= stm32_qspi_check_buswidth(qspi, op->data.buswidth);
++
++	if (ret)
++		return false;
++
++	/* Max 32-bit address. */
++	if (op->addr.nbytes > 4)
++		return false;
++
++	/* Max 31 dummy clock cycles. */
++	if (op->dummy.nbytes * 8 / op->dummy.buswidth > 31)
++		return false;
++
++	return true;
++}
++
++static void stm32_qspi_select_mem(struct stm32_qspi *qspi, struct spi_device *spi)
++{
++	u32 presc, temp;
++	static bool selected = false;
++
++	if (selected)
++		return;
++
++	temp = readl_relaxed(qspi->io_base + QUADSPI_DCR) & ~DCR_FSIZE_MASK;
++	temp |= DCR_FSIZE(0x1b); // set fixed size of 256M
++	writel_relaxed(temp, qspi->io_base + QUADSPI_DCR);
++
++	presc = DIV_ROUND_UP(qspi->clk_rate, spi->max_speed_hz) - 1;
++
++	temp = readl_relaxed(qspi->io_base + QUADSPI_CR);
++	temp &= ~CR_PRESC_MASK & ~CR_FSEL;
++	temp |= CR_PRESC(presc);
++	temp |= spi->chip_select ? CR_FSEL:0;
++	writel_relaxed(temp, qspi->io_base + QUADSPI_CR);
++
++	selected = true;
++}
++
++static void stm32_qspi_read_fifo(u8 *val, void __iomem *addr)
++{
++	*val = readb_relaxed(addr);
++}
++
++static void stm32_qspi_write_fifo(u8 *val, void __iomem *addr)
++{
++	writeb_relaxed(*val, addr);
++}
++
++static int stm32_qspi_tx_poll(struct stm32_qspi *qspi,
++			      const struct spi_mem_op *op)
++{
++	void (*tx_fifo)(u8 *, void __iomem *);
++	u32 len = op->data.nbytes, sr;
++	u8 *buf = op->data.buf.in;
++	int ret;
++
++	if (op->data.dir == SPI_MEM_DATA_OUT)
++		tx_fifo = stm32_qspi_write_fifo;
++	else
++		tx_fifo = stm32_qspi_read_fifo;
++
++	while (len--) {
++		ret = readl_relaxed_poll_timeout(qspi->io_base + QUADSPI_SR,
++						 sr, (sr & SR_FTF), 10,
++						 STM32_QSPI_FIFO_TIMEOUT_US);
++		if (ret) {
++			dev_err(qspi->dev, "fifo timeout (stat:%#x)\n", sr);
++			return ret;
++		}
++		tx_fifo(buf++, qspi->io_base + QUADSPI_DR);
++	}
++
++	return 0;
++}
++
++static int stm32_qspi_exec_op(struct spi_mem *mem,
++			      const struct spi_mem_op *op)
++{
++	struct stm32_qspi *qspi = spi_controller_get_devdata(mem->spi->master);
++	u32 reg = 0;
++	int err;
++
++	mutex_lock(&qspi->lock);
++
++	err = stm32_qspi_wait_nobusy(qspi);
++	if (err)
++		goto abort;
++
++	stm32_qspi_select_mem(qspi, mem->spi);
++
++	// set data size, direction and buswidth
++	if(op->data.nbytes) {
++		writel_relaxed(op->data.nbytes - 1, qspi->io_base + QUADSPI_DLR);
++		reg = op->data.dir == SPI_MEM_DATA_IN ?
++		                      CCR_FMODE_INDR : CCR_FMODE_INDW;
++		reg |= CCR_DMODE(op->data.buswidth);
++	}
++	else
++		writel_relaxed(0, qspi->io_base + QUADSPI_DLR);
++
++	// set instruction buswidth
++	reg |= CCR_IMODE(op->cmd.buswidth);;
++
++	// set address size and buswidth
++	if(op->addr.nbytes) {
++		reg |= CCR_ADSIZE(op->addr.nbytes - 1);
++		reg |= CCR_ADMODE(op->addr.buswidth);
++	}
++
++	// set number of dummy clock cycles
++	reg |= CCR_DCYC(op->dummy.nbytes * 8 / op->dummy.buswidth);
++
++	// set instruction opcode
++	reg |= CCR_INST(op->cmd.opcode);
++	writel_relaxed(reg, qspi->io_base + QUADSPI_CCR);
++
++	// set address
++	if(op->addr.nbytes)
++		writel_relaxed(op->addr.val, qspi->io_base + QUADSPI_AR);
++
++	// send/receive data
++	if(op->data.nbytes) {
++		err = stm32_qspi_tx_poll(qspi, op);
++		if (err)
++			goto abort;
++	}
++
++	err = stm32_qspi_wait_cmd(qspi);
++	if (err)
++		goto abort;
++
++	writel_relaxed(FCR_CTCF, qspi->io_base + QUADSPI_FCR);
++	mutex_unlock(&qspi->lock);
++
++	return err;
++
++abort:
++	reg = readl_relaxed(qspi->io_base + QUADSPI_CR) | CR_ABORT;
++	writel_relaxed(reg, qspi->io_base + QUADSPI_CR);
++	mutex_unlock(&qspi->lock);
++
++	dev_err(qspi->dev, "%s abort err:%d\n", __func__, err);
++	return err;
++}
++
++static int stm32_qspi_adjust_op_size(struct spi_mem *mem,
++				     struct spi_mem_op *op)
++{
++	return 0;
++}
++
++static irqreturn_t stm32_qspi_irq(int irq, void *dev_id)
++{
++	struct stm32_qspi *qspi = (struct stm32_qspi *)dev_id;
++	u32 cr, sr, fcr = 0;
++
++	cr = readl_relaxed(qspi->io_base + QUADSPI_CR);
++	sr = readl_relaxed(qspi->io_base + QUADSPI_SR);
++
++	if ((cr & CR_TCIE) && (sr & SR_TCF)) {
++		/* tx complete */
++		fcr |= FCR_CTCF;
++		complete(&qspi->cmd_completion);
++	} else {
++		dev_info_ratelimited(qspi->dev, "spurious interrupt\n");
++	}
++
++	writel_relaxed(fcr, qspi->io_base + QUADSPI_FCR);
++
++	return IRQ_HANDLED;
++}
++
++static const struct spi_controller_mem_ops stm32_qspi_mem_ops = {
++	.adjust_op_size = stm32_qspi_adjust_op_size,
++	.supports_op = stm32_qspi_supports_op,
++	.exec_op = stm32_qspi_exec_op,
++};
++
++static int stm32_qspi_probe(struct platform_device *pdev)
++{
++	struct spi_controller *ctlr;
++	struct device *dev = &pdev->dev;
++	struct reset_control *rstc;
++	struct stm32_qspi *qspi;
++	struct resource *res;
++	int ret, irq;
++	u32 num_chips;
++
++	ctlr = spi_alloc_master(dev, sizeof(*qspi));
++	if (!ctlr)
++		return -ENOMEM;
++
++	ctlr->mode_bits = SPI_RX_DUAL | SPI_RX_QUAD |
++			  SPI_TX_DUAL | SPI_TX_QUAD;
++	qspi = spi_controller_get_devdata(ctlr);
++	qspi->dev = dev;
++
++	platform_set_drvdata(pdev, qspi);
++
++	num_chips = of_get_child_count(dev->of_node);
++	if (num_chips > STM32_MAX_CHIP) {
++		ret = -ENODEV;
++		goto err_put_ctrl;
++	}
++
++	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi");
++	qspi->io_base = devm_ioremap_resource(dev, res);
++	if (IS_ERR(qspi->io_base)) {
++		ret = PTR_ERR(qspi->io_base);
++		goto err_put_ctrl;
++	}
++
++	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi_mm");
++	qspi->mm_base = devm_ioremap_resource(dev, res);
++	if (IS_ERR(qspi->mm_base)) {
++		ret = PTR_ERR(qspi->io_base);
++		goto err_put_ctrl;
++	}
++
++	qspi->mm_size = resource_size(res);
++
++	irq = platform_get_irq(pdev, 0);
++	ret = devm_request_irq(dev, irq, stm32_qspi_irq, 0,
++			       dev_name(dev), qspi);
++	if (ret) {
++		dev_err(dev, "failed to request irq\n");
++		goto err_put_ctrl;
++	}
++
++	init_completion(&qspi->cmd_completion);
++
++	qspi->clk = devm_clk_get(dev, NULL);
++	if (IS_ERR(qspi->clk)) {
++		ret = PTR_ERR(qspi->clk);
++		goto err_put_ctrl;
++	}
++
++	qspi->clk_rate = clk_get_rate(qspi->clk);
++	if (!qspi->clk_rate) {
++		ret = -EINVAL;
++		goto err_put_ctrl;
++	}
++
++	ret = clk_prepare_enable(qspi->clk);
++	if (ret) {
++		dev_err(dev, "can not enable the clock\n");
++		goto err_put_ctrl;
++	}
++
++	rstc = devm_reset_control_get(dev, NULL);
++	if (!IS_ERR(rstc)) {
++		reset_control_assert(rstc);
++		udelay(2);
++		reset_control_deassert(rstc);
++	}
++
++	ctlr->bus_num = -1;
++	ctlr->num_chipselect = 2;
++	ctlr->mem_ops = &stm32_qspi_mem_ops;
++
++	mutex_init(&qspi->lock);
++
++	writel_relaxed(LPTR_DFT_TIMEOUT, qspi->io_base + QUADSPI_LPTR);
++
++	writel_relaxed(CR_FTHRES(3) | CR_TCEN | CR_SSHIFT
++		       | CR_EN, qspi->io_base + QUADSPI_CR);
++
++	writel_relaxed(DCR_CSHT(1), qspi->io_base + QUADSPI_DCR);
++
++	ctlr->dev.of_node = pdev->dev.of_node;
++
++	ret = spi_register_controller(ctlr);
++	if (ret)
++		goto err_disable_clk;
++
++	return 0;
++
++err_disable_clk:
++	clk_disable_unprepare(qspi->clk);
++
++err_put_ctrl:
++	spi_controller_put(ctlr);
++
++	dev_err(dev, "STM32 QuadSPI probe failed\n");
++	return ret;
++}
++
++static int stm32_qspi_remove(struct platform_device *pdev)
++{
++	struct stm32_qspi *qspi = platform_get_drvdata(pdev);
++
++	/* disable qspi */
++	writel_relaxed(0, qspi->io_base + QUADSPI_CR);
++
++	//stm32_qspi_mtd_free(qspi);
++	mutex_destroy(&qspi->lock);
++
++	clk_disable_unprepare(qspi->clk);
++	return 0;
++}
++
++static const struct of_device_id stm32_qspi_match[] = {
++	{.compatible = "st,stm32f469-qspi"},
++	{}
++};
++MODULE_DEVICE_TABLE(of, stm32_qspi_match);
++
++static struct platform_driver stm32_qspi_driver = {
++	.probe	= stm32_qspi_probe,
++	.remove	= stm32_qspi_remove,
++	.driver	= {
++		.name = "stm32-quadspi",
++		.of_match_table = stm32_qspi_match,
++	},
++};
++module_platform_driver(stm32_qspi_driver);
++
++MODULE_AUTHOR("Ludovic Barre <ludovic.barre@st.com>");
++MODULE_DESCRIPTION("STMicroelectronics STM32 quad spi driver");
++MODULE_LICENSE("GPL v2");
+-- 
+2.7.4
+
diff --git a/recipes-kernel/linux/linux-stm32mp/patches/0022-fixup-spi-create-spi-mem-based-driver-for-stm32-QSPI.patch b/recipes-kernel/linux/linux-stm32mp/patches/0022-fixup-spi-create-spi-mem-based-driver-for-stm32-QSPI.patch
new file mode 100644
index 0000000000000000000000000000000000000000..709321b89e2aff3c095c481e3f911ec211559765
--- /dev/null
+++ b/recipes-kernel/linux/linux-stm32mp/patches/0022-fixup-spi-create-spi-mem-based-driver-for-stm32-QSPI.patch
@@ -0,0 +1,53 @@
+From 66dcb6f89a975ece18456e5fe9ecf474737f916b Mon Sep 17 00:00:00 2001
+From: Frieder Schrempf <frieder.schrempf@exceet.de>
+Date: Tue, 29 May 2018 08:45:02 +0200
+Subject: [PATCH 22/28] fixup! spi: create spi-mem based driver for stm32 QSPI
+
+---
+ drivers/spi/spi-stm32-qspi.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/spi/spi-stm32-qspi.c b/drivers/spi/spi-stm32-qspi.c
+index e3630c4..85d50b5 100644
+--- a/drivers/spi/spi-stm32-qspi.c
++++ b/drivers/spi/spi-stm32-qspi.c
+@@ -123,7 +123,7 @@ struct stm32_qspi {
+ 	struct clk *clk;
+ 	u32 clk_rate;
+ 	struct completion cmd_completion;
+-
++	int selected;
+ 	/*
+ 	 * to protect device configuration, could be different between
+ 	 * 2 flash access (bk1, bk2)
+@@ -209,9 +209,8 @@ static bool stm32_qspi_supports_op(struct spi_mem *mem,
+ static void stm32_qspi_select_mem(struct stm32_qspi *qspi, struct spi_device *spi)
+ {
+ 	u32 presc, temp;
+-	static bool selected = false;
+ 
+-	if (selected)
++	if (qspi->selected == spi->chip_select)
+ 		return;
+ 
+ 	temp = readl_relaxed(qspi->io_base + QUADSPI_DCR) & ~DCR_FSIZE_MASK;
+@@ -226,7 +225,7 @@ static void stm32_qspi_select_mem(struct stm32_qspi *qspi, struct spi_device *sp
+ 	temp |= spi->chip_select ? CR_FSEL:0;
+ 	writel_relaxed(temp, qspi->io_base + QUADSPI_CR);
+ 
+-	selected = true;
++	qspi->selected = spi->chip_select;
+ }
+ 
+ static void stm32_qspi_read_fifo(u8 *val, void __iomem *addr)
+@@ -447,6 +446,7 @@ static int stm32_qspi_probe(struct platform_device *pdev)
+ 		reset_control_deassert(rstc);
+ 	}
+ 
++	qspi->selected = -1;
+ 	ctlr->bus_num = -1;
+ 	ctlr->num_chipselect = 2;
+ 	ctlr->mem_ops = &stm32_qspi_mem_ops;
+-- 
+2.7.4
+
diff --git a/recipes-kernel/linux/linux-stm32mp/patches/0505-mtd-nand-spi-Add-initial-support-for-Toshiba-TC58CVG.patch b/recipes-kernel/linux/linux-stm32mp/patches/0023-mtd-nand-spi-Add-initial-support-for-Toshiba-TC58CVG.patch
similarity index 67%
rename from recipes-kernel/linux/linux-stm32mp/patches/0505-mtd-nand-spi-Add-initial-support-for-Toshiba-TC58CVG.patch
rename to recipes-kernel/linux/linux-stm32mp/patches/0023-mtd-nand-spi-Add-initial-support-for-Toshiba-TC58CVG.patch
index cc9d5682e346f03315c6c10cf1a051ea7c21a6f4..840d106c44d502419bc518a0f067d4380da67aba 100644
--- a/recipes-kernel/linux/linux-stm32mp/patches/0505-mtd-nand-spi-Add-initial-support-for-Toshiba-TC58CVG.patch
+++ b/recipes-kernel/linux/linux-stm32mp/patches/0023-mtd-nand-spi-Add-initial-support-for-Toshiba-TC58CVG.patch
@@ -1,36 +1,32 @@
-From 48585ceba8f2d638831c4b5f54fa6ec0e73eb722 Mon Sep 17 00:00:00 2001
-From: Frieder Schrempf <frieder.schrempf@kontron.de>
-Date: Thu, 8 Nov 2018 08:51:51 +0100
-Subject: [PATCH] mtd: nand: spi: Add initial support for Toshiba TC58CVG2S0H
-
-Add minimal support for the Toshiba TC58CVG2S0H SPI NAND chip.
-
-Signed-off-by: Frieder Schrempf <frieder.schrempf@kontron.de>
+From 1e852c1e843bb432e49b0659de44d44802801881 Mon Sep 17 00:00:00 2001
+From: Frieder Schrempf <frieder.schrempf@exceet.de>
+Date: Thu, 12 Apr 2018 17:16:13 +0200
+Subject: [PATCH 23/28] mtd: nand: spi: Add initial support for Toshiba
+ TC58CVG2S0H
 
 ---
  drivers/mtd/nand/spi/Makefile  |   2 +-
  drivers/mtd/nand/spi/core.c    |   1 +
- drivers/mtd/nand/spi/toshiba.c | 137 +++++++++++++++++++++++++++++++++
+ drivers/mtd/nand/spi/toshiba.c | 163 +++++++++++++++++++++++++++++++++++++++++
  include/linux/mtd/spinand.h    |   1 +
- 4 files changed, 140 insertions(+), 1 deletion(-)
+ 4 files changed, 166 insertions(+), 1 deletion(-)
  create mode 100644 drivers/mtd/nand/spi/toshiba.c
 
 diff --git a/drivers/mtd/nand/spi/Makefile b/drivers/mtd/nand/spi/Makefile
-index b74e074b363a..be5f73512ece 100644
+index 983a94f..32c0812 100644
 --- a/drivers/mtd/nand/spi/Makefile
 +++ b/drivers/mtd/nand/spi/Makefile
-@@ -1,3 +1,3 @@
- # SPDX-License-Identifier: GPL-2.0
--spinand-objs := core.o macronix.o micron.o winbond.o
-+spinand-objs := core.o macronix.o micron.o toshiba.o winbond.o
+@@ -1,2 +1,2 @@
+-spinand-objs := core.o micron.o winbond.o
++spinand-objs := core.o micron.o winbond.o toshiba.o
  obj-$(CONFIG_MTD_SPI_NAND) += spinand.o
 diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
-index 403dbda4115f..5974262f2af5 100644
+index 057adb5..4229067 100644
 --- a/drivers/mtd/nand/spi/core.c
 +++ b/drivers/mtd/nand/spi/core.c
-@@ -762,6 +762,7 @@ static const struct nand_ops spinand_ops = {
+@@ -769,6 +769,7 @@ static const struct nand_ops spinand_ops = {
+ 
  static const struct spinand_manufacturer *spinand_manufacturers[] = {
- 	&macronix_spinand_manufacturer,
  	&micron_spinand_manufacturer,
 +	&toshiba_spinand_manufacturer,
  	&winbond_spinand_manufacturer,
@@ -38,16 +34,15 @@ index 403dbda4115f..5974262f2af5 100644
  
 diff --git a/drivers/mtd/nand/spi/toshiba.c b/drivers/mtd/nand/spi/toshiba.c
 new file mode 100644
-index 000000000000..fa4e7b94a744
+index 0000000..27e531a
 --- /dev/null
 +++ b/drivers/mtd/nand/spi/toshiba.c
-@@ -0,0 +1,137 @@
+@@ -0,0 +1,163 @@
 +// SPDX-License-Identifier: GPL-2.0
 +/*
 + * Copyright (c) 2018 exceet electronics GmbH
-+ * Copyright (c) 2018 Kontron Electronics GmbH
 + *
-+ * Author: Frieder Schrempf <frieder.schrempf@kontron.de>
++ * Author: Frieder Schrempf <frieder.schrempf@exceet.de>
 + */
 +
 +#include <linux/device.h>
@@ -55,7 +50,6 @@ index 000000000000..fa4e7b94a744
 +#include <linux/mtd/spinand.h>
 +
 +#define SPINAND_MFR_TOSHIBA		0x98
-+#define TOSH_STATUS_ECC_HAS_BITFLIPS_T	(3 << 4)
 +
 +static SPINAND_OP_VARIANTS(read_cache_variants,
 +		SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
@@ -75,21 +69,20 @@ index 000000000000..fa4e7b94a744
 +	if (section > 7)
 +		return -ERANGE;
 +
-+	region->offset = 128 + 16 * section;
++	region->offset = 16 * section + 128;
 +	region->length = 16;
 +
-+
 +	return 0;
 +}
 +
 +static int tc58cvg2s0h_ooblayout_free(struct mtd_info *mtd, int section,
 +				      struct mtd_oob_region *region)
 +{
-+	if (section > 0)
++	if (section > 7)
 +		return -ERANGE;
 +
-+	region->offset = 2;
-+	region->length = 126;
++	region->offset = 16 * section;
++	region->length = 16;
 +
 +	return 0;
 +}
@@ -99,12 +92,30 @@ index 000000000000..fa4e7b94a744
 +	.free = tc58cvg2s0h_ooblayout_free,
 +};
 +
++static int tc58cvg2s0h_get_eccsr(struct spinand_device *spinand, u8 *eccsr)
++{
++	u8 i, temp = 0;
++	struct spi_mem_op op = SPINAND_GET_FEATURE_OP(0x40, &temp);
++	int ret;
++	
++	for(i = 0; i < 4; i++) {
++		op.addr.val += 0x10;
++
++		ret = spi_mem_exec_op(spinand->spimem, &op);
++		if(ret)
++			return ret;
++
++		*eccsr += (temp & 0x0F) + (temp >> 4);
++	}
++
++	return 0;
++}
++
 +static int tc58cvg2s0h_ecc_get_status(struct spinand_device *spinand,
 +				      u8 status)
 +{
 +	struct nand_device *nand = spinand_to_nand(spinand);
-+	u8 mbf = 0;
-+	struct spi_mem_op op = SPINAND_GET_FEATURE_OP(0x30, &mbf);
++	u8 eccsr;
 +
 +	switch (status & STATUS_ECC_MASK) {
 +	case STATUS_ECC_NO_BITFLIPS:
@@ -114,21 +125,20 @@ index 000000000000..fa4e7b94a744
 +		return -EBADMSG;
 +
 +	case STATUS_ECC_HAS_BITFLIPS:
-+	case TOSH_STATUS_ECC_HAS_BITFLIPS_T:
 +		/*
 +		 * Let's try to retrieve the real maximum number of bitflips
 +		 * in order to avoid forcing the wear-leveling layer to move
 +		 * data around if it's not necessary.
 +		 */
-+		if (spi_mem_exec_op(spinand->spimem, &op))
++		if (tc58cvg2s0h_get_eccsr(spinand, &eccsr))
 +			return nand->eccreq.strength;
 +
-+		mbf >>= 4;
++		eccsr >>= 4;
 +
-+		if (WARN_ON(mbf > nand->eccreq.strength || !mbf))
++		if (WARN_ON(eccsr > nand->eccreq.strength || !eccsr))
 +			return nand->eccreq.strength;
 +
-+		return mbf;
++		return eccsr;
 +
 +	default:
 +		break;
@@ -139,14 +149,15 @@ index 000000000000..fa4e7b94a744
 +
 +static const struct spinand_info toshiba_spinand_table[] = {
 +	SPINAND_INFO("TC58CVG2S0H", 0xCD,
-+		     NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
++		     NAND_MEMORG(1, 4069, 256, 64, 2048, 1, 1, 1),
 +		     NAND_ECCREQ(8, 512),
 +		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
 +					      &write_cache_variants,
 +					      &update_cache_variants),
 +		     SPINAND_HAS_QE_BIT,
 +		     SPINAND_ECCINFO(&tc58cvg2s0h_ooblayout,
-+				     tc58cvg2s0h_ecc_get_status)),
++				      tc58cvg2s0h_ecc_get_status),
++		     ),
 +};
 +
 +static int toshiba_spinand_detect(struct spinand_device *spinand)
@@ -155,8 +166,8 @@ index 000000000000..fa4e7b94a744
 +	int ret;
 +
 +	/*
-+	 * Toshiba SPI NAND read ID needs a dummy byte,
-+	 * so the first byte in id is garbage.
++	 * Toshiba SPI NAND read ID needs a dummy byte, so the first byte in
++	 * raw_id is garbage.
 +	 */
 +	if (id[1] != SPINAND_MFR_TOSHIBA)
 +		return 0;
@@ -170,8 +181,19 @@ index 000000000000..fa4e7b94a744
 +	return 1;
 +}
 +
++static int toshiba_spinand_init(struct spinand_device *spinand)
++{
++	struct nand_device *nand = spinand_to_nand(spinand);
++	const u8 val = 8 << 4;
++	struct spi_mem_op op = SPINAND_SET_FEATURE_OP(0x10, &val);
++
++	/* set bitflip threshold to 8 */
++	return spi_mem_exec_op(spinand->spimem, &op);
++}
++
 +static const struct spinand_manufacturer_ops toshiba_spinand_manuf_ops = {
 +	.detect = toshiba_spinand_detect,
++	.init = toshiba_spinand_init,
 +};
 +
 +const struct spinand_manufacturer toshiba_spinand_manufacturer = {
@@ -180,14 +202,17 @@ index 000000000000..fa4e7b94a744
 +	.ops = &toshiba_spinand_manuf_ops,
 +};
 diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
-index 088ff96c3eb6..816c4b00abca 100644
+index 31d9936..4a1c327 100644
 --- a/include/linux/mtd/spinand.h
 +++ b/include/linux/mtd/spinand.h
-@@ -196,6 +196,7 @@ struct spinand_manufacturer {
+@@ -194,6 +194,7 @@ struct spinand_manufacturer {
+ 
  /* SPI NAND manufacturers */
- extern const struct spinand_manufacturer macronix_spinand_manufacturer;
  extern const struct spinand_manufacturer micron_spinand_manufacturer;
 +extern const struct spinand_manufacturer toshiba_spinand_manufacturer;
  extern const struct spinand_manufacturer winbond_spinand_manufacturer;
  
  /**
+-- 
+2.7.4
+
diff --git a/recipes-kernel/linux/linux-stm32mp/patches/0024-fixup-mtd-nand-Add-core-infrastructure-to-support-SP.patch b/recipes-kernel/linux/linux-stm32mp/patches/0024-fixup-mtd-nand-Add-core-infrastructure-to-support-SP.patch
new file mode 100644
index 0000000000000000000000000000000000000000..fb1ed340fa0506253f01227f58f051a9cfb7949a
--- /dev/null
+++ b/recipes-kernel/linux/linux-stm32mp/patches/0024-fixup-mtd-nand-Add-core-infrastructure-to-support-SP.patch
@@ -0,0 +1,39 @@
+From 908cc6e8e2d32c6aff07ac8957748469190d5af1 Mon Sep 17 00:00:00 2001
+From: Frieder Schrempf <frieder.schrempf@exceet.de>
+Date: Tue, 29 May 2018 12:28:01 +0200
+Subject: [PATCH 24/28] fixup! mtd: nand: Add core infrastructure to support
+ SPI NANDs
+
+---
+ drivers/mtd/nand/spi/core.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
+index 4229067..eddf0c0 100644
+--- a/drivers/mtd/nand/spi/core.c
++++ b/drivers/mtd/nand/spi/core.c
+@@ -979,6 +979,10 @@ static int spinand_init(struct spinand_device *spinand)
+ 	if (!spinand->scratchbuf)
+ 		return -ENOMEM;
+ 
++	ret = spinand_init_cfg_cache(spinand);
++	if (ret)
++		goto err_free_bufs;
++
+ 	ret = spinand_detect(spinand);
+ 	if (ret)
+ 		goto err_free_bufs;
+@@ -996,10 +1000,6 @@ static int spinand_init(struct spinand_device *spinand)
+ 
+ 	spinand->oobbuf = spinand->databuf + nanddev_page_size(nand);
+ 
+-	ret = spinand_init_cfg_cache(spinand);
+-	if (ret)
+-		goto err_free_bufs;
+-
+ 	ret = spinand_manufacturer_init(spinand);
+ 	if (ret) {
+ 		dev_err(dev,
+-- 
+2.7.4
+
diff --git a/recipes-kernel/linux/linux-stm32mp/patches/0502-mtd-spi-nor-Add-support-for-Macronix-MX25V8035F.patch b/recipes-kernel/linux/linux-stm32mp/patches/0025-mtd-spi-nor-Add-support-for-Macronix-MX25V8035F.patch
similarity index 77%
rename from recipes-kernel/linux/linux-stm32mp/patches/0502-mtd-spi-nor-Add-support-for-Macronix-MX25V8035F.patch
rename to recipes-kernel/linux/linux-stm32mp/patches/0025-mtd-spi-nor-Add-support-for-Macronix-MX25V8035F.patch
index 0c3df90c8b13148e9d185683359520e7584aad60..77485a62357a1e075c25b2b4f5257778bd59f8e5 100644
--- a/recipes-kernel/linux/linux-stm32mp/patches/0502-mtd-spi-nor-Add-support-for-Macronix-MX25V8035F.patch
+++ b/recipes-kernel/linux/linux-stm32mp/patches/0025-mtd-spi-nor-Add-support-for-Macronix-MX25V8035F.patch
@@ -1,17 +1,17 @@
-From 80744390beaccbbeee1bee0f5e9c4c0ff8771c34 Mon Sep 17 00:00:00 2001
+From 3d57fb5cb1e388171e8002dadaf22c6badcf466a Mon Sep 17 00:00:00 2001
 From: Frieder Schrempf <frieder.schrempf@exceet.de>
 Date: Tue, 16 Jan 2018 16:38:40 +0100
-Subject: [PATCH] mtd: spi-nor: Add support for Macronix MX25V8035F
+Subject: [PATCH 25/28] mtd: spi-nor: Add support for Macronix MX25V8035F
 
 ---
  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 fdd080a30a2e..0066ddc5fb7a 100644
+index 19c00072..70b94f2 100644
 --- a/drivers/mtd/spi-nor/spi-nor.c
 +++ b/drivers/mtd/spi-nor/spi-nor.c
-@@ -1082,6 +1082,7 @@ static const struct flash_info spi_nor_ids[] = {
+@@ -1015,6 +1015,7 @@ 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) },
@@ -19,3 +19,6 @@ index fdd080a30a2e..0066ddc5fb7a 100644
  	{ "mx25u2033e",  INFO(0xc22532, 0, 64 * 1024,   4, SECT_4K) },
  	{ "mx25u4035",   INFO(0xc22533, 0, 64 * 1024,   8, SECT_4K) },
  	{ "mx25u8035",   INFO(0xc22534, 0, 64 * 1024,  16, SECT_4K) },
+-- 
+2.7.4
+
diff --git a/recipes-kernel/linux/linux-stm32mp/bleeding/patches/0503-drm-panel-simple-Add-support-for-Admatec-T043C004800.patch b/recipes-kernel/linux/linux-stm32mp/patches/0026-drm-panel-simple-Add-support-for-Admatec-T043C004800.patch
similarity index 81%
rename from recipes-kernel/linux/linux-stm32mp/bleeding/patches/0503-drm-panel-simple-Add-support-for-Admatec-T043C004800.patch
rename to recipes-kernel/linux/linux-stm32mp/patches/0026-drm-panel-simple-Add-support-for-Admatec-T043C004800.patch
index 99558d441fa05f32656af5dc5a26f4f269166a29..ee23e5cd7fcfb3b248b8254018d6ec7b4a5f6fa1 100644
--- a/recipes-kernel/linux/linux-stm32mp/bleeding/patches/0503-drm-panel-simple-Add-support-for-Admatec-T043C004800.patch
+++ b/recipes-kernel/linux/linux-stm32mp/patches/0026-drm-panel-simple-Add-support-for-Admatec-T043C004800.patch
@@ -1,17 +1,18 @@
-From 070d1210349944a749d8f35421797b15bb2fd55c Mon Sep 17 00:00:00 2001
+From 3560d1e05c69da7c005064a2a37457a21ac0e21a Mon Sep 17 00:00:00 2001
 From: Frieder Schrempf <frieder.schrempf@exceet.de>
 Date: Wed, 10 Jan 2018 15:00:14 +0100
-Subject: [PATCH] drm/panel: simple: Add support for Admatec T043C004800272T2A
+Subject: [PATCH 26/28] drm/panel: simple: Add support for Admatec
+ T043C004800272T2A
 
 ---
  drivers/gpu/drm/panel/panel-simple.c | 28 ++++++++++++++++++++++++++++
  1 file changed, 28 insertions(+)
 
 diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c
-index 654fea2b4312..65ae2a41e4c2 100644
+index 234af81..3a3dc6c 100644
 --- a/drivers/gpu/drm/panel/panel-simple.c
 +++ b/drivers/gpu/drm/panel/panel-simple.c
-@@ -386,6 +386,31 @@ static void panel_simple_shutdown(struct device *dev)
+@@ -388,6 +388,31 @@ static void panel_simple_shutdown(struct device *dev)
  	panel_simple_unprepare(&panel->base);
  }
  
@@ -43,7 +44,7 @@ index 654fea2b4312..65ae2a41e4c2 100644
  static const struct drm_display_mode ampire_am_480272h3tmqw_t01h_mode = {
  	.clock = 9000,
  	.hdisplay = 480,
-@@ -2351,6 +2376,9 @@ static const struct panel_desc winstar_wf35ltiacd = {
+@@ -1941,6 +1966,9 @@ static const struct panel_desc winstar_wf35ltiacd = {
  
  static const struct of_device_id platform_of_match[] = {
  	{
@@ -53,3 +54,6 @@ index 654fea2b4312..65ae2a41e4c2 100644
  		.compatible = "ampire,am-480272h3tmqw-t01h",
  		.data = &ampire_am_480272h3tmqw_t01h,
  	}, {
+-- 
+2.7.4
+
diff --git a/recipes-kernel/linux/linux-stm32mp/patches/0501-add-SPI-NOR-mx25r1635f.patch b/recipes-kernel/linux/linux-stm32mp/patches/0027-add-SPI-NOR-mx25r1635f.patch
similarity index 79%
rename from recipes-kernel/linux/linux-stm32mp/patches/0501-add-SPI-NOR-mx25r1635f.patch
rename to recipes-kernel/linux/linux-stm32mp/patches/0027-add-SPI-NOR-mx25r1635f.patch
index 094323efa78ac3d6efc044ecdf104e5940747603..72dfd48c999c46709b14900272c726cc39846afc 100644
--- a/recipes-kernel/linux/linux-stm32mp/patches/0501-add-SPI-NOR-mx25r1635f.patch
+++ b/recipes-kernel/linux/linux-stm32mp/patches/0027-add-SPI-NOR-mx25r1635f.patch
@@ -1,17 +1,17 @@
-From 41437336dcef60a7da3e9baf50e418a21e2db52f Mon Sep 17 00:00:00 2001
+From 3dab6df04eaefced653400a5cface33e89a49d92 Mon Sep 17 00:00:00 2001
 From: Eberhard Stoll <eberhard.stoll@exceet.de>
 Date: Fri, 18 May 2018 15:10:51 +0200
-Subject: [PATCH] add SPI-NOR mx25r1635f
+Subject: [PATCH 27/28] add SPI-NOR mx25r1635f
 
 ---
  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 f028277fb1ce..fdd080a30a2e 100644
+index 70b94f2..28ba2d2 100644
 --- a/drivers/mtd/spi-nor/spi-nor.c
 +++ b/drivers/mtd/spi-nor/spi-nor.c
-@@ -1095,6 +1095,7 @@ static const struct flash_info spi_nor_ids[] = {
+@@ -1029,6 +1029,7 @@ static const struct flash_info spi_nor_ids[] = {
  	{ "mx66u51235f", INFO(0xc2253a, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
  	{ "mx66l1g45g",  INFO(0xc2201b, 0, 64 * 1024, 2048, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
  	{ "mx66l1g55g",  INFO(0xc2261b, 0, 64 * 1024, 2048, SPI_NOR_QUAD_READ) },
@@ -19,3 +19,6 @@ index f028277fb1ce..fdd080a30a2e 100644
  
  	/* Micron */
  	{ "n25q016a",	 INFO(0x20bb15, 0, 64 * 1024,   32, SECT_4K | SPI_NOR_QUAD_READ) },
+-- 
+2.7.4
+
diff --git a/recipes-kernel/linux/linux-stm32mp/patches/0301-Add-mcp25xxfd-SPI-CANFD-driver.patch b/recipes-kernel/linux/linux-stm32mp/patches/0301-Add-mcp25xxfd-SPI-CANFD-driver.patch
deleted file mode 100644
index faa512e0cdcf24e80235307e90cbc4019d10e939..0000000000000000000000000000000000000000
--- a/recipes-kernel/linux/linux-stm32mp/patches/0301-Add-mcp25xxfd-SPI-CANFD-driver.patch
+++ /dev/null
@@ -1,6825 +0,0 @@
-From ff421ef645518c6d55cdb06ff7efd571c6dfb95d Mon Sep 17 00:00:00 2001
-From: Eberhard Stoll <eberhard.stoll@kontron.de>
-Date: Wed, 4 Nov 2020 15:43:19 +0100
-Subject: [PATCH] Add mcp25xxfd SPI CANFD driver Backported driver from  
- repository: git@github.com:msperl/linux-rpi.git   branch:
- upstream-v5.0-rc3-mcp25xxfd-v6.11   commit:
- 5b9376cdbb5b58a4feaa5718965c93faac2e0a18   culumative patch of following
- commits:     5b9376cdbb5b (HEAD -> upstream-v5.0-rc3-mcp25xxfd-v6.11,
- origin/upstream-v5.0-rc3-mcp25xxfd-v6.11) can: mcp25xxfd: optimize reception
- of big CanFD frame reception with BRS     830e66a8a5a2 can: mcp25xxfd: add
- prediction of CanFD frames sizes based on history     14cde5669d56 can:
- mcp25xxfd: optimize SPI reads of FIFOs in can2.0 mode     edee77129629 can:
- mcp25xxfd: optimize TEF reads reading multiple TEFs in one go    
- 1fc13b23ba5a can: mcp25xxfd: optimize TEF read avoiding unnecessary SPI
- transfers     75100d8b1828 can: mcp25xxfd: Add Microchip mcp25xxfd CAN FD
- driver     d12121aa0e2e can: mcp25xxfd: add gpiolib support for GPIO0/1 (aka.
- INT0/INT1)     f63fc17c0779 can: mcp25xxfd: Add Microchip mcp25xxfd CAN FD
- driver basics     16476a8077d6 dt-binding: can: mcp25xxfd: document device
- tree bindings     4114cf95cff9 Add config for mcp2517fd to dt    
- ef6f5fd4d558 added dts for raspberry pi cm3
-
----
- .../bindings/net/can/microchip,mcp25xxfd.txt  |  32 +
- arch/arm/boot/dts/Makefile                    |   6 +-
- .../dts/bcm2835-rpi-cm1-io1-mcp2517fd.dts     |  37 +
- .../dts/bcm2837-rpi-cm3-io3-mcp2517fd.dts     |  37 +
- arch/arm/boot/dts/bcm2837-rpi-cm3-io3x.dts    |   1 +
- drivers/net/can/spi/Kconfig                   |   2 +
- drivers/net/can/spi/Makefile                  |   2 +
- drivers/net/can/spi/mcp25xxfd/Kconfig         |   5 +
- drivers/net/can/spi/mcp25xxfd/Makefile        |  18 +
- .../net/can/spi/mcp25xxfd/mcp25xxfd_base.c    | 281 +++++++
- .../net/can/spi/mcp25xxfd/mcp25xxfd_base.h    |  14 +
- drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can.c | 684 +++++++++++++++
- drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can.h |  56 ++
- .../can/spi/mcp25xxfd/mcp25xxfd_can_debugfs.c | 235 ++++++
- .../can/spi/mcp25xxfd/mcp25xxfd_can_debugfs.h |  44 +
- .../can/spi/mcp25xxfd/mcp25xxfd_can_fifo.c    | 347 ++++++++
- .../can/spi/mcp25xxfd/mcp25xxfd_can_fifo.h    |  16 +
- .../net/can/spi/mcp25xxfd/mcp25xxfd_can_id.h  |  69 ++
- .../net/can/spi/mcp25xxfd/mcp25xxfd_can_int.c | 705 ++++++++++++++++
- .../net/can/spi/mcp25xxfd/mcp25xxfd_can_int.h |  17 +
- .../can/spi/mcp25xxfd/mcp25xxfd_can_priv.h    | 203 +++++
- .../net/can/spi/mcp25xxfd/mcp25xxfd_can_rx.c  | 521 ++++++++++++
- .../net/can/spi/mcp25xxfd/mcp25xxfd_can_rx.h  |  18 +
- .../net/can/spi/mcp25xxfd/mcp25xxfd_can_tx.c  | 794 ++++++++++++++++++
- .../net/can/spi/mcp25xxfd/mcp25xxfd_can_tx.h  |  86 ++
- .../net/can/spi/mcp25xxfd/mcp25xxfd_clock.c   | 485 +++++++++++
- .../net/can/spi/mcp25xxfd/mcp25xxfd_clock.h   |  28 +
- drivers/net/can/spi/mcp25xxfd/mcp25xxfd_cmd.c | 312 +++++++
- drivers/net/can/spi/mcp25xxfd/mcp25xxfd_cmd.h |  84 ++
- drivers/net/can/spi/mcp25xxfd/mcp25xxfd_crc.c |  31 +
- drivers/net/can/spi/mcp25xxfd/mcp25xxfd_crc.h |  15 +
- .../net/can/spi/mcp25xxfd/mcp25xxfd_debugfs.c | 110 +++
- .../net/can/spi/mcp25xxfd/mcp25xxfd_debugfs.h |  30 +
- drivers/net/can/spi/mcp25xxfd/mcp25xxfd_ecc.c |  75 ++
- drivers/net/can/spi/mcp25xxfd/mcp25xxfd_ecc.h |  16 +
- .../net/can/spi/mcp25xxfd/mcp25xxfd_gpio.c    | 194 +++++
- .../net/can/spi/mcp25xxfd/mcp25xxfd_gpio.h    |  16 +
- drivers/net/can/spi/mcp25xxfd/mcp25xxfd_int.c |  73 ++
- drivers/net/can/spi/mcp25xxfd/mcp25xxfd_int.h |  15 +
- .../net/can/spi/mcp25xxfd/mcp25xxfd_priv.h    |  83 ++
- .../net/can/spi/mcp25xxfd/mcp25xxfd_regs.h    | 661 +++++++++++++++
- 41 files changed, 6457 insertions(+), 1 deletion(-)
- create mode 100644 Documentation/devicetree/bindings/net/can/microchip,mcp25xxfd.txt
- create mode 100644 arch/arm/boot/dts/bcm2835-rpi-cm1-io1-mcp2517fd.dts
- create mode 100644 arch/arm/boot/dts/bcm2837-rpi-cm3-io3-mcp2517fd.dts
- create mode 120000 arch/arm/boot/dts/bcm2837-rpi-cm3-io3x.dts
- create mode 100644 drivers/net/can/spi/mcp25xxfd/Kconfig
- create mode 100644 drivers/net/can/spi/mcp25xxfd/Makefile
- create mode 100644 drivers/net/can/spi/mcp25xxfd/mcp25xxfd_base.c
- create mode 100644 drivers/net/can/spi/mcp25xxfd/mcp25xxfd_base.h
- create mode 100644 drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can.c
- create mode 100644 drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can.h
- create mode 100644 drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_debugfs.c
- create mode 100644 drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_debugfs.h
- create mode 100644 drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_fifo.c
- create mode 100644 drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_fifo.h
- create mode 100644 drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_id.h
- create mode 100644 drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_int.c
- create mode 100644 drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_int.h
- create mode 100644 drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_priv.h
- create mode 100644 drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_rx.c
- create mode 100644 drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_rx.h
- create mode 100644 drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_tx.c
- create mode 100644 drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_tx.h
- create mode 100644 drivers/net/can/spi/mcp25xxfd/mcp25xxfd_clock.c
- create mode 100644 drivers/net/can/spi/mcp25xxfd/mcp25xxfd_clock.h
- create mode 100644 drivers/net/can/spi/mcp25xxfd/mcp25xxfd_cmd.c
- create mode 100644 drivers/net/can/spi/mcp25xxfd/mcp25xxfd_cmd.h
- create mode 100644 drivers/net/can/spi/mcp25xxfd/mcp25xxfd_crc.c
- create mode 100644 drivers/net/can/spi/mcp25xxfd/mcp25xxfd_crc.h
- create mode 100644 drivers/net/can/spi/mcp25xxfd/mcp25xxfd_debugfs.c
- create mode 100644 drivers/net/can/spi/mcp25xxfd/mcp25xxfd_debugfs.h
- create mode 100644 drivers/net/can/spi/mcp25xxfd/mcp25xxfd_ecc.c
- create mode 100644 drivers/net/can/spi/mcp25xxfd/mcp25xxfd_ecc.h
- create mode 100644 drivers/net/can/spi/mcp25xxfd/mcp25xxfd_gpio.c
- create mode 100644 drivers/net/can/spi/mcp25xxfd/mcp25xxfd_gpio.h
- create mode 100644 drivers/net/can/spi/mcp25xxfd/mcp25xxfd_int.c
- create mode 100644 drivers/net/can/spi/mcp25xxfd/mcp25xxfd_int.h
- create mode 100644 drivers/net/can/spi/mcp25xxfd/mcp25xxfd_priv.h
- create mode 100644 drivers/net/can/spi/mcp25xxfd/mcp25xxfd_regs.h
-
-diff --git a/Documentation/devicetree/bindings/net/can/microchip,mcp25xxfd.txt b/Documentation/devicetree/bindings/net/can/microchip,mcp25xxfd.txt
-new file mode 100644
-index 000000000000..b388b3eb3905
---- /dev/null
-+++ b/Documentation/devicetree/bindings/net/can/microchip,mcp25xxfd.txt
-@@ -0,0 +1,32 @@
-+* Microchip MCP2517 stand-alone CAN controller device tree bindings
-+
-+Required properties:
-+ - compatible: Should be one of the following:
-+   - "microchip,mcp2517fd" for MCP2517fd.
-+ - reg: SPI chip select.
-+ - clocks: The clock feeding the CAN controller.
-+ - interrupt-parent: The parent interrupt controller.
-+ - interrupts: Should contain IRQ line for the CAN controller.
-+ - gpio-controller: Marks the device node as a GPIO controller
-+
-+Optional properties:
-+ - vdd-supply: Regulator that powers the CAN controller.
-+ - xceiver-supply: Regulator that powers the CAN transceiver.
-+ - microchip,clock-out-div = <0|1|2|4|10>: Clock output pin divider
-+					   0 = Start of Frame output
-+					   default: 10
-+ - microchip,clock-div2: bool: divide the internal clock by 2
-+ - microchip,gpio-open-drain: bool: enable open-drain for all pins
-+                                    (except cantx)
-+
-+Example:
-+	can0: can@1 {
-+		compatible = "microchip,mcp2517fd";
-+		reg = <1>;
-+		clocks = <&clk24m>;
-+		interrupt-parent = <&gpio4>;
-+		interrupts = <13 0x8>;
-+		vdd-supply = <&reg5v0>;
-+		xceiver-supply = <&reg5v0>;
-+		gpio-controller;
-+	};
-diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
-index 566529092366..33b6e205ea01 100644
---- a/arch/arm/boot/dts/Makefile
-+++ b/arch/arm/boot/dts/Makefile
-@@ -78,11 +78,15 @@ dtb-$(CONFIG_ARCH_BCM2835) += \
- 	bcm2835-rpi-b-plus.dtb \
- 	bcm2835-rpi-a-plus.dtb \
- 	bcm2835-rpi-cm1-io1.dtb \
-+	bcm2835-rpi-cm1-io1-mcp2517fd.dtb \
- 	bcm2836-rpi-2-b.dtb \
- 	bcm2837-rpi-3-b.dtb \
- 	bcm2837-rpi-3-b-plus.dtb \
- 	bcm2835-rpi-zero.dtb \
--	bcm2835-rpi-zero-w.dtb
-+	bcm2835-rpi-zero-w.dtb \
-+	bcm2837-rpi-cm3-io3.dtb \
-+	bcm2837-rpi-cm3-io3x.dtb \
-+        bcm2837-rpi-cm3-io3-mcp2517fd.dtb
- dtb-$(CONFIG_ARCH_BCM_5301X) += \
- 	bcm4708-asus-rt-ac56u.dtb \
- 	bcm4708-asus-rt-ac68u.dtb \
-diff --git a/arch/arm/boot/dts/bcm2835-rpi-cm1-io1-mcp2517fd.dts b/arch/arm/boot/dts/bcm2835-rpi-cm1-io1-mcp2517fd.dts
-new file mode 100644
-index 000000000000..4294b5d07257
---- /dev/null
-+++ b/arch/arm/boot/dts/bcm2835-rpi-cm1-io1-mcp2517fd.dts
-@@ -0,0 +1,37 @@
-+#include "bcm2835-rpi-cm1-io1.dts"
-+
-+/ {
-+ soc {
-+  can0_osc: can0_osc {
-+   compatible = "fixed-clock";
-+   #clock-cells = <0>;
-+   clock-frequency  = <4000000>;
-+  };
-+ };
-+};
-+
-+&gpio {
-+  can0_pins: can0_pins {
-+   brcm,pins = <16>;
-+   brcm,function = <0>; /* input */
-+  };
-+};
-+
-+&spi {
-+ status = "okay";
-+//  pinctrl-names = "default";
-+//  pinctrl-0 = <&spi0_gpio7>;
-+ dmas = <&dma 6>, <&dma 7>;
-+ dma-names = "tx", "rx";
-+
-+mcp2517fdcan0: can@0 {
-+  compatible = "microchip,mcp2517fd";
-+  pinctrl-names = "default";
-+  pinctrl-0 = <&can0_pins>;
-+  reg = <0>;
-+  clocks = <&can0_osc>;
-+  spi-max-frequency = <12500000>;
-+  interrupt-parent = <&gpio>;
-+  interrupts = <16 0x8>;
-+ };
-+};
-diff --git a/arch/arm/boot/dts/bcm2837-rpi-cm3-io3-mcp2517fd.dts b/arch/arm/boot/dts/bcm2837-rpi-cm3-io3-mcp2517fd.dts
-new file mode 100644
-index 000000000000..5fd1586df0bd
---- /dev/null
-+++ b/arch/arm/boot/dts/bcm2837-rpi-cm3-io3-mcp2517fd.dts
-@@ -0,0 +1,37 @@
-+#include "bcm2837-rpi-cm3-io3.dts"
-+
-+/ {
-+ soc {
-+  can0_osc: can0_osc {
-+   compatible = "fixed-clock";
-+   #clock-cells = <0>;
-+   clock-frequency  = <4000000>;
-+  };
-+ };
-+};
-+
-+&gpio {
-+  can0_pins: can0_pins {
-+   brcm,pins = <16>;
-+   brcm,function = <0>; /* input */
-+  };
-+};
-+
-+&spi {
-+ status = "okay";
-+//  pinctrl-names = "default";
-+//  pinctrl-0 = <&spi0_gpio7>;
-+ dmas = <&dma 6>, <&dma 7>;
-+ dma-names = "tx", "rx";
-+
-+mcp2517fdcan0: can@0 {
-+  compatible = "microchip,mcp2517fd";
-+  pinctrl-names = "default";
-+  pinctrl-0 = <&can0_pins>;
-+  reg = <0>;
-+  clocks = <&can0_osc>;
-+  spi-max-frequency = <12500000>;
-+  interrupt-parent = <&gpio>;
-+  interrupts = <16 0x8>;
-+ };
-+};
-diff --git a/arch/arm/boot/dts/bcm2837-rpi-cm3-io3x.dts b/arch/arm/boot/dts/bcm2837-rpi-cm3-io3x.dts
-new file mode 120000
-index 000000000000..bf7587580334
---- /dev/null
-+++ b/arch/arm/boot/dts/bcm2837-rpi-cm3-io3x.dts
-@@ -0,0 +1 @@
-+bcm2837-rpi-cm3-io3-mcp2517fd.dts
-\ No newline at end of file
-diff --git a/drivers/net/can/spi/Kconfig b/drivers/net/can/spi/Kconfig
-index 8f2e0dd7b756..7a5b1436492e 100644
---- a/drivers/net/can/spi/Kconfig
-+++ b/drivers/net/can/spi/Kconfig
-@@ -13,4 +13,6 @@ config CAN_MCP251X
- 	---help---
- 	  Driver for the Microchip MCP251x SPI CAN controllers.
- 
-+source "drivers/net/can/spi/mcp25xxfd/Kconfig"
-+
- endmenu
-diff --git a/drivers/net/can/spi/Makefile b/drivers/net/can/spi/Makefile
-index f59fa3731073..67d3ad21730b 100644
---- a/drivers/net/can/spi/Makefile
-+++ b/drivers/net/can/spi/Makefile
-@@ -5,3 +5,5 @@
- 
- obj-$(CONFIG_CAN_HI311X)	+= hi311x.o
- obj-$(CONFIG_CAN_MCP251X)	+= mcp251x.o
-+
-+obj-y                           += mcp25xxfd/
-diff --git a/drivers/net/can/spi/mcp25xxfd/Kconfig b/drivers/net/can/spi/mcp25xxfd/Kconfig
-new file mode 100644
-index 000000000000..f720f1377612
---- /dev/null
-+++ b/drivers/net/can/spi/mcp25xxfd/Kconfig
-@@ -0,0 +1,5 @@
-+config CAN_MCP25XXFD
-+	tristate "Microchip MCP25xxFD SPI CAN controllers"
-+	depends on HAS_DMA
-+	help
-+	  Driver for the Microchip MCP25XXFD SPI FD-CAN controller family.
-diff --git a/drivers/net/can/spi/mcp25xxfd/Makefile b/drivers/net/can/spi/mcp25xxfd/Makefile
-new file mode 100644
-index 000000000000..8f455881b639
---- /dev/null
-+++ b/drivers/net/can/spi/mcp25xxfd/Makefile
-@@ -0,0 +1,18 @@
-+#
-+#  Makefile for the Linux Controller Area Network SPI drivers.
-+#
-+obj-$(CONFIG_CAN_MCP25XXFD)	+= mcp25xxfd.o
-+mcp25xxfd-objs                  := mcp25xxfd_base.o
-+mcp25xxfd-objs                  += mcp25xxfd_can.o
-+mcp25xxfd-objs                  += mcp25xxfd_can_debugfs.o
-+mcp25xxfd-objs                  += mcp25xxfd_can_fifo.o
-+mcp25xxfd-objs                  += mcp25xxfd_can_int.o
-+mcp25xxfd-objs                  += mcp25xxfd_can_rx.o
-+mcp25xxfd-objs                  += mcp25xxfd_can_tx.o
-+mcp25xxfd-objs                  += mcp25xxfd_clock.o
-+mcp25xxfd-objs                  += mcp25xxfd_cmd.o
-+mcp25xxfd-objs                  += mcp25xxfd_crc.o
-+mcp25xxfd-objs                  += mcp25xxfd_debugfs.o
-+mcp25xxfd-objs                  += mcp25xxfd_ecc.o
-+mcp25xxfd-objs                  += mcp25xxfd_gpio.o
-+mcp25xxfd-objs                  += mcp25xxfd_int.o
-diff --git a/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_base.c b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_base.c
-new file mode 100644
-index 000000000000..5db4a5812952
---- /dev/null
-+++ b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_base.c
-@@ -0,0 +1,281 @@
-+// SPDX-License-Identifier: GPL-2.0
-+
-+/* CAN bus driver for Microchip 25XXFD CAN Controller with SPI Interface
-+ *
-+ * Copyright 2019 Martin Sperl <kernel@martin.sperl.org>
-+ */
-+
-+#include <linux/interrupt.h>
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/of_device.h>
-+#include <linux/platform_device.h>
-+#include <linux/slab.h>
-+
-+#include "mcp25xxfd_can.h"
-+#include "mcp25xxfd_clock.h"
-+#include "mcp25xxfd_cmd.h"
-+#include "mcp25xxfd_debugfs.h"
-+#include "mcp25xxfd_ecc.h"
-+#include "mcp25xxfd_gpio.h"
-+#include "mcp25xxfd_int.h"
-+#include "mcp25xxfd_priv.h"
-+
-+/* Device description and rational:
-+ *
-+ * The mcp25xxfd is a CanFD controller that also supports can2.0 only
-+ * modes.
-+ * It is connected via spi to the host and requires at minimum a single
-+ * irq line in addition to the SPI lines - it is not mentioned explicitly
-+ * in the documentation but in principle SPI 3-wire should be possible.
-+ *
-+ * The clock connected is typically 4MHz, 20MHz or 40MHz.
-+ * When using a 4MHz clock the controller can use an integrated PLL to
-+ * get 40MHz.
-+ *
-+ * The controller itself has 2KB of SRAM for CAN-data.
-+ * ECC can get enabled for SRAM.
-+ * CRC-16 checksumming of SPI transfers can get implemented
-+ *   - some optimization options may not be efficient in such a situation.
-+ *   - more SPI bus bandwidth is used for transfer of CRCs and
-+ *     transfer length information
-+ *
-+ * It also contains 2 GPIO pins that can get used either as interrupt lines
-+ * or GPIO IN or Out or STANDBY flags.
-+ * In addition there is a PIN that allows output of a (divided) clock out
-+ * or as a SOF (Start of Can FRAME) interrupt line - e.g for wakeup.
-+ */
-+
-+int mcp25xxfd_base_power_enable(struct regulator *reg, int enable)
-+{
-+	if (IS_ERR_OR_NULL(reg))
-+		return 0;
-+
-+	if (enable)
-+		return regulator_enable(reg);
-+	else
-+		return regulator_disable(reg);
-+}
-+
-+static const struct of_device_id mcp25xxfd_of_match[] = {
-+	{
-+		.compatible	= "microchip,mcp2517fd",
-+		.data		= (void *)CAN_MCP2517FD,
-+	},
-+	{ }
-+};
-+MODULE_DEVICE_TABLE(of, mcp25xxfd_of_match);
-+
-+static int mcp25xxfd_base_probe(struct spi_device *spi)
-+{
-+	const struct of_device_id *of_id =
-+		of_match_device(mcp25xxfd_of_match, &spi->dev);
-+	struct mcp25xxfd_priv *priv;
-+	int ret;
-+
-+	/* as irq_create_fwspec_mapping() can return 0, check for it */
-+	if (spi->irq <= 0) {
-+		dev_err(&spi->dev, "no valid irq line defined: irq = %i\n",
-+			spi->irq);
-+		return -EINVAL;
-+	}
-+
-+	priv = devm_kzalloc(&spi->dev, sizeof(*priv), GFP_KERNEL);
-+	if (!priv)
-+		return -ENOMEM;
-+
-+	/* cross assigns */
-+	spi_set_drvdata(spi, priv);
-+	priv->spi = spi;
-+
-+	/* assign name */
-+	snprintf(priv->device_name, sizeof(priv->device_name),
-+		 DEVICE_NAME "-%s", dev_name(&priv->spi->dev));
-+
-+	/* assign model from of or driver_data */
-+	if (of_id)
-+		priv->model = (enum mcp25xxfd_model)of_id->data;
-+	else
-+		priv->model = spi_get_device_id(spi)->driver_data;
-+
-+	mutex_init(&priv->spi_rxtx_lock);
-+
-+	ret = mcp25xxfd_clock_init(priv);
-+	if (ret)
-+		goto out_free;
-+
-+	/* Configure the SPI bus */
-+	spi->bits_per_word = 8;
-+	ret = spi_setup(spi);
-+	if (ret)
-+		goto out_clk;
-+
-+	priv->power = devm_regulator_get_optional(&spi->dev, "vdd");
-+	if (PTR_ERR(priv->power) == -EPROBE_DEFER) {
-+		ret = -EPROBE_DEFER;
-+		goto out_clk;
-+	}
-+
-+	ret = mcp25xxfd_base_power_enable(priv->power, 1);
-+	if (ret)
-+		goto out_clk;
-+
-+	/* this will also enable the MCP25XXFD_CLK_USER_CAN clock */
-+	ret = mcp25xxfd_clock_probe(priv);
-+	if (ret)
-+		goto out_probe;
-+
-+	/* enable the can controller clock */
-+	ret = mcp25xxfd_clock_start(priv, MCP25XXFD_CLK_USER_CAN);
-+	if (ret)
-+		goto out_probe;
-+
-+	/* try to identify the can-controller - we need the clock here */
-+	ret = mcp25xxfd_can_probe(priv);
-+	if (ret)
-+		goto out_ctlclk;
-+
-+	/* add debugfs */
-+	mcp25xxfd_debugfs_setup(priv);
-+
-+	/* disable interrupts */
-+	ret = mcp25xxfd_int_enable(priv, false);
-+	if (ret)
-+		goto out_debugfs;
-+
-+	/* setup ECC for SRAM */
-+	ret = mcp25xxfd_ecc_enable(priv);
-+	if (ret)
-+		goto out_debugfs;
-+
-+	/* setting up GPIO */
-+	ret = mcp25xxfd_gpio_setup(priv);
-+	if (ret)
-+		goto out_debugfs;
-+
-+	/* setting up CAN */
-+	ret = mcp25xxfd_can_setup(priv);
-+	if (ret)
-+		goto out_gpio;
-+
-+	/* and put controller to sleep by stopping the can clock */
-+	ret = mcp25xxfd_clock_stop(priv, MCP25XXFD_CLK_USER_CAN);
-+	if (ret)
-+		goto out_can;
-+
-+	dev_info(&spi->dev,
-+		 "MCP%x successfully initialized.\n", priv->model);
-+	return 0;
-+
-+out_can:
-+	mcp25xxfd_can_remove(priv);
-+out_gpio:
-+	mcp25xxfd_gpio_remove(priv);
-+out_debugfs:
-+	mcp25xxfd_debugfs_remove(priv);
-+out_ctlclk:
-+	mcp25xxfd_clock_stop(priv, MCP25XXFD_CLK_USER_CAN);
-+out_probe:
-+	mcp25xxfd_base_power_enable(priv->power, 0);
-+out_clk:
-+	mcp25xxfd_clock_release(priv);
-+out_free:
-+	dev_err(&spi->dev, "Probe failed, err=%d\n", -ret);
-+	return ret;
-+}
-+
-+static int mcp25xxfd_base_remove(struct spi_device *spi)
-+{
-+	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
-+
-+	/* remove can */
-+	mcp25xxfd_can_remove(priv);
-+
-+	/* remove gpio */
-+	mcp25xxfd_gpio_remove(priv);
-+
-+	/* clear all running clocks */
-+	mcp25xxfd_clock_stop(priv, priv->clk_user_mask);
-+
-+	mcp25xxfd_debugfs_remove(priv);
-+
-+	mcp25xxfd_base_power_enable(priv->power, 0);
-+
-+	mcp25xxfd_clock_release(priv);
-+
-+	return 0;
-+}
-+
-+static int __maybe_unused mcp25xxfd_base_suspend(struct device *dev)
-+{
-+	struct spi_device *spi = to_spi_device(dev);
-+	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
-+
-+	mutex_lock(&priv->clk_user_lock);
-+	priv->clk_sleep_mask = priv->clk_user_mask;
-+	mutex_unlock(&priv->clk_user_lock);
-+
-+	/* disable interrupts */
-+	mcp25xxfd_int_enable(priv, false);
-+
-+	/* stop the clocks */
-+	mcp25xxfd_clock_stop(priv, priv->clk_sleep_mask);
-+
-+	/* disable power to controller */
-+	return mcp25xxfd_base_power_enable(priv->power, 0);
-+}
-+
-+static int __maybe_unused mcp25xxfd_base_resume(struct device *dev)
-+{
-+	struct spi_device *spi = to_spi_device(dev);
-+	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
-+	int ret = 0;
-+
-+	/* enable power to controller */
-+	mcp25xxfd_base_power_enable(priv->power, 1);
-+
-+	/* if there is no sleep mask, then there is nothing to wake */
-+	if (!priv->clk_sleep_mask)
-+		return 0;
-+
-+	/* start the clocks */
-+	ret = mcp25xxfd_clock_start(priv, priv->clk_sleep_mask);
-+	if (ret)
-+		return 0;
-+
-+	/* clear the sleep mask */
-+	mutex_lock(&priv->clk_user_lock);
-+	priv->clk_sleep_mask = 0;
-+	mutex_unlock(&priv->clk_user_lock);
-+
-+	/* enable the interrupts again */
-+	return mcp25xxfd_int_enable(priv, true);
-+}
-+
-+static SIMPLE_DEV_PM_OPS(mcp25xxfd_base_pm_ops, mcp25xxfd_base_suspend,
-+			 mcp25xxfd_base_resume);
-+
-+static const struct spi_device_id mcp25xxfd_id_table[] = {
-+	{
-+		.name		= "mcp2517fd",
-+		.driver_data	= (kernel_ulong_t)CAN_MCP2517FD,
-+	},
-+	{ }
-+};
-+MODULE_DEVICE_TABLE(spi, mcp25xxfd_id_table);
-+
-+static struct spi_driver mcp25xxfd_can_driver = {
-+	.driver = {
-+		.name = DEVICE_NAME,
-+		.of_match_table = mcp25xxfd_of_match,
-+		.pm = &mcp25xxfd_base_pm_ops,
-+	},
-+	.id_table = mcp25xxfd_id_table,
-+	.probe = mcp25xxfd_base_probe,
-+	.remove = mcp25xxfd_base_remove,
-+};
-+module_spi_driver(mcp25xxfd_can_driver);
-+
-+MODULE_AUTHOR("Martin Sperl <kernel@martin.sperl.org>");
-+MODULE_DESCRIPTION("Microchip 25XXFD CAN driver");
-+MODULE_LICENSE("GPL v2");
-diff --git a/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_base.h b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_base.h
-new file mode 100644
-index 000000000000..4559ac60645c
---- /dev/null
-+++ b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_base.h
-@@ -0,0 +1,14 @@
-+/* SPDX-License-Identifier: GPL-2.0 */
-+
-+/* CAN bus driver for Microchip 25XXFD CAN Controller with SPI Interface
-+ *
-+ * Copyright 2019 Martin Sperl <kernel@martin.sperl.org>
-+ */
-+#ifndef __MCP25XXFD_BASE_H
-+#define __MCP25XXFD_BASE_H
-+
-+#include <linux/regulator/consumer.h>
-+
-+int mcp25xxfd_base_power_enable(struct regulator *reg, int enable);
-+
-+#endif /* __MCP25XXFD_BASE_H */
-diff --git a/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can.c b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can.c
-new file mode 100644
-index 000000000000..e28aad2b6ac8
---- /dev/null
-+++ b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can.c
-@@ -0,0 +1,684 @@
-+// SPDX-License-Identifier: GPL-2.0
-+
-+/* CAN bus driver for Microchip 25XXFD CAN Controller with SPI Interface
-+ *
-+ * Copyright 2019 Martin Sperl <kernel@martin.sperl.org>
-+ */
-+
-+/* controller details
-+ *
-+ *  It has 32 FIFOs (of up to 32 CAN-frames).
-+ *
-+ * There are 4 Fifo types which can get configured:
-+ * * TEF - Transmission Event Fifo - which consumes FIFO 0
-+ *   even if it is not configured
-+ * * Tansmission Queue - for up to 32 Frames.
-+ *   this queue reorders CAN frames to get transmitted following the
-+ *   typical CAN dominant/recessive rules on the can bus itself.
-+ *   This FIFO is optional.
-+ * * TX FIFO: generic TX fifos that can contain arbitrary data
-+ *   and which come with a configurable priority for transmission
-+ *   It is also possible to have the Controller automatically trigger
-+ *   a transfer when a Filter Rule for a RTR frame matches.
-+ *   Each of these fifos in principle can get configured for distinct
-+ *   dlc sizes (8 thru 64 bytes)
-+ * * RX FIFO: generic RX fifo which is filled via filter-rules.
-+ *   Each of these fifos in principle can get configured for distinct
-+ *   dlc sizes (8 thru 64 bytes)
-+ *   Unfortunately there is no filter rule that would allow triggering
-+ *   on different frame sizes, so for all practical purposes the
-+ *   RX fifos have to be of the same size (unless one wants to experience
-+ *   lost data).
-+ * When a Can Frame is transmitted from the TX Queue or an individual
-+ * TX FIFO then a small TEF Frame can get added to the TEF FIFO queue
-+ * to log the Transmission of the frame - this includes ID, Flags
-+ * (including a custom identifier/index) and the timestamp (see below).
-+ *
-+ * The controller provides an optional free running counter with a divider
-+ * for timestamping of RX frames as well as for TEF entries.
-+ */
-+
-+#include <linux/can/core.h>
-+#include <linux/can/dev.h>
-+#include <linux/device.h>
-+#include <linux/interrupt.h>
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/of.h>
-+#include <linux/regulator/consumer.h>
-+#include <linux/spi/spi.h>
-+
-+#include "mcp25xxfd_base.h"
-+#include "mcp25xxfd_can_debugfs.h"
-+#include "mcp25xxfd_can_fifo.h"
-+#include "mcp25xxfd_can_int.h"
-+#include "mcp25xxfd_can_priv.h"
-+#include "mcp25xxfd_can_tx.h"
-+#include "mcp25xxfd_clock.h"
-+#include "mcp25xxfd_cmd.h"
-+#include "mcp25xxfd_int.h"
-+#include "mcp25xxfd_priv.h"
-+#include "mcp25xxfd_regs.h"
-+
-+#include <uapi/linux/can/netlink.h>
-+
-+/* module parameters */
-+unsigned int bw_sharing_log2bits;
-+module_param(bw_sharing_log2bits, uint, 0664);
-+MODULE_PARM_DESC(bw_sharing_log2bits,
-+		 "Delay between 2 transmissions in number of arbitration bit times\n");
-+bool enable_edge_filter;
-+module_param(enable_edge_filter, bool, 0664);
-+MODULE_PARM_DESC(enable_edge_filter,
-+		 "Enable ISO11898-1:2015 edge_filtering");
-+unsigned int tdc_mode = 2;
-+module_param(tdc_mode, uint, 0664);
-+MODULE_PARM_DESC(tdc_mode,
-+		 "Transmitter Delay Mode - 0 = disabled, 1 = fixed, 2 = auto\n");
-+unsigned int tdc_value;
-+module_param(tdc_value, uint, 0664);
-+MODULE_PARM_DESC(tdc_value,
-+		 "Transmission Delay Value - range: [0:63] SCLK");
-+int tdc_offset = 64; /* outside of range to use computed values */
-+module_param(tdc_offset, int, 0664);
-+MODULE_PARM_DESC(tdc_offset,
-+		 "Transmission Delay offset - range: [-64:63] SCLK");
-+
-+/* everything related to bit timing */
-+static
-+const struct can_bittiming_const mcp25xxfd_can_nominal_bittiming_const = {
-+	.name           = DEVICE_NAME,
-+	.tseg1_min      = 2,
-+	.tseg1_max      = BIT(MCP25XXFD_CAN_NBTCFG_TSEG1_BITS),
-+	.tseg2_min      = 1,
-+	.tseg2_max      = BIT(MCP25XXFD_CAN_NBTCFG_TSEG2_BITS),
-+	.sjw_max        = BIT(MCP25XXFD_CAN_NBTCFG_SJW_BITS),
-+	.brp_min        = 1,
-+	.brp_max        = BIT(MCP25XXFD_CAN_NBTCFG_BRP_BITS),
-+	.brp_inc        = 1,
-+};
-+
-+static
-+const struct can_bittiming_const mcp25xxfd_can_data_bittiming_const = {
-+	.name           = DEVICE_NAME,
-+	.tseg1_min      = 1,
-+	.tseg1_max      = BIT(MCP25XXFD_CAN_DBTCFG_TSEG1_BITS),
-+	.tseg2_min      = 1,
-+	.tseg2_max      = BIT(MCP25XXFD_CAN_DBTCFG_TSEG2_BITS),
-+	.sjw_max        = BIT(MCP25XXFD_CAN_DBTCFG_SJW_BITS),
-+	.brp_min        = 1,
-+	.brp_max        = BIT(MCP25XXFD_CAN_DBTCFG_BRP_BITS),
-+	.brp_inc        = 1,
-+};
-+
-+static int mcp25xxfd_can_do_set_nominal_bittiming(struct net_device *net)
-+{
-+	struct mcp25xxfd_can_priv *cpriv = netdev_priv(net);
-+	struct can_bittiming *bt = &cpriv->can.bittiming;
-+
-+	int sjw = bt->sjw;
-+	int pseg2 = bt->phase_seg2;
-+	int pseg1 = bt->phase_seg1;
-+	int propseg = bt->prop_seg;
-+	int brp = bt->brp;
-+
-+	int tseg1 = propseg + pseg1;
-+	int tseg2 = pseg2;
-+
-+	/* calculate nominal bit timing */
-+	cpriv->regs.nbtcfg = ((sjw - 1) << MCP25XXFD_CAN_NBTCFG_SJW_SHIFT) |
-+		((tseg2 - 1) << MCP25XXFD_CAN_NBTCFG_TSEG2_SHIFT) |
-+		((tseg1 - 1) << MCP25XXFD_CAN_NBTCFG_TSEG1_SHIFT) |
-+		((brp - 1) << MCP25XXFD_CAN_NBTCFG_BRP_SHIFT);
-+
-+	return mcp25xxfd_cmd_write(cpriv->priv->spi, MCP25XXFD_CAN_NBTCFG,
-+				   cpriv->regs.nbtcfg);
-+}
-+
-+static int mcp25xxfd_can_do_set_data_bittiming(struct net_device *net)
-+{
-+	struct mcp25xxfd_can_priv *cpriv = netdev_priv(net);
-+	struct mcp25xxfd_priv *priv = cpriv->priv;
-+	struct can_bittiming *bt = &cpriv->can.data_bittiming;
-+	struct spi_device *spi = priv->spi;
-+
-+	int sjw = bt->sjw;
-+	int pseg2 = bt->phase_seg2;
-+	int pseg1 = bt->phase_seg1;
-+	int propseg = bt->prop_seg;
-+	int brp = bt->brp;
-+
-+	int tseg1 = propseg + pseg1;
-+	int tseg2 = pseg2;
-+
-+	int tdco;
-+	int ret;
-+
-+	/* set up Transmitter delay compensation */
-+	cpriv->regs.tdc = 0;
-+	/* configure TDC mode */
-+	if (tdc_mode < 4)
-+		cpriv->regs.tdc = tdc_mode << MCP25XXFD_CAN_TDC_TDCMOD_SHIFT;
-+	else
-+		cpriv->regs.tdc = MCP25XXFD_CAN_TDC_TDCMOD_AUTO <<
-+			MCP25XXFD_CAN_TDC_TDCMOD_SHIFT;
-+
-+	/* configure TDC offsets */
-+	if ((tdc_offset >= -64) && tdc_offset < 64)
-+		tdco = tdc_offset;
-+	else
-+		tdco = clamp_t(int, bt->brp * tseg1, -64, 63);
-+	cpriv->regs.tdc |= (tdco << MCP25XXFD_CAN_TDC_TDCO_SHIFT) &
-+		MCP25XXFD_CAN_TDC_TDCO_MASK;
-+
-+	/* configure TDC value */
-+	if (tdc_value < 64)
-+		cpriv->regs.tdc |= tdc_value << MCP25XXFD_CAN_TDC_TDCV_SHIFT;
-+
-+	/* enable edge filtering */
-+	if (enable_edge_filter)
-+		cpriv->regs.tdc |= MCP25XXFD_CAN_TDC_EDGFLTEN;
-+
-+	/* set TDC */
-+	ret = mcp25xxfd_cmd_write(spi, MCP25XXFD_CAN_TDC, cpriv->regs.tdc);
-+	if (ret)
-+		return ret;
-+
-+	/* calculate data bit timing */
-+	cpriv->regs.dbtcfg = ((sjw - 1) << MCP25XXFD_CAN_DBTCFG_SJW_SHIFT) |
-+		((tseg2 - 1) << MCP25XXFD_CAN_DBTCFG_TSEG2_SHIFT) |
-+		((tseg1 - 1) << MCP25XXFD_CAN_DBTCFG_TSEG1_SHIFT) |
-+		((brp - 1) << MCP25XXFD_CAN_DBTCFG_BRP_SHIFT);
-+
-+	return mcp25xxfd_cmd_write(spi, MCP25XXFD_CAN_DBTCFG,
-+				   cpriv->regs.dbtcfg);
-+}
-+
-+int mcp25xxfd_can_get_mode(struct mcp25xxfd_priv *priv, u32 *reg)
-+{
-+	int ret;
-+
-+	ret = mcp25xxfd_cmd_read(priv->spi, MCP25XXFD_CAN_CON, reg);
-+	if (ret)
-+		return ret;
-+
-+	return (*reg & MCP25XXFD_CAN_CON_OPMOD_MASK) >>
-+		MCP25XXFD_CAN_CON_OPMOD_SHIFT;
-+}
-+
-+int mcp25xxfd_can_switch_mode_no_wait(struct mcp25xxfd_priv *priv,
-+				      u32 *reg, int mode)
-+{
-+	u32 dummy;
-+	int ret;
-+
-+	/* get the current mode/register - if reg is NULL
-+	 * when the can controller is not setup yet
-+	 * typically by calling mcp25xxfd_can_sleep_mode
-+	 * (this only happens during initialization phase)
-+	 */
-+	if (reg) {
-+		if (!reg) {
-+			ret = mcp25xxfd_can_get_mode(priv, reg);
-+			if (ret < 0)
-+				return ret;
-+		}
-+	} else {
-+		/* alternatively use dummy */
-+		dummy = 0;
-+		reg = &dummy;
-+	}
-+
-+	/* compute the effective mode in osc*/
-+	*reg &= ~(MCP25XXFD_CAN_CON_REQOP_MASK |
-+		  MCP25XXFD_CAN_CON_OPMOD_MASK);
-+	*reg |= (mode << MCP25XXFD_CAN_CON_REQOP_SHIFT) |
-+		(mode << MCP25XXFD_CAN_CON_OPMOD_SHIFT);
-+
-+	/* if the opmode is sleep then the oscilator will be disabled
-+	 * and also not ready, so fake this change
-+	 */
-+	if (mode == MCP25XXFD_CAN_CON_MODE_SLEEP)
-+		mcp25xxfd_clock_fake_sleep(priv);
-+
-+	/* request the mode switch */
-+	return mcp25xxfd_cmd_write(priv->spi, MCP25XXFD_CAN_CON, *reg);
-+}
-+
-+int mcp25xxfd_can_switch_mode(struct mcp25xxfd_priv *priv, u32 *reg, int mode)
-+{
-+	int ret, i;
-+
-+	/* trigger the mode switch itself */
-+	ret = mcp25xxfd_can_switch_mode_no_wait(priv, reg, mode);
-+	if (ret)
-+		return ret;
-+
-+	/* if we are in now sleep mode then return immediately
-+	 * the controller does not respond back!
-+	 */
-+	if (mode == MCP25XXFD_CAN_CON_MODE_SLEEP)
-+		return 0;
-+
-+	/* wait for it to stabilize/switch mode
-+	 * we assume 256 rounds should be enough as this is > 12ms
-+	 * at 1MHz Can Bus speed without any extra overhead
-+	 *
-+	 * The assumption here is that it depends on bus activity
-+	 * how long it takes the controller to switch modes
-+	 */
-+	for (i = 0; i < 256; i++) {
-+		/* get the mode */
-+		ret = mcp25xxfd_can_get_mode(priv, reg);
-+		if (ret < 0)
-+			return ret;
-+		/* check that we have reached our mode */
-+		if (ret == mode)
-+			return 0;
-+	}
-+
-+	dev_err(&priv->spi->dev, "Failed to switch to mode %u in time\n",
-+		mode);
-+	return -ETIMEDOUT;
-+}
-+
-+static int mcp25xxfd_can_probe_modeswitch(struct mcp25xxfd_priv *priv)
-+{
-+	u32 mode_data;
-+	int ret;
-+
-+	/* so we should be in config mode now, so move to INT_LOOPBACK */
-+	ret = mcp25xxfd_can_switch_mode(priv, &mode_data,
-+					MCP25XXFD_CAN_CON_MODE_INT_LOOPBACK);
-+	if (ret) {
-+		dev_err(&priv->spi->dev,
-+			"Failed to switch into loopback mode\n");
-+		return ret;
-+	}
-+
-+	/* and back into config mode */
-+	ret = mcp25xxfd_can_switch_mode(priv, &mode_data,
-+					MCP25XXFD_CAN_CON_MODE_CONFIG);
-+	if (ret) {
-+		dev_err(&priv->spi->dev,
-+			"Failed to switch back to config mode\n");
-+		return ret;
-+	}
-+
-+	/* so we have checked basic functionality successfully */
-+	return 0;
-+}
-+
-+int mcp25xxfd_can_sleep_mode(struct mcp25xxfd_priv *priv)
-+{
-+	return mcp25xxfd_can_switch_mode(priv, NULL,
-+					 MCP25XXFD_CAN_CON_MODE_SLEEP);
-+}
-+
-+int mcp25xxfd_can_probe(struct mcp25xxfd_priv *priv)
-+{
-+	struct spi_device *spi = priv->spi;
-+	u32 mode_data;
-+	int mode, ret;
-+
-+	/* read TXQCON - the TXEN bit should always read as 1 */
-+	ret = mcp25xxfd_cmd_read(spi, MCP25XXFD_CAN_TXQCON, &mode_data);
-+	if (ret)
-+		return ret;
-+	if ((mode_data & MCP25XXFD_CAN_TXQCON_TXEN) == 0) {
-+		dev_err(&spi->dev,
-+			"Register TXQCON does not have bit TXEN set - reads as %08x - this may be a problem with spi bus signal quality - try reducing spi-clock speed if this can get reproduced",
-+			mode_data);
-+		return -EINVAL;
-+	}
-+
-+	/* try to get the current mode */
-+	mode = mcp25xxfd_can_get_mode(priv, &mode_data);
-+	if (mode < 0)
-+		return mode;
-+
-+	/* we would expect to be in config mode, as a SPI-reset should
-+	 * have moved us into config mode.
-+	 * But then the documentation says that SPI-reset may only work
-+	 * reliably when already in config mode
-+	 */
-+
-+	/* so if we are in config mode then everything is fine
-+	 * and we check that a mode switch works propperly
-+	 */
-+	if (mode == MCP25XXFD_CAN_CON_MODE_CONFIG)
-+		return mcp25xxfd_can_probe_modeswitch(priv);
-+
-+	/* if the bitfield is 0 then there is something is wrong */
-+	if (!mode_data) {
-+		dev_err(&spi->dev,
-+			"got controller config register reading as 0\n");
-+		return -EINVAL;
-+	}
-+
-+	/* any other mode is unexpected */
-+	dev_err(&spi->dev,
-+		"Found controller in unexpected mode %i - register reads as %08x\n",
-+		mode, mode_data);
-+
-+	/* so try to move to config mode
-+	 * if this fails, then everything is lost and the controller
-+	 * is not identified
-+	 * This action MAY be destructive if a different device is connected
-+	 * but note that the first hurdle (oscillator) was already
-+	 * successful - so we should be safe...
-+	 */
-+	ret = mcp25xxfd_can_switch_mode(priv, &mode_data,
-+					MCP25XXFD_CAN_CON_MODE_CONFIG);
-+	if (ret) {
-+		dev_err(&priv->spi->dev,
-+			"Mode did not switch to config as expected - could not identify controller - register reads as %08x\n",
-+			mode_data);
-+		return -EINVAL;
-+	}
-+	/* check that modeswitch is really working */
-+	return mcp25xxfd_can_probe_modeswitch(priv);
-+}
-+
-+static int mcp25xxfd_can_config(struct net_device *net)
-+{
-+	struct mcp25xxfd_can_priv *cpriv = netdev_priv(net);
-+	struct mcp25xxfd_priv *priv = cpriv->priv;
-+	struct spi_device *spi = priv->spi;
-+	int ret;
-+
-+	/* setup value of con_register */
-+	cpriv->regs.con = MCP25XXFD_CAN_CON_STEF; /* enable TEF, disable TXQ */
-+
-+	/* transmission bandwidth sharing bits */
-+	if (bw_sharing_log2bits > 12)
-+		bw_sharing_log2bits = 12;
-+	cpriv->regs.con |= bw_sharing_log2bits <<
-+		MCP25XXFD_CAN_CON_TXBWS_SHIFT;
-+
-+	/* non iso FD mode */
-+	if (!(cpriv->can.ctrlmode & CAN_CTRLMODE_FD_NON_ISO))
-+		cpriv->regs.con |= MCP25XXFD_CAN_CON_ISOCRCEN;
-+
-+	/* one shot */
-+	if (cpriv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT)
-+		cpriv->regs.con |= MCP25XXFD_CAN_CON_RTXAT;
-+
-+	/* apply it now together with a mode switch */
-+	ret = mcp25xxfd_can_switch_mode(cpriv->priv, &cpriv->regs.con,
-+					MCP25XXFD_CAN_CON_MODE_CONFIG);
-+	if (ret)
-+		return 0;
-+
-+	/* time stamp control register - 1ns resolution */
-+	cpriv->regs.tscon = 0;
-+	ret = mcp25xxfd_cmd_write(spi, MCP25XXFD_CAN_TBC, 0);
-+	if (ret)
-+		return ret;
-+
-+	cpriv->regs.tscon = MCP25XXFD_CAN_TSCON_TBCEN |
-+		((cpriv->can.clock.freq / 1000000)
-+		 << MCP25XXFD_CAN_TSCON_TBCPRE_SHIFT);
-+	ret = mcp25xxfd_cmd_write(spi, MCP25XXFD_CAN_TSCON, cpriv->regs.tscon);
-+	if (ret)
-+		return ret;
-+
-+	/* setup fifos */
-+	ret = mcp25xxfd_can_fifo_setup(cpriv);
-+	if (ret)
-+		return ret;
-+
-+	/* setup can bittiming now - the do_set_bittiming methods
-+	 * are not used as they get callled before open
-+	 */
-+	ret = mcp25xxfd_can_do_set_nominal_bittiming(net);
-+	if (ret)
-+		return ret;
-+	ret = mcp25xxfd_can_do_set_data_bittiming(net);
-+	if (ret)
-+		return ret;
-+
-+	return ret;
-+}
-+
-+/* mode setting */
-+static int mcp25xxfd_can_do_set_mode(struct net_device *net,
-+				     enum can_mode mode)
-+{
-+	switch (mode) {
-+	case CAN_MODE_START:
-+		break;
-+	default:
-+		return -EOPNOTSUPP;
-+	}
-+
-+	return 0;
-+}
-+
-+/* binary error counters */
-+static int mcp25xxfd_can_get_berr_counter(const struct net_device *net,
-+					  struct can_berr_counter *bec)
-+{
-+	struct mcp25xxfd_can_priv *cpriv = netdev_priv(net);
-+
-+	bec->txerr = (cpriv->status.trec & MCP25XXFD_CAN_TREC_TEC_MASK) >>
-+		MCP25XXFD_CAN_TREC_TEC_SHIFT;
-+	bec->rxerr = (cpriv->status.trec & MCP25XXFD_CAN_TREC_REC_MASK) >>
-+		MCP25XXFD_CAN_TREC_REC_SHIFT;
-+
-+	return 0;
-+}
-+
-+static int mcp25xxfd_can_open(struct net_device *net)
-+{
-+	struct mcp25xxfd_can_priv *cpriv = netdev_priv(net);
-+	struct spi_device *spi = cpriv->priv->spi;
-+	int ret;
-+
-+	ret = open_candev(net);
-+	if (ret) {
-+		netdev_err(net, "unable to set initial baudrate!\n");
-+		return ret;
-+	}
-+
-+	/* clear those statistics */
-+	memset(&cpriv->stats, 0, sizeof(cpriv->stats));
-+
-+	/* request an IRQ but keep disabled for now */
-+	ret = request_threaded_irq(spi->irq, NULL,
-+				   mcp25xxfd_can_int,
-+				   IRQF_ONESHOT | IRQF_TRIGGER_LOW,
-+				   cpriv->priv->device_name, cpriv);
-+	if (ret) {
-+		dev_err(&spi->dev, "failed to acquire irq %d - %i\n",
-+			spi->irq, ret);
-+		goto out_candev;
-+	}
-+	disable_irq(spi->irq);
-+	cpriv->irq.allocated = true;
-+	cpriv->irq.enabled = false;
-+
-+	/* enable power to the transceiver */
-+	ret = mcp25xxfd_base_power_enable(cpriv->transceiver, 1);
-+	if (ret)
-+		goto out_irq;
-+
-+	/* enable clock (so that spi works) */
-+	ret = mcp25xxfd_clock_start(cpriv->priv, MCP25XXFD_CLK_USER_CAN);
-+	if (ret)
-+		goto out_transceiver;
-+
-+	/* configure controller for reception */
-+	ret = mcp25xxfd_can_config(net);
-+	if (ret)
-+		goto out_canclock;
-+
-+	/* setting up state */
-+	cpriv->can.state = CAN_STATE_ERROR_ACTIVE;
-+
-+	/* enable interrupts */
-+	ret = mcp25xxfd_int_enable(cpriv->priv, true);
-+	if (ret)
-+		goto out_canconfig;
-+
-+	/* switch to active mode */
-+	ret = mcp25xxfd_can_switch_mode(cpriv->priv, &cpriv->regs.con,
-+					(net->mtu == CAN_MTU) ?
-+					MCP25XXFD_CAN_CON_MODE_CAN2_0 :
-+					MCP25XXFD_CAN_CON_MODE_MIXED);
-+	if (ret)
-+		goto out_int;
-+
-+	/* start the tx_queue */
-+	mcp25xxfd_can_tx_queue_manage(cpriv,
-+				      MCP25XXFD_CAN_TX_QUEUE_STATE_STARTED);
-+
-+	return 0;
-+
-+out_int:
-+	mcp25xxfd_int_enable(cpriv->priv, false);
-+out_canconfig:
-+	mcp25xxfd_can_fifo_release(cpriv);
-+out_canclock:
-+	mcp25xxfd_clock_stop(cpriv->priv, MCP25XXFD_CLK_USER_CAN);
-+out_transceiver:
-+	mcp25xxfd_base_power_enable(cpriv->transceiver, 0);
-+out_irq:
-+	free_irq(spi->irq, cpriv);
-+	cpriv->irq.allocated = false;
-+	cpriv->irq.enabled = false;
-+out_candev:
-+	close_candev(net);
-+	return ret;
-+}
-+
-+static void mcp25xxfd_can_shutdown(struct mcp25xxfd_can_priv *cpriv)
-+{
-+	/* switch us to CONFIG mode - this disables the controller */
-+	mcp25xxfd_can_switch_mode(cpriv->priv, &cpriv->regs.con,
-+				  MCP25XXFD_CAN_CON_MODE_CONFIG);
-+}
-+
-+static int mcp25xxfd_can_stop(struct net_device *net)
-+{
-+	struct mcp25xxfd_can_priv *cpriv = netdev_priv(net);
-+	struct mcp25xxfd_priv *priv = cpriv->priv;
-+	struct spi_device *spi = priv->spi;
-+
-+	/* stop transmit queue */
-+	mcp25xxfd_can_tx_queue_manage(cpriv,
-+				      MCP25XXFD_CAN_TX_QUEUE_STATE_STOPPED);
-+
-+	/* release fifos and debugfs */
-+	mcp25xxfd_can_fifo_release(cpriv);
-+
-+	/* shutdown the can controller */
-+	mcp25xxfd_can_shutdown(cpriv);
-+
-+	/* disable inerrupts on controller */
-+	mcp25xxfd_int_enable(cpriv->priv, false);
-+
-+	/* stop the clock */
-+	mcp25xxfd_clock_stop(cpriv->priv, MCP25XXFD_CLK_USER_CAN);
-+
-+	/* and disable the transceiver */
-+	mcp25xxfd_base_power_enable(cpriv->transceiver, 0);
-+
-+	/* disable interrupt on host */
-+	free_irq(spi->irq, cpriv);
-+	cpriv->irq.allocated = false;
-+	cpriv->irq.enabled = false;
-+
-+	/* close the can_decice */
-+	close_candev(net);
-+
-+	return 0;
-+}
-+
-+static const struct net_device_ops mcp25xxfd_netdev_ops = {
-+	.ndo_open = mcp25xxfd_can_open,
-+	.ndo_stop = mcp25xxfd_can_stop,
-+	.ndo_start_xmit = mcp25xxfd_can_tx_start_xmit,
-+	.ndo_change_mtu = can_change_mtu,
-+};
-+
-+/* probe and remove */
-+int mcp25xxfd_can_setup(struct mcp25xxfd_priv *priv)
-+{
-+	struct spi_device *spi = priv->spi;
-+	struct mcp25xxfd_can_priv *cpriv;
-+	struct net_device *net;
-+	struct regulator *transceiver;
-+	int ret;
-+
-+	/* get transceiver power regulator*/
-+	transceiver = devm_regulator_get_optional(&spi->dev,
-+						  "xceiver");
-+	if (PTR_ERR(transceiver) == -EPROBE_DEFER)
-+		return -EPROBE_DEFER;
-+
-+	/* allocate can device */
-+	net = alloc_candev(sizeof(*cpriv), TX_ECHO_SKB_MAX);
-+	if (!net)
-+		return -ENOMEM;
-+
-+	/* and do some cross-asignments */
-+	cpriv = netdev_priv(net);
-+	cpriv->priv = priv;
-+	priv->cpriv = cpriv;
-+
-+	/* setup network */
-+	SET_NETDEV_DEV(net, &spi->dev);
-+	net->netdev_ops = &mcp25xxfd_netdev_ops;
-+	net->flags |= IFF_ECHO;
-+
-+	/* assign transceiver */
-+	cpriv->transceiver = transceiver;
-+
-+	/* setup can */
-+	cpriv->can.clock.freq = priv->clock_freq;
-+	cpriv->can.bittiming_const =
-+		&mcp25xxfd_can_nominal_bittiming_const;
-+	cpriv->can.data_bittiming_const =
-+		&mcp25xxfd_can_data_bittiming_const;
-+	/* we are not setting bit-timing methods here as they get
-+	 * called by the framework before open so the controller is
-+	 * still in sleep mode, which does not help
-+	 * things are configured in open instead
-+	 */
-+	cpriv->can.do_set_mode =
-+		mcp25xxfd_can_do_set_mode;
-+	cpriv->can.do_get_berr_counter =
-+		mcp25xxfd_can_get_berr_counter;
-+	cpriv->can.ctrlmode_supported =
-+		CAN_CTRLMODE_FD |
-+		CAN_CTRLMODE_FD_NON_ISO |
-+		CAN_CTRLMODE_LOOPBACK |
-+		CAN_CTRLMODE_LISTENONLY |
-+		CAN_CTRLMODE_BERR_REPORTING |
-+		CAN_CTRLMODE_ONE_SHOT;
-+
-+	ret = register_candev(net);
-+	if (ret) {
-+		dev_err(&spi->dev, "Failed to register can device\n");
-+		goto out;
-+	}
-+
-+	mcp25xxfd_can_debugfs_setup(cpriv);
-+
-+	return 0;
-+out:
-+	free_candev(net);
-+	priv->cpriv = NULL;
-+
-+	return ret;
-+}
-+
-+void mcp25xxfd_can_remove(struct mcp25xxfd_priv *priv)
-+{
-+	if (priv->cpriv) {
-+		unregister_candev(priv->cpriv->can.dev);
-+		free_candev(priv->cpriv->can.dev);
-+		priv->cpriv = NULL;
-+	}
-+}
-diff --git a/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can.h b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can.h
-new file mode 100644
-index 000000000000..b480220d4ccd
---- /dev/null
-+++ b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can.h
-@@ -0,0 +1,56 @@
-+/* SPDX-License-Identifier: GPL-2.0 */
-+
-+/* CAN bus driver for Microchip 25XXFD CAN Controller with SPI Interface
-+ *
-+ * Copyright 2019 Martin Sperl <kernel@martin.sperl.org>
-+ */
-+
-+#ifndef __MCP25XXFD_CAN_H
-+#define __MCP25XXFD_CAN_H
-+
-+#include "mcp25xxfd_can_debugfs.h"
-+#include "mcp25xxfd_can_priv.h"
-+#include "mcp25xxfd_priv.h"
-+#include "mcp25xxfd_regs.h"
-+
-+/* get the optimal controller target mode */
-+static inline
-+int mcp25xxfd_can_targetmode(struct mcp25xxfd_can_priv *cpriv)
-+{
-+	return (cpriv->can.dev->mtu == CAN_MTU) ?
-+		MCP25XXFD_CAN_CON_MODE_CAN2_0 : MCP25XXFD_CAN_CON_MODE_MIXED;
-+}
-+
-+static inline
-+void mcp25xxfd_can_queue_frame(struct mcp25xxfd_can_priv *cpriv,
-+			       s32 fifo, u16 ts, bool is_rx)
-+{
-+	int idx = cpriv->fifos.submit_queue_count;
-+
-+	cpriv->fifos.submit_queue[idx].fifo = fifo;
-+	cpriv->fifos.submit_queue[idx].ts = ts;
-+	cpriv->fifos.submit_queue[idx].is_rx = is_rx;
-+
-+	MCP25XXFD_DEBUGFS_INCR(cpriv->fifos.submit_queue_count);
-+}
-+
-+/* get the current controller mode */
-+int mcp25xxfd_can_get_mode(struct mcp25xxfd_priv *priv, u32 *reg);
-+
-+/* to put us to sleep fully we need the CAN controller to enter sleep mode */
-+int mcp25xxfd_can_sleep_mode(struct mcp25xxfd_priv *priv);
-+
-+/* switch controller mode */
-+int mcp25xxfd_can_switch_mode_no_wait(struct mcp25xxfd_priv *priv,
-+				      u32 *reg, int mode);
-+int mcp25xxfd_can_switch_mode(struct mcp25xxfd_priv *priv,
-+			      u32 *reg, int mode);
-+
-+/* probe the can controller */
-+int mcp25xxfd_can_probe(struct mcp25xxfd_priv *priv);
-+
-+/* setup and the can controller net interface */
-+int mcp25xxfd_can_setup(struct mcp25xxfd_priv *priv);
-+void mcp25xxfd_can_remove(struct mcp25xxfd_priv *priv);
-+
-+#endif /* __MCP25XXFD_CAN_H */
-diff --git a/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_debugfs.c b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_debugfs.c
-new file mode 100644
-index 000000000000..d2caf82a6b3e
---- /dev/null
-+++ b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_debugfs.c
-@@ -0,0 +1,235 @@
-+// SPDX-License-Identifier: GPL-2.0
-+
-+/* CAN bus driver for Microchip 25XXFD CAN Controller with SPI Interface
-+ *
-+ * Copyright 2019 Martin Sperl <kernel@martin.sperl.org>
-+ */
-+
-+#ifdef CONFIG_DEBUG_FS
-+
-+#include <linux/dcache.h>
-+#include <linux/debugfs.h>
-+#include "mcp25xxfd_can_priv.h"
-+#include "mcp25xxfd_can_tx.h"
-+
-+static void mcp25xxfd_can_debugfs_regs(struct mcp25xxfd_can_priv *cpriv,
-+				       struct dentry *root)
-+{
-+	struct dentry *dir = debugfs_create_dir("regs", root);
-+
-+	debugfs_create_x32("con",    0444, dir, &cpriv->regs.con);
-+	debugfs_create_x32("tdc",    0444, dir, &cpriv->regs.tdc);
-+	debugfs_create_x32("tscon",  0444, dir, &cpriv->regs.tscon);
-+	debugfs_create_x32("tefcon", 0444, dir, &cpriv->regs.tscon);
-+	debugfs_create_x32("nbtcfg", 0444, dir, &cpriv->regs.nbtcfg);
-+	debugfs_create_x32("dbtcfg", 0444, dir, &cpriv->regs.dbtcfg);
-+}
-+
-+static void mcp25xxfd_can_debugfs_status(struct mcp25xxfd_can_priv *cpriv,
-+					 struct dentry *root)
-+{
-+	struct dentry *dir = debugfs_create_dir("status", root);
-+
-+	debugfs_create_x32("intf",    0444, dir, &cpriv->status.intf);
-+	debugfs_create_x32("rx_if",   0444, dir, &cpriv->status.rxif);
-+	debugfs_create_x32("tx_if",   0444, dir, &cpriv->status.txif);
-+	debugfs_create_x32("rx_ovif", 0444, dir, &cpriv->status.rxovif);
-+	debugfs_create_x32("tx_atif", 0444, dir, &cpriv->status.txatif);
-+	debugfs_create_x32("tx_req",  0444, dir, &cpriv->status.txreq);
-+	debugfs_create_x32("trec",    0444, dir, &cpriv->status.trec);
-+}
-+
-+static void mcp25xxfd_can_debugfs_stats(struct mcp25xxfd_can_priv *cpriv,
-+					struct dentry *root)
-+{
-+	struct dentry *dir = debugfs_create_dir("stats", root);
-+	char name[32];
-+	u64 *data;
-+	int i;
-+
-+# define DEBUGFS_CREATE(name, var) debugfs_create_u64(name, 0444, dir, \
-+						      &cpriv->stats.var)
-+	DEBUGFS_CREATE("irq_calls",		 irq_calls);
-+	DEBUGFS_CREATE("irq_loops",		 irq_loops);
-+	DEBUGFS_CREATE("irq_thread_rescheduled", irq_thread_rescheduled);
-+
-+	DEBUGFS_CREATE("int_system_error",	 int_serr_count);
-+	DEBUGFS_CREATE("int_system_error_tx",	 int_serr_tx_count);
-+	DEBUGFS_CREATE("int_system_error_rx",	 int_serr_rx_count);
-+	DEBUGFS_CREATE("int_mode_switch",	 int_mod_count);
-+	DEBUGFS_CREATE("int_rx",		 int_rx_count);
-+	DEBUGFS_CREATE("int_tx_attempt",	 int_txat_count);
-+	DEBUGFS_CREATE("int_tef",		 int_tef_count);
-+	DEBUGFS_CREATE("int_rx_overflow",	 int_rxov_count);
-+	DEBUGFS_CREATE("int_ecc_error",		 int_ecc_count);
-+	DEBUGFS_CREATE("int_rx_invalid_message", int_ivm_count);
-+	DEBUGFS_CREATE("int_crcerror",		 int_cerr_count);
-+
-+	DEBUGFS_CREATE("tef_reads",		 tef_reads);
-+	DEBUGFS_CREATE("tef_conservative_reads", tef_conservative_reads);
-+	DEBUGFS_CREATE("tef_optimized_reads",	 tef_optimized_reads);
-+	DEBUGFS_CREATE("tef_read_splits",	 tef_read_splits);
-+
-+	for (i = 0; i < MCP25XXFD_CAN_TEF_READ_BINS - 1; i++) {
-+		snprintf(name, sizeof(name),
-+			 "tef_optimized_reads_%i", i + 1);
-+		data = &cpriv->stats.tef_optimized_read_sizes[i];
-+		debugfs_create_u64(name, 0444, dir, data);
-+	}
-+	snprintf(name, sizeof(name), "tef_optimized_reads_%i+", i + 1);
-+	debugfs_create_u64(name, 0444, dir,
-+			   &cpriv->stats.tef_optimized_read_sizes[i]);
-+
-+	DEBUGFS_CREATE("tx_frames_fd",		 tx_fd_count);
-+	DEBUGFS_CREATE("tx_frames_brs",		 tx_brs_count);
-+
-+	DEBUGFS_CREATE("rx_reads",		 rx_reads);
-+	DEBUGFS_CREATE("rx_reads_prefetched_too_few",
-+		       rx_reads_prefetched_too_few);
-+	DEBUGFS_CREATE("rx_reads_prefetched_too_few_bytes",
-+		       rx_reads_prefetched_too_few_bytes);
-+	DEBUGFS_CREATE("rx_reads_prefetched_too_many",
-+		       rx_reads_prefetched_too_many);
-+	DEBUGFS_CREATE("rx_reads_prefetched_too_many_bytes",
-+		       rx_reads_prefetched_too_many_bytes);
-+	DEBUGFS_CREATE("rx_single_reads",	 rx_single_reads);
-+	DEBUGFS_CREATE("rx_bulk_reads",		 rx_bulk_reads);
-+
-+	for (i = 0; i < MCP25XXFD_CAN_RX_BULK_READ_BINS - 1; i++) {
-+		snprintf(name, sizeof(name), "rx_bulk_reads_%i", i + 1);
-+		data = &cpriv->stats.rx_bulk_read_sizes[i];
-+		debugfs_create_u64(name, 0444, dir, data);
-+	}
-+	snprintf(name, sizeof(name), "rx_bulk_reads_%i+", i + 1);
-+	debugfs_create_u64(name, 0444, dir,
-+			   &cpriv->stats.rx_bulk_read_sizes[i]);
-+
-+	if (cpriv->can.dev->mtu == CANFD_MTU)
-+		debugfs_create_u32("rx_reads_prefetch_predicted_len", 0444,
-+				   dir, &cpriv->rx_history.predicted_len);
-+#undef DEBUGFS_CREATE
-+}
-+
-+static void mcp25xxfd_can_debugfs_tef(struct mcp25xxfd_can_priv *cpriv,
-+				      struct dentry *root)
-+{
-+	struct dentry *dir = debugfs_create_dir("tef", root);
-+
-+	debugfs_create_u32("count", 0444, dir, &cpriv->fifos.tef.count);
-+	debugfs_create_u32("size",  0444, dir, &cpriv->fifos.tef.size);
-+}
-+
-+static void mcp25xxfd_can_debugfs_fifo_info(struct mcp25xxfd_fifo_info *info,
-+					    int index, struct dentry *root)
-+{
-+	struct dentry *dir;
-+	char name[4];
-+
-+	snprintf(name, sizeof(name), "%02i", index);
-+	dir = debugfs_create_dir(name, root);
-+
-+	debugfs_create_u32("is_rx",     0444, dir, &info->is_rx);
-+	debugfs_create_x32("offset",    0444, dir, &info->offset);
-+	debugfs_create_u32("priority",  0444, dir, &info->priority);
-+
-+	debugfs_create_u64("use_count", 0444, dir, &info->use_count);
-+}
-+
-+static void mcp25xxfd_can_debugfs_fifos(struct mcp25xxfd_can_priv *cpriv,
-+					struct dentry *root)
-+{
-+	struct dentry *dir = debugfs_create_dir("fifos", root);
-+	int i;
-+
-+	/* now present all fifos - there is no fifo 0 */
-+	for (i = 1; i < 32; i++)
-+		mcp25xxfd_can_debugfs_fifo_info(&cpriv->fifos.info[i], i, dir);
-+}
-+
-+static void mcp25xxfd_can_debugfs_rxtx_fifos(struct mcp25xxfd_fifo *d,
-+					     struct dentry *root)
-+{
-+	int i, f;
-+	char name[4];
-+	char link[32];
-+
-+	debugfs_create_u32("count", 0444, root, &d->count);
-+	debugfs_create_u32("size",  0444, root, &d->size);
-+	debugfs_create_u32("start", 0444, root, &d->start);
-+
-+	for (f = d->start, i = 0; i < d->count; f++, i++) {
-+		snprintf(name, sizeof(name), "%02i", i);
-+		snprintf(link, sizeof(link), "../fifos/%02i", f);
-+
-+		debugfs_create_symlink(name, root, link);
-+	}
-+}
-+
-+static void mcp25xxfd_can_debugfs_rx_fifos(struct mcp25xxfd_can_priv *cpriv,
-+					   struct dentry *root)
-+{
-+	struct dentry *dir = debugfs_create_dir("rx_fifos", root);
-+
-+	mcp25xxfd_can_debugfs_rxtx_fifos(&cpriv->fifos.rx, dir);
-+}
-+
-+static void mcp25xxfd_can_debugfs_tx_fifos(struct mcp25xxfd_can_priv *cpriv,
-+					   struct dentry *root)
-+{
-+	struct dentry *dir = debugfs_create_dir("tx_fifos", root);
-+
-+	mcp25xxfd_can_debugfs_rxtx_fifos(&cpriv->fifos.rx, dir);
-+}
-+
-+static void mcp25xxfd_can_debugfs_tx_queue(struct mcp25xxfd_can_priv *cpriv,
-+					   struct dentry *root)
-+{
-+	struct mcp25xxfd_tx_spi_message_queue *queue = cpriv->fifos.tx_queue;
-+	struct dentry *dir;
-+
-+	if (!queue)
-+		return;
-+
-+	dir = debugfs_create_dir("tx_queue", root);
-+
-+	debugfs_create_u32("state", 0444, dir, &queue->state);
-+	debugfs_create_x32("fifos_idle", 0444, dir, &queue->idle);
-+	debugfs_create_x32("fifos_in_fill_fifo_transfer",
-+			   0444, dir, &queue->in_fill_fifo_transfer);
-+	debugfs_create_x32("fifos_in_trigger_fifo_transfer",
-+			   0444, dir, &queue->in_trigger_fifo_transfer);
-+	debugfs_create_x32("fifos_in_can_transfer",
-+			   0444, dir, &queue->in_can_transfer);
-+	debugfs_create_x32("fifos_transferred",
-+			   0444, dir, &queue->transferred);
-+}
-+
-+void mcp25xxfd_can_debugfs_remove(struct mcp25xxfd_can_priv *cpriv)
-+{
-+	debugfs_remove_recursive(cpriv->debugfs_dir);
-+	cpriv->debugfs_dir = NULL;
-+}
-+
-+void mcp25xxfd_can_debugfs_setup(struct mcp25xxfd_can_priv *cpriv)
-+{
-+	struct dentry *root;
-+
-+	/* remove first as we get called during probe and also
-+	 * when the can_device is configured/removed
-+	 */
-+	mcp25xxfd_can_debugfs_remove(cpriv);
-+
-+	root = debugfs_create_dir("can", cpriv->priv->debugfs_dir);
-+	cpriv->debugfs_dir = root;
-+
-+	mcp25xxfd_can_debugfs_regs(cpriv, root);
-+	mcp25xxfd_can_debugfs_stats(cpriv, root);
-+	mcp25xxfd_can_debugfs_status(cpriv, root);
-+	mcp25xxfd_can_debugfs_tef(cpriv, root);
-+	mcp25xxfd_can_debugfs_fifos(cpriv, root);
-+	mcp25xxfd_can_debugfs_rx_fifos(cpriv, root);
-+	mcp25xxfd_can_debugfs_tx_fifos(cpriv, root);
-+	mcp25xxfd_can_debugfs_tx_queue(cpriv, root);
-+}
-+
-+#endif
-diff --git a/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_debugfs.h b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_debugfs.h
-new file mode 100644
-index 000000000000..7c6a255c9400
---- /dev/null
-+++ b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_debugfs.h
-@@ -0,0 +1,44 @@
-+/* SPDX-License-Identifier: GPL-2.0 */
-+
-+/* CAN bus driver for Microchip 25XXFD CAN Controller with SPI Interface
-+ *
-+ * Copyright 2019 Martin Sperl <kernel@martin.sperl.org>
-+ */
-+
-+#ifndef __MCP25XXFD_CAN_DEBUGFS_H
-+#define __MCP25XXFD_CAN_DEBUGFS_H
-+
-+#ifdef CONFIG_DEBUG_FS
-+
-+#include <linux/debugfs.h>
-+#include "mcp25xxfd_can_priv.h"
-+
-+#define MCP25XXFD_DEBUGFS_INCR(counter) ((counter)++)
-+#define MCP25XXFD_DEBUGFS_ADD(counter, val) ((counter) += (val))
-+#define MCP25XXFD_DEBUGFS_STATS_INCR(cpriv, counter)		\
-+	(((cpriv)->stats.counter)++)
-+#define MCP25XXFD_DEBUGFS_STATS_ADD(cpriv, counter, val)	\
-+	(((cpriv)->stats.counter) += (val))
-+
-+void mcp25xxfd_can_debugfs_setup(struct mcp25xxfd_can_priv *cpriv);
-+void mcp25xxfd_can_debugfs_remove(struct mcp25xxfd_can_priv *cpriv);
-+
-+#else /* CONFIG_DEBUG_FS */
-+
-+#define MCP25XXFD_DEBUGFS_INCR(counter)
-+#define MCP25XXFD_DEBUGFS_ADD(counter, val)
-+#define MCP25XXFD_DEBUGFS_STATS_INCR(cpriv, counter)
-+#define MCP25XXFD_DEBUGFS_STATS_ADD(cpriv, counter, val)
-+
-+static inline
-+void mcp25xxfd_can_debugfs_setup(struct mcp25xxfd_can_priv *cpriv)
-+{
-+}
-+
-+static inline
-+void mcp25xxfd_can_debugfs_remove(struct mcp25xxfd_can_priv *cpriv)
-+{
-+}
-+
-+#endif /* CONFIG_DEBUG_FS */
-+#endif /* __MCP25XXFD_CAN_DEBUGFS_H */
-diff --git a/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_fifo.c b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_fifo.c
-new file mode 100644
-index 000000000000..bf94120f2609
---- /dev/null
-+++ b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_fifo.c
-@@ -0,0 +1,347 @@
-+// SPDX-License-Identifier: GPL-2.0
-+
-+/* CAN bus driver for Microchip 25XXFD CAN Controller with SPI Interface
-+ *
-+ * Copyright 2019 Martin Sperl <kernel@martin.sperl.org>
-+ */
-+
-+/* here we define and configure the fifo layout */
-+
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/spi/spi.h>
-+
-+#include "mcp25xxfd_can.h"
-+#include "mcp25xxfd_can_priv.h"
-+#include "mcp25xxfd_can_tx.h"
-+#include "mcp25xxfd_cmd.h"
-+
-+/* some controller parameters are currently not configurable via netlink
-+ * so we allow to control them via module parameters (that can changed
-+ * in /sys if needed) - theses are only needed during setup if the can_device
-+ */
-+unsigned int tx_fifos;
-+module_param(tx_fifos, uint, 0664);
-+MODULE_PARM_DESC(tx_fifos, "Number of tx-fifos to configure\n");
-+
-+bool three_shot;
-+module_param(three_shot, bool, 0664);
-+MODULE_PARM_DESC(three_shot, "Use 3 shots when one-shot is requested");
-+
-+static int mcp25xxfd_can_fifo_get_address(struct mcp25xxfd_can_priv *cpriv)
-+{
-+	int fifo, ret;
-+
-+	/* we need to move out of config mode to force address computation */
-+	ret = mcp25xxfd_can_switch_mode(cpriv->priv, &cpriv->regs.con,
-+					MCP25XXFD_CAN_CON_MODE_INT_LOOPBACK);
-+	if (ret)
-+		return ret;
-+
-+	/* and get back into config mode */
-+	ret = mcp25xxfd_can_switch_mode(cpriv->priv, &cpriv->regs.con,
-+					MCP25XXFD_CAN_CON_MODE_CONFIG);
-+	if (ret)
-+		return ret;
-+
-+	/* read address and config back in */
-+	for (fifo = 1; fifo < 32; fifo++) {
-+		ret = mcp25xxfd_cmd_read(cpriv->priv->spi,
-+					 MCP25XXFD_CAN_FIFOUA(fifo),
-+					 &cpriv->fifos.info[fifo].offset);
-+		if (ret)
-+			return ret;
-+	}
-+
-+	return 0;
-+}
-+
-+static int mcp25xxfd_can_fifo_setup_config(struct mcp25xxfd_can_priv *cpriv,
-+					   struct mcp25xxfd_fifo *desc,
-+					   u32 flags, u32 flags_last)
-+{
-+	u32 val;
-+	int i, p, f, c, ret;
-+
-+	/* now setup the fifos themselves */
-+	for (i = 0, f = desc->start, c = desc->count, p = 31;
-+	     c > 0; i++, f++, p--, c--) {
-+		/* select the effective value */
-+		val = (c > 1) ? flags : flags_last;
-+
-+		/* are we in tx mode */
-+		if (flags & MCP25XXFD_CAN_FIFOCON_TXEN) {
-+			cpriv->fifos.info[f].is_rx = false;
-+			cpriv->fifos.info[f].priority = p;
-+			val |= (p << MCP25XXFD_CAN_FIFOCON_TXPRI_SHIFT);
-+		} else {
-+			cpriv->fifos.info[f].is_rx = true;
-+		}
-+
-+		/* write the config to the controller in one go */
-+		ret = mcp25xxfd_cmd_write(cpriv->priv->spi,
-+					  MCP25XXFD_CAN_FIFOCON(f), val);
-+		if (ret)
-+			return ret;
-+	}
-+
-+	return 0;
-+}
-+
-+static int mcp25xxfd_can_fifo_setup_tx(struct mcp25xxfd_can_priv *cpriv)
-+{
-+	u32 tx_flags = MCP25XXFD_CAN_FIFOCON_FRESET |     /* reset FIFO */
-+		MCP25XXFD_CAN_FIFOCON_TXEN |              /* a tx FIFO */
-+		MCP25XXFD_CAN_FIFOCON_TXATIE |            /* state in txatif */
-+		(cpriv->fifos.payload_mode <<
-+		 MCP25XXFD_CAN_FIFOCON_PLSIZE_SHIFT) |    /* paylod size */
-+		(0 << MCP25XXFD_CAN_FIFOCON_FSIZE_SHIFT); /* 1 FIFO deep */
-+
-+	/* handle oneshot/three-shot */
-+	if (cpriv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT)
-+		if (three_shot)
-+			tx_flags |= MCP25XXFD_CAN_FIFOCON_TXAT_THREE_SHOT <<
-+				MCP25XXFD_CAN_FIFOCON_TXAT_SHIFT;
-+		else
-+			tx_flags |= MCP25XXFD_CAN_FIFOCON_TXAT_ONE_SHOT <<
-+				MCP25XXFD_CAN_FIFOCON_TXAT_SHIFT;
-+	else
-+		tx_flags |= MCP25XXFD_CAN_FIFOCON_TXAT_UNLIMITED <<
-+			MCP25XXFD_CAN_FIFOCON_TXAT_SHIFT;
-+
-+	return mcp25xxfd_can_fifo_setup_config(cpriv, &cpriv->fifos.tx,
-+					       tx_flags, tx_flags);
-+}
-+
-+static int mcp25xxfd_can_fifo_setup_rx(struct mcp25xxfd_can_priv *cpriv)
-+{
-+	u32 rx_flags = MCP25XXFD_CAN_FIFOCON_FRESET |     /* reset FIFO */
-+		MCP25XXFD_CAN_FIFOCON_RXTSEN |            /* RX timestamps */
-+		MCP25XXFD_CAN_FIFOCON_TFERFFIE |          /* FIFO Full */
-+		MCP25XXFD_CAN_FIFOCON_TFHRFHIE |          /* FIFO Half Full*/
-+		MCP25XXFD_CAN_FIFOCON_TFNRFNIE |          /* FIFO not empty */
-+		(cpriv->fifos.payload_mode <<
-+		 MCP25XXFD_CAN_FIFOCON_PLSIZE_SHIFT) |
-+		(0 << MCP25XXFD_CAN_FIFOCON_FSIZE_SHIFT); /* 1 FIFO deep */
-+	/* enable overflow int on last fifo */
-+	u32 rx_flags_last = rx_flags | MCP25XXFD_CAN_FIFOCON_RXOVIE;
-+
-+	return mcp25xxfd_can_fifo_setup_config(cpriv, &cpriv->fifos.rx,
-+					       rx_flags, rx_flags_last);
-+}
-+
-+static int mcp25xxfd_can_fifo_setup_rxfilter(struct mcp25xxfd_can_priv *cpriv)
-+{
-+	u8 filter_con[32];
-+	int c, f;
-+
-+	/* clear the filters and filter mappings for all filters */
-+	memset(filter_con, 0, sizeof(filter_con));
-+
-+	/* and now set up the rx filters */
-+	for (c = 0, f = cpriv->fifos.rx.start; c < cpriv->fifos.rx.count;
-+	     c++, f++) {
-+		/* set up filter config - we can use the mask of filter 0 */
-+		filter_con[c] = MCP25XXFD_CAN_FIFOCON_FLTEN(0) |
-+			(f << MCP25XXFD_CAN_FILCON_SHIFT(0));
-+	}
-+
-+	/* and set up filter control */
-+	return mcp25xxfd_cmd_write_regs(cpriv->priv->spi,
-+					MCP25XXFD_CAN_FLTCON(0),
-+					(u32 *)filter_con, sizeof(filter_con));
-+}
-+
-+static int mcp25xxfd_can_fifo_compute(struct mcp25xxfd_can_priv *cpriv)
-+{
-+	int tef_memory_used, tx_memory_used, rx_memory_available;
-+
-+	/* default settings as per MTU/CANFD */
-+	switch (cpriv->can.dev->mtu) {
-+	case CAN_MTU:
-+		/* mtu is 8 */
-+		cpriv->fifos.payload_size = 8;
-+		cpriv->fifos.payload_mode = MCP25XXFD_CAN_TXQCON_PLSIZE_8;
-+
-+		/* 7 tx fifos */
-+		cpriv->fifos.tx.count = 7;
-+
-+		break;
-+	case CANFD_MTU:
-+		/* wish there was a way to have hw filters
-+		 * that can separate based on length ...
-+		 */
-+		/* MTU is 64 */
-+		cpriv->fifos.payload_size = 64;
-+		cpriv->fifos.payload_mode = MCP25XXFD_CAN_TXQCON_PLSIZE_64;
-+
-+		/* 7 tx fifos */
-+		cpriv->fifos.tx.count = 7;
-+
-+		break;
-+	default:
-+		return -EINVAL;
-+	}
-+
-+	/* compute effective sizes */
-+	cpriv->fifos.tef.size = sizeof(struct mcp25xxfd_can_obj_tef);
-+	cpriv->fifos.tx.size = sizeof(struct mcp25xxfd_can_obj_tx) +
-+		cpriv->fifos.payload_size;
-+	cpriv->fifos.rx.size = sizeof(struct mcp25xxfd_can_obj_rx) +
-+		cpriv->fifos.payload_size;
-+
-+	/* if defined as a module parameter modify the number of tx_fifos */
-+	if (tx_fifos) {
-+		netdev_info(cpriv->can.dev,
-+			    "Using %i tx-fifos as per module parameter\n",
-+			    tx_fifos);
-+		cpriv->fifos.tx.count = tx_fifos;
-+	}
-+
-+	/* there can be at the most 30 tx fifos (TEF and at least 1 RX fifo */
-+	if (cpriv->fifos.tx.count > 30) {
-+		netdev_err(cpriv->can.dev,
-+			   "There is an absolute maximum of 30 tx-fifos\n");
-+		return -EINVAL;
-+	}
-+
-+	/* set tef fifos to the number of tx fifos */
-+	cpriv->fifos.tef.count = cpriv->fifos.tx.count;
-+
-+	/* compute size of the tx fifos and TEF */
-+	tx_memory_used = cpriv->fifos.tx.count * cpriv->fifos.tx.size;
-+	tef_memory_used = cpriv->fifos.tef.count * cpriv->fifos.tef.size;
-+
-+	/* calculate evailable memory for RX_fifos */
-+	rx_memory_available = MCP25XXFD_SRAM_SIZE - tx_memory_used -
-+		tef_memory_used;
-+
-+	/* we need at least one RX Frame */
-+	if (rx_memory_available < cpriv->fifos.rx.size) {
-+		netdev_err(cpriv->can.dev,
-+			   "Configured %i tx-fifos exceeds available memory already\n",
-+			   cpriv->fifos.tx.count);
-+		return -EINVAL;
-+	}
-+
-+	/* calculate possible amount of RX fifos */
-+	cpriv->fifos.rx.count = rx_memory_available / cpriv->fifos.rx.size;
-+
-+	/* so now calculate effective number of rx-fifos
-+	 * there are only 31 fifos available in total,
-+	 * so we need to limit ourselves
-+	 */
-+	if (cpriv->fifos.rx.count + cpriv->fifos.tx.count > 31)
-+		cpriv->fifos.rx.count = 31 - cpriv->fifos.tx.count;
-+
-+	/* define the layout now that we have gotten everything */
-+	cpriv->fifos.tx.start = 1;
-+	cpriv->fifos.rx.start = cpriv->fifos.tx.start + cpriv->fifos.tx.count;
-+
-+	return 0;
-+}
-+
-+static int mcp25xxfd_can_fifo_clear_regs(struct mcp25xxfd_can_priv *cpriv,
-+					 u32 start, u32 end)
-+{
-+	size_t len = end - start;
-+	u8 *data = kzalloc(len, GFP_KERNEL);
-+	int ret;
-+
-+	if (!data)
-+		return -ENOMEM;
-+
-+	ret = mcp25xxfd_cmd_write_regs(cpriv->priv->spi,
-+				       start, (u32 *)data, len);
-+
-+	kfree(data);
-+
-+	return ret;
-+}
-+
-+static int mcp25xxfd_can_fifo_clear(struct mcp25xxfd_can_priv *cpriv)
-+{
-+	int ret;
-+
-+	memset(&cpriv->fifos.info, 0, sizeof(cpriv->fifos.info));
-+	memset(&cpriv->fifos.tx, 0, sizeof(cpriv->fifos.tx));
-+	memset(&cpriv->fifos.rx, 0, sizeof(cpriv->fifos.rx));
-+
-+	/* clear FIFO config */
-+	ret = mcp25xxfd_can_fifo_clear_regs(cpriv, MCP25XXFD_CAN_FIFOCON(1),
-+					    MCP25XXFD_CAN_FIFOCON(32));
-+	if (ret)
-+		return ret;
-+
-+	/* clear the filter mask - match any frame with every filter */
-+	return mcp25xxfd_can_fifo_clear_regs(cpriv, MCP25XXFD_CAN_FLTCON(0),
-+					     MCP25XXFD_CAN_FLTCON(32));
-+}
-+
-+int mcp25xxfd_can_fifo_setup(struct mcp25xxfd_can_priv *cpriv)
-+{
-+	int ret;
-+
-+	/* clear fifo config */
-+	ret = mcp25xxfd_can_fifo_clear(cpriv);
-+	if (ret)
-+		return ret;
-+
-+	/* compute fifos counts */
-+	ret = mcp25xxfd_can_fifo_compute(cpriv);
-+	if (ret)
-+		return ret;
-+
-+	/* configure TEF */
-+	if (cpriv->fifos.tef.count)
-+		cpriv->regs.tefcon =
-+			MCP25XXFD_CAN_TEFCON_FRESET |
-+			MCP25XXFD_CAN_TEFCON_TEFNEIE |
-+			MCP25XXFD_CAN_TEFCON_TEFTSEN |
-+			((cpriv->fifos.tef.count - 1) <<
-+			 MCP25XXFD_CAN_TEFCON_FSIZE_SHIFT);
-+	else
-+		cpriv->regs.tefcon = 0;
-+	ret = mcp25xxfd_cmd_write(cpriv->priv->spi, MCP25XXFD_CAN_TEFCON,
-+				  cpriv->regs.tefcon);
-+	if (ret)
-+		return ret;
-+
-+	/* TXQueue disabled */
-+	ret = mcp25xxfd_cmd_write(cpriv->priv->spi, MCP25XXFD_CAN_TXQCON, 0);
-+	if (ret)
-+		return ret;
-+
-+	/* configure FIFOS themselves */
-+	ret = mcp25xxfd_can_fifo_setup_tx(cpriv);
-+	if (ret)
-+		return ret;
-+	ret = mcp25xxfd_can_fifo_setup_rx(cpriv);
-+	if (ret)
-+		return ret;
-+	ret = mcp25xxfd_can_fifo_setup_rxfilter(cpriv);
-+	if (ret)
-+		return ret;
-+
-+	/* get fifo addresses */
-+	ret = mcp25xxfd_can_fifo_get_address(cpriv);
-+	if (ret)
-+		return ret;
-+
-+	/* setup tx_fifo_queue */
-+	ret = mcp25xxfd_can_tx_queue_alloc(cpriv);
-+	if (ret)
-+		return ret;
-+
-+	/* add the can info to debugfs */
-+	mcp25xxfd_can_debugfs_setup(cpriv);
-+
-+	return 0;
-+}
-+
-+void mcp25xxfd_can_fifo_release(struct mcp25xxfd_can_priv *cpriv)
-+{
-+	mcp25xxfd_can_tx_queue_free(cpriv);
-+	mcp25xxfd_can_fifo_clear(cpriv);
-+	mcp25xxfd_can_debugfs_remove(cpriv);
-+}
-diff --git a/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_fifo.h b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_fifo.h
-new file mode 100644
-index 000000000000..ed2daa05220a
---- /dev/null
-+++ b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_fifo.h
-@@ -0,0 +1,16 @@
-+/* SPDX-License-Identifier: GPL-2.0 */
-+
-+/* CAN bus driver for Microchip 25XXFD CAN Controller with SPI Interface
-+ *
-+ * Copyright 2019 Martin Sperl <kernel@martin.sperl.org>
-+ */
-+
-+#ifndef __MCP25XXFD_CAN_FIFO_H
-+#define __MCP25XXFD_CAN_FIFO_H
-+
-+#include "mcp25xxfd_can_priv.h"
-+
-+int mcp25xxfd_can_fifo_setup(struct mcp25xxfd_can_priv *cpriv);
-+void mcp25xxfd_can_fifo_release(struct mcp25xxfd_can_priv *cpriv);
-+
-+#endif /* __MCP25XXFD_CAN_FIFO_H */
-diff --git a/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_id.h b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_id.h
-new file mode 100644
-index 000000000000..00a6c6639bd5
---- /dev/null
-+++ b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_id.h
-@@ -0,0 +1,69 @@
-+/* SPDX-License-Identifier: GPL-2.0 */
-+
-+/* CAN bus driver for Microchip 25XXFD CAN Controller with SPI Interface
-+ *
-+ * Copyright 2019 Martin Sperl <kernel@martin.sperl.org>
-+ */
-+
-+#ifndef __MCP25XXFD_CAN_IF_H
-+#define __MCP25XXFD_CAN_IF_H
-+
-+#include <uapi/linux/can.h>
-+
-+#include "mcp25xxfd_can_id.h"
-+#include "mcp25xxfd_regs.h"
-+
-+/* ideally these would be defined in uapi/linux/can.h */
-+#define MCP25XXFD_CAN_EFF_SID_SHIFT	(CAN_EFF_ID_BITS - CAN_SFF_ID_BITS)
-+#define MCP25XXFD_CAN_EFF_SID_BITS	CAN_SFF_ID_BITS
-+#define MCP25XXFD_CAN_EFF_SID_MASK					\
-+	GENMASK(MCP25XXFD_CAN_EFF_SID_SHIFT + MCP25XXFD_CAN_EFF_SID_BITS - 1, \
-+		MCP25XXFD_CAN_EFF_SID_SHIFT)
-+#define MCP25XXFD_CAN_EFF_EID_SHIFT	0
-+#define MCP25XXFD_CAN_EFF_EID_BITS	MCP25XXFD_CAN_EFF_SID_SHIFT
-+#define MCP25XXFD_CAN_EFF_EID_MASK					\
-+	GENMASK(MCP25XXFD_CAN_EFF_EID_SHIFT + MCP25XXFD_CAN_EFF_EID_BITS - 1, \
-+		MCP25XXFD_CAN_EFF_EID_SHIFT)
-+
-+static inline
-+void mcp25xxfd_can_id_from_mcp25xxfd(u32 mcp_id, u32 mcp_flags, u32 *can_id)
-+{
-+	u32 sid = (mcp_id & MCP25XXFD_CAN_OBJ_ID_SID_MASK) >>
-+		MCP25XXFD_CAN_OBJ_ID_SID_SHIFT;
-+	u32 eid = (mcp_id & MCP25XXFD_CAN_OBJ_ID_EID_MASK) >>
-+		MCP25XXFD_CAN_OBJ_ID_EID_SHIFT;
-+
-+	/* select normal or extended ids */
-+	if (mcp_flags & MCP25XXFD_CAN_OBJ_FLAGS_IDE) {
-+		*can_id = (eid << MCP25XXFD_CAN_EFF_EID_SHIFT) |
-+			(sid << MCP25XXFD_CAN_EFF_SID_SHIFT) |
-+			CAN_EFF_FLAG;
-+	} else {
-+		*can_id = sid << MCP25XXFD_CAN_EFF_EID_SHIFT;
-+	}
-+	/* handle rtr */
-+	*can_id |= (mcp_flags & MCP25XXFD_CAN_OBJ_FLAGS_RTR) ? CAN_RTR_FLAG : 0;
-+}
-+
-+static inline
-+void mcp25xxfd_can_id_to_mcp25xxfd(u32 can_id, u32 *id, u32 *flags)
-+{
-+	/* depending on can_id flag compute extended or standard ids */
-+	if (can_id & CAN_EFF_FLAG) {
-+		int sid = (can_id & MCP25XXFD_CAN_EFF_SID_MASK) >>
-+			MCP25XXFD_CAN_EFF_SID_SHIFT;
-+		int eid = (can_id & MCP25XXFD_CAN_EFF_EID_MASK) >>
-+			MCP25XXFD_CAN_EFF_EID_SHIFT;
-+		*id = (eid << MCP25XXFD_CAN_OBJ_ID_EID_SHIFT) |
-+			(sid << MCP25XXFD_CAN_OBJ_ID_SID_SHIFT);
-+		*flags = MCP25XXFD_CAN_OBJ_FLAGS_IDE;
-+	} else {
-+		*id = can_id & CAN_SFF_MASK;
-+		*flags = 0;
-+	}
-+
-+	/* Handle RTR */
-+	*flags |= (can_id & CAN_RTR_FLAG) ? MCP25XXFD_CAN_OBJ_FLAGS_RTR : 0;
-+}
-+
-+#endif /* __MCP25XXFD_CAN_IF_H */
-diff --git a/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_int.c b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_int.c
-new file mode 100644
-index 000000000000..84f9c8273ce7
---- /dev/null
-+++ b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_int.c
-@@ -0,0 +1,705 @@
-+// SPDX-License-Identifier: GPL-2.0
-+
-+/* CAN bus driver for Microchip 25XXFD CAN Controller with SPI Interface
-+ *
-+ * Copyright 2019 Martin Sperl <kernel@martin.sperl.org>
-+ */
-+
-+#include <linux/can/core.h>
-+#include <linux/can/dev.h>
-+#include <linux/device.h>
-+#include <linux/interrupt.h>
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/net.h>
-+#include <linux/netdevice.h>
-+#include <linux/sched.h>
-+#include <linux/slab.h>
-+#include <linux/sort.h>
-+
-+#include "mcp25xxfd_regs.h"
-+#include "mcp25xxfd_can.h"
-+#include "mcp25xxfd_can_debugfs.h"
-+#include "mcp25xxfd_can_priv.h"
-+#include "mcp25xxfd_can_rx.h"
-+#include "mcp25xxfd_can_tx.h"
-+#include "mcp25xxfd_cmd.h"
-+#include "mcp25xxfd_ecc.h"
-+
-+unsigned int reschedule_int_thread_after = 4;
-+module_param(reschedule_int_thread_after, uint, 0664);
-+MODULE_PARM_DESC(reschedule_int_thread_after,
-+		 "Reschedule the interrupt thread after this many loops\n");
-+
-+static void mcp25xxfd_can_int_send_error_skb(struct mcp25xxfd_can_priv *cpriv)
-+{
-+	struct net_device *net = cpriv->can.dev;
-+	struct sk_buff *skb;
-+	struct can_frame *frame;
-+
-+	/* allocate error frame */
-+	skb = alloc_can_err_skb(net, &frame);
-+	if (!skb) {
-+		netdev_err(net, "cannot allocate error skb\n");
-+		return;
-+	}
-+
-+	/* setup can error frame data */
-+	frame->can_id |= cpriv->error_frame.id;
-+	memcpy(frame->data, cpriv->error_frame.data, sizeof(frame->data));
-+
-+	/* and submit it */
-+	netif_receive_skb(skb);
-+}
-+
-+static int mcp25xxfd_can_int_compare_obj_ts(const void *a, const void *b)
-+{
-+	s32 ats = ((struct mcp25xxfd_obj_ts *)a)->ts;
-+	s32 bts = ((struct mcp25xxfd_obj_ts *)b)->ts;
-+
-+	if (ats < bts)
-+		return -1;
-+	if (ats > bts)
-+		return 1;
-+	return 0;
-+}
-+
-+static int mcp25xxfd_can_int_submit_frames(struct mcp25xxfd_can_priv *cpriv)
-+{
-+	struct mcp25xxfd_obj_ts *queue = cpriv->fifos.submit_queue;
-+	int count = cpriv->fifos.submit_queue_count;
-+	int i, fifo;
-+	int ret;
-+
-+	/* skip processing if the queue count is 0 */
-+	if (count == 0)
-+		goto out;
-+
-+	/* sort the fifos (rx and tx - actually TEF) by receive timestamp */
-+	sort(queue, count, sizeof(*queue),
-+	     mcp25xxfd_can_int_compare_obj_ts, NULL);
-+
-+	/* now submit the fifos  */
-+	for (i = 0; i < count; i++) {
-+		fifo = queue[i].fifo;
-+		ret = (queue[i].is_rx) ?
-+			mcp25xxfd_can_rx_submit_frame(cpriv, fifo) :
-+			mcp25xxfd_can_tx_submit_frame(cpriv, fifo);
-+		if (ret)
-+			return ret;
-+	}
-+
-+	/* if we have received or transmitted something
-+	 * and the IVMIE is disabled, then enable it
-+	 * this is mostly to avoid unnecessary interrupts during a
-+	 * disconnected CAN BUS
-+	 */
-+	if (!(cpriv->status.intf | MCP25XXFD_CAN_INT_IVMIE)) {
-+		cpriv->status.intf |= MCP25XXFD_CAN_INT_IVMIE;
-+		ret = mcp25xxfd_cmd_write_mask(cpriv->priv->spi,
-+					       MCP25XXFD_CAN_INT,
-+					       cpriv->status.intf,
-+					       MCP25XXFD_CAN_INT_IVMIE);
-+		if (ret)
-+			return ret;
-+	}
-+
-+out:
-+	/* enable tx_queue if necessary */
-+	mcp25xxfd_can_tx_queue_restart(cpriv);
-+
-+	return 0;
-+}
-+
-+static int mcp25xxfd_can_int_clear_int_flags(struct mcp25xxfd_can_priv *cpriv)
-+{
-+	u32 clearable_irq_active = cpriv->status.intf &
-+		MCP25XXFD_CAN_INT_IF_CLEAR_MASK;
-+	u32 clear_irq = cpriv->status.intf & (~MCP25XXFD_CAN_INT_IF_CLEAR_MASK);
-+
-+	/* if no clearable flags are set then skip the whole transfer */
-+	if (!clearable_irq_active)
-+		return 0;
-+
-+	return mcp25xxfd_cmd_write_mask(cpriv->priv->spi, MCP25XXFD_CAN_INT,
-+					clear_irq, clearable_irq_active);
-+}
-+
-+static
-+int mcp25xxfd_can_int_handle_serrif_txmab(struct mcp25xxfd_can_priv *cpriv)
-+{
-+	int mode = mcp25xxfd_can_targetmode(cpriv);
-+
-+	cpriv->can.dev->stats.tx_fifo_errors++;
-+	cpriv->can.dev->stats.tx_errors++;
-+	MCP25XXFD_DEBUGFS_STATS_INCR(cpriv, int_serr_tx_count);
-+
-+	/* data7 contains custom mcp25xxfd error flags */
-+	cpriv->error_frame.data[7] |= MCP25XXFD_CAN_ERR_DATA7_MCP25XXFD_SERR_TX;
-+
-+	/* and switch back into the correct mode */
-+	return mcp25xxfd_can_switch_mode_no_wait(cpriv->priv,
-+						 &cpriv->regs.con, mode);
-+}
-+
-+static
-+int mcp25xxfd_can_int_handle_serrif_rxmab(struct mcp25xxfd_can_priv *cpriv)
-+{
-+	cpriv->can.dev->stats.rx_dropped++;
-+	cpriv->can.dev->stats.rx_errors++;
-+	MCP25XXFD_DEBUGFS_STATS_INCR(cpriv, int_serr_rx_count);
-+
-+	/* data7 contains custom mcp25xxfd error flags */
-+	cpriv->error_frame.data[7] |= MCP25XXFD_CAN_ERR_DATA7_MCP25XXFD_SERR_RX;
-+
-+	return 0;
-+}
-+
-+static int mcp25xxfd_can_int_handle_serrif(struct mcp25xxfd_can_priv *cpriv)
-+{
-+	if (!(cpriv->status.intf & MCP25XXFD_CAN_INT_SERRIF))
-+		return 0;
-+
-+	/* increment statistics counter now */
-+	MCP25XXFD_DEBUGFS_STATS_INCR(cpriv, int_serr_count);
-+
-+	/* interrupt flags have been cleared already */
-+
-+	/* Errors here are:
-+	 * * Bus Bandwidth Error: when a RX Message Assembly Buffer
-+	 *   is still full when the next message has already arrived
-+	 *   the recived message shall be ignored
-+	 * * TX MAB Underflow: when a TX Message is invalid
-+	 *   due to ECC errors or TXMAB underflow
-+	 *   in this situatioon the system will transition to
-+	 *   Restricted or Listen Only mode
-+	 */
-+
-+	cpriv->error_frame.id |= CAN_ERR_CRTL;
-+	cpriv->error_frame.data[1] |= CAN_ERR_CRTL_UNSPEC;
-+
-+	/* a mode change + invalid message would indicate
-+	 * TX MAB Underflow
-+	 */
-+	if ((cpriv->status.intf & MCP25XXFD_CAN_INT_MODIF) &&
-+	    (cpriv->status.intf & MCP25XXFD_CAN_INT_IVMIF)) {
-+		return mcp25xxfd_can_int_handle_serrif_txmab(cpriv);
-+	}
-+
-+	/* for RX there is only the RXIF an indicator
-+	 * - surprizingly RX-MAB does not change mode or anything
-+	 */
-+	if (cpriv->status.intf & MCP25XXFD_CAN_INT_RXIF)
-+		return mcp25xxfd_can_int_handle_serrif_rxmab(cpriv);
-+
-+	/* the final case */
-+	dev_warn_ratelimited(&cpriv->priv->spi->dev,
-+			     "unidentified system interrupt - intf =  %08x\n",
-+			     cpriv->status.intf);
-+
-+	return 0;
-+}
-+
-+static int mcp25xxfd_can_int_handle_modif(struct mcp25xxfd_can_priv *cpriv)
-+{
-+	struct spi_device *spi = cpriv->priv->spi;
-+	int mode;
-+	int ret;
-+
-+	/* Note that this irq does not get triggered in all situations
-+	 * for example SERRIF will move to RESTICTED or LISTENONLY
-+	 * but MODIF will not be raised!
-+	 */
-+
-+	if (!(cpriv->status.intf & MCP25XXFD_CAN_INT_MODIF))
-+		return 0;
-+	MCP25XXFD_DEBUGFS_STATS_INCR(cpriv, int_mod_count);
-+
-+	/* get the current mode */
-+	ret = mcp25xxfd_can_get_mode(cpriv->priv, &mode);
-+	if (ret)
-+		return ret;
-+	mode = ret;
-+
-+	/* switches to the same mode as before are ignored
-+	 * - this typically happens if the driver is shortly
-+	 *   switching to a different mode and then returning to the
-+	 *   original mode
-+	 */
-+	if (mode == cpriv->mode)
-+		return 0;
-+
-+	/* if we are restricted, then return to "normal" mode */
-+	if (mode == MCP25XXFD_CAN_CON_MODE_RESTRICTED) {
-+		cpriv->mode = mode;
-+		mode = mcp25xxfd_can_targetmode(cpriv);
-+		return mcp25xxfd_can_switch_mode_no_wait(cpriv->priv,
-+							 &cpriv->regs.con,
-+							 mode);
-+	}
-+
-+	/* the controller itself will transition to sleep, so we ignore it */
-+	if (mode == MCP25XXFD_CAN_CON_MODE_SLEEP) {
-+		cpriv->mode = mode;
-+		return 0;
-+	}
-+
-+	/* these we need to handle correctly, so warn and give context */
-+	dev_warn(&spi->dev,
-+		 "Controller unexpectedly switched from mode %u to %u\n",
-+		 cpriv->mode, mode);
-+
-+	/* assign the mode as current */
-+	cpriv->mode = mode;
-+
-+	return 0;
-+}
-+
-+static int mcp25xxfd_can_int_handle_eccif(struct mcp25xxfd_can_priv *cpriv)
-+{
-+	if (!(cpriv->status.intf & MCP25XXFD_CAN_INT_ECCIF))
-+		return 0;
-+
-+	MCP25XXFD_DEBUGFS_STATS_INCR(cpriv, int_ecc_count);
-+
-+	/* and prepare ERROR FRAME */
-+	cpriv->error_frame.id |= CAN_ERR_CRTL;
-+	cpriv->error_frame.data[1] |= CAN_ERR_CRTL_UNSPEC;
-+	/* data7 contains custom mcp25xxfd error flags */
-+	cpriv->error_frame.data[7] |= MCP25XXFD_CAN_ERR_DATA7_MCP25XXFD_ECC;
-+
-+	/* delegate to interrupt cleaning */
-+	return mcp25xxfd_ecc_clear_int(cpriv->priv);
-+}
-+
-+static void mcp25xxfd_can_int_handle_ivmif_tx(struct mcp25xxfd_can_priv *cpriv,
-+					      u32 *mask)
-+{
-+	/* check if it is really a known tx error */
-+	if ((cpriv->bus.bdiag[1] &
-+	     (MCP25XXFD_CAN_BDIAG1_DBIT1ERR |
-+	      MCP25XXFD_CAN_BDIAG1_DBIT0ERR |
-+	      MCP25XXFD_CAN_BDIAG1_NACKERR |
-+	      MCP25XXFD_CAN_BDIAG1_NBIT1ERR |
-+	      MCP25XXFD_CAN_BDIAG1_NBIT0ERR
-+		     )) == 0)
-+		return;
-+
-+	/* mark it as a protocol error */
-+	cpriv->error_frame.id |= CAN_ERR_PROT;
-+
-+	/* and update statistics */
-+	cpriv->can.dev->stats.tx_errors++;
-+
-+	/* and handle all the known cases */
-+	if (cpriv->bus.bdiag[1] & MCP25XXFD_CAN_BDIAG1_NACKERR) {
-+		/* TX-Frame not acknowledged - connected to CAN-bus? */
-+		*mask |= MCP25XXFD_CAN_BDIAG1_NACKERR;
-+		cpriv->error_frame.data[2] |= CAN_ERR_PROT_TX;
-+		cpriv->can.dev->stats.tx_aborted_errors++;
-+	}
-+	if (cpriv->bus.bdiag[1] & MCP25XXFD_CAN_BDIAG1_NBIT1ERR) {
-+		/* TX-Frame CAN-BUS Level is unexpectedly dominant */
-+		*mask |= MCP25XXFD_CAN_BDIAG1_NBIT1ERR;
-+		cpriv->can.dev->stats.tx_carrier_errors++;
-+		cpriv->error_frame.data[2] |= CAN_ERR_PROT_BIT1;
-+	}
-+	if (cpriv->bus.bdiag[1] & MCP25XXFD_CAN_BDIAG1_NBIT0ERR) {
-+		/* TX-Frame CAN-BUS Level is unexpectedly recessive */
-+		*mask |= MCP25XXFD_CAN_BDIAG1_NBIT0ERR;
-+		cpriv->can.dev->stats.tx_carrier_errors++;
-+		cpriv->error_frame.data[2] |= CAN_ERR_PROT_BIT0;
-+	}
-+	if (cpriv->bus.bdiag[1] & MCP25XXFD_CAN_BDIAG1_DBIT1ERR) {
-+		/* TX-Frame CAN-BUS Level is unexpectedly dominant
-+		 * during data phase
-+		 */
-+		*mask |= MCP25XXFD_CAN_BDIAG1_DBIT1ERR;
-+		cpriv->can.dev->stats.tx_carrier_errors++;
-+		cpriv->error_frame.data[2] |= CAN_ERR_PROT_BIT1;
-+	}
-+	if (cpriv->bus.bdiag[1] & MCP25XXFD_CAN_BDIAG1_DBIT0ERR) {
-+		/* TX-Frame CAN-BUS Level is unexpectedly recessive
-+		 * during data phase
-+		 */
-+		*mask |= MCP25XXFD_CAN_BDIAG1_DBIT0ERR;
-+		cpriv->can.dev->stats.tx_carrier_errors++;
-+		cpriv->error_frame.data[2] |= CAN_ERR_PROT_BIT0;
-+	}
-+}
-+
-+static void mcp25xxfd_can_int_handle_ivmif_rx(struct mcp25xxfd_can_priv *cpriv,
-+					      u32 *mask)
-+{
-+	/* check if it is really a known tx error */
-+	if ((cpriv->bus.bdiag[1] &
-+	     (MCP25XXFD_CAN_BDIAG1_DCRCERR |
-+	      MCP25XXFD_CAN_BDIAG1_DSTUFERR |
-+	      MCP25XXFD_CAN_BDIAG1_DFORMERR |
-+	      MCP25XXFD_CAN_BDIAG1_NCRCERR |
-+	      MCP25XXFD_CAN_BDIAG1_NSTUFERR |
-+	      MCP25XXFD_CAN_BDIAG1_NFORMERR
-+		     )) == 0)
-+		return;
-+
-+	/* mark it as a protocol error */
-+	cpriv->error_frame.id |= CAN_ERR_PROT;
-+
-+	/* and update statistics */
-+	cpriv->can.dev->stats.rx_errors++;
-+
-+	/* handle the cases */
-+	if (cpriv->bus.bdiag[1] & MCP25XXFD_CAN_BDIAG1_DCRCERR) {
-+		/* RX-Frame with bad CRC during data phase */
-+		*mask |= MCP25XXFD_CAN_BDIAG1_DCRCERR;
-+		cpriv->can.dev->stats.rx_crc_errors++;
-+		cpriv->error_frame.data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ;
-+	}
-+	if (cpriv->bus.bdiag[1] & MCP25XXFD_CAN_BDIAG1_DSTUFERR) {
-+		/* RX-Frame with bad stuffing during data phase */
-+		*mask |= MCP25XXFD_CAN_BDIAG1_DSTUFERR;
-+		cpriv->can.dev->stats.rx_frame_errors++;
-+		cpriv->error_frame.data[2] |= CAN_ERR_PROT_STUFF;
-+	}
-+	if (cpriv->bus.bdiag[1] & MCP25XXFD_CAN_BDIAG1_DFORMERR) {
-+		/* RX-Frame with bad format during data phase */
-+		*mask |= MCP25XXFD_CAN_BDIAG1_DFORMERR;
-+		cpriv->can.dev->stats.rx_frame_errors++;
-+		cpriv->error_frame.data[2] |= CAN_ERR_PROT_FORM;
-+	}
-+	if (cpriv->bus.bdiag[1] & MCP25XXFD_CAN_BDIAG1_NCRCERR) {
-+		/* RX-Frame with bad CRC during data phase */
-+		*mask |= MCP25XXFD_CAN_BDIAG1_NCRCERR;
-+		cpriv->can.dev->stats.rx_crc_errors++;
-+		cpriv->error_frame.data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ;
-+	}
-+	if (cpriv->bus.bdiag[1] & MCP25XXFD_CAN_BDIAG1_NSTUFERR) {
-+		/* RX-Frame with bad stuffing during data phase */
-+		*mask |= MCP25XXFD_CAN_BDIAG1_NSTUFERR;
-+		cpriv->can.dev->stats.rx_frame_errors++;
-+		cpriv->error_frame.data[2] |= CAN_ERR_PROT_STUFF;
-+	}
-+	if (cpriv->bus.bdiag[1] & MCP25XXFD_CAN_BDIAG1_NFORMERR) {
-+		/* RX-Frame with bad format during data phase */
-+		*mask |= MCP25XXFD_CAN_BDIAG1_NFORMERR;
-+		cpriv->can.dev->stats.rx_frame_errors++;
-+		cpriv->error_frame.data[2] |= CAN_ERR_PROT_FORM;
-+	}
-+}
-+
-+static int mcp25xxfd_can_int_handle_ivmif(struct mcp25xxfd_can_priv *cpriv)
-+{
-+	struct spi_device *spi = cpriv->priv->spi;
-+	u32 mask, bdiag1;
-+	int ret;
-+
-+	if (!(cpriv->status.intf & MCP25XXFD_CAN_INT_IVMIF))
-+		return 0;
-+
-+	MCP25XXFD_DEBUGFS_STATS_INCR(cpriv, int_ivm_count);
-+
-+	/* if we have a systemerror as well,
-+	 * then ignore it as they correlate
-+	 */
-+	if (cpriv->status.intf & MCP25XXFD_CAN_INT_SERRIF)
-+		return 0;
-+
-+	/* read bus diagnostics */
-+	ret = mcp25xxfd_cmd_read_regs(spi, MCP25XXFD_CAN_BDIAG0,
-+				      cpriv->bus.bdiag,
-+				      sizeof(cpriv->bus.bdiag));
-+	if (ret)
-+		return ret;
-+
-+	/* clear the masks of bits to clear */
-+	mask = 0;
-+
-+	/* check rx and tx errors */
-+	mcp25xxfd_can_int_handle_ivmif_tx(cpriv, &mask);
-+	mcp25xxfd_can_int_handle_ivmif_rx(cpriv, &mask);
-+
-+	/* clear flags if we have bits masked */
-+	if (!mask) {
-+		/* the unsupported case, where we are not
-+		 * clearing any registers
-+		 */
-+		dev_warn_once(&spi->dev,
-+			      "found IVMIF situation not supported by driver - bdiag = [0x%08x, 0x%08x]",
-+			      cpriv->bus.bdiag[0], cpriv->bus.bdiag[1]);
-+		return -EINVAL;
-+	}
-+
-+	/* clear the bits in bdiag1 */
-+	bdiag1 = cpriv->bus.bdiag[1] & (~mask);
-+	/* and write it */
-+	ret = mcp25xxfd_cmd_write_mask(spi, MCP25XXFD_CAN_BDIAG1, bdiag1, mask);
-+	if (ret)
-+		return ret;
-+
-+	/* and clear the interrupt flag until we have received or transmited */
-+	cpriv->status.intf &= ~(MCP25XXFD_CAN_INT_IVMIE);
-+	return mcp25xxfd_cmd_write_mask(spi, MCP25XXFD_CAN_INT,
-+					cpriv->status.intf,
-+					MCP25XXFD_CAN_INT_IVMIE);
-+}
-+
-+static int mcp25xxfd_can_int_handle_cerrif(struct mcp25xxfd_can_priv *cpriv)
-+{
-+	if (!(cpriv->status.intf & MCP25XXFD_CAN_INT_CERRIF))
-+		return 0;
-+
-+	/* this interrupt exists primarilly to counter possible
-+	 * bus off situations more detailed information
-+	 * can be found and controlled in the TREC register
-+	 */
-+
-+	MCP25XXFD_DEBUGFS_STATS_INCR(cpriv, int_cerr_count);
-+
-+	netdev_warn(cpriv->can.dev, "CAN Bus error experienced");
-+
-+	return 0;
-+}
-+
-+static int mcp25xxfd_can_int_error_counters(struct mcp25xxfd_can_priv *cpriv)
-+{
-+	if (cpriv->status.trec & MCP25XXFD_CAN_TREC_TXWARN) {
-+		cpriv->bus.new_state = CAN_STATE_ERROR_WARNING;
-+		cpriv->error_frame.id |= CAN_ERR_CRTL;
-+		cpriv->error_frame.data[1] |= CAN_ERR_CRTL_TX_WARNING;
-+	}
-+	if (cpriv->status.trec & MCP25XXFD_CAN_TREC_RXWARN) {
-+		cpriv->bus.new_state = CAN_STATE_ERROR_WARNING;
-+		cpriv->error_frame.id |= CAN_ERR_CRTL;
-+		cpriv->error_frame.data[1] |= CAN_ERR_CRTL_RX_WARNING;
-+	}
-+	if (cpriv->status.trec & MCP25XXFD_CAN_TREC_TXBP) {
-+		cpriv->bus.new_state = CAN_STATE_ERROR_PASSIVE;
-+		cpriv->error_frame.id |= CAN_ERR_CRTL;
-+		cpriv->error_frame.data[1] |= CAN_ERR_CRTL_TX_PASSIVE;
-+	}
-+	if (cpriv->status.trec & MCP25XXFD_CAN_TREC_RXBP) {
-+		cpriv->bus.new_state = CAN_STATE_ERROR_PASSIVE;
-+		cpriv->error_frame.id |= CAN_ERR_CRTL;
-+		cpriv->error_frame.data[1] |= CAN_ERR_CRTL_RX_PASSIVE;
-+	}
-+	if (cpriv->status.trec & MCP25XXFD_CAN_TREC_TXBO) {
-+		cpriv->bus.new_state = CAN_STATE_BUS_OFF;
-+		cpriv->error_frame.id |= CAN_ERR_BUSOFF;
-+	}
-+
-+	return 0;
-+}
-+
-+static int mcp25xxfd_can_int_error_handling(struct mcp25xxfd_can_priv *cpriv)
-+{
-+	/* based on the last state state check the new state */
-+	switch (cpriv->can.state) {
-+	case CAN_STATE_ERROR_ACTIVE:
-+		if (cpriv->bus.new_state >= CAN_STATE_ERROR_WARNING &&
-+		    cpriv->bus.new_state <= CAN_STATE_BUS_OFF)
-+			cpriv->can.can_stats.error_warning++;
-+		/* fallthrough */
-+	case CAN_STATE_ERROR_WARNING:
-+		if (cpriv->bus.new_state >= CAN_STATE_ERROR_PASSIVE &&
-+		    cpriv->bus.new_state <= CAN_STATE_BUS_OFF)
-+			cpriv->can.can_stats.error_passive++;
-+		break;
-+	default:
-+		break;
-+	}
-+	cpriv->can.state = cpriv->bus.new_state;
-+
-+	/* and send error packet */
-+	if (cpriv->error_frame.id)
-+		mcp25xxfd_can_int_send_error_skb(cpriv);
-+
-+	/* handle BUS OFF */
-+	if (cpriv->can.state == CAN_STATE_BUS_OFF) {
-+		if (cpriv->can.restart_ms == 0) {
-+			cpriv->can.can_stats.bus_off++;
-+			can_bus_off(cpriv->can.dev);
-+		}
-+	} else {
-+		/* restart the tx queue if needed */
-+		mcp25xxfd_can_tx_queue_restart(cpriv);
-+	}
-+
-+	return 0;
-+}
-+
-+static int mcp25xxfd_can_int_handle_status(struct mcp25xxfd_can_priv *cpriv)
-+{
-+	int ret;
-+
-+	/* clear all the interrupts asap - we have them on file allready */
-+	ret = mcp25xxfd_can_int_clear_int_flags(cpriv);
-+	if (ret)
-+		return ret;
-+
-+	/* set up new state and error frame for this loop */
-+	cpriv->bus.new_state = cpriv->bus.state;
-+	memset(&cpriv->error_frame, 0, sizeof(cpriv->error_frame));
-+
-+	/* setup the process queue by clearing the counter */
-+	cpriv->fifos.submit_queue_count = 0;
-+
-+	/* handle interrupts */
-+
-+	/* system error interrupt needs to get handled first
-+	 * to get us out of restricted mode
-+	 */
-+	ret = mcp25xxfd_can_int_handle_serrif(cpriv);
-+	if (ret)
-+		return ret;
-+
-+	/* mode change interrupt */
-+	ret = mcp25xxfd_can_int_handle_modif(cpriv);
-+	if (ret)
-+		return ret;
-+
-+	/* handle the rx */
-+	ret = mcp25xxfd_can_rx_handle_int_rxif(cpriv);
-+	if (ret)
-+		return ret;
-+	/* handle aborted TX FIFOs */
-+	ret = mcp25xxfd_can_tx_handle_int_txatif(cpriv);
-+	if (ret)
-+		return ret;
-+
-+	/* handle the TEF */
-+	ret = mcp25xxfd_can_tx_handle_int_tefif(cpriv);
-+	if (ret)
-+		return ret;
-+
-+	/* handle error interrupt flags */
-+	ret = mcp25xxfd_can_rx_handle_int_rxovif(cpriv);
-+	if (ret)
-+		return ret;
-+
-+	/* sram ECC error interrupt */
-+	ret = mcp25xxfd_can_int_handle_eccif(cpriv);
-+	if (ret)
-+		return ret;
-+
-+	/* message format interrupt */
-+	ret = mcp25xxfd_can_int_handle_ivmif(cpriv);
-+	if (ret)
-+		return ret;
-+
-+	/* handle bus errors in more detail */
-+	ret = mcp25xxfd_can_int_handle_cerrif(cpriv);
-+	if (ret)
-+		return ret;
-+
-+	/* error counter handling */
-+	ret = mcp25xxfd_can_int_error_counters(cpriv);
-+	if (ret)
-+		return ret;
-+
-+	/* error counter handling */
-+	ret = mcp25xxfd_can_int_error_handling(cpriv);
-+	if (ret)
-+		return ret;
-+
-+	/* and submit can frames to network stack */
-+	ret = mcp25xxfd_can_int_submit_frames(cpriv);
-+
-+	return ret;
-+}
-+
-+irqreturn_t mcp25xxfd_can_int(int irq, void *dev_id)
-+{
-+	struct mcp25xxfd_can_priv *cpriv = dev_id;
-+	int loops, ret;
-+
-+	/* count interrupt calls */
-+	MCP25XXFD_DEBUGFS_STATS_INCR(cpriv, irq_calls);
-+
-+	/* loop forever unless we need to exit */
-+	for (loops = 0; true; loops++) {
-+		/* count irq loops */
-+		MCP25XXFD_DEBUGFS_STATS_INCR(cpriv, irq_loops);
-+
-+		/* read interrupt status flags in bulk */
-+		ret = mcp25xxfd_cmd_read_regs(cpriv->priv->spi,
-+					      MCP25XXFD_CAN_INT,
-+					      &cpriv->status.intf,
-+					      sizeof(cpriv->status));
-+		if (ret)
-+			return ret;
-+
-+		/* only act if the IE mask configured has active IF bits
-+		 * otherwise the Interrupt line should be deasserted already
-+		 * so we can exit the loop
-+		 */
-+		if (((cpriv->status.intf >> MCP25XXFD_CAN_INT_IE_SHIFT) &
-+		       cpriv->status.intf) == 0)
-+			break;
-+
-+		/* handle the status */
-+		ret = mcp25xxfd_can_int_handle_status(cpriv);
-+		if (ret)
-+			return ret;
-+
-+		/* allow voluntarily rescheduling every so often to avoid
-+		 * long CS lows at the end of a transfer on low power CPUs
-+		 * avoiding SERR happening
-+		 */
-+		if (loops % reschedule_int_thread_after == 0) {
-+			MCP25XXFD_DEBUGFS_STATS_INCR(cpriv,
-+						     irq_thread_rescheduled);
-+			cond_resched();
-+		}
-+	}
-+
-+	return IRQ_HANDLED;
-+}
-+
-+int mcp25xxfd_can_int_clear(struct mcp25xxfd_priv *priv)
-+{
-+	return mcp25xxfd_cmd_write_mask(priv->spi, MCP25XXFD_CAN_INT, 0,
-+					MCP25XXFD_CAN_INT_IF_MASK);
-+}
-+
-+int mcp25xxfd_can_int_enable(struct mcp25xxfd_priv *priv, bool enable)
-+{
-+	struct mcp25xxfd_can_priv *cpriv = priv->cpriv;
-+	const u32 mask = MCP25XXFD_CAN_INT_TEFIE |
-+		MCP25XXFD_CAN_INT_RXIE |
-+		MCP25XXFD_CAN_INT_MODIE |
-+		MCP25XXFD_CAN_INT_SERRIE |
-+		MCP25XXFD_CAN_INT_IVMIE |
-+		MCP25XXFD_CAN_INT_CERRIE |
-+		MCP25XXFD_CAN_INT_RXOVIE |
-+		MCP25XXFD_CAN_INT_ECCIE;
-+	u32 value = cpriv ? cpriv->status.intf : 0;
-+	int ret;
-+
-+	/* apply mask and */
-+	value &= ~(MCP25XXFD_CAN_INT_IE_MASK);
-+	if (enable)
-+		value |= mask;
-+
-+	/* and write to int register */
-+	ret = mcp25xxfd_cmd_write_mask(priv->spi, MCP25XXFD_CAN_INT,
-+				       value, mask);
-+	if (ret)
-+		return ret;
-+	if (!cpriv)
-+		return 0;
-+
-+	cpriv->status.intf = value;
-+
-+	/* enable/disable interrupt handler */
-+	if (cpriv->irq.allocated) {
-+		if (enable && !cpriv->irq.enabled)
-+			enable_irq(cpriv->priv->spi->irq);
-+		if (!enable && cpriv->irq.enabled)
-+			disable_irq(cpriv->priv->spi->irq);
-+		cpriv->irq.enabled = enable;
-+	} else {
-+		cpriv->irq.enabled = false;
-+	}
-+
-+	return 0;
-+}
-diff --git a/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_int.h b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_int.h
-new file mode 100644
-index 000000000000..cc2ad992c307
---- /dev/null
-+++ b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_int.h
-@@ -0,0 +1,17 @@
-+/* SPDX-License-Identifier: GPL-2.0 */
-+
-+/* CAN bus driver for Microchip 25XXFD CAN Controller with SPI Interface
-+ *
-+ * Copyright 2019 Martin Sperl <kernel@martin.sperl.org>
-+ */
-+#ifndef __MCP25XXFD_CAN_INT_H
-+#define __MCP25XXFD_CAN_INT_H
-+
-+#include "mcp25xxfd_priv.h"
-+
-+int mcp25xxfd_can_int_clear(struct mcp25xxfd_priv *priv);
-+int mcp25xxfd_can_int_enable(struct mcp25xxfd_priv *priv, bool enable);
-+
-+irqreturn_t mcp25xxfd_can_int(int irq, void *dev_id);
-+
-+#endif /* __MCP25XXFD_CAN_INT_H */
-diff --git a/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_priv.h b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_priv.h
-new file mode 100644
-index 000000000000..eeb9c88c7e97
---- /dev/null
-+++ b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_priv.h
-@@ -0,0 +1,203 @@
-+/* SPDX-License-Identifier: GPL-2.0 */
-+
-+/* CAN bus driver for Microchip 25XXFD CAN Controller with SPI Interface
-+ *
-+ * Copyright 2019 Martin Sperl <kernel@martin.sperl.org>
-+ */
-+
-+#ifndef __MCP25XXFD_CAN_PRIV_H
-+#define __MCP25XXFD_CAN_PRIV_H
-+
-+#include <linux/can/dev.h>
-+#include <linux/dcache.h>
-+
-+#include "mcp25xxfd_priv.h"
-+
-+#define TX_ECHO_SKB_MAX	32
-+
-+/* information on each fifo type */
-+struct mcp25xxfd_fifo {
-+	u32 count;
-+	u32 start;
-+	u32 size;
-+#ifdef CONFIG_DEBUG_FS
-+	u64 dlc_usage[16];
-+	u64 fd_count;
-+#endif /* CONFIG_DEBUG_FS */
-+};
-+
-+/* used for sorting incoming messages */
-+struct mcp25xxfd_obj_ts {
-+	s32 ts; /* using signed to handle rollover correctly when sorting */
-+	u16 fifo;
-+	s16 is_rx;
-+};
-+
-+/* general info on each fifo */
-+struct mcp25xxfd_fifo_info {
-+	u32 is_rx;
-+	u32 offset;
-+	u32 priority;
-+#ifdef CONFIG_DEBUG_FS
-+	u64 use_count;
-+#endif /* CONFIG_DEBUG_FS */
-+};
-+
-+struct mcp25xxfd_can_priv {
-+	/* can_priv has to be the first one to be usable with alloc_candev
-+	 * which expects struct can_priv to be right at the start of the
-+	 * priv structure
-+	 */
-+	struct can_priv can;
-+	struct mcp25xxfd_priv *priv;
-+	struct regulator *transceiver;
-+
-+	/* the can mode currently active */
-+	int mode;
-+
-+	/* interrupt state */
-+	struct {
-+		int enabled;
-+		int allocated;
-+	} irq;
-+
-+	/* can config registers */
-+	struct {
-+		u32 con;
-+		u32 tdc;
-+		u32 tscon;
-+		u32 tefcon;
-+		u32 nbtcfg;
-+		u32 dbtcfg;
-+	} regs;
-+
-+	/* can status registers (mostly) - read in one go
-+	 * bdiag0 and bdiag1 are optional, but when
-+	 * berr counters are requested on a regular basis
-+	 * during high CAN-bus load this would trigger the fact
-+	 * that spi_sync would get queued for execution in the
-+	 * spi thread and the spi handler would not get
-+	 * called inline in the interrupt thread without any
-+	 * context switches or wakeups...
-+	 */
-+	struct {
-+		u32 intf;
-+		/* ASSERT(CAN_INT + 4 == CAN_RXIF) */
-+		u32 rxif;
-+		/* ASSERT(CAN_RXIF + 4 == CAN_TXIF) */
-+		u32 txif;
-+		/* ASSERT(CAN_TXIF + 4 == CAN_RXOVIF) */
-+		u32 rxovif;
-+		/* ASSERT(CAN_RXOVIF + 4 == CAN_TXATIF) */
-+		u32 txatif;
-+		/* ASSERT(CAN_TXATIF + 4 == CAN_TXREQ) */
-+		u32 txreq;
-+		/* ASSERT(CAN_TXREQ + 4 == CAN_TREC) */
-+		u32 trec;
-+	} status;
-+
-+	/* information of fifo setup */
-+	struct {
-+		/* define payload size and mode */
-+		u32 payload_size;
-+		u32 payload_mode;
-+
-+		/* infos on fifo layout */
-+
-+		/* TEF */
-+		struct {
-+			u32 count;
-+			u32 size;
-+			u32 index;
-+		} tef;
-+
-+		/* info on each fifo */
-+		struct mcp25xxfd_fifo_info info[32];
-+
-+		/* extra info on rx/tx fifo groups */
-+		struct mcp25xxfd_fifo tx;
-+		struct mcp25xxfd_fifo rx;
-+
-+		/* queue of can frames that need to get submitted
-+		 * to the network stack during an interrupt loop in one go
-+		 * (this gets sorted by timestamp before submission
-+		 * and contains both rx frames as well tx frames that have
-+		 * gone over the CAN bus successfully
-+		 */
-+		struct mcp25xxfd_obj_ts submit_queue[32];
-+		int  submit_queue_count;
-+
-+		/* the tx queue of spi messages */
-+		struct mcp25xxfd_tx_spi_message_queue *tx_queue;
-+	} fifos;
-+
-+	/* statistics exposed via debugfs */
-+#ifdef CONFIG_DEBUG_FS
-+	struct dentry *debugfs_dir;
-+
-+	struct {
-+		u64 irq_calls;
-+		u64 irq_loops;
-+		u64 irq_thread_rescheduled;
-+
-+		u64 int_serr_count;
-+		u64 int_serr_rx_count;
-+		u64 int_serr_tx_count;
-+		u64 int_mod_count;
-+		u64 int_rx_count;
-+		u64 int_txat_count;
-+		u64 int_tef_count;
-+		u64 int_rxov_count;
-+		u64 int_ecc_count;
-+		u64 int_ivm_count;
-+		u64 int_cerr_count;
-+
-+		u64 tx_fd_count;
-+		u64 tx_brs_count;
-+
-+		u64 tef_reads;
-+		u64 tef_read_splits;
-+		u64 tef_conservative_reads;
-+		u64 tef_optimized_reads;
-+#define MCP25XXFD_CAN_TEF_READ_BINS 8
-+		u64 tef_optimized_read_sizes[MCP25XXFD_CAN_TEF_READ_BINS];
-+
-+		u64 rx_reads;
-+		u64 rx_reads_prefetched_too_few;
-+		u64 rx_reads_prefetched_too_few_bytes;
-+		u64 rx_reads_prefetched_too_many;
-+		u64 rx_reads_prefetched_too_many_bytes;
-+		u64 rx_single_reads;
-+		u64 rx_bulk_reads;
-+#define MCP25XXFD_CAN_RX_BULK_READ_BINS 8
-+		u64 rx_bulk_read_sizes[MCP25XXFD_CAN_RX_BULK_READ_BINS];
-+	} stats;
-+#endif /* CONFIG_DEBUG_FS */
-+
-+	/* history of rx-dlc */
-+	struct {
-+#define MCP25XXFD_CAN_RX_DLC_HISTORY_SIZE 32
-+		u8 dlc[MCP25XXFD_CAN_RX_DLC_HISTORY_SIZE];
-+		u8 brs[MCP25XXFD_CAN_RX_DLC_HISTORY_SIZE];
-+		u8 index;
-+		u32 predicted_len;
-+	} rx_history;
-+
-+	/* bus state */
-+	struct {
-+		u32 state;
-+		u32 new_state;
-+		u32 bdiag[2];
-+	} bus;
-+
-+	/* can error messages */
-+	struct {
-+		u32 id;
-+		u8  data[8];
-+	} error_frame;
-+
-+	/* a copy of mcp25xxfd-sram in ram */
-+	u8 sram[MCP25XXFD_SRAM_SIZE];
-+};
-+
-+#endif /* __MCP25XXFD_CAN_PRIV_H */
-diff --git a/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_rx.c b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_rx.c
-new file mode 100644
-index 000000000000..55d027cd3049
---- /dev/null
-+++ b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_rx.c
-@@ -0,0 +1,521 @@
-+// SPDX-License-Identifier: GPL-2.0
-+
-+/* CAN bus driver for Microchip 25XXFD CAN Controller with SPI Interface
-+ *
-+ * Copyright 2019 Martin Sperl <kernel@martin.sperl.org>
-+ *
-+ * Based on Microchip MCP251x CAN controller driver written by
-+ * David Vrabel, Copyright 2006 Arcom Control Systems Ltd.
-+ */
-+
-+#include <linux/can/core.h>
-+#include <linux/can/dev.h>
-+#include <linux/device.h>
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/netdevice.h>
-+#include <linux/skbuff.h>
-+#include <linux/slab.h>
-+#include <linux/spi/spi.h>
-+
-+#include "mcp25xxfd_cmd.h"
-+#include "mcp25xxfd_can.h"
-+#include "mcp25xxfd_can_debugfs.h"
-+#include "mcp25xxfd_can_id.h"
-+#include "mcp25xxfd_can_priv.h"
-+#include "mcp25xxfd_can_rx.h"
-+
-+/* module parameters */
-+unsigned int rx_prefetch_bytes = -1;
-+module_param(rx_prefetch_bytes, uint, 0664);
-+MODULE_PARM_DESC(rx_prefetch_bytes,
-+		 "number of bytes to blindly prefetch when reading a rx-fifo");
-+
-+static struct sk_buff *
-+mcp25xxfd_can_rx_submit_normal_frame(struct mcp25xxfd_can_priv *cpriv,
-+				     u32 id, u32 dlc, u8 **data)
-+{
-+	struct can_frame *frame;
-+	struct sk_buff *skb;
-+
-+	/* allocate frame */
-+	skb = alloc_can_skb(cpriv->can.dev, &frame);
-+	if (!skb)
-+		return NULL;
-+
-+	/* set id, dlc and flags */
-+	frame->can_id = id;
-+	frame->can_dlc = dlc;
-+
-+	/* and set the pointer to data */
-+	*data = frame->data;
-+
-+	return skb;
-+}
-+
-+/* it is almost identical except for the type of the frame... */
-+static struct sk_buff *
-+mcp25xxfd_can_rx_submit_fd_frame(struct mcp25xxfd_can_priv *cpriv,
-+				 u32 id, u32 flags, u32 len, u8 **data)
-+{
-+	struct canfd_frame *frame;
-+	struct sk_buff *skb;
-+
-+	/* allocate frame */
-+	skb = alloc_canfd_skb(cpriv->can.dev, &frame);
-+	if (!skb)
-+		return NULL;
-+
-+	/* set id, dlc and flags */
-+	frame->can_id = id;
-+	frame->len = len;
-+	frame->flags |= flags;
-+
-+	/* and set the pointer to data */
-+	*data = frame->data;
-+
-+	return skb;
-+}
-+
-+int mcp25xxfd_can_rx_submit_frame(struct mcp25xxfd_can_priv *cpriv, int fifo)
-+{
-+	struct net_device *net = cpriv->can.dev;
-+	int addr = cpriv->fifos.info[fifo].offset;
-+	struct mcp25xxfd_can_obj_rx *rx =
-+		(struct mcp25xxfd_can_obj_rx *)(cpriv->sram + addr);
-+	u8 *data = NULL;
-+	struct sk_buff *skb;
-+	u32 id, dlc, len, flags;
-+
-+	/* compute the can_id */
-+	mcp25xxfd_can_id_from_mcp25xxfd(rx->id, rx->flags, &id);
-+
-+	/* and dlc */
-+	dlc = (rx->flags & MCP25XXFD_CAN_OBJ_FLAGS_DLC_MASK) >>
-+		MCP25XXFD_CAN_OBJ_FLAGS_DLC_SHIFT;
-+	len = can_dlc2len(dlc);
-+
-+	/* update stats */
-+	net->stats.rx_packets++;
-+	net->stats.rx_bytes += len;
-+	cpriv->fifos.rx.dlc_usage[dlc]++;
-+	if (rx->flags & MCP25XXFD_CAN_OBJ_FLAGS_FDF)
-+		MCP25XXFD_DEBUGFS_INCR(cpriv->fifos.rx.fd_count);
-+
-+	/* add to rx_history */
-+	cpriv->rx_history.dlc[cpriv->rx_history.index] = dlc;
-+	cpriv->rx_history.brs[cpriv->rx_history.index] =
-+		(rx->flags & MCP25XXFD_CAN_OBJ_FLAGS_BRS) ? CANFD_BRS : 0;
-+	cpriv->rx_history.index++;
-+	if (cpriv->rx_history.index >= MCP25XXFD_CAN_RX_DLC_HISTORY_SIZE)
-+		cpriv->rx_history.index = 0;
-+
-+	/* allocate the skb buffer */
-+	if (rx->flags & MCP25XXFD_CAN_OBJ_FLAGS_FDF) {
-+		flags = 0;
-+		flags |= (rx->flags & MCP25XXFD_CAN_OBJ_FLAGS_BRS) ?
-+			CANFD_BRS : 0;
-+		flags |= (rx->flags & MCP25XXFD_CAN_OBJ_FLAGS_ESI) ?
-+			CANFD_ESI : 0;
-+		skb = mcp25xxfd_can_rx_submit_fd_frame(cpriv, id, flags,
-+						       len, &data);
-+	} else {
-+		skb = mcp25xxfd_can_rx_submit_normal_frame(cpriv, id,
-+							   len, &data);
-+	}
-+	if (!skb) {
-+		netdev_err(net, "cannot allocate RX skb\n");
-+		net->stats.rx_dropped++;
-+		return -ENOMEM;
-+	}
-+
-+	/* copy the payload data */
-+	memcpy(data, rx->data, len);
-+
-+	/* and submit the frame */
-+	netif_rx_ni(skb);
-+
-+	return 0;
-+}
-+
-+static int mcp25xxfd_can_rx_read_frame(struct mcp25xxfd_can_priv *cpriv,
-+				       int fifo, int prefetch_bytes, bool read)
-+{
-+	struct spi_device *spi = cpriv->priv->spi;
-+	struct net_device *net = cpriv->can.dev;
-+	int addr = cpriv->fifos.info[fifo].offset;
-+	struct mcp25xxfd_can_obj_rx *rx =
-+		(struct mcp25xxfd_can_obj_rx *)(cpriv->sram + addr);
-+	int dlc;
-+	int len, ret;
-+
-+	/* we read the header plus prefetch_bytes */
-+	if (read) {
-+		cpriv->stats.rx_single_reads++;
-+		ret = mcp25xxfd_cmd_readn(spi, MCP25XXFD_SRAM_ADDR(addr),
-+					  rx, sizeof(*rx) + prefetch_bytes);
-+		if (ret)
-+			return ret;
-+	}
-+
-+	/* transpose the headers to CPU format*/
-+	rx->id = le32_to_cpu(rx->id);
-+	rx->flags = le32_to_cpu(rx->flags);
-+	rx->ts = le32_to_cpu(rx->ts);
-+
-+	/* compute len */
-+	dlc = (rx->flags & MCP25XXFD_CAN_OBJ_FLAGS_DLC_MASK) >>
-+		MCP25XXFD_CAN_OBJ_FLAGS_DLC_SHIFT;
-+	len = can_dlc2len(min_t(int, dlc, (net->mtu == CANFD_MTU) ? 15 : 8));
-+
-+	/* read the remaining data for canfd frames */
-+	if (read && len > prefetch_bytes) {
-+		/* update stats */
-+		MCP25XXFD_DEBUGFS_STATS_INCR(cpriv,
-+					     rx_reads_prefetched_too_few);
-+		MCP25XXFD_DEBUGFS_STATS_ADD(cpriv,
-+					    rx_reads_prefetched_too_few_bytes,
-+					    len - prefetch_bytes);
-+		/* here the extra portion reading data after prefetch */
-+		ret = mcp25xxfd_cmd_readn(spi,
-+					  MCP25XXFD_SRAM_ADDR(addr) +
-+					  sizeof(*rx) + prefetch_bytes,
-+					  &rx->data[prefetch_bytes],
-+					  len - prefetch_bytes);
-+		if (ret)
-+			return ret;
-+	}
-+
-+	/* update stats */
-+	cpriv->stats.rx_reads++;
-+	if (len < prefetch_bytes) {
-+		MCP25XXFD_DEBUGFS_STATS_INCR(cpriv,
-+					     rx_reads_prefetched_too_many);
-+		MCP25XXFD_DEBUGFS_STATS_ADD(cpriv,
-+					    rx_reads_prefetched_too_many,
-+					    prefetch_bytes - len);
-+	}
-+
-+	/* clear the rest of the buffer - just to be safe */
-+	memset(rx->data + len, 0, ((net->mtu == CANFD_MTU) ? 64 : 8) - len);
-+
-+	/* increment the statistics counter */
-+	MCP25XXFD_DEBUGFS_INCR(cpriv->fifos.info[fifo].use_count);
-+
-+	/* add the fifo to the process queues */
-+	mcp25xxfd_can_queue_frame(cpriv, fifo, rx->ts, true);
-+
-+	/* and clear the interrupt flag for that fifo */
-+	return mcp25xxfd_cmd_write_mask(spi, MCP25XXFD_CAN_FIFOCON(fifo),
-+					MCP25XXFD_CAN_FIFOCON_FRESET,
-+					MCP25XXFD_CAN_FIFOCON_FRESET);
-+}
-+
-+static int mcp25xxfd_can_read_rx_frame_bulk(struct mcp25xxfd_can_priv *cpriv,
-+					    int fstart,
-+					    int fend)
-+{
-+	struct net_device *net = cpriv->can.dev;
-+	int count = abs(fend - fstart) + 1;
-+	int flowest = min_t(int, fstart, fend);
-+	int addr = cpriv->fifos.info[flowest].offset;
-+	struct mcp25xxfd_can_obj_rx *rx =
-+		(struct mcp25xxfd_can_obj_rx *)(cpriv->sram + addr);
-+	int len = (sizeof(*rx) + ((net->mtu == CANFD_MTU) ? 64 : 8)) * count;
-+	int fifo, i, ret;
-+
-+	/* update stats */
-+	MCP25XXFD_DEBUGFS_STATS_INCR(cpriv, rx_bulk_reads);
-+	i = min_t(int, MCP25XXFD_CAN_RX_BULK_READ_BINS - 1, count - 1);
-+	MCP25XXFD_DEBUGFS_STATS_INCR(cpriv, rx_bulk_read_sizes[i]);
-+
-+	/* we read the header plus read_min data bytes */
-+	ret = mcp25xxfd_cmd_readn(cpriv->priv->spi, MCP25XXFD_SRAM_ADDR(addr),
-+				  rx, len);
-+	if (ret)
-+		return ret;
-+
-+	/* now process all of them - no need to read... */
-+	for (fifo = fstart; count > 0; fifo ++, count--) {
-+		ret = mcp25xxfd_can_rx_read_frame(cpriv, fifo, 8, false);
-+		if (ret)
-+			return ret;
-+	}
-+
-+	return 0;
-+}
-+
-+/* predict dlc size based on historic behaviour */
-+static int mcp25xxfd_can_rx_predict_prefetch(struct mcp25xxfd_can_priv *cpriv)
-+{
-+	int dlc, i, top;
-+	u8 histo[16];
-+
-+	/* if we have a prfecth set then use that one */
-+	if (rx_prefetch_bytes != -1)
-+		return min_t(int, rx_prefetch_bytes,
-+			     (cpriv->can.dev->mtu == CANFD_MTU) ? 64 : 8);
-+
-+	/* memset */
-+	memset(histo, 0, sizeof(histo));
-+
-+	/* for all others compute the histogram */
-+	for (i = 0; i < MCP25XXFD_CAN_RX_DLC_HISTORY_SIZE; i++)
-+		histo[cpriv->rx_history.dlc[i]]++;
-+
-+	/* and now find the highest fit */
-+	for (i = (cpriv->can.dev->mtu == CANFD_MTU) ? 15 : 8, dlc = 8, top = 0;
-+	      i >= 0; i--) {
-+		if (top < histo[i]) {
-+			top = histo[i];
-+			dlc = i;
-+		}
-+	}
-+
-+	/* compute length from dlc */
-+	cpriv->rx_history.predicted_len = can_dlc2len(dlc);
-+
-+	/* return the predicted length */
-+	return cpriv->rx_history.predicted_len;
-+}
-+
-+/* at least in can2.0 mode we can read multiple RX-fifos in one go
-+ * in case they are ajactent to each other and thus we can reduce
-+ * the number of spi messages produced and this improves spi-bus
-+ * usage efficiency.
-+ * In canFD mode this may also be possible, but would need some
-+ * statistics to decide if it is worth reading a full 64 bytes
-+ * in one go.
-+ * But those statistics can get used to predict how many bytes
-+ * to read together with the can header (which is fixed to 8 at
-+ * this very moment.
-+ *
-+ * notes on the rational here:
-+ * * Reading just the CAN header info takes:
-+ *   * bytes read
-+ *     *  2 bytes command+address
-+ *     * 12 bytes data (id, flags, timestamp)
-+ *   * so that is at the very least 112 SCK (= 14 byte * 8 SCK/1 byte)
-+ *     - on a Raspberry pi 3 for such short requests actually
-+ *       126 SCK (=14 byte * 9 SCK/1 byte)
-+ *   * some SPI framework overhead which is observed to be 5-10 us
-+ *     on a raspberry pi 3 (time between SCK and stop SCK start)
-+ *   * with an effective 17.85 MHz SPI clock on a RPI it takes in total:
-+ *     it takes 12us = 6us + 6us
-+ * * now reading 8 bytes of CAN data (can2.0) takes:
-+ *   * bytes read
-+ *     *  2 bytes command+address
-+ *     *  8 bytes data
-+ *   * so that is at the very least 80 SCK (= 10 byte * 8 SCK/1 byte)
-+ *     - on a Raspberry pi 3 for such short requests actually
-+ *       90 SCK (= 10 byte * 9 SCK/1 byte)
-+ *   * some SPI framework overhead which is observed to be 5-10 us
-+ *     on a raspberry pi 3 (time between SCK and stop SCK start)
-+ *   * with an effective 17.85 MHz SPI clock on a RPI it takes in total:
-+ *     it takes 11us = 5.0us + 6us
-+ * * now reading CAN header plus 8 bytes of CAN data (can2.0) takes:
-+ *   * bytes read
-+ *     *  2 bytes command+address
-+ *     * 20 bytes data
-+ *   * so that is at the very least 176 SCK (= 22 byte * 8 SCK/1 byte)
-+ *     - on a Raspberry pi 3 for such short requests actually
-+ *       198 SCK (= 22 byte * 9 SCK/1 byte)
-+ *   * some SPI framework overhead which is observed to be 5-10 us
-+ *     on a raspberry pi 3 (time between SCK and stop SCK start)
-+ *   * with an effective 17.85 MHz SPI clock on a RPI it takes in total:
-+ *     it takes 17.1us = 11.1us + 6us
-+ *   * this is faster than the 2 individual SPI transfers for header
-+ *     and data which is in total 23us
-+ *     * this is even true for the case where we only have a single
-+ *       data byte (DLC=1) - the time here is 19.5us on a RPI3
-+ *     * the only time where we are less efficient is for the DLC=0 case.
-+ *       but the assumption here is that this is a rare case
-+ * To put it into perspective here the full table for a RPI3:
-+ * LE 2m  pr0 pr1 pr2 pr3 pr4 pr5  pr6  pr7  pr8 pr12 pr16 pr20 pr24 pr32 pr48
-+ *                                                                         pr64
-+ *  0  7.1 7.1
-+ *  1 14.6    7.6 8.1 8.6 9.1 9.6 10.1 10.6 11.1 13.1
-+ *  2 15.1        8.1 8.6 9.1 9.6 10.1 10.6 11.1 13.1
-+ *  3 15.6            8.6 9.1 9.6 10.1 10.6 11.1 13.1 15.1
-+ *  4 16.1                9.1 9.6 10.1 10.6 11.1 13.1 15.1
-+ *  5 16.6                    9.6 10.1 10.6 11.1 13.1 15.1
-+ *  6 17.1                        10.1 10.6 11.1 13.1 15.1
-+ *  7 17.6                             10.6 11.1 13.1 15.1 17.1
-+ *  8 18.1                                  11.1 13.1 15.1 17.1
-+ * 12 20.1                                       13.1 15.1 17.1 19.2
-+ * 16 22.1                                            15.1 17.1 19.2
-+ * 20 24.1                                                 17.1 19.2 23.2
-+ * 24 26.2                                                      19.2 23.2
-+ * 32 30.2                                                           23.2
-+ * 48 38.3                                                                31.3
-+ * 64 46.3                                                                 39.3
-+ * (Parameters: SPI Clock=17.8MHz, SCK/byte=9, overhead=6us)
-+ * Legend:
-+ *   LE = length,
-+ *   2m    = 2 SPI messages (header+data - except for LEN=0, only header)
-+ *  prX/pX = prefecth length times (only shown when < 2m and Len >= Prefetch)
-+ *
-+ * The diagonal schows the "optimal" time when the size of the Can frame would
-+ * be known ahead of time - i.e if it would be possible to define RX reception
-+ * filters based on can DLC values
-+ *
-+ * So for any Can frame except for LEN=0 the prefetch data solution is
-+ * better for prefetch of data=12 for CanFD.
-+ *
-+ * Here another table showing the optimal prefetch limits for SPI speeds
-+ * vs overhead_us at 8 or 9 SCLK/byte
-+ *
-+ * MHZ  2us@8   2us@9   4us@8   4us@9   6us@8   6us@9   8us@8   8us@9
-+ * 10.0 8b***   8b***   8b      8b*     12b**   8b*     12b     12b*
-+ * 12.5 8b**    8b***   12b***  8b      12b     12b*    16b*    16b**
-+ * 15.0 8b**    8b**    12b**   12b***  16b**   12b     20b**   16b
-+ * 17.5 8b*     8b*     12b*    12b**   16b     16b**   20b     20b**
-+ * 20.0 8b      8b*     16b***  12b*    20b**   16b     24b*    20b
-+ * (a * signifies not a full match, but for any length > count(*))
-+ *
-+ * So 8 bytes prefetch seems to be a very good tradeoff for can frame
-+ * except for DLC/LEN=0 frames.
-+ * The question here is mainly: how many frames do we have with DLC=0
-+ * vs all others.
-+ *
-+ * With some statistics of recent CAN frames this may be set dynamically
-+ * in the future.
-+ *
-+ * For this to work efficiently we would also need an estimate on
-+ * the SPI framework overhead, which is a function of the spi-bus-driver
-+ * implementation details, CPU type and speed as well as system load.
-+ * Also the effective SPI-clock speed is needed as well as the
-+ * number of spi clock cycles it takes for a single byte to get transferred
-+ * The bcm283x SOC for example pauses the SPI clock one cycle after
-+ * every byte it sends unless the data is fed to the controller by DMA.
-+ * (but for short transfers DMA mapping is very expensive and not worth
-+ * the effort. PIO and - in some situations - polling is used instead to
-+ * reduce the number of interrupts and the need for thread scheduling as
-+ * much as possible)
-+ *
-+ * This also means that for can2.0 only configured interfaces
-+ * reading multiple rx fifos is a realistic option of optimization
-+ */
-+
-+static int mcp25xxfd_can_rx_read_single_frames(struct mcp25xxfd_can_priv *cpriv,
-+					       int prefetch)
-+{
-+	int i, f, ret;
-+
-+	/* loop all frames */
-+	for (i = 0, f = cpriv->fifos.rx.start; i < cpriv->fifos.rx.count;
-+	     i++, f++) {
-+		if (cpriv->status.rxif & BIT(f)) {
-+			/* read the frame */
-+			ret = mcp25xxfd_can_rx_read_frame(cpriv, f,
-+							  prefetch, true);
-+			if (ret)
-+				return ret;
-+		}
-+	}
-+
-+	return 0;
-+}
-+
-+static int mcp25xxfd_can_rx_read_bulk_frames(struct mcp25xxfd_can_priv *cpriv)
-+{
-+	int i, start, end;
-+	int ret;
-+
-+	/* iterate over fifos trying to find fifos next to each other */
-+	for (i = 0, start = cpriv->fifos.rx.start, end = start;
-+	     i < cpriv->fifos.rx.count; i++, end++, start = end) {
-+		/* if bit is not set then continue */
-+		if (!(cpriv->status.rxif & BIT(start)))
-+			continue;
-+		/* find the last fifo with a bit set in sequence */
-+		for (end = start; cpriv->status.rxif & BIT(end + 1); end++)
-+			;
-+		/* and now read those fifos in bulk */
-+		ret = mcp25xxfd_can_read_rx_frame_bulk(cpriv, start, end);
-+		if (ret)
-+			return ret;
-+	}
-+
-+	return 0;
-+}
-+
-+static int mcp25xxfd_can_rx_read_fd_frames(struct mcp25xxfd_can_priv *cpriv)
-+{
-+	int i, count_dlc15, count_brs, prefetch;
-+
-+	/* get a prediction on prefetch */
-+	prefetch = mcp25xxfd_can_rx_predict_prefetch(cpriv);
-+
-+	/* if the prefetch is < 64 then just read single */
-+	if (prefetch < 64)
-+		return mcp25xxfd_can_rx_read_single_frames(cpriv, prefetch);
-+
-+	/* check if we have mostly brs frames of those DLC=15 frames */
-+	for (i = 0, count_brs = 0, count_dlc15 = 0;
-+	     i < MCP25XXFD_CAN_RX_DLC_HISTORY_SIZE; i++)
-+		if (cpriv->rx_history.dlc[i] == 15) {
-+			count_dlc15++;
-+			if (cpriv->rx_history.brs[i])
-+				count_brs++;
-+		}
-+
-+	/* if we have at least 33% brs frames then run bulk */
-+	if (count_brs * 3 >= count_dlc15 )
-+		return mcp25xxfd_can_rx_read_bulk_frames(cpriv);
-+	else
-+		return mcp25xxfd_can_rx_read_single_frames(cpriv, prefetch);
-+}
-+
-+static int mcp25xxfd_can_rx_read_frames(struct mcp25xxfd_can_priv *cpriv)
-+{
-+	if (cpriv->can.dev->mtu == CANFD_MTU)
-+		return mcp25xxfd_can_rx_read_fd_frames(cpriv);
-+	else
-+		return mcp25xxfd_can_rx_read_bulk_frames(cpriv);
-+}
-+
-+int mcp25xxfd_can_rx_handle_int_rxif(struct mcp25xxfd_can_priv *cpriv)
-+{
-+	if (!cpriv->status.rxif)
-+		return 0;
-+
-+	MCP25XXFD_DEBUGFS_STATS_INCR(cpriv, int_rx_count);
-+
-+	/* read all the fifos */
-+	return mcp25xxfd_can_rx_read_frames(cpriv);
-+}
-+
-+int mcp25xxfd_can_rx_handle_int_rxovif(struct mcp25xxfd_can_priv *cpriv)
-+{
-+	u32 mask = MCP25XXFD_CAN_FIFOSTA_RXOVIF;
-+	int ret, i, reg;
-+
-+	if (!cpriv->status.rxovif)
-+		return 0;
-+
-+	MCP25XXFD_DEBUGFS_STATS_INCR(cpriv, int_rxov_count);
-+
-+	/* clear all fifos that have an overflow bit set */
-+	for (i = 0; i < 32; i++) {
-+		if (cpriv->status.rxovif & BIT(i)) {
-+			/* clear fifo status */
-+			reg = MCP25XXFD_CAN_FIFOSTA(i);
-+			ret = mcp25xxfd_cmd_write_mask(cpriv->priv->spi,
-+						       reg, 0, mask);
-+			if (ret)
-+				return ret;
-+
-+			/* update statistics */
-+			cpriv->can.dev->stats.rx_over_errors++;
-+			cpriv->can.dev->stats.rx_errors++;
-+
-+			/* and prepare ERROR FRAME */
-+			cpriv->error_frame.id |= CAN_ERR_CRTL;
-+			cpriv->error_frame.data[1] |=
-+				CAN_ERR_CRTL_RX_OVERFLOW;
-+		}
-+	}
-+
-+	return 0;
-+}
-diff --git a/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_rx.h b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_rx.h
-new file mode 100644
-index 000000000000..71953e2f3615
---- /dev/null
-+++ b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_rx.h
-@@ -0,0 +1,18 @@
-+/* SPDX-License-Identifier: GPL-2.0 */
-+
-+/* CAN bus driver for Microchip 25XXFD CAN Controller with SPI Interface
-+ *
-+ * Copyright 2019 Martin Sperl <kernel@martin.sperl.org>
-+ */
-+
-+#ifndef __MCP25XXFD_CAN_RX_H
-+#define __MCP25XXFD_CAN_RX_H
-+
-+#include "mcp25xxfd_priv.h"
-+
-+int mcp25xxfd_can_rx_submit_frame(struct mcp25xxfd_can_priv *cpriv, int fifo);
-+
-+int mcp25xxfd_can_rx_handle_int_rxif(struct mcp25xxfd_can_priv *cpriv);
-+int mcp25xxfd_can_rx_handle_int_rxovif(struct mcp25xxfd_can_priv *cpriv);
-+
-+#endif /* __MCP25XXFD_CAN_RX_H */
-diff --git a/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_tx.c b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_tx.c
-new file mode 100644
-index 000000000000..13cb898247fe
---- /dev/null
-+++ b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_tx.c
-@@ -0,0 +1,794 @@
-+// SPDX-License-Identifier: GPL-2.0
-+
-+/* CAN bus driver for Microchip 25XXFD CAN Controller with SPI Interface
-+ *
-+ * Copyright 2019 Martin Sperl <kernel@martin.sperl.org>
-+ *
-+ * Based on Microchip MCP251x CAN controller driver written by
-+ * David Vrabel, Copyright 2006 Arcom Control Systems Ltd.
-+ */
-+
-+#include <linux/can/core.h>
-+#include <linux/can/dev.h>
-+#include <linux/device.h>
-+#include <linux/kernel.h>
-+#include <linux/list.h>
-+#include <linux/netdevice.h>
-+#include <linux/slab.h>
-+#include <linux/spi/spi.h>
-+
-+#include "mcp25xxfd_can.h"
-+#include "mcp25xxfd_can_id.h"
-+#include "mcp25xxfd_can_tx.h"
-+#include "mcp25xxfd_cmd.h"
-+#include "mcp25xxfd_regs.h"
-+
-+/* mostly bit manipulations to move between stages */
-+static struct mcp25xxfd_tx_spi_message *
-+mcp25xxfd_can_tx_queue_first_spi_message(struct mcp25xxfd_tx_spi_message_queue *
-+					 queue, u32 *bitmap)
-+{
-+	u32 first = ffs(*bitmap);
-+
-+	if (!first)
-+		return NULL;
-+
-+	return queue->fifo2message[first - 1];
-+}
-+
-+static void mcp25xxfd_can_tx_queue_remove_spi_message(u32 *bitmap, int fifo)
-+{
-+	*bitmap &= ~BIT(fifo);
-+}
-+
-+static void mcp25xxfd_can_tx_queue_add_spi_message(u32 *bitmap, int fifo)
-+{
-+	*bitmap |= BIT(fifo);
-+}
-+
-+static void mcp25xxfd_can_tx_queue_move_spi_message(u32 *src, u32 *dest,
-+						    int fifo)
-+{
-+	mcp25xxfd_can_tx_queue_remove_spi_message(src, fifo);
-+	mcp25xxfd_can_tx_queue_add_spi_message(dest, fifo);
-+}
-+
-+static void mcp25xxfd_can_tx_spi_message_fill_fifo_complete(void *context)
-+{
-+	struct mcp25xxfd_tx_spi_message *msg = context;
-+	struct mcp25xxfd_can_priv *cpriv = msg->cpriv;
-+	struct mcp25xxfd_tx_spi_message_queue *q = cpriv->fifos.tx_queue;
-+	unsigned long flags;
-+
-+	/* reset transfer length to without data (DLC = 0) */
-+	msg->fill_fifo.xfer.len = sizeof(msg->fill_fifo.data.cmd) +
-+		sizeof(msg->fill_fifo.data.header);
-+
-+	/* we need to hold this lock to protect us from
-+	 * concurrent access by start_xmit
-+	 */
-+	spin_lock_irqsave(&cpriv->fifos.tx_queue->lock, flags);
-+
-+	/* move to in_trigger_fifo_transfer */
-+	mcp25xxfd_can_tx_queue_move_spi_message(&q->in_fill_fifo_transfer,
-+						&q->in_trigger_fifo_transfer,
-+						msg->fifo);
-+
-+	spin_unlock_irqrestore(&cpriv->fifos.tx_queue->lock, flags);
-+}
-+
-+static void mcp25xxfd_can_tx_spi_message_trigger_fifo_complete(void *context)
-+{
-+	struct mcp25xxfd_tx_spi_message *msg = context;
-+	struct mcp25xxfd_can_priv *cpriv = msg->cpriv;
-+	struct mcp25xxfd_tx_spi_message_queue *q = cpriv->fifos.tx_queue;
-+	unsigned long flags;
-+
-+	/* we need to hold this lock to protect us from
-+	 * concurrent access by the interrupt thread
-+	 */
-+	spin_lock_irqsave(&cpriv->fifos.tx_queue->lock, flags);
-+
-+	/* move to can_transfer */
-+	mcp25xxfd_can_tx_queue_move_spi_message(&q->in_trigger_fifo_transfer,
-+						&q->in_can_transfer,
-+						msg->fifo);
-+
-+	spin_unlock_irqrestore(&cpriv->fifos.tx_queue->lock, flags);
-+}
-+
-+static
-+void mcp25xxfd_can_tx_message_init(struct mcp25xxfd_can_priv *cpriv,
-+				   struct mcp25xxfd_tx_spi_message *msg,
-+				   int fifo)
-+{
-+	const u32 trigger = MCP25XXFD_CAN_FIFOCON_TXREQ |
-+		MCP25XXFD_CAN_FIFOCON_UINC;
-+	const int first_byte = mcp25xxfd_cmd_first_byte(trigger);
-+	u32 addr;
-+
-+	/* and initialize the structure */
-+	msg->cpriv = cpriv;
-+	msg->fifo = fifo;
-+
-+	/* init fill_fifo */
-+	spi_message_init(&msg->fill_fifo.msg);
-+	msg->fill_fifo.msg.complete =
-+		mcp25xxfd_can_tx_spi_message_fill_fifo_complete;
-+	msg->fill_fifo.msg.context = msg;
-+
-+	msg->fill_fifo.xfer.speed_hz = cpriv->priv->spi_use_speed_hz;
-+	msg->fill_fifo.xfer.tx_buf = msg->fill_fifo.data.cmd;
-+	msg->fill_fifo.xfer.len = sizeof(msg->fill_fifo.data.cmd) +
-+		sizeof(msg->fill_fifo.data.header);
-+	spi_message_add_tail(&msg->fill_fifo.xfer, &msg->fill_fifo.msg);
-+
-+	addr = MCP25XXFD_SRAM_ADDR(cpriv->fifos.info[fifo].offset);
-+	mcp25xxfd_cmd_calc(MCP25XXFD_INSTRUCTION_WRITE, addr,
-+			   msg->fill_fifo.data.cmd);
-+
-+	/* init trigger_fifo */
-+	spi_message_init(&msg->trigger_fifo.msg);
-+	msg->trigger_fifo.msg.complete =
-+		mcp25xxfd_can_tx_spi_message_trigger_fifo_complete;
-+	msg->trigger_fifo.msg.context = msg;
-+
-+	msg->trigger_fifo.xfer.speed_hz = cpriv->priv->spi_use_speed_hz;
-+	msg->trigger_fifo.xfer.tx_buf = msg->trigger_fifo.data.cmd;
-+	msg->trigger_fifo.xfer.len = sizeof(msg->trigger_fifo.data.cmd) +
-+		sizeof(msg->trigger_fifo.data.data);
-+	spi_message_add_tail(&msg->trigger_fifo.xfer, &msg->trigger_fifo.msg);
-+
-+	mcp25xxfd_cmd_calc(MCP25XXFD_INSTRUCTION_WRITE,
-+			   MCP25XXFD_CAN_FIFOCON(fifo) + first_byte,
-+			   msg->trigger_fifo.data.cmd);
-+	msg->trigger_fifo.data.data = trigger >> (8 * first_byte);
-+
-+	/* and add to idle tx transfers */
-+	mcp25xxfd_can_tx_queue_add_spi_message(&cpriv->fifos.tx_queue->idle,
-+					       fifo);
-+}
-+
-+static
-+void mcp25xxfd_can_tx_queue_manage_nolock(struct mcp25xxfd_can_priv *cpriv,
-+					  int state)
-+{
-+	struct net_device *net = cpriv->can.dev;
-+
-+	/* skip early */
-+	if (state == cpriv->fifos.tx_queue->state)
-+		return;
-+
-+	/* start/stop netif_queue if necessary */
-+	switch (cpriv->fifos.tx_queue->state) {
-+	case MCP25XXFD_CAN_TX_QUEUE_STATE_RUNABLE:
-+		switch (state) {
-+		case MCP25XXFD_CAN_TX_QUEUE_STATE_RESTART:
-+		case MCP25XXFD_CAN_TX_QUEUE_STATE_STARTED:
-+			netif_wake_queue(net);
-+			cpriv->fifos.tx_queue->state =
-+				MCP25XXFD_CAN_TX_QUEUE_STATE_STARTED;
-+			break;
-+		}
-+		break;
-+	case MCP25XXFD_CAN_TX_QUEUE_STATE_STOPPED:
-+		switch (state) {
-+		case MCP25XXFD_CAN_TX_QUEUE_STATE_STARTED:
-+			netif_wake_queue(net);
-+			cpriv->fifos.tx_queue->state = state;
-+			break;
-+		}
-+		break;
-+	case MCP25XXFD_CAN_TX_QUEUE_STATE_STARTED:
-+		switch (state) {
-+		case MCP25XXFD_CAN_TX_QUEUE_STATE_RUNABLE:
-+		case MCP25XXFD_CAN_TX_QUEUE_STATE_STOPPED:
-+			netif_stop_queue(net);
-+			cpriv->fifos.tx_queue->state = state;
-+			break;
-+		}
-+		break;
-+	default:
-+		WARN(true, "Unsupported tx_queue state: %i\n",
-+		     cpriv->fifos.tx_queue->state);
-+		break;
-+	}
-+}
-+
-+void mcp25xxfd_can_tx_queue_manage(struct mcp25xxfd_can_priv *cpriv, int state)
-+{
-+	unsigned long flags;
-+
-+	spin_lock_irqsave(&cpriv->fifos.tx_queue->lock, flags);
-+
-+	mcp25xxfd_can_tx_queue_manage_nolock(cpriv, state);
-+
-+	spin_unlock_irqrestore(&cpriv->fifos.tx_queue->lock, flags);
-+}
-+
-+void mcp25xxfd_can_tx_queue_restart(struct mcp25xxfd_can_priv *cpriv)
-+{
-+	u32 state = MCP25XXFD_CAN_TX_QUEUE_STATE_RESTART;
-+	unsigned long flags;
-+	u32 mask;
-+
-+	spin_lock_irqsave(&cpriv->fifos.tx_queue->lock, flags);
-+
-+	/* only move if there is nothing pending or idle */
-+	mask = cpriv->fifos.tx_queue->idle |
-+		cpriv->fifos.tx_queue->in_fill_fifo_transfer |
-+		cpriv->fifos.tx_queue->in_trigger_fifo_transfer |
-+		cpriv->fifos.tx_queue->in_can_transfer;
-+	if (mask)
-+		goto out;
-+
-+	/* move all items from transferred to idle */
-+	cpriv->fifos.tx_queue->idle |= cpriv->fifos.tx_queue->transferred;
-+	cpriv->fifos.tx_queue->transferred = 0;
-+
-+	/* and enable queue */
-+	mcp25xxfd_can_tx_queue_manage_nolock(cpriv, state);
-+out:
-+	spin_unlock_irqrestore(&cpriv->fifos.tx_queue->lock, flags);
-+}
-+
-+static
-+int mcp25xxfd_can_tx_tef_read(struct mcp25xxfd_can_priv *cpriv,
-+			      int start, int count)
-+{
-+	u32 tef_offset = start * cpriv->fifos.tef.size;
-+	struct mcp25xxfd_can_obj_tef *tef =
-+		(struct mcp25xxfd_can_obj_tef *)(cpriv->sram + tef_offset);
-+	int last, read, ret;
-+
-+	/* compute how many we can read in one go */
-+	last = start + count;
-+	read = (last > cpriv->fifos.tef.count) ?
-+		(cpriv->fifos.tef.count - start) :
-+		count;
-+
-+	/* and read it */
-+	ret = mcp25xxfd_cmd_read_regs(cpriv->priv->spi,
-+				      MCP25XXFD_SRAM_ADDR(tef_offset),
-+				      &tef->id, sizeof(*tef) * read);
-+	if (ret)
-+		return ret;
-+
-+	/* and read a second part on wrap */
-+	if (read != count) {
-+		/* update stats */
-+		MCP25XXFD_DEBUGFS_STATS_INCR(cpriv, tef_read_splits);
-+		/* compute the addresses  */
-+		read = count - read;
-+		tef = (struct mcp25xxfd_can_obj_tef *)(cpriv->sram);
-+		/* and read again */
-+		ret = mcp25xxfd_cmd_read_regs(cpriv->priv->spi,
-+					      MCP25XXFD_SRAM_ADDR(0),
-+					      &tef->id,
-+					      sizeof(*tef) * read);
-+	}
-+
-+	return ret;
-+}
-+
-+static
-+int mcp25xxfd_can_tx_handle_int_tefif_fifo(struct mcp25xxfd_can_priv *cpriv,
-+					   bool read_data)
-+{
-+	u32 tef_offset = cpriv->fifos.tef.index * cpriv->fifos.tef.size;
-+	struct mcp25xxfd_can_obj_tef *tef =
-+		(struct mcp25xxfd_can_obj_tef *)(cpriv->sram + tef_offset);
-+	int fifo, ret;
-+	unsigned long flags;
-+
-+	/* read the next TEF entry to get the transmit timestamp and fifo */
-+	if (read_data) {
-+		ret = mcp25xxfd_can_tx_tef_read(cpriv,
-+						cpriv->fifos.tef.index, 1);
-+		if (ret)
-+			return ret;
-+	}
-+
-+	/* get the fifo from tef */
-+	fifo = (tef->flags & MCP25XXFD_CAN_OBJ_FLAGS_SEQ_MASK) >>
-+		MCP25XXFD_CAN_OBJ_FLAGS_SEQ_SHIFT;
-+
-+	/* check that the fifo is valid */
-+	spin_lock_irqsave(&cpriv->fifos.tx_queue->lock, flags);
-+	if ((cpriv->fifos.tx_queue->in_can_transfer & BIT(fifo)) == 0)
-+		netdev_err(cpriv->can.dev,
-+			   "tefif: fifo %i not pending - tef data: id: %08x flags: %08x, ts: %08x - this may be a problem with spi signal quality- try reducing spi-clock speed if this can get reproduced",
-+			   fifo, tef->id, tef->flags, tef->ts);
-+	spin_unlock_irqrestore(&cpriv->fifos.tx_queue->lock, flags);
-+
-+	/* update stats */
-+	MCP25XXFD_DEBUGFS_STATS_INCR(cpriv, tef_reads);
-+
-+	/* now we can schedule the fifo for echo submission */
-+	mcp25xxfd_can_queue_frame(cpriv, fifo, tef->ts, false);
-+
-+	/* increment the tef index with wraparround */
-+	cpriv->fifos.tef.index++;
-+	if (cpriv->fifos.tef.index >= cpriv->fifos.tef.count)
-+		cpriv->fifos.tef.index = 0;
-+
-+	/* finally just increment the TEF pointer */
-+	return mcp25xxfd_cmd_write_mask(cpriv->priv->spi, MCP25XXFD_CAN_TEFCON,
-+					MCP25XXFD_CAN_TEFCON_UINC,
-+					MCP25XXFD_CAN_TEFCON_UINC);
-+}
-+
-+/* reading TEF entries can be made even more efficient by reading
-+ * multiple TEF entries in one go.
-+ * Under the assumption that we have count(TEF) >= count(TX_FIFO)
-+ * we can even release TEFs early (before we read them)
-+ * (and potentially restarting the transmit-queue early aswell)
-+ */
-+
-+static int
-+mcp25xxfd_can_tx_handle_int_tefif_conservative(struct mcp25xxfd_can_priv *cpriv)
-+{
-+	u32 tefsta;
-+	int ret;
-+
-+	/* read the TEF status */
-+	ret = mcp25xxfd_cmd_read_mask(cpriv->priv->spi, MCP25XXFD_CAN_TEFSTA,
-+				      &tefsta, MCP25XXFD_CAN_TEFSTA_TEFNEIF);
-+	if (ret)
-+		return ret;
-+
-+	/* read the tef in an inefficient loop */
-+	while (tefsta & MCP25XXFD_CAN_TEFSTA_TEFNEIF) {
-+		/* read one tef */
-+		ret = mcp25xxfd_can_tx_handle_int_tefif_fifo(cpriv, true);
-+		if (ret)
-+			return ret;
-+
-+		MCP25XXFD_DEBUGFS_STATS_INCR(cpriv, tef_conservative_reads);
-+
-+		/* read the TEF status */
-+		ret = mcp25xxfd_cmd_read_mask(cpriv->priv->spi,
-+					      MCP25XXFD_CAN_TEFSTA, &tefsta,
-+					      MCP25XXFD_CAN_TEFSTA_TEFNEIF);
-+		if (ret)
-+			return ret;
-+	}
-+
-+	return 0;
-+}
-+
-+static int
-+mcp25xxfd_can_tx_handle_int_tefif_optimized(struct mcp25xxfd_can_priv *cpriv,
-+					    u32 finished)
-+{
-+	int i, fifo, count, ret;
-+
-+	/* count the number of fifos that have terminated */
-+	for (i = 0, fifo = cpriv->fifos.tx.start, count = 0;
-+	     i < cpriv->fifos.tx.count; i++, fifo++)
-+		if (finished & BIT(fifo))
-+			count++;
-+
-+	/* read them in one go if possible
-+	 * we also assume that we have count(TEF) >= count(TX-FIFOS)
-+	 * this may require 2 reads when we wrap arround
-+	 * (that is unless count(TEF) == count(TX-FIFOS))
-+	 */
-+	ret = mcp25xxfd_can_tx_tef_read(cpriv, cpriv->fifos.tef.index, count);
-+	if (ret)
-+		return ret;
-+
-+	/* update stats */
-+	MCP25XXFD_DEBUGFS_STATS_INCR(cpriv, tef_optimized_reads);
-+	i = min_t(int, MCP25XXFD_CAN_TEF_READ_BINS - 1, count - 1);
-+	MCP25XXFD_DEBUGFS_STATS_INCR(cpriv, tef_optimized_read_sizes[i]);
-+
-+	/* now iterate those */
-+	for (i = 0, fifo = cpriv->fifos.tx.start; i < cpriv->fifos.tx.count;
-+	     i++, fifo++) {
-+		if (finished & BIT(fifo)) {
-+			ret = mcp25xxfd_can_tx_handle_int_tefif_fifo(cpriv,
-+								     false);
-+			if (ret)
-+				return ret;
-+		}
-+	}
-+
-+	return 0;
-+}
-+
-+int mcp25xxfd_can_tx_handle_int_tefif(struct mcp25xxfd_can_priv *cpriv)
-+{
-+	unsigned long flags;
-+	u32 finished;
-+
-+	if (!(cpriv->status.intf & MCP25XXFD_CAN_INT_TEFIF))
-+		return 0;
-+
-+	MCP25XXFD_DEBUGFS_STATS_INCR(cpriv, int_tef_count);
-+
-+	spin_lock_irqsave(&cpriv->fifos.tx_queue->lock, flags);
-+
-+	/* compute finished fifos and clear them immediately */
-+	finished = (cpriv->fifos.tx_queue->in_can_transfer ^
-+		    cpriv->status.txreq) &
-+		cpriv->fifos.tx_queue->in_can_transfer;
-+
-+	spin_unlock_irqrestore(&cpriv->fifos.tx_queue->lock, flags);
-+
-+	/* run in optimized mode if possible */
-+	if (finished)
-+		return mcp25xxfd_can_tx_handle_int_tefif_optimized(cpriv,
-+								   finished);
-+	/* otherwise play it safe */
-+	netdev_warn(cpriv->can.dev,
-+		    "Something is wrong - we got a TEF interrupt but we were not able to detect a finished fifo\n");
-+	return mcp25xxfd_can_tx_handle_int_tefif_conservative(cpriv);
-+}
-+
-+static
-+void mcp25xxfd_can_tx_fill_fifo_common(struct mcp25xxfd_can_priv *cpriv,
-+				       struct mcp25xxfd_tx_spi_message *smsg,
-+				       struct mcp25xxfd_can_obj_tx *tx,
-+				       int dlc, u8 *data)
-+{
-+	int len = can_dlc2len(dlc);
-+
-+	/* update statistics */
-+	MCP25XXFD_DEBUGFS_INCR(cpriv->fifos.tx.dlc_usage[dlc]);
-+	MCP25XXFD_DEBUGFS_INCR(cpriv->fifos.info[smsg->fifo].use_count);
-+
-+	/* add fifo number as seq */
-+	tx->flags |= smsg->fifo << MCP25XXFD_CAN_OBJ_FLAGS_SEQ_SHIFT;
-+
-+	/* copy data to tx->data for future reference */
-+	memcpy(tx->data, data, len);
-+
-+	/* transform header to controller format */
-+	mcp25xxfd_cmd_convert_from_cpu(&tx->id, sizeof(*tx) / sizeof(u32));
-+
-+	/* copy header + data to final location - we are not aligned */
-+	memcpy(smsg->fill_fifo.data.header, &tx->id, sizeof(*tx) + len);
-+
-+	/* transfers to sram should be a multiple of 4 and be zero padded */
-+	for (; len & 3; len++)
-+		*(smsg->fill_fifo.data.header + sizeof(*tx) + len) = 0;
-+
-+	/* convert it back to CPU format */
-+	mcp25xxfd_cmd_convert_to_cpu(&tx->id, sizeof(*tx) / sizeof(u32));
-+
-+	/* set up size of transfer */
-+	smsg->fill_fifo.xfer.len = sizeof(smsg->fill_fifo.data.cmd) +
-+		sizeof(smsg->fill_fifo.data.header) + len;
-+}
-+
-+static
-+void mcp25xxfd_can_tx_fill_fifo_fd(struct mcp25xxfd_can_priv *cpriv,
-+				   struct canfd_frame *frame,
-+				   struct mcp25xxfd_tx_spi_message *smsg,
-+				   struct mcp25xxfd_can_obj_tx *tx)
-+{
-+	int dlc = can_len2dlc(frame->len);
-+
-+	/* update some statistics */
-+	MCP25XXFD_DEBUGFS_STATS_INCR(cpriv, tx_fd_count);
-+
-+	/* compute can id */
-+	mcp25xxfd_can_id_to_mcp25xxfd(frame->can_id, &tx->id, &tx->flags);
-+
-+	/* setup flags */
-+	tx->flags |= dlc << MCP25XXFD_CAN_OBJ_FLAGS_DLC_SHIFT;
-+	tx->flags |= (frame->can_id & CAN_EFF_FLAG) ?
-+		MCP25XXFD_CAN_OBJ_FLAGS_IDE : 0;
-+	tx->flags |= (frame->can_id & CAN_RTR_FLAG) ?
-+		MCP25XXFD_CAN_OBJ_FLAGS_RTR : 0;
-+	if (frame->flags & CANFD_BRS) {
-+		tx->flags |= MCP25XXFD_CAN_OBJ_FLAGS_BRS;
-+		MCP25XXFD_DEBUGFS_STATS_INCR(cpriv, tx_brs_count);
-+	}
-+	tx->flags |= (frame->flags & CANFD_ESI) ?
-+		MCP25XXFD_CAN_OBJ_FLAGS_ESI : 0;
-+	tx->flags |= MCP25XXFD_CAN_OBJ_FLAGS_FDF;
-+
-+	/* and do common processing */
-+	mcp25xxfd_can_tx_fill_fifo_common(cpriv, smsg, tx, dlc, frame->data);
-+}
-+
-+static
-+void mcp25xxfd_can_tx_fill_fifo(struct mcp25xxfd_can_priv *cpriv,
-+				struct can_frame *frame,
-+				struct mcp25xxfd_tx_spi_message *smsg,
-+				struct mcp25xxfd_can_obj_tx *tx)
-+{
-+	/* set frame to valid dlc */
-+	if (frame->can_dlc > 8)
-+		frame->can_dlc = 8;
-+
-+	/* compute can id */
-+	mcp25xxfd_can_id_to_mcp25xxfd(frame->can_id, &tx->id, &tx->flags);
-+
-+	/* setup flags */
-+	tx->flags |= frame->can_dlc << MCP25XXFD_CAN_OBJ_FLAGS_DLC_SHIFT;
-+	tx->flags |= (frame->can_id & CAN_EFF_FLAG) ?
-+		MCP25XXFD_CAN_OBJ_FLAGS_IDE : 0;
-+	tx->flags |= (frame->can_id & CAN_RTR_FLAG) ?
-+		MCP25XXFD_CAN_OBJ_FLAGS_RTR : 0;
-+
-+	/* and do common processing */
-+	mcp25xxfd_can_tx_fill_fifo_common(cpriv, smsg, tx, frame->can_dlc,
-+					  frame->data);
-+}
-+
-+static struct mcp25xxfd_tx_spi_message *
-+mcp25xxfd_can_tx_queue_get_next_fifo(struct mcp25xxfd_can_priv *cpriv)
-+{
-+	u32 state = MCP25XXFD_CAN_TX_QUEUE_STATE_RUNABLE;
-+	struct mcp25xxfd_tx_spi_message_queue *q = cpriv->fifos.tx_queue;
-+	struct mcp25xxfd_tx_spi_message *smsg;
-+	unsigned long flags;
-+
-+	/* we need to hold this lock to protect us against
-+	 * concurrent modifications of cpriv->fifos.tx_queue->idle
-+	 * in the interrupt thread
-+	 */
-+	spin_lock_irqsave(&q->lock, flags);
-+
-+	/* get the first entry from idle */
-+	smsg = mcp25xxfd_can_tx_queue_first_spi_message(q, &q->idle);
-+	if (!smsg)
-+		goto out_busy;
-+
-+	/* and move the fifo to next stage */
-+	mcp25xxfd_can_tx_queue_move_spi_message(&q->idle,
-+						&q->in_fill_fifo_transfer,
-+						smsg->fifo);
-+
-+	/* if queue is empty then stop the network queue immediately */
-+	if (!q->idle)
-+		mcp25xxfd_can_tx_queue_manage_nolock(cpriv, state);
-+out_busy:
-+	spin_unlock_irqrestore(&q->lock, flags);
-+
-+	return smsg;
-+}
-+
-+/* submit the can message to the can-bus */
-+netdev_tx_t mcp25xxfd_can_tx_start_xmit(struct sk_buff *skb,
-+					struct net_device *net)
-+{
-+	u32 state = MCP25XXFD_CAN_TX_QUEUE_STATE_STOPPED;
-+	struct mcp25xxfd_can_priv *cpriv = netdev_priv(net);
-+	struct mcp25xxfd_tx_spi_message_queue *q = cpriv->fifos.tx_queue;
-+	struct mcp25xxfd_priv *priv = cpriv->priv;
-+	struct spi_device *spi = priv->spi;
-+	struct mcp25xxfd_tx_spi_message *smsg;
-+	struct mcp25xxfd_can_obj_tx *tx;
-+	unsigned long flags;
-+	int ret;
-+
-+	/* invalid skb we can ignore */
-+	if (can_dropped_invalid_skb(net, skb))
-+		return NETDEV_TX_OK;
-+
-+	/* acquire lock on spi so that we are are not risking
-+	 * some reordering of spi messages when we are running
-+	 * start_xmit in multiple threads (on multiple cores)
-+	 */
-+	spin_lock_irqsave(&q->spi_lock, flags);
-+
-+	/* get the fifo message structure to process now */
-+	smsg = mcp25xxfd_can_tx_queue_get_next_fifo(cpriv);
-+	if (!smsg)
-+		goto out_busy;
-+
-+	/* compute the fifo in sram */
-+	tx = (struct mcp25xxfd_can_obj_tx *)
-+		(cpriv->sram + cpriv->fifos.info[smsg->fifo].offset);
-+
-+	/* fill in message from skb->data depending on can2.0 or canfd */
-+	if (can_is_canfd_skb(skb))
-+		mcp25xxfd_can_tx_fill_fifo_fd(cpriv,
-+					      (struct canfd_frame *)skb->data,
-+					      smsg, tx);
-+	else
-+		mcp25xxfd_can_tx_fill_fifo(cpriv,
-+					   (struct can_frame *)skb->data,
-+					   smsg, tx);
-+
-+	/* submit the two messages asyncronously
-+	 * the reason why we separate transfers into two spi_messages is:
-+	 *  * because the spi framework (currently) does add a 10us delay
-+	 *    between 2 spi_transfers in a single spi_message when
-+	 *    change_cs is set - 2 consecutive spi messages show a shorter
-+	 *    cs disable phase increasing bus utilization
-+	 *    (code reduction with a fix in spi core would be aprox.50 lines)
-+	 *  * this allows the interrupt handler to start spi messages earlier
-+	 *    so reducing latencies a bit and to allow for better concurrency
-+	 *  * this separation - in the future - may get used to fill fifos
-+	 *    early and reduce the delay on "rollover"
-+	 */
-+	ret = spi_async(spi, &smsg->fill_fifo.msg);
-+	if (ret)
-+		goto out_async_failed;
-+	ret = spi_async(spi, &smsg->trigger_fifo.msg);
-+	if (ret)
-+		goto out_async_failed;
-+
-+	/* unlock the spi bus */
-+	spin_unlock_irqrestore(&q->spi_lock, flags);
-+
-+	/* keep it for reference until the message really got transmitted */
-+	can_put_echo_skb(skb, net, smsg->fifo);
-+
-+	return NETDEV_TX_OK;
-+out_async_failed:
-+	netdev_err(net, "spi_async submission of fifo %i failed - %i\n",
-+		   smsg->fifo, ret);
-+
-+out_busy:
-+	/* stop the queue */
-+	mcp25xxfd_can_tx_queue_manage_nolock(cpriv, state);
-+
-+	spin_unlock_irqrestore(&q->spi_lock, flags);
-+
-+	return NETDEV_TX_BUSY;
-+}
-+
-+/* submit the fifo back to the network stack */
-+int mcp25xxfd_can_tx_submit_frame(struct mcp25xxfd_can_priv *cpriv, int fifo)
-+{
-+	struct mcp25xxfd_tx_spi_message_queue *q = cpriv->fifos.tx_queue;
-+	struct mcp25xxfd_can_obj_tx *tx = (struct mcp25xxfd_can_obj_tx *)
-+		(cpriv->sram + cpriv->fifos.info[fifo].offset);
-+	int dlc = (tx->flags & MCP25XXFD_CAN_OBJ_FLAGS_DLC_MASK) >>
-+		MCP25XXFD_CAN_OBJ_FLAGS_DLC_SHIFT;
-+	unsigned long flags;
-+
-+	/* update counters */
-+	cpriv->can.dev->stats.tx_packets++;
-+	cpriv->can.dev->stats.tx_bytes += can_dlc2len(dlc);
-+	MCP25XXFD_DEBUGFS_INCR(cpriv->fifos.tx.dlc_usage[dlc]);
-+	if (tx->flags & MCP25XXFD_CAN_OBJ_FLAGS_FDF)
-+		MCP25XXFD_DEBUGFS_STATS_INCR(cpriv, tx_fd_count);
-+	if (tx->flags & MCP25XXFD_CAN_OBJ_FLAGS_BRS)
-+		MCP25XXFD_DEBUGFS_STATS_INCR(cpriv, tx_brs_count);
-+
-+	spin_lock_irqsave(&cpriv->fifos.tx_queue->lock, flags);
-+
-+	/* release the echo buffer */
-+	can_get_echo_skb(cpriv->can.dev, fifo);
-+
-+	/* move from in_can_transfer to transferred */
-+	mcp25xxfd_can_tx_queue_move_spi_message(&q->in_can_transfer,
-+						&q->transferred, fifo);
-+
-+	spin_unlock_irqrestore(&cpriv->fifos.tx_queue->lock, flags);
-+
-+	return 0;
-+}
-+
-+/* interrupt handler */
-+int mcp25xxfd_can_tx_handle_int_txatif_fifo(struct mcp25xxfd_can_priv *cpriv,
-+					    int fifo)
-+{
-+	struct mcp25xxfd_tx_spi_message_queue *q = cpriv->fifos.tx_queue;
-+	u32 val;
-+	unsigned long flags;
-+	int ret;
-+
-+	/* read fifo status */
-+	ret = mcp25xxfd_cmd_read(cpriv->priv->spi,
-+				 MCP25XXFD_CAN_FIFOSTA(fifo), &val);
-+	if (ret)
-+		return ret;
-+
-+	/* clear the relevant interrupt flags */
-+	ret = mcp25xxfd_cmd_write_mask(cpriv->priv->spi,
-+				       MCP25XXFD_CAN_FIFOSTA(fifo), 0,
-+				       MCP25XXFD_CAN_FIFOSTA_TXABT |
-+				       MCP25XXFD_CAN_FIFOSTA_TXLARB |
-+				       MCP25XXFD_CAN_FIFOSTA_TXERR |
-+				       MCP25XXFD_CAN_FIFOSTA_TXATIF);
-+	if (ret)
-+		return ret;
-+
-+	spin_lock_irqsave(&q->lock, flags);
-+	/* for specific cases we probably could trigger a retransmit
-+	 * instead of an abort.
-+	 */
-+
-+	/* and we release it from the echo_skb buffer
-+	 * NOTE: this is one place where packet delivery will not
-+	 * be ordered, as we do not have any timing information
-+	 * when this occurred
-+	 */
-+	can_get_echo_skb(cpriv->can.dev, fifo);
-+
-+	mcp25xxfd_can_tx_queue_move_spi_message(&q->in_can_transfer,
-+						&q->transferred, fifo);
-+
-+	spin_unlock_irqrestore(&q->lock, flags);
-+
-+	/* but we need to run a bit of cleanup */
-+	cpriv->status.txif &= ~BIT(fifo);
-+	cpriv->can.dev->stats.tx_aborted_errors++;
-+
-+	/* handle all the known cases accordingly - ignoring FIFO full */
-+	val &= MCP25XXFD_CAN_FIFOSTA_TXABT |
-+		MCP25XXFD_CAN_FIFOSTA_TXLARB |
-+		MCP25XXFD_CAN_FIFOSTA_TXERR;
-+	switch (val) {
-+	case MCP25XXFD_CAN_FIFOSTA_TXERR:
-+		/* this indicates a possible bus error */
-+		break;
-+	default:
-+		dev_warn_ratelimited(&cpriv->priv->spi->dev,
-+				     "Unknown TX-Fifo abort condition: %08x - stopping tx-queue\n",
-+				     val);
-+		break;
-+	}
-+
-+	return 0;
-+}
-+
-+int mcp25xxfd_can_tx_handle_int_txatif(struct mcp25xxfd_can_priv *cpriv)
-+{
-+	int i, f, ret;
-+
-+	/* if txatif is unset, then there are no
-+	 * can frames that have been transmitted
-+	 * and need to get reingested into the network stack
-+	 */
-+	if (!cpriv->status.txatif)
-+		return 0;
-+	MCP25XXFD_DEBUGFS_STATS_INCR(cpriv, int_txat_count);
-+
-+	/* process all the fifos with that flag set */
-+	for (i = 0, f = cpriv->fifos.tx.start; i < cpriv->fifos.tx.count;
-+	     i++, f++) {
-+		if (cpriv->status.txatif & BIT(f)) {
-+			ret = mcp25xxfd_can_tx_handle_int_txatif_fifo(cpriv, f);
-+			if (ret)
-+				return ret;
-+		}
-+	}
-+
-+	return 0;
-+}
-+
-+int mcp25xxfd_can_tx_queue_alloc(struct mcp25xxfd_can_priv *cpriv)
-+{
-+	struct mcp25xxfd_tx_spi_message *msg;
-+	size_t size = sizeof(struct mcp25xxfd_tx_spi_message_queue) +
-+		cpriv->fifos.tx.count * sizeof(*msg);
-+	int i, f;
-+
-+	/* allocate the fifos as an array */
-+	cpriv->fifos.tx_queue = kzalloc(size, GFP_KERNEL);
-+	if (!cpriv->fifos.tx_queue)
-+		return -ENOMEM;
-+
-+	/* initialize the tx_queue structure */
-+	spin_lock_init(&cpriv->fifos.tx_queue->lock);
-+	spin_lock_init(&cpriv->fifos.tx_queue->spi_lock);
-+
-+	/* initialize the individual spi_message structures */
-+	for (i = 0, f = cpriv->fifos.tx.start; i < cpriv->fifos.tx.count;
-+	     i++, f++) {
-+		msg = &cpriv->fifos.tx_queue->message[i];
-+		cpriv->fifos.tx_queue->fifo2message[f] = msg;
-+		mcp25xxfd_can_tx_message_init(cpriv, msg, f);
-+	}
-+
-+	return 0;
-+}
-+
-+void mcp25xxfd_can_tx_queue_free(struct mcp25xxfd_can_priv *cpriv)
-+{
-+	/* eventually we may need to wait here
-+	 * for all transfers to have finished
-+	 */
-+
-+	kfree(cpriv->fifos.tx_queue);
-+	cpriv->fifos.tx_queue = NULL;
-+}
-diff --git a/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_tx.h b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_tx.h
-new file mode 100644
-index 000000000000..1947b3420d58
---- /dev/null
-+++ b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_tx.h
-@@ -0,0 +1,86 @@
-+/* SPDX-License-Identifier: GPL-2.0 */
-+
-+/* CAN bus driver for Microchip 25XXFD CAN Controller with SPI Interface
-+ *
-+ * Copyright 2019 Martin Sperl <kernel@martin.sperl.org>
-+ */
-+
-+#ifndef __MCP25XXFD_CAN_TX_H
-+#define __MCP25XXFD_CAN_TX_H
-+
-+#include <linux/spinlock.h>
-+#include <linux/spi/spi.h>
-+
-+#include "mcp25xxfd_can_priv.h"
-+
-+/* structure of a spi message that is prepared and can get submitted quickly */
-+struct mcp25xxfd_tx_spi_message {
-+	/* the network device this is related to */
-+	struct mcp25xxfd_can_priv *cpriv;
-+	/* the fifo this fills */
-+	u32 fifo;
-+	/* the xfer to fill in the fifo data */
-+	struct {
-+		struct spi_message msg;
-+		struct spi_transfer xfer;
-+		struct {
-+			u8 cmd[2];
-+			u8 header[sizeof(struct mcp25xxfd_can_obj_tx)];
-+			u8 data[64];
-+		} data;
-+	} fill_fifo;
-+	/* the xfer to enable transmission on the can bus */
-+	struct {
-+		struct spi_message msg;
-+		struct spi_transfer xfer;
-+		struct {
-+			u8 cmd[2];
-+			u8 data;
-+		} data;
-+	} trigger_fifo;
-+};
-+
-+struct mcp25xxfd_tx_spi_message_queue {
-+	/* spinlock protecting the bitmaps
-+	 * as well as state and the skb_echo_* functions
-+	 */
-+	spinlock_t lock;
-+	/* bitmap of which fifo is in which stage */
-+	u32 idle;
-+	u32 in_fill_fifo_transfer;
-+	u32 in_trigger_fifo_transfer;
-+	u32 in_can_transfer;
-+	u32 transferred;
-+
-+	/* the queue state as seen per controller */
-+	int state;
-+#define MCP25XXFD_CAN_TX_QUEUE_STATE_STOPPED 0
-+#define MCP25XXFD_CAN_TX_QUEUE_STATE_STARTED 1
-+#define MCP25XXFD_CAN_TX_QUEUE_STATE_RUNABLE 2
-+#define MCP25XXFD_CAN_TX_QUEUE_STATE_RESTART 3
-+
-+	/* spinlock protecting spi submission order */
-+	spinlock_t spi_lock;
-+
-+	/* map each fifo to a mcp25xxfd_tx_spi_message */
-+	struct mcp25xxfd_tx_spi_message *fifo2message[32];
-+
-+	/* the individual messages */
-+	struct mcp25xxfd_tx_spi_message message[];
-+};
-+
-+int mcp25xxfd_can_tx_submit_frame(struct mcp25xxfd_can_priv *cpriv, int fifo);
-+void mcp25xxfd_can_tx_queue_restart(struct mcp25xxfd_can_priv *cpriv);
-+
-+int mcp25xxfd_can_tx_handle_int_txatif(struct mcp25xxfd_can_priv *cpriv);
-+int mcp25xxfd_can_tx_handle_int_tefif(struct mcp25xxfd_can_priv *cpriv);
-+
-+netdev_tx_t mcp25xxfd_can_tx_start_xmit(struct sk_buff *skb,
-+					struct net_device *net);
-+
-+void mcp25xxfd_can_tx_queue_manage(struct mcp25xxfd_can_priv *cpriv, int state);
-+
-+int mcp25xxfd_can_tx_queue_alloc(struct mcp25xxfd_can_priv *cpriv);
-+void mcp25xxfd_can_tx_queue_free(struct mcp25xxfd_can_priv *cpriv);
-+
-+#endif /* __MCP25XXFD_CAN_TX_H */
-diff --git a/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_clock.c b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_clock.c
-new file mode 100644
-index 000000000000..aee482e7c02a
---- /dev/null
-+++ b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_clock.c
-@@ -0,0 +1,485 @@
-+// SPDX-License-Identifier: GPL-2.0
-+
-+/* CAN bus driver for Microchip 25XXFD CAN Controller with SPI Interface
-+ *
-+ * Copyright 2019 Martin Sperl <kernel@martin.sperl.org>
-+ */
-+
-+/* Known hardware issues and workarounds in this driver:
-+ *
-+ * * There is one situation where the controller will require a full POR
-+ *   (total power off) to recover from a bad Clock configuration.
-+ *   This happens when the wrong clock is configured in the device tree
-+ *   (say 4MHz are configured, while 40MHz is the actual clock frequency
-+ *   of the HW).
-+ *   In such a situation the driver tries to enable the PLL, which will
-+ *   never synchronize and the controller becomes unresponsive to further
-+ *   spi requests until a full POR.
-+ *
-+ *   Mitigation:
-+ *     none as of now
-+ *
-+ *   Possible implementation of a mitigation/sanity check:
-+ *     during initialization:
-+ *       * try to identify the HW at 1MHz:
-+ *         on success:
-+ *           * controller is identified
-+ *         on failure:
-+ *           * controller is absent - fail
-+ *       * force controller clock to run with disabled PLL
-+ *       * try to identify the HW at 2MHz:
-+ *         on success:
-+ *           * controller clock is >= 4 MHz
-+ *           * this may be 4MHz
-+ *         on failure:
-+ *           * controller clock is < 4 MHz
-+ *       * try to identify the HW at 2.5MHz:
-+ *         on success:
-+ *           * controller clock is >= 5 MHz
-+ *           * this may not be 4MHz
-+ *         on failure:
-+ *           * controller clock is 4 MHz
-+ *           * enable PLL
-+ *           * exit successfully (or run last test for verification purposes)
-+ *       * try to identify the HW at <dt-clock/2> MHz:
-+ *         on success:
-+ *           * controller clock is >= <dt-clock/2> MHz
-+ *              (it could be higher though)
-+ *         on failure:
-+ *           * the controller is not running at the
-+ *             clock rate configured in the DT
-+ *           * if PLL is enabled warn about requirements of POR
-+ *           * fail
-+ *
-+ *   Side-effects:
-+ *     * longer initialization time
-+ *
-+ *   Possible issues with mitigation:
-+ *     * possibly miss-identification because the SPI block may work
-+ *       "somewhat" at frequencies > < clock / 2 + delta f>
-+ *       this may be especially true for the situation where we test if
-+ *       2.5MHz SPI-Clock works.
-+ *     * also SPI HW-clock dividers may do a round down to fixed frequencies
-+ *       which is not properly reported and may result in false positives
-+ *       because a frequency lower than expected is used.
-+ *
-+ *   This is the reason why only simple testing is enabled at the risk of
-+ *   the need for a POR.
-+ */
-+
-+#include <linux/clk.h>
-+#include <linux/delay.h>
-+#include <linux/jiffies.h>
-+#include <linux/kernel.h>
-+#include <linux/mutex.h>
-+#include <linux/of.h>
-+#include <linux/spi/spi.h>
-+
-+#include "mcp25xxfd_can.h"
-+#include "mcp25xxfd_cmd.h"
-+#include "mcp25xxfd_priv.h"
-+
-+/* the PLL may take some time to synchronize - use 1 second as timeout */
-+#define MCP25XXFD_OSC_POLLING_JIFFIES	(HZ)
-+
-+static u32 _mcp25xxfd_clkout_mask(struct mcp25xxfd_priv *priv)
-+{
-+	u32 val = 0;
-+
-+	if (priv->config.clock_div2)
-+		val |= MCP25XXFD_OSC_SCLKDIV;
-+
-+	switch (priv->config.clock_odiv) {
-+	case 0:
-+		break;
-+	case 1:
-+		val |= MCP25XXFD_OSC_CLKODIV_1 << MCP25XXFD_OSC_CLKODIV_SHIFT;
-+		break;
-+	case 2:
-+		val |= MCP25XXFD_OSC_CLKODIV_2 << MCP25XXFD_OSC_CLKODIV_SHIFT;
-+		break;
-+	case 4:
-+		val |= MCP25XXFD_OSC_CLKODIV_4 << MCP25XXFD_OSC_CLKODIV_SHIFT;
-+		break;
-+	case 10:
-+		val |= MCP25XXFD_OSC_CLKODIV_10 << MCP25XXFD_OSC_CLKODIV_SHIFT;
-+		break;
-+	default:
-+		/* this should never happen but is error-handled
-+		 * by the dt-parsing
-+		 */
-+		break;
-+	}
-+
-+	return val;
-+}
-+
-+static int _mcp25xxfd_waitfor_osc(struct mcp25xxfd_priv *priv,
-+				  u32 waitfor, u32 mask)
-+{
-+	unsigned long timeout;
-+	int ret;
-+
-+	/* wait for synced pll/osc/sclk */
-+	timeout = jiffies + MCP25XXFD_OSC_POLLING_JIFFIES;
-+	while (time_before_eq(jiffies, timeout)) {
-+		ret = mcp25xxfd_cmd_read(priv->spi, MCP25XXFD_OSC,
-+					 &priv->regs.osc);
-+		if (ret)
-+			return ret;
-+		/* check for expected bits to be set/unset */
-+		if ((priv->regs.osc & mask) == waitfor)
-+			return 0;
-+	}
-+
-+	return -ETIMEDOUT;
-+}
-+
-+static int _mcp25xxfd_clock_configure_osc(struct mcp25xxfd_priv *priv,
-+					  u32 value, u32 waitfor, u32 mask)
-+{
-+	int ret;
-+
-+	/* write the osc value to the controller - waking it if necessary */
-+	ret = mcp25xxfd_cmd_write(priv->spi, MCP25XXFD_OSC, value);
-+	if (ret)
-+		return ret;
-+
-+	/* wait for the clock to stabelize */
-+	ret = _mcp25xxfd_waitfor_osc(priv, waitfor, mask);
-+
-+	/* on timeout try again setting the register */
-+	if (ret == -ETIMEDOUT) {
-+		/* write the clock to the controller */
-+		ret = mcp25xxfd_cmd_write(priv->spi, MCP25XXFD_OSC, value);
-+		if (ret)
-+			return ret;
-+
-+		/* wait for the clock to stabelize */
-+		ret = _mcp25xxfd_waitfor_osc(priv, waitfor, mask);
-+	}
-+
-+	/* handle timeout special - report the fact */
-+	if (ret == -ETIMEDOUT)
-+		dev_err(&priv->spi->dev,
-+			"Clock did not switch within the timeout period\n");
-+
-+	return ret;
-+}
-+
-+static int _mcp25xxfd_clock_start(struct mcp25xxfd_priv *priv)
-+{
-+	u32 value = _mcp25xxfd_clkout_mask(priv);
-+	u32 waitfor = MCP25XXFD_OSC_OSCRDY;
-+	u32 mask = waitfor | MCP25XXFD_OSC_OSCDIS | MCP25XXFD_OSC_PLLRDY |
-+		MCP25XXFD_OSC_PLLEN;
-+
-+	/* enable PLL as well - set expectations */
-+	if (priv->config.clock_pll) {
-+		value   |= MCP25XXFD_OSC_PLLEN;
-+		waitfor |= MCP25XXFD_OSC_PLLRDY | MCP25XXFD_OSC_PLLEN;
-+	}
-+
-+	/* set the oscilator now */
-+	return _mcp25xxfd_clock_configure_osc(priv, value, waitfor, mask);
-+}
-+
-+static int _mcp25xxfd_clock_stop(struct mcp25xxfd_priv *priv)
-+{
-+	u32 value = _mcp25xxfd_clkout_mask(priv);
-+	u32 waitfor = 0;
-+	u32 mask = MCP25XXFD_OSC_OSCDIS | MCP25XXFD_OSC_PLLRDY |
-+		MCP25XXFD_OSC_PLLEN;
-+	int ret;
-+
-+	ret = _mcp25xxfd_clock_configure_osc(priv, value, waitfor, mask);
-+	if (ret)
-+		return ret;
-+
-+	/* finally switch the controller mode to sleep
-+	 * by this time the controller should be in config mode already
-+	 * this way we wake to config mode again
-+	 */
-+	return mcp25xxfd_can_sleep_mode(priv);
-+}
-+
-+int mcp25xxfd_clock_start(struct mcp25xxfd_priv *priv, int requestor_mask)
-+{
-+	int ret = 0;
-+
-+	/* without a clock there is nothing we can do... */
-+	if (IS_ERR(priv->clk))
-+		return PTR_ERR(priv->clk);
-+
-+	mutex_lock(&priv->clk_user_lock);
-+
-+	/* if clock is already started, then skip */
-+	if (priv->clk_user_mask & requestor_mask)
-+		goto out;
-+
-+	/* enable the clock on the host side*/
-+	ret = clk_prepare_enable(priv->clk);
-+	if (ret)
-+		goto out;
-+
-+	/* enable the clock on the controller side */
-+	ret = _mcp25xxfd_clock_start(priv);
-+	if (ret)
-+		goto out;
-+
-+	/* mark the clock for the specific component as started */
-+	priv->clk_user_mask |= requestor_mask;
-+
-+	/* and now we use the normal spi speed */
-+	priv->spi_use_speed_hz = priv->spi_normal_speed_hz;
-+
-+out:
-+	mutex_unlock(&priv->clk_user_lock);
-+
-+	return ret;
-+}
-+
-+int mcp25xxfd_clock_stop(struct mcp25xxfd_priv *priv, int requestor_mask)
-+{
-+	int ret;
-+
-+	/* without a clock there is nothing we can do... */
-+	if (IS_ERR(priv->clk))
-+		return PTR_ERR(priv->clk);
-+
-+	mutex_lock(&priv->clk_user_lock);
-+
-+	/* if the mask is empty then skip, as the clock is stopped */
-+	if (!priv->clk_user_mask)
-+		goto out;
-+
-+	/* clear the clock mask */
-+	priv->clk_user_mask &= ~requestor_mask;
-+
-+	/* if the mask is not empty then skip, as the clock is needed */
-+	if (priv->clk_user_mask)
-+		goto out;
-+
-+	/* and now we use the setup spi speed */
-+	priv->spi_use_speed_hz = priv->spi_setup_speed_hz;
-+
-+	/* stop the clock on the controller */
-+	ret = _mcp25xxfd_clock_stop(priv);
-+
-+	/* and we stop the clock on the host*/
-+	if (!IS_ERR(priv->clk))
-+		clk_disable_unprepare(priv->clk);
-+out:
-+	mutex_unlock(&priv->clk_user_lock);
-+
-+	return 0;
-+}
-+
-+static int _mcp25xxfd_clock_probe(struct mcp25xxfd_priv *priv)
-+{
-+	int ret;
-+
-+	/* Wait for oscillator startup timer after power up */
-+	mdelay(MCP25XXFD_OST_DELAY_MS);
-+
-+	/* send a "blind" reset, hoping we are in Config mode */
-+	mcp25xxfd_cmd_reset(priv->spi);
-+
-+	/* Wait for oscillator startup again */
-+	mdelay(MCP25XXFD_OST_DELAY_MS);
-+
-+	/* check clock register that the clock is ready or disabled */
-+	ret = mcp25xxfd_cmd_read(priv->spi, MCP25XXFD_OSC,
-+				 &priv->regs.osc);
-+	if (ret)
-+		return ret;
-+
-+	/* there can only be one... */
-+	switch (priv->regs.osc &
-+		(MCP25XXFD_OSC_OSCRDY | MCP25XXFD_OSC_OSCDIS)) {
-+	case MCP25XXFD_OSC_OSCRDY: /* either the clock is ready */
-+		break;
-+	case MCP25XXFD_OSC_OSCDIS: /* or the clock is disabled */
-+		break;
-+	default:
-+		/* otherwise there is no valid device (or in strange state)
-+		 *
-+		 * if PLL is enabled but not ready, then there may be
-+		 * something "fishy"
-+		 * this happened during driver development
-+		 * (enabling pll, when when on wrong clock), so best warn
-+		 * about such a possibility
-+		 */
-+		if ((priv->regs.osc &
-+		     (MCP25XXFD_OSC_PLLEN | MCP25XXFD_OSC_PLLRDY))
-+		    == MCP25XXFD_OSC_PLLEN)
-+			dev_err(&priv->spi->dev,
-+				"mcp25xxfd may be in a strange state - a power disconnect may be required\n");
-+
-+		return -ENODEV;
-+	}
-+
-+	return 0;
-+}
-+
-+int mcp25xxfd_clock_probe(struct mcp25xxfd_priv *priv)
-+{
-+	int ret;
-+
-+	/* this will also enable the MCP25XXFD_CLK_USER_CAN clock */
-+	ret = _mcp25xxfd_clock_probe(priv);
-+
-+	/* on error retry a second time */
-+	if (ret == -ENODEV) {
-+		ret = _mcp25xxfd_clock_probe(priv);
-+		if (!ret)
-+			dev_info(&priv->spi->dev,
-+				 "found device only during retry\n");
-+	}
-+	if (ret) {
-+		if (ret == -ENODEV)
-+			dev_err(&priv->spi->dev,
-+				"Cannot initialize MCP%x. Wrong wiring? (oscilator register reads as %08x)\n",
-+				priv->model, priv->regs.osc);
-+	}
-+
-+	return ret;
-+}
-+
-+void mcp25xxfd_clock_release(struct mcp25xxfd_priv *priv)
-+{
-+	if (!IS_ERR_OR_NULL(priv->clk))
-+		clk_disable_unprepare(priv->clk);
-+}
-+
-+#ifdef CONFIG_OF_DYNAMIC
-+static int mcp25xxfd_clock_of_parse(struct mcp25xxfd_priv *priv)
-+{
-+	struct spi_device *spi = priv->spi;
-+	const struct device_node *np = spi->dev.of_node;
-+	u32 val;
-+	int ret;
-+
-+	priv->config.clock_div2 = false;
-+	priv->config.clock_div2 =
-+		of_property_read_bool(np, "microchip,clock-div2");
-+
-+	priv->config.clock_odiv = 10;
-+	ret = of_property_read_u32_index(np, "microchip,clock-out-div",
-+					 0, &val);
-+	if (!ret) {
-+		switch (val) {
-+		case 0:
-+		case 1:
-+		case 2:
-+		case 4:
-+		case 10:
-+			priv->config.clock_odiv = val;
-+			break;
-+		default:
-+			dev_err(&spi->dev,
-+				"Invalid value in device tree for microchip,clock_out_div: %u - valid values: 0, 1, 2, 4, 10\n",
-+				val);
-+			return -EINVAL;
-+		}
-+	}
-+
-+	return 0;
-+}
-+#else
-+static int mcp25xxfd_clock_of_parse(struct mcp25xxfd_priv *priv)
-+{
-+	return 0;
-+}
-+#endif
-+
-+int mcp25xxfd_clock_init(struct mcp25xxfd_priv *priv)
-+{
-+	struct spi_device *spi = priv->spi;
-+	struct clk *clk;
-+	int ret, freq;
-+
-+	mutex_init(&priv->clk_user_lock);
-+
-+	priv->config.clock_div2 = false;
-+	priv->config.clock_odiv = 10;
-+
-+	ret = mcp25xxfd_clock_of_parse(priv);
-+	if (ret)
-+		return ret;
-+
-+	/* get clock */
-+	clk = devm_clk_get(&spi->dev, NULL);
-+	if (IS_ERR(clk))
-+		return PTR_ERR(clk);
-+
-+	freq = clk_get_rate(clk);
-+	if (freq < MCP25XXFD_MIN_CLOCK_FREQUENCY ||
-+	    freq > MCP25XXFD_MAX_CLOCK_FREQUENCY) {
-+		dev_err(&spi->dev,
-+			"Clock frequency %i is not in range [%i:%i]\n",
-+			freq,
-+			MCP25XXFD_MIN_CLOCK_FREQUENCY,
-+			MCP25XXFD_MAX_CLOCK_FREQUENCY);
-+		return -ERANGE;
-+	}
-+
-+	/* enable the clock and mark as enabled */
-+	ret = clk_prepare_enable(clk);
-+	if (ret)
-+		return ret;
-+	priv->clk = clk;
-+
-+	/* if we have a clock that is <= 4MHz, enable the pll */
-+	priv->config.clock_pll =
-+		(freq <= MCP25XXFD_AUTO_PLL_MAX_CLOCK_FREQUENCY);
-+
-+	/* decide on the effective clock rate */
-+	priv->clock_freq = freq;
-+	if (priv->config.clock_pll)
-+		priv->clock_freq *= MCP25XXFD_PLL_MULTIPLIER;
-+	if (priv->config.clock_div2)
-+		priv->clock_freq /= MCP25XXFD_SCLK_DIVIDER;
-+
-+	/* calculate the clock frequencies to use
-+	 *
-+	 * setup clock speed is at most 1/4 the input clock speed
-+	 * the reason for the factor of 4 is that there is
-+	 * a clock divider in the controller that MAY be enabled in some
-+	 * circumstances so we may find a controller with that enabled
-+	 * during probe phase
-+	 */
-+	priv->spi_setup_speed_hz = freq / 4;
-+
-+	/* normal operation clock speeds */
-+	priv->spi_normal_speed_hz = priv->clock_freq / 2;
-+	if (priv->config.clock_div2) {
-+		priv->spi_setup_speed_hz /= MCP25XXFD_SCLK_DIVIDER;
-+		priv->spi_normal_speed_hz /= MCP25XXFD_SCLK_DIVIDER;
-+	}
-+
-+	/* set limit on speed */
-+	if (spi->max_speed_hz) {
-+		priv->spi_setup_speed_hz = min_t(int,
-+						 priv->spi_setup_speed_hz,
-+						 spi->max_speed_hz);
-+		priv->spi_normal_speed_hz = min_t(int,
-+						  priv->spi_normal_speed_hz,
-+						  spi->max_speed_hz);
-+	}
-+
-+	/* use setup speed by default
-+	 * - this is switched when clock is enabled/disabled
-+	 */
-+	priv->spi_use_speed_hz = priv->spi_setup_speed_hz;
-+
-+	return 0;
-+}
-+
-+void mcp25xxfd_clock_fake_sleep(struct mcp25xxfd_priv *priv)
-+{
-+	priv->regs.osc &= ~(MCP25XXFD_OSC_OSCRDY |
-+			    MCP25XXFD_OSC_PLLRDY |
-+			    MCP25XXFD_OSC_SCLKRDY);
-+	priv->regs.osc |= MCP25XXFD_OSC_OSCDIS;
-+}
-diff --git a/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_clock.h b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_clock.h
-new file mode 100644
-index 000000000000..049e95cfa9ad
---- /dev/null
-+++ b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_clock.h
-@@ -0,0 +1,28 @@
-+/* SPDX-License-Identifier: GPL-2.0 */
-+
-+/* CAN bus driver for Microchip 25XXFD CAN Controller with SPI Interface
-+ *
-+ * Copyright 2019 Martin Sperl <kernel@martin.sperl.org>
-+ */
-+
-+#ifndef __MCP25XXFD_CLOCK_H
-+#define __MCP25XXFD_CLOCK_H
-+
-+#include "mcp25xxfd_priv.h"
-+
-+#define MCP25XXFD_CLK_USER_CAN BIT(0)
-+#define MCP25XXFD_CLK_USER_GPIO0 BIT(1)
-+#define MCP25XXFD_CLK_USER_GPIO1 BIT(2)
-+#define MCP25XXFD_CLK_USER_CLKOUT BIT(3)
-+
-+/* shared (internal) clock control */
-+int mcp25xxfd_clock_init(struct mcp25xxfd_priv *priv);
-+int mcp25xxfd_clock_probe(struct mcp25xxfd_priv *priv);
-+void mcp25xxfd_clock_release(struct mcp25xxfd_priv *priv);
-+
-+int mcp25xxfd_clock_stop(struct mcp25xxfd_priv *priv, int requestor_mask);
-+int mcp25xxfd_clock_start(struct mcp25xxfd_priv *priv, int requestor_mask);
-+
-+void mcp25xxfd_clock_fake_sleep(struct mcp25xxfd_priv *priv);
-+
-+#endif /* __MCP25XXFD_CLOCK_H */
-diff --git a/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_cmd.c b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_cmd.c
-new file mode 100644
-index 000000000000..0332189b4f07
---- /dev/null
-+++ b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_cmd.c
-@@ -0,0 +1,312 @@
-+// SPDX-License-Identifier: GPL-2.0
-+
-+/* CAN bus driver for Microchip 25XXFD CAN Controller with SPI Interface
-+ *
-+ * Copyright 2019 Martin Sperl <kernel@martin.sperl.org>
-+ */
-+
-+#include <linux/mutex.h>
-+#include <linux/slab.h>
-+#include <linux/spi/spi.h>
-+
-+#include "mcp25xxfd_cmd.h"
-+#include "mcp25xxfd_priv.h"
-+
-+/* SPI helper */
-+
-+/* wrapper arround spi_sync, that sets speed_hz */
-+static int mcp25xxfd_cmd_sync_transfer(struct spi_device *spi,
-+				       struct spi_transfer *xfer,
-+				       unsigned int xfers)
-+{
-+	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
-+	int i;
-+
-+	for (i = 0; i < xfers; i++)
-+		xfer[i].speed_hz = priv->spi_use_speed_hz;
-+
-+	return spi_sync_transfer(spi, xfer, xfers);
-+}
-+
-+/* simple spi_write wrapper with speed_hz
-+ * WARINING: tx_buf needs to be on heap!
-+ */
-+static int mcp25xxfd_cmd_sync_write(struct spi_device *spi,
-+				    const void *tx_buf,
-+				    unsigned int tx_len)
-+{
-+	struct spi_transfer xfer;
-+
-+	memset(&xfer, 0, sizeof(xfer));
-+	xfer.tx_buf = tx_buf;
-+	xfer.len = tx_len;
-+
-+	return mcp25xxfd_cmd_sync_transfer(spi, &xfer, 1);
-+}
-+
-+/* alloc buffer */
-+static int mcp25xxfd_cmd_alloc_buf(struct spi_device *spi,
-+				   size_t len,
-+				   u8 **tx, u8 **rx)
-+{
-+	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
-+
-+	/* allocate from heap in case the size is to big
-+	 * or the preallocated buffer is already used (i.e locked)
-+	 */
-+	if (len > sizeof(priv->spi_tx) ||
-+	    !mutex_trylock(&priv->spi_rxtx_lock)) {
-+		/* allocate tx+rx in one allocation if rx is requested */
-+		*tx = kzalloc(rx ? 2 * len : len, GFP_KERNEL);
-+		if (!*tx)
-+			return -ENOMEM;
-+		if (rx)
-+			*rx = *tx + len;
-+	} else {
-+		/* use the preallocated buffers instead */
-+		*tx = priv->spi_tx;
-+		memset(priv->spi_tx, 0, sizeof(priv->spi_tx));
-+		if (rx) {
-+			*rx = priv->spi_rx;
-+			memset(priv->spi_rx, 0, sizeof(priv->spi_rx));
-+		}
-+	}
-+
-+	return 0;
-+}
-+
-+static void mcp25xxfd_cmd_release_buf(struct spi_device *spi, u8 *tx, u8 *rx)
-+{
-+	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
-+
-+	if (tx == priv->spi_tx)
-+		mutex_unlock(&priv->spi_rxtx_lock);
-+	else
-+		kfree(tx);
-+}
-+
-+/* an optimization of spi_write_then_read that merges the transfers
-+ * this also makes sure that the data is ALWAYS on heap
-+ */
-+static int mcp25xxfd_cmd_write_then_read(struct spi_device *spi,
-+					 const void *tx_buf,
-+					 unsigned int tx_len,
-+					 void *rx_buf,
-+					 unsigned int rx_len)
-+{
-+	struct spi_transfer xfer[2];
-+	u8 *spi_tx, *spi_rx;
-+	int xfers;
-+	int ret;
-+
-+	/* get pointer to buffers */
-+	ret = mcp25xxfd_cmd_alloc_buf(spi, tx_len + rx_len, &spi_tx, &spi_rx);
-+	if (ret)
-+		return ret;
-+
-+	/* clear the xfers */
-+	memset(xfer, 0, sizeof(xfer));
-+
-+	/* special handling for half-duplex */
-+	if (spi->master->flags & SPI_MASTER_HALF_DUPLEX) {
-+		xfers = 2;
-+		xfer[0].tx_buf = spi_tx;
-+		xfer[0].len = tx_len;
-+		/* the offset for rx_buf needs to get aligned */
-+		xfer[1].rx_buf = spi_rx + tx_len;
-+		xfer[1].len = rx_len;
-+	} else {
-+		xfers = 1;
-+		xfer[0].len = tx_len + rx_len;
-+		xfer[0].tx_buf = spi_tx;
-+		xfer[0].rx_buf = spi_rx;
-+	}
-+
-+	/* copy data - especially to avoid buffers from stack */
-+	memcpy(spi_tx, tx_buf, tx_len);
-+
-+	/* do the transfer */
-+	ret = mcp25xxfd_cmd_sync_transfer(spi, xfer, xfers);
-+	if (ret)
-+		goto out;
-+
-+	/* copy result back */
-+	memcpy(rx_buf, xfer[0].rx_buf + tx_len, rx_len);
-+
-+out:
-+	mcp25xxfd_cmd_release_buf(spi, spi_tx, spi_rx);
-+
-+	return ret;
-+}
-+
-+static int mcp25xxfd_cmd_write_then_write(struct spi_device *spi,
-+					  const void *tx_buf,
-+					  unsigned int tx_len,
-+					  const void *tx2_buf,
-+					  unsigned int tx2_len)
-+{
-+	struct spi_transfer xfer;
-+	u8 *spi_tx;
-+	int ret;
-+
-+	/* get pointer to buffers */
-+	ret = mcp25xxfd_cmd_alloc_buf(spi, tx_len + tx2_len, &spi_tx, NULL);
-+	if (ret)
-+		return ret;
-+
-+	/* setup xfer */
-+	memset(&xfer, 0, sizeof(xfer));
-+	xfer.len = tx_len + tx2_len;
-+	xfer.tx_buf = spi_tx;
-+
-+	/* copy data to correct location in buffer */
-+	memcpy(spi_tx, tx_buf, tx_len);
-+	memcpy(spi_tx + tx_len, tx2_buf, tx2_len);
-+
-+	/* run the transfer */
-+	ret = mcp25xxfd_cmd_sync_transfer(spi, &xfer, 1);
-+
-+	mcp25xxfd_cmd_release_buf(spi, spi_tx, NULL);
-+
-+	return ret;
-+}
-+
-+/* mcp25xxfd spi command/protocol helper */
-+
-+/* read multiple bytes, transform some registers */
-+int mcp25xxfd_cmd_readn(struct spi_device *spi, u32 reg,
-+			void *data, int n)
-+{
-+	u8 cmd[2];
-+	int ret;
-+
-+	mcp25xxfd_cmd_calc(MCP25XXFD_INSTRUCTION_READ, reg, cmd);
-+
-+	ret = mcp25xxfd_cmd_write_then_read(spi, &cmd, 2, data, n);
-+	if (ret)
-+		return ret;
-+
-+	return 0;
-+}
-+
-+/* read a register, but we are only interrested in a few bytes */
-+int mcp25xxfd_cmd_read_mask(struct spi_device *spi, u32 reg,
-+			    u32 *data, u32 mask)
-+{
-+	int first_byte, last_byte, len_byte;
-+	int ret;
-+
-+	/* check that at least one bit is set */
-+	if (!mask)
-+		return -EINVAL;
-+
-+	/* calculate first and last byte used */
-+	first_byte = mcp25xxfd_cmd_first_byte(mask);
-+	last_byte = mcp25xxfd_cmd_last_byte(mask);
-+	len_byte = last_byte - first_byte + 1;
-+
-+	/* do a partial read */
-+	*data = 0;
-+	ret = mcp25xxfd_cmd_readn(spi, reg + first_byte,
-+				  ((void *)data + first_byte), len_byte);
-+	if (ret)
-+		return ret;
-+
-+	mcp25xxfd_cmd_convert_to_cpu(data, 1);
-+
-+	return 0;
-+}
-+
-+int mcp25xxfd_cmd_writen(struct spi_device *spi, u32 reg,
-+			 void *data, int n)
-+{
-+	u8 cmd[2];
-+	int ret;
-+
-+	mcp25xxfd_cmd_calc(MCP25XXFD_INSTRUCTION_WRITE, reg, cmd);
-+
-+	ret = mcp25xxfd_cmd_write_then_write(spi, &cmd, 2, data, n);
-+	if (ret)
-+		return ret;
-+
-+	return 0;
-+}
-+
-+/* read a register, but we are only interrested in a few bytes */
-+int mcp25xxfd_cmd_write_mask(struct spi_device *spi, u32 reg,
-+			     u32 data, u32 mask)
-+{
-+	int first_byte, last_byte, len_byte;
-+	u8 cmd[2];
-+
-+	/* check that at least one bit is set */
-+	if (!mask)
-+		return -EINVAL;
-+
-+	/* calculate first and last byte used */
-+	first_byte = mcp25xxfd_cmd_first_byte(mask);
-+	last_byte = mcp25xxfd_cmd_last_byte(mask);
-+	len_byte = last_byte - first_byte + 1;
-+
-+	/* prepare buffer */
-+	mcp25xxfd_cmd_calc(MCP25XXFD_INSTRUCTION_WRITE,
-+			   reg + first_byte, cmd);
-+
-+	mcp25xxfd_cmd_convert_from_cpu(&data, 1);
-+
-+	return mcp25xxfd_cmd_write_then_write(spi,
-+					      cmd, sizeof(cmd),
-+					      ((void *)&data + first_byte),
-+					      len_byte);
-+}
-+
-+int mcp25xxfd_cmd_write_regs(struct spi_device *spi, u32 reg,
-+			     u32 *data, u32 bytes)
-+{
-+	int ret;
-+
-+	/* first transpose to controller format */
-+	mcp25xxfd_cmd_convert_from_cpu(data, bytes / sizeof(bytes));
-+
-+	/* now write it */
-+	ret = mcp25xxfd_cmd_writen(spi, reg, data, bytes);
-+
-+	/* and convert it back to cpu format even if it fails */
-+	mcp25xxfd_cmd_convert_to_cpu(data, bytes / sizeof(bytes));
-+
-+	return ret;
-+}
-+
-+int mcp25xxfd_cmd_read_regs(struct spi_device *spi, u32 reg,
-+			    u32 *data, u32 bytes)
-+{
-+	int ret;
-+
-+	/* read it */
-+	ret = mcp25xxfd_cmd_readn(spi, reg, data, bytes);
-+
-+	/* and convert it to cpu format */
-+	mcp25xxfd_cmd_convert_to_cpu((u32 *)data, bytes / sizeof(bytes));
-+
-+	return ret;
-+}
-+
-+int mcp25xxfd_cmd_reset(struct spi_device *spi)
-+{
-+	u8 *cmd;
-+	int ret;
-+
-+	/* allocate 2 bytes on heap, as we use sync_write */
-+	cmd = kzalloc(2, GFP_KERNEL);
-+	if (!cmd)
-+		return -ENOMEM;
-+
-+	mcp25xxfd_cmd_calc(MCP25XXFD_INSTRUCTION_RESET, 0, cmd);
-+
-+	/* write the reset command */
-+	ret = mcp25xxfd_cmd_sync_write(spi, cmd, 2);
-+
-+	kfree(cmd);
-+
-+	return ret;
-+}
-diff --git a/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_cmd.h b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_cmd.h
-new file mode 100644
-index 000000000000..c9b8ae4db151
---- /dev/null
-+++ b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_cmd.h
-@@ -0,0 +1,84 @@
-+/* SPDX-License-Identifier: GPL-2.0 */
-+
-+/* CAN bus driver for Microchip 25XXFD CAN Controller with SPI Interface
-+ *
-+ * Copyright 2019 Martin Sperl <kernel@martin.sperl.org>
-+ */
-+
-+#ifndef __MCP25XXFD_CMD_H
-+#define __MCP25XXFD_CMD_H
-+
-+#include <linux/byteorder/generic.h>
-+#include <linux/spi/spi.h>
-+
-+/* SPI commands */
-+#define MCP25XXFD_INSTRUCTION_RESET		0x0000
-+#define MCP25XXFD_INSTRUCTION_READ		0x3000
-+#define MCP25XXFD_INSTRUCTION_WRITE		0x2000
-+#define MCP25XXFD_INSTRUCTION_READ_CRC		0xB000
-+#define MCP25XXFD_INSTRUCTION_WRITE_CRC		0xA000
-+#define MCP25XXFD_INSTRUCTION_WRITE_SAVE	0xC000
-+
-+#define MCP25XXFD_ADDRESS_MASK			0x0fff
-+
-+static inline void mcp25xxfd_cmd_convert_to_cpu(u32 *data, int n)
-+{
-+	le32_to_cpu_array(data, n);
-+}
-+
-+static inline void mcp25xxfd_cmd_convert_from_cpu(u32 *data, int n)
-+{
-+	cpu_to_le32_array(data, n);
-+}
-+
-+static inline void mcp25xxfd_cmd_calc(u16 cmd, u16 addr, u8 *data)
-+{
-+	cmd = cmd | (addr & MCP25XXFD_ADDRESS_MASK);
-+
-+	data[0] = (cmd >> 8) & 0xff;
-+	data[1] = (cmd >> 0) & 0xff;
-+}
-+
-+static inline int mcp25xxfd_cmd_first_byte(u32 mask)
-+{
-+	return (mask & 0x0000ffff) ?
-+		((mask & 0x000000ff) ? 0 : 1) :
-+		((mask & 0x00ff0000) ? 2 : 3);
-+}
-+
-+static inline int mcp25xxfd_cmd_last_byte(u32 mask)
-+{
-+	return (mask & 0xffff0000) ?
-+		((mask & 0xff000000) ? 3 : 2) :
-+		((mask & 0x0000ff00) ? 1 : 0);
-+}
-+
-+int mcp25xxfd_cmd_readn(struct spi_device *spi, u32 reg,
-+			void *data, int n);
-+int mcp25xxfd_cmd_read_mask(struct spi_device *spi, u32 reg,
-+			    u32 *data, u32 mask);
-+static inline int mcp25xxfd_cmd_read(struct spi_device *spi, u32 reg,
-+				     u32 *data)
-+{
-+	return mcp25xxfd_cmd_read_mask(spi, reg, data, -1);
-+}
-+
-+int mcp25xxfd_cmd_read_regs(struct spi_device *spi, u32 reg,
-+			    u32 *data, u32 bytes);
-+
-+int mcp25xxfd_cmd_writen(struct spi_device *spi, u32 reg,
-+			 void *data, int n);
-+int mcp25xxfd_cmd_write_mask(struct spi_device *spi, u32 reg,
-+			     u32 data, u32 mask);
-+static inline int mcp25xxfd_cmd_write(struct spi_device *spi, u32 reg,
-+				      u32 data)
-+{
-+	return mcp25xxfd_cmd_write_mask(spi, reg, data, -1);
-+}
-+
-+int mcp25xxfd_cmd_write_regs(struct spi_device *spi, u32 reg,
-+			     u32 *data, u32 bytes);
-+
-+int mcp25xxfd_cmd_reset(struct spi_device *spi);
-+
-+#endif /* __MCP25XXFD_CMD_H */
-diff --git a/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_crc.c b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_crc.c
-new file mode 100644
-index 000000000000..b893d8009448
---- /dev/null
-+++ b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_crc.c
-@@ -0,0 +1,31 @@
-+// SPDX-License-Identifier: GPL-2.0
-+
-+/* CAN bus driver for Microchip 25XXFD CAN Controller with SPI Interface
-+ *
-+ * Copyright 2019 Martin Sperl <kernel@martin.sperl.org>
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/spi/spi.h>
-+#include "mcp25xxfd_cmd.h"
-+#include "mcp25xxfd_crc.h"
-+#include "mcp25xxfd_regs.h"
-+#include "mcp25xxfd_priv.h"
-+
-+int mcp25xxfd_crc_enable_int(struct mcp25xxfd_priv *priv, bool enable)
-+{
-+	u32 mask = MCP25XXFD_CRC_CRCERRIE | MCP25XXFD_CRC_FERRIE;
-+
-+	priv->regs.crc &= ~mask;
-+	priv->regs.crc |= enable ? mask : 0;
-+
-+	return mcp25xxfd_cmd_write_mask(priv->spi, MCP25XXFD_CRC,
-+					priv->regs.crc, mask);
-+}
-+
-+int mcp25xxfd_crc_clear_int(struct mcp25xxfd_priv *priv)
-+{
-+	return mcp25xxfd_cmd_write_mask(priv->spi, MCP25XXFD_CRC, 0,
-+					MCP25XXFD_CRC_CRCERRIF |
-+					MCP25XXFD_CRC_FERRIF);
-+}
-diff --git a/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_crc.h b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_crc.h
-new file mode 100644
-index 000000000000..6e42fe0fad0f
---- /dev/null
-+++ b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_crc.h
-@@ -0,0 +1,15 @@
-+/* SPDX-License-Identifier: GPL-2.0 */
-+
-+/* CAN bus driver for Microchip 25XXFD CAN Controller with SPI Interface
-+ *
-+ * Copyright 2019 Martin Sperl <kernel@martin.sperl.org>
-+ */
-+#ifndef __MCP25XXFD_CRC_H
-+#define __MCP25XXFD_CRC_H
-+
-+#include "mcp25xxfd_priv.h"
-+
-+int mcp25xxfd_crc_enable_int(struct mcp25xxfd_priv *priv, bool enable);
-+int mcp25xxfd_crc_clear_int(struct mcp25xxfd_priv *priv);
-+
-+#endif /* __MCP25XXFD_CRC_H */
-diff --git a/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_debugfs.c b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_debugfs.c
-new file mode 100644
-index 000000000000..92ee4d737f84
---- /dev/null
-+++ b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_debugfs.c
-@@ -0,0 +1,110 @@
-+// SPDX-License-Identifier: GPL-2.0
-+
-+/* CAN bus driver for Microchip 25XXFD CAN Controller with SPI Interface
-+ *
-+ * Copyright 2019 Martin Sperl <kernel@martin.sperl.org>
-+ */
-+
-+#ifdef CONFIG_DEBUG_FS
-+
-+#include <linux/debugfs.h>
-+#include <linux/kernel.h>
-+#include <linux/seq_file.h>
-+
-+#include "mcp25xxfd_cmd.h"
-+#include "mcp25xxfd_debugfs.h"
-+#include "mcp25xxfd_priv.h"
-+
-+static int mcp25xxfd_debugfs_dump_regs_range(struct seq_file *file,
-+					     u32 start, u32 end)
-+{
-+	struct spi_device *spi = file->private;
-+	u32 data[32];
-+	int bytes = end - start + sizeof(*data);
-+	int i, l, count, ret;
-+
-+	for (count =  bytes / sizeof(*data); count > 0; count -= 32) {
-+		/* read up to 32 registers in one go */
-+		l = min(count, 32);
-+		ret = mcp25xxfd_cmd_read_regs(spi, start,
-+					      data, l * sizeof(*data));
-+		if (ret)
-+			return ret;
-+		/* dump those read registers */
-+		for (i = 0; i < l; i++, start += sizeof(*data))
-+			seq_printf(file, "Reg 0x%03x = 0x%08x\n",
-+				   start, data[i]);
-+	}
-+
-+	return 0;
-+}
-+
-+static int mcp25xxfd_debugfs_dump_regs(struct seq_file *file, void *offset)
-+{
-+	return mcp25xxfd_debugfs_dump_regs_range(file, MCP25XXFD_OSC,
-+						 MCP25XXFD_ECCSTAT);
-+}
-+
-+static int mcp25xxfd_debugfs_dump_can_regs(struct seq_file *file,
-+					   void *offset)
-+{
-+	return mcp25xxfd_debugfs_dump_regs_range(file, MCP25XXFD_CAN_CON,
-+						 MCP25XXFD_CAN_TXQUA);
-+}
-+
-+static int mcp25xxfd_debugfs_dump_can_all_regs(struct seq_file *file,
-+					       void *offset)
-+{
-+	return mcp25xxfd_debugfs_dump_regs_range(file, MCP25XXFD_CAN_CON,
-+						 MCP25XXFD_CAN_FLTMASK(31));
-+}
-+
-+static void mcp25xxfd_debugfs_mod_setup(struct mcp25xxfd_priv *priv)
-+{
-+	struct dentry *root, *regs;
-+
-+	/* the base directory */
-+	priv->debugfs_dir = debugfs_create_dir(priv->device_name, NULL);
-+	root = priv->debugfs_dir;
-+
-+	/* expose some parameters related to clocks */
-+	debugfs_create_u32("spi_setup_speed_hz", 0444, root,
-+			   &priv->spi_setup_speed_hz);
-+	debugfs_create_u32("spi_normal_speed_hz", 0444, root,
-+			   &priv->spi_normal_speed_hz);
-+	debugfs_create_u32("spi_use_speed_hz", 0444, root,
-+			   &priv->spi_use_speed_hz);
-+	debugfs_create_u32("clk_user_mask", 0444, root, &priv->clk_user_mask);
-+
-+	/* expose the system registers */
-+	priv->debugfs_regs_dir = debugfs_create_dir("regs", root);
-+	regs = priv->debugfs_regs_dir;
-+	debugfs_create_x32("osc", 0444, regs, &priv->regs.osc);
-+	debugfs_create_x32("iocon", 0444, regs, &priv->regs.iocon);
-+	debugfs_create_x32("crc", 0444, regs, &priv->regs.crc);
-+	debugfs_create_x32("ecccon", 0444, regs, &priv->regs.ecccon);
-+
-+	/* dump the controller registers themselves */
-+	debugfs_create_devm_seqfile(&priv->spi->dev, "regs_live_dump",
-+				    root, mcp25xxfd_debugfs_dump_regs);
-+	/* and the essential can registers */
-+	debugfs_create_devm_seqfile(&priv->spi->dev, "can_regs_live_dump",
-+				    root, mcp25xxfd_debugfs_dump_can_regs);
-+	/* and the complete can registers */
-+	debugfs_create_devm_seqfile(&priv->spi->dev,
-+				    "can_regs_all_live_dump", root,
-+				    mcp25xxfd_debugfs_dump_can_all_regs);
-+}
-+
-+void mcp25xxfd_debugfs_setup(struct mcp25xxfd_priv *priv)
-+{
-+	mcp25xxfd_debugfs_mod_setup(priv);
-+}
-+
-+void mcp25xxfd_debugfs_remove(struct mcp25xxfd_priv *priv)
-+{
-+	debugfs_remove_recursive(priv->debugfs_dir);
-+	priv->debugfs_dir = NULL;
-+}
-+
-+#endif /* CONFIG_DEBUG_FS */
-diff --git a/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_debugfs.h b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_debugfs.h
-new file mode 100644
-index 000000000000..800672442ffb
---- /dev/null
-+++ b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_debugfs.h
-@@ -0,0 +1,30 @@
-+/* SPDX-License-Identifier: GPL-2.0 */
-+
-+/* CAN bus driver for Microchip 25XXFD CAN Controller with SPI Interface
-+ *
-+ * Copyright 2019 Martin Sperl <kernel@martin.sperl.org>
-+ */
-+
-+#ifndef __MCP25XXFD_DEBUGFS_H
-+#define __MCP25XXFD_DEBUGFS_H
-+
-+#include "mcp25xxfd_priv.h"
-+
-+#ifdef CONFIG_DEBUG_FS
-+
-+void mcp25xxfd_debugfs_setup(struct mcp25xxfd_priv *priv);
-+void mcp25xxfd_debugfs_remove(struct mcp25xxfd_priv *priv);
-+
-+#else
-+
-+static inline void mcp25xxfd_debugfs_setup(struct mcp25xxfd_priv *priv)
-+{
-+	return 0;
-+}
-+
-+static inline void mcp25xxfd_debugfs_remove(struct mcp25xxfd_priv *priv)
-+{
-+}
-+
-+#endif /* CONFIG_DEBUG_FS */
-+#endif /* __MCP25XXFD_DEBUGFS_H */
-diff --git a/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_ecc.c b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_ecc.c
-new file mode 100644
-index 000000000000..526f345d0a17
---- /dev/null
-+++ b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_ecc.c
-@@ -0,0 +1,75 @@
-+// SPDX-License-Identifier: GPL-2.0
-+
-+/* CAN bus driver for Microchip 25XXFD CAN Controller with SPI Interface
-+ *
-+ * Copyright 2019 Martin Sperl <kernel@martin.sperl.org>
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/spi/spi.h>
-+#include "mcp25xxfd_cmd.h"
-+#include "mcp25xxfd_ecc.h"
-+#include "mcp25xxfd_priv.h"
-+#include "mcp25xxfd_regs.h"
-+
-+int mcp25xxfd_ecc_clear_int(struct mcp25xxfd_priv *priv)
-+{
-+	u32 val, addr;
-+	int ret;
-+
-+	/* first report the error address */
-+	ret = mcp25xxfd_cmd_read(priv->spi, MCP25XXFD_ECCSTAT, &val);
-+	if (ret)
-+		return ret;
-+
-+	/* if no flags are set then nothing to do */
-+	if (!(val & (MCP25XXFD_ECCSTAT_SECIF | MCP25XXFD_ECCSTAT_DEDIF)))
-+		return 0;
-+
-+	addr = (val & MCP25XXFD_ECCSTAT_ERRADDR_MASK) >>
-+		MCP25XXFD_ECCSTAT_ERRADDR_SHIFT;
-+
-+	dev_err_ratelimited(&priv->spi->dev, "ECC %s bit error at %03x\n",
-+			    (val & MCP25XXFD_ECCSTAT_DEDIF) ?
-+			    "double" : "single",
-+			    addr);
-+
-+	/* and clear the error */
-+	return mcp25xxfd_cmd_write_mask(priv->spi, MCP25XXFD_ECCSTAT, 0,
-+					MCP25XXFD_ECCSTAT_SECIF |
-+					MCP25XXFD_ECCSTAT_DEDIF);
-+}
-+
-+int mcp25xxfd_ecc_enable_int(struct mcp25xxfd_priv *priv, bool enable)
-+{
-+	u32 mask = MCP25XXFD_ECCCON_SECIE | MCP25XXFD_ECCCON_DEDIE;
-+
-+	priv->regs.ecccon &= ~mask;
-+	priv->regs.ecccon |= MCP25XXFD_ECCCON_ECCEN | (enable ? mask : 0);
-+
-+	return mcp25xxfd_cmd_write_mask(priv->spi, MCP25XXFD_ECCCON,
-+					priv->regs.ecccon,
-+					MCP25XXFD_ECCCON_ECCEN | mask);
-+}
-+
-+int mcp25xxfd_ecc_enable(struct mcp25xxfd_priv *priv)
-+{
-+	u8 buffer[256];
-+	int i, ret;
-+
-+	/* set up RAM ECC - enable interrupts sets it as well */
-+	ret = mcp25xxfd_ecc_enable_int(priv, false);
-+	if (ret)
-+		return ret;
-+
-+	/* and clear SRAM so that no reads fails from now on */
-+	memset(buffer, 0, sizeof(buffer));
-+	for (i = 0; i < MCP25XXFD_SRAM_SIZE; i += sizeof(buffer)) {
-+		ret = mcp25xxfd_cmd_writen(priv->spi, MCP25XXFD_SRAM_ADDR(i),
-+					   buffer, sizeof(buffer));
-+		if (ret)
-+			return ret;
-+	}
-+
-+	return 0;
-+}
-diff --git a/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_ecc.h b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_ecc.h
-new file mode 100644
-index 000000000000..117f58c65a46
---- /dev/null
-+++ b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_ecc.h
-@@ -0,0 +1,16 @@
-+/* SPDX-License-Identifier: GPL-2.0 */
-+
-+/* CAN bus driver for Microchip 25XXFD CAN Controller with SPI Interface
-+ *
-+ * Copyright 2019 Martin Sperl <kernel@martin.sperl.org>
-+ */
-+#ifndef __MCP25XXFD_ECC_H
-+#define __MCP25XXFD_ECC_H
-+
-+#include "mcp25xxfd_priv.h"
-+
-+int mcp25xxfd_ecc_clear_int(struct mcp25xxfd_priv *priv);
-+int mcp25xxfd_ecc_enable_int(struct mcp25xxfd_priv *priv, bool enable);
-+int mcp25xxfd_ecc_enable(struct mcp25xxfd_priv *priv);
-+
-+#endif /* __MCP25XXFD_ECC_H */
-diff --git a/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_gpio.c b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_gpio.c
-new file mode 100644
-index 000000000000..69eb9c6ef176
---- /dev/null
-+++ b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_gpio.c
-@@ -0,0 +1,194 @@
-+// SPDX-License-Identifier: GPL-2.0
-+
-+/* CAN bus driver for Microchip 25XXFD CAN Controller with SPI Interface
-+ *
-+ * Copyright 2019 Martin Sperl <kernel@martin.sperl.org>
-+ *
-+ * Based on Microchip MCP251x CAN controller driver written by
-+ * David Vrabel, Copyright 2006 Arcom Control Systems Ltd.
-+ */
-+
-+#include <linux/gpio/driver.h>
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/slab.h>
-+
-+#include "mcp25xxfd_clock.h"
-+#include "mcp25xxfd_cmd.h"
-+#include "mcp25xxfd_priv.h"
-+
-+/* GPIO component */
-+#ifdef CONFIG_GPIOLIB
-+
-+enum mcp25xxfd_gpio_pins {
-+	MCP25XXFD_GPIO_GPIO0 = 0,
-+	MCP25XXFD_GPIO_GPIO1 = 1,
-+};
-+
-+static int mcp25xxfd_gpio_request(struct gpio_chip *chip,
-+				  unsigned int offset)
-+{
-+	struct mcp25xxfd_priv *priv = gpiochip_get_data(chip);
-+	int clock_requestor = offset ?
-+		MCP25XXFD_CLK_USER_GPIO1 : MCP25XXFD_CLK_USER_GPIO0;
-+
-+	/* only handle gpio 0/1 */
-+	if (offset > 1)
-+		return -EINVAL;
-+
-+	mcp25xxfd_clock_start(priv, clock_requestor);
-+
-+	return 0;
-+}
-+
-+static void mcp25xxfd_gpio_free(struct gpio_chip *chip,
-+				unsigned int offset)
-+{
-+	struct mcp25xxfd_priv *priv = gpiochip_get_data(chip);
-+	int clock_requestor = offset ?
-+		MCP25XXFD_CLK_USER_GPIO1 : MCP25XXFD_CLK_USER_GPIO0;
-+
-+	/* only handle gpio 0/1 */
-+	if (offset > 1)
-+		return;
-+
-+	mcp25xxfd_clock_stop(priv, clock_requestor);
-+}
-+
-+static int mcp25xxfd_gpio_get(struct gpio_chip *chip, unsigned int offset)
-+{
-+	struct mcp25xxfd_priv *priv = gpiochip_get_data(chip);
-+	u32 mask = (offset) ? MCP25XXFD_IOCON_GPIO1 : MCP25XXFD_IOCON_GPIO0;
-+	int ret;
-+
-+	/* only handle gpio 0/1 */
-+	if (offset > 1)
-+		return -EINVAL;
-+
-+	/* read the relevant gpio Latch */
-+	ret = mcp25xxfd_cmd_read_mask(priv->spi, MCP25XXFD_IOCON,
-+				      &priv->regs.iocon, mask);
-+	if (ret)
-+		return ret;
-+
-+	/* return the match */
-+	return priv->regs.iocon & mask;
-+}
-+
-+static void mcp25xxfd_gpio_set(struct gpio_chip *chip, unsigned int offset,
-+			       int value)
-+{
-+	struct mcp25xxfd_priv *priv = gpiochip_get_data(chip);
-+	u32 mask = (offset) ? MCP25XXFD_IOCON_LAT1 : MCP25XXFD_IOCON_LAT0;
-+
-+	/* only handle gpio 0/1 */
-+	if (offset > 1)
-+		return;
-+
-+	/* update in memory representation with the corresponding value */
-+	if (value)
-+		priv->regs.iocon |= mask;
-+	else
-+		priv->regs.iocon &= ~mask;
-+
-+	mcp25xxfd_cmd_write_mask(priv->spi, MCP25XXFD_IOCON,
-+				 priv->regs.iocon, mask);
-+}
-+
-+static int mcp25xxfd_gpio_direction_input(struct gpio_chip *chip,
-+					  unsigned int offset)
-+{
-+	struct mcp25xxfd_priv *priv = gpiochip_get_data(chip);
-+	u32 mask_tri = (offset) ?
-+		MCP25XXFD_IOCON_TRIS1 : MCP25XXFD_IOCON_TRIS0;
-+	u32 mask_stby = (offset) ?
-+		0 : MCP25XXFD_IOCON_XSTBYEN;
-+	u32 mask_pm = (offset) ?
-+		MCP25XXFD_IOCON_PM1 : MCP25XXFD_IOCON_PM0;
-+
-+	/* only handle gpio 0/1 */
-+	if (offset > 1)
-+		return -EINVAL;
-+
-+	/* set the mask */
-+	priv->regs.iocon |= mask_tri | mask_pm;
-+
-+	/* clear stby */
-+	priv->regs.iocon &= ~mask_stby;
-+
-+	return mcp25xxfd_cmd_write_mask(priv->spi, MCP25XXFD_IOCON,
-+					priv->regs.iocon,
-+					mask_tri | mask_stby | mask_pm);
-+}
-+
-+static int mcp25xxfd_gpio_direction_output(struct gpio_chip *chip,
-+					   unsigned int offset, int value)
-+{
-+	struct mcp25xxfd_priv *priv = gpiochip_get_data(chip);
-+	u32 mask_tri = (offset) ?
-+		MCP25XXFD_IOCON_TRIS1 : MCP25XXFD_IOCON_TRIS0;
-+	u32 mask_lat = (offset) ?
-+		MCP25XXFD_IOCON_LAT1 : MCP25XXFD_IOCON_LAT0;
-+	u32 mask_pm = (offset) ?
-+		MCP25XXFD_IOCON_PM1 : MCP25XXFD_IOCON_PM0;
-+	u32 mask_stby = (offset) ?
-+		0 : MCP25XXFD_IOCON_XSTBYEN;
-+
-+	/* only handle gpio 0/1 */
-+	if (offset > 1)
-+		return -EINVAL;
-+
-+	/* clear the tristate bit and also clear stby */
-+	priv->regs.iocon &= ~(mask_tri | mask_stby);
-+
-+	/* set GPIO mode */
-+	priv->regs.iocon |= mask_pm;
-+
-+	/* set the value */
-+	if (value)
-+		priv->regs.iocon |= mask_lat;
-+	else
-+		priv->regs.iocon &= ~mask_lat;
-+
-+	return mcp25xxfd_cmd_write_mask(priv->spi, MCP25XXFD_IOCON,
-+					priv->regs.iocon,
-+					mask_tri | mask_lat |
-+					mask_pm | mask_stby);
-+}
-+
-+int mcp25xxfd_gpio_setup(struct mcp25xxfd_priv *priv)
-+{
-+	struct gpio_chip *gpio = &priv->gpio;
-+
-+	/* gpiochip only handles GPIO0 and GPIO1 */
-+	gpio->owner                = THIS_MODULE;
-+	gpio->parent               = &priv->spi->dev;
-+	gpio->label                = dev_name(&priv->spi->dev);
-+	gpio->direction_input      = mcp25xxfd_gpio_direction_input;
-+	gpio->get                  = mcp25xxfd_gpio_get;
-+	gpio->direction_output     = mcp25xxfd_gpio_direction_output;
-+	gpio->set                  = mcp25xxfd_gpio_set;
-+	gpio->request              = mcp25xxfd_gpio_request;
-+	gpio->free                 = mcp25xxfd_gpio_free;
-+	gpio->base                 = -1;
-+	gpio->ngpio                = 2;
-+	gpio->can_sleep            = 1;
-+
-+	return gpiochip_add_data(gpio, priv);
-+}
-+
-+void mcp25xxfd_gpio_remove(struct mcp25xxfd_priv *priv)
-+{
-+	gpiochip_remove(&priv->gpio);
-+}
-+
-+#else
-+int mcp25xxfd_gpio_setup(struct mcp25xxfd_priv *priv)
-+{
-+	return 0;
-+}
-+
-+void mcp25xxfd_gpio_remove(struct mcp25xxfd_priv *priv)
-+{
-+}
-+#endif
-diff --git a/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_gpio.h b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_gpio.h
-new file mode 100644
-index 000000000000..46740e8abc45
---- /dev/null
-+++ b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_gpio.h
-@@ -0,0 +1,16 @@
-+/* SPDX-License-Identifier: GPL-2.0 */
-+
-+/* CAN bus driver for Microchip 25XXFD CAN Controller with SPI Interface
-+ *
-+ * Copyright 2019 Martin Sperl <kernel@martin.sperl.org>
-+ */
-+#ifndef __MCP25XXFD_GPIO_H
-+#define __MCP25XXFD_GPIO_H
-+
-+#include "mcp25xxfd_priv.h"
-+
-+/* gpiolib support */
-+int mcp25xxfd_gpio_setup(struct mcp25xxfd_priv *priv);
-+void mcp25xxfd_gpio_remove(struct mcp25xxfd_priv *priv);
-+
-+#endif /* __MCP25XXFD_GPIO_H */
-diff --git a/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_int.c b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_int.c
-new file mode 100644
-index 000000000000..cca9c996b542
---- /dev/null
-+++ b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_int.c
-@@ -0,0 +1,73 @@
-+// SPDX-License-Identifier: GPL-2.0
-+
-+/* CAN bus driver for Microchip 25XXFD CAN Controller with SPI Interface
-+ *
-+ * Copyright 2019 Martin Sperl <kernel@martin.sperl.org>
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/spi/spi.h>
-+
-+#include "mcp25xxfd_can_int.h"
-+#include "mcp25xxfd_crc.h"
-+#include "mcp25xxfd_ecc.h"
-+#include "mcp25xxfd_int.h"
-+#include "mcp25xxfd_priv.h"
-+
-+int mcp25xxfd_int_clear(struct mcp25xxfd_priv *priv)
-+{
-+	int ret;
-+
-+	ret = mcp25xxfd_ecc_clear_int(priv);
-+	if (ret)
-+		return ret;
-+	ret = mcp25xxfd_crc_clear_int(priv);
-+	if (ret)
-+		return ret;
-+	ret = mcp25xxfd_can_int_clear(priv);
-+
-+	return ret;
-+}
-+
-+int mcp25xxfd_int_enable(struct mcp25xxfd_priv *priv, bool enable)
-+{
-+	/* error handling only on enable for this function */
-+	int ret = 0;
-+
-+	/* if we enable clear interrupt flags first */
-+	if (enable) {
-+		ret = mcp25xxfd_int_clear(priv);
-+		if (ret)
-+			goto out;
-+	}
-+
-+	ret = mcp25xxfd_crc_enable_int(priv, enable);
-+	if (ret)
-+		goto out;
-+
-+	ret = mcp25xxfd_ecc_enable(priv);
-+	if (ret)
-+		goto out_crc;
-+
-+	ret = mcp25xxfd_ecc_enable_int(priv, enable);
-+	if (ret)
-+		goto out_crc;
-+
-+	ret = mcp25xxfd_can_int_enable(priv, enable);
-+	if (ret)
-+		goto out_ecc;
-+
-+	/* if we disable interrupts clear interrupt flags last */
-+	if (!enable)
-+		mcp25xxfd_int_clear(priv);
-+
-+	return 0;
-+
-+out_ecc:
-+	mcp25xxfd_ecc_enable_int(priv, false);
-+
-+out_crc:
-+	mcp25xxfd_crc_enable_int(priv, false);
-+out:
-+	return ret;
-+}
-diff --git a/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_int.h b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_int.h
-new file mode 100644
-index 000000000000..4daf0182d1af
---- /dev/null
-+++ b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_int.h
-@@ -0,0 +1,15 @@
-+/* SPDX-License-Identifier: GPL-2.0 */
-+
-+/* CAN bus driver for Microchip 25XXFD CAN Controller with SPI Interface
-+ *
-+ * Copyright 2019 Martin Sperl <kernel@martin.sperl.org>
-+ */
-+#ifndef __MCP25XXFD_INT_H
-+#define __MCP25XXFD_INT_H
-+
-+#include "mcp25xxfd_priv.h"
-+
-+int mcp25xxfd_int_clear(struct mcp25xxfd_priv *priv);
-+int mcp25xxfd_int_enable(struct mcp25xxfd_priv *priv, bool enable);
-+
-+#endif /* __MCP25XXFD_INT_H */
-diff --git a/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_priv.h b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_priv.h
-new file mode 100644
-index 000000000000..e95a8eef70d8
---- /dev/null
-+++ b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_priv.h
-@@ -0,0 +1,83 @@
-+/* SPDX-License-Identifier: GPL-2.0 */
-+
-+/* CAN bus driver for Microchip 25XXFD CAN Controller with SPI Interface
-+ *
-+ * Copyright 2019 Martin Sperl <kernel@martin.sperl.org>
-+ */
-+#ifndef __MCP25XXFD_PRIV_H
-+#define __MCP25XXFD_PRIV_H
-+
-+#include <linux/clk.h>
-+#include <linux/debugfs.h>
-+#include <linux/gpio/driver.h>
-+#include <linux/mutex.h>
-+#include <linux/regulator/consumer.h>
-+#include <linux/spi/spi.h>
-+
-+#include "mcp25xxfd_regs.h"
-+
-+/* some defines for the driver */
-+#define DEVICE_NAME "mcp25xxfd"
-+
-+enum mcp25xxfd_model {
-+	CAN_MCP2517FD	= 0x2517,
-+};
-+
-+struct mcp25xxfd_can_priv;
-+struct mcp25xxfd_priv {
-+	struct spi_device *spi;
-+	struct clk *clk;
-+	struct gpio_chip gpio;
-+	struct mcp25xxfd_can_priv *cpriv;
-+
-+	/* the actual model of the mcp25xxfd */
-+	enum mcp25xxfd_model model;
-+
-+	/* full device name used for debugfs ant interrupts */
-+	char device_name[32];
-+
-+	/* everything clock related */
-+	int clock_freq;
-+	struct {
-+		/* clock configuration */
-+		int clock_pll;
-+		int clock_div2;
-+		int clock_odiv;
-+	} config;
-+
-+	/* lock for enabling/disabling the clock */
-+	struct mutex clk_user_lock;
-+	u32 clk_user_mask;
-+	u32 clk_sleep_mask;
-+
-+	/* power related */
-+	struct regulator *power;
-+
-+	/* the distinct spi_speeds to use for spi communication */
-+	u32 spi_setup_speed_hz;
-+	u32 spi_normal_speed_hz;
-+	u32 spi_use_speed_hz;
-+
-+	/* spi-tx/rx buffers for efficient transfers
-+	 * used during setup and irq
-+	 */
-+	struct mutex spi_rxtx_lock; /* protects use of spi_tx/rx */
-+	u8 spi_tx[MCP25XXFD_SRAM_SIZE];
-+	u8 spi_rx[MCP25XXFD_SRAM_SIZE];
-+
-+	/* configuration registers */
-+	struct {
-+		u32 osc;
-+		u32 iocon;
-+		u32 crc;
-+		u32 ecccon;
-+	} regs;
-+
-+	/* debugfs related */
-+#if defined(CONFIG_DEBUG_FS)
-+	struct dentry *debugfs_dir;
-+	struct dentry *debugfs_regs_dir;
-+#endif
-+};
-+
-+#endif /* __MCP25XXFD_PRIV_H */
-diff --git a/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_regs.h b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_regs.h
-new file mode 100644
-index 000000000000..222527439c70
---- /dev/null
-+++ b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_regs.h
-@@ -0,0 +1,661 @@
-+/* SPDX-License-Identifier: GPL-2.0 */
-+
-+/* CAN bus driver for Microchip 25XXFD CAN Controller with SPI Interface
-+ *
-+ * Copyright 2019 Martin Sperl <kernel@martin.sperl.org>
-+ */
-+
-+#ifndef __MCP25XXFD_REGS_H
-+#define __MCP25XXFD_REGS_H
-+
-+#include <linux/bitops.h>
-+
-+/* some constants derived from the datasheets */
-+#define MCP25XXFD_OST_DELAY_MS		3
-+#define MCP25XXFD_MIN_CLOCK_FREQUENCY	1000000
-+#define MCP25XXFD_MAX_CLOCK_FREQUENCY	40000000
-+#define MCP25XXFD_PLL_MULTIPLIER	10
-+#define MCP25XXFD_AUTO_PLL_MAX_CLOCK_FREQUENCY				\
-+	(MCP25XXFD_MAX_CLOCK_FREQUENCY / MCP25XXFD_PLL_MULTIPLIER)
-+#define MCP25XXFD_SCLK_DIVIDER		2
-+
-+/* GPIO, clock, ecc related register definitions of Controller itself */
-+#define MCP25XXFD_SFR_BASE(x)			(0xE00 + (x))
-+#define MCP25XXFD_OSC				MCP25XXFD_SFR_BASE(0x00)
-+#  define MCP25XXFD_OSC_PLLEN			BIT(0)
-+#  define MCP25XXFD_OSC_OSCDIS			BIT(2)
-+#  define MCP25XXFD_OSC_SCLKDIV			BIT(4)
-+#  define MCP25XXFD_OSC_CLKODIV_BITS		2
-+#  define MCP25XXFD_OSC_CLKODIV_SHIFT		5
-+#  define MCP25XXFD_OSC_CLKODIV_MASK					\
-+	GENMASK(MCP25XXFD_OSC_CLKODIV_SHIFT				\
-+		+ MCP25XXFD_OSC_CLKODIV_BITS - 1,			\
-+		MCP25XXFD_OSC_CLKODIV_SHIFT)
-+#  define MCP25XXFD_OSC_CLKODIV_10		3
-+#  define MCP25XXFD_OSC_CLKODIV_4		2
-+#  define MCP25XXFD_OSC_CLKODIV_2		1
-+#  define MCP25XXFD_OSC_CLKODIV_1		0
-+#  define MCP25XXFD_OSC_PLLRDY			BIT(8)
-+#  define MCP25XXFD_OSC_OSCRDY			BIT(10)
-+#  define MCP25XXFD_OSC_SCLKRDY			BIT(12)
-+#define MCP25XXFD_IOCON				MCP25XXFD_SFR_BASE(0x04)
-+#  define MCP25XXFD_IOCON_TRIS0			BIT(0)
-+#  define MCP25XXFD_IOCON_TRIS1			BIT(1)
-+#  define MCP25XXFD_IOCON_XSTBYEN		BIT(6)
-+#  define MCP25XXFD_IOCON_LAT0			BIT(8)
-+#  define MCP25XXFD_IOCON_LAT1			BIT(9)
-+#  define MCP25XXFD_IOCON_GPIO0			BIT(16)
-+#  define MCP25XXFD_IOCON_GPIO1			BIT(17)
-+#  define MCP25XXFD_IOCON_PM0			BIT(24)
-+#  define MCP25XXFD_IOCON_PM1			BIT(25)
-+#  define MCP25XXFD_IOCON_TXCANOD		BIT(28)
-+#  define MCP25XXFD_IOCON_SOF			BIT(29)
-+#  define MCP25XXFD_IOCON_INTOD			BIT(30)
-+#define MCP25XXFD_CRC				MCP25XXFD_SFR_BASE(0x08)
-+#  define MCP25XXFD_CRC_MASK			GENMASK(15, 0)
-+#  define MCP25XXFD_CRC_CRCERRIE		BIT(16)
-+#  define MCP25XXFD_CRC_FERRIE			BIT(17)
-+#  define MCP25XXFD_CRC_CRCERRIF		BIT(24)
-+#  define MCP25XXFD_CRC_FERRIF			BIT(25)
-+#define MCP25XXFD_ECCCON			MCP25XXFD_SFR_BASE(0x0C)
-+#  define MCP25XXFD_ECCCON_ECCEN		BIT(0)
-+#  define MCP25XXFD_ECCCON_SECIE		BIT(1)
-+#  define MCP25XXFD_ECCCON_DEDIE		BIT(2)
-+#  define MCP25XXFD_ECCCON_PARITY_BITS		6
-+#  define MCP25XXFD_ECCCON_PARITY_SHIFT		8
-+#  define MCP25XXFD_ECCCON_PARITY_MASK					\
-+	GENMASK(MCP25XXFD_ECCCON_PARITY_SHIFT				\
-+		+ MCP25XXFD_ECCCON_PARITY_BITS - 1,			\
-+		MCP25XXFD_ECCCON_PARITY_SHIFT)
-+#define MCP25XXFD_ECCSTAT			MCP25XXFD_SFR_BASE(0x10)
-+#  define MCP25XXFD_ECCSTAT_SECIF		BIT(1)
-+#  define MCP25XXFD_ECCSTAT_DEDIF		BIT(2)
-+#  define MCP25XXFD_ECCSTAT_ERRADDR_SHIFT	8
-+#  define MCP25XXFD_ECCSTAT_ERRADDR_MASK				\
-+	GENMASK(MCP25XXFD_ECCSTAT_ERRADDR_SHIFT + 11,			\
-+		MCP25XXFD_ECCSTAT_ERRADDR_SHIFT)
-+
-+/* CAN related register definitions of Controller CAN block */
-+#define MCP25XXFD_CAN_SFR_BASE(x)		(0x000 + (x))
-+#define MCP25XXFD_CAN_CON						\
-+	MCP25XXFD_CAN_SFR_BASE(0x00)
-+#  define MCP25XXFD_CAN_CON_DNCNT_BITS		5
-+#  define MCP25XXFD_CAN_CON_DNCNT_SHIFT		0
-+#  define MCP25XXFD_CAN_CON_DNCNT_MASK					\
-+	GENMASK(MCP25XXFD_CAN_CON_DNCNT_SHIFT +				\
-+		MCP25XXFD_CAN_CON_DNCNT_BITS - 1,			\
-+		MCP25XXFD_CAN_CON_DNCNT_SHIFT)
-+#  define MCP25XXFD_CAN_CON_ISOCRCEN		BIT(5)
-+#  define MCP25XXFD_CAN_CON_PXEDIS		BIT(6)
-+#  define MCP25XXFD_CAN_CON_WAKFIL		BIT(8)
-+#  define MCP25XXFD_CAN_CON_WFT_BITS		2
-+#  define MCP25XXFD_CAN_CON_WFT_SHIFT		9
-+#  define MCP25XXFD_CAN_CON_WFT_MASK					\
-+	GENMASK(MCP25XXFD_CAN_CON_WFT_SHIFT +				\
-+		MCP25XXFD_CAN_CON_WFT_BITS - 1,				\
-+		MCP25XXFD_CAN_CON_WFT_SHIFT)
-+#  define MCP25XXFD_CAN_CON_BUSY		BIT(11)
-+#  define MCP25XXFD_CAN_CON_BRSDIS		BIT(12)
-+#  define MCP25XXFD_CAN_CON_RTXAT		BIT(16)
-+#  define MCP25XXFD_CAN_CON_ESIGM		BIT(17)
-+#  define MCP25XXFD_CAN_CON_SERR2LOM		BIT(18)
-+#  define MCP25XXFD_CAN_CON_STEF		BIT(19)
-+#  define MCP25XXFD_CAN_CON_TXQEN		BIT(20)
-+#  define MCP25XXFD_CAN_CON_OPMODE_BITS		3
-+#  define MCP25XXFD_CAN_CON_OPMOD_SHIFT		21
-+#  define MCP25XXFD_CAN_CON_OPMOD_MASK					\
-+	GENMASK(MCP25XXFD_CAN_CON_OPMOD_SHIFT +				\
-+		MCP25XXFD_CAN_CON_OPMODE_BITS - 1,			\
-+		MCP25XXFD_CAN_CON_OPMOD_SHIFT)
-+#  define MCP25XXFD_CAN_CON_REQOP_BITS		3
-+#  define MCP25XXFD_CAN_CON_REQOP_SHIFT		24
-+#  define MCP25XXFD_CAN_CON_REQOP_MASK					\
-+	GENMASK(MCP25XXFD_CAN_CON_REQOP_SHIFT +				\
-+		MCP25XXFD_CAN_CON_REQOP_BITS - 1,			\
-+		MCP25XXFD_CAN_CON_REQOP_SHIFT)
-+#    define MCP25XXFD_CAN_CON_MODE_MIXED	0
-+#    define MCP25XXFD_CAN_CON_MODE_SLEEP	1
-+#    define MCP25XXFD_CAN_CON_MODE_INT_LOOPBACK	2
-+#    define MCP25XXFD_CAN_CON_MODE_LISTENONLY	3
-+#    define MCP25XXFD_CAN_CON_MODE_CONFIG	4
-+#    define MCP25XXFD_CAN_CON_MODE_EXT_LOOPBACK	5
-+#    define MCP25XXFD_CAN_CON_MODE_CAN2_0	6
-+#    define MCP25XXFD_CAN_CON_MODE_RESTRICTED	7
-+#  define MCP25XXFD_CAN_CON_ABAT		BIT(27)
-+#  define MCP25XXFD_CAN_CON_TXBWS_BITS		3
-+#  define MCP25XXFD_CAN_CON_TXBWS_SHIFT		28
-+#  define MCP25XXFD_CAN_CON_TXBWS_MASK					\
-+	GENMASK(MCP25XXFD_CAN_CON_TXBWS_SHIFT +				\
-+		MCP25XXFD_CAN_CON_TXBWS_BITS - 1,			\
-+		MCP25XXFD_CAN_CON_TXBWS_SHIFT)
-+#  define MCP25XXFD_CAN_CON_DEFAULT					\
-+	(MCP25XXFD_CAN_CON_ISOCRCEN |					\
-+	 MCP25XXFD_CAN_CON_PXEDIS |					\
-+	 MCP25XXFD_CAN_CON_WAKFIL |					\
-+	 (3 << MCP25XXFD_CAN_CON_WFT_SHIFT) |				\
-+	 MCP25XXFD_CAN_CON_STEF |					\
-+	 MCP25XXFD_CAN_CON_TXQEN |					\
-+	 (MCP25XXFD_CAN_CON_MODE_CONFIG << MCP25XXFD_CAN_CON_OPMOD_SHIFT) | \
-+	 (MCP25XXFD_CAN_CON_MODE_CONFIG << MCP25XXFD_CAN_CON_REQOP_SHIFT))
-+#  define MCP25XXFD_CAN_CON_DEFAULT_MASK				\
-+	(MCP25XXFD_CAN_CON_DNCNT_MASK |					\
-+	 MCP25XXFD_CAN_CON_ISOCRCEN |					\
-+	 MCP25XXFD_CAN_CON_PXEDIS |					\
-+	 MCP25XXFD_CAN_CON_WAKFIL |					\
-+	 MCP25XXFD_CAN_CON_WFT_MASK |					\
-+	 MCP25XXFD_CAN_CON_BRSDIS |					\
-+	 MCP25XXFD_CAN_CON_RTXAT |					\
-+	 MCP25XXFD_CAN_CON_ESIGM |					\
-+	 MCP25XXFD_CAN_CON_SERR2LOM |					\
-+	 MCP25XXFD_CAN_CON_STEF |					\
-+	 MCP25XXFD_CAN_CON_TXQEN |					\
-+	 MCP25XXFD_CAN_CON_OPMOD_MASK |					\
-+	 MCP25XXFD_CAN_CON_REQOP_MASK |					\
-+	 MCP25XXFD_CAN_CON_ABAT |					\
-+	 MCP25XXFD_CAN_CON_TXBWS_MASK)
-+#define MCP25XXFD_CAN_NBTCFG			MCP25XXFD_CAN_SFR_BASE(0x04)
-+#  define MCP25XXFD_CAN_NBTCFG_SJW_BITS		7
-+#  define MCP25XXFD_CAN_NBTCFG_SJW_SHIFT	0
-+#  define MCP25XXFD_CAN_NBTCFG_SJW_MASK					\
-+	GENMASK(MCP25XXFD_CAN_NBTCFG_SJW_SHIFT +			\
-+		MCP25XXFD_CAN_NBTCFG_SJW_BITS - 1,			\
-+		MCP25XXFD_CAN_NBTCFG_SJW_SHIFT)
-+#  define MCP25XXFD_CAN_NBTCFG_TSEG2_BITS	7
-+#  define MCP25XXFD_CAN_NBTCFG_TSEG2_SHIFT	8
-+#  define MCP25XXFD_CAN_NBTCFG_TSEG2_MASK				\
-+	GENMASK(MCP25XXFD_CAN_NBTCFG_TSEG2_SHIFT +			\
-+		MCP25XXFD_CAN_NBTCFG_TSEG2_BITS - 1,			\
-+		MCP25XXFD_CAN_NBTCFG_TSEG2_SHIFT)
-+#  define MCP25XXFD_CAN_NBTCFG_TSEG1_BITS	8
-+#  define MCP25XXFD_CAN_NBTCFG_TSEG1_SHIFT	16
-+#  define MCP25XXFD_CAN_NBTCFG_TSEG1_MASK				\
-+	GENMASK(MCP25XXFD_CAN_NBTCFG_TSEG1_SHIFT +			\
-+		MCP25XXFD_CAN_NBTCFG_TSEG1_BITS - 1,			\
-+		MCP25XXFD_CAN_NBTCFG_TSEG1_SHIFT)
-+#  define MCP25XXFD_CAN_NBTCFG_BRP_BITS		8
-+#  define MCP25XXFD_CAN_NBTCFG_BRP_SHIFT	24
-+#  define MCP25XXFD_CAN_NBTCFG_BRP_MASK					\
-+	GENMASK(MCP25XXFD_CAN_NBTCFG_BRP_SHIFT +			\
-+		MCP25XXFD_CAN_NBTCFG_BRP_BITS - 1,			\
-+		MCP25XXFD_CAN_NBTCFG_BRP_SHIFT)
-+#define MCP25XXFD_CAN_DBTCFG			MCP25XXFD_CAN_SFR_BASE(0x08)
-+#  define MCP25XXFD_CAN_DBTCFG_SJW_BITS		4
-+#  define MCP25XXFD_CAN_DBTCFG_SJW_SHIFT	0
-+#  define MCP25XXFD_CAN_DBTCFG_SJW_MASK					\
-+	GENMASK(MCP25XXFD_CAN_DBTCFG_SJW_SHIFT +			\
-+		MCP25XXFD_CAN_DBTCFG_SJW_BITS - 1,			\
-+		MCP25XXFD_CAN_DBTCFG_SJW_SHIFT)
-+#  define MCP25XXFD_CAN_DBTCFG_TSEG2_BITS	4
-+#  define MCP25XXFD_CAN_DBTCFG_TSEG2_SHIFT	8
-+#  define MCP25XXFD_CAN_DBTCFG_TSEG2_MASK				\
-+	GENMASK(MCP25XXFD_CAN_DBTCFG_TSEG2_SHIFT +			\
-+		MCP25XXFD_CAN_DBTCFG_TSEG2_BITS - 1,			\
-+		MCP25XXFD_CAN_DBTCFG_TSEG2_SHIFT)
-+#  define MCP25XXFD_CAN_DBTCFG_TSEG1_BITS	5
-+#  define MCP25XXFD_CAN_DBTCFG_TSEG1_SHIFT	16
-+#  define MCP25XXFD_CAN_DBTCFG_TSEG1_MASK				\
-+	GENMASK(MCP25XXFD_CAN_DBTCFG_TSEG1_SHIFT +			\
-+		MCP25XXFD_CAN_DBTCFG_TSEG1_BITS - 1,			\
-+		MCP25XXFD_CAN_DBTCFG_TSEG1_SHIFT)
-+#  define MCP25XXFD_CAN_DBTCFG_BRP_BITS		8
-+#  define MCP25XXFD_CAN_DBTCFG_BRP_SHIFT	24
-+#  define MCP25XXFD_CAN_DBTCFG_BRP_MASK					\
-+	GENMASK(MCP25XXFD_CAN_DBTCFG_BRP_SHIFT +			\
-+		MCP25XXFD_CAN_DBTCFG_BRP_BITS - 1,			\
-+		MCP25XXFD_CAN_DBTCFG_BRP_SHIFT)
-+#define MCP25XXFD_CAN_TDC			MCP25XXFD_CAN_SFR_BASE(0x0C)
-+#  define MCP25XXFD_CAN_TDC_TDCV_BITS		5
-+#  define MCP25XXFD_CAN_TDC_TDCV_SHIFT		0
-+#  define MCP25XXFD_CAN_TDC_TDCV_MASK					\
-+	GENMASK(MCP25XXFD_CAN_TDC_TDCV_SHIFT +				\
-+		MCP25XXFD_CAN_TDC_TDCV_BITS - 1,			\
-+		MCP25XXFD_CAN_TDC_TDCV_SHIFT)
-+#  define MCP25XXFD_CAN_TDC_TDCO_BITS		5
-+#  define MCP25XXFD_CAN_TDC_TDCO_SHIFT		8
-+#  define MCP25XXFD_CAN_TDC_TDCO_MASK					\
-+	GENMASK(MCP25XXFD_CAN_TDC_TDCO_SHIFT +				\
-+		MCP25XXFD_CAN_TDC_TDCO_BITS - 1,			\
-+		MCP25XXFD_CAN_TDC_TDCO_SHIFT)
-+#  define MCP25XXFD_CAN_TDC_TDCMOD_BITS		2
-+#  define MCP25XXFD_CAN_TDC_TDCMOD_SHIFT	16
-+#  define MCP25XXFD_CAN_TDC_TDCMOD_MASK					\
-+	GENMASK(MCP25XXFD_CAN_TDC_TDCMOD_SHIFT +			\
-+		MCP25XXFD_CAN_TDC_TDCMOD_BITS - 1,			\
-+		MCP25XXFD_CAN_TDC_TDCMOD_SHIFT)
-+#  define MCP25XXFD_CAN_TDC_TDCMOD_DISABLED	0
-+#  define MCP25XXFD_CAN_TDC_TDCMOD_MANUAL	1
-+#  define MCP25XXFD_CAN_TDC_TDCMOD_AUTO		2
-+#  define MCP25XXFD_CAN_TDC_SID11EN		BIT(24)
-+#  define MCP25XXFD_CAN_TDC_EDGFLTEN		BIT(25)
-+#define MCP25XXFD_CAN_TBC			MCP25XXFD_CAN_SFR_BASE(0x10)
-+#define MCP25XXFD_CAN_TSCON			MCP25XXFD_CAN_SFR_BASE(0x14)
-+#  define MCP25XXFD_CAN_TSCON_TBCPRE_BITS	10
-+#  define MCP25XXFD_CAN_TSCON_TBCPRE_SHIFT	0
-+#  define MCP25XXFD_CAN_TSCON_TBCPRE_MASK				\
-+	GENMASK(MCP25XXFD_CAN_TSCON_TBCPRE_SHIFT +			\
-+		MCP25XXFD_CAN_TSCON_TBCPRE_BITS - 1,			\
-+		MCP25XXFD_CAN_TSCON_TBCPRE_SHIFT)
-+#  define MCP25XXFD_CAN_TSCON_TBCEN		BIT(16)
-+#  define MCP25XXFD_CAN_TSCON_TSEOF		BIT(17)
-+#  define MCP25XXFD_CAN_TSCON_TSRES		BIT(18)
-+#define MCP25XXFD_CAN_VEC			MCP25XXFD_CAN_SFR_BASE(0x18)
-+#  define MCP25XXFD_CAN_VEC_ICODE_BITS		7
-+#  define MCP25XXFD_CAN_VEC_ICODE_SHIFT		0
-+#  define MCP25XXFD_CAN_VEC_ICODE_MASK					\
-+	GENMASK(MCP25XXFD_CAN_VEC_ICODE_SHIFT +				\
-+		MCP25XXFD_CAN_VEC_ICODE_BITS - 1,			\
-+		MCP25XXFD_CAN_VEC_ICODE_SHIFT)
-+#  define MCP25XXFD_CAN_VEC_FILHIT_BITS		5
-+#  define MCP25XXFD_CAN_VEC_FILHIT_SHIFT	8
-+#  define MCP25XXFD_CAN_VEC_FILHIT_MASK					\
-+	GENMASK(MCP25XXFD_CAN_VEC_FILHIT_SHIFT +			\
-+		MCP25XXFD_CAN_VEC_FILHIT_BITS - 1,			\
-+		MCP25XXFD_CAN_VEC_FILHIT_SHIFT)
-+#  define MCP25XXFD_CAN_VEC_TXCODE_BITS		7
-+#  define MCP25XXFD_CAN_VEC_TXCODE_SHIFT	16
-+#  define MCP25XXFD_CAN_VEC_TXCODE_MASK					\
-+	GENMASK(MCP25XXFD_CAN_VEC_TXCODE_SHIFT +			\
-+		MCP25XXFD_CAN_VEC_TXCODE_BITS - 1,			\
-+		MCP25XXFD_CAN_VEC_TXCODE_SHIFT)
-+#  define MCP25XXFD_CAN_VEC_RXCODE_BITS		7
-+#  define MCP25XXFD_CAN_VEC_RXCODE_SHIFT	24
-+#  define MCP25XXFD_CAN_VEC_RXCODE_MASK					\
-+	GENMASK(MCP25XXFD_CAN_VEC_RXCODE_SHIFT +			\
-+		MCP25XXFD_CAN_VEC_RXCODE_BITS - 1,			\
-+		MCP25XXFD_CAN_VEC_RXCODE_SHIFT)
-+#define MCP25XXFD_CAN_INT			MCP25XXFD_CAN_SFR_BASE(0x1C)
-+#  define MCP25XXFD_CAN_INT_IF_SHIFT		0
-+#  define MCP25XXFD_CAN_INT_TXIF		BIT(0)
-+#  define MCP25XXFD_CAN_INT_RXIF		BIT(1)
-+#  define MCP25XXFD_CAN_INT_TBCIF		BIT(2)
-+#  define MCP25XXFD_CAN_INT_MODIF		BIT(3)
-+#  define MCP25XXFD_CAN_INT_TEFIF		BIT(4)
-+#  define MCP25XXFD_CAN_INT_ECCIF		BIT(8)
-+#  define MCP25XXFD_CAN_INT_SPICRCIF		BIT(9)
-+#  define MCP25XXFD_CAN_INT_TXATIF		BIT(10)
-+#  define MCP25XXFD_CAN_INT_RXOVIF		BIT(11)
-+#  define MCP25XXFD_CAN_INT_SERRIF		BIT(12)
-+#  define MCP25XXFD_CAN_INT_CERRIF		BIT(13)
-+#  define MCP25XXFD_CAN_INT_WAKIF		BIT(14)
-+#  define MCP25XXFD_CAN_INT_IVMIF		BIT(15)
-+#  define MCP25XXFD_CAN_INT_IF_MASK					\
-+	(MCP25XXFD_CAN_INT_TXIF |					\
-+	 MCP25XXFD_CAN_INT_RXIF |					\
-+	 MCP25XXFD_CAN_INT_TBCIF |					\
-+	 MCP25XXFD_CAN_INT_MODIF |					\
-+	 MCP25XXFD_CAN_INT_TEFIF |					\
-+	 MCP25XXFD_CAN_INT_ECCIF |					\
-+	 MCP25XXFD_CAN_INT_SPICRCIF |					\
-+	 MCP25XXFD_CAN_INT_TXATIF |					\
-+	 MCP25XXFD_CAN_INT_RXOVIF |					\
-+	 MCP25XXFD_CAN_INT_CERRIF |					\
-+	 MCP25XXFD_CAN_INT_SERRIF |					\
-+	 MCP25XXFD_CAN_INT_WAKIF |					\
-+	 MCP25XXFD_CAN_INT_IVMIF)
-+#  define MCP25XXFD_CAN_INT_IF_CLEAR_MASK				\
-+	(MCP25XXFD_CAN_INT_TBCIF  |					\
-+	 MCP25XXFD_CAN_INT_MODIF  |					\
-+	 MCP25XXFD_CAN_INT_CERRIF |					\
-+	 MCP25XXFD_CAN_INT_SERRIF |					\
-+	 MCP25XXFD_CAN_INT_WAKIF |					\
-+	 MCP25XXFD_CAN_INT_IVMIF)
-+#  define MCP25XXFD_CAN_INT_IE_SHIFT		16
-+#  define MCP25XXFD_CAN_INT_TXIE					\
-+	(MCP25XXFD_CAN_INT_TXIF << MCP25XXFD_CAN_INT_IE_SHIFT)
-+#  define MCP25XXFD_CAN_INT_RXIE					\
-+	(MCP25XXFD_CAN_INT_RXIF << MCP25XXFD_CAN_INT_IE_SHIFT)
-+#  define MCP25XXFD_CAN_INT_TBCIE					\
-+	(MCP25XXFD_CAN_INT_TBCIF << MCP25XXFD_CAN_INT_IE_SHIFT)
-+#  define MCP25XXFD_CAN_INT_MODIE					\
-+	(MCP25XXFD_CAN_INT_MODIF << MCP25XXFD_CAN_INT_IE_SHIFT)
-+#  define MCP25XXFD_CAN_INT_TEFIE					\
-+	(MCP25XXFD_CAN_INT_TEFIF << MCP25XXFD_CAN_INT_IE_SHIFT)
-+#  define MCP25XXFD_CAN_INT_ECCIE					\
-+	(MCP25XXFD_CAN_INT_ECCIF << MCP25XXFD_CAN_INT_IE_SHIFT)
-+#  define MCP25XXFD_CAN_INT_SPICRCIE					\
-+	(MCP25XXFD_CAN_INT_SPICRCIF << MCP25XXFD_CAN_INT_IE_SHIFT)
-+#  define MCP25XXFD_CAN_INT_TXATIE					\
-+	(MCP25XXFD_CAN_INT_TXATIF << MCP25XXFD_CAN_INT_IE_SHIFT)
-+#  define MCP25XXFD_CAN_INT_RXOVIE					\
-+	(MCP25XXFD_CAN_INT_RXOVIF << MCP25XXFD_CAN_INT_IE_SHIFT)
-+#  define MCP25XXFD_CAN_INT_CERRIE					\
-+	(MCP25XXFD_CAN_INT_CERRIF << MCP25XXFD_CAN_INT_IE_SHIFT)
-+#  define MCP25XXFD_CAN_INT_SERRIE					\
-+	(MCP25XXFD_CAN_INT_SERRIF << MCP25XXFD_CAN_INT_IE_SHIFT)
-+#  define MCP25XXFD_CAN_INT_WAKIE					\
-+	(MCP25XXFD_CAN_INT_WAKIF << MCP25XXFD_CAN_INT_IE_SHIFT)
-+#  define MCP25XXFD_CAN_INT_IVMIE					\
-+	(MCP25XXFD_CAN_INT_IVMIF << MCP25XXFD_CAN_INT_IE_SHIFT)
-+#  define MCP25XXFD_CAN_INT_IE_MASK					\
-+	(MCP25XXFD_CAN_INT_TXIE |					\
-+	 MCP25XXFD_CAN_INT_RXIE |					\
-+	 MCP25XXFD_CAN_INT_TBCIE |					\
-+	 MCP25XXFD_CAN_INT_MODIE |					\
-+	 MCP25XXFD_CAN_INT_TEFIE |					\
-+	 MCP25XXFD_CAN_INT_ECCIE |					\
-+	 MCP25XXFD_CAN_INT_SPICRCIE |					\
-+	 MCP25XXFD_CAN_INT_TXATIE |					\
-+	 MCP25XXFD_CAN_INT_RXOVIE |					\
-+	 MCP25XXFD_CAN_INT_CERRIE |					\
-+	 MCP25XXFD_CAN_INT_SERRIE |					\
-+	 MCP25XXFD_CAN_INT_WAKIE |					\
-+	 MCP25XXFD_CAN_INT_IVMIE)
-+#define MCP25XXFD_CAN_RXIF			MCP25XXFD_CAN_SFR_BASE(0x20)
-+#define MCP25XXFD_CAN_TXIF			MCP25XXFD_CAN_SFR_BASE(0x24)
-+#define MCP25XXFD_CAN_RXOVIF			MCP25XXFD_CAN_SFR_BASE(0x28)
-+#define MCP25XXFD_CAN_TXATIF			MCP25XXFD_CAN_SFR_BASE(0x2C)
-+#define MCP25XXFD_CAN_TXREQ			MCP25XXFD_CAN_SFR_BASE(0x30)
-+#define MCP25XXFD_CAN_TREC			MCP25XXFD_CAN_SFR_BASE(0x34)
-+#  define MCP25XXFD_CAN_TREC_REC_BITS		8
-+#  define MCP25XXFD_CAN_TREC_REC_SHIFT		0
-+#  define MCP25XXFD_CAN_TREC_REC_MASK					\
-+	GENMASK(MCP25XXFD_CAN_TREC_REC_SHIFT +				\
-+		MCP25XXFD_CAN_TREC_REC_BITS - 1,			\
-+		MCP25XXFD_CAN_TREC_REC_SHIFT)
-+#  define MCP25XXFD_CAN_TREC_TEC_BITS		8
-+#  define MCP25XXFD_CAN_TREC_TEC_SHIFT		8
-+#  define MCP25XXFD_CAN_TREC_TEC_MASK					\
-+	GENMASK(MCP25XXFD_CAN_TREC_TEC_SHIFT +				\
-+		MCP25XXFD_CAN_TREC_TEC_BITS - 1,			\
-+		MCP25XXFD_CAN_TREC_TEC_SHIFT)
-+#  define MCP25XXFD_CAN_TREC_EWARN		BIT(16)
-+#  define MCP25XXFD_CAN_TREC_RXWARN		BIT(17)
-+#  define MCP25XXFD_CAN_TREC_TXWARN		BIT(18)
-+#  define MCP25XXFD_CAN_TREC_RXBP		BIT(19)
-+#  define MCP25XXFD_CAN_TREC_TXBP		BIT(20)
-+#  define MCP25XXFD_CAN_TREC_TXBO		BIT(21)
-+#define MCP25XXFD_CAN_BDIAG0			MCP25XXFD_CAN_SFR_BASE(0x38)
-+#  define MCP25XXFD_CAN_BDIAG0_NRERRCNT_BITS	8
-+#  define MCP25XXFD_CAN_BDIAG0_NRERRCNT_SHIFT	0
-+#  define MCP25XXFD_CAN_BDIAG0_NRERRCNT_MASK				\
-+	GENMASK(MCP25XXFD_CAN_BDIAG0_NRERRCNT_SHIFT +			\
-+		MCP25XXFD_CAN_BDIAG0_NRERRCNT_BITS - 1,			\
-+		MCP25XXFD_CAN_BDIAG0_NRERRCNT_SHIFT)
-+#  define MCP25XXFD_CAN_BDIAG0_NTERRCNT_BITS	8
-+#  define MCP25XXFD_CAN_BDIAG0_NTERRCNT_SHIFT	8
-+#  define MCP25XXFD_CAN_BDIAG0_NTERRCNT_MASK				\
-+	GENMASK(MCP25XXFD_CAN_BDIAG0_NTERRCNT_SHIFT +			\
-+		MCP25XXFD_CAN_BDIAG0_NTERRCNT_BITS - 1,			\
-+		MCP25XXFD_CAN_BDIAG0_NTERRCNT_SHIFT)
-+#  define MCP25XXFD_CAN_BDIAG0_DRERRCNT_BITS	8
-+#  define MCP25XXFD_CAN_BDIAG0_DRERRCNT_SHIFT	16
-+#  define MCP25XXFD_CAN_BDIAG0_DRERRCNT_MASK				\
-+	GENMASK(MCP25XXFD_CAN_BDIAG0_DRERRCNT_SHIFT +			\
-+		MCP25XXFD_CAN_BDIAG0_DRERRCNT_BITS - 1,			\
-+		MCP25XXFD_CAN_BDIAG0_DRERRCNT_SHIFT)
-+#  define MCP25XXFD_CAN_BDIAG0_DTERRCNT_BITS	8
-+#  define MCP25XXFD_CAN_BDIAG0_DTERRCNT_SHIFT	24
-+#  define MCP25XXFD_CAN_BDIAG0_DTERRCNT_MASK				\
-+	GENMASK(MCP25XXFD_CAN_BDIAG0_DTERRCNT_SHIFT +			\
-+		MCP25XXFD_CAN_BDIAG0_DTERRCNT_BITS - 1,			\
-+		MCP25XXFD_CAN_BDIAG0_DTERRCNT_SHIFT)
-+#define MCP25XXFD_CAN_BDIAG1			MCP25XXFD_CAN_SFR_BASE(0x3C)
-+#  define MCP25XXFD_CAN_BDIAG1_EFMSGCNT_BITS	16
-+#  define MCP25XXFD_CAN_BDIAG1_EFMSGCNT_SHIFT	0
-+#  define MCP25XXFD_CAN_BDIAG1_EFMSGCNT_MASK				\
-+	GENMASK(MCP25XXFD_CAN_BDIAG1_EFMSGCNT_SHIFT +			\
-+		MCP25XXFD_CAN_BDIAG1_EFMSGCNT_BITS - 1,			\
-+		MCP25XXFD_CAN_BDIAG1_EFMSGCNT_SHIFT)
-+#  define MCP25XXFD_CAN_BDIAG1_NBIT0ERR		BIT(16)
-+#  define MCP25XXFD_CAN_BDIAG1_NBIT1ERR		BIT(17)
-+#  define MCP25XXFD_CAN_BDIAG1_NACKERR		BIT(18)
-+#  define MCP25XXFD_CAN_BDIAG1_NSTUFERR		BIT(19)
-+#  define MCP25XXFD_CAN_BDIAG1_NFORMERR		BIT(20)
-+#  define MCP25XXFD_CAN_BDIAG1_NCRCERR		BIT(21)
-+#  define MCP25XXFD_CAN_BDIAG1_TXBOERR		BIT(23)
-+#  define MCP25XXFD_CAN_BDIAG1_DBIT0ERR		BIT(24)
-+#  define MCP25XXFD_CAN_BDIAG1_DBIT1ERR		BIT(25)
-+#  define MCP25XXFD_CAN_BDIAG1_DFORMERR		BIT(27)
-+#  define MCP25XXFD_CAN_BDIAG1_DSTUFERR		BIT(28)
-+#  define MCP25XXFD_CAN_BDIAG1_DCRCERR		BIT(29)
-+#  define MCP25XXFD_CAN_BDIAG1_ESI		BIT(30)
-+#  define MCP25XXFD_CAN_BDIAG1_DLCMM		BIT(31)
-+#define MCP25XXFD_CAN_TEFCON			MCP25XXFD_CAN_SFR_BASE(0x40)
-+#  define MCP25XXFD_CAN_TEFCON_TEFNEIE		BIT(0)
-+#  define MCP25XXFD_CAN_TEFCON_TEFHIE		BIT(1)
-+#  define MCP25XXFD_CAN_TEFCON_TEFFIE		BIT(2)
-+#  define MCP25XXFD_CAN_TEFCON_TEFOVIE		BIT(3)
-+#  define MCP25XXFD_CAN_TEFCON_TEFTSEN		BIT(5)
-+#  define MCP25XXFD_CAN_TEFCON_UINC		BIT(8)
-+#  define MCP25XXFD_CAN_TEFCON_FRESET		BIT(10)
-+#  define MCP25XXFD_CAN_TEFCON_FSIZE_BITS	5
-+#  define MCP25XXFD_CAN_TEFCON_FSIZE_SHIFT	24
-+#  define MCP25XXFD_CAN_TEFCON_FSIZE_MASK				\
-+	GENMASK(MCP25XXFD_CAN_TEFCON_FSIZE_SHIFT +			\
-+		MCP25XXFD_CAN_TEFCON_FSIZE_BITS - 1,			\
-+		MCP25XXFD_CAN_TEFCON_FSIZE_SHIFT)
-+#define MCP25XXFD_CAN_TEFSTA			MCP25XXFD_CAN_SFR_BASE(0x44)
-+#  define MCP25XXFD_CAN_TEFSTA_TEFNEIF		BIT(0)
-+#  define MCP25XXFD_CAN_TEFSTA_TEFHIF		BIT(1)
-+#  define MCP25XXFD_CAN_TEFSTA_TEFFIF		BIT(2)
-+#  define MCP25XXFD_CAN_TEFSTA_TEVOVIF		BIT(3)
-+#define MCP25XXFD_CAN_TEFUA			MCP25XXFD_CAN_SFR_BASE(0x48)
-+#define MCP25XXFD_CAN_RESERVED			MCP25XXFD_CAN_SFR_BASE(0x4C)
-+#define MCP25XXFD_CAN_TXQCON			MCP25XXFD_CAN_SFR_BASE(0x50)
-+#  define MCP25XXFD_CAN_TXQCON_TXQNIE		BIT(0)
-+#  define MCP25XXFD_CAN_TXQCON_TXQEIE		BIT(2)
-+#  define MCP25XXFD_CAN_TXQCON_TXATIE		BIT(4)
-+#  define MCP25XXFD_CAN_TXQCON_TXEN		BIT(7)
-+#  define MCP25XXFD_CAN_TXQCON_UINC		BIT(8)
-+#  define MCP25XXFD_CAN_TXQCON_TXREQ		BIT(9)
-+#  define MCP25XXFD_CAN_TXQCON_FRESET		BIT(10)
-+#  define MCP25XXFD_CAN_TXQCON_TXPRI_BITS	5
-+#  define MCP25XXFD_CAN_TXQCON_TXPRI_SHIFT	16
-+#  define MCP25XXFD_CAN_TXQCON_TXPRI_MASK				\
-+	GENMASK(MCP25XXFD_CAN_TXQCON_TXPRI_SHIFT +			\
-+		MCP25XXFD_CAN_TXQCON_TXPRI_BITS - 1,			\
-+		MCP25XXFD_CAN_TXQCON_TXPRI_SHIFT)
-+#  define MCP25XXFD_CAN_TXQCON_TXAT_BITS	2
-+#  define MCP25XXFD_CAN_TXQCON_TXAT_SHIFT	21
-+#  define MCP25XXFD_CAN_TXQCON_TXAT_MASK				\
-+	GENMASK(MCP25XXFD_CAN_TXQCON_TXAT_SHIFT +			\
-+		#MCP25XXFD_CAN_TXQCON_TXAT_BITS - 1,			\
-+		MCP25XXFD_CAN_TXQCON_TXAT_SHIFT)
-+#  define MCP25XXFD_CAN_TXQCON_FSIZE_BITS	5
-+#  define MCP25XXFD_CAN_TXQCON_FSIZE_SHIFT	24
-+#  define MCP25XXFD_CAN_TXQCON_FSIZE_MASK				\
-+	GENMASK(MCP25XXFD_CAN_TXQCON_FSIZE_SHIFT +			\
-+		MCP25XXFD_CAN_TXQCON_FSIZE_BITS - 1,			\
-+		MCP25XXFD_CAN_TXQCON_FSIZE_SHIFT)
-+#  define MCP25XXFD_CAN_TXQCON_PLSIZE_BITS	3
-+#  define MCP25XXFD_CAN_TXQCON_PLSIZE_SHIFT	29
-+#  define MCP25XXFD_CAN_TXQCON_PLSIZE_MASK				\
-+	GENMASK(MCP25XXFD_CAN_TXQCON_PLSIZE_SHIFT +			\
-+		MCP25XXFD_CAN_TXQCON_PLSIZE_BITS - 1,			\
-+		MCP25XXFD_CAN_TXQCON_PLSIZE_SHIFT)
-+#    define MCP25XXFD_CAN_TXQCON_PLSIZE_8	0
-+#    define MCP25XXFD_CAN_TXQCON_PLSIZE_12	1
-+#    define MCP25XXFD_CAN_TXQCON_PLSIZE_16	2
-+#    define MCP25XXFD_CAN_TXQCON_PLSIZE_20	3
-+#    define MCP25XXFD_CAN_TXQCON_PLSIZE_24	4
-+#    define MCP25XXFD_CAN_TXQCON_PLSIZE_32	5
-+#    define MCP25XXFD_CAN_TXQCON_PLSIZE_48	6
-+#    define MCP25XXFD_CAN_TXQCON_PLSIZE_64	7
-+
-+#define MCP25XXFD_CAN_TXQSTA			MCP25XXFD_CAN_SFR_BASE(0x54)
-+#  define MCP25XXFD_CAN_TXQSTA_TXQNIF		BIT(0)
-+#  define MCP25XXFD_CAN_TXQSTA_TXQEIF		BIT(2)
-+#  define MCP25XXFD_CAN_TXQSTA_TXATIF		BIT(4)
-+#  define MCP25XXFD_CAN_TXQSTA_TXERR		BIT(5)
-+#  define MCP25XXFD_CAN_TXQSTA_TXLARB		BIT(6)
-+#  define MCP25XXFD_CAN_TXQSTA_TXABT		BIT(7)
-+#  define MCP25XXFD_CAN_TXQSTA_TXQCI_BITS	5
-+#  define MCP25XXFD_CAN_TXQSTA_TXQCI_SHIFT	8
-+#  define MCP25XXFD_CAN_TXQSTA_TXQCI_MASK				\
-+	GENMASK(MCP25XXFD_CAN_TXQSTA_TXQCI_SHIFT +			\
-+		MCP25XXFD_CAN_TXQSTA_TXQCI_BITS - 1,			\
-+		MCP25XXFD_CAN_TXQSTA_TXQCI_SHIFT)
-+
-+#define MCP25XXFD_CAN_TXQUA			MCP25XXFD_CAN_SFR_BASE(0x58)
-+#define MCP25XXFD_CAN_FIFOCON(x)					\
-+	MCP25XXFD_CAN_SFR_BASE(0x5C + 12 * ((x) - 1))
-+#define MCP25XXFD_CAN_FIFOCON_TFNRFNIE		BIT(0)
-+#define MCP25XXFD_CAN_FIFOCON_TFHRFHIE		BIT(1)
-+#define MCP25XXFD_CAN_FIFOCON_TFERFFIE		BIT(2)
-+#define MCP25XXFD_CAN_FIFOCON_RXOVIE		BIT(3)
-+#define MCP25XXFD_CAN_FIFOCON_TXATIE		BIT(4)
-+#define MCP25XXFD_CAN_FIFOCON_RXTSEN		BIT(5)
-+#define MCP25XXFD_CAN_FIFOCON_RTREN		BIT(6)
-+#define MCP25XXFD_CAN_FIFOCON_TXEN		BIT(7)
-+#define MCP25XXFD_CAN_FIFOCON_UINC		BIT(8)
-+#define MCP25XXFD_CAN_FIFOCON_TXREQ		BIT(9)
-+#define MCP25XXFD_CAN_FIFOCON_FRESET		BIT(10)
-+#  define MCP25XXFD_CAN_FIFOCON_TXPRI_BITS	5
-+#  define MCP25XXFD_CAN_FIFOCON_TXPRI_SHIFT	16
-+#  define MCP25XXFD_CAN_FIFOCON_TXPRI_MASK				\
-+	GENMASK(MCP25XXFD_CAN_FIFOCON_TXPRI_SHIFT +			\
-+		MCP25XXFD_CAN_FIFOCON_TXPRI_BITS - 1,			\
-+		MCP25XXFD_CAN_FIFOCON_TXPRI_SHIFT)
-+#  define MCP25XXFD_CAN_FIFOCON_TXAT_BITS	2
-+#  define MCP25XXFD_CAN_FIFOCON_TXAT_SHIFT	21
-+#  define MCP25XXFD_CAN_FIFOCON_TXAT_MASK				\
-+	GENMASK(MCP25XXFD_CAN_FIFOCON_TXAT_SHIFT +			\
-+		MCP25XXFD_CAN_FIFOCON_TXAT_BITS - 1,			\
-+		MCP25XXFD_CAN_FIFOCON_TXAT_SHIFT)
-+#  define MCP25XXFD_CAN_FIFOCON_TXAT_ONE_SHOT	0
-+#  define MCP25XXFD_CAN_FIFOCON_TXAT_THREE_SHOT	1
-+#  define MCP25XXFD_CAN_FIFOCON_TXAT_UNLIMITED	2
-+#  define MCP25XXFD_CAN_FIFOCON_FSIZE_BITS	5
-+#  define MCP25XXFD_CAN_FIFOCON_FSIZE_SHIFT	24
-+#  define MCP25XXFD_CAN_FIFOCON_FSIZE_MASK				\
-+	GENMASK(MCP25XXFD_CAN_FIFOCON_FSIZE_SHIFT +			\
-+		MCP25XXFD_CAN_FIFOCON_FSIZE_BITS - 1,			\
-+		MCP25XXFD_CAN_FIFOCON_FSIZE_SHIFT)
-+#  define MCP25XXFD_CAN_FIFOCON_PLSIZE_BITS	3
-+#  define MCP25XXFD_CAN_FIFOCON_PLSIZE_SHIFT	29
-+#  define MCP25XXFD_CAN_FIFOCON_PLSIZE_MASK				\
-+	GENMASK(MCP25XXFD_CAN_FIFOCON_PLSIZE_SHIFT +			\
-+		MCP25XXFD_CAN_FIFOCON_PLSIZE_BITS - 1,			\
-+		MCP25XXFD_CAN_FIFOCON_PLSIZE_SHIFT)
-+#define MCP25XXFD_CAN_FIFOSTA(x)					\
-+	MCP25XXFD_CAN_SFR_BASE(0x60 + 12 * ((x) - 1))
-+#  define MCP25XXFD_CAN_FIFOSTA_TFNRFNIF	BIT(0)
-+#  define MCP25XXFD_CAN_FIFOSTA_TFHRFHIF	BIT(1)
-+#  define MCP25XXFD_CAN_FIFOSTA_TFERFFIF	BIT(2)
-+#  define MCP25XXFD_CAN_FIFOSTA_RXOVIF		BIT(3)
-+#  define MCP25XXFD_CAN_FIFOSTA_TXATIF		BIT(4)
-+#  define MCP25XXFD_CAN_FIFOSTA_TXERR		BIT(5)
-+#  define MCP25XXFD_CAN_FIFOSTA_TXLARB		BIT(6)
-+#  define MCP25XXFD_CAN_FIFOSTA_TXABT		BIT(7)
-+#  define MCP25XXFD_CAN_FIFOSTA_FIFOCI_BITS	5
-+#  define MCP25XXFD_CAN_FIFOSTA_FIFOCI_SHIFT	8
-+#  define MCP25XXFD_CAN_FIFOSTA_FIFOCI_MASK				\
-+	GENMASK(MCP25XXFD_CAN_FIFOSTA_FIFOCI_SHIFT +			\
-+		MCP25XXFD_CAN_FIFOSTA_FIFOCI_BITS - 1,			\
-+		MCP25XXFD_CAN_FIFOSTA_FIFOCI_SHIFT)
-+#define MCP25XXFD_CAN_FIFOUA(x)						\
-+	MCP25XXFD_CAN_SFR_BASE(0x64 + 12 * ((x) - 1))
-+#define MCP25XXFD_CAN_FLTCON(x)						\
-+	MCP25XXFD_CAN_SFR_BASE(0x1D0 + ((x) & 0x1c))
-+#  define MCP25XXFD_CAN_FILCON_SHIFT(x)		(((x) & 3) * 8)
-+#  define MCP25XXFD_CAN_FILCON_BITS(x)		MCP25XXFD_CAN_FILCON_BITS_
-+#  define MCP25XXFD_CAN_FILCON_BITS_		4
-+	/* avoid macro reuse warning, so do not use GENMASK as above */
-+#  define MCP25XXFD_CAN_FILCON_MASK(x)					\
-+	(GENMASK(MCP25XXFD_CAN_FILCON_BITS_ - 1, 0) <<			\
-+	 MCP25XXFD_CAN_FILCON_SHIFT(x))
-+#  define MCP25XXFD_CAN_FIFOCON_FLTEN(x)				\
-+	BIT(7 + MCP25XXFD_CAN_FILCON_SHIFT(x))
-+#define MCP25XXFD_CAN_FLTOBJ(x)						\
-+	MCP25XXFD_CAN_SFR_BASE(0x1F0 + 8 * (x))
-+#  define MCP25XXFD_CAN_FILOBJ_SID_BITS		11
-+#  define MCP25XXFD_CAN_FILOBJ_SID_SHIFT	0
-+#  define MCP25XXFD_CAN_FILOBJ_SID_MASK					\
-+	GENMASK(MCP25XXFD_CAN_FILOBJ_SID_SHIFT +			\
-+		MCP25XXFD_CAN_FILOBJ_SID_BITS - 1,			\
-+		MCP25XXFD_CAN_FILOBJ_SID_SHIFT)
-+#  define MCP25XXFD_CAN_FILOBJ_EID_BITS		18
-+#  define MCP25XXFD_CAN_FILOBJ_EID_SHIFT	12
-+#  define MCP25XXFD_CAN_FILOBJ_EID_MASK					\
-+	GENMASK(MCP25XXFD_CAN_FILOBJ_EID_SHIFT +			\
-+		MCP25XXFD_CAN_FILOBJ_EID_BITS - 1,			\
-+		MCP25XXFD_CAN_FILOBJ_EID_SHIFT)
-+#  define MCP25XXFD_CAN_FILOBJ_SID11		BIT(29)
-+#  define MCP25XXFD_CAN_FILOBJ_EXIDE		BIT(30)
-+#define MCP25XXFD_CAN_FLTMASK(x)					\
-+	MCP25XXFD_CAN_SFR_BASE(0x1F4 + 8 * (x))
-+#  define MCP25XXFD_CAN_FILMASK_MSID_BITS	11
-+#  define MCP25XXFD_CAN_FILMASK_MSID_SHIFT	0
-+#  define MCP25XXFD_CAN_FILMASK_MSID_MASK				\
-+	GENMASK(MCP25XXFD_CAN_FILMASK_MSID_SHIFT +			\
-+		MCP25XXFD_CAN_FILMASK_MSID_BITS - 1,			\
-+		MCP25XXFD_CAN_FILMASK_MSID_SHIFT)
-+#  define MCP25XXFD_CAN_FILMASK_MEID_BITS	18
-+#  define MCP25XXFD_CAN_FILMASK_MEID_SHIFT	12
-+#  define MCP25XXFD_CAN_FILMASK_MEID_MASK				\
-+	GENMASK(MCP25XXFD_CAN_FILMASK_MEID_SHIFT +			\
-+		MCP25XXFD_CAN_FILMASK_MEID_BITS - 1,			\
-+		MCP25XXFD_CAN_FILMASK_MEID_SHIFT)
-+#  define MCP25XXFD_CAN_FILMASK_MSID11		BIT(29)
-+#  define MCP25XXFD_CAN_FILMASK_MIDE		BIT(30)
-+
-+/* the FIFO Objects in SRAM */
-+#define MCP25XXFD_SRAM_SIZE 2048
-+#define MCP25XXFD_SRAM_ADDR(x) (0x400 + (x))
-+
-+/* memory structure in sram for tx fifos */
-+struct mcp25xxfd_can_obj_tx {
-+	u32 id;
-+	u32 flags;
-+	u8 data[];
-+};
-+
-+/* memory structure in sram for rx fifos */
-+struct mcp25xxfd_can_obj_rx {
-+	u32 id;
-+	u32 flags;
-+	u32 ts;
-+	u8 data[];
-+};
-+
-+/* memory structure in sram for tef fifos */
-+struct mcp25xxfd_can_obj_tef {
-+	u32 id;
-+	u32 flags;
-+	u32 ts;
-+};
-+
-+#define MCP25XXFD_CAN_OBJ_ID_SID_BITS		11
-+#define MCP25XXFD_CAN_OBJ_ID_SID_SHIFT		0
-+#define MCP25XXFD_CAN_OBJ_ID_SID_MASK					\
-+	GENMASK(MCP25XXFD_CAN_OBJ_ID_SID_SHIFT +			\
-+		MCP25XXFD_CAN_OBJ_ID_SID_BITS - 1,			\
-+		MCP25XXFD_CAN_OBJ_ID_SID_SHIFT)
-+#define MCP25XXFD_CAN_OBJ_ID_EID_BITS		18
-+#define MCP25XXFD_CAN_OBJ_ID_EID_SHIFT		11
-+#define MCP25XXFD_CAN_OBJ_ID_EID_MASK					\
-+	GENMASK(MCP25XXFD_CAN_OBJ_ID_EID_SHIFT +			\
-+		MCP25XXFD_CAN_OBJ_ID_EID_BITS - 1,			\
-+		MCP25XXFD_CAN_OBJ_ID_EID_SHIFT)
-+#define MCP25XXFD_CAN_OBJ_ID_SID_BIT11		BIT(29)
-+
-+#define MCP25XXFD_CAN_OBJ_FLAGS_DLC_BITS	4
-+#define MCP25XXFD_CAN_OBJ_FLAGS_DLC_SHIFT	0
-+#define MCP25XXFD_CAN_OBJ_FLAGS_DLC_MASK				\
-+	GENMASK(MCP25XXFD_CAN_OBJ_FLAGS_DLC_SHIFT +			\
-+		MCP25XXFD_CAN_OBJ_FLAGS_DLC_BITS - 1,			\
-+		MCP25XXFD_CAN_OBJ_FLAGS_DLC_SHIFT)
-+#define MCP25XXFD_CAN_OBJ_FLAGS_IDE		BIT(4)
-+#define MCP25XXFD_CAN_OBJ_FLAGS_RTR		BIT(5)
-+#define MCP25XXFD_CAN_OBJ_FLAGS_BRS		BIT(6)
-+#define MCP25XXFD_CAN_OBJ_FLAGS_FDF		BIT(7)
-+#define MCP25XXFD_CAN_OBJ_FLAGS_ESI		BIT(8)
-+#define MCP25XXFD_CAN_OBJ_FLAGS_SEQ_BITS	7
-+#define MCP25XXFD_CAN_OBJ_FLAGS_SEQ_SHIFT	9
-+#define MCP25XXFD_CAN_OBJ_FLAGS_SEQ_MASK				\
-+	GENMASK(MCP25XXFD_CAN_OBJ_FLAGS_SEQ_SHIFT +			\
-+		MCP25XXFD_CAN_OBJ_FLAGS_SEQ_BITS - 1,			\
-+		MCP25XXFD_CAN_OBJ_FLAGS_SEQ_SHIFT)
-+#define MCP25XXFD_CAN_OBJ_FLAGS_FILHIT_BITS	11
-+#define MCP25XXFD_CAN_OBJ_FLAGS_FILHIT_SHIFT	5
-+#define MCP25XXFD_CAN_OBJ_FLAGS_FILHIT_MASK				\
-+	GENMASK(MCP25XXFD_CAN_FLAGS_FILHIT_SHIFT +			\
-+		MCP25XXFD_CAN_FLAGS_FILHIT_BITS - 1,			\
-+		MCP25XXFD_CAN_FLAGS_FILHIT_SHIFT)
-+
-+/* custom status error */
-+#define MCP25XXFD_CAN_ERR_DATA7_MCP25XXFD_SERR_RX BIT(0)
-+#define MCP25XXFD_CAN_ERR_DATA7_MCP25XXFD_SERR_TX BIT(1)
-+#define MCP25XXFD_CAN_ERR_DATA7_MCP25XXFD_ECC	  BIT(2)
-+
-+#endif /* __MCP25XXFD_REGS_H */
--- 
-2.17.1
-
diff --git a/recipes-kernel/linux/linux-stm32mp/patches/0301-drm-stm-dsi-higher-pll-out-only-in-video-burst-mode.patch b/recipes-kernel/linux/linux-stm32mp/patches/0301-drm-stm-dsi-higher-pll-out-only-in-video-burst-mode.patch
deleted file mode 100644
index 82ba55c04ca66e737b1ae9b30fe22aa9bbfd4209..0000000000000000000000000000000000000000
--- a/recipes-kernel/linux/linux-stm32mp/patches/0301-drm-stm-dsi-higher-pll-out-only-in-video-burst-mode.patch
+++ /dev/null
@@ -1,40 +0,0 @@
-From 64af7ff0d18d7383b15ad25f1c92e72d804b4677 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Yannick=20Fertr=C3=A9?= <yannick.fertre@st.com>
-Date: Thu, 12 Sep 2019 10:56:29 +0200
-Subject: [PATCH 1/3] drm/stm: dsi: higher pll out only in video burst mode
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-In order to better support video non-burst modes,
-the +20% on pll out is added only in burst mode.
-
-Signed-off-by: Philippe Cornu <philippe.cornu@st.com>
-Signed-off-by: Yannick Fertré <yannick.fertre@st.com>
-Reviewed-by: Yannick Fertré <yannick.fertre@st.com>
-Signed-off-by: Benjamin Gaignard <benjamin.gaignard@linaro.org>
-Link: https://patchwork.freedesktop.org/patch/msgid/1568278589-20400-1-git-send-email-yannick.fertre@st.com
----
- drivers/gpu/drm/stm/dw_mipi_dsi-stm.c | 5 ++++-
- 1 file changed, 4 insertions(+), 1 deletion(-)
-
-diff --git a/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c b/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c
-index b7b2a248a213..a584607d1aeb 100644
---- a/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c
-+++ b/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c
-@@ -253,8 +253,11 @@ dw_mipi_dsi_get_lane_mbps(void *priv_data, struct drm_display_mode *mode,
- 	/* Compute requested pll out */
- 	bpp = mipi_dsi_pixel_format_to_bpp(format);
- 	pll_out_khz = mode->clock * bpp / lanes;
-+
- 	/* Add 20% to pll out to be higher than pixel bw (burst mode only) */
--	pll_out_khz = (pll_out_khz * 12) / 10;
-+	if (mode_flags & MIPI_DSI_MODE_VIDEO_BURST)
-+		pll_out_khz = (pll_out_khz * 12) / 10;
-+
- 	if (pll_out_khz > dsi->lane_max_kbps) {
- 		pll_out_khz = dsi->lane_max_kbps;
- 		DRM_WARN("Warning max phy mbps is used\n");
--- 
-2.17.1
-
diff --git a/recipes-kernel/linux/linux-stm32mp/patches/0301-stm-drm-driver-fetch-newest-source-code-from-st-repo.patch b/recipes-kernel/linux/linux-stm32mp/patches/0301-stm-drm-driver-fetch-newest-source-code-from-st-repo.patch
deleted file mode 100644
index 97f514599b248a0b22c20b2bb2b300cd26c17d3d..0000000000000000000000000000000000000000
--- a/recipes-kernel/linux/linux-stm32mp/patches/0301-stm-drm-driver-fetch-newest-source-code-from-st-repo.patch
+++ /dev/null
@@ -1,484 +0,0 @@
-From ac8df9a4568db5cb4c032ae6f4d56a239761e90e Mon Sep 17 00:00:00 2001
-From: Eberhard Stoll <eberhard.stoll@kontron.de>
-Date: Wed, 17 Jun 2020 12:30:40 +0200
-Subject: [PATCH 1/6] stm drm driver: fetch newest source code from st repos
- (a8a26358a17edab2479bd7f0bd6fe1487c89db7d)
-
----
- drivers/gpu/drm/stm/drv.c  |  42 ++++++--
- drivers/gpu/drm/stm/ltdc.c | 200 ++++++++++++++++++++++++-------------
- drivers/gpu/drm/stm/ltdc.h |   3 +-
- 3 files changed, 167 insertions(+), 78 deletions(-)
-
-diff --git a/drivers/gpu/drm/stm/drv.c b/drivers/gpu/drm/stm/drv.c
-index cf618758b230..f578da4b1baf 100644
---- a/drivers/gpu/drm/stm/drv.c
-+++ b/drivers/gpu/drm/stm/drv.c
-@@ -10,6 +10,7 @@
- 
- #include <linux/component.h>
- #include <linux/of_platform.h>
-+#include <linux/pm_runtime.h>
- 
- #include <drm/drm_atomic.h>
- #include <drm/drm_atomic_helper.h>
-@@ -131,13 +132,14 @@ static __maybe_unused int drv_suspend(struct device *dev)
- 	struct ltdc_device *ldev = ddev->dev_private;
- 	struct drm_atomic_state *state;
- 
--	drm_kms_helper_poll_disable(ddev);
-+	WARN_ON(ldev->suspend_state);
-+
- 	state = drm_atomic_helper_suspend(ddev);
--	if (IS_ERR(state)) {
--		drm_kms_helper_poll_enable(ddev);
-+	if (IS_ERR(state))
- 		return PTR_ERR(state);
--	}
-+
- 	ldev->suspend_state = state;
-+	pm_runtime_force_suspend(dev);
- 
- 	return 0;
- }
-@@ -146,15 +148,43 @@ static __maybe_unused int drv_resume(struct device *dev)
- {
- 	struct drm_device *ddev = dev_get_drvdata(dev);
- 	struct ltdc_device *ldev = ddev->dev_private;
-+	int ret;
-+
-+	if (WARN_ON(!ldev->suspend_state))
-+		return -ENOENT;
-+
-+	pm_runtime_force_resume(dev);
-+	ret = drm_atomic_helper_resume(ddev, ldev->suspend_state);
-+	if (ret)
-+		pm_runtime_force_suspend(dev);
-+
-+	ldev->suspend_state = NULL;
-+
-+	return ret;
-+}
- 
--	drm_atomic_helper_resume(ddev, ldev->suspend_state);
--	drm_kms_helper_poll_enable(ddev);
-+static __maybe_unused int drv_runtime_suspend(struct device *dev)
-+{
-+	struct drm_device *ddev = dev_get_drvdata(dev);
-+
-+	DRM_DEBUG_DRIVER("\n");
-+	ltdc_suspend(ddev);
- 
- 	return 0;
- }
- 
-+static __maybe_unused int drv_runtime_resume(struct device *dev)
-+{
-+	struct drm_device *ddev = dev_get_drvdata(dev);
-+
-+	DRM_DEBUG_DRIVER("\n");
-+	return ltdc_resume(ddev);
-+}
-+
- static const struct dev_pm_ops drv_pm_ops = {
- 	SET_SYSTEM_SLEEP_PM_OPS(drv_suspend, drv_resume)
-+	SET_RUNTIME_PM_OPS(drv_runtime_suspend,
-+			   drv_runtime_resume, NULL)
- };
- 
- static int stm_drm_platform_probe(struct platform_device *pdev)
-diff --git a/drivers/gpu/drm/stm/ltdc.c b/drivers/gpu/drm/stm/ltdc.c
-index 3527e699603a..013b9f9c69a7 100644
---- a/drivers/gpu/drm/stm/ltdc.c
-+++ b/drivers/gpu/drm/stm/ltdc.c
-@@ -12,6 +12,8 @@
- #include <linux/component.h>
- #include <linux/of_address.h>
- #include <linux/of_graph.h>
-+#include <linux/pinctrl/consumer.h>
-+#include <linux/pm_runtime.h>
- #include <linux/reset.h>
- 
- #include <drm/drm_atomic.h>
-@@ -19,6 +21,7 @@
- #include <drm/drm_crtc_helper.h>
- #include <drm/drm_fb_cma_helper.h>
- #include <drm/drm_gem_cma_helper.h>
-+#include <drm/drm_gem_framebuffer_helper.h>
- #include <drm/drm_of.h>
- #include <drm/drm_bridge.h>
- #include <drm/drm_plane_helper.h>
-@@ -350,33 +353,6 @@ static inline u32 get_pixelformat_without_alpha(u32 drm)
- 	}
- }
- 
--static int ltdc_power_up(struct ltdc_device *ldev)
--{
--	int ret;
--
--	DRM_DEBUG_DRIVER("\n");
--
--	if (!ldev->power_on) {
--		ret = clk_prepare_enable(ldev->pixel_clk);
--		if (ret) {
--			DRM_ERROR("failed to enable pixel clock (%d)\n",
--				  ret);
--			return ret;
--		}
--		ldev->power_on = true;
--	}
--
--	return 0;
--}
--
--static void ltdc_power_down(struct ltdc_device *ldev)
--{
--	DRM_DEBUG_DRIVER("\n");
--
--	clk_disable_unprepare(ldev->pixel_clk);
--	ldev->power_on = false;
--}
--
- static irqreturn_t ltdc_irq_thread(int irq, void *arg)
- {
- 	struct drm_device *ddev = arg;
-@@ -437,14 +413,9 @@ static void ltdc_crtc_atomic_enable(struct drm_crtc *crtc,
- 				    struct drm_crtc_state *old_state)
- {
- 	struct ltdc_device *ldev = crtc_to_ltdc(crtc);
--	int ret;
- 
- 	DRM_DEBUG_DRIVER("\n");
- 
--	ret = ltdc_power_up(ldev);
--	if (ret)
--		return;
--
- 	/* Sets the background color value */
- 	reg_write(ldev->regs, LTDC_BCCR, BCCR_BCBLACK);
- 
-@@ -454,9 +425,6 @@ static void ltdc_crtc_atomic_enable(struct drm_crtc *crtc,
- 	/* Immediately commit the planes */
- 	reg_set(ldev->regs, LTDC_SRCR, SRCR_IMR);
- 
--	/* Enable LTDC */
--	reg_set(ldev->regs, LTDC_GCR, GCR_LTDCEN);
--
- 	drm_crtc_vblank_on(crtc);
- }
- 
-@@ -464,21 +432,19 @@ static void ltdc_crtc_atomic_disable(struct drm_crtc *crtc,
- 				     struct drm_crtc_state *old_state)
- {
- 	struct ltdc_device *ldev = crtc_to_ltdc(crtc);
-+	struct drm_device *ddev = crtc->dev;
- 
- 	DRM_DEBUG_DRIVER("\n");
- 
- 	drm_crtc_vblank_off(crtc);
- 
--	/* disable LTDC */
--	reg_clear(ldev->regs, LTDC_GCR, GCR_LTDCEN);
--
- 	/* disable IRQ */
- 	reg_clear(ldev->regs, LTDC_IER, IER_RRIE | IER_FUIE | IER_TERRIE);
- 
- 	/* immediately commit disable of layers before switching off LTDC */
- 	reg_set(ldev->regs, LTDC_SRCR, SRCR_IMR);
- 
--	ltdc_power_down(ldev);
-+	pm_runtime_put_sync(ddev->dev);
- }
- 
- #define CLK_TOLERANCE_HZ 50
-@@ -527,7 +493,15 @@ static bool ltdc_crtc_mode_fixup(struct drm_crtc *crtc,
- 				 struct drm_display_mode *adjusted_mode)
- {
- 	struct ltdc_device *ldev = crtc_to_ltdc(crtc);
-+	struct drm_device *ddev = crtc->dev;
- 	int rate = mode->clock * 1000;
-+	bool runtime_active;
-+	int ret;
-+
-+	runtime_active = pm_runtime_active(ddev->dev);
-+
-+	if (runtime_active)
-+		pm_runtime_put_sync(ddev->dev);
- 
- 	if (clk_set_rate(ldev->pixel_clk, rate) < 0) {
- 		DRM_ERROR("Cannot set rate (%dHz) for pixel clk\n", rate);
-@@ -536,6 +510,14 @@ static bool ltdc_crtc_mode_fixup(struct drm_crtc *crtc,
- 
- 	adjusted_mode->clock = clk_get_rate(ldev->pixel_clk) / 1000;
- 
-+	if (runtime_active) {
-+		ret = pm_runtime_get_sync(ddev->dev);
-+		if (ret) {
-+			DRM_ERROR("Failed to fixup mode, cannot get sync\n");
-+			return false;
-+		}
-+	}
-+
- 	DRM_DEBUG_DRIVER("requested clock %dkHz, adjusted clock %dkHz\n",
- 			 mode->clock, adjusted_mode->clock);
- 
-@@ -545,6 +527,7 @@ static bool ltdc_crtc_mode_fixup(struct drm_crtc *crtc,
- static void ltdc_crtc_mode_set_nofb(struct drm_crtc *crtc)
- {
- 	struct ltdc_device *ldev = crtc_to_ltdc(crtc);
-+	struct drm_device *ddev = crtc->dev;
- 	struct drm_display_mode *mode = &crtc->state->adjusted_mode;
- 	struct videomode vm;
- 	u32 hsync, vsync, accum_hbp, accum_vbp, accum_act_w, accum_act_h;
-@@ -552,9 +535,13 @@ static void ltdc_crtc_mode_set_nofb(struct drm_crtc *crtc)
- 	u32 val;
- 	int ret;
- 
--	ret = ltdc_power_up(ldev);
--	if (ret)
--		return;
-+	if (!pm_runtime_active(ddev->dev)) {
-+		ret = pm_runtime_get_sync(ddev->dev);
-+		if (ret) {
-+			DRM_ERROR("Failed to set mode, cannot get sync\n");
-+			return;
-+		}
-+	}
- 
- 	drm_display_mode_to_videomode(mode, &vm);
- 
-@@ -648,14 +635,8 @@ static const struct drm_crtc_helper_funcs ltdc_crtc_helper_funcs = {
- static int ltdc_crtc_enable_vblank(struct drm_crtc *crtc)
- {
- 	struct ltdc_device *ldev = crtc_to_ltdc(crtc);
--	int ret;
- 
- 	DRM_DEBUG_DRIVER("\n");
--
--	ret = ltdc_power_up(ldev);
--	if (ret)
--		return ret;
--
- 	reg_set(ldev->regs, LTDC_IER, IER_LIE);
- 
- 	return 0;
-@@ -666,12 +647,6 @@ static void ltdc_crtc_disable_vblank(struct drm_crtc *crtc)
- 	struct ltdc_device *ldev = crtc_to_ltdc(crtc);
- 
- 	DRM_DEBUG_DRIVER("\n");
--
--	if (!ldev->power_on) {
--		DRM_WARN("power is already down\n");
--		return;
--	}
--
- 	reg_clear(ldev->regs, LTDC_IER, IER_LIE);
- }
- 
-@@ -700,15 +675,19 @@ bool ltdc_crtc_scanoutpos(struct drm_device *ddev, unsigned int pipe,
- 	 * Computation for the two first cases are identical so we can
- 	 * simplify the code and only test if line > vactive_end
- 	 */
--	line = reg_read(ldev->regs, LTDC_CPSR) & CPSR_CYPOS;
--	vactive_start = reg_read(ldev->regs, LTDC_BPCR) & BPCR_AVBP;
--	vactive_end = reg_read(ldev->regs, LTDC_AWCR) & AWCR_AAH;
--	vtotal = reg_read(ldev->regs, LTDC_TWCR) & TWCR_TOTALH;
--
--	if (line > vactive_end)
--		*vpos = line - vtotal - vactive_start;
--	else
--		*vpos = line - vactive_start;
-+	if (pm_runtime_active(ddev->dev)) {
-+		line = reg_read(ldev->regs, LTDC_CPSR) & CPSR_CYPOS;
-+		vactive_start = reg_read(ldev->regs, LTDC_BPCR) & BPCR_AVBP;
-+		vactive_end = reg_read(ldev->regs, LTDC_AWCR) & AWCR_AAH;
-+		vtotal = reg_read(ldev->regs, LTDC_TWCR) & TWCR_TOTALH;
-+
-+		if (line > vactive_end)
-+			*vpos = line - vtotal - vactive_start;
-+		else
-+			*vpos = line - vactive_start;
-+	} else {
-+		*vpos = 0;
-+	}
- 
- 	*hpos = 0;
- 
-@@ -937,6 +916,7 @@ static const struct drm_plane_funcs ltdc_plane_funcs = {
- };
- 
- static const struct drm_plane_helper_funcs ltdc_plane_helper_funcs = {
-+	.prepare_fb = drm_gem_fb_prepare_fb,
- 	.atomic_check = ltdc_plane_atomic_check,
- 	.atomic_update = ltdc_plane_atomic_update,
- 	.atomic_disable = ltdc_plane_atomic_disable,
-@@ -1056,6 +1036,54 @@ static const struct drm_encoder_funcs ltdc_encoder_funcs = {
- 	.destroy = drm_encoder_cleanup,
- };
- 
-+static void ltdc_encoder_disable(struct drm_encoder *encoder)
-+{
-+	struct drm_device *ddev = encoder->dev;
-+	struct ltdc_device *ldev = ddev->dev_private;
-+
-+	DRM_DEBUG_DRIVER("\n");
-+
-+	/* Disable LTDC */
-+	reg_clear(ldev->regs, LTDC_GCR, GCR_LTDCEN);
-+
-+	/* Set to sleep state the pinctrl whatever type of encoder */
-+	pinctrl_pm_select_sleep_state(ddev->dev);
-+}
-+
-+static void ltdc_encoder_enable(struct drm_encoder *encoder)
-+{
-+	struct drm_device *ddev = encoder->dev;
-+	struct ltdc_device *ldev = ddev->dev_private;
-+
-+	DRM_DEBUG_DRIVER("\n");
-+
-+	/* Enable LTDC */
-+	reg_set(ldev->regs, LTDC_GCR, GCR_LTDCEN);
-+}
-+
-+static void ltdc_encoder_mode_set(struct drm_encoder *encoder,
-+				  struct drm_display_mode *mode,
-+				  struct drm_display_mode *adjusted_mode)
-+{
-+	struct drm_device *ddev = encoder->dev;
-+
-+	DRM_DEBUG_DRIVER("\n");
-+
-+	/*
-+	 * Set to default state the pinctrl only with DPI type.
-+	 * Others types like DSI, don't need pinctrl due to
-+	 * internal bridge (the signals do not come out of the chipset).
-+	 */
-+	if (encoder->encoder_type == DRM_MODE_ENCODER_DPI)
-+		pinctrl_pm_select_default_state(ddev->dev);
-+}
-+
-+static const struct drm_encoder_helper_funcs ltdc_encoder_helper_funcs = {
-+	.disable = ltdc_encoder_disable,
-+	.enable = ltdc_encoder_enable,
-+	.mode_set = ltdc_encoder_mode_set,
-+};
-+
- static int ltdc_encoder_init(struct drm_device *ddev, struct drm_bridge *bridge)
- {
- 	struct drm_encoder *encoder;
-@@ -1071,6 +1099,8 @@ static int ltdc_encoder_init(struct drm_device *ddev, struct drm_bridge *bridge)
- 	drm_encoder_init(ddev, encoder, &ltdc_encoder_funcs,
- 			 DRM_MODE_ENCODER_DPI, NULL);
- 
-+	drm_encoder_helper_add(encoder, &ltdc_encoder_helper_funcs);
-+
- 	ret = drm_bridge_attach(encoder, bridge, NULL);
- 	if (ret) {
- 		drm_encoder_cleanup(encoder);
-@@ -1128,6 +1158,30 @@ static int ltdc_get_caps(struct drm_device *ddev)
- 	return 0;
- }
- 
-+void ltdc_suspend(struct drm_device *ddev)
-+{
-+	struct ltdc_device *ldev = ddev->dev_private;
-+
-+	DRM_DEBUG_DRIVER("\n");
-+	clk_disable_unprepare(ldev->pixel_clk);
-+}
-+
-+int ltdc_resume(struct drm_device *ddev)
-+{
-+	struct ltdc_device *ldev = ddev->dev_private;
-+	int ret;
-+
-+	DRM_DEBUG_DRIVER("\n");
-+
-+	ret = clk_prepare_enable(ldev->pixel_clk);
-+	if (ret) {
-+		DRM_ERROR("failed to enable pixel clock (%d)\n", ret);
-+		return ret;
-+	}
-+
-+	return 0;
-+}
-+
- int ltdc_load(struct drm_device *ddev)
- {
- 	struct platform_device *pdev = to_platform_device(ddev->dev);
-@@ -1172,10 +1226,10 @@ int ltdc_load(struct drm_device *ddev)
- 		return PTR_ERR(ldev->pixel_clk);
- 	}
- 
--	ldev->power_on = false;
--	ret = ltdc_power_up(ldev);
--	if (ret)
--		return ret;
-+	if (clk_prepare_enable(ldev->pixel_clk)) {
-+		DRM_ERROR("Unable to prepare pixel clock\n");
-+		return -ENODEV;
-+	}
- 
- 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- 	ldev->regs = devm_ioremap_resource(dev, res);
-@@ -1266,20 +1320,24 @@ int ltdc_load(struct drm_device *ddev)
- 	/* Allow usage of vblank without having to call drm_irq_install */
- 	ddev->irq_enabled = 1;
- 
--	return 0;
-+	clk_disable_unprepare(ldev->pixel_clk);
-+
-+	pinctrl_pm_select_sleep_state(ddev->dev);
-+
-+	pm_runtime_enable(ddev->dev);
- 
-+	return 0;
- err:
- 	for (i = 0; i < MAX_ENDPOINTS; i++)
- 		drm_panel_bridge_remove(bridge[i]);
- 
--	ltdc_power_down(ldev);
-+	clk_disable_unprepare(ldev->pixel_clk);
- 
- 	return ret;
- }
- 
- void ltdc_unload(struct drm_device *ddev)
- {
--	struct ltdc_device *ldev = ddev->dev_private;
- 	int i;
- 
- 	DRM_DEBUG_DRIVER("\n");
-@@ -1287,7 +1345,7 @@ void ltdc_unload(struct drm_device *ddev)
- 	for (i = 0; i < MAX_ENDPOINTS; i++)
- 		drm_of_panel_bridge_remove(ddev->dev->of_node, 0, i);
- 
--	ltdc_power_down(ldev);
-+	pm_runtime_disable(ddev->dev);
- }
- 
- MODULE_AUTHOR("Philippe Cornu <philippe.cornu@st.com>");
-diff --git a/drivers/gpu/drm/stm/ltdc.h b/drivers/gpu/drm/stm/ltdc.h
-index 08bd69d8f546..9b410c67c4c5 100644
---- a/drivers/gpu/drm/stm/ltdc.h
-+++ b/drivers/gpu/drm/stm/ltdc.h
-@@ -37,7 +37,6 @@ struct ltdc_device {
- 	u32 irq_status;
- 	struct fps_info plane_fpsi[LTDC_MAX_LAYER];
- 	struct drm_atomic_state *suspend_state;
--	bool power_on;
- };
- 
- bool ltdc_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe,
-@@ -46,5 +45,7 @@ bool ltdc_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe,
- 			  const struct drm_display_mode *mode);
- int ltdc_load(struct drm_device *ddev);
- void ltdc_unload(struct drm_device *ddev);
-+void ltdc_suspend(struct drm_device *ddev);
-+int ltdc_resume(struct drm_device *ddev);
- 
- #endif
--- 
-2.17.1
-
diff --git a/recipes-kernel/linux/linux-stm32mp/patches/0302-synopsys-dsi-driver-fetch-newest-source-code-from-st.patch b/recipes-kernel/linux/linux-stm32mp/patches/0302-synopsys-dsi-driver-fetch-newest-source-code-from-st.patch
deleted file mode 100644
index c476220647d7bedcede0570b77ac57cef85df77a..0000000000000000000000000000000000000000
--- a/recipes-kernel/linux/linux-stm32mp/patches/0302-synopsys-dsi-driver-fetch-newest-source-code-from-st.patch
+++ /dev/null
@@ -1,190 +0,0 @@
-From 5c23c1a5a97d7307fbb84ce4f2c6174b046b2ced Mon Sep 17 00:00:00 2001
-From: Eberhard Stoll <eberhard.stoll@kontron.de>
-Date: Wed, 17 Jun 2020 18:09:57 +0200
-Subject: [PATCH 2/6] synopsys dsi driver: fetch newest source code from st
- repos (a8a26358a17edab2479bd7f0bd6fe1487c89db7d)
-
----
- drivers/gpu/drm/bridge/synopsys/dw-hdmi.c     | 12 ++-
- drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c | 90 ++++++++++++++++---
- 2 files changed, 91 insertions(+), 11 deletions(-)
-
-diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
-index 5971976284bf..2a0a1654d3ce 100644
---- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
-+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
-@@ -39,6 +39,7 @@
- 
- #include <media/cec-notifier.h>
- 
-+#define DDC_CI_ADDR		0x37
- #define DDC_SEGMENT_ADDR	0x30
- 
- #define HDMI_EDID_LEN		512
-@@ -320,6 +321,15 @@ static int dw_hdmi_i2c_xfer(struct i2c_adapter *adap,
- 	u8 addr = msgs[0].addr;
- 	int i, ret = 0;
- 
-+	if (addr == DDC_CI_ADDR)
-+		/*
-+		 * The internal I2C controller does not support the multi-byte
-+		 * read and write operations needed for DDC/CI.
-+		 * TOFIX: Blacklist the DDC/CI address until we filter out
-+		 * unsupported I2C operations.
-+		 */
-+		return -EOPNOTSUPP;
-+
- 	dev_dbg(hdmi->dev, "xfer: num: %d, addr: %#x\n", num, addr);
- 
- 	for (i = 0; i < num; i++) {
-@@ -1747,7 +1757,7 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
- 
- 		/* HDMI Initialization Step E - Configure audio */
- 		hdmi_clk_regenerator_update_pixel_clock(hdmi);
--		hdmi_enable_audio_clk(hdmi, true);
-+		hdmi_enable_audio_clk(hdmi, hdmi->audio_enable);
- 	}
- 
- 	/* not for DVI mode */
-diff --git a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
-index 8cd3ee903390..2e4334f0a8f5 100644
---- a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
-+++ b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
-@@ -206,6 +206,20 @@
- 
- #define DSI_INT_ST0			0xbc
- #define DSI_INT_ST1			0xc0
-+#define GPRXE				BIT(12)
-+#define GPRDE				BIT(11)
-+#define GPTXE				BIT(10)
-+#define GPWRE				BIT(9)
-+#define GCWRE				BIT(8)
-+#define DPIPLDWE			BIT(7)
-+#define EOTPE				BIT(6)
-+#define PSE				BIT(5)
-+#define CRCE				BIT(4)
-+#define ECCME				BIT(3)
-+#define ECCSE				BIT(2)
-+#define TOLPRX				BIT(1)
-+#define TOHSTX				BIT(0)
-+
- #define DSI_INT_MSK0			0xc4
- #define DSI_INT_MSK1			0xc8
- 
-@@ -357,6 +371,42 @@ static int dw_mipi_dsi_gen_pkt_hdr_write(struct dw_mipi_dsi *dsi, u32 hdr_val)
- 	return 0;
- }
- 
-+static int dw_mipi_dsi_read_status(struct dw_mipi_dsi *dsi)
-+{
-+	u32 val;
-+
-+	val = dsi_read(dsi, DSI_INT_ST1);
-+
-+	if (val & GPRXE)
-+		DRM_DEBUG_DRIVER("DSI Generic payload receive error\n");
-+	if (val & GPRDE)
-+		DRM_DEBUG_DRIVER("DSI Generic payload read error\n");
-+	if (val & GPTXE)
-+		DRM_DEBUG_DRIVER("DSI Generic payload transmit error\n");
-+	if (val & GPWRE)
-+		DRM_DEBUG_DRIVER("DSI Generic payload write error\n");
-+	if (val & GCWRE)
-+		DRM_DEBUG_DRIVER("DSI Generic command write error\n");
-+	if (val & DPIPLDWE)
-+		DRM_DEBUG_DRIVER("DSI DPI payload write error\n");
-+	if (val & EOTPE)
-+		DRM_DEBUG_DRIVER("DSI EoTp error\n");
-+	if (val & PSE)
-+		DRM_DEBUG_DRIVER("DSI Packet size error\n");
-+	if (val & CRCE)
-+		DRM_DEBUG_DRIVER("DSI CRC error\n");
-+	if (val & ECCME)
-+		DRM_DEBUG_DRIVER("DSI ECC multi-bit error\n");
-+	if (val & ECCSE)
-+		DRM_DEBUG_DRIVER("DSI ECC single-bit error\n");
-+	if (val & TOLPRX)
-+		DRM_DEBUG_DRIVER("DSI Timeout low-power reception\n");
-+	if (val & TOHSTX)
-+		DRM_DEBUG_DRIVER("DSI Timeout high-speed transmission\n");
-+
-+	return val;
-+}
-+
- static int dw_mipi_dsi_write(struct dw_mipi_dsi *dsi,
- 			     const struct mipi_dsi_packet *packet)
- {
-@@ -386,6 +436,12 @@ static int dw_mipi_dsi_write(struct dw_mipi_dsi *dsi,
- 				"failed to get available write payload FIFO\n");
- 			return ret;
- 		}
-+
-+		val = dw_mipi_dsi_read_status(dsi);
-+		if (val) {
-+			dev_err(dsi->dev, "dsi status error 0x%0x\n", val);
-+			return -EINVAL;
-+		}
- 	}
- 
- 	word = 0;
-@@ -419,6 +475,12 @@ static int dw_mipi_dsi_read(struct dw_mipi_dsi *dsi,
- 			return ret;
- 		}
- 
-+		val = dw_mipi_dsi_read_status(dsi);
-+		if (val) {
-+			dev_err(dsi->dev, "dsi status error 0x%0x\n", val);
-+			return -EINVAL;
-+		}
-+
- 		val = dsi_read(dsi, DSI_GEN_PLD_DATA);
- 		for (j = 0; j < 4 && j + i < len; j++)
- 			buf[i + j] = val >> (8 * j);
-@@ -433,6 +495,7 @@ static ssize_t dw_mipi_dsi_host_transfer(struct mipi_dsi_host *host,
- 	struct dw_mipi_dsi *dsi = host_to_dsi(host);
- 	struct mipi_dsi_packet packet;
- 	int ret, nb_bytes;
-+	int retry = 3;
- 
- 	ret = mipi_dsi_create_packet(&packet, msg);
- 	if (ret) {
-@@ -442,19 +505,26 @@ static ssize_t dw_mipi_dsi_host_transfer(struct mipi_dsi_host *host,
- 
- 	dw_mipi_message_config(dsi, msg);
- 
--	ret = dw_mipi_dsi_write(dsi, &packet);
--	if (ret)
--		return ret;
--
--	if (msg->rx_buf && msg->rx_len) {
--		ret = dw_mipi_dsi_read(dsi, msg);
-+	while (retry--) {
-+		ret = dw_mipi_dsi_write(dsi, &packet);
- 		if (ret)
--			return ret;
--		nb_bytes = msg->rx_len;
--	} else {
--		nb_bytes = packet.size;
-+			continue;
-+
-+		if (msg->rx_buf && msg->rx_len) {
-+			ret = dw_mipi_dsi_read(dsi, msg);
-+			if (ret)
-+				continue;
-+			nb_bytes = msg->rx_len;
-+			break;
-+		} else {
-+			nb_bytes = packet.size;
-+			break;
-+		}
- 	}
- 
-+	if (ret)
-+		return ret;
-+
- 	return nb_bytes;
- }
- 
--- 
-2.17.1
-
diff --git a/recipes-kernel/linux/linux-stm32mp/patches/0303-drm-bridge-synopsys-dsi-fix-activation-sequence.patch b/recipes-kernel/linux/linux-stm32mp/patches/0303-drm-bridge-synopsys-dsi-fix-activation-sequence.patch
deleted file mode 100644
index 87dd3cda4a28466cd9464b75bea647667c208011..0000000000000000000000000000000000000000
--- a/recipes-kernel/linux/linux-stm32mp/patches/0303-drm-bridge-synopsys-dsi-fix-activation-sequence.patch
+++ /dev/null
@@ -1,114 +0,0 @@
-From bc8d5124e14646e54eac4b2424e20b483fde6de8 Mon Sep 17 00:00:00 2001
-From: Antonio Borneo <antonio.borneo@st.com>
-Date: Tue, 23 Jun 2020 09:30:46 +0200
-Subject: [PATCH 3/6] drm/bridge/synopsys/dsi: fix activation sequence
-
-The current driver relies on the probing of panel or bridge
-sub-nodes to trigger the execution of dsi host attach() in order
-to add the dsi bridge to the global bridge list through
-drm_bridge_add().
-This causes an incomplete driver initialization if the panel or
-the next bridge is not present as sub-node, e.g. because it is an
-i2c device, thus sub-node of the respective i2c controller.
-
-Move the relevant code from host attach() to probe(), and the
-corresponding code from detach() to remove().
-
-Signed-off-by: Antonio Borneo <antonio.borneo@st.com>
-Change-Id: Ide6ab2249b97e86ff7797dc2dddce48ae5c29dfa
----
- drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c | 44 +++++++++----------
- 1 file changed, 20 insertions(+), 24 deletions(-)
-
-diff --git a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
-index 2e4334f0a8f5..4d27d7d89f7d 100644
---- a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
-+++ b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
-@@ -284,9 +284,6 @@ static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host,
- 				   struct mipi_dsi_device *device)
- {
- 	struct dw_mipi_dsi *dsi = host_to_dsi(host);
--	struct drm_bridge *bridge;
--	struct drm_panel *panel;
--	int ret;
- 
- 	if (device->lanes > dsi->plat_data->max_data_lanes) {
- 		dev_err(dsi->dev, "the number of data lanes(%u) is too many\n",
-@@ -299,33 +296,12 @@ static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host,
- 	dsi->format = device->format;
- 	dsi->mode_flags = device->mode_flags;
- 
--	ret = drm_of_find_panel_or_bridge(host->dev->of_node, 1, 0,
--					  &panel, &bridge);
--	if (ret)
--		return ret;
--
--	if (panel) {
--		bridge = drm_panel_bridge_add(panel, DRM_MODE_CONNECTOR_DSI);
--		if (IS_ERR(bridge))
--			return PTR_ERR(bridge);
--	}
--
--	dsi->panel_bridge = bridge;
--
--	drm_bridge_add(&dsi->bridge);
--
- 	return 0;
- }
- 
- static int dw_mipi_dsi_host_detach(struct mipi_dsi_host *host,
- 				   struct mipi_dsi_device *device)
- {
--	struct dw_mipi_dsi *dsi = host_to_dsi(host);
--
--	drm_of_panel_bridge_remove(host->dev->of_node, 1, 0);
--
--	drm_bridge_remove(&dsi->bridge);
--
- 	return 0;
- }
- 
-@@ -940,6 +916,8 @@ __dw_mipi_dsi_probe(struct platform_device *pdev,
- 	struct reset_control *apb_rst;
- 	struct dw_mipi_dsi *dsi;
- 	struct resource *res;
-+	struct drm_bridge *bridge;
-+	struct drm_panel *panel;
- 	int ret;
- 
- 	dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL);
-@@ -1018,6 +996,21 @@ __dw_mipi_dsi_probe(struct platform_device *pdev,
- 	dsi->bridge.of_node = pdev->dev.of_node;
- #endif
- 
-+	ret = drm_of_find_panel_or_bridge(pdev->dev.of_node, 1, 0,
-+					  &panel, &bridge);
-+	if (ret)
-+		return ERR_PTR(ret);
-+
-+	if (panel) {
-+		bridge = drm_panel_bridge_add(panel, DRM_MODE_CONNECTOR_DSI);
-+		if (IS_ERR(bridge))
-+			return ERR_PTR(PTR_ERR(bridge));
-+	}
-+
-+	dsi->panel_bridge = bridge;
-+
-+	drm_bridge_add(&dsi->bridge);
-+
- 	return dsi;
- }
- 
-@@ -1039,6 +1032,9 @@ EXPORT_SYMBOL_GPL(dw_mipi_dsi_probe);
- 
- void dw_mipi_dsi_remove(struct dw_mipi_dsi *dsi)
- {
-+	drm_of_panel_bridge_remove(dsi->bridge.of_node, 1, 0);
-+	drm_bridge_remove(&dsi->bridge);
-+
- 	mipi_dsi_host_unregister(&dsi->dsi_host);
- 
- 	__dw_mipi_dsi_remove(dsi);
--- 
-2.17.1
-
diff --git a/recipes-kernel/linux/linux-stm32mp/patches/0304-drm-bridge-synopsys-dsi-cleanup-when-probe-fails.patch b/recipes-kernel/linux/linux-stm32mp/patches/0304-drm-bridge-synopsys-dsi-cleanup-when-probe-fails.patch
deleted file mode 100644
index e77838dcaa1297c4ed93ad2cc92c9bd6547f5dd8..0000000000000000000000000000000000000000
--- a/recipes-kernel/linux/linux-stm32mp/patches/0304-drm-bridge-synopsys-dsi-cleanup-when-probe-fails.patch
+++ /dev/null
@@ -1,62 +0,0 @@
-From 4d8b00225ab75eed007318a6a3a2ccd0f1c705b2 Mon Sep 17 00:00:00 2001
-From: Antonio Borneo <antonio.borneo@st.com>
-Date: Tue, 30 Jun 2020 21:40:17 +0200
-Subject: [PATCH 4/6] drm/bridge/synopsys/dsi: cleanup when probe fails
-
-In case of probe fail, before quit cleanup the host registration
-and disable the pm runtime.
-
-Signed-off-by: Antonio Borneo <antonio.borneo@st.com>
-Change-Id: I8ecde90fd8c1098e3d8134cb097fbef6e0645e3b
----
- drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c | 17 +++++++++++++----
- 1 file changed, 13 insertions(+), 4 deletions(-)
-
-diff --git a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
-index 4d27d7d89f7d..8188fce597e6 100644
---- a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
-+++ b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
-@@ -987,7 +987,7 @@ __dw_mipi_dsi_probe(struct platform_device *pdev,
- 	ret = mipi_dsi_host_register(&dsi->dsi_host);
- 	if (ret) {
- 		dev_err(dev, "Failed to register MIPI host: %d\n", ret);
--		return ERR_PTR(ret);
-+		goto pmr_enable;
- 	}
- 
- 	dsi->bridge.driver_private = dsi;
-@@ -999,12 +999,14 @@ __dw_mipi_dsi_probe(struct platform_device *pdev,
- 	ret = drm_of_find_panel_or_bridge(pdev->dev.of_node, 1, 0,
- 					  &panel, &bridge);
- 	if (ret)
--		return ERR_PTR(ret);
-+		goto host_reg;
- 
- 	if (panel) {
- 		bridge = drm_panel_bridge_add(panel, DRM_MODE_CONNECTOR_DSI);
--		if (IS_ERR(bridge))
--			return ERR_PTR(PTR_ERR(bridge));
-+		if (IS_ERR(bridge)) {
-+			ret = PTR_ERR(bridge);
-+			goto host_reg;
-+		}
- 	}
- 
- 	dsi->panel_bridge = bridge;
-@@ -1012,6 +1014,13 @@ __dw_mipi_dsi_probe(struct platform_device *pdev,
- 	drm_bridge_add(&dsi->bridge);
- 
- 	return dsi;
-+
-+host_reg:
-+	mipi_dsi_host_unregister(&dsi->dsi_host);
-+
-+pmr_enable:
-+	pm_runtime_disable(dev);
-+	return ERR_PTR(ret);
- }
- 
- static void __dw_mipi_dsi_remove(struct dw_mipi_dsi *dsi)
--- 
-2.17.1
-
diff --git a/recipes-kernel/linux/linux-stm32mp/patches/0305-drm-bridge-synposys-dsi-fix-oops-in-drm-post_disable.patch b/recipes-kernel/linux/linux-stm32mp/patches/0305-drm-bridge-synposys-dsi-fix-oops-in-drm-post_disable.patch
deleted file mode 100644
index 5eb3e613336832f93c1b59715e8de7f126b2dd28..0000000000000000000000000000000000000000
--- a/recipes-kernel/linux/linux-stm32mp/patches/0305-drm-bridge-synposys-dsi-fix-oops-in-drm-post_disable.patch
+++ /dev/null
@@ -1,26 +0,0 @@
-From 21e44267a05bc7ed70d10ac752d2a9f558ccb4ef Mon Sep 17 00:00:00 2001
-From: Eberhard Stoll <eberhard.stoll@kontron.de>
-Date: Fri, 3 Jul 2020 16:42:47 +0200
-Subject: [PATCH 5/6] drm/bridge/synposys/dsi: fix oops in drm post_disable
-
----
- drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
-diff --git a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
-index 8188fce597e6..56dfe736e0d1 100644
---- a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
-+++ b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
-@@ -811,7 +811,8 @@ static void dw_mipi_dsi_bridge_post_disable(struct drm_bridge *bridge)
- 	 * This needs to be fixed in the drm_bridge framework and the API
- 	 * needs to be updated to manage our own call chains...
- 	 */
--	dsi->panel_bridge->funcs->post_disable(dsi->panel_bridge);
-+	if (dsi->panel_bridge->funcs->post_disable)
-+		dsi->panel_bridge->funcs->post_disable(dsi->panel_bridge);
- 
- 	dw_mipi_dsi_disable(dsi);
- 	clk_disable_unprepare(dsi->pclk);
--- 
-2.17.1
-
diff --git a/recipes-kernel/linux/linux-stm32mp/patches/0306-drm_modes-suppress-error-for-hsync-vsync-flag.patch b/recipes-kernel/linux/linux-stm32mp/patches/0306-drm_modes-suppress-error-for-hsync-vsync-flag.patch
deleted file mode 100644
index b247140a9f844f935887a536501ca60ef8c37279..0000000000000000000000000000000000000000
--- a/recipes-kernel/linux/linux-stm32mp/patches/0306-drm_modes-suppress-error-for-hsync-vsync-flag.patch
+++ /dev/null
@@ -1,44 +0,0 @@
-From 3d6d4f2c889ccee9cd7dbf19623a3c349d808372 Mon Sep 17 00:00:00 2001
-From: Eberhard Stoll <eberhard.stoll@kontron.de>
-Date: Tue, 21 Jul 2020 19:29:20 +0200
-Subject: [PATCH 6/6] drm_modes: suppress error for hsync vsync flag
-
----
- drivers/gpu/drm/drm_modes.c | 16 +++++++++++++---
- 1 file changed, 13 insertions(+), 3 deletions(-)
-
-diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
-index f1600e495e4f..f9da6dd563e7 100644
---- a/drivers/gpu/drm/drm_modes.c
-+++ b/drivers/gpu/drm/drm_modes.c
-@@ -1122,14 +1122,24 @@ EXPORT_SYMBOL(drm_mode_equal_no_clocks_no_stereo);
- static enum drm_mode_status
- drm_mode_validate_basic(const struct drm_display_mode *mode)
- {
--	if (mode->type & ~DRM_MODE_TYPE_ALL)
-+	if (mode->type & ~DRM_MODE_TYPE_ALL){
-+		DRM_DEBUG("MODE_BAD: type = 0x%0X mask = 0x%0X\n", mode->type, DRM_MODE_TYPE_ALL);
- 		return MODE_BAD;
-+	}
- 
--	if (mode->flags & ~DRM_MODE_FLAG_ALL)
-+#if 0
-+	if (mode->flags & ~DRM_MODE_FLAG_ALL){
-+		DRM_DEBUG("MODE_BAD: flags = 0x%0X mask = 0x%0X\n", mode->flags, DRM_MODE_FLAG_ALL);
- 		return MODE_BAD;
-+	}
- 
--	if ((mode->flags & DRM_MODE_FLAG_3D_MASK) > DRM_MODE_FLAG_3D_MAX)
-+	if ((mode->flags & DRM_MODE_FLAG_3D_MASK) > DRM_MODE_FLAG_3D_MAX){
-+		DRM_DEBUG("MODE_BAD: flags = 0x%0X max = 0x%0X\n", mode->flags, DRM_MODE_FLAG_3D_MAX);
- 		return MODE_BAD;
-+	}
-+#else
-+#warning HACK DISABLED flags CHECK
-+#endif
- 
- 	if (mode->clock == 0)
- 		return MODE_CLOCK_LOW;
--- 
-2.17.1
-
diff --git a/recipes-kernel/linux/linux-stm32mp/patches/0400-STMFIX-regulator-stm32-vrefbuf-fix-a-possible-overshoot-whe.patch b/recipes-kernel/linux/linux-stm32mp/patches/0400-STMFIX-regulator-stm32-vrefbuf-fix-a-possible-overshoot-whe.patch
deleted file mode 100644
index aa066d47504d04f4492e4e0adf2805b098bb6c91..0000000000000000000000000000000000000000
--- a/recipes-kernel/linux/linux-stm32mp/patches/0400-STMFIX-regulator-stm32-vrefbuf-fix-a-possible-overshoot-whe.patch
+++ /dev/null
@@ -1,43 +0,0 @@
-From a950cec5fbba4e8515817030860758a709024b91 Mon Sep 17 00:00:00 2001
-From: Fabrice Gasnier <fabrice.gasnier@st.com>
-Date: Thu, 16 Jan 2020 18:34:29 +0100
-Subject: [PATCH] regulator: stm32-vrefbuf: fix a possible overshoot when
- re-enabling
-
-There maybe an overshoot, when disabling, then re-enabling vrefbuf
-too quickly. VREFBUF is used by ADC/DAC on some boards. When re-enabling
-too quickly, an overshoot on the reference voltage make the conversions
-inaccurate for a short period of time.
-- Don't put the VREFBUF in HiZ when disabling, to force an active
-discharge.
-- Enforce a 1ms OFF/ON delay
-
-Fixes: 0cdbf481e927 ("regulator: Add support for stm32-vrefbuf")
-
-Signed-off-by: Fabrice Gasnier <fabrice.gasnier@st.com>
-
----
- drivers/regulator/stm32-vrefbuf.c | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
-diff --git a/drivers/regulator/stm32-vrefbuf.c b/drivers/regulator/stm32-vrefbuf.c
-index 29cca32675d1..a74dffefad9c 100644
---- a/drivers/regulator/stm32-vrefbuf.c
-+++ b/drivers/regulator/stm32-vrefbuf.c
-@@ -89,7 +89,7 @@ static int stm32_vrefbuf_disable(struct regulator_dev *rdev)
- 	}
- 
- 	val = readl_relaxed(priv->base + STM32_VREFBUF_CSR);
--	val = (val & ~STM32_ENVR) | STM32_HIZ;
-+	val &= ~STM32_ENVR;
- 	writel_relaxed(val, priv->base + STM32_VREFBUF_CSR);
- 
- 	pm_runtime_mark_last_busy(priv->dev);
-@@ -176,6 +176,7 @@ static const struct regulator_desc stm32_vrefbuf_regu = {
- 	.volt_table = stm32_vrefbuf_voltages,
- 	.n_voltages = ARRAY_SIZE(stm32_vrefbuf_voltages),
- 	.ops = &stm32_vrefbuf_volt_ops,
-+	.off_on_delay = 1000,
- 	.type = REGULATOR_VOLTAGE,
- 	.owner = THIS_MODULE,
- };
diff --git a/recipes-kernel/linux/linux-stm32mp/patches/0401-fix-missing-eth-phy-clocks.patch b/recipes-kernel/linux/linux-stm32mp/patches/0401-fix-missing-eth-phy-clocks.patch
deleted file mode 100644
index 73facc6407cde36b7420e6c97aba27b502a3c1f6..0000000000000000000000000000000000000000
--- a/recipes-kernel/linux/linux-stm32mp/patches/0401-fix-missing-eth-phy-clocks.patch
+++ /dev/null
@@ -1,31 +0,0 @@
-From 4c7bcda79e0e864997bbef1be7fad0a61b18408b Mon Sep 17 00:00:00 2001
-From: Eberhard Stoll <eberhard.stoll@kontron.de>
-Date: Tue, 2 Apr 2019 12:14:30 +0200
-Subject: [PATCH] fix missing eth phy clocks
-
----
- arch/arm/boot/dts/stm32mp157c.dtsi | 8 ++++++--
- 1 file changed, 6 insertions(+), 2 deletions(-)
-
-diff --git a/arch/arm/boot/dts/stm32mp157c.dtsi b/arch/arm/boot/dts/stm32mp157c.dtsi
-index e8f995a38bd9..2389eca648da 100644
---- a/arch/arm/boot/dts/stm32mp157c.dtsi
-+++ b/arch/arm/boot/dts/stm32mp157c.dtsi
-@@ -1775,11 +1775,15 @@
- 			clock-names = "stmmaceth",
- 				      "mac-clk-tx",
- 				      "mac-clk-rx",
--				      "ethstp";
-+				      "ethstp",
-+				      "syscfg-clk",
-+				      "eth-ck";
- 			clocks = <&rcc ETHMAC>,
- 				 <&rcc ETHTX>,
- 				 <&rcc ETHRX>,
--				 <&rcc ETHSTP>;
-+				 <&rcc ETHSTP>,
-+				 <&rcc SYSCFG>,
-+				 <&rcc ETHCK_K>;
- 			st,syscon = <&syscfg 0x4>;
- 			snps,mixed-burst;
- 			snps,pbl = <2>;
diff --git a/recipes-kernel/linux/linux-stm32mp/patches/0402-spi-nand-fix-QSPI-NAND-bad-block-marking-issue.patch b/recipes-kernel/linux/linux-stm32mp/patches/0402-spi-nand-fix-QSPI-NAND-bad-block-marking-issue.patch
deleted file mode 100644
index e3592b8918d1d73e1dfb0ef3b309f35e88d241ee..0000000000000000000000000000000000000000
--- a/recipes-kernel/linux/linux-stm32mp/patches/0402-spi-nand-fix-QSPI-NAND-bad-block-marking-issue.patch
+++ /dev/null
@@ -1,66 +0,0 @@
-From 926a166db523cefb0c06e88b39a897ac9d2d0b30 Mon Sep 17 00:00:00 2001
-From: Eberhard Stoll <eberhard.stoll@kontron.de>
-Date: Mon, 2 Mar 2020 10:58:53 +0100
-Subject: [PATCH] spi-nand: fix QSPI NAND bad block marking issue
-
----
- drivers/mtd/nand/spi/core.c | 18 ++++++++----------
- 1 file changed, 8 insertions(+), 10 deletions(-)
-
-diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
-index 8c7bf91ce4e1..403dbda4115f 100644
---- a/drivers/mtd/nand/spi/core.c
-+++ b/drivers/mtd/nand/spi/core.c
-@@ -629,18 +629,18 @@ static int spinand_mtd_write(struct mtd_info *mtd, loff_t to,
- static bool spinand_isbad(struct nand_device *nand, const struct nand_pos *pos)
- {
- 	struct spinand_device *spinand = nand_to_spinand(nand);
-+	u8 marker[2] = { };
- 	struct nand_page_io_req req = {
- 		.pos = *pos,
--		.ooblen = 2,
-+		.ooblen = sizeof(marker),
- 		.ooboffs = 0,
--		.oobbuf.in = spinand->oobbuf,
-+		.oobbuf.in = marker,
- 		.mode = MTD_OPS_RAW,
- 	};
- 
--	memset(spinand->oobbuf, 0, 2);
- 	spinand_select_target(spinand, pos->target);
- 	spinand_read_page(spinand, &req, false);
--	if (spinand->oobbuf[0] != 0xff || spinand->oobbuf[1] != 0xff)
-+	if (marker[0] != 0xff || marker[1] != 0xff)
- 		return true;
- 
- 	return false;
-@@ -664,15 +664,16 @@ static int spinand_mtd_block_isbad(struct mtd_info *mtd, loff_t offs)
- static int spinand_markbad(struct nand_device *nand, const struct nand_pos *pos)
- {
- 	struct spinand_device *spinand = nand_to_spinand(nand);
-+	u8 marker[2] = { };
- 	struct nand_page_io_req req = {
- 		.pos = *pos,
- 		.ooboffs = 0,
--		.ooblen = 2,
--		.oobbuf.out = spinand->oobbuf,
-+		.ooblen = sizeof(marker),
-+		.oobbuf.out = marker,
-+		.mode = MTD_OPS_RAW,
- 	};
- 	int ret;
- 
--	/* Erase block before marking it bad. */
- 	ret = spinand_select_target(spinand, pos->target);
- 	if (ret)
- 		return ret;
-@@ -681,9 +682,6 @@ static int spinand_markbad(struct nand_device *nand, const struct nand_pos *pos)
- 	if (ret)
- 		return ret;
- 
--	spinand_erase_op(spinand, pos);
--
--	memset(spinand->oobbuf, 0, 2);
- 	return spinand_write_page(spinand, &req);
- }
- 
diff --git a/recipes-kernel/linux/linux-stm32mp/patches/0503-drm-panel-simple-Add-support-for-Admatec-T043C004800.patch b/recipes-kernel/linux/linux-stm32mp/patches/0503-drm-panel-simple-Add-support-for-Admatec-T043C004800.patch
deleted file mode 100644
index 5e4881afb95d070e98db62f44bb03ad12c0d7548..0000000000000000000000000000000000000000
--- a/recipes-kernel/linux/linux-stm32mp/patches/0503-drm-panel-simple-Add-support-for-Admatec-T043C004800.patch
+++ /dev/null
@@ -1,55 +0,0 @@
-From 67956c60b0dcbb67f96fea91b9a2d2b45205eb6a Mon Sep 17 00:00:00 2001
-From: Frieder Schrempf <frieder.schrempf@exceet.de>
-Date: Wed, 10 Jan 2018 15:00:14 +0100
-Subject: [PATCH] drm/panel: simple: Add support for Admatec T043C004800272T2A
-
----
- drivers/gpu/drm/panel/panel-simple.c | 28 ++++++++++++++++++++++++++++
- 1 file changed, 28 insertions(+)
-
-diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c
-index 97964f7f2ace..736fe680b2a3 100644
---- a/drivers/gpu/drm/panel/panel-simple.c
-+++ b/drivers/gpu/drm/panel/panel-simple.c
-@@ -386,6 +386,31 @@ static void panel_simple_shutdown(struct device *dev)
- 	panel_simple_unprepare(&panel->base);
- }
- 
-+static const struct drm_display_mode admatec_t043c004800272t2a_mode = {
-+	.clock = 9200,
-+	.hdisplay = 480,
-+	.hsync_start = 480 + 40,
-+	.hsync_end = 480 + 40 + 20,
-+	.htotal = 480 + 40 + 20 + 60,
-+	.vdisplay = 272,
-+	.vsync_start = 272 + 10,
-+	.vsync_end = 272 + 10 + 10,
-+	.vtotal = 272 + 10 + 10 + 10,
-+	.vrefresh = 60,
-+};
-+
-+static const struct panel_desc admatec_t043c004800272t2a = {
-+	.modes = &admatec_t043c004800272t2a_mode,
-+	.num_modes = 1,
-+	.bpc = 8,
-+	.size = {
-+		.width = 95,
-+		.height = 54,
-+	},
-+	.bus_format = MEDIA_BUS_FMT_RGB888_1X24,
-+	.bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_POSEDGE,
-+};
-+
- static const struct drm_display_mode ampire_am_480272h3tmqw_t01h_mode = {
- 	.clock = 9000,
- 	.hdisplay = 480,
-@@ -2325,6 +2350,9 @@ static const struct panel_desc winstar_wf35ltiacd = {
- 
- static const struct of_device_id platform_of_match[] = {
- 	{
-+		.compatible = "admatec,t043c004800272t2a",
-+		.data = &admatec_t043c004800272t2a,
-+	}, {
- 		.compatible = "ampire,am-480272h3tmqw-t01h",
- 		.data = &ampire_am_480272h3tmqw_t01h,
- 	}, {
diff --git a/recipes-kernel/linux/linux-stm32mp/patches/0506-sn65dsi83-Add-ti-sn85dsi83-dsi-to-lvds-bridge-driver.patch b/recipes-kernel/linux/linux-stm32mp/patches/0506-sn65dsi83-Add-ti-sn85dsi83-dsi-to-lvds-bridge-driver.patch
deleted file mode 100644
index 9932ea9237827dfd7587f216b9210f018883ea6e..0000000000000000000000000000000000000000
--- a/recipes-kernel/linux/linux-stm32mp/patches/0506-sn65dsi83-Add-ti-sn85dsi83-dsi-to-lvds-bridge-driver.patch
+++ /dev/null
@@ -1,972 +0,0 @@
-From 8871b423ade39916b0f61920f67221c86afc0e7c Mon Sep 17 00:00:00 2001
-From: Eberhard Stoll <eberhard.stoll@kontron.de>
-Date: Tue, 2 Jul 2019 16:50:06 +0200
-Subject: [PATCH] sn65dsi83: Add ti,sn85dsi83 dsi to lvds bridge driver
-
----
- drivers/gpu/drm/bridge/Kconfig                |   2 +
- drivers/gpu/drm/bridge/Makefile               |   1 +
- drivers/gpu/drm/bridge/sn65dsi83/Kconfig      |   6 +
- drivers/gpu/drm/bridge/sn65dsi83/Makefile     |   2 +
- .../gpu/drm/bridge/sn65dsi83/sn65dsi83_brg.c  | 388 +++++++++++++++++
- .../gpu/drm/bridge/sn65dsi83/sn65dsi83_brg.h  |  55 +++
- .../gpu/drm/bridge/sn65dsi83/sn65dsi83_drv.c  | 409 ++++++++++++++++++
- .../drm/bridge/sn65dsi83/sn65dsi83_timing.h   |  33 ++
- 8 files changed, 896 insertions(+)
- create mode 100644 drivers/gpu/drm/bridge/sn65dsi83/Kconfig
- create mode 100644 drivers/gpu/drm/bridge/sn65dsi83/Makefile
- create mode 100644 drivers/gpu/drm/bridge/sn65dsi83/sn65dsi83_brg.c
- create mode 100644 drivers/gpu/drm/bridge/sn65dsi83/sn65dsi83_brg.h
- create mode 100644 drivers/gpu/drm/bridge/sn65dsi83/sn65dsi83_drv.c
- create mode 100644 drivers/gpu/drm/bridge/sn65dsi83/sn65dsi83_timing.h
-
-diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
-index fe91c205005b..6bcadabf9f37 100644
---- a/drivers/gpu/drm/bridge/Kconfig
-+++ b/drivers/gpu/drm/bridge/Kconfig
-@@ -135,4 +135,6 @@ source "drivers/gpu/drm/bridge/adv7511/Kconfig"
- 
- source "drivers/gpu/drm/bridge/synopsys/Kconfig"
- 
-+source "drivers/gpu/drm/bridge/sn65dsi83/Kconfig"
-+
- endmenu
-diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
-index 35f88d48ec20..10acd0ae6540 100644
---- a/drivers/gpu/drm/bridge/Makefile
-+++ b/drivers/gpu/drm/bridge/Makefile
-@@ -14,4 +14,5 @@ obj-$(CONFIG_DRM_TOSHIBA_TC358767) += tc358767.o
- obj-$(CONFIG_DRM_ANALOGIX_DP) += analogix/
- obj-$(CONFIG_DRM_I2C_ADV7511) += adv7511/
- obj-$(CONFIG_DRM_TI_TFP410) += ti-tfp410.o
-+obj-$(CONFIG_DRM_I2C_SN65DSI83) += sn65dsi83/
- obj-y += synopsys/
-diff --git a/drivers/gpu/drm/bridge/sn65dsi83/Kconfig b/drivers/gpu/drm/bridge/sn65dsi83/Kconfig
-new file mode 100644
-index 000000000000..ea765d36a61c
---- /dev/null
-+++ b/drivers/gpu/drm/bridge/sn65dsi83/Kconfig
-@@ -0,0 +1,6 @@
-+config DRM_I2C_SN65DSI83
-+	tristate "TI SN65DSI83 MIPI DSI to LVDS bridge"
-+	depends on OF
-+	select DRM_MIPI_DSI
-+	help
-+	  TI SN65DSI83 MIPI DSI to LVDS bridge driver
-diff --git a/drivers/gpu/drm/bridge/sn65dsi83/Makefile b/drivers/gpu/drm/bridge/sn65dsi83/Makefile
-new file mode 100644
-index 000000000000..dee7f493b323
---- /dev/null
-+++ b/drivers/gpu/drm/bridge/sn65dsi83/Makefile
-@@ -0,0 +1,2 @@
-+sn65dsi83-objs := sn65dsi83_drv.o sn65dsi83_brg.o
-+obj-$(CONFIG_DRM_I2C_SN65DSI83) := sn65dsi83.o
-diff --git a/drivers/gpu/drm/bridge/sn65dsi83/sn65dsi83_brg.c b/drivers/gpu/drm/bridge/sn65dsi83/sn65dsi83_brg.c
-new file mode 100644
-index 000000000000..727a21e73272
---- /dev/null
-+++ b/drivers/gpu/drm/bridge/sn65dsi83/sn65dsi83_brg.c
-@@ -0,0 +1,388 @@
-+/*
-+ * Copyright (C) 2018 CopuLab Ltd.
-+ *
-+ * 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/i2c.h>
-+#include <linux/device.h>
-+#include <linux/gpio/consumer.h>
-+#include <linux/module.h>
-+#include <linux/of.h>
-+#include <linux/of_device.h>
-+#include <linux/of_graph.h>
-+#include <linux/slab.h>
-+
-+#include <drm/drmP.h>
-+#include <drm/drm_atomic.h>
-+#include <drm/drm_atomic_helper.h>
-+#include <drm/drm_edid.h>
-+#include <drm/drm_mipi_dsi.h>
-+#include <drm/drm_connector.h>
-+#include <video/mipi_display.h>
-+#include <video/of_videomode.h>
-+#include <video/videomode.h>
-+
-+#include "sn65dsi83_brg.h"
-+
-+/* Register addresses */
-+
-+#define SN65DSI83_SOFT_RESET         0x09
-+#define SN65DSI83_CORE_PLL           0x0A
-+    #define LVDS_CLK_RANGE_SHIFT    1
-+    #define HS_CLK_SRC_SHIFT        0
-+
-+#define SN65DSI83_PLL_DIV            0x0B
-+    #define DSI_CLK_DIV_SHIFT       3
-+
-+#define SN65DSI83_PLL_EN             0x0D
-+#define SN65DSI83_DSI_CFG            0x10
-+    #define CHA_DSI_LANES_SHIFT    3
-+
-+#define SN65DSI83_DSI_EQ              0x11
-+#define SN65DSI83_CHA_DSI_CLK_RNG     0x12
-+#define SN65DSI83_CHB_DSI_CLK_RNG     0x13
-+#define SN65DSI83_LVDS_MODE           0x18
-+    #define DE_NEG_POLARITY_SHIFT 7
-+    #define HS_NEG_POLARITY_SHIFT 6
-+    #define VS_NEG_POLARITY_SHIFT 5
-+    #define LVDS_LINK_CFG_SHIFT   4
-+    #define CHA_24BPP_MODE_SHIFT  3
-+    #define CHA_24BPP_FMT1_SHIFT  1
-+
-+#define SN65DSI83_LVDS_SIGN           0x19
-+#define SN65DSI83_LVDS_TERM           0x1A
-+#define SN65DSI83_LVDS_CM_ADJ         0x1B
-+#define SN65DSI83_CHA_LINE_LEN_LO     0x20
-+#define SN65DSI83_CHA_LINE_LEN_HI     0x21
-+#define SN65DSI83_CHB_LINE_LEN_LO     0x22
-+#define SN65DSI83_CHB_LINE_LEN_HI     0x23
-+#define SN65DSI83_CHA_VERT_LINES_LO   0x24
-+#define SN65DSI83_CHA_VERT_LINES_HI   0x25
-+#define SN65DSI83_CHB_VERT_LINES_LO   0x26
-+#define SN65DSI83_CHB_VERT_LINES_HI   0x27
-+#define SN65DSI83_CHA_SYNC_DELAY_LO   0x28
-+#define SN65DSI83_CHA_SYNC_DELAY_HI   0x29
-+#define SN65DSI83_CHB_SYNC_DELAY_LO   0x2A
-+#define SN65DSI83_CHB_SYNC_DELAY_HI   0x2B
-+#define SN65DSI83_CHA_HSYNC_WIDTH_LO  0x2C
-+#define SN65DSI83_CHA_HSYNC_WIDTH_HI  0x2D
-+#define SN65DSI83_CHB_HSYNC_WIDTH_LO  0x2E
-+#define SN65DSI83_CHB_HSYNC_WIDTH_HI  0x2F
-+#define SN65DSI83_CHA_VSYNC_WIDTH_LO  0x30
-+#define SN65DSI83_CHA_VSYNC_WIDTH_HI  0x31
-+#define SN65DSI83_CHB_VSYNC_WIDTH_LO  0x32
-+#define SN65DSI83_CHB_VSYNC_WIDTH_HI  0x33
-+#define SN65DSI83_CHA_HORZ_BACKPORCH  0x34
-+#define SN65DSI83_CHB_HORZ_BACKPORCH  0x35
-+#define SN65DSI83_CHA_VERT_BACKPORCH  0x36
-+#define SN65DSI83_CHB_VERT_BACKPORCH  0x37
-+#define SN65DSI83_CHA_HORZ_FRONTPORCH 0x38
-+#define SN65DSI83_CHB_HORZ_FRONTPORCH 0x39
-+#define SN65DSI83_CHA_VERT_FRONTPORCH 0x3A
-+#define SN65DSI83_CHB_VERT_FRONTPORCH 0x3B
-+#define SN65DSI83_CHA_ERR             0xE5
-+#define SN65DSI83_TEST_PATTERN        0x3C
-+#define SN65DSI83_REG_3D              0x3D
-+#define SN65DSI83_REG_3E              0x3E
-+
-+static int sn65dsi83_brg_power_on(struct sn65dsi83_brg *brg)
-+{
-+    dev_dbg(&brg->client->dev,"%s\n",__func__);
-+    gpiod_set_value_cansleep(brg->gpio_enable, 1);
-+    /* Wait for 1ms for the internal voltage regulator to stabilize */
-+    msleep(1);
-+
-+    return 0;
-+}
-+
-+static void sn65dsi83_brg_power_off(struct sn65dsi83_brg *brg)
-+{
-+    dev_dbg(&brg->client->dev,"%s\n",__func__);
-+    gpiod_set_value_cansleep(brg->gpio_enable, 0);
-+    /*
-+     * The EN pin must be held low for at least 10 ms
-+     * before being asserted high
-+     */
-+    msleep(10);
-+}
-+
-+static int sn65dsi83_write(struct i2c_client *client, u8 reg, u8 val)
-+{
-+    int ret;
-+
-+    ret = i2c_smbus_write_byte_data(client, reg, val);
-+
-+    if (ret)
-+        dev_err(&client->dev, "failed to write at 0x%02x", reg);
-+
-+    dev_dbg(&client->dev, "%s: write reg 0x%02x data 0x%02x", __func__, reg, val);
-+
-+    return ret;
-+}
-+#define SN65DSI83_WRITE(reg,val) sn65dsi83_write(client, (reg) , (val))
-+
-+static int sn65dsi83_read(struct i2c_client *client, u8 reg)
-+{
-+    int ret;
-+
-+    dev_dbg(&client->dev, "client 0x%p", client);
-+    ret = i2c_smbus_read_byte_data(client, reg);
-+
-+    if (ret < 0) {
-+        dev_err(&client->dev, "failed reading at 0x%02x", reg);
-+        return ret;
-+    }
-+
-+    dev_dbg(&client->dev, "%s: read reg 0x%02x data 0x%02x", __func__, reg, ret);
-+
-+    return ret;
-+}
-+#define SN65DSI83_READ(reg) sn65dsi83_read(client, (reg))
-+
-+static int sn65dsi83_brg_start_stream(struct sn65dsi83_brg *brg)
-+{
-+    int regval;
-+    struct i2c_client *client = I2C_CLIENT(brg);
-+
-+    dev_dbg(&client->dev,"%s\n",__func__);
-+    /* Set the PLL_EN bit (CSR 0x0D.0) */
-+    SN65DSI83_WRITE(SN65DSI83_PLL_EN, 0x1);
-+    /* Wait for the PLL_LOCK bit to be set (CSR 0x0A.7) */
-+    msleep(200);
-+
-+    /* Perform SW reset to apply changes */
-+    SN65DSI83_WRITE(SN65DSI83_SOFT_RESET, 0x01);
-+
-+    /* Read CHA Error register */
-+    regval = SN65DSI83_READ(SN65DSI83_CHA_ERR);
-+    dev_dbg(&client->dev, "CHA (0x%02x) = 0x%02x",
-+         SN65DSI83_CHA_ERR, regval);
-+
-+    return 0;
-+}
-+
-+static void sn65dsi83_brg_stop_stream(struct sn65dsi83_brg *brg)
-+{
-+    struct i2c_client *client = I2C_CLIENT(brg);
-+    dev_dbg(&client->dev,"%s\n",__func__);
-+    /* Clear the PLL_EN bit (CSR 0x0D.0) */
-+    SN65DSI83_WRITE(SN65DSI83_PLL_EN, 0x00);
-+}
-+
-+static int sn65dsi83_calk_clk_range(int min_regval, int max_regval,
-+                unsigned long min_clk, unsigned long inc,
-+                unsigned long target_clk)
-+{
-+    int regval = min_regval;
-+    unsigned long clk = min_clk;
-+
-+    while (regval <= max_regval) {
-+        if ((clk <= target_clk) && (target_clk < (clk + inc)))
-+            return regval;
-+
-+        regval++;
-+        clk += inc;
-+    }
-+
-+    return -1;
-+}
-+
-+#define ABS(X) ((X) < 0 ? (-1 * (X)) : (X))
-+static int sn65dsi83_calk_div(int min_regval, int max_regval, int min_div,
-+                int inc, unsigned long source_clk,
-+                unsigned long target_clk)
-+{
-+    int regval = min_regval;
-+    int div = min_div;
-+    unsigned long curr_delta;
-+    unsigned long prev_delta = ABS(DIV_ROUND_UP(source_clk, div) -
-+                    target_clk);
-+
-+    while (regval <= max_regval) {
-+        curr_delta = ABS(DIV_ROUND_UP(source_clk, div) - target_clk);
-+        if (curr_delta > prev_delta)
-+            return --regval;
-+
-+        regval++;
-+        div += inc;
-+    }
-+
-+    return -1;
-+}
-+
-+static int sn65dsi83_brg_configure(struct sn65dsi83_brg *brg)
-+{
-+    int regval = 0;
-+    struct i2c_client *client = I2C_CLIENT(brg);
-+    struct videomode *vm = VM(brg);
-+
-+    u32 dsi_clk = (((PIXCLK * BPP(brg)) / DSI_LANES(brg)) >> 1);
-+
-+    dev_info(&client->dev, "DSI clock [ %u ] Hz\n",dsi_clk);
-+    dev_info(&client->dev, "GeoMetry [ %d x %d ] Hz\n",HACTIVE,VACTIVE);
-+
-+    /* Reset PLL_EN and SOFT_RESET registers */
-+    SN65DSI83_WRITE(SN65DSI83_SOFT_RESET,0x00);
-+    SN65DSI83_WRITE(SN65DSI83_PLL_EN,0x00);
-+
-+    /* LVDS clock setup */
-+    if  ((25000000 <= PIXCLK) && (PIXCLK < 37500000))
-+        regval = 0;
-+    else
-+        regval = sn65dsi83_calk_clk_range(0x01, 0x05, 37500000, 25000000,
-+                    PIXCLK);
-+
-+    if (regval < 0) {
-+        dev_err(&client->dev, "failed to configure LVDS clock");
-+        return -EINVAL;
-+    }
-+
-+    regval = (regval << LVDS_CLK_RANGE_SHIFT);
-+    regval |= (1 << HS_CLK_SRC_SHIFT); /* Use DSI clock */
-+    SN65DSI83_WRITE(SN65DSI83_CORE_PLL,regval);
-+
-+    /* DSI clock range */
-+    regval = sn65dsi83_calk_clk_range(0x08, 0x64, 40000000, 5000000, dsi_clk);
-+    if (regval < 0) {
-+        dev_err(&client->dev, "failed to configure DSI clock range\n");
-+        return -EINVAL;
-+    }
-+    SN65DSI83_WRITE(SN65DSI83_CHA_DSI_CLK_RNG,regval);
-+
-+    /* DSI clock divider */
-+    regval = sn65dsi83_calk_div(0x0, 0x18, 1, 1, dsi_clk, PIXCLK);
-+    if (regval < 0) {
-+        dev_err(&client->dev, "failed to calculate DSI clock divider");
-+        return -EINVAL;
-+    }
-+
-+    regval = regval << DSI_CLK_DIV_SHIFT;
-+    SN65DSI83_WRITE(SN65DSI83_PLL_DIV,regval);
-+
-+    /* Configure DSI_LANES  */
-+    regval = SN65DSI83_READ(SN65DSI83_DSI_CFG);
-+    regval &= ~(3 << CHA_DSI_LANES_SHIFT);
-+    regval |= ((4 - DSI_LANES(brg)) << CHA_DSI_LANES_SHIFT);
-+    SN65DSI83_WRITE(SN65DSI83_DSI_CFG,regval);
-+
-+    /* CHA_DSI_DATA_EQ - No Equalization */
-+    /* CHA_DSI_CLK_EQ  - No Equalization */
-+    SN65DSI83_WRITE(SN65DSI83_DSI_EQ,0x00);
-+
-+    /* Video formats */
-+    regval = 0;
-+    if (FLAGS & DISPLAY_FLAGS_HSYNC_LOW)
-+        regval |= (1 << HS_NEG_POLARITY_SHIFT);
-+
-+    if (FLAGS & DISPLAY_FLAGS_VSYNC_LOW)
-+        regval |= (1 << VS_NEG_POLARITY_SHIFT);
-+
-+    if (FLAGS & DISPLAY_FLAGS_DE_LOW)
-+        regval |= (1 << DE_NEG_POLARITY_SHIFT);
-+
-+    if (BPP(brg) == 24)
-+        regval |= (1 << CHA_24BPP_MODE_SHIFT);
-+
-+    if (FORMAT(brg) == 1)
-+        regval |= (1 << CHA_24BPP_FMT1_SHIFT);
-+
-+    regval |= (1 << LVDS_LINK_CFG_SHIFT);
-+    SN65DSI83_WRITE(SN65DSI83_LVDS_MODE,regval);
-+
-+    /* Voltage and pins */
-+    SN65DSI83_WRITE(SN65DSI83_LVDS_SIGN,0x00);
-+    SN65DSI83_WRITE(SN65DSI83_LVDS_TERM,0x03);
-+    SN65DSI83_WRITE(SN65DSI83_LVDS_CM_ADJ,0x00);
-+
-+    /* Configure sync delay to minimal allowed value */
-+    SN65DSI83_WRITE(SN65DSI83_CHA_SYNC_DELAY_LO,0x21);
-+    SN65DSI83_WRITE(SN65DSI83_CHA_SYNC_DELAY_HI,0x00);
-+
-+    /* Geometry */
-+    SN65DSI83_WRITE(SN65DSI83_CHA_LINE_LEN_LO,LOW(HACTIVE));
-+    SN65DSI83_WRITE(SN65DSI83_CHA_LINE_LEN_HI,HIGH(HACTIVE));
-+
-+    SN65DSI83_WRITE(SN65DSI83_CHA_VERT_LINES_LO,LOW(VACTIVE));
-+    SN65DSI83_WRITE(SN65DSI83_CHA_VERT_LINES_HI,HIGH(VACTIVE));
-+
-+    SN65DSI83_WRITE(SN65DSI83_CHA_HSYNC_WIDTH_LO,LOW(HPW));
-+    SN65DSI83_WRITE(SN65DSI83_CHA_HSYNC_WIDTH_HI,HIGH(HPW));
-+
-+    SN65DSI83_WRITE(SN65DSI83_CHA_VSYNC_WIDTH_LO,LOW(VPW));
-+    SN65DSI83_WRITE(SN65DSI83_CHA_VSYNC_WIDTH_HI,HIGH(VPW));
-+
-+    SN65DSI83_WRITE(SN65DSI83_CHA_HORZ_BACKPORCH,LOW(HBP));
-+    SN65DSI83_WRITE(SN65DSI83_CHA_VERT_BACKPORCH,LOW(VBP));
-+
-+    SN65DSI83_WRITE(SN65DSI83_CHA_HORZ_FRONTPORCH,LOW(HFP));
-+    SN65DSI83_WRITE(SN65DSI83_CHA_VERT_FRONTPORCH,LOW(VFP));
-+
-+    SN65DSI83_WRITE(SN65DSI83_TEST_PATTERN,0x00);
-+    SN65DSI83_WRITE(SN65DSI83_REG_3D,0x00);
-+    SN65DSI83_WRITE(SN65DSI83_REG_3E,0x00);
-+
-+    /* mute channel B */
-+    SN65DSI83_WRITE(SN65DSI83_CHB_DSI_CLK_RNG, 0x00);
-+    SN65DSI83_WRITE(SN65DSI83_CHB_LINE_LEN_LO, 0x00);
-+    SN65DSI83_WRITE(SN65DSI83_CHB_LINE_LEN_HI, 0x00);
-+    SN65DSI83_WRITE(SN65DSI83_CHB_VERT_LINES_LO, 0x00);
-+    SN65DSI83_WRITE(SN65DSI83_CHB_VERT_LINES_HI, 0x00);
-+    SN65DSI83_WRITE(SN65DSI83_CHB_SYNC_DELAY_LO, 0x00);
-+    SN65DSI83_WRITE(SN65DSI83_CHB_SYNC_DELAY_HI, 0x00);
-+    SN65DSI83_WRITE(SN65DSI83_CHB_HSYNC_WIDTH_LO, 0x00);
-+    SN65DSI83_WRITE(SN65DSI83_CHB_HSYNC_WIDTH_HI, 0x00);
-+    SN65DSI83_WRITE(SN65DSI83_CHB_VSYNC_WIDTH_LO, 0x00);
-+    SN65DSI83_WRITE(SN65DSI83_CHB_VSYNC_WIDTH_HI, 0x00);
-+    SN65DSI83_WRITE(SN65DSI83_CHB_HORZ_BACKPORCH, 0x00);
-+    SN65DSI83_WRITE(SN65DSI83_CHB_VERT_BACKPORCH, 0x00);
-+    SN65DSI83_WRITE(SN65DSI83_CHB_HORZ_FRONTPORCH, 0x00);
-+    SN65DSI83_WRITE(SN65DSI83_CHB_VERT_FRONTPORCH, 0x00);
-+    return 0;
-+}
-+
-+static int sn65dsi83_brg_setup(struct sn65dsi83_brg *brg)
-+{
-+    struct i2c_client *client = I2C_CLIENT(brg);
-+    dev_dbg(&client->dev,"%s\n",__func__);
-+    sn65dsi83_brg_power_on(brg);
-+    return sn65dsi83_brg_configure(brg);
-+}
-+
-+static int sn65dsi83_brg_reset(struct sn65dsi83_brg *brg)
-+{
-+    /* Soft Reset reg value at power on should be 0x00 */
-+    struct i2c_client *client = I2C_CLIENT(brg);
-+    int ret = SN65DSI83_READ(SN65DSI83_SOFT_RESET);
-+    dev_dbg(&client->dev,"%s\n",__func__);
-+    if (ret != 0x00) {
-+        dev_err(&client->dev,"Failed to reset the device");
-+        return -ENODEV;
-+    }
-+    return 0;
-+}
-+
-+static struct sn65dsi83_brg_funcs brg_func = {
-+    .power_on = sn65dsi83_brg_power_on,
-+    .power_off = sn65dsi83_brg_power_off,
-+    .setup = sn65dsi83_brg_setup,
-+    .reset = sn65dsi83_brg_reset,
-+    .start_stream = sn65dsi83_brg_start_stream,
-+    .stop_stream = sn65dsi83_brg_stop_stream,
-+};
-+
-+static struct sn65dsi83_brg brg = {
-+    .funcs = &brg_func,
-+};
-+
-+struct sn65dsi83_brg *sn65dsi83_brg_get(void) {
-+    return &brg;
-+}
-diff --git a/drivers/gpu/drm/bridge/sn65dsi83/sn65dsi83_brg.h b/drivers/gpu/drm/bridge/sn65dsi83/sn65dsi83_brg.h
-new file mode 100644
-index 000000000000..9f23df8afedc
---- /dev/null
-+++ b/drivers/gpu/drm/bridge/sn65dsi83/sn65dsi83_brg.h
-@@ -0,0 +1,55 @@
-+#ifndef _SN65DSI83_BRG_H__
-+#define _SN65DSI83_BRG_H__
-+
-+#include <linux/i2c.h>
-+#include <linux/gpio/consumer.h>
-+#include <video/videomode.h>
-+
-+struct sn65dsi83_brg;
-+struct sn65dsi83_brg_funcs {
-+    int (*power_on)(struct sn65dsi83_brg *sn65dsi8383_brg);
-+    void (*power_off)(struct sn65dsi83_brg *sn65dsi8383_brg);
-+    int (*reset)(struct sn65dsi83_brg *sn65dsi8383_brg);
-+    int (*setup)(struct sn65dsi83_brg *sn65dsi8383_brg);
-+    int (*start_stream)(struct sn65dsi83_brg *sn65dsi8383_brg);
-+    void (*stop_stream)(struct sn65dsi83_brg *sn65dsi8383_brg);
-+};
-+
-+struct sn65dsi83_brg {
-+    struct i2c_client *client;
-+    struct gpio_desc *gpio_enable;
-+    /* Bridge Panel Parameters */
-+    struct videomode vm;
-+    u32 width_mm;
-+    u32 height_mm;
-+    u32 format;
-+    u32 bpp;
-+
-+    u8 num_dsi_lanes;
-+    struct sn65dsi83_brg_funcs *funcs;
-+};
-+struct sn65dsi83_brg *sn65dsi83_brg_get(void);
-+
-+#define I2C_DEVICE(A) &(A)->client->dev
-+#define I2C_CLIENT(A) (A)->client
-+#define VM(A) &(A)->vm
-+#define BPP(A) (A)->bpp
-+#define FORMAT(A) (A)->format
-+#define DSI_LANES(A) (A)->num_dsi_lanes
-+
-+/* The caller has to have a vm structure defined */
-+#define PIXCLK vm->pixelclock
-+#define HACTIVE vm->hactive
-+#define HFP vm->hfront_porch
-+#define HBP vm->hback_porch
-+#define HPW vm->hsync_len
-+#define VACTIVE vm->vactive
-+#define VFP vm->vfront_porch
-+#define VBP vm->vback_porch
-+#define VPW vm->vsync_len
-+#define FLAGS vm->flags
-+
-+#define HIGH(A) (((A) >> 8) & 0xFF)
-+#define LOW(A)  ((A)  & 0xFF)
-+
-+#endif /* _SN65DSI83_BRG_H__ */
-diff --git a/drivers/gpu/drm/bridge/sn65dsi83/sn65dsi83_drv.c b/drivers/gpu/drm/bridge/sn65dsi83/sn65dsi83_drv.c
-new file mode 100644
-index 000000000000..0e59da263881
---- /dev/null
-+++ b/drivers/gpu/drm/bridge/sn65dsi83/sn65dsi83_drv.c
-@@ -0,0 +1,409 @@
-+/*
-+ * Licensed under the GPL-2.
-+ */
-+
-+#include <linux/device.h>
-+#include <linux/gpio/consumer.h>
-+#include <linux/module.h>
-+#include <linux/of.h>
-+#include <linux/of_device.h>
-+#include <linux/of_graph.h>
-+#include <linux/slab.h>
-+
-+#include <drm/drmP.h>
-+#include <drm/drm_atomic.h>
-+#include <drm/drm_atomic_helper.h>
-+#include <drm/drm_edid.h>
-+#include <drm/drm_mipi_dsi.h>
-+#include <drm/drm_connector.h>
-+#include <drm/drm_crtc_helper.h>
-+#include <video/mipi_display.h>
-+#include <video/of_videomode.h>
-+#include <video/videomode.h>
-+
-+#include "sn65dsi83_timing.h"
-+#include "sn65dsi83_brg.h"
-+
-+struct sn65dsi83 {
-+    u8 channel_id;
-+    enum drm_connector_status status;
-+    bool powered;
-+    struct drm_display_mode curr_mode;
-+    struct drm_bridge bridge;
-+    struct drm_connector connector;
-+    struct device_node *host_node;
-+    struct mipi_dsi_device *dsi;
-+    struct sn65dsi83_brg *brg;
-+};
-+
-+static int sn65dsi83_attach_dsi(struct sn65dsi83 *sn65dsi83);
-+#define DRM_DEVICE(A) A->dev->dev
-+/* Connector funcs */
-+static struct sn65dsi83 *connector_to_sn65dsi83(struct drm_connector *connector)
-+{
-+    return container_of(connector, struct sn65dsi83, connector);
-+}
-+
-+static int sn65dsi83_connector_get_modes(struct drm_connector *connector)
-+{
-+    struct sn65dsi83 *sn65dsi83 = connector_to_sn65dsi83(connector);
-+    struct sn65dsi83_brg *brg = sn65dsi83->brg;
-+    struct device *dev = connector->dev->dev;
-+    struct drm_display_mode *mode;
-+    u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24;
-+    u32 *bus_flags = &connector->display_info.bus_flags;
-+    int ret;
-+
-+    dev_dbg(dev, "%s\n",__func__);
-+    mode = drm_mode_create(connector->dev);
-+    if (!mode) {
-+        DRM_DEV_ERROR(dev, "Failed to create display mode!\n");
-+        return 0;
-+    }
-+
-+    drm_display_mode_from_videomode(&brg->vm, mode);
-+    mode->width_mm = brg->width_mm;
-+    mode->height_mm = brg->height_mm;
-+    mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
-+
-+    drm_mode_probed_add(connector, mode);
-+    drm_connector_list_update(connector);
-+
-+    connector->display_info.width_mm = mode->width_mm;
-+    connector->display_info.height_mm = mode->height_mm;
-+
-+    if (brg->vm.flags & DISPLAY_FLAGS_DE_HIGH)
-+        *bus_flags |= DRM_BUS_FLAG_DE_HIGH;
-+    if (brg->vm.flags & DISPLAY_FLAGS_DE_LOW)
-+        *bus_flags |= DRM_BUS_FLAG_DE_LOW;
-+    if (brg->vm.flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE)
-+        *bus_flags |= DRM_BUS_FLAG_PIXDATA_NEGEDGE;
-+    if (brg->vm.flags & DISPLAY_FLAGS_PIXDATA_POSEDGE)
-+        *bus_flags |= DRM_BUS_FLAG_PIXDATA_POSEDGE;
-+
-+    ret = drm_display_info_set_bus_formats(&connector->display_info,
-+                           &bus_format, 1);
-+    if (ret)
-+        return ret;
-+
-+    return 1;
-+}
-+
-+static enum drm_mode_status
-+sn65dsi83_connector_mode_valid(struct drm_connector *connector,
-+                 struct drm_display_mode *mode)
-+{
-+    struct sn65dsi83 *sn65dsi83 = connector_to_sn65dsi83(connector);
-+    struct device *dev = connector->dev->dev;
-+	if (mode->clock > ( sn65dsi83->brg->vm.pixelclock / 1000 ))
-+		return MODE_CLOCK_HIGH;
-+
-+    dev_info(dev, "%s: mode: %d*%d@%d is valid\n",__func__,
-+            mode->hdisplay,mode->vdisplay,mode->clock);
-+    return MODE_OK;
-+}
-+
-+static struct drm_connector_helper_funcs sn65dsi83_connector_helper_funcs = {
-+    .get_modes = sn65dsi83_connector_get_modes,
-+    .mode_valid = sn65dsi83_connector_mode_valid,
-+};
-+
-+static enum drm_connector_status
-+sn65dsi83_connector_detect(struct drm_connector *connector, bool force)
-+{
-+    struct sn65dsi83 *sn65dsi83 = connector_to_sn65dsi83(connector);
-+    struct device *dev = connector->dev->dev;
-+    enum drm_connector_status status;
-+    dev_dbg(dev, "%s\n",__func__);
-+
-+    status = connector_status_connected;
-+    sn65dsi83->status = status;
-+    return status;
-+}
-+
-+int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
-+                        uint32_t maxX, uint32_t maxY);
-+
-+static struct drm_connector_funcs sn65dsi83_connector_funcs = {
-+    .fill_modes = drm_helper_probe_single_connector_modes,
-+    .detect = sn65dsi83_connector_detect,
-+    .destroy = drm_connector_cleanup,
-+    .reset = drm_atomic_helper_connector_reset,
-+    .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
-+    .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
-+};
-+
-+/* Bridge funcs */
-+static struct sn65dsi83 *bridge_to_sn65dsi83(struct drm_bridge *bridge)
-+{
-+    return container_of(bridge, struct sn65dsi83, bridge);
-+}
-+
-+static void sn65dsi83_bridge_enable(struct drm_bridge *bridge)
-+{
-+    struct sn65dsi83 *sn65dsi83 = bridge_to_sn65dsi83(bridge);
-+    dev_dbg(DRM_DEVICE(bridge),"%s\n",__func__);
-+    sn65dsi83->brg->funcs->setup(sn65dsi83->brg);
-+    sn65dsi83->brg->funcs->start_stream(sn65dsi83->brg);
-+}
-+
-+static void sn65dsi83_bridge_disable(struct drm_bridge *bridge)
-+{
-+    struct sn65dsi83 *sn65dsi83 = bridge_to_sn65dsi83(bridge);
-+    dev_dbg(DRM_DEVICE(bridge),"%s\n",__func__);
-+    sn65dsi83->brg->funcs->stop_stream(sn65dsi83->brg);
-+    sn65dsi83->brg->funcs->power_off(sn65dsi83->brg);
-+}
-+
-+static void sn65dsi83_bridge_mode_set(struct drm_bridge *bridge,
-+                    struct drm_display_mode *mode,
-+                    struct drm_display_mode *adj_mode)
-+{
-+    struct sn65dsi83 *sn65dsi83 = bridge_to_sn65dsi83(bridge);
-+    dev_dbg(DRM_DEVICE(bridge), "%s: mode: %d*%d@%d\n",__func__,
-+            mode->hdisplay,mode->vdisplay,mode->clock);
-+    drm_mode_copy(&sn65dsi83->curr_mode, adj_mode);
-+}
-+
-+static int sn65dsi83_bridge_attach(struct drm_bridge *bridge)
-+{
-+    struct sn65dsi83 *sn65dsi83 = bridge_to_sn65dsi83(bridge);
-+    int ret;
-+
-+    dev_dbg(DRM_DEVICE(bridge),"%s\n",__func__);
-+    if (!bridge->encoder) {
-+        DRM_ERROR("Parent encoder object not found");
-+        return -ENODEV;
-+    }
-+
-+    sn65dsi83->connector.polled = DRM_CONNECTOR_POLL_CONNECT;
-+
-+    ret = drm_connector_init(bridge->dev, &sn65dsi83->connector,
-+                 &sn65dsi83_connector_funcs,
-+                 DRM_MODE_CONNECTOR_DSI);
-+    if (ret) {
-+        DRM_ERROR("Failed to initialize connector with drm\n");
-+        return ret;
-+    }
-+    drm_connector_helper_add(&sn65dsi83->connector,
-+                 &sn65dsi83_connector_helper_funcs);
-+    drm_connector_attach_encoder(&sn65dsi83->connector, bridge->encoder);
-+
-+    ret = sn65dsi83_attach_dsi(sn65dsi83);
-+
-+    return ret;
-+}
-+
-+static struct drm_bridge_funcs sn65dsi83_bridge_funcs = {
-+    .enable = sn65dsi83_bridge_enable,
-+    .disable = sn65dsi83_bridge_disable,
-+    .mode_set = sn65dsi83_bridge_mode_set,
-+    .attach = sn65dsi83_bridge_attach,
-+};
-+
-+static int sn65dsi83_parse_dt(struct device_node *np,
-+    struct sn65dsi83 *sn65dsi83)
-+{
-+    struct device *dev = &sn65dsi83->brg->client->dev;
-+    u32 num_lanes = 2, bpp = 24, format = 2, width = 149, height = 93;
-+    struct device_node *endpoint;
-+
-+    endpoint = of_graph_get_next_endpoint(np, NULL);
-+    if (!endpoint)
-+        return -ENODEV;
-+
-+    sn65dsi83->host_node = of_graph_get_remote_port_parent(endpoint);
-+    if (!sn65dsi83->host_node) {
-+        of_node_put(endpoint);
-+        return -ENODEV;
-+    }
-+
-+    of_property_read_u32(np, "ti,dsi-lanes", &num_lanes);
-+    of_property_read_u32(np, "ti,lvds-format", &format);
-+    of_property_read_u32(np, "ti,lvds-bpp", &bpp);
-+    of_property_read_u32(np, "ti,width-mm", &width);
-+    of_property_read_u32(np, "ti,height-mm", &height);
-+
-+    if (num_lanes < 1 || num_lanes > 4) {
-+        dev_err(dev, "Invalid dsi-lanes: %d\n", num_lanes);
-+        return -EINVAL;
-+    }
-+    sn65dsi83->brg->num_dsi_lanes = num_lanes;
-+
-+    sn65dsi83->brg->gpio_enable = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
-+    if (IS_ERR(sn65dsi83->brg->gpio_enable)) {
-+        dev_err(dev, "failed to parse enable gpio");
-+        return PTR_ERR(sn65dsi83->brg->gpio_enable);
-+    }
-+
-+    sn65dsi83->brg->format = format;
-+    sn65dsi83->brg->bpp = bpp;
-+
-+    sn65dsi83->brg->width_mm = width;
-+    sn65dsi83->brg->height_mm = height;
-+
-+    /* Read default timing if there is not device tree node for */
-+    if ((of_get_videomode(np, &sn65dsi83->brg->vm, 0)) < 0)
-+        videomode_from_timing(&panel_default_timing, &sn65dsi83->brg->vm);
-+
-+    of_node_put(endpoint);
-+    of_node_put(sn65dsi83->host_node);
-+
-+    return 0;
-+}
-+
-+static int sn65dsi83_probe(struct i2c_client *i2c,
-+    const struct i2c_device_id *id)
-+{
-+    struct sn65dsi83 *sn65dsi83;
-+    struct device *dev = &i2c->dev;
-+    int ret;
-+
-+    dev_dbg(dev,"%s\n",__func__);
-+    if (!dev->of_node)
-+        return -EINVAL;
-+
-+    sn65dsi83 = devm_kzalloc(dev, sizeof(*sn65dsi83), GFP_KERNEL);
-+    if (!sn65dsi83)
-+        return -ENOMEM;
-+
-+    /* Initialize it before DT parser */
-+    sn65dsi83->brg = sn65dsi83_brg_get();
-+    sn65dsi83->brg->client = i2c;
-+
-+    sn65dsi83->powered = false;
-+    sn65dsi83->status = connector_status_disconnected;
-+
-+    i2c_set_clientdata(i2c, sn65dsi83);
-+
-+    ret = sn65dsi83_parse_dt(dev->of_node, sn65dsi83);
-+    if (ret)
-+        return ret;
-+
-+    sn65dsi83->brg->funcs->power_off(sn65dsi83->brg);
-+    sn65dsi83->brg->funcs->power_on(sn65dsi83->brg);
-+    ret  = sn65dsi83->brg->funcs->reset(sn65dsi83->brg);
-+    if (ret != 0x00) {
-+        dev_err(dev, "Failed to reset the device");
-+        return -ENODEV;
-+    }
-+    sn65dsi83->brg->funcs->power_off(sn65dsi83->brg);
-+
-+
-+    sn65dsi83->bridge.funcs = &sn65dsi83_bridge_funcs;
-+    sn65dsi83->bridge.of_node = dev->of_node;
-+
-+    drm_bridge_add(&sn65dsi83->bridge);
-+
-+    return ret;
-+}
-+
-+static int sn65dsi83_attach_dsi(struct sn65dsi83 *sn65dsi83)
-+{
-+    struct device *dev = &sn65dsi83->brg->client->dev;
-+    struct mipi_dsi_host *host;
-+    struct mipi_dsi_device *dsi;
-+    int ret = 0;
-+    const struct mipi_dsi_device_info info = { .type = "sn65dsi83",
-+                           .channel = 0,
-+                           .node = NULL,
-+                         };
-+
-+    dev_dbg(dev, "%s\n",__func__);
-+    host = of_find_mipi_dsi_host_by_node(sn65dsi83->host_node);
-+    if (!host) {
-+        dev_err(dev, "failed to find dsi host\n");
-+        return -EPROBE_DEFER;
-+    }
-+
-+    dsi = mipi_dsi_device_register_full(host, &info);
-+    if (IS_ERR(dsi)) {
-+        dev_err(dev, "failed to create dsi device\n");
-+        ret = PTR_ERR(dsi);
-+        return -ENODEV;
-+    }
-+
-+    sn65dsi83->dsi = dsi;
-+
-+    dsi->lanes = sn65dsi83->brg->num_dsi_lanes;
-+    dsi->format = MIPI_DSI_FMT_RGB888;
-+    dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST;
-+    //dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_HSE |
-+    //           MIPI_DSI_CLOCK_NON_CONTINUOUS;
-+
-+    ret = mipi_dsi_attach(dsi);
-+    if (ret < 0) {
-+        dev_err(dev, "failed to attach dsi to host\n");
-+        mipi_dsi_device_unregister(dsi);
-+    }
-+
-+    return ret;
-+}
-+
-+static void sn65dsi83_detach_dsi(struct sn65dsi83 *sn65dsi83)
-+{
-+    struct device *dev = &sn65dsi83->brg->client->dev;
-+    dev_dbg(dev, "%s\n",__func__);
-+    mipi_dsi_detach(sn65dsi83->dsi);
-+    mipi_dsi_device_unregister(sn65dsi83->dsi);
-+}
-+
-+static int sn65dsi83_remove(struct i2c_client *i2c)
-+{
-+    struct sn65dsi83 *sn65dsi83 = i2c_get_clientdata(i2c);
-+    struct device *dev = &sn65dsi83->brg->client->dev;
-+    dev_dbg(dev, "%s\n",__func__);
-+
-+    sn65dsi83_detach_dsi(sn65dsi83);
-+    drm_bridge_remove(&sn65dsi83->bridge);
-+
-+    return 0;
-+}
-+
-+static const struct i2c_device_id sn65dsi83_i2c_ids[] = {
-+    { "sn65dsi83", 0 },
-+    { }
-+};
-+MODULE_DEVICE_TABLE(i2c, sn65dsi83_i2c_ids);
-+
-+static const struct of_device_id sn65dsi83_of_ids[] = {
-+    { .compatible = "ti,sn65dsi83" },
-+    { }
-+};
-+MODULE_DEVICE_TABLE(of, sn65dsi83_of_ids);
-+
-+static struct mipi_dsi_driver sn65dsi83_dsi_driver = {
-+    .driver.name = "sn65dsi83",
-+};
-+
-+static struct i2c_driver sn65dsi83_driver = {
-+    .driver = {
-+        .name = "sn65dsi83",
-+        .of_match_table = sn65dsi83_of_ids,
-+    },
-+    .id_table = sn65dsi83_i2c_ids,
-+    .probe = sn65dsi83_probe,
-+    .remove = sn65dsi83_remove,
-+};
-+
-+static int __init sn65dsi83_init(void)
-+{
-+    if (IS_ENABLED(CONFIG_DRM_MIPI_DSI))
-+        mipi_dsi_driver_register(&sn65dsi83_dsi_driver);
-+
-+    return i2c_add_driver(&sn65dsi83_driver);
-+}
-+module_init(sn65dsi83_init);
-+
-+static void __exit sn65dsi83_exit(void)
-+{
-+    i2c_del_driver(&sn65dsi83_driver);
-+
-+    if (IS_ENABLED(CONFIG_DRM_MIPI_DSI))
-+        mipi_dsi_driver_unregister(&sn65dsi83_dsi_driver);
-+}
-+module_exit(sn65dsi83_exit);
-+
-+MODULE_AUTHOR("CompuLab <compulab@compula.co.il>");
-+MODULE_DESCRIPTION("SN65DSI bridge driver");
-+MODULE_LICENSE("GPL");
-diff --git a/drivers/gpu/drm/bridge/sn65dsi83/sn65dsi83_timing.h b/drivers/gpu/drm/bridge/sn65dsi83/sn65dsi83_timing.h
-new file mode 100644
-index 000000000000..e9bb6633c376
---- /dev/null
-+++ b/drivers/gpu/drm/bridge/sn65dsi83/sn65dsi83_timing.h
-@@ -0,0 +1,33 @@
-+#ifndef __SN65DSI83_TIMING_H__
-+#define __SN65DSI83_TIMING_H__
-+
-+/* Default Video Parameters */
-+#define PIXCLK_INIT 62500000
-+
-+#define HACTIVE_INIT 1280
-+#define HPW_INIT 2
-+#define HBP_INIT 6
-+#define HFP_INIT 5
-+
-+#define VACTIVE_INIT 800
-+#define VPW_INIT 1
-+#define VBP_INIT 2
-+#define VFP_INIT 3
-+
-+static const struct display_timing panel_default_timing = {
-+    .pixelclock = { PIXCLK_INIT, PIXCLK_INIT, PIXCLK_INIT },
-+    .hactive = { HACTIVE_INIT, HACTIVE_INIT, HACTIVE_INIT },
-+    .hfront_porch = { HFP_INIT, HFP_INIT, HFP_INIT },
-+    .hsync_len = { HPW_INIT, HPW_INIT, HPW_INIT },
-+    .hback_porch = { HBP_INIT, HBP_INIT, HBP_INIT },
-+    .vactive = { VACTIVE_INIT, VACTIVE_INIT, VACTIVE_INIT },
-+    .vfront_porch = { VFP_INIT, VFP_INIT, VFP_INIT },
-+    .vsync_len = { VPW_INIT, VPW_INIT, VPW_INIT },
-+    .vback_porch = { VBP_INIT, VBP_INIT, VBP_INIT },
-+    .flags = DISPLAY_FLAGS_HSYNC_LOW |
-+         DISPLAY_FLAGS_VSYNC_LOW |
-+         DISPLAY_FLAGS_DE_LOW |
-+         DISPLAY_FLAGS_PIXDATA_NEGEDGE,
-+};
-+
-+#endif /* __SN65DSI83_TIMING_H__ */
diff --git a/recipes-kernel/linux/linux-stm32mp/patches/0507-wm8510-switch-to-mclk-on-hw-init.patch b/recipes-kernel/linux/linux-stm32mp/patches/0507-wm8510-switch-to-mclk-on-hw-init.patch
deleted file mode 100644
index 11d1e867d86921aae1932d03b8996fccaa5b8926..0000000000000000000000000000000000000000
--- a/recipes-kernel/linux/linux-stm32mp/patches/0507-wm8510-switch-to-mclk-on-hw-init.patch
+++ /dev/null
@@ -1,38 +0,0 @@
-From 7d00823f3f7f05c6d9e37736642ae0833635909e Mon Sep 17 00:00:00 2001
-From: pibeck <philipp.beck@exceet.de>
-Date: Fri, 24 May 2019 10:46:37 +0200
-Subject: [PATCH] wm8510 switch to mclk on hw init
-
----
- sound/soc/codecs/wm8510.c | 11 +++++++++++
- 1 file changed, 11 insertions(+)
-
-diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c
-index 1a2412d73e35..3685bdc79b6b 100644
---- a/sound/soc/codecs/wm8510.c
-+++ b/sound/soc/codecs/wm8510.c
-@@ -447,6 +447,7 @@ static int wm8510_pcm_hw_params(struct snd_pcm_substream *substream,
- 	struct snd_soc_component *component = dai->component;
- 	u16 iface = snd_soc_component_read32(component, WM8510_IFACE) & 0x19f;
- 	u16 adn = snd_soc_component_read32(component, WM8510_ADD) & 0x1f1;
-+	u16 reg;
- 
- 	/* bit size */
- 	switch (params_width(params)) {
-@@ -487,6 +488,16 @@ static int wm8510_pcm_hw_params(struct snd_pcm_substream *substream,
- 
- 	snd_soc_component_write(component, WM8510_IFACE, iface);
- 	snd_soc_component_write(component, WM8510_ADD, adn);
-+
-+	/* Clock CODEC directly from MCLK */
-+	reg = snd_soc_component_read32(component, WM8510_CLOCK);
-+	snd_soc_component_write(component, WM8510_CLOCK, reg & 0x0ff);
-+
-+	/* Turn off PLL */
-+	reg = snd_soc_component_read32(component, WM8510_POWER1);
-+	snd_soc_component_write(component, WM8510_POWER1, reg & 0x1df);
-+
-+
- 	return 0;
- }
- 
diff --git a/recipes-kernel/linux/linux-stm32mp/patches/0508-add-spi-clock-debug-print.patch b/recipes-kernel/linux/linux-stm32mp/patches/0508-add-spi-clock-debug-print.patch
deleted file mode 100644
index cab0bdd6e3d1c0952c5394b1f3261ee94aecc881..0000000000000000000000000000000000000000
--- a/recipes-kernel/linux/linux-stm32mp/patches/0508-add-spi-clock-debug-print.patch
+++ /dev/null
@@ -1,22 +0,0 @@
-From 3a40e8818bd09eb1ae1bd71a1208adc1ec91f491 Mon Sep 17 00:00:00 2001
-From: Eberhard Stoll <eberhard.stoll@kontron.de>
-Date: Mon, 5 Aug 2019 14:40:50 +0200
-Subject: [PATCH] add spi clock debug print
-
----
- drivers/spi/spi-stm32.c | 2 ++
- 1 file changed, 2 insertions(+)
-
-diff --git a/drivers/spi/spi-stm32.c b/drivers/spi/spi-stm32.c
-index b0887645c099..124c2c3dacf9 100644
---- a/drivers/spi/spi-stm32.c
-+++ b/drivers/spi/spi-stm32.c
-@@ -275,6 +275,8 @@ static int stm32_spi_prepare_mbr(struct stm32_spi *spi, u32 speed_hz)
- 		mbrdiv = fls(div) - 1;
- 
- 	spi->cur_speed = spi->clk_rate / (1 << mbrdiv);
-+	dev_dbg(spi->dev, "%s: cur_speed=%d, clk_rate=%d, mbrdiv=%d\n",
-+		__func__, spi->cur_speed, spi->clk_rate, mbrdiv);
- 
- 	return mbrdiv - 1;
- }
diff --git a/recipes-kernel/linux/linux-stm32mp/patches/0509-pinctl-disable-strict-checking.patch b/recipes-kernel/linux/linux-stm32mp/patches/0509-pinctl-disable-strict-checking.patch
deleted file mode 100644
index aa76297443cd465bd05aaccae4e5a7e606cbe314..0000000000000000000000000000000000000000
--- a/recipes-kernel/linux/linux-stm32mp/patches/0509-pinctl-disable-strict-checking.patch
+++ /dev/null
@@ -1,23 +0,0 @@
-From 0a8bd2ec9e2d2b3699503378492587dea5b6497b Mon Sep 17 00:00:00 2001
-From: Eberhard Stoll <eberhard.stoll@kontron.de>
-Date: Tue, 8 Oct 2019 14:39:47 +0200
-Subject: [PATCH] pinctl disable strict checking
-
----
- drivers/pinctrl/stm32/pinctrl-stm32.c | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
-diff --git a/drivers/pinctrl/stm32/pinctrl-stm32.c b/drivers/pinctrl/stm32/pinctrl-stm32.c
-index 5b71c978da7a..8761c5a7afec 100644
---- a/drivers/pinctrl/stm32/pinctrl-stm32.c
-+++ b/drivers/pinctrl/stm32/pinctrl-stm32.c
-@@ -776,7 +776,8 @@ static const struct pinmux_ops stm32_pmx_ops = {
- 	.get_function_groups	= stm32_pmx_get_func_groups,
- 	.set_mux		= stm32_pmx_set_mux,
- 	.gpio_set_direction	= stm32_pmx_gpio_set_direction,
--	.strict			= true,
-+	.strict			= false,
-+	/*.strict			= true,*/
- };
- 
- /* Pinconf functions */
diff --git a/recipes-kernel/linux/linux-stm32mp/patches/0510-adv7511-mainline-5.4.x-code-integrated.patch b/recipes-kernel/linux/linux-stm32mp/patches/0510-adv7511-mainline-5.4.x-code-integrated.patch
deleted file mode 100644
index e744611600ad936ae2ffd93b67e4c6c8975ce1e1..0000000000000000000000000000000000000000
--- a/recipes-kernel/linux/linux-stm32mp/patches/0510-adv7511-mainline-5.4.x-code-integrated.patch
+++ /dev/null
@@ -1,220 +0,0 @@
-From 604a4a45fef7914746314870ae413b8eb51fe408 Mon Sep 17 00:00:00 2001
-From: Eberhard Stoll <eberhard.stoll@kontron.de>
-Date: Thu, 5 Dec 2019 14:16:57 +0100
-Subject: [PATCH] adv7511: mainline 5.4.x code integrated
-
----
- drivers/gpu/drm/bridge/adv7511/Kconfig        |  1 +
- drivers/gpu/drm/bridge/adv7511/Makefile       |  1 +
- drivers/gpu/drm/bridge/adv7511/adv7511.h      | 11 ++---
- .../gpu/drm/bridge/adv7511/adv7511_audio.c    |  3 +-
- drivers/gpu/drm/bridge/adv7511/adv7511_drv.c  | 44 +++++++++----------
- drivers/gpu/drm/bridge/adv7511/adv7533.c      | 12 +----
- 6 files changed, 33 insertions(+), 39 deletions(-)
-
-diff --git a/drivers/gpu/drm/bridge/adv7511/Kconfig b/drivers/gpu/drm/bridge/adv7511/Kconfig
-index 944e440c4fde..8a56ff81f4fb 100644
---- a/drivers/gpu/drm/bridge/adv7511/Kconfig
-+++ b/drivers/gpu/drm/bridge/adv7511/Kconfig
-@@ -1,3 +1,4 @@
-+# SPDX-License-Identifier: GPL-2.0-only
- config DRM_I2C_ADV7511
- 	tristate "ADV7511 encoder"
- 	depends on OF
-diff --git a/drivers/gpu/drm/bridge/adv7511/Makefile b/drivers/gpu/drm/bridge/adv7511/Makefile
-index 5bb384938a71..b46ebeb35fd4 100644
---- a/drivers/gpu/drm/bridge/adv7511/Makefile
-+++ b/drivers/gpu/drm/bridge/adv7511/Makefile
-@@ -1,3 +1,4 @@
-+# SPDX-License-Identifier: GPL-2.0-only
- adv7511-y := adv7511_drv.o
- adv7511-$(CONFIG_DRM_I2C_ADV7511_AUDIO) += adv7511_audio.o
- adv7511-$(CONFIG_DRM_I2C_ADV7511_CEC) += adv7511_cec.o
-diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511.h b/drivers/gpu/drm/bridge/adv7511/adv7511.h
-index 73d8ccb97742..52b2adfdc877 100644
---- a/drivers/gpu/drm/bridge/adv7511/adv7511.h
-+++ b/drivers/gpu/drm/bridge/adv7511/adv7511.h
-@@ -1,9 +1,8 @@
-+/* SPDX-License-Identifier: GPL-2.0-only */
- /*
-  * Analog Devices ADV7511 HDMI transmitter driver
-  *
-  * Copyright 2012 Analog Devices Inc.
-- *
-- * Licensed under the GPL-2.
-  */
- 
- #ifndef __DRM_I2C_ADV7511_H__
-@@ -14,8 +13,10 @@
- #include <linux/regmap.h>
- #include <linux/regulator/consumer.h>
- 
--#include <drm/drm_crtc_helper.h>
-+#include <drm/drm_bridge.h>
-+#include <drm/drm_connector.h>
- #include <drm/drm_mipi_dsi.h>
-+#include <drm/drm_modes.h>
- 
- #define ADV7511_REG_CHIP_REVISION		0x00
- #define ADV7511_REG_N0				0x01
-@@ -395,7 +396,7 @@ static inline int adv7511_cec_init(struct device *dev, struct adv7511 *adv7511)
- #ifdef CONFIG_DRM_I2C_ADV7533
- void adv7533_dsi_power_on(struct adv7511 *adv);
- void adv7533_dsi_power_off(struct adv7511 *adv);
--void adv7533_mode_set(struct adv7511 *adv, struct drm_display_mode *mode);
-+void adv7533_mode_set(struct adv7511 *adv, const struct drm_display_mode *mode);
- int adv7533_patch_registers(struct adv7511 *adv);
- int adv7533_patch_cec_registers(struct adv7511 *adv);
- int adv7533_attach_dsi(struct adv7511 *adv);
-@@ -411,7 +412,7 @@ static inline void adv7533_dsi_power_off(struct adv7511 *adv)
- }
- 
- static inline void adv7533_mode_set(struct adv7511 *adv,
--				    struct drm_display_mode *mode)
-+				    const struct drm_display_mode *mode)
- {
- }
- 
-diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_audio.c b/drivers/gpu/drm/bridge/adv7511/adv7511_audio.c
-index 1b4783d45c53..a428185be2c1 100644
---- a/drivers/gpu/drm/bridge/adv7511/adv7511_audio.c
-+++ b/drivers/gpu/drm/bridge/adv7511/adv7511_audio.c
-@@ -1,10 +1,9 @@
-+// SPDX-License-Identifier: GPL-2.0-only
- /*
-  * Analog Devices ADV7511 HDMI transmitter driver
-  *
-  * Copyright 2012 Analog Devices Inc.
-  * Copyright (c) 2016, Linaro Limited
-- *
-- * Licensed under the GPL-2.
-  */
- 
- #include <sound/core.h>
-diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
-index 85c2d407a52e..9e13e466e72c 100644
---- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
-+++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
-@@ -1,24 +1,24 @@
-+// SPDX-License-Identifier: GPL-2.0-only
- /*
-  * Analog Devices ADV7511 HDMI transmitter driver
-  *
-  * Copyright 2012 Analog Devices Inc.
-- *
-- * Licensed under the GPL-2.
-  */
- 
-+#include <linux/clk.h>
- #include <linux/device.h>
- #include <linux/gpio/consumer.h>
- #include <linux/module.h>
- #include <linux/of_device.h>
- #include <linux/slab.h>
--#include <linux/clk.h>
- 
--#include <drm/drmP.h>
-+#include <media/cec.h>
-+
- #include <drm/drm_atomic.h>
- #include <drm/drm_atomic_helper.h>
- #include <drm/drm_edid.h>
--
--#include <media/cec.h>
-+#include <drm/drm_print.h>
-+#include <drm/drm_probe_helper.h>
- 
- #include "adv7511.h"
- 
-@@ -676,8 +676,8 @@ static enum drm_mode_status adv7511_mode_valid(struct adv7511 *adv7511,
- }
- 
- static void adv7511_mode_set(struct adv7511 *adv7511,
--			     struct drm_display_mode *mode,
--			     struct drm_display_mode *adj_mode)
-+			     const struct drm_display_mode *mode,
-+			     const struct drm_display_mode *adj_mode)
- {
- 	unsigned int low_refresh_rate;
- 	unsigned int hsync_polarity = 0;
-@@ -839,8 +839,8 @@ static void adv7511_bridge_disable(struct drm_bridge *bridge)
- }
- 
- static void adv7511_bridge_mode_set(struct drm_bridge *bridge,
--				    struct drm_display_mode *mode,
--				    struct drm_display_mode *adj_mode)
-+				    const struct drm_display_mode *mode,
-+				    const struct drm_display_mode *adj_mode)
- {
- 	struct adv7511 *adv = bridge_to_adv7511(bridge);
- 
-@@ -981,10 +981,10 @@ static int adv7511_init_cec_regmap(struct adv7511 *adv)
- {
- 	int ret;
- 
--	adv->i2c_cec = i2c_new_secondary_device(adv->i2c_main, "cec",
-+	adv->i2c_cec = i2c_new_ancillary_device(adv->i2c_main, "cec",
- 						ADV7511_CEC_I2C_ADDR_DEFAULT);
--	if (!adv->i2c_cec)
--		return -EINVAL;
-+	if (IS_ERR(adv->i2c_cec))
-+		return PTR_ERR(adv->i2c_cec);
- 	i2c_set_clientdata(adv->i2c_cec, adv);
- 
- 	adv->regmap_cec = devm_regmap_init_i2c(adv->i2c_cec,
-@@ -1165,20 +1165,20 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
- 
- 	adv7511_packet_disable(adv7511, 0xffff);
- 
--	adv7511->i2c_edid = i2c_new_secondary_device(i2c, "edid",
-+	adv7511->i2c_edid = i2c_new_ancillary_device(i2c, "edid",
- 					ADV7511_EDID_I2C_ADDR_DEFAULT);
--	if (!adv7511->i2c_edid) {
--		ret = -EINVAL;
-+	if (IS_ERR(adv7511->i2c_edid)) {
-+		ret = PTR_ERR(adv7511->i2c_edid);
- 		goto uninit_regulators;
- 	}
- 
- 	regmap_write(adv7511->regmap, ADV7511_REG_EDID_I2C_ADDR,
- 		     adv7511->i2c_edid->addr << 1);
- 
--	adv7511->i2c_packet = i2c_new_secondary_device(i2c, "packet",
-+	adv7511->i2c_packet = i2c_new_ancillary_device(i2c, "packet",
- 					ADV7511_PACKET_I2C_ADDR_DEFAULT);
--	if (!adv7511->i2c_packet) {
--		ret = -EINVAL;
-+	if (IS_ERR(adv7511->i2c_packet)) {
-+		ret = PTR_ERR(adv7511->i2c_packet);
- 		goto err_i2c_unregister_edid;
- 	}
- 
-diff --git a/drivers/gpu/drm/bridge/adv7511/adv7533.c b/drivers/gpu/drm/bridge/adv7511/adv7533.c
-index 185b6d842166..aa19d5a40e31 100644
---- a/drivers/gpu/drm/bridge/adv7511/adv7533.c
-+++ b/drivers/gpu/drm/bridge/adv7511/adv7533.c
-@@ -1,14 +1,6 @@
-+// SPDX-License-Identifier: GPL-2.0-only
- /*
-  * Copyright (c) 2016, The Linux Foundation. All rights reserved.
-- *
-- * This program is free software; you can redistribute it and/or modify
-- * it under the terms of the GNU General Public License version 2 and
-- * only 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/of_graph.h>
-@@ -108,7 +100,7 @@ void adv7533_dsi_power_off(struct adv7511 *adv)
- 	regmap_write(adv->regmap_cec, 0x27, 0x0b);
- }
- 
--void adv7533_mode_set(struct adv7511 *adv, struct drm_display_mode *mode)
-+void adv7533_mode_set(struct adv7511 *adv, const struct drm_display_mode *mode)
- {
- 	struct mipi_dsi_device *dsi = adv->dsi;
- 	int lanes, ret;
diff --git a/recipes-kernel/linux/linux-stm32mp/patches/0511-dt-bindings-drm-bridge-adv7511-Add-ADV7535-support.patch b/recipes-kernel/linux/linux-stm32mp/patches/0511-dt-bindings-drm-bridge-adv7511-Add-ADV7535-support.patch
deleted file mode 100644
index 5522cef4f8928001771f2445e8e45b257d5f6c78..0000000000000000000000000000000000000000
--- a/recipes-kernel/linux/linux-stm32mp/patches/0511-dt-bindings-drm-bridge-adv7511-Add-ADV7535-support.patch
+++ /dev/null
@@ -1,82 +0,0 @@
-From b00e48036af4fbdd93f8e98d16c2ecbe828ea2f3 Mon Sep 17 00:00:00 2001
-From: Bogdan Togorean <bogdan.togorean@analog.com>
-Date: Thu, 28 Nov 2019 20:00:19 +0200
-Subject: [PATCH] dt-bindings: drm: bridge: adv7511: Add ADV7535 support
-
-ADV7535 is a part compatible with ADV7533 but it supports 1080p@60hz and
-v1p2 supply is fixed to 1.8V
-
-Signed-off-by: Bogdan Togorean <bogdan.togorean@analog.com>
-Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
-
----
- .../bindings/display/bridge/adi,adv7511.txt   | 23 ++++++++++---------
- 1 file changed, 12 insertions(+), 11 deletions(-)
-
-diff --git a/Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt b/Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt
-index 2c887536258c..e8ddec5d9d91 100644
---- a/Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt
-+++ b/Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt
-@@ -1,10 +1,10 @@
--Analog Device ADV7511(W)/13/33 HDMI Encoders
-+Analog Device ADV7511(W)/13/33/35 HDMI Encoders
- -----------------------------------------
- 
--The ADV7511, ADV7511W, ADV7513 and ADV7533 are HDMI audio and video transmitters
--compatible with HDMI 1.4 and DVI 1.0. They support color space conversion,
--S/PDIF, CEC and HDCP. ADV7533 supports the DSI interface for input pixels, while
--the others support RGB interface.
-+The ADV7511, ADV7511W, ADV7513, ADV7533 and ADV7535 are HDMI audio and video
-+transmitters compatible with HDMI 1.4 and DVI 1.0. They support color space
-+conversion, S/PDIF, CEC and HDCP. ADV7533/5 supports the DSI interface for input
-+pixels, while the others support RGB interface.
- 
- Required properties:
- 
-@@ -13,6 +13,7 @@ Required properties:
- 		"adi,adv7511w"
- 		"adi,adv7513"
- 		"adi,adv7533"
-+		"adi,adv7535"
- 
- - reg: I2C slave addresses
-   The ADV7511 internal registers are split into four pages exposed through
-@@ -52,14 +53,14 @@ The following input format properties are required except in "rgb 1x" and
- - bgvdd-supply: A 1.8V supply that powers up the BGVDD pin. This is
-   needed only for ADV7511.
- 
--The following properties are required for ADV7533:
-+The following properties are required for ADV7533 and ADV7535:
- 
- - adi,dsi-lanes: Number of DSI data lanes connected to the DSI host. It should
-   be one of 1, 2, 3 or 4.
- - a2vdd-supply: 1.8V supply that powers up the A2VDD pin on the chip.
- - v3p3-supply: A 3.3V supply that powers up the V3P3 pin on the chip.
- - v1p2-supply: A supply that powers up the V1P2 pin on the chip. It can be
--  either 1.2V or 1.8V.
-+  either 1.2V or 1.8V for ADV7533 but only 1.8V for ADV7535.
- 
- Optional properties:
- 
-@@ -71,9 +72,9 @@ Optional properties:
- - adi,embedded-sync: The input uses synchronization signals embedded in the
-   data stream (similar to BT.656). Defaults to separate H/V synchronization
-   signals.
--- adi,disable-timing-generator: Only for ADV7533. Disables the internal timing
--  generator. The chip will rely on the sync signals in the DSI data lanes,
--  rather than generate its own timings for HDMI output.
-+- adi,disable-timing-generator: Only for ADV7533 and ADV7535. Disables the
-+  internal timing generator. The chip will rely on the sync signals in the
-+  DSI data lanes, rather than generate its own timings for HDMI output.
- - clocks: from common clock binding: reference to the CEC clock.
- - clock-names: from common clock binding: must be "cec".
- - reg-names : Names of maps with programmable addresses.
-@@ -85,7 +86,7 @@ Required nodes:
- The ADV7511 has two video ports. Their connections are modelled using the OF
- graph bindings specified in Documentation/devicetree/bindings/graph.txt.
- 
--- Video port 0 for the RGB, YUV or DSI input. In the case of ADV7533, the
-+- Video port 0 for the RGB, YUV or DSI input. In the case of ADV7533/5, the
-   remote endpoint phandle should be a reference to a valid mipi_dsi_host device
-   node.
- - Video port 1 for the HDMI output
diff --git a/recipes-kernel/linux/linux-stm32mp/patches/0512-drm-bridge-adv7511-Add-support-for-ADV7535.patch b/recipes-kernel/linux/linux-stm32mp/patches/0512-drm-bridge-adv7511-Add-support-for-ADV7535.patch
deleted file mode 100644
index 0f4e8c97135a65aa4bd6cec1e09026a50c0ea932..0000000000000000000000000000000000000000
--- a/recipes-kernel/linux/linux-stm32mp/patches/0512-drm-bridge-adv7511-Add-support-for-ADV7535.patch
+++ /dev/null
@@ -1,265 +0,0 @@
-From a972ad002ec0a6caa1cba49db2430e814ce4c8b7 Mon Sep 17 00:00:00 2001
-From: Bogdan Togorean <bogdan.togorean@analog.com>
-Date: Thu, 28 Nov 2019 20:00:20 +0200
-Subject: [PATCH] drm: bridge: adv7511: Add support for ADV7535
-
-ADV7535 is a DSI to HDMI bridge chip like ADV7533 but it allows
-1080p@60Hz. v1p2 is fixed to 1.8V on ADV7535 but on ADV7533 can be 1.2V
-or 1.8V and is configurable in a register.
-
-Signed-off-by: Bogdan Togorean <bogdan.togorean@analog.com>
-
----
- drivers/gpu/drm/bridge/adv7511/Kconfig       | 13 ++----
- drivers/gpu/drm/bridge/adv7511/Makefile      |  3 +-
- drivers/gpu/drm/bridge/adv7511/adv7511.h     | 44 +++-----------------
- drivers/gpu/drm/bridge/adv7511/adv7511_drv.c | 35 ++++++++++------
- 4 files changed, 32 insertions(+), 63 deletions(-)
-
-diff --git a/drivers/gpu/drm/bridge/adv7511/Kconfig b/drivers/gpu/drm/bridge/adv7511/Kconfig
-index 8a56ff81f4fb..47d4eb9e845d 100644
---- a/drivers/gpu/drm/bridge/adv7511/Kconfig
-+++ b/drivers/gpu/drm/bridge/adv7511/Kconfig
-@@ -4,8 +4,9 @@ config DRM_I2C_ADV7511
- 	depends on OF
- 	select DRM_KMS_HELPER
- 	select REGMAP_I2C
-+	select DRM_MIPI_DSI
- 	help
--	  Support for the Analog Device ADV7511(W) and ADV7513 HDMI encoders.
-+	  Support for the Analog Device ADV7511(W)/13/33/35 HDMI encoders.
- 
- config DRM_I2C_ADV7511_AUDIO
- 	bool "ADV7511 HDMI Audio driver"
-@@ -15,16 +16,8 @@ config DRM_I2C_ADV7511_AUDIO
- 	  Support the ADV7511 HDMI Audio interface. This is used in
- 	  conjunction with the AV7511  HDMI driver.
- 
--config DRM_I2C_ADV7533
--	bool "ADV7533 encoder"
--	depends on DRM_I2C_ADV7511
--	select DRM_MIPI_DSI
--	default y
--	help
--	  Support for the Analog Devices ADV7533 DSI to HDMI encoder.
--
- config DRM_I2C_ADV7511_CEC
--	bool "ADV7511/33 HDMI CEC driver"
-+	bool "ADV7511/33/35 HDMI CEC driver"
- 	depends on DRM_I2C_ADV7511
- 	select CEC_CORE
- 	default y
-diff --git a/drivers/gpu/drm/bridge/adv7511/Makefile b/drivers/gpu/drm/bridge/adv7511/Makefile
-index b46ebeb35fd4..d8ceb534b51f 100644
---- a/drivers/gpu/drm/bridge/adv7511/Makefile
-+++ b/drivers/gpu/drm/bridge/adv7511/Makefile
-@@ -1,6 +1,5 @@
- # SPDX-License-Identifier: GPL-2.0-only
--adv7511-y := adv7511_drv.o
-+adv7511-y := adv7511_drv.o adv7533.o
- adv7511-$(CONFIG_DRM_I2C_ADV7511_AUDIO) += adv7511_audio.o
- adv7511-$(CONFIG_DRM_I2C_ADV7511_CEC) += adv7511_cec.o
--adv7511-$(CONFIG_DRM_I2C_ADV7533) += adv7533.o
- obj-$(CONFIG_DRM_I2C_ADV7511) += adv7511.o
-diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511.h b/drivers/gpu/drm/bridge/adv7511/adv7511.h
-index 52b2adfdc877..ed9cfd944098 100644
---- a/drivers/gpu/drm/bridge/adv7511/adv7511.h
-+++ b/drivers/gpu/drm/bridge/adv7511/adv7511.h
-@@ -220,6 +220,10 @@
- 
- #define ADV7533_REG_CEC_OFFSET		0x70
- 
-+#define ADV7533_REG_SUPPLY_SELECT	0xe4
-+
-+#define ADV7533_V1P2_ENABLE		BIT(7)
-+
- enum adv7511_input_clock {
- 	ADV7511_INPUT_CLOCK_1X,
- 	ADV7511_INPUT_CLOCK_2X,
-@@ -320,6 +324,7 @@ struct adv7511_video_config {
- enum adv7511_type {
- 	ADV7511,
- 	ADV7533,
-+	ADV7535,
- };
- 
- #define ADV7511_MAX_ADDRS 3
-@@ -393,7 +398,6 @@ static inline int adv7511_cec_init(struct device *dev, struct adv7511 *adv7511)
- }
- #endif
- 
--#ifdef CONFIG_DRM_I2C_ADV7533
- void adv7533_dsi_power_on(struct adv7511 *adv);
- void adv7533_dsi_power_off(struct adv7511 *adv);
- void adv7533_mode_set(struct adv7511 *adv, const struct drm_display_mode *mode);
-@@ -402,44 +406,6 @@ int adv7533_patch_cec_registers(struct adv7511 *adv);
- int adv7533_attach_dsi(struct adv7511 *adv);
- void adv7533_detach_dsi(struct adv7511 *adv);
- int adv7533_parse_dt(struct device_node *np, struct adv7511 *adv);
--#else
--static inline void adv7533_dsi_power_on(struct adv7511 *adv)
--{
--}
--
--static inline void adv7533_dsi_power_off(struct adv7511 *adv)
--{
--}
--
--static inline void adv7533_mode_set(struct adv7511 *adv,
--				    const struct drm_display_mode *mode)
--{
--}
--
--static inline int adv7533_patch_registers(struct adv7511 *adv)
--{
--	return -ENODEV;
--}
--
--static inline int adv7533_patch_cec_registers(struct adv7511 *adv)
--{
--	return -ENODEV;
--}
--
--static inline int adv7533_attach_dsi(struct adv7511 *adv)
--{
--	return -ENODEV;
--}
--
--static inline void adv7533_detach_dsi(struct adv7511 *adv)
--{
--}
--
--static inline int adv7533_parse_dt(struct device_node *np, struct adv7511 *adv)
--{
--	return -ENODEV;
--}
--#endif
- 
- #ifdef CONFIG_DRM_I2C_ADV7511_AUDIO
- int adv7511_audio_init(struct device *dev, struct adv7511 *adv7511);
-diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
-index 9e13e466e72c..35595472e771 100644
---- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
-+++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
-@@ -367,7 +367,7 @@ static void adv7511_power_on(struct adv7511 *adv7511)
- 	 */
- 	regcache_sync(adv7511->regmap);
- 
--	if (adv7511->type == ADV7533)
-+	if (adv7511->type == ADV7533 || adv7511->type == ADV7535)
- 		adv7533_dsi_power_on(adv7511);
- 	adv7511->powered = true;
- }
-@@ -387,7 +387,7 @@ static void __adv7511_power_off(struct adv7511 *adv7511)
- static void adv7511_power_off(struct adv7511 *adv7511)
- {
- 	__adv7511_power_off(adv7511);
--	if (adv7511->type == ADV7533)
-+	if (adv7511->type == ADV7533 || adv7511->type == ADV7535)
- 		adv7533_dsi_power_off(adv7511);
- 	adv7511->powered = false;
- }
-@@ -761,7 +761,7 @@ static void adv7511_mode_set(struct adv7511 *adv7511,
- 	regmap_update_bits(adv7511->regmap, 0x17,
- 		0x60, (vsync_polarity << 6) | (hsync_polarity << 5));
- 
--	if (adv7511->type == ADV7533)
-+	if (adv7511->type == ADV7533 || adv7511->type == ADV7535)
- 		adv7533_mode_set(adv7511, adj_mode);
- 
- 	drm_mode_copy(&adv7511->curr_mode, adj_mode);
-@@ -874,7 +874,7 @@ static int adv7511_bridge_attach(struct drm_bridge *bridge)
- 				 &adv7511_connector_helper_funcs);
- 	drm_connector_attach_encoder(&adv->connector, bridge->encoder);
- 
--	if (adv->type == ADV7533)
-+	if (adv->type == ADV7533 || adv->type == ADV7535)
- 		ret = adv7533_attach_dsi(adv);
- 
- 	if (adv->i2c_main->irq)
-@@ -903,6 +903,7 @@ static const char * const adv7511_supply_names[] = {
- 	"dvdd-3v",
- };
- 
-+/* The order of entries is important. If changed update hardcoded indices */
- static const char * const adv7533_supply_names[] = {
- 	"avdd",
- 	"dvdd",
-@@ -952,7 +953,7 @@ static bool adv7511_cec_register_volatile(struct device *dev, unsigned int reg)
- 	struct i2c_client *i2c = to_i2c_client(dev);
- 	struct adv7511 *adv7511 = i2c_get_clientdata(i2c);
- 
--	if (adv7511->type == ADV7533)
-+	if (adv7511->type == ADV7533 || adv7511->type == ADV7535)
- 		reg -= ADV7533_REG_CEC_OFFSET;
- 
- 	switch (reg) {
-@@ -994,7 +995,7 @@ static int adv7511_init_cec_regmap(struct adv7511 *adv)
- 		goto err;
- 	}
- 
--	if (adv->type == ADV7533) {
-+	if (adv->type == ADV7533 || adv->type == ADV7535) {
- 		ret = adv7533_patch_cec_registers(adv);
- 		if (ret)
- 			goto err;
-@@ -1094,8 +1095,9 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
- 	struct adv7511_link_config link_config;
- 	struct adv7511 *adv7511;
- 	struct device *dev = &i2c->dev;
-+	struct regulator *reg_v1p2;
- 	unsigned int val;
--	int ret;
-+	int ret, reg_v1p2_uV;
- 
- 	if (!dev->of_node)
- 		return -EINVAL;
-@@ -1163,6 +1165,17 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
- 	if (ret)
- 		goto uninit_regulators;
- 
-+	if (adv7511->type == ADV7533) {
-+		reg_v1p2 = adv7511->supplies[5].consumer;
-+		reg_v1p2_uV = regulator_get_voltage(reg_v1p2);
-+
-+		if (reg_v1p2_uV == 1200000) {
-+			regmap_update_bits(adv7511->regmap,
-+				ADV7533_REG_SUPPLY_SELECT, ADV7533_V1P2_ENABLE,
-+				ADV7533_V1P2_ENABLE);
-+		}
-+	}
-+
- 	adv7511_packet_disable(adv7511, 0xffff);
- 
- 	adv7511->i2c_edid = i2c_new_ancillary_device(i2c, "edid",
-@@ -1242,7 +1255,7 @@ static int adv7511_remove(struct i2c_client *i2c)
- {
- 	struct adv7511 *adv7511 = i2c_get_clientdata(i2c);
- 
--	if (adv7511->type == ADV7533)
-+	if (adv7511->type == ADV7533 || adv7511->type == ADV7535)
- 		adv7533_detach_dsi(adv7511);
- 	i2c_unregister_device(adv7511->i2c_cec);
- 	if (adv7511->cec_clk)
-@@ -1266,9 +1279,8 @@ static const struct i2c_device_id adv7511_i2c_ids[] = {
- 	{ "adv7511", ADV7511 },
- 	{ "adv7511w", ADV7511 },
- 	{ "adv7513", ADV7511 },
--#ifdef CONFIG_DRM_I2C_ADV7533
- 	{ "adv7533", ADV7533 },
--#endif
-+	{ "adv7535", ADV7535 },
- 	{ }
- };
- MODULE_DEVICE_TABLE(i2c, adv7511_i2c_ids);
-@@ -1277,9 +1289,8 @@ static const struct of_device_id adv7511_of_ids[] = {
- 	{ .compatible = "adi,adv7511", .data = (void *)ADV7511 },
- 	{ .compatible = "adi,adv7511w", .data = (void *)ADV7511 },
- 	{ .compatible = "adi,adv7513", .data = (void *)ADV7511 },
--#ifdef CONFIG_DRM_I2C_ADV7533
- 	{ .compatible = "adi,adv7533", .data = (void *)ADV7533 },
--#endif
-+	{ .compatible = "adi,adv7535", .data = (void *)ADV7535 },
- 	{ }
- };
- MODULE_DEVICE_TABLE(of, adv7511_of_ids);
diff --git a/recipes-kernel/linux/linux-stm32mp/patches/0513-adapt-kernel-interfaces.patch b/recipes-kernel/linux/linux-stm32mp/patches/0513-adapt-kernel-interfaces.patch
deleted file mode 100644
index 912e1b6aad267486dc1f6c5c15280009c1d7cd3e..0000000000000000000000000000000000000000
--- a/recipes-kernel/linux/linux-stm32mp/patches/0513-adapt-kernel-interfaces.patch
+++ /dev/null
@@ -1,100 +0,0 @@
-From 7114c78cb3521d66e172e1640da202b910ba8af0 Mon Sep 17 00:00:00 2001
-From: Eberhard Stoll <eberhard.stoll@kontron.de>
-Date: Thu, 5 Dec 2019 15:29:26 +0100
-Subject: [PATCH] adapt kernel interfaces
-
----
- drivers/gpu/drm/bridge/adv7511/adv7511_drv.c | 22 ++++++++--------
- include/drm/drm_probe_helper.h               | 27 ++++++++++++++++++++
- 2 files changed, 38 insertions(+), 11 deletions(-)
- create mode 100644 include/drm/drm_probe_helper.h
-
-diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
-index 35595472e771..d84d7dc57b22 100644
---- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
-+++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
-@@ -839,8 +839,8 @@ static void adv7511_bridge_disable(struct drm_bridge *bridge)
- }
- 
- static void adv7511_bridge_mode_set(struct drm_bridge *bridge,
--				    const struct drm_display_mode *mode,
--				    const struct drm_display_mode *adj_mode)
-+				    /*const*/ struct drm_display_mode *mode,
-+				    /*const*/ struct drm_display_mode *adj_mode)
- {
- 	struct adv7511 *adv = bridge_to_adv7511(bridge);
- 
-@@ -982,10 +982,10 @@ static int adv7511_init_cec_regmap(struct adv7511 *adv)
- {
- 	int ret;
- 
--	adv->i2c_cec = i2c_new_ancillary_device(adv->i2c_main, "cec",
-+	adv->i2c_cec = i2c_new_secondary_device(adv->i2c_main, "cec",
- 						ADV7511_CEC_I2C_ADDR_DEFAULT);
--	if (IS_ERR(adv->i2c_cec))
--		return PTR_ERR(adv->i2c_cec);
-+	if (!adv->i2c_cec)
-+		return -EINVAL;
- 	i2c_set_clientdata(adv->i2c_cec, adv);
- 
- 	adv->regmap_cec = devm_regmap_init_i2c(adv->i2c_cec,
-@@ -1178,20 +1178,20 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
- 
- 	adv7511_packet_disable(adv7511, 0xffff);
- 
--	adv7511->i2c_edid = i2c_new_ancillary_device(i2c, "edid",
-+	adv7511->i2c_edid = i2c_new_secondary_device(i2c, "edid",
- 					ADV7511_EDID_I2C_ADDR_DEFAULT);
--	if (IS_ERR(adv7511->i2c_edid)) {
--		ret = PTR_ERR(adv7511->i2c_edid);
-+	if (!adv7511->i2c_edid) {
-+		ret = -EINVAL;
- 		goto uninit_regulators;
- 	}
- 
- 	regmap_write(adv7511->regmap, ADV7511_REG_EDID_I2C_ADDR,
- 		     adv7511->i2c_edid->addr << 1);
- 
--	adv7511->i2c_packet = i2c_new_ancillary_device(i2c, "packet",
-+	adv7511->i2c_packet = i2c_new_secondary_device(i2c, "packet",
- 					ADV7511_PACKET_I2C_ADDR_DEFAULT);
--	if (IS_ERR(adv7511->i2c_packet)) {
--		ret = PTR_ERR(adv7511->i2c_packet);
-+	if (!adv7511->i2c_packet) {
-+		ret = -EINVAL;
- 		goto err_i2c_unregister_edid;
- 	}
- 
-diff --git a/include/drm/drm_probe_helper.h b/include/drm/drm_probe_helper.h
-new file mode 100644
-index 000000000000..8d3ed2834d34
---- /dev/null
-+++ b/include/drm/drm_probe_helper.h
-@@ -0,0 +1,27 @@
-+// SPDX-License-Identifier: GPL-2.0 OR MIT
-+
-+#ifndef __DRM_PROBE_HELPER_H__
-+#define __DRM_PROBE_HELPER_H__
-+
-+#include <linux/types.h>
-+
-+struct drm_connector;
-+struct drm_device;
-+struct drm_modeset_acquire_ctx;
-+
-+int drm_helper_probe_single_connector_modes(struct drm_connector
-+					    *connector, uint32_t maxX,
-+					    uint32_t maxY);
-+int drm_helper_probe_detect(struct drm_connector *connector,
-+			    struct drm_modeset_acquire_ctx *ctx,
-+			    bool force);
-+void drm_kms_helper_poll_init(struct drm_device *dev);
-+void drm_kms_helper_poll_fini(struct drm_device *dev);
-+bool drm_helper_hpd_irq_event(struct drm_device *dev);
-+void drm_kms_helper_hotplug_event(struct drm_device *dev);
-+
-+void drm_kms_helper_poll_disable(struct drm_device *dev);
-+void drm_kms_helper_poll_enable(struct drm_device *dev);
-+bool drm_kms_helper_is_poll_worker(void);
-+
-+#endif
diff --git a/recipes-kernel/linux/linux-stm32mp/patches/0514-add-drm_probe_helper.h.patch b/recipes-kernel/linux/linux-stm32mp/patches/0514-add-drm_probe_helper.h.patch
deleted file mode 100644
index c38ace9ad5e4e26451dbf279150bd78f2aa24933..0000000000000000000000000000000000000000
--- a/recipes-kernel/linux/linux-stm32mp/patches/0514-add-drm_probe_helper.h.patch
+++ /dev/null
@@ -1,42 +0,0 @@
-From: Manuel Schreiner, manuel.schreiner@accso.de
-Date: Wed, 26th July 2023
-Subject: [PATCH] add missing drm_probe_helper.h
-
----
- include/drm/drm_probe_helper.h               | 27 ++++++++++++++++++++
- 1 files changed, 27 insertions(+)
- create mode 100644 include/drm/drm_probe_helper.h
-
-diff --git a/include/drm/drm_probe_helper.h b/include/drm/drm_probe_helper.h
-new file mode 100644
-index 000000000000..8d3ed2834d34
---- /dev/null
-+++ b/include/drm/drm_probe_helper.h
-@@ -0,0 +1,27 @@
-+// SPDX-License-Identifier: GPL-2.0 OR MIT
-+
-+#ifndef __DRM_PROBE_HELPER_H__
-+#define __DRM_PROBE_HELPER_H__
-+
-+#include <linux/types.h>
-+
-+struct drm_connector;
-+struct drm_device;
-+struct drm_modeset_acquire_ctx;
-+
-+int drm_helper_probe_single_connector_modes(struct drm_connector
-+					    *connector, uint32_t maxX,
-+					    uint32_t maxY);
-+int drm_helper_probe_detect(struct drm_connector *connector,
-+			    struct drm_modeset_acquire_ctx *ctx,
-+			    bool force);
-+void drm_kms_helper_poll_init(struct drm_device *dev);
-+void drm_kms_helper_poll_fini(struct drm_device *dev);
-+bool drm_helper_hpd_irq_event(struct drm_device *dev);
-+void drm_kms_helper_hotplug_event(struct drm_device *dev);
-+
-+void drm_kms_helper_poll_disable(struct drm_device *dev);
-+void drm_kms_helper_poll_enable(struct drm_device *dev);
-+bool drm_kms_helper_is_poll_worker(void);
-+
-+#endif
diff --git a/recipes-kernel/linux/linux-stm32mp/patches/rename_patches.sh b/recipes-kernel/linux/linux-stm32mp/patches/rename_patches.sh
deleted file mode 100644
index 6ff4e3d0f26652205eb3b9187c6e4ae4e4f06522..0000000000000000000000000000000000000000
--- a/recipes-kernel/linux/linux-stm32mp/patches/rename_patches.sh
+++ /dev/null
@@ -1,20 +0,0 @@
-patches=$(ls 10*-*.patch)
-counter=1
-for patch in $patches
-do
-  mv $patch 0001-$patch  
-done
-patches=$(ls 11*-*.patch)
-counter=1
-for patch in $patches
-do
-  mv $patch 0001-$patch
-done
-patches=$(ls 12*-*.patch)
-counter=1
-for patch in $patches
-do
-  mv $patch 0001-$patch
-done
-
-
diff --git a/recipes-kernel/linux/linux-stm32mp/stm32mp-board-k.dtsi b/recipes-kernel/linux/linux-stm32mp/stm32mp-board-k.dtsi
deleted file mode 100644
index dfa9af57218f5f88606678c7c5417ed06fe6c437..0000000000000000000000000000000000000000
--- a/recipes-kernel/linux/linux-stm32mp/stm32mp-board-k.dtsi
+++ /dev/null
@@ -1,465 +0,0 @@
-/* Devicetree file for device
- *
- * device   : stm32mp-board-k
- * revision : 0
- *
- * Kontron Electronics GmbH
- * Copyright 2019 Kontron Electronics GmbH. All rights reserved.
- */
-
-#include <dt-bindings/gpio/gpio.h>
-
-/ {
-	device-identification {
-		board = "k";
-		board_pcb = "1 951 1825";
-		board_code = "40099 176 00";
-	};
-
-	aliases {
-		serial0 = &uart4;    /* console */
-		serial1 = &usart2;   /* rs485 */
-		serial2 = &usart3;   /* rs232 */
-		ethernet1 = &ethernet1;
-	};
-
-	v5v: regulator-v5v {
-		compatible = "regulator-fixed";
-		regulator-name = "v5v";
-		regulator-min-microvolt = <5000000>;
-		regulator-max-microvolt = <5000000>;
-		regulator-always-on;
-		status = "okay";
-	};
-
-	vdd_sd: regulator-vdd_sd {
-		compatible = "regulator-fixed";
-		regulator-name = "vdd_sd";
-		regulator-min-microvolt = <3300000>;
-		regulator-max-microvolt = <3300000>;
-		regulator-always-on;
-		status = "okay";
-	};
-
-	vdd_1v8: regulator-1v8 {
-		compatible = "regulator-fixed";
-		regulator-name = "vdd_1v8";
-		regulator-min-microvolt = <1800000>;
-		regulator-max-microvolt = <1800000>;
-		regulator-always-on;
-		status = "okay";
-	};
-
-	reg_dsi_sel: regulator-dsi-sel {
-		compatible = "regulator-fixed";
-		regulator-name = "rst-dsi-sel";
-		gpio = <&gpiod 13 GPIO_ACTIVE_HIGH>;
-		regulator-always-on;
-		enable-active-high; /* select hdmi output: set to HIGH voltage */
-		status = "okay";
-	};
-
-	beeper:pwm-beeper {
-		compatible = "pwm-beeper";
-		/* pwm timers1, Channel 2 */
-		/* Use 440Hz which is default frequency for beep command */
-		pwms = <&pwm_beep 1 2272727>;
-		amp-supply = <&v5v>;
-	};
-
-	/* leds */
-	leds:led {
-		compatible = "gpio-leds";
-		status = "okay";
-		led1 {
-			/* LED for M4 in kontron demo */
-			label = "LED1";
-			gpios = <&gpioa 13 GPIO_ACTIVE_LOW>;
-			default-state = "off";
-			status = "okay";
-		};
-		led2 {
-			/* LED for linux heartbeat */
-			label = "LED2";
-			gpios = <&gpioa 14 GPIO_ACTIVE_LOW>;
-			linux,default-trigger = "heartbeat";
-			default-state = "off";
-			status = "okay";
-		};
-	};
-
-	hdmi-out {
-		compatible = "hdmi-connector";
-		type = "a";
-
-		port {
-			hdmi_con_in: endpoint {
-				remote-endpoint = <&adv7533_hdmi_out>;
-			};
-		};
-	};
-
-};
-
-&i2c4 {
-	/* External i2c bus */
-	clock-frequency = <400000>;
-	status = "okay";
-};
-
-/* Internal ADC reference voltage */
-&vrefbuf {
-	status = "okay";
-	/* Set referece voltage to 2.5V */
-	regulator-max-microvolt = <2500000>;
-	regulator-min-microvolt = <2500000>;
-	vdda-supply = <&vdd>;
-};
-
-/* ADC settings */
-&adc {
-	/* ADC_INP5 is fast, ADC_INP16 is slow channel */
-
-	/* Use internal reference voltage */
-	vref-supply = <&vrefbuf>;
-	status = "okay";
-
-	adc1: adc@0 {
-		st,adc-channels = <5 16>;
-		st,min-sample-time-nsecs = <100000>;
-		status = "okay";
-	};
-
-	adc2: adc@100 {
-		// VREFINT VDDCORE VBAT/4 DAC_OUT1 DAC_OUT2
-		st,adc-channels = <13 14 15 16 17>;
-		st,min-sample-time-nsecs = <100000>;
-		status = "okay";
-	};
-
-};
-
-
-/* sd interfaces */
-&sdmmc1 {
-	/* add opendrain pins which aren't generated by cubemx */
-	pinctrl-names = "default", "sleep", "opendrain";
-	pinctrl-0 = <&sdmmc1_pins_mx>;
-	pinctrl-1 = <&sdmmc1_sleep_pins_mx>;
-	pinctrl-2 = <&sdmmc1_opendrain_pins_mx>;
-	broken-cd;
-	no-1-8-v;
-	st,neg-edge;
-	bus-width = <4>;
-	vmmc-supply = <&vdd_sd>;
-	status = "okay";
-};
-
-
-/* emmc interface */
-&sdmmc2 {
-	/* add opendrain pins which aren't generated by cubemx */
-	pinctrl-names = "default", "sleep", "opendrain";
-	pinctrl-0 = <&sdmmc2_pins_mx>;
-	pinctrl-1 = <&sdmmc2_sleep_pins_mx>;
-	pinctrl-2 = <&sdmmc2_opendrain_pins_mx>;
-	non-removable;
-	no-sd;
-	no-sdio;
-	st,neg-edge;
-	mmc-ddr-3_3v;
-	bus-width = <4>;
-	vmmc-supply = <&v3v3>;
-	status = "okay";
-};
-
-
-/* RS485 interface */
-&usart2 {
-	linux,rs485-enabled-at-boot-time;
-    status = "okay";
-};
-
-
-/* timer1: CH2 Beeper */
-&timers1 {
-    status = "okay";
-	/* spare dmas for other usage */
-	/delete-property/dmas;
-	/delete-property/dma-names;
-
-	pwm_beep:pwm {
-		#pwm-cells = <2>;
-		status = "okay";
-	};
-};
-
-
-/* timer4: CH3 Backlight */
-&timers4 {
-    status = "okay";
-	/* spare dmas for other usage */
-	/delete-property/dmas;
-	/delete-property/dma-names;
-
-	pwm_bl:pwm {
-		#pwm-cells = <2>;
-		status = "okay";
-	};
-};
-
-
-&pinctrl {
-	/* Add touch connector gpios */
-    touch_pins_dev: touch_pins_dev@0 {
-        pins {
-            pinmux = <STM32_PINMUX('G', 7, GPIO)>, /* TOUCH_INT */
-                     <STM32_PINMUX('E', 0, GPIO)>; /* TOUCH_WAKE */
-            bias-pull-up;
-        };
-    };
-    /* Add adv7535 DSI2HDMI */
-    pinctrl_adv7535: adv7535_pins_dev {
-    	pins {
-    		pinmux = <STM32_PINMUX('G', 9, GPIO)>; /* DSI2HDMI IRQ */
-    		bias-pull-up;
-    	};
-    };
-};
-
-&usbh_ehci {
-	/*
-	*	node structure for smsc95xx driver to find and pick up mac-address
-	*	eth1addr will be written into local-mac from u-boot
-	*/
-	#address-cells = <1>;
-	#size-cells = <0>;
-	usb1@1 {
-		compatible = "usb424,9514";
-		reg = <1>;
-		#address-cells = <1>;
-		#size-cells = <0>;
-
-		ethernet1: usbether@1 {
-			compatible = "usb424,ec00";
-			reg = <1>;
-			local-mac-address = [00 00 00 00 00 00];
-		};
-	};
-};
-
-
-&ltdc {
-	status = "okay";
-
-	port {
-		#address-cells = <1>;
-		#size-cells = <0>;
-
-		/* Parallel output */
-		ltdc_ep0_out: endpoint@0 {
-			reg = <0>;
-			remote-endpoint = <&dsi_in>;
-		};
-	};
-};
-
-
-&dsi {
-	#address-cells = <1>;
-	#size-cells = <0>;
-	/* When enabling the dsi interface, linux kernel fbdev emulation requires
-	 * the configuration of the display on command line. E.g:
-	 *   video=DPI-1:800x480
-	 */
-	status = "okay";
-
-	ports {
-		#address-cells = <1>;
-		#size-cells = <0>;
-
-		port@0 {
-			reg = <0>;
-			dsi_in: endpoint {
-				remote-endpoint = <&ltdc_ep0_out>;
-			};
-		};
-
-		port@1 {
-			reg = <1>;
-			dsi_out: endpoint {
-				/* default endpoint without display is hdmi */
-				remote-endpoint = <&adv7533_dsi_in>;
-			};
-		};
-	};
-};
-
-
-&i2c2 {
-	hdmi: hdmi@39 {
-		status = "okay";
-
-		compatible = "adi,adv7535";
-		reg = <0x39>;
-		interrupt-parent = <&gpiog>;
-		interupts = <9 IRQ_TYPE_EDGE_FALLING>;
-
-		pinctrl-names = "default";
-		pinctrl-0 = <&pinctrl_adv7535>;
-
-		adi,input-depth = <8>;
-		adi,input-colorspace = "rgb";
-		adi,input-clock = "1x";
-		//adi,input-style = <1>;
-		//adi,input-justification = "evenly";
-
-		adi,dsi-lanes = <2>;
-		a2vdd-supply = <&vdd_1v8>;
-		v1p2-supply = <&vdd_1v8>;
-		v3p3-supply = <&v3v3>;
-
-		ports {
-			#address-cells = <1>;
-			#size-cells = <0>;
-
-			port@0 {
-				/* DSI input */
-				reg = <0>;
-				adv7533_dsi_in: endpoint {
-					remote-endpoint = <&dsi_out>;
-				};
-			};
-			port@1 {
-				/* HDMI output */
-				reg = <1>;
-				adv7533_hdmi_out: endpoint {
-					remote-endpoint = <&hdmi_con_in>;
-				};
-			};
-		};
-	};
-
-	lvds: lvds@2c {
-		compatible = "ti,sn65dsi83";
-		reg = <0x2c>;
-		ti,dsi-lanes = <2>;
-		/* there'n no dedicated enable-gpio, but driver requires one,
-		* so give it the SOM internal test pad */
-		enable-gpios = <&gpioc 13 GPIO_ACTIVE_LOW>; // is LED1
-		status = "disabled";
-	};
-};
-
-
-/* Name common gpios */
-&gpio_exp {
-	gpio-line-names = \
-		"CFG0", "CFG1", \
-		"CFG2", "CFG3", \
-		"LVDS_SHLR", "LVDS_UPDN", \
-		"LVDS_TFT_RESET", "LVDS_STBY";
-};
-&gpioa {
-	gpio-line-names = \
-		"PA0", "PA1", \
-		"PA2", "PA3", \
-		"PA4", "PA5", \
-		"PA6", "PA7", \
-		"PA8", "PA9", \
-		"PA10", "DIN2", \
-		"PA12", "LED1", \
-		"LED2", "PA15";
-};
-&gpiob {
-	gpio-line-names = \
-		"PB0", "PB1", \
-		"PB2", "PB3", \
-		"PB4", "PB5", \
-		"PB6", "PB7", \
-		"PB8", "PB9", \
-		"PB10", "PB11", \
-		"PB12", "PB13", \
-		"PB14", "PB15";
-};
-&gpioc {
-	gpio-line-names = \
-		"PC0", "PC1", \
-		"DOUT2", "DIN1", \
-		"PC4", "PC5", \
-		"PC6", "PC7", \
-		"PC8", "PC9", \
-		"PC10", "PC11", \
-		"PC12", "PC13", \
-		"PC14", "PC15";
-};
-&gpiod {
-	gpio-line-names = \
-		"PD0", "PD1", \
-		"PD2", "PD3", \
-		"PD4", "PD5", \
-		"PD6", "PD7", \
-		"PD8", "PD9", \
-		"PD10", "PD11", \
-		"PD12", "DSI_SEL", \
-		"PD14", "RESET_OUT";
-};
-&gpioe {
-	gpio-line-names = \
-		"TOUCH_WAKE", "DOUT1", \
-		"PE2", "PE3", \
-		"PE4", "PE5", \
-		"PE6", "PE7", \
-		"PE8", "PE9", \
-		"PE10", "PE11", \
-		"PE12", "PE13", \
-		"PE14", "PE15";
-};
-&gpiof {
-	gpio-line-names = \
-		"PF0", "PF1", \
-		"PF2", "PF3", \
-		"PF4", "PF5", \
-		"PF6", "PF7", \
-		"PF8", "PF9", \
-		"PF10", "PF11", \
-		"PF12", "PF13", \
-		"PF14", "PF15";
-};
-&gpiog {
-	gpio-line-names = \
-		"PG0", "PG1", \
-		"PG2", "PG3", \
-		"PG4", "PG5", \
-		"PG6", "TOUCH_INT", \
-		"PG8", "DSI2HDMI_IRQ", \
-		"PG10", "PG11", \
-		"PG12", "PG13", \
-		"DSI2LVDS_IRQ", "PG15";
-};
-&gpioh {
-	gpio-line-names = \
-		"PH0", "PH1", \
-		"PH2", "PH3", \
-		"PH4", "PH5", \
-		"PH6", "PH7", \
-		"PH8", "PH9", \
-		"PH10", "PH11", \
-		"PH12", "PH13", \
-		"PH14", "PH15";
-};
-
-
-/*
-* Disable usart3 for linux and enable m4 resource
-*/
-&usart3{
-	st,hw-flow-ctrl;
-	status = "disabled";
-};
-
-&m4_usart3{
-    status = "okay";
-};
-
-
diff --git a/recipes-kernel/linux/linux-stm32mp/stm32mp-board-mini.dtsi b/recipes-kernel/linux/linux-stm32mp/stm32mp-board-mini.dtsi
new file mode 100644
index 0000000000000000000000000000000000000000..09cd274ab4a55e9f1fbae2c5aee0f9848a50cd94
--- /dev/null
+++ b/recipes-kernel/linux/linux-stm32mp/stm32mp-board-mini.dtsi
@@ -0,0 +1,139 @@
+/* Devicetree file for device
+ *
+ * device   : stm32mp-board-mini
+ * revision : prototype
+ *
+ * Kontron Electronics GmbH
+ * Copyright 2018 Kontron Electronics GmbH. All rights reserved.
+ */
+
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+	device-identification {
+		board = "mini";
+		board_pcb = "1 950 1422";
+		board_code = "40099 113 01 (prototype)";
+	};
+};
+
+/* i2c interfaces */
+&i2c2 {
+	status = "okay";
+
+	/* Vishay VCNL4020 ambient sensor */
+	vcnl4000@13 {
+		compatible = "vishay,vcnl4000";
+		reg = <0x13>;
+	};
+};
+
+&i2c4 {
+	status = "okay";
+	clock-frequency = <100000>;
+};
+
+
+/* spi interfaces */
+&spi2 {
+	cs-gpios = <&gpioa 11 GPIO_ACTIVE_HIGH>;
+	status = "disabled";
+	
+	spidev: spidev@0 {
+		status = "disabled";
+		/* linux,spidev produces heavy warning on boot. spidev is
+		 * non-conformant for linux kernel hacker because it's no device (it's
+		 * a connection with unknown devices on it).
+		 * We could use here 'rohm,dh2228fv' to get rid of this warning or patch
+		 * the driver with your own compatible string. */
+		compatible = "linux,spidev";
+		spi-max-frequency = <25000000>;
+		reg = <0>;
+	};
+};
+
+
+/* ADC settings */
+&adc {
+	/* ADC_INP5 is fast, ADC_INP16 is slow channel */
+
+	/* Use internal reference voltage */
+	/* vref-supply = <&vrefbuf>; */
+
+	/* Use external reference voltage */
+	vref-supply = <&vdda>;
+	status = "okay";
+
+
+	adc1: adc@0 {
+		st,adc-channels = <2 3 5 16>;
+		/* 16.5 ck_cycles sampling time */
+		st,min-sample-time-nsecs = <400>;
+		status = "okay";
+	};
+
+	jadc1: jadc@0 {
+		st,adc-channels = <2 3 5 16>;
+		/* 16.5 ck_cycles sampling time */
+		st,min-sample-time-nsecs = <400>;
+		status = "okay";
+	};
+
+	adc2: adc@100 {
+		status = "okay";
+	};
+
+	adc_temp: temp {
+		/* temperature sensor on adc2 */
+		status = "okay";
+	};
+
+};
+
+
+/* sd/mmc interfaces */
+&sdmmc1 {
+	broken-cd;
+	//cd-gpios = <&gpioa 10 GPIO_ACTIVE_HIGH>;
+	st,dirpol;
+	st,negedge;
+	no-1-8-v;
+	bus-width = <4>;
+	vmmc-supply = <&vdd_sd>;
+	status = "okay";
+};
+
+
+/* M4 ressources */
+&m4_rproc {
+	m4_system_resources {
+		compatible = "rproc-srm-core";
+		status = "disabled";
+		
+		/* spi2 is for M4 */
+		m4_spi2: m4_spi2 {
+			compatible = "rproc-srm-dev";
+			pinctrl-names = "default";
+			pinctrl-0 = <&spi2_pins_mx>;
+			clocks = <&rcc 131>;
+			status = "disabled";
+		};
+	};
+};
+
+
+/* timer1: CH1,2,3,4 - PWM, trigger and capture capable */
+&timers1 {
+    status = "okay";
+    /* if we don't use capture dma can be disabled */
+    /* for capture dma is required - limit capture for CH1 and CH2 */
+	//dmas = <&dmamux1 11 0x400 0x5>;
+	//dma-names = "ch1";
+    
+	pwm {
+		status = "okay";
+	};
+	timer@0 {
+		status = "okay";
+	};
+};
diff --git a/recipes-kernel/linux/linux-stm32mp/stm32mp-board-minimal.dtsi b/recipes-kernel/linux/linux-stm32mp/stm32mp-board-minimal.dtsi
deleted file mode 100644
index 08d965543665b2c5f27f4f4be5f774e23b5fc14d..0000000000000000000000000000000000000000
--- a/recipes-kernel/linux/linux-stm32mp/stm32mp-board-minimal.dtsi
+++ /dev/null
@@ -1,114 +0,0 @@
-/* Devicetree file for basic t1000 SOM module
- *
- * These settings should work with most baseboards
- *
- * device   : stm32mp-board-minimal
- * revision : -
- *
- * Kontron Electronics GmbH
- * Copyright 2019 Kontron Electronics GmbH. All rights reserved.
- */
-
-#include <dt-bindings/gpio/gpio.h>
-
-/ {
- 	/* Add your board identification (only for informational purpose) */
-	device-identification {
-		board = "minimal";
-		board_pcb = "none";
-		board_code = "none";
-	};
-
-	aliases {
-		serial0 = &uart4;    /* console */
-	};
-
-	/* SD card voltage - may be adapted to board */
-	vdd_sd: regulator-vdd_sd {
-		compatible = "regulator-fixed";
-		regulator-name = "vdd_sd";
-		regulator-min-microvolt = <3300000>;
-		regulator-max-microvolt = <3300000>;
-		regulator-always-on;
-	};
-};
-
-
-/* Internal ADC reference voltage */
-&vrefbuf {
-	status = "okay";
-	/* Set referece voltage to 2.5V */
-	regulator-max-microvolt = <2500000>;
-	regulator-min-microvolt = <2500000>;
-	vdda-supply = <&vdd>;
-};
-
-
-/* ADC settings - Not required, but useful and not disturbing */
-&adc {
-	/* Use internal reference voltage */
-	vref-supply = <&vrefbuf>;
-	status = "okay";
-
-	adc2: adc@100 {
-		// VREFINT VDDCORE VBAT/4 DAC_OUT1 DAC_OUT2
-		st,adc-channels = <13 14 15 16 17>;
-		st,min-sample-time-nsecs = <100000>;
-		status = "okay";
-	};
-
-	adc_temp: temp {
-		/* temperature sensor on adc2 */
-		status = "okay";
-	};
-
-};
-
-
-/* sd interfaces */
-/* Simple sd interface */
-&sdmmc1 {
-	/* add opendrain pins which aren't generated by cubemx */
-	pinctrl-names = "default", "sleep", "opendrain";
-	pinctrl-0 = <&sdmmc1_pins_mx>;
-	pinctrl-1 = <&sdmmc1_sleep_pins_mx>;
-	pinctrl-2 = <&sdmmc1_od_pins>;
-	broken-cd;
-	no-1-8-v;
-	st,neg-edge;
-	bus-width = <4>;
-	vmmc-supply = <&vdd_sd>;
-	status = "okay";
-};
-
-
-&pinctrl {
-	/* add opendrain pin config */
-    sdmmc1_od_pins: sdmmc1_od@0 {
-        pins1 {
-            u-boot,dm-pre-reloc;
-            pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
-                     <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
-                     <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
-                     <STM32_PINMUX('C', 11, AF12)>; /* SDMMC1_D3 */
-            bias-pull-up;
-            drive-push-pull;
-            slew-rate = <1>;
-        };
-        pins2 {
-            u-boot,dm-pre-reloc;
-            pinmux = <STM32_PINMUX('C', 12, AF12)>; /* SDMMC1_CK */
-            bias-pull-up;
-            drive-push-pull;
-            slew-rate = <3>;
-        };
-        pins3 {
-            u-boot,dm-pre-reloc;
-            pinmux = <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
-            bias-pull-up;
-            drive-open-drain;
-            slew-rate = <1>;
-        };
-    };
-};
-
diff --git a/recipes-kernel/linux/linux-stm32mp/stm32mp-board-s.dtsi b/recipes-kernel/linux/linux-stm32mp/stm32mp-board-s.dtsi
index c0c22adc9efd645d961f47c77b8acb5328581abf..c441504cddc8037d071a78b172312df669035321 100644
--- a/recipes-kernel/linux/linux-stm32mp/stm32mp-board-s.dtsi
+++ b/recipes-kernel/linux/linux-stm32mp/stm32mp-board-s.dtsi
@@ -12,17 +12,10 @@
 / {
 	device-identification {
 		board = "s";
-		board_pcb = "1 951 1619";
-		board_code = "40099 131 01";
+		board_pcb = "1 950 1619";
+		board_code = "40099 131 00 (prototype)";
 	};
-
-	aliases {
-		serial0 = &uart4;    /* console */
-		serial1 = &usart2;   /* rs485 */
-		serial2 = &usart6;   /* rs232 */
-		ethernet1 = &ethernet1;
-	};
-
+	
 	v5v: regulator-v5v {
 		compatible = "regulator-fixed";
 		regulator-name = "v5v";
@@ -30,23 +23,15 @@
 		regulator-max-microvolt = <5000000>;
 		regulator-always-on;
 	};
-
-	vdd_sd: regulator-vdd_sd {
-		compatible = "regulator-fixed";
-		regulator-name = "vdd_sd";
-		regulator-min-microvolt = <3300000>;
-		regulator-max-microvolt = <3300000>;
-		regulator-always-on;
-	};
-
+	
 	beeper:pwm-beeper {
 		compatible = "pwm-beeper";
-		/* pwm timers1, Channel 2 */
+		/* pwm timers4, Channel 1 */
 		/* Use 440Hz which is default frequency for beep command */
-		pwms = <&pwm_beep 1 2272727>;
+		pwms = <&pwm 0 2272727>;
 		amp-supply = <&v5v>;
 	};
-
+	
 	/* leds */
 	leds:led {
 		compatible = "gpio-leds";
@@ -55,14 +40,14 @@
 			label = "LED1";
 			gpios = <&gpioa 13 GPIO_ACTIVE_LOW>;
 			default-state = "off";
-			//linux,default-trigger = "heartbeat";
-			status = "disabled";
+			linux,default-trigger = "heartbeat";
+			status = "okay";
 		};
 		led2 {
 			label = "LED2";
 			gpios = <&gpioa 14 GPIO_ACTIVE_LOW>;
 			default-state = "off";
-			//linux,default-trigger = "heartbeat";
+			linux,default-trigger = "heartbeat";
 			status = "okay";
 		};
 		led3 {
@@ -73,50 +58,8 @@
 			status = "okay";
 		};
 	};
-
-	/* Sound interface */
-	sound {
-		compatible = "simple-audio-card";
-		simple-audio-card,name = "WM8510";
-		simple-audio-card,format = "i2s";
-		simple-audio-card,bitclock-master = <&sound1_cpu>;
-		simple-audio-card,frame-master = <&sound1_cpu>;
-		simple-audio-card,mclk-fs = <256>; /*factor x for mclk  = x*fs (framesynchro clock)*/
-		simple-audio-card,widgets =
-			"Speaker", "Ext Spk";
-		simple-audio-card,routing =
-			"Ext Spk", "SPKOUTP",
-			"Ext Spk", "SPKOUTN";
-		sound1_cpu: simple-audio-card,cpu {
-			sound-dai = <&i2s2>;
-};
-		sound1_codec: simple-audio-card,codec {
-			sound-dai = <&codec>;
-		};
-	};
-
 };
 
-
-&i2c4 {
-	status = "okay";
-
-	codec: wm8510@1a {
-		#sound-dai-cells = <0>;
-		compatible = "wlf,wm8510";
-		reg = <0x1a>;
-		status = "okay";
-	};
-
-};
-
-&i2s2{
-	clocks = <&rcc SPI2>, <&rcc SPI2_K>, <&rcc PLL3_R>, <&rcc PLL3_Q>;
-	clock-names = "pclk", "i2sclk", "x8k", "x11k";
-	status="okay";
-};
-
-
 /* Internal ADC reference voltage */
 &vrefbuf {
 	status = "okay";
@@ -142,10 +85,19 @@
 		status = "okay";
 	};
 
+	jadc1: jadc@0 {
+		st,adc-channels = <5 16>;
+		/* 16.5 ck_cycles sampling time */
+		st,min-sample-time-nsecs = <400>;
+		status = "okay";
+	};
+
 	adc2: adc@100 {
-		// VREFINT VDDCORE VBAT/4 DAC_OUT1 DAC_OUT2
-		st,adc-channels = <13 14 15 16 17>;
-		st,min-sample-time-nsecs = <100000>;
+		status = "okay";
+	};
+
+	adc_temp: temp {
+		/* temperature sensor on adc2 */
 		status = "okay";
 	};
 
@@ -154,14 +106,11 @@
 
 /* sd interfaces */
 &sdmmc1 {
-	/* add opendrain pins which aren't generated by cubemx */
-	pinctrl-names = "default", "sleep", "opendrain";
-	pinctrl-0 = <&sdmmc1_pins_mx>;
-	pinctrl-1 = <&sdmmc1_sleep_pins_mx>;
-	pinctrl-2 = <&sdmmc1_od_pins>;
 	broken-cd;
+	//cd-gpios = <&gpioa 10 GPIO_ACTIVE_HIGH>;
+	st,dirpol;
+	st,negedge;
 	no-1-8-v;
-	st,neg-edge;
 	bus-width = <4>;
 	vmmc-supply = <&vdd_sd>;
 	status = "okay";
@@ -170,79 +119,19 @@
 
 /* emmc interface */
 &sdmmc2 {
-	/* add opendrain pins which aren't generated by cubemx */
-	pinctrl-names = "default", "sleep", "opendrain";
-	pinctrl-0 = <&sdmmc2_pins_mx>;
-	pinctrl-1 = <&sdmmc2_sleep_pins_mx>;
-	pinctrl-2 = <&sdmmc2_od_pins>;
 	non-removable;
 	no-sd;
 	no-sdio;
-	st,neg-edge;
-	mmc-ddr-3_3v;
+	st,dirpol;
+	st,negedge;
+	// 3,3v ddr should be possible
+	//mmc-ddr-3_3v;
+	no-1-8-v;
 	bus-width = <4>;
 	vmmc-supply = <&v3v3>;
 	status = "okay";
 };
 
-&pinctrl {
-	/* add opendrain pin config */
-    sdmmc1_od_pins: sdmmc1_od@0 {
-        pins1 {
-            u-boot,dm-pre-reloc;
-            pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
-                     <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
-                     <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
-                     <STM32_PINMUX('C', 11, AF12)>; /* SDMMC1_D3 */
-            bias-pull-up;
-            drive-push-pull;
-            slew-rate = <1>;
-        };
-        pins2 {
-            u-boot,dm-pre-reloc;
-            pinmux = <STM32_PINMUX('C', 12, AF12)>; /* SDMMC1_CK */
-            bias-pull-up;
-            drive-push-pull;
-            slew-rate = <3>;
-        };
-        pins3 {
-            u-boot,dm-pre-reloc;
-            pinmux = <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
-            bias-pull-up;
-            drive-open-drain;
-            slew-rate = <1>;
-        };
-    };
-
-    sdmmc2_od_pins: sdmmc2_od@0 {
-        u-boot,dm-pre-reloc;
-        pins1 {
-            u-boot,dm-pre-reloc;
-            pinmux = <STM32_PINMUX('B', 3, AF9)>, /* SDMMC2_D2 */
-                     <STM32_PINMUX('B', 4, AF9)>, /* SDMMC2_D3 */
-                     <STM32_PINMUX('B', 14, AF9)>, /* SDMMC2_D0 */
-                     <STM32_PINMUX('B', 15, AF9)>; /* SDMMC2_D1 */
-            bias-pull-up;
-            drive-push-pull;
-            slew-rate = <1>;
-        };
-        pins2 {
-            u-boot,dm-pre-reloc;
-            pinmux = <STM32_PINMUX('E', 3, AF9)>; /* SDMMC2_CK */
-            bias-pull-up;
-            drive-push-pull;
-            slew-rate = <3>;
-        };
-        pins3 {
-            u-boot,dm-pre-reloc;
-            pinmux = <STM32_PINMUX('G', 6, AF10)>; /* SDMMC2_CMD */
-            bias-pull-up;
-            drive-open-drain;
-            slew-rate = <1>;
-        };
-    };
-};
-
 
 /* RS485 interface */
 &usart2 {
@@ -251,28 +140,14 @@
 };
 
 
-/* timer1: CH2 Beeper */
-&timers1 {
-    status = "okay";
-	/* spare dmas for other usage */
-	/delete-property/dmas;
-	/delete-property/dma-names;
-
-	pwm_beep:pwm {
-		#pwm-cells = <2>;
-		status = "okay";
-	};
-};
-
-
-/* timer4: CH3 Backlight */
+/* timer4: CH1 BEEPER, CH3 Backlight */
 &timers4 {
     status = "okay";
 	/* spare dmas for other usage */
 	/delete-property/dmas;
 	/delete-property/dma-names;
-
-	pwm_bl:pwm {
+    
+	pwm:pwm {
 		#pwm-cells = <2>;
 		status = "okay";
 	};
@@ -284,7 +159,7 @@
     touch_pins_dev: touch_pins_dev@0 {
         pins {
             /* touch int is initialized by touch driver */
-            pinmux = <STM32_PINMUX('D', 9, GPIO)>, /* TOUCH_INT */
+            pinmux = /* <STM32_PINMUX('D', 9, GPIO)>,*/ /* TOUCH_INT */
                      <STM32_PINMUX('D', 11, GPIO)>; /* TOUCH_WAKE */
             bias-pull-down;
         };
@@ -292,40 +167,50 @@
 
 };
 
-&usbh_ehci {
-	/*
-	*	node structure for smsc95xx driver to find and pick up mac-address
-	*	eth1addr will be written into local-mac from u-boot
-	*/
-	#address-cells = <1>;
-	#size-cells = <0>;
-	usb1@1 {
-		compatible = "usb424,9514";
-		reg = <1>;
-		#address-cells = <1>;
-		#size-cells = <0>;
-
-		ethernet1: usbether@1 {
-			compatible = "usb424,ec00";
-			reg = <1>;
-			local-mac-address = [00 00 00 00 00 00];
-		};
+
+/* Sound interface */
+#if 0
+/* TODO configure sound interface */
+sound {
+	compatible = "simple-audio-card";
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_sound>;
+	simple-audio-card,name = "WM8510";
+	simple-audio-card,format = "i2s";
+	simple-audio-card,bitclock-master = <&sound1_codec>;
+	simple-audio-card,frame-master = <&sound1_codec>;
+	simple-audio-card,widgets =
+		"Speaker", "Ext Spk";
+	simple-audio-card,routing =
+		"Ext Spk", "SPKOUTP",
+		"Ext Spk", "SPKOUTN";
+
+	sound1_cpu: simple-audio-card,cpu {
+		sound-dai = <&ssi2>;
 	};
-};
 
-/*
-* Disable usart6 for linux and enable m4 resource
-*/
+	sound1_codec: simple-audio-card,codec {
+		sound-dai = <&codec>;
+		clocks = <&codec_osc>;
+	};
+};
+#endif
 
-&usart6{
+&i2c4 {
+	status = "okay";
 
-      status = "disabled";
+	codec: wm8510@1a {
+		#sound-dai-cells = <0>;
+		compatible = "wlf,wm8510";
+		reg = <0x1a>;
+		status = "okay";
+	};
 
 };
-&m4_usart6{
 
-    status = "okay";
 
+&usbotg_hs {
+	dr_mode = "host"; /* workaround for board OTG and HOST are reversed */
 };
 
 
diff --git a/recipes-kernel/linux/linux-stm32mp/stm32mp-housing-24.dtsi b/recipes-kernel/linux/linux-stm32mp/stm32mp-housing-24.dtsi
deleted file mode 100644
index cf5f0bbaf05682ec66ad14dc2ae304132723ecd6..0000000000000000000000000000000000000000
--- a/recipes-kernel/linux/linux-stm32mp/stm32mp-housing-24.dtsi
+++ /dev/null
@@ -1,155 +0,0 @@
-/* Devicetree file for device
- *
- * device   : stm32mp-housing-24
- * revision : prototype
- *
- * Kontron Electronics GmbH
- * Copyright 2019 Kontron Electronics GmbH. All rights reserved.
- */
-
-#include <dt-bindings/gpio/gpio.h>
-
-/* Display interfaces */
-&ltdc{
-    status = "disabled";
-    u-boot,dm-pre-reloc;
-};
-
-&spi1{
-    status = "okay";
-    pinctrl-names = "default";
-    pinctrl-0 = <&spi1_pins_x12>;
-    // cs low: enable
-    cs-gpios = <&gpiob 0 GPIO_ACTIVE_LOW>;
-
-
-    disp_st7789v2_fbdev: st7789v2_fbdev@0{
-        status = "okay";
-        compatible = "sitronix,st7789v";
-        reg = <0>;
-        //pinctrl-names = "default";
-        //pinctrl-0 = <&disp_pins_x12>;
-        spi-max-frequency = <62500000>;
-        // reset voltage: reset=low
-        reset-gpios = <&gpioa 15 GPIO_ACTIVE_HIGH>;
-        // d/c voltage: data=hi  command=low
-        // remark: It doesn't matter if ACTIVE_HIGH or ACTIVE_LOW is set
-        //         the reason is unclear, but it is observed like that!
-        dc-gpios = <&gpiog 13 GPIO_ACTIVE_HIGH>;
-        buswidth = <8>;
-	/* Jenson JT60188 setings */
-	gamma = "D0 1A 1E 0A 0A 27 3B 44 4A 2b 16 15 1A 1E\nD0 1A 1E 0A 0A 27 3B 44 4A 2b 16 15 1A 1E";
-	init = <\
-	    0x01000011                            /* MIPI_DCS_EXIT_SLEEP_MODE */ \
-	    0x02000078                            /* delay 120 */ \
-	    0x0100003A 0x05                       /* MIPI_DCS_SET_PIXEL_FORMAT MIPI_DCS_PIXEL_FMT_16BIT */ \
-	    0x010000B2 0x0C 0x0C 0x00 0x33 0x33   /* PORCTRL */ \
-	    0x010000B7 0x75                       /* GCTRL, 0x75 */ \
-	    0x010000BB 0x30                       /* VCOMS, 0x30 */ \
-	    0x010000C0 0x2C                       /* LCMCTRL, 0x2C */ \
-	    0x010000C2 0x01 0xFF                  /* VDVVRHEN, 0x01, 0xFF */ \
-	    0x010000C3 0x13                       /* VRHS, 0x13 */ \
-	    0x010000C4 0x20                       /* VDVS, 0x20 */ \
-	    0x010000C6 0x0F                       /* FRCTRL2, 0x0F */ \
-	    0x010000D0 0xA4 0xA1                  /* PWCTRL1, 0xA4, 0xA1 */ \
-	    0x01000029                            /* MIPI_DCS_SET_DISPLAY_ON */ \
-	    >;
-    };
-};
-
-
-/* Touch interfaces */
-&i2c2 {
-	/* Remark: Shared with SOM internal gpio expander */
-	status = "okay";
-
-	ft6336g@38 {
-		status = "okay";
-		compatible = "focaltech,ft6336";
-		reg = <0x38>;
-		pinctrl-names = "default";
-		pinctrl-0 = <&touch_pins_dev>;
-		interrupt-parent = <&gpiod>;
-		interrupts = <9 IRQ_TYPE_EDGE_FALLING>;
-		// reset: low is active
-		reset-gpios = <&gpio_exp 7 GPIO_ACTIVE_LOW>;
-
-		touchscreen-size-x = <240>;
-		touchscreen-size-y = <320>;
-
-		/*
-		Optional properties:
-		- threshold:   allows setting the "click"-threshold in the range from 0 to 80.
-
-		- gain:        allows setting the sensitivity in the range from 0 to
-		               31. Note that lower values indicate higher
-		               sensitivity.
-
-		- offset:      allows setting the edge compensation in the range from
-		               0 to 31.
-		- touchscreen-size-x        : See touchscreen.txt
-		- touchscreen-size-y        : See touchscreen.txt
-		- touchscreen-fuzz-x      : See touchscreen.txt
-		- touchscreen-fuzz-y      : See touchscreen.txt
-		- touchscreen-inverted-x  : See touchscreen.txt
-		- touchscreen-inverted-y  : See touchscreen.txt
-		- touchscreen-swapped-x-y : See touchscreen.txt
-		*/
-	};
-};
-
-/* gpio pins */
-&pinctrl {
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctl_hog>;
-
-	/* normal gpio pins */
-	pinctl_hog:pinctl_hog@0{
-		pins {
-            pinmux = <STM32_PINMUX('E', 4, GPIO)>,
-					 <STM32_PINMUX('G', 12, GPIO)>,
-					 <STM32_PINMUX('G', 10, GPIO)>,
-					 <STM32_PINMUX('D', 10, GPIO)>,
-					 <STM32_PINMUX('E', 12, GPIO)>,
-					 <STM32_PINMUX('A', 3, GPIO)>,
-					 <STM32_PINMUX('B', 8, GPIO)>,
-					 <STM32_PINMUX('B', 9, GPIO)>,
-					 <STM32_PINMUX('E', 14, GPIO)>,
-					 <STM32_PINMUX('C', 6, GPIO)>,
-					 <STM32_PINMUX('A', 4, GPIO)>,
-					 <STM32_PINMUX('E', 13, GPIO)>;
-            bias-disable;
-            drive-push-pull;
-            slew-rate = <1>;
-		};
-	};
-
-    spi1_pins_x12: spi1_x12@0 {
-        pins {
-            pinmux = <STM32_PINMUX('A', 5, AF5)>, /* SPI1_SCK */
-                     <STM32_PINMUX('A', 6, AF5)>, /* SPI1_MISO */
-                     <STM32_PINMUX('B', 5, AF5)>; /* SPI1_MOSI */
-            bias-disable;
-            drive-push-pull;
-            slew-rate = <1>;
-        };
-    };
-
-    disp_pins_x12: disp_x12@0 {
-        pins_out {
-            pinmux = <STM32_PINMUX('G', 13, GPIO)>, /* A0 (data/command) */
-                     <STM32_PINMUX('A', 15, GPIO)>; /* RST */
-            bias-disable;
-            drive-push-pull;
-            slew-rate = <1>;
-        };
-        pins_in {
-            pinmux = <STM32_PINMUX('A', 1, GPIO)>, /* MESH ? */
-					 <STM32_PINMUX('A', 12, GPIO)>; /* LPTE */
-            bias-pull-down;
-            drive-push-pull;
-            slew-rate = <1>;
-        };
-
-    };
-};
diff --git a/recipes-kernel/linux/linux-stm32mp/stm32mp-housing-43.dtsi b/recipes-kernel/linux/linux-stm32mp/stm32mp-housing-43.dtsi
index 492459d0d5eeddc61335eaa1273a35826d12a930..38c0ee38b6b0b54b5c7144c514b02d0f5cd0974a 100644
--- a/recipes-kernel/linux/linux-stm32mp/stm32mp-housing-43.dtsi
+++ b/recipes-kernel/linux/linux-stm32mp/stm32mp-housing-43.dtsi
@@ -12,7 +12,8 @@
 / {
 	backlight: backlight {
 		compatible = "pwm-backlight";
-		pwms = <&pwm_bl 2 5000000>; /* 200 Hz */
+		/* Use 440Hz to synchronize with beeper default frequency */
+		pwms = <&pwm 2 2272727>;
 		brightness-levels = <0 4 8 16 32 64 128 255>;
 		default-brightness-level = <6>;
 		power-supply = <&v5v>;
@@ -52,26 +53,17 @@
 &i2c2 {
 	/* Remark: Shared with SOM internal gpio expander, max clock frequency 100kHz */
 	status = "okay";
-
+	
 	gt911@14 {
 		compatible = "goodix,gt928";
 		reg = <0x14>;
 		pinctrl-names = "default";
-		pinctrl-0 = <&touch_pins_dev_goodix>;
+		pinctrl-0 = <&touch_pins_dev>;
 		interrupt-parent = <&gpiod>;
 		interrupts = <9 IRQ_TYPE_LEVEL_LOW>;
 		reset-gpios = <&gpio_exp 7 0>;
 		irq-gpios = <&gpiod 9 0>;
 	};
-	};
 
-&pinctrl {
-    touch_pins_dev_goodix: touch_pins_dev_goodix@0 {
-        pins {
-            /* touch int is initialized by touch driver */
-            pinmux = /*<STM32_PINMUX('D', 9, GPIO)>,*/ /* TOUCH_INT */
-                     <STM32_PINMUX('D', 11, GPIO)>; /* TOUCH_WAKE */
-            bias-pull-down;
-        };
-    };
 };
+
diff --git a/recipes-kernel/linux/linux-stm32mp/stm32mp-housing-50.dtsi b/recipes-kernel/linux/linux-stm32mp/stm32mp-housing-50.dtsi
index da2b8b3dff670c8dbed36bb48ecbe3c9f8d16132..61f9dc60f7f5997eafb02bdda1b7514c44e96154 100644
--- a/recipes-kernel/linux/linux-stm32mp/stm32mp-housing-50.dtsi
+++ b/recipes-kernel/linux/linux-stm32mp/stm32mp-housing-50.dtsi
@@ -12,7 +12,9 @@
 / {
 	backlight: backlight {
 		compatible = "pwm-backlight";
-		pwms = <&pwm_bl 2 5000000>; /* 200 Hz */
+		/* Use 440Hz to synchronize with beeper default frequency */
+		pwms = <&pwm 2 2272727>;
+		/*pwms = <&pwm 2 20000000>;*/ /* 50Hz */
 		brightness-levels = <0 4 8 16 32 64 128 255>;
 		default-brightness-level = <6>;
 		power-supply = <&v5v>;
@@ -52,26 +54,17 @@
 &i2c2 {
 	/* Remark: Shared with SOM internal gpio expander, max clock frequency 100kHz */
 	status = "okay";
-
+	
 	gt911@14 {
 		compatible = "goodix,gt928";
 		reg = <0x14>;
 		pinctrl-names = "default";
-		pinctrl-0 = <&touch_pins_dev_goodix>;
+		pinctrl-0 = <&touch_pins_dev>;
 		interrupt-parent = <&gpiod>;
 		interrupts = <9 IRQ_TYPE_LEVEL_LOW>;
 		reset-gpios = <&gpio_exp 7 0>;
 		irq-gpios = <&gpiod 9 0>;
 	};
-};
 
-&pinctrl {
-    touch_pins_dev_goodix: touch_pins_dev_goodix@0 {
-        pins {
-            /* touch int is initialized by touch driver */
-            pinmux = /*<STM32_PINMUX('D', 9, GPIO)>,*/ /* TOUCH_INT */
-                     <STM32_PINMUX('D', 11, GPIO)>; /* TOUCH_WAKE */
-            bias-pull-down;
-        };
-    };
 };
+
diff --git a/recipes-kernel/linux/linux-stm32mp/stm32mp-housing-k-101.dtsi b/recipes-kernel/linux/linux-stm32mp/stm32mp-housing-k-101.dtsi
deleted file mode 100644
index 6bb63ca384c7cae51ad0283c723e75a180d94573..0000000000000000000000000000000000000000
--- a/recipes-kernel/linux/linux-stm32mp/stm32mp-housing-k-101.dtsi
+++ /dev/null
@@ -1,194 +0,0 @@
-/* Devicetree file for device
- *
- * device   : stm32mp-housing-k-70
- * revision : 0
- *
- * Kontron Electronics GmbH
- * Copyright 2020 Kontron Electronics GmbH. All rights reserved.
- */
-
-#include <dt-bindings/gpio/gpio.h>
-
-/ {
-
-	backlight: backlight {
-		compatible = "pwm-backlight";
-		pwms = <&pwm_bl 2 5000000>; /* 200 Hz */
-		brightness-levels = <0 4 8 16 32 64 128 255>;
-		default-brightness-level = <6>;
-		power-supply = <&v5v>;
-		status = "okay";
-	};
-
-	/* This is not required any more because sn65dsi driver has its
-	 * own power gpio */
-	reg_panel_pwr: regpanel-pwr {
-		compatible = "regulator-fixed";
-		regulator-name = "reg_panel_pwr";
-		regulator-always-on;
-		gpio = <&gpiod 3 GPIO_ACTIVE_HIGH>;
-		enable-active-high;
-	};
-
-	reg_panel_rst: regpanel-rst {
-		compatible = "regulator-fixed";
-		regulator-name = "reg_panel_rst";
-		regulator-always-on;
-		gpio = <&gpio_exp 6 GPIO_ACTIVE_HIGH>;
-		enable-active-high;
-	};
-
-	reg_panel_stby: regpanel-stby {
-		compatible = "regulator-fixed";
-		regulator-name = "reg_panel_stby";
-		regulator-always-on;
-		gpio = <&gpio_exp 7 GPIO_ACTIVE_HIGH>;
-		enable-active-high;
-	};
-
-	reg_panel_hinv: regpanel-hinv {
-		compatible = "regulator-fixed";
-		regulator-name = "reg_panel_hinv";
-		regulator-always-on;
-		gpio = <&gpio_exp 4 GPIO_ACTIVE_HIGH>;
-		enable-active-high;
-	};
-
-	reg_panel_vinv: regpanel-vinv {
-		compatible = "regulator-fixed";
-		regulator-name = "reg_panel_vinv";
-		regulator-always-on;
-		gpio = <&gpio_exp 5 GPIO_ACTIVE_HIGH>;
-		//enable-active-high;
-	};
-
-};
-
-&reg_dsi_sel {
-	/* select lvds output: set to LOW voltage */
-	/delete-property/enable-active-high;
-};
-
-/* Graphics pipeline ltdc->dsi->lvds  */
-&hdmi {
-	status = "disabled";
-};
-
-
-&ltdc {
-	port {
-		#address-cells = <1>;
-		#size-cells = <0>;
-
-		/* Parallel output */
-		ltdc_ep0_out: endpoint@0 {
-			reg = <0>;
-			remote-endpoint = <&dsi_in>;
-		};
-
-		/* DSI output */
-		ltdc_ep1_out: endpoint@1 {
-			reg = <1>;
-			/* no endpoint */
-			/delete-property/remote-endpoint;
-		};
-	};
-};
-
-
-&dsi {
-	status = "okay";
-
-	ports {
-		#address-cells = <1>;
-		#size-cells = <0>;
-
-		port@0 {
-			reg = <0>;
-			dsi_in: endpoint {
-				remote-endpoint = <&ltdc_ep0_out>;
-			};
-		};
-
-		port@1 {
-			reg = <1>;
-			dsi_out: endpoint {
-				remote-endpoint = <&sn65dsi84_in>;
-			};
-		};
-	};
-};
-
-
-&lvds {
-	ti,lvds-format = <2>;
-	ti,lvds-bpp = <24>;
-	ti,lvds-channels = <1>;
-	status = "okay";
-
-	/* LVDS 10.1 inch display */
-	ti,width-mm = <217>;
-	ti,height-mm = <135>;
-	display-timings {
-		lvds {
-			clock-frequency = <72000000>;
-			
-			hback-porch = <60>;
-			hactive = <1280>;
-			hfront-porch = <100>;
-			hsync-len = <16>;
-
-			vback-porch = <11>;
-			vactive = <800>;
-			vfront-porch = <11>;
-			vsync-len = <2>;
-
-			hsync-active = <0>;
-			vsync-active = <0>;
-			de-active = <1>;
-			pixelclk-active = <0>;
-		};
-	};
-
-	port@0 {
-		reg = <0>;
-		sn65dsi84_in: endpoint {
-			remote-endpoint = <&dsi_out>;
-		};
-	};
-};
-
-
-&adv7533_dsi_in {
-	/delete-property/remote-endpoint;
-};
-
-
-/* Touch interfaces */
-&i2c4 {
-	status = "okay";
-
-	sis@5c {
-		compatible = "sis,9200-ts";
-		reg = <0x5c>;
-		pinctrl-names = "default";
-		pinctrl-0 = <&touch_pins_dev_goodix>;
-		interrupt-parent = <&gpiog>;
-		interrupts = <7 IRQ_TYPE_EDGE_FALLING>;
-		irq-gpios = <&gpiog 7 GPIO_ACTIVE_LOW>;
-		reset-gpios = <&gpioe 0 GPIO_ACTIVE_LOW>;
-	};
-};
-
-&pinctrl {
-    touch_pins_dev_goodix: touch_pins_dev_goodix@0 {
-        pins1 {
-            pinmux = <STM32_PINMUX('E', 0, GPIO)>; /* TOUCH_WAKE (RESET) */
-            bias-pull-down;
-        };
-        pins2 {
-            pinmux = <STM32_PINMUX('G', 7, GPIO)>; /* TOUCH_INT */
-            bias-pull-up;
-        };
-    };
-};
diff --git a/recipes-kernel/linux/linux-stm32mp/stm32mp-housing-k-50.dtsi b/recipes-kernel/linux/linux-stm32mp/stm32mp-housing-k-50.dtsi
deleted file mode 100644
index 2da86e3b067aa2f3586e04a63b55e3154183304e..0000000000000000000000000000000000000000
--- a/recipes-kernel/linux/linux-stm32mp/stm32mp-housing-k-50.dtsi
+++ /dev/null
@@ -1,73 +0,0 @@
-/* Devicetree file for device
- *
- * device   : stm32mp-housing-k-50
- * revision : 0
- *
- * Kontron Electronics GmbH
- * Copyright 2019 Kontron Electronics GmbH. All rights reserved.
- */
-
-#include <dt-bindings/gpio/gpio.h>
-
-/ {
-	backlight: backlight {
-		compatible = "pwm-backlight";
-		pwms = <&pwm_bl 2 5000000>; /* 200 Hz */
-		brightness-levels = <0 4 8 16 32 64 128 255>;
-		default-brightness-level = <6>;
-		power-supply = <&v5v>;
-		status = "okay";
-	};
-
-	panel {
-		compatible = "admatec,t070p133t0s301";
-		backlight = <&backlight>;
-
-		port {
-			panel_in: endpoint {
-				remote-endpoint = <&ltdc_ep0_out>;
-			};
-		};
-	};
-};
-
-
-/* Graphics interfaces ltdc->panel */
-&ltdc_ep0_out {
-	remote-endpoint = <&panel_in>;
-};
-
-&dsi_in {
-    /* cut off default pipeline ltdc->dsi->hdmi */
-    /delete-property/ remote-endpoint;
-};
-
-/* Touch interfaces */
-&i2c4 {
-	/* Remark: Shared with SOM internal gpio expander, max clock frequency 100kHz */
-	status = "okay";
-
-	gt911@14 {
-		compatible = "goodix,gt928";
-		reg = <0x14>;
-		pinctrl-names = "default";
-		pinctrl-0 = <&touch_pins_dev_goodix>;
-		interrupt-parent = <&gpiog>;
-		interrupts = <7 IRQ_TYPE_LEVEL_LOW>;
-		reset-gpios = <&gpioe 0 0>;
-		irq-gpios = <&gpiog 7 0>;
-	};
-};
-
-&pinctrl {
-    touch_pins_dev_goodix: touch_pins_dev_goodix@0 {
-        pins1 {
-            pinmux = <STM32_PINMUX('E', 0, GPIO)>; /* TOUCH_WAKE (RESET) */
-            bias-pull-down;
-        };
-        pins2 {
-            pinmux = <STM32_PINMUX('G', 7, GPIO)>; /* TOUCH_INT */
-            bias-pull-up;
-        };
-    };
-};
diff --git a/recipes-kernel/linux/linux-stm32mp/stm32mp-housing-k-70.dtsi b/recipes-kernel/linux/linux-stm32mp/stm32mp-housing-k-70.dtsi
deleted file mode 100644
index 792c19dcb6b77b41912f07891a1460668afd91ab..0000000000000000000000000000000000000000
--- a/recipes-kernel/linux/linux-stm32mp/stm32mp-housing-k-70.dtsi
+++ /dev/null
@@ -1,191 +0,0 @@
-/* Devicetree file for device
- *
- * device   : stm32mp-housing-k-70
- * revision : 0
- *
- * Kontron Electronics GmbH
- * Copyright 2020 Kontron Electronics GmbH. All rights reserved.
- */
-
-#include <dt-bindings/gpio/gpio.h>
-
-/ {
-
-	backlight: backlight {
-		compatible = "pwm-backlight";
-		pwms = <&pwm_bl 2 5000000>; /* 200 Hz */
-		brightness-levels = <0 4 8 16 32 64 128 255>;
-		default-brightness-level = <6>;
-		power-supply = <&v5v>;
-		status = "okay";
-	};
-
-	/* This is not required any more because sn65dsi driver has its
-	 * own power gpio */
-	reg_panel_pwr: regpanel-pwr {
-		compatible = "regulator-fixed";
-		regulator-name = "reg_panel_pwr";
-		regulator-always-on;
-		gpio = <&gpiod 3 GPIO_ACTIVE_HIGH>;
-		enable-active-high;
-	};
-
-	reg_panel_rst: regpanel-rst {
-		compatible = "regulator-fixed";
-		regulator-name = "reg_panel_rst";
-		regulator-always-on;
-		gpio = <&gpio_exp 6 GPIO_ACTIVE_HIGH>;
-		enable-active-high;
-	};
-
-	reg_panel_stby: regpanel-stby {
-		compatible = "regulator-fixed";
-		regulator-name = "reg_panel_stby";
-		regulator-always-on;
-		gpio = <&gpio_exp 7 GPIO_ACTIVE_HIGH>;
-		enable-active-high;
-	};
-
-	reg_panel_hinv: regpanel-hinv {
-		compatible = "regulator-fixed";
-		regulator-name = "reg_panel_hinv";
-		regulator-always-on;
-		gpio = <&gpio_exp 4 GPIO_ACTIVE_HIGH>;
-		enable-active-high;
-	};
-
-	reg_panel_vinv: regpanel-vinv {
-		compatible = "regulator-fixed";
-		regulator-name = "reg_panel_vinv";
-		regulator-always-on;
-		gpio = <&gpio_exp 5 GPIO_ACTIVE_HIGH>;
-		//enable-active-high;
-	};
-
-};
-
-&reg_dsi_sel {
-	/* select lvds output: set to LOW voltage */
-	/delete-property/enable-active-high;
-};
-
-/* Graphics pipeline ltdc->dsi->lvds  */
-&hdmi {
-	status = "disabled";
-};
-
-
-&ltdc {
-	port {
-		#address-cells = <1>;
-		#size-cells = <0>;
-
-		/* Parallel output */
-		ltdc_ep0_out: endpoint@0 {
-			reg = <0>;
-			remote-endpoint = <&dsi_in>;
-		};
-
-		/* DSI output */
-		ltdc_ep1_out: endpoint@1 {
-			reg = <1>;
-			/* no endpoint */
-			/delete-property/remote-endpoint;
-		};
-	};
-};
-
-
-&dsi {
-	status = "okay";
-
-	ports {
-		#address-cells = <1>;
-		#size-cells = <0>;
-
-		port@0 {
-			reg = <0>;
-			dsi_in: endpoint {
-				remote-endpoint = <&ltdc_ep0_out>;
-			};
-		};
-
-		port@1 {
-			reg = <1>;
-			dsi_out: endpoint {
-				remote-endpoint = <&sn65dsi84_in>;
-			};
-		};
-	};
-};
-
-
-&lvds {
-	ti,lvds-format = <2>;
-	ti,lvds-bpp = <24>;
-	ti,lvds-channels = <1>;
-	status = "okay";
-
-	/* LVDS 7 inch display */
-	ti,width-mm = <154>;
-	ti,height-mm = <86>;
-	display-timings {
-		lvds {
-			clock-frequency = <51200000>;
-			hactive = <1024>;
-			vactive = <600>;
-			hback-porch = <40>;
-			hfront-porch = <40>;
-			vback-porch = <10>;
-			vfront-porch = <3>;
-			hsync-len = <80>;
-			vsync-len = <10>;
-			hsync-active = <0>;
-			vsync-active = <0>;
-			de-active = <1>;
-			pixelclk-active = <0>;
-		};
-	};
-
-	port@0 {
-		reg = <0>;
-		sn65dsi84_in: endpoint {
-			remote-endpoint = <&dsi_out>;
-		};
-	};
-};
-
-
-&adv7533_dsi_in {
-	/delete-property/remote-endpoint;
-};
-
-
-/* Touch interfaces */
-&i2c4 {
-	status = "okay";
-
-	gt911@14 {
-		compatible = "goodix,gt928";
-		reg = <0x14>;
-		pinctrl-names = "default";
-		pinctrl-0 = <&touch_pins_dev_goodix>;
-		interrupt-parent = <&gpiog>;
-		interrupts = <7 IRQ_TYPE_LEVEL_LOW>;
-		reset-gpios = <&gpioe 0 0>;
-		irq-gpios = <&gpiog 7 0>;
-	};
-};
-
-&pinctrl {
-    touch_pins_dev_goodix: touch_pins_dev_goodix@0 {
-        pins1 {
-            pinmux = <STM32_PINMUX('E', 0, GPIO)>; /* TOUCH_WAKE (RESET) */
-            bias-pull-down;
-        };
-        pins2 {
-            pinmux = <STM32_PINMUX('G', 7, GPIO)>; /* TOUCH_INT */
-            bias-pull-up;
-        };
-    };
-};
diff --git a/recipes-kernel/linux/linux-stm32mp/stm32mp-som-t1000.dtsi b/recipes-kernel/linux/linux-stm32mp/stm32mp-som-t1000.dtsi
index fbe7a5addaf02813f65b35ba5d900e7be14b295b..c09d5a7ce2ca9ea952bc5545691e934fac9f2c5d 100644
--- a/recipes-kernel/linux/linux-stm32mp/stm32mp-som-t1000.dtsi
+++ b/recipes-kernel/linux/linux-stm32mp/stm32mp-som-t1000.dtsi
@@ -1,11 +1,10 @@
 /* Devicetree file for device
  *
- * device    : stm32mp-som-t1000
- * board code: 40099 167
- * revision  : 0
+ * device   : stm32mp-som-t1000
+ * revision : prototype
  *
  * Kontron Electronics GmbH
- * Copyright 2019 Kontron Electronics GmbH. All rights reserved.
+ * Copyright 2018 Kontron Electronics GmbH. All rights reserved.
  */
 
 #include <dt-bindings/gpio/gpio.h>
@@ -13,17 +12,15 @@
 / {
 	device-identification {
 		som = "t1000";
-		som_pcb = "1 951 1616";
-		som_code = "40099 167 00";
+		som_pcb = "1 950 1616";
+		som_code = "40099 130 00 (prototype)";
 	};
 
 	chosen {
-		bootargs = "earlyprintk console=ttySTM0,115200 root=/dev/ram";
-		stdout-path = "serial0:115200n8";
+		stdout-path = "serial3:115200n8";
 	};
 
 	aliases {
-		serial0 = &uart4;
 		ethernet0 = "/soc/ethernet@5800a000";
 		i2c1 = "/soc/i2c@40013000";
 		i2c2 = "/soc/i2c@5c002000";
@@ -73,6 +70,23 @@
 		regulator-always-on;
 	};
 
+	vdd_sd: regulator-vdd_sd {
+		compatible = "regulator-fixed";
+		regulator-name = "vdd_sd";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-always-on;
+	};
+
+	/* Analog reference voltage - may be adapted to board */
+	vdda: regulator-vdda {
+		compatible = "regulator-fixed";
+		regulator-name = "vdda";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-always-on;
+	};
+
 	/* Set reset_out to low */
 	reset_out: regulator-reset_out {
 		compatible = "regulator-fixed";
@@ -90,43 +104,23 @@
 		#size-cells = <1>;
 		ranges;
 
-		retram: retram@0x38000000 {
-			compatible = "shared-dma-pool";
-			reg = <0x38000000 0x10000>;
-			no-map;
-		};
-
-		mcuram: mcuram@0x30000000 {
-			compatible = "shared-dma-pool";
-			reg = <0x30000000 0x40000>;
-			no-map;
-		};
-
-		mcuram2: mcuram2@0x10000000 {
-			compatible = "shared-dma-pool";
-			reg = <0x10000000 0x40000>;
-			no-map;
-		};
-
-		vdev0vring0: vdev0vring0@10040000 {
+		ipc_share: sram_rproc@10040000 {
 			compatible = "shared-dma-pool";
-			reg = <0x10040000 0x2000>;
+			reg = <0x10040000 0x10000>;
 			no-map;
 		};
 
-		vdev0vring1: vdev0vring1@10042000 {
-			compatible = "shared-dma-pool";
-			reg = <0x10042000 0x2000>;
+		dma1_reserved: sram_dma1@10050000 {
+			reg = <0x10050000 0x8000>;
 			no-map;
 		};
 
-		vdev0buffer: vdev0buffer@10044000 {
-			compatible = "shared-dma-pool";
-			reg = <0x10044000 0x4000>;
+		dma2_reserved: sram_dma2@10058000 {
+			reg = <0x10058000 0x8000>;
 			no-map;
 		};
 
-		gpu_reserved: gpu@dc000000 {
+		gcnano_reserved: gpu@dc000000 {
 			/* 64MB reserved for GPU (min 32MB, max 192MB)
 			 * REMARK: RAM starts at 0xC0000000 and this is the end of RAM */
 			reg = <0xdc000000 0x4000000>;
@@ -134,18 +128,6 @@
 		};
 	};
 
-	sram: sram@10050000 {
-		compatible = "mmio-sram";
-		reg = <0x10050000 0x10000>;
-		#address-cells = <1>;
-		#size-cells = <1>;
-		ranges = <0 0x10050000 0x10000>;
-
-		dma_pool: dma_pool@0 {
-			reg = <0x0 0x10000>;
-			pool;
-		};
-	};
 };
 
 
@@ -188,11 +170,23 @@
 	phy-mode = "rmii";
 	max-speed = <100>;
 	phy-handle = <&phy0>;
-
-	st,eth_ref_clk_sel; /* Use internal clock for PHY (clocktree in tf-a must match) */
-
-	/*local mac address in which ethaddr gets written*/
-	local-mac-address = [00 00 00 00 00 00];
+	st,int-phyclk;	/* Use internal clock for PHY (clocktree in tf-a must match) */
+
+	/* clock eth-ck is missing in ST SOC description. Here it is fixed.
+	 * Should be removed if ST definition is fixed (Beta1) */
+	clock-names = "stmmaceth",
+		      "mac-clk-tx",
+		      "mac-clk-rx",
+		      "ethstp",
+		      "syscfg-clk",
+			  "eth-ck";
+
+	clocks = <&rcc ETHMAC>,
+		 <&rcc ETHTX>,
+		 <&rcc ETHRX>,
+		 <&rcc ETHSTP>,
+		 <&rcc SYSCFG>,
+		 <&rcc ETHCK_K>;
 
 	mdio0 {
 		#address-cells = <1>;
@@ -219,12 +213,10 @@
     pinctrl-0 = <&quadspi_pins_som>;
     pinctrl-1 = <&quadspi_sleep_pins_som>;
 
-	/* QSPI NOR for boot */
 	flash0: mx25r1635f@0 {
 		u-boot,dm-pre-reloc;
 		compatible = "spi-flash", "jedec,spi-nor";
 		reg = <0>;
-
 		spi-rx-bus-width = <4>;
 		spi-tx-bus-width = <4>;
 		spi-max-frequency = <8000000>; /* MX25R1635F is slow */
@@ -233,7 +225,8 @@
 		#address-cells = <1>;
 		#size-cells = <1>;
 	};
-	/* QSPI NAND for rootfs and data */
+#if 0
+	/* this confuses the driver */
 	flash1: spinand@1 {
 		u-boot,dm-pre-reloc;
 		compatible = "spi-nand";
@@ -246,6 +239,7 @@
 		#address-cells = <1>;
 		#size-cells = <1>;
 	};
+#endif
 };
 
 
@@ -272,7 +266,7 @@
 
 /* USB settings */
 &usbh_ohci {
-    status = "okay";
+    status = "disabled";
 };
 
 
@@ -285,9 +279,6 @@
 
 &usbotg_hs {
 	status = "okay";
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&usb_otg_hs_pins_som>;
-	pinctrl-1 = <&usb_otg_hs_sleep_pins_som>;
 	phys = <&usbphyc_port1 0>;
 	phy-names = "usb2-phy";
 	//vbus-supply = <&vbus_otg>;
@@ -299,7 +290,6 @@
 	status = "okay";
 	vdda1v1-supply = <&reg11>;
 	vdda1v8-supply = <&reg18>;
-	vdd3v3-supply = <&vdd_usb>;
 };
 
 
@@ -314,9 +304,9 @@
 
 
 /* GPU settings */
-&gpu {
+&gcnano {
 	status = "okay";
-	contiguous-area = <&gpu_reserved>;
+	contiguous-area = <&gcnano_reserved>;
 };
 
 
@@ -325,20 +315,14 @@
 };
 
 
-&crc1{
-	/* enabling crc currently leads to sd/emmc disfunction */
-    status = "disabled";
-};
-
-
 /* DMA settings */
 &dma1 {
-	sram = <&dma_pool>;
+	memory-region = <&dma1_reserved>;
 };
 
 
 &dma2 {
-	sram = <&dma_pool>;
+	memory-region = <&dma2_reserved>;
 };
 
 
@@ -364,10 +348,9 @@
 /* reserved ressources for m4 */
 &m4_rproc {
 	status = "okay";
-	memory-region = <&retram>, <&mcuram>, <&mcuram2>, <&vdev0vring0>,
-			<&vdev0vring1>, <&vdev0buffer>;
-	mboxes = <&ipcc 0>, <&ipcc 1>, <&ipcc 2>;
-	mbox-names = "vq0", "vq1", "shutdown";
+	memory-region = <&ipc_share>;
+	mboxes = <&ipcc 0>, <&ipcc 1>;
+	mbox-names = "vq0", "vq1";
 	interrupt-parent = <&exti>;
 	interrupts = <68 1>;
 	interrupt-names = "wdg";
@@ -378,42 +361,41 @@
 &pinctrl {
     eth1_pins_som: eth1_som@0 {
         pins1 {
-            pinmux = <STM32_PINMUX('B', 12, AF11)>, /* ETH1_TXD0 */
+            pinmux = <STM32_PINMUX('A', 2, AF11)>, /* ETH1_MDIO */
+                     <STM32_PINMUX('B', 11, AF11)>, /* ETH1_TX_EN */
+                     <STM32_PINMUX('B', 12, AF11)>, /* ETH1_TXD0 */
                      <STM32_PINMUX('B', 13, AF11)>, /* ETH1_TXD1 */
                      <STM32_PINMUX('C', 1, AF11)>, /* ETH1_MDC */
                      <STM32_PINMUX('G', 8, AF2)>; /* ETH1_CLK */
             bias-disable;
             drive-push-pull;
-            slew-rate = <1>;
+            slew-rate = <3>;
         };
         pins2 {
-            pinmux = <STM32_PINMUX('A', 2, AF11)>; /* ETH1_MDIO */
-            bias-disable;
-            drive-push-pull;
-            slew-rate = <0>;
-        };
-        pins3 {
             pinmux = <STM32_PINMUX('A', 7, AF11)>, /* ETH1_CRS_DV */
                      <STM32_PINMUX('C', 4, AF11)>, /* ETH1_RXD0 */
                      <STM32_PINMUX('C', 5, AF11)>; /* ETH1_RXD1 */
             bias-disable;
         };
-        pins4 {
-            pinmux = <STM32_PINMUX('B', 11, AF11)>; /* ETH1_TX_EN */
-        };
     };
 
     eth1_sleep_pins_som: eth1_sleep_som@0 {
-        pins {
-            pinmux = <STM32_PINMUX('A', 2, ANALOG)>, /* ETH1_MDIO */
-                     <STM32_PINMUX('A', 7, ANALOG)>, /* ETH1_CRS_DV */
-                     <STM32_PINMUX('B', 11, ANALOG)>, /* ETH1_TX_EN */
-                     <STM32_PINMUX('B', 12, ANALOG)>, /* ETH1_TXD0 */
-                     <STM32_PINMUX('B', 13, ANALOG)>, /* ETH1_TXD1 */
-                     <STM32_PINMUX('C', 1, ANALOG)>, /* ETH1_MDC */
-                     <STM32_PINMUX('C', 4, ANALOG)>, /* ETH1_RXD0 */
-                     <STM32_PINMUX('C', 5, ANALOG)>, /* ETH1_RXD1 */
-                     <STM32_PINMUX('G', 8, ANALOG)>; /* ETH1_CLK */
+        pins1 {
+            pinmux = <STM32_PINMUX('A', 2, AF11)>, /* ETH1_MDIO */
+                     <STM32_PINMUX('B', 11, AF11)>, /* ETH1_TX_EN */
+                     <STM32_PINMUX('B', 12, AF11)>, /* ETH1_TXD0 */
+                     <STM32_PINMUX('B', 13, AF11)>, /* ETH1_TXD1 */
+                     <STM32_PINMUX('C', 1, AF11)>, /* ETH1_MDC */
+                     <STM32_PINMUX('G', 8, AF2)>; /* ETH1_CLK */
+            bias-disable;
+            drive-push-pull;
+            slew-rate = <3>;
+        };
+        pins2 {
+            pinmux = <STM32_PINMUX('A', 7, AF11)>, /* ETH1_CRS_DV */
+                     <STM32_PINMUX('C', 4, AF11)>, /* ETH1_RXD0 */
+                     <STM32_PINMUX('C', 5, AF11)>; /* ETH1_RXD1 */
+            bias-disable;
         };
     };
 
@@ -429,24 +411,21 @@
 
     i2c2_sleep_pins_som: i2c2_sleep_som@0 {
         pins {
-            pinmux = <STM32_PINMUX('D', 7, ANALOG)>, /* I2C2_SCL */
-                     <STM32_PINMUX('G', 15, ANALOG)>; /* I2C2_SDA */
+            pinmux = <STM32_PINMUX('D', 7, AF4)>, /* I2C2_SCL */
+                     <STM32_PINMUX('G', 15, AF4)>; /* I2C2_SDA */
+            bias-disable;
+            drive-open-drain;
+            slew-rate = <0>;
         };
     };
 
     quadspi_pins_som: quadspi_som@0 {
         u-boot,dm-pre-reloc;
-        pins1 {
+        pins {
             u-boot,dm-pre-reloc;
             pinmux = <STM32_PINMUX('B', 6, AF10)>, /* QUADSPI_BK1_NCS */
-                     <STM32_PINMUX('C', 0, AF10)>; /* QUADSPI_BK2_NCS */
-            bias-pull-up;
-            drive-push-pull;
-            slew-rate = <3>;
-        };
-        pins2 {
-            u-boot,dm-pre-reloc;
-            pinmux = <STM32_PINMUX('E', 7, AF10)>, /* QUADSPI_BK2_IO0 */
+                     <STM32_PINMUX('C', 0, AF10)>, /* QUADSPI_BK2_NCS */
+                     <STM32_PINMUX('E', 7, AF10)>, /* QUADSPI_BK2_IO0 */
                      <STM32_PINMUX('E', 8, AF10)>, /* QUADSPI_BK2_IO1 */
                      <STM32_PINMUX('E', 9, AF10)>, /* QUADSPI_BK2_IO2 */
                      <STM32_PINMUX('E', 10, AF10)>, /* QUADSPI_BK2_IO3 */
@@ -497,28 +476,18 @@
 
     uart4_sleep_pins_som: uart4_sleep_som@0 {
         u-boot,dm-pre-reloc;
-        pins {
-            u-boot,dm-pre-reloc;
-            pinmux = <STM32_PINMUX('B', 2, ANALOG)>, /* UART4_RX */
-                     <STM32_PINMUX('G', 11, ANALOG)>; /* UART4_TX */
-        };
-    };
-
-    usb_otg_hs_pins_som: usb_otg_hs_som-0 {
-        u-boot,dm-pre-reloc;
-        pins {
+        pins1 {
             u-boot,dm-pre-reloc;
-            pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
+            pinmux = <STM32_PINMUX('G', 11, AF6)>; /* UART4_TX */
+            bias-pull-up;
+            drive-push-pull;
+            slew-rate = <0>;
         };
-    };
-
-    usb_otg_hs_sleep_pins_som: usb_otg_hs_sleep_som-0 {
-        u-boot,dm-pre-reloc;
-        pins {
+        pins2 {
             u-boot,dm-pre-reloc;
-            pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
+            pinmux = <STM32_PINMUX('B', 2, AF8)>; /* UART4_RX */
+            bias-pull-up;
         };
     };
-
-
 };
+
diff --git a/recipes-kernel/linux/linux-stm32mp/stm32mp-som-t1001.dtsi b/recipes-kernel/linux/linux-stm32mp/stm32mp-som-t1001.dtsi
deleted file mode 100644
index a6984c7cc66c3ddb7a0a13fcf8a7e4e83b202dc0..0000000000000000000000000000000000000000
--- a/recipes-kernel/linux/linux-stm32mp/stm32mp-som-t1001.dtsi
+++ /dev/null
@@ -1,393 +0,0 @@
-/* Devicetree file for device
- *
- * device    : stm32mp-som-t1001
- * board code: 40099 164
- * revision  : 00
- *
- * Kontron Electronics GmbH
- * Copyright 2019 Kontron Electronics GmbH. All rights reserved.
- */
-
-#include <dt-bindings/gpio/gpio.h>
-
-/ {
-	device-identification {
-		som = "t1001";
-		som_pcb = "1 950 1743";
-		som_code = "40099 164 00";
-	};
-
-	chosen {
-		bootargs = "earlyprintk console=ttySTM0,115200 root=/dev/ram";
-		stdout-path = "serial0:115200n8";
-	};
-
-	aliases {
-		serial0 = &uart4;
-		i2c1 = "/soc/i2c@40013000";
-		mmc0 = "/soc/sdmmc@58005000";
-		spi0 = "/soc/qspi@58003000";
-	};
-
-    /* Regulators */
-	vddcore: regulator-vddcore {
-		compatible = "regulator-fixed";
-		regulator-name = "vddcore";
-		regulator-min-microvolt = <1200000>;
-		regulator-max-microvolt = <1200000>;
-		regulator-always-on;
-	};
-
-	vdd_ddr: regulator-vdd_ddr {
-		compatible = "regulator-fixed";
-		regulator-name = "vdd_ddr";
-		regulator-min-microvolt = <1350000>;
-		regulator-max-microvolt = <1350000>;
-		regulator-always-on;
-	};
-
-	vdd_usb: regulator-vdd_usb {
-		compatible = "regulator-fixed";
-		regulator-name = "vdd_usb";
-		regulator-min-microvolt = <3300000>;
-		regulator-max-microvolt = <3300000>;
-		regulator-always-on;
-	};
-
-	vdd: regulator-vdd {
-		compatible = "regulator-fixed";
-		regulator-name = "vdd";
-		regulator-min-microvolt = <3300000>;
-		regulator-max-microvolt = <3300000>;
-		regulator-always-on;
-	};
-
-	v3v3: regulator-v3v3 {
-		compatible = "regulator-fixed";
-		regulator-name = "v3v3";
-		regulator-min-microvolt = <3300000>;
-		regulator-max-microvolt = <3300000>;
-		regulator-always-on;
-	};
-
-	/* Set reset_out to low */
-	reset_out: regulator-reset_out {
-		compatible = "regulator-fixed";
-		regulator-name = "reset_out";
-		regulator-min-microvolt = <3300000>;
-		regulator-max-microvolt = <3300000>;
-		gpio = <&gpiod 15 GPIO_ACTIVE_HIGH>;
-		regulator-always-on;
-		regulator-boot-on;
-	};
-
-	/* Memory reservations */
-	reserved-memory {
-		#address-cells = <1>;
-		#size-cells = <1>;
-		ranges;
-
-		retram: retram@0x38000000 {
-			compatible = "shared-dma-pool";
-			reg = <0x38000000 0x10000>;
-			no-map;
-		};
-
-		mcuram: mcuram@0x30000000 {
-			compatible = "shared-dma-pool";
-			reg = <0x30000000 0x40000>;
-			no-map;
-		};
-
-		mcuram2: mcuram2@0x10000000 {
-			compatible = "shared-dma-pool";
-			reg = <0x10000000 0x40000>;
-			no-map;
-		};
-
-		vdev0vring0: vdev0vring0@10040000 {
-			compatible = "shared-dma-pool";
-			reg = <0x10040000 0x2000>;
-			no-map;
-		};
-
-		vdev0vring1: vdev0vring1@10042000 {
-			compatible = "shared-dma-pool";
-			reg = <0x10042000 0x2000>;
-			no-map;
-		};
-
-		vdev0buffer: vdev0buffer@10044000 {
-			compatible = "shared-dma-pool";
-			reg = <0x10044000 0x4000>;
-			no-map;
-		};
-
-		gpu_reserved: gpu@dc000000 {
-			/* 64MB reserved for GPU (min 32MB, max 192MB)
-			 * REMARK: RAM starts at 0xC0000000 and this is the end of RAM */
-			reg = <0xdc000000 0x4000000>;
-			no-map;
-		};
-	};
-
-	sram: sram@10050000 {
-		compatible = "mmio-sram";
-		reg = <0x10050000 0x10000>;
-		#address-cells = <1>;
-		#size-cells = <1>;
-		ranges = <0 0x10050000 0x10000>;
-
-		dma_pool: dma_pool@0 {
-			reg = <0x0 0x10000>;
-			pool;
-		};
-	};
-};
-
-
-/* reset and clock distribution */
-&rcc {
-    u-boot,dm-pre-reloc;
-    status = "okay";
-};
-
-
-/* internal rtc */
-&rtc {
-	status = "okay";
-};
-
-
-/* qspi interface */
-&qspi {
-    u-boot,dm-pre-reloc;
-	status = "okay";
-	#address-cells = <1>;
-	#size-cells = <0>;
-    pinctrl-names = "default", "sleep";
-    pinctrl-0 = <&quadspi_pins_som>;
-    pinctrl-1 = <&quadspi_sleep_pins_som>;
-
-	/* QSPI NOR for boot */
-	flash0: mx25r1635f@0 {
-		u-boot,dm-pre-reloc;
-		compatible = "spi-flash", "jedec,spi-nor";
-		reg = <0>;
-
-		spi-rx-bus-width = <4>;
-		spi-tx-bus-width = <4>;
-		spi-max-frequency = <8000000>; /* MX25R1635F is slow */
-
-		/* required for partitions when mtdparts in u-boot are used */
-		#address-cells = <1>;
-		#size-cells = <1>;
-	};
-};
-
-
-/* UART console */
-&uart4 {
-    u-boot,dm-pre-reloc;
-    pinctrl-names = "default", "sleep";
-    pinctrl-0 = <&uart4_pins_som>;
-    pinctrl-1 = <&uart4_sleep_pins_som>;
-    status = "okay";
-};
-
-
-/* Internal ADC reference voltage */
-/* Fallback configuration */
-&vrefbuf {
-	status = "okay";
-	/* Set referece voltage to 2.5V */
-	regulator-max-microvolt = <2500000>;
-	regulator-min-microvolt = <2500000>;
-	/*vdda-supply = <&vdd>;*/
-};
-
-
-/* USB settings */
-&usbh_ohci {
-    status = "okay";
-};
-
-
-&usbh_ehci {
-	status = "okay";
-	phys = <&usbphyc_port0>;
-	phy-names = "usb";
-};
-
-
-&usbotg_hs {
-	status = "okay";
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&usb_otg_hs_pins_som>;
-	pinctrl-1 = <&usb_otg_hs_sleep_pins_som>;
-	phys = <&usbphyc_port1 0>;
-	phy-names = "usb2-phy";
-	//vbus-supply = <&vbus_otg>;
-	usb33d-supply = <&usb33>;
-};
-
-
-&usbphyc {
-	status = "okay";
-	vdda1v1-supply = <&reg11>;
-	vdda1v8-supply = <&reg18>;
-	vdd3v3-supply = <&vdd_usb>;
-};
-
-
-&usbphyc_port0 {
-	phy-supply = <&vdd_usb>;
-};
-
-
-&usbphyc_port1 {
-	phy-supply = <&vdd_usb>;
-};
-
-
-/* GPU settings */
-&gpu {
-	status = "okay";
-	contiguous-area = <&gpu_reserved>;
-};
-
-
-&rng1 {
-	status = "okay";
-};
-
-
-&crc1{
-	/* enabling crc currently leads to sd/emmc disfunction */
-    status = "disabled";
-};
-
-
-/* DMA settings */
-&dma1 {
-	sram = <&dma_pool>;
-};
-
-
-&dma2 {
-	sram = <&dma_pool>;
-};
-
-
-/* Independent watchdog */
-&iwdg2 {
-	status = "okay";
-	timeout-sec = <32>;
-};
-
-
-/* Power control */
-&pwr {
-	pwr-supply = <&vdd>;
-};
-
-
-/* uC interface */
-&ipcc {
-	status = "okay";
-};
-
-
-/* reserved ressources for m4 */
-&m4_rproc {
-	status = "okay";
-	memory-region = <&retram>, <&mcuram>, <&mcuram2>, <&vdev0vring0>,
-			<&vdev0vring1>, <&vdev0buffer>;
-	mboxes = <&ipcc 0>, <&ipcc 1>, <&ipcc 2>;
-	mbox-names = "vq0", "vq1", "shutdown";
-	interrupt-parent = <&exti>;
-	interrupts = <68 1>;
-	interrupt-names = "wdg";
-};
-
-
-/* pin configuration */
-&pinctrl {
-
-    quadspi_pins_som: quadspi_som@0 {
-        u-boot,dm-pre-reloc;
-        pins1 {
-            u-boot,dm-pre-reloc;
-            pinmux = <STM32_PINMUX('B', 6, AF10)>; /* QUADSPI_BK1_NCS */
-            bias-pull-up;
-            drive-push-pull;
-            slew-rate = <3>;
-        };
-        pins2 {
-            u-boot,dm-pre-reloc;
-            pinmux = <STM32_PINMUX('F', 6, AF9)>, /* QUADSPI_BK1_IO3 */
-                     <STM32_PINMUX('F', 7, AF9)>, /* QUADSPI_BK1_IO2 */
-                     <STM32_PINMUX('F', 8, AF10)>, /* QUADSPI_BK1_IO0 */
-                     <STM32_PINMUX('F', 9, AF10)>, /* QUADSPI_BK1_IO1 */
-                     <STM32_PINMUX('F', 10, AF9)>; /* QUADSPI_CLK */
-            bias-disable;
-            drive-push-pull;
-            slew-rate = <3>;
-        };
-    };
-
-    quadspi_sleep_pins_som: quadspi_sleep_som@0 {
-        u-boot,dm-pre-reloc;
-        pins {
-            u-boot,dm-pre-reloc;
-            pinmux = <STM32_PINMUX('F', 6, ANALOG)>, /* QUADSPI_BK1_IO3 */
-                     <STM32_PINMUX('F', 7, ANALOG)>, /* QUADSPI_BK1_IO2 */
-                     <STM32_PINMUX('F', 8, ANALOG)>, /* QUADSPI_BK1_IO0 */
-                     <STM32_PINMUX('F', 9, ANALOG)>, /* QUADSPI_BK1_IO1 */
-                     <STM32_PINMUX('F', 10, ANALOG)>; /* QUADSPI_CLK */
-        };
-    };
-
-    uart4_pins_som: uart4_som@0 {
-        u-boot,dm-pre-reloc;
-        pins1 {
-            u-boot,dm-pre-reloc;
-            pinmux = <STM32_PINMUX('G', 11, AF6)>; /* UART4_TX */
-            bias-pull-up;
-            drive-push-pull;
-            slew-rate = <0>;
-        };
-        pins2 {
-            u-boot,dm-pre-reloc;
-            pinmux = <STM32_PINMUX('B', 2, AF8)>; /* UART4_RX */
-            bias-pull-up;
-        };
-    };
-
-    uart4_sleep_pins_som: uart4_sleep_som@0 {
-        u-boot,dm-pre-reloc;
-        pins {
-            u-boot,dm-pre-reloc;
-            pinmux = <STM32_PINMUX('B', 2, ANALOG)>, /* UART4_RX */
-                     <STM32_PINMUX('G', 11, ANALOG)>; /* UART4_TX */
-        };
-    };
-
-    usb_otg_hs_pins_som: usb_otg_hs_som-0 {
-        u-boot,dm-pre-reloc;
-        pins {
-            u-boot,dm-pre-reloc;
-            pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
-        };
-    };
-
-    usb_otg_hs_sleep_pins_som: usb_otg_hs_sleep_som-0 {
-        u-boot,dm-pre-reloc;
-        pins {
-            u-boot,dm-pre-reloc;
-            pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
-        };
-    };
-
-
-};
diff --git a/recipes-kernel/linux/linux-stm32mp/stm32mp-som-t1004.dtsi b/recipes-kernel/linux/linux-stm32mp/stm32mp-som-t1004.dtsi
deleted file mode 100644
index 247d511c7e94e8b479d7080f321edd382328f65b..0000000000000000000000000000000000000000
--- a/recipes-kernel/linux/linux-stm32mp/stm32mp-som-t1004.dtsi
+++ /dev/null
@@ -1,33 +0,0 @@
-/* Devicetree file for device
- *
- * device    : stm32mp-som-t1004
- * board code: 40099 180
- * revision  : 0
- *
- * Single core variant STM32MP151 without GPU/DSI and without CAN
- *
- * Kontron Electronics GmbH
- * Copyright 2019 Kontron Electronics GmbH. All rights reserved.
- */
-
-#include "stm32mp-som-t1000.dtsi"
-
-/ {
-	device-identification {
-		som = "t1004";
-		som_pcb = "1 951 1616";
-		som_code = "40099 180 00";
-	};
-};
-
-&m_can1 {
-	status = "disabled";
-};
-
-&gpu {
-	status = "disabled";
-};
-
-&dsi {
-	status = "disabled";
-};
diff --git a/recipes-kernel/linux/linux-stm32mp/stm32mp-som-t1005.dtsi b/recipes-kernel/linux/linux-stm32mp/stm32mp-som-t1005.dtsi
deleted file mode 100644
index f1c85b6bf842a817274dab12fc2143a6ee38a196..0000000000000000000000000000000000000000
--- a/recipes-kernel/linux/linux-stm32mp/stm32mp-som-t1005.dtsi
+++ /dev/null
@@ -1,29 +0,0 @@
-/* Devicetree file for device
- *
- * device    : stm32mp-som-t1005
- * board code: 40099 179
- * revision  : 0
- *
- * Variant STM32MP153 without GPU/DSI
- *
- * Kontron Electronics GmbH
- * Copyright 2019 Kontron Electronics GmbH. All rights reserved.
- */
-
-#include "stm32mp-som-t1000.dtsi"
-
-/ {
-	device-identification {
-		som = "t1004";
-		som_pcb = "1 951 1616";
-		som_code = "40099 179 00";
-	};
-};
-
-&gpu {
-	status = "disabled";
-};
-
-&dsi {
-	status = "disabled";
-};
diff --git a/recipes-kernel/linux/linux-stm32mp/stm32mp-t1000-k-101.dts b/recipes-kernel/linux/linux-stm32mp/stm32mp-t1000-k-101.dts
deleted file mode 100644
index 4f363e2067e0b2769059ed40799d91c4fbbf1c42..0000000000000000000000000000000000000000
--- a/recipes-kernel/linux/linux-stm32mp/stm32mp-t1000-k-101.dts
+++ /dev/null
@@ -1,25 +0,0 @@
-/* Devicetree file for device
- *
- * device   : stm32mp-t1000-k-101
- * revision : 0
- *
- * Kontron Electronics GmbH
- * Copyright 2020 Kontron Electronics GmbH. All rights reserved.
- */
-
-/* Include baseboard */
-#include "stm32mp-t1000-k.dts"
-
-/* Include housing */
-#include "stm32mp-housing-k-101.dtsi"
-
-/* Model identification */
-/ {
-	model = "stm32mp-t1000-k-101 (linux)";
- 	compatible = "ex,stm32mp-t1000-k-101", "st,stm32mp157";
-
- 	device-identification {
- 		device = "t1000-k-101";
- 		device_code = "prototype";
- 	};
-};
diff --git a/recipes-kernel/linux/linux-stm32mp/stm32mp-t1000-k-50.dts b/recipes-kernel/linux/linux-stm32mp/stm32mp-t1000-k-50.dts
deleted file mode 100644
index 38b7f30f8c57629ff2287a9762d9dd910f3e3f0f..0000000000000000000000000000000000000000
--- a/recipes-kernel/linux/linux-stm32mp/stm32mp-t1000-k-50.dts
+++ /dev/null
@@ -1,26 +0,0 @@
-/* Devicetree file for device
- *
- * device   : stm32mp-t1000-k-50
- * revision : 0
- *
- * Kontron Electronics GmbH
- * Copyright 2019 Kontron Electronics GmbH. All rights reserved.
- */
-
-/* Include baseboard */
-#include "stm32mp-t1000-k.dts"
-
-/* Include housing */
-#include "stm32mp-housing-k-50.dtsi"
-
-
-/* Model identification */
-/ {
-	model = "stm32mp-t1000-k-50 (linux)";
- 	compatible = "ex,stm32mp-t1000-k-50", "st,stm32mp157";
-
- 	device-identification {
- 		device = "t1000-k-50";
- 		device_code = "50099 044 01";
- 	};
-};
diff --git a/recipes-kernel/linux/linux-stm32mp/stm32mp-t1000-k-70.dts b/recipes-kernel/linux/linux-stm32mp/stm32mp-t1000-k-70.dts
deleted file mode 100644
index 3e2a89c68564f53bacc03c07035cfe129d572e11..0000000000000000000000000000000000000000
--- a/recipes-kernel/linux/linux-stm32mp/stm32mp-t1000-k-70.dts
+++ /dev/null
@@ -1,25 +0,0 @@
-/* Devicetree file for device
- *
- * device   : stm32mp-t1000-k-70
- * revision : 0
- *
- * Kontron Electronics GmbH
- * Copyright 2020 Kontron Electronics GmbH. All rights reserved.
- */
-
-/* Include baseboard */
-#include "stm32mp-t1000-k.dts"
-
-/* Include housing */
-#include "stm32mp-housing-k-70.dtsi"
-
-/* Model identification */
-/ {
-	model = "stm32mp-t1000-k-70 (linux)";
- 	compatible = "ex,stm32mp-t1000-k-70", "st,stm32mp157";
-
- 	device-identification {
- 		device = "t1000-k-70";
- 		device_code = "prototype";
- 	};
-};
diff --git a/recipes-kernel/linux/linux-stm32mp/stm32mp-t1000-k.dts b/recipes-kernel/linux/linux-stm32mp/stm32mp-t1000-k.dts
deleted file mode 100644
index 55df37beda804019b42c6babe8c179101e2d4479..0000000000000000000000000000000000000000
--- a/recipes-kernel/linux/linux-stm32mp/stm32mp-t1000-k.dts
+++ /dev/null
@@ -1,38 +0,0 @@
-/* Devicetree file for device
- *
- * device   : stm32mp-t1000-k
- * revision : 0
- *
- * Kontron Electronics GmbH
- * Copyright 2019 Kontron Electronics GmbH. All rights reserved.
- */
-
-/* Include CubeMX board configuration
- * - pinmultiplexing and
- * - peripheal activation
- */
-#include "stm32mp157c-t1000-k-mx.dts"
-
-/* Include SOM components
- * - SOM components: RAM,
- * - Basic Clocks (only tf-a, u-boot)
- */
-#include "stm32mp-som-t1000.dtsi"
-
-/* Include baseboard */
-#include "stm32mp-board-k.dtsi"
-
-/* Include housing */
-/* NOT AVAILABLE */
-
-
-/* Model identification */
-/ {
-	model = "stm32mp-t1000-k (linux)";
- 	compatible = "ex,stm32mp-t1000-k", "st,stm32mp157";
-
- 	device-identification {
- 		device = "t1000-k";
- 		device_code = "50099 045 01";
- 	};
-};
diff --git a/recipes-kernel/linux/linux-stm32mp/stm32mp-t1000-mini.dts b/recipes-kernel/linux/linux-stm32mp/stm32mp-t1000-mini.dts
new file mode 100644
index 0000000000000000000000000000000000000000..8d42873103be5ca48f8ccdb489ca8ecd9d88c1f0
--- /dev/null
+++ b/recipes-kernel/linux/linux-stm32mp/stm32mp-t1000-mini.dts
@@ -0,0 +1,57 @@
+/* Devicetree file for device
+ *
+ * device   : stm32mp-t1000-mini
+ * revision : prototype
+ *
+ * Kontron Electronics GmbH
+ * Copyright 2018 Kontron Electronics GmbH. All rights reserved.
+ */
+
+/* Include CubeMX board configuration
+ * - pinmultiplexing and
+ * - peripheal activation
+ */
+#include "stm32mp157c-t1000-mini-mx.dts"
+
+/* Include SOM components
+ * - SOM components: RAM,
+ * - Basic Clocks (only tf-a, u-boot)
+ */
+#include "stm32mp-som-t1000.dtsi"
+
+/* Include baseboard */
+#include "stm32mp-board-mini.dtsi"
+
+/* Include housing */
+/* NOT AVAILABLE */
+
+
+/* Model identification */
+/ {
+	model = "stm32mp-t1000-mini (linux)";
+ 	compatible = "ex,stm32mp-t1000-mini", "st,stm32mp157";
+
+ 	device-identification {
+ 		device = "t1000-mini";
+ 		device_code = "40099 113 01 (prototype)";
+ 	};
+
+	leds:led {
+		compatible = "gpio-leds";
+		status = "okay";
+		red {
+			label = "stm32mp:red:status";
+			gpios = <&gpioa 13 GPIO_ACTIVE_LOW>;
+			default-state = "off";
+			linux,default-trigger = "heartbeat";
+			status = "okay";
+		};
+		green {
+			label = "stm32mp:green:user";
+			gpios = <&gpioa 14 GPIO_ACTIVE_LOW>;
+			default-state = "off";
+			linux,default-trigger = "heartbeat";
+			status = "okay";
+		};
+	};
+};
diff --git a/recipes-kernel/linux/linux-stm32mp/stm32mp-t1000-s-24.dts b/recipes-kernel/linux/linux-stm32mp/stm32mp-t1000-s-24.dts
deleted file mode 100644
index ad32a6c5ba6b903336ce083c938f7a7ab4e1e3d1..0000000000000000000000000000000000000000
--- a/recipes-kernel/linux/linux-stm32mp/stm32mp-t1000-s-24.dts
+++ /dev/null
@@ -1,26 +0,0 @@
-/* Devicetree file for device
- *
- * device   : stm32mp-t1000-s-24
- * revision : prototype
- *
- * Kontron Electronics GmbH
- * Copyright 2019 Kontron Electronics GmbH. All rights reserved.
- */
-
-/* Include baseboard */
-#include "stm32mp-t1000-s.dts"
-
-/* Include housing */
-#include "stm32mp-housing-24.dtsi"
-
-
-/* Model identification */
-/ {
-	model = "stm32mp-t1000-s-24 (linux)";
- 	compatible = "ex,stm32mp-t1000-s-24", "st,stm32mp157";
-
- 	device-identification {
- 		device = "t1000-s-24";
- 		device_code = "prototype";
- 	};
-};
diff --git a/recipes-kernel/linux/linux-stm32mp/stm32mp-t1000-s-50.dts b/recipes-kernel/linux/linux-stm32mp/stm32mp-t1000-s-50.dts
index 6f8f6e5fbdb2da1bf057c9af5ed9ccaf9b56f022..32032e635fa8971fb0f6865130c3c2177d4dca5a 100644
--- a/recipes-kernel/linux/linux-stm32mp/stm32mp-t1000-s-50.dts
+++ b/recipes-kernel/linux/linux-stm32mp/stm32mp-t1000-s-50.dts
@@ -1,7 +1,7 @@
 /* Devicetree file for device
  *
  * device   : stm32mp-t1000-s-50
- * revision : 0
+ * revision : prototype
  *
  * Kontron Electronics GmbH
  * Copyright 2018 Kontron Electronics GmbH. All rights reserved.
@@ -21,6 +21,6 @@
 
  	device-identification {
  		device = "t1000-s-50";
- 		device_code = "50099 044 000";
+ 		device_code = "unknown (prototype)";
  	};
 };
diff --git a/recipes-kernel/linux/linux-stm32mp/stm32mp-t1000-s-clkout32k.dts b/recipes-kernel/linux/linux-stm32mp/stm32mp-t1000-s-clkout32k.dts
deleted file mode 100644
index 83c35f02a102f57329cf70a6db390c95ee791b8e..0000000000000000000000000000000000000000
--- a/recipes-kernel/linux/linux-stm32mp/stm32mp-t1000-s-clkout32k.dts
+++ /dev/null
@@ -1,57 +0,0 @@
-/* Devicetree file for device
- *
- * device   : stm32mp-t1000-s
- * revision : 0
- *
- * Kontron Electronics GmbH
- * Copyright 2018 Kontron Electronics GmbH. All rights reserved.
- */
-
-/* Include CubeMX board configuration
- * - pinmultiplexing and
- * - peripheal activation
- */
-#include "stm32mp157c-t1000-s-mx.dts"
-
-/* Include SOM components
- * - SOM components: RAM,
- * - Basic Clocks (only tf-a, u-boot)
- */
-#include "stm32mp-som-t1000.dtsi"
-
-/* Include baseboard */
-#include "stm32mp-board-s.dtsi"
-
-/* Include housing */
-/* NOT AVAILABLE */
-
-&pinctrl {
-	rcc_pins_mx: rcc_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 13, AF2)>; /* RCC_MCO_1 */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-	};
-};
-
-&rcc{
-	pinctrl-names = "default";
-	pinctrl-0 = <&rcc_pins_mx>;
-};
-
-&leds{
-	/delete-node/led1;
-};
-
-/* Model identification */
-/ {
-	model = "stm32mp-t1000-s (linux)";
- 	compatible = "ex,stm32mp-t1000-s", "st,stm32mp157";
-
- 	device-identification {
- 		device = "t1000-s";
- 		device_code = "50099 045 000";
- 	};
-};
diff --git a/recipes-kernel/linux/linux-stm32mp/stm32mp-t1000-s.dts b/recipes-kernel/linux/linux-stm32mp/stm32mp-t1000-s.dts
index 642731bb2fed8f056c93a2d2973f03260a4896de..763bac6c726c873db05a62582c76f75430b60b93 100644
--- a/recipes-kernel/linux/linux-stm32mp/stm32mp-t1000-s.dts
+++ b/recipes-kernel/linux/linux-stm32mp/stm32mp-t1000-s.dts
@@ -1,7 +1,7 @@
 /* Devicetree file for device
  *
  * device   : stm32mp-t1000-s
- * revision : 0
+ * revision : prototype
  *
  * Kontron Electronics GmbH
  * Copyright 2018 Kontron Electronics GmbH. All rights reserved.
@@ -33,6 +33,6 @@
 
  	device-identification {
  		device = "t1000-s";
- 		device_code = "50099 045 000";
+ 		device_code = "40099 131 00 (prototype)";
  	};
 };
diff --git a/recipes-kernel/linux/linux-stm32mp/stm32mp-t1000.dts b/recipes-kernel/linux/linux-stm32mp/stm32mp-t1000.dts
deleted file mode 100644
index e3a4766ee5b93db2d35db14aa888235b182c8a95..0000000000000000000000000000000000000000
--- a/recipes-kernel/linux/linux-stm32mp/stm32mp-t1000.dts
+++ /dev/null
@@ -1,39 +0,0 @@
-/* Devicetree file for basic t1000 SOM module
- *
- * These settings should work with most baseboards
- *
- * device    : stm32mp-t1000
- * board code: 40099 167
- * revision  : 0
- *
- * Kontron Electronics GmbH
- * Copyright 2019 Kontron Electronics GmbH. All rights reserved.
- */
-
-/* Include (your) CubeMX board configuration
- * - pinmultiplexing and
- * - peripheal activation
- */
-#include "stm32mp157c-t1000-som-minimal-mx.dts"
-
-/* Include SOM components
- * - SOM components: RAM,
- * - Basic Clocks (only tf-a, u-boot)
- */
-#include "stm32mp-som-t1000.dtsi"
-
-/* Include (your) baseboard */
-#include "stm32mp-board-minimal.dtsi"
-
-/* Model identification */
-/ {
-	model = "stm32mp-t1000 (linux)";
- 	compatible = "ex,stm32mp-t1000", "st,stm32mp157";
- 	/* Compatibility string correspondents to extlinux base directory */
-
- 	/* Add your device identification (only for informational purpose) */
- 	device-identification {
- 		device = "t1000";
- 		device_code = "40099 167 00";
- 	};
-};
diff --git a/recipes-kernel/linux/linux-stm32mp/stm32mp-t1001.dts b/recipes-kernel/linux/linux-stm32mp/stm32mp-t1001.dts
deleted file mode 100644
index 3fce988f6b486b07a803fec6492749ff5f885dd4..0000000000000000000000000000000000000000
--- a/recipes-kernel/linux/linux-stm32mp/stm32mp-t1001.dts
+++ /dev/null
@@ -1,39 +0,0 @@
-/* Devicetree file for basic t1001 SOM module
- *
- * These settings should work with most baseboards
- *
- * device    : stm32mp-som-t1001
- * board code: 40099 164
- * revision  : 00
- *
- * Kontron Electronics GmbH
- * Copyright 2019 Kontron Electronics GmbH. All rights reserved.
- */
-
-/* Include (your) CubeMX board configuration
- * - pinmultiplexing and
- * - peripheal activation
- */
-#include "stm32mp157c-t1001-som-minimal-mx.dts"
-
-/* Include SOM components
- * - SOM components: RAM,
- * - Basic Clocks (only tf-a, u-boot)
- */
-#include "stm32mp-som-t1001.dtsi"
-
-/* Include (your) baseboard */
-#include "stm32mp-board-minimal.dtsi"
-
-/* Model identification */
-/ {
-	model = "stm32mp-t1001 (linux)";
- 	compatible = "ex,stm32mp-t1001", "st,stm32mp157";
- 	/* Compatibility string correspondents to extlinux base directory */
-
- 	/* Add your device identification (only for informational purpose) */
- 	device-identification {
- 		device = "t1001";
- 		device_code = "40099 164 00";
- 	};
-};
diff --git a/recipes-kernel/linux/linux-stm32mp/stm32mp-t1004-k-50.dts b/recipes-kernel/linux/linux-stm32mp/stm32mp-t1004-k-50.dts
deleted file mode 100644
index 1ae6efcddfa447276d4d0592ed80cbbeb89c6ab8..0000000000000000000000000000000000000000
--- a/recipes-kernel/linux/linux-stm32mp/stm32mp-t1004-k-50.dts
+++ /dev/null
@@ -1,32 +0,0 @@
-/* Devicetree file for device
- *
- * device   : stm32mp-t1004-k-50
- * revision : 0
- *
- * Variant STM32MP151
- *
- * Kontron Electronics GmbH
- * Copyright 2019 Kontron Electronics GmbH. All rights reserved.
- */
-
-/* Include baseboard */
-#include "stm32mp-t1004-k.dts"
-
-/* Include housing */
-#include "stm32mp-housing-k-50.dtsi"
-
-// disable GPU/DSI for STM32MP151 variant
-&dsi {
-	status = "disabled";
-};
-
-/* Model identification */
-/ {
-	model = "stm32mp-t1004-k-50 (linux)";
- 	compatible = "ex,stm32mp-t1004-k-50", "st,stm32mp157";
-
- 	device-identification {
- 		device = "t1004-k-50";
- 		device_code = "";
- 	};
-};
diff --git a/recipes-kernel/linux/linux-stm32mp/stm32mp-t1004-k.dts b/recipes-kernel/linux/linux-stm32mp/stm32mp-t1004-k.dts
deleted file mode 100644
index c817b46da4c64243d049890109bb79e927399a5a..0000000000000000000000000000000000000000
--- a/recipes-kernel/linux/linux-stm32mp/stm32mp-t1004-k.dts
+++ /dev/null
@@ -1,45 +0,0 @@
-/* Devicetree file for device
- *
- * device   : stm32mp-t1004-k
- * revision : 0
- *
- * Variant STM32MP151
- *
- * Kontron Electronics GmbH
- * Copyright 2019 Kontron Electronics GmbH. All rights reserved.
- */
-
-/* Include CubeMX board configuration
- * - pinmultiplexing and
- * - peripheal activation
- */
-#include "stm32mp157c-t1000-k-mx.dts"
-
-/* Include SOM components
- * - SOM components: RAM,
- * - Basic Clocks (only tf-a, u-boot)
- */
-#include "stm32mp-som-t1004.dtsi"
-
-/* Include baseboard */
-#include "stm32mp-board-k.dtsi"
-
-// disable GPU/DSI for STM32MP151 variant
-&dsi {
-	status = "disabled";
-};
-
-/* Include housing */
-/* NOT AVAILABLE */
-
-
-/* Model identification */
-/ {
-	model = "stm32mp-t1004-k (linux)";
- 	compatible = "ex,stm32mp-t1004-k", "st,stm32mp157";
-
- 	device-identification {
- 		device = "t1004-k";
- 		device_code = "";
- 	};
-};
diff --git a/recipes-kernel/linux/linux-stm32mp/stm32mp-t1004.dts b/recipes-kernel/linux/linux-stm32mp/stm32mp-t1004.dts
deleted file mode 100644
index a8dac14af31bfdbdbb9186410e1979e4257687ad..0000000000000000000000000000000000000000
--- a/recipes-kernel/linux/linux-stm32mp/stm32mp-t1004.dts
+++ /dev/null
@@ -1,40 +0,0 @@
-/* Devicetree file for basic t1004 SOM module
- * STM32MP151 variant
- *
- * These settings should work with most baseboards
- *
- * device    : stm32mp-som-t1004
- * board code: 40099 180
- * revision  : 0
- *
- * Kontron Electronics GmbH
- * Copyright 2019 Kontron Electronics GmbH. All rights reserved.
- */
-
-/* Include (your) CubeMX board configuration
- * - pinmultiplexing and
- * - peripheal activation
- */
-#include "stm32mp157c-t1001-som-minimal-mx.dts"
-
-/* Include SOM components
- * - SOM components: RAM,
- * - Basic Clocks (only tf-a, u-boot)
- */
-#include "stm32mp-som-t1004.dtsi"
-
-/* Include (your) baseboard */
-#include "stm32mp-board-minimal.dtsi"
-
-/* Model identification */
-/ {
-	model = "stm32mp-t1004 (linux)";
- 	compatible = "ex,stm32mp-t1004", "st,stm32mp157";
- 	/* Compatibility string correspondents to extlinux base directory */
-
- 	/* Add your device identification (only for informational purpose) */
- 	device-identification {
- 		device = "t1004";
- 		device_code = "40099 180 00";
- 	};
-};
diff --git a/recipes-kernel/linux/linux-stm32mp/stm32mp-t1005-k-50.dts b/recipes-kernel/linux/linux-stm32mp/stm32mp-t1005-k-50.dts
deleted file mode 100644
index a32db725e2373070fc51c65c54498295acade34a..0000000000000000000000000000000000000000
--- a/recipes-kernel/linux/linux-stm32mp/stm32mp-t1005-k-50.dts
+++ /dev/null
@@ -1,32 +0,0 @@
-/* Devicetree file for device
- *
- * device   : stm32mp-t1005-k-50
- * revision : 0
- *
- * Variant STM32MP153
- *
- * Kontron Electronics GmbH
- * Copyright 2019 Kontron Electronics GmbH. All rights reserved.
- */
-
-/* Include baseboard */
-#include "stm32mp-t1005-k.dts"
-
-/* Include housing */
-#include "stm32mp-housing-k-50.dtsi"
-
-// disable GPU/DSI for STM32MP153 variant
-&dsi {
-	status = "disabled";
-};
-
-/* Model identification */
-/ {
-	model = "stm32mp-t1005-k-50 (linux)";
- 	compatible = "ex,stm32mp-t1005-k-50", "st,stm32mp157";
-
- 	device-identification {
- 		device = "t1005-k-50";
- 		device_code = "";
- 	};
-};
diff --git a/recipes-kernel/linux/linux-stm32mp/stm32mp-t1005-k.dts b/recipes-kernel/linux/linux-stm32mp/stm32mp-t1005-k.dts
deleted file mode 100644
index 7feb9d43b7a0a3a89fe896aae1bfb9753765961c..0000000000000000000000000000000000000000
--- a/recipes-kernel/linux/linux-stm32mp/stm32mp-t1005-k.dts
+++ /dev/null
@@ -1,45 +0,0 @@
-/* Devicetree file for device
- *
- * device   : stm32mp-t1005-k
- * revision : 0
- *
- * Variant STM32MP153
- *
- * Kontron Electronics GmbH
- * Copyright 2019 Kontron Electronics GmbH. All rights reserved.
- */
-
-/* Include CubeMX board configuration
- * - pinmultiplexing and
- * - peripheal activation
- */
-#include "stm32mp157c-t1000-k-mx.dts"
-
-/* Include SOM components
- * - SOM components: RAM,
- * - Basic Clocks (only tf-a, u-boot)
- */
-#include "stm32mp-som-t1005.dtsi"
-
-/* Include baseboard */
-#include "stm32mp-board-k.dtsi"
-
-// disable GPU/DSI for STM32MP153 variant
-&dsi {
-	status = "disabled";
-};
-
-/* Include housing */
-/* NOT AVAILABLE */
-
-
-/* Model identification */
-/ {
-	model = "stm32mp-t1004-k (linux)";
- 	compatible = "ex,stm32mp-t1004-k", "st,stm32mp157";
-
- 	device-identification {
- 		device = "t1004-k";
- 		device_code = "";
- 	};
-};
diff --git a/recipes-kernel/linux/linux-stm32mp/stm32mp-t1005.dts b/recipes-kernel/linux/linux-stm32mp/stm32mp-t1005.dts
deleted file mode 100644
index f51a689b8475545001eef3ce3e013fcc54db2e33..0000000000000000000000000000000000000000
--- a/recipes-kernel/linux/linux-stm32mp/stm32mp-t1005.dts
+++ /dev/null
@@ -1,40 +0,0 @@
-/* Devicetree file for basic t1004 SOM module
- * STM32MP153 variant
- *
- * These settings should work with most baseboards
- *
- * device    : stm32mp-som-t1005
- * board code: 40099 181
- * revision  : 0
- *
- * Kontron Electronics GmbH
- * Copyright 2019 Kontron Electronics GmbH. All rights reserved.
- */
-
-/* Include (your) CubeMX board configuration
- * - pinmultiplexing and
- * - peripheal activation
- */
-#include "stm32mp157c-t1001-som-minimal-mx.dts"
-
-/* Include SOM components
- * - SOM components: RAM,
- * - Basic Clocks (only tf-a, u-boot)
- */
-#include "stm32mp-som-t1005.dtsi"
-
-/* Include (your) baseboard */
-#include "stm32mp-board-minimal.dtsi"
-
-/* Model identification */
-/ {
-	model = "stm32mp-t1005 (linux)";
- 	compatible = "ex,stm32mp-t1005", "st,stm32mp157";
- 	/* Compatibility string correspondents to extlinux base directory */
-
- 	/* Add your device identification (only for informational purpose) */
- 	device-identification {
- 		device = "t1004";
- 		device_code = "40099 181 00";
- 	};
-};
diff --git a/recipes-kernel/linux/linux-stm32mp/bleeding/stm32mp157c-t1000-s-mx.dts b/recipes-kernel/linux/linux-stm32mp/stm32mp157c-t1000-default-mx.dts
similarity index 57%
rename from recipes-kernel/linux/linux-stm32mp/bleeding/stm32mp157c-t1000-s-mx.dts
rename to recipes-kernel/linux/linux-stm32mp/stm32mp157c-t1000-default-mx.dts
index a57a14bc76b1aa98b2f5c6837ffd16b42ffe915d..f3f88f4535e2697e6ddea77391b4ecbb10c6a46c 100644
--- a/recipes-kernel/linux/linux-stm32mp/bleeding/stm32mp157c-t1000-s-mx.dts
+++ b/recipes-kernel/linux/linux-stm32mp/stm32mp157c-t1000-default-mx.dts
@@ -1,112 +1,108 @@
 /* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
 /*
- * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
+ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved
  * Author: STM32CubeMX code generation for STMicroelectronics.
  */
 
 /dts-v1/;
 #include "stm32mp157c.dtsi"
 #include "stm32mp157cad-pinctrl.dtsi"
-#include "stm32mp157c-m4-srm.dtsi"
 
-/* USER CODE BEGIN includes */
-/* USER CODE END includes */
+/* USER CODE BEGIN dts_include */
+/* USER CODE END dts_include */
 
 / {
-	model = "STMicroelectronics custom STM32CubeMX board";
-	compatible = "st,stm32mp157c-t1000-s-mx", "st,stm32mp157";
+    model = "STMicroelectronics custom STM32CubeMX board";
+	compatible = "st,stm32mp157c-t1000-default-mx", "st,stm32mp157";
 
-    memory@c0000000 {
-        reg = <0xc0000000 0x20000000>;
+	memory {
+		reg = <0xC0000000 0x20000000>;
+	};
 
-        /* USER CODE BEGIN memory */
-        /* USER CODE END memory */
-    };
-
-    reserved-memory {
-        #address-cells = <1>;
-        #size-cells = <1>;
-        ranges;
-
-        /* USER CODE BEGIN reserved-memory */
-        /* USER CODE END reserved-memory */
-
-        gpu_reserved: gpu@dc000000 {
-            reg = <0xdc000000 0x4000000>;
-            no-map;
-        };
-    };
-
-	/* USER CODE BEGIN root */
-	/* USER CODE END root */
+	/* USER CODE BEGIN root_prop */
+	/* USER CODE END root_prop */
 
     clocks {
-        /* USER CODE BEGIN clocks */
-        /* USER CODE END clocks */
-
+        u-boot,dm-pre-reloc;
         clk_hsi: clk-hsi {
+            #clock-cells = <0>;
+            compatible = "fixed-clock";
             clock-frequency = <64000000>;
+            u-boot,dm-pre-reloc;
         };
-        clk_csi: clk-csi {
-            clock-frequency = <4000000>;
+        clk_usbo_48m: ck_usbo_48m {
+            #clock-cells = <0>;
+            compatible = "fixed-clock";
+            clock-frequency = <48000000>;
+            u-boot,dm-pre-reloc;
         };
         clk_lse: clk-lse {
+            #clock-cells = <0>;
+            compatible = "fixed-clock";
             clock-frequency = <32768>;
+            u-boot,dm-pre-reloc;
         };
         clk_hse: clk-hse {
+            #clock-cells = <0>;
+            compatible = "fixed-clock";
             clock-frequency = <24000000>;
+            u-boot,dm-pre-reloc;
         };
     };
+	/* USER CODE BEGIN root_subnodes */
+	/* USER CODE END root_subnodes */
+
+	/* USER CODE BEGIN root_board */
+	/* USER CODE END root_board */
+
+	/* USER CODE BEGIN root_platform */
+	/* USER CODE END root_platform */
 
 }; /*root*/
 
+/* USER CODE BEGIN dts_board */
+/* USER CODE END dts_board */
+
 &pinctrl {
     u-boot,dm-pre-reloc;
-    adc_pins_mx: adc_mx-0 {
+    adc_pins_mx: adc_mx@0 {
         pins {
             pinmux = <STM32_PINMUX('A', 0, ANALOG)>, /* ADC1_INP16 */
                      <STM32_PINMUX('B', 1, ANALOG)>; /* ADC1_INP5 */
         };
     };
-    eth1_pins_mx: eth1_mx-0 {
+    eth1_pins_mx: eth1_mx@0 {
         pins1 {
-            pinmux = <STM32_PINMUX('B', 12, AF11)>, /* ETH1_TXD0 */
+            pinmux = <STM32_PINMUX('A', 2, AF11)>, /* ETH1_MDIO */
+                     <STM32_PINMUX('B', 11, AF11)>, /* ETH1_TX_EN */
+                     <STM32_PINMUX('B', 12, AF11)>, /* ETH1_TXD0 */
                      <STM32_PINMUX('B', 13, AF11)>, /* ETH1_TXD1 */
                      <STM32_PINMUX('C', 1, AF11)>, /* ETH1_MDC */
                      <STM32_PINMUX('G', 8, AF2)>; /* ETH1_CLK */
             bias-disable;
             drive-push-pull;
-            slew-rate = <1>;
+            slew-rate = <3>;
         };
         pins2 {
-            pinmux = <STM32_PINMUX('A', 2, AF11)>; /* ETH1_MDIO */
-            bias-disable;
-            drive-push-pull;
-            slew-rate = <0>;
-        };
-        pins3 {
             pinmux = <STM32_PINMUX('A', 7, AF11)>, /* ETH1_CRS_DV */
                      <STM32_PINMUX('C', 4, AF11)>, /* ETH1_RXD0 */
                      <STM32_PINMUX('C', 5, AF11)>; /* ETH1_RXD1 */
             bias-disable;
         };
-        pins4 {
-            pinmux = <STM32_PINMUX('B', 11, AF11)>; /* ETH1_TX_EN */
-        };
     };
-    fdcan1_pins_mx: fdcan1_mx-0 {
+    fdcan1_pins_mx: fdcan1_mx@0 {
         pins1 {
             pinmux = <STM32_PINMUX('D', 1, AF9)>; /* FDCAN1_TX */
             bias-disable;
             drive-push-pull;
-            slew-rate = <0>;
+            slew-rate = <1>;
         };
         pins2 {
             pinmux = <STM32_PINMUX('D', 0, AF9)>; /* FDCAN1_RX */
             bias-disable;
         };
     };
-    i2c2_pins_mx: i2c2_mx-0 {
+    i2c2_pins_mx: i2c2_mx@0 {
         pins {
             pinmux = <STM32_PINMUX('D', 7, AF4)>, /* I2C2_SCL */
                      <STM32_PINMUX('G', 15, AF4)>; /* I2C2_SDA */
@@ -115,7 +111,7 @@
             slew-rate = <0>;
         };
     };
-    i2c4_pins_mx: i2c4_mx-0 {
+    i2c4_pins_mx: i2c4_mx@0 {
         pins {
             pinmux = <STM32_PINMUX('B', 7, AF6)>, /* I2C4_SDA */
                      <STM32_PINMUX('E', 2, AF4)>; /* I2C4_SCL */
@@ -124,22 +120,8 @@
             slew-rate = <0>;
         };
     };
-    i2s2_pins_mx: i2s2_mx-0 {
+    ltdc_pins_mx: ltdc_mx@0 {
         pins {
-            pinmux = <STM32_PINMUX('A', 11, AF5)>, /* I2S2_WS */
-                     <STM32_PINMUX('C', 2, AF5)>, /* I2S2_SDI */
-                     <STM32_PINMUX('C', 3, AF5)>, /* I2S2_SDO */
-                     <STM32_PINMUX('D', 3, AF5)>, /* I2S2_CK */
-                     <STM32_PINMUX('E', 1, AF5)>; /* I2S2_MCK */
-            bias-disable;
-            drive-push-pull;
-            slew-rate = <1>;
-        };
-    };
-    ltdc_pins_mx: ltdc_mx-0 {
-        u-boot,dm-pre-reloc;
-        pins1 {
-            u-boot,dm-pre-reloc;
             pinmux = <STM32_PINMUX('A', 1, AF14)>, /* LTDC_R2 */
                      <STM32_PINMUX('A', 3, AF14)>, /* LTDC_B5 */
                      <STM32_PINMUX('A', 4, AF14)>, /* LTDC_VSYNC */
@@ -147,7 +129,6 @@
                      <STM32_PINMUX('A', 6, AF14)>, /* LTDC_G2 */
                      <STM32_PINMUX('A', 8, AF14)>, /* LTDC_R6 */
                      <STM32_PINMUX('A', 12, AF14)>, /* LTDC_R5 */
-                     <STM32_PINMUX('A', 15, AF14)>, /* LTDC_R1 */
                      <STM32_PINMUX('B', 0, AF9)>, /* LTDC_R3 */
                      <STM32_PINMUX('B', 5, AF14)>, /* LTDC_G7 */
                      <STM32_PINMUX('B', 8, AF14)>, /* LTDC_B6 */
@@ -156,42 +137,25 @@
                      <STM32_PINMUX('C', 6, AF14)>, /* LTDC_HSYNC */
                      <STM32_PINMUX('C', 7, AF14)>, /* LTDC_G6 */
                      <STM32_PINMUX('D', 10, AF14)>, /* LTDC_B3 */
-                     <STM32_PINMUX('E', 4, AF14)>, /* LTDC_B0 */
-                     <STM32_PINMUX('E', 5, AF14)>, /* LTDC_G0 */
-                     <STM32_PINMUX('E', 6, AF14)>, /* LTDC_G1 */
                      <STM32_PINMUX('E', 11, AF14)>, /* LTDC_G3 */
                      <STM32_PINMUX('E', 12, AF14)>, /* LTDC_B4 */
                      <STM32_PINMUX('E', 13, AF14)>, /* LTDC_DE */
+                     <STM32_PINMUX('E', 14, AF14)>, /* LTDC_CLK */
                      <STM32_PINMUX('E', 15, AF14)>, /* LTDC_R7 */
                      <STM32_PINMUX('F', 11, AF14)>, /* LTDC_G5 */
-                     <STM32_PINMUX('G', 10, AF14)>, /* LTDC_B2 */
-                     <STM32_PINMUX('G', 12, AF14)>, /* LTDC_B1 */
-                     <STM32_PINMUX('G', 13, AF14)>; /* LTDC_R0 */
-            bias-disable;
-            drive-push-pull;
-            slew-rate = <0>;
-        };
-        pins2 {
-            u-boot,dm-pre-reloc;
-            pinmux = <STM32_PINMUX('E', 14, AF14)>; /* LTDC_CLK */
+                     <STM32_PINMUX('G', 10, AF14)>; /* LTDC_B2 */
             bias-disable;
             drive-push-pull;
-            slew-rate = <1>;
+            slew-rate = <3>;
         };
     };
-    quadspi_pins_mx: quadspi_mx-0 {
+    quadspi_pins_mx: quadspi_mx@0 {
         u-boot,dm-pre-reloc;
-        pins1 {
+        pins {
             u-boot,dm-pre-reloc;
             pinmux = <STM32_PINMUX('B', 6, AF10)>, /* QUADSPI_BK1_NCS */
-                     <STM32_PINMUX('C', 0, AF10)>; /* QUADSPI_BK2_NCS */
-            bias-pull-up;
-            drive-push-pull;
-            slew-rate = <3>;
-        };
-        pins2 {
-            u-boot,dm-pre-reloc;
-            pinmux = <STM32_PINMUX('E', 7, AF10)>, /* QUADSPI_BK2_IO0 */
+                     <STM32_PINMUX('C', 0, AF10)>, /* QUADSPI_BK2_NCS */
+                     <STM32_PINMUX('E', 7, AF10)>, /* QUADSPI_BK2_IO0 */
                      <STM32_PINMUX('E', 8, AF10)>, /* QUADSPI_BK2_IO1 */
                      <STM32_PINMUX('E', 9, AF10)>, /* QUADSPI_BK2_IO2 */
                      <STM32_PINMUX('E', 10, AF10)>, /* QUADSPI_BK2_IO3 */
@@ -205,65 +169,47 @@
             slew-rate = <3>;
         };
     };
-    sdmmc1_pins_mx: sdmmc1_mx-0 {
+    sdmmc1_pins_mx: sdmmc1_mx@0 {
         u-boot,dm-pre-reloc;
-        pins1 {
+        pins {
             u-boot,dm-pre-reloc;
             pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
                      <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
                      <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
                      <STM32_PINMUX('C', 11, AF12)>, /* SDMMC1_D3 */
+                     <STM32_PINMUX('C', 12, AF12)>, /* SDMMC1_CK */
                      <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
             bias-pull-up;
             drive-push-pull;
-            slew-rate = <1>;
-        };
-        pins2 {
-            u-boot,dm-pre-reloc;
-            pinmux = <STM32_PINMUX('C', 12, AF12)>; /* SDMMC1_CK */
-            bias-pull-up;
-            drive-push-pull;
             slew-rate = <3>;
         };
     };
-    sdmmc2_pins_mx: sdmmc2_mx-0 {
+    sdmmc2_pins_mx: sdmmc2_mx@0 {
         u-boot,dm-pre-reloc;
-        pins1 {
+        pins {
             u-boot,dm-pre-reloc;
             pinmux = <STM32_PINMUX('B', 3, AF9)>, /* SDMMC2_D2 */
                      <STM32_PINMUX('B', 4, AF9)>, /* SDMMC2_D3 */
                      <STM32_PINMUX('B', 14, AF9)>, /* SDMMC2_D0 */
                      <STM32_PINMUX('B', 15, AF9)>, /* SDMMC2_D1 */
+                     <STM32_PINMUX('E', 3, AF9)>, /* SDMMC2_CK */
                      <STM32_PINMUX('G', 6, AF10)>; /* SDMMC2_CMD */
             bias-pull-up;
             drive-push-pull;
-            slew-rate = <1>;
-        };
-        pins2 {
-            u-boot,dm-pre-reloc;
-            pinmux = <STM32_PINMUX('E', 3, AF9)>; /* SDMMC2_CK */
-            bias-pull-up;
-            drive-push-pull;
             slew-rate = <3>;
         };
     };
-    tim1_pwm_pins_mx: tim1_pwm_mx-0 {
-        pins {
-            pinmux = <STM32_PINMUX('A', 9, AF1)>; /* TIM1_CH2 */
-            bias-disable;
-            drive-push-pull;
-            slew-rate = <0>;
-        };
-    };
-    tim4_pwm_pins_mx: tim4_pwm_mx-0 {
+    spi2_pins_mx: spi2_mx@0 {
         pins {
-            pinmux = <STM32_PINMUX('D', 14, AF2)>; /* TIM4_CH3 */
+            pinmux = <STM32_PINMUX('A', 9, AF5)>, /* SPI2_SCK */
+                     <STM32_PINMUX('C', 2, AF5)>, /* SPI2_MISO */
+                     <STM32_PINMUX('C', 3, AF5)>; /* SPI2_MOSI */
             bias-disable;
             drive-push-pull;
-            slew-rate = <0>;
+            slew-rate = <1>;
         };
     };
-    uart4_pins_mx: uart4_mx-0 {
+    uart4_pins_mx: uart4_mx@0 {
         u-boot,dm-pre-reloc;
         pins1 {
             u-boot,dm-pre-reloc;
@@ -278,7 +224,29 @@
             bias-pull-up;
         };
     };
-    usart2_pins_mx: usart2_mx-0 {
+    uart8_pins_mx: uart8_mx@0 {
+        pins1 {
+            pinmux = <STM32_PINMUX('E', 1, AF8)>; /* UART8_TX */
+            bias-pull-up;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+        pins2 {
+            pinmux = <STM32_PINMUX('D', 14, AF8)>; /* UART8_CTS */
+            bias-pull-down;
+        };
+        pins3 {
+            pinmux = <STM32_PINMUX('G', 7, AF8)>; /* UART8_RTS */
+            bias-pull-down;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+        pins4 {
+            pinmux = <STM32_PINMUX('E', 0, AF8)>; /* UART8_RX */
+            bias-pull-up;
+        };
+    };
+    usart2_pins_mx: usart2_mx@0 {
         pins1 {
             pinmux = <STM32_PINMUX('D', 5, AF7)>; /* USART2_TX */
             bias-pull-up;
@@ -286,17 +254,43 @@
             slew-rate = <0>;
         };
         pins2 {
+            pinmux = <STM32_PINMUX('D', 3, AF7)>; /* USART2_CTS */
+            bias-pull-down;
+        };
+        pins3 {
             pinmux = <STM32_PINMUX('D', 4, AF7)>; /* USART2_RTS */
             bias-pull-down;
             drive-push-pull;
             slew-rate = <0>;
         };
-        pins3 {
+        pins4 {
             pinmux = <STM32_PINMUX('D', 6, AF7)>; /* USART2_RX */
             bias-pull-up;
         };
     };
-    usart6_pins_mx: usart6_mx-0 {
+    usart3_pins_mx: usart3_mx@0 {
+        pins1 {
+            pinmux = <STM32_PINMUX('D', 8, AF7)>; /* USART3_TX */
+            bias-pull-up;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+        pins2 {
+            pinmux = <STM32_PINMUX('D', 11, AF7)>; /* USART3_CTS */
+            bias-pull-down;
+        };
+        pins3 {
+            pinmux = <STM32_PINMUX('D', 12, AF7)>; /* USART3_RTS */
+            bias-pull-down;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+        pins4 {
+            pinmux = <STM32_PINMUX('D', 9, AF7)>; /* USART3_RX */
+            bias-pull-up;
+        };
+    };
+    usart6_pins_mx: usart6_mx@0 {
         pins1 {
             pinmux = <STM32_PINMUX('G', 14, AF7)>; /* USART6_TX */
             bias-pull-up;
@@ -308,63 +302,64 @@
             bias-pull-up;
         };
     };
-    usb_otg_hs_pins_mx: usb_otg_hs_mx-0 {
+    usb_otg_hs_pins_mx: usb_otg_hs_mx@0 {
         u-boot,dm-pre-reloc;
         pins {
             u-boot,dm-pre-reloc;
             pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
         };
     };
-    adc_sleep_pins_mx: adc_sleep_mx-0 {
+    adc_sleep_pins_mx: adc_sleep_mx@0 {
         pins {
             pinmux = <STM32_PINMUX('A', 0, ANALOG)>, /* ADC1_INP16 */
                      <STM32_PINMUX('B', 1, ANALOG)>; /* ADC1_INP5 */
         };
     };
-    eth1_sleep_pins_mx: eth1_sleep_mx-0 {
-        pins {
-            pinmux = <STM32_PINMUX('A', 2, ANALOG)>, /* ETH1_MDIO */
-                     <STM32_PINMUX('A', 7, ANALOG)>, /* ETH1_CRS_DV */
-                     <STM32_PINMUX('B', 11, ANALOG)>, /* ETH1_TX_EN */
-                     <STM32_PINMUX('B', 12, ANALOG)>, /* ETH1_TXD0 */
-                     <STM32_PINMUX('B', 13, ANALOG)>, /* ETH1_TXD1 */
-                     <STM32_PINMUX('C', 1, ANALOG)>, /* ETH1_MDC */
-                     <STM32_PINMUX('C', 4, ANALOG)>, /* ETH1_RXD0 */
-                     <STM32_PINMUX('C', 5, ANALOG)>, /* ETH1_RXD1 */
-                     <STM32_PINMUX('G', 8, ANALOG)>; /* ETH1_CLK */
-        };
-    };
-    fdcan1_sleep_pins_mx: fdcan1_sleep_mx-0 {
-        pins {
-            pinmux = <STM32_PINMUX('D', 0, ANALOG)>, /* FDCAN1_RX */
-                     <STM32_PINMUX('D', 1, ANALOG)>; /* FDCAN1_TX */
+    eth1_sleep_pins_mx: eth1_sleep_mx@0 {
+        pins1 {
+            pinmux = <STM32_PINMUX('A', 2, AF11)>, /* ETH1_MDIO */
+                     <STM32_PINMUX('B', 11, AF11)>, /* ETH1_TX_EN */
+                     <STM32_PINMUX('B', 12, AF11)>, /* ETH1_TXD0 */
+                     <STM32_PINMUX('B', 13, AF11)>, /* ETH1_TXD1 */
+                     <STM32_PINMUX('C', 1, AF11)>, /* ETH1_MDC */
+                     <STM32_PINMUX('G', 8, AF2)>; /* ETH1_CLK */
+            bias-disable;
+            drive-push-pull;
+            slew-rate = <3>;
+        };
+        pins2 {
+            pinmux = <STM32_PINMUX('A', 7, AF11)>, /* ETH1_CRS_DV */
+                     <STM32_PINMUX('C', 4, AF11)>, /* ETH1_RXD0 */
+                     <STM32_PINMUX('C', 5, AF11)>; /* ETH1_RXD1 */
+            bias-disable;
         };
     };
-    i2c2_sleep_pins_mx: i2c2_sleep_mx-0 {
+    fdcan1_sleep_pins_mx: fdcan1_sleep_mx@0 {
         pins {
-            pinmux = <STM32_PINMUX('D', 7, ANALOG)>, /* I2C2_SCL */
-                     <STM32_PINMUX('G', 15, ANALOG)>; /* I2C2_SDA */
+            pinmux = <STM32_PINMUX('D', 0, ANALOG)>, /* FDCAN1_RX */
+                     <STM32_PINMUX('D', 1, ANALOG)>; /* FDCAN1_TX */
         };
     };
-    i2c4_sleep_pins_mx: i2c4_sleep_mx-0 {
+    i2c2_sleep_pins_mx: i2c2_sleep_mx@0 {
         pins {
-            pinmux = <STM32_PINMUX('B', 7, ANALOG)>, /* I2C4_SDA */
-                     <STM32_PINMUX('E', 2, ANALOG)>; /* I2C4_SCL */
+            pinmux = <STM32_PINMUX('D', 7, AF4)>, /* I2C2_SCL */
+                     <STM32_PINMUX('G', 15, AF4)>; /* I2C2_SDA */
+            bias-disable;
+            drive-open-drain;
+            slew-rate = <0>;
         };
     };
-    i2s2_sleep_pins_mx: i2s2_sleep_mx-0 {
+    i2c4_sleep_pins_mx: i2c4_sleep_mx@0 {
         pins {
-            pinmux = <STM32_PINMUX('A', 11, ANALOG)>, /* I2S2_WS */
-                     <STM32_PINMUX('C', 2, ANALOG)>, /* I2S2_SDI */
-                     <STM32_PINMUX('C', 3, ANALOG)>, /* I2S2_SDO */
-                     <STM32_PINMUX('D', 3, ANALOG)>, /* I2S2_CK */
-                     <STM32_PINMUX('E', 1, ANALOG)>; /* I2S2_MCK */
+            pinmux = <STM32_PINMUX('B', 7, AF6)>, /* I2C4_SDA */
+                     <STM32_PINMUX('E', 2, AF4)>; /* I2C4_SCL */
+            bias-disable;
+            drive-open-drain;
+            slew-rate = <0>;
         };
     };
-    ltdc_sleep_pins_mx: ltdc_sleep_mx-0 {
-        u-boot,dm-pre-reloc;
+    ltdc_sleep_pins_mx: ltdc_sleep_mx@0 {
         pins {
-            u-boot,dm-pre-reloc;
             pinmux = <STM32_PINMUX('A', 1, ANALOG)>, /* LTDC_R2 */
                      <STM32_PINMUX('A', 3, ANALOG)>, /* LTDC_B5 */
                      <STM32_PINMUX('A', 4, ANALOG)>, /* LTDC_VSYNC */
@@ -372,7 +367,6 @@
                      <STM32_PINMUX('A', 6, ANALOG)>, /* LTDC_G2 */
                      <STM32_PINMUX('A', 8, ANALOG)>, /* LTDC_R6 */
                      <STM32_PINMUX('A', 12, ANALOG)>, /* LTDC_R5 */
-                     <STM32_PINMUX('A', 15, ANALOG)>, /* LTDC_R1 */
                      <STM32_PINMUX('B', 0, ANALOG)>, /* LTDC_R3 */
                      <STM32_PINMUX('B', 5, ANALOG)>, /* LTDC_G7 */
                      <STM32_PINMUX('B', 8, ANALOG)>, /* LTDC_B6 */
@@ -381,21 +375,16 @@
                      <STM32_PINMUX('C', 6, ANALOG)>, /* LTDC_HSYNC */
                      <STM32_PINMUX('C', 7, ANALOG)>, /* LTDC_G6 */
                      <STM32_PINMUX('D', 10, ANALOG)>, /* LTDC_B3 */
-                     <STM32_PINMUX('E', 4, ANALOG)>, /* LTDC_B0 */
-                     <STM32_PINMUX('E', 5, ANALOG)>, /* LTDC_G0 */
-                     <STM32_PINMUX('E', 6, ANALOG)>, /* LTDC_G1 */
                      <STM32_PINMUX('E', 11, ANALOG)>, /* LTDC_G3 */
                      <STM32_PINMUX('E', 12, ANALOG)>, /* LTDC_B4 */
                      <STM32_PINMUX('E', 13, ANALOG)>, /* LTDC_DE */
                      <STM32_PINMUX('E', 14, ANALOG)>, /* LTDC_CLK */
                      <STM32_PINMUX('E', 15, ANALOG)>, /* LTDC_R7 */
                      <STM32_PINMUX('F', 11, ANALOG)>, /* LTDC_G5 */
-                     <STM32_PINMUX('G', 10, ANALOG)>, /* LTDC_B2 */
-                     <STM32_PINMUX('G', 12, ANALOG)>, /* LTDC_B1 */
-                     <STM32_PINMUX('G', 13, ANALOG)>; /* LTDC_R0 */
+                     <STM32_PINMUX('G', 10, ANALOG)>; /* LTDC_B2 */
         };
     };
-    quadspi_sleep_pins_mx: quadspi_sleep_mx-0 {
+    quadspi_sleep_pins_mx: quadspi_sleep_mx@0 {
         u-boot,dm-pre-reloc;
         pins {
             u-boot,dm-pre-reloc;
@@ -412,7 +401,7 @@
                      <STM32_PINMUX('F', 10, ANALOG)>; /* QUADSPI_CLK */
         };
     };
-    sdmmc1_sleep_pins_mx: sdmmc1_sleep_mx-0 {
+    sdmmc1_sleep_pins_mx: sdmmc1_sleep_mx@0 {
         u-boot,dm-pre-reloc;
         pins {
             u-boot,dm-pre-reloc;
@@ -424,7 +413,7 @@
                      <STM32_PINMUX('D', 2, ANALOG)>; /* SDMMC1_CMD */
         };
     };
-    sdmmc2_sleep_pins_mx: sdmmc2_sleep_mx-0 {
+    sdmmc2_sleep_pins_mx: sdmmc2_sleep_mx@0 {
         u-boot,dm-pre-reloc;
         pins {
             u-boot,dm-pre-reloc;
@@ -436,38 +425,110 @@
                      <STM32_PINMUX('G', 6, ANALOG)>; /* SDMMC2_CMD */
         };
     };
-    tim1_pwm_sleep_pins_mx: tim1_pwm_sleep_mx-0 {
+    spi2_sleep_pins_mx: spi2_sleep_mx@0 {
         pins {
-            pinmux = <STM32_PINMUX('A', 9, ANALOG)>; /* TIM1_CH2 */
-        };
-    };
-    tim4_pwm_sleep_pins_mx: tim4_pwm_sleep_mx-0 {
-        pins {
-            pinmux = <STM32_PINMUX('D', 14, ANALOG)>; /* TIM4_CH3 */
+            pinmux = <STM32_PINMUX('A', 9, AF5)>, /* SPI2_SCK */
+                     <STM32_PINMUX('C', 2, AF5)>, /* SPI2_MISO */
+                     <STM32_PINMUX('C', 3, AF5)>; /* SPI2_MOSI */
+            bias-disable;
+            drive-push-pull;
+            slew-rate = <1>;
         };
     };
-    uart4_sleep_pins_mx: uart4_sleep_mx-0 {
+    uart4_sleep_pins_mx: uart4_sleep_mx@0 {
         u-boot,dm-pre-reloc;
-        pins {
+        pins1 {
+            u-boot,dm-pre-reloc;
+            pinmux = <STM32_PINMUX('G', 11, AF6)>; /* UART4_TX */
+            bias-pull-up;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+        pins2 {
             u-boot,dm-pre-reloc;
-            pinmux = <STM32_PINMUX('B', 2, ANALOG)>, /* UART4_RX */
-                     <STM32_PINMUX('G', 11, ANALOG)>; /* UART4_TX */
+            pinmux = <STM32_PINMUX('B', 2, AF8)>; /* UART4_RX */
+            bias-pull-up;
         };
     };
-    usart2_sleep_pins_mx: usart2_sleep_mx-0 {
-        pins {
-            pinmux = <STM32_PINMUX('D', 4, ANALOG)>, /* USART2_RTS */
-                     <STM32_PINMUX('D', 5, ANALOG)>, /* USART2_TX */
-                     <STM32_PINMUX('D', 6, ANALOG)>; /* USART2_RX */
+    uart8_sleep_pins_mx: uart8_sleep_mx@0 {
+        pins1 {
+            pinmux = <STM32_PINMUX('E', 1, AF8)>; /* UART8_TX */
+            bias-pull-up;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+        pins2 {
+            pinmux = <STM32_PINMUX('D', 14, AF8)>; /* UART8_CTS */
+            bias-pull-down;
+        };
+        pins3 {
+            pinmux = <STM32_PINMUX('G', 7, AF8)>; /* UART8_RTS */
+            bias-pull-down;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+        pins4 {
+            pinmux = <STM32_PINMUX('E', 0, AF8)>; /* UART8_RX */
+            bias-pull-up;
         };
     };
-    usart6_sleep_pins_mx: usart6_sleep_mx-0 {
-        pins {
-            pinmux = <STM32_PINMUX('G', 9, ANALOG)>, /* USART6_RX */
-                     <STM32_PINMUX('G', 14, ANALOG)>; /* USART6_TX */
+    usart2_sleep_pins_mx: usart2_sleep_mx@0 {
+        pins1 {
+            pinmux = <STM32_PINMUX('D', 5, AF7)>; /* USART2_TX */
+            bias-pull-up;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+        pins2 {
+            pinmux = <STM32_PINMUX('D', 3, AF7)>; /* USART2_CTS */
+            bias-pull-down;
+        };
+        pins3 {
+            pinmux = <STM32_PINMUX('D', 4, AF7)>; /* USART2_RTS */
+            bias-pull-down;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+        pins4 {
+            pinmux = <STM32_PINMUX('D', 6, AF7)>; /* USART2_RX */
+            bias-pull-up;
         };
     };
-    usb_otg_hs_sleep_pins_mx: usb_otg_hs_sleep_mx-0 {
+    usart3_sleep_pins_mx: usart3_sleep_mx@0 {
+        pins1 {
+            pinmux = <STM32_PINMUX('D', 8, AF7)>; /* USART3_TX */
+            bias-pull-up;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+        pins2 {
+            pinmux = <STM32_PINMUX('D', 11, AF7)>; /* USART3_CTS */
+            bias-pull-down;
+        };
+        pins3 {
+            pinmux = <STM32_PINMUX('D', 12, AF7)>; /* USART3_RTS */
+            bias-pull-down;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+        pins4 {
+            pinmux = <STM32_PINMUX('D', 9, AF7)>; /* USART3_RX */
+            bias-pull-up;
+        };
+    };
+    usart6_sleep_pins_mx: usart6_sleep_mx@0 {
+        pins1 {
+            pinmux = <STM32_PINMUX('G', 14, AF7)>; /* USART6_TX */
+            bias-pull-up;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+        pins2 {
+            pinmux = <STM32_PINMUX('G', 9, AF7)>; /* USART6_RX */
+            bias-pull-up;
+        };
+    };
+    usb_otg_hs_sleep_pins_mx: usb_otg_hs_sleep_mx@0 {
         u-boot,dm-pre-reloc;
         pins {
             u-boot,dm-pre-reloc;
@@ -476,319 +537,136 @@
     };
 };
 
-&m4_rproc{
-    mboxes = <&ipcc 0>, <&ipcc 1>, <&ipcc 2>;
-    mbox-names = "vq0", "vq1", "shutdown";
-    recovery;
-    status = "okay";
-
-    /* USER CODE BEGIN m4_rproc */
-    /* USER CODE END m4_rproc */
-};
-
-&adc{
+&adc {
     pinctrl-names = "default", "sleep";
     pinctrl-0 = <&adc_pins_mx>;
     pinctrl-1 = <&adc_sleep_pins_mx>;
     status = "okay";
-
-    /* USER CODE BEGIN adc */
-    /* USER CODE END adc */
-};
-
-&bsec{
-    status = "okay";
-
-    /* USER CODE BEGIN bsec */
-    /* USER CODE END bsec */
-};
-
-&crc1{
-    status = "okay";
-
-    /* USER CODE BEGIN crc1 */
-    /* USER CODE END crc1 */
-};
-
-&cryp1{
-    status = "okay";
-
-    /* USER CODE BEGIN cryp1 */
-    /* USER CODE END cryp1 */
-};
-
-&dts{
-    status = "okay";
-
-    /* USER CODE BEGIN dts */
-    /* USER CODE END dts */
 };
 
-&ethernet0{
+&ethernet0 {
     pinctrl-names = "default", "sleep";
     pinctrl-0 = <&eth1_pins_mx>;
     pinctrl-1 = <&eth1_sleep_pins_mx>;
     status = "okay";
-
-    /* USER CODE BEGIN ethernet0 */
-    /* USER CODE END ethernet0 */
-};
-
-&gpu{
-    status = "okay";
-
-    /* USER CODE BEGIN gpu */
-    /* USER CODE END gpu */
-};
-
-&hash1{
-    status = "okay";
-
-    /* USER CODE BEGIN hash1 */
-    /* USER CODE END hash1 */
 };
 
-&hsem{
+&m_can1 {
+    pinctrl-names = "default", "sleep";
+    pinctrl-0 = <&fdcan1_pins_mx>;
+    pinctrl-1 = <&fdcan1_sleep_pins_mx>;
     status = "okay";
-
-    /* USER CODE BEGIN hsem */
-    /* USER CODE END hsem */
 };
 
-&i2c2{
+&i2c2 {
     pinctrl-names = "default", "sleep";
     pinctrl-0 = <&i2c2_pins_mx>;
     pinctrl-1 = <&i2c2_sleep_pins_mx>;
     status = "okay";
-
-    /* USER CODE BEGIN i2c2 */
-    /* USER CODE END i2c2 */
 };
 
-&i2c4{
+&i2c4 {
     pinctrl-names = "default", "sleep";
     pinctrl-0 = <&i2c4_pins_mx>;
     pinctrl-1 = <&i2c4_sleep_pins_mx>;
     status = "okay";
-
-    /* USER CODE BEGIN i2c4 */
-    /* USER CODE END i2c4 */
-};
-
-&i2s2{
-    pinctrl-names = "default", "sleep";
-    pinctrl-0 = <&i2s2_pins_mx>;
-    pinctrl-1 = <&i2s2_sleep_pins_mx>;
-    status = "okay";
-
-    /* USER CODE BEGIN i2s2 */
-    /* USER CODE END i2s2 */
-};
-
-&ipcc{
-    status = "okay";
-
-    /* USER CODE BEGIN ipcc */
-    /* USER CODE END ipcc */
 };
 
-&ltdc{
-    u-boot,dm-pre-reloc;
+&ltdc {
     pinctrl-names = "default", "sleep";
     pinctrl-0 = <&ltdc_pins_mx>;
     pinctrl-1 = <&ltdc_sleep_pins_mx>;
     status = "okay";
-
-    /* USER CODE BEGIN ltdc */
-    /* USER CODE END ltdc */
 };
 
-&m_can1{
-    pinctrl-names = "default", "sleep";
-    pinctrl-0 = <&fdcan1_pins_mx>;
-    pinctrl-1 = <&fdcan1_sleep_pins_mx>;
-    status = "okay";
-
-    /* USER CODE BEGIN m_can1 */
-    /* USER CODE END m_can1 */
-};
-
-&qspi{
+&qspi {
     u-boot,dm-pre-reloc;
     pinctrl-names = "default", "sleep";
     pinctrl-0 = <&quadspi_pins_mx>;
     pinctrl-1 = <&quadspi_sleep_pins_mx>;
     status = "okay";
-
-    /* USER CODE BEGIN qspi */
-    /* USER CODE END qspi */
 };
 
-&rcc{
+&rcc {
     u-boot,dm-pre-reloc;
     status = "okay";
-
-    /* USER CODE BEGIN rcc */
-    /* USER CODE END rcc */
 };
 
-&rng1{
+&rtc {
     status = "okay";
-
-    /* USER CODE BEGIN rng1 */
-    /* USER CODE END rng1 */
-};
-
-&rtc{
-    status = "okay";
-
-    /* USER CODE BEGIN rtc */
-    /* USER CODE END rtc */
 };
 
-&sdmmc1{
+&sdmmc1 {
     u-boot,dm-pre-reloc;
     pinctrl-names = "default", "sleep";
     pinctrl-0 = <&sdmmc1_pins_mx>;
     pinctrl-1 = <&sdmmc1_sleep_pins_mx>;
     status = "okay";
-
-    /* USER CODE BEGIN sdmmc1 */
-    /* USER CODE END sdmmc1 */
 };
 
-&sdmmc2{
+&sdmmc2 {
     u-boot,dm-pre-reloc;
     pinctrl-names = "default", "sleep";
     pinctrl-0 = <&sdmmc2_pins_mx>;
     pinctrl-1 = <&sdmmc2_sleep_pins_mx>;
     status = "okay";
-
-    /* USER CODE BEGIN sdmmc2 */
-    /* USER CODE END sdmmc2 */
 };
 
-&timers1{
-    status = "okay";
-
-    /* USER CODE BEGIN timers1 */
-    /* USER CODE END timers1 */
-
-    pwm{
-        pinctrl-names = "default", "sleep";
-        pinctrl-0 = <&tim1_pwm_pins_mx>;
-        pinctrl-1 = <&tim1_pwm_sleep_pins_mx>;
-        status = "okay";
-
-        /* USER CODE BEGIN timers1_pwm */
-        /* USER CODE END timers1_pwm */
-    };
-};
-
-&timers4{
+&spi2 {
+    pinctrl-names = "default", "sleep";
+    pinctrl-0 = <&spi2_pins_mx>;
+    pinctrl-1 = <&spi2_sleep_pins_mx>;
     status = "okay";
-
-    /* USER CODE BEGIN timers4 */
-    /* USER CODE END timers4 */
-
-    pwm{
-        pinctrl-names = "default", "sleep";
-        pinctrl-0 = <&tim4_pwm_pins_mx>;
-        pinctrl-1 = <&tim4_pwm_sleep_pins_mx>;
-        status = "okay";
-
-        /* USER CODE BEGIN timers4_pwm */
-        /* USER CODE END timers4_pwm */
-    };
 };
 
-&uart4{
+&uart4 {
     u-boot,dm-pre-reloc;
     pinctrl-names = "default", "sleep";
     pinctrl-0 = <&uart4_pins_mx>;
     pinctrl-1 = <&uart4_sleep_pins_mx>;
     status = "okay";
-
-    /* USER CODE BEGIN uart4 */
-    /* USER CODE END uart4 */
 };
 
-&usart2{
+&uart8 {
     pinctrl-names = "default", "sleep";
-    pinctrl-0 = <&usart2_pins_mx>;
-    pinctrl-1 = <&usart2_sleep_pins_mx>;
+    pinctrl-0 = <&uart8_pins_mx>;
+    pinctrl-1 = <&uart8_sleep_pins_mx>;
     status = "okay";
-
-    /* USER CODE BEGIN usart2 */
-    /* USER CODE END usart2 */
 };
 
-&usart6{
+&usart2 {
     pinctrl-names = "default", "sleep";
-    pinctrl-0 = <&usart6_pins_mx>;
-    pinctrl-1 = <&usart6_sleep_pins_mx>;
+    pinctrl-0 = <&usart2_pins_mx>;
+    pinctrl-1 = <&usart2_sleep_pins_mx>;
     status = "okay";
-
-    /* USER CODE BEGIN usart6 */
-    /* USER CODE END usart6 */
 };
 
-&usbh_ehci{
+&usart3 {
+    pinctrl-names = "default", "sleep";
+    pinctrl-0 = <&usart3_pins_mx>;
+    pinctrl-1 = <&usart3_sleep_pins_mx>;
     status = "okay";
-
-    /* USER CODE BEGIN usbh_ehci */
-    /* USER CODE END usbh_ehci */
 };
 
-&usbh_ohci{
+&usart6 {
+    pinctrl-names = "default", "sleep";
+    pinctrl-0 = <&usart6_pins_mx>;
+    pinctrl-1 = <&usart6_sleep_pins_mx>;
     status = "okay";
-
-    /* USER CODE BEGIN usbh_ohci */
-    /* USER CODE END usbh_ohci */
 };
 
-&usbotg_hs{
+&usbotg_hs {
     u-boot,dm-pre-reloc;
     pinctrl-names = "default", "sleep";
     pinctrl-0 = <&usb_otg_hs_pins_mx>;
     pinctrl-1 = <&usb_otg_hs_sleep_pins_mx>;
     status = "okay";
-
-    /* USER CODE BEGIN usbotg_hs */
-    /* USER CODE END usbotg_hs */
-};
-
-&usbphyc{
-    u-boot,dm-pre-reloc;
-    status = "okay";
-
-    /* USER CODE BEGIN usbphyc */
-    /* USER CODE END usbphyc */
-};
-
-&usbphyc_port0{
-    u-boot,dm-pre-reloc;
-    status = "okay";
-
-    /* USER CODE BEGIN usbphyc_port0 */
-    /* USER CODE END usbphyc_port0 */
-};
-
-&usbphyc_port1{
-    u-boot,dm-pre-reloc;
-    status = "okay";
-
-    /* USER CODE BEGIN usbphyc_port1 */
-    /* USER CODE END usbphyc_port1 */
 };
 
-&vrefbuf{
+&usbh_ohci {
     status = "okay";
-
-    /* USER CODE BEGIN vrefbuf */
-    /* USER CODE END vrefbuf */
 };
 
-/* USER CODE BEGIN addons */
-/* USER CODE END addons */
+/* USER CODE BEGIN dts_soc */
+/* USER CODE END dts_soc */
 
diff --git a/recipes-kernel/linux/linux-stm32mp/stm32mp157c-t1000-k-mx.dts b/recipes-kernel/linux/linux-stm32mp/stm32mp157c-t1000-k-mx.dts
deleted file mode 100644
index 52b8368243f58fffb0585cd1c22cc679d364d37e..0000000000000000000000000000000000000000
--- a/recipes-kernel/linux/linux-stm32mp/stm32mp157c-t1000-k-mx.dts
+++ /dev/null
@@ -1,879 +0,0 @@
-/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
-/*
- * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
- * Author: STM32CubeMX code generation for STMicroelectronics.
- */
-
-/dts-v1/;
-#include "stm32mp157c.dtsi"
-#include "stm32mp157c-m4-srm.dtsi"
-#include "stm32mp157cad-pinctrl.dtsi"
-
-/* USER CODE BEGIN includes */
-/* USER CODE END includes */
-
-/ {
-	model = "STMicroelectronics custom STM32CubeMX board";
-	compatible = "st,stm32mp157c-t1000-k-mx", "st,stm32mp157";
-
-	memory@c0000000 {
-		reg = <0xc0000000 0x20000000>;
-
-		/* USER CODE BEGIN memory */
-		/* USER CODE END memory */
-	};
-
-	reserved-memory {
-		#address-cells = <1>;
-		#size-cells = <1>;
-		ranges;
-
-		/* USER CODE BEGIN reserved-memory */
-		/* USER CODE END reserved-memory */
-
-		gpu_reserved: gpu@dc000000 {
-			reg = <0xdc000000 0x4000000>;
-			no-map;
-		};
-	};
-
-	/* USER CODE BEGIN root */
-	/* USER CODE END root */
-
-	clocks {
-		/* USER CODE BEGIN clocks */
-		/* USER CODE END clocks */
-
-		clk_hsi: clk-hsi {
-			clock-frequency = <64000000>;
-		};
-
-		clk_csi: clk-csi {
-			clock-frequency = <4000000>;
-		};
-
-		clk_lse: clk-lse {
-			clock-frequency = <32768>;
-		};
-
-		clk_hse: clk-hse {
-			clock-frequency = <24000000>;
-		};
-	};
-
-}; /*root*/
-
-&pinctrl {
-	u-boot,dm-pre-reloc;
-
-	adc_pins_mx: adc_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 0, ANALOG)>, /* ADC1_INP16 */
-					 <STM32_PINMUX('B', 1, ANALOG)>; /* ADC1_INP5 */
-		};
-	};
-
-	adc_sleep_pins_mx: adc_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 0, ANALOG)>, /* ADC1_INP16 */
-					 <STM32_PINMUX('B', 1, ANALOG)>; /* ADC1_INP5 */
-		};
-	};
-
-	eth1_pins_mx: eth1_mx-0 {
-		pins1 {
-			pinmux = <STM32_PINMUX('A', 2, AF11)>; /* ETH1_MDIO */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-		pins2 {
-			pinmux = <STM32_PINMUX('A', 7, AF11)>, /* ETH1_CRS_DV */
-					 <STM32_PINMUX('C', 4, AF11)>, /* ETH1_RXD0 */
-					 <STM32_PINMUX('C', 5, AF11)>; /* ETH1_RXD1 */
-			bias-disable;
-		};
-		pins3 {
-			pinmux = <STM32_PINMUX('B', 11, AF11)>; /* ETH1_TX_EN */
-		};
-		pins4 {
-			pinmux = <STM32_PINMUX('B', 12, AF11)>, /* ETH1_TXD0 */
-					 <STM32_PINMUX('B', 13, AF11)>, /* ETH1_TXD1 */
-					 <STM32_PINMUX('C', 1, AF11)>, /* ETH1_MDC */
-					 <STM32_PINMUX('G', 8, AF2)>; /* ETH1_CLK */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-	};
-
-	eth1_sleep_pins_mx: eth1_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 2, ANALOG)>, /* ETH1_MDIO */
-					 <STM32_PINMUX('A', 7, ANALOG)>, /* ETH1_CRS_DV */
-					 <STM32_PINMUX('B', 11, ANALOG)>, /* ETH1_TX_EN */
-					 <STM32_PINMUX('B', 12, ANALOG)>, /* ETH1_TXD0 */
-					 <STM32_PINMUX('B', 13, ANALOG)>, /* ETH1_TXD1 */
-					 <STM32_PINMUX('C', 1, ANALOG)>, /* ETH1_MDC */
-					 <STM32_PINMUX('C', 4, ANALOG)>, /* ETH1_RXD0 */
-					 <STM32_PINMUX('C', 5, ANALOG)>, /* ETH1_RXD1 */
-					 <STM32_PINMUX('G', 8, ANALOG)>; /* ETH1_CLK */
-		};
-	};
-
-	fdcan1_pins_mx: fdcan1_mx-0 {
-		pins1 {
-			pinmux = <STM32_PINMUX('D', 0, AF9)>; /* FDCAN1_RX */
-			bias-disable;
-		};
-		pins2 {
-			pinmux = <STM32_PINMUX('D', 1, AF9)>; /* FDCAN1_TX */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-	};
-
-	fdcan1_sleep_pins_mx: fdcan1_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('D', 0, ANALOG)>, /* FDCAN1_RX */
-					 <STM32_PINMUX('D', 1, ANALOG)>; /* FDCAN1_TX */
-		};
-	};
-
-	i2c2_pins_mx: i2c2_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('D', 7, AF4)>, /* I2C2_SCL */
-					 <STM32_PINMUX('G', 15, AF4)>; /* I2C2_SDA */
-			bias-disable;
-			drive-open-drain;
-			slew-rate = <0>;
-		};
-	};
-
-	i2c2_sleep_pins_mx: i2c2_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('D', 7, ANALOG)>, /* I2C2_SCL */
-					 <STM32_PINMUX('G', 15, ANALOG)>; /* I2C2_SDA */
-		};
-	};
-
-	i2c4_pins_mx: i2c4_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('B', 7, AF6)>, /* I2C4_SDA */
-					 <STM32_PINMUX('E', 2, AF4)>; /* I2C4_SCL */
-			bias-disable;
-			drive-open-drain;
-			slew-rate = <0>;
-		};
-	};
-
-	i2c4_sleep_pins_mx: i2c4_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('B', 7, ANALOG)>, /* I2C4_SDA */
-					 <STM32_PINMUX('E', 2, ANALOG)>; /* I2C4_SCL */
-		};
-	};
-
-	ltdc_pins_mx: ltdc_mx-0 {
-		pins1 {
-			pinmux = <STM32_PINMUX('A', 1, AF14)>, /* LTDC_R2 */
-					 <STM32_PINMUX('A', 3, AF14)>, /* LTDC_B5 */
-					 <STM32_PINMUX('A', 4, AF14)>, /* LTDC_VSYNC */
-					 <STM32_PINMUX('A', 5, AF14)>, /* LTDC_R4 */
-					 <STM32_PINMUX('A', 6, AF14)>, /* LTDC_G2 */
-					 <STM32_PINMUX('A', 8, AF14)>, /* LTDC_R6 */
-					 <STM32_PINMUX('A', 12, AF14)>, /* LTDC_R5 */
-					 <STM32_PINMUX('A', 15, AF14)>, /* LTDC_R1 */
-					 <STM32_PINMUX('B', 0, AF9)>, /* LTDC_R3 */
-					 <STM32_PINMUX('B', 5, AF14)>, /* LTDC_G7 */
-					 <STM32_PINMUX('B', 8, AF14)>, /* LTDC_B6 */
-					 <STM32_PINMUX('B', 9, AF14)>, /* LTDC_B7 */
-					 <STM32_PINMUX('B', 10, AF14)>, /* LTDC_G4 */
-					 <STM32_PINMUX('C', 6, AF14)>, /* LTDC_HSYNC */
-					 <STM32_PINMUX('C', 7, AF14)>, /* LTDC_G6 */
-					 <STM32_PINMUX('D', 10, AF14)>, /* LTDC_B3 */
-					 <STM32_PINMUX('E', 4, AF14)>, /* LTDC_B0 */
-					 <STM32_PINMUX('E', 5, AF14)>, /* LTDC_G0 */
-					 <STM32_PINMUX('E', 6, AF14)>, /* LTDC_G1 */
-					 <STM32_PINMUX('E', 11, AF14)>, /* LTDC_G3 */
-					 <STM32_PINMUX('E', 12, AF14)>, /* LTDC_B4 */
-					 <STM32_PINMUX('E', 13, AF14)>, /* LTDC_DE */
-					 <STM32_PINMUX('E', 15, AF14)>, /* LTDC_R7 */
-					 <STM32_PINMUX('F', 11, AF14)>, /* LTDC_G5 */
-					 <STM32_PINMUX('G', 10, AF14)>, /* LTDC_B2 */
-					 <STM32_PINMUX('G', 12, AF14)>, /* LTDC_B1 */
-					 <STM32_PINMUX('G', 13, AF14)>; /* LTDC_R0 */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-		pins2 {
-			pinmux = <STM32_PINMUX('E', 14, AF14)>; /* LTDC_CLK */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-	};
-
-	ltdc_sleep_pins_mx: ltdc_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 1, ANALOG)>, /* LTDC_R2 */
-					 <STM32_PINMUX('A', 3, ANALOG)>, /* LTDC_B5 */
-					 <STM32_PINMUX('A', 4, ANALOG)>, /* LTDC_VSYNC */
-					 <STM32_PINMUX('A', 5, ANALOG)>, /* LTDC_R4 */
-					 <STM32_PINMUX('A', 6, ANALOG)>, /* LTDC_G2 */
-					 <STM32_PINMUX('A', 8, ANALOG)>, /* LTDC_R6 */
-					 <STM32_PINMUX('A', 12, ANALOG)>, /* LTDC_R5 */
-					 <STM32_PINMUX('A', 15, ANALOG)>, /* LTDC_R1 */
-					 <STM32_PINMUX('B', 0, ANALOG)>, /* LTDC_R3 */
-					 <STM32_PINMUX('B', 5, ANALOG)>, /* LTDC_G7 */
-					 <STM32_PINMUX('B', 8, ANALOG)>, /* LTDC_B6 */
-					 <STM32_PINMUX('B', 9, ANALOG)>, /* LTDC_B7 */
-					 <STM32_PINMUX('B', 10, ANALOG)>, /* LTDC_G4 */
-					 <STM32_PINMUX('C', 6, ANALOG)>, /* LTDC_HSYNC */
-					 <STM32_PINMUX('C', 7, ANALOG)>, /* LTDC_G6 */
-					 <STM32_PINMUX('D', 10, ANALOG)>, /* LTDC_B3 */
-					 <STM32_PINMUX('E', 4, ANALOG)>, /* LTDC_B0 */
-					 <STM32_PINMUX('E', 5, ANALOG)>, /* LTDC_G0 */
-					 <STM32_PINMUX('E', 6, ANALOG)>, /* LTDC_G1 */
-					 <STM32_PINMUX('E', 11, ANALOG)>, /* LTDC_G3 */
-					 <STM32_PINMUX('E', 12, ANALOG)>, /* LTDC_B4 */
-					 <STM32_PINMUX('E', 13, ANALOG)>, /* LTDC_DE */
-					 <STM32_PINMUX('E', 14, ANALOG)>, /* LTDC_CLK */
-					 <STM32_PINMUX('E', 15, ANALOG)>, /* LTDC_R7 */
-					 <STM32_PINMUX('F', 11, ANALOG)>, /* LTDC_G5 */
-					 <STM32_PINMUX('G', 10, ANALOG)>, /* LTDC_B2 */
-					 <STM32_PINMUX('G', 12, ANALOG)>, /* LTDC_B1 */
-					 <STM32_PINMUX('G', 13, ANALOG)>; /* LTDC_R0 */
-		};
-	};
-
-	quadspi_pins_mx: quadspi_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 6, AF10)>, /* QUADSPI_BK1_NCS */
-					 <STM32_PINMUX('C', 0, AF10)>; /* QUADSPI_BK2_NCS */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('E', 7, AF10)>, /* QUADSPI_BK2_IO0 */
-					 <STM32_PINMUX('E', 8, AF10)>, /* QUADSPI_BK2_IO1 */
-					 <STM32_PINMUX('E', 9, AF10)>, /* QUADSPI_BK2_IO2 */
-					 <STM32_PINMUX('E', 10, AF10)>, /* QUADSPI_BK2_IO3 */
-					 <STM32_PINMUX('F', 6, AF9)>, /* QUADSPI_BK1_IO3 */
-					 <STM32_PINMUX('F', 7, AF9)>, /* QUADSPI_BK1_IO2 */
-					 <STM32_PINMUX('F', 8, AF10)>, /* QUADSPI_BK1_IO0 */
-					 <STM32_PINMUX('F', 9, AF10)>; /* QUADSPI_BK1_IO1 */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins3 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('F', 10, AF9)>; /* QUADSPI_CLK */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <2>;
-		};
-	};
-
-	quadspi_sleep_pins_mx: quadspi_sleep_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 6, ANALOG)>, /* QUADSPI_BK1_NCS */
-					 <STM32_PINMUX('C', 0, ANALOG)>, /* QUADSPI_BK2_NCS */
-					 <STM32_PINMUX('E', 7, ANALOG)>, /* QUADSPI_BK2_IO0 */
-					 <STM32_PINMUX('E', 8, ANALOG)>, /* QUADSPI_BK2_IO1 */
-					 <STM32_PINMUX('E', 9, ANALOG)>, /* QUADSPI_BK2_IO2 */
-					 <STM32_PINMUX('E', 10, ANALOG)>, /* QUADSPI_BK2_IO3 */
-					 <STM32_PINMUX('F', 6, ANALOG)>, /* QUADSPI_BK1_IO3 */
-					 <STM32_PINMUX('F', 7, ANALOG)>, /* QUADSPI_BK1_IO2 */
-					 <STM32_PINMUX('F', 8, ANALOG)>, /* QUADSPI_BK1_IO0 */
-					 <STM32_PINMUX('F', 9, ANALOG)>, /* QUADSPI_BK1_IO1 */
-					 <STM32_PINMUX('F', 10, ANALOG)>; /* QUADSPI_CLK */
-		};
-	};
-
-	rtc_pins_mx: rtc_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('C', 13, ANALOG)>; /* RTC_LSCO */
-		};
-	};
-
-	rtc_sleep_pins_mx: rtc_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('C', 13, ANALOG)>; /* RTC_LSCO */
-		};
-	};
-
-	sdmmc1_pins_mx: sdmmc1_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
-					 <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
-					 <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
-					 <STM32_PINMUX('C', 11, AF12)>, /* SDMMC1_D3 */
-					 <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 12, AF12)>; /* SDMMC1_CK */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-	};
-
-	sdmmc1_opendrain_pins_mx: sdmmc1_opendrain_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
-					 <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
-					 <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
-					 <STM32_PINMUX('C', 11, AF12)>; /* SDMMC1_D3 */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 12, AF12)>; /* SDMMC1_CK */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins3 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
-			bias-pull-up;
-			drive-open-drain;
-			slew-rate = <1>;
-		};
-	};
-
-	sdmmc1_sleep_pins_mx: sdmmc1_sleep_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 8, ANALOG)>, /* SDMMC1_D0 */
-					 <STM32_PINMUX('C', 9, ANALOG)>, /* SDMMC1_D1 */
-					 <STM32_PINMUX('C', 10, ANALOG)>, /* SDMMC1_D2 */
-					 <STM32_PINMUX('C', 11, ANALOG)>, /* SDMMC1_D3 */
-					 <STM32_PINMUX('C', 12, ANALOG)>, /* SDMMC1_CK */
-					 <STM32_PINMUX('D', 2, ANALOG)>; /* SDMMC1_CMD */
-		};
-	};
-
-	sdmmc2_pins_mx: sdmmc2_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 3, AF9)>, /* SDMMC2_D2 */
-					 <STM32_PINMUX('B', 4, AF9)>, /* SDMMC2_D3 */
-					 <STM32_PINMUX('B', 14, AF9)>, /* SDMMC2_D0 */
-					 <STM32_PINMUX('B', 15, AF9)>, /* SDMMC2_D1 */
-					 <STM32_PINMUX('G', 6, AF10)>; /* SDMMC2_CMD */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('E', 3, AF9)>; /* SDMMC2_CK */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-	};
-
-	sdmmc2_opendrain_pins_mx: sdmmc2_opendrain_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 3, AF9)>, /* SDMMC2_D2 */
-					 <STM32_PINMUX('B', 4, AF9)>, /* SDMMC2_D3 */
-					 <STM32_PINMUX('B', 14, AF9)>, /* SDMMC2_D0 */
-					 <STM32_PINMUX('B', 15, AF9)>; /* SDMMC2_D1 */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('E', 3, AF9)>; /* SDMMC2_CK */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins3 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('G', 6, AF10)>; /* SDMMC2_CMD */
-			bias-pull-up;
-			drive-open-drain;
-			slew-rate = <1>;
-		};
-	};
-
-	sdmmc2_sleep_pins_mx: sdmmc2_sleep_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 3, ANALOG)>, /* SDMMC2_D2 */
-					 <STM32_PINMUX('B', 4, ANALOG)>, /* SDMMC2_D3 */
-					 <STM32_PINMUX('B', 14, ANALOG)>, /* SDMMC2_D0 */
-					 <STM32_PINMUX('B', 15, ANALOG)>, /* SDMMC2_D1 */
-					 <STM32_PINMUX('E', 3, ANALOG)>, /* SDMMC2_CK */
-					 <STM32_PINMUX('G', 6, ANALOG)>; /* SDMMC2_CMD */
-		};
-	};
-
-	tim1_pwm_pins_mx: tim1_pwm_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 9, AF1)>; /* TIM1_CH2 */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-	};
-
-	tim1_pwm_sleep_pins_mx: tim1_pwm_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 9, ANALOG)>; /* TIM1_CH2 */
-		};
-	};
-
-	tim4_pwm_pins_mx: tim4_pwm_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('D', 14, AF2)>; /* TIM4_CH3 */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-	};
-
-	tim4_pwm_sleep_pins_mx: tim4_pwm_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('D', 14, ANALOG)>; /* TIM4_CH3 */
-		};
-	};
-
-	uart4_pins_mx: uart4_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 2, AF8)>; /* UART4_RX */
-			bias-pull-up;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('G', 11, AF6)>; /* UART4_TX */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-	};
-
-	uart4_sleep_pins_mx: uart4_sleep_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 2, ANALOG)>, /* UART4_RX */
-					 <STM32_PINMUX('G', 11, ANALOG)>; /* UART4_TX */
-		};
-	};
-
-	usart2_pins_mx: usart2_mx-0 {
-		pins1 {
-			pinmux = <STM32_PINMUX('D', 4, AF7)>; /* USART2_RTS */
-			bias-pull-down;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-		pins2 {
-			pinmux = <STM32_PINMUX('D', 5, AF7)>; /* USART2_TX */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-		pins3 {
-			pinmux = <STM32_PINMUX('D', 6, AF7)>; /* USART2_RX */
-			bias-pull-up;
-		};
-	};
-
-	usart2_sleep_pins_mx: usart2_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('D', 4, ANALOG)>, /* USART2_RTS */
-					 <STM32_PINMUX('D', 5, ANALOG)>, /* USART2_TX */
-					 <STM32_PINMUX('D', 6, ANALOG)>; /* USART2_RX */
-		};
-	};
-
-	usart3_pins_mx: usart3_mx-0 {
-		pins1 {
-			pinmux = <STM32_PINMUX('D', 9, AF7)>, /* USART3_RX */
-					 <STM32_PINMUX('D', 11, AF7)>; /* USART3_CTS */
-			bias-disable;
-		};
-		pins2 {
-			pinmux = <STM32_PINMUX('D', 8, AF7)>, /* USART3_TX */
-					 <STM32_PINMUX('D', 12, AF7)>; /* USART3_RTS */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-	};
-
-	usart3_sleep_pins_mx: usart3_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('D', 8, ANALOG)>, /* USART3_TX */
-					 <STM32_PINMUX('D', 9, ANALOG)>, /* USART3_RX */
-					 <STM32_PINMUX('D', 11, ANALOG)>, /* USART3_CTS */
-					 <STM32_PINMUX('D', 12, ANALOG)>; /* USART3_RTS */
-		};
-	};
-
-	usb_otg_hs_pins_mx: usb_otg_hs_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
-		};
-	};
-
-	usb_otg_hs_sleep_pins_mx: usb_otg_hs_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
-		};
-	};
-
-	/* USER CODE BEGIN pinctrl */
-	/* USER CODE END pinctrl */
-};
-
-&pinctrl_z {
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN pinctrl_z */
-	/* USER CODE END pinctrl_z */
-};
-
-&m4_rproc{
-	mboxes = <&ipcc 0>, <&ipcc 1>, <&ipcc 2>;
-	mbox-names = "vq0", "vq1", "shutdown";
-	recovery;
-	status = "okay";
-
-	/* USER CODE BEGIN m4_rproc */
-	/* USER CODE END m4_rproc */
-};
-
-&adc{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&adc_pins_mx>;
-	pinctrl-1 = <&adc_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN adc */
-	/* USER CODE END adc */
-};
-
-&bsec{
-	status = "okay";
-
-	/* USER CODE BEGIN bsec */
-	/* USER CODE END bsec */
-};
-
-&crc1{
-	status = "okay";
-
-	/* USER CODE BEGIN crc1 */
-	/* USER CODE END crc1 */
-};
-
-&cryp1{
-	status = "okay";
-
-	/* USER CODE BEGIN cryp1 */
-	/* USER CODE END cryp1 */
-};
-
-&dts{
-	status = "okay";
-
-	/* USER CODE BEGIN dts */
-	/* USER CODE END dts */
-};
-
-&ethernet0{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&eth1_pins_mx>;
-	pinctrl-1 = <&eth1_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN ethernet0 */
-	/* USER CODE END ethernet0 */
-};
-
-&gpu{
-	status = "okay";
-
-	/* USER CODE BEGIN gpu */
-	/* USER CODE END gpu */
-};
-
-&hash1{
-	status = "okay";
-
-	/* USER CODE BEGIN hash1 */
-	/* USER CODE END hash1 */
-};
-
-&hsem{
-	status = "okay";
-
-	/* USER CODE BEGIN hsem */
-	/* USER CODE END hsem */
-};
-
-&i2c2{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&i2c2_pins_mx>;
-	pinctrl-1 = <&i2c2_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN i2c2 */
-	/* USER CODE END i2c2 */
-};
-
-&i2c4{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&i2c4_pins_mx>;
-	pinctrl-1 = <&i2c4_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN i2c4 */
-	/* USER CODE END i2c4 */
-};
-
-&ipcc{
-	status = "okay";
-
-	/* USER CODE BEGIN ipcc */
-	/* USER CODE END ipcc */
-};
-
-&ltdc{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&ltdc_pins_mx>;
-	pinctrl-1 = <&ltdc_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN ltdc */
-	/* USER CODE END ltdc */
-};
-
-&m_can1{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&fdcan1_pins_mx>;
-	pinctrl-1 = <&fdcan1_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN m_can1 */
-	/* USER CODE END m_can1 */
-};
-
-&qspi{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&quadspi_pins_mx>;
-	pinctrl-1 = <&quadspi_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN qspi */
-	/* USER CODE END qspi */
-};
-
-&rcc{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN rcc */
-	/* USER CODE END rcc */
-};
-
-&rng1{
-	status = "okay";
-
-	/* USER CODE BEGIN rng1 */
-	/* USER CODE END rng1 */
-};
-
-&rtc{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&rtc_pins_mx>;
-	pinctrl-1 = <&rtc_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN rtc */
-	/* USER CODE END rtc */
-};
-
-&sdmmc1{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "opendrain", "sleep";
-	pinctrl-0 = <&sdmmc1_pins_mx>;
-	pinctrl-1 = <&sdmmc1_opendrain_pins_mx>;
-	pinctrl-2 = <&sdmmc1_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN sdmmc1 */
-	/* USER CODE END sdmmc1 */
-};
-
-&sdmmc2{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "opendrain", "sleep";
-	pinctrl-0 = <&sdmmc2_pins_mx>;
-	pinctrl-1 = <&sdmmc2_opendrain_pins_mx>;
-	pinctrl-2 = <&sdmmc2_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN sdmmc2 */
-	/* USER CODE END sdmmc2 */
-};
-
-&timers1{
-	status = "okay";
-
-	/* USER CODE BEGIN timers1 */
-	/* USER CODE END timers1 */
-
-	pwm{
-		pinctrl-names = "default", "sleep";
-		pinctrl-0 = <&tim1_pwm_pins_mx>;
-		pinctrl-1 = <&tim1_pwm_sleep_pins_mx>;
-		status = "okay";
-
-		/* USER CODE BEGIN timers1_pwm */
-		/* USER CODE END timers1_pwm */
-	};
-};
-
-&timers4{
-	status = "okay";
-
-	/* USER CODE BEGIN timers4 */
-	/* USER CODE END timers4 */
-
-	pwm{
-		pinctrl-names = "default", "sleep";
-		pinctrl-0 = <&tim4_pwm_pins_mx>;
-		pinctrl-1 = <&tim4_pwm_sleep_pins_mx>;
-		status = "okay";
-
-		/* USER CODE BEGIN timers4_pwm */
-		/* USER CODE END timers4_pwm */
-	};
-};
-
-&uart4{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&uart4_pins_mx>;
-	pinctrl-1 = <&uart4_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN uart4 */
-	/* USER CODE END uart4 */
-};
-
-&usart2{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&usart2_pins_mx>;
-	pinctrl-1 = <&usart2_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN usart2 */
-	/* USER CODE END usart2 */
-};
-
-&usart3{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&usart3_pins_mx>;
-	pinctrl-1 = <&usart3_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN usart3 */
-	/* USER CODE END usart3 */
-};
-
-&usbh_ehci{
-	status = "okay";
-
-	/* USER CODE BEGIN usbh_ehci */
-	/* USER CODE END usbh_ehci */
-};
-
-&usbh_ohci{
-	status = "okay";
-
-	/* USER CODE BEGIN usbh_ohci */
-	/* USER CODE END usbh_ohci */
-};
-
-&usbotg_hs{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&usb_otg_hs_pins_mx>;
-	pinctrl-1 = <&usb_otg_hs_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN usbotg_hs */
-	/* USER CODE END usbotg_hs */
-};
-
-&usbphyc{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc */
-	/* USER CODE END usbphyc */
-};
-
-&usbphyc_port0{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc_port0 */
-	/* USER CODE END usbphyc_port0 */
-};
-
-&usbphyc_port1{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc_port1 */
-	/* USER CODE END usbphyc_port1 */
-};
-
-&vrefbuf{
-	status = "okay";
-
-	/* USER CODE BEGIN vrefbuf */
-	/* USER CODE END vrefbuf */
-};
-
-/* USER CODE BEGIN addons */
-/* USER CODE END addons */
-
diff --git a/recipes-kernel/linux/linux-stm32mp/stm32mp157c-t1000-mini-mx.dts b/recipes-kernel/linux/linux-stm32mp/stm32mp157c-t1000-mini-mx.dts
new file mode 100644
index 0000000000000000000000000000000000000000..d18dafcc949bb896b764a702e6a1138b26a8c576
--- /dev/null
+++ b/recipes-kernel/linux/linux-stm32mp/stm32mp157c-t1000-mini-mx.dts
@@ -0,0 +1,451 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
+/*
+ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved
+ * Author: STM32CubeMX code generation for STMicroelectronics.
+ */
+
+/dts-v1/;
+#include "stm32mp157c.dtsi"
+#include "stm32mp157cad-pinctrl.dtsi"
+
+/* USER CODE BEGIN dts_include */
+/* USER CODE END dts_include */
+
+/ {
+    model = "STMicroelectronics custom STM32CubeMX board";
+	compatible = "st,stm32mp157c-t1000-mini-mx", "st,stm32mp157";
+
+	memory {
+		reg = <0xC0000000 0x20000000>;
+	};
+
+	/* USER CODE BEGIN root_prop */
+	/* USER CODE END root_prop */
+
+    clocks {
+        u-boot,dm-pre-reloc;
+        clk_hsi: clk-hsi {
+            #clock-cells = <0>;
+            compatible = "fixed-clock";
+            clock-frequency = <64000000>;
+            u-boot,dm-pre-reloc;
+        };
+        clk_usbo_48m: ck_usbo_48m {
+            #clock-cells = <0>;
+            compatible = "fixed-clock";
+            clock-frequency = <48000000>;
+            u-boot,dm-pre-reloc;
+        };
+        clk_lse: clk-lse {
+            #clock-cells = <0>;
+            compatible = "fixed-clock";
+            clock-frequency = <32768>;
+            u-boot,dm-pre-reloc;
+        };
+        clk_hse: clk-hse {
+            #clock-cells = <0>;
+            compatible = "fixed-clock";
+            clock-frequency = <24000000>;
+            u-boot,dm-pre-reloc;
+        };
+    };
+	/* USER CODE BEGIN root_subnodes */
+	/* USER CODE END root_subnodes */
+
+	/* USER CODE BEGIN root_board */
+	/* USER CODE END root_board */
+
+	/* USER CODE BEGIN root_platform */
+	/* USER CODE END root_platform */
+
+}; /*root*/
+
+/* USER CODE BEGIN dts_board */
+/* USER CODE END dts_board */
+
+&pinctrl {
+    u-boot,dm-pre-reloc;
+    adc_pins_mx: adc_mx@0 {
+        pins {
+            pinmux = <STM32_PINMUX('A', 0, ANALOG)>, /* ADC1_INP16 */
+                     <STM32_PINMUX('A', 6, ANALOG)>, /* ADC1_INP3 */
+                     <STM32_PINMUX('B', 1, ANALOG)>, /* ADC1_INP5 */
+                     <STM32_PINMUX('F', 11, ANALOG)>; /* ADC1_INP2 */
+        };
+    };
+    eth1_pins_mx: eth1_mx@0 {
+        pins1 {
+            pinmux = <STM32_PINMUX('A', 2, AF11)>, /* ETH1_MDIO */
+                     <STM32_PINMUX('B', 11, AF11)>, /* ETH1_TX_EN */
+                     <STM32_PINMUX('B', 12, AF11)>, /* ETH1_TXD0 */
+                     <STM32_PINMUX('B', 13, AF11)>, /* ETH1_TXD1 */
+                     <STM32_PINMUX('C', 1, AF11)>, /* ETH1_MDC */
+                     <STM32_PINMUX('G', 8, AF2)>; /* ETH1_CLK */
+            bias-disable;
+            drive-push-pull;
+            slew-rate = <3>;
+        };
+        pins2 {
+            pinmux = <STM32_PINMUX('A', 7, AF11)>, /* ETH1_CRS_DV */
+                     <STM32_PINMUX('C', 4, AF11)>, /* ETH1_RXD0 */
+                     <STM32_PINMUX('C', 5, AF11)>; /* ETH1_RXD1 */
+            bias-disable;
+        };
+    };
+    i2c2_pins_mx: i2c2_mx@0 {
+        pins {
+            pinmux = <STM32_PINMUX('D', 7, AF4)>, /* I2C2_SCL */
+                     <STM32_PINMUX('G', 15, AF4)>; /* I2C2_SDA */
+            bias-disable;
+            drive-open-drain;
+            slew-rate = <0>;
+        };
+    };
+    i2c4_pins_mx: i2c4_mx@0 {
+        pins {
+            pinmux = <STM32_PINMUX('B', 7, AF6)>, /* I2C4_SDA */
+                     <STM32_PINMUX('E', 2, AF4)>; /* I2C4_SCL */
+            bias-disable;
+            drive-open-drain;
+            slew-rate = <0>;
+        };
+    };
+    quadspi_pins_mx: quadspi_mx@0 {
+        u-boot,dm-pre-reloc;
+        pins {
+            u-boot,dm-pre-reloc;
+            pinmux = <STM32_PINMUX('B', 6, AF10)>, /* QUADSPI_BK1_NCS */
+                     <STM32_PINMUX('C', 0, AF10)>, /* QUADSPI_BK2_NCS */
+                     <STM32_PINMUX('E', 7, AF10)>, /* QUADSPI_BK2_IO0 */
+                     <STM32_PINMUX('E', 8, AF10)>, /* QUADSPI_BK2_IO1 */
+                     <STM32_PINMUX('E', 9, AF10)>, /* QUADSPI_BK2_IO2 */
+                     <STM32_PINMUX('E', 10, AF10)>, /* QUADSPI_BK2_IO3 */
+                     <STM32_PINMUX('F', 6, AF9)>, /* QUADSPI_BK1_IO3 */
+                     <STM32_PINMUX('F', 7, AF9)>, /* QUADSPI_BK1_IO2 */
+                     <STM32_PINMUX('F', 8, AF10)>, /* QUADSPI_BK1_IO0 */
+                     <STM32_PINMUX('F', 9, AF10)>, /* QUADSPI_BK1_IO1 */
+                     <STM32_PINMUX('F', 10, AF9)>; /* QUADSPI_CLK */
+            bias-disable;
+            drive-push-pull;
+            slew-rate = <3>;
+        };
+    };
+    sdmmc1_pins_mx: sdmmc1_mx@0 {
+        u-boot,dm-pre-reloc;
+        pins {
+            u-boot,dm-pre-reloc;
+            pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
+                     <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
+                     <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
+                     <STM32_PINMUX('C', 11, AF12)>, /* SDMMC1_D3 */
+                     <STM32_PINMUX('C', 12, AF12)>, /* SDMMC1_CK */
+                     <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
+            bias-pull-up;
+            drive-push-pull;
+            slew-rate = <3>;
+        };
+    };
+    spi2_pins_mx: spi2_mx@0 {
+        pins {
+            pinmux = <STM32_PINMUX('A', 9, AF5)>, /* SPI2_SCK */
+                     <STM32_PINMUX('C', 2, AF5)>, /* SPI2_MISO */
+                     <STM32_PINMUX('C', 3, AF5)>; /* SPI2_MOSI */
+            bias-disable;
+            drive-push-pull;
+            slew-rate = <1>;
+        };
+    };
+    tim1_pwm_pins_mx: tim1_pwm_mx@0 {
+        pins {
+            pinmux = <STM32_PINMUX('A', 8, AF1)>, /* TIM1_CH1 */
+                     <STM32_PINMUX('E', 11, AF1)>, /* TIM1_CH2 */
+                     <STM32_PINMUX('E', 13, AF1)>, /* TIM1_CH3 */
+                     <STM32_PINMUX('E', 14, AF1)>; /* TIM1_CH4 */
+            bias-disable;
+            drive-push-pull;
+            slew-rate = <3>;
+        };
+    };
+    uart4_pins_mx: uart4_mx@0 {
+        u-boot,dm-pre-reloc;
+        pins1 {
+            u-boot,dm-pre-reloc;
+            pinmux = <STM32_PINMUX('G', 11, AF6)>; /* UART4_TX */
+            bias-pull-up;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+        pins2 {
+            u-boot,dm-pre-reloc;
+            pinmux = <STM32_PINMUX('B', 2, AF8)>; /* UART4_RX */
+            bias-pull-up;
+        };
+    };
+    usart2_pins_mx: usart2_mx@0 {
+        pins1 {
+            pinmux = <STM32_PINMUX('D', 5, AF7)>; /* USART2_TX */
+            bias-pull-up;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+        pins2 {
+            pinmux = <STM32_PINMUX('D', 3, AF7)>; /* USART2_CTS */
+            bias-pull-down;
+        };
+        pins3 {
+            pinmux = <STM32_PINMUX('D', 4, AF7)>; /* USART2_RTS */
+            bias-pull-down;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+        pins4 {
+            pinmux = <STM32_PINMUX('D', 6, AF7)>; /* USART2_RX */
+            bias-pull-up;
+        };
+    };
+    usb_otg_hs_pins_mx: usb_otg_hs_mx@0 {
+        u-boot,dm-pre-reloc;
+        pins {
+            u-boot,dm-pre-reloc;
+            pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
+        };
+    };
+    adc_sleep_pins_mx: adc_sleep_mx@0 {
+        pins {
+            pinmux = <STM32_PINMUX('A', 0, ANALOG)>, /* ADC1_INP16 */
+                     <STM32_PINMUX('A', 6, ANALOG)>, /* ADC1_INP3 */
+                     <STM32_PINMUX('B', 1, ANALOG)>, /* ADC1_INP5 */
+                     <STM32_PINMUX('F', 11, ANALOG)>; /* ADC1_INP2 */
+        };
+    };
+    eth1_sleep_pins_mx: eth1_sleep_mx@0 {
+        pins1 {
+            pinmux = <STM32_PINMUX('A', 2, AF11)>, /* ETH1_MDIO */
+                     <STM32_PINMUX('B', 11, AF11)>, /* ETH1_TX_EN */
+                     <STM32_PINMUX('B', 12, AF11)>, /* ETH1_TXD0 */
+                     <STM32_PINMUX('B', 13, AF11)>, /* ETH1_TXD1 */
+                     <STM32_PINMUX('C', 1, AF11)>, /* ETH1_MDC */
+                     <STM32_PINMUX('G', 8, AF2)>; /* ETH1_CLK */
+            bias-disable;
+            drive-push-pull;
+            slew-rate = <3>;
+        };
+        pins2 {
+            pinmux = <STM32_PINMUX('A', 7, AF11)>, /* ETH1_CRS_DV */
+                     <STM32_PINMUX('C', 4, AF11)>, /* ETH1_RXD0 */
+                     <STM32_PINMUX('C', 5, AF11)>; /* ETH1_RXD1 */
+            bias-disable;
+        };
+    };
+    i2c2_sleep_pins_mx: i2c2_sleep_mx@0 {
+        pins {
+            pinmux = <STM32_PINMUX('D', 7, AF4)>, /* I2C2_SCL */
+                     <STM32_PINMUX('G', 15, AF4)>; /* I2C2_SDA */
+            bias-disable;
+            drive-open-drain;
+            slew-rate = <0>;
+        };
+    };
+    i2c4_sleep_pins_mx: i2c4_sleep_mx@0 {
+        pins {
+            pinmux = <STM32_PINMUX('B', 7, AF6)>, /* I2C4_SDA */
+                     <STM32_PINMUX('E', 2, AF4)>; /* I2C4_SCL */
+            bias-disable;
+            drive-open-drain;
+            slew-rate = <0>;
+        };
+    };
+    quadspi_sleep_pins_mx: quadspi_sleep_mx@0 {
+        u-boot,dm-pre-reloc;
+        pins {
+            u-boot,dm-pre-reloc;
+            pinmux = <STM32_PINMUX('B', 6, ANALOG)>, /* QUADSPI_BK1_NCS */
+                     <STM32_PINMUX('C', 0, ANALOG)>, /* QUADSPI_BK2_NCS */
+                     <STM32_PINMUX('E', 7, ANALOG)>, /* QUADSPI_BK2_IO0 */
+                     <STM32_PINMUX('E', 8, ANALOG)>, /* QUADSPI_BK2_IO1 */
+                     <STM32_PINMUX('E', 9, ANALOG)>, /* QUADSPI_BK2_IO2 */
+                     <STM32_PINMUX('E', 10, ANALOG)>, /* QUADSPI_BK2_IO3 */
+                     <STM32_PINMUX('F', 6, ANALOG)>, /* QUADSPI_BK1_IO3 */
+                     <STM32_PINMUX('F', 7, ANALOG)>, /* QUADSPI_BK1_IO2 */
+                     <STM32_PINMUX('F', 8, ANALOG)>, /* QUADSPI_BK1_IO0 */
+                     <STM32_PINMUX('F', 9, ANALOG)>, /* QUADSPI_BK1_IO1 */
+                     <STM32_PINMUX('F', 10, ANALOG)>; /* QUADSPI_CLK */
+        };
+    };
+    sdmmc1_sleep_pins_mx: sdmmc1_sleep_mx@0 {
+        u-boot,dm-pre-reloc;
+        pins {
+            u-boot,dm-pre-reloc;
+            pinmux = <STM32_PINMUX('C', 8, ANALOG)>, /* SDMMC1_D0 */
+                     <STM32_PINMUX('C', 9, ANALOG)>, /* SDMMC1_D1 */
+                     <STM32_PINMUX('C', 10, ANALOG)>, /* SDMMC1_D2 */
+                     <STM32_PINMUX('C', 11, ANALOG)>, /* SDMMC1_D3 */
+                     <STM32_PINMUX('C', 12, ANALOG)>, /* SDMMC1_CK */
+                     <STM32_PINMUX('D', 2, ANALOG)>; /* SDMMC1_CMD */
+        };
+    };
+    spi2_sleep_pins_mx: spi2_sleep_mx@0 {
+        pins {
+            pinmux = <STM32_PINMUX('A', 9, AF5)>, /* SPI2_SCK */
+                     <STM32_PINMUX('C', 2, AF5)>, /* SPI2_MISO */
+                     <STM32_PINMUX('C', 3, AF5)>; /* SPI2_MOSI */
+            bias-disable;
+            drive-push-pull;
+            slew-rate = <1>;
+        };
+    };
+    tim1_pwm_sleep_pins_mx: tim1_pwm_sleep_mx@0 {
+        pins {
+            pinmux = <STM32_PINMUX('A', 8, ANALOG)>, /* TIM1_CH1 */
+                     <STM32_PINMUX('E', 11, ANALOG)>, /* TIM1_CH2 */
+                     <STM32_PINMUX('E', 13, ANALOG)>, /* TIM1_CH3 */
+                     <STM32_PINMUX('E', 14, ANALOG)>; /* TIM1_CH4 */
+        };
+    };
+    uart4_sleep_pins_mx: uart4_sleep_mx@0 {
+        u-boot,dm-pre-reloc;
+        pins1 {
+            u-boot,dm-pre-reloc;
+            pinmux = <STM32_PINMUX('G', 11, AF6)>; /* UART4_TX */
+            bias-pull-up;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+        pins2 {
+            u-boot,dm-pre-reloc;
+            pinmux = <STM32_PINMUX('B', 2, AF8)>; /* UART4_RX */
+            bias-pull-up;
+        };
+    };
+    usart2_sleep_pins_mx: usart2_sleep_mx@0 {
+        pins1 {
+            pinmux = <STM32_PINMUX('D', 5, AF7)>; /* USART2_TX */
+            bias-pull-up;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+        pins2 {
+            pinmux = <STM32_PINMUX('D', 3, AF7)>; /* USART2_CTS */
+            bias-pull-down;
+        };
+        pins3 {
+            pinmux = <STM32_PINMUX('D', 4, AF7)>; /* USART2_RTS */
+            bias-pull-down;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+        pins4 {
+            pinmux = <STM32_PINMUX('D', 6, AF7)>; /* USART2_RX */
+            bias-pull-up;
+        };
+    };
+    usb_otg_hs_sleep_pins_mx: usb_otg_hs_sleep_mx@0 {
+        u-boot,dm-pre-reloc;
+        pins {
+            u-boot,dm-pre-reloc;
+            pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
+        };
+    };
+};
+
+&adc {
+    pinctrl-names = "default", "sleep";
+    pinctrl-0 = <&adc_pins_mx>;
+    pinctrl-1 = <&adc_sleep_pins_mx>;
+    status = "okay";
+};
+
+&ethernet0 {
+    pinctrl-names = "default", "sleep";
+    pinctrl-0 = <&eth1_pins_mx>;
+    pinctrl-1 = <&eth1_sleep_pins_mx>;
+    status = "okay";
+};
+
+&i2c2 {
+    pinctrl-names = "default", "sleep";
+    pinctrl-0 = <&i2c2_pins_mx>;
+    pinctrl-1 = <&i2c2_sleep_pins_mx>;
+    status = "okay";
+};
+
+&i2c4 {
+    pinctrl-names = "default", "sleep";
+    pinctrl-0 = <&i2c4_pins_mx>;
+    pinctrl-1 = <&i2c4_sleep_pins_mx>;
+    status = "okay";
+};
+
+&qspi {
+    u-boot,dm-pre-reloc;
+    pinctrl-names = "default", "sleep";
+    pinctrl-0 = <&quadspi_pins_mx>;
+    pinctrl-1 = <&quadspi_sleep_pins_mx>;
+    status = "okay";
+};
+
+&rcc {
+    u-boot,dm-pre-reloc;
+    status = "okay";
+};
+
+&rtc {
+    status = "okay";
+};
+
+&sdmmc1 {
+    u-boot,dm-pre-reloc;
+    pinctrl-names = "default", "sleep";
+    pinctrl-0 = <&sdmmc1_pins_mx>;
+    pinctrl-1 = <&sdmmc1_sleep_pins_mx>;
+    status = "okay";
+};
+
+&spi2 {
+    pinctrl-names = "default", "sleep";
+    pinctrl-0 = <&spi2_pins_mx>;
+    pinctrl-1 = <&spi2_sleep_pins_mx>;
+    status = "okay";
+};
+
+&timers1 {
+    status = "okay";
+
+    pwm{
+        pinctrl-names = "default", "sleep";
+        pinctrl-0 = <&tim1_pwm_pins_mx>;
+        pinctrl-1 = <&tim1_pwm_sleep_pins_mx>;
+        status = "okay";
+    };
+};
+
+&uart4 {
+    u-boot,dm-pre-reloc;
+    pinctrl-names = "default", "sleep";
+    pinctrl-0 = <&uart4_pins_mx>;
+    pinctrl-1 = <&uart4_sleep_pins_mx>;
+    status = "okay";
+};
+
+&usart2 {
+    pinctrl-names = "default", "sleep";
+    pinctrl-0 = <&usart2_pins_mx>;
+    pinctrl-1 = <&usart2_sleep_pins_mx>;
+    status = "okay";
+};
+
+&usbotg_hs {
+    u-boot,dm-pre-reloc;
+    pinctrl-names = "default", "sleep";
+    pinctrl-0 = <&usb_otg_hs_pins_mx>;
+    pinctrl-1 = <&usb_otg_hs_sleep_pins_mx>;
+    status = "okay";
+};
+
+&usbh_ohci {
+    status = "okay";
+};
+
+/* USER CODE BEGIN dts_soc */
+/* USER CODE END dts_soc */
+
diff --git a/recipes-kernel/linux/linux-stm32mp/stm32mp157c-t1000-mx.dts b/recipes-kernel/linux/linux-stm32mp/stm32mp157c-t1000-mx.dts
new file mode 100644
index 0000000000000000000000000000000000000000..f32e3ab8c2009ec6a1e24fc28cf48a2c1690342c
--- /dev/null
+++ b/recipes-kernel/linux/linux-stm32mp/stm32mp157c-t1000-mx.dts
@@ -0,0 +1,644 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
+/*
+ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved
+ * Author: STM32CubeMX code generation for STMicroelectronics.
+ */
+
+/dts-v1/;
+#include "stm32mp157c.dtsi"
+#include "stm32mp157cad-pinctrl.dtsi"
+
+/* USER CODE BEGIN dts_include */
+/* USER CODE END dts_include */
+
+/ {
+    model = "STMicroelectronics custom STM32CubeMX board";
+	compatible = "st,stm32mp157c-t1000-mx", "st,stm32mp157";
+
+	memory {
+		reg = <0xC0000000 0x20000000>;
+	};
+
+	/* USER CODE BEGIN root_prop */
+	/* USER CODE END root_prop */
+
+    clocks {
+        u-boot,dm-pre-reloc;
+        clk_hsi: clk-hsi {
+            #clock-cells = <0>;
+            compatible = "fixed-clock";
+            clock-frequency = <64000000>;
+            u-boot,dm-pre-reloc;
+        };
+        clk_usbo_48m: ck_usbo_48m {
+            #clock-cells = <0>;
+            compatible = "fixed-clock";
+            clock-frequency = <48000000>;
+            u-boot,dm-pre-reloc;
+        };
+        clk_lse: clk-lse {
+            #clock-cells = <0>;
+            compatible = "fixed-clock";
+            clock-frequency = <32768>;
+            u-boot,dm-pre-reloc;
+        };
+        clk_hse: clk-hse {
+            #clock-cells = <0>;
+            compatible = "fixed-clock";
+            clock-frequency = <24000000>;
+            u-boot,dm-pre-reloc;
+        };
+    };
+	/* USER CODE BEGIN root_subnodes */
+	/* USER CODE END root_subnodes */
+
+	/* USER CODE BEGIN root_board */
+	/* USER CODE END root_board */
+
+	/* USER CODE BEGIN root_platform */
+	/* USER CODE END root_platform */
+
+}; /*root*/
+
+/* USER CODE BEGIN dts_board */
+/* USER CODE END dts_board */
+
+&pinctrl {
+    u-boot,dm-pre-reloc;
+    adc_pins_mx: adc_mx@0 {
+        pins {
+            pinmux = <STM32_PINMUX('A', 0, ANALOG)>, /* ADC1_INP16 */
+                     <STM32_PINMUX('B', 1, ANALOG)>; /* ADC1_INP5 */
+        };
+    };
+    eth1_pins_mx: eth1_mx@0 {
+        pins1 {
+            pinmux = <STM32_PINMUX('A', 2, AF11)>, /* ETH1_MDIO */
+                     <STM32_PINMUX('B', 11, AF11)>, /* ETH1_TX_EN */
+                     <STM32_PINMUX('B', 12, AF11)>, /* ETH1_TXD0 */
+                     <STM32_PINMUX('B', 13, AF11)>, /* ETH1_TXD1 */
+                     <STM32_PINMUX('C', 1, AF11)>, /* ETH1_MDC */
+                     <STM32_PINMUX('G', 8, AF2)>; /* ETH1_CLK */
+            bias-disable;
+            drive-push-pull;
+            slew-rate = <3>;
+        };
+        pins2 {
+            pinmux = <STM32_PINMUX('A', 7, AF11)>, /* ETH1_CRS_DV */
+                     <STM32_PINMUX('C', 4, AF11)>, /* ETH1_RXD0 */
+                     <STM32_PINMUX('C', 5, AF11)>; /* ETH1_RXD1 */
+            bias-disable;
+        };
+    };
+    fdcan1_pins_mx: fdcan1_mx@0 {
+        pins1 {
+            pinmux = <STM32_PINMUX('D', 1, AF9)>; /* FDCAN1_TX */
+            bias-disable;
+            drive-push-pull;
+            slew-rate = <1>;
+        };
+        pins2 {
+            pinmux = <STM32_PINMUX('D', 0, AF9)>; /* FDCAN1_RX */
+            bias-disable;
+        };
+    };
+    i2c2_pins_mx: i2c2_mx@0 {
+        pins {
+            pinmux = <STM32_PINMUX('D', 7, AF4)>, /* I2C2_SCL */
+                     <STM32_PINMUX('G', 15, AF4)>; /* I2C2_SDA */
+            bias-disable;
+            drive-open-drain;
+            slew-rate = <0>;
+        };
+    };
+    i2c4_pins_mx: i2c4_mx@0 {
+        pins {
+            pinmux = <STM32_PINMUX('B', 7, AF6)>, /* I2C4_SDA */
+                     <STM32_PINMUX('E', 2, AF4)>; /* I2C4_SCL */
+            bias-disable;
+            drive-open-drain;
+            slew-rate = <0>;
+        };
+    };
+    ltdc_pins_mx: ltdc_mx@0 {
+        pins {
+            pinmux = <STM32_PINMUX('A', 1, AF14)>, /* LTDC_R2 */
+                     <STM32_PINMUX('A', 3, AF14)>, /* LTDC_B5 */
+                     <STM32_PINMUX('A', 4, AF14)>, /* LTDC_VSYNC */
+                     <STM32_PINMUX('A', 5, AF14)>, /* LTDC_R4 */
+                     <STM32_PINMUX('A', 6, AF14)>, /* LTDC_G2 */
+                     <STM32_PINMUX('A', 8, AF14)>, /* LTDC_R6 */
+                     <STM32_PINMUX('A', 12, AF14)>, /* LTDC_R5 */
+                     <STM32_PINMUX('B', 0, AF9)>, /* LTDC_R3 */
+                     <STM32_PINMUX('B', 5, AF14)>, /* LTDC_G7 */
+                     <STM32_PINMUX('B', 8, AF14)>, /* LTDC_B6 */
+                     <STM32_PINMUX('B', 9, AF14)>, /* LTDC_B7 */
+                     <STM32_PINMUX('B', 10, AF14)>, /* LTDC_G4 */
+                     <STM32_PINMUX('C', 6, AF14)>, /* LTDC_HSYNC */
+                     <STM32_PINMUX('C', 7, AF14)>, /* LTDC_G6 */
+                     <STM32_PINMUX('D', 10, AF14)>, /* LTDC_B3 */
+                     <STM32_PINMUX('E', 11, AF14)>, /* LTDC_G3 */
+                     <STM32_PINMUX('E', 12, AF14)>, /* LTDC_B4 */
+                     <STM32_PINMUX('E', 13, AF14)>, /* LTDC_DE */
+                     <STM32_PINMUX('E', 14, AF14)>, /* LTDC_CLK */
+                     <STM32_PINMUX('E', 15, AF14)>, /* LTDC_R7 */
+                     <STM32_PINMUX('F', 11, AF14)>, /* LTDC_G5 */
+                     <STM32_PINMUX('G', 10, AF14)>; /* LTDC_B2 */
+            bias-disable;
+            drive-push-pull;
+            slew-rate = <3>;
+        };
+    };
+    quadspi_pins_mx: quadspi_mx@0 {
+        u-boot,dm-pre-reloc;
+        pins {
+            u-boot,dm-pre-reloc;
+            pinmux = <STM32_PINMUX('B', 6, AF10)>, /* QUADSPI_BK1_NCS */
+                     <STM32_PINMUX('C', 0, AF10)>, /* QUADSPI_BK2_NCS */
+                     <STM32_PINMUX('E', 7, AF10)>, /* QUADSPI_BK2_IO0 */
+                     <STM32_PINMUX('E', 8, AF10)>, /* QUADSPI_BK2_IO1 */
+                     <STM32_PINMUX('E', 9, AF10)>, /* QUADSPI_BK2_IO2 */
+                     <STM32_PINMUX('E', 10, AF10)>, /* QUADSPI_BK2_IO3 */
+                     <STM32_PINMUX('F', 6, AF9)>, /* QUADSPI_BK1_IO3 */
+                     <STM32_PINMUX('F', 7, AF9)>, /* QUADSPI_BK1_IO2 */
+                     <STM32_PINMUX('F', 8, AF10)>, /* QUADSPI_BK1_IO0 */
+                     <STM32_PINMUX('F', 9, AF10)>, /* QUADSPI_BK1_IO1 */
+                     <STM32_PINMUX('F', 10, AF9)>; /* QUADSPI_CLK */
+            bias-disable;
+            drive-push-pull;
+            slew-rate = <3>;
+        };
+    };
+    sdmmc1_pins_mx: sdmmc1_mx@0 {
+        u-boot,dm-pre-reloc;
+        pins {
+            u-boot,dm-pre-reloc;
+            pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
+                     <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
+                     <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
+                     <STM32_PINMUX('C', 11, AF12)>, /* SDMMC1_D3 */
+                     <STM32_PINMUX('C', 12, AF12)>, /* SDMMC1_CK */
+                     <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
+            bias-pull-up;
+            drive-push-pull;
+            slew-rate = <3>;
+        };
+    };
+    sdmmc2_pins_mx: sdmmc2_mx@0 {
+        u-boot,dm-pre-reloc;
+        pins {
+            u-boot,dm-pre-reloc;
+            pinmux = <STM32_PINMUX('B', 3, AF9)>, /* SDMMC2_D2 */
+                     <STM32_PINMUX('B', 4, AF9)>, /* SDMMC2_D3 */
+                     <STM32_PINMUX('B', 14, AF9)>, /* SDMMC2_D0 */
+                     <STM32_PINMUX('B', 15, AF9)>, /* SDMMC2_D1 */
+                     <STM32_PINMUX('E', 3, AF9)>, /* SDMMC2_CK */
+                     <STM32_PINMUX('G', 6, AF10)>; /* SDMMC2_CMD */
+            bias-pull-up;
+            drive-push-pull;
+            slew-rate = <3>;
+        };
+    };
+    spi2_pins_mx: spi2_mx@0 {
+        pins {
+            pinmux = <STM32_PINMUX('A', 9, AF5)>, /* SPI2_SCK */
+                     <STM32_PINMUX('C', 2, AF5)>, /* SPI2_MISO */
+                     <STM32_PINMUX('C', 3, AF5)>; /* SPI2_MOSI */
+            bias-disable;
+            drive-push-pull;
+            slew-rate = <1>;
+        };
+    };
+    uart4_pins_mx: uart4_mx@0 {
+        u-boot,dm-pre-reloc;
+        pins1 {
+            u-boot,dm-pre-reloc;
+            pinmux = <STM32_PINMUX('G', 11, AF6)>; /* UART4_TX */
+            bias-disable;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+        pins2 {
+            u-boot,dm-pre-reloc;
+            pinmux = <STM32_PINMUX('B', 2, AF8)>; /* UART4_RX */
+            bias-disable;
+        };
+    };
+    uart8_pins_mx: uart8_mx@0 {
+        pins1 {
+            pinmux = <STM32_PINMUX('E', 1, AF8)>, /* UART8_TX */
+                     <STM32_PINMUX('G', 7, AF8)>; /* UART8_RTS */
+            bias-disable;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+        pins2 {
+            pinmux = <STM32_PINMUX('D', 14, AF8)>, /* UART8_CTS */
+                     <STM32_PINMUX('E', 0, AF8)>; /* UART8_RX */
+            bias-disable;
+        };
+    };
+    usart2_pins_mx: usart2_mx@0 {
+        pins1 {
+            pinmux = <STM32_PINMUX('D', 5, AF7)>; /* USART2_TX */
+            bias-pull-up;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+        pins2 {
+            pinmux = <STM32_PINMUX('D', 3, AF7)>, /* USART2_CTS */
+                     <STM32_PINMUX('D', 6, AF7)>; /* USART2_RX */
+            bias-disable;
+        };
+        pins3 {
+            pinmux = <STM32_PINMUX('D', 4, AF7)>; /* USART2_RTS */
+            bias-disable;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+    };
+    usart3_pins_mx: usart3_mx@0 {
+        pins1 {
+            pinmux = <STM32_PINMUX('D', 8, AF7)>; /* USART3_TX */
+            bias-pull-up;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+        pins2 {
+            pinmux = <STM32_PINMUX('D', 9, AF7)>, /* USART3_RX */
+                     <STM32_PINMUX('D', 11, AF7)>; /* USART3_CTS */
+            bias-disable;
+        };
+        pins3 {
+            pinmux = <STM32_PINMUX('D', 12, AF7)>; /* USART3_RTS */
+            bias-disable;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+    };
+    usart6_pins_mx: usart6_mx@0 {
+        pins1 {
+            pinmux = <STM32_PINMUX('G', 14, AF7)>; /* USART6_TX */
+            bias-pull-up;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+        pins2 {
+            pinmux = <STM32_PINMUX('G', 9, AF7)>; /* USART6_RX */
+            bias-disable;
+        };
+    };
+    usb_otg_hs_pins_mx: usb_otg_hs_mx@0 {
+        u-boot,dm-pre-reloc;
+        pins {
+            u-boot,dm-pre-reloc;
+            pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
+        };
+    };
+    adc_sleep_pins_mx: adc_sleep_mx@0 {
+        pins {
+            pinmux = <STM32_PINMUX('A', 0, ANALOG)>, /* ADC1_INP16 */
+                     <STM32_PINMUX('B', 1, ANALOG)>; /* ADC1_INP5 */
+        };
+    };
+    eth1_sleep_pins_mx: eth1_sleep_mx@0 {
+        pins1 {
+            pinmux = <STM32_PINMUX('A', 2, AF11)>, /* ETH1_MDIO */
+                     <STM32_PINMUX('B', 11, AF11)>, /* ETH1_TX_EN */
+                     <STM32_PINMUX('B', 12, AF11)>, /* ETH1_TXD0 */
+                     <STM32_PINMUX('B', 13, AF11)>, /* ETH1_TXD1 */
+                     <STM32_PINMUX('C', 1, AF11)>, /* ETH1_MDC */
+                     <STM32_PINMUX('G', 8, AF2)>; /* ETH1_CLK */
+            bias-disable;
+            drive-push-pull;
+            slew-rate = <3>;
+        };
+        pins2 {
+            pinmux = <STM32_PINMUX('A', 7, AF11)>, /* ETH1_CRS_DV */
+                     <STM32_PINMUX('C', 4, AF11)>, /* ETH1_RXD0 */
+                     <STM32_PINMUX('C', 5, AF11)>; /* ETH1_RXD1 */
+            bias-disable;
+        };
+    };
+    fdcan1_sleep_pins_mx: fdcan1_sleep_mx@0 {
+        pins {
+            pinmux = <STM32_PINMUX('D', 0, ANALOG)>, /* FDCAN1_RX */
+                     <STM32_PINMUX('D', 1, ANALOG)>; /* FDCAN1_TX */
+        };
+    };
+    i2c2_sleep_pins_mx: i2c2_sleep_mx@0 {
+        pins {
+            pinmux = <STM32_PINMUX('D', 7, AF4)>, /* I2C2_SCL */
+                     <STM32_PINMUX('G', 15, AF4)>; /* I2C2_SDA */
+            bias-disable;
+            drive-open-drain;
+            slew-rate = <0>;
+        };
+    };
+    i2c4_sleep_pins_mx: i2c4_sleep_mx@0 {
+        pins {
+            pinmux = <STM32_PINMUX('B', 7, AF6)>, /* I2C4_SDA */
+                     <STM32_PINMUX('E', 2, AF4)>; /* I2C4_SCL */
+            bias-disable;
+            drive-open-drain;
+            slew-rate = <0>;
+        };
+    };
+    ltdc_sleep_pins_mx: ltdc_sleep_mx@0 {
+        pins {
+            pinmux = <STM32_PINMUX('A', 1, ANALOG)>, /* LTDC_R2 */
+                     <STM32_PINMUX('A', 3, ANALOG)>, /* LTDC_B5 */
+                     <STM32_PINMUX('A', 4, ANALOG)>, /* LTDC_VSYNC */
+                     <STM32_PINMUX('A', 5, ANALOG)>, /* LTDC_R4 */
+                     <STM32_PINMUX('A', 6, ANALOG)>, /* LTDC_G2 */
+                     <STM32_PINMUX('A', 8, ANALOG)>, /* LTDC_R6 */
+                     <STM32_PINMUX('A', 12, ANALOG)>, /* LTDC_R5 */
+                     <STM32_PINMUX('B', 0, ANALOG)>, /* LTDC_R3 */
+                     <STM32_PINMUX('B', 5, ANALOG)>, /* LTDC_G7 */
+                     <STM32_PINMUX('B', 8, ANALOG)>, /* LTDC_B6 */
+                     <STM32_PINMUX('B', 9, ANALOG)>, /* LTDC_B7 */
+                     <STM32_PINMUX('B', 10, ANALOG)>, /* LTDC_G4 */
+                     <STM32_PINMUX('C', 6, ANALOG)>, /* LTDC_HSYNC */
+                     <STM32_PINMUX('C', 7, ANALOG)>, /* LTDC_G6 */
+                     <STM32_PINMUX('D', 10, ANALOG)>, /* LTDC_B3 */
+                     <STM32_PINMUX('E', 11, ANALOG)>, /* LTDC_G3 */
+                     <STM32_PINMUX('E', 12, ANALOG)>, /* LTDC_B4 */
+                     <STM32_PINMUX('E', 13, ANALOG)>, /* LTDC_DE */
+                     <STM32_PINMUX('E', 14, ANALOG)>, /* LTDC_CLK */
+                     <STM32_PINMUX('E', 15, ANALOG)>, /* LTDC_R7 */
+                     <STM32_PINMUX('F', 11, ANALOG)>, /* LTDC_G5 */
+                     <STM32_PINMUX('G', 10, ANALOG)>; /* LTDC_B2 */
+        };
+    };
+    quadspi_sleep_pins_mx: quadspi_sleep_mx@0 {
+        u-boot,dm-pre-reloc;
+        pins {
+            u-boot,dm-pre-reloc;
+            pinmux = <STM32_PINMUX('B', 6, ANALOG)>, /* QUADSPI_BK1_NCS */
+                     <STM32_PINMUX('C', 0, ANALOG)>, /* QUADSPI_BK2_NCS */
+                     <STM32_PINMUX('E', 7, ANALOG)>, /* QUADSPI_BK2_IO0 */
+                     <STM32_PINMUX('E', 8, ANALOG)>, /* QUADSPI_BK2_IO1 */
+                     <STM32_PINMUX('E', 9, ANALOG)>, /* QUADSPI_BK2_IO2 */
+                     <STM32_PINMUX('E', 10, ANALOG)>, /* QUADSPI_BK2_IO3 */
+                     <STM32_PINMUX('F', 6, ANALOG)>, /* QUADSPI_BK1_IO3 */
+                     <STM32_PINMUX('F', 7, ANALOG)>, /* QUADSPI_BK1_IO2 */
+                     <STM32_PINMUX('F', 8, ANALOG)>, /* QUADSPI_BK1_IO0 */
+                     <STM32_PINMUX('F', 9, ANALOG)>, /* QUADSPI_BK1_IO1 */
+                     <STM32_PINMUX('F', 10, ANALOG)>; /* QUADSPI_CLK */
+        };
+    };
+    sdmmc1_sleep_pins_mx: sdmmc1_sleep_mx@0 {
+        u-boot,dm-pre-reloc;
+        pins {
+            u-boot,dm-pre-reloc;
+            pinmux = <STM32_PINMUX('C', 8, ANALOG)>, /* SDMMC1_D0 */
+                     <STM32_PINMUX('C', 9, ANALOG)>, /* SDMMC1_D1 */
+                     <STM32_PINMUX('C', 10, ANALOG)>, /* SDMMC1_D2 */
+                     <STM32_PINMUX('C', 11, ANALOG)>, /* SDMMC1_D3 */
+                     <STM32_PINMUX('C', 12, ANALOG)>, /* SDMMC1_CK */
+                     <STM32_PINMUX('D', 2, ANALOG)>; /* SDMMC1_CMD */
+        };
+    };
+    sdmmc2_sleep_pins_mx: sdmmc2_sleep_mx@0 {
+        u-boot,dm-pre-reloc;
+        pins {
+            u-boot,dm-pre-reloc;
+            pinmux = <STM32_PINMUX('B', 3, ANALOG)>, /* SDMMC2_D2 */
+                     <STM32_PINMUX('B', 4, ANALOG)>, /* SDMMC2_D3 */
+                     <STM32_PINMUX('B', 14, ANALOG)>, /* SDMMC2_D0 */
+                     <STM32_PINMUX('B', 15, ANALOG)>, /* SDMMC2_D1 */
+                     <STM32_PINMUX('E', 3, ANALOG)>, /* SDMMC2_CK */
+                     <STM32_PINMUX('G', 6, ANALOG)>; /* SDMMC2_CMD */
+        };
+    };
+    spi2_sleep_pins_mx: spi2_sleep_mx@0 {
+        pins {
+            pinmux = <STM32_PINMUX('A', 9, AF5)>, /* SPI2_SCK */
+                     <STM32_PINMUX('C', 2, AF5)>, /* SPI2_MISO */
+                     <STM32_PINMUX('C', 3, AF5)>; /* SPI2_MOSI */
+            bias-disable;
+            drive-push-pull;
+            slew-rate = <1>;
+        };
+    };
+    uart4_sleep_pins_mx: uart4_sleep_mx@0 {
+        u-boot,dm-pre-reloc;
+        pins1 {
+            u-boot,dm-pre-reloc;
+            pinmux = <STM32_PINMUX('G', 11, AF6)>; /* UART4_TX */
+            bias-disable;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+        pins2 {
+            u-boot,dm-pre-reloc;
+            pinmux = <STM32_PINMUX('B', 2, AF8)>; /* UART4_RX */
+            bias-disable;
+        };
+    };
+    uart8_sleep_pins_mx: uart8_sleep_mx@0 {
+        pins1 {
+            pinmux = <STM32_PINMUX('E', 1, AF8)>, /* UART8_TX */
+                     <STM32_PINMUX('G', 7, AF8)>; /* UART8_RTS */
+            bias-disable;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+        pins2 {
+            pinmux = <STM32_PINMUX('D', 14, AF8)>, /* UART8_CTS */
+                     <STM32_PINMUX('E', 0, AF8)>; /* UART8_RX */
+            bias-disable;
+        };
+    };
+    usart2_sleep_pins_mx: usart2_sleep_mx@0 {
+        pins1 {
+            pinmux = <STM32_PINMUX('D', 5, AF7)>; /* USART2_TX */
+            bias-pull-up;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+        pins2 {
+            pinmux = <STM32_PINMUX('D', 3, AF7)>, /* USART2_CTS */
+                     <STM32_PINMUX('D', 6, AF7)>; /* USART2_RX */
+            bias-disable;
+        };
+        pins3 {
+            pinmux = <STM32_PINMUX('D', 4, AF7)>; /* USART2_RTS */
+            bias-disable;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+    };
+    usart3_sleep_pins_mx: usart3_sleep_mx@0 {
+        pins1 {
+            pinmux = <STM32_PINMUX('D', 8, AF7)>; /* USART3_TX */
+            bias-pull-up;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+        pins2 {
+            pinmux = <STM32_PINMUX('D', 9, AF7)>, /* USART3_RX */
+                     <STM32_PINMUX('D', 11, AF7)>; /* USART3_CTS */
+            bias-disable;
+        };
+        pins3 {
+            pinmux = <STM32_PINMUX('D', 12, AF7)>; /* USART3_RTS */
+            bias-disable;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+    };
+    usart6_sleep_pins_mx: usart6_sleep_mx@0 {
+        pins1 {
+            pinmux = <STM32_PINMUX('G', 14, AF7)>; /* USART6_TX */
+            bias-pull-up;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+        pins2 {
+            pinmux = <STM32_PINMUX('G', 9, AF7)>; /* USART6_RX */
+            bias-disable;
+        };
+    };
+    usb_otg_hs_sleep_pins_mx: usb_otg_hs_sleep_mx@0 {
+        u-boot,dm-pre-reloc;
+        pins {
+            u-boot,dm-pre-reloc;
+            pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
+        };
+    };
+};
+
+&adc {
+    pinctrl-names = "default", "sleep";
+    pinctrl-0 = <&adc_pins_mx>;
+    pinctrl-1 = <&adc_sleep_pins_mx>;
+    status = "okay";
+};
+
+&ethernet0 {
+    pinctrl-names = "default", "sleep";
+    pinctrl-0 = <&eth1_pins_mx>;
+    pinctrl-1 = <&eth1_sleep_pins_mx>;
+    status = "okay";
+};
+
+&m_can1 {
+    pinctrl-names = "default", "sleep";
+    pinctrl-0 = <&fdcan1_pins_mx>;
+    pinctrl-1 = <&fdcan1_sleep_pins_mx>;
+    status = "okay";
+};
+
+&i2c2 {
+    pinctrl-names = "default", "sleep";
+    pinctrl-0 = <&i2c2_pins_mx>;
+    pinctrl-1 = <&i2c2_sleep_pins_mx>;
+    status = "okay";
+};
+
+&i2c4 {
+    pinctrl-names = "default", "sleep";
+    pinctrl-0 = <&i2c4_pins_mx>;
+    pinctrl-1 = <&i2c4_sleep_pins_mx>;
+    status = "okay";
+};
+
+&ltdc {
+    pinctrl-names = "default", "sleep";
+    pinctrl-0 = <&ltdc_pins_mx>;
+    pinctrl-1 = <&ltdc_sleep_pins_mx>;
+    status = "okay";
+};
+
+&qspi {
+    u-boot,dm-pre-reloc;
+    pinctrl-names = "default", "sleep";
+    pinctrl-0 = <&quadspi_pins_mx>;
+    pinctrl-1 = <&quadspi_sleep_pins_mx>;
+    status = "okay";
+};
+
+&rcc {
+    u-boot,dm-pre-reloc;
+    status = "okay";
+};
+
+&rtc {
+    status = "okay";
+};
+
+&sdmmc1 {
+    u-boot,dm-pre-reloc;
+    pinctrl-names = "default", "sleep";
+    pinctrl-0 = <&sdmmc1_pins_mx>;
+    pinctrl-1 = <&sdmmc1_sleep_pins_mx>;
+    status = "okay";
+};
+
+&sdmmc2 {
+    u-boot,dm-pre-reloc;
+    pinctrl-names = "default", "sleep";
+    pinctrl-0 = <&sdmmc2_pins_mx>;
+    pinctrl-1 = <&sdmmc2_sleep_pins_mx>;
+    status = "okay";
+};
+
+&spi2 {
+    pinctrl-names = "default", "sleep";
+    pinctrl-0 = <&spi2_pins_mx>;
+    pinctrl-1 = <&spi2_sleep_pins_mx>;
+    status = "okay";
+};
+
+&uart4 {
+    u-boot,dm-pre-reloc;
+    pinctrl-names = "default", "sleep";
+    pinctrl-0 = <&uart4_pins_mx>;
+    pinctrl-1 = <&uart4_sleep_pins_mx>;
+    status = "okay";
+};
+
+&uart8 {
+    pinctrl-names = "default", "sleep";
+    pinctrl-0 = <&uart8_pins_mx>;
+    pinctrl-1 = <&uart8_sleep_pins_mx>;
+    status = "okay";
+};
+
+&usart2 {
+    pinctrl-names = "default", "sleep";
+    pinctrl-0 = <&usart2_pins_mx>;
+    pinctrl-1 = <&usart2_sleep_pins_mx>;
+    status = "okay";
+};
+
+&usart3 {
+    pinctrl-names = "default", "sleep";
+    pinctrl-0 = <&usart3_pins_mx>;
+    pinctrl-1 = <&usart3_sleep_pins_mx>;
+    status = "okay";
+};
+
+&usart6 {
+    pinctrl-names = "default", "sleep";
+    pinctrl-0 = <&usart6_pins_mx>;
+    pinctrl-1 = <&usart6_sleep_pins_mx>;
+    status = "okay";
+};
+
+&usbotg_hs {
+    u-boot,dm-pre-reloc;
+    pinctrl-names = "default", "sleep";
+    pinctrl-0 = <&usb_otg_hs_pins_mx>;
+    pinctrl-1 = <&usb_otg_hs_sleep_pins_mx>;
+    status = "okay";
+};
+
+&usbh_ohci {
+    status = "okay";
+};
+
+/* USER CODE BEGIN dts_soc */
+/* USER CODE END dts_soc */
+
diff --git a/recipes-kernel/linux/linux-stm32mp/stm32mp157c-t1000-s-mx.dts b/recipes-kernel/linux/linux-stm32mp/stm32mp157c-t1000-s-mx.dts
index c5efe699b5137a6f24580a3ee4169608e5afd037..d708d679dcb4ca3b740810b6a2b4b3a431d71b6f 100644
--- a/recipes-kernel/linux/linux-stm32mp/stm32mp157c-t1000-s-mx.dts
+++ b/recipes-kernel/linux/linux-stm32mp/stm32mp157c-t1000-s-mx.dts
@@ -1,112 +1,108 @@
 /* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
 /*
- * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
+ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved
  * Author: STM32CubeMX code generation for STMicroelectronics.
  */
 
 /dts-v1/;
 #include "stm32mp157c.dtsi"
-#include "stm32mp157c-m4-srm.dtsi"
 #include "stm32mp157cad-pinctrl.dtsi"
 
-/* USER CODE BEGIN includes */
-/* USER CODE END includes */
+/* USER CODE BEGIN dts_include */
+/* USER CODE END dts_include */
 
 / {
-	model = "STMicroelectronics custom STM32CubeMX board";
+    model = "STMicroelectronics custom STM32CubeMX board";
 	compatible = "st,stm32mp157c-t1000-s-mx", "st,stm32mp157";
 
-    memory@c0000000 {
-        reg = <0xc0000000 0x20000000>;
+	memory {
+		reg = <0xC0000000 0x20000000>;
+	};
 
-        /* USER CODE BEGIN memory */
-        /* USER CODE END memory */
-    };
-
-    reserved-memory {
-        #address-cells = <1>;
-        #size-cells = <1>;
-        ranges;
-
-        /* USER CODE BEGIN reserved-memory */
-        /* USER CODE END reserved-memory */
-
-        gpu_reserved: gpu@dc000000 {
-            reg = <0xdc000000 0x4000000>;
-            no-map;
-        };
-    };
-
-	/* USER CODE BEGIN root */
-	/* USER CODE END root */
+	/* USER CODE BEGIN root_prop */
+	/* USER CODE END root_prop */
 
     clocks {
-        /* USER CODE BEGIN clocks */
-        /* USER CODE END clocks */
-
+        u-boot,dm-pre-reloc;
         clk_hsi: clk-hsi {
+            #clock-cells = <0>;
+            compatible = "fixed-clock";
             clock-frequency = <64000000>;
+            u-boot,dm-pre-reloc;
         };
-        clk_csi: clk-csi {
-            clock-frequency = <4000000>;
+        clk_usbo_48m: ck_usbo_48m {
+            #clock-cells = <0>;
+            compatible = "fixed-clock";
+            clock-frequency = <48000000>;
+            u-boot,dm-pre-reloc;
         };
         clk_lse: clk-lse {
+            #clock-cells = <0>;
+            compatible = "fixed-clock";
             clock-frequency = <32768>;
+            u-boot,dm-pre-reloc;
         };
         clk_hse: clk-hse {
+            #clock-cells = <0>;
+            compatible = "fixed-clock";
             clock-frequency = <24000000>;
+            u-boot,dm-pre-reloc;
         };
     };
+	/* USER CODE BEGIN root_subnodes */
+	/* USER CODE END root_subnodes */
+
+	/* USER CODE BEGIN root_board */
+	/* USER CODE END root_board */
+
+	/* USER CODE BEGIN root_platform */
+	/* USER CODE END root_platform */
 
 }; /*root*/
 
+/* USER CODE BEGIN dts_board */
+/* USER CODE END dts_board */
+
 &pinctrl {
     u-boot,dm-pre-reloc;
-    adc_pins_mx: adc_mx-0 {
+    adc_pins_mx: adc_mx@0 {
         pins {
             pinmux = <STM32_PINMUX('A', 0, ANALOG)>, /* ADC1_INP16 */
                      <STM32_PINMUX('B', 1, ANALOG)>; /* ADC1_INP5 */
         };
     };
-    eth1_pins_mx: eth1_mx-0 {
+    eth1_pins_mx: eth1_mx@0 {
         pins1 {
-            pinmux = <STM32_PINMUX('B', 12, AF11)>, /* ETH1_TXD0 */
+            pinmux = <STM32_PINMUX('A', 2, AF11)>, /* ETH1_MDIO */
+                     <STM32_PINMUX('B', 11, AF11)>, /* ETH1_TX_EN */
+                     <STM32_PINMUX('B', 12, AF11)>, /* ETH1_TXD0 */
                      <STM32_PINMUX('B', 13, AF11)>, /* ETH1_TXD1 */
                      <STM32_PINMUX('C', 1, AF11)>, /* ETH1_MDC */
                      <STM32_PINMUX('G', 8, AF2)>; /* ETH1_CLK */
             bias-disable;
             drive-push-pull;
-            slew-rate = <1>;
+            slew-rate = <3>;
         };
         pins2 {
-            pinmux = <STM32_PINMUX('A', 2, AF11)>; /* ETH1_MDIO */
-            bias-disable;
-            drive-push-pull;
-            slew-rate = <0>;
-        };
-        pins3 {
             pinmux = <STM32_PINMUX('A', 7, AF11)>, /* ETH1_CRS_DV */
                      <STM32_PINMUX('C', 4, AF11)>, /* ETH1_RXD0 */
                      <STM32_PINMUX('C', 5, AF11)>; /* ETH1_RXD1 */
             bias-disable;
         };
-        pins4 {
-            pinmux = <STM32_PINMUX('B', 11, AF11)>; /* ETH1_TX_EN */
-        };
     };
-    fdcan1_pins_mx: fdcan1_mx-0 {
+    fdcan1_pins_mx: fdcan1_mx@0 {
         pins1 {
             pinmux = <STM32_PINMUX('D', 1, AF9)>; /* FDCAN1_TX */
             bias-disable;
             drive-push-pull;
-            slew-rate = <0>;
+            slew-rate = <1>;
         };
         pins2 {
             pinmux = <STM32_PINMUX('D', 0, AF9)>; /* FDCAN1_RX */
             bias-disable;
         };
     };
-    i2c2_pins_mx: i2c2_mx-0 {
+    i2c2_pins_mx: i2c2_mx@0 {
         pins {
             pinmux = <STM32_PINMUX('D', 7, AF4)>, /* I2C2_SCL */
                      <STM32_PINMUX('G', 15, AF4)>; /* I2C2_SDA */
@@ -115,7 +111,7 @@
             slew-rate = <0>;
         };
     };
-    i2c4_pins_mx: i2c4_mx-0 {
+    i2c4_pins_mx: i2c4_mx@0 {
         pins {
             pinmux = <STM32_PINMUX('B', 7, AF6)>, /* I2C4_SDA */
                      <STM32_PINMUX('E', 2, AF4)>; /* I2C4_SCL */
@@ -124,7 +120,7 @@
             slew-rate = <0>;
         };
     };
-    i2s2_pins_mx: i2s2_mx-0 {
+    i2s2_pins_mx: i2s2_mx@0 {
         pins {
             pinmux = <STM32_PINMUX('A', 11, AF5)>, /* I2S2_WS */
                      <STM32_PINMUX('C', 2, AF5)>, /* I2S2_SDI */
@@ -136,10 +132,8 @@
             slew-rate = <1>;
         };
     };
-    ltdc_pins_mx: ltdc_mx-0 {
-        u-boot,dm-pre-reloc;
-        pins1 {
-            u-boot,dm-pre-reloc;
+    ltdc_pins_mx: ltdc_mx@0 {
+        pins {
             pinmux = <STM32_PINMUX('A', 1, AF14)>, /* LTDC_R2 */
                      <STM32_PINMUX('A', 3, AF14)>, /* LTDC_B5 */
                      <STM32_PINMUX('A', 4, AF14)>, /* LTDC_VSYNC */
@@ -147,7 +141,6 @@
                      <STM32_PINMUX('A', 6, AF14)>, /* LTDC_G2 */
                      <STM32_PINMUX('A', 8, AF14)>, /* LTDC_R6 */
                      <STM32_PINMUX('A', 12, AF14)>, /* LTDC_R5 */
-                     <STM32_PINMUX('A', 15, AF14)>, /* LTDC_R1 */
                      <STM32_PINMUX('B', 0, AF9)>, /* LTDC_R3 */
                      <STM32_PINMUX('B', 5, AF14)>, /* LTDC_G7 */
                      <STM32_PINMUX('B', 8, AF14)>, /* LTDC_B6 */
@@ -156,42 +149,25 @@
                      <STM32_PINMUX('C', 6, AF14)>, /* LTDC_HSYNC */
                      <STM32_PINMUX('C', 7, AF14)>, /* LTDC_G6 */
                      <STM32_PINMUX('D', 10, AF14)>, /* LTDC_B3 */
-                     <STM32_PINMUX('E', 4, AF14)>, /* LTDC_B0 */
-                     <STM32_PINMUX('E', 5, AF14)>, /* LTDC_G0 */
-                     <STM32_PINMUX('E', 6, AF14)>, /* LTDC_G1 */
                      <STM32_PINMUX('E', 11, AF14)>, /* LTDC_G3 */
                      <STM32_PINMUX('E', 12, AF14)>, /* LTDC_B4 */
                      <STM32_PINMUX('E', 13, AF14)>, /* LTDC_DE */
+                     <STM32_PINMUX('E', 14, AF14)>, /* LTDC_CLK */
                      <STM32_PINMUX('E', 15, AF14)>, /* LTDC_R7 */
                      <STM32_PINMUX('F', 11, AF14)>, /* LTDC_G5 */
-                     <STM32_PINMUX('G', 10, AF14)>, /* LTDC_B2 */
-                     <STM32_PINMUX('G', 12, AF14)>, /* LTDC_B1 */
-                     <STM32_PINMUX('G', 13, AF14)>; /* LTDC_R0 */
+                     <STM32_PINMUX('G', 10, AF14)>; /* LTDC_B2 */
             bias-disable;
             drive-push-pull;
-            slew-rate = <0>;
-        };
-        pins2 {
-            u-boot,dm-pre-reloc;
-            pinmux = <STM32_PINMUX('E', 14, AF14)>; /* LTDC_CLK */
-            bias-disable;
-            drive-push-pull;
-            slew-rate = <1>;
+            slew-rate = <3>;
         };
     };
-    quadspi_pins_mx: quadspi_mx-0 {
+    quadspi_pins_mx: quadspi_mx@0 {
         u-boot,dm-pre-reloc;
-        pins1 {
+        pins {
             u-boot,dm-pre-reloc;
             pinmux = <STM32_PINMUX('B', 6, AF10)>, /* QUADSPI_BK1_NCS */
-                     <STM32_PINMUX('C', 0, AF10)>; /* QUADSPI_BK2_NCS */
-            bias-pull-up;
-            drive-push-pull;
-            slew-rate = <3>;
-        };
-        pins2 {
-            u-boot,dm-pre-reloc;
-            pinmux = <STM32_PINMUX('E', 7, AF10)>, /* QUADSPI_BK2_IO0 */
+                     <STM32_PINMUX('C', 0, AF10)>, /* QUADSPI_BK2_NCS */
+                     <STM32_PINMUX('E', 7, AF10)>, /* QUADSPI_BK2_IO0 */
                      <STM32_PINMUX('E', 8, AF10)>, /* QUADSPI_BK2_IO1 */
                      <STM32_PINMUX('E', 9, AF10)>, /* QUADSPI_BK2_IO2 */
                      <STM32_PINMUX('E', 10, AF10)>, /* QUADSPI_BK2_IO3 */
@@ -205,65 +181,46 @@
             slew-rate = <3>;
         };
     };
-    sdmmc1_pins_mx: sdmmc1_mx-0 {
+    sdmmc1_pins_mx: sdmmc1_mx@0 {
         u-boot,dm-pre-reloc;
-        pins1 {
+        pins {
             u-boot,dm-pre-reloc;
             pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
                      <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
                      <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
                      <STM32_PINMUX('C', 11, AF12)>, /* SDMMC1_D3 */
+                     <STM32_PINMUX('C', 12, AF12)>, /* SDMMC1_CK */
                      <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
             bias-pull-up;
             drive-push-pull;
-            slew-rate = <1>;
-        };
-        pins2 {
-            u-boot,dm-pre-reloc;
-            pinmux = <STM32_PINMUX('C', 12, AF12)>; /* SDMMC1_CK */
-            bias-pull-up;
-            drive-push-pull;
             slew-rate = <3>;
         };
     };
-    sdmmc2_pins_mx: sdmmc2_mx-0 {
+    sdmmc2_pins_mx: sdmmc2_mx@0 {
         u-boot,dm-pre-reloc;
-        pins1 {
+        pins {
             u-boot,dm-pre-reloc;
             pinmux = <STM32_PINMUX('B', 3, AF9)>, /* SDMMC2_D2 */
                      <STM32_PINMUX('B', 4, AF9)>, /* SDMMC2_D3 */
                      <STM32_PINMUX('B', 14, AF9)>, /* SDMMC2_D0 */
                      <STM32_PINMUX('B', 15, AF9)>, /* SDMMC2_D1 */
+                     <STM32_PINMUX('E', 3, AF9)>, /* SDMMC2_CK */
                      <STM32_PINMUX('G', 6, AF10)>; /* SDMMC2_CMD */
             bias-pull-up;
             drive-push-pull;
-            slew-rate = <1>;
-        };
-        pins2 {
-            u-boot,dm-pre-reloc;
-            pinmux = <STM32_PINMUX('E', 3, AF9)>; /* SDMMC2_CK */
-            bias-pull-up;
-            drive-push-pull;
             slew-rate = <3>;
         };
     };
-    tim1_pwm_pins_mx: tim1_pwm_mx-0 {
+    tim4_pwm_pins_mx: tim4_pwm_mx@0 {
         pins {
-            pinmux = <STM32_PINMUX('A', 9, AF1)>; /* TIM1_CH2 */
+            pinmux = <STM32_PINMUX('D', 12, AF2)>, /* TIM4_CH1 */
+                     <STM32_PINMUX('D', 14, AF2)>; /* TIM4_CH3 */
             bias-disable;
             drive-push-pull;
-            slew-rate = <0>;
+            slew-rate = <2>;
         };
     };
-    tim4_pwm_pins_mx: tim4_pwm_mx-0 {
-        pins {
-            pinmux = <STM32_PINMUX('D', 14, AF2)>; /* TIM4_CH3 */
-            bias-disable;
-            drive-push-pull;
-            slew-rate = <0>;
-        };
-    };
-    uart4_pins_mx: uart4_mx-0 {
+    uart4_pins_mx: uart4_mx@0 {
         u-boot,dm-pre-reloc;
         pins1 {
             u-boot,dm-pre-reloc;
@@ -278,7 +235,7 @@
             bias-pull-up;
         };
     };
-    usart2_pins_mx: usart2_mx-0 {
+    usart2_pins_mx: usart2_mx@0 {
         pins1 {
             pinmux = <STM32_PINMUX('D', 5, AF7)>; /* USART2_TX */
             bias-pull-up;
@@ -296,7 +253,7 @@
             bias-pull-up;
         };
     };
-    usart6_pins_mx: usart6_mx-0 {
+    usart6_pins_mx: usart6_mx@0 {
         pins1 {
             pinmux = <STM32_PINMUX('G', 14, AF7)>; /* USART6_TX */
             bias-pull-up;
@@ -308,51 +265,63 @@
             bias-pull-up;
         };
     };
-    usb_otg_hs_pins_mx: usb_otg_hs_mx-0 {
+    usb_otg_hs_pins_mx: usb_otg_hs_mx@0 {
         u-boot,dm-pre-reloc;
         pins {
             u-boot,dm-pre-reloc;
             pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
         };
     };
-    adc_sleep_pins_mx: adc_sleep_mx-0 {
+    adc_sleep_pins_mx: adc_sleep_mx@0 {
         pins {
             pinmux = <STM32_PINMUX('A', 0, ANALOG)>, /* ADC1_INP16 */
                      <STM32_PINMUX('B', 1, ANALOG)>; /* ADC1_INP5 */
         };
     };
-    eth1_sleep_pins_mx: eth1_sleep_mx-0 {
-        pins {
-            pinmux = <STM32_PINMUX('A', 2, ANALOG)>, /* ETH1_MDIO */
-                     <STM32_PINMUX('A', 7, ANALOG)>, /* ETH1_CRS_DV */
-                     <STM32_PINMUX('B', 11, ANALOG)>, /* ETH1_TX_EN */
-                     <STM32_PINMUX('B', 12, ANALOG)>, /* ETH1_TXD0 */
-                     <STM32_PINMUX('B', 13, ANALOG)>, /* ETH1_TXD1 */
-                     <STM32_PINMUX('C', 1, ANALOG)>, /* ETH1_MDC */
-                     <STM32_PINMUX('C', 4, ANALOG)>, /* ETH1_RXD0 */
-                     <STM32_PINMUX('C', 5, ANALOG)>, /* ETH1_RXD1 */
-                     <STM32_PINMUX('G', 8, ANALOG)>; /* ETH1_CLK */
-        };
-    };
-    fdcan1_sleep_pins_mx: fdcan1_sleep_mx-0 {
+    eth1_sleep_pins_mx: eth1_sleep_mx@0 {
+        pins1 {
+            pinmux = <STM32_PINMUX('A', 2, AF11)>, /* ETH1_MDIO */
+                     <STM32_PINMUX('B', 11, AF11)>, /* ETH1_TX_EN */
+                     <STM32_PINMUX('B', 12, AF11)>, /* ETH1_TXD0 */
+                     <STM32_PINMUX('B', 13, AF11)>, /* ETH1_TXD1 */
+                     <STM32_PINMUX('C', 1, AF11)>, /* ETH1_MDC */
+                     <STM32_PINMUX('G', 8, AF2)>; /* ETH1_CLK */
+            bias-disable;
+            drive-push-pull;
+            slew-rate = <3>;
+        };
+        pins2 {
+            pinmux = <STM32_PINMUX('A', 7, AF11)>, /* ETH1_CRS_DV */
+                     <STM32_PINMUX('C', 4, AF11)>, /* ETH1_RXD0 */
+                     <STM32_PINMUX('C', 5, AF11)>; /* ETH1_RXD1 */
+            bias-disable;
+        };
+    };
+    fdcan1_sleep_pins_mx: fdcan1_sleep_mx@0 {
         pins {
             pinmux = <STM32_PINMUX('D', 0, ANALOG)>, /* FDCAN1_RX */
                      <STM32_PINMUX('D', 1, ANALOG)>; /* FDCAN1_TX */
         };
     };
-    i2c2_sleep_pins_mx: i2c2_sleep_mx-0 {
+    i2c2_sleep_pins_mx: i2c2_sleep_mx@0 {
         pins {
-            pinmux = <STM32_PINMUX('D', 7, ANALOG)>, /* I2C2_SCL */
-                     <STM32_PINMUX('G', 15, ANALOG)>; /* I2C2_SDA */
+            pinmux = <STM32_PINMUX('D', 7, AF4)>, /* I2C2_SCL */
+                     <STM32_PINMUX('G', 15, AF4)>; /* I2C2_SDA */
+            bias-disable;
+            drive-open-drain;
+            slew-rate = <0>;
         };
     };
-    i2c4_sleep_pins_mx: i2c4_sleep_mx-0 {
+    i2c4_sleep_pins_mx: i2c4_sleep_mx@0 {
         pins {
-            pinmux = <STM32_PINMUX('B', 7, ANALOG)>, /* I2C4_SDA */
-                     <STM32_PINMUX('E', 2, ANALOG)>; /* I2C4_SCL */
+            pinmux = <STM32_PINMUX('B', 7, AF6)>, /* I2C4_SDA */
+                     <STM32_PINMUX('E', 2, AF4)>; /* I2C4_SCL */
+            bias-disable;
+            drive-open-drain;
+            slew-rate = <0>;
         };
     };
-    i2s2_sleep_pins_mx: i2s2_sleep_mx-0 {
+    i2s2_sleep_pins_mx: i2s2_sleep_mx@0 {
         pins {
             pinmux = <STM32_PINMUX('A', 11, ANALOG)>, /* I2S2_WS */
                      <STM32_PINMUX('C', 2, ANALOG)>, /* I2S2_SDI */
@@ -361,10 +330,8 @@
                      <STM32_PINMUX('E', 1, ANALOG)>; /* I2S2_MCK */
         };
     };
-    ltdc_sleep_pins_mx: ltdc_sleep_mx-0 {
-        u-boot,dm-pre-reloc;
+    ltdc_sleep_pins_mx: ltdc_sleep_mx@0 {
         pins {
-            u-boot,dm-pre-reloc;
             pinmux = <STM32_PINMUX('A', 1, ANALOG)>, /* LTDC_R2 */
                      <STM32_PINMUX('A', 3, ANALOG)>, /* LTDC_B5 */
                      <STM32_PINMUX('A', 4, ANALOG)>, /* LTDC_VSYNC */
@@ -372,7 +339,6 @@
                      <STM32_PINMUX('A', 6, ANALOG)>, /* LTDC_G2 */
                      <STM32_PINMUX('A', 8, ANALOG)>, /* LTDC_R6 */
                      <STM32_PINMUX('A', 12, ANALOG)>, /* LTDC_R5 */
-                     <STM32_PINMUX('A', 15, ANALOG)>, /* LTDC_R1 */
                      <STM32_PINMUX('B', 0, ANALOG)>, /* LTDC_R3 */
                      <STM32_PINMUX('B', 5, ANALOG)>, /* LTDC_G7 */
                      <STM32_PINMUX('B', 8, ANALOG)>, /* LTDC_B6 */
@@ -381,21 +347,16 @@
                      <STM32_PINMUX('C', 6, ANALOG)>, /* LTDC_HSYNC */
                      <STM32_PINMUX('C', 7, ANALOG)>, /* LTDC_G6 */
                      <STM32_PINMUX('D', 10, ANALOG)>, /* LTDC_B3 */
-                     <STM32_PINMUX('E', 4, ANALOG)>, /* LTDC_B0 */
-                     <STM32_PINMUX('E', 5, ANALOG)>, /* LTDC_G0 */
-                     <STM32_PINMUX('E', 6, ANALOG)>, /* LTDC_G1 */
                      <STM32_PINMUX('E', 11, ANALOG)>, /* LTDC_G3 */
                      <STM32_PINMUX('E', 12, ANALOG)>, /* LTDC_B4 */
                      <STM32_PINMUX('E', 13, ANALOG)>, /* LTDC_DE */
                      <STM32_PINMUX('E', 14, ANALOG)>, /* LTDC_CLK */
                      <STM32_PINMUX('E', 15, ANALOG)>, /* LTDC_R7 */
                      <STM32_PINMUX('F', 11, ANALOG)>, /* LTDC_G5 */
-                     <STM32_PINMUX('G', 10, ANALOG)>, /* LTDC_B2 */
-                     <STM32_PINMUX('G', 12, ANALOG)>, /* LTDC_B1 */
-                     <STM32_PINMUX('G', 13, ANALOG)>; /* LTDC_R0 */
+                     <STM32_PINMUX('G', 10, ANALOG)>; /* LTDC_B2 */
         };
     };
-    quadspi_sleep_pins_mx: quadspi_sleep_mx-0 {
+    quadspi_sleep_pins_mx: quadspi_sleep_mx@0 {
         u-boot,dm-pre-reloc;
         pins {
             u-boot,dm-pre-reloc;
@@ -412,7 +373,7 @@
                      <STM32_PINMUX('F', 10, ANALOG)>; /* QUADSPI_CLK */
         };
     };
-    sdmmc1_sleep_pins_mx: sdmmc1_sleep_mx-0 {
+    sdmmc1_sleep_pins_mx: sdmmc1_sleep_mx@0 {
         u-boot,dm-pre-reloc;
         pins {
             u-boot,dm-pre-reloc;
@@ -424,7 +385,7 @@
                      <STM32_PINMUX('D', 2, ANALOG)>; /* SDMMC1_CMD */
         };
     };
-    sdmmc2_sleep_pins_mx: sdmmc2_sleep_mx-0 {
+    sdmmc2_sleep_pins_mx: sdmmc2_sleep_mx@0 {
         u-boot,dm-pre-reloc;
         pins {
             u-boot,dm-pre-reloc;
@@ -436,38 +397,58 @@
                      <STM32_PINMUX('G', 6, ANALOG)>; /* SDMMC2_CMD */
         };
     };
-    tim1_pwm_sleep_pins_mx: tim1_pwm_sleep_mx-0 {
+    tim4_pwm_sleep_pins_mx: tim4_pwm_sleep_mx@0 {
         pins {
-            pinmux = <STM32_PINMUX('A', 9, ANALOG)>; /* TIM1_CH2 */
+            pinmux = <STM32_PINMUX('D', 12, ANALOG)>, /* TIM4_CH1 */
+                     <STM32_PINMUX('D', 14, ANALOG)>; /* TIM4_CH3 */
         };
     };
-    tim4_pwm_sleep_pins_mx: tim4_pwm_sleep_mx-0 {
-        pins {
-            pinmux = <STM32_PINMUX('D', 14, ANALOG)>; /* TIM4_CH3 */
-        };
-    };
-    uart4_sleep_pins_mx: uart4_sleep_mx-0 {
+    uart4_sleep_pins_mx: uart4_sleep_mx@0 {
         u-boot,dm-pre-reloc;
-        pins {
+        pins1 {
             u-boot,dm-pre-reloc;
-            pinmux = <STM32_PINMUX('B', 2, ANALOG)>, /* UART4_RX */
-                     <STM32_PINMUX('G', 11, ANALOG)>; /* UART4_TX */
+            pinmux = <STM32_PINMUX('G', 11, AF6)>; /* UART4_TX */
+            bias-pull-up;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+        pins2 {
+            u-boot,dm-pre-reloc;
+            pinmux = <STM32_PINMUX('B', 2, AF8)>; /* UART4_RX */
+            bias-pull-up;
         };
     };
-    usart2_sleep_pins_mx: usart2_sleep_mx-0 {
-        pins {
-            pinmux = <STM32_PINMUX('D', 4, ANALOG)>, /* USART2_RTS */
-                     <STM32_PINMUX('D', 5, ANALOG)>, /* USART2_TX */
-                     <STM32_PINMUX('D', 6, ANALOG)>; /* USART2_RX */
+    usart2_sleep_pins_mx: usart2_sleep_mx@0 {
+        pins1 {
+            pinmux = <STM32_PINMUX('D', 5, AF7)>; /* USART2_TX */
+            bias-pull-up;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+        pins2 {
+            pinmux = <STM32_PINMUX('D', 4, AF7)>; /* USART2_RTS */
+            bias-pull-down;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+        pins3 {
+            pinmux = <STM32_PINMUX('D', 6, AF7)>; /* USART2_RX */
+            bias-pull-up;
         };
     };
-    usart6_sleep_pins_mx: usart6_sleep_mx-0 {
-        pins {
-            pinmux = <STM32_PINMUX('G', 9, ANALOG)>, /* USART6_RX */
-                     <STM32_PINMUX('G', 14, ANALOG)>; /* USART6_TX */
+    usart6_sleep_pins_mx: usart6_sleep_mx@0 {
+        pins1 {
+            pinmux = <STM32_PINMUX('G', 14, AF7)>; /* USART6_TX */
+            bias-pull-up;
+            drive-push-pull;
+            slew-rate = <0>;
+        };
+        pins2 {
+            pinmux = <STM32_PINMUX('G', 9, AF7)>; /* USART6_RX */
+            bias-pull-up;
         };
     };
-    usb_otg_hs_sleep_pins_mx: usb_otg_hs_sleep_mx-0 {
+    usb_otg_hs_sleep_pins_mx: usb_otg_hs_sleep_mx@0 {
         u-boot,dm-pre-reloc;
         pins {
             u-boot,dm-pre-reloc;
@@ -476,319 +457,133 @@
     };
 };
 
-&m4_rproc{
-    mboxes = <&ipcc 0>, <&ipcc 1>, <&ipcc 2>;
-    mbox-names = "vq0", "vq1", "shutdown";
-    recovery;
-    status = "okay";
-
-    /* USER CODE BEGIN m4_rproc */
-    /* USER CODE END m4_rproc */
-};
-
-&adc{
+&adc {
     pinctrl-names = "default", "sleep";
     pinctrl-0 = <&adc_pins_mx>;
     pinctrl-1 = <&adc_sleep_pins_mx>;
     status = "okay";
-
-    /* USER CODE BEGIN adc */
-    /* USER CODE END adc */
 };
 
-&bsec{
-    status = "okay";
-
-    /* USER CODE BEGIN bsec */
-    /* USER CODE END bsec */
-};
-
-&crc1{
-    status = "okay";
-
-    /* USER CODE BEGIN crc1 */
-    /* USER CODE END crc1 */
-};
-
-&cryp1{
-    status = "okay";
-
-    /* USER CODE BEGIN cryp1 */
-    /* USER CODE END cryp1 */
-};
-
-&dts{
-    status = "okay";
-
-    /* USER CODE BEGIN dts */
-    /* USER CODE END dts */
-};
-
-&ethernet0{
+&ethernet0 {
     pinctrl-names = "default", "sleep";
     pinctrl-0 = <&eth1_pins_mx>;
     pinctrl-1 = <&eth1_sleep_pins_mx>;
     status = "okay";
-
-    /* USER CODE BEGIN ethernet0 */
-    /* USER CODE END ethernet0 */
-};
-
-&gpu{
-    status = "okay";
-
-    /* USER CODE BEGIN gpu */
-    /* USER CODE END gpu */
 };
 
-&hash1{
-    status = "okay";
-
-    /* USER CODE BEGIN hash1 */
-    /* USER CODE END hash1 */
-};
-
-&hsem{
+&m_can1 {
+    pinctrl-names = "default", "sleep";
+    pinctrl-0 = <&fdcan1_pins_mx>;
+    pinctrl-1 = <&fdcan1_sleep_pins_mx>;
     status = "okay";
-
-    /* USER CODE BEGIN hsem */
-    /* USER CODE END hsem */
 };
 
-&i2c2{
+&i2c2 {
     pinctrl-names = "default", "sleep";
     pinctrl-0 = <&i2c2_pins_mx>;
     pinctrl-1 = <&i2c2_sleep_pins_mx>;
     status = "okay";
-
-    /* USER CODE BEGIN i2c2 */
-    /* USER CODE END i2c2 */
 };
 
-&i2c4{
+&i2c4 {
     pinctrl-names = "default", "sleep";
     pinctrl-0 = <&i2c4_pins_mx>;
     pinctrl-1 = <&i2c4_sleep_pins_mx>;
     status = "okay";
-
-    /* USER CODE BEGIN i2c4 */
-    /* USER CODE END i2c4 */
 };
 
-&i2s2{
+&i2s2 {
     pinctrl-names = "default", "sleep";
     pinctrl-0 = <&i2s2_pins_mx>;
     pinctrl-1 = <&i2s2_sleep_pins_mx>;
     status = "okay";
-
-    /* USER CODE BEGIN i2s2 */
-    /* USER CODE END i2s2 */
-};
-
-&ipcc{
-    status = "okay";
-
-    /* USER CODE BEGIN ipcc */
-    /* USER CODE END ipcc */
 };
 
-&ltdc{
-    u-boot,dm-pre-reloc;
+&ltdc {
     pinctrl-names = "default", "sleep";
     pinctrl-0 = <&ltdc_pins_mx>;
     pinctrl-1 = <&ltdc_sleep_pins_mx>;
     status = "okay";
-
-    /* USER CODE BEGIN ltdc */
-    /* USER CODE END ltdc */
 };
 
-&m_can1{
-    pinctrl-names = "default", "sleep";
-    pinctrl-0 = <&fdcan1_pins_mx>;
-    pinctrl-1 = <&fdcan1_sleep_pins_mx>;
-    status = "okay";
-
-    /* USER CODE BEGIN m_can1 */
-    /* USER CODE END m_can1 */
-};
-
-&qspi{
+&qspi {
     u-boot,dm-pre-reloc;
     pinctrl-names = "default", "sleep";
     pinctrl-0 = <&quadspi_pins_mx>;
     pinctrl-1 = <&quadspi_sleep_pins_mx>;
     status = "okay";
-
-    /* USER CODE BEGIN qspi */
-    /* USER CODE END qspi */
 };
 
-&rcc{
+&rcc {
     u-boot,dm-pre-reloc;
     status = "okay";
-
-    /* USER CODE BEGIN rcc */
-    /* USER CODE END rcc */
-};
-
-&rng1{
-    status = "okay";
-
-    /* USER CODE BEGIN rng1 */
-    /* USER CODE END rng1 */
 };
 
-&rtc{
+&rtc {
     status = "okay";
-
-    /* USER CODE BEGIN rtc */
-    /* USER CODE END rtc */
 };
 
-&sdmmc1{
+&sdmmc1 {
     u-boot,dm-pre-reloc;
     pinctrl-names = "default", "sleep";
     pinctrl-0 = <&sdmmc1_pins_mx>;
     pinctrl-1 = <&sdmmc1_sleep_pins_mx>;
     status = "okay";
-
-    /* USER CODE BEGIN sdmmc1 */
-    /* USER CODE END sdmmc1 */
 };
 
-&sdmmc2{
+&sdmmc2 {
     u-boot,dm-pre-reloc;
     pinctrl-names = "default", "sleep";
     pinctrl-0 = <&sdmmc2_pins_mx>;
     pinctrl-1 = <&sdmmc2_sleep_pins_mx>;
     status = "okay";
-
-    /* USER CODE BEGIN sdmmc2 */
-    /* USER CODE END sdmmc2 */
 };
 
-&timers1{
+&timers4 {
     status = "okay";
 
-    /* USER CODE BEGIN timers1 */
-    /* USER CODE END timers1 */
-
-    pwm{
-        pinctrl-names = "default", "sleep";
-        pinctrl-0 = <&tim1_pwm_pins_mx>;
-        pinctrl-1 = <&tim1_pwm_sleep_pins_mx>;
-        status = "okay";
-
-        /* USER CODE BEGIN timers1_pwm */
-        /* USER CODE END timers1_pwm */
-    };
-};
-
-&timers4{
-    status = "okay";
-
-    /* USER CODE BEGIN timers4 */
-    /* USER CODE END timers4 */
-
     pwm{
         pinctrl-names = "default", "sleep";
         pinctrl-0 = <&tim4_pwm_pins_mx>;
         pinctrl-1 = <&tim4_pwm_sleep_pins_mx>;
         status = "okay";
-
-        /* USER CODE BEGIN timers4_pwm */
-        /* USER CODE END timers4_pwm */
     };
 };
 
-&uart4{
+&uart4 {
     u-boot,dm-pre-reloc;
     pinctrl-names = "default", "sleep";
     pinctrl-0 = <&uart4_pins_mx>;
     pinctrl-1 = <&uart4_sleep_pins_mx>;
     status = "okay";
-
-    /* USER CODE BEGIN uart4 */
-    /* USER CODE END uart4 */
 };
 
-&usart2{
+&usart2 {
     pinctrl-names = "default", "sleep";
     pinctrl-0 = <&usart2_pins_mx>;
     pinctrl-1 = <&usart2_sleep_pins_mx>;
     status = "okay";
-
-    /* USER CODE BEGIN usart2 */
-    /* USER CODE END usart2 */
 };
 
-&usart6{
+&usart6 {
     pinctrl-names = "default", "sleep";
     pinctrl-0 = <&usart6_pins_mx>;
     pinctrl-1 = <&usart6_sleep_pins_mx>;
     status = "okay";
-
-    /* USER CODE BEGIN usart6 */
-    /* USER CODE END usart6 */
-};
-
-&usbh_ehci{
-    status = "okay";
-
-    /* USER CODE BEGIN usbh_ehci */
-    /* USER CODE END usbh_ehci */
 };
 
-&usbh_ohci{
-    status = "okay";
-
-    /* USER CODE BEGIN usbh_ohci */
-    /* USER CODE END usbh_ohci */
-};
-
-&usbotg_hs{
+&usbotg_hs {
     u-boot,dm-pre-reloc;
     pinctrl-names = "default", "sleep";
     pinctrl-0 = <&usb_otg_hs_pins_mx>;
     pinctrl-1 = <&usb_otg_hs_sleep_pins_mx>;
     status = "okay";
-
-    /* USER CODE BEGIN usbotg_hs */
-    /* USER CODE END usbotg_hs */
 };
 
-&usbphyc{
-    u-boot,dm-pre-reloc;
+&usbh_ohci {
     status = "okay";
-
-    /* USER CODE BEGIN usbphyc */
-    /* USER CODE END usbphyc */
-};
-
-&usbphyc_port0{
-    u-boot,dm-pre-reloc;
-    status = "okay";
-
-    /* USER CODE BEGIN usbphyc_port0 */
-    /* USER CODE END usbphyc_port0 */
-};
-
-&usbphyc_port1{
-    u-boot,dm-pre-reloc;
-    status = "okay";
-
-    /* USER CODE BEGIN usbphyc_port1 */
-    /* USER CODE END usbphyc_port1 */
-};
-
-&vrefbuf{
-    status = "okay";
-
-    /* USER CODE BEGIN vrefbuf */
-    /* USER CODE END vrefbuf */
 };
 
-/* USER CODE BEGIN addons */
-/* USER CODE END addons */
+/* USER CODE BEGIN dts_soc */
+/* USER CODE END dts_soc */
 
diff --git a/recipes-kernel/linux/linux-stm32mp/stm32mp157c-t1000-som-minimal-mx.dts b/recipes-kernel/linux/linux-stm32mp/stm32mp157c-t1000-som-minimal-mx.dts
deleted file mode 100644
index c9753dfd647a80120c3e55a48116af453e66cbc0..0000000000000000000000000000000000000000
--- a/recipes-kernel/linux/linux-stm32mp/stm32mp157c-t1000-som-minimal-mx.dts
+++ /dev/null
@@ -1,518 +0,0 @@
-/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
-/*
- * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
- * Author: STM32CubeMX code generation for STMicroelectronics.
- */
-
-/dts-v1/;
-#include "stm32mp157c.dtsi"
-#include "stm32mp157c-m4-srm.dtsi"
-#include "stm32mp157cad-pinctrl.dtsi"
-
-/* USER CODE BEGIN includes */
-/* USER CODE END includes */
-
-/ {
-	model = "STMicroelectronics custom STM32CubeMX board";
-	compatible = "st,stm32mp157c-t1000-som-minimal-mx", "st,stm32mp157";
-
-	memory@c0000000 {
-		reg = <0xc0000000 0x20000000>;
-
-		/* USER CODE BEGIN memory */
-		/* USER CODE END memory */
-	};
-
-	reserved-memory {
-		#address-cells = <1>;
-		#size-cells = <1>;
-		ranges;
-
-		/* USER CODE BEGIN reserved-memory */
-		/* USER CODE END reserved-memory */
-
-		gpu_reserved: gpu@dc000000 {
-			reg = <0xdc000000 0x4000000>;
-			no-map;
-		};
-	};
-
-	/* USER CODE BEGIN root */
-	/* USER CODE END root */
-
-	clocks {
-		/* USER CODE BEGIN clocks */
-		/* USER CODE END clocks */
-
-		clk_hsi: clk-hsi {
-			clock-frequency = <64000000>;
-		};
-
-		clk_csi: clk-csi {
-			clock-frequency = <4000000>;
-		};
-
-		clk_lse: clk-lse {
-			clock-frequency = <32768>;
-		};
-
-		clk_hse: clk-hse {
-			clock-frequency = <24000000>;
-		};
-	};
-
-}; /*root*/
-
-&pinctrl {
-	u-boot,dm-pre-reloc;
-
-	eth1_pins_mx: eth1_mx-0 {
-		pins1 {
-			pinmux = <STM32_PINMUX('A', 2, AF11)>; /* ETH1_MDIO */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-		pins2 {
-			pinmux = <STM32_PINMUX('A', 7, AF11)>, /* ETH1_CRS_DV */
-					 <STM32_PINMUX('C', 4, AF11)>, /* ETH1_RXD0 */
-					 <STM32_PINMUX('C', 5, AF11)>; /* ETH1_RXD1 */
-			bias-disable;
-		};
-		pins3 {
-			pinmux = <STM32_PINMUX('B', 11, AF11)>; /* ETH1_TX_EN */
-		};
-		pins4 {
-			pinmux = <STM32_PINMUX('B', 12, AF11)>, /* ETH1_TXD0 */
-					 <STM32_PINMUX('B', 13, AF11)>, /* ETH1_TXD1 */
-					 <STM32_PINMUX('C', 1, AF11)>, /* ETH1_MDC */
-					 <STM32_PINMUX('G', 8, AF2)>; /* ETH1_CLK */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-	};
-
-	eth1_sleep_pins_mx: eth1_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 2, ANALOG)>, /* ETH1_MDIO */
-					 <STM32_PINMUX('A', 7, ANALOG)>, /* ETH1_CRS_DV */
-					 <STM32_PINMUX('B', 11, ANALOG)>, /* ETH1_TX_EN */
-					 <STM32_PINMUX('B', 12, ANALOG)>, /* ETH1_TXD0 */
-					 <STM32_PINMUX('B', 13, ANALOG)>, /* ETH1_TXD1 */
-					 <STM32_PINMUX('C', 1, ANALOG)>, /* ETH1_MDC */
-					 <STM32_PINMUX('C', 4, ANALOG)>, /* ETH1_RXD0 */
-					 <STM32_PINMUX('C', 5, ANALOG)>, /* ETH1_RXD1 */
-					 <STM32_PINMUX('G', 8, ANALOG)>; /* ETH1_CLK */
-		};
-	};
-
-	i2c2_pins_mx: i2c2_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('D', 7, AF4)>, /* I2C2_SCL */
-					 <STM32_PINMUX('G', 15, AF4)>; /* I2C2_SDA */
-			bias-disable;
-			drive-open-drain;
-			slew-rate = <0>;
-		};
-	};
-
-	i2c2_sleep_pins_mx: i2c2_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('D', 7, ANALOG)>, /* I2C2_SCL */
-					 <STM32_PINMUX('G', 15, ANALOG)>; /* I2C2_SDA */
-		};
-	};
-
-	quadspi_pins_mx: quadspi_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 6, AF10)>, /* QUADSPI_BK1_NCS */
-					 <STM32_PINMUX('C', 0, AF10)>; /* QUADSPI_BK2_NCS */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('E', 7, AF10)>, /* QUADSPI_BK2_IO0 */
-					 <STM32_PINMUX('E', 8, AF10)>, /* QUADSPI_BK2_IO1 */
-					 <STM32_PINMUX('E', 9, AF10)>, /* QUADSPI_BK2_IO2 */
-					 <STM32_PINMUX('E', 10, AF10)>, /* QUADSPI_BK2_IO3 */
-					 <STM32_PINMUX('F', 6, AF9)>, /* QUADSPI_BK1_IO3 */
-					 <STM32_PINMUX('F', 7, AF9)>, /* QUADSPI_BK1_IO2 */
-					 <STM32_PINMUX('F', 8, AF10)>, /* QUADSPI_BK1_IO0 */
-					 <STM32_PINMUX('F', 9, AF10)>; /* QUADSPI_BK1_IO1 */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins3 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('F', 10, AF9)>; /* QUADSPI_CLK */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <2>;
-		};
-	};
-
-	quadspi_sleep_pins_mx: quadspi_sleep_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 6, ANALOG)>, /* QUADSPI_BK1_NCS */
-					 <STM32_PINMUX('C', 0, ANALOG)>, /* QUADSPI_BK2_NCS */
-					 <STM32_PINMUX('E', 7, ANALOG)>, /* QUADSPI_BK2_IO0 */
-					 <STM32_PINMUX('E', 8, ANALOG)>, /* QUADSPI_BK2_IO1 */
-					 <STM32_PINMUX('E', 9, ANALOG)>, /* QUADSPI_BK2_IO2 */
-					 <STM32_PINMUX('E', 10, ANALOG)>, /* QUADSPI_BK2_IO3 */
-					 <STM32_PINMUX('F', 6, ANALOG)>, /* QUADSPI_BK1_IO3 */
-					 <STM32_PINMUX('F', 7, ANALOG)>, /* QUADSPI_BK1_IO2 */
-					 <STM32_PINMUX('F', 8, ANALOG)>, /* QUADSPI_BK1_IO0 */
-					 <STM32_PINMUX('F', 9, ANALOG)>, /* QUADSPI_BK1_IO1 */
-					 <STM32_PINMUX('F', 10, ANALOG)>; /* QUADSPI_CLK */
-		};
-	};
-
-	rtc_pins_mx: rtc_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('C', 13, ANALOG)>; /* RTC_LSCO */
-		};
-	};
-
-	rtc_sleep_pins_mx: rtc_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('C', 13, ANALOG)>; /* RTC_LSCO */
-		};
-	};
-
-	sdmmc1_pins_mx: sdmmc1_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
-					 <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
-					 <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
-					 <STM32_PINMUX('C', 11, AF12)>, /* SDMMC1_D3 */
-					 <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 12, AF12)>; /* SDMMC1_CK */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-	};
-
-	sdmmc1_opendrain_pins_mx: sdmmc1_opendrain_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
-					 <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
-					 <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
-					 <STM32_PINMUX('C', 11, AF12)>; /* SDMMC1_D3 */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 12, AF12)>; /* SDMMC1_CK */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins3 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
-			bias-pull-up;
-			drive-open-drain;
-			slew-rate = <1>;
-		};
-	};
-
-	sdmmc1_sleep_pins_mx: sdmmc1_sleep_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 8, ANALOG)>, /* SDMMC1_D0 */
-					 <STM32_PINMUX('C', 9, ANALOG)>, /* SDMMC1_D1 */
-					 <STM32_PINMUX('C', 10, ANALOG)>, /* SDMMC1_D2 */
-					 <STM32_PINMUX('C', 11, ANALOG)>, /* SDMMC1_D3 */
-					 <STM32_PINMUX('C', 12, ANALOG)>, /* SDMMC1_CK */
-					 <STM32_PINMUX('D', 2, ANALOG)>; /* SDMMC1_CMD */
-		};
-	};
-
-	uart4_pins_mx: uart4_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 2, AF8)>; /* UART4_RX */
-			bias-pull-up;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('G', 11, AF6)>; /* UART4_TX */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-	};
-
-	uart4_sleep_pins_mx: uart4_sleep_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 2, ANALOG)>, /* UART4_RX */
-					 <STM32_PINMUX('G', 11, ANALOG)>; /* UART4_TX */
-		};
-	};
-
-	usb_otg_hs_pins_mx: usb_otg_hs_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
-		};
-	};
-
-	usb_otg_hs_sleep_pins_mx: usb_otg_hs_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
-		};
-	};
-
-	/* USER CODE BEGIN pinctrl */
-	/* USER CODE END pinctrl */
-};
-
-&pinctrl_z {
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN pinctrl_z */
-	/* USER CODE END pinctrl_z */
-};
-
-&m4_rproc{
-	mboxes = <&ipcc 0>, <&ipcc 1>, <&ipcc 2>;
-	mbox-names = "vq0", "vq1", "shutdown";
-	recovery;
-	status = "okay";
-
-	/* USER CODE BEGIN m4_rproc */
-	/* USER CODE END m4_rproc */
-};
-
-&adc{
-	status = "okay";
-
-	/* USER CODE BEGIN adc */
-	/* USER CODE END adc */
-};
-
-&bsec{
-	status = "okay";
-
-	/* USER CODE BEGIN bsec */
-	/* USER CODE END bsec */
-};
-
-&crc1{
-	status = "okay";
-
-	/* USER CODE BEGIN crc1 */
-	/* USER CODE END crc1 */
-};
-
-&cryp1{
-	status = "okay";
-
-	/* USER CODE BEGIN cryp1 */
-	/* USER CODE END cryp1 */
-};
-
-&dts{
-	status = "okay";
-
-	/* USER CODE BEGIN dts */
-	/* USER CODE END dts */
-};
-
-&ethernet0{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&eth1_pins_mx>;
-	pinctrl-1 = <&eth1_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN ethernet0 */
-	/* USER CODE END ethernet0 */
-};
-
-&gpu{
-	status = "okay";
-
-	/* USER CODE BEGIN gpu */
-	/* USER CODE END gpu */
-};
-
-&hash1{
-	status = "okay";
-
-	/* USER CODE BEGIN hash1 */
-	/* USER CODE END hash1 */
-};
-
-&hsem{
-	status = "okay";
-
-	/* USER CODE BEGIN hsem */
-	/* USER CODE END hsem */
-};
-
-&i2c2{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&i2c2_pins_mx>;
-	pinctrl-1 = <&i2c2_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN i2c2 */
-	/* USER CODE END i2c2 */
-};
-
-&ipcc{
-	status = "okay";
-
-	/* USER CODE BEGIN ipcc */
-	/* USER CODE END ipcc */
-};
-
-&iwdg2{
-	status = "okay";
-
-	/* USER CODE BEGIN iwdg2 */
-	/* USER CODE END iwdg2 */
-};
-
-&qspi{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&quadspi_pins_mx>;
-	pinctrl-1 = <&quadspi_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN qspi */
-	/* USER CODE END qspi */
-};
-
-&rcc{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN rcc */
-	/* USER CODE END rcc */
-};
-
-&rng1{
-	status = "okay";
-
-	/* USER CODE BEGIN rng1 */
-	/* USER CODE END rng1 */
-};
-
-&rtc{
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&rtc_pins_mx>;
-	pinctrl-1 = <&rtc_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN rtc */
-	/* USER CODE END rtc */
-};
-
-&sdmmc1{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "opendrain", "sleep";
-	pinctrl-0 = <&sdmmc1_pins_mx>;
-	pinctrl-1 = <&sdmmc1_opendrain_pins_mx>;
-	pinctrl-2 = <&sdmmc1_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN sdmmc1 */
-	/* USER CODE END sdmmc1 */
-};
-
-&uart4{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&uart4_pins_mx>;
-	pinctrl-1 = <&uart4_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN uart4 */
-	/* USER CODE END uart4 */
-};
-
-&usbh_ehci{
-	status = "okay";
-
-	/* USER CODE BEGIN usbh_ehci */
-	/* USER CODE END usbh_ehci */
-};
-
-&usbh_ohci{
-	status = "okay";
-
-	/* USER CODE BEGIN usbh_ohci */
-	/* USER CODE END usbh_ohci */
-};
-
-&usbotg_hs{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&usb_otg_hs_pins_mx>;
-	pinctrl-1 = <&usb_otg_hs_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN usbotg_hs */
-	/* USER CODE END usbotg_hs */
-};
-
-&usbphyc{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc */
-	/* USER CODE END usbphyc */
-};
-
-&usbphyc_port0{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc_port0 */
-	/* USER CODE END usbphyc_port0 */
-};
-
-&usbphyc_port1{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc_port1 */
-	/* USER CODE END usbphyc_port1 */
-};
-
-&vrefbuf{
-	status = "okay";
-
-	/* USER CODE BEGIN vrefbuf */
-	/* USER CODE END vrefbuf */
-};
-
-/* USER CODE BEGIN addons */
-/* USER CODE END addons */
-
diff --git a/recipes-kernel/linux/linux-stm32mp/stm32mp157c-t1001-som-minimal-mx.dts b/recipes-kernel/linux/linux-stm32mp/stm32mp157c-t1001-som-minimal-mx.dts
deleted file mode 100644
index 860db514df9845f933572d562ad27081c2ce609f..0000000000000000000000000000000000000000
--- a/recipes-kernel/linux/linux-stm32mp/stm32mp157c-t1001-som-minimal-mx.dts
+++ /dev/null
@@ -1,405 +0,0 @@
-/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
-/*
- * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
- * Author: STM32CubeMX code generation for STMicroelectronics.
- */
-
-/dts-v1/;
-#include "stm32mp157c.dtsi"
-#include "stm32mp157c-m4-srm.dtsi"
-#include "stm32mp157cad-pinctrl.dtsi"
-
-/* USER CODE BEGIN includes */
-/* USER CODE END includes */
-
-/ {
-	model = "STMicroelectronics custom STM32CubeMX board";
-	compatible = "st,stm32mp157c-t1001-som-minimal-mx", "st,stm32mp157";
-
-	memory@c0000000 {
-		reg = <0xc0000000 0x20000000>;
-
-		/* USER CODE BEGIN memory */
-		/* USER CODE END memory */
-	};
-
-	reserved-memory {
-		#address-cells = <1>;
-		#size-cells = <1>;
-		ranges;
-
-		/* USER CODE BEGIN reserved-memory */
-		/* USER CODE END reserved-memory */
-
-		gpu_reserved: gpu@dc000000 {
-			reg = <0xdc000000 0x4000000>;
-			no-map;
-		};
-	};
-
-	/* USER CODE BEGIN root */
-	/* USER CODE END root */
-
-	clocks {
-		/* USER CODE BEGIN clocks */
-		/* USER CODE END clocks */
-
-		clk_csi: clk-csi {
-			clock-frequency = <4000000>;
-		};
-
-		clk_lse: clk-lse {
-			clock-frequency = <32768>;
-		};
-
-		clk_hse: clk-hse {
-			clock-frequency = <24000000>;
-		};
-	};
-
-}; /*root*/
-
-&pinctrl {
-	u-boot,dm-pre-reloc;
-
-	quadspi_pins_mx: quadspi_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 6, AF10)>; /* QUADSPI_BK1_NCS */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('F', 6, AF9)>, /* QUADSPI_BK1_IO3 */
-					 <STM32_PINMUX('F', 7, AF9)>, /* QUADSPI_BK1_IO2 */
-					 <STM32_PINMUX('F', 8, AF10)>, /* QUADSPI_BK1_IO0 */
-					 <STM32_PINMUX('F', 9, AF10)>, /* QUADSPI_BK1_IO1 */
-					 <STM32_PINMUX('F', 10, AF9)>; /* QUADSPI_CLK */
-			bias-disable;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-	};
-
-	quadspi_sleep_pins_mx: quadspi_sleep_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 6, ANALOG)>, /* QUADSPI_BK1_NCS */
-					 <STM32_PINMUX('F', 6, ANALOG)>, /* QUADSPI_BK1_IO3 */
-					 <STM32_PINMUX('F', 7, ANALOG)>, /* QUADSPI_BK1_IO2 */
-					 <STM32_PINMUX('F', 8, ANALOG)>, /* QUADSPI_BK1_IO0 */
-					 <STM32_PINMUX('F', 9, ANALOG)>, /* QUADSPI_BK1_IO1 */
-					 <STM32_PINMUX('F', 10, ANALOG)>; /* QUADSPI_CLK */
-		};
-	};
-
-	sdmmc1_pins_mx: sdmmc1_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
-					 <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
-					 <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
-					 <STM32_PINMUX('C', 11, AF12)>, /* SDMMC1_D3 */
-					 <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 12, AF12)>; /* SDMMC1_CK */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-	};
-
-	sdmmc1_opendrain_pins_mx: sdmmc1_opendrain_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
-					 <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
-					 <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
-					 <STM32_PINMUX('C', 11, AF12)>; /* SDMMC1_D3 */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <1>;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 12, AF12)>; /* SDMMC1_CK */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <3>;
-		};
-		pins3 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
-			bias-pull-up;
-			drive-open-drain;
-			slew-rate = <1>;
-		};
-	};
-
-	sdmmc1_sleep_pins_mx: sdmmc1_sleep_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('C', 8, ANALOG)>, /* SDMMC1_D0 */
-					 <STM32_PINMUX('C', 9, ANALOG)>, /* SDMMC1_D1 */
-					 <STM32_PINMUX('C', 10, ANALOG)>, /* SDMMC1_D2 */
-					 <STM32_PINMUX('C', 11, ANALOG)>, /* SDMMC1_D3 */
-					 <STM32_PINMUX('C', 12, ANALOG)>, /* SDMMC1_CK */
-					 <STM32_PINMUX('D', 2, ANALOG)>; /* SDMMC1_CMD */
-		};
-	};
-
-	uart4_pins_mx: uart4_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins1 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 2, AF8)>; /* UART4_RX */
-			bias-pull-up;
-		};
-		pins2 {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('G', 11, AF6)>; /* UART4_TX */
-			bias-pull-up;
-			drive-push-pull;
-			slew-rate = <0>;
-		};
-	};
-
-	uart4_sleep_pins_mx: uart4_sleep_mx-0 {
-		u-boot,dm-pre-reloc;
-		pins {
-			u-boot,dm-pre-reloc;
-			pinmux = <STM32_PINMUX('B', 2, ANALOG)>, /* UART4_RX */
-					 <STM32_PINMUX('G', 11, ANALOG)>; /* UART4_TX */
-		};
-	};
-
-	usb_otg_hs_pins_mx: usb_otg_hs_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
-		};
-	};
-
-	usb_otg_hs_sleep_pins_mx: usb_otg_hs_sleep_mx-0 {
-		pins {
-			pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* USB_OTG_HS_ID */
-		};
-	};
-
-	/* USER CODE BEGIN pinctrl */
-	/* USER CODE END pinctrl */
-};
-
-&pinctrl_z {
-	u-boot,dm-pre-reloc;
-
-	/* USER CODE BEGIN pinctrl_z */
-	/* USER CODE END pinctrl_z */
-};
-
-&m4_rproc{
-	mboxes = <&ipcc 0>, <&ipcc 1>, <&ipcc 2>;
-	mbox-names = "vq0", "vq1", "shutdown";
-	recovery;
-	status = "okay";
-
-	/* USER CODE BEGIN m4_rproc */
-	/* USER CODE END m4_rproc */
-};
-
-&adc{
-	status = "okay";
-
-	/* USER CODE BEGIN adc */
-	/* USER CODE END adc */
-};
-
-&bsec{
-	status = "okay";
-
-	/* USER CODE BEGIN bsec */
-	/* USER CODE END bsec */
-};
-
-&crc1{
-	status = "okay";
-
-	/* USER CODE BEGIN crc1 */
-	/* USER CODE END crc1 */
-};
-
-&cryp1{
-	status = "okay";
-
-	/* USER CODE BEGIN cryp1 */
-	/* USER CODE END cryp1 */
-};
-
-&dts{
-	status = "okay";
-
-	/* USER CODE BEGIN dts */
-	/* USER CODE END dts */
-};
-
-&gpu{
-	status = "okay";
-
-	/* USER CODE BEGIN gpu */
-	/* USER CODE END gpu */
-};
-
-&hash1{
-	status = "okay";
-
-	/* USER CODE BEGIN hash1 */
-	/* USER CODE END hash1 */
-};
-
-&hsem{
-	status = "okay";
-
-	/* USER CODE BEGIN hsem */
-	/* USER CODE END hsem */
-};
-
-&ipcc{
-	status = "okay";
-
-	/* USER CODE BEGIN ipcc */
-	/* USER CODE END ipcc */
-};
-
-&iwdg2{
-	status = "okay";
-
-	/* USER CODE BEGIN iwdg2 */
-	/* USER CODE END iwdg2 */
-};
-
-&qspi{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&quadspi_pins_mx>;
-	pinctrl-1 = <&quadspi_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN qspi */
-	/* USER CODE END qspi */
-};
-
-&rcc{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN rcc */
-	/* USER CODE END rcc */
-};
-
-&rng1{
-	status = "okay";
-
-	/* USER CODE BEGIN rng1 */
-	/* USER CODE END rng1 */
-};
-
-&rtc{
-	status = "okay";
-
-	/* USER CODE BEGIN rtc */
-	/* USER CODE END rtc */
-};
-
-&sdmmc1{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "opendrain", "sleep";
-	pinctrl-0 = <&sdmmc1_pins_mx>;
-	pinctrl-1 = <&sdmmc1_opendrain_pins_mx>;
-	pinctrl-2 = <&sdmmc1_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN sdmmc1 */
-	/* USER CODE END sdmmc1 */
-};
-
-&uart4{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&uart4_pins_mx>;
-	pinctrl-1 = <&uart4_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN uart4 */
-	/* USER CODE END uart4 */
-};
-
-&usbh_ehci{
-	status = "okay";
-
-	/* USER CODE BEGIN usbh_ehci */
-	/* USER CODE END usbh_ehci */
-};
-
-&usbh_ohci{
-	status = "okay";
-
-	/* USER CODE BEGIN usbh_ohci */
-	/* USER CODE END usbh_ohci */
-};
-
-&usbotg_hs{
-	u-boot,dm-pre-reloc;
-	pinctrl-names = "default", "sleep";
-	pinctrl-0 = <&usb_otg_hs_pins_mx>;
-	pinctrl-1 = <&usb_otg_hs_sleep_pins_mx>;
-	status = "okay";
-
-	/* USER CODE BEGIN usbotg_hs */
-	/* USER CODE END usbotg_hs */
-};
-
-&usbphyc{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc */
-	/* USER CODE END usbphyc */
-};
-
-&usbphyc_port0{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc_port0 */
-	/* USER CODE END usbphyc_port0 */
-};
-
-&usbphyc_port1{
-	u-boot,dm-pre-reloc;
-	status = "okay";
-
-	/* USER CODE BEGIN usbphyc_port1 */
-	/* USER CODE END usbphyc_port1 */
-};
-
-&vrefbuf{
-	status = "okay";
-
-	/* USER CODE BEGIN vrefbuf */
-	/* USER CODE END vrefbuf */
-};
-
-/* USER CODE BEGIN addons */
-/* USER CODE END addons */
-
diff --git a/recipes-kernel/linux/linux-stm32mp/stmxceet-mp157-som.dts b/recipes-kernel/linux/linux-stm32mp/stmxceet-mp157-som.dts
new file mode 100644
index 0000000000000000000000000000000000000000..b77908addd66ec944f6a056f3ffaa0bb5d2b496a
--- /dev/null
+++ b/recipes-kernel/linux/linux-stm32mp/stmxceet-mp157-som.dts
@@ -0,0 +1,431 @@
+/* u-boot devicetree for device
+ *
+ * device   : stmxceet-mp157-som
+ * revision : prototype
+ *
+ * Copyright (c) 2018 exceet electronics GmbH
+ */
+
+#include <dt-bindings/gpio/gpio.h>
+#include "stm32mp157c-t1000-mx.dts"
+
+/ {
+	model = "stmxceet-mp157-som (linux)";
+	compatible = "ex,stmxceet-mp157-som", "st,stm32mp157";
+
+	chosen {
+		bootargs = "earlyprintk console=ttyS3,115200 root=/dev/ram";
+		stdout-path = "serial3:115200n8";
+	};
+
+	aliases {
+		ethernet0 = "/soc/ethernet@5800a000";
+		i2c1 = "/soc/i2c@40013000";
+		i2c2 = "/soc/i2c@5c002000";
+		mmc0 = "/soc/sdmmc@58005000";
+		mmc1 = "/soc/sdmmc@58007000";
+		spi0 = "/soc/qspi@58003000";
+	};
+
+	config {
+		/* u-boot led configuration */
+		u-boot,dm-pre-reloc;
+		u-boot,red-led = "stm32mp:red:status";
+		u-boot,green-led = "stm32mp:green:user";
+	};
+
+	leds:led {
+		compatible = "gpio-leds";
+		status = "okay";
+		red {
+			label = "stm32mp:red:status";
+			gpios = <&gpioa 13 GPIO_ACTIVE_LOW>;
+			default-state = "off";
+			linux,default-trigger = "heartbeat";
+			status = "okay";
+		};
+		green {
+			label = "stm32mp:green:user";
+			gpios = <&gpioa 14 GPIO_ACTIVE_LOW>;
+			default-state = "off";
+			linux,default-trigger = "heartbeat";
+			status = "okay";
+		};
+	};
+
+    /* Regulators */
+	vddcore: regulator-vddcore {
+		compatible = "regulator-fixed";
+		regulator-name = "vddcore";
+		regulator-min-microvolt = <1200000>;
+		regulator-max-microvolt = <1200000>;
+		regulator-always-on;
+	};
+
+	vdd_ddr: regulator-vdd_ddr {
+		compatible = "regulator-fixed";
+		regulator-name = "vdd_ddr";
+		regulator-min-microvolt = <1350000>;
+		regulator-max-microvolt = <1350000>;
+		regulator-always-on;
+	};
+
+	vdd_usb: regulator-vdd_usb {
+		compatible = "regulator-fixed";
+		regulator-name = "vdd_usb";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-always-on;
+	};
+
+	vdd: regulator-vdd {
+		compatible = "regulator-fixed";
+		regulator-name = "vdd";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-always-on;
+	};
+
+	v3v3: regulator-v3v3 {
+		compatible = "regulator-fixed";
+		regulator-name = "v3v3";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-always-on;
+	};
+
+	vdd_sd: regulator-vdd_sd {
+		compatible = "regulator-fixed";
+		regulator-name = "vdd_sd";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-always-on;
+	};
+
+	/* Analog reference voltage - may be adapted to board */
+	vdda: regulator-vdda {
+		compatible = "regulator-fixed";
+		regulator-name = "vdda";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-always-on;
+	};
+
+	/* Set reset_out to low */
+	reset_out: regulator-reset_out {
+		compatible = "regulator-fixed";
+		regulator-name = "reset_out";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		gpio = <&gpiod 15 GPIO_ACTIVE_HIGH>;
+		regulator-always-on;
+		regulator-boot-on;
+	};
+
+	/* Memory reservations */
+	reserved-memory {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		ipc_share: sram_rproc@10040000 {
+			compatible = "shared-dma-pool";
+			reg = <0x10040000 0x10000>;
+			no-map;
+		};
+
+		dma1_reserved: sram_dma1@10050000 {
+			reg = <0x10050000 0x8000>;
+			no-map;
+		};
+
+		dma2_reserved: sram_dma2@10058000 {
+			reg = <0x10058000 0x8000>;
+			no-map;
+		};
+
+		gcnano_reserved: gpu@f8000000 {
+			/* 128MB reserved for GPU (min 32MB, max 192MB) */
+			reg = <0xf8000000 0x8000000>;
+			no-map;
+		};
+	};
+
+};
+
+/* DEBUG: Disable reboot - REMOVE when not needed any more */
+//&rcc_reboot {
+//	mask = <0x0>;
+//	attention_patched;
+//};
+
+/* internal rtc */
+&rtc {
+	status = "okay";
+};
+
+
+/* i2c interfaces */
+&i2c2 {
+	clock-frequency = <400000>;
+	status = "okay";
+
+	gpio_exp:gpio_exp@20 {
+		compatible = "ti,tca6408";
+		reg = <0x20>;
+		gpio-controller;
+		#gpio-cells = <2>;
+	};
+};
+
+&i2c4 {
+	clock-frequency = <100000>;
+	status = "okay";
+};
+
+
+/* spi interfaces */
+&spi2 {
+	cs-gpios = <&gpioa 11 GPIO_ACTIVE_HIGH>;
+	status = "okay";
+};
+
+
+/* ADC settings */
+&adc {
+	/* ADC_INP5 is fast, ADC_INP16 is slow channel */
+
+	/* Use internal reference voltage */
+	/* vref-supply = <&vrefbuf>; */
+
+	/* Use external reference voltage */
+	vref-supply = <&vdda>;
+	status = "okay";
+
+
+	adc1: adc@0 {
+		st,adc-channels = <5 16>;
+		/* 16.5 ck_cycles sampling time */
+		st,min-sample-time-nsecs = <400>;
+		status = "okay";
+	};
+
+	jadc1: jadc@0 {
+		st,adc-channels = <5 16>;
+		/* 16.5 ck_cycles sampling time */
+		st,min-sample-time-nsecs = <400>;
+		status = "okay";
+	};
+
+	adc2: adc@100 {
+		status = "okay";
+	};
+
+	adc_temp: temp {
+		/* temperature sensor on adc2 */
+		status = "okay";
+	};
+
+};
+
+
+/* ethernet interface */
+&ethernet0 {
+	status = "okay";
+
+	phy-mode = "rmii";
+	max-speed = <100>;
+	phy-handle = <&phy0>;
+	st,int-phyclk;	/* Use internal clock for PHY (clocktree in tf-a must match) */
+
+	/* clock eth-ck is missing in ST SOC description. Here it is fixed.
+	 * Should be removed if ST definition is fixed (Beta1) */
+	clock-names = "stmmaceth",
+		      "mac-clk-tx",
+		      "mac-clk-rx",
+		      "ethstp",
+		      "syscfg-clk",
+			  "eth-ck";
+
+	clocks = <&rcc ETHMAC>,
+		 <&rcc ETHTX>,
+		 <&rcc ETHRX>,
+		 <&rcc ETHSTP>,
+		 <&rcc SYSCFG>,
+		 <&rcc ETHCK_K>;
+
+	mdio0 {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		compatible = "snps,dwmac-mdio";
+		phy0: ethernet-phy@1 {
+			reg = <1>;
+			/* Feature of Micrel PHY: set PHY config for 25MHz/50MHz
+			 * dependend on 'rmii-ref' clock */
+			clock-names = "rmii-ref";
+			clocks = <&rcc ETHCK_K>;
+		};
+	};
+};
+
+
+/* sd/mmc interfaces */
+&sdmmc1 {
+	broken-cd;
+	//cd-gpios = <&gpioa 10 GPIO_ACTIVE_HIGH>;
+	st,dirpol;
+	st,negedge;
+	no-1-8-v;
+	bus-width = <4>;
+	vmmc-supply = <&vdd_sd>;
+	status = "okay";
+};
+
+&sdmmc2 {
+	non-removable;
+	no-sd;
+	no-sdio;
+	st,dirpol;
+	st,negedge;
+	bus-width = <4>;
+	vmmc-supply = <&v3v3>;
+	status = "disabled";
+};
+
+
+/* qspi interface */
+&qspi {
+	#address-cells = <1>;
+	#size-cells = <0>;
+	status = "okay";
+
+	flash0: mx25r1635f@0 {
+		u-boot,dm-pre-reloc;
+		compatible = "spi-flash", "jedec,spi-nor";
+		reg = <0>;
+		spi-rx-bus-width = <4>;
+		spi-tx-bus-width = <4>;
+		spi-max-frequency = <8000000>; /* MX25R1635F is slow */
+
+		/* required for partitions when mtdparts in u-boot are used */
+		#address-cells = <1>;
+		#size-cells = <1>;
+	};
+#if 0
+	/* this confuses the driver */
+	flash1: spinand@1 {
+		u-boot,dm-pre-reloc;
+		compatible = "spi-nand";
+		reg = <1>;
+		spi-rx-bus-width = <4>;
+		spi-tx-bus-width = <4>;
+		spi-max-frequency = <104000000>;
+
+		/* required for partitions when mtdparts in u-boot are used */
+		#address-cells = <1>;
+		#size-cells = <1>;
+	};
+#endif
+};
+
+
+/* Internal ADC reference voltage */
+&vrefbuf {
+	/* Set referece voltage to 2.5V */
+	regulator-max-microvolt = <2500000>;
+	regulator-min-microvolt = <2500000>;
+	/*vdda-supply = <&vdd>;*/
+};
+
+
+/* USB settings */
+&usbh_ohci {
+    status = "disabled";
+};
+
+&usbh_ehci {
+	phys = <&usbphyc_port0>;
+	phy-names = "usb";
+	status = "okay";
+};
+
+&usbotg_hs {
+	phys = <&usbphyc_port1 0>;
+	phy-names = "usb2-phy";
+	//vbus-supply = <&vbus_otg>;
+	usb33d-supply = <&usb33>;
+	status = "okay";
+};
+
+&usbphyc {
+	vdda1v1-supply = <&reg11>;
+	vdda1v8-supply = <&reg18>;
+	status = "okay";
+};
+
+&usbphyc_port0 {
+	phy-supply = <&vdd_usb>;
+};
+
+&usbphyc_port1 {
+	phy-supply = <&vdd_usb>;
+};
+
+/* GPU settings */
+&gcnano {
+	contiguous-area = <&gcnano_reserved>;
+	status = "okay";
+};
+
+&rng1 {
+	status = "okay";
+};
+
+/* DMA settings */
+&dma1 {
+	memory-region = <&dma1_reserved>;
+};
+
+&dma2 {
+	memory-region = <&dma2_reserved>;
+};
+
+
+/* Independent watchdog */
+&iwdg2 {
+	timeout-sec = <32>;
+	status = "okay";
+};
+
+
+/* Power control */
+&pwr {
+	pwr-supply = <&vdd>;
+};
+
+
+/* uC interface */
+&ipcc {
+	status = "okay";
+};
+
+&m4_rproc {
+	memory-region = <&ipc_share>;
+	mboxes = <&ipcc 0>, <&ipcc 1>;
+	mbox-names = "vq0", "vq1";
+	interrupt-parent = <&exti>;
+	interrupts = <68 1>;
+	interrupt-names = "wdg";
+	status = "okay";
+};
+
+/* ========================================================================== */
+/* Mini board peripheral */
+
+&i2c2 {
+	/* Vishay VCNL4020 ambient sensor */
+	vcnl4000@13 {
+		compatible = "vishay,vcnl4000";
+		reg = <0x13>;
+	};
+};
diff --git a/recipes-kernel/linux/linux-stm32mp_4.14.bbappend b/recipes-kernel/linux/linux-stm32mp_4.14.bbappend
new file mode 100644
index 0000000000000000000000000000000000000000..504b5f640ed83ee10a04256df53deb4703fa5002
--- /dev/null
+++ b/recipes-kernel/linux/linux-stm32mp_4.14.bbappend
@@ -0,0 +1,104 @@
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
+
+# QSPI related patches (applies until #12)
+NOT_YET_PORTED_SRC_URI_append = " \
+    file://patches/0001-mtd-Add-sanity-checks-in-mtd_write-read_oob.patch \
+    file://patches/0002-mtd-mtdpart-Make-ECC-stat-handling-consistent.patch \
+    file://patches/0003-mtd-Fallback-to-_read-write_oob-when-_read-write-is-.patch \
+    file://patches/0004-spi-Check-presence-the-of-transfer-_xxx-before-regis.patch \
+    file://patches/0005-spi-Expose-spi_-map-unmap-_buf-for-internal-use.patch \
+    file://patches/0006-spi-Add-an-helper-to-flush-the-message-queue.patch \
+    file://patches/0007-spi-Extend-the-core-to-ease-integration-of-SPI-memor.patch \
+    file://patches/0008-spi-Make-support-for-regular-transfers-optional-when.patch \
+    file://patches/0009-spi-bcm-qspi-Implement-the-spi_mem-interface.patch \
+    file://patches/0010-spi-bcm53xx-Implement-the-spi_mem-interface.patch \
+    file://patches/0011-spi-ti-qspi-Implement-the-spi_mem-interface.patch \
+    file://patches/0012-mtd-spi-nor-Use-the-spi_mem_xx-API.patch \
+    file://patches/0013-spi-Get-rid-of-the-spi_flash_read-API.patch \
+    file://patches/0014-mtd-nand-move-raw-NAND-related-code-to-the-raw-subdi.patch \
+    file://patches/0015-mtd-nand-Add-core-infrastructure-to-deal-with-NAND-d.patch \
+    file://patches/0016-mtd-nand-Pass-mode-information-to-nand_page_io_req.patch \
+    file://patches/0017-mtd-nand-Add-core-infrastructure-to-support-SPI-NAND.patch \
+    file://patches/0018-dt-bindings-Add-bindings-for-SPI-NAND-devices.patch \
+    file://patches/0019-mtd-nand-spi-Add-initial-support-for-Micron-MT29F2G0.patch \
+    file://patches/0020-mtd-nand-spi-Add-initial-support-for-Winbond-W25M02G.patch \
+    file://patches/0021-spi-create-spi-mem-based-driver-for-stm32-QSPI.patch \
+    file://patches/0022-fixup-spi-create-spi-mem-based-driver-for-stm32-QSPI.patch \
+    file://patches/0023-mtd-nand-spi-Add-initial-support-for-Toshiba-TC58CVG.patch \
+    file://patches/0024-fixup-mtd-nand-Add-core-infrastructure-to-support-SP.patch \
+    "
+
+# common patches
+SRC_URI_append += " \
+    file://patches/0001-fix-add-CAD-definition-files.patch \
+    file://patches/0025-mtd-spi-nor-Add-support-for-Macronix-MX25V8035F.patch \
+    file://patches/0026-drm-panel-simple-Add-support-for-Admatec-T043C004800.patch \
+    file://patches/0027-add-SPI-NOR-mx25r1635f.patch \
+    file://patches/0002-linux-stm32mp-disable-spidev-warning-message.patch \
+    file://patches/0001-drm-panel-simple-Add-support-for-Admatec-T070P133T0S.patch \
+	"
+
+# add devicetree configuration for board
+SRC_URI_append += " \
+    file://stmxceet-mp157-som.dts \
+    file://stm32mp157c-t1000-mx.dts \
+    file://stm32mp-som-t1000.dtsi \
+    "
+
+# add board mini
+SRC_URI_append += " \
+    file://stm32mp-t1000-mini.dts \
+    file://stm32mp157c-t1000-mini-mx.dts \
+    file://stm32mp-board-mini.dtsi \
+    "
+
+# add board s-*
+SRC_URI_append += " \
+    file://stm32mp-t1000-s.dts \
+    file://stm32mp157c-t1000-s-mx.dts \
+    file://stm32mp-board-s.dtsi \
+    file://stm32mp-housing-43.dtsi \
+    file://stm32mp-t1000-s-43.dts \
+    file://stm32mp-housing-50.dtsi \
+    file://stm32mp-t1000-s-50.dts \
+    "
+
+
+# add kernel config patches
+SRC_URI_append += " \
+    file://4.14/fragment-01-config-gz.config;subdir=fragments \
+    file://4.14/fragment-02-pca953x.config;subdir=fragments \
+    file://4.14/fragment-03-vcnl4000.config;subdir=fragments \
+    file://4.14/fragment-04-spinand.config;subdir=fragments \
+    file://4.14/fragment-05-cpufreq.config;subdir=fragments \
+    file://4.14/fragment-06-fbdev-emulation.config;subdir=fragments \
+    file://4.14/fragment-07-wlan-marvell.config;subdir=fragments \
+    file://4.14/fragment-08-pwm-beeper.config;subdir=fragments \
+    "
+
+# This should work if you want to use a defconfig file, but is not tested yet!
+# Simply mentionning 'defconfig' isn't sufficient any more!
+#SRC_URI += "file://defconfig"
+#KERNEL_EXTERNAL_DEFCONFIG = defconfig
+KERNEL_CONFIG_FRAGMENTS += " \
+    ${WORKDIR}/fragments/4.14/fragment-01-config-gz.config \
+    ${WORKDIR}/fragments/4.14/fragment-02-pca953x.config \
+    ${WORKDIR}/fragments/4.14/fragment-03-vcnl4000.config \
+    ${WORKDIR}/fragments/4.14/fragment-04-spinand.config \
+    ${WORKDIR}/fragments/4.14/fragment-05-cpufreq.config \
+    ${WORKDIR}/fragments/4.14/fragment-06-fbdev-emulation.config \
+    ${WORKDIR}/fragments/4.14/fragment-07-wlan-marvell.config \
+    ${WORKDIR}/fragments/4.14/fragment-08-pwm-beeper.config \
+    "
+
+do_configure_prepend() {
+    echo "Sourcecode location is: ${S}"
+    for dtsfile in $(find ${WORKDIR} -maxdepth 1 -name "*.dts" -o -name "*.dtsi"); do
+        mkdir -p ${S}/arch/arm/boot/dts
+        echo "Copy file $dtsfile to dts directory"
+        cp ${dtsfile} ${S}/arch/arm/boot/dts/$(basename ${dtsfile})
+    done
+
+    #cp ${WORKDIR}/stmxceet-*_ddr.h ${S}/arch/arm/dts
+}
+
diff --git a/recipes-kernel/linux/linux-stm32mp_4.19.bbappend b/recipes-kernel/linux/linux-stm32mp_4.19.bbappend
deleted file mode 100644
index 3df565d0213db6c0b06a667917596c932b43d863..0000000000000000000000000000000000000000
--- a/recipes-kernel/linux/linux-stm32mp_4.19.bbappend
+++ /dev/null
@@ -1,346 +0,0 @@
-FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
-
-####################################################################################
-# Set source to stm git and respective URI
-# Version r2.0
-####################################################################################
-
-# 4.19.49 / r2.0: 9cc80ff80f5ea5f1ff35122f61afaa7b11ad22ae -->meta-st-stm32mp: rev=cc8dcc21ee8304bfafc02e86e60d7efbf6ad2dbd
-# 4.19.93 / r3.0: 1cb30cb5ffc29a53ec2031b6a29878ddd266516c --> meta-st-stm32mp: rev=96ba7e130e79bbb0e2db434495acc56641963013
-# 4.19.143 / r3.3: 24e698236f9c2197f9e4547075ec9647e8b99814 --> meta-st-stm32mp: rev=d8cbac759e1275b1a27d4ba38b64a0d83d0e8c9f
-
-SRCREV = "9cc80ff80f5ea5f1ff35122f61afaa7b11ad22ae"
-SRCREV_bleeding = "${AUTOREV}"
-SRC_URI="git://github.com/STMicroelectronics/linux.git;protocol=https;branch=v${LINUX_VERSION}-stm32mp;name=linux"
-
-SUBDIR_DIR = "git"
-S = "${WORKDIR}/${SUBDIR_DIR}"
-
-####################################################################################
-# patches and device trees
-####################################################################################
-
-# Fixes
-
-# Kernel 4.19.49
-PATCHLIST = "\
-	file://patches/0400-STMFIX-regulator-stm32-vrefbuf-fix-a-possible-overshoot-whe.patch \
-	file://patches/0401-fix-missing-eth-phy-clocks.patch \
-	file://patches/0402-spi-nand-fix-QSPI-NAND-bad-block-marking-issue.patch \
-	"
-# Features
-PATCHLIST += "\
-	file://patches/0500-linux-stm32mp-disable-spidev-warning-message.patch \
-	file://patches/0501-add-SPI-NOR-mx25r1635f.patch \
-	file://patches/0502-mtd-spi-nor-Add-support-for-Macronix-MX25V8035F.patch \
-	file://patches/0503-drm-panel-simple-Add-support-for-Admatec-T043C004800.patch \
-	file://patches/0504-drm-panel-simple-Add-support-for-Admatec-T070P133T0S.patch \
-	file://patches/0505-mtd-nand-spi-Add-initial-support-for-Toshiba-TC58CVG.patch \
-	file://patches/0506-sn65dsi83-Add-ti-sn85dsi83-dsi-to-lvds-bridge-driver.patch \
-	file://patches/0507-wm8510-switch-to-mclk-on-hw-init.patch \
-	file://patches/0508-add-spi-clock-debug-print.patch \
-	file://patches/0509-pinctl-disable-strict-checking.patch \
-	file://patches/0510-adv7511-mainline-5.4.x-code-integrated.patch \
-	file://patches/0511-dt-bindings-drm-bridge-adv7511-Add-ADV7535-support.patch \
-	file://patches/0512-drm-bridge-adv7511-Add-support-for-ADV7535.patch \
-	file://patches/0513-adapt-kernel-interfaces.patch \
-	file://patches/0301-stm-drm-driver-fetch-newest-source-code-from-st-repo.patch \
-	file://patches/0302-synopsys-dsi-driver-fetch-newest-source-code-from-st.patch \
-	file://patches/0303-drm-bridge-synopsys-dsi-fix-activation-sequence.patch \
-	file://patches/0304-drm-bridge-synopsys-dsi-cleanup-when-probe-fails.patch \
-	file://patches/0305-drm-bridge-synposys-dsi-fix-oops-in-drm-post_disable.patch \
-	file://patches/0306-drm_modes-suppress-error-for-hsync-vsync-flag.patch \
-	file://patches/0301-drm-stm-dsi-higher-pll-out-only-in-video-burst-mode.patch \
-	file://patches/0301-Add-mcp25xxfd-SPI-CANFD-driver.patch \
-	"
-
-# Kernel 4.19.94
-#PATCHLIST = "\
-#	file://patches/0401-fix-missing-eth-phy-clocks.patch \
-#	file://patches/0402-spi-nand-fix-QSPI-NAND-bad-block-marking-issue.patch \
-#	"
-## Features
-#PATCHLIST += "\
-#	file://patches/0500-linux-stm32mp-disable-spidev-warning-message.patch \
-#	file://patches/0501-add-SPI-NOR-mx25r1635f.patch \
-#	file://patches/0502-mtd-spi-nor-Add-support-for-Macronix-MX25V8035F.patch \
-#	file://patches/0503-drm-panel-simple-Add-support-for-Admatec-T043C004800.patch \
-#	file://patches/0504-drm-panel-simple-Add-support-for-Admatec-T070P133T0S.patch \
-#	file://patches/0505-mtd-nand-spi-Add-initial-support-for-Toshiba-TC58CVG.patch \
-#	file://patches/0506-sn65dsi83-Add-ti-sn85dsi83-dsi-to-lvds-bridge-driver.patch \
-#	file://patches/0507-wm8510-switch-to-mclk-on-hw-init.patch \
-#	file://patches/0508-add-spi-clock-debug-print.patch \
-#	file://patches/0509-pinctl-disable-strict-checking.patch \
-#	file://patches/0510-adv7511-mainline-5.4.x-code-integrated.patch \
-#	file://patches/0511-dt-bindings-drm-bridge-adv7511-Add-ADV7535-support.patch \
-#	file://patches/0512-drm-bridge-adv7511-Add-support-for-ADV7535.patch \
-#	file://patches/0513-adapt-kernel-interfaces.patch \
-#	file://patches/0303-drm-bridge-synopsys-dsi-fix-activation-sequence.patch \
-#	file://patches/0304-drm-bridge-synopsys-dsi-cleanup-when-probe-fails.patch \
-#	file://patches/0305-drm-bridge-synposys-dsi-fix-oops-in-drm-post_disable.patch \
-#	file://patches/0306-drm_modes-suppress-error-for-hsync-vsync-flag.patch \
-#	file://patches/0301-drm-stm-dsi-higher-pll-out-only-in-video-burst-mode.patch \
-#	file://patches/0301-Add-mcp25xxfd-SPI-CANFD-driver.patch \
-#	"
-
-# Kernel 4.19.143
-#PATCHLIST = "\
-#	file://patches/0401-fix-missing-eth-phy-clocks.patch \
-#	"
-## Features
-#PATCHLIST += "\
-#	file://patches/0500-linux-stm32mp-disable-spidev-warning-message.patch \
-#	file://patches/0501-add-SPI-NOR-mx25r1635f.patch \
-#	file://patches/0502-mtd-spi-nor-Add-support-for-Macronix-MX25V8035F.patch \
-#	file://patches/0503-drm-panel-simple-Add-support-for-Admatec-T043C004800.patch \
-#	file://patches/0504-drm-panel-simple-Add-support-for-Admatec-T070P133T0S.patch \
-#	file://patches/0505-mtd-nand-spi-Add-initial-support-for-Toshiba-TC58CVG.patch \
-#	file://patches/0507-wm8510-switch-to-mclk-on-hw-init.patch \
-#	file://patches/0508-add-spi-clock-debug-print.patch \
-#	file://patches/0509-pinctl-disable-strict-checking.patch \
-#	file://patches/0510-adv7511-mainline-5.4.x-code-integrated.patch \
-#	file://patches/0511-dt-bindings-drm-bridge-adv7511-Add-ADV7535-support.patch \
-#	file://patches/0512-drm-bridge-adv7511-Add-support-for-ADV7535.patch \
-#    file://patches/0513-adapt-kernel-interfaces.patch \
-#	file://patches/0303-drm-bridge-synopsys-dsi-fix-activation-sequence.patch \
-#	file://patches/0304-drm-bridge-synopsys-dsi-cleanup-when-probe-fails.patch \
-#	file://patches/0305-drm-bridge-synposys-dsi-fix-oops-in-drm-post_disable.patch \
-#	file://patches/0306-drm_modes-suppress-error-for-hsync-vsync-flag.patch \
-#	file://patches/0301-drm-stm-dsi-higher-pll-out-only-in-video-burst-mode.patch \
-#	"
-
-
-# Fixes
-PATCHLIST_bleeding = "\
-	file://patches/0401-fix-missing-eth-phy-clocks.patch \
-	file://patches/0402-spi-nand-fix-QSPI-NAND-bad-block-marking-issue.patch \
-	"
-PATCHLIST_bleeding += "\
-	file://patches/0500-linux-stm32mp-disable-spidev-warning-message.patch \
-	file://patches/0501-add-SPI-NOR-mx25r1635f.patch \
-	file://patches/0502-mtd-spi-nor-Add-support-for-Macronix-MX25V8035F.patch \
-	file://patches/0503-drm-panel-simple-Add-support-for-Admatec-T043C004800.patch \
-	file://patches/0504-drm-panel-simple-Add-support-for-Admatec-T070P133T0S.patch \
-	file://patches/0505-mtd-nand-spi-Add-initial-support-for-Toshiba-TC58CVG.patch \
-	file://patches/0506-sn65dsi83-Add-ti-sn85dsi83-dsi-to-lvds-bridge-driver.patch \
-	file://patches/0507-wm8510-switch-to-mclk-on-hw-init.patch \
-	file://patches/0508-add-spi-clock-debug-print.patch \
-	file://patches/0509-pinctl-disable-strict-checking.patch \
-	file://patches/0510-adv7511-mainline-5.4.x-code-integrated.patch \
-	file://patches/0511-dt-bindings-drm-bridge-adv7511-Add-ADV7535-support.patch \
-	file://patches/0512-drm-bridge-adv7511-Add-support-for-ADV7535.patch \
-	file://patches/0513-adapt-kernel-interfaces.patch \
-	"
-
-#
-#    file://${LINUX_VERSION}/4.19.94/0001-ARM-stm32mp1-r3-MACHINE.patch \
-#    file://${LINUX_VERSION}/4.19.94/0002-ARM-stm32mp1-r3-CPUFREQ.patch \
-#    file://${LINUX_VERSION}/4.19.94/0003-ARM-stm32mp1-r3-CRYPTO.patch \
-#    file://${LINUX_VERSION}/4.19.94/0004-ARM-stm32mp1-r3-BLUETOOTH-CHAR.patch \
-#    file://${LINUX_VERSION}/4.19.94/0005-ARM-stm32mp1-r3-CLOCK.patch \
-#    file://${LINUX_VERSION}/4.19.94/0006-ARM-stm32mp1-r3-DMA.patch \
-#    file://${LINUX_VERSION}/4.19.94/0007-ARM-stm32mp1-r3-DRM.patch \
-#    file://${LINUX_VERSION}/4.19.94/0008-ARM-stm32mp1-r3-GPIO.patch \
-#    file://${LINUX_VERSION}/4.19.94/0009-ARM-stm32mp1-r3-HWSPINLOCK.patch \
-#    file://${LINUX_VERSION}/4.19.94/0010-ARM-stm32mp1-r3-HWTRACING-I2C.patch \
-#    file://${LINUX_VERSION}/4.19.94/0011-ARM-stm32mp1-r3-IIO.patch \
-#    file://${LINUX_VERSION}/4.19.94/0012-ARM-stm32mp1-r3-INPUT-IRQ-Mailbox.patch \
-#    file://${LINUX_VERSION}/4.19.94/0013-ARM-stm32mp1-r3-MEDIA.patch \
-#    file://${LINUX_VERSION}/4.19.94/0014-ARM-stm32mp1-r3-MFD.patch \
-#    file://${LINUX_VERSION}/4.19.94/0015-ARM-stm32mp1-r3-MMC-MTD.patch \
-#    file://${LINUX_VERSION}/4.19.94/0016-ARM-stm32mp1-r3-NET.patch \
-#    file://${LINUX_VERSION}/4.19.94/0017-ARM-stm32mp1-r3-NVMEM.patch \
-#    file://${LINUX_VERSION}/4.19.94/0018-ARM-stm32mp1-r3-PERF.patch \
-#    file://${LINUX_VERSION}/4.19.94/0019-ARM-stm32mp1-r3-PHY-PINCTRL-PWM.patch \
-#    file://${LINUX_VERSION}/4.19.94/0020-ARM-stm32mp1-r3-REGULATOR.patch \
-#    file://${LINUX_VERSION}/4.19.94/0021-ARM-stm32mp1-r3-REMOTEPROC-RPMSG-RESET.patch \
-#    file://${LINUX_VERSION}/4.19.94/0022-ARM-stm32mp1-r3-RTC.patch \
-#    file://${LINUX_VERSION}/4.19.94/0023-ARM-stm32mp1-r3-SOC.patch \
-#    file://${LINUX_VERSION}/4.19.94/0024-ARM-stm32mp1-r3-SPI.patch \
-#    file://${LINUX_VERSION}/4.19.94/0025-ARM-stm32mp1-r3-THERMAL.patch \
-#	 file://${LINUX_VERSION}/4.19.94/0027-ARM-stm32mp1-r3-WATCHDOG.patch \
-#    file://${LINUX_VERSION}/4.19.94/0028-ARM-stm32mp1-r3-SOUND.patch \
-#	 file://${LINUX_VERSION}/4.19.94/0030-ARM-stm32mp1-r3-DEVICETREE.patch \
-#    file://${LINUX_VERSION}/4.19.94/0026-ARM-stm32mp1-r3-TTY-USB.patch \
-#    file://${LINUX_VERSION}/4.19.94/0029-ARM-stm32mp1-r3-MISC.patch \
-#
-
-#SRC_URI_append += "\
-#    file://${LINUX_VERSION}/4.19.94/0001-ARM-stm32mp1-r3-MACHINE.patch \
-#    file://${LINUX_VERSION}/4.19.94/0002-ARM-stm32mp1-r3-CPUFREQ.patch \
-#    file://${LINUX_VERSION}/4.19.94/0003-ARM-stm32mp1-r3-CRYPTO.patch \
-#    file://${LINUX_VERSION}/4.19.94/0004-ARM-stm32mp1-r3-BLUETOOTH-CHAR.patch \
-#    file://${LINUX_VERSION}/4.19.94/0005-ARM-stm32mp1-r3-CLOCK.patch \
-#    file://${LINUX_VERSION}/4.19.94/0006-ARM-stm32mp1-r3-DMA.patch \
-#    file://${LINUX_VERSION}/4.19.94/0007-ARM-stm32mp1-r3-DRM.patch \
-#    file://${LINUX_VERSION}/4.19.94/0008-ARM-stm32mp1-r3-GPIO.patch \
-#    file://${LINUX_VERSION}/4.19.94/0009-ARM-stm32mp1-r3-HWSPINLOCK.patch \
-#    file://${LINUX_VERSION}/4.19.94/0010-ARM-stm32mp1-r3-HWTRACING-I2C.patch \
-#    file://${LINUX_VERSION}/4.19.94/0011-ARM-stm32mp1-r3-IIO.patch \
-#    file://${LINUX_VERSION}/4.19.94/0012-ARM-stm32mp1-r3-INPUT-IRQ-Mailbox.patch \
-#    file://${LINUX_VERSION}/4.19.94/0013-ARM-stm32mp1-r3-MEDIA.patch \
-#    file://${LINUX_VERSION}/4.19.94/0014-ARM-stm32mp1-r3-MFD.patch \
-#    file://${LINUX_VERSION}/4.19.94/0015-ARM-stm32mp1-r3-MMC-MTD.patch \
-#    file://${LINUX_VERSION}/4.19.94/0016-ARM-stm32mp1-r3-NET.patch \
-#    file://${LINUX_VERSION}/4.19.94/0017-ARM-stm32mp1-r3-NVMEM.patch \
-#    file://${LINUX_VERSION}/4.19.94/0018-ARM-stm32mp1-r3-PERF.patch \
-#    file://${LINUX_VERSION}/4.19.94/0019-ARM-stm32mp1-r3-PHY-PINCTRL-PWM.patch \
-#    file://${LINUX_VERSION}/4.19.94/0020-ARM-stm32mp1-r3-REGULATOR.patch \
-#    file://${LINUX_VERSION}/4.19.94/0021-ARM-stm32mp1-r3-REMOTEPROC-RPMSG-RESET.patch \
-#    file://${LINUX_VERSION}/4.19.94/0022-ARM-stm32mp1-r3-RTC.patch \
-#    file://${LINUX_VERSION}/4.19.94/0023-ARM-stm32mp1-r3-SOC.patch \
-#    file://${LINUX_VERSION}/4.19.94/0024-ARM-stm32mp1-r3-SPI.patch \
-#    file://${LINUX_VERSION}/4.19.94/0025-ARM-stm32mp1-r3-THERMAL.patch \
-#	file://${LINUX_VERSION}/4.19.94/0027-ARM-stm32mp1-r3-WATCHDOG.patch \
-#    file://${LINUX_VERSION}/4.19.94/0028-ARM-stm32mp1-r3-SOUND.patch \
-#	file://${LINUX_VERSION}/4.19.94/0030-ARM-stm32mp1-r3-DEVICETREE.patch \
-#    file://${LINUX_VERSION}/4.19.94/0026-ARM-stm32mp1-r3-TTY-USB.patch \
-#    file://${LINUX_VERSION}/4.19.94/0029-ARM-stm32mp1-r3-MISC.patch \
-#    "
-
-# common patches
-SRC_URI_append += "${PATCHLIST}"
-
-# add board s-*
-SRC_URI_append += " \
-    file://stm32mp-t1000-s.dts \
-    file://stm32mp157c-t1000-s-mx.dts \
-    file://stm32mp-board-s.dtsi \
-    file://stm32mp-housing-43.dtsi \
-    file://stm32mp-t1000-s-43.dts \
-    file://stm32mp-housing-50.dtsi \
-    file://stm32mp-t1000-s-50.dts \
-    file://stm32mp-housing-24.dtsi \
-    file://stm32mp-t1000-s-24.dts \
-    file://stm32mp-t1000-s-clkout32k.dts \
-    "
-
-# add board k-*
-SRC_URI_append += " \
-    file://stm32mp-t1000-k.dts \
-    file://stm32mp157c-t1000-k-mx.dts \
-    file://stm32mp-board-k.dtsi \
-    file://stm32mp-housing-k-50.dtsi \
-    file://stm32mp-t1000-k-50.dts \
-    file://stm32mp-housing-k-70.dtsi \
-    file://stm32mp-t1000-k-70.dts \
-    file://stm32mp-housing-k-101.dtsi \
-    file://stm32mp-t1000-k-101.dts \
-    file://stm32mp-t1004-k.dts \
-    file://stm32mp-t1004-k-50.dts \
-    file://stm32mp-t1005-k.dts \
-    file://stm32mp-t1005-k-50.dts \
-    "
-
-# add board testadapter
-SRC_URI_append += " \
-    file://stm32mp-t1000-testadapter.dts \
-    "
-
-# add som virtual mini baseboard
-SRC_URI_append += " \
-    file://stm32mp-board-minimal.dtsi \
-    "
-
-# add som t1000/t1004/t1005
-SRC_URI_append += " \
-    file://stm32mp157c-t1000-som-minimal-mx.dts \
-    file://stm32mp-som-t1000.dtsi \
-    file://stm32mp-t1000.dts \
-    file://stm32mp-som-t1004.dtsi \
-    file://stm32mp-t1004.dts \
-    file://stm32mp-som-t1005.dtsi \
-    file://stm32mp-t1005.dts \
-    "
-
-# add som t1001
-SRC_URI_append += " \
-    file://stm32mp157c-t1001-som-minimal-mx.dts \
-    file://stm32mp-som-t1001.dtsi \
-    file://stm32mp-t1001.dts \
-    "
-
-
-####################################################################################
-# fragments from ST layer which wont copy because SRC_URI is overwritten
-####################################################################################
-
-SRC_URI += "file://4.19/fragment-03-systemd.config;subdir=fragments"
-SRC_URI += "file://4.19/fragment-04-optee.config;subdir=fragments"
-SRC_URI += "file://4.19/fragment-05-modules.config;subdir=fragments"
-
-
-####################################################################################
-# our fragments
-####################################################################################
-
-
-# add kernel config fragments
-SRC_URI_append += " \
-    file://4.19/fragment-01-config-gz.config;subdir=fragments \
-    file://4.19/fragment-02-pca953x.config;subdir=fragments \
-    file://4.19/fragment-03-vcnl4000.config;subdir=fragments \
-    file://4.19/fragment-04-spinand.config;subdir=fragments \
-    file://4.19/fragment-05-cpufreq.config;subdir=fragments \
-    file://4.19/fragment-06-fbdev-emulation.config;subdir=fragments \
-    file://4.19/fragment-07-wlan-marvell.config;subdir=fragments \
-    file://4.19/fragment-08-pwm-beeper.config;subdir=fragments \
-    file://4.19/fragment-09-early_printk.config;subdir=fragments \
-	file://4.19/fragment-10-gpio-sysfs.config;subdir=fragments \
-	file://4.19/fragment-11-wm8510-driver.config;subdir=fragments \
-	file://4.19/fragment-100-fbtft-st7789.config;subdir=fragments \
-	file://4.19/fragment-101-wlan-ralink53xx.config;subdir=fragments \
-	file://4.19/fragment-102-lvds-bridge-sn65dsi.config;subdir=fragments \
-	file://4.19/fragment-103-hdmi-bridge-adv.config;subdir=fragments \
-	file://4.19/fragment-104-touch-sis.config;subdir=fragments \
- 	"
-	
-
-# activate kernel config fragments
-KERNEL_CONFIG_FRAGMENTS_append += " \
-    ${WORKDIR}/fragments/4.19/fragment-01-config-gz.config \
-    ${WORKDIR}/fragments/4.19/fragment-02-pca953x.config \
-    ${WORKDIR}/fragments/4.19/fragment-03-vcnl4000.config \
-    ${WORKDIR}/fragments/4.19/fragment-04-spinand.config \
-    ${WORKDIR}/fragments/4.19/fragment-05-cpufreq.config \
-    ${WORKDIR}/fragments/4.19/fragment-06-fbdev-emulation.config \
-    ${WORKDIR}/fragments/4.19/fragment-07-wlan-marvell.config \
-    ${WORKDIR}/fragments/4.19/fragment-08-pwm-beeper.config \
-	${WORKDIR}/fragments/4.19/fragment-09-early_printk.config \
-	${WORKDIR}/fragments/4.19/fragment-10-gpio-sysfs.config \
-	${WORKDIR}/fragments/4.19/fragment-11-wm8510-driver.config \
-	${WORKDIR}/fragments/4.19/fragment-100-fbtft-st7789.config \
-	${WORKDIR}/fragments/4.19/fragment-101-wlan-ralink53xx.config \
-	${WORKDIR}/fragments/4.19/fragment-102-lvds-bridge-sn65dsi.config \
-	${WORKDIR}/fragments/4.19/fragment-103-hdmi-bridge-adv.config \
-	${WORKDIR}/fragments/4.19/fragment-104-touch-sis.config \
-    "
-	
-
-do_configure_prepend() {
-    echo "Sourcecode location is: ${S}"
-    for dtsfile in $(find ${WORKDIR} -maxdepth 1 -name "*.dts" -o -name "*.dtsi"); do
-        mkdir -p ${S}/arch/arm/boot/dts
-        echo "Copy file $dtsfile to dts directory"
-        cp ${dtsfile} ${S}/arch/arm/boot/dts/$(basename ${dtsfile})
-    done
-}
-
-do_buildenv[nostamp]="1"
-do_buildenv() {
-	{
-		echo "export MF=\"-j6 ARCH=arm O=${B} CROSS_COMPILE=${CROSS_COMPILE} LOADADDR=${ST_KERNEL_LOADADDR}\""
-		echo "export S=${S}"
-		echo "export O=${B}"
-		echo "export D=${D}"
-		echo "alias makey=\"make \${MF}\""
-		echo "echo Output directory O=${B}"
-		echo "echo Kernel source directory KDIR=${S}"
-		echo "echo Makeflags MF=\${MF}"
-		echo "echo CROSS_COMPILE=${CROSS_COMPILE}"
-		
-	} > ${S}/recipe.env
-}
-
-addtask buildenv after do_configure before do_devshell
-
diff --git a/recipes-ktn/board-tools/board-tools.bb b/recipes-ktn/board-tools/board-tools.bb
deleted file mode 100644
index 5d9df38004f99fa70a7f33dcb35d46757702be3c..0000000000000000000000000000000000000000
--- a/recipes-ktn/board-tools/board-tools.bb
+++ /dev/null
@@ -1,26 +0,0 @@
-FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
-FILESEXTRAPATHS_prepend := "${THISDIR}/files:"
-
-DESCRIPTION = "convenience tools for board peripherals"
-
-LICENSE = "GPLv2"
-LIC_FILES_CHKSUM = "file://${COREBASE}/meta/COPYING.GPLv2;md5=751419260aa954499f7abaabaa882bbe"
-
-PV = "1"
-PR = "r0"
-
-SRC_URI = "\
-	file://adcread \
-	file://rpmsg0 \
-	file://rpmsg1 \
-	"
-
-inherit allarch
-
-S="${WORKDIR}"
-
-do_install () {
-    install -Dm 0755 ${WORKDIR}/adcread ${D}${bindir}/adcread
-	install -Dm 0755 ${WORKDIR}/rpmsg0 ${D}${bindir}/rpmsg0
-	install -Dm 0755 ${WORKDIR}/rpmsg1 ${D}${bindir}/rpmsg1
-}
diff --git a/recipes-ktn/board-tools/files/adcread b/recipes-ktn/board-tools/files/adcread
deleted file mode 100755
index ec67cf6edf2a04a9612c085dc4fb399588a956f8..0000000000000000000000000000000000000000
--- a/recipes-ktn/board-tools/files/adcread
+++ /dev/null
@@ -1,127 +0,0 @@
-#!/bin/sh
-
-# example:
-#    read first adc channel of t1000 eval board
-#    >  adcread 0 5
-
-ADC_ID=${1}
-ADC_CHANNEL=${2}
-SYSFS_DIR=/sys/bus/iio/devices/iio:device${ADC_ID}
-SYSFS_VIN=${SYSFS_DIR}/in_voltage${ADC_CHANNEL}_raw
-ADC_REGS="/sys/kernel/debug/iio/iio:device${ADC_ID}/direct_reg_access"
-
-# Has to be adapted to external prescalers on board
-BOARD_SCALE=11
-
-print_help ()
-{
-    echo "Usage"
-    echo "    adcread ADC-INSTANCE ADC-CHANNEL"
-	echo ""
-    echo "Read ADC inputs with board prescaler"
-    echo ""
-    echo "On the second ADC instance (48003000.adc:adc@100) there are also internal voltages avilable:"
-    echo ""
-    echo "  Channel 13 - VREFINT (~1200mV)"
-    echo "  Channel 14 - VDDCORE (~1200mV)"
-    echo "  Channel 15 - VBAT"
-    echo "  Channel 16 - DAC_OUT1"
-    echo "  Channel 17 - DAC_OUT2"
-    echo ""
-    echo "If they are available and on which ADC-INSTANCE depends on your board"
-    
-}
-
-setup_adc ()
-{
-    local SYSFS_ADC1="/sys/devices/platform/soc/48003000.adc/48003000.adc:adc@0"
-    local SYSFS_ADC2="/sys/devices/platform/soc/48003000.adc/48003000.adc:adc@100"
-    local ADC2_REGS="/sys/kernel/debug/iio/iio:device1/direct_reg_access"
-    local MODE_REQ="on"
-    
-    # Disable power control for ADC1
-    if test -f "${SYSFS_ADC1}/power/control"; then
-        local mode=$(cat ${SYSFS_ADC1}/power/control)
-        if test "${mode}" != "${MODE_REQ}"; then
-            echo "Disable power autosuspend for ADC1" 1>&2
-            echo "${MODE_REQ}" > "${SYSFS_ADC1}/power/control"
-        fi
-    fi
-    
-    # Disable power control for ADC2
-    if test -f "${SYSFS_ADC2}/power/control"; then
-        local mode=$(cat ${SYSFS_ADC2}/power/control)
-        if test "${mode}" != "${MODE_REQ}"; then
-            echo "Disable power autosuspend for ADC2" 1>&2
-            echo "${MODE_REQ}" > "${SYSFS_ADC2}/power/control"
-        fi
-    fi
-
-    if test -f "${ADC2_REGS}"; then
-        # Also enable internal voltage measurements
-        #set bits if not set
-
-        ##vrefint and vbat
-        echo 0x208 > ${ADC2_REGS}
-        reg1=$(cat ${ADC2_REGS})
-        if test "$reg1" != "0x1C00000" ;then
-                echo "Enable VREFINT and VBAT bits" 1>&2
-                echo 0x208 0x1C00000 > ${ADC2_REGS}
-        fi
-        #vddcore
-        echo 0xd0 > ${ADC2_REGS}
-        reg1=$(cat ${ADC2_REGS})
-        if test "$reg1" != "0x1" ;then
-                echo "Enable VDDCOREEN bit" 1>&2
-                echo 0xd0 0x1 > ${ADC2_REGS}
-        fi
-    fi
-}
-
-case ${1} in
-	-h|--help|help)
-		print_help
-		exit 0
-		;;
-esac
-
-if test ! -e "${SYSFS_DIR}"; then
-    echo "ERROR: ADC device ${ADC_ID} doesn't exist"
-    exit 1
-fi
-
-if test ! -e "${SYSFS_VIN}"; then
-    echo "ERROR: ADC channel ${ADC_CHANNEL} on device ${ADC_ID} doesn't exist"
-    exit 1
-fi
-
-setup_adc
-
-if test -n "$(readlink ${SYSFS_DIR} | grep 48003000.adc:adc@100)"; then
-
-    # Set prescaler for internal ADC channels
-    # 13 - VREFINT (~1200mV)
-    # 14 - VDDCORE (~1200mV)
-    # 15 - VBAT
-    # 16 - DAC_OUT1
-    # 17 - DAC_OUT2
-    case ${ADC_CHANNEL} in
-    13|14|16|17)
-        BOARD_SCALE=1
-        ;;
-    15)
-        BOARD_SCALE=4
-        ;;
-    esac
-fi
-
-VIN_RAW=$(cat ${SYSFS_VIN})
-VIN_SCALE=$(cat ${SYSFS_DIR}/in_voltage_scale)
-VIN_OFFSET=$(cat ${SYSFS_DIR}/in_voltage_offset)
-VIN=$(awk "BEGIN{ printf (\"%d\", ( ${VIN_RAW} + ${VIN_OFFSET} ) * ${VIN_SCALE} * ${BOARD_SCALE} ) }")
-
-#echo "VIN_RAW ${VIN_RAW}"
-#echo "VIN_SCALE ${VIN_SCALE}"
-#echo "VIN_OFFSET ${VIN_OFFSET}"
-#echo "ADC${ADC_ID}:${ADC_CHANNEL}: ${VIN} mV (offset ${VIN_OFFSET}, scale ${VIN_SCALE})" 
-echo "ADC${ADC_ID}.${ADC_CHANNEL}: ${VIN} mV"
diff --git a/recipes-ktn/board-tools/files/rpmsg0 b/recipes-ktn/board-tools/files/rpmsg0
deleted file mode 100755
index 7761d36eb3c66f2738114ea5dd7576aad664b6e5..0000000000000000000000000000000000000000
--- a/recipes-ktn/board-tools/files/rpmsg0
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/bin/sh
-
-stty -onlcr -echo -F /dev/ttyRPMSG0 
-cat /dev/ttyRPMSG0 &
-PID=$!
-sleep 0.1s					#somehow necessary
-        echo "$1" > /dev/ttyRPMSG0		#write arg 1
-	sleep 0.1s				#wait for response
-kill $PID					#kill cat
-
-
-
diff --git a/recipes-ktn/board-tools/files/rpmsg1 b/recipes-ktn/board-tools/files/rpmsg1
deleted file mode 100755
index bf80e066526f05e9d1716bddc7f6c0ca8c40bff7..0000000000000000000000000000000000000000
--- a/recipes-ktn/board-tools/files/rpmsg1
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/bin/sh
-
-stty -onlcr -echo -F /dev/ttyRPMSG1 
-cat /dev/ttyRPMSG1 &
-PID=$!
-sleep 0.1s					#somehow necessary
-        echo "$1" > /dev/ttyRPMSG1		#write arg 1
-	sleep 0.1s				#wait for response
-kill $PID					#kill cat
-
-
-
diff --git a/recipes-ktn/kontron-demo/files/autostart-eglfs.env b/recipes-ktn/kontron-demo/files/autostart-eglfs.env
deleted file mode 100644
index 876bb4dc40b2a9927f76934d91ee971b4e61a8d2..0000000000000000000000000000000000000000
--- a/recipes-ktn/kontron-demo/files/autostart-eglfs.env
+++ /dev/null
@@ -1,6 +0,0 @@
-# Start eglfs application
-APPLICATION=/usr/bin/kontron-demo
-
-# Default with no setting is 'linuxfb'
-QT_QPA_PLATFORM=linuxfb
-#QT_QPA_PLATFORM=eglfs
diff --git a/recipes-ktn/production-tool/mptool/common/create-sd-card.sh b/recipes-ktn/production-tool/mptool/common/create-sd-card.sh
deleted file mode 100644
index 10c38459df517a8d7994e5155d4c54af6ac0053f..0000000000000000000000000000000000000000
--- a/recipes-ktn/production-tool/mptool/common/create-sd-card.sh
+++ /dev/null
@@ -1,662 +0,0 @@
-#!/bin/bash
-#=======================================================================
-#
-#          FILE: create-sd-card
-#
-#         USAGE: sudo ./create-sd-card
-#
-#   DESCRIPTION: generate recpective sd card with partitions and images 
-#                defined in config
-#
-#=======================================================================
-
-##############################################################################
-# Set configuration defaults
-##############################################################################
-FW_DIR="."
-IMG_NAME=""
-PROD_IMG="y"
-PROD_IMG_EXTRA_SIZE="300"
-PARTITION_LAYOUT="TFA TFA UBOOT BOROOTFS USERFS RESCUEFS"
-TFA_IMG="tf-a-unknown.stm32"
-TFA_IMG_SIZE="256"
-UBOOT_IMG="u-boot-unknown.stm32"
-UBOOT_SIZE="2"
-BOROOTFS_IMG="borootfs-unknown.tar.gz"
-USERFS_IMG="userfs-unknown.tar.gz"
-RESCUEFS="n"
-RESCUEFS_IMG="rescuefs-unknown.tar.gz"
-RESCUEFS_SIZE="45"
-
-
-CONFIG_PATH="sd-card.layout"
-PROD_IMG="y"
-VERBOSE=""
-
-#=======================================================================
-#	reads config file
-#	
-#	If config file is set by command line use this, else use 
-#	default config file
-#=======================================================================
-read_config_file ()
-{
-    while test "$1" != ""; do
-	case ${1} in
-	-c)
-		CONFIG_PATH=${2}
-		IMG_NAME=$(basename ${2} .layout).sdcard
-		shift
-		;;
-	esac
-	shift
-    done
-		
-    #source config
-    if test -f ${CONFIG_PATH} ;then
-	    . $(realpath ${CONFIG_PATH})
-    else
-	    echo "ERROR: config file <${CONFIG_PATH}> not found"
-	    exit 1
-    fi
-}
-
-#=======================================================================
-#	user interface shows help text
-#	input: -
-#	return: -
-#=======================================================================
-ui_show_help ()
-{
-	echo "Usage:"
-	echo "  create-sd-card.sh [FLAGS]"
-	echo 
-	echo "Flags and options"
-	echo "  Flags or options on commandline have higher priority"
-	echo "  -p y|n               Expand userfs and copy tar files to it (default y)"
-	echo "  -c <FILENAME>        Use alternate config file (default ist /etc/mptool.config)"
-	echo "  -u <DIRECTORY>       Set base directory for update files (default is FW_DIR)"
-	echo "  -n <FILENAME>        Set sd image output name (default is IMG_NAME)"
-	echo ""
-	echo "SD card image is placed alongside the tar files in FW_DIR"
-	echo ""
-}
-
-#=======================================================================
-#	parse command line and set environment variable from arguments
-#	Exits program if command line parsing fails
-#	input: command line arguments
-#	return: -
-#=======================================================================
-parse_cmdline()
-{
-    while test "$1" != ""; do
-
-	#echo "Processing parameter <${1}> / $*" 
-	
-	case ${1} in
-	-h | --help)
-		ui_show_help
-		exit 0
-		;;
-	-u)
-		FW_DIR=${2}
-		shift
-		;;
-	-n)
-		IMG_NAME=${2}
-		shift
-		;;
-		
-	-p)
-		PROD_IMG=${2}
-		shift
-		;;
-	-c)
-		# Configfile was parsed already earlier
-		shift
-		;;
-	-v)
-		# Verbose switch
-		VERBOSE=1
-		;;
-	-*)
-		echo "ERROR: Invalid option <${1}>"
-		exit 1
-		;;
-	*)
-		echo "ERROR: Invalid option <${1}>"
-		exit 1
-		;;
-	esac
-	shift
-    done
-    
-
-}
-
-
-
-
-#=======================================================================
-#
-# get sd* device
-#
-# outputs sd device to use
-#=======================================================================
-decide_sd_device () {
-    local  __resultvar=$1
-    
-    local mount_device=$(mount | grep "on / type" | cut -d' ' -f1 )        
-    mount_device=${mount_device%?}
-    
-    local sd_device
-    local confirmation=""
-    
-    
-    
-    while test "$confirmation" != "yes"
-    do
-	ls /dev | grep sd 
-	echo "select sd card device"
-	read sd_device
-	
-	
-	if [ "/dev/$sd_device" = "$mount_device" ]
-	then
-	    echo "================================"
-	    echo "ERROR: selected device is rootfs"
-	    echo "================================"
-	else
-	    echo "confirm device $sd_device"
-	    read confirmation
-	fi
-	
-    done
-    sd_device="/dev/$sd_device"
-    
-    eval $__resultvar="'$sd_device'"
-}
-
-#=======================================================================
-#
-# check_if_rescueos
-#
-# check recuefs var and modify PARTITION LAYOUT
-#=======================================================================
-check_if_rescueos () {
-    local __resultvar=$1
-    local checkvar=$2
-    local i=0
-    
-    
-    if test "$checkvar" != "y"
-    then
-	for val in ${PARTITION_LAYOUT} ;do
-	    
-	    if test "$val" != "RESCUEFS" ;then
-		part_array[$i]=$val
-		i=$((i+1))
-	    fi
-	done
-    else
-	for val in ${PARTITION_LAYOUT} ;do
-	    part_array[$i]=$val
-	    i=$((i+1))
-	done
-    fi
-    
-    eval $__resultvar="'${part_array[*]}'"
-}
-#=======================================================================
-#
-# check_all_imgs
-#
-# checks img from part_array
-#=======================================================================
-check_all_imgs () {
-    local local_parts=$*
-    local i=0
-    local img="_IMG"
-    
-    echo "Checking image files ..."
-    for part in ${local_parts[@]} 
-    do
-	# Generate list for image contents
-	combined_name="${part}${img}"
-	if test -z "${!combined_name}"; then
-	    PART_IMG[i]=":empty:"
-	else
-	    PART_IMG[i]=$FW_DIR/${!combined_name}
-	fi
-
-	# Generate list for production files
-	combined_name_prod="${part}${img}_PROD"
-	if test -v "${combined_name_prod}"; then
-	    echo "   ${combined_name_prod} is set"
-	    if test -z "${!combined_name_prod}"; then
-		PART_IMG_PROD[i]=":empty:"
-	    else
-		PART_IMG_PROD[i]=$FW_DIR/${!combined_name_prod}
-	    fi
-	else
-	    echo "   ${combined_name_prod} is not set, using sdcard defaults"
-	    PART_IMG_PROD[i]=${PART_IMG[i]}
-	fi
-
-	i=$((i+1))
-    done
-
-    # Check existence of files
-    echo "Checking if required files exist"
-    for file in ${PART_IMG[@]} ${PART_IMG_PROD[@]}; do
-	if test "${file}" = ":empty:"; then
-	    continue
-	fi
-	if test ! -f ${file}; then
-	    echo "   ERROR: image file <${file}> is missing"
-	    exit 1
-	else
-	    echo "   OK: ${file}"
-	fi
-    done
-
-
-    i=0
-    echo "Partition contents:"
-    for part in ${local_parts[@]} ; do
-	echo "   ${part}: ${PART_IMG[${i}]} (prod ${PART_IMG_PROD[${i}]})"
-	i=$((i+1))
-    done
-}
-#=======================================================================
-#
-# get partition size
-#
-# 
-#=======================================================================
-get_partition_size () {
-    local local_parts=$*
-    local i=0
-    local img="_SIZE"
-    
-    for part in ${local_parts[@]} 
-    do
-	combined_name="$part$img"
-	PART_SIZE[i]=${!combined_name}
-	i=$((i+1))
-    done
-}
-#=======================================================================
-#
-# unmount all partitions of dev
-#
-# 
-#=======================================================================
-unmount_all_parts () {
-    local device=$1
-    local i=1
-    local dev_short=$(echo "${device}" | cut -d '/' -f3)
-    local current_parts="$(ls /dev | grep $dev_short | awk 'NR=='$i'')" 
-    
-    while test "$current_parts" != "" 
-    do
-	if test -e "/dev/${current_parts}" ; then
-	    umount "/dev/$current_parts" 1>/dev/null 2>&1
-	fi
-	i=$((i+1))
-	
-	current_parts="$(ls /dev | grep $dev_short | awk 'NR=='$i'')"
-	
-    done
-        
-}
-#=======================================================================
-#
-# do partiotions
-#
-# 
-#=======================================================================
-
-do_sd_partitions () {
-    local __retdev=$1
-    local sd_img_dev=""
-    local i=0
-    local tfa_index=1
-    local tmp_dir=$(mktemp -d)
-    local tmp_file="${tmp_dir}/sfdisk.layout"
-    local size=0
-    local status
-    
-    echo "Create partitions ..."
-    
-    echo "label: gpt" > $tmp_file 
-    for part in ${PART_ARRAY[@]} 
-    do
-	#echo "$part"
-	if test "$part" == "TFA" 
-	then
-	    echo "size=256KiB, name=fsbl${tfa_index}" >> $tmp_file
-	    tfa_index=$((tfa_index+1))
-	    size=$((size+256))
-	elif test "$part" == "UBOOT"
-	then
-	    echo "size=${PART_SIZE[i]}MiB, name=ssbl" >> $tmp_file
-	    size=$((size+(PART_SIZE[i]*1024)))
-	elif test "$part" == "BOROOTFS"
-	then
-	    echo "size=${PART_SIZE[i]}MiB, name=boroot , attrs=\"LegacyBIOSBootable\"" >> $tmp_file
-	    size=$((size+(PART_SIZE[i]*1024)))
-	elif test "$part" == "USERFS"
-	then
-	    if test "$PROD_IMG" = "y"
-	    then
-		echo "size=$((PART_SIZE[i]+PROD_IMG_EXTRA_SIZE))MiB, name=userfs" >> $tmp_file
-		size=$((size+(PART_SIZE[i]+PROD_IMG_EXTRA_SIZE)*1024))
-	    else
-		echo "size=${PART_SIZE[i]}MiB, name=userfs" >> $tmp_file
-		size=$((size+(PART_SIZE[i]*1024)))
-	    fi
-	    
-	elif test "$part" == "RESCUEFS"
-	then
-	    echo "size=${PART_SIZE[i]}MiB, name=rescue-os" >> $tmp_file
-	    size=$((size+(PART_SIZE[i]*1024)))
-	fi
-	i=$((i+1))
-    done
-    
-    #create image
-    echo "   Calculated image size: $size kiB"
-    if test -e ${FW_DIR}/${IMG_NAME}
-    then
-	rm -rf ${FW_DIR}/{$IMG_NAME}
-    fi
-    dd if=/dev/zero of=${FW_DIR}/${IMG_NAME} bs=1k count=${size} 1>/dev/zero 2>&1
-    
-    sd_img_dev="$(losetup --show -f -P $FW_DIR/$IMG_NAME)"
-    
-    sfdisk -f -q $sd_img_dev < $tmp_file > /dev/null
-    
-    partprobe -d $sd_img_dev 1>/dev/zero 2>&1
-    
-    #rm $tmp_file
-    eval $__retdev="'${sd_img_dev}'"
-    
-    rm -rf ${tmp_dir}
-}
-
-#=======================================================================
-#
-# flash partitions
-# 
-#=======================================================================
-flash_partitions () {
-    local ret_val
-    local device=$1
-    local tmp_dir=$(mktemp -d)
-    local mnt_point="${tmp_dir}/sdcard-mount/"
-    local part_label="p"
-    mkdir -p $mnt_point 1>/dev/null 2>&1
-    local array_index=0
-    local dev_index=1
-    local prod_index=0
-    local status=0
-    
-    echo "Fill partitions ..."
-    for part in ${PART_ARRAY[@]} 
-    do
-	if [ "$part" == "TFA" -o "$part" == "UBOOT" ]; then
-	    if test "${PART_IMG[array_index]}" = ":empty:"; then
-		echo "   Skip filling ${part_array[array_index]} (part $dev_index)"
-	    else
-		echo "   Filling ${part_array[array_index]} (part $dev_index) with ${PART_IMG[array_index]}"
-		dd if=${PART_IMG[array_index]} of="${device}p$dev_index" conv=notrunc 1>/dev/null 2>&1
-	    fi
-	else
-	    mkfs.ext4 -F "${device}p$dev_index" 1>/dev/null 2>&1
-	    mkdir "${mnt_point}/${dev_index}" 1>/dev/null 2>&1
-	    mount "${device}p$dev_index" "${mnt_point}/${dev_index}" 1>/dev/null 2>&1
-	    ret_val=$?
-	    if test "$ret_val" != 0
-	    then
-		echo "problem with $part partition"
-		
-		rm -rf "${mnt_point}/${dev_index}" 1>/dev/null 2>&1
-		losetup -d "${device}"
-		rm -rf $mnt_point 1>/dev/null 2>&1
-		rm -rf ${tmp_dir}
-		exit 1
-	    else
-		if test "${PART_IMG[array_index]}" = ":empty:"; then
-		    echo "   Skip filling ${part_array[array_index]} (part $dev_index)"
-		else
-		    echo "   Filling ${part_array[array_index]} (part $dev_index) with ${PART_IMG[array_index]}"
-		    tar xf ${PART_IMG[array_index]} -C "${mnt_point}/${dev_index}" 1>/dev/null 2>&1
-		    status=$?
-		    if test $status != 0; then
-			echo "failed to burn ${PART_IMG[array_index]} to Partition $dev_index "
-			echo "Image partition size (${PART_SIZE[array_index]}MB) might not be enough"
-			echo "try increasing it"
-			umount "${mnt_point}/${dev_index}" 1>/dev/null 2>&1
-			rm -rf "${mnt_point}/${dev_index}" 1>/dev/null 2>&1
-			losetup -d "${device}"
-			rm -rf $mnt_point 1>/dev/null 2>&1
-			rm -rf ${tmp_dir}
-			exit 1
-		    fi
-		fi
-	    fi
-	    #prod img copy all images to userfs
-	    if [ "$PROD_IMG" == "y" ]; then
-		if [ "$part" == "USERFS" ]; then
-		    echo "Extending production image ..."
-		    for part in ${PART_ARRAY[@]} 
-		    do
-			if test "${PART_IMG_PROD[prod_index]}" != ":empty:"; then
-			    echo "   Writing ${PART_IMG_PROD[prod_index]}"
-			    cp ${PART_IMG_PROD[prod_index]} "${mnt_point}/${dev_index}"
-			fi
-			prod_index=$((prod_index+1))
-		    done
-		    echo "   Modify mptool.config"
-		    create_mptool_config "${mnt_point}/${dev_index}/mptool.config"
-		fi
-	    fi
-	    umount "${mnt_point}/${dev_index}" 1>/dev/null 2>&1
-	    rm -rf "${mnt_point}/${dev_index}" 1>/dev/null 2>&1
-	fi
-	array_index=$((array_index+1))
-	dev_index=$((dev_index+1))
-    done
-    losetup -d "${device}"
-    rm -rf $mnt_point 1>/dev/null 2>&1
-    rm -rf ${tmp_dir}
-}
-
-check_user_root ()
-{
-    if test "${USER}" != "root"; then
-	echo "ERROR: Script must be run as user 'root'. Please use sudo or something similar!" >&2
-	exit 1
-    fi
-}
-
-create_mptool_config ()
-{
-    local CONFIGFILE=${1}
-    
-    (
-	# Use subshell not to destroy script environment
-	
-	# Set dynamic defaults
-	if test ! -v TFA_IMG_PROD; then
-	    # not set -> set defaults
-	    TFA_IMG_PROD=${TFA_IMG}
-	fi
-	if test ! -v UBOOT_IMG_PROD; then
-	    # not set -> set defaults
-	    UBOOT_IMG_PROD=${UBOOT_IMG}
-	fi
-	if test ! -v BOROOTFS_IMG_PROD; then
-	    # not set -> set defaults
-	    BOROOTFS_IMG_PROD=${BOROOTFS_IMG}
-	fi
-	if test ! -v USERFS_IMG_PROD; then
-	    # not set -> set defaults
-	    USERFS_IMG_PROD=${USERFS_IMG}
-	fi
-	if test ! -v RESCUEFS_IMG_PROD; then
-	    # not set -> set defaults
-	    RESCUEFS_IMG_PROD=${RESCUEFS_IMG}
-	fi
-	
-	echo "# Generated file from create-sd-card.sh script"
-	echo "#"
-	echo "#TFA_IMG_PROD=${TFA_IMG_PROD}"
-	echo "#UBOOT_IMG_PROD=${UBOOT_IMG_PROD}"
-	echo "#BOROOTFS_IMG_PROD=${BOROOTFS_IMG_PROD}"
-	echo "#USERFS_IMG_PROD=${USERFS_IMG_PROD}"
-	echo "#RESCUEFS_IMG_PROD=${RESCUEFS_IMG_PROD}"
-	echo ""
-    
-	echo "FW_DIR=\"/usr/local\""
-	echo "PROD_LOG=\"/tmp/prod_log.txt\""
-	echo 
-	echo "# bootloaders"
-	echo "TFA_IMG=\"${TFA_IMG_PROD}\""
-	echo "UBOOT_IMG=\"${UBOOT_IMG_PROD}\""
-	echo 
-	echo "#boot + rootfs (SIZE in MiB)"
-	echo "BOROOTFS_IMG=\"${BOROOTFS_IMG_PROD}\""
-	echo 
-	echo "#userfs (if size empty -> all remaining space taken else SIZE in MiB)"
-	echo "USERFS_IMG=\"${USERFS_IMG_PROD}\""
-	echo
-	echo "#Rescue-os"
-	echo "RESCUEFS=\"${RESCUEFS}\""
-	echo "RESCUEFS_IMG=\"${RESCUEFS_IMG_PROD}\""
-
-    ) > ${CONFIGFILE}
-    
-    if test -n "${VERBOSE}"; then
-	echo "==== Begin mptool.cfg ===="
-	cat ${CONFIGFILE}
-	echo "==== End mptool.cfg ===="
-    fi
-}
-
-
-show_configuration ()
-{
-    echo "Selected configuration:"
-    echo "  FW_DIR              ${FW_DIR}"
-    echo "  IMG_NAME            ${IMG_NAME}"
-    echo "  PROD_IMG            ${PROD_IMG}"
-    echo "  RESCUEFS            ${RESCUEFS}"
-    echo ""
-    echo "Partition contens:"
-    echo "  TFA_IMG             ${TFA_IMG}"
-    echo "  UBOOT_IMG           ${UBOOT_IMG}"
-    echo "  BOROOTFS_IMG        ${BOROOTFS_IMG}"
-    echo "  USERFS_IMG          ${USERFS_IMG}"
-    echo "  RESCUEFS_IMG        ${RESCUEFS_IMG}"
-    echo ""
-    echo "Partition layouts:"
-    echo "  PARTITION_LAYOUT    ${PARTITION_LAYOUT}"
-    echo "  TFA_IMG_SIZE        ${TFA_IMG_SIZE}"
-    echo "  UBOOT_SIZE          ${UBOOT_SIZE}"
-    echo "  BOROOTFS_SIZE       ${BOROOTFS_SIZE}"
-    echo "  USERFS_SIZE         ${USERFS_SIZE}"
-    echo "  PROD_IMG_EXTRA_SIZE ${PROD_IMG_EXTRA_SIZE}"
-    echo "  RESCUEFS_SIZE       ${RESCUEFS_SIZE}"
-    echo ""
-    echo "Production configuration:"
-    if test ! -v TFA_IMG_PROD; then
-	# not set -> set defaults
-	echo "  TFA_IMG_PROD        -> sdcard contents"
-    else
-	echo "  TFA_IMG_PROD        ${TFA_IMG_PROD}"
-    fi
-
-    if test ! -v UBOOT_IMG_PROD; then
-	# not set -> set defaults
-	echo "  UBOOT_IMG_PROD      -> sdcard contents"
-    else
-	echo "  UBOOT_IMG_PROD      ${UBOOT_IMG_PROD}"
-    fi
-
-    if test ! -v BOROOTFS_IMG_PROD; then
-	# not set -> set defaults
-	echo "  BOROOTFS_IMG_PROD   -> sdcard contents"
-    else
-	echo "  BOROOTFS_IMG_PROD   ${BOROOTFS_IMG_PROD}"
-    fi
-
-    if test ! -v USERFS_IMG_PROD; then
-	# not set -> set defaults
-	echo "  USERFS_IMG_PROD     -> sdcard contents"
-    else
-	echo "  USERFS_IMG_PROD     ${USERFS_IMG_PROD}"
-    fi
-
-    if test ! -v RESCUEFS_IMG_PROD; then
-	# not set -> set defaults
-	echo "  RESCUEFS_IMG_PROD   -> sdcard contents"
-    else
-	echo "  RESCUEFS_IMG_PROD   ${RESCUEFS_IMG_PROD}"
-    fi
-    
-    echo ""
-}
-
-
-#=======================================================================
-#
-# main
-#
-# 
-#=======================================================================
-
-
-main () {
-    read_config_file $*
-    
-    parse_cmdline $*
-    
-    if test -n "${VERBOSE}"; then
-	show_configuration
-    fi
-    
-    check_user_root
-    
-    check_if_rescueos PART_ARRAY $RESCUEFS
-    
-    check_all_imgs ${PART_ARRAY[*]}
-    
-    get_partition_size ${PART_ARRAY[*]}
-    
-    do_sd_partitions IMG_DEVICE 
-    
-    flash_partitions $IMG_DEVICE
-    
-    echo ""
-    echo "Created image file: ${FW_DIR}/${IMG_NAME}"
-    echo ""
-    echo "You can burn this image to your sd card with this command"
-    echo "> dd if=${FW_DIR}/${IMG_NAME} bs=8M conv=fdatasync of=/dev/sd-yourdevice"
-    echo ""
-    echo "ATTENTION !!!"
-    echo "    Be careful! Use the correct device file for your sd card else you may"
-    echo "    DAMAGE your system!"
-    echo ""
-    
-}
-#=======================================================================
-#
-# 
-#
-# 
-#=======================================================================
-
-main $*
diff --git a/recipes-ktn/production-tool/mptool/common/image-ktn-ktn-eglfs-stm32mp-t1000-s-multi.layout b/recipes-ktn/production-tool/mptool/common/image-ktn-ktn-eglfs-stm32mp-t1000-s-multi.layout
deleted file mode 100755
index e33357717b8e69043306325827844bd19623edd3..0000000000000000000000000000000000000000
--- a/recipes-ktn/production-tool/mptool/common/image-ktn-ktn-eglfs-stm32mp-t1000-s-multi.layout
+++ /dev/null
@@ -1,13 +0,0 @@
-# image directory set by recipe
-FW_DIR="./.."
-
-TFA_IMG="tf-a-stm32mp-t1000-s-trusted.stm32"
-UBOOT_IMG="u-boot-stm32mp-t1000-s-trusted.stm32"
-
-# borootfs (boot + rootfs)
-BOROOTFS_IMG="image-ktn-ktn-eglfs-stm32mp-t1000-s-multi.tar.gz"
-BOROOTFS_SIZE="400"
-
-# userfs
-USERFS_IMG="image-ktn-ktn-eglfs-userfs-stm32mp-t1000-s-multi-thud.tar.gz"
-USERFS_SIZE="50"
diff --git a/recipes-ktn/production-tool/mptool/common/image-ktn-ktn-stm32mp-t1000-multi.layout b/recipes-ktn/production-tool/mptool/common/image-ktn-ktn-stm32mp-t1000-multi.layout
deleted file mode 100755
index 3461090d1f6da707a8d4dc46ebbbf7aaf233a156..0000000000000000000000000000000000000000
--- a/recipes-ktn/production-tool/mptool/common/image-ktn-ktn-stm32mp-t1000-multi.layout
+++ /dev/null
@@ -1,14 +0,0 @@
-# image directory set by recipe
-FW_DIR="./.."
-
-TFA_IMG="tf-a-stm32mp-t1000-trusted.stm32"
-UBOOT_IMG="u-boot-stm32mp-t1000-k-sdcard.stm32"
-UBOOT_IMG_PROD="u-boot-stm32mp-t1000-k-trusted.stm32"
-
-# borootfs (boot + rootfs)
-BOROOTFS_IMG="image-ktn-stm32mp-t1000-multi.tar.gz"
-BOROOTFS_SIZE="400"
-
-# userfs
-USERFS_IMG="image-ktn-userfs-stm32mp-t1000-multi-thud.tar.gz"
-USERFS_SIZE="50"
diff --git a/recipes-ktn/production-tool/mptool/common/image-ktn-ktn-stm32mp-t1000-s-multi.layout b/recipes-ktn/production-tool/mptool/common/image-ktn-ktn-stm32mp-t1000-s-multi.layout
deleted file mode 100755
index 3874208d31d50ac896205f5a5f7550b8ba20b959..0000000000000000000000000000000000000000
--- a/recipes-ktn/production-tool/mptool/common/image-ktn-ktn-stm32mp-t1000-s-multi.layout
+++ /dev/null
@@ -1,14 +0,0 @@
-# image directory set by recipe
-FW_DIR="./.."
-
-TFA_IMG="tf-a-stm32mp-t1000-s-trusted.stm32"
-UBOOT_IMG="u-boot-stm32mp-t1000-s-sdcard.stm32"
-UBOOT_IMG_PROD="u-boot-stm32mp-t1000-s-trusted.stm32"
-
-# borootfs (boot + rootfs)
-BOROOTFS_IMG="image-ktn-stm32mp-t1000-s-multi.tar.gz"
-BOROOTFS_SIZE="400"
-
-# userfs
-USERFS_IMG="image-ktn-userfs-stm32mp-t1000-s-multi-thud.tar.gz"
-USERFS_SIZE="50"
diff --git a/recipes-ktn/production-tool/mptool/common/image-ktn-ktn-stm32mp-t1000.layout b/recipes-ktn/production-tool/mptool/common/image-ktn-ktn-stm32mp-t1000.layout
deleted file mode 100755
index 937557395539d5e3db1854111ee32f61f9d2e6d1..0000000000000000000000000000000000000000
--- a/recipes-ktn/production-tool/mptool/common/image-ktn-ktn-stm32mp-t1000.layout
+++ /dev/null
@@ -1,15 +0,0 @@
-# image directory set by recipe
-FW_DIR="./.."
-PROD_IMG="y"
-
-TFA_IMG="tf-a-stm32mp-t1000-trusted.stm32"
-UBOOT_IMG="u-boot-stm32mp-t1000-sdcard.stm32"
-UBOOT_IMG_PROD="u-boot-stm32mp-t1000-trusted.stm32"
-
-# borootfs (boot + rootfs)
-BOROOTFS_IMG="image-ktn-stm32mp-t1000.tar.gz"
-BOROOTFS_SIZE="400"
-
-# userfs
-USERFS_IMG="image-ktn-userfs-stm32mp-t1000-thud.tar.gz"
-USERFS_SIZE="50"
diff --git a/recipes-ktn/production-tool/mptool/common/image-ktn-ktn-stm32mp-t1001.layout b/recipes-ktn/production-tool/mptool/common/image-ktn-ktn-stm32mp-t1001.layout
deleted file mode 100755
index c176e70611cd9dec35f6ca0c6b7b6e803c222331..0000000000000000000000000000000000000000
--- a/recipes-ktn/production-tool/mptool/common/image-ktn-ktn-stm32mp-t1001.layout
+++ /dev/null
@@ -1,15 +0,0 @@
-# image directory set by recipe
-FW_DIR="./.."
-PROD_IMG="n"
-
-TFA_IMG="tf-a-stm32mp-t1001-trusted.stm32"
-UBOOT_IMG="u-boot-stm32mp-t1001-sdcard.stm32"
-UBOOT_IMG_PROD="u-boot-stm32mp-t1001-trusted.stm32"
-
-# borootfs (boot + rootfs)
-BOROOTFS_IMG="image-ktn-stm32mp-t1001.tar.gz"
-BOROOTFS_SIZE="400"
-
-# userfs
-USERFS_IMG="image-ktn-userfs-stm32mp-t1001-thud.tar.gz"
-USERFS_SIZE="50"
diff --git a/recipes-ktn/production-tool/mptool/common/image-ktn-ktn-stm32mp-t1004.layout b/recipes-ktn/production-tool/mptool/common/image-ktn-ktn-stm32mp-t1004.layout
deleted file mode 100755
index 81b0e2844b66c99c9e3cd18c59bba596e2179366..0000000000000000000000000000000000000000
--- a/recipes-ktn/production-tool/mptool/common/image-ktn-ktn-stm32mp-t1004.layout
+++ /dev/null
@@ -1,15 +0,0 @@
-# image directory set by recipe
-FW_DIR="./.."
-PROD_IMG="y"
-
-TFA_IMG="tf-a-stm32mp-t1000-trusted.stm32"
-UBOOT_IMG="u-boot-stm32mp-t1004-sdcard.stm32"
-UBOOT_IMG_PROD="u-boot-stm32mp-t1004-trusted.stm32"
-
-# borootfs (boot + rootfs)
-BOROOTFS_IMG="image-ktn-stm32mp-t1004.tar.gz"
-BOROOTFS_SIZE="400"
-
-# userfs
-USERFS_IMG="image-ktn-userfs-stm32mp-t1004-thud.tar.gz"
-USERFS_SIZE="50"
diff --git a/recipes-ktn/production-tool/mptool/common/image-ktn-ktn-stm32mp-t1005.layout b/recipes-ktn/production-tool/mptool/common/image-ktn-ktn-stm32mp-t1005.layout
deleted file mode 100755
index b450026c0c55945521afadf4a8e428d2e37cc413..0000000000000000000000000000000000000000
--- a/recipes-ktn/production-tool/mptool/common/image-ktn-ktn-stm32mp-t1005.layout
+++ /dev/null
@@ -1,15 +0,0 @@
-# image directory set by recipe
-FW_DIR="./.."
-PROD_IMG="y"
-
-TFA_IMG="tf-a-stm32mp-t1000-trusted.stm32"
-UBOOT_IMG="u-boot-stm32mp-t1005-sdcard.stm32"
-UBOOT_IMG_PROD="u-boot-stm32mp-t1005-trusted.stm32"
-
-# borootfs (boot + rootfs)
-BOROOTFS_IMG="image-ktn-stm32mp-t1005.tar.gz"
-BOROOTFS_SIZE="400"
-
-# userfs
-USERFS_IMG="image-ktn-userfs-stm32mp-t1005-thud.tar.gz"
-USERFS_SIZE="50"
diff --git a/recipes-ktn/production-tool/mptool/common/image-ktn-qt-ktn-eglfs-stm32mp-t1000-s-multi.layout b/recipes-ktn/production-tool/mptool/common/image-ktn-qt-ktn-eglfs-stm32mp-t1000-s-multi.layout
deleted file mode 100755
index 0820e3888eed1999cd9e17de7013d3af8214eb7d..0000000000000000000000000000000000000000
--- a/recipes-ktn/production-tool/mptool/common/image-ktn-qt-ktn-eglfs-stm32mp-t1000-s-multi.layout
+++ /dev/null
@@ -1,13 +0,0 @@
-# image directory set by recipe
-FW_DIR="./.."
-
-TFA_IMG="tf-a-stm32mp-t1000-s-trusted.stm32"
-UBOOT_IMG="u-boot-stm32mp-t1000-s-trusted.stm32"
-
-# borootfs (boot + rootfs)
-BOROOTFS_IMG="image-ktn-qt-ktn-eglfs-stm32mp-t1000-s-multi.tar.gz"
-BOROOTFS_SIZE="500"
-
-# userfs
-USERFS_IMG="image-ktn-qt-ktn-eglfs-userfs-stm32mp-t1000-s-multi-thud.tar.gz"
-USERFS_SIZE="50"
diff --git a/recipes-ktn/production-tool/mptool/common/image-ktn-qt-ktn-stm32mp-t1000-multi.layout b/recipes-ktn/production-tool/mptool/common/image-ktn-qt-ktn-stm32mp-t1000-multi.layout
deleted file mode 100755
index 97d5a8d0be989f02220fcec8920788fc801cfc16..0000000000000000000000000000000000000000
--- a/recipes-ktn/production-tool/mptool/common/image-ktn-qt-ktn-stm32mp-t1000-multi.layout
+++ /dev/null
@@ -1,14 +0,0 @@
-# image directory set by recipe
-FW_DIR="./.."
-
-TFA_IMG="tf-a-stm32mp-t1000-trusted.stm32"
-UBOOT_IMG="u-boot-stm32mp-t1000-k-sdcard.stm32"
-UBOOT_IMG_PROD="u-boot-stm32mp-t1000-k-trusted.stm32"
-
-# borootfs (boot + rootfs)
-BOROOTFS_IMG="image-ktn-qt-stm32mp-t1000-multi.tar.gz"
-BOROOTFS_SIZE="500"
-
-# userfs
-USERFS_IMG="image-ktn-qt-userfs-stm32mp-t1000-multi-thud.tar.gz"
-USERFS_SIZE="50"
diff --git a/recipes-ktn/production-tool/mptool/common/image-ktn-qt-ktn-stm32mp-t1000-s-multi.layout b/recipes-ktn/production-tool/mptool/common/image-ktn-qt-ktn-stm32mp-t1000-s-multi.layout
deleted file mode 100755
index a044aae83c18833bc23c053398220769bde7149c..0000000000000000000000000000000000000000
--- a/recipes-ktn/production-tool/mptool/common/image-ktn-qt-ktn-stm32mp-t1000-s-multi.layout
+++ /dev/null
@@ -1,14 +0,0 @@
-# image directory set by recipe
-FW_DIR="./.."
-
-TFA_IMG="tf-a-stm32mp-t1000-s-trusted.stm32"
-UBOOT_IMG="u-boot-stm32mp-t1000-s-sdcard.stm32"
-UBOOT_IMG_PROD="u-boot-stm32mp-t1000-s-trusted.stm32"
-
-# borootfs (boot + rootfs)
-BOROOTFS_IMG="image-ktn-qt-stm32mp-t1000-s-multi.tar.gz"
-BOROOTFS_SIZE="500"
-
-# userfs
-USERFS_IMG="image-ktn-qt-userfs-stm32mp-t1000-s-multi-thud.tar.gz"
-USERFS_SIZE="50"
diff --git a/recipes-ktn/production-tool/mptool/common/image-stm32mp-console-ktn-eglfs-stm32mp-t1000-s-multi.layout b/recipes-ktn/production-tool/mptool/common/image-stm32mp-console-ktn-eglfs-stm32mp-t1000-s-multi.layout
deleted file mode 100755
index ad43e38e978cdfdec07009860a9b4ebc50f48b57..0000000000000000000000000000000000000000
--- a/recipes-ktn/production-tool/mptool/common/image-stm32mp-console-ktn-eglfs-stm32mp-t1000-s-multi.layout
+++ /dev/null
@@ -1,13 +0,0 @@
-# image directory set by recipe
-FW_DIR="./.."
-
-TFA_IMG="tf-a-stm32mp-t1000-s-trusted.stm32"
-UBOOT_IMG="u-boot-stm32mp-t1000-s-trusted.stm32"
-
-# borootfs (boot + rootfs)
-BOROOTFS_IMG="image-stm32mp-console-ktn-eglfs-stm32mp-t1000-s-multi.tar.gz"
-BOROOTFS_SIZE="400"
-
-# userfs
-USERFS_IMG="st-image-userfs-ktn-eglfs-stm32mp-t1000-s-multi.tar.gz"
-USERFS_SIZE="50"
diff --git a/recipes-ktn/production-tool/mptool/common/image-stm32mp-qt-ktn-eglfs-stm32mp-t1000-s-multi.layout b/recipes-ktn/production-tool/mptool/common/image-stm32mp-qt-ktn-eglfs-stm32mp-t1000-s-multi.layout
deleted file mode 100755
index f0f4e074b98a7cc6adb9844447976c2e63d6d100..0000000000000000000000000000000000000000
--- a/recipes-ktn/production-tool/mptool/common/image-stm32mp-qt-ktn-eglfs-stm32mp-t1000-s-multi.layout
+++ /dev/null
@@ -1,13 +0,0 @@
-# image directory set by recipe
-FW_DIR="./.."
-
-TFA_IMG="tf-a-stm32mp-t1000-s-trusted.stm32"
-UBOOT_IMG="u-boot-stm32mp-t1000-s-trusted.stm32"
-
-# borootfs (boot + rootfs)
-BOROOTFS_IMG="image-stm32mp-qt-ktn-eglfs-stm32mp-t1000-s-multi.tar.gz"
-BOROOTFS_SIZE="500"
-
-# userfs
-USERFS_IMG="st-image-userfs-ktn-eglfs-stm32mp-t1000-s-multi.tar.gz"
-USERFS_SIZE="50"
diff --git a/recipes-ktn/production-tool/mptool/common/sd-card.layout b/recipes-ktn/production-tool/mptool/common/sd-card.layout
deleted file mode 100644
index b5bcef39126e29b859b7c1b469e43d2c1e9735f0..0000000000000000000000000000000000000000
--- a/recipes-ktn/production-tool/mptool/common/sd-card.layout
+++ /dev/null
@@ -1,76 +0,0 @@
-##############################################################################
-# st32mp1 config eval board
-#
-# Example config for create-sd-card.sh
-# Commented out values are default values
-# Adapt it to your needs!
-##############################################################################
-
-##############################################################################
-# Input and output location
-##############################################################################
-# Image directory set by recipe - where to find images and where to create
-# sdcard image file
-#FW_DIR="."
-FW_DIR="./.."
-
-# Name of image file. Defaults to name of *.layout file replaced with 
-# '.sdcard' extension
-#IMG_NAME="sd-card.sdcard"
-
-##############################################################################
-# Production image (all tar copied to userfs)
-##############################################################################
-# Place your images also in userfs to ease updating internal flashes of your
-# device with mptool
-#PROD_IMG="y"
-# Increase configured userfs size to provide extra space for the update images
-#PROD_IMG_EXTRA_SIZE="300"
-
-# These are the images copied into userfs. If the variable is not set the
-# contents of the sd card are also copied into userfs. If the variable is set
-# the mentioned file is copied and if the variable is set, but empty ("")
-# copying is skipped
-#TFA_IMG_PROD=""
-#UBOOT_IMG=""
-#BOROOTFS_IMG=""
-#USERFS_IMG=""
-#RESCUEFS_IMG=""
-
-
-##############################################################################
-# Partition layout
-##############################################################################
-# Partition layout - no need to modify
-#PARTITION_LAYOUT="TFA TFA UBOOT BOROOTFS USERFS RESCUEFS"
-
-##############################################################################
-# Images
-##############################################################################
-# Put your images and partition sizes here
-# If the image name is empty the partition is created and formatted, but not
-# filled!
-
-# fist stage bootloader
-TFA_IMG="tf-a-stm32mp-t1000-trusted.stm32"
-#TFA_IMG_SIZE="256"
-
-# second stage bootloader
-# used for sdcard
-UBOOT_IMG="u-boot-stm32mp-t1000-k-sdcard.stm32"
-# used for flash contents
-UBOOT_IMG_PROD="u-boot-stm32mp-t1000-k-trusted.stm32"
-#UBOOT_SIZE="2"
-
-# borootfs (boot + rootfs)
-BOROOTFS_IMG="image-ktn-stm32mp-t1000-multi.tar.gz"
-BOROOTFS_SIZE="400"
-
-# userfs
-USERFS_IMG="image-ktn-userfs-stm32mp-t1000-multi-thud.tar.gz"
-USERFS_SIZE="50"
-
-# rescuefs
-#RESCUEFS="n"
-RESCUEFS_IMG="rescuefs.tar.gz"
-RESCUEFS_SIZE="45"
diff --git a/recipes-ktn/production-tool/mptool/stm32mp-t1000-multi/mptool.config b/recipes-ktn/production-tool/mptool/stm32mp-t1000-multi/mptool.config
deleted file mode 100644
index fa91b11c220401b7d41e9f27ce365ff8e44b401e..0000000000000000000000000000000000000000
--- a/recipes-ktn/production-tool/mptool/stm32mp-t1000-multi/mptool.config
+++ /dev/null
@@ -1,23 +0,0 @@
-##############################################################################
-# mptool config for stm32mp-t1000-multi
-#
-##############################################################################
-
-##############################################################################
-#tfa uboot image & NAND/EMMC
-##############################################################################
-
-# NAND/EMMC
-MEDIUM="NAND"
-
-#images
-TFA_IMG="tf-a-stm32mp-t1000-trusted.stm32"
-UBOOT_IMG="u-boot-stm32mp-t1000-trusted.stm32"
-
-#boot + rootfs (SIZE in MiB)
-BOROOTFS_IMG="image-ktn-qt-stm32mp-t1000-multi.tar.gz"
-BOROOTFS_SIZE="350"
-
-#userfs (if size empty -> all remaining space taken else SIZE in MiB)
-USERFS_IMG="image-ktn-qt-userfs-stm32mp-t1000-multi-thud.tar.gz"
-USERFS_SIZE="100"
diff --git a/recipes-ktn/production-tool/mptool/stm32mp-t1000-multi/mptool_EMMC.config b/recipes-ktn/production-tool/mptool/stm32mp-t1000-multi/mptool_EMMC.config
deleted file mode 100644
index e83d539f2f9f37bee05c86a7556d9827511ce8a5..0000000000000000000000000000000000000000
--- a/recipes-ktn/production-tool/mptool/stm32mp-t1000-multi/mptool_EMMC.config
+++ /dev/null
@@ -1,23 +0,0 @@
-##############################################################################
-# mptool config for stm32mp-t1000-multi
-#
-##############################################################################
-
-##############################################################################
-#tfa uboot image & NAND/EMMC
-##############################################################################
-
-# NAND/EMMC
-MEDIUM="EMMC"
-
-#images
-TFA_IMG="tf-a-stm32mp-t1000-trusted.stm32"
-UBOOT_IMG="u-boot-stm32mp-t1000-trusted.stm32"
-
-#boot + rootfs (SIZE in MiB)
-BOROOTFS_IMG="image-ktn-qt-stm32mp-t1000-multi.tar.gz"
-BOROOTFS_SIZE="500"
-
-#userfs (if size empty -> all remaining space taken else SIZE in MiB)
-USERFS_IMG="image-ktn-qt-userfs-stm32mp-t1000-multi-thud.tar.gz"
-USERFS_SIZE="500"
diff --git a/recipes-ktn/production-tool/mptool/stm32mp-t1000-s-multi/mptool.config b/recipes-ktn/production-tool/mptool/stm32mp-t1000-s-multi/mptool.config
deleted file mode 100644
index 55d0d541fcf035a64e1bbbd1a925a8994f971245..0000000000000000000000000000000000000000
--- a/recipes-ktn/production-tool/mptool/stm32mp-t1000-s-multi/mptool.config
+++ /dev/null
@@ -1,39 +0,0 @@
-##############################################################################
-# mptool config for stm32mp-t1000-s-multi
-#
-##############################################################################
-#image directory
-FW_DIR="/usr/local"
-
-# log file 
-PROD_LOG="/tmp/prod_log.txt"
-##############################################################################
-#tfa uboot image & NAND/EMMC
-##############################################################################
-
-# NAND/EMMC
-MEDIUM="NAND"
-
-#images
-TFA_IMG="tf-a-stm32mp-t1000-s-trusted.stm32"
-UBOOT_IMG="u-boot-stm32mp-t1000-s-trusted.stm32"
-
-#boot + rootfs (SIZE in MiB)
-BOROOTFS_IMG="image-ktn-qt-stm32mp-t1000-s-multi.tar.gz"
-BOROOTFS_SIZE="350"
-
-#userfs (if size empty -> all remaining space taken else SIZE in MiB)
-USERFS_IMG="image-ktn-qt-userfs-stm32mp-t1000-s-multi-thud.tar.gz"
-USERFS_SIZE="100"
-
-#Rescue-os
-RESCUEFS="n"
-RESCUEFS_IMG="rescuefs.tar.gz"
-RESCUEFS_SIZE="30"
-##############################################################################
-
-#optional hardware specific
-FSBL1_MTD_DEVICE=""
-FSBL2_MTD_DEVICE=""
-UBOOT_MTD_DEVICE=""
-UBI_MTD_DEVICE=""
diff --git a/recipes-ktn/production-tool/mptool/stm32mp-t1000-s-multi/mptool_EMMC.config b/recipes-ktn/production-tool/mptool/stm32mp-t1000-s-multi/mptool_EMMC.config
deleted file mode 100644
index b744fe0f0023f8722464a49aa99b23464860dd14..0000000000000000000000000000000000000000
--- a/recipes-ktn/production-tool/mptool/stm32mp-t1000-s-multi/mptool_EMMC.config
+++ /dev/null
@@ -1,39 +0,0 @@
-##############################################################################
-# mptool config for stm32mp-t1000-s-multi
-#
-##############################################################################
-#image directory
-FW_DIR="/usr/local"
-
-# log file 
-PROD_LOG="/tmp/prod_log.txt"
-##############################################################################
-#tfa uboot image & NAND/EMMC
-##############################################################################
-
-# NAND/EMMC
-MEDIUM="EMMC"
-
-#images
-TFA_IMG="tf-a-stm32mp-t1000-s-trusted.stm32"
-UBOOT_IMG="u-boot-stm32mp-t1000-s-trusted.stm32"
-
-#boot + rootfs (SIZE in MiB)
-BOROOTFS_IMG="image-ktn-qt-stm32mp-t1000-s-multi.tar.gz"
-BOROOTFS_SIZE="500"
-
-#userfs (if size empty -> all remaining space taken else SIZE in MiB)
-USERFS_IMG="image-ktn-qt-userfs-stm32mp-t1000-s-multi-thud.tar.gz"
-USERFS_SIZE="500"
-
-#Rescue-os
-RESCUEFS="n"
-RESCUEFS_IMG="rescuefs.tar.gz"
-RESCUEFS_SIZE="30"
-##############################################################################
-
-#optional hardware specific
-FSBL1_MTD_DEVICE=""
-FSBL2_MTD_DEVICE=""
-UBOOT_MTD_DEVICE=""
-UBI_MTD_DEVICE=""
diff --git a/recipes-ktn/production-tool/mptool/stm32mp-t1000/mptool.config b/recipes-ktn/production-tool/mptool/stm32mp-t1000/mptool.config
deleted file mode 100644
index 5606afcfbe04cc9433e62822a544d15c7933e569..0000000000000000000000000000000000000000
--- a/recipes-ktn/production-tool/mptool/stm32mp-t1000/mptool.config
+++ /dev/null
@@ -1,39 +0,0 @@
-##############################################################################
-# mptool config for stm32mp-t1000
-#
-##############################################################################
-#image directory
-FW_DIR="/usr/local"
-
-# log file 
-PROD_LOG="/tmp/prod_log.txt"
-##############################################################################
-#tfa uboot image & NAND/EMMC
-##############################################################################
-
-# NAND/EMMC
-MEDIUM="NAND"
-
-#images
-TFA_IMG="tf-a-stm32mp-t1000-trusted.stm32"
-UBOOT_IMG="u-boot-stm32mp-t1000-trusted.stm32"
-
-#boot + rootfs (SIZE in MiB)
-BOROOTFS_IMG="image-ktn-stm32mp-t1000.tar.gz"
-BOROOTFS_SIZE="400"
-
-#userfs (if size empty -> all remaining space taken else SIZE in MiB)
-USERFS_IMG="image-ktn-userfs-stm32mp-t1000-thud.tar.gz"
-USERFS_SIZE="50"
-
-#Rescue-os
-RESCUEFS="n"
-RESCUEFS_IMG="rescuefs.tar.gz"
-RESCUEFS_SIZE="30"
-##############################################################################
-
-#optional hardware specific
-FSBL1_MTD_DEVICE=""
-FSBL2_MTD_DEVICE=""
-UBOOT_MTD_DEVICE=""
-UBI_MTD_DEVICE=""
diff --git a/recipes-ktn/production-tool/mptool/stm32mp-t1001/mptool.config b/recipes-ktn/production-tool/mptool/stm32mp-t1001/mptool.config
deleted file mode 100644
index 58c26cc0a5817e6f69b869fa4820ef257e5c4a95..0000000000000000000000000000000000000000
--- a/recipes-ktn/production-tool/mptool/stm32mp-t1001/mptool.config
+++ /dev/null
@@ -1,39 +0,0 @@
-##############################################################################
-# mptool config for stm32mp-t1001
-#
-##############################################################################
-#image directory
-FW_DIR="/usr/local"
-
-# log file 
-PROD_LOG="/tmp/prod_log.txt"
-##############################################################################
-#tfa uboot image & NAND/EMMC
-##############################################################################
-
-# NAND/EMMC
-MEDIUM="EMMC"
-
-#images
-TFA_IMG="tf-a-stm32mp-t1001-trusted.stm32"
-UBOOT_IMG="u-boot-stm32mp-t1001-trusted.stm32"
-
-#boot + rootfs (SIZE in MiB)
-BOROOTFS_IMG="image-ktn-stm32mp-t1001.tar.gz"
-BOROOTFS_SIZE="400"
-
-#userfs (if size empty -> all remaining space taken else SIZE in MiB)
-USERFS_IMG="image-ktn-userfs-stm32mp-t1001-thud.tar.gz"
-USERFS_SIZE="50"
-
-#Rescue-os
-RESCUEFS="n"
-RESCUEFS_IMG="rescuefs.tar.gz"
-RESCUEFS_SIZE="30"
-##############################################################################
-
-#optional hardware specific
-FSBL1_MTD_DEVICE=""
-FSBL2_MTD_DEVICE=""
-UBOOT_MTD_DEVICE=""
-UBI_MTD_DEVICE=""
diff --git a/recipes-ktn/production-tool/mptool/stm32mp-t1004/mptool.config b/recipes-ktn/production-tool/mptool/stm32mp-t1004/mptool.config
deleted file mode 100644
index 448d93e74bdb7cfbcd34719531a04e97e152c541..0000000000000000000000000000000000000000
--- a/recipes-ktn/production-tool/mptool/stm32mp-t1004/mptool.config
+++ /dev/null
@@ -1,39 +0,0 @@
-##############################################################################
-# mptool config for stm32mp-t1000
-#
-##############################################################################
-#image directory
-FW_DIR="/usr/local"
-
-# log file 
-PROD_LOG="/tmp/prod_log.txt"
-##############################################################################
-#tfa uboot image & NAND/EMMC
-##############################################################################
-
-# NAND/EMMC
-MEDIUM="NAND"
-
-#images
-TFA_IMG="tf-a-stm32mp-t1000-trusted.stm32"
-UBOOT_IMG="u-boot-stm32mp-t1004-trusted.stm32"
-
-#boot + rootfs (SIZE in MiB)
-BOROOTFS_IMG="image-ktn-stm32mp-t1004.tar.gz"
-BOROOTFS_SIZE="400"
-
-#userfs (if size empty -> all remaining space taken else SIZE in MiB)
-USERFS_IMG="image-ktn-userfs-stm32mp-t1004-thud.tar.gz"
-USERFS_SIZE="50"
-
-#Rescue-os
-RESCUEFS="n"
-RESCUEFS_IMG="rescuefs.tar.gz"
-RESCUEFS_SIZE="30"
-##############################################################################
-
-#optional hardware specific
-FSBL1_MTD_DEVICE=""
-FSBL2_MTD_DEVICE=""
-UBOOT_MTD_DEVICE=""
-UBI_MTD_DEVICE=""
diff --git a/recipes-ktn/production-tool/mptool/stm32mp-t1005/mptool.config b/recipes-ktn/production-tool/mptool/stm32mp-t1005/mptool.config
deleted file mode 100644
index 706dbad35596240bab6bb363342b72e2e721d387..0000000000000000000000000000000000000000
--- a/recipes-ktn/production-tool/mptool/stm32mp-t1005/mptool.config
+++ /dev/null
@@ -1,39 +0,0 @@
-##############################################################################
-# mptool config for stm32mp-t1000
-#
-##############################################################################
-#image directory
-FW_DIR="/usr/local"
-
-# log file 
-PROD_LOG="/tmp/prod_log.txt"
-##############################################################################
-#tfa uboot image & NAND/EMMC
-##############################################################################
-
-# NAND/EMMC
-MEDIUM="NAND"
-
-#images
-TFA_IMG="tf-a-stm32mp-t1000-trusted.stm32"
-UBOOT_IMG="u-boot-stm32mp-t1005-trusted.stm32"
-
-#boot + rootfs (SIZE in MiB)
-BOROOTFS_IMG="image-ktn-stm32mp-t1005.tar.gz"
-BOROOTFS_SIZE="400"
-
-#userfs (if size empty -> all remaining space taken else SIZE in MiB)
-USERFS_IMG="image-ktn-userfs-stm32mp-t1005-thud.tar.gz"
-USERFS_SIZE="50"
-
-#Rescue-os
-RESCUEFS="n"
-RESCUEFS_IMG="rescuefs.tar.gz"
-RESCUEFS_SIZE="30"
-##############################################################################
-
-#optional hardware specific
-FSBL1_MTD_DEVICE=""
-FSBL2_MTD_DEVICE=""
-UBOOT_MTD_DEVICE=""
-UBI_MTD_DEVICE=""
diff --git a/recipes-ktn/production-tool/mptool_git.bb b/recipes-ktn/production-tool/mptool_git.bb
deleted file mode 100644
index 28b91b8bd4530063dfcf09679d9e4c13c764135a..0000000000000000000000000000000000000000
--- a/recipes-ktn/production-tool/mptool_git.bb
+++ /dev/null
@@ -1,70 +0,0 @@
-FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:${THISDIR}/${PN}/common:"
-
-DESCRIPTION = "mptool is used to run testing, production and serialization tasks on Linux hardware"
-
-LICENSE = "GPLv2"
-LIC_FILES_CHKSUM = "file://${COREBASE}/meta/COPYING.GPLv2;md5=751419260aa954499f7abaabaa882bbe"
-
-SRCBRANCH = "master"
-
-RDEPENDS_${PN} += "bash"
-
-#SRCREV = "${AUTOREV}"
-#PV = "1.0+git${SRCPV}"
-SRCREV = "54b25d5143bf96f80c8b7958a572ce7ac2f9a953"
-SRC_URI = "git://${KTN_GIT_APPS}/mptool.git;protocol=ssh;branch=${SRCBRANCH}"
-SRC_URI_http = "git://${KTN_GIT_APPS}/mptool.git;protocol=http;user=${KTN_GIT_USER}:${KTN_GIT_PWD};branch=${SRCBRANCH}"
-
-SRC_URI_append = "\
-	file://mptool.config;subdir=git \
-	file://create-sd-card.sh \
-	file://sd-card.layout \
-	file://image-stm32mp-console-ktn-eglfs-stm32mp-t1000-s-multi.layout \
-	file://image-stm32mp-qt-ktn-eglfs-stm32mp-t1000-s-multi.layout \
-	file://image-ktn-ktn-stm32mp-t1000-s-multi.layout \
-	file://image-ktn-qt-ktn-stm32mp-t1000-s-multi.layout \
-	file://image-ktn-qt-ktn-eglfs-stm32mp-t1000-s-multi.layout \
-	file://image-ktn-ktn-eglfs-stm32mp-t1000-s-multi.layout \
-	file://image-ktn-ktn-stm32mp-t1000.layout \
-	file://image-ktn-ktn-stm32mp-t1001.layout \
-	file://image-ktn-ktn-stm32mp-t1004.layout \
-	file://image-ktn-ktn-stm32mp-t1005.layout \
-	file://image-ktn-qt-ktn-stm32mp-t1000-multi.layout \
-	file://image-ktn-ktn-stm32mp-t1000-multi.layout \
-	"
-
-# Add extra EMMC configuration for Eval-Kits
-SRC_URI_append_stm32mp-t1000-s-multi += "file://mptool_EMMC.config;subdir=git"
-SRC_URI_append_stm32mp-t1000-multi += "file://mptool_EMMC.config;subdir=git"
-
-FILES_${PN} += "\
-	/usr \
-	/etc \
-	"
-S = "${WORKDIR}/git"
-
-do_install () {
-	install -Dm 0755 ${S}/mptool ${D}${bindir}/mptool
-	install -Dm 0755 ${S}/productionLib.sh ${D}/usr/lib/mptool/productionLib.sh	
-	install -Dm 0755 ${S}/mptool-classic ${D}${bindir}/mptool-classic
-	install -Dm 0755 ${S}/productionLib-classic.sh ${D}/usr/lib/mptool/productionLib-classic.sh	
-	install -d ${D}${sysconfdir}
-	install -Dm 0755 ${S}/mptool.config.fullsample ${D}${sysconfdir}/mptool.config.sample
-	install -Dm 0755 ${S}/mptool*.config ${D}${sysconfdir}
-}
-
-inherit deploy
-
-do_deploy () {
-	install -d ${DEPLOYDIR}/script-mp
-    install -m 0755 ${WORKDIR}/create-sd-card.sh ${DEPLOYDIR}/script-mp/
-    install -m 0755 ${WORKDIR}/sd-card.layout ${DEPLOYDIR}/script-mp/
-  
-  	bbnote "Searching for files ... ${DISTRO}-${MACHINE}.layout"
-	for layout in $(ls -1 ${WORKDIR}/*${DISTRO}-${MACHINE}.layout); do
-		bbnote cp ${layout} ${DEPLOYDIR}/script-mp/$(basename ${layout})
-		cp ${layout} ${DEPLOYDIR}/script-mp/$(basename ${layout})
-	done
-}
-
-addtask deploy before do_build after do_compile
diff --git a/recipes-qt/qt5/qtbase_%.bbappend b/recipes-qt/qt5/qtbase_%.bbappend
deleted file mode 100644
index 130f0ae291793bf907baa57d2dbbb404b2def2c9..0000000000000000000000000000000000000000
--- a/recipes-qt/qt5/qtbase_%.bbappend
+++ /dev/null
@@ -1,2 +0,0 @@
-PACKAGECONFIG_append_pn-qtbase = " kms gbm libinput cups fontconfig sm xkbcommon-evdev"
-QT_CONFIG_FLAGS_append = " -qpa linuxfb "
diff --git a/recipes-st/images/st-image-userfs.bbappend b/recipes-st/images/st-image-userfs.bbappend
deleted file mode 100644
index 06a8a279d45c9bb553999c334d1ea8cf7ba19ff6..0000000000000000000000000000000000000000
--- a/recipes-st/images/st-image-userfs.bbappend
+++ /dev/null
@@ -1,11 +0,0 @@
-# Reset PACKAGE_INSTALL
-PACKAGE_INSTALL = ""
-
-# Fix for creating empty userfs
-# Script in ST layer doesn't create an empty filesystem if the mountpoint doesn't exist. Fix it.
-IMAGE_PREPROCESS_COMMAND_prepend = "create_mountpoint;"
-
-create_mountpoint() {
-	mkdir -p ${IMAGE_ROOTFS}${IMAGE_PARTITION_MOUNTPOINT}
-	touch ${IMAGE_ROOTFS}${IMAGE_PARTITION_MOUNTPOINT}/dummy
-}
diff --git a/swupdate/recipes-bsp/libubootenv/libubootenv/fw_env.config b/swupdate/recipes-bsp/libubootenv/libubootenv/fw_env.config
deleted file mode 100644
index 934936526d497f7ced307e18e18452a9994700d6..0000000000000000000000000000000000000000
--- a/swupdate/recipes-bsp/libubootenv/libubootenv/fw_env.config
+++ /dev/null
@@ -1,15 +0,0 @@
-# Configuration file for fw_(printenv/setenv) utility.
-# Up to two entries are valid, in this case the redundant
-# environment sector is assumed present.
-# Notice, that the "Number of sectors" is not required on NOR and SPI-dataflash.
-# Futhermore, if the Flash sector size is omitted, this value is assumed to
-# be the same as the Environment size, which is valid for NOR and SPI-dataflash
-# Device offset must be prefixed with 0x to be parsed as a hexadecimal value.
-
-# NOR example
-# MTD device name   Device offset   Env. size   Flash sector size   Number of sectors
-/dev/mtd3          0x0000          0x4000      0x10000
-
-# For Mini Board without NAND
-#/dev/mtd0           0x40000         0x4000      0x10000
-
diff --git a/swupdate/recipes-bsp/libubootenv/libubootenv_%.bbappend b/swupdate/recipes-bsp/libubootenv/libubootenv_%.bbappend
deleted file mode 100644
index 5cd3253373e8efc235ead807eef3ceea3911cbe4..0000000000000000000000000000000000000000
--- a/swupdate/recipes-bsp/libubootenv/libubootenv_%.bbappend
+++ /dev/null
@@ -1,8 +0,0 @@
-FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
-
-SRC_URI_append += " file://fw_env.config"
-
-do_install_append () {
-	install -d ${D}${sysconfdir}
-	install -m 0644 ${WORKDIR}/fw_env.config ${D}${sysconfdir}/fw_env.config
-}
diff --git a/swupdate/recipes-swupdate/rescue-os/rescue-os.bbappend b/swupdate/recipes-swupdate/rescue-os/rescue-os.bbappend
deleted file mode 100644
index b652cba2876df70d772b35784c73124fb40f0199..0000000000000000000000000000000000000000
--- a/swupdate/recipes-swupdate/rescue-os/rescue-os.bbappend
+++ /dev/null
@@ -1,17 +0,0 @@
-# Special packages
-IMAGE_INSTALL += "\
-	${@bb.utils.contains('DISTRO_FEATURES', 'systemd', 'systemd-networkd-configuration', '', d)} \
-	${@bb.utils.contains('DISTRO_FEATURES', 'systemd', 'systemd-analyze', '', d)} \
-	"
-	
-IMAGE_INSTALL_remove = " resize-helper systemd-mount-partitions "
-
-#define kernel and device tree for rescuefs
-EXTRA_RESCUEFS_FILES="\
-					uImage \
-					stm32mp-t1000-s-50.dtb \
-					"
-
-
-
-
diff --git a/swupdate/recipes-swupdate/st-image-appends/st-image-userfs.bbappend b/swupdate/recipes-swupdate/st-image-appends/st-image-userfs.bbappend
deleted file mode 100644
index 16f2bb1af2ebf37abef87f392273f0db7e7dd195..0000000000000000000000000000000000000000
--- a/swupdate/recipes-swupdate/st-image-appends/st-image-userfs.bbappend
+++ /dev/null
@@ -1,3 +0,0 @@
-PACKAGE_INSTALL_append = " \
-		${@bb.utils.contains('DISTRO_FEATURES', 'swupdate', 'add-update-files', '', d)} \
-				" 
\ No newline at end of file