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, ®, &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, ®, &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, ®, &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, ®, &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, ®, &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, ®, &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, ×);
+ 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(®->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)®->miscr, (1 << 28), 0);
+ break;
+
+ case MESON_PWM_1:
+ case MESON_PWM_3:
+ prvPwmRegWrite((uint32_t)®->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)®->miscr, (1 << 28), (1 << 28));
+ break;
+
+ case MESON_PWM_1:
+ case MESON_PWM_3:
+ prvPwmRegWrite((uint32_t)®->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(®->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)®->miscr, ((0x3 << 4) | (0x7f << 8) | (1 << 15)), (((pwm->pwm_pre_div << 8)) | (1 << 15)));
+ }
+
+ /*set duty */
+ prvPwmRegWrite((uint32_t)®->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)®->miscr, ((0x3 << 6) | (0x7f << 16) | (1 << 23)), ((pwm->pwm_pre_div << 16) | (1 << 23)));
+ }
+
+ /*set duty */
+ prvPwmRegWrite((uint32_t)®->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)®->miscr, ((0x3 << 4) | (0x7f << 8) | (1 << 15)), ((pwm->pwm_pre_div << 8) | (1 << 15)));
+ /*set duty */
+ prvPwmRegWrite((uint32_t)®->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)®->miscr, ((0x3 << 6) | (0x7f << 16) | (1 << 23)), ((pwm->pwm_pre_div << 16) | (1 << 23)));
+ /*set duty */
+ prvPwmRegWrite((uint32_t)®->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)®->miscr, (1 << 0), 0);
+ break;
+
+ case MESON_PWM_1:
+ prvPwmRegWrite((uint32_t)®->miscr, (1 << 1), 0);
+ break;
+
+ case MESON_PWM_2:
+ prvPwmRegWrite((uint32_t)®->miscr, (1 << 25), 0);
+ break;
+
+ case MESON_PWM_3:
+ prvPwmRegWrite((uint32_t)®->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)®->miscr, (1 << 0), (1 << 0));
+ break;
+
+ case MESON_PWM_1:
+ prvPwmRegWrite((uint32_t)®->miscr, (1 << 1), (1 << 1));
+ break;
+
+ case MESON_PWM_2:
+ prvPwmRegWrite((uint32_t)®->miscr, (1 << 25), (1 << 25));
+ break;
+
+ case MESON_PWM_3:
+ prvPwmRegWrite((uint32_t)®->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)®->tr, (0xff << 24), (times << 24));
+ break;
+
+ case MESON_PWM_1:
+ prvPwmRegWrite((uint32_t)®->tr, (0xff << 8), (times << 8));
+ break;
+
+ case MESON_PWM_2:
+ prvPwmRegWrite((uint32_t)®->tr, (0xff << 16), (times << 16));
+ break;
+
+ case MESON_PWM_3:
+ prvPwmRegWrite((uint32_t)®->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)®->br, 0xf, times);
+ break;
+
+ case MESON_PWM_1:
+ prvPwmRegWrite((uint32_t)®->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)®->br, (1 << 8), (1 << 8));
+ break;
+
+ case MESON_PWM_1:
+ prvPwmRegWrite((uint32_t)®->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)®->br, (1 << 8), (0 << 8));
+ break;
+
+ case MESON_PWM_1:
+ prvPwmRegWrite((uint32_t)®->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;