uboot source code init for ADT4

BUG:243826112

build cmd:
./fip/mk sc2_ah212 --avb2 --vab --fastboot-write --build-nogit

bl2: 566a5d185332e3c36a1e484adc77c3d797a406b0
bl30: c377f94e241b4d2c37cf6699b508b908633b5e87
bl31: 7f1d253c16ef0e841ad6dbbd3afff7de883f7349
bl32: c0a6c90a271da4a08485b094e5d7417947548244
bl33: 46db68c8d4bea61905c41bd285110f8684e7ad8a
bl40: c5485a46f6aaf5844db5ecef7d4b7cef7e1aedbf
soc:  cc65bc9fb0915ee9dd7e7ae2dc08f74f446a6cad
fip: c8e2beee706928e068f75e721a2003a3ec5e1dba

Change-Id: I2277d2a8c8c25026102a7e86fce7a6045e8b30b1
Signed-off-by: Liang Ji <liang.ji@amlogic.com>
diff --git a/bl2/bin/LICENSE.TXT b/bl2/bin/LICENSE.TXT
new file mode 100755
index 0000000..6816c08
--- /dev/null
+++ b/bl2/bin/LICENSE.TXT
@@ -0,0 +1,334 @@
+                      SOFTWARE LICENSE AGREEMENT
+
+
+This Software License Agreement (the "Agreement") is entered into as of August 10, 2017 (the
+"Effictive Date"), by and between AMLOGIC (CA) CO., INC., with principal office at 2518
+Mission College Blvd., Suite 120, Santa Clara, CA 95054, USA ("Amlogic"), with a place of business
+ at 1600 Amphitheatre Parkway, Mountain View, California 94043, USA ("Licensee"). The parties
+agree as follows:
+
+      1.    DEFINITIONS.
+
+             1.1  "Authorized Location" shall mean the location set forth in the applicable
+ Software Description Form in the form attached hereto as Exhibit A, or if none is listed, then the
+address for Licensee set forth above.
+
+             1.2  "Authorized Licensee Product" means the specific product listed in the
+applicable Software Description Form, or if none is listed, then any system level product sold by
+Licensee that incorporates the Amlogic Product and the Software or Derivative Work and
+includes other hardware and software provided by Licensee.
+
+             1.3  "Amlogic Product" means any of the proprietary integrated circuit
+product(s) sold by Amlogic with which the Software was designed to be used.
+
+             1.4  "Derivative Work" means any discrete modification to the Software made
+by Licensee pursuant to this agreement and any modified, altered, enhanced or adapted version
+of the Software, or derivative work thereof (as that term is defined under United States copyright
+ law) based on the Software.
+
+             1.5  "End User Agreement" means a written, legally enforceable agreement
+that (i) stipulates that the Software is licensed, not sold, and that title to and ownership of the
+ Software and any portion thereof remain with Amlogic or its licensors; (ii) disclaims all express
+and implied warranties on behalf of Amlogic, and exclude liability of Amlogic and its licensors
+ for any special, indirect, exemplary, incidental or consequential damages; and (iii) prohibits the
+end user from (a) copying the Software, except as reasonably necessary for internal back-up
+purposes, (b) using andlor transferring the Software to any third party apart from a Authorized
+Licensee Product, (c) modifying the Software, (d) attempting to reverse engineer, decompile or
+disassemble any portion of the Software, or (e) exporting the Software or any underlying
+technology in contravention of any applicable U.S. or foreign export laws and regulations.
+
+             1.6  "Object Code" means those portions of the Software, if any, furnished to
+Licensee in object code or machine readable form, including, without limitation, any bit images
+or other binary files for FPGAs.
+
+             1.7  "Software" shall mean that software provided by Amlogic to Licensee
+ from time to time and which is described in a Software Description Form executed by the parties
+ that references this Agreement.
+             1.8  "Source Code" means those portions ofthe Software, if any, furnished to
+Licensee in source code or human readable form, including, without limitation, any Verilog,
+HTL or RTL code.
+
+      2.    LICENSEE GRANT; OWNERSHIP.
+
+            2.1    License Grants. Subject to the terms and conditions of this Agreement,
+Amlogic hereby grants to Licensee, under all of Amlogic' s intellectual property rights in and to
+the Software, a limited, non-exclusive, non-transferable, royalty-free license (i) to use, modify
+and create Derivative Works from the Source Code, and to use the Object Code, without right to
+ sublicense, solely at the Authorized Location, solely for the purpose of incorporating the
+ Software or Derivative Works in Authorized Licensee Products for use solely with the Amlogic
+ Product, and only if in compliance with Section 2.2 below; and (ii) to reproduce, distribute and
+ sublicense, in object code form only, copies ofthe Software or Derivative Works only to be
+ incorporated in Authorized Licensee Products for use solely with the Amlogic Product to
+resellers, distributors and end users of such Authorized Licensee Products, and only if in
+compliance with Section 2.3 below.
+
+            2.2    Restriction on Modification. If and to the extent that the Software is
+designed to be compliant with any published standard (including, without limitation, DOCSIS,
+ HomePNA, IEEE, and ITU standards), Licensee may not make any modifications to the
+ Software that would cause the Software or the accompanying Amlogic Products to be
+ incompatible with such standard.
+
+            2.3    Restriction on Distribution. Licensee shall only distribute the Software
+or Derivative Works to resellers, distributors and end users either (a) physically embedded in the
+Authorized Licensee Products in a manner that is not readily accessible to end users; or
+(b) pursuant to an End User Agreement. By way of example only, an End User Agreement shall
+be required to distribute the Software or Derivative Works on a CD-ROM, floppy disk, or by
+electronic transmission.
+
+            2.4    Proprietary Notices. Licensee shall not remove, efface or obscure any
+copyright or trademark notices from the Software or Derivative Work. Licensee shall include
+reproductions of the Amlogic copyright notice with each copy of the Software and any
+Derivative Work, except where such Software is embedded in a manner not readily accessible to
+the end user. Licensee acknowledges that any symbols, trademarks, tradenames, and service
+marks adopted by Amlogic to identify the Software or otherwise, belong to Amlogic and that
+Licensee shall have no rights therein.
+
+            2.5   Ownership.  Amlogic shall retain all right, title and interest, including all
+intellectual property rights, in and to the Software. Licensee hereby irrevocably assigns and
+agrees to assign to Amlogic all right, title and interest in and to the Derivative Works. Licensee
+agrees to perform all acts deemed reasonably necessary or desirable by Amlogic to permit and
+assist Amlogic, at Amlogic's expense, to obtain and enforce the full benefits throughout the
+world of Licensee's assignment of all right, title and interest in the Derivative Works to the
+ Software and all related intellectual property rights to Amlogic, including but not limited to
+ execution of documents and assistance or cooperation in the registration and enforcement of any
+ such intellectual property rights throughout the world. If Amlogic is unable for any reason
+
+
+                                       2
+
+whatsoever to secure Licensee's signature to any document Licensee is required to execute
+pursuant to the foregoing, Licensee hereby irrevocably designates and appoints Amlogic and its
+duly authorized officers and agents, as their agents and attorneys-in-fact to act for and in its
+behalf and instead of Licensee, to execute and file any such document and to do all other
+lawfully permitted acts to further the purposes of the foregoing with the same legal force and
+effect as if executed by Licensee. The foregoing is deemed a power coupled with an interest and
+is irrevocable. Notwithstanding the foregoing or any other provision of this Agreement, nothing
+contained herein shall be construed as granting Amlogic any right, title or interest in or to any of
+Licensee's intellectual property or Confidential Information.
+
+            2.6   Third Party Software. The Software is distributed to Licensee in
+aggregation with various third party software ("Open Source Software"). The Open Source
+Software is distributed to Licensee under the terms ofvarious "open source tl license agreements
+which are incorporated herein by reference. Please review
+http://openlinux.amlogic.com/wikilindex.php/AlTI1/Android/3.0Third­
+Party Libraries and Open Source License Agreements for these notices and requirements.
+Licensee agrees to comply with terms and conditions contained in all such Open Source
+Software licenses with respect to the applicable Open Source Software.
+
+            2.7   No Other Rights Granted. Apart from the license rights expressly set
+forth in this Agreement, Amlogic does not grant and Licensee does not receive any ownership
+right, title or interest nor any security interest or other interest in any intellectual property rights
+relating to the Software, nor in any copy of any part of the foregoing. Licensee shall not use,
+license, sell or otherwise distribute the Software or any Derivative Work except as provided in
+this Agreement, and shall not, directly or indirectly, reverse engineer, decompile or disassemble
+any portion of the Object Code (or attempt to do so).
+
+            2.8   Fees. In consideration of the licenses granted hereunder, Licensee shall
+pay to Amlogic the fees according to the terms set forth on the Software Description Form, if
+applicable. If the Software Description Form does not include payment terms, all payments
+under this Agreement shall be made within thirty (30) days of the invoice date. Licensee shall
+pay any taxes, duties or charges of any kind (including any sales, withholding or value added
+taxes) imposed by any federal, state or local governmental entity for products or services
+provided under this Agreement excluding only taxes based solely on Amlogic's net income. If all
+or any part of any payment owed to Amlogic under this Agreement is withheld, based upon a
+claim that such withholding is required pursuant to the tax laws of any country or its political
+subdivisions andlor any tax treaty between the U.S. and any such country, such payment shall be
+increased by the amount necessary to result in a net payment to Amlogic of the amounts
+otherwise payable under this Agreement. Any amounts due under this Agreement which are not
+paid within thirty (30) calendar days of their due date shall be subject to a late payment charge of
+the lower of: (i) one and one half percent (1.5%) per month (and shall thereafter bear interest at a
+rate of eighteen percent (18%) per annum until paid); and (ii) the highest interest rate permitted
+by applicable law. Each party is responsible for its own expenses under this Agreement. All
+fees payable under this Agreement are non-refundable.
+
+
+                                       3
+
+      3.    NO WARRANTY OR SUPPORT.
+
+            3.1   No Warranty.  THE SOFTWARE IS   PROVIDED "AS IS," AND WITH
+ALL FAULTS.   AMLOGIC PROVIDESNO WARRANTIES OF ANY KIND, WHETHER
+EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION, COURSE OF         DEALING OR
+CONDUCT WITH LICENSEE, OR OTHERWISE.       AMLOGIC SPECIFICALLY DISCLAIMS
+ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FORA SPECIFIC
+PURPOSE OR NONINFRINGEMENT CONCERNING THE SOFTWARE OR ANY
+UPGRADES TO    OR DOCUMENTATION FOR THE SOFTWARE.        WITHOUT
+LIMITATION OF THE ABOVE, AMLOGIC GRANTS NO WARRANTY THAT THE
+SOFTWARE IS   ERROR-FREE OR WILL OPERATE WITHOUT INTERRUPTION, AND
+GRANTS NO WARRANTY REGARDING ITS        USE OR THE RESULTS THEREFROM
+INCLUDING, WITHOUT LIMITATION, ITS     CORRECTNESS, ACCURACY OR
+RELIABILITY.
+
+            3.2   No Support. Nothing in this Agreement shall obligate Amlogic to
+provide any support for the Software. Amlogic may, but shall be under no obligation to, correct
+any defects in the Software and/or provide updates to licensees of the Software. Licensee shall
+make reasonable efforts to promptly report to Amlogic any defects it finds in the Software, as an
+aid to creating improved revisions of the Software.
+
+            3.3   End User Support. Licensee shall, at its own expense, be solely
+responsible for providing technical support and training to its customers for Authorized Licensee
+Products, and Amlogic shall have no obligation with respect thereto. Licensee shall be solely
+responsible for, and Amlogic shall have no obligation to honor, any warranties that Licensee
+provides to its customers or to end users with respect to the Software or Derivative Works.
+Licensee shall defend any claim against Amlogic arising in connection with any such warranties,
+express, implied, statutory, or otherwise, and shall pay any settlements or damages awarded
+against Amlogic that are based on any such warranties.
+
+      4.    TERM AND TERMINATION.
+
+            4.1   Term and Termination. This Agreement shall become effective on the
+date first set forth above and shall remain in effect perpetually unless terminated as provided
+below. If Licensee defaults in a material obligation under this Agreement, and if the default is
+curable, also fails to cure such default thirty (30) days after written notice of such default,
+Amlogic may immediately terminate and cancel this Agreement and the licenses granted
+hereunder upon written notice to Licensee. Licensee may terminate this Agreement at any time
+upon written notice to Amlogic and fulfillment of its obligations under Section 4.2 herein.
+
+            4.2   Effect of Termination. Upon any termination of this Agreement, the
+rights and licenses granted to Licensee under this Agreement shall immediately terminate;
+provided, however, that sublicenses of the Software or Derivative Works in Object Code format,
+to the extent validly granted to end users pursuant to Section 2.1(ii) prior to termination of this
+Agreement, shall survive such termination subject to compliance with the obligations set forth
+herein. Upon termination, Licensee shall ship to Amlogic, within thirty (30) days, all tangible
+ items in its possession or control which are proprietary to Amlogic; and Licensee shall destroy or
+
+
+                                       4
+
+return to Amlogic, at Amlogic's option, all copies of the Software and Derivative Works
+(including, without limitation, Source Code) in its possession or control.
+
+            4.3   Survival. The provisions of Sections 1,2.2,2.3,2.4,2.5,2.6,2.7,3,4,5,
+6 and 7 shall survive the termination of this Agreement.
+
+      S.    CONFIDENTIALITY.
+
+            5.1   Existing NDA (if Applicable). If Amlogic and Licensee already have put
+in place a non-disclosure agreement that would protect communications made under this
+Agreement (the "NDA"), then all such communications shall be subject to the terms and
+conditions of such NDA, which the parties acknowledge is in full force and effect. The parties
+agree that the Software, Object Code, Source and any accompanying documentation will be
+considered Confidential Information under the NDA. In the event of a conflict between the
+terms of this Agreement and the terms of the NDA, the terms of this Agreement will prevail.
+
+            5.2   Obligations if No NDA Exists. If no NDA exists, then the following
+terms shall apply: Licensee acknowledges and agrees that the Software, Object Code, Source
+Code, any accompanying documentation, and any other information (if such other information is
+identified as confidential or should be recognized as confidential under the circumstances)
+provided to Licensee by Amlogic hereunder (collectively, "Confidential Information") constitute
+the confidential and proprietary information of Amlogic, and that Licensee's protection thereof is
+an essential condition to Licensee's use and possession of the Confidential Information.
+Licensee shall retain all Confidential Information in strict confidence and not disclose it to any
+third party or use it in any way except as permitted by this Agreement without Amlogic's express
+written consent. Licensee will exercise at least the same amount of diligence in preserving the
+secrecy of the Confidential Information as it uses in preserving the secrecy ofits own most
+valuable confidential information, but in no event less than reasonable diligence. The
+prohibitions contained in this Section 5.2 preclude dissemination of Confidential Information to
+Licensee's subsidiaries, affiliates, contractors or subcontractors, except in the event of a
+permitted assignment pursuant to Section 7.1. Information shall not be considered Confidential
+Information if and to the extent that it: (i) was in the public domain at the time it was disclosed
+or has entered the public domain through no fault of Licensee; (ii) was known to Licensee,
+without restriction, at the time of disclosure as proven by the files of Licensee in existence at the
+time of disclosure; or (iii) becomes known to Licensee, without restriction, from a source other
+than Amlogic without breach of this Agreement by Licensee and otherwise not in violation of
+Amlogic's rights. Because of the unique and valuable nature of the Confidential Information,
+Licensee acknowledges and agrees that Amlogic will suffer irreparable harm in the event that the
+Licensee fails to comply with any of its obligations herein and that monetary damages will be
+inadequate to compensate Amlogic for such breach. Accordingly, Amlogic and Licensee agree
+that Amlogic will, in addition to any other remedies available at law or in equity, be entitled to
+obtain injunctive relief to enforce the terms of this Agreement.
+
+            5.3   Source Code Protection. Licensee shall not under any circumstances
+copy, duplicate or otherwise reproduce the Source Code in any manner except as provided
+herein. Licensee is granted the right to make one (1) archival or backup copy ofthe Source
+Code, which shall be marked as an archival copy and as the confidential and proprietary property
+of Amlogic to which access is restricted. Licensee agrees to inform all employees and
+
+
+                                       5
+
+contractors who are given access by Licensee to the Software, including the Source Code, the
+Object Code, or any accompanying documentation, that such materials are confidential and trade
+secrets of Amlogic licensed to Licensee as such.
+
+      6.    LIMITATION OF LIABILITY.
+
+      EXCEPT FOR A BREACH BY LICENSEE OF SECTION 2 (LICENSE GRANT;
+OWNERSHIP) OR A BREACH BY EITHER PARTY OF SECTION 5 (CONFIDENTIALITY),
+IN NO EVENT SHALL LICENSEE, AMLOGIC OR ANY OF AMLOGIC'S LICENSORS
+HAVE ANY LIABILITY FOR ANY INDIRECT, INCIDENTAL, SPECIAL, OR
+CONSEQUENTIAL DAMAGES, HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER FOR BREACH OF CONTRACT, TORT (INCLUDING
+NEGLIGENCE) OR OTHER WISE, ARISING OUT OF THIS AGREEMENT, INCLUDING
+BUT NOT LIMITED TO LOSS OF PROFITS, EVEN IF    SUCH PARTY HAS BEEN
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.       THESE LIMITATIONS SHALL
+APPLY NOTWITHSTANDING ANY FAILURE OF ESSENTIAL PURPOSE OF ANY
+LIMITED REMEDY.
+
+IN NO EVENT SHALL AMLOGIC BE LIABLE FOR ANY AMOUNT EXCEEDING THE
+GREATER OF ONE HUNDRED DOLLARS AND THE AMOUNTS PAID BY CUSTOMER
+TO AMLOGIC HEREUNDER.
+
+      7.    MISCELLANEOUS.
+
+            7.1   Assignment. This Agreement shall be binding upon and inure to the
+benefit ofthe parties and their respective successors and assigns, provided, however that
+Licensee may not assign this Agreement or any rights or obligation hereunder, directly or
+indirectly, by operation of law or otherwise, without the prior written consent ofAmlogic, and
+any such attempted assignment shall be void. Notwithstanding the foregoing, Licensee may
+assign this Agreement to a successor to all or substantially all of its business or assets to which
+this Agreement relates that is not a competitor of Amlogic.
+
+            7.2   Notices. All notices between the parties shall be in writing and shall be
+deemed to have been given if personally delivered or sent by certified mail (return receipt
+requested), or telecopy, to the other party's legal department at the address set forth in this
+Agreement, and for Amlogic to Attn: Legal Department, Amlogic, Inc. 2518 Mission College
+Blvd, Suite 120, Santa Clara CA, 95054, USA and such other address as is provided by notice as
+set forth herein. Notices shall be deemed effective upon receipt if personally delivered, three (3)
+business days after it was sent if by certified mail, or one (1) business day after it was sent if by
+telecopier.
+
+            7.3   Governing Law; Venue. This Agreement shall be governed by the laws
+of California without regard to any conflict-of-Iaws rules, and the United Nations Convention on
+Contracts for the International Sale of Goods is hereby excluded. The sole jurisdiction and
+venue for actions related to the subject matter hereof shall be the state and federal courts located
+in the County of Santa Clara, California, and both parties hereby consent to such jurisdiction and
+venue.
+
+
+                                       6
+
+            7.4   Severability. All terms and provisions ofthis Agreement shall, if
+possible, be construed in a manner which makes them valid, but in the event any term or
+provision of this Agreement is found by a court of competent jurisdiction to be illegal or
+unenforceable, the validity or enforceability of the remainder of this Agreement shall not be
+affected if the illegal or unenforceable provision does not materially affect the intent ofthis
+Agreement. If the illegal or unenforceable provision materially affects the intent of the parties to
+this Agreement, this Agreement shall become terminated.
+
+            7.5   Equitable Relief. Licensee hereby acknowledges that its breach of this
+Agreement would cause irreparable harm and significant injury to Amlogic that may be difficult
+to ascertain and that a remedy at law would be inadequate. Accordingly, Licensee agrees that
+Amlogic shall have the right to seek and obtain immediate injunctive relief to enforce obligations
+under the Agreement in addition to any other rights and remedies it may have.
+
+            7.6   Export Regulations. Licensee agrees and warrants that it shall comply, at
+its own expense, with the U.S. Foreign Corrupt Practices Act and all export laws, restrictions,
+national security controls and regulations of the United States and any applicable foreign agency
+or authority. Licensee shall not export or re-export, or authorize the export or re-export of the
+Software or any other product, technology, or information that Licensee obtains or learns
+hereunder, or any copy or direct product thereof, in violation of any of such laws, restrictions, or
+regulations or without any license or approval required thereunder. Any and all obligations of
+Amlogic to provide Software or any media in which the Software is contained shall be subject in
+all respects to such laws, restrictions, and regulations.
+
+            7.7   Waiver. The waiver of, or failure to enforce, any breach or default
+hereunder shall not constitute the waiver of any other or subsequent breach or default.
+
+            7.8   Entire Agreement. This Agreement, along with any associated Software
+Description Forms, sets forth the entire Agreement between the parties and supersedes any and
+all prior proposals, agreements and representations between them, whether written or oral. This
+Agreement may be changed only by mutual agreement of the parties in writing. In the event of
+a conflict between the terms of this Agreement and the terms of a Software Description Form,
+the term of the Software Description Form will prevail.
+
diff --git a/bl2/bin/README b/bl2/bin/README
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/bl2/bin/README
diff --git a/bl2/bin/sc2/s905x4/bb1st.sto.bin.bl2-only b/bl2/bin/sc2/s905x4/bb1st.sto.bin.bl2-only
new file mode 100644
index 0000000..5834f12
--- /dev/null
+++ b/bl2/bin/sc2/s905x4/bb1st.sto.bin.bl2-only
Binary files differ
diff --git a/bl2/bin/sc2/s905x4/bb1st.usb.bin.bl2-only b/bl2/bin/sc2/s905x4/bb1st.usb.bin.bl2-only
new file mode 100644
index 0000000..b127311
--- /dev/null
+++ b/bl2/bin/sc2/s905x4/bb1st.usb.bin.bl2-only
Binary files differ
diff --git a/bl2/bin/sc2/s905x4/blob-bl2e.sto.bin.signed b/bl2/bin/sc2/s905x4/blob-bl2e.sto.bin.signed
new file mode 100644
index 0000000..24b069d
--- /dev/null
+++ b/bl2/bin/sc2/s905x4/blob-bl2e.sto.bin.signed
Binary files differ
diff --git a/bl2/bin/sc2/s905x4/blob-bl2e.usb.bin.signed b/bl2/bin/sc2/s905x4/blob-bl2e.usb.bin.signed
new file mode 100755
index 0000000..c1094fe
--- /dev/null
+++ b/bl2/bin/sc2/s905x4/blob-bl2e.usb.bin.signed
Binary files differ
diff --git a/bl2/bin/sc2/s905x4/blob-bl2x.bin.signed b/bl2/bin/sc2/s905x4/blob-bl2x.bin.signed
new file mode 100755
index 0000000..f962df6
--- /dev/null
+++ b/bl2/bin/sc2/s905x4/blob-bl2x.bin.signed
Binary files differ
diff --git a/bl2/bin/sc2/s905x4/blob-ddr-fip.bin.signed b/bl2/bin/sc2/s905x4/blob-ddr-fip.bin.signed
new file mode 100644
index 0000000..bd30936
--- /dev/null
+++ b/bl2/bin/sc2/s905x4/blob-ddr-fip.bin.signed
Binary files differ
diff --git a/bl2/bin/sc2/s905x4/ddr3/bb1st.sto.bin.bl2-only b/bl2/bin/sc2/s905x4/ddr3/bb1st.sto.bin.bl2-only
new file mode 100644
index 0000000..777b796
--- /dev/null
+++ b/bl2/bin/sc2/s905x4/ddr3/bb1st.sto.bin.bl2-only
Binary files differ
diff --git a/bl2/bin/sc2/s905x4/ddr3/bb1st.sto.bin.signed b/bl2/bin/sc2/s905x4/ddr3/bb1st.sto.bin.signed
new file mode 100755
index 0000000..81b494e
--- /dev/null
+++ b/bl2/bin/sc2/s905x4/ddr3/bb1st.sto.bin.signed
Binary files differ
diff --git a/bl2/bin/sc2/s905x4/ddr3/bb1st.usb.bin.bl2-only b/bl2/bin/sc2/s905x4/ddr3/bb1st.usb.bin.bl2-only
new file mode 100644
index 0000000..053dd54
--- /dev/null
+++ b/bl2/bin/sc2/s905x4/ddr3/bb1st.usb.bin.bl2-only
Binary files differ
diff --git a/bl2/bin/sc2/s905x4/ddr3/bb1st.usb.bin.signed b/bl2/bin/sc2/s905x4/ddr3/bb1st.usb.bin.signed
new file mode 100755
index 0000000..3e0e30c
--- /dev/null
+++ b/bl2/bin/sc2/s905x4/ddr3/bb1st.usb.bin.signed
Binary files differ
diff --git a/bl2/bin/sc2/s905x4/ddr4/bb1st.sto.bin.bl2-only b/bl2/bin/sc2/s905x4/ddr4/bb1st.sto.bin.bl2-only
new file mode 100644
index 0000000..9cefa56
--- /dev/null
+++ b/bl2/bin/sc2/s905x4/ddr4/bb1st.sto.bin.bl2-only
Binary files differ
diff --git a/bl2/bin/sc2/s905x4/ddr4/bb1st.sto.bin.signed b/bl2/bin/sc2/s905x4/ddr4/bb1st.sto.bin.signed
new file mode 100755
index 0000000..49aa28b
--- /dev/null
+++ b/bl2/bin/sc2/s905x4/ddr4/bb1st.sto.bin.signed
Binary files differ
diff --git a/bl2/bin/sc2/s905x4/ddr4/bb1st.usb.bin.bl2-only b/bl2/bin/sc2/s905x4/ddr4/bb1st.usb.bin.bl2-only
new file mode 100644
index 0000000..bee7b20
--- /dev/null
+++ b/bl2/bin/sc2/s905x4/ddr4/bb1st.usb.bin.bl2-only
Binary files differ
diff --git a/bl2/bin/sc2/s905x4/ddr4/bb1st.usb.bin.signed b/bl2/bin/sc2/s905x4/ddr4/bb1st.usb.bin.signed
new file mode 100755
index 0000000..7b4ad23
--- /dev/null
+++ b/bl2/bin/sc2/s905x4/ddr4/bb1st.usb.bin.signed
Binary files differ
diff --git a/bl2/bin/sc2/s905x4/lpddr3/bb1st.sto.bin.bl2-only b/bl2/bin/sc2/s905x4/lpddr3/bb1st.sto.bin.bl2-only
new file mode 100644
index 0000000..e0d69be
--- /dev/null
+++ b/bl2/bin/sc2/s905x4/lpddr3/bb1st.sto.bin.bl2-only
Binary files differ
diff --git a/bl2/bin/sc2/s905x4/lpddr3/bb1st.sto.bin.signed b/bl2/bin/sc2/s905x4/lpddr3/bb1st.sto.bin.signed
new file mode 100755
index 0000000..8aafcdf
--- /dev/null
+++ b/bl2/bin/sc2/s905x4/lpddr3/bb1st.sto.bin.signed
Binary files differ
diff --git a/bl2/bin/sc2/s905x4/lpddr3/bb1st.usb.bin.bl2-only b/bl2/bin/sc2/s905x4/lpddr3/bb1st.usb.bin.bl2-only
new file mode 100644
index 0000000..59583b1
--- /dev/null
+++ b/bl2/bin/sc2/s905x4/lpddr3/bb1st.usb.bin.bl2-only
Binary files differ
diff --git a/bl2/bin/sc2/s905x4/lpddr3/bb1st.usb.bin.signed b/bl2/bin/sc2/s905x4/lpddr3/bb1st.usb.bin.signed
new file mode 100755
index 0000000..62089cf
--- /dev/null
+++ b/bl2/bin/sc2/s905x4/lpddr3/bb1st.usb.bin.signed
Binary files differ
diff --git a/bl2/bin/sc2/s905x4/lpddr4/bb1st.sto.bin.bl2-only b/bl2/bin/sc2/s905x4/lpddr4/bb1st.sto.bin.bl2-only
new file mode 100644
index 0000000..5c02c4f
--- /dev/null
+++ b/bl2/bin/sc2/s905x4/lpddr4/bb1st.sto.bin.bl2-only
Binary files differ
diff --git a/bl2/bin/sc2/s905x4/lpddr4/bb1st.sto.bin.signed b/bl2/bin/sc2/s905x4/lpddr4/bb1st.sto.bin.signed
new file mode 100755
index 0000000..1e2d593
--- /dev/null
+++ b/bl2/bin/sc2/s905x4/lpddr4/bb1st.sto.bin.signed
Binary files differ
diff --git a/bl2/bin/sc2/s905x4/lpddr4/bb1st.usb.bin.bl2-only b/bl2/bin/sc2/s905x4/lpddr4/bb1st.usb.bin.bl2-only
new file mode 100644
index 0000000..a77783c
--- /dev/null
+++ b/bl2/bin/sc2/s905x4/lpddr4/bb1st.usb.bin.bl2-only
Binary files differ
diff --git a/bl2/bin/sc2/s905x4/lpddr4/bb1st.usb.bin.signed b/bl2/bin/sc2/s905x4/lpddr4/bb1st.usb.bin.signed
new file mode 100755
index 0000000..31b164c
--- /dev/null
+++ b/bl2/bin/sc2/s905x4/lpddr4/bb1st.usb.bin.signed
Binary files differ
diff --git a/bl30/src_ao/LICENSE b/bl30/src_ao/LICENSE
new file mode 100644
index 0000000..9bfc82c
--- /dev/null
+++ b/bl30/src_ao/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2017 Amazon Web Services
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/bl30/src_ao/README.md b/bl30/src_ao/README.md
new file mode 100644
index 0000000..e42baed
--- /dev/null
+++ b/bl30/src_ao/README.md
@@ -0,0 +1,31 @@
+## Getting Started
+
+For more information on Amazon FreeRTOS, refer to the [Getting Started section of Amazon FreeRTOS webpage](https://aws.amazon.com/freertos).
+
+To directly access the **Getting Started Guide** for supported hardware platforms, click the corresponding link in the Supported Hardware section below.
+
+For detailed documentation on Amazon FreeRTOS, refer to the [Amazon FreeRTOS User Guide](https://aws.amazon.com/documentation/freertos).
+
+## Supported Hardware
+
+The following MCU boards are supported for Amazon FreeRTOS:
+1. **Texas Instruments** - [CC3220SF-LAUNCHXL](http://www.ti.com/tool/cc3220sf-launchxl).
+    * [Getting Started Guide](https://docs.aws.amazon.com/freertos/latest/userguide/getting_started_ti.html)
+    * IDEs: [Code Composer Studio](http://www.ti.com/tools-software/ccs.html), [IAR Embedded Workbench](https://www.iar.com/iar-embedded-workbench/partners/texas-instruments)
+2. **STMicroelectronics** - [STM32L4 Discovery kit IoT node](http://www.st.com/en/evaluation-tools/b-l475e-iot01a.html).
+    * [Getting Started Guide](https://docs.aws.amazon.com/freertos/latest/userguide/getting_started_st.html)
+    * IDE: [STM32 System Workbench](http://openstm32.org/HomePage)
+3. **NXP** - [LPC54018 IoT Module](http://www.nxp.com/LPC-AWS-Module).
+    * [Getting Started Guide](https://docs.aws.amazon.com/freertos/latest/userguide/getting_started_nxp.html)
+    * IDEs: [IAR Embedded Workbench](https://www.iar.com/iar-embedded-workbench/partners/nxp), [MCUXpresso IDE](https://www.nxp.com/mcuxpresso/ide/download)
+4. **Microchip** - [Curiosity PIC32MZEF](http://www.microchipdirect.com/product/search/all/dm320104-BNDL).
+    * [Getting Started Guide](https://docs.aws.amazon.com/freertos/latest/userguide/getting_started_mch.html)
+    * IDE: [MPLAB X IDE](http://www.microchip.com/mplab/mplab-x-ide)
+5. **Espressif** - [ESP32-DevKitC](https://www.espressif.com/en/products/hardware/esp32-devkitc/overview), [ESP-WROVER-KIT](https://www.espressif.com/en/products/hardware/esp-wrover-kit/overview).
+    * [Getting Started Guide](https://docs.aws.amazon.com/freertos/latest/userguide/getting_started_espressif.html)
+
+**Windows Simulator**
+To evaluate Amazon FreeRTOS without using MCU-based hardware, you can use the Windows Simulator.
+* Requirements: Microsoft Windows 7 or newer, with at least a dual core and a hard-wired Ethernet connection
+* [Getting Started Guide](https://docs.aws.amazon.com/freertos/latest/userguide/getting_started_windows.html)
+* IDE: [Visual Studio Community Edition](https://www.visualstudio.com/downloads/)
diff --git a/bl30/src_ao/change_log.txt b/bl30/src_ao/change_log.txt
new file mode 100644
index 0000000..36d993b
--- /dev/null
+++ b/bl30/src_ao/change_log.txt
@@ -0,0 +1,296 @@
+Change Log for Amazon FreeRTOS V1.2.7 05/31/2018
+
+    - Updated the Texas Instrument SimpleLink CC3220 SDK from version 1.40.01.00 to 
+      version 2.10.00.04.
+    - Fix the MQTT Echo Demo (Hello World Demo) to avoid truncating recieved strings.
+    - The Getting Started scripts now check if the AWS CLI is configured.
+
+Secure Sockets for CC3220SF-LAUNCHXL V1.0.4
+    - Updated comments for SimpleLink CC3220 SDK version 2.10.00.04.
+
+---------------------------------------------------------------------------------------
+
+Change Log for Amazon FreeRTOS V1.2.6 05/18/2018
+
+    - Fix NXP MCUXpresso project build failure on Linux.
+
+---------------------------------------------------------------------------------------
+
+Change Log for Amazon FreeRTOS V1.2.5 05/14/2018
+
+    - Added support for Espressif's ESP32-DevKitC and ESP-WROVER-KIT.
+
+FreeRTOS+TCP V2.0.4
+    - Added Espressif ESP32 network interface support.
+
+mbedTLS-based PKCS#11 V1.0.3
+    - Implement C_DigestInit, C_DigestUpdate, and C_DigestFinal for SHA-256.
+    - Implement C_GenerateKeyPair for non-persistent ECDSA P256.
+
+PKCS#11 for for ESP32-DevKitC ESP-WROVER-KIT V1.0.0
+    - Added support for Espressif's ESP32-DevKitC and ESP-WROVER-KIT.
+
+Wi-Fi STM32L4 Discovery kit IoT node V1.0.2
+    - Bug fix to ensure that WIFI_ConnectAP() switches to the network parameters input, even when already connected to a different set.
+
+Wi-Fi for ESP32-DevKitC ESP-WROVER-KIT V1.0.0
+    - Added support for Espressif's ESP32-DevKitC and ESP-WROVER-KIT.
+
+---------------------------------------------------------------------------------------
+
+Change Log for Amazon FreeRTOS V1.2.4 05/01/2018
+
+    - Upgraded to mbedTLS version 2.8.
+    - Added MCUXpresso IDE demo project for the NXP LPC54018 IoT Module.
+
+Crypto V1.0.2
+    - Minor updates due to mbedTLS crypto interface changes.
+
+FreeRTOS+TCP V2.0.3
+    - Fixed a bug where re-transmission and duplicated TCP packets would create a 
+      computation underflow as well as a memory leak.
+    - New public function FreeRTOS_UpdateMACAddress() to allow changing the MAC address 
+      after FreeRTOS_IPInit. Sometimes the device MAC address is not available at the 
+      time FreeRTOS_IPInit() is called, so it needs to be changed afterward.
+    - Removed non-cryptographic rand() implementation.
+    - Removed a static variable in functions prvGetHostByName() and 
+      prvCreateDNSSocket() to make them threadsafe.
+
+Greengrass Discovery V1.0.3
+    - Provide a helpful error message if the Greengrass Discovery JSON does not fit in 
+      the supplied buffer.
+
+MQTT Agent V1.1.2
+    - Bug fix to avoid socket leak if MQTT Connect fails after a successful TCP 
+      connection.
+    - The user can now disable subscription management feature by defining the macro 
+      mqttconfigENABLE_SUBSCRIPTION_MANAGEMENT as 0.
+
+OTA PAL for Curiosity PIC32MZEF V0.9.1
+    - Updated for PKCS#11 PAL layer API changes.
+
+OTA PAL for Windows Simulator V0.9.2
+    - Minor restructuring of file locations.Minor restructuring of file locations.
+
+OTA PAL for CC3220SF-LAUNCHXL V0.9.3
+    - Minor changes to enable test integration.
+
+OTA Agent V0.9.4
+    - Minor restructuring of file locations.
+
+mbedTLS-based PKCS#11 V1.0.2
+    - Combined the mbedTLS based PKCS#11 implementation from Curiosity PIC32MZEF, 
+      LPC54018 IoT Module, Windows Simulator, and STM32L4 Discovery kit IoT node into a
+      single file.
+    - Add support for public key verification of signatures.
+    - Fix to free context structures on session failure.
+    - Update C_OpenSession to use CKF_SERIAL_SESSION flag.
+
+PKCS#11 for Curiosity PIC32MZEF V1.0.2
+    - Create port specific functions for certificate and key access: 
+      PKCS11_PAL_SaveFile(), PKCS11_PAL_ReadFile(), PKCS11_PAL_ReleaseFileData().
+
+PKCS#11 for LPC54018 IoT Module V1.0.1
+    - Create port specific functions for certificate and key access: 
+      PKCS11_PAL_SaveFile(), PKCS11_PAL_ReadFile(), PKCS11_PAL_ReleaseFileData().
+
+PKCS#11 PAL for Windows Simulator V1.0.2
+    - Create port specific functions for certificate and key access: 
+      PKCS11_PAL_SaveFile(), PKCS11_PAL_ReadFile(), PKCS11_PAL_ReleaseFileData().
+
+PKCS#11 for STM32L4 Discovery kit IoT node V1.0.1
+    - Create port specific functions for certificate and key access: 
+      PKCS11_PAL_SaveFile(), PKCS11_PAL_ReadFile(), PKCS11_PAL_ReleaseFileData().
+
+PKCS#11 for CC3220SF-LAUNCHXL V1.0.2
+    - PKCS#11 implementation for TI based on mbedTLS moved into this file.
+
+Secure Socket for FreeRTOS+TCP V1.1.2
+    - Combined Secure Sockets implementation for Curiosity PIC32MZEF and Windows 
+      Simulator into a single file.
+    - Fixed return value of SOCKETS_Socket on error.
+    - Attempting to create an unsupported UDP socket now triggers an assert.
+    - Added cryptographic random number generator function for TCP sequence numbers.
+    - Updated the Socket structure to keep track of a connection attempt and added 
+      support of the ECONN error.
+
+Secure Sockets for LPC54018 IoT Module V1.0.0 Beta 3
+    - Fixed minor bug in SOCKETS_Recv().
+
+Secure Sockets for STM32L4 Discovery kit IoT node V1.0.0 Beta 2
+    - Fixed return value of SOCKETS_Close on error.
+
+Secure Sockets for CC3220SF-LAUNCHXL V1.0.3
+    - Secure sockets printing is now controlled independently using the SOCKETS_PRINT 
+      macro. SOCKETS_PRINT prints TI driver error codes.
+
+Shadow V1.0.3
+    - Changed names of configuration constants to be consistent with FreeRTOS style.
+
+TLS V1.1.1
+    - Support AWS IoT Just-in-Time Registration (JITR) by sending optional 
+      client-issuer certificate.
+    - Use CKF_SERIAL_SESSION flag with PKCS#11.
+
+Wi-Fi for Curiosity PIC32MZEF V1.0.3
+    - Updated for setting the MAC Address in WIFI_On() by using new FreeRTOS+TCP 
+      function FreeRTOS_UpdateMACAddress().
+    - Redefined printing and assert stubs used in the Wi-Fi driver code.
+    - Added implementation of WIFI_GetMAC().
+    - Added implementation of WIFI_IsConnected().
+    - Minor bug fixes.
+
+Wi-Fi for LPC54018 IoT Module V1.0.2
+    - Added implementation of WIFI_IsConnected().
+    - Fixed max DNS name length redefinition.
+    - Fixed compiler errors in MCUXpresso IDE.
+    - Minor bug fixes.
+
+Wi-Fi STM32L4 Discovery kit IoT node V1.0.1
+    - Added implementation of WIFI_IsConnected().
+    - Added NULL pointer checks throughout.
+    - Minor bug fixes.
+
+Wi-Fi for CC3220SF-LAUNCHXL V1.0.2
+    - Added implementation of WIFI_IsConnected().
+    - Added NULL pointer checks throughout.
+    - Minor bug fixes.
+
+---------------------------------------------------------------------------------------
+
+Change Log for Amazon FreeRTOS V1.2.3 03/29/2018
+    - Fixed TI IAR project build failure.
+
+---------------------------------------------------------------------------------------
+
+Change Log for Amazon FreeRTOS V1.2.2 02/27/2018
+
+OTA Agent V0.9.3
+    - Formatting update.
+
+OTA PAL for Curiosity PIC32MZEF V0.9.0
+    - Beta release of the OTA Update support for the Microchip Curiosity PIC32MZEF.
+
+PKCS#11 for Curiosity_PIC32MZEF V1.0.1
+    - Added support for the management of OTA update code signing keys.
+
+Wi-Fi for Curiosity PIC32MZEF V1.0.1
+    - Updated to conditionally compile the entire file.
+
+---------------------------------------------------------------------------------------
+
+Change Log for Amazon FreeRTOS V1.2.1 02/23/2018
+
+    - Added an IAR IDE demo project for the Texas Instruments CC3220SF-LAUNCHXL.
+    - Added Wi-Fi support for the Microchip Curiosity PIC32MZEF.
+
+FreeRTOS+TCP V2.0.2
+    - Improved NULL variable check in buffer management.
+
+MQTT Agent V1.1.1
+    - Minor bug fix checking for a NULL pointer.
+
+OTA Agent V0.9.2
+    - Updated to support NULL OTA file handles.
+
+Amazon FreeRTOS OTA PAL for CC3220SF-LAUNCHXL V0.9.2
+    - Updated to support NULL OTA file handles.
+
+PKCS#11 for CC3220SF-LAUNCHXL V1.0.1
+    - Added a dummy variable to a previosly empty structure to fix IAR compiler errors.
+
+Secure Socket for Windows Simulator V1.1.1
+    - Formatting update.
+
+Secure Sockets for CC3220SF-LAUNCHXL V1.0.2
+    - Updated to print SimpleLink driver specific error codes when debugging.
+    - Added error handling for non-blocking sockets.
+    - Updated socket option to return an error if security options are specified after 
+      a connection.
+
+Wi-Fi for Curiosity PIC32MZEF V1.0.1
+    - Updated such that Wi-Fi disconnection waits until the link is down before 
+      returning.
+
+Wi-Fi for CC3220SF-LAUNCHXL V1.0.1
+    - Fixed error in attempting to overwrite a const memory.
+
+---------------------------------------------------------------------------------------
+
+Change Log for Amazon FreeRTOS V1.2.0 02/06/2018
+
+Greengrass Discovery V1.0.2
+    Updated to send all data until an error is recieved.
+
+MQTT Agent V1.1.0
+    Added support for ALPN. ALPN allows MQTT traffic to be sent to
+    the AWS IoT broker over port 443 instead of 8883.
+
+OTA Agent V0.9.1
+    The agent was fixed to send a FAILED status when a file too large for the platform
+    is recieved. 
+    Some files were renamed.
+
+PKCS#11 for Windows Simulator
+    Added developer mode key provisioning support.
+
+Secure Socket for Curiosity PIC32MZEF V1.0.1
+    Added support for ALPN.
+
+Secure Socket for Windows Simulator V1.1.0
+    Added support for ALPN.
+
+Secure Sockets for CC3220SF-LAUNCHXL V1.0.1
+    Removed unnecessary server certificate storage on the client side.
+    Removed unnecessary global synchronization semaphore. 
+    Updated for other small bugs.
+
+Shadow V1.0.2
+    Fixed error handling bugs.
+    Require client tokens.
+    Updated for other small bugs.
+
+TLS V1.1.0
+    Added support for ALPN.
+
+---------------------------------------------------------------------------------------
+
+Change Log for Amazon FreeRTOS V1.1.0 12/20/2017
+
+Crypto V1.0.1
+    Fixed compiler warning for the Microchip Curiosity PIC32MZEF.
+
+FreeRTOS+TCP V2.0.1
+    Added support for the Microchip Curiosity PIC32MZEF.
+
+FreeRTOS Kernel V10.0.1
+    Minor bug fixes to allow Linux and C++ builds.
+
+Greengrass Discovery V1.0.1
+    Reformatted console display messages in order to better facilitate 
+    demos and debugging.
+
+MQTT Agent V1.0.1
+    The MQTT Agent now processes commands between successive socket reads to
+    enable faster command handling, especially when the connected socket is
+    receiving data continuously.
+
+OTA Agent V0.9.0
+    Beta release of OTA Update library for Amazon FreeRTOS. Includes support
+    for the Texas Instruments CC3220SF-LAUNCHXL and Windows Simulator.
+
+PKCS#11 for Curiosity PIC32MZEF V1.0.0 Beta 1
+    Added support for the Microchip Curiosity PIC32MZEF.
+
+Secure Socket for Curiosity PIC32MZEF V1.0.0
+    Added support for the Microchip Curiosity PIC32MZEF.
+
+Secure Sockets for LPC54018 IoT Module V1.0.0 Beta 2
+    Fixed bugs in the Secure Sockets implementation for the NXP LPC54018 IoT
+    Module.
+
+Shadow V1.0.1
+    Fixed compiler warning for the Microchip Curiosity PIC32MZEF.
+
+Wi-Fi for LPC54018 IoT Module V1.0.1
+    Changed the Wi-Fi Connection timeout to 10 seconds.
\ No newline at end of file
diff --git a/bl30/src_ao/check.sh b/bl30/src_ao/check.sh
new file mode 100755
index 0000000..f5c440d
--- /dev/null
+++ b/bl30/src_ao/check.sh
@@ -0,0 +1,54 @@
+#!/bin/bash
+#
+#  Copyright (c) 2019 Amlogic, Inc. All rights reserved.
+#
+source scripts/amlogic/util.sh
+
+if [ "$1" == "clear-all" ];then
+        rm -fr demos/amlogic/n200/*/*/gcc
+        rm bl30.bin
+        exit 0
+fi
+
+declare -i FAIL_COUNTER=0
+SCRIPT_PATH=${SCRIPT_PATH:-$(dirname $(readlink -f $0))}
+autobuild=${SCRIPT_PATH}/build-`date +%Y%m%d%H%M%S`
+#mkdir -p $autobuild
+echo $autobuild
+
+declare -i TOTAL_CFG=1
+
+board=$(list_boards)
+ALL_BOARDS='\n'"Build BL30 for boards: "$board'\n'"--- $autobuild"'\n\n'
+
+echo -e $ALL_BOARDS
+
+RESULT='\n'"-------------------------------------------------------"'\n'
+
+for item in ${board[@]}
+{
+        ./mk $item
+
+        if [ $? != 0 ]; then
+                FAIL_COUNTER=$FAIL_COUNTER+1
+                RESULT=$RESULT"$TOTAL_CFG."'\t'${item}'\t\033[41;37m--- build failed\033[0m\n'
+        else
+                RESULT=$RESULT"$TOTAL_CFG.\t"${item}'\r\t\t\t\t--- pass\n'
+
+                #cp -fr ./build/$item $autobuild/
+                rm -fr demos/amlogic/n200/*/${item}/gcc
+        fi
+        TOTAL_CFG+=1;
+
+        echo -e $RESULT
+}
+
+if [ $FAIL_COUNTER != 0 ]; then
+        RESULT=$RESULT"\n\tCompile failed SoC number : "'\033[41;37m'$FAIL_COUNTER'\033[0m\n'
+else
+        RESULT=$RESULT"\n\tCompile all passed!\n\n"
+fi
+
+#echo -e $RESULT
+
+exit $FAIL_COUNTER
diff --git a/bl30/src_ao/clean b/bl30/src_ao/clean
new file mode 100755
index 0000000..2074e09
--- /dev/null
+++ b/bl30/src_ao/clean
@@ -0,0 +1,9 @@
+#!/usr/bin/env bash
+
+source scripts/amlogic/clean.sh $1
+
+if [ -f bl30.bin ]
+then
+	rm bl30.bin
+fi
+
diff --git a/bl30/src_ao/demos/amlogic/common/myprintf.c b/bl30/src_ao/demos/amlogic/common/myprintf.c
new file mode 100644
index 0000000..a94027d
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/common/myprintf.c
@@ -0,0 +1,432 @@
+/*
+ *  Copyright (C) 2014-2018 Amlogic, Inc. All rights reserved.
+ *
+ *  All information contained herein is Amlogic confidential.
+ *
+ *  This software is provided to you pursuant to Software License Agreement
+ *  (SLA) with Amlogic Inc ("Amlogic"). This software may be used
+ *  only in accordance with the terms of this agreement.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification is strictly prohibited without prior written permission from
+ *  Amlogic.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *  OWNER 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, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* Printf-like functionality for Chrome EC */
+
+#include "myprintf.h"
+#include "projdefs.h"
+#include "util.h"
+//#include <stdarg.h>
+//#include <stdlib.h>
+//#include <stdio.h>
+//#include <string.h>
+#include "uart.h"
+#include "FreeRTOS.h"
+#include "task.h"     /* RTOS task related API prototypes. */
+
+static const char error_str[] = "ERROR";
+
+#define MAX_FORMAT 1024		/* Maximum chars in a single format field */
+static char printbuffer[512];
+
+/**
+ * Convert the lowest nibble of a number to hex
+ *
+ * @param c	Number to extract lowest nibble from
+ *
+ * @return The corresponding ASCII character ('0' - 'f').
+ */
+static int hexdigit(int c)
+{
+	/* Strip off just the last nibble */
+	c &= 0x0f;
+
+	return c > 9 ? (c + 'a' - 10) : (c + '0');
+}
+
+/* Flags for vfnprintf() flags */
+#define PF_LEFT		(1 << 0)	/* Left-justify */
+#define PF_PADZERO	(1 << 1)	/* Pad with 0's not spaces */
+#define PF_NEGATIVE	(1 << 2)	/* Number is negative */
+#define PF_64BIT	(1 << 3)	/* Number is 64-bit */
+#if 1
+int vfnprintf(int (*addchar)(void *context, int c), void *context,
+	      const char *format, va_list args)
+{
+	/*
+	 * Longest uint64 in decimal = 20
+	 * Longest uint32 in binary  = 32
+	 * + sign bit
+	 * + terminating null
+	 */
+	char intbuf[34];
+	int flags;
+	int pad_width;
+	int precision;
+	char *vstr;
+	int vlen;
+
+	while (*format) {
+		int c = *format++;
+
+		/* Copy normal characters */
+		if (c != '%') {
+			if (addchar(context, c))
+				return pdFREERTOS_ERRNO_EINVAL;
+			continue;
+		}
+
+		/* Zero flags, now that we're in a format */
+		flags = 0;
+
+		/* Get first format character */
+		c = *format++;
+
+		/* Send "%" for "%%" input */
+		if (c == '%' || c == '\0') {
+			if (addchar(context, '%'))
+				return pdFREERTOS_ERRNO_EINVAL;
+			continue;
+		}
+
+		/* Handle %c */
+		if (c == 'c') {
+			c = va_arg(args, int);
+
+			if (addchar(context, c))
+				return pdFREERTOS_ERRNO_EINVAL;
+			continue;
+		}
+
+		/* Handle left-justification ("%-5s") */
+		if (c == '-') {
+			flags |= PF_LEFT;
+			c = *format++;
+		}
+
+		/* Handle padding with 0's */
+		if (c == '0') {
+			flags |= PF_PADZERO;
+			c = *format++;
+		}
+
+		/* Count padding length */
+		pad_width = 0;
+		if (c == '*') {
+			pad_width = va_arg(args, int);
+
+			c = *format++;
+		} else {
+			while (c >= '0' && c <= '9') {
+				pad_width = (10 * pad_width) + c - '0';
+				c = *format++;
+			}
+		}
+		if (pad_width < 0 || pad_width > MAX_FORMAT) {
+			/* Sanity check for precision failed */
+			format = error_str;
+			continue;
+		}
+		/* Count precision */
+		precision = 0;
+		if (c == '.') {
+			c = *format++;
+			if (c == '*') {
+				precision = va_arg(args, int);
+
+				c = *format++;
+			} else {
+				while (c >= '0' && c <= '9') {
+					precision = (10 * precision) + c - '0';
+					c = *format++;
+				}
+			}
+			if (precision < 0 || precision > MAX_FORMAT) {
+				/* Sanity check for precision failed */
+				format = error_str;
+				continue;
+			}
+		}
+
+		if (c == 's') {
+			vstr = va_arg(args, char *);
+
+			if (vstr == NULL) {	/*Fix me */
+				;	//vstr = "(NULL)";
+			}
+		} else if (c == 'h') {
+			/* Hex dump output */
+			vstr = va_arg(args, char *);
+
+			if (!precision) {
+				/* Hex dump requires precision */
+				format = error_str;
+				continue;
+			}
+
+			for (; precision; precision--, vstr++) {
+				if (addchar(context, hexdigit(*vstr >> 4)) ||
+				    addchar(context, hexdigit(*vstr)))
+					return pdFREERTOS_ERRNO_EINVAL;
+			}
+
+			continue;
+		} else {
+			uint64_t v;
+			int base = 10;
+
+			/* Handle length */
+			if (c == 'l') {
+				if (sizeof(long) == 8)
+					flags |= PF_64BIT;
+				c = *format++;
+				if (c == 'l') {
+					flags |= PF_64BIT;
+					c = *format++;	// long long is 64bit at LP64
+				}
+			}
+
+			/* Special-case: %T = current time */
+			if (c == 'T') {
+				//v = get_time().val;
+				flags |= PF_64BIT;
+				precision = 6;
+			} else if (flags & PF_64BIT) {
+				v = va_arg(args, uint64_t);
+			} else {
+				v = va_arg(args, uint32_t);
+			}
+
+			switch (c) {
+			case 'd':
+				if (flags & PF_64BIT) {
+					if ((int64_t) v < 0) {
+						flags |= PF_NEGATIVE;
+						if (v != (1ULL << 63))
+							v = -v;
+					}
+				} else {
+					if ((int)v < 0) {
+						flags |= PF_NEGATIVE;
+						if (v != (1ULL << 31))
+							v = -(int)v;
+					}
+				}
+				break;
+			case 'u':
+			case 'T':
+				break;
+			case 'X':
+			case 'x':
+			case 'p':
+				base = 16;
+				break;
+			case 'b':
+				base = 2;
+				break;
+			default:
+				format = error_str;
+			}
+			if (format == error_str)
+				continue;	/* Bad format specifier */
+
+			/*
+			 * Convert integer to string, starting at end of
+			 * buffer and working backwards.
+			 */
+			vstr = intbuf + sizeof(intbuf) - 1;
+			*(vstr) = '\0';
+
+			/*
+			 * Fixed-point precision must fit in our buffer.
+			 * Leave space for "0." and the terminating null.
+			 */
+			if (precision > (int)(sizeof(intbuf) - 3))
+				precision = (int)(sizeof(intbuf) - 3);
+
+			/*
+			 * Handle digits to right of decimal for fixed point
+			 * numbers.
+			 */
+			for (vlen = 0; vlen < precision; vlen++)
+				*(--vstr) = '0' + uint64divmod(&v, 10);
+			if (precision)
+				*(--vstr) = '.';
+
+			if (!v)
+				*(--vstr) = '0';
+
+			while (v) {
+				int digit = uint64divmod(&v, base);
+
+				if (digit < 10)
+					*(--vstr) = '0' + digit;
+				else if (c == 'X')
+					*(--vstr) = 'A' + digit - 10;
+				else
+					*(--vstr) = 'a' + digit - 10;
+			}
+
+			if (flags & PF_NEGATIVE)
+				*(--vstr) = '-';
+
+			/*
+			 * Precision field was interpreted by fixed-point
+			 * logic, so clear it.
+			 */
+			precision = 0;
+		}
+
+		/* Copy string (or stringified integer) */
+		if (vstr != NULL)
+			vlen = strlen(vstr);
+		else
+			vlen = 0;
+
+		/* No padding strings to wider than the precision */
+		if (precision > 0 && pad_width > precision)
+			pad_width = precision;
+
+		/* If precision is zero, print everything */
+		if (!precision)
+			precision = MAX(vlen, pad_width);
+
+		while (vlen < pad_width && !(flags & PF_LEFT)) {
+			if (addchar(context, flags & PF_PADZERO ? '0' : ' '))
+				return pdFREERTOS_ERRNO_EINVAL;
+			vlen++;
+		}
+
+		if (vstr != NULL) {
+			while (*vstr && --precision >= 0)
+				if (addchar(context, *vstr++))
+					return pdFREERTOS_ERRNO_EINVAL;
+		}
+		while (vlen < pad_width && flags & PF_LEFT) {
+			if (addchar(context, ' '))
+				return pdFREERTOS_ERRNO_EINVAL;
+			vlen++;
+		}
+	}
+
+	/* If we're still here, we consumed all output */
+	return pdFREERTOS_ERRNO_NONE;
+}
+#endif
+/* Context for snprintf() */
+struct snprintf_context {
+	char *str;
+	size_t size;
+};
+
+/**
+ * Add a character to the string context.
+ *
+ * @param context	Context receiving character
+ * @param c		Character to add
+ * @return 0 if character added, 1 if character dropped because no space.
+ */
+static int snprintf_addchar(void *context, int c)
+{
+	struct snprintf_context *ctx = (struct snprintf_context *)context;
+
+	if (!ctx->size)
+		return 1;
+
+	*(ctx->str++) = c;
+	ctx->size--;
+
+	return 0;
+}
+
+int sPrintf_ext(char *str, size_t size, const char *format, va_list args)
+{
+	struct snprintf_context ctx;
+	int rv;
+
+	if (!str || !size)
+		return pdFREERTOS_ERRNO_EINVAL;
+
+	ctx.str = str;
+	ctx.size = size - 1;	/* Reserve space for terminating '\0' */
+
+	rv = vfnprintf(snprintf_addchar, &ctx, format, args);
+
+	/* Terminate string */
+	*ctx.str = '\0';
+
+	return rv;
+}
+
+int sPrintf(char *str, size_t size, const char *fmt, ...)
+{
+	va_list args;
+	int i;
+
+	va_start(args, fmt);
+
+	i = sPrintf_ext(str, size, fmt, args);
+	va_end(args);
+
+	return i;
+}
+
+//int iprintf(const char *fmt, ...)
+int iprintf(const char *fmt, ...)
+{
+	va_list args;
+	int i;
+	UBaseType_t uxSavedInterruptStatus;
+
+	//char buf[20] = {0};
+
+	uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
+
+	va_start(args, fmt);
+
+	/* For this to work, printbuffer must be larger than
+	 * anything we ever want to print.
+	 */
+	i = sPrintf_ext(printbuffer, sizeof(printbuffer), fmt, args);
+	va_end(args);
+	{
+		/* Print the string */
+		//sprintf(buf, "%lld : ", (long long int)xTaskGetTickCount());
+		//vSerialPutString(ConsoleSerial, buf);
+		//vSerialPutString(ConsoleSerial, printbuffer);
+		vUartPuts(printbuffer);
+	}
+	portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );
+	return i;
+}
+
+int iprint_string(char *str)
+{
+	//vSerialPutString(ConsoleSerial, str);
+	vUartPuts(str);
+
+	return 0;
+}
+
+extern int puts(const char *str);
+
+int puts(const char *str)
+{
+	vUartPuts(str);
+
+	return 0;
+}
+
diff --git a/bl30/src_ao/demos/amlogic/common/util.c b/bl30/src_ao/demos/amlogic/common/util.c
new file mode 100644
index 0000000..5e3824f
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/common/util.c
@@ -0,0 +1,462 @@
+/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* Utility functions for Chrome EC */
+
+#include "util.h"
+
+unsigned int strlen(const char *s)
+{
+	int len = 0;
+
+	while (*s++)
+		len++;
+
+	return len;
+}
+
+
+int isspace(int c)
+{
+	return c == ' ' || c == '\t' || c == '\r' || c == '\n';
+}
+
+
+int isdigit(int c)
+{
+	return c >= '0' && c <= '9';
+}
+
+
+int isalpha(int c)
+{
+	return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
+}
+
+int isprint(int c)
+{
+	return c >= ' ' && c <= '~';
+}
+
+int tolower(int c)
+{
+	return c >= 'A' && c <= 'Z' ? c + 'a' - 'A' : c;
+}
+
+
+int strcasecmp(const char *s1, const char *s2)
+{
+	int diff;
+	do {
+		diff = tolower(*s1) - tolower(*s2);
+		if (diff)
+			return diff;
+	} while (*(s1++) && *(s2++));
+	return 0;
+}
+
+
+int strncasecmp(const char *s1, const char *s2, size_t size)
+{
+	int diff;
+
+	if (!size)
+		return 0;
+
+	do {
+		diff = tolower(*s1) - tolower(*s2);
+		if (diff)
+			return diff;
+	} while (*(s1++) && *(s2++) && --size);
+	return 0;
+}
+
+
+int atoi(const char *nptr)
+{
+	int result = 0;
+	int neg = 0;
+	char c = '\0';
+
+	while ((c = *nptr++) && isspace(c))
+		;
+
+	if (c == '-') {
+		neg = 1;
+		c = *nptr++;
+	}
+
+	while (isdigit(c)) {
+		result = result * 10 + (c - '0');
+		c = *nptr++;
+	}
+
+	return neg ? -result : result;
+}
+
+
+/* Like strtol(), but for integers */
+int strtoi(const char *nptr, char **endptr, int base)
+{
+	int result = 0;
+	int neg = 0;
+	int c = '\0';
+
+	if (endptr)
+		*endptr = (char *)nptr;
+
+	while ((c = *nptr++) && isspace(c))
+		;
+
+	if (c == '0' && *nptr == 'x') {
+		base = 16;
+		c = nptr[1];
+		nptr += 2;
+	} else if (base == 0) {
+		base = 10;
+		if (c == '-') {
+			neg = 1;
+			c = *nptr++;
+		}
+	}
+
+	while (c) {
+		if (c >= '0' && c < '0' + MIN(base, 10))
+			result = result * base + (c - '0');
+		else if (c >= 'A' && c < 'A' + base - 10)
+			result = result * base + (c - 'A' + 10);
+		else if (c >= 'a' && c < 'a' + base - 10)
+			result = result * base + (c - 'a' + 10);
+		else
+			break;
+
+		if (endptr)
+			*endptr = (char *)nptr;
+		c = *nptr++;
+	}
+
+	return neg ? -result : result;
+}
+
+int parse_bool(const char *s, int *dest)
+{
+	if (!strcasecmp(s, "off") || !strncasecmp(s, "dis", 3) ||
+	    tolower(*s) == 'f' || tolower(*s) == 'n') {
+		*dest = 0;
+		return 1;
+	} else if (!strcasecmp(s, "on") || !strncasecmp(s, "ena", 3) ||
+	    tolower(*s) == 't' || tolower(*s) == 'y') {
+		*dest = 1;
+		return 1;
+	} else {
+		return 0;
+	}
+}
+
+int memcmp(const void *s1, const void *s2, size_t len)
+{
+	const char *sa = s1;
+	const char *sb = s2;
+
+	int diff = 0;
+	while (len-- > 0) {
+		diff = *(sa++) - *(sb++);
+		if (diff)
+			return diff;
+	}
+
+	return 0;
+}
+
+
+void *memcpy(void *dest, const void *src, size_t len)
+{
+	char *d = (char *)dest;
+	const char *s = (const char *)src;
+	uint32_t *dw;
+	const uint32_t *sw;
+	char *head;
+	char * const tail = (char *)dest + len;
+	/* Set 'body' to the last word boundary */
+	uint32_t * const body = (uint32_t *)((uintptr_t)tail & ~3);
+
+	if (((uintptr_t)dest & 3) != ((uintptr_t)src & 3)) {
+		/* Misaligned. no body, no tail. */
+		head = tail;
+	} else {
+		/* Aligned */
+		if ((uintptr_t)tail < (((uintptr_t)d + 3) & ~3))
+			/* len is shorter than the first word boundary */
+			head = tail;
+		else
+			/* Set 'head' to the first word boundary */
+			head = (char *)(((uintptr_t)d + 3) & ~3);
+	}
+
+	/* Copy head */
+	while (d < head)
+		*(d++) = *(s++);
+
+	/* Copy body */
+	dw = (uint32_t *)d;
+	sw = (uint32_t *)s;
+	while (dw < body)
+		*(dw++) = *(sw++);
+
+	/* Copy tail */
+	d = (char *)dw;
+	s = (const char *)sw;
+	while (d < tail)
+		*(d++) = *(s++);
+
+	return dest;
+}
+
+
+void *memset(void *dest, int c, size_t len)
+{
+	char *d = (char *)dest;
+	uint32_t cccc;
+	uint32_t *dw;
+	char *head;
+	char * const tail = (char *)dest + len;
+	/* Set 'body' to the last word boundary */
+	uint32_t * const body = (uint32_t *)((uintptr_t)tail & ~3);
+
+	c &= 0xff;	/* Clear upper bits before ORing below */
+	cccc = c | (c << 8) | (c << 16) | (c << 24);
+
+	if ((uintptr_t)tail < (((uintptr_t)d + 3) & ~3))
+		/* len is shorter than the first word boundary */
+		head = tail;
+	else
+		/* Set 'head' to the first word boundary */
+		head = (char *)(((uintptr_t)d + 3) & ~3);
+
+	/* Copy head */
+	while (d < head)
+		*(d++) = c;
+
+	/* Copy body */
+	dw = (uint32_t *)d;
+	while (dw < body)
+		*(dw++) = cccc;
+
+	/* Copy tail */
+	d = (char *)dw;
+	while (d < tail)
+		*(d++) = c;
+
+	return dest;
+}
+
+
+void *memmove(void *dest, const void *src, size_t len)
+{
+	if ((uintptr_t)dest <= (uintptr_t)src ||
+	    (uintptr_t)dest >= (uintptr_t)src + len) {
+		/* Start of destination doesn't overlap source, so just use
+		 * memcpy(). */
+		return memcpy(dest, src, len);
+	} else {
+		/* Need to copy from tail because there is overlap. */
+		char *d = (char *)dest + len;
+		const char *s = (const char *)src + len;
+		uint32_t *dw;
+		const uint32_t *sw;
+		char *head;
+		char * const tail = (char *)dest;
+		/* Set 'body' to the last word boundary */
+		uint32_t * const body = (uint32_t *)(((uintptr_t)tail+3) & ~3);
+
+		if (((uintptr_t)dest & 3) != ((uintptr_t)src & 3)) {
+			/* Misaligned. no body, no tail. */
+			head = tail;
+		} else {
+			/* Aligned */
+			if ((uintptr_t)tail > ((uintptr_t)d & ~3))
+				/* Shorter than the first word boundary */
+				head = tail;
+			else
+				/* Set 'head' to the first word boundary */
+				head = (char *)((uintptr_t)d & ~3);
+		}
+
+		/* Copy head */
+		while (d > head)
+			*(--d) = *(--s);
+
+		/* Copy body */
+		dw = (uint32_t *)d;
+		sw = (uint32_t *)s;
+		while (dw > body)
+			*(--dw) = *(--sw);
+
+		/* Copy tail */
+		d = (char *)dw;
+		s = (const char *)sw;
+		while (d > tail)
+			*(--d) = *(--s);
+
+		return dest;
+	}
+}
+
+
+char *strzcpy(char *dest, const char *src, int len)
+{
+	char *d = dest;
+	if (len <= 0)
+		return dest;
+	while (len > 1 && *src) {
+		*(d++) = *(src++);
+		len--;
+	}
+	*d = '\0';
+	return dest;
+}
+
+
+int uint64divmod(uint64_t *n, int d)
+{
+	uint64_t q = 0, mask;
+	int r = 0;
+
+	/* Divide-by-zero returns zero */
+	if (!d) {
+		*n = 0;
+		return 0;
+	}
+
+	/* Common powers of 2 = simple shifts */
+	if (d == 2) {
+		r = *n & 1;
+		*n >>= 1;
+		return r;
+	} else if (d == 16) {
+		r = *n & 0xf;
+		*n >>= 4;
+		return r;
+	}
+
+	/* If v fits in 32-bit, we're done. */
+	if (*n <= 0xffffffff) {
+		uint32_t v32 = *n;
+		r = v32 % d;
+		*n = v32 / d;
+		return r;
+	}
+
+	/* Otherwise do integer division the slow way. */
+	for (mask = (1ULL << 63); mask; mask >>= 1) {
+		r <<= 1;
+		if (*n & mask)
+			r |= 1;
+		if (r >= d) {
+			r -= d;
+			q |= mask;
+		}
+	}
+	*n = q;
+	return r;
+}
+
+int __clzsi2(int x)
+{
+	int r = 0;
+
+	if (!x)
+		return 32;
+	if (!(x & 0xffff0000u)) {
+		x <<= 16;
+		r += 16;
+	}
+	if (!(x & 0xff000000u)) {
+		x <<= 8;
+		r += 8;
+	}
+	if (!(x & 0xf0000000u)) {
+		x <<= 4;
+		r += 4;
+	}
+	if (!(x & 0xc0000000u)) {
+		x <<= 2;
+		r += 2;
+	}
+	if (!(x & 0x80000000u)) {
+		x <<= 1;
+		r += 1;
+	}
+	return r;
+}
+
+int get_next_bit(uint32_t *mask)
+{
+	int bit = 31 - __clzsi2(*mask);
+	*mask &= ~(1 << bit);
+	return bit;
+}
+
+char *strncpy (char *s1, const char *s2, size_t n)
+{
+	char c;
+	char *s = s1;
+
+	--s1;
+
+	if (n >= 4)
+	{
+		size_t n4 = n >> 2;
+
+		for (;;)
+		{
+			c = *s2++;
+			*++s1 = c;
+			if (c == '\0')
+			break;
+			c = *s2++;
+			*++s1 = c;
+			if (c == '\0')
+			break;
+			c = *s2++;
+			*++s1 = c;
+			if (c == '\0')
+			break;
+			c = *s2++;
+			*++s1 = c;
+			if (c == '\0')
+			break;
+			if (--n4 == 0)
+			goto last_chars;
+		}
+		n = n - (s1 - s) - 1;
+		if (n == 0)
+			return s;
+		goto zero_fill;
+	}
+
+	last_chars:
+	n &= 3;
+	if (n == 0)
+		return s;
+
+	do
+	{
+		c = *s2++;
+		*++s1 = c;
+		if (--n == 0)
+		return s;
+	}
+	while (c != '\0');
+
+	zero_fill:
+	do
+		*++s1 = '\0';
+	while (--n > 0);
+
+	return s;
+}
+
+
diff --git a/bl30/src_ao/demos/amlogic/driver/bt/s4_bt_common/btwake.c b/bl30/src_ao/demos/amlogic/driver/bt/s4_bt_common/btwake.c
new file mode 100644
index 0000000..eabbe7b
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/bt/s4_bt_common/btwake.c
@@ -0,0 +1,103 @@
+#include <string.h>
+#include "FreeRTOS.h"
+#include "suspend.h"
+#include "task.h"
+#include "gpio.h"
+#include "btwake.h"
+
+#include "queue.h"    /* RTOS queue related API prototypes. */
+#include "timers.h"   /* Software timer related API prototypes. */
+#include "semphr.h"   /* Semaphore related API prototypes. */
+
+static TaskHandle_t btTask = NULL;
+
+static void bt_wakeup_Task(void *args)
+{
+	uint32_t buf[4] = {0};
+	int cnt = 0;
+	int flag_p = 0;
+	int flag_n = 0;
+
+restart_task:
+	UNUSED(args);
+	INFO();
+	vTaskSuspend(btTask);
+	vTaskDelay(pdMS_TO_TICKS(100));
+	if (!xGpioGetValue(BT_WAKE_HOST)) {
+		vTaskDelay(pdMS_TO_TICKS(100));
+		do {
+			vTaskDelay(pdMS_TO_TICKS(20));
+			if (xGpioGetValue(BT_WAKE_HOST)) {
+				flag_p++;
+			}
+			else if (!xGpioGetValue(BT_WAKE_HOST)) {
+				flag_n++;
+			}
+			cnt++;
+		} while (cnt < 10);
+
+		if (flag_p >= 7) {
+			INFO("power key: %d", flag_p);
+			buf[0] = BT_WAKEUP;
+		}
+		else if (flag_n >= 7) {
+			vTaskDelay(pdMS_TO_TICKS(120));
+			if (!xGpioGetValue(BT_WAKE_HOST)) {
+				INFO("suspend any key");
+				buf[0] = BT_WAKEUP;
+			}
+			else {
+				INFO("netflix key: %d", flag_n);
+				buf[0] = REMOTE_CUS_WAKEUP;
+			}
+		}
+		else
+		{
+			INFO("flag_p= %d, flag_n = %d",flag_p, flag_n);
+			buf[0] = BT_WAKEUP;
+		}
+
+	}
+	if (buf[0] != 0) {
+		STR_Wakeup_src_Queue_Send(buf);
+		while (1) {
+			vTaskSuspend(NULL);
+			INFO("suspend null");
+		}
+	}
+	vEnableGpioIRQ(BT_WAKE_HOST);
+	goto restart_task;
+}
+
+static void vBTWakeup(void)
+{
+	vDisableGpioIRQ(BT_WAKE_HOST);
+	xTaskResumeFromISR(btTask);
+}
+
+static void bt_task_create(void)
+{
+	int ret = 0;
+	ret = xTaskCreate(bt_wakeup_Task, "bt_wakeup", configMINIMAL_STACK_SIZE, NULL, 2, &btTask);
+	if (ret != pdPASS)
+		INFO("bt_wakeup_Task create failed!");
+}
+
+void bt_task_init(void)
+{
+	bt_task_create();
+	xGpioSetDir(BT_WAKE_HOST, GPIO_DIR_IN);
+	xRequestGpioIRQ(BT_WAKE_HOST, vBTWakeup, IRQF_TRIGGER_LOW);
+}
+
+void bt_task_deinit(void)
+{
+	if (btTask != NULL)
+	{
+		INFO("deinit");
+		vTaskDelete(btTask);
+		btTask = NULL;
+	}
+	vFreeGpioIRQ(BT_WAKE_HOST);
+}
+
diff --git a/bl30/src_ao/demos/amlogic/driver/bt/s4_bt_common/btwake.h b/bl30/src_ao/demos/amlogic/driver/bt/s4_bt_common/btwake.h
new file mode 100644
index 0000000..4706585
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/bt/s4_bt_common/btwake.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C)2018 Amlogic, Inc. All rights reserved.
+ *
+ * All information contained herein is Amlogic confidential.
+ *
+ * This software is provided to you pursuant to Software License Agreement
+ * (SLA) with Amlogic Inc ("Amlogic"). This software may be used
+ * only in accordance with the terms of this agreement.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification is strictly prohibited without prior written permission from
+ * Amlogic.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER 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, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _BTWAKE_H_
+#define _BTWAKE_H_
+
+#define UNUSED(x) ((void)x)
+#define BT_WAKE_HOST GPIOX_18  //bt_wake_host pin
+#define INFO(fmt, args...) printf("[%s] " fmt "\n", __func__, ##args)
+
+void bt_task_init(void);
+void bt_task_deinit(void);
+
+#endif
\ No newline at end of file
diff --git a/bl30/src_ao/demos/amlogic/driver/bt/s4_bt_common/build.mk b/bl30/src_ao/demos/amlogic/driver/bt/s4_bt_common/build.mk
new file mode 100644
index 0000000..0abfe2a
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/bt/s4_bt_common/build.mk
@@ -0,0 +1,26 @@
+#
+#  Copyright (C) 2014-2018 Amlogic, Inc. All rights reserved.
+#
+#  All information contained herein is Amlogic confidential.
+#
+#  This software is provided to you pursuant to Software License Agreement
+#  (SLA) with Amlogic Inc ("Amlogic"). This software may be used
+#  only in accordance with the terms of this agreement.
+#
+#  Redistribution and use in source and binary forms, with or without
+#  modification is strictly prohibited without prior written permission from
+#  Amlogic.
+#
+#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#  OWNER 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, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+s4_bt_common-y = btwake.o
diff --git a/bl30/src_ao/demos/amlogic/driver/bt/t3_bt_common/btwake.c b/bl30/src_ao/demos/amlogic/driver/bt/t3_bt_common/btwake.c
new file mode 100644
index 0000000..f14c1ff
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/bt/t3_bt_common/btwake.c
@@ -0,0 +1,37 @@
+#include <string.h>
+#include "FreeRTOS.h"
+#include "suspend.h"
+#include "task.h"
+#include "gpio.h"
+#include "btwake.h"
+
+#include "queue.h"    /* RTOS queue related API prototypes. */
+#include "timers.h"   /* Software timer related API prototypes. */
+#include "semphr.h"   /* Semaphore related API prototypes. */
+
+void Bt_IRQHandle(void)
+{
+	uint32_t buf[4] = {0};
+
+	INFO("bt resume");
+	vDisableGpioIRQ(BT_WAKE_HOST);
+	if (!xGpioGetValue(BT_WAKE_HOST)) {
+		buf[0] = BT_WAKEUP;
+		INFO("power key");
+		STR_Wakeup_src_Queue_Send_FromISR(buf);
+	}
+}
+
+void Bt_GpioIRQRegister(void)
+{
+	INFO();
+	xGpioSetDir(BT_WAKE_HOST, GPIO_DIR_IN);
+	xRequestGpioIRQ(BT_WAKE_HOST, Bt_IRQHandle, IRQF_TRIGGER_FALLING);
+}
+
+void Bt_GpioIRQFree(void)
+{
+	vFreeGpioIRQ(BT_WAKE_HOST);
+}
+
+
diff --git a/bl30/src_ao/demos/amlogic/driver/bt/t3_bt_common/btwake.h b/bl30/src_ao/demos/amlogic/driver/bt/t3_bt_common/btwake.h
new file mode 100644
index 0000000..821f721
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/bt/t3_bt_common/btwake.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C)2018 Amlogic, Inc. All rights reserved.
+ *
+ * All information contained herein is Amlogic confidential.
+ *
+ * This software is provided to you pursuant to Software License Agreement
+ * (SLA) with Amlogic Inc ("Amlogic"). This software may be used
+ * only in accordance with the terms of this agreement.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification is strictly prohibited without prior written permission from
+ * Amlogic.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER 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, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _BTWAKE_H_
+#define _BTWAKE_H_
+
+#define UNUSED(x) ((void)x)
+#define BT_WAKE_HOST GPIOC_14  //bt_wake_host pin
+#define INFO(fmt, args...) printf("[%s] " fmt "\n", __func__, ##args)
+
+void Bt_IRQHandle(void);
+void Bt_GpioIRQRegister(void);
+void Bt_GpioIRQFree(void);
+
+#endif
\ No newline at end of file
diff --git a/bl30/src_ao/demos/amlogic/driver/bt/t3_bt_common/build.mk b/bl30/src_ao/demos/amlogic/driver/bt/t3_bt_common/build.mk
new file mode 100644
index 0000000..0be09b3
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/bt/t3_bt_common/build.mk
@@ -0,0 +1,26 @@
+#
+#  Copyright (C) 2014-2018 Amlogic, Inc. All rights reserved.
+#
+#  All information contained herein is Amlogic confidential.
+#
+#  This software is provided to you pursuant to Software License Agreement
+#  (SLA) with Amlogic Inc ("Amlogic"). This software may be used
+#  only in accordance with the terms of this agreement.
+#
+#  Redistribution and use in source and binary forms, with or without
+#  modification is strictly prohibited without prior written permission from
+#  Amlogic.
+#
+#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#  OWNER 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, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+t3_bt_common-y = btwake.o
diff --git a/bl30/src_ao/demos/amlogic/driver/cec/build.mk b/bl30/src_ao/demos/amlogic/driver/cec/build.mk
new file mode 100644
index 0000000..2777635
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/cec/build.mk
@@ -0,0 +1,26 @@
+#
+#  Copyright (C) 2014-2018 Amlogic, Inc. All rights reserved.
+#
+#  All information contained herein is Amlogic confidential.
+#
+#  This software is provided to you pursuant to Software License Agreement
+#  (SLA) with Amlogic Inc ("Amlogic"). This software may be used
+#  only in accordance with the terms of this agreement.
+#
+#  Redistribution and use in source and binary forms, with or without
+#  modification is strictly prohibited without prior written permission from
+#  Amlogic.
+#
+#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#  OWNER 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, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+cec-y = hdmi_cec.o
diff --git a/bl30/src_ao/demos/amlogic/driver/cec/hdmi_cec.c b/bl30/src_ao/demos/amlogic/driver/cec/hdmi_cec.c
new file mode 100644
index 0000000..6cb11ab
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/cec/hdmi_cec.c
@@ -0,0 +1,2423 @@
+/**************************************************
+ *           HDMI CEC uboot code                  *
+ *                                                *
+ **************************************************/
+/* Kernel includes. */
+#include "FreeRTOS.h" /* Must come first. */
+#include "task.h"     /* RTOS task related API prototypes. */
+#include "queue.h"    /* RTOS queue related API prototypes. */
+#include "timers.h"   /* Software timer related API prototypes. */
+#include "semphr.h"   /* Semaphore related API prototypes. */
+#include "myprintf.h"
+#include "common.h"
+#include "util.h"
+#include <unistd.h>
+#include "irq.h"
+//#include "n200_eclic.h"
+#include "n200_func.h"
+#include "projdefs.h"
+#include "portmacro.h"
+#include "suspend.h"
+#include "mailbox-api.h"
+#include "rpc-user.h"
+#include "register.h"
+#include "gpio.h"
+
+#define CONFIG_CEC_WAKEUP
+#ifdef CONFIG_CEC_WAKEUP
+#include "hdmi_cec.h"
+#include "cec-data.h"
+#include "hdmi_cec_reg.h"
+#ifndef NULL
+
+#define NULL ((void *)0)
+#endif
+
+#define CEC_REG_DEBUG		0
+#define CEC_CFG_DEBUG		0
+#define CEC_TASK_DEBUG		0
+#define CEC_FW_DEBUG		0
+
+#define PHY_ADDR_LEN		4 /*16bit/4bit*/
+
+#define DEVICE_TV		0
+#define DEVICE_RECORDER		1
+#define DEVICE_RESERVED		2
+#define DEVICE_TUNER		3
+#define DEVICE_PLAYBACK		4
+#define DEVICE_AUDIO_SYSTEM	5
+#define DEVICE_PURE_CEC_SWITCH	6
+#define DEVICE_VIDEO_PROCESSOR	7
+
+typedef struct {
+	unsigned int wk_logic_addr:8;
+	unsigned int wk_phy_addr:16;
+	unsigned int wk_port_id:8;
+}cec_wakeup_t;
+
+struct st_cec_mailbox_data {
+	unsigned int cec_config;
+	unsigned int phy_addr;
+	unsigned int vendor_id;
+	unsigned char osd_name[16];
+} __packed;
+
+static unsigned int cec_wait_addr;
+static cec_wakeup_t cec_wakup;
+static unsigned char hdmi_cec_func_config;
+static cec_msg_t cec_msg;
+static u32 cec_wakup_flag;
+struct st_cec_mailbox_data cec_mailbox;
+static enum cec_chip_ver cec_chip = CEC_CHIP_SC2;
+static u32 cec_ip;
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+/* [0] for msg len */
+static unsigned char cec_otp_msg[17];
+static unsigned char cec_as_msg[17];
+static void cec_set_wk_msg(unsigned char *otp_msg, unsigned char *as_msg);
+
+struct cec_tx_msg_t {
+	unsigned char buf[16];
+	unsigned char retry;
+	unsigned char len;
+};
+
+#define CEX_TX_MSG_BUF_NUM	  4
+#define CEC_TX_MSG_BUF_MASK	 (CEX_TX_MSG_BUF_NUM - 1)
+
+struct cec_tx_msg {
+	struct cec_tx_msg_t msg[CEX_TX_MSG_BUF_NUM];
+	unsigned char send_idx;
+	unsigned char queue_idx;
+};
+
+struct cec_tx_msg cec_tx_msgs = {};
+static void cec_reset_addr(void);
+
+#ifdef CEC_CHIP_SEL_T7
+/*T7 same with SC2 register enum cec_reg_idx */
+unsigned int cec_reg_tab[] = {
+	CLKCTRL_CECA_CTRL0,
+	CLKCTRL_CECA_CTRL1,
+	CECA_GEN_CNTL,
+	CECA_RW_REG,
+	CECA_INTR_MASKN,
+	CECA_INTR_CLR,
+	CECA_INTR_STAT,
+
+	CLKCTRL_CECB_CTRL0,
+	CLKCTRL_CECB_CTRL1,
+	CECB_GEN_CNTL,
+	CECB_RW_REG,
+	CECB_INTR_MASKN,
+	CECB_INTR_CLR,
+	CECB_INTR_STAT,
+
+	SYSCTRL_STATUS_REG0,
+	SYSCTRL_STATUS_REG1,
+
+	0xffff,//AO_CEC_STICKY_DATA0,
+	0xffff,//AO_CEC_STICKY_DATA1,
+	0xffff,//AO_CEC_STICKY_DATA2,
+	0xffff,//AO_CEC_STICKY_DATA3,
+	0xffff,//AO_CEC_STICKY_DATA4,
+	0xffff,//AO_CEC_STICKY_DATA5,
+	0xffff,//AO_CEC_STICKY_DATA6,
+	0xffff,//AO_CEC_STICKY_DATA7,
+};
+#endif
+
+#ifdef CEC_CHIP_SEL_S4
+/*s4 register enum cec_reg_idx */
+unsigned int cec_reg_tab[] = {
+	CLKCTRL_CECA_CTRL0,
+	CLKCTRL_CECA_CTRL1,
+	CECA_GEN_CNTL,
+	CECA_RW_REG,
+	CECA_INTR_MASKN,
+	CECA_INTR_CLR,
+	CECA_INTR_STAT,
+
+	CLKCTRL_CECB_CTRL0,
+	CLKCTRL_CECB_CTRL1,
+	CECB_GEN_CNTL,
+	CECB_RW_REG,
+	CECB_INTR_MASKN,
+	CECB_INTR_CLR,
+	CECB_INTR_STAT,
+
+	SYSCTRL_STATUS_REG0,
+	SYSCTRL_STATUS_REG1,
+
+	0xffff,//AO_CEC_STICKY_DATA0,
+	0xffff,//AO_CEC_STICKY_DATA1,
+	0xffff,//AO_CEC_STICKY_DATA2,
+	0xffff,//AO_CEC_STICKY_DATA3,
+	0xffff,//AO_CEC_STICKY_DATA4,
+	0xffff,//AO_CEC_STICKY_DATA5,
+	0xffff,//AO_CEC_STICKY_DATA6,
+	0xffff,//AO_CEC_STICKY_DATA7,
+};
+#endif
+
+#ifdef CEC_CHIP_SEL_SC2
+/*SC2 register enum cec_reg_idx */
+unsigned int cec_reg_tab[] = {
+	CLKCTRL_CECA_CTRL0,
+	CLKCTRL_CECA_CTRL1,
+	CECA_GEN_CNTL,
+	CECA_RW_REG,
+	CECA_INTR_MASKN,
+	CECA_INTR_CLR,
+	CECA_INTR_STAT,
+
+	CLKCTRL_CECB_CTRL0,
+	CLKCTRL_CECB_CTRL1,
+	CECB_GEN_CNTL,
+	CECB_RW_REG,
+	CECB_INTR_MASKN,
+	CECB_INTR_CLR,
+	CECB_INTR_STAT,
+
+	SYSCTRL_STATUS_REG0,
+	SYSCTRL_STATUS_REG1,
+
+	0xffff,//AO_CEC_STICKY_DATA0,
+	0xffff,//AO_CEC_STICKY_DATA1,
+	0xffff,//AO_CEC_STICKY_DATA2,
+	0xffff,//AO_CEC_STICKY_DATA3,
+	0xffff,//AO_CEC_STICKY_DATA4,
+	0xffff,//AO_CEC_STICKY_DATA5,
+	0xffff,//AO_CEC_STICKY_DATA6,
+	0xffff,//AO_CEC_STICKY_DATA7,
+};
+#endif
+
+#ifdef CEC_CHIP_SEL_T5
+/*T5 register table enum cec_reg_idx*/
+unsigned int cec_reg_tab[] ={
+	0xffff,/*AO_CEC_CLK_CNTL_REG0*/
+	0xffff,/*AO_CEC_CLK_CNTL_REG1*/
+	0xffff,/*AO_CEC_GEN_CNTL*/
+	0xffff,/*AO_CEC_RW_REG*/
+	0xffff,/*AO_CEC_INTR_MASKN*/
+	0xffff,/*AO_CEC_INTR_CLR*/
+	0xffff,/*AO_CEC_INTR_STAT*/
+
+	AO_CECB_CLK_CNTL_REG0,
+	AO_CECB_CLK_CNTL_REG1,
+	AO_CECB_GEN_CNTL,
+	AO_CECB_RW_REG,
+	AO_CECB_INTR_MASKN,
+	AO_CECB_INTR_CLR,
+	AO_CECB_INTR_STAT,
+
+	AO_DEBUG_REG0,
+	AO_DEBUG_REG1,
+
+	AO_CEC_STICKY_DATA0,
+	AO_CEC_STICKY_DATA1,/*port info return val to kernel*/
+	AO_CEC_STICKY_DATA2,/*not use*/
+	AO_CEC_STICKY_DATA3,/*not use*/
+	AO_CEC_STICKY_DATA4,/*not use*/
+	AO_CEC_STICKY_DATA5,/*not use*/
+	AO_CEC_STICKY_DATA6,/*not use*/
+	AO_CEC_STICKY_DATA7,/*not use*/
+};
+#endif
+
+#ifdef CEC_CHIP_SEL_T3
+/*T3 register table enum cec_reg_idx*/
+unsigned int cec_reg_tab[] = {
+	0xffff,/*CLKCTRL_CECA_CTRL0*/
+	0xffff,/*CLKCTRL_CECA_CTRL1*/
+	0xffff,/*CECA_GEN_CNTL*/
+	0xffff,/*CECA_RW_REG*/
+	0xffff,/*CECA_INTR_MASKN*/
+	0xffff,/*CECA_INTR_CLR*/
+	0xffff,/*CECA_INTR_STAT*/
+
+	CLKCTRL_CECB_CTRL0,
+	CLKCTRL_CECB_CTRL1,
+	CECB_GEN_CNTL,
+	CECB_RW_REG,
+	CECB_INTR_MASKN,
+	CECB_INTR_CLR,
+	CECB_INTR_STAT,
+
+	SYSCTRL_STATUS_REG0,
+	SYSCTRL_STATUS_REG1,
+
+	SYSCTRL_CEC_STICKY_REG0,
+	SYSCTRL_CEC_STICKY_REG1,/*port info for kernel*/
+	SYSCTRL_CEC_STICKY_REG2,/*not use*/
+	SYSCTRL_CEC_STICKY_REG3,/*not use*/
+	SYSCTRL_CEC_STICKY_REG4,/*not use*/
+	SYSCTRL_CEC_STICKY_REG5,/*not use*/
+	SYSCTRL_CEC_STICKY_REG6,/*not use*/
+	SYSCTRL_CEC_STICKY_REG7,/*not use*/
+};
+
+#endif
+
+#if CEC_REG_DEBUG
+static const char * const ceca_reg_name1[] = {
+	"CEC_TX_MSG_LENGTH",
+	"CEC_TX_MSG_CMD",
+	"CEC_TX_WRITE_BUF",
+	"CEC_TX_CLEAR_BUF",
+	"CEC_RX_MSG_CMD",
+	"CEC_RX_CLEAR_BUF",
+	"CEC_LOGICAL_ADDR0",
+	"CEC_LOGICAL_ADDR1",
+	"CEC_LOGICAL_ADDR2",
+	"CEC_LOGICAL_ADDR3",
+	"CEC_LOGICAL_ADDR4",
+	"CEC_CLOCK_DIV_H",
+	"CEC_CLOCK_DIV_L"
+};
+
+static const char * const ceca_reg_name2[] = {
+	"CEC_RX_MSG_LENGTH",
+	"CEC_RX_MSG_STATUS",
+	"CEC_RX_NUM_MSG",
+	"CEC_TX_MSG_STATUS",
+	"CEC_TX_NUM_MSG"
+};
+
+static const char * const ceca_reg_name3[] = {
+	"STAT_0_0",
+	"STAT_0_1",
+	"STAT_0_2",
+	"STAT_0_3",
+	"STAT_1_0",
+	"STAT_1_1",
+	"STAT_1_2"
+};
+#endif
+
+void cec_delay(u32 cnt)
+{
+	volatile u32 tmp = cnt;
+
+	while (tmp-- > 0) {
+		tmp = tmp;
+	}
+}
+
+static int cec_strlen(char *p)
+{
+	int i = 0;
+
+	while (*p++)
+		i++;
+	return i;
+}
+
+static void *cec_memcpy(void *memto, const void *memfrom, unsigned int size)
+{
+	char *tempfrom = (char *)memfrom;
+	char *tempto = (char *)memto;
+
+	if ((memto == NULL) || (memfrom == NULL))
+		return NULL;
+	while (size -- > 0)
+		*tempto++ = *tempfrom++;
+	return memto;
+}
+
+void *cec_update_config_data(void *data)
+{
+	unsigned int i;
+
+	memcpy((void *)&cec_mailbox, data, sizeof(struct st_cec_mailbox_data));
+
+	if (cec_mailbox.cec_config & CEC_CFG_DBG_EN) {
+		printf("cec_config:0x%x\n", cec_mailbox.cec_config);
+		printf("phy_addr:0x%x\n", cec_mailbox.phy_addr);
+		printf("vendor_id:0x%x\n", cec_mailbox.vendor_id);
+		printf("osd_name:");
+		for (i = 0; i < 16; i++) {
+			printf(" 0x%x", cec_mailbox.osd_name[i]);
+		}
+		printf("\n");
+	}
+
+	return NULL;
+}
+
+void cec_update_phyaddress(unsigned int phyaddr)
+{
+	cec_mailbox.phy_addr = cec_mailbox.phy_addr & 0xffff0000;
+	cec_mailbox.phy_addr |= phyaddr & 0xffff;
+	printf("update phyaddr:0x%x\n", phyaddr);
+}
+
+void cec_update_func_cfg(unsigned int cfg)
+{
+	cec_mailbox.cec_config = cfg;
+
+	if (hdmi_cec_func_config & CEC_CFG_DBG_EN) {
+		printf("cec_config:0x%x\n", cfg);
+	}
+}
+
+static void write_ao(enum cec_reg_idx addr, unsigned int data)
+{
+	unsigned int real_addr;
+
+	real_addr = cec_reg_tab[addr];
+
+	if (real_addr == 0xffff) {
+		printf("%s no reg:0x%x", __func__, addr);
+		return;
+	}
+#if CEC_FW_DEBUG
+	//printf("%s :0x%x val:0x%x\n", __func__, real_addr, data);
+#endif
+	REG32(real_addr) = data;
+}
+
+static unsigned int read_ao(enum cec_reg_idx addr)
+{
+	unsigned int real_addr;
+	unsigned int data;
+
+	real_addr = cec_reg_tab[addr];
+
+	if (real_addr == 0xffff) {
+		printf("%s no reg:0x%x\n", __func__, addr);
+		return 0x0;
+	}
+
+	data = REG32(real_addr);
+#if CEC_FW_DEBUG
+	//printf("%s :0x%x val:0x%x\n", __func__, real_addr, data);
+#endif
+	return data;
+}
+
+#if 1
+static unsigned long cecb_rd_reg(unsigned long addr)
+{
+	unsigned long data32;
+	unsigned int timeout = 0;
+
+	data32  = 0;
+	data32 |= 0    << 16;  // [16]   cec_reg_wr
+	data32 |= 0    << 8;   // [15:8] cec_reg_wrdata
+	data32 |= addr << 0;   // [7:0]  cec_reg_addr
+	write_ao(CECB_REG_RW_REG, data32);
+	while (data32 & (1 << 23)) {
+		if (timeout++ > 500) {
+			printf("cecb r reg 0x%x fail\n",
+				(unsigned int)addr);
+			break;
+		}
+		data32 = read_ao(CECB_REG_RW_REG);/*REG32(CECB_RW_REG);*/
+	}
+	data32 = ((read_ao(CECB_REG_RW_REG)) >> 24) & 0xff;
+	return (data32);
+} /* cecb_rd_reg */
+
+static void cecb_wr_reg (unsigned long addr, unsigned long data)
+{
+	unsigned long data32;
+	unsigned int timeout = 0;
+
+	data32 = read_ao(CECB_REG_RW_REG);
+	while (data32 & (1 << 23)) {
+		if (timeout++ > 200) {
+			printf("cecb w reg 0x%x fail\n",
+				(unsigned int)addr);
+			break;
+		}
+		/*data32 = REG32(CECB_RW_REG);*/
+		data32 = read_ao(CECB_REG_RW_REG);
+	}
+
+	data32  = 0;
+	data32 |= 1 << 16;  // [16]   cec_reg_wr
+	data32 |= data << 8;   // [15:8] cec_reg_wrdata
+	data32 |= addr << 0;   // [7:0]  cec_reg_addr
+	write_ao(CECB_REG_RW_REG, data32);
+} /* aocec_wr_only_reg */
+
+static inline void cecb_set_bits(uint32_t reg, uint32_t bits,
+				       uint32_t start, uint32_t len)
+{
+	unsigned int tmp;
+	tmp = cecb_rd_reg(reg);
+	tmp &= ~(((1 << len) - 1) << start);
+	tmp |=  (bits << start);
+	cecb_wr_reg(reg, tmp);
+}
+#endif
+
+#if 1
+static unsigned long ceca_rd_reg(unsigned long addr)
+{
+	unsigned long data32;
+	unsigned int timeout = 0;
+
+	data32  = 0;
+	data32 |= 0    << 16;  // [16]   cec_reg_wr
+	data32 |= 0    << 8;   // [15:8] cec_reg_wrdata
+	data32 |= addr << 0;   // [7:0]  cec_reg_addr
+	write_ao(CECA_REG_RW_REG, data32);
+	while (data32 & (1 << 23)) {
+		if (timeout++ > 500) {
+			printf("cecb r reg 0x%x fail\n",
+				(unsigned int)addr);
+			break;
+		}
+		data32 = read_ao(CECA_REG_RW_REG);
+	}
+	data32 = ((read_ao(CECA_REG_RW_REG)) >> 24) & 0xff;
+	return (data32);
+} /* cecb_rd_reg */
+
+static void ceca_wr_reg (unsigned long addr, unsigned long data)
+{
+	unsigned long data32;
+	unsigned int timeout = 0;
+
+	data32 = read_ao(CECA_REG_RW_REG);
+	while (data32 & (1 << 23)) {
+		if (timeout++ > 200) {
+			printf("cecb w reg 0x%x fail\n",
+				(unsigned int)addr);
+			break;
+		}
+		data32 = read_ao(CECA_REG_RW_REG);
+	}
+
+	data32  = 0;
+	data32 |= 1 << 16;  // [16]   cec_reg_wr
+	data32 |= data << 8;   // [15:8] cec_reg_wrdata
+	data32 |= addr << 0;   // [7:0]  cec_reg_addr
+	write_ao(CECA_REG_RW_REG, data32);
+} /* aocec_wr_only_reg */
+
+#if 0
+static inline void ceca_set_bits(uint32_t reg, uint32_t bits,
+				       uint32_t start, uint32_t len)
+{
+	unsigned int tmp;
+
+	tmp = ceca_rd_reg(reg);
+	tmp &= ~(((1 << len) - 1) << start);
+	tmp |=  (bits << start);
+	ceca_wr_reg(reg, tmp);
+}
+#endif
+
+#endif
+
+static void cec_set_reg_bits(enum cec_reg_idx addr, unsigned int value,
+	unsigned int offset, unsigned int len)
+{
+	unsigned int data32 = 0;
+
+	data32 = read_ao(addr);//REG32(addr);
+	data32 &= ~(((1 << len) - 1) << offset);
+	data32 |= (value & ((1 << len) - 1)) << offset;
+	//REG32(addr) = data32;
+	write_ao(addr, data32);
+}
+
+static void cec_rx_read_pos_plus(void)
+{
+	(cec_msg.rx_read_pos ==  cec_msg.rx_buf_size - 1) ?
+				(cec_msg.rx_read_pos = 0) :
+				(cec_msg.rx_read_pos++);
+}
+
+#if CEC_REG_DEBUG
+static void dump_cec_reg(void)
+{
+	u32 i = 0;
+	unsigned char reg;
+	unsigned int reg32;
+
+	if (cec_ip == CEC_B) {
+		reg32 = read_ao(CECB_REG_CLK_CNTL_REG0);
+		printf("CECB_CLK_CNTL0:0x%x\n", reg32);
+		reg32 = read_ao(CECB_REG_CLK_CNTL_REG1);
+		printf("CECB_CLK_CNTL1:0x%x\n", reg32);
+		reg32 = read_ao(CECB_REG_GEN_CNTL);
+		printf("CECB_GEN_CNTL:0x%x\n", reg32);
+		reg32 = read_ao(CECB_REG_RW_REG);
+		printf("CECB_RW:0x%x\n", reg32);
+		reg32 = read_ao(CECB_REG_INTR_MASKN);
+		printf("CECB_INT_MASKN:0x%x\n", reg32);
+		reg32 = read_ao(CECB_REG_INTR_STAT);
+		printf("CECB_INT_STAT:0x%x\n", reg32);
+
+		printf("CECB_CTRL:0x%x\n", cecb_rd_reg(DWC_CECB_CTRL));
+		printf("CECB_CTRL2:0x%x\n", cecb_rd_reg(DWC_CECB_CTRL2));
+		printf("CECB_MASK:0x%x\n", cecb_rd_reg(DWC_CECB_INTR_MASK));
+		printf("CECB_ADDR_L:0x%x\n", cecb_rd_reg(DWC_CECB_LADD_LOW));
+		printf("CECB_ADDR_H:0x%x\n", cecb_rd_reg(DWC_CECB_LADD_HIGH));
+		printf("CECB_TX_CNT:0x%x\n", cecb_rd_reg(DWC_CECB_TX_CNT));
+		printf("CECB_RX_CNT:0x%x\n", cecb_rd_reg(DWC_CECB_RX_CNT));
+		printf("CECB_STAT0:0x%x\n", cecb_rd_reg(DWC_CECB_STAT0));
+		printf("CECB_LOCK:0x%x\n", cecb_rd_reg(DWC_CECB_LOCK_BUF));
+		printf("CECB_WKUPCTRL:0x%x\n", cecb_rd_reg(DWC_CECB_WAKEUPCTRL));
+
+		printf("CECB_RX buffer:");
+		for (i = 0; i < 16; i++) {
+			reg = cecb_rd_reg(DWC_CECB_RX_DATA00 + i);
+			printf(" 0x%x", reg);
+		}
+		printf("\n");
+		printf("CECB_TX buffer:");
+		for (i = 0; i < 16; i++) {
+			reg = cecb_rd_reg(DWC_CECB_TX_DATA00 + i);
+			printf(" 0x%x", reg);
+		}
+	} else {
+		reg32 = read_ao(CECA_REG_CLK_CNTL_REG0);
+		printf("CECA_CLK_CNTL0:0x%x\n", reg32);
+		reg32 = read_ao(CECA_REG_CLK_CNTL_REG1);
+		printf("CECA_CLK_CNTL1:0x%x\n", reg32);
+		reg32 = read_ao(CECA_REG_GEN_CNTL);
+		printf("CECA_GEN_CNTL:0x%x\n", reg32);
+		reg32 = read_ao(CECA_REG_RW_REG);
+		printf("CECA_RW:0x%x\n", reg32);
+		reg32 = read_ao(CECA_REG_INTR_MASKN);
+		printf("CECA_INT_MASKN:0x%x\n", reg32);
+		reg32 = read_ao(CECA_REG_INTR_STAT);
+		printf("CECA_INT_STAT:0x%x\n", reg32);
+
+		for (i = 0; i < ARRAY_SIZE(ceca_reg_name1); i++)
+			printf("%s:0x%x\n", ceca_reg_name1[i], ceca_rd_reg(i + 0x10));
+
+		for (i = 0; i < ARRAY_SIZE(ceca_reg_name2); i++)
+			printf("%s:0x%x\n", ceca_reg_name2[i], ceca_rd_reg(i + 0x90));
+
+		for (i = 0; i < ARRAY_SIZE(ceca_reg_name3); i++)
+			printf("%s:0x%x\n", ceca_reg_name3[i], ceca_rd_reg(i + 0xa0));
+	}
+	printf("\n");
+}
+#endif
+
+/* for back, replace it with cec_set_wk_msg() */
+static u32 set_cec_wakeup_port_info(unsigned int port_info)
+{
+	printf("%s wakeup port info:0x%x\n", __func__, port_info);
+	/* write_ao(CEC_REG_STICK_DATA1, port_info); */
+	return 0;
+}
+
+/* OTP message */
+static void *cec_get_wakeup_info1(void *msg)
+{
+	u32 val;
+
+	/*val = cec_wakup.wk_logic_addr | (cec_wakup.wk_phy_addr << 8) |*/
+	/*	(cec_wakup.wk_port_id << 24);*/
+	val = read_ao(CEC_REG_STICK_DATA1);
+	/* need to clear wakeup info after read,
+	 * avoid it's mis-used in next wakeup
+	 */
+	write_ao(CEC_REG_STICK_DATA1, 0);
+	*(u32 *)msg = val;
+	printf("[%s]: info=0x%x\n", __func__, val);
+
+	return NULL;
+}
+
+/* active source message */
+static void *cec_get_wakeup_info2(void *msg)
+{
+	u32 val;
+
+	val = read_ao(CEC_REG_STICK_DATA2);
+	/* need to clear wakeup info after read,
+	 * avoid it's mis-used in next wakeup
+	 */
+	write_ao(CEC_REG_STICK_DATA2, 0);
+	*(u32 *)msg = val;
+	printf("[%s]: info=0x%x\n", __func__, val);
+
+	return NULL;
+}
+
+static void cec_enable_irq(u32 onoff)
+{
+	if (cec_ip == CEC_B) {
+		if (onoff) {
+			/*enable the interrupt*/
+			/*REG32(CECB_INTR_MASKN) = CECB_IRQ_EN_MASK;*/
+			write_ao(CECB_REG_INTR_MASKN, CECB_IRQ_EN_MASK);
+			cecb_wr_reg(DWC_CECB_WAKEUPCTRL, WAKEUP_DIS_MASK);
+		} else {
+			/*REG32(CECB_INTR_MASKN) = 0;*/
+			write_ao(CECB_REG_INTR_MASKN, 0);
+			cecb_wr_reg(DWC_CECB_WAKEUPCTRL, WAKEUP_DIS_MASK);
+		}
+	} else {
+		if (onoff)
+			cec_set_reg_bits(CECA_REG_INTR_MASKN, 0x6, 0, 3);
+		else
+			cec_set_reg_bits(CECA_REG_INTR_MASKN, 0x0, 0, 3);
+	}
+	/*printf("%s cec_ip:%d\n", __func__);*/
+}
+
+static void cec_clear_int_sts(void)
+{
+	unsigned int reg;
+
+	if (cec_ip == CEC_B) {
+		reg = read_ao(CECB_REG_INTR_STAT);
+		if (reg)
+			write_ao(CECB_REG_INTR_CLR, reg);
+	} else {
+		reg = read_ao(CECA_REG_INTR_STAT);
+		if (reg)
+			write_ao(CECA_REG_INTR_CLR, reg);
+	}
+}
+
+#if 0
+static void cec_sts_check(void)
+{
+	printf("CECB_INTR_STAT=0x%x\n", read_ao(CECB_REG_INTR_STAT));
+	printf("DWC_CECB_LOCK_BUF=0x%x\n", cecb_rd_reg(DWC_CECB_LOCK_BUF));
+	printf("DWC_CECB_CTRL=0x%x\n", cecb_rd_reg(DWC_CECB_CTRL));
+}
+#endif
+
+static u32 cec_set_pin_mux(u32 chip)
+{
+	u32 chip_type = chip;
+
+	xPinmuxSet(CEC_PIN_MX, CEC_PIN_FUNC);
+	printf("%s pin mux:0x%x func:0x%x\n", __func__, CEC_PIN_MX, CEC_PIN_FUNC);
+	return chip_type;
+}
+
+static void cec_ip_share_io(u32 share, u32 ip)
+{
+	if (share) {
+		if (ip == CEC_A) {
+			cec_set_reg_bits(CECA_REG_GEN_CNTL, 1, 4, 1);
+			cec_set_reg_bits(CECB_REG_GEN_CNTL, 0, 4, 1);
+			printf("share pin mux to b\n");
+		} else {
+			cec_set_reg_bits(CECA_REG_GEN_CNTL, 0, 4, 1);
+			cec_set_reg_bits(CECB_REG_GEN_CNTL, 1, 4, 1);
+			/* printf("share pin mux to a\n"); */
+		}
+	} else {
+		cec_set_reg_bits(CECA_REG_GEN_CNTL, 0, 4, 1);
+		cec_set_reg_bits(CECB_REG_GEN_CNTL, 0, 4, 1);
+	}
+}
+
+#if (CEC_IP == CEC_B)
+static u32 cecb_hw_reset(void)
+{
+#if (CEC_IP == CEC_B)
+	unsigned int reg;
+	unsigned int data32;
+
+	printf("cecb reset\n");
+	reg =   (0 << 31) |
+		(0 << 30) |
+		(1 << 28) |		/* clk_div0/clk_div1 in turn */
+		((732-1) << 12) |	/* Div_tcnt1 */
+		((733-1) << 0);		/* Div_tcnt0 */
+	/*REG32(CLKCTRL_CECB_CTRL0) = reg;*/
+	write_ao(CECB_REG_CLK_CNTL_REG0, reg);
+	reg =   (0 << 13) |
+		((11-1)  << 12) |
+		((8-1)  <<  0);
+	/*REG32(CLKCTRL_CECB_CTRL1) = reg;*/
+	write_ao(CECB_REG_CLK_CNTL_REG1, reg);
+
+	reg = read_ao(CECB_REG_CLK_CNTL_REG0);/*REG32(CLKCTRL_CECB_CTRL0);*/
+	reg |= (1 << 31);
+	/*REG32(CLKCTRL_CECB_CTRL0) = reg;*/
+	write_ao(CECB_REG_CLK_CNTL_REG0, reg);
+
+	/*_udelay(200);*/
+	reg |= (1 << 30);
+	/*REG32(CLKCTRL_CECB_CTRL0) = reg;*/
+	write_ao(CECB_REG_CLK_CNTL_REG0, reg);
+
+	data32  = 0;
+	data32 |= (7 << 12);	/* filter_del */
+	data32 |= (1 <<  8);	/* filter_tick: 1us */
+	data32 |= (1 <<  3);	/* enable system clock */
+	data32 |= 0 << 1;	/* [2:1]	cntl_clk: */
+				/* 0=Disable clk (Power-off mode); */
+				/* 1=Enable gated clock (Normal mode); */
+				/* 2=Enable free-run clk (Debug mode). */
+	data32 |= 1 << 0;	/* [0]	  sw_reset: 1=Reset */
+	/*REG32(CECB_GEN_CNTL) = data32;*/
+	write_ao(CECB_REG_GEN_CNTL, data32);
+	/* Enable gated clock (Normal mode). */
+	cec_set_reg_bits(CECB_REG_GEN_CNTL, 1, 1, 1);
+	/* Release SW reset */
+	cec_set_reg_bits(CECB_REG_GEN_CNTL, 0, 0, 1);
+
+	reg = 0;
+	reg |= (0 << 6);/*curb_err_init*/
+	reg |= (0 << 5);/*en_chk_sbitlow*/
+	reg |= (2 << 0);/*rise_del_max*/
+	cecb_wr_reg(DWC_CECB_CTRL2, reg);
+	cec_set_pin_mux(cec_chip);
+	/* on T7, only use CEC_A pin for CEC on board,
+	 * for cec robustness, use cecb controller
+	 * with CEC_A pin(share to CEC_B)
+	 */
+	if (cec_chip == CEC_CHIP_T7)
+		cec_ip_share_io(1, CEC_A);
+	cec_clear_int_sts();
+	/*enable the interrupt*/
+	cec_enable_irq(1);
+	cec_delay(200);
+#endif
+	return 0;
+}
+#endif
+
+#if (CEC_IP != CEC_B)
+static u32 ceca_hw_reset(void)
+{
+#if (CEC_IP == CEC_A)
+	unsigned int reg;
+	unsigned int data32;
+
+	printf("ceca reset\n");
+	reg =	(0 << 31) |
+		(0 << 30) |
+		(1 << 28) |		/* clk_div0/clk_div1 in turn */
+		((732-1) << 12) |	/* Div_tcnt1 */
+		((733-1) << 0); 	/* Div_tcnt0 */
+	write_ao(CECA_REG_CLK_CNTL_REG0, reg);
+	reg =	(0 << 13) |
+		((11-1)  << 12) |
+		((8-1)	<<  0);
+	write_ao(CECA_REG_CLK_CNTL_REG1, reg);
+
+	reg = read_ao(CECA_REG_CLK_CNTL_REG0);
+	reg |= (1 << 31);
+	write_ao(CECA_REG_CLK_CNTL_REG0, reg);
+
+	cec_delay(200);
+	reg |= (1 << 30);
+	write_ao(CECA_REG_CLK_CNTL_REG0, reg);
+
+	data32	= 0;
+	data32 |= (7 << 12);	/* filter_del */
+	data32 |= (1 <<  8);	/* filter_tick: 1us */
+	data32 |= (1 <<  3);	/* enable system clock */
+	data32 |= 0 << 1;	/* [2:1]	cntl_clk: */
+				/* 0=Disable clk (Power-off mode); */
+				/* 1=Enable gated clock (Normal mode); */
+				/* 2=Enable free-run clk (Debug mode). */
+	data32 |= 1 << 0;	/* [0]	  sw_reset: 1=Reset */
+	write_ao(CECA_REG_GEN_CNTL, data32);
+	/* Enable gated clock (Normal mode). */
+	cec_set_reg_bits(CECA_REG_GEN_CNTL, 1, 1, 1);
+	/* Release SW reset */
+	cec_set_reg_bits(CECA_REG_GEN_CNTL, 0, 0, 1);
+
+	cec_set_pin_mux(cec_chip);
+
+	cec_clear_int_sts();
+	/*enable the interrupt*/
+	cec_enable_irq(1);
+	cec_delay(200);
+#endif
+	return 0;
+}
+#endif
+
+static u32 cec_hw_reset(void)
+{
+#if (CEC_IP == CEC_B)
+	cecb_hw_reset();
+#else
+	ceca_hw_reset();
+#endif
+
+	return 0;
+}
+
+static unsigned char remote_cecb_ll_rx(void)
+{
+	int i;
+	int len;
+
+	len = cecb_rd_reg(DWC_CECB_RX_CNT);
+	printf("cec R:");
+	for (i = 0; i < len; i++) {
+		cec_msg.buf[cec_msg.rx_write_pos].msg[i] = cecb_rd_reg(DWC_CECB_RX_DATA00 + i);
+		printf(" 0x%02x", cec_msg.buf[cec_msg.rx_write_pos].msg[i]);
+	}
+	/* clr CEC lock bit */
+	cecb_wr_reg(DWC_CECB_LOCK_BUF, 0);
+	cec_msg.buf[cec_msg.rx_write_pos].msg_len = len;
+	printf("\n");
+	return 0;
+}
+
+static u32 ceca_rx_buf_clear(void)
+{
+	ceca_wr_reg(CECA_RX_CLEAR_BUF, 0x1);
+	ceca_wr_reg(CECA_RX_CLEAR_BUF, 0x0);
+
+	return 0;
+}
+
+static unsigned char remote_ceca_ll_rx(void)
+{
+	int i;
+	int len;
+
+	len = ceca_rd_reg(CECA_RX_MSG_LENGTH) + 1;
+	printf("cec R:");
+	for (i = 0; i < len; i++) {
+		cec_msg.buf[cec_msg.rx_write_pos].msg[i] = ceca_rd_reg(CECA_RX_MSG_0_HEADER + i);
+		printf(" 0x%02x", cec_msg.buf[cec_msg.rx_write_pos].msg[i]);
+	}
+
+	write_ao(CECA_REG_INTR_CLR, (1 << 2));
+	ceca_wr_reg(CECA_RX_MSG_CMD, RX_ACK_CURRENT);
+	ceca_wr_reg(CECA_RX_MSG_CMD, RX_NO_OP);
+	ceca_rx_buf_clear();
+	cec_msg.buf[cec_msg.rx_write_pos].msg_len = len;
+	printf("\n");
+	return 0;
+}
+
+static unsigned char remote_cec_ll_rx(void)
+{
+	if (cec_ip == CEC_B)
+		remote_cecb_ll_rx();
+	else
+		remote_ceca_ll_rx();
+
+	return 0;
+}
+
+static void cec_buf_clear(void)
+{
+	int i;
+
+	for (i = 0; i < 16; i++)
+		cec_msg.buf[cec_msg.rx_read_pos].msg[i] = 0;
+}
+
+static void cec_tx_buf_init(void)
+{
+	int i, j;
+	for (j = 0; j < CEX_TX_MSG_BUF_NUM; j++) {
+		for (i = 0; i < 16; i++) {
+			cec_tx_msgs.msg[j].buf[i] = 0;
+		}
+		cec_tx_msgs.msg[j].retry = 0;
+		cec_tx_msgs.msg[j].len = 0;
+	}
+}
+
+static int cec_queue_tx_msg(unsigned char *msg, unsigned char len)
+{
+	int s_idx, q_idx;
+
+	s_idx = cec_tx_msgs.send_idx;
+	q_idx = cec_tx_msgs.queue_idx;
+	if (((q_idx + 1) & CEC_TX_MSG_BUF_MASK) == s_idx) {
+		printf("tx buffer full, abort msg\n");
+		cec_reset_addr();
+		return -1;
+	}
+	if (len && msg) {
+		cec_memcpy(cec_tx_msgs.msg[q_idx].buf, msg, len);
+		cec_tx_msgs.msg[q_idx].len = len;
+		cec_tx_msgs.queue_idx = (q_idx + 1) & CEC_TX_MSG_BUF_MASK;
+	}
+	return 0;
+}
+
+static int cecb_trigger_tx(unsigned char *msg, unsigned char len)
+{
+	int i = 0, lock;
+
+	while (1) {
+		/* send is in process */
+		lock = cecb_rd_reg(DWC_CECB_LOCK_BUF);
+		if (lock) {
+			printf("rx msg in tx\n");
+			return -1;
+		}
+		if (cecb_rd_reg(DWC_CECB_CTRL) & 0x01)
+			i++;
+		else
+			break;
+		if (i > 25) {
+			printf("lock:0x%x, wait busy timeout\n", lock);
+			return -1;
+		}
+		cec_delay(50);
+	}
+
+	printf("cec T:");
+	for (i = 0; i < len; i++) {
+		cecb_wr_reg(DWC_CECB_TX_DATA00 + i, msg[i]);
+		printf(" 0x%02x", msg[i]);
+	}
+	printf("\n");
+
+	/* start send */
+	cecb_wr_reg(DWC_CECB_TX_CNT, len);
+	cecb_set_bits(DWC_CECB_CTRL, 3, 0, 3);
+	return 0;
+}
+
+static int ceca_trigger_tx(unsigned char *msg, unsigned char len)
+{
+	int i = 0/*, lock*/;
+	unsigned int j = 40;
+	unsigned int tx_stat;
+	static int cec_timeout_cnt = 1;
+
+	while (1) {
+		/*check idle*/
+		tx_stat = ceca_rd_reg(CECA_TX_MSG_STATUS);
+		if (tx_stat != TX_BUSY)
+			break;
+
+		if (!(j--)) {
+			printf("ceca waiting busy timeout\n");
+			ceca_wr_reg(CECA_TX_MSG_CMD, TX_ABORT);
+			cec_timeout_cnt++;
+			if (cec_timeout_cnt > 0x08)
+				cec_hw_reset();
+			break;
+		}
+
+		cec_delay(50);
+	}
+
+	tx_stat = ceca_rd_reg(CECA_TX_MSG_STATUS);
+	if (tx_stat == TX_IDLE || tx_stat == TX_DONE) {
+		printf("cec T:");
+		for (i = 0; i < len; i++) {
+			ceca_wr_reg(CECA_TX_MSG_0_HEADER + i, msg[i]);
+			printf(" 0x%02x", msg[i]);
+		}
+		printf("\n");
+
+		ceca_wr_reg(CECA_TX_MSG_LENGTH, len - 1);
+		ceca_wr_reg(CECA_TX_MSG_CMD, TX_REQ_CURRENT);
+	} else {
+		printf("err tx state 0x%x\n", tx_stat);
+	}
+
+	return 0;
+}
+
+static int cec_trigger_tx(unsigned char *msg, unsigned char len)
+{
+	int ret;
+
+	if (cec_ip == CEC_B)
+		ret = cecb_trigger_tx(msg, len);
+	else
+		ret = ceca_trigger_tx(msg, len);
+
+	return ret;
+}
+
+static int remote_cec_ll_tx(unsigned char *msg, unsigned char len)
+{
+	int ret = 0;
+
+	cec_queue_tx_msg(msg, len);
+	ret = cec_trigger_tx(msg, len);
+
+	return ret;
+}
+
+static int cecb_check_irq_sts(void)
+{
+	unsigned int reg;
+	unsigned int ret = TX_IDLE;
+	unsigned int cnt = 0;
+
+	while (cec_tx_msgs.queue_idx != cec_tx_msgs.send_idx) {
+		reg = read_ao(CECB_REG_INTR_STAT);
+		if (reg)
+			write_ao(CECB_REG_INTR_CLR, reg);
+
+		if (reg & CECB_IRQ_TX_DONE) {
+			ret = TX_DONE;
+			cec_tx_msgs.send_idx = (cec_tx_msgs.send_idx + 1) & CEC_TX_MSG_BUF_MASK;
+			printf("tx:TX_DONE %d\n", cnt);
+			break;
+		}
+
+		if (reg & CECB_IRQ_TX_NACK) {
+			ret = TX_ERROR;
+			cec_tx_msgs.send_idx = (cec_tx_msgs.send_idx + 1) & CEC_TX_MSG_BUF_MASK;
+			printf("tx:TX_NACK %d\n", cnt);
+			break;
+		}
+		if (reg & CECB_IRQ_TX_ARB_LOST) {
+			ret = TX_BUSY;
+			cec_tx_msgs.send_idx = (cec_tx_msgs.send_idx + 1) & CEC_TX_MSG_BUF_MASK;
+			printf("tx:TX_ABT_LOST %d\n", cnt);
+			break;
+		}
+		if (reg & CECB_IRQ_TX_ERR_INITIATOR) {
+			ret = TX_BUSY;
+			cec_tx_msgs.send_idx = (cec_tx_msgs.send_idx + 1) & CEC_TX_MSG_BUF_MASK;
+			printf("tx:TX_ERR_INIT %d\n", cnt);
+			break;
+		}
+
+		if (cnt++ >= 200) {
+			printf("%s time out %d\n", __func__, cnt);
+			/* cnt = 0; */
+			break;
+		}
+		cec_delay(200);
+	}
+
+	return ret;
+}
+
+static int ceca_check_irq_sts(void)
+{
+	unsigned int reg;
+	unsigned int ret = TX_IDLE;
+	unsigned int cnt = 0;
+	unsigned int int_st;
+
+	while (cec_tx_msgs.queue_idx != cec_tx_msgs.send_idx) {
+		int_st = read_ao(CECA_REG_INTR_STAT);
+		if (int_st)
+			write_ao(CECA_REG_INTR_CLR, int_st);
+		else
+
+		reg = ceca_rd_reg(CECA_TX_MSG_STATUS);
+		if ( reg == TX_DONE ) {
+			ret = TX_DONE;
+			ceca_wr_reg(CECA_TX_MSG_CMD, TX_NO_OP);
+			cec_tx_msgs.send_idx = (cec_tx_msgs.send_idx + 1) & CEC_TX_MSG_BUF_MASK;
+			printf("ping_cec_ll_tx:TX_DONE\n");
+			break;
+		}
+
+		if (reg == TX_ERROR) {
+			ret = TX_ERROR;
+			cec_tx_msgs.send_idx = (cec_tx_msgs.send_idx + 1) & CEC_TX_MSG_BUF_MASK;
+			ceca_wr_reg(CECA_TX_MSG_CMD, TX_NO_OP);
+			printf("ping_cec_ll_tx:TX_ERROR\n");
+			break;
+		}
+
+		if (reg != TX_BUSY) {
+			break;
+		}
+
+		if (cnt++ >= 200) {
+			printf("%s time out %d\n", __func__, cnt);
+			/* cnt = 0; */
+			break;
+		}
+		cec_delay(200);
+	}
+
+	return ret;
+}
+
+
+static int cec_check_irq_sts(void)
+{
+	unsigned int ret;
+
+	if (cec_ip == CEC_B)
+		ret = cecb_check_irq_sts();
+	else
+		ret = ceca_check_irq_sts();
+
+	return ret;
+}
+
+static int ping_cec_ll_tx(unsigned char *msg, unsigned char len)
+{
+	unsigned int ret = 0;
+
+	/*printf("ping: 0x%x\n", msg[0]);*/
+	ret = remote_cec_ll_tx(msg, len);
+	return ret;
+}
+
+static unsigned char log_addr_to_devtye(unsigned int addr)
+{
+	static unsigned char addr_map[] = {
+		DEVICE_TV,
+		DEVICE_RECORDER,
+		DEVICE_RECORDER,
+		DEVICE_TUNER,
+		DEVICE_PLAYBACK,
+		DEVICE_AUDIO_SYSTEM,
+		DEVICE_TUNER,
+		DEVICE_TUNER,
+		DEVICE_PLAYBACK,
+		DEVICE_RECORDER,
+		DEVICE_TUNER,
+		DEVICE_PLAYBACK,
+		DEVICE_RESERVED,
+		DEVICE_RESERVED,
+		DEVICE_TV
+	};
+	return addr_map[addr & 0xf];
+}
+
+/* if multi-addr is configured in kernel(4 + 5 for soundbar),
+ * then use CEC_AUDIO_SYSTEM_ADDR as default logic addr
+ * cec_msg.log_addr is configured as 5
+ */
+static void cec_report_physical_address(unsigned char source)
+{
+	unsigned char msg[5];
+
+	msg[0] = ((source & 0xf) << 4) | CEC_BROADCAST_ADDR;
+	msg[1] = CEC_OC_REPORT_PHYSICAL_ADDRESS;
+	msg[2] = (cec_mailbox.phy_addr >> 8) & 0xff;
+	msg[3] = cec_mailbox.phy_addr & 0xff;
+	msg[4] = log_addr_to_devtye(cec_msg.log_addr);
+
+	remote_cec_ll_tx(msg, 5);
+}
+
+static void cec_report_device_power_status(unsigned char source, unsigned char dst)
+{
+	unsigned char msg[3];
+
+	msg[0] = ((source & 0xf) << 4) | (dst & 0xf);
+	msg[1] = CEC_OC_REPORT_POWER_STATUS;
+	msg[2] = cec_msg.power_status;
+
+	remote_cec_ll_tx(msg, 3);
+}
+
+static void cec_set_stream_path(void)
+{
+	unsigned char phy_addr_ab = (cec_mailbox.phy_addr >> 8) & 0xff;
+	unsigned char phy_addr_cd = cec_mailbox.phy_addr & 0xff;
+
+	if ((hdmi_cec_func_config >> CEC_FUNC_MASK) & 0x1) {
+		if ((hdmi_cec_func_config >> AUTO_POWER_ON_MASK) & 0x1) {
+			if ((phy_addr_ab == cec_msg.buf[cec_msg.rx_read_pos].msg[2]) &&
+			    (phy_addr_cd == cec_msg.buf[cec_msg.rx_read_pos].msg[3]))  {
+				cec_msg.cec_power = 0x1;
+				/* no need for playback dev wakeup */
+				/* cec_msg.active_source = 1; */
+				memset(cec_otp_msg, 0, sizeof(cec_otp_msg));
+				cec_otp_msg[0] = cec_msg.buf[cec_msg.rx_read_pos].msg_len;
+				memcpy(&cec_otp_msg[1], cec_msg.buf[cec_msg.rx_read_pos].msg, cec_otp_msg[0]);
+				cec_set_wk_msg(cec_otp_msg, cec_as_msg);
+				printf("%s power on\n", __func__);
+			}
+		}
+	}
+}
+
+static int cec_routing_change(void)
+{
+	unsigned char phy_addr_ab = (cec_mailbox.phy_addr >> 8) & 0xff;
+	unsigned char phy_addr_cd = cec_mailbox.phy_addr & 0xff;
+
+	if ((hdmi_cec_func_config >> CEC_FUNC_MASK) & 0x1) {
+		if ((hdmi_cec_func_config >> AUTO_POWER_ON_MASK) & 0x1) {
+			/* wake up if routing destination is self */
+			if ((phy_addr_ab == cec_msg.buf[cec_msg.rx_read_pos].msg[4]) &&
+			    (phy_addr_cd == cec_msg.buf[cec_msg.rx_read_pos].msg[5])) {
+				cec_msg.cec_power = 0x1;
+				/* no need for playback dev wakeup */
+				/* cec_msg.active_source = 1; */
+				memset(cec_otp_msg, 0, sizeof(cec_otp_msg));
+				cec_otp_msg[0] = cec_msg.buf[cec_msg.rx_read_pos].msg_len;
+				memcpy(&cec_otp_msg[1], cec_msg.buf[cec_msg.rx_read_pos].msg, cec_otp_msg[0]);
+				cec_set_wk_msg(cec_otp_msg, cec_as_msg);
+				printf("%s power on\n", __func__);
+			}
+		}
+	}
+	return cec_msg.cec_power;
+}
+
+static void cec_device_vendor_id(unsigned char source)
+{
+	unsigned char msg[5];
+	unsigned int vendor_id = cec_mailbox.vendor_id;
+
+	msg[0] = ((source & 0xf) << 4) | CEC_BROADCAST_ADDR;
+	msg[1] = CEC_OC_DEVICE_VENDOR_ID;
+	msg[2] = (vendor_id >> 16) & 0xff;
+	msg[3] = (vendor_id >> 8) & 0xff;
+	msg[4] = (vendor_id >> 0) & 0xff;
+
+	remote_cec_ll_tx(msg, 5);
+}
+
+static void cec_menu_status_smp(int menu_status, unsigned char source, unsigned char dst)
+{
+	unsigned char msg[3];
+
+	msg[0] = ((source & 0xf) << 4) | (dst & 0xf);
+	msg[1] = CEC_OC_MENU_STATUS;
+	msg[2] = menu_status;
+
+	remote_cec_ll_tx(msg, 3);
+}
+
+static void cec_give_deck_status(unsigned char source, unsigned char dst)
+{
+	unsigned char msg[3];
+
+	msg[0] = ((source & 0xf) << 4) | (dst & 0xf);
+	msg[1] = CEC_OC_DECK_STATUS;
+	msg[2] = 0x1a;
+
+	remote_cec_ll_tx(msg, 3);
+}
+
+/*static void cec_standby(void)
+{
+	unsigned char msg[2];
+
+	msg[0] = ((cec_msg.log_addr & 0xf) << 4) | CEC_BROADCAST_ADDR;
+	msg[1] = CEC_OC_STANDBY;
+
+	remote_cec_ll_tx(msg, 2);
+}*/
+
+static void cec_set_osd_name(unsigned char source, unsigned char dst)
+{
+	unsigned char msg[16];
+	unsigned char osd_len = cec_mailbox.osd_name[15];
+
+	msg[0] = ((source & 0xf) << 4) | (dst & 0xf);
+	msg[1] = CEC_OC_SET_OSD_NAME;
+	if (osd_len > 0 && osd_len <= 14) {
+		cec_memcpy(&msg[2], cec_mailbox.osd_name, osd_len);
+	} else {
+		osd_len = cec_strlen(CONFIG_CEC_OSD_NAME);
+		cec_memcpy(&msg[2], CONFIG_CEC_OSD_NAME, osd_len);
+	}
+
+	remote_cec_ll_tx(msg, osd_len + 2);
+}
+
+static void cec_get_version(unsigned char source, unsigned char dst)
+{
+	unsigned char dest_log_addr = cec_msg.log_addr & 0xf;
+	unsigned char msg[3];
+
+	if (0xf != dest_log_addr) {
+		msg[0] = ((source & 0xf) << 4) | (dst & 0xf);
+		msg[1] = CEC_OC_CEC_VERSION;
+		msg[2] = CEC_VERSION_14A;
+		remote_cec_ll_tx(msg, 3);
+	}
+}
+
+static int check_addr(int phy_addr)
+{
+	unsigned int local_addr = (cec_mailbox.phy_addr) & 0xffff;
+	unsigned int i, mask = 0xf000, a, b;
+
+	for (i = 0; i < 4; i++) {
+		if (!(local_addr & mask)) {
+			break;
+		}
+		a = local_addr & mask;
+		b = phy_addr & mask;
+		if (a != b)	{// node is not same
+			printf("addr fail 1\n");
+			return 0;
+		}
+		mask >>= 4;
+	}
+	printf("addr ok\n");
+	return 1;
+}
+
+//static int is_playback_dev(int addr)
+//{
+//	if (addr != CEC_PLAYBACK_DEVICE_1_ADDR &&
+//	    addr != CEC_PLAYBACK_DEVICE_2_ADDR &&
+//	    addr != CEC_PLAYBACK_DEVICE_3_ADDR) {
+//		return 0;
+//	}
+//	return 1;
+//}
+
+static int is_tv_dev(int addr)
+{
+	if ((addr & 0xf) == CEC_TV_ADDR)
+		return 1;
+
+	return 0;
+}
+
+static int is_audio_system_dev(int addr)
+{
+	if ((addr & 0xf) == CEC_AUDIO_SYSTEM_ADDR)
+		return 1;
+
+	return 0;
+}
+
+#if 0
+static int is_phy_addr_ready(cec_msg_t *msg)
+{
+	if (msg == NULL)
+		return 0;
+	if (((hdmi_cec_func_config >> CEC_FUNC_MASK) & 0x1) &&
+	    ((hdmi_cec_func_config >> AUTO_POWER_ON_MASK) & 0x1) &&
+	    msg->cec_power) {
+		if (cec_wakup.wk_phy_addr &&
+		    cec_wakup.wk_logic_addr &&
+			(cec_wakup.wk_phy_addr != 0xFFFF)) {
+				printf("is_phy_addr_ready 0x%x\n",
+				       cec_wakup.wk_phy_addr);
+				return 1;
+		}
+	}
+
+	return 0;
+}
+#endif
+
+/* kernel will recovery the port info from msg. only for backup */
+static u32 cec_save_port_id(void)
+{
+	unsigned int phy_addr;
+	int i, port_id;
+	u32 data;
+
+	phy_addr = cec_wakup.wk_phy_addr;
+	printf("save port id\n");
+	if ((phy_addr == 0xFFFF) || ((phy_addr & 0xF000) == 0)) {
+		cec_wakup.wk_port_id = 0xFF;
+		data = cec_wakup.wk_logic_addr | (cec_wakup.wk_phy_addr << 8) |
+			(cec_wakup.wk_port_id << 24);
+		set_cec_wakeup_port_info(data);
+		return 0;
+	}
+
+	for (i = 0; i < PHY_ADDR_LEN; i++) {
+		port_id = (phy_addr >> (PHY_ADDR_LEN - i - 1)*4) & 0xF;
+		if (port_id == 0) {
+			 port_id = (phy_addr >> (PHY_ADDR_LEN - i)*4) & 0xF;
+			 break;
+		}
+	}
+	cec_wakup.wk_port_id = port_id;
+	data = cec_wakup.wk_logic_addr | (cec_wakup.wk_phy_addr << 8) |
+		(cec_wakup.wk_port_id << 24);
+	set_cec_wakeup_port_info(data);
+	return 0;
+}
+
+static u32 cec_handle_message(void)
+{
+	unsigned char opcode;
+	unsigned char source;
+	unsigned char dest;
+	unsigned int  phy_addr;
+	u32 data;
+
+	source = (cec_msg.buf[cec_msg.rx_read_pos].msg[0] >> 4) & 0xf;
+	dest = cec_msg.buf[cec_msg.rx_read_pos].msg[0] & 0xf;
+	if ((hdmi_cec_func_config & CEC_CFG_FUNC_EN) &&
+		(cec_msg.buf[cec_msg.rx_read_pos].msg_len > 1)) {
+		opcode = cec_msg.buf[cec_msg.rx_read_pos].msg[1];
+#if CEC_FW_DEBUG
+		printf("handle:0x%02x\n", opcode);
+#endif
+		switch (opcode) {
+		case CEC_OC_GET_CEC_VERSION:
+			cec_get_version(dest, source);
+			break;
+		case CEC_OC_GIVE_DECK_STATUS:
+			cec_give_deck_status(dest, source);
+			break;
+		case CEC_OC_GIVE_PHYSICAL_ADDRESS:
+			cec_report_physical_address(dest);
+			break;
+		case CEC_OC_GIVE_DEVICE_VENDOR_ID:
+			cec_device_vendor_id(dest);
+			break;
+		case CEC_OC_GIVE_OSD_NAME:
+			cec_set_osd_name(dest, source);
+			break;
+		case CEC_OC_SET_STREAM_PATH:
+			cec_set_stream_path();
+			break;
+		case CEC_OC_ROUTING_CHANGE:
+			cec_routing_change();
+			break;
+		case CEC_OC_GIVE_DEVICE_POWER_STATUS:
+			cec_report_device_power_status(dest, source);
+			break;
+		case CEC_OC_USER_CONTROL_PRESSED:
+			if (((hdmi_cec_func_config >> CEC_FUNC_MASK) & 0x1) &&
+			    ((hdmi_cec_func_config >> AUTO_POWER_ON_MASK) & 0x1) &&
+			     (cec_msg.buf[cec_msg.rx_read_pos].msg_len == 3) &&
+			    ((0x40 == cec_msg.buf[cec_msg.rx_read_pos].msg[2]) ||
+			     (0x6d == cec_msg.buf[cec_msg.rx_read_pos].msg[2]) ||
+			     (0x09 == cec_msg.buf[cec_msg.rx_read_pos].msg[2]) )) {
+				cec_msg.cec_power = 0x1;
+				memset(cec_otp_msg, 0, sizeof(cec_otp_msg));
+				cec_otp_msg[0] = cec_msg.buf[cec_msg.rx_read_pos].msg_len;
+				memcpy(&cec_otp_msg[1], cec_msg.buf[cec_msg.rx_read_pos].msg, cec_otp_msg[0]);
+				cec_set_wk_msg(cec_otp_msg, cec_as_msg);
+				printf("user power on\n");
+			}
+			break;
+		case CEC_OC_MENU_REQUEST:
+			cec_menu_status_smp(DEVICE_MENU_INACTIVE, dest, source);
+			break;
+
+		/* TV Wake up by image/text view on */
+		case CEC_OC_IMAGE_VIEW_ON:
+		case CEC_OC_TEXT_VIEW_ON:
+			if (((hdmi_cec_func_config >> CEC_FUNC_MASK) & 0x1) &&
+			    ((hdmi_cec_func_config >> AUTO_POWER_ON_MASK) & 0x1) &&
+			    (is_tv_dev(cec_msg.log_addr))) {
+				/* request active source needed */
+				phy_addr = 0xffff;
+				cec_msg.cec_power = 0x1;
+				cec_wakup.wk_logic_addr = source;
+				cec_wakup.wk_phy_addr = phy_addr;
+				data = cec_wakup.wk_logic_addr | (cec_wakup.wk_phy_addr << 8) |
+					(cec_wakup.wk_port_id << 24);
+				set_cec_wakeup_port_info(data);
+				memset(cec_otp_msg, 0, sizeof(cec_otp_msg));
+				cec_otp_msg[0] = cec_msg.buf[cec_msg.rx_read_pos].msg_len;
+				memcpy(&cec_otp_msg[1], cec_msg.buf[cec_msg.rx_read_pos].msg, cec_otp_msg[0]);
+				cec_set_wk_msg(cec_otp_msg, cec_as_msg);
+				printf("otp power on\n");
+			}
+			break;
+
+		/* TV Wake up by active source*/
+		case CEC_OC_ACTIVE_SOURCE:
+			phy_addr = (cec_msg.buf[cec_msg.rx_read_pos].msg[2] << 8) |
+				   (cec_msg.buf[cec_msg.rx_read_pos].msg[3] << 0);
+			if (((hdmi_cec_func_config >> CEC_FUNC_MASK) & 0x1) &&
+			    ((hdmi_cec_func_config >> AUTO_POWER_ON_MASK) & 0x1) &&
+			    (is_tv_dev(cec_msg.log_addr) && check_addr(phy_addr))) {
+				cec_msg.cec_power = 0x1;
+				cec_msg.active_source = 1;
+				cec_wakup.wk_logic_addr = source;
+				cec_wakup.wk_phy_addr = phy_addr;
+				data = cec_wakup.wk_logic_addr | (cec_wakup.wk_phy_addr << 8) |
+					(cec_wakup.wk_port_id << 24);
+				set_cec_wakeup_port_info(data);
+				memset(cec_as_msg, 0, sizeof(cec_as_msg));
+				cec_as_msg[0] = cec_msg.buf[cec_msg.rx_read_pos].msg_len;
+				memcpy(&cec_as_msg[1], cec_msg.buf[cec_msg.rx_read_pos].msg, cec_as_msg[0]);
+				cec_set_wk_msg(cec_otp_msg, cec_as_msg);
+				printf("active src power on:0x%x\n", data);
+			}
+			break;
+		case CEC_OC_SYSTEM_AUDIO_MODE_REQUEST:
+			/* soundbar will wakeup when receive this msg */
+			if (((hdmi_cec_func_config >> CEC_FUNC_MASK) & 0x1) &&
+			    ((hdmi_cec_func_config >> AUTO_POWER_ON_MASK) & 0x1) &&
+			    is_audio_system_dev(cec_msg.log_addr)) {
+				phy_addr = 0xffff;
+				cec_msg.cec_power = 0x1;
+				cec_wakup.wk_logic_addr = source;
+				cec_wakup.wk_phy_addr = phy_addr;
+				data = cec_wakup.wk_logic_addr | (cec_wakup.wk_phy_addr << 8) |
+					(cec_wakup.wk_port_id << 24);
+				set_cec_wakeup_port_info(data);
+				memset(cec_otp_msg, 0, sizeof(cec_otp_msg));
+				cec_otp_msg[0] = cec_msg.buf[cec_msg.rx_read_pos].msg_len;
+				if (cec_otp_msg[0] <= MAX_MSG)
+					memcpy(&cec_otp_msg[1],
+						cec_msg.buf[cec_msg.rx_read_pos].msg,
+						cec_otp_msg[0]);
+				cec_set_wk_msg(cec_otp_msg, cec_as_msg);
+				printf("system audio mode request wakeup\n");
+			}
+			break;
+		default:
+			break;
+		}
+	}
+	cec_rx_read_pos_plus();
+	return 0;
+}
+
+/* CEC A */
+static void ceca_addr_add(unsigned int l_add)
+{
+	unsigned int addr;
+
+	if (l_add > 15)
+		return ;
+
+	if (l_add < 8) {
+		addr = ceca_rd_reg(CECA_LOGICAL_ADDR0);
+		addr |= (1 << l_add);
+		ceca_wr_reg(CECA_LOGICAL_ADDR0, addr);
+	} else {
+		addr = ceca_rd_reg(CECA_LOGICAL_ADDR1);
+		addr |= (1 << (l_add - 8));
+		ceca_wr_reg(CECA_LOGICAL_ADDR1, addr);
+	}
+	printf("cec a add addr: 0x%x\n", l_add);
+}
+
+/* CEC B */
+static void cecb_addr_add(unsigned int l_add)
+{
+	unsigned int addr;
+
+	if (l_add > 15)
+		return ;
+
+	if (l_add < 8) {
+		addr = cecb_rd_reg(DWC_CECB_LADD_LOW);
+		addr |= (1 << l_add);
+		cecb_wr_reg(DWC_CECB_LADD_LOW, addr);
+	} else {
+		addr = cecb_rd_reg(DWC_CECB_LADD_HIGH);
+		addr |= (1 << (l_add - 8));
+		cecb_wr_reg(DWC_CECB_LADD_HIGH, addr);
+	}
+	printf("cec b add addr: 0x%x\n", l_add);
+}
+
+static void cec_addr_add(unsigned int l_add)
+{
+	if (cec_ip == CEC_B)
+		cecb_addr_add(l_add);
+	else
+		ceca_addr_add(l_add);
+}
+
+static void cec_set_log_addr(int addr)
+{
+	cec_addr_add(addr);
+	cec_msg.addr_enable |= (1 << addr);
+	cec_delay(100);
+}
+
+static void cec_clear_all_logical_addr(void)
+{
+	printf("clear all logical addr\n");
+
+	if (cec_ip == CEC_B) {
+		cecb_wr_reg(DWC_CECB_LADD_LOW, 0);
+		cecb_wr_reg(DWC_CECB_LADD_HIGH, 0);
+	} else {
+		ceca_wr_reg(CECA_LOGICAL_ADDR0, 0);
+		ceca_wr_reg(CECA_LOGICAL_ADDR1, 0);
+	}
+	/*udelay(100);*/
+}
+
+static void cec_restore_logical_addr(unsigned int addr_en)
+{
+	unsigned int i;
+	unsigned int addr_enable = addr_en;
+
+	cec_clear_all_logical_addr();
+	for (i = 0; i < 15; i++) {
+		if (addr_enable & 0x1)
+			cec_addr_add(i);
+
+		addr_enable = addr_enable >> 1;
+	}
+	cec_delay(100);
+	printf("cec restore_logical_addr: 0x%x\n", addr_en);
+}
+
+static void cec_reset_addr(void)
+{
+	cec_hw_reset();
+	cec_restore_logical_addr(cec_msg.addr_enable);
+}
+
+static unsigned int cec_get_log_addr(void)
+{
+	unsigned int reg;
+
+	if (cec_ip == CEC_B) {
+		reg = cecb_rd_reg(DWC_CECB_LADD_LOW);
+		reg = (cecb_rd_reg(DWC_CECB_LADD_HIGH) << 8) | reg;
+	} else {
+		reg = ceca_rd_reg(CECA_LOGICAL_ADDR0);
+		reg = (ceca_rd_reg(CECA_LOGICAL_ADDR1) << 8) | reg;
+	}
+
+	return reg & 0xffff;
+}
+
+#if (CEC_IP == CEC_B)
+static u32 cecb_irq_handler(void)
+{
+	unsigned char s_idx;
+	static int busy_count = 0;
+	int irq;
+
+	irq = read_ao(CECB_REG_INTR_STAT);
+	if (irq)
+		write_ao(CECB_REG_INTR_CLR, irq);
+	else
+		return 0;
+
+#if CEC_REG_DEBUG
+	if (irq) {
+		printf("irq sts:0x%x\n", irq);
+		dump_cec_reg();
+	}
+#endif
+	if (irq & CECB_IRQ_RX_EOM) {
+		remote_cec_ll_rx();
+		(cec_msg.rx_write_pos == cec_msg.rx_buf_size - 1) ? (cec_msg.rx_write_pos = 0) : (cec_msg.rx_write_pos++);
+#if CEC_REG_DEBUG
+		printf("RX_OK\n");
+#endif
+	}
+	if (irq & CECB_IRQ_RX_ERR_FOLLOWER) {
+		printf("RX_ERROR\n");
+		cecb_wr_reg(DWC_CECB_LOCK_BUF, 0);
+	}
+	if (irq & CECB_IRQ_RX_WAKEUP) {
+		printf("rx wake up\n");
+		cecb_wr_reg(DWC_CECB_WAKEUPCTRL, 0);
+		/* TODO: wake up system if needed */
+	}
+
+	if (irq & CECB_IRQ_TX_DONE) {
+		cec_tx_msgs.send_idx = (cec_tx_msgs.send_idx + 1) & CEC_TX_MSG_BUF_MASK;
+		s_idx = cec_tx_msgs.send_idx;
+		if (cec_tx_msgs.send_idx != cec_tx_msgs.queue_idx) {
+			printf("TX_OK\n");
+			cec_trigger_tx(cec_tx_msgs.msg[s_idx].buf,
+				       cec_tx_msgs.msg[s_idx].len);
+		} else {
+#if CEC_REG_DEBUG
+			printf("TX_END\n");
+#endif
+		}
+		busy_count = 0;
+	}
+
+	if (irq & CECB_IRQ_TX_NACK) {
+		printf("@TX_NACK\n");
+		s_idx = cec_tx_msgs.send_idx;
+		if (cec_tx_msgs.msg[s_idx].retry < 2) {
+			cec_tx_msgs.msg[s_idx].retry++;
+			cec_trigger_tx(cec_tx_msgs.msg[s_idx].buf,
+				       cec_tx_msgs.msg[s_idx].len);
+		} else {
+			/*printf("TX retry too much, abort msg\n");*/
+			cec_tx_msgs.send_idx = (cec_tx_msgs.send_idx + 1) & CEC_TX_MSG_BUF_MASK;
+		}
+		busy_count = 0;
+	}
+
+	if (irq & CECB_IRQ_TX_ERR_INITIATOR) {
+		printf("@TX_ERR_INIT\n");
+		s_idx = cec_tx_msgs.send_idx;
+		if (cec_tx_msgs.send_idx != cec_tx_msgs.queue_idx) { // trigger tx if idle
+			cec_trigger_tx(cec_tx_msgs.msg[s_idx].buf,
+				       cec_tx_msgs.msg[s_idx].len);
+		}
+		busy_count = 0;
+	}
+
+	if (irq & CECB_IRQ_TX_ARB_LOST) {
+	    busy_count++;
+		if (busy_count >= 2000) {
+			printf("busy too long, reset hw\n");
+			cec_reset_addr();
+			busy_count = 0;
+		}
+	}
+
+	if (cec_msg.rx_read_pos != cec_msg.rx_write_pos) {
+		cec_handle_message();
+	}
+
+	return 0;
+}
+#endif
+
+#if (CEC_IP != CEC_B)
+static u32 ceca_irq_handler(void)
+{
+	unsigned char s_idx;
+	static int busy_count = 0;
+	int irq;
+
+	irq = read_ao(CECA_REG_INTR_STAT);
+	if (irq)
+		write_ao(CECA_REG_INTR_CLR, irq);
+	else
+		return 0;
+#if CEC_REG_DEBUG
+	if (irq) {
+		printf("cec a irq sts:0x%x\n", irq);
+		//dump_cec_reg();
+	}
+#endif
+
+	if (0xf == ceca_rd_reg(CECA_RX_NUM_MSG)) {
+		ceca_wr_reg(CECA_RX_CLEAR_BUF, 0x1);
+		ceca_wr_reg(CECA_RX_CLEAR_BUF, 0x0);
+		ceca_wr_reg(CECA_RX_MSG_CMD,  RX_ACK_CURRENT);
+		ceca_wr_reg(CECA_RX_MSG_CMD, RX_NO_OP);
+		printf("error:hw_buf overflow\n");
+	}
+
+	switch (ceca_rd_reg(CECA_RX_MSG_STATUS)) {
+	case RX_DONE:
+		if (1 == ceca_rd_reg(CECA_RX_NUM_MSG)) {
+			remote_cec_ll_rx();
+			(cec_msg.rx_write_pos == cec_msg.rx_buf_size - 1) ? (cec_msg.rx_write_pos = 0) : (cec_msg.rx_write_pos++);
+		}
+		ceca_wr_reg(CECA_RX_MSG_CMD, RX_ACK_CURRENT);
+		ceca_wr_reg(CECA_RX_MSG_CMD, RX_NO_OP);
+		printf("RX_OK\n");
+		break;
+	case RX_ERROR:
+		printf("RX_ERROR\n");
+		if (TX_ERROR == ceca_rd_reg(CECA_TX_MSG_STATUS)) {
+			printf("TX_ERROR\n");
+			cec_reset_addr();
+		} else {
+			printf("TX_other\n");
+			ceca_wr_reg(CECA_RX_MSG_CMD,  RX_ACK_CURRENT);
+			ceca_wr_reg(CECA_RX_MSG_CMD, RX_NO_OP);
+		}
+		break;
+	default:
+		break;
+	}
+
+	switch (ceca_rd_reg(CECA_TX_MSG_STATUS)) {
+	case TX_DONE:
+		ceca_wr_reg(CECA_TX_MSG_CMD, TX_NO_OP);
+		cec_tx_msgs.send_idx = (cec_tx_msgs.send_idx + 1) & CEC_TX_MSG_BUF_MASK;
+		s_idx = cec_tx_msgs.send_idx;
+		if (cec_tx_msgs.send_idx != cec_tx_msgs.queue_idx) {
+			printf("TX_OK\n");
+			cec_trigger_tx(cec_tx_msgs.msg[s_idx].buf,
+				       cec_tx_msgs.msg[s_idx].len);
+		} else {
+			printf("TX_END\n");
+		}
+		busy_count = 0;
+		break;
+
+	case TX_ERROR:
+		printf("@TX_NACK\n");
+		if (RX_ERROR == ceca_rd_reg(CECA_RX_MSG_STATUS)) {
+			printf("@RX_ERROR\n");
+			cec_reset_addr();
+		} else {
+			ceca_wr_reg(CECA_TX_MSG_CMD, TX_NO_OP);
+			s_idx = cec_tx_msgs.send_idx;
+			if (cec_tx_msgs.msg[s_idx].retry < 3) {
+				cec_tx_msgs.msg[s_idx].retry++;
+				cec_trigger_tx(cec_tx_msgs.msg[s_idx].buf,
+					       cec_tx_msgs.msg[s_idx].len);
+			} else {
+				printf("TX retry too much, abort msg\n");
+				cec_tx_msgs.send_idx = (cec_tx_msgs.send_idx + 1) & CEC_TX_MSG_BUF_MASK;
+			}
+		}
+		busy_count = 0;
+		break;
+
+	 case TX_IDLE:
+		s_idx = cec_tx_msgs.send_idx;
+		if (cec_tx_msgs.send_idx != cec_tx_msgs.queue_idx) {
+			cec_trigger_tx(cec_tx_msgs.msg[s_idx].buf,
+				       cec_tx_msgs.msg[s_idx].len);
+		}
+		busy_count = 0;
+		break;
+
+	case TX_BUSY:
+		busy_count++;
+		if (busy_count >= 2000) {
+			printf("busy too long, reset hw\n");
+			cec_reset_addr();
+			busy_count = 0;
+		}
+		break;
+
+	 default:
+		break;
+	}
+
+	if (cec_msg.rx_read_pos != cec_msg.rx_write_pos) {
+		cec_handle_message();
+	}
+
+	return 0;
+}
+#endif
+
+static u32 cec_irq_handler(void)
+{
+	u32 ret;
+
+#if (CEC_IP == CEC_B)
+	ret = cecb_irq_handler();
+#else
+	ret = ceca_irq_handler();
+#endif
+
+	return ret;
+}
+
+/*static void check_standby(void)
+{
+	if (((cec_msg.log_addr & 0xf) == 0) &&
+	    ((hdmi_cec_func_config >> CEC_FUNC_MASK) & 0x1) &&
+	    ((hdmi_cec_func_config >> ONE_TOUCH_STANDBY_MASK) & 0x1)) {
+		cec_standby();
+	}
+}*/
+
+static unsigned int *probe = NULL;
+static unsigned int ping_state = 0;/*0:send statue, 1:check irq state*/
+static unsigned int idle_cnt = 0;
+
+static void cec_node_init(void)
+{
+	static unsigned int retry = 0;
+	/*static unsigned int regist_devs = 0;*/
+	static unsigned char idx = 0, sub_idx = 0;
+	unsigned int log_addr;
+	int tx_stat;
+	unsigned char msg[16];
+	/*unsigned int kern_log_addr = (REG32(SYSCTRL_STATUS_REG1) >> 16) & 0xf;*/
+	unsigned int kern_log_addr = (read_ao(CEC_REG_STS1) >> 16) & 0xf;
+	unsigned int kern_log_addr2 = 0;
+	unsigned int start_poll_log_addr = CEC_PLAYBACK_DEVICE_1_ADDR;
+	unsigned int player_dev[3][3] =
+		{{CEC_PLAYBACK_DEVICE_1_ADDR, CEC_PLAYBACK_DEVICE_2_ADDR, CEC_PLAYBACK_DEVICE_3_ADDR},
+		 {CEC_PLAYBACK_DEVICE_2_ADDR, CEC_PLAYBACK_DEVICE_3_ADDR, CEC_PLAYBACK_DEVICE_1_ADDR},
+		 {CEC_PLAYBACK_DEVICE_3_ADDR, CEC_PLAYBACK_DEVICE_1_ADDR, CEC_PLAYBACK_DEVICE_2_ADDR}};
+
+#if CEC_FW_DEBUG
+	printf("%s\n", __func__);
+#endif
+	if (kern_log_addr != 0)
+		kern_log_addr2 = (read_ao(CEC_REG_STS1) >> 24) & 0xf;
+	cec_wait_addr = 0;
+	cec_wakup_flag = 0;
+	if (retry >= 12) {  // retry all device addr
+		cec_msg.log_addr = 0x0f;
+		printf("failed on retried all possible address\n");
+		return ;
+	}
+	memset(&cec_wakup, 0, sizeof(cec_wakup));
+	if (probe == NULL) {
+		cec_msg.rx_read_pos = 0;
+		cec_msg.rx_write_pos = 0;
+		cec_msg.rx_buf_size = 2;
+
+		cec_msg.power_status = 1;
+		cec_msg.active_source = 0;
+		cec_msg.cec_power = 0;
+		cec_tx_msgs.send_idx = 0;
+		cec_tx_msgs.queue_idx = 0;
+		cec_msg.log_addr = 0;
+		cec_msg.addr_enable = 0;
+		cec_clear_all_logical_addr();
+		cec_tx_buf_init();
+		cec_buf_clear();
+		retry = 0;
+		/*regist_devs = 0;*/
+		idx = 0;
+		/*_udelay(100);*/
+		/*
+		 * use kernel cec logic address to detect which logic address is the
+		 * started one to allocate.
+		 */
+		printf("addr from kernel:0x%x, 0x%x\n", kern_log_addr, kern_log_addr2);
+		/* we don't need probe TV address nor audio system.
+		 * if audio system logic addr is configured in kernel,
+		 * then use CEC_AUDIO_SYSTEM_ADDR as default logic addr
+		 * witch is used to respond to directly addressed message
+		 * cec_report_physical_address()
+		 */
+		if (is_tv_dev(kern_log_addr)) {
+			cec_set_log_addr(kern_log_addr);
+			msg[0] = (kern_log_addr << 4) | kern_log_addr;
+			ping_cec_ll_tx(msg, 1);
+			cec_msg.log_addr = 0x10 | kern_log_addr;
+			/*_udelay(100);*/
+			printf("log_addr:0x%x ADDR0:0x%x\n",
+			       cec_msg.log_addr,
+			       cec_get_log_addr());
+			probe = NULL;
+			/*regist_devs = 0;*/
+			idx = 0;
+			retry = 0;
+			/*check_standby();*/
+			return ;
+		} else if (is_audio_system_dev(kern_log_addr)) {
+			msg[0] = (kern_log_addr << 4) | kern_log_addr;
+			ping_cec_ll_tx(msg, 1);
+			cec_delay(500);
+			tx_stat = cec_check_irq_sts();
+			/* set logic addr for audio system directly
+			 * mostly, there's only one avr in system,
+			 * just for simple check, ignore TX_BUSY
+			 */
+			if (tx_stat == TX_DONE) {
+				printf("TX_DONE somebody takes cec log_addr:0x%x\n",
+					kern_log_addr);
+			} else {
+				cec_set_log_addr(kern_log_addr);
+				printf("Set cec log_addr:0x%0x, ADDR0:0x%x\n",
+					kern_log_addr, cec_get_log_addr());
+			}
+			probe = NULL;
+			/* regist_devs = 0; */
+			idx = 0;
+			retry = 0;
+			/* continue polling addr for second playback logic
+			 * addr if it's configured in kernel, here
+			 * we assume the second logic addr is playback addr
+			 */
+			if (kern_log_addr2 != 0) {
+				start_poll_log_addr = kern_log_addr2;
+			} else {
+				/* only 1 logic addr for soundbar */
+				cec_msg.log_addr = kern_log_addr;
+				return;
+			}
+		} else if (is_audio_system_dev(kern_log_addr2)) {
+			msg[0] = (kern_log_addr2 << 4) | kern_log_addr2;
+			ping_cec_ll_tx(msg, 1);
+			cec_delay(500);
+			tx_stat = cec_check_irq_sts();
+			if (tx_stat == TX_DONE) {
+				printf("TX_DONE somebody takes cec log_addr:0x%x\n",
+					kern_log_addr2);
+			} else {
+				cec_set_log_addr(kern_log_addr2);
+				printf("Set cec log_addr:0x%0x, ADDR0:0x%x\n",
+					kern_log_addr2, cec_get_log_addr());
+			}
+			probe = NULL;
+			/* regist_devs = 0; */
+			idx = 0;
+			retry = 0;
+			/* continue polling addr for second logic
+			 *if it's configured in kernel
+			 */
+			if (kern_log_addr != 0) {
+				start_poll_log_addr = kern_log_addr;
+			} else {
+				/* only 1 logic addr for soundbar */
+				cec_msg.log_addr = kern_log_addr2;
+				return;
+			}
+		}
+
+		for (idx = 0; idx < 3; idx++) {
+			if (start_poll_log_addr == player_dev[idx][0]) {
+				sub_idx = 0;
+				probe = (unsigned int *)&player_dev[idx];
+				break;
+			}
+		}
+
+		if (probe == NULL) {
+			probe = player_dev[0];
+		} else {
+			/*printf("0x%x, 0x%x, 0x%x\n", probe[0], probe[1], probe[2]);*/
+		}
+		sub_idx = 0;
+		/*cec_hw_reset();*/
+		ping_state = 0;
+		idle_cnt = 0;
+		retry = 0;
+		return;
+	} else {
+		/* ping dev addr */
+		log_addr = player_dev[idx][sub_idx];
+		/* don't need to set logic addr before poll logic addr */
+		/* cec_set_log_addr(log_addr); */
+		msg[0] = (log_addr << 4 ) | log_addr;
+		/*printf("%s ping:idx:%d, 0x%x\n", __func__, sub_idx, msg[0]);*/
+		if (!ping_state) {
+			ping_cec_ll_tx(msg, 1);
+			cec_delay(500);
+			ping_state = 1;
+		} else {
+			tx_stat = cec_check_irq_sts();
+			if (tx_stat == TX_BUSY) {   // can't get cec bus
+				printf("TX_BUSY");
+				cec_hw_reset();
+				if (retry++ > 4) {
+					printf("TX_BUSY retry too much, log_addr:0x%x\n", probe[sub_idx]);
+					retry = 0;
+				}
+				ping_state = 0;
+				return;
+			} else if (tx_stat == TX_ERROR) {
+				cec_delay(100);
+				/* if there're 2 logic addr(soundbar):
+				 * use audio system addr as main logic addr
+				 */
+				if (is_audio_system_dev(kern_log_addr) ||
+					is_audio_system_dev(kern_log_addr2))
+					cec_msg.log_addr = CEC_AUDIO_SYSTEM_ADDR;
+				else
+					cec_msg.log_addr = log_addr;
+				cec_set_log_addr(log_addr);
+				printf("Set log_addr:0x%x,addr0:0x%x\n",
+				       log_addr, cec_get_log_addr());
+				probe = NULL;
+				/*regist_devs = 0;*/
+				idx = 0;
+				retry = 0;
+				ping_state = 0;
+				return ;
+			} else if (tx_stat == TX_DONE) {
+				printf("TX_DONE somebody takes cec log_addr:0x%x\n", player_dev[idx][sub_idx]);
+				#if 0
+				regist_devs |= (1 << dev_idx);
+				retry += (4 - (retry & 0x03));
+				if (regist_devs == 0x07) {
+					// No avilable logical address
+					cec_msg.log_addr = 0x0f;
+					cec_set_log_addr(15);
+					printf("CEC allocate logic address failed\n");
+				}
+				#endif
+				ping_state = 0;
+			} else {
+				/*idle*/
+				if (idle_cnt++ > 5) {
+					ping_state = 0;/*to tx state*/
+				} else {
+					return;
+				}
+			}
+
+			/*need ping next address*/
+			sub_idx++;
+			if (sub_idx == 3) {
+				sub_idx = 0;
+				/* no match addr*/
+				cec_msg.log_addr = 0x0f;
+				cec_set_log_addr(cec_msg.log_addr);
+				printf("CEC allocate logic address failed\n");
+			}
+		}
+	}
+}
+
+static u32 cec_suspend_wakeup_chk(void)
+{
+	u32 timeout_flag = 0;
+
+	if ((cec_msg.cec_power == 0x1) &&
+		(hdmi_cec_func_config & CEC_CFG_FUNC_EN)) {
+		if (cec_wait_addr++ < 80) {
+			if (cec_msg.active_source) {
+				cec_save_port_id();
+				timeout_flag = 1;
+				printf("active src cmd in, wakeup\n");
+			}
+			printf(".");
+		} else {
+			timeout_flag = 1;
+		}
+	}
+
+	if (timeout_flag) {
+		cec_wakup_flag = 1;
+		printf("wakeup\n");
+		/*set_cec_val0(CEC_WAKEUP);*/
+		return 1;
+	} else {
+		return 0;
+	}
+}
+
+u32 cec_suspend_handle(void)
+{
+	u32 active_src_flag = 0;
+
+	/*cec_sts_check();*/
+	cec_suspend_wakeup_chk();
+	if (cec_msg.log_addr) {
+		if (hdmi_cec_func_config & CEC_CFG_FUNC_EN) {
+			cec_irq_handler();
+			if (cec_msg.cec_power == 0x1) {
+				if (cec_msg.active_source) {
+					cec_save_port_id();
+					/*cec power key*/
+					active_src_flag = 1;
+					printf("message wakeup\n");
+				}
+			}
+		}
+	} else if (hdmi_cec_func_config & CEC_CFG_FUNC_EN) {
+		cec_node_init();
+	}
+
+	if (active_src_flag) {
+		printf("active source:0x%x\n", cec_msg.active_source);
+		printf("wk_logic_addr:0x%x\n", cec_wakup.wk_logic_addr);
+		printf("wk_phy_addr:0x%x\n", cec_wakup.wk_phy_addr);
+		printf("wk_port_id:0x%x\n", cec_wakup.wk_port_id);
+		return 1;
+	} else
+		return 0;
+}
+
+u32 cec_init_config(void)
+{
+#if CEC_CFG_DEBUG
+	write_ao(CEC_REG_STS0, 0x8000002f);
+	//write_ao(CEC_REG_STS1, 0x000000);
+	write_ao(CEC_REG_STS1, 0x441000);
+	cec_mailbox.cec_config |= CEC_CFG_DBG_EN;
+#endif
+
+	hdmi_cec_func_config = read_ao(CEC_REG_STS0);
+	/*cec_mailbox.cec_config = hdmi_cec_func_config;*/
+	cec_mailbox.phy_addr = read_ao(CEC_REG_STS1);
+	cec_ip = CEC_IP;
+	printf("cec_ip %d\n", cec_ip);
+	if (cec_mailbox.cec_config & CEC_CFG_DBG_EN) {
+		printf("%s\n", CEC_VERSION);
+		printf("cec cfg1:0x%x\n", hdmi_cec_func_config);
+		printf("cec cfg2:0x%x\n", read_ao(CEC_REG_STS1));
+	}
+
+	if (hdmi_cec_func_config & CEC_CFG_FUNC_EN) {
+		probe = NULL;
+		ping_state = 0;
+		idle_cnt = 0;
+		cec_msg.log_addr = 0;
+		cec_hw_reset();
+		/*cec_node_init();*/
+	} else {
+		cec_enable_irq(0);
+	}
+
+#if CEC_REG_DEBUG
+	dump_cec_reg();
+#endif
+	/*cec enable*/
+	if (hdmi_cec_func_config & CEC_CFG_FUNC_EN) {
+		return 1;
+	} else
+		return 0;
+}
+
+u32 cec_get_wakup_flag(void)
+{
+	return cec_wakup_flag;
+}
+
+static void *cec_get_wakeup_otp_msg(void *msg)
+{
+	if (msg)
+		memcpy(msg, (void *)cec_otp_msg, sizeof(cec_otp_msg));
+	return NULL;
+}
+
+static void *cec_get_wakeup_as_msg(void *msg)
+{
+	if (msg)
+		memcpy(msg, (void *)cec_as_msg, sizeof(cec_as_msg));
+	return NULL;
+}
+
+/* wakeup message from source
+ * <Image View On> 0x04 len = 2
+ * <Text View On> 0x0D len = 2
+ * <Active Source> 0x82 len = 4
+ *
+ * wakeup message from TV
+ * <Set Stream Path> 0x86 len = 4
+ * <Routing Change> 0x80 len = 6
+ * <remote key> 0x40 0x6d 0x09 len = 3
+ * if <Routing Change> is received
+ * then ignore other otp/as msg
+ */
+static void cec_set_wk_msg(unsigned char *otp_msg, unsigned char *as_msg)
+{
+	unsigned int tmp_otp_msg = 0;
+	unsigned int tmp_as_msg = 0;
+
+	if (!otp_msg || !as_msg)
+		return;
+
+	if (otp_msg[0] > 8) {
+		printf("wrong otp msg len: %d\n", otp_msg[0]);
+		if (as_msg[0] == 4) {
+			tmp_as_msg = as_msg[1] << 24 |
+				as_msg[2] << 16 |
+				as_msg[3] << 8 |
+				as_msg[4];
+			write_ao(CEC_REG_STICK_DATA2, tmp_as_msg);
+		}
+	} else if (otp_msg[0] > 4) {
+		/* otp msg store in two stick regs */
+		tmp_otp_msg = otp_msg[1] << 24 |
+			otp_msg[2] << 16 |
+			otp_msg[3] << 8 |
+			otp_msg[4];
+		write_ao(CEC_REG_STICK_DATA1, tmp_otp_msg);
+		tmp_otp_msg = 0;
+		tmp_otp_msg = otp_msg[5] << 24 |
+			otp_msg[6] << 16 |
+			otp_msg[7] << 8 |
+			otp_msg[8];
+		write_ao(CEC_REG_STICK_DATA2, tmp_otp_msg);
+	} else if (otp_msg[0] > 0) {
+		/* otp msg store in one stick reg */
+		tmp_otp_msg = otp_msg[1] << 24 |
+			otp_msg[2] << 16 |
+			otp_msg[3] << 8 |
+			otp_msg[4];
+		write_ao(CEC_REG_STICK_DATA1, tmp_otp_msg);
+		if (as_msg[0] == 4) {
+			tmp_as_msg = as_msg[1] << 24 |
+				as_msg[2] << 16 |
+				as_msg[3] << 8 |
+				as_msg[4];
+			write_ao(CEC_REG_STICK_DATA2, tmp_as_msg);
+		}
+	}
+}
+
+
+void vCEC_task(void __unused *pvParameters)
+{
+	u32 ret;
+	u32 buf[4] = {0};
+
+	memset(cec_otp_msg, 0, sizeof(cec_otp_msg));
+	memset(cec_as_msg, 0, sizeof(cec_as_msg));
+	if (CEC_ON == 0) {
+		printf("cec define disabled\n");
+		goto idle;
+	}
+
+	buf[0] = CEC_WAKEUP;
+	/* pvParameters = pvParameters; */
+	ret = cec_init_config();
+	if (!ret) {
+		printf("cec not enable\n");
+		goto idle;
+	}
+	cec_delay(100);
+	while (1) {
+		//printf("%s 01\n", __func__);
+		vTaskDelay(pdMS_TO_TICKS(20));
+		cec_suspend_handle();
+		if (cec_get_wakup_flag()) {
+			printf("%s wakeup\n", __func__);
+			STR_Wakeup_src_Queue_Send(buf);
+			break;
+		}
+	}
+
+idle:
+	for ( ;; ) {
+		vTaskDelay(pdMS_TO_TICKS(2000));
+		//printf("%s idle\n", __func__);
+	}
+}
+
+#if (CEC_TASK_DEBUG)
+static TaskHandle_t cecTask_temp = NULL;
+#endif
+void vCecCallbackInit(enum cec_chip_ver chip_mode)
+{
+	int ret;
+
+	if (CEC_ON == 0) {
+		return;
+	}
+
+	/*initial bl30 start call*/
+	cec_mailbox.cec_config = CEC_CFG_FUNC_EN | CEC_CFG_OTP_EN | CEC_CFG_PW_ON_EN;
+	cec_mailbox.phy_addr = 0x1000;
+
+	cec_mailbox.osd_name[0] = 'a';
+	cec_mailbox.osd_name[1] = 'm';
+	cec_mailbox.osd_name[2] = 'l';
+	cec_mailbox.osd_name[14] = 3;
+
+	cec_chip = chip_mode;
+	/* for shutdown/resume case */
+	ret = xInstallRemoteMessageCallbackFeedBack(AOREE_CHANNEL, MBX_CMD_GET_CEC_INFO1,
+						    cec_get_wakeup_info1, 1);
+	if (ret == MBOX_CALL_MAX)
+		printf("mbox cmd 0x%x register fail\n", MBX_CMD_GET_CEC_INFO1);
+
+	ret = xInstallRemoteMessageCallbackFeedBack(AOREE_CHANNEL, MBX_CMD_GET_CEC_INFO2,
+						    cec_get_wakeup_info2, 1);
+	if (ret == MBOX_CALL_MAX)
+		printf("mbox cmd 0x%x register fail\n", MBX_CMD_GET_CEC_INFO2);
+
+	ret = xInstallRemoteMessageCallbackFeedBack(AOREE_CHANNEL, MBX_CMD_SET_CEC_DATA,
+						    cec_update_config_data, 1);
+	if (ret == MBOX_CALL_MAX)
+		printf("mbox cmd 0x%x register fail\n", MBX_CMD_SET_CEC_DATA);
+
+	/* only for suspend/resume case, for shutdown/resume
+	 * case, need sticky registers to store wakeup info.
+	 * as box have no CEC sticky registers, now wakeup
+	 * msg can only be transfered under suspend/resume.
+	 */
+	ret = xInstallRemoteMessageCallbackFeedBack(AOREE_CHANNEL, MBX_CMD_GET_WAKEUP_OTP_MSG,
+						    cec_get_wakeup_otp_msg, 1);
+	if (ret == MBOX_CALL_MAX)
+		printf("mbox cmd 0x%x register fail\n", MBX_CMD_GET_WAKEUP_OTP_MSG);
+
+	ret = xInstallRemoteMessageCallbackFeedBack(AOREE_CHANNEL, MBX_CMD_CLR_WAKEUP_AS_MSG,
+						    cec_get_wakeup_as_msg, 1);
+	if (ret == MBOX_CALL_MAX)
+		printf("mbox cmd 0x%x register fail\n", MBX_CMD_CLR_WAKEUP_AS_MSG);
+
+	/* only for temp debug, only for no resume function */
+#if (CEC_TASK_DEBUG)
+	xTaskCreate(vCEC_task, "CECtask", configMINIMAL_STACK_SIZE,
+		    NULL, CEC_TASK_PRI, &cecTask_temp);
+#endif
+}
+
+void cec_req_irq(u32 __unused onoff)
+{
+	/* onoff = onoff; */
+}
+
+#endif
+
diff --git a/bl30/src_ao/demos/amlogic/driver/cec/hdmi_cec_reg.h b/bl30/src_ao/demos/amlogic/driver/cec/hdmi_cec_reg.h
new file mode 100644
index 0000000..a6723e7
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/cec/hdmi_cec_reg.h
@@ -0,0 +1,358 @@
+
+/*
+ * arch/arm/cpu/armv8/txl/firmware/scp_task/cec_tx_reg.h
+ *
+ * Copyright (C) 2015 Amlogic, Inc. All rights reserved.
+*/
+
+#ifndef _CEC_TX_REG_H
+#define _CEC_TX_REG_H
+
+#ifndef CONFIG_CEC_OSD_NAME
+#define CONFIG_CEC_OSD_NAME "AML_TV"
+#endif
+
+/*#define CEC_VERSION "freeRTOS cec:2020/0923"*/
+
+enum cec_reg_idx {
+	CECA_REG_CLK_CNTL_REG0 = 0,
+	CECA_REG_CLK_CNTL_REG1,	/*1*/
+	CECA_REG_GEN_CNTL,	/*2*/
+	CECA_REG_RW_REG,
+	CECA_REG_INTR_MASKN,
+	CECA_REG_INTR_CLR,
+	CECA_REG_INTR_STAT,
+
+	CECB_REG_CLK_CNTL_REG0,	/*7*/
+	CECB_REG_CLK_CNTL_REG1,	/*8*/
+	CECB_REG_GEN_CNTL,	/*9*/
+	CECB_REG_RW_REG, 	/*0xa*/
+	CECB_REG_INTR_MASKN,	/*0xb*/
+	CECB_REG_INTR_CLR,	/*0xc*/
+	CECB_REG_INTR_STAT,	/*0xd*/
+
+	CEC_REG_STS0,
+	CEC_REG_STS1,
+
+	CEC_REG_STICK_DATA0,	/*config*/
+	CEC_REG_STICK_DATA1,	/*port info*/
+	CEC_REG_STICK_DATA2,
+	CEC_REG_STICK_DATA3,
+	CEC_REG_STICK_DATA4,
+	CEC_REG_STICK_DATA5,
+	CEC_REG_STICK_DATA6,
+	CEC_REG_STICK_DATA7,
+
+	CEC_REG_DEF_END
+};
+
+#define REG_MASK_ADDR	0x00ffffff
+//#define REG_MASK_PR	0x01000000/*periphs register*/
+
+/* FOR AO_CECB */
+#define DWC_CECB_CTRL                0x00
+#define DWC_CECB_CTRL2               0x01/*tl1 later*/
+#define DWC_CECB_INTR_MASK           0x02
+#define DWC_CECB_LADD_LOW            0x05
+#define DWC_CECB_LADD_HIGH           0x06
+#define DWC_CECB_TX_CNT              0x07
+#define DWC_CECB_RX_CNT              0x08
+#define DWC_CECB_STAT0               0x09/*tl1 later*/
+#define DWC_CECB_TX_DATA00           0x10
+#define DWC_CECB_TX_DATA01           0x11
+#define DWC_CECB_TX_DATA02           0x12
+#define DWC_CECB_TX_DATA03           0x13
+#define DWC_CECB_TX_DATA04           0x14
+#define DWC_CECB_TX_DATA05           0x15
+#define DWC_CECB_TX_DATA06           0x16
+#define DWC_CECB_TX_DATA07           0x17
+#define DWC_CECB_TX_DATA08           0x18
+#define DWC_CECB_TX_DATA09           0x19
+#define DWC_CECB_TX_DATA10           0x1A
+#define DWC_CECB_TX_DATA11           0x1B
+#define DWC_CECB_TX_DATA12           0x1C
+#define DWC_CECB_TX_DATA13           0x1D
+#define DWC_CECB_TX_DATA14           0x1E
+#define DWC_CECB_TX_DATA15           0x1F
+#define DWC_CECB_RX_DATA00           0x20
+#define DWC_CECB_RX_DATA01           0x21
+#define DWC_CECB_RX_DATA02           0x22
+#define DWC_CECB_RX_DATA03           0x23
+#define DWC_CECB_RX_DATA04           0x24
+#define DWC_CECB_RX_DATA05           0x25
+#define DWC_CECB_RX_DATA06           0x26
+#define DWC_CECB_RX_DATA07           0x27
+#define DWC_CECB_RX_DATA08           0x28
+#define DWC_CECB_RX_DATA09           0x29
+#define DWC_CECB_RX_DATA10           0x2A
+#define DWC_CECB_RX_DATA11           0x2B
+#define DWC_CECB_RX_DATA12           0x2C
+#define DWC_CECB_RX_DATA13           0x2D
+#define DWC_CECB_RX_DATA14           0x2E
+#define DWC_CECB_RX_DATA15           0x2F
+#define DWC_CECB_LOCK_BUF            0x30
+#define DWC_CECB_WAKEUPCTRL          0x31
+
+/* cec irq bit flags for AO_CEC_B */
+#define CECB_IRQ_TX_DONE		(1 << 0)
+#define CECB_IRQ_RX_EOM			(1 << 1)
+#define CECB_IRQ_TX_NACK		(1 << 2)
+#define CECB_IRQ_TX_ARB_LOST		(1 << 3)
+#define CECB_IRQ_TX_ERR_INITIATOR	(1 << 4)
+#define CECB_IRQ_RX_ERR_FOLLOWER	(1 << 5)
+#define CECB_IRQ_RX_WAKEUP		(1 << 6)
+#define CECB_IRQ_EN_MASK		(0x3f << 0)
+
+// tx_msg_status definition
+#define TX_IDLE                 0  // No transaction
+#define TX_BUSY                 1  // Transmitter is busy
+#define TX_DONE                 2  // Message has been successfully transmitted
+#define TX_ERROR                3  // Message has been transmitted with error
+
+/*
+ * AOCEC_A internal register
+ * read/write tx register list
+ */
+#define CECA_TX_MSG_0_HEADER        0x00
+#define CECA_TX_MSG_1_OPCODE        0x01
+#define CECA_TX_MSG_2_OP1           0x02
+#define CECA_TX_MSG_3_OP2           0x03
+#define CECA_TX_MSG_4_OP3           0x04
+#define CECA_TX_MSG_5_OP4           0x05
+#define CECA_TX_MSG_6_OP5           0x06
+#define CECA_TX_MSG_7_OP6           0x07
+#define CECA_TX_MSG_8_OP7           0x08
+#define CECA_TX_MSG_9_OP8           0x09
+#define CECA_TX_MSG_A_OP9           0x0A
+#define CECA_TX_MSG_B_OP10          0x0B
+#define CECA_TX_MSG_C_OP11          0x0C
+#define CECA_TX_MSG_D_OP12          0x0D
+#define CECA_TX_MSG_E_OP13          0x0E
+#define CECA_TX_MSG_F_OP14          0x0F
+#define CECA_TX_MSG_LENGTH          0x10
+#define CECA_TX_MSG_CMD             0x11
+#define CECA_TX_WRITE_BUF           0x12
+#define CECA_TX_CLEAR_BUF           0x13
+#define CECA_RX_MSG_CMD             0x14
+#define CECA_RX_CLEAR_BUF           0x15
+#define CECA_LOGICAL_ADDR0          0x16
+#define CECA_LOGICAL_ADDR1          0x17/*ADDR L tm2 later*/
+#define CECA_LOGICAL_ADDR2          0x18/*ADDR H tm2 later*/
+#define CECA_LOGICAL_ADDR3          0x19
+#define CECA_LOGICAL_ADDR4          0x1A
+#define CECA_CLOCK_DIV_H            0x1B
+#define CECA_CLOCK_DIV_L            0x1C
+
+/*
+ * AOCEC_A internal register
+ * read only register list
+ */
+#define CECA_RX_MSG_0_HEADER        0x80
+#define CECA_RX_MSG_1_OPCODE        0x81
+#define CECA_RX_MSG_2_OP1           0x82
+#define CECA_RX_MSG_3_OP2           0x83
+#define CECA_RX_MSG_4_OP3           0x84
+#define CECA_RX_MSG_5_OP4           0x85
+#define CECA_RX_MSG_6_OP5           0x86
+#define CECA_RX_MSG_7_OP6           0x87
+#define CECA_RX_MSG_8_OP7           0x88
+#define CECA_RX_MSG_9_OP8           0x89
+#define CECA_RX_MSG_A_OP9           0x8A
+#define CECA_RX_MSG_B_OP10          0x8B
+#define CECA_RX_MSG_C_OP11          0x8C
+#define CECA_RX_MSG_D_OP12          0x8D
+#define CECA_RX_MSG_E_OP13          0x8E
+#define CECA_RX_MSG_F_OP14          0x8F
+#define CECA_RX_MSG_LENGTH          0x90
+#define CECA_RX_MSG_STATUS          0x91
+#define CECA_RX_NUM_MSG             0x92
+#define CECA_TX_MSG_STATUS          0x93
+#define CECA_TX_NUM_MSG             0x94
+/*
+ * AOCEC_A internal register
+ * read only (tl1 later)
+ */
+#define CECA_STAT_0_0				0xA0
+#define CECA_STAT_0_1				0xA1
+#define CECA_STAT_0_2				0xA2
+#define CECA_STAT_0_3				0xA3
+#define CECA_STAT_1_0				0xA4
+#define CECA_STAT_1_1				0xA5
+#define CECA_STAT_1_2				0xA6
+
+
+// tx_msg_cmd definition
+#define TX_NO_OP                0  // No transaction
+#define TX_REQ_CURRENT          1  // Transmit earliest message in buffer
+#define TX_ABORT                2  // Abort transmitting earliest message
+#define TX_REQ_NEXT             3  // Overwrite earliest message in buffer and transmit next message
+
+// tx_msg_status definition
+#define TX_IDLE                 0  // No transaction
+#define TX_BUSY                 1  // Transmitter is busy
+#define TX_DONE                 2  // Message has been successfully transmitted
+#define TX_ERROR                3  // Message has been transmitted with error
+
+// rx_msg_cmd
+#define RX_NO_OP                0  // No transaction
+#define RX_ACK_CURRENT          1  // Read earliest message in buffer
+#define RX_DISABLE              2  // Disable receiving latest message
+#define RX_ACK_NEXT             3  // Clear earliest message from buffer and read next message
+
+// rx_msg_status
+#define RX_IDLE                 0  // No transaction
+#define RX_BUSY                 1  // Receiver is busy
+#define RX_DONE                 2  // Message has been received successfully
+#define RX_ERROR                3  // Message has been received with error
+
+#define CECA_HOST_INT	0x1
+#define CECA_TX_INT	0x2
+#define CECA_RX_INT	0x4
+
+/* wakeup mask */
+#define WAKEUP_OP_86_EN			BIT(7)
+#define WAKEUP_OP_82_EN			BIT(6)
+#define WAKEUP_OP_70_EN			BIT(5)
+#define WAKEUP_OP_44_EN			BIT(4)
+#define WAKEUP_OP_42_EN			BIT(3)
+#define WAKEUP_OP_41_EN			BIT(2)
+#define WAKEUP_OP_0D_EN			BIT(1)
+#define WAKEUP_OP_04_EN			BIT(0)
+#define WAKEUP_DIS_MASK			0
+#define WAKEUP_EN_MASK		(WAKEUP_OP_86_EN | \
+							WAKEUP_OP_0D_EN | \
+							WAKEUP_OP_04_EN)
+
+/*
+ * CEC OPCODES
+ */
+#define	CEC_OC_ABORT_MESSAGE 					0xFF
+#define	CEC_OC_ACTIVE_SOURCE 					0x82
+#define	CEC_OC_CEC_VERSION 					0x9E
+#define	CEC_OC_CLEAR_ANALOGUE_TIMER 				0x33
+#define	CEC_OC_CLEAR_DIGITAL_TIMER 				0x99
+#define	CEC_OC_CLEAR_EXTERNAL_TIMER 				0xA1
+#define	CEC_OC_DECK_CONTROL 					0x42
+#define	CEC_OC_DECK_STATUS 					0x1B
+#define	CEC_OC_DEVICE_VENDOR_ID 				0x87
+#define	CEC_OC_FEATURE_ABORT 					0x00
+#define	CEC_OC_GET_CEC_VERSION 					0x9F
+#define	CEC_OC_GET_MENU_LANGUAGE 				0x91
+#define	CEC_OC_GIVE_AUDIO_STATUS 				0x71
+#define	CEC_OC_GIVE_DECK_STATUS 				0x1A
+#define	CEC_OC_GIVE_DEVICE_POWER_STATUS 			0x8F
+#define	CEC_OC_GIVE_DEVICE_VENDOR_ID 				0x8C
+#define	CEC_OC_GIVE_OSD_NAME 					0x46
+#define	CEC_OC_GIVE_PHYSICAL_ADDRESS 				0x83
+#define	CEC_OC_GIVE_SYSTEM_AUDIO_MODE_STATUS 			0x7D
+#define	CEC_OC_GIVE_TUNER_DEVICE_STATUS 			0x08
+#define	CEC_OC_IMAGE_VIEW_ON 					0x04
+#define	CEC_OC_INACTIVE_SOURCE 					0x9D
+#define	CEC_OC_MENU_REQUEST 					0x8D
+#define	CEC_OC_MENU_STATUS 					0x8E
+#define	CEC_OC_PLAY 						0x41
+#define	CEC_OC_POLLING_MESSAGE 					0xFC	/* Fake Code - <Poll Message> has no OP Code and requires only the header byte */
+#define	CEC_OC_RECORD_OFF 					0x0B
+#define	CEC_OC_RECORD_ON 					0x09
+#define	CEC_OC_RECORD_STATUS 					0x0A
+#define	CEC_OC_RECORD_TV_SCREEN 				0x0F
+#define	CEC_OC_REPORT_AUDIO_STATUS 				0x7A
+#define	CEC_OC_REPORT_PHYSICAL_ADDRESS 				0x84
+#define	CEC_OC_REPORT_POWER_STATUS 				0x90
+#define	CEC_OC_REQUEST_ACTIVE_SOURCE 				0x85
+#define	CEC_OC_ROUTING_CHANGE 					0x80
+#define	CEC_OC_ROUTING_INFORMATION 				0x81
+#define	CEC_OC_SELECT_ANALOGUE_SERVICE 				0x92
+#define	CEC_OC_SELECT_DIGITAL_SERVICE 				0x93
+#define	CEC_OC_SET_ANALOGUE_TIMER 				0x34
+#define	CEC_OC_SET_AUDIO_RATE 					0x9A
+#define	CEC_OC_SET_DIGITAL_TIMER 				0x97
+#define	CEC_OC_SET_EXTERNAL_TIMER 				0xA2
+#define	CEC_OC_SET_MENU_LANGUAGE 				0x32
+#define	CEC_OC_SET_OSD_NAME 					0x47
+#define	CEC_OC_SET_OSD_STRING 					0x64
+#define	CEC_OC_SET_STREAM_PATH 					0x86
+#define	CEC_OC_SET_SYSTEM_AUDIO_MODE 				0x72
+#define	CEC_OC_SET_TIMER_PROGRAM_TITLE 				0x67
+#define	CEC_OC_STANDBY 						0x36
+#define	CEC_OC_SYSTEM_AUDIO_MODE_REQUEST 			0x70
+#define	CEC_OC_SYSTEM_AUDIO_MODE_STATUS 			0x7E
+#define	CEC_OC_TEXT_VIEW_ON 					0x0D
+#define	CEC_OC_TIMER_CLEARED_STATUS 				0x43
+#define	CEC_OC_TIMER_STATUS 					0x35
+#define	CEC_OC_TUNER_DEVICE_STATUS 				0x07
+#define	CEC_OC_TUNER_STEP_DECREMENT 				0x06
+#define	CEC_OC_TUNER_STEP_INCREMENT 				0x05
+#define	CEC_OC_USER_CONTROL_PRESSED 				0x44
+#define	CEC_OC_USER_CONTROL_RELEASED 				0x45
+#define	CEC_OC_VENDOR_COMMAND 					0x89
+#define	CEC_OC_VENDOR_COMMAND_WITH_ID 				0xA0
+#define	CEC_OC_VENDOR_REMOTE_BUTTON_DOWN 			0x8A
+#define	CEC_OC_VENDOR_REMOTE_BUTTON_UP 				0x8B
+
+/*CEC UI MASK*/
+#define CEC_FUNC_MASK                        0
+#define ONE_TOUCH_PLAY_MASK                  1
+#define ONE_TOUCH_STANDBY_MASK               2
+#define AUTO_POWER_ON_MASK                   3
+
+//#define P_HHI_GCLK_MPEG2 CBUS_REG_ADDR(HHI_GCLK_MPEG2)
+//#define P_HHI_HDMI_CLK_CNTL CBUS_REG_ADDR(HHI_HDMI_CLK_CNTL)
+#define MAX_MSG 16
+#define CEC_PLAYBACK_DEVICE_TYPE 4
+#define CEC_BROADCAST_ADDR 0xf
+#define CEC_VERSION_14A 5
+
+enum _cec_log_dev_addr_e {
+    CEC_TV_ADDR = 0x00,
+    CEC_RECORDING_DEVICE_1_ADDR,
+    CEC_RECORDING_DEVICE_2_ADDR,
+    CEC_TUNER_1_ADDR,
+    CEC_PLAYBACK_DEVICE_1_ADDR,
+    CEC_AUDIO_SYSTEM_ADDR,
+    CEC_TUNER_2_ADDR,
+    CEC_TUNER_3_ADDR,
+    CEC_PLAYBACK_DEVICE_2_ADDR,
+    CEC_RECORDING_DEVICE_3_ADDR,
+    CEC_TUNER_4_ADDR,
+    CEC_PLAYBACK_DEVICE_3_ADDR,
+    CEC_RESERVED_1_ADDR,
+    CEC_RESERVED_2_ADDR,
+    CEC_FREE_USE_ADDR,
+    CEC_UNREGISTERED_ADDR
+};
+
+typedef enum  {
+    CEC_UNRECONIZED_OPCODE = 0x0,
+    CEC_NOT_CORRECT_MODE_TO_RESPOND,
+    CEC_CANNOT_PROVIDE_SOURCE,
+    CEC_INVALID_OPERAND,
+    CEC_REFUSED,
+    CEC_UNABLE_TO_DETERMINE,
+} cec_feature_abort_e;
+
+typedef enum {
+    DEVICE_MENU_ACTIVE = 0,
+    DEVICE_MENU_INACTIVE,
+} cec_device_menu_state_e;
+
+/* cec message structure */
+typedef struct {
+    unsigned char msg[16];
+    unsigned char msg_len;
+} cec_msg_buf_t;
+
+typedef struct {
+	cec_msg_buf_t buf[2];          /* message memory */
+	unsigned char power_status;
+	unsigned char log_addr;
+	unsigned char cec_power;
+	unsigned char active_source;
+	unsigned char rx_write_pos;
+	unsigned char rx_read_pos;
+	unsigned char rx_buf_size;
+	unsigned int addr_enable;
+} cec_msg_t;
+
+#endif  // _HDMI_RX_REG_H
+
diff --git a/bl30/src_ao/demos/amlogic/driver/ddr/build.mk b/bl30/src_ao/demos/amlogic/driver/ddr/build.mk
new file mode 100644
index 0000000..dca5454
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/ddr/build.mk
@@ -0,0 +1,26 @@
+#
+#  Copyright (C) 2014-2018 Amlogic, Inc. All rights reserved.
+#
+#  All information contained herein is Amlogic confidential.
+#
+#  This software is provided to you pursuant to Software License Agreement
+#  (SLA) with Amlogic Inc ("Amlogic"). This software may be used
+#  only in accordance with the terms of this agreement.
+#
+#  Redistribution and use in source and binary forms, with or without
+#  modification is strictly prohibited without prior written permission from
+#  Amlogic.
+#
+#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#  OWNER 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, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+ddr-y = ddr.o
diff --git a/bl30/src_ao/demos/amlogic/driver/ddr/ddr.c b/bl30/src_ao/demos/amlogic/driver/ddr/ddr.c
new file mode 100644
index 0000000..5f5ed47
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/ddr/ddr.c
@@ -0,0 +1,592 @@
+/*
+ * Copyright (C) 2014-2018 Amlogic, Inc. All rights reserved.
+ *
+ * All information contained herein is Amlogic confidential.
+ *
+ * This software is provided to you pursuant to Software License Agreement
+ * (SLA) with Amlogic Inc ("Amlogic"). This software may be used
+ * only in accordance with the terms of this agreement.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification is strictly prohibited without prior written permission from
+ * Amlogic.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER 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, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *//*
+ * Copyright (C) 2014-2018 Amlogic, Inc. All rights reserved.
+ *
+ * All information contained herein is Amlogic confidential.
+ *
+ * This software is provided to you pursuant to Software License Agreement
+ * (SLA) with Amlogic Inc ("Amlogic"). This software may be used
+ * only in accordance with the terms of this agreement.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification is strictly prohibited without prior written permission from
+ * Amlogic.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER 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, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "common.h"
+#include "register.h"
+#include "FreeRTOS.h"
+#include "task.h"
+#include "soc.h"
+#include "suspend.h"
+
+#define timere_read()	REG32(TIMERE_LOW_REG)
+/* io defines */
+#define wr_reg(addr, val)					(*((volatile uint32_t *)(addr)))  = (val)
+#define rd_reg(addr)						(*((volatile uint32_t *)(addr)))
+
+/*clear [mask] 0 bits in [addr], set these 0 bits with [value] corresponding bits*/
+#define modify_reg(addr, value, mask)       wr_reg(addr, ((rd_reg(addr) & (mask)) | (value)))
+#define wait_set(addr, loc)                 do {} while (0 == (rd_reg(addr) & (1 << loc)));
+#define wait_clr(addr, loc)                 do {} while (1 == (rd_reg(addr) & (1 << loc)));
+#define wait_equal(addr, data)              do {} while (data != (rd_reg(addr)));
+
+#define _udelay(tim)                        vTaskDelay(tim)
+
+unsigned int g_nAPDSet = 0;
+#if 0
+void vDDR_suspend(uint32_t st_f)
+{
+	//printf("aml log : DDR suspend...dummy\n");
+	//return;
+
+	printf("aml log : DDR suspend...1");
+
+	g_nAPDSet = rd_reg(DMC_DRAM_APD_CTRL);
+	wr_reg(DMC_DRAM_APD_CTRL,0);
+
+#ifdef CHECK_DMC_IDLE
+	while ((((rd_reg(DMC_DRAM_STAT)) & 0xf0) != 0) &&
+		(((rd_reg(DMC_DRAM_STAT)) & 0xf0) != 0x40)) {
+	}
+#endif
+
+#if 0
+	wr_reg(DMC_DRAM_SCFG, 2);
+	vTaskDelay(pdMS_TO_TICKS(1));
+	while (((((rd_reg(DMC_DRAM_STAT)) >> 4) & 0xf) != 3)) {
+	}
+#endif
+
+	wr_reg(DMC_DRAM_DFIINITCFG, (1 | (1 << 8)));
+
+	wait_clr(DMC_DRAM_DFIINITCFG, 31);
+
+	vTaskDelay(pdMS_TO_TICKS(1));
+	//wr_reg(AM_DDR_PLL_CNTL0,
+	//	(rd_reg(AM_DDR_PLL_CNTL0) & (~(0xf << 28))) | (1 << 29));
+
+	printf("done!!\n");
+
+	vTaskDelay(pdMS_TO_TICKS(1000));
+
+	//vDDR_resume(0);
+
+	printf("\naml log : DMC_DRAM_STAT=0x%x",rd_reg(DMC_DRAM_STAT));
+	printf("\naml log : DMC_DRAM_DFIINITCFG=0x%x\n",rd_reg(DMC_DRAM_DFIINITCFG));
+
+}
+
+void vDDR_resume(uint32_t st_f)
+{
+	printf("aml log : DDR resume...2");
+
+	//printf("aml log : DDR resume...dummy\n");
+	//return;
+
+	#if 0
+	do {
+		wr_reg(AM_DDR_PLL_CNTL0, (rd_reg(AM_DDR_PLL_CNTL0) & (~(0xf << 28))) | (0xc << 28));
+		vTaskDelay(pdMS_TO_TICKS(1));
+		wr_reg(AM_DDR_PLL_CNTL0, (rd_reg(AM_DDR_PLL_CNTL0) & (~(0xf << 28))) | (0xd << 28));
+		vTaskDelay(pdMS_TO_TICKS(5));
+		wr_reg(AM_DDR_PLL_CNTL0, (rd_reg(AM_DDR_PLL_CNTL0) & (~(0xf << 28))) | (0x5 << 28));
+		vTaskDelay(pdMS_TO_TICKS(10));
+		wr_reg(AM_DDR_PLL_CNTL0, (rd_reg(AM_DDR_PLL_CNTL0) & (~(0xf << 28))) | (0x7 << 28));
+		vTaskDelay(pdMS_TO_TICKS(100));
+	} while ((0 == ((rd_reg(AM_DDR_PLL_STS) >> 31) & 0x1)));
+	wr_reg(DDR_CLK_CNTL, 0x10000000);
+	wr_reg(DDR_CLK_CNTL, 0xb0000007);
+
+	vTaskDelay(pdMS_TO_TICKS(1));
+	#endif
+
+
+	wr_reg(DMC_DRAM_DFIINITCFG, (0 | (1 << 8)));
+	vTaskDelay(pdMS_TO_TICKS(1));
+
+	printf("-1");
+
+	wait_set(DMC_DRAM_DFIINITCFG, 31);
+	vTaskDelay(pdMS_TO_TICKS(10)); //extra 10us for vt
+#if 0
+	wr_reg(DMC_DRAM_SCFG, 4);
+#endif
+	vTaskDelay(pdMS_TO_TICKS(1));
+
+	printf("-2");
+
+	int nLoopFlag = 1;
+	do {
+
+		switch ((rd_reg(DMC_DRAM_STAT)) & 0xf0)
+		{
+		case 0:    //DRAM IDLE
+		case 0x20: //DRAM ACCESS
+		case 0x40: //DRAM APD
+		nLoopFlag = 0;
+		break;
+		default: break;
+		}
+	} while(nLoopFlag);
+
+	vTaskDelay(pdMS_TO_TICKS(30));
+
+	printf("-3");
+
+	printf("done\n");
+
+	printf("\naml log : DMC_DRAM_STAT=0x%x",rd_reg(DMC_DRAM_STAT));
+	printf("\naml log : DMC_DRAM_DFIINITCFG=0x%x\n",rd_reg(DMC_DRAM_DFIINITCFG));
+
+}
+#endif
+
+/*
+#define PATTERN_MATRIX_X   (3 + 32 + 16 + 17)     //68*32==2176 ///2.2k -0x880-1 loop
+#define PATTERN_MATRIX_Y  (32)
+#define PATTERN_MATRIX_LOOP_SIZE   ((PATTERN_MATRIX_X)*(PATTERN_MATRIX_Y) * 4)
+unsigned int cpu_ddr_test_init_pattern_generater(uint32_t martix_x_select, uint32_t martix_y_select)
+{
+	unsigned int pattern_value = 0;
+	unsigned int pattern_value_temp_16 = 0;
+
+	martix_x_select = (martix_x_select % PATTERN_MATRIX_X);
+	{
+		{
+			{
+				if (martix_x_select == 0)
+					pattern_value = 0xaaaa5555;  //for 16 bit bus pattern
+
+				if (martix_x_select == 1)
+					pattern_value = 0x0000ffff;  //for 16 bit bus pattern
+
+				if (martix_x_select == 2)
+					pattern_value = 0;
+
+				if ((martix_x_select > 2) && (martix_x_select < (3 + 32)))
+					pattern_value = 1 << (martix_x_select - 3);
+				if ((martix_x_select > (2 + 32)) && (martix_x_select < (3 + 32 + 16))) { //for 16 bit bus pattern
+					pattern_value_temp_16 = (1 << (martix_x_select - 3 - 32));
+					pattern_value = pattern_value_temp_16 | ((~pattern_value_temp_16) << 16);
+				}
+				if ((martix_x_select > (2 + 32 + 16)) && (martix_x_select < (3 + 32 + 16 + 17))) { //for dbi bus pattern  17 group
+					pattern_value_temp_16 = (0x0f0f + 0xf0f * (martix_x_select - 3 - 32 - 16));
+					pattern_value = pattern_value_temp_16 | ((~pattern_value_temp_16) << 16);
+				}
+			}
+			if ((martix_y_select % 2))
+				pattern_value = ~pattern_value;
+			if ((martix_y_select % ((PATTERN_MATRIX_Y) / 2)) == (((PATTERN_MATRIX_Y * 1) / 8) - 1)) //for dbi pattern walk 0 and walk 1
+				pattern_value = 0;                                                              //insert for dbi pattern jiaxing 20190117
+			if ((martix_y_select % ((PATTERN_MATRIX_Y) / 2)) == (((PATTERN_MATRIX_Y * 3) / 8) - 1)) //for dbi pattern walk 0 and walk 1
+				pattern_value = ~0;                                                             //insert for dbi pattern jiaxing 20190117
+		}
+	}
+	return pattern_value;
+}
+*/
+#if 0
+static unsigned int dmc_ddr_test(unsigned int start_add, unsigned int write_enable, unsigned int read_enable, unsigned int read_compare, unsigned int test_end_add, unsigned int pattern, unsigned int seed)
+{
+	seed=2;
+#define DATA_LOOP_PATTERN_INDEX  4 + 32        //0xff
+	unsigned int dmc_test_sts = 0;
+	unsigned int dmc_error = 0;
+	//unsigned int pattern_select = 0;
+	unsigned int pattern_value = 0;
+	unsigned int pattern_inv_value = 0;
+
+	dmc_error = 0;
+	{
+		test_end_add = test_end_add - 4;        //sha must bit 0-6 ==ff;
+	}
+	wr_reg(DMC_TEST_STA, start_add);                // RESET FIFOS  //0x03d81e3f
+	wr_reg(DMC_TEST_EDA, test_end_add);             //0x07d81e3f
+	if (pattern == 0) {
+		wr_reg(DMC_TEST_WD0, 0xaa5555aa);
+		wr_reg(DMC_TEST_WD1, 0x55aaaa55);
+		wr_reg(DMC_TEST_WD2, 0);
+		wr_reg(DMC_TEST_WD3, 0xffffffff);
+		wr_reg(DMC_TEST_WD4, 0);
+		wr_reg(DMC_TEST_WD5, 0x0000ffff);
+		wr_reg(DMC_TEST_WD6, 0xffff0000);
+		wr_reg(DMC_TEST_WD7, 0x33cccc33);
+		wr_reg(DMC_TEST_WD0 + 32, 0xaa5555aa);
+		wr_reg(DMC_TEST_WD1 + 32, 0x55aaaa55);
+		wr_reg(DMC_TEST_WD2 + 32, 0);
+		wr_reg(DMC_TEST_WD3 + 32, 0xffffffff);
+		wr_reg(DMC_TEST_WD4 + 32, 0);
+		wr_reg(DMC_TEST_WD5 + 32, 0x0000ffff);
+		wr_reg(DMC_TEST_WD6 + 32, 0xffff0000);
+		wr_reg(DMC_TEST_WD7 + 32, 0x33cccc33);
+	} else if (pattern < 33) {
+		wr_reg(DMC_TEST_WD0, ((1 << (pattern - 1)) + seed));
+		wr_reg(DMC_TEST_WD1, ((2 << (pattern - 1)) + seed));
+		wr_reg(DMC_TEST_WD2, ((3 << (pattern - 1)) + seed));
+		wr_reg(DMC_TEST_WD3, ((4 << (pattern - 1)) + seed));
+		wr_reg(DMC_TEST_WD4, ((4 << (pattern - 1))));
+		wr_reg(DMC_TEST_WD5, ((4 << (pattern - 1))));
+		wr_reg(DMC_TEST_WD6, ((4 << (pattern - 1))));
+		wr_reg(DMC_TEST_WD7, ((4 << (pattern - 1))));
+		if (pattern > 16) {
+			wr_reg(DMC_TEST_WD4, ((4 << (pattern - 1)) + 0x01010101));
+			wr_reg(DMC_TEST_WD5, ((4 << (pattern - 1)) + 0x01010101));
+			wr_reg(DMC_TEST_WD6, ((4 << (pattern - 1)) + 0x01010101));
+			wr_reg(DMC_TEST_WD7, ((4 << (pattern - 1)) + 0x01010101));
+		} else if (pattern > 1) {
+			wr_reg(DMC_TEST_WD4, ((4 << (pattern - 1)) + 0x01010101));
+			wr_reg(DMC_TEST_WD5, ((4 << (pattern - 1)) + 0x01010101));
+			wr_reg(DMC_TEST_WD6, ((4 << (pattern - 1)) + 0x01010101));
+			wr_reg(DMC_TEST_WD7, ((4 << (pattern - 1)) + 0x01010101));
+		}
+	} else {
+		//pattern_select = pattern - 33;
+		pattern_value =1;// cpu_ddr_test_init_pattern_generater(pattern_select, 0);
+		pattern_inv_value = ~pattern_value;
+		for (char counter = 0; counter < 32; ) {
+			wr_reg((DMC_TEST_WD0 + counter), pattern_value);
+			counter = counter + 4;
+			wr_reg((DMC_TEST_WD0 + counter), pattern_inv_value);
+			if (counter == 16)
+				wr_reg((DMC_TEST_WD0 + counter), 0);
+			counter = counter + 4;
+		}
+		for (char counter = 0; counter < 32; ) { //for g12b-revb register not continuous
+			wr_reg((DMC_TEST_WD8 + counter), pattern_value);
+			counter = counter + 4;
+			wr_reg((DMC_TEST_WD8 + counter), pattern_inv_value);
+			if (counter == 16)
+				wr_reg((DMC_TEST_WD0 + counter), ~0);
+			counter = counter + 4;
+		}
+	}
+
+
+	wr_reg(DMC_TEST_STS, 0x8000001f);                       //must clear watchdog and done flag jiaxing debug 2016_12_07
+	wr_reg(DMC_TEST_WDG, 0xf000f000);                       //wdg should >rfc value ,use dmc clk count.
+	if ((pattern == 1) || ((pattern < 33) && pattern))      //should repeat 1 times for read ,all will fail when data increase jiaxing debug 20180322
+		wr_reg(DMC_TEST_CTRL, (1 << 31) | (read_compare << 27) | (0 << 28) | (0 << 25) | (1 << 24) | (0 << 20) | (1 << 23) | (0x0 << 16) | (0 << 8) | (0x428) | (3 << 18) | (write_enable << 30) | (read_enable << 29));
+	else
+		wr_reg(DMC_TEST_CTRL, (1 << 31) | (read_compare << 27) | (0 << 28) | (1 << 24) | (0x0 << 16) | (0 << 18) | (0x0 << 0) | (0 << 8) | (0x428) | (3 << 18) | (write_enable << 30) | (read_enable << 29));
+
+	do
+		//_udelay(1);
+		dmc_test_sts = (rd_reg(DMC_TEST_STS));
+	while (!(dmc_test_sts & 0xc0000000));
+
+	wr_reg(DMC_TEST_CTRL, 0x00000000);
+
+	if ((dmc_test_sts & 0x40000000))
+		dmc_error = 1;
+	else
+	if (dmc_test_sts & 0x40000001)         //can not deter write triger ,or can not quickly recover dmc with phy? 2016_12_12
+		dmc_error = 1;
+
+	dmc_error = dmc_error + (rd_reg(DMC_TEST_ERR_CNT));
+	wr_reg(DMC_TEST_STS, 0x8000001f); //must clear watchdog and done flag jiaxing debug 2016_12_07
+
+	if (dmc_error) {
+		for (unsigned int counter1 = 0; counter1 < (DMC_TEST_RDRSP_ADDR+4-DMC_TEST_STA); )
+		{
+		printf("\n counter %08x %08x",counter1,(rd_reg(DMC_TEST_STA+(counter1))));
+		counter1=counter1+4;
+		}
+		wr_reg(DMC_SOFT_RST, (rd_reg(DMC_SOFT_RST)) & (~((1 << 29) | (1 << 24))));  //clear read buffer dmc test reset
+		vTaskDelay(pdMS_TO_TICKS(1));
+		wr_reg(DMC_SOFT_RST, (rd_reg(DMC_SOFT_RST)) | ((1 << 29)) | (1 << 24));
+		vTaskDelay(pdMS_TO_TICKS(1));
+	}
+	return dmc_error;
+}
+
+unsigned int apb_sec_ctrl = 0;
+#define DDR_APB_SEC_CTRL                           ((0x00f0  << 2) + 0xff639000)
+#endif
+#if 0 //def CFG_ENABLE_DDR_SUSPEND_TEST
+static void ddr_suspend_resume_test(uint32_t test_size, uint32_t test_delay_time_ms, uint32_t test_write_loops, uint32_t test_read_loops, uint32_t test_skip_suspend, uint32_t p_dev)
+{
+	//return;
+	uint32_t lock_cnt = 100;
+	uint32_t apd_value = 0;
+	p_dev = p_dev;
+	printf( "enter suspend_n_debug\n");
+	apd_value = rd_reg(DMC_DRAM_APD_CTRL);
+	wr_reg(DMC_DRAM_APD_CTRL, 0);
+
+	//watchdog_disable();
+	printf( "test_size=%08x test_delay_time_ms=%d test_write_loops=%d test_read_loops=%d", \
+		     test_size, test_delay_time_ms, test_write_loops, test_read_loops);
+	printf( "enter suspend111\n");
+
+#if 1 //def CFG_ENABLE_DDR_DMC_TEST
+	uint64_t dram_size = 0, dram_base = 0;
+	dram_base = 0x0000000;                                                      // p_ddrs->ddr_base_addr;
+	//dram_size = 1024;//p_ddrs->cfg_board_common_setting.dram_cs0_size_MB + p_ddrs->cfg_board_common_setting.dram_cs1_size_MB;
+	dram_size =1024;
+
+	if (!test_size)
+		test_size = (dram_size << 20) - 4;
+
+	//if (!test_delay_time_ms)
+	//	test_delay_time_ms = 3000;
+
+	if (!test_write_loops)
+		test_write_loops = 1;
+
+	if (!test_read_loops)
+		test_read_loops = 1;
+	uint32_t ddr_bist_test_error = 0;
+#endif
+
+	while ((test_write_loops) || (test_read_loops)) {
+		if (test_write_loops)
+			ddr_bist_test_error = dmc_ddr_test(dram_base, 1, 0, 0, test_size, 1, 0) + ddr_bist_test_error;
+printf( "enter suspend113\n");
+		if (!test_skip_suspend) {
+#if  0 //def CHECK_DMC_IDLE
+			while ((((rd_reg(DMC_DRAM_STAT)) & 0xf0) != 0) && (((rd_reg(DMC_DRAM_STAT)) & 0xf0) != 0x40)) {
+			}
+#endif
+#if 0
+			wr_reg(DMC_DRAM_SCFG, 2);
+			vTaskDelay(pdMS_TO_TICKS(1));
+
+			while (((((rd_reg(DMC_DRAM_STAT)) >> 4) & 0xf) != 3)) {
+			}
+#endif
+//printf( "enter suspend114\n");
+			wr_reg(DMC_DRAM_DFIINITCFG, (1 | (0 << 1) | (0 << 6) | (0 << 14) | (1 << 8)));
+			vTaskDelay(pdMS_TO_TICKS(1));
+			wait_clr(DMC_DRAM_DFIINITCFG, 31);                                                                                                                                     //final version, wait_clr
+			vTaskDelay(pdMS_TO_TICKS(3));
+		//	printf( "enter suspend115\n");
+			wr_reg(AM_DDR_PLL_CNTL0, (rd_reg(AM_DDR_PLL_CNTL0) & (~(0xf << 28))) | (1 << 29));
+		}
+		//_udelay(test_delay_time_ms * 1000);
+		vTaskDelay(test_delay_time_ms * pdMS_TO_TICKS(1000));
+		//_udelay( 1000);
+printf( "enter suspend111..wait\n");
+		if (!test_skip_suspend) {
+			printf("enter resume\n");
+
+			do {
+				wr_reg(AM_DDR_PLL_CNTL0, (rd_reg(AM_DDR_PLL_CNTL0) & (~(0xf << 28))) | (1 << 29));
+				vTaskDelay(pdMS_TO_TICKS(1));
+				wr_reg(AM_DDR_PLL_CNTL0, (rd_reg(AM_DDR_PLL_CNTL0) & (~(0x1 << 29))) | (1 << 28));
+
+				vTaskDelay(pdMS_TO_TICKS(200));                                                                                                                                                                                                          //must wait some time than to read
+			} while ((0 == ((rd_reg(AM_DDR_PLL_CNTL0) >> 31) & 0x1)) && (lock_cnt--));
+
+			printf( "pll relock ok\n");                                                                                                                                         //need extra delay
+			vTaskDelay(pdMS_TO_TICKS(1));
+			wr_reg(DMC_DRAM_DFIINITCFG, (0 | (0 << 1) | (0 << 6) | (0 << 14) | (1 << 8)));
+			vTaskDelay(pdMS_TO_TICKS(1));
+			wait_set(DMC_DRAM_DFIINITCFG, 31);
+			vTaskDelay(pdMS_TO_TICKS(100));                                                                                                                                    //extra 10us for vt
+		}
+#if 1 //def CFG_ENABLE_DDR_DMC_TEST
+		if (test_read_loops)
+			ddr_bist_test_error = dmc_ddr_test(dram_base, 0, 1, 1, test_size, 1, 0) + ddr_bist_test_error;
+		 //if (ddr_bist_test_error)
+		printf( "dmc full test result = %d\n", ddr_bist_test_error);
+#endif
+
+		if (test_write_loops)
+			test_write_loops--;
+
+		if (test_read_loops)
+			test_read_loops--;
+	}
+	wr_reg(DMC_DRAM_APD_CTRL, apd_value);
+
+	//printf("end resume test11\n");
+} /* ddr_suspend_resume_test */
+#endif
+	//#define DDR_SUSPEND_MODE_DMC_TRIGGER_SUSPEND_1   1
+	#define DDR_SUSPEND_MODE_MANUAL_TRIGGER_DFI_INIT_START   2
+void vDDR_suspend(uint32_t st_f)
+{
+	//printf("aml log : DDR suspend...dummy\n");
+	//return;
+
+	st_f = st_f;
+	//unsigned int time_start, time_end;
+	printf("Enter ddr suspend\n");
+
+	//return ;
+
+	while (0xfffffff != rd_reg(DMC_CHAN_STS)) {
+		printf("DMC_CHAN_STS: 0x%x\n", rd_reg(DMC_CHAN_STS));
+		vTaskDelay(pdMS_TO_TICKS(100000));
+	}
+
+	//time_start = rd_reg(P_ISA_TIMERE);
+
+	/* open DMC reg access for M3 */
+	//apb_sec_ctrl = rd_reg(DDR_APB_SEC_CTRL);
+	//wr_reg(DDR_APB_SEC_CTRL,0x91911);
+
+	wr_reg(DMC_REQ_CTRL, 0); //bit0: A53.
+	_udelay(1);
+
+	/* suspend flow */
+	while ((((rd_reg(DMC_DRAM_STAT))&0xf0) != 0) && (((rd_reg(DMC_DRAM_STAT))&0xf0) != 0x40)) {
+	//	printf("DMC_DRAM_STAT11: 0x%x\n", rd_reg(DMC_DRAM_STAT));
+		vTaskDelay(pdMS_TO_TICKS(1));
+	}
+#ifdef DDR_SUSPEND_MODE_DMC_TRIGGER_SUSPEND_1
+	wr_reg(DMC_DRAM_ASR_CTRL,(1<<18));  //bit 18 will auto trigger dfi init start cmd when scfg set to value 2
+	wr_reg(DMC_DRAM_SCFG, 2);
+	while (((((rd_reg(DMC_DRAM_STAT))>>4)&0xf) != 3)) {
+		//printf("DMC_DRAM_STAT22: 0x%x\n", readl(DMC_DRAM_STAT));
+		//_udelay(1);//do not add any delay,since use ao cpu maybe speed too slow
+	}
+
+#endif
+
+#ifdef DDR_SUSPEND_MODE_MANUAL_TRIGGER_DFI_INIT_START
+	wr_reg(DMC_DRAM_SCFG, 1);
+	while (((((rd_reg(DMC_DRAM_STAT))>>4)&0xf) != 1)) {
+		//printf("DMC_DRAM_STAT22: 0x%x\n", readl(DMC_DRAM_STAT));
+		//_udelay(1);//do not add any delay,since use ao cpu maybe speed too slow
+	}
+
+			wr_reg(DMC_DRAM_DFIINITCFG, (1 | (0 << 1) | (0 << 6) | (0 << 14) | (1 << 8)));
+			vTaskDelay(pdMS_TO_TICKS(1));
+			wait_clr(DMC_DRAM_DFIINITCFG, 31);
+#endif                                                                                                                                  //final version, wait_clr
+			vTaskDelay(pdMS_TO_TICKS(3));
+			wr_reg(AM_DDR_PLL_CNTL0, (rd_reg(AM_DDR_PLL_CNTL0) & (~(0xf << 28))) | (1 << 29));
+
+
+	/* print time consumption */
+	//time_end = rd_reg(P_ISA_TIMERE);
+	//printf("ddr suspend time: %dus\n", time_end - time_start);
+	printf("\nddr suspend is done\n");
+	//ddr_suspend_resume_test((1024<<20), 100, 3, 3, 0, 0);
+	//ddr_suspend_resume_test((80<<20), 10000000, 0, 3, 0, 0);
+}
+
+static unsigned int pll_lock(void)
+{
+	unsigned int lock_cnt = 1000;
+
+	wr_reg(AM_DDR_PLL_CNTL0, (rd_reg(AM_DDR_PLL_CNTL0) & (~(0xf << 28))) | (1 << 29));
+	vTaskDelay(pdMS_TO_TICKS(1));
+	wr_reg(AM_DDR_PLL_CNTL0, (rd_reg(AM_DDR_PLL_CNTL0) & (~(0x1 << 29))) | (1 << 28));
+	do {
+		vTaskDelay(pdMS_TO_TICKS(1));
+	} while ((0 == ((rd_reg(AM_DDR_PLL_CNTL0) >> 31) & 0x1)) && (lock_cnt--));
+	return lock_cnt;
+}
+
+void vDDR_resume(uint32_t st_f)
+{
+	//unsigned int time_start, time_end;
+	unsigned int ret = 0;
+	uint32_t last_time = timere_read();
+	st_f = st_f;
+	printf("Enter ddr resume\n");
+
+
+	//return;
+
+	//time_start = rd_reg(P_ISA_TIMERE);
+	/* resume flow */
+	#if 1
+	ret = pll_lock();
+	if (!ret) {
+		printf("ddr pll lock r1\n");
+		wr_reg(AM_DDR_PLL_CNTL3, rd_reg(AM_DDR_PLL_CNTL3)|(1<<31));
+		ret = pll_lock();
+		if (!ret) {
+			printf("ddr pll lock r2\n");
+			wr_reg(AM_DDR_PLL_CNTL6, 0x55540000);
+			ret = pll_lock();
+			if (!ret) {
+				printf("ddr pll lock r2\n");
+				while (1) {};
+			}
+		}
+	}
+#endif
+
+#ifdef DDR_SUSPEND_MODE_DMC_TRIGGER_SUSPEND_1
+
+#endif
+
+#ifdef DDR_SUSPEND_MODE_MANUAL_TRIGGER_DFI_INIT_START
+			wr_reg(DMC_DRAM_DFIINITCFG, (0 | (0 << 1) | (0 << 6) | (0 << 14) | (1 << 8)));
+			vTaskDelay(pdMS_TO_TICKS(1));
+			wait_set(DMC_DRAM_DFIINITCFG, 31);
+			vTaskDelay(pdMS_TO_TICKS(1));
+#endif
+	wr_reg(DMC_DRAM_SCFG, 4);
+	while (((((rd_reg(DMC_DRAM_STAT))>>4)&0xf) != 2)) {
+		//printf("DMC_DRAM_STAT22: 0x%x\n", readl(DMC_DRAM_STAT));
+		//_udelay(1);//do not add any delay,since use ao cpu maybe speed too slow
+	}
+
+	#if 0
+	wr_reg( DMC_DRAM_SCFG, 4);
+	vTaskDelay(pdMS_TO_TICKS(1));
+	#endif
+
+	wr_reg(DMC_REQ_CTRL, 0xffffffff);
+	//wr_reg(DDR_APB_SEC_CTRL, apb_sec_ctrl);
+	/* print time consumption */
+	//time_end = readl(P_ISA_TIMERE);
+	//printf("ddr resume time: %dus\n", time_end - time_start);
+	//	unsigned int ddr_bist_test_error = 0;
+	//ddr_bist_test_error = dmc_ddr_test(dram_base, 0, 1, 1, test_size, 1, 0) + ddr_bist_test_error;
+	//ddr_bist_test_error = dmc_ddr_test(0, 0, 1, 1, (80<<20), 1, 0) + ddr_bist_test_error;
+	//printf("ddr_bist_test_error = %d\n", ddr_bist_test_error);
+	//wr_reg(0xfe002440, 2);
+//	wr_reg(0xfe002440, 0);
+//	_udelay(300);
+	//ddr_bist_test_error = dmc_ddr_test(0, 1, 0, 0, (1<<20), 1, 0) + ddr_bist_test_error;
+	//ddr_bist_test_error = dmc_ddr_test(0, 0, 1, 1, (1<<20), 1, 0) + ddr_bist_test_error;
+//	printf("ddr_bist_test_error = %d\n", ddr_bist_test_error);
+	//ddr_suspend_resume_test((1<<20), 2, 1, 3, 0, 0);
+	//ddr_suspend_resume_test((1<<20), 0, 1, 3, 0, 0);
+	//_udelay(300);
+//	wr_reg(DMC_REQ_CTRL, 0xffffffff);
+	printf("ddr resume done %d us\n", timere_read() - last_time);
+}
+
+
diff --git a/bl30/src_ao/demos/amlogic/driver/eth/build.mk b/bl30/src_ao/demos/amlogic/driver/eth/build.mk
new file mode 100644
index 0000000..e1d327a
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/eth/build.mk
@@ -0,0 +1,26 @@
+#
+#  Copyright (C) 2014-2018 Amlogic, Inc. All rights reserved.
+#
+#  All information contained herein is Amlogic confidential.
+#
+#  This software is provided to you pursuant to Software License Agreement
+#  (SLA) with Amlogic Inc ("Amlogic"). This software may be used
+#  only in accordance with the terms of this agreement.
+#
+#  Redistribution and use in source and binary forms, with or without
+#  modification is strictly prohibited without prior written permission from
+#  Amlogic.
+#
+#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#  OWNER 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, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+eth-y = eth.o
diff --git a/bl30/src_ao/demos/amlogic/driver/eth/eth.c b/bl30/src_ao/demos/amlogic/driver/eth/eth.c
new file mode 100644
index 0000000..57c9dff
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/eth/eth.c
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2014-2018 Amlogic, Inc. All rights reserved.
+ *
+ * All information contained herein is Amlogic confidential.
+ *
+ * This software is provided to you pursuant to Software License Agreement
+ * (SLA) with Amlogic Inc ("Amlogic"). This software may be used
+ * only in accordance with the terms of this agreement.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification is strictly prohibited without prior written permission from
+ * Amlogic.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER 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, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * eth wol driver
+ */
+#include "FreeRTOS.h"
+#include "suspend.h"
+#include "interrupt.h"
+#include "mailbox-api.h"
+#include "eth.h"
+
+uint32_t eth_wol_flag = 0;
+uint32_t ethIrq;
+void eth_handler(void)
+{
+	uint32_t buf[4] = {0};
+
+	buf[0] = ETH_PMT_WAKEUP;
+	STR_Wakeup_src_Queue_Send_FromISR(buf);
+	DisableIrq(ethIrq);
+}
+
+void vETHInit(uint32_t ulIrq,function_ptr_t handler)
+{
+	ethIrq = ulIrq;
+	RegisterIrq(ulIrq, 2, handler);
+}
+
+void vETHDeint(void)
+{
+	DisableIrq(ethIrq);
+	UnRegisterIrq(ethIrq);
+}
+
+int eth_deinit = 0;
+void eth_handler_t5(void)
+{
+	uint32_t buf[4] = {0};
+	if (eth_deinit == 0) {
+		buf[0] = ETH_PMT_WAKEUP;
+		STR_Wakeup_src_Queue_Send_FromISR(buf);
+		DisableIrq(ethIrq);
+	} else {
+		eth_deinit = 0;
+	}
+}
+
+void vETHDeint_t5(void)
+{
+	eth_deinit = 1;
+	DisableIrq(ethIrq);
+	UnRegisterIrq(ethIrq);
+}
+
+int get_ETHWol_flag(void)
+{
+	return eth_wol_flag;
+}
+
+static void *prvETHSetWol(void *msg)
+{
+	eth_wol_flag = *(u32 *)msg;
+	return NULL;
+}
+
+void vETHMailboxCallback(void)
+{
+	int32_t ret;
+	ret = xInstallRemoteMessageCallbackFeedBack(AOREE_CHANNEL, MBX_CMD_SET_ETHERNET_WOL,
+		prvETHSetWol, 1);
+	if (ret == MBOX_CALL_MAX) {
+		printf("mailbox cmd 0x%x register fail\n");
+		return;
+	}
+}
\ No newline at end of file
diff --git a/bl30/src_ao/demos/amlogic/driver/get_version/build.mk b/bl30/src_ao/demos/amlogic/driver/get_version/build.mk
new file mode 100644
index 0000000..f46fa06
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/get_version/build.mk
@@ -0,0 +1,26 @@
+ #
+ #  Copyright (C) 2014-2018 Amlogic, Inc. All rights reserved.
+ #
+ #  All information contained herein is Amlogic confidential.
+ #
+ #  This software is provided to you pursuant to Software License Agreement
+ #  (SLA) with Amlogic Inc ("Amlogic"). This software may be used
+ #  only in accordance with the terms of this agreement.
+ #
+ #  Redistribution and use in source and binary forms, with or without
+ #  modification is strictly prohibited without prior written permission from
+ #  Amlogic.
+ #
+ #  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ #  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ #  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ #  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ #  OWNER 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, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ #
+get_version-y = version.o
diff --git a/bl30/src_ao/demos/amlogic/driver/get_version/version.c b/bl30/src_ao/demos/amlogic/driver/get_version/version.c
new file mode 100644
index 0000000..75a22e8
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/get_version/version.c
@@ -0,0 +1,10 @@
+#include "version.h"
+#include "myprintf.h"
+
+int version(void)
+{
+	printf("AOCPU image version='%s'\n", VERSION);
+
+	return 0;
+}
+
diff --git a/bl30/src_ao/demos/amlogic/driver/glb_timer/build.mk b/bl30/src_ao/demos/amlogic/driver/glb_timer/build.mk
new file mode 100644
index 0000000..4ed2324
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/glb_timer/build.mk
@@ -0,0 +1,26 @@
+#
+#  Copyright (C) 2014-2018 Amlogic, Inc. All rights reserved.
+#
+#  All information contained herein is Amlogic confidential.
+#
+#  This software is provided to you pursuant to Software License Agreement
+#  (SLA) with Amlogic Inc ("Amlogic"). This software may be used
+#  only in accordance with the terms of this agreement.
+#
+#  Redistribution and use in source and binary forms, with or without
+#  modification is strictly prohibited without prior written permission from
+#  Amlogic.
+#
+#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#  OWNER 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, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+glb_timer-y = glb_timer.o
diff --git a/bl30/src_ao/demos/amlogic/driver/glb_timer/glb_timer.c b/bl30/src_ao/demos/amlogic/driver/glb_timer/glb_timer.c
new file mode 100644
index 0000000..324f8b7
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/glb_timer/glb_timer.c
@@ -0,0 +1,358 @@
+/*
+ * Copyright (C) 2014-2021 Amlogic, Inc. All rights reserved.
+ *
+ * All information contained herein is Amlogic confidential.
+ *
+ * This software is provided to you pursuant to Software License Agreement
+ * (SLA) with Amlogic Inc ("Amlogic"). This software may be used
+ * only in accordance with the terms of this agreement.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification is strictly prohibited without prior written permission from
+ * Amlogic.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER 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, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "FreeRTOS.h"
+#include <common.h>
+//#include <printf.h>
+#include <stdint.h>
+#include <task.h>
+#include <gpio.h>
+#include "util.h"
+#include "projdefs.h"
+#include "portmacro.h"
+#include "glb_timer.h"
+#include "global_timer.h"
+//#include "hwspinlock_new.h"
+
+#ifdef HWSPINLOCK_ID_GLB_TIMER
+static  hwspinlock_lock_t *hwlock;
+#endif
+
+static inline void prvGlbTimerUpdateBit(uint32_t addr, uint32_t mask,
+					uint32_t val)
+{
+	REG32_UPDATE_BITS(addr, mask, val);
+}
+
+static inline int prvGlbTimerRead(uint32_t addr)
+{
+	return REG32(addr);
+}
+
+static inline void prvGlbTimerWrite(uint32_t addr, uint32_t ulvalue)
+{
+	REG32((unsigned long)(addr)) = ulvalue;
+}
+
+static inline void vGlbTimerTopCtlReset(void)
+{
+	prvGlbTimerUpdateBit(TOP_CTRL_BASE + TOP_CTRL0, BIT(2), BIT(2));
+	prvGlbTimerUpdateBit(TOP_CTRL_BASE + TOP_CTRL0, BIT(2), 0);
+}
+
+/******************************get counter function***************************/
+static inline void vGlbTimerTopCtlClear(void)
+{
+	prvGlbTimerUpdateBit(TOP_CTRL_BASE + TOP_CTRL0, BIT(3), BIT(3));
+}
+
+static inline void vGlbTimerTopCtlHold(void)
+{
+	prvGlbTimerUpdateBit(TOP_CTRL_BASE + TOP_CTRL0, BIT(1), BIT(1));
+}
+
+static inline uint64_t prvGlbTimerGetCounter(void)
+{
+	uint32_t ulTS_L;
+	uint32_t ulTS_H;
+	uint64_t ullTS;
+
+	ulTS_L = prvGlbTimerRead(TOP_CTRL_BASE + TOP_TS0);
+	ulTS_H = prvGlbTimerRead(TOP_CTRL_BASE + TOP_TS1);
+
+	ullTS = ulTS_H;
+
+	return (ullTS << 32) | ulTS_L;
+}
+
+/*
+ * ullGlobalTimerGlobalSnapshot
+ * return the global timer 64 bit snapshot value
+ */
+uint64_t ullGlobalTimerGlobalSnapshot(void)
+{
+	uint64_t ts;
+#ifdef  HWSPINLOCK_ID_GLB_TIMER
+	if (hwlock) {
+		vHwspinLock_get(hwlock, HWSPINLOCK_ID_GLB_TIMER);
+		ts = prvGlbTimerGetCounter();
+		vHwspinLock_release(hwlock, HWSPINLOCK_ID_GLB_TIMER);
+	} else {
+		ts = prvGlbTimerGetCounter();
+	}
+#else
+		ts = prvGlbTimerGetCounter();
+#endif
+
+	return ts;
+}
+
+void vGlobalTimerReset(void)
+{
+	vGlbTimerTopCtlReset();
+}
+
+/******************************input function*********************************/
+static inline void prvGlbTimerTrigSrcEnable(uint8_t ucSrc, uint8_t on)
+{
+	on = on;
+	prvGlbTimerUpdateBit(TRIG_SRC_BASE + SRC_OFFSET(TRIG_SRC0_CTRL0, ucSrc),
+			     BIT(31), BIT(31));
+}
+
+static inline void prvGlbTimerTrigSrcConfig(uint8_t ucSrc,
+					enum MesonGlbSrcSelFlag type)
+{
+	uint32_t ulmask;
+	uint32_t ulvalue;
+
+	ulmask = GENMASK(31, 29) | GENMASK(17, 16);
+	ulvalue = GENMASK(31, 30) |
+		  ((type & GENMASK(1, 0)) << 16) |
+		  ((type & BIT(2)) << 29);
+
+	prvGlbTimerUpdateBit(TRIG_SRC_BASE + SRC_OFFSET(TRIG_SRC0_CTRL0, ucSrc),
+			     ulmask, ulvalue);
+}
+
+static inline void prvGlbTimerTrigSrcOneShot(uint8_t ucSrc)
+{
+	prvGlbTimerUpdateBit(TRIG_SRC_BASE + SRC_OFFSET(TRIG_SRC0_CTRL0, ucSrc),
+			     BIT(1), BIT(1));
+}
+
+static inline void prvGlbTimerTrigSrcSWTrig(uint8_t ucSrc)
+{
+	prvGlbTimerUpdateBit(TRIG_SRC_BASE + SRC_OFFSET(TRIG_SRC0_CTRL0, ucSrc),
+			     BIT(0), BIT(0));
+}
+
+static inline uint64_t prvGlbTimerTrigSrcGetCount(uint8_t ucSrc)
+{
+	uint32_t ulTS_L;
+	uint32_t ulTS_H;
+	uint64_t ullTS;
+
+	ulTS_L = prvGlbTimerRead(TRIG_SRC_BASE + SRC_OFFSET(TRIG_SRC0_TS_L,
+				 ucSrc));
+	ulTS_H = prvGlbTimerRead(TRIG_SRC_BASE + SRC_OFFSET(TRIG_SRC0_TS_H,
+				 ucSrc));
+
+	ullTS = ulTS_H;
+
+	return (ullTS << 32) | ulTS_L;
+}
+
+/*
+ * ulGlobalTimerInputGPIOConfigure
+ * @ucSrc: Triger Source can be found in
+ * lib/third_party/amlogic/include/drivers/global_timer.h note that this number
+ * and GPIO
+ * line number should keep mapping 0-31 <--> GLBT_GPIO0_IRQ -- GLBT_GPIO31_IRQ
+ * @MesonGlbSrcSelFlag: Trigger type can be found in
+ * lib/third_party/amlogic/include/drivers/global_timer.h
+ * @returns: return 0 for success or -EINVAL fail.
+ */
+int uGlobalTimerInputGPIOConfigure(uint8_t ucSrc, enum MesonGlbSrcSelFlag type)
+{
+	if (type > TRIG_ONE_SHOT)
+		return -EINVAL;
+
+	if (ucSrc < GLBT_GPIO0_IRQ || ucSrc > GLBT_GPIO31_IRQ)
+		return -EINVAL;
+
+	prvGlbTimerTrigSrcConfig(ucSrc, type);
+	return 0;
+}
+
+
+/*
+ * ullGlobalTimerInputGPIOGetSnapshot
+ * @ucSrc: Triger Source can be found in
+ * lib/third_party/amlogic/include/drivers/global_timer.h note that this
+ * number and GPIO
+ * line number should keep mapping 0-31 <--> GLBT_GPIO0_IRQ -- GLBT_GPIO31_IRQ
+ * @retruns:the global timer 64 bit snapshot value
+ */
+uint64_t ullGlobalTimerInputGPIOGetSnapshot(uint8_t ucSrc)
+{
+	return prvGlbTimerTrigSrcGetCount(ucSrc);
+}
+
+/******************************output function*********************************/
+static inline void prvGlbTimerOutputEnable(uint8_t ucSrc, uint8_t ucOn)
+{
+	prvGlbTimerUpdateBit(OUTPUT_BASE + SRC_OFFSET(OUTPUT_CTRL0, ucSrc),
+			     BIT(31), ucOn << 31);
+}
+
+static inline void prvGlbTimerOutputSWStart(uint8_t ucSrc)
+{
+	prvGlbTimerUpdateBit(OUTPUT_BASE + SRC_OFFSET(OUTPUT_CTRL0, ucSrc),
+			     BIT(1), BIT(1));
+}
+
+static inline void prvGlbTimerOutputSWStop(uint8_t ucSrc)
+{
+	prvGlbTimerUpdateBit(OUTPUT_BASE + SRC_OFFSET(OUTPUT_CTRL0, ucSrc),
+			     BIT(0), BIT(0));
+}
+
+static inline void prvGlbTimerOutputForceOutput(uint8_t ucSrc, uint8_t level)
+{
+	prvGlbTimerUpdateBit(OUTPUT_BASE + SRC_OFFSET(OUTPUT_CTRL0, ucSrc),
+			     GENMASK(17, 16), BIT(17) | (level << 16));
+	prvGlbTimerUpdateBit(OUTPUT_BASE + SRC_OFFSET(OUTPUT_CTRL0, ucSrc),
+			     GENMASK(19, 18), BIT(19));
+}
+
+static inline void prvGlbTimerOutputForceInput(uint8_t ucSrc)
+{
+	prvGlbTimerUpdateBit(OUTPUT_BASE + SRC_OFFSET(OUTPUT_CTRL0, ucSrc),
+			     GENMASK(19, 18), GENMASK(19, 18));
+}
+
+static inline void prvGlbTimerOutputPulseConfig(uint8_t ucSrc,
+						uint8_t ucPulsePolarity,
+						uint32_t ulPulseWith,
+						uint32_t ulPulseInterval,
+						uint32_t ulPulseNum)
+{
+	if (ucPulsePolarity)
+		prvGlbTimerUpdateBit(OUTPUT_BASE +
+				     SRC_OFFSET(OUTPUT_CTRL0, ucSrc),
+				     BIT(28), BIT(28));
+
+	prvGlbTimerWrite(OUTPUT_BASE + SRC_OFFSET(OUTPUT_PULSE_WDITH, ucSrc),
+			 ulPulseWith);
+	prvGlbTimerWrite(OUTPUT_BASE + SRC_OFFSET(OUTPUT_INTERVAL, ucSrc),
+			ulPulseInterval);
+	prvGlbTimerWrite(OUTPUT_BASE + SRC_OFFSET(OUTPUT_STOP_NUM, ucSrc),
+			ulPulseNum);
+}
+
+static inline void prvGlbTimerOutputSetExpire(uint8_t ucSrc, uint64_t ts)
+{
+	uint32_t ts_l;
+	uint32_t ts_h;
+
+	ts_l = ts & GENMASK(31, 0);
+	ts_h = (ts >> 32) & GENMASK(31, 0);
+
+	prvGlbTimerWrite(OUTPUT_BASE + SRC_OFFSET(OUTPUT_EXPIRES_TS_L, ucSrc),
+			 ts_l);
+	prvGlbTimerWrite(OUTPUT_BASE + SRC_OFFSET(OUTPUT_EXPIRES_TS_H, ucSrc),
+			 ts_h);
+}
+
+/* OUTPUT Source Select routing gen_n to rt_gpio_n */
+static inline void prvGlbTimerSetOutputSrc(uint8_t ucSrc, uint8_t gen)
+{
+	prvGlbTimerUpdateBit(OUTPUT_SEL_BASE + (ucSrc << 2),
+			     BIT(31) | GENMASK(3, 0),
+			     BIT(31) | gen);
+}
+
+/*
+ * uGlobalTimerOutputGPIOSetup
+ * @ucSrc: Select output source, can be found in
+ * lib/third_party/amlogic/include/drivers/global_timer.h
+ * @ucOneShot: if true then one shot pulse or continuous macro can be found
+ * in /lib/third_party/amlogic/include/driver/global_timer.h
+ * @uPulseWith: pulse with in global timer clock cycles
+ * @uInterval: pulse interval in global timer cycles
+ * @ucInitval: decides the initial value of the gpio state and the pulse
+ * would be inverse of that init value
+ * @retruns: 0 on success and error code on failure
+ */
+int uGlobalTimerOutputGPIOSetup(uint8_t ucSrc, uint8_t ucOneshot,
+				uint32_t uPulseWith, uint32_t uInterval,
+				uint8_t ucInitVal)
+{
+	uint32_t ureg;
+
+	if (ucSrc > GLBT_OUTPUT_GPIO15)
+		return -EINVAL;
+
+	/* reset generator */
+	for (ureg = 0; ureg < (OUTPUT_ST1 >> 2); ureg++)
+		prvGlbTimerUpdateBit(OUTPUT_BASE + SRC_OFFSET(ureg << 2, ucSrc),
+				     BIT(0), BIT(0));
+
+	/* init val */
+	if (ucInitVal)
+		prvGlbTimerUpdateBit(OUTPUT_BASE +
+				     SRC_OFFSET(OUTPUT_CTRL0, ucSrc), BIT(28),
+				     BIT(28));
+
+	/* config pulse type */
+	prvGlbTimerWrite(OUTPUT_BASE + SRC_OFFSET(OUTPUT_PULSE_WDITH, ucSrc),
+			 uPulseWith);
+	prvGlbTimerWrite(OUTPUT_BASE + SRC_OFFSET(OUTPUT_INTERVAL, ucSrc),
+			 uInterval);
+	prvGlbTimerWrite(OUTPUT_BASE + SRC_OFFSET(OUTPUT_STOP_NUM, ucSrc), 0);
+
+	if (ucOneshot)
+		prvGlbTimerUpdateBit(OUTPUT_BASE +
+				     SRC_OFFSET(OUTPUT_CTRL0, ucSrc),
+				     BIT(3), BIT(3));
+	else
+		prvGlbTimerUpdateBit(OUTPUT_BASE +
+				     SRC_OFFSET(OUTPUT_CTRL0, ucSrc),
+				     BIT(2), BIT(2));
+	return 0;
+}
+
+
+/*
+ * uGlobalTimerOutputStart
+ * @ucSrcn: Select output source, must same as setup api can be found in
+ * lib/third_party/amlogic/include/drivers/global_timer.h
+ * @ullexpires: the 64 bit future expires value for when the pulse must start
+ * @returns: 0 for success or -EINVAL for fail
+ */
+int uGlobalTimerOutputStart(uint8_t ucSrcn, uint64_t ullexpires)
+{
+	if (ucSrcn > GLBT_OUTPUT_GPIO15)
+		return -EINVAL;
+
+	prvGlbTimerSetOutputSrc(ucSrcn, ucSrcn);
+	prvGlbTimerOutputSetExpire(ucSrcn, ullexpires);
+	prvGlbTimerOutputEnable(ucSrcn, 1);
+
+	return 0;
+}
+
+/*
+ * vGlobalTimerHardwareLockInit
+ * Init hwspinlock must be used at main.c before read counter
+ */
+void vGlobalTimerHardwareLockInit(void)
+{
+#if HWSPINLOCK_ID_GLB_TIMER
+	if (!hwlock)
+		vHwspinLock_init(&hwlock, HWSPINLOCK_ID_GLB_TIMER, NULL);
+#endif
+}
diff --git a/bl30/src_ao/demos/amlogic/driver/glb_timer/glb_timer.h b/bl30/src_ao/demos/amlogic/driver/glb_timer/glb_timer.h
new file mode 100644
index 0000000..934ba6b
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/glb_timer/glb_timer.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2014-2021 Amlogic, Inc. All rights reserved.
+ *
+ * All information contained herein is Amlogic confidential.
+ *
+ * This software is provided to you pursuant to Software License Agreement
+ * (SLA) with Amlogic Inc ("Amlogic"). This software may be used
+ * only in accordance with the terms of this agreement.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification is strictly prohibited without prior written permission from
+ * Amlogic.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER 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, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include  "register.h"
+
+#define DRIVER_NAME     "meson_glb_timer"
+
+#define TOP_CTRL_BASE		GLOBAL_TOP_CTRL0
+#define TRIG_SRC_BASE		GLOBAL_TRIG_SRC0_CTRL0
+#define OUTPUT_BASE		GLOBAL_GPIO_OUT0_CTRL0
+#define OUTPUT_SEL_BASE		GLOBAL_GPIO_OUT0_SEL
+
+#define SRC_OFFSET(REG, SRCN)   ((REG) + (((SRCN) * 0x08) << 2))
+
+struct meson_glb_timer;
+
+enum {
+        TOP_CTRL0                       = 0x00 << 2,
+        TOP_CTRL1                       = 0x01 << 2,
+        TOP_CTRL2                       = 0x02 << 2,
+        TOP_CTRL3                       = 0x03 << 2,
+        TOP_CTRL4                       = 0x04 << 2,
+        TOP_TS0                         = 0x08 << 2,
+        TOP_TS1                         = 0x09 << 2,
+};
+
+enum {
+        TRIG_SRC0_CTRL0                 = 0x00 << 2,
+        TRIG_SRC0_TS_L                  = 0x01 << 2,
+        TRIG_SRC0_TS_H                  = 0x02 << 2,
+};
+
+enum {
+        OUTPUT_CTRL0                    = 0x00 << 2,
+        OUTPUT_PULSE_WDITH              = 0x01 << 2,
+        OUTPUT_INTERVAL                 = 0x02 << 2,
+        OUTPUT_STOP_NUM                 = 0x03 << 2,
+        OUTPUT_EXPIRES_TS_L             = 0x04 << 2,
+        OUTPUT_EXPIRES_TS_H             = 0x05 << 2,
+        OUTPUT_ST0                      = 0x06 << 2,
+        OUTPUT_ST1                      = 0x07 << 2,
+};
+
+enum {
+        RESET_TIMER                     = 0x1,
+        HOLD_COUNTER                    = 0x2,
+        CLEAR_TIMER                     = 0x3,
+        SET_FORCE_COUNT                 = 0x4,
+};
+
+enum {
+        LOW                             = 0,
+        HIGH                            = 1,
+};
+
+struct meson_glb_timer {
+
+};
diff --git a/bl30/src_ao/demos/amlogic/driver/gpio/build.mk b/bl30/src_ao/demos/amlogic/driver/gpio/build.mk
new file mode 100644
index 0000000..ba56a34
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/gpio/build.mk
@@ -0,0 +1,26 @@
+#
+#  Copyright (C) 2014-2018 Amlogic, Inc. All rights reserved.
+#
+#  All information contained herein is Amlogic confidential.
+#
+#  This software is provided to you pursuant to Software License Agreement
+#  (SLA) with Amlogic Inc ("Amlogic"). This software may be used
+#  only in accordance with the terms of this agreement.
+#
+#  Redistribution and use in source and binary forms, with or without
+#  modification is strictly prohibited without prior written permission from
+#  Amlogic.
+#
+#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#  OWNER 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, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+gpio-y = gpio.o gpio_irq.o gpio_${SOC}_plat.o
diff --git a/bl30/src_ao/demos/amlogic/driver/gpio/gpio.c b/bl30/src_ao/demos/amlogic/driver/gpio/gpio.c
new file mode 100644
index 0000000..312eb52
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/gpio/gpio.c
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) 2014-2018 Amlogic, Inc. All rights reserved.
+ *
+ * All information contained herein is Amlogic confidential.
+ *
+ * This software is provided to you pursuant to Software License Agreement
+ * (SLA) with Amlogic Inc ("Amlogic"). This software may be used
+ * only in accordance with the terms of this agreement.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification is strictly prohibited without prior written permission from
+ * Amlogic.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER 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, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * gpio driver
+ */
+#include "FreeRTOS.h"
+#include <register.h>
+#include <common.h>
+#include <task.h>
+#include <gpio.h>
+#include "util.h"
+#include "projdefs.h"
+#include "gpio_drv.h"
+#include "portmacro.h"
+
+#define DRIVER_NAME "gpio"
+
+extern unsigned int xPortIsIsrContext(void);
+static void prvEnterCritical(UBaseType_t *uxIsr)
+{
+	if (xPortIsIsrContext())
+		*uxIsr = taskENTER_CRITICAL_FROM_ISR();
+	else {
+		taskENTER_CRITICAL();
+		*uxIsr = 0;
+	}
+};
+
+static void prvExitCritical(UBaseType_t uxSaveIsr)
+{
+	if (xPortIsIsrContext())
+		taskEXIT_CRITICAL_FROM_ISR(uxSaveIsr);
+	else {
+		taskEXIT_CRITICAL();
+		(void)uxSaveIsr;
+	}
+};
+
+static inline void prvGpioRegWrite(uint32_t addr,
+				   uint32_t mask, uint32_t val)
+{
+	UBaseType_t uxSavedIsr;
+
+	prvEnterCritical(&uxSavedIsr);
+	REG32_UPDATE_BITS(addr, mask, val);
+	prvExitCritical(uxSavedIsr);
+}
+
+static inline void prvGpioCalcRegAndBit(const GpioBank_t *bk,
+					uint8_t offset,
+					enum GpioRegType regType,
+					uint16_t *reg, uint8_t *bit)
+{
+	*reg = bk->regs[regType].reg << 2;
+	*bit = bk->regs[regType].bit + offset;
+}
+
+static inline void prvGpioGetBankAndOffset(uint16_t gpio,
+					   const GpioBank_t **bk,
+					   uint8_t *off)
+{
+	const GpioBank_t *gpk;
+
+	gpk = pGetGpioBank();
+	*bk = &gpk[gpio >> 5];
+	*off = gpio % 32;
+}
+
+int xGpioSetDir(uint16_t gpio, enum GpioDirType dir)
+{
+	uint16_t reg;
+	uint8_t bit;
+	uint8_t offset;
+	const GpioBank_t *bk;
+
+	if (dir >= GPIO_DIR_INVALID) {
+		iprintf("%s: invalid DIR [OUT=0, IN=1]: %d\n", DRIVER_NAME,
+			dir);
+		return -pdFREERTOS_ERRNO_EINVAL;
+	}
+
+	prvGpioGetBankAndOffset(gpio, &bk, &offset);
+
+	prvGpioCalcRegAndBit(bk, offset, REG_DIR, &reg, &bit);
+
+	prvGpioRegWrite(bk->domain->rGpio + reg, BIT(bit), dir ? BIT(bit) : 0);
+
+	return 0;
+}
+
+int xGpioSetValue(uint16_t gpio, enum GpioOutLevelType level)
+{
+	uint16_t reg;
+	uint8_t bit;
+	uint8_t offset;
+	const GpioBank_t *bk;
+
+	if (level >= GPIO_LEVEL_INVALID) {
+		iprintf("%s: invalid output level [LOW=1, HIGH=0]: %d\n",
+			DRIVER_NAME, level);
+		return -pdFREERTOS_ERRNO_EINVAL;
+	}
+
+	prvGpioGetBankAndOffset(gpio, &bk, &offset);
+
+	prvGpioCalcRegAndBit(bk, offset, REG_OUT, &reg, &bit);
+
+	prvGpioRegWrite(bk->domain->rGpio + reg, BIT(bit),
+			level ? BIT(bit) : 0);
+
+	return 0;
+}
+
+int xGpioGetValue(uint16_t gpio)
+{
+	uint16_t reg;
+	uint8_t bit;
+	uint8_t offset;
+	const GpioBank_t *bk;
+
+	prvGpioGetBankAndOffset(gpio, &bk, &offset);
+
+	prvGpioCalcRegAndBit(bk, offset, REG_IN, &reg, &bit);
+
+	return !!(REG32((unsigned long)bk->domain->rGpio + reg) & BIT(bit));
+}
+
+int xPinconfSet(uint16_t gpio, uint32_t flags)
+{
+	uint16_t reg;
+	uint8_t bit;
+	uint8_t offset;
+	uint8_t ds_value = 0;
+	const GpioBank_t *bk;
+	const GpioRegDesc_t *desc;
+
+	prvGpioGetBankAndOffset(gpio, &bk, &offset);
+
+	prvGpioCalcRegAndBit(bk, offset, REG_PULLEN, &reg, &bit);
+
+	if (flags & PINF_CONFIG_BIAS_DISABLE) {
+		prvGpioRegWrite(bk->domain->rPullen + reg, BIT(bit), 0);
+	} else if (flags &
+		   (PINF_CONFIG_BIAS_PULL_UP | PINF_CONFIG_BIAS_PULL_DOWN)) {
+		prvGpioRegWrite(bk->domain->rPullen + reg, BIT(bit), BIT(bit));
+
+		prvGpioCalcRegAndBit(bk, offset, REG_PULL, &reg, &bit);
+		if (flags & PINF_CONFIG_BIAS_PULL_UP)
+			prvGpioRegWrite(bk->domain->rPull + reg, BIT(bit),
+					BIT(bit));
+		else
+			prvGpioRegWrite(bk->domain->rPull + reg, BIT(bit), 0);
+	}
+
+	if ((flags & PINF_CONFIG_DRV_MASK) && &bk->regs[REG_DRV] != 0) {
+
+		prvGpioCalcRegAndBit(bk, offset, REG_DRV, &reg, &bit);
+		desc = &bk->regs[REG_DRV];
+
+		reg = desc->reg + ((desc->bit + (offset << 1)) >> 5);
+		bit = (desc->bit + (offset << 1)) % 32;
+
+		if (flags & PINF_CONFIG_DRV_STRENGTH_0)
+			ds_value = 0;
+		else if (flags & PINF_CONFIG_DRV_STRENGTH_1)
+			ds_value = 1;
+		else if (flags & PINF_CONFIG_DRV_STRENGTH_2)
+			ds_value = 2;
+		else if (flags & PINF_CONFIG_DRV_STRENGTH_3)
+			ds_value = 3;
+
+		prvGpioRegWrite(bk->domain->rDrv + (reg << 2), 0x3 << bit,
+				ds_value << bit);
+	}
+
+	return 0;
+}
+
+int xPinmuxSet(uint16_t gpio, enum PinMuxType func)
+{
+	uint16_t reg;
+	uint8_t bit;
+	uint8_t offset;
+	const GpioBank_t *bk;
+	const GpioRegDesc_t *desc;
+
+	if (func >= PIN_FUNC_INVALID) {
+		iprintf("%s: invalid pin Function [0 - %d]: %d\n",
+			DRIVER_NAME, PIN_FUNC_INVALID - 1, func);
+		return -pdFREERTOS_ERRNO_EINVAL;
+	}
+
+	prvGpioGetBankAndOffset(gpio, &bk, &offset);
+	desc = &bk->regs[REG_MUX];
+
+	reg = desc->reg + ((desc->bit + (offset << 2)) >> 5);
+	bit = (desc->bit + (offset << 2)) % 32;
+
+	prvGpioRegWrite(bk->domain->rMux + (reg << 2), 0xf << bit, func << bit);
+
+	return 0;
+}
diff --git a/bl30/src_ao/demos/amlogic/driver/gpio/gpio_a5_plat.c b/bl30/src_ao/demos/amlogic/driver/gpio/gpio_a5_plat.c
new file mode 100644
index 0000000..448770f
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/gpio/gpio_a5_plat.c
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2014-2018 Amlogic, Inc. All rights reserved.
+ *
+ * All information contained herein is Amlogic confidential.
+ *
+ * This software is provided to you pursuant to Software License Agreement
+ * (SLA) with Amlogic Inc ("Amlogic"). This software may be used
+ * only in accordance with the terms of this agreement.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification is strictly prohibited without prior written permission from
+ * Amlogic.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER 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, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * gpio driver platform data
+ */
+#include "FreeRTOS.h"
+#include <register.h>
+#include <common.h>
+#include <gpio.h>
+#include "util.h"
+#include "projdefs.h"
+#include "gpio_drv.h"
+#include "gpio_irq.h"
+#include "portmacro.h"
+
+/* gpio irq controller */
+#define IRQ_GPIO0_NUM 10
+#define IRQ_GPIO1_NUM 11
+#define IRQ_GPIO2_NUM 12
+#define IRQ_GPIO3_NUM 13
+#define IRQ_GPIO4_NUM 14
+#define IRQ_GPIO5_NUM 15
+#define IRQ_GPIO6_NUM 16
+#define IRQ_GPIO7_NUM 17
+
+#define REG_PIN_SC2_SEL			0x04
+#define REG_EDGE_POL_EXTR		0x1c
+#define REG_EDGE_POL_MASK_SC2(x)			\
+	({typeof(x) _x = (x); BIT(_x) | BIT(12 + (_x)); })
+#define GPIO_IRQ_FILTER_SHIFT(x)	(((x) % 2 == 0) ? 8 : 24)
+#define GPIO_IRQ_POL_SHIFT(x)		(BIT(0 + (x)))
+#define GPIO_IRQ_EDGE_SHIFT(x)		(BIT(12 + (x)))
+#define GPIO_IRQ_BOTH_SHIFT(x)		(BIT(0 + (x)))
+
+static const GpioDomain_t eeDomain = {
+	.name = "EE",
+	.rPullen = PADCTRL_GPIOZ_I,
+	.rPull = PADCTRL_GPIOZ_I,
+	.rGpio = PADCTRL_GPIOZ_I,
+	.rMux = PADCTRL_PIN_MUX_REG0,
+	.rDrv = PADCTRL_GPIOZ_I,
+};
+
+static const GpioBank_t gpioBanks[BANK_NUM_MAX] = {
+			  /* pullen    pull	 dir       out       in        mux */
+	BANK("E", &eeDomain, 0x43, 0, 0x44, 0, 0x42, 0, 0x41, 0, 0x40, 0, 0x12,
+	     0, 0x47, 0),
+	BANK("H", &eeDomain, 0x73, 0, 0x74, 0, 0x72, 0, 0x71, 0, 0x70, 0, 0x13,
+	     0, 0x77, 0),
+	BANK("D", &eeDomain, 0x33, 0, 0x34, 0, 0x32, 0, 0x31, 0, 0x30, 0, 0x10,
+	     0, 0x37, 0),
+	BANK("B", &eeDomain, 0x63, 0, 0x64, 0, 0x62, 0, 0x61, 0, 0x60, 0, 0x00,
+	     0, 0x67, 0),
+	BANK("X", &eeDomain, 0x13, 0, 0x14, 0, 0x12, 0, 0x11, 0, 0x10, 0, 0x03,
+	     0, 0x17, 0),
+	BANK("C", &eeDomain, 0x53, 0, 0x54, 0, 0x52, 0, 0x51, 0, 0x50, 0, 0x09,
+	     0, 0x57, 0),
+	BANK("T", &eeDomain, 0x23, 0, 0x24, 0, 0x22, 0, 0x21, 0, 0x20, 0, 0x0b,
+	     0, 0x27, 0),
+	BANK("Z", &eeDomain, 0x03, 0, 0x04, 0, 0x02, 0, 0x01, 0, 0x00, 0, 0x06,
+	     0, 0x07, 0),
+	BANK("TEST_N", &eeDomain, 0x83, 0, 0x84, 0, 0x82, 0, 0x81, 0, 0x80, 0,
+	     0x0f, 0, 0x87, 0),
+};
+
+static ParentIRQDesc_t eeIRQs[] = {
+	[GPIO_EE_IRQ_L0] = PARENT_IRQ_BK(NULL, 0, GPIO_INVALID, IRQ_GPIO0_NUM),
+	[GPIO_EE_IRQ_L1] = PARENT_IRQ_BK(NULL, 0, GPIO_INVALID, IRQ_GPIO1_NUM),
+	[GPIO_EE_IRQ_L2] = PARENT_IRQ_BK(NULL, 0, GPIO_INVALID, IRQ_GPIO2_NUM),
+	[GPIO_EE_IRQ_L3] = PARENT_IRQ_BK(NULL, 0, GPIO_INVALID, IRQ_GPIO3_NUM),
+	[GPIO_EE_IRQ_L4] = PARENT_IRQ_BK(NULL, 0, GPIO_INVALID, IRQ_GPIO4_NUM),
+	[GPIO_EE_IRQ_L5] = PARENT_IRQ_BK(NULL, 0, GPIO_INVALID, IRQ_GPIO5_NUM),
+	[GPIO_EE_IRQ_L6] = PARENT_IRQ_BK(NULL, 0, GPIO_INVALID, IRQ_GPIO6_NUM),
+	[GPIO_EE_IRQ_L7] = PARENT_IRQ_BK(NULL, 0, GPIO_INVALID, IRQ_GPIO7_NUM),
+};
+
+static const GpioIRQBank_t irqBanks[BANK_NUM_MAX] = {
+	GPIO_IRQ_BK("E", 25, eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("H", 27, eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("D", 32, eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("B", 0, eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("X", 62, eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("C", 14, eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("T", 48, eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("Z", 82, eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("TEST_N", 98, eeIRQs, ARRAY_SIZE(eeIRQs)),
+};
+
+const GpioBank_t *pGetGpioBank(void)
+{
+	return gpioBanks;
+}
+
+const GpioIRQBank_t *pGetGpioIrqBank(void)
+{
+	return irqBanks;
+}
+
+void prvGpioPlatIrqSetup(uint16_t irqNum, uint8_t line, uint32_t flags)
+{
+	uint32_t val = 0;
+	uint32_t reg_offset = 0;
+	uint16_t bit_offset = 0;
+
+	bit_offset = ((line % 2) == 0) ? 0 : 16;
+	reg_offset = REG_PIN_SC2_SEL + ((line / 2) << 2);
+
+	/* clear both edge */
+	REG32_UPDATE_BITS(GPIO_EE_IRQ_BASE + REG_EDGE_POL_EXTR,
+			  GPIO_IRQ_BOTH_SHIFT(line), 0);
+
+	/* set filter */
+	REG32_UPDATE_BITS(GPIO_EE_IRQ_BASE + reg_offset,
+			  0x7 << GPIO_IRQ_FILTER_SHIFT(line),
+			  0x7 << GPIO_IRQ_FILTER_SHIFT(line));
+
+	/* select trigger pin */
+	REG32_UPDATE_BITS(GPIO_EE_IRQ_BASE + reg_offset,
+			  0x7f << bit_offset, irqNum << bit_offset);
+
+	/* set trigger both type */
+	if (flags & IRQF_TRIGGER_BOTH) {
+		val |= GPIO_IRQ_BOTH_SHIFT(line);
+		REG32_UPDATE_BITS(GPIO_EE_IRQ_BASE + REG_EDGE_POL_EXTR,
+				  GPIO_IRQ_BOTH_SHIFT(line), val);
+		return;
+	}
+
+	/* set trigger single edge or level  type */
+	if (flags & (IRQF_TRIGGER_LOW | IRQF_TRIGGER_FALLING))
+		val |= GPIO_IRQ_POL_SHIFT(line);
+
+	if (flags & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING))
+		val |= GPIO_IRQ_EDGE_SHIFT(line);
+
+	REG32_UPDATE_BITS(GPIO_EE_IRQ_BASE, REG_EDGE_POL_MASK_SC2(line), val);
+
+}
+
diff --git a/bl30/src_ao/demos/amlogic/driver/gpio/gpio_drv.h b/bl30/src_ao/demos/amlogic/driver/gpio/gpio_drv.h
new file mode 100644
index 0000000..4ddf6b4
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/gpio/gpio_drv.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2014-2018 Amlogic, Inc. All rights reserved.
+ *
+ * All information contained herein is Amlogic confidential.  *
+ * This software is provided to you pursuant to Software License Agreement
+ * (SLA) with Amlogic Inc ("Amlogic"). This software may be used
+ * only in accordance with the terms of this agreement.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification is strictly prohibited without prior written permission from
+ * Amlogic.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER 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, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * gpio driver header file
+ */
+#ifndef _GPIO_DRIVER_H_
+#define _GPIO_DRIVER_H_
+
+/**
+ * enum GpioRegType - type of registers encoded in @meson_reg_desc
+ */
+enum GpioRegType {
+	REG_PULLEN = 0x0,
+	REG_PULL,
+	REG_DIR,
+	REG_OUT,
+	REG_IN,
+	REG_MUX,
+	REG_DRV,
+	NUM_REG,
+};
+
+typedef struct GpioRegDesc {
+	uint8_t reg;
+	uint8_t bit;
+} GpioRegDesc_t;
+
+typedef struct GpioDomain {
+	const char *name;
+
+	volatile uint32_t rPullen;
+	volatile uint32_t rPull;
+	volatile uint32_t rGpio;
+	volatile uint32_t rMux;
+	volatile uint32_t rDrv;
+} GpioDomain_t;
+
+typedef struct GpioBank {
+	const char *name;
+	const GpioDomain_t *domain;
+	GpioRegDesc_t regs[NUM_REG];
+} GpioBank_t;
+
+const GpioBank_t *pGetGpioBank(void);
+
+#define BANK(n, d, per, peb, pr, pb, dr, db, or, ob, ir, ib, mr, mb, sr, sb)	\
+{										\
+	.name   = n,								\
+	.domain = d,								\
+	.regs	= {								\
+		[REG_PULLEN]	= {per, peb},					\
+		[REG_PULL]	= {pr, pb},					\
+		[REG_DIR]	= {dr, db},					\
+		[REG_OUT]	= {or, ob},					\
+		[REG_IN]	= {ir, ib},					\
+		[REG_MUX]	= {mr, mb},					\
+		[REG_DRV]	= {sr, sb},					\
+	},									\
+}
+
+#endif
diff --git a/bl30/src_ao/demos/amlogic/driver/gpio/gpio_irq.c b/bl30/src_ao/demos/amlogic/driver/gpio/gpio_irq.c
new file mode 100644
index 0000000..2449bca
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/gpio/gpio_irq.c
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2014-2018 Amlogic, Inc. All rights reserved.
+ *
+ * All information contained herein is Amlogic confidential.
+ *
+ * This software is provided to you pursuant to Software License Agreement
+ * (SLA) with Amlogic Inc ("Amlogic"). This software may be used
+ * only in accordance with the terms of this agreement.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification is strictly prohibited without prior written permission from
+ * Amlogic.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER 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, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * gpio driver
+ */
+#include "FreeRTOS.h"
+#include "register.h"
+#include "util.h"
+#include "projdefs.h"
+#include "gpio_irq.h"
+#include "semphr.h"
+
+#include <unistd.h>
+#include "n200_func.h"
+#include "common.h"
+
+#define  DRIVER_NAME  "gpio_irq"
+
+static uint32_t GpioIrqRegBackup[IRQ_REG_NUM] = {0};
+
+/* old platform like t5/t5d */
+#ifdef GPIO_AO_IRQ_BASE
+static uint32_t GpioIrqRegAOBackup;
+#endif
+
+void vGpioIRQInit(void)
+{
+	REG32_UPDATE_BITS(GPIO_EE_IRQ_BASE, BIT(31), BIT(31));
+}
+
+/* irqnum: gpio controller irqnum
+ * line: gpio irq line
+ * */
+static void prvGpioSetupIRQ(uint16_t irqNum, uint8_t line, uint32_t flags)
+{
+	prvGpioPlatIrqSetup(irqNum, line, flags);
+}
+
+static int32_t prvRequestParentIRQ(uint16_t gpio, GpioIRQHandler_t handler,
+				   uint32_t flags)
+{
+	const GpioIRQBank_t *bk = &(pGetGpioIrqBank()[gpio >> 5]);
+	uint8_t offset = gpio % 32;
+	uint16_t irq;
+	uint8_t i;
+
+	irq = bk->gpioIRQBase + offset;
+
+	for (i = 0; i < bk->parentIRQNum; i++) {
+		if (bk->parentIRQs[i].owner == gpio &&
+		    (bk->parentIRQs[i].flags == flags)) {
+			iprintf("%s: irq had been allocated for gpio[%d]\n",
+				DRIVER_NAME, gpio);
+			return -pdFREERTOS_ERRNO_EINVAL;
+		}
+		if (bk->parentIRQs[i].owner == GPIO_INVALID)
+			break;
+	}
+
+	if (i == bk->parentIRQNum) {
+		iprintf("%s: no more gpio irqs available for gpio[%d]\n",
+			DRIVER_NAME, gpio);
+		return -pdFREERTOS_ERRNO_EINVAL;
+	}
+
+	bk->parentIRQs[i].owner = gpio;
+	bk->parentIRQs[i].flags = flags;
+
+	prvGpioSetupIRQ(irq, i, flags);
+
+	iprintf("bk->parentIRQs[i].irq is %d\n", bk->parentIRQs[i].irq);
+
+	RegisterIrq(bk->parentIRQs[i].irq, 2, handler);
+	ClearPendingIrq(bk->parentIRQs[i].irq);
+	EnableIrq(bk->parentIRQs[i].irq);
+
+	return 0;
+}
+
+static void prvFreeParentIRQ(uint16_t gpio)
+{
+	const GpioIRQBank_t *bk = &(pGetGpioIrqBank()[gpio >> 5]);
+	uint8_t i;
+
+	for (i = 0; i < bk->parentIRQNum; i++) {
+		if (bk->parentIRQs[i].owner == gpio) {
+			DisableIrq(bk->parentIRQs[i].irq);
+			bk->parentIRQs[i].owner = GPIO_INVALID;
+			bk->parentIRQs[i].flags = 0;
+			UnRegisterIrq(bk->parentIRQs[i].irq);
+		}
+	}
+}
+
+int32_t xRequestGpioIRQ(uint16_t gpio, GpioIRQHandler_t handler, uint32_t flags)
+{
+	int32_t ret;
+
+	ret = prvRequestParentIRQ(gpio, handler, flags);
+	if (ret) {
+		iprintf("%s: fail to allocate Parent irq for gpio[%d]\n",
+			DRIVER_NAME, gpio);
+		prvFreeParentIRQ(gpio);
+		return ret;
+	}
+
+	return 0;
+}
+
+void vFreeGpioIRQ(uint16_t gpio)
+{
+	prvFreeParentIRQ(gpio);
+}
+
+void vEnableGpioIRQ(uint16_t gpio)
+{
+	const GpioIRQBank_t *bk = &(pGetGpioIrqBank()[gpio >> 5]);
+	uint8_t i;
+
+	for (i = 0; i < bk->parentIRQNum; i++) {
+		if (bk->parentIRQs[i].owner == gpio) {
+			ClearPendingIrq(bk->parentIRQs[i].irq);
+			EnableIrq(bk->parentIRQs[i].irq);
+		}
+	}
+}
+
+void vDisableGpioIRQ(uint16_t gpio)
+{
+	const GpioIRQBank_t *bk = &(pGetGpioIrqBank()[gpio >> 5]);
+	uint8_t i;
+
+	for (i = 0; i < bk->parentIRQNum; i++) {
+		if (bk->parentIRQs[i].owner == gpio) {
+			DisableIrq(bk->parentIRQs[i].irq);
+		}
+	}
+}
+
+/* resume */
+void vRestoreGpioIrqReg(void)
+{
+	uint8_t ucIndex;
+	for (ucIndex = 0; ucIndex < IRQ_REG_NUM; ucIndex++)
+		REG32((unsigned long)(GPIO_EE_IRQ_BASE + 0x04 * ucIndex))
+		= GpioIrqRegBackup[ucIndex];
+
+/* old platform like t5/t5d */
+#ifdef GPIO_AO_IRQ_BASE
+	REG32((unsigned long)GPIO_AO_IRQ_BASE) = GpioIrqRegAOBackup;
+#endif
+
+}
+
+/* when come into suspend before request gpio irq*/
+void vBackupAndClearGpioIrqReg(void)
+{
+	uint8_t ucIndex;
+	for (ucIndex = 0; ucIndex < IRQ_REG_NUM; ucIndex++) {
+		GpioIrqRegBackup[ucIndex] =
+			REG32((unsigned long)GPIO_EE_IRQ_BASE + 0x04 * ucIndex);
+		//iprintf("reg[%d] is 0x%x\n", ucIndex, GpioIrqRegBackup[ucIndex]);
+	}
+
+	for (ucIndex = 0; ucIndex < IRQ_REG_NUM; ucIndex++)
+		REG32((unsigned long)(GPIO_EE_IRQ_BASE + 0x04 * ucIndex)) = 0;
+
+/* old platform like t5/t5d */
+#ifdef GPIO_AO_IRQ_BASE
+	GpioIrqRegAOBackup = REG32((unsigned long)GPIO_AO_IRQ_BASE);
+	REG32((unsigned long)GPIO_AO_IRQ_BASE) = 0;
+#endif
+
+}
diff --git a/bl30/src_ao/demos/amlogic/driver/gpio/gpio_irq.h b/bl30/src_ao/demos/amlogic/driver/gpio/gpio_irq.h
new file mode 100644
index 0000000..a009f46
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/gpio/gpio_irq.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2014-2018 Amlogic, Inc. All rights reserved.
+ *
+ * All information contained herein is Amlogic confidential.
+ * This software is provided to you pursuant to Software License Agreement
+ * (SLA) with Amlogic Inc ("Amlogic"). This software may be used
+ * only in accordance with the terms of this agreement.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification is strictly prohibited without prior written permission from
+ * Amlogic.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER 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, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * gpio IRQ header file
+ */
+#ifndef _GPIO_IRQ_H_
+#define _GPIO_IRQ_H_
+
+#include <gpio.h>
+
+/**
+ * enum GpioEEIRQLineType - type of gpio EE IRQ Lines
+ */
+enum GpioEEIRQLineType {
+	GPIO_EE_IRQ_L0 = 0x0,
+	GPIO_EE_IRQ_L1,
+	GPIO_EE_IRQ_L2,
+	GPIO_EE_IRQ_L3,
+	GPIO_EE_IRQ_L4,
+	GPIO_EE_IRQ_L5,
+	GPIO_EE_IRQ_L6,
+	GPIO_EE_IRQ_L7,
+	GPIO_EE_IRQ_LINE_INVALID,
+};
+
+enum GPioAOIRQLineType {
+	GPIO_AO_IRQ_L0 = 0x0,
+	GPIO_AO_IRQ_L1,
+	GPIO_AO_IRQ_LINE_INVALID,
+};
+
+
+typedef struct ParentIRQDesc {
+	GpioIRQHandler_t phandler;
+	uint32_t flags;
+	uint16_t owner;
+	uint16_t irq;
+} ParentIRQDesc_t;
+
+typedef struct GpioIRQBank {
+	const char *name;
+	ParentIRQDesc_t *parentIRQs;
+	uint16_t gpioIRQBase;
+	uint8_t parentIRQNum;
+} GpioIRQBank_t;
+
+#define LEN_NAME		32
+
+#ifdef PADCTRL_GPIO_IRQ_CTRL0
+#define GPIO_EE_IRQ_BASE	PADCTRL_GPIO_IRQ_CTRL0
+#else
+#define GPIO_EE_IRQ_BASE	(0xffd00000 + (0x3c20  << 2))
+#endif
+
+#define PARENT_IRQ_BK(p, f, o, n)					\
+{									\
+	.phandler = p,							\
+	.flags    = f,							\
+	.owner    = o,							\
+	.irq      = n,							\
+}
+
+#define GPIO_IRQ_BK(n, b, i, in)					\
+{									\
+	.name		= n,						\
+	.gpioIRQBase	= b,						\
+	.parentIRQs	= i,						\
+	.parentIRQNum	= in,						\
+}
+
+const GpioIRQBank_t *pGetGpioIrqBank(void);
+void prvGpioPlatIrqSetup(uint16_t irqNum, uint8_t line, uint32_t flags);
+#endif
diff --git a/bl30/src_ao/demos/amlogic/driver/gpio/gpio_p1_plat.c b/bl30/src_ao/demos/amlogic/driver/gpio/gpio_p1_plat.c
new file mode 100644
index 0000000..4d2efa6
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/gpio/gpio_p1_plat.c
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2014-2018 Amlogic, Inc. All rights reserved.
+ *
+ * All information contained herein is Amlogic confidential.
+ *
+ * This software is provided to you pursuant to Software License Agreement
+ * (SLA) with Amlogic Inc ("Amlogic"). This software may be used
+ * only in accordance with the terms of this agreement.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification is strictly prohibited without prior written permission from
+ * Amlogic.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER 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, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * gpio driver platform data
+ */
+#include "FreeRTOS.h"
+#include <register.h>
+#include <common.h>
+#include <gpio.h>
+#include "util.h"
+#include "projdefs.h"
+#include "gpio_drv.h"
+#include "gpio_irq.h"
+#include "portmacro.h"
+
+/* gpio irq controller */
+#define IRQ_GPIO0_NUM 228
+#define IRQ_GPIO1_NUM 229
+#define IRQ_GPIO2_NUM 230
+#define IRQ_GPIO3_NUM 231
+#define IRQ_GPIO4_NUM 232
+#define IRQ_GPIO5_NUM 233
+#define IRQ_GPIO6_NUM 234
+#define IRQ_GPIO7_NUM 235
+
+#define REG_PIN_P1_SEL			0x10
+#define REG_EDGE_SINGLE			0x04
+#define REG_POL_LOW			0x08
+#define REG_EDGE_BOTH			0x0c
+#define GPIO_IRQ_FILTER_SHIFT(x)	(((x) % 2 == 0) ? 8 : 24)
+#define GPIO_IRQ_POL_SHIFT(x)		(BIT(0 + (x)))
+#define GPIO_IRQ_EDGE_SHIFT(x)		(BIT(0 + (x)))
+#define GPIO_IRQ_BOTH_SHIFT(x)		(BIT(0 + (x)))
+
+static const GpioDomain_t stDomain = {
+	.name = "ST",
+	.rPullen = PADCTRL_GPIOB_I,
+	.rPull = PADCTRL_GPIOB_I,
+	.rGpio = PADCTRL_GPIOB_I,
+	.rMux = PADCTRL_PIN_MUX_REG10,
+	.rDrv = PADCTRL_GPIOB_I,
+};
+
+static const GpioDomain_t eeDomain = {
+	.name = "EE",
+	.rPullen = PADCTRL_TESTN_I,
+	.rPull = PADCTRL_TESTN_I,
+	.rGpio = PADCTRL_TESTN_I,
+	.rMux = PADCTRL_PIN_MUX_REG2,
+	.rDrv = PADCTRL_TESTN_I,
+};
+
+static const GpioBank_t gpioBanks[BANK_NUM_MAX] = {
+			/* pullen   pull    dir       out      in      mux */
+	BANK("D", &eeDomain, 0x13, 0, 0x14, 0, 0x12, 0, 0x11, 0, 0x10, 0, 0x00,
+	        /* drv */
+	     0, 0x17, 0),
+	BANK("E", &eeDomain, 0x23, 0, 0x24, 0, 0x22, 0, 0x21, 0, 0x20, 0, 0x02,
+	     0, 0x27, 0),
+	BANK("Z", &eeDomain, 0x33, 0, 0x34, 0, 0x32, 0, 0x31, 0, 0x30, 0, 0x1d,
+	     0, 0x37, 0),
+	BANK("H", &eeDomain, 0x43, 0, 0x44, 0, 0x42, 0, 0x41, 0, 0x40, 0, 0x0d,
+	     0, 0x47, 0),
+	BANK("C", &eeDomain, 0x53, 0, 0x54, 0, 0x52, 0, 0x51, 0, 0x50, 0, 0x03,
+	     0, 0x57, 0),
+	BANK("B", &stDomain, 0x03, 0, 0x04, 0, 0x02, 0, 0x01, 0, 0x00, 0, 0x00,
+	     0, 0x07, 0),
+	BANK("X", &eeDomain, 0x73, 0, 0x74, 0, 0x72, 0, 0x71, 0, 0x70, 0, 0x17,
+	     0, 0x77, 0),
+	BANK("T", &eeDomain, 0x83, 0, 0x84, 0, 0x82, 0, 0x81, 0, 0x80, 0, 0x06,
+	     0, 0x87, 0),
+	BANK("K", &eeDomain, 0x93, 0, 0x94, 0, 0x92, 0, 0x91, 0, 0x90, 0, 0x10,
+	     0, 0x97, 0),
+	BANK("W", &eeDomain, 0xa3, 0, 0xa4, 0, 0xa2, 0, 0xa1, 0, 0xa0, 0, 0x14,
+	     0, 0xa7, 0),
+	BANK("M", &eeDomain, 0xb3, 0, 0xb4, 0, 0xb2, 0, 0xb1, 0, 0xb0, 0, 0x0a,
+	     0, 0xb7, 0),
+	BANK("Y", &eeDomain, 0xc3, 0, 0xc4, 0, 0xc2, 0, 0xc1, 0, 0xc0, 0, 0x1b,
+	     0, 0xc7, 0),
+	BANK("N", &eeDomain, 0xd3, 0, 0xd4, 0, 0xd2, 0, 0xd1, 0, 0xd0, 0, 0x0b,
+	     0, 0xd7, 0),
+	BANK("TEST_N", &eeDomain, 0x03, 0, 0x04, 0, 0x02, 0, 0x01, 0, 0x00, 0, 0x0a,
+	0, 0x07, 0),
+};
+
+static ParentIRQDesc_t eeIRQs[] = {
+	[GPIO_EE_IRQ_L0] = PARENT_IRQ_BK(NULL, 0, GPIO_INVALID, IRQ_GPIO0_NUM),
+	[GPIO_EE_IRQ_L1] = PARENT_IRQ_BK(NULL, 0, GPIO_INVALID, IRQ_GPIO1_NUM),
+	[GPIO_EE_IRQ_L2] = PARENT_IRQ_BK(NULL, 0, GPIO_INVALID, IRQ_GPIO2_NUM),
+	[GPIO_EE_IRQ_L3] = PARENT_IRQ_BK(NULL, 0, GPIO_INVALID, IRQ_GPIO3_NUM),
+	[GPIO_EE_IRQ_L4] = PARENT_IRQ_BK(NULL, 0, GPIO_INVALID, IRQ_GPIO4_NUM),
+	[GPIO_EE_IRQ_L5] = PARENT_IRQ_BK(NULL, 0, GPIO_INVALID, IRQ_GPIO5_NUM),
+	[GPIO_EE_IRQ_L6] = PARENT_IRQ_BK(NULL, 0, GPIO_INVALID, IRQ_GPIO6_NUM),
+	[GPIO_EE_IRQ_L7] = PARENT_IRQ_BK(NULL, 0, GPIO_INVALID, IRQ_GPIO7_NUM),
+};
+
+static const GpioIRQBank_t irqBanks[BANK_NUM_MAX] = {
+	GPIO_IRQ_BK("D", 13,  eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("E", 26,  eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("Z", 222,  eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("H", 102, eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("C", 32,  eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("B", 0,   eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("X", 175,  eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("T", 50,  eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("K", 126,  eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("W", 157,  eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("M", 82, eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("Y", 207, eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("N", 88, eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("TEST_N", 230, eeIRQs, ARRAY_SIZE(eeIRQs)),
+};
+
+const GpioBank_t *pGetGpioBank(void)
+{
+	return gpioBanks;
+}
+
+const GpioIRQBank_t *pGetGpioIrqBank(void)
+{
+	return irqBanks;
+}
+
+void prvGpioPlatIrqSetup(uint16_t irqNum, uint8_t line, uint32_t flags)
+{
+	uint32_t val = 0;
+	uint32_t reg_offset = 0;
+	uint16_t bit_offset = 0;
+
+	bit_offset = ((line % 2) == 0) ? 0 : 16;
+	reg_offset = REG_PIN_P1_SEL + ((line / 2) << 2);
+
+	/* clear both edge */
+	REG32_UPDATE_BITS(GPIO_EE_IRQ_BASE + REG_EDGE_BOTH,
+			  GPIO_IRQ_BOTH_SHIFT(line), 0);
+	/* set filter */
+	REG32_UPDATE_BITS(GPIO_EE_IRQ_BASE + reg_offset,
+			  0x7 << GPIO_IRQ_FILTER_SHIFT(line),
+			  0x7 << GPIO_IRQ_FILTER_SHIFT(line));
+
+	/* select trigger pin */
+	REG32_UPDATE_BITS(GPIO_EE_IRQ_BASE + reg_offset,
+			  0xff << bit_offset, irqNum << bit_offset);
+
+	/* set trigger both type */
+	if (flags & IRQF_TRIGGER_BOTH) {
+		val |= GPIO_IRQ_BOTH_SHIFT(line);
+		REG32_UPDATE_BITS(GPIO_EE_IRQ_BASE + REG_EDGE_BOTH,
+				  GPIO_IRQ_BOTH_SHIFT(line), val);
+		return;
+	}
+
+	/* set trigger single edge or level  type */
+	if (flags & (IRQF_TRIGGER_LOW | IRQF_TRIGGER_FALLING)) {
+		val |= GPIO_IRQ_POL_SHIFT(line);
+		REG32_UPDATE_BITS(GPIO_EE_IRQ_BASE + REG_POL_LOW, GPIO_IRQ_POL_SHIFT(line), val);
+	}
+
+	if (flags & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) {
+		val = 0;
+		val |= GPIO_IRQ_EDGE_SHIFT(line);
+		REG32_UPDATE_BITS(GPIO_EE_IRQ_BASE + REG_EDGE_SINGLE, GPIO_IRQ_EDGE_SHIFT(line), val);
+	}
+}
+
diff --git a/bl30/src_ao/demos/amlogic/driver/gpio/gpio_s4_plat.c b/bl30/src_ao/demos/amlogic/driver/gpio/gpio_s4_plat.c
new file mode 100644
index 0000000..e611595
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/gpio/gpio_s4_plat.c
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2014-2018 Amlogic, Inc. All rights reserved.
+ *
+ * All information contained herein is Amlogic confidential.
+ *
+ * This software is provided to you pursuant to Software License Agreement
+ * (SLA) with Amlogic Inc ("Amlogic"). This software may be used
+ * only in accordance with the terms of this agreement.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification is strictly prohibited without prior written permission from
+ * Amlogic.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER 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, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * gpio driver platform data
+ */
+#include "FreeRTOS.h"
+#include <register.h>
+#include <common.h>
+#include <gpio.h>
+#include "util.h"
+#include "projdefs.h"
+#include "gpio_drv.h"
+#include "gpio_irq.h"
+#include "portmacro.h"
+
+/* gpio irq controller */
+#define IRQ_GPIO0_NUM 10
+#define IRQ_GPIO1_NUM 11
+#define IRQ_GPIO2_NUM 12
+#define IRQ_GPIO3_NUM 13
+#define IRQ_GPIO4_NUM 14
+#define IRQ_GPIO5_NUM 15
+#define IRQ_GPIO6_NUM 16
+#define IRQ_GPIO7_NUM 17
+
+#define REG_PIN_SC2_SEL			0x04
+#define REG_EDGE_POL_EXTR		0x1c
+#define REG_EDGE_POL_MASK_SC2(x)			\
+	({typeof(x) _x = (x); BIT(_x) | BIT(12 + (_x)); })
+#define GPIO_IRQ_FILTER_SHIFT(x)	(((x) % 2 == 0) ? 8 : 24)
+#define GPIO_IRQ_POL_SHIFT(x)		(BIT(0 + (x)))
+#define GPIO_IRQ_EDGE_SHIFT(x)		(BIT(12 + (x)))
+#define GPIO_IRQ_BOTH_SHIFT(x)		(BIT(0 + (x)))
+
+static const GpioDomain_t eeDomain = {
+	.name = "EE",
+	.rPullen = PADCTRL_GPIOZ_I,
+	.rPull = PADCTRL_GPIOZ_I,
+	.rGpio = PADCTRL_GPIOZ_I,
+	.rMux = PADCTRL_PIN_MUX_REG0,
+	.rDrv = PADCTRL_GPIOZ_I,
+};
+
+static const GpioBank_t gpioBanks[BANK_NUM_MAX] = {
+			  /* pullen    pull	 dir       out       in        mux */
+	BANK("E", &eeDomain, 0x43, 0, 0x44, 0, 0x42, 0, 0x41, 0, 0x40, 0, 0x12,
+	     0, 0x47, 0),
+	BANK("B", &eeDomain, 0x63, 0, 0x64, 0, 0x62, 0, 0x61, 0, 0x60, 0, 0x00,
+	     0, 0x67, 0),
+	BANK("C", &eeDomain, 0x53, 0, 0x54, 0, 0x52, 0, 0x51, 0, 0x50, 0, 0x09,
+	     0, 0x57, 0),
+	BANK("D", &eeDomain, 0x33, 0, 0x34, 0, 0x32, 0, 0x31, 0, 0x30, 0, 0x10,
+	     0, 0x37, 0),
+	BANK("H", &eeDomain, 0x23, 0, 0x24, 0, 0x22, 0, 0x21, 0, 0x20, 0, 0x0b,
+	     0, 0x27, 0),
+	BANK("X", &eeDomain, 0x13, 0, 0x14, 0, 0x12, 0, 0x11, 0, 0x10, 0, 0x03,
+	     0, 0x17, 0),
+	BANK("Z", &eeDomain, 0x03, 0, 0x04, 0, 0x02, 0, 0x01, 0, 0x00, 0, 0x06,
+	     0, 0x07, 0),
+	BANK("TEST_N", &eeDomain, 0x83, 0, 0x84, 0, 0x82, 0, 0x81, 0, 0x80, 0,
+	     0x0f, 0, 0x87, 0),
+};
+
+static ParentIRQDesc_t eeIRQs[] = {
+	[GPIO_EE_IRQ_L0] = PARENT_IRQ_BK(NULL, 0, GPIO_INVALID, IRQ_GPIO0_NUM),
+	[GPIO_EE_IRQ_L1] = PARENT_IRQ_BK(NULL, 0, GPIO_INVALID, IRQ_GPIO1_NUM),
+	[GPIO_EE_IRQ_L2] = PARENT_IRQ_BK(NULL, 0, GPIO_INVALID, IRQ_GPIO2_NUM),
+	[GPIO_EE_IRQ_L3] = PARENT_IRQ_BK(NULL, 0, GPIO_INVALID, IRQ_GPIO3_NUM),
+	[GPIO_EE_IRQ_L4] = PARENT_IRQ_BK(NULL, 0, GPIO_INVALID, IRQ_GPIO4_NUM),
+	[GPIO_EE_IRQ_L5] = PARENT_IRQ_BK(NULL, 0, GPIO_INVALID, IRQ_GPIO5_NUM),
+	[GPIO_EE_IRQ_L6] = PARENT_IRQ_BK(NULL, 0, GPIO_INVALID, IRQ_GPIO6_NUM),
+	[GPIO_EE_IRQ_L7] = PARENT_IRQ_BK(NULL, 0, GPIO_INVALID, IRQ_GPIO7_NUM),
+};
+
+static const GpioIRQBank_t irqBanks[BANK_NUM_MAX] = {
+	GPIO_IRQ_BK("E", 22, eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("B", 0, eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("C", 14, eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("D", 24, eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("H", 36, eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("X", 48, eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("Z", 68, eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("TEST_N", 86, eeIRQs, ARRAY_SIZE(eeIRQs)),
+};
+
+const GpioBank_t *pGetGpioBank(void)
+{
+	return gpioBanks;
+}
+
+const GpioIRQBank_t *pGetGpioIrqBank(void)
+{
+	return irqBanks;
+}
+
+void prvGpioPlatIrqSetup(uint16_t irqNum, uint8_t line, uint32_t flags)
+{
+	uint32_t val = 0;
+	uint32_t reg_offset = 0;
+	uint16_t bit_offset = 0;
+
+	bit_offset = ((line % 2) == 0) ? 0 : 16;
+	reg_offset = REG_PIN_SC2_SEL + ((line / 2) << 2);
+
+	/* clear both edge */
+	REG32_UPDATE_BITS(GPIO_EE_IRQ_BASE + REG_EDGE_POL_EXTR,
+			  GPIO_IRQ_BOTH_SHIFT(line), 0);
+
+	/* set filter */
+	REG32_UPDATE_BITS(GPIO_EE_IRQ_BASE + reg_offset,
+			  0x7 << GPIO_IRQ_FILTER_SHIFT(line),
+			  0x7 << GPIO_IRQ_FILTER_SHIFT(line));
+
+	/* select trigger pin */
+	REG32_UPDATE_BITS(GPIO_EE_IRQ_BASE + reg_offset,
+			  0x7f << bit_offset, irqNum << bit_offset);
+
+	/* set trigger both type */
+	if (flags & IRQF_TRIGGER_BOTH) {
+		val |= GPIO_IRQ_BOTH_SHIFT(line);
+		REG32_UPDATE_BITS(GPIO_EE_IRQ_BASE + REG_EDGE_POL_EXTR,
+				  GPIO_IRQ_BOTH_SHIFT(line), val);
+		return;
+	}
+
+	/* set trigger single edge or level  type */
+	if (flags & (IRQF_TRIGGER_LOW | IRQF_TRIGGER_FALLING))
+		val |= GPIO_IRQ_POL_SHIFT(line);
+
+	if (flags & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING))
+		val |= GPIO_IRQ_EDGE_SHIFT(line);
+
+	REG32_UPDATE_BITS(GPIO_EE_IRQ_BASE, REG_EDGE_POL_MASK_SC2(line), val);
+
+}
+
diff --git a/bl30/src_ao/demos/amlogic/driver/gpio/gpio_sc2_plat.c b/bl30/src_ao/demos/amlogic/driver/gpio/gpio_sc2_plat.c
new file mode 100644
index 0000000..8fe02c4
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/gpio/gpio_sc2_plat.c
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2014-2018 Amlogic, Inc. All rights reserved.
+ *
+ * All information contained herein is Amlogic confidential.
+ *
+ * This software is provided to you pursuant to Software License Agreement
+ * (SLA) with Amlogic Inc ("Amlogic"). This software may be used
+ * only in accordance with the terms of this agreement.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification is strictly prohibited without prior written permission from
+ * Amlogic.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER 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, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * gpio driver platform data
+ */
+#include "FreeRTOS.h"
+#include <register.h>
+#include <common.h>
+#include <gpio.h>
+#include "util.h"
+#include "projdefs.h"
+#include "gpio_drv.h"
+#include "gpio_irq.h"
+#include "portmacro.h"
+
+/* gpio irq controller */
+#define IRQ_GPIO0_NUM 10
+#define IRQ_GPIO1_NUM 11
+#define IRQ_GPIO2_NUM 12
+#define IRQ_GPIO3_NUM 13
+#define IRQ_GPIO4_NUM 14
+#define IRQ_GPIO5_NUM 15
+#define IRQ_GPIO6_NUM 16
+#define IRQ_GPIO7_NUM 17
+
+#define REG_PIN_SC2_SEL			0x04
+#define REG_EDGE_POL_EXTR		0x1c
+#define REG_EDGE_POL_MASK_SC2(x)			\
+	({typeof(x) _x = (x); BIT(_x) | BIT(12 + (_x)); })
+#define GPIO_IRQ_FILTER_SHIFT(x)	(((x) % 2 == 0) ? 8 : 24)
+#define GPIO_IRQ_POL_SHIFT(x)		(BIT(0 + (x)))
+#define GPIO_IRQ_EDGE_SHIFT(x)		(BIT(12 + (x)))
+#define GPIO_IRQ_BOTH_SHIFT(x)		(BIT(0 + (x)))
+
+static const GpioDomain_t eeDomain = {
+	.name = "EE",
+	.rPullen = PADCTRL_GPIOZ_I,
+	.rPull = PADCTRL_GPIOZ_I,
+	.rGpio = PADCTRL_GPIOZ_I,
+	.rMux = PADCTRL_PIN_MUX_REG0,
+	.rDrv = PADCTRL_GPIOZ_I,
+};
+
+static const GpioBank_t gpioBanks[BANK_NUM_MAX] = {
+			  /* pullen    pull	 dir       out       in        mux */
+	BANK("A", &eeDomain, 0x73, 14, 0x74, 14, 0x72, 14, 0x71, 14, 0x70, 14, 0x0e,
+		/* drv */
+	     24, 0x77, 28),
+	BANK("B", &eeDomain, 0x63, 0, 0x64, 0, 0x62, 0, 0x61, 0, 0x60, 0, 0x00,
+	     0, 0x67, 0),
+	BANK("C", &eeDomain, 0x53, 0, 0x54, 0, 0x52, 0, 0x51, 0, 0x50, 0, 0x09,
+	     0, 0x57, 0),
+	BANK("E", &eeDomain, 0x43, 0, 0x44, 0, 0x42, 0, 0x41, 0, 0x40, 0, 0x12,
+	     0, 0x47, 0),
+	BANK("D", &eeDomain, 0x33, 0, 0x34, 0, 0x32, 0, 0x31, 0, 0x30, 0, 0x10,
+	     0, 0x37, 0),
+	BANK("H", &eeDomain, 0x23, 0, 0x24, 0, 0x22, 0, 0x21, 0, 0x20, 0, 0x0b,
+	     0, 0x27, 0),
+	BANK("X", &eeDomain, 0x13, 0, 0x14, 0, 0x12, 0, 0x11, 0, 0x10, 0, 0x03,
+	     0, 0x17, 0),
+	BANK("Z", &eeDomain, 0x03, 0, 0x04, 0, 0x02, 0, 0x01, 0, 0x00, 0, 0x06,
+	     0, 0x07, 0),
+	BANK("TEST_N", &eeDomain, 0x83, 0, 0x84, 0, 0x82, 0, 0x81, 0, 0x80, 0,
+	     0x0f, 0, 0x87, 0),
+};
+
+static ParentIRQDesc_t eeIRQs[] = {
+	[GPIO_EE_IRQ_L0] = PARENT_IRQ_BK(NULL, 0, GPIO_INVALID, IRQ_GPIO0_NUM),
+	[GPIO_EE_IRQ_L1] = PARENT_IRQ_BK(NULL, 0, GPIO_INVALID, IRQ_GPIO1_NUM),
+	[GPIO_EE_IRQ_L2] = PARENT_IRQ_BK(NULL, 0, GPIO_INVALID, IRQ_GPIO2_NUM),
+	[GPIO_EE_IRQ_L3] = PARENT_IRQ_BK(NULL, 0, GPIO_INVALID, IRQ_GPIO3_NUM),
+	[GPIO_EE_IRQ_L4] = PARENT_IRQ_BK(NULL, 0, GPIO_INVALID, IRQ_GPIO4_NUM),
+	[GPIO_EE_IRQ_L5] = PARENT_IRQ_BK(NULL, 0, GPIO_INVALID, IRQ_GPIO5_NUM),
+	[GPIO_EE_IRQ_L6] = PARENT_IRQ_BK(NULL, 0, GPIO_INVALID, IRQ_GPIO6_NUM),
+	[GPIO_EE_IRQ_L7] = PARENT_IRQ_BK(NULL, 0, GPIO_INVALID, IRQ_GPIO7_NUM),
+};
+
+static const GpioIRQBank_t irqBanks[BANK_NUM_MAX] = {
+	GPIO_IRQ_BK("A", 0, eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("B", 2, eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("C", 18, eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("E", 26, eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("D", 29, eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("H", 41, eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("X", 50, eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("Z", 70, eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("TEST_N", 86, eeIRQs, ARRAY_SIZE(eeIRQs)),
+};
+
+const GpioBank_t *pGetGpioBank(void)
+{
+	return gpioBanks;
+}
+
+const GpioIRQBank_t *pGetGpioIrqBank(void)
+{
+	return irqBanks;
+}
+
+void prvGpioPlatIrqSetup(uint16_t irqNum, uint8_t line, uint32_t flags)
+{
+	uint32_t val = 0;
+	uint32_t reg_offset = 0;
+	uint16_t bit_offset = 0;
+
+	bit_offset = ((line % 2) == 0) ? 0 : 16;
+	reg_offset = REG_PIN_SC2_SEL + ((line / 2) << 2);
+
+	/* clear both edge */
+	REG32_UPDATE_BITS(GPIO_EE_IRQ_BASE + REG_EDGE_POL_EXTR,
+			  GPIO_IRQ_BOTH_SHIFT(line), 0);
+
+	/* set filter */
+	REG32_UPDATE_BITS(GPIO_EE_IRQ_BASE + reg_offset,
+			  0x7 << GPIO_IRQ_FILTER_SHIFT(line),
+			  0x7 << GPIO_IRQ_FILTER_SHIFT(line));
+
+	/* select trigger pin */
+	REG32_UPDATE_BITS(GPIO_EE_IRQ_BASE + reg_offset,
+			  0x7f << bit_offset, irqNum << bit_offset);
+
+	/* set trigger both type */
+	if (flags & IRQF_TRIGGER_BOTH) {
+		val |= GPIO_IRQ_BOTH_SHIFT(line);
+		REG32_UPDATE_BITS(GPIO_EE_IRQ_BASE + REG_EDGE_POL_EXTR,
+				  GPIO_IRQ_BOTH_SHIFT(line), val);
+		return;
+	}
+
+	/* set trigger single edge or level  type */
+	if (flags & (IRQF_TRIGGER_LOW | IRQF_TRIGGER_FALLING))
+		val |= GPIO_IRQ_POL_SHIFT(line);
+
+	if (flags & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING))
+		val |= GPIO_IRQ_EDGE_SHIFT(line);
+
+	REG32_UPDATE_BITS(GPIO_EE_IRQ_BASE, REG_EDGE_POL_MASK_SC2(line), val);
+
+}
+
diff --git a/bl30/src_ao/demos/amlogic/driver/gpio/gpio_t3_plat.c b/bl30/src_ao/demos/amlogic/driver/gpio/gpio_t3_plat.c
new file mode 100644
index 0000000..7f6d90b
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/gpio/gpio_t3_plat.c
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2014-2018 Amlogic, Inc. All rights reserved.
+ *
+ * All information contained herein is Amlogic confidential.
+ *
+ * This software is provided to you pursuant to Software License Agreement
+ * (SLA) with Amlogic Inc ("Amlogic"). This software may be used
+ * only in accordance with the terms of this agreement.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification is strictly prohibited without prior written permission from
+ * Amlogic.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER 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, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * gpio driver platform data
+ */
+#include "FreeRTOS.h"
+#include <register.h>
+#include <common.h>
+#include <gpio.h>
+#include "util.h"
+#include "projdefs.h"
+#include "gpio_drv.h"
+#include "gpio_irq.h"
+#include "portmacro.h"
+
+/* gpio irq controller */
+#define IRQ_GPIO0_NUM 10
+#define IRQ_GPIO1_NUM 11
+#define IRQ_GPIO2_NUM 12
+#define IRQ_GPIO3_NUM 13
+#define IRQ_GPIO4_NUM 14
+#define IRQ_GPIO5_NUM 15
+#define IRQ_GPIO6_NUM 16
+#define IRQ_GPIO7_NUM 17
+
+#define REG_PIN_SC2_SEL			0x04
+#define REG_EDGE_POL_EXTR		0x1c
+#define REG_EDGE_POL_MASK_SC2(x)			\
+	({typeof(x) _x = (x); BIT(_x) | BIT(12 + (_x)); })
+#define GPIO_IRQ_FILTER_SHIFT(x)	(((x) % 2 == 0) ? 8 : 24)
+#define GPIO_IRQ_POL_SHIFT(x)		(BIT(0 + (x)))
+#define GPIO_IRQ_EDGE_SHIFT(x)		(BIT(12 + (x)))
+#define GPIO_IRQ_BOTH_SHIFT(x)		(BIT(0 + (x)))
+
+static const GpioDomain_t eeDomain = {
+	.name = "EE",
+	.rPullen = PADCTRL_GPIOD_I,
+	.rPull = PADCTRL_GPIOD_I,
+	.rGpio = PADCTRL_GPIOD_I,
+	.rMux = PADCTRL_PIN_MUX_REG0,
+	.rDrv = PADCTRL_GPIOD_I,
+};
+
+static const GpioBank_t gpioBanks[BANK_NUM_MAX] = {
+			  /* pullen   pull    dir       out      in      mux */
+	BANK("D", &eeDomain, 0x03, 0, 0x04, 0, 0x02, 0, 0x01, 0, 0x00, 0, 0x0b,
+		/* drv */
+	     0, 0x07, 0),
+	BANK("E", &eeDomain, 0x0b, 0, 0x0c, 0, 0x0a, 0, 0x09, 0, 0x08, 0, 0x0d,
+	     0, 0x0f, 0),
+	BANK("Z", &eeDomain, 0x13, 0, 0x14, 0, 0x12, 0, 0x11, 0, 0x10, 0, 0x04,
+	     0, 0x17, 0),
+	BANK("Z1", &eeDomain, 0x13, 16, 0x14, 16, 0x12, 16, 0x11, 16, 0x10, 16,
+	     0x06, 0, 0xc0, 0),
+	BANK("H", &eeDomain, 0x1b, 0, 0x1c, 0, 0x1a, 0, 0x19, 0, 0x18, 0, 0x07,
+	     0, 0x1f, 0),
+	BANK("H1", &eeDomain, 0x1b, 16, 0x1c, 16, 0x1a, 16, 0x19, 16, 0x18, 16,
+	     0x09, 0, 0xc1, 0),
+	BANK("B", &eeDomain, 0x2b, 0, 0x2c, 0, 0x2a, 0, 0x29, 0, 0x28, 0, 0x00,
+	     0, 0x2f, 0),
+	BANK("C", &eeDomain, 0x33, 0, 0x34, 0, 0x32, 0, 0x31, 0, 0x30, 0, 0x02,
+	     0, 0x37, 0),
+	BANK("W", &eeDomain, 0x63, 0, 0x64, 0, 0x62, 0, 0x61, 0, 0x60, 0, 0x12,
+	     0, 0x67, 0),
+	BANK("M", &eeDomain, 0x73, 0, 0x74, 0, 0x72, 0, 0x71, 0, 0x70, 0, 0x0e,
+	     0, 0x77, 0),
+	BANK("M1", &eeDomain, 0x73, 16, 0x74, 16, 0x72, 16, 0x71, 16, 0x70, 16,
+	     0x10, 0, 0xc2, 0),
+	BANK("TEST_N", &eeDomain, 0x83, 0, 0x84, 0, 0x82, 0, 0x81, 0, 0x80, 0,
+	     0x14, 0, 0x87, 0),
+};
+
+static ParentIRQDesc_t eeIRQs[] = {
+	[GPIO_EE_IRQ_L0] = PARENT_IRQ_BK(NULL, 0, GPIO_INVALID, IRQ_GPIO0_NUM),
+	[GPIO_EE_IRQ_L1] = PARENT_IRQ_BK(NULL, 0, GPIO_INVALID, IRQ_GPIO1_NUM),
+	[GPIO_EE_IRQ_L2] = PARENT_IRQ_BK(NULL, 0, GPIO_INVALID, IRQ_GPIO2_NUM),
+	[GPIO_EE_IRQ_L3] = PARENT_IRQ_BK(NULL, 0, GPIO_INVALID, IRQ_GPIO3_NUM),
+	[GPIO_EE_IRQ_L4] = PARENT_IRQ_BK(NULL, 0, GPIO_INVALID, IRQ_GPIO4_NUM),
+	[GPIO_EE_IRQ_L5] = PARENT_IRQ_BK(NULL, 0, GPIO_INVALID, IRQ_GPIO5_NUM),
+	[GPIO_EE_IRQ_L6] = PARENT_IRQ_BK(NULL, 0, GPIO_INVALID, IRQ_GPIO6_NUM),
+	[GPIO_EE_IRQ_L7] = PARENT_IRQ_BK(NULL, 0, GPIO_INVALID, IRQ_GPIO7_NUM),
+};
+
+/* need real gpio irq number */
+static const GpioIRQBank_t irqBanks[BANK_NUM_MAX] = {
+	GPIO_IRQ_BK("D", 43,  eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("E", 54,  eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("Z", 56,  eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("Z1", 72,  eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("H", 107, eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("H1", 123, eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("B", 0,   eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("C", 14,  eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("W", 30,  eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("M", 76, eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("M1", 92, eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("TEST_N", 135, eeIRQs, ARRAY_SIZE(eeIRQs)),
+};
+
+const GpioBank_t *pGetGpioBank(void)
+{
+	return gpioBanks;
+}
+
+const GpioIRQBank_t *pGetGpioIrqBank(void)
+{
+	return irqBanks;
+}
+
+void prvGpioPlatIrqSetup(uint16_t irqNum, uint8_t line, uint32_t flags)
+{
+	uint32_t val = 0;
+	uint32_t reg_offset = 0;
+	uint16_t bit_offset = 0;
+
+	bit_offset = ((line % 2) == 0) ? 0 : 16;
+	reg_offset = REG_PIN_SC2_SEL + ((line / 2) << 2);
+
+	/* clear both edge */
+	REG32(GPIO_EE_IRQ_BASE + REG_EDGE_POL_EXTR) =
+			REG32(GPIO_EE_IRQ_BASE + REG_EDGE_POL_EXTR) &
+			~GPIO_IRQ_BOTH_SHIFT(line);
+
+	/* set filter */
+	REG32_UPDATE_BITS(GPIO_EE_IRQ_BASE + reg_offset,
+			  0x7 << GPIO_IRQ_FILTER_SHIFT(line),
+			  0x7 << GPIO_IRQ_FILTER_SHIFT(line));
+
+	/* select trigger pin */
+	REG32_UPDATE_BITS(GPIO_EE_IRQ_BASE + reg_offset,
+			  0xff << bit_offset, irqNum << bit_offset);
+
+	/* set trigger both type */
+	if (flags & IRQF_TRIGGER_BOTH) {
+		val |= GPIO_IRQ_BOTH_SHIFT(line);
+		REG32_UPDATE_BITS(GPIO_EE_IRQ_BASE + REG_EDGE_POL_EXTR,
+				  GPIO_IRQ_BOTH_SHIFT(line), val);
+		return;
+	}
+
+	/* set trigger single edge or level  type */
+	if (flags & (IRQF_TRIGGER_LOW | IRQF_TRIGGER_FALLING))
+		val |= GPIO_IRQ_POL_SHIFT(line);
+
+	if (flags & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING))
+		val |= GPIO_IRQ_EDGE_SHIFT(line);
+
+	REG32_UPDATE_BITS(GPIO_EE_IRQ_BASE, REG_EDGE_POL_MASK_SC2(line), val);
+
+}
+
diff --git a/bl30/src_ao/demos/amlogic/driver/gpio/gpio_t5_plat.c b/bl30/src_ao/demos/amlogic/driver/gpio/gpio_t5_plat.c
new file mode 100644
index 0000000..85814fb
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/gpio/gpio_t5_plat.c
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2014-2018 Amlogic, Inc. All rights reserved.
+ *
+ * All information contained herein is Amlogic confidential.
+ *
+ * This software is provided to you pursuant to Software License Agreement
+ * (SLA) with Amlogic Inc ("Amlogic"). This software may be used
+ * only in accordance with the terms of this agreement.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification is strictly prohibited without prior written permission from
+ * Amlogic.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER 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, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * gpio driver platform data
+ */
+#include "FreeRTOS.h"
+#include <register.h>
+#include <common.h>
+#include <gpio.h>
+#include "util.h"
+#include "projdefs.h"
+#include "gpio_drv.h"
+#include "gpio_irq.h"
+#include "portmacro.h"
+
+/* gpio irq controller EE */
+#define IRQ_GPIO0_NUM	67
+#define IRQ_GPIO1_NUM	68
+#define IRQ_GPIO2_NUM	69
+#define IRQ_GPIO3_NUM	70
+
+/* gpio irq controller AO */
+#define IRQ_AO_GPIO0_NUM	17
+#define IRQ_AO_GPIO1_NUM	18
+
+
+#define EE_IRQ_REG_EDGE_POL	0x00
+#define EE_IRQ_REG_PIN_03_SEL	0x04
+#define EE_IRQ_REG_PIN_47_SEL	0x08
+#define EE_IRQ_REG_FILTER_SEL	0x0c
+
+#define EE_GPIO_IRQ_POL_EDGE_MASK(x)	(BIT(x) | BIT(16 + x))
+#define EE_GPIO_IRQ_POL(x)		BIT(16 + (x))
+#define EE_GPIO_IRQ_EDGE(x)		BIT(x)
+#define EE_GPIO_IRQ_FILTER_SHIFT(x)	((x) << 2)
+#define EE_GPIO_IRQ_SEL_SHIFT(x)	(((x) << 3) % 32)
+#define EE_GPIO_IRQ_BOTH(x)		BIT(8 + (x))
+
+#define AO_GPIO_NUM			10
+#define AO_GPIO_IRQ_POL_EDGE_MASK(x)	(BIT(16 + x) | BIT(18 + x))
+#define AO_GPIO_IRQ_POL(x)		BIT(16 + (x))
+#define AO_GPIO_IRQ_EDGE(x)		BIT(18 + (x))
+#define AO_GPIO_IRQ_FILTER_SHIFT(x)	(8 + ((x) << 2))
+#define AO_GPIO_IRQ_SEL_SHIFT(x)	((x) << 2)
+#define AO_GPIO_IRQ_BOTH(x)		(BIT((x) + 20))
+
+static const GpioDomain_t aoDomain = {
+	.name = "AO",
+	.rPullen = AO_GPIO_O_EN_N,
+	.rPull = AO_GPIO_O_EN_N,
+	.rGpio = AO_GPIO_O_EN_N,
+	.rMux = AO_RTI_PINMUX_REG0,
+	.rDrv = AO_PAD_DS_A,
+};
+
+static const GpioDomain_t eeDomain = {
+	.name = "EE",
+	.rPullen = PAD_PULL_UP_EN_REG0,
+	.rPull = PAD_PULL_UP_REG0,
+	.rGpio = PREG_PAD_GPIO0_EN_N,
+	.rMux = PERIPHS_PIN_MUX_0,
+	.rDrv = PAD_DS_REG0A,
+};
+
+static const GpioBank_t gpioBanks[BANK_NUM_MAX] = {
+			  /* pullen pull  dir    out   in     mux   drv*/
+	BANK("D", &aoDomain, 3, 0,  2, 0, 0, 0,  4, 0, 1, 0,  0, 0, 0, 0),
+	BANK("H", &eeDomain, 2, 0,  2, 0, 6, 0,  7, 0, 8, 0,  5, 0, 2, 0),
+	BANK("B", &eeDomain, 0, 0,  0, 0, 0, 0,  1, 0, 2, 0,  0, 0, 0, 0),
+	BANK("Z", &eeDomain, 1, 0,  1, 0, 3, 0,  4, 0, 5, 0,  4, 0, 1, 0),
+	BANK("W", &eeDomain, 3, 0,  3, 0, 9, 0,  10, 0, 11, 0, 2,0, 3, 9),
+	BANK("E", &aoDomain, 3, 16, 2, 16, 0, 16, 4, 16, 1, 16, 1, 16, 1, 0),
+};
+
+static ParentIRQDesc_t eeIRQs[] = {
+	[GPIO_EE_IRQ_L0] = PARENT_IRQ_BK(NULL, 0, GPIO_INVALID, IRQ_GPIO0_NUM),
+	[GPIO_EE_IRQ_L1] = PARENT_IRQ_BK(NULL, 0, GPIO_INVALID, IRQ_GPIO1_NUM),
+	[GPIO_EE_IRQ_L2] = PARENT_IRQ_BK(NULL, 0, GPIO_INVALID, IRQ_GPIO2_NUM),
+	[GPIO_EE_IRQ_L3] = PARENT_IRQ_BK(NULL, 0, GPIO_INVALID, IRQ_GPIO3_NUM),
+};
+
+static ParentIRQDesc_t aoIRQs[] = {
+	[GPIO_AO_IRQ_L0] = PARENT_IRQ_BK(NULL, 0, GPIO_INVALID,
+					 IRQ_AO_GPIO0_NUM),
+	[GPIO_AO_IRQ_L1] = PARENT_IRQ_BK(NULL, 0, GPIO_INVALID,
+					 IRQ_AO_GPIO1_NUM),
+
+};
+
+static const GpioIRQBank_t irqBanks[BANK_NUM_MAX] = {
+	GPIO_IRQ_BK("D", 0, aoIRQs, ARRAY_SIZE(aoIRQs)),
+	GPIO_IRQ_BK("H", 11, eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("B", 33, eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("Z", 47, eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("W", 54, eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("E", 67, eeIRQs, ARRAY_SIZE(eeIRQs)),
+};
+
+const GpioBank_t *pGetGpioBank(void)
+{
+	return gpioBanks;
+}
+
+const GpioIRQBank_t *pGetGpioIrqBank(void)
+{
+	return irqBanks;
+}
+
+static void prvGpioEEsetupIRQ(uint16_t irqNum, uint8_t line, uint32_t flags)
+{
+
+	uint32_t val = 0;
+
+	REG32_UPDATE_BITS(GPIO_EE_IRQ_BASE + EE_IRQ_REG_FILTER_SEL,
+			  0x7 << EE_GPIO_IRQ_FILTER_SHIFT(line),
+			  0x7 << EE_GPIO_IRQ_FILTER_SHIFT(line));
+
+	if (flags & IRQF_TRIGGER_BOTH) {
+		val |= EE_GPIO_IRQ_BOTH(line);
+		REG32_UPDATE_BITS(GPIO_EE_IRQ_BASE, EE_GPIO_IRQ_BOTH(line), val);
+		goto out;
+	}
+
+	if (flags & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING))
+		val |= EE_GPIO_IRQ_EDGE(line);
+
+	if (flags & (IRQF_TRIGGER_LOW | IRQF_TRIGGER_FALLING))
+		val |= EE_GPIO_IRQ_POL(line);
+
+	REG32_UPDATE_BITS(GPIO_EE_IRQ_BASE,
+			  EE_GPIO_IRQ_POL_EDGE_MASK(line), val);
+
+out:
+	REG32_UPDATE_BITS(GPIO_EE_IRQ_BASE + ((line > GPIO_EE_IRQ_L3) ?
+			  EE_IRQ_REG_PIN_47_SEL :
+			  EE_IRQ_REG_PIN_03_SEL),
+			  0xff << EE_GPIO_IRQ_SEL_SHIFT(line),
+			  irqNum << EE_GPIO_IRQ_SEL_SHIFT(line));
+
+}
+
+static void prvGpioAOsetupIRQ(uint16_t irqNum, uint8_t line, uint32_t flags)
+{
+	uint32_t val = 0;
+
+	if (flags & IRQF_TRIGGER_BOTH)
+		val |= AO_GPIO_IRQ_BOTH(line);
+
+	if (flags & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING))
+		val |= AO_GPIO_IRQ_EDGE(line);
+
+	if (flags & (IRQF_TRIGGER_LOW | IRQF_TRIGGER_FALLING))
+		val |= AO_GPIO_IRQ_POL(line);
+
+	val |= (0x7 << AO_GPIO_IRQ_FILTER_SHIFT(line));
+
+	val |= (irqNum << AO_GPIO_IRQ_SEL_SHIFT(line));
+
+	if (GPIO_AO_IRQ_BASE == 0)
+	return;
+
+	REG32_UPDATE_BITS(GPIO_AO_IRQ_BASE, (AO_GPIO_IRQ_POL_EDGE_MASK(line) | (AO_GPIO_IRQ_BOTH(line)) |
+			  (0x7 << AO_GPIO_IRQ_FILTER_SHIFT(line)) |
+			  (0xf << AO_GPIO_IRQ_SEL_SHIFT(line))), val);
+}
+
+void prvGpioPlatIrqSetup(uint16_t irqNum, uint8_t line, uint32_t flags)
+{
+	if (irqNum > AO_GPIO_NUM)
+		prvGpioEEsetupIRQ(irqNum, line, flags);
+	else
+		prvGpioAOsetupIRQ(irqNum, line, flags);
+
+}
+
diff --git a/bl30/src_ao/demos/amlogic/driver/gpio/gpio_t5d_plat.c b/bl30/src_ao/demos/amlogic/driver/gpio/gpio_t5d_plat.c
new file mode 100644
index 0000000..0be2483
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/gpio/gpio_t5d_plat.c
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2014-2018 Amlogic, Inc. All rights reserved.
+ *
+ * All information contained herein is Amlogic confidential.
+ *
+ * This software is provided to you pursuant to Software License Agreement
+ * (SLA) with Amlogic Inc ("Amlogic"). This software may be used
+ * only in accordance with the terms of this agreement.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification is strictly prohibited without prior written permission from
+ * Amlogic.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER 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, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * gpio driver platform data
+ */
+#include "FreeRTOS.h"
+#include <register.h>
+#include <common.h>
+#include <gpio.h>
+#include "util.h"
+#include "projdefs.h"
+#include "gpio_drv.h"
+#include "gpio_irq.h"
+#include "portmacro.h"
+
+/* gpio irq controller EE */
+#define IRQ_GPIO0_NUM	67
+#define IRQ_GPIO1_NUM	68
+#define IRQ_GPIO2_NUM	69
+#define IRQ_GPIO3_NUM	70
+
+/* gpio irq controller AO */
+#define IRQ_AO_GPIO0_NUM	17
+#define IRQ_AO_GPIO1_NUM	18
+
+
+#define EE_IRQ_REG_EDGE_POL	0x00
+#define EE_IRQ_REG_PIN_03_SEL	0x04
+#define EE_IRQ_REG_PIN_47_SEL	0x08
+#define EE_IRQ_REG_FILTER_SEL	0x0c
+
+#define EE_GPIO_IRQ_POL_EDGE_MASK(x)	(BIT(x) | BIT(16 + x))
+#define EE_GPIO_IRQ_POL(x)		BIT(16 + (x))
+#define EE_GPIO_IRQ_EDGE(x)		BIT(x)
+#define EE_GPIO_IRQ_FILTER_SHIFT(x)	((x) << 2)
+#define EE_GPIO_IRQ_SEL_SHIFT(x)	(((x) << 3) % 32)
+#define EE_GPIO_IRQ_BOTH(x)		BIT(8 + (x))
+
+#define AO_GPIO_NUM			10
+#define AO_GPIO_IRQ_POL_EDGE_MASK(x)	(BIT(16 + x) | BIT(18 + x))
+#define AO_GPIO_IRQ_POL(x)		BIT(16 + (x))
+#define AO_GPIO_IRQ_EDGE(x)		BIT(18 + (x))
+#define AO_GPIO_IRQ_FILTER_SHIFT(x)	(8 + ((x) << 2))
+#define AO_GPIO_IRQ_SEL_SHIFT(x)	((x) << 2)
+#define AO_GPIO_IRQ_BOTH(x)		(BIT((x) + 20))
+
+static const GpioDomain_t aoDomain = {
+	.name = "AO",
+	.rPullen = AO_GPIO_O_EN_N,
+	.rPull = AO_GPIO_O_EN_N,
+	.rGpio = AO_GPIO_O_EN_N,
+	.rMux = AO_RTI_PINMUX_REG0,
+	.rDrv = AO_PAD_DS_A,
+};
+
+static const GpioDomain_t eeDomain = {
+	.name = "EE",
+	.rPullen = PAD_PULL_UP_EN_REG0,
+	.rPull = PAD_PULL_UP_REG0,
+	.rGpio = PREG_PAD_GPIO0_EN_N,
+	.rMux = PERIPHS_PIN_MUX_0,
+	.rDrv = PAD_DS_REG0A,
+};
+
+static const GpioBank_t gpioBanks[BANK_NUM_MAX] = {
+			  /* pullen pull  dir    out   in     mux   drv*/
+	BANK("D", &aoDomain, 3, 0,  2, 0, 0, 0,  4, 0, 1, 0,  0, 0, 0, 0),
+	BANK("H", &eeDomain, 2, 0,  2, 0, 6, 0,  7, 0, 8, 0,  5, 0, 3, 0),
+	BANK("B", &eeDomain, 0, 0,  0, 0, 0, 0,  1, 0, 2, 0,  0, 0, 0, 0),
+	BANK("Z1", &eeDomain, 1, 0,  1, 0, 3, 0,  4, 0, 5, 0,  4, 0, 1, 0),
+	BANK("Z2", &eeDomain, 1, 7,  1, 7, 3, 7,  4, 7, 5, 7,  8, 0, 1, 14),
+	BANK("W", &eeDomain, 3, 0,  3, 0, 9, 0,  10, 0, 11, 0, 2,0, 5, 0),
+	BANK("E", &aoDomain, 3, 16, 2, 16, 0, 16, 4, 16, 1, 16, 1, 16, 1, 0),
+	BANK("M", &eeDomain, 4, 0, 4, 0, 12, 0, 13, 0, 14, 0, 0xa, 0, 6, 0),
+};
+
+static ParentIRQDesc_t eeIRQs[] = {
+	[GPIO_EE_IRQ_L0] = PARENT_IRQ_BK(NULL, 0, GPIO_INVALID, IRQ_GPIO0_NUM),
+	[GPIO_EE_IRQ_L1] = PARENT_IRQ_BK(NULL, 0, GPIO_INVALID, IRQ_GPIO1_NUM),
+	[GPIO_EE_IRQ_L2] = PARENT_IRQ_BK(NULL, 0, GPIO_INVALID, IRQ_GPIO2_NUM),
+	[GPIO_EE_IRQ_L3] = PARENT_IRQ_BK(NULL, 0, GPIO_INVALID, IRQ_GPIO3_NUM),
+};
+
+static ParentIRQDesc_t aoIRQs[] = {
+	[GPIO_AO_IRQ_L0] = PARENT_IRQ_BK(NULL, 0, GPIO_INVALID,
+					 IRQ_AO_GPIO0_NUM),
+	[GPIO_AO_IRQ_L1] = PARENT_IRQ_BK(NULL, 0, GPIO_INVALID,
+					 IRQ_AO_GPIO1_NUM),
+
+};
+
+static const GpioIRQBank_t irqBanks[BANK_NUM_MAX] = {
+	GPIO_IRQ_BK("D", 0, aoIRQs, ARRAY_SIZE(aoIRQs)),
+	GPIO_IRQ_BK("H", 11, eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("B", 33, eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("Z1", 47, eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("Z2", 55, eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("W", 67, eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("E", 80, eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("M", 83, eeIRQs, ARRAY_SIZE(eeIRQs)),
+};
+
+const GpioBank_t *pGetGpioBank(void)
+{
+	return gpioBanks;
+}
+
+const GpioIRQBank_t *pGetGpioIrqBank(void)
+{
+	return irqBanks;
+}
+
+static void prvGpioEEsetupIRQ(uint16_t irqNum, uint8_t line, uint32_t flags)
+{
+
+	uint32_t val = 0;
+
+	REG32_UPDATE_BITS(GPIO_EE_IRQ_BASE + EE_IRQ_REG_FILTER_SEL,
+			  0x7 << EE_GPIO_IRQ_FILTER_SHIFT(line),
+			  0x7 << EE_GPIO_IRQ_FILTER_SHIFT(line));
+
+	if (flags & IRQF_TRIGGER_BOTH) {
+		val |= EE_GPIO_IRQ_BOTH(line);
+		REG32_UPDATE_BITS(GPIO_EE_IRQ_BASE, EE_GPIO_IRQ_BOTH(line), val);
+		goto out;
+	}
+
+	if (flags & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING))
+		val |= EE_GPIO_IRQ_EDGE(line);
+
+	if (flags & (IRQF_TRIGGER_LOW | IRQF_TRIGGER_FALLING))
+		val |= EE_GPIO_IRQ_POL(line);
+
+	REG32_UPDATE_BITS(GPIO_EE_IRQ_BASE,
+			  EE_GPIO_IRQ_POL_EDGE_MASK(line), val);
+
+out:
+	REG32_UPDATE_BITS(GPIO_EE_IRQ_BASE + ((line > GPIO_EE_IRQ_L3) ?
+			  EE_IRQ_REG_PIN_47_SEL :
+			  EE_IRQ_REG_PIN_03_SEL),
+			  0xff << EE_GPIO_IRQ_SEL_SHIFT(line),
+			  irqNum << EE_GPIO_IRQ_SEL_SHIFT(line));
+
+}
+
+static void prvGpioAOsetupIRQ(uint16_t irqNum, uint8_t line, uint32_t flags)
+{
+	uint32_t val = 0;
+
+	if (flags & IRQF_TRIGGER_BOTH)
+		val |= AO_GPIO_IRQ_BOTH(line);
+
+	if (flags & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING))
+		val |= AO_GPIO_IRQ_EDGE(line);
+
+	if (flags & (IRQF_TRIGGER_LOW | IRQF_TRIGGER_FALLING))
+		val |= AO_GPIO_IRQ_POL(line);
+
+	val |= (0x7 << AO_GPIO_IRQ_FILTER_SHIFT(line));
+
+	val |= (irqNum << AO_GPIO_IRQ_SEL_SHIFT(line));
+
+	if (GPIO_AO_IRQ_BASE == 0)
+	return;
+
+	REG32_UPDATE_BITS(GPIO_AO_IRQ_BASE, (AO_GPIO_IRQ_POL_EDGE_MASK(line) | (AO_GPIO_IRQ_BOTH(line)) |
+			  (0x7 << AO_GPIO_IRQ_FILTER_SHIFT(line)) |
+			  (0xf << AO_GPIO_IRQ_SEL_SHIFT(line))), val);
+}
+
+void prvGpioPlatIrqSetup(uint16_t irqNum, uint8_t line, uint32_t flags)
+{
+	if (irqNum > AO_GPIO_NUM)
+		prvGpioEEsetupIRQ(irqNum, line, flags);
+	else
+		prvGpioAOsetupIRQ(irqNum, line, flags);
+
+}
+
diff --git a/bl30/src_ao/demos/amlogic/driver/gpio/gpio_t5w_plat.c b/bl30/src_ao/demos/amlogic/driver/gpio/gpio_t5w_plat.c
new file mode 100644
index 0000000..449fdf0
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/gpio/gpio_t5w_plat.c
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2014-2018 Amlogic, Inc. All rights reserved.
+ *
+ * All information contained herein is Amlogic confidential.
+ *
+ * This software is provided to you pursuant to Software License Agreement
+ * (SLA) with Amlogic Inc ("Amlogic"). This software may be used
+ * only in accordance with the terms of this agreement.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification is strictly prohibited without prior written permission from
+ * Amlogic.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER 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, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * gpio driver platform data
+ */
+#include "FreeRTOS.h"
+#include <register.h>
+#include <common.h>
+#include <gpio.h>
+#include "util.h"
+#include "projdefs.h"
+#include "gpio_drv.h"
+#include "gpio_irq.h"
+#include "portmacro.h"
+
+/* gpio irq controller EE */
+#define IRQ_GPIO0_NUM	67
+#define IRQ_GPIO1_NUM	68
+#define IRQ_GPIO2_NUM	69
+#define IRQ_GPIO3_NUM	70
+
+/* gpio irq controller AO */
+#define IRQ_AO_GPIO0_NUM	17
+#define IRQ_AO_GPIO1_NUM	18
+
+
+#define EE_IRQ_REG_EDGE_POL	0x00
+#define EE_IRQ_REG_PIN_03_SEL	0x04
+#define EE_IRQ_REG_PIN_47_SEL	0x08
+#define EE_IRQ_REG_FILTER_SEL	0x0c
+
+#define EE_GPIO_IRQ_POL_EDGE_MASK(x)	(BIT(x) | BIT(16 + x))
+#define EE_GPIO_IRQ_POL(x)		BIT(16 + (x))
+#define EE_GPIO_IRQ_EDGE(x)		BIT(x)
+#define EE_GPIO_IRQ_FILTER_SHIFT(x)	((x) << 2)
+#define EE_GPIO_IRQ_SEL_SHIFT(x)	(((x) << 3) % 32)
+#define EE_GPIO_IRQ_BOTH(x)		BIT(8 + (x))
+
+#define AO_GPIO_NUM			10
+#define AO_GPIO_IRQ_POL_EDGE_MASK(x)	(BIT(16 + x) | BIT(18 + x))
+#define AO_GPIO_IRQ_POL(x)		BIT(16 + (x))
+#define AO_GPIO_IRQ_EDGE(x)		BIT(18 + (x))
+#define AO_GPIO_IRQ_FILTER_SHIFT(x)	(8 + ((x) << 2))
+#define AO_GPIO_IRQ_SEL_SHIFT(x)	((x) << 2)
+#define AO_GPIO_IRQ_BOTH(x)		(BIT((x) + 20))
+
+static const GpioDomain_t aoDomain = {
+	.name = "AO",
+	.rPullen = AO_GPIO_O_EN_N,
+	.rPull = AO_GPIO_O_EN_N,
+	.rGpio = AO_GPIO_O_EN_N,
+	.rMux = AO_RTI_PINMUX_REG0,
+	.rDrv = AO_PAD_DS_A,
+};
+
+static const GpioDomain_t eeDomain = {
+	.name = "EE",
+	.rPullen = PAD_PULL_UP_EN_REG0,
+	.rPull = PAD_PULL_UP_REG0,
+	.rGpio = PREG_PAD_GPIO0_EN_N,
+	.rMux = PERIPHS_PIN_MUX_0,
+	.rDrv = PAD_DS_REG0A,
+};
+
+static const GpioBank_t gpioBanks[BANK_NUM_MAX] = {
+			  /* pullen pull  dir    out   in     mux   drv*/
+	BANK("D", &aoDomain, 3, 0,  2, 0, 0, 0,  4, 0, 1, 0,  0, 0, 0, 0),
+	BANK("H", &eeDomain, 2, 0,  2, 0, 6, 0,  7, 0, 8, 0,  5, 0, 3, 0),
+	BANK("B", &eeDomain, 0, 0,  0, 0, 0, 0,  1, 0, 2, 0,  0, 0, 0, 0),
+	BANK("Z1", &eeDomain, 1, 0,  1, 0, 3, 0,  4, 0, 5, 0,  4, 0, 1, 0),
+	BANK("Z2", &eeDomain, 1, 7,  1, 7, 3, 7,  4, 7, 5, 7,  8, 0, 1, 14),
+	BANK("W", &eeDomain, 3, 0,  3, 0, 9, 0,  10, 0, 11, 0, 2,0, 5, 0),
+	BANK("E", &aoDomain, 3, 16, 2, 16, 0, 16, 4, 16, 1, 16, 1, 16, 1, 16),
+	BANK("M", &eeDomain, 4, 0, 4, 0, 12, 0, 13, 0, 14, 0, 0xa, 0, 6, 0),
+	BANK("C1", &eeDomain, 5, 0, 5, 0, 16, 0, 17, 0, 18, 0, 0xf, 0, 0x28, 0),
+	BANK("C2", &eeDomain, 4, 8, 4, 8, 16, 8, 17, 8, 18, 8, 0x2a, 0, 0x28, 8),
+	BANK("H2", &eeDomain, 2, 24, 2, 24, 6, 24, 7, 24, 8, 24,  0x2b, 0, 3, 24),
+};
+
+static ParentIRQDesc_t eeIRQs[] = {
+	[GPIO_EE_IRQ_L0] = PARENT_IRQ_BK(NULL, 0, GPIO_INVALID, IRQ_GPIO0_NUM),
+	[GPIO_EE_IRQ_L1] = PARENT_IRQ_BK(NULL, 0, GPIO_INVALID, IRQ_GPIO1_NUM),
+	[GPIO_EE_IRQ_L2] = PARENT_IRQ_BK(NULL, 0, GPIO_INVALID, IRQ_GPIO2_NUM),
+	[GPIO_EE_IRQ_L3] = PARENT_IRQ_BK(NULL, 0, GPIO_INVALID, IRQ_GPIO3_NUM),
+};
+
+static ParentIRQDesc_t aoIRQs[] = {
+	[GPIO_AO_IRQ_L0] = PARENT_IRQ_BK(NULL, 0, GPIO_INVALID,
+					 IRQ_AO_GPIO0_NUM),
+	[GPIO_AO_IRQ_L1] = PARENT_IRQ_BK(NULL, 0, GPIO_INVALID,
+					 IRQ_AO_GPIO1_NUM),
+
+};
+
+static const GpioIRQBank_t irqBanks[BANK_NUM_MAX] = {
+	GPIO_IRQ_BK("D", 0, aoIRQs, ARRAY_SIZE(aoIRQs)),
+	GPIO_IRQ_BK("H", 11, eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("B", 52, eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("Z1", 66, eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("Z2", 74, eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("W", 86, eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("E", 99, eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("M", 101, eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("C1", 37, eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("C2", 45, eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("H2", 35, eeIRQs, ARRAY_SIZE(eeIRQs)),
+};
+
+const GpioBank_t *pGetGpioBank(void)
+{
+	return gpioBanks;
+}
+
+const GpioIRQBank_t *pGetGpioIrqBank(void)
+{
+	return irqBanks;
+}
+
+static void prvGpioEEsetupIRQ(uint16_t irqNum, uint8_t line, uint32_t flags)
+{
+
+	uint32_t val = 0;
+
+	REG32_UPDATE_BITS(GPIO_EE_IRQ_BASE + EE_IRQ_REG_FILTER_SEL,
+			  0x7 << EE_GPIO_IRQ_FILTER_SHIFT(line),
+			  0x7 << EE_GPIO_IRQ_FILTER_SHIFT(line));
+
+	if (flags & IRQF_TRIGGER_BOTH) {
+		val |= EE_GPIO_IRQ_BOTH(line);
+		REG32_UPDATE_BITS(GPIO_EE_IRQ_BASE, EE_GPIO_IRQ_BOTH(line), val);
+		goto out;
+	}
+
+	if (flags & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING))
+		val |= EE_GPIO_IRQ_EDGE(line);
+
+	if (flags & (IRQF_TRIGGER_LOW | IRQF_TRIGGER_FALLING))
+		val |= EE_GPIO_IRQ_POL(line);
+
+	REG32_UPDATE_BITS(GPIO_EE_IRQ_BASE,
+			  EE_GPIO_IRQ_POL_EDGE_MASK(line), val);
+
+out:
+	REG32_UPDATE_BITS(GPIO_EE_IRQ_BASE + ((line > GPIO_EE_IRQ_L3) ?
+			  EE_IRQ_REG_PIN_47_SEL :
+			  EE_IRQ_REG_PIN_03_SEL),
+			  0xff << EE_GPIO_IRQ_SEL_SHIFT(line),
+			  irqNum << EE_GPIO_IRQ_SEL_SHIFT(line));
+
+}
+
+static void prvGpioAOsetupIRQ(uint16_t irqNum, uint8_t line, uint32_t flags)
+{
+	uint32_t val = 0;
+
+	if (flags & IRQF_TRIGGER_BOTH)
+		val |= AO_GPIO_IRQ_BOTH(line);
+
+	if (flags & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING))
+		val |= AO_GPIO_IRQ_EDGE(line);
+
+	if (flags & (IRQF_TRIGGER_LOW | IRQF_TRIGGER_FALLING))
+		val |= AO_GPIO_IRQ_POL(line);
+
+	val |= (0x7 << AO_GPIO_IRQ_FILTER_SHIFT(line));
+
+	val |= (irqNum << AO_GPIO_IRQ_SEL_SHIFT(line));
+
+	if (GPIO_AO_IRQ_BASE == 0)
+	return;
+
+	REG32_UPDATE_BITS(GPIO_AO_IRQ_BASE, (AO_GPIO_IRQ_POL_EDGE_MASK(line) | (AO_GPIO_IRQ_BOTH(line)) |
+			  (0x7 << AO_GPIO_IRQ_FILTER_SHIFT(line)) |
+			  (0xf << AO_GPIO_IRQ_SEL_SHIFT(line))), val);
+}
+
+void prvGpioPlatIrqSetup(uint16_t irqNum, uint8_t line, uint32_t flags)
+{
+	if (irqNum > AO_GPIO_NUM)
+		prvGpioEEsetupIRQ(irqNum, line, flags);
+	else
+		prvGpioAOsetupIRQ(irqNum, line, flags);
+
+}
+
diff --git a/bl30/src_ao/demos/amlogic/driver/gpio/gpio_t7_plat.c b/bl30/src_ao/demos/amlogic/driver/gpio/gpio_t7_plat.c
new file mode 100644
index 0000000..654ab23
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/gpio/gpio_t7_plat.c
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2014-2018 Amlogic, Inc. All rights reserved.
+ *
+ * All information contained herein is Amlogic confidential.
+ *
+ * This software is provided to you pursuant to Software License Agreement
+ * (SLA) with Amlogic Inc ("Amlogic"). This software may be used
+ * only in accordance with the terms of this agreement.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification is strictly prohibited without prior written permission from
+ * Amlogic.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER 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, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * gpio driver platform data
+ */
+#include "FreeRTOS.h"
+#include <register.h>
+#include <common.h>
+#include <gpio.h>
+#include "util.h"
+#include "projdefs.h"
+#include "gpio_drv.h"
+#include "gpio_irq.h"
+#include "portmacro.h"
+
+/* gpio irq controller */
+#define IRQ_GPIO0_NUM 10
+#define IRQ_GPIO1_NUM 11
+#define IRQ_GPIO2_NUM 12
+#define IRQ_GPIO3_NUM 13
+#define IRQ_GPIO4_NUM 14
+#define IRQ_GPIO5_NUM 15
+#define IRQ_GPIO6_NUM 16
+#define IRQ_GPIO7_NUM 17
+
+#define REG_PIN_SC2_SEL			0x04
+#define REG_EDGE_POL_EXTR		0x1c
+#define REG_EDGE_POL_MASK_SC2(x)			\
+	({typeof(x) _x = (x); BIT(_x) | BIT(12 + (_x)); })
+#define GPIO_IRQ_FILTER_SHIFT(x)	(((x) % 2 == 0) ? 8 : 24)
+#define GPIO_IRQ_POL_SHIFT(x)		(BIT(0 + (x)))
+#define GPIO_IRQ_EDGE_SHIFT(x)		(BIT(12 + (x)))
+#define GPIO_IRQ_BOTH_SHIFT(x)		(BIT(0 + (x)))
+
+static const GpioDomain_t eeDomain = {
+	.name = "EE",
+	.rPullen = PADCTRL_GPIOD_I,
+	.rPull = PADCTRL_GPIOD_I,
+	.rGpio = PADCTRL_GPIOD_I,
+	.rMux = PADCTRL_PIN_MUX_REG0,
+	.rDrv = PADCTRL_GPIOD_I,
+};
+
+static const GpioBank_t gpioBanks[BANK_NUM_MAX] = {
+			  /* pullen   pull    dir       out      in      mux */
+	BANK("D", &eeDomain, 0x03, 0, 0x04, 0, 0x02, 0, 0x01, 0, 0x00, 0, 0x0a,
+		/* drv */
+	     0, 0x07, 0),
+	BANK("E", &eeDomain, 0x0b, 0, 0x0c, 0, 0x0a, 0, 0x09, 0, 0x08, 0, 0x0c,
+	     0, 0x0f, 0),
+	BANK("Z", &eeDomain, 0x13, 0, 0x14, 0, 0x12, 0, 0x11, 0, 0x10, 0, 0x05,
+	     0, 0x17, 0),
+	BANK("H", &eeDomain, 0x1b, 0, 0x1c, 0, 0x1a, 0, 0x19, 0, 0x18, 0, 0x08,
+	     0, 0x1f, 0),
+	BANK("C", &eeDomain, 0x23, 0, 0x24, 0, 0x22, 0, 0x21, 0, 0x20, 0, 0x07,
+	     0, 0x27, 0),
+	BANK("B", &eeDomain, 0x2b, 0, 0x2c, 0, 0x2a, 0, 0x29, 0, 0x28, 0, 0x00,
+	     0, 0x2f, 0),
+	BANK("X", &eeDomain, 0x33, 0, 0x34, 0, 0x32, 0, 0x31, 0, 0x30, 0, 0x02,
+	     0, 0x37, 0),
+	BANK("T", &eeDomain, 0x43, 0, 0x44, 0, 0x42, 0, 0x41, 0, 0x40, 0, 0x0f,
+	     0, 0x47, 0),
+	BANK("Y", &eeDomain, 0x53, 0, 0x54, 0, 0x52, 0, 0x51, 0, 0x50, 0, 0x13,
+	     0, 0x57, 0),
+	BANK("W", &eeDomain, 0x63, 0, 0x64, 0, 0x62, 0, 0x61, 0, 0x60, 0, 0x16,
+	     0, 0x67, 0),
+	BANK("M", &eeDomain, 0x73, 0, 0x74, 0, 0x72, 0, 0x71, 0, 0x70, 0, 0x0d,
+	     0, 0x77, 0),
+	BANK("TEST_N", &eeDomain, 0x83, 0, 0x84, 0, 0x82, 0, 0x81, 0, 0x80, 0,
+	     0x09, 0, 0x87, 0),
+};
+
+static ParentIRQDesc_t eeIRQs[] = {
+	[GPIO_EE_IRQ_L0] = PARENT_IRQ_BK(NULL, 0, GPIO_INVALID, IRQ_GPIO0_NUM),
+	[GPIO_EE_IRQ_L1] = PARENT_IRQ_BK(NULL, 0, GPIO_INVALID, IRQ_GPIO1_NUM),
+	[GPIO_EE_IRQ_L2] = PARENT_IRQ_BK(NULL, 0, GPIO_INVALID, IRQ_GPIO2_NUM),
+	[GPIO_EE_IRQ_L3] = PARENT_IRQ_BK(NULL, 0, GPIO_INVALID, IRQ_GPIO3_NUM),
+	[GPIO_EE_IRQ_L4] = PARENT_IRQ_BK(NULL, 0, GPIO_INVALID, IRQ_GPIO4_NUM),
+	[GPIO_EE_IRQ_L5] = PARENT_IRQ_BK(NULL, 0, GPIO_INVALID, IRQ_GPIO5_NUM),
+	[GPIO_EE_IRQ_L6] = PARENT_IRQ_BK(NULL, 0, GPIO_INVALID, IRQ_GPIO6_NUM),
+	[GPIO_EE_IRQ_L7] = PARENT_IRQ_BK(NULL, 0, GPIO_INVALID, IRQ_GPIO7_NUM),
+};
+
+/* need real gpio irq number */
+static const GpioIRQBank_t irqBanks[BANK_NUM_MAX] = {
+	GPIO_IRQ_BK("D", 57,  eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("E", 70,  eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("Z", 77,  eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("H", 148, eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("C", 13,  eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("B", 0,   eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("X", 20,  eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("T", 91,  eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("Y", 129, eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("W", 40,  eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("M", 115, eeIRQs, ARRAY_SIZE(eeIRQs)),
+	GPIO_IRQ_BK("TEST_N", 156, eeIRQs, ARRAY_SIZE(eeIRQs)),
+};
+
+const GpioBank_t *pGetGpioBank(void)
+{
+	return gpioBanks;
+}
+
+const GpioIRQBank_t *pGetGpioIrqBank(void)
+{
+	return irqBanks;
+}
+
+void prvGpioPlatIrqSetup(uint16_t irqNum, uint8_t line, uint32_t flags)
+{
+	uint32_t val = 0;
+	uint32_t reg_offset = 0;
+	uint16_t bit_offset = 0;
+
+	bit_offset = ((line % 2) == 0) ? 0 : 16;
+	reg_offset = REG_PIN_SC2_SEL + ((line / 2) << 2);
+
+	/* clear both edge */
+	REG32_UPDATE_BITS(GPIO_EE_IRQ_BASE + REG_EDGE_POL_EXTR,
+			  GPIO_IRQ_BOTH_SHIFT(line), 0);
+
+	/* set filter */
+	REG32_UPDATE_BITS(GPIO_EE_IRQ_BASE + reg_offset,
+			  0x7 << GPIO_IRQ_FILTER_SHIFT(line),
+			  0x7 << GPIO_IRQ_FILTER_SHIFT(line));
+
+	/* select trigger pin */
+	REG32_UPDATE_BITS(GPIO_EE_IRQ_BASE + reg_offset,
+			  0xff << bit_offset, irqNum << bit_offset);
+
+	/* set trigger both type */
+	if (flags & IRQF_TRIGGER_BOTH) {
+		val |= GPIO_IRQ_BOTH_SHIFT(line);
+		REG32_UPDATE_BITS(GPIO_EE_IRQ_BASE + REG_EDGE_POL_EXTR,
+				  GPIO_IRQ_BOTH_SHIFT(line), val);
+		return;
+	}
+
+	/* set trigger single edge or level  type */
+	if (flags & (IRQF_TRIGGER_LOW | IRQF_TRIGGER_FALLING))
+		val |= GPIO_IRQ_POL_SHIFT(line);
+
+	if (flags & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING))
+		val |= GPIO_IRQ_EDGE_SHIFT(line);
+
+	REG32_UPDATE_BITS(GPIO_EE_IRQ_BASE, REG_EDGE_POL_MASK_SC2(line), val);
+
+}
+
diff --git a/bl30/src_ao/demos/amlogic/driver/hdmirx/t7_common/build.mk b/bl30/src_ao/demos/amlogic/driver/hdmirx/t7_common/build.mk
new file mode 100644
index 0000000..930fc4b
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/hdmirx/t7_common/build.mk
@@ -0,0 +1,26 @@
+#
+#  Copyright (C) 2014-2018 Amlogic, Inc. All rights reserved.
+#
+#  All information contained herein is Amlogic confidential.
+#
+#  This software is provided to you pursuant to Software License Agreement
+#  (SLA) with Amlogic Inc ("Amlogic"). This software may be used
+#  only in accordance with the terms of this agreement.
+#
+#  Redistribution and use in source and binary forms, with or without
+#  modification is strictly prohibited without prior written permission from
+#  Amlogic.
+#
+#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#  OWNER 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, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+t7_common-y = hdmirx_wake.o
diff --git a/bl30/src_ao/demos/amlogic/driver/hdmirx/t7_common/hdmirx_wake.c b/bl30/src_ao/demos/amlogic/driver/hdmirx/t7_common/hdmirx_wake.c
new file mode 100644
index 0000000..aee403a
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/hdmirx/t7_common/hdmirx_wake.c
@@ -0,0 +1,67 @@
+#include <string.h>
+#include "FreeRTOS.h"
+#include "suspend.h"
+#include "task.h"
+#include "gpio.h"
+
+#include "queue.h"    /* RTOS queue related API prototypes. */
+#include "timers.h"   /* Software timer related API prototypes. */
+#include "semphr.h"   /* Semaphore related API prototypes. */
+#include "hdmirx_wake.h"
+
+#define GPIO_HDMI_RX1_POWER	GPIOW_1
+#define GPIO_HDMI_RX2_POWER	GPIOW_9
+#define GPIO_HDMI_RX3_POWER	GPIOW_5
+
+static void hdmirx_IRQHandle(void)
+{
+	uint32_t buf[4] = {0};
+
+	vDisableGpioIRQ(GPIO_HDMI_RX1_POWER);
+	vDisableGpioIRQ(GPIO_HDMI_RX2_POWER);
+	vDisableGpioIRQ(GPIO_HDMI_RX3_POWER);
+	if (xGpioGetValue(GPIO_HDMI_RX1_POWER) ||
+		xGpioGetValue(GPIO_HDMI_RX2_POWER) ||
+		xGpioGetValue(GPIO_HDMI_RX3_POWER)) {
+		buf[0] = HDMI_RX_WAKEUP;
+		INFO("hdmirx_5v A/B/C input lvl: %d :%d :%d",
+			xGpioGetValue(GPIO_HDMI_RX1_POWER),
+			xGpioGetValue(GPIO_HDMI_RX2_POWER),
+			xGpioGetValue(GPIO_HDMI_RX3_POWER));
+	}
+	STR_Wakeup_src_Queue_Send_FromISR(buf);
+}
+
+void hdmirx_GpioIRQRegister(void)
+{
+	/* clear pinmux */
+	xPinmuxSet(GPIO_HDMI_RX1_POWER, PIN_FUNC0);
+	xPinmuxSet(GPIO_HDMI_RX2_POWER, PIN_FUNC0);
+	xPinmuxSet(GPIO_HDMI_RX3_POWER, PIN_FUNC0);
+
+	xGpioSetDir(GPIO_HDMI_RX1_POWER, GPIO_DIR_IN);
+	xGpioSetDir(GPIO_HDMI_RX2_POWER, GPIO_DIR_IN);
+	xGpioSetDir(GPIO_HDMI_RX3_POWER, GPIO_DIR_IN);
+
+	INFO("hdmi_5v A/B/C input lvl: %d :%d :%d",
+		xGpioGetValue(GPIO_HDMI_RX1_POWER),
+		xGpioGetValue(GPIO_HDMI_RX2_POWER),
+		xGpioGetValue(GPIO_HDMI_RX3_POWER));
+
+	xRequestGpioIRQ(GPIO_HDMI_RX1_POWER, hdmirx_IRQHandle, IRQF_TRIGGER_RISING);
+	xRequestGpioIRQ(GPIO_HDMI_RX2_POWER, hdmirx_IRQHandle, IRQF_TRIGGER_RISING);
+	xRequestGpioIRQ(GPIO_HDMI_RX3_POWER, hdmirx_IRQHandle, IRQF_TRIGGER_RISING);
+}
+
+void hdmirx_GpioIRQFree(void)
+{
+	vFreeGpioIRQ(GPIO_HDMI_RX1_POWER);
+	vFreeGpioIRQ(GPIO_HDMI_RX2_POWER);
+	vFreeGpioIRQ(GPIO_HDMI_RX3_POWER);
+	/* recovery pinmux */
+	xPinmuxSet(GPIO_HDMI_RX1_POWER, PIN_FUNC1);
+	xPinmuxSet(GPIO_HDMI_RX2_POWER, PIN_FUNC1);
+	xPinmuxSet(GPIO_HDMI_RX3_POWER, PIN_FUNC1);
+}
+
+
diff --git a/bl30/src_ao/demos/amlogic/driver/i2c/build.mk b/bl30/src_ao/demos/amlogic/driver/i2c/build.mk
new file mode 100644
index 0000000..fc351c4
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/i2c/build.mk
@@ -0,0 +1,27 @@
+ #
+ #  Copyright (C) 2014-2018 Amlogic, Inc. All rights reserved.
+ #
+ #  All information contained herein is Amlogic confidential.
+ #
+ #  This software is provided to you pursuant to Software License Agreement
+ #  (SLA) with Amlogic Inc ("Amlogic"). This software may be used
+ #  only in accordance with the terms of this agreement.
+ #
+ #  Redistribution and use in source and binary forms, with or without
+ #  modification is strictly prohibited without prior written permission from
+ #  Amlogic.
+ #
+ #  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ #  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ #  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ #  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ #  OWNER 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, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ #
+
+i2c-y = i2c.o ${SOC}_plat.o
diff --git a/bl30/src_ao/demos/amlogic/driver/i2c/i2c.c b/bl30/src_ao/demos/amlogic/driver/i2c/i2c.c
new file mode 100644
index 0000000..07279f3
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/i2c/i2c.c
@@ -0,0 +1,503 @@
+/*
+ * Copyright (C)2018 Amlogic, Inc. All rights reserved.
+ *
+ * All information contained herein is Amlogic confidential.
+ *
+ * This software is provided to you pursuant to Software License Agreement
+ * (SLA) with Amlogic Inc ("Amlogic"). This software may be used
+ * only in accordance with the terms of this agreement.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification is strictly prohibited without prior written permission from
+ * Amlogic.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER 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, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * Author:  Jian Hu <jian.hu@amlogic.com>
+ */
+
+#include "common.h"
+#include "uart.h"
+#include "FreeRTOS.h"
+#include <task.h>
+#include "meson_i2c.h"
+#include <util.h>
+#include "timer_source.h"
+
+#define BIT(nr)			(1UL << (nr))
+#define GENMASK(h, l) \
+(((~0UL) << (l)) & (~0UL >> (BITS_PER_LONG - 1 - (h))))
+
+#define I2C_TIMEOUT_MS			1000*100
+
+/* Control register fields */
+#define REG_CTRL_START			BIT(0)
+#define REG_CTRL_ACK_IGNORE		BIT(1)
+#define REG_CTRL_STATUS			BIT(2)
+#define REG_CTRL_ERROR			BIT(3)
+#define REG_CTRL_CLKDIV_SHIFT		12
+#define REG_CTRL_CLKDIV_MASK		GENMASK(21, 12)
+#define REG_CTRL_CLKDIVEXT_SHIFT	28
+#define REG_CTRL_CLKDIVEXT_MASK		GENMASK(29, 28)
+
+#define I2C_DEBUG			0
+
+typedef enum { false, true } bool;
+
+enum {
+	TOKEN_END = 0,
+	TOKEN_START,
+	TOKEN_SLAVE_ADDR_WRITE,
+	TOKEN_SLAVE_ADDR_READ,
+	TOKEN_DATA,
+	TOKEN_DATA_LAST,
+	TOKEN_STOP,
+};
+
+struct xI2cRegs {
+	uint32_t ctrl;
+	uint32_t slave_addr;
+	uint32_t tok_list0;
+	uint32_t tok_list1;
+	uint32_t tok_wdata0;
+	uint32_t tok_wdata1;
+	uint32_t tok_rdata0;
+	uint32_t tok_rdata1;
+};
+
+struct xMesonI2c {
+	struct xI2cRegs *regs;
+	struct xI2cMsg *msg;	/* Current I2C message */
+	bool last;		/* Whether the message is the last */
+	uint32_t count;		/* Number of bytes in the current transfer */
+	uint32_t pos;		/* Position of current transfer in message */
+	uint32_t tokens[2];	/* Sequence of tokens to be written */
+	uint32_t num_tokens;	/* Number of tokens to be written */
+	uint32_t clock_frequency;
+	uint32_t div_factor;
+	uint32_t delay_adjust;
+	uint32_t clkin_rate;
+};
+
+struct xMesonI2c i2cs[11];
+struct xMesonI2cPlatdata *plat;
+
+uint32_t current_id;
+
+#define DEFAULT_CLK81	0
+
+/* AXG/G12A/G12B/SM1/TM2 i2c data */
+struct xMesonI2cPlatdata AxgI2cData[] = {
+	{0, 0xffd1f000, 3, 15, 100000, MESON_I2C_CLK_RATE, DEFAULT_CLK81, 0},
+	{1, 0xffd1e000, 3, 15, 100000, MESON_I2C_CLK_RATE, DEFAULT_CLK81, 0},
+	{2, 0xffd1d000, 3, 15, 100000, MESON_I2C_CLK_RATE, DEFAULT_CLK81, 0},
+	{3, 0xffd1c000, 3, 15, 100000, MESON_I2C_CLK_RATE, DEFAULT_CLK81, 0},
+	{4, 0xff805000, 3, 15, 100000, MESON_I2C_CLK_RATE, DEFAULT_CLK81, 0},
+};
+
+/* A1 i2c data */
+struct xMesonI2cPlatdata A1I2cData[] = {
+	{0, 0xfe001400, 3, 15, 100000, 64000000, DEFAULT_CLK81, 0},	/* i2c A */
+	{1, 0xfe005c00, 3, 15, 100000, 64000000, DEFAULT_CLK81, 0},	/* i2c B */
+	{2, 0xfe006800, 3, 15, 100000, 64000000, DEFAULT_CLK81, 0},	/* i2c C */
+	{3, 0xfe006c00, 3, 15, 100000, 64000000, DEFAULT_CLK81, 0},	/* i2c D */
+};
+
+/* C1 i2c data */
+struct xMesonI2cPlatdata C1I2cData[] = {
+	{0, 0xfe001400, 3, 15, 100000, MESON_I2C_CLK_RATE, DEFAULT_CLK81, 0},	/* i2c A */
+	{1, 0xfe005c00, 3, 15, 100000, MESON_I2C_CLK_RATE, DEFAULT_CLK81, 0},	/* i2c B */
+	{2, 0xfe006800, 3, 15, 100000, MESON_I2C_CLK_RATE, DEFAULT_CLK81, 0},	/* i2c C */
+	{3, 0xfe006c00, 3, 15, 100000, MESON_I2C_CLK_RATE, DEFAULT_CLK81, 0},	/* i2c D */
+	{4, 0xfe00b000, 3, 15, 100000, MESON_I2C_CLK_RATE, DEFAULT_CLK81, 0},	/* i2c E */
+};
+
+static void prvSetBitsLe32(uint32_t *reg, uint32_t set)
+{
+	uint32_t val;
+
+	val = REG32(reg);
+	val |= (set);
+	REG32(reg) = val;
+}
+
+static void prvClrBitsLe32(uint32_t *reg, uint32_t clr)
+{
+	uint32_t val;
+
+	val = REG32(reg);
+	val &= (~(clr));
+	REG32(reg) = val;
+}
+
+static void prvClrSetBitsLe32(uint32_t *reg, uint32_t clr, uint32_t set)
+{
+	uint32_t val;
+
+	val = REG32(reg);
+	val &= (~(clr));
+	val |= (set);
+	REG32(reg) = val;
+}
+
+void xI2cDumpRegs(void)
+{
+	iprintf("i2c reg : 0x%x = 0x%x\n", &i2cs[current_id].regs->ctrl,
+		i2cs[current_id].regs->ctrl);
+	iprintf("i2c reg : 0x%x = 0x%x\n", &i2cs[current_id].regs->slave_addr,
+		i2cs[current_id].regs->slave_addr);
+	iprintf("i2c reg : 0x%x = 0x%x\n", &i2cs[current_id].regs->tok_list0,
+		i2cs[current_id].regs->tok_list0);
+	iprintf("i2c reg : 0x%x = 0x%x\n", &i2cs[current_id].regs->tok_list1,
+		i2cs[current_id].regs->tok_list1);
+	iprintf("i2c reg : 0x%x = 0x%x\n", &i2cs[current_id].regs->tok_wdata0,
+		i2cs[current_id].regs->tok_wdata0);
+	iprintf("i2c reg : 0x%x = 0x%x\n", &i2cs[current_id].regs->tok_wdata1,
+		i2cs[current_id].regs->tok_wdata1);
+	iprintf("i2c reg : 0x%x = 0x%x\n", &i2cs[current_id].regs->tok_rdata0,
+		i2cs[current_id].regs->tok_rdata0);
+	iprintf("i2c reg : 0x%x = 0x%x\n", &i2cs[current_id].regs->tok_rdata1,
+		i2cs[current_id].regs->tok_rdata1);
+}
+
+static void prvMesonI2cRegsInit(void)
+{
+	uint32_t i;
+
+	for (i = 0; i < 8; i++)
+		REG32(&i2cs[current_id].regs->ctrl + i) = 0;
+}
+
+static void prvMesonI2cResetTokens(void)
+{
+	i2cs[current_id].tokens[0] = 0;
+	i2cs[current_id].tokens[1] = 0;
+	i2cs[current_id].num_tokens = 0;
+}
+
+static void prvMesonI2cAddToken(uint32_t token)
+{
+	if (i2cs[current_id].num_tokens < 8)
+		i2cs[current_id].tokens[0] |=
+		    (token & 0xf) << (i2cs[current_id].num_tokens * 4);
+	else
+		i2cs[current_id].tokens[1] |=
+		    (token & 0xf) << ((i2cs[current_id].num_tokens % 8) * 4);
+
+	i2cs[current_id].num_tokens++;
+}
+
+/*
+ * Retrieve data for the current transfer (which can be at most 8
+ * bytes) from the device internal buffer.
+ */
+static void prvMesonI2cGetData(uint8_t *buf, uint32_t len)
+{
+	uint32_t rdata0, rdata1;
+	uint32_t i;
+
+	rdata0 = i2cs[current_id].regs->tok_rdata0;
+	rdata1 = i2cs[current_id].regs->tok_rdata1;
+
+#if I2C_DEBUG
+	iprintf("meson i2c: read data %08x %08x len %d\n", rdata0, rdata1, len);
+#endif
+
+	for (i = 0; i < MIN((uint32_t) 4, len); i++)
+		*buf++ = (rdata0 >> i * 8) & 0xff;
+
+	for (i = 4; i < MIN((uint32_t) 8, len); i++)
+		*buf++ = (rdata1 >> (i - 4) * 8) & 0xff;
+}
+
+/*
+ * Write data for the current transfer (which can be at most 8 bytes)
+ * to the device internal buffer.
+ */
+static void prvMesonI2cPutData(uint8_t *buf, uint32_t len)
+{
+	uint32_t wdata0 = 0, wdata1 = 0;
+	uint32_t i;
+
+	for (i = 0; i < MIN((uint32_t) 4, len); i++)
+		wdata0 |= *buf++ << (i * 8);
+
+	for (i = 4; i < MIN((uint32_t) 8, len); i++)
+		wdata1 |= *buf++ << ((i - 4) * 8);
+
+	i2cs[current_id].regs->tok_wdata0 = wdata0;
+	i2cs[current_id].regs->tok_wdata1 = wdata1;
+
+#if I2C_DEBUG
+	iprintf("meson i2c: write data 0x%08x 0x%08x len %d\n", wdata0, wdata1,
+		len);
+#endif
+}
+
+/*
+ * Prepare the next transfer: pick the next 8 bytes in the remaining
+ * part of message and write tokens and data (if needed) to the
+ * device.
+ */
+static void prvMesonI2cPrepareXfer(void)
+{
+	bool write = !(i2cs[current_id].msg->flags & I2C_M_RD);
+	uint32_t i;
+
+	i2cs[current_id].count =
+	    MIN(i2cs[current_id].msg->len - i2cs[current_id].pos, 8u);
+
+	for (i = 0; i + 1 < i2cs[current_id].count; i++)
+		prvMesonI2cAddToken(TOKEN_DATA);
+
+	if (i2cs[current_id].count) {
+		if (write
+		    || i2cs[current_id].pos + i2cs[current_id].count <
+		    i2cs[current_id].msg->len)
+			prvMesonI2cAddToken(TOKEN_DATA);
+		else
+			prvMesonI2cAddToken(TOKEN_DATA_LAST);
+	}
+
+	if (write)
+		prvMesonI2cPutData(i2cs[current_id].msg->buf +
+				   i2cs[current_id].pos,
+				   i2cs[current_id].count);
+
+	if (i2cs[current_id].last
+	    && i2cs[current_id].pos + i2cs[current_id].count >=
+	    i2cs[current_id].msg->len)
+		prvMesonI2cAddToken(TOKEN_STOP);
+
+	i2cs[current_id].regs->tok_list0 = i2cs[current_id].tokens[0];
+	i2cs[current_id].regs->tok_list1 = i2cs[current_id].tokens[1];
+}
+
+static void prvMesonI2cDoStart(struct xI2cMsg *msg)
+{
+	uint32_t token;
+
+	token = (msg->flags & I2C_M_RD) ? TOKEN_SLAVE_ADDR_READ :
+	    TOKEN_SLAVE_ADDR_WRITE;
+	/* change it if duty change */
+	i2cs[current_id].regs->slave_addr = msg->addr << 1;
+	prvMesonI2cAddToken(TOKEN_START);
+	prvMesonI2cAddToken(token);
+}
+
+static int32_t prvMesonI2cXferMsg(struct xI2cMsg *msg, uint32_t last)
+{
+	uint32_t time_count = 0;
+	uint32_t *ctrl = &i2cs[current_id].regs->ctrl;
+
+	taskENTER_CRITICAL();
+#if I2C_DEBUG
+	iprintf("meson i2c: %s addr 0x%x len %u\n",
+		(msg->flags & I2C_M_RD) ? "read" : "write",
+		msg->addr, msg->len);
+#endif
+	i2cs[current_id].msg = msg;
+	i2cs[current_id].last = last;
+	i2cs[current_id].pos = 0;
+	i2cs[current_id].count = 0;
+
+	prvMesonI2cResetTokens();
+	prvMesonI2cDoStart(msg);
+
+	do {
+		prvMesonI2cPrepareXfer();
+		/* start the transfer */
+		prvSetBitsLe32(&(i2cs[current_id].regs->ctrl), REG_CTRL_START);
+		while (REG32(ctrl) & REG_CTRL_STATUS) {
+			if (time_count > I2C_TIMEOUT_MS) {
+				prvClrBitsLe32(&i2cs[current_id].regs->ctrl,
+					       REG_CTRL_START);
+				iprintf("meson i2c: timeout\n");
+				return -1;
+			}
+			udelay(1);
+			time_count++;
+		}
+		prvMesonI2cResetTokens();
+		prvClrBitsLe32(&i2cs[current_id].regs->ctrl, REG_CTRL_START);
+
+		if (REG32(ctrl) & REG_CTRL_ERROR) {
+			iprintf("meson i2c: error(0x%x)\n", REG32(ctrl));
+			return -1;
+		}
+
+		if ((msg->flags & I2C_M_RD) && i2cs[current_id].count) {
+			prvMesonI2cGetData(i2cs[current_id].msg->buf +
+					   i2cs[current_id].pos,
+					   i2cs[current_id].count);
+		}
+		i2cs[current_id].pos += i2cs[current_id].count;
+
+	} while (i2cs[current_id].pos < msg->len);
+	taskEXIT_CRITICAL();
+
+	return 0;
+}
+
+int32_t xI2cMesonXfer(struct xI2cMsg *msg, uint32_t nmsgs)
+{
+	uint32_t i;
+	int32_t ret;
+
+	for (i = 0; i < nmsgs; i++) {
+		ret = prvMesonI2cXferMsg(msg + i, i == (nmsgs - 1));
+		if (ret) {
+			iprintf("meson_i2c_xfer  error\n");
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+int32_t xI2cMesonSetBusSpeed(uint32_t speed)
+{
+	uint32_t clk_rate = i2cs[current_id].clkin_rate;
+	uint32_t div;
+
+	taskENTER_CRITICAL();
+	div = DIV_ROUND_UP(clk_rate, speed * i2cs[current_id].div_factor);
+
+	/* clock divider has 12 bits */
+	if (div >= (1 << 12)) {
+		iprintf("meson i2c: requested bus frequency too low\n");
+		div = (1 << 12) - 1;
+	}
+	prvClrSetBitsLe32(&i2cs[current_id].regs->ctrl, REG_CTRL_CLKDIV_MASK,
+			  (div & GENMASK(9, 0)) << REG_CTRL_CLKDIV_SHIFT);
+
+	prvClrSetBitsLe32(&i2cs[current_id].regs->ctrl, REG_CTRL_CLKDIVEXT_MASK,
+			  (div >> 10) << REG_CTRL_CLKDIVEXT_SHIFT);
+	taskEXIT_CRITICAL();
+
+	return 0;
+}
+
+int32_t xI2cMesonRead(uint32_t addr, uint8_t offset,
+		      uint8_t *buffer, uint32_t len)
+{
+	struct xI2cMsg msg[2], *ptr;
+	uint32_t msg_count;
+	int32_t ret;
+
+	if (!len) {
+		iprintf("invalid length\n");
+		return -1;
+	}
+
+	ptr = msg;
+
+	ptr->addr = addr;
+	ptr->flags = 0;
+	ptr->len = 1;
+	ptr->buf = &offset;
+	ptr++;
+
+	ptr->addr = addr;
+	ptr->flags = I2C_M_RD;
+	ptr->len = len;
+	ptr->buf = buffer;
+	ptr++;
+
+	msg_count = ptr - msg;
+	ret = xI2cMesonXfer(msg, msg_count);
+	if (ret < 0) {
+		iprintf("i2c transfer read failed\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+int32_t xI2cMesonWrite(uint32_t addr, uint8_t offset,
+		       uint8_t *buffer, uint32_t len)
+{
+	struct xI2cMsg msg[1];
+	int32_t ret = 0;
+	uint8_t buf[len + 1];
+
+	buf[0] = offset;
+
+	msg->addr = addr;
+	msg->len = len + 1;	/* addr's length + len */
+	msg->buf = buf;
+	msg->flags = 0;
+
+	memcpy(&buf[1], buffer, len);
+	ret = xI2cMesonXfer(msg, 1);
+	if (ret < 0) {
+		iprintf("i2c transfer write failed\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+extern uint32_t suspend_flag;
+/*
+ *i2c master platform data init
+ */
+int32_t xI2cMesonPortInit(uint32_t id)
+{
+	struct xMesonI2cPlatdata *cur_plat = NULL;
+
+	/* get the global i2c plat  data */
+	meson_i2c_plat_init();
+	cur_plat = &plat[id];
+
+	i2cs[id].regs = (struct xI2cRegs *)cur_plat->reg;
+	i2cs[id].div_factor = cur_plat->div_factor;
+	i2cs[id].delay_adjust = cur_plat->delay_adjust;
+	i2cs[id].clock_frequency = cur_plat->clock_frequency;
+
+	if (cur_plat->clk_base)
+		REG32_UPDATE_BITS(cur_plat->clk_base, BIT(cur_plat->clk_offset),
+				BIT(cur_plat->clk_offset));
+
+	if (suspend_flag) {
+#if I2C_DEBUG
+		iprintf("meson i2c: clkin is 24M\n");
+#endif
+		i2cs[id].clkin_rate = 24000000;
+	}
+	else {
+#if I2C_DEBUG
+		iprintf("meson i2c: clkin is 166M\n");
+#endif
+		i2cs[id].clkin_rate = cur_plat->clkin_rate;
+	}
+	current_id = id;
+
+#if I2C_DEBUG
+	iprintf
+	    ("index = %u, reg = 0x%x, div = %u, delay = %u ,clock-frequency = %u\n",
+	     cur_plat->bus_num, i2cs[id].regs, i2cs[id].div_factor,
+	     i2cs[id].delay_adjust, i2cs[id].clock_frequency);
+#endif
+	prvMesonI2cRegsInit();
+
+	xI2cMesonSetBusSpeed(i2cs[id].clock_frequency);	/*init i2c work speed */
+
+	return 0;
+}
+
+void xI2cSetCurrentId(uint32_t id)
+{
+	taskENTER_CRITICAL();
+	current_id = id;
+	taskEXIT_CRITICAL();
+}
diff --git a/bl30/src_ao/demos/amlogic/driver/i2c/p1_plat.c b/bl30/src_ao/demos/amlogic/driver/i2c/p1_plat.c
new file mode 100644
index 0000000..9ea7478
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/i2c/p1_plat.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2014-2018 Amlogic, Inc. All rights reserved.
+ *
+ * All information contained herein is Amlogic confidential.
+ *
+ * This software is provided to you pursuant to Software License Agreement
+ * (SLA) with Amlogic Inc ("Amlogic"). This software may be used
+ * only in accordance with the terms of this agreement.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification is strictly prohibited without prior written permission from
+ * Amlogic.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER 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, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "FreeRTOS.h"
+#include <common.h>
+#include "util.h"
+#include "meson_i2c.h"
+
+#define CLKCTRL_SYS_CLK_EN0_REG1	((0x0012  << 2) + 0xfe000000)
+#define CLKCTRL_SYS_CLK_EN0_REG2	((0x0013  << 2) + 0xfe000000)
+
+struct xMesonI2cPlatdata p1_i2c_data[] = {
+	{0, 0xfe066000, 3, 15, 100000, MESON_I2C_CLK_RATE, CLKCTRL_SYS_CLK_EN0_REG1, 30}, /* i2c A */
+	{1, 0xfe068000, 3, 15, 100000, MESON_I2C_CLK_RATE, CLKCTRL_SYS_CLK_EN0_REG1, 31}, /* i2c B */
+	{2, 0xfe06a000, 3, 15, 100000, MESON_I2C_CLK_RATE, CLKCTRL_SYS_CLK_EN0_REG2, 0}, /* i2c C */
+	{3, 0xfe06c000, 3, 15, 100000, MESON_I2C_CLK_RATE, CLKCTRL_SYS_CLK_EN0_REG2, 1}, /* i2c D */
+	{4, 0xfe06e000, 3, 15, 100000, MESON_I2C_CLK_RATE, CLKCTRL_SYS_CLK_EN0_REG2, 2}, /* i2c E */
+	{5, 0xfe070000, 3, 15, 100000, MESON_I2C_CLK_RATE, CLKCTRL_SYS_CLK_EN0_REG2, 3}, /* i2c F */
+	{6, 0xfe0a2000, 3, 15, 100000, MESON_I2C_CLK_RATE, CLKCTRL_SYS_CLK_EN0_REG2, 4}, /* i2c G */
+	{7, 0xfe0a4000, 3, 15, 100000, MESON_I2C_CLK_RATE, CLKCTRL_SYS_CLK_EN0_REG2, 5}, /* i2c H */
+	{8, 0xfe0a6000, 3, 15, 100000, MESON_I2C_CLK_RATE, CLKCTRL_SYS_CLK_EN0_REG2, 6}, /* i2c I */
+	{9, 0xfe0a8000, 3, 15, 100000, MESON_I2C_CLK_RATE, CLKCTRL_SYS_CLK_EN0_REG2, 7}, /* i2c J */
+	{10, 0xfe0aa000, 3, 15, 100000, MESON_I2C_CLK_RATE, CLKCTRL_SYS_CLK_EN0_REG2, 9}, /* i2c K */
+};
+
+void meson_i2c_plat_init(void)
+{
+	plat = p1_i2c_data;
+}
diff --git a/bl30/src_ao/demos/amlogic/driver/i2c/t5w_plat.c b/bl30/src_ao/demos/amlogic/driver/i2c/t5w_plat.c
new file mode 100644
index 0000000..f27ef6d
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/i2c/t5w_plat.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2014-2018 Amlogic, Inc. All rights reserved.
+ *
+ * All information contained herein is Amlogic confidential.
+ *
+ * This software is provided to you pursuant to Software License Agreement
+ * (SLA) with Amlogic Inc ("Amlogic"). This software may be used
+ * only in accordance with the terms of this agreement.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification is strictly prohibited without prior written permission from
+ * Amlogic.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER 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, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "FreeRTOS.h"
+#include <common.h>
+#include "util.h"
+#include "meson_i2c.h"
+
+#define HHI_GCLK_MPEG0			((0x050 << 2) + 0xff63c000)
+
+struct xMesonI2cPlatdata t5w_i2c_data[] = {
+	{0, 0xffd1f000, 3, 15, 100000, MESON_I2C_CLK_RATE, HHI_GCLK_MPEG0, 9}, /* i2c A */
+	{1, 0xffd1e000, 3, 15, 100000, MESON_I2C_CLK_RATE, HHI_GCLK_MPEG0, 9}, /* i2c B */
+	{2, 0xffd1d000, 3, 15, 100000, MESON_I2C_CLK_RATE, HHI_GCLK_MPEG0, 9}, /* i2c C */
+	{3, 0xffd1c000, 3, 15, 100000, MESON_I2C_CLK_RATE, HHI_GCLK_MPEG0, 9}, /* i2c D */
+};
+
+void meson_i2c_plat_init(void)
+{
+	plat = t5w_i2c_data;
+}
diff --git a/bl30/src_ao/demos/amlogic/driver/i2c/t7_plat.c b/bl30/src_ao/demos/amlogic/driver/i2c/t7_plat.c
new file mode 100644
index 0000000..891e327
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/i2c/t7_plat.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2014-2018 Amlogic, Inc. All rights reserved.
+ *
+ * All information contained herein is Amlogic confidential.
+ *
+ * This software is provided to you pursuant to Software License Agreement
+ * (SLA) with Amlogic Inc ("Amlogic"). This software may be used
+ * only in accordance with the terms of this agreement.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification is strictly prohibited without prior written permission from
+ * Amlogic.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER 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, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "FreeRTOS.h"
+#include <common.h>
+#include "util.h"
+#include "meson_i2c.h"
+
+#define CLKCTRL_SYS_CLK_EN0_REG1	((0x0012  << 2) + 0xfe000000)
+#define CLKCTRL_SYS_CLK_EN0_REG2	((0x0013  << 2) + 0xfe000000)
+
+struct xMesonI2cPlatdata t7_i2c_data[] = {
+	{0, 0xfe066000, 3, 15, 100000, MESON_I2C_CLK_RATE, CLKCTRL_SYS_CLK_EN0_REG1, 30}, /* i2c A */
+	{1, 0xfe068000, 3, 15, 100000, MESON_I2C_CLK_RATE, CLKCTRL_SYS_CLK_EN0_REG1, 31}, /* i2c B */
+	{2, 0xfe06a000, 3, 15, 100000, MESON_I2C_CLK_RATE, CLKCTRL_SYS_CLK_EN0_REG2, 0}, /* i2c C */
+	{3, 0xfe06c000, 3, 15, 100000, MESON_I2C_CLK_RATE, CLKCTRL_SYS_CLK_EN0_REG2, 1}, /* i2c D */
+	{4, 0xfe06e000, 3, 15, 100000, MESON_I2C_CLK_RATE, CLKCTRL_SYS_CLK_EN0_REG2, 2}, /* i2c E */
+	{5, 0xfe070000, 3, 15, 100000, MESON_I2C_CLK_RATE, CLKCTRL_SYS_CLK_EN0_REG2, 3}, /* i2c F */
+	{6, 0xfe076000, 3, 15, 100000, MESON_I2C_CLK_RATE, CLKCTRL_SYS_CLK_EN0_REG1, 28}, /* i2c AO A */
+	{7, 0xfe086000, 3, 15, 100000, MESON_I2C_CLK_RATE, CLKCTRL_SYS_CLK_EN0_REG1, 29}, /* i2c AO B */
+};
+
+void meson_i2c_plat_init(void)
+{
+	plat = t7_i2c_data;
+}
diff --git a/bl30/src_ao/demos/amlogic/driver/ir/build.mk b/bl30/src_ao/demos/amlogic/driver/ir/build.mk
new file mode 100644
index 0000000..67eea27
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/ir/build.mk
@@ -0,0 +1,26 @@
+#
+#  Copyright (C) 2014-2018 Amlogic, Inc. All rights reserved.
+#
+#  All information contained herein is Amlogic confidential.
+#
+#  This software is provided to you pursuant to Software License Agreement
+#  (SLA) with Amlogic Inc ("Amlogic"). This software may be used
+#  only in accordance with the terms of this agreement.
+#
+#  Redistribution and use in source and binary forms, with or without
+#  modification is strictly prohibited without prior written permission from
+#  Amlogic.
+#
+#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#  OWNER 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, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+ir-y = ir.o ir_regmap.o
diff --git a/bl30/src_ao/demos/amlogic/driver/ir/ir.c b/bl30/src_ao/demos/amlogic/driver/ir/ir.c
new file mode 100644
index 0000000..22caa8e
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/ir/ir.c
@@ -0,0 +1,310 @@
+
+/*
+ * Copyright (C)2018 Amlogic, Inc. All rights reserved.
+ *
+ * All information contained herein is Amlogic confidential.
+ *
+ * This software is provided to you pursuant to Software License Agreement
+ * (SLA) with Amlogic Inc ("Amlogic"). This software may be used
+ * only in accordance with the terms of this agreement.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification is strictly prohibited without prior written permission from
+ * Amlogic.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER 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, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "FreeRTOS.h"
+#include "gpio.h"
+#include "util.h"
+#include "projdefs.h"
+#include "portmacro.h"
+
+#include <unistd.h>
+#include "n200_func.h"
+#include "common.h"
+#include "ir.h"
+#include "mailbox-api.h"
+
+#include "ir_drv.h"
+
+static uint8_t ucIsDebugEnable;
+static IRPowerKey_t prvKeyCodeList[MAX_KEY_NUM] = {};
+static uint32_t key_cnt;
+
+#define IRDebug(fmt, x...)						\
+do {									\
+	if (ucIsDebugEnable)						\
+		iprintf("%sDebug: %s: "fmt, DRIVE_NAME, __func__,  ##x);\
+} while (0)
+
+#define IRError(fmt, x...)						\
+	iprintf("%sError: %s: "fmt, DRIVE_NAME, __func__,  ##x);
+
+static inline void prvIRRegWrite(uint8_t ucCTL, uint8_t ucAddr, uint32_t ulvalue)
+{
+	uint32_t ulRegBase = 0;
+
+	if (!IR_BASE_ADDR || !IR_BASE_ADDR_OLD) {
+		IRError("IR_BASE_ADDR not found!\n");
+		return;
+	}
+
+	ulRegBase = IS_LEGACY_CTRL(ucCTL);
+
+	REG32((unsigned long)(ulRegBase + ucAddr)) = ulvalue;
+}
+
+static inline uint32_t prvIRRegRead(uint8_t ucCTL, uint8_t ucAddr)
+{
+	uint32_t ulRegBase = 0;
+
+	if (!IR_BASE_ADDR || !IR_BASE_ADDR_OLD) {
+		IRError("IR_BASE_ADDR not found!\n");
+		return -1;
+	}
+
+	ulRegBase = IS_LEGACY_CTRL(ucCTL);
+
+	return REG32(ulRegBase + ucAddr);
+}
+
+static inline void prvIRRegUpdateBit(uint8_t ucCTL, uint8_t ucAddr,
+				     uint32_t ulMask, uint32_t ulVal)
+{
+	uint32_t ulRegBase = 0;
+
+	if (!IR_BASE_ADDR || !IR_BASE_ADDR_OLD) {
+		IRError("IR_BASE_ADDR not found!\n");
+		return;
+	}
+
+	ulRegBase = IS_LEGACY_CTRL(ucCTL);
+
+	REG32_UPDATE_BITS(ulRegBase + ucAddr, ulMask, ulVal);
+}
+
+static void vSetIRWorkMode(uint16_t usWorkMode, uint8_t ucWorkCTL)
+{
+	uint8_t ucRegSize = 0;
+	uint8_t i = 0;
+	uint32_t ulValue = 0;
+	const struct xRegProtocolMethod **xProData;
+
+	xProData = pGetSupportProtocol();
+
+	for (; (*xProData) != NULL;) {
+		if ((*xProData)->ucProtocol == usWorkMode)
+			break;
+		xProData++;
+	}
+
+	if (!*xProData) {
+		IRError("Not support this type Protocol!\n");
+		return;
+	}
+
+	/*clear status and disable ir decoder */
+	prvIRRegRead(ucWorkCTL, REG_FRAME);
+	prvIRRegWrite(ucWorkCTL, REG_REG1, 0x01);
+
+	ucRegSize = (*xProData)->ucRegNum;
+
+	for (; i < ucRegSize; i++)
+		prvIRRegWrite(ucWorkCTL, (*xProData)->RegList[i].ucReg,
+			      (*xProData)->RegList[i].ulVal);
+
+	/*reset IR decoder when reinstall */
+	ulValue = prvIRRegRead(ucWorkCTL, REG_REG1);
+	ulValue |= 1;
+	prvIRRegWrite(ucWorkCTL, REG_REG1, ulValue);
+	ulValue &= ~0x01;
+	prvIRRegWrite(ucWorkCTL, REG_REG1, ulValue);
+}
+
+void vInitIRWorkMode(uint16_t usWorkMode)
+{
+	if (ENABLE_LEGACY_CTL(usWorkMode))
+		vSetIRWorkMode(LEGACY_IR_CTL_MASK(usWorkMode), LEGACY_CTL);
+	else
+		prvIRRegWrite(LEGACY_CTL, REG_REG1, 0);
+
+	IRDebug("change mode to 0x%x\n", usWorkMode);
+	if (MULTI_IR_CTL_MASK(usWorkMode))
+		vSetIRWorkMode(MULTI_IR_CTL_MASK(usWorkMode), MULTI_CTL);
+}
+
+static void prvCheckPowerKey(void)
+{
+	struct xIRDrvData *xDrvData;
+	IRPowerKey_t *ulPowerKeyList;
+	uint8_t ucIndex = 0;
+
+	xDrvData = pGetIRDrvData();
+	ulPowerKeyList = xDrvData->ulPowerKeyList;
+	if (!xDrvData->ulFrameCode) {
+		IRDebug("invalid key or repeat :0x%x\n", xDrvData->ulFrameCode);
+		return;
+	};
+
+	IRDebug("receive key code :0x%x\n", xDrvData->ulFrameCode);
+	/* search power key list */
+	for ( ;ucIndex < xDrvData->ucPowerKeyNum; ucIndex++)
+		if (ulPowerKeyList[ucIndex].code == xDrvData->ulFrameCode) {
+			iprintf("receive the right power key:0x%x\n",
+				xDrvData->ulFrameCode);
+			if (xDrvData->vIRHandler)
+				xDrvData->vIRHandler(&ulPowerKeyList[ucIndex]);
+		}
+}
+
+static void vIRInterruptHandler(void)
+{
+	uint32_t ulDecodeStatus = 0;
+	uint8_t ucIndex = 0;
+	uint16_t ucCurWorkMode;
+	struct xIRDrvData *xDrvData;
+
+	xDrvData = pGetIRDrvData();
+	ucCurWorkMode = xDrvData->ucCurWorkMode;
+
+	/*choose controller */
+	for (; ucIndex < (ENABLE_LEGACY_CTL(ucCurWorkMode) ? 2:1); ucIndex++) {
+		ulDecodeStatus = prvIRRegRead(ucIndex, REG_STATUS);
+		if (ulDecodeStatus & 0x08) {
+			xDrvData->ucWorkCTL = ucIndex;
+			break;
+		}
+	}
+
+	if (ucIndex == ERROR_CTL) {
+		IRError("error interrupt !\n");
+		return;
+	}
+
+	ulDecodeStatus = prvIRRegRead(xDrvData->ucWorkCTL, REG_STATUS);
+
+	xDrvData->ucIRStatus = STATUS_NORMAL;
+	if (ulDecodeStatus & 0x01)
+		xDrvData->ucIRStatus = STATUS_REPEAT;
+
+	xDrvData->ulFrameCode = prvIRRegRead(xDrvData->ucWorkCTL, REG_FRAME);
+
+	prvCheckPowerKey();
+
+}
+
+int8_t ucIsIRInit(void)
+{
+	struct xIRDrvData *xDrvData;
+
+	xDrvData = pGetIRDrvData();
+	return xDrvData->ucIsInit;
+}
+
+void vIRInit(uint16_t usWorkMode, uint16_t usGpio, enum PinMuxType func,
+	     IRPowerKey_t *ulPowerKeyList, uint8_t ucPowerKeyNum,
+	     void (*vIRHandler)(IRPowerKey_t *pkey))
+{
+	struct xIRDrvData *xDrvData;
+
+	if (ucIsIRInit()) {
+		IRError("all ready init\n");
+		return;
+	}
+
+	if (!IR_INTERRUPT_NUM || !IRQ_NUM_IRIN) {
+		IRError("ir irq number not found, ir init failed\n");
+		return;
+	}
+
+	if (ulPowerKeyList == NULL || !ucPowerKeyNum) {
+		IRError("not set power key list, ir init failed\n");
+		return;
+	}
+
+	if (xPinmuxSet(usGpio, func)) {
+		IRError("pin mux setting error\n");
+		return;
+	}
+
+	xDrvData = pGetIRDrvData();
+	vInitIRWorkMode(usWorkMode);
+
+	xDrvData->ulPowerKeyList = ulPowerKeyList;
+	xDrvData->ucPowerKeyNum = ucPowerKeyNum;
+	xDrvData->ucCurWorkMode = usWorkMode;
+	xDrvData->vIRHandler = vIRHandler;
+
+	RegisterIrq(IRQ_NUM_IRIN, 2, vIRInterruptHandler);
+	EnableIrq(IRQ_NUM_IRIN);
+
+	xDrvData->ucIsInit = 1;
+}
+
+void vIRDeint(void)
+{
+	struct xIRDrvData *xDrvData;
+
+	xDrvData = pGetIRDrvData();
+
+	xDrvData->ucIsInit = 0;
+	xDrvData->vIRHandler = NULL;
+
+	DisableIrq(IRQ_NUM_IRIN);
+	UnRegisterIrq(IRQ_NUM_IRIN);
+}
+
+void vIRGetKeyCode(IRPowerKey_t *PowerKeyList)
+{
+	IRPowerKey_t *Keydest = PowerKeyList;
+	IRPowerKey_t *KeyList = prvKeyCodeList;
+
+	while (key_cnt--)
+		*Keydest++ = *KeyList++;
+}
+
+static void *prvIRGetInfo(void *msg)
+{
+
+	uint32_t key_num, i;
+	uint32_t *key_code, *key_type;
+	key_num = *(u32 *)msg;
+	key_code = ((u32 *)msg) + 1;
+	key_type = ((u32 *)msg) + key_num / 2 + 1;
+
+	for (i = 0; i < key_num / 2; i++) {
+		prvKeyCodeList[i].code = *key_code;
+		prvKeyCodeList[i].type = *key_type;
+		key_code++;
+		key_type++;
+	}
+
+	key_cnt = i;
+	return NULL;
+
+
+}
+
+void vIRMailboxEnable(void)
+{
+	int32_t ret;
+
+	ret = xInstallRemoteMessageCallbackFeedBack(AOREE_CHANNEL, MBX_CMD_GET_IR_INFO,
+						    prvIRGetInfo, 1);
+	if (ret == MBOX_CALL_MAX) {
+		printf("mailbox cmd 0x%x register fail\n");
+		return;
+	}
+}
+
diff --git a/bl30/src_ao/demos/amlogic/driver/ir/ir_drv.h b/bl30/src_ao/demos/amlogic/driver/ir/ir_drv.h
new file mode 100644
index 0000000..1bd75f0
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/ir/ir_drv.h
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C)2018 Amlogic, Inc. All rights reserved.
+ *
+ * All information contained herein is Amlogic confidential.
+ *
+ * This software is provided to you pursuant to Software License Agreement
+ * (SLA) with Amlogic Inc ("Amlogic"). This software may be used
+ * only in accordance with the terms of this agreement.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification is strictly prohibited without prior written permission from
+ * Amlogic.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER 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, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _IR_DRIVER_H_
+#define _IR_DRIVER_H_
+#include <ir.h>
+#include "register.h"
+#include "irq.h"
+
+#define	DRIVE_NAME		"[ir]"
+
+/* only for sc2 now */
+#define	IR_INTERRUPT_NUM	22
+
+#ifndef IR_INTERRUPT_NUM
+#define IR_INTERRUPT_NUM	0
+#endif
+
+#ifndef IRQ_NUM_IRIN
+#define IRQ_NUM_IRIN		0
+#endif
+
+#ifdef IRCTRL_IR_DEC_LDR_ACTIVE
+#define	IR_BASE_ADDR_OLD	IRCTRL_IR_DEC_LDR_ACTIVE
+#else
+#ifdef AO_IR_DEC_LDR_ACTIVE
+#define	IR_BASE_ADDR_OLD	AO_IR_DEC_LDR_ACTIVE
+#else
+#define	IR_BASE_ADDR_OLD	0
+#endif
+#endif
+
+#ifdef IRCTRL_MF_IR_DEC_LDR_ACTIVE
+#define	IR_BASE_ADDR		IRCTRL_MF_IR_DEC_LDR_ACTIVE
+#else
+#ifdef AO_MF_IR_DEC_LDR_ACTIVE
+#define	IR_BASE_ADDR		AO_MF_IR_DEC_LDR_ACTIVE
+#else
+#define	IR_BASE_ADDR		0
+#endif
+#endif
+
+#define	IS_LEGACY_CTRL(x)	((x) ? (IR_BASE_ADDR_OLD) : (IR_BASE_ADDR))
+#define	ENABLE_LEGACY_CTL(x)	(((x) >> 8) & 0xff)
+#define	LEGACY_IR_CTL_MASK(x)	ENABLE_LEGACY_CTL(x)
+#define	MULTI_IR_CTL_MASK(x)	((x) & 0xff)
+
+/*frame status*/
+enum {
+	STATUS_INVALID = 0,
+	STATUS_NORMAL,
+	STATUS_REPEAT,
+};
+
+enum {
+	MULTI_CTL = 0,
+	LEGACY_CTL,
+	ERROR_CTL,
+};
+
+/*register file*/
+enum xIRReg {
+	REG_LDR_ACTIVE = 0x00 << 2,
+	REG_LDR_IDLE = 0x01 << 2,
+	REG_LDR_REPEAT = 0x02 << 2,
+	REG_BIT_0 = 0x03 << 2,
+	REG_REG0 = 0x04 << 2,
+	REG_FRAME = 0x05 << 2,
+	REG_STATUS = 0x06 << 2,
+	REG_REG1 = 0x07 << 2,
+	REG_REG2 = 0x08 << 2,
+	REG_DURATN2 = 0x09 << 2,
+	REG_DURATN3 = 0x0a << 2,
+	REG_FRAME1 = 0x0b << 2,
+	REG_STATUS1 = 0x0c << 2,
+	REG_STATUS2 = 0x0d << 2,
+	REG_REG3 = 0x0e << 2,
+	REG_FRAME_RSV0 = 0x0f << 2,
+	REG_FRAME_RSV1 = 0x10 << 2,
+	REG_IRQ_CTL = 0x12 << 2,
+	REG_FIFO = 0x13 << 2,
+	REG_WITH = 0x14 << 2,
+	REG_REPEAT_DET = 0x15 << 2,
+	REG_DEMOD_CNTL0 = 0x20 << 2,
+	REG_DEMOD_CNTL1 = 0x21 << 2,
+	REG_DEMOD_IIR_THD = 0x22 << 2,
+	REG_DEMOD_THD0 = 0x23 << 2,
+	REG_DEMOD_THD1 = 0x24 << 2,
+	REG_DEMOD_SUM_CNT0 = 0x25 << 2,
+	REG_DEMOD_SUM_CNT1 = 0x26 << 2,
+	REG_DEMOD_CNT0 = 0x27 << 2,
+	REG_DEMOD_CNT1 = 0x28 << 2,
+};
+
+struct xRegList {
+	uint8_t ucReg;
+	uint32_t ulVal;
+};
+
+/* protocol-->register */
+typedef struct xRegProtocolMethod {
+	uint8_t ucProtocol;
+	uint8_t ucRegNum;
+	struct xRegList *RegList;
+} xRegProtocolMethod;
+
+/*IR Driver data*/
+struct xIRDrvData {
+	uint8_t ucWorkCTL:1;
+	uint8_t ucIsInit:1;
+	uint8_t ucIRStatus:4;
+	uint8_t ucPowerKeyNum;
+	uint16_t ucCurWorkMode;
+	uint32_t ulFrameCode;
+	IRPowerKey_t *ulPowerKeyList;
+	void (*vIRHandler)(IRPowerKey_t *pkey);
+};
+
+const xRegProtocolMethod **pGetSupportProtocol(void);
+struct xIRDrvData *pGetIRDrvData(void);
+
+#endif
diff --git a/bl30/src_ao/demos/amlogic/driver/ir/ir_regmap.c b/bl30/src_ao/demos/amlogic/driver/ir/ir_regmap.c
new file mode 100644
index 0000000..a595d27
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/ir/ir_regmap.c
@@ -0,0 +1,277 @@
+/*
+ * Copyright (C)2018 Amlogic, Inc. All rights reserved.
+ *
+ * All information contained herein is Amlogic confidential.
+ *
+ * This software is provided to you pursuant to Software License Agreement
+ * (SLA) with Amlogic Inc ("Amlogic"). This software may be used
+ * only in accordance with the terms of this agreement.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification is strictly prohibited without prior written permission from
+ * Amlogic.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER 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, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "FreeRTOS.h"
+#include <common.h>
+#include "ir_drv.h"
+
+static struct xRegList xNECLegacyRegList[] = {
+        {REG_LDR_ACTIVE,    (500 << 16) | (400 << 0)},
+        {REG_LDR_IDLE,      300 << 16 | 200 << 0},
+        {REG_LDR_REPEAT,    150 << 16 | 80 << 0},
+        {REG_BIT_0,         72 << 16 | 40 << 0 },
+        {REG_REG0,          7 << 28 | (0xFA0 << 12) | 0x13},
+        {REG_STATUS,        (134 << 20) | (90 << 10)},
+        {REG_REG1,          0xbe00},
+};
+
+static struct xRegList xNECRegList[] = {
+	{REG_LDR_ACTIVE, (500 << 16) | (400 << 0)},
+	{REG_LDR_IDLE, 300 << 16 | 200 << 0},
+	{REG_LDR_REPEAT, 150 << 16 | 80 << 0},
+	{REG_BIT_0, 72 << 16 | 40 << 0},
+	{REG_REG0, 7 << 28 | (0xFA0 << 12) | 0x13},
+	{REG_STATUS, (134 << 20) | (90 << 10)},
+	{REG_REG1, 0x9f00},
+	{REG_REG2, 0x00},
+	{REG_DURATN2, 0x00},
+	{REG_DURATN3, 0x00}
+};
+
+#ifdef MODE_HARD_DUOKAN
+static struct xRegList xDUOKANRegList[] = {
+	{ REG_LDR_ACTIVE,   ((70 << 16) | (30 << 0))},
+	{ REG_LDR_IDLE,     ((50 << 16) | (15 << 0))},
+	{ REG_LDR_REPEAT,   ((30 << 16) | (26 << 0))},
+	{ REG_BIT_0,        ((66 << 16) | (40 << 0))},
+	{ REG_REG0,         ((3 << 28) | (0x4e2 << 12) | (0x13))},
+	{ REG_STATUS,       ((80 << 20) | (66 << 10))},
+	{ REG_REG1,         0x9300},
+	{ REG_REG2,         0xb90b},
+	{ REG_DURATN2,      ((97 << 16) | (80 << 0))},
+	{ REG_DURATN3,      ((120 << 16) | (97 << 0))},
+	{ REG_REG3,         5000<<0}
+};
+
+static xRegProtocolMethod xDUOKANDecode = {
+	.ucProtocol = MODE_HARD_DUOKAN,
+	.RegList = xDUOKANRegList,
+	.ucRegNum = ARRAY_SIZE(xDUOKANRegList),
+};
+#endif
+
+#ifdef MODE_HARD_XMP_1
+static struct xRegList xXMP1RegList[] = {
+	{ REG_LDR_ACTIVE,   0},
+	{ REG_LDR_IDLE,     0},
+	{ REG_LDR_REPEAT,   0},
+	{ REG_BIT_0,        (52 << 16) | (45<<0)},
+	{ REG_REG0,         ((7 << 28) | (0x5DC << 12) | (0x13))},
+	{ REG_STATUS,       (87 << 20) | (80 << 10)},
+	{ REG_REG1,         0x9f00},
+	{ REG_REG2,         0xa90e},
+	/*n=10,758+137*10=2128us,2128/20= 106*/
+	{ REG_DURATN2,      (121<<16) | (114<<0)},
+	{ REG_DURATN3,      (7<<16) | (7<<0)},
+	{ REG_REG3,         0}
+};
+
+static xRegProtocolMethod xXMP1Decode = {
+	.ucProtocol = MODE_HARD_XMP_1,
+	.RegList = xXMP1RegList,
+	.ucRegNum = ARRAY_SIZE(xXMP1RegList),
+};
+#endif
+
+#ifdef MODE_HARD_RC5
+static struct xRegList xRC5RegList[] = {
+	{ REG_LDR_ACTIVE,   0},
+	{ REG_LDR_IDLE,     0},
+	{ REG_LDR_REPEAT,   0},
+	{ REG_BIT_0,        0},
+	{ REG_REG0,         ((3 << 28) | (0x1644 << 12) | 0x13)},
+	{ REG_STATUS,       (1 << 30)},
+	{ REG_REG1,         ((1 << 15) | (13 << 8))},
+	/*bit[0-3]: RC5; bit[8]: MSB first mode; bit[11]: compare frame method*/
+	{ REG_REG2,         ((1 << 13) | (1 << 11) | (1 << 8) | 0x7)},
+	/*Half bit for RC5 format: 888.89us*/
+	{ REG_DURATN2,      ((53 << 16) | (38 << 0))},
+	/*RC5 typically 1777.78us for whole bit*/
+	{ REG_DURATN3,      ((99 << 16) | (81 << 0))},
+	{ REG_REG3,         0}
+};
+
+static xRegProtocolMethod xRC5Decode = {
+	.ucProtocol = MODE_HARD_RC5,
+	.RegList = xRC5RegList,
+	.ucRegNum = ARRAY_SIZE(xRC5RegList),
+};
+#endif
+
+#ifdef MODE_HARD_RC6
+static struct xRegList xRC6RegList[] = {
+	{REG_LDR_ACTIVE,    (210 << 16) | (125 << 0)},
+	{REG_LDR_IDLE,      50 << 16 | 38 << 0}, /* leader idle 400*/
+	{REG_LDR_REPEAT,    145 << 16 | 125 << 0}, /* leader repeat*/
+	/* logic '0' or '00' 1500us*/
+	{REG_BIT_0,         51 << 16 | 38 << 0 },
+	{REG_REG0,          (7 << 28)|(0xFA0 << 12)|0x13},
+	/* sys clock time.base time = 20 body frame*/
+	{REG_STATUS,       (94 << 20) | (82 << 10)},
+	/*20bit:9440 32bit:9f40 36bit:a340 37bit:a440*/
+	{REG_REG1,         0xa440},
+	/*it may get the wrong customer value and key value from register if
+	 *the value is set to 0x4,so the register value must set to 0x104
+	 */
+	{REG_REG2,         0x2909},
+	{REG_DURATN2,      ((28 << 16) | (16 << 0))},
+	{REG_DURATN3,      ((51 << 16) | (38 << 0))},
+};
+
+static xRegProtocolMethod xRC6Decode = {
+	.ucProtocol = MODE_HARD_RC6,
+	.RegList = xRC6RegList,
+	.ucRegNum = ARRAY_SIZE(xRC6RegList),
+};
+#endif
+
+#ifdef MODE_HARD_TOSHIBA
+static struct xRegList xTOSHIBARegList[] = {
+	{ REG_LDR_ACTIVE,       (280 << 16) | (180 << 0)},
+	{ REG_LDR_IDLE,         (280 << 16) | (180 << 0)},
+	{ REG_LDR_REPEAT,       (150 << 16) | (60 << 0)},
+	{ REG_BIT_0,            (72 << 16) | (40 << 0)},
+	{ REG_REG0,             (7 << 28) | (0xFA0 << 12) | 0x13},
+	{ REG_STATUS,           (134 << 20) | (90 << 10)},
+	{ REG_REG1,             0x9f00},
+	{ REG_REG2,             (0x05) | (1 << 24) | (23 << 11)},
+	{ REG_DURATN2,          0x00},
+	{ REG_DURATN3,          0x00},
+	{ REG_REPEAT_DET,       (1 << 31) | (0xFA0 << 16) | (10 << 0)},
+	{ REG_REG3,             0x2AF8},
+};
+
+static xRegProtocolMethod xTOSHIBADecode = {
+	.ucProtocol = MODE_HARD_TOSHIBA,
+	.RegList = xTOSHIBARegList,
+	.ucRegNum = ARRAY_SIZE(xTOSHIBARegList),
+};
+#endif
+
+
+#ifdef MODE_HARD_RCA
+static struct xRegList xRCARegList[] = {
+	{ REG_LDR_ACTIVE,   (250 << 16) | (160 << 0)},
+	{ REG_LDR_IDLE,     250 << 16 | 160 << 0},
+	{ REG_LDR_REPEAT,   250 << 16 | 160 << 0},
+	{ REG_BIT_0,        100 << 16 | 48 << 0},
+	{ REG_REG0,         7 << 28 | (0xFA0 << 12) | 0x13},
+	{ REG_STATUS,       (150 << 20) | (110 << 10)},
+	{ REG_REG1,         0x9700},
+	{ REG_REG2,         0x104 | (1 << 24) | (23 << 11)},
+	{ REG_DURATN2,      0x00},
+	{ REG_REPEAT_DET,  (1 << 31) | (0xFA0 << 16) | (10 << 0)},
+	{ REG_REG3,        0x1A00},
+	{ REG_DURATN3,      0x00}
+};
+
+static xRegProtocolMethod xRCADecode = {
+	.ucProtocol = MODE_HARD_RCA,
+	.RegList = xRCARegList,
+	.ucRegNum = ARRAY_SIZE(xRCARegList),
+};
+
+#endif
+
+#ifdef MODE_HARD_RCMM
+static struct xRegList xRCMMRegList[] = {
+	{REG_LDR_ACTIVE,    (35 << 16) | (17 << 0)},
+	{REG_LDR_IDLE,      (17 << 16) | (8 << 0)},
+	{REG_LDR_REPEAT,    (31 << 16) | (11 << 0)},
+	{REG_BIT_0,         (25 << 16) | (21 << 0)},
+	{REG_REG0,          (7 << 28)  | (0x590 << 12) | 0x13},
+	{REG_STATUS,        (36 << 20) | (29 << 10)},
+	{REG_REG1,         0x9f00},
+	{REG_REG2,         0x1150a},
+	{REG_DURATN2,      ((43 << 16) | (37 << 0))},
+	{REG_DURATN3,      ((50 << 16) | (44 << 0))},
+	{REG_REG3,         1200 << 0},
+};
+
+static xRegProtocolMethod xRCMMDecode = {
+	.ucProtocol = MODE_HARD_RCMM,
+	.RegList = xRCMMRegList,
+	.ucRegNum = ARRAY_SIZE(xRCMMRegList),
+};
+#endif
+
+static xRegProtocolMethod xNECLegacyDecode = {
+	.ucProtocol = MODE_HARD_LEGACY_NEC,
+	.RegList = xNECLegacyRegList,
+	.ucRegNum = ARRAY_SIZE(xNECLegacyRegList),
+};
+
+static xRegProtocolMethod xNECDecode = {
+	.ucProtocol = MODE_HARD_NEC,
+	.RegList = xNECRegList,
+	.ucRegNum = ARRAY_SIZE(xNECRegList),
+};
+
+static const xRegProtocolMethod *xSupportProtocol[] = {
+	&xNECDecode,
+	&xNECLegacyDecode,
+
+#ifdef MODE_HARD_DUOKAN
+	&xDUOKANDecode,
+#endif
+
+#ifdef MODE_HARD_RCA
+	&xRCADecode,
+#endif
+
+#ifdef MODE_HARD_RC5
+	&xRC5Decode,
+#endif
+
+#ifdef MODE_HARD_RC6
+	&xRC6Decode,
+#endif
+
+#ifdef MODE_HARD_TOSHIBA
+	&xTOSHIBADecode,
+#endif
+
+#ifdef MODE_HARD_XMP_1
+	&xXMP1Decode,
+#endif
+
+#ifdef MODE_HARD_RCMM
+	&xRCMMDecode,
+#endif
+	NULL,
+};
+
+static struct xIRDrvData xIRDrvPrvData;
+
+struct xIRDrvData *pGetIRDrvData(void)
+{
+	return &xIRDrvPrvData;
+}
+
+const xRegProtocolMethod **pGetSupportProtocol(void)
+{
+	return xSupportProtocol;
+}
diff --git a/bl30/src_ao/demos/amlogic/driver/key/adc_key.c b/bl30/src_ao/demos/amlogic/driver/key/adc_key.c
new file mode 100644
index 0000000..47f1261
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/key/adc_key.c
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2014-2018 Amlogic, Inc. All rights reserved.
+ *
+ * All information contained herein is Amlogic confidential.
+ *
+ * This software is provided to you pursuant to Software License Agreement
+ * (SLA) with Amlogic Inc ("Amlogic"). This software may be used
+ * only in accordance with the terms of this agreement.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification is strictly prohibited without prior written permission from
+ * Amlogic.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER 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, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "FreeRTOS.h"
+#include "common.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <timers.h>
+#include <task.h>
+#include "keypad.h"
+#include "saradc.h"
+
+struct xOneAdcKeyInfo {
+	enum KeyState keyState;
+	struct xAdcKeyInfo *adcKeyInfo;
+	struct xOneAdcKeyInfo *xNext;
+};
+
+static int jitterCount;
+static struct xOneAdcKeyInfo *xHeadKey;
+static TimerHandle_t xAdcKeyCycleTimer;
+
+static void prReportEvent(struct xAdcKeyInfo *xKey, uint32_t event)
+{
+	struct xReportEvent reportEvent;
+
+	reportEvent.ulCode = xKey->keyInitInfo.ulKeyId;
+	reportEvent.data = xKey->keyInitInfo.data;
+	reportEvent.event = event;
+	reportEvent.responseTime = 0;
+
+	if (xKey->keyInitInfo.CallBack)
+		xKey->keyInitInfo.CallBack(reportEvent);
+}
+
+static void prAdcKeyProcess(TimerHandle_t xTimer)
+{
+	int ret;
+	uint16_t usAdcData;
+	struct xOneAdcKeyInfo *xPassBtn = xHeadKey;
+	struct xAdcKeyInfo *adcKeyInfo;
+
+	(void)xTimer;
+	for (xPassBtn = xHeadKey; xPassBtn != NULL;
+						xPassBtn = xPassBtn->xNext) {
+		adcKeyInfo = xPassBtn->adcKeyInfo;
+		ret = xAdcGetSample(&usAdcData, 1, &(adcKeyInfo->xAdcDecp));
+		if (ret < 0)
+			continue;
+		if (xPassBtn->keyState == UP) {
+			if ((usAdcData >= adcKeyInfo->ulValue -
+						SAMPLE_DEVIATION)
+			    && (usAdcData <=
+				adcKeyInfo->ulValue + SAMPLE_DEVIATION)) {
+				if (jitterCount < KEY_JITTER_COUNT) {
+					jitterCount++;
+					return;
+				}
+				jitterCount = 0;
+				xPassBtn->keyState = DOWN;
+				prReportEvent(xPassBtn->adcKeyInfo, EVENT_SHORT);
+			}
+
+		} else if (xPassBtn->keyState == DOWN) {
+			if (((usAdcData <= adcKeyInfo->ulValue -
+							SAMPLE_DEVIATION)
+			     || (usAdcData >=
+				 adcKeyInfo->ulValue + SAMPLE_DEVIATION))) {
+				if (jitterCount < KEY_JITTER_COUNT) {
+					jitterCount++;
+					return;
+				}
+				jitterCount = 0;
+				xPassBtn->keyState = UP;
+			}
+		}
+	}
+}
+
+static void prvAddAdcKey(struct xOneAdcKeyInfo *xKey)
+{
+	if (!xKey)
+		return;
+	xKey->xNext = xHeadKey;
+	xHeadKey = xKey;
+}
+
+void vCreateAdcKey(struct xAdcKeyInfo *keyArr, uint16_t keyNum)
+{
+	uint16_t i;
+	struct xOneAdcKeyInfo *xOneKey;
+	struct xKeyInitInfo *keyInitInfo;
+	struct xAdcKeyInfo *adcKeyInfo;
+
+	if (!xAdcKeyCycleTimer) {
+		xAdcKeyCycleTimer = xTimerCreate((const char *)"xAdcKeyTimer",
+						 pdMS_TO_TICKS
+						 (TIMER_CYCLE_TIME), pdTRUE,
+						 (void *)1,
+						 (TimerCallbackFunction_t)
+						 prAdcKeyProcess);
+		if (!xAdcKeyCycleTimer) {
+			printf("adc timer create failed!\n");
+			return;
+		}
+	}
+
+	for (i = 0; i < keyNum; i++) {
+		keyInitInfo = &(keyArr[i].keyInitInfo);
+
+		if (keyInitInfo->ulKeyId < ADCKEY_ID_BASE) {
+			printf("adc key:[%d] key code not less than 512.\n", i);
+			continue;
+		}
+
+		xOneKey = pvPortMalloc(sizeof(struct xOneAdcKeyInfo));
+		if (xOneKey == NULL)
+			goto fail_alloc2;
+
+		adcKeyInfo = pvPortMalloc(sizeof(struct xAdcKeyInfo));
+		if (adcKeyInfo == NULL)
+			goto fail_alloc1;
+
+		memcpy(adcKeyInfo, &keyArr[i], sizeof(struct xAdcKeyInfo));
+		memset(xOneKey, 0, sizeof(struct xOneAdcKeyInfo));
+		xOneKey->keyState = UP;
+		xOneKey->adcKeyInfo = adcKeyInfo;
+		prvAddAdcKey(xOneKey);
+
+		printf("keypad: add adc key [%ld]\n", keyInitInfo->ulKeyId);
+	}
+
+	return;
+
+fail_alloc1:
+	vPortFree(xOneKey);
+fail_alloc2:
+	printf("adc key: [%d] malloc failed!\n", i);
+}
+
+void vDestoryAdcKey(void)
+{
+	struct xOneAdcKeyInfo *xPassBtn, *xTmpBtn;
+	uint32_t key_id;
+
+	for (xPassBtn = xHeadKey; xPassBtn != NULL;) {
+		key_id = xPassBtn->adcKeyInfo->keyInitInfo.ulKeyId;
+
+		vPortFree(xPassBtn->adcKeyInfo);
+
+		xTmpBtn = xPassBtn;
+		xPassBtn = xPassBtn->xNext;
+
+		vPortFree(xTmpBtn);
+
+		printf("keypad: del adc key [%ld]\n", key_id);
+	}
+
+	xHeadKey = NULL;
+}
+
+void vAdcKeyEnable(void)
+{
+	vAdcInit();
+	vAdcHwEnable();
+
+	if (xAdcKeyCycleTimer) {
+		xTimerStart(xAdcKeyCycleTimer, 0);
+	}
+}
+
+void vAdcKeyDisable(void)
+{
+	if (xAdcKeyCycleTimer) {
+		xTimerStop(xAdcKeyCycleTimer, pdMS_TO_TICKS(TIMER_CYCLE_TIME));
+	}
+
+	vAdcHwDisable();
+	vAdcDeinit();
+}
+
+int vAdcKeyIsEmpty(void)
+{
+	return (!xHeadKey);
+}
diff --git a/bl30/src_ao/demos/amlogic/driver/key/build.mk b/bl30/src_ao/demos/amlogic/driver/key/build.mk
new file mode 100644
index 0000000..b302410
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/key/build.mk
@@ -0,0 +1,26 @@
+ #
+ #  Copyright (C) 2014-2018 Amlogic, Inc. All rights reserved.
+ #
+ #  All information contained herein is Amlogic confidential.
+ #
+ #  This software is provided to you pursuant to Software License Agreement
+ #  (SLA) with Amlogic Inc ("Amlogic"). This software may be used
+ #  only in accordance with the terms of this agreement.
+ #
+ #  Redistribution and use in source and binary forms, with or without
+ #  modification is strictly prohibited without prior written permission from
+ #  Amlogic.
+ #
+ #  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ #  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ #  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ #  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ #  OWNER 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, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ #
+key-y = adc_key.o gpio_key.o dynamic_keypad.o
diff --git a/bl30/src_ao/demos/amlogic/driver/key/dynamic_keypad.c b/bl30/src_ao/demos/amlogic/driver/key/dynamic_keypad.c
new file mode 100644
index 0000000..06dad94
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/key/dynamic_keypad.c
@@ -0,0 +1,86 @@
+#include <string.h>
+#include "FreeRTOS.h"
+#include "keypad.h"
+#include "gpio.h"
+#include "saradc.h"
+#include "suspend.h"
+#include "mailbox-api.h"
+
+/*KEY ID*/
+#define GPIO_KEY_ID_POWER	GPIOD_3
+
+#define ADC_KEY_ID_HOME		520
+
+static void vKeyCallBack(struct xReportEvent event)
+{
+	uint32_t buf[4] = {0};
+
+	buf[0] = POWER_KEY_WAKEUP;
+	STR_Wakeup_src_Queue_Send(buf);
+
+	printf("dynamic key event 0x%x, key code %d, responseTicks %d\n",
+		event.event, event.ulCode, event.responseTime);
+}
+
+static void *xMboxSetKeypad(void *msg)
+{
+	uint32_t *key_info = (uint32_t *)msg;
+
+	if (key_info[0] == 0xFFFFFFFF) {
+		/* remove all key */
+		vDestoryAdcKey();
+		vDestoryGpioKey();
+
+		return NULL;
+	}
+
+	if ((key_info[3] < 1) || (key_info[3] > 2)) {
+		printf("keypad: illegal key event\n");
+		return NULL;
+	}
+
+	if (key_info[0] >= ADCKEY_ID_BASE) {
+		if (key_info[1] > ((1 << 12) - 1)) {
+			printf("keypad: illegal adc voltage value\n");
+			return NULL;
+		}
+
+		if (key_info[2] > 7) {
+			printf("keypad: illegal adc channel\n");
+			return NULL;
+		}
+
+		struct xAdcKeyInfo adcKey[1] = {
+			ADC_KEY_INFO(key_info[0], key_info[1],
+				     (enum AdcChannelType)key_info[2],
+				     key_info[3], vKeyCallBack, NULL)
+		};
+
+		vCreateAdcKey(adcKey, 1);
+	} else if (key_info[0] < ADCKEY_ID_BASE) {
+		if (key_info[1] > 1) {
+			printf("keypad: illegal gpio key status\n");
+			return NULL;
+		}
+
+		struct xGpioKeyInfo gpioKey[1] = {
+			GPIO_KEY_INFO(key_info[0], key_info[1], key_info[2],
+					vKeyCallBack, NULL)
+		};
+
+		vCreateGpioKey(gpioKey, 1);
+	}
+
+	return NULL;
+}
+
+void vDynamicKeypadInit(void)
+{
+	int ret;
+
+	ret = xInstallRemoteMessageCallbackFeedBack(AOREE_CHANNEL,
+							CMD_SET_KEYPAD,
+							xMboxSetKeypad, 0);
+	if (ret == MBOX_CALL_MAX)
+		printf("mbox cmd 0x%x register fail\n", CMD_SET_KEYPAD);
+}
diff --git a/bl30/src_ao/demos/amlogic/driver/key/gpio_key.c b/bl30/src_ao/demos/amlogic/driver/key/gpio_key.c
new file mode 100644
index 0000000..f399d04
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/key/gpio_key.c
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2014-2018 Amlogic, Inc. All rights reserved.
+ *
+ * All information contained herein is Amlogic confidential.
+ *
+ * This software is provided to you pursuant to Software License Agreement
+ * (SLA) with Amlogic Inc ("Amlogic"). This software may be used
+ * only in accordance with the terms of this agreement.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification is strictly prohibited without prior written permission from
+ * Amlogic.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER 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, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "keypad.h"
+#include "gpio.h"
+#include "common.h"
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "FreeRTOS.h"
+#include <timers.h>
+#include <task.h>
+
+struct xOneGpioKeyInfo {
+	uint16_t keyJitterCount;
+	enum KeyState keyState;
+	struct xGpioKeyInfo *gpioKeyInfo;
+	struct xOneGpioKeyInfo *xNext;
+};
+
+static struct xOneGpioKeyInfo *xHeadKey;
+static TimerHandle_t xGpioKeyCycleTimer;
+
+static void prReportEvent(struct xGpioKeyInfo *xKey, uint32_t event)
+{
+	struct xReportEvent reportEvent;
+
+	reportEvent.ulCode = xKey->keyInitInfo.ulKeyId;
+	reportEvent.data = xKey->keyInitInfo.data;
+	reportEvent.event = event;
+	reportEvent.responseTime = 0;
+
+	if (xKey->keyInitInfo.CallBack)
+		xKey->keyInitInfo.CallBack(reportEvent);
+}
+
+static void prRunPollFromISR(void)
+{
+	if (xGpioKeyCycleTimer)
+		xTimerChangePeriodFromISR(xGpioKeyCycleTimer,
+					  1,
+					  NULL);
+}
+
+static void prvDetectGpioKey(TimerHandle_t xTimer)
+{
+	int uiValue;
+	uint8_t isPressingKey = 0;
+	struct xOneGpioKeyInfo *xPassBtn = xHeadKey;
+	struct xGpioKeyInfo *gpioKeyInfo;
+
+	(void)xTimer;
+	for (xPassBtn = xHeadKey; xPassBtn != NULL;
+						xPassBtn = xPassBtn->xNext) {
+		gpioKeyInfo = xPassBtn->gpioKeyInfo;
+
+		uiValue = xGpioGetValue(gpioKeyInfo->keyInitInfo.ulKeyId);
+		if (uiValue != gpioKeyInfo->ulInitLevel
+					&& xPassBtn->keyState == UP) {
+			isPressingKey = 1;
+
+			if (xPassBtn->keyJitterCount < KEY_JITTER_COUNT) {
+				xPassBtn->keyJitterCount++;
+				continue;
+			}
+			xPassBtn->keyJitterCount = 0;
+			xPassBtn->keyState = DOWN;
+			prReportEvent(xPassBtn->gpioKeyInfo, EVENT_SHORT);
+		} else if (uiValue == gpioKeyInfo->ulInitLevel
+			   && xPassBtn->keyState == DOWN) {
+
+			if (xPassBtn->keyJitterCount < KEY_JITTER_COUNT) {
+				xPassBtn->keyJitterCount++;
+				isPressingKey = 1;
+				continue;
+			}
+			xPassBtn->keyJitterCount = 0;
+			xPassBtn->keyState = UP;
+		} else if (uiValue != gpioKeyInfo->ulInitLevel
+			   && xPassBtn->keyState == DOWN) {
+			isPressingKey = 1;
+		}
+	}
+
+	if (isPressingKey) {
+		xTimerChangePeriod(xGpioKeyCycleTimer,
+				   pdMS_TO_TICKS(TIMER_CYCLE_TIME),
+				   0);
+	}
+}
+
+static void prvAddGpioKey(struct xOneGpioKeyInfo *xKey)
+{
+	if (!xKey)
+		return;
+	xKey->xNext = xHeadKey;
+	xHeadKey = xKey;
+}
+
+static void prvGpioKeyHandler(void)
+{
+	UBaseType_t uxSavedIntStaus;
+
+	uxSavedIntStaus = taskENTER_CRITICAL_FROM_ISR();
+	prRunPollFromISR();
+	taskEXIT_CRITICAL_FROM_ISR(uxSavedIntStaus);
+}
+
+void vCreateGpioKey(struct xGpioKeyInfo *keyArr, uint16_t keyNum)
+{
+	struct xOneGpioKeyInfo *xOneKey;
+	struct xGpioKeyInfo *gpioKeyInfo;
+	uint16_t i;
+
+	if (!xGpioKeyCycleTimer) {
+		xGpioKeyCycleTimer = xTimerCreate((const char *)"xGpioKeyTimer",
+						  1,
+						  pdFALSE,
+						  (void *)1,
+						  (TimerCallbackFunction_t)
+						  prvDetectGpioKey);
+		if (!xGpioKeyCycleTimer) {
+			printf("gpio timer create failed!\n");
+			return;
+		}
+	}
+
+	for (i = 0; i < keyNum; i++) {
+		xOneKey = pvPortMalloc(sizeof(struct xOneGpioKeyInfo));
+		if (xOneKey == NULL)
+			goto fail_alloc2;
+
+		gpioKeyInfo = pvPortMalloc(sizeof(struct xGpioKeyInfo));
+		if (gpioKeyInfo == NULL)
+			goto fail_alloc1;
+
+		memcpy(gpioKeyInfo, &keyArr[i], sizeof(struct xGpioKeyInfo));
+		memset(xOneKey, 0, sizeof(struct xOneGpioKeyInfo));
+		xOneKey->keyJitterCount = 0;
+		xOneKey->keyState = UP;
+		xOneKey->gpioKeyInfo = gpioKeyInfo;
+		prvAddGpioKey(xOneKey);
+
+		printf("keypad: add gpio key [%ld]\n",
+			xOneKey->gpioKeyInfo->keyInitInfo.ulKeyId);
+	}
+
+	return;
+
+fail_alloc1:
+	vPortFree(xOneKey);
+fail_alloc2:
+	printf("gpio key: [%d] malloc failed!\n", i);
+}
+
+void vDestoryGpioKey(void)
+{
+	struct xOneGpioKeyInfo *xPassBtn, *xTmpBtn;
+	uint32_t key_id;
+
+	for (xPassBtn = xHeadKey; xPassBtn != NULL;) {
+		key_id = xHeadKey->gpioKeyInfo->keyInitInfo.ulKeyId;
+
+		vPortFree(xPassBtn->gpioKeyInfo);
+
+		xTmpBtn = xPassBtn;
+		xPassBtn = xPassBtn->xNext;
+
+		vPortFree(xTmpBtn);
+
+		printf("keypad: del gpio key [%ld]\n", key_id);
+	}
+
+	xHeadKey = NULL;
+}
+
+void vGpioKeyEnable(void)
+{
+	struct xOneGpioKeyInfo *xPassBtn = xHeadKey;
+	struct xKeyInitInfo *keyInitInfo;
+
+	for (xPassBtn = xHeadKey; xPassBtn != NULL;
+						xPassBtn = xPassBtn->xNext) {
+		keyInitInfo = &(xPassBtn->gpioKeyInfo->keyInitInfo);
+
+		xPinmuxSet(keyInitInfo->ulKeyId, PIN_FUNC0);
+		xGpioSetDir(keyInitInfo->ulKeyId, GPIO_DIR_IN);
+		xPinconfSet(keyInitInfo->ulKeyId,
+				(xPassBtn->gpioKeyInfo->ulInitLevel == HIGH) ?
+				PINF_CONFIG_BIAS_PULL_UP :
+				PINF_CONFIG_BIAS_PULL_DOWN);
+		xRequestGpioIRQ(keyInitInfo->ulKeyId, prvGpioKeyHandler,
+				(xPassBtn->gpioKeyInfo->ulInitLevel == HIGH) ?
+				IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING);
+	}
+}
+
+void vGpioKeyDisable(void)
+{
+	struct xOneGpioKeyInfo *xPassBtn = xHeadKey;
+	struct xKeyInitInfo *keyInitInfo;
+
+	for (xPassBtn = xHeadKey; xPassBtn != NULL;
+						xPassBtn = xPassBtn->xNext) {
+		keyInitInfo = &(xPassBtn->gpioKeyInfo->keyInitInfo);
+
+		vFreeGpioIRQ(keyInitInfo->ulKeyId);
+	}
+}
+
+int vGpioKeyIsEmpty(void)
+{
+	return (!xHeadKey);
+}
diff --git a/bl30/src_ao/demos/amlogic/driver/leds/build.mk b/bl30/src_ao/demos/amlogic/driver/leds/build.mk
new file mode 100644
index 0000000..cd60cd5
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/leds/build.mk
@@ -0,0 +1,26 @@
+#
+#  Copyright (C) 2014-2018 Amlogic, Inc. All rights reserved.
+#
+#  All information contained herein is Amlogic confidential.
+#
+#  This software is provided to you pursuant to Software License Agreement
+#  (SLA) with Amlogic Inc ("Amlogic"). This software may be used
+#  only in accordance with the terms of this agreement.
+#
+#  Redistribution and use in source and binary forms, with or without
+#  modification is strictly prohibited without prior written permission from
+#  Amlogic.
+#
+#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#  OWNER 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, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+leds-y = leds_state.o leds_${SOC}_plat.o
diff --git a/bl30/src_ao/demos/amlogic/driver/leds/leds_a5_plat.c b/bl30/src_ao/demos/amlogic/driver/leds/leds_a5_plat.c
new file mode 100644
index 0000000..09c2abb
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/leds/leds_a5_plat.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2014-2018 Amlogic, Inc. All rights reserved.
+ *
+ * All information contained herein is Amlogic confidential.
+ *
+ * This software is provided to you pursuant to Software License Agreement
+ * (SLA) with Amlogic Inc ("Amlogic"). This software may be used
+ * only in accordance with the terms of this agreement.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification is strictly prohibited without prior written permission from
+ * Amlogic.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER 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, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "FreeRTOS.h"
+#include <gpio.h>
+#include <leds_plat.h>
+#include <leds_state.h>
+
+/* TODO: Temporarily use static variables instead of stick mem */
+static int32_t LedStickMem0;
+//static int32_t LedStickMem1;
+
+static LedCoord_t BreathInflections0[] = {
+	{0, 0},
+	{2500, 255},
+	{5000, 0}
+};
+
+static LedCoord_t BreathInflections1[] = {
+	{0, 0},
+	{5000, 255},
+	{10000, 0}
+};
+
+static LedCoord_t BreathInflections2[] = {
+	{0, 0},
+	{10000, 255},
+	{20000, 0}
+};
+
+static LedCoord_t BreathInflections3[] = {
+	{0, 0},
+	{20000, 255},
+	{40000, 0}
+};
+
+LedCoord_t *BreathInflections[LED_BREATH_MAX_COUNT] = {
+	BreathInflections0,
+	BreathInflections1,
+	BreathInflections2,
+	BreathInflections3,
+};
+
+LedDevice_t MesonLeds[] = {
+	{
+		.id = LED_ID_0,
+		.type = LED_TYPE_PWM,
+		.name = "sys_led",
+		.hardware_id = LED_PWM_G,
+		.polarity = LED_POLARITY_POSITIVE,
+		.breathtime = 0,
+	},
+};
+
+int32_t get_led_breath_len(uint32_t breath_id)
+{
+	switch (breath_id) {
+		case 0:
+			return sizeof(BreathInflections0)/sizeof(LedCoord_t);
+		case 1:
+			return sizeof(BreathInflections1)/sizeof(LedCoord_t);
+		case 2:
+			return sizeof(BreathInflections2)/sizeof(LedCoord_t);
+		case 3:
+			return sizeof(BreathInflections3)/sizeof(LedCoord_t);
+	} /* end swith */
+
+	iprintf("%s: id: %ld leds state init!\n", DRIVER_NAME, breath_id);
+
+	return -pdFREERTOS_ERRNO_EINVAL;
+}
+
+int32_t vLedPlatInit(int32_t ** stickmem)
+{
+	/* TODO: Here is initialization stickmem, but not doing so now */
+	*stickmem = &LedStickMem0;
+
+	/* off by default */
+	return xLedsStateSetBrightness(LED_ID_0, LED_OFF);
+}
+
+int32_t vLedPinmuxInit(void)
+{
+	/* set pinmux */
+	return xPinmuxSet(GPIOD_11, PIN_FUNC2);
+}
+
+
diff --git a/bl30/src_ao/demos/amlogic/driver/leds/leds_p1_plat.c b/bl30/src_ao/demos/amlogic/driver/leds/leds_p1_plat.c
new file mode 100644
index 0000000..faf3af9
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/leds/leds_p1_plat.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2014-2018 Amlogic, Inc. All rights reserved.
+ *
+ * All information contained herein is Amlogic confidential.
+ *
+ * This software is provided to you pursuant to Software License Agreement
+ * (SLA) with Amlogic Inc ("Amlogic"). This software may be used
+ * only in accordance with the terms of this agreement.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification is strictly prohibited without prior written permission from
+ * Amlogic.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER 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, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "FreeRTOS.h"
+#include <gpio.h>
+#include <leds_plat.h>
+#include <leds_state.h>
+
+/* TODO: Temporarily use static variables instead of stick mem */
+static int32_t LedStickMem0;
+//static int32_t LedStickMem1;
+
+static LedCoord_t BreathInflections0[] = {
+	{0, 0},
+	{2500, 255},
+	{5000, 0}
+};
+
+static LedCoord_t BreathInflections1[] = {
+	{0, 0},
+	{5000, 255},
+	{10000, 0}
+};
+
+static LedCoord_t BreathInflections2[] = {
+	{0, 0},
+	{10000, 255},
+	{20000, 0}
+};
+
+static LedCoord_t BreathInflections3[] = {
+	{0, 0},
+	{20000, 255},
+	{40000, 0}
+};
+
+LedCoord_t *BreathInflections[LED_BREATH_MAX_COUNT] = {
+	BreathInflections0,
+	BreathInflections1,
+	BreathInflections2,
+	BreathInflections3,
+};
+
+LedDevice_t MesonLeds[] = {
+	{
+		.id = LED_ID_0,
+		.type = LED_TYPE_PWM,
+		.name = "sys_led",
+		.hardware_id = LED_PWMAO_G,
+		.polarity = LED_POLARITY_POSITIVE,
+		.breathtime = 0,
+	},
+};
+
+int32_t get_led_breath_len(uint32_t breath_id)
+{
+	switch (breath_id) {
+		case 0:
+			return sizeof(BreathInflections0)/sizeof(LedCoord_t);
+		case 1:
+			return sizeof(BreathInflections1)/sizeof(LedCoord_t);
+		case 2:
+			return sizeof(BreathInflections2)/sizeof(LedCoord_t);
+		case 3:
+			return sizeof(BreathInflections3)/sizeof(LedCoord_t);
+	} /* end swith */
+
+	iprintf("%s: id: %ld leds state init!\n", DRIVER_NAME, breath_id);
+
+	return -pdFREERTOS_ERRNO_EINVAL;
+}
+
+int32_t vLedPlatInit(int32_t ** stickmem)
+{
+	/* TODO: Here is initialization stickmem, but not doing so now */
+	*stickmem = &LedStickMem0;
+
+	/* off by default */
+	return xLedsStateSetBrightness(LED_ID_0, LED_OFF);
+}
+
+int32_t vLedPinmuxInit(void)
+{
+	/* set pinmux */
+	return xPinmuxSet(GPIOD_7, PIN_FUNC2);
+}
+
+
diff --git a/bl30/src_ao/demos/amlogic/driver/leds/leds_s4_plat.c b/bl30/src_ao/demos/amlogic/driver/leds/leds_s4_plat.c
new file mode 100644
index 0000000..09c2abb
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/leds/leds_s4_plat.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2014-2018 Amlogic, Inc. All rights reserved.
+ *
+ * All information contained herein is Amlogic confidential.
+ *
+ * This software is provided to you pursuant to Software License Agreement
+ * (SLA) with Amlogic Inc ("Amlogic"). This software may be used
+ * only in accordance with the terms of this agreement.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification is strictly prohibited without prior written permission from
+ * Amlogic.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER 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, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "FreeRTOS.h"
+#include <gpio.h>
+#include <leds_plat.h>
+#include <leds_state.h>
+
+/* TODO: Temporarily use static variables instead of stick mem */
+static int32_t LedStickMem0;
+//static int32_t LedStickMem1;
+
+static LedCoord_t BreathInflections0[] = {
+	{0, 0},
+	{2500, 255},
+	{5000, 0}
+};
+
+static LedCoord_t BreathInflections1[] = {
+	{0, 0},
+	{5000, 255},
+	{10000, 0}
+};
+
+static LedCoord_t BreathInflections2[] = {
+	{0, 0},
+	{10000, 255},
+	{20000, 0}
+};
+
+static LedCoord_t BreathInflections3[] = {
+	{0, 0},
+	{20000, 255},
+	{40000, 0}
+};
+
+LedCoord_t *BreathInflections[LED_BREATH_MAX_COUNT] = {
+	BreathInflections0,
+	BreathInflections1,
+	BreathInflections2,
+	BreathInflections3,
+};
+
+LedDevice_t MesonLeds[] = {
+	{
+		.id = LED_ID_0,
+		.type = LED_TYPE_PWM,
+		.name = "sys_led",
+		.hardware_id = LED_PWM_G,
+		.polarity = LED_POLARITY_POSITIVE,
+		.breathtime = 0,
+	},
+};
+
+int32_t get_led_breath_len(uint32_t breath_id)
+{
+	switch (breath_id) {
+		case 0:
+			return sizeof(BreathInflections0)/sizeof(LedCoord_t);
+		case 1:
+			return sizeof(BreathInflections1)/sizeof(LedCoord_t);
+		case 2:
+			return sizeof(BreathInflections2)/sizeof(LedCoord_t);
+		case 3:
+			return sizeof(BreathInflections3)/sizeof(LedCoord_t);
+	} /* end swith */
+
+	iprintf("%s: id: %ld leds state init!\n", DRIVER_NAME, breath_id);
+
+	return -pdFREERTOS_ERRNO_EINVAL;
+}
+
+int32_t vLedPlatInit(int32_t ** stickmem)
+{
+	/* TODO: Here is initialization stickmem, but not doing so now */
+	*stickmem = &LedStickMem0;
+
+	/* off by default */
+	return xLedsStateSetBrightness(LED_ID_0, LED_OFF);
+}
+
+int32_t vLedPinmuxInit(void)
+{
+	/* set pinmux */
+	return xPinmuxSet(GPIOD_11, PIN_FUNC2);
+}
+
+
diff --git a/bl30/src_ao/demos/amlogic/driver/leds/leds_sc2_plat.c b/bl30/src_ao/demos/amlogic/driver/leds/leds_sc2_plat.c
new file mode 100644
index 0000000..0194566
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/leds/leds_sc2_plat.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2014-2018 Amlogic, Inc. All rights reserved.
+ *
+ * All information contained herein is Amlogic confidential.
+ *
+ * This software is provided to you pursuant to Software License Agreement
+ * (SLA) with Amlogic Inc ("Amlogic"). This software may be used
+ * only in accordance with the terms of this agreement.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification is strictly prohibited without prior written permission from
+ * Amlogic.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER 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, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "FreeRTOS.h"
+#include <gpio.h>
+#include <leds_plat.h>
+#include <leds_state.h>
+
+/* TODO: Temporarily use static variables instead of stick mem */
+static int32_t LedStickMem0;
+//static int32_t LedStickMem1;
+
+static LedCoord_t BreathInflections0[] = {
+	{0, 0},
+	{2500, 255},
+	{5000, 0}
+};
+
+static LedCoord_t BreathInflections1[] = {
+	{0, 0},
+	{5000, 255},
+	{10000, 0}
+};
+
+static LedCoord_t BreathInflections2[] = {
+	{0, 0},
+	{10000, 255},
+	{20000, 0}
+};
+
+static LedCoord_t BreathInflections3[] = {
+	{0, 0},
+	{20000, 255},
+	{40000, 0}
+};
+
+LedCoord_t *BreathInflections[LED_BREATH_MAX_COUNT] = {
+	BreathInflections0,
+	BreathInflections1,
+	BreathInflections2,
+	BreathInflections3,
+};
+
+LedDevice_t MesonLeds[] = {
+	{
+		.id = LED_ID_0,
+		.type = LED_TYPE_PWM,
+		.name = "sys_led",
+		.hardware_id = LED_PWM_G,
+		.polarity = LED_POLARITY_POSITIVE,
+		.breathtime = 0,
+	},
+};
+
+int32_t get_led_breath_len(uint32_t breath_id)
+{
+	switch (breath_id) {
+		case 0:
+			return sizeof(BreathInflections0)/sizeof(LedCoord_t);
+		case 1:
+			return sizeof(BreathInflections1)/sizeof(LedCoord_t);
+		case 2:
+			return sizeof(BreathInflections2)/sizeof(LedCoord_t);
+		case 3:
+			return sizeof(BreathInflections3)/sizeof(LedCoord_t);
+	} /* end swith */
+
+	iprintf("%s: id: %ld leds state init!\n", DRIVER_NAME, breath_id);
+
+	return -pdFREERTOS_ERRNO_EINVAL;
+}
+
+int32_t vLedPlatInit(int32_t ** stickmem)
+{
+	/* TODO: Here is initialization stickmem, but not doing so now */
+	*stickmem = &LedStickMem0;
+
+	/* off by default */
+	return xLedsStateSetBrightness(LED_ID_0, LED_OFF);
+}
+
+int32_t vLedPinmuxInit(void)
+{
+	/* set pinmux */
+	return xPinmuxSet(GPIOD_11, PIN_FUNC3);
+}
+
diff --git a/bl30/src_ao/demos/amlogic/driver/leds/leds_state.c b/bl30/src_ao/demos/amlogic/driver/leds/leds_state.c
new file mode 100644
index 0000000..d66f134
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/leds/leds_state.c
@@ -0,0 +1,586 @@
+/*
+ * Copyright (C) 2014-2018 Amlogic, Inc. All rights reserved.
+ *
+ * All information contained herein is Amlogic confidential.
+ *
+ * This software is provided to you pursuant to Software License Agreement
+ * (SLA) with Amlogic Inc ("Amlogic"). This software may be used
+ * only in accordance with the terms of this agreement.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification is strictly prohibited without prior written permission from
+ * Amlogic.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER 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, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * leds driver
+ */
+
+#include "FreeRTOS.h" /* Must come first. */
+#include "task.h"     /* RTOS task related API prototypes. */
+#include "queue.h"    /* RTOS queue related API prototypes. */
+#include "timers.h"   /* Software timer related API prototypes. */
+#include "semphr.h"   /* Semaphore related API prototypes. */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <common.h>
+#include <pwm.h>
+#include <leds_plat.h>
+#include <leds_state.h>
+#include "mailbox-api.h"
+
+/* todo: wait for stick mem ready */
+static int32_t *PLedStickMem[LED_ID_MAX];
+extern LedCoord_t *BreathInflections[];
+
+uint32_t LedMask[STICK_LED_INVALID] = {
+	STICK_LED_STATE_MASK,
+	STICK_LED_BRIGHTNESS_MASK,
+	STICK_LED_BREATH_ID_MASK,
+	STICK_LED_BLINK_TIMES_MASK,
+	STICK_LED_BLINK_HIGH_MASK,
+	STICK_LED_BLINK_LOW_MASK
+};
+
+static int32_t prvStickMemLedRead(uint32_t id, enum StickMemLedIdx index, uint32_t *data)
+{
+	uint32_t temp;
+
+	if ((index >= STICK_LED_INVALID) || (id >= LED_ID_MAX)) {
+		iprintf("%s: index: %d id: %ld read stick mem fail!\n", DRIVER_NAME, index, id);
+		return -pdFREERTOS_ERRNO_EINVAL;
+	}
+
+	if (!PLedStickMem[id]) {
+		iprintf("%s: id: %ld stick mem no ready!\n", DRIVER_NAME, id);
+		return -pdFREERTOS_ERRNO_EINVAL;
+	}
+
+	temp = *PLedStickMem[id];
+	*data = FIELD_GET(LedMask[index], temp);
+
+	return 0;
+}
+
+static int32_t prvStickMemLedWrite(uint32_t id, enum StickMemLedIdx index, uint32_t data)
+{
+	uint32_t temp;
+
+	if ((index >= STICK_LED_INVALID) || (id >= LED_ID_MAX)) {
+		iprintf("%s: index: %d id: %ld write stick mem fail!\n", DRIVER_NAME, index, id);
+		return -pdFREERTOS_ERRNO_EINVAL;
+	}
+
+	if (!PLedStickMem[id]) {
+		iprintf("%s: id: %ld stick mem no ready!\n", DRIVER_NAME, id);
+		return -pdFREERTOS_ERRNO_EINVAL;
+	}
+
+	temp = *PLedStickMem[id];
+	temp &= ~(LedMask[index]);
+	temp |= FIELD_PREP(LedMask[index], data);
+	*PLedStickMem[id] = temp;
+
+	return 0;
+}
+
+static int32_t prvPwmLedIsBlinkedComplete(uint32_t id)
+{
+	return xPwmMesonIsBlinkComplete(MesonLeds[id].pwm);
+}
+
+static int32_t prvPwmLedSetBrightness(uint32_t id, uint32_t brightness)
+{
+	uint32_t new_duty;
+	unsigned long temp;
+
+	if (MesonLeds[id].polarity) {
+		/* TODO: Consider using hardware inversion later */
+		//vPwmMesonSetPolarity(MesonLeds[id].pwm, LED_POLARITY_INVERT);
+		brightness = LED_FULL - brightness;
+	}
+	temp = LED_PERIOD * (unsigned long)brightness;
+	temp /= LED_FULL;
+	new_duty = (uint32_t)temp;
+	xPwmMesonConfig(MesonLeds[id].pwm, new_duty, LED_PERIOD);
+	vPwmMesonDisable(MesonLeds[id].pwm_sub);
+	vPwmMesonEnable(MesonLeds[id].pwm);
+
+	return 0;
+}
+
+static int32_t prvPwmLedBlinkTimes(uint32_t id, uint32_t times, uint32_t high_cnt, uint32_t low_cnt)
+{
+	uint32_t duty1 ,duty2;
+
+	/* TODO: blink brightness */
+	duty1 = 50000000; // 50ms
+	duty2 = 0;
+
+	if (MesonLeds[id].polarity) {
+		/* TODO: Consider using hardware inversion later */
+		//vPwmMesonSetPolarity(MesonLeds[id].pwm, LED_POLARITY_INVERT);
+		xPwmMesonConfig(MesonLeds[id].pwm, duty1, duty1);
+		xPwmMesonConfig(MesonLeds[id].pwm_sub, duty2, duty1);
+	} else {
+		xPwmMesonConfig(MesonLeds[id].pwm, duty2, duty1);
+		xPwmMesonConfig(MesonLeds[id].pwm_sub, duty1, duty1);
+	}
+	vPwmConstantDisable(MesonLeds[id].pwm);
+	vPwmMesonSetTimes(MesonLeds[id].pwm, high_cnt);
+	vPwmMesonSetTimes(MesonLeds[id].pwm_sub, low_cnt);
+	if (times) {
+		vPwmMesonSetBlinkTimes(MesonLeds[id].pwm, times);
+		vPwmMesonBlinkEnable(MesonLeds[id].pwm);
+	} else {
+		vPwmMesonBlinkDisable(MesonLeds[id].pwm);
+	}
+	vPwmMesonEnable(MesonLeds[id].pwm_sub);
+	vPwmMesonEnable(MesonLeds[id].pwm);
+
+	return 0;
+}
+
+static uint32_t prvCurveApproximate(LedCoord_t *c, uint32_t num, uint32_t x)
+{
+	uint32_t i, x0, y0, x1, y1, y=0;
+
+	for (i = 1; i <= num; i++) {
+		if (x < c[i].x) {
+			x0 = c[i-1].x;
+			y0 = c[i-1].y;
+			x1 = c[i].x;
+			y1 = c[i].y;
+			if (y1 == y0) {
+				y = y0;
+			} else if (y1 > y0) {
+				y = y0 + (y1-y0)*(x-x0)/(x1-x0);
+			} else {
+				y = y0 - (y0-y1)*(x-x0)/(x1-x0);
+			}
+			break;
+		}
+	}
+	return y;
+}
+
+static void prvLedBreath(uint32_t id, uint32_t breath_id)
+{
+	int32_t num = 0;
+	uint32_t brightness;
+	LedCoord_t *co;
+
+	/*init breath_inflections parameters*/
+	num = get_led_breath_len(breath_id);
+	if (num <= 0) {
+		iprintf("%s: id: %ld get breath len fail!\n", DRIVER_NAME, breath_id);
+		return;
+	}
+	co = BreathInflections[breath_id];
+	if (MesonLeds[id].breathtime > co[num-1].x)
+		MesonLeds[id].breathtime = 0;
+	brightness = prvCurveApproximate(co, num, MesonLeds[id].breathtime);
+	prvPwmLedSetBrightness(id, brightness);
+	MesonLeds[id].breathtime += LED_TASK_TIME_MS;
+}
+
+static void prvSetLedStateToDefault(uint32_t id)
+{
+	prvStickMemLedWrite(id, STICK_LED_STATE, LED_STATE_DEFAULT);
+}
+
+
+static uint32_t prvGetLedBlinkHigh(uint32_t id)
+{
+	uint32_t high;
+	int32_t ret;
+
+	ret = prvStickMemLedRead(id, STICK_LED_BLINK_HIGH, &high);
+	if (ret) {
+		iprintf("%s: id: %ld get led blink high fail return 1!\n", DRIVER_NAME, id);
+		return LED_ERROR_CNT;
+	}
+
+	return high;
+}
+
+static uint32_t prvGetLedBlinkLow(uint32_t id)
+{
+	uint32_t low;
+	int32_t ret;
+
+	ret = prvStickMemLedRead(id, STICK_LED_BLINK_LOW, &low);
+	if (ret) {
+		iprintf("%s: id: %ld get led blink low fail return 1!\n", DRIVER_NAME, id);
+		return LED_ERROR_CNT;
+	}
+
+	return low;
+}
+
+static uint32_t prvGetLedBlinkTimes(uint32_t id)
+{
+	uint32_t times;
+	int32_t ret;
+
+	ret = prvStickMemLedRead(id, STICK_LED_BLINK_TIMES, &times);
+	if (ret) {
+		iprintf("%s: id: %ld get led blink times fail return 1!\n", DRIVER_NAME, id);
+		return LED_ERROR_CNT;
+	}
+
+	return times;
+}
+
+static uint32_t prvGetLedBreathId(uint32_t id)
+{
+	uint32_t breath_id;
+	int32_t ret;
+
+	ret = prvStickMemLedRead(id, STICK_LED_BREATH_ID, &breath_id);
+	if (ret) {
+		iprintf("%s: id: %ld get led breath id fail return 1!\n", DRIVER_NAME, id);
+		return LED_ERROR_CNT;
+	}
+
+	return breath_id;
+}
+
+static uint32_t prvGetLedBrightness(uint32_t id)
+{
+	uint32_t brightness;
+	int32_t ret;
+
+	ret = prvStickMemLedRead(id, STICK_LED_BRIGHTNESS, &brightness);
+	if (ret) {
+		iprintf("%s: id: %ld get led brightness fail return 1!\n", DRIVER_NAME, id);
+		return LED_ERROR_CNT;
+	}
+
+	return (brightness & 0xff);
+}
+
+static void prvSetLedState(enum LedState state, uint32_t id)
+{
+	if (state == MesonLeds[id].curr_led_state)
+		return;
+	MesonLeds[id].last_led_state = MesonLeds[id].curr_led_state;
+	MesonLeds[id].curr_led_state = state;
+}
+
+static enum LedState prvGetLastLedState(uint32_t id)
+{
+	return MesonLeds[id].last_led_state;
+}
+
+static void prvLedStateMachine(enum LedState state, uint32_t id)
+{
+	static int blinkflag = 0;
+	prvSetLedState(state, id);
+
+	switch (state) {
+		/*
+		 * led breath use the same timer task to handle breathe.
+		 * so don't set the new state.
+		 */
+		case LED_STATE_BRIGHTNESS:
+			prvPwmLedSetBrightness(id, prvGetLedBrightness(id));
+			prvSetLedStateToDefault(id);
+			blinkflag = 0;
+			break;
+		case LED_STATE_BREATH:
+			prvLedBreath(id, prvGetLedBreathId(id));
+			blinkflag = 0;
+			break;
+		case LED_STATE_BLINK_ON:
+			if (blinkflag == 0) {
+				prvPwmLedBlinkTimes(id, prvGetLedBlinkTimes(id), prvGetLedBlinkHigh(id), prvGetLedBlinkLow(id));
+				prvStickMemLedWrite(id, STICK_LED_STATE, LED_STATE_BLINK_ON_HANDLE);
+				blinkflag++;
+			} else if (prvPwmLedIsBlinkedComplete(id)) {
+				prvPwmLedBlinkTimes(id, prvGetLedBlinkTimes(id), prvGetLedBlinkHigh(id), prvGetLedBlinkLow(id));
+				prvStickMemLedWrite(id, STICK_LED_STATE, LED_STATE_BLINK_ON_HANDLE);
+			}
+			break;
+		case LED_STATE_BLINK_OFF:
+			if (blinkflag == 0) {
+				prvPwmLedBlinkTimes(id, prvGetLedBlinkTimes(id), prvGetLedBlinkHigh(id), prvGetLedBlinkLow(id));
+				prvStickMemLedWrite(id, STICK_LED_STATE, LED_STATE_BLINK_OFF_HANDLE);
+				blinkflag++;
+			} else if (prvPwmLedIsBlinkedComplete(id)) {
+				prvPwmLedBlinkTimes(id, prvGetLedBlinkTimes(id), prvGetLedBlinkHigh(id), prvGetLedBlinkLow(id));
+				prvStickMemLedWrite(id, STICK_LED_STATE, LED_STATE_BLINK_OFF_HANDLE);
+			}
+			break;
+		case LED_STATE_BLINK_BREATH:
+			prvPwmLedBlinkTimes(id, prvGetLedBlinkTimes(id), prvGetLedBlinkHigh(id), prvGetLedBlinkLow(id));
+			prvStickMemLedWrite(id, STICK_LED_STATE, LED_STATE_BLINK_BREATH_HANDLE);
+			break;
+		case LED_STATE_BLINK_ON_HANDLE:
+			if ((prvPwmLedIsBlinkedComplete(id) == 1)
+				|| (prvGetLastLedState(id)==LED_STATE_DEFAULT)) {
+				prvPwmLedSetBrightness(id, LED_FULL);
+				prvSetLedStateToDefault(id);
+				blinkflag = 0;
+			}
+			break;
+		case LED_STATE_BLINK_OFF_HANDLE:
+			if ((prvPwmLedIsBlinkedComplete(id) == 1)
+				|| (prvGetLastLedState(id)==LED_STATE_DEFAULT)) {
+				prvPwmLedSetBrightness(id, LED_OFF);
+				prvSetLedStateToDefault(id);
+				blinkflag = 0;
+			}
+			break;
+		case LED_STATE_BLINK_BREATH_HANDLE:
+			if ((prvPwmLedIsBlinkedComplete(id) == 1)
+				|| (prvGetLastLedState(id)==LED_STATE_DEFAULT)) {
+				prvStickMemLedWrite(id, STICK_LED_STATE, LED_STATE_BREATH);
+			}
+			break;
+#if 0
+		/* TODO: Expansion of auxiliary functions */
+		case LED_STATE_SET_MAX_BRIGHTNESS:
+			break;
+		case LED_STATE_CLEAR_PINMUX:
+			break;
+		case LED_STATE_SET_PINMUX:
+			break;
+		case LED_STATE_INFO:
+			break;
+		case LED_STATE_DEBUG:
+			break;
+#endif
+		case LED_STATE_INVALID:
+			break;
+		case LED_STATE_DEFAULT:
+			break;
+	} /* end swith */
+
+}
+
+static void *prvLedGetInfo(void *msg)
+{
+	uint32_t state, id, brightness, breath, blink_times, blink_high, blink_low;
+
+	id = *(u32 *)msg;
+	state = *(((u32 *)msg) + 1);
+	switch (state) {
+			/*
+			 * led breath use the same timer task to handle breathe.
+			 * so don't set the new state.
+			 */
+			case LED_STATE_BRIGHTNESS:
+				brightness = *(((u32 *)msg) + 2);
+				xLedsStateSetBrightness(id, brightness);
+				break;
+			case LED_STATE_BREATH:
+				breath = *(((u32 *)msg) + 2);
+				xLedsStateSetBreath(id, breath);
+				break;
+			case LED_STATE_BLINK_ON:
+				blink_times = *(((u32 *)msg) + 2);
+				blink_high = *(((u32 *)msg) + 3);
+				blink_low = *(((u32 *)msg) + 4);
+				xLedsStateSetBlinkOn(id, blink_times, blink_high, blink_low, 0, 0);
+				break;
+			case LED_STATE_BLINK_OFF:
+				blink_times = *(((u32 *)msg) + 2);
+				blink_high = *(((u32 *)msg) + 3);
+				blink_low = *(((u32 *)msg) + 4);
+				xLedsStateSetBlinkOff(id, blink_times, blink_high, blink_low, 0, 0);
+				break;
+			case LED_STATE_BLINK_BREATH:
+				blink_times = *(((u32 *)msg) + 2);
+				blink_high = *(((u32 *)msg) + 3);
+				blink_low = *(((u32 *)msg) + 4);
+				xLedsStateSetBlinkBreath(id, blink_times, blink_high, blink_low, 0, 0);
+				break;
+#if 0
+			/* TODO: Expansion of auxiliary functions */
+			case LED_STATE_SET_MAX_BRIGHTNESS:
+				break;
+			case LED_STATE_CLEAR_PINMUX:
+				break;
+			case LED_STATE_SET_PINMUX:
+				break;
+			case LED_STATE_INFO:
+				break;
+			case LED_STATE_DEBUG:
+				break;
+#endif
+			case LED_STATE_INVALID:
+				break;
+			case LED_STATE_DEFAULT:
+				break;
+		} /* end swith */
+
+	return NULL;
+}
+
+static void vPrintLedsStatus(TimerHandle_t xTimer)
+{
+	xTimer = xTimer;
+	uint32_t i, state = 0;
+
+	//taskENTER_CRITICAL();
+	for (i = 0; i < LED_ID_MAX; i++) {
+		prvStickMemLedRead(i , STICK_LED_STATE, &state);
+		prvLedStateMachine(state, i);
+	}
+	//taskEXIT_CRITICAL();
+}
+
+int32_t xLedsStateSetBlinkBreath(uint32_t id, uint32_t times, uint32_t high_ms, uint32_t low_ms, uint32_t high_br, uint32_t low_br)
+{
+	if ((id >= LED_ID_MAX) || (times > LED_MAX_BLINK_CNT)) {
+		iprintf("%s: id: %ld times: %ld set blink breath fail! maxid: %d maxtime: %d\n", DRIVER_NAME, id, times, LED_ID_MAX - 1, LED_MAX_BLINK_CNT);
+		return -pdFREERTOS_ERRNO_EINVAL;
+	}
+
+	if ((high_ms > LED_MAX_HIGH_MS) || (low_ms > LED_MAX_HIGH_MS)) {
+		iprintf("%s: high: %ldms low: %ldms set blink breath fail! maxhigh: %dms maxlow: %dms\n", DRIVER_NAME, high_ms, low_ms, LED_MAX_HIGH_MS, LED_MAX_LOW_MS);
+		return -pdFREERTOS_ERRNO_EINVAL;
+	}
+
+	/* TODO: high_br low_br no ready */
+	if (low_br || high_br)
+		iprintf("%s: low_br high_br no ready!\n", DRIVER_NAME);
+
+	prvStickMemLedWrite(id, STICK_LED_BLINK_TIMES, times);
+	prvStickMemLedWrite(id, STICK_LED_BLINK_HIGH, high_ms / 50);
+	prvStickMemLedWrite(id, STICK_LED_BLINK_LOW, low_ms / 50);
+	prvStickMemLedWrite(id, STICK_LED_STATE, LED_STATE_BLINK_BREATH);
+
+	return 0;
+}
+
+int32_t xLedsStateSetBlinkOn(uint32_t id, uint32_t times, uint32_t high_ms, uint32_t low_ms, uint32_t high_br, uint32_t low_br)
+{
+	if ((id >= LED_ID_MAX) || (times > LED_MAX_BLINK_CNT)) {
+		iprintf("%s: id: %ld times: %ld set blink on fail! maxid: %d maxtime: %d\n", DRIVER_NAME, id, times, LED_ID_MAX - 1, LED_MAX_BLINK_CNT);
+		return -pdFREERTOS_ERRNO_EINVAL;
+	}
+
+	if ((high_ms > LED_MAX_HIGH_MS) || (low_ms > LED_MAX_HIGH_MS)) {
+		iprintf("%s: high: %ldms low: %ldms set blink on fail! maxhigh: %dms maxlow: %dms\n", DRIVER_NAME, high_ms, low_ms, LED_MAX_HIGH_MS, LED_MAX_LOW_MS);
+		return -pdFREERTOS_ERRNO_EINVAL;
+	}
+
+	/* TODO: high_br low_br no ready */
+	if (low_br || high_br)
+		iprintf("%s: low_br high_br no ready!\n", DRIVER_NAME);
+
+	prvStickMemLedWrite(id, STICK_LED_BLINK_TIMES, times);
+	prvStickMemLedWrite(id, STICK_LED_BLINK_HIGH, high_ms / 50);
+	prvStickMemLedWrite(id, STICK_LED_BLINK_LOW, low_ms / 50);
+	prvStickMemLedWrite(id, STICK_LED_STATE, LED_STATE_BLINK_ON);
+
+	return 0;
+}
+
+int32_t xLedsStateSetBlinkOff(uint32_t id, uint32_t times, uint32_t high_ms, uint32_t low_ms, uint32_t high_br, uint32_t low_br)
+{
+	if ((id >= LED_ID_MAX) || (times > LED_MAX_BLINK_CNT)) {
+		iprintf("%s: id: %ld times: %ld set blink off fail! maxid: %d maxtime: %d\n", DRIVER_NAME, id, times, LED_ID_MAX - 1, LED_MAX_BLINK_CNT);
+		return -pdFREERTOS_ERRNO_EINVAL;
+	}
+
+	if ((high_ms > LED_MAX_HIGH_MS) || (low_ms > LED_MAX_HIGH_MS)) {
+		iprintf("%s: high: %ldms low: %ldms set blink off fail! maxhigh: %dms maxlow: %dms\n", DRIVER_NAME, high_ms, low_ms, LED_MAX_HIGH_MS, LED_MAX_LOW_MS);
+		return -pdFREERTOS_ERRNO_EINVAL;
+	}
+
+	/* TODO: high_br low_br no ready */
+	if (low_br || high_br)
+		iprintf("%s: low_br high_br no ready!\n", DRIVER_NAME);
+
+	prvStickMemLedWrite(id, STICK_LED_BLINK_TIMES, times);
+	prvStickMemLedWrite(id, STICK_LED_BLINK_HIGH, high_ms / 50);
+	prvStickMemLedWrite(id, STICK_LED_BLINK_LOW, low_ms / 50);
+	prvStickMemLedWrite(id, STICK_LED_STATE, LED_STATE_BLINK_OFF);
+
+	return 0;
+}
+
+int32_t xLedsStateSetBreath(uint32_t id, uint32_t breath_id)
+{
+	if ((id >= LED_ID_MAX) || (breath_id >= LED_BREATH_MAX_COUNT)) {
+		iprintf("%s: id: %ld breath id: %ld set breath fail! maxid: %d maxbreath id: %d\n", DRIVER_NAME, id, breath_id, LED_ID_MAX - 1, LED_BREATH_MAX_COUNT - 1);
+		return -pdFREERTOS_ERRNO_EINVAL;
+	}
+
+	MesonLeds[id].breathtime = 0;
+	prvStickMemLedWrite(id, STICK_LED_BREATH_ID, breath_id);
+	prvStickMemLedWrite(id, STICK_LED_STATE, LED_STATE_BREATH);
+
+	return 0;
+}
+
+int32_t xLedsStateSetBrightness(uint32_t id, uint32_t brightness)
+{
+	if ((id >= LED_ID_MAX) || (brightness > LED_FULL)) {
+		iprintf("%s: id: %ld brightness: %ld set brightness fail! maxid: %d maxbrightness: %d\n", DRIVER_NAME, id, brightness, LED_ID_MAX - 1, LED_FULL);
+		return -pdFREERTOS_ERRNO_EINVAL;
+	}
+
+	prvStickMemLedWrite(id, STICK_LED_BRIGHTNESS, brightness);
+	prvStickMemLedWrite(id, STICK_LED_STATE, LED_STATE_BRIGHTNESS);
+
+	return 0;
+}
+
+int32_t xLedsStateInit(void)
+{
+	TimerHandle_t xLedsTimer = NULL;
+	int32_t ret, i;
+
+	iprintf("%s: leds state init!\n", DRIVER_NAME);
+	/* TODO: free */
+	/* apply pwm */
+	for (i = 0; i < LED_ID_MAX; i++) {
+		MesonLeds[i].pwm = xPwmMesonChannelApply(MesonLeds[i].hardware_id / LED_PWM_CHAN_CNT, MesonLeds[i].hardware_id % LED_PWM_CHAN_CNT);
+		if (!MesonLeds[i].pwm) {
+			iprintf("%s: id: %ld chip: %ld channel: %ld apply pwm channel fail!\n", DRIVER_NAME, i, MesonLeds[i].hardware_id / LED_PWM_CHAN_CNT, MesonLeds[i].hardware_id % LED_PWM_CHAN_CNT);
+			return -pdFREERTOS_ERRNO_EINVAL;
+		}
+		MesonLeds[i].pwm_sub= xPwmMesonChannelApply(MesonLeds[i].hardware_id / LED_PWM_CHAN_CNT, MesonLeds[i].hardware_id % LED_PWM_CHAN_CNT + LED_PWM_CHAN_CNT);
+		if (!MesonLeds[i].pwm_sub) {
+			iprintf("%s: id: %ld chip: %ld channel: %ld apply pwm channel fail!\n", DRIVER_NAME, i, MesonLeds[i].hardware_id / LED_PWM_CHAN_CNT, MesonLeds[i].hardware_id % LED_PWM_CHAN_CNT + LED_PWM_CHAN_CNT);
+			return -pdFREERTOS_ERRNO_EINVAL;
+		}
+	}
+
+	/* register mailbox */
+	ret = xInstallRemoteMessageCallbackFeedBack(AOREE_CHANNEL, MBX_CMD_GET_LED_INFO,
+						    prvLedGetInfo, 1);
+	if (ret == MBOX_CALL_MAX) {
+		iprintf("%s: mbox cmd 0x%x register fail\n", DRIVER_NAME, MBX_CMD_GET_LED_INFO);
+		return -pdFREERTOS_ERRNO_EINVAL;
+	}
+
+	/* initialization status */
+	vLedPlatInit(PLedStickMem);
+	/* creat led timer */
+	xLedsTimer = xTimerCreate("Timer", pdMS_TO_TICKS(LED_TASK_TIME_MS), pdTRUE, NULL, vPrintLedsStatus);
+	iprintf("%s: Starting leds task ...\n", DRIVER_NAME);
+	xTimerStart(xLedsTimer, 0);
+
+	/* pinmux needs setting at the end */
+	return vLedPinmuxInit();
+}
+
diff --git a/bl30/src_ao/demos/amlogic/driver/leds/leds_t3_plat.c b/bl30/src_ao/demos/amlogic/driver/leds/leds_t3_plat.c
new file mode 100644
index 0000000..27b9cfb
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/leds/leds_t3_plat.c
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2014-2018 Amlogic, Inc. All rights reserved.
+ *
+ * All information contained herein is Amlogic confidential.
+ *
+ * This software is provided to you pursuant to Software License Agreement
+ * (SLA) with Amlogic Inc ("Amlogic"). This software may be used
+ * only in accordance with the terms of this agreement.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification is strictly prohibited without prior written permission from
+ * Amlogic.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER 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, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "FreeRTOS.h"
+#include <gpio.h>
+#include <leds_plat.h>
+#include <leds_state.h>
+
+/* TODO: Temporarily use static variables instead of stick mem */
+static int32_t LedStickMem0;
+//static int32_t LedStickMem1;
+
+static LedCoord_t BreathInflections0[] = {
+	{0, 0},
+	{2500, 255},
+	{5000, 0}
+};
+
+static LedCoord_t BreathInflections1[] = {
+	{0, 0},
+	{5000, 255},
+	{10000, 0}
+};
+
+static LedCoord_t BreathInflections2[] = {
+	{0, 0},
+	{10000, 255},
+	{20000, 0}
+};
+
+static LedCoord_t BreathInflections3[] = {
+	{0, 0},
+	{20000, 255},
+	{40000, 0}
+};
+
+LedCoord_t *BreathInflections[LED_BREATH_MAX_COUNT] = {
+	BreathInflections0,
+	BreathInflections1,
+	BreathInflections2,
+	BreathInflections3,
+};
+
+LedDevice_t MesonLeds[] = {
+	{
+		.id = LED_ID_0,
+		.type = LED_TYPE_PWM,
+		.name = "sys_led",
+		.hardware_id = LED_PWM_C,
+		.polarity = LED_POLARITY_POSITIVE,
+		.breathtime = 0,
+	},
+};
+
+int32_t get_led_breath_len(uint32_t breath_id)
+{
+	switch (breath_id) {
+		case 0:
+			return sizeof(BreathInflections0)/sizeof(LedCoord_t);
+		case 1:
+			return sizeof(BreathInflections1)/sizeof(LedCoord_t);
+		case 2:
+			return sizeof(BreathInflections2)/sizeof(LedCoord_t);
+		case 3:
+			return sizeof(BreathInflections3)/sizeof(LedCoord_t);
+	} /* end swith */
+
+	iprintf("%s: id: %ld leds state init!\n", DRIVER_NAME, breath_id);
+
+	return -pdFREERTOS_ERRNO_EINVAL;
+}
+
+int32_t vLedPlatInit(int32_t ** stickmem)
+{
+	/* TODO: Here is initialization stickmem, but not doing so now */
+	*stickmem = &LedStickMem0;
+
+	/* off by default */
+	return xLedsStateSetBrightness(LED_ID_0, LED_OFF);
+}
+
+int32_t vLedPinmuxInit(void)
+{
+	/* set pinmux */
+	return xPinmuxSet(GPIOD_7, PIN_FUNC2);
+}
+
+
+
diff --git a/bl30/src_ao/demos/amlogic/driver/leds/leds_t5_plat.c b/bl30/src_ao/demos/amlogic/driver/leds/leds_t5_plat.c
new file mode 100644
index 0000000..39646e5
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/leds/leds_t5_plat.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2014-2018 Amlogic, Inc. All rights reserved.
+ *
+ * All information contained herein is Amlogic confidential.
+ *
+ * This software is provided to you pursuant to Software License Agreement
+ * (SLA) with Amlogic Inc ("Amlogic"). This software may be used
+ * only in accordance with the terms of this agreement.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification is strictly prohibited without prior written permission from
+ * Amlogic.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER 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, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "FreeRTOS.h"
+#include <gpio.h>
+#include <leds_plat.h>
+#include <leds_state.h>
+
+/* TODO: Temporarily use static variables instead of stick mem */
+static int32_t LedStickMem0;
+//static int32_t LedStickMem1;
+
+static LedCoord_t BreathInflections0[] = {
+	{0, 0},
+	{2500, 255},
+	{5000, 0}
+};
+
+static LedCoord_t BreathInflections1[] = {
+	{0, 0},
+	{5000, 255},
+	{10000, 0}
+};
+
+static LedCoord_t BreathInflections2[] = {
+	{0, 0},
+	{10000, 255},
+	{20000, 0}
+};
+
+static LedCoord_t BreathInflections3[] = {
+	{0, 0},
+	{20000, 255},
+	{40000, 0}
+};
+
+LedCoord_t *BreathInflections[LED_BREATH_MAX_COUNT] = {
+	BreathInflections0,
+	BreathInflections1,
+	BreathInflections2,
+	BreathInflections3,
+};
+
+LedDevice_t MesonLeds[] = {
+	{
+		.id = LED_ID_0,
+		.type = LED_TYPE_PWM,
+		.name = "sys_led",
+		.hardware_id = LED_PWM_C,
+		.polarity = LED_POLARITY_POSITIVE,
+		.breathtime = 0,
+	},
+};
+
+int32_t get_led_breath_len(uint32_t breath_id)
+{
+	switch (breath_id) {
+		case 0:
+			return sizeof(BreathInflections0)/sizeof(LedCoord_t);
+		case 1:
+			return sizeof(BreathInflections1)/sizeof(LedCoord_t);
+		case 2:
+			return sizeof(BreathInflections2)/sizeof(LedCoord_t);
+		case 3:
+			return sizeof(BreathInflections3)/sizeof(LedCoord_t);
+	} /* end swith */
+
+	iprintf("%s: id: %ld leds state init!\n", DRIVER_NAME, breath_id);
+
+	return -pdFREERTOS_ERRNO_EINVAL;
+}
+
+int32_t vLedPlatInit(int32_t ** stickmem)
+{
+	/* TODO: Here is initialization stickmem, but not doing so now */
+	*stickmem = &LedStickMem0;
+
+	/* off by default */
+	return xLedsStateSetBrightness(LED_ID_0, LED_OFF);
+}
+
+int32_t vLedPinmuxInit(void)
+{
+	/* set pinmux */
+	return xPinmuxSet(GPIOD_7, PIN_FUNC2);
+}
+
+
diff --git a/bl30/src_ao/demos/amlogic/driver/leds/leds_t5d_plat.c b/bl30/src_ao/demos/amlogic/driver/leds/leds_t5d_plat.c
new file mode 100644
index 0000000..935a894
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/leds/leds_t5d_plat.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2014-2018 Amlogic, Inc. All rights reserved.
+ *
+ * All information contained herein is Amlogic confidential.
+ *
+ * This software is provided to you pursuant to Software License Agreement
+ * (SLA) with Amlogic Inc ("Amlogic"). This software may be used
+ * only in accordance with the terms of this agreement.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification is strictly prohibited without prior written permission from
+ * Amlogic.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER 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, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "FreeRTOS.h"
+#include <gpio.h>
+#include <leds_plat.h>
+#include <leds_state.h>
+
+/* TODO: Temporarily use static variables instead of stick mem */
+static int32_t LedStickMem0;
+//static int32_t LedStickMem1;
+
+static LedCoord_t BreathInflections0[] = {
+	{0, 0},
+	{2500, 255},
+	{5000, 0}
+};
+
+static LedCoord_t BreathInflections1[] = {
+	{0, 0},
+	{5000, 255},
+	{10000, 0}
+};
+
+static LedCoord_t BreathInflections2[] = {
+	{0, 0},
+	{10000, 255},
+	{20000, 0}
+};
+
+static LedCoord_t BreathInflections3[] = {
+	{0, 0},
+	{20000, 255},
+	{40000, 0}
+};
+
+LedCoord_t *BreathInflections[LED_BREATH_MAX_COUNT] = {
+	BreathInflections0,
+	BreathInflections1,
+	BreathInflections2,
+	BreathInflections3,
+};
+
+LedDevice_t MesonLeds[] = {
+	{
+		.id = LED_ID_0,
+		.type = LED_TYPE_PWM,
+		.name = "sys_led",
+		.hardware_id = LED_PWM_C,
+		.polarity = LED_POLARITY_POSITIVE,
+		.breathtime = 0,
+	},
+};
+
+int32_t get_led_breath_len(uint32_t breath_id)
+{
+	switch (breath_id) {
+		case 0:
+			return sizeof(BreathInflections0)/sizeof(LedCoord_t);
+		case 1:
+			return sizeof(BreathInflections1)/sizeof(LedCoord_t);
+		case 2:
+			return sizeof(BreathInflections2)/sizeof(LedCoord_t);
+		case 3:
+			return sizeof(BreathInflections3)/sizeof(LedCoord_t);
+	} /* end swith */
+
+	iprintf("%s: id: %ld leds state init!\n", DRIVER_NAME, breath_id);
+
+	return -pdFREERTOS_ERRNO_EINVAL;
+}
+
+int32_t vLedPlatInit(int32_t ** stickmem)
+{
+	/* TODO: Here is initialization stickmem, but not doing so now */
+	*stickmem = &LedStickMem0;
+
+	/* off by default */
+	return xLedsStateSetBrightness(LED_ID_0, LED_OFF);
+}
+
+int32_t vLedPinmuxInit(void)
+{
+	/* set pinmux */
+	return xPinmuxSet(GPIOD_7, PIN_FUNC2);
+}
+
diff --git a/bl30/src_ao/demos/amlogic/driver/leds/leds_t5w_plat.c b/bl30/src_ao/demos/amlogic/driver/leds/leds_t5w_plat.c
new file mode 100644
index 0000000..935a894
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/leds/leds_t5w_plat.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2014-2018 Amlogic, Inc. All rights reserved.
+ *
+ * All information contained herein is Amlogic confidential.
+ *
+ * This software is provided to you pursuant to Software License Agreement
+ * (SLA) with Amlogic Inc ("Amlogic"). This software may be used
+ * only in accordance with the terms of this agreement.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification is strictly prohibited without prior written permission from
+ * Amlogic.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER 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, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "FreeRTOS.h"
+#include <gpio.h>
+#include <leds_plat.h>
+#include <leds_state.h>
+
+/* TODO: Temporarily use static variables instead of stick mem */
+static int32_t LedStickMem0;
+//static int32_t LedStickMem1;
+
+static LedCoord_t BreathInflections0[] = {
+	{0, 0},
+	{2500, 255},
+	{5000, 0}
+};
+
+static LedCoord_t BreathInflections1[] = {
+	{0, 0},
+	{5000, 255},
+	{10000, 0}
+};
+
+static LedCoord_t BreathInflections2[] = {
+	{0, 0},
+	{10000, 255},
+	{20000, 0}
+};
+
+static LedCoord_t BreathInflections3[] = {
+	{0, 0},
+	{20000, 255},
+	{40000, 0}
+};
+
+LedCoord_t *BreathInflections[LED_BREATH_MAX_COUNT] = {
+	BreathInflections0,
+	BreathInflections1,
+	BreathInflections2,
+	BreathInflections3,
+};
+
+LedDevice_t MesonLeds[] = {
+	{
+		.id = LED_ID_0,
+		.type = LED_TYPE_PWM,
+		.name = "sys_led",
+		.hardware_id = LED_PWM_C,
+		.polarity = LED_POLARITY_POSITIVE,
+		.breathtime = 0,
+	},
+};
+
+int32_t get_led_breath_len(uint32_t breath_id)
+{
+	switch (breath_id) {
+		case 0:
+			return sizeof(BreathInflections0)/sizeof(LedCoord_t);
+		case 1:
+			return sizeof(BreathInflections1)/sizeof(LedCoord_t);
+		case 2:
+			return sizeof(BreathInflections2)/sizeof(LedCoord_t);
+		case 3:
+			return sizeof(BreathInflections3)/sizeof(LedCoord_t);
+	} /* end swith */
+
+	iprintf("%s: id: %ld leds state init!\n", DRIVER_NAME, breath_id);
+
+	return -pdFREERTOS_ERRNO_EINVAL;
+}
+
+int32_t vLedPlatInit(int32_t ** stickmem)
+{
+	/* TODO: Here is initialization stickmem, but not doing so now */
+	*stickmem = &LedStickMem0;
+
+	/* off by default */
+	return xLedsStateSetBrightness(LED_ID_0, LED_OFF);
+}
+
+int32_t vLedPinmuxInit(void)
+{
+	/* set pinmux */
+	return xPinmuxSet(GPIOD_7, PIN_FUNC2);
+}
+
diff --git a/bl30/src_ao/demos/amlogic/driver/leds/leds_t7_plat.c b/bl30/src_ao/demos/amlogic/driver/leds/leds_t7_plat.c
new file mode 100644
index 0000000..faf3af9
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/leds/leds_t7_plat.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2014-2018 Amlogic, Inc. All rights reserved.
+ *
+ * All information contained herein is Amlogic confidential.
+ *
+ * This software is provided to you pursuant to Software License Agreement
+ * (SLA) with Amlogic Inc ("Amlogic"). This software may be used
+ * only in accordance with the terms of this agreement.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification is strictly prohibited without prior written permission from
+ * Amlogic.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER 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, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "FreeRTOS.h"
+#include <gpio.h>
+#include <leds_plat.h>
+#include <leds_state.h>
+
+/* TODO: Temporarily use static variables instead of stick mem */
+static int32_t LedStickMem0;
+//static int32_t LedStickMem1;
+
+static LedCoord_t BreathInflections0[] = {
+	{0, 0},
+	{2500, 255},
+	{5000, 0}
+};
+
+static LedCoord_t BreathInflections1[] = {
+	{0, 0},
+	{5000, 255},
+	{10000, 0}
+};
+
+static LedCoord_t BreathInflections2[] = {
+	{0, 0},
+	{10000, 255},
+	{20000, 0}
+};
+
+static LedCoord_t BreathInflections3[] = {
+	{0, 0},
+	{20000, 255},
+	{40000, 0}
+};
+
+LedCoord_t *BreathInflections[LED_BREATH_MAX_COUNT] = {
+	BreathInflections0,
+	BreathInflections1,
+	BreathInflections2,
+	BreathInflections3,
+};
+
+LedDevice_t MesonLeds[] = {
+	{
+		.id = LED_ID_0,
+		.type = LED_TYPE_PWM,
+		.name = "sys_led",
+		.hardware_id = LED_PWMAO_G,
+		.polarity = LED_POLARITY_POSITIVE,
+		.breathtime = 0,
+	},
+};
+
+int32_t get_led_breath_len(uint32_t breath_id)
+{
+	switch (breath_id) {
+		case 0:
+			return sizeof(BreathInflections0)/sizeof(LedCoord_t);
+		case 1:
+			return sizeof(BreathInflections1)/sizeof(LedCoord_t);
+		case 2:
+			return sizeof(BreathInflections2)/sizeof(LedCoord_t);
+		case 3:
+			return sizeof(BreathInflections3)/sizeof(LedCoord_t);
+	} /* end swith */
+
+	iprintf("%s: id: %ld leds state init!\n", DRIVER_NAME, breath_id);
+
+	return -pdFREERTOS_ERRNO_EINVAL;
+}
+
+int32_t vLedPlatInit(int32_t ** stickmem)
+{
+	/* TODO: Here is initialization stickmem, but not doing so now */
+	*stickmem = &LedStickMem0;
+
+	/* off by default */
+	return xLedsStateSetBrightness(LED_ID_0, LED_OFF);
+}
+
+int32_t vLedPinmuxInit(void)
+{
+	/* set pinmux */
+	return xPinmuxSet(GPIOD_7, PIN_FUNC2);
+}
+
+
diff --git a/bl30/src_ao/demos/amlogic/driver/mailbox/build.mk b/bl30/src_ao/demos/amlogic/driver/mailbox/build.mk
new file mode 100644
index 0000000..c31e672
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/mailbox/build.mk
@@ -0,0 +1,57 @@
+#
+#  Copyright (C) 2014-2018 Amlogic, Inc. All rights reserved.
+#
+#  All information contained herein is Amlogic confidential.
+#
+#  This software is provided to you pursuant to Software License Agreement
+#  (SLA) with Amlogic Inc ("Amlogic"). This software may be used
+#  only in accordance with the terms of this agreement.
+#
+#  Redistribution and use in source and binary forms, with or without
+#  modification is strictly prohibited without prior written permission from
+#  Amlogic.
+#
+#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#  OWNER 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, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+ifeq ("$(SOC)","t3")
+MAILBOX=y
+endif
+ifeq ("$(SOC)","p1")
+MAILBOX=y
+endif
+ifeq ("$(SOC)","t7")
+MAILBOX=y
+endif
+ifeq ("$(SOC)","s4")
+MAILBOX=y
+endif
+ifeq ("$(SOC)","a5")
+MAILBOX=y
+endif
+ifeq ("$(SOC)","sc2")
+MAILBOX=y
+endif
+ifeq ("$(SOC)","t5")
+MAILBOX_PL=y
+endif
+ifeq ("$(SOC)","t5d")
+MAILBOX_PL=y
+endif
+
+ifeq ("$(SOC)","t5w")
+MAILBOX_PL=y
+endif
+
+mailbox-$(MAILBOX) = mailbox.o mailbox-irq.o mailbox-htbl.o rpc-user.o
+mailbox-$(MAILBOX_PL) = mailbox-pl.o mailbox-htbl.o rpc-user.o
diff --git a/bl30/src_ao/demos/amlogic/driver/mailbox/mailbox-htbl.c b/bl30/src_ao/demos/amlogic/driver/mailbox/mailbox-htbl.c
new file mode 100644
index 0000000..72bfe40
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/mailbox/mailbox-htbl.c
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2014-2018 Amlogic, Inc. All rights reserved.
+ *
+ * All information contained herein is Amlogic confidential.
+ *
+ * This software is provided to you pursuant to Software License Agreement
+ * (SLA) with Amlogic Inc ("Amlogic"). This software may be used
+ * only in accordance with the terms of this agreement.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification is strictly prohibited without prior written permission from
+ * Amlogic.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER 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, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * hanlder table module (H-TBL)
+ * - register handler with cmd id
+ * - invoke handler with cmd id
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "FreeRTOS.h"
+#include "myprintf.h"
+
+#include "mailbox-htbl.h"
+
+#define PRINT(...)	//printf(__VA_ARGS__)
+#define PRINT_ERR(...)	printf(__VA_ARGS__)
+
+#define malloc pvPortMalloc
+#define free vPortFree
+
+struct entry {
+	uint32_t cmd;
+	void *(*handler)(void *);
+	uint8_t needFdBak;
+	uint32_t tabLen;
+};
+
+static inline void *mbmemset(void *dst, int val, size_t count)
+{
+	char *ptr = dst;
+
+	while (count--)
+		*ptr++ = val;
+
+	return dst;
+}
+
+static inline void *mbmemcpy(void *dst, const void *src, size_t len)
+{
+	const char *s = src;
+	char *d = dst;
+
+	while (len--)
+		*d++ = *s++;
+
+	return dst;
+}
+
+void mailbox_htbl_init(void **pHTbl)
+{
+	size_t size = sizeof(struct entry) * MAX_ENTRY_NUM;
+	struct entry *p = NULL;
+
+	p = malloc(size);
+	if (p == NULL)
+		return;
+	mbmemset(p, 0x00, size);
+	*pHTbl = p;
+	p[0].tabLen = MAX_ENTRY_NUM;
+}
+
+void mailbox_htbl_init_size(void **pHTbl, uint32_t tabLen)
+{
+	size_t size = sizeof(struct entry) * tabLen;
+	struct entry *p = NULL;
+
+	if (tabLen == 0) {
+		PRINT_ERR("tabLen == 0\n");
+		return;
+	}
+	p = malloc(size);
+	if (p == NULL)
+		return;
+	mbmemset(p, 0x00, size);
+	*pHTbl = p;
+	p[0].tabLen = tabLen;
+}
+
+uint32_t mailbox_htbl_reg(void *pHTbl, uint32_t cmd, void *(handler) (void *))
+{
+	struct entry *p = pHTbl;
+	uint32_t i;
+	uint32_t tabLen = p[0].tabLen;
+
+	for (i = 0; i != tabLen; i++) {
+		if (p[i].cmd == cmd && p[i].handler != NULL) {
+			PRINT_ERR("FATAL ERROR: reg repeat cmd=%lx handler=%p\n", cmd, handler);
+			for (;;);
+		}
+		if (p[i].handler == NULL) {
+			p[i].cmd = cmd;
+			p[i].handler = handler;
+			p[i].needFdBak = 0;
+			PRINT_ERR("AOCPU reg cmd=%lx handler=%p\n", cmd, handler);
+			return i;
+		}
+	}
+	return tabLen;
+}
+
+uint32_t mailbox_htbl_reg_feedback(void *pHTbl, uint32_t cmd,
+				   void *(*handler) (void *), uint8_t needFdBak)
+{
+	struct entry *p = pHTbl;
+	uint32_t i;
+	uint32_t tabLen = p[0].tabLen;
+
+	for (i = 0; i != tabLen; i++) {
+		if (p[i].cmd == cmd && p[i].handler != NULL) {
+			PRINT_ERR("FATAL ERROR: reg repeat cmd=%lx handler=%p\n", cmd,
+				  handler);
+			for (;;);
+		}
+		if (p[i].handler == NULL) {
+			p[i].cmd = cmd;
+			p[i].handler = handler;
+			p[i].needFdBak = needFdBak;
+			PRINT_ERR("reg idx=%ld cmd=%lx handler=%p\n", i, cmd, handler);
+			return i;
+		}
+	}
+	return tabLen;
+}
+
+uint32_t mailbox_htbl_unreg(void *pHTbl, uint32_t cmd)
+{
+	struct entry *p = pHTbl;
+	uint32_t i;
+	uint32_t tabLen = p[0].tabLen;
+
+	for (i = 0; i != tabLen; i++) {
+		if (p[i].cmd == cmd) {
+			PRINT("unreg cmd=%lx handler=%p\n", cmd, p[i].handler);
+			p[i].cmd = 0;
+			p[i].handler = NULL;
+			p[i].needFdBak = 0;
+			return i;
+		}
+	}
+	return MAX_ENTRY_NUM;
+}
+
+uint32_t mailbox_htbl_invokeCmd(void *pHTbl, uint32_t cmd, void *arg)
+{
+	PRINT("AOCPU search in cmd handler table pHTbl=%p cmd=%lx arg=%p\n", pHTbl,
+	      cmd, arg);
+	struct entry *p = pHTbl;
+	uint32_t i;
+	uint32_t tabLen = p[0].tabLen;
+
+	for (i = 0; i != tabLen; i++) {
+		PRINT("AOCPU input_cmd=%x i=%ld cmd=%lx\n", cmd, i, p[i].cmd);
+		if (p[i].cmd == cmd) {
+			PRINT("AOCPU idx=%ld cmd=%lx handler=%p arg=%p\n", i,
+			      p[i].cmd, p[i].handler, arg);
+			if (p[i].handler == NULL) {
+				return tabLen;
+			}
+			p[i].handler(arg);
+			return p[i].needFdBak;
+		}
+	}
+	PRINT_ERR("AOCPU unknown cmd=%lx\n", cmd);
+	return tabLen;
+}
diff --git a/bl30/src_ao/demos/amlogic/driver/mailbox/mailbox-htbl.h b/bl30/src_ao/demos/amlogic/driver/mailbox/mailbox-htbl.h
new file mode 100644
index 0000000..6c95995
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/mailbox/mailbox-htbl.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2014-2018 Amlogic, Inc. All rights reserved.
+ *
+ * All information contained herein is Amlogic confidential.
+ *
+ * This software is provided to you pursuant to Software License Agreement
+ * (SLA) with Amlogic Inc ("Amlogic"). This software may be used
+ * only in accordance with the terms of this agreement.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification is strictly prohibited without prior written permission from
+ * Amlogic.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER 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, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * handler table for mailbox
+ *
+ * Author: Yang Liu <yang.liu@amlogic.com>
+ * Version:
+ * - 0.1        init
+ */
+
+#ifndef _MAILBOX_HTBL_H_
+#define _MAILBOX_HTBL_H_
+
+#include <stdint.h>
+#include "mailbox-api.h"
+
+/** handler table
+ * 0, mailbox init one htbl
+ * 1, user could register it's handler on specific cmd to htbl
+ * 2, mailbox invoke handler when specific cmd come from peer core
+ *
+ * For now, ARM and DSP have only one htbl at each side.
+ */
+void mailbox_htbl_init(void **pHTbl);
+void mailbox_htbl_init_size(void **pHTbl, uint32_t tabLen);
+uint32_t mailbox_htbl_reg(void *pHTbl, uint32_t cmd, void *(handler)(void *));
+uint32_t mailbox_htbl_reg_feedback(void *pHTbl, uint32_t cmd,
+                              void *(*handler)(void *), uint8_t needFdBak);
+uint32_t mailbox_htbl_unreg(void *pHTbl, uint32_t cmd);
+uint32_t mailbox_htbl_invokeCmd(void *pHTbl, uint32_t cmd, void *arg);
+
+/** dispatch mailbox msg from ISR to job task with this struct
+ * sample user case:
+ * In ISR:
+ * 1, get msg(cmd and data) from mailbox, create event
+ * 2, push event to Q in ISR
+ * 3, notify the job task in ISR
+ * In job task:
+ * 1, wait until be notified from ISR
+ * 2, recieve event from Q
+ * 3, registered handler process the event
+ * 4, waiting for next event
+ */
+// ARM side don't support malloc in ISR,
+// so change to fixed payload style
+// defect:
+// - fixed payload length
+// - it have to copy to Q when pushing, copy from Q when poping
+#define PAYLOAD_LEN         24
+struct event {
+    uint32_t cmd;
+    uint8_t arg[PAYLOAD_LEN];
+};
+#endif
diff --git a/bl30/src_ao/demos/amlogic/driver/mailbox/mailbox-in.h b/bl30/src_ao/demos/amlogic/driver/mailbox/mailbox-in.h
new file mode 100644
index 0000000..702d288
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/mailbox/mailbox-in.h
@@ -0,0 +1,268 @@
+#ifndef __MAIL_IN_H__
+#define __MAIL_IN_H__
+
+#include "myprintf.h"
+#include "mailbox.h"
+#include "mailbox-api.h"
+
+#define UNUSED(x)           (void)(x)
+
+#define ACK_OK				1
+#define ACK_FAIL			2
+#define MHU_MB_STK_SIZE		2048
+#define QUEUE_LENGTH		20
+#define	TASK_POOL_SIZE		3
+
+#define MAILBOX_BUFFER_SIZE             MHU_MAX_SIZE
+#define MAILBOX_CMD_MAX                 0xFFFF
+
+#define PRINT_DBG(...)			//printf(__VA_ARGS__)
+#define aml_writel32(val, reg)		(REG32(reg) = val)
+#define aml_readl32(reg)		(REG32(reg))
+
+#ifndef MAILBOX_DSPA2AO
+#define MAILBOX_DSPA2AO 0xc
+#endif
+#ifndef MAILBOX_AO2DSPA
+#define MAILBOX_AO2DSPA 0xd
+#endif
+
+enum sync_type {
+	MB_ASYNC = 1,
+	MB_SYNC,
+};
+
+typedef struct {
+	uint32_t cmd:16;
+	uint32_t size:9;
+	uint32_t sync:7;
+} MbStat_t;
+
+typedef union {
+	MbStat_t st;
+	uint32_t reg;
+} MbStat_in_t;
+
+typedef struct __attribute__((__packed__)) {
+	uint32_t status;
+	uint64_t taskid;
+	uint64_t complete;
+	uint64_t ullclt;
+}mbHeadInfo;
+
+typedef struct __attribute__((__packed__)) {
+	uint32_t status;
+	uint64_t taskid;
+	uint64_t complete;
+	uint64_t ullclt;
+	uint8_t data[MHU_DATA_SIZE];
+}mboxData;
+
+typedef struct __attribute__((__packed__)) {
+	mboxData mbdata;	// hack to pass more data
+	uint32_t ulCmd;
+	uint32_t ulSize;
+	uint32_t ulChan;
+}mbPackInfo;
+
+
+#define VALID_CMD_SIZE(cmd, size) \
+    configASSERT(cmd <= MAILBOX_CMD_MAX && size <= MAILBOX_BUFFER_SIZE)
+
+#define VALID_CHANNEL(chan) \
+    configASSERT(chan == AOREE_CHANNEL || chan == AOTEE_CHANNEL || chan == AODSPA_CHANNEL)
+
+#define VALID_BUFFER_SIZE(size) \
+    configASSERT(size <= MAILBOX_BUFFER_SIZE)
+
+
+static inline MbStat_t xGetMboxStats(uint32_t reg)
+{
+	MbStat_in_t stat;
+
+	stat.reg = aml_readl32(reg);
+	return stat.st;
+}
+
+static inline void vSetMboxStats(uint32_t reg, MbStat_t st)
+{
+	MbStat_in_t stat;
+
+	stat.st = st;
+	aml_writel32(stat.reg, reg);
+}
+
+static inline void vClrMboxStats(uint32_t reg)
+{
+	aml_writel32(0xFFFFFFFF, reg);
+}
+
+static inline uint32_t xGetChan(uint32_t mbox)
+{
+	switch (mbox) {
+	case MAILBOX_ARMREE2AO:
+		return AOREE_CHANNEL;
+	case MAILBOX_ARMTEE2AO:
+		return AOTEE_CHANNEL;
+	case MAILBOX_DSPA2AO:
+		return AODSPA_CHANNEL;
+	default:
+		configASSERT(0);
+	}
+}
+
+static inline uint32_t xGetRevMbox(uint32_t ulChan)
+{
+	switch (ulChan) {
+	case AOREE_CHANNEL:
+		return MAILBOX_ARMREE2AO;
+	case AOTEE_CHANNEL:
+		return MAILBOX_ARMTEE2AO;
+	case AODSPA_CHANNEL:
+		return MAILBOX_DSPA2AO;
+	default:
+		configASSERT(0);
+	}
+}
+
+static inline uint32_t xGetSendMbox(uint32_t ulChan)
+{
+	switch (ulChan) {
+	case AODSPA_CHANNEL:
+		return MAILBOX_AO2DSPA;
+	case AOREE_CHANNEL:
+	case AOTEE_CHANNEL:
+	default:
+		configASSERT(0);
+	}
+	return 0;
+}
+
+static inline uint32_t xDspRevAddr(uint32_t ulChan)
+{
+	switch (ulChan) {
+	case AOREE_CHANNEL:
+	case AOTEE_CHANNEL:
+	case AODSPA_CHANNEL:
+		return PAYLOAD_RD_BASE(xGetRevMbox(ulChan));
+	default:
+		configASSERT(0);
+	}
+}
+
+static inline uint32_t xSendAddr(uint32_t ulChan)
+{
+	switch (ulChan) {
+	case AOREE_CHANNEL:
+	case AOTEE_CHANNEL:
+	case AODSPA_CHANNEL:
+		return PAYLOAD_WR_BASE(xGetSendMbox(ulChan));
+	default:
+		configASSERT(0);
+	}
+}
+/*send back for sync api*/
+static inline uint32_t xSendAddrBack(uint32_t ulChan)
+{
+	switch (ulChan) {
+	case AOREE_CHANNEL:
+	case AOTEE_CHANNEL:
+	case AODSPA_CHANNEL:
+		return PAYLOAD_RD_BASE(xGetSendMbox(ulChan));
+	default:
+		configASSERT(0);
+	}
+}
+
+
+static inline uint32_t xRevAddrMbox(uint32_t mbox)
+{
+	return PAYLOAD_RD_BASE(mbox);
+}
+
+static inline uint32_t xSendAddrMbox(uint32_t mbox)
+{
+	return PAYLOAD_WR_BASE(mbox);
+}
+
+static inline void MbWrite(uint32_t to, void *from, long count)
+{
+        int i = 0;
+	int len = count / 4 + ((count % 4) ? 1 : 0);
+	uint32_t *p = from;
+
+        PRINT_DBG("vMbWrite Count: 0x%x, len: 0x%x\n", count, len);
+        while (len > 0) {
+		aml_writel32(p[i], to + (4 * i));
+                PRINT_DBG("vMbwrite reg: 0x%x\n",  REG32(to + 4 * i + 0x800));
+                len--;
+                i++;
+        }
+}
+
+static inline void MbRead(void *to, uint32_t from, long count)
+{
+	int i = 0;
+	int len = count / 4 + ((count % 4) ? 1 : 0);
+	uint32_t *p = to;
+
+	PRINT_DBG("vMbRead Count:0x%x, len: 0x%x\n", count, len);
+	while (len > 0) {
+		p[i] = aml_readl32(from + (4 * i));
+		PRINT_DBG("vMbread p: 0x%x\n",  p[i]);
+		len--;
+		i++;
+	}
+}
+
+static inline void xGetPayloadHead(uint32_t addr, void *head)
+{
+	mbHeadInfo *phead = head;
+
+	MbRead(&phead->status, addr, 0x4);
+	MbRead(&phead->taskid, addr + 0x4, 0x8);
+	MbRead(&phead->complete, addr + 0xc, 0x8);
+	MbRead(&phead->ullclt, addr + 0x14, 0x8);
+}
+static inline void xBuildPayloadHead(uint32_t addr, void *head)
+{
+	mbHeadInfo *phead = head;
+
+	MbWrite(addr, &phead->status,  0x4);
+	MbWrite(addr + 0x4, &phead->taskid, 0x8);
+	MbWrite(addr + 0xc, &phead->complete, 0x8);
+	MbWrite(addr + 0x14, &phead->ullclt, 0x8);
+}
+
+static inline void vGetPayload(uint32_t addr, void *data, size_t size)
+{
+	VALID_BUFFER_SIZE(size);
+
+	PRINT_DBG("get payload: addr:0x%x\n", addr);
+	if (data != NULL) {
+		MbRead(data, addr, size);
+	}
+
+}
+
+static inline void vBuildPayload(uint32_t addr, void *data, size_t size)
+{
+	VALID_BUFFER_SIZE(size);
+
+	PRINT_DBG("vBuildPayload: addr:0x%x\n", addr);
+	if (data != NULL) {
+		MbWrite(addr, data, size);
+	}
+}
+
+static inline void vReBuildPayload(uint32_t addr, void *data, size_t size)
+{
+	VALID_BUFFER_SIZE(size);
+
+	PRINT_DBG("vBuildPayload: addr:0x%x\n", addr);
+	if (data != NULL) {
+		MbWrite(addr, 0, MAILBOX_BUFFER_SIZE);
+		MbWrite(addr, data, size);
+	}
+}
+#endif
diff --git a/bl30/src_ao/demos/amlogic/driver/mailbox/mailbox-irq.c b/bl30/src_ao/demos/amlogic/driver/mailbox/mailbox-irq.c
new file mode 100644
index 0000000..de7a179
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/mailbox/mailbox-irq.c
@@ -0,0 +1,95 @@
+#include <stdlib.h>
+#include <stdint.h>
+#include "myprintf.h"
+
+#include "mailbox-irq.h"
+#include "mailbox.h"
+
+#define AOTAG "AOCPU"
+#define PRINT_DBG(...)	//printf(__VA_ARGS__)
+#define PRINT_ERR(...)	printf(__VA_ARGS__)
+#define NO_DISABLE_IRQ	1
+
+#define aml_writel32(val, reg)		(REG32(reg) = val)
+#define aml_readl32(reg)		(REG32(reg))
+
+xHandlerTableEntry xMbHandlerTable[IRQ_MAX];
+
+void vMbDefaultHandler(void *vArg)
+{
+	vArg = vArg;
+	return;
+}
+
+void vSetMbIrqHandler(unsigned int xNum, vHandlerFunc vHandler, void *vArg,
+		    unsigned int xPriority)
+{
+	PRINT_DBG("vSetMbIrqHandler xNum:%d\n", xNum);
+	if (vHandler == NULL) {
+		xMbHandlerTable[xNum].vHandler = &vMbDefaultHandler;
+		xMbHandlerTable[xNum].vArg = NULL;
+	} else {
+		xMbHandlerTable[xNum].vHandler = vHandler;
+		xMbHandlerTable[xNum].vArg = vArg;
+	}
+	xMbHandlerTable[xNum].xPriority = xPriority;
+}
+
+void vMbSetIrqPriority(unsigned int xNum, unsigned int xPriority)
+{
+	xMbHandlerTable[xNum].xPriority = xPriority;
+}
+
+void vEnableMbInterrupt(unsigned int xMask)
+{
+#ifndef NO_DISABLE_IRQ
+	unsigned int val = 0;
+
+	val = aml_readl32(MAILBOX_IRQ_MASK) | xMask;
+	aml_writel32(val, MAILBOX_IRQ_MASK);
+#else
+	xMask = xMask;
+#endif
+}
+
+void vDisableMbInterrupt(unsigned int xMask)
+{
+#ifndef NO_DISABLE_IRQ
+	unsigned int val = 0;
+
+	val = aml_readl32(MAILBOX_IRQ_MASK) & (~xMask);
+	aml_writel32(val, MAILBOX_IRQ_MASK);
+#else
+	xMask = xMask;
+#endif
+}
+
+void vClrMbInterrupt(uint64_t xMask)
+{
+#ifdef IRQ_MORE
+        uint32_t lval = 0, hval = 0;
+
+        lval = xMask & 0xffffffff;
+        hval = (xMask >> 32) & 0xffffffff;
+        aml_writel32(lval, MAILBOX_IRQ_CLR);
+        aml_writel32(hval, MAILBOX_IRQ_CLR1);
+#else
+        aml_writel32(xMask, MAILBOX_IRQ_CLR);
+#endif
+}
+
+uint64_t xGetMbIrqStats(void)
+{
+#ifdef IRQ_MORE
+        uint64_t val = 0;
+        uint32_t lval = 0, hval = 0;
+
+        lval = aml_readl32(MAILBOX_IRQ_STS);
+        hval = aml_readl32(MAILBOX_IRQ_STS1);
+        val = hval;
+        val = ((val & 0xffffffff) << 32) | lval;
+        return val;
+#else
+        return aml_readl32(MAILBOX_IRQ_STS);
+#endif
+}
diff --git a/bl30/src_ao/demos/amlogic/driver/mailbox/mailbox-irq.h b/bl30/src_ao/demos/amlogic/driver/mailbox/mailbox-irq.h
new file mode 100644
index 0000000..f463341
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/mailbox/mailbox-irq.h
@@ -0,0 +1,13 @@
+#ifndef _MAILBOX_IRQ_H_
+#define _MAILBOX_IRQ_H_
+#include "mailbox.h"
+
+void vMbDefaultHandler(void *vArg);
+void vSetMbIrqHandler(unsigned int xNum, vHandlerFunc vHandler, void *vArg, unsigned int xPriority);
+void vMbSetIrqPriority(unsigned int xNum, unsigned int xPriority);
+void vEnableMbInterrupt(unsigned int xMask);
+void vDisableMbInterrupt(unsigned int xMask);
+void vClrMbInterrupt(uint64_t xMask);
+uint64_t xGetMbIrqStats(void);
+#endif
+
diff --git a/bl30/src_ao/demos/amlogic/driver/mailbox/mailbox-pl-in.h b/bl30/src_ao/demos/amlogic/driver/mailbox/mailbox-pl-in.h
new file mode 100644
index 0000000..2dd1c31
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/mailbox/mailbox-pl-in.h
@@ -0,0 +1,224 @@
+#ifndef __MAIL_IN_H__
+#define __MAIL_IN_H__
+
+#include "mailbox.h"
+#include "mailbox-api.h"
+
+#define UNUSED(x)           (void)(x)
+
+#define ACK_OK				1
+#define ACK_FAIL			2
+#define QUEUE_LENGTH		20
+#define	TASK_POOL_SIZE		3
+#if( configMAX_PRIORITIES < 2 )
+	#error configMAX_PRIORITIES should no less than 3
+#endif
+#define MHU_MB_TASK_PRIORITIES	configMAX_PRIORITIES - 2
+
+#define MAILBOX_BUFFER_SIZE             MHU_MAX_SIZE
+#define MAILBOX_CMD_MAX                 0xFFFF
+
+#define PRINT_DBG(...)			//printf(__VA_ARGS__)
+#define aml_writel32(val, reg)		(REG32(reg) = val)
+#define aml_readl32(reg)		(REG32(reg))
+
+enum sync_type {
+	MB_ASYNC = 1,
+	MB_SYNC,
+};
+
+typedef struct {
+	uint32_t cmd:16;
+	uint32_t size:9;
+	uint32_t sync:7;
+} MbStat_t;
+
+typedef union {
+	MbStat_t st;
+	uint32_t reg;
+} MbStat_in_t;
+
+typedef struct __attribute__((__packed__)) {
+	uint32_t status;
+	uint64_t taskid;
+	uint64_t complete;
+	uint64_t ullclt;
+}mbHeadInfo;
+
+typedef struct __attribute__((__packed__)) {
+	uint32_t status;
+	uint64_t taskid;
+	uint64_t complete;
+	uint64_t ullclt;
+	uint8_t data[MHU_DATA_SIZE];
+}mboxData;
+
+typedef struct __attribute__((__packed__)) {
+	mboxData mbdata;	// hack to pass more data
+	uint32_t ulCmd;
+	uint32_t ulSize;
+	uint32_t ulChan;
+}mbPackInfo;
+
+#define VALID_CMD_SIZE(cmd, size) \
+    configASSERT(cmd <= MAILBOX_CMD_MAX && size <= MAILBOX_BUFFER_SIZE)
+
+#define VALID_CHANNEL(chan) \
+    configASSERT(chan == AOREE_CHANNEL || chan == AOTEE_CHANNEL)
+
+#define VALID_BUFFER_SIZE(size) \
+    configASSERT(size <= MAILBOX_BUFFER_SIZE)
+
+
+static inline MbStat_t xGetMboxStats(uint32_t reg)
+{
+	MbStat_in_t stat;
+
+	stat.reg = aml_readl32(reg);
+	return stat.st;
+}
+
+static inline void vSetMboxStats(uint32_t reg, MbStat_t st)
+{
+	MbStat_in_t stat;
+
+	stat.st = st;
+	aml_writel32(stat.reg, reg);
+}
+
+static inline void vClrMboxStats(uint32_t reg)
+{
+	aml_writel32(0xFFFFFFFF, reg);
+}
+
+static inline uint32_t xGetChan(uint32_t mbox)
+{
+	switch (mbox) {
+	case MAILBOX_ARMREE2AO:
+		return AOREE_CHANNEL;
+	case MAILBOX_ARMTEE2AO:
+		return AOTEE_CHANNEL;
+	default:
+		configASSERT(0);
+	}
+	return 0;
+}
+
+static inline uint32_t xGetRevMbox(uint32_t ulChan)
+{
+	switch (ulChan) {
+	case AOREE_CHANNEL:
+		return MAILBOX_ARMREE2AO;
+	case AOTEE_CHANNEL:
+		return MAILBOX_ARMTEE2AO;
+	default:
+		configASSERT(0);
+	}
+	return 0;
+}
+
+static inline uint32_t xGetSendMbox(uint32_t ulChan)
+{
+	switch (ulChan) {
+	case AOREE_CHANNEL:
+		return 0;
+	case AOTEE_CHANNEL:
+		return 0;
+	default:
+		configASSERT(0);
+	}
+	return 0;
+}
+
+static inline uint32_t *xRevAddr(uint32_t ulChan)
+{
+	switch (ulChan) {
+	case AOREE_CHANNEL:
+		return (uint32_t *)MAILBOX_REE2AO;
+	case AOTEE_CHANNEL:
+		return (uint32_t *)MAILBOX_TEE2AO;
+	default:
+		configASSERT(0);
+	}
+	return NULL;
+}
+
+static inline uint32_t *xSendAddr(uint32_t ulChan)
+{
+	switch (ulChan) {
+	case AOREE_CHANNEL:
+		return (uint32_t *)MAILBOX_AO2REE;
+	case AOTEE_CHANNEL:
+		return (uint32_t *)MAILBOX_AO2TEE;
+	default:
+		configASSERT(0);
+	}
+	return NULL;
+}
+/*send back for sync api*/
+static inline uint32_t *xSendAddrBack(uint32_t ulChan)
+{
+	switch (ulChan) {
+	case AOREE_CHANNEL:
+		return (uint32_t *)MAILBOX_REE2AO;
+	case AOTEE_CHANNEL:
+		return (uint32_t *)MAILBOX_TEE2AO;
+	default:
+		configASSERT(0);
+	}
+	return NULL;
+}
+
+static inline void *mbmemset(void *dst, int val, size_t count)
+{
+	char *ptr = dst;
+
+	while (count--)
+		*ptr++ = val;
+
+	return dst;
+}
+
+static inline void *mbmemcpy(void *dst, const void *src, size_t len)
+{
+	const char *s = src;
+	char *d = dst;
+
+	while (len--)
+		*d++ = *s++;
+
+	return dst;
+}
+
+static inline void vGetPayload(void *addr, void *data, size_t size)
+{
+	VALID_BUFFER_SIZE(size);
+
+	PRINT_DBG("get payload: addr:0x%x, 0x%x\n", addr, size);
+	if (data != NULL) {
+		mbmemcpy(data, addr, size);
+	}
+
+}
+
+static inline void vBuildPayload(void *addr, void *data, size_t size)
+{
+	VALID_BUFFER_SIZE(size);
+
+	PRINT_DBG("vBuildPayload: addr:0x%x\n", addr);
+	if (data != NULL) {
+		mbmemcpy(addr, data, size);
+	}
+}
+
+static inline void vReBuildPayload(void *addr, void *data, size_t size)
+{
+	VALID_BUFFER_SIZE(size);
+
+	PRINT_DBG("vBuildPayload: addr:0x%x\n", addr);
+	if (data != NULL) {
+		mbmemset(addr, 0, MAILBOX_BUFFER_SIZE);
+		mbmemcpy(addr, data, size);
+	}
+}
+#endif
diff --git a/bl30/src_ao/demos/amlogic/driver/mailbox/mailbox-pl.c b/bl30/src_ao/demos/amlogic/driver/mailbox/mailbox-pl.c
new file mode 100644
index 0000000..78f53e2
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/mailbox/mailbox-pl.c
@@ -0,0 +1,337 @@
+
+/*
+ *  Copyright (C) 2014-2018 Amlogic, Inc. All rights reserved.
+ *
+ *  All information contained herein is Amlogic confidential.
+ *
+ */
+
+/*Mailbox driver*/
+#include <stdint.h>
+#include <stdlib.h>
+#include <util.h>
+#include "FreeRTOS.h"
+#include "task.h"
+#include "queue.h"
+#include "semphr.h"
+#include <stdio.h>
+#include <unistd.h>
+#include "n200_func.h"
+#include "uart.h"
+#include "common.h"
+#include "riscv_encoding.h"
+
+#include "mailbox.h"
+#include "mailbox-pl-in.h"
+#include "mailbox-htbl.h"
+#include "mailbox-api.h"
+
+#define MBTAG		"AOCPU"
+#define PRINT_DBG(...)	//printf(__VA_ARGS__)
+#define PRINT_ERR(...)	printf(__VA_ARGS__)
+#define PRINT(...)	printf(__VA_ARGS__)
+
+#define AO_MBOX_ONLY_SYNC	1
+
+void *g_tbl_ao;
+
+TaskHandle_t mbTeeHandler;
+TaskHandle_t mbReeHandler;
+static uint32_t ulTeeSyncTaskWake;
+static uint32_t ulReeSyncTaskWake;
+mbPackInfo syncTeeMbInfo;
+mbPackInfo syncReeMbInfo;
+
+extern void vRpcUserCmdInit(void);
+
+static void vEnterCritical(void)
+{
+        taskENTER_CRITICAL();
+}
+
+static void vExitCritical(void)
+{
+        taskEXIT_CRITICAL();
+}
+
+
+/*ARM 2 AOCPU mailbox*/
+static void vAoRevTeeMbHandler(uint32_t mailbox)
+{
+	//BaseType_t xYieldRequired = pdFALSE;
+	uint32_t mbox = mailbox;
+	mbPackInfo mbInfo;
+	MbStat_t st;
+	uint32_t *addr = NULL;
+	uint32_t ulMbCmd, ulSize, ulSync;
+
+	DisableIrq(MAILBOX_AOCPU_TEE_IRQ);
+	PRINT_DBG("[%s]: Teembox 0x%x\n", MBTAG, mbox);
+	st = xGetMboxStats(MAILBOX_STAT(mbox));
+	addr = xRevAddr(xGetChan(mbox));
+	ulMbCmd = st.cmd;
+	ulSize = st.size;
+	ulSync = st.sync;
+
+	PRINT_DBG("[%s]: %X, %X, %X, %X\n", MBTAG, mbox, ulMbCmd, ulSize, ulSync);
+
+	if (aml_readl32(MAILBOX_STAT(mbox)) == 0) {
+		PRINT_DBG("mbox cmd is 0, cannot match\n");
+		ClearPendingIrq(MAILBOX_AOCPU_TEE_IRQ);
+		EnableIrq(MAILBOX_AOCPU_TEE_IRQ);
+		return;
+	}
+
+	if (ulSize != 0)
+		vGetPayload(addr, &mbInfo.mbdata, ulSize);
+
+	PRINT_DBG("%s taskid: 0x%llx\n", MBTAG, mbInfo.mbdata.taskid);
+	PRINT_DBG("%s complete: 0x%llx\n", MBTAG, mbInfo.mbdata.complete);
+	PRINT_DBG("%s ullclt: 0x%llx\n", MBTAG, mbInfo.mbdata.ullclt);
+
+	switch (ulSync) {
+	case MB_SYNC:
+		if (ulTeeSyncTaskWake) {
+			PRINT("TeeSyncTaskWake Busy\n");
+			break;
+		}
+		PRINT_DBG("[%s]: SYNC\n", MBTAG);
+		ulTeeSyncTaskWake = 1;
+		mbInfo.ulCmd = ulMbCmd;
+		mbInfo.ulSize = ulSize;
+		mbInfo.ulChan = xGetChan(mbox);
+		mbmemcpy(&syncTeeMbInfo, &mbInfo, sizeof(syncTeeMbInfo));;
+		vTaskNotifyGiveFromISR(mbTeeHandler, NULL);
+		//portYIELD_FROM_ISR(xYieldRequired);
+		break;
+	case MB_ASYNC:
+#ifdef AO_MBOX_ONLY_SYNC
+		PRINT_DBG("[%s]: ASYNC no support\n", MBTAG);
+		vClrMboxStats(MAILBOX_CLR(mbox));
+		ClearPendingIrq(MAILBOX_AOCPU_REE_IRQ);
+		EnableIrq(MAILBOX_AOCPU_TEE_IRQ);
+#endif
+		break;
+	default:
+		PRINT_ERR("[%s]: Not SYNC or ASYNC, Fail\n", MBTAG);
+		vClrMboxStats(MAILBOX_CLR(mbox));
+		ClearPendingIrq(MAILBOX_AOCPU_TEE_IRQ);
+		EnableIrq(MAILBOX_AOCPU_TEE_IRQ);
+		break;
+	}
+}
+
+static void vTeeSyncTask(void *pvParameters)
+{
+	uint32_t *addr = NULL;
+	uint32_t mbox = 0;
+	int index = 0;
+
+	pvParameters = pvParameters;
+	while (1) {
+		ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
+		PRINT_DBG("[%s]:TeeSyncTask\n", MBTAG);
+
+		index = mailbox_htbl_invokeCmd(g_tbl_ao, syncTeeMbInfo.ulCmd,
+					       syncTeeMbInfo.mbdata.data);
+		mbox = xGetRevMbox(syncTeeMbInfo.ulChan);
+		addr = xSendAddrBack(syncTeeMbInfo.ulChan);
+		PRINT_DBG("[%s]:MbSyncTask mbox:%d\n", MBTAG, mbox);
+		if (index != 0) {
+			if (index == MAX_ENTRY_NUM) {
+				mbmemset(&syncTeeMbInfo.mbdata.data, 0, sizeof(syncTeeMbInfo.mbdata.data));
+				syncTeeMbInfo.mbdata.status = ACK_FAIL;
+				vReBuildPayload(addr, &syncTeeMbInfo.mbdata, sizeof(syncTeeMbInfo.mbdata));
+				PRINT_DBG("[%s]: undefine cmd or no callback\n", MBTAG);
+			} else {
+				PRINT_DBG("[%s]:MbSyncTask re len:%d\n", MBTAG, sizeof(syncTeeMbInfo.mbdata));
+				syncTeeMbInfo.mbdata.status = ACK_OK;
+				vReBuildPayload(addr, &syncTeeMbInfo.mbdata, sizeof(syncTeeMbInfo.mbdata));
+			}
+		}
+
+		vEnterCritical();
+		PRINT_DBG("[%s]:MbSync clear mbox:0x%lx\n", MBTAG, mbox);
+		ulTeeSyncTaskWake = 0;
+		vClrMboxStats(MAILBOX_CLR(mbox));
+		ClearPendingIrq(MAILBOX_AOCPU_TEE_IRQ);
+		EnableIrq(MAILBOX_AOCPU_TEE_IRQ);
+		vExitCritical();
+	}
+}
+
+
+
+static void vAoRevReeMbHandler(uint32_t mailbox)
+{
+	//BaseType_t xYieldRequired = pdFALSE;
+	uint32_t mbox = mailbox;
+	mbPackInfo mbInfo;
+	MbStat_t st;
+	uint32_t *addr = NULL;
+	uint32_t ulMbCmd, ulSize, ulSync;
+
+	DisableIrq(MAILBOX_AOCPU_REE_IRQ);
+	PRINT_DBG("[%s]: Reembox 0x%x\n", MBTAG, mbox);
+	st = xGetMboxStats(MAILBOX_STAT(mbox));
+	addr = xRevAddr(xGetChan(mbox));
+	ulMbCmd = st.cmd;
+	ulSize = st.size;
+	ulSync = st.sync;
+
+	PRINT_DBG("[%s]: %X, %X, %X, %X\n", MBTAG, ulMbCmd, ulSize, ulSync);
+
+	if (aml_readl32(MAILBOX_STAT(mbox)) == 0) {
+		PRINT_DBG("mbox cmd is 0, cannot match\n");
+		ClearPendingIrq(MAILBOX_AOCPU_REE_IRQ);
+		EnableIrq(MAILBOX_AOCPU_REE_IRQ);
+		return;
+	}
+
+	if (ulSize != 0)
+		vGetPayload(addr, &mbInfo.mbdata, ulSize);
+
+	PRINT_DBG("%s taskid: 0x%llx\n", MBTAG, mbInfo.mbdata.taskid);
+	PRINT_DBG("%s complete: 0x%llx\n", MBTAG, mbInfo.mbdata.complete);
+	PRINT_DBG("%s ullclt: 0x%llx\n", MBTAG, mbInfo.mbdata.ullclt);
+
+	switch (ulSync) {
+	case MB_SYNC:
+		if (ulReeSyncTaskWake) {
+			PRINT("ulReeSyncTaskWake Busy\n");
+			break;
+		}
+		PRINT_DBG("[%s]: SYNC\n", MBTAG);
+		ulReeSyncTaskWake = 1;
+		mbInfo.ulCmd = ulMbCmd;
+		mbInfo.ulSize = ulSize;
+		mbInfo.ulChan = xGetChan(mbox);
+		mbmemcpy(&syncReeMbInfo, &mbInfo, sizeof(syncReeMbInfo));;
+		vTaskNotifyGiveFromISR(mbReeHandler, NULL);
+		//portYIELD_FROM_ISR(xYieldRequired);
+		break;
+	case MB_ASYNC:
+#ifdef AO_MBOX_ONLY_SYNC
+		PRINT_ERR("[%s]: ASYNC no support\n", MBTAG);
+		vClrMboxStats(MAILBOX_CLR(mbox));
+		ClearPendingIrq(MAILBOX_AOCPU_REE_IRQ);
+		EnableIrq(MAILBOX_AOCPU_REE_IRQ);
+#endif
+		break;
+	default:
+		PRINT_ERR("[%s]: Not SYNC or ASYNC, Fail\n", MBTAG);
+		vClrMboxStats(MAILBOX_CLR(mbox));
+		ClearPendingIrq(MAILBOX_AOCPU_REE_IRQ);
+		EnableIrq(MAILBOX_AOCPU_REE_IRQ);
+		break;
+	}
+}
+
+static void vReeSyncTask(void *pvParameters)
+{
+	uint32_t *addr = NULL;
+	uint32_t mbox = 0;
+	int index = 0;
+
+	pvParameters = pvParameters;
+	while (1) {
+		ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
+		PRINT_DBG("[%s]:ReeSyncTask\n", MBTAG);
+
+		index = mailbox_htbl_invokeCmd(g_tbl_ao, syncReeMbInfo.ulCmd,
+					       syncReeMbInfo.mbdata.data);
+		mbox = xGetRevMbox(syncReeMbInfo.ulChan);
+		addr = xSendAddrBack(syncReeMbInfo.ulChan);
+		PRINT_DBG("[%s]:MbSyncTask mbox:%d\n", MBTAG, mbox);
+		if (index != 0) {
+			if (index == MAX_ENTRY_NUM) {
+				mbmemset(&syncReeMbInfo.mbdata.data, 0, sizeof(syncReeMbInfo.mbdata.data));
+				syncReeMbInfo.mbdata.status = ACK_FAIL;
+				vReBuildPayload(addr, &syncReeMbInfo.mbdata, sizeof(syncReeMbInfo.mbdata));
+				PRINT_DBG("[%s]: undefine cmd or no callback\n", MBTAG);
+			} else {
+				PRINT_DBG("[%s]:MbSyncTask re len:%d\n", MBTAG, sizeof(syncReeMbInfo.mbdata));
+				syncReeMbInfo.mbdata.status = ACK_OK;
+				vReBuildPayload(addr, &syncReeMbInfo.mbdata, sizeof(syncReeMbInfo.mbdata));
+			}
+		}
+
+		vEnterCritical();
+		PRINT_DBG("[%s]:MbSync clear mbox:0x%lx\n", MBTAG, mbox);
+		ulReeSyncTaskWake = 0;
+		vClrMboxStats(MAILBOX_CLR(mbox));
+		ClearPendingIrq(MAILBOX_AOCPU_REE_IRQ);
+		EnableIrq(MAILBOX_AOCPU_REE_IRQ);
+		vExitCritical();
+	}
+}
+
+
+static void vMbHandleReeIsr(void);
+static void vMbHandleReeIsr(void)
+{
+	vAoRevReeMbHandler(MAILBOX_ARMREE2AO);
+}
+
+static void vMbHandleTeeIsr(void);
+static void vMbHandleTeeIsr(void)
+{
+	vAoRevTeeMbHandler(MAILBOX_ARMTEE2AO);
+}
+
+void vMbInit(void)
+{
+	PRINT("[%s]: mailbox init start\n", MBTAG);
+
+	mailbox_htbl_init(&g_tbl_ao);
+
+	RegisterIrq(MAILBOX_AOCPU_REE_IRQ, 6, vMbHandleReeIsr);
+	RegisterIrq(MAILBOX_AOCPU_TEE_IRQ, 6, vMbHandleTeeIsr);
+
+	EnableIrq(MAILBOX_AOCPU_REE_IRQ);
+	EnableIrq(MAILBOX_AOCPU_TEE_IRQ);
+
+	xTaskCreate(vTeeSyncTask,
+		    "AoTeeSyncTask",
+		    configMINIMAL_STACK_SIZE,
+		    0,
+		    MHU_MB_TASK_PRIORITIES,
+		    (TaskHandle_t *)&mbTeeHandler);
+
+	xTaskCreate(vReeSyncTask,
+		    "AoReeSyncTask",
+		    configMINIMAL_STACK_SIZE,
+		    0,
+		    MHU_MB_TASK_PRIORITIES,
+		    (TaskHandle_t *)&mbReeHandler);
+
+	vRpcUserCmdInit();
+	PRINT("[%s]: mailbox -v1 init end\n", MBTAG);
+}
+
+BaseType_t xInstallRemoteMessageCallbackFeedBack(uint32_t ulChan, uint32_t cmd,
+						 void *(handler) (void *),
+						 uint8_t needFdBak)
+{
+	VALID_CHANNEL(ulChan);
+	UNUSED(ulChan);
+	return mailbox_htbl_reg_feedback(g_tbl_ao, cmd, handler, needFdBak);
+}
+
+BaseType_t xUninstallRemoteMessageCallback(uint32_t ulChan, int32_t cmd)
+{
+	UNUSED(ulChan);
+	return mailbox_htbl_unreg(g_tbl_ao, cmd);
+}
+
+BaseType_t xTransferMessageAsync(uint32_t ulChan, uint32_t ulCmd,
+				 void *data, size_t size)
+{
+
+	UNUSED(ulChan);
+	UNUSED(ulCmd);
+	UNUSED(data);
+	UNUSED(size);
+	PRINT("[%s]: mailbox pl not suppot transfer Async\n", MBTAG);
+	return 0;
+}
diff --git a/bl30/src_ao/demos/amlogic/driver/mailbox/mailbox.c b/bl30/src_ao/demos/amlogic/driver/mailbox/mailbox.c
new file mode 100644
index 0000000..a606cb0
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/mailbox/mailbox.c
@@ -0,0 +1,403 @@
+
+/*
+ *  Copyright (C) 2014-2018 Amlogic, Inc. All rights reserved.
+ *
+ *  All information contained herein is Amlogic confidential.
+ *
+ */
+
+/*Mailbox driver*/
+#include <stdint.h>
+#include <stdlib.h>
+#include <util.h>
+#include "FreeRTOS.h"
+#include "task.h"
+#include "queue.h"
+#include "semphr.h"
+#include <stdio.h>
+#include "myprintf.h"
+#include <unistd.h>
+#include "n200_eclic.h"
+#include "n200_func.h"
+#include "uart.h"
+#include "common.h"
+#include "riscv_encoding.h"
+
+#include "mailbox.h"
+#include "mailbox-irq.h"
+#include "mailbox-in.h"
+#include "mailbox-htbl.h"
+#include "mailbox-api.h"
+
+#define MBTAG "AOCPU"
+#define PRINT_DBG(...)  //printf(__VA_ARGS__)
+#define PRINT_ERR(...)  printf(__VA_ARGS__)
+#define PRINT(...)	printf(__VA_ARGS__)
+
+#define MHU_MB_STK_SIZE		2048
+#define MB_DATA_SHR_SIZE	240
+
+#undef TASK_PRIORITY
+#define TASK_PRIORITY		0x2
+
+#define AO_MBOX_ONLY_SYNC	1
+
+void *g_tbl_ao;
+
+TaskHandle_t ReembHandler;
+TaskHandle_t TeembHandler;
+TaskHandle_t DspmbHandler;
+static uint32_t ulReeSyncTaskWake;
+static uint32_t ulTeeSyncTaskWake;
+static uint32_t ulDspSyncTaskWake;
+mbPackInfo syncReeMbInfo;
+mbPackInfo syncTeeMbInfo;
+mbPackInfo syncDspMbInfo;
+
+extern xHandlerTableEntry xMbHandlerTable[IRQ_MAX];
+extern void vRpcUserCmdInit(void);
+
+static void vEnterCritical(void)
+{
+        taskENTER_CRITICAL();
+}
+
+static void vExitCritical(void)
+{
+        taskEXIT_CRITICAL();
+}
+
+static void vMbHandleIsr(void)
+{
+	uint64_t val = 0;
+	uint64_t ulIrqMask = IRQ_MASK;
+	int i = 0;
+	uint64_t ulIrqBitHandled = 0;
+
+	val = xGetMbIrqStats();
+	PRINT_DBG("[%s]: mb isr: 0x%llx\n", MBTAG, val);
+	val &= ulIrqMask;
+	while (val) {
+		for (i = 0; i < IRQ_MAX; i++) {
+			if (val & (1 << i)) {
+				if (xMbHandlerTable[i].vHandler != NULL) {
+					xMbHandlerTable[i].vHandler(xMbHandlerTable[i].vArg);
+				}
+			}
+		}
+		ulIrqBitHandled |= val;
+		val = xGetMbIrqStats();
+		val &= ulIrqMask;
+		val = val ^ (ulIrqBitHandled & val);
+		PRINT_DBG("[%s]: mb isr: 0x%llx\n", MBTAG, val);
+	}
+}
+//DECLARE_IRQ(IRQ_NUM_MB_4, vMbHandleIsr)
+
+/*Ree 2 AOCPU mailbox*/
+static void vAoRevMbHandler(void *vArg)
+{
+	//BaseType_t xYieldRequired = pdFALSE;
+	uint32_t mbox = (uint32_t)vArg;
+	mbPackInfo mbInfo;
+	MbStat_t st;
+	uint32_t addr, ulMbCmd, ulSize, ulSync;
+
+	vDisableMbInterrupt(IRQ_REV_BIT(mbox));
+	st = xGetMboxStats(MAILBOX_STAT(mbox));
+	addr = xRevAddrMbox(mbox);
+	ulMbCmd = st.cmd;
+	ulSize = st.size;
+	ulSync = st.sync;
+
+	PRINT_DBG("[%s]: prvRevMbHandler 0x%lx, 0x%lx, 0x%lx\n", MBTAG, ulMbCmd, ulSize, ulSync);
+
+	if (ulMbCmd == 0) {
+		PRINT_DBG("[%s] mbox cmd is 0, cannot match\n");
+		vClrMboxStats(MAILBOX_CLR(mbox));
+		vClrMbInterrupt(IRQ_REV_BIT(mbox));
+		vEnableMbInterrupt(IRQ_REV_BIT(mbox));
+		return;
+	}
+
+	if (ulSize != 0)
+		vGetPayload(addr, &mbInfo.mbdata, ulSize);
+
+	PRINT_DBG("%s taskid: 0x%llx\n", MBTAG, mbInfo.mbdata.taskid);
+	PRINT_DBG("%s complete: 0x%llx\n", MBTAG, mbInfo.mbdata.complete);
+	PRINT_DBG("%s ullclt: 0x%llx\n", MBTAG, mbInfo.mbdata.ullclt);
+
+	switch (ulSync) {
+	case MB_SYNC:
+		if (ulReeSyncTaskWake && (MAILBOX_ARMREE2AO == xGetChan(mbox))) {
+			PRINT("ulReeSyncTaskWake Busy\n");
+			break;
+		}
+		if (ulTeeSyncTaskWake && (MAILBOX_ARMTEE2AO == xGetChan(mbox))) {
+			PRINT("ulTeeSyncTaskWake Busy\n");
+			break;
+		}
+		if (ulDspSyncTaskWake && (MAILBOX_DSPA2AO == xGetChan(mbox))) {
+			PRINT("ulDspSyncTaskWake Busy\n");
+			break;
+		}
+		PRINT_DBG("[%s]: SYNC\n", MBTAG);
+		mbInfo.ulCmd = ulMbCmd;
+		mbInfo.ulSize = ulSize;
+		mbInfo.ulChan = xGetChan(mbox);
+		if (MAILBOX_ARMREE2AO == xGetChan(mbox)) {
+			syncReeMbInfo = mbInfo;
+			ulReeSyncTaskWake = 1;
+			vTaskNotifyGiveFromISR(ReembHandler, NULL);
+		}
+		if (MAILBOX_ARMTEE2AO == xGetChan(mbox)) {
+			syncTeeMbInfo = mbInfo;
+			ulTeeSyncTaskWake = 1;
+			vTaskNotifyGiveFromISR(TeembHandler, NULL);
+		}
+		if (MAILBOX_DSPA2AO == xGetChan(mbox)) {
+			syncDspMbInfo = mbInfo;
+			ulDspSyncTaskWake = 1;
+			vTaskNotifyGiveFromISR(DspmbHandler, NULL);
+		}
+		//portYIELD_FROM_ISR(xYieldRequired);
+		break;
+	case MB_ASYNC:
+#ifdef AO_MBOX_ONLY_SYNC
+		PRINT_DBG("[%s]: ASYNC no support\n", MBTAG);
+		vClrMboxStats(MAILBOX_CLR(mbox));
+		vClrMbInterrupt(IRQ_REV_BIT(mbox));
+		vEnableMbInterrupt(IRQ_REV_BIT(mbox));
+#endif
+		break;
+	default:
+		PRINT_ERR("[%s]: Not SYNC or ASYNC, Fail\n", MBTAG);
+		vClrMboxStats(MAILBOX_CLR(mbox));
+		vClrMbInterrupt(IRQ_REV_BIT(mbox));
+		vEnableMbInterrupt(IRQ_REV_BIT(mbox));
+		break;
+	}
+}
+
+static void vAoAckMbHandler(void *vArg)
+{
+	uint32_t mbox = (uint32_t)vArg;
+	uint32_t addr = xRevAddrMbox(mbox);
+	mbHeadInfo mbHead;
+	BaseType_t xYieldRequired = pdFALSE;
+
+	xGetPayloadHead(addr, &mbHead);
+	if (mbHead.taskid)
+		vTaskNotifyGiveFromISR((TaskHandle_t)((uint32_t)mbHead.taskid), &xYieldRequired);
+	portYIELD_FROM_ISR(xYieldRequired);
+}
+
+static void vReeSyncTask(void *pvParameters)
+{
+	uint32_t addr = 0;
+	uint32_t mbox = 0;
+	int index = 0;
+
+	pvParameters = pvParameters;
+	while (1) {
+		ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
+		PRINT_DBG("[%s]:ReeSyncTask\n", MBTAG);
+
+		index = mailbox_htbl_invokeCmd(g_tbl_ao, syncReeMbInfo.ulCmd,
+					       syncReeMbInfo.mbdata.data);
+		mbox = xGetRevMbox(syncReeMbInfo.ulChan);
+		PRINT_DBG("[%s]:ReeSyncTask mbox:%d\n", MBTAG, mbox);
+		addr = xSendAddrMbox(mbox);
+		if (index != 0) {
+			if (index == MAX_ENTRY_NUM) {
+				memset(&syncReeMbInfo.mbdata.data, 0, sizeof(syncReeMbInfo.mbdata.data));
+				syncReeMbInfo.mbdata.status = ACK_FAIL;
+				vBuildPayload(addr, &syncReeMbInfo.mbdata, sizeof(syncReeMbInfo.mbdata));
+				PRINT_DBG("[%s]: undefine cmd or no callback\n", MBTAG);
+			} else {
+				PRINT_DBG("[%s]:SyncTask re len:%d\n", MBTAG, sizeof(syncReeMbInfo.mbdata));
+				syncReeMbInfo.mbdata.status = ACK_OK;
+				vBuildPayload(addr, &syncReeMbInfo.mbdata, sizeof(syncReeMbInfo.mbdata));
+			}
+		}
+
+		vEnterCritical();
+		PRINT_DBG("[%s]:Ree Sync clear mbox:%d\n", MBTAG, mbox);
+		ulReeSyncTaskWake = 0;
+		vClrMboxStats(MAILBOX_CLR(mbox));
+		vClrMbInterrupt(IRQ_REV_BIT(mbox));
+		vEnableMbInterrupt(IRQ_REV_BIT(mbox));
+		vExitCritical();
+	}
+}
+
+static void vTeeSyncTask(void *pvParameters)
+{
+	uint32_t addr = 0;
+	uint32_t mbox = 0;
+	int index = 0;
+
+	pvParameters = pvParameters;
+	while (1) {
+		ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
+		PRINT_DBG("[%s]:TeeSyncTask\n", MBTAG);
+
+		index = mailbox_htbl_invokeCmd(g_tbl_ao, syncTeeMbInfo.ulCmd,
+					       syncTeeMbInfo.mbdata.data);
+		mbox = xGetRevMbox(syncTeeMbInfo.ulChan);
+		PRINT_DBG("[%s]:TeeSyncTask mbox:%d\n", MBTAG, mbox);
+		addr = xSendAddrMbox(mbox);
+		if (index != 0) {
+			if (index == MAX_ENTRY_NUM) {
+				memset(&syncTeeMbInfo.mbdata.data, 0, sizeof(syncTeeMbInfo.mbdata.data));
+				syncTeeMbInfo.mbdata.status = ACK_FAIL;
+				vBuildPayload(addr, &syncTeeMbInfo.mbdata, sizeof(syncTeeMbInfo.mbdata));
+				PRINT_DBG("[%s]: undefine cmd or no callback\n", MBTAG);
+			} else {
+				PRINT_DBG("[%s]:SyncTask re len:%d\n", MBTAG, sizeof(syncTeeMbInfo.mbdata));
+				syncTeeMbInfo.mbdata.status = ACK_OK;
+				vBuildPayload(addr, &syncTeeMbInfo.mbdata, sizeof(syncTeeMbInfo.mbdata));
+			}
+		}
+
+		vEnterCritical();
+		PRINT_DBG("[%s]:Tee Sync clear mbox:%d\n", MBTAG, mbox);
+		ulTeeSyncTaskWake = 0;
+		vClrMboxStats(MAILBOX_CLR(mbox));
+		vClrMbInterrupt(IRQ_REV_BIT(mbox));
+		vEnableMbInterrupt(IRQ_REV_BIT(mbox));
+		vExitCritical();
+	}
+}
+
+static void vDspSyncTask(void *pvParameters)
+{
+	uint32_t addr = 0;
+	uint32_t mbox = 0;
+	int index = 0;
+
+	pvParameters = pvParameters;
+	while (1) {
+		ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
+		PRINT_DBG("[%s]:DspSyncTask\n", MBTAG);
+
+		index = mailbox_htbl_invokeCmd(g_tbl_ao, syncDspMbInfo.ulCmd,
+					       syncDspMbInfo.mbdata.data);
+		mbox = xGetRevMbox(syncDspMbInfo.ulChan);
+		PRINT_DBG("[%s]:DspSyncTask mbox:%d\n", MBTAG, mbox);
+		addr = xSendAddrMbox(mbox);
+		if (index != 0) {
+			if (index == MAX_ENTRY_NUM) {
+				memset(&syncDspMbInfo.mbdata.data, 0, sizeof(syncDspMbInfo.mbdata.data));
+				syncDspMbInfo.mbdata.status = ACK_FAIL;
+				vBuildPayload(addr, &syncDspMbInfo.mbdata, sizeof(syncDspMbInfo.mbdata));
+				PRINT_DBG("[%s]: undefine cmd or no callback\n", MBTAG);
+			} else {
+				PRINT_DBG("[%s]:SyncTask re len:%d\n", MBTAG, sizeof(syncDspMbInfo.mbdata));
+				syncDspMbInfo.mbdata.status = ACK_OK;
+				vBuildPayload(addr, &syncDspMbInfo.mbdata, sizeof(syncDspMbInfo.mbdata));
+			}
+		}
+
+		vEnterCritical();
+		PRINT_DBG("[%s]:Tee Sync clear mbox:%d\n", MBTAG, mbox);
+		ulDspSyncTaskWake = 0;
+		vClrMboxStats(MAILBOX_CLR(mbox));
+		vClrMbInterrupt(IRQ_REV_BIT(mbox));
+		vEnableMbInterrupt(IRQ_REV_BIT(mbox));
+		vExitCritical();
+	}
+}
+
+void vMbInit(void)
+{
+	PRINT("[%s]: mailbox init start\n", MBTAG);
+	mailbox_htbl_init(&g_tbl_ao);
+
+	/* Set MBOX IRQ Handler and Priority */
+	vSetMbIrqHandler(IRQ_REV_NUM(MAILBOX_ARMREE2AO), vAoRevMbHandler, (void *)MAILBOX_ARMREE2AO, 10);
+
+	vSetMbIrqHandler(IRQ_REV_NUM(MAILBOX_ARMTEE2AO), vAoRevMbHandler, (void *)MAILBOX_ARMTEE2AO, 10);
+
+	vSetMbIrqHandler(IRQ_REV_NUM(MAILBOX_DSPA2AO), vAoRevMbHandler, (void *)MAILBOX_DSPA2AO, 10);
+	vSetMbIrqHandler(IRQ_SENDACK_NUM(MAILBOX_AO2DSPA), vAoAckMbHandler, (void *)MAILBOX_AO2DSPA, 10);
+
+	//vEnableIrq(IRQ_NUM_MB_4, MAILBOX_AOCPU_IRQ);
+	RegisterIrq(MAILBOX_AOCPU_IRQ, 1, vMbHandleIsr);
+	//printf("%s: TODO: please use new vEnableIiq function.\n", __func__);
+	EnableIrq(MAILBOX_AOCPU_IRQ);
+
+	xTaskCreate(vReeSyncTask,
+		    "AOReeSyncTask",
+		    configMINIMAL_STACK_SIZE,
+		    0,
+		    TASK_PRIORITY,
+		    (TaskHandle_t *)&ReembHandler);
+	xTaskCreate(vTeeSyncTask,
+		    "AOTeeSyncTask",
+		    configMINIMAL_STACK_SIZE,
+		    0,
+		    TASK_PRIORITY,
+		    (TaskHandle_t *)&TeembHandler);
+	xTaskCreate(vDspSyncTask,
+		    "AODspSyncTask",
+		    configMINIMAL_STACK_SIZE,
+		    0,
+		    TASK_PRIORITY,
+		    (TaskHandle_t *)&DspmbHandler);
+
+	vRpcUserCmdInit();
+	PRINT("[%s]: mailbox init end\n", MBTAG);
+}
+
+BaseType_t xInstallRemoteMessageCallbackFeedBack(uint32_t ulChan, uint32_t cmd,
+						 void *(*handler) (void *),
+						 uint8_t needFdBak)
+{
+	VALID_CHANNEL(ulChan);
+	UNUSED(ulChan);
+	return mailbox_htbl_reg_feedback(g_tbl_ao, cmd, handler, needFdBak);
+}
+
+BaseType_t xUninstallRemoteMessageCallback(uint32_t ulChan, int32_t cmd)
+{
+	UNUSED(ulChan);
+	return mailbox_htbl_unreg(g_tbl_ao, cmd);
+}
+
+BaseType_t xTransferMessageAsync(uint32_t ulChan, uint32_t ulCmd,
+				 void *data, size_t size)
+{
+	mboxData mbData;
+	uint32_t mboxId;
+	uint32_t addr;
+	uint32_t mbSize;
+	MbStat_t st;
+	uint32_t xPreVal = 0;
+
+	VALID_CHANNEL(ulChan);
+	mboxId = xGetSendMbox(ulChan);
+	addr = xSendAddrMbox(mboxId);
+	mbSize = size + sizeof(mbHeadInfo);
+
+	st.cmd = ulCmd;
+	st.size = mbSize;
+	st.sync = MB_ASYNC;
+
+	strncpy((char *)mbData.data, data, size);
+	mbData.taskid = (uint32_t)(void *)xTaskGetCurrentTaskHandle();
+	mbData.status = 1;
+	vBuildPayload(addr, &mbData, mbSize);
+	vSetMboxStats(MAILBOX_SET(mboxId), st);
+	xPreVal = ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(3000));
+	if (xPreVal == 0) {
+		st.cmd = 0;
+		st.size = 0;
+		st.sync = 0;
+		vSetMboxStats(MAILBOX_SET(mboxId), st);
+	} else {
+		vClrMbInterrupt(IRQ_SENDACK_BIT(mboxId));
+		vEnableMbInterrupt(IRQ_SENDACK_BIT(mboxId));
+	}
+	return 0;
+}
diff --git a/bl30/src_ao/demos/amlogic/driver/mailbox/rpc-user.c b/bl30/src_ao/demos/amlogic/driver/mailbox/rpc-user.c
new file mode 100644
index 0000000..a0fc495
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/mailbox/rpc-user.c
@@ -0,0 +1,100 @@
+
+/*
+ *  Copyright (C) 2014-2018 Amlogic, Inc. All rights reserved.
+ *
+ *  All information contained herein is Amlogic confidential.
+ *
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <util.h>
+#include "FreeRTOS.h"
+#include "task.h"
+#include "queue.h"
+#include "semphr.h"
+#include <stdio.h>
+#include "myprintf.h"
+
+#include <unistd.h>
+#include "n200_func.h"
+#include "uart.h"
+#include "common.h"
+#include "riscv_encoding.h"
+
+#include "mailbox-api.h"
+
+#define MBTAG "AOCPU"
+#define PRINT_DBG(...)  printf(__VA_ARGS__)
+#define PRINT_ERR(...)  printf(__VA_ARGS__)
+#define PRINT(...)	printf(__VA_ARGS__)
+
+/*ARM 2 AOCPU mailbox*/
+void vRpcUserCmdInit(void);
+
+struct Uintcase {
+	char data[20];
+	uint32_t ulTaskDelay;
+};
+
+static inline void *mbmemset(void *dst, int val, size_t count)
+{
+	char *ptr = dst;
+
+	while (count--)
+		*ptr++ = val;
+
+	return dst;
+}
+
+static inline void *mbmemcpy(void *dst, const void *src, size_t len)
+{
+	const char *s = src;
+	char *d = dst;
+
+	while (len--)
+		*d++ = *s++;
+
+	return dst;
+}
+
+static void xMboxUintReeTestCase(void *msg)
+{
+	struct Uintcase *pdata = msg;
+	char back[20] = "Response AOCPU\n";
+
+	PRINT("[%s]: scpi %s\n", MBTAG, pdata->data);
+	mbmemset(msg, 0, MBOX_BUF_LEN);
+	mbmemcpy(msg, back, sizeof(back));
+
+	PRINT("[%s]: delay after %ld\n", MBTAG, pdata->ulTaskDelay);
+
+}
+
+static void xMboxUintTeeTestCase(void *msg)
+{
+	char *s = msg;
+
+	PRINT("[%s]: from tee: %s\n", MBTAG, s);
+
+}
+
+static void vRegisterRpcCallBack(void)
+{
+	int ret;
+
+	ret = xInstallRemoteMessageCallbackFeedBack(AOREE_CHANNEL, MBX_CMD_RPCUINTREE_TEST,
+						    (void *)xMboxUintReeTestCase, 1);
+	if (ret == MBOX_CALL_MAX)
+		PRINT("[%s]: mbox cmd 0x%x register fail\n",MBTAG, MBX_CMD_RPCUINTREE_TEST);
+
+	ret = xInstallRemoteMessageCallbackFeedBack(AOTEE_CHANNEL, MBX_CMD_RPCUINTTEE_TEST,
+						    (void *)xMboxUintTeeTestCase, 0);
+	if (ret == MBOX_CALL_MAX)
+		PRINT("[%s]: mbox cmd 0x%x register fail\n", MBTAG, MBX_CMD_RPCUINTTEE_TEST);
+}
+
+void vRpcUserCmdInit(void)
+{
+        vRegisterRpcCallBack();
+}
diff --git a/bl30/src_ao/demos/amlogic/driver/pm/build.mk b/bl30/src_ao/demos/amlogic/driver/pm/build.mk
new file mode 100644
index 0000000..dc57880
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/pm/build.mk
@@ -0,0 +1,32 @@
+#
+#  Copyright (C) 2014-2018 Amlogic, Inc. All rights reserved.
+#
+#  All information contained herein is Amlogic confidential.
+#
+#  This software is provided to you pursuant to Software License Agreement
+#  (SLA) with Amlogic Inc ("Amlogic"). This software may be used
+#  only in accordance with the terms of this agreement.
+#
+#  Redistribution and use in source and binary forms, with or without
+#  modification is strictly prohibited without prior written permission from
+#  Amlogic.
+#
+#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#  OWNER 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, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+ifeq ("$(SOC)","t3")
+PM=y
+CFLAGS += -DSUPPORT_PM
+endif
+
+pm-$(PM) = suspend.o
diff --git a/bl30/src_ao/demos/amlogic/driver/pm/suspend.c b/bl30/src_ao/demos/amlogic/driver/pm/suspend.c
new file mode 100644
index 0000000..2da1ae2
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/pm/suspend.c
@@ -0,0 +1,297 @@
+/*
+ * Copyright (C) 2014-2022 Amlogic, Inc. All rights reserved.
+ *
+ * All information contained herein is Amlogic confidential.
+ *
+ * This software is provided to you pursuant to Software License Agreement
+ * (SLA) with Amlogic Inc ("Amlogic"). This software may be used
+ * only in accordance with the terms of this agreement.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification is strictly prohibited without prior written permission from
+ * Amlogic.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER 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, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#define MTAG	"pm"
+#include "pm.h"
+#include "FreeRTOS.h"
+#include "list.h"
+#include "task.h"
+#include "common.h"
+#include "myprintf.h"
+#include "queue.h"
+#include "semphr.h"
+#include "soc.h"
+#include "wakeup.h"
+
+#define PM_SUSPEND_ON		(0)
+#define PM_SUSPEND_TO_IDLE	(1)
+#define PM_RESUME	(2)
+#define PM_SUSPEND_MEM		(3)
+#define PM_SUSPEND_MIN		PM_SUSPEND_TO_IDLE
+#define PM_SUSPEND_MAX		(4)
+
+#define malloc pvPortMalloc
+#define free vPortFree
+
+#define mutex_lock(x)	xSemaphoreTake((x), portMAX_DELAY)
+#define mutex_unlock(x) xSemaphoreGive((x))
+
+static List_t pm_dev;
+
+struct wakeup_source {
+	ListItem_t list_item;
+	char *name;
+	uint32_t wake_count;
+	uint32_t need_wakeup:1;
+	void *data;
+	struct dev_power_ops * ops;
+};
+
+void pm_main(void *arg);
+static SemaphoreHandle_t xPM_wakeup_sem = NULL;
+static uint32_t system_status = PM_SUSPEND_ON;
+static int default_pm(void);
+
+
+static struct platform_power_ops * platform_pm_ops =
+	&(struct platform_power_ops){
+		.begin = default_pm,
+		.end = default_pm,
+};
+
+static int default_pm(void)
+{
+	logi("%s\n", __func__);
+	return 0;
+}
+
+static struct wakeup_source * active_ws;
+
+static QueueHandle_t pm_list_lock;
+static TaskHandle_t pm_main_handle;
+static struct wakeup_source * kernel_ws;
+/*
+ * System suspend/freeze event processing therad
+ * */
+
+extern void platform_power_interface_register(void);
+
+static int virtual_kernel_ws_enter(void *arg)
+{
+	(void)arg;
+	logi("%s\n", __func__);
+	return 0;
+}
+
+static int virtual_kernel_ws_restore(void *arg)
+{
+	(void)arg;
+	logi("%s\n", __func__);
+	return 0;
+}
+
+static struct dev_power_ops ws_kernel_ops = {
+	.enter = virtual_kernel_ws_enter,
+	.restore = virtual_kernel_ws_restore,
+};
+
+void pm_main(void *arg)
+{
+	(void) arg;
+	int i;
+	struct wakeup_source *ws;
+
+	xPM_wakeup_sem = xSemaphoreCreateBinary();
+	configASSERT(xPM_wakeup_sem);
+
+	logi(" Ready to startup power manage\n");
+
+	platform_power_interface_register();
+
+	kernel_ws = dev_register_ws("kernel", &ws_kernel_ops, NULL, WS_NEED_NOT_WAKEUP);
+	for (;;) {
+		system_status = PM_SUSPEND_ON;;
+		logi("Ready to wait\n");
+		ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
+		logi("Entry freeze\n");
+		taskENTER_CRITICAL();
+		active_ws = NULL;
+		taskEXIT_CRITICAL();
+		system_status = PM_SUSPEND_TO_IDLE;
+		mutex_lock(pm_list_lock);
+		for (i = 0; i < (int)listCURRENT_LIST_LENGTH(&pm_dev); i++) {
+			listGET_OWNER_OF_NEXT_ENTRY(ws, &pm_dev);
+			if (ws && ws->ops->enter)
+				ws->ops->enter(ws);
+		}
+		mutex_unlock(pm_list_lock);
+		platform_pm_ops->begin();
+
+		xSemaphoreTake(xPM_wakeup_sem, portMAX_DELAY);
+		logi("Resume freeze\n");
+
+		platform_pm_ops->end();
+		mutex_lock(pm_list_lock);
+		for (i = 0; i < (int)listCURRENT_LIST_LENGTH(&pm_dev); i++) {
+			listGET_OWNER_OF_PRE_ENTRY(ws, &pm_dev);
+			if (ws && ws->ops->restore)
+				ws->ops->restore(ws);
+		}
+		mutex_unlock(pm_list_lock);
+
+		logi("AOCPU already resume done.\n");
+
+		if (active_ws) {
+			if (active_ws->need_wakeup) {
+				logi("ready to wakeup ap\n");
+				wakeup_ap();
+			}
+		} else {
+			loge("Error occurred, should never get here.\n");
+		}
+	}
+}
+
+static int os_is_running(void)
+{
+	return system_status == PM_SUSPEND_ON;
+}
+
+extern uint32_t _module_pm_begin;
+extern uint32_t _module_pm_end;
+int find_static_power_dev(void)
+{
+	initcall_t * p = (void *)&_module_pm_begin;
+	vListInitialise(&pm_dev);
+
+	pm_list_lock = xSemaphoreCreateMutex();
+
+	if (xTaskCreate( pm_main, "pm_task", configMINIMAL_STACK_SIZE, NULL, 3, &pm_main_handle ) < 0)
+		loge("STR_task create fail!!\n");
+
+	for (; p < (initcall_t *)&_module_pm_end; ) {
+		int (* fn)(void) = (*p++);
+		if (fn)
+			fn();
+	}
+	return 0;
+}
+
+int pm_enter(void)
+{
+	xTaskNotifyGive(pm_main_handle);
+	return 0;
+}
+
+struct wakeup_source * dev_register_ws(char * name, struct dev_power_ops *ops, void *data, uint32_t need_wakeup_flag)
+{
+	struct wakeup_source * ws;
+
+	if (!name || !ops) {
+		loge("Invalid pass parameters\n");
+		return NULL;
+	}
+
+	ws = (struct wakeup_source *)malloc((size_t)sizeof(struct wakeup_source));
+
+	if (!ws) {
+		loge("Wakeup source malloc fail!!\n");
+		return NULL;
+	}
+
+	ws->name = name;
+	ws->ops = ops;
+	ws->data = data;
+	ws->need_wakeup = !!need_wakeup_flag;
+	ws->list_item.pvOwner = (void *)ws;
+
+	mutex_lock(pm_list_lock);
+	vListInsert(&pm_dev, &ws->list_item);
+	mutex_unlock(pm_list_lock);
+
+	return ws;
+}
+
+int dev_unregister_ws(ws_t  arg)
+{
+	struct wakeup_source *ws = arg;
+	uint32_t ret;
+
+	if (!ws) {
+		loge("Invalid parameters\n");
+		return -1;
+	}
+
+	ret = uxListRemove(&(ws->list_item));
+	(void)ret;
+
+	free(ws);
+	ws = NULL;
+	return 0;
+}
+
+int pm_wake_up(ws_t arg)
+{
+	struct wakeup_source *ws = arg;
+	if (!ws) {
+		loge("Invalid parameters\n");
+		return -1;
+	}
+
+	if (!listIS_CONTAINED_WITHIN(&pm_dev, &ws->list_item)) {
+		loge("Invalid wakeup source.\n");
+		return -1;
+	}
+
+	if (active_ws) {
+		loge("System is ready to wake up, source is %s\n",
+				active_ws->name);
+		return -1;
+	}
+
+	taskENTER_CRITICAL();
+	active_ws = ws;
+	taskEXIT_CRITICAL();
+
+	ws->wake_count ++;
+	xSemaphoreGive(xPM_wakeup_sem);
+	logi("Activation source received:%s\n", ws->name);
+	return 0;
+}
+
+int set_platform_power_ops(struct platform_power_ops *ops)
+{
+	if (!ops) {
+		loge("Invalid parameters\n");
+		return -1;
+	}
+
+	platform_pm_ops = ops;
+	return 0;
+}
+
+/*
+ * Wakeup 30 interface, only used for wakeup events sent by the kernel.
+ * */
+void wakeup_ap_from_kernel(void)
+{
+	logi("ARM sync with 30...\n");
+	pm_wake_up(kernel_ws);
+	/* need sync*/
+	while (!os_is_running()) {
+		logi("ARM sync with 30...\n");
+		vTaskDelay(pdMS_TO_TICKS(100));
+	}
+}
diff --git a/bl30/src_ao/demos/amlogic/driver/pmic/bd71837.c b/bl30/src_ao/demos/amlogic/driver/pmic/bd71837.c
new file mode 100644
index 0000000..6da67bb
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/pmic/bd71837.c
@@ -0,0 +1,506 @@
+/*
+ * Copyright (C) 2014-2018 Amlogic, Inc. All rights reserved.
+ *
+ * All information contained herein is Amlogic confidential.
+ *
+ * This software is provided to you pursuant to Software License Agreement
+ * (SLA) with Amlogic Inc ("Amlogic"). This software may be used
+ * only in accordance with the terms of this agreement.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification is strictly prohibited without prior written permission from
+ * Amlogic.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER 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, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "bd71837.h"
+#include "meson_i2c.h"
+#include "uart.h"
+#include "myprintf.h"
+#include "gpio.h"
+
+static const struct regulator_linear_range bd718xx_dvs_buck_volts[] = {
+	REGULATOR_LINEAR_RANGE(700000, 0x00, 0x3C, 10000),
+	REGULATOR_LINEAR_RANGE(1300000, 0x3D, 0x3F, 0),
+};
+
+static const struct regulator_linear_range bd71837_buck5_volts[] = {
+	/* Ranges when VOLT_SEL bit is 0 */
+	REGULATOR_LINEAR_RANGE(700000, 0x00, 0x03, 100000),
+	REGULATOR_LINEAR_RANGE(1050000, 0x04, 0x05, 50000),
+	REGULATOR_LINEAR_RANGE(1200000, 0x06, 0x07, 150000),
+};
+
+static const struct regulator_linear_range bd71837_buck6_volts[] = {
+	REGULATOR_LINEAR_RANGE(3000000, 0x00, 0x03, 100000),
+};
+
+static const unsigned int bd71837_buck7_volts[] = {
+	1605000, 1695000, 1755000, 1800000, 1845000, 1905000, 1950000, 1995000
+};
+
+static const struct regulator_linear_range bd71837_buck8_volts[] = {
+	REGULATOR_LINEAR_RANGE(680000, 0x00, 0x3C, 11500),
+	REGULATOR_LINEAR_RANGE(1370000, 0x3C, 0x3F, 0),
+ };
+
+static const struct regulator_linear_range bd718xx_ldo1_volts[] = {
+	REGULATOR_LINEAR_RANGE(1600000, 0x00, 0x03, 100000),
+};
+
+static const unsigned int ldo_2_volts[] = {
+	900000, 800000
+};
+
+static const struct regulator_linear_range bd718xx_ldo3_volts[] = {
+	REGULATOR_LINEAR_RANGE(1800000, 0x00, 0x0F, 100000),
+};
+
+static const struct regulator_linear_range bd718xx_ldo4_volts[] = {
+	REGULATOR_LINEAR_RANGE(900000, 0x00, 0x09, 100000),
+	REGULATOR_LINEAR_RANGE(1800000, 0xa, 0xf, 0),
+};
+
+static const struct regulator_linear_range bd71837_ldo5_volts[] = {
+	REGULATOR_LINEAR_RANGE(1800000, 0x00, 0x0F, 100000),
+};
+
+static const struct regulator_linear_range bd718xx_ldo6_volts[] = {
+	REGULATOR_LINEAR_RANGE(900000, 0x00, 0x09, 100000),
+	REGULATOR_LINEAR_RANGE(1800000, 0xA, 0xF, 0),
+};
+
+static const struct regulator_linear_range bd71837_ldo7_volts[] = {
+	REGULATOR_LINEAR_RANGE(1800000, 0x00, 0x0F, 100000),
+};
+
+static int find_index(const unsigned int *p,unsigned int len,unsigned int sel)
+{
+	for (unsigned int i = 0; i < len; i++)
+	{
+		if (sel == p[i])
+			return i;
+	}
+	return -1;
+
+}
+
+static int find_index_struct(struct regulator_desc *rdev,unsigned int sel, int id)
+{
+	int b = 0;
+	unsigned int min_sel1 = 0;
+	unsigned int step = 0;
+	min_sel1 = (rdev->linear_ranges)[id].min_sel;
+	step = (rdev->linear_ranges)[id].uV_step;
+	b = sel - (rdev->linear_ranges)[id].min_uV;
+	b = b/step;
+	b = min_sel1 + b;
+	return b;
+
+}
+
+static void set_pmic_bd71837_pinmux(struct pmic_i2c *bd71837_i2c_config1)
+{
+	   // set pinmux
+	   iprintf("set %s pinmux\n",bd71837_i2c_config1->name);
+	   xPinmuxSet(bd71837_i2c_config1->scl, bd71837_i2c_config1->scl_value);
+	   xPinmuxSet(bd71837_i2c_config1->sda, bd71837_i2c_config1->sda_value);
+	   //set ds and pull up
+	   xPinconfSet(bd71837_i2c_config1->scl, PINF_CONFIG_BIAS_PULL_UP | PINF_CONFIG_DRV_STRENGTH_3);
+	   xPinconfSet(bd71837_i2c_config1->sda, PINF_CONFIG_BIAS_PULL_UP | PINF_CONFIG_DRV_STRENGTH_3);
+}
+
+static void BD71837_PMIC_I2C_INIT(struct pmic_i2c *bd71837_i2c_config) {
+	set_pmic_bd71837_pinmux(bd71837_i2c_config);
+	xI2cMesonPortInit(bd71837_i2c_config->port);
+}
+
+static int bd71837_regulator_ctrl(struct regulator_desc *rdev,int status)
+{
+	int ret = 0;
+	unsigned char ctrl_reg = 0x0;
+	if ((rdev->id)<= 7) {
+		ret = xI2cMesonRead(bd718x7_slave_address,rdev->enable_reg,&ctrl_reg,1);
+		if (ret < 0) {
+			printf("i2c buck read failed\n");
+			return ret;
+		}
+		ctrl_reg &= (~(rdev->enable_mask));
+		if (status) {
+			ctrl_reg |= rdev->enable_val;
+		} else {
+			ctrl_reg |= rdev->disable_val;
+		}
+		ret = xI2cMesonWrite(bd718x7_slave_address,rdev->enable_reg,&ctrl_reg,1);
+		if (ret < 0) {
+			printf("i2c buck write failed\n");
+			return ret;
+		}
+
+	} else {
+		ret = xI2cMesonRead(bd718x7_slave_address,rdev->ldo_reg,&ctrl_reg,1);
+		if (ret < 0) {
+			printf("i2c ldo read failed\n");
+			return ret;
+		}
+		ctrl_reg &= (~(rdev->ldo_mask_ctrl));
+		if (status) {
+			ctrl_reg |= rdev->ldo_val_ctrl;
+		} else {
+			ctrl_reg |= rdev->ldo_val_ctrl_disable;
+		}
+		ret = xI2cMesonWrite(bd718x7_slave_address,rdev->ldo_reg,&ctrl_reg,1);
+		if (ret < 0) {
+			printf("i2c ldo write failed\n");
+			return ret;
+		}
+
+	}
+	return ret;
+}
+
+static int bd71837_regulator_set_voltage(struct regulator_desc *rdev, unsigned int sel)
+{
+	int a = 0;
+	int ret = 0;
+	unsigned char ctrl_reg = 0;
+	if ((rdev->id)<= 3) { /* buck1-4 */
+		if (sel <= 1290000) {
+			a = find_index_struct(rdev,sel,0);
+		} else {
+			a = (rdev->linear_ranges)[1].min_sel;
+		}
+	} /* buck5 */
+	if ((rdev->id) == 4) {
+		if (sel <= 1000000) {
+			a = find_index_struct(rdev,sel,0);
+		} else if (1050000 <= sel && sel <= 1100000) {
+			a = find_index_struct(rdev,sel,1);
+		} else {
+			a = find_index_struct(rdev,sel,2);
+		}
+	} /*  buck6 */
+	if ((rdev->id) == 5) {
+		a = find_index_struct(rdev,sel,0);
+	} /*buck7 */
+	if ((rdev->id) == 6) {
+		a = find_index(rdev->volt_table,rdev->n_voltages,sel);
+	} /*buck8*/
+	if ((rdev->id) == 7) {
+		if (sel <= 1358500) {
+			a = find_index_struct(rdev,sel,0);
+		} else {
+			a = (rdev->linear_ranges)[1].min_sel;
+		}
+	}  /* ldo1 */
+	if ((rdev->id) == 8) {
+		a = find_index_struct(rdev,sel,0);
+	} /* ldo2 */
+	if ((rdev->id) == 9) {
+		a = find_index(rdev->volt_table,rdev->n_voltages,sel);
+		a = a << 5;
+	} /* ldo3 */
+	if ((rdev->id) == 10) {
+		a = find_index_struct(rdev,sel,0);
+	} /* ldo4 */
+	if ((rdev->id) == 11) {
+		if (sel <= 1700000) {
+			a = find_index_struct(rdev,sel,0);
+		} else {
+			a = (rdev->linear_ranges)[1].min_sel;
+		}
+	} /* ldo5 */
+	if ((rdev->id) == 12) {
+		a = find_index_struct(rdev,sel,0);
+	} /* ldo6 */
+	if ((rdev->id) == 13) {
+		if (sel <= 1700000) {
+			a = find_index_struct(rdev,sel,0);
+		} else {
+			a = (rdev->linear_ranges)[1].min_sel;
+		}
+	} /* ldo7 */
+	if ((rdev->id) == 14) {
+		a = find_index_struct(rdev,sel,0);
+	}
+	if ((rdev->id) <= 7) {
+		ret = xI2cMesonRead(bd718x7_slave_address,rdev->vsel_reg,&ctrl_reg,1);
+		if (ret < 0) {
+			printf("i2c buck read failed\n");
+			return ret;
+		}
+		ctrl_reg &= (~(rdev->vsel_mask));
+		ctrl_reg |= (a<<0);
+		ret = xI2cMesonWrite(bd718x7_slave_address,rdev->vsel_reg,&ctrl_reg,1);
+		if (ret < 0) {
+			printf("i2c buck write failed\n");
+			return ret;
+		}
+	}
+	if ((rdev->id) > 7) {
+		ret = xI2cMesonRead(bd718x7_slave_address,rdev->ldo_reg,&ctrl_reg,1);
+		if (ret < 0) {
+			printf("i2c ldo read failed\n");
+			return ret;
+		}
+		ctrl_reg &= (~(rdev->ldo_out_mask));
+		ctrl_reg |= a;
+		ret = xI2cMesonWrite(bd718x7_slave_address,rdev->ldo_reg,&ctrl_reg,1);
+		if (ret < 0) {
+			printf("i2c ldo write failed\n");
+			return ret;
+		}
+	}
+
+	return ret;
+}
+
+static void bd71837_osc_ctrl(int status)
+{
+	unsigned char ctrl_reg = 0;
+	int ret = 0;
+	ret = xI2cMesonRead(bd718x7_slave_address,BD718XX_REG_OUT32K,&ctrl_reg,1);
+	if (ret < 0) {
+		printf("i2c osc read failed\n");
+		return;
+	}
+	if (status) {
+		ctrl_reg &= (~0x1);
+		ctrl_reg |= 0x1;
+	} else {
+		ctrl_reg &= (~0x1);
+		ctrl_reg |= 0x0;
+	}
+	ret = xI2cMesonWrite(bd718x7_slave_address,BD718XX_REG_OUT32K,&ctrl_reg,1);
+	if (ret < 0) {
+		printf("i2c osc write failed\n");
+		return;
+	}
+	return;
+}
+
+static const struct regulator_ops bd718xx_dvs_buck_regulator_ops = {
+	.ctrl = bd71837_regulator_ctrl,
+	.set_voltage = bd71837_regulator_set_voltage,
+};
+
+struct regulator_desc bd71837_desc[15] = {
+		{
+			.name = "buck1",
+			.id = BD718XX_BUCK1,
+			.ops = &bd718xx_dvs_buck_regulator_ops,
+			.linear_ranges = bd718xx_dvs_buck_volts,
+			.n_linear_ranges = ARRAY_SIZE(bd718xx_dvs_buck_volts),
+			.enable_reg = BD718XX_REG_BUCK1_CTRL,
+			.enable_mask = 0x3,   //bit0 = 1, bit1 = 1
+			.enable_val = 0x3,
+			.disable_val = 0x2,  //bit0 = 0 ,bit1 = 1
+			.vsel_reg = BD718XX_REG_BUCK1_VOLT_RUN,
+			.vsel_mask = 0x3f,
+		},
+		{
+			.name = "buck2",
+			.id = BD718XX_BUCK2,
+			.ops = &bd718xx_dvs_buck_regulator_ops,
+			.linear_ranges = bd718xx_dvs_buck_volts,
+			.n_linear_ranges = ARRAY_SIZE(bd718xx_dvs_buck_volts),
+			.enable_reg = BD718XX_REG_BUCK2_CTRL,
+			.enable_mask = 0x3,    //bit0 =1 ,bit1 = 1;
+			.enable_val = 0x3,
+			.disable_val = 0x2,  //bit0 = 0 ,bit1 = 1
+			.vsel_reg = BD718XX_REG_BUCK2_VOLT_RUN,
+			.vsel_mask = 0x3f,
+		},
+		{
+			.name = "buck3",
+			.id = BD718XX_BUCK3,
+			.ops = &bd718xx_dvs_buck_regulator_ops,
+			.linear_ranges = bd718xx_dvs_buck_volts,
+			.n_linear_ranges = ARRAY_SIZE(bd718xx_dvs_buck_volts),
+			.enable_reg = BD71837_REG_BUCK3_CTRL,
+			.enable_mask = 0x7,    //bit0 =1 ,bit1 = 1 , bit2 = 1;
+			.enable_val = 0x7,
+			.disable_val = 0x2,  //bit0 = 0 ,bit1 = 1
+			.vsel_reg = BD71837_REG_BUCK3_VOLT_RUN,
+			.vsel_mask = 0x3f,
+		},
+		{
+			.name = "buck4",
+			.id = BD718XX_BUCK4,
+			.ops = &bd718xx_dvs_buck_regulator_ops,
+			.linear_ranges = bd718xx_dvs_buck_volts,
+			.n_linear_ranges = ARRAY_SIZE(bd718xx_dvs_buck_volts),
+			.enable_reg = BD71837_REG_BUCK4_CTRL,
+			.enable_mask = 0x7, //bit0 =1 ,bit1 = 1 , bit2 = 1;
+			.enable_val = 0x7,
+			.disable_val = 0x2,  //bit0 = 0 ,bit1 = 1
+			.vsel_reg = BD71837_REG_BUCK4_VOLT_RUN,
+			.vsel_mask = 0x3f,
+		},
+		{
+			.name = "buck5",
+			.id = BD718XX_BUCK5,
+			.ops = &bd718xx_dvs_buck_regulator_ops,
+			.linear_ranges = bd71837_buck5_volts,
+			.n_linear_ranges =
+				ARRAY_SIZE(bd71837_buck5_volts),
+			.enable_reg = BD718XX_REG_1ST_NODVS_BUCK_CTRL,
+			.enable_mask = 0x3,   //bit0 =1 ,bit1 = 1
+			.enable_val = 0x3,
+			.disable_val = 0x2,  //bit0 = 0 ,bit1 = 1
+			.vsel_reg = BD718XX_REG_1ST_NODVS_BUCK_VOLT,
+			.vsel_mask = 0x7,  // 某认bit7 = 0
+
+		},
+		{
+			.name = "buck6",
+			.id = BD718XX_BUCK6,
+			.ops = &bd718xx_dvs_buck_regulator_ops,
+			.linear_ranges = bd71837_buck6_volts,
+			.n_linear_ranges =
+				ARRAY_SIZE(bd71837_buck6_volts),
+			.enable_reg = BD718XX_REG_2ND_NODVS_BUCK_CTRL,
+			.enable_mask = 0x3,   //bit0 =1 ,bit1 = 1,
+			.enable_val = 0x3,
+			.disable_val = 0x2,  //bit0 = 0 ,bit1 = 1
+			.vsel_reg = BD718XX_REG_2ND_NODVS_BUCK_VOLT,
+			.vsel_mask = 0x3,
+		},
+		{
+			.name = "buck7",
+			.id = BD718XX_BUCK7,
+			.ops = &bd718xx_dvs_buck_regulator_ops,
+			.volt_table = &bd71837_buck7_volts[0],
+			.n_voltages = sizeof(bd71837_buck7_volts),
+			.enable_reg = BD718XX_REG_3RD_NODVS_BUCK_CTRL,
+			.enable_mask = 0x3,   //bit0 =1 ,bit1 = 1,
+			.enable_val = 0x3,
+			.disable_val = 0x2,  //bit0 = 0 ,bit1 = 1
+			.vsel_reg = BD718XX_REG_3RD_NODVS_BUCK_VOLT,
+			.vsel_mask = 0x7,
+		},
+		{
+			.name = "buck8",
+			.id = BD718XX_BUCK8,
+			.ops = &bd718xx_dvs_buck_regulator_ops,
+			.linear_ranges = bd71837_buck8_volts,
+			.n_linear_ranges =
+				ARRAY_SIZE(bd71837_buck8_volts),
+			.enable_reg = BD718XX_REG_4TH_NODVS_BUCK_CTRL,
+			.enable_mask = 0x3,   //bit0 =1 ,bit1 = 1,
+			.enable_val = 0x3,
+			.disable_val = 0x2,  //bit0 = 0 ,bit1 = 1
+			.vsel_reg = BD718XX_REG_4TH_NODVS_BUCK_VOLT,
+			.vsel_mask = 0x3f,
+		},
+		{
+			.name = "ldo1",
+			.id = BD718XX_LDO1,
+			.ops = &bd718xx_dvs_buck_regulator_ops,
+			.linear_ranges = bd718xx_ldo1_volts,
+			.n_linear_ranges = ARRAY_SIZE(bd718xx_ldo1_volts),
+			.ldo_reg = BD718XX_REG_LDO1_VOLT,
+			.ldo_mask_ctrl = 0xe0,   //bit5 = 1,bit6 =1,bit7 =1
+			.ldo_val_ctrl = 0xe0,
+			.ldo_val_ctrl_disable = 0x80,  //bit6 =0 ,bit7 = 1
+			.ldo_out_mask = 0x3,  //bit0-bit1 = 1
+
+		},
+		{
+			.name = "ldo2",
+			.id = BD718XX_LDO2,
+			.ops = &bd718xx_dvs_buck_regulator_ops,
+			.volt_table = &ldo_2_volts[0],
+			.n_voltages =
+					ARRAY_SIZE(bd71837_buck8_volts),
+			.ldo_reg = BD718XX_REG_LDO2_VOLT,
+			.ldo_mask_ctrl = 0xc0,  //bit6 =1,bit7 =1
+			.ldo_val_ctrl = 0xc0,
+			.ldo_val_ctrl_disable = 0x80,  //bit6 =0 ,bit7 = 1
+			.ldo_out_mask = 0x20,  //bit5 = 1
+		},
+		{
+			.name = "ldo3",
+			.id = BD718XX_LDO3,
+			.ops = &bd718xx_dvs_buck_regulator_ops,
+			.linear_ranges = bd718xx_ldo3_volts,
+			.n_linear_ranges = ARRAY_SIZE(bd718xx_ldo3_volts),
+			.ldo_reg = BD718XX_REG_LDO3_VOLT,
+			.ldo_mask_ctrl = 0xc0,  //bit6=1,bi7=1
+			.ldo_val_ctrl = 0xc0,
+			.ldo_val_ctrl_disable = 0x80,  //bit6 =0 ,bit7 = 1
+			.ldo_out_mask = 0xf,  //bit0-bit3 = 1
+		},
+		{
+			.name = "ldo4",
+			.id = BD718XX_LDO4,
+			.ops = &bd718xx_dvs_buck_regulator_ops,
+			.linear_ranges = bd718xx_ldo4_volts,
+			.n_linear_ranges = ARRAY_SIZE(bd718xx_ldo4_volts),
+			.ldo_reg = BD718XX_REG_LDO4_VOLT,
+			.ldo_mask_ctrl = 0xc0,  //bit6=1,bi7=1,
+			.ldo_val_ctrl = 0xc0,
+			.ldo_val_ctrl_disable = 0x80,  //bit6 =0 ,bit7 = 1
+			.ldo_out_mask = 0xf,  //bit0-bit3 = 1
+		},
+		{
+			.name = "ldo5",
+			.id = BD718XX_LDO5,
+			.ops = &bd718xx_dvs_buck_regulator_ops,
+			.linear_ranges = bd71837_ldo5_volts,
+			.n_linear_ranges = ARRAY_SIZE(bd71837_ldo5_volts),
+			.ldo_reg = BD718XX_REG_LDO5_VOLT,
+			.ldo_mask_ctrl = 0xc0,   //bit6=1,bi7=1,
+			.ldo_val_ctrl = 0xc0,
+			.ldo_val_ctrl_disable = 0x80,  //bit6 =0 ,bit7 = 1
+			.ldo_out_mask = 0xf,  //bit0-bit3 = 1
+		},
+		{
+			.name = "ldo6",
+			.id = BD718XX_LDO6,
+			.ops = &bd718xx_dvs_buck_regulator_ops,
+			.linear_ranges = bd718xx_ldo6_volts,
+			.n_linear_ranges = ARRAY_SIZE(bd718xx_ldo6_volts),
+			.ldo_reg = BD718XX_REG_LDO6_VOLT,
+			.ldo_mask_ctrl = 0xc0,   //bit6=1,bi7=1,
+			.ldo_val_ctrl = 0xc0,
+			.ldo_val_ctrl_disable = 0x80,  //bit6 =0 ,bit7 = 1
+			.ldo_out_mask = 0xf,  //bit0-bit3 = 1
+		},
+		{
+			.name = "ldo7",
+			.id = BD718XX_LDO7,
+			.ops = &bd718xx_dvs_buck_regulator_ops,
+			.linear_ranges = bd71837_ldo7_volts,
+			.n_linear_ranges = ARRAY_SIZE(bd71837_ldo7_volts),
+
+			.ldo_reg = BD71837_REG_LDO7_VOLT,
+			.ldo_mask_ctrl = 0xc0,   //bit6=1,bi7=1,
+			.ldo_val_ctrl = 0xc0,
+			.ldo_val_ctrl_disable = 0x80,  //bit6 =0 ,bit7 = 1
+			.ldo_out_mask = 0xf,  //bit0-bit3 = 1
+		},
+
+};
+
+struct pmic_regulator BD71837_PMIC = {
+	.pmic_i2c_config = BD71837_PMIC_I2C_INIT,
+	.osc_ctrl = bd71837_osc_ctrl,
+	.rdev = bd71837_desc,
+	.num = ARRAY_SIZE(bd71837_desc),
+};
+
+
+
+
diff --git a/bl30/src_ao/demos/amlogic/driver/pmic/build.mk b/bl30/src_ao/demos/amlogic/driver/pmic/build.mk
new file mode 100644
index 0000000..abb306e
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/pmic/build.mk
@@ -0,0 +1,26 @@
+ #
+ #  Copyright (C) 2014-2018 Amlogic, Inc. All rights reserved.
+ #
+ #  All information contained herein is Amlogic confidential.
+ #
+ #  This software is provided to you pursuant to Software License Agreement
+ #  (SLA) with Amlogic Inc ("Amlogic"). This software may be used
+ #  only in accordance with the terms of this agreement.
+ #
+ #  Redistribution and use in source and binary forms, with or without
+ #  modification is strictly prohibited without prior written permission from
+ #  Amlogic.
+ #
+ #  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ #  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ #  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ #  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ #  OWNER 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, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ #
+pmic-y = bd71837.o pmic.o
diff --git a/bl30/src_ao/demos/amlogic/driver/pmic/pmic.c b/bl30/src_ao/demos/amlogic/driver/pmic/pmic.c
new file mode 100644
index 0000000..2b4d4ad
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/pmic/pmic.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2014-2018 Amlogic, Inc. All rights reserved.
+ *
+ * All information contained herein is Amlogic confidential.
+ *
+ * This software is provided to you pursuant to Software License Agreement
+ * (SLA) with Amlogic Inc ("Amlogic"). This software may be used
+ * only in accordance with the terms of this agreement.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification is strictly prohibited without prior written permission from
+ * Amlogic.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER 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, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "pmic.h"
+#include "myprintf.h"
+
+struct pmic_regulator *pmic_regulators[PMIC_MAXNUM] = {NULL1,NULL1,NULL1,NULL1,NULL1};
+
+int pmic_regulators_register(struct pmic_regulator *PmicRegulator, int *dev_id)
+{
+	for (int i = 0;i < PMIC_MAXNUM;i++) {
+		if (pmic_regulators[i] == NULL1) {
+			pmic_regulators[i] = PmicRegulator;
+			*dev_id = i;
+			return 0;
+		}
+	}
+	printf("pmic_regulators has Greatered than PMIC_MAXNUM\n");
+	return -1;
+}
+
+void pmic_i2c_init(int dev_id,struct pmic_i2c *pmic_i2c) {
+	((pmic_regulators[dev_id])->pmic_i2c_config)(pmic_i2c);
+}
+
+int pmic_regulator_ctrl(int dev_id, int id, int status){
+	struct regulator_desc pmic_desc = ((pmic_regulators[dev_id])->rdev)[id];
+	pmic_desc.ops->ctrl(&pmic_desc, status);
+	return 0;
+}
+
+int pmic_regulator_set_voltage(int dev_id, int id,int sel){
+	struct regulator_desc pmic_desc = ((pmic_regulators[dev_id])->rdev)[id];
+	pmic_desc.ops->set_voltage(&pmic_desc, sel);
+	return 0;
+}
+
+void pmic_osc(int dev_id, int status){
+	((pmic_regulators[dev_id])->osc_ctrl)(status);
+}
+
+
+
diff --git a/bl30/src_ao/demos/amlogic/driver/pwm/build.mk b/bl30/src_ao/demos/amlogic/driver/pwm/build.mk
new file mode 100644
index 0000000..42fb676
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/pwm/build.mk
@@ -0,0 +1,26 @@
+#
+#  Copyright (C) 2014-2018 Amlogic, Inc. All rights reserved.
+#
+#  All information contained herein is Amlogic confidential.
+#
+#  This software is provided to you pursuant to Software License Agreement
+#  (SLA) with Amlogic Inc ("Amlogic"). This software may be used
+#  only in accordance with the terms of this agreement.
+#
+#  Redistribution and use in source and binary forms, with or without
+#  modification is strictly prohibited without prior written permission from
+#  Amlogic.
+#
+#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#  OWNER 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, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+pwm-y = pwm_meson_v2.o pwm_${SOC}_plat.o
diff --git a/bl30/src_ao/demos/amlogic/driver/pwm/pwm_a5_plat.c b/bl30/src_ao/demos/amlogic/driver/pwm/pwm_a5_plat.c
new file mode 100644
index 0000000..87dcf5a
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/pwm/pwm_a5_plat.c
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2014-2018 Amlogic, Inc. All rights reserved.
+ *
+ * All information contained herein is Amlogic confidential.
+ *
+ * This software is provided to you pursuant to Software License Agreement
+ * (SLA) with Amlogic Inc ("Amlogic"). This software may be used
+ * only in accordance with the terms of this agreement.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification is strictly prohibited without prior written permission from
+ * Amlogic.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER 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, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * pwm s4 plat driver
+ */
+#include "FreeRTOS.h"
+#include <common.h>
+#include <pwm.h>
+#include "util.h"
+
+xPwmMesonChip_t meson_pwm_chip[] = {
+	{PWM_AB, PWMAB_PWM_A, 0, CLKCTRL_PWM_CLK_AB_CTRL},
+	{PWM_CD, PWMCD_PWM_A, 0, CLKCTRL_PWM_CLK_CD_CTRL},
+	{PWM_EF, PWMEF_PWM_A, 0, CLKCTRL_PWM_CLK_EF_CTRL},
+	{PWM_GH, PWMGH_PWM_A, 0, CLKCTRL_PWM_CLK_GH_CTRL},
+};
+
+/* VDDEE voltage table  volt must ascending */
+xPwmMesonVoltage_t vddee_table[] = {
+		{700, 0x140000},
+		{710, 0x120000},
+		{720, 0x110001},
+		{730, 0x100002},
+		{740, 0x0f0003},
+		{750, 0x0e0004},
+		{760, 0x0d0005},
+		{770, 0x0c0006},
+		{780, 0x0b0007},
+		{790, 0x0a0008},
+		{800, 0x090009},
+		{810, 0x08000a},
+		{820, 0x07000b},
+		{830, 0x06000c},
+		{840, 0x05000d},
+		{850, 0x04000e},
+		{860, 0x03000f},
+		{870, 0x020010},
+		{880, 0x010011},
+		{890, 0x12},
+		{900, 0x14},
+};
+
+/* VDDCPU voltage table  volt must ascending */
+xPwmMesonVoltage_t vddcpu_table[] = {
+		{690, 0x00240000},
+		{700, 0x00220000},
+		{710, 0x00210001},
+		{720, 0x00200002},
+		{730, 0x001f0003},
+		{740, 0x001e0004},
+		{750, 0x001d0005},
+		{760, 0x001c0006},
+		{770, 0x001b0007},
+		{780, 0x001a0008},
+		{790, 0x00190009},
+		{800, 0x0018000a},
+		{810, 0x0017000b},
+		{820, 0x0016000c},
+		{830, 0x0015000d},
+		{840, 0x0014000e},
+		{850, 0x0013000f},
+		{860, 0x00120010},
+		{870, 0x00110011},
+		{880, 0x00100012},
+		{890, 0x000f0013},
+		{900, 0x000e0014},
+		{910, 0x000d0015},
+		{920, 0x000c0016},
+		{930, 0x000b0017},
+		{940, 0x000a0018},
+		{950, 0x00090019},
+		{960, 0x0008001a},
+		{970, 0x0007001b},
+		{980, 0x0006001c},
+		{990, 0x0005001d},
+		{1000, 0x0004001e},
+		{1010, 0x0003001f},
+		{1020, 0x00020020},
+		{1030, 0x00010021},
+		{1040, 0x00000022},
+		{1050, 0x00000024},
+};
+
+/*
+ * todo: need processing here vddee pwmh vddcpu pwmj
+ * Different boards may use different pwm channels
+ */
+uint32_t prvMesonVoltToPwmChip(enum pwm_voltage_id voltage_id)
+{
+	switch (voltage_id) {
+	case VDDEE_VOLT:
+		return PWM_EF;
+
+	case VDDCPU_VOLT:
+		return PWM_EF;
+
+	default:
+		break;
+	}
+	return PWM_MUX;
+}
+
+/*
+ * todo: need processing here
+ * Different boards may use different pwm channels
+ */
+uint32_t prvMesonVoltToPwmChannel(enum pwm_voltage_id voltage_id)
+{
+	switch (voltage_id) {
+	case VDDEE_VOLT:
+		return MESON_PWM_0;
+
+	case VDDCPU_VOLT:
+		return MESON_PWM_1;
+
+	default:
+		break;
+	}
+	return MESON_PWM_2;
+}
+
+xPwmMesonVoltage_t *vPwmMesonGetVoltTable(uint32_t voltage_id)
+{
+	switch (voltage_id) {
+	case VDDEE_VOLT:
+		return vddee_table;
+
+	case VDDCPU_VOLT:
+		return vddcpu_table;
+
+	default:
+		break;
+	}
+	return NULL;
+}
+
+uint32_t vPwmMesonGetVoltTableSize(uint32_t voltage_id)
+{
+	switch (voltage_id) {
+	case VDDEE_VOLT:
+		return sizeof(vddee_table)/sizeof(xPwmMesonVoltage_t);
+
+	case VDDCPU_VOLT:
+		return sizeof(vddcpu_table)/sizeof(xPwmMesonVoltage_t);
+
+	default:
+		break;
+	}
+	return 0;
+}
+
+xPwmMesonChip_t *prvIdToPwmChip(uint32_t chip_id)
+{
+	if (chip_id >= PWM_MUX) {
+		iprintf("pwm chip id is invalid!\n");
+		return NULL;
+	}
+
+	return meson_pwm_chip + chip_id;
+}
+
+
diff --git a/bl30/src_ao/demos/amlogic/driver/pwm/pwm_meson_v2.c b/bl30/src_ao/demos/amlogic/driver/pwm/pwm_meson_v2.c
new file mode 100644
index 0000000..e5ae64b
--- /dev/null
+++ b/bl30/src_ao/demos/amlogic/driver/pwm/pwm_meson_v2.c
@@ -0,0 +1,805 @@
+/*
+ * Copyright (C) 2014-2018 Amlogic, Inc. All rights reserved.
+ *
+ * All information contained herein is Amlogic confidential.
+ *
+ * This software is provided to you pursuant to Software License Agreement
+ * (SLA) with Amlogic Inc ("Amlogic"). This software may be used
+ * only in accordance with the terms of this agreement.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification is strictly prohibited without prior written permission from
+ * Amlogic.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER 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, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * pwm driver
+ */
+#include "FreeRTOS.h"
+#include <common.h>
+#include <pwm.h>
+#include <util.h>
+#include <register.h>
+#include <task.h>
+
+#define pwm_readl(reg)				(*((volatile uint32_t *)(reg)))
+#define CLK_24M					24000000UL
+#define USEC_PER_SEC				1000000000ULL
+
+/*pwm register att*/
+typedef struct xPwmMesonRegs {
+	uint32_t  dar; /* A Duty Register */
+	uint32_t  dbr; /* B Duty Register */
+	uint32_t  miscr; /* misc Register */
+	uint32_t  dsr;/*DS Register*/
+	uint32_t  tr;/*times Register*/
+	uint32_t  da2r; /* A2 Duty Register */
+	uint32_t  db2r; /* B2 Duty Register */
+	uint32_t  br; /*Blink Register*/
+} xPwmMesonRegs_t;
+
+extern unsigned int xPortIsIsrContext(void);
+static void prvPwmEnterCritical(UBaseType_t *uxIsr)
+{
+	if (xPortIsIsrContext())
+		*uxIsr = taskENTER_CRITICAL_FROM_ISR();
+	else {
+		taskENTER_CRITICAL();
+		*uxIsr = 0;
+	}
+};
+
+static void prvPwmExitCritical(UBaseType_t uxSaveIsr)
+{
+	if (xPortIsIsrContext())
+		taskEXIT_CRITICAL_FROM_ISR(uxSaveIsr);
+	else {
+		taskEXIT_CRITICAL();
+		uxSaveIsr = 0;
+	}
+};
+
+static void prvPwmRegWrite(uint32_t addr, uint32_t mask, uint32_t val)
+{
+	UBaseType_t uxSavedIsr;
+
+	prvPwmEnterCritical(&uxSavedIsr);
+	REG32_UPDATE_BITS(addr, mask, val);
+	prvPwmExitCritical(uxSavedIsr);
+}
+
+static xPwmMesonRegs_t *prvDeviceToRegs(xPwmMesondevice_t *pwm)
+{
+	return (xPwmMesonRegs_t *) pwm->chip->addr;
+}
+
+static uint32_t vPwmMesonVolttoDuty(xPwmMesonVoltage_t *vtable,
+				 uint32_t vtable_size,
+				 uint32_t voltage_mv)
+{
+	uint32_t i;
+
+	if ((voltage_mv < vtable[0].Voltage_mv) ||
+	    (voltage_mv > vtable[vtable_size - 1].Voltage_mv)) {
+		iprintf("volt: %dmv out of set range [%dmv - %dmv]\n",
+			voltage_mv, vtable[0].Voltage_mv, vtable[vtable_size - 1].Voltage_mv);
+		return 0;
+	}
+
+	/* Get voltage up */
+	for (i = 0; i < vtable_size; i++)
+		if (voltage_mv <= vtable[i].Voltage_mv)
+			return vtable[i].Duty_reg;
+
+	return 0;
+}
+
+static int32_t vPwmMesonDutytoVolt(xPwmMesonVoltage_t *vtable,
+				 uint32_t vtable_size,
+				 uint32_t duty)
+{
+	uint32_t i;
+
+	for (i = 0; i < vtable_size; i++)
+		if (duty == vtable[i].Duty_reg)
+			return vtable[i].Voltage_mv;
+
+	return -1;
+}
+
+void vPwmMesonPwmDebug(xPwmMesondevice_t *pwm)
+{
+	uint32_t tmp = 0;
+	uint32_t i;
+	xPwmMesonRegs_t *reg = prvDeviceToRegs(pwm);
+
+	iprintf("pwm debug info chip_id = %d channel_id = %d addr = %p\n",
+		pwm->chip->chip_id, pwm->hwpwm, reg);
+
+	for (i = 0; i <= 7; i++) {
+		tmp = pwm_readl(&reg->dar + i);
+		iprintf("reg-> = 0x%x\n", tmp);
+	}
+}
+
+void vPwmConstantDisable(xPwmMesondevice_t *pwm)
+{
+	xPwmMesonRegs_t *reg = prvDeviceToRegs(pwm);
+
+	switch (pwm->hwpwm) {
+	case MESON_PWM_0:
+	case MESON_PWM_2:
+		prvPwmRegWrite((uint32_t)&reg->miscr, (1 << 28), 0);
+		break;
+
+	case MESON_PWM_1:
+	case MESON_PWM_3:
+		prvPwmRegWrite((uint32_t)&reg->miscr, (1 << 29), 0);
+		break;
+
+	default:
+		iprintf("%s Id:%d is invalid!\n", __func__, pwm->hwpwm);
+		break;
+	}
+}
+
+void vPwmConstantEnable(xPwmMesondevice_t *pwm)
+{
+	xPwmMesonRegs_t *reg = prvDeviceToRegs(pwm);
+
+	switch (pwm->hwpwm) {
+	case MESON_PWM_0:
+	case MESON_PWM_2:
+		prvPwmRegWrite((uint32_t)&reg->miscr, (1 << 28), (1 << 28));
+		break;
+
+	case MESON_PWM_1:
+	case MESON_PWM_3:
+		prvPwmRegWrite((uint32_t)&reg->miscr, (1 << 29), (1 << 29));
+		break;
+
+	default:
+		iprintf("%s Id:%d is invalid!\n", __func__, pwm->hwpwm);
+		break;
+	}
+}
+
+static uint32_t prvPwmGetPolarity(xPwmMesondevice_t *pwm)
+{
+	uint32_t tmp, val;
+	xPwmMesonRegs_t *reg = prvDeviceToRegs(pwm);
+
+	switch (pwm->hwpwm) {
+	case MESON_PWM_0:
+	case MESON_PWM_2:
+		val = 0x1 << 26;
+		break;
+
+	case MESON_PWM_1:
+	case MESON_PWM_3:
+		val = 0x1 << 27;
+		break;
+
+	default:
+		iprintf("%s Id:%d is invalid!\n", __func__, pwm->hwpwm);
+		return 0;
+	}
+
+	tmp = pwm_readl(&reg->miscr);
+	tmp = tmp & val;
+	if (tmp == 0)
+		return 0;
+	else
+		return 1;
+}
+
+static void prvPwmMesonClockSet(xPwmMesondevice_t *pwm)
+{
+	switch (pwm->hwpwm) {
+	case MESON_PWM_0:
+	case MESON_PWM_2:
+		prvPwmRegWrite(pwm->chip->clk_addr, ((0x3 << 9) | (0x1 << 8)), (0x1 << 8));
+		break;
+
+	case MESON_PWM_1:
+	case MESON_PWM_3:
+		prvPwmRegWrite(pwm->chip->clk_addr, ((0x3 << 25) | (0x1 << 24)), (0x1 << 24));
+		break;
+
+	default:
+		iprintf("%s Id:%d is invalid!\n", __func__, pwm->hwpwm);
+		break;
+	}
+}
+
+static int32_t prvPwmCalc(xPwmMesondevice_t *pwm, uint32_t duty, uint32_t period)
+{
+	uint32_t pre_div, cnt, duty_cnt;
+	uint32_t fin_freq, fin_ns;
+	int32_t inv;
+
+	inv = prvPwmGetPolarity(pwm);
+	if (inv)
+		duty = period - duty;
+
+	/*fin_freq = CLK_24M; */
+	fin_freq = 24000000;
+	fin_ns = USEC_PER_SEC / fin_freq;
+
+	for (pre_div = 0; pre_div < 0x7f; pre_div++) {
+		cnt = DIV_ROUND_CLOSEST(period, fin_ns * (pre_div + 1));
+		if (cnt <= 0xffff)
+			break;
+	}
+
+	if (pre_div == 0x7f) {
+		iprintf("unable to get period pre_div\n");
+		return -1;
+	}
+
+	if (duty == period) {
+		pwm->pwm_pre_div = pre_div;
+		pwm->pwm_hi = cnt - 2;
+		pwm->pwm_lo = 0;
+		vPwmConstantEnable(pwm);
+	} else if (duty == 0) {
+		pwm->pwm_pre_div = pre_div;
+		pwm->pwm_hi = 0;
+		pwm->pwm_lo = cnt - 2;
+		vPwmConstantEnable(pwm);
+	} else {
+		/* Then check is we can have the duty with the same pre_div */
+		duty_cnt = DIV_ROUND_CLOSEST(duty, fin_ns * (pre_div + 1));
+		if (duty_cnt > 0xffff) {
+			iprintf("unable to get duty cycle\n");
+			return -1;
+		}
+
+		pwm->pwm_pre_div = pre_div;
+
+		if (duty_cnt == 0) {
+			cnt = (cnt < 2 ? 2 : cnt);
+			pwm->pwm_hi = 0;
+			pwm->pwm_lo = cnt - 2;
+		} else if (cnt == duty_cnt) {
+			duty_cnt = (duty_cnt < 2 ? 2 : duty_cnt);
+			pwm->pwm_hi = duty_cnt - 2;
+			pwm->pwm_lo = 0;
+		} else {
+			pwm->pwm_hi = duty_cnt - 1;
+			pwm->pwm_lo = cnt - duty_cnt - 1;
+		}
+		vPwmConstantDisable(pwm);
+	}
+
+	return 0;
+}
+
+static void prvMesonConfig(xPwmMesondevice_t *pwm)
+{
+	xPwmMesonRegs_t *reg = prvDeviceToRegs(pwm);
+
+	switch (pwm->hwpwm) {
+	case MESON_PWM_0:
+		/*set div and clock enable */
+		if (pwm->chip->clk_addr) {
+			/* If using clktree */
+			prvPwmRegWrite(pwm->chip->clk_addr, ((0xff << 0) | (1 << 8)), ((pwm->pwm_pre_div << 0) | (1 << 8)));
+		} else {
+			prvPwmRegWrite((uint32_t)&reg->miscr, ((0x3 << 4) | (0x7f << 8) | (1 << 15)), (((pwm->pwm_pre_div << 8)) | (1 << 15)));
+		}
+
+		/*set duty */
+		prvPwmRegWrite((uint32_t)&reg->dar, 0xffffffff, ((pwm->pwm_hi << 16) | (pwm->pwm_lo)));
+		break;
+
+	case MESON_PWM_1:
+		/*set div and clock enable */
+		if (pwm->chip->clk_addr) {
+			prvPwmRegWrite(pwm->chip->clk_addr, ((0xff << 16) | (1 << 24)), ((pwm->pwm_pre_div << 16) | (1 << 24)));
+		} else {
+			prvPwmRegWrite((uint32_t)&reg->miscr, ((0x3 << 6) | (0x7f << 16) | (1 << 23)),  ((pwm->pwm_pre_div << 16) | (1 << 23)));
+		}
+
+		/*set duty */
+		prvPwmRegWrite((uint32_t)&reg->dbr, 0xffffffff, ((pwm->pwm_hi << 16) | (pwm->pwm_lo)));
+		break;
+
+	default:
+		iprintf("%s Id:%d is invalid!\n", __func__, pwm->hwpwm);
+		break;
+	}
+}
+
+static void prvMesonConfigExt(xPwmMesondevice_t *pwm)
+{
+	xPwmMesonRegs_t *reg = prvDeviceToRegs(pwm);
+
+	switch (pwm->hwpwm) {
+	case MESON_PWM_2:
+		/*set div and clock enable */
+		if (pwm->chip->clk_addr)
+			prvPwmRegWrite(pwm->chip->clk_addr, ((0xff << 0) | (1 << 8)), ((pwm->pwm_pre_div) | (1 << 8)));
+		else
+			prvPwmRegWrite((uint32_t)&reg->miscr, ((0x3 << 4) | (0x7f << 8) | (1 << 15)), ((pwm->pwm_pre_div << 8) | (1 << 15)));
+		/*set duty */
+		prvPwmRegWrite((uint32_t)&reg->da2r, 0xffffffff, ((pwm->pwm_hi << 16) | (pwm->pwm_lo)));
+		break;
+
+	case MESON_PWM_3:
+		/*set div and clock enable */
+		if (pwm->chip->clk_addr)
+			prvPwmRegWrite(pwm->chip->clk_addr, ((0xff << 16) | (1 << 24)), ((pwm->pwm_pre_div << 16) | (1 << 24)));
+		else
+			prvPwmRegWrite((uint32_t)&reg->miscr, ((0x3 << 6) | (0x7f << 16) | (1 << 23)), ((pwm->pwm_pre_div << 16) | (1 << 23)));
+		/*set duty */
+		prvPwmRegWrite((uint32_t)&reg->db2r, 0xffffffff, ((pwm->pwm_hi << 16) | (pwm->pwm_lo)));
+		break;
+	default:
+		iprintf("%s Id:%d is invalid!\n", __func__, pwm->hwpwm);
+		break;
+	}
+}
+
+int32_t xPwmMesonConfig(xPwmMesondevice_t *pwm, uint32_t duty_ns,
+			uint32_t period_ns)
+{
+	int32_t tmp;
+
+	if ((duty_ns > period_ns) || (!period_ns)) {
+		iprintf("Not available duty_ns period_ns !\n");
+		return -1;
+	}
+
+	/* If using clktree */
+	if (pwm->chip->clk_addr)
+		prvPwmMesonClockSet(pwm);
+	tmp = prvPwmCalc(pwm, duty_ns, period_ns);
+	if (tmp != 0) {
+		iprintf("calc pwm freq err error");
+	}
+
+	switch (pwm->hwpwm) {
+	case MESON_PWM_0:
+	case MESON_PWM_1:
+		prvMesonConfig(pwm);
+		break;
+
+	case MESON_PWM_2:
+	case MESON_PWM_3:
+		prvMesonConfigExt(pwm);
+		break;
+
+	default:
+		iprintf("%s Id:%d is invalid!\n", __func__, pwm->hwpwm);
+		break;
+	}
+
+	return 0;
+}
+
+void vPwmMesonDisable(xPwmMesondevice_t *pwm)
+{
+	xPwmMesonRegs_t *reg = prvDeviceToRegs(pwm);
+
+	switch (pwm->hwpwm) {
+	case MESON_PWM_0:
+		prvPwmRegWrite((uint32_t)&reg->miscr, (1 << 0), 0);
+		break;
+
+	case MESON_PWM_1:
+		prvPwmRegWrite((uint32_t)&reg->miscr, (1 << 1), 0);
+		break;
+
+	case MESON_PWM_2:
+		prvPwmRegWrite((uint32_t)&reg->miscr, (1 << 25), 0);
+		break;
+
+	case MESON_PWM_3:
+		prvPwmRegWrite((uint32_t)&reg->miscr, (1 << 24), 0);
+		break;
+
+	default:
+		iprintf("%s Id:%d is invalid!\n", __func__, pwm->hwpwm);
+		break;
+	}
+	return;
+}
+
+/**
+ * pwm_meson_enable() - enable pwm output
+ * @pwm: pwm channel to choose
+ */
+void vPwmMesonEnable(xPwmMesondevice_t *pwm)
+{
+	xPwmMesonRegs_t *reg = prvDeviceToRegs(pwm);
+
+	switch (pwm->hwpwm) {
+	case MESON_PWM_0:
+		prvPwmRegWrite((uint32_t)&reg->miscr, (1 << 0), (1 << 0));
+		break;
+
+	case MESON_PWM_1:
+		prvPwmRegWrite((uint32_t)&reg->miscr, (1 << 1), (1 << 1));
+		break;
+
+	case MESON_PWM_2:
+		prvPwmRegWrite((uint32_t)&reg->miscr, (1 << 25), (1 << 25));
+		break;
+
+	case MESON_PWM_3:
+		prvPwmRegWrite((uint32_t)&reg->miscr, (1 << 24), (1 << 24));
+		break;
+
+	default:
+		iprintf("%s Id:%d is invalid!\n", __func__, pwm->hwpwm);
+		break;
+	}
+}
+
+void vPwmMesonSetTimes(xPwmMesondevice_t *pwm, uint32_t times)
+{
+	xPwmMesonRegs_t *reg = prvDeviceToRegs(pwm);
+
+	times--;
+	switch (pwm->hwpwm) {
+	case MESON_PWM_0:
+		prvPwmRegWrite((uint32_t)&reg->tr, (0xff << 24), (times << 24));
+		break;
+
+	case MESON_PWM_1:
+		prvPwmRegWrite((uint32_t)&reg->tr, (0xff << 8), (times << 8));
+		break;
+
+	case MESON_PWM_2:
+		prvPwmRegWrite((uint32_t)&reg->tr, (0xff << 16), (times << 16));
+		break;
+
+	case MESON_PWM_3:
+		prvPwmRegWrite((uint32_t)&reg->tr, (0xff << 0), (times << 0));
+		break;
+
+	default:
+		iprintf("%s Id:%d is invalid!\n", __func__, pwm->hwpwm);
+		break;
+	}
+}
+
+void vPwmMesonSetBlinkTimes(xPwmMesondevice_t *pwm, uint32_t times)
+{
+	xPwmMesonRegs_t *reg = prvDeviceToRegs(pwm);
+
+	times--;
+	switch (pwm->hwpwm) {
+	case MESON_PWM_0:
+		prvPwmRegWrite((uint32_t)&reg->br, 0xf, times);
+		break;
+
+	case MESON_PWM_1:
+		prvPwmRegWrite((uint32_t)&reg->br, (0xf << 4), (times << 4));
+		break;
+
+	default:
+		iprintf("%s Id:%d is invalid!\n", __func__, pwm->hwpwm);
+		break;
+	}
+}
+
+void vPwmMesonBlinkEnable(xPwmMesondevice_t *pwm)
+{
+	xPwmMesonRegs_t *reg = prvDeviceToRegs(pwm);
+
+	switch (pwm->hwpwm) {
+	case MESON_PWM_0:
+		prvPwmRegWrite((uint32_t)&reg->br, (1 << 8), (1 << 8));
+		break;
+
+	case MESON_PWM_1:
+		prvPwmRegWrite((uint32_t)&reg->br, (1 << 9), (1 << 9));
+		break;
+
+	default:
+		iprintf("%s Id:%d is invalid!\n", __func__, pwm->hwpwm);
+		break;
+	}
+}
+
+void vPwmMesonBlinkDisable(xPwmMesondevice_t *pwm)
+{
+	xPwmMesonRegs_t *reg = prvDeviceToRegs(pwm);
+
+	switch (pwm->hwpwm) {
+	case MESON_PWM_0:
+		prvPwmRegWrite((uint32_t)&reg->br, (1 << 8), (0 << 8));
+		break;
+
+	case MESON_PWM_1:
+		prvPwmRegWrite((uint32_t)&reg->br, (1 << 9), (0 << 9));
+		break;
+
+	default:
+		iprintf("%s Id:%d is invalid!\n", __func__, pwm->hwpwm);
+		break;
+	}
+}
+
+int32_t xPwmMesonIsBlinkComplete(xPwmMesondevice_t *pwm)
+{
+	xPwmMesonRegs_t *reg = prvDeviceToRegs(pwm);
+	uint32_t a1, val;
+
+	switch (pwm->hwpwm) {
+	case MESON_PWM_0:
+		val = 0x1 << 0;
+		break;
+
+	case MESON_PWM_1:
+		val = 0x1 << 1;
+		break;