Browse Source

Linux_SDK_V0.9.5

thead_admin 1 year ago
commit
ea940b0b08
47 changed files with 21795 additions and 0 deletions
  1. 27 0
      .gitignore
  2. 674 0
      COPYING
  3. 75 0
      Makefile
  4. 0 0
      README.md
  5. 142 0
      linux/dwl/dwl_defs.h
  6. 88 0
      linux/memalloc/Makefile
  7. 44 0
      linux/memalloc/README
  8. 22 0
      linux/memalloc/build_for_pcie.sh
  9. 369 0
      linux/memalloc/memalloc.c
  10. 88 0
      linux/memalloc/memalloc.h
  11. 99 0
      linux/memalloc/memalloc_load.sh
  12. 207 0
      linux/memalloc/testbench_memalloc.c
  13. 88 0
      linux/subsys_driver/Makefile
  14. 49 0
      linux/subsys_driver/README
  15. 220 0
      linux/subsys_driver/bidirect_list.c
  16. 107 0
      linux/subsys_driver/bidirect_list.h
  17. 10 0
      linux/subsys_driver/build_for_mpcore.sh
  18. 10 0
      linux/subsys_driver/build_for_socle.sh
  19. 10 0
      linux/subsys_driver/build_for_vexpress.sh
  20. 43 0
      linux/subsys_driver/driver_load.sh
  21. 43 0
      linux/subsys_driver/driver_load_sc.sh
  22. 255 0
      linux/subsys_driver/freertos/dev_common_freertos.h
  23. 2065 0
      linux/subsys_driver/freertos/hantro_dec_freertos.c
  24. 3843 0
      linux/subsys_driver/freertos/hantro_vcmd_freertos.c
  25. 86 0
      linux/subsys_driver/freertos/io_tools.c
  26. 89 0
      linux/subsys_driver/freertos/io_tools.h
  27. 484 0
      linux/subsys_driver/freertos/memalloc_freertos.c
  28. 104 0
      linux/subsys_driver/freertos/memalloc_freertos.h
  29. 192 0
      linux/subsys_driver/freertos/subsys_freertos.c
  30. 151 0
      linux/subsys_driver/freertos/user_freertos.c
  31. 79 0
      linux/subsys_driver/freertos/user_freertos.h
  32. 88 0
      linux/subsys_driver/hantro_axife.c
  33. 2973 0
      linux/subsys_driver/hantro_dec.c
  34. 1869 0
      linux/subsys_driver/hantro_mmu.c
  35. 4033 0
      linux/subsys_driver/hantro_vcmd.c
  36. 63 0
      linux/subsys_driver/hantroaxife.h
  37. 199 0
      linux/subsys_driver/hantrodec.h
  38. 109 0
      linux/subsys_driver/hantrommu.h
  39. 192 0
      linux/subsys_driver/hantrovcmd.h
  40. 1286 0
      linux/subsys_driver/kernel_allocator.c
  41. 121 0
      linux/subsys_driver/kernel_allocator.h
  42. 203 0
      linux/subsys_driver/subsys.c
  43. 203 0
      linux/subsys_driver/subsys.h
  44. 156 0
      linux/subsys_driver/vcmdregisterenum.h
  45. 156 0
      linux/subsys_driver/vcmdregistertable.h
  46. 148 0
      linux/subsys_driver/vcmdswhwregisters.c
  47. 233 0
      linux/subsys_driver/vcmdswhwregisters.h

+ 27 - 0
.gitignore

@@ -0,0 +1,27 @@
+/.auto.deps
+/.config.cmd
+/.config.old
+/..config.tmp
+/.config
+*.tmp
+*.depend
+*.o
+*.a
+*.o.d
+*.o.cmd
+*.a.cmd
+*.ko.cmd
+*.ko
+*.mod
+*.mod.c
+*.mod.cmd
+*.order
+*.orig
+*.symvers.cmd
+*.order.cmd
+Module.symvers
+out/
+output/
+obj/
+dependencies/
+.vscode/

+ 674 - 0
COPYING

@@ -0,0 +1,674 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+    <program>  Copyright (C) <year>  <name of author>
+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+  The GNU General Public License does not permit incorporating your program
+into proprietary programs.  If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.  But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.

+ 75 - 0
Makefile

@@ -0,0 +1,75 @@
+##
+ # Copyright (C) 2020 Alibaba Group Holding Limited
+##
+
+DIR_TARGET_KO  =bsp/vdec/ko
+
+MODULE_NAME=VDEC
+BUILD_LOG_START="\033[47;30m>>> $(MODULE_NAME) $@ begin\033[0m"
+BUILD_LOG_END  ="\033[47;30m<<< $(MODULE_NAME) $@ end\033[0m"
+
+#
+# Do a parallel build with multiple jobs, based on the number of CPUs online
+# in this system: 'make -j8' on a 8-CPU system, etc.
+#
+# (To override it, run 'make JOBS=1' and similar.)
+#
+ifeq ($(JOBS),)
+  JOBS := $(shell grep -c ^processor /proc/cpuinfo 2>/dev/null)
+  ifeq ($(JOBS),)
+    JOBS := 1
+  endif
+endif
+
+all:    driver install_local_output
+.PHONY: driver install_local_output install_prepare clean_driver clean_output clean
+
+info:
+	@echo $(BUILD_LOG_START)
+	@echo "  ====== Build Info from repo project ======"
+	@echo "    BUILDROOT_DIR="$(BUILDROOT_DIR)
+	@echo "    CROSS_COMPILE="$(CROSS_COMPILE)
+	@echo "    LINUX_DIR="$(LINUX_DIR)
+	@echo "    ARCH="$(ARCH)
+	@echo "    BOARD_NAME="$(BOARD_NAME)
+	@echo "    KERNEL_ID="$(KERNELVERSION)
+	@echo "    KERNEL_DIR="$(LINUX_DIR)
+	@echo "    INSTALL_DIR_SDK="$(INSTALL_DIR_SDK)
+	@echo "  ====== Build configuration by settings ======"
+	@echo "    JOBS="$(JOBS)
+	@echo $(BUILD_LOG_END)
+
+driver:
+	@echo $(BUILD_LOG_START)
+	make -C linux/subsys_driver KDIR=$(LINUX_DIR) CROSS=$(CROSS_COMPILE) ARCH=$(ARCH)
+	make -C linux/memalloc KDIR=$(LINUX_DIR) CROSS=$(CROSS_COMPILE) ARCH=$(ARCH)
+	@echo $(BUILD_LOG_END)
+
+clean_driver:
+	@echo $(BUILD_LOG_START)
+	make -C linux/subsys_driver clean
+	make -C linux/memalloc clean
+	@echo $(BUILD_LOG_END)
+
+install_prepare:
+	mkdir -p ./output/rootfs/$(DIR_TARGET_KO)
+
+install_local_output: driver install_prepare
+	@echo $(BUILD_LOG_START)
+	find ./linux -name "*.ko" | xargs -i cp -f {} ./output/rootfs/$(DIR_TARGET_KO)
+	cp -f ./linux/subsys_driver/driver_load.sh ./output/rootfs/$(DIR_TARGET_KO)
+	cp -f ./linux/memalloc/memalloc_load.sh ./output/rootfs/$(DIR_TARGET_KO)
+	chmod +x ./output/rootfs/$(DIR_TARGET_KO)/*.sh
+	echo "hantrodec" > ./output/rootfs/$(DIR_TARGET_KO)/vc8000d.conf
+	@if [ `command -v tree` != "" ]; then \
+	    tree ./output/rootfs;             \
+	fi
+	@echo $(BUILD_LOG_END)
+
+clean_output:
+	@echo $(BUILD_LOG_START)
+	rm -rf ./output
+	@echo $(BUILD_LOG_END)
+
+clean: clean_output clean_driver
+

+ 0 - 0
README.md


+ 142 - 0
linux/dwl/dwl_defs.h

@@ -0,0 +1,142 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2021 VERISILICON
+*
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2021 VERISILICON
+*
+*    This program is free software; you can redistribute it and/or
+*    modify it under the terms of the GNU General Public License
+*    as published by the Free Software Foundation; either version 2
+*    of the License, or (at your option) any later version.
+*
+*    This program is distributed in the hope that it will be useful,
+*    but WITHOUT ANY WARRANTY; without even the implied warranty of
+*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*    GNU General Public License for more details.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+#ifndef SOFTWARE_LINUX_DWL_DWL_DEFS_H_
+#define SOFTWARE_LINUX_DWL_DWL_DEFS_H_
+
+#define DWL_MPEG2_E      31 /* 1 bit  */
+#define DWL_VC1_E        29 /* 2 bits */
+#define DWL_JPEG_E       28 /* 1 bit  */
+#define DWL_HJPEG_E      17 /* 1 bit  */
+#define DWL_AV1_E        16 /* 1 bit  */
+#define DWL_MPEG4_E      26 /* 2 bits */
+#define DWL_H264_E       24 /* 2 bits */
+#define DWL_H264HIGH10_E 20 /* 1 bits */
+#define DWL_AVS2_E       18 /* 2 bits */
+#define DWL_VP6_E        23 /* 1 bit  */
+#define DWL_RV_E         26 /* 2 bits */
+#define DWL_VP8_E        23 /* 1 bit  */
+#define DWL_VP7_E        24 /* 1 bit  */
+#define DWL_WEBP_E       19 /* 1 bit  */
+#define DWL_AVS_E        22 /* 1 bit  */
+#define DWL_G1_PP_E      16 /* 1 bit  */
+#define DWL_G2_PP_E      31 /* 1 bit  */
+#define DWL_PP_E         31 /* 1 bit  */
+#define DWL_HEVC_E       26 /* 3 bits */
+#define DWL_VP9_E        29 /* 3 bits */
+
+#define DWL_H264_PIPELINE_E 31 /* 1 bit */
+#define DWL_JPEG_PIPELINE_E 30 /* 1 bit */
+
+#define DWL_G2_HEVC_E    0  /* 1 bits */
+#define DWL_G2_VP9_E     1  /* 1 bits */
+#define DWL_G2_RFC_E        2  /* 1 bits */
+#define DWL_RFC_E        17  /* 2 bits */
+#define DWL_G2_DS_E         3  /* 1 bits */
+#define DWL_DS_E         28  /* 3 bits */
+#define DWL_HEVC_VER     8  /* 4 bits */
+#define DWL_VP9_PROFILE  12 /* 3 bits */
+#define DWL_RING_E       16 /* 1 bits */
+
+#define HANTRODEC_IRQ_STAT_DEC       1
+#define HANTRODEC_IRQ_STAT_DEC_OFF   (HANTRODEC_IRQ_STAT_DEC * 4)
+#define BIGOCEAN_IRQ_STAT_DEC       2
+#define BIGOCEAN_IRQ_STAT_DEC_OFF   (HANTRODEC_IRQ_STAT_DEC * 4)
+
+#define HANTRODECPP_SYNTH_CFG        60
+#define HANTRODECPP_SYNTH_CFG_OFF    (HANTRODECPP_SYNTH_CFG * 4)
+#define HANTRODEC_SYNTH_CFG          50
+#define HANTRODEC_SYNTH_CFG_OFF      (HANTRODEC_SYNTH_CFG * 4)
+#define HANTRODEC_SYNTH_CFG_2        54
+#define HANTRODEC_SYNTH_CFG_2_OFF    (HANTRODEC_SYNTH_CFG_2 * 4)
+#define HANTRODEC_SYNTH_CFG_3        56
+#define HANTRODEC_SYNTH_CFG_3_OFF    (HANTRODEC_SYNTH_CFG_3 * 4)
+#define HANTRODEC_CFG_STAT           23
+#define HANTRODEC_CFG_STAT_OFF       (HANTRODEC_CFG_STAT * 4)
+#define HANTRODECPP_CFG_STAT         260
+#define HANTRODECPP_CFG_STAT_OFF     (HANTRODECPP_CFG_STAT * 4)
+
+
+#define HANTRODEC_DEC_E              0x01
+#define HANTRODEC_PP_E               0x01
+#define HANTRODEC_DEC_ABORT          0x20
+#define HANTRODEC_DEC_IRQ_DISABLE    0x10
+#define HANTRODEC_DEC_IRQ            0x100
+
+/* Legacy from G1 */
+#define HANTRO_IRQ_STAT_DEC          1
+#define HANTRO_IRQ_STAT_DEC_OFF      (HANTRO_IRQ_STAT_DEC * 4)
+#define HANTRO_IRQ_STAT_PP           60
+#define HANTRO_IRQ_STAT_PP_OFF       (HANTRO_IRQ_STAT_PP * 4)
+
+#define HANTROPP_SYNTH_CFG           100
+#define HANTROPP_SYNTH_CFG_OFF       (HANTROPP_SYNTH_CFG * 4)
+#define HANTRODEC_SYNTH_CFG          50
+#define HANTRODEC_SYNTH_CFG_OFF      (HANTRODEC_SYNTH_CFG * 4)
+#define HANTRODEC_SYNTH_CFG_2        54
+#define HANTRODEC_SYNTH_CFG_2_OFF    (HANTRODEC_SYNTH_CFG_2 * 4)
+
+/* VC8000D HW build id */
+#define HANTRODEC_HW_BUILD_ID        309
+#define HANTRODEC_HW_BUILD_ID_OFF    (HANTRODEC_HW_BUILD_ID * 4)
+
+#define HANTRO_DEC_E                 0x01
+#define HANTRO_PP_E                  0x01
+#define HANTRO_DEC_ABORT             0x20
+#define HANTRO_DEC_IRQ_DISABLE       0x10
+#define HANTRO_PP_IRQ_DISABLE        0x10
+#define HANTRO_DEC_IRQ               0x100
+#define HANTRO_PP_IRQ                0x100
+
+#endif /* SOFTWARE_LINUX_DWL_DWL_DEFS_H_ */

+ 88 - 0
linux/memalloc/Makefile

@@ -0,0 +1,88 @@
+#############################################################################
+#
+#    The MIT License (MIT)
+#
+#    Copyright (c) 2014 - 2021 VERISILICON
+#
+#    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.
+#
+#############################################################################
+#
+#    The GPL License (GPL)
+#
+#    Copyright (C) 2014 - 2021 VERISILICON
+#
+#    This program is free software; you can redistribute it and/or
+#    modify it under the terms of the GNU General Public License
+#    as published by the Free Software Foundation; either version 2
+#    of the License, or (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program; if not, write to the Free Software Foundation,
+#    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+#############################################################################
+#
+#    Note: This software is released under dual MIT and GPL licenses. A
+#    recipient may use this file under the terms of either the MIT license or
+#    GPL License. If you wish to use only one license not the other, you can
+#    indicate your decision by deleting one of the above license notices in your
+#    version of this file.
+#
+##############################################################################
+
+ifeq ($(DEBUG),y)
+  DEBFLAGS = -O -g -DMEMALLOC_DEBUG
+else
+  DEBFLAGS = -O2
+endif
+
+# base address and size (MB) for linear memory allocation
+HLINA_START := 0x02000000
+HLINA_SIZE  := 96
+
+EXTRA_CFLAGS += $(DEBFLAGS)
+EXTRA_CFLAGS += -DHLINA_START_ADDRESS=$(HLINA_START) -DHLINA_SIZE=$(HLINA_SIZE)
+
+ifneq ($(KERNELRELEASE),)
+# recursive call from kernel build system
+
+memalloc-objs :=
+obj-m         += memalloc.o
+
+else
+
+#KDIR := /export/Testing/Board_Version_Control/SW_Common/SOCLE_MDK-3D/openlinux/2.6.29/v0_5/android_linux-2.6.29
+KDIR := /lib/modules/3.2.0-36-generic/build
+
+PWD  := $(shell pwd)
+
+all:
+	$(MAKE) -C $(KDIR) M=$(PWD) modules
+
+endif
+
+clean:
+	rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions
+	rm -rf modules.order Module.symvers

+ 44 - 0
linux/memalloc/README

@@ -0,0 +1,44 @@
+==============================================================================
+                            USAGE
+==============================================================================
+
+./memalloc_load.sh
+
+===============================================================================
+                            What is memalloc?
+===============================================================================
+
+memalloc is a test environment specific memory allocation kernel driver.
+It uses memory left outside linux memory management, divides it into chunks and
+gives base addresses to processes for these chunks(= a block of memory).
+
+It has been written for test memory purposes for a very specific test
+environment and nothing more.
+
+===============================================================================
+                    Loading the memalloc kernel driver
+===============================================================================
+
+1. compile the kernel driver in software/linux/memalloc
+> make
+
+2. For testing load kernel driver with:
+>./memalloc_load.sh
+
+...or if you want to specify the max size in MB of linear memory:
+>./memalloc_load.sh alloc_size=400
+
+...or if you want to specify the base address of linear memory:
+>./memalloc_load.sh alloc_base=0x42000000
+
+...or both:
+>./memalloc_load.sh alloc_base=0x42000000 alloc_size=400
+
+3. Debugging:
+the device node should show up in the the directory /dev
+The device should show up in the list /proc/devices
+> ls /dev
+> cat /proc/devices
+Kernel messages can be viewed with
+> dmesg
+More kernel debug prints can be enabled in the Makefile

+ 22 - 0
linux/memalloc/build_for_pcie.sh

@@ -0,0 +1,22 @@
+#!/bin/sh
+
+
+KVER=$(uname -r)
+KDIR=/lib/modules/$KVER/build
+
+HLINA_START=0x30000000
+HLINA_SIZE=512              #Size in megabytes
+
+HLINA_END=$(($HLINA_START + $HLINA_SIZE*1024*1024))
+
+echo
+echo "KDIR=$KDIR"
+echo "CROSS=$CROSS"
+echo
+echo   "Linear memory base   = $HLINA_START"
+printf "Linear top-of-memory = 0x%x\n" $HLINA_END
+echo   "Linear memory size   = ${HLINA_SIZE}MB"
+echo
+
+make KDIR=$KDIR CROSS=$CROSS HLINA_START=${HLINA_START}U HLINA_SIZE=${HLINA_SIZE}U $1
+exit $?

+ 369 - 0
linux/memalloc/memalloc.c

@@ -0,0 +1,369 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2021 VERISILICON
+*
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2021 VERISILICON
+*
+*    This program is free software; you can redistribute it and/or
+*    modify it under the terms of the GNU General Public License
+*    as published by the Free Software Foundation; either version 2
+*    of the License, or (at your option) any later version.
+*
+*    This program is distributed in the hope that it will be useful,
+*    but WITHOUT ANY WARRANTY; without even the implied warranty of
+*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*    GNU General Public License for more details.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+#include <asm/io.h>
+#include <linux/uaccess.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/version.h>
+#include <linux/vmalloc.h>
+
+#include "memalloc.h"
+
+#ifndef HLINA_START_ADDRESS
+#define HLINA_START_ADDRESS 0x1e0000000
+#endif
+
+#ifndef HLINA_SIZE
+#define HLINA_SIZE 512
+#endif
+
+#ifndef HLINA_TRANSL_OFFSET
+#define HLINA_TRANSL_OFFSET 0x0
+#endif
+
+/* the size of chunk in MEMALLOC_DYNAMIC */
+#define CHUNK_SIZE (PAGE_SIZE * 4)
+
+/* memory size in MBs for MEMALLOC_DYNAMIC */
+unsigned long alloc_size = HLINA_SIZE;
+unsigned long alloc_base = HLINA_START_ADDRESS;
+
+/* user space SW will substract HLINA_TRANSL_OFFSET from the bus address
+ * and decoder HW will use the result as the address translated base
+ * address. The SW needs the original host memory bus address for memory
+ * mapping to virtual address. */
+unsigned long addr_transl = HLINA_TRANSL_OFFSET;
+
+static int memalloc_major = 0; /* dynamic */
+
+/* module_param(name, type, perm) */
+module_param(alloc_size, ulong, 0);
+module_param(alloc_base, ulong, 0);
+module_param(addr_transl, ulong, 0);
+
+static DEFINE_SPINLOCK(mem_lock);
+
+typedef struct hlinc {
+  u64 bus_address;
+  u32 chunks_reserved;
+  const struct file *filp; /* Client that allocated this chunk */
+} hlina_chunk;
+
+static hlina_chunk *hlina_chunks = NULL;
+static size_t chunks = 0;
+
+static int AllocMemory(unsigned long *busaddr, unsigned int size,
+                       const struct file *filp);
+static int FreeMemory(unsigned long busaddr, const struct file *filp);
+static void ResetMems(void);
+
+static long memalloc_ioctl(struct file *filp, unsigned int cmd,
+                           unsigned long arg) {
+  int ret = 0;
+  MemallocParams memparams;
+  unsigned long busaddr;
+
+  PDEBUG("ioctl cmd 0x%08x\n", cmd);
+
+  /*
+   * extract the type and number bitfields, and don't decode
+   * wrong cmds: return ENOTTY (inappropriate ioctl) before access_ok()
+   */
+  if (_IOC_TYPE(cmd) != MEMALLOC_IOC_MAGIC) return -ENOTTY;
+  if (_IOC_NR(cmd) > MEMALLOC_IOC_MAXNR) return -ENOTTY;
+
+  if (_IOC_DIR(cmd) & _IOC_READ)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,0,0)
+    ret = !access_ok(arg, _IOC_SIZE(cmd));
+#else
+    ret = !access_ok(VERIFY_WRITE, arg, _IOC_SIZE(cmd));
+#endif
+  else if (_IOC_DIR(cmd) & _IOC_WRITE)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,0,0)
+    ret = !access_ok(arg, _IOC_SIZE(cmd));
+#else
+    ret = !access_ok(VERIFY_READ, arg, _IOC_SIZE(cmd));
+#endif
+  if (ret) return -EFAULT;
+
+  switch (cmd) {
+  case MEMALLOC_IOCHARDRESET:
+    PDEBUG("HARDRESET\n");
+    ResetMems();
+    break;
+  case MEMALLOC_IOCXGETBUFFER:
+    PDEBUG("GETBUFFER");
+
+    ret = copy_from_user(&memparams, (MemallocParams *)arg,
+                         sizeof(MemallocParams));
+    if (ret) break;
+
+    ret = AllocMemory(&memparams.bus_address, memparams.size, filp);
+
+    memparams.translation_offset = addr_transl;
+
+    ret |= copy_to_user((MemallocParams *)arg, &memparams,
+                        sizeof(MemallocParams));
+
+    break;
+  case MEMALLOC_IOCSFREEBUFFER:
+    PDEBUG("FREEBUFFER\n");
+
+    __get_user(busaddr, (unsigned long *)arg);
+    ret = FreeMemory(busaddr, filp);
+    break;
+  }
+
+  return ret ? -EFAULT : 0;
+}
+
+static int memalloc_open(struct inode *inode, struct file *filp) {
+
+  PDEBUG("dev opened\n");
+  return 0;
+}
+
+static int memalloc_release(struct inode *inode, struct file *filp) {
+  int i = 0;
+
+  spin_lock(&mem_lock);
+
+  for (i = 0; i < chunks; i++) {
+    if (hlina_chunks[i].filp == filp) {
+      printk(KERN_WARNING "memalloc: Found unfreed memory at release time!\n");
+
+      hlina_chunks[i].filp = NULL;
+      hlina_chunks[i].chunks_reserved = 0;
+    }
+  }
+
+  spin_unlock(&mem_lock);
+  PDEBUG("dev closed\n");
+  return 0;
+}
+
+void __exit memalloc_cleanup(void) {
+  if (hlina_chunks != NULL) vfree(hlina_chunks);
+
+  unregister_chrdev(memalloc_major, "memalloc");
+
+  PDEBUG("module removed\n");
+  return;
+}
+
+/* VFS methods */
+static struct file_operations memalloc_fops = {
+  .owner = THIS_MODULE,
+  .open = memalloc_open,
+  .release = memalloc_release,
+  .unlocked_ioctl = memalloc_ioctl
+};
+
+int __init memalloc_init(void) {
+  int result;
+
+  PDEBUG("module init\n");
+  printk("memalloc: Linear Memory Allocator\n");
+  printk("memalloc: Linear memory base = 0x%llx\n", alloc_base);
+
+  chunks = (alloc_size * 1024 * 1024) / CHUNK_SIZE;
+
+  printk(KERN_INFO
+         "memalloc: Total size %ld MB; %d chunks"
+         " of size %lu\n",
+         alloc_size, (int)chunks, CHUNK_SIZE);
+
+  hlina_chunks = (hlina_chunk *)vmalloc(chunks * sizeof(hlina_chunk));
+  if (hlina_chunks == NULL) {
+    printk(KERN_ERR "memalloc: cannot allocate hlina_chunks\n");
+    result = -ENOMEM;
+    goto err;
+  }
+
+  result = register_chrdev(memalloc_major, "memalloc", &memalloc_fops);
+  if (result < 0) {
+    PDEBUG("memalloc: unable to get major %d\n", memalloc_major);
+    goto err;
+  } else if (result != 0) {/* this is for dynamic major */
+    memalloc_major = result;
+  }
+
+  ResetMems();
+
+  return 0;
+
+err:
+  if (hlina_chunks != NULL) vfree(hlina_chunks);
+
+  return result;
+}
+
+/* Cycle through the buffers we have, give the first free one */
+static int AllocMemory(unsigned long *busaddr, unsigned int size,
+                       const struct file *filp) {
+
+  int i = 0;
+  int j = 0;
+  unsigned int skip_chunks = 0;
+
+  /* calculate how many chunks we need; round up to chunk boundary */
+  unsigned int alloc_chunks = (size + CHUNK_SIZE - 1) / CHUNK_SIZE;
+
+  *busaddr = 0;
+
+  spin_lock(&mem_lock);
+
+  /* run through the chunk table */
+  for (i = 0; i < chunks;) {
+    skip_chunks = 0;
+    /* if this chunk is available */
+    if (!hlina_chunks[i].chunks_reserved) {
+      /* check that there is enough memory left */
+      if (i + alloc_chunks > chunks) break;
+
+      /* check that there is enough consecutive chunks available */
+      for (j = i; j < i + alloc_chunks; j++) {
+        if (hlina_chunks[j].chunks_reserved) {
+          skip_chunks = 1;
+          /* skip the used chunks */
+          i = j + hlina_chunks[j].chunks_reserved;
+          break;
+        }
+      }
+
+      /* if enough free memory found */
+      if (!skip_chunks) {
+        *busaddr = hlina_chunks[i].bus_address;
+        hlina_chunks[i].filp = filp;
+        hlina_chunks[i].chunks_reserved = alloc_chunks;
+        break;
+      }
+    } else {
+      /* skip the used chunks */
+      i += hlina_chunks[i].chunks_reserved;
+    }
+  }
+
+  spin_unlock(&mem_lock);
+
+  if (*busaddr == 0) {
+    printk("memalloc: Allocation FAILED: size = %ld\n", size);
+    return -EFAULT;
+  } else {
+    PDEBUG("MEMALLOC OK: size: %d, reserved: %ld\n", size,
+           alloc_chunks * CHUNK_SIZE);
+  }
+
+  return 0;
+}
+
+/* Free a buffer based on bus address */
+static int FreeMemory(unsigned long busaddr, const struct file *filp) {
+  int i = 0;
+
+  spin_lock(&mem_lock);
+
+  for (i = 0; i < chunks; i++) {
+    /* user space SW has stored the translated bus address, add addr_transl to
+     * translate back to our address space */
+    if (hlina_chunks[i].bus_address == busaddr + addr_transl) {
+      if (hlina_chunks[i].filp == filp) {
+        hlina_chunks[i].filp = NULL;
+        hlina_chunks[i].chunks_reserved = 0;
+      } else {
+        printk(KERN_WARNING "memalloc: Owner mismatch while freeing memory!\n");
+      }
+      break;
+    }
+  }
+
+  spin_unlock(&mem_lock);
+
+  return 0;
+}
+
+/* Reset "used" status */
+static void ResetMems(void) {
+  int i = 0;
+  unsigned long ba = alloc_base;
+
+  spin_lock(&mem_lock);
+
+  for (i = 0; i < chunks; i++) {
+    hlina_chunks[i].bus_address = ba;
+    hlina_chunks[i].filp = NULL;
+    hlina_chunks[i].chunks_reserved = 0;
+
+    ba += CHUNK_SIZE;
+  }
+
+  spin_unlock(&mem_lock);
+}
+
+module_init(memalloc_init);
+module_exit(memalloc_cleanup);
+
+/* module description */
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Verisilicon");
+MODULE_DESCRIPTION("Linear RAM allocation");

+ 88 - 0
linux/memalloc/memalloc.h

@@ -0,0 +1,88 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2021 VERISILICON
+*
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2021 VERISILICON
+*
+*    This program is free software; you can redistribute it and/or
+*    modify it under the terms of the GNU General Public License
+*    as published by the Free Software Foundation; either version 2
+*    of the License, or (at your option) any later version.
+*
+*    This program is distributed in the hope that it will be useful,
+*    but WITHOUT ANY WARRANTY; without even the implied warranty of
+*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*    GNU General Public License for more details.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+#ifndef MEMALLOC_H
+#define MEMALLOC_H
+
+#include <linux/ioctl.h>
+
+#undef PDEBUG
+#ifdef MEMALLOC_DEBUG
+#ifdef __KERNEL__
+#define PDEBUG(fmt, args...) printk(KERN_INFO "memalloc: " fmt, ##args)
+#else
+#define PDEBUG(fmt, args...) fprintf(stderr, fmt, ##args)
+#endif
+#else
+#define PDEBUG(fmt, args...)
+#endif
+
+typedef struct {
+  unsigned long bus_address;
+  unsigned int size;
+  unsigned long translation_offset;
+  unsigned int mem_type;
+  int fd;
+  int flags;
+} MemallocParams;
+
+#define MEMALLOC_IOC_MAGIC 'k'
+
+#define MEMALLOC_IOCXGETBUFFER _IOWR(MEMALLOC_IOC_MAGIC, 1, MemallocParams*)
+#define MEMALLOC_IOCSFREEBUFFER _IOW(MEMALLOC_IOC_MAGIC, 2, unsigned long*)
+
+#define MEMALLOC_IOCHARDRESET _IO(MEMALLOC_IOC_MAGIC, 15) /* debugging tool */
+#define MEMALLOC_IOC_MAXNR 15
+
+#endif /* MEMALLOC_H */

+ 99 - 0
linux/memalloc/memalloc_load.sh

@@ -0,0 +1,99 @@
+#!/bin/sh
+
+#############################################################################
+#
+#    The MIT License (MIT)
+#
+#    Copyright (c) 2014 - 2021 VERISILICON
+#
+#    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.
+#
+#############################################################################
+#
+#    The GPL License (GPL)
+#
+#    Copyright (C) 2014 - 2021 VERISILICON
+#
+#    This program is free software; you can redistribute it and/or
+#    modify it under the terms of the GNU General Public License
+#    as published by the Free Software Foundation; either version 2
+#    of the License, or (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program; if not, write to the Free Software Foundation,
+#    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+#############################################################################
+#
+#    Note: This software is released under dual MIT and GPL licenses. A
+#    recipient may use this file under the terms of either the MIT license or
+#    GPL License. If you wish to use only one license not the other, you can
+#    indicate your decision by deleting one of the above license notices in your
+#    version of this file.
+#
+##############################################################################
+#
+# Load memalloc
+
+module="memalloc"
+device="/dev/memalloc"
+mode="666"
+
+echo
+
+if [ ! -e /dev ]
+then
+    mkdir -p /dev/
+fi
+
+#insert module
+rm_module=`lsmod |grep $module`
+if [ ! -z "$rm_module" ]
+then
+   rmmod $module || exit 1
+fi
+insmod $module.ko $* || exit 1
+
+echo "module $module inserted"
+
+#remove old nod
+rm -f $device
+
+#read the major asigned at loading time
+major=`cat /proc/devices | grep $module | cut -c1-3`
+
+echo "$module major = $major"
+
+#create dev node
+mknod $device c $major 0
+
+echo "node $device created"
+
+#give all 'rw' access
+chmod $mode $device
+
+echo "set node access to $mode"
+
+#the end
+echo

+ 207 - 0
linux/memalloc/testbench_memalloc.c

@@ -0,0 +1,207 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2021 VERISILICON
+*
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2021 VERISILICON
+*
+*    This program is free software; you can redistribute it and/or
+*    modify it under the terms of the GNU General Public License
+*    as published by the Free Software Foundation; either version 2
+*    of the License, or (at your option) any later version.
+*
+*    This program is distributed in the hope that it will be useful,
+*    but WITHOUT ANY WARRANTY; without even the implied warranty of
+*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*    GNU General Public License for more details.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <getopt.h>
+#include <assert.h>
+
+#include "basetype.h"
+#include "memalloc.h"
+
+int main(void) {
+
+  i32 memdev_fd = -1;
+  i32 memdev_fd_2 = -1;
+  i32 memdev_map = -1;
+  i32 i = 0, u = 0;
+  u32 *virtual1 = MAP_FAILED;
+  u32 *virtual2 = MAP_FAILED;
+
+  u32 pgsize = getpagesize();
+
+  const char *memdev = "/dev/memalloc";
+  const char *memmap = "/dev/mem";
+
+  u32 bus_address1 = 0, bus_address2 = 0;
+  u32 size = 4096;
+
+  memdev_fd = open(memdev, O_RDWR);
+  if (memdev_fd == -1) {
+    printf("Failed to open dev: %s\n", memdev);
+    goto end1;
+  }
+
+  memdev_fd_2 = open(memdev, O_RDWR);
+  if (memdev_fd_2 == -1) {
+    printf("Failed to open dev: %s\n", memdev);
+    goto end1;
+  }
+
+  memdev_map = open(memmap, O_RDWR);
+  if (memdev_map == -1) {
+    printf("Failed to open dev: %s\n", memmap);
+    goto end1;
+  }
+
+  size = (size + pgsize) & (~(pgsize - 1));
+
+  printf("Hard Reset\n", size);
+  /*ioctl(memdev_fd, MEMALLOC_IOCHARDRESET, 0);*/
+
+  for (i = 0; i < 100; i++) {
+
+    ioctl(memdev_fd, MEMALLOC_IOCXGETBUFFER, &bus_address1);
+    printf("bus_address1 0x%08x\n", bus_address1);
+
+    ioctl(memdev_fd_2, MEMALLOC_IOCXGETBUFFER, &bus_address2);
+    printf("bus_address2 0x%08x\n", bus_address2);
+
+    /* test write stuff in the mem are*/
+
+    if (bus_address1) {
+
+      virtual1 = (u32 *)mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED,
+                             memdev_map, bus_address1);
+
+      printf("Virtual1 %08x\n", virtual1);
+    }
+    if (virtual1 != MAP_FAILED) {
+      for (u = 0; u < size / 4; u++) {
+        *virtual1 = i + 1;
+      }
+    } else {
+      printf("map failed\n");
+    }
+
+    /* test write stuff in the mem are*/
+
+    if (bus_address2) {
+
+      virtual2 = (u32 *)mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED,
+                             memdev_map, bus_address2);
+
+      printf("Virtual2 0x%08x\n", virtual2);
+    }
+    if (virtual2 != MAP_FAILED) {
+      for (u = 0; u < size / 4; u++) {
+        *virtual2 = i + 2;
+      }
+    } else {
+      printf("map failed\n");
+    }
+
+    if (virtual1 != MAP_FAILED) {
+      for (u = 0; u < size / 4; u++) {
+        if (*virtual1 != i + 1) {
+          printf("MISMATCH1!\n");
+          break;
+        }
+      }
+    }
+
+    if (virtual2 != MAP_FAILED) {
+      for (u = 0; u < size / 4; u++) {
+        if (*virtual2 != i + 2) {
+          printf("MISMATCH2!\n");
+          break;
+        }
+      }
+    }
+
+    if ((i % 30)) {
+      printf("release %d ", size);
+      ioctl(memdev_fd, MEMALLOC_IOCSFREEBUFFER, &bus_address1);
+      printf("address:\t\t0x%08x\n", bus_address1);
+    }
+
+    printf("release %d ", size);
+    /*ioctl(memdev_fd_2, MEMALLOC_IOCSFREEBUFFER, &bus_address2);
+    printf("address:\t\t0x%08x\n", bus_address2);
+    virtual1 = MAP_FAILED;
+    virtual2 = MAP_FAILED;*/
+
+    if (!(i % 30)) {
+      close(memdev_fd);
+      memdev_fd = open(memdev, O_RDWR);
+      if (memdev_fd == -1) {
+        printf("Failed to open dev: %s\n", memdev);
+        goto end1;
+      }
+    }
+    close(memdev_fd_2);
+    memdev_fd_2 = open(memdev, O_RDWR);
+    if (memdev_fd_2 == -1) {
+      printf("Failed to open dev: %s\n", memdev);
+      goto end1;
+    }
+  }
+
+end1:
+
+  close(memdev_fd);
+  close(memdev_fd_2);
+  close(memdev_map);
+
+  return 0;
+}

+ 88 - 0
linux/subsys_driver/Makefile

@@ -0,0 +1,88 @@
+#############################################################################
+#
+#    The MIT License (MIT)
+#
+#    Copyright (c) 2014 - 2021 VERISILICON
+#
+#    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.
+#
+#############################################################################
+#
+#    The GPL License (GPL)
+#
+#    Copyright (C) 2014 - 2021 VERISILICON
+#
+#    This program is free software; you can redistribute it and/or
+#    modify it under the terms of the GNU General Public License
+#    as published by the Free Software Foundation; either version 2
+#    of the License, or (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program; if not, write to the Free Software Foundation,
+#    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+#############################################################################
+#
+#    Note: This software is released under dual MIT and GPL licenses. A
+#    recipient may use this file under the terms of either the MIT license or
+#    GPL License. If you wish to use only one license not the other, you can
+#    indicate your decision by deleting one of the above license notices in your
+#    version of this file.
+#
+##############################################################################
+
+DEBUG ?= n
+ifeq ($(DEBUG),y)
+  DEBFLAGS = -O -g -DHANTRODEC_DEBUG
+  DEBFLAGS += -DHANTROMMU_DEBUG
+else
+  DEBFLAGS = -O2
+endif
+
+EXTRA_CFLAGS += $(DEBFLAGS)
+EXTRA_CFLAGS += -I$(PWD)/../dwl
+# EXTRA_CFLAGS   += -DDYNAMIC_MALLOC_VCMDNODE
+
+ifneq ($(KERNELRELEASE),)
+# recursive call from kernel build system
+
+hantrodec-objs := hantro_dec.o hantro_mmu.o hantro_axife.o hantro_vcmd.o bidirect_list.o vcmdswhwregisters.o subsys.o kernel_allocator.o
+obj-m         += hantrodec.o
+
+else
+
+#KDIR := /mnt/export/Testing/Board_Version_Control/SW_Common/SOCLE_MDK-3D/openlinux/2.6.29/v0_5/android_linux-2.6.29
+KVER := $(shell uname -r)
+KDIR := /lib/modules/$(KVER)/build
+
+PWD  := $(shell pwd)
+
+all:
+	$(MAKE) -C $(KDIR) M=$(PWD) modules
+
+endif
+
+clean:
+	rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions
+	rm -rf modules.order Module.symvers

+ 49 - 0
linux/subsys_driver/README

@@ -0,0 +1,49 @@
+/* Copyright 2013 Google Inc. All Rights Reserved. */
+
+-- BUILD --
+
+You need a fully configured kernel source tree in order to build the
+driver. Please set the location of the kernel tree in the Makefile (KDIR).
+If you want some extra debug information in the kernel logs, you could
+define the HANTRODEC_DEBUG but please be aware that allot of things are traced
+with this option.
+Also you could set a particular device MAJOR in the 'hantrodec.c' if you don't want
+dynamic allocation.
+
+Just run in this dir:
+
+%make
+
+-- USAGE --
+
+The parameters that can be set when loading the driver are the HW IO base
+address and the assigned IRQ number.
+
+First of all the module has to be inserted into the kernel with:
+(you need a Linux shell cmd line)
+
+%insmod hantrodec.o base_port=<baseaddress> irq=<irq number> pcie=<pcie_enabled>
+
+Set the correct values for the HW IO base address and the IRQ number if
+the default values compiled into the module are not valid.
+
+E.g., to disable PCIE mode:
+
+%insmod hantrodec.o pcie=0 base_port=<baseaddress> irq=<irq number>
+
+E.g., to enable vcmd mode:
+
+%insmod hantrodec.o vcmd=1
+
+Second of all a char device file has to be created:
+
+%mknod /dev/hantrodec c <MAJOR> 0
+
+Replace MAJOR with the correct value (i.e. read /proc/devices to found out
+the exact values).
+
+Make sure that you have RW rights for the newly created dev file (use 'chmod').
+
+The 'driver_load' script is provided for preparing all the things necessary for
+the driver to be usable. The script is using 'awk' to retrieve the device's
+major from /proc/devices. Remember to set the driver parameters.

+ 220 - 0
linux/subsys_driver/bidirect_list.c

@@ -0,0 +1,220 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2021 VERISILICON
+*
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2021 VERISILICON
+*
+*    This program is free software; you can redistribute it and/or
+*    modify it under the terms of the GNU General Public License
+*    as published by the Free Software Foundation; either version 2
+*    of the License, or (at your option) any later version.
+*
+*    This program is distributed in the hope that it will be useful,
+*    but WITHOUT ANY WARRANTY; without even the implied warranty of
+*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*    GNU General Public License for more details.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+#ifdef __FREERTOS__
+#include <string.h>
+#include "osal.h"
+#elif defined(__linux__)
+#include <linux/kernel.h>
+#include <linux/module.h>
+/* needed for __init,__exit directives */
+#include <linux/init.h>
+/* needed for remap_page_range
+    SetPageReserved
+    ClearPageReserved
+*/
+#include <linux/mm.h>
+/* obviously, for kmalloc */
+#include <linux/slab.h>
+/* for struct file_operations, register_chrdev() */
+#include <linux/fs.h>
+/* standard error codes */
+#include <linux/errno.h>
+
+#include <linux/moduleparam.h>
+/* request_irq(), free_irq() */
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+
+#include <linux/semaphore.h>
+#include <linux/spinlock.h>
+/* needed for virt_to_phys() */
+#include <asm/io.h>
+#include <linux/pci.h>
+#include <asm/uaccess.h>
+#include <linux/ioport.h>
+
+#include <asm/irq.h>
+
+#include <linux/version.h>
+#include <linux/vmalloc.h>
+#include <linux/timer.h>
+#else //For other os
+//TODO...
+#endif
+#include "bidirect_list.h"
+
+void init_bi_list(bi_list* list)
+{
+  list->head = NULL;
+  list->tail = NULL; 
+}
+
+bi_list_node* bi_list_create_node(void)
+{
+  bi_list_node* node=NULL;
+  node=(bi_list_node*)vmalloc(sizeof(bi_list_node));
+  if(node==NULL)
+  {
+    PDEBUG ("%s\n","vmalloc for node fail!");
+    return node;
+  }
+  memset(node,0,sizeof(bi_list_node)); 
+  return node;
+}
+void bi_list_free_node(bi_list_node* node)
+{
+  //free current node
+  vfree(node);
+  return;
+}
+
+void bi_list_insert_node_tail(bi_list* list,bi_list_node* current_node)
+{
+  if(current_node==NULL)
+  {
+    PDEBUG ("%s\n","insert node tail  NULL");
+    return;
+  }
+  if(list->tail)
+  {
+   current_node->previous=list->tail;
+   list->tail->next=current_node;
+   list->tail=current_node;
+   list->tail->next=NULL;
+  }
+  else
+  {
+   list->head=current_node;
+   list->tail=current_node;
+   current_node->next=NULL;
+   current_node->previous=NULL;
+  }
+  return;
+}
+
+void bi_list_insert_node_before(bi_list* list,bi_list_node* base_node,bi_list_node* new_node)
+{
+  bi_list_node* temp_node_previous=NULL;
+  if(new_node==NULL)
+  {
+    PDEBUG ("%s\n","insert node before new node NULL");
+    return;
+  }
+  if(base_node)
+  {
+   if(base_node->previous)
+   {
+    //at middle position
+    temp_node_previous = base_node->previous;
+    temp_node_previous->next=new_node;
+    new_node->next = base_node;
+    base_node->previous = new_node;
+    new_node->previous=temp_node_previous;
+   }
+   else
+   {
+    //at head
+    base_node->previous = new_node;
+    new_node->next = base_node;
+    list->head=new_node;
+    new_node->previous = NULL;
+   }
+  }
+  else
+  {
+   //at tail
+   bi_list_insert_node_tail(list,new_node);
+  }
+  return;
+}
+
+
+void bi_list_remove_node(bi_list* list,bi_list_node* current_node)
+{
+  bi_list_node* temp_node_previous=NULL;
+  bi_list_node* temp_node_next=NULL;
+  if(current_node==NULL)
+  {
+    PDEBUG ("%s\n","remove node NULL");
+    return;
+  }
+  temp_node_next=current_node->next;
+  temp_node_previous=current_node->previous;
+  
+  if(temp_node_next==NULL && temp_node_previous==NULL )
+  {
+    //there is only one node.
+    list->head=NULL;
+    list->tail=NULL;
+  }
+  else if(temp_node_next==NULL)
+  {
+    //at tail
+    list->tail=temp_node_previous;
+    temp_node_previous->next=NULL;
+  }
+  else if( temp_node_previous==NULL)
+  {
+    //at head
+    list->head=temp_node_next;
+    temp_node_next->previous=NULL;
+  }
+  else
+  {
+   //at middle position
+   temp_node_previous->next=temp_node_next;
+   temp_node_next->previous=temp_node_previous;
+  }
+  return;
+}

+ 107 - 0
linux/subsys_driver/bidirect_list.h

@@ -0,0 +1,107 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2021 VERISILICON
+*
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2021 VERISILICON
+*
+*    This program is free software; you can redistribute it and/or
+*    modify it under the terms of the GNU General Public License
+*    as published by the Free Software Foundation; either version 2
+*    of the License, or (at your option) any later version.
+*
+*    This program is distributed in the hope that it will be useful,
+*    but WITHOUT ANY WARRANTY; without even the implied warranty of
+*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*    GNU General Public License for more details.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+#ifndef _BIDIRECT_LIST_H_
+#define _BIDIRECT_LIST_H_
+#ifdef __FREERTOS__
+#include "dev_common_freertos.h"    /* needed for the _IOW etc stuff used later */
+#elif defined(__linux__)
+#include <linux/ioctl.h>    /* needed for the _IOW etc stuff used later */
+#else //For other os
+//TODO...
+#endif
+
+/*
+ * Macros to help debugging
+ */
+
+#undef PDEBUG   /* undef it, just in case */
+#ifdef BIDIRECTION_LIST_DEBUG
+#  ifdef __KERNEL__
+    /* This one if debugging is on, and kernel space */
+#    define PDEBUG(fmt, args...) printk( KERN_INFO "hmp4e: " fmt, ## args)
+#  else
+    /* This one for user space */
+#    define PDEBUG(fmt, args...) printf(__FILE__ ":%d: " fmt, __LINE__ , ## args)
+#  endif
+#else
+#  define PDEBUG(fmt, args...)  /* not debugging: nothing */
+#endif
+
+/***********************************************************************************************************************************************\
+* <Typedefs>
+\**********************************************************************************************************************************************/
+typedef struct bi_list_node{
+  void* data;
+  struct bi_list_node* next; 
+  struct bi_list_node* previous;
+}bi_list_node;
+typedef struct bi_list{
+  bi_list_node* head; 
+  bi_list_node* tail; 
+}bi_list;
+
+void init_bi_list(bi_list* list);
+
+bi_list_node* bi_list_create_node(void);
+
+void bi_list_free_node(bi_list_node* node);
+
+void bi_list_insert_node_tail(bi_list* list,bi_list_node* current_node);
+
+void bi_list_insert_node_before(bi_list* list,bi_list_node* base_node,bi_list_node* new_node);
+
+void bi_list_remove_node(bi_list* list,bi_list_node* current_node);
+
+#endif /* !_BIDIRECT_LIST_H_ */ 

+ 10 - 0
linux/subsys_driver/build_for_mpcore.sh

@@ -0,0 +1,10 @@
+#!/bin/sh
+
+KDIR=/mnt/export/Testing/Board_Version_Control/SW_Common/ARM_realview_v6/2.6.28-arm1/v0_1-v6/linux-2.6.28-arm1
+
+echo
+echo "KDIR=$KDIR"
+echo "CROSS=$CROSS"
+
+make KDIR=$KDIR $1
+

+ 10 - 0
linux/subsys_driver/build_for_socle.sh

@@ -0,0 +1,10 @@
+#!/bin/sh
+
+KDIR=/mnt/export/Testing/Board_Version_Control/SW_Common/SOCLE_MDK-3D/openlinux/2.6.29/v0_5/android_linux-2.6.29
+
+echo
+echo "KDIR=$KDIR"
+echo "CROSS=$CROSS"
+
+make KDIR=$KDIR $1
+

+ 10 - 0
linux/subsys_driver/build_for_vexpress.sh

@@ -0,0 +1,10 @@
+#!/bin/sh
+
+KDIR=/mnt/export/Testing/Board_Version_Control/SW_Common/VExpress/linux-linaro-3.2-2012.01-0
+
+echo
+echo "KDIR=$KDIR"
+echo "CROSS=$CROSS"
+
+make KDIR=$KDIR $1
+

+ 43 - 0
linux/subsys_driver/driver_load.sh

@@ -0,0 +1,43 @@
+#  Copyright 2013 Google Inc. All Rights Reserved.
+
+module="hantrodec"
+device="/dev/hantrodec"
+mode="666"
+
+echo
+
+if [ ! -e /dev ]
+then
+    mkdir -p /dev/
+fi
+
+#insert module
+rm_module=`lsmod |grep $module`
+if [ ! -z "$rm_module" ]
+then
+   rmmod $module || exit 1
+fi
+insmod $module.ko $* || exit 1
+
+echo "module $module inserted"
+
+#remove old nod
+rm -f $device
+
+#read the major asigned at loading time
+major=`cat /proc/devices | grep $module | cut -c1-3`
+
+echo "$module major = $major"
+
+#create dev node
+mknod $device c $major 0
+
+echo "node $device created"
+
+#give all 'rw' access
+chmod $mode $device
+
+echo "set node access to $mode"
+
+#the end
+echo

+ 43 - 0
linux/subsys_driver/driver_load_sc.sh

@@ -0,0 +1,43 @@
+#  Copyright 2013 Google Inc. All Rights Reserved.
+
+module="hantrodec"
+device="/dev/hantrodec"
+mode="666"
+
+echo
+
+if [ ! -e /dev ]
+then
+    mkdir -p /dev/
+fi
+
+#insert module
+rm_module=`lsmod |grep $module`
+if [ ! -z "$rm_module" ]
+then
+   rmmod $module || exit 1
+fi
+insmod $module.ko $* base_port=0xd0000000 || exit 1
+
+echo "module $module inserted"
+
+#remove old nod
+rm -f $device
+
+#read the major asigned at loading time
+major=`cat /proc/devices | grep $module | cut -c1-3`
+#major='50'
+echo "$module major = $major"
+
+#create dev node
+mknod $device c $major 0
+
+echo "node $device created"
+
+#give all 'rw' access
+chmod $mode $device
+
+echo "set node access to $mode"
+
+#the end
+echo

+ 255 - 0
linux/subsys_driver/freertos/dev_common_freertos.h

@@ -0,0 +1,255 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2021 VERISILICON
+*
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2021 VERISILICON
+*
+*    This program is free software; you can redistribute it and/or
+*    modify it under the terms of the GNU General Public License
+*    as published by the Free Software Foundation; either version 2
+*    of the License, or (at your option) any later version.
+*
+*    This program is distributed in the hope that it will be useful,
+*    but WITHOUT ANY WARRANTY; without even the implied warranty of
+*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*    GNU General Public License for more details.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+#ifndef _DEV_COMMON_FREERTOS_H_
+#define _DEV_COMMON_FREERTOS_H_
+
+/**********Driver for FreeRTOS based on the method of Linux's calling**********/
+#define __u8 u8
+#define __i8 i8
+#define __u32 u32
+#define __i32 i32
+
+#define sema_init(s,v)               sem_init(s,0,v)
+
+//PCIE
+#define pci_get_device(a,b,c)        (void *)0
+#define pci_enable_device(a)         0
+#define pci_disable_device(a)        0
+#define pci_resource_start(a,b)      0
+#define pci_resource_len(a,b)        0
+/*--------------------------------*/
+/* IO */
+//#define O_RDONLY (1)
+//#define O_WRONLY (1 << 1)
+//#define O_RDWR (O_RDONLY | O_WRONLY)
+//#define O_SYNC (1 << 2)
+#undef MAP_FAILED
+#define MAP_FAILED NULL
+#undef NULL
+#define NULL  ((void *)0)
+#define getpagesize() (1)
+#define ioremap_nocache(addr,size)           (addr)
+#define iounmap(addr)
+#define mmap(va, size, access, flag, fd, pa) DirectMemoryMap(pa, size)
+#define munmap(pRegs, size)
+#define vmalloc(a)                   pvPortMalloc(a) //malloc(a);
+#define vfree(a)                     vPortFree(a) //free(a);
+#define probe(a)                     Platform_init(a)
+#define open(name,flag)              freertos_open(name,flag)
+#define ioctl(fd,cmd,arg)            freertos_ioctl(fd,cmd,arg)
+#define close(fd)                    freertos_close(fd)
+#define KERN_INFO
+#define KERN_ERR
+#define KERN_WARNING
+#define KERN_DEBUG 
+#define printk                       PDEBUG
+#define access_ok(a,b,c)             (1)
+#define __init
+#define __exit
+#define msleep(s)                    osal_usleep(s*1000)
+
+/*
+ * Let any architecture override either of the following before
+ * including this file.
+ */
+#ifndef _IOC_SIZEBITS
+# define _IOC_SIZEBITS  14
+#endif
+
+#ifndef _IOC_DIRBITS
+# define _IOC_DIRBITS   2
+#endif
+#define _IOC_NRBITS     8
+#define _IOC_TYPEBITS   8
+
+#define _IOC_NRMASK     ((1 << _IOC_NRBITS)-1)
+#define _IOC_TYPEMASK   ((1 << _IOC_TYPEBITS)-1)
+#define _IOC_SIZEMASK   ((1 << _IOC_SIZEBITS)-1)
+#define _IOC_DIRMASK    ((1 << _IOC_DIRBITS)-1)
+
+#define _IOC_NRSHIFT    0
+#define _IOC_TYPESHIFT  (_IOC_NRSHIFT+_IOC_NRBITS)
+#define _IOC_SIZESHIFT  (_IOC_TYPESHIFT+_IOC_TYPEBITS)
+#define _IOC_DIRSHIFT   (_IOC_SIZESHIFT+_IOC_SIZEBITS)
+
+	/*
+	 * Direction bits, which any architecture can choose to override
+	 * before including this file.
+	 */
+#ifndef _IOC_NONE
+# define _IOC_NONE      0U
+#endif
+
+#ifndef _IOC_WRITE
+# define _IOC_WRITE     1U
+#endif
+
+#ifndef _IOC_READ
+# define _IOC_READ      2U
+#endif
+
+#define _IOC(dir,type,nr,size) \
+			(((dir)  << _IOC_DIRSHIFT) | \
+			 ((type) << _IOC_TYPESHIFT) | \
+			 ((nr)	 << _IOC_NRSHIFT) | \
+			 ((size) << _IOC_SIZESHIFT))
+
+#define _IOC_TYPECHECK(t) (sizeof(t))
+
+/* used to create numbers */
+#define _IO(type,nr)            _IOC(_IOC_NONE,(type),(nr),0)
+#define _IOR(type,nr,size)      _IOC(_IOC_READ,(type),(nr),(_IOC_TYPECHECK(size)))
+#define _IOW(type,nr,size)      _IOC(_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size)))
+#define _IOWR(type,nr,size)     _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size)))
+#define _IOR_BAD(type,nr,size)  _IOC(_IOC_READ,(type),(nr),sizeof(size))
+#define _IOW_BAD(type,nr,size)  _IOC(_IOC_WRITE,(type),(nr),sizeof(size))
+
+/* used to decode ioctl numbers.. */
+#define _IOC_DIR(nr)            (((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK)
+#define _IOC_TYPE(nr)           (((nr) >> _IOC_TYPESHIFT) & _IOC_TYPEMASK)
+#define _IOC_NR(nr)             (((nr) >> _IOC_NRSHIFT) & _IOC_NRMASK)
+#define _IOC_SIZE(nr)           (((nr) >> _IOC_SIZESHIFT) & _IOC_SIZEMASK)
+
+/* ...and for the drivers/sound files... */
+#define IOC_IN                  (_IOC_WRITE << _IOC_DIRSHIFT)
+#define IOC_OUT                 (_IOC_READ << _IOC_DIRSHIFT)
+#define IOC_INOUT               ((_IOC_WRITE|_IOC_READ) << _IOC_DIRSHIFT)
+#define IOCSIZE_MASK            (_IOC_SIZEMASK << _IOC_SIZESHIFT)
+#define IOCSIZE_SHIFT           (_IOC_SIZESHIFT)
+
+#define DECLARE_WAIT_QUEUE_HEAD(a)
+
+/* Kernel/User space */
+#define copy_from_user(des,src,size)       (memcpy(des,src,size),0)
+#define copy_to_user(des,src,size)         (memcpy(des,src,size),0)
+#define raw_copy_from_user(des,src,size)   (memcpy(des,src,size),0)
+#define raw_copy_to_user(des,src,size)     (memcpy(des,src,size),0)
+#define __put_user(val,user)               (*(user) = (val))
+#define __get_user(val,user)               ((val) = *user)
+
+/* Interrupt */
+/*********************request_irq, disable_irq, enable_irq need to be provided by customer*********************/
+#define request_irq(i,isr,flag,name,data)  RegisterIRQ(i, isr, flag, name, data)
+#define disable_irq(i)                     IntDisableIRQ(i)
+#define enable_irq(i)                      IntEnableIRQ(i)
+#define free_irq(i,data)
+#define irqreturn_t                        void
+#define down_interruptible(a)              pthread_mutex_lock(a)
+#define up(a)                              pthread_mutex_unlock(a)
+#define wait_event_interruptible(a,b)      sem_wait(&a)
+#define wake_up_interruptible_all(a)       sem_post(a)
+#define IRQ_RETVAL(a)                      //(a)
+#define IRQ_HANDLED                        //1
+#define IRQ_NONE                           //0
+#define register_chrdev(m,name,op)         (0)
+#define unregister_chrdev(m,name)
+#define IRQF_SHARED                        1
+#define IRQF_DISABLED                      0x00000020
+#define request_mem_region(addr,size,name) (1)
+#define release_mem_region(addr,size)
+#define kill_fasync(queue,sig,flag)
+//Timer
+//typedef TimerHandle_t struct timer_list; //For FreeRTOS
+
+#define ERR_OS_FAIL                        (0xffff)
+#define ERESTARTSYS                        ERR_OS_FAIL
+#ifdef EFAULT
+#undef EFAULT
+#endif
+#define EFAULT                             ERR_OS_FAIL
+#ifdef ENOTTY
+#undef ENOTTY
+#endif
+#define ENOTTY                             ERR_OS_FAIL
+#ifdef EINVAL
+#undef EINVAL
+#endif
+#define EINVAL                             ERR_OS_FAIL
+#ifdef EBUSY
+#undef EBUSY
+#endif
+#define EBUSY                              ERR_OS_FAIL
+
+/* kernel sync objects */
+/**********the atomic operations need to be provided by customer**********/
+//#define atomic_t                           __attribute__((section("cpu_dram"), aligned(4))) xmp_atomic_int_t//i32
+//#define ATOMIC_INIT(a)                     XMP_ATOMIC_INT_INITIALIZER(a)//a
+//#define atomic_inc(a)                      xmp_atomic_int_increment(a,1)//((*(a))++)
+//#define atomic_read(a)                     xmp_atomic_int_value(a)//(a)
+#define atomic_t                           i32
+#define ATOMIC_INIT(a)                     a
+#define atomic_inc(a)                      ((*(a))++)
+#define atomic_read(a)                     (a)
+typedef int sig_atomic_t;
+//typedef int sigset_t;
+#define sigemptyset(set)
+#define sigaddset(set, sig)
+#define sigsuspend(set)
+#define sigwait(set, signo)
+
+#define spinlock_t                         pthread_mutex_t
+#define spin_lock_init(a)                  (*a = PTHREAD_MUTEX_INITIALIZER)
+#define isr_spin_lock_irqsave(a,b)
+#define isr_spin_unlock_irqrestore(a,b)
+#define spin_lock_irqsave(a,b)        {pthread_mutex_lock(a); \
+                                       b = ioread32((void *)SYS_REG_INT_EN) & g_vc8000_int_enable_mask; \
+                                       *((volatile uint32_t *)SYS_REG_INT_EN) &= ~(b);}
+#define spin_unlock_irqrestore(a,b)   {*((volatile uint32_t *)SYS_REG_INT_EN) = \
+                                           ioread32((void *)SYS_REG_INT_EN) | (b); \
+                                       pthread_mutex_unlock(a); }
+#define spin_lock(a)                       pthread_mutex_lock(a)
+#define spin_unlock(a)                     pthread_mutex_unlock(a)
+#define getpid()                           (int)pthread_self()
+
+#endif /* _DEV_COMMON_FREERTOS_H_ */

+ 2065 - 0
linux/subsys_driver/freertos/hantro_dec_freertos.c

@@ -0,0 +1,2065 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2021 VERISILICON
+*
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2021 VERISILICON
+*
+*    This program is free software; you can redistribute it and/or
+*    modify it under the terms of the GNU General Public License
+*    as published by the Free Software Foundation; either version 2
+*    of the License, or (at your option) any later version.
+*
+*    This program is distributed in the hope that it will be useful,
+*    but WITHOUT ANY WARRANTY; without even the implied warranty of
+*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*    GNU General Public License for more details.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+#include "hantrodec.h"
+#include "dwl_defs.h"
+#include "subsys.h"
+#include "io_tools.h"
+#include "osal.h"
+
+#include "xtensa_api.h"
+//#include "../src/libxmp/xmp-library.h" //For atomic operations
+#include <xtensa/xtruntime.h> //interrupt for xtensa
+
+#include <stdint.h>
+#include <string.h>
+
+#undef PDEBUG
+#ifdef HANTRODEC_DEBUG
+#  ifdef __KERNEL__
+#    define PDEBUG(fmt, args...) printk( KERN_INFO "hantrodec: " fmt, ## args)
+#  else
+#    define PDEBUG(fmt, args...) fprintf(stderr, fmt, ## args)
+#  endif
+#else
+#  define PDEBUG(fmt, ...)
+#endif
+/*-----------------------------------------------------------------------------------------
+************************CPU Xtensa OS FreeRTOS PORTING LAYER*******************************
+------------------------------------------------------------------------------------------*/
+static u32 g_vc8000_int_enable_mask = 0;
+//VCMD for netint
+#define SYS_REG_INT_TOP_BASE     (0x02800000)
+//ENCODER
+#if 0
+#define CPU_INT_IRQ              8 /* All Encoder Modules' interrupt will be connected to CPU IRQ 8 */
+#define SYS_INT_MASK             (0x220)
+#define SYS_REG_INT_VAL          (SYS_REG_INT_TOP_BASE + 0x3c)
+#define SYS_REG_INT_STAT         (SYS_REG_INT_TOP_BASE + 0x40)
+#define SYS_REG_INT_EN           (SYS_REG_INT_TOP_BASE + 0x44)
+#else
+//DECODER
+#define CPU_INT_IRQ              9
+#define SYS_INT_MASK             (0x001)
+#define SYS_REG_INT_VAL          (SYS_REG_INT_TOP_BASE + 0x48)
+#define SYS_REG_INT_STAT         (SYS_REG_INT_TOP_BASE + 0x4c)
+#define SYS_REG_INT_EN           (SYS_REG_INT_TOP_BASE + 0x50)
+#endif
+
+/* hantro G1 regs config including dec and pp */
+#define HANTRO_DEC_ORG_REGS             60
+#define HANTRO_PP_ORG_REGS              41
+
+#define HANTRO_DEC_EXT_REGS             27
+#define HANTRO_PP_EXT_REGS              9
+
+//#define HANTRO_G1_DEC_TOTAL_REGS        (HANTRO_DEC_ORG_REGS + HANTRO_DEC_EXT_REGS)
+#define HANTRO_PP_TOTAL_REGS            (HANTRO_PP_ORG_REGS + HANTRO_PP_EXT_REGS)
+#define HANTRO_G1_DEC_REGS              155 /*G1 total regs*/
+
+//#define HANTRO_DEC_ORG_FIRST_REG        0
+//#define HANTRO_DEC_ORG_LAST_REG         59
+//#define HANTRO_DEC_EXT_FIRST_REG        119
+//#define HANTRO_DEC_EXT_LAST_REG         145
+
+#define HANTRO_PP_ORG_FIRST_REG         60
+#define HANTRO_PP_ORG_LAST_REG          100
+#define HANTRO_PP_EXT_FIRST_REG         146
+#define HANTRO_PP_EXT_LAST_REG          154
+
+/* hantro G2 reg config */
+#define HANTRO_G2_DEC_REGS              337 /*G2 total regs*/
+#define HANTRO_G2_DEC_FIRST_REG         0
+#define HANTRO_G2_DEC_LAST_REG          HANTRO_G2_DEC_REGS-1
+
+/* hantro VC8000D reg config */
+#define HANTRO_VC8000D_REGS             503 /*VC8000D total regs*/
+#define HANTRO_VC8000D_FIRST_REG        0
+#define HANTRO_VC8000D_LAST_REG         HANTRO_VC8000D_REGS-1
+
+/* Logic module IRQs */
+#define HXDEC_NO_IRQ                    -1
+
+#define MAX(a, b)                       (((a) > (b)) ? (a) : (b))
+
+#define DEC_IO_SIZE_MAX                 (MAX(MAX(HANTRO_G2_DEC_REGS, HANTRO_G1_DEC_REGS), HANTRO_VC8000D_REGS) * 4)
+
+/* User should modify these configuration if do porting to own platform. */
+/* Please guarantee the base_addr, io_size, dec_irq belong to same core. */
+
+/* Defines use kernel clk cfg or not**/
+//#define CLK_CFG
+#if 0
+#ifdef CLK_CFG
+#define CLK_ID                          "hantrodec_clk"  /*this id should conform with platform define*/
+#endif
+#endif
+
+/* Logic module base address */
+#define SOCLE_LOGIC_0_BASE              (0x02310000 + 0x2000)
+#define SOCLE_LOGIC_1_BASE              -1 //(0x02350000 + 0x2000)
+#define SOCLE_LOGIC_2_BASE              -1 //(0x02390000 + 0x2000)
+#define SOCLE_LOGIC_3_BASE              -1 //(0x023D0000 + 0x2000)
+
+//#define VEXPRESS_LOGIC_0_BASE           0xFC010000
+//#define VEXPRESS_LOGIC_1_BASE           0xFC020000
+
+#define DEC_IO_SIZE_0                   DEC_IO_SIZE_MAX /* bytes */
+#define DEC_IO_SIZE_1                   DEC_IO_SIZE_MAX /* bytes */
+#define DEC_IO_SIZE_2                   DEC_IO_SIZE_MAX /* bytes */
+#define DEC_IO_SIZE_3                   DEC_IO_SIZE_MAX /* bytes */
+
+#define DEC_IRQ_0                       9 //3
+#define DEC_IRQ_1                       HXDEC_NO_IRQ
+
+#define IS_G1(hw_id)                    (((hw_id) == 0x6731)? 1 : 0)
+#define IS_G2(hw_id)                    (((hw_id) == 0x6732)? 1 : 0)
+#define IS_VC8000D(hw_id)               (((hw_id) == 0x8001)? 1 : 0)
+
+static const int DecHwId[] = {
+  0x6731, /* G1 */
+  0x6732, /* G2 */
+  0x8001  /* VC8000D */
+};
+
+unsigned long base_port = 0;
+volatile unsigned char *reg = NULL;
+int vcmd = 0;
+
+unsigned long multicorebase[HXDEC_MAX_CORES] = {
+  SOCLE_LOGIC_0_BASE,
+  SOCLE_LOGIC_1_BASE,
+  SOCLE_LOGIC_2_BASE,
+  SOCLE_LOGIC_3_BASE
+};
+
+int irq[HXDEC_MAX_CORES] = {
+  DEC_IRQ_0,
+  -1,
+  -1,
+  -1
+};
+
+unsigned int iosize[HXDEC_MAX_CORES] = {
+  DEC_IO_SIZE_0,
+  DEC_IO_SIZE_1,
+  DEC_IO_SIZE_2,
+  DEC_IO_SIZE_3
+};
+
+/* Because one core may contain multi-pipeline, so multicore base may be changed */
+unsigned long multicorebase_actual[HXDEC_MAX_CORES];
+
+struct subsys_config vpu_subsys[MAX_SUBSYS_NUM];
+
+int elements = 4;
+
+#if 0
+#ifdef CLK_CFG
+struct clk *clk_cfg;
+int is_clk_on;
+struct timer_list timer;
+#endif
+#endif
+
+static int hantrodec_major = 0; /* dynamic allocation */
+
+/* here's all the must remember stuff */
+typedef struct {
+  char *buffer;
+  volatile unsigned int iosize[HXDEC_MAX_CORES];
+  volatile u8 *hwregs[HXDEC_MAX_CORES];
+  volatile int irq[HXDEC_MAX_CORES];
+  int hw_id[HXDEC_MAX_CORES];
+  int cores;
+  //struct fasync_struct *async_queue_dec;
+  //struct fasync_struct *async_queue_pp;
+} hantrodec_t;
+
+typedef struct {
+  u32 cfg[HXDEC_MAX_CORES];              /* indicate the supported format */
+  u32 cfg_backup[HXDEC_MAX_CORES];       /* back up of cfg */
+  int its_main_core_id[HXDEC_MAX_CORES]; /* indicate if main core exist */
+  int its_aux_core_id[HXDEC_MAX_CORES];  /* indicate if aux core exist */
+} core_cfg;
+
+static hantrodec_t hantrodec_data; /* dynamic allocation? */
+
+static int ReserveIO(void);
+static void ReleaseIO(void);
+
+static void ResetAsic(hantrodec_t * dev);
+
+#ifdef HANTRODEC_DEBUG
+static void dump_regs(hantrodec_t *dev);
+#endif
+
+/* Interrupt */
+/*********************request_irq, disable_irq, enable_irq need to be provided by customer*********************/
+static int RegisterIRQ(i32 i, IRQHandler isr, i32 flag, const char* name, void *data);
+static void IntEnableIRQ(u32 irq);
+static void IntDisableIRQ(u32 irq);
+static void IntClearIRQStatus(u32 irq, u32 type);
+static u32 IntGetIRQStatus(u32 irq);
+static inline uint32_t ReadInterruptStatus(void);
+
+/* IRQ handler */
+static irqreturn_t hantrodec_isr(void *args);
+static u32 dec_regs[HXDEC_MAX_CORES][DEC_IO_SIZE_MAX/4];
+
+#undef down_interruptible
+#undef up
+#define down_interruptible(a)              sem_wait(a)
+#define up(a)                              sem_post(a)
+sem_t dec_core_sem;
+sem_t pp_core_sem;
+
+static int dec_irq = 0;
+static int pp_irq = 0;
+
+/*********************the atomic operations need to be provided by customer*********************/
+atomic_t irq_rx = ATOMIC_INIT(0);
+atomic_t irq_tx = ATOMIC_INIT(0);
+
+static int dec_owner[HXDEC_MAX_CORES];
+static int pp_owner[HXDEC_MAX_CORES];
+static int CoreHasFormat(const u32 *cfg, int core, u32 format);
+#if 0
+/* spinlock_t owner_lock = SPIN_LOCK_UNLOCKED; */
+DEFINE_SPINLOCK(owner_lock);
+DECLARE_WAIT_QUEUE_HEAD(dec_wait_queue);
+DECLARE_WAIT_QUEUE_HEAD(pp_wait_queue);
+DECLARE_WAIT_QUEUE_HEAD(hw_queue);
+
+#ifdef CLK_CFG
+DEFINE_SPINLOCK(clk_lock);
+#endif
+#endif
+
+pthread_mutex_t owner_lock = PTHREAD_MUTEX_INITIALIZER;
+sem_t dec_wait_queue;
+sem_t pp_wait_queue;
+sem_t hw_queue;
+
+#define DWL_CLIENT_TYPE_H264_DEC         1U
+#define DWL_CLIENT_TYPE_MPEG4_DEC        2U
+#define DWL_CLIENT_TYPE_JPEG_DEC         3U
+#define DWL_CLIENT_TYPE_PP               4U
+#define DWL_CLIENT_TYPE_VC1_DEC          5U
+#define DWL_CLIENT_TYPE_MPEG2_DEC        6U
+#define DWL_CLIENT_TYPE_VP6_DEC          7U
+#define DWL_CLIENT_TYPE_AVS_DEC          8U
+#define DWL_CLIENT_TYPE_RV_DEC           9U
+#define DWL_CLIENT_TYPE_VP8_DEC          10U
+#define DWL_CLIENT_TYPE_VP9_DEC          11U
+#define DWL_CLIENT_TYPE_HEVC_DEC         12U
+
+static core_cfg config;
+
+static void ReadCoreConfig(hantrodec_t *dev) {
+  int c;
+  u32 reg, tmp, mask;
+
+  memset(config.cfg, 0, sizeof(config.cfg));
+
+  for(c = 0; c < dev->cores; c++) {
+    /* Decoder configuration */
+    if (IS_G1(dev->hw_id[c])) {
+      reg = ioread32((void*)(dev->hwregs[c] + HANTRODEC_SYNTH_CFG * 4));
+
+      tmp = (reg >> DWL_H264_E) & 0x3U;
+      if(tmp) printk(KERN_INFO "hantrodec: core[%d] has H264\n", c);
+      config.cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_H264_DEC : 0;
+
+      tmp = (reg >> DWL_JPEG_E) & 0x01U;
+      if(tmp) printk(KERN_INFO "hantrodec: core[%d] has JPEG\n", c);
+      config.cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_JPEG_DEC : 0;
+
+      tmp = (reg >> DWL_HJPEG_E) & 0x01U;
+      if(tmp) printk(KERN_INFO "hantrodec: core[%d] has HJPEG\n", c);
+      config.cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_JPEG_DEC : 0;
+
+      tmp = (reg >> DWL_MPEG4_E) & 0x3U;
+      if(tmp) printk(KERN_INFO "hantrodec: core[%d] has MPEG4\n", c);
+      config.cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_MPEG4_DEC : 0;
+
+      tmp = (reg >> DWL_VC1_E) & 0x3U;
+      if(tmp) printk(KERN_INFO "hantrodec: core[%d] has VC1\n", c);
+      config.cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_VC1_DEC: 0;
+
+      tmp = (reg >> DWL_MPEG2_E) & 0x01U;
+      if(tmp) printk(KERN_INFO "hantrodec: core[%d] has MPEG2\n", c);
+      config.cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_MPEG2_DEC : 0;
+
+      tmp = (reg >> DWL_VP6_E) & 0x01U;
+      if(tmp) printk(KERN_INFO "hantrodec: core[%d] has VP6\n", c);
+      config.cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_VP6_DEC : 0;
+
+      reg = ioread32((void*)(dev->hwregs[c] + HANTRODEC_SYNTH_CFG_2 * 4));
+
+      /* VP7 and WEBP is part of VP8 */
+      mask =  (1 << DWL_VP8_E) | (1 << DWL_VP7_E) | (1 << DWL_WEBP_E);
+      tmp = (reg & mask);
+      if(tmp & (1 << DWL_VP8_E))
+        printk(KERN_INFO "hantrodec: core[%d] has VP8\n", c);
+      if(tmp & (1 << DWL_VP7_E))
+        printk(KERN_INFO "hantrodec: core[%d] has VP7\n", c);
+      if(tmp & (1 << DWL_WEBP_E))
+        printk(KERN_INFO "hantrodec: core[%d] has WebP\n", c);
+      config.cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_VP8_DEC : 0;
+
+      tmp = (reg >> DWL_AVS_E) & 0x01U;
+      if(tmp) printk(KERN_INFO "hantrodec: core[%d] has AVS\n", c);
+      config.cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_AVS_DEC: 0;
+
+      tmp = (reg >> DWL_RV_E) & 0x03U;
+      if(tmp) printk(KERN_INFO "hantrodec: core[%d] has RV\n", c);
+      config.cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_RV_DEC : 0;
+
+      /* Post-processor configuration */
+      reg = ioread32((void*)(dev->hwregs[c] + HANTROPP_SYNTH_CFG * 4));
+
+      tmp = (reg >> DWL_G1_PP_E) & 0x01U;
+      if(tmp) printk(KERN_INFO "hantrodec: core[%d] has PP\n", c);
+      config.cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_PP : 0;
+    } else if((IS_G2(dev->hw_id[c]))) {
+      reg = ioread32((void*)(dev->hwregs[c] + HANTRODEC_CFG_STAT * 4));
+
+      tmp = (reg >> DWL_G2_HEVC_E) & 0x01U;
+      if(tmp) printk(KERN_INFO "hantrodec: core[%d] has HEVC\n", c);
+      config.cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_HEVC_DEC : 0;
+
+      tmp = (reg >> DWL_G2_VP9_E) & 0x01U;
+      if(tmp) printk(KERN_INFO "hantrodec: core[%d] has VP9\n", c);
+      config.cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_VP9_DEC : 0;
+
+      /* Post-processor configuration */
+      reg = ioread32((void*)(dev->hwregs[c] + HANTRODECPP_SYNTH_CFG * 4));
+
+      tmp = (reg >> DWL_G2_PP_E) & 0x01U;
+      if(tmp) printk(KERN_INFO "hantrodec: core[%d] has PP\n", c);
+      config.cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_PP : 0;
+    } else if((IS_VC8000D(dev->hw_id[c])) && config.its_main_core_id[c] < 0) {
+      reg = ioread32((void*)(dev->hwregs[c] + HANTRODEC_SYNTH_CFG * 4));
+
+      tmp = (reg >> DWL_H264_E) & 0x3U;
+      if(tmp) printk(KERN_INFO "hantrodec: core[%d] has H264\n", c);
+      config.cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_H264_DEC : 0;
+
+      tmp = (reg >> DWL_H264HIGH10_E) & 0x01U;
+      if(tmp) printk(KERN_INFO "hantrodec: core[%d] has H264HIGH10\n", c);
+      config.cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_H264_DEC : 0;
+
+      tmp = (reg >> DWL_JPEG_E) & 0x01U;
+      if(tmp) printk(KERN_INFO "hantrodec: core[%d] has JPEG\n", c);
+      config.cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_JPEG_DEC : 0;
+
+      tmp = (reg >> DWL_HJPEG_E) & 0x01U;
+      if(tmp) printk(KERN_INFO "hantrodec: core[%d] has HJPEG\n", c);
+      config.cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_JPEG_DEC : 0;
+
+      tmp = (reg >> DWL_MPEG4_E) & 0x3U;
+      if(tmp) printk(KERN_INFO "hantrodec: core[%d] has MPEG4\n", c);
+      config.cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_MPEG4_DEC : 0;
+
+      tmp = (reg >> DWL_VC1_E) & 0x3U;
+      if(tmp) printk(KERN_INFO "hantrodec: core[%d] has VC1\n", c);
+      config.cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_VC1_DEC: 0;
+
+      tmp = (reg >> DWL_MPEG2_E) & 0x01U;
+      if(tmp) printk(KERN_INFO "hantrodec: core[%d] has MPEG2\n", c);
+      config.cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_MPEG2_DEC : 0;
+
+      tmp = (reg >> DWL_VP6_E) & 0x01U;
+      if(tmp) printk(KERN_INFO "hantrodec: core[%d] has VP6\n", c);
+      config.cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_VP6_DEC : 0;
+
+      reg = ioread32((void*)(dev->hwregs[c] + HANTRODEC_SYNTH_CFG_2 * 4));
+
+      /* VP7 and WEBP is part of VP8 */
+      mask =  (1 << DWL_VP8_E) | (1 << DWL_VP7_E) | (1 << DWL_WEBP_E);
+      tmp = (reg & mask);
+      if(tmp & (1 << DWL_VP8_E))
+        printk(KERN_INFO "hantrodec: core[%d] has VP8\n", c);
+      if(tmp & (1 << DWL_VP7_E))
+        printk(KERN_INFO "hantrodec: core[%d] has VP7\n", c);
+      if(tmp & (1 << DWL_WEBP_E))
+        printk(KERN_INFO "hantrodec: core[%d] has WebP\n", c);
+      config.cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_VP8_DEC : 0;
+
+      tmp = (reg >> DWL_AVS_E) & 0x01U;
+      if(tmp) printk(KERN_INFO "hantrodec: core[%d] has AVS\n", c);
+      config.cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_AVS_DEC: 0;
+
+      tmp = (reg >> DWL_RV_E) & 0x03U;
+      if(tmp) printk(KERN_INFO "hantrodec: core[%d] has RV\n", c);
+      config.cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_RV_DEC : 0;
+
+      reg = ioread32((void*)(dev->hwregs[c] + HANTRODEC_SYNTH_CFG_3 * 4));
+
+      tmp = (reg >> DWL_HEVC_E) & 0x07U;
+      if(tmp) printk(KERN_INFO "hantrodec: core[%d] has HEVC\n", c);
+      config.cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_HEVC_DEC : 0;
+
+      tmp = (reg >> DWL_VP9_E) & 0x07U;
+      if(tmp) printk(KERN_INFO "hantrodec: core[%d] has VP9\n", c);
+      config.cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_VP9_DEC : 0;
+
+      /* Post-processor configuration */
+      reg = ioread32((void*)(dev->hwregs[c] + HANTRODECPP_CFG_STAT * 4));
+
+      tmp = (reg >> DWL_PP_E) & 0x01U;
+      if(tmp) printk(KERN_INFO "hantrodec: core[%d] has PP\n", c);
+      config.cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_PP : 0;
+
+      if (config.its_aux_core_id[c] >= 0) {
+        /* set main_core_id and aux_core_id */
+        reg = ioread32((void*)(dev->hwregs[c] + HANTRODEC_SYNTH_CFG_2 * 4));
+
+        tmp = (reg >> DWL_H264_PIPELINE_E) & 0x01U;
+        if(tmp) printk(KERN_INFO "hantrodec: core[%d] has pipeline H264\n", c);
+        config.cfg[config.its_aux_core_id[c]] |= tmp ? 1 << DWL_CLIENT_TYPE_H264_DEC : 0;
+
+        tmp = (reg >> DWL_JPEG_PIPELINE_E) & 0x01U;
+        if(tmp) printk(KERN_INFO "hantrodec: core[%d] has pipeline JPEG\n", c);
+        config.cfg[config.its_aux_core_id[c]] |= tmp ? 1 << DWL_CLIENT_TYPE_JPEG_DEC : 0;
+      }
+    }
+  }
+  memcpy(config.cfg_backup, config.cfg, sizeof(config.cfg));
+}
+
+static int CoreHasFormat(const u32 *cfg, int core, u32 format) {
+  return (cfg[core] & (1 << format)) ? 1 : 0;
+}
+
+int GetDecCore(long core, hantrodec_t *dev, int filp, unsigned long format) {
+  int success = 0;
+  unsigned long flags;
+
+  spin_lock_irqsave(&owner_lock, flags);
+  if(CoreHasFormat(config.cfg, core, format) && dec_owner[core] == 0 /*&& config.its_main_core_id[core] >= 0*/) {
+    dec_owner[core] = filp;
+    success = 1;
+
+    /* If one main core takes one format which doesn't supported by aux core, set aux core's cfg to none video format support */
+    if (config.its_aux_core_id[core] >= 0 &&
+        !CoreHasFormat(config.cfg, config.its_aux_core_id[core], format)) {
+      config.cfg[config.its_aux_core_id[core]] = 0;
+    }
+    /* If one aux core takes one format, set main core's cfg to aux core supported video format */
+    else if (config.its_main_core_id[core] >= 0) {
+      config.cfg[config.its_main_core_id[core]] = config.cfg[core];
+    }
+  }
+
+  spin_unlock_irqrestore(&owner_lock, flags);
+
+  return success;
+}
+
+int GetDecCoreAny(long *core, hantrodec_t *dev, int filp,
+                  unsigned long format) {
+  int success = 0;
+  long c;
+
+  *core = -1;
+
+  for(c = 0; c < dev->cores; c++) {
+    /* a free core that has format */
+    /* xuanji: simplely impto get core for single core, exists issue */
+    if(GetDecCore(c, dev, filp, format)) {
+      success = 1;
+      *core = c;
+      break;
+    }
+  }
+
+  return success;
+}
+
+int GetDecCoreID(hantrodec_t *dev, int filp,
+                 unsigned long format) {
+  long c;
+  unsigned long flags;
+
+  int core_id = -1;
+
+  for(c = 0; c < dev->cores; c++) {
+    /* a core that has format */
+    spin_lock_irqsave(&owner_lock, flags);
+    if(CoreHasFormat(config.cfg, c, format)) {
+      core_id = c;
+      spin_unlock_irqrestore(&owner_lock, flags);
+      break;
+    }
+    spin_unlock_irqrestore(&owner_lock, flags);
+  }
+  return core_id;
+}
+
+#if 0
+static int hantrodec_choose_core(int is_g1) {
+  volatile unsigned char *reg = NULL;
+  unsigned int blk_base = 0x38320000;
+
+  PDEBUG("hantrodec_choose_core\n");
+  if (!request_mem_region(blk_base, 0x1000, "blk_ctl")) {
+    printk(KERN_INFO "blk_ctl: failed to reserve HW regs\n");
+    return -EBUSY;
+  }
+
+  reg = (volatile u8 *) ioremap_nocache(blk_base, 0x1000);
+
+  if (reg == NULL ) {
+    printk(KERN_INFO "blk_ctl: failed to ioremap HW regs\n");
+    if (reg)
+      iounmap((void *)reg);
+    release_mem_region(blk_base, 0x1000);
+    return -EBUSY;
+  }
+
+  // G1 use, set to 1; G2 use, set to 0, choose the one you are using
+  if (is_g1)
+    iowrite32(0x1, (void*)(reg + 0x14));  // VPUMIX only use G1, user should modify the reg according to platform design
+  else
+    iowrite32(0x0, (void*)(reg + 0x14)); // VPUMIX only use G2, user should modify the reg according to platform design
+
+  if (reg)
+    iounmap((void *)reg);
+  release_mem_region(blk_base, 0x1000);
+  PDEBUG("hantrodec_choose_core OK!\n");
+  return 0;
+}
+#endif
+
+long ReserveDecoder(hantrodec_t *dev, int filp, unsigned long format) {
+  long core = -1;
+
+  /* reserve a core */
+  if (down_interruptible(&dec_core_sem))
+    return -ERESTARTSYS;
+
+  /* lock a core that has specific format*/
+  if(wait_event_interruptible(hw_queue,GetDecCoreAny(&core, dev, filp, format) != 0 ))
+    return -ERESTARTSYS;
+  /* xuanji: simplely imp to get core for single core, exists issue */
+  GetDecCoreAny(&core, dev, filp, format);
+
+#if 0
+  if(IS_G1(dev->hw_id[core])) {
+    if (0 == hantrodec_choose_core(1))
+      printk("G1 is reserved\n");
+    else
+      return -1;
+  } else {
+    if (0 == hantrodec_choose_core(0))
+      printk("G2 is reserved\n");
+    else
+      return -1;
+  }
+#endif
+
+  return core;
+}
+
+void ReleaseDecoder(hantrodec_t *dev, long core) {
+  u32 status;
+  unsigned long flags;
+
+  status = ioread32((void*)(dev->hwregs[core] + HANTRODEC_IRQ_STAT_DEC_OFF));
+
+  /* make sure HW is disabled */
+  if(status & HANTRODEC_DEC_E) {
+    printk(KERN_INFO "hantrodec: DEC[%li] still enabled -> reset\n", core);
+
+    /* abort decoder */
+    status |= HANTRODEC_DEC_ABORT | HANTRODEC_DEC_IRQ_DISABLE;
+    iowrite32(status, (void*)(dev->hwregs[core] + HANTRODEC_IRQ_STAT_DEC_OFF));
+  }
+
+  spin_lock_irqsave(&owner_lock, flags);
+
+  /* If aux core released, revert main core's config back */
+  if (config.its_main_core_id[core] >= 0) {
+    config.cfg[config.its_main_core_id[core]] = config.cfg_backup[config.its_main_core_id[core]];
+  }
+
+  /* If main core released, revert aux core's config back */
+  if (config.its_aux_core_id[core] >= 0) {
+    config.cfg[config.its_aux_core_id[core]] = config.cfg_backup[config.its_aux_core_id[core]];
+  }
+
+  dec_owner[core] = 0;
+
+  spin_unlock_irqrestore(&owner_lock, flags);
+
+  up(&dec_core_sem);
+
+  wake_up_interruptible_all(&hw_queue);
+}
+
+long ReservePostProcessor(hantrodec_t *dev, int filp) {
+  unsigned long flags;
+
+  long core = 0;
+
+  /* single core PP only */
+  if (down_interruptible(&pp_core_sem))
+    return -ERESTARTSYS;
+
+  spin_lock_irqsave(&owner_lock, flags);
+
+  pp_owner[core] = filp;
+
+  spin_unlock_irqrestore(&owner_lock, flags);
+
+  return core;
+}
+
+void ReleasePostProcessor(hantrodec_t *dev, long core) {
+  unsigned long flags;
+
+  u32 status = ioread32((void*)(dev->hwregs[core] + HANTRO_IRQ_STAT_PP_OFF));
+
+  /* make sure HW is disabled */
+  if(status & HANTRO_PP_E) {
+    printk(KERN_INFO "hantrodec: PP[%li] still enabled -> reset\n", core);
+
+    /* disable IRQ */
+    status |= HANTRO_PP_IRQ_DISABLE;
+
+    /* disable postprocessor */
+    status &= (~HANTRO_PP_E);
+    iowrite32(0x10, (void*)(dev->hwregs[core] + HANTRO_IRQ_STAT_PP_OFF));
+  }
+
+  spin_lock_irqsave(&owner_lock, flags);
+
+  pp_owner[core] = 0;
+
+  spin_unlock_irqrestore(&owner_lock, flags);
+
+  up(&pp_core_sem);
+}
+
+long ReserveDecPp(hantrodec_t *dev, int filp, unsigned long format) {
+  /* reserve core 0, DEC+PP for pipeline */
+  unsigned long flags;
+
+  long core = 0;
+
+  /* check that core has the requested dec format */
+  if(!CoreHasFormat(config.cfg, core, format))
+    return -EFAULT;
+
+  /* check that core has PP */
+  if(!CoreHasFormat(config.cfg, core, DWL_CLIENT_TYPE_PP))
+    return -EFAULT;
+
+  /* reserve a core */
+  if (down_interruptible(&dec_core_sem))
+    return -ERESTARTSYS;
+
+  /* wait until the core is available */
+  if(wait_event_interruptible(hw_queue, GetDecCore(core, dev, filp, format) != 0)) {
+    up(&dec_core_sem);
+    return -ERESTARTSYS;
+  }
+  /* xuanji: simplely imp to get core for single core, exists issue */
+  GetDecCore(core, dev, filp, format);
+
+  if (down_interruptible(&pp_core_sem)) {
+    ReleaseDecoder(dev, core);
+    return -ERESTARTSYS;
+  }
+
+  spin_lock_irqsave(&owner_lock, flags);
+  pp_owner[core] = filp;
+  spin_unlock_irqrestore(&owner_lock, flags);
+
+  return core;
+}
+
+long DecFlushRegs(hantrodec_t *dev, struct core_desc *core) {
+  long ret = 0, i;
+
+  u32 id = core->id;
+
+#if 1
+  ret = copy_from_user(dec_regs[id], core->regs, HANTRO_VC8000D_REGS*4);
+  if (ret) {
+    PDEBUG("Hantrodec copy_from_user failed, returned %li\n", ret);
+    return -EFAULT;
+  }
+
+  /* write all regs but the status reg[1] to hardware */
+  iowrite32(0x0, (void*)(dev->hwregs[id] + 4));
+  for(i = 2; i <= HANTRO_VC8000D_LAST_REG; i++) {
+    iowrite32(dec_regs[id][i], (void*)(dev->hwregs[id] + i*4));
+  }
+#else
+  if (IS_G1(dev->hw_id[id])) {
+    /* copy original dec regs to kernal space*/
+    ret = copy_from_user(dec_regs[id], core->regs, HANTRO_DEC_ORG_REGS*4);
+    if (ret) {
+      PDEBUG("copy_from_user failed, returned %li\n", ret);
+      return -EFAULT;
+    }
+#ifdef USE_64BIT_ENV
+    /* copy extended dec regs to kernal space*/
+    ret = copy_from_user(dec_regs[id] + HANTRO_DEC_EXT_FIRST_REG,
+                         core->regs + HANTRO_DEC_EXT_FIRST_REG,
+                         HANTRO_DEC_EXT_REGS*4);
+#endif
+    if (ret) {
+      PDEBUG("copy_from_user failed, returned %li\n", ret);
+      return -EFAULT;
+    }
+
+    /* write dec regs but the status reg[1] to hardware */
+    /* both original and extended regs need to be written */
+    for(i = 2; i <= HANTRO_DEC_ORG_LAST_REG; i++) {
+      iowrite32(dec_regs[id][i], dev->hwregs[id] + i*4);
+    }
+#ifdef USE_64BIT_ENV
+    for(i = HANTRO_DEC_EXT_FIRST_REG; i <= HANTRO_DEC_EXT_LAST_REG; i++)
+      iowrite32(dec_regs[id][i], dev->hwregs[id] + i*4);
+#endif
+  } else {
+    ret = copy_from_user(dec_regs[id], core->regs, HANTRO_G2_DEC_REGS*4);
+    if (ret) {
+      PDEBUG("copy_from_user failed, returned %li\n", ret);
+      return -EFAULT;
+    }
+
+    /* write all regs but the status reg[1] to hardware */
+    for(i = 2; i <= HANTRO_G2_DEC_LAST_REG; i++) {
+#if 0
+      if(i==2)
+        //dec_regs[id][i] = 0x78777777;
+        //dec_regs[id][i] = 0x78778787;
+        //c_regs[id][i] = 0x78888888; //64bit
+      {
+        printk("reg2=%08x\n",dec_regs[id][i]);
+        //dec_regs[id][i] = 0xF0F00000;//128bit 0xF0F0F000
+      }
+      //dec_regs[id][i] = 0xF0F0000F;//128bit 0xF0F00000 for big endian
+      if(i==58) {
+        printk("reg58=%08x\n",dec_regs[id][i]);
+        //dec_regs[id][i]= 0x210;//128bit
+        //dec_regs[id][i]= 0x110;//64bit
+      }
+      if(i==3) {
+        printk("reg3=%08x\n",dec_regs[id][i]);
+        //dec_regs[id][i] |= 0x00F00000;//128bit
+        //dec_regs[id][i]= 0x110;//64bit
+      }
+#endif
+      iowrite32(dec_regs[id][i], dev->hwregs[id] + i*4);
+
+    }
+  }
+#endif
+
+  /* write the status register, which may start the decoder */
+  iowrite32(dec_regs[id][1], (void*)(dev->hwregs[id] + 4));
+
+  PDEBUG("Hantrodec flushed registers on core %d\n", id);
+
+  return 0;
+}
+
+
+long DecWriteRegs(hantrodec_t *dev, struct core_desc *core)
+{
+  long ret = 0, i;
+  u32 id = core->id;
+  i = core->reg_id;
+
+  ret = copy_from_user(dec_regs[id] + core->reg_id, core->regs + core->reg_id, 4);
+
+  if (ret) {
+    PDEBUG("Hantrodec copy_from_user failed, returned %li\n", ret);
+    return -EFAULT;
+  }
+
+  iowrite32(dec_regs[id][i], (void*)(dev->hwregs[id] + i*4));
+  return 0;
+}
+
+long DecReadRegs(hantrodec_t *dev, struct core_desc *core)
+{
+  long ret, i;
+  u32 id = core->id;
+  i = core->reg_id;
+
+  /* user has to know exactly what they are asking for */
+  //if(core->size != (HANTRO_VC8000D_REGS * 4))
+  //  return -EFAULT;
+
+  /* read specific registers from hardware */
+  i = core->reg_id;
+  dec_regs[id][i] = ioread32((void*)(dev->hwregs[id] + i*4));
+
+  /* put registers to user space*/
+  ret = copy_to_user(core->regs + core->reg_id, dec_regs[id] + core->reg_id, 4);
+  if (ret) {
+    PDEBUG("Hantrodec copy_to_user failed, returned %li\n", ret);
+    return -EFAULT;
+  }
+  return 0;
+}
+
+long DecRefreshRegs(hantrodec_t *dev, struct core_desc *core) {
+  long ret, i;
+  u32 id = core->id;
+
+#if 1
+  //for(i = 0; i <= HANTRO_DEC_ORG_LAST_REG; i++) {
+  for(i = 0; i <= HANTRO_VC8000D_LAST_REG; i++) {
+    dec_regs[id][i] = ioread32((void*)(dev->hwregs[id] + i*4));
+  }
+  //ret = copy_to_user(core->regs, dec_regs[id], HANTRO_DEC_ORG_REGS*4);
+  ret = copy_to_user(core->regs, dec_regs[id], HANTRO_G2_DEC_REGS*4);
+  if (ret) {
+    PDEBUG("Hantrodec copy_to_user failed, returned %li\n", ret);
+    return -EFAULT;
+  }
+#else
+
+  if (IS_G1(dev->hw_id[id])) {
+#ifdef USE_64BIT_ENV
+    /* user has to know exactly what they are asking for */
+    if(core->size != (HANTRO_DEC_TOTAL_REGS * 4))
+      return -EFAULT;
+#else
+    /* user has to know exactly what they are asking for */
+    //if(core->size != (HANTRO_DEC_ORG_REGS * 4))
+    //  return -EFAULT;
+#endif
+    /* read all registers from hardware */
+    /* both original and extended regs need to be read */
+    for(i = 0; i <= HANTRO_DEC_ORG_LAST_REG; i++)
+      dec_regs[id][i] = ioread32(dev->hwregs[id] + i*4);
+#ifdef USE_64BIT_ENV
+    for(i = HANTRO_DEC_EXT_FIRST_REG; i <= HANTRO_DEC_EXT_LAST_REG; i++)
+      dec_regs[id][i] = ioread32(dev->hwregs[id] + i*4);
+#endif
+    /* put registers to user space*/
+    /* put original registers to user space*/
+    ret = copy_to_user(core->regs, dec_regs[id], HANTRO_DEC_ORG_REGS*4);
+#ifdef USE_64BIT_ENV
+    /*put extended registers to user space*/
+    ret = copy_to_user(core->regs + HANTRO_DEC_EXT_FIRST_REG,
+                       dec_regs[id] + HANTRO_DEC_EXT_FIRST_REG,
+                       HANTRO_DEC_EXT_REGS * 4);
+#endif
+    if (ret) {
+      PDEBUG("copy_to_user failed, returned %li\n", ret);
+      return -EFAULT;
+    }
+  } else {
+    /* user has to know exactly what they are asking for */
+    if(core->size != (HANTRO_G2_DEC_REGS * 4))
+      return -EFAULT;
+
+    /* read all registers from hardware */
+    for(i = 0; i <= HANTRO_G2_DEC_LAST_REG; i++)
+      dec_regs[id][i] = ioread32(dev->hwregs[id] + i*4);
+
+    /* put registers to user space*/
+    ret = copy_to_user(core->regs, dec_regs[id], HANTRO_G2_DEC_REGS*4);
+    if (ret) {
+      PDEBUG("copy_to_user failed, returned %li\n", ret);
+      return -EFAULT;
+    }
+  }
+#endif
+  return 0;
+}
+
+static int CheckDecIrq(hantrodec_t *dev, int id) {
+  unsigned long flags;
+  int rdy = 0;
+
+  const u32 irq_mask = (1 << id);
+
+  spin_lock_irqsave(&owner_lock, flags);
+
+  if(dec_irq & irq_mask) {
+    /* reset the wait condition(s) */
+    dec_irq &= ~irq_mask;
+    rdy = 1;
+  }
+
+  spin_unlock_irqrestore(&owner_lock, flags);
+
+  return rdy;
+}
+
+long WaitDecReadyAndRefreshRegs(hantrodec_t *dev, struct core_desc *core) {
+  u32 id = core->id;
+  long ret;
+
+  PDEBUG("Hantrodec wait_event_interruptible DEC[%d]\n", id);
+  ret = wait_event_interruptible(dec_wait_queue, CheckDecIrq(dev, id));
+  if(ret) {
+    PDEBUG("Hantrodec DEC[%d]  wait_event_interruptible interrupted\n", id);
+    return -ERESTARTSYS;
+  }
+  /* xuanji: simplely imp to get core for single core, exists issue */
+  CheckDecIrq(dev, id);
+
+  atomic_inc(&irq_tx);
+
+  /* refresh registers */
+  return DecRefreshRegs(dev, core);
+}
+
+long PPFlushRegs(hantrodec_t *dev, struct core_desc *core) {
+  long ret = 0;
+  u32 id = core->id;
+  u32 i;
+
+  /* copy original dec regs to kernal space*/
+  ret = copy_from_user(dec_regs[id] + HANTRO_PP_ORG_FIRST_REG,
+                       core->regs + HANTRO_PP_ORG_FIRST_REG,
+                       HANTRO_PP_ORG_REGS*4);
+  if(sizeof(addr_t) == 8) {
+    /* copy extended dec regs to kernal space*/
+    ret = copy_from_user(dec_regs[id] + HANTRO_PP_EXT_FIRST_REG,
+                         core->regs + HANTRO_PP_EXT_FIRST_REG,
+                         HANTRO_PP_EXT_REGS*4);
+  }
+  if (ret) {
+    PDEBUG("Hantrodec copy_from_user failed, returned %li\n", ret);
+    return -EFAULT;
+  }
+
+  /* write all regs but the status reg[1] to hardware */
+  /* both original and extended regs need to be written */
+  for(i = HANTRO_PP_ORG_FIRST_REG + 1; i <= HANTRO_PP_ORG_LAST_REG; i++)
+    iowrite32(dec_regs[id][i], (void*)(dev->hwregs[id] + i*4));
+  if(sizeof(addr_t) == 8) {
+    for(i = HANTRO_PP_EXT_FIRST_REG; i <= HANTRO_PP_EXT_LAST_REG; i++)
+      iowrite32(dec_regs[id][i], (void*)(dev->hwregs[id] + i*4));
+  }
+  /* write the stat reg, which may start the PP */
+  iowrite32(dec_regs[id][HANTRO_PP_ORG_FIRST_REG],
+            (void*)(dev->hwregs[id] + HANTRO_PP_ORG_FIRST_REG * 4));
+
+  return 0;
+}
+
+long PPRefreshRegs(hantrodec_t *dev, struct core_desc *core) {
+  long i, ret;
+  u32 id = core->id;
+  if(sizeof(addr_t) == 8) {
+    /* user has to know exactly what they are asking for */
+    if(core->size != (HANTRO_PP_TOTAL_REGS * 4))
+      return -EFAULT;
+  } else {
+    /* user has to know exactly what they are asking for */
+    if(core->size != (HANTRO_PP_ORG_REGS * 4))
+      return -EFAULT;
+  }
+
+  /* read all registers from hardware */
+  /* both original and extended regs need to be read */
+  for(i = HANTRO_PP_ORG_FIRST_REG; i <= HANTRO_PP_ORG_LAST_REG; i++)
+    dec_regs[id][i] = ioread32((void*)(dev->hwregs[id] + i*4));
+  if(sizeof(addr_t) == 8) {
+    for(i = HANTRO_PP_EXT_FIRST_REG; i <= HANTRO_PP_EXT_LAST_REG; i++)
+      dec_regs[id][i] = ioread32((void*)(dev->hwregs[id] + i*4));
+  }
+  /* put registers to user space*/
+  /* put original registers to user space*/
+  ret = copy_to_user(core->regs + HANTRO_PP_ORG_FIRST_REG,
+                     dec_regs[id] + HANTRO_PP_ORG_FIRST_REG,
+                     HANTRO_PP_ORG_REGS*4);
+  if(sizeof(addr_t) == 8) {
+    /* put extended registers to user space*/
+    ret = copy_to_user(core->regs + HANTRO_PP_EXT_FIRST_REG,
+                       dec_regs[id] + HANTRO_PP_EXT_FIRST_REG,
+                       HANTRO_PP_EXT_REGS * 4);
+  }
+  if (ret) {
+    PDEBUG("Hantrodec copy_to_user failed, returned %li\n", ret);
+    return -EFAULT;
+  }
+
+  return 0;
+}
+
+static int CheckPPIrq(hantrodec_t *dev, int id) {
+  unsigned long flags;
+  int rdy = 0;
+
+  const u32 irq_mask = (1 << id);
+
+  spin_lock_irqsave(&owner_lock, flags);
+
+  if(pp_irq & irq_mask) {
+    /* reset the wait condition(s) */
+    pp_irq &= ~irq_mask;
+    rdy = 1;
+  }
+
+  spin_unlock_irqrestore(&owner_lock, flags);
+
+  return rdy;
+}
+
+long WaitPPReadyAndRefreshRegs(hantrodec_t *dev, struct core_desc *core) {
+  u32 id = core->id;
+
+  PDEBUG("Hantrodec wait_event_interruptible PP[%d]\n", id);
+
+  if(wait_event_interruptible(pp_wait_queue, CheckPPIrq(dev, id))) {
+    PDEBUG("Hantrodec PP[%d]  wait_event_interruptible interrupted\n", id);
+    return -ERESTARTSYS;
+  }
+  /* xuanji: simplely imp to get core for single core, exists issue */
+  CheckPPIrq(dev, id);
+
+  atomic_inc(&irq_tx);
+
+  /* refresh registers */
+  return PPRefreshRegs(dev, core);
+}
+
+static int CheckCoreIrq(hantrodec_t *dev, const int filp, int *id) {
+  unsigned long flags;
+  int rdy = 0, n = 0;
+
+  do {
+    u32 irq_mask = (1 << n);
+
+    spin_lock_irqsave(&owner_lock, flags);
+
+    if(dec_irq & irq_mask) {
+      if (dec_owner[n] == filp) {
+        /* we have an IRQ for our client */
+
+        /* reset the wait condition(s) */
+        dec_irq &= ~irq_mask;
+
+        /* signal ready core no. for our client */
+        *id = n;
+
+        rdy = 1;
+
+        spin_unlock_irqrestore(&owner_lock, flags);
+        break;
+      } else if(dec_owner[n] == 0) {
+        /* zombie IRQ */
+        printk(KERN_INFO "IRQ on core[%d], but no owner!!!\n", n);
+
+        /* reset the wait condition(s) */
+        dec_irq &= ~irq_mask;
+      }
+    }
+
+    spin_unlock_irqrestore(&owner_lock, flags);
+
+    n++; /* next core */
+  } while(n < dev->cores);
+
+  return rdy;
+}
+
+long WaitCoreReady(hantrodec_t *dev, const int filp, int *id) {
+  PDEBUG("Hantrodec wait_event_interruptible CORE\n");
+
+  if(wait_event_interruptible(dec_wait_queue, CheckCoreIrq(dev, filp, id))) {
+    PDEBUG("Hantrodec CORE  wait_event_interruptible interrupted\n");
+    return -ERESTARTSYS;
+  }
+  /* xuanji: simplely imp to get core for single core, exists issue */
+  CheckCoreIrq(dev, filp, id);
+
+  atomic_inc(&irq_tx);
+
+  return 0;
+}
+
+/*------------------------------------------------------------------------------
+ Function name   : hantrodec_ioctl
+ Description     : communication method to/from the user space
+
+ Return type     : long
+------------------------------------------------------------------------------*/
+
+long hantrodec_ioctl(int filp, unsigned int cmd, void *arg) {
+  int err = 0;
+  long tmp;
+#if 0
+#ifdef CLK_CFG
+  unsigned long flags;
+#endif
+#endif
+
+#ifdef HW_PERFORMANCE
+  struct timeval *end_time_arg;
+#endif
+
+  PDEBUG("Hantrodec ioctl cmd 0x%08x\n", cmd);
+  /*
+   * extract the type and number bitfields, and don't decode
+   * wrong cmds: return ENOTTY (inappropriate ioctl) before access_ok()
+   */
+  if (_IOC_TYPE(cmd) != HANTRODEC_IOC_MAGIC &&
+      //_IOC_TYPE(cmd) != HANTRO_IOC_MMU &&
+      _IOC_TYPE(cmd) != HANTRO_VCMD_IOC_MAGIC)
+    return -ENOTTY;
+  if ((_IOC_TYPE(cmd) == HANTRODEC_IOC_MAGIC &&
+      _IOC_NR(cmd) > HANTRODEC_IOC_MAXNR) ||
+      //(_IOC_TYPE(cmd) == HANTRO_IOC_MMU &&
+      //_IOC_NR(cmd) > HANTRO_IOC_MMU_MAXNR) ||
+      (_IOC_TYPE(cmd) == HANTRO_VCMD_IOC_MAGIC &&
+      _IOC_NR(cmd) > HANTRO_VCMD_IOC_MAXNR))
+    return -ENOTTY;
+
+  /*
+   * the direction is a bitmask, and VERIFY_WRITE catches R/W
+   * transfers. `Type' is user-oriented, while
+   * access_ok is kernel-oriented, so the concept of "read" and
+   * "write" is reversed
+   */
+  if (_IOC_DIR(cmd) & _IOC_READ)
+    err = !access_ok(VERIFY_WRITE, (void *) arg, _IOC_SIZE(cmd));
+  else if (_IOC_DIR(cmd) & _IOC_WRITE)
+    err = !access_ok(VERIFY_READ, (void *) arg, _IOC_SIZE(cmd));
+
+  if (err)
+    return -EFAULT;
+
+#if 0
+#ifdef CLK_CFG
+  spin_lock_irqsave(&clk_lock, flags);
+  if (clk_cfg!=NULL && !IS_ERR(clk_cfg)&&(is_clk_on==0)) {
+    printk("Hantrodec turn on clock by user\n");
+    if (clk_enable(clk_cfg)) {
+      spin_unlock_irqrestore(&clk_lock, flags);
+      return -EFAULT;
+    } else
+      is_clk_on=1;
+  }
+  spin_unlock_irqrestore(&clk_lock, flags);
+  mod_timer(&timer, jiffies + 10*HZ); /*the interval is 10s*/
+#endif
+#endif
+
+  switch (cmd) {
+  case HANTRODEC_IOC_CLI: {
+    __u32 id;
+    __get_user(id, (__u32*)arg);
+
+    if(id >= hantrodec_data.cores) {
+      return -EFAULT;
+    }
+    disable_irq(hantrodec_data.irq[id]);
+    break;
+  }
+  case HANTRODEC_IOC_STI: {
+    __u32 id;
+    __get_user(id, (__u32*)arg);
+
+    if(id >= hantrodec_data.cores) {
+      return -EFAULT;
+    }
+    enable_irq(hantrodec_data.irq[id]);
+    break;
+  }
+  case HANTRODEC_IOCGHWOFFSET: {
+    __u32 id;
+    __get_user(id, (__u32*)arg);
+
+    if(id >= hantrodec_data.cores) {
+      return -EFAULT;
+    }
+
+    __put_user(multicorebase_actual[id], (unsigned long *) arg);
+    break;
+  }
+  case HANTRODEC_IOCGHWIOSIZE: {
+    __u32 id;
+    __u32 io_size;
+    __get_user(id, (__u32*)arg);
+
+    if(id >= hantrodec_data.cores) {
+      return -EFAULT;
+    }
+    io_size = hantrodec_data.iosize[id];
+    __put_user(io_size, (u32 *) arg);
+
+    return 0;
+  }
+  case HANTRODEC_IOC_MC_OFFSETS: {
+    tmp = copy_to_user((unsigned long *) arg, multicorebase_actual, sizeof(multicorebase_actual));
+    if (err) {
+      PDEBUG("Hantrodec copy_to_user failed, returned %li\n", tmp);
+      return -EFAULT;
+    }
+    break;
+  }
+  case HANTRODEC_IOC_MC_CORES:
+    __put_user(hantrodec_data.cores, (unsigned int *) arg);
+    PDEBUG("Hantrodec hantrodec_data.cores=%d\n", hantrodec_data.cores);
+    break;
+  case HANTRODEC_IOCS_DEC_PUSH_REG: {
+    struct core_desc core;
+    uint32_t curr_int_status = 0;
+
+    /* get registers from user space*/
+    tmp = copy_from_user(&core, (void*)arg, sizeof(struct core_desc));
+    if (tmp) {
+      PDEBUG("Hantrodec copy_from_user failed, returned %li\n", tmp);
+      return -EFAULT;
+    }
+
+    DecFlushRegs(&hantrodec_data, &core);
+    curr_int_status = ReadInterruptStatus();
+    break;
+  }
+  case HANTRODEC_IOCS_DEC_WRITE_REG: {
+    struct core_desc core;
+
+    /* get registers from user space*/
+    tmp = copy_from_user(&core, (void*)arg, sizeof(struct core_desc));
+    if (tmp) {
+      PDEBUG("Hantrodec copy_from_user failed, returned %li\n", tmp);
+      return -EFAULT;
+    }
+
+    DecWriteRegs(&hantrodec_data, &core);
+    break;
+  }
+  case HANTRODEC_IOCS_PP_PUSH_REG: {
+    struct core_desc core;
+
+    /* get registers from user space*/
+    tmp = copy_from_user(&core, (void*)arg, sizeof(struct core_desc));
+    if (tmp) {
+      PDEBUG("Hantrodec copy_from_user failed, returned %li\n", tmp);
+      return -EFAULT;
+    }
+
+    PPFlushRegs(&hantrodec_data, &core);
+    break;
+  }
+  case HANTRODEC_IOCS_DEC_PULL_REG: {
+    struct core_desc core;
+
+    /* get registers from user space*/
+    tmp = copy_from_user(&core, (void*)arg, sizeof(struct core_desc));
+    if (tmp) {
+      PDEBUG("Hantrodec copy_from_user failed, returned %li\n", tmp);
+      return -EFAULT;
+    }
+
+    return DecRefreshRegs(&hantrodec_data, &core);
+  }
+  case HANTRODEC_IOCS_DEC_READ_REG: {
+    struct core_desc core;
+
+    /* get registers from user space*/
+    tmp = copy_from_user(&core, (void*)arg, sizeof(struct core_desc));
+    if (tmp) {
+      PDEBUG("Hantrodec copy_from_user failed, returned %li\n", tmp);
+      return -EFAULT;
+    }
+
+    return DecReadRegs(&hantrodec_data, &core);
+  }
+  case HANTRODEC_IOCS_PP_PULL_REG: {
+    struct core_desc core;
+
+    /* get registers from user space*/
+    tmp = copy_from_user(&core, (void*)arg, sizeof(struct core_desc));
+    if (tmp) {
+      PDEBUG("Hantrodec copy_from_user failed, returned %li\n", tmp);
+      return -EFAULT;
+    }
+
+    return PPRefreshRegs(&hantrodec_data, &core);
+  }
+  case HANTRODEC_IOCH_DEC_RESERVE: {
+    u32 format = 0;
+    __get_user(format, (unsigned long *)arg);
+    PDEBUG("Hantrodec Reserve DEC core, format = %li\n", format);
+    return ReserveDecoder(&hantrodec_data, filp, format);
+  }
+  case HANTRODEC_IOCT_DEC_RELEASE: {
+    u32 core = *(unsigned long *)arg;
+    if(core >= hantrodec_data.cores || dec_owner[core] != filp) {
+      PDEBUG("Hantrodec bogus DEC release, core = %li\n", core);
+      return -EFAULT;
+    }
+
+    PDEBUG("Hantrodec Release DEC, core = %li\n", core);
+
+    ReleaseDecoder(&hantrodec_data, core);
+
+    break;
+  }
+  case HANTRODEC_IOCQ_PP_RESERVE:
+    return ReservePostProcessor(&hantrodec_data, filp);
+  case HANTRODEC_IOCT_PP_RELEASE: {
+    u32 core = 0;
+    __get_user(core, (unsigned long *)arg);
+    if(core != 0 || pp_owner[core] != filp) {
+      PDEBUG("Hantrodec bogus PP release %li\n", core);
+      return -EFAULT;
+    }
+
+    ReleasePostProcessor(&hantrodec_data, core);
+
+    break;
+  }
+  case HANTRODEC_IOCX_DEC_WAIT: {
+    struct core_desc core;
+
+    /* get registers from user space */
+    tmp = copy_from_user(&core, (void*)arg, sizeof(struct core_desc));
+    if (tmp) {
+      PDEBUG("Hantrodec copy_from_user failed, returned %li\n", tmp);
+      return -EFAULT;
+    }
+
+    return WaitDecReadyAndRefreshRegs(&hantrodec_data, &core);
+  }
+  case HANTRODEC_IOCX_PP_WAIT: {
+    struct core_desc core;
+
+    /* get registers from user space */
+    tmp = copy_from_user(&core, (void*)arg, sizeof(struct core_desc));
+    if (tmp) {
+      PDEBUG("Hantrodec copy_from_user failed, returned %li\n", tmp);
+      return -EFAULT;
+    }
+
+    return WaitPPReadyAndRefreshRegs(&hantrodec_data, &core);
+  }
+  case HANTRODEC_IOCG_CORE_WAIT: {
+    int id;
+    uint32_t curr_int_status = 0;
+    curr_int_status = ReadInterruptStatus();
+    tmp = WaitCoreReady(&hantrodec_data, filp, &id);
+    __put_user(id, (int *) arg);
+    return tmp;
+  }
+  case HANTRODEC_IOX_ASIC_ID: {
+    u32 id;
+    __get_user(id, (u32*)arg);
+
+    if(id >= hantrodec_data.cores) {
+      return -EFAULT;
+    }
+    id = ioread32((void*)(hantrodec_data.hwregs[id]));
+    __put_user(id, (u32 *) arg);
+    return 0;
+  }
+  case HANTRODEC_IOCG_CORE_ID: {
+    u32 format = 0;
+    __get_user(format, (unsigned long *)arg);
+
+    PDEBUG("Hantrodec Get DEC Core_id, format = %li\n", format);
+    return GetDecCoreID(&hantrodec_data, filp, format);
+  }
+  case HANTRODEC_IOX_ASIC_BUILD_ID: {
+    u32 id, hw_id;
+    __get_user(id, (u32*)arg);
+
+    if(id >= hantrodec_data.cores) {
+      return -EFAULT;
+    }
+    hw_id = ioread32((void*)(hantrodec_data.hwregs[id]));
+    if (IS_G1(hw_id >> 16) || IS_G2(hw_id >> 16))
+      __put_user(hw_id, (u32 *) arg);
+    else {
+      hw_id = ioread32((void*)(hantrodec_data.hwregs[id] + HANTRODEC_HW_BUILD_ID_OFF));
+      __put_user(hw_id, (u32 *) arg);
+    }
+    return 0;
+  }
+  case HANTRODEC_DEBUG_STATUS: {
+    printk(KERN_INFO "hantrodec: dec_irq     = 0x%08x \n", dec_irq);
+    printk(KERN_INFO "hantrodec: pp_irq      = 0x%08x \n", pp_irq);
+
+    printk(KERN_INFO "hantrodec: IRQs received/sent2user = %d / %d \n",
+           atomic_read(&irq_rx), atomic_read(&irq_tx));
+
+    for (tmp = 0; tmp < hantrodec_data.cores; tmp++) {
+      printk(KERN_INFO "hantrodec: dec_core[%li] %s\n",
+             tmp, dec_owner[tmp] == NULL ? "FREE" : "RESERVED");
+      printk(KERN_INFO "hantrodec: pp_core[%li]  %s\n",
+             tmp, pp_owner[tmp] == NULL ? "FREE" : "RESERVED");
+    }
+    return 0;
+  }
+  case HANTRODEC_IOX_SUBSYS: {
+    struct subsys_desc subsys = {0};
+    /* TODO(min): check all the subsys */
+    if (vcmd) {
+      subsys.subsys_vcmd_num = 1;
+      subsys.subsys_num = subsys.subsys_vcmd_num;
+    } else {
+      subsys.subsys_num = hantrodec_data.cores;
+      subsys.subsys_vcmd_num = 0;
+    }
+    copy_to_user((u32 *) arg, &subsys, sizeof(struct subsys_desc));
+    return 0;
+  }
+  case HANTRODEC_IOCX_POLL: {
+    hantrodec_isr(&hantrodec_data);
+    return 0;
+  }
+  default:
+    if (_IOC_TYPE(cmd) == HANTRO_VCMD_IOC_MAGIC) {
+      return (hantrovcmd_ioctl(filp, cmd, arg));
+    }
+    return -ENOTTY;
+  }
+
+  return 0;
+}
+
+/*------------------------------------------------------------------------------
+ Function name   : hantrodec_open
+ Description     : open method
+
+ Return type     : int
+------------------------------------------------------------------------------*/
+
+int hantrodec_open(int *inode, int filp) {
+  PDEBUG("Hantrodec dev opened\n");
+  
+  if (vcmd)
+    hantrovcmd_open(inode, filp);
+
+  return 0;
+}
+
+/*------------------------------------------------------------------------------
+ Function name   : hantrodec_release
+ Description     : Release driver
+
+ Return type     : int
+------------------------------------------------------------------------------*/
+
+int hantrodec_release(int *inode, int filp) {
+  int n;
+  hantrodec_t *dev = &hantrodec_data;
+
+  PDEBUG("Hantrodec closing ...\n");
+
+  if (vcmd) {
+    hantrovcmd_release(inode, filp);
+    return 0;
+  }
+
+  for(n = 0; n < dev->cores; n++) {
+    if(dec_owner[n] == filp) {
+      PDEBUG("Hantrodec releasing dec core %i lock\n", n);
+      ReleaseDecoder(dev, n);
+    }
+  }
+
+  for(n = 0; n < 1; n++) {
+    if(pp_owner[n] == filp) {
+      PDEBUG("Hantrodec releasing pp core %i lock\n", n);
+      ReleasePostProcessor(dev, n);
+    }
+  }
+
+  PDEBUG("Hantrodec closed\n");
+  return 0;
+}
+
+#if 0
+#ifdef CLK_CFG
+void hantrodec_disable_clk(unsigned long value) {
+  unsigned long flags;
+  /*entering this function means decoder is idle over expiry.So disable clk*/
+  if (clk_cfg!=NULL && !IS_ERR(clk_cfg)) {
+    spin_lock_irqsave(&clk_lock, flags);
+    if (is_clk_on==1) {
+      clk_disable(clk_cfg);
+      is_clk_on = 0;
+      printk("turned off hantrodec clk\n");
+    }
+    spin_unlock_irqrestore(&clk_lock, flags);
+  }
+}
+#endif
+#endif
+
+/* VFS methods */
+/*
+static struct file_operations hantrodec_fops = {
+  .owner = THIS_MODULE,
+  .open = hantrodec_open,
+  .release = hantrodec_release,
+  .unlocked_ioctl = hantrodec_ioctl,
+  .fasync = NULL
+};
+*/
+
+/*------------------------------------------------------------------------------
+ Function name   : hantrodec_init
+ Description     : Initialize the driver
+
+ Return type     : int
+------------------------------------------------------------------------------*/
+int __init hantrodec_init(void) {
+  int result, i;
+
+  PDEBUG("Hantrodec module init\n");
+
+  CheckSubsysCoreArray(vpu_subsys, &vcmd);
+
+  if (vcmd) {
+    result = hantrovcmd_init();
+    if (result) return result;
+
+    return 0;
+  }
+
+  printk(KERN_INFO "hantrodec: dec/pp kernel module. \n");
+
+  /* If base_port is set, use that for single core legacy mode */
+  if(base_port != 0) {
+    multicorebase[0] = base_port;
+    elements = 1;
+    printk(KERN_INFO "hantrodec: Init single core at 0x%08lx IRQ=%i\n",
+           multicorebase[0], irq[0]);
+  } else {
+    printk(KERN_INFO "hantrodec: Init multi core[0] at 0x%16lx\n"
+           "                      core[1] at 0x%16lx\n"
+           "                      core[2] at 0x%16lx\n"
+           "                      core[3] at 0x%16lx\n"
+           "           IRQ_0=%i\n"
+           "           IRQ_1=%i\n",
+           multicorebase[0], multicorebase[1],
+           multicorebase[2], multicorebase[3],
+           irq[0],irq[1]);
+  }
+
+  hantrodec_data.cores = 0;
+
+  hantrodec_data.iosize[0] = DEC_IO_SIZE_0;
+  hantrodec_data.irq[0] = irq[0];
+  hantrodec_data.iosize[1] = DEC_IO_SIZE_1;
+  hantrodec_data.irq[1] = irq[1];
+
+  for(i=0; i< HXDEC_MAX_CORES; i++) {
+    hantrodec_data.hwregs[i] = 0;
+    /* If user gave less core bases that we have by default,
+     * invalidate default bases
+     */
+    if(elements && i>=elements) {
+      multicorebase[i] = -1;
+    }
+  }
+
+  //hantrodec_data.async_queue_dec = NULL;
+  //hantrodec_data.async_queue_pp = NULL;
+
+  result = register_chrdev(hantrodec_major, "hantrodec", &hantrodec_fops);
+  if(result < 0) {
+    printk(KERN_INFO "hantrodec: unable to get major %d\n", hantrodec_major);
+    goto err;
+  } else if(result != 0) { /* this is for dynamic major */
+    hantrodec_major = result;
+  }
+  
+#if 0
+#ifdef CLK_CFG
+  /* first get clk instance pointer */
+  clk_cfg = clk_get(NULL, CLK_ID);
+  if (!clk_cfg||IS_ERR(clk_cfg)) {
+    printk("get handrodec clk failed!\n");
+    goto err;
+  }
+
+  /* prepare and enable clk */
+  if(clk_prepare_enable(clk_cfg)) {
+    printk("try to enable handrodec clk failed!\n");
+    goto err;
+  }
+  is_clk_on = 1;
+
+  /*init a timer to disable clk*/
+  init_timer(&timer);
+  timer.function = &hantrodec_disable_clk;
+  timer.expires =  jiffies + 100*HZ; //the expires time is 100s
+  add_timer(&timer);
+#endif
+#endif
+
+  result = ReserveIO();
+  if(result < 0) {
+    goto err;
+  }
+
+  memset(dec_owner, 0, sizeof(dec_owner));
+  memset(pp_owner, 0, sizeof(pp_owner));
+
+  sema_init(&dec_core_sem, hantrodec_data.cores);
+  sema_init(&pp_core_sem, 1);
+
+  sem_init(&dec_wait_queue, 0, 0);
+  sem_init(&pp_wait_queue, 0, 0);
+  sem_init(&hw_queue, 0, hantrodec_data.cores);
+  
+  /* read configuration fo all cores */
+  ReadCoreConfig(&hantrodec_data);
+
+  /* reset hardware */
+  ResetAsic(&hantrodec_data);
+
+  /* register irq for each core */
+  if(irq[0] > 0) {
+    result = request_irq(irq[0], hantrodec_isr, IRQF_SHARED, "hantrodec", (void *) &hantrodec_data);
+
+    if(result != 0) {
+      if(result == -EINVAL) {
+        printk(KERN_ERR "hantrodec: Bad irq number or handler\n");
+      } else if(result == -EBUSY) {
+        printk(KERN_ERR "hantrodec: IRQ <%d> busy, change your config\n",
+               hantrodec_data.irq[0]);
+      }
+
+      ReleaseIO();
+      goto err;
+    }
+  } else {
+    printk(KERN_INFO "hantrodec: IRQ not in use!\n");
+  }
+
+  if(irq[1] > 0) {
+    result = request_irq(irq[1], hantrodec_isr,
+//#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18))
+//                         SA_INTERRUPT | SA_SHIRQ,
+//#else
+                         IRQF_SHARED,
+//#endif
+                         "hantrodec", (void *) &hantrodec_data);
+
+    if(result != 0) {
+      if(result == -EINVAL) {
+        printk(KERN_ERR "hantrodec: Bad irq number or handler\n");
+      } else if(result == -EBUSY) {
+        printk(KERN_ERR "hantrodec: IRQ <%d> busy, change your config\n",
+               hantrodec_data.irq[1]);
+      }
+
+      ReleaseIO();
+      goto err;
+    }
+  } else {
+    printk(KERN_INFO "hantrodec: IRQ not in use!\n");
+  }
+
+  printk(KERN_INFO "hantrodec: module inserted. Major = %d\n", hantrodec_major);
+
+  return 0;
+
+err:
+  ReleaseIO();
+  printk(KERN_INFO "hantrodec: module not inserted\n");
+  unregister_chrdev(hantrodec_major, "hantrodec");
+  return result;
+}
+
+/*------------------------------------------------------------------------------
+ Function name   : hantrodec_cleanup
+ Description     : clean up
+
+ Return type     : int
+------------------------------------------------------------------------------*/
+void __exit hantrodec_cleanup(void) {
+  hantrodec_t *dev = &hantrodec_data;
+  int n = 0;
+  /* reset hardware */
+  ResetAsic(dev);
+
+  /* free the IRQ */
+  for (n = 0; n < dev->cores; n++) {
+    if(dev->irq[n] != -1) {
+      free_irq(dev->irq[n], (void *) dev);
+    }
+  }
+
+  ReleaseIO();
+
+#if 0
+#ifdef CLK_CFG
+  if (clk_cfg!=NULL && !IS_ERR(clk_cfg)) {
+    clk_disable_unprepare(clk_cfg);
+    is_clk_on = 0;
+    printk("turned off hantrodec clk\n");
+  }
+
+  /*delete timer*/
+  del_timer(&timer);
+#endif
+#endif
+  unregister_chrdev(hantrodec_major, "hantrodec");
+
+  printk(KERN_INFO "hantrodec: module removed\n");
+  return;
+}
+/*------------------------------------------------------------------------------
+ Function name   : CheckHwId
+ Return type     : int
+------------------------------------------------------------------------------*/
+static int CheckHwId(hantrodec_t * dev) {
+  long int hwid;
+  int i;
+  size_t num_hw = sizeof(DecHwId) / sizeof(*DecHwId);
+
+  int found = 0;
+
+  for (i = 0; i < dev->cores; i++) {
+    if (dev->hwregs[i] != NULL ) {
+      hwid = readl(dev->hwregs[i]);
+      printk(KERN_INFO "hantrodec: core %d HW ID=0x%16lx\n", i, hwid);
+      hwid = (hwid >> 16) & 0xFFFF; /* product version only */
+
+      while (num_hw--) {
+        if (hwid == DecHwId[num_hw]) {
+          printk(KERN_INFO "hantrodec: Supported HW found at 0x%16lx\n",
+                 multicorebase_actual[i]);
+          found++;
+          dev->hw_id[i] = hwid;
+          break;
+        }
+      }
+      if (!found) {
+        printk(KERN_INFO "hantrodec: Unknown HW found at 0x%16lx\n",
+               multicorebase_actual[i]);
+        return 0;
+      }
+      found = 0;
+      num_hw = sizeof(DecHwId) / sizeof(*DecHwId);
+    }
+  }
+
+  return 1;
+}
+
+/*------------------------------------------------------------------------------
+ Function name   : ReserveIO
+ Description     : IO reserve
+
+ Return type     : int
+------------------------------------------------------------------------------*/
+static int ReserveIO(void) {
+  int i = 0;
+  long int hwid = 0;
+  u32 reg = 0;
+
+  memcpy(multicorebase_actual, multicorebase, HXDEC_MAX_CORES * sizeof(unsigned long));
+  memcpy((unsigned int*)(hantrodec_data.iosize), iosize, HXDEC_MAX_CORES * sizeof(unsigned int));
+  memcpy((unsigned int*)(hantrodec_data.irq), irq, HXDEC_MAX_CORES * sizeof(int));
+
+  for (i = 0; i < HXDEC_MAX_CORES; i++) {
+    if (multicorebase_actual[i] != -1) {
+      if (!request_mem_region(multicorebase_actual[i], hantrodec_data.iosize[i],
+                              "hantrodec0")) {
+        printk(KERN_INFO "hantrodec: failed to reserve HW regs\n");
+        return -EBUSY;
+      }
+
+      hantrodec_data.hwregs[i] = (volatile u8 *) ioremap_nocache(multicorebase_actual[i],
+                                 hantrodec_data.iosize[i]);
+
+      if (hantrodec_data.hwregs[i] == NULL ) {
+        printk(KERN_INFO "hantrodec: failed to ioremap HW regs\n");
+        ReleaseIO();
+        return -EBUSY;
+      }
+      hantrodec_data.cores++;
+      config.its_main_core_id[i] = -1;
+      config.its_aux_core_id[i] = -1;
+
+      hwid = ((readl(hantrodec_data.hwregs[i])) >> 16) & 0xFFFF; /* product version only */
+
+      if (IS_VC8000D(hwid)) {
+        reg = readl(hantrodec_data.hwregs[i] + HANTRODEC_SYNTH_CFG_2_OFF);
+        if (((reg >> DWL_H264_PIPELINE_E) & 0x01U) || ((reg >> DWL_JPEG_PIPELINE_E) & 0x01U)) {
+          i++;
+          config.its_aux_core_id[i-1] = i;
+          config.its_main_core_id[i] = i-1;
+          config.its_aux_core_id[i] = -1;
+          multicorebase_actual[i] = multicorebase_actual[i-1] + 0x800;
+          hantrodec_data.iosize[i] = hantrodec_data.iosize[i-1];
+          memcpy(multicorebase_actual+i+1, multicorebase+i,
+                 (HXDEC_MAX_CORES - i - 1) * sizeof(unsigned long));
+          memcpy((unsigned int*)hantrodec_data.iosize+i+1, iosize+i,
+                 (HXDEC_MAX_CORES - i - 1) * sizeof(unsigned int));
+          if (!request_mem_region(multicorebase_actual[i], hantrodec_data.iosize[i],
+                              "hantrodec0")) {
+            printk(KERN_INFO "hantrodec: failed to reserve HW regs\n");
+            return -EBUSY;
+          }
+
+          hantrodec_data.hwregs[i] = (volatile u8 *) ioremap_nocache(multicorebase_actual[i],
+                                     hantrodec_data.iosize[i]);
+
+          if (hantrodec_data.hwregs[i] == NULL ) {
+            printk(KERN_INFO "hantrodec: failed to ioremap HW regs\n");
+            ReleaseIO();
+              return -EBUSY;
+          }
+          hantrodec_data.cores++;
+        }
+      }
+    }
+  }
+
+  /* check for correct HW */
+  if (!CheckHwId(&hantrodec_data)) {
+    ReleaseIO();
+    return -EBUSY;
+  }
+
+  return 0;
+}
+
+/*------------------------------------------------------------------------------
+ Function name   : releaseIO
+ Description     : release
+
+ Return type     : void
+------------------------------------------------------------------------------*/
+
+static void ReleaseIO(void) {
+  int i = 0;
+  for (i = 0; i < hantrodec_data.cores; i++) {
+    if (hantrodec_data.hwregs[i])
+      iounmap((void *) hantrodec_data.hwregs[i]);
+    release_mem_region(multicorebase_actual[i], hantrodec_data.iosize[i]);
+  }
+}
+
+/*------------------------------------------------------------------------------
+ Function name   : hantrodec_isr
+ Description     : interrupt handler
+
+ Return type     : irqreturn_t
+------------------------------------------------------------------------------*/
+static irqreturn_t hantrodec_isr(void *args) {
+  unsigned long flags = 0;
+  unsigned int handled = 0;
+  int i = 0;
+  volatile u8 *hwregs = NULL;
+
+  hantrodec_t *dev = (hantrodec_t *) args;
+  u32 irq_status_dec = 0;
+
+  spin_lock_irqsave(&owner_lock, flags);
+  IntClearIRQStatus(irq[0], 0);
+
+  for(i=0; i<dev->cores; i++) {
+    volatile u8 *hwregs = dev->hwregs[i];
+
+    /* interrupt status register read */
+    irq_status_dec = ioread32((void*)(hwregs + HANTRODEC_IRQ_STAT_DEC_OFF));
+
+    if(irq_status_dec & HANTRODEC_DEC_IRQ) {
+      /* clear dec IRQ */
+      irq_status_dec &= (~HANTRODEC_DEC_IRQ);
+      iowrite32(irq_status_dec, (void*)(hwregs + HANTRODEC_IRQ_STAT_DEC_OFF));
+
+      PDEBUG("Hantrodec decoder IRQ received! core %d\n", i);
+
+      atomic_inc(&irq_rx);
+
+      dec_irq |= (1 << i);
+
+      wake_up_interruptible_all(&dec_wait_queue);
+      handled++;
+    }
+  }
+
+  spin_unlock_irqrestore(&owner_lock, flags);
+
+  if(!handled) {
+    PDEBUG("Hantrodec IRQ received, but not hantrodec's!\n");
+  }
+
+  (void)flags;
+  return IRQ_RETVAL(handled);
+}
+
+/*------------------------------------------------------------------------------
+ Function name   : ResetAsic
+ Description     : reset asic
+
+ Return type     :
+------------------------------------------------------------------------------*/
+void ResetAsic(hantrodec_t * dev) {
+  int i, j;
+  u32 status;
+
+  for (j = 0; j < dev->cores; j++) {
+    status = ioread32((void *)(dev->hwregs[j] + HANTRODEC_IRQ_STAT_DEC_OFF));
+
+    if( status & HANTRODEC_DEC_E) {
+      /* abort with IRQ disabled */
+      status = HANTRODEC_DEC_ABORT | HANTRODEC_DEC_IRQ_DISABLE;
+      iowrite32(status, (void *)(dev->hwregs[j] + HANTRODEC_IRQ_STAT_DEC_OFF));
+    }
+
+    if (IS_G1(dev->hw_id[j]))
+      /* reset PP */
+      iowrite32(0, (void *)(dev->hwregs[j] + HANTRO_IRQ_STAT_PP_OFF));
+
+    for (i = 4; i < dev->iosize[j]; i += 4) {
+      iowrite32(0, (void *)(dev->hwregs[j] + i));
+    }
+  }
+}
+
+/*------------------------------------------------------------------------------
+ Function name   : dump_regs
+ Description     : Dump registers
+
+ Return type     :
+------------------------------------------------------------------------------*/
+#ifdef HANTRODEC_DEBUG
+void dump_regs(hantrodec_t *dev) {
+  int i,c;
+
+  PDEBUG("Hantrodec Reg Dump Start\n");
+  for(c = 0; c < dev->cores; c++) {
+    for(i = 0; i < dev->iosize[c]; i += 4*4) {
+      PDEBUG("\toffset %04X: %08X  %08X  %08X  %08X\n", i,
+             ioread32(dev->hwregs[c] + i),
+             ioread32(dev->hwregs[c] + i + 4),
+             ioread32(dev->hwregs[c] + i + 16),
+             ioread32(dev->hwregs[c] + i + 24));
+    }
+  }
+  PDEBUG("Hantrodec Reg Dump End\n");
+}
+#endif
+
+av_unused int RegisterIRQ(i32 irq_offset, IRQHandler isr_handler, i32 flag, const char* name, void* data) {
+//_xtos_set_interrupt_handle
+  u32 irq_mask = 1 << irq_offset; //irq_offset -> Irq[0] is 3
+  u32 enabled_int = 0;
+  if ((xthal_get_intenable() & irq_mask) == 0)
+  {
+    /* Clear MCPU DB2 interrupt before enable */
+    xthal_set_intclear(irq_mask);
+    /* Assign Interrupt handler */
+    xt_set_interrupt_handler(irq_offset, (xt_handler) isr_handler, data);
+
+    *((volatile uint32_t *)0x0280004c) = 0x1; // clear current irq  for slice 0
+    *((volatile uint32_t *)0x02800050) = 0x1; // enable dec irq  for slice 0
+
+    xt_ints_on(irq_mask);
+  }
+  enabled_int = xthal_get_intenable();
+  printf("INTs are enabled: 0x%x\n", enabled_int);
+  return 0;
+}
+
+av_unused void IntEnableIRQ(u32 irq_offset) {
+  //_xtos_interrupt_enable
+  u32 irq_mask = 1 << irq_offset;
+  u32 enabled_int = 0;
+  xt_ints_on(irq_mask);
+
+  enabled_int = xthal_get_intenable();
+  printf("INTs are enabled 2: 0x%x\n", enabled_int);
+}
+
+av_unused void IntDisableIRQ(u32 irq_offset) {
+  //_xtos_interrupt_disable
+  u32 irq_mask = 1 << irq_offset;
+  u32 enabled_int = 0;
+  xt_ints_off(irq_mask);
+  enabled_int = xthal_get_intenable();
+  printf("INTs are disabled 3: 0x%x\n", enabled_int);
+}
+
+av_unused void IntClearIRQStatus(u32 irq_offset, u32 type) {
+  //xthal_set_intclear
+  *((volatile uint32_t *)0x0280004c) = 0x1; // clear current irq for slice 0
+  u32 irq_mask = 1 << irq_offset;
+  xthal_set_intclear(irq_mask);
+}
+
+static inline uint32_t ReadInterruptStatus(void) {
+  uint32_t interrupt;
+  __asm__ __volatile__("rsr %0, interrupt": "=a"(interrupt));
+  return interrupt;
+}
+//For debug
+av_unused u32 IntGetIRQStatus(u32 irq_offset) {
+  uint32_t ret_val;
+  //ReadInterruptStatus
+  ret_val = ReadInterruptStatus();
+  //mask other interrupts ?
+  ret_val &= (1 << irq_offset);
+  // return 1 if requested interrupt is set
+  if (ret_val)
+    ret_val = 1;
+  return 0;
+}

+ 3843 - 0
linux/subsys_driver/freertos/hantro_vcmd_freertos.c

@@ -0,0 +1,3843 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2021 VERISILICON
+*
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2021 VERISILICON
+*
+*    This program is free software; you can redistribute it and/or
+*    modify it under the terms of the GNU General Public License
+*    as published by the Free Software Foundation; either version 2
+*    of the License, or (at your option) any later version.
+*
+*    This program is distributed in the hope that it will be useful,
+*    but WITHOUT ANY WARRANTY; without even the implied warranty of
+*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*    GNU General Public License for more details.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+/*------------------------------------------------------------------------------
+--  Abstract : vc8000 Vcmd device driver (kernel module)
+------------------------------------------------------------------------------*/
+/* our own stuff */
+#include "vcmdswhwregisters.h"
+#include "bidirect_list.h"
+#include "hantrovcmd.h"
+#include "subsys.h"
+#include "io_tools.h"
+#include "osal.h"
+#include "memalloc_freertos.h"
+
+//Netint xtensa cpu and FreeRTOS OS
+#include "xtensa_api.h"
+//#include "../src/libxmp/xmp-library.h" //For atomic operations
+#include <xtensa/xtruntime.h> //interrupt for xtensa
+
+/*
+ * Macros to help debugging
+ */
+
+#undef PDEBUG   /* undef it, just in case */
+#ifdef HANTRO_VCMD_DRIVER_DEBUG
+#  ifdef __KERNEL__
+    /* This one if debugging is on, and kernel space */
+#    define PDEBUG(fmt, args...) printk( KERN_INFO "vc8000_vcmd: " fmt, ## args)
+#  else
+    /* This one for user space */
+#    define PDEBUG(fmt, args...) printf(":%d: " fmt, __LINE__ , ## args)
+#  endif
+#else
+#  define PDEBUG(fmt, args...)  /* not debugging: nothing */
+#endif
+
+/*-----------------------------------------------------------------------------------------
+************************CPU Xtensa OS FreeRTOS PORTING LAYER*******************************
+------------------------------------------------------------------------------------------*/
+static u32 g_vc8000_int_enable_mask = 0;
+//VCMD for netint
+#define SYS_REG_INT_TOP_BASE     (0x02800000)
+//ENCODER
+#if 0
+#define CPU_INT_IRQ              8 /* All Encoder Modules' interrupt will be connected to CPU IRQ 8 */
+#define SYS_INT_MASK             (0x220)
+#define SYS_REG_INT_VAL          (SYS_REG_INT_TOP_BASE + 0x3c)
+#define SYS_REG_INT_STAT         (SYS_REG_INT_TOP_BASE + 0x40)
+#define SYS_REG_INT_EN           (SYS_REG_INT_TOP_BASE + 0x44)
+#else
+//DECODER
+#define CPU_INT_IRQ              9
+#define SYS_INT_MASK             (0x001)
+#define SYS_REG_INT_VAL          (SYS_REG_INT_TOP_BASE + 0x48)
+#define SYS_REG_INT_STAT         (SYS_REG_INT_TOP_BASE + 0x4c)
+#define SYS_REG_INT_EN           (SYS_REG_INT_TOP_BASE + 0x50)
+#endif
+/*------------------------------------------------------------------------
+*****************************VCMD CONFIGURATION BY CUSTOMER********************************
+-------------------------------------------------------------------------*/
+//video encoder vcmd configuration
+#define VCMD_ENC_IO_ADDR_0                      0x90000  /*customer specify according to own platform*/
+#define VCMD_ENC_IO_SIZE_0                      (ASIC_VCMD_SWREG_AMOUNT * 4)    /* bytes */
+#define VCMD_ENC_INT_PIN_0                      -1
+#define VCMD_ENC_MODULE_TYPE_0                  0
+#define VCMD_ENC_MODULE_MAIN_ADDR_0             0x0000    /*customer specify according to own platform*/
+#define VCMD_ENC_MODULE_DEC400_ADDR_0           0XFFFF    /*0xffff means no such kind of submodule*/
+#define VCMD_ENC_MODULE_L2CACHE_ADDR_0          0XFFFF
+#define VCMD_ENC_MODULE_MMU_ADDR_0              0XFFFF
+
+#define VCMD_ENC_IO_ADDR_1                      (0x02300000 + 0x40000)       /*customer specify according to own platform*/
+#define VCMD_ENC_IO_SIZE_1                      (ASIC_VCMD_SWREG_AMOUNT * 4) /* bytes */
+#define VCMD_ENC_INT_PIN_1                      5
+#define VCMD_ENC_MODULE_TYPE_1                  0
+#define VCMD_ENC_MODULE_MAIN_ADDR_1             0x1000   /*customer specify according to own platform*/
+#define VCMD_ENC_MODULE_DEC400_ADDR_1           0X2000 /*0xffff means no such kind of submodule*/
+#define VCMD_ENC_MODULE_L2CACHE_ADDR_1          0XFFFF
+#define VCMD_ENC_MODULE_MMU_ADDR_1              0XFFFF
+
+#define VCMD_ENC_IO_ADDR_2                      0x92000   /*customer specify according to own platform*/
+#define VCMD_ENC_IO_SIZE_2                      (ASIC_VCMD_SWREG_AMOUNT * 4)    /* bytes */
+#define VCMD_ENC_INT_PIN_2                      -1
+#define VCMD_ENC_MODULE_TYPE_2                  0
+#define VCMD_ENC_MODULE_MAIN_ADDR_2             0x0000    /*customer specify according to own platform*/
+#define VCMD_ENC_MODULE_DEC400_ADDR_2           0XFFFF    /*0xffff means no such kind of submodule*/
+#define VCMD_ENC_MODULE_L2CACHE_ADDR_2          0XFFFF
+#define VCMD_ENC_MODULE_MMU_ADDR_2              0XFFFF
+
+#define VCMD_ENC_IO_ADDR_3                      0x93000   /*customer specify according to own platform*/
+#define VCMD_ENC_IO_SIZE_3                      (ASIC_VCMD_SWREG_AMOUNT * 4)    /* bytes */
+#define VCMD_ENC_INT_PIN_3                      -1
+#define VCMD_ENC_MODULE_TYPE_3                  0
+#define VCMD_ENC_MODULE_MAIN_ADDR_3             0x0000    /*customer specify according to own platform*/
+#define VCMD_ENC_MODULE_DEC400_ADDR_3           0XFFFF    /*0xffff means no such kind of submodule*/
+#define VCMD_ENC_MODULE_L2CACHE_ADDR_3          0XFFFF
+#define VCMD_ENC_MODULE_MMU_ADDR_3              0XFFFF
+
+//video encoder cutree/IM  vcmd configuration
+#define VCMD_IM_IO_ADDR_0                      0xa00000    /*customer specify according to own platform*/
+#define VCMD_IM_IO_SIZE_0                      (ASIC_VCMD_SWREG_AMOUNT * 4)    /* bytes */
+#define VCMD_IM_INT_PIN_0                      -1
+#define VCMD_IM_MODULE_TYPE_0                  1
+#define VCMD_IM_MODULE_MAIN_ADDR_0             0x0000     /*customer specify according to own platform*/
+#define VCMD_IM_MODULE_DEC400_ADDR_0           0XFFFF     /*0xffff means no such kind of submodule*/
+#define VCMD_IM_MODULE_L2CACHE_ADDR_0          0XFFFF
+#define VCMD_IM_MODULE_MMU_ADDR_0              0XFFFF
+
+#define VCMD_IM_IO_ADDR_1                      (0x02300000 + 0x44000)    /*customer specify according to own platform*/
+#define VCMD_IM_IO_SIZE_1                      (ASIC_VCMD_SWREG_AMOUNT * 4)    /* bytes */
+#define VCMD_IM_INT_PIN_1                      9
+#define VCMD_IM_MODULE_TYPE_1                  1
+#define VCMD_IM_MODULE_MAIN_ADDR_1             0x1000     /*customer specify according to own platform*/
+#define VCMD_IM_MODULE_DEC400_ADDR_1           0XFFFF     /*0xffff means no such kind of submodule*/
+#define VCMD_IM_MODULE_L2CACHE_ADDR_1          0XFFFF
+#define VCMD_IM_MODULE_MMU_ADDR_1              0XFFFF
+
+#define VCMD_IM_IO_ADDR_2                      0xa2000    /*customer specify according to own platform*/
+#define VCMD_IM_IO_SIZE_2                      (ASIC_VCMD_SWREG_AMOUNT * 4)    /* bytes */
+#define VCMD_IM_INT_PIN_2                      -1
+#define VCMD_IM_MODULE_TYPE_2                  1
+#define VCMD_IM_MODULE_MAIN_ADDR_2             0x0000     /*customer specify according to own platform*/
+#define VCMD_IM_MODULE_DEC400_ADDR_2           0XFFFF     /*0xffff means no such kind of submodule*/
+#define VCMD_IM_MODULE_L2CACHE_ADDR_2          0XFFFF
+#define VCMD_IM_MODULE_MMU_ADDR_2              0XFFFF
+
+#define VCMD_IM_IO_ADDR_3                      0xa3000    /*customer specify according to own platform*/
+#define VCMD_IM_IO_SIZE_3                      (ASIC_VCMD_SWREG_AMOUNT * 4)    /* bytes */
+#define VCMD_IM_INT_PIN_3                      -1
+#define VCMD_IM_MODULE_TYPE_3                  1
+#define VCMD_IM_MODULE_MAIN_ADDR_3             0x0000     /*customer specify according to own platform*/
+#define VCMD_IM_MODULE_DEC400_ADDR_3           0XFFFF     /*0xffff means no such kind of submodule*/
+#define VCMD_IM_MODULE_L2CACHE_ADDR_3          0XFFFF
+#define VCMD_IM_MODULE_MMU_ADDR_3              0XFFFF
+
+//video decoder vcmd configuration
+#define VCMD_DEC_IO_ADDR_0                      0x02310000 /*customer specify according to own platform*/
+#define VCMD_DEC_IO_SIZE_0                      (ASIC_VCMD_SWREG_AMOUNT * 4)    /* bytes */
+#define VCMD_DEC_INT_PIN_0                      0
+#define VCMD_DEC_MODULE_TYPE_0                  2
+#define VCMD_DEC_MODULE_MAIN_ADDR_0             0x2000    /*customer specify according to own platform*/
+#define VCMD_DEC_MODULE_DEC400_ADDR_0           0X6000   /*0xffff means no such kind of submodule*/
+#define VCMD_DEC_MODULE_L2CACHE_ADDR_0          0X4000
+#define VCMD_DEC_MODULE_MMU_ADDR_0              0XFFFF
+
+#define VCMD_DEC_IO_ADDR_1                      0xb1000   /*customer specify according to own platform*/
+#define VCMD_DEC_IO_SIZE_1                      (ASIC_VCMD_SWREG_AMOUNT * 4)    /* bytes */
+#define VCMD_DEC_INT_PIN_1                      -1
+#define VCMD_DEC_MODULE_TYPE_1                  2
+#define VCMD_DEC_MODULE_MAIN_ADDR_1             0x0000    /*customer specify according to own platform*/
+#define VCMD_DEC_MODULE_DEC400_ADDR_1           0XFFFF    /*0xffff means no such kind of submodule*/
+#define VCMD_DEC_MODULE_L2CACHE_ADDR_1          0XFFFF
+#define VCMD_DEC_MODULE_MMU_ADDR_1              0XFFFF
+
+#define VCMD_DEC_IO_ADDR_2                      0xb2000   /*customer specify according to own platform*/
+#define VCMD_DEC_IO_SIZE_2                      (ASIC_VCMD_SWREG_AMOUNT * 4)    /* bytes */
+#define VCMD_DEC_INT_PIN_2                      -1
+#define VCMD_DEC_MODULE_TYPE_2                  2
+#define VCMD_DEC_MODULE_MAIN_ADDR_2             0x0000    /*customer specify according to own platform*/
+#define VCMD_DEC_MODULE_DEC400_ADDR_2           0XFFFF    /*0xffff means no such kind of submodule*/
+#define VCMD_DEC_MODULE_L2CACHE_ADDR_2          0XFFFF
+#define VCMD_DEC_MODULE_MMU_ADDR_2              0XFFFF
+
+#define VCMD_DEC_IO_ADDR_3                      0xb3000   /*customer specify according to own platform*/
+#define VCMD_DEC_IO_SIZE_3                      (ASIC_VCMD_SWREG_AMOUNT * 4)    /* bytes */
+#define VCMD_DEC_INT_PIN_3                      -1
+#define VCMD_DEC_MODULE_TYPE_3                  2
+#define VCMD_DEC_MODULE_MAIN_ADDR_3             0x0000    /*customer specify according to own platform*/
+#define VCMD_DEC_MODULE_DEC400_ADDR_3           0XFFFF    /*0xffff means no such kind of submodule*/
+#define VCMD_DEC_MODULE_L2CACHE_ADDR_3          0XFFFF
+#define VCMD_DEC_MODULE_MMU_ADDR_3              0XFFFF
+
+//JPEG encoder vcmd configuration
+#define VCMD_JPEGE_IO_ADDR_0                      0x90000   /*customer specify according to own platform*/
+#define VCMD_JPEGE_IO_SIZE_0                      (ASIC_VCMD_SWREG_AMOUNT * 4)    /* bytes */
+#define VCMD_JPEGE_INT_PIN_0                      -1
+#define VCMD_JPEGE_MODULE_TYPE_0                  3
+#define VCMD_JPEGE_MODULE_MAIN_ADDR_0             0x1000    /*customer specify according to own platform*/
+#define VCMD_JPEGE_MODULE_DEC400_ADDR_0           0XFFFF    /*0xffff means no such kind of submodule*/
+#define VCMD_JPEGE_MODULE_L2CACHE_ADDR_0          0XFFFF
+#define VCMD_JPEGE_MODULE_MMU_ADDR_0              0XFFFF
+
+#define VCMD_JPEGE_IO_ADDR_1                      0xC1000   /*customer specify according to own platform*/
+#define VCMD_JPEGE_IO_SIZE_1                      (ASIC_VCMD_SWREG_AMOUNT * 4)    /* bytes */
+#define VCMD_JPEGE_INT_PIN_1                      -1
+#define VCMD_JPEGE_MODULE_TYPE_1                  3
+#define VCMD_JPEGE_MODULE_MAIN_ADDR_1             0x0000    /*customer specify according to own platform*/
+#define VCMD_JPEGE_MODULE_DEC400_ADDR_1           0XFFFF    /*0xffff means no such kind of submodule*/
+#define VCMD_JPEGE_MODULE_L2CACHE_ADDR_1          0XFFFF
+#define VCMD_JPEGE_MODULE_MMU_ADDR_1              0XFFFF
+
+#define VCMD_JPEGE_IO_ADDR_2                      0xC2000   /*customer specify according to own platform*/
+#define VCMD_JPEGE_IO_SIZE_2                      (ASIC_VCMD_SWREG_AMOUNT * 4)    /* bytes */
+#define VCMD_JPEGE_INT_PIN_2                      -1
+#define VCMD_JPEGE_MODULE_TYPE_2                  3
+#define VCMD_JPEGE_MODULE_MAIN_ADDR_2             0x0000    /*customer specify according to own platform*/
+#define VCMD_JPEGE_MODULE_DEC400_ADDR_2           0XFFFF    /*0xffff means no such kind of submodule*/
+#define VCMD_JPEGE_MODULE_L2CACHE_ADDR_2          0XFFFF
+#define VCMD_JPEGE_MODULE_MMU_ADDR_2              0XFFFF
+
+#define VCMD_JPEGE_IO_ADDR_3                      0xC3000   /*customer specify according to own platform*/
+#define VCMD_JPEGE_IO_SIZE_3                      (ASIC_VCMD_SWREG_AMOUNT * 4)    /* bytes */
+#define VCMD_JPEGE_INT_PIN_3                      -1
+#define VCMD_JPEGE_MODULE_TYPE_3                  3
+#define VCMD_JPEGE_MODULE_MAIN_ADDR_3             0x0000    /*customer specify according to own platform*/
+#define VCMD_JPEGE_MODULE_DEC400_ADDR_3           0XFFFF    /*0xffff means no such kind of submodule*/
+#define VCMD_JPEGE_MODULE_L2CACHE_ADDR_3          0XFFFF
+#define VCMD_JPEGE_MODULE_MMU_ADDR_3              0XFFFF
+
+//JPEG decoder vcmd configuration
+#define VCMD_JPEGD_IO_ADDR_0                      0xD0000   /*customer specify according to own platform*/
+#define VCMD_JPEGD_IO_SIZE_0                      (ASIC_VCMD_SWREG_AMOUNT * 4)    /* bytes */
+#define VCMD_JPEGD_INT_PIN_0                      -1
+#define VCMD_JPEGD_MODULE_TYPE_0                  4
+#define VCMD_JPEGD_MODULE_MAIN_ADDR_0             0x0000    /*customer specify according to own platform*/
+#define VCMD_JPEGD_MODULE_DEC400_ADDR_0           0XFFFF    /*0xffff means no such kind of submodule*/
+#define VCMD_JPEGD_MODULE_L2CACHE_ADDR_0          0XFFFF
+#define VCMD_JPEGD_MODULE_MMU_ADDR_0              0XFFFF
+
+#define VCMD_JPEGD_IO_ADDR_1                      0xD1000   /*customer specify according to own platform*/
+#define VCMD_JPEGD_IO_SIZE_1                      (ASIC_VCMD_SWREG_AMOUNT * 4)    /* bytes */
+#define VCMD_JPEGD_INT_PIN_1                      -1
+#define VCMD_JPEGD_MODULE_TYPE_1                  4
+#define VCMD_JPEGD_MODULE_MAIN_ADDR_1             0x0000    /*customer specify according to own platform*/
+#define VCMD_JPEGD_MODULE_DEC400_ADDR_1           0XFFFF    /*0xffff means no such kind of submodule*/
+#define VCMD_JPEGD_MODULE_L2CACHE_ADDR_1          0XFFFF
+#define VCMD_JPEGD_MODULE_MMU_ADDR_1              0XFFFF
+
+#define VCMD_JPEGD_IO_ADDR_2                      0xD2000   /*customer specify according to own platform*/
+#define VCMD_JPEGD_IO_SIZE_2                      (ASIC_VCMD_SWREG_AMOUNT * 4)    /* bytes */
+#define VCMD_JPEGD_INT_PIN_2                      -1
+#define VCMD_JPEGD_MODULE_TYPE_2                  4
+#define VCMD_JPEGD_MODULE_MAIN_ADDR_2             0x0000    /*customer specify according to own platform*/
+#define VCMD_JPEGD_MODULE_DEC400_ADDR_2           0XFFFF    /*0xffff means no such kind of submodule*/
+#define VCMD_JPEGD_MODULE_L2CACHE_ADDR_2          0XFFFF
+#define VCMD_JPEGD_MODULE_MMU_ADDR_2              0XFFFF
+
+#define VCMD_JPEGD_IO_ADDR_3                      0xD3000   /*customer specify according to own platform*/
+#define VCMD_JPEGD_IO_SIZE_3                      (ASIC_VCMD_SWREG_AMOUNT * 4)    /* bytes */
+#define VCMD_JPEGD_INT_PIN_3                      -1
+#define VCMD_JPEGD_MODULE_TYPE_3                  4
+#define VCMD_JPEGD_MODULE_MAIN_ADDR_3             0x0000    /*customer specify according to own platform*/
+#define VCMD_JPEGD_MODULE_DEC400_ADDR_3           0XFFFF    /*0xffff means no such kind of submodule*/
+#define VCMD_JPEGD_MODULE_L2CACHE_ADDR_3          0XFFFF
+#define VCMD_JPEGD_MODULE_MMU_ADDR_3              0XFFFF
+
+#define NETINT
+//#define MAGVII
+
+/*for all vcmds, the core info should be listed here for subsequent use*/
+struct vcmd_config vcmd_core_array[] = {
+//encoder configuration
+#if 0
+    {VCMD_ENC_IO_ADDR_0,
+    VCMD_ENC_IO_SIZE_0,
+    VCMD_ENC_INT_PIN_0,
+    VCMD_ENC_MODULE_TYPE_0,
+    VCMD_ENC_MODULE_MAIN_ADDR_0,
+    VCMD_ENC_MODULE_DEC400_ADDR_0,
+    VCMD_ENC_MODULE_L2CACHE_ADDR_0,
+    VCMD_ENC_MODULE_MMU_ADDR_0},
+
+    {VCMD_ENC_IO_ADDR_1,
+    VCMD_ENC_IO_SIZE_1,
+    VCMD_ENC_INT_PIN_1,
+    VCMD_ENC_MODULE_TYPE_1,
+    VCMD_ENC_MODULE_MAIN_ADDR_1,
+    VCMD_ENC_MODULE_DEC400_ADDR_1,
+    VCMD_ENC_MODULE_L2CACHE_ADDR_1,
+    VCMD_ENC_MODULE_MMU_ADDR_1},
+
+    {VCMD_ENC_IO_ADDR_2,
+    VCMD_ENC_IO_SIZE_2,
+    VCMD_ENC_INT_PIN_2,
+    VCMD_ENC_MODULE_TYPE_2,
+    VCMD_ENC_MODULE_MAIN_ADDR_2,
+    VCMD_ENC_MODULE_DEC400_ADDR_2,
+    VCMD_ENC_MODULE_L2CACHE_ADDR_2,
+    VCMD_ENC_MODULE_MMU_ADDR_2},
+
+    {VCMD_ENC_IO_ADDR_3,
+    VCMD_ENC_IO_SIZE_3,
+    VCMD_ENC_INT_PIN_3,
+    VCMD_ENC_MODULE_TYPE_3,
+    VCMD_ENC_MODULE_MAIN_ADDR_3,
+    VCMD_ENC_MODULE_DEC400_ADDR_3,
+    VCMD_ENC_MODULE_L2CACHE_ADDR_3,
+    VCMD_ENC_MODULE_MMU_ADDR_3},
+
+//cutree/IM configuration
+
+    {VCMD_IM_IO_ADDR_0,
+    VCMD_IM_IO_SIZE_0,
+    VCMD_IM_INT_PIN_0,
+    VCMD_IM_MODULE_TYPE_0,
+    VCMD_IM_MODULE_MAIN_ADDR_0,
+    VCMD_IM_MODULE_DEC400_ADDR_0,
+    VCMD_IM_MODULE_L2CACHE_ADDR_0,
+    VCMD_IM_MODULE_MMU_ADDR_0},
+
+    {VCMD_IM_IO_ADDR_1,
+    VCMD_IM_IO_SIZE_1,
+    VCMD_IM_INT_PIN_1,
+    VCMD_IM_MODULE_TYPE_1,
+    VCMD_IM_MODULE_MAIN_ADDR_1,
+    VCMD_IM_MODULE_DEC400_ADDR_1,
+    VCMD_IM_MODULE_L2CACHE_ADDR_1,
+    VCMD_IM_MODULE_MMU_ADDR_1},
+
+    {VCMD_IM_IO_ADDR_2,
+    VCMD_IM_IO_SIZE_2,
+    VCMD_IM_INT_PIN_2,
+    VCMD_IM_MODULE_TYPE_2,
+    VCMD_IM_MODULE_MAIN_ADDR_2,
+    VCMD_IM_MODULE_DEC400_ADDR_2,
+    VCMD_IM_MODULE_L2CACHE_ADDR_2,
+    VCMD_IM_MODULE_MMU_ADDR_2},
+
+    {VCMD_IM_IO_ADDR_3,
+    VCMD_IM_IO_SIZE_3,
+    VCMD_IM_INT_PIN_3,
+    VCMD_IM_MODULE_TYPE_3,
+    VCMD_IM_MODULE_MAIN_ADDR_3,
+    VCMD_IM_MODULE_DEC400_ADDR_3,
+    VCMD_IM_MODULE_L2CACHE_ADDR_3,
+    VCMD_IM_MODULE_MMU_ADDR_3},
+#endif
+#ifdef NETINT
+//decoder configuration
+    {VCMD_DEC_IO_ADDR_0,
+    VCMD_DEC_IO_SIZE_0,
+    VCMD_DEC_INT_PIN_0,
+    VCMD_DEC_MODULE_TYPE_0,
+    VCMD_DEC_MODULE_MAIN_ADDR_0,
+    VCMD_DEC_MODULE_DEC400_ADDR_0,
+    VCMD_DEC_MODULE_L2CACHE_ADDR_0,
+    VCMD_DEC_MODULE_MMU_ADDR_0},
+#endif
+#if 0
+    {VCMD_DEC_IO_ADDR_1,
+    VCMD_DEC_IO_SIZE_1,
+    VCMD_DEC_INT_PIN_1,
+    VCMD_DEC_MODULE_TYPE_1,
+    VCMD_DEC_MODULE_MAIN_ADDR_1,
+    VCMD_DEC_MODULE_DEC400_ADDR_1,
+    VCMD_DEC_MODULE_L2CACHE_ADDR_1,
+    VCMD_DEC_MODULE_MMU_ADDR_1},
+
+    {VCMD_DEC_IO_ADDR_2,
+    VCMD_DEC_IO_SIZE_2,
+    VCMD_DEC_INT_PIN_2,
+    VCMD_DEC_MODULE_TYPE_2,
+    VCMD_DEC_MODULE_MAIN_ADDR_2,
+    VCMD_DEC_MODULE_DEC400_ADDR_2,
+    VCMD_DEC_MODULE_L2CACHE_ADDR_2,
+    VCMD_DEC_MODULE_MMU_ADDR_2},
+
+    {VCMD_DEC_IO_ADDR_3,
+    VCMD_DEC_IO_SIZE_3,
+    VCMD_DEC_INT_PIN_3,
+    VCMD_DEC_MODULE_TYPE_3,
+    VCMD_DEC_MODULE_MAIN_ADDR_3,
+    VCMD_DEC_MODULE_DEC400_ADDR_3,
+    VCMD_DEC_MODULE_L2CACHE_ADDR_3,
+    VCMD_DEC_MODULE_MMU_ADDR_3},
+#endif
+#ifdef MAGVII
+    //JPEG encoder configuration
+    {VCMD_JPEGE_IO_ADDR_0,
+     VCMD_JPEGE_IO_SIZE_0,
+     VCMD_JPEGE_INT_PIN_0,
+     VCMD_JPEGE_MODULE_TYPE_0,
+     VCMD_JPEGE_MODULE_MAIN_ADDR_0,
+     VCMD_JPEGE_MODULE_DEC400_ADDR_0,
+     VCMD_JPEGE_MODULE_L2CACHE_ADDR_0,
+     VCMD_JPEGE_MODULE_MMU_ADDR_0},
+#endif
+#if 0
+    {VCMD_JPEGE_IO_ADDR_1,
+    VCMD_JPEGE_IO_SIZE_1,
+    VCMD_JPEGE_INT_PIN_1,
+    VCMD_JPEGE_MODULE_TYPE_1,
+    VCMD_JPEGE_MODULE_MAIN_ADDR_1,
+    VCMD_JPEGE_MODULE_DEC400_ADDR_1,
+    VCMD_JPEGE_MODULE_L2CACHE_ADDR_1,
+    VCMD_JPEGE_MODULE_MMU_ADDR_1},
+
+    {VCMD_JPEGE_IO_ADDR_2,
+    VCMD_JPEGE_IO_SIZE_2,
+    VCMD_JPEGE_INT_PIN_2,
+    VCMD_JPEGE_MODULE_TYPE_2,
+    VCMD_JPEGE_MODULE_MAIN_ADDR_2,
+    VCMD_JPEGE_MODULE_DEC400_ADDR_2,
+    VCMD_JPEGE_MODULE_L2CACHE_ADDR_2,
+    VCMD_JPEGE_MODULE_MMU_ADDR_2},
+
+    {VCMD_JPEGE_IO_ADDR_3,
+    VCMD_JPEGE_IO_SIZE_3,
+    VCMD_JPEGE_INT_PIN_3,
+    VCMD_JPEGE_MODULE_TYPE_3,
+    VCMD_JPEGE_MODULE_MAIN_ADDR_3,
+    VCMD_JPEGE_MODULE_DEC400_ADDR_3,
+    VCMD_JPEGE_MODULE_L2CACHE_ADDR_3,
+    VCMD_JPEGE_MODULE_MMU_ADDR_3},
+//JPEG decoder configuration
+    {VCMD_JPEGD_IO_ADDR_0,
+    VCMD_JPEGD_IO_SIZE_0,
+    VCMD_JPEGD_INT_PIN_0,
+    VCMD_JPEGD_MODULE_TYPE_0,
+    VCMD_JPEGD_MODULE_MAIN_ADDR_0,
+    VCMD_JPEGD_MODULE_DEC400_ADDR_0,
+    VCMD_JPEGD_MODULE_L2CACHE_ADDR_0,
+    VCMD_JPEGD_MODULE_MMU_ADDR_0},
+
+    {VCMD_JPEGD_IO_ADDR_1,
+    VCMD_JPEGD_IO_SIZE_1,
+    VCMD_JPEGD_INT_PIN_1,
+    VCMD_JPEGD_MODULE_TYPE_1,
+    VCMD_JPEGD_MODULE_MAIN_ADDR_1,
+    VCMD_JPEGD_MODULE_DEC400_ADDR_1,
+    VCMD_JPEGD_MODULE_L2CACHE_ADDR_1,
+    VCMD_JPEGD_MODULE_MMU_ADDR_1},
+
+    {VCMD_JPEGD_IO_ADDR_2,
+    VCMD_JPEGD_IO_SIZE_2,
+    VCMD_JPEGD_INT_PIN_2,
+    VCMD_JPEGD_MODULE_TYPE_2,
+    VCMD_JPEGD_MODULE_MAIN_ADDR_2,
+    VCMD_JPEGD_MODULE_DEC400_ADDR_2,
+    VCMD_JPEGD_MODULE_L2CACHE_ADDR_2,
+    VCMD_JPEGD_MODULE_MMU_ADDR_2},
+
+    {VCMD_JPEGD_IO_ADDR_3,
+    VCMD_JPEGD_IO_SIZE_3,
+    VCMD_JPEGD_INT_PIN_3,
+    VCMD_JPEGD_MODULE_TYPE_3,
+    VCMD_JPEGD_MODULE_MAIN_ADDR_3,
+    VCMD_JPEGD_MODULE_DEC400_ADDR_3,
+    VCMD_JPEGD_MODULE_L2CACHE_ADDR_3,
+    VCMD_JPEGD_MODULE_MMU_ADDR_3},
+#endif
+};
+/*these size need to be modified according to hw config.*/
+#define VCMD_ENCODER_REGISTER_SIZE              (479 * 4)
+#define VCMD_DECODER_REGISTER_SIZE              (512 * 4)
+#define VCMD_IM_REGISTER_SIZE                   (479 * 4)
+#define VCMD_JPEG_ENCODER_REGISTER_SIZE         (479 * 4)
+#define VCMD_JPEG_DECODER_REGISTER_SIZE         (512 * 4)
+
+#define MAX_VCMD_NUMBER     (MAX_VCMD_TYPE*MAX_SAME_MODULE_TYPE_CORE_NUMBER)              //
+
+#define HW_WORK_STATE_PEND            3
+
+#define MAX_CMDBUF_INT_NUMBER         1
+#define INT_MIN_SUM_OF_IMAGE_SIZE    (4096*2160*MAX_SAME_MODULE_TYPE_CORE_NUMBER*MAX_CMDBUF_INT_NUMBER)
+
+#if PROCESS_MANAGER
+#define MAX_PROCESS_CORE_NUMBER         4*8
+#define PROCESS_MAX_SUM_OF_IMAGE_SIZE     (4096*2160*MAX_SAME_MODULE_TYPE_CORE_NUMBER*MAX_PROCESS_CORE_NUMBER)
+#endif
+
+#define MAX_SAME_MODULE_TYPE_CORE_NUMBER            4
+
+/*******************PCIE CONFIG*************************/
+#define PCI_VENDOR_ID_HANTRO 0x10ee     //0x16c3
+#define PCI_DEVICE_ID_HANTRO_PCI 0x8014 // 0x7011
+/* Base address got control register */
+#define PCI_H2_BAR 4
+/* Base address DDR register */
+#define PCI_DDR_BAR 0
+/*struct pci_dev * */ void *g_vcmd_dev = NULL; /* PCI device structure. */
+unsigned long g_vcmd_base_hdwr = 0;                /* PCI base register address (Hardware address) */
+unsigned long g_vcmd_base_ddr_hw = 0;              /* PCI base register address (memalloc) */
+u32 g_vcmd_base_len = 0;                           /* Base register address Length */
+static ptr_t /*size_t*/ base_ddr_addr = 0;     /*pcie address need to substract this value then can be put to register*/
+
+/********variables declaration related with race condition**********/
+#define CMDBUF_MAX_SIZE (512 * 4 * 4)
+#define CMDBUF_POOL_TOTAL_SIZE (2 * 1024 * 1024) //approximately=2Mbytes
+#define TOTAL_DISCRETE_CMDBUF_NUM (CMDBUF_POOL_TOTAL_SIZE / CMDBUF_MAX_SIZE)
+#define CMDBUF_VCMD_REGISTER_TOTAL_SIZE 0x100000 // 1M
+#define VCMD_REGISTER_SIZE (128 * 4)
+
+struct noncache_mem
+{
+  u32 *virtualAddress;
+  ptr_t /* dma_addr_t */ busAddress;
+  u32 size;
+  u16 cmdbuf_id;
+};
+
+#if PROCESS_MANAGER
+struct process_manager_obj
+{
+  /*struct file */ int filp;
+  u32 total_exe_time;
+  spinlock_t spinlock;
+  /* wait_queue_head_t */ sem_t wait_queue;
+};
+#endif
+
+struct cmdbuf_obj
+{
+  u32 module_type;                    //current CMDBUF type: input vc8000e=0,IM=1,vc8000d=2,jpege=3, jpegd=4
+  u32 priority;                       //current CMDBUFpriority: normal=0, high=1
+  u32 executing_time;                 //current CMDBUFexecuting_time=encoded_image_size*(rdoLevel+1)*(rdoq+1);
+  u32 cmdbuf_size;                    //current CMDBUF size
+  u32 *cmdbuf_virtualAddress;         //current CMDBUF start virtual address.
+  ptr_t /*size_t*/ cmdbuf_busAddress; //current CMDBUF start physical address.
+  u32 *status_virtualAddress;         //current status CMDBUF start virtual address.
+  ptr_t /*size_t*/ status_busAddress; //current status CMDBUF start physical address.
+  u32 status_size;                    //current status CMDBUF size
+  u32 executing_status;               //current CMDBUF executing status.
+  /*struct file */ int filp;          //file pointer in the same process.
+  u16 core_id;                        //which vcmd core is used.
+  u16 cmdbuf_id;                      //used to manage CMDBUF in driver.It is a handle to identify cmdbuf.also is an interrupt vector.position in pool,same as status position.
+  u8 cmdbuf_data_loaded;              //0 means sw has not copied data into this CMDBUF; 1 means sw has copied data into this CMDBUF
+  u8 cmdbuf_data_linked;              //0 :not linked, 1:linked.
+  volatile u8 cmdbuf_run_done;        //if 0,waiting for CMDBUF finish; if 1, op code in CMDBUF has finished one by one. HANTRO_VCMD_IOCH_WAIT_CMDBUF will check this variable.
+  u8 cmdbuf_need_remove;              // if 0, not need to remove CMDBUF; 1 CMDBUF can be removed if it is not the last CMDBUF;
+  u32 waited;                         // if 0, the cmd buf hasn't been waited, otherwise, has been waited
+  u8 has_end_cmdbuf;                  //if 1, the last opcode is end opCode.
+  u8 no_normal_int_cmdbuf;            //if 1, JMP will not send normal interrupt.
+#ifdef PROCESS_MANAGER
+  struct process_manager_obj* process_manager_obj;
+#endif
+};
+
+struct hantrovcmd_dev
+{
+  struct vcmd_config vcmd_core_cfg; //config of each core,such as base addr, irq,etc
+  u32 core_id;                      //vcmd core id for driver and sw internal use
+  u32 sw_cmdbuf_rdy_num;
+  spinlock_t *spinlock;
+  //wait_queue_head_t * wait_queue;
+  //wait_queue_head_t * wait_abort_queue;
+  bi_list list_manager;
+  volatile u8 *hwregs; /* IO mem base */
+  u32 reg_mirror[ASIC_VCMD_SWREG_AMOUNT];
+  u32 duration_without_int; //number of cmdbufs without interrupt.
+  u8 working_state;
+  u32 total_exe_time;
+  u16 status_cmdbuf_id;                     //used for analyse configuration in cwl.
+  u32 hw_version_id;                        /*megvii 0x43421001, later 0x43421102*/
+  u32 *vcmd_reg_mem_virtualAddress;         //start virtual address of vcmd registers memory of  CMDBUF.
+  ptr_t /*size_t*/ vcmd_reg_mem_busAddress; //start physical address of vcmd registers memory of  CMDBUF.
+  u32 vcmd_reg_mem_size;                    //size of vcmd registers memory of CMDBUF.
+};
+
+/*
+ * Ioctl definitions
+ */
+#define VCMD_HW_ID 0x4342
+
+static struct noncache_mem vcmd_buf_mem_pool = {0};
+static struct noncache_mem vcmd_status_buf_mem_pool = {0};
+static struct noncache_mem vcmd_registers_mem_pool = {0};
+
+static u16 cmdbuf_used[TOTAL_DISCRETE_CMDBUF_NUM] = {0};
+static u16 cmdbuf_used_pos = 0;
+static u16 cmdbuf_used_residual = 0;
+
+static struct hantrovcmd_dev *vcmd_manager[MAX_VCMD_TYPE][MAX_VCMD_NUMBER] = {NULL};
+bi_list_node *global_cmdbuf_node[TOTAL_DISCRETE_CMDBUF_NUM] = {NULL};
+#if PROCESS_MANAGER
+bi_list global_process_manager = {NULL};
+#endif
+static u16 vcmd_position[MAX_VCMD_TYPE] = {0};
+static int vcmd_type_core_num[MAX_VCMD_TYPE] = {0};
+
+#define EXECUTING_CMDBUF_ID_ADDR       26
+#define VCMD_EXE_CMDBUF_COUNT           3
+
+#define WORKING_STATE_IDLE          0
+#define WORKING_STATE_WORKING       1
+#define CMDBUF_EXE_STATUS_OK        0
+#define CMDBUF_EXE_STATUS_CMDERR        1
+#define CMDBUF_EXE_STATUS_BUSERR        2
+
+/*struct semaphore*/ pthread_mutex_t vcmd_reserve_cmdbuf_sem[MAX_VCMD_TYPE]; //for reserve
+static void queue_vcmd_init(void *semaphore);
+static void queue_vcmd_wakeup(void *semaphore);
+static u32 queue_vcmd_wait(void *semaphore);
+/***************************TYPE AND FUNCTION DECLARATION****************/
+/* here's all the must remember stuff */
+static int vcmd_reserve_IO(void);
+static void vcmd_release_IO(void);
+static void vcmd_reset_asic(struct hantrovcmd_dev *dev);
+static void vcmd_reset_current_asic(struct hantrovcmd_dev *dev);
+static int allocate_cmdbuf(struct noncache_mem *new_cmdbuf_addr, struct noncache_mem *new_status_cmdbuf_addr);
+static void vcmd_link_cmdbuf(struct hantrovcmd_dev *dev, bi_list_node *last_linked_cmdbuf_node);
+static void vcmd_start(struct hantrovcmd_dev *dev, bi_list_node *first_linked_cmdbuf_node);
+static void create_kernel_process_manager(void);
+
+static irqreturn_t hantrovcmd_isr(/*int irq, */ void *dev_id);
+/* Interrupt */
+/*********************request_irq, disable_irq, enable_irq need to be provided by customer*********************/
+static int RegisterIRQ(i32 i, IRQHandler isr, i32 flag, const char *name, void *data);
+static void IntEnableIRQ(u32 irq);
+static void IntDisableIRQ(u32 irq);
+static void IntClearIRQStatus(u32 irq);
+static u32 IntGetIRQStatus(u32 irq);
+static inline uint32_t ReadInterruptStatus(void);
+/*********************local variable declaration*****************/
+static unsigned long vcmd_sram_base = 0;
+static unsigned int vcmd_sram_size = 0;
+/* and this is our MAJOR; use 0 for dynamic allocation (recommended)*/
+static int hantrovcmd_major = 0;
+int total_vcmd_core_num = 0;
+/* dynamic allocation*/
+static struct hantrovcmd_dev *hantrovcmd_data = NULL;
+
+//#define VCMD_DEBUG_INTERNAL
+
+//#define IRQ_SIMULATION
+
+#ifdef IRQ_SIMULATION
+struct timer_manager
+{
+  u32 core_id; //vcmd core id for driver and sw internal use
+  u32 timer_id;
+
+  TimerHandle_t * /*struct timer_list * */ timer;
+};
+static TimerHandle_t /*struct timer_list */ timer[10000];
+struct timer_manager timer_reserve[10000];
+
+#if 0
+static struct timer_list timer0;
+static struct timer_list timer1;
+#endif
+#endif
+
+//hw_queue can be used for reserve cmdbuf memory
+//DECLARE_WAIT_QUEUE_HEAD(vcmd_cmdbuf_memory_wait);
+sem_t vcmd_cmdbuf_memory_wait;
+//DEFINE_SPINLOCK(vcmd_cmdbuf_alloc_lock);
+pthread_mutex_t vcmd_cmdbuf_alloc_lock = PTHREAD_MUTEX_INITIALIZER;
+#if PROCESS_MANAGER
+//DEFINE_SPINLOCK(vcmd_process_manager_lock);
+pthread_mutex_t vcmd_process_manager_lock = PTHREAD_MUTEX_INITIALIZER;
+#endif
+spinlock_t owner_lock_vcmd[MAX_VCMD_NUMBER];
+
+static u8 vcmd_init_flag = 0;
+
+#ifdef VCMD_POLLING
+/*wait_queue_head_t*/ sem_t wait_queue_vcmd[TOTAL_DISCRETE_CMDBUF_NUM /*MAX_VCMD_NUMBER*/];
+/*wait_queue_head_t*/ sem_t abort_queue_vcmd[TOTAL_DISCRETE_CMDBUF_NUM /*MAX_VCMD_NUMBER*/];
+#else
+/*wait_queue_head_t*/ SemaphoreHandle_t wait_queue_vcmd[TOTAL_DISCRETE_CMDBUF_NUM /*MAX_VCMD_NUMBER*/];
+/*wait_queue_head_t*/ SemaphoreHandle_t abort_queue_vcmd[TOTAL_DISCRETE_CMDBUF_NUM /*MAX_VCMD_NUMBER*/];
+#endif
+
+/* mc wait queue, used in wait_cmdbuf_ready with ANY_CMDBUF_ID. */
+static /*wait_queue_head_t*/ /*sem_t*/SemaphoreHandle_t mc_wait_queue;
+
+#if 0
+/*allocate non-cacheable DMA memory*/
+#define DRIVER_NAME_HANTRO_NON_CACH_MEM "non_cach_memory"
+
+static struct platform_device *noncachable_mem_dev = NULL;
+
+
+static const struct platform_device_info hantro_platform_info = {
+    .name = DRIVER_NAME_HANTRO_NON_CACH_MEM,
+    .id = -1,
+    .dma_mask = DMA_BIT_MASK(32),
+};
+
+
+static int hantro_noncachable_mem_probe(struct platform_device *pdev)
+{
+  struct device *dev = &pdev->dev;
+  vcmd_buf_mem_pool.virtualAddress = dma_alloc_coherent(dev,CMDBUF_POOL_TOTAL_SIZE,&vcmd_buf_mem_pool.busAddress, GFP_KERNEL | GFP_DMA);
+  vcmd_buf_mem_pool.size = CMDBUF_POOL_TOTAL_SIZE;
+  vcmd_status_buf_mem_pool.virtualAddress = dma_alloc_coherent(dev,CMDBUF_POOL_TOTAL_SIZE,&vcmd_status_buf_mem_pool.busAddress, GFP_KERNEL | GFP_DMA);
+  vcmd_status_buf_mem_pool.size = CMDBUF_POOL_TOTAL_SIZE;
+  return 0;
+}
+
+static int hantro_noncachable_mem_remove(struct platform_device *pdev)
+{
+  struct device *dev = &pdev->dev;
+
+  dma_free_coherent(dev,vcmd_buf_mem_pool.size,vcmd_buf_mem_pool.virtualAddress,vcmd_buf_mem_pool.busAddress);
+  dma_free_coherent(dev,vcmd_status_buf_mem_pool.size,vcmd_status_buf_mem_pool.virtualAddress,vcmd_status_buf_mem_pool.busAddress);
+
+  return 0;
+}
+
+
+static const struct platform_device_id hantro_noncachable_mem_platform_ids[]={
+  {
+    .name = DRIVER_NAME_HANTRO_NON_CACH_MEM,
+  },
+  {/* sentinel */},
+};
+
+
+static const struct of_device_id  hantro_of_match[]={
+  {
+    .compatible  =  "thead,light-vc8000d",
+  },
+  {/* sentinel */},
+};
+
+static struct platform_driver hantro_noncachable_mem_platform_driver = {
+  .probe  = hantro_noncachable_mem_probe,
+  .remove  = hantro_noncachable_mem_remove,
+  .driver  ={
+    .name = DRIVER_NAME_HANTRO_NON_CACH_MEM,
+    .owner  = THIS_MODULE,
+    .of_match_table = hantro_of_match,
+  },
+  .id_table = hantro_noncachable_mem_platform_ids,
+};
+
+static void init_vcmd_non_cachable_memory_allocate(void)
+{
+
+  /*create device: This will create a {struct platform_device}, It has a member dev, which is a {struct device} */
+  noncachable_mem_dev = platform_device_register_full(&hantro_platform_info);
+
+  /*when this function is called, the .probe callback is invoked.*/
+  platform_driver_register(&hantro_noncachable_mem_platform_driver);
+
+
+}
+
+static void release_vcmd_non_cachable_memory(void)
+{
+
+  /* when this fucntion is called, .remove callback will be invoked. use it to clean up all resources allocated in .probe.*/
+  platform_driver_unregister(&hantro_noncachable_mem_platform_driver);
+
+  /*destroy the device*/
+  platform_device_unregister(noncachable_mem_dev);
+}
+#endif
+
+void PrintInstr(u32 i, u32 instr, u32 *size)
+{
+  if ((instr & 0xF8000000) == OPCODE_WREG)
+  {
+    int length = ((instr >> 16) & 0x3FF);
+    printk(KERN_INFO "current cmdbuf data %d = 0x%08x => [%s %s %d 0x%x]\n", i, instr, "WREG", ((instr >> 26) & 0x1) ? "FIX" : "",
+           length, (instr & 0xFFFF));
+    *size = ((length + 2) >> 1) << 1;
+  }
+  else if ((instr & 0xF8000000) == OPCODE_END)
+  {
+    printk(KERN_INFO "current cmdbuf data %d = 0x%08x => [%s]\n", i, instr, "END");
+    *size = 2;
+  }
+  else if ((instr & 0xF8000000) == OPCODE_NOP)
+  {
+    printk(KERN_INFO "current cmdbuf data %d = 0x%08x => [%s]\n", i, instr, "NOP");
+    *size = 2;
+  }
+  else if ((instr & 0xF8000000) == OPCODE_RREG)
+  {
+    int length = ((instr >> 16) & 0x3FF);
+    printk(KERN_INFO "current cmdbuf data %d = 0x%08x => [%s %s %d 0x%x]\n", i, instr, "RREG", ((instr >> 26) & 0x1) ? "FIX" : "",
+           length, (instr & 0xFFFF));
+    *size = 4;
+  }
+  else if ((instr & 0xF8000000) == OPCODE_JMP)
+  {
+    printk(KERN_INFO "current cmdbuf data %d = 0x%08x => [%s %s %s]\n", i, instr, "JMP", ((instr >> 26) & 0x1) ? "RDY" : "",
+           ((instr >> 25) & 0x1) ? "IE" : "");
+    *size = 4;
+  }
+  else if ((instr & 0xF8000000) == OPCODE_STALL)
+  {
+    printk(KERN_INFO "current cmdbuf data %d = 0x%08x => [%s %s 0x%x]\n", i, instr, "STALL", ((instr >> 26) & 0x1) ? "IM" : "",
+           (instr & 0xFFFF));
+    *size = 2;
+  }
+  else if ((instr & 0xF8000000) == OPCODE_CLRINT)
+  {
+    printk(KERN_INFO "current cmdbuf data %d = 0x%08x => [%s %d 0x%x]\n", i, instr, "CLRINT", (instr >> 25) & 0x3,
+           (instr & 0xFFFF));
+    *size = 2;
+  }
+  else
+    *size = 1;
+}
+
+/**********************************************************************************************************\
+*cmdbuf object management
+\***********************************************************************************************************/
+static struct cmdbuf_obj *create_cmdbuf_obj(void)
+{
+  struct cmdbuf_obj *cmdbuf_obj = NULL;
+  cmdbuf_obj = vmalloc(sizeof(struct cmdbuf_obj));
+  if (cmdbuf_obj == NULL)
+  {
+    PDEBUG("%s\n", "vmalloc for cmdbuf_obj fail!");
+    return cmdbuf_obj;
+  }
+  memset(cmdbuf_obj, 0, sizeof(struct cmdbuf_obj));
+  return cmdbuf_obj;
+}
+
+static void free_cmdbuf_obj(struct cmdbuf_obj *cmdbuf_obj)
+{
+  if (cmdbuf_obj == NULL)
+  {
+    PDEBUG("%s\n", "remove_cmdbuf_obj NULL");
+    return;
+  }
+  //free current cmdbuf_obj
+  vfree(cmdbuf_obj);
+  return;
+}
+static void free_cmdbuf_mem(u16 cmdbuf_id)
+{
+  unsigned long flags;
+
+  spin_lock_irqsave(&vcmd_cmdbuf_alloc_lock, flags);
+  cmdbuf_used[cmdbuf_id] = 0;
+  cmdbuf_used_residual += 1;
+  spin_unlock_irqrestore(&vcmd_cmdbuf_alloc_lock, flags);
+#if 1
+  sem_post(&vcmd_cmdbuf_memory_wait);
+  PDEBUG("Release cmdbuf_id [%d], remain cmd buffer %d\n", cmdbuf_id, vcmd_cmdbuf_memory_wait.value);
+#else
+  wake_up_interruptible_all(&vcmd_cmdbuf_memory_wait);
+#endif
+}
+
+static bi_list_node *create_cmdbuf_node(void)
+{
+  bi_list_node *current_node = NULL;
+  struct cmdbuf_obj *cmdbuf_obj = NULL;
+  struct noncache_mem new_cmdbuf_addr = {0};
+  struct noncache_mem new_status_cmdbuf_addr = {0};
+#if 1
+  if (sem_wait(&vcmd_cmdbuf_memory_wait))
+  { //wait cmdbuf, need to sem_wait until some cmdbuf was posted
+    PDEBUG("%s\n", "wait vcmd_cmdbuf_memory fail!");
+    return NULL;
+  }
+  allocate_cmdbuf(&new_cmdbuf_addr, &new_status_cmdbuf_addr);
+#else
+  if (wait_event_interruptible(vcmd_cmdbuf_memory_wait, allocate_cmdbuf(&new_cmdbuf_addr, &new_status_cmdbuf_addr)))
+    return NULL;
+#endif
+  cmdbuf_obj = create_cmdbuf_obj();
+  if (cmdbuf_obj == NULL)
+  {
+    PDEBUG("%s\n", "create_cmdbuf_obj fail!");
+    free_cmdbuf_mem(new_cmdbuf_addr.cmdbuf_id);
+    return NULL;
+  }
+  cmdbuf_obj->cmdbuf_busAddress = new_cmdbuf_addr.busAddress;
+  cmdbuf_obj->cmdbuf_virtualAddress = new_cmdbuf_addr.virtualAddress;
+  cmdbuf_obj->cmdbuf_size = new_cmdbuf_addr.size;
+  cmdbuf_obj->cmdbuf_id = new_cmdbuf_addr.cmdbuf_id;
+  cmdbuf_obj->status_busAddress = new_status_cmdbuf_addr.busAddress;
+  cmdbuf_obj->status_virtualAddress = new_status_cmdbuf_addr.virtualAddress;
+  cmdbuf_obj->status_size = new_status_cmdbuf_addr.size;
+  current_node = bi_list_create_node();
+  if (current_node == NULL)
+  {
+    PDEBUG("%s\n", "bi_list_create_node fail!");
+    free_cmdbuf_mem(new_cmdbuf_addr.cmdbuf_id);
+    free_cmdbuf_obj(cmdbuf_obj);
+    return NULL;
+  }
+  current_node->data = (void *)cmdbuf_obj;
+  current_node->next = NULL;
+  current_node->previous = NULL;
+  return current_node;
+}
+static void free_cmdbuf_node(bi_list_node *cmdbuf_node)
+{
+  struct cmdbuf_obj *cmdbuf_obj = NULL;
+  if (cmdbuf_node == NULL)
+  {
+    PDEBUG("%s\n", "remove_cmdbuf_node NULL");
+    return;
+  }
+  cmdbuf_obj = (struct cmdbuf_obj *)cmdbuf_node->data;
+  //free cmdbuf mem in pool
+  free_cmdbuf_mem(cmdbuf_obj->cmdbuf_id);
+
+  //free struct cmdbuf_obj
+  free_cmdbuf_obj(cmdbuf_obj);
+  //free current cmdbuf_node entity.
+  bi_list_free_node(cmdbuf_node);
+  return;
+}
+
+//just remove, not free the node.
+static bi_list_node *remove_cmdbuf_node_from_list(bi_list *list, bi_list_node *cmdbuf_node)
+{
+  if (cmdbuf_node == NULL)
+  {
+    PDEBUG("%s\n", "remove_cmdbuf_node_from_list  NULL");
+    return NULL;
+  }
+  if (cmdbuf_node->next)
+  {
+    bi_list_remove_node(list, cmdbuf_node);
+    return cmdbuf_node;
+  }
+  else
+  {
+    //the last one, should not be removed.
+    return NULL;
+  }
+}
+//calculate executing_time of each vcmd
+static u32 calculate_executing_time_after_node(bi_list_node *exe_cmdbuf_node)
+{
+  u32 time_run_all = 0;
+  struct cmdbuf_obj *cmdbuf_obj_temp = NULL;
+  while (1)
+  {
+    if (exe_cmdbuf_node == NULL)
+      break;
+    cmdbuf_obj_temp = (struct cmdbuf_obj *)exe_cmdbuf_node->data;
+    time_run_all += cmdbuf_obj_temp->executing_time;
+    exe_cmdbuf_node = exe_cmdbuf_node->next;
+  }
+  return time_run_all;
+}
+static u32 calculate_executing_time_after_node_high_priority(bi_list_node *exe_cmdbuf_node)
+{
+  u32 time_run_all = 0;
+  struct cmdbuf_obj *cmdbuf_obj_temp = NULL;
+  if (exe_cmdbuf_node == NULL)
+    return time_run_all;
+  cmdbuf_obj_temp = (struct cmdbuf_obj *)exe_cmdbuf_node->data;
+  time_run_all += cmdbuf_obj_temp->executing_time;
+  exe_cmdbuf_node = exe_cmdbuf_node->next;
+  while (1)
+  {
+    if (exe_cmdbuf_node == NULL)
+      break;
+    cmdbuf_obj_temp = (struct cmdbuf_obj *)exe_cmdbuf_node->data;
+    if (cmdbuf_obj_temp->priority == CMDBUF_PRIORITY_NORMAL)
+      break;
+    time_run_all += cmdbuf_obj_temp->executing_time;
+    exe_cmdbuf_node = exe_cmdbuf_node->next;
+  }
+  return time_run_all;
+}
+
+/**********************************************************************************************************\
+*cmdbuf pool management
+\***********************************************************************************************************/
+static int allocate_cmdbuf(struct noncache_mem *new_cmdbuf_addr, struct noncache_mem *new_status_cmdbuf_addr)
+{
+  unsigned long flags;
+  spin_lock_irqsave(&vcmd_cmdbuf_alloc_lock, flags);
+  if (cmdbuf_used_residual == 0)
+  {
+    spin_unlock_irqrestore(&vcmd_cmdbuf_alloc_lock, flags);
+    //no empty cmdbuf
+    return 0;
+  }
+  //there is one cmdbuf at least
+  while (1)
+  {
+    if (cmdbuf_used[cmdbuf_used_pos] == 0 && (global_cmdbuf_node[cmdbuf_used_pos] == NULL))
+    {
+      cmdbuf_used[cmdbuf_used_pos] = 1;
+      cmdbuf_used_residual -= 1;
+      new_cmdbuf_addr->virtualAddress = vcmd_buf_mem_pool.virtualAddress + cmdbuf_used_pos * CMDBUF_MAX_SIZE / 4;
+      new_cmdbuf_addr->busAddress = vcmd_buf_mem_pool.busAddress + cmdbuf_used_pos * CMDBUF_MAX_SIZE;
+      new_cmdbuf_addr->size = CMDBUF_MAX_SIZE;
+      new_cmdbuf_addr->cmdbuf_id = cmdbuf_used_pos;
+      new_status_cmdbuf_addr->virtualAddress = vcmd_status_buf_mem_pool.virtualAddress + cmdbuf_used_pos * CMDBUF_MAX_SIZE / 4;
+      new_status_cmdbuf_addr->busAddress = vcmd_status_buf_mem_pool.busAddress + cmdbuf_used_pos * CMDBUF_MAX_SIZE;
+      new_status_cmdbuf_addr->size = CMDBUF_MAX_SIZE;
+      new_status_cmdbuf_addr->cmdbuf_id = cmdbuf_used_pos;
+      cmdbuf_used_pos++;
+      if (cmdbuf_used_pos >= TOTAL_DISCRETE_CMDBUF_NUM)
+        cmdbuf_used_pos = 0;
+      spin_unlock_irqrestore(&vcmd_cmdbuf_alloc_lock, flags);
+      return 1;
+    }
+    else
+    {
+      cmdbuf_used_pos++;
+      if (cmdbuf_used_pos >= TOTAL_DISCRETE_CMDBUF_NUM)
+        cmdbuf_used_pos = 0;
+    }
+  }
+  return 0;
+}
+
+static bi_list_node *get_cmdbuf_node_in_list_by_addr(/*size_t*/ ptr_t cmdbuf_addr, bi_list *list)
+{
+  bi_list_node *new_cmdbuf_node = NULL;
+  struct cmdbuf_obj *cmdbuf_obj = NULL;
+  new_cmdbuf_node = list->head;
+  while (1)
+  {
+    if (new_cmdbuf_node == NULL)
+      return NULL;
+    cmdbuf_obj = (struct cmdbuf_obj *)new_cmdbuf_node->data;
+    if (((cmdbuf_obj->cmdbuf_busAddress - base_ddr_addr) <= cmdbuf_addr) && (((cmdbuf_obj->cmdbuf_busAddress - base_ddr_addr + cmdbuf_obj->cmdbuf_size) > cmdbuf_addr)))
+    {
+      return new_cmdbuf_node;
+    }
+    new_cmdbuf_node = new_cmdbuf_node->next;
+  }
+  return NULL;
+}
+
+static int wait_abort_rdy(struct hantrovcmd_dev *dev)
+{
+  return dev->working_state == WORKING_STATE_IDLE;
+}
+
+
+static inline void increase_vcmd_position(u32 module_type)
+{
+  vcmd_position[module_type]++;
+  if (vcmd_position[module_type] >= vcmd_type_core_num[module_type])
+    vcmd_position[module_type] = 0;
+}
+
+static inline int vcmd_is_free(struct hantrovcmd_dev *dev)
+{
+  bi_list *list = NULL;
+  struct cmdbuf_obj *cmdbuf_obj_temp = NULL;
+
+  list = &dev->list_manager;
+  if (dev->list_manager.tail == NULL)
+  {
+    //no vcmd_buf is linked
+    return 1;
+  }
+
+  cmdbuf_obj_temp = (struct cmdbuf_obj *)list->tail->data;
+  if(cmdbuf_obj_temp->cmdbuf_run_done == 1)
+  {
+    //last vcmd_buf is done.
+    return 1;
+  }
+
+  return 0;
+}
+
+static int vcmd_get_executing_time(struct hantrovcmd_dev *dev, int priority)
+{
+  bi_list *list = NULL;
+  bi_list_node *curr_cmdbuf_node = NULL;
+  struct cmdbuf_obj *cmdbuf_obj_temp = NULL;
+  ptr_t exe_cmdbuf_addr = 0;
+  unsigned long flags = 0;
+  u32 cmdbuf_id = 0;
+
+  list = &dev->list_manager;
+  //read executing cmdbuf address
+  if (dev->hw_version_id <= HW_ID_1_0_C)
+  {
+    exe_cmdbuf_addr = VCMDGetAddrRegisterValue((const void *)dev->hwregs, dev->reg_mirror, HWIF_VCMD_EXECUTING_CMD_ADDR);
+
+    spin_lock_irqsave(dev->spinlock, flags);
+    //get the executing cmdbuf node.
+    curr_cmdbuf_node = get_cmdbuf_node_in_list_by_addr(exe_cmdbuf_addr, list);
+  }
+  else
+  {
+    cmdbuf_id = *(dev->vcmd_reg_mem_virtualAddress + EXECUTING_CMDBUF_ID_ADDR + 1);
+    if (cmdbuf_id >= TOTAL_DISCRETE_CMDBUF_NUM || cmdbuf_id == 0)
+    {
+      printk(KERN_ERR "cmdbuf_id greater than the ceiling !!\n");
+      return -1;
+    }
+
+    spin_lock_irqsave(dev->spinlock, flags);
+    //get the executing cmdbuf node.
+    curr_cmdbuf_node = global_cmdbuf_node[cmdbuf_id];
+    if (curr_cmdbuf_node == NULL)
+    {
+      curr_cmdbuf_node = list->head;
+      while (1)
+      {
+        if (curr_cmdbuf_node == NULL)
+          break;
+        cmdbuf_obj_temp = (struct cmdbuf_obj *)curr_cmdbuf_node->data;
+        if (cmdbuf_obj_temp->cmdbuf_data_linked && cmdbuf_obj_temp->cmdbuf_run_done == 0)
+          break;
+        curr_cmdbuf_node = curr_cmdbuf_node->next;
+      }
+    }
+  }
+
+  //calculate total execute time of this device
+  if(priority == CMDBUF_PRIORITY_HIGH)
+    dev->total_exe_time = calculate_executing_time_after_node_high_priority(curr_cmdbuf_node);
+  else
+    dev->total_exe_time = calculate_executing_time_after_node(curr_cmdbuf_node);
+
+  spin_unlock_irqrestore(dev->spinlock, flags);
+  return 0;
+}
+
+static int select_vcmd(bi_list_node *new_cmdbuf_node)
+{
+  struct cmdbuf_obj *cmdbuf_obj = NULL;
+  bi_list_node *curr_cmdbuf_node = NULL;
+  bi_list *list = NULL;
+  struct hantrovcmd_dev *dev = NULL;
+  struct hantrovcmd_dev *smallest_dev = NULL;
+  u32 executing_time = 0xffff;
+  int counter = 0;
+  unsigned long flags = 0;
+  u32 hw_rdy_cmdbuf_num = 0;
+  /*size_t*/ ptr_t exe_cmdbuf_addr = 0;
+  struct cmdbuf_obj *cmdbuf_obj_temp = NULL;
+  u32 cmdbuf_id = 0;
+  cmdbuf_obj = (struct cmdbuf_obj *)new_cmdbuf_node->data;
+  int ret;
+
+  //if there is an empty vcmd
+  for(counter=0; counter<vcmd_type_core_num[cmdbuf_obj->module_type]; counter++)
+  {
+    dev = vcmd_manager[cmdbuf_obj->module_type][vcmd_position[cmdbuf_obj->module_type]];
+	increase_vcmd_position(cmdbuf_obj->module_type);
+
+    list = &dev->list_manager;
+
+    spin_lock_irqsave(dev->spinlock, flags);
+
+    if (vcmd_is_free(dev))
+    {
+      bi_list_insert_node_tail(list, new_cmdbuf_node);
+      spin_unlock_irqrestore(dev->spinlock, flags);
+      cmdbuf_obj->core_id = dev->core_id;
+      return 0;
+    }
+
+    spin_unlock_irqrestore(dev->spinlock, flags);
+  }
+
+  //another case, tail = executing node, and vcmd=pend state (finish but not generate interrupt)
+  for(counter=0; counter<vcmd_type_core_num[cmdbuf_obj->module_type]; counter++)
+  {
+    dev = vcmd_manager[cmdbuf_obj->module_type][vcmd_position[cmdbuf_obj->module_type]];
+	increase_vcmd_position(cmdbuf_obj->module_type);
+
+    list = &dev->list_manager;
+    //read executing cmdbuf address
+    if (dev->hw_version_id <= HW_ID_1_0_C)
+      hw_rdy_cmdbuf_num = vcmd_get_register_value((const void *)dev->hwregs, dev->reg_mirror, HWIF_VCMD_EXE_CMDBUF_COUNT);
+    else
+    {
+      hw_rdy_cmdbuf_num = *(dev->vcmd_reg_mem_virtualAddress + VCMD_EXE_CMDBUF_COUNT);
+      if (hw_rdy_cmdbuf_num != dev->sw_cmdbuf_rdy_num)
+        hw_rdy_cmdbuf_num += 1;
+    }
+
+    if (dev->sw_cmdbuf_rdy_num == hw_rdy_cmdbuf_num)
+    {
+	  spin_lock_irqsave(dev->spinlock, flags);
+      bi_list_insert_node_tail(list, new_cmdbuf_node);
+      spin_unlock_irqrestore(dev->spinlock, flags);
+      cmdbuf_obj->core_id = dev->core_id;
+      return 0;
+    }
+  }
+
+  //there is no idle vcmd,if low priority,calculate exe time, select the least one.
+  // or if high priority, calculate the exe time, select the least one and abort it.
+  executing_time = 0xffffffff;
+  for(counter=0; counter<vcmd_type_core_num[cmdbuf_obj->module_type]; counter++)
+  {
+	dev = vcmd_manager[cmdbuf_obj->module_type][vcmd_position[cmdbuf_obj->module_type]];
+	increase_vcmd_position(cmdbuf_obj->module_type);
+  
+	ret = vcmd_get_executing_time(dev, cmdbuf_obj->priority);
+	if(ret)
+	  return ret;
+  
+	if (dev->total_exe_time <= executing_time)
+	{
+	  executing_time = dev->total_exe_time;
+	  smallest_dev = dev;
+	}
+  }
+
+  if (cmdbuf_obj->priority == CMDBUF_PRIORITY_NORMAL)
+  {
+    //insert list
+    list = &smallest_dev->list_manager;
+    spin_lock_irqsave(smallest_dev->spinlock, flags);
+    bi_list_insert_node_tail(list, new_cmdbuf_node);
+    spin_unlock_irqrestore(smallest_dev->spinlock, flags);
+    cmdbuf_obj->core_id = smallest_dev->core_id;
+    return 0;
+  }
+  else
+  {
+    //CMDBUF_PRIORITY_HIGH
+
+    //abort the vcmd and wait
+    vcmd_write_register_value((const void *)smallest_dev->hwregs, smallest_dev->reg_mirror, HWIF_VCMD_START_TRIGGER, 0);
+
+#if 1
+#if 1
+    //use yield
+    while(1)
+    {
+      if (cmdbuf_obj->cmdbuf_run_done)
+        break;
+      sched_yield();
+    }
+#else
+    queue_vcmd_wait(&abort_queue_vcmd[cmdbuf_obj->cmdbuf_id]);
+#endif
+#else
+    if (wait_event_interruptible(*smallest_dev->wait_abort_queue, wait_abort_rdy(dev)))
+      return -ERESTARTSYS;
+#endif
+    //need to select inserting position again because hw maybe have run to the next node.
+    //CMDBUF_PRIORITY_HIGH
+    spin_lock_irqsave(smallest_dev->spinlock, flags);
+    curr_cmdbuf_node = smallest_dev->list_manager.head;
+    while (1)
+    {
+      //if list is empty or tail,insert to tail
+      if (curr_cmdbuf_node == NULL)
+        break;
+      cmdbuf_obj_temp = (struct cmdbuf_obj *)curr_cmdbuf_node->data;
+      //if find the first node which priority is normal, insert node prior to  the node
+      if ((cmdbuf_obj_temp->priority == CMDBUF_PRIORITY_NORMAL) && (cmdbuf_obj_temp->cmdbuf_run_done == 0))
+        break;
+      curr_cmdbuf_node = curr_cmdbuf_node->next;
+    }
+    bi_list_insert_node_before(list, curr_cmdbuf_node, new_cmdbuf_node);
+    cmdbuf_obj->core_id = smallest_dev->core_id;
+    spin_unlock_irqrestore(smallest_dev->spinlock, flags);
+
+    return 0;
+  }
+  return 0;
+}
+
+#if PROCESS_MANAGER
+static int wait_process_resource_rdy(struct process_manager_obj *process_manager_obj)
+{
+  return process_manager_obj->total_exe_time <= PROCESS_MAX_SUM_OF_IMAGE_SIZE;
+}
+#endif
+
+static long reserve_cmdbuf(/*struct file */ int filp, struct exchange_parameter *input_para)
+{
+  bi_list_node *new_cmdbuf_node = NULL;
+  struct cmdbuf_obj *cmdbuf_obj = NULL;
+  bi_list_node *process_manager_node = NULL;
+#if PROCESS_MANAGER
+  struct process_manager_obj *process_manager_obj = NULL;
+#endif
+  unsigned long flags = 0;
+  input_para->cmdbuf_id = 0;
+
+  if (input_para->cmdbuf_size > CMDBUF_MAX_SIZE)
+  {
+    return -1;
+  }
+  PDEBUG("reserve cmdbuf filp %p\n", (void *)filp);
+
+#if PROCESS_MANAGER
+  spin_lock_irqsave(&vcmd_process_manager_lock, flags);
+  process_manager_node = global_process_manager.head;
+  while (1)
+  {
+    if (process_manager_node == NULL)
+    {
+      //should not happen
+      printk(KERN_ERR "hantrovcmd: ERROR process_manager_node !!\n");
+      spin_unlock_irqrestore(&vcmd_process_manager_lock, flags);
+      return -1;
+    }
+    process_manager_obj = (struct process_manager_obj *)process_manager_node->data;
+    PDEBUG("reserve loop: node %p, filp %p\n", (void *)process_manager_node,
+           (void *)process_manager_obj->filp);
+    if (filp == process_manager_obj->filp)
+    {
+      spin_lock_irqsave(&process_manager_obj->spinlock, flags);
+      process_manager_obj->total_exe_time += input_para->executing_time;
+      spin_unlock_irqrestore(&process_manager_obj->spinlock, flags);
+      break;
+    }
+    process_manager_node = process_manager_node->next;
+  }
+  spin_unlock_irqrestore(&vcmd_process_manager_lock, flags);
+
+  if (wait_event_interruptible(process_manager_obj->wait_queue, wait_process_resource_rdy(process_manager_obj)))
+    return -1;
+#endif
+
+  new_cmdbuf_node = create_cmdbuf_node();
+  if (new_cmdbuf_node == NULL)
+    return -1;
+
+  cmdbuf_obj = (struct cmdbuf_obj *)new_cmdbuf_node->data;
+  cmdbuf_obj->module_type = input_para->module_type;
+  cmdbuf_obj->priority = input_para->priority;
+  cmdbuf_obj->executing_time = input_para->executing_time;
+  cmdbuf_obj->cmdbuf_size = CMDBUF_MAX_SIZE;
+  input_para->cmdbuf_size = CMDBUF_MAX_SIZE;
+  cmdbuf_obj->filp = filp;
+
+#if PROCESS_MANAGER
+  cmdbuf_obj->process_manager_obj = process_manager_obj;
+#endif
+
+  input_para->cmdbuf_id = cmdbuf_obj->cmdbuf_id;
+  global_cmdbuf_node[input_para->cmdbuf_id] = new_cmdbuf_node;
+
+  return 0;
+}
+
+static long release_cmdbuf(/*struct file */ int filp, u16 cmdbuf_id)
+{
+  struct cmdbuf_obj *cmdbuf_obj = NULL;
+  bi_list_node *last_cmdbuf_node = NULL;
+  bi_list_node *new_cmdbuf_node = NULL;
+  bi_list *list = NULL;
+  u32 module_type;
+
+  unsigned long flags;
+  struct hantrovcmd_dev *dev = NULL;
+  /*get cmdbuf object according to cmdbuf_id*/
+  new_cmdbuf_node = global_cmdbuf_node[cmdbuf_id];
+  if (new_cmdbuf_node == NULL)
+  {
+    //should not happen
+    printk(KERN_ERR "hantrovcmd: ERROR cmdbuf_id !!\n");
+    return -1;
+  }
+  cmdbuf_obj = (struct cmdbuf_obj *)new_cmdbuf_node->data;
+  if (cmdbuf_obj->filp != filp)
+  {
+    //should not happen
+    printk(KERN_ERR "hantrovcmd: ERROR cmdbuf_id !!\n");
+    return -1;
+  }
+  module_type = cmdbuf_obj->module_type;
+  //TODO
+  if (down_interruptible(&vcmd_reserve_cmdbuf_sem[module_type]))
+    return -ERESTARTSYS;
+  dev = &hantrovcmd_data[cmdbuf_obj->core_id];
+
+  //spin_lock_irqsave(dev->spinlock, flags);
+  list = &dev->list_manager;
+  cmdbuf_obj->cmdbuf_need_remove = 1;
+  last_cmdbuf_node = new_cmdbuf_node->previous;
+  while (1)
+  {
+    //remove current node
+    cmdbuf_obj = (struct cmdbuf_obj *)new_cmdbuf_node->data;
+    if (cmdbuf_obj->cmdbuf_need_remove == 1)
+    {
+      new_cmdbuf_node = remove_cmdbuf_node_from_list(list, new_cmdbuf_node);
+      if (new_cmdbuf_node)
+      {
+        //free node
+        global_cmdbuf_node[cmdbuf_obj->cmdbuf_id] = NULL;
+#if PROCESS_MANAGER
+        if (cmdbuf_obj->process_manager_obj)
+        {
+          spin_lock_irqsave(&cmdbuf_obj->process_manager_obj->spinlock, flags);
+          cmdbuf_obj->process_manager_obj->total_exe_time -= cmdbuf_obj->executing_time;
+          spin_unlock_irqrestore(&cmdbuf_obj->process_manager_obj->spinlock, flags);
+          wake_up_interruptible_all(&cmdbuf_obj->process_manager_obj->wait_queue);
+        }
+#endif
+        free_cmdbuf_node(new_cmdbuf_node);
+      }
+    }
+    if (last_cmdbuf_node == NULL)
+      break;
+    new_cmdbuf_node = last_cmdbuf_node;
+    last_cmdbuf_node = new_cmdbuf_node->previous;
+  }
+  //spin_unlock_irqrestore(dev->spinlock, flags);
+  up(&vcmd_reserve_cmdbuf_sem[module_type]);
+  return 0;
+}
+static long release_cmdbuf_node(bi_list *list, bi_list_node *cmdbuf_node)
+{
+  bi_list_node *new_cmdbuf_node = NULL;
+  struct cmdbuf_obj *cmdbuf_obj = NULL;
+  /*get cmdbuf object according to cmdbuf_id*/
+  new_cmdbuf_node = cmdbuf_node;
+  if (new_cmdbuf_node == NULL)
+    return -1;
+  //remove node from list
+  new_cmdbuf_node = remove_cmdbuf_node_from_list(list, new_cmdbuf_node);
+  if (new_cmdbuf_node)
+  {
+    //free node
+    cmdbuf_obj = (struct cmdbuf_obj *)new_cmdbuf_node->data;
+    global_cmdbuf_node[cmdbuf_obj->cmdbuf_id] = NULL;
+    free_cmdbuf_node(new_cmdbuf_node);
+    return 0;
+  }
+  return 1;
+}
+
+static long release_cmdbuf_node_cleanup(bi_list *list)
+{
+  bi_list_node *new_cmdbuf_node = NULL;
+  struct cmdbuf_obj *cmdbuf_obj = NULL;
+  while (1)
+  {
+    new_cmdbuf_node = list->head;
+    if (new_cmdbuf_node == NULL)
+      return 0;
+    //remove node from list
+    bi_list_remove_node(list, new_cmdbuf_node);
+    //free node
+    cmdbuf_obj = (struct cmdbuf_obj *)new_cmdbuf_node->data;
+    global_cmdbuf_node[cmdbuf_obj->cmdbuf_id] = NULL;
+    free_cmdbuf_node(new_cmdbuf_node);
+  }
+  return 0;
+}
+
+static bi_list_node *find_last_linked_cmdbuf(bi_list_node *current_node)
+{
+  bi_list_node *new_cmdbuf_node = current_node;
+  bi_list_node *last_cmdbuf_node;
+  struct cmdbuf_obj *cmdbuf_obj = NULL;
+  if (current_node == NULL)
+    return NULL;
+  last_cmdbuf_node = new_cmdbuf_node;
+  new_cmdbuf_node = new_cmdbuf_node->previous;
+  while (1)
+  {
+    if (new_cmdbuf_node == NULL)
+      return last_cmdbuf_node;
+    cmdbuf_obj = (struct cmdbuf_obj *)new_cmdbuf_node->data;
+    if (cmdbuf_obj->cmdbuf_data_linked)
+    {
+      return new_cmdbuf_node;
+    }
+    last_cmdbuf_node = new_cmdbuf_node;
+    new_cmdbuf_node = new_cmdbuf_node->previous;
+  }
+  return NULL;
+}
+static long link_and_run_cmdbuf(/*struct file */ int filp, struct exchange_parameter *input_para)
+{
+  struct cmdbuf_obj *cmdbuf_obj = NULL;
+  bi_list_node *new_cmdbuf_node = NULL;
+  bi_list_node *last_cmdbuf_node = NULL;
+  u32 *jmp_addr = NULL;
+  u32 opCode = 0;
+  u32 tempOpcode = 0;
+  u32 record_last_cmdbuf_rdy_num = 0;
+  struct hantrovcmd_dev *dev = NULL;
+  unsigned long flags = 0;
+  int return_value = 0;
+  u16 cmdbuf_id = input_para->cmdbuf_id;
+
+  new_cmdbuf_node = global_cmdbuf_node[cmdbuf_id];
+  if (new_cmdbuf_node == NULL)
+  {
+    //should not happen
+    printk(KERN_ERR "hantrovcmd: ERROR cmdbuf_id !!\n");
+    return -1;
+  }
+  cmdbuf_obj = (struct cmdbuf_obj *)new_cmdbuf_node->data;
+  if (cmdbuf_obj->filp != filp)
+  {
+    //should not happen
+    printk(KERN_ERR "hantrovcmd: ERROR cmdbuf_id !!\n");
+    return -1;
+  }
+  cmdbuf_obj->cmdbuf_data_loaded = 1;
+  cmdbuf_obj->cmdbuf_size = input_para->cmdbuf_size;
+  cmdbuf_obj->waited = 0;
+#ifdef VCMD_DEBUG_INTERNAL
+  {
+    u32 i, inst = 0, size = 0;
+    printk(KERN_INFO "vcmd link, current cmdbuf content\n");
+    for (i = 0; i < cmdbuf_obj->cmdbuf_size / 4; i++)
+    {
+      if (i == inst)
+      {
+        PrintInstr(i, *(cmdbuf_obj->cmdbuf_virtualAddress + i), &size);
+        inst += size;
+      }
+      else
+      {
+        printk(KERN_INFO "current cmdbuf data %d = 0x%x\n", i, *(cmdbuf_obj->cmdbuf_virtualAddress + i));
+      }
+    }
+  }
+#endif
+  //test nop and end opcode, then assign value.
+  cmdbuf_obj->has_end_cmdbuf = 0;       //0: has jmp opcode,1 has end code
+  cmdbuf_obj->no_normal_int_cmdbuf = 0; //0: interrupt when JMP,1 not interrupt when JMP
+  jmp_addr = cmdbuf_obj->cmdbuf_virtualAddress + (cmdbuf_obj->cmdbuf_size / 4);
+  opCode = tempOpcode = *(jmp_addr - 4);
+  opCode >>= 27;
+  opCode <<= 27;
+  //we can't identify END opcode or JMP opcode, so we don't support END opcode in control sw and driver.
+  if (opCode == OPCODE_JMP)
+  {
+    //jmp
+    opCode = tempOpcode;
+    opCode &= 0x02000000;
+    if (opCode == JMP_IE_1)
+    {
+      cmdbuf_obj->no_normal_int_cmdbuf = 0;
+    }
+    else
+    {
+      cmdbuf_obj->no_normal_int_cmdbuf = 1;
+    }
+  }
+  else
+  {
+    //not support other opcode
+    return -1;
+  }
+
+  if (down_interruptible(&vcmd_reserve_cmdbuf_sem[cmdbuf_obj->module_type]))
+    return -ERESTARTSYS;
+
+  return_value = select_vcmd(new_cmdbuf_node);
+  if (return_value)
+    return return_value;
+
+  dev = &hantrovcmd_data[cmdbuf_obj->core_id];
+  input_para->core_id = cmdbuf_obj->core_id;
+  printk(KERN_INFO "Allocate cmd buffer [%d] to core [%d], remain cmd buffer %d\n", cmdbuf_id, input_para->core_id, vcmd_cmdbuf_memory_wait.value);
+  //set ddr address for vcmd registers copy.
+  if (dev->hw_version_id > HW_ID_1_0_C)
+  {
+    //read vcmd executing register into ddr memory.
+    //now core id is got and output ddr address of vcmd register can be filled in.
+    //each core has its own fixed output ddr address of vcmd registers.
+    jmp_addr = cmdbuf_obj->cmdbuf_virtualAddress;
+    if (sizeof(ptr_t) == 8)
+    {
+      *(jmp_addr + 2) = (u32)((u64)(dev->vcmd_reg_mem_busAddress + (EXECUTING_CMDBUF_ID_ADDR + 1) * 4) >> 32);
+    }
+    else
+    {
+      *(jmp_addr + 2) = 0;
+    }
+    *(jmp_addr + 1) = (u32)((dev->vcmd_reg_mem_busAddress + (EXECUTING_CMDBUF_ID_ADDR + 1) * 4));
+
+    jmp_addr = cmdbuf_obj->cmdbuf_virtualAddress + (cmdbuf_obj->cmdbuf_size / 4);
+    //read vcmd all registers into ddr memory.
+    //now core id is got and output ddr address of vcmd registers can be filled in.
+    //each core has its own fixed output ddr address of vcmd registers.
+    if (sizeof(ptr_t) == 8)
+    {
+      *(jmp_addr - 6) = (u32)((u64)dev->vcmd_reg_mem_busAddress >> 32);
+    }
+    else
+    {
+      *(jmp_addr - 6) = 0;
+    }
+    *(jmp_addr - 7) = (u32)(dev->vcmd_reg_mem_busAddress);
+  }
+  //start to link and/or run
+  spin_lock_irqsave(dev->spinlock, flags);
+  last_cmdbuf_node = find_last_linked_cmdbuf(new_cmdbuf_node);
+  record_last_cmdbuf_rdy_num = dev->sw_cmdbuf_rdy_num;
+  vcmd_link_cmdbuf(dev, last_cmdbuf_node);
+  if (dev->working_state == WORKING_STATE_IDLE)
+  {
+    //run
+    vcmd_start(dev, last_cmdbuf_node);
+  }
+  else
+  {
+    //just update cmdbuf ready number
+    if (record_last_cmdbuf_rdy_num != dev->sw_cmdbuf_rdy_num) {
+      _Pragma("flush_memory");
+      xthal_dcache_all_writeback_inv();
+      _Pragma("flush_memory");
+      vcmd_write_register_value((const void *)dev->hwregs, dev->reg_mirror, HWIF_VCMD_RDY_CMDBUF_COUNT, dev->sw_cmdbuf_rdy_num);
+    }
+  }
+
+  spin_unlock_irqrestore(dev->spinlock, flags);
+
+  up(&vcmd_reserve_cmdbuf_sem[cmdbuf_obj->module_type]);
+
+  return 0;
+}
+
+/******************************************************************************/
+static int check_cmdbuf_irq(struct hantrovcmd_dev *dev, struct cmdbuf_obj *cmdbuf_obj, u32 *irq_status_ret)
+{
+
+  int rdy = 0;
+  unsigned long flags;
+  spin_lock_irqsave(dev->spinlock, flags);
+  if (cmdbuf_obj->cmdbuf_run_done)
+  {
+    rdy = 1;
+    *irq_status_ret = cmdbuf_obj->executing_status; //need to decide how to assign this variable
+  }
+  spin_unlock_irqrestore(dev->spinlock, flags);
+  return rdy;
+}
+
+/******************************************************************************/
+static int check_mc_cmdbuf_irq(/*struct file * */ int filp, struct cmdbuf_obj *cmdbuf_obj, u32 *irq_status_ret)
+{
+  int k;
+  bi_list_node *new_cmdbuf_node = NULL;
+  struct hantrovcmd_dev *dev = NULL;
+
+  for(k=0;k<TOTAL_DISCRETE_CMDBUF_NUM;k++)
+  {
+    new_cmdbuf_node = global_cmdbuf_node[k];
+    if(new_cmdbuf_node==NULL)
+      continue;
+
+    cmdbuf_obj=(struct cmdbuf_obj*)new_cmdbuf_node->data;
+    if(!cmdbuf_obj || cmdbuf_obj->filp != filp)
+      continue;
+
+    dev = &hantrovcmd_data[cmdbuf_obj->core_id];
+    if (check_cmdbuf_irq(dev, cmdbuf_obj, irq_status_ret) == 1) {
+    /* Return cmdbuf_id when ANY_CMDBUF_ID is used. */
+      if (!cmdbuf_obj->waited) {
+        *irq_status_ret = cmdbuf_obj->cmdbuf_id;
+        cmdbuf_obj->waited = 1;
+        return 1;
+      }
+    }
+  }
+  // check no job
+  //if (k == TOTAL_DISCRETE_CMDBUF_NUM)
+  //  return 1;
+  return 0;
+}
+
+#ifdef IRQ_SIMULATION
+void get_random_bytes(void *buf, int nbytes);
+#if 0
+void hantrovcmd_trigger_irq_0(struct timer_list* timer)
+{
+  PDEBUG("trigger core 0 irq\n");
+  del_timer(timer);
+  hantrovcmd_isr(0,(void *)&hantrovcmd_data[0]);
+}
+void hantrovcmd_trigger_irq_1(struct timer_list* timer)
+{
+  PDEBUG("trigger core 1 irq\n");
+  del_timer(timer);
+  hantrovcmd_isr(0,(void *)&hantrovcmd_data[1]);
+}
+#else
+void hantrovcmd_trigger_irq(TimerHandle_t * /*struct timer_list * */ timer)
+{
+
+  u32 timer_id = 0;
+  u32 core_id = 0;
+  u32 i;
+  for (i = 0; i < 10000; i++)
+  {
+    if (timer_reserve[i].timer == timer)
+    {
+      timer_id = timer_reserve[i].timer_id;
+      core_id = timer_reserve[i].core_id;
+      break;
+    }
+  }
+  PDEBUG("trigger core 0 irq\n");
+  hantrovcmd_isr(/*core_id,*/ (void *)&hantrovcmd_data[core_id]);
+
+  //del_timer(timer);
+  xTimerDelete(timer);
+  timer_reserve[timer_id].timer = NULL;
+}
+
+#endif
+#endif
+
+static unsigned int wait_cmdbuf_ready(/*struct file */ int filp, u16 cmdbuf_id, u32 *irq_status_ret)
+{
+  struct cmdbuf_obj *cmdbuf_obj = NULL;
+  bi_list_node *new_cmdbuf_node = NULL;
+  struct hantrovcmd_dev *dev = NULL;
+  if(cmdbuf_id != ANY_CMDBUF_ID) {
+    PDEBUG("wait_cmdbuf_ready cmdbuf_id [%d]\n", cmdbuf_id);
+    new_cmdbuf_node = global_cmdbuf_node[cmdbuf_id];
+    if (new_cmdbuf_node == NULL)
+    {
+      //should not happen
+      printk(KERN_ERR "hantrovcmd: ERROR cmdbuf_id !!\n");
+      return -1;
+    }
+    cmdbuf_obj = (struct cmdbuf_obj *)new_cmdbuf_node->data;
+    if (cmdbuf_obj->filp != filp)
+    {
+      //should not happen
+      printk(KERN_ERR "hantrovcmd: ERROR cmdbuf_id !!\n");
+      return -1;
+    }
+    dev = &hantrovcmd_data[cmdbuf_obj->core_id];
+#ifdef IRQ_SIMULATION
+    {
+      u32 random_num;
+      //get_random_bytes(&random_num, sizeof(u32));
+      random_num = (u32)((u64)100 * cmdbuf_obj->executing_time / (4096 * 2160) + 50);
+      PDEBUG("random_num=%d\n", random_num);
+#if 0
+      /*init a timer to trigger irq*/
+      if (cmdbuf_obj->core_id==0)
+      {
+        //init_timer(&timer0);
+        //timer0.function = hantrovcmd_trigger_irq_0;
+        timer_setup(&timer0,hantrovcmd_trigger_irq_0,0);
+        timer0.expires =  jiffies + random_num*HZ/10; //the expires time is 1s
+        add_timer(&timer0);
+      }
+
+      if (cmdbuf_obj->core_id==1)
+      {
+        //init_timer(&timer1);
+        //timer1.function = hantrovcmd_trigger_irq_1;
+        timer_setup(&timer1,hantrovcmd_trigger_irq_1,0);
+        timer1.expires =  jiffies + random_num*HZ/10; //the expires time is 1s
+        add_timer(&timer1);
+      }
+#else
+      {
+        u32 i;
+        /*struct timer_list */ TimerHandle_t *temp_timer = NULL;
+        for (i = 0; i < 10000; i++)
+        {
+          if (timer_reserve[i].timer == NULL)
+          {
+            timer_reserve[i].timer_id = i;
+            timer_reserve[i].core_id = cmdbuf_obj->core_id;
+            temp_timer = timer_reserve[i].timer = &timer[i];
+            break;
+          }
+        }
+        //if (cmdbuf_obj->core_id==0)
+        {
+#if 1
+          temp_timer = xTimerCreate("Timer", pdMS_TO_TICKS(1000), pdTRUE, (void *)0, hantrovcmd_trigger_irq);
+          if (temp_timer == NULL)
+          {
+            /* The timer was not created. */
+          }
+          else if (xTimerStart(temp_timer, 0) != pdPASS)
+          {
+            /* The timer could not be set into the Active state. */
+          }
+
+#else
+          //init_timer(&timer0);
+          //timer0.function = hantrovcmd_trigger_irq_0;
+
+          timer_setup(temp_timer, hantrovcmd_trigger_irq, 0);
+          temp_timer->expires = jiffies + random_num * HZ / 10; //the expires time is 1s
+          add_timer(temp_timer);
+#endif
+        }
+      }
+#endif
+    }
+#endif
+#if 1
+#if 1
+    //use yield
+    while(1)
+    {
+      if (cmdbuf_obj->cmdbuf_run_done)
+        break;
+      sched_yield();
+    }
+#else
+    //wait a wait_queue
+    if (queue_vcmd_wait(&wait_queue_vcmd[cmdbuf_obj->cmdbuf_id]))
+    {
+      PDEBUG("wait vcmd_wait_queue failed\n");
+      //abort the vcmd
+      vcmd_write_register_value((const void *)dev->hwregs, dev->reg_mirror, HWIF_VCMD_START_TRIGGER, 0);
+      return -ERESTARTSYS;
+    }
+#endif
+#else
+    if (wait_event_interruptible(*dev->wait_queue, check_cmdbuf_irq(dev, cmdbuf_obj, irq_status_ret)))
+    {
+      PDEBUG("vcmd_wait_queue_0 interrupted\n");
+      //abort the vcmd
+      vcmd_write_register_value((const void *)dev->hwregs, dev->reg_mirror, HWIF_VCMD_START_TRIGGER, 0);
+      return -ERESTARTSYS;
+    }
+#endif
+  } else {
+    /*if (check_mc_cmdbuf_irq(filp, cmdbuf_obj, irq_status_ret))
+      return 0;
+    if (wait_event_interruptible(mc_wait_queue, check_mc_cmdbuf_irq(filp, cmdbuf_obj, irq_status_ret)))
+    {
+      PDEBUG("multicore wait_queue interrupted\n");
+      return -ERESTARTSYS;
+    }*/
+
+    while(1) {
+      if (check_mc_cmdbuf_irq(filp, cmdbuf_obj, irq_status_ret)) {
+        return 0;
+      }
+
+      queue_vcmd_wait(&mc_wait_queue);
+    }
+  }
+  
+  return 0;
+}
+
+long hantrovcmd_ioctl(int filp, unsigned int cmd, void *arg)
+{
+  int err = 0;
+
+  PDEBUG("ioctl cmd 0x%08x, filp 0x%x\n", cmd, filp);
+  /*
+     * extract the type and number bitfields, and don't encode
+     * wrong cmds: return ENOTTY (inappropriate ioctl) before access_ok()
+     */
+  if (_IOC_TYPE(cmd) != HANTRO_VCMD_IOC_MAGIC)
+    return -ENOTTY;
+  if ((_IOC_TYPE(cmd) == HANTRO_VCMD_IOC_MAGIC &&
+       _IOC_NR(cmd) > HANTRO_VCMD_IOC_MAXNR))
+    return -ENOTTY;
+
+  /*
+     * the direction is a bitmask, and VERIFY_WRITE catches R/W
+     * transfers. `Type' is user-oriented, while
+     * access_ok is kernel-oriented, so the concept of "read" and
+     * "write" is reversed
+     */
+  if (_IOC_DIR(cmd) & _IOC_READ)
+    err = !access_ok(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd));
+  else if (_IOC_DIR(cmd) & _IOC_WRITE)
+    err = !access_ok(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd));
+  if (err)
+    return -EFAULT;
+
+  switch (cmd)
+  {
+  case HANTRO_VCMD_IOCH_GET_CMDBUF_PARAMETER:
+  {
+    struct cmdbuf_mem_parameter local_cmdbuf_mem_data = {NULL, 0};
+    PDEBUG("VCMD-Get VCMD CMDBUF Parameter. \n");
+    local_cmdbuf_mem_data.cmdbuf_unit_size = CMDBUF_MAX_SIZE;
+    local_cmdbuf_mem_data.status_cmdbuf_unit_size = CMDBUF_MAX_SIZE;
+    local_cmdbuf_mem_data.cmdbuf_total_size = CMDBUF_POOL_TOTAL_SIZE;
+    local_cmdbuf_mem_data.status_cmdbuf_total_size = CMDBUF_POOL_TOTAL_SIZE;
+    local_cmdbuf_mem_data.phy_status_cmdbuf_addr = vcmd_status_buf_mem_pool.busAddress;
+    local_cmdbuf_mem_data.phy_cmdbuf_addr = vcmd_buf_mem_pool.busAddress;
+    local_cmdbuf_mem_data.base_ddr_addr = base_ddr_addr;
+    copy_to_user((struct cmdbuf_mem_parameter *)arg, &local_cmdbuf_mem_data, sizeof(struct cmdbuf_mem_parameter));
+    break;
+  }
+  case HANTRO_VCMD_IOCH_GET_VCMD_PARAMETER:
+  {
+    struct config_parameter input_para = {0};
+    PDEBUG("VCMD-Get VCMD Config Parameter. \n");
+    copy_from_user(&input_para, (struct config_parameter *)arg, sizeof(struct config_parameter));
+    if (vcmd_type_core_num[input_para.module_type])
+    {
+      input_para.submodule_main_addr = vcmd_manager[input_para.module_type][0]->vcmd_core_cfg.submodule_main_addr;
+      input_para.submodule_dec400_addr = vcmd_manager[input_para.module_type][0]->vcmd_core_cfg.submodule_dec400_addr;
+      input_para.submodule_L2Cache_addr = vcmd_manager[input_para.module_type][0]->vcmd_core_cfg.submodule_L2Cache_addr;
+      input_para.submodule_MMU_addr = vcmd_manager[input_para.module_type][0]->vcmd_core_cfg.submodule_MMU_addr;
+      input_para.config_status_cmdbuf_id = vcmd_manager[input_para.module_type][0]->status_cmdbuf_id;
+      input_para.vcmd_hw_version_id = vcmd_manager[input_para.module_type][0]->hw_version_id;
+      input_para.vcmd_core_num = vcmd_type_core_num[input_para.module_type];
+    }
+    else
+    {
+      input_para.submodule_main_addr = 0xffff;
+      input_para.submodule_dec400_addr = 0xffff;
+      input_para.submodule_L2Cache_addr = 0xffff;
+      input_para.submodule_MMU_addr = 0xffff;
+      input_para.config_status_cmdbuf_id = 0;
+      input_para.vcmd_core_num = 0;
+      input_para.vcmd_hw_version_id = HW_ID_1_0_C;
+    }
+    copy_to_user((struct config_parameter *)arg, &input_para, sizeof(struct config_parameter));
+    break;
+  }
+  case HANTRO_VCMD_IOCH_RESERVE_CMDBUF:
+  {
+    int ret = 0;
+    struct exchange_parameter input_para = {0};
+    PDEBUG("VCMD-Reserve CMDBUF. \n");
+    copy_from_user(&input_para, (struct exchange_parameter *)arg, sizeof(struct exchange_parameter));
+    ret = reserve_cmdbuf(filp, &input_para);
+    if (ret == 0)
+      copy_to_user((struct exchange_parameter *)arg, &input_para, sizeof(struct exchange_parameter));
+    return ret;
+  }
+
+  case HANTRO_VCMD_IOCH_LINK_RUN_CMDBUF:
+  {
+    struct exchange_parameter input_para = {0};
+    long retVal = 0;
+    copy_from_user(&input_para, (struct exchange_parameter *)arg, sizeof(struct exchange_parameter));
+
+    PDEBUG("VCMD-Link and Run CMDBUF. \n");
+    retVal = link_and_run_cmdbuf(filp, &input_para);
+    copy_to_user((struct exchange_parameter *)arg, &input_para, sizeof(struct exchange_parameter));
+    return retVal;
+    break;
+  }
+
+  case HANTRO_VCMD_IOCH_WAIT_CMDBUF:
+  {
+    u16 cmdbuf_id = 0;
+    unsigned int tmp = 0;
+    u32 irq_status_ret = 0;
+    __get_user(cmdbuf_id, (u16 *)arg);
+    /*high 16 bits are core id, low 16 bits are cmdbuf_id*/
+
+    PDEBUG("VCMD-Wait for CMDBUF Finishing. \n");
+    tmp = wait_cmdbuf_ready(filp, cmdbuf_id, &irq_status_ret);
+    cmdbuf_id = (u16)irq_status_ret;
+    if (tmp == 0)
+    {
+      __put_user(cmdbuf_id, (u16 *)arg);
+      return tmp; //return core_id
+    }
+    else
+    {
+      __put_user(0, (u16 *)arg);
+      return -1;
+    }
+
+    break;
+  }
+  case HANTRO_VCMD_IOCH_RELEASE_CMDBUF:
+  {
+    u16 cmdbuf_id = 0;
+    __get_user(cmdbuf_id, (u16 *)arg);
+    /*16 bits are cmdbuf_id*/
+
+    PDEBUG("VCMD-Release CMDBUF. \n");
+    release_cmdbuf(filp, cmdbuf_id);
+    return 0;
+    break;
+  }
+  case HANTRO_VCMD_IOCH_POLLING_CMDBUF:
+  {
+    u16 core_id = 0;
+    __get_user(core_id, (u16 *)arg);
+    /*16 bits are cmdbuf_id*/
+    if (core_id >= total_vcmd_core_num)
+      return -1;
+    hantrovcmd_isr(/*core_id,*/ &hantrovcmd_data[core_id]);
+    return 0;
+    break;
+  }
+  default:
+  {
+    break;
+  }
+  }
+  return 0;
+}
+/**********************************************************************************************************\
+*process manager object management
+\***********************************************************************************************************/
+#if PROCESS_MANAGER
+static struct process_manager_obj *create_process_manager_obj(void)
+{
+  struct process_manager_obj *process_manager_obj = NULL;
+  process_manager_obj = vmalloc(sizeof(struct process_manager_obj));
+  if (process_manager_obj == NULL)
+  {
+    PDEBUG("%s\n", "vmalloc for process_manager_obj fail!");
+    return process_manager_obj;
+  }
+  memset(process_manager_obj, 0, sizeof(struct process_manager_obj));
+  return process_manager_obj;
+}
+
+static void free_process_manager_obj(struct process_manager_obj *process_manager_obj)
+{
+  if (process_manager_obj == NULL)
+  {
+    PDEBUG("%s\n", "free_process_manager_obj NULL");
+    return;
+  }
+  //free current cmdbuf_obj
+  vfree(process_manager_obj);
+  return;
+}
+
+static bi_list_node *create_process_manager_node(void)
+{
+  bi_list_node *current_node = NULL;
+  struct process_manager_obj *process_manager_obj = NULL;
+
+  process_manager_obj = create_process_manager_obj();
+  if (process_manager_obj == NULL)
+  {
+    PDEBUG("%s\n", "create_process_manager_obj fail!");
+    return NULL;
+  }
+  process_manager_obj->total_exe_time = 0;
+  spin_lock_init(&process_manager_obj->spinlock);
+  //init_waitqueue_head(&process_manager_obj->wait_queue);
+  sem_init(&process_manager_obj->wait_queue, 0, ???);
+  current_node = bi_list_create_node();
+  if (current_node == NULL)
+  {
+    PDEBUG("%s\n", "bi_list_create_node fail!");
+    free_process_manager_obj(process_manager_obj);
+    return NULL;
+  }
+  current_node->data = (void *)process_manager_obj;
+  return current_node;
+}
+static void free_process_manager_node(bi_list_node *process_node)
+{
+  struct process_manager_obj *process_manager_obj = NULL;
+  if (process_node == NULL)
+  {
+    PDEBUG("%s\n", "free_process_manager_node NULL");
+    return;
+  }
+  process_manager_obj = (struct process_manager_obj *)process_node->data;
+  //free struct process_manager_obj
+  free_process_manager_obj(process_manager_obj);
+  //free current process_manager_obj entity.
+  bi_list_free_node(process_node);
+  return;
+}
+
+static long release_process_node_cleanup(bi_list *list)
+{
+  bi_list_node *new_process_node = NULL;
+
+  while (1)
+  {
+    new_process_node = list->head;
+    if (new_process_node == NULL)
+      break;
+    //remove node from list
+    bi_list_remove_node(list, new_process_node);
+    //remove node from list
+    free_process_manager_node(new_process_node);
+  }
+  return 0;
+}
+
+static void create_kernel_process_manager(void)
+{
+  bi_list_node *process_manager_node;
+  struct process_manager_obj *process_manager_obj = NULL;
+  process_manager_node = create_process_manager_node();
+  process_manager_obj = (struct process_manager_obj *)process_manager_node->data;
+  //process_manager_obj->filp = NULL;
+  process_manager_obj->filp = 0;
+  bi_list_insert_node_tail(&global_process_manager, process_manager_node);
+}
+#endif
+
+int hantrovcmd_open(int *inode, int filp)
+{
+  int result = 0;
+  struct hantrovcmd_dev *dev = hantrovcmd_data;
+#if PROCESS_MANAGER
+  bi_list_node *process_manager_node;
+  unsigned long flags;
+  struct process_manager_obj *process_manager_obj = NULL;
+
+  //filp->private_data = (void *) dev;
+  process_manager_node = create_process_manager_node();
+  if (process_manager_node == NULL)
+    return -1;
+  process_manager_obj = (struct process_manager_obj *)process_manager_node->data;
+  process_manager_obj->filp = filp;
+  spin_lock_irqsave(&vcmd_process_manager_lock, flags);
+  bi_list_insert_node_tail(&global_process_manager, process_manager_node);
+  spin_unlock_irqrestore(&vcmd_process_manager_lock, flags);
+#endif
+  PDEBUG("dev opened, filp 0x%x\n", filp);
+  return result;
+}
+int hantrovcmd_release(/*struct inode*/ int *inode, /*struct file */ int filp)
+{
+  struct hantrovcmd_dev *dev; // = hantrovcmd_data; //(struct hantrovcmd_dev *) filp->private_data;
+  u32 core_id = 0;
+  u32 release_cmdbuf_num = 0;
+  bi_list_node *new_cmdbuf_node = NULL;
+  struct cmdbuf_obj *cmdbuf_obj_temp = NULL;
+#if PROCESS_MANAGER
+  bi_list_node *process_manager_node;
+  struct process_manager_obj *process_manager_obj = NULL;
+#endif
+  unsigned long flags;
+  long retVal = 0;
+
+  PDEBUG("dev closed, filp 0x%x\n", filp);
+//  printf(".");
+
+  for (core_id = 0; core_id < total_vcmd_core_num; core_id++)
+  {
+    dev = &hantrovcmd_data[core_id];
+    if (dev->hwregs == NULL)
+      continue;
+    if (down_interruptible(&vcmd_reserve_cmdbuf_sem[dev->vcmd_core_cfg.sub_module_type]))
+      return -ERESTARTSYS;
+    spin_lock_irqsave(dev->spinlock, flags);
+    new_cmdbuf_node = dev->list_manager.head;
+    while (1)
+    {
+      if (new_cmdbuf_node == NULL)
+        break;
+      cmdbuf_obj_temp = (struct cmdbuf_obj *)new_cmdbuf_node->data;
+      if (cmdbuf_obj_temp->filp == filp)
+      {
+        if (cmdbuf_obj_temp->cmdbuf_run_done)
+        {
+          cmdbuf_obj_temp->cmdbuf_need_remove = 1;
+          retVal = release_cmdbuf_node(&dev->list_manager, new_cmdbuf_node);
+#if PROCESS_MANAGER
+          if (retVal == 1)
+            cmdbuf_obj_temp->process_manager_obj = NULL;
+#endif
+        }
+        else if (cmdbuf_obj_temp->cmdbuf_data_linked == 0)
+        {
+          cmdbuf_obj_temp->cmdbuf_data_linked = 1;
+          cmdbuf_obj_temp->cmdbuf_run_done = 1;
+          cmdbuf_obj_temp->cmdbuf_need_remove = 1;
+          retVal = release_cmdbuf_node(&dev->list_manager, new_cmdbuf_node);
+#if PROCESS_MANAGER
+          if (retVal == 1)
+            cmdbuf_obj_temp->process_manager_obj = NULL;
+#endif
+        }
+        else if (cmdbuf_obj_temp->cmdbuf_data_linked == 1 && dev->working_state == WORKING_STATE_IDLE)
+        {
+          cmdbuf_obj_temp->cmdbuf_run_done = 1;
+          cmdbuf_obj_temp->cmdbuf_need_remove = 1;
+          retVal = release_cmdbuf_node(&dev->list_manager, new_cmdbuf_node);
+#if PROCESS_MANAGER
+          if (retVal == 1)
+            cmdbuf_obj_temp->process_manager_obj = NULL;
+#endif
+        }
+        else if (cmdbuf_obj_temp->cmdbuf_data_linked == 1 && dev->working_state == WORKING_STATE_WORKING)
+        {
+          bi_list_node *last_cmdbuf_node;
+          u32 record_last_cmdbuf_rdy_num;
+          //abort the vcmd and wait
+          vcmd_write_register_value((const void *)dev->hwregs, dev->reg_mirror, HWIF_VCMD_START_TRIGGER, 0);
+#if 1
+#if 1
+          while(1)
+          {
+            if (cmdbuf_obj_temp->cmdbuf_run_done)
+              break;
+            sched_yield();
+          }
+#else
+          queue_vcmd_wait(&abort_queue_vcmd[cmdbuf_obj_temp->cmdbuf_id]);
+#endif
+#else
+          if (wait_event_interruptible(*dev->wait_abort_queue, wait_abort_rdy(&dev[core_id])))
+            return -ERESTARTSYS;
+#endif
+
+          cmdbuf_obj_temp->cmdbuf_run_done = 1;
+          cmdbuf_obj_temp->cmdbuf_need_remove = 1;
+          //printf("hantrovcmd_release before: vcmd_cmdbuf_memory_wait sem value %d\n", vcmd_cmdbuf_memory_wait.value);
+          retVal = release_cmdbuf_node(&dev->list_manager, new_cmdbuf_node);
+#if PROCESS_MANAGER
+          if (retVal == 1)
+            cmdbuf_obj_temp->process_manager_obj = NULL;
+#endif
+          //link
+          last_cmdbuf_node = find_last_linked_cmdbuf(dev->list_manager.tail);
+          record_last_cmdbuf_rdy_num = dev->sw_cmdbuf_rdy_num;
+          vcmd_link_cmdbuf(dev, last_cmdbuf_node);
+          //re-run
+          if (dev->sw_cmdbuf_rdy_num)
+            vcmd_start(dev, last_cmdbuf_node);
+        }
+        release_cmdbuf_num++;
+      }
+      new_cmdbuf_node = new_cmdbuf_node->next;
+    }
+    spin_unlock_irqrestore(dev->spinlock, flags);
+    up(&vcmd_reserve_cmdbuf_sem[dev->vcmd_core_cfg.sub_module_type]);
+  }
+#if 0    
+    if(release_cmdbuf_num)
+      wake_up_interruptible_all(&vcmd_cmdbuf_memory_wait);
+#endif
+#if PROCESS_MANAGER
+  spin_lock_irqsave(&vcmd_process_manager_lock, flags);
+  process_manager_node = global_process_manager.head;
+  while (1)
+  {
+    if (process_manager_node == NULL)
+      break;
+    process_manager_obj = (struct process_manager_obj *)process_manager_node->data;
+    if (process_manager_obj->filp == filp)
+      break;
+    process_manager_node = process_manager_node->next;
+  }
+  //remove node from list
+  PDEBUG("process node %p for filp to be removed: %p\n", (void *)process_manager_node, (void *)process_manager_obj->filp);
+  bi_list_remove_node(&global_process_manager, process_manager_node);
+  spin_unlock_irqrestore(&vcmd_process_manager_lock, flags);
+  free_process_manager_node(process_manager_node);
+#endif
+  return 0;
+}
+
+
+static void vcmd_link_cmdbuf(struct hantrovcmd_dev *dev, bi_list_node *last_linked_cmdbuf_node)
+{
+  bi_list_node *new_cmdbuf_node = NULL;
+  bi_list_node *next_cmdbuf_node = NULL;
+  struct cmdbuf_obj *cmdbuf_obj = NULL;
+  struct cmdbuf_obj *next_cmdbuf_obj = NULL;
+  u32 *jmp_addr = NULL;
+  u32 operation_code = 0;
+  new_cmdbuf_node = last_linked_cmdbuf_node;
+  //for the first cmdbuf.
+  if (new_cmdbuf_node != NULL)
+  {
+    cmdbuf_obj = (struct cmdbuf_obj *)new_cmdbuf_node->data;
+    if (cmdbuf_obj->cmdbuf_data_linked == 0)
+    {
+      dev->sw_cmdbuf_rdy_num++;
+      cmdbuf_obj->cmdbuf_data_linked = 1;
+      dev->duration_without_int = 0;
+      if (cmdbuf_obj->has_end_cmdbuf == 0)
+      {
+        if (cmdbuf_obj->no_normal_int_cmdbuf == 1)
+        {
+          dev->duration_without_int = cmdbuf_obj->executing_time;
+          //maybe nop is modified, so write back.
+          if (dev->duration_without_int >= INT_MIN_SUM_OF_IMAGE_SIZE)
+          {
+            jmp_addr = cmdbuf_obj->cmdbuf_virtualAddress + (cmdbuf_obj->cmdbuf_size / 4);
+            operation_code = *(jmp_addr - 4);
+            operation_code = JMP_IE_1 | operation_code;
+            *(jmp_addr - 4) = operation_code;
+            dev->duration_without_int = 0;
+          }
+        }
+      }
+    }
+  }
+  while (1)
+  {
+    if (new_cmdbuf_node == NULL)
+      break;
+    if (new_cmdbuf_node->next == NULL)
+      break;
+    next_cmdbuf_node = new_cmdbuf_node->next;
+    cmdbuf_obj = (struct cmdbuf_obj *)new_cmdbuf_node->data;
+    next_cmdbuf_obj = (struct cmdbuf_obj *)next_cmdbuf_node->data;
+    if (cmdbuf_obj->has_end_cmdbuf == 0)
+    {
+      //need to link, current cmdbuf link to next cmdbuf
+      jmp_addr = cmdbuf_obj->cmdbuf_virtualAddress + (cmdbuf_obj->cmdbuf_size / 4);
+      if (dev->hw_version_id > HW_ID_1_0_C)
+      {
+        //set next cmdbuf id
+        *(jmp_addr - 1) = next_cmdbuf_obj->cmdbuf_id;
+      }
+      if (sizeof(ptr_t) == 8)
+      {
+        *(jmp_addr - 2) = (u32)((u64)(next_cmdbuf_obj->cmdbuf_busAddress - base_ddr_addr) >> 32);
+      }
+      else
+      {
+        *(jmp_addr - 2) = 0;
+      }
+      *(jmp_addr - 3) = (u32)(next_cmdbuf_obj->cmdbuf_busAddress - base_ddr_addr);
+      operation_code = *(jmp_addr - 4);
+      operation_code >>= 16;
+      operation_code <<= 16;
+      *(jmp_addr - 4) = (u32)(operation_code | JMP_RDY_1 | ((next_cmdbuf_obj->cmdbuf_size + 7) / 8));
+      next_cmdbuf_obj->cmdbuf_data_linked = 1;
+      dev->sw_cmdbuf_rdy_num++;
+      //modify nop code of next cmdbuf
+      if (next_cmdbuf_obj->has_end_cmdbuf == 0)
+      {
+        if (next_cmdbuf_obj->no_normal_int_cmdbuf == 1)
+        {
+          dev->duration_without_int += next_cmdbuf_obj->executing_time;
+
+          //maybe we see the modified nop before abort, so need to write back.
+          if (dev->duration_without_int >= INT_MIN_SUM_OF_IMAGE_SIZE)
+          {
+            jmp_addr = next_cmdbuf_obj->cmdbuf_virtualAddress + (next_cmdbuf_obj->cmdbuf_size / 4);
+            operation_code = *(jmp_addr - 4);
+            operation_code = JMP_IE_1 | operation_code;
+            *(jmp_addr - 4) = operation_code;
+            dev->duration_without_int = 0;
+          }
+        }
+      }
+      else
+      {
+        dev->duration_without_int = 0;
+      }
+#ifdef VCMD_DEBUG_INTERNAL
+      {
+        u32 i;
+        printk(KERN_INFO "vcmd link, last cmdbuf content\n");
+        for (i = cmdbuf_obj->cmdbuf_size / 4 - 8; i < cmdbuf_obj->cmdbuf_size / 4; i++)
+        {
+          printk(KERN_INFO "current linked cmdbuf data %d =0x%x\n", i, *(cmdbuf_obj->cmdbuf_virtualAddress + i));
+        }
+      }
+#endif
+    }
+    else
+      break;
+    new_cmdbuf_node = new_cmdbuf_node->next;
+  }
+  return;
+}
+
+/*------------------------------------------------------------------------------
+ Function name   : vcmd_pcie_init
+ Description     : Initialize PCI Hw access
+
+ Return type     : int
+ ------------------------------------------------------------------------------*/
+static int vcmd_pcie_init(void)
+{
+  int i = 0;
+
+  g_vcmd_dev = pci_get_device(PCI_VENDOR_ID_HANTRO, PCI_DEVICE_ID_HANTRO_PCI, g_vcmd_dev);
+  //if (NULL == g_vcmd_dev) {
+  //    printk(KERN_ERR "Init: Hardware not found.\n");
+  //    goto out;
+  //}
+
+  if (0 > pci_enable_device(g_vcmd_dev))
+  {
+    printk(KERN_ERR "Init: Device not enabled.\n");
+    goto out;
+  }
+
+  g_vcmd_base_hdwr = pci_resource_start(g_vcmd_dev, PCI_H2_BAR);
+  //if (0 > g_vcmd_base_hdwr) {
+  //    printk(KERN_INFO "Init: Base Address not set.\n");
+  //    goto out_pci_disable_device;
+  //}
+  printk(KERN_INFO "Base hw val 0x%llx\n", (long long unsigned int)g_vcmd_base_hdwr);
+
+  g_vcmd_base_len = pci_resource_len(g_vcmd_dev, PCI_H2_BAR);
+  printk(KERN_INFO "Base hw len 0x%d\n", (unsigned int)g_vcmd_base_len);
+
+  for (i = 0; i < total_vcmd_core_num; i++)
+  {
+    vcmd_core_array[i].vcmd_base_addr = g_vcmd_base_hdwr + vcmd_core_array[i].vcmd_base_addr; //the offset is based on which bus interface is chosen
+  }
+
+  vcmd_sram_base = g_vcmd_base_hdwr + 0x000000; //axi0 interface
+  vcmd_sram_size = 0x80000;
+
+  g_vcmd_base_ddr_hw = pci_resource_start(g_vcmd_dev, PCI_DDR_BAR);
+  //if (0 > g_vcmd_base_ddr_hw) {
+  //  printk(KERN_INFO "PcieInit: Base Address not set.\n");
+  //  goto out_pci_disable_device;
+  //}
+  printk(KERN_INFO "Base memory val 0x%08x\n", (unsigned int)g_vcmd_base_ddr_hw);
+  base_ddr_addr = g_vcmd_base_ddr_hw;
+  g_vcmd_base_len = pci_resource_len(g_vcmd_dev, PCI_DDR_BAR);
+  printk(KERN_INFO "Base memory len 0x%d\n", (unsigned int)g_vcmd_base_len);
+
+  //Get bus addr for VCMD devide
+  vcmd_buf_mem_pool.busAddress = GetBusAddrForIODevide(CMDBUF_POOL_TOTAL_SIZE * 2 + 0x100000); //5M //g_vcmd_base_ddr_hw+0x800000;
+  vcmd_buf_mem_pool.size = CMDBUF_POOL_TOTAL_SIZE;
+  if (!request_mem_region(vcmd_buf_mem_pool.busAddress, vcmd_buf_mem_pool.size,
+                          "vc8000_vcmd_driver"))
+  {
+    printk(KERN_INFO "Init: failed to request hw region.\n");
+    return -1;
+  }
+  printk(KERN_INFO "Init: vcmd_buf_mem_pool.busAddress=0x%llx.\n", (long long unsigned int)vcmd_buf_mem_pool.busAddress);
+
+  vcmd_buf_mem_pool.virtualAddress = (u32 *)DirectMemoryMap(vcmd_buf_mem_pool.busAddress, vcmd_buf_mem_pool.size);
+
+  if (vcmd_buf_mem_pool.virtualAddress == NULL)
+  {
+    printk(KERN_INFO "Init: failed to ioremap.\n");
+    return -1;
+  }
+  printk(KERN_INFO "Init: vcmd_buf_mem_pool.virtualAddress=0x%llx.\n", (long long unsigned int)vcmd_buf_mem_pool.virtualAddress);
+
+  vcmd_status_buf_mem_pool.busAddress = vcmd_buf_mem_pool.busAddress + CMDBUF_POOL_TOTAL_SIZE;
+  vcmd_status_buf_mem_pool.size = CMDBUF_POOL_TOTAL_SIZE;
+  if (!request_mem_region(vcmd_status_buf_mem_pool.busAddress, vcmd_status_buf_mem_pool.size,
+                          "vc8000_vcmd_driver"))
+  {
+    printk(KERN_INFO "Init: failed to request hw region.\n");
+    return -1;
+  }
+  printk(KERN_INFO "Init: vcmd_status_buf_mem_pool.busAddress=0x%llx.\n", (long long unsigned int)vcmd_status_buf_mem_pool.busAddress);
+  vcmd_status_buf_mem_pool.virtualAddress = (u32 *)DirectMemoryMap(vcmd_status_buf_mem_pool.busAddress,
+                                                                   vcmd_status_buf_mem_pool.size);
+
+  if (vcmd_status_buf_mem_pool.virtualAddress == NULL)
+  {
+    printk(KERN_INFO "Init: failed to ioremap.\n");
+    return -1;
+  }
+  printk(KERN_INFO "Init: vcmd_status_buf_mem_pool.virtualAddress=0x%llx.\n", (long long unsigned int)vcmd_status_buf_mem_pool.virtualAddress);
+
+  vcmd_registers_mem_pool.busAddress = vcmd_status_buf_mem_pool.busAddress + CMDBUF_POOL_TOTAL_SIZE;
+  vcmd_registers_mem_pool.size = CMDBUF_VCMD_REGISTER_TOTAL_SIZE;
+  if (!request_mem_region(vcmd_registers_mem_pool.busAddress, vcmd_registers_mem_pool.size,
+                          "vc8000_vcmd_driver"))
+  {
+    printk(KERN_INFO "Init: failed to request hw region.\n");
+    return -1;
+  }
+  printk(KERN_INFO "Init: vcmd_registers_mem_pool.busAddress=0x%llx.\n", (long long unsigned int)vcmd_registers_mem_pool.busAddress);
+  vcmd_registers_mem_pool.virtualAddress = (u32 *)DirectMemoryMap(vcmd_registers_mem_pool.busAddress,
+                                                                  vcmd_registers_mem_pool.size);
+
+  if (vcmd_registers_mem_pool.virtualAddress == NULL)
+  {
+    printk(KERN_INFO "Init: failed to ioremap.\n");
+    return -1;
+  }
+  printk(KERN_INFO "Init: vcmd_registers_mem_pool.virtualAddress=0x%llx.\n", (long long unsigned int)vcmd_registers_mem_pool.virtualAddress);
+
+  return 0;
+
+out_pci_disable_device:
+  pci_disable_device(g_vcmd_dev);
+out:
+  return -1;
+}
+
+static void vcmd_delink_cmdbuf(struct hantrovcmd_dev *dev, bi_list_node *last_linked_cmdbuf_node)
+{
+  bi_list_node *new_cmdbuf_node = NULL;
+  struct cmdbuf_obj *cmdbuf_obj = NULL;
+
+  new_cmdbuf_node = last_linked_cmdbuf_node;
+  while (1)
+  {
+    if (new_cmdbuf_node == NULL)
+      break;
+    cmdbuf_obj = (struct cmdbuf_obj *)new_cmdbuf_node->data;
+    if (cmdbuf_obj->cmdbuf_data_linked)
+    {
+      cmdbuf_obj->cmdbuf_data_linked = 0;
+    }
+    else
+      break;
+    new_cmdbuf_node = new_cmdbuf_node->next;
+  }
+  dev->sw_cmdbuf_rdy_num = 0;
+}
+
+static void vcmd_start(struct hantrovcmd_dev *dev, bi_list_node *first_linked_cmdbuf_node)
+{
+  struct cmdbuf_obj *cmdbuf_obj = NULL;
+
+  if (dev->working_state == WORKING_STATE_IDLE)
+  {
+    if ((first_linked_cmdbuf_node != NULL) && dev->sw_cmdbuf_rdy_num)
+    {
+      cmdbuf_obj = (struct cmdbuf_obj *)first_linked_cmdbuf_node->data;
+      //0x40
+      vcmd_set_register_mirror_value(dev->reg_mirror, HWIF_VCMD_AXI_CLK_GATE_DISABLE, 0);
+      vcmd_set_register_mirror_value(dev->reg_mirror, HWIF_VCMD_MASTER_OUT_CLK_GATE_DISABLE, 1); //this bit should be set 1 only when need to reset dec400
+      vcmd_set_register_mirror_value(dev->reg_mirror, HWIF_VCMD_CORE_CLK_GATE_DISABLE, 0);
+      vcmd_set_register_mirror_value(dev->reg_mirror, HWIF_VCMD_ABORT_MODE, 0);
+      vcmd_set_register_mirror_value(dev->reg_mirror, HWIF_VCMD_RESET_CORE, 0);
+      vcmd_set_register_mirror_value(dev->reg_mirror, HWIF_VCMD_RESET_ALL, 0);
+      vcmd_set_register_mirror_value(dev->reg_mirror, HWIF_VCMD_START_TRIGGER, 0);
+      //0x48
+      if (dev->hw_version_id <= HW_ID_1_0_C)
+      {
+        vcmd_set_register_mirror_value(dev->reg_mirror, HWIF_VCMD_IRQ_INTCMD_EN, 0xffff);
+      }
+      else
+      {
+        vcmd_set_register_mirror_value(dev->reg_mirror, HWIF_VCMD_IRQ_JMPP_EN, 1);
+        vcmd_set_register_mirror_value(dev->reg_mirror, HWIF_VCMD_IRQ_JMPD_EN, 1);
+      }
+      vcmd_set_register_mirror_value(dev->reg_mirror, HWIF_VCMD_IRQ_RESET_EN, 1);
+      vcmd_set_register_mirror_value(dev->reg_mirror, HWIF_VCMD_IRQ_ABORT_EN, 1);
+      vcmd_set_register_mirror_value(dev->reg_mirror, HWIF_VCMD_IRQ_CMDERR_EN, 1);
+      vcmd_set_register_mirror_value(dev->reg_mirror, HWIF_VCMD_IRQ_TIMEOUT_EN, 1);
+      vcmd_set_register_mirror_value(dev->reg_mirror, HWIF_VCMD_IRQ_BUSERR_EN, 1);
+      vcmd_set_register_mirror_value(dev->reg_mirror, HWIF_VCMD_IRQ_ENDCMD_EN, 1);
+      //0x4c
+      vcmd_set_register_mirror_value(dev->reg_mirror, HWIF_VCMD_TIMEOUT_EN, 1);
+      vcmd_set_register_mirror_value(dev->reg_mirror, HWIF_VCMD_TIMEOUT_CYCLES, 0x1dcd6500);
+      vcmd_set_register_mirror_value(dev->reg_mirror, HWIF_VCMD_EXECUTING_CMD_ADDR, (u32)(cmdbuf_obj->cmdbuf_busAddress - base_ddr_addr));
+      if (sizeof(ptr_t) == 8)
+      {
+        vcmd_set_register_mirror_value(dev->reg_mirror, HWIF_VCMD_EXECUTING_CMD_ADDR_MSB, (u32)((u64)(cmdbuf_obj->cmdbuf_busAddress - base_ddr_addr) >> 32));
+      }
+      else
+      {
+        vcmd_set_register_mirror_value(dev->reg_mirror, HWIF_VCMD_EXECUTING_CMD_ADDR_MSB, 0);
+      }
+      vcmd_set_register_mirror_value(dev->reg_mirror, HWIF_VCMD_EXE_CMDBUF_LENGTH, (u32)((cmdbuf_obj->cmdbuf_size + 7) / 8));
+      vcmd_set_register_mirror_value(dev->reg_mirror, HWIF_VCMD_RDY_CMDBUF_COUNT, dev->sw_cmdbuf_rdy_num);
+      vcmd_set_register_mirror_value(dev->reg_mirror, HWIF_VCMD_MAX_BURST_LEN, 0x10);
+      if (dev->hw_version_id > HW_ID_1_0_C)
+      {
+        vcmd_write_register_value((const void *)dev->hwregs, dev->reg_mirror, HWIF_VCMD_CMDBUF_EXECUTING_ID, (u32)cmdbuf_obj->cmdbuf_id);
+      }
+      vcmd_write_reg((const void *)dev->hwregs, 0x40, dev->reg_mirror[0x40 / 4]);
+      vcmd_write_reg((const void *)dev->hwregs, 0x44, vcmd_read_reg((const void *)dev->hwregs, 0x44));
+      vcmd_write_reg((const void *)dev->hwregs, 0x48, dev->reg_mirror[0x48 / 4]);
+      vcmd_write_reg((const void *)dev->hwregs, 0x4c, dev->reg_mirror[0x4c / 4]);
+      vcmd_write_reg((const void *)dev->hwregs, 0x50, dev->reg_mirror[0x50 / 4]);
+      vcmd_write_reg((const void *)dev->hwregs, 0x54, dev->reg_mirror[0x54 / 4]);
+      vcmd_write_reg((const void *)dev->hwregs, 0x58, dev->reg_mirror[0x58 / 4]);
+      vcmd_write_reg((const void *)dev->hwregs, 0x5c, dev->reg_mirror[0x5c / 4]);
+      vcmd_write_reg((const void *)dev->hwregs, 0x60, dev->reg_mirror[0x60 / 4]);
+#if 1
+      vcmd_write_reg((const void *)dev->hwregs, 0x64, 0xffffffff); //not interrupt cpu
+#else
+      // Top 20 needs to mask abnormal interrupt
+      vcmd_write_reg((const void *)dev->hwregs, 0x64, 0xffff0000);
+#endif
+
+      dev->working_state = WORKING_STATE_WORKING;
+      //start
+      vcmd_set_register_mirror_value(dev->reg_mirror, HWIF_VCMD_MASTER_OUT_CLK_GATE_DISABLE, 0); //this bit should be set 1 only when need to reset dec400
+      vcmd_set_register_mirror_value(dev->reg_mirror, HWIF_VCMD_START_TRIGGER, 1);
+      vcmd_write_reg((const void *)dev->hwregs, 0x40, dev->reg_mirror[0x40 / 4]);
+    }
+  }
+}
+
+static void create_read_all_registers_cmdbuf(struct exchange_parameter *input_para)
+{
+  u32 register_range[] = {VCMD_ENCODER_REGISTER_SIZE,
+                          VCMD_IM_REGISTER_SIZE,
+                          VCMD_DECODER_REGISTER_SIZE,
+                          VCMD_JPEG_ENCODER_REGISTER_SIZE,
+                          VCMD_JPEG_DECODER_REGISTER_SIZE};
+  u32 counter_cmdbuf_size = 0;
+  u32 *set_base_addr = vcmd_buf_mem_pool.virtualAddress + input_para->cmdbuf_id * CMDBUF_MAX_SIZE / 4;
+  //u32 *status_base_virt_addr=vcmd_status_buf_mem_pool.virtualAddress + input_para->cmdbuf_id*CMDBUF_MAX_SIZE/4+(vcmd_manager[input_para->module_type][0]->vcmd_core_cfg.submodule_main_addr/2/4+0);
+  ptr_t status_base_phy_addr = vcmd_status_buf_mem_pool.busAddress + input_para->cmdbuf_id * CMDBUF_MAX_SIZE + (vcmd_manager[input_para->module_type][0]->vcmd_core_cfg.submodule_main_addr / 2 + 0);
+  u32 offset_inc = 0;
+  u32 offset_inc_dec400 = 0;
+  if (vcmd_manager[input_para->module_type][0]->hw_version_id > HW_ID_1_0_C)
+  {
+    printk(KERN_INFO "vc8000_vcmd_driver:create cmdbuf data when hw_version_id = 0x%x\n", vcmd_manager[input_para->module_type][0]->hw_version_id);
+
+    //read vcmd executing cmdbuf id registers to ddr for balancing core load.
+    *(set_base_addr + 0) = (OPCODE_RREG) | (1 << 16) | (EXECUTING_CMDBUF_ID_ADDR * 4);
+    counter_cmdbuf_size += 4;
+    *(set_base_addr + 1) = (u32)0; //will be changed in link stage
+    counter_cmdbuf_size += 4;
+    *(set_base_addr + 2) = (u32)0; //will be changed in link stage
+    counter_cmdbuf_size += 4;
+    //alignment
+    *(set_base_addr + 3) = 0;
+    counter_cmdbuf_size += 4;
+
+    //read main IP all registers
+    *(set_base_addr + 4) = (OPCODE_RREG) | ((register_range[input_para->module_type] / 4) << 16) | (vcmd_manager[input_para->module_type][0]->vcmd_core_cfg.submodule_main_addr + 0);
+    counter_cmdbuf_size += 4;
+    *(set_base_addr + 5) = (u32)(status_base_phy_addr - base_ddr_addr);
+    counter_cmdbuf_size += 4;
+    if (sizeof(ptr_t) == 8)
+    {
+      *(set_base_addr + 6) = (u32)((u64)(status_base_phy_addr - base_ddr_addr) >> 32);
+    }
+    else
+    {
+      *(set_base_addr + 6) = 0;
+    }
+    counter_cmdbuf_size += 4;
+    //alignment
+    *(set_base_addr + 7) = 0;
+    counter_cmdbuf_size += 4;
+
+    if (vcmd_manager[input_para->module_type][0]->vcmd_core_cfg.submodule_L2Cache_addr != 0xffff)
+    {
+      //read L2 cache register
+      offset_inc = 4;
+      status_base_phy_addr = vcmd_status_buf_mem_pool.busAddress + input_para->cmdbuf_id * CMDBUF_MAX_SIZE + (vcmd_manager[input_para->module_type][0]->vcmd_core_cfg.submodule_L2Cache_addr / 2 + 0);
+      //read L2cache IP first register
+      *(set_base_addr + 8) = (OPCODE_RREG) | (1 << 16) | (vcmd_manager[input_para->module_type][0]->vcmd_core_cfg.submodule_L2Cache_addr + 0);
+      counter_cmdbuf_size += 4;
+      *(set_base_addr + 9) = (u32)(status_base_phy_addr - base_ddr_addr);
+      counter_cmdbuf_size += 4;
+      if (sizeof(ptr_t) == 8)
+      {
+        *(set_base_addr + 10) = (u32)((u64)(status_base_phy_addr - base_ddr_addr) >> 32);
+      }
+      else
+      {
+        *(set_base_addr + 10) = 0;
+      }
+      counter_cmdbuf_size += 4;
+      //alignment
+      *(set_base_addr + 11) = 0;
+      counter_cmdbuf_size += 4;
+    }
+#if 0
+    if (vcmd_manager[input_para->module_type][0]->vcmd_core_cfg.submodule_dec400_addr != 0xffff)
+    {
+      //read dec400 register
+      offset_inc_dec400 = 4;
+      status_base_phy_addr = vcmd_status_buf_mem_pool.busAddress + input_para->cmdbuf_id * CMDBUF_MAX_SIZE + (vcmd_manager[input_para->module_type][0]->vcmd_core_cfg.submodule_dec400_addr / 2 + 0);
+      //read L2cache IP first register
+      *(set_base_addr + 8 + offset_inc) = (OPCODE_RREG) | (0x2b << 16) | (vcmd_manager[input_para->module_type][0]->vcmd_core_cfg.submodule_dec400_addr + 0);
+      counter_cmdbuf_size += 4;
+      *(set_base_addr + 9 + offset_inc) = (u32)(status_base_phy_addr - base_ddr_addr);
+      counter_cmdbuf_size += 4;
+      if (sizeof(ptr_t) == 8)
+      {
+        *(set_base_addr + 10 + offset_inc) = (u32)((u64)(status_base_phy_addr - base_ddr_addr) >> 32);
+      }
+      else
+      {
+        *(set_base_addr + 10 + offset_inc) = 0;
+      }
+      counter_cmdbuf_size += 4;
+      //alignment
+      *(set_base_addr + 11 + offset_inc) = 0;
+      counter_cmdbuf_size += 4;
+    }
+#endif
+#if 0
+      //INT code, interrupt immediately
+      *(set_base_addr+4) = (OPCODE_INT) |0 |input_para->cmdbuf_id;
+      counter_cmdbuf_size += 4;
+      //alignment
+      *(set_base_addr+5) = 0;
+      counter_cmdbuf_size += 4;
+#endif
+    //read vcmd registers to ddr
+    *(set_base_addr + 8 + offset_inc + offset_inc_dec400) = (OPCODE_RREG) | (27 << 16) | (0);
+    counter_cmdbuf_size += 4;
+    *(set_base_addr + 9 + offset_inc + offset_inc_dec400) = (u32)0; //will be changed in link stage
+    counter_cmdbuf_size += 4;
+    *(set_base_addr + 10 + offset_inc + offset_inc_dec400) = (u32)0; //will be changed in link stage
+    counter_cmdbuf_size += 4;
+    //alignment
+    *(set_base_addr + 11 + offset_inc + offset_inc_dec400) = 0;
+    counter_cmdbuf_size += 4;
+    //JMP RDY = 0
+    *(set_base_addr + 12 + offset_inc + offset_inc_dec400) = (OPCODE_JMP_RDY0) | 0 | JMP_IE_1 | 0;
+    counter_cmdbuf_size += 4;
+    *(set_base_addr + 13 + offset_inc + offset_inc_dec400) = 0;
+    counter_cmdbuf_size += 4;
+    *(set_base_addr + 14 + offset_inc + offset_inc_dec400) = 0;
+    counter_cmdbuf_size += 4;
+    *(set_base_addr + 15 + offset_inc + offset_inc_dec400) = input_para->cmdbuf_id;
+    //don't add the last alignment DWORD in order to  identify END command or JMP command.
+    //counter_cmdbuf_size += 4;
+    input_para->cmdbuf_size = (16 + offset_inc + offset_inc_dec400) * 4;
+  }
+  else
+  {
+    printk(KERN_INFO "vc8000_vcmd_driver:create cmdbuf data when hw_version_id = 0x%x\n", vcmd_manager[input_para->module_type][0]->hw_version_id);
+    //read all registers
+    *(set_base_addr + 0) = (OPCODE_RREG) | ((register_range[input_para->module_type] / 4) << 16) | (vcmd_manager[input_para->module_type][0]->vcmd_core_cfg.submodule_main_addr + 0);
+    counter_cmdbuf_size += 4;
+    *(set_base_addr + 1) = (u32)(status_base_phy_addr - base_ddr_addr);
+    counter_cmdbuf_size += 4;
+    if (sizeof(ptr_t) == 8)
+    {
+      *(set_base_addr + 2) = (u32)((u64)(status_base_phy_addr - base_ddr_addr) >> 32);
+    }
+    else
+    {
+      *(set_base_addr + 2) = 0;
+    }
+    counter_cmdbuf_size += 4;
+    //alignment
+    *(set_base_addr + 3) = 0;
+    counter_cmdbuf_size += 4;
+#if 0
+      //INT code, interrupt immediately
+      *(set_base_addr+4) = (OPCODE_INT) |0 |input_para->cmdbuf_id;
+      counter_cmdbuf_size += 4;
+      //alignment
+      *(set_base_addr+5) = 0;
+      counter_cmdbuf_size += 4;
+#endif
+    //JMP RDY = 0
+    *(set_base_addr + 4) = (OPCODE_JMP_RDY0) | 0 | JMP_IE_1 | 0;
+    counter_cmdbuf_size += 4;
+    *(set_base_addr + 5) = 0;
+    counter_cmdbuf_size += 4;
+    *(set_base_addr + 6) = 0;
+    counter_cmdbuf_size += 4;
+    *(set_base_addr + 7) = input_para->cmdbuf_id;
+    //don't add the last alignment DWORD in order to  identify END command or JMP command.
+    //counter_cmdbuf_size += 4;
+    input_para->cmdbuf_size = 8 * 4;
+  }
+}
+volatile int tmpTimer=100000;
+static void read_main_module_all_registers(u32 main_module_type)
+{
+  int ret;
+  struct exchange_parameter input_para;
+  u32 irq_status_ret = 0;
+  u32 *status_base_virt_addr;
+
+  input_para.executing_time = 0;
+  input_para.priority = CMDBUF_PRIORITY_NORMAL;
+  input_para.module_type = main_module_type;
+  input_para.cmdbuf_size = 0;
+  //ret = reserve_cmdbuf(NULL,&input_para);
+  ret = reserve_cmdbuf(0, &input_para);
+  vcmd_manager[main_module_type][0]->status_cmdbuf_id = input_para.cmdbuf_id;
+  create_read_all_registers_cmdbuf(&input_para);
+  //link_and_run_cmdbuf(NULL,&input_para);
+  link_and_run_cmdbuf(0, &input_para);
+#if 0
+  msleep(1000);
+#else
+  while(tmpTimer--);
+#endif
+  hantrovcmd_isr(/*input_para.core_id,*/ &hantrovcmd_data[input_para.core_id]);
+  //wait_cmdbuf_ready(NULL,input_para.cmdbuf_id,&irq_status_ret);
+  wait_cmdbuf_ready(0, input_para.cmdbuf_id, &irq_status_ret);
+  status_base_virt_addr = vcmd_status_buf_mem_pool.virtualAddress + input_para.cmdbuf_id * CMDBUF_MAX_SIZE / 4 + (vcmd_manager[input_para.module_type][0]->vcmd_core_cfg.submodule_main_addr / 2 / 4 + 0);
+  printf(KERN_INFO "vc8000_vcmd_driver: main module register 0:0x%x\n", *status_base_virt_addr);
+  printf(KERN_INFO "vc8000_vcmd_driver: main module register 50:0x%08x\n", *(status_base_virt_addr + 50));
+  printf(KERN_INFO "vc8000_vcmd_driver: main module register 54:0x%08x\n", *(status_base_virt_addr + 54));
+  printf(KERN_INFO "vc8000_vcmd_driver: main module register 56:0x%08x\n", *(status_base_virt_addr + 56));
+  printf(KERN_INFO "vc8000_vcmd_driver: main module register 309:0x%08x\n", *(status_base_virt_addr + 309));
+  //don't release cmdbuf because it can be used repeatedly
+  //release_cmdbuf(NULL, input_para.cmdbuf_id);
+  //release_cmdbuf(0,input_para.cmdbuf_id);
+}
+
+int __init hantrovcmd_init(void)
+{
+  int i = 0, k = 0;
+  int result = 0, irq_enabled = 0;
+
+  total_vcmd_core_num = sizeof(vcmd_core_array) / sizeof(struct vcmd_config);
+  result = vcmd_pcie_init();
+  if (result)
+    goto err1;
+
+  for (i = 0; i < total_vcmd_core_num; i++)
+  {
+    printk(KERN_INFO "vcmd: module init - vcmdcore[%d] addr =0x%llx\n", i,
+           (long long unsigned int)vcmd_core_array[i].vcmd_base_addr);
+  }
+  hantrovcmd_data = (struct hantrovcmd_dev *)vmalloc(sizeof(struct hantrovcmd_dev) * total_vcmd_core_num);
+  if (hantrovcmd_data == NULL)
+    goto err1;
+  memset(hantrovcmd_data, 0, sizeof(struct hantrovcmd_dev) * total_vcmd_core_num);
+  for (k = 0; k < MAX_VCMD_TYPE; k++)
+  {
+    vcmd_type_core_num[k] = 0;
+    vcmd_position[k] = 0;
+    for (i = 0; i < MAX_VCMD_NUMBER; i++)
+    {
+      vcmd_manager[k][i] = NULL;
+    }
+  }
+#if PROCESS_MANAGER
+  init_bi_list(&global_process_manager);
+#endif
+  for (i = 0; i < total_vcmd_core_num; i++)
+  {
+    hantrovcmd_data[i].vcmd_core_cfg = vcmd_core_array[i];
+    hantrovcmd_data[i].hwregs = NULL;
+    hantrovcmd_data[i].core_id = i;
+    hantrovcmd_data[i].working_state = WORKING_STATE_IDLE;
+    hantrovcmd_data[i].sw_cmdbuf_rdy_num = 0;
+    hantrovcmd_data[i].spinlock = &owner_lock_vcmd[i];
+    spin_lock_init(&owner_lock_vcmd[i]);
+#if 1
+//    hantrovcmd_data[i].wait_queue = &wait_queue_vcmd[i];
+//wait_queue_vcmd[i] = xSemaphoreCreateCounting(0x7FFU, 0);
+//    sem_init(&wait_queue_vcmd[i], 0, 0);
+//    hantrovcmd_data[i].wait_abort_queue=&abort_queue_vcmd[i];
+//abort_queue_vcmd[i] = xSemaphoreCreateCounting(0x7FFU, 0);
+//    sem_init(&abort_queue_vcmd[i], 0, 0);
+#else
+    hantrovcmd_data[i].wait_queue = &wait_queue_vcmd[i];
+    init_waitqueue_head(&wait_queue_vcmd[i]);
+    hantrovcmd_data[i].wait_abort_queue = &abort_queue_vcmd[i];
+    init_waitqueue_head(&abort_queue_vcmd[i]);
+#endif
+    init_bi_list(&hantrovcmd_data[i].list_manager);
+    hantrovcmd_data[i].duration_without_int = 0;
+    vcmd_manager[vcmd_core_array[i].sub_module_type][vcmd_type_core_num[vcmd_core_array[i].sub_module_type]] = &hantrovcmd_data[i];
+    vcmd_type_core_num[vcmd_core_array[i].sub_module_type]++;
+    hantrovcmd_data[i].vcmd_reg_mem_busAddress = vcmd_registers_mem_pool.busAddress + i * VCMD_REGISTER_SIZE - base_ddr_addr;
+    hantrovcmd_data[i].vcmd_reg_mem_virtualAddress = vcmd_registers_mem_pool.virtualAddress + i * VCMD_REGISTER_SIZE / 4;
+    hantrovcmd_data[i].vcmd_reg_mem_size = VCMD_REGISTER_SIZE;
+    memset(hantrovcmd_data[i].vcmd_reg_mem_virtualAddress, 0, VCMD_REGISTER_SIZE);
+  }
+  //init_waitqueue_head(&mc_wait_queue);
+  //sema_init(&mc_wait_queue, 0);
+  queue_vcmd_init(&mc_wait_queue);
+  for (i = 0; i < TOTAL_DISCRETE_CMDBUF_NUM; i++)
+  {
+    queue_vcmd_init(&wait_queue_vcmd[i]);
+    queue_vcmd_init(&abort_queue_vcmd[i]);
+  }
+
+  result = register_chrdev(hantrovcmd_major, "vc8000_vcmd_driver", &hantrovcmd_fops);
+  if (result < 0)
+  {
+    printk(KERN_INFO "vc8000_vcmd_driver: unable to get major <%d>\n",
+           hantrovcmd_major);
+    goto err1;
+  }
+  else if (result != 0) /* this is for dynamic major */
+  {
+    hantrovcmd_major = result;
+  }
+  result = vcmd_reserve_IO();
+  if (result < 0)
+  {
+    goto err;
+  }
+  vcmd_reset_asic(hantrovcmd_data);
+
+  /* get the IRQ line */
+  for (i = 0; i < total_vcmd_core_num; i++)
+  {
+    if (hantrovcmd_data[i].hwregs == NULL)
+      continue;
+    if (hantrovcmd_data[i].vcmd_core_cfg.vcmd_irq != -1)
+    {
+      //cpu interrrupt enable
+      IntEnableIRQ(hantrovcmd_data[i].vcmd_core_cfg.vcmd_irq);
+      irq_enabled = 1;
+    }
+    else
+    {
+      printk(KERN_INFO "vc8000_vcmd_driver: IRQ not in use!\n");
+    }
+  }
+  if (irq_enabled == 1)
+  {
+    result = request_irq(CPU_INT_IRQ, hantrovcmd_isr,
+                         IRQF_SHARED,
+                         "vc8000_vcmd_driver", (void *)&hantrovcmd_data[i]);
+
+    if (result == -EINVAL)
+    {
+      printk(KERN_ERR "vc8000_vcmd_driver: Bad vcmd_irq number or handler, core_id=%d\n", i);
+      vcmd_release_IO();
+      goto err;
+    }
+    else if (result == -EBUSY)
+    {
+      printk(KERN_ERR "vc8000_vcmd_driver: IRQ <%d> busy, change your config, core_id=%d\n",
+             hantrovcmd_data[i].vcmd_core_cfg.vcmd_irq, i);
+      vcmd_release_IO();
+      goto err;
+    }
+  }
+  //cmdbuf pool allocation
+  //init_vcmd_non_cachable_memory_allocate();
+  //for cmdbuf management
+  cmdbuf_used_pos = 0;
+  for (k = 0; k < TOTAL_DISCRETE_CMDBUF_NUM; k++)
+  {
+    cmdbuf_used[k] = 0;
+    global_cmdbuf_node[k] = NULL;
+  }
+  //cmdbuf_used[0] not be used, because int vector must non-zero
+  cmdbuf_used_residual = TOTAL_DISCRETE_CMDBUF_NUM;
+  cmdbuf_used_pos = 1;
+  cmdbuf_used[0] = 1;
+  cmdbuf_used_residual -= 1;
+
+  printk(KERN_INFO "vc8000_vcmd_driver: module inserted. Major <%d>\n", hantrovcmd_major);
+#if PROCESS_MANAGER
+  create_kernel_process_manager();
+#endif
+  for (i = 0; i < MAX_VCMD_TYPE; i++)
+  {
+    if (vcmd_type_core_num[i] == 0)
+      continue;
+#if 1
+    vcmd_reserve_cmdbuf_sem[i] = PTHREAD_MUTEX_INITIALIZER;
+#else
+    sema_init(&vcmd_reserve_cmdbuf_sem[i], 1);
+#endif
+  }
+  sema_init(&vcmd_cmdbuf_memory_wait, TOTAL_DISCRETE_CMDBUF_NUM - 1);
+
+#ifdef IRQ_SIMULATION
+  for (i = 0; i < 10000; i++)
+  {
+    timer_reserve[i].timer = NULL;
+  }
+#endif
+  /*read all registers for each type of module for analyzing configuration in cwl*/
+  vcmd_init_flag = 1;
+  for (i = 0; i < MAX_VCMD_TYPE; i++)
+  {
+    if (vcmd_type_core_num[i] == 0)
+      continue;
+    read_main_module_all_registers(i);
+  }
+  vcmd_init_flag = 0;
+
+  printf("vcmd init successful...\n");
+  return 0;
+err:
+  unregister_chrdev(hantrovcmd_major, "vc8000_vcmd_driver");
+err1:
+  if (hantrovcmd_data != NULL)
+    vfree(hantrovcmd_data);
+  printk(KERN_INFO "vc8000_vcmd_driver: module not inserted\n");
+  return result;
+}
+
+void __exit hantrovcmd_cleanup(void)
+{
+  int i = 0;
+  u32 result;
+
+  for (i = 0; i < total_vcmd_core_num; i++)
+  {
+    if (hantrovcmd_data[i].hwregs == NULL)
+      continue;
+    //disable interrupt at first
+    vcmd_write_reg((const void *)hantrovcmd_data[i].hwregs, VCMD_REGISTER_INT_CTL_OFFSET, 0x0000);
+    //disable HW
+    vcmd_write_reg((const void *)hantrovcmd_data[i].hwregs, VCMD_REGISTER_CONTROL_OFFSET, 0x0000);
+    //read status register
+    result = vcmd_read_reg((const void *)hantrovcmd_data[i].hwregs, VCMD_REGISTER_INT_STATUS_OFFSET);
+    //clean status register
+    vcmd_write_reg((const void *)hantrovcmd_data[i].hwregs, VCMD_REGISTER_INT_STATUS_OFFSET, result);
+
+    /* free the vcmd IRQ */
+    if (hantrovcmd_data[i].vcmd_core_cfg.vcmd_irq != -1)
+    {
+      free_irq(hantrovcmd_data[i].vcmd_core_cfg.vcmd_irq, (void *)&hantrovcmd_data[i]);
+    }
+    release_cmdbuf_node_cleanup(&hantrovcmd_data[i].list_manager);
+  }
+#if PROCESS_MANAGER
+  release_process_node_cleanup(&global_process_manager);
+#endif
+  vcmd_release_IO();
+  vfree(hantrovcmd_data);
+
+  //release_vcmd_non_cachable_memory();
+  iounmap((void *)vcmd_buf_mem_pool.virtualAddress);
+  release_mem_region(vcmd_buf_mem_pool.busAddress, vcmd_buf_mem_pool.size);
+  iounmap((void *)vcmd_status_buf_mem_pool.virtualAddress);
+  release_mem_region(vcmd_status_buf_mem_pool.busAddress, vcmd_status_buf_mem_pool.size);
+  iounmap((void *)vcmd_registers_mem_pool.virtualAddress);
+  release_mem_region(vcmd_registers_mem_pool.busAddress, vcmd_registers_mem_pool.size);
+  unregister_chrdev(hantrovcmd_major, "vc8000_vcmd_driver");
+
+  printk(KERN_INFO "vc8000_vcmd_driver: module removed\n");
+  return;
+}
+
+static int vcmd_reserve_IO(void)
+{
+  u32 hwid;
+  int i;
+  u32 found_hw = 0;
+
+  for (i = 0; i < total_vcmd_core_num; i++)
+  {
+    hantrovcmd_data[i].hwregs = NULL;
+
+    if (!request_mem_region(hantrovcmd_data[i].vcmd_core_cfg.vcmd_base_addr, hantrovcmd_data[i].vcmd_core_cfg.vcmd_iosize, "vc8000_vcmd_driver"))
+    {
+      printk(KERN_INFO "hantrovcmd: failed to reserve HW regs\n");
+      continue;
+    }
+
+    hantrovcmd_data[i].hwregs =
+        (volatile u8 *)ioremap_nocache(hantrovcmd_data[i].vcmd_core_cfg.vcmd_base_addr,
+                                       hantrovcmd_data[i].vcmd_core_cfg.vcmd_iosize);
+
+    if (hantrovcmd_data[i].hwregs == NULL)
+    {
+      printk(KERN_INFO "hantrovcmd: failed to ioremap HW regs\n");
+      release_mem_region(hantrovcmd_data[i].vcmd_core_cfg.vcmd_base_addr, hantrovcmd_data[i].vcmd_core_cfg.vcmd_iosize);
+      continue;
+    }
+
+    /*read hwid and check validness and store it*/
+    hwid = (u32)ioread32((void *)hantrovcmd_data[i].hwregs);
+    printk(KERN_INFO "hwid=0x%08x\n", hwid);
+    hantrovcmd_data[i].hw_version_id = hwid;
+
+    /* check for vcmd HW ID */
+    if (((hwid >> 16) & 0xFFFF) != VCMD_HW_ID)
+    {
+      printk(KERN_INFO "hantrovcmd: HW not found at 0x%llx\n",
+             (long long unsigned int)hantrovcmd_data[i].vcmd_core_cfg.vcmd_base_addr);
+      iounmap((void *)hantrovcmd_data[i].hwregs);
+      release_mem_region(hantrovcmd_data[i].vcmd_core_cfg.vcmd_base_addr, hantrovcmd_data[i].vcmd_core_cfg.vcmd_iosize);
+      hantrovcmd_data[i].hwregs = NULL;
+      continue;
+    }
+
+    found_hw = 1;
+
+    printk(KERN_INFO
+           "hantrovcmd: HW at base <0x%llx> with ID <0x%08x>\n",
+           (long long unsigned int)hantrovcmd_data[i].vcmd_core_cfg.vcmd_base_addr, hwid);
+  }
+
+  if (found_hw == 0)
+  {
+    printk(KERN_ERR "hantrovcmd: NO ANY HW found!!\n");
+    return -1;
+  }
+
+  return 0;
+}
+
+static void vcmd_release_IO(void)
+{
+  u32 i;
+  for (i = 0; i < total_vcmd_core_num; i++)
+  {
+    if (hantrovcmd_data[i].hwregs)
+    {
+      iounmap((void *)hantrovcmd_data[i].hwregs);
+      release_mem_region(hantrovcmd_data[i].vcmd_core_cfg.vcmd_base_addr, hantrovcmd_data[i].vcmd_core_cfg.vcmd_iosize);
+      hantrovcmd_data[i].hwregs = NULL;
+    }
+  }
+}
+
+static irqreturn_t ProcessingInterrupt(void *dev_id, unsigned int * handled)
+{
+  struct hantrovcmd_dev *dev = (struct hantrovcmd_dev *) dev_id;
+  unsigned long flags = 0;
+  bi_list_node *new_cmdbuf_node = NULL;
+  bi_list_node *base_cmdbuf_node = NULL;
+  struct cmdbuf_obj *cmdbuf_obj = NULL;
+  ptr_t /*size_t*/ exe_cmdbuf_busAddress = 0;
+  u32 irq_status = 0;
+  u32 cmdbuf_processed_num = 0;
+  u32 cmdbuf_id = 0;
+
+  /*If core is not reserved by any user, but irq is received, just clean it*/
+  isr_spin_lock_irqsave(dev->spinlock, flags);
+  if (dev->list_manager.head == NULL)
+  {
+	PDEBUG("In ISR, received IRQ but core has nothing to do.\n");
+	irq_status = vcmd_read_reg((const void *)dev->hwregs, VCMD_REGISTER_INT_STATUS_OFFSET);
+	vcmd_write_reg((const void *)dev->hwregs, VCMD_REGISTER_INT_STATUS_OFFSET, irq_status);
+	isr_spin_unlock_irqrestore(dev->spinlock, flags);
+	return IRQ_HANDLED;
+  }
+  irq_status = vcmd_read_reg((const void *)dev->hwregs, VCMD_REGISTER_INT_STATUS_OFFSET);
+#ifdef VCMD_DEBUG_INTERNAL
+  {
+	u32 i, fordebug;
+	for (i = 0; i < ASIC_VCMD_SWREG_AMOUNT; i++)
+	{
+	  fordebug = vcmd_read_reg((const void *)dev->hwregs, i * 4);
+	  printk(KERN_INFO "vcmd register %d:0x%x\n", i, fordebug);
+	}
+  }
+#endif
+
+  if (!irq_status)
+  {
+	//printk(KERN_INFO"hantrovcmd_isr error,irq_status :0x%x",irq_status);
+	isr_spin_unlock_irqrestore(dev->spinlock, flags);
+	return IRQ_HANDLED;
+  }
+
+  PDEBUG("In ISR, received IRQ, irq_status of %d is:%x\n", dev->core_id, irq_status);
+  vcmd_write_reg((const void *)dev->hwregs, VCMD_REGISTER_INT_STATUS_OFFSET, irq_status);
+  dev->reg_mirror[VCMD_REGISTER_INT_STATUS_OFFSET / 4] = irq_status;
+
+  if ((dev->hw_version_id > HW_ID_1_0_C) && (irq_status & 0x3f))
+  {
+	//if error,read from register directly.
+	cmdbuf_id = vcmd_get_register_value((const void *)dev->hwregs, dev->reg_mirror, HWIF_VCMD_CMDBUF_EXECUTING_ID);
+	if (cmdbuf_id >= TOTAL_DISCRETE_CMDBUF_NUM)
+	{
+	  printk(KERN_ERR "hantrovcmd_isr error cmdbuf_id greater than the ceiling !!\n");
+	  isr_spin_unlock_irqrestore(dev->spinlock, flags);
+	  return IRQ_HANDLED;
+	}
+  }
+  else if ((dev->hw_version_id > HW_ID_1_0_C))
+  {
+	//read cmdbuf id from ddr
+#ifdef VCMD_DEBUG_INTERNAL
+	{
+	  u32 i, fordebug;
+	  printk(KERN_INFO "ddr vcmd register phy_addr=0x%x\n", dev->vcmd_reg_mem_busAddress);
+	  printk(KERN_INFO "ddr vcmd register virt_addr=0x%x\n", dev->vcmd_reg_mem_virtualAddress);
+	  for (i = 0; i < ASIC_VCMD_SWREG_AMOUNT; i++)
+	  {
+		fordebug = *(dev->vcmd_reg_mem_virtualAddress + i);
+		printk(KERN_INFO "ddr vcmd register %d:0x%x\n", i, fordebug);
+	  }
+	}
+#endif
+
+	cmdbuf_id = *(dev->vcmd_reg_mem_virtualAddress + EXECUTING_CMDBUF_ID_ADDR);
+	PDEBUG("In ISR, the current cmdbuf_id is [%d]\n", cmdbuf_id);
+	if (cmdbuf_id >= TOTAL_DISCRETE_CMDBUF_NUM)
+	{
+	  printk(KERN_ERR "hantrovcmd_isr error cmdbuf_id greater than the ceiling !!\n");
+	  isr_spin_unlock_irqrestore(dev->spinlock, flags);
+	  return IRQ_HANDLED;
+	}
+  }
+
+  if (vcmd_get_register_mirror_value(dev->reg_mirror, HWIF_VCMD_IRQ_RESET))
+  {
+	//reset error,all cmdbuf that is not  done will be run again.
+	new_cmdbuf_node = dev->list_manager.head;
+	dev->working_state = WORKING_STATE_IDLE;
+	//find the first run_done=0
+	while (1)
+	{
+	  if (new_cmdbuf_node == NULL)
+		break;
+	  cmdbuf_obj = (struct cmdbuf_obj *)new_cmdbuf_node->data;
+	  if (cmdbuf_obj->cmdbuf_run_done == 0)
+		break;
+	  new_cmdbuf_node = new_cmdbuf_node->next;
+	}
+	base_cmdbuf_node = new_cmdbuf_node;
+	vcmd_delink_cmdbuf(dev, base_cmdbuf_node);
+	vcmd_link_cmdbuf(dev, base_cmdbuf_node);
+	if (dev->sw_cmdbuf_rdy_num != 0)
+	{
+	  //restart new command
+	  vcmd_start(dev, base_cmdbuf_node);
+	}
+	(*handled)++;
+	isr_spin_unlock_irqrestore(dev->spinlock, flags);
+	return IRQ_HANDLED;
+  }
+  if (vcmd_get_register_mirror_value(dev->reg_mirror, HWIF_VCMD_IRQ_ABORT))
+  {
+	//abort error,don't need to reset
+	new_cmdbuf_node = dev->list_manager.head;
+	dev->working_state = WORKING_STATE_IDLE;
+	if (dev->hw_version_id > HW_ID_1_0_C)
+	{
+	  new_cmdbuf_node = global_cmdbuf_node[cmdbuf_id];
+	  if (new_cmdbuf_node == NULL)
+	  {
+		printk(KERN_ERR "hantrovcmd_isr error cmdbuf_id !!\n");
+		isr_spin_unlock_irqrestore(dev->spinlock, flags);
+		return IRQ_HANDLED;
+	  }
+	}
+	else
+	{
+	  exe_cmdbuf_busAddress = VCMDGetAddrRegisterValue((const void *)dev->hwregs, dev->reg_mirror, HWIF_VCMD_EXECUTING_CMD_ADDR);
+	  //find the cmderror cmdbuf
+	  while (1)
+	  {
+		if (new_cmdbuf_node == NULL)
+		{
+		  isr_spin_unlock_irqrestore(dev->spinlock, flags);
+		  return IRQ_HANDLED;
+		}
+		cmdbuf_obj = (struct cmdbuf_obj *)new_cmdbuf_node->data;
+		if ((((cmdbuf_obj->cmdbuf_busAddress - base_ddr_addr) <= exe_cmdbuf_busAddress) && (((cmdbuf_obj->cmdbuf_busAddress - base_ddr_addr + cmdbuf_obj->cmdbuf_size) > exe_cmdbuf_busAddress))) && (cmdbuf_obj->cmdbuf_run_done == 0))
+		  break;
+		new_cmdbuf_node = new_cmdbuf_node->next;
+	  }
+	}
+	base_cmdbuf_node = new_cmdbuf_node;
+	// this cmdbuf and cmdbufs prior to itself, run_done = 1
+	while (1)
+	{
+	  if (new_cmdbuf_node == NULL)
+		break;
+	  cmdbuf_obj = (struct cmdbuf_obj *)new_cmdbuf_node->data;
+	  if (cmdbuf_obj->cmdbuf_run_done == 0)
+	  {
+		cmdbuf_obj->cmdbuf_run_done = 1;
+		cmdbuf_obj->executing_status = CMDBUF_EXE_STATUS_OK;
+		queue_vcmd_wakeup(&wait_queue_vcmd[cmdbuf_obj->cmdbuf_id]);
+		cmdbuf_processed_num++;
+	  }
+	  else
+		break;
+	  new_cmdbuf_node = new_cmdbuf_node->previous;
+	}
+	base_cmdbuf_node = base_cmdbuf_node->next;
+	vcmd_delink_cmdbuf(dev, base_cmdbuf_node);
+
+	isr_spin_unlock_irqrestore(dev->spinlock, flags);
+#if 1
+    //queue_vcmd_wakeup(&abort_queue_vcmd[cmdbuf_id]);
+    queue_vcmd_wakeup(&mc_wait_queue);
+#else
+    if (cmdbuf_processed_num)
+      wake_up_interruptible_all(dev->wait_queue);
+    //to let high priority cmdbuf be inserted
+    wake_up_interruptible_all(dev->wait_abort_queue);
+    wake_up_interruptible_all(&mc_wait_queue);
+#endif
+
+    (*handled)++;
+    return IRQ_HANDLED;
+  }
+  if (vcmd_get_register_mirror_value(dev->reg_mirror, HWIF_VCMD_IRQ_BUSERR))
+  {
+	//bus error ,don't need to reset , where to record status?
+	new_cmdbuf_node = dev->list_manager.head;
+	dev->working_state = WORKING_STATE_IDLE;
+	if (dev->hw_version_id > HW_ID_1_0_C)
+	{
+	  new_cmdbuf_node = global_cmdbuf_node[cmdbuf_id];
+	  if (new_cmdbuf_node == NULL)
+	  {
+		printk(KERN_ERR "hantrovcmd_isr error cmdbuf_id !!\n");
+		isr_spin_unlock_irqrestore(dev->spinlock, flags);
+		return IRQ_HANDLED;
+	  }
+	}
+	else
+	{
+	  exe_cmdbuf_busAddress = VCMDGetAddrRegisterValue((const void *)dev->hwregs, dev->reg_mirror, HWIF_VCMD_EXECUTING_CMD_ADDR);
+	  //find the buserr cmdbuf
+	  while (1)
+	  {
+		if (new_cmdbuf_node == NULL)
+		{
+		  isr_spin_unlock_irqrestore(dev->spinlock, flags);
+		  return IRQ_HANDLED;
+		}
+		cmdbuf_obj = (struct cmdbuf_obj *)new_cmdbuf_node->data;
+		if ((((cmdbuf_obj->cmdbuf_busAddress - base_ddr_addr) <= exe_cmdbuf_busAddress) && (((cmdbuf_obj->cmdbuf_busAddress - base_ddr_addr + cmdbuf_obj->cmdbuf_size) > exe_cmdbuf_busAddress))) && (cmdbuf_obj->cmdbuf_run_done == 0))
+		  break;
+		new_cmdbuf_node = new_cmdbuf_node->next;
+	  }
+	}
+	base_cmdbuf_node = new_cmdbuf_node;
+	// this cmdbuf and cmdbufs prior to itself, run_done = 1
+	while (1)
+	{
+	  if (new_cmdbuf_node == NULL)
+		break;
+	  cmdbuf_obj = (struct cmdbuf_obj *)new_cmdbuf_node->data;
+	  if (cmdbuf_obj->cmdbuf_run_done == 0)
+	  {
+		cmdbuf_obj->cmdbuf_run_done = 1;
+		cmdbuf_obj->executing_status = CMDBUF_EXE_STATUS_OK;
+	   //queue_vcmd_wakeup(&wait_queue_vcmd[cmdbuf_obj->cmdbuf_id]);
+		cmdbuf_processed_num++;
+	  }
+	  else
+		break;
+	  new_cmdbuf_node = new_cmdbuf_node->previous;
+	}
+	new_cmdbuf_node = base_cmdbuf_node;
+	if (new_cmdbuf_node != NULL)
+	{
+	  cmdbuf_obj = (struct cmdbuf_obj *)new_cmdbuf_node->data;
+	  cmdbuf_obj->executing_status = CMDBUF_EXE_STATUS_BUSERR;
+	}
+	base_cmdbuf_node = base_cmdbuf_node->next;
+	vcmd_delink_cmdbuf(dev, base_cmdbuf_node);
+	vcmd_link_cmdbuf(dev, base_cmdbuf_node);
+	if (dev->sw_cmdbuf_rdy_num != 0)
+	{
+	  //restart new command
+	  vcmd_start(dev, base_cmdbuf_node);
+	}
+	isr_spin_unlock_irqrestore(dev->spinlock, flags);
+#if PROCESS_MANAGER
+	if (cmdbuf_processed_num)
+	  wake_up_interruptible_all(dev->wait_queue);
+#endif
+
+    (*handled)++;
+    //wake_up_interruptible_all(&mc_wait_queue);
+    queue_vcmd_wakeup(&mc_wait_queue);
+    return IRQ_HANDLED;
+  }
+  if (vcmd_get_register_mirror_value(dev->reg_mirror, HWIF_VCMD_IRQ_TIMEOUT))
+  {
+	//time out,need to reset
+	new_cmdbuf_node = dev->list_manager.head;
+	dev->working_state = WORKING_STATE_IDLE;
+	if (dev->hw_version_id > HW_ID_1_0_C)
+	{
+	  new_cmdbuf_node = global_cmdbuf_node[cmdbuf_id];
+	  if (new_cmdbuf_node == NULL)
+	  {
+		printk(KERN_ERR "hantrovcmd_isr error cmdbuf_id !!\n");
+		isr_spin_unlock_irqrestore(dev->spinlock, flags);
+		return IRQ_HANDLED;
+	  }
+	}
+	else
+	{
+	  exe_cmdbuf_busAddress = VCMDGetAddrRegisterValue((const void *)dev->hwregs, dev->reg_mirror, HWIF_VCMD_EXECUTING_CMD_ADDR);
+	  //find the timeout cmdbuf
+	  while (1)
+	  {
+		if (new_cmdbuf_node == NULL)
+		{
+		  isr_spin_unlock_irqrestore(dev->spinlock, flags);
+		  return IRQ_HANDLED;
+		}
+		cmdbuf_obj = (struct cmdbuf_obj *)new_cmdbuf_node->data;
+		if ((((cmdbuf_obj->cmdbuf_busAddress - base_ddr_addr) <= exe_cmdbuf_busAddress) && (((cmdbuf_obj->cmdbuf_busAddress - base_ddr_addr + cmdbuf_obj->cmdbuf_size) > exe_cmdbuf_busAddress))) && (cmdbuf_obj->cmdbuf_run_done == 0))
+		  break;
+		new_cmdbuf_node = new_cmdbuf_node->next;
+	  }
+	}
+	base_cmdbuf_node = new_cmdbuf_node;
+	new_cmdbuf_node = new_cmdbuf_node->previous;
+	// this cmdbuf and cmdbufs prior to itself, run_done = 1
+	while (1)
+	{
+	  if (new_cmdbuf_node == NULL)
+		break;
+	  cmdbuf_obj = (struct cmdbuf_obj *)new_cmdbuf_node->data;
+	  if (cmdbuf_obj->cmdbuf_run_done == 0)
+	  {
+		cmdbuf_obj->cmdbuf_run_done = 1;
+		cmdbuf_obj->executing_status = CMDBUF_EXE_STATUS_OK;
+		//queue_vcmd_wakeup(&wait_queue_vcmd[cmdbuf_obj->cmdbuf_id]);
+		cmdbuf_processed_num++;
+	  }
+	  else
+		break;
+	  new_cmdbuf_node = new_cmdbuf_node->previous;
+	}
+	vcmd_delink_cmdbuf(dev, base_cmdbuf_node);
+	vcmd_link_cmdbuf(dev, base_cmdbuf_node);
+	if (dev->sw_cmdbuf_rdy_num != 0)
+	{
+	  //reset
+	  vcmd_reset_current_asic(dev);
+	  //restart new command
+	  vcmd_start(dev, base_cmdbuf_node);
+	}
+	isr_spin_unlock_irqrestore(dev->spinlock, flags);
+#if PROCESS_MANAGER
+	if (cmdbuf_processed_num)
+	  wake_up_interruptible_all(dev->wait_queue);
+#endif
+
+    (*handled)++;
+    //wake_up_interruptible_all(&mc_wait_queue);
+    queue_vcmd_wakeup(&mc_wait_queue);
+    return IRQ_HANDLED;
+  }
+  if (vcmd_get_register_mirror_value(dev->reg_mirror, HWIF_VCMD_IRQ_CMDERR))
+  {
+	//command error,don't need to reset
+	new_cmdbuf_node = dev->list_manager.head;
+	dev->working_state = WORKING_STATE_IDLE;
+	if (dev->hw_version_id > HW_ID_1_0_C)
+	{
+	  new_cmdbuf_node = global_cmdbuf_node[cmdbuf_id];
+	  if (new_cmdbuf_node == NULL)
+	  {
+		printk(KERN_ERR "hantrovcmd_isr error cmdbuf_id !!\n");
+		isr_spin_unlock_irqrestore(dev->spinlock, flags);
+		return IRQ_HANDLED;
+	  }
+	}
+	else
+	{
+	  exe_cmdbuf_busAddress = VCMDGetAddrRegisterValue((const void *)dev->hwregs, dev->reg_mirror, HWIF_VCMD_EXECUTING_CMD_ADDR);
+	  //find the cmderror cmdbuf
+	  while (1)
+	  {
+		if (new_cmdbuf_node == NULL)
+		{
+		  isr_spin_unlock_irqrestore(dev->spinlock, flags);
+		  return IRQ_HANDLED;
+		}
+		cmdbuf_obj = (struct cmdbuf_obj *)new_cmdbuf_node->data;
+		if ((((cmdbuf_obj->cmdbuf_busAddress - base_ddr_addr) <= exe_cmdbuf_busAddress) && (((cmdbuf_obj->cmdbuf_busAddress - base_ddr_addr + cmdbuf_obj->cmdbuf_size) > exe_cmdbuf_busAddress))) && (cmdbuf_obj->cmdbuf_run_done == 0))
+		  break;
+		new_cmdbuf_node = new_cmdbuf_node->next;
+	  }
+	}
+	base_cmdbuf_node = new_cmdbuf_node;
+	// this cmdbuf and cmdbufs prior to itself, run_done = 1
+	while (1)
+	{
+	  if (new_cmdbuf_node == NULL)
+		break;
+	  cmdbuf_obj = (struct cmdbuf_obj *)new_cmdbuf_node->data;
+	  if (cmdbuf_obj->cmdbuf_run_done == 0)
+	  {
+		cmdbuf_obj->cmdbuf_run_done = 1;
+		cmdbuf_obj->executing_status = CMDBUF_EXE_STATUS_OK;
+		//queue_vcmd_wakeup(&wait_queue_vcmd[cmdbuf_obj->cmdbuf_id]);
+		cmdbuf_processed_num++;
+	  }
+	  else
+		break;
+	  new_cmdbuf_node = new_cmdbuf_node->previous;
+	}
+	new_cmdbuf_node = base_cmdbuf_node;
+	if (new_cmdbuf_node != NULL)
+	{
+	  cmdbuf_obj = (struct cmdbuf_obj *)new_cmdbuf_node->data;
+	  cmdbuf_obj->executing_status = CMDBUF_EXE_STATUS_CMDERR; //cmderr
+	}
+	base_cmdbuf_node = base_cmdbuf_node->next;
+	vcmd_delink_cmdbuf(dev, base_cmdbuf_node);
+	vcmd_link_cmdbuf(dev, base_cmdbuf_node);
+	if (dev->sw_cmdbuf_rdy_num != 0)
+	{
+	  //restart new command
+	  vcmd_start(dev, base_cmdbuf_node);
+	}
+	isr_spin_unlock_irqrestore(dev->spinlock, flags);
+#if PROCESS_MANAGER
+	if (cmdbuf_processed_num)
+	  wake_up_interruptible_all(dev->wait_queue);
+#endif
+
+    (*handled)++;
+    //wake_up_interruptible_all(&mc_wait_queue);
+    queue_vcmd_wakeup(&mc_wait_queue);
+    return IRQ_HANDLED;
+  }
+
+  if (vcmd_get_register_mirror_value(dev->reg_mirror, HWIF_VCMD_IRQ_ENDCMD))
+  {
+	//end command interrupt
+	new_cmdbuf_node = dev->list_manager.head;
+	dev->working_state = WORKING_STATE_IDLE;
+	if (dev->hw_version_id > HW_ID_1_0_C)
+	{
+	  new_cmdbuf_node = global_cmdbuf_node[cmdbuf_id];
+	  if (new_cmdbuf_node == NULL)
+	  {
+		printk(KERN_ERR "hantrovcmd_isr error cmdbuf_id !!\n");
+		isr_spin_unlock_irqrestore(dev->spinlock, flags);
+		return IRQ_HANDLED;
+	  }
+	}
+	else
+	{
+	  //find the end cmdbuf
+	  while (1)
+	  {
+		if (new_cmdbuf_node == NULL)
+		{
+		  isr_spin_unlock_irqrestore(dev->spinlock, flags);
+		  return IRQ_HANDLED;
+		}
+		cmdbuf_obj = (struct cmdbuf_obj *)new_cmdbuf_node->data;
+		if ((cmdbuf_obj->has_end_cmdbuf == 1) && (cmdbuf_obj->cmdbuf_run_done == 0))
+		  break;
+		new_cmdbuf_node = new_cmdbuf_node->next;
+	  }
+	}
+	base_cmdbuf_node = new_cmdbuf_node;
+	// this cmdbuf and cmdbufs prior to itself, run_done = 1
+	while (1)
+	{
+	  if (new_cmdbuf_node == NULL)
+		break;
+	  cmdbuf_obj = (struct cmdbuf_obj *)new_cmdbuf_node->data;
+	  if (cmdbuf_obj->cmdbuf_run_done == 0)
+	  {
+		cmdbuf_obj->cmdbuf_run_done = 1;
+		cmdbuf_obj->executing_status = CMDBUF_EXE_STATUS_OK;
+		//queue_vcmd_wakeup(&wait_queue_vcmd[cmdbuf_obj->cmdbuf_id]);
+		cmdbuf_processed_num++;
+	  }
+	  else
+		break;
+	  new_cmdbuf_node = new_cmdbuf_node->previous;
+	}
+	base_cmdbuf_node = base_cmdbuf_node->next;
+	vcmd_delink_cmdbuf(dev, base_cmdbuf_node);
+	vcmd_link_cmdbuf(dev, base_cmdbuf_node);
+	if (dev->sw_cmdbuf_rdy_num != 0)
+	{
+	  //restart new command
+	  vcmd_start(dev, base_cmdbuf_node);
+	}
+	isr_spin_unlock_irqrestore(dev->spinlock, flags);
+#if PROCESS_MANAGER
+	if (cmdbuf_processed_num)
+	  wake_up_interruptible_all(dev->wait_queue);
+#endif
+
+    (*handled)++;
+    //wake_up_interruptible_all(&mc_wait_queue);
+    queue_vcmd_wakeup(&mc_wait_queue);
+    return IRQ_HANDLED;
+  }
+  if (dev->hw_version_id <= HW_ID_1_0_C)
+	cmdbuf_id = vcmd_get_register_mirror_value(dev->reg_mirror, HWIF_VCMD_IRQ_INTCMD);
+  if (cmdbuf_id)
+  {
+	if (dev->hw_version_id <= HW_ID_1_0_C)
+	{
+	  if (cmdbuf_id >= TOTAL_DISCRETE_CMDBUF_NUM)
+	  {
+		printk(KERN_ERR "hantrovcmd_isr error cmdbuf_id greater than the ceiling !!\n");
+		isr_spin_unlock_irqrestore(dev->spinlock, flags);
+		return IRQ_HANDLED;
+	  }
+	}
+	new_cmdbuf_node = global_cmdbuf_node[cmdbuf_id];
+	if (new_cmdbuf_node == NULL)
+	{
+	  printk(KERN_ERR "hantrovcmd_isr error cmdbuf_id !!\n");
+	  isr_spin_unlock_irqrestore(dev->spinlock, flags);
+	  return IRQ_HANDLED;
+	}
+	// interrupt cmdbuf and cmdbufs prior to itself, run_done = 1
+	while (1)
+	{
+	  if (new_cmdbuf_node == NULL)
+		break;
+	  cmdbuf_obj = (struct cmdbuf_obj *)new_cmdbuf_node->data;
+	  if (cmdbuf_obj->cmdbuf_run_done == 0)
+	  {
+		cmdbuf_obj->cmdbuf_run_done = 1;
+		cmdbuf_obj->executing_status = CMDBUF_EXE_STATUS_OK;
+		//queue_vcmd_wakeup(&wait_queue_vcmd[cmdbuf_obj->cmdbuf_id]);
+		PDEBUG("In ISR, post wait_queue_vcmd[%d]\n", cmdbuf_obj->cmdbuf_id);
+		cmdbuf_processed_num++;
+	  }
+	  else
+		break;
+	  new_cmdbuf_node = new_cmdbuf_node->previous;
+	}
+	(*handled)++;
+  }
+
+  isr_spin_unlock_irqrestore(dev->spinlock, flags);
+#if PROCESS_MANAGER
+  if (cmdbuf_processed_num)
+	wake_up_interruptible_all(dev->wait_queue);
+#endif
+
+  return IRQ_HANDLED;
+}
+static irqreturn_t hantrovcmd_isr(void *dev_id)
+{
+  struct hantrovcmd_dev *dev = NULL;
+  unsigned int handled = 0;
+  u32 i = 0, irq = 0, intr_val = 0, core_id = 0;
+  if (vcmd_init_flag)
+  {
+    ProcessingInterrupt(dev_id, &handled);
+    for (i = 0; i < total_vcmd_core_num; i++)
+      IntClearIRQStatus(vcmd_core_array[i].vcmd_irq);
+  }
+  else
+  {
+    intr_val = (u32)ioread32((void *)SYS_REG_INT_STAT/*SYS_REG_INT_VAL*/);
+    PDEBUG("In ISR, the interrupt value is 0x%x\n", intr_val);
+    irq = 0;
+    while (intr_val)
+    {
+      if (intr_val & 1)
+      {
+        for (i = 0; i < total_vcmd_core_num; i++)
+        {
+          if (vcmd_core_array[i].vcmd_irq != irq)
+          {
+            continue;
+          }
+          else
+          { //found out the trigger source cor for interrupt
+            /* get dev & core_id */
+            core_id = i;
+            dev = &hantrovcmd_data[core_id];
+            IntClearIRQStatus(irq);
+
+            /* interrupt processing */
+            ProcessingInterrupt(dev, &handled);
+            break; // have found the trigger source core, exit the for(total_vcmd_core)
+          }
+        }
+      }
+      /* next irq */
+      intr_val >>= 1;
+      irq++;
+    }
+  }
+  if (!handled)
+  {
+    printf("IRQ received, but not hantro's!\n");
+  }
+  //wake_up_interruptible_all(&mc_wait_queue);
+  queue_vcmd_wakeup(&mc_wait_queue);
+#if 0
+  static int i_lxj = 0;
+  printf("post %d mc_wait_queue\n", ++i_lxj);
+#endif
+  return IRQ_HANDLED;
+}
+
+void vcmd_reset_asic(struct hantrovcmd_dev *dev)
+{
+  int i, n;
+  u32 result;
+  for (n = 0; n < total_vcmd_core_num; n++)
+  {
+    if (dev[n].hwregs != NULL)
+    {
+      //disable interrupt at first
+      vcmd_write_reg((const void *)dev[n].hwregs, VCMD_REGISTER_INT_CTL_OFFSET, 0x0000);
+      //reset all
+      vcmd_write_reg((const void *)dev[n].hwregs, VCMD_REGISTER_CONTROL_OFFSET, 0x0004);
+      //read status register
+      result = vcmd_read_reg((const void *)dev[n].hwregs, VCMD_REGISTER_INT_STATUS_OFFSET);
+      //clean status register
+      vcmd_write_reg((const void *)dev[n].hwregs, VCMD_REGISTER_INT_STATUS_OFFSET, result);
+      for (i = VCMD_REGISTER_CONTROL_OFFSET; i < dev[n].vcmd_core_cfg.vcmd_iosize; i += 4)
+      {
+        //set all register 0
+        vcmd_write_reg((const void *)dev[n].hwregs, i, 0x0000);
+      }
+      //enable all interrupt
+      vcmd_write_reg((const void *)dev[n].hwregs, VCMD_REGISTER_INT_CTL_OFFSET, 0xffffffff);
+    }
+  }
+}
+
+static void vcmd_reset_current_asic(struct hantrovcmd_dev *dev)
+{
+  u32 result;
+
+  if (dev->hwregs != NULL)
+  {
+    //disable interrupt at first
+    vcmd_write_reg((const void *)dev->hwregs, VCMD_REGISTER_INT_CTL_OFFSET, 0x0000);
+    //reset all
+    vcmd_write_reg((const void *)dev->hwregs, VCMD_REGISTER_CONTROL_OFFSET, 0x0002);
+    //read status register
+    result = vcmd_read_reg((const void *)dev->hwregs, VCMD_REGISTER_INT_STATUS_OFFSET);
+    //clean status register
+    vcmd_write_reg((const void *)dev->hwregs, VCMD_REGISTER_INT_STATUS_OFFSET, result);
+  }
+}
+
+/*
+* the related code for xtensa interrupt interfaces
+*/
+av_unused int RegisterIRQ(i32 irq_offset, IRQHandler isr_handler, i32 flag, const char *name, void *data)
+{
+  //CPU interrupt handler
+  //_xtos_set_interrupt_handle
+  u32 irq_mask = 1 << irq_offset; //irq_offset -> Irq[0] is 8
+  u32 enabled_int = 0;
+  if ((xthal_get_intenable() & irq_mask) == 0)
+  {
+    /* Clear MCPU DB2 interrupt before enable */
+    xthal_set_intclear(irq_mask);
+    /* Assign Interrupt handler */
+    xt_set_interrupt_handler(irq_offset, (xt_handler)isr_handler, data);
+
+    xt_ints_on(irq_mask);
+
+    enabled_int = xthal_get_intenable();
+    PDEBUG("INTs are enabled: 0x%x\n", enabled_int);
+  }
+
+  return 0;
+}
+
+static void IntEnableIRQ(u32 irq_offset)
+{
+  //sys reg interrupt enable
+  u32 irq_mask = 1 << irq_offset;
+  u32 curr_en;
+
+  *((volatile uint32_t *)SYS_REG_INT_STAT) = irq_mask; // clear this irq
+
+  curr_en = ioread32((void *)SYS_REG_INT_EN) | irq_mask;
+  *((volatile uint32_t *)SYS_REG_INT_EN) = curr_en; // enable this irq
+  
+  g_vc8000_int_enable_mask |= irq_mask;
+}
+
+av_unused void IntDisableIRQ(u32 irq_offset)
+{
+  //sys reg interrupt disable
+  u32 irq_mask = 1 << irq_offset;
+  u32 curr_en;
+
+  *((volatile uint32_t *)SYS_REG_INT_STAT) = irq_mask; // clear this irq
+
+  curr_en = ioread32((void *)SYS_REG_INT_EN) & (~irq_mask);
+  *((volatile uint32_t *)SYS_REG_INT_EN) = curr_en; // disable this irq
+}
+
+static void IntClearIRQStatus(u32 irq_offset)
+{
+  //sys reg interrupt clear
+  u32 irq_mask = 1 << irq_offset;
+
+  *((volatile uint32_t *)SYS_REG_INT_STAT) = irq_mask; // clear this irq
+}
+
+static inline uint32_t ReadInterruptStatus(void)
+{
+  uint32_t interrupt;
+  __asm__ __volatile__("rsr %0, interrupt"
+                       : "=a"(interrupt));
+  return interrupt;
+}
+//For debug
+av_unused u32 IntGetIRQStatus(u32 irq_offset)
+{
+  uint32_t ret_val;
+  //ReadInterruptStatus
+  ret_val = ReadInterruptStatus();
+  //mask other interrupts ?
+  ret_val &= (1 << irq_offset);
+  // return 1 if requested interrupt is set
+  if (ret_val)
+    ret_val = 1;
+  return 0;
+}
+
+void queue_vcmd_init(void *semaphore)
+{
+#ifdef VCMD_POLLING
+  sem_t *sem_temp = (sem_t *)semaphore;
+  sem_init(sem_temp, 0, 0);
+#else
+  SemaphoreHandle_t *sem_temp = (SemaphoreHandle_t *)semaphore;
+  *sem_temp = xSemaphoreCreateBinary(); //xSemaphoreCreateCounting(0x7FFU, 0);
+#endif
+}
+
+u32 queue_vcmd_wait(void *semaphore)
+{
+#ifdef VCMD_POLLING
+  sem_t *sem_temp = (sem_t *)semaphore;
+  sem_wait(sem_temp);
+#else
+  SemaphoreHandle_t *sem_temp = (SemaphoreHandle_t *)semaphore;
+  xSemaphoreTake(*sem_temp, portMAX_DELAY);
+#endif
+  return 0;
+}
+
+void queue_vcmd_wakeup(void *semaphore)
+{
+//use sched_yield to free the cpu cycles of hantrovcmd_isr functions
+  //u32 wake_up_start =  xthal_get_ccount();
+#ifdef VCMD_POLLING
+  sem_t * sem_temp = (sem_t *) semaphore;
+  sem_post(sem_temp);
+#else
+  SemaphoreHandle_t * sem_temp = (SemaphoreHandle_t *)semaphore;
+  if(vcmd_init_flag)
+    xSemaphoreGive(*sem_temp);
+  else
+    xSemaphoreGiveFromISR(*sem_temp, NULL);
+#endif
+  //u32 wake_up_end = xthal_get_ccount();
+  //printf("sem post cpu cycle is %d\n", wake_up_end-wake_up_start);
+}

+ 86 - 0
linux/subsys_driver/freertos/io_tools.c

@@ -0,0 +1,86 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2021 VERISILICON
+*
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2021 VERISILICON
+*
+*    This program is free software; you can redistribute it and/or
+*    modify it under the terms of the GNU General Public License
+*    as published by the Free Software Foundation; either version 2
+*    of the License, or (at your option) any later version.
+*
+*    This program is distributed in the hope that it will be useful,
+*    but WITHOUT ANY WARRANTY; without even the implied warranty of
+*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*    GNU General Public License for more details.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+#include "io_tools.h"
+
+inline u32 ioread32(volatile void* addr) {
+  return *(volatile u32*)(addr);
+}
+
+inline void iowrite32(u32 val,volatile void *addr) {
+  *(volatile u32*)addr = val;
+}
+inline u16 ioread16(volatile void* addr) {
+  return *(volatile u16*)(addr);
+}
+
+inline void iowrite16(u16 val,volatile void *addr) {
+  *(volatile u16*)addr = val;
+}
+
+inline u8 ioread8(volatile void* addr) {
+  return *(volatile u8*)(addr);
+}
+
+inline void iowrite8(u8 val,volatile void *addr) {
+  *(volatile u8*)addr = val;
+}
+
+inline u32 readl(volatile void* addr) {
+  return *(volatile u32*)(addr);
+}
+
+inline void writel(unsigned int v, volatile void *addr) {
+  *(volatile unsigned int *)addr = /*cpu_to_le32*/(v);
+}

+ 89 - 0
linux/subsys_driver/freertos/io_tools.h

@@ -0,0 +1,89 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2021 VERISILICON
+*
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2021 VERISILICON
+*
+*    This program is free software; you can redistribute it and/or
+*    modify it under the terms of the GNU General Public License
+*    as published by the Free Software Foundation; either version 2
+*    of the License, or (at your option) any later version.
+*
+*    This program is distributed in the hope that it will be useful,
+*    but WITHOUT ANY WARRANTY; without even the implied warranty of
+*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*    GNU General Public License for more details.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+#ifndef _IO_TOOLS_
+#define _IO_TOOLS_
+
+#include "basetype.h"
+
+u32 ioread32(volatile void* addr);
+void iowrite32(u32 val,volatile void *addr);
+u16 ioread16(volatile void* addr);
+u8 ioread8(volatile void* addr);
+void iowrite16(u16 val,volatile void *addr);
+void iowrite8(u8 val,volatile void *addr);
+u32 readl(volatile void* addr);
+void writel(unsigned int v, volatile void *addr);
+#define read_mreg32(addr) ioread32((void*)(addr))
+#define write_mreg32(addr,val) iowrite32(val, (void*)(addr))
+#define read_mreg16(addr) ioread16((void*)addr)
+#define write_mreg16(addr,val) iowrite16(val, (void*)(addr))
+#define read_mreg8(addr) ioread8((void*)addr)
+#define write_mreg8(addr,val) iowrite8(val, (void*)(addr))
+
+//Dec
+int hantrodec_init(void);
+int hantrodec_open(int *inode, int filp);
+int hantrodec_release(int *inode, int filp);
+long hantrodec_ioctl(int filp, unsigned int cmd, void *arg);
+
+//VCMD interfaces funcs
+int hantrovcmd_init(void);
+int hantrovcmd_open(int *inode, int filp);
+int hantrovcmd_release(int *inode, int filp);
+long hantrovcmd_ioctl(int filp, unsigned int cmd, void *arg);
+//typedef int (*IRQHandler)(i32 i, void* data);
+typedef void (*IRQHandler)(void* data);
+
+#endif //_IO_TOOLS_

+ 484 - 0
linux/subsys_driver/freertos/memalloc_freertos.c

@@ -0,0 +1,484 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2021 VERISILICON
+*
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2021 VERISILICON
+*
+*    This program is free software; you can redistribute it and/or
+*    modify it under the terms of the GNU General Public License
+*    as published by the Free Software Foundation; either version 2
+*    of the License, or (at your option) any later version.
+*
+*    This program is distributed in the hope that it will be useful,
+*    but WITHOUT ANY WARRANTY; without even the implied warranty of
+*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*    GNU General Public License for more details.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+#include "osal.h"
+#include "memalloc_freertos.h"
+
+/* Dev Memory Map for NETNT */
+#define DEV_MEM_BANK_0           (0)
+#define MEM_BANK0_SIZE           (16*1024*1024*1024LL)
+#define DEV_MEM_BANK_1           (1)
+#define MEM_BANK1_SIZE           (16*1024*1024*1024LL)
+#if 1
+#define SHARED_MEM_DEV_ADDRESS   (0x840000000LL) //TOP 29
+#define SHARED_MEM_CPU_ADDRESS    (0x40000000)
+//#define SHARED_MEM_CPU_ADDRESS   (0x30000000)
+//#define SHARED_MEM_CPU_ADDRESS   (0x30000000)
+#define SHARED_MEM_SIZE          (2*1024*1024*1024LL)
+#define SHARED_MEM_BANK          (DEV_MEM_BANK_0)
+#else
+#define SHARED_MEM_DEV_ADDRESS   (0x800000000LL) //TOP24
+#define SHARED_MEM_CPU_ADDRESS   (0x80000000)
+#define SHARED_MEM_SIZE          (2*1024*1024*1024LL)
+#define SHARED_MEM_BANK          (DEV_MEM_BANK_0)
+#endif
+
+#define MEM_0_DEV_ADDRESS        (SHARED_MEM_DEV_ADDRESS + SHARED_MEM_SIZE)
+#define MEM_0_CPU_ADDRESS        (0)
+#define MEM_0_SIZE               (MEM_BANK0_SIZE + MEM_BANK1_SIZE - SHARED_MEM_SIZE)
+#define MEM_0_BANK               (DEV_MEM_BANK_0)
+
+/*
+#define MEM_1_DEV_ADDRESS        (0xC00000000LL)
+#define MEM_1_CPU_ADDRESS        (0)
+#define MEM_1_SIZE               (16*1024*1024*1024LL)
+#define MEM_1_BANK               (DEV_MEM_BANK_1)
+*/
+
+/* the size of chunk in MEMALLOC_DYNAMIC */
+#define CHUNK_SIZE    (16*1024)
+
+/* DO NOT change below defines, they need to be matched with DWL_MEM_TYPE_xx */
+#define _MEM_TYPE_CPU                 0U /* CPU RW. non-secure CMA memory */
+#define _MEM_TYPE_SLICE               1U /* VPU R, CAAM W */
+#define _MEM_TYPE_DPB                 2U /* VPU RW, Render R */
+#define _MEM_TYPE_VPU_WORKING         3U /* VPU R, CPU W. non-secure memory */
+#define _MEM_TYPE_VPU_WORKING_SPECIAL 4U /* VPU R, CPU RW. only for VP9 counter context table */
+#define _MEM_TYPE_VPU_ONLY            5U /* VPU RW only. */
+
+/*
+  memory type enum
+*/
+typedef enum {
+  MEM_TYPE_SHARED = 0,
+  MEM_TYPE_DEVICE,
+}_mem_type;
+
+/*
+  memory region id enum, also as index of array "_regions" and array "hlina_mgr"
+*/
+typedef enum {
+  MEM_ID_SHARED = 0,
+  MEM_ID_0,
+/*  MEM_ID_1, */
+  MAX_MEM_REGION
+}_mem_region_id;
+
+/*
+  memory region properties struct
+*/
+typedef struct __mem_region {
+  unsigned long long bus_addr;          /* Physical address of dev memory region */
+  char *             virt_addr;         /* virtual address mapping to CPU, 0 means invisible to CPU */
+  unsigned long long size;              /* size of dev memory region */
+  unsigned short     bank;              /* DDR RAM bank id */
+  _mem_type          type;
+  unsigned long      translation_offset; /* user space SW will substract HLINA_TRANSL_OFFSET from the bus address
+                                          * and decoder HW will use the result as the address translated base
+                                          * address. The SW needs the original host memory bus address for memory
+                                          * mapping to virtual address. */
+} _mem_region_t;
+
+/*
+  descriptor for each chunk
+*/
+typedef struct hlinc {
+  unsigned short chunks_occupied;       /* indicate number of occupied chunks which start from current chunk */
+  int filp;                             /* Client that allocated this chunk */
+} hlina_chunk_t;
+
+/*
+  memory region management struct
+*/
+typedef struct __hlina_mgr {
+	hlina_chunk_t *hlina_chunks;        /* point to descriptor of each chunks */
+	unsigned long chunks;               /* total chunks in this mem region */
+	unsigned long reserved_chunks;      /* number of reserved chunks in this mem rtegion. 
+                                         * The reserved chunks is located at the beginning of corresponding mem region, application can't use them */
+	_mem_region_t *mem_prop;
+} _hlina_mgr_t;
+
+
+/* 
+  memory regions perporties, indexed by _mem_region_id.
+*/
+static _mem_region_t _regions[MAX_MEM_REGION] = {
+  /*MEM_ID_SHARED*/ { SHARED_MEM_DEV_ADDRESS, (char *)SHARED_MEM_CPU_ADDRESS, SHARED_MEM_SIZE, SHARED_MEM_BANK,  MEM_TYPE_SHARED,  0 },
+  /*MEM_ID_0     */ { MEM_0_DEV_ADDRESS,      (char *)MEM_0_CPU_ADDRESS,      MEM_0_SIZE,      MEM_0_BANK,       MEM_TYPE_DEVICE,  0 }
+  /*MEM_ID_1        { MEM_1_DEV_ADDRESS,      (char *)MEM_1_CPU_ADDRESS,      MEM_1_SIZE,      MEM_1_BANK,       MEM_TYPE_DEVICE,  0 } */
+};
+
+/* 
+  memory regions hlina manager, indexed by _mem_region_id.
+*/
+static _hlina_mgr_t hlina_mgr[MAX_MEM_REGION];
+
+int memalloc_major = -1;
+//static DEFINE_SPINLOCK(mem_lock);
+pthread_mutex_t mem_lock = PTHREAD_MUTEX_INITIALIZER;
+/*
+  Functions declaration
+*/
+static int AllocMemory(unsigned long long *busaddr, unsigned int size, unsigned int region, const int filp);
+static int FreeMemory(unsigned long long busaddr, const int filp);
+//static void * DirectMemoryMap(unsigned long long busaddr, unsigned long map_size);
+static void CalculateChunks(_mem_region_id id, unsigned long *chunks, unsigned long *chunks_mgr_size);
+static void ResetMems(void);
+
+/*
+  To specified mem region, calculate total chunks number and aligned buffer size to store chunks' descriptors.
+*/
+static void CalculateChunks(_mem_region_id id, unsigned long *chunks, unsigned long *chunks_mgr_size)
+{
+  *chunks = 0;
+  *chunks_mgr_size = 0;
+
+  if(id < MAX_MEM_REGION) {
+    *chunks = _regions[id].size / CHUNK_SIZE;
+    *chunks_mgr_size = (((unsigned int)*chunks) * sizeof(hlina_chunk_t) + CHUNK_SIZE - 1) & (~(CHUNK_SIZE - 1));
+  }
+}
+
+/*
+  To specified bus address, convert it to virtual (CPU) address according to mem region properties.
+*/
+void * DirectMemoryMap(unsigned long long busaddr, unsigned long map_size) {
+  int i;
+  unsigned long long offset;
+  void *virtaddr = NULL;
+  u32 busAddrRight = 0;
+
+  if(map_size == 0) {
+    return NULL;
+  }
+
+  for(i=0; i<MAX_MEM_REGION; i++) {
+    if((busaddr >= _regions[i].bus_addr) && (busaddr <= _regions[i].bus_addr + _regions[i].size)) {
+      busAddrRight = 1;
+      if(_regions[i].virt_addr == NULL) {
+        continue;
+      }
+      else {
+        offset = busaddr - _regions[i].bus_addr;
+        if ((offset + map_size) <= _regions[i].size) {
+          virtaddr = (void *)(_regions[i].virt_addr + offset);
+          break;
+        }
+      }
+    }
+  }
+  if((!busAddrRight) && (virtaddr==NULL)) {
+    return (void *)(unsigned long)busaddr;
+  }
+
+  return virtaddr;
+}
+
+/*
+  ioctl
+*/
+long memalloc_ioctl(int filp, unsigned int cmd, void *arg) {
+  int ret = 0;
+  MemallocParams memparams;
+  addr_t busaddr;
+  unsigned int region;
+
+  PDEBUG("memalloc ioctl cmd 0x%08x\n", cmd);
+
+  /*
+   * extract the type and number bitfields, and don't decode
+   * wrong cmds: return ENOTTY (inappropriate ioctl) before access_ok()
+   */
+  if (_IOC_TYPE(cmd) != MEMALLOC_IOC_MAGIC) return -ENOTTY;
+  if (_IOC_NR(cmd) > MEMALLOC_IOC_MAXNR) return -ENOTTY;
+
+  if (_IOC_DIR(cmd) & _IOC_READ)
+    ret = !access_ok(VERIFY_WRITE, arg, _IOC_SIZE(cmd));
+  else if (_IOC_DIR(cmd) & _IOC_WRITE)
+    ret = !access_ok(VERIFY_READ, arg, _IOC_SIZE(cmd));
+  if (ret) return -EFAULT;
+
+  spin_lock(&mem_lock);
+
+  switch (cmd) {
+  case MEMALLOC_IOCHARDRESET:
+    PDEBUG("memalloc HARDRESET\n");
+    ResetMems();
+    break;
+  case MEMALLOC_IOCXGETBUFFER:
+    PDEBUG("memalloc GETBUFFER");
+
+    ret = copy_from_user(&memparams, (MemallocParams *)arg,
+                         sizeof(MemallocParams));
+    if (ret) break;
+
+    region = MEM_ID_SHARED;
+    if(memparams.mem_type == _MEM_TYPE_DPB || memparams.mem_type == _MEM_TYPE_VPU_ONLY)
+#ifndef MEM_ONLY_DEV_CHECK
+      region = MEM_ID_SHARED; //For get output buffer for CPU
+#else
+      region = MEM_ID_0;
+#endif
+    ret = AllocMemory(&memparams.bus_address, memparams.size, region, filp);
+
+    memparams.translation_offset = _regions[region].translation_offset;
+
+    ret |= copy_to_user((MemallocParams *)arg, &memparams,
+                        sizeof(MemallocParams));
+
+    break;
+  case MEMALLOC_IOCSFREEBUFFER:
+    PDEBUG("memalloc FREEBUFFER\n");
+
+    __get_user(busaddr, (addr_t *)arg);
+    ret = FreeMemory(busaddr, filp);
+    break;
+  }
+
+  spin_unlock(&mem_lock);
+
+  return ret ? -EFAULT : 0;
+}
+
+int memalloc_open(int *inode, int filp) {
+  PDEBUG("memalloc dev opened\n");
+  return 0;
+}
+
+int memalloc_release(int *inode, int filp) {
+  int i = 0, j = 0;
+  hlina_chunk_t *p_hlina;
+
+  for (i = 0; i < MAX_MEM_REGION; i++) {
+  	p_hlina = hlina_mgr[i].hlina_chunks;
+    for (j = hlina_mgr[i].reserved_chunks; j < hlina_mgr[i].chunks; j++) {
+      spin_lock(&mem_lock);
+      if (p_hlina[j].filp == filp) {
+        printk(KERN_WARNING "memalloc: Found unfreed memory at release time!\n");
+
+        p_hlina[j].filp = 0;
+        p_hlina[j].chunks_occupied = 0;
+      }
+      spin_unlock(&mem_lock);
+    }
+  }
+  PDEBUG("memalloc dev closed\n");
+  return 0;
+}
+
+int __init memalloc_init(void) {
+  int result;
+  int i;
+  unsigned long chunks, mgr_size, reserved_size;
+  void *p;
+
+
+  PDEBUG("memalloc module init\n");
+  printk("memalloc: Linear Memory Allocator\n");
+
+  /*
+    Allocate memory for hlina_mgr
+    In NETINT platform, there is no big heap memory to store hlina_mgr, so it is put to beginning of shared memory region directly
+  */
+  reserved_size = 0;
+  for (i=0; i<MAX_MEM_REGION; i++) {
+    CalculateChunks(i, &chunks, &mgr_size);
+
+    /* all hlina_chunks are put to SHARED memory region */
+    p = DirectMemoryMap(_regions[MEM_ID_SHARED].bus_addr + reserved_size, mgr_size);
+    hlina_mgr[i].hlina_chunks    = (hlina_chunk_t *)p;
+    hlina_mgr[i].chunks          = chunks;
+    hlina_mgr[i].reserved_chunks = 0;
+    hlina_mgr[i].mem_prop        = &_regions[i];
+
+    reserved_size += mgr_size;
+	printk("memalloc: Linear memory base = 0x%08llx\n", _regions[i].bus_addr);
+    printk(KERN_INFO
+           "memalloc: Region[%d] size %lu MB; %lu chunks"
+           " of size %d\n", i,
+           (unsigned long)(_regions[i].size/(1024*1024)), chunks, CHUNK_SIZE);
+  }
+  hlina_mgr[MEM_ID_SHARED].reserved_chunks = reserved_size / CHUNK_SIZE;
+
+  result = register_chrdev(memalloc_major, "memalloc", &memalloc_fops);
+  if (result < 0) {
+    PDEBUG("memalloc: unable to get major %d\n", memalloc_major);
+    goto err;
+  } else if (result != 0) {/* this is for dynamic major */
+    memalloc_major = result;
+  }
+
+  ResetMems();
+
+  printf("memalloc init successful...\n");
+  return 0;
+
+err:
+#if 0
+  if (hlina_chunks != NULL) vfree(hlina_chunks);
+#endif
+
+  return result;
+}
+
+/* 
+  Cycle through the buffers in specified region, give the first free one.
+  TBD: need to check if specifying _mem_type is better than region.
+*/
+static int AllocMemory(unsigned long long *busaddr, unsigned int size, unsigned int region, const int filp) {
+  int i = 0;
+  int j = 0;
+  unsigned int skip_chunks = 0;
+  unsigned long total_chunks;
+  hlina_chunk_t *p_hlina;
+
+  /* calculate how many chunks we need; round up to chunk boundary */
+  unsigned int alloc_chunks = (size + CHUNK_SIZE - 1) / CHUNK_SIZE;
+
+  *busaddr = 0;
+
+  if(region >= MAX_MEM_REGION) {
+    printk("memalloc: Allocation FAILED: unknown region = %u\n", region);
+    return -EFAULT;
+  }
+
+  p_hlina = hlina_mgr[region].hlina_chunks;
+  total_chunks = hlina_mgr[region].chunks;
+
+  /* run through the chunk table */
+  for (i = hlina_mgr[region].reserved_chunks; i < total_chunks;) {
+    skip_chunks = 0;
+    /* if this chunk is available */
+    if (!p_hlina[i].chunks_occupied) {
+      /* check that there is enough memory left */
+      if (i + alloc_chunks > total_chunks) break;
+
+      /* check that there is enough consecutive chunks available */
+      for (j = i; j < i + alloc_chunks; j++) {
+        if (p_hlina[j].chunks_occupied) {
+          skip_chunks = 1;
+          /* skip the used chunks */
+          i = j + p_hlina[j].chunks_occupied;
+          break;
+        }
+      }
+
+      /* if enough free memory found */
+      if (!skip_chunks) {
+        *busaddr = hlina_mgr[region].mem_prop->bus_addr + i * CHUNK_SIZE;
+        p_hlina[i].filp = filp;
+        p_hlina[i].chunks_occupied = alloc_chunks;
+        break;
+      }
+    } else {
+      /* skip the used chunks */
+      i += p_hlina[i].chunks_occupied;
+    }
+  }
+
+  if (*busaddr == 0) {
+    printk("memalloc: Allocation FAILED: size = %u\n", size);
+    return -EFAULT;
+  } else {
+    PDEBUG("MEMALLOC OK: size: %d, reserved: %d\n", size,
+           alloc_chunks * CHUNK_SIZE);
+  }
+
+  return 0;
+}
+
+/* Free a buffer based on bus address */
+static int FreeMemory(unsigned long long busaddr, const int filp) {
+  unsigned int i, id;
+  unsigned long long addr;
+  hlina_chunk_t *p_hlina;
+
+  for(i = 0; i < MAX_MEM_REGION; i++) {
+    addr = busaddr + _regions[i].translation_offset;
+	if ((addr >= _regions[i].bus_addr) && (addr < _regions[i].bus_addr + _regions[i].size)) {
+      id = (addr - _regions[i].bus_addr) / CHUNK_SIZE;
+      p_hlina = &hlina_mgr[i].hlina_chunks[id];
+      if ((p_hlina->chunks_occupied) && (p_hlina->filp == filp)) {
+        p_hlina->filp = 0;
+        p_hlina->chunks_occupied = 0;
+        return 0;
+      }
+    }
+  }
+
+  printk(KERN_WARNING "memalloc: Owner mismatch while freeing memory!\n");
+  return -1;
+}
+
+
+/* Reset "used" status */
+static void ResetMems(void) {
+  int i, j = 0;
+  hlina_chunk_t *p_hlina;
+
+  for (i=0; i<MAX_MEM_REGION; i++) {
+    p_hlina = hlina_mgr[i].hlina_chunks;
+    for(j=hlina_mgr[i].reserved_chunks; j<hlina_mgr[i].chunks; j++) {
+      p_hlina[j].filp = 0;
+      p_hlina[j].chunks_occupied = 0;
+    }
+  }
+}
+
+//memory type is shared
+//return busAddr and virtrulAddr
+addr_t GetBusAddrForIODevide(unsigned int size) {
+  addr_t bus_addr = 0;
+  AllocMemory(&bus_addr, size, MEM_ID_SHARED , MEM_FD);
+  return bus_addr;
+}

+ 104 - 0
linux/subsys_driver/freertos/memalloc_freertos.h

@@ -0,0 +1,104 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2021 VERISILICON
+*
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2021 VERISILICON
+*
+*    This program is free software; you can redistribute it and/or
+*    modify it under the terms of the GNU General Public License
+*    as published by the Free Software Foundation; either version 2
+*    of the License, or (at your option) any later version.
+*
+*    This program is distributed in the hope that it will be useful,
+*    but WITHOUT ANY WARRANTY; without even the implied warranty of
+*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*    GNU General Public License for more details.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+#ifndef _MEMALLOC_FREERTOS_H_
+#define _MEMALLOC_FREERTOS_H_
+
+#include "user_freertos.h"
+#include "dev_common_freertos.h"
+
+#undef PDEBUG   /* undef it, just in case */
+#ifdef MEMALLOC_DEBUG
+/* This one for user space */
+#define PDEBUG(fmt, args...) fprintf(stderr, fmt, ## args)
+#else
+#define PDEBUG(fmt, args...)  /* not debugging: nothing */
+#endif
+/*
+ * Ioctl definitions
+ */
+/* Use 'k' as magic number */
+#define MEMALLOC_IOC_MAGIC  'k'
+/*
+ * S means "Set" through a ptr,
+ * T means "Tell" directly with the argument value
+ * G means "Get": reply by setting through a pointer
+ * Q means "Query": response is on the return value
+ * X means "eXchange": G and S atomically
+ * H means "sHift": T and Q atomically
+ */
+#define MEMALLOC_IOCXGETBUFFER    _IOWR(MEMALLOC_IOC_MAGIC, 1, MemallocParams*)
+#define MEMALLOC_IOCSFREEBUFFER   _IOW(MEMALLOC_IOC_MAGIC, 2, unsigned long*)
+#define MEMALLOC_IOCGMEMBASE	  _IOR(MEMALLOC_IOC_MAGIC, 3, unsigned long *)
+
+/* ... more to come */
+#define MEMALLOC_IOCHARDRESET     _IO(MEMALLOC_IOC_MAGIC, 15) /* debugging tool */
+#define MEMALLOC_IOC_MAXNR 15
+
+
+typedef struct {
+  unsigned long long bus_address;
+  unsigned int size;
+  unsigned long translation_offset;
+  unsigned int mem_type;
+} MemallocParams;
+
+//Mem device
+int __init memalloc_init(void);
+int memalloc_open(int *inode, int filp);
+int memalloc_release(int *inode, int filp);
+long memalloc_ioctl(int filp, unsigned int cmd, void *arg);
+void * DirectMemoryMap(unsigned long long busaddr, unsigned long map_size);
+addr_t GetBusAddrForIODevide(unsigned int size);
+
+#endif /* _MEMALLOC_FREERTOS_H_ */

+ 192 - 0
linux/subsys_driver/freertos/subsys_freertos.c

@@ -0,0 +1,192 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2021 VERISILICON
+*
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2021 VERISILICON
+*
+*    This program is free software; you can redistribute it and/or
+*    modify it under the terms of the GNU General Public License
+*    as published by the Free Software Foundation; either version 2
+*    of the License, or (at your option) any later version.
+*
+*    This program is distributed in the hope that it will be useful,
+*    but WITHOUT ANY WARRANTY; without even the implied warranty of
+*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*    GNU General Public License for more details.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+#include "subsys.h"
+#include <string.h>
+
+#undef PDEBUG
+#ifdef HANTRODEC_DEBUG
+#  ifdef __KERNEL__
+#    define PDEBUG(fmt, args...) printk( KERN_INFO "hantrodec: " fmt, ## args)
+#  else
+#    define PDEBUG(fmt, args...) fprintf(stderr, fmt, ## args)
+#  endif
+#else
+#  define PDEBUG(fmt, args...)
+#endif
+
+/******************************************************************************/
+/* subsystem configuration                                                    */
+/******************************************************************************/
+
+/* List of subsystems */
+static struct SubsysDesc subsys_array[] = {
+  /* {slice_index, index, base} */
+  {0, 0, 0x02310000},
+//  {0, 1, 0x02350000}
+};
+
+/* List of all HW cores. */
+static struct CoreDesc core_array[] = {
+  /* {slice, subsys, core_type, offset, iosize, irq, has_apb} */
+#if 0
+  {0, 0, HW_VC8000DJ, 0x600000, 0, 0},
+  {0, 0, HW_VC8000D, 0x602000, 0, 0},
+  {0, 0, HW_L2CACHE, 0x604000, 0, 0},
+  {0, 0, HW_DEC400, 0x606000, 0, 0},
+  {0, 0, HW_BIGOCEAN, 0x608000, 0, 0},
+  {0, 0, HW_NOC,0x60a000, 0, 0},
+  {0, 0, HW_AXIFE, 0x60c000, 0, 0}
+#endif
+  {0, 0, HW_VCMD, 0x0, 27*4, 0, -1},
+  {0, 0, HW_VC8000D, 0x2000, 503*4, -1, -1},
+//  {0, 0, HW_MMU, 0x3000, 228*4, -1, 0},
+//  {0, 0, HW_MMU_WR, 0x4000, 228*4, -1, 0},
+  {0, 0, HW_DEC400, 0x6000, 1568*4, -1, -1},
+  {0, 0, HW_L2CACHE, 0x4000, 231*4, -1, -1},
+//  {0, 0, HW_AXIFE, 0x5000, 64*4, -1, 1},
+
+//  {0, 1, HW_VCMD, 0x0, 27*4, -1, 0},
+//  {0, 1, HW_VC8000D, 0x2000, 503*4, -1, 1},
+//  {0, 1, HW_MMU, 0x3000, 228*4, -1, 0},
+//  {0, 1, HW_MMU_WR, 0x4000, 228*4, -1, 0},
+//  {0, 1, HW_DEC400, 0x6000, 1568*4, -1, 0},
+//  {0, 1, HW_L2CACHE, 0x4000, 231*4, -1, 0},
+//  {0, 1, HW_AXIFE, 0x5000, 64*4, -1, 1},
+};
+
+extern struct vcmd_config vcmd_core_array[MAX_SUBSYS_NUM];
+extern int total_vcmd_core_num;
+extern unsigned long multicorebase[];
+extern int irq[];
+extern unsigned int iosize[];
+extern int reg_count[];
+
+/*
+   If VCMD is used, convert core_array to vcmd_core_array, which are used in
+   hantor_vcmd_xxx.c.
+   Otherwise, covnert core_array to multicore_base/irq/iosize, which are used in
+   hantro_dec_xxx.c
+
+   VCMD:
+        - struct vcmd_config vcmd_core_array[MAX_SUBSYS_NUM]
+        - total_vcmd_core_num
+
+   NON-VCMD:
+        - multicorebase[HXDEC_MAX_CORES]
+        - irq[HXDEC_MAX_CORES]
+        - iosize[HXDEC_MAX_CORES]
+*/
+void CheckSubsysCoreArray(struct subsys_config *subsys, int *vcmd) {
+  int num = sizeof(subsys_array)/sizeof(subsys_array[0]);
+  int i, j;
+
+  memset(subsys, 0, sizeof(subsys[0])*MAX_SUBSYS_NUM);
+  for (i = 0; i < num; i++) {
+    subsys[i].base_addr = subsys_array[i].base;
+    subsys[i].irq = -1;
+    for (j = 0; j < HW_CORE_MAX; j++) {
+      subsys[i].submodule_offset[j] = 0xffff;
+      subsys[i].submodule_iosize[j] = 0;
+      subsys[i].submodule_hwregs[j] = NULL;
+    }
+  }
+
+  total_vcmd_core_num = 0;
+
+  for (i = 0; i < sizeof(core_array)/sizeof(core_array[0]); i++) {
+    if (!subsys[core_array[i].subsys].base_addr) {
+      /* undefined subsystem */
+      continue;
+    }
+    subsys[core_array[i].subsys].submodule_offset[core_array[i].core_type]
+                                  = core_array[i].offset;
+    subsys[core_array[i].subsys].submodule_iosize[core_array[i].core_type]
+                                  = core_array[i].iosize;
+    if (core_array[i].irq != -1) {
+      subsys[core_array[i].subsys].irq = core_array[i].irq;
+    }
+    subsys[core_array[i].subsys].has_apbfilter[core_array[i].core_type] = core_array[i].has_apb; 
+    /* vcmd found */
+    if (core_array[i].core_type == HW_VCMD) {
+      *vcmd = 1;
+      total_vcmd_core_num++;
+    }
+  }
+
+  printk(KERN_INFO "hantrodec: vcmd = %d\n", *vcmd);
+
+  /* To plug into hantro_vcmd.c */
+  if (*vcmd) {
+    for (i = 0; i < total_vcmd_core_num; i++) {
+      vcmd_core_array[i].vcmd_base_addr = subsys[i].base_addr;
+      vcmd_core_array[i].vcmd_iosize = subsys[i].submodule_iosize[HW_VCMD];
+      vcmd_core_array[i].vcmd_irq = subsys[i].irq;
+      vcmd_core_array[i].sub_module_type = 2; /* TODO(min): to be fixed */
+      vcmd_core_array[i].submodule_main_addr = subsys[i].submodule_offset[HW_VC8000D];
+      vcmd_core_array[i].submodule_dec400_addr = subsys[i].submodule_offset[HW_DEC400];
+      vcmd_core_array[i].submodule_L2Cache_addr = subsys[i].submodule_offset[HW_L2CACHE];
+      vcmd_core_array[i].submodule_MMU_addr = subsys[i].submodule_offset[HW_MMU];
+    }
+  }
+  memset(multicorebase, 0, sizeof(multicorebase[0]) * HXDEC_MAX_CORES);
+  for (i = 0; i < num; i++) {
+    multicorebase[i] = subsys[i].base_addr + subsys[i].submodule_offset[HW_VC8000D];
+    irq[i] = subsys[i].irq;
+    iosize[i] = subsys[i].submodule_iosize[HW_VC8000D];
+    printk(KERN_INFO "hantrodec: [%d] multicorebase 0x%08lx, iosize %d\n", i, multicorebase[i], iosize[i]);
+  }
+}
+
+

+ 151 - 0
linux/subsys_driver/freertos/user_freertos.c

@@ -0,0 +1,151 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2021 VERISILICON
+*
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2021 VERISILICON
+*
+*    This program is free software; you can redistribute it and/or
+*    modify it under the terms of the GNU General Public License
+*    as published by the Free Software Foundation; either version 2
+*    of the License, or (at your option) any later version.
+*
+*    This program is distributed in the hope that it will be useful,
+*    but WITHOUT ANY WARRANTY; without even the implied warranty of
+*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*    GNU General Public License for more details.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+#include "osal.h"
+#include "user_freertos.h"
+#include "io_tools.h"
+#include "memalloc_freertos.h"
+
+static pthread_mutex_t vcmd_dev_open_count_mutex = PTHREAD_MUTEX_INITIALIZER;
+static u32 vcmd_dev_open_count = 0;
+extern int vcmd; //it is defined in hantro_dec_freertos.c
+
+/**
+ * Unify driver for vcmd, the related vcmd interface besides init/open/release/
+ * ioctl will be called in the hantrdec_init/open/release/ioctl when vcmd is used.
+ * All drivers's probe should be added and be called by main() explicitly
+ */
+int Platform_init() {
+  //Firstly, initialize the mem for IO device
+  if (memalloc_init() != 0) {
+    PDEBUG("memalloc_init error\n");
+    assert(0);
+  }
+
+  //vcmd will modify if exist vcmd device in hantrodec_init
+  if (hantrodec_init() != 0) {
+    PDEBUG("hantroenc_init error\n");
+    assert(0);
+  }
+
+  return 0;
+}
+int freertos_open(const char* dev_name, int flag) {
+  //do a hash operator to gain the only dev fd
+  //int fd = hash(name);
+  int fd = 0; //the default is error id
+  if(!strcmp(dev_name, DEC_MODULE_PATH)) { 
+    fd = DEC_FD << 28;
+    if(vcmd) {
+      //u32, MSB 4bit for device type, LSB 28bit for reference count
+      pthread_mutex_lock(&vcmd_dev_open_count_mutex);
+      vcmd_dev_open_count++;
+      fd += vcmd_dev_open_count;
+      pthread_mutex_unlock(&vcmd_dev_open_count_mutex);
+    }    
+    hantrodec_open(NULL, fd);
+  }  
+  else if(!strcmp(dev_name, MEMALLOC_MODULE_PATH)) {
+    fd = MEM_FD << 28;
+    memalloc_open(NULL, fd);
+  }
+  return fd;
+}
+
+void freertos_close(int fd) {
+  //u32, MSB 4bit for device type
+  u32 fd_tmp = fd;
+  fd_tmp = fd_tmp >> 28;
+
+  switch(fd_tmp) {
+    case DEC_FD: {
+      hantrodec_release(NULL, fd);
+      break;
+    }
+    case MEM_FD: {
+      //so if low in special paltform, could comment it when test, but in normal, it will be opened
+      //memalloc_release(NULL, fd);
+      break;
+    }
+    case 0: //for /dev/mem, it it not used, so shouldn't go to default
+    	break;
+    default: {
+      PDEBUG("freertos_release fd 0x%x error\n", fd);
+      break;
+    }
+  }
+}
+
+long freertos_ioctl(int fd, unsigned int cmd, void *arg) {
+  long ret = -1;
+  //u32, MSB 4bit for device type
+  u32 fd_tmp = fd;
+  fd_tmp = fd_tmp >> 28;
+  switch(fd_tmp) {
+    case DEC_FD: {
+      ret = hantrodec_ioctl(fd, cmd, arg);
+      break;
+    }
+    case MEM_FD: {
+      ret = memalloc_ioctl(fd, cmd, arg);
+      break;
+    }
+    default: {
+      PDEBUG("freertos_ioctl fd 0x%x error\n", fd);
+      break;
+    }
+  }
+  
+  return ret;
+}
+

+ 79 - 0
linux/subsys_driver/freertos/user_freertos.h

@@ -0,0 +1,79 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2021 VERISILICON
+*
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2021 VERISILICON
+*
+*    This program is free software; you can redistribute it and/or
+*    modify it under the terms of the GNU General Public License
+*    as published by the Free Software Foundation; either version 2
+*    of the License, or (at your option) any later version.
+*
+*    This program is distributed in the hope that it will be useful,
+*    but WITHOUT ANY WARRANTY; without even the implied warranty of
+*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*    GNU General Public License for more details.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+#ifndef _USER_FREERTOS_H_
+#define _USER_FREERTOS_H_
+
+#include "basetype.h"
+
+#include <stddef.h>   // size_t
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+
+//u32, MSB 4bit for device type, LSB 28bit for reference count
+enum {
+  ENC_FD = 0x1,
+  DEC_FD = 0x2,
+  MEM_FD = 0x3
+  //TODO for other device, can exist 15 kinds of evices
+};
+
+int Platform_init();
+int freertos_open(const char* dev_name, int flag);
+void freertos_close(int fd);
+long freertos_ioctl(int filp, unsigned int cmd, void *arg);
+
+#endif /* _USER_FREERTOS_H_ */

+ 88 - 0
linux/subsys_driver/hantro_axife.c

@@ -0,0 +1,88 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2021 VERISILICON
+*
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2021 VERISILICON
+*
+*    This program is free software; you can redistribute it and/or
+*    modify it under the terms of the GNU General Public License
+*    as published by the Free Software Foundation; either version 2
+*    of the License, or (at your option) any later version.
+*
+*    This program is distributed in the hope that it will be useful,
+*    but WITHOUT ANY WARRANTY; without even the implied warranty of
+*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*    GNU General Public License for more details.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+#include <linux/version.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/debugfs.h>
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/pagemap.h>
+#include <linux/sched.h>
+#include <stddef.h>
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0))
+#include <linux/dma-map-ops.h>
+#else
+#include <linux/dma-contiguous.h>
+#endif
+#include <linux/platform_device.h>
+#include <linux/dma-buf.h>
+
+#include "hantroaxife.h"
+
+#define HANTRO_AXIFE_OFFSET 0
+
+void AXIFEEnable (volatile unsigned char *hwregs) {
+  if (!hwregs) return;
+
+  //AXI FE pass through
+  iowrite32(0x40, (void*)(hwregs + HANTRO_AXIFE_OFFSET + 0x2C));
+  printk(KERN_INFO "AXI FE: 0x2C = 0x%x\n", ioread32((void*)(hwregs + 0x2C)));
+  iowrite32(0x2, (void*)(hwregs + HANTRO_AXIFE_OFFSET + 0x28));
+  printk(KERN_INFO "AXI FE: 0x28 = 0x%x\n", ioread32((void*)(hwregs + 0x28)));
+}
+

+ 2973 - 0
linux/subsys_driver/hantro_dec.c

@@ -0,0 +1,2973 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2021 VERISILICON
+*
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2021 VERISILICON
+*
+*    This program is free software; you can redistribute it and/or
+*    modify it under the terms of the GNU General Public License
+*    as published by the Free Software Foundation; either version 2
+*    of the License, or (at your option) any later version.
+*
+*    This program is distributed in the hope that it will be useful,
+*    but WITHOUT ANY WARRANTY; without even the implied warranty of
+*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*    GNU General Public License for more details.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+#include "hantrodec.h"
+#include "dwl_defs.h"
+
+#include <asm/io.h>
+#include <linux/uaccess.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/pci.h>
+#include <linux/sched.h>
+#include <linux/semaphore.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/version.h>
+#include <linux/wait.h>
+#include <linux/timer.h>
+#include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/types.h>
+#include <linux/bitops.h>
+#include <linux/mod_devicetable.h>
+#include "subsys.h"
+#include "hantroaxife.h"
+#include <asm/irq.h>
+#include <linux/platform_device.h>
+#include <linux/device.h>
+#include <linux/cdev.h>
+#include <linux/pm_runtime.h>
+#include <linux/debugfs.h>
+#include "kernel_allocator.h"
+
+#undef PDEBUG
+#ifdef HANTRODEC_DEBUG
+#  ifdef __KERNEL__
+#    define PDEBUG(fmt, args...) printk( KERN_INFO "hantrodec: " fmt, ## args)
+#  else
+#    define PDEBUG(fmt, args...) fprintf(stderr, fmt, ## args)
+#  endif
+#else
+#  define PDEBUG(fmt, args...)
+#endif
+
+#define PCI_VENDOR_ID_HANTRO            0x10ee// 0x1ae0//0x16c3
+#define PCI_DEVICE_ID_HANTRO_PCI        0x8014//0x001a// 0xabcd
+
+/* Base address DDR register */
+#define PCI_DDR_BAR 0
+
+/* Base address got control register */
+#define PCI_CONTROL_BAR                 4
+
+/* PCIe hantro driver offset in control register */
+#define HANTRO_REG_OFFSET0               0x600000
+#define HANTRO_REG_OFFSET1               0x700000
+
+/* TODO(mheikkinen) Implement multicore support. */
+struct pci_dev *gDev = NULL;     /* PCI device structure. */
+unsigned long gBaseHdwr;         /* PCI base register address (Hardware address) */
+unsigned long gBaseDDRHw;        /* PCI base register address (memalloc) */
+u32  gBaseLen;                   /* Base register address Length */
+
+/* hantro G1 regs config including dec and pp */
+//#define HANTRO_DEC_ORG_REGS             60
+//#define HANTRO_PP_ORG_REGS              41
+
+#define HANTRO_DEC_EXT_REGS             27
+#define HANTRO_PP_EXT_REGS              9
+
+//#define HANTRO_G1_DEC_TOTAL_REGS        (HANTRO_DEC_ORG_REGS + HANTRO_DEC_EXT_REGS)
+#define HANTRO_PP_TOTAL_REGS            (HANTRO_PP_ORG_REGS + HANTRO_PP_EXT_REGS)
+#define HANTRO_G1_DEC_REGS              155 /*G1 total regs*/
+
+//#define HANTRO_DEC_ORG_FIRST_REG        0
+//#define HANTRO_DEC_ORG_LAST_REG         59
+//#define HANTRO_DEC_EXT_FIRST_REG        119
+//#define HANTRO_DEC_EXT_LAST_REG         145
+
+#define HANTRO_PP_ORG_FIRST_REG         60
+#define HANTRO_PP_ORG_LAST_REG          100
+#define HANTRO_PP_EXT_FIRST_REG         146
+#define HANTRO_PP_EXT_LAST_REG          154
+
+/* hantro G2 reg config */
+#define HANTRO_G2_DEC_REGS              337 /*G2 total regs*/
+#define HANTRO_G2_DEC_FIRST_REG         0
+#define HANTRO_G2_DEC_LAST_REG          HANTRO_G2_DEC_REGS-1
+
+/* hantro VC8000D reg config */
+#define HANTRO_VC8000D_REGS             503 /*VC8000D total regs*/
+#define HANTRO_VC8000D_FIRST_REG        0
+#define HANTRO_VC8000D_LAST_REG         HANTRO_VC8000D_REGS-1
+#define HANTRODEC_HWBUILD_ID_OFF (309 * 4)
+
+/* Logic module IRQs */
+#define HXDEC_NO_IRQ                    -1
+
+#define MAX(a, b)                       (((a) > (b)) ? (a) : (b))
+
+#define DEC_IO_SIZE_MAX                 (MAX(MAX(HANTRO_G2_DEC_REGS, HANTRO_G1_DEC_REGS), HANTRO_VC8000D_REGS) * 4)
+
+/* User should modify these configuration if do porting to own platform. */
+/* Please guarantee the base_addr, io_size, dec_irq belong to same core. */
+
+/* Defines use kernel clk cfg or not**/
+//#define CLK_CFG
+#ifdef CLK_CFG
+#define CLK_ID                          "hantrodec_clk"  /*this id should conform with platform define*/
+#endif
+
+/* Logic module base address */
+#define SOCLE_LOGIC_0_BASE              0x38300000
+#define SOCLE_LOGIC_1_BASE              0x38310000
+
+#define VEXPRESS_LOGIC_0_BASE           0xFC010000
+#define VEXPRESS_LOGIC_1_BASE           0xFC020000
+
+#define DEC_IO_SIZE_0                   DEC_IO_SIZE_MAX /* bytes */
+#define DEC_IO_SIZE_1                   DEC_IO_SIZE_MAX /* bytes */
+
+#define DEC_IRQ_0                       HXDEC_NO_IRQ
+#define DEC_IRQ_1                       HXDEC_NO_IRQ
+
+#define IS_G1(hw_id)                    (((hw_id) == 0x6731)? 1 : 0)
+#define IS_G2(hw_id)                    (((hw_id) == 0x6732)? 1 : 0)
+#define IS_VC8000D(hw_id)               (((hw_id) == 0x8001)? 1 : 0)
+#define IS_BIGOCEAN(hw_id)              (((hw_id) == 0xB16D)? 1 : 0)
+
+/* Some IPs HW configuration paramters for APB Filter */
+/* Because now such information can't be read from APB filter configuration registers */
+/* The fixed value have to be used */
+#define VC8000D_NUM_MASK_REG            336
+#define VC8000D_NUM_MODE                4
+#define VC8000D_MASK_REG_OFFSET         4096
+#define VC8000D_MASK_BITS_PER_REG       1
+
+#define VC8000DJ_NUM_MASK_REG           332
+#define VC8000DJ_NUM_MODE               1
+#define VC8000DJ_MASK_REG_OFFSET        4096
+#define VC8000DJ_MASK_BITS_PER_REG      1
+
+#define AV1_NUM_MASK_REG                303
+#define AV1_NUM_MODE                    1
+#define AV1_MASK_REG_OFFSET             4096
+#define AV1_MASK_BITS_PER_REG           1
+
+#define AXIFE_NUM_MASK_REG              144
+#define AXIFE_NUM_MODE                  1
+#define AXIFE_MASK_REG_OFFSET           4096
+#define AXIFE_MASK_BITS_PER_REG         1
+
+#define VC8000D_MAX_CONFIG_LEN          32
+
+#define VC8000D_PM_TIMEOUT              100 /* ms */
+/*************************************************************/
+
+/*********************local variable declaration*****************/
+
+static const int DecHwId[] = {
+  0x6731, /* G1 */
+  0x6732, /* G2 */
+  0xB16D, /* BigOcean */
+  0x8001  /* VC8000D */
+};
+
+unsigned long base_port = -1;
+unsigned int pcie = 0;
+volatile unsigned char *reg = NULL;
+unsigned int reg_access_opt = 0;
+unsigned int vcmd = 0;
+unsigned long alloc_size = 512;
+unsigned long alloc_base = 0x1c0000000;
+
+unsigned long multicorebase[HXDEC_MAX_CORES] = {
+  HANTRO_REG_OFFSET0,
+  HANTRO_REG_OFFSET1,
+  0,
+  0
+};
+
+int irq[HXDEC_MAX_CORES] = {
+  131,
+  DEC_IRQ_1,
+  -1,
+  -1
+};
+
+unsigned int iosize[HXDEC_MAX_CORES] = {
+  DEC_IO_SIZE_0,
+  DEC_IO_SIZE_1,
+  -1,
+  -1
+};
+
+/* Because one core may contain multi-pipeline, so multicore base may be changed */
+unsigned long multicorebase_actual[HXDEC_MAX_CORES];
+
+struct subsys_config vpu_subsys[MAX_SUBSYS_NUM];
+
+struct apbfilter_cfg apbfilter_cfg[MAX_SUBSYS_NUM][HW_CORE_MAX];
+
+struct axife_cfg axife_cfg[MAX_SUBSYS_NUM];
+int elements = 2;
+
+#ifdef CLK_CFG
+struct clk *clk_cfg;
+int is_clk_on;
+struct timer_list timer;
+#endif
+
+/* module_param(name, type, perm) */
+//module_param(base_port, ulong, 0);
+module_param(pcie, uint, 0);
+//module_param_array(irq, int, &elements, 0);
+module_param_array(multicorebase, ulong, &elements, 0644);
+module_param(reg_access_opt, uint, 0);
+module_param(vcmd, uint, 0);
+module_param(alloc_base, ulong, 0);
+module_param(alloc_size, ulong, 0);
+
+
+static int hantrodec_major = 0; /* dynamic allocation */
+static int hantrodec_minor = 0; /* dynamic allocation */
+static struct cdev hantrodec_cdev;
+static dev_t hantrodec_devt;
+static struct class *hantrodec_class;
+
+static struct dentry *root_debugfs_dir = NULL;
+
+/* here's all the must remember stuff */
+typedef struct {
+  char *buffer;
+  volatile unsigned int iosize[HXDEC_MAX_CORES];
+  /* mapped address to different HW cores regs*/
+  volatile u8 *hwregs[HXDEC_MAX_CORES][HW_CORE_MAX];
+  /* mapped address to different HW cores regs*/
+  volatile u8 *apbfilter_hwregs[HXDEC_MAX_CORES][HW_CORE_MAX];
+  volatile int irq[HXDEC_MAX_CORES];
+  int hw_id[HXDEC_MAX_CORES][HW_CORE_MAX];
+  /* Requested client type for given core, used when a subsys has multiple
+     decoders, e.g., VC8000D+VC8000DJ+BigOcean */
+  int client_type[HXDEC_MAX_CORES];
+  int cores;
+  struct fasync_struct *async_queue_dec;
+  struct fasync_struct *async_queue_pp;
+  struct platform_device *pdev;
+  struct clk *cclk;
+  struct clk *aclk;
+  struct clk *pclk;
+  char config_buf[VC8000D_MAX_CONFIG_LEN];
+  int has_power_domains;
+} hantrodec_t;
+
+typedef struct {
+  u32 cfg[HXDEC_MAX_CORES];              /* indicate the supported format */
+  u32 cfg_backup[HXDEC_MAX_CORES];       /* back up of cfg */
+  int its_main_core_id[HXDEC_MAX_CORES]; /* indicate if main core exist */
+  int its_aux_core_id[HXDEC_MAX_CORES];  /* indicate if aux core exist */
+} core_cfg;
+
+static hantrodec_t hantrodec_data; /* dynamic allocation? */
+
+static int ReserveIO(void);
+static void ReleaseIO(void);
+
+static void ResetAsic(hantrodec_t * dev);
+
+#ifdef HANTRODEC_DEBUG
+static void dump_regs(hantrodec_t *dev);
+#endif
+
+/* IRQ handler */
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18))
+static irqreturn_t hantrodec_isr(int irq, void *dev_id, struct pt_regs *regs);
+#else
+static irqreturn_t hantrodec_isr(int irq, void *dev_id);
+#endif
+
+static u32 dec_regs[HXDEC_MAX_CORES][DEC_IO_SIZE_MAX/4];
+static u32 apbfilter_regs[HXDEC_MAX_CORES][DEC_IO_SIZE_MAX/4+1];
+/* shadow_regs used to compare whether it's necessary to write to registers */
+static u32 shadow_dec_regs[HXDEC_MAX_CORES][DEC_IO_SIZE_MAX/4];
+
+struct semaphore dec_core_sem;
+struct semaphore pp_core_sem;
+
+static int dec_irq = 0;
+static int pp_irq = 0;
+
+atomic_t irq_rx = ATOMIC_INIT(0);
+atomic_t irq_tx = ATOMIC_INIT(0);
+
+static struct file* dec_owner[HXDEC_MAX_CORES];
+static struct file* pp_owner[HXDEC_MAX_CORES];
+static int CoreHasFormat(const u32 *cfg, int core, u32 format);
+
+/* spinlock_t owner_lock = SPIN_LOCK_UNLOCKED; */
+DEFINE_SPINLOCK(owner_lock);
+
+DECLARE_WAIT_QUEUE_HEAD(dec_wait_queue);
+DECLARE_WAIT_QUEUE_HEAD(pp_wait_queue);
+DECLARE_WAIT_QUEUE_HEAD(hw_queue);
+#ifdef CLK_CFG
+DEFINE_SPINLOCK(clk_lock);
+#endif
+
+#define DWL_CLIENT_TYPE_H264_DEC        1U
+#define DWL_CLIENT_TYPE_MPEG4_DEC       2U
+#define DWL_CLIENT_TYPE_JPEG_DEC        3U
+#define DWL_CLIENT_TYPE_PP              4U
+#define DWL_CLIENT_TYPE_VC1_DEC         5U
+#define DWL_CLIENT_TYPE_MPEG2_DEC       6U
+#define DWL_CLIENT_TYPE_VP6_DEC         7U
+#define DWL_CLIENT_TYPE_AVS_DEC         8U
+#define DWL_CLIENT_TYPE_RV_DEC          9U
+#define DWL_CLIENT_TYPE_VP8_DEC         10U
+#define DWL_CLIENT_TYPE_VP9_DEC         11U
+#define DWL_CLIENT_TYPE_HEVC_DEC        12U
+#define DWL_CLIENT_TYPE_ST_PP           14U
+#define DWL_CLIENT_TYPE_H264_MAIN10     15U
+#define DWL_CLIENT_TYPE_AVS2_DEC        16U
+#define DWL_CLIENT_TYPE_AV1_DEC         17U
+#define DWL_CLIENT_TYPE_BO_AV1_DEC      31U
+
+#define BIGOCEANDEC_CFG 1
+#define BIGOCEANDEC_AV1_E 5
+
+static core_cfg config;
+
+static void ReadCoreConfig(hantrodec_t *dev) {
+  int c, j;
+  u32 reg, tmp, mask;
+
+  memset(config.cfg, 0, sizeof(config.cfg));
+
+  for(c = 0; c < dev->cores; c++) {
+    for (j = 0; j < HW_CORE_MAX; j++) {
+      if (j != HW_VC8000D && j != HW_VC8000DJ && j != HW_BIGOCEAN)
+        continue;
+      if (!dev->hwregs[c][j])   /* NOT defined core type */
+        continue;
+      /* Decoder configuration */
+      if (IS_G1(dev->hw_id[c][j])) {
+        reg = ioread32((void*)(dev->hwregs[c][j] + HANTRODEC_SYNTH_CFG * 4));
+
+        tmp = (reg >> DWL_H264_E) & 0x3U;
+        if(tmp) pr_info("hantrodec: subsys[%d] has H264\n", c);
+        config.cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_H264_DEC : 0;
+
+        tmp = (reg >> DWL_JPEG_E) & 0x01U;
+        if(tmp) pr_info("hantrodec: subsys[%d] has JPEG\n", c);
+        config.cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_JPEG_DEC : 0;
+
+        tmp = (reg >> DWL_HJPEG_E) & 0x01U;
+        if(tmp) pr_info("hantrodec: subsys[%d] has HJPEG\n", c);
+        config.cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_JPEG_DEC : 0;
+
+        tmp = (reg >> DWL_MPEG4_E) & 0x3U;
+        if(tmp) pr_info("hantrodec: subsys[%d] has MPEG4\n", c);
+        config.cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_MPEG4_DEC : 0;
+
+        tmp = (reg >> DWL_VC1_E) & 0x3U;
+        if(tmp) pr_info("hantrodec: subsys[%d] has VC1\n", c);
+        config.cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_VC1_DEC: 0;
+
+        tmp = (reg >> DWL_MPEG2_E) & 0x01U;
+        if(tmp) pr_info("hantrodec: subsys[%d] has MPEG2\n", c);
+        config.cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_MPEG2_DEC : 0;
+
+        tmp = (reg >> DWL_VP6_E) & 0x01U;
+        if(tmp) pr_info("hantrodec: subsys[%d] has VP6\n", c);
+        config.cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_VP6_DEC : 0;
+
+        reg = ioread32((void*)(dev->hwregs[c][j] + HANTRODEC_SYNTH_CFG_2 * 4));
+
+        /* VP7 and WEBP is part of VP8 */
+        mask =  (1 << DWL_VP8_E) | (1 << DWL_VP7_E) | (1 << DWL_WEBP_E);
+        tmp = (reg & mask);
+        if(tmp & (1 << DWL_VP8_E))
+          pr_info("hantrodec: subsys[%d] has VP8\n", c);
+        if(tmp & (1 << DWL_VP7_E))
+          pr_info("hantrodec: subsys[%d] has VP7\n", c);
+        if(tmp & (1 << DWL_WEBP_E))
+          pr_info("hantrodec: subsys[%d] has WebP\n", c);
+        config.cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_VP8_DEC : 0;
+
+        tmp = (reg >> DWL_AVS_E) & 0x01U;
+        if(tmp) pr_info("hantrodec: subsys[%d] has AVS\n", c);
+        config.cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_AVS_DEC: 0;
+
+        tmp = (reg >> DWL_RV_E) & 0x03U;
+        if(tmp) pr_info("hantrodec: subsys[%d] has RV\n", c);
+        config.cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_RV_DEC : 0;
+
+        /* Post-processor configuration */
+        reg = ioread32((void*)(dev->hwregs[c][j] + HANTROPP_SYNTH_CFG * 4));
+
+        tmp = (reg >> DWL_G1_PP_E) & 0x01U;
+        if(tmp) pr_info("hantrodec: subsys[%d] has PP\n", c);
+        config.cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_PP : 0;
+      } else if((IS_G2(dev->hw_id[c][j]))) {
+        reg = ioread32((void*)(dev->hwregs[c][j] + HANTRODEC_CFG_STAT * 4));
+
+        tmp = (reg >> DWL_G2_HEVC_E) & 0x01U;
+        if(tmp) pr_info("hantrodec: subsys[%d] has HEVC\n", c);
+        config.cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_HEVC_DEC : 0;
+
+        tmp = (reg >> DWL_G2_VP9_E) & 0x01U;
+        if(tmp) pr_info("hantrodec: subsys[%d] has VP9\n", c);
+        config.cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_VP9_DEC : 0;
+
+        /* Post-processor configuration */
+        reg = ioread32((void*)(dev->hwregs[c][j] + HANTRODECPP_SYNTH_CFG * 4));
+
+        tmp = (reg >> DWL_G2_PP_E) & 0x01U;
+        if(tmp) pr_info("hantrodec: subsys[%d] has PP\n", c);
+        config.cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_PP : 0;
+      } else if((IS_VC8000D(dev->hw_id[c][j])) && config.its_main_core_id[c] < 0) {
+        reg = ioread32((void*)(dev->hwregs[c][j] + HANTRODEC_SYNTH_CFG * 4));
+        pr_info("hantrodec: subsys[%d] swreg[%d] = 0x%08x\n", c, HANTRODEC_SYNTH_CFG, reg);
+
+        tmp = (reg >> DWL_H264_E) & 0x3U;
+        if(tmp) pr_info("hantrodec: subsys[%d] has H264\n", c);
+        config.cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_H264_DEC : 0;
+
+        tmp = (reg >> DWL_H264HIGH10_E) & 0x01U;
+        if(tmp) pr_info("hantrodec: subsys[%d] has H264HIGH10\n", c);
+        config.cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_H264_DEC : 0;
+
+        tmp = (reg >> DWL_AVS2_E) & 0x03U;
+        if(tmp) pr_info("hantrodec: subsys[%d] has AVS2\n", c);
+        config.cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_AVS2_DEC : 0;
+
+        tmp = (reg >> DWL_JPEG_E) & 0x01U;
+        if(tmp) pr_info("hantrodec: subsys[%d] has JPEG\n", c);
+        config.cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_JPEG_DEC : 0;
+
+        tmp = (reg >> DWL_HJPEG_E) & 0x01U;
+        if(tmp) pr_info("hantrodec: subsys[%d] has HJPEG\n", c);
+        config.cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_JPEG_DEC : 0;
+
+        tmp = (reg >> DWL_MPEG4_E) & 0x3U;
+        if(tmp) pr_info("hantrodec: subsys[%d] has MPEG4\n", c);
+        config.cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_MPEG4_DEC : 0;
+
+        tmp = (reg >> DWL_VC1_E) & 0x3U;
+        if(tmp) pr_info("hantrodec: subsys[%d] has VC1\n", c);
+        config.cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_VC1_DEC: 0;
+
+        tmp = (reg >> DWL_MPEG2_E) & 0x01U;
+        if(tmp) pr_info("hantrodec: subsys[%d] has MPEG2\n", c);
+        config.cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_MPEG2_DEC : 0;
+
+        tmp = (reg >> DWL_VP6_E) & 0x01U;
+        if(tmp) pr_info("hantrodec: subsys[%d] has VP6\n", c);
+        config.cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_VP6_DEC : 0;
+
+        reg = ioread32((void*)(dev->hwregs[c][j] + HANTRODEC_SYNTH_CFG_2 * 4));
+        pr_info("hantrodec: subsys[%d] swreg[%d] = 0x%08x\n", c, HANTRODEC_SYNTH_CFG_2, reg);
+
+        /* VP7 and WEBP is part of VP8 */
+        mask =  (1 << DWL_VP8_E) | (1 << DWL_VP7_E) | (1 << DWL_WEBP_E);
+        tmp = (reg & mask);
+        if(tmp & (1 << DWL_VP8_E))
+          pr_info("hantrodec: subsys[%d] has VP8\n", c);
+        if(tmp & (1 << DWL_VP7_E))
+          pr_info("hantrodec: subsys[%d] has VP7\n", c);
+        if(tmp & (1 << DWL_WEBP_E))
+          pr_info("hantrodec: subsys[%d] has WebP\n", c);
+        config.cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_VP8_DEC : 0;
+
+        tmp = (reg >> DWL_AVS_E) & 0x01U;
+        if(tmp) pr_info("hantrodec: subsys[%d] has AVS\n", c);
+        config.cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_AVS_DEC: 0;
+
+        tmp = (reg >> DWL_RV_E) & 0x03U;
+        if(tmp) pr_info("hantrodec: subsys[%d] has RV\n", c);
+        config.cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_RV_DEC : 0;
+
+        reg = ioread32((void*)(dev->hwregs[c][j] + HANTRODEC_SYNTH_CFG_3 * 4));
+        pr_info("hantrodec: subsys[%d] swreg[%d] = 0x%08x\n", c, HANTRODEC_SYNTH_CFG_3, reg);
+
+        tmp = (reg >> DWL_HEVC_E) & 0x07U;
+        if(tmp) pr_info("hantrodec: subsys[%d] has HEVC\n", c);
+        config.cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_HEVC_DEC : 0;
+
+        tmp = (reg >> DWL_VP9_E) & 0x07U;
+        if(tmp) pr_info("hantrodec: subsys[%d] has VP9\n", c);
+        config.cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_VP9_DEC : 0;
+
+        /* Post-processor configuration */
+        reg = ioread32((void*)(dev->hwregs[c][j] + HANTRODECPP_CFG_STAT * 4));
+
+        tmp = (reg >> DWL_PP_E) & 0x01U;
+        if(tmp) pr_info("hantrodec: subsys[%d] has PP\n", c);
+        config.cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_PP : 0;
+
+        config.cfg[c] |= 1 << DWL_CLIENT_TYPE_ST_PP;
+
+        if (config.its_aux_core_id[c] >= 0) {
+          /* set main_core_id and aux_core_id */
+          reg = ioread32((void*)(dev->hwregs[c][j] + HANTRODEC_SYNTH_CFG_2 * 4));
+
+          tmp = (reg >> DWL_H264_PIPELINE_E) & 0x01U;
+          if(tmp) pr_info("hantrodec: subsys[%d] has pipeline H264\n", c);
+          config.cfg[config.its_aux_core_id[c]] |= tmp ? 1 << DWL_CLIENT_TYPE_H264_DEC : 0;
+
+          tmp = (reg >> DWL_JPEG_PIPELINE_E) & 0x01U;
+          if(tmp) pr_info("hantrodec: subsys[%d] has pipeline JPEG\n", c);
+          config.cfg[config.its_aux_core_id[c]] |= tmp ? 1 << DWL_CLIENT_TYPE_JPEG_DEC : 0;
+        }
+      } else if (IS_BIGOCEAN(dev->hw_id[c][j])) {
+        reg = ioread32((void*)(dev->hwregs[c][j] + BIGOCEANDEC_CFG * 4));
+
+        tmp = (reg >> BIGOCEANDEC_AV1_E) & 0x01U;
+        if(tmp) pr_info("hantrodec: subsys[%d] has AV1 (BigOcean)\n", c);
+        config.cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_BO_AV1_DEC : 0;
+      }
+    }
+  }
+  memcpy(config.cfg_backup, config.cfg, sizeof(config.cfg));
+}
+
+static int CoreHasFormat(const u32 *cfg, int core, u32 format) {
+  return (cfg[core] & (1 << format)) ? 1 : 0;
+}
+
+int GetDecCore(long core, hantrodec_t *dev, struct file* filp, unsigned long format) {
+  int success = 0;
+  unsigned long flags;
+
+  spin_lock_irqsave(&owner_lock, flags);
+  if(CoreHasFormat(config.cfg, core, format) && dec_owner[core] == NULL /*&& config.its_main_core_id[core] >= 0*/) {
+    dec_owner[core] = filp;
+    success = 1;
+
+    /* If one main core takes one format which doesn't supported by aux core, set aux core's cfg to none video format support */
+    if (config.its_aux_core_id[core] >= 0 &&
+        !CoreHasFormat(config.cfg, config.its_aux_core_id[core], format)) {
+      config.cfg[config.its_aux_core_id[core]] = 0;
+    }
+    /* If one aux core takes one format, set main core's cfg to aux core supported video format */
+    else if (config.its_main_core_id[core] >= 0) {
+      config.cfg[config.its_main_core_id[core]] = config.cfg[core];
+    }
+  }
+
+  spin_unlock_irqrestore(&owner_lock, flags);
+
+  return success;
+}
+
+int GetDecCoreAny(long *core, hantrodec_t *dev, struct file* filp,
+                  unsigned long format) {
+  int success = 0;
+  long c;
+
+  *core = -1;
+
+  for(c = 0; c < dev->cores; c++) {
+    /* a free core that has format */
+    if(GetDecCore(c, dev, filp, format)) {
+      success = 1;
+      *core = c;
+      break;
+    }
+  }
+
+  return success;
+}
+
+int GetDecCoreID(hantrodec_t *dev, struct file* filp,
+                 unsigned long format) {
+  long c;
+  unsigned long flags;
+
+  int core_id = -1;
+
+  for(c = 0; c < dev->cores; c++) {
+    /* a core that has format */
+    spin_lock_irqsave(&owner_lock, flags);
+    if(CoreHasFormat(config.cfg, c, format)) {
+      core_id = c;
+      spin_unlock_irqrestore(&owner_lock, flags);
+      break;
+    }
+    spin_unlock_irqrestore(&owner_lock, flags);
+  }
+  return core_id;
+}
+
+#if 0
+static int hantrodec_choose_core(int is_g1) {
+  volatile unsigned char *reg = NULL;
+  unsigned int blk_base = 0x38320000;
+
+  PDEBUG("hantrodec_choose_core\n");
+  if (!request_mem_region(blk_base, 0x1000, "blk_ctl")) {
+    pr_info("blk_ctl: failed to reserve HW regs\n");
+    return -EBUSY;
+  }
+
+  reg = (volatile u8 *) ioremap_nocache(blk_base, 0x1000);
+
+  if (reg == NULL ) {
+    pr_info("blk_ctl: failed to ioremap HW regs\n");
+    if (reg)
+      iounmap((void *)reg);
+    release_mem_region(blk_base, 0x1000);
+    return -EBUSY;
+  }
+
+  // G1 use, set to 1; G2 use, set to 0, choose the one you are using
+  if (is_g1)
+    iowrite32(0x1, (void*)(reg + 0x14));  // VPUMIX only use G1, user should modify the reg according to platform design
+  else
+    iowrite32(0x0, (void*)(reg + 0x14)); // VPUMIX only use G2, user should modify the reg according to platform design
+
+  if (reg)
+    iounmap((void *)reg);
+  release_mem_region(blk_base, 0x1000);
+  PDEBUG("hantrodec_choose_core OK!\n");
+  return 0;
+}
+#endif
+
+long ReserveDecoder(hantrodec_t *dev, struct file* filp, unsigned long format) {
+  long core = -1;
+
+  /* reserve a core */
+  if (down_interruptible(&dec_core_sem))
+    return -ERESTARTSYS;
+
+  /* lock a core that has specific format*/
+  if(wait_event_interruptible(hw_queue,
+                              GetDecCoreAny(&core, dev, filp, format) != 0 ))
+    return -ERESTARTSYS;
+
+#if 0
+  if(IS_G1(dev->hw_id[core])) {
+    if (0 == hantrodec_choose_core(1))
+      printk("G1 is reserved\n");
+    else
+      return -1;
+  } else {
+    if (0 == hantrodec_choose_core(0))
+      printk("G2 is reserved\n");
+    else
+      return -1;
+  }
+#endif
+
+  dev->client_type[core] = format;
+  return core;
+}
+
+void ReleaseDecoder(hantrodec_t *dev, long core) {
+  u32 status;
+  unsigned long flags;
+
+  PDEBUG("ReleaseDecoder %ld\n", core);
+
+  if (dev->client_type[core] == DWL_CLIENT_TYPE_BO_AV1_DEC)
+    status = ioread32((void*)(dev->hwregs[core][HW_BIGOCEAN] + BIGOCEAN_IRQ_STAT_DEC_OFF));
+  else
+    status = ioread32((void*)(dev->hwregs[core][HW_VC8000D] + HANTRODEC_IRQ_STAT_DEC_OFF));
+
+  /* make sure HW is disabled */
+  if(status & HANTRODEC_DEC_E) {
+    pr_info("hantrodec: DEC[%li] still enabled -> reset\n", core);
+
+    /* abort decoder */
+    status |= HANTRODEC_DEC_ABORT | HANTRODEC_DEC_IRQ_DISABLE;
+    iowrite32(status, (void*)(dev->hwregs[core][HW_VC8000D] + HANTRODEC_IRQ_STAT_DEC_OFF));
+  }
+
+  spin_lock_irqsave(&owner_lock, flags);
+
+  /* If aux core released, revert main core's config back */
+  if (config.its_main_core_id[core] >= 0) {
+    config.cfg[config.its_main_core_id[core]] = config.cfg_backup[config.its_main_core_id[core]];
+  }
+
+  /* If main core released, revert aux core's config back */
+  if (config.its_aux_core_id[core] >= 0) {
+    config.cfg[config.its_aux_core_id[core]] = config.cfg_backup[config.its_aux_core_id[core]];
+  }
+
+  dec_owner[core] = NULL;
+
+  spin_unlock_irqrestore(&owner_lock, flags);
+
+  up(&dec_core_sem);
+
+  wake_up_interruptible_all(&hw_queue);
+}
+
+long ReservePostProcessor(hantrodec_t *dev, struct file* filp) {
+  unsigned long flags;
+
+  long core = 0;
+
+  /* single core PP only */
+  if (down_interruptible(&pp_core_sem))
+    return -ERESTARTSYS;
+
+  spin_lock_irqsave(&owner_lock, flags);
+
+  pp_owner[core] = filp;
+
+  spin_unlock_irqrestore(&owner_lock, flags);
+
+  return core;
+}
+
+void ReleasePostProcessor(hantrodec_t *dev, long core) {
+  unsigned long flags;
+
+  u32 status = ioread32((void*)(dev->hwregs[core][HW_VC8000D] + HANTRO_IRQ_STAT_PP_OFF));
+
+  /* make sure HW is disabled */
+  if(status & HANTRO_PP_E) {
+    pr_info("hantrodec: PP[%li] still enabled -> reset\n", core);
+
+    /* disable IRQ */
+    status |= HANTRO_PP_IRQ_DISABLE;
+
+    /* disable postprocessor */
+    status &= (~HANTRO_PP_E);
+    iowrite32(0x10, (void*)(dev->hwregs[core][HW_VC8000D] + HANTRO_IRQ_STAT_PP_OFF));
+  }
+
+  spin_lock_irqsave(&owner_lock, flags);
+
+  pp_owner[core] = NULL;
+
+  spin_unlock_irqrestore(&owner_lock, flags);
+
+  up(&pp_core_sem);
+}
+
+long ReserveDecPp(hantrodec_t *dev, struct file* filp, unsigned long format) {
+  /* reserve core 0, DEC+PP for pipeline */
+  unsigned long flags;
+
+  long core = 0;
+
+  /* check that core has the requested dec format */
+  if(!CoreHasFormat(config.cfg, core, format))
+    return -EFAULT;
+
+  /* check that core has PP */
+  if(!CoreHasFormat(config.cfg, core, DWL_CLIENT_TYPE_PP))
+    return -EFAULT;
+
+  /* reserve a core */
+  if (down_interruptible(&dec_core_sem))
+    return -ERESTARTSYS;
+
+  /* wait until the core is available */
+  if(wait_event_interruptible(hw_queue,
+                              GetDecCore(core, dev, filp, format) != 0)) {
+    up(&dec_core_sem);
+    return -ERESTARTSYS;
+  }
+
+  if (down_interruptible(&pp_core_sem)) {
+    ReleaseDecoder(dev, core);
+    return -ERESTARTSYS;
+  }
+
+  spin_lock_irqsave(&owner_lock, flags);
+  pp_owner[core] = filp;
+  spin_unlock_irqrestore(&owner_lock, flags);
+
+  return core;
+}
+
+#ifdef HANTRODEC_DEBUG
+static u32 flush_count = 0; /* times of calling of DecFlushRegs */
+static u32 flush_regs = 0;  /* total number of registers flushed */
+#endif
+
+long DecFlushRegs(hantrodec_t *dev, struct core_desc *core) {
+  long ret = 0, i;
+#ifdef HANTRODEC_DEBUG
+  int reg_wr = 2;
+#endif
+  u32 id = core->id;
+  u32 type = core->type;
+
+  PDEBUG("hantrodec: DecFlushRegs\n");
+  PDEBUG("hantrodec: id = %d, type = %d, size = %d, reg_id = %d\n",
+                    core->id, core->type, core->size, core->reg_id);
+
+  if (type == HW_VC8000D && !vpu_subsys[id].submodule_hwregs[type])
+    type = HW_VC8000DJ;
+  if (dev->client_type[id] == DWL_CLIENT_TYPE_BO_AV1_DEC)
+    type = HW_BIGOCEAN;
+
+  if (id >= MAX_SUBSYS_NUM ||
+      !vpu_subsys[id].base_addr ||
+      core->type >= HW_CORE_MAX ||
+      !vpu_subsys[id].submodule_hwregs[type])
+    return -EINVAL;
+
+  PDEBUG("hantrodec: submodule_iosize = %d\n", vpu_subsys[id].submodule_iosize[type]);
+
+  ret = copy_from_user(dec_regs[id], core->regs, vpu_subsys[id].submodule_iosize[type]);
+  if (ret) {
+    PDEBUG("copy_from_user failed, returned %li\n", ret);
+    return -EFAULT;
+  }
+
+  if (type == HW_VC8000D || type == HW_BIGOCEAN || type == HW_VC8000DJ) {
+    /* write all regs but the status reg[1] to hardware */
+    if (reg_access_opt) {
+      for(i = 3; i < vpu_subsys[id].submodule_iosize[type]/4; i++) {
+        /* check whether register value is updated. */
+        if (dec_regs[id][i] != shadow_dec_regs[id][i]) {
+          iowrite32(dec_regs[id][i], (void*)(dev->hwregs[id][type] + i*4));
+          shadow_dec_regs[id][i] = dec_regs[id][i];
+#ifdef HANTRODEC_DEBUG
+          reg_wr++;
+#endif
+        }
+      }
+    } else {
+      for(i = 3; i < vpu_subsys[id].submodule_iosize[type]/4; i++) {
+        iowrite32(dec_regs[id][i], (void*)(dev->hwregs[id][type] + i*4));
+#ifdef VALIDATE_REGS_WRITE
+        if (dec_regs[id][i] != ioread32((void*)(dev->hwregs[id][type] + i*4)))
+          pr_info("hantrodec: swreg[%ld]: read %08x != write %08x *\n",
+                 i, ioread32((void*)(dev->hwregs[id][type] + i*4)), dec_regs[id][i]);
+#endif
+      }
+#ifdef HANTRODEC_DEBUG
+      reg_wr = vpu_subsys[id].submodule_iosize[type]/4 - 1;
+#endif
+    }
+
+    /* write swreg2 for AV1, in which bit0 is the start bit */
+    iowrite32(dec_regs[id][2], (void*)(dev->hwregs[id][type] + 8));
+    shadow_dec_regs[id][2] = dec_regs[id][2];
+
+    /* write the status register, which may start the decoder */
+    iowrite32(dec_regs[id][1], (void*)(dev->hwregs[id][type] + 4));
+    shadow_dec_regs[id][1] = dec_regs[id][1];
+
+#ifdef HANTRODEC_DEBUG
+    flush_count++;
+    flush_regs += reg_wr;
+#endif
+
+    PDEBUG("flushed registers on core %d\n", id);
+    PDEBUG("%d DecFlushRegs: flushed %d/%d registers (dec_mode = %d, avg %d regs per flush)\n",
+           flush_count, reg_wr, flush_regs, dec_regs[id][3]>>27, flush_regs/flush_count);
+  } else {
+    /* write all regs but the status reg[1] to hardware */
+    for(i = 0; i < vpu_subsys[id].submodule_iosize[type]/4; i++) {
+      iowrite32(dec_regs[id][i], (void*)(dev->hwregs[id][type] + i*4));
+#ifdef VALIDATE_REGS_WRITE
+      if (dec_regs[id][i] != ioread32((void*)(dev->hwregs[id][type] + i*4)))
+        pr_info("hantrodec: swreg[%ld]: read %08x != write %08x *\n",
+               i, ioread32((void*)(dev->hwregs[id][type] + i*4)), dec_regs[id][i]);
+#endif
+    }
+  }
+
+  return 0;
+}
+
+
+long DecWriteRegs(hantrodec_t *dev, struct core_desc *core)
+{
+  long ret = 0;
+  u32 i = core->reg_id;
+  u32 id = core->id;
+  u32 type = core->type;
+
+  PDEBUG("hantrodec: DecWriteRegs\n");
+  PDEBUG("hantrodec: id = %d, type = %d, size = %d, reg_id = %d\n",
+          core->id, core->type, core->size, core->reg_id);
+
+  if (type == HW_VC8000D && !vpu_subsys[id].submodule_hwregs[type])
+    type = HW_VC8000DJ;
+  if (dev->client_type[id] == DWL_CLIENT_TYPE_BO_AV1_DEC)
+    type = HW_BIGOCEAN;
+
+  if (id >= MAX_SUBSYS_NUM ||
+      !vpu_subsys[id].base_addr ||
+      type >= HW_CORE_MAX ||
+      !vpu_subsys[id].submodule_hwregs[type] ||
+      (core->size & 0x3) ||
+      core->reg_id * 4 + core->size > vpu_subsys[id].submodule_iosize[type])
+    return -EINVAL;
+
+  ret = copy_from_user(dec_regs[id], core->regs, core->size);
+  if (ret) {
+    PDEBUG("copy_from_user failed, returned %li\n", ret);
+    return -EFAULT;
+  }
+
+  for (i = core->reg_id; i < core->reg_id + core->size/4; i++) {
+    PDEBUG("hantrodec: write %08x to reg[%d] core %d\n", dec_regs[id][i-core->reg_id], i, id);
+    iowrite32(dec_regs[id][i-core->reg_id], (void*)(dev->hwregs[id][type] + i*4));
+    if (type == HW_VC8000D)
+      shadow_dec_regs[id][i] = dec_regs[id][i-core->reg_id];
+  }
+  return 0;
+}
+
+long DecWriteApbFilterRegs(hantrodec_t *dev, struct core_desc *core)
+{
+  long ret = 0;
+  u32 i = core->reg_id;
+  u32 id = core->id;
+
+  PDEBUG("hantrodec: DecWriteApbFilterRegs\n");
+  PDEBUG("hantrodec: id = %d, type = %d, size = %d, reg_id = %d\n",
+          core->id, core->type, core->size, core->reg_id);
+
+  if (id >= MAX_SUBSYS_NUM ||
+      !vpu_subsys[id].base_addr ||
+      core->type >= HW_CORE_MAX ||
+      !vpu_subsys[id].submodule_hwregs[core->type] ||
+      (core->size & 0x3) ||
+      core->reg_id * 4 + core->size > vpu_subsys[id].submodule_iosize[core->type] + 4)
+    return -EINVAL;
+
+  ret = copy_from_user(apbfilter_regs[id], core->regs, core->size);
+  if (ret) {
+    PDEBUG("copy_from_user failed, returned %li\n", ret);
+    return -EFAULT;
+  }
+
+  for (i = core->reg_id; i < core->reg_id + core->size/4; i++) {
+    PDEBUG("hantrodec: write %08x to reg[%d] core %d\n", dec_regs[id][i-core->reg_id], i, id);
+    iowrite32(apbfilter_regs[id][i-core->reg_id], (void*)(dev->apbfilter_hwregs[id][core->type] + i*4));
+  }
+  return 0;
+}
+
+long DecReadRegs(hantrodec_t *dev, struct core_desc *core)
+{
+  long ret;
+  u32 id = core->id;
+  u32 i = core->reg_id;
+  u32 type = core->type;
+
+  PDEBUG("hantrodec: DecReadRegs\n");
+  PDEBUG("hantrodec: id = %d, type = %d, size = %d, reg_id = %d\n",
+          core->id, core->type, core->size, core->reg_id);
+
+  if (type == HW_VC8000D && !vpu_subsys[id].submodule_hwregs[type])
+    type = HW_VC8000DJ;
+  if (dev->client_type[id] == DWL_CLIENT_TYPE_BO_AV1_DEC)
+    type = HW_BIGOCEAN;
+
+  if (id >= MAX_SUBSYS_NUM ||
+      !vpu_subsys[id].base_addr ||
+      type >= HW_CORE_MAX ||
+      !vpu_subsys[id].submodule_hwregs[type] ||
+      (core->size & 0x3) ||
+      core->reg_id * 4 + core->size > vpu_subsys[id].submodule_iosize[type])
+    return -EINVAL;
+
+  /* read specific registers from hardware */
+  for (i = core->reg_id; i < core->reg_id + core->size/4; i++) {
+    dec_regs[id][i-core->reg_id] = ioread32((void*)(dev->hwregs[id][type] + i*4));
+    PDEBUG("hantrodec: read %08x from reg[%d] core %d\n", dec_regs[id][i-core->reg_id], i, id);
+    if (type == HW_VC8000D)
+      shadow_dec_regs[id][i] = dec_regs[id][i];
+  }
+
+  /* put registers to user space*/
+  ret = copy_to_user(core->regs, dec_regs[id], core->size);
+  if (ret) {
+    PDEBUG("copy_to_user failed, returned %li\n", ret);
+    return -EFAULT;
+  }
+  return 0;
+}
+
+long DecRefreshRegs(hantrodec_t *dev, struct core_desc *core) 
+{
+  long ret, i;
+  u32 id = core->id;
+  u32 type = core->type;
+
+  PDEBUG("hantrodec: DecRefreshRegs\n");
+  PDEBUG("hantrodec: id = %d, type = %d, size = %d, reg_id = %d\n",
+                    core->id, core->type, core->size, core->reg_id);
+
+  if (type == HW_VC8000D && !vpu_subsys[id].submodule_hwregs[type])
+    type = HW_VC8000DJ;
+  if (dev->client_type[id] == DWL_CLIENT_TYPE_BO_AV1_DEC)
+    type = HW_BIGOCEAN;
+
+  if (id >= MAX_SUBSYS_NUM ||
+      !vpu_subsys[id].base_addr ||
+      type >= HW_CORE_MAX ||
+      !vpu_subsys[id].submodule_hwregs[type])
+    return -EINVAL;
+
+  PDEBUG("hantrodec: submodule_iosize = %d\n", vpu_subsys[id].submodule_iosize[type]);
+
+  if (!reg_access_opt) {
+    for(i = 0; i < vpu_subsys[id].submodule_iosize[type]/4; i++) {
+      dec_regs[id][i] = ioread32((void*)(dev->hwregs[id][type] + i*4));
+    }
+  } else {
+    // only need to read swreg1,62(?),63,168,169
+#define REFRESH_REG(idx) i = (idx); shadow_dec_regs[id][i] = dec_regs[id][i] = ioread32((void*)(dev->hwregs[id][type] + i*4))
+    REFRESH_REG(0);
+    REFRESH_REG(1);
+    REFRESH_REG(62);
+    REFRESH_REG(63);
+    REFRESH_REG(168);
+    REFRESH_REG(169);
+#undef REFRESH_REG
+  }
+
+  ret = copy_to_user(core->regs, dec_regs[id], vpu_subsys[id].submodule_iosize[type]);
+  if (ret) {
+    PDEBUG("copy_to_user failed, returned %li\n", ret);
+    return -EFAULT;
+  }
+  return 0;
+}
+
+static int CheckDecIrq(hantrodec_t *dev, int id) {
+  unsigned long flags;
+  int rdy = 0;
+
+  const u32 irq_mask = (1 << id);
+
+  spin_lock_irqsave(&owner_lock, flags);
+
+  if(dec_irq & irq_mask) {
+    /* reset the wait condition(s) */
+    dec_irq &= ~irq_mask;
+    rdy = 1;
+  }
+
+  spin_unlock_irqrestore(&owner_lock, flags);
+
+  return rdy;
+}
+
+long WaitDecReadyAndRefreshRegs(hantrodec_t *dev, struct core_desc *core) {
+  u32 id = core->id;
+  long ret;
+
+  PDEBUG("wait_event_interruptible DEC[%d]\n", id);
+#ifdef USE_SW_TIMEOUT
+  u32 status;
+  ret = wait_event_interruptible_timeout(dec_wait_queue, CheckDecIrq(dev, id), msecs_to_jiffies(2000));
+  if(ret < 0) {
+    PDEBUG("DEC[%d]  wait_event_interruptible interrupted\n", id);
+    return -ERESTARTSYS;
+  } else if (ret == 0) {
+    PDEBUG("DEC[%d]  wait_event_interruptible timeout\n", id);
+    status = ioread32((void*)(dev->hwregs[id][HW_VC8000D] + HANTRODEC_IRQ_STAT_DEC_OFF));
+    /* check if HW is enabled */
+    if(status & HANTRODEC_DEC_E) {
+      pr_info("hantrodec: DEC[%d] reset becuase of timeout\n", id);
+
+      /* abort decoder */
+      status |= HANTRODEC_DEC_ABORT | HANTRODEC_DEC_IRQ_DISABLE;
+      iowrite32(status, (void*)(dev->hwregs[id][HW_VC8000D] + HANTRODEC_IRQ_STAT_DEC_OFF));
+    }
+  }
+#else
+  ret = wait_event_interruptible(dec_wait_queue, CheckDecIrq(dev, id));
+  if(ret) {
+    PDEBUG("DEC[%d]  wait_event_interruptible interrupted\n", id);
+    return -ERESTARTSYS;
+  }
+#endif
+  atomic_inc(&irq_tx);
+
+  /* refresh registers */
+  return DecRefreshRegs(dev, core);
+}
+
+#if 0
+long PPFlushRegs(hantrodec_t *dev, struct core_desc *core) {
+  long ret = 0;
+  u32 id = core->id;
+  u32 i;
+
+  /* copy original dec regs to kernal space*/
+  ret = copy_from_user(dec_regs[id] + HANTRO_PP_ORG_FIRST_REG,
+                       core->regs + HANTRO_PP_ORG_FIRST_REG,
+                       HANTRO_PP_ORG_REGS*4);
+  if (sizeof(void *) == 8) {
+    /* copy extended dec regs to kernal space*/
+    ret = copy_from_user(dec_regs[id] + HANTRO_PP_EXT_FIRST_REG,
+                         core->regs + HANTRO_PP_EXT_FIRST_REG,
+                         HANTRO_PP_EXT_REGS*4);
+  }
+  if (ret) {
+    PDEBUG("copy_from_user failed, returned %li\n", ret);
+    return -EFAULT;
+  }
+
+  /* write all regs but the status reg[1] to hardware */
+  /* both original and extended regs need to be written */
+  for(i = HANTRO_PP_ORG_FIRST_REG + 1; i <= HANTRO_PP_ORG_LAST_REG; i++)
+    iowrite32(dec_regs[id][i], (void*)(dev->hwregs[id] + i*4));
+  if (sizeof(void *) == 8) {
+    for(i = HANTRO_PP_EXT_FIRST_REG; i <= HANTRO_PP_EXT_LAST_REG; i++)
+      iowrite32(dec_regs[id][i], (void*)(dev->hwregs[id] + i*4));
+  }
+  /* write the stat reg, which may start the PP */
+  iowrite32(dec_regs[id][HANTRO_PP_ORG_FIRST_REG],
+            (void*)(dev->hwregs[id] + HANTRO_PP_ORG_FIRST_REG * 4));
+
+  return 0;
+}
+
+long PPRefreshRegs(hantrodec_t *dev, struct core_desc *core) {
+  long i, ret;
+  u32 id = core->id;
+  if (sizeof(void *) == 8) {
+    /* user has to know exactly what they are asking for */
+    if(core->size != (HANTRO_PP_TOTAL_REGS * 4))
+      return -EFAULT;
+  } else {
+    /* user has to know exactly what they are asking for */
+    if(core->size != (HANTRO_PP_ORG_REGS * 4))
+      return -EFAULT;
+  }
+
+  /* read all registers from hardware */
+  /* both original and extended regs need to be read */
+  for(i = HANTRO_PP_ORG_FIRST_REG; i <= HANTRO_PP_ORG_LAST_REG; i++)
+    dec_regs[id][i] = ioread32((void*)(dev->hwregs[id] + i*4));
+  if (sizeof(void *) == 8) {
+    for(i = HANTRO_PP_EXT_FIRST_REG; i <= HANTRO_PP_EXT_LAST_REG; i++)
+      dec_regs[id][i] = ioread32((void*)(dev->hwregs[id] + i*4));
+  }
+  /* put registers to user space*/
+  /* put original registers to user space*/
+  ret = copy_to_user(core->regs + HANTRO_PP_ORG_FIRST_REG,
+                     dec_regs[id] + HANTRO_PP_ORG_FIRST_REG,
+                     HANTRO_PP_ORG_REGS*4);
+  if (sizeof(void *) == 8) {
+    /* put extended registers to user space*/
+    ret = copy_to_user(core->regs + HANTRO_PP_EXT_FIRST_REG,
+                       dec_regs[id] + HANTRO_PP_EXT_FIRST_REG,
+                       HANTRO_PP_EXT_REGS * 4);
+  }
+  if (ret) {
+    PDEBUG("copy_to_user failed, returned %li\n", ret);
+    return -EFAULT;
+  }
+
+  return 0;
+}
+
+static int CheckPPIrq(hantrodec_t *dev, int id) {
+  unsigned long flags;
+  int rdy = 0;
+
+  const u32 irq_mask = (1 << id);
+
+  spin_lock_irqsave(&owner_lock, flags);
+
+  if(pp_irq & irq_mask) {
+    /* reset the wait condition(s) */
+    pp_irq &= ~irq_mask;
+    rdy = 1;
+  }
+
+  spin_unlock_irqrestore(&owner_lock, flags);
+
+  return rdy;
+}
+
+long WaitPPReadyAndRefreshRegs(hantrodec_t *dev, struct core_desc *core) {
+  u32 id = core->id;
+
+  PDEBUG("wait_event_interruptible PP[%d]\n", id);
+
+  if(wait_event_interruptible(pp_wait_queue, CheckPPIrq(dev, id))) {
+    PDEBUG("PP[%d]  wait_event_interruptible interrupted\n", id);
+    return -ERESTARTSYS;
+  }
+
+  atomic_inc(&irq_tx);
+
+  /* refresh registers */
+  return PPRefreshRegs(dev, core);
+}
+#endif
+
+static int CheckCoreIrq(hantrodec_t *dev, const struct file *filp, int *id) {
+  unsigned long flags;
+  int rdy = 0, n = 0;
+
+  do {
+    u32 irq_mask = (1 << n);
+
+    spin_lock_irqsave(&owner_lock, flags);
+
+    if(dec_irq & irq_mask) {
+      if (dec_owner[n] == filp) {
+        /* we have an IRQ for our client */
+
+        /* reset the wait condition(s) */
+        dec_irq &= ~irq_mask;
+
+        /* signal ready core no. for our client */
+        *id = n;
+
+        rdy = 1;
+
+        spin_unlock_irqrestore(&owner_lock, flags);
+        break;
+      } else if(dec_owner[n] == NULL) {
+        /* zombie IRQ */
+        pr_info("IRQ on core[%d], but no owner!!!\n", n);
+
+        /* reset the wait condition(s) */
+        dec_irq &= ~irq_mask;
+      }
+    }
+
+    spin_unlock_irqrestore(&owner_lock, flags);
+
+    n++; /* next core */
+  } while(n < dev->cores);
+
+  return rdy;
+}
+
+long WaitCoreReady(hantrodec_t *dev, const struct file *filp, int *id) {
+  long ret;
+  PDEBUG("wait_event_interruptible CORE\n");
+#ifdef USE_SW_TIMEOUT
+  u32 i, status;
+  ret = wait_event_interruptible_timeout(dec_wait_queue, CheckCoreIrq(dev, filp, id), msecs_to_jiffies(2000));
+  if(ret < 0) {
+    PDEBUG("CORE  wait_event_interruptible interrupted\n");
+    return -ERESTARTSYS;
+  } else if (ret == 0) {
+    PDEBUG("CORE  wait_event_interruptible timeout\n");
+    for(i = 0; i < dev->cores; i++) {
+      status = ioread32((void*)(dev->hwregs[i][HW_VC8000D] + HANTRODEC_IRQ_STAT_DEC_OFF));
+      /* check if HW is enabled */
+      if((status & HANTRODEC_DEC_E) && dec_owner[i] == filp) {
+        pr_info("hantrodec: CORE[%d] reset becuase of timeout\n", i);
+        *id = i;
+        /* abort decoder */
+        status |= HANTRODEC_DEC_ABORT | HANTRODEC_DEC_IRQ_DISABLE;
+        iowrite32(status, (void*)(dev->hwregs[i][HW_VC8000D] + HANTRODEC_IRQ_STAT_DEC_OFF));
+        break;
+      }
+    }
+  }
+#else
+  ret = wait_event_interruptible(dec_wait_queue, CheckCoreIrq(dev, filp, id));
+  if(ret) {
+    PDEBUG("CORE[%d] wait_event_interruptible interrupted with 0x%x\n", *id, ret);
+    return -ERESTARTSYS;
+  }
+#endif
+  atomic_inc(&irq_tx);
+
+  return 0;
+}
+
+/*------------------------------------------------------------------------------
+ Function name   : hantrodec_ioctl
+ Description     : communication method to/from the user space
+
+ Return type     : long
+------------------------------------------------------------------------------*/
+
+static long hantrodec_ioctl(struct file *filp, unsigned int cmd,
+                            unsigned long arg) {
+  int err = 0;
+  long tmp;
+  u32 i = 0;
+#ifdef CLK_CFG
+  unsigned long flags;
+#endif
+
+#ifdef HW_PERFORMANCE
+  struct timeval *end_time_arg;
+#endif
+
+  PDEBUG("ioctl cmd 0x%08x\n", cmd);
+  /*
+   * extract the type and number bitfields, and don't decode
+   * wrong cmds: return ENOTTY (inappropriate ioctl) before access_ok()
+   */
+  if (_IOC_TYPE(cmd) != HANTRODEC_IOC_MAGIC &&
+      _IOC_TYPE(cmd) != HANTRO_IOC_MMU &&
+      _IOC_TYPE(cmd) != MEMORY_IOC_MAGIC &&
+      _IOC_TYPE(cmd) != HANTRO_VCMD_IOC_MAGIC)
+    return -ENOTTY;
+  if ((_IOC_TYPE(cmd) == HANTRODEC_IOC_MAGIC &&
+      _IOC_NR(cmd) > HANTRODEC_IOC_MAXNR) ||
+      (_IOC_TYPE(cmd) == HANTRO_IOC_MMU &&
+      _IOC_NR(cmd) > HANTRO_IOC_MMU_MAXNR) ||
+      (_IOC_TYPE(cmd) == MEMORY_IOC_MAGIC &&
+      _IOC_NR(cmd) > MEMORY_IOC_MAXNR) ||
+      (_IOC_TYPE(cmd) == HANTRO_VCMD_IOC_MAGIC &&
+      _IOC_NR(cmd) > HANTRO_VCMD_IOC_MAXNR))
+    return -ENOTTY;
+  /*
+   * the direction is a bitmask, and VERIFY_WRITE catches R/W
+   * transfers. `Type' is user-oriented, while
+   * access_ok is kernel-oriented, so the concept of "read" and
+   * "write" is reversed
+   */
+  if (_IOC_DIR(cmd) & _IOC_READ)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,0,0)
+    err = !access_ok((void *) arg, _IOC_SIZE(cmd));
+#else
+    err = !access_ok(VERIFY_WRITE, (void *) arg, _IOC_SIZE(cmd));
+#endif
+  else if (_IOC_DIR(cmd) & _IOC_WRITE)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,0,0)
+    err = !access_ok((void *) arg, _IOC_SIZE(cmd));
+#else
+    err = !access_ok(VERIFY_READ, (void *) arg, _IOC_SIZE(cmd));
+#endif
+
+  if (err)
+    return -EFAULT;
+
+#ifdef CLK_CFG
+  spin_lock_irqsave(&clk_lock, flags);
+  if (clk_cfg!=NULL && !IS_ERR(clk_cfg)&&(is_clk_on==0)) {
+    printk("turn on clock by user\n");
+    if (clk_enable(clk_cfg)) {
+      spin_unlock_irqrestore(&clk_lock, flags);
+      return -EFAULT;
+    } else
+      is_clk_on=1;
+  }
+  spin_unlock_irqrestore(&clk_lock, flags);
+  mod_timer(&timer, jiffies + 10*HZ); /*the interval is 10s*/
+#endif
+
+  switch (cmd) {
+  case HANTRODEC_IOC_CLI: {
+    __u32 id;
+    __get_user(id, (__u32*)arg);
+
+    if(id >= hantrodec_data.cores) {
+      return -EFAULT;
+    }
+    disable_irq(hantrodec_data.irq[id]);
+    break;
+  }
+  case HANTRODEC_IOC_STI: {
+    __u32 id;
+    __get_user(id, (__u32*)arg);
+
+    if(id >= hantrodec_data.cores) {
+      return -EFAULT;
+    }
+    enable_irq(hantrodec_data.irq[id]);
+    break;
+  }
+  case HANTRODEC_IOCGHWOFFSET: {
+    __u32 id;
+    __get_user(id, (__u32*)arg);
+
+    if(id >= hantrodec_data.cores) {
+      return -EFAULT;
+    }
+
+    __put_user(multicorebase_actual[id], (unsigned long *) arg);
+    break;
+  }
+  case HANTRODEC_IOCGHWIOSIZE: {
+    struct regsize_desc core;
+    pm_runtime_resume_and_get(&hantrodec_data.pdev->dev);
+    /* get registers from user space*/
+    tmp = copy_from_user(&core, (void*)arg, sizeof(struct regsize_desc));
+    if (tmp) {
+      PDEBUG("copy_from_user failed, returned %li\n", tmp);
+      pm_runtime_mark_last_busy(&hantrodec_data.pdev->dev);
+      pm_runtime_put_autosuspend(&hantrodec_data.pdev->dev);
+      return -EFAULT;
+    }
+
+    if(core.id >= MAX_SUBSYS_NUM /*hantrodec_data.cores*/) {
+      pm_runtime_mark_last_busy(&hantrodec_data.pdev->dev);
+      pm_runtime_put_autosuspend(&hantrodec_data.pdev->dev);
+      return -EFAULT;
+    }
+
+    if (core.type == HW_SHAPER) {
+      u32 asic_id;
+      /* Shaper is configured with l2cache. */
+      if (vpu_subsys[core.id].submodule_hwregs[HW_L2CACHE]) {
+        asic_id = ioread32((void*)vpu_subsys[core.id].submodule_hwregs[HW_L2CACHE]);
+        switch ((asic_id >> 16) & 0x3) {
+        case 1: /* cache only */
+          core.size = 0; break;
+        case 0: /* cache + shaper */
+        case 2: /* shaper only*/
+          core.size = vpu_subsys[core.id].submodule_iosize[HW_L2CACHE];
+          break;
+        default:
+          pm_runtime_mark_last_busy(&hantrodec_data.pdev->dev);
+          pm_runtime_put_autosuspend(&hantrodec_data.pdev->dev);
+          return -EFAULT;
+        }
+      } else
+        core.size = 0;
+    } else {
+      core.size = vpu_subsys[core.id].submodule_iosize[core.type];
+      if (core.type == HW_VC8000D && !core.size &&
+          vpu_subsys[core.id].submodule_hwregs[HW_VC8000DJ]) {
+        /* If VC8000D doesn't exists, while VC8000DJ exists, return VC8000DJ. */
+        core.size = vpu_subsys[core.id].submodule_iosize[HW_VC8000DJ];
+      }
+    }
+    copy_to_user((u32 *) arg, &core, sizeof(struct regsize_desc));
+    pm_runtime_mark_last_busy(&hantrodec_data.pdev->dev);
+    pm_runtime_put_autosuspend(&hantrodec_data.pdev->dev);
+
+    return 0;
+  }
+  case HANTRODEC_IOC_MC_OFFSETS: {
+    tmp = copy_to_user((unsigned long *) arg, multicorebase_actual, sizeof(multicorebase_actual));
+    if (err) {
+      PDEBUG("copy_to_user failed, returned %li\n", tmp);
+      return -EFAULT;
+    }
+    break;
+  }
+  case HANTRODEC_IOC_MC_CORES:
+    __put_user(hantrodec_data.cores, (unsigned int *) arg);
+    PDEBUG("hantrodec_data.cores=%d\n", hantrodec_data.cores);
+    break;
+  case HANTRODEC_IOCS_DEC_PUSH_REG: {
+    struct core_desc core;
+
+    /* get registers from user space*/
+    tmp = copy_from_user(&core, (void*)arg, sizeof(struct core_desc));
+    if (tmp) {
+      PDEBUG("copy_from_user failed, returned %li\n", tmp);
+      return -EFAULT;
+    }
+
+    return DecFlushRegs(&hantrodec_data, &core);
+  }
+  case HANTRODEC_IOCS_DEC_WRITE_REG: {
+    struct core_desc core;
+
+    /* get registers from user space*/
+    tmp = copy_from_user(&core, (void*)arg, sizeof(struct core_desc));
+    if (tmp) {
+      PDEBUG("copy_from_user failed, returned %li\n", tmp);
+      return -EFAULT;
+    }
+
+    return DecWriteRegs(&hantrodec_data, &core);
+  }
+  case HANTRODEC_IOCS_DEC_WRITE_APBFILTER_REG: {
+    struct core_desc core;
+
+    /* get registers from user space*/
+    tmp = copy_from_user(&core, (void*)arg, sizeof(struct core_desc));
+    if (tmp) {
+      PDEBUG("copy_from_user failed, returned %li\n", tmp);
+      return -EFAULT;
+    }
+
+    return DecWriteApbFilterRegs(&hantrodec_data, &core);
+  }
+  case HANTRODEC_IOCS_PP_PUSH_REG: {
+#if 0
+    struct core_desc core;
+
+    /* get registers from user space*/
+    tmp = copy_from_user(&core, (void*)arg, sizeof(struct core_desc));
+    if (tmp) {
+      PDEBUG("copy_from_user failed, returned %li\n", tmp);
+      return -EFAULT;
+    }
+
+    PPFlushRegs(&hantrodec_data, &core);
+#else
+    return EINVAL;
+#endif
+  }
+  case HANTRODEC_IOCS_DEC_PULL_REG: {
+	printk("%s:case HANTRODEC_IOCS_DEC_PULL_REG\n",__func__);
+    struct core_desc core;
+
+    /* get registers from user space*/
+    tmp = copy_from_user(&core, (void*)arg, sizeof(struct core_desc));
+    if (tmp) {
+      PDEBUG("copy_from_user failed, returned %li\n", tmp);
+      return -EFAULT;
+    }
+
+	printk("%s:return DecRefreshRegs!\n",__func__);
+    return DecRefreshRegs(&hantrodec_data, &core);
+  }
+  case HANTRODEC_IOCS_DEC_READ_REG: {
+    struct core_desc core;
+
+    /* get registers from user space*/
+    tmp = copy_from_user(&core, (void*)arg, sizeof(struct core_desc));
+    if (tmp) {
+      PDEBUG("copy_from_user failed, returned %li\n", tmp);
+      return -EFAULT;
+    }
+
+    return DecReadRegs(&hantrodec_data, &core);
+  }
+  case HANTRODEC_IOCS_PP_PULL_REG: {
+#if 0
+    struct core_desc core;
+
+    /* get registers from user space*/
+    tmp = copy_from_user(&core, (void*)arg, sizeof(struct core_desc));
+    if (tmp) {
+      PDEBUG("copy_from_user failed, returned %li\n", tmp);
+      return -EFAULT;
+    }
+
+    return PPRefreshRegs(&hantrodec_data, &core);
+#else
+    return EINVAL;
+#endif
+  }
+  case HANTRODEC_IOCH_DEC_RESERVE: {
+    u32 format = 0;
+    __get_user(format, (unsigned long *)arg);
+    PDEBUG("Reserve DEC core, format = %li\n", format);
+    return ReserveDecoder(&hantrodec_data, filp, format);
+  }
+  case HANTRODEC_IOCT_DEC_RELEASE: {
+    u32 core = 0;
+    __get_user(core, (unsigned long *)arg);
+    if(core >= hantrodec_data.cores || dec_owner[core] != filp) {
+      PDEBUG("bogus DEC release, core = %li\n", core);
+      return -EFAULT;
+    }
+
+    PDEBUG("Release DEC, core = %li\n", core);
+
+    ReleaseDecoder(&hantrodec_data, core);
+
+    break;
+  }
+  case HANTRODEC_IOCQ_PP_RESERVE:
+#if 0
+    return ReservePostProcessor(&hantrodec_data, filp);
+#else
+    return EINVAL;
+#endif
+  case HANTRODEC_IOCT_PP_RELEASE: {
+#if 0
+    if(arg != 0 || pp_owner[arg] != filp) {
+      PDEBUG("bogus PP release %li\n", arg);
+      return -EFAULT;
+    }
+
+    ReleasePostProcessor(&hantrodec_data, arg);
+    break;
+#else
+    return EINVAL;
+#endif
+  }
+  case HANTRODEC_IOCX_DEC_WAIT: {
+    struct core_desc core;
+
+    /* get registers from user space */
+    tmp = copy_from_user(&core, (void*)arg, sizeof(struct core_desc));
+    if (tmp) {
+      PDEBUG("copy_from_user failed, returned %li\n", tmp);
+      return -EFAULT;
+    }
+
+    return WaitDecReadyAndRefreshRegs(&hantrodec_data, &core);
+  }
+  case HANTRODEC_IOCX_PP_WAIT: {
+#if 0
+    struct core_desc core;
+
+    /* get registers from user space */
+    tmp = copy_from_user(&core, (void*)arg, sizeof(struct core_desc));
+    if (tmp) {
+      PDEBUG("copy_from_user failed, returned %li\n", tmp);
+      return -EFAULT;
+    }
+
+    return WaitPPReadyAndRefreshRegs(&hantrodec_data, &core);
+#else
+    return EINVAL;
+#endif
+  }
+  case HANTRODEC_IOCG_CORE_WAIT: {
+    int id;
+    tmp = WaitCoreReady(&hantrodec_data, filp, &id);
+    __put_user(id, (int *) arg);
+    return tmp;
+  }
+  case HANTRODEC_IOX_ASIC_ID: {
+    struct core_param core;
+
+    /* get registers from user space*/
+    tmp = copy_from_user(&core, (void*)arg, sizeof(struct core_param));
+    if (tmp) {
+      PDEBUG("copy_from_user failed, returned %li\n", tmp);
+      return -EFAULT;
+    }
+
+    if (core.id >= MAX_SUBSYS_NUM /*hantrodec_data.cores*/ ||
+       ((core.type == HW_VC8000D || core.type == HW_VC8000DJ) &&
+        !vpu_subsys[core.id].submodule_iosize[core.type == HW_VC8000D] &&
+        !vpu_subsys[core.id].submodule_iosize[core.type == HW_VC8000DJ]) ||
+       ((core.type != HW_VC8000D && core.type != HW_VC8000DJ) &&
+        !vpu_subsys[core.id].submodule_iosize[core.type])) {
+      return -EFAULT;
+    }
+
+    core.size = vpu_subsys[core.id].submodule_iosize[core.type];
+    if (vpu_subsys[core.id].submodule_hwregs[core.type])
+      core.asic_id = ioread32((void*)hantrodec_data.hwregs[core.id][core.type]);
+    else if (core.type == HW_VC8000D &&
+             hantrodec_data.hwregs[core.id][HW_VC8000DJ]) {
+      core.asic_id = ioread32((void*)hantrodec_data.hwregs[core.id][HW_VC8000DJ]);
+    } else
+      core.asic_id = 0;
+    copy_to_user((u32 *) arg, &core, sizeof(struct core_param));
+
+    return 0;
+  }
+  case HANTRODEC_IOCG_CORE_ID: {
+    u32 format = 0;
+    __get_user(format, (unsigned long *)arg);
+
+    PDEBUG("Get DEC Core_id, format = %li\n", format);
+    return GetDecCoreID(&hantrodec_data, filp, format);
+  }
+  case HANTRODEC_IOX_ASIC_BUILD_ID: {
+    u32 id, hw_id;
+    __get_user(id, (u32*)arg);
+
+    if(id >= hantrodec_data.cores) {
+      return -EFAULT;
+    }
+    if (hantrodec_data.hwregs[id][HW_VC8000D] ||
+        hantrodec_data.hwregs[id][HW_VC8000DJ]) {
+      volatile u8 *hwregs;
+      /* VC8000D first if it exists, otherwise VC8000DJ. */
+      if (hantrodec_data.hwregs[id][HW_VC8000D])
+        hwregs = hantrodec_data.hwregs[id][HW_VC8000D];
+      else
+        hwregs = hantrodec_data.hwregs[id][HW_VC8000DJ];
+      hw_id = ioread32((void*)hwregs);
+      if (IS_G1(hw_id >> 16) || IS_G2(hw_id >> 16) ||
+          (IS_VC8000D(hw_id >> 16) && ((hw_id & 0xFFFF) == 0x6010)))
+        __put_user(hw_id, (u32 *) arg);
+      else {
+        hw_id = ioread32((void*)(hwregs + HANTRODEC_HW_BUILD_ID_OFF));
+        __put_user(hw_id, (u32 *) arg);
+      }
+    } else if (hantrodec_data.hwregs[id][HW_BIGOCEAN]) {
+      hw_id = ioread32((void*)(hantrodec_data.hwregs[id][HW_BIGOCEAN]));
+      if (IS_BIGOCEAN(hw_id >> 16))
+        __put_user(hw_id, (u32 *) arg);
+      else
+        return -EFAULT;
+    }
+    return 0;
+  }
+  case HANTRODEC_DEBUG_STATUS: {
+    pr_info("hantrodec: dec_irq     = 0x%08x \n", dec_irq);
+    pr_info("hantrodec: pp_irq      = 0x%08x \n", pp_irq);
+
+    pr_info("hantrodec: IRQs received/sent2user = %d / %d \n",
+           atomic_read(&irq_rx), atomic_read(&irq_tx));
+
+    for (tmp = 0; tmp < hantrodec_data.cores; tmp++) {
+      pr_info("hantrodec: dec_core[%li] %s\n",
+             tmp, dec_owner[tmp] == NULL ? "FREE" : "RESERVED");
+      pr_info("hantrodec: pp_core[%li]  %s\n",
+             tmp, pp_owner[tmp] == NULL ? "FREE" : "RESERVED");
+    }
+    return 0;
+  }
+  case HANTRODEC_IOX_SUBSYS: {
+    struct subsys_desc subsys = {0};
+    /* TODO(min): check all the subsys */
+    pm_runtime_resume_and_get(&hantrodec_data.pdev->dev);
+    if (vcmd) {
+      subsys.subsys_vcmd_num = 1;
+      subsys.subsys_num = subsys.subsys_vcmd_num;
+    } else {
+      subsys.subsys_num = hantrodec_data.cores;
+      subsys.subsys_vcmd_num = 0;
+    }
+    copy_to_user((u32 *) arg, &subsys, sizeof(struct subsys_desc));
+    pm_runtime_mark_last_busy(&hantrodec_data.pdev->dev);
+    pm_runtime_put_autosuspend(&hantrodec_data.pdev->dev);
+    return 0;
+  }
+  case HANTRODEC_IOCX_POLL: {
+    hantrodec_isr(0, &hantrodec_data);
+    return 0;
+  }
+  case HANTRODEC_IOC_APBFILTER_CONFIG: {
+    struct apbfilter_cfg tmp_apbfilter;
+
+    /* get registers from user space*/
+    tmp = copy_from_user(&tmp_apbfilter, (void*)arg, sizeof(struct apbfilter_cfg));
+    if (tmp) {
+      PDEBUG("copy_from_user failed, returned %li\n", tmp);
+      return -EFAULT;
+    }
+
+    if(tmp_apbfilter.id >= MAX_SUBSYS_NUM || tmp_apbfilter.type >= HW_CORE_MAX) {
+      return -EFAULT;
+    }
+
+    apbfilter_cfg[tmp_apbfilter.id][tmp_apbfilter.type].id = tmp_apbfilter.id;
+    apbfilter_cfg[tmp_apbfilter.id][tmp_apbfilter.type].type = tmp_apbfilter.type;
+
+    memcpy(&tmp_apbfilter, &(apbfilter_cfg[tmp_apbfilter.id][tmp_apbfilter.type]), sizeof(struct apbfilter_cfg));
+
+    copy_to_user((u32 *) arg, &tmp_apbfilter, sizeof(struct apbfilter_cfg));
+
+    return 0;
+  }
+  case HANTRODEC_IOC_AXIFE_CONFIG: {
+    struct axife_cfg tmp_axife;
+
+    /* get registers from user space*/
+    tmp = copy_from_user(&tmp_axife, (void*)arg, sizeof(struct axife_cfg));
+    if (tmp) {
+      PDEBUG("copy_from_user failed, returned %li\n", tmp);
+      return -EFAULT;
+    }
+
+    if(tmp_axife.id >= MAX_SUBSYS_NUM) {
+      return -EFAULT;
+    }
+
+    axife_cfg[tmp_axife.id].id = tmp_axife.id;
+
+    memcpy(&tmp_axife, &(axife_cfg[tmp_axife.id]), sizeof(struct axife_cfg));
+
+    copy_to_user((u32 *) arg, &tmp_axife, sizeof(struct axife_cfg));
+
+    return 0;
+  }
+  default: {
+    if(_IOC_TYPE(cmd) == HANTRO_IOC_MMU) {
+      volatile u8* mmu_hwregs[MAX_SUBSYS_NUM][2];
+      for (i = 0; i < MAX_SUBSYS_NUM; i++ ) {
+         mmu_hwregs[i][0] = hantrodec_data.hwregs[i][HW_MMU];
+         mmu_hwregs[i][1] = hantrodec_data.hwregs[i][HW_MMU_WR];
+      }
+      pm_runtime_resume_and_get(&hantrodec_data.pdev->dev);
+      long retval = MMUIoctl(cmd, filp, arg, mmu_hwregs);
+      pm_runtime_mark_last_busy(&hantrodec_data.pdev->dev);
+      pm_runtime_put_autosuspend(&hantrodec_data.pdev->dev);
+      return retval;
+    } else if (_IOC_TYPE(cmd) == HANTRO_VCMD_IOC_MAGIC) {
+      return (hantrovcmd_ioctl(filp, cmd, arg));
+    } else if (_IOC_TYPE(cmd) == MEMORY_IOC_MAGIC) {
+      return (allocator_ioctl(filp, cmd, arg));
+    }
+    return -ENOTTY;
+  }
+  }
+  return 0;
+}
+
+/*------------------------------------------------------------------------------
+ Function name   : hantrodec_open
+ Description     : open method
+
+ Return type     : int
+------------------------------------------------------------------------------*/
+
+static int hantrodec_open(struct inode *inode, struct file *filp) {
+  PDEBUG("dev opened\n");
+  pr_debug("==========%s:open!============\n",__func__);
+  if (vcmd)
+    hantrovcmd_open(inode, filp);
+
+  allocator_open(inode, filp);
+
+  return 0;
+}
+
+/*------------------------------------------------------------------------------
+ Function name   : hantrodec_release
+ Description     : Release driver
+
+ Return type     : int
+------------------------------------------------------------------------------*/
+
+static int hantrodec_release(struct inode *inode, struct file *filp) {
+  int n;
+  hantrodec_t *dev = &hantrodec_data;
+
+  PDEBUG("closing ...\n");
+
+  if (vcmd) {
+    hantrovcmd_release(inode, filp);
+    allocator_release(inode, filp);
+    return 0;
+  }
+
+  for(n = 0; n < dev->cores; n++) {
+    if(dec_owner[n] == filp) {
+      PDEBUG("releasing dec core %i lock\n", n);
+      ReleaseDecoder(dev, n);
+    }
+  }
+
+  for(n = 0; n < 1; n++) {
+    if(pp_owner[n] == filp) {
+      PDEBUG("releasing pp core %i lock\n", n);
+      ReleasePostProcessor(dev, n);
+    }
+  }
+
+  MMURelease(filp, hantrodec_data.hwregs[0][HW_MMU]);
+  
+  allocator_release(inode, filp);
+
+  PDEBUG("closed\n");
+  return 0;
+}
+
+#ifdef CLK_CFG
+void hantrodec_disable_clk(unsigned long value) {
+  unsigned long flags;
+  /*entering this function means decoder is idle over expiry.So disable clk*/
+  if (clk_cfg!=NULL && !IS_ERR(clk_cfg)) {
+    spin_lock_irqsave(&clk_lock, flags);
+    if (is_clk_on==1) {
+      clk_disable(clk_cfg);
+      is_clk_on = 0;
+      pr_info("turned off hantrodec clk\n");
+    }
+    spin_unlock_irqrestore(&clk_lock, flags);
+  }
+}
+#endif
+
+/* VFS methods */
+static struct file_operations hantrodec_fops = {
+  .owner = THIS_MODULE,
+  .open = hantrodec_open,
+  .release = hantrodec_release,
+  .unlocked_ioctl = hantrodec_ioctl,
+  .mmap = allocator_mmap,
+  .fasync = NULL
+};
+
+static int PcieInit(void) {
+  int i;
+
+  gDev = pci_get_device(PCI_VENDOR_ID_HANTRO, PCI_DEVICE_ID_HANTRO_PCI, gDev);
+  if (NULL == gDev) {
+    pr_info("Init: Hardware not found.\n");
+    goto out;
+  }
+
+  if (0 > pci_enable_device(gDev)) {
+    pr_info("PcieInit: Device not enabled.\n");
+    goto out;
+  }
+
+  gBaseHdwr = pci_resource_start (gDev, PCI_CONTROL_BAR);
+  if (0 == gBaseHdwr) {
+    pr_info("PcieInit: Base Address not set.\n");
+    goto out_pci_disable_device;
+  }
+  pr_info("Base hw val 0x%X\n", (unsigned int)gBaseHdwr);
+
+  gBaseLen = pci_resource_len (gDev, PCI_CONTROL_BAR);
+  pr_info("Base hw len 0x%X\n", (unsigned int)gBaseLen);
+
+  for (i = 0; i < MAX_SUBSYS_NUM; i++) {
+    if (vpu_subsys[i].base_addr) {
+      vpu_subsys[i].base_addr += gBaseHdwr;
+      multicorebase[i] += gBaseHdwr;
+    }
+  }
+
+  gBaseDDRHw = pci_resource_start (gDev, PCI_DDR_BAR);
+  if (0 == gBaseDDRHw) {
+    pr_info("PcieInit: Base Address not set.\n");
+    goto out_pci_disable_device;
+  }
+  pr_info("Base memory val 0x%llx\n", (unsigned int)gBaseDDRHw);
+
+  gBaseLen = pci_resource_len (gDev, PCI_DDR_BAR);
+  pr_info("Base memory len 0x%x\n", (unsigned int)gBaseLen);
+
+  return 0;
+
+out_pci_disable_device:
+  pci_disable_device(gDev);
+
+out:
+  return -1;
+}
+
+static void dump_vpu_subsys(struct subsys_config *cfg)
+{
+	int i;
+	pr_info("lucz: dumping subsys_config[0]\n");
+	pr_info("  base_addr=0x%llx\n", cfg->base_addr);
+	if (cfg->base_addr == 0) {
+		pr_info("  base_addr=0, not dump any more\n");
+		return;
+	}
+	pr_info("  irq=%d\n", cfg->irq);
+	pr_info("  subsys_type=%u\n", cfg->subsys_type);
+	pr_info("  submodule_offset=");
+	for (i = 0; i < HW_CORE_MAX; i++) {
+		pr_info("    0x%x,", cfg->submodule_offset[i]);
+	}
+	pr_info("\n");
+	pr_info("  submodule_iosize=");
+	for (i = 0; i < HW_CORE_MAX; i++) {
+		pr_info("    %d,", cfg->submodule_iosize[i]);
+	}
+	pr_info("\n");
+	pr_info("  submodule_hwregs=");
+	for (i = 0; i < HW_CORE_MAX; i++) {
+		pr_info("    %p,", cfg->submodule_hwregs[i]);
+	}
+	pr_info("\n");
+	pr_info("  has_apbfilter=");
+	for (i = 0; i < HW_CORE_MAX; i++) {
+		pr_info("    %d,", cfg->has_apbfilter[i]);
+	}
+	pr_info("\n");
+}
+
+static ssize_t decoder_config_write(struct file *filp,
+				const char __user *userbuf,
+				size_t count, loff_t *ppos)
+{
+	hantrodec_t *dev = &hantrodec_data;
+	unsigned long value;
+	int ret;
+
+	if (count > VC8000D_MAX_CONFIG_LEN)
+		count = VC8000D_MAX_CONFIG_LEN;
+	else if (count <= 2)
+		return 0;
+
+	ret = copy_from_user(dev->config_buf, userbuf, count);
+	if (ret) {
+		ret = -EFAULT;
+		goto out;
+	}
+
+	//pr_info("hantrodec config: %s\n", dev->config_buf);
+	switch (dev->config_buf[0]) {
+		case 'd':
+			value = simple_strtoul(&(dev->config_buf[1]), NULL, 10);
+			pm_runtime_set_autosuspend_delay(&dev->pdev->dev, value);
+			pr_info("Set pm runtime auto suspend delay to %ldms\n", value);
+			break;
+		default:
+			printk(KERN_WARNING "Unsupported config!\n");
+	}
+
+out:
+	return ret < 0 ? ret : count;
+}
+
+static ssize_t decoder_config_read(struct file *filp,
+				char __user *userbuf,
+				size_t count, loff_t *ppos)
+{
+	hantrodec_t *dev = &hantrodec_data;
+	memset(dev->config_buf, 0, VC8000D_MAX_CONFIG_LEN);
+	return 0;
+}
+
+static const struct file_operations decoder_debug_ops = {
+	.write	= decoder_config_write,
+	.read	= decoder_config_read,
+	.open	= simple_open,
+	.llseek	= generic_file_llseek,
+};
+
+static int decoder_add_debugfs(struct platform_device *pdev)
+{
+	root_debugfs_dir = debugfs_create_dir("vc8000d",NULL);
+	if (!root_debugfs_dir) {
+		dev_err(&pdev->dev, "Failed to create vc8000d debugfs\n");
+		return -EINVAL;
+	}
+
+  dev_info(&pdev->dev, "Create vc8000d debugfs.\n");
+
+	debugfs_create_file("config", 0600, root_debugfs_dir,
+		&hantrodec_data, &decoder_debug_ops);
+	return 0;
+}
+
+/*------------------------------------------------------------
+platform register
+
+------------------------------------------------------------*/
+
+static const struct of_device_id isp_of_match[] = {
+	{ .compatible = "thead,light-vc8000d",  },
+	{ /* sentinel */  },
+};
+
+
+static int check_power_domain(void)
+{
+	struct device_node *dn = NULL;
+	struct property *info = NULL;
+	dn = of_find_node_by_name(NULL, "vdec");
+	if (dn != NULL)
+		info = of_find_property(dn, "power-domains", NULL);
+	pr_debug("%s, %d: power gating is %s\n", __func__, __LINE__, 
+		(info == NULL) ? "disabled" : "enabled");
+	return (info == NULL) ? 0 : 1;
+}
+
+static int decoder_runtime_suspend(struct device *dev)
+{
+	hantrodec_t *decdev = &hantrodec_data;
+
+	pr_debug("%s, %d: Disable clock\n", __func__, __LINE__);
+
+	clk_disable_unprepare(decdev->cclk);
+	clk_disable_unprepare(decdev->aclk);
+	clk_disable_unprepare(decdev->pclk);
+
+	return 0;
+}
+
+static int decoder_runtime_resume(struct device *dev)
+{
+	hantrodec_t *decdev = &hantrodec_data;
+	int ret;
+
+	ret = clk_prepare_enable(decdev->cclk);
+	if (ret < 0) {
+		dev_err(dev, "could not prepare or enable core clock\n");
+		return ret;
+	}
+
+	ret = clk_prepare_enable(decdev->aclk);
+	if (ret < 0) {
+		dev_err(dev, "could not prepare or enable axi clock\n");
+		clk_disable_unprepare(decdev->cclk);
+		return ret;
+	}
+
+	ret = clk_prepare_enable(decdev->pclk);
+	if (ret < 0) {
+		dev_err(dev, "could not prepare or enable apb clock\n");
+		clk_disable_unprepare(decdev->cclk);
+		clk_disable_unprepare(decdev->aclk);
+		return ret;
+	}
+
+	if (hantrodec_data.has_power_domains) {
+		if (hantrodec_data.hwregs[0][HW_MMU]) {
+			int i;
+			volatile u8* mmu_hwregs[MAX_SUBSYS_NUM][2];
+			for (i = 0; i < MAX_SUBSYS_NUM; i++ ) {
+				mmu_hwregs[i][0] = hantrodec_data.hwregs[i][HW_MMU];
+				mmu_hwregs[i][1] = hantrodec_data.hwregs[i][HW_MMU_WR];
+			}
+			MMURestore(mmu_hwregs);
+		}
+		hantrovcmd_reset();
+	}
+
+	pr_debug("%s, %d: Enabled clock\n", __func__, __LINE__);
+
+	return 0;
+}
+
+static int decoder_hantrodec_probe(struct platform_device *pdev)
+{
+  printk("enter %s\n",__func__);
+  printk("pcie=%d\n",pcie);
+  int result, i;
+  struct resource *mem;
+  //struct decoder_driver_device *pdriver_dev;
+  enum MMUStatus status = 0;
+  enum MMUStatus mmu_status = MMU_STATUS_FALSE;
+  volatile u8* mmu_hwregs[MAX_SUBSYS_NUM][2];
+  //pdriver_dev = devm_kzalloc(&pdev->dev,sizeof(struct decoder_driver_device),GFP_KERNEL);
+ // if(pdriver_dev == NULL)
+  //{
+//	  pr_err("%s:alloc struct deocder_driver_device error!\n",__func__);
+//	  return -ENOMEM;
+ /// }
+
+  //pdriver_dev->hantrodec_class = class_create(THIS_MODULE,"hantrodec");
+  printk("%s:init variable is ok!\n",__func__);
+  mem = platform_get_resource(pdev,IORESOURCE_MEM,0);
+  printk("%s:get resource is ok!\n",__func__);
+  //devm_ioremap_resource(&pdev->dev,mem);
+  if(mem->start)
+  	base_port = mem->start;
+  else
+	  printk("%s:mem->start is not exist!\n",__func__);
+  printk("%s:start get irq!\n",__func__);
+
+
+  PDEBUG("module init\n");
+
+  CheckSubsysCoreArray(vpu_subsys, &vcmd);
+  irq[0] = platform_get_irq(pdev,0);
+  printk("%s:get irq!\n",__func__);
+  printk("%s:base_port=0x%llx,irq=%d\n",__func__,base_port,irq[0]);
+  printk("%s:pcie=%d\n",__func__,pcie);
+
+  if (pcie) {
+    result = PcieInit();
+    if(result)
+      goto err;
+  }
+
+  pr_info("hantrodec: dec/pp kernel module. \n");
+
+  /* If base_port is set when insmod, use that for single core legacy mode. */
+  if (base_port != -1) {
+    multicorebase[0] = base_port;
+    if (pcie)
+      multicorebase[0] += HANTRO_REG_OFFSET0;
+    elements = 1;
+    vpu_subsys[0].base_addr = base_port;
+    pr_info("hantrodec: Init single core at 0x%08lx IRQ=%i\n",
+           multicorebase[0], irq[0]);
+  } else {
+    pr_info("hantrodec: Init multi core[0] at 0x%16lx\n"
+           "                      core[1] at 0x%16lx\n"
+           "                      core[2] at 0x%16lx\n"
+           "                      core[3] at 0x%16lx\n"
+           "           IRQ_0=%i\n"
+           "           IRQ_1=%i\n",
+           multicorebase[0], multicorebase[1],
+           multicorebase[2], multicorebase[3],
+           irq[0],irq[1]);
+  }
+
+  hantrodec_data.pdev = pdev;
+  hantrodec_data.cores = 0;
+
+  hantrodec_data.iosize[0] = DEC_IO_SIZE_0;
+  hantrodec_data.irq[0] = irq[0];
+  hantrodec_data.iosize[1] = DEC_IO_SIZE_1;
+  hantrodec_data.irq[1] = irq[1];
+
+  //extern void dump_core_array(void);
+  //dump_vpu_subsys(&(vpu_subsys[0]));
+  //dump_core_array();
+  pr_info("hantrodec_data.irq=%d\n",
+         hantrodec_data.irq[0]);
+
+  for(i=0; i< HXDEC_MAX_CORES; i++) {
+    int j;
+    for (j = 0; j < HW_CORE_MAX; j++)
+      hantrodec_data.hwregs[i][j] = 0;
+    /* If user gave less core bases that we have by default,
+     * invalidate default bases
+     */
+    if(elements && i>=elements) {
+      multicorebase[i] = 0;
+    }
+  }
+
+  hantrodec_data.async_queue_dec = NULL;
+  hantrodec_data.async_queue_pp = NULL;
+
+    hantrodec_data.has_power_domains = check_power_domain();
+
+    hantrodec_data.cclk = devm_clk_get(&pdev->dev, "cclk");
+    if (IS_ERR(hantrodec_data.cclk)) {
+        dev_err(&pdev->dev, "failed to get core clock\n");
+        goto err;
+    }
+
+    hantrodec_data.aclk = devm_clk_get(&pdev->dev, "aclk");
+    if (IS_ERR(hantrodec_data.aclk)) {
+        dev_err(&pdev->dev, "failed to get axi clock\n");
+        goto err;
+    }
+
+    hantrodec_data.pclk = devm_clk_get(&pdev->dev, "pclk");
+    if (IS_ERR(hantrodec_data.pclk)) {
+        dev_err(&pdev->dev, "failed to get apb clock\n");
+        goto err;
+    }
+
+    pm_runtime_set_autosuspend_delay(&pdev->dev, VC8000D_PM_TIMEOUT);
+    pm_runtime_use_autosuspend(&pdev->dev);
+    pm_runtime_enable(&pdev->dev);
+    if (!pm_runtime_enabled(&pdev->dev)) {
+      if (decoder_runtime_resume(&pdev->dev))
+      {
+        pm_runtime_disable(&pdev->dev);
+        pm_runtime_dont_use_autosuspend(&pdev->dev);
+      }
+    }
+    pm_runtime_resume_and_get(&pdev->dev);
+
+    if (hantrodec_major == 0)
+    {
+        result = alloc_chrdev_region(&hantrodec_devt, 0, 1, "hantrodec");
+        if (result != 0)
+        {
+            printk(KERN_ERR "%s: alloc_chrdev_region error\n", __func__);
+            goto err;
+        }
+        hantrodec_major = MAJOR(hantrodec_devt);
+        hantrodec_minor = MINOR(hantrodec_devt);
+    }
+    else
+    {
+        hantrodec_devt = MKDEV(hantrodec_major, hantrodec_minor);
+        result = register_chrdev_region(hantrodec_devt, 1, "hantrodec");
+        if (result)
+        {
+            printk(KERN_ERR "%s: register_chrdev_region error\n", __func__);
+            goto err;
+        }
+    }
+
+    hantrodec_class = class_create(THIS_MODULE, "hantrodec");
+    if (IS_ERR(hantrodec_class))
+    {
+        printk(KERN_ERR "%s, %d: class_create error!\n", __func__, __LINE__);
+        goto err;
+    }
+	hantrodec_devt = MKDEV(hantrodec_major, hantrodec_minor);
+
+	cdev_init(&hantrodec_cdev, &hantrodec_fops);
+	result = cdev_add(&hantrodec_cdev, hantrodec_devt, 1);
+	if ( result )
+	{
+		printk(KERN_ERR "%s, %d: cdev_add error!\n", __func__, __LINE__);
+		goto err;
+	}
+
+	device_create(hantrodec_class, NULL, hantrodec_devt,
+			NULL, "hantrodec");
+
+#ifdef CLK_CFG
+  /* first get clk instance pointer */
+  clk_cfg = clk_get(NULL, CLK_ID);
+  if (!clk_cfg||IS_ERR(clk_cfg)) {
+    printk("get handrodec clk failed!\n");
+    goto err;
+  }
+
+  /* prepare and enable clk */
+  if(clk_prepare_enable(clk_cfg)) {
+    printk("try to enable handrodec clk failed!\n");
+    goto err;
+  }
+  is_clk_on = 1;
+
+  /*init a timer to disable clk*/
+  init_timer(&timer);
+  timer.function = &hantrodec_disable_clk;
+  timer.expires =  jiffies + 100*HZ; //the expires time is 100s
+  add_timer(&timer);
+#endif
+
+  result = ReserveIO();
+  if(result < 0) {
+    goto err;
+  }
+
+  for (i = 0; i < hantrodec_data.cores; i++) {
+    AXIFEEnable(hantrodec_data.hwregs[i][HW_AXIFE]);
+  }
+
+  /* MMU only initial once No matter how many MMU we have */
+  if (hantrodec_data.hwregs[0][HW_MMU]) {
+    status = MMUInit(hantrodec_data.hwregs[0][HW_MMU]);
+    if(status == MMU_STATUS_NOT_FOUND)
+      pr_info("MMU does not exist!\n");
+    else if(status != MMU_STATUS_OK)
+      goto err;
+    else
+      pr_info("MMU detected!\n");
+
+    for (i = 0; i < MAX_SUBSYS_NUM; i++ ) {
+      mmu_hwregs[i][0] = hantrodec_data.hwregs[i][HW_MMU];
+      mmu_hwregs[i][1] = hantrodec_data.hwregs[i][HW_MMU_WR];
+    }
+    mmu_status = MMUEnable(mmu_hwregs);
+  }
+
+  allocator_init(&pdev->dev);
+
+  decoder_add_debugfs(pdev);
+
+  if (vcmd) {
+    /* unmap and release mem region for VCMD, since it will be mapped and
+       reserved again in hantro_vcmd.c*/
+    for (i = 0; i < hantrodec_data.cores; i++) {
+      if (hantrodec_data.hwregs[i][HW_VCMD]) {
+        iounmap((void *)hantrodec_data.hwregs[i][HW_VCMD]);
+        release_mem_region(vpu_subsys[i].base_addr + vpu_subsys[i].submodule_offset[HW_VCMD],
+                           vpu_subsys[i].submodule_iosize[HW_VCMD]);
+        hantrodec_data.hwregs[i][HW_VCMD] = 0;
+      }
+    }
+    result = hantrovcmd_init(pdev);
+    pm_runtime_mark_last_busy(&pdev->dev);
+    pm_runtime_put_autosuspend(&pdev->dev);
+    if (result) return result;
+
+    pr_info("PM runtime was enable\n");
+
+    return 0;
+  }
+
+  memset(dec_owner, 0, sizeof(dec_owner));
+  memset(pp_owner, 0, sizeof(pp_owner));
+
+  sema_init(&dec_core_sem, hantrodec_data.cores);
+  sema_init(&pp_core_sem, 1);
+
+  /* read configuration fo all cores */
+  ReadCoreConfig(&hantrodec_data);
+
+  /* reset hardware */
+  ResetAsic(&hantrodec_data);
+
+  /* register irq for each core */
+  if(irq[0] > 0) {
+    result = request_irq(irq[0], hantrodec_isr,
+//#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18))
+//                         SA_INTERRUPT | SA_SHIRQ,
+//#else
+//                         IRQF_SHARED,
+//#endif
+			 IRQF_TRIGGER_RISING,
+                         "hantrodec", (void *) &hantrodec_data);
+
+    if(result != 0) {
+      if(result == -EINVAL) {
+        printk(KERN_ERR "hantrodec: Bad irq number or handler\n");
+      } else if(result == -EBUSY) {
+        printk(KERN_ERR "hantrodec: IRQ <%d> busy, change your config\n",
+               hantrodec_data.irq[0]);
+      }
+
+      ReleaseIO();
+      goto err;
+    }
+  } else {
+    pr_info("hantrodec: IRQ not in use!\n");
+  }
+
+  if(irq[1] > 0) {
+    result = request_irq(irq[1], hantrodec_isr,
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18))
+                         SA_INTERRUPT | SA_SHIRQ,
+#else
+                         IRQF_SHARED,
+#endif
+                         "hantrodec", (void *) &hantrodec_data);
+
+    if(result != 0) {
+      if(result == -EINVAL) {
+        printk(KERN_ERR "hantrodec: Bad irq number or handler\n");
+      } else if(result == -EBUSY) {
+        printk(KERN_ERR "hantrodec: IRQ <%d> busy, change your config\n",
+               hantrodec_data.irq[1]);
+      }
+
+      ReleaseIO();
+      goto err;
+    }
+  } else {
+    pr_info("hantrodec: IRQ not in use!\n");
+  }
+
+  for (i = 0; i < hantrodec_data.cores; i++) {
+    volatile u8 *hwregs = hantrodec_data.hwregs[i][HW_VC8000D];
+    if (hwregs) {
+      pr_info("hantrodec: VC8000D [%d] has build id 0x%08x\n",
+             i, ioread32((void*)(hwregs + HANTRODEC_HWBUILD_ID_OFF)));
+    }
+  }
+
+  pm_runtime_mark_last_busy(&pdev->dev);
+  pm_runtime_put_autosuspend(&pdev->dev);
+  pr_info("hantrodec: module inserted. Major = %d\n", hantrodec_major);
+
+  /* Please call the TEE functions to set VC8000D DRM relative registers here */
+
+  return 0;
+
+err:
+  if (root_debugfs_dir) {
+    debugfs_remove_recursive(root_debugfs_dir);
+    root_debugfs_dir = NULL;
+  }
+  ReleaseIO();
+  pr_info("hantrodec: module not inserted\n");
+  pm_runtime_mark_last_busy(&pdev->dev);
+  pm_runtime_put_autosuspend(&pdev->dev);
+  unregister_chrdev_region(hantrodec_devt, 1);
+  return result;
+}
+
+
+static int decoder_hantrodec_remove(struct platform_device *pdev)
+{
+  if (root_debugfs_dir) {
+    debugfs_remove_recursive(root_debugfs_dir);
+    root_debugfs_dir = NULL;
+  }
+  pm_runtime_resume_and_get(&pdev->dev);
+	if(irq[0] > 0)
+	{
+		free_irq(irq[0],(void *) &hantrodec_data);
+	}
+	if(irq[1] > 0)
+	{
+		free_irq(irq[1],(void *) &hantrodec_data);
+	}
+  hantrodec_t *dev = &hantrodec_data;
+  int i, n =0;
+  volatile u8* mmu_hwregs[MAX_SUBSYS_NUM][2];
+
+  for (i = 0; i < MAX_SUBSYS_NUM; i++ ) {
+    mmu_hwregs[i][0] = dev->hwregs[i][HW_MMU];
+    mmu_hwregs[i][1] = dev->hwregs[i][HW_MMU_WR];
+  }
+  if (dev->hwregs[0][HW_MMU] || dev->hwregs[1][HW_MMU] ||
+      dev->hwregs[2][HW_MMU] || dev->hwregs[3][HW_MMU])
+    MMUCleanup(mmu_hwregs);
+
+  if (vcmd) {
+    hantrovcmd_cleanup(pdev);
+  } else {
+    /* reset hardware */
+    ResetAsic(dev);
+
+    /* free the IRQ */
+    for (n = 0; n < dev->cores; n++) {
+      if(dev->irq[n] != -1) {
+        free_irq(dev->irq[n], (void *) dev);
+      }
+    }
+  }
+  ReleaseIO();
+
+#ifdef CLK_CFG
+  if (clk_cfg!=NULL && !IS_ERR(clk_cfg)) {
+    clk_disable_unprepare(clk_cfg);
+    is_clk_on = 0;
+    printk("turned off hantrodec clk\n");
+  }
+
+  /*delete timer*/
+  del_timer(&timer);
+#endif
+
+  pm_runtime_mark_last_busy(&pdev->dev);
+  pm_runtime_put_autosuspend(&pdev->dev);
+	pm_runtime_disable(&pdev->dev);
+	if (!pm_runtime_status_suspended(&pdev->dev))
+		decoder_runtime_suspend(&pdev->dev);
+
+  cdev_del(&hantrodec_cdev);
+  device_destroy(hantrodec_class, hantrodec_devt);
+  unregister_chrdev_region(hantrodec_devt, 1);
+  class_destroy(hantrodec_class);
+
+  pr_info("hantrodec: module removed\n");
+  return 0;
+}
+
+
+static const struct dev_pm_ops decoder_runtime_pm_ops = {
+	SET_RUNTIME_PM_OPS(decoder_runtime_suspend, decoder_runtime_resume, NULL)
+};
+
+static struct platform_driver decoder_hantrodec_driver = {
+	.probe  = decoder_hantrodec_probe,
+	.remove = decoder_hantrodec_remove,
+	.driver = {
+		.name   = "decoder_hantrodec",
+		.owner  = THIS_MODULE,
+		.of_match_table = of_match_ptr(isp_of_match),
+    .pm = &decoder_runtime_pm_ops,
+	}
+};
+
+
+/*------------------------------------------------------------------------------
+ Function name   : hantrodec_init
+ Description     : Initialize the driver
+
+ Return type     : int
+------------------------------------------------------------------------------*/
+
+int __init hantrodec_init(void) {
+	int ret = 0;
+	printk("enter %s\n",__func__);
+	ret = platform_driver_register(&decoder_hantrodec_driver);
+	if(ret)
+	{
+		pr_err("register platform driver failed!\n");
+	}
+	return ret;
+}
+
+/*------------------------------------------------------------------------------
+ Function name   : hantrodec_cleanup
+ Description     : clean up
+
+ Return type     : int
+------------------------------------------------------------------------------*/
+
+void __exit hantrodec_cleanup(void) {
+	printk("enter %s\n",__func__);
+	platform_driver_unregister(&decoder_hantrodec_driver);
+	return;
+}
+
+/*------------------------------------------------------------------------------
+ Function name   : CheckHwId
+ Return type     : int
+------------------------------------------------------------------------------*/
+static int CheckHwId(hantrodec_t * dev) {
+  int hwid;
+  int i, j;
+  size_t num_hw = sizeof(DecHwId) / sizeof(*DecHwId);
+
+  int found = 0;
+
+  for (i = 0; i < dev->cores; i++) {
+    for (j = 0; j < HW_CORE_MAX; j++) {
+      if ((j == HW_VC8000D || j == HW_BIGOCEAN || j == HW_VC8000DJ) &&
+           dev->hwregs[i][j] != NULL) {
+        hwid = readl(dev->hwregs[i][j]);
+        pr_info("hantrodec: core %d HW ID=0x%08x\n", i, hwid);
+        hwid = (hwid >> 16) & 0xFFFF; /* product version only */
+        while (num_hw--) {
+          if (hwid == DecHwId[num_hw]) {
+            pr_info("hantrodec: Supported HW found at 0x%16lx\n",
+                   vpu_subsys[i].base_addr + vpu_subsys[i].submodule_offset[j]);
+            found++;
+            dev->hw_id[i][j] = hwid;
+            break;
+          }
+        }
+        if (!found) {
+          pr_info("hantrodec: Unknown HW found at 0x%16lx\n",
+                 multicorebase_actual[i]);
+          return 0;
+        }
+        found = 0;
+        num_hw = sizeof(DecHwId) / sizeof(*DecHwId);
+      }
+    }
+  }
+
+  return 1;
+}
+
+/*------------------------------------------------------------------------------
+ Function name   : ReserveIO
+ Description     : IO reserve
+
+ Return type     : int
+------------------------------------------------------------------------------*/
+static int ReserveIO(void) {
+  int i, j;
+  long int hwid;
+  u32  axife_config;
+
+  memcpy(multicorebase_actual, multicorebase, HXDEC_MAX_CORES * sizeof(unsigned long));
+  memcpy((unsigned int*)(hantrodec_data.iosize), iosize, HXDEC_MAX_CORES * sizeof(unsigned int));
+  memcpy((unsigned int*)(hantrodec_data.irq), irq, HXDEC_MAX_CORES * sizeof(int));
+
+  for (i = 0; i < MAX_SUBSYS_NUM; i++) {
+    if (!vpu_subsys[i].base_addr) continue;
+
+    for (j = 0; j < HW_CORE_MAX; j++) {
+      if (vpu_subsys[i].submodule_iosize[j]) {
+        pr_info("hantrodec: base=0x%16lx, iosize=%d\n",
+                          vpu_subsys[i].base_addr + vpu_subsys[i].submodule_offset[j],
+                          vpu_subsys[i].submodule_iosize[j]);
+
+        if (!request_mem_region(vpu_subsys[i].base_addr + vpu_subsys[i].submodule_offset[j],
+                                vpu_subsys[i].submodule_iosize[j],
+                                "hantrodec0")) {
+          pr_info("hantrodec: failed to reserve HW %d regs\n", j);
+          return -EBUSY;
+        }
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,17,0))
+        vpu_subsys[i].submodule_hwregs[j] =
+          hantrodec_data.hwregs[i][j] =
+            (volatile u8 *) ioremap_nocache(vpu_subsys[i].base_addr + vpu_subsys[i].submodule_offset[j],
+                                            vpu_subsys[i].submodule_iosize[j]);
+#else
+        vpu_subsys[i].submodule_hwregs[j] =
+          hantrodec_data.hwregs[i][j] =
+            (volatile u8 *) ioremap(vpu_subsys[i].base_addr + vpu_subsys[i].submodule_offset[j],
+                                            vpu_subsys[i].submodule_iosize[j]);
+#endif
+
+        if (hantrodec_data.hwregs[i][j] == NULL) {
+          pr_info("hantrodec: failed to ioremap HW %d regs\n", j);
+          release_mem_region(vpu_subsys[i].base_addr + vpu_subsys[i].submodule_offset[j],
+                             vpu_subsys[i].submodule_iosize[j]);
+          return -EBUSY;
+        } else {
+          if (vpu_subsys[i].has_apbfilter[j]) {
+            apbfilter_cfg[i][j].has_apbfilter = 1;
+            hwid = ioread32((void*)(hantrodec_data.hwregs[i][HW_VC8000D]));
+            if (IS_BIGOCEAN(hwid & 0xFFFF)) {
+              if (j == HW_BIGOCEAN) {
+                apbfilter_cfg[i][j].nbr_mask_regs = AV1_NUM_MASK_REG;
+                apbfilter_cfg[i][j].num_mode = AV1_NUM_MODE;
+                apbfilter_cfg[i][j].mask_reg_offset = AV1_MASK_REG_OFFSET;
+                apbfilter_cfg[i][j].mask_bits_per_reg = AV1_MASK_BITS_PER_REG;
+                apbfilter_cfg[i][j].page_sel_addr = apbfilter_cfg[i][j].mask_reg_offset + apbfilter_cfg[i][j].nbr_mask_regs * 4;
+              }
+              if (j == HW_AXIFE) {
+                apbfilter_cfg[i][j].nbr_mask_regs = AXIFE_NUM_MASK_REG;
+                apbfilter_cfg[i][j].num_mode = AXIFE_NUM_MODE;
+                apbfilter_cfg[i][j].mask_reg_offset = AXIFE_MASK_REG_OFFSET;
+                apbfilter_cfg[i][j].mask_bits_per_reg = AXIFE_MASK_BITS_PER_REG;
+                apbfilter_cfg[i][j].page_sel_addr = apbfilter_cfg[i][j].mask_reg_offset + apbfilter_cfg[i][j].nbr_mask_regs * 4;
+              }
+            } else {
+              hwid = ioread32((void*)(hantrodec_data.hwregs[i][HW_VC8000D] + HANTRODEC_HW_BUILD_ID_OFF));
+              if (hwid == 0x1F58) {
+                if (j == HW_VC8000D) {
+                  apbfilter_cfg[i][j].nbr_mask_regs = VC8000D_NUM_MASK_REG;
+                  apbfilter_cfg[i][j].num_mode = VC8000D_NUM_MODE;
+                  apbfilter_cfg[i][j].mask_reg_offset = VC8000D_MASK_REG_OFFSET;
+                  apbfilter_cfg[i][j].mask_bits_per_reg = VC8000D_MASK_BITS_PER_REG;
+                  apbfilter_cfg[i][j].page_sel_addr = apbfilter_cfg[i][j].mask_reg_offset + apbfilter_cfg[i][j].nbr_mask_regs * 4;
+                }
+                if (j == HW_AXIFE) {
+                  apbfilter_cfg[i][j].nbr_mask_regs = AXIFE_NUM_MASK_REG;
+                  apbfilter_cfg[i][j].num_mode = AXIFE_NUM_MODE;
+                  apbfilter_cfg[i][j].mask_reg_offset = AXIFE_MASK_REG_OFFSET;
+                  apbfilter_cfg[i][j].mask_bits_per_reg = AXIFE_MASK_BITS_PER_REG;
+                  apbfilter_cfg[i][j].page_sel_addr = apbfilter_cfg[i][j].mask_reg_offset + apbfilter_cfg[i][j].nbr_mask_regs * 4;
+                }
+              } else if (hwid == 0x1F59) {
+                if (j == HW_VC8000DJ) {
+                  apbfilter_cfg[i][j].nbr_mask_regs = VC8000DJ_NUM_MASK_REG;
+                  apbfilter_cfg[i][j].num_mode = VC8000DJ_NUM_MODE;
+                  apbfilter_cfg[i][j].mask_reg_offset = VC8000DJ_MASK_REG_OFFSET;
+                  apbfilter_cfg[i][j].mask_bits_per_reg = VC8000DJ_MASK_BITS_PER_REG;
+                  apbfilter_cfg[i][j].page_sel_addr = apbfilter_cfg[i][j].mask_reg_offset + apbfilter_cfg[i][j].nbr_mask_regs * 4;
+                }
+                if (j == HW_AXIFE) {
+                  apbfilter_cfg[i][j].nbr_mask_regs = AXIFE_NUM_MASK_REG;
+                  apbfilter_cfg[i][j].num_mode = AXIFE_NUM_MODE;
+                  apbfilter_cfg[i][j].mask_reg_offset = AXIFE_MASK_REG_OFFSET;
+                  apbfilter_cfg[i][j].mask_bits_per_reg = AXIFE_MASK_BITS_PER_REG;
+                  apbfilter_cfg[i][j].page_sel_addr = apbfilter_cfg[i][j].mask_reg_offset + apbfilter_cfg[i][j].nbr_mask_regs * 4;
+                }
+              } else {
+                  pr_info("hantrodec: furture APBFILTER can read those configure parameters from REG\n");
+              }
+            }
+            hantrodec_data.apbfilter_hwregs[i][j] = hantrodec_data.hwregs[i][j] + apbfilter_cfg[i][j].mask_reg_offset;
+          } else {
+            apbfilter_cfg[i][j].has_apbfilter = 0;
+          }
+
+          if (j == HW_AXIFE) {
+            hwid = ioread32((void*)(hantrodec_data.hwregs[i][j] + HANTRODEC_HW_BUILD_ID_OFF));
+            axife_config = ioread32((void*)(hantrodec_data.hwregs[i][j]));
+            axife_cfg[i].axi_rd_chn_num = axife_config & 0x7F;
+            axife_cfg[i].axi_wr_chn_num = (axife_config >> 7) & 0x7F;
+            axife_cfg[i].axi_rd_burst_length = (axife_config >> 14) & 0x1F;
+            axife_cfg[i].axi_wr_burst_length = (axife_config >> 22) & 0x1F;
+            axife_cfg[i].fe_mode = 0; /*need to read from reg in furture*/
+            if (hwid == 0x1F66) {
+              axife_cfg[i].fe_mode = 1;
+            }
+          }
+        }
+        config.its_main_core_id[i] = -1;
+        config.its_aux_core_id[i] = -1;
+
+        pr_info("hantrodec: HW %d reg[0]=0x%08x\n", j, readl(hantrodec_data.hwregs[i][j]));
+
+#ifdef SUPPORT_2ND_PIPELINES
+	if (j != HW_VC8000D) continue;
+        hwid = ((readl(hantrodec_data.hwregs[i][HW_VC8000D])) >> 16) & 0xFFFF; /* product version only */
+
+        if (IS_VC8000D(hwid)) {
+          u32 reg;
+          /*TODO(min): DO NOT support 2nd pipeline. */
+          reg = readl(hantrodec_data.hwregs[i][HW_VC8000D] + HANTRODEC_SYNTH_CFG_2_OFF);
+          if (((reg >> DWL_H264_PIPELINE_E) & 0x01U) || ((reg >> DWL_JPEG_PIPELINE_E) & 0x01U)) {
+            i++;
+            config.its_aux_core_id[i-1] = i;
+            config.its_main_core_id[i] = i-1;
+            config.its_aux_core_id[i] = -1;
+            multicorebase_actual[i] = multicorebase_actual[i-1] + 0x800;
+            hantrodec_data.iosize[i] = hantrodec_data.iosize[i-1];
+            memcpy(multicorebase_actual+i+1, multicorebase+i,
+                   (HXDEC_MAX_CORES - i - 1) * sizeof(unsigned long));
+            memcpy((unsigned int*)hantrodec_data.iosize+i+1, iosize+i,
+                   (HXDEC_MAX_CORES - i - 1) * sizeof(unsigned int));
+            if (!request_mem_region(multicorebase_actual[i], hantrodec_data.iosize[i],
+                                "hantrodec0")) {
+              pr_info("hantrodec: failed to reserve HW regs\n");
+              return -EBUSY;
+            }
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,17,0))
+            hantrodec_data.hwregs[i][HW_VC8000D] = (volatile u8 *) ioremap_nocache(multicorebase_actual[i],
+                                       hantrodec_data.iosize[i]);
+#else
+            hantrodec_data.hwregs[i][HW_VC8000D] = (volatile u8 *) ioremap(multicorebase_actual[i],
+                                       hantrodec_data.iosize[i]);
+#endif
+
+            if (hantrodec_data.hwregs[i][HW_VC8000D] == NULL ) {
+              pr_info("hantrodec: failed to ioremap HW regs\n");
+              ReleaseIO();
+                return -EBUSY;
+            }
+            hantrodec_data.cores++;
+          }
+        }
+#endif
+      } else {
+        hantrodec_data.hwregs[i][j] = NULL;
+      }
+    }
+    hantrodec_data.cores++;
+  }
+
+  /* check for correct HW */
+  if (!CheckHwId(&hantrodec_data)) {
+    ReleaseIO();
+    return -EBUSY;
+  }
+
+  return 0;
+}
+
+/*------------------------------------------------------------------------------
+ Function name   : releaseIO
+ Description     : release
+
+ Return type     : void
+------------------------------------------------------------------------------*/
+
+static void ReleaseIO(void) {
+  int i, j;
+  for (i = 0; i < hantrodec_data.cores; i++) {
+    for (j = 0; j < HW_CORE_MAX; j++) {
+      if (hantrodec_data.hwregs[i][j]) {
+        iounmap((void *) hantrodec_data.hwregs[i][j]);
+        release_mem_region(vpu_subsys[i].base_addr + vpu_subsys[i].submodule_offset[j],
+                           vpu_subsys[i].submodule_iosize[j]);
+        hantrodec_data.hwregs[i][j] = 0;
+      }
+    }
+  }
+}
+
+/*------------------------------------------------------------------------------
+ Function name   : hantrodec_isr
+ Description     : interrupt handler
+
+ Return type     : irqreturn_t
+------------------------------------------------------------------------------*/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18))
+irqreturn_t hantrodec_isr(int irq, void *dev_id, struct pt_regs *regs)
+#else
+irqreturn_t hantrodec_isr(int irq, void *dev_id)
+#endif
+{
+  printk("%s:start!\n",__func__);
+  unsigned long flags;
+  unsigned int handled = 0;
+  int i;
+  volatile u8 *hwregs;
+
+  hantrodec_t *dev = (hantrodec_t *) dev_id;
+  u32 irq_status_dec;
+
+  spin_lock_irqsave(&owner_lock, flags);
+
+  for(i=0; i<dev->cores; i++) {
+    volatile u8 *hwregs = dev->hwregs[i][HW_VC8000D];
+
+    /* interrupt status register read */
+    irq_status_dec = ioread32((void*)(hwregs + HANTRODEC_IRQ_STAT_DEC_OFF));
+
+    if(irq_status_dec & HANTRODEC_DEC_IRQ) {
+      /* clear dec IRQ */
+      irq_status_dec &= (~HANTRODEC_DEC_IRQ);
+      iowrite32(irq_status_dec, (void*)(hwregs + HANTRODEC_IRQ_STAT_DEC_OFF));
+
+      PDEBUG("decoder IRQ received! core %d\n", i);
+
+      atomic_inc(&irq_rx);
+
+      dec_irq |= (1 << i);
+
+      wake_up_interruptible_all(&dec_wait_queue);
+      handled++;
+    }
+  }
+
+  spin_unlock_irqrestore(&owner_lock, flags);
+
+  if(!handled) {
+    PDEBUG("IRQ received, but not hantrodec's!\n");
+  }
+
+  (void)hwregs;
+  printk("%s:end!\n",__func__);
+  return IRQ_RETVAL(handled);
+}
+
+/*------------------------------------------------------------------------------
+ Function name   : ResetAsic
+ Description     : reset asic (only VC8000D supports reset)
+
+ Return type     :
+------------------------------------------------------------------------------*/
+void ResetAsic(hantrodec_t * dev) {
+  int i, j;
+  u32 status;
+
+  for (j = 0; j < dev->cores; j++) {
+    if (!dev->hwregs[j][HW_VC8000D]) continue;
+
+    status = ioread32((void*)(dev->hwregs[j][HW_VC8000D] + HANTRODEC_IRQ_STAT_DEC_OFF));
+
+    if( status & HANTRODEC_DEC_E) {
+      /* abort with IRQ disabled */
+      status = HANTRODEC_DEC_ABORT | HANTRODEC_DEC_IRQ_DISABLE;
+      iowrite32(status, (void*)(dev->hwregs[j][HW_VC8000D] + HANTRODEC_IRQ_STAT_DEC_OFF));
+    }
+
+    if (IS_G1(dev->hw_id[j][HW_VC8000D]))
+      /* reset PP */
+      iowrite32(0, (void*)(dev->hwregs[j][HW_VC8000D] + HANTRO_IRQ_STAT_PP_OFF));
+
+    for (i = 4; i < dev->iosize[j]; i += 4) {
+      iowrite32(0, (void*)(dev->hwregs[j][HW_VC8000D] + i));
+    }
+  }
+}
+
+/*------------------------------------------------------------------------------
+ Function name   : dump_regs
+ Description     : Dump registers
+
+ Return type     :
+------------------------------------------------------------------------------*/
+#ifdef HANTRODEC_DEBUG
+void dump_regs(hantrodec_t *dev) {
+  int i,c;
+
+  PDEBUG("Reg Dump Start\n");
+  for(c = 0; c < dev->cores; c++) {
+    for(i = 0; i < dev->iosize[c]; i += 4*4) {
+      PDEBUG("\toffset %04X: %08X  %08X  %08X  %08X\n", i,
+             ioread32(dev->hwregs[c][HW_VC8000D] + i),
+             ioread32(dev->hwregs[c][HW_VC8000D] + i + 4),
+             ioread32(dev->hwregs[c][HW_VC8000D] + i + 16),
+             ioread32(dev->hwregs[c][HW_VC8000D] + i + 24));
+    }
+  }
+  PDEBUG("Reg Dump End\n");
+}
+#endif
+
+
+module_init( hantrodec_init);
+module_exit( hantrodec_cleanup);
+
+/* module description */
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("VeriSilicon Microelectronics ");
+MODULE_DESCRIPTION("driver module for Hantro video decoder VC8000D");
+

+ 1869 - 0
linux/subsys_driver/hantro_mmu.c

@@ -0,0 +1,1869 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2021 VERISILICON
+*
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2021 VERISILICON
+*
+*    This program is free software; you can redistribute it and/or
+*    modify it under the terms of the GNU General Public License
+*    as published by the Free Software Foundation; either version 2
+*    of the License, or (at your option) any later version.
+*
+*    This program is distributed in the hope that it will be useful,
+*    but WITHOUT ANY WARRANTY; without even the implied warranty of
+*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*    GNU General Public License for more details.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+#include <linux/version.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/debugfs.h>
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/pagemap.h>
+#include <linux/sched.h>
+#include <stddef.h>
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0))
+#include <linux/dma-map-ops.h>
+#else
+#include <linux/dma-contiguous.h>
+#endif
+#include <linux/platform_device.h>
+#include <linux/version.h>
+#include <linux/mod_devicetable.h>
+#include <linux/dma-buf.h>
+#include "hantrommu.h"
+#include "subsys.h"
+
+MODULE_DESCRIPTION("Verisilicon VPU Driver");
+MODULE_LICENSE("GPL");
+
+#ifndef NULL
+#ifdef __cplusplus
+#define NULL 0
+#else
+#define NULL ((void *)0)
+#endif
+#endif
+
+#define MMU_REG_OFFSET              0
+#define MMU_REG_HW_ID               (MMU_REG_OFFSET + 6*4)
+#define MMU_REG_FLUSH               (MMU_REG_OFFSET + 97*4)
+#define MMU_REG_PAGE_TABLE_ID       (MMU_REG_OFFSET + 107*4)
+#define MMU_REG_CONTROL             (MMU_REG_OFFSET + 226*4)
+#define MMU_REG_ADDRESS             (MMU_REG_OFFSET + 227*4)
+#define MMU_REG_ADDRESS_MSB         (MMU_REG_OFFSET + 228*4)
+
+/*******************************************************************************
+***** New MMU Defination *******************************************************/
+#define MMU_MTLB_SHIFT           22
+#define MMU_STLB_4K_SHIFT        12
+#define MMU_STLB_64K_SHIFT       16
+
+#define MMU_MTLB_BITS            (32 - MMU_MTLB_SHIFT)
+#define MMU_PAGE_4K_BITS         MMU_STLB_4K_SHIFT
+#define MMU_STLB_4K_BITS         (32 - MMU_MTLB_BITS - MMU_PAGE_4K_BITS)
+#define MMU_PAGE_64K_BITS        MMU_STLB_64K_SHIFT
+#define MMU_STLB_64K_BITS        (32 - MMU_MTLB_BITS - MMU_PAGE_64K_BITS)
+
+#define MMU_MTLB_ENTRY_NUM       (1 << MMU_MTLB_BITS)
+#define MMU_MTLB_SIZE            (MMU_MTLB_ENTRY_NUM << 2)
+#define MMU_STLB_4K_ENTRY_NUM    (1 << MMU_STLB_4K_BITS)
+#define MMU_STLB_4K_SIZE         (MMU_STLB_4K_ENTRY_NUM << 2)
+#define MMU_PAGE_4K_SIZE         (1 << MMU_STLB_4K_SHIFT)
+#define MMU_STLB_64K_ENTRY_NUM   (1 << MMU_STLB_64K_BITS)
+#define MMU_STLB_64K_SIZE        (MMU_STLB_64K_ENTRY_NUM << 2)
+#define MMU_PAGE_64K_SIZE        (1 << MMU_STLB_64K_SHIFT)
+
+#define MMU_MTLB_MASK            (~((1U << MMU_MTLB_SHIFT)-1))
+#define MMU_STLB_4K_MASK         ((~0U << MMU_STLB_4K_SHIFT) ^ MMU_MTLB_MASK)
+#define MMU_PAGE_4K_MASK         (MMU_PAGE_4K_SIZE - 1)
+#define MMU_STLB_64K_MASK        ((~((1U << MMU_STLB_64K_SHIFT)-1)) ^ MMU_MTLB_MASK)
+#define MMU_PAGE_64K_MASK        (MMU_PAGE_64K_SIZE - 1)
+
+/* Page offset definitions. */
+#define MMU_OFFSET_4K_BITS       (32 - MMU_MTLB_BITS - MMU_STLB_4K_BITS)
+#define MMU_OFFSET_4K_MASK       ((1U << MMU_OFFSET_4K_BITS) - 1)
+#define MMU_OFFSET_16K_BITS      (32 - MMU_MTLB_BITS - MMU_STLB_16K_BITS)
+#define MMU_OFFSET_16K_MASK      ((1U << MMU_OFFSET_16K_BITS) - 1)
+
+#define MMU_MTLB_ENTRY_HINTS_BITS 6
+#define MMU_MTLB_ENTRY_STLB_MASK  (~((1U << MMU_MTLB_ENTRY_HINTS_BITS) - 1))
+
+#define MMU_MTLB_PRESENT         0x00000001
+#define MMU_MTLB_EXCEPTION       0x00000002
+#define MMU_MTLB_4K_PAGE         0x00000000
+
+#define MMU_STLB_PRESENT         0x00000001
+#define MMU_STLB_EXCEPTION       0x00000002
+#define MMU_STLB_4K_PAGE         0x00000000
+
+#define MMU_FALSE                0
+#define MMU_TRUE                 1
+
+#define MMU_ERR_OS_FAIL          (0xffff)
+#define MMU_EFAULT               MMU_ERR_OS_FAIL
+#define MMU_ENOTTY               MMU_ERR_OS_FAIL
+
+#define MMU_INFINITE             ((u32) ~0U)
+
+#define MAX_NOPAGED_SIZE         0x20000
+#define MMU_SUPPRESS_OOM_MESSAGE 1
+
+#define MTLB_PCIE_START_ADDRESS  0x00100000
+#define PAGE_PCIE_START_ADDRESS  0x00200000 /* page_table_entry start address */
+#define STLB_PCIE_START_ADDRESS  0x00300000
+#define PAGE_TABLE_ENTRY_SIZE    64
+
+#if MMU_SUPPRESS_OOM_MESSAGE
+#define MMU_NOWARN __GFP_NOWARN
+#else
+#define MMU_NOWARN 0
+#endif
+
+#define MMU_IS_ERROR(status)         (status < 0)
+#define MMU_NO_ERROR(status)         (status >= 0)
+#define MMU_IS_SUCCESS(status)       (status == MMU_STATUS_OK)
+
+#undef MMUDEBUG
+#ifdef HANTROMMU_DEBUG
+#  ifdef __KERNEL__
+#    define MMUDEBUG(fmt, args...) printk( KERN_INFO "hantrommu: " fmt, ## args)
+#  else
+#    define MMUDEBUG(fmt, args...) fprintf(stderr, fmt, ## args)
+#  endif
+#else
+#  define MMUDEBUG(fmt, args...)
+#endif
+
+#define MMU_ON_ERROR(func) \
+  do { \
+    status = func; \
+    if (MMU_IS_ERROR(status)){ \
+      goto onerror; \
+    } \
+  }while (MMU_FALSE)
+
+#define WritePageEntry(page_entry, entry_value) \
+    *(unsigned int *)(page_entry) =(unsigned int)(entry_value)
+
+#define ReadPageEntry(page_entry) *(unsigned int *)(page_entry)
+
+#define DRIVER_NAME "hantrodecdma"
+
+/* simple map mode: generate mmu address which is same as input bus address*/
+unsigned int simple_map = 0;
+/* this shift should be an integral multiple of mmu page size(4096).
+   It can generate a mmu address shift in simple map mode*/
+unsigned int map_shift = 0;
+
+/* module_param(name, type, perm) */
+module_param(simple_map, uint, 0);
+module_param(map_shift, uint, 0);
+
+enum MMURegion {
+  MMU_REGION_IN,
+  MMU_REGION_OUT,
+  MMU_REGION_PRIVATE,
+  MMU_REGION_PUB,
+
+  MMU_REGION_COUNT
+};
+
+struct MMUNode {
+  void                       *buf_virtual_address;
+  unsigned int               buf_bus_address; /* used in kernel map mode */
+  int                        mtlb_start;
+  int                        stlb_start;
+  int                        mtlb_end;
+  int                        stlb_end;
+  unsigned int               page_count;
+  int                        process_id;
+  struct file*               filp;
+
+  struct MMUNode             *next;
+  struct MMUNode             *prev;
+};
+
+struct MMUDDRRegion {
+  unsigned long long         physical_address;
+  unsigned long long         virtual_address;
+  unsigned int               page_count;
+
+  void                       *node_mutex;
+  struct MMUNode             *simple_map_head;
+  struct MMUNode             *simple_map_tail;
+  struct MMUNode             *free_map_head;
+  struct MMUNode             *map_head;
+  struct MMUNode             *free_map_tail;
+  struct MMUNode             *map_tail;
+};
+
+struct MMU {
+  void                        *page_table_mutex;
+  /* Master TLB information. */
+  unsigned int                mtlb_size;
+  unsigned long long          mtlb_physical;
+  void                        *mtlb_virtual;
+  unsigned int                mtlb_entries;
+
+  int                         enabled;
+  unsigned int                stlb_size;
+  unsigned long long          stlb_physical;
+  void                        *stlb_virtual;
+  struct MMUDDRRegion         region[MMU_REGION_COUNT];
+  unsigned int                page_table_array_size;
+  unsigned long long          page_table_array_physical;
+  void                        *page_table_array;
+};
+
+static struct MMU *g_mmu       = NULL;
+extern unsigned long gBaseDDRHw;
+unsigned int mmu_enable = MMU_FALSE;
+static unsigned int mmu_init = MMU_FALSE;
+extern unsigned int pcie;
+static unsigned int region_in_mmu_start = REGION_IN_MMU_START;
+static unsigned int region_in_mmu_end = REGION_IN_MMU_END;
+static unsigned int region_out_mmu_start = REGION_OUT_MMU_START;
+static unsigned int region_out_mmu_end = REGION_OUT_MMU_END;
+static unsigned int region_private_mmu_start = REGION_PRIVATE_MMU_START;
+static unsigned int region_private_mmu_end = REGION_PRIVATE_MMU_END;
+
+static const struct platform_device_info hantro_platform_info = {
+  .name = DRIVER_NAME,
+  .id = -1,
+  .dma_mask = DMA_BIT_MASK(32),
+};
+
+static int hantro_drm_probe(struct platform_device *pdev)
+{
+  int result;
+  struct device *dev = &pdev->dev;
+  (void) dev;
+  (void) result;
+  return 0;
+}
+static int hantro_drm_remove(struct platform_device *pdev)
+{
+  struct device *dev = &pdev->dev;
+  (void) dev;
+  return 0;
+}
+static const struct platform_device_id hantro_drm_platform_ids[] = {
+  {
+    .name = DRIVER_NAME,
+  },
+  {/* sentinel */ },
+};
+static const struct of_device_id hantro_of_match[] = {
+  { .compatible = "thead,light-vc8000d-mmu", },
+  {/* sentinel */}
+};
+static struct platform_driver hantro_drm_platform_driver = {
+  .probe       = hantro_drm_probe,
+  .remove      = hantro_drm_remove,
+  .driver      = {
+    .name           = DRIVER_NAME,
+    .owner          = THIS_MODULE,
+    .of_match_table = hantro_of_match,
+  },
+  .id_table = hantro_drm_platform_ids,
+};
+
+struct platform_device *platformdev;
+
+static enum MMUStatus ZeroMemory(void *memory, unsigned int bytes) {
+  memset(memory, 0, bytes);
+
+  return MMU_STATUS_OK;
+}
+
+static enum MMUStatus AllocateMemory(unsigned int bytes, void **memory){
+  void *pointer;
+  enum MMUStatus status;
+
+  if (bytes > MAX_NOPAGED_SIZE) {
+    pointer = (void*) vmalloc(bytes);
+    MMUDEBUG(" *****VMALLOC size*****%d\n", bytes);
+  } else {
+    pointer = (void*) kmalloc(bytes, GFP_KERNEL | MMU_NOWARN);
+    MMUDEBUG(" *****KMALLOC size*****%d\n", bytes);
+  }
+
+  if (pointer == NULL) {
+    /* Out of memory. */
+    status = MMU_STATUS_OUT_OF_MEMORY;
+    goto onerror;
+  }
+
+  /* Return pointer to the memory allocation. */
+  *memory = pointer;
+
+  return MMU_STATUS_OK;
+
+onerror:
+  /* Return the status. */
+  return status;
+}
+
+static enum MMUStatus FreeMemory(void *memory) {
+  /* Free the memory from the OS pool. */
+  if (is_vmalloc_addr(memory)) {
+    MMUDEBUG(" *****VFREE*****%p\n", memory);
+    vfree(memory);
+  } else {
+    MMUDEBUG(" *****KFREE*****%p\n", memory);
+    kfree(memory);
+  }
+  return MMU_STATUS_OK;
+}
+
+
+static enum MMUStatus SMDeleteNode(struct MMUNode **pp) {
+  (*pp)->prev->next = (*pp)->next;
+  (*pp)->next->prev = (*pp)->prev;
+
+  MMUDEBUG(" *****DeleteNode size*****%d\n", (*pp)->page_count);
+  FreeMemory(*pp);
+
+  return MMU_STATUS_OK;
+}
+
+static enum MMUStatus DeleteNode(struct MMUNode **pp) {
+  (*pp)->prev->next = (*pp)->next;
+  (*pp)->next->prev = (*pp)->prev;
+
+  MMUDEBUG(" *****DeleteNode size*****%d\n", (*pp)->page_count);
+  FreeMemory(*pp);
+
+  return MMU_STATUS_OK;
+}
+
+static enum MMUStatus MergeNode(struct MMUNode *h,
+                                struct MMUNode **pp) {
+  struct MMUNode *tmp0 = h->next;
+  struct MMUNode *tmp1 = h->next;
+  while(tmp0) {
+    /* 1th step: find front contiguous memory node */
+    if(tmp0->mtlb_end == (*pp)->mtlb_start &&
+       tmp0->stlb_end == (*pp)->stlb_start) {
+      tmp0->mtlb_end = (*pp)->mtlb_end;
+      tmp0->stlb_end = (*pp)->stlb_end;
+      tmp0->page_count += (*pp)->page_count;
+      DeleteNode(pp);
+      MMUDEBUG(" *****first merge to front. node size*****%d\n", tmp0->page_count);
+      /* after merge to front contiguous memory node,
+         find if there is behind contiguous memory node */
+      while(tmp1) {
+        /* merge */
+        if(tmp1->mtlb_start == tmp0->mtlb_end &&
+           tmp1->stlb_start == tmp0->stlb_end) {
+          tmp1->mtlb_start  = tmp0->mtlb_start;
+          tmp1->stlb_start  = tmp0->stlb_start;
+          tmp1->page_count += tmp0->page_count;
+          MMUDEBUG(" *****second merge to behind. node size*****%d\n", tmp1->page_count);
+          DeleteNode(&tmp0);
+          return MMU_STATUS_OK;
+        }
+        tmp1 = tmp1->next;
+      }
+      return MMU_STATUS_OK;
+    /* 1th step: find behind contiguous memory node */
+    } else if(tmp0->mtlb_start == (*pp)->mtlb_end &&
+              tmp0->stlb_start == (*pp)->stlb_end) {
+      tmp0->mtlb_start = (*pp)->mtlb_start;
+      tmp0->stlb_start = (*pp)->stlb_start;
+      tmp0->page_count += (*pp)->page_count;
+      DeleteNode(pp);
+      MMUDEBUG(" *****first merge to behind. node size*****%d\n", tmp0->page_count);
+      /* after merge to behind contiguous memory node,
+         find if there is front contiguous memory node */
+      while(tmp1) {
+        /* merge */
+        if(tmp1->mtlb_end == tmp0->mtlb_start &&
+           tmp1->stlb_end == tmp0->stlb_start) {
+          tmp1->mtlb_end    = tmp0->mtlb_end;
+          tmp1->stlb_end    = tmp0->stlb_end;
+          tmp1->page_count += tmp0->page_count;
+          MMUDEBUG(" *****second merge to front. node size*****%d\n", tmp1->page_count);
+          DeleteNode(&tmp0);
+          return MMU_STATUS_OK;
+        }
+        tmp1 = tmp1->next;
+      }
+      return MMU_STATUS_OK;
+    }
+    tmp0 = tmp0->next;
+  }
+  return MMU_STATUS_FALSE;
+}
+
+/* Insert a node to map list */
+static enum MMUStatus SMInsertNode(enum MMURegion e,
+                                   struct MMUNode **pp) {
+  struct MMUNode *h;
+
+  h = g_mmu->region[e].simple_map_head;
+
+  h->next->prev     = *pp;
+  (*pp)->next       = h->next;
+  (*pp)->prev       = h;
+  h->next           = *pp;
+  MMUDEBUG(" *****insert bm node*****%d\n", (*pp)->page_count);
+
+  return MMU_STATUS_OK;
+}
+
+static enum MMUStatus InsertNode(enum MMURegion e,
+                                 struct MMUNode **pp,
+                                 unsigned int free) {
+  enum MMUStatus status;
+  struct MMUNode *h, *b;
+
+  if(free) {
+    h = g_mmu->region[e].free_map_head;
+    b = g_mmu->region[e].map_head;
+    status = MergeNode(h, pp);
+    MMUDEBUG(" *****insert free*****%d\n", (*pp)->page_count);
+    if(MMU_IS_ERROR(status)) {
+      /* remove from map*/
+      if((*pp)->prev != NULL && (*pp)->next != NULL) {
+        (*pp)->prev->next = (*pp)->next;
+        (*pp)->next->prev = (*pp)->prev;
+      }
+      /* insert to free map */
+      h->next->prev     = *pp;
+      (*pp)->next       = h->next;
+      (*pp)->prev       = h;
+      h->next           = *pp;
+    }
+  } else {
+    h = g_mmu->region[e].map_head;
+
+    h->next->prev     = *pp;
+    (*pp)->next       = h->next;
+    (*pp)->prev       = h;
+    h->next           = *pp;
+    MMUDEBUG(" *****insert unfree*****%d\n", (*pp)->page_count);
+  }
+
+  return MMU_STATUS_OK;
+}
+
+/* Create a Node */
+static enum MMUStatus SMCreateNode(enum MMURegion e,
+                                   struct MMUNode **node,
+                                   unsigned int page_count) {
+  struct MMUNode *p, **new;
+
+  p = kmalloc(sizeof(struct MMUNode), GFP_KERNEL | MMU_NOWARN);
+  new = &p;
+
+  (*new)->mtlb_start = -1;
+  (*new)->stlb_start = -1;
+  (*new)->mtlb_end   = -1;
+  (*new)->stlb_end   = -1;
+  (*new)->process_id = 0;
+  (*new)->filp       = NULL;
+  (*new)->page_count = 0;
+  (*new)->prev       = NULL;
+  (*new)->next       = NULL;
+  /* Insert a uncomplete Node, it will be initialized later */
+  SMInsertNode(e, new);
+
+  /* return a new node for map buffer */
+  *node = *new;
+  return MMU_STATUS_OK;
+}
+
+/* Create initial Nodes */
+static enum MMUStatus SMCreateNodes(void) {
+  struct MMUNode *simple_map_head;
+  struct MMUNode *simple_map_tail;
+  int i;
+
+  /* Init each region map node */
+  for (i = 0; i < MMU_REGION_COUNT ; i++) {
+    simple_map_head      = kmalloc(sizeof(struct MMUNode), GFP_KERNEL | MMU_NOWARN);
+    simple_map_tail      = kmalloc(sizeof(struct MMUNode), GFP_KERNEL | MMU_NOWARN);
+
+    simple_map_head->mtlb_start = -1;
+    simple_map_head->stlb_start = -1;
+    simple_map_head->mtlb_end   = -1;
+    simple_map_head->stlb_end   = -1;
+    simple_map_head->process_id = 0;
+    simple_map_head->filp       = NULL;
+    simple_map_head->page_count = 0;
+    simple_map_head->prev       = NULL;
+    simple_map_head->next       = simple_map_tail;
+
+    simple_map_tail->mtlb_start = -1;
+    simple_map_tail->stlb_start = -1;
+    simple_map_tail->mtlb_end   = -1;
+    simple_map_tail->stlb_end   = -1;
+    simple_map_tail->process_id = 0;
+    simple_map_tail->filp       = NULL;
+    simple_map_tail->page_count = 0;
+    simple_map_tail->prev       = simple_map_head;
+    simple_map_tail->next       = NULL;
+
+    g_mmu->region[i].simple_map_head = simple_map_head;
+    g_mmu->region[i].simple_map_tail = simple_map_tail;
+  }
+  return MMU_STATUS_OK;
+}
+
+static enum MMUStatus CreateNode(void) {
+  struct MMUNode *free_map_head, *map_head, *p, **pp;
+  struct MMUNode *free_map_tail, *map_tail;
+  int i;
+  unsigned int page_count;
+  unsigned int prev_stlb = 0, prev_mtlb = 0;
+
+  /* Init each region map node */
+  for (i = 0; i < MMU_REGION_COUNT ; i++) {
+    free_map_head = kmalloc(sizeof(struct MMUNode), GFP_KERNEL | MMU_NOWARN);
+    map_head      = kmalloc(sizeof(struct MMUNode), GFP_KERNEL | MMU_NOWARN);
+    free_map_tail = kmalloc(sizeof(struct MMUNode), GFP_KERNEL | MMU_NOWARN);
+    map_tail      = kmalloc(sizeof(struct MMUNode), GFP_KERNEL | MMU_NOWARN);
+
+    free_map_head->mtlb_start = map_head->mtlb_start = -1;
+    free_map_head->stlb_start = map_head->stlb_start = -1;
+    free_map_head->mtlb_end   = map_head->mtlb_end   = -1;
+    free_map_head->stlb_end   = map_head->stlb_end   = -1;
+    free_map_head->process_id = map_head->process_id = 0;
+    free_map_head->filp       = map_head->filp       = NULL;
+    free_map_head->page_count = map_head->page_count = 0;
+    free_map_head->prev       = map_head->prev       = NULL;
+    free_map_head->next       = free_map_tail;
+    map_head->next            = map_tail;
+
+    free_map_tail->mtlb_start = map_tail->mtlb_start = -1;
+    free_map_tail->stlb_start = map_tail->stlb_start = -1;
+    free_map_tail->mtlb_end   = map_tail->mtlb_end   = -1;
+    free_map_tail->stlb_end   = map_tail->stlb_end   = -1;
+    free_map_tail->process_id = map_tail->process_id = 0;
+    free_map_tail->filp       = map_tail->filp       = NULL;
+    free_map_tail->page_count = map_tail->page_count = 0;
+    free_map_tail->prev       = free_map_head;
+    map_tail->prev            = map_head;
+    free_map_tail->next       = map_tail->next       = NULL;
+
+    g_mmu->region[i].free_map_head = free_map_head;
+    g_mmu->region[i].map_head = map_head;
+    g_mmu->region[i].free_map_tail = free_map_tail;
+    g_mmu->region[i].map_tail = map_tail;
+
+    p  = kmalloc(sizeof(struct MMUNode), GFP_KERNEL | MMU_NOWARN);
+    pp = &p;
+
+    switch(i) {
+    case MMU_REGION_IN:
+      page_count = (REGION_IN_END - REGION_IN_START + 1)/PAGE_SIZE;
+      p->stlb_start = region_in_mmu_start >> 12 & 0x3FF;  //hold mmu addr: 0x0
+      p->mtlb_start = region_in_mmu_start >> 22;
+      //end point next region start: +1; for remainder: +1
+      p->stlb_end = prev_stlb = region_in_mmu_end >> 12 & 0x3FF;
+      p->mtlb_end = prev_mtlb = region_in_mmu_end >> 22;
+      p->page_count = page_count - 1;  //hold mmu addr: 0x0
+      break;
+    case MMU_REGION_OUT:
+      page_count = (REGION_OUT_END - REGION_OUT_START + 1)/PAGE_SIZE;
+      p->stlb_start = region_out_mmu_start >> 12 & 0x3FF;
+      p->mtlb_start = region_out_mmu_start >> 22;
+      p->stlb_end = prev_stlb = region_out_mmu_end >> 12 & 0x3FF;
+      p->mtlb_end = prev_mtlb = region_out_mmu_end >> 22;
+      p->page_count = page_count;
+      break;
+    case MMU_REGION_PRIVATE:
+      page_count = (REGION_PRIVATE_END - REGION_PRIVATE_START + 1)/PAGE_SIZE;
+      p->stlb_start = region_private_mmu_start >> 12 & 0x3FF;
+      p->mtlb_start = region_private_mmu_start >> 22;
+      p->stlb_end = prev_stlb = region_private_mmu_end >> 12 & 0x3FF;
+      p->mtlb_end = prev_mtlb = region_private_mmu_end >> 22;
+      p->page_count = page_count;
+      break;
+    case MMU_REGION_PUB:
+      p->stlb_start = prev_stlb;
+      p->mtlb_start = prev_mtlb;
+      p->stlb_end = prev_stlb = MMU_STLB_4K_ENTRY_NUM - 1;
+      p->mtlb_end = prev_mtlb = MMU_MTLB_ENTRY_NUM - 1;
+      p->page_count = (p->mtlb_end - p->mtlb_start) * MMU_STLB_4K_ENTRY_NUM +
+                      p->stlb_end - p->stlb_start + 1;
+      break;
+    default:
+      pr_notice(" *****MMU Region Error*****\n");
+      break;
+    }
+
+    p->process_id = 0;
+    p->filp       = NULL;
+    p->next       = p->prev = NULL;
+
+    InsertNode(i, pp, 1);
+  }
+
+  return MMU_STATUS_OK;
+}
+
+/* A simpile function to check if the map buffer is existed.
+   it needs more complex version*/
+static enum MMUStatus SMCheckAddress(enum MMURegion e,
+                                     void *virtual_address) {
+  struct MMUNode *p;
+  p = g_mmu->region[e].simple_map_head->next;
+
+  while(p) {
+    if(p->buf_virtual_address == virtual_address) {
+      return MMU_STATUS_FALSE;
+    }
+    p = p->next;
+  }
+  return MMU_STATUS_OK;
+}
+
+static enum MMUStatus FindFreeNode(enum MMURegion e,
+                                   struct MMUNode **node,
+                                   unsigned int page_count) {
+  struct MMUNode *p;
+  p = g_mmu->region[e].free_map_head->next;
+
+  while(p) {
+    if(p->page_count >= page_count) {
+      *node = p;
+      return MMU_STATUS_OK;
+    }
+    p = p->next;
+  }
+  return MMU_STATUS_FALSE;
+}
+
+static enum MMUStatus SplitFreeNode(enum MMURegion e,
+                                   struct MMUNode **node,
+                                   unsigned int page_count) {
+  struct MMUNode *p, **new;
+
+  p = kmalloc(sizeof(struct MMUNode), GFP_KERNEL | MMU_NOWARN);
+  new = &p;
+
+  **new = **node;
+
+  (*new)->mtlb_start = (*node)->mtlb_start;
+  (*new)->stlb_start = (*node)->stlb_start;
+  (*new)->mtlb_end   = (page_count + (*node)->stlb_start) /
+                       MMU_STLB_4K_ENTRY_NUM +
+                       (*node)->mtlb_start;
+  (*new)->stlb_end   = (page_count + (*node)->stlb_start) %
+                       MMU_STLB_4K_ENTRY_NUM;
+  (*new)->process_id = (*node)->process_id;
+  (*new)->page_count = page_count;
+
+  MMUDEBUG(" *****new mtlb_start*****%d\n", (*new)->mtlb_start);
+  MMUDEBUG(" *****new stlb_start*****%d\n", (*new)->stlb_start);
+  MMUDEBUG(" *****new mtlb_end*****%d\n", (*new)->mtlb_end);
+  MMUDEBUG(" *****new stlb_end*****%d\n", (*new)->stlb_end);
+  /* Insert a new node in map */
+  InsertNode(e, new, 0);
+
+  /* Update free node in free map*/
+  (*node)->page_count -= page_count;
+  if((*node)->page_count == 0) {
+    DeleteNode(node);
+    MMUDEBUG(" *****old node deleted*****\n");
+  } else {
+    (*node)->mtlb_start  = (*new)->mtlb_end;
+    (*node)->stlb_start  = (*new)->stlb_end;
+
+    MMUDEBUG(" *****old mtlb_start*****%d\n", (*node)->mtlb_start);
+    MMUDEBUG(" *****old stlb_start*****%d\n", (*node)->stlb_start);
+    MMUDEBUG(" *****old mtlb_end*****%d\n", (*node)->mtlb_end);
+    MMUDEBUG(" *****old stlb_end*****%d\n", (*node)->stlb_end);
+  }
+  /* return a new node for map buffer */
+  *node = *new;
+
+  return MMU_STATUS_OK;
+}
+
+static enum MMUStatus SMRemoveNode(enum MMURegion e,
+                                   void *buf_virtual_address,
+                                   unsigned int process_id) {
+  struct MMUNode *p, **pp;
+  p = g_mmu->region[e].simple_map_head->next;
+  pp = &p;
+
+  while(*pp) {
+    if((*pp)->buf_virtual_address == buf_virtual_address &&
+       (*pp)->process_id == process_id) {
+      SMDeleteNode(pp);
+      break;
+    }
+    *pp = (*pp)->next;
+  }
+
+  return MMU_STATUS_OK;
+}
+
+static enum MMUStatus RemoveNode(enum MMURegion e,
+                                 void *buf_virtual_address,
+                                 unsigned int process_id) {
+  struct MMUNode *p, **pp;
+  p = g_mmu->region[e].map_head->next;
+  pp = &p;
+
+  while(*pp) {
+    if((*pp)->buf_virtual_address == buf_virtual_address &&
+       (*pp)->process_id == process_id) {
+      InsertNode(e, pp, 1);
+      break;
+    }
+    *pp = (*pp)->next;
+  }
+
+  return MMU_STATUS_OK;
+}
+
+static enum MMUStatus SMRemoveKernelNode(enum MMURegion e,
+                                   unsigned int buf_bus_address,
+                                   unsigned int process_id) {
+  struct MMUNode *p, **pp;
+  p = g_mmu->region[e].simple_map_head->next;
+  pp = &p;
+
+  while(*pp) {
+    if((*pp)->buf_bus_address == buf_bus_address &&
+       (*pp)->process_id == process_id) {
+      SMDeleteNode(pp);
+      break;
+    }
+    *pp = (*pp)->next;
+  }
+
+  return MMU_STATUS_OK;
+}
+
+static enum MMUStatus RemoveKernelNode(enum MMURegion e,
+                                 unsigned int buf_bus_address,
+                                 unsigned int process_id) {
+  struct MMUNode *p, **pp;
+  p = g_mmu->region[e].map_head->next;
+  pp = &p;
+
+  while(*pp) {
+    if((*pp)->buf_bus_address == buf_bus_address &&
+       (*pp)->process_id == process_id) {
+      InsertNode(e, pp, 1);
+      break;
+    }
+    *pp = (*pp)->next;
+  }
+
+  return MMU_STATUS_OK;
+}
+
+static enum MMUStatus Delay(unsigned int delay) {
+  if(delay > 0) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)
+    ktime_t dl = ktime_set((delay / MSEC_PER_SEC),
+                      (delay % MSEC_PER_SEC) * NSEC_PER_MSEC);
+    __set_current_state(TASK_UNINTERRUPTIBLE);
+    schedule_hrtimeout(&dl, HRTIMER_MODE_REL);
+#else
+    msleep(delay);
+#endif
+  }
+
+  return MMU_STATUS_OK;
+}
+
+static enum MMUStatus CreateMutex(void **mtx) {
+  enum MMUStatus status;
+
+  /* Allocate the mutex structure. */
+  status = AllocateMemory(sizeof(struct mutex), mtx);
+  if (MMU_IS_SUCCESS(status)) {
+    /* Initialize the mutex. */
+    mutex_init(*(struct mutex **)mtx);
+  }
+
+  return status;
+}
+
+static enum MMUStatus DeleteMutex(void *mtx) {
+    /* Destroy the mutex. */
+    mutex_destroy((struct mutex *)mtx);
+
+    /* Free the mutex structure. */
+    FreeMemory(mtx);
+
+    return MMU_STATUS_OK;
+}
+
+static enum MMUStatus AcquireMutex(void *mtx, unsigned int timeout) {
+  if (timeout == MMU_INFINITE)
+  {
+    /* Lock the mutex. */
+    mutex_lock(mtx);
+
+    /* Success. */
+    return MMU_STATUS_OK;
+  }
+
+  for (;;) {
+    /* Try to acquire the mutex. */
+    if (mutex_trylock(mtx)) {
+      /* Success. */
+      return MMU_STATUS_OK;
+    }
+
+    if (timeout-- == 0) {
+      break;
+    }
+
+    /* Wait for 1 millisecond. */
+    Delay(1);
+  }
+
+  return MMU_STATUS_OK;
+}
+
+static enum MMUStatus ReleaseMutex(void *mtx) {
+  /* Release the mutex. */
+  mutex_unlock(mtx);
+
+  return MMU_STATUS_OK;
+}
+
+
+static inline enum MMUStatus QueryProcessPageTable(void  *logical,
+                               unsigned long long *address) {
+  unsigned long lg = (unsigned long)logical;
+  unsigned long offset = lg & ~PAGE_MASK;
+  struct vm_area_struct *vma;
+  spinlock_t *ptl;
+  pgd_t *pgd;
+  pud_t *pud;
+  pmd_t *pmd;
+  pte_t *pte;
+
+  if (is_vmalloc_addr(logical)) {
+    /* vmalloc area. */
+    *address = page_to_phys(vmalloc_to_page(logical)) | offset;
+    return MMU_STATUS_OK;
+  } else if (virt_addr_valid(lg)) {
+    /* Kernel logical address. */
+    *address = virt_to_phys(logical);
+    return MMU_STATUS_OK;
+  } else {
+    /* Try user VM area. */
+    if (!current->mm)
+      return MMU_STATUS_NOT_FOUND;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)
+    down_read(&current->mm->mmap_lock);
+#else
+    down_read(&current->mm->mmap_sem);
+#endif
+    vma = find_vma(current->mm, lg);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)
+    up_read(&current->mm->mmap_lock);
+#else
+    up_read(&current->mm->mmap_sem);
+#endif
+
+    /* To check if mapped to user. */
+    if (!vma)
+      return MMU_STATUS_NOT_FOUND;
+
+    pgd = pgd_offset(current->mm, lg);
+    if (pgd_none(*pgd) || pgd_bad(*pgd))
+      return MMU_STATUS_NOT_FOUND;
+
+#if (defined(CONFIG_CPU_CSKYV2) || defined(CONFIG_X86)) \
+    && LINUX_VERSION_CODE >= KERNEL_VERSION (4,12,0)
+    pud = pud_offset((p4d_t*)pgd, lg);
+#elif (defined(CONFIG_CPU_CSKYV2) || defined(CONFIG_RISCV)) \
+    && LINUX_VERSION_CODE >= KERNEL_VERSION (4,11,0)
+    pud = pud_offset((p4d_t*)pgd, lg);
+#else
+    pud = pud_offset(pgd, lg);
+#endif
+    if (pud_none(*pud) || pud_bad(*pud))
+      return MMU_STATUS_NOT_FOUND;
+
+    pmd = pmd_offset(pud, lg);
+    if (pmd_none(*pmd) || pmd_bad(*pmd))
+      return MMU_STATUS_NOT_FOUND;
+
+    pte = pte_offset_map_lock(current->mm, pmd, lg, &ptl);
+    if (!pte) {
+      spin_unlock(ptl);
+      return MMU_STATUS_NOT_FOUND;
+    }
+
+    if (!pte_present(*pte)) {
+      pte_unmap_unlock(pte, ptl);
+      return MMU_STATUS_NOT_FOUND;
+    }
+
+    *address = (pte_pfn(*pte) << PAGE_SHIFT) | offset;
+    pte_unmap_unlock(pte, ptl);
+
+    *address -= gBaseDDRHw;
+	//MMUDEBUG(" QueryProcessPageTable map: virt %p -> %p\n", logical, (void *)*address);
+
+    return MMU_STATUS_OK;
+  }
+}
+
+static inline int GetProcessID(void) {
+  return current->tgid;
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
+static inline int is_vmalloc_addr(void *addr) {
+  unsigned long long addr = (unsigned long long)Addr;
+
+  return addr >= VMALLOC_START && addr < VMALLOC_END;
+}
+#endif
+
+static enum MMUStatus GetPhysicalAddress(void *logical,
+                        unsigned long long *address) {
+  enum MMUStatus status;
+
+  status = QueryProcessPageTable(logical, address);
+
+  return status;
+}
+
+static enum MMUStatus GetPageEntry(struct MMUNode *node,
+                                   unsigned int **page_table_entry,
+                                   unsigned int i) {
+  int num = node->mtlb_start * MMU_STLB_4K_ENTRY_NUM +
+            node->stlb_start + i;
+  *page_table_entry = (unsigned int*)g_mmu->stlb_virtual + num;
+  return MMU_STATUS_OK;
+}
+
+static enum MMUStatus SetupDynamicSpace(void) {
+  int i;
+  enum MMUStatus status;
+  unsigned int stlb_entry;
+  void *pointer;
+  unsigned long long address;
+  dma_addr_t dma_handle;
+  unsigned int num_entries = MMU_MTLB_ENTRY_NUM;
+  unsigned int *mtlb_virtual = (unsigned int *)g_mmu->mtlb_virtual;
+
+  AcquireMutex(g_mmu->page_table_mutex, MMU_INFINITE);
+  if(pcie) {
+    pointer = ioremap(gBaseDDRHw+STLB_PCIE_START_ADDRESS, num_entries*MMU_STLB_4K_SIZE);
+    g_mmu->stlb_virtual = pointer;
+    MMUDEBUG(" *****stlb_virtual = %p**%d\n", pointer, num_entries*MMU_STLB_4K_SIZE);
+    address = STLB_PCIE_START_ADDRESS;
+    for(i = 0; i < num_entries; i++){
+        stlb_entry = address
+                    /* 4KB page size */
+                    | (0 << 2)
+                    /* Ignore exception */
+                    | (0 << 1)
+                    /* Present */
+                    | (1 << 0);
+        WritePageEntry(mtlb_virtual++, stlb_entry);
+        address += MMU_STLB_4K_SIZE;
+      }
+
+  } else {
+    g_mmu->stlb_virtual = (void *)((u64)(g_mmu->mtlb_virtual) + MMU_MTLB_SIZE);
+    g_mmu->stlb_physical = address = g_mmu->mtlb_physical + MMU_MTLB_SIZE;
+    g_mmu->stlb_size = num_entries * MMU_STLB_4K_SIZE;
+
+    for(i = 0; i < num_entries; i++){
+      stlb_entry = address
+                  /* 4KB page size */
+                  | (0 << 2)
+                  /* Ignore exception */
+                  | (0 << 1)
+                  /* Present */
+                  | (1 << 0);
+      WritePageEntry(mtlb_virtual++, stlb_entry);
+      address += MMU_STLB_4K_SIZE;
+    }
+  }
+  ReleaseMutex(g_mmu->page_table_mutex);
+
+  /* Initial map info. */
+  if (simple_map)
+    SMCreateNodes();
+  else
+    CreateNode();
+
+  return MMU_STATUS_OK;
+onerror:
+    /* Return status. */
+    return status;
+}
+
+
+enum MMUStatus MMUInit(volatile unsigned char *hwregs) {
+  enum MMUStatus status;
+  unsigned i;
+  int result;
+  void *pointer;
+
+  if (mmu_init == MMU_TRUE) {
+    /* All mmu use common table and dev, just initial once*/
+    pr_notice(" *****MMU Already Initialed*****\n");
+    return MMU_STATUS_OK;
+  }
+
+  if(!hwregs || (ioread32((void*)(hwregs + MMU_REG_HW_ID))>>16) != 0x4D4D)
+    return MMU_STATUS_NOT_FOUND;
+
+  pr_notice(" *****MMU Init*****\n");
+
+  platformdev = platform_device_register_full(&hantro_platform_info);
+  if(platformdev == NULL) {
+    pr_err("hantrodec create platform device fail\n");
+    status = MMU_STATUS_FALSE;
+    goto onerror;
+  } else {
+    pr_info("Create platform device success\n");
+  }
+
+  result = platform_driver_register(&hantro_drm_platform_driver);
+  pr_notice("Platform driver status is %d\n", result);
+
+  /* Allocate memory for the MMU object. */
+  MMU_ON_ERROR(AllocateMemory(sizeof(struct MMU), &pointer));
+  ZeroMemory(pointer, sizeof(struct MMU));
+
+  g_mmu = pointer;
+
+  g_mmu->page_table_mutex   = NULL;
+
+  /* Create the page table mutex. */
+  MMU_ON_ERROR(CreateMutex(&g_mmu->page_table_mutex));
+
+  for (i = 0; i < MMU_REGION_COUNT;i++) {
+    MMU_ON_ERROR(CreateMutex(&g_mmu->region[i].node_mutex));
+  }
+
+  mmu_init = MMU_TRUE;
+  return MMU_STATUS_OK;
+
+onerror:
+  pr_notice(" *****MMU Init Error*****\n");
+  return status;
+}
+
+enum MMUStatus MMURelease(void *filp, volatile unsigned char *hwregs) {
+  int i, j;
+  struct MMUNode *p, *tmp;
+  unsigned long long address;
+  unsigned int *page_table_entry;
+
+  if(!hwregs || (ioread32((void*)(hwregs + MMU_REG_HW_ID))>>16) != 0x4D4D)
+    return MMU_STATUS_FALSE;
+
+  /* if mmu or TLB not enabled, return */
+  if (simple_map) {
+    if(g_mmu == NULL || g_mmu->region[0].simple_map_head == NULL)
+      return MMU_STATUS_OK;
+  } else {
+    if(g_mmu == NULL || g_mmu->region[0].map_head == NULL)
+      return MMU_STATUS_OK;
+  }
+
+  pr_notice(" *****MMU Release*****\n");
+
+  AcquireMutex(g_mmu->page_table_mutex, MMU_INFINITE);
+
+  if (simple_map) {
+    for (i = 0; i < MMU_REGION_COUNT; i++) {
+      p = g_mmu->region[i].simple_map_head->next;
+
+      while(p) {
+        tmp = p->next;
+        if(p->filp == (struct file *)filp) {
+
+          for(j = 0;j < p->page_count; j++) {
+            GetPageEntry(p, &page_table_entry, j);
+            address = 0;
+            WritePageEntry(page_table_entry, address);
+          }
+
+          SMRemoveNode(i, p->buf_virtual_address, p->process_id);
+        }
+        p = tmp;
+      }
+    }
+  } else {
+    for (i = 0; i < MMU_REGION_COUNT; i++) {
+      p = g_mmu->region[i].map_head->next;
+
+      while(p) {
+        tmp = p->next;
+        if(p->filp == (struct file *)filp) {
+
+          for(j = 0;j < p->page_count; j++) {
+            GetPageEntry(p, &page_table_entry, j);
+            address = 0;
+            WritePageEntry(page_table_entry, address);
+          }
+
+          RemoveNode(i, p->buf_virtual_address, p->process_id);
+        }
+        p = tmp;
+      }
+    }
+  }
+  ReleaseMutex(g_mmu->page_table_mutex);
+
+  return MMU_STATUS_OK;
+}
+
+enum MMUStatus MMUCleanup(volatile unsigned char *hwregs[MAX_SUBSYS_NUM][2]) {
+  int i;
+  struct MMUNode *p, *tmp;
+  struct MMUNode *fp;
+
+  for (i = 0; i < MAX_SUBSYS_NUM; i++) {
+    if (hwregs[i][0] != NULL &&
+        (ioread32((void*)(hwregs[i][0] + MMU_REG_HW_ID))>>16) != 0x4D4D)
+      return MMU_STATUS_FALSE;
+    if (hwregs[i][1] != NULL &&
+        (ioread32((void*)(hwregs[i][1] + MMU_REG_HW_ID))>>16) != 0x4D4D)
+      return MMU_STATUS_FALSE;
+  }
+
+  pr_info(" *****MMU cleanup*****\n");
+  if (pcie) {
+    if (g_mmu->stlb_virtual)
+      iounmap(g_mmu->stlb_virtual);
+    if (g_mmu->mtlb_virtual)
+      iounmap(g_mmu->mtlb_virtual);
+    if (g_mmu->page_table_array)
+      iounmap(g_mmu->page_table_array);
+  } else {
+    if (g_mmu->stlb_virtual)
+      dma_free_coherent(&platformdev->dev, g_mmu->stlb_size,
+		        g_mmu->stlb_virtual, (dma_addr_t)g_mmu->stlb_physical);
+    if (g_mmu->mtlb_virtual)
+      dma_free_coherent(&platformdev->dev, g_mmu->mtlb_size,
+                        g_mmu->mtlb_virtual, (dma_addr_t)g_mmu->mtlb_physical);
+    if (g_mmu->page_table_array)
+      dma_free_coherent(&platformdev->dev, g_mmu->page_table_array_size,
+                        g_mmu->page_table_array, (dma_addr_t)g_mmu->page_table_array_physical);
+  }
+  DeleteMutex(g_mmu->page_table_mutex);
+
+  for (i = 0; i < MMU_REGION_COUNT; i++) {
+    DeleteMutex(g_mmu->region[i].node_mutex);
+    if (simple_map) {
+      p = g_mmu->region[i].simple_map_head;
+      while(p) {
+        tmp = p->next;
+        FreeMemory(p);
+        p   = tmp;
+        MMUDEBUG(" *****clean node*****\n");
+      }
+    } else {
+      fp = g_mmu->region[i].free_map_head;
+      p  = g_mmu->region[i].map_head;
+      while(fp) {
+        tmp = fp->next;
+        FreeMemory(fp);
+        fp  = tmp;
+        MMUDEBUG(" *****clean free node*****\n");
+      }
+
+      while(p) {
+        tmp = p->next;
+        FreeMemory(p);
+        p   = tmp;
+        MMUDEBUG(" *****clean node*****\n");
+      }
+    }
+  }
+  FreeMemory(g_mmu);
+
+  platform_device_unregister(platformdev);
+  platform_driver_unregister(&hantro_drm_platform_driver);
+  pr_info("Unregister platform device.\n");
+
+  for (i = 0; i < MAX_SUBSYS_NUM; i++) {
+    if (hwregs[i][0] != NULL)
+      iowrite32(0, (void*)(hwregs[i][0] + MMU_REG_CONTROL));
+    if (hwregs[i][1] != NULL)
+      iowrite32(0, (void*)(hwregs[i][1] + MMU_REG_CONTROL));
+  }
+  mmu_enable = 0;
+  mmu_init = 0;
+
+  return MMU_STATUS_OK;
+}
+
+/*------------------------------------------------------------------------------
+    Function name: MMUEnable
+        Description:
+            Create TLB, set registers and enable MMU
+
+    For pcie, TLB buffers come from FPGA memory and The distribution is as follows
+           MTLB:              start from: 0x00100000, size: 4K bits
+           page table array:              0x00200000        64 bits
+           STLB:                          0x00300000        4M bits
+ ------------------------------------------------------------------------------*/
+enum MMUStatus MMUEnable(volatile unsigned char *hwregs[MAX_SUBSYS_NUM][2]) {
+  enum MMUStatus status;
+  unsigned int address;
+  unsigned int mutex = MMU_FALSE;
+  dma_addr_t dma_handle;
+  u32 i = 0;
+  u32 address_ext;
+  u32 total_table_size = 0;
+
+  if(mmu_enable == MMU_TRUE) {
+    pr_info(" *****MMU Already Enabled*****\n");
+    return MMU_STATUS_OK;
+  }
+
+  pr_info(" *****MMU Enable...*****\n");
+
+  AcquireMutex(g_mmu->page_table_mutex, MMU_INFINITE);
+  mutex = MMU_TRUE;
+  if(pcie) {
+    g_mmu->mtlb_size = MMU_MTLB_SIZE;
+    g_mmu->mtlb_virtual = ioremap(gBaseDDRHw+MTLB_PCIE_START_ADDRESS, g_mmu->mtlb_size);
+    g_mmu->mtlb_physical = MTLB_PCIE_START_ADDRESS;
+
+    g_mmu->page_table_array = ioremap(gBaseDDRHw+PAGE_PCIE_START_ADDRESS, PAGE_TABLE_ENTRY_SIZE);
+  } else {
+    /* Allocate the 4K mode MTLB table. */
+    total_table_size = MMU_MTLB_SIZE + MMU_MTLB_ENTRY_NUM*MMU_STLB_4K_SIZE;
+    g_mmu->mtlb_size = MMU_MTLB_SIZE;
+    g_mmu->mtlb_virtual = dma_alloc_coherent(&platformdev->dev, total_table_size,
+		                             &dma_handle, GFP_KERNEL | GFP_DMA);
+    MMUDEBUG(" *****g_mmu->mtlb_virtual = 0x%p\n", g_mmu->mtlb_virtual);
+    g_mmu->mtlb_physical = (unsigned long long)dma_handle;
+    MMUDEBUG(" *****mtlb_physical = 0x%llx\n", (unsigned int)g_mmu->mtlb_physical);
+    if(g_mmu->mtlb_virtual == NULL) {
+      pr_err("hantrodec alloc buffer fail\n");
+      status = MMU_STATUS_FALSE;
+      goto onerror;
+    }
+
+    g_mmu->page_table_array_size = PAGE_TABLE_ENTRY_SIZE;
+    g_mmu->page_table_array = dma_alloc_coherent(&platformdev->dev, g_mmu->page_table_array_size,
+			                         &dma_handle, GFP_KERNEL | GFP_DMA);
+    MMUDEBUG(" *****g_mmu->page_table_array = 0x%p\n", g_mmu->page_table_array);
+    g_mmu->page_table_array_physical = (unsigned long long)dma_handle;
+    MMUDEBUG(" *****page_table_array_physical = 0x%llx\n", (unsigned int)g_mmu->page_table_array_physical);
+    if(g_mmu->page_table_array == NULL) {
+      pr_err("hantrodec alloc buffer fail\n");
+      status = MMU_STATUS_FALSE;
+      goto onerror;
+    }
+  }
+
+  *((unsigned int*)g_mmu->page_table_array) =
+      (g_mmu->mtlb_physical & 0xFFFFF000) | (0 << 0);
+  *((unsigned int *)g_mmu->page_table_array+1) =
+      (u32)(g_mmu->mtlb_physical >> 32)&0xff;
+  *((unsigned int *)g_mmu->page_table_array+2) =
+      (g_mmu->mtlb_physical & 0xFFFFF000) | (0 << 0);
+  *((unsigned int *)g_mmu->page_table_array+3) =
+      (u32)(g_mmu->mtlb_physical >> 32)&0xff;
+
+  MMUDEBUG(" Page table array[0]: lsb = 0x%llx\n", ((int *)g_mmu->page_table_array)[0]);
+  MMUDEBUG("                      msb = 0x%llx\n", ((int *)g_mmu->page_table_array)[1]);
+
+  ZeroMemory(g_mmu->mtlb_virtual, total_table_size);
+
+  ReleaseMutex(g_mmu->page_table_mutex);
+
+  MMU_ON_ERROR(SetupDynamicSpace());
+
+  if(pcie) {
+    address = PAGE_PCIE_START_ADDRESS;
+  } else {
+    address = g_mmu->page_table_array_physical;
+    address_ext = ((u32)(g_mmu->page_table_array_physical >> 32))&0xff;
+  }
+
+  /* set regs of all MMUs */
+  for (i = 0; i < MAX_SUBSYS_NUM; i++) {
+    if (hwregs[i][0] != NULL) {
+      iowrite32(address, (void*)(hwregs[i][0] + MMU_REG_ADDRESS));
+      iowrite32(address_ext, (void *)(hwregs[i][0] + MMU_REG_ADDRESS_MSB));
+
+      iowrite32(0x10000, (void*)(hwregs[i][0] + MMU_REG_PAGE_TABLE_ID));
+      iowrite32(0x00000, (void*)(hwregs[i][0] + MMU_REG_PAGE_TABLE_ID));
+
+      iowrite32(1, (void*)(hwregs[i][0] + MMU_REG_CONTROL));
+    }
+    if (hwregs[i][1] != NULL) {
+      iowrite32(address, (void*)(hwregs[i][1] + MMU_REG_ADDRESS));
+      iowrite32(address_ext, (void *)(hwregs[i][1] + MMU_REG_ADDRESS_MSB));
+
+      iowrite32(0x10000, (void*)(hwregs[i][1] + MMU_REG_PAGE_TABLE_ID));
+      iowrite32(0x00000, (void*)(hwregs[i][1] + MMU_REG_PAGE_TABLE_ID));
+
+      iowrite32(1, (void*)(hwregs[i][1] + MMU_REG_CONTROL));
+    }
+  }
+  mmu_enable = MMU_TRUE;
+  return MMU_STATUS_OK;
+
+onerror:
+  if (mutex) {
+    ReleaseMutex(g_mmu->page_table_mutex);
+  }
+  MMUDEBUG(" *****MMU Enable Error*****\n");
+  return status;
+}
+
+/*------------------------------------------------------------------------------
+    Function name: MMUFlush
+        Description:
+            Flush MMU reg to update cache in MMU.
+ ------------------------------------------------------------------------------*/
+static enum MMUStatus MMUFlush(u32 core_id, volatile unsigned char *hwregs[MAX_SUBSYS_NUM][2]) {
+  enum MMUStatus status;
+  unsigned int mutex = MMU_FALSE;
+
+  MMUDEBUG(" *****MMU Flush*****\n");
+  AcquireMutex(g_mmu->page_table_mutex, MMU_INFINITE);
+  mutex = MMU_TRUE;
+
+  if (hwregs[core_id][0] != NULL) {
+    iowrite32(0x10, (void*)(hwregs[core_id][0] + MMU_REG_FLUSH));
+    iowrite32(0x00, (void*)(hwregs[core_id][0] + MMU_REG_FLUSH));
+  } else {
+    pr_err("hantrodec alloc buffer fail\n");
+    status = MMU_STATUS_FALSE;
+    goto onerror;
+  }
+  if (hwregs[core_id][1] != NULL) {
+    iowrite32(0x10, (void*)(hwregs[core_id][1] + MMU_REG_FLUSH));
+    iowrite32(0x00, (void*)(hwregs[core_id][1] + MMU_REG_FLUSH));
+  }
+
+  ReleaseMutex(g_mmu->page_table_mutex);
+  return MMU_STATUS_OK;
+
+onerror:
+  if (mutex) {
+    ReleaseMutex(g_mmu->page_table_mutex);
+  }
+  MMUDEBUG(" *****MMU Flush Error*****\n");
+  return status;
+}
+
+static enum MMUStatus MMUMemNodeMap(struct addr_desc *addr, struct file *filp) {
+  enum MMUStatus status;
+  unsigned int  page_count = 0;
+  unsigned int i = 0;
+  struct MMUNode *p;
+  unsigned long long address = 0x0;
+  unsigned int *page_table_entry;
+  enum MMURegion e;
+  unsigned int mutex = MMU_FALSE;
+  u32 ext_addr;
+  u32 page_entry_value = 0;
+
+  MMUDEBUG(" *****MMU Map*****\n");
+  AcquireMutex(g_mmu->page_table_mutex, MMU_INFINITE);
+  mutex = MMU_TRUE;
+
+  page_count = (addr->size - 1)/PAGE_SIZE + 1;
+
+  GetPhysicalAddress(addr->virtual_address, &address);
+  MMUDEBUG(" *****MMU map address*****%x\n", address);
+  if(address >= REGION_IN_START &&
+     address + addr->size < REGION_IN_END)
+    e = MMU_REGION_IN;
+  else if(address >= REGION_OUT_START &&
+          address + addr->size < REGION_OUT_END)
+    e = MMU_REGION_OUT;
+  else if(address >= REGION_PRIVATE_START &&
+          address + addr->size < REGION_PRIVATE_END)
+    e = MMU_REGION_PRIVATE;
+  else
+    e = MMU_REGION_PUB;
+
+  if (simple_map) {
+    MMU_ON_ERROR(SMCheckAddress(e, addr->virtual_address));
+
+    SMCreateNode(e, &p, page_count);
+    MMUDEBUG(" *****Node map size*****%d\n", page_count);
+
+    p->buf_virtual_address = addr->virtual_address;
+    p->process_id          = GetProcessID();
+    p->filp                = filp;
+
+    p->mtlb_start = ((address + map_shift) >> MMU_MTLB_SHIFT);
+    p->stlb_start = ((address + map_shift) >> MMU_STLB_4K_SHIFT ) & 0x3FF;
+    p->mtlb_end   = (page_count + p->stlb_start) / MMU_STLB_4K_ENTRY_NUM +
+                     p->mtlb_start;
+    p->stlb_end   = (page_count + p->stlb_start) % MMU_STLB_4K_ENTRY_NUM;
+    p->page_count = page_count;
+
+    for(i = 0;i < page_count; i++) {
+      GetPhysicalAddress(addr->virtual_address + i * PAGE_SIZE, &address);
+      GetPageEntry(p, &page_table_entry, i);
+      ext_addr = ((u32)(address>>32))&0xff;
+      page_entry_value = (address & 0xFFFFF000)
+                        /* ext address , physical address bits [39,32]*/
+                        | (ext_addr << 4)
+                        /* writable */
+                        | (1 << 2)
+                        /* Ignore exception */
+                        | (0 << 1)
+                        /* Present */
+                        | (1 << 0);
+      WritePageEntry(page_table_entry, page_entry_value);
+    }
+
+    /* Purpose of Bare_metal mode: input bus address==mmu address*/
+    addr->bus_address = p->mtlb_start << MMU_MTLB_SHIFT
+                        | p->stlb_start << MMU_STLB_4K_SHIFT;
+  } else {
+    MMU_ON_ERROR(FindFreeNode(e, &p, page_count));
+
+    SplitFreeNode(e, &p, page_count);
+    MMUDEBUG(" *****Node map size*****%d\n", p->page_count);
+
+    p->buf_virtual_address = addr->virtual_address;
+    p->process_id          = GetProcessID();
+    p->filp                = filp;
+
+    for(i = 0;i < page_count; i++) {
+      GetPhysicalAddress(addr->virtual_address + i * PAGE_SIZE, &address);
+      GetPageEntry(p, &page_table_entry, i);
+      ext_addr = ((u32)(address>>32))&0xff;
+      page_entry_value = (address & 0xFFFFF000)
+                        /* ext address , physical address bits [39,32]*/
+                        | (ext_addr << 4)
+                        /* writable */
+                        | (1 << 2)
+                        /* Ignore exception */
+                        | (0 << 1)
+                        /* Present */
+                        | (1 << 0);
+      WritePageEntry(page_table_entry, page_entry_value);
+    }
+    addr->bus_address = p->mtlb_start << MMU_MTLB_SHIFT
+                        | p->stlb_start << MMU_STLB_4K_SHIFT;
+  }
+  MMUDEBUG(" MMU_MTLB_SHIFT %d MMU_STLB_4K_SHIFT %d\n", MMU_MTLB_SHIFT, MMU_STLB_4K_SHIFT);
+  MMUDEBUG(" MMUMemNodeMap map total %d pages in region %d\nMTLB/STLB starts %d/%d, MTLB/STLB ends %d/%d\n",
+             page_count, (u32)e, p->mtlb_start, p->stlb_start, p->mtlb_end, p->stlb_end);
+  MMUDEBUG(" MMUMemNodeMap map %p -> 0x%08x\n", addr->virtual_address, addr->bus_address);
+
+  ReleaseMutex(g_mmu->page_table_mutex);
+
+  return MMU_STATUS_OK;
+
+onerror:
+  if (mutex) {
+    ReleaseMutex(g_mmu->page_table_mutex);
+  }
+  MMUDEBUG(" *****MMU Map Error*****\n");
+  return status;
+}
+
+static enum MMUStatus MMUMemNodeUnmap(struct addr_desc *addr) {
+  unsigned int i;
+  unsigned long long address = 0x0;
+  unsigned int *page_table_entry;
+  int process_id = GetProcessID();
+  enum MMURegion e = MMU_REGION_COUNT;
+  enum MMUStatus status = MMU_STATUS_OUT_OF_MEMORY;
+  struct MMUNode *p;
+  unsigned int mutex = MMU_FALSE;
+
+  MMUDEBUG(" *****MMU Unmap*****\n");
+  AcquireMutex(g_mmu->page_table_mutex, MMU_INFINITE);
+  mutex = MMU_TRUE;
+
+  GetPhysicalAddress(addr->virtual_address, &address);
+  if(address >= REGION_IN_START &&
+     address < REGION_IN_END)
+    e = MMU_REGION_IN;
+  else if(address >= REGION_OUT_START &&
+          address < REGION_OUT_END)
+    e = MMU_REGION_OUT;
+  else if(address >= REGION_PRIVATE_START &&
+          address < REGION_PRIVATE_END)
+    e = MMU_REGION_PRIVATE;
+  else
+    e = MMU_REGION_PUB;
+
+  if (simple_map)
+    p = g_mmu->region[e].simple_map_head->next;
+  else
+    p = g_mmu->region[e].map_head->next;
+  /* Reset STLB of the node */
+  while(p) {
+    if(p->buf_virtual_address == addr->virtual_address &&
+        p->process_id == process_id) {
+      for(i = 0;i < p->page_count; i++) {
+        GetPageEntry(p, &page_table_entry, i);
+        address = 0;
+        WritePageEntry(page_table_entry, address);
+      }
+      break;
+    }
+    p = p->next;
+  }
+  if(!p)
+    goto onerror;
+
+  if (simple_map)
+    SMRemoveNode(e, addr->virtual_address, process_id);
+  else
+    RemoveNode(e, addr->virtual_address, process_id);
+
+  ReleaseMutex(g_mmu->page_table_mutex);
+  return MMU_STATUS_OK;
+
+onerror:
+  if (mutex) {
+    ReleaseMutex(g_mmu->page_table_mutex);
+  }
+  MMUDEBUG(" *****MMU Unmap Error*****\n");
+  return status;
+}
+
+enum MMUStatus MMUKernelMemNodeMap(struct kernel_addr_desc *addr) {
+  enum MMUStatus status;
+  unsigned int  page_count = 0;
+  unsigned int i = 0;
+  struct MMUNode *p;
+  unsigned long long address = 0x0;
+  unsigned int *page_table_entry;
+  enum MMURegion e;
+  unsigned int mutex = MMU_FALSE;
+  u32 ext_addr;
+  u32 page_entry_value = 0;
+
+  MMUDEBUG(" *****MMU Map*****\n");
+  AcquireMutex(g_mmu->page_table_mutex, MMU_INFINITE);
+  mutex = MMU_TRUE;
+
+  page_count = (addr->size - 1)/PAGE_SIZE + 1;
+
+  address = addr->bus_address;
+  MMUDEBUG(" *****MMU map address*****%llx\n", address);
+  if(address >= REGION_IN_START &&
+     address + addr->size < REGION_IN_END)
+    e = MMU_REGION_IN;
+  else if(address >= REGION_OUT_START &&
+          address + addr->size < REGION_OUT_END)
+    e = MMU_REGION_OUT;
+  else if(address >= REGION_PRIVATE_START &&
+          address + addr->size < REGION_PRIVATE_END)
+    e = MMU_REGION_PRIVATE;
+  else
+    e = MMU_REGION_PUB;
+
+  if (simple_map) {
+    //TODO: should check bus addr
+    //MMU_ON_ERROR(SMCheckAddress(e, addr->virtual_address));
+
+    SMCreateNode(e, &p, page_count);
+    MMUDEBUG(" *****Node map size*****%d\n", page_count);
+
+    p->buf_bus_address     = addr->bus_address;
+    p->process_id          = GetProcessID();
+    p->filp                = NULL;
+
+    p->mtlb_start = ((address + map_shift) >> MMU_MTLB_SHIFT);
+    p->stlb_start = ((address + map_shift) >> MMU_STLB_4K_SHIFT ) & 0x3FF;
+    p->mtlb_end   = (page_count + p->stlb_start) / MMU_STLB_4K_ENTRY_NUM +
+                     p->mtlb_start;
+    p->stlb_end   = (page_count + p->stlb_start) % MMU_STLB_4K_ENTRY_NUM;
+    p->page_count = page_count;
+
+    for(i = 0;i < page_count; i++) {
+      /* this function used in kernel only, so we think it's a contunuous buffer*/
+      address += (i ? PAGE_SIZE : 0);
+      GetPageEntry(p, &page_table_entry, i);
+      ext_addr = ((u32)(address>>32))&0xff;
+      page_entry_value = (address & 0xFFFFF000)
+                        /* ext address , physical address bits [39,32]*/
+                        | (ext_addr << 4)
+                        /* writable */
+                        | (1 << 2)
+                        /* Ignore exception */
+                        | (0 << 1)
+                        /* Present */
+                        | (1 << 0);
+      WritePageEntry(page_table_entry, page_entry_value);
+    }
+
+    /* Purpose of Bare_metal mode: input bus address==mmu address*/
+    addr->mmu_bus_address = p->mtlb_start << MMU_MTLB_SHIFT
+                            | p->stlb_start << MMU_STLB_4K_SHIFT;
+  } else {
+    MMU_ON_ERROR(FindFreeNode(e, &p, page_count));
+
+    SplitFreeNode(e, &p, page_count);
+    MMUDEBUG(" *****Node map size*****%d\n", p->page_count);
+
+    p->buf_bus_address     = addr->bus_address;
+    p->process_id          = GetProcessID();
+    p->filp                = NULL;
+
+    for(i = 0;i < page_count; i++) {
+      /* this function used in kernel only, so we think it's a contunuous buffer*/
+      address += (i ? PAGE_SIZE : 0);
+      GetPageEntry(p, &page_table_entry, i);
+      ext_addr = ((u32)(address>>32))&0xff;
+      page_entry_value = (address & 0xFFFFF000)
+                        /* ext address , physical address bits [39,32]*/
+                        | (ext_addr << 4)
+                        /* writable */
+                        | (1 << 2)
+                        /* Ignore exception */
+                        | (0 << 1)
+                        /* Present */
+                        | (1 << 0);
+      WritePageEntry(page_table_entry, page_entry_value);
+    }
+    addr->mmu_bus_address = p->mtlb_start << MMU_MTLB_SHIFT
+                            | p->stlb_start << MMU_STLB_4K_SHIFT;
+  }
+  MMUDEBUG(" KERNEL MMU_MTLB_SHIFT %d MMU_STLB_4K_SHIFT %d\n", MMU_MTLB_SHIFT, MMU_STLB_4K_SHIFT);
+  MMUDEBUG(" MMUKernelMemNodeMap map total %d pages in region %d\nMTLB/STLB starts %d/%d, MTLB/STLB ends %d/%d\n",
+             page_count, (u32)e, p->mtlb_start, p->stlb_start, p->mtlb_end, p->stlb_end);
+  MMUDEBUG(" MMUKernelMemNodeMap map 0x%llx -> 0x%08x\n", addr->bus_address, addr->mmu_bus_address);
+
+  ReleaseMutex(g_mmu->page_table_mutex);
+
+  return MMU_STATUS_OK;
+
+onerror:
+  if (mutex) {
+    ReleaseMutex(g_mmu->page_table_mutex);
+  }
+  MMUDEBUG(" *****MMU Map Error*****\n");
+  return status;
+}
+
+enum MMUStatus MMUKernelMemNodeUnmap(struct kernel_addr_desc *addr) {
+  unsigned int i;
+  unsigned long long address = 0x0;
+  unsigned int *page_table_entry;
+  int process_id = GetProcessID();
+  enum MMURegion e = MMU_REGION_COUNT;
+  enum MMUStatus status = MMU_STATUS_OUT_OF_MEMORY;
+  struct MMUNode *p;
+  unsigned int mutex = MMU_FALSE;
+
+  MMUDEBUG(" *****MMU Unmap*****\n");
+  AcquireMutex(g_mmu->page_table_mutex, MMU_INFINITE);
+  mutex = MMU_TRUE;
+
+  address = addr->bus_address;
+  if(address >= REGION_IN_START &&
+     address < REGION_IN_END)
+    e = MMU_REGION_IN;
+  else if(address >= REGION_OUT_START &&
+          address < REGION_OUT_END)
+    e = MMU_REGION_OUT;
+  else if(address >= REGION_PRIVATE_START &&
+          address < REGION_PRIVATE_END)
+    e = MMU_REGION_PRIVATE;
+  else
+    e = MMU_REGION_PUB;
+
+  if (simple_map)
+    p = g_mmu->region[e].simple_map_head->next;
+  else
+    p = g_mmu->region[e].map_head->next;
+  /* Reset STLB of the node */
+  while(p) {
+    if(p->buf_bus_address == addr->bus_address &&
+        p->process_id == process_id) {
+      for(i = 0;i < p->page_count; i++) {
+        GetPageEntry(p, &page_table_entry, i);
+        address = 0;
+        WritePageEntry(page_table_entry, address);
+      }
+      break;
+    }
+    p = p->next;
+  }
+  if(!p)
+    goto onerror;
+
+  if (simple_map)
+    SMRemoveKernelNode(e, addr->bus_address, process_id);
+  else
+    RemoveKernelNode(e, addr->bus_address, process_id);
+
+  ReleaseMutex(g_mmu->page_table_mutex);
+  return MMU_STATUS_OK;
+
+onerror:
+  if (mutex) {
+    ReleaseMutex(g_mmu->page_table_mutex);
+  }
+  MMUDEBUG(" *****MMU Unmap Error*****\n");
+  return status;
+}
+
+
+static long MMUCtlBufferMap(struct file *filp, unsigned long arg) {
+  struct addr_desc addr;
+  long tmp;
+
+  tmp = copy_from_user(&addr, (void*)arg, sizeof(struct addr_desc));
+  if (tmp) {
+    MMUDEBUG("copy_from_user failed, returned %li\n", tmp);
+    return -MMU_EFAULT;
+  }
+
+  MMUMemNodeMap(&addr, filp);
+
+  tmp = copy_to_user((void*) arg, &addr, sizeof(struct addr_desc));
+  if (tmp) {
+    MMUDEBUG("copy_to_user failed, returned %li\n", tmp);
+    return -MMU_EFAULT;
+  }
+  return 0;
+}
+
+static long MMUCtlBufferUnmap(unsigned long arg) {
+  struct addr_desc addr;
+  long tmp;
+
+  tmp = copy_from_user(&addr, (void*)arg, sizeof(struct addr_desc));
+  if (tmp) {
+    MMUDEBUG("copy_from_user failed, returned %li\n", tmp);
+    return -MMU_EFAULT;
+  }
+
+  MMUMemNodeUnmap(&addr);
+  return 0;
+}
+
+static long MMUCtlFlush(unsigned long arg, volatile unsigned char *hwregs[HXDEC_MAX_CORES][2]) {
+  unsigned int core_id;
+  long tmp;
+
+  tmp = copy_from_user(&core_id, (void*)arg, sizeof(unsigned int));
+  if (tmp) {
+    MMUDEBUG("copy_from_user failed, returned %li\n", tmp);
+    return -MMU_EFAULT;
+  }
+
+  MMUFlush(core_id, hwregs);
+
+  return 0;
+}
+
+long MMUIoctl(unsigned int cmd, void *filp, unsigned long arg,
+                  volatile unsigned char *hwregs[HXDEC_MAX_CORES][2]) {
+
+  u32 i = 0;
+  for (i = 0; i < MAX_SUBSYS_NUM; i++) {
+    if (hwregs[i][0] != NULL &&
+        (ioread32((void*)(hwregs[i][0] + MMU_REG_HW_ID))>>16) != 0x4D4D)
+      return -MMU_ENOTTY;
+    if (hwregs[i][1] != NULL &&
+        (ioread32((void*)(hwregs[i][1] + MMU_REG_HW_ID))>>16) != 0x4D4D)
+      return -MMU_ENOTTY;
+  }
+
+  switch (cmd) {
+  case HANTRO_IOCS_MMU_MEM_MAP: {
+    return (MMUCtlBufferMap((struct file *)filp, arg));
+  }
+  case HANTRO_IOCS_MMU_MEM_UNMAP: {
+    return (MMUCtlBufferUnmap(arg));
+  }
+  case HANTRO_IOCS_MMU_FLUSH: {
+    return (MMUCtlFlush(arg, hwregs));
+  }
+  default:
+    return -MMU_ENOTTY;
+  }
+}
+
+void MMURestore(volatile unsigned char *hwregs[MAX_SUBSYS_NUM][2])
+{
+  if (g_mmu == NULL)
+    return;
+
+  int i;
+  unsigned int address;
+  u32 address_ext;
+  address = g_mmu->page_table_array_physical;
+  address_ext = ((u32)(g_mmu->page_table_array_physical >> 32))&0xff;
+  for (i = 0; i < MAX_SUBSYS_NUM; i++) {
+    if (hwregs[i][0] != NULL) {
+      iowrite32(address, (void*)(hwregs[i][0] + MMU_REG_ADDRESS));
+      iowrite32(address_ext, (void *)(hwregs[i][0] + MMU_REG_ADDRESS_MSB));
+
+      iowrite32(0x10000, (void*)(hwregs[i][0] + MMU_REG_PAGE_TABLE_ID));
+      iowrite32(0x00000, (void*)(hwregs[i][0] + MMU_REG_PAGE_TABLE_ID));
+
+      iowrite32(1, (void*)(hwregs[i][0] + MMU_REG_CONTROL));
+    }
+    if (hwregs[i][1] != NULL) {
+      iowrite32(address, (void*)(hwregs[i][1] + MMU_REG_ADDRESS));
+      iowrite32(address_ext, (void *)(hwregs[i][1] + MMU_REG_ADDRESS_MSB));
+
+      iowrite32(0x10000, (void*)(hwregs[i][1] + MMU_REG_PAGE_TABLE_ID));
+      iowrite32(0x00000, (void*)(hwregs[i][1] + MMU_REG_PAGE_TABLE_ID));
+
+      iowrite32(1, (void*)(hwregs[i][1] + MMU_REG_CONTROL));
+    }
+  }
+
+}

+ 4033 - 0
linux/subsys_driver/hantro_vcmd.c

@@ -0,0 +1,4033 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2021 VERISILICON
+*
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2021 VERISILICON
+*
+*    This program is free software; you can redistribute it and/or
+*    modify it under the terms of the GNU General Public License
+*    as published by the Free Software Foundation; either version 2
+*    of the License, or (at your option) any later version.
+*
+*    This program is distributed in the hope that it will be useful,
+*    but WITHOUT ANY WARRANTY; without even the implied warranty of
+*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*    GNU General Public License for more details.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+/* needed for __init,__exit directives */
+#include <linux/init.h>
+/* needed for remap_page_range
+    SetPageReserved
+    ClearPageReserved
+*/
+#include <linux/mm.h>
+/* obviously, for kmalloc */
+#include <linux/slab.h>
+/* for struct file_operations, register_chrdev() */
+#include <linux/fs.h>
+/* standard error codes */
+#include <linux/errno.h>
+
+#include <linux/moduleparam.h>
+/* request_irq(), free_irq() */
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+
+#include <linux/semaphore.h>
+#include <linux/spinlock.h>
+/* needed for virt_to_phys() */
+#include <asm/io.h>
+#include <linux/pci.h>
+#include <linux/uaccess.h>
+#include <linux/ioport.h>
+
+#include <asm/irq.h>
+
+#include <linux/version.h>
+#include <linux/vmalloc.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/pm_runtime.h>
+
+/* our own stuff */
+#include <linux/platform_device.h>
+#include "vcmdswhwregisters.h"
+#include "bidirect_list.h"
+#include "vcmdswhwregisters.h"
+#include "hantrovcmd.h"
+#include "subsys.h"
+
+/*
+ * Macros to help debugging
+ */
+
+#undef PDEBUG   /* undef it, just in case */
+//#define  HANTRO_VCMD_DRIVER_DEBUG
+#ifdef HANTRO_VCMD_DRIVER_DEBUG
+#  ifdef __KERNEL__
+    /* This one if debugging is on, and kernel space */
+#    define PDEBUG(fmt, args...) printk( KERN_INFO "vc8000_vcmd: " fmt, ## args)
+#  else
+    /* This one for user space */
+#    define PDEBUG(fmt, args...) printf(__FILE__ ":%d: " fmt, __LINE__ , ## args)
+#  endif
+#else
+#  define PDEBUG(fmt, args...)  /* not debugging: nothing */
+#endif
+
+/*------------------------------------------------------------------------
+*****************************VCMD CONFIGURATION BY CUSTOMER********************************
+-------------------------------------------------------------------------*/
+//video encoder vcmd configuration
+
+#define VCMD_ENC_IO_ADDR_0                      0x90000   /*customer specify according to own platform*/
+#define VCMD_ENC_IO_SIZE_0                      (ASIC_VCMD_SWREG_AMOUNT * 4)    /* bytes */
+#define VCMD_ENC_INT_PIN_0                      -1
+#define VCMD_ENC_MODULE_TYPE_0                  0
+#define VCMD_ENC_MODULE_MAIN_ADDR_0             0x0000    /*customer specify according to own platform*/
+#define VCMD_ENC_MODULE_DEC400_ADDR_0           0XFFFF    /*0xffff means no such kind of submodule*/
+#define VCMD_ENC_MODULE_L2CACHE_ADDR_0          0XFFFF
+#define VCMD_ENC_MODULE_MMU_ADDR_0              0XFFFF
+
+#define VCMD_ENC_IO_ADDR_1                      0x91000   /*customer specify according to own platform*/
+#define VCMD_ENC_IO_SIZE_1                      (ASIC_VCMD_SWREG_AMOUNT * 4)    /* bytes */
+#define VCMD_ENC_INT_PIN_1                      -1
+#define VCMD_ENC_MODULE_TYPE_1                  0
+#define VCMD_ENC_MODULE_MAIN_ADDR_1             0x0000    /*customer specify according to own platform*/
+#define VCMD_ENC_MODULE_DEC400_ADDR_1           0XFFFF    /*0xffff means no such kind of submodule*/
+#define VCMD_ENC_MODULE_L2CACHE_ADDR_1          0XFFFF
+#define VCMD_ENC_MODULE_MMU_ADDR_1              0XFFFF
+
+#define VCMD_ENC_IO_ADDR_2                      0x92000   /*customer specify according to own platform*/
+#define VCMD_ENC_IO_SIZE_2                      (ASIC_VCMD_SWREG_AMOUNT * 4)    /* bytes */
+#define VCMD_ENC_INT_PIN_2                      -1
+#define VCMD_ENC_MODULE_TYPE_2                  0
+#define VCMD_ENC_MODULE_MAIN_ADDR_2             0x0000    /*customer specify according to own platform*/
+#define VCMD_ENC_MODULE_DEC400_ADDR_2           0XFFFF    /*0xffff means no such kind of submodule*/
+#define VCMD_ENC_MODULE_L2CACHE_ADDR_2          0XFFFF
+#define VCMD_ENC_MODULE_MMU_ADDR_2              0XFFFF
+
+#define VCMD_ENC_IO_ADDR_3                      0x93000   /*customer specify according to own platform*/
+#define VCMD_ENC_IO_SIZE_3                      (ASIC_VCMD_SWREG_AMOUNT * 4)    /* bytes */
+#define VCMD_ENC_INT_PIN_3                      -1
+#define VCMD_ENC_MODULE_TYPE_3                  0
+#define VCMD_ENC_MODULE_MAIN_ADDR_3             0x0000    /*customer specify according to own platform*/
+#define VCMD_ENC_MODULE_DEC400_ADDR_3           0XFFFF    /*0xffff means no such kind of submodule*/
+#define VCMD_ENC_MODULE_L2CACHE_ADDR_3          0XFFFF
+#define VCMD_ENC_MODULE_MMU_ADDR_3              0XFFFF
+
+//video encoder cutree/IM  vcmd configuration
+
+
+#define VCMD_IM_IO_ADDR_0                      0xa0000    /*customer specify according to own platform*/
+#define VCMD_IM_IO_SIZE_0                      (ASIC_VCMD_SWREG_AMOUNT * 4)    /* bytes */
+#define VCMD_IM_INT_PIN_0                      -1
+#define VCMD_IM_MODULE_TYPE_0                  1
+#define VCMD_IM_MODULE_MAIN_ADDR_0             0x0000     /*customer specify according to own platform*/
+#define VCMD_IM_MODULE_DEC400_ADDR_0           0XFFFF     /*0xffff means no such kind of submodule*/
+#define VCMD_IM_MODULE_L2CACHE_ADDR_0          0XFFFF
+#define VCMD_IM_MODULE_MMU_ADDR_0              0XFFFF
+
+#define VCMD_IM_IO_ADDR_1                      0xa1000    /*customer specify according to own platform*/
+#define VCMD_IM_IO_SIZE_1                      (ASIC_VCMD_SWREG_AMOUNT * 4)    /* bytes */
+#define VCMD_IM_INT_PIN_1                      -1
+#define VCMD_IM_MODULE_TYPE_1                  1
+#define VCMD_IM_MODULE_MAIN_ADDR_1             0x0000     /*customer specify according to own platform*/
+#define VCMD_IM_MODULE_DEC400_ADDR_1           0XFFFF     /*0xffff means no such kind of submodule*/
+#define VCMD_IM_MODULE_L2CACHE_ADDR_1          0XFFFF
+#define VCMD_IM_MODULE_MMU_ADDR_1              0XFFFF
+
+#define VCMD_IM_IO_ADDR_2                      0xa2000    /*customer specify according to own platform*/
+#define VCMD_IM_IO_SIZE_2                      (ASIC_VCMD_SWREG_AMOUNT * 4)    /* bytes */
+#define VCMD_IM_INT_PIN_2                      -1
+#define VCMD_IM_MODULE_TYPE_2                  1
+#define VCMD_IM_MODULE_MAIN_ADDR_2             0x0000     /*customer specify according to own platform*/
+#define VCMD_IM_MODULE_DEC400_ADDR_2           0XFFFF     /*0xffff means no such kind of submodule*/
+#define VCMD_IM_MODULE_L2CACHE_ADDR_2          0XFFFF
+#define VCMD_IM_MODULE_MMU_ADDR_2              0XFFFF
+
+#define VCMD_IM_IO_ADDR_3                      0xa3000    /*customer specify according to own platform*/
+#define VCMD_IM_IO_SIZE_3                      (ASIC_VCMD_SWREG_AMOUNT * 4)    /* bytes */
+#define VCMD_IM_INT_PIN_3                      -1
+#define VCMD_IM_MODULE_TYPE_3                  1
+#define VCMD_IM_MODULE_MAIN_ADDR_3             0x0000     /*customer specify according to own platform*/
+#define VCMD_IM_MODULE_DEC400_ADDR_3           0XFFFF     /*0xffff means no such kind of submodule*/
+#define VCMD_IM_MODULE_L2CACHE_ADDR_3          0XFFFF
+#define VCMD_IM_MODULE_MMU_ADDR_3              0XFFFF
+
+//video decoder vcmd configuration
+
+
+#define VCMD_DEC_IO_ADDR_0                      0x600000   /*customer specify according to own platform*/
+#define VCMD_DEC_IO_SIZE_0                      (ASIC_VCMD_SWREG_AMOUNT * 4)    /* bytes */
+#define VCMD_DEC_INT_PIN_0                      -1
+#define VCMD_DEC_MODULE_TYPE_0                  2
+#define VCMD_DEC_MODULE_MAIN_ADDR_0             0x1000    /*customer specify according to own platform*/
+#define VCMD_DEC_MODULE_DEC400_ADDR_0           0XFFFF    /*0xffff means no such kind of submodule*/
+#define VCMD_DEC_MODULE_L2CACHE_ADDR_0          0X2000
+#define VCMD_DEC_MODULE_MMU_ADDR_0              0XFFFF
+
+
+#define VCMD_DEC_IO_ADDR_1                      0x700000   /*customer specify according to own platform*/
+#define VCMD_DEC_IO_SIZE_1                      (ASIC_VCMD_SWREG_AMOUNT * 4)    /* bytes */
+#define VCMD_DEC_INT_PIN_1                      -1
+#define VCMD_DEC_MODULE_TYPE_1                  2
+#define VCMD_DEC_MODULE_MAIN_ADDR_1             0x1000    /*customer specify according to own platform*/
+#define VCMD_DEC_MODULE_DEC400_ADDR_1           0XFFFF    /*0xffff means no such kind of submodule*/
+#define VCMD_DEC_MODULE_L2CACHE_ADDR_1          0X2000
+#define VCMD_DEC_MODULE_MMU_ADDR_1              0XFFFF
+
+#define VCMD_DEC_IO_ADDR_2                      0xb2000   /*customer specify according to own platform*/
+#define VCMD_DEC_IO_SIZE_2                      (ASIC_VCMD_SWREG_AMOUNT * 4)    /* bytes */
+#define VCMD_DEC_INT_PIN_2                      -1
+#define VCMD_DEC_MODULE_TYPE_2                  2
+#define VCMD_DEC_MODULE_MAIN_ADDR_2             0x0000    /*customer specify according to own platform*/
+#define VCMD_DEC_MODULE_DEC400_ADDR_2           0XFFFF    /*0xffff means no such kind of submodule*/
+#define VCMD_DEC_MODULE_L2CACHE_ADDR_2          0XFFFF
+#define VCMD_DEC_MODULE_MMU_ADDR_2              0XFFFF
+
+#define VCMD_DEC_IO_ADDR_3                      0xb3000   /*customer specify according to own platform*/
+#define VCMD_DEC_IO_SIZE_3                      (ASIC_VCMD_SWREG_AMOUNT * 4)    /* bytes */
+#define VCMD_DEC_INT_PIN_3                      -1
+#define VCMD_DEC_MODULE_TYPE_3                  2
+#define VCMD_DEC_MODULE_MAIN_ADDR_3             0x0000    /*customer specify according to own platform*/
+#define VCMD_DEC_MODULE_DEC400_ADDR_3           0XFFFF    /*0xffff means no such kind of submodule*/
+#define VCMD_DEC_MODULE_L2CACHE_ADDR_3          0XFFFF
+#define VCMD_DEC_MODULE_MMU_ADDR_3              0XFFFF
+
+//JPEG encoder vcmd configuration
+
+#define VCMD_JPEGE_IO_ADDR_0                      0x90000   /*customer specify according to own platform*/
+#define VCMD_JPEGE_IO_SIZE_0                      (ASIC_VCMD_SWREG_AMOUNT * 4)    /* bytes */
+#define VCMD_JPEGE_INT_PIN_0                      -1
+#define VCMD_JPEGE_MODULE_TYPE_0                  3
+#define VCMD_JPEGE_MODULE_MAIN_ADDR_0             0x1000    /*customer specify according to own platform*/
+#define VCMD_JPEGE_MODULE_DEC400_ADDR_0           0XFFFF    /*0xffff means no such kind of submodule*/
+#define VCMD_JPEGE_MODULE_L2CACHE_ADDR_0          0XFFFF
+#define VCMD_JPEGE_MODULE_MMU_ADDR_0              0XFFFF
+
+#define VCMD_JPEGE_IO_ADDR_1                      0xC1000   /*customer specify according to own platform*/
+#define VCMD_JPEGE_IO_SIZE_1                      (ASIC_VCMD_SWREG_AMOUNT * 4)    /* bytes */
+#define VCMD_JPEGE_INT_PIN_1                      -1
+#define VCMD_JPEGE_MODULE_TYPE_1                  3
+#define VCMD_JPEGE_MODULE_MAIN_ADDR_1             0x0000    /*customer specify according to own platform*/
+#define VCMD_JPEGE_MODULE_DEC400_ADDR_1           0XFFFF    /*0xffff means no such kind of submodule*/
+#define VCMD_JPEGE_MODULE_L2CACHE_ADDR_1          0XFFFF
+#define VCMD_JPEGE_MODULE_MMU_ADDR_1              0XFFFF
+
+#define VCMD_JPEGE_IO_ADDR_2                      0xC2000   /*customer specify according to own platform*/
+#define VCMD_JPEGE_IO_SIZE_2                      (ASIC_VCMD_SWREG_AMOUNT * 4)    /* bytes */
+#define VCMD_JPEGE_INT_PIN_2                      -1
+#define VCMD_JPEGE_MODULE_TYPE_2                  3
+#define VCMD_JPEGE_MODULE_MAIN_ADDR_2             0x0000    /*customer specify according to own platform*/
+#define VCMD_JPEGE_MODULE_DEC400_ADDR_2           0XFFFF    /*0xffff means no such kind of submodule*/
+#define VCMD_JPEGE_MODULE_L2CACHE_ADDR_2          0XFFFF
+#define VCMD_JPEGE_MODULE_MMU_ADDR_2              0XFFFF
+
+#define VCMD_JPEGE_IO_ADDR_3                      0xC3000   /*customer specify according to own platform*/
+#define VCMD_JPEGE_IO_SIZE_3                      (ASIC_VCMD_SWREG_AMOUNT * 4)    /* bytes */
+#define VCMD_JPEGE_INT_PIN_3                      -1
+#define VCMD_JPEGE_MODULE_TYPE_3                  3
+#define VCMD_JPEGE_MODULE_MAIN_ADDR_3             0x0000    /*customer specify according to own platform*/
+#define VCMD_JPEGE_MODULE_DEC400_ADDR_3           0XFFFF    /*0xffff means no such kind of submodule*/
+#define VCMD_JPEGE_MODULE_L2CACHE_ADDR_3          0XFFFF
+#define VCMD_JPEGE_MODULE_MMU_ADDR_3              0XFFFF
+
+
+//JPEG decoder vcmd configuration
+
+#define VCMD_JPEGD_IO_ADDR_0                      0x600000   /*customer specify according to own platform*/
+#define VCMD_JPEGD_IO_SIZE_0                      (ASIC_VCMD_SWREG_AMOUNT * 4)    /* bytes */
+#define VCMD_JPEGD_INT_PIN_0                      -1
+#define VCMD_JPEGD_MODULE_TYPE_0                  4
+#define VCMD_JPEGD_MODULE_MAIN_ADDR_0             0x1000    /*customer specify according to own platform*/
+#define VCMD_JPEGD_MODULE_DEC400_ADDR_0           0XFFFF    /*0xffff means no such kind of submodule*/
+#define VCMD_JPEGD_MODULE_L2CACHE_ADDR_0          0XFFFF
+#define VCMD_JPEGD_MODULE_MMU_ADDR_0              0XFFFF
+
+#define VCMD_JPEGD_IO_ADDR_1                      0xD1000   /*customer specify according to own platform*/
+#define VCMD_JPEGD_IO_SIZE_1                      (ASIC_VCMD_SWREG_AMOUNT * 4)    /* bytes */
+#define VCMD_JPEGD_INT_PIN_1                      -1
+#define VCMD_JPEGD_MODULE_TYPE_1                  4
+#define VCMD_JPEGD_MODULE_MAIN_ADDR_1             0x0000    /*customer specify according to own platform*/
+#define VCMD_JPEGD_MODULE_DEC400_ADDR_1           0XFFFF    /*0xffff means no such kind of submodule*/
+#define VCMD_JPEGD_MODULE_L2CACHE_ADDR_1          0XFFFF
+#define VCMD_JPEGD_MODULE_MMU_ADDR_1              0XFFFF
+
+#define VCMD_JPEGD_IO_ADDR_2                      0xD2000   /*customer specify according to own platform*/
+#define VCMD_JPEGD_IO_SIZE_2                      (ASIC_VCMD_SWREG_AMOUNT * 4)    /* bytes */
+#define VCMD_JPEGD_INT_PIN_2                      -1
+#define VCMD_JPEGD_MODULE_TYPE_2                  4
+#define VCMD_JPEGD_MODULE_MAIN_ADDR_2             0x0000    /*customer specify according to own platform*/
+#define VCMD_JPEGD_MODULE_DEC400_ADDR_2           0XFFFF    /*0xffff means no such kind of submodule*/
+#define VCMD_JPEGD_MODULE_L2CACHE_ADDR_2          0XFFFF
+#define VCMD_JPEGD_MODULE_MMU_ADDR_2              0XFFFF
+
+#define VCMD_JPEGD_IO_ADDR_3                      0xD3000   /*customer specify according to own platform*/
+#define VCMD_JPEGD_IO_SIZE_3                      (ASIC_VCMD_SWREG_AMOUNT * 4)    /* bytes */
+#define VCMD_JPEGD_INT_PIN_3                      -1
+#define VCMD_JPEGD_MODULE_TYPE_3                  4
+#define VCMD_JPEGD_MODULE_MAIN_ADDR_3             0x0000    /*customer specify according to own platform*/
+#define VCMD_JPEGD_MODULE_DEC400_ADDR_3           0XFFFF    /*0xffff means no such kind of submodule*/
+#define VCMD_JPEGD_MODULE_L2CACHE_ADDR_3          0XFFFF
+#define VCMD_JPEGD_MODULE_MMU_ADDR_3              0XFFFF
+
+/*for all vcmds, the core info should be listed here for subsequent use*/
+struct vcmd_config vcmd_core_array[MAX_SUBSYS_NUM]= {
+#if 0
+    //encoder configuration
+    {VCMD_ENC_IO_ADDR_0,
+    VCMD_ENC_IO_SIZE_0,
+    VCMD_ENC_INT_PIN_0,
+    VCMD_ENC_MODULE_TYPE_0,
+    VCMD_ENC_MODULE_MAIN_ADDR_0,
+    VCMD_ENC_MODULE_DEC400_ADDR_0,
+    VCMD_ENC_MODULE_L2CACHE_ADDR_0,
+    VCMD_ENC_MODULE_MMU_ADDR_0},
+
+    {VCMD_ENC_IO_ADDR_1,
+    VCMD_ENC_IO_SIZE_1,
+    VCMD_ENC_INT_PIN_1,
+    VCMD_ENC_MODULE_TYPE_1,
+    VCMD_ENC_MODULE_MAIN_ADDR_1,
+    VCMD_ENC_MODULE_DEC400_ADDR_1,
+    VCMD_ENC_MODULE_L2CACHE_ADDR_1,
+    VCMD_ENC_MODULE_MMU_ADDR_1},
+
+    {VCMD_ENC_IO_ADDR_2,
+    VCMD_ENC_IO_SIZE_2,
+    VCMD_ENC_INT_PIN_2,
+    VCMD_ENC_MODULE_TYPE_2,
+    VCMD_ENC_MODULE_MAIN_ADDR_2,
+    VCMD_ENC_MODULE_DEC400_ADDR_2,
+    VCMD_ENC_MODULE_L2CACHE_ADDR_2,
+    VCMD_ENC_MODULE_MMU_ADDR_2},
+
+    {VCMD_ENC_IO_ADDR_3,
+    VCMD_ENC_IO_SIZE_3,
+    VCMD_ENC_INT_PIN_3,
+    VCMD_ENC_MODULE_TYPE_3,
+    VCMD_ENC_MODULE_MAIN_ADDR_3,
+    VCMD_ENC_MODULE_DEC400_ADDR_3,
+    VCMD_ENC_MODULE_L2CACHE_ADDR_3,
+    VCMD_ENC_MODULE_MMU_ADDR_3},
+
+    //cutree/IM configuration
+
+    {VCMD_IM_IO_ADDR_0,
+    VCMD_IM_IO_SIZE_0,
+    VCMD_IM_INT_PIN_0,
+    VCMD_IM_MODULE_TYPE_0,
+    VCMD_IM_MODULE_MAIN_ADDR_0,
+    VCMD_IM_MODULE_DEC400_ADDR_0,
+    VCMD_IM_MODULE_L2CACHE_ADDR_0,
+    VCMD_IM_MODULE_MMU_ADDR_0},
+
+    {VCMD_IM_IO_ADDR_1,
+    VCMD_IM_IO_SIZE_1,
+    VCMD_IM_INT_PIN_1,
+    VCMD_IM_MODULE_TYPE_1,
+    VCMD_IM_MODULE_MAIN_ADDR_1,
+    VCMD_IM_MODULE_DEC400_ADDR_1,
+    VCMD_IM_MODULE_L2CACHE_ADDR_1,
+    VCMD_IM_MODULE_MMU_ADDR_1},
+
+    {VCMD_IM_IO_ADDR_2,
+    VCMD_IM_IO_SIZE_2,
+    VCMD_IM_INT_PIN_2,
+    VCMD_IM_MODULE_TYPE_2,
+    VCMD_IM_MODULE_MAIN_ADDR_2,
+    VCMD_IM_MODULE_DEC400_ADDR_2,
+    VCMD_IM_MODULE_L2CACHE_ADDR_2,
+    VCMD_IM_MODULE_MMU_ADDR_2},
+
+    {VCMD_IM_IO_ADDR_3,
+    VCMD_IM_IO_SIZE_3,
+    VCMD_IM_INT_PIN_3,
+    VCMD_IM_MODULE_TYPE_3,
+    VCMD_IM_MODULE_MAIN_ADDR_3,
+    VCMD_IM_MODULE_DEC400_ADDR_3,
+    VCMD_IM_MODULE_L2CACHE_ADDR_3,
+    VCMD_IM_MODULE_MMU_ADDR_3},
+#endif
+
+    //decoder configuration
+    {VCMD_DEC_IO_ADDR_0,
+    VCMD_DEC_IO_SIZE_0,
+    VCMD_DEC_INT_PIN_0,
+    VCMD_DEC_MODULE_TYPE_0,
+    VCMD_DEC_MODULE_MAIN_ADDR_0,
+    VCMD_DEC_MODULE_DEC400_ADDR_0,
+    VCMD_DEC_MODULE_L2CACHE_ADDR_0,
+    VCMD_DEC_MODULE_MMU_ADDR_0},
+
+    {VCMD_DEC_IO_ADDR_1,
+    VCMD_DEC_IO_SIZE_1,
+    VCMD_DEC_INT_PIN_1,
+    VCMD_DEC_MODULE_TYPE_1,
+    VCMD_DEC_MODULE_MAIN_ADDR_1,
+    VCMD_DEC_MODULE_DEC400_ADDR_1,
+    VCMD_DEC_MODULE_L2CACHE_ADDR_1,
+    VCMD_DEC_MODULE_MMU_ADDR_1},
+
+#if 0
+    {VCMD_DEC_IO_ADDR_2,
+    VCMD_DEC_IO_SIZE_2,
+    VCMD_DEC_INT_PIN_2,
+    VCMD_DEC_MODULE_TYPE_2,
+    VCMD_DEC_MODULE_MAIN_ADDR_2,
+    VCMD_DEC_MODULE_DEC400_ADDR_2,
+    VCMD_DEC_MODULE_L2CACHE_ADDR_2,
+    VCMD_DEC_MODULE_MMU_ADDR_2},
+
+    {VCMD_DEC_IO_ADDR_3,
+    VCMD_DEC_IO_SIZE_3,
+    VCMD_DEC_INT_PIN_3,
+    VCMD_DEC_MODULE_TYPE_3,
+    VCMD_DEC_MODULE_MAIN_ADDR_3,
+    VCMD_DEC_MODULE_DEC400_ADDR_3,
+    VCMD_DEC_MODULE_L2CACHE_ADDR_3,
+    VCMD_DEC_MODULE_MMU_ADDR_3},
+#endif
+#if 0
+    //JPEG encoder configuration
+    {VCMD_JPEGE_IO_ADDR_0,
+    VCMD_JPEGE_IO_SIZE_0,
+    VCMD_JPEGE_INT_PIN_0,
+    VCMD_JPEGE_MODULE_TYPE_0,
+    VCMD_JPEGE_MODULE_MAIN_ADDR_0,
+    VCMD_JPEGE_MODULE_DEC400_ADDR_0,
+    VCMD_JPEGE_MODULE_L2CACHE_ADDR_0,
+    VCMD_JPEGE_MODULE_MMU_ADDR_0},
+#endif
+#if 0
+    {VCMD_JPEGE_IO_ADDR_1,
+    VCMD_JPEGE_IO_SIZE_1,
+    VCMD_JPEGE_INT_PIN_1,
+    VCMD_JPEGE_MODULE_TYPE_1,
+    VCMD_JPEGE_MODULE_MAIN_ADDR_1,
+    VCMD_JPEGE_MODULE_DEC400_ADDR_1,
+    VCMD_JPEGE_MODULE_L2CACHE_ADDR_1,
+    VCMD_JPEGE_MODULE_MMU_ADDR_1},
+
+    {VCMD_JPEGE_IO_ADDR_2,
+    VCMD_JPEGE_IO_SIZE_2,
+    VCMD_JPEGE_INT_PIN_2,
+    VCMD_JPEGE_MODULE_TYPE_2,
+    VCMD_JPEGE_MODULE_MAIN_ADDR_2,
+    VCMD_JPEGE_MODULE_DEC400_ADDR_2,
+    VCMD_JPEGE_MODULE_L2CACHE_ADDR_2,
+    VCMD_JPEGE_MODULE_MMU_ADDR_2},
+
+    {VCMD_JPEGE_IO_ADDR_3,
+    VCMD_JPEGE_IO_SIZE_3,
+    VCMD_JPEGE_INT_PIN_3,
+    VCMD_JPEGE_MODULE_TYPE_3,
+    VCMD_JPEGE_MODULE_MAIN_ADDR_3,
+    VCMD_JPEGE_MODULE_DEC400_ADDR_3,
+    VCMD_JPEGE_MODULE_L2CACHE_ADDR_3,
+    VCMD_JPEGE_MODULE_MMU_ADDR_3},
+    //JPEG decoder configuration
+    {VCMD_JPEGD_IO_ADDR_0,
+    VCMD_JPEGD_IO_SIZE_0,
+    VCMD_JPEGD_INT_PIN_0,
+    VCMD_JPEGD_MODULE_TYPE_0,
+    VCMD_JPEGD_MODULE_MAIN_ADDR_0,
+    VCMD_JPEGD_MODULE_DEC400_ADDR_0,
+    VCMD_JPEGD_MODULE_L2CACHE_ADDR_0,
+    VCMD_JPEGD_MODULE_MMU_ADDR_0},
+
+    {VCMD_JPEGD_IO_ADDR_1,
+    VCMD_JPEGD_IO_SIZE_1,
+    VCMD_JPEGD_INT_PIN_1,
+    VCMD_JPEGD_MODULE_TYPE_1,
+    VCMD_JPEGD_MODULE_MAIN_ADDR_1,
+    VCMD_JPEGD_MODULE_DEC400_ADDR_1,
+    VCMD_JPEGD_MODULE_L2CACHE_ADDR_1,
+    VCMD_JPEGD_MODULE_MMU_ADDR_1},
+
+    {VCMD_JPEGD_IO_ADDR_2,
+    VCMD_JPEGD_IO_SIZE_2,
+    VCMD_JPEGD_INT_PIN_2,
+    VCMD_JPEGD_MODULE_TYPE_2,
+    VCMD_JPEGD_MODULE_MAIN_ADDR_2,
+    VCMD_JPEGD_MODULE_DEC400_ADDR_2,
+    VCMD_JPEGD_MODULE_L2CACHE_ADDR_2,
+    VCMD_JPEGD_MODULE_MMU_ADDR_2},
+
+    {VCMD_JPEGD_IO_ADDR_3,
+    VCMD_JPEGD_IO_SIZE_3,
+    VCMD_JPEGD_INT_PIN_3,
+    VCMD_JPEGD_MODULE_TYPE_3,
+    VCMD_JPEGD_MODULE_MAIN_ADDR_3,
+    VCMD_JPEGD_MODULE_DEC400_ADDR_3,
+    VCMD_JPEGD_MODULE_L2CACHE_ADDR_3,
+    VCMD_JPEGD_MODULE_MMU_ADDR_3},
+#endif
+};
+/*these size need to be modified according to hw config.*/
+#define VCMD_ENCODER_REGISTER_SIZE              (479 * 4)
+#define VCMD_DECODER_REGISTER_SIZE              (1023 * 4)
+#define VCMD_IM_REGISTER_SIZE                   (479 * 4)
+#define VCMD_JPEG_ENCODER_REGISTER_SIZE         (479 * 4)
+#define VCMD_JPEG_DECODER_REGISTER_SIZE         (1023 * 4)
+
+#define MAX_VCMD_NUMBER     (MAX_VCMD_TYPE*MAX_SAME_MODULE_TYPE_CORE_NUMBER)              //
+
+
+#define HW_WORK_STATE_PEND            3
+
+#define MAX_CMDBUF_INT_NUMBER         1
+#define INT_MIN_SUM_OF_IMAGE_SIZE    (4096*2160*MAX_SAME_MODULE_TYPE_CORE_NUMBER*MAX_CMDBUF_INT_NUMBER)
+#define MAX_PROCESS_CORE_NUMBER         4*8
+#define PROCESS_MAX_VIDEO_SIZE          (4096*2160*MAX_SAME_MODULE_TYPE_CORE_NUMBER*MAX_PROCESS_CORE_NUMBER)
+#define PROCESS_MAX_JPEG_SIZE           (2147483648) //32768*32768*2
+#define PROCESS_MAX_SUM_OF_IMAGE_SIZE   (PROCESS_MAX_VIDEO_SIZE>PROCESS_MAX_JPEG_SIZE?PROCESS_MAX_VIDEO_SIZE:PROCESS_MAX_JPEG_SIZE)
+
+
+#define MAX_SAME_MODULE_TYPE_CORE_NUMBER            4
+
+
+
+/*******************PCIE CONFIG*************************/
+
+/*******************PCIE CONFIG*************************/
+
+#define PCI_VENDOR_ID_HANTRO            0x10ee//0x16c3
+#define PCI_DEVICE_ID_HANTRO_PCI      0x8014// 0x7011
+
+/* Base address got control register */
+#define PCI_H2_BAR              4
+
+/* Base address DDR register */
+#define PCI_DDR_BAR             0
+
+
+static size_t base_ddr_addr = 0;              /*pcie address need to substract this value then can be put to register*/
+
+
+
+/********variables declaration related with race condition**********/
+
+#define CMDBUF_MAX_SIZE       (512*4*4)
+
+
+#define CMDBUF_POOL_TOTAL_SIZE     (2*1024*1024)        //approximately=128x(320x240)=128x2k=128x8kbyte=1Mbytes
+#define TOTAL_DISCRETE_CMDBUF_NUM (CMDBUF_POOL_TOTAL_SIZE/CMDBUF_MAX_SIZE)
+#define CMDBUF_VCMD_REGISTER_TOTAL_SIZE        9*1024*1024-CMDBUF_POOL_TOTAL_SIZE*2
+#define VCMD_REGISTER_SIZE       (128*4)
+
+#ifndef DYNAMIC_MALLOC_VCMDNODE
+static struct cmdbuf_obj *g_cmdbuf_obj_pool;
+static struct bi_list_node *g_cmdbuf_node_pool;
+#endif
+
+struct noncache_mem
+{
+  u32 *virtualAddress;
+  dma_addr_t  busAddress;
+  unsigned int mmu_bus_address;  /* buffer physical address in MMU*/
+  u32 size;
+  u16 cmdbuf_id;
+};
+
+struct process_manager_obj
+{
+    struct file *filp;
+    u64 total_exe_time;
+    spinlock_t spinlock;
+    u32 pm_count;
+    wait_queue_head_t wait_queue;
+} ;
+
+struct cmdbuf_obj
+{
+  u32 module_type;               //current CMDBUF type: input vc8000e=0,IM=1,vc8000d=2,jpege=3, jpegd=4
+  u32 priority;                  //current CMDBUFpriority: normal=0, high=1
+  u64 executing_time;           //current CMDBUFexecuting_time=encoded_image_size*(rdoLevel+1)*(rdoq+1);
+  u32 cmdbuf_size;              //current CMDBUF size
+  u32 *cmdbuf_virtualAddress;   //current CMDBUF start virtual address.
+  size_t cmdbuf_busAddress;      //current CMDBUF start physical address.
+  unsigned int mmu_cmdbuf_busAddress;      //current CMDBUF start mmu mapping address.
+  u32 *status_virtualAddress;   //current status CMDBUF start virtual address.
+  size_t status_busAddress;      //current status CMDBUF start physical address.
+  unsigned int mmu_status_busAddress;      //current status CMDBUF start mmu mapping address.
+  u32 status_size;              //current status CMDBUF size
+  u32 executing_status;          //current CMDBUF executing status.
+  struct file *filp;            //file pointer in the same process.
+  u16 core_id;                  //which vcmd core is used.
+  u16 cmdbuf_id;                 //used to manage CMDBUF in driver.It is a handle to identify cmdbuf.also is an interrupt vector.position in pool,same as status position.
+  u8 cmdbuf_data_loaded;        //0 means sw has not copied data into this CMDBUF; 1 means sw has copied data into this CMDBUF
+  u8 cmdbuf_data_linked;        //0 :not linked, 1:linked.
+  u8 cmdbuf_run_done;           //if 0,waiting for CMDBUF finish; if 1, op code in CMDBUF has finished one by one. HANTRO_VCMD_IOCH_WAIT_CMDBUF will check this variable.
+  u8 cmdbuf_need_remove;        // if 0, not need to remove CMDBUF; 1 CMDBUF can be removed if it is not the last CMDBUF;
+  u32 waited;                   // if 0, the cmd buf hasn't been waited, otherwise, has been waited.
+  u8 has_end_cmdbuf;            //if 1, the last opcode is end opCode.
+  u8 no_normal_int_cmdbuf;      //if 1, JMP will not send normal interrupt.
+  struct process_manager_obj* process_manager_obj;
+};
+
+struct hantrovcmd_dev
+{
+    struct vcmd_config vcmd_core_cfg; //config of each core,such as base addr, irq,etc
+    u32 core_id; //vcmd core id for driver and sw internal use
+    u32 sw_cmdbuf_rdy_num;
+    spinlock_t* spinlock;
+    wait_queue_head_t * wait_queue;
+    wait_queue_head_t * wait_abort_queue;
+    bi_list list_manager;
+    volatile u8 *hwregs;/* IO mem base */
+    u32 reg_mirror[ASIC_VCMD_SWREG_AMOUNT];
+    u32 duration_without_int;              //number of cmdbufs without interrupt.
+    volatile u8 working_state;
+    u64 total_exe_time;
+    u16 status_cmdbuf_id;//used for analyse configuration in cwl.
+    u32 hw_version_id; /*megvii 0x43421001, later 0x43421102*/
+    u32 *vcmd_reg_mem_virtualAddress;//start virtual address of vcmd registers memory of  CMDBUF.
+    size_t vcmd_reg_mem_busAddress;  //start physical address of vcmd registers memory of  CMDBUF.
+    unsigned int mmu_vcmd_reg_mem_busAddress;  //start mmu mapping address of vcmd registers memory of CMDBUF.
+    u32  vcmd_reg_mem_size;              // size of vcmd registers memory of CMDBUF.
+    struct platform_device *pdev;
+} ;
+
+/*
+ * Ioctl definitions
+ */
+#define VCMD_HW_ID                  0x4342
+
+
+static struct noncache_mem vcmd_buf_mem_pool;
+static struct noncache_mem vcmd_status_buf_mem_pool;
+static struct noncache_mem vcmd_registers_mem_pool;
+
+static u16 cmdbuf_used[TOTAL_DISCRETE_CMDBUF_NUM];
+static u16 cmdbuf_used_pos;
+static u16 cmdbuf_used_residual;
+
+static struct hantrovcmd_dev* vcmd_manager[MAX_VCMD_TYPE][MAX_VCMD_NUMBER];
+bi_list_node* global_cmdbuf_node[TOTAL_DISCRETE_CMDBUF_NUM];
+
+bi_list global_process_manager;
+
+static u16 vcmd_position[MAX_VCMD_TYPE];
+static int vcmd_type_core_num[MAX_VCMD_TYPE];
+
+#define EXECUTING_CMDBUF_ID_ADDR       26
+#define VCMD_EXE_CMDBUF_COUNT           3
+
+#define WORKING_STATE_IDLE          0
+#define WORKING_STATE_WORKING       1
+#define CMDBUF_EXE_STATUS_OK        0
+#define CMDBUF_EXE_STATUS_CMDERR        1
+#define CMDBUF_EXE_STATUS_BUSERR        2
+
+
+struct semaphore vcmd_reserve_cmdbuf_sem[MAX_VCMD_TYPE]; //for reserve
+
+extern unsigned long gBaseDDRHw;        /* PCI base register address (memalloc) */
+extern unsigned int mmu_enable;
+
+
+/***************************TYPE AND FUNCTION DECLARATION****************/
+
+/* here's all the must remember stuff */
+
+
+static int vcmd_reserve_IO(void);
+static void vcmd_release_IO(void);
+static void vcmd_reset_asic(struct hantrovcmd_dev * dev);
+static void vcmd_reset_current_asic(struct hantrovcmd_dev * dev);
+static int allocate_cmdbuf(struct noncache_mem*  new_cmdbuf_addr,struct noncache_mem*  new_status_cmdbuf_addr);
+static void vcmd_link_cmdbuf(struct hantrovcmd_dev *dev,bi_list_node* last_linked_cmdbuf_node);
+static void vcmd_start(struct hantrovcmd_dev *dev,bi_list_node* first_linked_cmdbuf_node);
+static void create_kernel_process_manager(void);
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18))
+static irqreturn_t hantrovcmd_isr(int irq, void *dev_id, struct pt_regs *regs);
+#else
+static irqreturn_t hantrovcmd_isr(int irq, void *dev_id);
+#endif
+
+static void printk_vcmd_register_debug(const void *hwregs, char * info);
+
+
+/*********************local variable declaration*****************/
+/* and this is our MAJOR; use 0 for dynamic allocation (recommended)*/
+int total_vcmd_core_num = 0;
+/* dynamic allocation*/
+static struct hantrovcmd_dev* hantrovcmd_data = NULL;
+
+//#define VCMD_DEBUG_INTERNAL
+
+//#define IRQ_SIMULATION
+
+#ifdef IRQ_SIMULATION
+struct timer_manager
+{
+    u32 core_id; //vcmd core id for driver and sw internal use
+    u32 timer_id;
+    struct timer_list *timer;
+} ;
+
+static struct timer_list timer[10000];
+struct timer_manager timer_reserve[10000];
+#if 0
+static struct timer_list timer0;
+static struct timer_list timer1;
+#endif
+#endif
+
+
+//hw_queue can be used for reserve cmdbuf memory
+DECLARE_WAIT_QUEUE_HEAD(vcmd_cmdbuf_memory_wait);
+
+DEFINE_SPINLOCK(vcmd_cmdbuf_alloc_lock);
+DEFINE_SPINLOCK(vcmd_process_manager_lock);
+
+
+spinlock_t owner_lock_vcmd[MAX_VCMD_NUMBER];
+
+wait_queue_head_t wait_queue_vcmd[MAX_VCMD_NUMBER];
+
+wait_queue_head_t abort_queue_vcmd[MAX_VCMD_NUMBER];
+
+/* mc wait queue, used in wait_cmdbuf_ready with ANY_CMDBUF_ID. */
+static wait_queue_head_t mc_wait_queue;
+
+#if 0
+/*allocate non-cacheable DMA memory*/
+#define DRIVER_NAME_HANTRO_NON_CACH_MEM "non_cach_memory"
+
+static struct platform_device *noncachable_mem_dev = NULL;
+
+
+static const struct platform_device_info hantro_platform_info = {
+    .name = DRIVER_NAME_HANTRO_NON_CACH_MEM,
+    .id = -1,
+    .dma_mask = DMA_BIT_MASK(32),
+};
+
+
+static int hantro_noncachable_mem_probe(struct platform_device *pdev)
+{
+  struct device *dev = &pdev->dev;
+  vcmd_buf_mem_pool.virtualAddress = dma_alloc_coherent(dev,CMDBUF_POOL_TOTAL_SIZE,&vcmd_buf_mem_pool.busAddress, GFP_KERNEL | GFP_DMA);
+  vcmd_buf_mem_pool.size = CMDBUF_POOL_TOTAL_SIZE;
+  vcmd_status_buf_mem_pool.virtualAddress = dma_alloc_coherent(dev,CMDBUF_POOL_TOTAL_SIZE,&vcmd_status_buf_mem_pool.busAddress, GFP_KERNEL | GFP_DMA);
+  vcmd_status_buf_mem_pool.size = CMDBUF_POOL_TOTAL_SIZE;
+  return 0;
+}
+
+static int hantro_noncachable_mem_remove(struct platform_device *pdev)
+{
+  struct device *dev = &pdev->dev;
+
+  dma_free_coherent(dev,vcmd_buf_mem_pool.size,vcmd_buf_mem_pool.virtualAddress,vcmd_buf_mem_pool.busAddress);
+  dma_free_coherent(dev,vcmd_status_buf_mem_pool.size,vcmd_status_buf_mem_pool.virtualAddress,vcmd_status_buf_mem_pool.busAddress);
+
+  return 0;
+}
+
+
+static const struct platform_device_id hantro_noncachable_mem_platform_ids[]={
+  {
+    .name = DRIVER_NAME_HANTRO_NON_CACH_MEM,
+  },
+  {/* sentinel */},
+};
+
+
+static const struct of_device_id  hantro_of_match[]={
+  {
+    .compatible  =  "thead,light-vc8000d",
+  },
+  {/* sentinel */},
+};
+
+static struct platform_driver hantro_noncachable_mem_platform_driver = {
+  .probe  = hantro_noncachable_mem_probe,
+  .remove  = hantro_noncachable_mem_remove,
+  .driver  ={
+    .name = DRIVER_NAME_HANTRO_NON_CACH_MEM,
+    .owner  = THIS_MODULE,
+    .of_match_table = hantro_of_match,
+  },
+  .id_table = hantro_noncachable_mem_platform_ids,
+};
+
+static void init_vcmd_non_cachable_memory_allocate(void)
+{
+
+  /*create device: This will create a {struct platform_device}, It has a member dev, which is a {struct device} */
+  noncachable_mem_dev = platform_device_register_full(&hantro_platform_info);
+
+  /*when this function is called, the .probe callback is invoked.*/
+  platform_driver_register(&hantro_noncachable_mem_platform_driver);
+
+
+}
+
+static void release_vcmd_non_cachable_memory(void)
+{
+
+  /* when this fucntion is called, .remove callback will be invoked. use it to clean up all resources allocated in .probe.*/
+  platform_driver_unregister(&hantro_noncachable_mem_platform_driver);
+
+  /*destroy the device*/
+  platform_device_unregister(noncachable_mem_dev);
+}
+#endif
+
+void PrintInstr(u32 i, u32 instr, u32 *size) {
+  if ((instr & 0xF8000000) == OPCODE_WREG) {
+    int length = ((instr >> 16) & 0x3FF);
+    pr_info("current cmdbuf data %d = 0x%08x => [%s %s %d 0x%x]\n", i, instr, "WREG", ((instr >> 26) & 0x1) ? "FIX" : "",
+           length, (instr & 0xFFFF));
+    *size = ((length+2)>>1)<<1;
+  } else if ((instr & 0xF8000000) == OPCODE_END) {
+    pr_info("current cmdbuf data %d = 0x%08x => [%s]\n", i, instr, "END");
+    *size = 2;
+  } else if ((instr & 0xF8000000) == OPCODE_NOP) {
+    pr_info("current cmdbuf data %d = 0x%08x => [%s]\n", i, instr, "NOP");
+    *size = 2;
+  } else if ((instr & 0xF8000000) == OPCODE_RREG) {
+    int length = ((instr >> 16) & 0x3FF);
+    pr_info("current cmdbuf data %d = 0x%08x => [%s %s %d 0x%x]\n", i, instr, "RREG", ((instr >> 26) & 0x1) ? "FIX" : "",
+           length, (instr & 0xFFFF));
+    *size = 4;
+  } else if ((instr & 0xF8000000) == OPCODE_JMP) {
+    pr_info("current cmdbuf data %d = 0x%08x => [%s %s %s]\n", i, instr, "JMP", ((instr >> 26) & 0x1) ? "RDY" : "",
+           ((instr >> 25) & 0x1) ? "IE" : "");
+    *size = 4;
+  } else if ((instr & 0xF8000000) == OPCODE_STALL) {
+    pr_info("current cmdbuf data %d = 0x%08x => [%s %s 0x%x]\n", i, instr, "STALL", ((instr >> 26) & 0x1) ? "IM" : "",
+           (instr & 0xFFFF));
+    *size = 2;
+  } else if ((instr & 0xF8000000) == OPCODE_CLRINT) {
+    pr_info("current cmdbuf data %d = 0x%08x => [%s %d 0x%x]\n", i, instr, "CLRINT", (instr >> 25) & 0x3,
+           (instr & 0xFFFF));
+    *size = 2;
+  } else
+    *size = 1;
+}
+
+/**********************************************************************************************************\
+*cmdbuf object management
+\***********************************************************************************************************/
+#ifdef DYNAMIC_MALLOC_VCMDNODE
+static struct cmdbuf_obj* create_cmdbuf_obj(void)
+{
+  struct cmdbuf_obj* cmdbuf_obj=NULL;
+  cmdbuf_obj=vmalloc(sizeof(struct cmdbuf_obj));
+  if(cmdbuf_obj==NULL)
+  {
+    PDEBUG ("%s\n","vmalloc for cmdbuf_obj fail!");
+    return cmdbuf_obj;
+  }
+  memset(cmdbuf_obj,0,sizeof(struct cmdbuf_obj));
+  return cmdbuf_obj;
+}
+#endif
+
+#ifdef DYNAMIC_MALLOC_VCMDNODE
+static void free_cmdbuf_obj(struct cmdbuf_obj* cmdbuf_obj)
+{
+  if(cmdbuf_obj==NULL)
+  {
+    PDEBUG ("%s\n","remove_cmdbuf_obj NULL");
+    return;
+  }
+  //free current cmdbuf_obj
+  vfree(cmdbuf_obj);
+  return;
+}
+#endif
+
+static void free_cmdbuf_mem(u16 cmdbuf_id )
+{
+    unsigned long flags;
+
+    spin_lock_irqsave(&vcmd_cmdbuf_alloc_lock, flags);
+    cmdbuf_used[cmdbuf_id]=0;
+    cmdbuf_used_residual +=1;
+    spin_unlock_irqrestore(&vcmd_cmdbuf_alloc_lock, flags);
+    wake_up_interruptible_all(&vcmd_cmdbuf_memory_wait);
+}
+
+static bi_list_node* create_cmdbuf_node(void)
+{
+  bi_list_node* current_node=NULL;
+  struct cmdbuf_obj* cmdbuf_obj=NULL;
+  struct noncache_mem  new_cmdbuf_addr;
+  struct noncache_mem  new_status_cmdbuf_addr;
+
+  if(wait_event_interruptible(vcmd_cmdbuf_memory_wait, allocate_cmdbuf(&new_cmdbuf_addr,&new_status_cmdbuf_addr)) )
+      return NULL;
+#ifdef DYNAMIC_MALLOC_VCMDNODE
+  cmdbuf_obj=create_cmdbuf_obj();
+#else
+  cmdbuf_obj = g_cmdbuf_obj_pool + new_cmdbuf_addr.cmdbuf_id;
+	if (cmdbuf_obj)
+    memset(cmdbuf_obj, 0, sizeof(struct cmdbuf_obj));
+#endif
+  if(cmdbuf_obj==NULL)
+  {
+    PDEBUG ("%s\n","create_cmdbuf_obj fail!");
+    free_cmdbuf_mem(new_cmdbuf_addr.cmdbuf_id);
+    return NULL;
+  }
+  cmdbuf_obj->cmdbuf_busAddress = new_cmdbuf_addr.busAddress;
+  cmdbuf_obj->mmu_cmdbuf_busAddress = new_cmdbuf_addr.mmu_bus_address;
+  cmdbuf_obj->cmdbuf_virtualAddress = new_cmdbuf_addr.virtualAddress;
+  cmdbuf_obj->cmdbuf_size = new_cmdbuf_addr.size;
+  cmdbuf_obj->cmdbuf_id = new_cmdbuf_addr.cmdbuf_id;
+  cmdbuf_obj->status_busAddress = new_status_cmdbuf_addr.busAddress;
+  cmdbuf_obj->mmu_status_busAddress = new_status_cmdbuf_addr.mmu_bus_address;
+  cmdbuf_obj->status_virtualAddress = new_status_cmdbuf_addr.virtualAddress;
+  cmdbuf_obj->status_size = new_status_cmdbuf_addr.size;
+#ifdef DYNAMIC_MALLOC_VCMDNODE
+  current_node=bi_list_create_node();
+#else
+  current_node = g_cmdbuf_node_pool + cmdbuf_obj->cmdbuf_id;
+  if (current_node)
+    memset(current_node, 0, sizeof(bi_list_node));
+#endif
+  if(current_node==NULL)
+  {
+    PDEBUG ("%s\n","bi_list_create_node fail!");
+    free_cmdbuf_mem(new_cmdbuf_addr.cmdbuf_id);
+#ifdef DYNAMIC_MALLOC_VCMDNODE
+    free_cmdbuf_obj(cmdbuf_obj);
+#endif
+    return NULL;
+  }
+  current_node->data = (void*)cmdbuf_obj;
+  current_node->next = NULL;
+  current_node->previous = NULL;
+  return current_node;
+}
+static void free_cmdbuf_node(bi_list_node* cmdbuf_node)
+{
+  struct cmdbuf_obj* cmdbuf_obj=NULL;
+  if(cmdbuf_node==NULL)
+  {
+    PDEBUG ("%s\n","remove_cmdbuf_node NULL");
+    return;
+  }
+  cmdbuf_obj = (struct cmdbuf_obj*)cmdbuf_node->data;
+  //free cmdbuf mem in pool
+  free_cmdbuf_mem(cmdbuf_obj->cmdbuf_id);
+
+#ifdef DYNAMIC_MALLOC_VCMDNODE
+  //free struct cmdbuf_obj
+  free_cmdbuf_obj(cmdbuf_obj);
+  //free current cmdbuf_node entity.
+  bi_list_free_node(cmdbuf_node);
+#endif
+  return;
+}
+
+//just remove, not free the node.
+static bi_list_node* remove_cmdbuf_node_from_list(bi_list* list,bi_list_node* cmdbuf_node)
+{
+  if(cmdbuf_node==NULL)
+  {
+    PDEBUG ("%s\n","remove_cmdbuf_node_from_list  NULL");
+    return NULL;
+  }
+  if(cmdbuf_node->next)
+  {
+    bi_list_remove_node(list,cmdbuf_node);
+    return cmdbuf_node;
+  }
+  else
+  {
+    //the last one, should not be removed.
+    return NULL;
+  }
+}
+//calculate executing_time of each vcmd
+static u64 calculate_executing_time_after_node(bi_list_node* exe_cmdbuf_node)
+{
+  u64 time_run_all=0;
+  struct cmdbuf_obj* cmdbuf_obj_temp=NULL;
+  while(1)
+  {
+    if(exe_cmdbuf_node==NULL)
+      break;
+    cmdbuf_obj_temp=(struct cmdbuf_obj* )exe_cmdbuf_node->data;
+    time_run_all += cmdbuf_obj_temp->executing_time;
+    exe_cmdbuf_node = exe_cmdbuf_node->next;
+  }
+  return time_run_all;
+}
+static u64 calculate_executing_time_after_node_high_priority(bi_list_node* exe_cmdbuf_node)
+{
+  u64 time_run_all=0;
+  struct cmdbuf_obj* cmdbuf_obj_temp=NULL;
+  if(exe_cmdbuf_node==NULL)
+    return time_run_all;
+  cmdbuf_obj_temp=(struct cmdbuf_obj* )exe_cmdbuf_node->data;
+  time_run_all += cmdbuf_obj_temp->executing_time;
+  exe_cmdbuf_node = exe_cmdbuf_node->next;
+  while(1)
+  {
+    if(exe_cmdbuf_node==NULL)
+      break;
+    cmdbuf_obj_temp=(struct cmdbuf_obj* )exe_cmdbuf_node->data;
+    if(cmdbuf_obj_temp->priority==CMDBUF_PRIORITY_NORMAL)
+      break;
+    time_run_all += cmdbuf_obj_temp->executing_time;
+    exe_cmdbuf_node = exe_cmdbuf_node->next;
+  }
+  return time_run_all;
+}
+
+
+/**********************************************************************************************************\
+*cmdbuf pool management
+\***********************************************************************************************************/
+static int allocate_cmdbuf(struct noncache_mem*  new_cmdbuf_addr,struct noncache_mem*  new_status_cmdbuf_addr)
+{
+  unsigned long flags;
+  spin_lock_irqsave(&vcmd_cmdbuf_alloc_lock, flags);
+  if(cmdbuf_used_residual==0)
+  {
+    spin_unlock_irqrestore(&vcmd_cmdbuf_alloc_lock, flags);
+    //no empty cmdbuf
+    return 0;
+  }
+  //there is one cmdbuf at least
+  while(1)
+  {
+    if(cmdbuf_used[cmdbuf_used_pos]==0&&(global_cmdbuf_node[cmdbuf_used_pos]==NULL ))
+    {
+      cmdbuf_used[cmdbuf_used_pos]=1;
+      cmdbuf_used_residual -=1;
+      new_cmdbuf_addr->virtualAddress=vcmd_buf_mem_pool.virtualAddress + cmdbuf_used_pos*CMDBUF_MAX_SIZE/4;
+      new_cmdbuf_addr->busAddress=vcmd_buf_mem_pool.busAddress + cmdbuf_used_pos*CMDBUF_MAX_SIZE;
+      new_cmdbuf_addr->mmu_bus_address=vcmd_buf_mem_pool.mmu_bus_address + cmdbuf_used_pos*CMDBUF_MAX_SIZE;
+      new_cmdbuf_addr->size=CMDBUF_MAX_SIZE;
+      new_cmdbuf_addr->cmdbuf_id = cmdbuf_used_pos;
+      new_status_cmdbuf_addr->virtualAddress=vcmd_status_buf_mem_pool.virtualAddress + cmdbuf_used_pos*CMDBUF_MAX_SIZE/4;
+      new_status_cmdbuf_addr->busAddress=vcmd_status_buf_mem_pool.busAddress + cmdbuf_used_pos*CMDBUF_MAX_SIZE;
+      new_status_cmdbuf_addr->mmu_bus_address=vcmd_status_buf_mem_pool.mmu_bus_address + cmdbuf_used_pos*CMDBUF_MAX_SIZE;
+      new_status_cmdbuf_addr->size=CMDBUF_MAX_SIZE;
+      new_status_cmdbuf_addr->cmdbuf_id = cmdbuf_used_pos;
+      cmdbuf_used_pos++;
+      if(cmdbuf_used_pos>=TOTAL_DISCRETE_CMDBUF_NUM)
+        cmdbuf_used_pos=0;
+      spin_unlock_irqrestore(&vcmd_cmdbuf_alloc_lock, flags);
+      return 1;
+    }
+    else
+    {
+      cmdbuf_used_pos++;
+      if(cmdbuf_used_pos>=TOTAL_DISCRETE_CMDBUF_NUM)
+        cmdbuf_used_pos=0;
+    }
+  }
+  return 0;
+}
+
+static bi_list_node* get_cmdbuf_node_in_list_by_addr(size_t  cmdbuf_addr,bi_list* list)
+{
+  bi_list_node* new_cmdbuf_node=NULL;
+  struct cmdbuf_obj* cmdbuf_obj=NULL;
+  new_cmdbuf_node=list->head;
+  while(1)
+  {
+    if(new_cmdbuf_node==NULL)
+      return NULL;
+    cmdbuf_obj=(struct cmdbuf_obj*)new_cmdbuf_node->data;
+    if(((cmdbuf_obj->cmdbuf_busAddress-base_ddr_addr) <=cmdbuf_addr)&&(((cmdbuf_obj->cmdbuf_busAddress-base_ddr_addr+cmdbuf_obj->cmdbuf_size) >cmdbuf_addr)) )
+    {
+      return new_cmdbuf_node;
+    }
+    new_cmdbuf_node=new_cmdbuf_node->next;
+  }
+  return NULL;
+}
+
+static int wait_abort_rdy(struct hantrovcmd_dev*dev)
+{
+  return dev->working_state == WORKING_STATE_IDLE;
+}
+static int select_vcmd(bi_list_node* new_cmdbuf_node)
+{
+  struct cmdbuf_obj* cmdbuf_obj=NULL;
+  bi_list_node* curr_cmdbuf_node=NULL;
+  bi_list* list=NULL;
+  struct hantrovcmd_dev*dev=NULL;
+  struct hantrovcmd_dev*smallest_dev=NULL;
+  u64 executing_time=0xffffffffffffffff;
+  int counter=0;
+  unsigned long flags=0;
+  u32 hw_rdy_cmdbuf_num=0;
+  size_t exe_cmdbuf_addr=0;
+  struct cmdbuf_obj* cmdbuf_obj_temp=NULL;
+  u32 cmdbuf_id=0;
+  cmdbuf_obj=(struct cmdbuf_obj*)new_cmdbuf_node->data;
+  //there is an empty vcmd to be used
+  while(1)
+  {
+    dev = vcmd_manager[cmdbuf_obj->module_type][vcmd_position[cmdbuf_obj->module_type]];
+    list=&dev->list_manager;
+    spin_lock_irqsave(dev->spinlock, flags);
+    if( list->tail==NULL)
+    {
+      bi_list_insert_node_tail(list,new_cmdbuf_node);
+      spin_unlock_irqrestore(dev->spinlock, flags);
+      vcmd_position[cmdbuf_obj->module_type]++;
+      if(vcmd_position[cmdbuf_obj->module_type]>=vcmd_type_core_num[cmdbuf_obj->module_type])
+        vcmd_position[cmdbuf_obj->module_type]=0;
+      cmdbuf_obj->core_id = dev->core_id;
+      return 0;
+    }
+    else
+    {
+      spin_unlock_irqrestore(dev->spinlock, flags);
+      vcmd_position[cmdbuf_obj->module_type]++;
+      if(vcmd_position[cmdbuf_obj->module_type]>=vcmd_type_core_num[cmdbuf_obj->module_type])
+        vcmd_position[cmdbuf_obj->module_type]=0;
+      counter++;
+    }
+    if(counter>=vcmd_type_core_num[cmdbuf_obj->module_type])
+      break;
+  }
+  //there is a vcmd which tail node -> cmdbuf_run_done == 1. It means this vcmd has nothing to do, so we select it.
+  counter =0;
+  while(1)
+  {
+    dev = vcmd_manager[cmdbuf_obj->module_type][vcmd_position[cmdbuf_obj->module_type]];
+    list=&dev->list_manager;
+    spin_lock_irqsave(dev->spinlock, flags);
+    curr_cmdbuf_node = list->tail;
+    if(curr_cmdbuf_node == NULL)
+    {
+      bi_list_insert_node_tail(list,new_cmdbuf_node);
+      spin_unlock_irqrestore(dev->spinlock, flags);
+      vcmd_position[cmdbuf_obj->module_type]++;
+      if(vcmd_position[cmdbuf_obj->module_type]>=vcmd_type_core_num[cmdbuf_obj->module_type])
+        vcmd_position[cmdbuf_obj->module_type]=0;
+      cmdbuf_obj->core_id = dev->core_id;
+      return 0;
+    }
+    cmdbuf_obj_temp =(struct cmdbuf_obj*) curr_cmdbuf_node->data;
+    if(cmdbuf_obj_temp->cmdbuf_run_done ==1)
+    {
+      bi_list_insert_node_tail(list,new_cmdbuf_node);
+      spin_unlock_irqrestore(dev->spinlock, flags);
+      vcmd_position[cmdbuf_obj->module_type]++;
+      if(vcmd_position[cmdbuf_obj->module_type]>=vcmd_type_core_num[cmdbuf_obj->module_type])
+        vcmd_position[cmdbuf_obj->module_type]=0;
+      cmdbuf_obj->core_id = dev->core_id;
+      return 0;
+    }
+    else
+    {
+      spin_unlock_irqrestore(dev->spinlock, flags);
+      vcmd_position[cmdbuf_obj->module_type]++;
+      if(vcmd_position[cmdbuf_obj->module_type]>=vcmd_type_core_num[cmdbuf_obj->module_type])
+        vcmd_position[cmdbuf_obj->module_type]=0;
+      counter++;
+    }
+    if(counter>=vcmd_type_core_num[cmdbuf_obj->module_type])
+      break;
+  }
+
+  //another case, tail = executing node, and vcmd=pend state (finish but not generate interrupt)
+  counter =0;
+  while(1)
+  {
+    dev = vcmd_manager[cmdbuf_obj->module_type][vcmd_position[cmdbuf_obj->module_type]];
+    list=&dev->list_manager;
+    //read executing cmdbuf address
+    if(dev->hw_version_id <= HW_ID_1_0_C )
+      hw_rdy_cmdbuf_num = vcmd_get_register_value((const void *)dev->hwregs,dev->reg_mirror,HWIF_VCMD_EXE_CMDBUF_COUNT);
+    else
+    {
+      hw_rdy_cmdbuf_num = *(dev->vcmd_reg_mem_virtualAddress+VCMD_EXE_CMDBUF_COUNT);
+      if(hw_rdy_cmdbuf_num!=dev->sw_cmdbuf_rdy_num)
+        hw_rdy_cmdbuf_num += 1;
+    }
+    spin_lock_irqsave(dev->spinlock, flags);
+    curr_cmdbuf_node = list->tail;
+    if(curr_cmdbuf_node == NULL)
+    {
+      bi_list_insert_node_tail(list,new_cmdbuf_node);
+      spin_unlock_irqrestore(dev->spinlock, flags);
+      vcmd_position[cmdbuf_obj->module_type]++;
+      if(vcmd_position[cmdbuf_obj->module_type]>=vcmd_type_core_num[cmdbuf_obj->module_type])
+        vcmd_position[cmdbuf_obj->module_type]=0;
+      cmdbuf_obj->core_id = dev->core_id;
+      return 0;
+    }
+
+    if((dev->sw_cmdbuf_rdy_num ==hw_rdy_cmdbuf_num))
+    {
+      bi_list_insert_node_tail(list,new_cmdbuf_node);
+      spin_unlock_irqrestore(dev->spinlock, flags);
+      vcmd_position[cmdbuf_obj->module_type]++;
+      if(vcmd_position[cmdbuf_obj->module_type]>=vcmd_type_core_num[cmdbuf_obj->module_type])
+        vcmd_position[cmdbuf_obj->module_type]=0;
+      cmdbuf_obj->core_id = dev->core_id;
+      return 0;
+    }
+    else
+    {
+      spin_unlock_irqrestore(dev->spinlock, flags);
+      vcmd_position[cmdbuf_obj->module_type]++;
+      if(vcmd_position[cmdbuf_obj->module_type]>=vcmd_type_core_num[cmdbuf_obj->module_type])
+        vcmd_position[cmdbuf_obj->module_type]=0;
+      counter++;
+    }
+    if(counter>=vcmd_type_core_num[cmdbuf_obj->module_type])
+      break;
+  }
+
+
+
+  //there is no idle vcmd,if low priority,calculate exe time, select the least one.
+  // or if high priority, calculate the exe time, select the least one and abort it.
+  if(cmdbuf_obj->priority==CMDBUF_PRIORITY_NORMAL)
+  {
+
+    counter =0;
+    //calculate total execute time of all devices
+    while(1)
+    {
+      dev = vcmd_manager[cmdbuf_obj->module_type][vcmd_position[cmdbuf_obj->module_type]];
+      //read executing cmdbuf address
+      if(dev->hw_version_id <= HW_ID_1_0_C )
+      {
+        exe_cmdbuf_addr = VCMDGetAddrRegisterValue((const void *)dev->hwregs,dev->reg_mirror,HWIF_VCMD_EXECUTING_CMD_ADDR);
+        list=&dev->list_manager;
+        spin_lock_irqsave(dev->spinlock, flags);
+        //get the executing cmdbuf node.
+        curr_cmdbuf_node=get_cmdbuf_node_in_list_by_addr(exe_cmdbuf_addr,list);
+
+        //calculate total execute time of this device
+        dev->total_exe_time=calculate_executing_time_after_node(curr_cmdbuf_node);
+        spin_unlock_irqrestore(dev->spinlock, flags);
+      }
+      else
+      {
+        //cmdbuf_id = vcmd_get_register_value((const void *)dev->hwregs,dev->reg_mirror,HWIF_VCMD_CMDBUF_EXECUTING_ID);
+        cmdbuf_id = *(dev->vcmd_reg_mem_virtualAddress+EXECUTING_CMDBUF_ID_ADDR+1);
+        spin_lock_irqsave(dev->spinlock, flags);
+        if(cmdbuf_id>=TOTAL_DISCRETE_CMDBUF_NUM||cmdbuf_id == 0)
+        {
+          pr_err("cmdbuf_id greater than the ceiling !!\n");
+          spin_unlock_irqrestore(dev->spinlock, flags);
+          return -1;
+        }
+        //get the executing cmdbuf node.
+        curr_cmdbuf_node=global_cmdbuf_node[cmdbuf_id];
+        if(curr_cmdbuf_node==NULL)
+        {
+          list=&dev->list_manager;
+          curr_cmdbuf_node = list->head;
+          while(1)
+          {
+            if(curr_cmdbuf_node == NULL)
+              break;
+            cmdbuf_obj_temp =(struct cmdbuf_obj*) curr_cmdbuf_node->data;
+            if(cmdbuf_obj_temp->cmdbuf_data_linked&&cmdbuf_obj_temp->cmdbuf_run_done==0)
+              break;
+            curr_cmdbuf_node = curr_cmdbuf_node->next;
+          }
+
+        }
+
+        //calculate total execute time of this device
+        dev->total_exe_time=calculate_executing_time_after_node(curr_cmdbuf_node);
+        spin_unlock_irqrestore(dev->spinlock, flags);
+
+      }
+      vcmd_position[cmdbuf_obj->module_type]++;
+      if(vcmd_position[cmdbuf_obj->module_type]>=vcmd_type_core_num[cmdbuf_obj->module_type])
+        vcmd_position[cmdbuf_obj->module_type]=0;
+      counter++;
+      if(counter>=vcmd_type_core_num[cmdbuf_obj->module_type])
+        break;
+    }
+    //find the device with the least total_exe_time.
+    counter =0;
+    executing_time=0xffffffffffffffff;
+    while(1)
+    {
+      dev = vcmd_manager[cmdbuf_obj->module_type][vcmd_position[cmdbuf_obj->module_type]];
+      if(dev->total_exe_time <= executing_time)
+      {
+        executing_time = dev->total_exe_time;
+        smallest_dev = dev;
+      }
+      vcmd_position[cmdbuf_obj->module_type]++;
+      if(vcmd_position[cmdbuf_obj->module_type]>=vcmd_type_core_num[cmdbuf_obj->module_type])
+        vcmd_position[cmdbuf_obj->module_type]=0;
+      counter++;
+      if(counter>=vcmd_type_core_num[cmdbuf_obj->module_type])
+        break;
+    }
+    //insert list
+    list = &smallest_dev->list_manager;
+    spin_lock_irqsave(smallest_dev->spinlock, flags);
+    bi_list_insert_node_tail(list,new_cmdbuf_node);
+    spin_unlock_irqrestore(smallest_dev->spinlock, flags);
+    cmdbuf_obj->core_id = smallest_dev->core_id;
+    return 0;
+  }
+  else
+  {
+    //CMDBUF_PRIORITY_HIGH
+    counter =0;
+    //calculate total execute time of all devices
+    while(1)
+    {
+      dev = vcmd_manager[cmdbuf_obj->module_type][vcmd_position[cmdbuf_obj->module_type]];
+      if(dev->hw_version_id <= HW_ID_1_0_C )
+      {
+        //read executing cmdbuf address
+        exe_cmdbuf_addr = VCMDGetAddrRegisterValue((const void *)dev->hwregs,dev->reg_mirror,HWIF_VCMD_EXECUTING_CMD_ADDR);
+        list=&dev->list_manager;
+        spin_lock_irqsave(dev->spinlock, flags);
+        //get the executing cmdbuf node.
+        curr_cmdbuf_node=get_cmdbuf_node_in_list_by_addr(exe_cmdbuf_addr,list);
+
+        //calculate total execute time of this device
+        dev->total_exe_time=calculate_executing_time_after_node_high_priority(curr_cmdbuf_node);
+        spin_unlock_irqrestore(dev->spinlock, flags);
+      }
+      else
+      {
+        //cmdbuf_id = vcmd_get_register_value((const void *)dev->hwregs,dev->reg_mirror,HWIF_VCMD_CMDBUF_EXECUTING_ID);
+        cmdbuf_id = *(dev->vcmd_reg_mem_virtualAddress+EXECUTING_CMDBUF_ID_ADDR);
+        spin_lock_irqsave(dev->spinlock, flags);
+        if(cmdbuf_id>=TOTAL_DISCRETE_CMDBUF_NUM||cmdbuf_id == 0)
+        {
+          pr_err("cmdbuf_id greater than the ceiling !!\n");
+          spin_unlock_irqrestore(dev->spinlock, flags);
+          return -1;
+        }
+        //get the executing cmdbuf node.
+        curr_cmdbuf_node=global_cmdbuf_node[cmdbuf_id];
+        if(curr_cmdbuf_node==NULL)
+        {
+          list=&dev->list_manager;
+          curr_cmdbuf_node = list->head;
+          while(1)
+          {
+            if(curr_cmdbuf_node == NULL)
+              break;
+            cmdbuf_obj_temp =(struct cmdbuf_obj*) curr_cmdbuf_node->data;
+            if(cmdbuf_obj_temp->cmdbuf_data_linked&&cmdbuf_obj_temp->cmdbuf_run_done==0)
+              break;
+            curr_cmdbuf_node = curr_cmdbuf_node->next;
+          }
+        }
+
+        //calculate total execute time of this device
+        dev->total_exe_time=calculate_executing_time_after_node(curr_cmdbuf_node);
+        spin_unlock_irqrestore(dev->spinlock, flags);
+      }
+      vcmd_position[cmdbuf_obj->module_type]++;
+      if(vcmd_position[cmdbuf_obj->module_type]>=vcmd_type_core_num[cmdbuf_obj->module_type])
+        vcmd_position[cmdbuf_obj->module_type]=0;
+      counter++;
+      if(counter>=vcmd_type_core_num[cmdbuf_obj->module_type])
+        break;
+    }
+    //find the smallest device.
+    counter =0;
+    executing_time=0xffffffffffffffff;
+    while(1)
+    {
+      dev = vcmd_manager[cmdbuf_obj->module_type][vcmd_position[cmdbuf_obj->module_type]];
+      if(dev->total_exe_time <= executing_time)
+      {
+        executing_time = dev->total_exe_time;
+        smallest_dev = dev;
+      }
+      vcmd_position[cmdbuf_obj->module_type]++;
+      if(vcmd_position[cmdbuf_obj->module_type]>=vcmd_type_core_num[cmdbuf_obj->module_type])
+        vcmd_position[cmdbuf_obj->module_type]=0;
+      counter++;
+      if(counter>=vcmd_type_core_num[cmdbuf_obj->module_type])
+        break;
+    }
+    //abort the vcmd and wait
+    vcmd_write_register_value((const void *)smallest_dev->hwregs,smallest_dev->reg_mirror,HWIF_VCMD_START_TRIGGER,0);
+    if(wait_event_interruptible(*smallest_dev->wait_abort_queue, wait_abort_rdy(smallest_dev)) )
+      return -ERESTARTSYS;
+    //need to select inserting position again because hw maybe have run to the next node.
+    //CMDBUF_PRIORITY_HIGH
+    spin_lock_irqsave(smallest_dev->spinlock, flags);
+    curr_cmdbuf_node = smallest_dev->list_manager.head;
+    while(1)
+    {
+     //if list is empty or tail,insert to tail
+     if(curr_cmdbuf_node == NULL)
+      break;
+     cmdbuf_obj_temp= (struct cmdbuf_obj*)curr_cmdbuf_node->data;
+     //if find the first node which priority is normal, insert node prior to  the node
+     if((cmdbuf_obj_temp->priority==CMDBUF_PRIORITY_NORMAL) && (cmdbuf_obj_temp->cmdbuf_run_done==0))
+      break;
+     curr_cmdbuf_node = curr_cmdbuf_node->next;
+    }
+    bi_list_insert_node_before(list,curr_cmdbuf_node,new_cmdbuf_node);
+    cmdbuf_obj->core_id = smallest_dev->core_id;
+    spin_unlock_irqrestore(smallest_dev->spinlock, flags);
+
+    return 0;
+  }
+  return 0;
+}
+static int wait_process_resource_rdy(struct process_manager_obj* process_manager_obj )
+{
+  return process_manager_obj->total_exe_time<=PROCESS_MAX_SUM_OF_IMAGE_SIZE;
+}
+
+static long reserve_cmdbuf(struct file *filp,struct exchange_parameter* input_para)
+{
+  bi_list_node* new_cmdbuf_node=NULL;
+  struct cmdbuf_obj* cmdbuf_obj=NULL;
+  bi_list_node* process_manager_node=NULL;
+  struct process_manager_obj* process_manager_obj=NULL;
+  unsigned long flags;
+  input_para->cmdbuf_id = 0;
+  if(input_para->cmdbuf_size>CMDBUF_MAX_SIZE)
+  {
+    return -1;
+  }
+  PDEBUG("reserve cmdbuf filp %p\n", (void *)filp);
+  spin_lock_irqsave(&vcmd_process_manager_lock, flags);
+  process_manager_node = global_process_manager.head;
+  while(1)
+  {
+    if (process_manager_node == NULL)
+    {
+      //should not happen
+      pr_err("hantrovcmd: ERROR process_manager_node !!\n");
+      spin_unlock_irqrestore(&vcmd_process_manager_lock, flags);
+      return -1;
+    }
+    process_manager_obj = (struct process_manager_obj*)process_manager_node->data;
+    PDEBUG("reserve loop: node %p, filp %p\n", (void *)process_manager_node,
+           (void *)process_manager_obj->filp);
+    if (filp == process_manager_obj->filp)
+      break;
+
+    process_manager_node = process_manager_node->next;
+  }
+  spin_unlock_irqrestore(&vcmd_process_manager_lock, flags);
+  spin_lock_irqsave(&process_manager_obj->spinlock, flags);
+  process_manager_obj->total_exe_time += input_para->executing_time;
+  spin_unlock_irqrestore(&process_manager_obj->spinlock, flags);
+  if(wait_event_interruptible(process_manager_obj->wait_queue, wait_process_resource_rdy(process_manager_obj)))
+     return -1;
+
+  new_cmdbuf_node=create_cmdbuf_node();
+  if(new_cmdbuf_node==NULL)
+    return -1;
+
+  cmdbuf_obj = (struct cmdbuf_obj* )new_cmdbuf_node->data;
+  cmdbuf_obj->module_type = input_para->module_type;
+  cmdbuf_obj->priority = input_para->priority;
+  cmdbuf_obj->executing_time = input_para->executing_time;
+  cmdbuf_obj->cmdbuf_size = CMDBUF_MAX_SIZE;
+  input_para->cmdbuf_size =CMDBUF_MAX_SIZE;
+  cmdbuf_obj->filp = filp;
+  cmdbuf_obj->process_manager_obj =process_manager_obj;
+
+  input_para->cmdbuf_id=cmdbuf_obj->cmdbuf_id;
+  global_cmdbuf_node[input_para->cmdbuf_id] = new_cmdbuf_node;
+
+  return 0;
+}
+
+static long release_cmdbuf(struct file *filp,u16 cmdbuf_id)
+{
+  struct cmdbuf_obj* cmdbuf_obj=NULL;
+  bi_list_node* last_cmdbuf_node=NULL;
+  bi_list_node* new_cmdbuf_node=NULL;
+  bi_list* list=NULL;
+  u32 module_type;
+
+
+  unsigned long flags;
+  struct hantrovcmd_dev* dev=NULL;
+  /*get cmdbuf object according to cmdbuf_id*/
+  new_cmdbuf_node = global_cmdbuf_node[cmdbuf_id];
+  if(new_cmdbuf_node==NULL)
+  {
+    //should not happen
+    pr_err("hantrovcmd: ERROR cmdbuf_id !!\n");
+    return -1;
+  }
+  cmdbuf_obj=(struct cmdbuf_obj*)new_cmdbuf_node->data;
+  if(cmdbuf_obj->filp!=filp)
+  {
+    //should not happen
+    pr_err("hantrovcmd: ERROR cmdbuf_id !!\n");
+    return -1;
+  }
+  module_type = cmdbuf_obj->module_type;
+  //TODO
+  if (down_interruptible(&vcmd_reserve_cmdbuf_sem[module_type]))
+      return -ERESTARTSYS;
+  dev = &hantrovcmd_data[cmdbuf_obj->core_id];
+
+  //spin_lock_irqsave(dev->spinlock, flags);
+  list=&dev->list_manager;
+  cmdbuf_obj->cmdbuf_need_remove=1;
+  last_cmdbuf_node = new_cmdbuf_node->previous;
+  while(1)
+  {
+    //remove current node
+    cmdbuf_obj=(struct cmdbuf_obj*)new_cmdbuf_node->data;
+    if(cmdbuf_obj->cmdbuf_need_remove==1)
+    {
+      new_cmdbuf_node=remove_cmdbuf_node_from_list(list,new_cmdbuf_node);
+      if(new_cmdbuf_node)
+      {
+        //free node
+        global_cmdbuf_node[cmdbuf_obj->cmdbuf_id] = NULL;
+        if(cmdbuf_obj->process_manager_obj)
+        {
+          spin_lock_irqsave(&cmdbuf_obj->process_manager_obj->spinlock, flags);
+          cmdbuf_obj->process_manager_obj->total_exe_time -= cmdbuf_obj->executing_time;
+          spin_unlock_irqrestore(&cmdbuf_obj->process_manager_obj->spinlock, flags);
+          wake_up_interruptible_all(&cmdbuf_obj->process_manager_obj->wait_queue);
+        }
+        free_cmdbuf_node(new_cmdbuf_node);
+
+      }
+    }
+    if(last_cmdbuf_node==NULL)
+      break;
+    new_cmdbuf_node=last_cmdbuf_node;
+    last_cmdbuf_node=new_cmdbuf_node->previous;
+  }
+  //spin_unlock_irqrestore(dev->spinlock, flags);
+  up(&vcmd_reserve_cmdbuf_sem[module_type]);
+  return 0;
+}
+static long release_cmdbuf_node(bi_list* list,bi_list_node*cmdbuf_node)
+{
+  bi_list_node* new_cmdbuf_node=NULL;
+  struct cmdbuf_obj* cmdbuf_obj=NULL;
+  /*get cmdbuf object according to cmdbuf_id*/
+  new_cmdbuf_node=cmdbuf_node;
+  if(new_cmdbuf_node==NULL)
+    return -1;
+  //remove node from list
+  new_cmdbuf_node=remove_cmdbuf_node_from_list(list,new_cmdbuf_node);
+  if(new_cmdbuf_node)
+  {
+    //free node
+    cmdbuf_obj = (struct cmdbuf_obj*)new_cmdbuf_node->data;
+    global_cmdbuf_node[cmdbuf_obj->cmdbuf_id] = NULL;
+    free_cmdbuf_node(new_cmdbuf_node);
+    return 0;
+  }
+  return 1;
+}
+
+static long release_cmdbuf_node_cleanup(bi_list* list)
+{
+  bi_list_node* new_cmdbuf_node=NULL;
+  struct cmdbuf_obj* cmdbuf_obj=NULL;
+  while(1)
+  {
+    new_cmdbuf_node=list->head;
+    if(new_cmdbuf_node==NULL)
+      return 0;
+    //remove node from list
+    bi_list_remove_node(list,new_cmdbuf_node);
+    //free node
+    cmdbuf_obj = (struct cmdbuf_obj*)new_cmdbuf_node->data;
+    global_cmdbuf_node[cmdbuf_obj->cmdbuf_id] = NULL;
+    free_cmdbuf_node(new_cmdbuf_node);
+  }
+  return 0;
+}
+
+
+
+static bi_list_node* find_last_linked_cmdbuf(bi_list_node* current_node)
+{
+  bi_list_node* new_cmdbuf_node=current_node;
+  bi_list_node* last_cmdbuf_node;
+  struct cmdbuf_obj* cmdbuf_obj=NULL;
+  if(current_node==NULL)
+    return NULL;
+  last_cmdbuf_node = new_cmdbuf_node;
+  new_cmdbuf_node = new_cmdbuf_node->previous;
+  while(1)
+  {
+    if(new_cmdbuf_node==NULL)
+      return last_cmdbuf_node;
+    cmdbuf_obj=(struct cmdbuf_obj*)new_cmdbuf_node->data;
+    if(cmdbuf_obj->cmdbuf_data_linked)
+    {
+      return new_cmdbuf_node;
+    }
+    last_cmdbuf_node = new_cmdbuf_node;
+    new_cmdbuf_node = new_cmdbuf_node->previous;
+  }
+  return NULL;
+}
+static long link_and_run_cmdbuf(struct file *filp,struct exchange_parameter* input_para)
+{
+  struct cmdbuf_obj* cmdbuf_obj=NULL;
+  bi_list_node* new_cmdbuf_node=NULL;
+  bi_list_node* last_cmdbuf_node;
+  u32* jmp_addr=NULL;
+  u32 opCode;
+  u32 tempOpcode;
+  u32 record_last_cmdbuf_rdy_num;
+  struct hantrovcmd_dev* dev=NULL;
+  unsigned long flags;
+  int return_value;
+  u16 cmdbuf_id=input_para->cmdbuf_id;
+
+
+  new_cmdbuf_node = global_cmdbuf_node[cmdbuf_id];
+  if(new_cmdbuf_node==NULL)
+  {
+    //should not happen
+    pr_err("hantrovcmd: ERROR cmdbuf_id !!\n");
+    return -1;
+  }
+  cmdbuf_obj=(struct cmdbuf_obj*)new_cmdbuf_node->data;
+  if(cmdbuf_obj->filp!=filp)
+  {
+    //should not happen
+    pr_err("hantrovcmd: ERROR cmdbuf_id !!\n");
+    return -1;
+  }
+  cmdbuf_obj->cmdbuf_data_loaded=1;
+  cmdbuf_obj->cmdbuf_size=input_para->cmdbuf_size;
+  cmdbuf_obj->waited = 0;
+#ifdef VCMD_DEBUG_INTERNAL
+  {
+    u32 i, inst = 0, size = 0;
+    pr_info("vcmd link, current cmdbuf content\n");
+    for(i=0;i<cmdbuf_obj->cmdbuf_size/4;i++)
+    {
+      if (i == inst) {
+        PrintInstr(i, *(cmdbuf_obj->cmdbuf_virtualAddress+i), &size);
+        inst += size;
+      } else {
+        pr_info("current cmdbuf data %d = 0x%x\n",i,*(cmdbuf_obj->cmdbuf_virtualAddress+i));
+      }
+    }
+  }
+#endif
+  //test nop and end opcode, then assign value.
+  cmdbuf_obj->has_end_cmdbuf=0; //0: has jmp opcode,1 has end code
+  cmdbuf_obj->no_normal_int_cmdbuf=0; //0: interrupt when JMP,1 not interrupt when JMP
+  jmp_addr = cmdbuf_obj->cmdbuf_virtualAddress + (cmdbuf_obj->cmdbuf_size/4);
+  opCode=tempOpcode = *(jmp_addr-4);
+  opCode >>=27;
+  opCode <<=27;
+  //we can't identify END opcode or JMP opcode, so we don't support END opcode in control sw and driver.
+  if(opCode == OPCODE_JMP)
+  {
+    //jmp
+    opCode=tempOpcode;
+    opCode &=0x02000000;
+    if(opCode == JMP_IE_1)
+    {
+      cmdbuf_obj->no_normal_int_cmdbuf=0;
+    }
+    else
+    {
+      cmdbuf_obj->no_normal_int_cmdbuf=1;
+    }
+  }
+  else
+  {
+    //not support other opcode
+    return -1;
+  }
+
+  if (down_interruptible(&vcmd_reserve_cmdbuf_sem[cmdbuf_obj->module_type]))
+      return -ERESTARTSYS;
+
+  return_value=select_vcmd(new_cmdbuf_node);
+  if(return_value)
+    return return_value;
+
+  dev = &hantrovcmd_data[cmdbuf_obj->core_id];
+  input_para->core_id = cmdbuf_obj->core_id;
+  pr_debug("filp=%p, VCMD Link    CMDBUF [%d] to core [%d]\n", (void *)filp, cmdbuf_id, input_para->core_id);
+  //set ddr address for vcmd registers copy.
+  if(dev->hw_version_id > HW_ID_1_0_C )
+  {
+    //read vcmd executing register into ddr memory.
+    //now core id is got and output ddr address of vcmd register can be filled in.
+    //each core has its own fixed output ddr address of vcmd registers.
+    jmp_addr = cmdbuf_obj->cmdbuf_virtualAddress;
+    if (mmu_enable) {
+      *(jmp_addr + 2) = 0;
+      *(jmp_addr+1) = (u32)((dev->mmu_vcmd_reg_mem_busAddress + (EXECUTING_CMDBUF_ID_ADDR+1)*4));
+    } else {
+      if(sizeof(size_t) == 8) {
+        *(jmp_addr + 2) = (u32)((u64)(dev->vcmd_reg_mem_busAddress + (EXECUTING_CMDBUF_ID_ADDR+1)*4)>>32);
+      } else {
+        *(jmp_addr + 2) = 0;
+      }
+      *(jmp_addr+1) = (u32)((dev->vcmd_reg_mem_busAddress + (EXECUTING_CMDBUF_ID_ADDR+1)*4));
+    }
+
+    jmp_addr = cmdbuf_obj->cmdbuf_virtualAddress + (cmdbuf_obj->cmdbuf_size/4);
+    //read vcmd all registers into ddr memory.
+    //now core id is got and output ddr address of vcmd registers can be filled in.
+    //each core has its own fixed output ddr address of vcmd registers.
+    if (mmu_enable) {
+      if(sizeof(size_t) == 8) {
+        *(jmp_addr-6) = 0;
+      }
+      *(jmp_addr-7) = (u32)(dev->mmu_vcmd_reg_mem_busAddress);
+    } else {
+      if(sizeof(size_t) == 8) {
+        *(jmp_addr-6) = (u32)((u64)dev->vcmd_reg_mem_busAddress>>32);
+      } else {
+        *(jmp_addr-6) = 0;
+      }
+      *(jmp_addr-7) = (u32)(dev->vcmd_reg_mem_busAddress);
+    }
+  }
+  //start to link and/or run
+  spin_lock_irqsave(dev->spinlock, flags);
+  last_cmdbuf_node = find_last_linked_cmdbuf(new_cmdbuf_node);
+  record_last_cmdbuf_rdy_num=dev->sw_cmdbuf_rdy_num;
+  vcmd_link_cmdbuf(dev,last_cmdbuf_node);
+  if(dev->working_state==WORKING_STATE_IDLE)
+  {
+    //run
+    while (last_cmdbuf_node &&
+           ((struct cmdbuf_obj*)last_cmdbuf_node->data)->cmdbuf_run_done)
+      last_cmdbuf_node = last_cmdbuf_node->next;
+
+    if (last_cmdbuf_node && last_cmdbuf_node->data) {
+      PDEBUG("vcmd start for cmdbuf id %d, cmdbuf_run_done = %d\n",
+            ((struct cmdbuf_obj*)last_cmdbuf_node->data)->cmdbuf_id,
+            ((struct cmdbuf_obj*)last_cmdbuf_node->data)->cmdbuf_run_done);
+    }
+    vcmd_start(dev,last_cmdbuf_node);
+  }
+  else
+  {
+    //just update cmdbuf ready number
+    if(record_last_cmdbuf_rdy_num!=dev->sw_cmdbuf_rdy_num)
+      vcmd_write_register_value((const void *)dev->hwregs,dev->reg_mirror,HWIF_VCMD_RDY_CMDBUF_COUNT,dev->sw_cmdbuf_rdy_num);
+  }
+  spin_unlock_irqrestore(dev->spinlock, flags);
+
+  up(&vcmd_reserve_cmdbuf_sem[cmdbuf_obj->module_type]);
+
+
+  return 0;
+}
+
+/******************************************************************************/
+static int check_cmdbuf_irq(struct hantrovcmd_dev* dev,struct cmdbuf_obj* cmdbuf_obj,u32 *irq_status_ret)
+{
+
+  int rdy = 0;
+  unsigned long flags;
+  spin_lock_irqsave(dev->spinlock, flags);
+  if(cmdbuf_obj->cmdbuf_run_done)
+  {
+    rdy = 1;
+    *irq_status_ret=cmdbuf_obj->executing_status;//need to decide how to assign this variable
+  }
+  spin_unlock_irqrestore(dev->spinlock, flags);
+  return rdy;
+}
+
+/******************************************************************************/
+static int check_mc_cmdbuf_irq(struct file *filp,struct cmdbuf_obj* cmdbuf_obj,u32 *irq_status_ret)
+{
+  int k;
+  bi_list_node* new_cmdbuf_node=NULL;
+  struct hantrovcmd_dev* dev=NULL;
+
+  for(k=0;k<TOTAL_DISCRETE_CMDBUF_NUM;k++)
+  {
+    new_cmdbuf_node = global_cmdbuf_node[k];
+    if(new_cmdbuf_node==NULL)
+      continue;
+
+    cmdbuf_obj=(struct cmdbuf_obj*)new_cmdbuf_node->data;
+    if(!cmdbuf_obj || cmdbuf_obj->filp != filp)
+      continue;
+
+    dev = &hantrovcmd_data[cmdbuf_obj->core_id];
+    if (check_cmdbuf_irq(dev, cmdbuf_obj, irq_status_ret) == 1) {
+      /* Return cmdbuf_id when ANY_CMDBUF_ID is used. */
+      if (!cmdbuf_obj->waited) {
+        *irq_status_ret = cmdbuf_obj->cmdbuf_id;
+        cmdbuf_obj->waited = 1;
+        return 1;
+      }
+    }
+  }
+
+  return 0;
+}
+
+#ifdef IRQ_SIMULATION
+void get_random_bytes(void *buf, int nbytes);
+#if 0
+void hantrovcmd_trigger_irq_0(struct timer_list* timer)
+{
+  PDEBUG("trigger core 0 irq\n");
+  del_timer(timer);
+  hantrovcmd_isr(0,(void *)&hantrovcmd_data[0]);
+}
+void hantrovcmd_trigger_irq_1(struct timer_list* timer)
+{
+  PDEBUG("trigger core 1 irq\n");
+  del_timer(timer);
+  hantrovcmd_isr(0,(void *)&hantrovcmd_data[1]);
+}
+#else
+void hantrovcmd_trigger_irq(struct timer_list *timer)
+{
+
+  u32 timer_id=0;
+  u32 core_id=0;
+  u32 i;
+  for(i=0;i<10000;i++)
+  {
+     if(timer_reserve[i].timer==timer)
+     {
+       timer_id=timer_reserve[i].timer_id;
+       core_id = timer_reserve[i].core_id;
+       break;
+     }
+  }
+  PDEBUG("trigger core 0 irq\n");
+  hantrovcmd_isr(core_id,(void *)&hantrovcmd_data[core_id]);
+  del_timer(timer);
+  timer_reserve[timer_id].timer=NULL;
+}
+
+#endif
+#endif
+
+static unsigned int wait_cmdbuf_ready(struct file *filp,u16 cmdbuf_id,u32 *irq_status_ret)
+{
+
+  struct cmdbuf_obj* cmdbuf_obj=NULL;
+  bi_list_node* new_cmdbuf_node=NULL;
+  struct hantrovcmd_dev* dev=NULL;
+
+  if (cmdbuf_id != ANY_CMDBUF_ID) {
+    PDEBUG("wait_cmdbuf_ready\n");
+    new_cmdbuf_node = global_cmdbuf_node[cmdbuf_id];
+    if(new_cmdbuf_node==NULL)
+    {
+      //should not happen
+      pr_err("hantrovcmd: ERROR cmdbuf_id !!\n");
+      return -1;
+    }
+    cmdbuf_obj=(struct cmdbuf_obj*)new_cmdbuf_node->data;
+    if(cmdbuf_obj->filp!=filp)
+    {
+      //should not happen
+      pr_err("hantrovcmd: ERROR cmdbuf_id !!\n");
+      return -1;
+    }
+    dev = &hantrovcmd_data[cmdbuf_obj->core_id];
+#ifdef IRQ_SIMULATION
+    {
+      u64 random_num;
+      //get_random_bytes(&random_num, sizeof(u32));
+      random_num = (u32)((u64)100*cmdbuf_obj->executing_time/(4096*2160)+50);
+      PDEBUG("random_num=%d\n",random_num);
+#if 0
+      /*init a timer to trigger irq*/
+      if (cmdbuf_obj->core_id==0)
+      {
+        //init_timer(&timer0);
+        //timer0.function = hantrovcmd_trigger_irq_0;
+        timer_setup(&timer0,hantrovcmd_trigger_irq_0,0);
+        timer0.expires =  jiffies + random_num*HZ/10; //the expires time is 1s
+        add_timer(&timer0);
+      }
+
+      if (cmdbuf_obj->core_id==1)
+      {
+        //init_timer(&timer1);
+        //timer1.function = hantrovcmd_trigger_irq_1;
+        timer_setup(&timer1,hantrovcmd_trigger_irq_1,0);
+        timer1.expires =  jiffies + random_num*HZ/10; //the expires time is 1s
+        add_timer(&timer1);
+      }
+#else
+      {
+          u32 i;
+          struct timer_list *temp_timer=NULL;
+          for(i=0;i<10000;i++)
+          {
+             if(timer_reserve[i].timer==NULL)
+             {
+               timer_reserve[i].timer_id=i;
+               timer_reserve[i].core_id=cmdbuf_obj->core_id;
+               temp_timer=timer_reserve[i].timer =&timer[i] ;
+               break;
+             }
+          }
+          //if (cmdbuf_obj->core_id==0)
+          {
+            //init_timer(&timer0);
+            //timer0.function = hantrovcmd_trigger_irq_0;
+            timer_setup(temp_timer,hantrovcmd_trigger_irq,0);
+            temp_timer->expires =  jiffies + random_num*HZ/10; //the expires time is 1s
+            add_timer(temp_timer);
+          }
+      }
+#endif
+    }
+#endif
+
+    if(wait_event_interruptible(*dev->wait_queue, check_cmdbuf_irq(dev,cmdbuf_obj,irq_status_ret)))
+    {
+        PDEBUG("vcmd_wait_queue_0 interrupted\n");
+        return -ERESTARTSYS;
+    }
+
+    pr_info("filp=%p, VCMD Wait    CMDBUF [%d]\n", (void *)filp, cmdbuf_id);
+    return 0;
+  } else {
+    if (check_mc_cmdbuf_irq(filp, cmdbuf_obj, irq_status_ret))
+      return 0;
+    if(wait_event_interruptible(mc_wait_queue, check_mc_cmdbuf_irq(filp,cmdbuf_obj,irq_status_ret)))
+    {
+        PDEBUG("multicore wait queue interrupted\n");
+        return -ERESTARTSYS;
+    }
+    return 0;
+  }
+}
+
+
+long hantrovcmd_ioctl(struct file *filp,
+                      unsigned int cmd, unsigned long arg)
+{
+    int err = 0;
+    static int last_polling_cmd = 0;
+    struct process_manager_obj* process_manager_obj=NULL;
+
+    if (cmd != HANTRO_VCMD_IOCH_POLLING_CMDBUF) {
+      last_polling_cmd = 0;
+      PDEBUG("ioctl cmd 0x%08x\n", cmd);
+    } else {
+      if (!last_polling_cmd)
+        PDEBUG("ioctl cmd 0x%08x\n", cmd);
+      last_polling_cmd = 1;
+    }
+    /*
+     * extract the type and number bitfields, and don't encode
+     * wrong cmds: return ENOTTY (inappropriate ioctl) before access_ok()
+     */
+    if(_IOC_TYPE(cmd) != HANTRO_VCMD_IOC_MAGIC )
+        return -ENOTTY;
+    if((_IOC_TYPE(cmd) == HANTRO_VCMD_IOC_MAGIC &&
+        _IOC_NR(cmd) > HANTRO_VCMD_IOC_MAXNR)  )
+        return -ENOTTY;
+
+    /*
+     * the direction is a bitmask, and VERIFY_WRITE catches R/W
+     * transfers. `Type' is user-oriented, while
+     * access_ok is kernel-oriented, so the concept of "read" and
+     * "write" is reversed
+     */
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 0, 0))
+    if(_IOC_DIR(cmd) & _IOC_READ)
+        err = !access_ok(VERIFY_WRITE, (void *) arg, _IOC_SIZE(cmd));
+    else if(_IOC_DIR(cmd) & _IOC_WRITE)
+        err = !access_ok(VERIFY_READ, (void *) arg, _IOC_SIZE(cmd));
+#else
+    if(_IOC_DIR(cmd) & _IOC_READ)
+        err = !access_ok((void *) arg, _IOC_SIZE(cmd));
+    else if(_IOC_DIR(cmd) & _IOC_WRITE)
+        err = !access_ok((void *) arg, _IOC_SIZE(cmd));
+#endif
+    if(err)
+        return -EFAULT;
+
+    process_manager_obj = (struct process_manager_obj*)filp->private_data;
+
+    switch (cmd)
+    {
+    case HANTRO_VCMD_IOCH_GET_CMDBUF_PARAMETER:
+      {
+       struct cmdbuf_mem_parameter local_cmdbuf_mem_data;
+       PDEBUG(" VCMD Reserve CMDBUF\n");
+       local_cmdbuf_mem_data.cmdbuf_unit_size = CMDBUF_MAX_SIZE;
+       local_cmdbuf_mem_data.status_cmdbuf_unit_size = CMDBUF_MAX_SIZE;
+       local_cmdbuf_mem_data.cmdbuf_total_size = CMDBUF_POOL_TOTAL_SIZE;
+       local_cmdbuf_mem_data.status_cmdbuf_total_size = CMDBUF_POOL_TOTAL_SIZE;
+       local_cmdbuf_mem_data.phy_status_cmdbuf_addr = vcmd_status_buf_mem_pool.busAddress;
+       local_cmdbuf_mem_data.phy_cmdbuf_addr = vcmd_buf_mem_pool.busAddress;
+       if (mmu_enable) {
+         local_cmdbuf_mem_data.mmu_phy_status_cmdbuf_addr = vcmd_status_buf_mem_pool.mmu_bus_address;
+         local_cmdbuf_mem_data.mmu_phy_cmdbuf_addr = vcmd_buf_mem_pool.mmu_bus_address;
+       } else {
+         local_cmdbuf_mem_data.mmu_phy_status_cmdbuf_addr = 0;
+         local_cmdbuf_mem_data.mmu_phy_cmdbuf_addr = 0;
+       }
+       local_cmdbuf_mem_data.base_ddr_addr = base_ddr_addr;
+       copy_to_user((struct cmdbuf_mem_parameter*)arg,&local_cmdbuf_mem_data,sizeof(struct cmdbuf_mem_parameter));
+       break;
+      }
+    case HANTRO_VCMD_IOCH_GET_VCMD_PARAMETER:
+      {
+       struct config_parameter input_para;
+       PDEBUG(" VCMD get vcmd config parameter \n");
+       copy_from_user(&input_para,(struct config_parameter*)arg,sizeof(struct config_parameter));
+       if(vcmd_type_core_num[input_para.module_type])
+       {
+         input_para.submodule_main_addr = vcmd_manager[input_para.module_type][0]->vcmd_core_cfg.submodule_main_addr;
+         input_para.submodule_dec400_addr = vcmd_manager[input_para.module_type][0]->vcmd_core_cfg.submodule_dec400_addr;
+         input_para.submodule_L2Cache_addr = vcmd_manager[input_para.module_type][0]->vcmd_core_cfg.submodule_L2Cache_addr;
+         input_para.submodule_MMU_addr = vcmd_manager[input_para.module_type][0]->vcmd_core_cfg.submodule_MMU_addr;
+         input_para.submodule_MMUWrite_addr = vcmd_manager[input_para.module_type][0]->vcmd_core_cfg.submodule_MMUWrite_addr;
+         input_para.submodule_axife_addr = vcmd_manager[input_para.module_type][0]->vcmd_core_cfg.submodule_axife_addr;
+         input_para.config_status_cmdbuf_id = vcmd_manager[input_para.module_type][0]->status_cmdbuf_id;
+         input_para.vcmd_hw_version_id = vcmd_manager[input_para.module_type][0]->hw_version_id;
+         input_para.vcmd_core_num = vcmd_type_core_num[input_para.module_type];
+       }
+       else
+       {
+         input_para.submodule_main_addr = 0xffff;
+         input_para.submodule_dec400_addr = 0xffff;
+         input_para.submodule_L2Cache_addr = 0xffff;
+         input_para.submodule_MMU_addr = 0xffff;
+         input_para.submodule_MMUWrite_addr = 0xffff;
+         input_para.submodule_axife_addr = 0xffff;
+         input_para.config_status_cmdbuf_id = 0;
+         input_para.vcmd_core_num = 0;
+         input_para.vcmd_hw_version_id =HW_ID_1_0_C;
+       }
+       copy_to_user((struct config_parameter*)arg,&input_para,sizeof(struct config_parameter));
+       break;
+      }
+    case HANTRO_VCMD_IOCH_RESERVE_CMDBUF:
+      {
+       int ret;
+       struct exchange_parameter input_para;
+       copy_from_user(&input_para,(struct exchange_parameter*)arg,sizeof(struct exchange_parameter));
+       ret = reserve_cmdbuf(filp,&input_para);
+       if (ret == 0)
+        copy_to_user((struct exchange_parameter*)arg,&input_para,sizeof(struct exchange_parameter));
+       pr_debug("filp=%p, VCMD Reserve CMDBUF [%d]\n", (void *)filp, input_para.cmdbuf_id);
+       return ret;
+      }
+
+    case HANTRO_VCMD_IOCH_LINK_RUN_CMDBUF:
+      {
+        struct exchange_parameter input_para;
+        long retVal;
+        copy_from_user(&input_para,(struct exchange_parameter*)arg,sizeof(struct exchange_parameter));
+
+        PDEBUG("VCMD link and run cmdbuf\n");
+        retVal = pm_runtime_resume_and_get(&hantrovcmd_data[0].pdev->dev);
+        if (retVal < 0)
+            return retVal;
+        if (process_manager_obj)
+          process_manager_obj->pm_count++;
+        retVal = link_and_run_cmdbuf(filp,&input_para);
+        copy_to_user((struct exchange_parameter*)arg,&input_para,sizeof(struct exchange_parameter));
+        return retVal;
+        break;
+      }
+
+    case HANTRO_VCMD_IOCH_WAIT_CMDBUF:
+      {
+
+        u16 cmdbuf_id;
+        unsigned int tmp;
+        u32 irq_status_ret=0;
+        __get_user(cmdbuf_id, (u16*)arg);
+        /*high 16 bits are core id, low 16 bits are cmdbuf_id*/
+
+        PDEBUG("VCMD wait for CMDBUF finishing. \n");
+
+        //TODO
+        tmp = wait_cmdbuf_ready(filp,cmdbuf_id,&irq_status_ret);
+        cmdbuf_id=(u16)irq_status_ret;
+        if (tmp==0)
+        {
+          __put_user(cmdbuf_id, (u16 *)arg);
+          return tmp;//return core_id
+        }
+        else
+        {
+          __put_user(0, (u16 *)arg);
+          return -1;
+        }
+
+        break;
+      }
+    case HANTRO_VCMD_IOCH_RELEASE_CMDBUF:
+      {
+        u16 cmdbuf_id;
+        __get_user(cmdbuf_id, (u16*)arg);
+        /*16 bits are cmdbuf_id*/
+
+        PDEBUG("VCMD release CMDBUF\n");
+
+        pm_runtime_mark_last_busy(&hantrovcmd_data[0].pdev->dev);
+        pm_runtime_put_autosuspend(&hantrovcmd_data[0].pdev->dev);
+        if (process_manager_obj)
+          process_manager_obj->pm_count--;
+        release_cmdbuf(filp,cmdbuf_id);
+        return 0;
+        break;
+      }
+    case HANTRO_VCMD_IOCH_POLLING_CMDBUF:
+      {
+        u16 core_id;
+        __get_user(core_id, (u16*)arg);
+        /*16 bits are cmdbuf_id*/
+        if(core_id>=total_vcmd_core_num)
+          return -1;
+        hantrovcmd_isr(core_id,&hantrovcmd_data[core_id]);
+        return 0;
+        break;
+      }
+    default:
+      {
+        break;
+      }
+    }
+    return 0;
+}
+/**********************************************************************************************************\
+*process manager object management
+\***********************************************************************************************************/
+static struct process_manager_obj* create_process_manager_obj(void)
+{
+  struct process_manager_obj* process_manager_obj=NULL;
+  process_manager_obj=vmalloc(sizeof(struct process_manager_obj));
+  if(process_manager_obj==NULL)
+  {
+    PDEBUG ("%s\n","vmalloc for process_manager_obj fail!");
+    return process_manager_obj;
+  }
+  memset(process_manager_obj,0,sizeof(struct process_manager_obj));
+  return process_manager_obj;
+}
+
+static void free_process_manager_obj( struct process_manager_obj* process_manager_obj)
+{
+  if(process_manager_obj==NULL)
+  {
+    PDEBUG ("%s\n","free_process_manager_obj NULL");
+    return;
+  }
+  //free current cmdbuf_obj
+  vfree(process_manager_obj);
+  return;
+}
+
+static bi_list_node* create_process_manager_node(void)
+{
+  bi_list_node* current_node=NULL;
+  struct process_manager_obj* process_manager_obj=NULL;
+
+  process_manager_obj=create_process_manager_obj();
+  if(process_manager_obj==NULL)
+  {
+    PDEBUG ("%s\n","create_process_manager_obj fail!");
+    return NULL;
+  }
+  process_manager_obj->total_exe_time = 0;
+  process_manager_obj->pm_count = 0;
+  spin_lock_init(&process_manager_obj->spinlock);
+  init_waitqueue_head(&process_manager_obj->wait_queue);
+  current_node=bi_list_create_node();
+  if(current_node==NULL)
+  {
+    PDEBUG ("%s\n","bi_list_create_node fail!");
+    free_process_manager_obj(process_manager_obj);
+    return NULL;
+  }
+  current_node->data = (void*)process_manager_obj;
+  return current_node;
+}
+static void free_process_manager_node(bi_list_node* process_node)
+{
+  struct process_manager_obj* process_manager_obj=NULL;
+  if(process_node==NULL)
+  {
+    PDEBUG ("%s\n","free_process_manager_node NULL");
+    return;
+  }
+  process_manager_obj = (struct process_manager_obj*)process_node->data;
+  //free struct process_manager_obj
+  free_process_manager_obj (process_manager_obj);
+  //free current process_manager_obj entity.
+  bi_list_free_node(process_node);
+  return;
+}
+
+static long release_process_node_cleanup(bi_list* list)
+{
+  bi_list_node* new_process_node=NULL;
+
+  while(1)
+  {
+    new_process_node=list->head;
+    if(new_process_node==NULL)
+      break;
+    //remove node from list
+    bi_list_remove_node(list,new_process_node);
+    //remove node from list
+    free_process_manager_node(new_process_node);
+  }
+  return 0;
+}
+
+static void create_kernel_process_manager(void)
+{
+  bi_list_node* process_manager_node;
+  struct process_manager_obj* process_manager_obj=NULL;
+  process_manager_node = create_process_manager_node();
+  process_manager_obj = (struct process_manager_obj*)process_manager_node->data;
+  process_manager_obj->filp = NULL;
+  bi_list_insert_node_tail(&global_process_manager,process_manager_node);
+}
+
+/* Update the last JMP cmd in cmdbuf_ojb in order to jump to next_cmdbuf_obj. */
+static void cmdbuf_update_jmp_cmd(int hw_version_id,
+                                        struct cmdbuf_obj *cmdbuf_obj,
+                                        struct cmdbuf_obj *next_cmdbuf_obj,
+                                        int jmp_IE_1) {
+  u32 *jmp_addr;
+  u32 operation_code;
+
+  if(!cmdbuf_obj)
+    return;
+
+  if(cmdbuf_obj->has_end_cmdbuf==0)
+  {
+    //need to link, current cmdbuf link to next cmdbuf
+    jmp_addr = cmdbuf_obj->cmdbuf_virtualAddress + (cmdbuf_obj->cmdbuf_size/4);
+    if (!next_cmdbuf_obj) {
+      // If next cmdbuf is not available, set the RDY to 0.
+      operation_code = *(jmp_addr-4);
+      operation_code >>=16;
+      operation_code <<=16;
+      *(jmp_addr-4)=(u32)(operation_code & ~JMP_RDY_1);
+    } else {
+      if(hw_version_id > HW_ID_1_0_C )
+      {
+        //set next cmdbuf id
+        *(jmp_addr-1) = next_cmdbuf_obj->cmdbuf_id;
+      }
+      if (mmu_enable) {
+        if(sizeof(size_t) == 8) {
+          *(jmp_addr-2)=(u32)((u64)(next_cmdbuf_obj->mmu_cmdbuf_busAddress)>>32);
+        } else {
+          *(jmp_addr-2)=0;
+        }
+        *(jmp_addr-3)=(u32)(next_cmdbuf_obj->mmu_cmdbuf_busAddress);
+      } else {
+        if(sizeof(size_t) == 8) {
+          *(jmp_addr-2)=(u32)((u64)(next_cmdbuf_obj->cmdbuf_busAddress-base_ddr_addr)>>32);
+        } else {
+          *(jmp_addr-2)=0;
+        }
+        *(jmp_addr-3)=(u32)(next_cmdbuf_obj->cmdbuf_busAddress-base_ddr_addr);
+      }
+      operation_code = *(jmp_addr-4);
+      operation_code >>=16;
+      operation_code <<=16;
+      *(jmp_addr-4)=(u32)(operation_code |JMP_RDY_1|jmp_IE_1|((next_cmdbuf_obj->cmdbuf_size+7)/8));
+    }
+
+#ifdef VCMD_DEBUG_INTERNAL
+    {
+       u32 i;
+       pr_info("vcmd link, last cmdbuf content\n");
+       for(i=cmdbuf_obj->cmdbuf_size/4 -8;i<cmdbuf_obj->cmdbuf_size/4;i++)
+       {
+         pr_info("current linked cmdbuf data %d =0x%x\n",i,*(cmdbuf_obj->cmdbuf_virtualAddress+i));
+       }
+    }
+#endif
+  }
+}
+
+
+/* delink given cmd buffer (cmdbuf_node) and remove it from list.
+   Also modify the last JMP of buf P to point to cmdbuf N.
+   Used when a process is terminated but there are pending cmd bufs in vmcd list.
+   E.g.,
+   before:
+
+     L->L->...->P->X->N->        ...        ->L
+     ^             ^                          ^
+     head          cmdbuf_node                 tail
+
+   end:
+
+     L->L->...->P->N->        ...        ->L
+     ^                                     ^
+     head                                  tail
+
+   Return: pointer to N or NULL if N doesn't exist.
+ */
+void vcmd_delink_rm_cmdbuf(struct hantrovcmd_dev *dev, bi_list_node* cmdbuf_node)
+{
+  bi_list *list = &dev->list_manager;
+  struct cmdbuf_obj* cmdbuf_obj = (struct cmdbuf_obj*)cmdbuf_node->data;
+  bi_list_node* prev = cmdbuf_node->previous;
+  bi_list_node* next = cmdbuf_node->next;
+
+  PDEBUG("Delink and remove cmdbuf [%d] from vcmd list.\n", cmdbuf_obj->cmdbuf_id);
+#ifdef HANTRO_VCMD_DRIVER_DEBUG
+  if (prev) {
+    PDEBUG("prev cmdbuf [%d].\n", ((struct cmdbuf_obj*)prev->data)->cmdbuf_id);
+  } else {
+    PDEBUG("NO prev cmdbuf.\n");
+  }
+  if (next) {
+    PDEBUG("next cmdbuf [%d].\n", ((struct cmdbuf_obj*)next->data)->cmdbuf_id);
+  } else {
+    PDEBUG("NO next cmdbuf.\n");
+  }
+#endif
+
+  bi_list_remove_node(list, cmdbuf_node);
+  global_cmdbuf_node[cmdbuf_obj->cmdbuf_id] = NULL;
+  free_cmdbuf_node(cmdbuf_node);
+
+  cmdbuf_update_jmp_cmd(dev->hw_version_id, prev ? prev->data : NULL, next ? next->data : NULL,
+                        dev->duration_without_int > INT_MIN_SUM_OF_IMAGE_SIZE);
+}
+
+int hantrovcmd_open(struct inode *inode, struct file *filp)
+{
+    int result = 0;
+    struct hantrovcmd_dev *dev = hantrovcmd_data;
+    bi_list_node* process_manager_node;
+    unsigned long flags;
+    struct process_manager_obj* process_manager_obj=NULL;
+
+    filp->private_data = NULL;
+    process_manager_node = create_process_manager_node();
+    if(process_manager_node== NULL)
+      return -1;
+    process_manager_obj = (struct process_manager_obj*)process_manager_node->data;
+    process_manager_obj->filp = filp;
+    spin_lock_irqsave(&vcmd_process_manager_lock, flags);
+    bi_list_insert_node_tail(&global_process_manager,process_manager_node);
+    spin_unlock_irqrestore(&vcmd_process_manager_lock, flags);
+    filp->private_data = process_manager_node->data;
+
+    PDEBUG("dev opened\n");
+    PDEBUG("process node %p for filp opened %p\n", (void *)process_manager_node, (void *)filp);
+    return result;
+}
+
+int hantrovcmd_release(struct inode *inode, struct file *filp)
+{
+    struct hantrovcmd_dev *dev = hantrovcmd_data;
+    u32 core_id = 0;
+    u32 release_cmdbuf_num=0;
+    bi_list_node* new_cmdbuf_node=NULL;
+    struct cmdbuf_obj* cmdbuf_obj_temp=NULL;
+    bi_list_node* process_manager_node;
+    struct process_manager_obj* process_manager_obj=NULL;
+    int vcmd_aborted = 0;  // vcmd is aborted in this function
+    struct cmdbuf_obj* restart_cmdbuf = NULL;
+
+    unsigned long flags;
+    long retVal=0;
+
+    PDEBUG("dev closed for process %p via hantrovcmd_release\n", (void *)filp);
+    if (down_interruptible(&vcmd_reserve_cmdbuf_sem[dev->vcmd_core_cfg.sub_module_type]))
+      return -ERESTARTSYS;
+
+    for (core_id = 0;core_id < total_vcmd_core_num; core_id++)
+    {
+      if((&dev[core_id])==NULL)
+        continue;
+      spin_lock_irqsave(dev[core_id].spinlock, flags);
+      new_cmdbuf_node=dev[core_id].list_manager.head;
+      while(1)
+      {
+        if(new_cmdbuf_node==NULL)
+          break;
+        cmdbuf_obj_temp=(struct cmdbuf_obj*)new_cmdbuf_node->data;
+        PDEBUG("Process %p is releasing: checking cmdbuf %d of process %p.\n",
+               filp, cmdbuf_obj_temp->cmdbuf_id, cmdbuf_obj_temp->filp);
+        if (dev[core_id].hwregs && (cmdbuf_obj_temp->filp == filp))
+        {
+          if(cmdbuf_obj_temp->cmdbuf_run_done)
+          {
+            cmdbuf_obj_temp->cmdbuf_need_remove=1;
+            retVal=release_cmdbuf_node(&dev[core_id].list_manager,new_cmdbuf_node);
+            if(retVal==1)
+              cmdbuf_obj_temp->process_manager_obj = NULL;
+          }
+          else if(cmdbuf_obj_temp->cmdbuf_data_linked==0)
+          {
+            cmdbuf_obj_temp->cmdbuf_data_linked = 1;
+            cmdbuf_obj_temp->cmdbuf_run_done=1;
+            cmdbuf_obj_temp->cmdbuf_need_remove=1;
+            retVal=release_cmdbuf_node(&dev[core_id].list_manager,new_cmdbuf_node);
+            if(retVal==1)
+              cmdbuf_obj_temp->process_manager_obj = NULL;
+          }
+          else if(cmdbuf_obj_temp->cmdbuf_data_linked==1 && dev[core_id].working_state==WORKING_STATE_IDLE)
+          {
+            vcmd_delink_rm_cmdbuf(&dev[core_id], new_cmdbuf_node);
+            if (restart_cmdbuf == cmdbuf_obj_temp)
+              restart_cmdbuf = new_cmdbuf_node->next ? new_cmdbuf_node->next->data : NULL;
+            if (restart_cmdbuf) {
+              PDEBUG("Set restart cmdbuf [%d].\n", restart_cmdbuf->cmdbuf_id);
+            } else {
+              PDEBUG("Set restart cmdbuf to NULL.\n");
+            }
+          }
+          else if(cmdbuf_obj_temp->cmdbuf_data_linked==1 && dev[core_id].working_state==WORKING_STATE_WORKING)
+          {
+            bi_list_node* last_cmdbuf_node = NULL;
+            bi_list_node* done_cmdbuf_node = NULL;
+            int abort_cmdbuf_id;
+            int loop_count = 0;
+
+            //abort the vcmd and wait
+            PDEBUG("Abort due to linked cmdbuf %d of current process.\n", cmdbuf_obj_temp->cmdbuf_id);
+            printk_vcmd_register_debug((const void *)dev->hwregs, "Before trigger to 0");
+            // disable abort interrupt
+            //vcmd_write_register_value((const void *)dev[core_id].hwregs,dev[core_id].reg_mirror,HWIF_VCMD_IRQ_ABORT_EN,0);
+            vcmd_write_register_value((const void *)dev[core_id].hwregs,dev[core_id].reg_mirror,HWIF_VCMD_START_TRIGGER,0);
+            vcmd_aborted = 1;
+
+            printk_vcmd_register_debug((const void *)dev->hwregs,"After trigger to 0");
+            // Wait vcmd core aborted and vcmd enters IDLE mode.
+            //while (dev[core_id].working_state != WORKING_STATE_IDLE) {
+            while (vcmd_get_register_value((const void *)dev[core_id].hwregs,dev[core_id].reg_mirror,HWIF_VCMD_WORK_STATE)) {
+              loop_count++;
+              if (!(loop_count % 10)) {
+                u32 irq_status = vcmd_read_reg((const void *)dev->hwregs, VCMD_REGISTER_INT_STATUS_OFFSET);
+                pr_err("hantrovcmd: expected idle state, but irq status = 0x%0x\n", irq_status);
+                pr_err("hantrovcmd: vcmd current status is %d\n", vcmd_get_register_value((const void *)dev->hwregs, dev[core_id].reg_mirror, HWIF_VCMD_WORK_STATE));
+              }
+              mdelay(10);  // wait 10ms
+              if (loop_count > 100) { // too long
+                pr_err("hantrovcmd: too long before vcmd core to IDLE state\n");
+                process_manager_obj = (struct process_manager_obj*)filp->private_data;
+                if (process_manager_obj)
+                {
+                  while(process_manager_obj->pm_count > 0)
+                  {
+                    pm_runtime_mark_last_busy(&dev[0].pdev->dev);
+                    pm_runtime_put_autosuspend(&dev[0].pdev->dev);
+                    process_manager_obj->pm_count--;
+                  }
+                }
+                spin_unlock_irqrestore(dev[core_id].spinlock, flags);
+                up(&vcmd_reserve_cmdbuf_sem[dev->vcmd_core_cfg.sub_module_type]);
+                return -ERESTARTSYS;
+              }
+            }
+            dev[core_id].working_state = WORKING_STATE_IDLE;
+            // clear interrupt & restore abort_e
+            if (vcmd_get_register_value((const void *)dev[core_id].hwregs,dev[core_id].reg_mirror,HWIF_VCMD_IRQ_ABORT)) {
+              PDEBUG("Abort interrupt triggered, now clear it to avoid abort int...\n");
+              vcmd_write_reg((const void *)dev->hwregs, VCMD_REGISTER_INT_STATUS_OFFSET, 0x1<<4);
+              PDEBUG("Now irq status = 0x%0x.\n", vcmd_read_reg((const void *)dev->hwregs, VCMD_REGISTER_INT_STATUS_OFFSET));
+            }
+            //printk_vcmd_register_debug((const void *)dev->hwregs, "vcmd status to IDLE");
+
+            abort_cmdbuf_id = vcmd_get_register_value((const void *)dev[core_id].hwregs,dev[core_id].reg_mirror,HWIF_VCMD_CMDBUF_EXECUTING_ID);
+            PDEBUG("Abort when executing cmd buf %d.\n", abort_cmdbuf_id);
+            dev[core_id].sw_cmdbuf_rdy_num = 0;
+            dev[core_id].duration_without_int = 0;
+            vcmd_write_register_value((const void *)dev[core_id].hwregs,dev[core_id].reg_mirror,HWIF_VCMD_EXE_CMDBUF_COUNT,0);
+            vcmd_write_register_value((const void *)dev[core_id].hwregs,dev[core_id].reg_mirror,HWIF_VCMD_RDY_CMDBUF_COUNT,0);
+
+            /* Mark cmdbuf_run_done to 1 for all the cmd buf executed. */
+            done_cmdbuf_node = dev[core_id].list_manager.head;
+            while (done_cmdbuf_node) {
+              if (!((struct cmdbuf_obj*)done_cmdbuf_node->data)->cmdbuf_run_done) {
+                ((struct cmdbuf_obj*)done_cmdbuf_node->data)->cmdbuf_run_done = 1;
+                ((struct cmdbuf_obj*)done_cmdbuf_node->data)->cmdbuf_data_linked = 0;
+                PDEBUG("Set cmdbuf [%d] cmdbuf_run_done to 1.\n", ((struct cmdbuf_obj*)done_cmdbuf_node->data)->cmdbuf_id);
+              }
+              if (((struct cmdbuf_obj*)done_cmdbuf_node->data)->cmdbuf_id == abort_cmdbuf_id)
+                break;
+              done_cmdbuf_node = done_cmdbuf_node->next;
+            }
+            if (cmdbuf_obj_temp->cmdbuf_run_done) {
+              /* current cmdbuf is in fact has been executed, but due to interrupt is not triggered, the status is not updated.
+                 Just delink and remove it from the list. */
+              if (done_cmdbuf_node && done_cmdbuf_node->data) {
+                PDEBUG("done_cmdbuf_node is cmdbuf [%d].\n", ((struct cmdbuf_obj*)done_cmdbuf_node->data)->cmdbuf_id);
+              }
+              done_cmdbuf_node = done_cmdbuf_node->next;
+              if (done_cmdbuf_node)
+                restart_cmdbuf = (struct cmdbuf_obj*)done_cmdbuf_node->data;
+              if (restart_cmdbuf) {
+                PDEBUG("Set restart cmdbuf [%d] via if.\n", restart_cmdbuf->cmdbuf_id);
+              }
+            } else {
+              last_cmdbuf_node = new_cmdbuf_node;
+              /* cmd buf num from aborted cmd buf to current cmdbuf_obj_temp */
+              if (cmdbuf_obj_temp->cmdbuf_id != abort_cmdbuf_id) {
+                last_cmdbuf_node  = new_cmdbuf_node->previous;
+
+                while (last_cmdbuf_node &&
+                      ((struct cmdbuf_obj*)last_cmdbuf_node->data)->cmdbuf_id != abort_cmdbuf_id) {
+                  restart_cmdbuf = (struct cmdbuf_obj*)last_cmdbuf_node->data;
+                  last_cmdbuf_node = last_cmdbuf_node->previous;
+                  dev[core_id].sw_cmdbuf_rdy_num++;
+                  dev[core_id].duration_without_int += restart_cmdbuf->executing_time;
+                  PDEBUG("Keep valid cmdbuf [%d] in the list.\n", restart_cmdbuf->cmdbuf_id);
+                }
+              }
+              if (restart_cmdbuf) {
+                PDEBUG("Set restart cmdbuf [%d] via else.\n", restart_cmdbuf->cmdbuf_id);
+              }
+            }
+
+            // remove first linked cmdbuf from list
+            vcmd_delink_rm_cmdbuf(&dev[core_id], new_cmdbuf_node);
+
+          }
+          release_cmdbuf_num++;
+          PDEBUG("release reserved cmdbuf\n");
+        } else  if (vcmd_aborted && !cmdbuf_obj_temp->cmdbuf_run_done) {
+          /* VCMD is aborted, need to re-calculate the duration_without_int */
+          if (!restart_cmdbuf)
+            restart_cmdbuf = cmdbuf_obj_temp; /* first cmdbuf to be restarted */
+          dev[core_id].duration_without_int += cmdbuf_obj_temp->executing_time;
+          dev[core_id].sw_cmdbuf_rdy_num++;
+        }
+
+        new_cmdbuf_node = new_cmdbuf_node->next;
+      }
+
+      if (restart_cmdbuf) {
+        u32 irq_status1, irq_status2;
+        PDEBUG("Restart from cmdbuf [%d] after aborting.\n", restart_cmdbuf->cmdbuf_id);
+
+        irq_status1 = vcmd_read_reg((const void *)dev->hwregs, VCMD_REGISTER_INT_STATUS_OFFSET);
+        vcmd_write_reg((const void *)dev->hwregs, VCMD_REGISTER_INT_STATUS_OFFSET, irq_status1);
+        irq_status2 = vcmd_read_reg((const void *)dev->hwregs, VCMD_REGISTER_INT_STATUS_OFFSET);
+        PDEBUG("Clear irq status from 0x%0x -> 0x%0x\n", irq_status1, irq_status2);
+        if (mmu_enable) {
+          vcmd_write_register_value((const void *)dev[core_id].hwregs,dev[core_id].reg_mirror, HWIF_VCMD_EXECUTING_CMD_ADDR,
+                                        (u32)(restart_cmdbuf->mmu_cmdbuf_busAddress));
+          if(sizeof(size_t) == 8) {
+            vcmd_write_register_value((const void *)dev[core_id].hwregs,dev[core_id].reg_mirror, HWIF_VCMD_EXECUTING_CMD_ADDR_MSB,(u32)((u64)(restart_cmdbuf->mmu_cmdbuf_busAddress)>>32));
+          } else {
+            vcmd_write_register_value((const void *)dev[core_id].hwregs,dev[core_id].reg_mirror, HWIF_VCMD_EXECUTING_CMD_ADDR_MSB, 0);
+          }
+        } else {
+          vcmd_write_register_value((const void *)dev[core_id].hwregs,dev[core_id].reg_mirror, HWIF_VCMD_EXECUTING_CMD_ADDR,(u32)(restart_cmdbuf->cmdbuf_busAddress-base_ddr_addr));
+          if(sizeof(size_t) == 8) {
+            vcmd_write_register_value((const void *)dev[core_id].hwregs,dev[core_id].reg_mirror, HWIF_VCMD_EXECUTING_CMD_ADDR_MSB,(u32)((u64)(restart_cmdbuf->cmdbuf_busAddress-base_ddr_addr)>>32));
+          } else {
+            vcmd_write_register_value((const void *)dev[core_id].hwregs,dev[core_id].reg_mirror, HWIF_VCMD_EXECUTING_CMD_ADDR_MSB, 0);
+          }
+        }
+        vcmd_write_register_value((const void *)dev[core_id].hwregs,dev[core_id].reg_mirror,HWIF_VCMD_EXE_CMDBUF_COUNT,0);
+        vcmd_write_register_value((const void *)dev[core_id].hwregs,dev[core_id].reg_mirror,HWIF_VCMD_EXE_CMDBUF_LENGTH,(u32)((restart_cmdbuf->cmdbuf_size+7)/8));
+        vcmd_write_register_value((const void *)dev[core_id].hwregs,dev[core_id].reg_mirror,HWIF_VCMD_CMDBUF_EXECUTING_ID,restart_cmdbuf->cmdbuf_id);
+        PDEBUG("====dev->sw_cmdbuf_rdy_num is %d\n", dev[core_id].sw_cmdbuf_rdy_num);
+        vcmd_write_register_value((const void *)dev[core_id].hwregs,dev[core_id].reg_mirror,HWIF_VCMD_RDY_CMDBUF_COUNT,dev[core_id].sw_cmdbuf_rdy_num);
+        printk_vcmd_register_debug((const void *)dev->hwregs, "before restart");
+        vcmd_write_register_value((const void *)dev[core_id].hwregs,dev[core_id].reg_mirror,HWIF_VCMD_START_TRIGGER,1);
+
+        PDEBUG("Restart from cmdbuf [%d] after aborting: start trigger = %d.\n", restart_cmdbuf->cmdbuf_id,
+                vcmd_get_register_value((const void *)dev[core_id].hwregs,dev[core_id].reg_mirror,HWIF_VCMD_START_TRIGGER));
+        PDEBUG("dev state from %d -> WORKING.\n", dev[core_id].working_state);
+        dev[core_id].working_state = WORKING_STATE_WORKING;
+        printk_vcmd_register_debug((const void *)dev->hwregs, "after restart");
+      } else {
+        PDEBUG("No more command buffer to be restarted!\n");
+      }
+      spin_unlock_irqrestore(dev[core_id].spinlock, flags);
+      // VCMD aborted but not restarted, nedd to wake up
+      if (vcmd_aborted && !restart_cmdbuf)
+        wake_up_interruptible_all(dev[core_id].wait_queue);
+    }
+
+    if(release_cmdbuf_num)
+      wake_up_interruptible_all(&vcmd_cmdbuf_memory_wait);
+    spin_lock_irqsave(&vcmd_process_manager_lock, flags);
+    process_manager_node = global_process_manager.head;
+    while(1)
+    {
+      if(process_manager_node == NULL)
+        break;
+      process_manager_obj = (struct process_manager_obj*)process_manager_node->data;
+      if(process_manager_obj->filp == filp)
+        break;
+      process_manager_node = process_manager_node->next;
+    }
+    if (process_manager_obj)
+    {
+      while(process_manager_obj->pm_count > 0)
+      {
+        pm_runtime_mark_last_busy(&dev[0].pdev->dev);
+        pm_runtime_put_autosuspend(&dev[0].pdev->dev);
+        process_manager_obj->pm_count--;
+      }
+    }
+    //remove node from list
+    PDEBUG("process node %p for filp to be removed: %p\n", (void *)process_manager_node, (void *)process_manager_obj->filp);
+    bi_list_remove_node(&global_process_manager,process_manager_node);
+    spin_unlock_irqrestore(&vcmd_process_manager_lock, flags);
+    free_process_manager_node(process_manager_node);
+    up(&vcmd_reserve_cmdbuf_sem[dev->vcmd_core_cfg.sub_module_type]);
+    return 0;
+}
+
+
+/*------------------------------------------------------------------------------
+ Function name   : vcmd_pcie_init
+ Description     : Initialize PCI Hw access
+
+ Return type     : int
+ ------------------------------------------------------------------------------*/
+static int vcmd_init(struct platform_device *pdev)
+{
+    int i =0;
+    struct kernel_addr_desc addr;
+    struct pci_dev *g_vcmd_dev = NULL;    /* PCI device structure. */
+
+    vcmd_buf_mem_pool.virtualAddress = dma_alloc_coherent(&pdev->dev, CMDBUF_POOL_TOTAL_SIZE*2 + CMDBUF_VCMD_REGISTER_TOTAL_SIZE,
+		                             &vcmd_buf_mem_pool.busAddress, GFP_KERNEL | GFP_DMA);
+
+    pr_info("Base memory val 0x%llx\n", vcmd_buf_mem_pool.busAddress);
+    pr_info("Base memory len 0x%x\n", CMDBUF_POOL_TOTAL_SIZE*2 + CMDBUF_VCMD_REGISTER_TOTAL_SIZE);
+
+    vcmd_buf_mem_pool.size =CMDBUF_POOL_TOTAL_SIZE;
+    pr_info("Init: vcmd_buf_mem_pool.busAddress=0x%llx.\n",(long long unsigned int)vcmd_buf_mem_pool.busAddress);
+
+    if (vcmd_buf_mem_pool.virtualAddress == NULL ) {
+      pr_info("Init: failed to ioremap.\n");
+      return -1;
+    }
+    pr_info("Init: vcmd_buf_mem_pool.virtualAddress=0x%llx.\n",(long long unsigned int)vcmd_buf_mem_pool.virtualAddress);
+    if (mmu_enable) {
+      addr.bus_address = vcmd_buf_mem_pool.busAddress - gBaseDDRHw;
+      addr.size = vcmd_buf_mem_pool.size;
+      if(MMUKernelMemNodeMap(&addr) != MMU_STATUS_OK) {
+        return -1;
+      }
+      vcmd_buf_mem_pool.mmu_bus_address = addr.mmu_bus_address;
+      pr_info("Init: vcmd_buf_mem_pool.mmu_bus_address=0x%llx.\n",(long long unsigned int)vcmd_buf_mem_pool.mmu_bus_address);
+    }
+
+    vcmd_status_buf_mem_pool.busAddress = (void *)vcmd_buf_mem_pool.busAddress+CMDBUF_POOL_TOTAL_SIZE;
+    vcmd_status_buf_mem_pool.virtualAddress = (void *)vcmd_buf_mem_pool.virtualAddress+CMDBUF_POOL_TOTAL_SIZE;
+    vcmd_status_buf_mem_pool.size =CMDBUF_POOL_TOTAL_SIZE;
+    pr_info("Init: vcmd_status_buf_mem_pool.busAddress=0x%llx.\n",(long long unsigned int)vcmd_status_buf_mem_pool.busAddress);
+    if (vcmd_status_buf_mem_pool.virtualAddress == NULL ) {
+      pr_info("Init: failed to ioremap.\n");
+      return -1;
+    }
+    pr_info("Init: vcmd_status_buf_mem_pool.virtualAddress=0x%llx.\n",(long long unsigned int)vcmd_status_buf_mem_pool.virtualAddress);
+    if (mmu_enable) {
+      addr.bus_address = vcmd_status_buf_mem_pool.busAddress - gBaseDDRHw;
+      addr.size = vcmd_status_buf_mem_pool.size;
+      if(MMUKernelMemNodeMap(&addr) != MMU_STATUS_OK) {
+        return -1;
+      }
+      vcmd_status_buf_mem_pool.mmu_bus_address = addr.mmu_bus_address;
+      pr_info("Init: vcmd_status_buf_mem_pool.mmu_bus_address=0x%llx.\n",(long long unsigned int)vcmd_status_buf_mem_pool.mmu_bus_address);
+    }
+
+    vcmd_registers_mem_pool.busAddress = (void *)vcmd_buf_mem_pool.busAddress+CMDBUF_POOL_TOTAL_SIZE*2;
+    vcmd_registers_mem_pool.virtualAddress = (void *)vcmd_buf_mem_pool.virtualAddress+CMDBUF_POOL_TOTAL_SIZE*2;
+    vcmd_registers_mem_pool.size =CMDBUF_VCMD_REGISTER_TOTAL_SIZE;
+    pr_info("Init: vcmd_registers_mem_pool.busAddress=0x%llx.\n",(long long unsigned int)vcmd_registers_mem_pool.busAddress);
+
+    if (vcmd_registers_mem_pool.virtualAddress == NULL ) {
+      pr_info("Init: failed to ioremap.\n");
+      return -1;
+    }
+    pr_info("Init: vcmd_registers_mem_pool.virtualAddress=0x%llx.\n",(long long unsigned int)vcmd_registers_mem_pool.virtualAddress);
+    if (mmu_enable) {
+      addr.bus_address = vcmd_registers_mem_pool.busAddress - gBaseDDRHw;
+      addr.size = vcmd_registers_mem_pool.size;
+      if(MMUKernelMemNodeMap(&addr) != MMU_STATUS_OK) {
+        return -1;
+      }
+      vcmd_registers_mem_pool.mmu_bus_address = addr.mmu_bus_address;
+      pr_info("Init: vcmd_registers_mem_pool.mmu_bus_address=0x%llx.\n",(long long unsigned int)vcmd_registers_mem_pool.mmu_bus_address);
+    }
+
+
+    return 0;
+
+out_pci_disable_device:
+    pci_disable_device(g_vcmd_dev);
+out:
+    return -1;
+}
+
+static void vcmd_link_cmdbuf(struct hantrovcmd_dev *dev,bi_list_node* last_linked_cmdbuf_node)
+{
+  bi_list_node* new_cmdbuf_node=NULL;
+  bi_list_node* next_cmdbuf_node=NULL;
+  struct cmdbuf_obj* cmdbuf_obj=NULL;
+  struct cmdbuf_obj* next_cmdbuf_obj=NULL;
+  u32 * jmp_addr=NULL;
+  u32 operation_code;
+  new_cmdbuf_node = last_linked_cmdbuf_node;
+  //for the first cmdbuf.
+  if(new_cmdbuf_node!=NULL)
+  {
+    cmdbuf_obj = (struct cmdbuf_obj*)new_cmdbuf_node->data;
+    if((cmdbuf_obj->cmdbuf_data_linked==0) )
+    {
+      dev->sw_cmdbuf_rdy_num ++;
+      cmdbuf_obj->cmdbuf_data_linked=1;
+      dev->duration_without_int = 0;
+      if(cmdbuf_obj->has_end_cmdbuf==0)
+      {
+        if(cmdbuf_obj->no_normal_int_cmdbuf==1)
+        {
+          dev->duration_without_int = cmdbuf_obj->executing_time;
+          //maybe nop is modified, so write back.
+          if(dev->duration_without_int>=INT_MIN_SUM_OF_IMAGE_SIZE)
+          {
+            jmp_addr = cmdbuf_obj->cmdbuf_virtualAddress + (cmdbuf_obj->cmdbuf_size/4);
+            operation_code = *(jmp_addr-4);
+            operation_code = JMP_IE_1|operation_code;
+            *(jmp_addr-4) = operation_code;
+            dev->duration_without_int = 0;
+          }
+
+        }
+      }
+    }
+  }
+  while(1)
+  {
+    if(new_cmdbuf_node==NULL)
+      break;
+    if(new_cmdbuf_node->next==NULL)
+      break;
+    next_cmdbuf_node = new_cmdbuf_node->next;
+    cmdbuf_obj = (struct cmdbuf_obj*)new_cmdbuf_node->data;
+    next_cmdbuf_obj = (struct cmdbuf_obj*)next_cmdbuf_node->data;
+    if(cmdbuf_obj->has_end_cmdbuf==0 && !next_cmdbuf_obj->cmdbuf_run_done)
+    {
+      //need to link, current cmdbuf link to next cmdbuf
+      PDEBUG("Link cmdbuf %d to cmdbuf %d", cmdbuf_obj->cmdbuf_id, next_cmdbuf_obj->cmdbuf_id);
+      jmp_addr = cmdbuf_obj->cmdbuf_virtualAddress + (cmdbuf_obj->cmdbuf_size/4);
+      if(dev->hw_version_id > HW_ID_1_0_C )
+      {
+        //set next cmdbuf id
+        *(jmp_addr-1) = next_cmdbuf_obj->cmdbuf_id;
+      }
+      if (mmu_enable) {
+        if(sizeof(size_t) == 8) {
+          *(jmp_addr-2)=(u32)((u64)(next_cmdbuf_obj->mmu_cmdbuf_busAddress)>>32);
+        } else {
+          *(jmp_addr-2)=0;
+        }
+        *(jmp_addr-3)=(u32)(next_cmdbuf_obj->mmu_cmdbuf_busAddress);
+      } else {
+        if(sizeof(size_t) == 8) {
+          *(jmp_addr-2)=(u32)((u64)(next_cmdbuf_obj->cmdbuf_busAddress-base_ddr_addr)>>32);
+        } else {
+          *(jmp_addr-2)=0;
+        }
+        *(jmp_addr-3)=(u32)(next_cmdbuf_obj->cmdbuf_busAddress-base_ddr_addr);
+      }
+      operation_code = *(jmp_addr-4);
+      operation_code >>=16;
+      operation_code <<=16;
+      *(jmp_addr-4)=(u32)(operation_code |JMP_RDY_1|((next_cmdbuf_obj->cmdbuf_size+7)/8));
+      next_cmdbuf_obj->cmdbuf_data_linked = 1;
+      dev->sw_cmdbuf_rdy_num ++;
+      //modify nop code of next cmdbuf
+      if(next_cmdbuf_obj->has_end_cmdbuf==0)
+      {
+        if(next_cmdbuf_obj->no_normal_int_cmdbuf==1)
+        {
+          dev->duration_without_int +=next_cmdbuf_obj->executing_time;
+
+          //maybe we see the modified nop before abort, so need to write back.
+          if(dev->duration_without_int>=INT_MIN_SUM_OF_IMAGE_SIZE)
+          {
+            jmp_addr = next_cmdbuf_obj->cmdbuf_virtualAddress + (next_cmdbuf_obj->cmdbuf_size/4);
+            operation_code = *(jmp_addr-4);
+            operation_code = JMP_IE_1|operation_code;
+            *(jmp_addr-4) = operation_code;
+            dev->duration_without_int = 0;
+          }
+        }
+      }
+      else
+      {
+        dev->duration_without_int = 0;
+      }
+#ifdef VCMD_DEBUG_INTERNAL
+      {
+         u32 i;
+         pr_info("vcmd link, last cmdbuf content\n");
+         for(i=cmdbuf_obj->cmdbuf_size/4 -8;i<cmdbuf_obj->cmdbuf_size/4;i++)
+         {
+           pr_info("current linked cmdbuf data %d =0x%x\n",i,*(cmdbuf_obj->cmdbuf_virtualAddress+i));
+         }
+      }
+#endif
+    }
+    else
+      break;
+    new_cmdbuf_node = new_cmdbuf_node->next;
+  }
+  return;
+}
+
+/* delink all the cmd buffers from the cmdbuf in front oflast_linked_cmdbuf_node
+   to head of the list. All the cmd bufs marked as X will be delinked.
+   E.g.,
+   X->X->...->X->L->L->        ...        ->L
+   ^             ^                          ^
+   head          last_linked_cmdbuf_node    tail
+ */
+static void vcmd_delink_cmdbuf(struct hantrovcmd_dev *dev,bi_list_node* last_linked_cmdbuf_node)
+{
+  bi_list_node* new_cmdbuf_node=NULL;
+  struct cmdbuf_obj* cmdbuf_obj=NULL;
+
+  new_cmdbuf_node = last_linked_cmdbuf_node;
+  while(1)
+  {
+    if(new_cmdbuf_node==NULL)
+      break;
+    cmdbuf_obj = (struct cmdbuf_obj*)new_cmdbuf_node->data;
+    if(cmdbuf_obj->cmdbuf_data_linked)
+    {
+      cmdbuf_obj->cmdbuf_data_linked = 0;
+    }
+    else
+      break;
+    new_cmdbuf_node = new_cmdbuf_node->next;
+  }
+  dev->sw_cmdbuf_rdy_num=0;
+}
+
+static void vcmd_start(struct hantrovcmd_dev *dev,bi_list_node* first_linked_cmdbuf_node)
+{
+  struct cmdbuf_obj* cmdbuf_obj=NULL;
+
+  if(dev->working_state == WORKING_STATE_IDLE)
+  {
+    if((first_linked_cmdbuf_node!=NULL) && dev->sw_cmdbuf_rdy_num)
+    {
+      cmdbuf_obj = (struct cmdbuf_obj*)first_linked_cmdbuf_node->data;
+      printk_vcmd_register_debug((const void *)dev->hwregs, "vcmd_start enters");
+      //0x40
+      vcmd_set_register_mirror_value(dev->reg_mirror,HWIF_VCMD_AXI_CLK_GATE_DISABLE,0);
+      vcmd_set_register_mirror_value(dev->reg_mirror,HWIF_VCMD_MASTER_OUT_CLK_GATE_DISABLE,1);//this bit should be set 1 only when need to reset dec400
+      vcmd_set_register_mirror_value(dev->reg_mirror,HWIF_VCMD_CORE_CLK_GATE_DISABLE,0);
+      vcmd_set_register_mirror_value(dev->reg_mirror,HWIF_VCMD_ABORT_MODE,0);
+      vcmd_set_register_mirror_value(dev->reg_mirror,HWIF_VCMD_RESET_CORE,0);
+      vcmd_set_register_mirror_value(dev->reg_mirror,HWIF_VCMD_RESET_ALL,0);
+      vcmd_set_register_mirror_value(dev->reg_mirror,HWIF_VCMD_START_TRIGGER,0);
+      //0x48
+      if(dev->hw_version_id <= HW_ID_1_0_C)
+        vcmd_set_register_mirror_value(dev->reg_mirror,HWIF_VCMD_IRQ_INTCMD_EN,0xffff);
+      else
+      {
+        vcmd_set_register_mirror_value(dev->reg_mirror,HWIF_VCMD_IRQ_JMPP_EN,1);
+        vcmd_set_register_mirror_value(dev->reg_mirror,HWIF_VCMD_IRQ_JMPD_EN,1);
+      }
+
+      vcmd_set_register_mirror_value(dev->reg_mirror,HWIF_VCMD_IRQ_RESET_EN,1);
+      vcmd_set_register_mirror_value(dev->reg_mirror,HWIF_VCMD_IRQ_ABORT_EN,1);
+      vcmd_set_register_mirror_value(dev->reg_mirror,HWIF_VCMD_IRQ_CMDERR_EN,1);
+      vcmd_set_register_mirror_value(dev->reg_mirror,HWIF_VCMD_IRQ_TIMEOUT_EN,1);
+      vcmd_set_register_mirror_value(dev->reg_mirror,HWIF_VCMD_IRQ_BUSERR_EN,1);
+      vcmd_set_register_mirror_value(dev->reg_mirror,HWIF_VCMD_IRQ_ENDCMD_EN,1);
+      //0x4c
+      vcmd_set_register_mirror_value(dev->reg_mirror,HWIF_VCMD_TIMEOUT_EN,1);
+      vcmd_set_register_mirror_value(dev->reg_mirror,HWIF_VCMD_TIMEOUT_CYCLES,0x1dcd6500);
+      if (mmu_enable) {
+        vcmd_set_register_mirror_value(dev->reg_mirror,HWIF_VCMD_EXECUTING_CMD_ADDR,(u32)(cmdbuf_obj->mmu_cmdbuf_busAddress));
+        if(sizeof(size_t) == 8) {
+          vcmd_set_register_mirror_value(dev->reg_mirror,HWIF_VCMD_EXECUTING_CMD_ADDR_MSB,(u32)((u64)(cmdbuf_obj->mmu_cmdbuf_busAddress)>>32));
+        } else {
+          vcmd_set_register_mirror_value(dev->reg_mirror,HWIF_VCMD_EXECUTING_CMD_ADDR_MSB, 0);
+        }
+      } else {
+        vcmd_set_register_mirror_value(dev->reg_mirror,HWIF_VCMD_EXECUTING_CMD_ADDR,(u32)(cmdbuf_obj->cmdbuf_busAddress-base_ddr_addr));
+        if(sizeof(size_t) == 8) {
+          vcmd_set_register_mirror_value(dev->reg_mirror,HWIF_VCMD_EXECUTING_CMD_ADDR_MSB,(u32)((u64)(cmdbuf_obj->cmdbuf_busAddress-base_ddr_addr)>>32));
+        } else {
+          vcmd_set_register_mirror_value(dev->reg_mirror,HWIF_VCMD_EXECUTING_CMD_ADDR_MSB, 0);
+        }
+      }
+      vcmd_set_register_mirror_value(dev->reg_mirror,HWIF_VCMD_EXE_CMDBUF_LENGTH,(u32)((cmdbuf_obj->cmdbuf_size+7)/8));
+      vcmd_set_register_mirror_value(dev->reg_mirror,HWIF_VCMD_RDY_CMDBUF_COUNT,dev->sw_cmdbuf_rdy_num);
+      vcmd_set_register_mirror_value(dev->reg_mirror,HWIF_VCMD_MAX_BURST_LEN,0x10);
+      if(dev->hw_version_id > HW_ID_1_0_C )
+      {
+        vcmd_write_register_value((const void *)dev->hwregs,dev->reg_mirror,HWIF_VCMD_CMDBUF_EXECUTING_ID,(u32)cmdbuf_obj->cmdbuf_id);
+      }
+      vcmd_write_reg((const void *)dev->hwregs,0x40,dev->reg_mirror[0x40/4]);
+      vcmd_write_reg((const void *)dev->hwregs,0x44,vcmd_read_reg((const void *)dev->hwregs,0x44));
+      vcmd_write_reg((const void *)dev->hwregs,0x48,dev->reg_mirror[0x48/4]);
+      vcmd_write_reg((const void *)dev->hwregs,0x4c,dev->reg_mirror[0x4c/4]);
+      vcmd_write_reg((const void *)dev->hwregs,0x50,dev->reg_mirror[0x50/4]);
+      vcmd_write_reg((const void *)dev->hwregs,0x54,dev->reg_mirror[0x54/4]);
+      vcmd_write_reg((const void *)dev->hwregs,0x58,dev->reg_mirror[0x58/4]);
+      vcmd_write_reg((const void *)dev->hwregs,0x5c,dev->reg_mirror[0x5c/4]);
+      vcmd_write_reg((const void *)dev->hwregs,0x60,dev->reg_mirror[0x60/4]);
+      vcmd_write_reg((const void *)dev->hwregs,0x64,0xffffffff);//not interrupt cpu
+
+      dev->working_state = WORKING_STATE_WORKING;
+      //start
+      vcmd_set_register_mirror_value(dev->reg_mirror,HWIF_VCMD_MASTER_OUT_CLK_GATE_DISABLE,0);//this bit should be set 1 only when need to reset dec400
+      vcmd_set_register_mirror_value(dev->reg_mirror,HWIF_VCMD_START_TRIGGER,1);
+      vcmd_write_reg((const void *)dev->hwregs,0x40,dev->reg_mirror[0x40/4]);
+
+      printk_vcmd_register_debug((const void *)dev->hwregs, "vcmd_start exits ");
+    }
+  }
+
+}
+
+static void create_read_all_registers_cmdbuf(struct exchange_parameter* input_para)
+{
+    u32 register_range[]={VCMD_ENCODER_REGISTER_SIZE,
+                    VCMD_IM_REGISTER_SIZE,
+                    VCMD_DECODER_REGISTER_SIZE,
+                    VCMD_JPEG_ENCODER_REGISTER_SIZE,
+                    VCMD_JPEG_DECODER_REGISTER_SIZE};
+    u32 counter_cmdbuf_size=0;
+    u32 * set_base_addr=vcmd_buf_mem_pool.virtualAddress + input_para->cmdbuf_id*CMDBUF_MAX_SIZE/4;
+    //u32 *status_base_virt_addr=vcmd_status_buf_mem_pool.virtualAddress + input_para->cmdbuf_id*CMDBUF_MAX_SIZE/4+(vcmd_manager[input_para->module_type][0]->vcmd_core_cfg.submodule_main_addr/2/4+0);
+    ptr_t status_base_phy_addr=vcmd_status_buf_mem_pool.busAddress + input_para->cmdbuf_id*CMDBUF_MAX_SIZE+(vcmd_manager[input_para->module_type][0]->vcmd_core_cfg.submodule_main_addr/2+0);
+    u32 map_status_base_phy_addr=vcmd_status_buf_mem_pool.mmu_bus_address + input_para->cmdbuf_id*CMDBUF_MAX_SIZE+(vcmd_manager[input_para->module_type][0]->vcmd_core_cfg.submodule_main_addr/2+0);
+    u32 offset_inc=0;
+    if(vcmd_manager[input_para->module_type][0]->hw_version_id>HW_ID_1_0_C)
+    {
+      pr_info("vc8000_vcmd_driver:create cmdbuf data when hw_version_id = 0x%x\n",vcmd_manager[input_para->module_type][0]->hw_version_id);
+
+      //read vcmd executing cmdbuf id registers to ddr for balancing core load.
+      *(set_base_addr+0) = (OPCODE_RREG) |(1<<16) |(EXECUTING_CMDBUF_ID_ADDR*4);
+      counter_cmdbuf_size += 4;
+      *(set_base_addr+1) = (u32)0; //will be changed in link stage
+      counter_cmdbuf_size += 4;
+      *(set_base_addr+2) = (u32)0; //will be changed in link stage
+      counter_cmdbuf_size += 4;
+      //alignment
+      *(set_base_addr+3) = 0;
+      counter_cmdbuf_size += 4;
+
+      //read main IP all registers
+      *(set_base_addr+4) = (OPCODE_RREG) |((register_range[input_para->module_type]/4)<<16) |(vcmd_manager[input_para->module_type][0]->vcmd_core_cfg.submodule_main_addr+0);
+      counter_cmdbuf_size += 4;
+      if (mmu_enable) {
+        *(set_base_addr+5) = map_status_base_phy_addr;
+      } else {
+        *(set_base_addr+5) = (u32)(status_base_phy_addr-base_ddr_addr);
+      }
+      counter_cmdbuf_size += 4;
+      if (mmu_enable) {
+        *(set_base_addr+6) = 0;
+      } else {
+        if(sizeof(size_t) == 8) {
+          *(set_base_addr+6) = (u32)((u64)(status_base_phy_addr-base_ddr_addr)>>32);
+        } else {
+          *(set_base_addr+6) = 0;
+        }
+      }
+      counter_cmdbuf_size += 4;
+      //alignment
+      *(set_base_addr+7) = 0;
+      counter_cmdbuf_size += 4;
+      if(vcmd_manager[input_para->module_type][0]->vcmd_core_cfg.submodule_L2Cache_addr != 0xffff)
+      {
+        offset_inc = 4;
+        status_base_phy_addr=vcmd_status_buf_mem_pool.busAddress + input_para->cmdbuf_id*CMDBUF_MAX_SIZE+(vcmd_manager[input_para->module_type][0]->vcmd_core_cfg.submodule_L2Cache_addr/2+0);
+        map_status_base_phy_addr=vcmd_status_buf_mem_pool.mmu_bus_address + input_para->cmdbuf_id*CMDBUF_MAX_SIZE+(vcmd_manager[input_para->module_type][0]->vcmd_core_cfg.submodule_L2Cache_addr/2+0);
+        //read L2cache IP first register
+        *(set_base_addr+8) = (OPCODE_RREG) |(1<<16) |(vcmd_manager[input_para->module_type][0]->vcmd_core_cfg.submodule_L2Cache_addr+0);
+        counter_cmdbuf_size += 4;
+        if (mmu_enable) {
+          *(set_base_addr+9) = map_status_base_phy_addr;
+        } else {
+          *(set_base_addr+9) = (u32)(status_base_phy_addr-base_ddr_addr);
+        }
+        counter_cmdbuf_size += 4;
+        if (mmu_enable) {
+          *(set_base_addr+10) = 0;
+        } else {
+          if(sizeof(size_t) == 8) {
+            *(set_base_addr+10) = (u32)((u64)(status_base_phy_addr-base_ddr_addr)>>32);
+          } else {
+            *(set_base_addr+10) = 0;
+          }
+        }
+        counter_cmdbuf_size += 4;
+        //alignment
+        *(set_base_addr+11) = 0;
+        counter_cmdbuf_size += 4;
+      }
+
+#if 0
+      //INT code, interrupt immediately
+      *(set_base_addr+4) = (OPCODE_INT) |0 |input_para->cmdbuf_id;
+      counter_cmdbuf_size += 4;
+      //alignment
+      *(set_base_addr+5) = 0;
+      counter_cmdbuf_size += 4;
+#endif
+      //read vcmd registers to ddr
+      *(set_base_addr+8+offset_inc) = (OPCODE_RREG) |(27<<16) |(0);
+      counter_cmdbuf_size += 4;
+      *(set_base_addr+9+offset_inc) = (u32)0; //will be changed in link stage
+      counter_cmdbuf_size += 4;
+      *(set_base_addr+10+offset_inc) = (u32)0; //will be changed in link stage
+      counter_cmdbuf_size += 4;
+      //alignment
+      *(set_base_addr+11+offset_inc) = 0;
+      counter_cmdbuf_size += 4;
+      //JMP RDY = 0
+      *(set_base_addr +12+offset_inc)= (OPCODE_JMP_RDY0) |0 |JMP_IE_1|0;
+      counter_cmdbuf_size += 4;
+      *(set_base_addr +13+offset_inc) = 0;
+      counter_cmdbuf_size += 4;
+      *(set_base_addr +14+offset_inc) = 0;
+      counter_cmdbuf_size += 4;
+      *(set_base_addr +15+offset_inc) = input_para->cmdbuf_id;
+      //don't add the last alignment DWORD in order to  identify END command or JMP command.
+      //counter_cmdbuf_size += 4;
+      input_para->cmdbuf_size=(16+offset_inc)*4;
+    }
+    else
+    {
+      pr_info("vc8000_vcmd_driver:create cmdbuf data when hw_version_id = 0x%x\n",vcmd_manager[input_para->module_type][0]->hw_version_id);
+      //read all registers
+      *(set_base_addr+0) = (OPCODE_RREG) |((register_range[input_para->module_type]/4)<<16) |(vcmd_manager[input_para->module_type][0]->vcmd_core_cfg.submodule_main_addr+0);
+      counter_cmdbuf_size += 4;
+      if (mmu_enable) {
+        *(set_base_addr+1) = map_status_base_phy_addr;
+      } else {
+        *(set_base_addr+1) = (u32)(status_base_phy_addr-base_ddr_addr);
+      }
+      counter_cmdbuf_size += 4;
+      if (mmu_enable) {
+        *(set_base_addr+2) = 0;
+      } else {
+        if(sizeof(size_t) == 8) {
+          *(set_base_addr+2) = (u32)((u64)(status_base_phy_addr-base_ddr_addr)>>32);
+        } else {
+          *(set_base_addr+2) = 0;
+        }
+      }
+      counter_cmdbuf_size += 4;
+      //alignment
+      *(set_base_addr+3) = 0;
+      counter_cmdbuf_size += 4;
+#if 0
+      //INT code, interrupt immediately
+      *(set_base_addr+4) = (OPCODE_INT) |0 |input_para->cmdbuf_id;
+      counter_cmdbuf_size += 4;
+      //alignment
+      *(set_base_addr+5) = 0;
+      counter_cmdbuf_size += 4;
+#endif
+      //JMP RDY = 0
+      *(set_base_addr +4)= (OPCODE_JMP_RDY0) |0 |JMP_IE_1|0;
+      counter_cmdbuf_size += 4;
+      *(set_base_addr +5) = 0;
+      counter_cmdbuf_size += 4;
+      *(set_base_addr +6) = 0;
+      counter_cmdbuf_size += 4;
+      *(set_base_addr +7) = input_para->cmdbuf_id;
+      //don't add the last alignment DWORD in order to  identify END command or JMP command.
+      //counter_cmdbuf_size += 4;
+      input_para->cmdbuf_size=8*4;
+    }
+}
+static void read_main_module_all_registers(u32 main_module_type)
+{
+  int ret;
+  struct exchange_parameter input_para;
+  u32 irq_status_ret=0;
+  u32 *status_base_virt_addr;
+
+  input_para.executing_time=0;
+  input_para.priority=CMDBUF_PRIORITY_NORMAL;
+  input_para.module_type = main_module_type;
+  input_para.cmdbuf_size=0;
+  ret = reserve_cmdbuf(NULL,&input_para);
+  vcmd_manager[main_module_type][0]->status_cmdbuf_id = input_para.cmdbuf_id;
+  create_read_all_registers_cmdbuf(&input_para);
+  link_and_run_cmdbuf(NULL,&input_para);
+  //msleep(1000);
+  hantrovcmd_isr(input_para.core_id, &hantrovcmd_data[input_para.core_id]);
+  wait_cmdbuf_ready(NULL,input_para.cmdbuf_id,&irq_status_ret);
+  status_base_virt_addr=vcmd_status_buf_mem_pool.virtualAddress + input_para.cmdbuf_id*CMDBUF_MAX_SIZE/4+(vcmd_manager[input_para.module_type][0]->vcmd_core_cfg.submodule_main_addr/2/4+0);
+  pr_info("vc8000_vcmd_driver: main module register 0:0x%x\n",*status_base_virt_addr);
+  pr_info("vc8000_vcmd_driver: main module register 50:0x%08x\n",*(status_base_virt_addr+50));
+  pr_info("vc8000_vcmd_driver: main module register 54:0x%08x\n",*(status_base_virt_addr+54));
+  pr_info("vc8000_vcmd_driver: main module register 56:0x%08x\n",*(status_base_virt_addr+56));
+  pr_info("vc8000_vcmd_driver: main module register 309:0x%x\n",*(status_base_virt_addr+309));
+  //don't release cmdbuf because it can be used repeatedly
+  //release_cmdbuf(input_para.cmdbuf_id);
+}
+
+int hantrovcmd_init(struct platform_device *pdev)
+{
+  int i,k;
+  int result;
+  struct kernel_addr_desc addr;
+
+  //total_vcmd_core_num = sizeof(vcmd_core_array)/sizeof(struct vcmd_config);
+  result = vcmd_init(pdev);
+  if(result)
+     goto err;
+  
+  for (i = 0; i< total_vcmd_core_num; i++)
+  {
+    pr_info("vcmd: module init - vcmdcore[%d] addr =0x%llx\n",i,
+           (long long unsigned int)vcmd_core_array[i].vcmd_base_addr);
+  }
+  hantrovcmd_data = (struct hantrovcmd_dev *)vmalloc(sizeof(struct hantrovcmd_dev)*total_vcmd_core_num);
+  if (hantrovcmd_data == NULL)
+    goto err;
+  memset(hantrovcmd_data,0,sizeof(struct hantrovcmd_dev)*total_vcmd_core_num);
+  hantrovcmd_data[0].pdev = pdev;
+  for(k=0;k<MAX_VCMD_TYPE;k++)
+  {
+    vcmd_type_core_num[k]=0;
+    vcmd_position[k]=0;
+    for(i=0;i<MAX_VCMD_NUMBER;i++)
+    {
+      vcmd_manager[k][i]=NULL;
+    }
+  }
+
+  init_bi_list(&global_process_manager);
+
+  for(i=0;i<total_vcmd_core_num;i++)
+  {
+    hantrovcmd_data[i].vcmd_core_cfg = vcmd_core_array[i];
+    hantrovcmd_data[i].hwregs = NULL;
+    hantrovcmd_data[i].core_id = i;
+    hantrovcmd_data[i].working_state= WORKING_STATE_IDLE;
+    hantrovcmd_data[i].sw_cmdbuf_rdy_num =0;
+    hantrovcmd_data[i].spinlock = &owner_lock_vcmd[i];
+    spin_lock_init(&owner_lock_vcmd[i]);
+    hantrovcmd_data[i].wait_queue = &wait_queue_vcmd[i];
+    init_waitqueue_head(&wait_queue_vcmd[i]);
+    hantrovcmd_data[i].wait_abort_queue=&abort_queue_vcmd[i];
+    init_waitqueue_head(&abort_queue_vcmd[i]);
+    init_bi_list(&hantrovcmd_data[i].list_manager);
+    hantrovcmd_data[i].duration_without_int = 0;
+    vcmd_manager[vcmd_core_array[i].sub_module_type][vcmd_type_core_num[vcmd_core_array[i].sub_module_type]]=&hantrovcmd_data[i];
+    vcmd_type_core_num[vcmd_core_array[i].sub_module_type]++;
+    hantrovcmd_data[i].vcmd_reg_mem_busAddress = vcmd_registers_mem_pool.busAddress + i*VCMD_REGISTER_SIZE-base_ddr_addr;
+    hantrovcmd_data[i].mmu_vcmd_reg_mem_busAddress = vcmd_registers_mem_pool.mmu_bus_address + i*VCMD_REGISTER_SIZE;
+    hantrovcmd_data[i].vcmd_reg_mem_virtualAddress = vcmd_registers_mem_pool.virtualAddress + i*VCMD_REGISTER_SIZE/4;
+    hantrovcmd_data[i].vcmd_reg_mem_size = VCMD_REGISTER_SIZE;
+    memset(hantrovcmd_data[i].vcmd_reg_mem_virtualAddress,0,VCMD_REGISTER_SIZE);
+  }
+  init_waitqueue_head(&mc_wait_queue);
+
+#if 0
+  result = register_chrdev(hantrovcmd_major, "hantrodec", &hantrovcmd_fops);
+  if(result < 0)
+  {
+    pr_info("vc8000_vcmd_driver: unable to get major <%d>\n",
+           hantrovcmd_major);
+    goto err1;
+  }
+  else if(result != 0)    /* this is for dynamic major */
+  {
+    hantrovcmd_major = result;
+  }
+#endif
+  result = vcmd_reserve_IO();
+  if(result < 0)
+  {
+    goto err;
+  }
+  vcmd_reset_asic(hantrovcmd_data);
+
+  hantrovcmd_data[0].vcmd_core_cfg.vcmd_irq = platform_get_irq(pdev, 0);
+  pr_info("%s:get irq %d\n",__func__,hantrovcmd_data[0].vcmd_core_cfg.vcmd_irq);
+
+  /* get the IRQ line */
+  for (i=0;i<total_vcmd_core_num;i++)
+  {
+    if (hantrovcmd_data[i].hwregs==NULL)
+      continue;
+
+#ifdef VCMD_DEBUG_INTERNAL
+    {
+         u32 j, fordebug;
+         for(j=0;j<ASIC_VCMD_SWREG_AMOUNT;j++)
+         {
+           fordebug=vcmd_read_reg ((const void *)hantrovcmd_data[i].hwregs, j*4);
+           pr_info("vcmd register %d:0x%x\n",j,fordebug);
+         }
+    }
+#endif
+    if(hantrovcmd_data[i].vcmd_core_cfg.vcmd_irq!= -1)
+    {
+      result = request_irq(hantrovcmd_data[i].vcmd_core_cfg.vcmd_irq, hantrovcmd_isr,
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18))
+                           SA_INTERRUPT | SA_SHIRQ,
+#else
+                           IRQF_SHARED,
+#endif
+                           "vc8000_vcmd_driver", (void *) &hantrovcmd_data[i]);
+      if(result == -EINVAL)
+      {
+        pr_err("vc8000_vcmd_driver: Bad vcmd_irq number or handler. core_id=%d\n",i);
+        vcmd_release_IO();
+        goto err;
+      }
+      else if(result == -EBUSY)
+      {
+        pr_err("vc8000_vcmd_driver: IRQ <%d> busy, change your config. core_id=%d\n",
+               hantrovcmd_data[i].vcmd_core_cfg.vcmd_irq,i);
+        vcmd_release_IO();
+        goto err;
+      } else {
+        pr_info("vc8000_vcmd_driver: request IRQ <%d> successfully for subsystem %d\n",
+               hantrovcmd_data[i].vcmd_core_cfg.vcmd_irq, i);
+      }
+    }
+    else
+    {
+      pr_info("vc8000_vcmd_driver: IRQ not in use!\n");
+    }
+  }
+  //cmdbuf pool allocation
+  //init_vcmd_non_cachable_memory_allocate();
+  //for cmdbuf management
+  cmdbuf_used_pos=0;
+  for(k=0;k<TOTAL_DISCRETE_CMDBUF_NUM;k++)
+  {
+    cmdbuf_used[k]=0;
+    global_cmdbuf_node[k] = NULL;
+  }
+  //cmdbuf_used[0] not be used, because int vector must non-zero
+  cmdbuf_used_residual=TOTAL_DISCRETE_CMDBUF_NUM;
+  cmdbuf_used_pos=1;
+  cmdbuf_used[0]=1;
+  cmdbuf_used_residual -=1;
+
+  create_kernel_process_manager();
+  for(i=0;i<MAX_VCMD_TYPE;i++)
+  {
+    if(vcmd_type_core_num[i]==0)
+      continue;
+    sema_init(&vcmd_reserve_cmdbuf_sem[i], 1);
+  }
+#ifdef IRQ_SIMULATION
+  for(i=0;i<10000;i++)
+  {
+    timer_reserve[i].timer=NULL;
+  }
+#endif
+#ifndef  DYNAMIC_MALLOC_VCMDNODE
+  g_cmdbuf_obj_pool = vmalloc(sizeof(struct cmdbuf_obj) * TOTAL_DISCRETE_CMDBUF_NUM);
+  g_cmdbuf_node_pool  = vmalloc(sizeof(bi_list_node) * TOTAL_DISCRETE_CMDBUF_NUM);
+#endif
+  /*read all registers for each type of module for analyzing configuration in cwl*/
+  for(i=0;i<MAX_VCMD_TYPE;i++)
+  {
+    if(vcmd_type_core_num[i]==0)
+      continue;
+    read_main_module_all_registers(i);
+  }
+
+
+  return 0;
+  err:
+    if (vcmd_buf_mem_pool.virtualAddress) {
+      if (mmu_enable) {
+        addr.bus_address = vcmd_buf_mem_pool.busAddress;
+        addr.size = vcmd_buf_mem_pool.size;
+        MMUKernelMemNodeUnmap(&addr);
+      }
+      dma_free_coherent(&pdev->dev, CMDBUF_POOL_TOTAL_SIZE*2 + CMDBUF_VCMD_REGISTER_TOTAL_SIZE,
+            vcmd_buf_mem_pool.virtualAddress, vcmd_buf_mem_pool.busAddress);
+    }
+    if (vcmd_status_buf_mem_pool.virtualAddress) {
+      if (mmu_enable) {
+        addr.bus_address = vcmd_status_buf_mem_pool.busAddress;
+        addr.size = vcmd_status_buf_mem_pool.size;
+        MMUKernelMemNodeUnmap(&addr);
+      }
+    }
+    if (vcmd_registers_mem_pool.virtualAddress) {
+      if (mmu_enable) {
+        addr.bus_address = vcmd_registers_mem_pool.busAddress;
+        addr.size = vcmd_registers_mem_pool.size;
+        MMUKernelMemNodeUnmap(&addr);
+      }
+    }
+    if (hantrovcmd_data != NULL)
+      vfree(hantrovcmd_data);
+    pr_info("vc8000_vcmd_driver: module not inserted\n");
+    return result;
+}
+
+void hantrovcmd_cleanup(struct platform_device *pdev)
+{
+  int i=0;
+  u32 result;
+
+  for(i=0;i<total_vcmd_core_num;i++)
+  {
+    if (hantrovcmd_data[i].hwregs==NULL)
+      continue;
+    //disable interrupt at first
+    vcmd_write_reg((const void *) hantrovcmd_data[i].hwregs,VCMD_REGISTER_INT_CTL_OFFSET,0x0000);
+    //disable HW
+    vcmd_write_reg((const void *) hantrovcmd_data[i].hwregs,VCMD_REGISTER_CONTROL_OFFSET,0x0000);
+    //read status register
+    result =vcmd_read_reg((const void *) hantrovcmd_data[i].hwregs,VCMD_REGISTER_INT_STATUS_OFFSET);
+    //clean status register
+    vcmd_write_reg((const void *) hantrovcmd_data[i].hwregs,VCMD_REGISTER_INT_STATUS_OFFSET,result);
+
+    /* free the vcmd IRQ */
+    if(hantrovcmd_data[i].vcmd_core_cfg.vcmd_irq != -1)
+    {
+      free_irq(hantrovcmd_data[i].vcmd_core_cfg.vcmd_irq, (void *)&hantrovcmd_data[i]);
+    }
+    release_cmdbuf_node_cleanup(&hantrovcmd_data[i].list_manager);
+   }
+
+   release_process_node_cleanup(&global_process_manager);
+
+   vcmd_release_IO();
+   vfree(hantrovcmd_data);
+  dma_free_coherent(&pdev->dev, CMDBUF_POOL_TOTAL_SIZE*2 + CMDBUF_VCMD_REGISTER_TOTAL_SIZE,
+        vcmd_buf_mem_pool.virtualAddress, vcmd_buf_mem_pool.busAddress);
+
+#ifndef DYNAMIC_MALLOC_VCMDNODE
+    if (g_cmdbuf_obj_pool) {
+      vfree(g_cmdbuf_obj_pool);
+      g_cmdbuf_obj_pool = NULL;
+    } 
+    if (g_cmdbuf_node_pool) {
+      vfree(g_cmdbuf_node_pool);
+      g_cmdbuf_node_pool = NULL;
+    }
+#endif
+   pr_info("vc8000_vcmd_driver: module removed\n");
+   return;
+}
+
+static int vcmd_reserve_IO(void)
+{
+    u32 hwid;
+    int i;
+    u32 found_hw = 0;
+
+    for (i=0;i<total_vcmd_core_num;i++)
+    {
+      hantrovcmd_data[i].hwregs = NULL;
+
+      if(!request_mem_region
+         (hantrovcmd_data[i].vcmd_core_cfg.vcmd_base_addr, hantrovcmd_data[i].vcmd_core_cfg.vcmd_iosize, "vc8000_vcmd_driver"))
+      {
+          pr_info("hantrovcmd: failed to reserve HW regs for vcmd %d\n", i);
+          pr_info("hantrovcmd: vcmd_base_addr = 0x%08lx, iosize = %d\n",
+                            hantrovcmd_data[i].vcmd_core_cfg.vcmd_base_addr,
+                            hantrovcmd_data[i].vcmd_core_cfg.vcmd_iosize);
+          continue;
+      }
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,17,0))
+      hantrovcmd_data[i].hwregs =
+          (volatile u8 *) ioremap_nocache(hantrovcmd_data[i].vcmd_core_cfg.vcmd_base_addr,
+                                          hantrovcmd_data[i].vcmd_core_cfg.vcmd_iosize);
+#else
+      hantrovcmd_data[i].hwregs =
+          (volatile u8 *) ioremap(hantrovcmd_data[i].vcmd_core_cfg.vcmd_base_addr,
+                                          hantrovcmd_data[i].vcmd_core_cfg.vcmd_iosize);
+#endif
+
+      if(hantrovcmd_data[i].hwregs == NULL)
+      {
+          pr_info("hantrovcmd: failed to ioremap HW regs\n");
+          release_mem_region(hantrovcmd_data[i].vcmd_core_cfg.vcmd_base_addr, hantrovcmd_data[i].vcmd_core_cfg.vcmd_iosize);
+          continue;
+      }
+
+      /*read hwid and check validness and store it*/
+      hwid = (u32)ioread32(( void *)hantrovcmd_data[i].hwregs);
+      pr_info("hwid=0x%08x\n", hwid);
+      hantrovcmd_data[i].hw_version_id = hwid;
+
+      /* check for vcmd HW ID */
+      if( ((hwid >> 16) & 0xFFFF) != VCMD_HW_ID  )
+      {
+          pr_info("hantrovcmd: HW not found at 0x%llx\n",
+                 (long long unsigned int)hantrovcmd_data[i].vcmd_core_cfg.vcmd_base_addr);
+          iounmap(( void *) hantrovcmd_data[i].hwregs);
+          release_mem_region(hantrovcmd_data[i].vcmd_core_cfg.vcmd_base_addr, hantrovcmd_data[i].vcmd_core_cfg.vcmd_iosize);
+          hantrovcmd_data[i].hwregs = NULL;
+          continue;
+      }
+
+      found_hw = 1;
+
+      pr_info(
+             "hantrovcmd: HW at base <0x%llx> with ID <0x%08x>\n",
+             (long long unsigned int)hantrovcmd_data[i].vcmd_core_cfg.vcmd_base_addr, hwid);
+
+    }
+
+    if (found_hw == 0)
+    {
+      pr_err("hantrovcmd: NO ANY HW found!!\n");
+      return -1;
+    }
+
+    return 0;
+}
+
+static void vcmd_release_IO(void)
+{
+    u32 i;
+    for (i=0;i<total_vcmd_core_num;i++)
+    {
+     if(hantrovcmd_data[i].hwregs)
+     {
+      iounmap((void *) hantrovcmd_data[i].hwregs);
+      release_mem_region(hantrovcmd_data[i].vcmd_core_cfg.vcmd_base_addr, hantrovcmd_data[i].vcmd_core_cfg.vcmd_iosize);
+      hantrovcmd_data[i].hwregs = NULL;
+     }
+    }
+}
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18))
+static irqreturn_t hantrovcmd_isr(int irq, void *dev_id, struct pt_regs *regs)
+#else
+static irqreturn_t hantrovcmd_isr(int irq, void *dev_id)
+#endif
+{
+    unsigned int handled = 0;
+    struct hantrovcmd_dev *dev = (struct hantrovcmd_dev *) dev_id;
+    u32 irq_status=0;
+    unsigned long flags;
+    bi_list_node* new_cmdbuf_node=NULL;
+    bi_list_node* base_cmdbuf_node=NULL;
+    struct cmdbuf_obj* cmdbuf_obj=NULL;
+    size_t exe_cmdbuf_busAddress;
+    u32 cmdbuf_processed_num=0;
+    u32 cmdbuf_id=0;
+	static u32 count = 0;
+
+    /*If core is not reserved by any user, but irq is received, just clean it*/
+    spin_lock_irqsave(dev->spinlock, flags);
+    if (dev->list_manager.head==NULL)
+    {
+      u32 irq_status1=0;
+	  if (count % 100000 == 0)
+        PDEBUG( "hantrovcmd_isr:received IRQ but core has nothing to do.\n");
+      irq_status = vcmd_read_reg((const void *)dev->hwregs,VCMD_REGISTER_INT_STATUS_OFFSET);
+      vcmd_write_reg((const void *)dev->hwregs,VCMD_REGISTER_INT_STATUS_OFFSET,irq_status);
+      spin_unlock_irqrestore(dev->spinlock, flags);
+      irq_status1 = vcmd_read_reg((const void *)dev->hwregs,VCMD_REGISTER_INT_STATUS_OFFSET);
+	  if (count++ % 100000 == 0)
+        PDEBUG( "hantrovcmd_isr: irq status 0x%x -> 0x%x\n", irq_status, irq_status1);
+      return IRQ_HANDLED;
+    }
+
+    PDEBUG( "hantrovcmd_isr:received IRQ!\n");
+    irq_status = vcmd_read_reg((const void *)dev->hwregs,VCMD_REGISTER_INT_STATUS_OFFSET);
+#ifdef VCMD_DEBUG_INTERNAL
+    {
+         u32 i, fordebug;
+         for(i=0;i<ASIC_VCMD_SWREG_AMOUNT;i++)
+         {
+           fordebug=vcmd_read_reg ((const void *)dev->hwregs, i*4);
+           pr_info("vcmd register %d:0x%x\n",i,fordebug);
+         }
+    }
+#endif
+
+    if(!irq_status)
+    {
+      //pr_info("hantrovcmd_isr error,irq_status :0x%x",irq_status);
+      spin_unlock_irqrestore(dev->spinlock, flags);
+      return IRQ_HANDLED;
+    }
+
+    PDEBUG( "irq_status of %d is:%x\n",dev->core_id,irq_status);
+    vcmd_write_reg((const void *)dev->hwregs,VCMD_REGISTER_INT_STATUS_OFFSET,irq_status);
+    dev->reg_mirror[VCMD_REGISTER_INT_STATUS_OFFSET/4] = irq_status;
+
+    if((dev->hw_version_id > HW_ID_1_0_C )&&(irq_status&0x3f))
+    {
+      //if error,read from register directly.
+      cmdbuf_id = vcmd_get_register_value((const void *)dev->hwregs,dev->reg_mirror,HWIF_VCMD_CMDBUF_EXECUTING_ID);
+      if(cmdbuf_id>=TOTAL_DISCRETE_CMDBUF_NUM)
+      {
+        pr_err("hantrovcmd_isr error cmdbuf_id greater than the ceiling !!\n");
+        spin_unlock_irqrestore(dev->spinlock, flags);
+        return IRQ_HANDLED;
+      }
+    }
+    else if((dev->hw_version_id > HW_ID_1_0_C ))
+    {
+      //read cmdbuf id from ddr
+#ifdef VCMD_DEBUG_INTERNAL
+      {
+         u32 i, fordebug;
+         pr_info("ddr vcmd register phy_addr=0x%x\n",dev->vcmd_reg_mem_busAddress);
+         pr_info("ddr vcmd register virt_addr=0x%x\n",dev->vcmd_reg_mem_virtualAddress);
+         for(i=0;i<ASIC_VCMD_SWREG_AMOUNT;i++)
+         {
+           fordebug=*(dev->vcmd_reg_mem_virtualAddress+i);
+           pr_info("ddr vcmd register %d:0x%x\n",i,fordebug);
+         }
+      }
+#endif
+
+      cmdbuf_id = *(dev->vcmd_reg_mem_virtualAddress+EXECUTING_CMDBUF_ID_ADDR);
+      if(cmdbuf_id>=TOTAL_DISCRETE_CMDBUF_NUM)
+      {
+        pr_err("hantrovcmd_isr error cmdbuf_id greater than the ceiling !!\n");
+        spin_unlock_irqrestore(dev->spinlock, flags);
+        return IRQ_HANDLED;
+      }
+    }
+
+
+    if(vcmd_get_register_mirror_value(dev->reg_mirror,HWIF_VCMD_IRQ_RESET))
+    {
+      //reset error,all cmdbuf that is not  done will be run again.
+      new_cmdbuf_node = dev->list_manager.head;
+      dev->working_state = WORKING_STATE_IDLE;
+      //find the first run_done=0
+      while(1)
+      {
+        if(new_cmdbuf_node==NULL)
+          break;
+        cmdbuf_obj = (struct cmdbuf_obj*)new_cmdbuf_node->data;
+        if((cmdbuf_obj->cmdbuf_run_done == 0))
+          break;
+        new_cmdbuf_node = new_cmdbuf_node->next;
+      }
+      base_cmdbuf_node = new_cmdbuf_node;
+      vcmd_delink_cmdbuf(dev,base_cmdbuf_node);
+      vcmd_link_cmdbuf(dev,base_cmdbuf_node);
+      if(dev->sw_cmdbuf_rdy_num !=0)
+      {
+        //restart new command
+        vcmd_start(dev,base_cmdbuf_node);
+      }
+      handled++;
+      spin_unlock_irqrestore(dev->spinlock, flags);
+      return IRQ_HANDLED;
+    }
+    if(vcmd_get_register_mirror_value(dev->reg_mirror,HWIF_VCMD_IRQ_ABORT))
+    {
+      //abort error,don't need to reset
+      new_cmdbuf_node = dev->list_manager.head;
+      dev->working_state = WORKING_STATE_IDLE;
+      if(dev->hw_version_id > HW_ID_1_0_C )
+      {
+        new_cmdbuf_node = global_cmdbuf_node[cmdbuf_id];
+        if(new_cmdbuf_node==NULL)
+        {
+          pr_err("hantrovcmd_isr error cmdbuf_id !!\n");
+          spin_unlock_irqrestore(dev->spinlock, flags);
+          return IRQ_HANDLED;
+        }
+      }
+      else
+      {
+        exe_cmdbuf_busAddress = VCMDGetAddrRegisterValue((const void *)dev->hwregs,dev->reg_mirror,HWIF_VCMD_EXECUTING_CMD_ADDR);
+        //find the cmdbuf that triggers ABORT
+        while(1)
+        {
+          if(new_cmdbuf_node==NULL)
+          {
+            spin_unlock_irqrestore(dev->spinlock, flags);
+            return IRQ_HANDLED;
+          }
+          cmdbuf_obj = (struct cmdbuf_obj*)new_cmdbuf_node->data;
+          if((((cmdbuf_obj->cmdbuf_busAddress-base_ddr_addr) <=exe_cmdbuf_busAddress)&&(((cmdbuf_obj->cmdbuf_busAddress-base_ddr_addr+cmdbuf_obj->cmdbuf_size) >exe_cmdbuf_busAddress)) ) &&(cmdbuf_obj->cmdbuf_run_done==0))
+            break;
+          new_cmdbuf_node = new_cmdbuf_node->next;
+        }
+      }
+      base_cmdbuf_node = new_cmdbuf_node;
+      // this cmdbuf and cmdbufs prior to itself, run_done = 1
+      while(1)
+      {
+        if(new_cmdbuf_node==NULL)
+          break;
+        cmdbuf_obj = (struct cmdbuf_obj*)new_cmdbuf_node->data;
+        if((cmdbuf_obj->cmdbuf_run_done==0))
+        {
+          cmdbuf_obj->cmdbuf_run_done=1;
+          cmdbuf_obj->executing_status = CMDBUF_EXE_STATUS_OK;
+          cmdbuf_processed_num++;
+        }
+        else
+          break;
+        new_cmdbuf_node = new_cmdbuf_node->previous;
+      }
+      base_cmdbuf_node=base_cmdbuf_node->next;
+      vcmd_delink_cmdbuf(dev,base_cmdbuf_node);
+      spin_unlock_irqrestore(dev->spinlock, flags);
+      if(cmdbuf_processed_num)
+        wake_up_interruptible_all(dev->wait_queue);
+      //to let high priority cmdbuf be inserted
+      wake_up_interruptible_all(dev->wait_abort_queue);
+      wake_up_interruptible_all(&mc_wait_queue);
+      handled++;
+      return IRQ_HANDLED;
+    }
+    if(vcmd_get_register_mirror_value(dev->reg_mirror,HWIF_VCMD_IRQ_BUSERR))
+    {
+      //bus error, don't need to reset where to record status?
+      new_cmdbuf_node = dev->list_manager.head;
+      dev->working_state = WORKING_STATE_IDLE;
+      if(dev->hw_version_id > HW_ID_1_0_C )
+      {
+        new_cmdbuf_node = global_cmdbuf_node[cmdbuf_id];
+        if(new_cmdbuf_node==NULL)
+        {
+          pr_err("hantrovcmd_isr error cmdbuf_id !!\n");
+          spin_unlock_irqrestore(dev->spinlock, flags);
+          return IRQ_HANDLED;
+        }
+      }
+      else
+      {
+        exe_cmdbuf_busAddress = VCMDGetAddrRegisterValue((const void *)dev->hwregs,dev->reg_mirror,HWIF_VCMD_EXECUTING_CMD_ADDR);
+        //find the buserr cmdbuf
+        while(1)
+        {
+          if(new_cmdbuf_node==NULL)
+          {
+            spin_unlock_irqrestore(dev->spinlock, flags);
+            return IRQ_HANDLED;
+          }
+          cmdbuf_obj = (struct cmdbuf_obj*)new_cmdbuf_node->data;
+          if((((cmdbuf_obj->cmdbuf_busAddress-base_ddr_addr) <=exe_cmdbuf_busAddress)&&(((cmdbuf_obj->cmdbuf_busAddress-base_ddr_addr+cmdbuf_obj->cmdbuf_size) >exe_cmdbuf_busAddress)) ) &&(cmdbuf_obj->cmdbuf_run_done==0))
+            break;
+          new_cmdbuf_node = new_cmdbuf_node->next;
+        }
+      }
+      base_cmdbuf_node = new_cmdbuf_node;
+      // this cmdbuf and cmdbufs prior to itself, run_done = 1
+      while(1)
+      {
+        if(new_cmdbuf_node==NULL)
+          break;
+        cmdbuf_obj = (struct cmdbuf_obj*)new_cmdbuf_node->data;
+        if((cmdbuf_obj->cmdbuf_run_done==0))
+        {
+          cmdbuf_obj->cmdbuf_run_done=1;
+          cmdbuf_obj->executing_status = CMDBUF_EXE_STATUS_OK;
+          cmdbuf_processed_num++;
+        }
+        else
+          break;
+        new_cmdbuf_node = new_cmdbuf_node->previous;
+      }
+      new_cmdbuf_node = base_cmdbuf_node;
+      if(new_cmdbuf_node!=NULL)
+      {
+        cmdbuf_obj = (struct cmdbuf_obj*)new_cmdbuf_node->data;
+        cmdbuf_obj->executing_status = CMDBUF_EXE_STATUS_BUSERR;
+      }
+      base_cmdbuf_node=base_cmdbuf_node->next;
+      vcmd_delink_cmdbuf(dev,base_cmdbuf_node);
+      vcmd_link_cmdbuf(dev,base_cmdbuf_node);
+      if(dev->sw_cmdbuf_rdy_num !=0)
+      {
+        //restart new command
+        vcmd_start(dev,base_cmdbuf_node);
+      }
+      spin_unlock_irqrestore(dev->spinlock, flags);
+      if(cmdbuf_processed_num)
+        wake_up_interruptible_all(dev->wait_queue);
+      handled++;
+      wake_up_interruptible_all(&mc_wait_queue);
+      return IRQ_HANDLED;
+    }
+    if(vcmd_get_register_mirror_value(dev->reg_mirror,HWIF_VCMD_IRQ_TIMEOUT))
+    {
+      //time out,need to reset
+      new_cmdbuf_node = dev->list_manager.head;
+      dev->working_state = WORKING_STATE_IDLE;
+      if(dev->hw_version_id > HW_ID_1_0_C )
+      {
+        new_cmdbuf_node = global_cmdbuf_node[cmdbuf_id];
+        if(new_cmdbuf_node==NULL)
+        {
+          pr_err("hantrovcmd_isr error cmdbuf_id !!\n");
+          spin_unlock_irqrestore(dev->spinlock, flags);
+          return IRQ_HANDLED;
+        }
+      }
+      else
+      {
+        exe_cmdbuf_busAddress = VCMDGetAddrRegisterValue((const void *)dev->hwregs,dev->reg_mirror,HWIF_VCMD_EXECUTING_CMD_ADDR);
+        //find the timeout cmdbuf
+        while(1)
+        {
+          if(new_cmdbuf_node==NULL)
+          {
+            spin_unlock_irqrestore(dev->spinlock, flags);
+            return IRQ_HANDLED;
+          }
+          cmdbuf_obj = (struct cmdbuf_obj*)new_cmdbuf_node->data;
+          if((((cmdbuf_obj->cmdbuf_busAddress-base_ddr_addr) <=exe_cmdbuf_busAddress)&&(((cmdbuf_obj->cmdbuf_busAddress-base_ddr_addr+cmdbuf_obj->cmdbuf_size) >exe_cmdbuf_busAddress)) ) &&(cmdbuf_obj->cmdbuf_run_done==0))
+            break;
+          new_cmdbuf_node = new_cmdbuf_node->next;
+        }
+      }
+      base_cmdbuf_node = new_cmdbuf_node;
+      new_cmdbuf_node = new_cmdbuf_node->previous;
+      // this cmdbuf and cmdbufs prior to itself, run_done = 1
+      while(1)
+      {
+        if(new_cmdbuf_node==NULL)
+          break;
+        cmdbuf_obj = (struct cmdbuf_obj*)new_cmdbuf_node->data;
+        if((cmdbuf_obj->cmdbuf_run_done==0))
+        {
+          cmdbuf_obj->cmdbuf_run_done=1;
+          cmdbuf_obj->executing_status = CMDBUF_EXE_STATUS_OK;
+          cmdbuf_processed_num++;
+        }
+        else
+          break;
+        new_cmdbuf_node = new_cmdbuf_node->previous;
+      }
+      vcmd_delink_cmdbuf(dev,base_cmdbuf_node);
+      vcmd_link_cmdbuf(dev,base_cmdbuf_node);
+      if(dev->sw_cmdbuf_rdy_num !=0)
+      {
+        //reset
+        vcmd_reset_current_asic(dev);
+        //restart new command
+        vcmd_start(dev,base_cmdbuf_node);
+      }
+      spin_unlock_irqrestore(dev->spinlock, flags);
+      if(cmdbuf_processed_num)
+        wake_up_interruptible_all(dev->wait_queue);
+      handled++;
+      wake_up_interruptible_all(&mc_wait_queue);
+      return IRQ_HANDLED;
+    }
+    if(vcmd_get_register_mirror_value(dev->reg_mirror,HWIF_VCMD_IRQ_CMDERR))
+    {
+      //command error,don't need to reset
+      new_cmdbuf_node = dev->list_manager.head;
+      dev->working_state = WORKING_STATE_IDLE;
+      if(dev->hw_version_id > HW_ID_1_0_C )
+      {
+        new_cmdbuf_node = global_cmdbuf_node[cmdbuf_id];
+        if(new_cmdbuf_node==NULL)
+        {
+          pr_err("hantrovcmd_isr error cmdbuf_id !!\n");
+          spin_unlock_irqrestore(dev->spinlock, flags);
+          return IRQ_HANDLED;
+        }
+      }
+      else
+      {
+        exe_cmdbuf_busAddress = VCMDGetAddrRegisterValue((const void *)dev->hwregs,dev->reg_mirror,HWIF_VCMD_EXECUTING_CMD_ADDR);
+        //find the cmderror cmdbuf
+        while(1)
+        {
+          if(new_cmdbuf_node==NULL)
+          {
+            spin_unlock_irqrestore(dev->spinlock, flags);
+            return IRQ_HANDLED;
+          }
+          cmdbuf_obj = (struct cmdbuf_obj*)new_cmdbuf_node->data;
+          if((((cmdbuf_obj->cmdbuf_busAddress-base_ddr_addr) <=exe_cmdbuf_busAddress)&&(((cmdbuf_obj->cmdbuf_busAddress-base_ddr_addr+cmdbuf_obj->cmdbuf_size) >exe_cmdbuf_busAddress)) ) &&(cmdbuf_obj->cmdbuf_run_done==0))
+            break;
+          new_cmdbuf_node = new_cmdbuf_node->next;
+        }
+      }
+      base_cmdbuf_node = new_cmdbuf_node;
+      // this cmdbuf and cmdbufs prior to itself, run_done = 1
+      while(1)
+      {
+        if(new_cmdbuf_node==NULL)
+          break;
+        cmdbuf_obj = (struct cmdbuf_obj*)new_cmdbuf_node->data;
+        if((cmdbuf_obj->cmdbuf_run_done==0))
+        {
+          cmdbuf_obj->cmdbuf_run_done=1;
+          cmdbuf_obj->executing_status = CMDBUF_EXE_STATUS_OK;
+          cmdbuf_processed_num++;
+        }
+        else
+          break;
+        new_cmdbuf_node = new_cmdbuf_node->previous;
+      }
+      new_cmdbuf_node = base_cmdbuf_node;
+      if(new_cmdbuf_node!=NULL)
+      {
+        cmdbuf_obj = (struct cmdbuf_obj*)new_cmdbuf_node->data;
+        cmdbuf_obj->executing_status = CMDBUF_EXE_STATUS_CMDERR;//cmderr
+      }
+      base_cmdbuf_node=base_cmdbuf_node->next;
+      vcmd_delink_cmdbuf(dev,base_cmdbuf_node);
+      vcmd_link_cmdbuf(dev,base_cmdbuf_node);
+      if(dev->sw_cmdbuf_rdy_num !=0)
+      {
+        //restart new command
+        vcmd_start(dev,base_cmdbuf_node);
+      }
+      spin_unlock_irqrestore(dev->spinlock, flags);
+      if(cmdbuf_processed_num)
+        wake_up_interruptible_all(dev->wait_queue);
+      handled++;
+      wake_up_interruptible_all(&mc_wait_queue);
+      return IRQ_HANDLED;
+    }
+
+    if(vcmd_get_register_mirror_value(dev->reg_mirror,HWIF_VCMD_IRQ_ENDCMD))
+    {
+      //end command interrupt
+      new_cmdbuf_node = dev->list_manager.head;
+      dev->working_state = WORKING_STATE_IDLE;
+      if(dev->hw_version_id > HW_ID_1_0_C )
+      {
+        new_cmdbuf_node = global_cmdbuf_node[cmdbuf_id];
+        if(new_cmdbuf_node==NULL)
+        {
+          pr_err("hantrovcmd_isr error cmdbuf_id !!\n");
+          spin_unlock_irqrestore(dev->spinlock, flags);
+          return IRQ_HANDLED;
+        }
+      }
+      else
+      {
+        //find the end cmdbuf
+        while(1)
+        {
+          if(new_cmdbuf_node==NULL)
+          {
+            spin_unlock_irqrestore(dev->spinlock, flags);
+            return IRQ_HANDLED;
+          }
+          cmdbuf_obj = (struct cmdbuf_obj*)new_cmdbuf_node->data;
+          if((cmdbuf_obj->has_end_cmdbuf == 1)&&(cmdbuf_obj->cmdbuf_run_done==0))
+            break;
+          new_cmdbuf_node = new_cmdbuf_node->next;
+        }
+      }
+      base_cmdbuf_node = new_cmdbuf_node;
+      // this cmdbuf and cmdbufs prior to itself, run_done = 1
+      while(1)
+      {
+        if(new_cmdbuf_node==NULL)
+          break;
+        cmdbuf_obj = (struct cmdbuf_obj*)new_cmdbuf_node->data;
+        if((cmdbuf_obj->cmdbuf_run_done==0))
+        {
+          cmdbuf_obj->cmdbuf_run_done=1;
+          cmdbuf_obj->executing_status = CMDBUF_EXE_STATUS_OK;
+          cmdbuf_processed_num++;
+        }
+        else
+          break;
+        new_cmdbuf_node = new_cmdbuf_node->previous;
+      }
+      base_cmdbuf_node=base_cmdbuf_node->next;
+      vcmd_delink_cmdbuf(dev,base_cmdbuf_node);
+      vcmd_link_cmdbuf(dev,base_cmdbuf_node);
+      if(dev->sw_cmdbuf_rdy_num !=0)
+      {
+        //restart new command
+        vcmd_start(dev,base_cmdbuf_node);
+      }
+      spin_unlock_irqrestore(dev->spinlock, flags);
+      if(cmdbuf_processed_num)
+        wake_up_interruptible_all(dev->wait_queue);
+      handled++;
+      wake_up_interruptible_all(&mc_wait_queue);
+      return IRQ_HANDLED;
+    }
+    if(dev->hw_version_id <= HW_ID_1_0_C )
+      cmdbuf_id = vcmd_get_register_mirror_value(dev->reg_mirror,HWIF_VCMD_IRQ_INTCMD);
+    if(cmdbuf_id)
+    {
+      if(dev->hw_version_id <= HW_ID_1_0_C )
+      {
+        if(cmdbuf_id>=TOTAL_DISCRETE_CMDBUF_NUM)
+        {
+          pr_err("hantrovcmd_isr error cmdbuf_id greater than the ceiling !!\n");
+          spin_unlock_irqrestore(dev->spinlock, flags);
+          return IRQ_HANDLED;
+        }
+      }
+      new_cmdbuf_node = global_cmdbuf_node[cmdbuf_id];
+      if(new_cmdbuf_node==NULL)
+      {
+        pr_err("hantrovcmd_isr error cmdbuf_id !!\n");
+        spin_unlock_irqrestore(dev->spinlock, flags);
+        return IRQ_HANDLED;
+      }
+      // interrupt cmdbuf and cmdbufs prior to itself, run_done = 1
+      while(1)
+      {
+        if(new_cmdbuf_node==NULL)
+          break;
+        cmdbuf_obj = (struct cmdbuf_obj*)new_cmdbuf_node->data;
+        if((cmdbuf_obj->cmdbuf_run_done==0))
+        {
+          cmdbuf_obj->cmdbuf_run_done=1;
+          cmdbuf_obj->executing_status = CMDBUF_EXE_STATUS_OK;
+          cmdbuf_processed_num++;
+        }
+        else
+          break;
+        new_cmdbuf_node = new_cmdbuf_node->previous;
+      }
+      handled++;
+    }
+
+    spin_unlock_irqrestore(dev->spinlock, flags);
+    if(cmdbuf_processed_num)
+      wake_up_interruptible_all(dev->wait_queue);
+    if(!handled)
+    {
+        PDEBUG("IRQ received, but not hantro's!\n");
+    }
+    wake_up_interruptible_all(&mc_wait_queue);
+    return IRQ_HANDLED;
+}
+
+void vcmd_reset_asic(struct hantrovcmd_dev * dev)
+{
+    int i,n;
+    u32 result;
+    for (n=0;n<total_vcmd_core_num;n++)
+    {
+      if(dev[n].hwregs!=NULL)
+      {
+        //disable interrupt at first
+        vcmd_write_reg((const void *)dev[n].hwregs,VCMD_REGISTER_INT_CTL_OFFSET,0x0000);
+        //reset all
+        vcmd_write_reg((const void *)dev[n].hwregs,VCMD_REGISTER_CONTROL_OFFSET,0x0002);
+        //read status register
+        result =vcmd_read_reg((const void *)dev[n].hwregs,VCMD_REGISTER_INT_STATUS_OFFSET);
+        //clean status register
+        vcmd_write_reg((const void *)dev[n].hwregs,VCMD_REGISTER_INT_STATUS_OFFSET,result);
+        for(i = VCMD_REGISTER_CONTROL_OFFSET; i < dev[n].vcmd_core_cfg.vcmd_iosize; i += 4)
+        {
+          //set all register 0
+          vcmd_write_reg((const void *)dev[n].hwregs,i,0x0000);
+        }
+        //enable all interrupt
+        vcmd_write_reg((const void *)dev[n].hwregs,VCMD_REGISTER_INT_CTL_OFFSET,0xffffffff);
+      }
+    }
+}
+
+static void vcmd_reset_current_asic(struct hantrovcmd_dev * dev)
+{
+  u32 result;
+
+  if(dev->hwregs!=NULL)
+  {
+    //disable interrupt at first
+    vcmd_write_reg((const void *)dev->hwregs,VCMD_REGISTER_INT_CTL_OFFSET,0x0000);
+    //reset all
+    vcmd_write_reg((const void *)dev->hwregs,VCMD_REGISTER_CONTROL_OFFSET,0x0002);
+    //read status register
+    result =vcmd_read_reg((const void *)dev->hwregs,VCMD_REGISTER_INT_STATUS_OFFSET);
+    //clean status register
+    vcmd_write_reg((const void *)dev->hwregs,VCMD_REGISTER_INT_STATUS_OFFSET,result);
+  }
+
+}
+
+static void printk_vcmd_register_debug(const void *hwregs, char * info) {
+#ifdef HANTRO_VCMD_DRIVER_DEBUG
+  u32 i, fordebug;
+  for(i = 0; i < ASIC_VCMD_SWREG_AMOUNT; i++) {
+      fordebug = vcmd_read_reg ((const void *)hwregs, i*4);
+      pr_info("%s vcmd register %d:0x%x\n",info,i,fordebug);
+  }
+#endif
+}
+
+void hantrovcmd_reset(void)
+{
+  if (hantrovcmd_data) {
+    int i;
+    for(i=0;i<total_vcmd_core_num;i++) {
+      hantrovcmd_data[i].working_state = WORKING_STATE_IDLE;
+      hantrovcmd_data[i].sw_cmdbuf_rdy_num = 0;
+    }
+    vcmd_reset_asic(hantrovcmd_data);
+  }
+}

+ 63 - 0
linux/subsys_driver/hantroaxife.h

@@ -0,0 +1,63 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2021 VERISILICON
+*
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2021 VERISILICON
+*
+*    This program is free software; you can redistribute it and/or
+*    modify it under the terms of the GNU General Public License
+*    as published by the Free Software Foundation; either version 2
+*    of the License, or (at your option) any later version.
+*
+*    This program is distributed in the hope that it will be useful,
+*    but WITHOUT ANY WARRANTY; without even the implied warranty of
+*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*    GNU General Public License for more details.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+#ifndef __HANTRO_AXIFE_H__
+#define __HANTRO_AXIFE_H__
+
+#include <linux/ioctl.h>
+#include <linux/types.h>
+
+void AXIFEEnable (volatile unsigned char *hwregs);
+
+#endif

+ 199 - 0
linux/subsys_driver/hantrodec.h

@@ -0,0 +1,199 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2021 VERISILICON
+*
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2021 VERISILICON
+*
+*    This program is free software; you can redistribute it and/or
+*    modify it under the terms of the GNU General Public License
+*    as published by the Free Software Foundation; either version 2
+*    of the License, or (at your option) any later version.
+*
+*    This program is distributed in the hope that it will be useful,
+*    but WITHOUT ANY WARRANTY; without even the implied warranty of
+*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*    GNU General Public License for more details.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+#ifndef _HANTRODEC_H_
+#define _HANTRODEC_H_
+#ifdef __FREERTOS__
+#include "basetype.h"
+#include "dev_common_freertos.h"
+#elif defined(__linux__)
+#include <linux/ioctl.h>
+#include <linux/types.h>
+#include "hantrommu.h"
+#else //For other os
+//TODO...
+#endif
+#include "hantrovcmd.h"
+
+enum CoreType {
+  /* Decoder */
+  HW_VC8000D = 0,
+  HW_VC8000DJ,
+  HW_BIGOCEAN,
+  HW_VCMD,
+  HW_MMU,  //if set HW_MMU_WR, then HW_MMU means HW_MMU_RD
+  HW_MMU_WR,
+  HW_DEC400,
+  HW_L2CACHE,
+  HW_SHAPER,
+  /* Encoder*/
+  /* Auxiliary IPs */
+  HW_NOC,
+  HW_AXIFE,
+  HW_APBFILTER,
+  HW_CORE_MAX     /* max number of cores supported */
+};
+
+struct core_desc {
+  __u32 id; /* id of the subsystem */
+  __u32 type; /* type of core to be written */
+  __u32 *regs; /* pointer to user registers */
+  __u32 size; /* size of register space */
+  __u32 reg_id; /* id of reigster to be read/written */
+};
+
+struct regsize_desc {
+  __u32 slice; /* id of the slice */
+  __u32 id; /* id of the subsystem */
+  __u32 type; /* type of core to be written */
+  __u32 size; /* iosize of the core */
+};
+
+struct core_param {
+  __u32 slice; /* id of the slice */
+  __u32 id; /* id of the subsystem */
+  __u32 type; /* type of core to be written */
+  __u32 size; /* iosize of the core */
+  __u32 asic_id; /* asic id of the core */
+};
+
+
+struct subsys_desc {
+  __u32 subsys_num;   /* total subsystems count */
+  __u32 subsys_vcmd_num;  /* subsystems with vcmd */
+};
+
+struct axife_cfg {
+  __u8 axi_rd_chn_num;
+  __u8 axi_wr_chn_num;
+  __u8 axi_rd_burst_length;
+  __u8 axi_wr_burst_length;
+  __u8 fe_mode;
+  __u32 id;
+};
+
+struct apbfilter_cfg {
+  __u32 nbr_mask_regs;
+  __u32 mask_reg_offset;
+  __u32 page_sel_addr;
+  __u8  num_mode;
+  __u8  mask_bits_per_reg;
+  __u32 id; /* id of the subsystem */
+  __u32 type; /* type of core to be written */
+  __u32 has_apbfilter;
+};
+/* Use 'k' as magic number */
+#define HANTRODEC_IOC_MAGIC  'k'
+
+/*
+ * S means "Set" through a ptr,
+ * T means "Tell" directly with the argument value
+ * G means "Get": reply by setting through a pointer
+ * Q means "Query": response is on the return value
+ * X means "eXchange": G and S atomically
+ * H means "sHift": T and Q atomically
+ */
+
+#define HANTRODEC_PP_INSTANCE       _IO(HANTRODEC_IOC_MAGIC, 1)
+#define HANTRODEC_HW_PERFORMANCE    _IO(HANTRODEC_IOC_MAGIC, 2)
+#define HANTRODEC_IOCGHWOFFSET      _IOR(HANTRODEC_IOC_MAGIC,  3, unsigned long *)
+#define HANTRODEC_IOCGHWIOSIZE      _IOR(HANTRODEC_IOC_MAGIC,  4, struct regsize_desc *)
+
+#define HANTRODEC_IOC_CLI           _IO(HANTRODEC_IOC_MAGIC,  5)
+#define HANTRODEC_IOC_STI           _IO(HANTRODEC_IOC_MAGIC,  6)
+#define HANTRODEC_IOC_MC_OFFSETS    _IOR(HANTRODEC_IOC_MAGIC, 7, unsigned long *)
+#define HANTRODEC_IOC_MC_CORES      _IOR(HANTRODEC_IOC_MAGIC, 8, unsigned int *)
+
+
+#define HANTRODEC_IOCS_DEC_PUSH_REG  _IOW(HANTRODEC_IOC_MAGIC, 9, struct core_desc *)
+#define HANTRODEC_IOCS_PP_PUSH_REG   _IOW(HANTRODEC_IOC_MAGIC, 10, struct core_desc *)
+
+#define HANTRODEC_IOCH_DEC_RESERVE   _IO(HANTRODEC_IOC_MAGIC, 11)
+#define HANTRODEC_IOCT_DEC_RELEASE   _IO(HANTRODEC_IOC_MAGIC, 12)
+#define HANTRODEC_IOCQ_PP_RESERVE    _IO(HANTRODEC_IOC_MAGIC, 13)
+#define HANTRODEC_IOCT_PP_RELEASE    _IO(HANTRODEC_IOC_MAGIC, 14)
+
+#define HANTRODEC_IOCX_DEC_WAIT      _IOWR(HANTRODEC_IOC_MAGIC, 15, struct core_desc *)
+#define HANTRODEC_IOCX_PP_WAIT       _IOWR(HANTRODEC_IOC_MAGIC, 16, struct core_desc *)
+
+#define HANTRODEC_IOCS_DEC_PULL_REG  _IOWR(HANTRODEC_IOC_MAGIC, 17, struct core_desc *)
+#define HANTRODEC_IOCS_PP_PULL_REG   _IOWR(HANTRODEC_IOC_MAGIC, 18, struct core_desc *)
+
+#define HANTRODEC_IOCG_CORE_WAIT     _IOR(HANTRODEC_IOC_MAGIC, 19, int *)
+
+#define HANTRODEC_IOX_ASIC_ID        _IOWR(HANTRODEC_IOC_MAGIC, 20, struct core_param *)
+
+#define HANTRODEC_IOCG_CORE_ID       _IOR(HANTRODEC_IOC_MAGIC, 21, unsigned long)
+
+#define HANTRODEC_IOCS_DEC_WRITE_REG  _IOW(HANTRODEC_IOC_MAGIC, 22, struct core_desc *)
+
+#define HANTRODEC_IOCS_DEC_READ_REG   _IOWR(HANTRODEC_IOC_MAGIC, 23, struct core_desc *)
+
+#define HANTRODEC_IOX_ASIC_BUILD_ID   _IOWR(HANTRODEC_IOC_MAGIC, 24, __u32 *)
+
+#define HANTRODEC_IOX_SUBSYS _IOWR(HANTRODEC_IOC_MAGIC, 25, struct subsys_desc *)
+
+#define HANTRODEC_IOCX_POLL _IO(HANTRODEC_IOC_MAGIC, 26)
+
+#define HANTRODEC_DEBUG_STATUS       _IO(HANTRODEC_IOC_MAGIC, 29)
+
+#define HANTRODEC_IOCS_DEC_WRITE_APBFILTER_REG  _IOW(HANTRODEC_IOC_MAGIC, 30, struct core_desc *)
+
+#define HANTRODEC_IOC_APBFILTER_CONFIG     _IOR(HANTRODEC_IOC_MAGIC,  31, struct apbfilter_cfg *)
+
+#define HANTRODEC_IOC_AXIFE_CONFIG   _IOR(HANTRODEC_IOC_MAGIC,  32, struct axife_cfg *)
+
+#define HANTRODEC_IOC_MAXNR 32
+
+#endif /* !_HANTRODEC_H_ */

+ 109 - 0
linux/subsys_driver/hantrommu.h

@@ -0,0 +1,109 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2021 VERISILICON
+*
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2021 VERISILICON
+*
+*    This program is free software; you can redistribute it and/or
+*    modify it under the terms of the GNU General Public License
+*    as published by the Free Software Foundation; either version 2
+*    of the License, or (at your option) any later version.
+*
+*    This program is distributed in the hope that it will be useful,
+*    but WITHOUT ANY WARRANTY; without even the implied warranty of
+*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*    GNU General Public License for more details.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+#ifndef _HANTROMMU_H_
+#define _HANTROMMU_H_
+#ifdef __FREERTOS__
+#include "basetype.h"
+#include "dev_common_freertos.h"
+#elif defined(__linux__)
+#include <linux/fs.h>
+#endif
+
+#define REGION_IN_START          0x0
+#define REGION_IN_END            0x0
+#define REGION_OUT_START         0x0
+#define REGION_OUT_END           0x0
+#define REGION_PRIVATE_START     0x0
+#define REGION_PRIVATE_END       0x0
+
+#define REGION_IN_MMU_START      0x1000
+#define REGION_IN_MMU_END        0x1000
+#define REGION_OUT_MMU_START     0x1000
+#define REGION_OUT_MMU_END       0x1000
+#define REGION_PRIVATE_MMU_START 0x1000
+#define REGION_PRIVATE_MMU_END   0x1000
+
+enum MMUStatus {
+  MMU_STATUS_OK                          =    0,
+
+  MMU_STATUS_FALSE                       =   -1,
+  MMU_STATUS_INVALID_ARGUMENT            =   -2,
+  MMU_STATUS_INVALID_OBJECT              =   -3,
+  MMU_STATUS_OUT_OF_MEMORY               =   -4,
+  MMU_STATUS_NOT_FOUND                   =   -19,
+};
+
+struct addr_desc {
+  void                       *virtual_address;  /* buffer virtual address */
+  unsigned int               bus_address;  /* buffer physical address */
+  unsigned int               size;  /* physical size */
+};
+
+struct kernel_addr_desc {
+  unsigned long long         bus_address;  /* buffer virtual address */
+  unsigned long long         mmu_bus_address;  /* buffer physical address in MMU*/
+  unsigned int               size;  /* physical size */
+};
+
+
+#define HANTRO_IOC_MMU  'm'
+
+#define HANTRO_IOCS_MMU_MEM_MAP    _IOWR(HANTRO_IOC_MMU, 1, struct addr_desc *)
+#define HANTRO_IOCS_MMU_MEM_UNMAP  _IOWR(HANTRO_IOC_MMU, 2, struct addr_desc *)
+#define HANTRO_IOCS_MMU_FLUSH      _IOWR(HANTRO_IOC_MMU, 3, unsigned int *)
+#define HANTRO_IOC_MMU_MAXNR 3
+
+#endif
+

+ 192 - 0
linux/subsys_driver/hantrovcmd.h

@@ -0,0 +1,192 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2021 VERISILICON
+*
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2021 VERISILICON
+*
+*    This program is free software; you can redistribute it and/or
+*    modify it under the terms of the GNU General Public License
+*    as published by the Free Software Foundation; either version 2
+*    of the License, or (at your option) any later version.
+*
+*    This program is distributed in the hope that it will be useful,
+*    but WITHOUT ANY WARRANTY; without even the implied warranty of
+*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*    GNU General Public License for more details.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+#ifndef _VC8000_VCMD_DRIVER_H_
+#define _VC8000_VCMD_DRIVER_H_
+#ifdef __FREERTOS__
+#include "basetype.h"
+#include "dev_common_freertos.h"
+#elif defined(__linux__)
+#include <linux/ioctl.h>    /* needed for the _IOW etc stuff used later */
+#endif
+
+#ifdef __FREERTOS__
+//addr_t has been defined in basetype.h //Now the FreeRTOS mem need to support 64bit env
+#elif defined(__linux__)
+#undef  addr_t
+#define addr_t ADDR_T_VCMD
+typedef size_t addr_t;
+#endif
+
+/* Use 'v' as magic number for vcmd */
+#define HANTRO_VCMD_IOC_MAGIC  'v'
+/*
+ * S means "Set" through a ptr,
+ * T means "Tell" directly with the argument value
+ * G means "Get": reply by setting through a pointer
+ * Q means "Query": response is on the return value
+ * X means "eXchange": G and S atomically
+ * H means "sHift": T and Q atomically
+ */
+
+#define HANTRO_VCMD_IOCH_GET_CMDBUF_PARAMETER           _IOWR(HANTRO_VCMD_IOC_MAGIC, 20,struct cmdbuf_mem_parameter *)
+#define HANTRO_VCMD_IOCH_GET_CMDBUF_POOL_SIZE           _IOWR(HANTRO_VCMD_IOC_MAGIC, 21,unsigned long)
+#define HANTRO_VCMD_IOCH_SET_CMDBUF_POOL_BASE           _IOWR(HANTRO_VCMD_IOC_MAGIC, 22,unsigned long)
+
+#define HANTRO_VCMD_IOCH_GET_VCMD_PARAMETER             _IOWR(HANTRO_VCMD_IOC_MAGIC, 24, struct config_parameter *)
+
+#define HANTRO_VCMD_IOCH_RESERVE_CMDBUF                 _IOWR(HANTRO_VCMD_IOC_MAGIC, 25,struct exchange_parameter *)
+#define HANTRO_VCMD_IOCH_LINK_RUN_CMDBUF                _IOR(HANTRO_VCMD_IOC_MAGIC, 26,u16 *)
+#define HANTRO_VCMD_IOCH_WAIT_CMDBUF                    _IOR(HANTRO_VCMD_IOC_MAGIC, 27,u16 *)
+#define HANTRO_VCMD_IOCH_RELEASE_CMDBUF                 _IOR(HANTRO_VCMD_IOC_MAGIC, 28,u16 *)
+
+#define HANTRO_VCMD_IOCH_POLLING_CMDBUF                 _IOR(HANTRO_VCMD_IOC_MAGIC, 40,u16 *)
+
+#define HANTRO_VCMD_IOC_MAXNR 50
+
+/*priority support*/
+
+#define MAX_CMDBUF_PRIORITY_TYPE            2       //0:normal priority,1:high priority
+
+#define CMDBUF_PRIORITY_NORMAL            0
+#define CMDBUF_PRIORITY_HIGH              1
+
+#if 0
+#define OPCODE_WREG               (0x01<<27)
+#define OPCODE_END                (0x02<<27)
+#define OPCODE_NOP                (0x03<<27)
+#define OPCODE_RREG               (0x16<<27)
+#define OPCODE_INT                (0x18<<27)
+#define OPCODE_JMP                (0x19<<27)
+#define OPCODE_STALL              (0x09<<27)
+#define OPCODE_CLRINT             (0x1a<<27)
+#define OPCODE_JMP_RDY0           (0x19<<27)
+#define OPCODE_JMP_RDY1           ((0x19<<27)|(1<<26))
+#define JMP_IE_1                  (1<<25)
+#define JMP_RDY_1                 (1<<26)
+
+#define CLRINT_OPTYPE_READ_WRITE_1_CLEAR         0
+#define CLRINT_OPTYPE_READ_WRITE_0_CLEAR         1
+#define CLRINT_OPTYPE_READ_CLEAR                 2
+
+#define VC8000E_FRAME_RDY_INT_MASK                        0x0001
+#define VC8000E_CUTREE_RDY_INT_MASK                       0x0002
+#define VC8000E_DEC400_INT_MASK                           0x0004
+#define VC8000E_L2CACHE_INT_MASK                          0x0008
+#define VC8000E_MMU_INT_MASK                              0x0010
+
+#define VC8000D_FRAME_RDY_INT_MASK                        0x0100
+#define VC8000D_DEC400_INT_MASK                           0x0400
+#define VC8000D_L2CACHE_INT_MASK                          0x0800
+#define VC8000D_MMU_INT_MASK                              0x1000
+#endif
+
+#define HW_ID_1_0_C                0x43421001
+#define HW_ID_1_1_2                0x43421102
+
+#define ANY_CMDBUF_ID 0xFFFF
+
+/*module_type support*/
+
+enum vcmd_module_type{
+  VCMD_TYPE_ENCODER = 0,
+  VCMD_TYPE_CUTREE,
+  VCMD_TYPE_DECODER,
+  VCMD_TYPE_JPEG_ENCODER,
+  VCMD_TYPE_JPEG_DECODER,
+  MAX_VCMD_TYPE
+};
+
+struct cmdbuf_mem_parameter
+{
+  u32 *virt_cmdbuf_addr;
+  addr_t phy_cmdbuf_addr;             //cmdbuf pool base physical address
+  u32 mmu_phy_cmdbuf_addr;             //cmdbuf pool base mmu mapping address
+  u32 cmdbuf_total_size;              //cmdbuf pool total size in bytes.
+  u16 cmdbuf_unit_size;               //one cmdbuf size in bytes. all cmdbuf have same size.
+  u32 *virt_status_cmdbuf_addr;
+  addr_t phy_status_cmdbuf_addr;      //status cmdbuf pool base physical address
+  u32 mmu_phy_status_cmdbuf_addr;      //status cmdbuf pool base mmu mapping address
+  u32 status_cmdbuf_total_size;       //status cmdbuf pool total size in bytes.
+  u16 status_cmdbuf_unit_size;        //one status cmdbuf size in bytes. all status cmdbuf have same size.
+  addr_t base_ddr_addr;               //for pcie interface, hw can only access phy_cmdbuf_addr-pcie_base_ddr_addr.
+                                      //for other interface, this value should be 0?
+};
+
+struct config_parameter
+{
+  u16 module_type;                    //input vc8000e=0,cutree=1,vc8000d=2,jpege=3, jpegd=4
+  u16 vcmd_core_num;                  //output, how many vcmd cores are there with corresponding module_type.
+  u16 submodule_main_addr;            //output,if submodule addr == 0xffff, this submodule does not exist.
+  u16 submodule_dec400_addr;          //output ,if submodule addr == 0xffff, this submodule does not exist.
+  u16 submodule_L2Cache_addr;         //output,if submodule addr == 0xffff, this submodule does not exist.
+  u16 submodule_MMU_addr;             //output,if submodule addr == 0xffff, this submodule does not exist.
+  u16 submodule_MMUWrite_addr;        //output,if submodule addr == 0xffff, this submodule does not exist.
+  u16 submodule_axife_addr;           //output,if submodule addr == 0xffff, this submodule does not exist.
+  u16 config_status_cmdbuf_id;        // output , this status comdbuf save the all register values read in driver init.//used for analyse configuration in cwl.
+  u32 vcmd_hw_version_id;
+};
+
+/*need to consider how many memory should be allocated for status.*/
+struct exchange_parameter
+{
+  u32 executing_time;                 //input ;executing_time=encoded_image_size*(rdoLevel+1)*(rdoq+1);
+  u16 module_type;                    //input input vc8000e=0,IM=1,vc8000d=2, jpege=3, jpegd=4
+  u16 cmdbuf_size;                    //input, reserve is not used; link and run is input.
+  u16 priority;                       //input,normal=0, high/live=1
+  u16 cmdbuf_id;                      //output, it is unique in driver.
+  u16 core_id;                        //just used for polling.
+};
+
+#endif /* !_VC8000_VCMD_DRIVER_H_ */

+ 1286 - 0
linux/subsys_driver/kernel_allocator.c

@@ -0,0 +1,1286 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2021 Vivante Corporation
+*
+*    Permission is hereby granted, free of charge, to any person obtaining a
+*    copy of this software and associated documentation files (the "Software"),
+*    to deal in the Software without restriction, including without limitation
+*    the rights to use, copy, modify, merge, publish, distribute, sublicense,
+*    and/or sell copies of the Software, and to permit persons to whom the
+*    Software is furnished to do so, subject to the following conditions:
+*
+*    The above copyright notice and this permission notice 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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2021 Vivante Corporation
+*
+*    This program is free software; you can redistribute it and/or
+*    modify it under the terms of the GNU General Public License
+*    as published by the Free Software Foundation; either version 2
+*    of the License, or (at your option) any later version.
+*
+*    This program is distributed in the hope that it will be useful,
+*    but WITHOUT ANY WARRANTY; without even the implied warranty of
+*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*    GNU General Public License for more details.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#include <linux/pagemap.h>
+#include <linux/seq_file.h>
+#include <linux/mman.h>
+#include <linux/errno.h>
+#include <asm/atomic.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/dma-buf.h>
+#include <linux/mm_types.h>
+#include <linux/version.h>
+#include "kernel_allocator.h"
+
+
+#define DISCRETE_PAGES 0
+//#define ALLOCATOR_DEBUG
+
+#define IS_ERROR(status)         (status > 0)
+
+/*******************************************************************************
+**
+**  ONERROR
+**
+**      Jump to the error handler in case there is an error.
+**
+**  ASSUMPTIONS:
+**
+**      'status' variable of int type must be defined.
+**
+**  ARGUMENTS:
+**
+**      func    Function to evaluate.
+*/
+#define _ONERROR(prefix, func) \
+    do \
+    { \
+        status = func; \
+        if (IS_ERROR(status)) \
+        { \
+            goto OnError; \
+        } \
+    } \
+    while (false)
+
+#define ONERROR(func)           _ONERROR(, func)
+
+/*******************************************************************************
+**
+**  ERR_BREAK
+**
+**      Executes a break statement on error.
+**
+**  ASSUMPTIONS:
+**
+**      'status' variable of int type must be defined.
+**
+**  ARGUMENTS:
+**
+**      func    Function to evaluate.
+*/
+#define _ERR_BREAK(prefix, func){ \
+    status = func; \
+    if (IS_ERROR(status)) \
+    { \
+        break; \
+    } \
+    do { } while (false); \
+    }
+
+#define ERR_BREAK(func)         _ERR_BREAK(, func)
+
+/*******************************************************************************
+**
+**  VERIFY_ARGUMENT
+**
+**      Assert if an argument does not apply to the specified expression.  If
+**      the argument evaluates to false, EINVAL will be
+**      returned from the current function.  In retail mode this macro does
+**      nothing.
+**
+**  ARGUMENTS:
+**
+**      arg     Argument to evaluate.
+*/
+#define _VERIFY_ARGUMENT(prefix, arg) \
+    do \
+    { \
+        if (!(arg)) \
+        { \
+            return EINVAL; \
+        } \
+    } \
+    while (false)
+#define VERIFY_ARGUMENT(arg)    _VERIFY_ARGUMENT(, arg)
+
+
+#define VM_FLAGS (VM_IO | VM_DONTCOPY | VM_DONTEXPAND | VM_DONTDUMP)
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,8,0)
+#define current_mm_mmap_sem current->mm->mmap_lock
+#else
+#define current_mm_mmap_sem current->mm->mmap_sem
+#endif
+
+#define GetPageCount(size, offset)     ((((size) + ((offset) & ~PAGE_MASK)) + PAGE_SIZE - 1) >> PAGE_SHIFT)
+
+#ifndef ALLOCATOR_DEBUG
+#define DEBUG_PRINT(...) \
+  do {                     \
+  } while (0)
+#else
+#undef DEBUG_PRINT
+#define DEBUG_PRINT(...) printk(__VA_ARGS__)
+#endif
+
+
+struct mem_block
+{
+    int contiguous;
+    size_t size;
+    size_t numPages;
+    struct dma_buf *dmabuf;
+    struct dma_buf_attachment * attachment;
+    struct sg_table           * sgt;
+    unsigned long             * pagearray;
+    struct vm_area_struct     * vma;
+
+    union
+    {
+        /* Pointer to a array of pages. */
+        struct
+        {
+            struct page *contiguousPages;
+            dma_addr_t dma_addr;
+            int exact;
+        };
+
+        struct
+        {
+            /* Pointer to a array of pointers to page. */
+            struct page **nonContiguousPages;
+
+            struct page **Pages1M;
+            int numPages1M;
+            int *isExact;
+        };
+    };
+};
+
+struct mem_node
+{
+    struct mem_block memBlk;
+    unsigned long busAddr;
+    int isImported;
+    struct list_head link;
+};
+
+struct file_node
+{
+    struct list_head memList;
+    struct file *filp;
+    struct list_head link;
+};
+
+static struct list_head fileList;
+
+static struct device *gdev = NULL;
+
+static DEFINE_SPINLOCK(mem_lock);
+
+static struct file_node * find_and_delete_file_node(struct file *filp)
+{
+    struct file_node *node;
+    struct file_node *temp;
+
+    spin_lock(&mem_lock);
+    list_for_each_entry_safe(node, temp, &fileList, link)
+    {
+        if (node->filp == filp)
+        {
+            list_del(&node->link);
+            spin_unlock(&mem_lock);
+            return node;
+        }
+    }
+    spin_unlock(&mem_lock);
+
+    return NULL;
+}
+
+static struct file_node * get_file_node(struct file *filp)
+{
+    struct file_node *node;
+
+    spin_lock(&mem_lock);
+    list_for_each_entry(node, &fileList, link)
+    {
+        if (node->filp == filp)
+        {
+            spin_unlock(&mem_lock);
+            return node;
+        }
+    }
+    spin_unlock(&mem_lock);
+
+    return NULL;
+}
+
+static struct mem_node * get_mem_node(struct file *filp, unsigned long bus_address, int imported)
+{
+    struct file_node *fnode;
+    struct mem_node *node;
+
+    fnode = get_file_node(filp);
+    if (NULL == fnode)
+    {
+        return NULL;
+    }
+
+    spin_lock(&mem_lock);
+    list_for_each_entry(node, &fnode->memList, link)
+    {
+        if (node->busAddr == bus_address && node->isImported == imported)
+        {
+            spin_unlock(&mem_lock);
+            return node;
+        }
+    }
+    spin_unlock(&mem_lock);
+
+    return NULL;
+}
+
+static int
+AllocateMemory(
+    IN size_t Bytes,
+    OUT void * * Memory
+    )
+{
+    void * memory = NULL;
+    int status = 0;
+
+    /* Verify the arguments. */
+    VERIFY_ARGUMENT(Bytes > 0);
+    VERIFY_ARGUMENT(Memory != NULL);
+
+    if (Bytes > PAGE_SIZE)
+    {
+        memory = (void *) vmalloc(Bytes);
+    }
+    else
+    {
+        memory = (void *) kmalloc(Bytes, GFP_KERNEL | __GFP_NOWARN);
+    }
+
+    if (memory == NULL)
+    {
+        /* Out of memory. */
+        ONERROR(ENOMEM);
+    }
+
+    /* Return pointer to the memory allocation. */
+    *Memory = memory;
+
+OnError:
+    /* Return the status. */
+    return status;
+}
+
+int
+static FreeMemory(
+    IN void * Memory
+    )
+{
+    /* Verify the arguments. */
+    VERIFY_ARGUMENT(Memory != NULL);
+
+    /* Free the memory from the OS pool. */
+    if (is_vmalloc_addr(Memory))
+    {
+        vfree(Memory);
+    }
+    else
+    {
+        kfree(Memory);
+    }
+
+    /* Success. */
+    return 0;
+}
+
+
+static int
+GetSGT(
+    IN struct mem_block *MemBlk,
+    IN size_t Offset,
+    IN size_t Bytes,
+    OUT void * *SGT
+    )
+{
+    struct page ** pages = NULL;
+    struct page ** tmpPages = NULL;
+    struct sg_table *sgt = NULL;
+    struct mem_block *memBlk = MemBlk;
+
+    int status = 0;
+    size_t offset = Offset & ~PAGE_MASK; /* Offset to the first page */
+    size_t skipPages = Offset >> PAGE_SHIFT;     /* skipped pages */
+    size_t numPages = (PAGE_ALIGN(Offset + Bytes) >> PAGE_SHIFT) - skipPages;
+    size_t i;
+
+    if (memBlk->contiguous)
+    {
+        ONERROR(AllocateMemory(sizeof(struct page*) * numPages, (void * *)&tmpPages));
+        pages = tmpPages;
+
+        for (i = 0; i < numPages; ++i)
+        {
+            pages[i] = nth_page(memBlk->contiguousPages, i + skipPages);
+        }
+    }
+    else
+    {
+        pages = &memBlk->nonContiguousPages[skipPages];
+    }
+
+    ONERROR(AllocateMemory(sizeof(struct sg_table) * numPages, (void * *)&sgt));
+
+    if (sg_alloc_table_from_pages(sgt, pages, numPages, offset, Bytes, GFP_KERNEL) < 0)
+    {
+        ONERROR(EPERM);
+    }
+
+    *SGT = (void *)sgt;
+
+OnError:
+    if (tmpPages)
+    {
+        FreeMemory(tmpPages);
+    }
+
+    if (IS_ERROR(status) && sgt)
+    {
+        FreeMemory(sgt);
+    }
+
+    return status;
+}
+
+static int
+Mmap(
+    IN struct mem_block *MemBlk,
+    IN size_t skipPages,
+    IN size_t numPages,
+    IN struct vm_area_struct *vma
+    )
+{
+    struct mem_block *memBlk = MemBlk;
+    int status = 0;
+
+    vma->vm_flags |= VM_FLAGS;
+
+    /* Make this mapping non-cached. */
+    vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+
+    /* Now map all the vmalloc pages to this user address. */
+    if (memBlk->contiguous)
+    {
+        /* map kernel memory to user space.. */
+        if (remap_pfn_range(vma,
+                            vma->vm_start,
+                            page_to_pfn(memBlk->contiguousPages) + skipPages,
+                            numPages << PAGE_SHIFT,
+                            vma->vm_page_prot) < 0)
+        {
+            ONERROR(ENOMEM);
+        }
+    }
+    else
+    {
+        size_t i;
+        unsigned long start = vma->vm_start;
+
+        for (i = 0; i < numPages; ++i)
+        {
+            unsigned long pfn = page_to_pfn(memBlk->nonContiguousPages[i + skipPages]);
+
+            if (remap_pfn_range(vma,
+                                start,
+                                pfn,
+                                PAGE_SIZE,
+                                vma->vm_page_prot) < 0)
+            {
+                ONERROR(ENOMEM);
+            }
+
+            start += PAGE_SIZE;
+        }
+    }
+
+OnError:
+    return status;
+}
+
+static int
+Attach(
+    INOUT struct mem_block *MemBlk
+    )
+{
+    int status;
+    struct mem_block *memBlk = MemBlk;
+
+    struct dma_buf *dmabuf = memBlk->dmabuf;
+    struct sg_table *sgt = NULL;
+    struct dma_buf_attachment *attachment = NULL;
+    int npages = 0;
+    unsigned long *pagearray = NULL;
+    int i, j, k = 0;
+    struct scatterlist *s;
+    unsigned int size = 0;
+
+    if (!dmabuf)
+    {
+        ONERROR(EFAULT);
+    }
+
+    get_dma_buf(dmabuf);
+    attachment = dma_buf_attach(dmabuf, gdev);
+
+    if (!attachment)
+    {
+        ONERROR(EFAULT);
+    }
+
+    sgt = dma_buf_map_attachment(attachment, DMA_BIDIRECTIONAL);
+
+    if (!sgt)
+    {
+        ONERROR(EFAULT);
+    }
+
+    /* Prepare page array. */
+    /* Get number of pages. */
+    for_each_sg(sgt->sgl, s, sgt->orig_nents, i)
+    {
+        npages += (sg_dma_len(s) + PAGE_SIZE - 1) / PAGE_SIZE;
+    }
+
+    /* Allocate page array. */
+    ONERROR(AllocateMemory(npages * sizeof(*pagearray), (void * *)&pagearray));
+
+    /* Fill page array. */
+    for_each_sg(sgt->sgl, s, sgt->orig_nents, i)
+    {
+        for (j = 0; j < (sg_dma_len(s) + PAGE_SIZE - 1) / PAGE_SIZE; j++)
+        {
+            pagearray[k++] = sg_dma_address(s) + j * PAGE_SIZE;
+        }
+        size = sg_dma_len(s);
+    }
+
+    memBlk->pagearray = pagearray;
+    memBlk->attachment = attachment;
+    memBlk->sgt = sgt;
+    memBlk->numPages = npages;
+    memBlk->size = size;
+    memBlk->contiguous = (sgt->nents == 1) ? true : false;
+
+    return 0;
+
+OnError:
+    if (pagearray)
+    {
+        FreeMemory(pagearray);
+        pagearray = NULL;
+    }
+
+    if (sgt)
+    {
+        dma_buf_unmap_attachment(attachment, sgt, DMA_BIDIRECTIONAL);
+    }
+
+    return status;
+}
+
+static struct sg_table *_dmabuf_map(struct dma_buf_attachment *attachment,
+                                    enum dma_data_direction direction)
+{
+    struct sg_table *sgt = NULL;
+    struct dma_buf *dmabuf = attachment->dmabuf;
+    struct mem_block *memBlk = dmabuf->priv;
+    int status = 0;
+
+    printk("%s\n", __func__);
+
+    do
+    {
+        ERR_BREAK(GetSGT(memBlk, 0, memBlk->size, (void **)&sgt));
+
+        if (dma_map_sg(attachment->dev, sgt->sgl, sgt->nents, direction) == 0)
+        {
+            sg_free_table(sgt);
+            kfree(sgt);
+            sgt = NULL;
+            ERR_BREAK(EPERM);
+        }
+    }
+    while (false);
+
+    return sgt;
+}
+
+static void _dmabuf_unmap(struct dma_buf_attachment *attachment,
+                          struct sg_table *sgt,
+                          enum dma_data_direction direction)
+{
+    dma_unmap_sg(attachment->dev, sgt->sgl, sgt->nents, direction);
+
+    sg_free_table(sgt);
+    kfree(sgt);
+}
+
+static int _dmabuf_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma)
+{
+    struct mem_block *memBlk = dmabuf->priv;
+    size_t skipPages = vma->vm_pgoff;
+    size_t numPages = PAGE_ALIGN(vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
+    int status = 0;
+
+    printk("%s, %d: 0x%llx\n", __func__, __LINE__, page_to_phys(nth_page(memBlk->contiguousPages, 0)));
+
+    ONERROR(Mmap(memBlk, skipPages, numPages, vma));
+
+OnError:
+    return IS_ERROR(status) ? -EINVAL : 0;
+}
+
+static void _dmabuf_release(struct dma_buf *dmabuf)
+{
+}
+
+static void *_dmabuf_kmap(struct dma_buf *dmabuf, unsigned long offset)
+{
+    char *kvaddr = NULL;
+
+    return (void *)kvaddr;
+}
+
+static void _dmabuf_kunmap(struct dma_buf *dmabuf, unsigned long offset, void *ptr)
+{
+}
+
+static struct dma_buf_ops _dmabuf_ops =
+{
+    .map_dma_buf = _dmabuf_map,
+    .unmap_dma_buf = _dmabuf_unmap,
+    .mmap = _dmabuf_mmap,
+    .release = _dmabuf_release,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5,6,0)
+    .map = _dmabuf_kmap,
+    .unmap = _dmabuf_kunmap,
+#endif
+};
+
+
+static int
+DMABUF_Export(
+    IN struct file *filp,
+    IN unsigned long bus_address,
+    IN signed int Flags,
+    OUT signed int *FD
+    )
+{
+    int status = 0;
+    struct dma_buf *dmabuf = NULL;
+    struct mem_block *memBlk = NULL;
+    struct mem_node *mnode = NULL;
+
+    mnode = get_mem_node(filp, bus_address, 0);
+    if (NULL == mnode)
+    {
+        printk("Allocator: Cannot find mem_node with bus address 0x%lx\n", bus_address);
+        ONERROR(EINVAL);
+    }
+
+    memBlk = &mnode->memBlk;
+
+    dmabuf = memBlk->dmabuf;
+    if (dmabuf == NULL)
+    {
+        size_t bytes = memBlk->size;
+
+        {
+            DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
+            exp_info.ops = &_dmabuf_ops;
+            exp_info.size = bytes;
+            exp_info.flags = Flags;
+            exp_info.priv = memBlk;
+            dmabuf = dma_buf_export(&exp_info);
+        }
+
+        if (dmabuf == NULL)
+        {
+            ONERROR(EFAULT);
+        }
+
+        memBlk->dmabuf = dmabuf;
+    }
+
+    if (FD)
+    {
+        int fd = dma_buf_fd(dmabuf, Flags);
+
+        if (fd < 0)
+        {
+            ONERROR(EIO);
+        }
+
+        *FD = fd;
+    }
+
+OnError:
+    return status;
+}
+
+static int
+DMABUF_Import(
+    IN struct file *filp,
+    IN signed int FD,
+    OUT unsigned long *bus_address,
+    OUT unsigned int *size
+    )
+{
+    int status;
+
+    struct mem_block *memBlk = NULL;
+    struct file_node *fnode = NULL;
+    struct mem_node *mnode = NULL;
+
+    mnode = kzalloc(sizeof(struct mem_node), GFP_KERNEL | __GFP_NORETRY);
+
+    if (!mnode)
+    {
+        ONERROR(ENOMEM);
+    }
+
+    fnode = get_file_node(filp);
+
+    if (NULL == fnode)
+    {
+        ONERROR(EINVAL);
+    }
+
+    memBlk = &mnode->memBlk;
+
+    /* Import dma buf handle. */
+    memBlk->dmabuf = dma_buf_get(FD);
+    if (!memBlk->dmabuf)
+    {
+        ONERROR(EFAULT);
+    }
+
+    ONERROR(Attach(memBlk));
+
+    *bus_address = memBlk->pagearray[0];
+    *size = memBlk->size;
+
+    mnode->busAddr = memBlk->pagearray[0];
+    mnode->isImported = 1;
+    spin_lock(&mem_lock);
+    list_add_tail(&mnode->link, &fnode->memList);
+    spin_unlock(&mem_lock);
+
+    return 0;
+
+OnError:
+    if (mnode)
+    {
+        kfree(mnode);
+    }
+
+
+    return status;
+}
+
+void
+DMABUF_Release(
+    IN struct file *filp,
+    IN unsigned long bus_address
+    )
+{
+    struct mem_block *memBlk = NULL;
+    struct mem_node *mnode = NULL;
+
+    mnode = get_mem_node(filp, bus_address, 1);
+    if (NULL == mnode)
+    {
+        return;
+    }
+
+    memBlk = &mnode->memBlk;
+
+    dma_buf_unmap_attachment(memBlk->attachment, memBlk->sgt, DMA_BIDIRECTIONAL);
+
+    dma_buf_detach(memBlk->dmabuf, memBlk->attachment);
+
+    dma_buf_put(memBlk->dmabuf);
+
+    FreeMemory(memBlk->pagearray);
+
+    spin_lock(&mem_lock);
+    list_del(&mnode->link);
+    spin_unlock(&mem_lock);
+    kfree(mnode);
+}
+
+/***************************************************************************\
+************************ GFP Allocator **********************************
+\***************************************************************************/
+static void
+NonContiguousFree(
+    IN struct page ** Pages,
+    IN size_t NumPages
+    )
+{
+    size_t i;
+
+    for (i = 0; i < NumPages; i++)
+    {
+        __free_page(Pages[i]);
+    }
+
+    FreeMemory(Pages);
+}
+
+static int
+NonContiguousAlloc(
+    IN struct mem_block *MemBlk,
+    IN size_t NumPages,
+    IN unsigned int Gfp
+    )
+{
+    struct page ** pages;
+    struct page *p;
+    size_t i, size;
+
+    if (NumPages > totalram_pages())
+    {
+        return ENOMEM;
+    }
+
+    size = NumPages * sizeof(struct page *);
+    if (AllocateMemory(size, (void * *)&pages))
+        return ENOMEM;
+
+    for (i = 0; i < NumPages; i++)
+    {
+        p = alloc_page(Gfp);
+
+        if (!p)
+        {
+            NonContiguousFree(pages, i);
+            return ENOMEM;
+        }
+
+#if DISCRETE_PAGES
+        if (i != 0)
+        {
+            if (page_to_pfn(pages[i-1]) == page_to_pfn(p)-1)
+            {
+                /* Replaced page. */
+                struct page *l = p;
+
+                /* Allocate a page which is not contiguous to previous one. */
+                p = alloc_page(Gfp);
+
+                /* Give replaced page back. */
+                __free_page(l);
+
+                if (!p)
+                {
+                    NonContiguousFree(pages, i);
+                    return ENOMEM;
+                }
+            }
+        }
+#endif
+
+        pages[i] = p;
+    }
+
+    MemBlk->nonContiguousPages = pages;
+
+    return 0;
+}
+
+static int
+getPhysical(
+    IN struct mem_block *MemBlk,
+    IN unsigned int Offset,
+    OUT unsigned long * Physical
+    )
+{
+    struct mem_block *memBlk = MemBlk;
+    unsigned int offsetInPage = Offset & ~PAGE_MASK;
+    unsigned int index = Offset / PAGE_SIZE;
+
+    if (memBlk->contiguous)
+    {
+        *Physical = page_to_phys(nth_page(memBlk->contiguousPages, index));
+    }
+    else
+    {
+        *Physical = page_to_phys(memBlk->nonContiguousPages[index]);
+    }
+
+    *Physical += offsetInPage;
+
+    return 0;
+}
+
+int
+GFP_Alloc(
+    IN struct file *filp,
+    IN unsigned int size,
+    IN unsigned int Flags,
+    OUT unsigned long *bus_address
+    )
+{
+    int status;
+    size_t i = 0;
+    unsigned int gfp = GFP_KERNEL | __GFP_HIGHMEM | __GFP_NOWARN;
+    int contiguous = Flags & ALLOC_FLAG_CONTIGUOUS;
+    size_t numPages = GetPageCount(size, 0);
+    unsigned long physical = 0;
+
+    struct mem_block *memBlk = NULL;
+    struct file_node *fnode = NULL;
+    struct mem_node *mnode = NULL;
+
+    mnode = kzalloc(sizeof(struct mem_node), GFP_KERNEL | __GFP_NORETRY);
+
+    if (!mnode)
+    {
+        ONERROR(ENOMEM);
+    }
+
+    fnode = get_file_node(filp);
+
+    if (NULL == fnode)
+    {
+        ONERROR(EINVAL);
+    }
+
+    memBlk = &mnode->memBlk;
+
+    if (Flags & ALLOC_FLAG_4GB_ADDR)
+    {
+        /* remove __GFP_HIGHMEM bit, add __GFP_DMA32 bit */
+        gfp &= ~__GFP_HIGHMEM;
+        gfp |= __GFP_DMA32;
+    }
+
+    if (contiguous)
+    {
+        size_t bytes = numPages << PAGE_SHIFT;
+
+        void *addr = NULL;
+
+        addr = alloc_pages_exact(bytes, (gfp & ~__GFP_HIGHMEM) | __GFP_NORETRY);
+
+        memBlk->contiguousPages = addr ? virt_to_page(addr) : NULL;
+
+        if (memBlk->contiguousPages)
+        {
+            memBlk->exact = true;
+        }
+
+        if (memBlk->contiguousPages == NULL)
+        {
+            int order = get_order(bytes);
+
+            if (order >= MAX_ORDER)
+            {
+                status = ENOMEM;
+                goto OnError;
+            }
+
+            memBlk->contiguousPages = alloc_pages(gfp, order);
+        }
+
+        if (memBlk->contiguousPages == NULL)
+        {
+            ONERROR(ENOMEM);
+        }
+
+        memBlk->dma_addr = dma_map_page(gdev,
+                memBlk->contiguousPages, 0, numPages * PAGE_SIZE,
+                DMA_BIDIRECTIONAL);
+
+        if (dma_mapping_error(gdev, memBlk->dma_addr))
+        {
+            if (memBlk->exact)
+            {
+                free_pages_exact(page_address(memBlk->contiguousPages), bytes);
+            }
+            else
+            {
+                __free_pages(memBlk->contiguousPages, get_order(bytes));
+            }
+
+            ONERROR(ENOMEM);
+        }
+    }
+    else // non-contiguous pages
+    {
+        ONERROR(NonContiguousAlloc(memBlk, numPages, gfp));
+
+        // this piece of code is for sanity check
+        memBlk->sgt = kzalloc(sizeof(struct sg_table), GFP_KERNEL | __GFP_NORETRY);
+        if (!memBlk->sgt)
+        {
+            ONERROR(ENOMEM);
+        }
+
+        status = sg_alloc_table_from_pages(memBlk->sgt,
+                    memBlk->nonContiguousPages, numPages, 0,
+                    numPages << PAGE_SHIFT, GFP_KERNEL);
+        memBlk->sgt->orig_nents = memBlk->sgt->nents;
+        if (status < 0)
+        {
+            NonContiguousFree(memBlk->nonContiguousPages, numPages);
+            ONERROR(ENOMEM);
+        }
+
+        status = dma_map_sg(gdev, memBlk->sgt->sgl, memBlk->sgt->nents, DMA_BIDIRECTIONAL);
+        if (status != memBlk->sgt->nents)
+        {
+            NonContiguousFree(memBlk->nonContiguousPages, numPages);
+            sg_free_table(memBlk->sgt);
+            ONERROR(ENOMEM);
+        }
+    }
+
+    for (i = 0; i < numPages; i++)
+    {
+        struct page *page;
+
+        if (contiguous)
+        {
+            page = nth_page(memBlk->contiguousPages, i);
+        }
+        else
+        {
+            page = memBlk->nonContiguousPages[i];
+        }
+
+        SetPageReserved(page);
+    }
+
+    memBlk->contiguous = contiguous;
+    memBlk->numPages = numPages;
+    memBlk->size = size;
+
+    getPhysical(memBlk, 0, &physical);
+    *bus_address = physical;
+    mnode->busAddr = physical;
+    mnode->isImported = 0;
+
+    list_add_tail(&mnode->link, &fnode->memList);
+
+    printk("Allocated %d bytes (%ld pages) at physical address 0x%lx with %d sg table entries\n", 
+        size, numPages, physical, contiguous ? 1 : memBlk->sgt->nents);
+
+    return 0;
+
+OnError:
+    if (mnode)
+    {
+        kfree(mnode);
+    }
+
+    if (memBlk->sgt)
+    {
+        kfree(memBlk->sgt);
+    }
+
+    return status;
+}
+
+
+void
+GFP_Free(
+    IN struct file *filp,
+    IN unsigned long bus_address
+    )
+{
+    size_t i;
+    struct page * page;
+    struct mem_block *memBlk = NULL;
+    struct mem_node *mnode = NULL;
+
+    mnode = get_mem_node(filp, bus_address, 0);
+    if (NULL == mnode)
+    {
+        return;
+    }
+
+    memBlk = &mnode->memBlk;
+
+    printk("Free %ld pages from physical address 0x%lx\n", memBlk->numPages, mnode->busAddr);
+
+    if (memBlk->contiguous)
+    {
+        dma_unmap_page(gdev, memBlk->dma_addr,
+                memBlk->numPages << PAGE_SHIFT, DMA_FROM_DEVICE);
+    }
+    else
+    {
+        dma_unmap_sg(gdev, memBlk->sgt->sgl, memBlk->sgt->nents,
+                DMA_FROM_DEVICE);
+
+        sg_free_table(memBlk->sgt);
+
+        if (memBlk->sgt)
+        {
+            kfree(memBlk->sgt);
+        }
+    }
+
+    for (i = 0; i < memBlk->numPages; i++)
+    {
+        if (memBlk->contiguous)
+        {
+            page = nth_page(memBlk->contiguousPages, i);
+
+            ClearPageReserved(page);
+        }
+    }
+
+    if (memBlk->contiguous)
+    {
+        if (memBlk->exact == true)
+        {
+            free_pages_exact(page_address(memBlk->contiguousPages), memBlk->numPages * PAGE_SIZE);
+        }
+        else
+        {
+            __free_pages(memBlk->contiguousPages, get_order(memBlk->numPages * PAGE_SIZE));
+        }
+    }
+    else
+    {
+        NonContiguousFree(memBlk->nonContiguousPages, memBlk->numPages);
+    }
+
+    list_del(&mnode->link);
+    kfree(mnode);
+}
+
+static int
+GFP_MapUser(
+    IN struct file *filp,
+    IN struct vm_area_struct *vma
+    )
+{
+    struct mem_block *memBlk = NULL;
+    struct mem_node *mnode = NULL;
+    unsigned long bus_address = vma->vm_pgoff * PAGE_SIZE;
+    int status = 0;
+
+    mnode = get_mem_node(filp, bus_address, 0);
+    if (NULL == mnode)
+    {
+        return EINVAL;
+    }
+
+    memBlk = &mnode->memBlk;
+
+    if (Mmap(memBlk, 0, memBlk->numPages, vma))
+    {
+        return ENOMEM;
+    }
+    
+    memBlk->vma = vma;
+
+    DEBUG_PRINT("Map %ld pages from physical address 0x%lx\n", memBlk->numPages, mnode->busAddr);
+
+    return status;
+}
+
+int allocator_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+    return GFP_MapUser(filp, vma);
+}
+
+int allocator_ioctl(void *filp, unsigned int cmd, unsigned long arg)
+{
+    MemallocParams params;
+    int ret = 0;
+
+    if (_IOC_TYPE(cmd) != MEMORY_IOC_MAGIC) return EINVAL;
+    if (_IOC_NR(cmd) > MEMORY_IOC_MAXNR) return EINVAL;
+
+    if (_IOC_DIR(cmd) & _IOC_READ)
+        ret = !access_ok(arg, _IOC_SIZE(cmd));
+    else if (_IOC_DIR(cmd) & _IOC_WRITE)
+        ret = !access_ok(arg, _IOC_SIZE(cmd));
+    if (ret) return EINVAL;
+
+    switch (cmd)
+    {
+    case MEMORY_IOC_ALLOCATE:
+    {
+        ret = copy_from_user(&params, (void*)arg, sizeof(MemallocParams));
+        if (!ret)
+        {
+            ret = GFP_Alloc(filp, params.size, params.flags, &params.bus_address);
+            params.translation_offset = 0;
+            if (!ret)
+                ret = copy_to_user((MemallocParams *)arg, &params, sizeof(MemallocParams));
+        }
+        break;
+    }
+    case MEMORY_IOC_FREE:
+    {
+        ret = copy_from_user(&params, (void*)arg, sizeof(MemallocParams));
+        if (!ret)
+        {
+            GFP_Free(filp, params.bus_address);
+            ret = copy_to_user((MemallocParams *)arg, &params, sizeof(MemallocParams));
+        }
+        break;
+    }
+    case MEMORY_IOC_DMABUF_EXPORT:
+    {
+        ret = copy_from_user(&params, (void*)arg, sizeof(MemallocParams));
+        if (!ret)
+        {
+            ret = DMABUF_Export(filp, params.bus_address, params.flags, &params.fd);
+            if (!ret)
+                ret = copy_to_user((MemallocParams *)arg, &params, sizeof(MemallocParams));
+        }
+        break;
+    }
+    case MEMORY_IOC_DMABUF_IMPORT:
+    {
+        ret = copy_from_user(&params, (void*)arg, sizeof(MemallocParams));
+        if (!ret)
+        {
+            ret = DMABUF_Import(filp, params.fd, &params.bus_address, &params.size);
+            params.translation_offset = 0;
+            if (!ret)
+                ret = copy_to_user((MemallocParams *)arg, &params, sizeof(MemallocParams));
+        }
+        break;
+    }
+    case MEMORY_IOC_DMABUF_RELEASE:
+    {
+        ret = copy_from_user(&params, (void*)arg, sizeof(MemallocParams));
+        if (!ret)
+        {
+            DMABUF_Release(filp, params.bus_address);
+            ret = copy_to_user((MemallocParams *)arg, &params, sizeof(MemallocParams));
+        }
+        break;
+    }
+    default:
+        ret = EINVAL;
+    }
+
+    return ret;
+}
+
+
+int allocator_init(struct device *dev)
+{
+    int ret = 0;
+
+    gdev = dev;
+    INIT_LIST_HEAD(&fileList);
+
+    return ret;
+}
+
+void allocator_remove(void)
+{
+}
+
+int allocator_open(struct inode *inode, struct file *filp)
+{
+    int ret = 0;
+    struct file_node *fnode = NULL;
+    
+    if (AllocateMemory(sizeof(struct file_node), (void * *)&fnode))
+        return ENOMEM;
+
+    fnode->filp = filp; 
+    INIT_LIST_HEAD(&fnode->memList);
+    spin_lock(&mem_lock);
+    list_add_tail(&fnode->link, &fileList);
+    spin_unlock(&mem_lock);
+
+    return ret;
+}
+
+void allocator_release(struct inode *inode, struct file *filp)
+{
+#if 0
+    struct file_node *fnode = find_and_delete_file_node(filp);
+    struct mem_node *node;
+    struct mem_node *temp;
+
+    if (NULL == fnode)
+        return;
+
+    list_for_each_entry_safe(node, temp, &fnode->memList, link)
+    {
+        // this is not expected, memory leak detected!
+        printk("Allocator: Found unfreed memory at 0x%lx\n", node->busAddr);
+        if (node->isImported)
+            DMABUF_Release(filp, node->busAddr);
+        else
+            GFP_Free(filp, node->busAddr);
+        list_del(&node->link);
+        FreeMemory(node);
+    }
+    
+    list_del(&fnode->link);
+    FreeMemory(fnode);
+#endif
+}

+ 121 - 0
linux/subsys_driver/kernel_allocator.h

@@ -0,0 +1,121 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2021 Vivante Corporation
+*
+*    Permission is hereby granted, free of charge, to any person obtaining a
+*    copy of this software and associated documentation files (the "Software"),
+*    to deal in the Software without restriction, including without limitation
+*    the rights to use, copy, modify, merge, publish, distribute, sublicense,
+*    and/or sell copies of the Software, and to permit persons to whom the
+*    Software is furnished to do so, subject to the following conditions:
+*
+*    The above copyright notice and this permission notice 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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2021 Vivante Corporation
+*
+*    This program is free software; you can redistribute it and/or
+*    modify it under the terms of the GNU General Public License
+*    as published by the Free Software Foundation; either version 2
+*    of the License, or (at your option) any later version.
+*
+*    This program is distributed in the hope that it will be useful,
+*    but WITHOUT ANY WARRANTY; without even the implied warranty of
+*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*    GNU General Public License for more details.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_kernel_allocator_h_
+#define __gc_hal_kernel_allocator_h_
+
+#include "../memalloc/memalloc.h"
+
+
+#define IN
+#define OUT
+#define INOUT
+#define OPTIONAL
+
+/* No special needs. */
+#define ALLOC_FLAG_NONE                  0x00000000
+/* Physical contiguous. */
+#define ALLOC_FLAG_CONTIGUOUS            0x00000001
+/* Physical non contiguous. */
+#define ALLOC_FLAG_NON_CONTIGUOUS        0x00000002
+/* Need 32bit address. */
+#define ALLOC_FLAG_4GB_ADDR              0x00000004
+
+
+#define MEMORY_IOC_MAGIC  'a'
+
+#define MEMORY_IOC_ALLOCATE         _IOWR(MEMORY_IOC_MAGIC, 1, MemallocParams *)
+#define MEMORY_IOC_FREE             _IOWR(MEMORY_IOC_MAGIC, 2, MemallocParams *)
+#define MEMORY_IOC_DMABUF_EXPORT    _IOWR(MEMORY_IOC_MAGIC, 3, MemallocParams *)
+#define MEMORY_IOC_DMABUF_IMPORT    _IOWR(MEMORY_IOC_MAGIC, 4, MemallocParams *)
+#define MEMORY_IOC_DMABUF_RELEASE   _IOWR(MEMORY_IOC_MAGIC, 5, MemallocParams *)
+#define MEMORY_IOC_MAXNR 5
+
+#if 0
+int
+GFP_Alloc(
+    INOUT MemallocParams *params,
+    IN unsigned int Flags,
+    IN struct device *dev
+    );
+
+void
+GFP_Free(
+    INOUT MemallocParams *params
+    );
+
+int
+DMABUF_Export(
+    IN MemallocParams *params,
+    IN signed int Flags,
+    OUT signed int *FD
+    );
+
+int
+DMABUF_Import(
+    IN unsigned int FD,
+    IN struct device *dev,
+    OUT MemallocParams *params
+    );
+
+void
+DMABUF_Release(
+    INOUT MemallocParams *params
+    );
+#endif
+
+
+
+#endif

+ 203 - 0
linux/subsys_driver/subsys.c

@@ -0,0 +1,203 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2021 VERISILICON
+*
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2021 VERISILICON
+*
+*    This program is free software; you can redistribute it and/or
+*    modify it under the terms of the GNU General Public License
+*    as published by the Free Software Foundation; either version 2
+*    of the License, or (at your option) any later version.
+*
+*    This program is distributed in the hope that it will be useful,
+*    but WITHOUT ANY WARRANTY; without even the implied warranty of
+*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*    GNU General Public License for more details.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+#include "subsys.h"
+
+/******************************************************************************/
+/* subsystem configuration                                                    */
+/******************************************************************************/
+
+/* List of subsystems */
+struct SubsysDesc subsys_array[] = {
+  /* {slice_index, index, base} */
+  {0, 0, 0xffecc00000},
+//  {0, 1, 0x700000}
+};
+
+/* List of all HW cores. */
+struct CoreDesc core_array[] = {
+  /* {slice, subsys, core_type, offset, iosize, irq, has_apbfilter} */
+#if 0
+  {0, 0, HW_VC8000DJ, 0x600000, 0, 0},
+  {0, 0, HW_VC8000D, 0x602000, 0, 0},
+  {0, 0, HW_L2CACHE, 0x604000, 0, 0},
+  {0, 0, HW_DEC400, 0x606000, 0, 0},
+  {0, 0, HW_BIGOCEAN, 0x608000, 0, 0},
+  {0, 0, HW_NOC,0x60a000, 0, 0},
+  {0, 0, HW_AXIFE, 0x60c000, 0, 0}
+#endif
+  {0, 0, HW_VCMD, 0x0, 27*4, 12},
+  {0, 0, HW_VC8000D, 0x1000, 1023*4, -1, 0},
+  {0, 0, HW_L2CACHE, 0x2000, 231*4, -1, 0},
+  {0, 0, HW_MMU, 0x3000, 228*4, -1, 0},
+  //{0, 0, HW_MMU_WR, 0x4000, 228*4, -1, 0},
+  //{0, 0, HW_AXIFE, 0x5000, 64*4, -1, 1},
+  {0, 0, HW_DEC400, 0x6000, 1568*4, -1, 0},
+  //{0, 1, HW_VCMD, 0x0, 27*4, -1, 0},
+  //{0, 1, HW_VC8000D, 0x1000, 503*4, -1, 1},
+  //{0, 1, HW_L2CACHE, 0x2000, 231*4, -1, 0},
+  //{0, 1, HW_MMU, 0x3000, 228*4, -1, 0},
+  //{0, 1, HW_MMU_WR, 0x4000, 228*4, -1, 0},
+  //{0, 1, HW_AXIFE, 0x5000, 64*4, -1, 1},
+  //{0, 1, HW_DEC400, 0x6000, 1568*4, -1, 0},
+};
+
+extern struct vcmd_config vcmd_core_array[MAX_SUBSYS_NUM];
+extern int total_vcmd_core_num;
+extern unsigned long multicorebase[];
+extern int irq[];
+extern unsigned int iosize[];
+extern int reg_count[];
+
+/*
+   If VCMD is used, convert core_array to vcmd_core_array, which are used in
+   hantor_vcmd.c.
+   Otherwise, covnert core_array to multicore_base/irq/iosize, which are used in
+   hantro_dec.c
+
+   VCMD:
+        - struct vcmd_config vcmd_core_array[MAX_SUBSYS_NUM]
+        - total_vcmd_core_num
+
+   NON-VCMD:
+        - multicorebase[HXDEC_MAX_CORES]
+        - irq[HXDEC_MAX_CORES]
+        - iosize[HXDEC_MAX_CORES]
+*/
+void CheckSubsysCoreArray(struct subsys_config *subsys, int *vcmd) {
+  int num = sizeof(subsys_array)/sizeof(subsys_array[0]);
+  int i, j;
+
+  memset(subsys, 0, sizeof(subsys[0])*MAX_SUBSYS_NUM);
+  for (i = 0; i < num; i++) {
+    subsys[i].base_addr = subsys_array[i].base;
+    subsys[i].irq = -1;
+    for (j = 0; j < HW_CORE_MAX; j++) {
+      subsys[i].submodule_offset[j] = 0xffff;
+      subsys[i].submodule_iosize[j] = 0;
+      subsys[i].submodule_hwregs[j] = NULL;
+    }
+  }
+
+  total_vcmd_core_num = 0;
+
+  for (i = 0; i < sizeof(core_array)/sizeof(core_array[0]); i++) {
+    if (!subsys[core_array[i].subsys].base_addr) {
+      /* undefined subsystem */
+      continue;
+    }
+    subsys[core_array[i].subsys].submodule_offset[core_array[i].core_type]
+                                  = core_array[i].offset;
+    subsys[core_array[i].subsys].submodule_iosize[core_array[i].core_type]
+                                  = core_array[i].iosize;
+    if (subsys[core_array[i].subsys].irq != -1 && core_array[i].irq != -1) {
+      if (subsys[core_array[i].subsys].irq != core_array[i].irq) {
+        printk(KERN_INFO "hantrodec: hw core type %d irq %d != subsystem irq %d\n",
+                          core_array[i].core_type,
+                          core_array[i].irq,
+                          subsys[core_array[i].subsys].irq);
+        printk(KERN_INFO "hantrodec: hw cores of a subsystem should have same irq\n");
+      }
+	} else if (core_array[i].irq != -1) {
+      subsys[core_array[i].subsys].irq = core_array[i].irq;
+    }
+    subsys[core_array[i].subsys].has_apbfilter[core_array[i].core_type] = core_array[i].has_apb;
+    /* vcmd found */
+    if (core_array[i].core_type == HW_VCMD) {
+      *vcmd = 1;
+      total_vcmd_core_num++;
+    }
+  }
+
+  printk(KERN_INFO "hantrodec: vcmd = %d\n", *vcmd);
+
+  /* To plug into hantro_vcmd.c */
+  if (*vcmd) {
+    for (i = 0; i < total_vcmd_core_num; i++) {
+      vcmd_core_array[i].vcmd_base_addr = subsys[i].base_addr;
+      vcmd_core_array[i].vcmd_iosize = subsys[i].submodule_iosize[HW_VCMD];
+      vcmd_core_array[i].vcmd_irq = subsys[i].irq;
+      vcmd_core_array[i].sub_module_type = 2; /* TODO(min): to be fixed */
+      vcmd_core_array[i].submodule_main_addr = subsys[i].submodule_offset[HW_VC8000D];
+      vcmd_core_array[i].submodule_dec400_addr = subsys[i].submodule_offset[HW_DEC400];
+      vcmd_core_array[i].submodule_L2Cache_addr = subsys[i].submodule_offset[HW_L2CACHE];
+      vcmd_core_array[i].submodule_MMU_addr = subsys[i].submodule_offset[HW_MMU];
+      vcmd_core_array[i].submodule_MMUWrite_addr = subsys[i].submodule_offset[HW_MMU_WR];
+      vcmd_core_array[i].submodule_axife_addr = subsys[i].submodule_offset[HW_AXIFE];
+    }
+  }
+  memset(multicorebase, 0, sizeof(multicorebase[0]) * HXDEC_MAX_CORES);
+  for (i = 0; i < num; i++) {
+    multicorebase[i] = subsys[i].base_addr + subsys[i].submodule_offset[HW_VC8000D];
+    irq[i] = subsys[i].irq;
+    iosize[i] = subsys[i].submodule_iosize[HW_VC8000D];
+    printk(KERN_INFO "hantrodec: [%d] multicorebase 0x%08lx, iosize %d\n", i, multicorebase[i], iosize[i]);
+  }
+}
+
+void dump_core_array(void)
+{
+	int i;
+	for (i = 0; i < sizeof(core_array)/sizeof(core_array[0]); i++) {
+		printk(KERN_INFO "lucz: dumping dump_core_array[%d]\n", i);
+		printk(KERN_INFO "  slice=%d\n", core_array[i].slice);
+		printk(KERN_INFO "  subsys=%d\n", core_array[i].subsys);
+		printk(KERN_INFO "  core_type=%d\n", core_array[i].core_type);
+		printk(KERN_INFO "  offset=%d\n", core_array[i].offset);
+		printk(KERN_INFO "  iosize=%d\n", core_array[i].iosize);
+		printk(KERN_INFO "  irq=%d\n", core_array[i].irq);
+		printk(KERN_INFO "  has_apb=%d\n", core_array[i].has_apb);
+	}
+}
+

+ 203 - 0
linux/subsys_driver/subsys.h

@@ -0,0 +1,203 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2021 VERISILICON
+*
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2021 VERISILICON
+*
+*    This program is free software; you can redistribute it and/or
+*    modify it under the terms of the GNU General Public License
+*    as published by the Free Software Foundation; either version 2
+*    of the License, or (at your option) any later version.
+*
+*    This program is distributed in the hope that it will be useful,
+*    but WITHOUT ANY WARRANTY; without even the implied warranty of
+*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*    GNU General Public License for more details.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+#ifndef _SUBSYS_H_
+#define _SUBSYS_H_
+
+#ifdef __FREERTOS__
+/* nothing */
+#elif defined(__linux__)
+#include <linux/fs.h>
+#include <linux/platform_device.h>
+#endif
+#include "hantrodec.h"
+
+#ifndef NULL
+#ifdef __cplusplus
+#define NULL 0
+#else
+#define NULL ((void *)0)
+#endif
+#endif
+
+/* Functions provided by all other subsystem IP - hantrodec_xxx.c */
+
+/******************************************************************************/
+/* subsys level */
+/******************************************************************************/
+
+#define MAX_SUBSYS_NUM  4   /* up to 4 subsystem (temporary) */
+#define HXDEC_MAX_CORES MAX_SUBSYS_NUM    /* used in hantro_dec_xxx.c */
+
+/* SubsysDesc & CoreDesc are used for configuration */
+struct SubsysDesc {
+  int slice_index;    /* slice this subsys belongs to */
+  int index;   /* subsystem index */
+  long base;
+};
+
+struct CoreDesc {
+  int slice;
+  int subsys;     /* subsys this core belongs to */
+  enum CoreType core_type;
+  int offset;     /* offset to subsystem base */
+  int iosize;
+  int irq;
+  int has_apb;
+};
+
+/* internal config struct (translated from SubsysDesc & CoreDesc) */
+struct subsys_config {
+  unsigned long base_addr;
+  int irq;
+  u32 subsys_type;  /* identifier for each subsys vc8000e=0,IM=1,vc8000d=2,jpege=3,jpegd=4 */
+  u32 submodule_offset[HW_CORE_MAX]; /* in bytes */
+  u16 submodule_iosize[HW_CORE_MAX]; /* in bytes */
+  volatile u8 *submodule_hwregs[HW_CORE_MAX]; /* virtual address */
+  int has_apbfilter[HW_CORE_MAX];
+};
+
+void CheckSubsysCoreArray(struct subsys_config *subsys, int *vcmd);
+
+/******************************************************************************/
+/* VCMD */
+/******************************************************************************/
+#define OPCODE_WREG               (0x01<<27)
+#define OPCODE_END                (0x02<<27)
+#define OPCODE_NOP                (0x03<<27)
+#define OPCODE_RREG               (0x16<<27)
+#define OPCODE_INT                (0x18<<27)
+#define OPCODE_JMP                (0x19<<27)
+#define OPCODE_STALL              (0x09<<27)
+#define OPCODE_CLRINT             (0x1a<<27)
+#define OPCODE_JMP_RDY0           (0x19<<27)
+#define OPCODE_JMP_RDY1           ((0x19<<27)|(1<<26))
+#define JMP_IE_1                  (1<<25)
+#define JMP_RDY_1                 (1<<26)
+
+/* Used in vcmd initialization in hantro_vcmd_xxx.c. */
+/* May be unified in next step. */
+struct vcmd_config {
+  unsigned long vcmd_base_addr;
+  u32 vcmd_iosize;
+  int vcmd_irq;
+  u32 sub_module_type;        /*input vc8000e=0,IM=1,vc8000d=2,jpege=3, jpegd=4*/
+  u16 submodule_main_addr;    // in byte
+  u16 submodule_dec400_addr;  //if submodule addr == 0xffff, this submodule does not exist.// in byte
+  u16 submodule_L2Cache_addr; // in byte
+  u16 submodule_MMU_addr;     // in byte
+  u16 submodule_MMUWrite_addr;// in byte
+  u16 submodule_axife_addr;   // in byte
+};
+
+
+#ifdef __FREERTOS__
+/* nothing */
+#elif defined(__linux__)
+int hantrovcmd_open(struct inode *inode, struct file *filp);
+int hantrovcmd_release(struct inode *inode, struct file *filp);
+long hantrovcmd_ioctl(struct file *filp,
+                      unsigned int cmd, unsigned long arg);
+int hantrovcmd_init(struct platform_device *pdev);
+void hantrovcmd_cleanup(struct platform_device *pdev);
+void hantrovcmd_reset(void);
+
+/******************************************************************************/
+/* MMU */
+/******************************************************************************/
+
+/* Init MMU, should be called in driver init function. */
+enum MMUStatus MMUInit(volatile unsigned char *hwregs);
+/* Clean up all data in MMU, should be called in driver cleanup function
+   when rmmod driver*/
+enum MMUStatus MMUCleanup(volatile unsigned char *hwregs[MAX_SUBSYS_NUM][2]);
+/* The function should be called in driver realease function
+   when driver exit unnormally */
+enum MMUStatus MMURelease(void *filp, volatile unsigned char *hwregs);
+
+enum MMUStatus MMUEnable(volatile unsigned char *hwregs[MAX_SUBSYS_NUM][2]);
+
+/* Used in kernel to map buffer */
+enum MMUStatus MMUKernelMemNodeMap(struct kernel_addr_desc *addr);
+/* Used in kernel to unmap buffer */
+enum MMUStatus MMUKernelMemNodeUnmap(struct kernel_addr_desc *addr);
+
+long MMUIoctl(unsigned int cmd, void *filp, unsigned long arg,
+              volatile unsigned char *hwregs[MAX_SUBSYS_NUM][2]);
+
+void MMURestore(volatile unsigned char *hwregs[MAX_SUBSYS_NUM][2]);
+
+int allocator_init(struct device *dev);
+void allocator_remove(void);
+int allocator_open(struct inode *inode, struct file *filp);
+void allocator_release(struct inode *inode, struct file *filp);
+int allocator_ioctl(void *filp, unsigned int cmd, unsigned long arg);
+int allocator_mmap(struct file *filp, struct vm_area_struct *vma);
+
+/******************************************************************************/
+/* L2Cache */
+/******************************************************************************/
+
+/******************************************************************************/
+/* DEC400 */
+/******************************************************************************/
+
+
+/******************************************************************************/
+/* AXI FE */
+/******************************************************************************/
+#endif
+
+#endif
+

+ 156 - 0
linux/subsys_driver/vcmdregisterenum.h

@@ -0,0 +1,156 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2021 VERISILICON
+*
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2021 VERISILICON
+*
+*    This program is free software; you can redistribute it and/or
+*    modify it under the terms of the GNU General Public License
+*    as published by the Free Software Foundation; either version 2
+*    of the License, or (at your option) any later version.
+*
+*    This program is distributed in the hope that it will be useful,
+*    but WITHOUT ANY WARRANTY; without even the implied warranty of
+*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*    GNU General Public License for more details.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+/* Register interface based on the document version 1.1.2 */
+    HWIF_VCMD_HW_ID,
+    HWIF_VCMD_HW_VERSION,
+    HWIF_VCMD_HW_BUILD_DATE,
+    HWIF_VCMD_EXT_ABN_INT_SRC_VCD_MMU,
+    HWIF_VCMD_EXT_ABN_INT_SRC_VCD_L2CACHE,
+    HWIF_VCMD_EXT_ABN_INT_SRC_VCD_DEC400,
+    HWIF_VCMD_EXT_ABN_INT_SRC_VCD,
+    HWIF_VCMD_EXT_ABN_INT_SRC_CUTREE_MMU,
+    HWIF_VCMD_EXT_ABN_INT_SRC_VCE_MMU,
+    HWIF_VCMD_EXT_ABN_INT_SRC_VCE_L2CACHE,
+    HWIF_VCMD_EXT_ABN_INT_SRC_VCE_DEC400,
+    HWIF_VCMD_EXT_ABN_INT_SRC_CUTREE,
+    HWIF_VCMD_EXT_ABN_INT_SRC_VCE,
+    HWIF_VCMD_EXT_NORM_INT_SRC_VCD_MMU,
+    HWIF_VCMD_EXT_NORM_INT_SRC_VCD_L2CACHE,
+    HWIF_VCMD_EXT_NORM_INT_SRC_VCD_DEC400,
+    HWIF_VCMD_EXT_NORM_INT_SRC_VCD,
+    HWIF_VCMD_EXT_NORM_INT_SRC_CUTREE_MMU,
+    HWIF_VCMD_EXT_NORM_INT_SRC_VCE_MMU,
+    HWIF_VCMD_EXT_NORM_INT_SRC_VCE_L2CACHE,
+    HWIF_VCMD_EXT_NORM_INT_SRC_VCE_DEC400,
+    HWIF_VCMD_EXT_NORM_INT_SRC_CUTREE,
+    HWIF_VCMD_EXT_NORM_INT_SRC_VCE,
+    HWIF_VCMD_EXE_CMDBUF_COUNT,
+    HWIF_VCMD_EXECUTING_CMD,
+    HWIF_VCMD_EXECUTING_CMD_MSB,
+    HWIF_VCMD_AXI_TOTAL_AR_LEN,
+    HWIF_VCMD_AXI_TOTAL_R,
+    HWIF_VCMD_AXI_TOTAL_AR,
+    HWIF_VCMD_AXI_TOTAL_R_LAST,
+    HWIF_VCMD_AXI_TOTAL_AW_LEN,
+    HWIF_VCMD_AXI_TOTAL_W,
+    HWIF_VCMD_AXI_TOTAL_AW,
+    HWIF_VCMD_AXI_TOTAL_W_LAST,
+    HWIF_VCMD_AXI_TOTAL_B,
+    HWIF_VCMD_AXI_AR_VALID,
+    HWIF_VCMD_AXI_AR_READY,
+    HWIF_VCMD_AXI_R_VALID,
+    HWIF_VCMD_AXI_R_READY,
+    HWIF_VCMD_AXI_AW_VALID,
+    HWIF_VCMD_AXI_AW_READY,
+    HWIF_VCMD_AXI_W_VALID,
+    HWIF_VCMD_AXI_W_READY,
+    HWIF_VCMD_AXI_B_VALID,
+    HWIF_VCMD_AXI_B_READY,
+    HWIF_VCMD_WORK_STATE,
+    HWIF_VCMD_AXI_CLK_GATE_DISABLE,
+    HWIF_VCMD_MASTER_OUT_CLK_GATE_DISABLE,
+    HWIF_VCMD_CORE_CLK_GATE_DISABLE,
+    HWIF_VCMD_ABORT_MODE,
+    HWIF_VCMD_RESET_CORE,
+    HWIF_VCMD_RESET_ALL,
+    HWIF_VCMD_START_TRIGGER,
+    HWIF_VCMD_IRQ_INTCMD,
+    HWIF_VCMD_IRQ_JMPP,
+    HWIF_VCMD_IRQ_JMPD,
+    HWIF_VCMD_IRQ_RESET,
+    HWIF_VCMD_IRQ_ABORT,
+    HWIF_VCMD_IRQ_CMDERR,
+    HWIF_VCMD_IRQ_TIMEOUT,
+    HWIF_VCMD_IRQ_BUSERR,
+    HWIF_VCMD_IRQ_ENDCMD,
+    HWIF_VCMD_IRQ_INTCMD_EN,
+    HWIF_VCMD_IRQ_JMPP_EN,
+    HWIF_VCMD_IRQ_JMPD_EN,
+    HWIF_VCMD_IRQ_RESET_EN,
+    HWIF_VCMD_IRQ_ABORT_EN,
+    HWIF_VCMD_IRQ_CMDERR_EN,
+    HWIF_VCMD_IRQ_TIMEOUT_EN,
+    HWIF_VCMD_IRQ_BUSERR_EN,
+    HWIF_VCMD_IRQ_ENDCMD_EN,
+    HWIF_VCMD_TIMEOUT_EN,
+    HWIF_VCMD_TIMEOUT_CYCLES,
+    HWIF_VCMD_EXECUTING_CMD_ADDR,
+    HWIF_VCMD_EXECUTING_CMD_ADDR_MSB,
+    HWIF_VCMD_EXE_CMDBUF_LENGTH,
+    HWIF_VCMD_CMD_SWAP,
+    HWIF_VCMD_MAX_BURST_LEN,
+    HWIF_VCMD_AXI_ID_RD,
+    HWIF_VCMD_AXI_ID_WR,
+    HWIF_VCMD_RDY_CMDBUF_COUNT,
+    HWIF_VCMD_EXT_ABN_INT_SRC_VCD_MMU_GATE,
+    HWIF_VCMD_EXT_ABN_INT_SRC_VCD_L2CACHE_GATE,
+    HWIF_VCMD_EXT_ABN_INT_SRC_VCD_DEC400_GATE,
+    HWIF_VCMD_EXT_ABN_INT_SRC_VCD_GATE,
+    HWIF_VCMD_EXT_ABN_INT_SRC_CUTREE_MMU_GATE,
+    HWIF_VCMD_EXT_ABN_INT_SRC_VCE_MMU_GATE,
+    HWIF_VCMD_EXT_ABN_INT_SRC_VCE_L2CACHE_GATE,
+    HWIF_VCMD_EXT_ABN_INT_SRC_VCE_DEC400_GATE,
+    HWIF_VCMD_EXT_ABN_INT_SRC_CUTREE_GATE,
+    HWIF_VCMD_EXT_ABN_INT_SRC_VCE_GATE,
+    HWIF_VCMD_EXT_NORM_INT_SRC_VCD_MMU_GATE,
+    HWIF_VCMD_EXT_NORM_INT_SRC_VCD_L2CACHE_GATE,
+    HWIF_VCMD_EXT_NORM_INT_SRC_VCD_DEC400_GATE,
+    HWIF_VCMD_EXT_NORM_INT_SRC_VCD_GATE,
+    HWIF_VCMD_EXT_NORM_INT_SRC_CUTREE_MMU_GATE,
+    HWIF_VCMD_EXT_NORM_INT_SRC_VCE_MMU_GATE,
+    HWIF_VCMD_EXT_NORM_INT_SRC_VCE_L2CACHE_GATE,
+    HWIF_VCMD_EXT_NORM_INT_SRC_VCE_DEC400_GATE,
+    HWIF_VCMD_EXT_NORM_INT_SRC_CUTREE_GATE,
+    HWIF_VCMD_EXT_NORM_INT_SRC_VCE_GATE,
+    HWIF_VCMD_CMDBUF_EXECUTING_ID,

+ 156 - 0
linux/subsys_driver/vcmdregistertable.h

@@ -0,0 +1,156 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2021 VERISILICON
+*
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2021 VERISILICON
+*
+*    This program is free software; you can redistribute it and/or
+*    modify it under the terms of the GNU General Public License
+*    as published by the Free Software Foundation; either version 2
+*    of the License, or (at your option) any later version.
+*
+*    This program is distributed in the hope that it will be useful,
+*    but WITHOUT ANY WARRANTY; without even the implied warranty of
+*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*    GNU General Public License for more details.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+/* Register interface based on the document version 1.1.2 */
+    VCMDREG(HWIF_VCMD_HW_ID                         , 0  ,0xffff0000,       16,        0,RO,"HW ID"),
+    VCMDREG(HWIF_VCMD_HW_VERSION                    , 0  ,0x0000ffff,        0,        0,RO,"version of hw(1.0.0).[15:12]-major [11:8]-minor [7:0]-build"),
+    VCMDREG(HWIF_VCMD_HW_BUILD_DATE                 , 4  ,0xffffffff,        0,        0,RO,"Hw package generation date in BCD code"),
+    VCMDREG(HWIF_VCMD_EXT_ABN_INT_SRC_VCD_MMU       , 8  ,0x08000000,       27,        0,RO,"external abnormal interrupt source from mmu of vcd."),
+    VCMDREG(HWIF_VCMD_EXT_ABN_INT_SRC_VCD_L2CACHE   , 8  ,0x04000000,       26,        0,RO,"external abnormal interrupt source from l2cache of vcd."),
+    VCMDREG(HWIF_VCMD_EXT_ABN_INT_SRC_VCD_DEC400    , 8  ,0x02000000,       25,        0,RO,"external abnormal interrupt source from dec400 of vcd."),
+    VCMDREG(HWIF_VCMD_EXT_ABN_INT_SRC_VCD           , 8  ,0x01000000,       24,        0,RO,"external abnormal interrupt source from vcd."),
+    VCMDREG(HWIF_VCMD_EXT_ABN_INT_SRC_CUTREE_MMU    , 8  ,0x00200000,       21,        0,RO,"external abnormal interrupt source from mmu of cutree."),
+    VCMDREG(HWIF_VCMD_EXT_ABN_INT_SRC_VCE_MMU       , 8  ,0x00100000,       20,        0,RO,"external abnormal interrupt source from mmu of vce."),
+    VCMDREG(HWIF_VCMD_EXT_ABN_INT_SRC_VCE_L2CACHE   , 8  ,0x00080000,       19,        0,RO,"external abnormal interrupt source from l2 cache of vce."),
+    VCMDREG(HWIF_VCMD_EXT_ABN_INT_SRC_VCE_DEC400    , 8  ,0x00040000,       18,        0,RO,"external abnormal interrupt source from dec400 of vce."),
+    VCMDREG(HWIF_VCMD_EXT_ABN_INT_SRC_CUTREE        , 8  ,0x00020000,       17,        0,RO,"external abnormal interrupt source from cutree."),
+    VCMDREG(HWIF_VCMD_EXT_ABN_INT_SRC_VCE           , 8  ,0x00010000,       16,        0,RO,"external abnormal interrupt source from vce."),
+    VCMDREG(HWIF_VCMD_EXT_NORM_INT_SRC_VCD_MMU      , 8  ,0x00000800,       11,        0,RO,"external normal interrupt source from mmu of vcd."),
+    VCMDREG(HWIF_VCMD_EXT_NORM_INT_SRC_VCD_L2CACHE  , 8  ,0x00000400,       10,        0,RO,"external normal interrupt source from l2cache of vcd."),
+    VCMDREG(HWIF_VCMD_EXT_NORM_INT_SRC_VCD_DEC400   , 8  ,0x00000200,        9,        0,RO,"external normal interrupt source from dec400 of vcd."),
+    VCMDREG(HWIF_VCMD_EXT_NORM_INT_SRC_VCD          , 8  ,0x00000100,        8,        0,RO,"external normal interrupt source from vcd."),
+    VCMDREG(HWIF_VCMD_EXT_NORM_INT_SRC_CUTREE_MMU   , 8  ,0x00000020,        5,        0,RO,"external normal interrupt source from mmu of cutree."),
+    VCMDREG(HWIF_VCMD_EXT_NORM_INT_SRC_VCE_MMU      , 8  ,0x00000010,        4,        0,RO,"external normal interrupt source from mmu of vce."),
+    VCMDREG(HWIF_VCMD_EXT_NORM_INT_SRC_VCE_L2CACHE  , 8  ,0x00000008,        3,        0,RO,"external normal interrupt source from l2 cache of vce."),
+    VCMDREG(HWIF_VCMD_EXT_NORM_INT_SRC_VCE_DEC400   , 8  ,0x00000004,        2,        0,RO,"external normal interrupt source from dec400 of vce."),
+    VCMDREG(HWIF_VCMD_EXT_NORM_INT_SRC_CUTREE       , 8  ,0x00000002,        1,        0,RO,"external normal interrupt source from cutree."),
+    VCMDREG(HWIF_VCMD_EXT_NORM_INT_SRC_VCE          , 8  ,0x00000001,        0,        0,RO,"external normal interrupt source from vce."),
+    VCMDREG(HWIF_VCMD_EXE_CMDBUF_COUNT              , 12 ,0xffffffff,        0,        0,RO,"Hw increases this counter by 1 after one more command buffer has been executed"),
+    VCMDREG(HWIF_VCMD_EXECUTING_CMD                 , 16 ,0xffffffff,        0,        0,RO,"the first 32 bits of the executing cmd."),
+    VCMDREG(HWIF_VCMD_EXECUTING_CMD_MSB             , 20 ,0xffffffff,        0,        0,RO,"the second 32 bits of the executing cmd."),
+    VCMDREG(HWIF_VCMD_AXI_TOTAL_AR_LEN              , 24 ,0xffffffff,        0,        0,RO,"axi total ar length"),
+    VCMDREG(HWIF_VCMD_AXI_TOTAL_R                   , 28 ,0xffffffff,        0,        0,RO,"axi total r"),
+    VCMDREG(HWIF_VCMD_AXI_TOTAL_AR                  , 32 ,0xffffffff,        0,        0,RO,"axi total ar"),
+    VCMDREG(HWIF_VCMD_AXI_TOTAL_R_LAST              , 36 ,0xffffffff,        0,        0,RO,"axi total r last"),
+    VCMDREG(HWIF_VCMD_AXI_TOTAL_AW_LEN              , 40 ,0xffffffff,        0,        0,RO,"axi total aw length"),
+    VCMDREG(HWIF_VCMD_AXI_TOTAL_W                   , 44 ,0xffffffff,        0,        0,RO,"axi total w"),
+    VCMDREG(HWIF_VCMD_AXI_TOTAL_AW                  , 48 ,0xffffffff,        0,        0,RO,"axi total aw"),
+    VCMDREG(HWIF_VCMD_AXI_TOTAL_W_LAST              , 52 ,0xffffffff,        0,        0,RO,"axi total w last"),
+    VCMDREG(HWIF_VCMD_AXI_TOTAL_B                   , 56 ,0xffffffff,        0,        0,RO,"axi total b"),
+    VCMDREG(HWIF_VCMD_AXI_AR_VALID                  , 60 ,0x80000000,       31,        0,RO,"axi ar valid"),
+    VCMDREG(HWIF_VCMD_AXI_AR_READY                  , 60 ,0x40000000,       30,        0,RO,"axi ar ready"),
+    VCMDREG(HWIF_VCMD_AXI_R_VALID                   , 60 ,0x20000000,       29,        0,RO,"axi r valid"),
+    VCMDREG(HWIF_VCMD_AXI_R_READY                   , 60 ,0x10000000,       28,        0,RO,"axi r ready"),
+    VCMDREG(HWIF_VCMD_AXI_AW_VALID                  , 60 ,0x08000000,       27,        0,RO,"axi aw valid"),
+    VCMDREG(HWIF_VCMD_AXI_AW_READY                  , 60 ,0x04000000,       26,        0,RO,"axi aw ready"),
+    VCMDREG(HWIF_VCMD_AXI_W_VALID                   , 60 ,0x02000000,       25,        0,RO,"axi w valid"),
+    VCMDREG(HWIF_VCMD_AXI_W_READY                   , 60 ,0x01000000,       24,        0,RO,"axi w ready"),
+    VCMDREG(HWIF_VCMD_AXI_B_VALID                   , 60 ,0x00800000,       23,        0,RO,"axi b valid"),
+    VCMDREG(HWIF_VCMD_AXI_B_READY                   , 60 ,0x00400000,       22,        0,RO,"axi b ready"),
+    VCMDREG(HWIF_VCMD_WORK_STATE                    , 60 ,0x00000007,        0,        0,RO,"hw work state. 0-IDLE 1-WORK 2-STALL 3-PEND 4-ABORT"),
+    VCMDREG(HWIF_VCMD_AXI_CLK_GATE_DISABLE          , 64 ,0x00000040,        6,        0,RW,"keep axi_clk always on when this bit is set to 1"),
+    VCMDREG(HWIF_VCMD_MASTER_OUT_CLK_GATE_DISABLE   , 64 ,0x00000020,        5,        0,RW,"keep master_out_clk(APB/AHB master) always on when this bit is set to 1"),
+    VCMDREG(HWIF_VCMD_CORE_CLK_GATE_DISABLE         , 64 ,0x00000010,        4,        0,RW,"keep core_clk always on when this bit is set to 1"),
+    VCMDREG(HWIF_VCMD_ABORT_MODE                    , 64 ,0x00000008,        3,        0,RW,"0:abort after finishing current cmdbuf command.1:abort immediately "),
+    VCMDREG(HWIF_VCMD_RESET_CORE                    , 64 ,0x00000004,        2,        0,RW,"sw write 1 to this bit will rset HW core logic when AXI/APB bus is idle."),
+    VCMDREG(HWIF_VCMD_RESET_ALL                     , 64 ,0x00000002,        1,        0,RW,"sw write 1 to this bit will rset HW immediately including all swregs and AXI/APB  bus logic"),
+    VCMDREG(HWIF_VCMD_START_TRIGGER                 , 64 ,0x00000001,        0,        0,RW,"0:abort previou task and stop hw. 1:trigger hw to fetch and execute commands."),
+    VCMDREG(HWIF_VCMD_IRQ_INTCMD                    , 68 ,0xffff0000,       16,        0,RW,"interrupt sources which are triggered by command buffer id.. Only for version 1.0.c"),
+    VCMDREG(HWIF_VCMD_IRQ_JMPP                      , 68 ,0x00000080,        7,        0,RW,"interrupt source which is triggered by JMP command when hw goes to PEND state."),
+    VCMDREG(HWIF_VCMD_IRQ_JMPD                      , 68 ,0x00000040,        6,        0,RW,"interrupt source which is triggered by JMP command directly."),
+    VCMDREG(HWIF_VCMD_IRQ_RESET                     , 68 ,0x00000020,        5,        0,RW,"interrupt source which is triggered by hw reset or sw_vcmd_reset_all."),
+    VCMDREG(HWIF_VCMD_IRQ_ABORT                     , 68 ,0x00000010,        4,        0,RW,"interrupt source which is triggered by abort operation."),
+    VCMDREG(HWIF_VCMD_IRQ_CMDERR                    , 68 ,0x00000008,        3,        0,RW,"interrupt source which is triggered when there is illegal command in cmdbuf"),
+    VCMDREG(HWIF_VCMD_IRQ_TIMEOUT                   , 68 ,0x00000004,        2,        0,RW,"interrupt source which is triggered when vcmd timeout."),
+    VCMDREG(HWIF_VCMD_IRQ_BUSERR                    , 68 ,0x00000002,        1,        0,RW,"interrupt source which is triggered when there is bus error."),
+    VCMDREG(HWIF_VCMD_IRQ_ENDCMD                    , 68 ,0x00000001,        0,        0,RW,"interrupt source which is triggered by END command."),
+    VCMDREG(HWIF_VCMD_IRQ_INTCMD_EN                 , 72 ,0xffff0000,       16,        0,RW,"interrupt sources which are triggered by command buffer id. Only for version 1.0.c"),
+    VCMDREG(HWIF_VCMD_IRQ_JMPP_EN                   , 72 ,0x00000080,        7,        0,RW,"interrupt enable for sw_vcmd_irq_jmpp"),
+    VCMDREG(HWIF_VCMD_IRQ_JMPD_EN                   , 72 ,0x00000040,        6,        0,RW,"interrupt enable for sw_vcmd_irq_jmpd"),
+    VCMDREG(HWIF_VCMD_IRQ_RESET_EN                  , 72 ,0x00000020,        5,        0,RW,"interrupt enable for sw_vcmd_irq_reset"),
+    VCMDREG(HWIF_VCMD_IRQ_ABORT_EN                  , 72 ,0x00000010,        4,        0,RW,"interrupt enable for sw_vcmd_irq_abort"),
+    VCMDREG(HWIF_VCMD_IRQ_CMDERR_EN                 , 72 ,0x00000008,        3,        0,RW,"interrupt enable for sw_vcmd_irq_cmderr"),
+    VCMDREG(HWIF_VCMD_IRQ_TIMEOUT_EN                , 72 ,0x00000004,        2,        0,RW,"interrupt enable for sw_vcmd_irq_timeout"),
+    VCMDREG(HWIF_VCMD_IRQ_BUSERR_EN                 , 72 ,0x00000002,        1,        0,RW,"interrupt enable for sw_vcmd_irq_buserr"),
+    VCMDREG(HWIF_VCMD_IRQ_ENDCMD_EN                 , 72 ,0x00000001,        0,        0,RW,"interrupt enable for sw_vcmd_irq_endcmd"),
+    VCMDREG(HWIF_VCMD_TIMEOUT_EN                    , 76 ,0x80000000,       31,        0,RW,"1:timeout work. 0: timeout do not work"),
+    VCMDREG(HWIF_VCMD_TIMEOUT_CYCLES                , 76 ,0x7fffffff,        0,        0,RW,"sw_vcmd_irq_timeout will be generated when timeout counter is equal to this value."),
+    VCMDREG(HWIF_VCMD_EXECUTING_CMD_ADDR            , 80 ,0xffffffff,        0,        0,RW,"the least 32 bits address of the executing command"),
+    VCMDREG(HWIF_VCMD_EXECUTING_CMD_ADDR_MSB        , 84 ,0xffffffff,        0,        0,RW,"the most  32 bits address of the executing command"),
+    VCMDREG(HWIF_VCMD_EXE_CMDBUF_LENGTH             , 88 ,0x0000ffff,        0,        0,RW,"the length of current command buffer in unit of 64bits."),
+    VCMDREG(HWIF_VCMD_CMD_SWAP                      , 92 ,0xf0000000,       28,        0,RW,"axi data swapping"),
+    VCMDREG(HWIF_VCMD_MAX_BURST_LEN                 , 92 ,0x00ff0000,       16,        0,RW,"max burst length which will be sent to axi bus"),
+    VCMDREG(HWIF_VCMD_AXI_ID_RD                     , 92 ,0x0000ff00,        8,        0,RW,"the arid which will be used on axi bus reading"),
+    VCMDREG(HWIF_VCMD_AXI_ID_WR                     , 92 ,0x000000ff,        0,        0,RW,"the awid which will be used on axi bus writing"),
+    VCMDREG(HWIF_VCMD_RDY_CMDBUF_COUNT              , 96 ,0xffffffff,        0,        0,RW,"sw increases this counter by 1 after one more command buffer was ready."),
+    VCMDREG(HWIF_VCMD_EXT_ABN_INT_SRC_VCD_MMU_GATE  , 100,0x10000000,       28,        0,RW,"external abnormal interrupt source from mmu of vcd gate."),
+    VCMDREG(HWIF_VCMD_EXT_ABN_INT_SRC_VCD_L2CACHE_GATE, 100,0x08000000,       27,        0,RW,"external abnormal interrupt source from l2cache of vcd gate."),
+    VCMDREG(HWIF_VCMD_EXT_ABN_INT_SRC_VCD_DEC400_GATE, 100,0x04000000,       26,        0,RW,"external abnormal interrupt source from dec400 of vcd gate."),
+    VCMDREG(HWIF_VCMD_EXT_ABN_INT_SRC_VCD_GATE      , 100,0x01000000,       24,        0,RW,"external abnormal interrupt source from vcd gate."),
+    VCMDREG(HWIF_VCMD_EXT_ABN_INT_SRC_CUTREE_MMU_GATE, 100,0x00200000,       21,        0,RW,"external abnormal interrupt source from mmu of cutree gate."),
+    VCMDREG(HWIF_VCMD_EXT_ABN_INT_SRC_VCE_MMU_GATE  , 100,0x00100000,       20,        0,RW,"external abnormal interrupt source from mmu of vce gate."),
+    VCMDREG(HWIF_VCMD_EXT_ABN_INT_SRC_VCE_L2CACHE_GATE, 100,0x00080000,       19,        0,RW,"external abnormal interrupt source from l2 cache of vce gate."),
+    VCMDREG(HWIF_VCMD_EXT_ABN_INT_SRC_VCE_DEC400_GATE, 100,0x00040000,       18,        0,RW,"external abnormal interrupt source from dec400 of vce gate."),
+    VCMDREG(HWIF_VCMD_EXT_ABN_INT_SRC_CUTREE_GATE   , 100,0x00020000,       17,        0,RW,"external abnormal interrupt source from cutree gate."),
+    VCMDREG(HWIF_VCMD_EXT_ABN_INT_SRC_VCE_GATE      , 100,0x00010000,       16,        0,RW,"external abnormal interrupt source from vce gate."),
+    VCMDREG(HWIF_VCMD_EXT_NORM_INT_SRC_VCD_MMU_GATE , 100,0x00000800,       11,        0,RW,"external normal interrupt source from mmu of vcd gate."),
+    VCMDREG(HWIF_VCMD_EXT_NORM_INT_SRC_VCD_L2CACHE_GATE, 100,0x00000400,       10,        0,RW,"external normal interrupt source from l2cache of vcd gate."),
+    VCMDREG(HWIF_VCMD_EXT_NORM_INT_SRC_VCD_DEC400_GATE, 100,0x00000200,        9,        0,RW,"external normal interrupt source from dec400 of vcd gate."),
+    VCMDREG(HWIF_VCMD_EXT_NORM_INT_SRC_VCD_GATE     , 100,0x00000100,        8,        0,RW,"external normal interrupt source from vcd gate."),
+    VCMDREG(HWIF_VCMD_EXT_NORM_INT_SRC_CUTREE_MMU_GATE, 100,0x00000020,        5,        0,RW,"external normal interrupt source from mmu of cutree gate."),
+    VCMDREG(HWIF_VCMD_EXT_NORM_INT_SRC_VCE_MMU_GATE , 100,0x00000010,        4,        0,RW,"external normal interrupt source from mmu of vce gate."),
+    VCMDREG(HWIF_VCMD_EXT_NORM_INT_SRC_VCE_L2CACHE_GATE, 100,0x00000008,        3,        0,RW,"external normal interrupt source from l2 cache of vce gate."),
+    VCMDREG(HWIF_VCMD_EXT_NORM_INT_SRC_VCE_DEC400_GATE, 100,0x00000004,        2,        0,RW,"external normal interrupt source from dec400 of vce gate."),
+    VCMDREG(HWIF_VCMD_EXT_NORM_INT_SRC_CUTREE_GATE  , 100,0x00000002,        1,        0,RW,"external normal interrupt source from cutree gate."),
+    VCMDREG(HWIF_VCMD_EXT_NORM_INT_SRC_VCE_GATE     , 100,0x00000001,        0,        0,RW,"external normal interrupt source from vce gate."),
+    VCMDREG(HWIF_VCMD_CMDBUF_EXECUTING_ID           , 104,0xffffffff,        0,        0,RW,"The ID of current executing command buffer.used after version 1.1.2."),

+ 148 - 0
linux/subsys_driver/vcmdswhwregisters.c

@@ -0,0 +1,148 @@
+/*
+ * Hantro Decoder device driver (kernel module)
+*
+* Copyright (C) 2020  VeriSilicon Microelectronics Co., Ltd.
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+*
+------------------------------------------------------------------------------*/
+
+/*------------------------------------------------------------------------------
+
+    Table of contents
+
+    1. Include headers
+    2. External compiler flags
+    3. Module defines
+
+------------------------------------------------------------------------------*/
+/*------------------------------------------------------------------------------
+    1. Include headers
+------------------------------------------------------------------------------*/
+#include <linux/io.h> /* for ioread32 and iowrite32 ... */
+#include "vcmdswhwregisters.h"
+
+
+/* NOTE: Don't use ',' in descriptions, because it is used as separator in csv
+ * parsing. */
+const regVcmdField_s asicVcmdRegisterDesc[] =
+{
+#include "vcmdregistertable.h"
+};
+
+/*------------------------------------------------------------------------------
+    2. External compiler flags
+--------------------------------------------------------------------------------
+
+--------------------------------------------------------------------------------
+    3. Module defines
+------------------------------------------------------------------------------*/
+
+/* Define this to print debug info for every register write.
+#define DEBUG_PRINT_REGS */
+
+/*******************************************************************************
+ Function name   : vcmd_read_reg
+ Description     : Retrive the content of a hadware register
+                    Note: The status register will be read after every MB
+                    so it may be needed to buffer it's content if reading
+                    the HW register is slow.
+ Return type     : u32
+ Argument        : u32 offset
+*******************************************************************************/
+u32 vcmd_read_reg(const void *hwregs, u32 offset)
+{
+    u32 val;
+
+    val =(u32) ioread32((void*)hwregs + offset);
+
+    PDEBUG("vcmd_read_reg 0x%02x --> %08x\n", offset, val);
+
+    return val;
+}
+
+/*******************************************************************************
+ Function name   : vcmd_write_reg
+ Description     : Set the content of a hadware register
+ Return type     : void
+ Argument        : u32 offset
+ Argument        : u32 val
+*******************************************************************************/
+void vcmd_write_reg(const void *hwregs, u32 offset, u32 val)
+{
+    iowrite32(val,(void*)hwregs + offset);
+
+    PDEBUG("vcmd_write_reg 0x%02x with value %08x\n", offset, val);
+}
+
+
+/*------------------------------------------------------------------------------
+
+    vcmd_write_register_value
+
+    Write a value into a defined register field (write will happens actually).
+
+------------------------------------------------------------------------------*/
+void vcmd_write_register_value(const void *hwregs,u32* reg_mirror,regVcmdName name, u32 value)
+{
+    const regVcmdField_s *field;
+    u32 regVal;
+
+    field = &asicVcmdRegisterDesc[name];
+
+#ifdef DEBUG_PRINT_REGS
+    PDEBUG("vcmd_write_register_value 0x%2x  0x%08x  Value: %10d  %s\n",
+            field->base, field->mask, value, field->description);
+#endif
+
+    /* Check that value fits in field */
+    PDEBUG("field->name == name=%d\n",field->name == name);
+    PDEBUG("((field->mask >> field->lsb) << field->lsb) == field->mask=%d\n",((field->mask >> field->lsb) << field->lsb) == field->mask);
+    PDEBUG("(field->mask >> field->lsb) >= value=%d\n",(field->mask >> field->lsb) >= value);
+    PDEBUG("field->base < ASIC_VCMD_SWREG_AMOUNT*4=%d\n",field->base < ASIC_VCMD_SWREG_AMOUNT*4);
+
+    /* Clear previous value of field in register */
+    regVal = reg_mirror[field->base/4] & ~(field->mask);
+
+    /* Put new value of field in register */
+    reg_mirror[field->base/4] = regVal | ((value << field->lsb) & field->mask);
+
+    /* write it into HW registers */
+    vcmd_write_reg(hwregs, field->base,reg_mirror[field->base/4]);
+}
+
+/*------------------------------------------------------------------------------
+
+    vcmd_get_register_value
+
+    Get an unsigned value from the ASIC registers
+
+------------------------------------------------------------------------------*/
+u32 vcmd_get_register_value(const void *hwregs, u32* reg_mirror,regVcmdName name)
+{
+  const regVcmdField_s *field;
+  u32 value;
+
+  field = &asicVcmdRegisterDesc[name];
+
+  PDEBUG("field->base < ASIC_VCMD_SWREG_AMOUNT * 4=%d\n",field->base < ASIC_VCMD_SWREG_AMOUNT * 4);
+
+  value = reg_mirror[field->base / 4] = vcmd_read_reg(hwregs, field->base);
+  value = (value & field->mask) >> field->lsb;
+
+  return value;
+}
+
+

+ 233 - 0
linux/subsys_driver/vcmdswhwregisters.h

@@ -0,0 +1,233 @@
+/****************************************************************************
+*
+*    The MIT License (MIT)
+*
+*    Copyright (c) 2014 - 2021 VERISILICON
+*
+*    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.
+*
+*****************************************************************************
+*
+*    The GPL License (GPL)
+*
+*    Copyright (C) 2014 - 2021 VERISILICON
+*
+*    This program is free software; you can redistribute it and/or
+*    modify it under the terms of the GNU General Public License
+*    as published by the Free Software Foundation; either version 2
+*    of the License, or (at your option) any later version.
+*
+*    This program is distributed in the hope that it will be useful,
+*    but WITHOUT ANY WARRANTY; without even the implied warranty of
+*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*    GNU General Public License for more details.
+*
+*    You should have received a copy of the GNU General Public License
+*    along with this program; if not, write to the Free Software Foundation,
+*    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+*    Note: This software is released under dual MIT and GPL licenses. A
+*    recipient may use this file under the terms of either the MIT license or
+*    GPL License. If you wish to use only one license not the other, you can
+*    indicate your decision by deleting one of the above license notices in your
+*    version of this file.
+*
+*****************************************************************************/
+
+/*------------------------------------------------------------------------------
+
+    Table of contents
+
+    1. Include headers
+    2. External compiler flags
+    3. Module defines
+
+------------------------------------------------------------------------------*/
+#ifndef VCMD_SWHWREGISTERS_H
+#define VCMD_SWHWREGISTERS_H
+
+/*------------------------------------------------------------------------------
+    1. Include headers
+------------------------------------------------------------------------------*/
+#ifdef __FREERTOS__
+#include "basetype.h"
+#include "io_tools.h"
+#elif defined(__linux__)
+#ifndef MODEL_SIMULATION
+#include <linux/ioctl.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#endif
+#endif
+
+#ifdef __FREERTOS__
+//addr_t has been defined in basetype.h //Now the FreeRTOS mem need to support 64bit env
+#elif defined(__linux__)
+typedef size_t    addr_t;
+#endif
+typedef addr_t    ptr_t;
+
+#undef PDEBUG   /* undef it, just in case */
+#ifdef REGISTER_DEBUG
+#  ifdef __KERNEL__
+    /* This one if debugging is on, and kernel space */
+#    define PDEBUG(fmt, args...) printk( KERN_INFO "memalloc: " fmt, ## args)
+#  else
+    /* This one for user space */
+#    define PDEBUG(fmt, args...) fprintf(stderr, fmt, ## args)
+#  endif
+#else
+#  define PDEBUG(fmt, ...)  /* not debugging: nothing */
+#endif
+
+/*------------------------------------------------------------------------------
+    2. External compiler flags
+--------------------------------------------------------------------------------
+
+--------------------------------------------------------------------------------
+    3. Module defines
+------------------------------------------------------------------------------*/
+
+#define ASIC_VCMD_SWREG_AMOUNT                  27
+#define VCMD_REGISTER_CONTROL_OFFSET            0X40
+#define VCMD_REGISTER_INT_STATUS_OFFSET         0X44
+#define VCMD_REGISTER_INT_CTL_OFFSET            0X48
+#define VCMD_REGISTER_EXT_INT_GATE_OFFSET       0X64
+
+/* HW Register field names */
+typedef enum
+{
+#include "vcmdregisterenum.h"
+  VcmdRegisterAmount
+} regVcmdName;
+
+/* HW Register field descriptions */
+typedef struct
+{
+  u32 name;               /* Register name and index  */
+  int base;               /* Register base address  */
+  u32 mask;               /* Bitmask for this field */
+  int lsb;                /* LSB for this field [31..0] */
+  int trace;              /* Enable/disable writing in swreg_params.trc */
+  int rw;                 /* 1=Read-only 2=Write-only 3=Read-Write */
+  char *description;      /* Field description */
+} regVcmdField_s;
+
+/* Flags for read-only, write-only and read-write */
+#define RO 1
+#define WO 2
+#define RW 3
+
+#define REGBASE(reg) (asicVcmdRegisterDesc[reg].base)
+
+/* Description field only needed for system model build. */
+#ifdef TEST_DATA
+#define VCMDREG(name, base, mask, lsb, trace, rw, desc) \
+        {name, base, mask, lsb, trace, rw, desc}
+#else
+#define VCMDREG(name, base, mask, lsb, trace, rw, desc) \
+        {name, base, mask, lsb, trace, rw, ""}
+#endif
+
+
+/*------------------------------------------------------------------------------
+    4. Function prototypes
+------------------------------------------------------------------------------*/
+extern const regVcmdField_s asicVcmdRegisterDesc[];
+
+/*------------------------------------------------------------------------------
+
+    EncAsicSetRegisterValue
+
+    Set a value into a defined register field
+
+------------------------------------------------------------------------------*/
+static inline void vcmd_set_register_mirror_value(u32 *reg_mirror, regVcmdName name, u32 value)
+{
+  const regVcmdField_s *field;
+  u32 regVal;
+
+  field = &asicVcmdRegisterDesc[name];
+
+#ifdef DEBUG_PRINT_REGS
+  printf("vcmd_set_register_mirror_value 0x%2x  0x%08x  Value: %10d  %s\n",
+         field->base, field->mask, value, field->description);
+#endif
+
+  /* Check that value fits in field */
+  PDEBUG("field->name == name=%d\n",field->name == name);
+  PDEBUG("((field->mask >> field->lsb) << field->lsb) == field->mask=%d\n",((field->mask >> field->lsb) << field->lsb) == field->mask);
+  PDEBUG("(field->mask >> field->lsb) >= value=%d\n",(field->mask >> field->lsb) >= value);
+  PDEBUG("field->base < ASIC_VCMD_SWREG_AMOUNT * 4=%d\n",field->base < ASIC_VCMD_SWREG_AMOUNT * 4);
+
+  /* Clear previous value of field in register */
+  regVal = reg_mirror[field->base / 4] & ~(field->mask);
+
+  /* Put new value of field in register */
+  reg_mirror[field->base / 4] = regVal | ((value << field->lsb) & field->mask);
+}
+static inline u32 vcmd_get_register_mirror_value(u32 *reg_mirror, regVcmdName name)
+{
+  const regVcmdField_s *field;
+  u32 regVal;
+
+  field = &asicVcmdRegisterDesc[name];
+
+
+  /* Check that value fits in field */
+  PDEBUG("field->name == name=%d\n",field->name == name);
+  PDEBUG("((field->mask >> field->lsb) << field->lsb) == field->mask=%d\n",((field->mask >> field->lsb) << field->lsb) == field->mask);
+  PDEBUG("field->base < ASIC_VCMD_SWREG_AMOUNT * 4=%d\n",field->base < ASIC_VCMD_SWREG_AMOUNT * 4);
+
+  regVal = reg_mirror[field->base / 4];
+  regVal = (regVal & field->mask) >> field->lsb;
+  
+#ifdef DEBUG_PRINT_REGS
+  PDEBUG("vcmd_get_register_mirror_value 0x%2x  0x%08x  Value: %10d  %s\n",
+         field->base, field->mask, regVal, field->description);
+#endif
+  return regVal;
+}
+
+u32 vcmd_read_reg(const void *hwregs, u32 offset);
+
+void vcmd_write_reg(const void *hwregs, u32 offset, u32 val);
+
+
+void vcmd_write_register_value(const void *hwregs,u32* reg_mirror,regVcmdName name, u32 value);
+u32 vcmd_get_register_value(const void *hwregs, u32* reg_mirror,regVcmdName name);
+
+#define vcmd_set_addr_register_value(reg_base, reg_mirror, name, value) do {\
+    if(sizeof(addr_t) == 8) {\
+      vcmd_write_register_value((reg_base), (reg_mirror),name, (u32)((addr_t)value));  \
+      vcmd_write_register_value((reg_base), (reg_mirror),name##_MSB, (u32)(((addr_t)value) >> 32));\
+    } else {\
+      vcmd_write_register_value((reg_base),(reg_mirror), name, (u32)((addr_t)value));\
+    }\
+}while (0)
+
+#define VCMDGetAddrRegisterValue(reg_base, reg_mirror,name)  \
+    ((sizeof(addr_t) == 8) ? (\
+     (((addr_t)vcmd_get_register_value((reg_base),(reg_mirror), name)) |  \
+     (((addr_t)vcmd_get_register_value((reg_base), (reg_mirror),name##_MSB)) << 32))\
+    ) : ((addr_t)vcmd_get_register_value((reg_base),(reg_mirror), (name))))
+
+#endif /* VCMD_SWHWREGISTERS_H */