├── .gitignore ├── .travis.yml ├── LICENSE.md ├── Makefile ├── README.md ├── adb-devprobe.sh ├── autoversion.sh ├── bin ├── fel-pio.bin ├── fel-pio.nm ├── fel-sdboot.sunxi ├── jtag-loop.sunxi ├── ramboot.scr ├── ramboot.uboot-sh └── uart0-helloworld-sdboot.sunxi ├── boot_head.S ├── boot_head.lds ├── bootinfo.c ├── common.h ├── fel-copy.c ├── fel-gpio ├── fel-pio.c ├── fel-pio.lds ├── fel-sdboot.S ├── fel-sdboot.lds ├── fel-to-spl-thunk.S ├── fel-to-spl-thunk.h ├── fel.c ├── fexc.c ├── fexc.h ├── include ├── list.h ├── portable_endian.h └── types.h ├── jtag-loop.S ├── jtag-loop.c ├── jtag-loop.lds ├── meminfo.c ├── nand-common.h ├── nand-image-builder.c ├── nand-part-a10.h ├── nand-part-a20.h ├── nand-part-main.c ├── nand-part.c ├── phoenix_info.c ├── pio.c ├── progress.c ├── progress.h ├── script.c ├── script.h ├── script_bin.c ├── script_bin.h ├── script_extractor.c ├── script_fex.c ├── script_fex.h ├── script_uboot.c ├── script_uboot.h ├── uart0-helloworld-sdboot.c └── uart0-helloworld-sdboot.lds /.gitignore: -------------------------------------------------------------------------------- 1 | bin2fex 2 | fex2bin 3 | sunxi-bootinfo 4 | sunxi-fel 5 | sunxi-fexc 6 | sunxi-nand-part 7 | sunxi-pio 8 | version.h 9 | *.o 10 | *.swp 11 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # use container-based infrastructure 2 | sudo: false 3 | 4 | language: c 5 | 6 | # treat all warnings as errors, fake cross-toolchain (build everything on host) 7 | env: 8 | - CFLAGS=-Werror CROSS_COMPILE="" 9 | 10 | os: 11 | - linux 12 | - osx 13 | compiler: 14 | - gcc 15 | - clang 16 | 17 | # OSX uses Apple's flavor of clang anyway, so there's no point in trying "gcc". 18 | # This excludes the "gcc" compiler from the build matrix for OSX: 19 | matrix: 20 | exclude: 21 | - os: osx 22 | compiler: gcc 23 | 24 | # take care of the libusb dependency for Linux 25 | addons: 26 | apt: 27 | packages: 28 | - libusb-1.0-0-dev 29 | 30 | # take care of the libusb dependency for Mac OS X; select make/install target 31 | before_install: 32 | - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then 33 | brew update; 34 | brew install libusb; 35 | export TARGET=tools; 36 | else 37 | export TARGET=all; 38 | fi 39 | 40 | # build using the Makefile 41 | script: 42 | - make ${TARGET} && make misc 43 | 44 | # run/simulate a test install 45 | after_success: 46 | - make install-${TARGET} install-misc DESTDIR=/tmp PREFIX=/sunxi-tools 47 | 48 | # turn off email notifications 49 | notifications: 50 | - email: false 51 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | ### GNU GENERAL PUBLIC LICENSE 2 | 3 | Version 2, June 1991 4 | 5 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 6 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA 7 | 8 | Everyone is permitted to copy and distribute verbatim copies 9 | of this license document, but changing it is not allowed. 10 | 11 | ### Preamble 12 | 13 | The licenses for most software are designed to take away your freedom 14 | to share and change it. By contrast, the GNU General Public License is 15 | intended to guarantee your freedom to share and change free 16 | software--to make sure the software is free for all its users. This 17 | General Public License applies to most of the Free Software 18 | Foundation's software and to any other program whose authors commit to 19 | using it. (Some other Free Software Foundation software is covered by 20 | the GNU Lesser General Public License instead.) You can apply it to 21 | your programs, too. 22 | 23 | When we speak of free software, we are referring to freedom, not 24 | price. Our General Public Licenses are designed to make sure that you 25 | have the freedom to distribute copies of free software (and charge for 26 | this service if you wish), that you receive source code or can get it 27 | if you want it, that you can change the software or use pieces of it 28 | in new free programs; and that you know you can do these things. 29 | 30 | To protect your rights, we need to make restrictions that forbid 31 | anyone to deny you these rights or to ask you to surrender the rights. 32 | These restrictions translate to certain responsibilities for you if 33 | you distribute copies of the software, or if you modify it. 34 | 35 | For example, if you distribute copies of such a program, whether 36 | gratis or for a fee, you must give the recipients all the rights that 37 | you have. You must make sure that they, too, receive or can get the 38 | source code. And you must show them these terms so they know their 39 | rights. 40 | 41 | We protect your rights with two steps: (1) copyright the software, and 42 | (2) offer you this license which gives you legal permission to copy, 43 | distribute and/or modify the software. 44 | 45 | Also, for each author's protection and ours, we want to make certain 46 | that everyone understands that there is no warranty for this free 47 | software. If the software is modified by someone else and passed on, 48 | we want its recipients to know that what they have is not the 49 | original, so that any problems introduced by others will not reflect 50 | on the original authors' reputations. 51 | 52 | Finally, any free program is threatened constantly by software 53 | patents. We wish to avoid the danger that redistributors of a free 54 | program will individually obtain patent licenses, in effect making the 55 | program proprietary. To prevent this, we have made it clear that any 56 | patent must be licensed for everyone's free use or not licensed at 57 | all. 58 | 59 | The precise terms and conditions for copying, distribution and 60 | modification follow. 61 | 62 | ### TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 63 | 64 | **0.** This License applies to any program or other work which 65 | contains a notice placed by the copyright holder saying it may be 66 | distributed under the terms of this General Public License. The 67 | "Program", below, refers to any such program or work, and a "work 68 | based on the Program" means either the Program or any derivative work 69 | under copyright law: that is to say, a work containing the Program or 70 | a portion of it, either verbatim or with modifications and/or 71 | translated into another language. (Hereinafter, translation is 72 | included without limitation in the term "modification".) Each licensee 73 | is addressed as "you". 74 | 75 | Activities other than copying, distribution and modification are not 76 | covered by this License; they are outside its scope. The act of 77 | running the Program is not restricted, and the output from the Program 78 | is covered only if its contents constitute a work based on the Program 79 | (independent of having been made by running the Program). Whether that 80 | is true depends on what the Program does. 81 | 82 | **1.** You may copy and distribute verbatim copies of the Program's 83 | source code as you receive it, in any medium, provided that you 84 | conspicuously and appropriately publish on each copy an appropriate 85 | copyright notice and disclaimer of warranty; keep intact all the 86 | notices that refer to this License and to the absence of any warranty; 87 | and give any other recipients of the Program a copy of this License 88 | along with the Program. 89 | 90 | You may charge a fee for the physical act of transferring a copy, and 91 | you may at your option offer warranty protection in exchange for a 92 | fee. 93 | 94 | **2.** You may modify your copy or copies of the Program or any 95 | portion of it, thus forming a work based on the Program, and copy and 96 | distribute such modifications or work under the terms of Section 1 97 | above, provided that you also meet all of these conditions: 98 | 99 | 100 | **a)** You must cause the modified files to carry prominent notices 101 | stating that you changed the files and the date of any change. 102 | 103 | 104 | **b)** You must cause any work that you distribute or publish, that in 105 | whole or in part contains or is derived from the Program or any part 106 | thereof, to be licensed as a whole at no charge to all third parties 107 | under the terms of this License. 108 | 109 | 110 | **c)** If the modified program normally reads commands interactively 111 | when run, you must cause it, when started running for such interactive 112 | use in the most ordinary way, to print or display an announcement 113 | including an appropriate copyright notice and a notice that there is 114 | no warranty (or else, saying that you provide a warranty) and that 115 | users may redistribute the program under these conditions, and telling 116 | the user how to view a copy of this License. (Exception: if the 117 | Program itself is interactive but does not normally print such an 118 | announcement, your work based on the Program is not required to print 119 | an announcement.) 120 | 121 | These requirements apply to the modified work as a whole. If 122 | identifiable sections of that work are not derived from the Program, 123 | and can be reasonably considered independent and separate works in 124 | themselves, then this License, and its terms, do not apply to those 125 | sections when you distribute them as separate works. But when you 126 | distribute the same sections as part of a whole which is a work based 127 | on the Program, the distribution of the whole must be on the terms of 128 | this License, whose permissions for other licensees extend to the 129 | entire whole, and thus to each and every part regardless of who wrote 130 | it. 131 | 132 | Thus, it is not the intent of this section to claim rights or contest 133 | your rights to work written entirely by you; rather, the intent is to 134 | exercise the right to control the distribution of derivative or 135 | collective works based on the Program. 136 | 137 | In addition, mere aggregation of another work not based on the Program 138 | with the Program (or with a work based on the Program) on a volume of 139 | a storage or distribution medium does not bring the other work under 140 | the scope of this License. 141 | 142 | **3.** You may copy and distribute the Program (or a work based on it, 143 | under Section 2) in object code or executable form under the terms of 144 | Sections 1 and 2 above provided that you also do one of the following: 145 | 146 | 147 | **a)** Accompany it with the complete corresponding machine-readable 148 | source code, which must be distributed under the terms of Sections 1 149 | and 2 above on a medium customarily used for software interchange; or, 150 | 151 | 152 | **b)** Accompany it with a written offer, valid for at least three 153 | years, to give any third party, for a charge no more than your cost of 154 | physically performing source distribution, a complete machine-readable 155 | copy of the corresponding source code, to be distributed under the 156 | terms of Sections 1 and 2 above on a medium customarily used for 157 | software interchange; or, 158 | 159 | 160 | **c)** Accompany it with the information you received as to the offer 161 | to distribute corresponding source code. (This alternative is allowed 162 | only for noncommercial distribution and only if you received the 163 | program in object code or executable form with such an offer, in 164 | accord with Subsection b above.) 165 | 166 | The source code for a work means the preferred form of the work for 167 | making modifications to it. For an executable work, complete source 168 | code means all the source code for all modules it contains, plus any 169 | associated interface definition files, plus the scripts used to 170 | control compilation and installation of the executable. However, as a 171 | special exception, the source code distributed need not include 172 | anything that is normally distributed (in either source or binary 173 | form) with the major components (compiler, kernel, and so on) of the 174 | operating system on which the executable runs, unless that component 175 | itself accompanies the executable. 176 | 177 | If distribution of executable or object code is made by offering 178 | access to copy from a designated place, then offering equivalent 179 | access to copy the source code from the same place counts as 180 | distribution of the source code, even though third parties are not 181 | compelled to copy the source along with the object code. 182 | 183 | **4.** You may not copy, modify, sublicense, or distribute the Program 184 | except as expressly provided under this License. Any attempt otherwise 185 | to copy, modify, sublicense or distribute the Program is void, and 186 | will automatically terminate your rights under this License. However, 187 | parties who have received copies, or rights, from you under this 188 | License will not have their licenses terminated so long as such 189 | parties remain in full compliance. 190 | 191 | **5.** You are not required to accept this License, since you have not 192 | signed it. However, nothing else grants you permission to modify or 193 | distribute the Program or its derivative works. These actions are 194 | prohibited by law if you do not accept this License. Therefore, by 195 | modifying or distributing the Program (or any work based on the 196 | Program), you indicate your acceptance of this License to do so, and 197 | all its terms and conditions for copying, distributing or modifying 198 | the Program or works based on it. 199 | 200 | **6.** Each time you redistribute the Program (or any work based on 201 | the Program), the recipient automatically receives a license from the 202 | original licensor to copy, distribute or modify the Program subject to 203 | these terms and conditions. You may not impose any further 204 | restrictions on the recipients' exercise of the rights granted herein. 205 | You are not responsible for enforcing compliance by third parties to 206 | this License. 207 | 208 | **7.** If, as a consequence of a court judgment or allegation of 209 | patent infringement or for any other reason (not limited to patent 210 | issues), conditions are imposed on you (whether by court order, 211 | agreement or otherwise) that contradict the conditions of this 212 | License, they do not excuse you from the conditions of this License. 213 | If you cannot distribute so as to satisfy simultaneously your 214 | obligations under this License and any other pertinent obligations, 215 | then as a consequence you may not distribute the Program at all. For 216 | example, if a patent license would not permit royalty-free 217 | redistribution of the Program by all those who receive copies directly 218 | or indirectly through you, then the only way you could satisfy both it 219 | and this License would be to refrain entirely from distribution of the 220 | Program. 221 | 222 | If any portion of this section is held invalid or unenforceable under 223 | any particular circumstance, the balance of the section is intended to 224 | apply and the section as a whole is intended to apply in other 225 | circumstances. 226 | 227 | It is not the purpose of this section to induce you to infringe any 228 | patents or other property right claims or to contest validity of any 229 | such claims; this section has the sole purpose of protecting the 230 | integrity of the free software distribution system, which is 231 | implemented by public license practices. Many people have made 232 | generous contributions to the wide range of software distributed 233 | through that system in reliance on consistent application of that 234 | system; it is up to the author/donor to decide if he or she is willing 235 | to distribute software through any other system and a licensee cannot 236 | impose that choice. 237 | 238 | This section is intended to make thoroughly clear what is believed to 239 | be a consequence of the rest of this License. 240 | 241 | **8.** If the distribution and/or use of the Program is restricted in 242 | certain countries either by patents or by copyrighted interfaces, the 243 | original copyright holder who places the Program under this License 244 | may add an explicit geographical distribution limitation excluding 245 | those countries, so that distribution is permitted only in or among 246 | countries not thus excluded. In such case, this License incorporates 247 | the limitation as if written in the body of this License. 248 | 249 | **9.** The Free Software Foundation may publish revised and/or new 250 | versions of the General Public License from time to time. Such new 251 | versions will be similar in spirit to the present version, but may 252 | differ in detail to address new problems or concerns. 253 | 254 | Each version is given a distinguishing version number. If the Program 255 | specifies a version number of this License which applies to it and 256 | "any later version", you have the option of following the terms and 257 | conditions either of that version or of any later version published by 258 | the Free Software Foundation. If the Program does not specify a 259 | version number of this License, you may choose any version ever 260 | published by the Free Software Foundation. 261 | 262 | **10.** If you wish to incorporate parts of the Program into other 263 | free programs whose distribution conditions are different, write to 264 | the author to ask for permission. For software which is copyrighted by 265 | the Free Software Foundation, write to the Free Software Foundation; 266 | we sometimes make exceptions for this. Our decision will be guided by 267 | the two goals of preserving the free status of all derivatives of our 268 | free software and of promoting the sharing and reuse of software 269 | generally. 270 | 271 | **NO WARRANTY** 272 | 273 | **11.** BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO 274 | WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. 275 | EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR 276 | OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY 277 | KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE 278 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 279 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE 280 | PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME 281 | THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 282 | 283 | **12.** IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN 284 | WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY 285 | AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU 286 | FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR 287 | CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE 288 | PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING 289 | RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A 290 | FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF 291 | SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 292 | DAMAGES. 293 | 294 | ### END OF TERMS AND CONDITIONS 295 | 296 | ### How to Apply These Terms to Your New Programs 297 | 298 | If you develop a new program, and you want it to be of the greatest 299 | possible use to the public, the best way to achieve this is to make it 300 | free software which everyone can redistribute and change under these 301 | terms. 302 | 303 | To do so, attach the following notices to the program. It is safest to 304 | attach them to the start of each source file to most effectively 305 | convey the exclusion of warranty; and each file should have at least 306 | the "copyright" line and a pointer to where the full notice is found. 307 | 308 | one line to give the program's name and an idea of what it does. 309 | Copyright (C) yyyy name of author 310 | 311 | This program is free software; you can redistribute it and/or 312 | modify it under the terms of the GNU General Public License 313 | as published by the Free Software Foundation; either version 2 314 | of the License, or (at your option) any later version. 315 | 316 | This program is distributed in the hope that it will be useful, 317 | but WITHOUT ANY WARRANTY; without even the implied warranty of 318 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 319 | GNU General Public License for more details. 320 | 321 | You should have received a copy of the GNU General Public License 322 | along with this program; if not, write to the Free Software 323 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 324 | 325 | Also add information on how to contact you by electronic and paper 326 | mail. 327 | 328 | If the program is interactive, make it output a short notice like this 329 | when it starts in an interactive mode: 330 | 331 | Gnomovision version 69, Copyright (C) year name of author 332 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details 333 | type `show w'. This is free software, and you are welcome 334 | to redistribute it under certain conditions; type `show c' 335 | for details. 336 | 337 | The hypothetical commands \`show w' and \`show c' should show the 338 | appropriate parts of the General Public License. Of course, the 339 | commands you use may be called something other than \`show w' and 340 | \`show c'; they could even be mouse-clicks or menu items--whatever 341 | suits your program. 342 | 343 | You should also get your employer (if you work as a programmer) or 344 | your school, if any, to sign a "copyright disclaimer" for the program, 345 | if necessary. Here is a sample; alter the names: 346 | 347 | Yoyodyne, Inc., hereby disclaims all copyright 348 | interest in the program `Gnomovision' 349 | (which makes passes at compilers) written 350 | by James Hacker. 351 | 352 | signature of Ty Coon, 1 April 1989 353 | Ty Coon, President of Vice 354 | 355 | This General Public License does not permit incorporating your program 356 | into proprietary programs. If your program is a subroutine library, 357 | you may consider it more useful to permit linking proprietary 358 | applications with the library. If this is what you want to do, use the 359 | [GNU Lesser General Public 360 | License](http://www.gnu.org/licenses/lgpl.html) instead of this 361 | License. -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2012 Alejandro Mery 2 | # Copyright (C) 2012,2013 Henrik Nordstrom 3 | # Copyright (C) 2013 Patrick Wood 4 | # Copyright (C) 2013 Pat Wood 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 2 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | 19 | CC ?= gcc 20 | DEFAULT_CFLAGS := -g -O0 -Wall -Wextra -std=c99 21 | 22 | DEFAULT_CFLAGS += -D_POSIX_C_SOURCE=200112L 23 | # Define _BSD_SOURCE, necessary to expose all endian conversions properly. 24 | # See http://linux.die.net/man/3/endian 25 | DEFAULT_CFLAGS += -D_BSD_SOURCE 26 | # glibc 2.20+ also requires _DEFAULT_SOURCE 27 | DEFAULT_CFLAGS += -D_DEFAULT_SOURCE 28 | ifeq (NetBSD,$(OS)) 29 | # add explicit _NETBSD_SOURCE, see https://github.com/linux-sunxi/sunxi-tools/pull/22 30 | DEFAULT_CFLAGS += -D_NETBSD_SOURCE 31 | endif 32 | 33 | DEFAULT_CFLAGS += -Iinclude/ 34 | 35 | # Tools useful on host and target 36 | TOOLS = sunxi-fexc sunxi-bootinfo sunxi-fel sunxi-nand-part 37 | 38 | # Symlinks to sunxi-fexc 39 | FEXC_LINKS = bin2fex fex2bin 40 | 41 | # Tools which are only useful on the target 42 | TARGET_TOOLS = sunxi-meminfo sunxi-pio 43 | 44 | # Misc tools (of more "exotic" nature) not part of our default build / install 45 | MISC_TOOLS = phoenix_info sunxi-nand-image-builder 46 | 47 | # ARM binaries and images 48 | # Note: To use this target, set/adjust CROSS_COMPILE and MKSUNXIBOOT if needed 49 | BINFILES = fel-pio.bin jtag-loop.sunxi fel-sdboot.sunxi uart0-helloworld-sdboot.sunxi 50 | 51 | CROSS_COMPILE ?= arm-none-eabi- 52 | CROSS_CC ?= $(CROSS_COMPILE)gcc 53 | MKSUNXIBOOT ?= mksunxiboot 54 | 55 | DESTDIR ?= 56 | PREFIX ?= /usr/local 57 | BINDIR ?= $(PREFIX)/bin 58 | 59 | .PHONY: all clean tools target-tools install install-tools install-target-tools 60 | 61 | tools: $(TOOLS) $(FEXC_LINKS) 62 | target-tools: $(TARGET_TOOLS) 63 | 64 | all: tools target-tools 65 | 66 | misc: $(MISC_TOOLS) 67 | 68 | binfiles: $(BINFILES) 69 | 70 | install: install-tools 71 | install-all: install-tools install-target-tools 72 | 73 | install-tools: $(TOOLS) 74 | install -d $(DESTDIR)$(BINDIR) 75 | @set -ex ; for t in $^ ; do \ 76 | install -m0755 $$t $(DESTDIR)$(BINDIR)/$$t ; \ 77 | done 78 | @set -ex ; for l in $(FEXC_LINKS) ; do \ 79 | ln -nfs sunxi-fexc $(DESTDIR)$(BINDIR)/$$l ; \ 80 | done 81 | 82 | install-target-tools: $(TARGET_TOOLS) 83 | install -d $(DESTDIR)$(BINDIR) 84 | @set -ex ; for t in $^ ; do \ 85 | install -m0755 $$t $(DESTDIR)$(BINDIR)/$$t ; \ 86 | done 87 | 88 | install-misc: $(MISC_TOOLS) 89 | install -d $(DESTDIR)$(BINDIR) 90 | @set -ex ; for t in $^ ; do \ 91 | install -m0755 $$t $(DESTDIR)$(BINDIR)/$$t ; \ 92 | done 93 | 94 | 95 | clean: 96 | @rm -vf $(TOOLS) $(FEXC_LINKS) $(TARGET_TOOLS) $(MISC_TOOLS) 97 | @rm -vf version.h *.o *.elf *.sunxi *.bin *.nm *.orig 98 | 99 | $(TOOLS) $(TARGET_TOOLS) $(MISC_TOOLS): Makefile common.h version.h 100 | 101 | fex2bin bin2fex: sunxi-fexc 102 | ln -nsf $< $@ 103 | 104 | sunxi-fexc: fexc.h script.h script.c \ 105 | script_uboot.h script_uboot.c \ 106 | script_bin.h script_bin.c \ 107 | script_fex.h script_fex.c 108 | 109 | LIBUSB = libusb-1.0 110 | LIBUSB_CFLAGS ?= `pkg-config --cflags $(LIBUSB)` 111 | LIBUSB_LIBS ?= `pkg-config --libs $(LIBUSB)` 112 | ifeq ($(OS),Windows_NT) 113 | # Windows lacks mman.h / mmap() 114 | DEFAULT_CFLAGS += -DNO_MMAP 115 | # portable_endian.h relies on winsock2 116 | LIBS += -lws2_32 117 | endif 118 | 119 | HOST_CFLAGS = $(DEFAULT_CFLAGS) $(CFLAGS) 120 | 121 | sunxi-fel: fel.c fel-to-spl-thunk.h progress.c progress.h 122 | $(CC) $(HOST_CFLAGS) $(LIBUSB_CFLAGS) $(LDFLAGS) -o $@ $(filter %.c,$^) $(LIBS) $(LIBUSB_LIBS) 123 | 124 | sunxi-nand-part: nand-part-main.c nand-part.c nand-part-a10.h nand-part-a20.h 125 | $(CC) $(HOST_CFLAGS) -c -o nand-part-main.o nand-part-main.c 126 | $(CC) $(HOST_CFLAGS) -c -o nand-part-a10.o nand-part.c -D A10 127 | $(CC) $(HOST_CFLAGS) -c -o nand-part-a20.o nand-part.c -D A20 128 | $(CC) $(LDFLAGS) -o $@ nand-part-main.o nand-part-a10.o nand-part-a20.o $(LIBS) 129 | 130 | sunxi-%: %.c 131 | $(CC) $(HOST_CFLAGS) $(LDFLAGS) -o $@ $(filter %.c,$^) $(LIBS) 132 | phoenix_info: phoenix_info.c 133 | $(CC) $(HOST_CFLAGS) $(LDFLAGS) -o $@ $< $(LIBS) 134 | 135 | %.bin: %.elf 136 | $(CROSS_COMPILE)objcopy -O binary $< $@ 137 | 138 | %.sunxi: %.bin 139 | $(MKSUNXIBOOT) $< $@ 140 | 141 | fel-pio.bin: fel-pio.elf fel-pio.nm 142 | 143 | ARM_ELF_FLAGS = -Os -marm -fpic -Wall 144 | ARM_ELF_FLAGS += -fno-common -fno-builtin -ffreestanding -nostdinc -fno-strict-aliasing 145 | ARM_ELF_FLAGS += -mno-thumb-interwork -fno-stack-protector -fno-toplevel-reorder 146 | ARM_ELF_FLAGS += -Wstrict-prototypes -Wno-format-nonliteral -Wno-format-security 147 | 148 | fel-pio.elf: fel-pio.c fel-pio.lds 149 | $(CROSS_CC) -g $(ARM_ELF_FLAGS) $< -nostdlib -o $@ -T fel-pio.lds 150 | 151 | fel-pio.nm: fel-pio.elf 152 | $(CROSS_COMPILE)nm $< | grep -v " _" >$@ 153 | 154 | jtag-loop.elf: jtag-loop.c jtag-loop.lds 155 | $(CROSS_CC) -g $(ARM_ELF_FLAGS) $< -nostdlib -o $@ -T jtag-loop.lds -Wl,-N 156 | 157 | fel-sdboot.elf: fel-sdboot.S fel-sdboot.lds 158 | $(CROSS_CC) -g $(ARM_ELF_FLAGS) $< -nostdlib -o $@ -T fel-sdboot.lds -Wl,-N 159 | 160 | uart0-helloworld-sdboot.elf: uart0-helloworld-sdboot.c uart0-helloworld-sdboot.lds 161 | $(CROSS_CC) -g $(ARM_ELF_FLAGS) $< -nostdlib -o $@ -T uart0-helloworld-sdboot.lds -Wl,-N 162 | 163 | boot_head_sun3i.elf: boot_head.S boot_head.lds 164 | $(CROSS_CC) -g $(ARM_ELF_FLAGS) $< -nostdlib -o $@ -T boot_head.lds -Wl,-N -DMACHID=0x1094 165 | 166 | boot_head_sun4i.elf: boot_head.S boot_head.lds 167 | $(CROSS_CC) -g $(ARM_ELF_FLAGS) $< -nostdlib -o $@ -T boot_head.lds -Wl,-N -DMACHID=0x1008 168 | 169 | boot_head_sun5i.elf: boot_head.S boot_head.lds 170 | $(CROSS_CC) -g $(ARM_ELF_FLAGS) $< -nostdlib -o $@ -T boot_head.lds -Wl,-N -DMACHID=0x102A 171 | 172 | sunxi-bootinfo: bootinfo.c 173 | 174 | # target tools 175 | TARGET_CFLAGS = $(DEFAULT_CFLAGS) -static $(CFLAGS) 176 | sunxi-pio: pio.c 177 | $(CROSS_CC) $(TARGET_CFLAGS) -o $@ $< 178 | sunxi-meminfo: meminfo.c 179 | $(CROSS_CC) $(TARGET_CFLAGS) -o $@ $< 180 | sunxi-script_extractor: script_extractor.c 181 | $(CROSS_CC) $(TARGET_CFLAGS) -o $@ $< 182 | 183 | version.h: 184 | @./autoversion.sh > $@ 185 | 186 | .gitignore: Makefile 187 | @for x in $(TOOLS) $(FEXC_LINKS) $(TARGET_TOOLS) version.h '*.o' '*.swp'; do \ 188 | echo "$$x"; \ 189 | done | sort -V > $@ 190 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # sunxi-tools 2 | [![License](http://img.shields.io/badge/License-GPL-green.svg)](LICENSE.md) 3 | [![Build Status](https://travis-ci.org/linux-sunxi/sunxi-tools.svg?branch=master)](https://travis-ci.org/linux-sunxi/sunxi-tools) 4 | [![Releases](https://img.shields.io/github/release/linux-sunxi/sunxi-tools.svg)](https://github.com/linux-sunxi/sunxi-tools/releases) 5 | 6 | Copyright (C) 2012 Alejandro Mery 7 |
For a full list of contributors, see 8 | [this link](https://github.com/linux-sunxi/sunxi-tools/contributors) 9 | or use the command `git shortlog -se --no-merges`. 10 | 11 | Tools to help hacking Allwinner A10 (aka sun4i) based devices and 12 | its successors ([sunxi][]), that's why the 'x' in the package name. 13 | 14 | ### sunxi-fexc 15 | `.fex` file (de)compiler 16 | 17 | Usage: ./sunxi-fexc [-vq] [-I ] [-O ] [ []] 18 | 19 | infmt: fex, bin (default:fex) 20 | outfmt: fex, bin (default:bin) 21 | 22 | ### bin2fex 23 | compatibility shortcut to call `sunxi-fexc` to decompile a _script.bin_ 24 | blob back into `.fex` format used by Allwinner's SDK to configure 25 | the boards. 26 | 27 | ### fex2bin 28 | compatiblity shortcut to call `sunxi-fexc` to compile a `.fex` file 29 | into the binary form used by the legacy 3.4 kernel ("linux‑sunxi"). 30 | 31 | ### sunxi-fel 32 | script interface for talking to the FEL USB handler built in to 33 | the CPU. You activate [FEL mode] by pushing the _uboot_ / _recovery_ 34 | button at poweron. See http://linux-sunxi.org/FEL/USBBoot for 35 | a detailed usage guide. 36 | 37 | ### fel-gpio 38 | Simple wrapper (script) around `fel-pio` and `sunxi-fel` 39 | to allow GPIO manipulations via FEL 40 | 41 | ### fel-sdboot 42 | ARM native sdcard bootloader forcing the device into FEL mode 43 | 44 | ### uart0-helloworld-sdboot 45 | ARM native sdcard bootloader, which is only printing a short "hello" 46 | message to the UART0 serial console. Because it relies on runtime 47 | SoC type detection, this single image is bootable on a wide range of 48 | Allwinner devices and can be used for testing. Additionally, it may 49 | serve as a template/example for developing simple bare metal code 50 | (LED blinking and other similar GPIO related things). 51 | 52 | ### fel-pio 53 | ARM native helper (binary) for `fel-gpio` 54 | 55 | ### sunxi-pio 56 | Manipulate PIO register dumps 57 | 58 | ### sunxi-nand-part 59 | Tool for manipulating Allwinner NAND partition tables 60 | 61 | ### sunxi-nand-image-builder 62 | Tool used to create raw NAND images (including boot0 images) 63 | 64 | ### jtag-loop.sunxi 65 | ARM native boot helper to force the SD port into JTAG and then stop, 66 | to ease debugging of bootloaders. 67 | 68 | ### sunxi-bootinfo 69 | Dump information from Allwinner boot files (_boot0_ / _boot1_) 70 | 71 | --type=sd include SD boot info 72 | --type=nand include NAND boot info (not implemented) 73 | 74 | ### phoenix_info 75 | gives information about a phoenix image created by the 76 | phoenixcard utility and optionally extracts the embedded boot 77 | code & firmware file from their hidden partitions. 78 | 79 | ### sunxi-meminfo 80 | Tool for reading DRAM settings from registers. Compiled as a 81 | static binary for use on android and other OSes. 82 | To build this, get a toolchain and run: 83 | 84 | make CROSS_COMPILE=arm-linux-gnueabihf- sunxi-meminfo 85 | 86 | ### sunxi-script_extractor 87 | A simple tool, which can be executed on a rooted Android device 88 | to dump the _script.bin_ blob from RAM via reading _/dev/mem_. 89 | To build this, get a toolchain and run: 90 | 91 | make CROSS_COMPILE=arm-linux-gnueabihf- sunxi-script_extractor 92 | --- 93 | 94 | ## Building 95 | 96 | Compilation requires the development version of *libusb-1.0* (include header 97 | and library) to be installed for `sunxi-fel`. Unless you explicitly pass 98 | *LIBUSB_CFLAGS* and *LIBUSB_LIBS* to the make utility, `pkg-config` is also 99 | needed. 100 | 101 | Available build targets: 102 | 103 | * `make tools` 104 | builds tools that are useful on the host. This is what most people will want, 105 | and our default target (when simply using `make`). 106 | 107 | * `make target-tools` 108 | builds tools that are intended for the target (Allwinner SoC), using a 109 | cross-compiler. The toolchain prefix *CROSS_COMPILE* defaults to `arm-none-eabi-`, 110 | adjust it if needed. 111 |
_Hint:_ When compiling 'natively' on the target platform you may 112 | simply use an empty toolchain prefix here (`make target-tools CROSS_COMPILE=` 113 | or `make all CROSS_COMPILE=`). 114 | 115 | * `make all` 116 | builds both *tools* and *target-tools*. 117 | 118 | * `make install-tools` 119 | builds *tools* and then copies/installs them to a filesystem location. The 120 | destination is affected by settings for `DESTDIR`, `PREFIX` and possibly 121 | `BINDIR`. For details, please refer to the *Makefile*. 122 | You may use `make install` as a shortcut for this. 123 | 124 | * `make install-target-tools` 125 | builds *target-tools* and then copies/installs them to a filesystem location 126 | selected by `DESTDIR`, `PREFIX` and possibly `BINDIR` - see `make install-tools` 127 | above. 128 | 129 | * `make install-all` 130 | builds and installs both *tools* and *target-tools*. 131 | 132 | * `make misc` 133 | builds miscellaneous (host) utilities that are not part of our 'standard' suite. 134 | Currently this means `phoenix_info` and `sunxi-nand-image-builder`. 135 | 136 | * `make install-misc` 137 | builds *misc* and installs the resulting binaries. 138 | 139 | ## License 140 | This software is licensed under the terms of GPLv2+ as defined by the 141 | Free Software Foundation, details can be read in the [LICENSE.md](LICENSE.md) 142 | file. 143 | 144 | [sunxi]: http://linux-sunxi.org 145 | [fel mode]: http://linux-sunxi.org/FEL 146 | -------------------------------------------------------------------------------- /adb-devprobe.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright (C) 2012 Henrik Nordstrom 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in 13 | # all copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | # THE SOFTWARE. 22 | 23 | adb shell insmod /vendor/modules/sunxi-dbgreg.ko >/dev/null 24 | 25 | dump_io() 26 | { 27 | module=$1 28 | addr=$2 29 | len=$3 30 | 31 | for ((i = 0; i < len; i+=4)) { 32 | printf "%x %s " $((addr + i)) $module 33 | adb shell "echo `printf %x $((addr + i))` > /sys/devices/virtual/misc/sunxi-reg/rw/address; cat /sys/devices/virtual/misc/sunxi-reg/rw/value" 34 | echo 35 | } 36 | } 37 | 38 | dump_io SRAM 0xf1c00000 0x100 39 | dump_io DRAM 0xf1c01000 0x400 40 | dump_io CCM 0xf1c20000 0x400 41 | dump_io PIO 0xf1c20800 0x400 42 | 43 | dump_pmu() 44 | { 45 | for ((i = 0; i <0x100; i+=2)) { 46 | adb shell "echo `printf 0x%x $i` > /sys/bus/i2c/devices/0-0034/axp20_reg; cat /sys/bus/i2c/devices/0-0034/axp20_regs" 47 | } 48 | } 49 | 50 | dump_pmu 51 | -------------------------------------------------------------------------------- /autoversion.sh: -------------------------------------------------------------------------------- 1 | # 2 | # This script auto-updates a VERSION string definition. 3 | # It outputs informational messages to stderr, while the actual 4 | # output (on stdout) can easily be redirected to a file. 5 | # 6 | 7 | LATEST_RELEASE="v1.4.1" 8 | 9 | if VER=`git describe --tags --dirty --always`; then 10 | echo "Setting version information: ${VER}" >&2 11 | else 12 | VER=${LATEST_RELEASE} 13 | echo "Unable to determine current version (using \"${VER}\" as fallback)" >&2 14 | fi 15 | echo >&2 16 | 17 | echo "/* Auto-generated information. DO NOT EDIT */" 18 | echo "#define VERSION \"${VER}\"" 19 | -------------------------------------------------------------------------------- /bin/fel-pio.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Icenowy/sunxi-tools/1c3a6ca549dc76cf4725d28241923e20b1409a65/bin/fel-pio.bin -------------------------------------------------------------------------------- /bin/fel-pio.nm: -------------------------------------------------------------------------------- 1 | 00002000 T pio_to_sram 2 | 00002004 T sram_to_pio 3 | -------------------------------------------------------------------------------- /bin/fel-sdboot.sunxi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Icenowy/sunxi-tools/1c3a6ca549dc76cf4725d28241923e20b1409a65/bin/fel-sdboot.sunxi -------------------------------------------------------------------------------- /bin/jtag-loop.sunxi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Icenowy/sunxi-tools/1c3a6ca549dc76cf4725d28241923e20b1409a65/bin/jtag-loop.sunxi -------------------------------------------------------------------------------- /bin/ramboot.scr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Icenowy/sunxi-tools/1c3a6ca549dc76cf4725d28241923e20b1409a65/bin/ramboot.scr -------------------------------------------------------------------------------- /bin/ramboot.uboot-sh: -------------------------------------------------------------------------------- 1 | # U-boot RAM boot script 2 | ramdisk= 3 | if iminfo 0x4c000000; then 4 | ramdisk=0x4c000000 5 | fi 6 | setenv bootargs console=ttyS0,115200 rdinit=/sbin/init panic=10 7 | bootm 0x44000000 $ramdisk 8 | -------------------------------------------------------------------------------- /bin/uart0-helloworld-sdboot.sunxi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Icenowy/sunxi-tools/1c3a6ca549dc76cf4725d28241923e20b1409a65/bin/uart0-helloworld-sdboot.sunxi -------------------------------------------------------------------------------- /boot_head.S: -------------------------------------------------------------------------------- 1 | /* 2 | * Boot header to work around broken Allwinner A1x boot loaders 3 | * 4 | * Copyright (C) 2012 Henrik Nordstrom 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License as 8 | * published by the Free Software Foundation; either version 2 of 9 | * the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 19 | * MA 02111-1307 USA 20 | * 21 | * 22 | * This file is a workaround to broken bootloaders on Allwinner A1x 23 | * platform who do not provide correct machid or atags address 24 | * 25 | * Usage: 26 | * load the header at 0x40007000 and change the entry point of your 27 | * boot process to 0x40007000 28 | * 29 | * Detailed memory map: 30 | * 0x40000100 atags 31 | * 0x40007000 boot_head (entry point) 32 | * 0x40008000 kernel 33 | * 0x43000000 script.bin 34 | * If you have a ramdisk then load it at some higher address 35 | */ 36 | 37 | _start: 38 | ldr r0, =0 39 | ldr r1, =MACHID 40 | ldr r2, =0x40000100 41 | ldr lr, =0x40008000 42 | bx lr 43 | -------------------------------------------------------------------------------- /boot_head.lds: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Henrik Nordstrom 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | SECTIONS 19 | { 20 | . = 0x40007000; 21 | .text : { *(.text) } 22 | /DISCARD/ : { *(.dynstr*) } 23 | /DISCARD/ : { *(.dynamic*) } 24 | /DISCARD/ : { *(.plt*) } 25 | /DISCARD/ : { *(.interp*) } 26 | /DISCARD/ : { *(.gnu*) } 27 | /DISCARD/ : { *(.note*) } 28 | } 29 | -------------------------------------------------------------------------------- /bootinfo.c: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2012 Henrik Nordstrom 3 | * 4 | * display information about sunxi boot headers 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License as 8 | * published by the Free Software Foundation; either version 2 of 9 | * the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 19 | * MA 02111-1307 USA 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include "common.h" 29 | #include "types.h" 30 | 31 | /* boot_file_head copied from mksunxiboot */ 32 | /* boot head definition from sun4i boot code */ 33 | typedef struct boot_file_head 34 | { 35 | u32 jump_instruction; // one intruction jumping to real code 36 | u8 magic[8]; // ="eGON.BT0" or "eGON.BT1", not C-style string. 37 | u32 check_sum; // generated by PC 38 | u32 length; // generated by PC 39 | u32 pub_head_size; // the size of boot_file_head_t 40 | u8 pub_head_vsn[4]; // the version of boot_file_head_t 41 | u8 file_head_vsn[4]; // the version of boot0_file_head_t or boot1_file_head_t 42 | u8 Boot_vsn[4]; // Boot version 43 | u8 eGON_vsn[4]; // eGON version 44 | u8 platform[8]; // platform information 45 | } boot_file_head_t; 46 | 47 | typedef struct brom_file_head 48 | { 49 | u32 jump_instruction; // one intruction jumping to real code 50 | u8 magic[8]; // ="eGON.BRM", not C-style string. 51 | u32 length; // generated by PC 52 | u8 Boot_vsn[4]; // Boot version 53 | u8 eGON_vsn[4]; // eGON version 54 | u8 platform[8]; // platform information 55 | } brom_file_head_t; 56 | 57 | typedef struct _boot_dram_para_t { 58 | __u32 dram_baseaddr; 59 | __u32 dram_clk; 60 | __u32 dram_type; 61 | __u32 dram_rank_num; 62 | __u32 dram_chip_density; 63 | __u32 dram_io_width; 64 | __u32 dram_bus_width; 65 | __u32 dram_cas; 66 | __u32 dram_zq; 67 | __u32 dram_odt_en; 68 | __u32 dram_size; 69 | __u32 dram_tpr0; 70 | __u32 dram_tpr1; 71 | __u32 dram_tpr2; 72 | __u32 dram_tpr3; 73 | __u32 dram_tpr4; 74 | __u32 dram_tpr5; 75 | __u32 dram_emr1; 76 | __u32 dram_emr2; 77 | __u32 dram_emr3; 78 | } boot_dram_para_t; 79 | 80 | typedef struct _normal_gpio_cfg { 81 | __u8 port; 82 | __u8 port_num; 83 | __u8 mul_sel; 84 | __u8 pull; 85 | __u8 drv_level; 86 | __u8 data; 87 | __u8 reserved[2]; 88 | } normal_gpio_cfg; 89 | 90 | typedef struct _boot0_private_head_t { 91 | __u32 prvt_head_size; 92 | char prvt_head_vsn[4]; 93 | boot_dram_para_t dram_para; 94 | __s32 uart_port; 95 | normal_gpio_cfg uart_ctrl[2]; 96 | __s32 enable_jtag; 97 | normal_gpio_cfg jtag_gpio[5]; 98 | normal_gpio_cfg storage_gpio[32]; 99 | __u8 storage_data[256]; 100 | } boot0_private_head_t; 101 | 102 | typedef struct _boot0_file_head_t { 103 | boot_file_head_t boot_head; 104 | boot0_private_head_t prvt_head; 105 | } boot0_file_head_t; 106 | 107 | typedef struct _boot_core_para_t { 108 | __u32 user_set_clock; 109 | __u32 user_set_core_vol; 110 | __u32 vol_threshold; 111 | } boot_core_para_t; 112 | 113 | typedef struct _boot1_private_head_t { 114 | __u32 prvt_head_size; 115 | __u8 prvt_head_vsn[4]; 116 | __s32 uart_port; 117 | normal_gpio_cfg uart_ctrl[2]; 118 | boot_dram_para_t dram_para; 119 | char script_buf[32768]; 120 | boot_core_para_t core_para; 121 | __s32 twi_port; 122 | normal_gpio_cfg twi_ctrl[2]; 123 | __s32 debug_enable; 124 | __s32 hold_key_min; 125 | __s32 hold_key_max; 126 | __u32 work_mode; 127 | __u32 storage_type; 128 | normal_gpio_cfg storage_gpio[32]; 129 | __u8 storage_data[256]; 130 | } boot1_private_head_t; 131 | 132 | typedef struct _boot1_file_head_t { 133 | boot_file_head_t boot_head; 134 | boot1_private_head_t prvt_head; 135 | } boot1_file_head_t; 136 | 137 | /* STORAGE DATA on SD loaders */ 138 | typedef struct _boot_sdcard_info_t { 139 | __s32 card_ctrl_num; 140 | __s32 boot_offset; 141 | __s32 card_no[4]; 142 | __s32 speed_mode[4]; 143 | __s32 line_sel[4]; 144 | __s32 line_count[4]; 145 | } boot_sdcard_info_t; 146 | 147 | #define BROM_MAGIC "eGON.BRM" 148 | #define BOOT0_MAGIC "eGON.BT0" 149 | #define BOOT1_MAGIC "eGON.BT1" 150 | 151 | union { 152 | boot_file_head_t boot; 153 | boot0_file_head_t boot0; 154 | boot1_file_head_t boot1; 155 | brom_file_head_t brom; 156 | } boot_hdr; 157 | 158 | typedef enum { 159 | ALLWINNER_UNKNOWN_LOADER=0, 160 | ALLWINNER_SD_LOADER, 161 | ALLWINNER_NAND_LOADER 162 | } loader_type; 163 | 164 | void fail(char *msg) { 165 | perror(msg); 166 | exit(1); 167 | } 168 | 169 | void pprintf(void *addr, const char *fmt, ...) 170 | { 171 | va_list ap; 172 | va_start(ap, fmt); 173 | printf("%8x:\t", (unsigned)((char *)addr - (char *)&boot_hdr)); 174 | vprintf(fmt, ap); 175 | va_end(ap); 176 | } 177 | 178 | void print_brom_file_head(brom_file_head_t *hdr) 179 | { 180 | pprintf(&hdr->magic, "Magic : %.8s\n", hdr->magic); 181 | pprintf(&hdr->length, "Length : %u\n", hdr->length); 182 | pprintf(&hdr->Boot_vsn, "BOOT ver : %.4s\n", hdr->Boot_vsn); 183 | pprintf(&hdr->eGON_vsn, "eGON ver : %.4s\n", hdr->eGON_vsn); 184 | pprintf(&hdr->platform, "Chip? : %.8s\n", hdr->platform); 185 | } 186 | 187 | void print_boot_file_head(boot_file_head_t *hdr) 188 | { 189 | pprintf(&hdr->magic, "Magic : %.8s\n", hdr->magic); 190 | pprintf(&hdr->length, "Length : %u\n", hdr->length); 191 | pprintf(&hdr->pub_head_size, "HSize : %u\n", hdr->pub_head_size); 192 | pprintf(&hdr->pub_head_vsn, "HEAD ver : %.4s\n", hdr->pub_head_vsn); 193 | pprintf(&hdr->file_head_vsn, "FILE ver : %.4s\n", hdr->file_head_vsn); 194 | pprintf(&hdr->Boot_vsn, "BOOT ver : %.4s\n", hdr->Boot_vsn); 195 | pprintf(&hdr->eGON_vsn, "eGON ver : %.4s\n", hdr->eGON_vsn); 196 | pprintf(&hdr->platform, "platform : %c%c%c%c%c%c%c%c\n", hdr->platform[0], hdr->platform[1], hdr->platform[2], hdr->platform[3], hdr->platform[4], hdr->platform[5], hdr->platform[6], hdr->platform[7]); 197 | } 198 | 199 | void print_boot_dram_para(boot_dram_para_t *dram) 200 | { 201 | pprintf(&dram->dram_baseaddr, "DRAM base : %p\n", (void *)(uintptr_t)dram->dram_baseaddr); 202 | pprintf(&dram->dram_clk, "DRAM clk : %d\n", dram->dram_clk); 203 | pprintf(&dram->dram_type, "DRAM type : %d\n", dram->dram_type); 204 | pprintf(&dram->dram_rank_num, "DRAM rank : %d\n", dram->dram_rank_num); 205 | pprintf(&dram->dram_chip_density,"DRAM den : %d\n", dram->dram_chip_density); 206 | pprintf(&dram->dram_io_width, "DRAM iow : %d\n", dram->dram_io_width); 207 | pprintf(&dram->dram_bus_width, "DRAM busw : %d\n", dram->dram_bus_width); 208 | pprintf(&dram->dram_cas, "DRAM cas : %d\n", dram->dram_cas); 209 | pprintf(&dram->dram_zq, "DRAM zq : %d\n", dram->dram_zq); 210 | pprintf(&dram->dram_odt_en, "DRAM odt : 0x%x\n", dram->dram_odt_en); 211 | pprintf(&dram->dram_size, "DRAM size : %d\n", dram->dram_size); 212 | pprintf(&dram->dram_tpr0, "DRAM tpr0 : 0x%x\n", dram->dram_tpr0); 213 | pprintf(&dram->dram_tpr1, "DRAM tpr1 : 0x%x\n", dram->dram_tpr1); 214 | pprintf(&dram->dram_tpr2, "DRAM tpr2 : 0x%x\n", dram->dram_tpr2); 215 | pprintf(&dram->dram_tpr3, "DRAM tpr3 : 0x%x\n", dram->dram_tpr3); 216 | pprintf(&dram->dram_tpr4, "DRAM tpr4 : 0x%x\n", dram->dram_tpr4); 217 | pprintf(&dram->dram_tpr5, "DRAM tpr5 : 0x%x\n", dram->dram_tpr5); 218 | pprintf(&dram->dram_emr1, "DRAM emr1 : 0x%x\n", dram->dram_emr1); 219 | pprintf(&dram->dram_emr2, "DRAM emr2 : 0x%x\n", dram->dram_emr2); 220 | pprintf(&dram->dram_emr3, "DRAM emr3 : 0x%x\n", dram->dram_emr3); 221 | } 222 | 223 | void print_normal_gpio_cfg(normal_gpio_cfg *gpio, int count) 224 | { 225 | int i; 226 | for (i = 0; i < count; i++) { 227 | if (gpio[i].port) 228 | pprintf(&gpio[i], " GPIO %d : port=%c%d, sel=%d, pull=%d, drv=%d, data=%d, reserved=%02x,%02x\n", i, 'A'+gpio[i].port-1, gpio[i].port_num, gpio[i].mul_sel, gpio[i].pull, gpio[i].drv_level, gpio[i].data, gpio[i].reserved[0], gpio[i].reserved[1]); 229 | } 230 | } 231 | 232 | void print_boot_sdcard_info(boot_sdcard_info_t *info) 233 | { 234 | pprintf(&info->card_ctrl_num, " CARD Ctrl Num: %d\n", info->card_ctrl_num); 235 | pprintf(&info->boot_offset, " BOOT Offset: %08x\n", info->boot_offset); 236 | 237 | for (int i = 0; i < 4; i++) { 238 | if (info->card_no[i] == -1) 239 | continue; 240 | pprintf(&info->card_no[i], " CARD No : %d (%d)\n", info->card_no[i], i); 241 | pprintf(&info->speed_mode[i], " Speed : %d\n", info->speed_mode[i]); 242 | pprintf(&info->line_sel[i], " Line sel: %d\n", info->line_sel[i]); 243 | pprintf(&info->line_count[i], " Line cnt: %d\n", info->line_count[i]); 244 | } 245 | } 246 | 247 | void print_boot0_private_head(boot0_private_head_t *hdr, loader_type type) 248 | { 249 | pprintf(&hdr->prvt_head_size, "FHSize : %u\n", hdr->prvt_head_size); 250 | pprintf(&hdr->prvt_head_vsn, "FILE ver : %.4s\n", hdr->prvt_head_vsn); 251 | print_boot_dram_para(&hdr->dram_para); 252 | pprintf(&hdr->uart_port, "UART port : %d\n", hdr->uart_port); 253 | print_normal_gpio_cfg(hdr->uart_ctrl, 2); 254 | pprintf(&hdr->enable_jtag, "JTAG en : %d\n", hdr->enable_jtag); 255 | print_normal_gpio_cfg(hdr->jtag_gpio, 5); 256 | pprintf(&hdr->storage_gpio, "STORAGE :\n"); 257 | print_normal_gpio_cfg(hdr->storage_gpio, 32); 258 | int i = 0; 259 | if (type == ALLWINNER_SD_LOADER) { 260 | print_boot_sdcard_info((boot_sdcard_info_t *)hdr->storage_data); 261 | i = sizeof(boot_sdcard_info_t); 262 | } 263 | for (int n = 0; i < 256; i++, n++) { 264 | if (n % 16 == 0) { 265 | if (n) { 266 | printf("\n"); 267 | } 268 | pprintf(&hdr->storage_data[i], " DATA %02x :", i); 269 | } 270 | printf(" %02x", hdr->storage_data[i]); 271 | } 272 | printf("\n"); 273 | } 274 | 275 | void print_script(void *UNUSED(script)) 276 | { 277 | } 278 | 279 | void print_core_para(boot_core_para_t *core) 280 | { 281 | pprintf(&core->user_set_clock, "Set Clock : %d\n", core->user_set_clock); 282 | pprintf(&core->user_set_core_vol, "Set Core Vol: %d\n", core->user_set_core_vol); 283 | pprintf(&core->vol_threshold, "Vol Threshold: %d\n", core->vol_threshold); 284 | } 285 | 286 | void print_boot1_private_head(boot1_private_head_t *hdr, loader_type type) 287 | { 288 | pprintf(&hdr->prvt_head_size, "FHSize : %u\n", hdr->prvt_head_size); 289 | pprintf(&hdr->prvt_head_vsn, "FILE ver : %.4s\n", hdr->prvt_head_vsn); 290 | pprintf(&hdr->uart_port, "UART port : %d\n", hdr->uart_port); 291 | print_normal_gpio_cfg(hdr->uart_ctrl, 2); 292 | print_boot_dram_para(&hdr->dram_para); 293 | print_script(&hdr->script_buf); 294 | print_core_para(&hdr->core_para); 295 | pprintf(&hdr->twi_port, "TWI port : %d\n", hdr->twi_port); 296 | print_normal_gpio_cfg(hdr->twi_ctrl, 2); 297 | pprintf(&hdr->debug_enable, "Debug : %d\n", hdr->debug_enable); 298 | pprintf(&hdr->hold_key_min, "Hold key min : %d\n", hdr->hold_key_min); 299 | pprintf(&hdr->hold_key_max, "Hold key max : %d\n", hdr->hold_key_max); 300 | pprintf(&hdr->work_mode, "Work mode : %d\n", hdr->work_mode); 301 | pprintf(&hdr->storage_type, "STORAGE :\n"); 302 | pprintf(&hdr->storage_type, " type : %d\n", hdr->storage_type); 303 | print_normal_gpio_cfg(hdr->storage_gpio, 32); 304 | int i = 0; 305 | if (type == ALLWINNER_SD_LOADER) { 306 | print_boot_sdcard_info((boot_sdcard_info_t *)hdr->storage_data); 307 | i = sizeof(boot_sdcard_info_t); 308 | } 309 | for (int n = 0; i < 256; i++, n++) { 310 | if (n % 16 == 0) { 311 | if (n) { 312 | printf("\n"); 313 | } 314 | pprintf(&hdr->storage_data[i], " DATA %02x :", i); 315 | } 316 | printf(" %02x", hdr->storage_data[i]); 317 | } 318 | printf("\n"); 319 | } 320 | 321 | void print_boot0_file_head(boot0_file_head_t *hdr, loader_type type) 322 | { 323 | print_boot_file_head(&hdr->boot_head); 324 | if (strncmp((char *)hdr->boot_head.file_head_vsn, "1230", 4) == 0) 325 | print_boot0_private_head(&hdr->prvt_head, type); 326 | else 327 | printf("Unknown boot0 header version\n"); 328 | } 329 | 330 | void print_boot1_file_head(boot1_file_head_t *hdr, loader_type type) 331 | { 332 | print_boot_file_head(&hdr->boot_head); 333 | if (strncmp((char *)hdr->boot_head.file_head_vsn, "1230", 4) == 0) 334 | print_boot1_private_head(&hdr->prvt_head, type); 335 | else 336 | printf("Unknown boot0 header version\n"); 337 | } 338 | 339 | static void usage(const char *cmd) 340 | { 341 | puts("sunxi-bootinfo " VERSION "\n"); 342 | printf("Usage: %s []\n", cmd); 343 | printf(" With no given, will read from stdin instead\n"); 344 | } 345 | 346 | int main(int argc, char * argv[]) 347 | { 348 | FILE *in = stdin; 349 | loader_type type = ALLWINNER_UNKNOWN_LOADER; 350 | if (argc > 1 && strcmp(argv[1], "--type=sd") == 0) { 351 | type = ALLWINNER_SD_LOADER; 352 | argc--; 353 | argv++; 354 | } 355 | if (argc > 1 && strcmp(argv[1], "--type=nand") == 0) { 356 | type = ALLWINNER_NAND_LOADER; 357 | argc--; 358 | argv++; 359 | } 360 | if (argc > 1) { 361 | in = fopen(argv[1], "rb"); 362 | if (!in) { 363 | if (*argv[1] == '-') 364 | usage(argv[0]); 365 | fail("open input"); 366 | } 367 | } 368 | int len; 369 | 370 | len = fread(&boot_hdr, 1, sizeof(boot_hdr), in); 371 | if (len < (int)sizeof(boot_file_head_t)) 372 | fail("Failed to read header:"); 373 | if (strncmp((char *)boot_hdr.boot.magic, BOOT0_MAGIC, strlen(BOOT0_MAGIC)) == 0) { 374 | print_boot0_file_head(&boot_hdr.boot0, type); 375 | } else if (strncmp((char *)boot_hdr.boot.magic, BOOT1_MAGIC, strlen(BOOT1_MAGIC)) == 0) { 376 | print_boot1_file_head(&boot_hdr.boot1, type); 377 | } else if (strncmp((char *)boot_hdr.boot.magic, BROM_MAGIC, strlen(BROM_MAGIC)) == 0) { 378 | print_brom_file_head(&boot_hdr.brom); 379 | } else { 380 | fail("Invalid magic\n"); 381 | } 382 | 383 | return 0; 384 | } 385 | -------------------------------------------------------------------------------- /common.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Alejandro Mery 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | #ifndef _SUNXI_TOOLS_COMMON_H 18 | #define _SUNXI_TOOLS_COMMON_H 19 | 20 | #include /* offsetof */ 21 | 22 | #include "version.h" /* auto-generated VERSION string */ 23 | 24 | /** flag function argument as unused */ 25 | #ifdef UNUSED 26 | #elif defined(__GNUC__) 27 | # define UNUSED(x) UNUSED_ ## x __attribute__((unused)) 28 | #else 29 | # define UNUSED(x) UNUSED_ ## x 30 | #endif 31 | 32 | /** finds the parent of an struct member */ 33 | #ifndef container_of 34 | #define container_of(P,T,M) (T *)((char *)(P) - offsetof(T, M)) 35 | #endif 36 | 37 | /** calculate number of elements of an array */ 38 | #ifndef ARRAY_SIZE 39 | #define ARRAY_SIZE(A) (sizeof(A)/sizeof((A)[0])) 40 | #endif 41 | 42 | /** shortcut to printf to stderr */ 43 | #define errf(...) fprintf(stderr, __VA_ARGS__) 44 | 45 | #endif /* _SUNXI_TOOLS_COMMON_H */ 46 | -------------------------------------------------------------------------------- /fel-copy.c: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2011 Henrik Nordstrom 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License as 6 | * published by the Free Software Foundation; either version 2 of 7 | * the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 17 | * MA 02111-1307 USA 18 | */ 19 | 20 | /* 21 | 22 | Build instructions: 23 | 24 | arm-none-linux-gnueabi-gcc -g -Os -fno-common -ffixed-r8 -msoft-float -fno-builtin -ffreestanding -nostdinc -mno-thumb-interwork -Wall -Wstrict-prototypes -fno-stack-protector -Wno-format-nonliteral -Wno-format-security -fno-toplevel-reorder fel-copy.c -c 25 | 26 | arm-none-linux-gnueabi-objcopy -O binary fel-copy.o fel-copy.bin 27 | 28 | Parameters: 29 | 0x2100 Destination address 30 | 0x2104 Source address 31 | 0x2108 Length 32 | 33 | Source address is updated, allowing repeated copy to same destination 34 | */ 35 | 36 | #define CONFIG_BASE 0x2100 37 | 38 | void copy(void) 39 | { 40 | unsigned long *b = (void *)CONFIG_BASE; 41 | unsigned long **ptr = (void *)b++; 42 | unsigned long *a = *ptr; 43 | unsigned long i = *b++; 44 | while (i--) { 45 | *b++ = *a++; 46 | } 47 | *ptr = a; 48 | } 49 | 50 | -------------------------------------------------------------------------------- /fel-gpio: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | # Copyright (C) 2012,2013 Henrik Nordstrom 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in 13 | # all copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | # THE SOFTWARE. 22 | 23 | pio_to_sram=0x2000 24 | sram_to_pio=0x2004 25 | 26 | if [ -f fel-pio.bin ]; then 27 | ./sunxi-fel write 0x2000 fel-pio.bin 28 | else 29 | ./sunxi-fel write 0x2000 bin/fel-pio.bin 30 | fi 31 | 32 | ./sunxi-fel exec $pio_to_sram 33 | ./sunxi-fel read 0x3000 0x228 pio.reg 34 | ./sunxi-pio -i pio.reg print > pio.old 35 | cat pio.old | fgrep -v '<0><0><0><0>' 36 | 37 | while read cmd; do 38 | ./sunxi-pio -i pio.reg -o pio.reg $cmd 39 | ./sunxi-fel write 0x3000 pio.reg 40 | ./sunxi-fel exe 0x2004 41 | ./sunxi-fel exe 0x2000 42 | ./sunxi-fel read 0x3000 0x228 pio.reg 43 | ./sunxi-pio -i pio.reg print > pio.new 44 | diff -U0 pio.old pio.new || true 45 | mv -f pio.new pio.old 46 | done 47 | -------------------------------------------------------------------------------- /fel-pio.c: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2011 Henrik Nordstrom 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License as 6 | * published by the Free Software Foundation; either version 2 of 7 | * the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 17 | * MA 02111-1307 USA 18 | */ 19 | 20 | /* 21 | 22 | Build instructions: 23 | 24 | arm-none-eabi-gcc -g -Os -fno-common -fno-builtin -ffreestanding -nostdinc -mno-thumb-interwork -Wall -Wstrict-prototypes -fno-stack-protector -Wno-format-nonliteral -Wno-format-security -fno-toplevel-reorder fel-pio.c -nostdlib -o fel-pio.elf 25 | 26 | arm-none-eabi-objcopy -O binary fel-pio.elf fel-pio.bin 27 | 28 | arm-none-eabi-nm fel-pio.o 29 | 30 | */ 31 | 32 | void _pio_to_sram(void); 33 | void _sram_to_pio(void); 34 | 35 | void pio_to_sram(void) 36 | { 37 | _pio_to_sram(); 38 | } 39 | 40 | void sram_to_pio(void) 41 | { 42 | _sram_to_pio(); 43 | } 44 | 45 | void _pio_to_sram(void) 46 | { 47 | unsigned long *a = (void *)0x1c20800; 48 | unsigned long *b = (void *)0x3000; 49 | int i = 0x228 >> 2; 50 | while (i--) { 51 | *b++ = *a++; 52 | } 53 | } 54 | 55 | void _sram_to_pio(void) 56 | { 57 | unsigned long *a = (void *)0x1c20800; 58 | unsigned long *b = (void *)0x3000; 59 | int i = 0x228 >> 2; 60 | while (i--) { 61 | *a++ = *b++; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /fel-pio.lds: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Henrik Nordstrom 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | SECTIONS 19 | { 20 | . = 0x2000; 21 | .text : { *(.text) } 22 | /DISCARD/ : { *(.dynstr*) } 23 | /DISCARD/ : { *(.dynamic*) } 24 | /DISCARD/ : { *(.plt*) } 25 | /DISCARD/ : { *(.interp*) } 26 | /DISCARD/ : { *(.gnu*) } 27 | /DISCARD/ : { *(.note*) } 28 | } 29 | -------------------------------------------------------------------------------- /fel-sdboot.S: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Bernhard Nortmann 3 | * 4 | * Based on previous works 5 | * Copyright (C) 2016 Siarhei Siamashka 6 | * Copyright (C) 2012 Henrik Nordstrom 7 | * 8 | * This program is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU General Public License as 10 | * published by the Free Software Foundation; either version 2 of 11 | * the License, or (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program; if not, write to the Free Software 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 21 | * MA 02111-1307 USA 22 | * 23 | */ 24 | 25 | /* 26 | * This file is a utility stub (bootloader code) to force the device into 27 | * FEL mode, by jumping directly to the corresponding (N-)BROM entry point. 28 | * 29 | * Build instructions: 30 | * make fel-sdboot.sunxi 31 | * 32 | * If needed, adjust CROSS_COMPILE and MKSUNXIBOOT according to your 33 | * toolchain, e.g. 34 | * make fel-sdboot.sunxi CROSS_COMPILE=armv7a-hardfloat-linux-gnueabi- \ 35 | * MKSUNXIBOOT=/usr/local/bin/mksunxiboot 36 | * 37 | * 38 | * Install instructions: 39 | * dd if=fel-sdboot.sunxi of=/dev/sdX bs=1024 seek=8 40 | */ 41 | 42 | SCTRL .req r0 43 | .equ V_BIT, (1 << 13) 44 | 45 | .equ BROM_ENTRY_LOW, 0x00000020 46 | .equ BROM_ENTRY_HIGH, 0xFFFF0020 47 | 48 | /* 49 | * In cases where insufficient padding is added by an old mksunxiboot, 50 | * _start may be 0x20, which means that the instruction at 0x28 could get 51 | * corrupted by the BROM - see https://patchwork.ozlabs.org/patch/622173/ 52 | * 53 | * Apply a workaround to avoid (= skip over) that memory location. 54 | * _main would be at 0x30 in that particular case. With newer (properly 55 | * fixed) versions of mksunxiboot, this code ends up at higher addresses 56 | * and will be moot, but harmless. 57 | */ 58 | _start: 59 | b _main 60 | nop 61 | nop 62 | nop 63 | 64 | _main: 65 | mrc p15, 0, SCTRL, c1, c0, 0 66 | tst SCTRL, #V_BIT @ test SCTRL.V 67 | moveq lr, #BROM_ENTRY_LOW 68 | ldrne lr, =BROM_ENTRY_HIGH 69 | bx lr 70 | -------------------------------------------------------------------------------- /fel-sdboot.lds: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Henrik Nordstrom 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | SECTIONS 19 | { 20 | . = 0x0030; 21 | .text : { *(.text) } 22 | /DISCARD/ : { *(.dynstr*) } 23 | /DISCARD/ : { *(.dynamic*) } 24 | /DISCARD/ : { *(.plt*) } 25 | /DISCARD/ : { *(.interp*) } 26 | /DISCARD/ : { *(.gnu*) } 27 | /DISCARD/ : { *(.note*) } 28 | } 29 | -------------------------------------------------------------------------------- /fel-to-spl-thunk.S: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2015 Siarhei Siamashka 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a 5 | * copy of this software and associated documentation files (the "Software"), 6 | * to deal in the Software without restriction, including without limitation 7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | * and/or sell copies of the Software, and to permit persons to whom the 9 | * Software is furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice (including the next 12 | * paragraph) shall be included in all copies or substantial portions of the 13 | * Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 | * DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | /*************************************************************************/ 25 | /* Usage instructions: "ruby -x fel-to-spl-thunk.S > fel-to-spl-thunk.h" */ 26 | /*************************************************************************/ 27 | 28 | /* Open a comment for gas. 29 | 30 | Do not close the comment until after the Ruby code terminator (__END__). 31 | Write the '*' '/' sequence of characters as "\x2a/" in string literals to 32 | avoid doing so. 33 | 34 | #!/usr/bin/env ruby 35 | 36 | def tool_exists(tool_name) 37 | `which #{tool_name} > /dev/null 2>&1` 38 | return $?.to_i == 0 39 | end 40 | 41 | toolchains = [ 42 | "arm-none-eabi-", 43 | "arm-linux-gnueabihf-", 44 | "arm-none-linux-gnueabi-", 45 | "armv7a-hardfloat-linux-gnueabi-", 46 | ] 47 | 48 | toolchain = toolchains.find { |toolchain| tool_exists("#{toolchain}as") } 49 | abort "Can't find any ARM crosscompiler\n" unless toolchain 50 | 51 | system("#{toolchain}as -o #{$PROGRAM_NAME}.o #{$PROGRAM_NAME}") 52 | exit($?.to_i) if $?.to_i != 0 53 | 54 | `#{toolchain}objdump -d #{$PROGRAM_NAME}.o`.each_line {|l| 55 | next unless l =~ /(\h+)\:\s+(\h+)\s+(\S+)\s+([^;]*)/ 56 | printf("\t0x%s, /* %8s: %-10s %-28s \x2a/\n", $2, $1, $3, $4.strip) 57 | } 58 | 59 | __END__ 60 | */ 61 | 62 | /*************************************************************************/ 63 | 64 | BUF1 .req r0 65 | BUF2 .req r1 66 | TMP1 .req r2 67 | TMP2 .req r3 68 | SWAPTBL .req r4 69 | FULLSIZE .req r5 70 | BUFSIZE .req r6 71 | CHECKSUM .req r7 72 | SPL_ADDR .req r8 73 | 74 | entry_point: 75 | b setup_stack 76 | 77 | stack_begin: 78 | nop 79 | nop 80 | nop 81 | nop 82 | nop 83 | nop 84 | nop 85 | nop 86 | stack_end: 87 | nop 88 | 89 | /* A function, which walks the table and swaps all buffers */ 90 | swap_all_buffers: 91 | adr SWAPTBL, appended_data + 4 92 | swap_next_buffer: 93 | ldr BUF1, [SWAPTBL], #4 94 | ldr BUF2, [SWAPTBL], #4 95 | ldr BUFSIZE, [SWAPTBL], #4 96 | cmp BUFSIZE, #0 97 | bxeq lr 98 | swap_next_word: 99 | ldr TMP1, [BUF1] 100 | ldr TMP2, [BUF2] 101 | subs BUFSIZE, BUFSIZE, #4 102 | str TMP1, [BUF2], #4 103 | str TMP2, [BUF1], #4 104 | bne swap_next_word 105 | b swap_next_buffer 106 | 107 | setup_stack: /* Save the original SP, LR and CPSR to stack */ 108 | ldr SPL_ADDR, appended_data 109 | adr BUF1, stack_end 110 | str sp, [BUF1, #-4]! 111 | mov sp, BUF1 112 | mrs TMP1, cpsr 113 | push {TMP1, lr} 114 | 115 | /* Disable IRQ and FIQ */ 116 | orr TMP1, #0xc0 117 | msr cpsr_c, TMP1 118 | 119 | /* Check if the instructions or data cache is enabled */ 120 | mrc p15, 0, TMP1, c1, c0, 0 121 | movw TMP2, #((1 << 12) | (1 << 2)) 122 | tst TMP1, TMP2 123 | bne cache_is_unsupported 124 | 125 | bl swap_all_buffers 126 | 127 | verify_checksum: 128 | movw CHECKSUM, #0x6c39 129 | movt CHECKSUM, #0x5f0a 130 | mov BUF1, SPL_ADDR 131 | ldr FULLSIZE, [BUF1, #16] 132 | check_next_word: 133 | ldr TMP1, [BUF1], #4 134 | subs FULLSIZE, FULLSIZE, #4 135 | add CHECKSUM, CHECKSUM, TMP1 136 | bne check_next_word 137 | 138 | ldr TMP1, [SPL_ADDR, #12] 139 | subs CHECKSUM, CHECKSUM, TMP1, lsl #1 140 | bne checksum_is_bad 141 | 142 | /* Change 'eGON.BT0' -> 'eGON.FEL' */ 143 | movw TMP1, (('F' << 8) + '.') 144 | movt TMP1, (('L' << 8) + 'E') 145 | str TMP1, [SPL_ADDR, #8] 146 | 147 | /* Call the SPL code */ 148 | dsb 149 | isb 150 | blx SPL_ADDR 151 | 152 | /* Return back to FEL */ 153 | b return_to_fel 154 | 155 | cache_is_unsupported: 156 | /* Bail out if cache is enabled and change 'eGON.BT0' -> 'eGON.???' */ 157 | movw TMP1, (('?' << 8) + '.') 158 | movt TMP1, (('?' << 8) + '?') 159 | str TMP1, [SPL_ADDR, #8] 160 | b return_to_fel_noswap 161 | 162 | checksum_is_bad: 163 | /* The checksum test failed, so change 'eGON.BT0' -> 'eGON.BAD' */ 164 | movw TMP1, (('B' << 8) + '.') 165 | movt TMP1, (('D' << 8) + 'A') 166 | str TMP1, [SPL_ADDR, #8] 167 | 168 | return_to_fel: 169 | bl swap_all_buffers 170 | return_to_fel_noswap: 171 | pop {TMP1, lr} 172 | msr cpsr_c, TMP1 /* Restore the original CPSR */ 173 | ldr sp, [sp] 174 | bx lr 175 | 176 | appended_data: 177 | /* 178 | * The appended data uses the following format: 179 | * 180 | * struct { 181 | * uint32_t spl_addr; 182 | * sram_swap_buffers swaptbl[]; 183 | * }; 184 | * 185 | * More details about the 'spl_addr' variable and the 'sram_swap_buffers' 186 | * struct can be found in the 'fel.c' source file. 187 | */ 188 | -------------------------------------------------------------------------------- /fel-to-spl-thunk.h: -------------------------------------------------------------------------------- 1 | 0xea000015, /* 0: b 5c */ 2 | 0xe1a00000, /* 4: nop */ 3 | 0xe1a00000, /* 8: nop */ 4 | 0xe1a00000, /* c: nop */ 5 | 0xe1a00000, /* 10: nop */ 6 | 0xe1a00000, /* 14: nop */ 7 | 0xe1a00000, /* 18: nop */ 8 | 0xe1a00000, /* 1c: nop */ 9 | 0xe1a00000, /* 20: nop */ 10 | 0xe1a00000, /* 24: nop */ 11 | 0xe28f40dc, /* 28: add r4, pc, #220 */ 12 | 0xe4940004, /* 2c: ldr r0, [r4], #4 */ 13 | 0xe4941004, /* 30: ldr r1, [r4], #4 */ 14 | 0xe4946004, /* 34: ldr r6, [r4], #4 */ 15 | 0xe3560000, /* 38: cmp r6, #0 */ 16 | 0x012fff1e, /* 3c: bxeq lr */ 17 | 0xe5902000, /* 40: ldr r2, [r0] */ 18 | 0xe5913000, /* 44: ldr r3, [r1] */ 19 | 0xe2566004, /* 48: subs r6, r6, #4 */ 20 | 0xe4812004, /* 4c: str r2, [r1], #4 */ 21 | 0xe4803004, /* 50: str r3, [r0], #4 */ 22 | 0x1afffff9, /* 54: bne 40 */ 23 | 0xeafffff3, /* 58: b 2c */ 24 | 0xe59f80a4, /* 5c: ldr r8, [pc, #164] */ 25 | 0xe24f0044, /* 60: sub r0, pc, #68 */ 26 | 0xe520d004, /* 64: str sp, [r0, #-4]! */ 27 | 0xe1a0d000, /* 68: mov sp, r0 */ 28 | 0xe10f2000, /* 6c: mrs r2, CPSR */ 29 | 0xe92d4004, /* 70: push {r2, lr} */ 30 | 0xe38220c0, /* 74: orr r2, r2, #192 */ 31 | 0xe121f002, /* 78: msr CPSR_c, r2 */ 32 | 0xee112f10, /* 7c: mrc 15, 0, r2, cr1, cr0, {0} */ 33 | 0xe3013004, /* 80: movw r3, #4100 */ 34 | 0xe1120003, /* 84: tst r2, r3 */ 35 | 0x1a000012, /* 88: bne d8 */ 36 | 0xebffffe5, /* 8c: bl 28 */ 37 | 0xe3067c39, /* 90: movw r7, #27705 */ 38 | 0xe3457f0a, /* 94: movt r7, #24330 */ 39 | 0xe1a00008, /* 98: mov r0, r8 */ 40 | 0xe5905010, /* 9c: ldr r5, [r0, #16] */ 41 | 0xe4902004, /* a0: ldr r2, [r0], #4 */ 42 | 0xe2555004, /* a4: subs r5, r5, #4 */ 43 | 0xe0877002, /* a8: add r7, r7, r2 */ 44 | 0x1afffffb, /* ac: bne a0 */ 45 | 0xe598200c, /* b0: ldr r2, [r8, #12] */ 46 | 0xe0577082, /* b4: subs r7, r7, r2, lsl #1 */ 47 | 0x1a00000a, /* b8: bne e8 */ 48 | 0xe304262e, /* bc: movw r2, #17966 */ 49 | 0xe3442c45, /* c0: movt r2, #19525 */ 50 | 0xe5882008, /* c4: str r2, [r8, #8] */ 51 | 0xf57ff04f, /* c8: dsb sy */ 52 | 0xf57ff06f, /* cc: isb sy */ 53 | 0xe12fff38, /* d0: blx r8 */ 54 | 0xea000006, /* d4: b f4 */ 55 | 0xe3032f2e, /* d8: movw r2, #16174 */ 56 | 0xe3432f3f, /* dc: movt r2, #16191 */ 57 | 0xe5882008, /* e0: str r2, [r8, #8] */ 58 | 0xea000003, /* e4: b f8 */ 59 | 0xe304222e, /* e8: movw r2, #16942 */ 60 | 0xe3442441, /* ec: movt r2, #17473 */ 61 | 0xe5882008, /* f0: str r2, [r8, #8] */ 62 | 0xebffffcb, /* f4: bl 28 */ 63 | 0xe8bd4004, /* f8: pop {r2, lr} */ 64 | 0xe121f002, /* fc: msr CPSR_c, r2 */ 65 | 0xe59dd000, /* 100: ldr sp, [sp] */ 66 | 0xe12fff1e, /* 104: bx lr */ 67 | -------------------------------------------------------------------------------- /fexc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Alejandro Mery 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #include "fexc.h" 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #ifndef NO_MMAP 25 | #include 26 | #endif 27 | #include 28 | #include 29 | #include 30 | 31 | #define pr_info(...) errf("fexc: " __VA_ARGS__) 32 | #define pr_err(...) errf("E: fexc: " __VA_ARGS__) 33 | 34 | enum script_format { 35 | FEX_SCRIPT_FORMAT, 36 | BIN_SCRIPT_FORMAT, 37 | UBOOT_HEADER_FORMAT, 38 | }; 39 | 40 | /* 41 | */ 42 | static inline char *read_all(int fd, const char *filename, size_t *size) 43 | { 44 | size_t buf_size = 4096, count = 0; 45 | char *p, *buf = malloc(buf_size); 46 | if (!buf) { 47 | pr_err("%s: %s\n", "malloc", strerror(errno)); 48 | return NULL; 49 | } 50 | p = buf; 51 | while (1) { 52 | ssize_t rc = read(fd, p, buf_size-count); 53 | if (rc == 0) 54 | break; 55 | else if (rc > 0) { 56 | count += rc; 57 | p += rc; 58 | 59 | if (count == buf_size) { 60 | char *new; 61 | buf_size *= 2; 62 | new = realloc(buf, buf_size); 63 | if (!new) { 64 | pr_err("%s: %s\n", "realloc", 65 | strerror(errno)); 66 | free(buf); 67 | return NULL; 68 | } else if (new != buf) { 69 | buf = new; 70 | p = buf + count; 71 | } 72 | } 73 | } else if (errno != EAGAIN && errno != EINTR) { 74 | pr_err("%s: %s: %s\n", filename, 75 | "read", strerror(errno)); 76 | free(buf); 77 | return NULL; 78 | } 79 | } 80 | 81 | *size = count; 82 | return buf; 83 | } 84 | 85 | /* 86 | */ 87 | static inline int script_parse(enum script_format format, 88 | const char *filename, 89 | struct script *script) 90 | { 91 | int ret = 0; 92 | switch (format) { 93 | case FEX_SCRIPT_FORMAT: { 94 | FILE *in = stdin; 95 | if (!filename) 96 | filename = ""; 97 | else if ((in = fopen(filename, "r")) == NULL) { 98 | pr_err("%s: %s\n", filename, strerror(errno)); 99 | break; 100 | } 101 | ret = script_parse_fex(in, filename, script); 102 | fclose(in); 103 | }; break; 104 | case BIN_SCRIPT_FORMAT: { 105 | int in = 0; /* stdin */ 106 | struct stat sb; 107 | void *bin = NULL; 108 | size_t bin_size; 109 | int allocated = 1; 110 | 111 | if (!filename) 112 | filename = ""; 113 | else if ((in = open(filename, O_RDONLY)) < 0) { 114 | pr_err("%s: %s\n", filename, strerror(errno)); 115 | break; 116 | } 117 | 118 | if (fstat(in, &sb) == -1) { 119 | pr_err("%s: %s: %s\n", filename, 120 | "fstat", strerror(errno)); 121 | goto bin_close; 122 | #ifndef NO_MMAP 123 | } else if (S_ISREG(sb.st_mode)) { 124 | /* regular file, mmap it */ 125 | bin = mmap(0, sb.st_size, PROT_READ, MAP_SHARED, in, 0); 126 | if (bin == MAP_FAILED) { 127 | pr_err("%s: %s: %s\n", filename, 128 | "mmap", strerror(errno)); 129 | goto bin_close; 130 | } 131 | bin_size = sb.st_size; 132 | allocated = 0; 133 | #endif 134 | } else { 135 | /* something else... just read it all! */ 136 | bin = read_all(in, filename, &bin_size); 137 | if (bin == NULL) 138 | goto bin_close; 139 | allocated = 1; 140 | } 141 | 142 | ret = script_decompile_bin(bin, bin_size, filename, script); 143 | if (allocated) 144 | free(bin); 145 | #ifndef NO_MMAP 146 | else if (munmap(bin, bin_size) == -1) { 147 | pr_err("%s: %s: %s\n", filename, 148 | "munmap", strerror(errno)); 149 | } 150 | #endif 151 | bin_close: 152 | close(in); 153 | }; break; 154 | case UBOOT_HEADER_FORMAT: /* not valid input */ 155 | ; 156 | } 157 | return ret; 158 | } 159 | static inline int script_generate(enum script_format format, 160 | const char *filename, 161 | struct script *script) 162 | { 163 | int ret = 0; 164 | static int (*text_gen[3]) (FILE *, const char *, struct script *) = { 165 | [FEX_SCRIPT_FORMAT] = script_generate_fex, 166 | [UBOOT_HEADER_FORMAT] = script_generate_uboot, 167 | }; 168 | 169 | if (text_gen[format]) { 170 | FILE *out = stdout; 171 | 172 | if (!filename) 173 | filename = ""; 174 | else if ((out = fopen(filename, "w")) == NULL) { 175 | pr_err("%s: %s\n", filename, strerror(errno)); 176 | goto done; 177 | } 178 | 179 | ret = text_gen[format](out, filename, script); 180 | fclose(out); 181 | } else { 182 | int out = 1; /* stdout */ 183 | size_t sections, entries, bin_size; 184 | void *bin; 185 | 186 | if (!filename) 187 | filename = ""; 188 | else if ((out = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0) { 189 | pr_err("%s: %s\n", filename, strerror(errno)); 190 | goto done; 191 | } 192 | 193 | bin_size = script_bin_size(script, §ions, &entries); 194 | bin = calloc(1, bin_size); 195 | if (!bin) 196 | pr_err("%s: %s\n", "malloc", strerror(errno)); 197 | else if (script_generate_bin(bin, bin_size, script, sections, entries)) { 198 | char *p = bin; 199 | while(bin_size) { 200 | ssize_t wc = write(out, p, bin_size); 201 | 202 | if (wc>0) { 203 | p += wc; 204 | bin_size -= wc; 205 | } else if (wc < 0 && errno != EINTR) { 206 | pr_err("%s: %s: %s\n", filename, 207 | "write", strerror(errno)); 208 | break; 209 | } 210 | } 211 | ret = (bin_size == 0); 212 | } 213 | free(bin); 214 | close(out); 215 | } 216 | done: 217 | return ret; 218 | } 219 | 220 | /* 221 | */ 222 | static inline void app_usage(const char *arg0, int mode) 223 | { 224 | fputs("sunxi-fexc " VERSION "\n\n", stderr); 225 | errf("Usage: %s [-vq]%s[ []]\n", arg0, 226 | mode ? " " : " [-I ] [-O ] "); 227 | 228 | if (mode == 0) 229 | fputs("\ninfmt: fex, bin (default:fex)" 230 | "\noutfmt: fex, bin, uboot (default:bin)\n", 231 | stderr); 232 | } 233 | 234 | static inline int app_choose_mode(char *arg0) 235 | { 236 | const char *name = basename(arg0); 237 | if (strcmp(name, "fex2bin") == 0) 238 | return 1; 239 | else if (strcmp(name, "bin2fex") == 0) 240 | return 2; 241 | else 242 | return 0; 243 | } 244 | 245 | /* 246 | */ 247 | int main(int argc, char *argv[]) 248 | { 249 | static const char *formats[] = { "fex", "bin", "uboot", NULL }; 250 | enum script_format infmt=FEX_SCRIPT_FORMAT; 251 | enum script_format outfmt=BIN_SCRIPT_FORMAT; 252 | const char *filename[] = { NULL /*stdin*/, NULL /*stdout*/}; 253 | struct script *script; 254 | 255 | int app_mode = app_choose_mode(argv[0]); 256 | 257 | const char *opt_string = "I:O:vq?"; 258 | if (app_mode != 0) opt_string += 4; /* disallow -I and -O */ 259 | int opt, ret = 1; 260 | int verbose = 0; 261 | 262 | if (app_mode == 2) { /* bin2fex */ 263 | infmt = BIN_SCRIPT_FORMAT; 264 | outfmt = FEX_SCRIPT_FORMAT; 265 | } 266 | 267 | while ((opt = getopt(argc, argv, opt_string)) != -1) { 268 | switch (opt) { 269 | case 'I': 270 | infmt=0; 271 | for (const char **f = formats; *f; f++, infmt++) { 272 | if (strcmp(*f, optarg) == 0) 273 | break; 274 | } 275 | switch (infmt) { 276 | case FEX_SCRIPT_FORMAT: 277 | case BIN_SCRIPT_FORMAT: 278 | break; 279 | default: 280 | errf("%s: invalid format -- \"%s\"\n", 281 | argv[0], optarg); 282 | goto show_usage; 283 | } 284 | break; 285 | case 'O': 286 | outfmt=0; 287 | for (const char **f = formats; *f; f++, outfmt++) { 288 | if (strcmp(*f, optarg) == 0) 289 | break; 290 | } 291 | if (!formats[outfmt]) { 292 | errf("%s: invalid format -- \"%s\"\n", 293 | argv[0], optarg); 294 | goto show_usage; 295 | } 296 | break; 297 | case 'v': 298 | verbose++; 299 | break; 300 | case 'q': 301 | verbose--; 302 | break; 303 | default: 304 | show_usage: 305 | app_usage(argv[0], app_mode); 306 | goto done; 307 | } 308 | } 309 | 310 | switch (argc - optind) { 311 | case 2: 312 | filename[1] = argv[optind+1]; /* out */ 313 | case 1: 314 | if (strcmp(argv[optind], "-") != 0) 315 | filename[0] = argv[optind]; /* in */ 316 | case 0: 317 | break; 318 | default: 319 | goto show_usage; 320 | } 321 | 322 | if (verbose>0) 323 | errf("%s: from %s:%s to %s:%s\n", argv[0], 324 | formats[infmt], filename[0]?filename[0]:"", 325 | formats[outfmt], filename[1]?filename[1]:""); 326 | 327 | if ((script = script_new()) == NULL) { 328 | perror("malloc"); 329 | goto done; 330 | } else if (script_parse(infmt, filename[0], script) && 331 | script_generate(outfmt, filename[1], script)) { 332 | ret = 0; 333 | } 334 | script_delete(script); 335 | done: 336 | return ret; 337 | } 338 | -------------------------------------------------------------------------------- /fexc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Alejandro Mery 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | #ifndef _SUNXI_TOOLS_FEXC_H 18 | #define _SUNXI_TOOLS_FEXC_H 19 | 20 | #include "common.h" 21 | 22 | #include 23 | #include 24 | 25 | #include "script.h" 26 | #include "script_bin.h" 27 | #include "script_fex.h" 28 | #include "script_uboot.h" 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /include/list.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Alejandro Mery 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | #ifndef _SUNXI_TOOLS_LIST_H 18 | #define _SUNXI_TOOLS_LIST_H 19 | 20 | /* 21 | * list 22 | */ 23 | 24 | /** a list hook */ 25 | struct list_entry { 26 | struct list_entry *prev; 27 | struct list_entry *next; 28 | }; 29 | 30 | /** initialize an empty list hook */ 31 | static inline void list_init(struct list_entry *self) 32 | { 33 | self->prev = self->next = self; 34 | } 35 | 36 | /** puts an entry between two other on a list */ 37 | static inline void list_inject(struct list_entry *l, 38 | struct list_entry *prev, 39 | struct list_entry *next) 40 | { 41 | l->prev = prev; 42 | l->next = next; 43 | 44 | next->prev = l; 45 | prev->next = l; 46 | } 47 | 48 | #define list_insert(H, E) list_inject((E), (H), (H)->next) 49 | #define list_append(H, E) list_inject((E), (H)->prev, (H)) 50 | 51 | /** removes an entry for the list where it's contained */ 52 | static inline void list_remove(struct list_entry *l) 53 | { 54 | struct list_entry *prev = l->prev, *next = l->next; 55 | next->prev = prev; 56 | prev->next = next; 57 | } 58 | 59 | /** returns first element of a list */ 60 | static inline struct list_entry *list_first(struct list_entry *l) 61 | { 62 | return (l->next == l) ? NULL : l->next; 63 | } 64 | 65 | /** returns last element of a list */ 66 | static inline struct list_entry *list_last(struct list_entry *l) 67 | { 68 | return (l->prev == l) ? NULL : l->prev; 69 | } 70 | 71 | /** returns next element on a list */ 72 | static inline struct list_entry *list_next(struct list_entry *l, 73 | struct list_entry *e) 74 | { 75 | return (e->next == l) ? NULL : e->next; 76 | } 77 | 78 | /** is list empty? */ 79 | static inline int list_empty(struct list_entry *l) 80 | { 81 | return (l->prev == l); 82 | } 83 | 84 | #endif /* _SUNXI_TOOLS_LIST_H */ 85 | -------------------------------------------------------------------------------- /include/portable_endian.h: -------------------------------------------------------------------------------- 1 | // "License": Public Domain 2 | // I, Mathias Panzenböck, place this file hereby into the public domain. Use it at your own risk for whatever you like. 3 | // In case there are jurisdictions that don't support putting things in the public domain you can also consider it to 4 | // be "dual licensed" under the BSD, MIT and Apache licenses, if you want to. This code is trivial anyway. Consider it 5 | // an example on how to get the endian conversion functions on different platforms. 6 | 7 | #ifndef PORTABLE_ENDIAN_H__ 8 | #define PORTABLE_ENDIAN_H__ 9 | 10 | #if (defined(_WIN16) || defined(_WIN32) || defined(_WIN64)) && !defined(__WINDOWS__) 11 | 12 | # define __WINDOWS__ 13 | 14 | #endif 15 | 16 | #if defined(__linux__) || defined(__CYGWIN__) 17 | 18 | # include 19 | 20 | #elif defined(__APPLE__) 21 | 22 | # include 23 | 24 | # define htobe16(x) OSSwapHostToBigInt16(x) 25 | # define htole16(x) OSSwapHostToLittleInt16(x) 26 | # define be16toh(x) OSSwapBigToHostInt16(x) 27 | # define le16toh(x) OSSwapLittleToHostInt16(x) 28 | 29 | # define htobe32(x) OSSwapHostToBigInt32(x) 30 | # define htole32(x) OSSwapHostToLittleInt32(x) 31 | # define be32toh(x) OSSwapBigToHostInt32(x) 32 | # define le32toh(x) OSSwapLittleToHostInt32(x) 33 | 34 | # define htobe64(x) OSSwapHostToBigInt64(x) 35 | # define htole64(x) OSSwapHostToLittleInt64(x) 36 | # define be64toh(x) OSSwapBigToHostInt64(x) 37 | # define le64toh(x) OSSwapLittleToHostInt64(x) 38 | 39 | # define __BYTE_ORDER BYTE_ORDER 40 | # define __BIG_ENDIAN BIG_ENDIAN 41 | # define __LITTLE_ENDIAN LITTLE_ENDIAN 42 | # define __PDP_ENDIAN PDP_ENDIAN 43 | 44 | #elif defined(__OpenBSD__) || defined(__FreeBSD__) 45 | 46 | # include 47 | 48 | #elif defined(__NetBSD__) || defined(__DragonFly__) 49 | 50 | # include 51 | 52 | # define be16toh(x) betoh16(x) 53 | # define le16toh(x) letoh16(x) 54 | 55 | # define be32toh(x) betoh32(x) 56 | # define le32toh(x) letoh32(x) 57 | 58 | # define be64toh(x) betoh64(x) 59 | # define le64toh(x) letoh64(x) 60 | 61 | #elif defined(__WINDOWS__) 62 | 63 | # include 64 | # include 65 | 66 | # if BYTE_ORDER == LITTLE_ENDIAN 67 | 68 | # define htobe16(x) htons(x) 69 | # define htole16(x) (x) 70 | # define be16toh(x) ntohs(x) 71 | # define le16toh(x) (x) 72 | 73 | # define htobe32(x) htonl(x) 74 | # define htole32(x) (x) 75 | # define be32toh(x) ntohl(x) 76 | # define le32toh(x) (x) 77 | 78 | # define htobe64(x) htonll(x) 79 | # define htole64(x) (x) 80 | # define be64toh(x) ntohll(x) 81 | # define le64toh(x) (x) 82 | 83 | # elif BYTE_ORDER == BIG_ENDIAN 84 | 85 | /* that would be xbox 360 */ 86 | # define htobe16(x) (x) 87 | # define htole16(x) __builtin_bswap16(x) 88 | # define be16toh(x) (x) 89 | # define le16toh(x) __builtin_bswap16(x) 90 | 91 | # define htobe32(x) (x) 92 | # define htole32(x) __builtin_bswap32(x) 93 | # define be32toh(x) (x) 94 | # define le32toh(x) __builtin_bswap32(x) 95 | 96 | # define htobe64(x) (x) 97 | # define htole64(x) __builtin_bswap64(x) 98 | # define be64toh(x) (x) 99 | # define le64toh(x) __builtin_bswap64(x) 100 | 101 | # else 102 | 103 | # error byte order not supported 104 | 105 | # endif 106 | 107 | # define __BYTE_ORDER BYTE_ORDER 108 | # define __BIG_ENDIAN BIG_ENDIAN 109 | # define __LITTLE_ENDIAN LITTLE_ENDIAN 110 | # define __PDP_ENDIAN PDP_ENDIAN 111 | 112 | #else 113 | 114 | # error platform not supported 115 | 116 | #endif 117 | 118 | #endif 119 | -------------------------------------------------------------------------------- /include/types.h: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2012 Henrik Nordstrom 3 | * (C) Copyright 2012 Alejandro Mery 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License as 7 | * published by the Free Software Foundation; either version 2 of 8 | * the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 18 | * MA 02111-1307 USA 19 | */ 20 | 21 | #ifndef SUNXI_TYPES_H 22 | #define SUNXI_TYPES_H 23 | 24 | #include 25 | 26 | #define __s8 int8_t 27 | #define __s16 int16_t 28 | #define __s32 int32_t 29 | #define __s64 int64_t 30 | 31 | #define s8 int8_t 32 | #define s16 int16_t 33 | #define s32 int32_t 34 | #define s64 int64_t 35 | 36 | #define __u8 uint8_t 37 | #define __u16 uint16_t 38 | #define __u32 uint32_t 39 | #define __u64 uint64_t 40 | 41 | #define u8 uint8_t 42 | #define u16 uint16_t 43 | #define u32 uint32_t 44 | #define u64 uint64_t 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /jtag-loop.S: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2012 Jens Andersen 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License as 6 | * published by the Free Software Foundation; either version 2 of 7 | * the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 17 | * MA 02111-1307 USA 18 | */ 19 | 20 | /* 21 | 22 | Build instructions: 23 | 24 | arm-none-linux-gnueabi-gcc -g -fno-common -ffixed-r8 -msoft-float -fno-builtin -ffreestanding -nostdinc -mno-thumb-interwork -Wall -Wstrict-prototypes -fno-stack-protector -Wno-format-nonliteral -Wno-format-security -fno-toplevel-reorder jtag-loop.S -c 25 | 26 | arm-none-linux-gnueabi-objcopy -O binary jtag-loop.o jtag-loop.bin 27 | 28 | mksunxiboot jtag-loop.bin jtag-loop.sunxi 29 | */ 30 | 31 | .file "fel-loop.S" 32 | .global entry 33 | .text 34 | .code 32 35 | .section ".start", "ax" 36 | 37 | entry: 38 | ldr r0,=0x01c208b4 39 | ldr r1,=0x00444444 40 | str r1, [r0] 41 | b . 42 | -------------------------------------------------------------------------------- /jtag-loop.c: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2012 Jens Andersen 3 | * (C) Copyright 2012 Henrik Nordstrom 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License as 7 | * published by the Free Software Foundation; either version 2 of 8 | * the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 18 | * MA 02111-1307 USA 19 | */ 20 | 21 | /* 22 | 23 | Build instructions: 24 | 25 | arm-none-linux-gnueabi-gcc -g -fno-common -ffixed-r8 -msoft-float -fno-builtin -ffreestanding -nostdinc -mno-thumb-interwork -Wall -Wstrict-prototypes -fno-stack-protector -Wno-format-nonliteral -Wno-format-security -fno-toplevel-reorder -Os jtag-loop.c -c 26 | 27 | arm-none-linux-gnueabi-objcopy -O binary jtag-loop.o jtag-loop.bin 28 | 29 | mksunxiboot jtag-loop.bin jtag-loop.sunxi 30 | */ 31 | 32 | void _start(void) 33 | { 34 | *(volatile unsigned long *)0x01c208b4 = 0x00444444; 35 | while(1); 36 | } 37 | -------------------------------------------------------------------------------- /jtag-loop.lds: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Henrik Nordstrom 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | SECTIONS 19 | { 20 | . = 0x0030; 21 | .text : { *(.text) } 22 | /DISCARD/ : { *(.dynstr*) } 23 | /DISCARD/ : { *(.dynamic*) } 24 | /DISCARD/ : { *(.plt*) } 25 | /DISCARD/ : { *(.interp*) } 26 | /DISCARD/ : { *(.gnu*) } 27 | /DISCARD/ : { *(.note*) } 28 | } 29 | -------------------------------------------------------------------------------- /meminfo.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Floris Bos 3 | * Copyright (c) 2014 Luc Verhaegen 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include "common.h" 29 | 30 | typedef uint32_t u32; 31 | 32 | /* from u-boot code: */ 33 | struct sun4i_dram_para { 34 | u32 baseaddr; 35 | u32 clock; 36 | u32 type; 37 | u32 rank_num; 38 | u32 density; 39 | u32 io_width; 40 | u32 bus_width; 41 | u32 cas; 42 | u32 zq; 43 | u32 odt_en; 44 | u32 size; 45 | u32 tpr0; 46 | u32 tpr1; 47 | u32 tpr2; 48 | u32 tpr3; 49 | u32 tpr4; 50 | u32 tpr5; 51 | u32 emr1; 52 | u32 emr2; 53 | u32 emr3; 54 | }; 55 | 56 | #define DEVMEM_FILE "/dev/mem" 57 | static int devmem_fd; 58 | 59 | enum sunxi_soc_version { 60 | SUNXI_SOC_SUN4I = 0x1623, /* A10 */ 61 | SUNXI_SOC_SUN5I = 0x1625, /* A13, A10s */ 62 | SUNXI_SOC_SUN6I = 0x1633, /* A31 */ 63 | SUNXI_SOC_SUN7I = 0x1651, /* A20 */ 64 | SUNXI_SOC_SUN8I = 0x1650, /* A23 */ 65 | SUNXI_SOC_SUN9I = 0x1667, /* A33 */ 66 | SUNXI_SOC_SUN10I = 0x1635, /* A80 */ 67 | }; 68 | 69 | static enum sunxi_soc_version soc_version; 70 | 71 | /* 72 | * Libv's favourite register handling calls. 73 | */ 74 | unsigned int 75 | sunxi_io_read(void *base, int offset) 76 | { 77 | return inl((unsigned long) (base + offset)); 78 | } 79 | 80 | void 81 | sunxi_io_write(void *base, int offset, unsigned int value) 82 | { 83 | outl(value, (unsigned long) (base + offset)); 84 | } 85 | 86 | void 87 | sunxi_io_mask(void *base, int offset, unsigned int value, unsigned int mask) 88 | { 89 | unsigned int tmp = inl((unsigned long) (base + offset)); 90 | 91 | tmp &= ~mask; 92 | tmp |= value & mask; 93 | 94 | outl(tmp, (unsigned long) (base + offset)); 95 | } 96 | 97 | 98 | /* 99 | * Find out exactly which SoC we are dealing with. 100 | */ 101 | #define SUNXI_IO_SRAM_BASE 0x01C00000 102 | #define SUNXI_IO_SRAM_SIZE 0x00001000 103 | 104 | #define SUNXI_IO_SRAM_VERSION 0x24 105 | 106 | static int 107 | soc_version_read(void) 108 | { 109 | void *base; 110 | unsigned int restore; 111 | 112 | base = mmap(NULL, SUNXI_IO_SRAM_SIZE, PROT_READ|PROT_WRITE, 113 | MAP_SHARED, devmem_fd, SUNXI_IO_SRAM_BASE); 114 | if (base == MAP_FAILED) { 115 | fprintf(stderr, "Failed to map sram registers: %s\n", 116 | strerror(errno)); 117 | return errno; 118 | } 119 | 120 | restore = sunxi_io_read(base, SUNXI_IO_SRAM_VERSION); 121 | 122 | sunxi_io_mask(base, SUNXI_IO_SRAM_VERSION, 0x8000, 0x8000); 123 | 124 | soc_version = sunxi_io_read(base, SUNXI_IO_SRAM_VERSION) >> 16; 125 | 126 | sunxi_io_mask(base, SUNXI_IO_SRAM_VERSION, restore, 0x8000); 127 | 128 | munmap(base, SUNXI_IO_SRAM_SIZE); 129 | 130 | return 0; 131 | } 132 | 133 | /* 134 | * Read DRAM clock. 135 | */ 136 | #define SUNXI_IO_CCM_BASE 0x01C20000 137 | #define SUNXI_IO_CCM_SIZE 0x00001000 138 | 139 | #define SUNXI_IO_CCM_PLL5_CFG 0x20 140 | 141 | static int 142 | sunxi_dram_clock_read(unsigned int *clock) 143 | { 144 | void *base; 145 | unsigned int tmp; 146 | int n, k, m; 147 | 148 | base = mmap(NULL, SUNXI_IO_CCM_SIZE, PROT_READ, 149 | MAP_SHARED, devmem_fd, SUNXI_IO_CCM_BASE); 150 | if (base == MAP_FAILED) { 151 | fprintf(stderr, "Failed to map ccm registers: %s\n", 152 | strerror(errno)); 153 | return errno; 154 | } 155 | 156 | tmp = sunxi_io_read(base, SUNXI_IO_CCM_PLL5_CFG); 157 | 158 | munmap(base, SUNXI_IO_CCM_SIZE); 159 | 160 | n = (tmp >> 8) & 0x1F; 161 | k = ((tmp >> 4) & 0x03) + 1; 162 | m = (tmp & 0x03) + 1; 163 | 164 | switch (soc_version) { 165 | case SUNXI_SOC_SUN6I: 166 | case SUNXI_SOC_SUN8I: 167 | n++; 168 | break; 169 | default: 170 | break; 171 | } 172 | 173 | *clock = (24 * n * k) / m; 174 | 175 | return 0; 176 | } 177 | 178 | struct regs { 179 | int offset; 180 | char *name; 181 | }; 182 | 183 | static int 184 | dram_registers_print(unsigned int address, int size, const struct regs *regs, 185 | const char *description, const char *prefix) 186 | { 187 | void *base; 188 | int i, j; 189 | 190 | base = mmap(NULL, size, PROT_READ, MAP_SHARED, devmem_fd, address); 191 | if (base == MAP_FAILED) { 192 | fprintf(stderr, "Failed to map %s registers: %s\n", 193 | description, strerror(errno)); 194 | return errno; 195 | } 196 | 197 | printf("/*\n"); 198 | printf(" * %s Registers\n", description); 199 | printf(" */\n"); 200 | 201 | for (i = 0; i < size; i += 4) { 202 | unsigned int reg = sunxi_io_read(base, i); 203 | 204 | for (j = 0; regs[j].name; j++) 205 | if (i == regs[j].offset) { 206 | printf("%s = 0x%08x;\n", regs[j].name, reg); 207 | } 208 | 209 | if (reg && !regs[j].name) 210 | printf("%s_%03X = 0x%08x;\n", prefix, i, reg); 211 | } 212 | 213 | printf("\n"); 214 | 215 | munmap(base, size); 216 | 217 | return 0; 218 | } 219 | 220 | static int 221 | dram_register_range_print(unsigned int address, int size, 222 | const char *description, const char *prefix) 223 | { 224 | void *base; 225 | int i; 226 | 227 | base = mmap(NULL, size, PROT_READ, MAP_SHARED, devmem_fd, address); 228 | if (base == MAP_FAILED) { 229 | fprintf(stderr, "Failed to map %s registers: %s\n", 230 | description, strerror(errno)); 231 | return errno; 232 | } 233 | 234 | printf("/*\n"); 235 | printf(" * %s Registers\n", description); 236 | printf(" */\n"); 237 | 238 | for (i = 0; i < size; i += 4) { 239 | unsigned int reg = sunxi_io_read(base, i); 240 | 241 | if (reg) 242 | printf("%s_%03X = 0x%08x;\n", prefix, i, reg); 243 | } 244 | 245 | printf("\n"); 246 | 247 | munmap(base, size); 248 | 249 | return 0; 250 | } 251 | 252 | /* 253 | * Read DRAM parameters. 254 | */ 255 | #define SUN4I_IO_DRAM_BASE 0x01C01000 256 | #define SUN4I_IO_DRAM_SIZE 0x00001000 257 | 258 | #define SUN4I_IO_DRAM_CCR 0x000 /* controller configuration register */ 259 | #define SUN4I_IO_DRAM_DCR 0x004 /* dram configuration */ 260 | #define SUN4I_IO_DRAM_IOCR 0x008 /* i/o configuration */ 261 | 262 | #define SUN4I_IO_DRAM_TPR0 0x014 /* dram timing parameters register 0 */ 263 | #define SUN4I_IO_DRAM_TPR1 0x018 /* dram timing parameters register 1 */ 264 | #define SUN4I_IO_DRAM_TPR2 0x01C /* dram timing parameters register 2 */ 265 | 266 | #define SUN4I_IO_DRAM_ZQCR0 0x0A8 /* zq control register 0 */ 267 | #define SUN4I_IO_DRAM_ZQCR1 0x0AC /* zq control register 1 */ 268 | 269 | #define SUN4I_IO_DRAM_MR 0x1F0 /* mode register */ 270 | #define SUN4I_IO_DRAM_EMR 0x1F4 /* extended mode register */ 271 | #define SUN4I_IO_DRAM_EMR2 0x1F8 /* extended mode register */ 272 | #define SUN4I_IO_DRAM_EMR3 0x1FC /* extended mode register */ 273 | 274 | #define SUN4I_IO_DRAM_DLLCR0 0x204 /* dll control register 0(byte 0) */ 275 | #define SUN4I_IO_DRAM_DLLCR1 0x208 /* dll control register 1(byte 1) */ 276 | #define SUN4I_IO_DRAM_DLLCR2 0x20C /* dll control register 2(byte 2) */ 277 | #define SUN4I_IO_DRAM_DLLCR3 0x210 /* dll control register 3(byte 3) */ 278 | #define SUN4I_IO_DRAM_DLLCR4 0x214 /* dll control register 4(byte 4) */ 279 | 280 | static int 281 | sun4i_dram_parameters_read(struct sun4i_dram_para *dram_para) 282 | { 283 | void *base; 284 | unsigned int zqcr0, dcr; 285 | unsigned int dllcr0, dllcr1, dllcr2, dllcr3, dllcr4; 286 | 287 | base = mmap(NULL, SUN4I_IO_DRAM_SIZE, PROT_READ, 288 | MAP_SHARED, devmem_fd, SUN4I_IO_DRAM_BASE); 289 | if (base == MAP_FAILED) { 290 | fprintf(stderr, "Failed to map dram registers: %s\n", 291 | strerror(errno)); 292 | return errno; 293 | } 294 | 295 | dram_para->tpr0 = sunxi_io_read(base, SUN4I_IO_DRAM_TPR0); 296 | dram_para->tpr1 = sunxi_io_read(base, SUN4I_IO_DRAM_TPR1); 297 | dram_para->tpr2 = sunxi_io_read(base, SUN4I_IO_DRAM_TPR2); 298 | 299 | dllcr0 = (sunxi_io_read(base, SUN4I_IO_DRAM_DLLCR0) >> 6) & 0x3F; 300 | dllcr1 = (sunxi_io_read(base, SUN4I_IO_DRAM_DLLCR1) >> 14) & 0x0F; 301 | dllcr2 = (sunxi_io_read(base, SUN4I_IO_DRAM_DLLCR2) >> 14) & 0x0F; 302 | dllcr3 = (sunxi_io_read(base, SUN4I_IO_DRAM_DLLCR3) >> 14) & 0x0F; 303 | dllcr4 = (sunxi_io_read(base, SUN4I_IO_DRAM_DLLCR4) >> 14) & 0x0F; 304 | 305 | dram_para->tpr3 = (dllcr0 << 16) | 306 | (dllcr4 << 12) | (dllcr3 << 8) | (dllcr2 << 4) | dllcr1; 307 | 308 | if (soc_version == SUNXI_SOC_SUN7I) { 309 | if (sunxi_io_read(base, SUN4I_IO_DRAM_CCR) & 0x20) 310 | dram_para->tpr4 |= 0x01; 311 | if (!(sunxi_io_read(base, SUN4I_IO_DRAM_ZQCR1) & 0x01000000)) 312 | dram_para->tpr4 |= 0x02; 313 | } 314 | 315 | dram_para->cas = (sunxi_io_read(base, SUN4I_IO_DRAM_MR) >> 4) & 0x0F; 316 | dram_para->emr1 = sunxi_io_read(base, SUN4I_IO_DRAM_EMR); 317 | dram_para->emr2 = sunxi_io_read(base, SUN4I_IO_DRAM_EMR2); 318 | dram_para->emr3 = sunxi_io_read(base, SUN4I_IO_DRAM_EMR3); 319 | 320 | dram_para->odt_en = sunxi_io_read(base, SUN4I_IO_DRAM_IOCR) & 0x03; 321 | zqcr0 = sunxi_io_read(base, SUN4I_IO_DRAM_ZQCR0); 322 | dram_para->zq = (zqcr0 & 0xf0000000) | 323 | ((zqcr0 >> 20) & 0xff) | 324 | ((zqcr0 & 0xfffff) << 8); 325 | 326 | dcr = sunxi_io_read(base, SUN4I_IO_DRAM_DCR); 327 | if (dcr & 0x01) { 328 | dram_para->cas += 4; 329 | dram_para->type = 3; 330 | } else 331 | dram_para->type = 2; 332 | 333 | dram_para->density = (1 << ((dcr >> 3) & 0x07)) * 256; 334 | dram_para->rank_num = ((dcr >> 10) & 0x03) + 1; 335 | dram_para->io_width = ((dcr >> 1) & 0x03) * 8; 336 | dram_para->bus_width = (((dcr >> 6) & 3) + 1) * 8; 337 | 338 | munmap(base, SUN4I_IO_DRAM_SIZE); 339 | 340 | return 0; 341 | } 342 | 343 | /* 344 | * Print a dram.c that can be stuck immediately into u-boot. 345 | */ 346 | void 347 | sun4i_dram_para_print_uboot(struct sun4i_dram_para *dram_para) 348 | { 349 | printf("// place this file in board/sunxi/ in u-boot\n"); 350 | printf("/* this file is generated, don't edit it yourself */\n"); 351 | printf("\n"); 352 | printf("#include \"common.h\"\n"); 353 | printf("#include \n"); 354 | printf("\n"); 355 | printf("static struct dram_para dram_para = {\n"); 356 | printf("\t.clock = %d,\n", dram_para->clock); 357 | printf("\t.type = %d,\n", dram_para->type); 358 | printf("\t.rank_num = %d,\n", dram_para->rank_num); 359 | printf("\t.density = %d,\n", dram_para->density); 360 | printf("\t.io_width = %d,\n", dram_para->io_width); 361 | printf("\t.bus_width = %d,\n", dram_para->bus_width); 362 | printf("\t.cas = %d,\n", dram_para->cas); 363 | printf("\t.zq = 0x%02x,\n", dram_para->zq); 364 | printf("\t.odt_en = %d,\n", dram_para->odt_en); 365 | printf("\t.size = !!! FIXME !!!, /* in MiB */\n"); 366 | printf("\t.tpr0 = 0x%08x,\n", dram_para->tpr0); 367 | printf("\t.tpr1 = 0x%04x,\n", dram_para->tpr1); 368 | printf("\t.tpr2 = 0x%05x,\n", dram_para->tpr2); 369 | printf("\t.tpr3 = 0x%02x,\n", dram_para->tpr3); 370 | printf("\t.tpr4 = 0x%02x,\n", dram_para->tpr4); 371 | printf("\t.tpr5 = 0x%02x,\n", dram_para->tpr5); 372 | printf("\t.emr1 = 0x%02x,\n", dram_para->emr1); 373 | printf("\t.emr2 = 0x%02x,\n", dram_para->emr2); 374 | printf("\t.emr3 = 0x%02x,\n", dram_para->emr3); 375 | printf("};\n"); 376 | printf("\n"); 377 | printf("unsigned long sunxi_dram_init(void)\n"); 378 | printf("{\n"); 379 | printf("\treturn dramc_init(&dram_para);\n"); 380 | printf("}\n"); 381 | } 382 | 383 | /* 384 | * Print output matching the .fex output, so it can be stuck in a 385 | * fex file directly. 386 | */ 387 | void 388 | sun4i_dram_para_print_fex(struct sun4i_dram_para *dram_para) 389 | { 390 | printf("; Insert this section into your .fex file\n"); 391 | printf("[dram_para]\n"); 392 | printf("dram_baseaddr = 0x40000000\n"); 393 | printf("dram_clk = %d\n", dram_para->clock); 394 | printf("dram_type = %d\n", dram_para->type); 395 | printf("dram_rank_num = %d\n", dram_para->rank_num); 396 | printf("dram_chip_density = %d\n", dram_para->density); 397 | printf("dram_io_width = %d\n", dram_para->io_width); 398 | printf("dram_bus_width = %d\n", dram_para->bus_width); 399 | printf("dram_cas = %d\n", dram_para->cas); 400 | printf("dram_zq = 0x%02x\n", dram_para->zq); 401 | printf("dram_odt_en = %d\n", dram_para->odt_en); 402 | printf("dram_size = !!! FIXME !!!\n"); 403 | printf("dram_tpr0 = 0x%08x\n", dram_para->tpr0); 404 | printf("dram_tpr1 = 0x%04x\n", dram_para->tpr1); 405 | printf("dram_tpr2 = 0x%05x\n", dram_para->tpr2); 406 | printf("dram_tpr3 = 0x%02x\n", dram_para->tpr3); 407 | printf("dram_tpr4 = 0x%02x\n", dram_para->tpr4); 408 | printf("dram_tpr5 = 0x%02x\n", dram_para->tpr5); 409 | printf("dram_emr1 = 0x%02x\n", dram_para->emr1); 410 | printf("dram_emr2 = 0x%02x\n", dram_para->emr2); 411 | printf("dram_emr3 = 0x%02x\n", dram_para->emr3); 412 | } 413 | 414 | static int 415 | sun4i_dram_para_print(bool uboot) 416 | { 417 | struct sun4i_dram_para dram_para = { .baseaddr = 0 }; 418 | int ret; 419 | 420 | ret = sunxi_dram_clock_read(&dram_para.clock); 421 | if (ret) 422 | return ret; 423 | 424 | ret = sun4i_dram_parameters_read(&dram_para); 425 | if (ret) 426 | return ret; 427 | 428 | if (uboot) 429 | sun4i_dram_para_print_uboot(&dram_para); 430 | else 431 | sun4i_dram_para_print_fex(&dram_para); 432 | 433 | return 0; 434 | } 435 | 436 | /* 437 | * 438 | */ 439 | #define SUN6I_IO_DRAMCOM_BASE 0x01C62000 440 | #define SUN6I_IO_DRAMCOM_SIZE 0x0300 441 | #define SUN6I_IO_DRAMCTL_BASE 0x01C63000 442 | #define SUN6I_IO_DRAMCTL_SIZE 0x0400 443 | #define SUN6I_IO_DRAMPHY_BASE 0x01C65000 444 | #define SUN6I_IO_DRAMPHY_SIZE 0x0400 445 | 446 | static struct regs 447 | sun6i_dramcom_regs[] = { 448 | {0x00, "SDR_COM_CR"}, 449 | {0x04, "SDR_COM_CCR"}, 450 | {0x10, "SDR_COM_MFACR"}, 451 | {0x30, "SDR_COM_MSACR"}, 452 | {0x50, "SDR_COM_MBACR"}, 453 | {0, NULL} 454 | }; 455 | 456 | static struct regs 457 | sun6i_dramctl_regs[] = { 458 | {0x004, "SDR_SCTL"}, 459 | {0x008, "SDR_SSTAT"}, 460 | {0x040, "SDR_MCMD"}, 461 | {0x04c, "SDR_CMDSTAT"}, 462 | {0x050, "SDR_CMDSTATEN"}, 463 | {0x060, "SDR_MRRCFG0"}, 464 | {0x064, "SDR_MRRSTAT0"}, 465 | {0x068, "SDR_MRRSTAT1"}, 466 | {0x07c, "SDR_MCFG1"}, 467 | {0x080, "SDR_MCFG"}, 468 | {0x084, "SDR_PPCFG"}, 469 | {0x088, "SDR_MSTAT"}, 470 | {0x08c, "SDR_LP2ZQCFG"}, 471 | {0x094, "SDR_DTUSTAT"}, 472 | {0x098, "SDR_DTUNA"}, 473 | {0x09c, "SDR_DTUNE"}, 474 | {0x0a0, "SDR_DTUPRD0"}, 475 | {0x0a4, "SDR_DTUPRD1"}, 476 | {0x0a8, "SDR_DTUPRD2"}, 477 | {0x0ac, "SDR_DTUPRD3"}, 478 | {0x0b0, "SDR_DTUAWDT"}, 479 | {0x0c0, "SDR_TOGCNT1U"}, 480 | {0x0cc, "SDR_TOGCNT100N"}, 481 | {0x0d0, "SDR_TREFI"}, 482 | {0x0d4, "SDR_TMRD"}, 483 | {0x0d8, "SDR_TRFC"}, 484 | {0x0dc, "SDR_TRP"}, 485 | {0x0e0, "SDR_TRTW"}, 486 | {0x0e4, "SDR_TAL"}, 487 | {0x0e8, "SDR_TCL"}, 488 | {0x0ec, "SDR_TCWL"}, 489 | {0x0f0, "SDR_TRAS"}, 490 | {0x0f4, "SDR_TRC"}, 491 | {0x0f8, "SDR_TRCD"}, 492 | {0x0fc, "SDR_TRRD"}, 493 | {0x100, "SDR_TRTP"}, 494 | {0x104, "SDR_TWR"}, 495 | {0x108, "SDR_TWTR"}, 496 | {0x10c, "SDR_TEXSR"}, 497 | {0x110, "SDR_TXP"}, 498 | {0x114, "SDR_TXPDLL"}, 499 | {0x118, "SDR_TZQCS"}, 500 | {0x11c, "SDR_TZQCSI"}, 501 | {0x120, "SDR_TDQS"}, 502 | {0x124, "SDR_TCKSRE"}, 503 | {0x128, "SDR_TCKSRX"}, 504 | {0x12c, "SDR_TCKE"}, 505 | {0x130, "SDR_TMOD"}, 506 | {0x134, "SDR_TRSTL"}, 507 | {0x138, "SDR_TZQCL"}, 508 | {0x13c, "SDR_TMRR"}, 509 | {0x140, "SDR_TCKESR"}, 510 | {0x144, "SDR_TDPD"}, 511 | {0x200, "SDR_DTUWACTL"}, 512 | {0x204, "SDR_DTURACTL"}, 513 | {0x208, "SDR_DTUCFG"}, 514 | {0x20c, "SDR_DTUECTL"}, 515 | {0x210, "SDR_DTUWD0"}, 516 | {0x214, "SDR_DTUWD1"}, 517 | {0x218, "SDR_DTUWD2"}, 518 | {0x21c, "SDR_DTUWD3"}, 519 | {0x220, "SDR_DTUWDM"}, 520 | {0x224, "SDR_DTURD0"}, 521 | {0x224, "SDR_DTURD1"}, 522 | {0x22c, "SDR_DTURD2"}, 523 | {0x230, "SDR_DTURD3"}, 524 | {0x234, "SDR_DTULFSRWD"}, 525 | {0x238, "SDR_DTULFSRRD"}, 526 | {0x23c, "SDR_DTUEAF"}, 527 | {0x240, "SDR_DFITCTLDLY"}, 528 | {0x244, "SDR_DFIODTCFG"}, 529 | {0x248, "SDR_DFIODTCFG1"}, 530 | {0x24c, "SDR_DFIODTRMAP"}, 531 | {0x250, "SDR_DFITPHYWRD"}, 532 | {0x254, "SDR_DFITPHYWRL"}, 533 | {0x260, "SDR_DFITRDDEN"}, 534 | {0x264, "SDR_DFITPHYRDL"}, 535 | {0x270, "SDR_DFITPHYUPDTYPE0"}, 536 | {0x274, "SDR_DFITPHYUPDTYPE1"}, 537 | {0x278, "SDR_DFITPHYUPDTYPE2"}, 538 | {0x27c, "SDR_DFITPHYUPDTYPE3"}, 539 | {0x280, "SDR_DFITCTRLUPDMIN"}, 540 | {0x284, "SDR_DFITCTRLUPDMAX"}, 541 | {0x288, "SDR_DFITCTRLUPDDLY"}, 542 | {0x290, "SDR_DFIUPDCFG"}, 543 | {0x294, "SDR_DFITREFMSKI"}, 544 | {0x298, "SDR_DFITCRLUPDI"}, 545 | {0x2ac, "SDR_DFITRCFG0"}, 546 | {0x2b0, "SDR_DFITRSTAT0"}, 547 | {0x2b4, "SDR_DFITRWRLVLEN"}, 548 | {0x2b8, "SDR_DFITRRDLVLEN"}, 549 | {0x2bc, "SDR_DFITRRDLVLGATEEN"}, 550 | {0x2c4, "SDR_DFISTCFG0"}, 551 | {0x2c8, "SDR_DFISTCFG1"}, 552 | {0x2d0, "SDR_DFITDRAMCLKEN"}, 553 | {0x2d4, "SDR_DFITDRAMCLKDIS"}, 554 | {0x2f0, "SDR_DFILPCFG0"}, 555 | {0, NULL} 556 | }; 557 | 558 | static struct regs 559 | sun6i_dramphy_regs[] = { 560 | {0x004, "SDR_PIR"}, 561 | {0x008, "SDR_PGCR"}, 562 | {0x00c, "SDR_PGSR"}, 563 | {0x010, "SDR_DLLGCR"}, 564 | {0x014, "SDR_ACDLLCR"}, 565 | {0x018, "SDR_PTR0"}, 566 | {0x01c, "SDR_PTR1"}, 567 | {0x020, "SDR_PTR2"}, 568 | {0x024, "SDR_ACIOCR"}, 569 | {0x028, "SDR_DXCCR"}, 570 | {0x02c, "SDR_DSGCR"}, 571 | {0x030, "SDR_DCR"}, 572 | {0x034, "SDR_DTPR0"}, 573 | {0x038, "SDR_DTPR1"}, 574 | {0x03c, "SDR_DTPR2"}, 575 | {0x040, "SDR_MR0"}, 576 | {0x044, "SDR_MR1"}, 577 | {0x048, "SDR_MR2"}, 578 | {0x04c, "SDR_MR3"}, 579 | {0x050, "SDR_ODTCR"}, 580 | {0x054, "SDR_DTAR"}, 581 | {0x058, "SDR_DTDT0"}, 582 | {0x05c, "SDR_DTDT1"}, 583 | {0x0c0, "SDR_DCUAR"}, 584 | {0x0c4, "SDR_DCUDR"}, 585 | {0x0c8, "SDR_DCURR"}, 586 | {0x0cc, "SDR_DCULR"}, 587 | {0x0d0, "SDR_DCUGCR"}, 588 | {0x0d4, "SDR_DCUTPR"}, 589 | {0x0d8, "SDR_DCUSR0"}, 590 | {0x0dc, "SDR_DCUSR1"}, 591 | {0x100, "SDR_BISTRR"}, 592 | {0x104, "SDR_BISTMSKR0"}, 593 | {0x108, "SDR_BISTMSKR1"}, 594 | {0x10c, "SDR_BISTWCR"}, 595 | {0x110, "SDR_BISTLSR"}, 596 | {0x114, "SDR_BISTAR0"}, 597 | {0x118, "SDR_BISTAR1"}, 598 | {0x11c, "SDR_BISTAR2"}, 599 | {0x120, "SDR_BISTUDPR"}, 600 | {0x124, "SDR_BISTGSR"}, 601 | {0x128, "SDR_BISTWER"}, 602 | {0x12c, "SDR_BISTBER0"}, 603 | {0x130, "SDR_BISTBER1"}, 604 | {0x134, "SDR_BISTBER2"}, 605 | {0x138, "SDR_BISTWCSR"}, 606 | {0x13c, "SDR_BISTFWR0"}, 607 | {0x140, "SDR_BISTFWR1"}, 608 | {0x180, "SDR_ZQ0CR0"}, 609 | {0x184, "SDR_ZQ0CR1"}, 610 | {0x188, "SDR_ZQ0SR0"}, 611 | {0x18c, "SDR_ZQ0SR1"}, 612 | {0x1c0, "SDR_DX0GCR"}, 613 | {0x1c4, "SDR_DX0GSR0"}, 614 | {0x1c8, "SDR_DX0GSR1"}, 615 | {0x1cc, "SDR_DX0DLLCR"}, 616 | {0x1d0, "SDR_DX0DQTR"}, 617 | {0x1d4, "SDR_DX0DQSTR"}, 618 | {0x200, "SDR_DX1GCR"}, 619 | {0x204, "SDR_DX1GSR0"}, 620 | {0x208, "SDR_DX1GSR1"}, 621 | {0x20c, "SDR_DX1DLLCR"}, 622 | {0x210, "SDR_DX1DQTR"}, 623 | {0x214, "SDR_DX1DQSTR"}, 624 | {0x240, "SDR_DX2GCR"}, 625 | {0x244, "SDR_DX2GSR0"}, 626 | {0x248, "SDR_DX2GSR1"}, 627 | {0x24c, "SDR_DX2DLLCR"}, 628 | {0x250, "SDR_DX2DQTR"}, 629 | {0x254, "SDR_DX2DQSTR"}, 630 | {0x280, "SDR_DX3GCR"}, 631 | {0x284, "SDR_DX3GSR0"}, 632 | {0x288, "SDR_DX3GSR1"}, 633 | {0x28c, "SDR_DX3DLLCR"}, 634 | {0x290, "SDR_DX3DQTR"}, 635 | {0x294, "SDR_DX3DQSTR"}, 636 | {0, NULL} 637 | }; 638 | 639 | static int 640 | sun6i_dram_regs_print(void) 641 | { 642 | unsigned int clock; 643 | int ret; 644 | 645 | ret = sunxi_dram_clock_read(&clock); 646 | if (ret) 647 | return ret; 648 | 649 | printf("DRAM Clock: %dMHz\n", clock); 650 | 651 | ret = dram_registers_print(SUN6I_IO_DRAMCOM_BASE, 652 | SUN6I_IO_DRAMCOM_SIZE, 653 | &sun6i_dramcom_regs[0], 654 | "DRAM COM", "SDR_COM"); 655 | if (ret) 656 | return ret; 657 | 658 | ret = dram_registers_print(SUN6I_IO_DRAMCTL_BASE, 659 | SUN6I_IO_DRAMCTL_SIZE, 660 | &sun6i_dramctl_regs[0], 661 | "DRAM CTL", "SDR_CTL"); 662 | if (ret) 663 | return ret; 664 | 665 | ret = dram_registers_print(SUN6I_IO_DRAMPHY_BASE, 666 | SUN6I_IO_DRAMPHY_SIZE, 667 | &sun6i_dramphy_regs[0], 668 | "DRAM PHY", "SDR_PHY"); 669 | if (ret) 670 | return ret; 671 | 672 | return 0; 673 | } 674 | 675 | /* 676 | * 677 | */ 678 | static int 679 | sun8i_dram_regs_print(void) 680 | { 681 | unsigned int clock; 682 | int ret; 683 | 684 | ret = sunxi_dram_clock_read(&clock); 685 | if (ret) 686 | return ret; 687 | 688 | printf("DRAM Clock: %dMHz\n", clock); 689 | 690 | ret = dram_register_range_print(SUN6I_IO_DRAMCOM_BASE, 691 | SUN6I_IO_DRAMCOM_SIZE, 692 | "DRAM COM", "SDR_COM"); 693 | if (ret) 694 | return ret; 695 | 696 | 697 | ret = dram_register_range_print(SUN6I_IO_DRAMCTL_BASE, 698 | SUN6I_IO_DRAMCTL_SIZE, 699 | "DRAM CTL", "SDR_CTL"); 700 | if (ret) 701 | return ret; 702 | 703 | ret = dram_register_range_print(SUN6I_IO_DRAMPHY_BASE, 704 | SUN6I_IO_DRAMPHY_SIZE, 705 | "DRAM PHY", "SDR_PHY"); 706 | if (ret) 707 | return ret; 708 | 709 | return 0; 710 | } 711 | 712 | static void 713 | print_usage(const char *name) 714 | { 715 | puts("sunxi-meminfo " VERSION "\n"); 716 | printf("Utility to retrieve DRAM information from registers on " 717 | "Allwinner SoCs.\n"); 718 | printf("\n"); 719 | printf("This is part of the sunxi-tools package from the sunxi " 720 | "project. "); 721 | printf("For more \ninformation visit " 722 | "http://linux-sunxi.org/Sunxi-tools.\n"); 723 | printf("\n"); 724 | printf("Usage: %s [OPTION]\n", name); 725 | printf("\n"); 726 | printf("Options:\n"); 727 | printf(" -f: print in FEX format (default).\n"); 728 | printf(" -u: print in sunxi U-Boot dram.c file format.\n"); 729 | printf(" -h: print this usage information.\n"); 730 | } 731 | 732 | int 733 | main(int argc, char *argv[]) 734 | { 735 | bool uboot; 736 | int ret; 737 | 738 | if (argc == 2) { 739 | if (argv[1][0] == '-') { 740 | if (argv[1][1] == 'f') 741 | uboot = false; 742 | else if (argv[1][1] == 'u') 743 | uboot = true; 744 | else if (argv[1][1] == 'h') 745 | goto help; 746 | else if ((argv[1][1] == '-') && (argv[1][2] == 'h')) 747 | goto help; 748 | else 749 | goto usage; 750 | 751 | if (argv[1][2] != 0) 752 | goto usage; 753 | } else 754 | goto usage; 755 | } else if (argc == 1) 756 | uboot = false; 757 | else 758 | goto usage; 759 | 760 | devmem_fd = open(DEVMEM_FILE, O_RDWR); 761 | if (devmem_fd == -1) { 762 | fprintf(stderr, "Error: failed to open %s: %s\n", DEVMEM_FILE, 763 | strerror(errno)); 764 | return errno; 765 | } 766 | 767 | ret = soc_version_read(); 768 | if (ret) 769 | return ret; 770 | switch (soc_version) { 771 | case SUNXI_SOC_SUN4I: 772 | case SUNXI_SOC_SUN5I: 773 | case SUNXI_SOC_SUN7I: 774 | return sun4i_dram_para_print(uboot); 775 | case SUNXI_SOC_SUN6I: 776 | return sun6i_dram_regs_print(); 777 | case SUNXI_SOC_SUN8I: 778 | return sun8i_dram_regs_print(); 779 | default: 780 | fprintf(stderr, "Error: unknown or unhandled Soc: 0x%04X\n", 781 | soc_version); 782 | return -1; 783 | } 784 | 785 | usage: 786 | fprintf(stderr, "Error: wrong argument(s).\n"); 787 | print_usage(argv[0]); 788 | return EINVAL; 789 | help: 790 | print_usage(argv[0]); 791 | return 0; 792 | } 793 | -------------------------------------------------------------------------------- /nand-common.h: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2013 3 | * Patrick H Wood, All rights reserved. 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License as 7 | * published by the Free Software Foundation; either version 2 of 8 | * the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 18 | * MA 02111-1307 USA 19 | * 20 | */ 21 | 22 | #include "types.h" 23 | 24 | extern int nand_part_a10 (int argc, char **argv, const char *cmd, int fd, int force); 25 | extern int nand_part_a20 (int argc, char **argv, const char *cmd, int fd, int force); 26 | extern int checkmbrs_a10 (int fd); 27 | extern int checkmbrs_a20 (int fd); 28 | extern void usage (const char *cmd); 29 | extern __u32 calc_crc32(void * buffer, __u32 length); 30 | -------------------------------------------------------------------------------- /nand-part-a10.h: -------------------------------------------------------------------------------- 1 | /* 2 | * drivers/block/sun4i_nand/nfd/mbr.h 3 | * 4 | * (C) Copyright 2007-2012 5 | * Allwinner Technology Co., Ltd. 6 | * 7 | * This program is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation; either version 2 of 10 | * the License, or (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 20 | * MA 02111-1307 USA 21 | */ 22 | 23 | #ifndef __MBR_H__ 24 | #define __MBR_H__ 25 | 26 | #include "types.h" 27 | 28 | #define MBR_MAGIC "softw311" 29 | #define MBR_VERSION 0x100 30 | #define nand_part nand_part_a10 31 | #define checkmbrs checkmbrs_a10 32 | 33 | #define MAX_PART_COUNT 15 //max part count 34 | #define MBR_COPY_NUM 4 //mbr backup count 35 | 36 | #define MBR_START_ADDRESS 0x0 //mbr start address 37 | #define MBR_SIZE 1024 //mbr size 38 | #define MBR_RESERVED (MBR_SIZE - 20 - (MAX_PART_COUNT * 64)) //mbr reserved space 39 | 40 | // extern struct __NandDriverGlobal_t NandDriverInfo; 41 | 42 | // extern struct __NandStorageInfo_t NandStorageInfo; 43 | 44 | #define DiskSize (SECTOR_CNT_OF_SINGLE_PAGE * PAGE_CNT_OF_PHY_BLK * BLOCK_CNT_OF_DIE * \ 45 | DIE_CNT_OF_CHIP * NandStorageInfo.ChipCnt / 1024 * DATA_BLK_CNT_OF_ZONE) 46 | 47 | 48 | struct nand_disk{ 49 | unsigned long size; 50 | unsigned long offset; 51 | unsigned char type; 52 | }; 53 | 54 | /* part info */ 55 | typedef struct tag_PARTITION{ 56 | __u32 addrhi; //start address high 32 bit 57 | __u32 addrlo; //start address low 32 bit 58 | __u32 lenhi; //size high 32 bit 59 | __u32 lenlo; //size low 32 bit 60 | __u8 classname[12]; //major device name 61 | __u8 name[12]; //minor device name 62 | unsigned int user_type; //标志当前盘符所属于的用户 63 | unsigned int ro; //标志当前盘符的读写属性 64 | __u8 res[16]; //reserved 65 | }PARTITION; 66 | 67 | /* mbr info */ 68 | typedef struct tag_MBR{ 69 | __u32 crc32; // crc, from byte 4 to mbr tail 70 | __u32 version; // version 71 | __u8 magic[8]; // magic number 72 | __u8 copy; // mbr backup count 73 | __u8 index; // current part no 74 | __u16 PartCount; // part counter 75 | PARTITION array[MAX_PART_COUNT];// part info 76 | __u8 res[MBR_RESERVED]; // reserved space 77 | }MBR; 78 | 79 | int mbr2disks(struct nand_disk* disk_array); 80 | 81 | #endif //__MBR_H__ 82 | -------------------------------------------------------------------------------- /nand-part-a20.h: -------------------------------------------------------------------------------- 1 | /* 2 | * drivers/block/sun4i_nand/nfd/mbr.h 3 | * 4 | * (C) Copyright 2007-2012 5 | * Allwinner Technology Co., Ltd. 6 | * 7 | * This program is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation; either version 2 of 10 | * the License, or (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 20 | * MA 02111-1307 USA 21 | */ 22 | 23 | #ifndef __MBR_H__ 24 | #define __MBR_H__ 25 | 26 | #include "types.h" 27 | 28 | #define MBR_MAGIC "softw411" 29 | #define MBR_VERSION 0x200 30 | #define nand_part nand_part_a20 31 | #define checkmbrs checkmbrs_a20 32 | 33 | #define MAX_PART_COUNT 120 //max part count 34 | #define MBR_COPY_NUM 4 //mbr backup count 35 | 36 | #define MBR_START_ADDRESS 0x0 //mbr start address 37 | #define MBR_SIZE 1024*16 //mbr size 38 | #define MBR_RESERVED (MBR_SIZE - 32 - (MAX_PART_COUNT * 128)) //mbr reserved space 39 | 40 | // extern struct __NandDriverGlobal_t NandDriverInfo; 41 | 42 | // extern struct __NandStorageInfo_t NandStorageInfo; 43 | 44 | #define DiskSize (SECTOR_CNT_OF_SINGLE_PAGE * PAGE_CNT_OF_PHY_BLK * BLOCK_CNT_OF_DIE * \ 45 | DIE_CNT_OF_CHIP * NandStorageInfo.ChipCnt / 1024 * DATA_BLK_CNT_OF_ZONE) 46 | 47 | 48 | struct nand_disk{ 49 | unsigned long size; 50 | unsigned long offset; 51 | unsigned char type; 52 | }; 53 | 54 | /* part info */ 55 | typedef struct nand_tag_PARTITION{ 56 | unsigned int addrhi; //起始地址, 以扇区为单位 57 | unsigned int addrlo; // 58 | unsigned int lenhi; //长度 59 | unsigned int lenlo; // 60 | unsigned char classname[16]; //次设备名 61 | unsigned char name[16]; //主设备名 62 | unsigned int user_type; //用户类型 63 | unsigned int keydata; //关键数据,要求量产不丢失 64 | unsigned int ro; //读写属性 65 | unsigned char res[68]; //保留数据,匹配分区信息128字节 66 | }__attribute__ ((packed))PARTITION; 67 | 68 | /* mbr info */ 69 | typedef struct nand_tag_MBR{ 70 | unsigned int crc32; // crc 1k - 4 71 | unsigned int version; // 版本信息, 0x00000100 72 | unsigned char magic[8]; //"softw411" 73 | unsigned int copy; //分数 74 | unsigned int index; //第几个MBR备份 75 | unsigned int PartCount; //分区个数 76 | unsigned int stamp[1]; //对齐 77 | PARTITION array[MAX_PART_COUNT]; // 78 | unsigned char res[MBR_RESERVED]; 79 | }__attribute__ ((packed)) MBR; 80 | 81 | int mbr2disks(struct nand_disk* disk_array); 82 | 83 | #endif //__MBR_H__ 84 | -------------------------------------------------------------------------------- /nand-part-main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2013 3 | * Patrick H Wood, All rights reserved. 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License as 7 | * published by the Free Software Foundation; either version 2 of 8 | * the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 18 | * MA 02111-1307 USA 19 | * 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include "nand-common.h" 27 | #include "common.h" 28 | 29 | void usage(const char *cmd) 30 | { 31 | puts("sunxi-nand-part " VERSION "\n"); 32 | printf("usage: %s [-f a10|a20] nand-device\n", cmd); 33 | printf(" %s nand-device 'name2 len2 [usertype2]' ['name3 len3 [usertype3]'] ...\n", cmd); 34 | printf(" %s [-f a10|a20] nand-device start1 'name1 len1 [usertype1]' ['name2 len2 [usertype2]'] ...\n", cmd); 35 | } 36 | 37 | typedef struct tag_CRC32_DATA 38 | { 39 | __u32 CRC; //int的大小是32位 40 | __u32 CRC_32_Tbl[256]; //用来保存码表 41 | }CRC32_DATA_t; 42 | 43 | __u32 calc_crc32(void * buffer, __u32 length) 44 | { 45 | __u32 i, j; 46 | CRC32_DATA_t crc32; // 47 | __u32 CRC32 = 0xffffffff; //设置初始值 48 | crc32.CRC = 0; 49 | 50 | for( i = 0; i < 256; ++i)//用++i以提高效率 51 | { 52 | crc32.CRC = i; 53 | for( j = 0; j < 8 ; ++j) 54 | { 55 | //这个循环实际上就是用"计算法"来求取CRC的校验码 56 | if(crc32.CRC & 1) 57 | crc32.CRC = (crc32.CRC >> 1) ^ 0xEDB88320; 58 | else //0xEDB88320就是CRC-32多项表达式的值 59 | crc32.CRC >>= 1; 60 | } 61 | crc32.CRC_32_Tbl[i] = crc32.CRC; 62 | } 63 | 64 | CRC32 = 0xffffffff; //设置初始值 65 | for( i = 0; i < length; ++i) 66 | { 67 | CRC32 = crc32.CRC_32_Tbl[(CRC32^((unsigned char*)buffer)[i]) & 0xff] ^ (CRC32>>8); 68 | } 69 | //return CRC32; 70 | return CRC32^0xffffffff; 71 | } 72 | 73 | int main (int argc, char **argv) 74 | { 75 | char *nand = "/dev/nand"; 76 | const char *cmd = argv[0]; 77 | int fd; 78 | int force = 0; // force write even if magics and CRCs don't match 79 | 80 | argc--; 81 | argv++; 82 | 83 | if (argc > 1) { 84 | if (!strcmp(argv[0], "-f")) { 85 | if (!strcasecmp(argv[1], "a10")) 86 | force = 10; 87 | else if (!strcasecmp(argv[1], "a20")) 88 | force = 20; 89 | else { 90 | usage(cmd); 91 | return -1; 92 | } 93 | argc -= 2; 94 | argv += 2; 95 | } 96 | } 97 | 98 | if (argc > 0) { 99 | nand = argv[0]; 100 | argc--; 101 | argv++; 102 | } 103 | fd = open(nand, O_RDWR); 104 | if (fd < 0) { 105 | usage(cmd); 106 | return -2; 107 | } 108 | if (force == 10) 109 | return nand_part_a10 (argc, argv, cmd, fd, force); 110 | if (force == 20) 111 | return nand_part_a20 (argc, argv, cmd, fd, force); 112 | 113 | if (checkmbrs_a10(fd)) 114 | return nand_part_a10 (argc, argv, cmd, fd, force); 115 | if (checkmbrs_a20(fd)) 116 | return nand_part_a20 (argc, argv, cmd, fd, force); 117 | } 118 | -------------------------------------------------------------------------------- /nand-part.c: -------------------------------------------------------------------------------- 1 | /* 2 | * mbr.c 3 | * (C) Copyright 2012 4 | * Patrick H Wood, All rights reserved. 5 | * Heavily modified from the Allwinner file drivers/block/sun4i_nand/nfd/mbr.c. 6 | * (Allwinner copyright block retained below.) 7 | * 8 | * This program is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU General Public License as 10 | * published by the Free Software Foundation; either version 2 of 11 | * the License, or (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program; if not, write to the Free Software 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 21 | * MA 02111-1307 USA 22 | * 23 | */ 24 | 25 | /* 26 | * drivers/block/sun4i_nand/nfd/mbr.c 27 | * (C) Copyright 2007-2012 28 | * Allwinner Technology Co., Ltd. 29 | * 30 | * This program is free software; you can redistribute it and/or 31 | * modify it under the terms of the GNU General Public License as 32 | * published by the Free Software Foundation; either version 2 of 33 | * the License, or (at your option) any later version. 34 | * 35 | * This program is distributed in the hope that it will be useful, 36 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 37 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 38 | * GNU General Public License for more details. 39 | * 40 | * You should have received a copy of the GNU General Public License 41 | * along with this program; if not, write to the Free Software 42 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 43 | * MA 02111-1307 USA 44 | */ 45 | 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #ifdef __linux__ 54 | # include 55 | # include /* BLKRRPART */ 56 | #endif 57 | #include "nand-common.h" 58 | 59 | // so far, only known formats are for A10 and A20 60 | #if defined(A10) 61 | # include "nand-part-a10.h" 62 | #elif defined(A20) 63 | # include "nand-part-a20.h" 64 | #endif 65 | 66 | #define MAX_NAME 16 67 | 68 | static void printmbrheader(MBR *mbr) 69 | { 70 | printf("mbr: version 0x%08x, magic %8.8s\n", mbr->version, mbr->magic); 71 | } 72 | 73 | static MBR *_get_mbr(int fd, int mbr_num, int force) 74 | { 75 | MBR *mbr; 76 | 77 | /*request mbr space*/ 78 | mbr = malloc(sizeof(MBR)); 79 | if(mbr == NULL) 80 | { 81 | printf("%s : request memory fail\n",__FUNCTION__); 82 | return NULL; 83 | } 84 | 85 | /*get mbr from nand device*/ 86 | lseek(fd,MBR_START_ADDRESS + MBR_SIZE*mbr_num,SEEK_SET); 87 | if(read(fd,mbr,MBR_SIZE) == MBR_SIZE) 88 | { 89 | /*checksum*/ 90 | printf("check partition table copy %d: ", mbr_num); 91 | printmbrheader(mbr); 92 | if (force) { 93 | strncpy((char *)mbr->magic, MBR_MAGIC, 8); 94 | mbr->version = MBR_VERSION; 95 | return mbr; 96 | } 97 | if(strncmp((char *)mbr->magic, MBR_MAGIC, 8)) 98 | { 99 | printf("magic %8.8s is not %8s\n", mbr->magic, MBR_MAGIC); 100 | return NULL; 101 | } 102 | if(mbr->version != MBR_VERSION) 103 | { 104 | printf("version 0x%08x is not 0x%08x\n", mbr->version, MBR_VERSION); 105 | return NULL; 106 | } 107 | if(*(__u32 *)mbr == calc_crc32((__u32 *)mbr + 1,MBR_SIZE - 4)) 108 | { 109 | printf("OK\n"); 110 | return mbr; 111 | } 112 | printf("BAD!\n"); 113 | } 114 | return NULL; 115 | } 116 | 117 | static __s32 _free_mbr(MBR *mbr) 118 | { 119 | if(mbr) 120 | { 121 | free(mbr); 122 | mbr = 0; 123 | } 124 | 125 | return 0; 126 | } 127 | 128 | static void printmbr(MBR *mbr) 129 | { 130 | unsigned int part_cnt; 131 | 132 | printmbrheader(mbr); 133 | printf("%d partitions\n", mbr->PartCount); 134 | for(part_cnt = 0; part_cnt < mbr->PartCount && part_cnt < MAX_PART_COUNT; part_cnt++) 135 | { 136 | printf("partition %2d: class = %12s, name = %12s, partition start = %8d, partition size = %8d user_type=%d\n", 137 | part_cnt + 1, 138 | mbr->array[part_cnt].classname, 139 | mbr->array[part_cnt].name, 140 | mbr->array[part_cnt].addrlo, 141 | mbr->array[part_cnt].lenlo, 142 | mbr->array[part_cnt].user_type); 143 | } 144 | } 145 | int checkmbrs(int fd) 146 | { 147 | int i; 148 | MBR *mbrs[MBR_COPY_NUM]; 149 | MBR *mbr = NULL; 150 | 151 | memset((void *) mbrs, 0, sizeof(mbrs)); 152 | for (i = 0; i < MBR_COPY_NUM; i++) { 153 | mbrs[i] = _get_mbr(fd, i, 0); 154 | if (mbrs[i]) 155 | mbr = mbrs[i]; 156 | } 157 | if (!mbr) { 158 | printf("all partition tables are bad!\n"); 159 | for (i = 0; i < MBR_COPY_NUM; i++) { 160 | if (mbrs[i]) 161 | _free_mbr(mbrs[i]); 162 | } 163 | return 0; 164 | } 165 | 166 | printmbr(mbr); 167 | for (i = 0; i < MBR_COPY_NUM; i++) { 168 | if (mbrs[i]) 169 | _free_mbr(mbrs[i]); 170 | } 171 | return 1; 172 | } 173 | 174 | static int writembrs(int fd, char names[][MAX_NAME], __u32 start, __u32 *lens, unsigned int *user_types, int nparts, int partoffset, int force) 175 | { 176 | unsigned int part_cnt = 0; 177 | int i; 178 | char yn = 'n'; 179 | MBR *mbrs[MBR_COPY_NUM]; 180 | MBR *mbr = NULL; 181 | FILE *backup; 182 | 183 | memset((void *) mbrs, 0, sizeof(mbrs)); 184 | for (i = 0; i < MBR_COPY_NUM; i++) { 185 | mbrs[i] = _get_mbr(fd, i, force); 186 | if (mbrs[i]) 187 | mbr = mbrs[i]; 188 | } 189 | if (!mbr) { 190 | printf("all partition tables are bad!\n"); 191 | for (i = 0; i < MBR_COPY_NUM; i++) { 192 | if (mbrs[i]) 193 | _free_mbr(mbrs[i]); 194 | } 195 | return 0; 196 | } 197 | // back up mbr data 198 | backup = fopen("nand_mbr.backup", "w"); 199 | if (!backup) { 200 | printf("can't open nand_mbr.backup to back up mbr data\n"); 201 | for (i = 0; i < MBR_COPY_NUM; i++) { 202 | if (mbrs[i]) 203 | _free_mbr(mbrs[i]); 204 | } 205 | return 0; 206 | } 207 | 208 | fprintf(backup, "%d ", mbr->array[0].addrlo); 209 | for(part_cnt = 0; part_cnt < mbr->PartCount && part_cnt < MAX_PART_COUNT; part_cnt++) 210 | { 211 | fprintf(backup, "'%s %d %d' ", mbr->array[part_cnt].name, 212 | mbr->array[part_cnt].lenlo, mbr->array[part_cnt].user_type); 213 | } 214 | fprintf(backup, "\n"); 215 | fclose(backup); 216 | 217 | mbr->PartCount = nparts + partoffset; 218 | if (partoffset) 219 | start = mbr->array[0].addrlo + mbr->array[0].lenlo; 220 | for(i = 0; i < nparts; i++) { 221 | strcpy((char *)mbr->array[i+partoffset].name, names[i]); 222 | strcpy((char *)mbr->array[i+partoffset].classname, "DISK"); 223 | memset((void *) mbr->array[i+partoffset].res, 0, sizeof(mbr->array[i+partoffset].res)); 224 | mbr->array[i+partoffset].user_type = user_types[i]; 225 | mbr->array[i+partoffset].ro = 0; 226 | mbr->array[i+partoffset].addrhi = 0; 227 | mbr->array[i+partoffset].lenhi = 0; 228 | mbr->array[i+partoffset].addrlo = start; 229 | mbr->array[i+partoffset].lenlo = lens[i]; 230 | start += lens[i]; 231 | } 232 | 233 | printf("\nready to write new partition tables:\n"); 234 | printmbr(mbr); 235 | for (i = 0; i < MBR_COPY_NUM; i++) { 236 | if (mbrs[i]) 237 | _free_mbr(mbrs[i]); 238 | } 239 | printf("\nwrite new partition tables? (Y/N)\n"); 240 | read(0, &yn, 1); 241 | if (yn != 'Y' && yn != 'y') { 242 | printf("aborting\n"); 243 | return 0; 244 | } 245 | 246 | for (i = 0; i < MBR_COPY_NUM; i++) { 247 | mbr->index = i; 248 | // calculate new checksum 249 | *(__u32 *)mbr = calc_crc32((__u32 *)mbr + 1,MBR_SIZE - 4); 250 | lseek(fd,MBR_START_ADDRESS + MBR_SIZE*i,SEEK_SET); 251 | write(fd,mbr,MBR_SIZE); 252 | } 253 | 254 | #ifdef __linux__ 255 | if (ioctl(fd, BLKRRPART, NULL)) 256 | perror("Failed rereading partition table"); 257 | #endif 258 | 259 | return 1; 260 | } 261 | 262 | int nand_part (int argc, char **argv, const char *cmd, int fd, int force) 263 | { 264 | int partoffset = 0; 265 | int i; 266 | char names[MAX_PART_COUNT][MAX_NAME]; 267 | __u32 lens[MAX_PART_COUNT]; 268 | unsigned int user_types[MAX_PART_COUNT]; 269 | __u32 start; 270 | 271 | 272 | // parse name/len arguments 273 | memset((void *) user_types, 0, sizeof(user_types)); 274 | if (argc > 0) { 275 | if (sscanf(argv[0], "%u", &start) != 1) { 276 | partoffset++; 277 | if (force) { 278 | printf("if using -f, must set info for first partition\n"); 279 | usage(cmd); 280 | close(fd); 281 | return -3; 282 | } 283 | } 284 | else { 285 | argc--; 286 | argv++; 287 | } 288 | 289 | if (start < MBR_SIZE * MBR_COPY_NUM / 512) { 290 | printf("Partition 1 starting offset must be at least %d\n", MBR_SIZE * MBR_COPY_NUM / 512); 291 | close(fd); 292 | return -3; 293 | } 294 | 295 | for (i = 0; i < argc; i++) { 296 | if (sscanf(argv[i], "%s %d %d", names[i], &lens[i], &user_types[i]) < 2) { 297 | printf("bad 'name len' argument\n"); 298 | usage(cmd); 299 | close(fd); 300 | return -3; 301 | } 302 | } 303 | } 304 | 305 | checkmbrs(fd); 306 | 307 | if (argc > MAX_PART_COUNT - partoffset) { 308 | printf("too many partitions specified (MAX 14)\n"); 309 | usage(cmd); 310 | close(fd); 311 | return -2; 312 | } 313 | 314 | 315 | if (argc > 0) { 316 | if (writembrs(fd, names, start, lens, user_types, argc, partoffset, force)) { 317 | printf("\nverifying new partition tables:\n"); 318 | checkmbrs(fd); 319 | #ifdef __linux__ 320 | printf("rereading partition table... returned %d\n", ioctl(fd, BLKRRPART, 0)); 321 | #endif 322 | } 323 | } 324 | close(fd); 325 | 326 | return 0; 327 | } 328 | -------------------------------------------------------------------------------- /phoenix_info.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Henrik Nordstrom 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include "common.h" 24 | #include "portable_endian.h" 25 | 26 | struct phoenix_ptable { 27 | char signature[16]; /* "PHOENIX_CARD_IMG" */ 28 | unsigned int unknown1; /* 0x00200100 */ 29 | unsigned short parts; /* Number of partitions */ 30 | unsigned short unknown2; /* 0x0001 */ 31 | unsigned char pad[8]; 32 | struct phoenix_entry { 33 | unsigned int start; /* 512 bytes blocks */ 34 | unsigned int size; /* bytes */ 35 | unsigned int unknown; /* ???? */ 36 | unsigned int sig; /* "add\0" */ 37 | } part[62]; 38 | } ptable; 39 | 40 | static int save_part(struct phoenix_ptable *ptable, int part, const char *dest, FILE *in) 41 | { 42 | int l = strlen(dest) + 16; 43 | char outname[l]; 44 | FILE *out = stdout; 45 | char *buf = NULL; 46 | int ret = 0; 47 | snprintf(outname, l, dest, part); 48 | if (part > ptable->parts) { 49 | fprintf(stderr, "ERROR: Part index out of range\n"); 50 | return -1; 51 | } 52 | buf = malloc(ptable->part[part].size); 53 | if (!buf) 54 | goto err; 55 | if (strcmp(outname, "-") != 0) 56 | out = fopen(outname, "wb"); 57 | if (!out) 58 | goto err; 59 | if (fseek(in, ptable->part[part].start * 0x200, SEEK_SET) == -1) 60 | goto err; 61 | if (fread(buf, ptable->part[part].size, 1, in) != 1) 62 | goto err; 63 | if (fwrite(buf, ptable->part[part].size, 1, out) != 1) 64 | goto err; 65 | ret = 0; 66 | _exit: 67 | if (buf) 68 | free(buf); 69 | if (out != stdout) 70 | fclose(out); 71 | return ret; 72 | err: 73 | perror(NULL); 74 | ret = -1; 75 | goto _exit; 76 | } 77 | 78 | static void usage(char **argv) 79 | { 80 | puts("phoenix-info " VERSION "\n"); 81 | printf("Usage: %s [options] [phoenix_image]\n" 82 | " -v verbose\n" 83 | " -q quiet\n" 84 | " -p N part number\n" 85 | " -o X destination directory, file or pattern (%%d for part number)\n" 86 | " -s save all parts\n" 87 | , argv[0] 88 | ); 89 | } 90 | 91 | int main(int argc, char **argv) 92 | { 93 | int i; 94 | FILE *in = stdin; 95 | int verbose = 1; 96 | int save_parts = 0; 97 | int part = -1; 98 | int opt; 99 | const char *dest = "%d.img"; 100 | 101 | while ((opt = getopt(argc, argv, "vqso:p:?")) != -1) { 102 | switch(opt) { 103 | case 'v': 104 | verbose++; 105 | break; 106 | case 'q': 107 | if (verbose) 108 | verbose--; 109 | break; 110 | case 'o': 111 | dest = optarg; 112 | save_parts = 1; 113 | break; 114 | case 'p': 115 | save_parts = 1; 116 | part = atoi(optarg); 117 | break; 118 | case 's': 119 | save_parts = 1; 120 | break; 121 | default: 122 | usage(argv); 123 | exit(1); 124 | break; 125 | } 126 | } 127 | if (save_parts && !strchr(dest, '%')) { 128 | const char *t = dest; 129 | if (!*t) 130 | t = "./"; 131 | if (t[strlen(t)-1] == '/' || !part) { 132 | int l = strlen(t) + strlen("/%d.img") + 1; 133 | char *tmp = malloc(l); 134 | snprintf(tmp, l, "%s/%%d.img", optarg); 135 | t = tmp; 136 | } 137 | dest = t; 138 | } 139 | if (argc > optind + 1) { 140 | usage(argv); 141 | exit(1); 142 | } 143 | if (optind < argc ) { 144 | in = fopen(argv[optind], "rb"); 145 | } 146 | fseek(in, 0x1C00, SEEK_CUR); 147 | fread(&ptable, 1, 0x400, in); 148 | if (strncmp(ptable.signature, "PHOENIX_CARD_IMG", 16) != 0) { 149 | fprintf(stderr, "ERROR: Not a phoenix image\n"); 150 | exit(1); 151 | } 152 | if (verbose > 1) { 153 | printf("???? : %08x\n", le32toh(ptable.unknown1)); 154 | printf("Parts : %d\n", le16toh(ptable.parts)); 155 | printf("???? : %08x\n", le16toh(ptable.unknown2)); 156 | printf("pad : %02x%02x%02x%02x%02x%02x%02x%02x\n", ptable.pad[0], ptable.pad[1], ptable.pad[2], ptable.pad[3], ptable.pad[4], ptable.pad[5], ptable.pad[6], ptable.pad[7]); 157 | printf("\n"); 158 | } 159 | for (i = 0; i < le16toh(ptable.parts); i++) { 160 | if (verbose && (part == -1 || part == i)) { 161 | printf("part %d:\n", i); 162 | printf("\tstart: 0x%08x (%u / 0x%08x)\n", le32toh(ptable.part[i].start)*512, le32toh(ptable.part[i].start), le32toh(ptable.part[i].start)); 163 | printf("\tsize : %u\n", le32toh(ptable.part[i].size)); 164 | printf("\t?????: %08x\n", le32toh(ptable.part[i].unknown)); 165 | if (verbose > 1 || le32toh(ptable.part[i].sig) != 0x00646461) 166 | printf("\tsig??: %08x\n", le32toh(ptable.part[i].sig)); 167 | printf("\n"); 168 | } 169 | if (save_parts && (part == -1 || part == i)) { 170 | save_part(&ptable, i, dest, in); 171 | } 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /pio.c: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2011 Henrik Nordstrom 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License as 6 | * published by the Free Software Foundation; either version 2 of 7 | * the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 17 | * MA 02111-1307 USA 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #ifndef NO_MMAP 28 | #include 29 | #endif 30 | #include 31 | #include 32 | #include 33 | 34 | #include "common.h" 35 | #include "portable_endian.h" 36 | 37 | #define PIO_REG_SIZE 0x228 /*0x300*/ 38 | #define PIO_PORT_SIZE 0x24 39 | 40 | struct pio_status { 41 | int mul_sel; 42 | int pull; 43 | int drv_level; 44 | int data; 45 | }; 46 | 47 | #define PIO_REG_CFG(B, N, I) ((B) + (N)*0x24 + ((I)<<2) + 0x00) 48 | #define PIO_REG_DLEVEL(B, N, I) ((B) + (N)*0x24 + ((I)<<2) + 0x14) 49 | #define PIO_REG_PULL(B, N, I) ((B) + (N)*0x24 + ((I)<<2) + 0x1C) 50 | #define PIO_REG_DATA(B, N) ((B) + (N)*0x24 + 0x10) 51 | #define PIO_NR_PORTS 9 /* A-I */ 52 | 53 | #define LE32TOH(X) le32toh(*((uint32_t*)(X))) 54 | 55 | static int pio_get(const char *buf, uint32_t port, uint32_t port_num, struct pio_status *pio) 56 | { 57 | uint32_t val; 58 | uint32_t port_num_func, port_num_pull; 59 | uint32_t offset_func, offset_pull; 60 | 61 | port_num_func = port_num >> 3; 62 | offset_func = ((port_num & 0x07) << 2); 63 | 64 | port_num_pull = port_num >> 4; 65 | offset_pull = ((port_num & 0x0f) << 1); 66 | 67 | /* func */ 68 | val = LE32TOH(PIO_REG_CFG(buf, port, port_num_func)); 69 | pio->mul_sel = (val>>offset_func) & 0x07; 70 | 71 | /* pull */ 72 | val = LE32TOH(PIO_REG_PULL(buf, port, port_num_pull)); 73 | pio->pull = (val>>offset_pull) & 0x03; 74 | 75 | /* dlevel */ 76 | val = LE32TOH(PIO_REG_DLEVEL(buf, port, port_num_pull)); 77 | pio->drv_level = (val>>offset_pull) & 0x03; 78 | 79 | /* i/o data */ 80 | if (pio->mul_sel > 1) 81 | pio->data = -1; 82 | else { 83 | val = LE32TOH(PIO_REG_DATA(buf, port)); 84 | pio->data = (val >> port_num) & 0x01; 85 | } 86 | return 1; 87 | } 88 | 89 | static int pio_set(char *buf, uint32_t port, uint32_t port_num, struct pio_status *pio) 90 | { 91 | uint32_t *addr, val; 92 | uint32_t port_num_func, port_num_pull; 93 | uint32_t offset_func, offset_pull; 94 | 95 | port_num_func = port_num >> 3; 96 | offset_func = ((port_num & 0x07) << 2); 97 | 98 | port_num_pull = port_num >> 4; 99 | offset_pull = ((port_num & 0x0f) << 1); 100 | 101 | /* func */ 102 | if (pio->mul_sel >= 0) { 103 | addr = (uint32_t*)PIO_REG_CFG(buf, port, port_num_func); 104 | val = le32toh(*addr); 105 | val &= ~(0x07 << offset_func); 106 | val |= (pio->mul_sel & 0x07) << offset_func; 107 | *addr = htole32(val); 108 | } 109 | 110 | /* pull */ 111 | if (pio->pull >= 0) { 112 | addr = (uint32_t*)PIO_REG_PULL(buf, port, port_num_pull); 113 | val = le32toh(*addr); 114 | val &= ~(0x03 << offset_pull); 115 | val |= (pio->pull & 0x03) << offset_pull; 116 | *addr = htole32(val); 117 | } 118 | 119 | /* dlevel */ 120 | if (pio->drv_level >= 0) { 121 | addr = (uint32_t*)PIO_REG_DLEVEL(buf, port, port_num_pull); 122 | val = le32toh(*addr); 123 | val &= ~(0x03 << offset_pull); 124 | val |= (pio->drv_level & 0x03) << offset_pull; 125 | *addr = htole32(val); 126 | } 127 | 128 | /* data */ 129 | if (pio->data >= 0) { 130 | addr = (uint32_t*)PIO_REG_DATA(buf, port); 131 | val = le32toh(*addr); 132 | if (pio->data) 133 | val |= (0x01 << port_num); 134 | else 135 | val &= ~(0x01 << port_num); 136 | *addr = htole32(val); 137 | } 138 | 139 | return 1; 140 | } 141 | 142 | static void pio_print(int port, int port_nr, struct pio_status *pio) 143 | { 144 | printf("P%c%d", 'A'+port, port_nr); 145 | printf("<%x>", pio->mul_sel); 146 | printf("<%x>", pio->pull); 147 | printf("<%x>", pio->drv_level); 148 | if (pio->data >= 0) 149 | printf("<%x>", pio->data); 150 | fputc('\n', stdout); 151 | } 152 | 153 | static void print(const char *buf) 154 | { 155 | int port, i; 156 | struct pio_status pio; 157 | for (port=0; port < PIO_NR_PORTS; port++) { 158 | for (i=0; i<32; i++) { 159 | if (pio_get(buf, port, i, &pio)) { 160 | pio_print(port, i, &pio); 161 | } 162 | } 163 | } 164 | } 165 | 166 | static const char *argv0; 167 | 168 | static void usage(int rc ) 169 | { 170 | fputs("sunxi-pio " VERSION "\n\n", stderr); 171 | fprintf(stderr, "usage: %s -m|-i input [-o output] pin..\n", argv0); 172 | fprintf(stderr," -m mmap - read pin state from system\n"); 173 | fprintf(stderr," -i read pin state from file\n"); 174 | fprintf(stderr," -o save pin state data to file\n"); 175 | fprintf(stderr," print Show all pins\n"); 176 | fprintf(stderr," Pxx Show pin\n"); 177 | fprintf(stderr," Pxx Configure pin\n"); 178 | fprintf(stderr," Pxx=data,drive Configure GPIO output\n"); 179 | fprintf(stderr," Pxx*count Oscillate GPIO output (mmap mode only)\n"); 180 | fprintf(stderr," Pxx?pull Configure GPIO input\n"); 181 | fprintf(stderr," clean Clean input pins\n"); 182 | fprintf(stderr, "\n mode 0-7, 0=input, 1=ouput, 2-7 I/O function\n"); 183 | fprintf(stderr, " pull 0=none, 1=up, 2=down\n"); 184 | fprintf(stderr, " drive 0-3, I/O drive level\n"); 185 | 186 | exit(rc); 187 | } 188 | 189 | static void parse_pin(int *port, int *pin, const char *name) 190 | { 191 | if (*name == 'P') name++; 192 | *port = *name++ - 'A'; 193 | *pin = atoi(name); 194 | } 195 | 196 | static void cmd_show_pin(char *buf, const char *pin) 197 | { 198 | int port, port_nr; 199 | struct pio_status pio; 200 | parse_pin(&port, &port_nr, pin); 201 | if (!pio_get(buf, port, port_nr, &pio)) 202 | usage(1); 203 | pio_print(port, port_nr, &pio); 204 | } 205 | 206 | static int parse_int(int *dst, const char *in) 207 | { 208 | int value; 209 | char *next; 210 | errno = 0; 211 | value = strtol(in, &next, 0); 212 | if (!errno && next != in) { 213 | *dst = value; 214 | return 0; 215 | } 216 | return -1; 217 | } 218 | 219 | static void cmd_set_pin(char *buf, const char *pin) 220 | { 221 | int port, port_nr; 222 | const char *t = pin; 223 | struct pio_status pio; 224 | parse_pin(&port, &port_nr, pin); 225 | if (!pio_get(buf, port, port_nr, &pio)) 226 | usage(1); 227 | if ((t = strchr(pin, '='))) { 228 | pio.mul_sel = 1; 229 | if (t) { 230 | t++; 231 | parse_int(&pio.data, t); 232 | } 233 | if (t) 234 | t = strchr(t, ','); 235 | if (t) { 236 | t++; 237 | parse_int(&pio.drv_level, t); 238 | } 239 | } else if ((t = strchr(pin, '?'))) { 240 | pio.mul_sel = 0; 241 | pio.data = 0; 242 | pio.drv_level = 0; 243 | if (t) { 244 | t++; 245 | parse_int(&pio.pull, t); 246 | } 247 | } else if ((t = strchr(pin, '<'))) { 248 | if (t) { 249 | t++; 250 | parse_int(&pio.mul_sel, t); 251 | } 252 | if (t) 253 | t = strchr(t, '<'); 254 | if (t) { 255 | t++; 256 | parse_int(&pio.pull, t); 257 | } 258 | if (t) 259 | t = strchr(t, '<'); 260 | if (t) { 261 | t++; 262 | parse_int(&pio.drv_level, t); 263 | } 264 | if (t) 265 | t = strchr(t, '<'); 266 | if (t) { 267 | t++; 268 | parse_int(&pio.data, t); 269 | } 270 | } 271 | pio_set(buf, port, port_nr, &pio); 272 | } 273 | 274 | static void cmd_oscillate(char *buf, const char *pin) 275 | { 276 | int port, port_nr; 277 | const char *t = pin; 278 | int i, n = 0; 279 | uint32_t *addr, val; 280 | 281 | parse_pin(&port, &port_nr, pin); 282 | { 283 | struct pio_status pio; 284 | if (!pio_get(buf, port, port_nr, &pio)) 285 | usage(1); 286 | pio.mul_sel = 1; 287 | pio_set(buf, port, port_nr, &pio); 288 | } 289 | 290 | addr = (uint32_t*)PIO_REG_DATA(buf, port); 291 | t = strchr(pin, '*'); 292 | parse_int(&n, t+1); 293 | val = le32toh(*addr); 294 | for (i = 0; i < n; i++) { 295 | val ^= 1 << port_nr; 296 | *addr = htole32(val); 297 | } 298 | } 299 | 300 | static void cmd_clean(char *buf) 301 | { 302 | int port, i; 303 | struct pio_status pio; 304 | for (port=0; port < PIO_NR_PORTS; port++) { 305 | for (i=0; i<32; i++) { 306 | if (pio_get(buf, port, i, &pio)) { 307 | if (pio.mul_sel == 0) { 308 | pio.data = 0; 309 | pio_set(buf, port, i, &pio); 310 | } 311 | } 312 | } 313 | } 314 | } 315 | 316 | static int do_command(char *buf, const char **args, int UNUSED(argc)) 317 | { 318 | const char *command = args[0]; 319 | if (*command == 'P') { 320 | if (strchr(command, '<')) 321 | cmd_set_pin(buf, command); 322 | else if (strchr(command, '=')) 323 | cmd_set_pin(buf, command); 324 | else if (strchr(command, '?')) 325 | cmd_set_pin(buf, command); 326 | else if (strchr(command, '*')) 327 | cmd_oscillate(buf, command); 328 | else 329 | cmd_show_pin(buf, command); 330 | } 331 | else if (strcmp(command, "print") == 0) 332 | print(buf); 333 | else if (strcmp(command, "clean") == 0) 334 | cmd_clean(buf); 335 | else usage(1); 336 | return 1; 337 | } 338 | 339 | int main(int argc, char **argv) 340 | { 341 | int opt; 342 | FILE *in = NULL; 343 | FILE *out = NULL; 344 | const char *in_name = NULL; 345 | const char *out_name = NULL; 346 | char buf_[PIO_REG_SIZE]; 347 | char *buf = buf_; 348 | int do_mmap = 0; 349 | 350 | argv0 = argv[0]; 351 | 352 | while ((opt = getopt(argc, argv, "i:o:m")) != -1) { 353 | switch(opt) { 354 | case '?': 355 | usage(0); 356 | case 'm': 357 | do_mmap = 1; 358 | break; 359 | case 'i': 360 | in_name = optarg; 361 | break; 362 | case 'o': 363 | out_name = optarg; 364 | break; 365 | } 366 | } 367 | if (!in_name && !do_mmap) 368 | usage(1); 369 | if (do_mmap) { 370 | #ifdef NO_MMAP 371 | errno = ENOSYS; /* Function not implemented */ 372 | perror("mmap PIO"); 373 | #else 374 | int pagesize = sysconf(_SC_PAGESIZE); 375 | int fd = open("/dev/mem",O_RDWR); 376 | int addr = 0x01c20800 & ~(pagesize-1); 377 | int offset = 0x01c20800 & (pagesize-1); 378 | if (fd == -1) { 379 | perror("open /dev/mem"); 380 | exit(1); 381 | } 382 | buf = mmap(NULL, (0x800 + pagesize - 1) & ~(pagesize-1), PROT_WRITE|PROT_READ, MAP_SHARED, fd, addr); 383 | if (!buf) { 384 | perror("mmap PIO"); 385 | exit(1); 386 | } 387 | close(fd); 388 | buf += offset; 389 | #endif 390 | } 391 | if (in_name) { 392 | if (strcmp(in_name, "-") == 0) { 393 | in = stdin; 394 | } else { 395 | in = fopen(in_name, "rb"); 396 | if (!in) { 397 | perror("open input"); 398 | exit(1); 399 | } 400 | } 401 | } 402 | if (in) { 403 | if (fread(buf, PIO_REG_SIZE, 1, in) != 1) { 404 | perror("read input"); 405 | exit(1); 406 | } 407 | if (in != stdin) 408 | fclose(in); 409 | } 410 | 411 | while(optind < argc) { 412 | optind += do_command(buf, (const char **)(argv + optind), argc - optind); 413 | } 414 | 415 | if (out_name) { 416 | if (strcmp(out_name, "-") == 0) { 417 | out = stdout; 418 | } else { 419 | out = fopen(out_name, "wb"); 420 | if (!out) { 421 | perror("open output"); 422 | exit(1); 423 | } 424 | } 425 | if (fwrite(buf, PIO_REG_SIZE, 1, out) != 1) { 426 | perror("write output"); 427 | exit(1); 428 | } 429 | } 430 | } 431 | -------------------------------------------------------------------------------- /progress.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Bernhard Nortmann 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | #include "progress.h" 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | /* Less reliable than clock_gettime, but does not require linking with -lrt */ 24 | inline double gettime(void) 25 | { 26 | struct timeval tv; 27 | gettimeofday(&tv, NULL); 28 | return tv.tv_sec + (double)tv.tv_usec / 1000000.; 29 | } 30 | 31 | /* Calculate transfer rate (in bytes per second) */ 32 | inline double rate(size_t transferred, double elapsed) 33 | { 34 | if (elapsed > 0) 35 | return (double)transferred / elapsed; 36 | return 0.; 37 | } 38 | 39 | /* Estimate remaining time ("ETA") for given transfer rate */ 40 | inline double estimate(size_t remaining, double rate) 41 | { 42 | if (rate > 0) 43 | return (double)remaining / rate; 44 | return 0.; 45 | } 46 | 47 | /* Return ETA (in seconds) as string, formatted to minutes and seconds */ 48 | const char *format_ETA(double remaining) 49 | { 50 | static char result[6] = ""; 51 | 52 | int seconds = remaining + 0.5; /* simplistic round() */ 53 | if (seconds >= 0 && seconds < 6000) { 54 | snprintf(result, sizeof(result), 55 | "%02d:%02d", seconds / 60, seconds % 60); 56 | return result; 57 | } 58 | return "--:--"; 59 | } 60 | 61 | /* Private progress state variable */ 62 | 63 | typedef struct { 64 | progress_cb_t callback; 65 | size_t total; 66 | size_t done; 67 | double start; /* start point (timestamp) for rate and ETA calculation */ 68 | } progress_private_t; 69 | 70 | static progress_private_t progress = { 71 | .callback = NULL, 72 | .start = 0. 73 | }; 74 | 75 | /* 'External' API */ 76 | 77 | void progress_start(progress_cb_t callback, size_t expected_total) 78 | { 79 | progress.callback = callback; 80 | progress.total = expected_total; 81 | progress.done = 0; 82 | progress.start = gettime(); /* reset start time */ 83 | } 84 | 85 | /* Update progress status, passing information to the callback function. */ 86 | void progress_update(size_t bytes_done) 87 | { 88 | progress.done += bytes_done; 89 | if (progress.callback) 90 | progress.callback(progress.total, progress.done); 91 | } 92 | 93 | /* Return relative / "elapsed" time, since progress_start() */ 94 | static inline double progress_elapsed(void) 95 | { 96 | if (progress.start != 0.) 97 | return gettime() - progress.start; 98 | return 0.; 99 | } 100 | 101 | /* Callback function implementing a simple progress bar written to stdout */ 102 | void progress_bar(size_t total, size_t done) 103 | { 104 | static const int WIDTH = 48; /* # of characters to use for progress bar */ 105 | 106 | float ratio = total > 0 ? (float)done / total : 0; 107 | int i, pos = WIDTH * ratio; 108 | double speed = rate(done, progress_elapsed()); 109 | double eta = estimate(total - done, speed); 110 | 111 | printf("\r%3.0f%% [", ratio * 100); /* current percentage */ 112 | for (i = 0; i < pos; i++) putchar('='); 113 | for (i = pos; i < WIDTH; i++) putchar(' '); 114 | if (done < total) 115 | printf("]%6.1f kB/s, ETA %s ", kilo(speed), format_ETA(eta)); 116 | else 117 | /* transfer complete, output totals plus a newline */ 118 | printf("] %5.0f kB, %6.1f kB/s\n", kilo(done), kilo(speed)); 119 | 120 | fflush(stdout); 121 | } 122 | 123 | /* 124 | * Progress callback that emits percentage numbers, each on a separate line. 125 | * The output is suitable for piping it into "dialog --gauge". 126 | * 127 | * sunxi-fel multiwrite-with-gauge <...> \ 128 | * | dialog --title "FEL upload progress" \ 129 | * --gauge "" 5 70 130 | */ 131 | void progress_gauge(size_t total, size_t done) 132 | { 133 | if (total > 0) { 134 | printf("%.0f\n", (float)done / total * 100); 135 | fflush(stdout); 136 | } 137 | } 138 | 139 | /* 140 | * A more sophisticated version of progress_gauge() that also updates the 141 | * prompt (caption) with additional information. This uses a feature of 142 | * the dialog utility that parses "XXX" delimiters - see 'man dialog'. 143 | * 144 | * sunxi-fel multiwrite-with-xgauge <...> \ 145 | * | dialog --title "FEL upload progress" \ 146 | * --backtitle "Please wait..." \ 147 | * --gauge "" 6 70 148 | */ 149 | void progress_gauge_xxx(size_t total, size_t done) 150 | { 151 | if (total > 0) { 152 | double speed = rate(done, progress_elapsed()); 153 | double eta = estimate(total - done, speed); 154 | printf("XXX\n"); 155 | printf("%.0f\n", (float)done / total * 100); 156 | if (done < total) 157 | printf("%zu of %zu, %.1f kB/s, ETA %s\n", 158 | done, total, kilo(speed), format_ETA(eta)); 159 | else 160 | printf("Done: %.1f kB, at %.1f kB/s\n", 161 | kilo(done), kilo(speed)); 162 | printf("XXX\n"); 163 | fflush(stdout); 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /progress.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Bernhard Nortmann 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | #ifndef _SUNXI_TOOLS_PROGRESS_H 18 | #define _SUNXI_TOOLS_PROGRESS_H 19 | 20 | #include 21 | 22 | /* function pointer type for a progress callback / notification */ 23 | typedef void (*progress_cb_t)(size_t total, size_t done); 24 | 25 | /* conversion helper macros */ 26 | #define kilo(value) ((double)(value) / 1000.) /* SI prefix "k" */ 27 | #define kibi(value) ((double)(value) / 1024.) /* binary prefix "Ki", "K" */ 28 | 29 | double gettime(void); 30 | double rate(size_t transferred, double elapsed); 31 | double estimate(size_t remaining, double rate); 32 | 33 | void progress_start(progress_cb_t callback, size_t expected_total); 34 | void progress_update(size_t bytes_done); 35 | 36 | /* progress callback implementations for various display styles */ 37 | void progress_bar(size_t total, size_t done); 38 | void progress_gauge(size_t total, size_t done); 39 | void progress_gauge_xxx(size_t total, size_t done); 40 | 41 | #endif /* _SUNXI_TOOLS_PROGRESS_H */ 42 | -------------------------------------------------------------------------------- /script.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Alejandro Mery 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #include "common.h" 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include "script.h" 26 | 27 | /* 28 | */ 29 | struct script *script_new(void) 30 | { 31 | struct script *script; 32 | if ((script = malloc(sizeof(*script)))) 33 | list_init(&script->sections); 34 | return script; 35 | } 36 | 37 | void script_delete(struct script *script) 38 | { 39 | struct list_entry *o; 40 | 41 | assert(script); 42 | 43 | while ((o = list_last(&script->sections))) { 44 | struct script_section *section = container_of(o, 45 | struct script_section, sections); 46 | 47 | script_section_delete(section); 48 | } 49 | 50 | free(script); 51 | } 52 | 53 | /* 54 | */ 55 | struct script_section *script_section_new(struct script *script, 56 | const char *name) 57 | { 58 | struct script_section *section; 59 | 60 | assert(script); 61 | assert(name && *name); 62 | 63 | if ((section = malloc(sizeof(*section)))) { 64 | size_t l = strlen(name); 65 | if (l>31) /* truncate */ 66 | l=31; 67 | memcpy(section->name, name, l); 68 | section->name[l] = '\0'; 69 | 70 | list_init(§ion->entries); 71 | list_append(&script->sections, §ion->sections); 72 | } 73 | return section; 74 | } 75 | 76 | void script_section_delete(struct script_section *section) 77 | { 78 | struct list_entry *o; 79 | 80 | assert(section); 81 | 82 | while ((o = list_last(§ion->entries))) { 83 | struct script_entry *entry = container_of(o, 84 | struct script_entry, entries); 85 | 86 | script_entry_delete(entry); 87 | } 88 | 89 | if (!list_empty(§ion->sections)) 90 | list_remove(§ion->sections); 91 | } 92 | 93 | struct script_section *script_find_section(struct script *script, 94 | const char *name) 95 | { 96 | struct list_entry *o; 97 | struct script_section *section; 98 | 99 | assert(script); 100 | assert(name); 101 | 102 | for (o = list_first(&script->sections); o; 103 | o = list_next(&script->sections, o)) { 104 | section = container_of(o, struct script_section, sections); 105 | 106 | if (strcmp(section->name, name) == 0) 107 | return section; 108 | } 109 | 110 | return NULL; 111 | } 112 | 113 | /* 114 | */ 115 | static inline void script_entry_append(struct script_section *section, 116 | struct script_entry *entry, 117 | enum script_value_type type, 118 | const char *name) 119 | { 120 | size_t l; 121 | 122 | assert(section); 123 | assert(entry); 124 | assert(name); 125 | 126 | l = strlen(name); 127 | if (l>31) /* truncate */ 128 | l=31; 129 | memcpy(entry->name, name, l); 130 | entry->name[l] = '\0'; 131 | 132 | entry->type = type; 133 | 134 | list_append(§ion->entries, &entry->entries); 135 | } 136 | 137 | void script_entry_delete(struct script_entry *entry) 138 | { 139 | void *container; 140 | 141 | assert(entry); 142 | assert(entry->type == SCRIPT_VALUE_TYPE_SINGLE_WORD || 143 | entry->type == SCRIPT_VALUE_TYPE_STRING || 144 | entry->type == SCRIPT_VALUE_TYPE_GPIO || 145 | entry->type == SCRIPT_VALUE_TYPE_NULL); 146 | 147 | if (!list_empty(&entry->entries)) 148 | list_remove(&entry->entries); 149 | 150 | switch(entry->type) { 151 | case SCRIPT_VALUE_TYPE_SINGLE_WORD: 152 | container = container_of(entry, struct script_single_entry, entry); 153 | break; 154 | case SCRIPT_VALUE_TYPE_STRING: 155 | container = container_of(entry, struct script_string_entry, entry); 156 | break; 157 | case SCRIPT_VALUE_TYPE_GPIO: 158 | container = container_of(entry, struct script_gpio_entry, entry); 159 | break; 160 | case SCRIPT_VALUE_TYPE_NULL: 161 | container = container_of(entry, struct script_null_entry, entry); 162 | break; 163 | default: 164 | abort(); 165 | } 166 | 167 | free(container); 168 | } 169 | 170 | struct script_null_entry *script_null_entry_new(struct script_section *section, 171 | const char *name) 172 | { 173 | struct script_null_entry *entry; 174 | 175 | assert(section); 176 | assert(name && *name); 177 | 178 | if ((entry = malloc(sizeof(*entry)))) { 179 | script_entry_append(section, &entry->entry, 180 | SCRIPT_VALUE_TYPE_NULL, name); 181 | } 182 | 183 | return entry; 184 | } 185 | 186 | struct script_single_entry *script_single_entry_new(struct script_section *section, 187 | const char *name, 188 | uint32_t value) 189 | { 190 | struct script_single_entry *entry; 191 | 192 | assert(section); 193 | assert(name && *name); 194 | 195 | if ((entry = malloc(sizeof(*entry)))) { 196 | entry->value = value; 197 | 198 | script_entry_append(section, &entry->entry, 199 | SCRIPT_VALUE_TYPE_SINGLE_WORD, name); 200 | } 201 | 202 | return entry; 203 | } 204 | 205 | struct script_string_entry *script_string_entry_new(struct script_section *section, 206 | const char *name, 207 | size_t l, const char *s) 208 | { 209 | struct script_string_entry *entry; 210 | 211 | assert(section); 212 | assert(name); 213 | assert(s); 214 | 215 | if ((entry = malloc(sizeof(*entry)+l+1))) { 216 | entry->l = l; 217 | memcpy(entry->string, s, l); 218 | entry->string[l] = '\0'; 219 | 220 | script_entry_append(section, &entry->entry, 221 | SCRIPT_VALUE_TYPE_STRING, name); 222 | } 223 | 224 | return entry; 225 | } 226 | 227 | struct script_gpio_entry *script_gpio_entry_new(struct script_section *section, 228 | const char *name, 229 | unsigned port, unsigned num, 230 | int32_t data[4]) 231 | { 232 | struct script_gpio_entry *entry; 233 | 234 | assert(section); 235 | assert(name && *name); 236 | 237 | if ((entry = malloc(sizeof(*entry)))) { 238 | entry->port = port; 239 | entry->port_num = num; 240 | for (int i=0; i<4; i++) 241 | entry->data[i] = data[i]; 242 | 243 | script_entry_append(section, &entry->entry, 244 | SCRIPT_VALUE_TYPE_GPIO, name); 245 | } 246 | 247 | return entry; 248 | } 249 | 250 | struct script_entry *script_find_entry(struct script_section *section, 251 | const char *name) 252 | { 253 | struct list_entry *o; 254 | struct script_entry *ep; 255 | 256 | assert(section); 257 | assert(name); 258 | 259 | for (o = list_first(§ion->entries); o; 260 | o = list_next(§ion->entries, o)) { 261 | ep = container_of(o, struct script_entry, entries); 262 | 263 | if (strcmp(ep->name, name) == 0) 264 | return ep; 265 | } 266 | 267 | return NULL; 268 | } 269 | -------------------------------------------------------------------------------- /script.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Alejandro Mery 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | #ifndef _SUNXI_TOOLS_SCRIPT_H 18 | #define _SUNXI_TOOLS_SCRIPT_H 19 | 20 | #include "list.h" 21 | 22 | #define GPIO_BANK_MAX 14 /* N, (zero-based) index 13 */ 23 | 24 | /** head of the data tree */ 25 | struct script { 26 | struct list_entry sections; 27 | }; 28 | 29 | /** head of each section */ 30 | struct script_section { 31 | char name[32]; 32 | 33 | struct list_entry sections; 34 | struct list_entry entries; 35 | }; 36 | 37 | /** types of values */ 38 | enum script_value_type { 39 | SCRIPT_VALUE_TYPE_SINGLE_WORD = 1, 40 | SCRIPT_VALUE_TYPE_STRING, 41 | SCRIPT_VALUE_TYPE_MULTI_WORD, 42 | SCRIPT_VALUE_TYPE_GPIO, 43 | SCRIPT_VALUE_TYPE_NULL, 44 | }; 45 | 46 | /** generic entry */ 47 | struct script_entry { 48 | char name[32]; 49 | enum script_value_type type; 50 | 51 | struct list_entry entries; 52 | }; 53 | 54 | /** null entry */ 55 | struct script_null_entry { 56 | struct script_entry entry; 57 | }; 58 | 59 | /** entry with 32b value */ 60 | struct script_single_entry { 61 | struct script_entry entry; 62 | 63 | uint32_t value; 64 | }; 65 | 66 | /** entry with string value */ 67 | struct script_string_entry { 68 | struct script_entry entry; 69 | 70 | size_t l; 71 | char string[]; 72 | }; 73 | 74 | /** entry describing a GPIO */ 75 | struct script_gpio_entry { 76 | struct script_entry entry; 77 | 78 | unsigned port, port_num; 79 | int32_t data[4]; 80 | }; 81 | 82 | /** create a new script tree */ 83 | struct script *script_new(void); 84 | /** deletes a tree recursively */ 85 | void script_delete(struct script *); 86 | 87 | /** create a new section appended to a given tree */ 88 | struct script_section *script_section_new(struct script *script, 89 | const char *name); 90 | /** deletes a section recursvely and removes it from the script */ 91 | void script_section_delete(struct script_section *section); 92 | 93 | /** find existing section */ 94 | struct script_section *script_find_section(struct script *script, 95 | const char *name); 96 | 97 | /** deletes an entry and removes it from the section */ 98 | void script_entry_delete(struct script_entry *entry); 99 | 100 | /** create a new empty/null entry appended to a section */ 101 | struct script_null_entry *script_null_entry_new(struct script_section *section, 102 | const char *name); 103 | /** create a new single word entry appended to a section */ 104 | struct script_single_entry *script_single_entry_new(struct script_section *section, 105 | const char *name, 106 | uint32_t value); 107 | /** create a new string entry appended to a section */ 108 | struct script_string_entry *script_string_entry_new(struct script_section *section, 109 | const char *name, 110 | size_t l, const char *s); 111 | /** create a new GPIO entry appended to a section */ 112 | struct script_gpio_entry *script_gpio_entry_new(struct script_section *script, 113 | const char *name, 114 | unsigned port, unsigned num, 115 | int32_t data[4]); 116 | 117 | /** find existing entry in a giving section */ 118 | struct script_entry *script_find_entry(struct script_section *section, 119 | const char *name); 120 | #endif 121 | -------------------------------------------------------------------------------- /script_bin.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Alejandro Mery 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #include "common.h" 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "script.h" 28 | #include "script_bin.h" 29 | 30 | #define pr_info(...) errf("fexc-bin: " __VA_ARGS__) 31 | #define pr_err(...) errf("E: fexc-bin: " __VA_ARGS__) 32 | 33 | #ifdef DEBUG 34 | #define pr_debug(...) errf("D: fexc-bin: " __VA_ARGS__) 35 | #else 36 | #define pr_debug(...) 37 | #endif 38 | 39 | #define PTR(B, OFF) (void*)((char*)(B)+(OFF)) 40 | #define WORDS(S) (((S)+(sizeof(uint32_t)-1))/(sizeof(uint32_t))) 41 | 42 | /* 43 | * generator 44 | */ 45 | size_t script_bin_size(struct script *script, 46 | size_t *sections, size_t *entries) 47 | { 48 | size_t words = 0, bin_size = 0; 49 | struct list_entry *ls, *le; 50 | struct script_section *section; 51 | struct script_entry *entry; 52 | struct script_string_entry *string; 53 | 54 | *sections = *entries = 0; 55 | 56 | /* count */ 57 | for (ls = list_first(&script->sections); ls; 58 | ls = list_next(&script->sections, ls)) { 59 | section = container_of(ls, struct script_section, sections); 60 | size_t c = 0; 61 | 62 | for (le = list_first(§ion->entries); le; 63 | le = list_next(§ion->entries, le)) { 64 | size_t size = 0; 65 | entry = container_of(le, struct script_entry, entries); 66 | c++; 67 | 68 | switch(entry->type) { 69 | case SCRIPT_VALUE_TYPE_NULL: 70 | case SCRIPT_VALUE_TYPE_SINGLE_WORD: 71 | size = sizeof(uint32_t); 72 | break; 73 | case SCRIPT_VALUE_TYPE_STRING: 74 | string = container_of(entry, struct script_string_entry, 75 | entry); 76 | size = string->l; 77 | break; 78 | case SCRIPT_VALUE_TYPE_GPIO: 79 | size = sizeof(struct script_bin_gpio_value); 80 | break; 81 | default: 82 | abort(); 83 | } 84 | words += WORDS(size); 85 | } 86 | *sections += 1; 87 | *entries += c; 88 | } 89 | 90 | bin_size = sizeof(struct script_bin_head) + 91 | (*sections)*sizeof(struct script_bin_section) + 92 | (*entries)*sizeof(struct script_bin_entry) + 93 | words*sizeof(uint32_t); 94 | pr_debug("sections:%zu entries:%zu data:%zu/%zu -> %zu\n", 95 | *sections, *entries, words, words*sizeof(uint32_t), 96 | bin_size); 97 | return bin_size; 98 | } 99 | 100 | int script_generate_bin(void *bin, size_t UNUSED(bin_size), 101 | struct script *script, 102 | size_t sections, size_t entries) 103 | { 104 | struct script_bin_head *head; 105 | struct script_bin_section *section; 106 | struct script_bin_entry *entry; 107 | void *data; 108 | 109 | struct list_entry *ls, *le; 110 | 111 | head = bin; 112 | section = head->section; 113 | entry = (void*)section+sections*sizeof(*section); 114 | data = (void*)entry+entries*sizeof(*entry); 115 | 116 | pr_debug("head....:%p\n", head); 117 | pr_debug("section.:%p (offset:%zu, each:%zu)\n", section, 118 | (void*)section-bin, sizeof(*section)); 119 | pr_debug("entry...:%p (offset:%zu, each:%zu)\n", entry, 120 | (void*)entry-bin, sizeof(*entry)); 121 | pr_debug("data....:%p (offset:%zu)\n", data, 122 | (void*)data-bin); 123 | 124 | head->sections = sections; 125 | head->version[0] = 0; 126 | head->version[1] = 1; 127 | head->version[2] = 2; 128 | 129 | for (ls = list_first(&script->sections); ls; 130 | ls = list_next(&script->sections, ls)) { 131 | struct script_section *s; 132 | size_t c = 0; 133 | s = container_of(ls, struct script_section, sections); 134 | 135 | memcpy(section->name, s->name, strlen(s->name)); 136 | section->offset = ((void*)entry-bin)>>2; 137 | 138 | for (le = list_first(&s->entries); le; 139 | le = list_next(&s->entries, le)) { 140 | struct script_entry *e; 141 | e = container_of(le, struct script_entry, entries); 142 | size_t size = 0; 143 | 144 | memcpy(entry->name, e->name, strlen(e->name)); 145 | entry->offset = ((void*)data-bin)>>2; 146 | entry->pattern = (e->type<<16); 147 | 148 | switch(e->type) { 149 | case SCRIPT_VALUE_TYPE_SINGLE_WORD: { 150 | struct script_single_entry *single; 151 | int32_t *bdata = data; 152 | single = container_of(e, struct script_single_entry, entry); 153 | 154 | *bdata = single->value; 155 | size = sizeof(*bdata); 156 | }; break; 157 | case SCRIPT_VALUE_TYPE_STRING: { 158 | struct script_string_entry *string; 159 | string = container_of(e, struct script_string_entry, entry); 160 | size = string->l; 161 | memcpy(data, string->string, size); 162 | /* align */ 163 | size += sizeof(uint32_t)-1; 164 | size /= sizeof(uint32_t); 165 | size *= sizeof(uint32_t); 166 | }; break; 167 | case SCRIPT_VALUE_TYPE_MULTI_WORD: 168 | abort(); 169 | case SCRIPT_VALUE_TYPE_GPIO: { 170 | struct script_gpio_entry *gpio; 171 | struct script_bin_gpio_value *bdata = data; 172 | gpio = container_of(e, struct script_gpio_entry, entry); 173 | bdata->port = gpio->port; 174 | bdata->port_num = gpio->port_num; 175 | bdata->mul_sel = gpio->data[0]; 176 | bdata->pull = gpio->data[1]; 177 | bdata->drv_level = gpio->data[2]; 178 | bdata->data = gpio->data[3]; 179 | size = sizeof(*bdata); 180 | }; break; 181 | case SCRIPT_VALUE_TYPE_NULL: 182 | size = sizeof(uint32_t); 183 | break; 184 | } 185 | 186 | data += size; 187 | entry->pattern |= (size>>2); 188 | pr_debug("%s.%s <%p> (type:%d, words:%d (%zu), offset:%d)\n", 189 | section->name, entry->name, entry, 190 | (entry->pattern>>16) & 0xffff, 191 | (entry->pattern>>0) & 0xffff, size, 192 | entry->offset); 193 | c++; 194 | entry++; 195 | } 196 | 197 | section->length = c; 198 | pr_debug("%s <%p> (length:%d, offset:%d)\n", 199 | section->name, section, section->length, section->offset); 200 | 201 | section++; 202 | } 203 | return 1; 204 | } 205 | 206 | /* 207 | * decompiler 208 | */ 209 | static int decompile_section(void *bin, size_t bin_size, 210 | const char *filename, 211 | struct script_bin_section *section, 212 | struct script *script) 213 | { 214 | struct script_bin_entry *entry; 215 | struct script_section *s; 216 | int size; 217 | 218 | if ((section->offset < 0) || (section->offset > (int)(bin_size / 4))) { 219 | pr_err("Malformed data: invalid section offset: %d\n", 220 | section->offset); 221 | return 0; 222 | } 223 | 224 | size = bin_size - 4 * section->offset; 225 | 226 | if ((section->length < 0) || 227 | (section->length > (size / (int)sizeof(struct script_bin_entry)))) { 228 | pr_err("Malformed data: invalid section length: %d\n", 229 | section->length); 230 | return 0; 231 | } 232 | 233 | if ((s = script_section_new(script, section->name)) == NULL) 234 | goto malloc_error; 235 | 236 | entry = PTR(bin, section->offset<<2); 237 | 238 | for (int i = section->length; i--; entry++) { 239 | void *data = PTR(bin, entry->offset<<2); 240 | unsigned type, words; 241 | type = (entry->pattern >> 16) & 0xffff; 242 | words = (entry->pattern >> 0) & 0xffff; 243 | 244 | for (char *p = entry->name; *p; p++) 245 | if (!(isalnum(*p) || *p == '_')) { 246 | pr_info("Warning: Malformed entry key \"%s\"\n", 247 | entry->name); 248 | break; 249 | } 250 | 251 | switch(type) { 252 | case SCRIPT_VALUE_TYPE_SINGLE_WORD: { 253 | uint32_t *v = data; 254 | if (words != 1) { 255 | pr_err("%s: %s.%s: invalid length %d (assuming %d)\n", 256 | filename, section->name, entry->name, words, 1); 257 | } 258 | if (!script_single_entry_new(s, entry->name, *v)) 259 | goto malloc_error; 260 | }; break; 261 | case SCRIPT_VALUE_TYPE_STRING: { 262 | size_t bytes = words << 2; 263 | const char *p, *pe, *v = data; 264 | 265 | for(p=v, pe=v+bytes; *p && p!=pe; p++) 266 | ; /* seek end-of-string */ 267 | 268 | if (!script_string_entry_new(s, entry->name, p-v, v)) 269 | goto malloc_error; 270 | }; break; 271 | case SCRIPT_VALUE_TYPE_GPIO: { 272 | struct script_bin_gpio_value *gpio = data; 273 | int32_t v[4]; 274 | if (words != 6) { 275 | pr_err("%s: %s.%s: invalid length %d (assuming %d)\n", 276 | filename, section->name, entry->name, words, 6); 277 | } else if (gpio->port == 0xffff) { 278 | ; /* port:power */ 279 | } else if (gpio->port < 1 || gpio->port > GPIO_BANK_MAX) { 280 | pr_err("%s: %s.%s: unknown GPIO port bank ", 281 | filename, section->name, entry->name); 282 | char c = 'A' + gpio->port - 1; 283 | if (c >= 'A' && c <= 'Z') 284 | pr_err("%c ", c); 285 | pr_err("(%u)\n", gpio->port); 286 | goto failure; 287 | } 288 | v[0] = gpio->mul_sel; 289 | v[1] = gpio->pull; 290 | v[2] = gpio->drv_level; 291 | v[3] = gpio->data; 292 | 293 | if (!script_gpio_entry_new(s, entry->name, 294 | gpio->port, gpio->port_num, 295 | v)) 296 | goto malloc_error; 297 | }; break; 298 | case SCRIPT_VALUE_TYPE_NULL: 299 | if (!*entry->name) { 300 | pr_err("%s: empty entry in section: %s\n", filename, section->name); 301 | } else if (!script_null_entry_new(s, entry->name)) { 302 | goto malloc_error; 303 | } 304 | break; 305 | default: 306 | pr_err("%s: %s.%s: unknown type %d\n", 307 | filename, section->name, entry->name, type); 308 | goto failure; 309 | } 310 | } 311 | return 1; 312 | 313 | malloc_error: 314 | pr_err("%s: %s\n", "malloc", strerror(errno)); 315 | failure: 316 | return 0; 317 | } 318 | 319 | #define SCRIPT_BIN_VERSION_LIMIT 0x10 320 | #define SCRIPT_BIN_SECTION_LIMIT 0x100 321 | 322 | int script_decompile_bin(void *bin, size_t bin_size, 323 | const char *filename, 324 | struct script *script) 325 | { 326 | unsigned int i; 327 | struct script_bin_head *head = bin; 328 | 329 | if (((head->version[0] & 0x3FFF) > SCRIPT_BIN_VERSION_LIMIT) || 330 | (head->version[1] > SCRIPT_BIN_VERSION_LIMIT) || 331 | (head->version[2] > SCRIPT_BIN_VERSION_LIMIT)) { 332 | pr_err("Malformed data: version %u.%u.%u.\n", 333 | head->version[0], head->version[1], head->version[2]); 334 | return 0; 335 | } 336 | 337 | if (head->sections > SCRIPT_BIN_SECTION_LIMIT) { 338 | pr_err("Malformed data: too many sections (%u).\n", 339 | head->sections); 340 | return 0; 341 | } 342 | 343 | pr_info("%s: version: %u.%u.%u\n", filename, 344 | head->version[0] & 0x3FFF, head->version[1], head->version[2]); 345 | pr_info("%s: size: %zu (%u sections)\n", filename, 346 | bin_size, head->sections); 347 | 348 | /* TODO: SANITY: compare head.sections with bin_size */ 349 | for (i=0; i < head->sections; i++) { 350 | struct script_bin_section *section = &head->section[i]; 351 | 352 | if (!decompile_section(bin, bin_size, filename, 353 | section, script)) 354 | return 0; 355 | } 356 | return 1; 357 | } 358 | -------------------------------------------------------------------------------- /script_bin.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Alejandro Mery 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | #ifndef _SUNXI_TOOLS_SCRIPT_BIN_H 18 | #define _SUNXI_TOOLS_SCRIPT_BIN_H 19 | 20 | /** binary representation of the head of a section */ 21 | struct script_bin_section { 22 | char name[32]; 23 | int32_t length; 24 | int32_t offset; 25 | }; 26 | 27 | /** binary representation of the head of the script file */ 28 | struct script_bin_head { 29 | uint32_t sections; 30 | uint32_t version[3]; 31 | struct script_bin_section section[]; 32 | }; 33 | 34 | /** binary representation of the head of an entry */ 35 | struct script_bin_entry { 36 | char name[32]; 37 | int32_t offset; 38 | int32_t pattern; 39 | }; 40 | 41 | /** binary representation of a GPIO */ 42 | struct script_bin_gpio_value { 43 | int32_t port; 44 | int32_t port_num; 45 | int32_t mul_sel; 46 | int32_t pull; 47 | int32_t drv_level; 48 | int32_t data; 49 | }; 50 | 51 | size_t script_bin_size(struct script *script, 52 | size_t *sections, size_t *entries); 53 | 54 | int script_generate_bin(void *bin, size_t bin_size, struct script *script, 55 | size_t sections, size_t entries); 56 | int script_decompile_bin(void *bin, size_t bin_size, 57 | const char *filename, 58 | struct script *script); 59 | #endif 60 | -------------------------------------------------------------------------------- /script_extractor.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Olliver Schinagl 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #define SCRIPT_START 0x43000000 27 | #define SCRIPT_SIZE 0x20000 28 | 29 | int main(void) { 30 | char *addr; 31 | int fd; 32 | int i; 33 | 34 | fd = open("/dev/mem", O_RDONLY); 35 | addr = (char *)mmap(NULL, SCRIPT_SIZE, PROT_READ, MAP_SHARED, fd, SCRIPT_START); 36 | for (i = 0; i < SCRIPT_SIZE; i++) 37 | putchar(addr[i]); 38 | munmap(addr, SCRIPT_SIZE); 39 | close(fd); 40 | 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /script_fex.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Alejandro Mery 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | #include "common.h" 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include "script.h" 26 | #include "script_fex.h" 27 | 28 | #define MAX_LINE 255 29 | 30 | #define pr_info(...) errf("fexc-fex: " __VA_ARGS__) 31 | #define pr_err(...) errf("E: fexc-fex: " __VA_ARGS__) 32 | 33 | #ifdef DEBUG 34 | #define pr_debug(...) errf("D: fexc-fex: " __VA_ARGS__) 35 | #else 36 | #define pr_debug(...) 37 | #endif 38 | 39 | /* 40 | * generator 41 | */ 42 | static inline size_t strlen2(const char *s) 43 | { 44 | size_t l = strlen(s); 45 | const char *p = &s[l-1]; 46 | while (l && *p >= '0' && *p <= '9') { 47 | l--; 48 | p--; 49 | } 50 | return l; 51 | } 52 | 53 | static int find_full_match(const char *s, size_t l, const char **list) 54 | { 55 | while (*list) { 56 | if (memcmp(s, *list, l) == 0) 57 | return 1; 58 | list++; 59 | } 60 | 61 | return 0; 62 | } 63 | 64 | /** 65 | */ 66 | static int decompile_single_mode(const char *name) 67 | { 68 | static const char *hexa_entries[] = { 69 | "dram_baseaddr", "dram_zq", "dram_tpr", "dram_emr", 70 | "g2d_size", 71 | "rtp_press_threshold", "rtp_sensitive_level", 72 | "ctp_twi_addr", "csi_twi_addr", "csi_twi_addr_b", "tkey_twi_addr", 73 | "lcd_gamma_tbl_", 74 | "gsensor_twi_addr", 75 | NULL }; 76 | size_t l = strlen2(name); 77 | 78 | if (find_full_match(name, l, hexa_entries)) 79 | return 0; 80 | else 81 | return -1; 82 | } 83 | 84 | int script_generate_fex(FILE *out, const char *UNUSED(filename), 85 | struct script *script) 86 | { 87 | struct list_entry *ls, *le; 88 | struct script_section *section; 89 | struct script_entry *entry; 90 | 91 | for (ls = list_first(&script->sections); ls; 92 | ls = list_next(&script->sections, ls)) { 93 | section = container_of(ls, struct script_section, sections); 94 | 95 | fprintf(out, "[%s]\n", section->name); 96 | for (le = list_first(§ion->entries); le; 97 | le = list_next(§ion->entries, le)) { 98 | entry = container_of(le, struct script_entry, entries); 99 | 100 | switch(entry->type) { 101 | case SCRIPT_VALUE_TYPE_SINGLE_WORD: { 102 | int mode = decompile_single_mode(entry->name); 103 | struct script_single_entry *single; 104 | single = container_of(entry, struct script_single_entry, entry); 105 | 106 | fprintf(out, "%s = ", entry->name); 107 | if (mode < 0) 108 | fprintf(out, "%d", single->value); 109 | else if (mode > 0) 110 | fprintf(out, "0x%0*x", mode, single->value); 111 | else 112 | fprintf(out, "0x%x", single->value); 113 | fputc('\n', out); 114 | }; break; 115 | case SCRIPT_VALUE_TYPE_STRING: { 116 | struct script_string_entry *string; 117 | string = container_of(entry, struct script_string_entry, entry); 118 | fprintf(out, "%s = \"%.*s\"\n", entry->name, 119 | (int)string->l, string->string); 120 | }; break; 121 | case SCRIPT_VALUE_TYPE_MULTI_WORD: 122 | abort(); 123 | case SCRIPT_VALUE_TYPE_GPIO: { 124 | char port = 'A'-1; 125 | struct script_gpio_entry *gpio; 126 | gpio = container_of(entry, struct script_gpio_entry, entry); 127 | 128 | if (gpio->port == 0xffff) { 129 | fprintf(out, "%s = port:power%u", entry->name, 130 | gpio->port_num); 131 | } else { 132 | port += gpio->port; 133 | fprintf(out, "%s = port:P%c%02u", entry->name, 134 | port, gpio->port_num); 135 | } 136 | for (const int *p = gpio->data, *pe = p+4; p != pe; p++) { 137 | if (*p == -1) 138 | fputs("", out); 139 | else 140 | fprintf(out, "<%d>", *p); 141 | } 142 | fputc('\n', out); 143 | }; break; 144 | case SCRIPT_VALUE_TYPE_NULL: 145 | fprintf(out, "%s =\n", entry->name); 146 | break; 147 | } 148 | } 149 | fputc('\n', out); 150 | } 151 | return 1; 152 | } 153 | 154 | /* 155 | * parser 156 | */ 157 | 158 | /** find first not blank char */ 159 | static inline char *skip_blank(char *p) 160 | { 161 | while(isblank(*p)) 162 | p++; 163 | return p; 164 | } 165 | 166 | /** trim out blank chars at the end of a string */ 167 | static inline char *rtrim(const char *s, char *p) 168 | { 169 | if (p>s) { 170 | while (p!=s && isblank(*--p)) 171 | ; 172 | *++p='\0'; 173 | } 174 | return p; 175 | } 176 | 177 | /** 178 | */ 179 | int script_parse_fex(FILE *in, const char *filename, struct script *script) 180 | { 181 | char buffer[MAX_LINE+1]; 182 | int ok = 1; 183 | struct script_section *last_section = NULL; 184 | 185 | /* TODO: deal with longer lines correctly (specially in comments) */ 186 | for(size_t line = 1; ok && fgets(buffer, sizeof(buffer), in); line++) { 187 | char *s = skip_blank(buffer); /* beginning */ 188 | char *pe = s; /* \0... to be found */ 189 | 190 | if (*pe) while (*++pe) 191 | ; 192 | 193 | if (pe>s && pe[-1] == '\n') { 194 | if (pe>s+1 && pe[-2] == '\r') 195 | pe -= 2; 196 | else 197 | pe -= 1; 198 | *pe = '\0'; 199 | } 200 | 201 | pe = rtrim(s, pe); 202 | 203 | if (pe == s || *s == ';' || *s == '#') 204 | continue; /* empty */ 205 | if (*s == ':') { 206 | /* see https://github.com/linux-sunxi/sunxi-boards/issues/50 */ 207 | errf("Warning: %s:%zu: invalid line, suspecting typo/malformed comment.\n", 208 | filename, line); 209 | continue; /* ignore this line */ 210 | } 211 | if (*s == '[') { 212 | /* section */ 213 | char *p = ++s; 214 | while (isalnum(*p) || *p == '_') 215 | p++; 216 | 217 | if (*p == ']' && *(p+1) == '\0') { 218 | *p = '\0'; 219 | if ((last_section = script_section_new(script, s))) 220 | continue; 221 | 222 | perror("malloc"); 223 | } else if (*p) { 224 | errf("E: %s:%zu: invalid character at %zu.\n", 225 | filename, line, p-buffer+1); 226 | } else { 227 | errf("E: %s:%zu: incomplete section declaration.\n", 228 | filename, line); 229 | } 230 | ok = 0; 231 | } else { 232 | /* key = value */ 233 | const char *key = s; 234 | char *mark, *p = s; 235 | 236 | if (!last_section) { 237 | errf("E: %s:%zu: data must follow a section.\n", 238 | filename, line); 239 | goto parse_error; 240 | }; 241 | 242 | while (isalnum(*p) || *p == '_') 243 | p++; 244 | mark = p; 245 | p = skip_blank(p); 246 | if (*p != '=') 247 | goto invalid_char_at_p; 248 | *mark = '\0'; /* truncate key */ 249 | p = skip_blank(p+1); 250 | 251 | if (*p == '\0') { 252 | /* NULL */ 253 | if (script_null_entry_new(last_section, key)) 254 | continue; 255 | perror("malloc"); 256 | } else if (pe > p+1 && *p == '"' && pe[-1] == '"') { 257 | /* string */ 258 | p++; *--pe = '\0'; 259 | if (script_string_entry_new(last_section, key, pe-p, p)) { 260 | pr_debug("%s.%s = \"%.*s\"\n", 261 | last_section->name, key, 262 | (int)(pe-p), p); 263 | continue; 264 | } 265 | perror("malloc"); 266 | } else if (memcmp("port:", p, 5) == 0) { 267 | /* GPIO */ 268 | p += 5; 269 | if (p[0] == 'P' && 270 | (p[1] < 'A' || p[1] > ('A' + GPIO_BANK_MAX))) 271 | ; 272 | else if (*p != 'P' && 273 | memcmp(p, "power", 5) != 0) 274 | ; 275 | else { 276 | char *end; 277 | int port; 278 | long v; 279 | 280 | if (*p == 'P') { 281 | /* port:PXN */ 282 | port = p[1] - 'A' + 1; 283 | p += 2; 284 | } else { 285 | /* port:powerN */ 286 | port = 0xffff; 287 | p += 5; 288 | } 289 | 290 | v = strtol(p, &end, 10); 291 | if (end == p) 292 | goto invalid_char_at_p; 293 | else if (v<0 || v>255) { 294 | errf("E: %s:%zu: port out of range at %zu (%ld).\n", 295 | filename, line, p-buffer+1, v); 296 | } else { 297 | int data[] = {-1,-1,-1,-1}; 298 | int port_num = v; 299 | p = end; 300 | for (int i=0; *p && i<4; i++) { 301 | if (memcmp(p, "", 9) == 0) { 302 | p += 9; 303 | continue; 304 | } else if (*p == '<') { 305 | v = strtol(++p, &end, 10); 306 | if (end == p) { 307 | ; 308 | } else if (v<0 || v>INT32_MAX) { 309 | errf("E: %s:%zu: value out of range at %zu (%ld).\n", 310 | filename, line, p-buffer+1, v); 311 | goto parse_error; 312 | } else if (*end != '>') { 313 | p = end; 314 | } else { 315 | p = end+1; 316 | data[i] = v; 317 | continue; 318 | } 319 | } 320 | break; 321 | } 322 | if (*p) 323 | goto invalid_char_at_p; 324 | if (script_gpio_entry_new(last_section, key, 325 | port, port_num, data)) { 326 | pr_debug("%s.%s = GPIO %d.%d (%d,%d,%d,%d)\n", 327 | last_section->name, key, 328 | port, port_num, 329 | data[0], data[1], data[2], data[3]); 330 | continue; 331 | } 332 | perror("malloc"); 333 | } 334 | } 335 | } else if (isdigit(*p) || (*p == '-' && isdigit(*(p+1)))) { 336 | long long v = 0; 337 | char *end; 338 | v = strtoll(p, &end, 0); 339 | p = end; 340 | if (p != pe) { 341 | goto invalid_char_at_p; 342 | } else if (v > UINT32_MAX) { 343 | errf("E: %s:%zu: value out of range %lld.\n", 344 | filename, line, v); 345 | } else if (script_single_entry_new(last_section, key, v)) { 346 | pr_debug("%s.%s = %lld\n", 347 | last_section->name, key, v); 348 | continue; 349 | } 350 | } else { 351 | goto invalid_char_at_p; 352 | } 353 | errf("E: %s:%zu: parse error at %zu.\n", 354 | filename, line, p-buffer+1); 355 | goto parse_error; 356 | invalid_char_at_p: 357 | errf("E: %s:%zu: invalid character at %zu.\n", 358 | filename, line, p-buffer+1); 359 | parse_error: 360 | ok = 0; 361 | } 362 | }; 363 | 364 | if (ferror(in)) 365 | ok = 0; 366 | return ok; 367 | } 368 | -------------------------------------------------------------------------------- /script_fex.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Alejandro Mery 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | #ifndef _SUBXI_TOOLS_SCRIPT_FEX_H 18 | #define _SUBXI_TOOLS_SCRIPT_FEX_H 19 | 20 | int script_parse_fex(FILE *in, const char *filename, struct script *script); 21 | int script_generate_fex(FILE *out, const char *filename, struct script *script); 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /script_uboot.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Alejandro Mery 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | #include "common.h" 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | #include "script.h" 24 | #include "script_uboot.h" 25 | 26 | #define pr_info(...) errf("fexc-uboot: " __VA_ARGS__) 27 | #define pr_err(...) errf("E: fexc-uboot: " __VA_ARGS__) 28 | 29 | #ifdef DEBUG 30 | #define pr_debug(...) errf("D: fexc-uboot: " __VA_ARGS__) 31 | #else 32 | #define pr_debug(...) 33 | #endif 34 | 35 | struct members { 36 | const char *name; 37 | const char *translation; 38 | int mode; 39 | }; 40 | #define foreach_member(I, T) for (const struct members *I = T; \ 41 | I < T+ARRAY_SIZE(T); I++) 42 | 43 | /* 44 | */ 45 | static inline void out_u32_member(FILE *out, const char *key, int hexa, 46 | struct script_single_entry *val) 47 | { 48 | const char *fmt; 49 | if (hexa) 50 | fmt = "\t.%s = %#x,\n"; 51 | else 52 | fmt = "\t.%s = %u,\n"; 53 | 54 | fprintf(out, fmt, key, val->value); 55 | } 56 | 57 | static inline void out_gpio_member(FILE *out, const char *key, 58 | struct script_gpio_entry *gpio) 59 | { 60 | fprintf(out, "\t.%s = ", key); 61 | 62 | if (gpio->port == 0xffff) 63 | fprintf(out, "GPIO_AXP_CFG(%u", gpio->port_num); 64 | else 65 | fprintf(out, "GPIO_CFG(%u, %u", gpio->port, gpio->port_num); 66 | 67 | for (const int *p = gpio->data, *pe = p+4; p != pe; p++) { 68 | if (*p == -1) 69 | fputs(", 0xff", out); 70 | else 71 | fprintf(out, ", %u", *p); 72 | } 73 | 74 | fputs("),\n", out); 75 | } 76 | 77 | static inline void out_null_member(FILE *out, const char *key) 78 | { 79 | fprintf(out, "\t/* %s is NULL */\n", key); 80 | } 81 | 82 | static inline int out_member(FILE *out, const char *key, int mode, 83 | struct script_entry *ep) 84 | { 85 | switch (ep->type) { 86 | case SCRIPT_VALUE_TYPE_SINGLE_WORD: 87 | out_u32_member(out, key, mode, 88 | container_of(ep, struct script_single_entry, entry)); 89 | break; 90 | case SCRIPT_VALUE_TYPE_NULL: 91 | out_null_member(out, key); 92 | break; 93 | case SCRIPT_VALUE_TYPE_GPIO: 94 | out_gpio_member(out, key, 95 | container_of(ep, struct script_gpio_entry, entry)); 96 | break; 97 | default: 98 | return 0; 99 | } 100 | return 1; 101 | } 102 | 103 | /* 104 | * DRAM 105 | */ 106 | static struct members dram_members[] = { 107 | { .name="dram_clock" }, 108 | { .name="dram_clk", .translation="clock" }, 109 | { .name="dram_type" }, 110 | { .name="dram_rank_num" }, 111 | { .name="dram_density" }, 112 | { .name="dram_chip_density", .translation="density" }, 113 | { .name="dram_io_width" }, 114 | { .name="dram_bus_width" }, 115 | { .name="dram_cas" }, 116 | { .name="dram_zq" }, 117 | { .name="dram_odt_en" }, 118 | { .name="dram_size" }, 119 | { .name="dram_tpr0", .mode=1 }, 120 | { .name="dram_tpr1", .mode=1 }, 121 | { .name="dram_tpr2", .mode=1 }, 122 | { .name="dram_tpr3", .mode=1 }, 123 | { .name="dram_tpr4", .mode=1 }, 124 | { .name="dram_tpr5", .mode=1 }, 125 | { .name="dram_emr1", .mode=1 }, 126 | { .name="dram_emr2", .mode=1 }, 127 | { .name="dram_emr3", .mode=1 }, 128 | }; 129 | 130 | static int generate_dram_struct(FILE *out, struct script_section *sp) 131 | { 132 | struct script_entry *ep; 133 | const char *key; 134 | int ret = 1; 135 | 136 | fprintf(out, "static struct dram_para dram_para = {\n"); 137 | foreach_member(mp, dram_members) { 138 | ep = script_find_entry(sp, mp->name); 139 | if (!ep) 140 | continue; 141 | 142 | key = (mp->translation) ? mp->translation : mp->name+5; 143 | if (!out_member(out, key, mp->mode, ep)) { 144 | pr_err("dram_para: %s: invalid field\n", ep->name); 145 | ret = 0; 146 | } 147 | 148 | } 149 | fprintf(out, "};\n"); 150 | fputs("\nunsigned long sunxi_dram_init(void)\n" 151 | "{\n\treturn dramc_init(&dram_para);\n}\n", 152 | out); 153 | 154 | return ret; 155 | } 156 | 157 | #if 0 158 | /* 159 | * PMU 160 | */ 161 | static struct members pmu_members[] = { 162 | { .name = "pmu_used2" }, 163 | { .name = "pmu_para" }, 164 | { .name = "pmu_adpdet" }, 165 | { .name = "pmu_shutdown_chgcur" }, 166 | { .name = "pmu_shutdown_chgcur2" }, 167 | { .name = "pmu_pwroff_vol" }, 168 | { .name = "pmu_pwron_vol" }, 169 | }; 170 | 171 | static int generate_pmu_struct(FILE *out, struct script_section *target, 172 | struct script_section *pmu_para) 173 | { 174 | struct list_entry *le; 175 | struct script_section *sp; 176 | struct script_entry *ep; 177 | const char *key; 178 | int ret = 1; 179 | 180 | fputs("\nstatic struct pmu_para pmu_para = {\n", out); 181 | 182 | sp = target; 183 | for (le = list_first(&sp->entries); le; 184 | le = list_next(&sp->entries, le)) { 185 | ep = container_of(le, struct script_entry, entries); 186 | 187 | if (!out_member(out, ep->name, 0, ep)) { 188 | pr_err("target: %s: invalid field\n", ep->name); 189 | ret = 0; 190 | } 191 | } 192 | 193 | foreach_member(mp, pmu_members) { 194 | ep = script_find_entry(pmu_para, mp->name); 195 | if (!ep) 196 | continue; 197 | 198 | key = (mp->translation) ? mp->translation : mp->name+4; 199 | if (!out_member(out, key, mp->mode, ep)) { 200 | pr_err("pmu_para: %s: invalid field\n", mp->name); 201 | ret = 0; 202 | } 203 | } 204 | 205 | fputs("};\n", out); 206 | fputs("\nint sunxi_pmu_init(void)\n" 207 | "{\n\treturn PMU_init(&pmu_para);\n}\n", 208 | out); 209 | return ret; 210 | 211 | (void) pmu_para; 212 | } 213 | #endif 214 | 215 | int script_generate_uboot(FILE *out, const char *UNUSED(filename), 216 | struct script *script) 217 | { 218 | struct { 219 | const char *name; 220 | struct script_section *sp; 221 | } sections[] = { 222 | { "dram_para", NULL }, 223 | #if 0 224 | { "target", NULL }, 225 | { "pmu_para", NULL }, 226 | #endif 227 | }; 228 | 229 | for (unsigned i=0; i\n" 244 | #if 0 245 | "#include \n" 246 | #endif 247 | "#include \n\n", 248 | out); 249 | 250 | generate_dram_struct(out, sections[0].sp); 251 | #if 0 252 | generate_pmu_struct(out, sections[1].sp, sections[2].sp); 253 | #endif 254 | 255 | return 1; 256 | } 257 | -------------------------------------------------------------------------------- /script_uboot.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Alejandro Mery 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | #ifndef _SUBXI_TOOLS_SCRIPT_UBOOT_H 18 | #define _SUBXI_TOOLS_SCRIPT_UBOOT_H 19 | 20 | int script_generate_uboot(FILE *out, const char *filename, struct script *script); 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /uart0-helloworld-sdboot.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Siarhei Siamashka 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | /* 19 | * Partially based on the uart code from ar100-info 20 | * 21 | * (C) Copyright 2013 Stefan Kristiansson 22 | * 23 | * This program is free software; you can redistribute it and/or 24 | * modify it under the terms of the GNU General Public License as 25 | * published by the Free Software Foundation; either version 2 of 26 | * the License, or (at your option) any later version. 27 | * 28 | * This program is distributed in the hope that it will be useful, 29 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 30 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 31 | * GNU General Public License for more details. 32 | * 33 | * You should have received a copy of the GNU General Public License 34 | * along with this program; if not, write to the Free Software 35 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 36 | * MA 02111-1307 USA 37 | */ 38 | 39 | /* 40 | * Partially based on the sunxi gpio code from U-Boot 41 | * 42 | * (C) Copyright 2012 Henrik Nordstrom 43 | * 44 | * Based on earlier arch/arm/cpu/armv7/sunxi/gpio.c: 45 | * 46 | * (C) Copyright 2007-2011 47 | * Allwinner Technology Co., Ltd. 48 | * Tom Cubie 49 | * 50 | * SPDX-License-Identifier: GPL-2.0+ 51 | */ 52 | 53 | typedef unsigned int u32; 54 | 55 | #define set_wbit(addr, v) (*((volatile unsigned long *)(addr)) |= (unsigned long)(v)) 56 | #define readl(addr) (*((volatile unsigned long *)(addr))) 57 | #define writel(v, addr) (*((volatile unsigned long *)(addr)) = (unsigned long)(v)) 58 | 59 | #define SUNXI_UART0_BASE 0x01C28000 60 | #define SUNXI_PIO_BASE 0x01C20800 61 | #define AW_CCM_BASE 0x01c20000 62 | #define AW_SRAMCTRL_BASE 0x01c00000 63 | 64 | /***************************************************************************** 65 | * GPIO code, borrowed from U-Boot * 66 | *****************************************************************************/ 67 | 68 | #define SUNXI_GPIO_A 0 69 | #define SUNXI_GPIO_B 1 70 | #define SUNXI_GPIO_C 2 71 | #define SUNXI_GPIO_D 3 72 | #define SUNXI_GPIO_E 4 73 | #define SUNXI_GPIO_F 5 74 | #define SUNXI_GPIO_G 6 75 | #define SUNXI_GPIO_H 7 76 | #define SUNXI_GPIO_I 8 77 | 78 | struct sunxi_gpio { 79 | u32 cfg[4]; 80 | u32 dat; 81 | u32 drv[2]; 82 | u32 pull[2]; 83 | }; 84 | 85 | struct sunxi_gpio_reg { 86 | struct sunxi_gpio gpio_bank[10]; 87 | }; 88 | 89 | #define GPIO_BANK(pin) ((pin) >> 5) 90 | #define GPIO_NUM(pin) ((pin) & 0x1F) 91 | 92 | #define GPIO_CFG_INDEX(pin) (((pin) & 0x1F) >> 3) 93 | #define GPIO_CFG_OFFSET(pin) ((((pin) & 0x1F) & 0x7) << 2) 94 | 95 | #define GPIO_PULL_INDEX(pin) (((pin) & 0x1f) >> 4) 96 | #define GPIO_PULL_OFFSET(pin) ((((pin) & 0x1f) & 0xf) << 1) 97 | 98 | /* GPIO bank sizes */ 99 | #define SUNXI_GPIO_A_NR (32) 100 | #define SUNXI_GPIO_B_NR (32) 101 | #define SUNXI_GPIO_C_NR (32) 102 | #define SUNXI_GPIO_D_NR (32) 103 | #define SUNXI_GPIO_E_NR (32) 104 | #define SUNXI_GPIO_F_NR (32) 105 | #define SUNXI_GPIO_G_NR (32) 106 | #define SUNXI_GPIO_H_NR (32) 107 | #define SUNXI_GPIO_I_NR (32) 108 | 109 | #define SUNXI_GPIO_NEXT(__gpio) ((__gpio##_START) + (__gpio##_NR) + 0) 110 | 111 | enum sunxi_gpio_number { 112 | SUNXI_GPIO_A_START = 0, 113 | SUNXI_GPIO_B_START = SUNXI_GPIO_NEXT(SUNXI_GPIO_A), 114 | SUNXI_GPIO_C_START = SUNXI_GPIO_NEXT(SUNXI_GPIO_B), 115 | SUNXI_GPIO_D_START = SUNXI_GPIO_NEXT(SUNXI_GPIO_C), 116 | SUNXI_GPIO_E_START = SUNXI_GPIO_NEXT(SUNXI_GPIO_D), 117 | SUNXI_GPIO_F_START = SUNXI_GPIO_NEXT(SUNXI_GPIO_E), 118 | SUNXI_GPIO_G_START = SUNXI_GPIO_NEXT(SUNXI_GPIO_F), 119 | SUNXI_GPIO_H_START = SUNXI_GPIO_NEXT(SUNXI_GPIO_G), 120 | SUNXI_GPIO_I_START = SUNXI_GPIO_NEXT(SUNXI_GPIO_H), 121 | }; 122 | 123 | /* SUNXI GPIO number definitions */ 124 | #define SUNXI_GPA(_nr) (SUNXI_GPIO_A_START + (_nr)) 125 | #define SUNXI_GPB(_nr) (SUNXI_GPIO_B_START + (_nr)) 126 | #define SUNXI_GPC(_nr) (SUNXI_GPIO_C_START + (_nr)) 127 | #define SUNXI_GPD(_nr) (SUNXI_GPIO_D_START + (_nr)) 128 | #define SUNXI_GPE(_nr) (SUNXI_GPIO_E_START + (_nr)) 129 | #define SUNXI_GPF(_nr) (SUNXI_GPIO_F_START + (_nr)) 130 | #define SUNXI_GPG(_nr) (SUNXI_GPIO_G_START + (_nr)) 131 | #define SUNXI_GPH(_nr) (SUNXI_GPIO_H_START + (_nr)) 132 | #define SUNXI_GPI(_nr) (SUNXI_GPIO_I_START + (_nr)) 133 | 134 | /* GPIO pin function config */ 135 | #define SUNXI_GPIO_INPUT (0) 136 | #define SUNXI_GPIO_OUTPUT (1) 137 | #define SUN4I_GPB_UART0 (2) 138 | #define SUN5I_GPB_UART0 (2) 139 | #define SUN6I_GPH_UART0 (2) 140 | #define SUN8I_H3_GPA_UART0 (2) 141 | #define SUN50I_A64_GPB_UART0 (4) 142 | #define SUNXI_GPF_UART0 (4) 143 | 144 | /* GPIO pin pull-up/down config */ 145 | #define SUNXI_GPIO_PULL_DISABLE (0) 146 | #define SUNXI_GPIO_PULL_UP (1) 147 | #define SUNXI_GPIO_PULL_DOWN (2) 148 | 149 | int sunxi_gpio_set_cfgpin(u32 pin, u32 val) 150 | { 151 | u32 cfg; 152 | u32 bank = GPIO_BANK(pin); 153 | u32 index = GPIO_CFG_INDEX(pin); 154 | u32 offset = GPIO_CFG_OFFSET(pin); 155 | struct sunxi_gpio *pio = 156 | &((struct sunxi_gpio_reg *)SUNXI_PIO_BASE)->gpio_bank[bank]; 157 | cfg = readl(&pio->cfg[0] + index); 158 | cfg &= ~(0xf << offset); 159 | cfg |= val << offset; 160 | writel(cfg, &pio->cfg[0] + index); 161 | return 0; 162 | } 163 | 164 | int sunxi_gpio_set_pull(u32 pin, u32 val) 165 | { 166 | u32 cfg; 167 | u32 bank = GPIO_BANK(pin); 168 | u32 index = GPIO_PULL_INDEX(pin); 169 | u32 offset = GPIO_PULL_OFFSET(pin); 170 | struct sunxi_gpio *pio = 171 | &((struct sunxi_gpio_reg *)SUNXI_PIO_BASE)->gpio_bank[bank]; 172 | cfg = readl(&pio->pull[0] + index); 173 | cfg &= ~(0x3 << offset); 174 | cfg |= val << offset; 175 | writel(cfg, &pio->pull[0] + index); 176 | return 0; 177 | } 178 | 179 | int sunxi_gpio_output(u32 pin, u32 val) 180 | { 181 | u32 dat; 182 | u32 bank = GPIO_BANK(pin); 183 | u32 num = GPIO_NUM(pin); 184 | struct sunxi_gpio *pio = 185 | &((struct sunxi_gpio_reg *)SUNXI_PIO_BASE)->gpio_bank[bank]; 186 | dat = readl(&pio->dat); 187 | if(val) 188 | dat |= 1 << num; 189 | else 190 | dat &= ~(1 << num); 191 | writel(dat, &pio->dat); 192 | return 0; 193 | } 194 | 195 | int sunxi_gpio_input(u32 pin) 196 | { 197 | u32 dat; 198 | u32 bank = GPIO_BANK(pin); 199 | u32 num = GPIO_NUM(pin); 200 | struct sunxi_gpio *pio = 201 | &((struct sunxi_gpio_reg *)SUNXI_PIO_BASE)->gpio_bank[bank]; 202 | dat = readl(&pio->dat); 203 | dat >>= num; 204 | return (dat & 0x1); 205 | } 206 | 207 | int gpio_direction_input(unsigned gpio) 208 | { 209 | sunxi_gpio_set_cfgpin(gpio, SUNXI_GPIO_INPUT); 210 | return sunxi_gpio_input(gpio); 211 | } 212 | 213 | int gpio_direction_output(unsigned gpio, int value) 214 | { 215 | sunxi_gpio_set_cfgpin(gpio, SUNXI_GPIO_OUTPUT); 216 | return sunxi_gpio_output(gpio, value); 217 | } 218 | 219 | /***************************************************************************** 220 | * Nearly all the Allwinner SoCs are using the same VER_REG register for * 221 | * runtime SoC type identification. For additional details see: * 222 | * * 223 | * https://linux-sunxi.org/SRAM_Controller_Register_Guide * 224 | * * 225 | * Allwinner A80 is an oddball and has a non-standard address of the VER_REG * 226 | * * 227 | * Allwinner A10s and A13 are using the same SoC type id, but they can be * 228 | * differentiated using a certain part of the SID register. * 229 | *****************************************************************************/ 230 | 231 | #define VER_REG (AW_SRAMCTRL_BASE + 0x24) 232 | #define SUN4I_SID_BASE 0x01C23800 233 | 234 | static u32 soc_id; 235 | 236 | void soc_detection_init(void) 237 | { 238 | u32 midr; 239 | asm volatile("mrc p15, 0, %0, c0, c0, 0" : "=r" (midr)); 240 | 241 | if (((midr >> 4) & 0xFFF) == 0xC0F) { 242 | soc_id = 0x1639; /* ARM Cortex-A15, so likely Allwinner A80 */ 243 | } else { 244 | set_wbit(VER_REG, 1 << 15); 245 | soc_id = readl(VER_REG) >> 16; 246 | } 247 | } 248 | 249 | int soc_is_a10(void) 250 | { 251 | return soc_id == 0x1623; 252 | } 253 | 254 | int soc_is_a10s(void) 255 | { 256 | return (soc_id == 0x1625) && 257 | (((readl(SUN4I_SID_BASE + 0x08) >> 12) & 0xf) == 7); 258 | } 259 | 260 | int soc_is_a13(void) 261 | { 262 | return (soc_id == 0x1625) && 263 | !(((readl(SUN4I_SID_BASE + 0x08) >> 12) & 0xf) == 7); 264 | } 265 | 266 | int soc_is_a20(void) 267 | { 268 | return soc_id == 0x1651; 269 | } 270 | 271 | int soc_is_a31(void) 272 | { 273 | return soc_id == 0x1633; 274 | } 275 | 276 | int soc_is_a80(void) 277 | { 278 | return soc_id == 0x1639; 279 | } 280 | 281 | int soc_is_a64(void) 282 | { 283 | return soc_id == 0x1689; 284 | } 285 | 286 | int soc_is_h3(void) 287 | { 288 | return soc_id == 0x1680; 289 | } 290 | 291 | /***************************************************************************** 292 | * UART is mostly the same on A10/A13/A20/A31/H3/A64, except that newer SoCs * 293 | * have changed the APB numbering scheme (A10/A13/A20 used to have APB0 and * 294 | * APB1 names, but newer SoCs just have renamed them into APB1 and APB2). * 295 | * The constants below are using the new APB numbering convention. * 296 | * Also the newer SoCs have introduced the APB2_RESET register, but writing * 297 | * to it effectively goes nowhere on older SoCs and is harmless. * 298 | *****************************************************************************/ 299 | 300 | #define CONFIG_CONS_INDEX 1 301 | #define APB2_CFG (AW_CCM_BASE + 0x058) 302 | #define APB2_GATE (AW_CCM_BASE + 0x06C) 303 | #define APB2_RESET (AW_CCM_BASE + 0x2D8) 304 | #define APB2_GATE_UART_SHIFT (16) 305 | #define APB2_RESET_UART_SHIFT (16) 306 | 307 | void clock_init_uart(void) 308 | { 309 | /* Open the clock gate for UART0 */ 310 | set_wbit(APB2_GATE, 1 << (APB2_GATE_UART_SHIFT + CONFIG_CONS_INDEX - 1)); 311 | /* Deassert UART0 reset (only needed on A31/A64/H3) */ 312 | set_wbit(APB2_RESET, 1 << (APB2_RESET_UART_SHIFT + CONFIG_CONS_INDEX - 1)); 313 | } 314 | 315 | /***************************************************************************** 316 | * UART0 pins muxing is different for different SoC variants. * 317 | * Allwinner A13 is a bit special, because there are no dedicated UART0 pins * 318 | * and they are shared with MMC0. * 319 | *****************************************************************************/ 320 | 321 | void gpio_init(void) 322 | { 323 | if (soc_is_a10() || soc_is_a20()) { 324 | sunxi_gpio_set_cfgpin(SUNXI_GPB(22), SUN4I_GPB_UART0); 325 | sunxi_gpio_set_cfgpin(SUNXI_GPB(23), SUN4I_GPB_UART0); 326 | sunxi_gpio_set_pull(SUNXI_GPB(23), SUNXI_GPIO_PULL_UP); 327 | } else if (soc_is_a10s()) { 328 | sunxi_gpio_set_cfgpin(SUNXI_GPB(19), SUN5I_GPB_UART0); 329 | sunxi_gpio_set_cfgpin(SUNXI_GPB(20), SUN5I_GPB_UART0); 330 | sunxi_gpio_set_pull(SUNXI_GPB(20), SUNXI_GPIO_PULL_UP); 331 | } else if (soc_is_a13()) { 332 | /* Disable PB19/PB20 as UART0 to avoid conflict */ 333 | gpio_direction_input(SUNXI_GPB(19)); 334 | gpio_direction_input(SUNXI_GPB(20)); 335 | /* Use SD breakout board to access UART0 on MMC0 pins */ 336 | sunxi_gpio_set_cfgpin(SUNXI_GPF(2), SUNXI_GPF_UART0); 337 | sunxi_gpio_set_cfgpin(SUNXI_GPF(4), SUNXI_GPF_UART0); 338 | sunxi_gpio_set_pull(SUNXI_GPF(4), SUNXI_GPIO_PULL_UP); 339 | } else if (soc_is_a31()) { 340 | sunxi_gpio_set_cfgpin(SUNXI_GPH(20), SUN6I_GPH_UART0); 341 | sunxi_gpio_set_cfgpin(SUNXI_GPH(21), SUN6I_GPH_UART0); 342 | sunxi_gpio_set_pull(SUNXI_GPH(21), SUNXI_GPIO_PULL_UP); 343 | } else if (soc_is_a64()) { 344 | sunxi_gpio_set_cfgpin(SUNXI_GPB(8), SUN50I_A64_GPB_UART0); 345 | sunxi_gpio_set_cfgpin(SUNXI_GPB(9), SUN50I_A64_GPB_UART0); 346 | sunxi_gpio_set_pull(SUNXI_GPB(9), SUNXI_GPIO_PULL_UP); 347 | } else if (soc_is_h3()) { 348 | sunxi_gpio_set_cfgpin(SUNXI_GPA(4), SUN8I_H3_GPA_UART0); 349 | sunxi_gpio_set_cfgpin(SUNXI_GPA(5), SUN8I_H3_GPA_UART0); 350 | sunxi_gpio_set_pull(SUNXI_GPA(5), SUNXI_GPIO_PULL_UP); 351 | } else { 352 | /* Unknown SoC */ 353 | while (1) {} 354 | } 355 | } 356 | 357 | /*****************************************************************************/ 358 | 359 | #define UART0_RBR (SUNXI_UART0_BASE + 0x0) /* receive buffer register */ 360 | #define UART0_THR (SUNXI_UART0_BASE + 0x0) /* transmit holding register */ 361 | #define UART0_DLL (SUNXI_UART0_BASE + 0x0) /* divisor latch low register */ 362 | 363 | #define UART0_DLH (SUNXI_UART0_BASE + 0x4) /* divisor latch high register */ 364 | #define UART0_IER (SUNXI_UART0_BASE + 0x4) /* interrupt enable reigster */ 365 | 366 | #define UART0_IIR (SUNXI_UART0_BASE + 0x8) /* interrupt identity register */ 367 | #define UART0_FCR (SUNXI_UART0_BASE + 0x8) /* fifo control register */ 368 | 369 | #define UART0_LCR (SUNXI_UART0_BASE + 0xc) /* line control register */ 370 | 371 | #define UART0_LSR (SUNXI_UART0_BASE + 0x14) /* line status register */ 372 | 373 | #define BAUD_115200 (0xD) /* 24 * 1000 * 1000 / 16 / 115200 = 13 */ 374 | #define NO_PARITY (0) 375 | #define ONE_STOP_BIT (0) 376 | #define DAT_LEN_8_BITS (3) 377 | #define LC_8_N_1 (NO_PARITY << 3 | ONE_STOP_BIT << 2 | DAT_LEN_8_BITS) 378 | 379 | void uart0_init(void) 380 | { 381 | clock_init_uart(); 382 | 383 | /* select dll dlh */ 384 | writel(0x80, UART0_LCR); 385 | /* set baudrate */ 386 | writel(0, UART0_DLH); 387 | writel(BAUD_115200, UART0_DLL); 388 | /* set line control */ 389 | writel(LC_8_N_1, UART0_LCR); 390 | } 391 | 392 | void uart0_putc(char c) 393 | { 394 | while (!(readl(UART0_LSR) & (1 << 6))) {} 395 | writel(c, UART0_THR); 396 | } 397 | 398 | void uart0_puts(const char *s) 399 | { 400 | while (*s) { 401 | if (*s == '\n') 402 | uart0_putc('\r'); 403 | uart0_putc(*s++); 404 | } 405 | } 406 | 407 | /*****************************************************************************/ 408 | 409 | /* A workaround for https://patchwork.ozlabs.org/patch/622173 */ 410 | void __attribute__((section(".start"))) __attribute__((naked)) start(void) 411 | { 412 | asm volatile("b main \n" 413 | ".long 0xffffffff \n" 414 | ".long 0xffffffff \n" 415 | ".long 0xffffffff \n"); 416 | } 417 | 418 | enum { BOOT_DEVICE_UNK, BOOT_DEVICE_FEL, BOOT_DEVICE_MMC0, BOOT_DEVICE_SPI }; 419 | 420 | int get_boot_device(void) 421 | { 422 | u32 *spl_signature = (void *)0x4; 423 | if (soc_is_a64() || soc_is_a80()) 424 | spl_signature = (void *)0x10004; 425 | 426 | /* Check the eGON.BT0 magic in the SPL header */ 427 | if (spl_signature[0] != 0x4E4F4765 || spl_signature[1] != 0x3054422E) 428 | return BOOT_DEVICE_FEL; 429 | 430 | u32 boot_dev = spl_signature[9] & 0xFF; /* offset into SPL = 0x28 */ 431 | if (boot_dev == 0) 432 | return BOOT_DEVICE_MMC0; 433 | if (boot_dev == 3) 434 | return BOOT_DEVICE_SPI; 435 | 436 | return BOOT_DEVICE_UNK; 437 | } 438 | 439 | int main(void) 440 | { 441 | soc_detection_init(); 442 | gpio_init(); 443 | uart0_init(); 444 | 445 | uart0_puts("\nHello from "); 446 | if (soc_is_a10()) 447 | uart0_puts("Allwinner A10!\n"); 448 | else if (soc_is_a10s()) 449 | uart0_puts("Allwinner A10s!\n"); 450 | else if (soc_is_a13()) 451 | uart0_puts("Allwinner A13!\n"); 452 | else if (soc_is_a20()) 453 | uart0_puts("Allwinner A20!\n"); 454 | else if (soc_is_a31()) 455 | uart0_puts("Allwinner A31/A31s!\n"); 456 | else if (soc_is_a64()) 457 | uart0_puts("Allwinner A64!\n"); 458 | else if (soc_is_h3()) 459 | uart0_puts("Allwinner H3!\n"); 460 | else 461 | uart0_puts("unknown Allwinner SoC!\n"); 462 | 463 | switch (get_boot_device()) { 464 | case BOOT_DEVICE_FEL: 465 | uart0_puts("Returning back to FEL.\n"); 466 | return 0; 467 | case BOOT_DEVICE_MMC0: 468 | uart0_puts("Booted from MMC0, entering an infinite loop.\n"); 469 | while (1) {} 470 | case BOOT_DEVICE_SPI: 471 | uart0_puts("Booted from SPI0, entering an infinite loop.\n"); 472 | while (1) {} 473 | default: 474 | uart0_puts("Booted from unknown media, entering an infinite loop.\n"); 475 | while (1) {} 476 | }; 477 | 478 | return 0; 479 | } 480 | -------------------------------------------------------------------------------- /uart0-helloworld-sdboot.lds: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Siarhei Siamashka 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | SECTIONS 19 | { 20 | . = 0x0000; 21 | .start : { *(.start) } 22 | .text : { *(.text) } 23 | /DISCARD/ : { *(.dynstr*) } 24 | /DISCARD/ : { *(.dynamic*) } 25 | /DISCARD/ : { *(.plt*) } 26 | /DISCARD/ : { *(.interp*) } 27 | /DISCARD/ : { *(.gnu*) } 28 | /DISCARD/ : { *(.note*) } 29 | } 30 | --------------------------------------------------------------------------------